A React component library for rendering common AT Protocol records for applications such as Bluesky and Leaflet.

Compare changes

Choose any two refs to compare.

+2 -2
.gitignore
··· 6 6 yarn-error.log* 7 7 pnpm-debug.log* 8 8 lerna-debug.log* 9 - 9 + demo 10 10 node_modules 11 11 dist 12 12 lib-dist ··· 25 25 *.sln 26 26 *.sw? 27 27 28 - *.tsbuildinfo 28 + *.tsbuildinfo
+22
.npmignore
··· 1 + # Demo and development files 2 + demo/ 3 + src/ 4 + index.html 5 + 6 + # Build configuration 7 + vite.config.ts 8 + vite.config.d.ts 9 + tsconfig.app.json 10 + tsconfig.node.json 11 + eslint.config.js 12 + tsconfig.lib.tsbuildinfo 13 + 14 + # Dependencies 15 + node_modules/ 16 + package-lock.json 17 + bun.lock 18 + 19 + CLAUDE.md 20 + 21 + # Output directory 22 + lib/
+42
.tangled/workflows/upload-demo-to-wisp.yml
··· 1 + when: 2 + - event: ['push'] 3 + branch: ['main'] 4 + - event: ['manual'] 5 + engine: 'nixery' 6 + clone: 7 + skip: false 8 + depth: 1 9 + submodules: false 10 + dependencies: 11 + nixpkgs: 12 + - nodejs 13 + - coreutils 14 + - curl 15 + github:NixOS/nixpkgs/nixpkgs-unstable: 16 + - bun 17 + 18 + environment: 19 + SITE_PATH: 'demo' 20 + SITE_NAME: 'atproto-ui' 21 + WISP_HANDLE: 'ana.pds.nkp.pet' 22 + 23 + steps: 24 + - name: build demo 25 + command: | 26 + export PATH="$HOME/.nix-profile/bin:$PATH" 27 + 28 + # regenerate lockfile, https://github.com/npm/cli/pull/8184 makes rolldown not install 29 + rm package-lock.json bun.lock 30 + bun install 31 + 32 + # run directly with bun because of shebang issues in nix 33 + BUILD_TARGET=demo bun node_modules/.bin/vite build 34 + - name: upload to wisp 35 + command: | 36 + curl https://sites.wisp.place/nekomimi.pet/wisp-cli-binaries/wisp-cli-x86_64-linux -o wisp-cli 37 + chmod +x wisp-cli 38 + ./wisp-cli \ 39 + "$WISP_HANDLE" \ 40 + --path "$SITE_PATH" \ 41 + --site "$SITE_NAME" \ 42 + --password "$WISP_APP_PASSWORD"
+701
CLAUDE.md
··· 1 + # AtReact Hooks Deep Dive 2 + 3 + ## Overview 4 + The AtReact hooks system provides a robust, cache-optimized layer for fetching AT Protocol data. All hooks follow React best practices with proper cleanup, cancellation, and stable references. 5 + 6 + --- 7 + 8 + ## Core Architecture Principles 9 + 10 + ### 1. **Three-Tier Caching Strategy** 11 + All data flows through three cache layers: 12 + - **DidCache** - DID documents, handle mappings, PDS endpoints 13 + - **BlobCache** - Media/image blobs with reference counting 14 + - **RecordCache** - AT Protocol records with deduplication 15 + 16 + ### 2. **Concurrent Request Deduplication** 17 + When multiple components request the same data, only one network request is made. Uses reference counting to manage in-flight requests. 18 + 19 + ### 3. **Stable Reference Pattern** 20 + Caches use memoized snapshots to prevent unnecessary re-renders: 21 + ```typescript 22 + // Only creates new snapshot if data actually changed 23 + if (existing && existing.did === did && existing.handle === handle) { 24 + return toSnapshot(existing); // Reuse existing 25 + } 26 + ``` 27 + 28 + ### 4. **Three-Tier Fallback for Bluesky** 29 + For `app.bsky.*` collections: 30 + 1. Try Bluesky appview API (fastest, public) 31 + 2. Fall back to Slingshot (microcosm service) 32 + 3. Finally query PDS directly 33 + 34 + --- 35 + 36 + ## Hook Catalog 37 + 38 + ## 1. `useDidResolution` 39 + **Purpose:** Resolves handles to DIDs or fetches DID documents 40 + 41 + ### Key Features: 42 + - **Bidirectional:** Works with handles OR DIDs 43 + - **Smart Caching:** Only fetches if not in cache 44 + - **Dual Resolution Paths:** 45 + - Handle โ†’ DID: Uses Slingshot first, then appview 46 + - DID โ†’ Document: Fetches full DID document for handle extraction 47 + 48 + ### State Flow: 49 + ```typescript 50 + Input: "alice.bsky.social" or "did:plc:xxx" 51 + โ†“ 52 + Check didCache 53 + โ†“ 54 + If handle: ensureHandle(resolver, handle) โ†’ DID 55 + If DID: ensureDidDoc(resolver, did) โ†’ DID doc + handle from alsoKnownAs 56 + โ†“ 57 + Return: { did, handle, loading, error } 58 + ``` 59 + 60 + ### Critical Implementation Details: 61 + - **Normalizes input** to lowercase for handles 62 + - **Memoizes input** to prevent effect re-runs 63 + - **Stabilizes error references** - only updates if message changes 64 + - **Cleanup:** Cancellation token prevents stale updates 65 + 66 + --- 67 + 68 + ## 2. `usePdsEndpoint` 69 + **Purpose:** Discovers the PDS endpoint for a DID 70 + 71 + ### Key Features: 72 + - **Depends on DID resolution** (implicit dependency) 73 + - **Extracts from DID document** if already cached 74 + - **Lazy fetching** - only when endpoint not in cache 75 + 76 + ### State Flow: 77 + ```typescript 78 + Input: DID 79 + โ†“ 80 + Check didCache.getByDid(did).pdsEndpoint 81 + โ†“ 82 + If missing: ensurePdsEndpoint(resolver, did) 83 + โ”œโ”€ Tries to get from existing DID doc 84 + โ””โ”€ Falls back to resolver.pdsEndpointForDid() 85 + โ†“ 86 + Return: { endpoint, loading, error } 87 + ``` 88 + 89 + ### Service Discovery: 90 + Looks for `AtprotoPersonalDataServer` service in DID document: 91 + ```json 92 + { 93 + "service": [{ 94 + "type": "AtprotoPersonalDataServer", 95 + "serviceEndpoint": "https://pds.example.com" 96 + }] 97 + } 98 + ``` 99 + 100 + --- 101 + 102 + ## 3. `useAtProtoRecord` 103 + **Purpose:** Fetches a single AT Protocol record with smart routing 104 + 105 + ### Key Features: 106 + - **Collection-aware routing:** Bluesky vs other protocols 107 + - **RecordCache deduplication:** Multiple components = one fetch 108 + - **Cleanup with reference counting** 109 + 110 + ### State Flow: 111 + ```typescript 112 + Input: { did, collection, rkey } 113 + โ†“ 114 + If collection.startsWith("app.bsky."): 115 + โ””โ”€ useBlueskyAppview() โ†’ Three-tier fallback 116 + Else: 117 + โ”œโ”€ useDidResolution(did) 118 + โ”œโ”€ usePdsEndpoint(resolved.did) 119 + โ””โ”€ recordCache.ensure() โ†’ Fetch from PDS 120 + โ†“ 121 + Return: { record, loading, error } 122 + ``` 123 + 124 + ### RecordCache Deduplication: 125 + ```typescript 126 + // First component calling this 127 + const { promise, release } = recordCache.ensure(did, collection, rkey, loader) 128 + // refCount = 1 129 + 130 + // Second component calling same record 131 + const { promise, release } = recordCache.ensure(...) // Same promise! 132 + // refCount = 2 133 + 134 + // On cleanup, both call release() 135 + // Only aborts when refCount reaches 0 136 + ``` 137 + 138 + --- 139 + 140 + ## 4. `useBlueskyAppview` 141 + **Purpose:** Fetches Bluesky records with appview optimization 142 + 143 + ### Key Features: 144 + - **Collection-aware endpoints:** 145 + - `app.bsky.actor.profile` โ†’ `app.bsky.actor.getProfile` 146 + - `app.bsky.feed.post` โ†’ `app.bsky.feed.getPostThread` 147 + - **CDN URL extraction:** Parses CDN URLs to extract CIDs 148 + - **Atomic state updates:** Uses reducer for complex state 149 + 150 + ### Three-Tier Fallback with Source Tracking: 151 + ```typescript 152 + async function fetchWithFallback() { 153 + // Tier 1: Appview (if endpoint mapped) 154 + try { 155 + const result = await fetchFromAppview(did, collection, rkey); 156 + return { record: result, source: "appview" }; 157 + } catch {} 158 + 159 + // Tier 2: Slingshot 160 + try { 161 + const result = await fetchFromSlingshot(did, collection, rkey); 162 + return { record: result, source: "slingshot" }; 163 + } catch {} 164 + 165 + // Tier 3: PDS 166 + try { 167 + const result = await fetchFromPds(did, collection, rkey); 168 + return { record: result, source: "pds" }; 169 + } catch {} 170 + 171 + // All tiers failed - provide helpful error for banned Bluesky accounts 172 + if (pdsEndpoint.includes('.bsky.network')) { 173 + throw new Error('Record unavailable. The Bluesky PDS may be unreachable or the account may be banned.'); 174 + } 175 + 176 + throw new Error('Failed to fetch record from all sources'); 177 + } 178 + ``` 179 + 180 + The `source` field in the result accurately indicates which tier successfully fetched the data, enabling debugging and analytics. 181 + 182 + ### CDN URL Handling: 183 + Appview returns CDN URLs like: 184 + ``` 185 + https://cdn.bsky.app/img/avatar/plain/did:plc:xxx/bafkreixxx@jpeg 186 + ``` 187 + 188 + Hook extracts CID (`bafkreixxx`) and creates standard Blob object: 189 + ```typescript 190 + { 191 + $type: "blob", 192 + ref: { $link: "bafkreixxx" }, 193 + mimeType: "image/jpeg", 194 + size: 0, 195 + cdnUrl: "https://cdn.bsky.app/..." // Preserved for fast rendering 196 + } 197 + ``` 198 + 199 + ### Reducer Pattern: 200 + ```typescript 201 + type Action = 202 + | { type: "SET_LOADING"; loading: boolean } 203 + | { type: "SET_SUCCESS"; record: T; source: "appview" | "slingshot" | "pds" } 204 + | { type: "SET_ERROR"; error: Error } 205 + | { type: "RESET" }; 206 + 207 + // Atomic state updates, no race conditions 208 + dispatch({ type: "SET_SUCCESS", record, source }); 209 + ``` 210 + 211 + --- 212 + 213 + ## 5. `useLatestRecord` 214 + **Purpose:** Fetches the most recent record from a collection 215 + 216 + ### Key Features: 217 + - **Timestamp validation:** Skips records before 2023 (pre-ATProto) 218 + - **PDS-only:** Slingshot doesn't support `listRecords` 219 + - **Smart fetching:** Gets 3 records to handle invalid timestamps 220 + 221 + ### State Flow: 222 + ```typescript 223 + Input: { did, collection } 224 + โ†“ 225 + useDidResolution(did) 226 + usePdsEndpoint(did) 227 + โ†“ 228 + callListRecords(endpoint, did, collection, limit: 3) 229 + โ†“ 230 + Filter: isValidTimestamp(record) โ†’ year >= 2023 231 + โ†“ 232 + Return first valid record: { record, rkey, loading, error, empty } 233 + ``` 234 + 235 + ### Timestamp Validation: 236 + ```typescript 237 + function isValidTimestamp(record: unknown): boolean { 238 + const timestamp = record.createdAt || record.indexedAt; 239 + if (!timestamp) return true; // No timestamp, assume valid 240 + 241 + const date = new Date(timestamp); 242 + return date.getFullYear() >= 2023; // ATProto created in 2023 243 + } 244 + ``` 245 + 246 + --- 247 + 248 + ## 6. `usePaginatedRecords` 249 + **Purpose:** Cursor-based pagination with prefetching 250 + 251 + ### Key Features: 252 + - **Dual fetching modes:** 253 + - Author feed (appview) - for Bluesky posts with filters 254 + - Direct PDS - for all other collections 255 + - **Smart prefetching:** Loads next page in background 256 + - **Invalid timestamp filtering:** Same as `useLatestRecord` 257 + - **Request sequencing:** Prevents race conditions with `requestSeq` 258 + 259 + ### State Management: 260 + ```typescript 261 + // Pages stored as array 262 + pages: [ 263 + { records: [...], cursor: "abc" }, // page 0 264 + { records: [...], cursor: "def" }, // page 1 265 + { records: [...], cursor: undefined } // page 2 (last) 266 + ] 267 + pageIndex: 1 // Currently viewing page 1 268 + ``` 269 + 270 + ### Prefetch Logic: 271 + ```typescript 272 + useEffect(() => { 273 + const cursor = pages[pageIndex]?.cursor; 274 + if (!cursor || pages[pageIndex + 1]) return; // No cursor or already loaded 275 + 276 + // Prefetch next page in background 277 + fetchPage(identity, cursor, pageIndex + 1, "prefetch"); 278 + }, [pageIndex, pages]); 279 + ``` 280 + 281 + ### Author Feed vs PDS: 282 + ```typescript 283 + if (preferAuthorFeed && collection === "app.bsky.feed.post") { 284 + // Use app.bsky.feed.getAuthorFeed 285 + const res = await callAppviewRpc("app.bsky.feed.getAuthorFeed", { 286 + actor: handle || did, 287 + filter: "posts_with_media", // Optional filter 288 + includePins: true 289 + }); 290 + } else { 291 + // Use com.atproto.repo.listRecords 292 + const res = await callListRecords(pdsEndpoint, did, collection, limit); 293 + } 294 + ``` 295 + 296 + ### Race Condition Prevention: 297 + ```typescript 298 + const requestSeq = useRef(0); 299 + 300 + // On identity change 301 + resetState(); 302 + requestSeq.current += 1; // Invalidate in-flight requests 303 + 304 + // In fetch callback 305 + const token = requestSeq.current; 306 + // ... do async work ... 307 + if (token !== requestSeq.current) return; // Stale request, abort 308 + ``` 309 + 310 + --- 311 + 312 + ## 7. `useBlob` 313 + **Purpose:** Fetches and caches media blobs with object URL management 314 + 315 + ### Key Features: 316 + - **Automatic cleanup:** Revokes object URLs on unmount 317 + - **BlobCache deduplication:** Same blob = one fetch 318 + - **Reference counting:** Safe concurrent access 319 + 320 + ### State Flow: 321 + ```typescript 322 + Input: { did, cid } 323 + โ†“ 324 + useDidResolution(did) 325 + usePdsEndpoint(did) 326 + โ†“ 327 + Check blobCache.get(did, cid) 328 + โ†“ 329 + If missing: blobCache.ensure() โ†’ Fetch from PDS 330 + โ”œโ”€ GET /xrpc/com.atproto.sync.getBlob?did={did}&cid={cid} 331 + โ””โ”€ Store in cache 332 + โ†“ 333 + Create object URL: URL.createObjectURL(blob) 334 + โ†“ 335 + Return: { url, loading, error } 336 + โ†“ 337 + Cleanup: URL.revokeObjectURL(url) 338 + ``` 339 + 340 + ### Object URL Management: 341 + ```typescript 342 + const objectUrlRef = useRef<string>(); 343 + 344 + // On successful fetch 345 + const nextUrl = URL.createObjectURL(blob); 346 + const prevUrl = objectUrlRef.current; 347 + objectUrlRef.current = nextUrl; 348 + if (prevUrl) URL.revokeObjectURL(prevUrl); // Clean up old URL 349 + 350 + // On unmount 351 + useEffect(() => () => { 352 + if (objectUrlRef.current) { 353 + URL.revokeObjectURL(objectUrlRef.current); 354 + } 355 + }, []); 356 + ``` 357 + 358 + --- 359 + 360 + ## 8. `useBlueskyProfile` 361 + **Purpose:** Wrapper around `useBlueskyAppview` for profile records 362 + 363 + ### Key Features: 364 + - **Simplified interface:** Just pass DID 365 + - **Type conversion:** Converts ProfileRecord to BlueskyProfileData 366 + - **CID extraction:** Extracts avatar/banner CIDs from blobs 367 + 368 + ### Implementation: 369 + ```typescript 370 + export function useBlueskyProfile(did: string | undefined) { 371 + const { record, loading, error } = useBlueskyAppview<ProfileRecord>({ 372 + did, 373 + collection: "app.bsky.actor.profile", 374 + rkey: "self", 375 + }); 376 + 377 + const data = record ? { 378 + did: did || "", 379 + handle: "", // Populated by caller 380 + displayName: record.displayName, 381 + description: record.description, 382 + avatar: extractCidFromBlob(record.avatar), 383 + banner: extractCidFromBlob(record.banner), 384 + createdAt: record.createdAt, 385 + } : undefined; 386 + 387 + return { data, loading, error }; 388 + } 389 + ``` 390 + 391 + --- 392 + 393 + ## 9. `useBacklinks` 394 + **Purpose:** Fetches backlinks from Microcosm Constellation API 395 + 396 + ### Key Features: 397 + - **Specialized use case:** Tangled stars, etc. 398 + - **Abort controller:** Cancels in-flight requests 399 + - **Refetch support:** Manual refresh capability 400 + 401 + ### State Flow: 402 + ```typescript 403 + Input: { subject: "at://did:plc:xxx/sh.tangled.repo/yyy", source: "sh.tangled.feed.star:subject" } 404 + โ†“ 405 + GET https://constellation.microcosm.blue/xrpc/blue.microcosm.links.getBacklinks 406 + ?subject={subject}&source={source}&limit={limit} 407 + โ†“ 408 + Return: { backlinks: [...], total, loading, error, refetch } 409 + ``` 410 + 411 + --- 412 + 413 + ## 10. `useRepoLanguages` 414 + **Purpose:** Fetches language statistics from Tangled knot server 415 + 416 + ### Key Features: 417 + - **Branch fallback:** Tries "main", then "master" 418 + - **Knot server query:** For repository analysis 419 + 420 + ### State Flow: 421 + ```typescript 422 + Input: { knot: "knot.gaze.systems", did, repoName, branch } 423 + โ†“ 424 + GET https://{knot}/xrpc/sh.tangled.repo.languages 425 + ?repo={did}/{repoName}&ref={branch} 426 + โ†“ 427 + If 404: Try fallback branch 428 + โ†“ 429 + Return: { data: { languages: {...} }, loading, error } 430 + ``` 431 + 432 + --- 433 + 434 + ## Cache Implementation Deep Dive 435 + 436 + ### DidCache 437 + **Purpose:** Cache DID documents, handle mappings, PDS endpoints 438 + 439 + ```typescript 440 + class DidCache { 441 + private byHandle = new Map<string, DidCacheEntry>(); 442 + private byDid = new Map<string, DidCacheEntry>(); 443 + private handlePromises = new Map<string, Promise<...>>(); 444 + private docPromises = new Map<string, Promise<...>>(); 445 + private pdsPromises = new Map<string, Promise<...>>(); 446 + 447 + // Memoized snapshots prevent re-renders 448 + private toSnapshot(entry): DidCacheSnapshot { 449 + if (entry.snapshot) return entry.snapshot; // Reuse 450 + entry.snapshot = { did, handle, doc, pdsEndpoint }; 451 + return entry.snapshot; 452 + } 453 + } 454 + ``` 455 + 456 + **Key methods:** 457 + - `getByHandle(handle)` - Instant cache lookup 458 + - `getByDid(did)` - Instant cache lookup 459 + - `ensureHandle(resolver, handle)` - Deduplicated resolution 460 + - `ensureDidDoc(resolver, did)` - Deduplicated doc fetch 461 + - `ensurePdsEndpoint(resolver, did)` - Deduplicated PDS discovery 462 + 463 + **Snapshot stability:** 464 + ```typescript 465 + memoize(entry) { 466 + const existing = this.byDid.get(did); 467 + 468 + // Data unchanged? Reuse snapshot (same reference) 469 + if (existing && existing.did === did && 470 + existing.handle === handle && ...) { 471 + return toSnapshot(existing); // Prevents re-render! 472 + } 473 + 474 + // Data changed, create new entry 475 + const merged = { did, handle, doc, pdsEndpoint, snapshot: undefined }; 476 + this.byDid.set(did, merged); 477 + return toSnapshot(merged); 478 + } 479 + ``` 480 + 481 + ### BlobCache 482 + **Purpose:** Cache media blobs with reference counting 483 + 484 + ```typescript 485 + class BlobCache { 486 + private store = new Map<string, BlobCacheEntry>(); 487 + private inFlight = new Map<string, InFlightBlobEntry>(); 488 + 489 + ensure(did, cid, loader) { 490 + // Already cached? 491 + const cached = this.get(did, cid); 492 + if (cached) return { promise: Promise.resolve(cached), release: noop }; 493 + 494 + // In-flight request? 495 + const existing = this.inFlight.get(key); 496 + if (existing) { 497 + existing.refCount++; // Multiple consumers 498 + return { promise: existing.promise, release: () => this.release(key) }; 499 + } 500 + 501 + // New request 502 + const { promise, abort } = loader(); 503 + this.inFlight.set(key, { promise, abort, refCount: 1 }); 504 + return { promise, release: () => this.release(key) }; 505 + } 506 + 507 + private release(key) { 508 + const entry = this.inFlight.get(key); 509 + entry.refCount--; 510 + if (entry.refCount <= 0) { 511 + this.inFlight.delete(key); 512 + entry.abort(); // Cancel fetch 513 + } 514 + } 515 + } 516 + ``` 517 + 518 + ### RecordCache 519 + **Purpose:** Cache AT Protocol records with deduplication 520 + 521 + Identical structure to BlobCache but for record data. 522 + 523 + --- 524 + 525 + ## Common Patterns 526 + 527 + ### 1. Cancellation Pattern 528 + ```typescript 529 + useEffect(() => { 530 + let cancelled = false; 531 + 532 + const assignState = (next) => { 533 + if (cancelled) return; // Don't update unmounted component 534 + setState(prev => ({ ...prev, ...next })); 535 + }; 536 + 537 + // ... async work ... 538 + 539 + return () => { 540 + cancelled = true; // Mark as cancelled 541 + release?.(); // Decrement refCount 542 + }; 543 + }, [deps]); 544 + ``` 545 + 546 + ### 2. Error Stabilization Pattern 547 + ```typescript 548 + setError(prevError => 549 + prevError?.message === newError.message 550 + ? prevError // Reuse same reference 551 + : newError // New error 552 + ); 553 + ``` 554 + 555 + ### 3. Identity Tracking Pattern 556 + ```typescript 557 + const identityRef = useRef<string>(); 558 + const identity = did && endpoint ? `${did}::${endpoint}` : undefined; 559 + 560 + useEffect(() => { 561 + if (identityRef.current !== identity) { 562 + identityRef.current = identity; 563 + resetState(); // Clear stale data 564 + } 565 + // ... 566 + }, [identity]); 567 + ``` 568 + 569 + ### 4. Dual-Mode Resolution 570 + ```typescript 571 + const isDid = input.startsWith("did:"); 572 + const normalizedHandle = !isDid ? input.toLowerCase() : undefined; 573 + 574 + // Different code paths 575 + if (isDid) { 576 + snapshot = await didCache.ensureDidDoc(resolver, input); 577 + } else { 578 + snapshot = await didCache.ensureHandle(resolver, normalizedHandle); 579 + } 580 + ``` 581 + 582 + --- 583 + 584 + ## Performance Optimizations 585 + 586 + ### 1. **Memoized Snapshots** 587 + Caches return stable references when data unchanged โ†’ prevents re-renders 588 + 589 + ### 2. **Reference Counting** 590 + Multiple components requesting same data share one fetch 591 + 592 + ### 3. **Prefetching** 593 + `usePaginatedRecords` loads next page in background 594 + 595 + ### 4. **CDN URLs** 596 + Bluesky appview returns CDN URLs โ†’ skip blob fetching for images 597 + 598 + ### 5. **Smart Routing** 599 + Bluesky collections use fast appview โ†’ non-Bluesky goes direct to PDS 600 + 601 + ### 6. **Request Deduplication** 602 + In-flight request maps prevent duplicate fetches 603 + 604 + ### 7. **Timestamp Validation** 605 + Skip invalid records early (before 2023) โ†’ fewer wasted cycles 606 + 607 + --- 608 + 609 + ## Error Handling Strategy 610 + 611 + ### 1. **Fallback Chains** 612 + Never fail on first attempt โ†’ try multiple sources 613 + 614 + ### 2. **Graceful Degradation** 615 + ```typescript 616 + // Slingshot failed? Try appview 617 + try { 618 + return await fetchFromSlingshot(); 619 + } catch (slingshotError) { 620 + try { 621 + return await fetchFromAppview(); 622 + } catch (appviewError) { 623 + // Combine errors for better debugging 624 + throw new Error(`${appviewError.message}; Slingshot: ${slingshotError.message}`); 625 + } 626 + } 627 + ``` 628 + 629 + ### 3. **Component Isolation** 630 + Errors in one component don't crash others (via error boundaries recommended) 631 + 632 + ### 4. **Abort Handling** 633 + ```typescript 634 + try { 635 + await fetch(url, { signal }); 636 + } catch (err) { 637 + if (err.name === "AbortError") return; // Expected, ignore 638 + throw err; 639 + } 640 + ``` 641 + 642 + ### 5. **Banned Bluesky Account Detection** 643 + When all three tiers fail and the PDS is a `.bsky.network` endpoint, provide a helpful error: 644 + ```typescript 645 + // All tiers failed - check if it's a banned Bluesky account 646 + if (pdsEndpoint.includes('.bsky.network')) { 647 + throw new Error( 648 + 'Record unavailable. The Bluesky PDS may be unreachable or the account may be banned.' 649 + ); 650 + } 651 + ``` 652 + 653 + This helps users understand why data is unavailable instead of showing generic fetch errors. Applies to both `useBlueskyAppview` and `useAtProtoRecord` hooks. 654 + 655 + --- 656 + 657 + ## Testing Considerations 658 + 659 + ### Key scenarios to test: 660 + 1. **Concurrent requests:** Multiple components requesting same data 661 + 2. **Race conditions:** Component unmounting mid-fetch 662 + 3. **Cache invalidation:** Identity changes during fetch 663 + 4. **Error fallbacks:** Slingshot down โ†’ appview works 664 + 5. **Timestamp filtering:** Records before 2023 skipped 665 + 6. **Reference counting:** Proper cleanup on unmount 666 + 7. **Prefetching:** Background loads don't interfere with active loads 667 + 668 + --- 669 + 670 + ## Common Gotchas 671 + 672 + ### 1. **React Rules of Hooks** 673 + All hooks called unconditionally, even if results not used: 674 + ```typescript 675 + // Always call, conditionally use results 676 + const blueskyResult = useBlueskyAppview({ 677 + did: isBlueskyCollection ? handleOrDid : undefined, // Pass undefined to skip 678 + collection: isBlueskyCollection ? collection : undefined, 679 + rkey: isBlueskyCollection ? rkey : undefined, 680 + }); 681 + ``` 682 + 683 + ### 2. **Cleanup Order Matters** 684 + ```typescript 685 + return () => { 686 + cancelled = true; // 1. Prevent state updates 687 + release?.(); // 2. Decrement refCount 688 + revokeObjectURL(...); // 3. Free resources 689 + }; 690 + ``` 691 + 692 + ### 3. **Snapshot Reuse** 693 + Don't modify cached snapshots! They're shared across components. 694 + 695 + ### 4. **CDN URL Extraction** 696 + Bluesky CDN URLs must be parsed carefully: 697 + ``` 698 + https://cdn.bsky.app/img/avatar/plain/did:plc:xxx/bafkreixxx@jpeg 699 + ^^^^^^^^^^^^ ^^^^^^ 700 + DID CID 701 + ```
+141 -78
README.md
··· 1 1 # atproto-ui 2 2 3 - atproto-ui is a component library and set of hooks for rendering records from the AT Protocol (Bluesky, Leaflet, and friends) in React applications. It handles DID resolution, PDS endpoint discovery, and record fetching so you can focus on UI. [Live demo](https://atproto-ui.wisp.place). 3 + A React component library for rendering AT Protocol records (Bluesky, Leaflet, Tangled, and more). Handles DID resolution, PDS discovery, and record fetching automatically as well as caching these so multiple components can render quickly. [Live demo](https://atproto-ui.wisp.place). 4 + 5 + This project is mostly a wrapper on the extremely amazing work [Mary](https://mary.my.id/) has done with [atcute](https://tangled.org/@mary.my.id/atcute), please support it. I have to give thanks to [phil](https://bsky.app/profile/bad-example.com) for microcosm and slingshot. Incredible services being given for free that is responsible for why the components fetch data so quickly. 4 6 5 7 ## Screenshots 6 8 ··· 9 11 10 12 ## Features 11 13 12 - - Drop-in components for common record types (`BlueskyPost`, `BlueskyProfile`, `TangledString`, etc.). 13 - - Pass prefetched data directly to components to skip API callsโ€”perfect for server-side rendering, caching, or when you already have the data. 14 - - Hooks and helpers for composing your own renderers for your own applications, (PRs welcome!) 15 - - Built on the lightweight [`@atcute/*`](https://github.com/atcute) clients. 14 + - **Drop-in components** for common record types (`BlueskyPost`, `BlueskyProfile`, `TangledRepo`, `LeafletDocument`) 15 + - **Prefetch support** - Pass data directly to skip API calls (perfect for SSR/caching) 16 + - **Caching** - Blobs, DIDs, and records are cached so components which use the same ones can render even quicker 17 + - **Customizable theming** - Override CSS variables to match your app's design 18 + - **Composable hooks** - Build custom renderers with protocol primitives 19 + - Built on lightweight [`@atcute/*`](https://tangled.org/@mary.my.id/atcute) clients 16 20 17 21 ## Installation 18 22 ··· 20 24 npm install atproto-ui 21 25 ``` 22 26 23 - ## Quick start 24 - 25 - 1. Wrap your app (once) with the `AtProtoProvider`. 26 - 2. Drop any of the ready-made components inside that provider. 27 - 3. Use the hooks to prefetch handles, blobs, or latest records when you want to control the render flow yourself. 27 + ## Quick Start 28 28 29 29 ```tsx 30 - import { AtProtoProvider, BlueskyPost } from "atproto-ui"; 30 + import { AtProtoProvider, BlueskyPost, LeafletDocument } from "atproto-ui"; 31 + import "atproto-ui/styles.css"; 31 32 32 33 export function App() { 33 34 return ( 34 35 <AtProtoProvider> 35 36 <BlueskyPost did="did:plc:example" rkey="3k2aexample" /> 36 - {/* you can use handles in the components as well. */} 37 + {/* You can use handles too */} 37 38 <LeafletDocument did="nekomimi.pet" rkey="3m2seagm2222c" /> 38 39 </AtProtoProvider> 39 40 ); 40 41 } 41 42 ``` 42 43 43 - ## Passing prefetched data to skip API calls 44 + **Note:** The library automatically imports the CSS when you import any component. If you prefer to import it explicitly (e.g., for better IDE support or control over load order), you can use `import "atproto-ui/styles.css"`. 45 + 46 + ## Theming 47 + 48 + Components use CSS variables for theming. By default, they respond to system dark mode preferences, or you can set a theme explicitly: 49 + 50 + ```tsx 51 + // Set theme via data attribute on document element 52 + document.documentElement.setAttribute("data-theme", "dark"); // or "light" 53 + 54 + // For system preference (default) 55 + document.documentElement.removeAttribute("data-theme"); 56 + ``` 57 + 58 + ### Available CSS Variables 59 + 60 + ```css 61 + --atproto-color-bg 62 + --atproto-color-bg-elevated 63 + --atproto-color-text 64 + --atproto-color-text-secondary 65 + --atproto-color-border 66 + --atproto-color-link 67 + /* ...and more, check out lib/styles.css */ 68 + ``` 44 69 45 - All components accept a `record` prop. When provided, the component uses your data immediately without making network requests for that record. This is perfect for SSR, caching strategies, or when you've already fetched data through other means. 70 + ### Override Component Theme 71 + 72 + Wrap any component in a div with custom CSS variables to override its appearance: 73 + 74 + ```tsx 75 + import { AtProtoStyles } from "atproto-ui"; 76 + 77 + <div style={{ 78 + '--atproto-color-bg': '#f0f0f0', 79 + '--atproto-color-text': '#000', 80 + '--atproto-color-link': '#0066cc', 81 + } satisfies AtProtoStyles}> 82 + <BlueskyPost did="..." rkey="..." /> 83 + </div> 84 + ``` 85 + 86 + ## Prefetched Data 87 + 88 + All components accept a `record` prop. When provided, the component uses your data immediately without making network requests. Perfect for SSR, caching, or when you've already fetched data. 46 89 47 90 ```tsx 48 91 import { BlueskyPost, useLatestRecord } from "atproto-ui"; ··· 63 106 }; 64 107 ``` 65 108 66 - The same pattern works for all components: 109 + All components support prefetched data: 67 110 68 111 ```tsx 69 - // BlueskyProfile with prefetched data 70 112 <BlueskyProfile did={did} record={profileRecord} /> 113 + <TangledString did={did} rkey={rkey} record={stringRecord} /> 114 + <LeafletDocument did={did} rkey={rkey} record={documentRecord} /> 115 + ``` 71 116 72 - // TangledString with prefetched data 73 - <TangledString did={did} rkey={rkey} record={stringRecord} /> 117 + ### Using atcute Directly 118 + 119 + Use atcute directly to construct records and pass them to componentsโ€”fully compatible! 120 + 121 + ```tsx 122 + import { Client, simpleFetchHandler, ok } from '@atcute/client'; 123 + import type { AppBskyFeedPost } from '@atcute/bluesky'; 124 + import { BlueskyPost } from 'atproto-ui'; 125 + 126 + // Create atcute client 127 + const client = new Client({ 128 + handler: simpleFetchHandler({ service: 'https://public.api.bsky.app' }) 129 + }); 130 + 131 + // Fetch a record 132 + const data = await ok( 133 + client.get('com.atproto.repo.getRecord', { 134 + params: { 135 + repo: 'did:plc:ttdrpj45ibqunmfhdsb4zdwq', 136 + collection: 'app.bsky.feed.post', 137 + rkey: '3m45rq4sjes2h' 138 + } 139 + }) 140 + ); 141 + 142 + const record = data.value as AppBskyFeedPost.Main; 74 143 75 - // LeafletDocument with prefetched data 76 - <LeafletDocument did={did} rkey={rkey} record={documentRecord} /> 144 + // Pass atcute record directly to component! 145 + <BlueskyPost 146 + did="did:plc:ttdrpj45ibqunmfhdsb4zdwq" 147 + rkey="3m45rq4sjes2h" 148 + record={record} 149 + /> 77 150 ``` 78 151 79 - ### Available building blocks 152 + ## API Reference 80 153 81 - | Component / Hook | What it does | 82 - | --------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | 83 - | `AtProtoProvider` | Configures PLC directory (defaults to `https://plc.directory`) and shares protocol clients via React context. | 84 - | `AtProtoRecord` | Core component that fetches and renders any AT Protocol record. **Accepts a `record` prop to use prefetched data and skip API calls.** | 85 - | `BlueskyProfile` | Renders a profile card for a DID/handle. **Accepts a `record` prop to skip fetching.** Also supports `fallback`, `loadingIndicator`, `renderer`, and `colorScheme`. | 86 - | `BlueskyPost` / `BlueskyQuotePost` | Shows a single Bluesky post with quotation support. **Accepts a `record` prop to skip fetching.** Custom renderer overrides and loading/fallback knobs available. | 87 - | `BlueskyPostList` | Lists the latest posts with built-in pagination (defaults: 5 per page, pagination controls on). | 88 - | `TangledString` | Renders a Tangled string (gist-like record). **Accepts a `record` prop to skip fetching.** Optional renderer overrides available. | 89 - | `LeafletDocument` | Displays long-form Leaflet documents with blocks and theme support. **Accepts a `record` prop to skip fetching.** Renderer overrides available. | 90 - | `useDidResolution`, `useLatestRecord`, `usePaginatedRecords`, โ€ฆ | Hook-level access to records. `useLatestRecord` returns both the `record` and `rkey` so you can pass them directly to components. | 154 + ### Components 155 + 156 + | Component | Description | 157 + |-----------|-------------| 158 + | `AtProtoProvider` | Context provider for sharing protocol clients. Optional `plcDirectory` prop. | 159 + | `AtProtoRecord` | Core component for fetching/rendering any AT Protocol record. Accepts `record` prop. | 160 + | `BlueskyProfile` | Profile card for a DID/handle. Accepts `record`, `fallback`, `loadingIndicator`, `renderer`. | 161 + | `BlueskyPost` | Single Bluesky post. Accepts `record`, `iconPlacement`, custom renderers. | 162 + | `BlueskyQuotePost` | Post with quoted post support. Accepts `record`. | 163 + | `BlueskyPostList` | Paginated list of posts (default: 5 per page). | 164 + | `TangledString` | Tangled string (code snippet) renderer. Accepts `record`. | 165 + | `LeafletDocument` | Long-form document with blocks. Accepts `record`, `publicationRecord`. | 166 + 167 + ### Hooks 91 168 92 - All components accept a `colorScheme` of `'light' | 'dark' | 'system'` so they can blend into your design. They also accept `fallback` and `loadingIndicator` props to control what renders before or during network work, and most expose a `renderer` override when you need total control of the final markup. 169 + | Hook | Returns | 170 + |------|---------| 171 + | `useDidResolution(did)` | `{ did, handle, loading, error }` | 172 + | `useLatestRecord(did, collection)` | `{ record, rkey, loading, error, empty }` | 173 + | `usePaginatedRecords(options)` | `{ records, loading, hasNext, loadNext, ... }` | 174 + | `useBlob(did, cid)` | `{ url, loading, error }` | 175 + | `useAtProtoRecord(did, collection, rkey)` | `{ record, loading, error }` | 93 176 94 - ### Using hooks to fetch data once 177 + ## Advanced Usage 95 178 96 - `useLatestRecord` gives you the most recent record for any collection along with its `rkey`. You can pass both to components to skip the fetch: 179 + ### Using Hooks for Custom Logic 97 180 98 181 ```tsx 99 182 import { useLatestRecord, BlueskyPost } from "atproto-ui"; ··· 114 197 }; 115 198 ``` 116 199 117 - The same pattern works for other components. Just swap the collection NSID and component: 200 + ### Custom Renderer 118 201 119 - ```tsx 120 - const LatestLeafletDocument: React.FC<{ did: string }> = ({ did }) => { 121 - const { record, rkey } = useLatestRecord(did, "pub.leaflet.document"); 122 - return record && rkey ? ( 123 - <LeafletDocument did={did} rkey={rkey} record={record} colorScheme="light" /> 124 - ) : null; 125 - }; 126 - ``` 127 - 128 - ## Compose your own component 129 - 130 - The helpers let you stitch together custom experiences without reimplementing protocol plumbing. The example below pulls a creator's latest post and renders a minimal summary: 202 + Use `AtProtoRecord` with a custom renderer for full control: 131 203 132 204 ```tsx 133 - import { useLatestRecord, useColorScheme, AtProtoRecord } from "atproto-ui"; 205 + import { AtProtoRecord } from "atproto-ui"; 134 206 import type { FeedPostRecord } from "atproto-ui"; 135 207 136 - const LatestPostSummary: React.FC<{ did: string }> = ({ did }) => { 137 - const scheme = useColorScheme("system"); 138 - const { rkey, loading, error } = useLatestRecord<FeedPostRecord>( 139 - did, 140 - "app.bsky.feed.post", 141 - ); 142 - 143 - if (loading) return <span>Loadingโ€ฆ</span>; 144 - if (error || !rkey) return <span>No post yet.</span>; 145 - 146 - return ( 147 - <AtProtoRecord<FeedPostRecord> 148 - did={did} 149 - collection="app.bsky.feed.post" 150 - rkey={rkey} 151 - renderer={({ record }) => ( 152 - <article data-color-scheme={scheme}> 153 - <strong>{record?.text ?? "Empty post"}</strong> 154 - </article> 155 - )} 156 - /> 157 - ); 158 - }; 208 + <AtProtoRecord<FeedPostRecord> 209 + did={did} 210 + collection="app.bsky.feed.post" 211 + rkey={rkey} 212 + renderer={({ record, loading, error }) => ( 213 + <article> 214 + <strong>{record?.text ?? "Empty post"}</strong> 215 + </article> 216 + )} 217 + /> 159 218 ``` 160 219 161 - There is a [demo](https://atproto-ui.wisp.place/) where you can see the components in live action. 220 + ## Demo 221 + 222 + Check out the [live demo](https://atproto-ui.wisp.place/) to see all components in action. 162 223 163 - ## Running the demo locally 224 + ### Running Locally 164 225 165 226 ```bash 166 227 npm install 167 228 npm run dev 168 229 ``` 169 230 170 - Then open the printed Vite URL and try entering a Bluesky handle to see the components in action. 231 + ## Contributing 171 232 172 - ## Next steps 233 + Contributions are welcome! Open an issue or PR for: 234 + - New record type support (e.g., Grain.social photos) 235 + - Improved documentation 236 + - Bug fixes or feature requests 173 237 174 - - Expand renderer coverage (e.g., Grain.social photos). 175 - - Expand documentation with TypeScript API references and theming guidelines. 238 + ## License 176 239 177 - Contributions and ideas are welcomeโ€”feel free to open an issue or PR! 240 + MIT
+697
bun.lock
··· 1 + { 2 + "lockfileVersion": 1, 3 + "configVersion": 1, 4 + "workspaces": { 5 + "": { 6 + "name": "atproto-ui", 7 + "dependencies": { 8 + "@atcute/atproto": "^3.1.7", 9 + "@atcute/bluesky": "^3.2.3", 10 + "@atcute/client": "^4.0.3", 11 + "@atcute/identity-resolver": "^1.1.3", 12 + "@atcute/tangled": "^1.0.10", 13 + }, 14 + "devDependencies": { 15 + "@eslint/js": "^9.36.0", 16 + "@microsoft/api-extractor": "^7.53.1", 17 + "@types/node": "^24.6.0", 18 + "@types/react": "^19.1.16", 19 + "@types/react-dom": "^19.1.9", 20 + "@vitejs/plugin-react": "^5.0.4", 21 + "eslint": "^9.36.0", 22 + "eslint-plugin-react-hooks": "^5.2.0", 23 + "eslint-plugin-react-refresh": "^0.4.22", 24 + "globals": "^16.4.0", 25 + "react": "^19.1.1", 26 + "react-dom": "^19.1.1", 27 + "rollup-plugin-typescript2": "^0.36.0", 28 + "typescript": "~5.9.3", 29 + "typescript-eslint": "^8.45.0", 30 + "unplugin-dts": "^1.0.0-beta.6", 31 + "vite": "npm:rolldown-vite@7.1.14", 32 + }, 33 + "peerDependencies": { 34 + "react": "^18.2.0 || ^19.0.0", 35 + "react-dom": "^18.2.0 || ^19.0.0", 36 + }, 37 + "optionalPeers": [ 38 + "react-dom", 39 + ], 40 + }, 41 + }, 42 + "packages": { 43 + "@atcute/atproto": ["@atcute/atproto@3.1.9", "", { "dependencies": { "@atcute/lexicons": "^1.2.2" } }, "sha512-DyWwHCTdR4hY2BPNbLXgVmm7lI+fceOwWbE4LXbGvbvVtSn+ejSVFaAv01Ra3kWDha0whsOmbJL8JP0QPpf1+w=="], 44 + 45 + "@atcute/bluesky": ["@atcute/bluesky@3.2.11", "", { "dependencies": { "@atcute/atproto": "^3.1.9", "@atcute/lexicons": "^1.2.5" } }, "sha512-AboS6y4t+zaxIq7E4noue10csSpIuk/Uwo30/l6GgGBDPXrd7STw8Yb5nGZQP+TdG/uC8/c2mm7UnY65SDOh6A=="], 46 + 47 + "@atcute/client": ["@atcute/client@4.1.0", "", { "dependencies": { "@atcute/identity": "^1.1.3", "@atcute/lexicons": "^1.2.5" } }, "sha512-AYhSu3RSDA2VDkVGOmad320NRbUUUf5pCFWJcOzlk25YC/4kyzmMFfpzhf1jjjEcY+anNBXGGhav/kKB1evggQ=="], 48 + 49 + "@atcute/identity": ["@atcute/identity@1.1.3", "", { "dependencies": { "@atcute/lexicons": "^1.2.4", "@badrap/valita": "^0.4.6" } }, "sha512-oIqPoI8TwWeQxvcLmFEZLdN2XdWcaLVtlm8pNk0E72As9HNzzD9pwKPrLr3rmTLRIoULPPFmq9iFNsTeCIU9ng=="], 50 + 51 + "@atcute/identity-resolver": ["@atcute/identity-resolver@1.1.4", "", { "dependencies": { "@atcute/lexicons": "^1.2.2", "@atcute/util-fetch": "^1.0.3", "@badrap/valita": "^0.4.6" }, "peerDependencies": { "@atcute/identity": "^1.0.0" } }, "sha512-/SVh8vf2cXFJenmBnGeYF2aY3WGQm3cJeew5NWTlkqoy3LvJ5wkvKq9PWu4Tv653VF40rPOp6LOdVr9Fa+q5rA=="], 52 + 53 + "@atcute/lexicons": ["@atcute/lexicons@1.2.5", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "esm-env": "^1.2.2" } }, "sha512-9yO9WdgxW8jZ7SbzUycH710z+JmsQ9W9n5S6i6eghYju32kkluFmgBeS47r8e8p2+Dv4DemS7o/3SUGsX9FR5Q=="], 54 + 55 + "@atcute/tangled": ["@atcute/tangled@1.0.12", "", { "dependencies": { "@atcute/atproto": "^3.1.9", "@atcute/lexicons": "^1.2.3" } }, "sha512-JKA5sOhd8SLhDFhY+PKHqLLytQBBKSiwcaEzfYUJBeyfvqXFPNNAwvRbe3VST4IQ3izoOu3O0R9/b1mjL45UzA=="], 56 + 57 + "@atcute/util-fetch": ["@atcute/util-fetch@1.0.4", "", { "dependencies": { "@badrap/valita": "^0.4.6" } }, "sha512-sIU9Qk0dE8PLEXSfhy+gIJV+HpiiknMytCI2SqLlqd0vgZUtEKI/EQfP+23LHWvP+CLCzVDOa6cpH045OlmNBg=="], 58 + 59 + "@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], 60 + 61 + "@babel/compat-data": ["@babel/compat-data@7.28.5", "", {}, "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA=="], 62 + 63 + "@babel/core": ["@babel/core@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw=="], 64 + 65 + "@babel/generator": ["@babel/generator@7.28.5", "", { "dependencies": { "@babel/parser": "^7.28.5", "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ=="], 66 + 67 + "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.27.2", "", { "dependencies": { "@babel/compat-data": "^7.27.2", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ=="], 68 + 69 + "@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="], 70 + 71 + "@babel/helper-module-imports": ["@babel/helper-module-imports@7.27.1", "", { "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" } }, "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w=="], 72 + 73 + "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw=="], 74 + 75 + "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.27.1", "", {}, "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw=="], 76 + 77 + "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], 78 + 79 + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], 80 + 81 + "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], 82 + 83 + "@babel/helpers": ["@babel/helpers@7.28.4", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.4" } }, "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w=="], 84 + 85 + "@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="], 86 + 87 + "@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw=="], 88 + 89 + "@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="], 90 + 91 + "@babel/template": ["@babel/template@7.27.2", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", "@babel/types": "^7.27.1" } }, "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw=="], 92 + 93 + "@babel/traverse": ["@babel/traverse@7.28.5", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", "@babel/types": "^7.28.5", "debug": "^4.3.1" } }, "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ=="], 94 + 95 + "@babel/types": ["@babel/types@7.28.5", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA=="], 96 + 97 + "@badrap/valita": ["@badrap/valita@0.4.6", "", {}, "sha512-4kdqcjyxo/8RQ8ayjms47HCWZIF5981oE5nIenbfThKDxWXtEHKipAOWlflpPJzZx9y/JWYQkp18Awr7VuepFg=="], 98 + 99 + "@emnapi/core": ["@emnapi/core@1.7.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg=="], 100 + 101 + "@emnapi/runtime": ["@emnapi/runtime@1.7.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA=="], 102 + 103 + "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="], 104 + 105 + "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g=="], 106 + 107 + "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="], 108 + 109 + "@eslint/config-array": ["@eslint/config-array@0.21.1", "", { "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.2" } }, "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA=="], 110 + 111 + "@eslint/config-helpers": ["@eslint/config-helpers@0.4.2", "", { "dependencies": { "@eslint/core": "^0.17.0" } }, "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw=="], 112 + 113 + "@eslint/core": ["@eslint/core@0.17.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ=="], 114 + 115 + "@eslint/eslintrc": ["@eslint/eslintrc@3.3.3", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^10.0.1", "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.1", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ=="], 116 + 117 + "@eslint/js": ["@eslint/js@9.39.1", "", {}, "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw=="], 118 + 119 + "@eslint/object-schema": ["@eslint/object-schema@2.1.7", "", {}, "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA=="], 120 + 121 + "@eslint/plugin-kit": ["@eslint/plugin-kit@0.4.1", "", { "dependencies": { "@eslint/core": "^0.17.0", "levn": "^0.4.1" } }, "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA=="], 122 + 123 + "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], 124 + 125 + "@humanfs/node": ["@humanfs/node@0.16.7", "", { "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.4.0" } }, "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ=="], 126 + 127 + "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="], 128 + 129 + "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="], 130 + 131 + "@isaacs/balanced-match": ["@isaacs/balanced-match@4.0.1", "", {}, "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ=="], 132 + 133 + "@isaacs/brace-expansion": ["@isaacs/brace-expansion@5.0.0", "", { "dependencies": { "@isaacs/balanced-match": "^4.0.1" } }, "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA=="], 134 + 135 + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], 136 + 137 + "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], 138 + 139 + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], 140 + 141 + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], 142 + 143 + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], 144 + 145 + "@microsoft/api-extractor": ["@microsoft/api-extractor@7.55.1", "", { "dependencies": { "@microsoft/api-extractor-model": "7.32.1", "@microsoft/tsdoc": "~0.16.0", "@microsoft/tsdoc-config": "~0.18.0", "@rushstack/node-core-library": "5.19.0", "@rushstack/rig-package": "0.6.0", "@rushstack/terminal": "0.19.4", "@rushstack/ts-command-line": "5.1.4", "diff": "~8.0.2", "lodash": "~4.17.15", "minimatch": "10.0.3", "resolve": "~1.22.1", "semver": "~7.5.4", "source-map": "~0.6.1", "typescript": "5.8.2" }, "bin": { "api-extractor": "bin/api-extractor" } }, "sha512-l8Z+8qrLkZFM3HM95Dbpqs6G39fpCa7O5p8A7AkA6hSevxkgwsOlLrEuPv0ADOyj5dI1Af5WVDiwpKG/ya5G3w=="], 146 + 147 + "@microsoft/api-extractor-model": ["@microsoft/api-extractor-model@7.32.1", "", { "dependencies": { "@microsoft/tsdoc": "~0.16.0", "@microsoft/tsdoc-config": "~0.18.0", "@rushstack/node-core-library": "5.19.0" } }, "sha512-u4yJytMYiUAnhcNQcZDTh/tVtlrzKlyKrQnLOV+4Qr/5gV+cpufWzCYAB1Q23URFqD6z2RoL2UYncM9xJVGNKA=="], 148 + 149 + "@microsoft/tsdoc": ["@microsoft/tsdoc@0.16.0", "", {}, "sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA=="], 150 + 151 + "@microsoft/tsdoc-config": ["@microsoft/tsdoc-config@0.18.0", "", { "dependencies": { "@microsoft/tsdoc": "0.16.0", "ajv": "~8.12.0", "jju": "~1.4.0", "resolve": "~1.22.2" } }, "sha512-8N/vClYyfOH+l4fLkkr9+myAoR6M7akc8ntBJ4DJdWH2b09uVfr71+LTMpNyG19fNqWDg8KEDZhx5wxuqHyGjw=="], 152 + 153 + "@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.0", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" } }, "sha512-Fq6DJW+Bb5jaWE69/qOE0D1TUN9+6uWhCeZpdnSBk14pjLcCWR7Q8n49PTSPHazM37JqrsdpEthXy2xn6jWWiA=="], 154 + 155 + "@oxc-project/runtime": ["@oxc-project/runtime@0.92.0", "", {}, "sha512-Z7x2dZOmznihvdvCvLKMl+nswtOSVxS2H2ocar+U9xx6iMfTp0VGIrX6a4xB1v80IwOPC7dT1LXIJrY70Xu3Jw=="], 156 + 157 + "@oxc-project/types": ["@oxc-project/types@0.93.0", "", {}, "sha512-yNtwmWZIBtJsMr5TEfoZFDxIWV6OdScOpza/f5YxbqUMJk+j6QX3Cf3jgZShGEFYWQJ5j9mJ6jM0tZHu2J9Yrg=="], 158 + 159 + "@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0-beta.41", "", { "os": "android", "cpu": "arm64" }, "sha512-Edflndd9lU7JVhVIvJlZhdCj5DkhYDJPIRn4Dx0RUdfc8asP9xHOI5gMd8MesDDx+BJpdIT/uAmVTearteU/mQ=="], 160 + 161 + "@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.0-beta.41", "", { "os": "darwin", "cpu": "arm64" }, "sha512-XGCzqfjdk7550PlyZRTBKbypXrB7ATtXhw/+bjtxnklLQs0mKP/XkQVOKyn9qGKSlvH8I56JLYryVxl0PCvSNw=="], 162 + 163 + "@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.0-beta.41", "", { "os": "darwin", "cpu": "x64" }, "sha512-Ho6lIwGJed98zub7n0xcRKuEtnZgbxevAmO4x3zn3C3N4GVXZD5xvCvTVxSMoeBJwTcIYzkVDRTIhylQNsTgLQ=="], 164 + 165 + "@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.0-beta.41", "", { "os": "freebsd", "cpu": "x64" }, "sha512-ijAZETywvL+gACjbT4zBnCp5ez1JhTRs6OxRN4J+D6AzDRbU2zb01Esl51RP5/8ZOlvB37xxsRQ3X4YRVyYb3g=="], 166 + 167 + "@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.41", "", { "os": "linux", "cpu": "arm" }, "sha512-EgIOZt7UildXKFEFvaiLNBXm+4ggQyGe3E5Z1QP9uRcJJs9omihOnm897FwOBQdCuMvI49iBgjFrkhH+wMJ2MA=="], 168 + 169 + "@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.0-beta.41", "", { "os": "linux", "cpu": "arm64" }, "sha512-F8bUwJq8v/JAU8HSwgF4dztoqJ+FjdyjuvX4//3+Fbe2we9UktFeZ27U4lRMXF1vxWtdV4ey6oCSqI7yUrSEeg=="], 170 + 171 + "@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.0-beta.41", "", { "os": "linux", "cpu": "arm64" }, "sha512-MioXcCIX/wB1pBnBoJx8q4OGucUAfC1+/X1ilKFsjDK05VwbLZGRgOVD5OJJpUQPK86DhQciNBrfOKDiatxNmg=="], 172 + 173 + "@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.0-beta.41", "", { "os": "linux", "cpu": "x64" }, "sha512-m66M61fizvRCwt5pOEiZQMiwBL9/y0bwU/+Kc4Ce/Pef6YfoEkR28y+DzN9rMdjo8Z28NXjsDPq9nH4mXnAP0g=="], 174 + 175 + "@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.0-beta.41", "", { "os": "linux", "cpu": "x64" }, "sha512-yRxlSfBvWnnfrdtJfvi9lg8xfG5mPuyoSHm0X01oiE8ArmLRvoJGHUTJydCYz+wbK2esbq5J4B4Tq9WAsOlP1Q=="], 176 + 177 + "@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.0.0-beta.41", "", { "os": "none", "cpu": "arm64" }, "sha512-PHVxYhBpi8UViS3/hcvQQb9RFqCtvFmFU1PvUoTRiUdBtgHA6fONNHU4x796lgzNlVSD3DO/MZNk1s5/ozSMQg=="], 178 + 179 + "@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.0-beta.41", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.0.5" }, "cpu": "none" }, "sha512-OAfcO37ME6GGWmj9qTaDT7jY4rM0T2z0/8ujdQIJQ2x2nl+ztO32EIwURfmXOK0U1tzkyuaKYvE34Pug/ucXlQ=="], 180 + 181 + "@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.0-beta.41", "", { "os": "win32", "cpu": "arm64" }, "sha512-NIYGuCcuXaq5BC4Q3upbiMBvmZsTsEPG9k/8QKQdmrch+ocSy5Jv9tdpdmXJyighKqm182nh/zBt+tSJkYoNlg=="], 182 + 183 + "@rolldown/binding-win32-ia32-msvc": ["@rolldown/binding-win32-ia32-msvc@1.0.0-beta.41", "", { "os": "win32", "cpu": "ia32" }, "sha512-kANdsDbE5FkEOb5NrCGBJBCaZ2Sabp3D7d4PRqMYJqyLljwh9mDyYyYSv5+QNvdAmifj+f3lviNEUUuUZPEFPw=="], 184 + 185 + "@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.0-beta.41", "", { "os": "win32", "cpu": "x64" }, "sha512-UlpxKmFdik0Y2VjZrgUCgoYArZJiZllXgIipdBRV1hw6uK45UbQabSTW6Kp6enuOu7vouYWftwhuxfpE8J2JAg=="], 186 + 187 + "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.47", "", {}, "sha512-8QagwMH3kNCuzD8EWL8R2YPW5e4OrHNSAHRFDdmFqEwEaD/KcNKjVoumo+gP2vW5eKB2UPbM6vTYiGZX0ixLnw=="], 188 + 189 + "@rollup/pluginutils": ["@rollup/pluginutils@4.2.1", "", { "dependencies": { "estree-walker": "^2.0.1", "picomatch": "^2.2.2" } }, "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ=="], 190 + 191 + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.53.3", "", { "os": "android", "cpu": "arm" }, "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w=="], 192 + 193 + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.53.3", "", { "os": "android", "cpu": "arm64" }, "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w=="], 194 + 195 + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.53.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA=="], 196 + 197 + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.53.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ=="], 198 + 199 + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.53.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w=="], 200 + 201 + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.53.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q=="], 202 + 203 + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.53.3", "", { "os": "linux", "cpu": "arm" }, "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw=="], 204 + 205 + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.53.3", "", { "os": "linux", "cpu": "arm" }, "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg=="], 206 + 207 + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.53.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w=="], 208 + 209 + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.53.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A=="], 210 + 211 + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.53.3", "", { "os": "linux", "cpu": "none" }, "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g=="], 212 + 213 + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.53.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw=="], 214 + 215 + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.53.3", "", { "os": "linux", "cpu": "none" }, "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g=="], 216 + 217 + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.53.3", "", { "os": "linux", "cpu": "none" }, "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A=="], 218 + 219 + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.53.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg=="], 220 + 221 + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.53.3", "", { "os": "linux", "cpu": "x64" }, "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w=="], 222 + 223 + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.53.3", "", { "os": "linux", "cpu": "x64" }, "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q=="], 224 + 225 + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.53.3", "", { "os": "none", "cpu": "arm64" }, "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw=="], 226 + 227 + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.53.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw=="], 228 + 229 + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.53.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA=="], 230 + 231 + "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.53.3", "", { "os": "win32", "cpu": "x64" }, "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg=="], 232 + 233 + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.53.3", "", { "os": "win32", "cpu": "x64" }, "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ=="], 234 + 235 + "@rushstack/node-core-library": ["@rushstack/node-core-library@5.19.0", "", { "dependencies": { "ajv": "~8.13.0", "ajv-draft-04": "~1.0.0", "ajv-formats": "~3.0.1", "fs-extra": "~11.3.0", "import-lazy": "~4.0.0", "jju": "~1.4.0", "resolve": "~1.22.1", "semver": "~7.5.4" }, "peerDependencies": { "@types/node": "*" }, "optionalPeers": ["@types/node"] }, "sha512-BxAopbeWBvNJ6VGiUL+5lbJXywTdsnMeOS8j57Cn/xY10r6sV/gbsTlfYKjzVCUBZATX2eRzJHSMCchsMTGN6A=="], 236 + 237 + "@rushstack/problem-matcher": ["@rushstack/problem-matcher@0.1.1", "", { "peerDependencies": { "@types/node": "*" }, "optionalPeers": ["@types/node"] }, "sha512-Fm5XtS7+G8HLcJHCWpES5VmeMyjAKaWeyZU5qPzZC+22mPlJzAsOxymHiWIfuirtPckX3aptWws+K2d0BzniJA=="], 238 + 239 + "@rushstack/rig-package": ["@rushstack/rig-package@0.6.0", "", { "dependencies": { "resolve": "~1.22.1", "strip-json-comments": "~3.1.1" } }, "sha512-ZQmfzsLE2+Y91GF15c65L/slMRVhF6Hycq04D4TwtdGaUAbIXXg9c5pKA5KFU7M4QMaihoobp9JJYpYcaY3zOw=="], 240 + 241 + "@rushstack/terminal": ["@rushstack/terminal@0.19.4", "", { "dependencies": { "@rushstack/node-core-library": "5.19.0", "@rushstack/problem-matcher": "0.1.1", "supports-color": "~8.1.1" }, "peerDependencies": { "@types/node": "*" }, "optionalPeers": ["@types/node"] }, "sha512-f4XQk02CrKfrMgyOfhYd3qWI944dLC21S4I/LUhrlAP23GTMDNG6EK5effQtFkISwUKCgD9vMBrJZaPSUquxWQ=="], 242 + 243 + "@rushstack/ts-command-line": ["@rushstack/ts-command-line@5.1.4", "", { "dependencies": { "@rushstack/terminal": "0.19.4", "@types/argparse": "1.0.38", "argparse": "~1.0.9", "string-argv": "~0.3.1" } }, "sha512-H0I6VdJ6sOUbktDFpP2VW5N29w8v4hRoNZOQz02vtEi6ZTYL1Ju8u+TcFiFawUDrUsx/5MQTUhd79uwZZVwVlA=="], 244 + 245 + "@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="], 246 + 247 + "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], 248 + 249 + "@types/argparse": ["@types/argparse@1.0.38", "", {}, "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA=="], 250 + 251 + "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], 252 + 253 + "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "^7.0.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="], 254 + 255 + "@types/babel__template": ["@types/babel__template@7.4.4", "", { "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A=="], 256 + 257 + "@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "^7.28.2" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="], 258 + 259 + "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], 260 + 261 + "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], 262 + 263 + "@types/node": ["@types/node@24.10.1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ=="], 264 + 265 + "@types/react": ["@types/react@19.2.7", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg=="], 266 + 267 + "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="], 268 + 269 + "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.48.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.48.1", "@typescript-eslint/type-utils": "8.48.1", "@typescript-eslint/utils": "8.48.1", "@typescript-eslint/visitor-keys": "8.48.1", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.48.1", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-X63hI1bxl5ohelzr0LY5coufyl0LJNthld+abwxpCoo6Gq+hSqhKwci7MUWkXo67mzgUK6YFByhmaHmUcuBJmA=="], 270 + 271 + "@typescript-eslint/parser": ["@typescript-eslint/parser@8.48.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.48.1", "@typescript-eslint/types": "8.48.1", "@typescript-eslint/typescript-estree": "8.48.1", "@typescript-eslint/visitor-keys": "8.48.1", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-PC0PDZfJg8sP7cmKe6L3QIL8GZwU5aRvUFedqSIpw3B+QjRSUZeeITC2M5XKeMXEzL6wccN196iy3JLwKNvDVA=="], 272 + 273 + "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.48.1", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.48.1", "@typescript-eslint/types": "^8.48.1", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-HQWSicah4s9z2/HifRPQ6b6R7G+SBx64JlFQpgSSHWPKdvCZX57XCbszg/bapbRsOEv42q5tayTYcEFpACcX1w=="], 274 + 275 + "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.48.1", "", { "dependencies": { "@typescript-eslint/types": "8.48.1", "@typescript-eslint/visitor-keys": "8.48.1" } }, "sha512-rj4vWQsytQbLxC5Bf4XwZ0/CKd362DkWMUkviT7DCS057SK64D5lH74sSGzhI6PDD2HCEq02xAP9cX68dYyg1w=="], 276 + 277 + "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.48.1", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-k0Jhs4CpEffIBm6wPaCXBAD7jxBtrHjrSgtfCjUvPp9AZ78lXKdTR8fxyZO5y4vWNlOvYXRtngSZNSn+H53Jkw=="], 278 + 279 + "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.48.1", "", { "dependencies": { "@typescript-eslint/types": "8.48.1", "@typescript-eslint/typescript-estree": "8.48.1", "@typescript-eslint/utils": "8.48.1", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-1jEop81a3LrJQLTf/1VfPQdhIY4PlGDBc/i67EVWObrtvcziysbLN3oReexHOM6N3jyXgCrkBsZpqwH0hiDOQg=="], 280 + 281 + "@typescript-eslint/types": ["@typescript-eslint/types@8.48.1", "", {}, "sha512-+fZ3LZNeiELGmimrujsDCT4CRIbq5oXdHe7chLiW8qzqyPMnn1puNstCrMNVAqwcl2FdIxkuJ4tOs/RFDBVc/Q=="], 282 + 283 + "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.48.1", "", { "dependencies": { "@typescript-eslint/project-service": "8.48.1", "@typescript-eslint/tsconfig-utils": "8.48.1", "@typescript-eslint/types": "8.48.1", "@typescript-eslint/visitor-keys": "8.48.1", "debug": "^4.3.4", "minimatch": "^9.0.4", "semver": "^7.6.0", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-/9wQ4PqaefTK6POVTjJaYS0bynCgzh6ClJHGSBj06XEHjkfylzB+A3qvyaXnErEZSaxhIo4YdyBgq6j4RysxDg=="], 284 + 285 + "@typescript-eslint/utils": ["@typescript-eslint/utils@8.48.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.48.1", "@typescript-eslint/types": "8.48.1", "@typescript-eslint/typescript-estree": "8.48.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-fAnhLrDjiVfey5wwFRwrweyRlCmdz5ZxXz2G/4cLn0YDLjTapmN4gcCsTBR1N2rWnZSDeWpYtgLDsJt+FpmcwA=="], 286 + 287 + "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.48.1", "", { "dependencies": { "@typescript-eslint/types": "8.48.1", "eslint-visitor-keys": "^4.2.1" } }, "sha512-BmxxndzEWhE4TIEEMBs8lP3MBWN3jFPs/p6gPm/wkv02o41hI6cq9AuSmGAaTTHPtA1FTi2jBre4A9rm5ZmX+Q=="], 288 + 289 + "@vitejs/plugin-react": ["@vitejs/plugin-react@5.1.1", "", { "dependencies": { "@babel/core": "^7.28.5", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.47", "@types/babel__core": "^7.20.5", "react-refresh": "^0.18.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-WQfkSw0QbQ5aJ2CHYw23ZGkqnRwqKHD/KYsMeTkZzPT4Jcf0DcBxBtwMJxnu6E7oxw5+JC6ZAiePgh28uJ1HBA=="], 290 + 291 + "@volar/language-core": ["@volar/language-core@2.4.26", "", { "dependencies": { "@volar/source-map": "2.4.26" } }, "sha512-hH0SMitMxnB43OZpyF1IFPS9bgb2I3bpCh76m2WEK7BE0A0EzpYsRp0CCH2xNKshr7kacU5TQBLYn4zj7CG60A=="], 292 + 293 + "@volar/source-map": ["@volar/source-map@2.4.26", "", {}, "sha512-JJw0Tt/kSFsIRmgTQF4JSt81AUSI1aEye5Zl65EeZ8H35JHnTvFGmpDOBn5iOxd48fyGE+ZvZBp5FcgAy/1Qhw=="], 294 + 295 + "@volar/typescript": ["@volar/typescript@2.4.26", "", { "dependencies": { "@volar/language-core": "2.4.26", "path-browserify": "^1.0.1", "vscode-uri": "^3.0.8" } }, "sha512-N87ecLD48Sp6zV9zID/5yuS1+5foj0DfuYGdQ6KHj/IbKvyKv1zNX6VCmnKYwtmHadEO6mFc2EKISiu3RDPAvA=="], 296 + 297 + "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], 298 + 299 + "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], 300 + 301 + "ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], 302 + 303 + "ajv-draft-04": ["ajv-draft-04@1.0.0", "", { "peerDependencies": { "ajv": "^8.5.0" }, "optionalPeers": ["ajv"] }, "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw=="], 304 + 305 + "ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="], 306 + 307 + "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], 308 + 309 + "ansis": ["ansis@4.2.0", "", {}, "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig=="], 310 + 311 + "argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], 312 + 313 + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], 314 + 315 + "baseline-browser-mapping": ["baseline-browser-mapping@2.8.32", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-OPz5aBThlyLFgxyhdwf/s2+8ab3OvT7AdTNvKHBwpXomIYeXqpUUuT8LrdtxZSsWJ4R4CU1un4XGh5Ez3nlTpw=="], 316 + 317 + "brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], 318 + 319 + "browserslist": ["browserslist@4.28.0", "", { "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", "electron-to-chromium": "^1.5.249", "node-releases": "^2.0.27", "update-browserslist-db": "^1.1.4" }, "bin": { "browserslist": "cli.js" } }, "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ=="], 320 + 321 + "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], 322 + 323 + "caniuse-lite": ["caniuse-lite@1.0.30001759", "", {}, "sha512-Pzfx9fOKoKvevQf8oCXoyNRQ5QyxJj+3O0Rqx2V5oxT61KGx8+n6hV/IUyJeifUci2clnmmKVpvtiqRzgiWjSw=="], 324 + 325 + "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], 326 + 327 + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], 328 + 329 + "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], 330 + 331 + "commondir": ["commondir@1.0.1", "", {}, "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg=="], 332 + 333 + "compare-versions": ["compare-versions@6.1.1", "", {}, "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg=="], 334 + 335 + "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], 336 + 337 + "confbox": ["confbox@0.2.2", "", {}, "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ=="], 338 + 339 + "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], 340 + 341 + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], 342 + 343 + "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], 344 + 345 + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], 346 + 347 + "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], 348 + 349 + "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], 350 + 351 + "diff": ["diff@8.0.2", "", {}, "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg=="], 352 + 353 + "electron-to-chromium": ["electron-to-chromium@1.5.263", "", {}, "sha512-DrqJ11Knd+lo+dv+lltvfMDLU27g14LMdH2b0O3Pio4uk0x+z7OR+JrmyacTPN2M8w3BrZ7/RTwG3R9B7irPlg=="], 354 + 355 + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], 356 + 357 + "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], 358 + 359 + "eslint": ["eslint@9.39.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.1", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "9.39.1", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g=="], 360 + 361 + "eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@5.2.0", "", { "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg=="], 362 + 363 + "eslint-plugin-react-refresh": ["eslint-plugin-react-refresh@0.4.24", "", { "peerDependencies": { "eslint": ">=8.40" } }, "sha512-nLHIW7TEq3aLrEYWpVaJ1dRgFR+wLDPN8e8FpYAql/bMV2oBEfC37K0gLEGgv9fy66juNShSMV8OkTqzltcG/w=="], 364 + 365 + "eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="], 366 + 367 + "eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="], 368 + 369 + "esm-env": ["esm-env@1.2.2", "", {}, "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA=="], 370 + 371 + "espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="], 372 + 373 + "esquery": ["esquery@1.6.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg=="], 374 + 375 + "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], 376 + 377 + "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], 378 + 379 + "estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], 380 + 381 + "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], 382 + 383 + "exsolve": ["exsolve@1.0.8", "", {}, "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA=="], 384 + 385 + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], 386 + 387 + "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], 388 + 389 + "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="], 390 + 391 + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], 392 + 393 + "file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="], 394 + 395 + "find-cache-dir": ["find-cache-dir@3.3.2", "", { "dependencies": { "commondir": "^1.0.1", "make-dir": "^3.0.2", "pkg-dir": "^4.1.0" } }, "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig=="], 396 + 397 + "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], 398 + 399 + "flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="], 400 + 401 + "flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="], 402 + 403 + "fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="], 404 + 405 + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], 406 + 407 + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], 408 + 409 + "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], 410 + 411 + "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], 412 + 413 + "globals": ["globals@16.5.0", "", {}, "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ=="], 414 + 415 + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], 416 + 417 + "graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="], 418 + 419 + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], 420 + 421 + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], 422 + 423 + "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], 424 + 425 + "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], 426 + 427 + "import-lazy": ["import-lazy@4.0.0", "", {}, "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw=="], 428 + 429 + "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], 430 + 431 + "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="], 432 + 433 + "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], 434 + 435 + "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], 436 + 437 + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], 438 + 439 + "jju": ["jju@1.4.0", "", {}, "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA=="], 440 + 441 + "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], 442 + 443 + "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], 444 + 445 + "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], 446 + 447 + "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], 448 + 449 + "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], 450 + 451 + "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], 452 + 453 + "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], 454 + 455 + "jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], 456 + 457 + "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], 458 + 459 + "kolorist": ["kolorist@1.8.0", "", {}, "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ=="], 460 + 461 + "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], 462 + 463 + "lightningcss": ["lightningcss@1.30.2", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.30.2", "lightningcss-darwin-arm64": "1.30.2", "lightningcss-darwin-x64": "1.30.2", "lightningcss-freebsd-x64": "1.30.2", "lightningcss-linux-arm-gnueabihf": "1.30.2", "lightningcss-linux-arm64-gnu": "1.30.2", "lightningcss-linux-arm64-musl": "1.30.2", "lightningcss-linux-x64-gnu": "1.30.2", "lightningcss-linux-x64-musl": "1.30.2", "lightningcss-win32-arm64-msvc": "1.30.2", "lightningcss-win32-x64-msvc": "1.30.2" } }, "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ=="], 464 + 465 + "lightningcss-android-arm64": ["lightningcss-android-arm64@1.30.2", "", { "os": "android", "cpu": "arm64" }, "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A=="], 466 + 467 + "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA=="], 468 + 469 + "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.30.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ=="], 470 + 471 + "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.30.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA=="], 472 + 473 + "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.30.2", "", { "os": "linux", "cpu": "arm" }, "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA=="], 474 + 475 + "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A=="], 476 + 477 + "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.30.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA=="], 478 + 479 + "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w=="], 480 + 481 + "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.30.2", "", { "os": "linux", "cpu": "x64" }, "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA=="], 482 + 483 + "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.30.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ=="], 484 + 485 + "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw=="], 486 + 487 + "local-pkg": ["local-pkg@1.1.2", "", { "dependencies": { "mlly": "^1.7.4", "pkg-types": "^2.3.0", "quansync": "^0.2.11" } }, "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A=="], 488 + 489 + "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], 490 + 491 + "lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="], 492 + 493 + "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], 494 + 495 + "lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="], 496 + 497 + "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], 498 + 499 + "make-dir": ["make-dir@3.1.0", "", { "dependencies": { "semver": "^6.0.0" } }, "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw=="], 500 + 501 + "minimatch": ["minimatch@10.0.3", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw=="], 502 + 503 + "mlly": ["mlly@1.8.0", "", { "dependencies": { "acorn": "^8.15.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "ufo": "^1.6.1" } }, "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g=="], 504 + 505 + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], 506 + 507 + "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], 508 + 509 + "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], 510 + 511 + "node-releases": ["node-releases@2.0.27", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="], 512 + 513 + "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], 514 + 515 + "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], 516 + 517 + "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], 518 + 519 + "p-try": ["p-try@2.2.0", "", {}, "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="], 520 + 521 + "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], 522 + 523 + "path-browserify": ["path-browserify@1.0.1", "", {}, "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="], 524 + 525 + "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], 526 + 527 + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], 528 + 529 + "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], 530 + 531 + "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], 532 + 533 + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], 534 + 535 + "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], 536 + 537 + "pkg-dir": ["pkg-dir@4.2.0", "", { "dependencies": { "find-up": "^4.0.0" } }, "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ=="], 538 + 539 + "pkg-types": ["pkg-types@2.3.0", "", { "dependencies": { "confbox": "^0.2.2", "exsolve": "^1.0.7", "pathe": "^2.0.3" } }, "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig=="], 540 + 541 + "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], 542 + 543 + "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], 544 + 545 + "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], 546 + 547 + "quansync": ["quansync@0.2.11", "", {}, "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA=="], 548 + 549 + "react": ["react@19.2.0", "", {}, "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ=="], 550 + 551 + "react-dom": ["react-dom@19.2.0", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.0" } }, "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ=="], 552 + 553 + "react-refresh": ["react-refresh@0.18.0", "", {}, "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw=="], 554 + 555 + "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], 556 + 557 + "resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="], 558 + 559 + "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], 560 + 561 + "rolldown": ["rolldown@1.0.0-beta.41", "", { "dependencies": { "@oxc-project/types": "=0.93.0", "@rolldown/pluginutils": "1.0.0-beta.41", "ansis": "=4.2.0" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.0-beta.41", "@rolldown/binding-darwin-arm64": "1.0.0-beta.41", "@rolldown/binding-darwin-x64": "1.0.0-beta.41", "@rolldown/binding-freebsd-x64": "1.0.0-beta.41", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.41", "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.41", "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.41", "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.41", "@rolldown/binding-linux-x64-musl": "1.0.0-beta.41", "@rolldown/binding-openharmony-arm64": "1.0.0-beta.41", "@rolldown/binding-wasm32-wasi": "1.0.0-beta.41", "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.41", "@rolldown/binding-win32-ia32-msvc": "1.0.0-beta.41", "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.41" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-U+NPR0Bkg3wm61dteD2L4nAM1U9dtaqVrpDXwC36IKRHpEO/Ubpid4Nijpa2imPchcVNHfxVFwSSMJdwdGFUbg=="], 562 + 563 + "rollup": ["rollup@4.53.3", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.53.3", "@rollup/rollup-android-arm64": "4.53.3", "@rollup/rollup-darwin-arm64": "4.53.3", "@rollup/rollup-darwin-x64": "4.53.3", "@rollup/rollup-freebsd-arm64": "4.53.3", "@rollup/rollup-freebsd-x64": "4.53.3", "@rollup/rollup-linux-arm-gnueabihf": "4.53.3", "@rollup/rollup-linux-arm-musleabihf": "4.53.3", "@rollup/rollup-linux-arm64-gnu": "4.53.3", "@rollup/rollup-linux-arm64-musl": "4.53.3", "@rollup/rollup-linux-loong64-gnu": "4.53.3", "@rollup/rollup-linux-ppc64-gnu": "4.53.3", "@rollup/rollup-linux-riscv64-gnu": "4.53.3", "@rollup/rollup-linux-riscv64-musl": "4.53.3", "@rollup/rollup-linux-s390x-gnu": "4.53.3", "@rollup/rollup-linux-x64-gnu": "4.53.3", "@rollup/rollup-linux-x64-musl": "4.53.3", "@rollup/rollup-openharmony-arm64": "4.53.3", "@rollup/rollup-win32-arm64-msvc": "4.53.3", "@rollup/rollup-win32-ia32-msvc": "4.53.3", "@rollup/rollup-win32-x64-gnu": "4.53.3", "@rollup/rollup-win32-x64-msvc": "4.53.3", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA=="], 564 + 565 + "rollup-plugin-typescript2": ["rollup-plugin-typescript2@0.36.0", "", { "dependencies": { "@rollup/pluginutils": "^4.1.2", "find-cache-dir": "^3.3.2", "fs-extra": "^10.0.0", "semver": "^7.5.4", "tslib": "^2.6.2" }, "peerDependencies": { "rollup": ">=1.26.3", "typescript": ">=2.4.0" } }, "sha512-NB2CSQDxSe9+Oe2ahZbf+B4bh7pHwjV5L+RSYpCu7Q5ROuN94F9b6ioWwKfz3ueL3KTtmX4o2MUH2cgHDIEUsw=="], 566 + 567 + "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], 568 + 569 + "semver": ["semver@7.5.4", "", { "dependencies": { "lru-cache": "^6.0.0" }, "bin": { "semver": "bin/semver.js" } }, "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA=="], 570 + 571 + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], 572 + 573 + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], 574 + 575 + "source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], 576 + 577 + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], 578 + 579 + "sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="], 580 + 581 + "string-argv": ["string-argv@0.3.2", "", {}, "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q=="], 582 + 583 + "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], 584 + 585 + "supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], 586 + 587 + "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], 588 + 589 + "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], 590 + 591 + "ts-api-utils": ["ts-api-utils@2.1.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ=="], 592 + 593 + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], 594 + 595 + "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], 596 + 597 + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], 598 + 599 + "typescript-eslint": ["typescript-eslint@8.48.1", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.48.1", "@typescript-eslint/parser": "8.48.1", "@typescript-eslint/typescript-estree": "8.48.1", "@typescript-eslint/utils": "8.48.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-FbOKN1fqNoXp1hIl5KYpObVrp0mCn+CLgn479nmu2IsRMrx2vyv74MmsBLVlhg8qVwNFGbXSp8fh1zp8pEoC2A=="], 600 + 601 + "ufo": ["ufo@1.6.1", "", {}, "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA=="], 602 + 603 + "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], 604 + 605 + "universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], 606 + 607 + "unplugin": ["unplugin@2.3.11", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "acorn": "^8.15.0", "picomatch": "^4.0.3", "webpack-virtual-modules": "^0.6.2" } }, "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww=="], 608 + 609 + "unplugin-dts": ["unplugin-dts@1.0.0-beta.6", "", { "dependencies": { "@rollup/pluginutils": "^5.1.4", "@volar/typescript": "^2.4.17", "compare-versions": "^6.1.1", "debug": "^4.4.0", "kolorist": "^1.8.0", "local-pkg": "^1.1.1", "magic-string": "^0.30.17", "unplugin": "^2.3.2" }, "peerDependencies": { "@microsoft/api-extractor": ">=7", "@rspack/core": "^1", "@vue/language-core": "~3.0.1", "esbuild": "*", "rolldown": "*", "rollup": ">=3", "typescript": ">=4", "vite": ">=3", "webpack": "^4 || ^5" }, "optionalPeers": ["@microsoft/api-extractor", "@rspack/core", "@vue/language-core", "esbuild", "rolldown", "rollup", "vite", "webpack"] }, "sha512-+xbFv5aVFtLZFNBAKI4+kXmd2h+T42/AaP8Bsp0YP/je/uOTN94Ame2Xt3e9isZS+Z7/hrLCLbsVJh+saqFMfQ=="], 610 + 611 + "update-browserslist-db": ["update-browserslist-db@1.1.4", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A=="], 612 + 613 + "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], 614 + 615 + "vite": ["rolldown-vite@7.1.14", "", { "dependencies": { "@oxc-project/runtime": "0.92.0", "fdir": "^6.5.0", "lightningcss": "^1.30.1", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rolldown": "1.0.0-beta.41", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "esbuild": "^0.25.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-eSiiRJmovt8qDJkGyZuLnbxAOAdie6NCmmd0NkTC0RJI9duiSBTfr8X2mBYJOUFzxQa2USaHmL99J9uMxkjCyw=="], 616 + 617 + "vscode-uri": ["vscode-uri@3.1.0", "", {}, "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ=="], 618 + 619 + "webpack-virtual-modules": ["webpack-virtual-modules@0.6.2", "", {}, "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="], 620 + 621 + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], 622 + 623 + "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], 624 + 625 + "yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], 626 + 627 + "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], 628 + 629 + "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], 630 + 631 + "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], 632 + 633 + "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], 634 + 635 + "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], 636 + 637 + "@eslint/config-array/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], 638 + 639 + "@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], 640 + 641 + "@eslint/eslintrc/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], 642 + 643 + "@microsoft/api-extractor/typescript": ["typescript@5.8.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ=="], 644 + 645 + "@microsoft/tsdoc-config/ajv": ["ajv@8.12.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", "uri-js": "^4.2.2" } }, "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA=="], 646 + 647 + "@rollup/pluginutils/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], 648 + 649 + "@rushstack/node-core-library/ajv": ["ajv@8.13.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", "uri-js": "^4.4.1" } }, "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA=="], 650 + 651 + "@rushstack/node-core-library/fs-extra": ["fs-extra@11.3.2", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A=="], 652 + 653 + "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], 654 + 655 + "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], 656 + 657 + "@typescript-eslint/typescript-estree/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], 658 + 659 + "ajv-formats/ajv": ["ajv@8.13.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", "uri-js": "^4.4.1" } }, "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA=="], 660 + 661 + "chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], 662 + 663 + "eslint/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], 664 + 665 + "js-yaml/argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], 666 + 667 + "make-dir/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], 668 + 669 + "mlly/pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], 670 + 671 + "pkg-dir/find-up": ["find-up@4.1.0", "", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], 672 + 673 + "rolldown/@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.41", "", {}, "sha512-ycMEPrS3StOIeb87BT3/+bu+blEtyvwQ4zmo2IcJQy0Rd1DAAhKksA0iUZ3MYSpJtjlPhg0Eo6mvVS6ggPhRbw=="], 674 + 675 + "rollup-plugin-typescript2/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], 676 + 677 + "unplugin-dts/@rollup/pluginutils": ["@rollup/pluginutils@5.3.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q=="], 678 + 679 + "@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], 680 + 681 + "@microsoft/tsdoc-config/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], 682 + 683 + "@rushstack/node-core-library/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], 684 + 685 + "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], 686 + 687 + "ajv-formats/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], 688 + 689 + "mlly/pkg-types/confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], 690 + 691 + "pkg-dir/find-up/locate-path": ["locate-path@5.0.0", "", { "dependencies": { "p-locate": "^4.1.0" } }, "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="], 692 + 693 + "pkg-dir/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="], 694 + 695 + "pkg-dir/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], 696 + } 697 + }
+325 -107
lib/components/BlueskyPost.tsx
··· 7 7 import { useBlob } from "../hooks/useBlob"; 8 8 import { BLUESKY_PROFILE_COLLECTION } from "./BlueskyProfile"; 9 9 import { getAvatarCid } from "../utils/profile"; 10 - import { formatDidForLabel } from "../utils/at-uri"; 10 + import { formatDidForLabel, parseAtUri } from "../utils/at-uri"; 11 + import { isBlobWithCdn } from "../utils/blob"; 11 12 12 13 /** 13 14 * Props for rendering a single Bluesky post with optional customization hooks. ··· 38 39 * React node displayed while the post fetch is actively loading. 39 40 */ 40 41 loadingIndicator?: React.ReactNode; 41 - /** 42 - * Preferred color scheme to pass through to renderers. 43 - */ 44 - colorScheme?: "light" | "dark" | "system"; 42 + 45 43 /** 46 44 * Whether the default renderer should show the Bluesky icon. 47 45 * Defaults to `true`. ··· 52 50 * Defaults to `'timestamp'`. 53 51 */ 54 52 iconPlacement?: "cardBottomRight" | "timestamp" | "linkInline"; 53 + /** 54 + * Controls whether to show the parent post if this post is a reply. 55 + * Defaults to `false`. 56 + */ 57 + showParent?: boolean; 58 + /** 59 + * Controls whether to recursively show all parent posts to the root. 60 + * Only applies when `showParent` is `true`. Defaults to `false`. 61 + */ 62 + recursiveParent?: boolean; 55 63 } 56 64 57 65 /** ··· 75 83 */ 76 84 authorHandle: string; 77 85 /** 86 + * The author's display name from their profile. 87 + */ 88 + authorDisplayName?: string; 89 + /** 78 90 * The DID that owns the post record. 79 91 */ 80 92 authorDid: string; ··· 82 94 * Resolved URL for the author's avatar blob, if available. 83 95 */ 84 96 avatarUrl?: string; 85 - /** 86 - * Preferred color scheme bubbled down to children. 87 - */ 88 - colorScheme?: "light" | "dark" | "system"; 97 + 89 98 /** 90 99 * Placement strategy for the Bluesky icon. 91 100 */ ··· 102 111 * Optional override for the rendered embed contents. 103 112 */ 104 113 embed?: React.ReactNode; 114 + /** 115 + * Whether this post is part of a thread. 116 + */ 117 + isInThread?: boolean; 118 + /** 119 + * Depth of this post in a thread (0 = root, 1 = first reply, etc.). 120 + */ 121 + threadDepth?: number; 122 + /** 123 + * Whether to show border even when in thread context. 124 + */ 125 + showThreadBorder?: boolean; 105 126 }; 106 127 107 - /** NSID for the canonical Bluesky feed post collection. */ 108 128 export const BLUESKY_POST_COLLECTION = "app.bsky.feed.post"; 109 129 130 + const threadContainerStyle: React.CSSProperties = { 131 + display: "flex", 132 + flexDirection: "column", 133 + maxWidth: "600px", 134 + width: "100%", 135 + background: "var(--atproto-color-bg)", 136 + position: "relative", 137 + borderRadius: "12px", 138 + overflow: "hidden" 139 + }; 140 + 141 + const parentPostStyle: React.CSSProperties = { 142 + position: "relative", 143 + }; 144 + 145 + const replyPostStyle: React.CSSProperties = { 146 + position: "relative", 147 + }; 148 + 149 + const loadingStyle: React.CSSProperties = { 150 + padding: "24px 18px", 151 + fontSize: "14px", 152 + textAlign: "center", 153 + color: "var(--atproto-color-text-secondary)", 154 + }; 155 + 110 156 /** 111 157 * Fetches a Bluesky feed post, resolves metadata such as author handle and avatar, 112 158 * and renders it via a customizable renderer component. 113 159 * 114 160 * @param did - DID of the repository that stores the post. 115 161 * @param rkey - Record key for the post within the feed collection. 162 + * @param record - Prefetched record for the post. 116 163 * @param renderer - Optional renderer component to override the default. 117 164 * @param fallback - Node rendered before the first fetch attempt resolves. 118 165 * @param loadingIndicator - Node rendered while the post is loading. 119 - * @param colorScheme - Preferred color scheme forwarded to downstream components. 120 166 * @param showIcon - Controls whether the Bluesky icon should render alongside the post. Defaults to `true`. 121 167 * @param iconPlacement - Determines where the icon is positioned in the rendered post. Defaults to `'timestamp'`. 122 168 * @returns A component that renders loading/fallback states and the resolved post. 123 169 */ 124 - export const BlueskyPost: React.FC<BlueskyPostProps> = ({ 125 - did: handleOrDid, 126 - rkey, 127 - record, 128 - renderer, 129 - fallback, 130 - loadingIndicator, 131 - colorScheme, 132 - showIcon = true, 133 - iconPlacement = "timestamp", 134 - }) => { 135 - const { 136 - did: resolvedDid, 137 - handle, 138 - loading: resolvingIdentity, 139 - error: resolutionError, 140 - } = useDidResolution(handleOrDid); 141 - const repoIdentifier = resolvedDid ?? handleOrDid; 142 - const { record: profile } = useAtProtoRecord<ProfileRecord>({ 143 - did: repoIdentifier, 144 - collection: BLUESKY_PROFILE_COLLECTION, 145 - rkey: "self", 146 - }); 147 - const avatarCid = getAvatarCid(profile); 170 + export const BlueskyPost: React.FC<BlueskyPostProps> = React.memo( 171 + ({ 172 + did: handleOrDid, 173 + rkey, 174 + record, 175 + renderer, 176 + fallback, 177 + loadingIndicator, 178 + showIcon = true, 179 + iconPlacement = "timestamp", 180 + showParent = false, 181 + recursiveParent = false, 182 + }) => { 183 + const { 184 + did: resolvedDid, 185 + handle, 186 + loading: resolvingIdentity, 187 + error: resolutionError, 188 + } = useDidResolution(handleOrDid); 189 + const repoIdentifier = resolvedDid ?? handleOrDid; 190 + const { record: profile } = useAtProtoRecord<ProfileRecord>({ 191 + did: repoIdentifier, 192 + collection: BLUESKY_PROFILE_COLLECTION, 193 + rkey: "self", 194 + }); 195 + const avatar = profile?.avatar; 196 + const avatarCdnUrl = isBlobWithCdn(avatar) ? avatar.cdnUrl : undefined; 197 + const avatarCid = avatarCdnUrl ? undefined : getAvatarCid(profile); 198 + const authorDisplayName = profile?.displayName; 148 199 149 - const Comp: React.ComponentType<BlueskyPostRendererInjectedProps> = useMemo( 150 - () => renderer ?? ((props) => <BlueskyPostRenderer {...props} />), 151 - [renderer] 152 - ); 200 + const { 201 + record: fetchedRecord, 202 + loading: currentLoading, 203 + error: currentError, 204 + } = useAtProtoRecord<FeedPostRecord>({ 205 + did: showParent && !record ? repoIdentifier : "", 206 + collection: showParent && !record ? BLUESKY_POST_COLLECTION : "", 207 + rkey: showParent && !record ? rkey : "", 208 + }); 153 209 154 - const displayHandle = 155 - handle ?? (handleOrDid.startsWith("did:") ? undefined : handleOrDid); 156 - const authorHandle = 157 - displayHandle ?? formatDidForLabel(resolvedDid ?? handleOrDid); 158 - const atUri = resolvedDid 159 - ? `at://${resolvedDid}/${BLUESKY_POST_COLLECTION}/${rkey}` 160 - : undefined; 210 + const currentRecord = record ?? fetchedRecord; 161 211 162 - const Wrapped = useMemo(() => { 163 - const WrappedComponent: React.FC<{ 164 - record: FeedPostRecord; 165 - loading: boolean; 166 - error?: Error; 167 - }> = (props) => { 168 - const { url: avatarUrl } = useBlob(repoIdentifier, avatarCid); 212 + const parentUri = currentRecord?.reply?.parent?.uri; 213 + const parsedParentUri = parentUri ? parseAtUri(parentUri) : null; 214 + const parentDid = parsedParentUri?.did; 215 + const parentRkey = parsedParentUri?.rkey; 216 + 217 + const { 218 + record: parentRecord, 219 + loading: parentLoading, 220 + error: parentError, 221 + } = useAtProtoRecord<FeedPostRecord>({ 222 + did: showParent && parentDid ? parentDid : "", 223 + collection: showParent && parentDid ? BLUESKY_POST_COLLECTION : "", 224 + rkey: showParent && parentRkey ? parentRkey : "", 225 + }); 226 + 227 + const Comp: React.ComponentType<BlueskyPostRendererInjectedProps> = 228 + useMemo( 229 + () => 230 + renderer ?? ((props) => <BlueskyPostRenderer {...props} />), 231 + [renderer], 232 + ); 233 + 234 + const displayHandle = 235 + handle ?? 236 + (handleOrDid.startsWith("did:") ? undefined : handleOrDid); 237 + const authorHandle = 238 + displayHandle ?? formatDidForLabel(resolvedDid ?? handleOrDid); 239 + const atUri = resolvedDid 240 + ? `at://${resolvedDid}/${BLUESKY_POST_COLLECTION}/${rkey}` 241 + : undefined; 242 + 243 + const Wrapped = useMemo(() => { 244 + const WrappedComponent: React.FC<{ 245 + record: FeedPostRecord; 246 + loading: boolean; 247 + error?: Error; 248 + }> = (props) => { 249 + const { url: avatarUrlFromBlob } = useBlob( 250 + repoIdentifier, 251 + avatarCid, 252 + ); 253 + const avatarUrl = avatarCdnUrl || avatarUrlFromBlob; 254 + return ( 255 + <Comp 256 + {...props} 257 + authorHandle={authorHandle} 258 + authorDisplayName={authorDisplayName} 259 + authorDid={repoIdentifier} 260 + avatarUrl={avatarUrl} 261 + iconPlacement={iconPlacement} 262 + showIcon={showIcon} 263 + atUri={atUri} 264 + isInThread 265 + threadDepth={showParent ? 1 : 0} 266 + showThreadBorder={!showParent && !!props.record?.reply?.parent} 267 + /> 268 + ); 269 + }; 270 + WrappedComponent.displayName = "BlueskyPostWrappedRenderer"; 271 + return WrappedComponent; 272 + }, [ 273 + Comp, 274 + repoIdentifier, 275 + avatarCid, 276 + avatarCdnUrl, 277 + authorHandle, 278 + authorDisplayName, 279 + iconPlacement, 280 + showIcon, 281 + atUri, 282 + showParent, 283 + ]); 284 + 285 + const WrappedWithoutIcon = useMemo(() => { 286 + const WrappedComponent: React.FC<{ 287 + record: FeedPostRecord; 288 + loading: boolean; 289 + error?: Error; 290 + }> = (props) => { 291 + const { url: avatarUrlFromBlob } = useBlob( 292 + repoIdentifier, 293 + avatarCid, 294 + ); 295 + const avatarUrl = avatarCdnUrl || avatarUrlFromBlob; 296 + return ( 297 + <Comp 298 + {...props} 299 + authorHandle={authorHandle} 300 + authorDisplayName={authorDisplayName} 301 + authorDid={repoIdentifier} 302 + avatarUrl={avatarUrl} 303 + iconPlacement={iconPlacement} 304 + showIcon={false} 305 + atUri={atUri} 306 + isInThread 307 + threadDepth={showParent ? 1 : 0} 308 + showThreadBorder={!showParent && !!props.record?.reply?.parent} 309 + /> 310 + ); 311 + }; 312 + WrappedComponent.displayName = "BlueskyPostWrappedRendererWithoutIcon"; 313 + return WrappedComponent; 314 + }, [ 315 + Comp, 316 + repoIdentifier, 317 + avatarCid, 318 + avatarCdnUrl, 319 + authorHandle, 320 + authorDisplayName, 321 + iconPlacement, 322 + atUri, 323 + showParent, 324 + ]); 325 + 326 + if (!displayHandle && resolvingIdentity) { 327 + return <div style={{ padding: 8 }}>Resolving handleโ€ฆ</div>; 328 + } 329 + if (!displayHandle && resolutionError) { 169 330 return ( 170 - <Comp 171 - {...props} 172 - authorHandle={authorHandle} 173 - authorDid={repoIdentifier} 174 - avatarUrl={avatarUrl} 175 - colorScheme={colorScheme} 176 - iconPlacement={iconPlacement} 177 - showIcon={showIcon} 178 - atUri={atUri} 331 + <div style={{ padding: 8, color: "crimson" }}> 332 + Could not resolve handle. 333 + </div> 334 + ); 335 + } 336 + 337 + const renderMainPost = (mainRecord?: FeedPostRecord) => { 338 + if (mainRecord !== undefined) { 339 + return ( 340 + <AtProtoRecord<FeedPostRecord> 341 + record={mainRecord} 342 + renderer={Wrapped} 343 + fallback={fallback} 344 + loadingIndicator={loadingIndicator} 345 + /> 346 + ); 347 + } 348 + 349 + return ( 350 + <AtProtoRecord<FeedPostRecord> 351 + did={repoIdentifier} 352 + collection={BLUESKY_POST_COLLECTION} 353 + rkey={rkey} 354 + renderer={Wrapped} 355 + fallback={fallback} 356 + loadingIndicator={loadingIndicator} 179 357 /> 180 358 ); 181 359 }; 182 - WrappedComponent.displayName = "BlueskyPostWrappedRenderer"; 183 - return WrappedComponent; 184 - }, [ 185 - Comp, 186 - repoIdentifier, 187 - avatarCid, 188 - authorHandle, 189 - colorScheme, 190 - iconPlacement, 191 - showIcon, 192 - atUri, 193 - ]); 194 360 195 - if (!displayHandle && resolvingIdentity) { 196 - return <div style={{ padding: 8 }}>Resolving handleโ€ฆ</div>; 197 - } 198 - if (!displayHandle && resolutionError) { 199 - return ( 200 - <div style={{ padding: 8, color: "crimson" }}> 201 - Could not resolve handle. 202 - </div> 203 - ); 204 - } 361 + const renderMainPostWithoutIcon = (mainRecord?: FeedPostRecord) => { 362 + if (mainRecord !== undefined) { 363 + return ( 364 + <AtProtoRecord<FeedPostRecord> 365 + record={mainRecord} 366 + renderer={WrappedWithoutIcon} 367 + fallback={fallback} 368 + loadingIndicator={loadingIndicator} 369 + /> 370 + ); 371 + } 205 372 206 - // When record is provided, pass it directly to skip fetching 207 - if (record) { 208 - return ( 209 - <AtProtoRecord<FeedPostRecord> 210 - record={record} 211 - renderer={Wrapped} 212 - fallback={fallback} 213 - loadingIndicator={loadingIndicator} 214 - /> 215 - ); 216 - } 373 + return ( 374 + <AtProtoRecord<FeedPostRecord> 375 + did={repoIdentifier} 376 + collection={BLUESKY_POST_COLLECTION} 377 + rkey={rkey} 378 + renderer={WrappedWithoutIcon} 379 + fallback={fallback} 380 + loadingIndicator={loadingIndicator} 381 + /> 382 + ); 383 + }; 217 384 218 - // Otherwise fetch the record using did, collection, and rkey 219 - return ( 220 - <AtProtoRecord<FeedPostRecord> 221 - did={repoIdentifier} 222 - collection={BLUESKY_POST_COLLECTION} 223 - rkey={rkey} 224 - renderer={Wrapped} 225 - fallback={fallback} 226 - loadingIndicator={loadingIndicator} 227 - /> 228 - ); 229 - }; 385 + if (showParent) { 386 + if (currentLoading || (parentLoading && !parentRecord)) { 387 + return ( 388 + <div style={threadContainerStyle}> 389 + <div style={loadingStyle}>Loading threadโ€ฆ</div> 390 + </div> 391 + ); 392 + } 393 + 394 + if (currentError) { 395 + return ( 396 + <div style={{ padding: 8, color: "crimson" }}> 397 + Failed to load post. 398 + </div> 399 + ); 400 + } 401 + 402 + if (!parentDid || !parentRkey) { 403 + return renderMainPost(record); 404 + } 405 + 406 + if (parentError) { 407 + return ( 408 + <div style={{ padding: 8, color: "crimson" }}> 409 + Failed to load parent post. 410 + </div> 411 + ); 412 + } 413 + 414 + return ( 415 + <div style={threadContainerStyle}> 416 + <div style={parentPostStyle}> 417 + {recursiveParent && parentRecord?.reply?.parent?.uri ? ( 418 + <BlueskyPost 419 + did={parentDid} 420 + rkey={parentRkey} 421 + record={parentRecord} 422 + showParent={true} 423 + recursiveParent={true} 424 + showIcon={showIcon} 425 + iconPlacement={iconPlacement} 426 + /> 427 + ) : ( 428 + <BlueskyPost 429 + did={parentDid} 430 + rkey={parentRkey} 431 + record={parentRecord} 432 + showIcon={showIcon} 433 + iconPlacement={iconPlacement} 434 + /> 435 + )} 436 + </div> 437 + 438 + <div style={replyPostStyle}> 439 + {renderMainPostWithoutIcon(record || currentRecord)} 440 + </div> 441 + </div> 442 + ); 443 + } 444 + 445 + return renderMainPost(record); 446 + }, 447 + ); 230 448 231 449 export default BlueskyPost;
+355 -268
lib/components/BlueskyPostList.tsx
··· 4 4 type AuthorFeedReason, 5 5 type ReplyParentInfo, 6 6 } from "../hooks/usePaginatedRecords"; 7 - import { useColorScheme } from "../hooks/useColorScheme"; 8 - import type { FeedPostRecord } from "../types/bluesky"; 7 + import type { FeedPostRecord, ProfileRecord } from "../types/bluesky"; 9 8 import { useDidResolution } from "../hooks/useDidResolution"; 10 9 import { BlueskyIcon } from "./BlueskyIcon"; 11 10 import { parseAtUri } from "../utils/at-uri"; 11 + import { useAtProto } from "../providers/AtProtoProvider"; 12 + import { useAtProtoRecord } from "../hooks/useAtProtoRecord"; 13 + import { useBlob } from "../hooks/useBlob"; 14 + import { getAvatarCid } from "../utils/profile"; 15 + import { isBlobWithCdn } from "../utils/blob"; 16 + import { BLUESKY_PROFILE_COLLECTION } from "./BlueskyProfile"; 17 + import { RichText as BlueskyRichText } from "./RichText"; 12 18 13 19 /** 14 20 * Options for rendering a paginated list of Bluesky posts. ··· 26 32 * Enables pagination controls when `true`. Defaults to `true`. 27 33 */ 28 34 enablePagination?: boolean; 29 - /** 30 - * Preferred color scheme passed through to styling helpers. 31 - * Defaults to `'system'` which follows the OS preference. 32 - */ 33 - colorScheme?: "light" | "dark" | "system"; 34 35 } 35 36 36 37 /** ··· 39 40 * @param did - DID whose posts should be displayed. 40 41 * @param limit - Maximum number of posts per page. Default `5`. 41 42 * @param enablePagination - Whether pagination controls should render. Default `true`. 42 - * @param colorScheme - Preferred color scheme used for styling. Default `'system'`. 43 43 * @returns A card-like list element with loading, empty, and error handling. 44 44 */ 45 - export const BlueskyPostList: React.FC<BlueskyPostListProps> = ({ 45 + export const BlueskyPostList: React.FC<BlueskyPostListProps> = React.memo(({ 46 46 did, 47 47 limit = 5, 48 48 enablePagination = true, 49 - colorScheme = "system", 50 49 }) => { 51 - const scheme = useColorScheme(colorScheme); 52 - const palette: ListPalette = scheme === "dark" ? darkPalette : lightPalette; 53 50 const { handle: resolvedHandle, did: resolvedDid } = useDidResolution(did); 54 51 const actorLabel = resolvedHandle ?? formatDid(did); 55 52 const actorPath = resolvedHandle ?? resolvedDid ?? did; ··· 82 79 83 80 if (error) 84 81 return ( 85 - <div style={{ padding: 8, color: "crimson" }}> 82 + <div role="alert" style={{ padding: 8, color: "crimson" }}> 86 83 Failed to load posts. 87 84 </div> 88 85 ); 89 86 90 87 return ( 91 - <div style={{ ...listStyles.card, ...palette.card }}> 92 - <div style={{ ...listStyles.header, ...palette.header }}> 88 + <div style={{ ...listStyles.card, background: `var(--atproto-color-bg)`, borderWidth: "1px", borderStyle: "solid", borderColor: `var(--atproto-color-border)` }}> 89 + <div style={{ ...listStyles.header, background: `var(--atproto-color-bg-elevated)`, color: `var(--atproto-color-text)` }}> 93 90 <div style={listStyles.headerInfo}> 94 91 <div style={listStyles.headerIcon}> 95 92 <BlueskyIcon size={20} /> ··· 99 96 <span 100 97 style={{ 101 98 ...listStyles.subtitle, 102 - ...palette.subtitle, 99 + color: `var(--atproto-color-text-secondary)`, 103 100 }} 104 101 > 105 102 @{actorLabel} ··· 108 105 </div> 109 106 {pageLabel && ( 110 107 <span 111 - style={{ ...listStyles.pageMeta, ...palette.pageMeta }} 108 + style={{ ...listStyles.pageMeta, color: `var(--atproto-color-text-secondary)` }} 112 109 > 113 110 {pageLabel} 114 111 </span> ··· 116 113 </div> 117 114 <div style={listStyles.items}> 118 115 {loading && records.length === 0 && ( 119 - <div style={{ ...listStyles.empty, ...palette.empty }}> 116 + <div style={{ ...listStyles.empty, color: `var(--atproto-color-text-secondary)` }}> 120 117 Loading postsโ€ฆ 121 118 </div> 122 119 )} ··· 126 123 record={record.value} 127 124 rkey={record.rkey} 128 125 did={actorPath} 126 + uri={record.uri} 129 127 reason={record.reason} 130 128 replyParent={record.replyParent} 131 - palette={palette} 132 129 hasDivider={idx < records.length - 1} 133 130 /> 134 131 ))} 135 132 {!loading && records.length === 0 && ( 136 - <div style={{ ...listStyles.empty, ...palette.empty }}> 133 + <div style={{ ...listStyles.empty, color: `var(--atproto-color-text-secondary)` }}> 137 134 No posts found. 138 135 </div> 139 136 )} 140 137 </div> 141 138 {enablePagination && ( 142 - <div style={{ ...listStyles.footer, ...palette.footer }}> 139 + <div style={{ ...listStyles.footer, borderTopColor: `var(--atproto-color-border)`, color: `var(--atproto-color-text)` }}> 143 140 <button 144 141 type="button" 145 142 style={{ 146 - ...listStyles.navButton, 147 - ...palette.navButton, 143 + ...listStyles.pageButton, 144 + background: `var(--atproto-color-button-bg)`, 145 + color: `var(--atproto-color-button-text)`, 148 146 cursor: hasPrev ? "pointer" : "not-allowed", 149 147 opacity: hasPrev ? 1 : 0.5, 150 148 }} ··· 157 155 <span 158 156 style={{ 159 157 ...listStyles.pageChipActive, 160 - ...palette.pageChipActive, 158 + color: `var(--atproto-color-button-text)`, 159 + background: `var(--atproto-color-button-bg)`, 160 + borderWidth: "1px", 161 + borderStyle: "solid", 162 + borderColor: `var(--atproto-color-button-bg)`, 161 163 }} 162 164 > 163 165 {pageIndex + 1} ··· 166 168 <span 167 169 style={{ 168 170 ...listStyles.pageChip, 169 - ...palette.pageChip, 171 + color: `var(--atproto-color-text-secondary)`, 172 + borderWidth: "1px", 173 + borderStyle: "solid", 174 + borderColor: `var(--atproto-color-border)`, 175 + background: `var(--atproto-color-bg)`, 170 176 }} 171 177 > 172 178 {pageIndex + 2} ··· 176 182 <button 177 183 type="button" 178 184 style={{ 179 - ...listStyles.navButton, 180 - ...palette.navButton, 185 + ...listStyles.pageButton, 186 + background: `var(--atproto-color-button-bg)`, 187 + color: `var(--atproto-color-button-text)`, 181 188 cursor: hasNext ? "pointer" : "not-allowed", 182 189 opacity: hasNext ? 1 : 0.5, 183 190 }} ··· 190 197 )} 191 198 {loading && records.length > 0 && ( 192 199 <div 193 - style={{ ...listStyles.loadingBar, ...palette.loadingBar }} 200 + style={{ ...listStyles.loadingBar, background: `var(--atproto-color-bg-elevated)`, color: `var(--atproto-color-text-secondary)` }} 194 201 > 195 202 Updatingโ€ฆ 196 203 </div> 197 204 )} 198 205 </div> 199 206 ); 200 - }; 207 + }); 201 208 202 209 interface ListRowProps { 203 210 record: FeedPostRecord; 204 211 rkey: string; 205 212 did: string; 213 + uri?: string; 206 214 reason?: AuthorFeedReason; 207 215 replyParent?: ReplyParentInfo; 208 - palette: ListPalette; 209 216 hasDivider: boolean; 210 217 } 211 218 ··· 213 220 record, 214 221 rkey, 215 222 did, 223 + uri, 216 224 reason, 217 225 replyParent, 218 - palette, 219 226 hasDivider, 220 227 }) => { 228 + const { blueskyAppBaseUrl } = useAtProto(); 221 229 const text = record.text?.trim() ?? ""; 222 230 const relative = record.createdAt 223 231 ? formatRelativeTime(record.createdAt) ··· 225 233 const absolute = record.createdAt 226 234 ? new Date(record.createdAt).toLocaleString() 227 235 : undefined; 228 - const href = `https://bsky.app/profile/${did}/post/${rkey}`; 229 - const repostLabel = 230 - reason?.$type === "app.bsky.feed.defs#reasonRepost" 231 - ? `${formatActor(reason.by) ?? "Someone"} reposted` 232 - : undefined; 236 + 237 + // Parse the URI to get the actual post's DID and rkey 238 + const parsedUri = uri ? parseAtUri(uri) : undefined; 239 + const postDid = parsedUri?.did ?? did; 240 + const postRkey = parsedUri?.rkey ?? rkey; 241 + const href = `${blueskyAppBaseUrl}/profile/${postDid}/post/${postRkey}`; 242 + 243 + // Author profile and avatar 244 + const { handle: authorHandle } = useDidResolution(postDid); 245 + const { record: authorProfile } = useAtProtoRecord<ProfileRecord>({ 246 + did: postDid, 247 + collection: BLUESKY_PROFILE_COLLECTION, 248 + rkey: "self", 249 + }); 250 + const authorDisplayName = authorProfile?.displayName; 251 + const authorAvatar = authorProfile?.avatar; 252 + const authorAvatarCdnUrl = isBlobWithCdn(authorAvatar) ? authorAvatar.cdnUrl : undefined; 253 + const authorAvatarCid = authorAvatarCdnUrl ? undefined : getAvatarCid(authorProfile); 254 + const { url: authorAvatarUrl } = useBlob( 255 + postDid, 256 + authorAvatarCid, 257 + ); 258 + const finalAuthorAvatarUrl = authorAvatarCdnUrl ?? authorAvatarUrl; 259 + 260 + // Repost metadata 261 + const isRepost = reason?.$type === "app.bsky.feed.defs#reasonRepost"; 262 + const reposterDid = reason?.by?.did; 263 + const { handle: reposterHandle } = useDidResolution(reposterDid); 264 + const { record: reposterProfile } = useAtProtoRecord<ProfileRecord>({ 265 + did: reposterDid, 266 + collection: BLUESKY_PROFILE_COLLECTION, 267 + rkey: "self", 268 + }); 269 + const reposterDisplayName = reposterProfile?.displayName; 270 + const reposterAvatar = reposterProfile?.avatar; 271 + const reposterAvatarCdnUrl = isBlobWithCdn(reposterAvatar) ? reposterAvatar.cdnUrl : undefined; 272 + const reposterAvatarCid = reposterAvatarCdnUrl ? undefined : getAvatarCid(reposterProfile); 273 + const { url: reposterAvatarUrl } = useBlob( 274 + reposterDid, 275 + reposterAvatarCid, 276 + ); 277 + const finalReposterAvatarUrl = reposterAvatarCdnUrl ?? reposterAvatarUrl; 278 + 279 + // Reply metadata 233 280 const parentUri = replyParent?.uri ?? record.reply?.parent?.uri; 234 - const parentDid = 235 - replyParent?.author?.did ?? 236 - (parentUri ? parseAtUri(parentUri)?.did : undefined); 237 - const { handle: resolvedReplyHandle } = useDidResolution( 281 + const parentDid = replyParent?.author?.did ?? (parentUri ? parseAtUri(parentUri)?.did : undefined); 282 + const { handle: parentHandle } = useDidResolution( 238 283 replyParent?.author?.handle ? undefined : parentDid, 239 284 ); 240 - const replyLabel = formatReplyTarget( 241 - parentUri, 242 - replyParent, 243 - resolvedReplyHandle, 285 + const { record: parentProfile } = useAtProtoRecord<ProfileRecord>({ 286 + did: parentDid, 287 + collection: BLUESKY_PROFILE_COLLECTION, 288 + rkey: "self", 289 + }); 290 + const parentAvatar = parentProfile?.avatar; 291 + const parentAvatarCdnUrl = isBlobWithCdn(parentAvatar) ? parentAvatar.cdnUrl : undefined; 292 + const parentAvatarCid = parentAvatarCdnUrl ? undefined : getAvatarCid(parentProfile); 293 + const { url: parentAvatarUrl } = useBlob( 294 + parentDid, 295 + parentAvatarCid, 244 296 ); 297 + const finalParentAvatarUrl = parentAvatarCdnUrl ?? parentAvatarUrl; 298 + 299 + const isReply = !!parentUri; 300 + const replyTargetHandle = replyParent?.author?.handle ?? parentHandle; 301 + 302 + const postPreview = text.slice(0, 100); 303 + const ariaLabel = text 304 + ? `Post by ${authorDisplayName ?? authorHandle ?? did}: ${postPreview}${text.length > 100 ? "..." : ""}` 305 + : `Post by ${authorDisplayName ?? authorHandle ?? did}`; 245 306 246 307 return ( 247 - <a 248 - href={href} 249 - target="_blank" 250 - rel="noopener noreferrer" 308 + <div 251 309 style={{ 252 - ...listStyles.row, 253 - ...palette.row, 254 - borderBottom: hasDivider 255 - ? `1px solid ${palette.divider}` 256 - : "none", 310 + ...listStyles.rowContainer, 311 + borderBottom: hasDivider ? `1px solid var(--atproto-color-border)` : "none", 257 312 }} 258 313 > 259 - {repostLabel && ( 260 - <span style={{ ...listStyles.rowMeta, ...palette.rowMeta }}> 261 - {repostLabel} 262 - </span> 263 - )} 264 - {replyLabel && ( 265 - <span style={{ ...listStyles.rowMeta, ...palette.rowMeta }}> 266 - {replyLabel} 267 - </span> 268 - )} 269 - {relative && ( 270 - <span 271 - style={{ ...listStyles.rowTime, ...palette.rowTime }} 272 - title={absolute} 273 - > 274 - {relative} 275 - </span> 314 + {isRepost && ( 315 + <div style={listStyles.repostIndicator}> 316 + {finalReposterAvatarUrl && ( 317 + <img 318 + src={finalReposterAvatarUrl} 319 + alt="" 320 + style={listStyles.repostAvatar} 321 + /> 322 + )} 323 + <svg 324 + width="16" 325 + height="16" 326 + viewBox="0 0 16 16" 327 + fill="none" 328 + style={{ flexShrink: 0 }} 329 + > 330 + <path 331 + d="M5.5 3.5L3 6L5.5 8.5M3 6H10C11.1046 6 12 6.89543 12 8V8.5M10.5 12.5L13 10L10.5 7.5M13 10H6C4.89543 10 4 9.10457 4 8V7.5" 332 + stroke="var(--atproto-color-text-secondary)" 333 + strokeWidth="1.5" 334 + strokeLinecap="round" 335 + strokeLinejoin="round" 336 + /> 337 + </svg> 338 + <span style={{ ...listStyles.repostText, color: "var(--atproto-color-text-secondary)" }}> 339 + {reposterDisplayName ?? reposterHandle ?? "Someone"} reposted 340 + </span> 341 + </div> 276 342 )} 277 - {text && ( 278 - <p style={{ ...listStyles.rowBody, ...palette.rowBody }}> 279 - {text} 280 - </p> 343 + 344 + {isReply && ( 345 + <div style={listStyles.replyIndicator}> 346 + <svg 347 + width="14" 348 + height="14" 349 + viewBox="0 0 14 14" 350 + fill="none" 351 + style={{ flexShrink: 0 }} 352 + > 353 + <path 354 + d="M11 7H3M3 7L7 3M3 7L7 11" 355 + stroke="#1185FE" 356 + strokeWidth="1.5" 357 + strokeLinecap="round" 358 + strokeLinejoin="round" 359 + /> 360 + </svg> 361 + <span style={{ ...listStyles.replyText, color: "var(--atproto-color-text-secondary)" }}> 362 + Replying to 363 + </span> 364 + {finalParentAvatarUrl && ( 365 + <img 366 + src={finalParentAvatarUrl} 367 + alt="" 368 + style={listStyles.replyAvatar} 369 + /> 370 + )} 371 + <span style={{ color: "#1185FE", fontWeight: 600 }}> 372 + @{replyTargetHandle ?? formatDid(parentDid ?? "")} 373 + </span> 374 + </div> 281 375 )} 282 - {!text && ( 283 - <p 284 - style={{ 285 - ...listStyles.rowBody, 286 - ...palette.rowBody, 287 - fontStyle: "italic", 288 - }} 289 - > 290 - No text content. 291 - </p> 292 - )} 293 - </a> 376 + 377 + <div style={listStyles.postContent}> 378 + <div style={listStyles.avatarContainer}> 379 + {finalAuthorAvatarUrl ? ( 380 + <img 381 + src={finalAuthorAvatarUrl} 382 + alt={authorDisplayName ?? authorHandle ?? "User avatar"} 383 + style={listStyles.avatar} 384 + /> 385 + ) : ( 386 + <div style={listStyles.avatarPlaceholder}> 387 + {(authorDisplayName ?? authorHandle ?? "?")[0].toUpperCase()} 388 + </div> 389 + )} 390 + </div> 391 + 392 + <div style={listStyles.postMain}> 393 + <div style={listStyles.postHeader}> 394 + <a 395 + href={`${blueskyAppBaseUrl}/profile/${postDid}`} 396 + target="_blank" 397 + rel="noopener noreferrer" 398 + style={{ ...listStyles.authorName, color: "var(--atproto-color-text)" }} 399 + onClick={(e) => e.stopPropagation()} 400 + > 401 + {authorDisplayName ?? authorHandle ?? formatDid(postDid)} 402 + </a> 403 + <span style={{ ...listStyles.authorHandle, color: "var(--atproto-color-text-secondary)" }}> 404 + @{authorHandle ?? formatDid(postDid)} 405 + </span> 406 + <span style={{ ...listStyles.separator, color: "var(--atproto-color-text-secondary)" }}>ยท</span> 407 + <span 408 + style={{ ...listStyles.timestamp, color: "var(--atproto-color-text-secondary)" }} 409 + title={absolute} 410 + > 411 + {relative} 412 + </span> 413 + </div> 414 + 415 + <a 416 + href={href} 417 + target="_blank" 418 + rel="noopener noreferrer" 419 + aria-label={ariaLabel} 420 + style={{ ...listStyles.postLink, color: "var(--atproto-color-text)" }} 421 + > 422 + {text && ( 423 + <p style={listStyles.postText}> 424 + <BlueskyRichText text={text} facets={record.facets} /> 425 + </p> 426 + )} 427 + {!text && ( 428 + <p style={{ ...listStyles.postText, fontStyle: "italic", color: "var(--atproto-color-text-secondary)" }}> 429 + No text content 430 + </p> 431 + )} 432 + </a> 433 + </div> 434 + </div> 435 + </div> 294 436 ); 295 437 }; 296 438 ··· 323 465 return rtf.format(Math.round(value), threshold.unit); 324 466 } 325 467 326 - interface ListPalette { 327 - card: { background: string; borderColor: string }; 328 - header: { borderBottomColor: string; color: string }; 329 - pageMeta: { color: string }; 330 - subtitle: { color: string }; 331 - empty: { color: string }; 332 - row: { color: string }; 333 - rowTime: { color: string }; 334 - rowBody: { color: string }; 335 - rowMeta: { color: string }; 336 - divider: string; 337 - footer: { borderTopColor: string; color: string }; 338 - navButton: { color: string; background: string }; 339 - pageChip: { color: string; borderColor: string; background: string }; 340 - pageChipActive: { color: string; background: string; borderColor: string }; 341 - loadingBar: { color: string }; 342 - } 343 468 344 469 const listStyles = { 345 470 card: { 346 471 borderRadius: 16, 347 - border: "1px solid transparent", 472 + borderWidth: "1px", 473 + borderStyle: "solid", 474 + borderColor: "transparent", 348 475 boxShadow: "0 8px 18px -12px rgba(15, 23, 42, 0.25)", 349 476 overflow: "hidden", 350 477 display: "flex", ··· 370 497 display: "flex", 371 498 alignItems: "center", 372 499 justifyContent: "center", 373 - //background: 'rgba(17, 133, 254, 0.14)', 374 500 borderRadius: "50%", 375 501 } satisfies React.CSSProperties, 376 502 headerText: { ··· 398 524 fontSize: 13, 399 525 textAlign: "center", 400 526 } satisfies React.CSSProperties, 401 - row: { 402 - padding: "18px", 403 - textDecoration: "none", 527 + rowContainer: { 528 + padding: "16px", 404 529 display: "flex", 405 530 flexDirection: "column", 406 - gap: 6, 531 + gap: 8, 407 532 transition: "background-color 120ms ease", 533 + position: "relative", 408 534 } satisfies React.CSSProperties, 409 - rowHeader: { 535 + repostIndicator: { 410 536 display: "flex", 411 - gap: 6, 412 - alignItems: "baseline", 537 + alignItems: "center", 538 + gap: 8, 413 539 fontSize: 13, 540 + fontWeight: 500, 541 + paddingLeft: 8, 542 + marginBottom: 4, 414 543 } satisfies React.CSSProperties, 415 - rowTime: { 416 - fontSize: 12, 544 + repostAvatar: { 545 + width: 16, 546 + height: 16, 547 + borderRadius: "50%", 548 + objectFit: "cover", 549 + } satisfies React.CSSProperties, 550 + repostText: { 551 + fontSize: 13, 417 552 fontWeight: 500, 418 553 } satisfies React.CSSProperties, 419 - rowMeta: { 420 - fontSize: 12, 554 + replyIndicator: { 555 + display: "flex", 556 + alignItems: "center", 557 + gap: 8, 558 + fontSize: 13, 559 + fontWeight: 500, 560 + paddingLeft: 8, 561 + marginBottom: 4, 562 + } satisfies React.CSSProperties, 563 + replyAvatar: { 564 + width: 16, 565 + height: 16, 566 + borderRadius: "50%", 567 + objectFit: "cover", 568 + } satisfies React.CSSProperties, 569 + replyText: { 570 + fontSize: 13, 421 571 fontWeight: 500, 422 - letterSpacing: "0.6px", 572 + } satisfies React.CSSProperties, 573 + postContent: { 574 + display: "flex", 575 + gap: 12, 423 576 } satisfies React.CSSProperties, 424 - rowBody: { 577 + avatarContainer: { 578 + flexShrink: 0, 579 + } satisfies React.CSSProperties, 580 + avatar: { 581 + width: 48, 582 + height: 48, 583 + borderRadius: "50%", 584 + objectFit: "cover", 585 + } satisfies React.CSSProperties, 586 + avatarPlaceholder: { 587 + width: 48, 588 + height: 48, 589 + borderRadius: "50%", 590 + background: "var(--atproto-color-bg-elevated)", 591 + color: "var(--atproto-color-text-secondary)", 592 + display: "flex", 593 + alignItems: "center", 594 + justifyContent: "center", 595 + fontSize: 18, 596 + fontWeight: 600, 597 + } satisfies React.CSSProperties, 598 + postMain: { 599 + flex: 1, 600 + minWidth: 0, 601 + display: "flex", 602 + flexDirection: "column", 603 + gap: 6, 604 + } satisfies React.CSSProperties, 605 + postHeader: { 606 + display: "flex", 607 + alignItems: "baseline", 608 + gap: 6, 609 + flexWrap: "wrap", 610 + } satisfies React.CSSProperties, 611 + authorName: { 612 + fontWeight: 700, 613 + fontSize: 15, 614 + textDecoration: "none", 615 + maxWidth: "200px", 616 + overflow: "hidden", 617 + textOverflow: "ellipsis", 618 + whiteSpace: "nowrap", 619 + } satisfies React.CSSProperties, 620 + authorHandle: { 621 + fontSize: 15, 622 + fontWeight: 400, 623 + maxWidth: "150px", 624 + overflow: "hidden", 625 + textOverflow: "ellipsis", 626 + whiteSpace: "nowrap", 627 + } satisfies React.CSSProperties, 628 + separator: { 629 + fontSize: 15, 630 + fontWeight: 400, 631 + } satisfies React.CSSProperties, 632 + timestamp: { 633 + fontSize: 15, 634 + fontWeight: 400, 635 + } satisfies React.CSSProperties, 636 + postLink: { 637 + textDecoration: "none", 638 + display: "block", 639 + } satisfies React.CSSProperties, 640 + postText: { 425 641 margin: 0, 426 642 whiteSpace: "pre-wrap", 427 - fontSize: 14, 428 - lineHeight: 1.45, 643 + fontSize: 15, 644 + lineHeight: 1.5, 645 + wordBreak: "break-word", 429 646 } satisfies React.CSSProperties, 430 647 footer: { 431 648 display: "flex", ··· 435 652 borderTop: "1px solid transparent", 436 653 fontSize: 13, 437 654 } satisfies React.CSSProperties, 438 - navButton: { 439 - border: "none", 440 - borderRadius: 999, 441 - padding: "6px 12px", 442 - fontSize: 13, 443 - fontWeight: 500, 444 - background: "transparent", 445 - display: "flex", 446 - alignItems: "center", 447 - gap: 4, 448 - transition: "background-color 120ms ease", 449 - } satisfies React.CSSProperties, 450 655 pageChips: { 451 656 display: "flex", 452 657 gap: 6, ··· 456 661 padding: "4px 10px", 457 662 borderRadius: 999, 458 663 fontSize: 13, 459 - border: "1px solid transparent", 664 + borderWidth: "1px", 665 + borderStyle: "solid", 666 + borderColor: "transparent", 460 667 } satisfies React.CSSProperties, 461 668 pageChipActive: { 462 669 padding: "4px 10px", 463 670 borderRadius: 999, 464 671 fontSize: 13, 465 672 fontWeight: 600, 466 - border: "1px solid transparent", 673 + borderWidth: "1px", 674 + borderStyle: "solid", 675 + borderColor: "transparent", 676 + } satisfies React.CSSProperties, 677 + pageButton: { 678 + border: "none", 679 + borderRadius: 999, 680 + padding: "6px 12px", 681 + fontSize: 13, 682 + fontWeight: 500, 683 + background: "transparent", 684 + display: "flex", 685 + alignItems: "center", 686 + gap: 4, 687 + transition: "background-color 120ms ease", 467 688 } satisfies React.CSSProperties, 468 689 loadingBar: { 469 690 padding: "4px 18px 14px", ··· 473 694 } satisfies React.CSSProperties, 474 695 }; 475 696 476 - const lightPalette: ListPalette = { 477 - card: { 478 - background: "#ffffff", 479 - borderColor: "#e2e8f0", 480 - }, 481 - header: { 482 - borderBottomColor: "#e2e8f0", 483 - color: "#0f172a", 484 - }, 485 - pageMeta: { 486 - color: "#64748b", 487 - }, 488 - subtitle: { 489 - color: "#475569", 490 - }, 491 - empty: { 492 - color: "#64748b", 493 - }, 494 - row: { 495 - color: "#0f172a", 496 - }, 497 - rowTime: { 498 - color: "#94a3b8", 499 - }, 500 - rowBody: { 501 - color: "#0f172a", 502 - }, 503 - rowMeta: { 504 - color: "#64748b", 505 - }, 506 - divider: "#e2e8f0", 507 - footer: { 508 - borderTopColor: "#e2e8f0", 509 - color: "#0f172a", 510 - }, 511 - navButton: { 512 - color: "#0f172a", 513 - background: "#f1f5f9", 514 - }, 515 - pageChip: { 516 - color: "#475569", 517 - borderColor: "#e2e8f0", 518 - background: "#ffffff", 519 - }, 520 - pageChipActive: { 521 - color: "#ffffff", 522 - background: "#0f172a", 523 - borderColor: "#0f172a", 524 - }, 525 - loadingBar: { 526 - color: "#64748b", 527 - }, 528 - }; 529 - 530 - const darkPalette: ListPalette = { 531 - card: { 532 - background: "#0f172a", 533 - borderColor: "#1e293b", 534 - }, 535 - header: { 536 - borderBottomColor: "#1e293b", 537 - color: "#e2e8f0", 538 - }, 539 - pageMeta: { 540 - color: "#94a3b8", 541 - }, 542 - subtitle: { 543 - color: "#94a3b8", 544 - }, 545 - empty: { 546 - color: "#94a3b8", 547 - }, 548 - row: { 549 - color: "#e2e8f0", 550 - }, 551 - rowTime: { 552 - color: "#94a3b8", 553 - }, 554 - rowBody: { 555 - color: "#e2e8f0", 556 - }, 557 - rowMeta: { 558 - color: "#94a3b8", 559 - }, 560 - divider: "#1e293b", 561 - footer: { 562 - borderTopColor: "#1e293b", 563 - color: "#e2e8f0", 564 - }, 565 - navButton: { 566 - color: "#e2e8f0", 567 - background: "#111c31", 568 - }, 569 - pageChip: { 570 - color: "#cbd5f5", 571 - borderColor: "#1e293b", 572 - background: "#0f172a", 573 - }, 574 - pageChipActive: { 575 - color: "#0f172a", 576 - background: "#38bdf8", 577 - borderColor: "#38bdf8", 578 - }, 579 - loadingBar: { 580 - color: "#94a3b8", 581 - }, 582 - }; 583 - 584 697 export default BlueskyPostList; 585 - 586 - function formatActor(actor?: { handle?: string; did?: string }) { 587 - if (!actor) return undefined; 588 - if (actor.handle) return `@${actor.handle}`; 589 - if (actor.did) return `@${formatDid(actor.did)}`; 590 - return undefined; 591 - } 592 - 593 - function formatReplyTarget( 594 - parentUri?: string, 595 - feedParent?: ReplyParentInfo, 596 - resolvedHandle?: string, 597 - ) { 598 - const directHandle = feedParent?.author?.handle; 599 - const handle = directHandle ?? resolvedHandle; 600 - if (handle) { 601 - return `Replying to @${handle}`; 602 - } 603 - const parentDid = feedParent?.author?.did; 604 - const targetUri = feedParent?.uri ?? parentUri; 605 - if (!targetUri) return undefined; 606 - const parsed = parseAtUri(targetUri); 607 - const did = parentDid ?? parsed?.did; 608 - if (!did) return undefined; 609 - return `Replying to @${formatDid(did)}`; 610 - }
+13 -18
lib/components/BlueskyProfile.tsx
··· 6 6 import { getAvatarCid } from "../utils/profile"; 7 7 import { useDidResolution } from "../hooks/useDidResolution"; 8 8 import { formatDidForLabel } from "../utils/at-uri"; 9 + import { isBlobWithCdn } from "../utils/blob"; 9 10 10 11 /** 11 12 * Props used to render a Bluesky actor profile record. ··· 40 41 * Pre-resolved handle to display when available externally. 41 42 */ 42 43 handle?: string; 43 - /** 44 - * Preferred color scheme forwarded to renderer implementations. 45 - */ 46 - colorScheme?: "light" | "dark" | "system"; 44 + 47 45 } 48 46 49 47 /** ··· 74 72 * Blob URL for the user's avatar, when available. 75 73 */ 76 74 avatarUrl?: string; 77 - /** 78 - * Preferred color scheme for theming downstream components. 79 - */ 80 - colorScheme?: "light" | "dark" | "system"; 75 + 81 76 }; 82 77 83 78 /** NSID for the canonical Bluesky profile collection. */ ··· 93 88 * @param fallback - Node rendered prior to loading state initialization. 94 89 * @param loadingIndicator - Node rendered while the profile request is in-flight. 95 90 * @param handle - Optional pre-resolved handle to display. 96 - * @param colorScheme - Preferred color scheme forwarded to the renderer. 97 91 * @returns A rendered profile component with loading/error states handled. 98 92 */ 99 - export const BlueskyProfile: React.FC<BlueskyProfileProps> = ({ 93 + export const BlueskyProfile: React.FC<BlueskyProfileProps> = React.memo(({ 100 94 did: handleOrDid, 101 95 rkey = "self", 102 96 record, ··· 104 98 fallback, 105 99 loadingIndicator, 106 100 handle, 107 - colorScheme, 108 101 }) => { 109 102 const Component: React.ComponentType<BlueskyProfileRendererInjectedProps> = 110 103 renderer ?? ((props) => <BlueskyProfileRenderer {...props} />); ··· 122 115 loading: boolean; 123 116 error?: Error; 124 117 }> = (props) => { 125 - const avatarCid = getAvatarCid(props.record); 126 - const { url: avatarUrl } = useBlob(repoIdentifier, avatarCid); 118 + // Check if the avatar has a CDN URL from the appview (preferred) 119 + const avatar = props.record?.avatar; 120 + const avatarCdnUrl = isBlobWithCdn(avatar) ? avatar.cdnUrl : undefined; 121 + const avatarCid = avatarCdnUrl ? undefined : getAvatarCid(props.record); 122 + const { url: avatarUrlFromBlob } = useBlob(repoIdentifier, avatarCid); 123 + const avatarUrl = avatarCdnUrl || avatarUrlFromBlob; 124 + 127 125 return ( 128 126 <Component 129 127 {...props} 130 128 did={repoIdentifier} 131 129 handle={effectiveHandle} 132 130 avatarUrl={avatarUrl} 133 - colorScheme={colorScheme} 134 131 /> 135 132 ); 136 133 }; 137 134 138 - // When record is provided, pass it directly to skip fetching 139 - if (record) { 135 + if (record !== undefined) { 140 136 return ( 141 137 <AtProtoRecord<ProfileRecord> 142 138 record={record} ··· 147 143 ); 148 144 } 149 145 150 - // Otherwise fetch the record using did, collection, and rkey 151 146 return ( 152 147 <AtProtoRecord<ProfileRecord> 153 148 did={repoIdentifier} ··· 158 153 loadingIndicator={loadingIndicator} 159 154 /> 160 155 ); 161 - }; 156 + }); 162 157 163 158 export default BlueskyProfile;
+4 -15
lib/components/BlueskyQuotePost.tsx
··· 20 20 */ 21 21 rkey: string; 22 22 /** 23 - * Preferred color scheme propagated to nested renders. 24 - */ 25 - colorScheme?: "light" | "dark" | "system"; 26 - /** 27 23 * Custom renderer override applied to the parent post. 28 24 */ 29 25 renderer?: React.ComponentType<BlueskyPostRendererInjectedProps>; ··· 50 46 * 51 47 * @param did - DID that owns the quoted parent post. 52 48 * @param rkey - Record key identifying the parent post. 53 - * @param colorScheme - Preferred color scheme for both parent and quoted posts. 54 49 * @param renderer - Optional renderer override applied to the parent post. 55 50 * @param fallback - Node rendered before parent post data loads. 56 51 * @param loadingIndicator - Node rendered while the parent post request is in-flight. ··· 61 56 const BlueskyQuotePostComponent: React.FC<BlueskyQuotePostProps> = ({ 62 57 did, 63 58 rkey, 64 - colorScheme, 65 59 renderer, 66 60 fallback, 67 61 loadingIndicator, ··· 73 67 const QuoteRenderer: React.FC<BlueskyPostRendererInjectedProps> = ( 74 68 props, 75 69 ) => { 76 - const resolvedColorScheme = props.colorScheme ?? colorScheme; 77 70 const embedSource = props.record.embed as 78 71 | QuoteRecordEmbed 79 72 | undefined; 80 73 const embedNode = useMemo( 81 - () => createQuoteEmbed(embedSource, resolvedColorScheme), 82 - [embedSource, resolvedColorScheme], 74 + () => createQuoteEmbed(embedSource), 75 + [embedSource], 83 76 ); 84 - return <BaseRenderer {...props} embed={embedNode} />; 77 + return <BaseRenderer isQuotePost={true} {...props} embed={embedNode} />; 85 78 }; 86 79 QuoteRenderer.displayName = "BlueskyQuotePostRenderer"; 87 80 const MemoizedQuoteRenderer = memo(QuoteRenderer); 88 81 MemoizedQuoteRenderer.displayName = "BlueskyQuotePostRenderer"; 89 82 return MemoizedQuoteRenderer; 90 - }, [BaseRenderer, colorScheme]); 83 + }, [BaseRenderer]); 91 84 92 85 return ( 93 86 <BlueskyPost 94 87 did={did} 95 88 rkey={rkey} 96 - colorScheme={colorScheme} 97 89 renderer={Renderer} 98 90 fallback={fallback} 99 91 loadingIndicator={loadingIndicator} ··· 113 105 * Builds the quoted post embed node when the parent record contains a record embed. 114 106 * 115 107 * @param embed - Embed payload containing a possible quote reference. 116 - * @param colorScheme - Desired visual theme for the nested quote. 117 108 * @returns A nested `BlueskyPost` or `null` if no compatible embed exists. 118 109 */ 119 110 type QuoteRecordEmbed = { $type?: string; record?: { uri?: string } }; 120 111 121 112 function createQuoteEmbed( 122 113 embed: QuoteRecordEmbed | undefined, 123 - colorScheme?: "light" | "dark" | "system", 124 114 ) { 125 115 if (!embed || embed.$type !== "app.bsky.embed.record") return null; 126 116 const quoted = embed.record; ··· 132 122 <BlueskyPost 133 123 did={parsed.did} 134 124 rkey={parsed.rkey} 135 - colorScheme={colorScheme} 136 125 showIcon={false} 137 126 /> 138 127 </div>
-129
lib/components/ColorSchemeToggle.tsx
··· 1 - import React from "react"; 2 - import type { ColorSchemePreference } from "../hooks/useColorScheme"; 3 - 4 - /** 5 - * Props for the `ColorSchemeToggle` segmented control. 6 - */ 7 - export interface ColorSchemeToggleProps { 8 - /** 9 - * Current color scheme preference selection. 10 - */ 11 - value: ColorSchemePreference; 12 - /** 13 - * Change handler invoked when the user selects a new scheme. 14 - */ 15 - onChange: (value: ColorSchemePreference) => void; 16 - /** 17 - * Theme used to style the control itself; defaults to `'light'`. 18 - */ 19 - scheme?: "light" | "dark"; 20 - } 21 - 22 - const options: Array<{ 23 - label: string; 24 - value: ColorSchemePreference; 25 - description: string; 26 - }> = [ 27 - { label: "System", value: "system", description: "Follow OS preference" }, 28 - { label: "Light", value: "light", description: "Always light mode" }, 29 - { label: "Dark", value: "dark", description: "Always dark mode" }, 30 - ]; 31 - 32 - /** 33 - * A button group that lets users choose between light, dark, or system color modes. 34 - * 35 - * @param value - Current scheme selection displayed as active. 36 - * @param onChange - Callback fired when a new option is selected. 37 - * @param scheme - Theme used to style the control itself. Defaults to `'light'`. 38 - * @returns A fully keyboard-accessible toggle rendered as a radio group. 39 - */ 40 - export const ColorSchemeToggle: React.FC<ColorSchemeToggleProps> = ({ 41 - value, 42 - onChange, 43 - scheme = "light", 44 - }) => { 45 - const palette = scheme === "dark" ? darkTheme : lightTheme; 46 - 47 - return ( 48 - <div 49 - aria-label="Color scheme" 50 - role="radiogroup" 51 - style={{ ...containerStyle, ...palette.container }} 52 - > 53 - {options.map((option) => { 54 - const isActive = option.value === value; 55 - const activeStyles = isActive ? palette.active : undefined; 56 - return ( 57 - <button 58 - key={option.value} 59 - role="radio" 60 - aria-checked={isActive} 61 - type="button" 62 - onClick={() => onChange(option.value)} 63 - style={{ 64 - ...buttonStyle, 65 - ...palette.button, 66 - ...(activeStyles ?? {}), 67 - }} 68 - title={option.description} 69 - > 70 - {option.label} 71 - </button> 72 - ); 73 - })} 74 - </div> 75 - ); 76 - }; 77 - 78 - const containerStyle: React.CSSProperties = { 79 - display: "inline-flex", 80 - borderRadius: 999, 81 - padding: 4, 82 - gap: 4, 83 - border: "1px solid transparent", 84 - background: "#f8fafc", 85 - }; 86 - 87 - const buttonStyle: React.CSSProperties = { 88 - border: "1px solid transparent", 89 - borderRadius: 999, 90 - padding: "4px 12px", 91 - fontSize: 12, 92 - fontWeight: 500, 93 - cursor: "pointer", 94 - background: "transparent", 95 - transition: 96 - "background-color 160ms ease, border-color 160ms ease, color 160ms ease", 97 - }; 98 - 99 - const lightTheme = { 100 - container: { 101 - borderColor: "#e2e8f0", 102 - background: "rgba(241, 245, 249, 0.8)", 103 - }, 104 - button: { 105 - color: "#334155", 106 - }, 107 - active: { 108 - background: "#2563eb", 109 - borderColor: "#2563eb", 110 - color: "#f8fafc", 111 - }, 112 - } satisfies Record<string, React.CSSProperties>; 113 - 114 - const darkTheme = { 115 - container: { 116 - borderColor: "#2e3540ff", 117 - background: "rgba(30, 38, 49, 0.6)", 118 - }, 119 - button: { 120 - color: "#e2e8f0", 121 - }, 122 - active: { 123 - background: "#38bdf8", 124 - borderColor: "#38bdf8", 125 - color: "#020617", 126 - }, 127 - } satisfies Record<string, React.CSSProperties>; 128 - 129 - export default ColorSchemeToggle;
+143
lib/components/CurrentlyPlaying.tsx
··· 1 + import React from "react"; 2 + import { AtProtoRecord } from "../core/AtProtoRecord"; 3 + import { CurrentlyPlayingRenderer } from "../renderers/CurrentlyPlayingRenderer"; 4 + import { useDidResolution } from "../hooks/useDidResolution"; 5 + import type { TealActorStatusRecord } from "../types/teal"; 6 + 7 + /** 8 + * Props for rendering teal.fm currently playing status. 9 + */ 10 + export interface CurrentlyPlayingProps { 11 + /** DID of the user whose currently playing status to display. */ 12 + did: string; 13 + /** Record key within the `fm.teal.alpha.actor.status` collection (usually "self"). */ 14 + rkey?: string; 15 + /** Prefetched teal.fm status record. When provided, skips fetching from the network. */ 16 + record?: TealActorStatusRecord; 17 + /** Optional renderer override for custom presentation. */ 18 + renderer?: React.ComponentType<CurrentlyPlayingRendererInjectedProps>; 19 + /** Fallback node displayed before loading begins. */ 20 + fallback?: React.ReactNode; 21 + /** Indicator node shown while data is loading. */ 22 + loadingIndicator?: React.ReactNode; 23 + /** Preferred color scheme for theming. */ 24 + colorScheme?: "light" | "dark" | "system"; 25 + /** Auto-refresh music data and album art. When true, refreshes every 15 seconds. Defaults to true. */ 26 + autoRefresh?: boolean; 27 + /** Refresh interval in milliseconds. Defaults to 15000 (15 seconds). Only used when autoRefresh is true. */ 28 + refreshInterval?: number; 29 + } 30 + 31 + /** 32 + * Values injected into custom currently playing renderer implementations. 33 + */ 34 + export type CurrentlyPlayingRendererInjectedProps = { 35 + /** Loaded teal.fm status record value. */ 36 + record: TealActorStatusRecord; 37 + /** Indicates whether the record is currently loading. */ 38 + loading: boolean; 39 + /** Fetch error, if any. */ 40 + error?: Error; 41 + /** Preferred color scheme for downstream components. */ 42 + colorScheme?: "light" | "dark" | "system"; 43 + /** DID associated with the record. */ 44 + did: string; 45 + /** Record key for the status. */ 46 + rkey: string; 47 + /** Label to display. */ 48 + label?: string; 49 + /** Handle to display in not listening state */ 50 + handle?: string; 51 + }; 52 + 53 + /** NSID for teal.fm actor status records. */ 54 + export const CURRENTLY_PLAYING_COLLECTION = "fm.teal.alpha.actor.status"; 55 + 56 + /** 57 + * Compares two teal.fm status records to determine if the track has changed. 58 + * Used to prevent unnecessary re-renders during auto-refresh when the same track is still playing. 59 + */ 60 + const compareTealRecords = ( 61 + prev: TealActorStatusRecord | undefined, 62 + next: TealActorStatusRecord | undefined 63 + ): boolean => { 64 + if (!prev || !next) return prev === next; 65 + 66 + const prevTrack = prev.item.trackName; 67 + const nextTrack = next.item.trackName; 68 + const prevArtist = prev.item.artists[0]?.artistName; 69 + const nextArtist = next.item.artists[0]?.artistName; 70 + 71 + return prevTrack === nextTrack && prevArtist === nextArtist; 72 + }; 73 + 74 + /** 75 + * Displays the currently playing track from teal.fm with auto-refresh. 76 + * 77 + * @param did - DID whose currently playing status should be fetched. 78 + * @param rkey - Record key within the teal.fm status collection (defaults to "self"). 79 + * @param renderer - Optional component override that will receive injected props. 80 + * @param fallback - Node rendered before the first load begins. 81 + * @param loadingIndicator - Node rendered while the status is loading. 82 + * @param colorScheme - Preferred color scheme for theming the renderer. 83 + * @param autoRefresh - When true (default), refreshes the record every 15 seconds (or custom interval). 84 + * @param refreshInterval - Custom refresh interval in milliseconds. Defaults to 15000 (15 seconds). 85 + * @returns A JSX subtree representing the currently playing track with loading states handled. 86 + */ 87 + export const CurrentlyPlaying: React.FC<CurrentlyPlayingProps> = React.memo(({ 88 + did, 89 + rkey = "self", 90 + record, 91 + renderer, 92 + fallback, 93 + loadingIndicator, 94 + colorScheme, 95 + autoRefresh = true, 96 + refreshInterval = 15000, 97 + }) => { 98 + // Resolve handle from DID 99 + const { handle } = useDidResolution(did); 100 + 101 + const Comp: React.ComponentType<CurrentlyPlayingRendererInjectedProps> = 102 + renderer ?? ((props) => <CurrentlyPlayingRenderer {...props} />); 103 + const Wrapped: React.FC<{ 104 + record: TealActorStatusRecord; 105 + loading: boolean; 106 + error?: Error; 107 + }> = (props) => ( 108 + <Comp 109 + {...props} 110 + colorScheme={colorScheme} 111 + did={did} 112 + rkey={rkey} 113 + label="CURRENTLY PLAYING" 114 + handle={handle} 115 + /> 116 + ); 117 + 118 + if (record !== undefined) { 119 + return ( 120 + <AtProtoRecord<TealActorStatusRecord> 121 + record={record} 122 + renderer={Wrapped} 123 + fallback={fallback} 124 + loadingIndicator={loadingIndicator} 125 + /> 126 + ); 127 + } 128 + 129 + return ( 130 + <AtProtoRecord<TealActorStatusRecord> 131 + did={did} 132 + collection={CURRENTLY_PLAYING_COLLECTION} 133 + rkey={rkey} 134 + renderer={Wrapped} 135 + fallback={fallback} 136 + loadingIndicator={loadingIndicator} 137 + refreshInterval={autoRefresh ? refreshInterval : undefined} 138 + compareRecords={compareTealRecords} 139 + /> 140 + ); 141 + }); 142 + 143 + export default CurrentlyPlaying;
+327
lib/components/GrainGallery.tsx
··· 1 + import React, { useMemo, useEffect, useState } from "react"; 2 + import { GrainGalleryRenderer, type GrainGalleryPhoto } from "../renderers/GrainGalleryRenderer"; 3 + import type { GrainGalleryRecord, GrainGalleryItemRecord, GrainPhotoRecord } from "../types/grain"; 4 + import type { ProfileRecord } from "../types/bluesky"; 5 + import { useDidResolution } from "../hooks/useDidResolution"; 6 + import { useAtProtoRecord } from "../hooks/useAtProtoRecord"; 7 + import { useBacklinks } from "../hooks/useBacklinks"; 8 + import { useBlob } from "../hooks/useBlob"; 9 + import { BLUESKY_PROFILE_COLLECTION } from "./BlueskyProfile"; 10 + import { getAvatarCid } from "../utils/profile"; 11 + import { formatDidForLabel, parseAtUri } from "../utils/at-uri"; 12 + import { isBlobWithCdn } from "../utils/blob"; 13 + import { createAtprotoClient } from "../utils/atproto-client"; 14 + 15 + /** 16 + * Props for rendering a grain.social gallery. 17 + */ 18 + export interface GrainGalleryProps { 19 + /** 20 + * Decentralized identifier for the repository that owns the gallery. 21 + */ 22 + did: string; 23 + /** 24 + * Record key identifying the specific gallery within the collection. 25 + */ 26 + rkey: string; 27 + /** 28 + * Prefetched gallery record. When provided, skips fetching the gallery from the network. 29 + */ 30 + record?: GrainGalleryRecord; 31 + /** 32 + * Custom renderer component that receives resolved gallery data and status flags. 33 + */ 34 + renderer?: React.ComponentType<GrainGalleryRendererInjectedProps>; 35 + /** 36 + * React node shown while the gallery query has not yet produced data or an error. 37 + */ 38 + fallback?: React.ReactNode; 39 + /** 40 + * React node displayed while the gallery fetch is actively loading. 41 + */ 42 + loadingIndicator?: React.ReactNode; 43 + /** 44 + * Constellation API base URL for fetching backlinks. 45 + */ 46 + constellationBaseUrl?: string; 47 + } 48 + 49 + /** 50 + * Values injected by `GrainGallery` into a downstream renderer component. 51 + */ 52 + export type GrainGalleryRendererInjectedProps = { 53 + /** 54 + * Resolved gallery record 55 + */ 56 + gallery: GrainGalleryRecord; 57 + /** 58 + * Array of photos in the gallery with their records and metadata 59 + */ 60 + photos: GrainGalleryPhoto[]; 61 + /** 62 + * `true` while network operations are in-flight. 63 + */ 64 + loading: boolean; 65 + /** 66 + * Error encountered during loading, if any. 67 + */ 68 + error?: Error; 69 + /** 70 + * The author's public handle derived from the DID. 71 + */ 72 + authorHandle?: string; 73 + /** 74 + * The author's display name from their profile. 75 + */ 76 + authorDisplayName?: string; 77 + /** 78 + * Resolved URL for the author's avatar blob, if available. 79 + */ 80 + avatarUrl?: string; 81 + }; 82 + 83 + export const GRAIN_GALLERY_COLLECTION = "social.grain.gallery"; 84 + export const GRAIN_GALLERY_ITEM_COLLECTION = "social.grain.gallery.item"; 85 + export const GRAIN_PHOTO_COLLECTION = "social.grain.photo"; 86 + 87 + /** 88 + * Fetches a grain.social gallery, resolves all photos via constellation backlinks, 89 + * and renders them in a grid layout. 90 + * 91 + * @param did - DID of the repository that stores the gallery. 92 + * @param rkey - Record key for the gallery. 93 + * @param record - Prefetched gallery record. 94 + * @param renderer - Optional renderer component to override the default. 95 + * @param fallback - Node rendered before the first fetch attempt resolves. 96 + * @param loadingIndicator - Node rendered while the gallery is loading. 97 + * @param constellationBaseUrl - Constellation API base URL. 98 + * @returns A component that renders loading/fallback states and the resolved gallery. 99 + */ 100 + export const GrainGallery: React.FC<GrainGalleryProps> = React.memo( 101 + ({ 102 + did: handleOrDid, 103 + rkey, 104 + record, 105 + renderer, 106 + fallback, 107 + loadingIndicator, 108 + constellationBaseUrl, 109 + }) => { 110 + const { 111 + did: resolvedDid, 112 + handle, 113 + loading: resolvingIdentity, 114 + error: resolutionError, 115 + } = useDidResolution(handleOrDid); 116 + 117 + const repoIdentifier = resolvedDid ?? handleOrDid; 118 + 119 + // Fetch author profile 120 + const { record: profile } = useAtProtoRecord<ProfileRecord>({ 121 + did: repoIdentifier, 122 + collection: BLUESKY_PROFILE_COLLECTION, 123 + rkey: "self", 124 + }); 125 + const avatar = profile?.avatar; 126 + const avatarCdnUrl = isBlobWithCdn(avatar) ? avatar.cdnUrl : undefined; 127 + const avatarCid = avatarCdnUrl ? undefined : getAvatarCid(profile); 128 + const authorDisplayName = profile?.displayName; 129 + const { url: avatarUrlFromBlob } = useBlob(repoIdentifier, avatarCid); 130 + const avatarUrl = avatarCdnUrl || avatarUrlFromBlob; 131 + 132 + // Fetch gallery record 133 + const { 134 + record: fetchedGallery, 135 + loading: galleryLoading, 136 + error: galleryError, 137 + } = useAtProtoRecord<GrainGalleryRecord>({ 138 + did: record ? "" : repoIdentifier, 139 + collection: record ? "" : GRAIN_GALLERY_COLLECTION, 140 + rkey: record ? "" : rkey, 141 + }); 142 + 143 + const galleryRecord = record ?? fetchedGallery; 144 + const galleryUri = resolvedDid 145 + ? `at://${resolvedDid}/${GRAIN_GALLERY_COLLECTION}/${rkey}` 146 + : undefined; 147 + 148 + // Fetch backlinks to get gallery items 149 + const { 150 + backlinks, 151 + loading: backlinksLoading, 152 + error: backlinksError, 153 + } = useBacklinks({ 154 + subject: galleryUri || "", 155 + source: `${GRAIN_GALLERY_ITEM_COLLECTION}:gallery`, 156 + enabled: !!galleryUri && !!galleryRecord, 157 + constellationBaseUrl, 158 + }); 159 + 160 + // Fetch all gallery item records and photo records 161 + const [photos, setPhotos] = useState<GrainGalleryPhoto[]>([]); 162 + const [photosLoading, setPhotosLoading] = useState(false); 163 + const [photosError, setPhotosError] = useState<Error | undefined>(undefined); 164 + 165 + useEffect(() => { 166 + if (!backlinks || backlinks.length === 0) { 167 + setPhotos([]); 168 + return; 169 + } 170 + 171 + let cancelled = false; 172 + setPhotosLoading(true); 173 + setPhotosError(undefined); 174 + 175 + (async () => { 176 + try { 177 + const photoPromises = backlinks.map(async (backlink) => { 178 + // Create client for gallery item DID (uses slingshot + PDS fallback) 179 + const { rpc: galleryItemClient } = await createAtprotoClient({ 180 + did: backlink.did, 181 + }); 182 + 183 + // Fetch gallery item record 184 + const galleryItemRes = await ( 185 + galleryItemClient as unknown as { 186 + get: ( 187 + nsid: string, 188 + opts: { 189 + params: { 190 + repo: string; 191 + collection: string; 192 + rkey: string; 193 + }; 194 + }, 195 + ) => Promise<{ ok: boolean; data: { value: GrainGalleryItemRecord } }>; 196 + } 197 + ).get("com.atproto.repo.getRecord", { 198 + params: { 199 + repo: backlink.did, 200 + collection: GRAIN_GALLERY_ITEM_COLLECTION, 201 + rkey: backlink.rkey, 202 + }, 203 + }); 204 + 205 + if (!galleryItemRes.ok) return null; 206 + 207 + const galleryItem = galleryItemRes.data.value; 208 + 209 + // Parse photo URI 210 + const photoUri = parseAtUri(galleryItem.item); 211 + if (!photoUri) return null; 212 + 213 + // Create client for photo DID (uses slingshot + PDS fallback) 214 + const { rpc: photoClient } = await createAtprotoClient({ 215 + did: photoUri.did, 216 + }); 217 + 218 + // Fetch photo record 219 + const photoRes = await ( 220 + photoClient as unknown as { 221 + get: ( 222 + nsid: string, 223 + opts: { 224 + params: { 225 + repo: string; 226 + collection: string; 227 + rkey: string; 228 + }; 229 + }, 230 + ) => Promise<{ ok: boolean; data: { value: GrainPhotoRecord } }>; 231 + } 232 + ).get("com.atproto.repo.getRecord", { 233 + params: { 234 + repo: photoUri.did, 235 + collection: photoUri.collection, 236 + rkey: photoUri.rkey, 237 + }, 238 + }); 239 + 240 + if (!photoRes.ok) return null; 241 + 242 + const photoRecord = photoRes.data.value; 243 + 244 + return { 245 + record: photoRecord, 246 + did: photoUri.did, 247 + rkey: photoUri.rkey, 248 + position: galleryItem.position, 249 + } as GrainGalleryPhoto; 250 + }); 251 + 252 + const resolvedPhotos = await Promise.all(photoPromises); 253 + const validPhotos = resolvedPhotos.filter((p): p is NonNullable<typeof p> => p !== null) as GrainGalleryPhoto[]; 254 + 255 + if (!cancelled) { 256 + setPhotos(validPhotos); 257 + setPhotosLoading(false); 258 + } 259 + } catch (err) { 260 + if (!cancelled) { 261 + setPhotosError(err instanceof Error ? err : new Error("Failed to fetch photos")); 262 + setPhotosLoading(false); 263 + } 264 + } 265 + })(); 266 + 267 + return () => { 268 + cancelled = true; 269 + }; 270 + }, [backlinks]); 271 + 272 + const Comp: React.ComponentType<GrainGalleryRendererInjectedProps> = 273 + useMemo( 274 + () => 275 + renderer ?? ((props) => <GrainGalleryRenderer {...props} />), 276 + [renderer], 277 + ); 278 + 279 + const displayHandle = 280 + handle ?? 281 + (handleOrDid.startsWith("did:") ? undefined : handleOrDid); 282 + const authorHandle = 283 + displayHandle ?? formatDidForLabel(resolvedDid ?? handleOrDid); 284 + 285 + if (!displayHandle && resolvingIdentity) { 286 + return loadingIndicator || <div role="status" aria-live="polite" style={{ padding: 8 }}>Resolving handleโ€ฆ</div>; 287 + } 288 + if (!displayHandle && resolutionError) { 289 + return ( 290 + <div style={{ padding: 8, color: "crimson" }}> 291 + Could not resolve handle. 292 + </div> 293 + ); 294 + } 295 + 296 + if (galleryError || backlinksError || photosError) { 297 + return ( 298 + <div style={{ padding: 8, color: "crimson" }}> 299 + Failed to load gallery. 300 + </div> 301 + ); 302 + } 303 + 304 + if (!galleryRecord && galleryLoading) { 305 + return loadingIndicator || <div style={{ padding: 8 }}>Loading galleryโ€ฆ</div>; 306 + } 307 + 308 + if (!galleryRecord) { 309 + return fallback || <div style={{ padding: 8 }}>Gallery not found.</div>; 310 + } 311 + 312 + const loading = galleryLoading || backlinksLoading || photosLoading; 313 + 314 + return ( 315 + <Comp 316 + gallery={galleryRecord} 317 + photos={photos} 318 + loading={loading} 319 + authorHandle={authorHandle} 320 + authorDisplayName={authorDisplayName} 321 + avatarUrl={avatarUrl} 322 + /> 323 + ); 324 + }, 325 + ); 326 + 327 + export default GrainGallery;
+165
lib/components/LastPlayed.tsx
··· 1 + import React, { useMemo } from "react"; 2 + import { useLatestRecord } from "../hooks/useLatestRecord"; 3 + import { useDidResolution } from "../hooks/useDidResolution"; 4 + import { CurrentlyPlayingRenderer } from "../renderers/CurrentlyPlayingRenderer"; 5 + import type { TealFeedPlayRecord, TealActorStatusRecord } from "../types/teal"; 6 + 7 + /** 8 + * Props for rendering the last played track from teal.fm feed. 9 + */ 10 + export interface LastPlayedProps { 11 + /** DID of the user whose last played track to display. */ 12 + did: string; 13 + /** Optional renderer override for custom presentation. */ 14 + renderer?: React.ComponentType<LastPlayedRendererInjectedProps>; 15 + /** Fallback node displayed before loading begins. */ 16 + fallback?: React.ReactNode; 17 + /** Indicator node shown while data is loading. */ 18 + loadingIndicator?: React.ReactNode; 19 + /** Preferred color scheme for theming. */ 20 + colorScheme?: "light" | "dark" | "system"; 21 + /** Auto-refresh music data and album art. Defaults to false for last played. */ 22 + autoRefresh?: boolean; 23 + /** Refresh interval in milliseconds. Defaults to 60000 (60 seconds). */ 24 + refreshInterval?: number; 25 + } 26 + 27 + /** 28 + * Values injected into custom last played renderer implementations. 29 + */ 30 + export type LastPlayedRendererInjectedProps = { 31 + /** Loaded teal.fm feed play record value. */ 32 + record: TealActorStatusRecord; 33 + /** Indicates whether the record is currently loading. */ 34 + loading: boolean; 35 + /** Fetch error, if any. */ 36 + error?: Error; 37 + /** Preferred color scheme for downstream components. */ 38 + colorScheme?: "light" | "dark" | "system"; 39 + /** DID associated with the record. */ 40 + did: string; 41 + /** Record key for the play record. */ 42 + rkey: string; 43 + /** Handle to display in not listening state */ 44 + handle?: string; 45 + }; 46 + 47 + /** NSID for teal.fm feed play records. */ 48 + export const LAST_PLAYED_COLLECTION = "fm.teal.alpha.feed.play"; 49 + 50 + /** 51 + * Displays the last played track from teal.fm feed. 52 + * 53 + * @param did - DID whose last played track should be fetched. 54 + * @param renderer - Optional component override that will receive injected props. 55 + * @param fallback - Node rendered before the first load begins. 56 + * @param loadingIndicator - Node rendered while the data is loading. 57 + * @param colorScheme - Preferred color scheme for theming the renderer. 58 + * @param autoRefresh - When true, refreshes album art and streaming platform links at the specified interval. Defaults to false. 59 + * @param refreshInterval - Refresh interval in milliseconds. Defaults to 60000 (60 seconds). 60 + * @returns A JSX subtree representing the last played track with loading states handled. 61 + */ 62 + export const LastPlayed: React.FC<LastPlayedProps> = React.memo(({ 63 + did, 64 + renderer, 65 + fallback, 66 + loadingIndicator, 67 + colorScheme, 68 + autoRefresh = false, 69 + refreshInterval = 60000, 70 + }) => { 71 + // Resolve handle from DID 72 + const { handle } = useDidResolution(did); 73 + 74 + // Auto-refresh key for refetching teal.fm record 75 + const [refreshKey, setRefreshKey] = React.useState(0); 76 + 77 + // Auto-refresh interval 78 + React.useEffect(() => { 79 + if (!autoRefresh) return; 80 + 81 + const interval = setInterval(() => { 82 + setRefreshKey((prev) => prev + 1); 83 + }, refreshInterval); 84 + 85 + return () => clearInterval(interval); 86 + }, [autoRefresh, refreshInterval]); 87 + 88 + const { record, rkey, loading, error, empty } = useLatestRecord<TealFeedPlayRecord>( 89 + did, 90 + LAST_PLAYED_COLLECTION, 91 + refreshKey, 92 + ); 93 + 94 + // Normalize TealFeedPlayRecord to match TealActorStatusRecord structure 95 + // Use useMemo to prevent creating new object on every render 96 + // MUST be called before any conditional returns (Rules of Hooks) 97 + const normalizedRecord = useMemo(() => { 98 + if (!record) return null; 99 + 100 + return { 101 + $type: "fm.teal.alpha.actor.status" as const, 102 + item: { 103 + artists: record.artists, 104 + originUrl: record.originUrl, 105 + trackName: record.trackName, 106 + playedTime: record.playedTime, 107 + releaseName: record.releaseName, 108 + recordingMbId: record.recordingMbId, 109 + releaseMbId: record.releaseMbId, 110 + submissionClientAgent: record.submissionClientAgent, 111 + musicServiceBaseDomain: record.musicServiceBaseDomain, 112 + isrc: record.isrc, 113 + duration: record.duration, 114 + }, 115 + time: new Date(record.playedTime).getTime().toString(), 116 + expiry: undefined, 117 + }; 118 + }, [record]); 119 + 120 + const Comp = renderer ?? CurrentlyPlayingRenderer; 121 + 122 + // Now handle conditional returns after all hooks 123 + if (error) { 124 + return ( 125 + <div style={{ padding: 8, color: "var(--atproto-color-error)" }}> 126 + Failed to load last played track. 127 + </div> 128 + ); 129 + } 130 + 131 + if (loading && !record) { 132 + return loadingIndicator ? ( 133 + <>{loadingIndicator}</> 134 + ) : ( 135 + <div style={{ padding: 8, color: "var(--atproto-color-text-secondary)" }}> 136 + Loadingโ€ฆ 137 + </div> 138 + ); 139 + } 140 + 141 + if (empty || !record || !normalizedRecord) { 142 + return fallback ? ( 143 + <>{fallback}</> 144 + ) : ( 145 + <div style={{ padding: 8, color: "var(--atproto-color-text-secondary)" }}> 146 + No plays found. 147 + </div> 148 + ); 149 + } 150 + 151 + return ( 152 + <Comp 153 + record={normalizedRecord} 154 + loading={loading} 155 + error={error} 156 + colorScheme={colorScheme} 157 + did={did} 158 + rkey={rkey || "unknown"} 159 + label="LAST PLAYED" 160 + handle={handle} 161 + /> 162 + ); 163 + }); 164 + 165 + export default LastPlayed;
+3 -12
lib/components/LeafletDocument.tsx
··· 8 8 LeafletDocumentRecord, 9 9 LeafletPublicationRecord, 10 10 } from "../types/leaflet"; 11 - import type { ColorSchemePreference } from "../hooks/useColorScheme"; 12 11 import { 13 12 parseAtUri, 14 13 toBlueskyPostUrl, ··· 45 44 * Indicator rendered while data is being fetched from the PDS. 46 45 */ 47 46 loadingIndicator?: React.ReactNode; 48 - /** 49 - * Preferred color scheme to forward to the renderer. 50 - */ 51 - colorScheme?: ColorSchemePreference; 52 47 } 53 48 54 49 /** ··· 71 66 * @param colorScheme - Preferred color scheme forwarded to the renderer. 72 67 * @returns A JSX subtree that renders a Leaflet document with contextual metadata. 73 68 */ 74 - export const LeafletDocument: React.FC<LeafletDocumentProps> = ({ 69 + export const LeafletDocument: React.FC<LeafletDocumentProps> = React.memo(({ 75 70 did, 76 71 rkey, 77 72 record, 78 73 renderer, 79 74 fallback, 80 75 loadingIndicator, 81 - colorScheme, 82 76 }) => { 83 77 const Comp: React.ComponentType<LeafletDocumentRendererInjectedProps> = 84 78 renderer ?? ((props) => <LeafletDocumentRenderer {...props} />); ··· 111 105 return ( 112 106 <Comp 113 107 {...props} 114 - colorScheme={colorScheme} 115 108 did={did} 116 109 rkey={rkey} 117 110 canonicalUrl={canonicalUrl} ··· 121 114 ); 122 115 }; 123 116 124 - // When record is provided, pass it directly to skip fetching 125 - if (record) { 117 + if (record !== undefined) { 126 118 return ( 127 119 <AtProtoRecord<LeafletDocumentRecord> 128 120 record={record} ··· 133 125 ); 134 126 } 135 127 136 - // Otherwise fetch the record using did, collection, and rkey 137 128 return ( 138 129 <AtProtoRecord<LeafletDocumentRecord> 139 130 did={did} ··· 144 135 loadingIndicator={loadingIndicator} 145 136 /> 146 137 ); 147 - }; 138 + }); 148 139 149 140 /** 150 141 * Determines the best canonical URL to expose for a Leaflet document.
+125
lib/components/RichText.tsx
··· 1 + import React from "react"; 2 + import type { AppBskyRichtextFacet } from "@atcute/bluesky"; 3 + import { createTextSegments, type TextSegment } from "../utils/richtext"; 4 + import { useAtProto } from "../providers/AtProtoProvider"; 5 + 6 + export interface RichTextProps { 7 + text: string; 8 + facets?: AppBskyRichtextFacet.Main[]; 9 + style?: React.CSSProperties; 10 + } 11 + 12 + /** 13 + * RichText component that renders text with facets (mentions, links, hashtags). 14 + * Properly handles byte offsets and multi-byte characters. 15 + */ 16 + export const RichText: React.FC<RichTextProps> = ({ text, facets, style }) => { 17 + const { blueskyAppBaseUrl } = useAtProto(); 18 + const segments = createTextSegments(text, facets); 19 + 20 + return ( 21 + <span style={style}> 22 + {segments.map((segment, idx) => ( 23 + <RichTextSegment key={idx} segment={segment} blueskyAppBaseUrl={blueskyAppBaseUrl} /> 24 + ))} 25 + </span> 26 + ); 27 + }; 28 + 29 + interface RichTextSegmentProps { 30 + segment: TextSegment; 31 + blueskyAppBaseUrl: string; 32 + } 33 + 34 + const RichTextSegment: React.FC<RichTextSegmentProps> = ({ segment, blueskyAppBaseUrl }) => { 35 + if (!segment.facet) { 36 + return <>{segment.text}</>; 37 + } 38 + 39 + // Find the first feature in the facet 40 + const feature = segment.facet.features?.[0]; 41 + if (!feature) { 42 + return <>{segment.text}</>; 43 + } 44 + 45 + const featureType = (feature as { $type?: string }).$type; 46 + 47 + // Render based on feature type 48 + switch (featureType) { 49 + case "app.bsky.richtext.facet#link": { 50 + const linkFeature = feature as AppBskyRichtextFacet.Link; 51 + return ( 52 + <a 53 + href={linkFeature.uri} 54 + target="_blank" 55 + rel="noopener noreferrer" 56 + style={{ 57 + color: "var(--atproto-color-link)", 58 + textDecoration: "none", 59 + }} 60 + onMouseEnter={(e) => { 61 + e.currentTarget.style.textDecoration = "underline"; 62 + }} 63 + onMouseLeave={(e) => { 64 + e.currentTarget.style.textDecoration = "none"; 65 + }} 66 + > 67 + {segment.text} 68 + </a> 69 + ); 70 + } 71 + 72 + case "app.bsky.richtext.facet#mention": { 73 + const mentionFeature = feature as AppBskyRichtextFacet.Mention; 74 + const profileUrl = `${blueskyAppBaseUrl}/profile/${mentionFeature.did}`; 75 + return ( 76 + <a 77 + href={profileUrl} 78 + target="_blank" 79 + rel="noopener noreferrer" 80 + style={{ 81 + color: "var(--atproto-color-link)", 82 + textDecoration: "none", 83 + }} 84 + onMouseEnter={(e) => { 85 + e.currentTarget.style.textDecoration = "underline"; 86 + }} 87 + onMouseLeave={(e) => { 88 + e.currentTarget.style.textDecoration = "none"; 89 + }} 90 + > 91 + {segment.text} 92 + </a> 93 + ); 94 + } 95 + 96 + case "app.bsky.richtext.facet#tag": { 97 + const tagFeature = feature as AppBskyRichtextFacet.Tag; 98 + const tagUrl = `${blueskyAppBaseUrl}/hashtag/${encodeURIComponent(tagFeature.tag)}`; 99 + return ( 100 + <a 101 + href={tagUrl} 102 + target="_blank" 103 + rel="noopener noreferrer" 104 + style={{ 105 + color: "var(--atproto-color-link)", 106 + textDecoration: "none", 107 + }} 108 + onMouseEnter={(e) => { 109 + e.currentTarget.style.textDecoration = "underline"; 110 + }} 111 + onMouseLeave={(e) => { 112 + e.currentTarget.style.textDecoration = "none"; 113 + }} 114 + > 115 + {segment.text} 116 + </a> 117 + ); 118 + } 119 + 120 + default: 121 + return <>{segment.text}</>; 122 + } 123 + }; 124 + 125 + export default RichText;
+648
lib/components/SongHistoryList.tsx
··· 1 + import React, { useState, useEffect, useMemo } from "react"; 2 + import { usePaginatedRecords } from "../hooks/usePaginatedRecords"; 3 + import { useDidResolution } from "../hooks/useDidResolution"; 4 + import type { TealFeedPlayRecord } from "../types/teal"; 5 + 6 + /** 7 + * Options for rendering a paginated list of song history from teal.fm. 8 + */ 9 + export interface SongHistoryListProps { 10 + /** 11 + * DID whose song history should be fetched. 12 + */ 13 + did: string; 14 + /** 15 + * Maximum number of records to list per page. Defaults to `6`. 16 + */ 17 + limit?: number; 18 + /** 19 + * Enables pagination controls when `true`. Defaults to `true`. 20 + */ 21 + enablePagination?: boolean; 22 + } 23 + 24 + interface SonglinkResponse { 25 + linksByPlatform: { 26 + [platform: string]: { 27 + url: string; 28 + entityUniqueId: string; 29 + }; 30 + }; 31 + entitiesByUniqueId: { 32 + [id: string]: { 33 + thumbnailUrl?: string; 34 + title?: string; 35 + artistName?: string; 36 + }; 37 + }; 38 + entityUniqueId?: string; 39 + } 40 + 41 + /** 42 + * Fetches a user's song history from teal.fm and renders them with album art focus. 43 + * 44 + * @param did - DID whose song history should be displayed. 45 + * @param limit - Maximum number of songs per page. Default `6`. 46 + * @param enablePagination - Whether pagination controls should render. Default `true`. 47 + * @returns A card-like list element with loading, empty, and error handling. 48 + */ 49 + export const SongHistoryList: React.FC<SongHistoryListProps> = React.memo(({ 50 + did, 51 + limit = 6, 52 + enablePagination = true, 53 + }) => { 54 + const { handle: resolvedHandle } = useDidResolution(did); 55 + const actorLabel = resolvedHandle ?? formatDid(did); 56 + 57 + const { 58 + records, 59 + loading, 60 + error, 61 + hasNext, 62 + hasPrev, 63 + loadNext, 64 + loadPrev, 65 + pageIndex, 66 + pagesCount, 67 + } = usePaginatedRecords<TealFeedPlayRecord>({ 68 + did, 69 + collection: "fm.teal.alpha.feed.play", 70 + limit, 71 + }); 72 + 73 + const pageLabel = useMemo(() => { 74 + const knownTotal = Math.max(pageIndex + 1, pagesCount); 75 + if (!enablePagination) return undefined; 76 + if (hasNext && knownTotal === pageIndex + 1) 77 + return `${pageIndex + 1}/โ€ฆ`; 78 + return `${pageIndex + 1}/${knownTotal}`; 79 + }, [enablePagination, hasNext, pageIndex, pagesCount]); 80 + 81 + if (error) 82 + return ( 83 + <div role="alert" style={{ padding: 8, color: "crimson" }}> 84 + Failed to load song history. 85 + </div> 86 + ); 87 + 88 + return ( 89 + <div style={{ ...listStyles.card, background: `var(--atproto-color-bg)`, borderWidth: "1px", borderStyle: "solid", borderColor: `var(--atproto-color-border)` }}> 90 + <div style={{ ...listStyles.header, background: `var(--atproto-color-bg-elevated)`, color: `var(--atproto-color-text)` }}> 91 + <div style={listStyles.headerInfo}> 92 + <div style={listStyles.headerIcon}> 93 + <svg 94 + width="24" 95 + height="24" 96 + viewBox="0 0 24 24" 97 + fill="none" 98 + stroke="currentColor" 99 + strokeWidth="2" 100 + strokeLinecap="round" 101 + strokeLinejoin="round" 102 + > 103 + <path d="M9 18V5l12-2v13" /> 104 + <circle cx="6" cy="18" r="3" /> 105 + <circle cx="18" cy="16" r="3" /> 106 + </svg> 107 + </div> 108 + <div style={listStyles.headerText}> 109 + <span style={listStyles.title}>Listening History</span> 110 + <span 111 + style={{ 112 + ...listStyles.subtitle, 113 + color: `var(--atproto-color-text-secondary)`, 114 + }} 115 + > 116 + @{actorLabel} 117 + </span> 118 + </div> 119 + </div> 120 + {pageLabel && ( 121 + <span 122 + style={{ ...listStyles.pageMeta, color: `var(--atproto-color-text-secondary)` }} 123 + > 124 + {pageLabel} 125 + </span> 126 + )} 127 + </div> 128 + <div style={listStyles.items}> 129 + {loading && records.length === 0 && ( 130 + <div style={{ ...listStyles.empty, color: `var(--atproto-color-text-secondary)` }}> 131 + Loading songsโ€ฆ 132 + </div> 133 + )} 134 + {records.map((record, idx) => ( 135 + <SongRow 136 + key={`${record.rkey}-${record.value.playedTime}`} 137 + record={record.value} 138 + hasDivider={idx < records.length - 1} 139 + /> 140 + ))} 141 + {!loading && records.length === 0 && ( 142 + <div style={{ ...listStyles.empty, color: `var(--atproto-color-text-secondary)` }}> 143 + No songs found. 144 + </div> 145 + )} 146 + </div> 147 + {enablePagination && ( 148 + <div style={{ ...listStyles.footer, borderTopColor: `var(--atproto-color-border)`, color: `var(--atproto-color-text)` }}> 149 + <button 150 + type="button" 151 + style={{ 152 + ...listStyles.pageButton, 153 + background: `var(--atproto-color-button-bg)`, 154 + color: `var(--atproto-color-button-text)`, 155 + cursor: hasPrev ? "pointer" : "not-allowed", 156 + opacity: hasPrev ? 1 : 0.5, 157 + }} 158 + onClick={loadPrev} 159 + disabled={!hasPrev} 160 + > 161 + โ€น Prev 162 + </button> 163 + <div style={listStyles.pageChips}> 164 + <span 165 + style={{ 166 + ...listStyles.pageChipActive, 167 + color: `var(--atproto-color-button-text)`, 168 + background: `var(--atproto-color-button-bg)`, 169 + borderWidth: "1px", 170 + borderStyle: "solid", 171 + borderColor: `var(--atproto-color-button-bg)`, 172 + }} 173 + > 174 + {pageIndex + 1} 175 + </span> 176 + {(hasNext || pagesCount > pageIndex + 1) && ( 177 + <span 178 + style={{ 179 + ...listStyles.pageChip, 180 + color: `var(--atproto-color-text-secondary)`, 181 + borderWidth: "1px", 182 + borderStyle: "solid", 183 + borderColor: `var(--atproto-color-border)`, 184 + background: `var(--atproto-color-bg)`, 185 + }} 186 + > 187 + {pageIndex + 2} 188 + </span> 189 + )} 190 + </div> 191 + <button 192 + type="button" 193 + style={{ 194 + ...listStyles.pageButton, 195 + background: `var(--atproto-color-button-bg)`, 196 + color: `var(--atproto-color-button-text)`, 197 + cursor: hasNext ? "pointer" : "not-allowed", 198 + opacity: hasNext ? 1 : 0.5, 199 + }} 200 + onClick={loadNext} 201 + disabled={!hasNext} 202 + > 203 + Next โ€บ 204 + </button> 205 + </div> 206 + )} 207 + {loading && records.length > 0 && ( 208 + <div 209 + style={{ ...listStyles.loadingBar, background: `var(--atproto-color-bg-elevated)`, color: `var(--atproto-color-text-secondary)` }} 210 + > 211 + Updatingโ€ฆ 212 + </div> 213 + )} 214 + </div> 215 + ); 216 + }); 217 + 218 + interface SongRowProps { 219 + record: TealFeedPlayRecord; 220 + hasDivider: boolean; 221 + } 222 + 223 + const SongRow: React.FC<SongRowProps> = ({ record, hasDivider }) => { 224 + const [albumArt, setAlbumArt] = useState<string | undefined>(undefined); 225 + const [artLoading, setArtLoading] = useState(true); 226 + 227 + const artistNames = record.artists.map((a) => a.artistName).join(", "); 228 + const relative = record.playedTime 229 + ? formatRelativeTime(record.playedTime) 230 + : undefined; 231 + const absolute = record.playedTime 232 + ? new Date(record.playedTime).toLocaleString() 233 + : undefined; 234 + 235 + useEffect(() => { 236 + let cancelled = false; 237 + setArtLoading(true); 238 + setAlbumArt(undefined); 239 + 240 + const fetchAlbumArt = async () => { 241 + try { 242 + // Try ISRC first 243 + if (record.isrc) { 244 + const response = await fetch( 245 + `https://api.song.link/v1-alpha.1/links?platform=isrc&type=song&id=${encodeURIComponent(record.isrc)}&songIfSingle=true` 246 + ); 247 + if (cancelled) return; 248 + if (response.ok) { 249 + const data: SonglinkResponse = await response.json(); 250 + const entityId = data.entityUniqueId; 251 + const entity = entityId ? data.entitiesByUniqueId?.[entityId] : undefined; 252 + if (entity?.thumbnailUrl) { 253 + setAlbumArt(entity.thumbnailUrl); 254 + setArtLoading(false); 255 + return; 256 + } 257 + } 258 + } 259 + 260 + // Fallback to iTunes search 261 + const iTunesSearchUrl = `https://itunes.apple.com/search?term=${encodeURIComponent( 262 + `${record.trackName} ${artistNames}` 263 + )}&media=music&entity=song&limit=1`; 264 + 265 + const iTunesResponse = await fetch(iTunesSearchUrl); 266 + if (cancelled) return; 267 + 268 + if (iTunesResponse.ok) { 269 + const iTunesData = await iTunesResponse.json(); 270 + if (iTunesData.results && iTunesData.results.length > 0) { 271 + const match = iTunesData.results[0]; 272 + const artworkUrl = match.artworkUrl100?.replace('100x100', '600x600') || match.artworkUrl100; 273 + if (artworkUrl) { 274 + setAlbumArt(artworkUrl); 275 + } 276 + } 277 + } 278 + setArtLoading(false); 279 + } catch (err) { 280 + console.error(`Failed to fetch album art for "${record.trackName}":`, err); 281 + setArtLoading(false); 282 + } 283 + }; 284 + 285 + fetchAlbumArt(); 286 + 287 + return () => { 288 + cancelled = true; 289 + }; 290 + }, [record.trackName, artistNames, record.isrc]); 291 + 292 + return ( 293 + <div 294 + style={{ 295 + ...listStyles.row, 296 + color: `var(--atproto-color-text)`, 297 + borderBottom: hasDivider 298 + ? `1px solid var(--atproto-color-border)` 299 + : "none", 300 + }} 301 + > 302 + {/* Album Art - Large and prominent */} 303 + <div style={listStyles.albumArtContainer}> 304 + {artLoading ? ( 305 + <div style={listStyles.albumArtPlaceholder}> 306 + <div style={listStyles.loadingSpinner} /> 307 + </div> 308 + ) : albumArt ? ( 309 + <img 310 + src={albumArt} 311 + alt={`${record.releaseName || "Album"} cover`} 312 + style={listStyles.albumArt} 313 + onError={(e) => { 314 + e.currentTarget.style.display = "none"; 315 + const parent = e.currentTarget.parentElement; 316 + if (parent) { 317 + const placeholder = document.createElement("div"); 318 + Object.assign(placeholder.style, listStyles.albumArtPlaceholder); 319 + placeholder.innerHTML = ` 320 + <svg 321 + width="48" 322 + height="48" 323 + viewBox="0 0 24 24" 324 + fill="none" 325 + stroke="currentColor" 326 + stroke-width="1.5" 327 + > 328 + <circle cx="12" cy="12" r="10" /> 329 + <circle cx="12" cy="12" r="3" /> 330 + <path d="M12 2v3M12 19v3M2 12h3M19 12h3" /> 331 + </svg> 332 + `; 333 + parent.appendChild(placeholder); 334 + } 335 + }} 336 + /> 337 + ) : ( 338 + <div style={listStyles.albumArtPlaceholder}> 339 + <svg 340 + width="48" 341 + height="48" 342 + viewBox="0 0 24 24" 343 + fill="none" 344 + stroke="currentColor" 345 + strokeWidth="1.5" 346 + > 347 + <circle cx="12" cy="12" r="10" /> 348 + <circle cx="12" cy="12" r="3" /> 349 + <path d="M12 2v3M12 19v3M2 12h3M19 12h3" /> 350 + </svg> 351 + </div> 352 + )} 353 + </div> 354 + 355 + {/* Song Info */} 356 + <div style={listStyles.songInfo}> 357 + <div style={listStyles.trackName}>{record.trackName}</div> 358 + <div style={{ ...listStyles.artistName, color: `var(--atproto-color-text-secondary)` }}> 359 + {artistNames} 360 + </div> 361 + {record.releaseName && ( 362 + <div style={{ ...listStyles.releaseName, color: `var(--atproto-color-text-secondary)` }}> 363 + {record.releaseName} 364 + </div> 365 + )} 366 + {relative && ( 367 + <div 368 + style={{ ...listStyles.playedTime, color: `var(--atproto-color-text-secondary)` }} 369 + title={absolute} 370 + > 371 + {relative} 372 + </div> 373 + )} 374 + </div> 375 + 376 + {/* External Link */} 377 + {record.originUrl && ( 378 + <a 379 + href={record.originUrl} 380 + target="_blank" 381 + rel="noopener noreferrer" 382 + style={listStyles.externalLink} 383 + title="Listen on streaming service" 384 + aria-label={`Listen to ${record.trackName} by ${artistNames}`} 385 + > 386 + <svg 387 + width="20" 388 + height="20" 389 + viewBox="0 0 24 24" 390 + fill="none" 391 + stroke="currentColor" 392 + strokeWidth="2" 393 + strokeLinecap="round" 394 + strokeLinejoin="round" 395 + > 396 + <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" /> 397 + <polyline points="15 3 21 3 21 9" /> 398 + <line x1="10" y1="14" x2="21" y2="3" /> 399 + </svg> 400 + </a> 401 + )} 402 + </div> 403 + ); 404 + }; 405 + 406 + function formatDid(did: string) { 407 + return did.replace(/^did:(plc:)?/, ""); 408 + } 409 + 410 + function formatRelativeTime(iso: string): string { 411 + const date = new Date(iso); 412 + const diffSeconds = (date.getTime() - Date.now()) / 1000; 413 + const absSeconds = Math.abs(diffSeconds); 414 + const thresholds: Array<{ 415 + limit: number; 416 + unit: Intl.RelativeTimeFormatUnit; 417 + divisor: number; 418 + }> = [ 419 + { limit: 60, unit: "second", divisor: 1 }, 420 + { limit: 3600, unit: "minute", divisor: 60 }, 421 + { limit: 86400, unit: "hour", divisor: 3600 }, 422 + { limit: 604800, unit: "day", divisor: 86400 }, 423 + { limit: 2629800, unit: "week", divisor: 604800 }, 424 + { limit: 31557600, unit: "month", divisor: 2629800 }, 425 + { limit: Infinity, unit: "year", divisor: 31557600 }, 426 + ]; 427 + const threshold = 428 + thresholds.find((t) => absSeconds < t.limit) ?? 429 + thresholds[thresholds.length - 1]; 430 + const value = diffSeconds / threshold.divisor; 431 + const rtf = new Intl.RelativeTimeFormat("en", { numeric: "auto" }); 432 + return rtf.format(Math.round(value), threshold.unit); 433 + } 434 + 435 + const listStyles = { 436 + card: { 437 + borderRadius: 16, 438 + borderWidth: "1px", 439 + borderStyle: "solid", 440 + borderColor: "transparent", 441 + boxShadow: "0 8px 18px -12px rgba(15, 23, 42, 0.25)", 442 + overflow: "hidden", 443 + display: "flex", 444 + flexDirection: "column", 445 + } satisfies React.CSSProperties, 446 + header: { 447 + display: "flex", 448 + alignItems: "center", 449 + justifyContent: "space-between", 450 + padding: "14px 18px", 451 + fontSize: 14, 452 + fontWeight: 500, 453 + borderBottom: "1px solid var(--atproto-color-border)", 454 + } satisfies React.CSSProperties, 455 + headerInfo: { 456 + display: "flex", 457 + alignItems: "center", 458 + gap: 12, 459 + } satisfies React.CSSProperties, 460 + headerIcon: { 461 + width: 28, 462 + height: 28, 463 + display: "flex", 464 + alignItems: "center", 465 + justifyContent: "center", 466 + borderRadius: "50%", 467 + color: "var(--atproto-color-text)", 468 + } satisfies React.CSSProperties, 469 + headerText: { 470 + display: "flex", 471 + flexDirection: "column", 472 + gap: 2, 473 + } satisfies React.CSSProperties, 474 + title: { 475 + fontSize: 15, 476 + fontWeight: 600, 477 + } satisfies React.CSSProperties, 478 + subtitle: { 479 + fontSize: 12, 480 + fontWeight: 500, 481 + } satisfies React.CSSProperties, 482 + pageMeta: { 483 + fontSize: 12, 484 + } satisfies React.CSSProperties, 485 + items: { 486 + display: "flex", 487 + flexDirection: "column", 488 + } satisfies React.CSSProperties, 489 + empty: { 490 + padding: "24px 18px", 491 + fontSize: 13, 492 + textAlign: "center", 493 + } satisfies React.CSSProperties, 494 + row: { 495 + padding: "18px", 496 + display: "flex", 497 + gap: 16, 498 + alignItems: "center", 499 + transition: "background-color 120ms ease", 500 + position: "relative", 501 + } satisfies React.CSSProperties, 502 + albumArtContainer: { 503 + width: 96, 504 + height: 96, 505 + flexShrink: 0, 506 + borderRadius: 8, 507 + overflow: "hidden", 508 + boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)", 509 + } satisfies React.CSSProperties, 510 + albumArt: { 511 + width: "100%", 512 + height: "100%", 513 + objectFit: "cover", 514 + display: "block", 515 + } satisfies React.CSSProperties, 516 + albumArtPlaceholder: { 517 + width: "100%", 518 + height: "100%", 519 + display: "flex", 520 + alignItems: "center", 521 + justifyContent: "center", 522 + background: "linear-gradient(135deg, #667eea 0%, #764ba2 100%)", 523 + color: "rgba(255, 255, 255, 0.6)", 524 + } satisfies React.CSSProperties, 525 + loadingSpinner: { 526 + width: 28, 527 + height: 28, 528 + border: "3px solid rgba(255, 255, 255, 0.3)", 529 + borderTop: "3px solid rgba(255, 255, 255, 0.9)", 530 + borderRadius: "50%", 531 + animation: "spin 1s linear infinite", 532 + } satisfies React.CSSProperties, 533 + songInfo: { 534 + flex: 1, 535 + display: "flex", 536 + flexDirection: "column", 537 + gap: 4, 538 + minWidth: 0, 539 + } satisfies React.CSSProperties, 540 + trackName: { 541 + fontSize: 16, 542 + fontWeight: 600, 543 + lineHeight: 1.3, 544 + color: "var(--atproto-color-text)", 545 + overflow: "hidden", 546 + textOverflow: "ellipsis", 547 + whiteSpace: "nowrap", 548 + } satisfies React.CSSProperties, 549 + artistName: { 550 + fontSize: 14, 551 + fontWeight: 500, 552 + overflow: "hidden", 553 + textOverflow: "ellipsis", 554 + whiteSpace: "nowrap", 555 + } satisfies React.CSSProperties, 556 + releaseName: { 557 + fontSize: 13, 558 + overflow: "hidden", 559 + textOverflow: "ellipsis", 560 + whiteSpace: "nowrap", 561 + } satisfies React.CSSProperties, 562 + playedTime: { 563 + fontSize: 12, 564 + fontWeight: 500, 565 + marginTop: 2, 566 + } satisfies React.CSSProperties, 567 + externalLink: { 568 + flexShrink: 0, 569 + width: 36, 570 + height: 36, 571 + display: "flex", 572 + alignItems: "center", 573 + justifyContent: "center", 574 + borderRadius: "50%", 575 + background: "var(--atproto-color-bg-elevated)", 576 + border: "1px solid var(--atproto-color-border)", 577 + color: "var(--atproto-color-text-secondary)", 578 + cursor: "pointer", 579 + transition: "all 0.2s ease", 580 + textDecoration: "none", 581 + } satisfies React.CSSProperties, 582 + footer: { 583 + display: "flex", 584 + alignItems: "center", 585 + justifyContent: "space-between", 586 + padding: "12px 18px", 587 + borderTop: "1px solid transparent", 588 + fontSize: 13, 589 + } satisfies React.CSSProperties, 590 + pageChips: { 591 + display: "flex", 592 + gap: 6, 593 + alignItems: "center", 594 + } satisfies React.CSSProperties, 595 + pageChip: { 596 + padding: "4px 10px", 597 + borderRadius: 999, 598 + fontSize: 13, 599 + borderWidth: "1px", 600 + borderStyle: "solid", 601 + borderColor: "transparent", 602 + } satisfies React.CSSProperties, 603 + pageChipActive: { 604 + padding: "4px 10px", 605 + borderRadius: 999, 606 + fontSize: 13, 607 + fontWeight: 600, 608 + borderWidth: "1px", 609 + borderStyle: "solid", 610 + borderColor: "transparent", 611 + } satisfies React.CSSProperties, 612 + pageButton: { 613 + border: "none", 614 + borderRadius: 999, 615 + padding: "6px 12px", 616 + fontSize: 13, 617 + fontWeight: 500, 618 + background: "transparent", 619 + display: "flex", 620 + alignItems: "center", 621 + gap: 4, 622 + transition: "background-color 120ms ease", 623 + } satisfies React.CSSProperties, 624 + loadingBar: { 625 + padding: "4px 18px 14px", 626 + fontSize: 12, 627 + textAlign: "right", 628 + color: "#64748b", 629 + } satisfies React.CSSProperties, 630 + }; 631 + 632 + // Add keyframes and hover styles 633 + if (typeof document !== "undefined") { 634 + const styleId = "song-history-styles"; 635 + if (!document.getElementById(styleId)) { 636 + const styleElement = document.createElement("style"); 637 + styleElement.id = styleId; 638 + styleElement.textContent = ` 639 + @keyframes spin { 640 + 0% { transform: rotate(0deg); } 641 + 100% { transform: rotate(360deg); } 642 + } 643 + `; 644 + document.head.appendChild(styleElement); 645 + } 646 + } 647 + 648 + export default SongHistoryList;
+131
lib/components/TangledRepo.tsx
··· 1 + import React from "react"; 2 + import { AtProtoRecord } from "../core/AtProtoRecord"; 3 + import { TangledRepoRenderer } from "../renderers/TangledRepoRenderer"; 4 + import type { TangledRepoRecord } from "../types/tangled"; 5 + import { useAtProto } from "../providers/AtProtoProvider"; 6 + 7 + /** 8 + * Props for rendering Tangled Repo records. 9 + */ 10 + export interface TangledRepoProps { 11 + /** DID of the repository that stores the repo record. */ 12 + did: string; 13 + /** Record key within the `sh.tangled.repo` collection. */ 14 + rkey: string; 15 + /** Prefetched Tangled Repo record. When provided, skips fetching from the network. */ 16 + record?: TangledRepoRecord; 17 + /** Optional renderer override for custom presentation. */ 18 + renderer?: React.ComponentType<TangledRepoRendererInjectedProps>; 19 + /** Fallback node displayed before loading begins. */ 20 + fallback?: React.ReactNode; 21 + /** Indicator node shown while data is loading. */ 22 + loadingIndicator?: React.ReactNode; 23 + /** Preferred color scheme for theming. */ 24 + colorScheme?: "light" | "dark" | "system"; 25 + /** Whether to show star count from backlinks. Defaults to true. */ 26 + showStarCount?: boolean; 27 + /** Branch to query for language information. Defaults to trying "main", then "master". */ 28 + branch?: string; 29 + /** Prefetched language names (e.g., ['TypeScript', 'React']). When provided, skips fetching languages from the knot server. */ 30 + languages?: string[]; 31 + } 32 + 33 + /** 34 + * Values injected into custom Tangled Repo renderer implementations. 35 + */ 36 + export type TangledRepoRendererInjectedProps = { 37 + /** Loaded Tangled Repo record value. */ 38 + record: TangledRepoRecord; 39 + /** Indicates whether the record is currently loading. */ 40 + loading: boolean; 41 + /** Fetch error, if any. */ 42 + error?: Error; 43 + /** Preferred color scheme for downstream components. */ 44 + colorScheme?: "light" | "dark" | "system"; 45 + /** DID associated with the record. */ 46 + did: string; 47 + /** Record key for the repo. */ 48 + rkey: string; 49 + /** Canonical external URL for linking to the repo. */ 50 + canonicalUrl: string; 51 + /** Whether to show star count from backlinks. */ 52 + showStarCount?: boolean; 53 + /** Branch to query for language information. */ 54 + branch?: string; 55 + /** Prefetched language names. */ 56 + languages?: string[]; 57 + }; 58 + 59 + /** NSID for Tangled Repo records. */ 60 + export const TANGLED_REPO_COLLECTION = "sh.tangled.repo"; 61 + 62 + /** 63 + * Resolves a Tangled Repo record and renders it with optional overrides while computing a canonical link. 64 + * 65 + * @param did - DID whose Tangled Repo should be fetched. 66 + * @param rkey - Record key within the Tangled Repo collection. 67 + * @param renderer - Optional component override that will receive injected props. 68 + * @param fallback - Node rendered before the first load begins. 69 + * @param loadingIndicator - Node rendered while the Tangled Repo is loading. 70 + * @param colorScheme - Preferred color scheme for theming the renderer. 71 + * @param showStarCount - Whether to show star count from backlinks. Defaults to true. 72 + * @param branch - Branch to query for language information. Defaults to trying "main", then "master". 73 + * @param languages - Prefetched language names (e.g., ['TypeScript', 'React']). When provided, skips fetching languages from the knot server. 74 + * @returns A JSX subtree representing the Tangled Repo record with loading states handled. 75 + */ 76 + export const TangledRepo: React.FC<TangledRepoProps> = React.memo(({ 77 + did, 78 + rkey, 79 + record, 80 + renderer, 81 + fallback, 82 + loadingIndicator, 83 + colorScheme, 84 + showStarCount = true, 85 + branch, 86 + languages, 87 + }) => { 88 + const { tangledBaseUrl } = useAtProto(); 89 + const Comp: React.ComponentType<TangledRepoRendererInjectedProps> = 90 + renderer ?? ((props) => <TangledRepoRenderer {...props} />); 91 + const Wrapped: React.FC<{ 92 + record: TangledRepoRecord; 93 + loading: boolean; 94 + error?: Error; 95 + }> = (props) => ( 96 + <Comp 97 + {...props} 98 + colorScheme={colorScheme} 99 + did={did} 100 + rkey={rkey} 101 + canonicalUrl={`${tangledBaseUrl}/${did}/${encodeURIComponent(props.record.name)}`} 102 + showStarCount={showStarCount} 103 + branch={branch} 104 + languages={languages} 105 + /> 106 + ); 107 + 108 + if (record !== undefined) { 109 + return ( 110 + <AtProtoRecord<TangledRepoRecord> 111 + record={record} 112 + renderer={Wrapped} 113 + fallback={fallback} 114 + loadingIndicator={loadingIndicator} 115 + /> 116 + ); 117 + } 118 + 119 + return ( 120 + <AtProtoRecord<TangledRepoRecord> 121 + did={did} 122 + collection={TANGLED_REPO_COLLECTION} 123 + rkey={rkey} 124 + renderer={Wrapped} 125 + fallback={fallback} 126 + loadingIndicator={loadingIndicator} 127 + /> 128 + ); 129 + }); 130 + 131 + export default TangledRepo;
+7 -7
lib/components/TangledString.tsx
··· 1 1 import React from "react"; 2 2 import { AtProtoRecord } from "../core/AtProtoRecord"; 3 3 import { TangledStringRenderer } from "../renderers/TangledStringRenderer"; 4 - import type { TangledStringRecord } from "../renderers/TangledStringRenderer"; 4 + import type { TangledStringRecord } from "../types/tangled"; 5 + import { useAtProto } from "../providers/AtProtoProvider"; 5 6 6 7 /** 7 8 * Props for rendering Tangled String records. ··· 57 58 * @param colorScheme - Preferred color scheme for theming the renderer. 58 59 * @returns A JSX subtree representing the Tangled String record with loading states handled. 59 60 */ 60 - export const TangledString: React.FC<TangledStringProps> = ({ 61 + export const TangledString: React.FC<TangledStringProps> = React.memo(({ 61 62 did, 62 63 rkey, 63 64 record, ··· 66 67 loadingIndicator, 67 68 colorScheme, 68 69 }) => { 70 + const { tangledBaseUrl } = useAtProto(); 69 71 const Comp: React.ComponentType<TangledStringRendererInjectedProps> = 70 72 renderer ?? ((props) => <TangledStringRenderer {...props} />); 71 73 const Wrapped: React.FC<{ ··· 78 80 colorScheme={colorScheme} 79 81 did={did} 80 82 rkey={rkey} 81 - canonicalUrl={`https://tangled.org/strings/${did}/${encodeURIComponent(rkey)}`} 83 + canonicalUrl={`${tangledBaseUrl}/strings/${did}/${encodeURIComponent(rkey)}`} 82 84 /> 83 85 ); 84 86 85 - // When record is provided, pass it directly to skip fetching 86 - if (record) { 87 + if (record !== undefined) { 87 88 return ( 88 89 <AtProtoRecord<TangledStringRecord> 89 90 record={record} ··· 94 95 ); 95 96 } 96 97 97 - // Otherwise fetch the record using did, collection, and rkey 98 98 return ( 99 99 <AtProtoRecord<TangledStringRecord> 100 100 did={did} ··· 105 105 loadingIndicator={loadingIndicator} 106 106 /> 107 107 ); 108 - }; 108 + }); 109 109 110 110 export default TangledString;
+123 -6
lib/core/AtProtoRecord.tsx
··· 1 - import React from "react"; 1 + import React, { useState, useEffect, useRef } from "react"; 2 2 import { useAtProtoRecord } from "../hooks/useAtProtoRecord"; 3 3 4 + /** 5 + * Common rendering customization props for AT Protocol records. 6 + */ 4 7 interface AtProtoRecordRenderProps<T> { 8 + /** Custom renderer component that receives the fetched record and loading state. */ 5 9 renderer?: React.ComponentType<{ 6 10 record: T; 7 11 loading: boolean; 8 12 error?: Error; 9 13 }>; 14 + /** React node displayed when no record is available (after error or before load). */ 10 15 fallback?: React.ReactNode; 16 + /** React node shown while the record is being fetched. */ 11 17 loadingIndicator?: React.ReactNode; 18 + /** Auto-refresh interval in milliseconds. When set, the record will be refetched at this interval. */ 19 + refreshInterval?: number; 20 + /** Comparison function to determine if a record has changed. Used to prevent unnecessary re-renders during auto-refresh. */ 21 + compareRecords?: (prev: T | undefined, next: T | undefined) => boolean; 12 22 } 13 23 24 + /** 25 + * Props for fetching an AT Protocol record from the network. 26 + */ 14 27 type AtProtoRecordFetchProps<T> = AtProtoRecordRenderProps<T> & { 28 + /** Repository DID that owns the record. */ 15 29 did: string; 30 + /** NSID collection containing the record. */ 16 31 collection: string; 32 + /** Record key identifying the specific record. */ 17 33 rkey: string; 34 + /** Must be undefined when fetching (discriminates the union type). */ 18 35 record?: undefined; 19 36 }; 20 37 38 + /** 39 + * Props for rendering a prefetched AT Protocol record. 40 + */ 21 41 type AtProtoRecordProvidedRecordProps<T> = AtProtoRecordRenderProps<T> & { 42 + /** Prefetched record value to render (skips network fetch). */ 22 43 record: T; 44 + /** Optional DID for context (not used for fetching). */ 23 45 did?: string; 46 + /** Optional collection for context (not used for fetching). */ 24 47 collection?: string; 48 + /** Optional rkey for context (not used for fetching). */ 25 49 rkey?: string; 26 50 }; 27 51 52 + /** 53 + * Union type for AT Protocol record props - supports both fetching and prefetched records. 54 + */ 28 55 export type AtProtoRecordProps<T = unknown> = 29 56 | AtProtoRecordFetchProps<T> 30 57 | AtProtoRecordProvidedRecordProps<T>; 31 58 59 + /** 60 + * Core component for fetching and rendering AT Protocol records with customizable presentation. 61 + * 62 + * Supports two modes: 63 + * 1. **Fetch mode**: Provide `did`, `collection`, and `rkey` to fetch the record from the network 64 + * 2. **Prefetch mode**: Provide a `record` directly to skip fetching (useful for SSR/caching) 65 + * 66 + * When no custom renderer is provided, displays the record as formatted JSON. 67 + * 68 + * **Auto-refresh**: Set `refreshInterval` to automatically refetch the record at the specified interval. 69 + * The component intelligently avoids re-rendering if the record hasn't changed (using `compareRecords`). 70 + * 71 + * @example 72 + * ```tsx 73 + * // Fetch mode - retrieves record from network 74 + * <AtProtoRecord 75 + * did="did:plc:example" 76 + * collection="app.bsky.feed.post" 77 + * rkey="3k2aexample" 78 + * renderer={MyCustomRenderer} 79 + * /> 80 + * ``` 81 + * 82 + * @example 83 + * ```tsx 84 + * // Prefetch mode - uses provided record 85 + * <AtProtoRecord 86 + * record={myPrefetchedRecord} 87 + * renderer={MyCustomRenderer} 88 + * /> 89 + * ``` 90 + * 91 + * @example 92 + * ```tsx 93 + * // Auto-refresh mode - refetches every 15 seconds 94 + * <AtProtoRecord 95 + * did="did:plc:example" 96 + * collection="fm.teal.alpha.actor.status" 97 + * rkey="self" 98 + * refreshInterval={15000} 99 + * compareRecords={(prev, next) => JSON.stringify(prev) === JSON.stringify(next)} 100 + * renderer={MyCustomRenderer} 101 + * /> 102 + * ``` 103 + * 104 + * @param props - Either fetch props (did/collection/rkey) or prefetch props (record). 105 + * @returns A rendered AT Protocol record with loading/error states handled. 106 + */ 32 107 export function AtProtoRecord<T = unknown>(props: AtProtoRecordProps<T>) { 33 108 const { 34 109 renderer: Renderer, 35 110 fallback = null, 36 111 loadingIndicator = "Loadingโ€ฆ", 112 + refreshInterval, 113 + compareRecords, 37 114 } = props; 38 115 const hasProvidedRecord = "record" in props; 39 116 const providedRecord = hasProvidedRecord ? props.record : undefined; 40 117 118 + // Extract fetch props for logging 119 + const fetchDid = hasProvidedRecord ? undefined : (props as any).did; 120 + const fetchCollection = hasProvidedRecord ? undefined : (props as any).collection; 121 + const fetchRkey = hasProvidedRecord ? undefined : (props as any).rkey; 122 + 123 + // State for managing auto-refresh 124 + const [refreshKey, setRefreshKey] = useState(0); 125 + const [stableRecord, setStableRecord] = useState<T | undefined>(providedRecord); 126 + const previousRecordRef = useRef<T | undefined>(providedRecord); 127 + 128 + // Auto-refresh interval 129 + useEffect(() => { 130 + if (!refreshInterval || hasProvidedRecord) return; 131 + 132 + const interval = setInterval(() => { 133 + setRefreshKey((prev) => prev + 1); 134 + }, refreshInterval); 135 + 136 + return () => clearInterval(interval); 137 + }, [refreshInterval, hasProvidedRecord, fetchCollection, fetchDid]); 138 + 41 139 const { 42 140 record: fetchedRecord, 43 141 error, 44 142 loading, 45 143 } = useAtProtoRecord<T>({ 46 - did: hasProvidedRecord ? undefined : props.did, 47 - collection: hasProvidedRecord ? undefined : props.collection, 48 - rkey: hasProvidedRecord ? undefined : props.rkey, 144 + did: fetchDid, 145 + collection: fetchCollection, 146 + rkey: fetchRkey, 147 + bypassCache: !!refreshInterval && refreshKey > 0, // Bypass cache on auto-refresh (but not initial load) 148 + _refreshKey: refreshKey, // Force hook to re-run 49 149 }); 50 150 51 - const record = providedRecord ?? fetchedRecord; 52 - const isLoading = loading && !providedRecord; 151 + // Determine which record to use 152 + const currentRecord = providedRecord ?? fetchedRecord; 153 + 154 + // Handle record changes with optional comparison 155 + useEffect(() => { 156 + if (!currentRecord) return; 157 + 158 + const hasChanged = compareRecords 159 + ? !compareRecords(previousRecordRef.current, currentRecord) 160 + : previousRecordRef.current !== currentRecord; 161 + 162 + if (hasChanged) { 163 + setStableRecord(currentRecord); 164 + previousRecordRef.current = currentRecord; 165 + } 166 + }, [currentRecord, compareRecords]); 167 + 168 + const record = stableRecord; 169 + const isLoading = loading && !providedRecord && !stableRecord; 53 170 54 171 if (error && !record) return <>{fallback}</>; 55 172 if (!record) return <>{isLoading ? loadingIndicator : fallback}</>;
+182 -27
lib/hooks/useAtProtoRecord.ts
··· 1 - import { useEffect, useState } from "react"; 1 + import { useEffect, useState, useRef } from "react"; 2 2 import { useDidResolution } from "./useDidResolution"; 3 3 import { usePdsEndpoint } from "./usePdsEndpoint"; 4 4 import { createAtprotoClient } from "../utils/atproto-client"; 5 + import { useBlueskyAppview } from "./useBlueskyAppview"; 6 + import { useAtProto } from "../providers/AtProtoProvider"; 5 7 6 8 /** 7 9 * Identifier trio required to address an AT Protocol record. ··· 13 15 collection?: string; 14 16 /** Record key string uniquely identifying the record within the collection. */ 15 17 rkey?: string; 18 + /** Force bypass cache and refetch from network. Useful for auto-refresh scenarios. */ 19 + bypassCache?: boolean; 20 + /** Internal refresh trigger - changes to this value force a refetch. */ 21 + _refreshKey?: number; 16 22 } 17 23 18 24 /** ··· 29 35 30 36 /** 31 37 * React hook that fetches a single AT Protocol record and tracks loading/error state. 38 + * 39 + * For Bluesky collections (app.bsky.*), uses a three-tier fallback strategy: 40 + * 1. Try Bluesky appview API first 41 + * 2. Fall back to Slingshot getRecord 42 + * 3. Finally query the PDS directly 43 + * 44 + * For other collections, queries the PDS directly (with Slingshot fallback via the client handler). 32 45 * 33 46 * @param did - DID (or handle before resolution) that owns the record. 34 47 * @param collection - NSID collection from which to fetch the record. 35 48 * @param rkey - Record key identifying the record within the collection. 49 + * @param bypassCache - Force bypass cache and refetch from network. Useful for auto-refresh scenarios. 50 + * @param _refreshKey - Internal parameter used to trigger refetches. 36 51 * @returns {AtProtoRecordState<T>} Object containing the resolved record, any error, and a loading flag. 37 52 */ 38 53 export function useAtProtoRecord<T = unknown>({ 39 54 did: handleOrDid, 40 55 collection, 41 56 rkey, 57 + bypassCache = false, 58 + _refreshKey = 0, 42 59 }: AtProtoRecordKey): AtProtoRecordState<T> { 60 + const { recordCache } = useAtProto(); 61 + const isBlueskyCollection = collection?.startsWith("app.bsky."); 62 + 63 + // Always call all hooks (React rules) - conditionally use results 64 + const blueskyResult = useBlueskyAppview<T>({ 65 + did: isBlueskyCollection ? handleOrDid : undefined, 66 + collection: isBlueskyCollection ? collection : undefined, 67 + rkey: isBlueskyCollection ? rkey : undefined, 68 + }); 69 + 43 70 const { 44 71 did, 45 72 error: didError, ··· 53 80 const [state, setState] = useState<AtProtoRecordState<T>>({ 54 81 loading: !!(handleOrDid && collection && rkey), 55 82 }); 83 + 84 + const releaseRef = useRef<(() => void) | undefined>(undefined); 56 85 57 86 useEffect(() => { 58 87 let cancelled = false; ··· 70 99 }); 71 100 return () => { 72 101 cancelled = true; 102 + if (releaseRef.current) { 103 + releaseRef.current(); 104 + releaseRef.current = undefined; 105 + } 73 106 }; 74 107 } 75 108 ··· 77 110 assignState({ loading: false, error: didError }); 78 111 return () => { 79 112 cancelled = true; 113 + if (releaseRef.current) { 114 + releaseRef.current(); 115 + releaseRef.current = undefined; 116 + } 80 117 }; 81 118 } 82 119 ··· 84 121 assignState({ loading: false, error: endpointError }); 85 122 return () => { 86 123 cancelled = true; 124 + if (releaseRef.current) { 125 + releaseRef.current(); 126 + releaseRef.current = undefined; 127 + } 87 128 }; 88 129 } 89 130 ··· 91 132 assignState({ loading: true, error: undefined }); 92 133 return () => { 93 134 cancelled = true; 135 + if (releaseRef.current) { 136 + releaseRef.current(); 137 + releaseRef.current = undefined; 138 + } 94 139 }; 95 140 } 96 141 97 142 assignState({ loading: true, error: undefined, record: undefined }); 98 143 99 - (async () => { 100 - try { 101 - const { rpc } = await createAtprotoClient({ 102 - service: endpoint, 144 + // Bypass cache if requested (for auto-refresh scenarios) 145 + if (bypassCache) { 146 + assignState({ loading: true, error: undefined }); 147 + 148 + // Skip cache and fetch directly 149 + const controller = new AbortController(); 150 + 151 + const fetchPromise = (async () => { 152 + try { 153 + const { rpc } = await createAtprotoClient({ 154 + service: endpoint, 155 + }); 156 + const res = await ( 157 + rpc as unknown as { 158 + get: ( 159 + nsid: string, 160 + opts: { 161 + params: { 162 + repo: string; 163 + collection: string; 164 + rkey: string; 165 + }; 166 + }, 167 + ) => Promise<{ ok: boolean; data: { value: T } }>; 168 + } 169 + ).get("com.atproto.repo.getRecord", { 170 + params: { repo: did, collection, rkey }, 171 + }); 172 + if (!res.ok) throw new Error("Failed to load record"); 173 + return (res.data as { value: T }).value; 174 + } catch (err) { 175 + // Provide helpful error for banned/unreachable Bluesky PDSes 176 + if (endpoint.includes('.bsky.network')) { 177 + throw new Error( 178 + `Record unavailable. The Bluesky PDS (${endpoint}) may be unreachable or the account may be banned.` 179 + ); 180 + } 181 + throw err; 182 + } 183 + })(); 184 + 185 + fetchPromise 186 + .then((record) => { 187 + if (!cancelled) { 188 + assignState({ record, loading: false }); 189 + } 190 + }) 191 + .catch((e) => { 192 + if (!cancelled) { 193 + const err = e instanceof Error ? e : new Error(String(e)); 194 + assignState({ error: err, loading: false }); 195 + } 103 196 }); 104 - const res = await ( 105 - rpc as unknown as { 106 - get: ( 107 - nsid: string, 108 - opts: { 109 - params: { 110 - repo: string; 111 - collection: string; 112 - rkey: string; 113 - }; 114 - }, 115 - ) => Promise<{ ok: boolean; data: { value: T } }>; 197 + 198 + return () => { 199 + cancelled = true; 200 + controller.abort(); 201 + }; 202 + } 203 + 204 + // Use recordCache.ensure for deduplication and caching 205 + const { promise, release } = recordCache.ensure<T>( 206 + did, 207 + collection, 208 + rkey, 209 + () => { 210 + const controller = new AbortController(); 211 + 212 + const fetchPromise = (async () => { 213 + try { 214 + const { rpc } = await createAtprotoClient({ 215 + service: endpoint, 216 + }); 217 + const res = await ( 218 + rpc as unknown as { 219 + get: ( 220 + nsid: string, 221 + opts: { 222 + params: { 223 + repo: string; 224 + collection: string; 225 + rkey: string; 226 + }; 227 + }, 228 + ) => Promise<{ ok: boolean; data: { value: T } }>; 229 + } 230 + ).get("com.atproto.repo.getRecord", { 231 + params: { repo: did, collection, rkey }, 232 + }); 233 + if (!res.ok) throw new Error("Failed to load record"); 234 + return (res.data as { value: T }).value; 235 + } catch (err) { 236 + // Provide helpful error for banned/unreachable Bluesky PDSes 237 + if (endpoint.includes('.bsky.network')) { 238 + throw new Error( 239 + `Record unavailable. The Bluesky PDS (${endpoint}) may be unreachable or the account may be banned.` 240 + ); 241 + } 242 + throw err; 116 243 } 117 - ).get("com.atproto.repo.getRecord", { 118 - params: { repo: did, collection, rkey }, 119 - }); 120 - if (!res.ok) throw new Error("Failed to load record"); 121 - const record = (res.data as { value: T }).value; 122 - assignState({ record, loading: false }); 123 - } catch (e) { 124 - const err = e instanceof Error ? e : new Error(String(e)); 125 - assignState({ error: err, loading: false }); 244 + })(); 245 + 246 + return { 247 + promise: fetchPromise, 248 + abort: () => controller.abort(), 249 + }; 126 250 } 127 - })(); 251 + ); 252 + 253 + releaseRef.current = release; 254 + 255 + promise 256 + .then((record) => { 257 + if (!cancelled) { 258 + assignState({ record, loading: false }); 259 + } 260 + }) 261 + .catch((e) => { 262 + if (!cancelled) { 263 + const err = e instanceof Error ? e : new Error(String(e)); 264 + assignState({ error: err, loading: false }); 265 + } 266 + }); 128 267 129 268 return () => { 130 269 cancelled = true; 270 + if (releaseRef.current) { 271 + releaseRef.current(); 272 + releaseRef.current = undefined; 273 + } 131 274 }; 132 275 }, [ 133 276 handleOrDid, ··· 139 282 resolvingEndpoint, 140 283 didError, 141 284 endpointError, 285 + recordCache, 286 + bypassCache, 287 + _refreshKey, 142 288 ]); 289 + 290 + // Return Bluesky result for app.bsky.* collections 291 + if (isBlueskyCollection) { 292 + return { 293 + record: blueskyResult.record, 294 + error: blueskyResult.error, 295 + loading: blueskyResult.loading, 296 + }; 297 + } 143 298 144 299 return state; 145 300 }
+163
lib/hooks/useBacklinks.ts
··· 1 + import { useEffect, useState, useCallback, useRef } from "react"; 2 + 3 + /** 4 + * Individual backlink record returned by Microcosm Constellation. 5 + */ 6 + export interface BacklinkRecord { 7 + /** DID of the author who created the backlink. */ 8 + did: string; 9 + /** Collection type of the backlink record (e.g., "sh.tangled.feed.star"). */ 10 + collection: string; 11 + /** Record key of the backlink. */ 12 + rkey: string; 13 + } 14 + 15 + /** 16 + * Response from Microcosm Constellation API. 17 + */ 18 + export interface BacklinksResponse { 19 + /** Total count of backlinks. */ 20 + total: number; 21 + /** Array of backlink records. */ 22 + records: BacklinkRecord[]; 23 + /** Cursor for pagination (optional). */ 24 + cursor?: string; 25 + } 26 + 27 + /** 28 + * Parameters for fetching backlinks. 29 + */ 30 + export interface UseBacklinksParams { 31 + /** The AT-URI subject to get backlinks for (e.g., "at://did:plc:xxx/sh.tangled.repo/yyy"). */ 32 + subject: string; 33 + /** The source collection and path (e.g., "sh.tangled.feed.star:subject"). */ 34 + source: string; 35 + /** Maximum number of results to fetch (default: 16, max: 100). */ 36 + limit?: number; 37 + /** Base URL for the Microcosm Constellation API. */ 38 + constellationBaseUrl?: string; 39 + /** Whether to automatically fetch backlinks on mount. */ 40 + enabled?: boolean; 41 + } 42 + 43 + const DEFAULT_CONSTELLATION = "https://constellation.microcosm.blue"; 44 + 45 + /** 46 + * Hook to fetch backlinks from Microcosm Constellation API. 47 + * 48 + * Backlinks are records that reference another record. For example, 49 + * `sh.tangled.feed.star` records are backlinks to `sh.tangled.repo` records, 50 + * representing users who have starred a repository. 51 + * 52 + * @param params - Configuration for fetching backlinks 53 + * @returns Object containing backlinks data, loading state, error, and refetch function 54 + * 55 + * @example 56 + * ```tsx 57 + * const { backlinks, loading, error, count } = useBacklinks({ 58 + * subject: "at://did:plc:example/sh.tangled.repo/3k2aexample", 59 + * source: "sh.tangled.feed.star:subject", 60 + * }); 61 + * ``` 62 + */ 63 + export function useBacklinks({ 64 + subject, 65 + source, 66 + limit = 16, 67 + constellationBaseUrl = DEFAULT_CONSTELLATION, 68 + enabled = true, 69 + }: UseBacklinksParams) { 70 + const [backlinks, setBacklinks] = useState<BacklinkRecord[]>([]); 71 + const [total, setTotal] = useState(0); 72 + const [loading, setLoading] = useState(false); 73 + const [error, setError] = useState<Error | undefined>(undefined); 74 + const [cursor, setCursor] = useState<string | undefined>(undefined); 75 + const abortControllerRef = useRef<AbortController | null>(null); 76 + 77 + const fetchBacklinks = useCallback( 78 + async (signal?: AbortSignal) => { 79 + if (!subject || !source || !enabled) return; 80 + 81 + try { 82 + setLoading(true); 83 + setError(undefined); 84 + 85 + const baseUrl = constellationBaseUrl.endsWith("/") 86 + ? constellationBaseUrl.slice(0, -1) 87 + : constellationBaseUrl; 88 + 89 + const params = new URLSearchParams({ 90 + subject: subject, 91 + source: source, 92 + limit: limit.toString(), 93 + }); 94 + 95 + const url = `${baseUrl}/xrpc/blue.microcosm.links.getBacklinks?${params}`; 96 + 97 + const response = await fetch(url, { signal }); 98 + 99 + if (!response.ok) { 100 + throw new Error( 101 + `Failed to fetch backlinks: ${response.status} ${response.statusText}`, 102 + ); 103 + } 104 + 105 + const data: BacklinksResponse = await response.json(); 106 + setBacklinks(data.records || []); 107 + setTotal(data.total || 0); 108 + setCursor(data.cursor); 109 + } catch (err) { 110 + if (err instanceof Error && err.name === "AbortError") { 111 + // Ignore abort errors 112 + return; 113 + } 114 + setError( 115 + err instanceof Error ? err : new Error("Unknown error fetching backlinks"), 116 + ); 117 + } finally { 118 + setLoading(false); 119 + } 120 + }, 121 + [subject, source, limit, constellationBaseUrl, enabled], 122 + ); 123 + 124 + const refetch = useCallback(() => { 125 + // Abort any in-flight request 126 + if (abortControllerRef.current) { 127 + abortControllerRef.current.abort(); 128 + } 129 + 130 + const controller = new AbortController(); 131 + abortControllerRef.current = controller; 132 + fetchBacklinks(controller.signal); 133 + }, [fetchBacklinks]); 134 + 135 + useEffect(() => { 136 + if (!enabled) return; 137 + 138 + const controller = new AbortController(); 139 + abortControllerRef.current = controller; 140 + fetchBacklinks(controller.signal); 141 + 142 + return () => { 143 + controller.abort(); 144 + }; 145 + }, [fetchBacklinks, enabled]); 146 + 147 + return { 148 + /** Array of backlink records. */ 149 + backlinks, 150 + /** Whether backlinks are currently being fetched. */ 151 + loading, 152 + /** Error if fetch failed. */ 153 + error, 154 + /** Pagination cursor (not yet implemented for pagination). */ 155 + cursor, 156 + /** Total count of backlinks from the API. */ 157 + total, 158 + /** Total count of backlinks (alias for total). */ 159 + count: total, 160 + /** Function to manually refetch backlinks. */ 161 + refetch, 162 + }; 163 + }
+727
lib/hooks/useBlueskyAppview.ts
··· 1 + import { useEffect, useReducer, useRef } from "react"; 2 + import { useDidResolution } from "./useDidResolution"; 3 + import { usePdsEndpoint } from "./usePdsEndpoint"; 4 + import { createAtprotoClient } from "../utils/atproto-client"; 5 + import { useAtProto } from "../providers/AtProtoProvider"; 6 + 7 + /** 8 + * Extended blob reference that includes CDN URL from appview responses. 9 + */ 10 + export interface BlobWithCdn { 11 + $type: "blob"; 12 + ref: { $link: string }; 13 + mimeType: string; 14 + size: number; 15 + /** CDN URL from Bluesky appview (e.g., https://cdn.bsky.app/img/avatar/plain/did:plc:xxx/bafkreixxx@jpeg) */ 16 + cdnUrl?: string; 17 + } 18 + 19 + 20 + 21 + /** 22 + * Appview getProfile response structure. 23 + */ 24 + interface AppviewProfileResponse { 25 + did: string; 26 + handle: string; 27 + displayName?: string; 28 + description?: string; 29 + avatar?: string; 30 + banner?: string; 31 + createdAt?: string; 32 + pronouns?: string; 33 + website?: string; 34 + [key: string]: unknown; 35 + } 36 + 37 + /** 38 + * Appview getPostThread response structure. 39 + */ 40 + interface AppviewPostThreadResponse<T = unknown> { 41 + thread?: { 42 + post?: { 43 + record?: T; 44 + embed?: { 45 + $type?: string; 46 + images?: Array<{ 47 + thumb?: string; 48 + fullsize?: string; 49 + alt?: string; 50 + aspectRatio?: { width: number; height: number }; 51 + }>; 52 + media?: { 53 + images?: Array<{ 54 + thumb?: string; 55 + fullsize?: string; 56 + alt?: string; 57 + aspectRatio?: { width: number; height: number }; 58 + }>; 59 + }; 60 + }; 61 + }; 62 + }; 63 + } 64 + 65 + /** 66 + * Options for {@link useBlueskyAppview}. 67 + */ 68 + export interface UseBlueskyAppviewOptions { 69 + /** DID or handle of the actor. */ 70 + did?: string; 71 + /** NSID collection (e.g., "app.bsky.feed.post"). */ 72 + collection?: string; 73 + /** Record key within the collection. */ 74 + rkey?: string; 75 + /** Override for the Bluesky appview service URL. Defaults to public.api.bsky.app. */ 76 + appviewService?: string; 77 + /** If true, skip the appview and go straight to Slingshot/PDS fallback. */ 78 + skipAppview?: boolean; 79 + } 80 + 81 + /** 82 + * Result returned from {@link useBlueskyAppview}. 83 + */ 84 + export interface UseBlueskyAppviewResult<T = unknown> { 85 + /** The fetched record value. */ 86 + record?: T; 87 + /** Indicates whether a fetch is in progress. */ 88 + loading: boolean; 89 + /** Error encountered during fetch. */ 90 + error?: Error; 91 + /** Source from which the record was successfully fetched. */ 92 + source?: "appview" | "slingshot" | "pds"; 93 + } 94 + 95 + /** 96 + * Maps Bluesky collection NSIDs to their corresponding appview API endpoints. 97 + * Only includes endpoints that can fetch individual records (not list endpoints). 98 + */ 99 + const BLUESKY_COLLECTION_TO_ENDPOINT: Record<string, string> = { 100 + "app.bsky.actor.profile": "app.bsky.actor.getProfile", 101 + "app.bsky.feed.post": "app.bsky.feed.getPostThread", 102 + 103 + }; 104 + 105 + /** 106 + * React hook that fetches a Bluesky record with a three-tier fallback strategy: 107 + * 1. Try the Bluesky appview API endpoint (e.g., getProfile, getPostThread) 108 + * 2. Fall back to Slingshot's getRecord 109 + * 3. As a last resort, query the actor's PDS directly 110 + * 111 + * The hook automatically handles DID resolution and determines the appropriate API endpoint 112 + * based on the collection type. The `source` field in the result indicates which tier 113 + * successfully returned the record. 114 + * 115 + * @example 116 + * ```tsx 117 + * // Fetch a Bluesky post with automatic fallback 118 + * import { useBlueskyAppview } from 'atproto-ui'; 119 + * import type { FeedPostRecord } from 'atproto-ui'; 120 + * 121 + * function MyPost({ did, rkey }: { did: string; rkey: string }) { 122 + * const { record, loading, error, source } = useBlueskyAppview<FeedPostRecord>({ 123 + * did, 124 + * collection: 'app.bsky.feed.post', 125 + * rkey, 126 + * }); 127 + * 128 + * if (loading) return <p>Loading post...</p>; 129 + * if (error) return <p>Error: {error.message}</p>; 130 + * if (!record) return <p>No post found</p>; 131 + * 132 + * return ( 133 + * <article> 134 + * <p>{record.text}</p> 135 + * <small>Fetched from: {source}</small> 136 + * </article> 137 + * ); 138 + * } 139 + * ``` 140 + * 141 + * @example 142 + * ```tsx 143 + * // Fetch a Bluesky profile 144 + * import { useBlueskyAppview } from 'atproto-ui'; 145 + * import type { ProfileRecord } from 'atproto-ui'; 146 + * 147 + * function MyProfile({ handle }: { handle: string }) { 148 + * const { record, loading, error } = useBlueskyAppview<ProfileRecord>({ 149 + * did: handle, // Handles are automatically resolved to DIDs 150 + * collection: 'app.bsky.actor.profile', 151 + * rkey: 'self', 152 + * }); 153 + * 154 + * if (loading) return <p>Loading profile...</p>; 155 + * if (!record) return null; 156 + * 157 + * return ( 158 + * <div> 159 + * <h2>{record.displayName}</h2> 160 + * <p>{record.description}</p> 161 + * </div> 162 + * ); 163 + * } 164 + * ``` 165 + * 166 + * @example 167 + * ```tsx 168 + * // Skip the appview and go directly to Slingshot/PDS 169 + * const { record } = useBlueskyAppview({ 170 + * did: 'did:plc:example', 171 + * collection: 'app.bsky.feed.post', 172 + * rkey: '3k2aexample', 173 + * skipAppview: true, // Bypasses Bluesky API, starts with Slingshot 174 + * }); 175 + * ``` 176 + * 177 + * @param options - Configuration object with did, collection, rkey, and optional overrides. 178 + * @returns {UseBlueskyAppviewResult<T>} Object containing the record, loading state, error, and source. 179 + */ 180 + 181 + // Reducer action types for useBlueskyAppview 182 + type BlueskyAppviewAction<T> = 183 + | { type: "SET_LOADING"; loading: boolean } 184 + | { type: "SET_SUCCESS"; record: T; source: "appview" | "slingshot" | "pds" } 185 + | { type: "SET_ERROR"; error: Error } 186 + | { type: "RESET" }; 187 + 188 + // Reducer function for atomic state updates 189 + function blueskyAppviewReducer<T>( 190 + state: UseBlueskyAppviewResult<T>, 191 + action: BlueskyAppviewAction<T> 192 + ): UseBlueskyAppviewResult<T> { 193 + switch (action.type) { 194 + case "SET_LOADING": 195 + return { 196 + ...state, 197 + loading: action.loading, 198 + error: undefined, 199 + }; 200 + case "SET_SUCCESS": 201 + return { 202 + record: action.record, 203 + loading: false, 204 + error: undefined, 205 + source: action.source, 206 + }; 207 + case "SET_ERROR": 208 + // Only update if error message changed (stabilize error reference) 209 + if (state.error?.message === action.error.message) { 210 + return state; 211 + } 212 + return { 213 + ...state, 214 + loading: false, 215 + error: action.error, 216 + source: undefined, 217 + }; 218 + case "RESET": 219 + return { 220 + record: undefined, 221 + loading: false, 222 + error: undefined, 223 + source: undefined, 224 + }; 225 + default: 226 + return state; 227 + } 228 + } 229 + 230 + export function useBlueskyAppview<T = unknown>({ 231 + did: handleOrDid, 232 + collection, 233 + rkey, 234 + appviewService, 235 + skipAppview = false, 236 + }: UseBlueskyAppviewOptions): UseBlueskyAppviewResult<T> { 237 + const { recordCache, blueskyAppviewService, resolver } = useAtProto(); 238 + const effectiveAppviewService = appviewService ?? blueskyAppviewService; 239 + 240 + // Only use this hook for Bluesky collections (app.bsky.*) 241 + const isBlueskyCollection = collection?.startsWith("app.bsky."); 242 + 243 + const { 244 + did, 245 + error: didError, 246 + loading: resolvingDid, 247 + } = useDidResolution(handleOrDid); 248 + const { 249 + endpoint: pdsEndpoint, 250 + error: endpointError, 251 + loading: resolvingEndpoint, 252 + } = usePdsEndpoint(did); 253 + 254 + const [state, dispatch] = useReducer(blueskyAppviewReducer<T>, { 255 + record: undefined, 256 + loading: false, 257 + error: undefined, 258 + source: undefined, 259 + }); 260 + 261 + const releaseRef = useRef<(() => void) | undefined>(undefined); 262 + 263 + useEffect(() => { 264 + let cancelled = false; 265 + 266 + // Early returns for missing inputs or resolution errors 267 + if (!handleOrDid || !collection || !rkey) { 268 + if (!cancelled) dispatch({ type: "RESET" }); 269 + return () => { 270 + cancelled = true; 271 + if (releaseRef.current) { 272 + releaseRef.current(); 273 + releaseRef.current = undefined; 274 + } 275 + }; 276 + } 277 + 278 + // Return early if not a Bluesky collection - this hook should not be used for other lexicons 279 + if (!isBlueskyCollection) { 280 + if (!cancelled) dispatch({ type: "RESET" }); 281 + return () => { 282 + cancelled = true; 283 + if (releaseRef.current) { 284 + releaseRef.current(); 285 + releaseRef.current = undefined; 286 + } 287 + }; 288 + } 289 + 290 + if (didError) { 291 + if (!cancelled) dispatch({ type: "SET_ERROR", error: didError }); 292 + return () => { 293 + cancelled = true; 294 + if (releaseRef.current) { 295 + releaseRef.current(); 296 + releaseRef.current = undefined; 297 + } 298 + }; 299 + } 300 + 301 + if (endpointError) { 302 + if (!cancelled) dispatch({ type: "SET_ERROR", error: endpointError }); 303 + return () => { 304 + cancelled = true; 305 + if (releaseRef.current) { 306 + releaseRef.current(); 307 + releaseRef.current = undefined; 308 + } 309 + }; 310 + } 311 + 312 + if (resolvingDid || resolvingEndpoint || !did || !pdsEndpoint) { 313 + if (!cancelled) dispatch({ type: "SET_LOADING", loading: true }); 314 + return () => { 315 + cancelled = true; 316 + if (releaseRef.current) { 317 + releaseRef.current(); 318 + releaseRef.current = undefined; 319 + } 320 + }; 321 + } 322 + 323 + // Start fetching 324 + dispatch({ type: "SET_LOADING", loading: true }); 325 + 326 + // Use recordCache.ensure for deduplication and caching 327 + const { promise, release } = recordCache.ensure<{ record: T; source: "appview" | "slingshot" | "pds" }>( 328 + did, 329 + collection, 330 + rkey, 331 + () => { 332 + const controller = new AbortController(); 333 + 334 + const fetchPromise = (async (): Promise<{ record: T; source: "appview" | "slingshot" | "pds" }> => { 335 + let lastError: Error | undefined; 336 + 337 + // Tier 1: Try Bluesky appview API 338 + if (!skipAppview && BLUESKY_COLLECTION_TO_ENDPOINT[collection]) { 339 + try { 340 + const result = await fetchFromAppview<T>( 341 + did, 342 + collection, 343 + rkey, 344 + effectiveAppviewService, 345 + ); 346 + if (result) { 347 + return { record: result, source: "appview" }; 348 + } 349 + } catch (err) { 350 + lastError = err as Error; 351 + // Continue to next tier 352 + } 353 + } 354 + 355 + // Tier 2: Try Slingshot getRecord 356 + try { 357 + const slingshotUrl = resolver.getSlingshotUrl(); 358 + const result = await fetchFromSlingshot<T>(did, collection, rkey, slingshotUrl); 359 + if (result) { 360 + return { record: result, source: "slingshot" }; 361 + } 362 + } catch (err) { 363 + lastError = err as Error; 364 + // Continue to next tier 365 + } 366 + 367 + // Tier 3: Try PDS directly 368 + try { 369 + const result = await fetchFromPds<T>( 370 + did, 371 + collection, 372 + rkey, 373 + pdsEndpoint, 374 + ); 375 + if (result) { 376 + return { record: result, source: "pds" }; 377 + } 378 + } catch (err) { 379 + lastError = err as Error; 380 + } 381 + 382 + // All tiers failed - provide helpful error for banned/unreachable Bluesky PDSes 383 + if (pdsEndpoint.includes('.bsky.network')) { 384 + throw new Error( 385 + `Record unavailable. The Bluesky PDS (${pdsEndpoint}) may be unreachable or the account may be banned.` 386 + ); 387 + } 388 + 389 + throw lastError ?? new Error("Failed to fetch record from all sources"); 390 + })(); 391 + 392 + return { 393 + promise: fetchPromise, 394 + abort: () => controller.abort(), 395 + }; 396 + } 397 + ); 398 + 399 + releaseRef.current = release; 400 + 401 + promise 402 + .then(({ record, source }) => { 403 + if (!cancelled) { 404 + dispatch({ 405 + type: "SET_SUCCESS", 406 + record, 407 + source, 408 + }); 409 + } 410 + }) 411 + .catch((err) => { 412 + if (!cancelled) { 413 + dispatch({ 414 + type: "SET_ERROR", 415 + error: err instanceof Error ? err : new Error(String(err)), 416 + }); 417 + } 418 + }); 419 + 420 + return () => { 421 + cancelled = true; 422 + if (releaseRef.current) { 423 + releaseRef.current(); 424 + releaseRef.current = undefined; 425 + } 426 + }; 427 + }, [ 428 + handleOrDid, 429 + did, 430 + collection, 431 + rkey, 432 + pdsEndpoint, 433 + effectiveAppviewService, 434 + skipAppview, 435 + resolvingDid, 436 + resolvingEndpoint, 437 + didError, 438 + endpointError, 439 + recordCache, 440 + resolver, 441 + ]); 442 + 443 + return state; 444 + } 445 + 446 + /** 447 + * Attempts to fetch a record from the Bluesky appview API. 448 + * Different collections map to different endpoints with varying response structures. 449 + */ 450 + async function fetchFromAppview<T>( 451 + did: string, 452 + collection: string, 453 + rkey: string, 454 + appviewService: string, 455 + ): Promise<T | undefined> { 456 + const { rpc } = await createAtprotoClient({ service: appviewService }); 457 + const endpoint = BLUESKY_COLLECTION_TO_ENDPOINT[collection]; 458 + 459 + if (!endpoint) { 460 + throw new Error(`No appview endpoint mapped for collection ${collection}`); 461 + } 462 + 463 + const atUri = `at://${did}/${collection}/${rkey}`; 464 + 465 + // Handle different appview endpoints 466 + if (endpoint === "app.bsky.actor.getProfile") { 467 + const res = await (rpc as unknown as { get: (nsid: string, opts: { params: Record<string, unknown> }) => Promise<{ ok: boolean; data: AppviewProfileResponse }> }).get(endpoint, { 468 + params: { actor: did }, 469 + }); 470 + 471 + if (!res.ok) throw new Error(`Appview ${endpoint} request failed for ${did}`); 472 + 473 + // The appview returns avatar/banner as CDN URLs like: 474 + // https://cdn.bsky.app/img/avatar/plain/{did}/{cid}@jpeg 475 + // We need to extract the CID and convert to ProfileRecord format 476 + const profile = res.data; 477 + const avatarCid = extractCidFromCdnUrl(profile.avatar); 478 + const bannerCid = extractCidFromCdnUrl(profile.banner); 479 + 480 + // Convert hydrated profile to ProfileRecord format 481 + // Store the CDN URL directly so components can use it without re-fetching 482 + const record: Record<string, unknown> = { 483 + displayName: profile.displayName, 484 + description: profile.description, 485 + createdAt: profile.createdAt, 486 + }; 487 + 488 + // Add pronouns and website if they exist 489 + if (profile.pronouns) { 490 + record.pronouns = profile.pronouns; 491 + } 492 + 493 + if (profile.website) { 494 + record.website = profile.website; 495 + } 496 + 497 + if (profile.avatar && avatarCid) { 498 + const avatarBlob: BlobWithCdn = { 499 + $type: "blob", 500 + ref: { $link: avatarCid }, 501 + mimeType: "image/jpeg", 502 + size: 0, 503 + cdnUrl: profile.avatar, 504 + }; 505 + record.avatar = avatarBlob; 506 + } 507 + 508 + if (profile.banner && bannerCid) { 509 + const bannerBlob: BlobWithCdn = { 510 + $type: "blob", 511 + ref: { $link: bannerCid }, 512 + mimeType: "image/jpeg", 513 + size: 0, 514 + cdnUrl: profile.banner, 515 + }; 516 + record.banner = bannerBlob; 517 + } 518 + 519 + return record as T; 520 + } 521 + 522 + if (endpoint === "app.bsky.feed.getPostThread") { 523 + const res = await (rpc as unknown as { get: (nsid: string, opts: { params: Record<string, unknown> }) => Promise<{ ok: boolean; data: AppviewPostThreadResponse<T> }> }).get(endpoint, { 524 + params: { uri: atUri, depth: 0 }, 525 + }); 526 + 527 + if (!res.ok) throw new Error(`Appview ${endpoint} request failed for ${atUri}`); 528 + 529 + const post = res.data.thread?.post; 530 + if (!post?.record) return undefined; 531 + 532 + const record = post.record as Record<string, unknown>; 533 + const appviewEmbed = post.embed; 534 + 535 + // If the appview includes embedded images with CDN URLs, inject them into the record 536 + if (appviewEmbed && record.embed) { 537 + const recordEmbed = record.embed as { $type?: string; images?: Array<Record<string, unknown>>; media?: Record<string, unknown> }; 538 + 539 + // Handle direct image embeds 540 + if (appviewEmbed.$type === "app.bsky.embed.images#view" && appviewEmbed.images) { 541 + if (recordEmbed.images && Array.isArray(recordEmbed.images)) { 542 + recordEmbed.images = recordEmbed.images.map((img: Record<string, unknown>, idx: number) => { 543 + const appviewImg = appviewEmbed.images?.[idx]; 544 + if (appviewImg?.fullsize) { 545 + const cid = extractCidFromCdnUrl(appviewImg.fullsize); 546 + const imageObj = img.image as { ref?: { $link?: string } } | undefined; 547 + return { 548 + ...img, 549 + image: { 550 + ...(img.image as Record<string, unknown> || {}), 551 + cdnUrl: appviewImg.fullsize, 552 + ref: { $link: cid || imageObj?.ref?.$link }, 553 + }, 554 + }; 555 + } 556 + return img; 557 + }); 558 + } 559 + } 560 + 561 + // Handle recordWithMedia embeds 562 + if (appviewEmbed.$type === "app.bsky.embed.recordWithMedia#view" && appviewEmbed.media) { 563 + const mediaImages = appviewEmbed.media.images; 564 + const mediaEmbedImages = (recordEmbed.media as { images?: Array<Record<string, unknown>> } | undefined)?.images; 565 + if (mediaImages && mediaEmbedImages && Array.isArray(mediaEmbedImages)) { 566 + (recordEmbed.media as { images: Array<Record<string, unknown>> }).images = mediaEmbedImages.map((img: Record<string, unknown>, idx: number) => { 567 + const appviewImg = mediaImages[idx]; 568 + if (appviewImg?.fullsize) { 569 + const cid = extractCidFromCdnUrl(appviewImg.fullsize); 570 + const imageObj = img.image as { ref?: { $link?: string } } | undefined; 571 + return { 572 + ...img, 573 + image: { 574 + ...(img.image as Record<string, unknown> || {}), 575 + cdnUrl: appviewImg.fullsize, 576 + ref: { $link: cid || imageObj?.ref?.$link }, 577 + }, 578 + }; 579 + } 580 + return img; 581 + }); 582 + } 583 + } 584 + } 585 + 586 + return record as T; 587 + } 588 + 589 + // For other endpoints, we might not have a clean way to extract the specific record 590 + // Fall through to let the caller try the next tier 591 + throw new Error(`Appview endpoint ${endpoint} not fully implemented`); 592 + } 593 + 594 + /** 595 + * Attempts to fetch a record from Slingshot's getRecord endpoint. 596 + */ 597 + async function fetchFromSlingshot<T>( 598 + did: string, 599 + collection: string, 600 + rkey: string, 601 + slingshotBaseUrl: string, 602 + ): Promise<T | undefined> { 603 + const res = await callGetRecord<T>(slingshotBaseUrl, did, collection, rkey); 604 + if (!res.ok) throw new Error(`Slingshot getRecord failed for ${did}/${collection}/${rkey}`); 605 + return res.data.value; 606 + } 607 + 608 + /** 609 + * Attempts to fetch a record directly from the actor's PDS. 610 + */ 611 + async function fetchFromPds<T>( 612 + did: string, 613 + collection: string, 614 + rkey: string, 615 + pdsEndpoint: string, 616 + ): Promise<T | undefined> { 617 + const res = await callGetRecord<T>(pdsEndpoint, did, collection, rkey); 618 + if (!res.ok) throw new Error(`PDS getRecord failed for ${did}/${collection}/${rkey} at ${pdsEndpoint}`); 619 + return res.data.value; 620 + } 621 + 622 + /** 623 + * Extracts and validates CID from Bluesky CDN URL. 624 + * Format: https://cdn.bsky.app/img/{type}/plain/{did}/{cid}@{format} 625 + * 626 + * @throws Error if URL format is invalid or CID extraction fails 627 + */ 628 + function extractCidFromCdnUrl(url: string | undefined): string | undefined { 629 + if (!url) return undefined; 630 + 631 + try { 632 + // Match pattern: /did:plc:xxxxx/CIDHERE@format or /did:web:xxxxx/CIDHERE@format 633 + const match = url.match(/\/did:[^/]+\/([^@/]+)@/); 634 + const cid = match?.[1]; 635 + 636 + if (!cid) { 637 + console.warn(`Failed to extract CID from CDN URL: ${url}`); 638 + return undefined; 639 + } 640 + 641 + // Basic CID validation - should start with common CID prefixes 642 + if (!cid.startsWith("bafk") && !cid.startsWith("bafyb") && !cid.startsWith("Qm")) { 643 + console.warn(`Extracted string does not appear to be a valid CID: ${cid} from URL: ${url}`); 644 + return undefined; 645 + } 646 + 647 + return cid; 648 + } catch (err) { 649 + console.error(`Error extracting CID from CDN URL: ${url}`, err); 650 + return undefined; 651 + } 652 + } 653 + 654 + /** 655 + * Shared RPC utility for making appview API calls with proper typing. 656 + */ 657 + export async function callAppviewRpc<TResponse>( 658 + service: string, 659 + nsid: string, 660 + params: Record<string, unknown>, 661 + ): Promise<{ ok: boolean; data: TResponse }> { 662 + const { rpc } = await createAtprotoClient({ service }); 663 + return await (rpc as unknown as { 664 + get: (nsid: string, opts: { params: Record<string, unknown> }) => Promise<{ ok: boolean; data: TResponse }>; 665 + }).get(nsid, { params }); 666 + } 667 + 668 + /** 669 + * Shared RPC utility for making getRecord calls (Slingshot or PDS). 670 + */ 671 + export async function callGetRecord<T>( 672 + service: string, 673 + did: string, 674 + collection: string, 675 + rkey: string, 676 + ): Promise<{ ok: boolean; data: { value: T } }> { 677 + const { rpc } = await createAtprotoClient({ service }); 678 + return await (rpc as unknown as { 679 + get: (nsid: string, opts: { params: Record<string, unknown> }) => Promise<{ ok: boolean; data: { value: T } }>; 680 + }).get("com.atproto.repo.getRecord", { 681 + params: { repo: did, collection, rkey }, 682 + }); 683 + } 684 + 685 + /** 686 + * Shared RPC utility for making listRecords calls. 687 + */ 688 + export async function callListRecords<T>( 689 + service: string, 690 + did: string, 691 + collection: string, 692 + limit: number, 693 + cursor?: string, 694 + ): Promise<{ 695 + ok: boolean; 696 + data: { 697 + records: Array<{ uri: string; rkey?: string; value: T }>; 698 + cursor?: string; 699 + }; 700 + }> { 701 + const { rpc } = await createAtprotoClient({ service }); 702 + 703 + const params: Record<string, unknown> = { 704 + repo: did, 705 + collection, 706 + limit, 707 + cursor, 708 + reverse: false, 709 + }; 710 + 711 + return await (rpc as unknown as { 712 + get: ( 713 + nsid: string, 714 + opts: { params: Record<string, unknown> }, 715 + ) => Promise<{ 716 + ok: boolean; 717 + data: { 718 + records: Array<{ uri: string; rkey?: string; value: T }>; 719 + cursor?: string; 720 + }; 721 + }>; 722 + }).get("com.atproto.repo.listRecords", { 723 + params, 724 + }); 725 + } 726 + 727 +
+30 -38
lib/hooks/useBlueskyProfile.ts
··· 1 - import { useEffect, useState } from "react"; 2 - import { usePdsEndpoint } from "./usePdsEndpoint"; 3 - import { createAtprotoClient } from "../utils/atproto-client"; 1 + import { useBlueskyAppview } from "./useBlueskyAppview"; 2 + import type { ProfileRecord } from "../types/bluesky"; 3 + import { extractCidFromBlob } from "../utils/blob"; 4 4 5 5 /** 6 6 * Minimal profile fields returned by the Bluesky actor profile endpoint. ··· 24 24 25 25 /** 26 26 * Fetches a Bluesky actor profile for a DID and exposes loading/error state. 27 + * 28 + * Uses a three-tier fallback strategy: 29 + * 1. Try Bluesky appview API (app.bsky.actor.getProfile) - CIDs are extracted from CDN URLs 30 + * 2. Fall back to Slingshot getRecord 31 + * 3. Finally query the PDS directly 32 + * 33 + * When using the appview, avatar/banner CDN URLs (e.g., https://cdn.bsky.app/img/avatar/plain/did:plc:xxx/bafkreixxx@jpeg) 34 + * are automatically parsed to extract CIDs and convert them to standard Blob format for compatibility. 27 35 * 28 36 * @param did - Actor DID whose profile should be retrieved. 29 37 * @returns {{ data: BlueskyProfileData | undefined; loading: boolean; error: Error | undefined }} Object exposing the profile payload, loading flag, and any error. 30 38 */ 31 39 export function useBlueskyProfile(did: string | undefined) { 32 - const { endpoint } = usePdsEndpoint(did); 33 - const [data, setData] = useState<BlueskyProfileData | undefined>(); 34 - const [loading, setLoading] = useState<boolean>(!!did); 35 - const [error, setError] = useState<Error | undefined>(); 40 + const { record, loading, error } = useBlueskyAppview<ProfileRecord>({ 41 + did, 42 + collection: "app.bsky.actor.profile", 43 + rkey: "self", 44 + }); 36 45 37 - useEffect(() => { 38 - let cancelled = false; 39 - async function run() { 40 - if (!did || !endpoint) return; 41 - setLoading(true); 42 - try { 43 - const { rpc } = await createAtprotoClient({ 44 - service: endpoint, 45 - }); 46 - const client = rpc as unknown as { 47 - get: ( 48 - nsid: string, 49 - options: { params: { actor: string } }, 50 - ) => Promise<{ ok: boolean; data: unknown }>; 51 - }; 52 - const res = await client.get("app.bsky.actor.getProfile", { 53 - params: { actor: did }, 54 - }); 55 - if (!res.ok) throw new Error("Profile request failed"); 56 - if (!cancelled) setData(res.data as BlueskyProfileData); 57 - } catch (e) { 58 - if (!cancelled) setError(e as Error); 59 - } finally { 60 - if (!cancelled) setLoading(false); 61 - } 46 + // Convert ProfileRecord to BlueskyProfileData 47 + // Note: avatar and banner are Blob objects in the record (from all sources) 48 + // The appview response is converted to ProfileRecord format by extracting CIDs from CDN URLs 49 + const data: BlueskyProfileData | undefined = record 50 + ? { 51 + did: did || "", 52 + handle: "", 53 + displayName: record.displayName, 54 + description: record.description, 55 + avatar: extractCidFromBlob(record.avatar), 56 + banner: extractCidFromBlob(record.banner), 57 + createdAt: record.createdAt, 62 58 } 63 - run(); 64 - return () => { 65 - cancelled = true; 66 - }; 67 - }, [did, endpoint]); 59 + : undefined; 68 60 69 61 return { data, loading, error }; 70 - } 62 + }
-66
lib/hooks/useColorScheme.ts
··· 1 - import { useEffect, useState } from "react"; 2 - 3 - /** 4 - * Possible user-facing color scheme preferences. 5 - */ 6 - export type ColorSchemePreference = "light" | "dark" | "system"; 7 - 8 - const MEDIA_QUERY = "(prefers-color-scheme: dark)"; 9 - 10 - /** 11 - * Resolves a persisted preference into an explicit light/dark value. 12 - * 13 - * @param pref - Stored preference value (`light`, `dark`, or `system`). 14 - * @returns Explicit light/dark scheme suitable for rendering. 15 - */ 16 - function resolveScheme(pref: ColorSchemePreference): "light" | "dark" { 17 - if (pref === "light" || pref === "dark") return pref; 18 - if ( 19 - typeof window === "undefined" || 20 - typeof window.matchMedia !== "function" 21 - ) { 22 - return "light"; 23 - } 24 - return window.matchMedia(MEDIA_QUERY).matches ? "dark" : "light"; 25 - } 26 - 27 - /** 28 - * React hook that returns the effective light/dark scheme, respecting system preferences. 29 - * 30 - * @param preference - User preference; defaults to following the OS setting. 31 - * @returns {'light' | 'dark'} Explicit scheme that should be used for rendering. 32 - */ 33 - export function useColorScheme( 34 - preference: ColorSchemePreference = "system", 35 - ): "light" | "dark" { 36 - const [scheme, setScheme] = useState<"light" | "dark">(() => 37 - resolveScheme(preference), 38 - ); 39 - 40 - useEffect(() => { 41 - if (preference === "light" || preference === "dark") { 42 - setScheme(preference); 43 - return; 44 - } 45 - if ( 46 - typeof window === "undefined" || 47 - typeof window.matchMedia !== "function" 48 - ) { 49 - setScheme("light"); 50 - return; 51 - } 52 - const media = window.matchMedia(MEDIA_QUERY); 53 - const update = (event: MediaQueryListEvent | MediaQueryList) => { 54 - setScheme(event.matches ? "dark" : "light"); 55 - }; 56 - update(media); 57 - if (typeof media.addEventListener === "function") { 58 - media.addEventListener("change", update); 59 - return () => media.removeEventListener("change", update); 60 - } 61 - media.addListener(update); 62 - return () => media.removeListener(update); 63 - }, [preference]); 64 - 65 - return scheme; 66 - }
+5 -1
lib/hooks/useDidResolution.ts
··· 93 93 } 94 94 } catch (e) { 95 95 if (!cancelled) { 96 - setError(e as Error); 96 + const newError = e as Error; 97 + // Only update error if message changed (stabilize reference) 98 + setError(prevError => 99 + prevError?.message === newError.message ? prevError : newError 100 + ); 97 101 } 98 102 } finally { 99 103 if (!cancelled) setLoading(false);
+61 -33
lib/hooks/useLatestRecord.ts
··· 1 1 import { useEffect, useState } from "react"; 2 2 import { useDidResolution } from "./useDidResolution"; 3 3 import { usePdsEndpoint } from "./usePdsEndpoint"; 4 - import { createAtprotoClient } from "../utils/atproto-client"; 4 + import { callListRecords } from "./useBlueskyAppview"; 5 5 6 6 /** 7 7 * Shape of the state returned by {@link useLatestRecord}. ··· 20 20 } 21 21 22 22 /** 23 - * Fetches the most recent record from a collection using `listRecords(limit=1)`. 23 + * Fetches the most recent record from a collection using `listRecords(limit=3)`. 24 + * 25 + * Note: Slingshot does not support listRecords, so this always queries the actor's PDS directly. 26 + * 27 + * Records with invalid timestamps (before 2023, when ATProto was created) are automatically 28 + * skipped, and additional records are fetched to find a valid one. 24 29 * 25 30 * @param handleOrDid - Handle or DID that owns the collection. 26 31 * @param collection - NSID of the collection to query. 32 + * @param refreshKey - Optional key that when changed, triggers a refetch. Use for auto-refresh scenarios. 27 33 * @returns {LatestRecordState<T>} Object reporting the latest record value, derived rkey, loading status, emptiness, and any error. 28 34 */ 29 35 export function useLatestRecord<T = unknown>( 30 36 handleOrDid: string | undefined, 31 37 collection: string, 38 + refreshKey?: number, 32 39 ): LatestRecordState<T> { 33 40 const { 34 41 did, ··· 91 98 92 99 (async () => { 93 100 try { 94 - const { rpc } = await createAtprotoClient({ 95 - service: endpoint, 96 - }); 97 - const res = await ( 98 - rpc as unknown as { 99 - get: ( 100 - nsid: string, 101 - opts: { 102 - params: Record< 103 - string, 104 - string | number | boolean 105 - >; 106 - }, 107 - ) => Promise<{ 108 - ok: boolean; 109 - data: { 110 - records: Array<{ 111 - uri: string; 112 - rkey?: string; 113 - value: T; 114 - }>; 115 - }; 116 - }>; 117 - } 118 - ).get("com.atproto.repo.listRecords", { 119 - params: { repo: did, collection, limit: 1, reverse: false }, 120 - }); 121 - if (!res.ok) throw new Error("Failed to list records"); 101 + // Slingshot doesn't support listRecords, so we query PDS directly 102 + const res = await callListRecords<T>( 103 + endpoint, 104 + did, 105 + collection, 106 + 3, // Fetch 3 in case some have invalid timestamps 107 + ); 108 + 109 + if (!res.ok) { 110 + throw new Error("Failed to list records from PDS"); 111 + } 112 + 122 113 const list = res.data.records; 123 114 if (list.length === 0) { 124 115 assign({ ··· 129 120 }); 130 121 return; 131 122 } 132 - const first = list[0]; 133 - const derivedRkey = first.rkey ?? extractRkey(first.uri); 123 + 124 + // Find the first valid record (skip records before 2023) 125 + const validRecord = list.find((item) => isValidTimestamp(item.value)); 126 + 127 + if (!validRecord) { 128 + console.warn("No valid records found (all had timestamps before 2023)"); 129 + assign({ 130 + loading: false, 131 + empty: true, 132 + record: undefined, 133 + rkey: undefined, 134 + }); 135 + return; 136 + } 137 + 138 + const derivedRkey = validRecord.rkey ?? extractRkey(validRecord.uri); 134 139 assign({ 135 - record: first.value, 140 + record: validRecord.value, 136 141 rkey: derivedRkey, 137 142 loading: false, 138 143 empty: false, ··· 154 159 resolvingEndpoint, 155 160 didError, 156 161 endpointError, 162 + refreshKey, 157 163 ]); 158 164 159 165 return state; ··· 164 170 const parts = uri.split("/"); 165 171 return parts[parts.length - 1]; 166 172 } 173 + 174 + /** 175 + * Validates that a record has a reasonable timestamp (not before 2023). 176 + * ATProto was created in 2023, so any timestamp before that is invalid. 177 + */ 178 + function isValidTimestamp(record: unknown): boolean { 179 + if (typeof record !== "object" || record === null) return true; 180 + 181 + const recordObj = record as { createdAt?: string; indexedAt?: string }; 182 + const timestamp = recordObj.createdAt || recordObj.indexedAt; 183 + 184 + if (!timestamp || typeof timestamp !== "string") return true; // No timestamp to validate 185 + 186 + try { 187 + const date = new Date(timestamp); 188 + // ATProto was created in 2023, reject anything before that 189 + return date.getFullYear() >= 2023; 190 + } catch { 191 + // If we can't parse the date, consider it valid to avoid false negatives 192 + return true; 193 + } 194 + }
+77 -83
lib/hooks/usePaginatedRecords.ts
··· 1 1 import { useCallback, useEffect, useMemo, useRef, useState } from "react"; 2 2 import { useDidResolution } from "./useDidResolution"; 3 3 import { usePdsEndpoint } from "./usePdsEndpoint"; 4 - import { createAtprotoClient } from "../utils/atproto-client"; 4 + import { callAppviewRpc, callListRecords } from "./useBlueskyAppview"; 5 + import { useAtProto } from "../providers/AtProtoProvider"; 5 6 6 7 /** 7 8 * Record envelope returned by paginated AT Protocol queries. ··· 70 71 pagesCount: number; 71 72 } 72 73 73 - const DEFAULT_APPVIEW_SERVICE = "https://public.api.bsky.app"; 74 + 74 75 75 76 export type AuthorFeedFilter = 76 77 | "posts_with_replies" ··· 114 115 authorFeedService, 115 116 authorFeedActor, 116 117 }: UsePaginatedRecordsOptions): UsePaginatedRecordsResult<T> { 118 + const { blueskyAppviewService } = useAtProto(); 117 119 const { 118 120 did, 119 121 handle, ··· 188 190 !!actorIdentifier; 189 191 if (shouldUseAuthorFeed) { 190 192 try { 191 - const { rpc } = await createAtprotoClient({ 192 - service: 193 - authorFeedService ?? DEFAULT_APPVIEW_SERVICE, 194 - }); 195 - const res = await ( 196 - rpc as unknown as { 197 - get: ( 198 - nsid: string, 199 - opts: { 200 - params: Record< 201 - string, 202 - | string 203 - | number 204 - | boolean 205 - | undefined 206 - >; 207 - }, 208 - ) => Promise<{ 209 - ok: boolean; 210 - data: { 211 - feed?: Array<{ 212 - post?: { 213 - uri?: string; 214 - record?: T; 215 - reply?: { 216 - parent?: { 217 - uri?: string; 218 - author?: { 219 - handle?: string; 220 - did?: string; 221 - }; 222 - }; 223 - }; 193 + interface AuthorFeedResponse { 194 + feed?: Array<{ 195 + post?: { 196 + uri?: string; 197 + record?: T; 198 + reply?: { 199 + parent?: { 200 + uri?: string; 201 + author?: { 202 + handle?: string; 203 + did?: string; 224 204 }; 225 - reason?: AuthorFeedReason; 226 - }>; 227 - cursor?: string; 205 + }; 228 206 }; 229 - }>; 230 - } 231 - ).get("app.bsky.feed.getAuthorFeed", { 232 - params: { 207 + }; 208 + reason?: AuthorFeedReason; 209 + }>; 210 + cursor?: string; 211 + } 212 + 213 + const res = await callAppviewRpc<AuthorFeedResponse>( 214 + authorFeedService ?? blueskyAppviewService, 215 + "app.bsky.feed.getAuthorFeed", 216 + { 233 217 actor: actorIdentifier, 234 218 limit, 235 219 cursor, 236 220 filter: authorFeedFilter, 237 221 includePins: authorFeedIncludePins, 238 222 }, 239 - }); 223 + ); 240 224 if (!res.ok) 241 225 throw new Error("Failed to fetch author feed"); 242 226 const { feed, cursor: feedCursor } = res.data; ··· 249 233 !post.record 250 234 ) 251 235 return acc; 236 + // Skip records with invalid timestamps (before 2023) 237 + if (!isValidTimestamp(post.record)) { 238 + console.warn("Skipping record with invalid timestamp:", post.uri); 239 + return acc; 240 + } 252 241 acc.push({ 253 242 uri: post.uri, 254 243 rkey: extractRkey(post.uri), ··· 268 257 } 269 258 270 259 if (!mapped) { 271 - const { rpc } = await createAtprotoClient({ 272 - service: endpoint, 273 - }); 274 - const res = await ( 275 - rpc as unknown as { 276 - get: ( 277 - nsid: string, 278 - opts: { 279 - params: Record< 280 - string, 281 - string | number | boolean | undefined 282 - >; 283 - }, 284 - ) => Promise<{ 285 - ok: boolean; 286 - data: { 287 - records: Array<{ 288 - uri: string; 289 - rkey?: string; 290 - value: T; 291 - }>; 292 - cursor?: string; 293 - }; 294 - }>; 295 - } 296 - ).get("com.atproto.repo.listRecords", { 297 - params: { 298 - repo: did, 299 - collection, 300 - limit, 301 - cursor, 302 - reverse: false, 303 - }, 304 - }); 305 - if (!res.ok) throw new Error("Failed to list records"); 260 + // Slingshot doesn't support listRecords, query PDS directly 261 + const res = await callListRecords<T>( 262 + endpoint, 263 + did, 264 + collection, 265 + limit, 266 + cursor, 267 + ); 268 + 269 + if (!res.ok) throw new Error("Failed to list records from PDS"); 306 270 const { records, cursor: repoCursor } = res.data; 307 - mapped = records.map((item) => ({ 308 - uri: item.uri, 309 - rkey: item.rkey ?? extractRkey(item.uri), 310 - value: item.value, 311 - })); 271 + mapped = records 272 + .filter((item) => { 273 + if (!isValidTimestamp(item.value)) { 274 + console.warn("Skipping record with invalid timestamp:", item.uri); 275 + return false; 276 + } 277 + return true; 278 + }) 279 + .map((item) => ({ 280 + uri: item.uri, 281 + rkey: item.rkey ?? extractRkey(item.uri), 282 + value: item.value, 283 + })); 312 284 nextCursor = repoCursor; 313 285 } 314 286 ··· 475 447 const parts = uri.split("/"); 476 448 return parts[parts.length - 1]; 477 449 } 450 + 451 + /** 452 + * Validates that a record has a reasonable timestamp (not before 2023). 453 + * ATProto was created in 2023, so any timestamp before that is invalid. 454 + */ 455 + function isValidTimestamp(record: unknown): boolean { 456 + if (typeof record !== "object" || record === null) return true; 457 + 458 + const recordObj = record as { createdAt?: string; indexedAt?: string }; 459 + const timestamp = recordObj.createdAt || recordObj.indexedAt; 460 + 461 + if (!timestamp || typeof timestamp !== "string") return true; // No timestamp to validate 462 + 463 + try { 464 + const date = new Date(timestamp); 465 + // ATProto was created in 2023, reject anything before that 466 + return date.getFullYear() >= 2023; 467 + } catch { 468 + // If we can't parse the date, consider it valid to avoid false negatives 469 + return true; 470 + } 471 + }
+5 -1
lib/hooks/usePdsEndpoint.ts
··· 45 45 }) 46 46 .catch((e) => { 47 47 if (cancelled) return; 48 - setError(e as Error); 48 + const newError = e as Error; 49 + // Only update error if message changed (stabilize reference) 50 + setError(prevError => 51 + prevError?.message === newError.message ? prevError : newError 52 + ); 49 53 }) 50 54 .finally(() => { 51 55 if (!cancelled) setLoading(false);
+104
lib/hooks/useRepoLanguages.ts
··· 1 + import { useState, useEffect } from "react"; 2 + import type { RepoLanguagesResponse } from "../types/tangled"; 3 + 4 + export interface UseRepoLanguagesOptions { 5 + /** The knot server URL (e.g., "knot.gaze.systems") */ 6 + knot?: string; 7 + /** DID of the repository owner */ 8 + did?: string; 9 + /** Repository name */ 10 + repoName?: string; 11 + /** Branch to query (defaults to trying "main", then "master") */ 12 + branch?: string; 13 + /** Whether to enable the query */ 14 + enabled?: boolean; 15 + } 16 + 17 + export interface UseRepoLanguagesResult { 18 + /** Language data from the knot server */ 19 + data?: RepoLanguagesResponse; 20 + /** Loading state */ 21 + loading: boolean; 22 + /** Error state */ 23 + error?: Error; 24 + } 25 + 26 + /** 27 + * Hook to fetch repository language information from a Tangled knot server. 28 + * If no branch supplied, tries "main" first, then falls back to "master". 29 + */ 30 + export function useRepoLanguages({ 31 + knot, 32 + did, 33 + repoName, 34 + branch, 35 + enabled = true, 36 + }: UseRepoLanguagesOptions): UseRepoLanguagesResult { 37 + const [data, setData] = useState<RepoLanguagesResponse | undefined>(); 38 + const [loading, setLoading] = useState(false); 39 + const [error, setError] = useState<Error | undefined>(); 40 + 41 + useEffect(() => { 42 + if (!enabled || !knot || !did || !repoName) { 43 + return; 44 + } 45 + 46 + let cancelled = false; 47 + 48 + const fetchLanguages = async (ref: string): Promise<boolean> => { 49 + try { 50 + const url = `https://${knot}/xrpc/sh.tangled.repo.languages?repo=${encodeURIComponent(`${did}/${repoName}`)}&ref=${encodeURIComponent(ref)}`; 51 + const response = await fetch(url); 52 + 53 + if (!response.ok) { 54 + return false; 55 + } 56 + 57 + const result = await response.json(); 58 + if (!cancelled) { 59 + setData(result); 60 + setError(undefined); 61 + } 62 + return true; 63 + } catch (err) { 64 + return false; 65 + } 66 + }; 67 + 68 + const fetchWithFallback = async () => { 69 + setLoading(true); 70 + setError(undefined); 71 + 72 + if (branch) { 73 + const success = await fetchLanguages(branch); 74 + if (!cancelled) { 75 + if (!success) { 76 + setError(new Error(`Failed to fetch languages for branch: ${branch}`)); 77 + } 78 + setLoading(false); 79 + } 80 + } else { 81 + // Try "main" first, then "master" 82 + let success = await fetchLanguages("main"); 83 + if (!success && !cancelled) { 84 + success = await fetchLanguages("master"); 85 + } 86 + 87 + if (!cancelled) { 88 + if (!success) { 89 + setError(new Error("Failed to fetch languages for main or master branch")); 90 + } 91 + setLoading(false); 92 + } 93 + } 94 + }; 95 + 96 + fetchWithFallback(); 97 + 98 + return () => { 99 + cancelled = true; 100 + }; 101 + }, [knot, did, repoName, branch, enabled]); 102 + 103 + return { data, loading, error }; 104 + }
+18 -2
lib/index.ts
··· 1 1 // Master exporter for the AT React component library. 2 2 3 + import "./styles.css"; 4 + 3 5 // Providers & core primitives 4 6 export * from "./providers/AtProtoProvider"; 5 7 export * from "./core/AtProtoRecord"; ··· 10 12 export * from "./components/BlueskyPostList"; 11 13 export * from "./components/BlueskyProfile"; 12 14 export * from "./components/BlueskyQuotePost"; 13 - export * from "./components/ColorSchemeToggle"; 15 + export * from "./components/GrainGallery"; 14 16 export * from "./components/LeafletDocument"; 17 + export * from "./components/TangledRepo"; 15 18 export * from "./components/TangledString"; 19 + export * from "./components/CurrentlyPlaying"; 20 + export * from "./components/LastPlayed"; 21 + export * from "./components/SongHistoryList"; 16 22 17 23 // Hooks 18 24 export * from "./hooks/useAtProtoRecord"; 25 + export * from "./hooks/useBacklinks"; 19 26 export * from "./hooks/useBlob"; 27 + export * from "./hooks/useBlueskyAppview"; 20 28 export * from "./hooks/useBlueskyProfile"; 21 - export * from "./hooks/useColorScheme"; 22 29 export * from "./hooks/useDidResolution"; 23 30 export * from "./hooks/useLatestRecord"; 24 31 export * from "./hooks/usePaginatedRecords"; 25 32 export * from "./hooks/usePdsEndpoint"; 33 + export * from "./hooks/useRepoLanguages"; 26 34 27 35 // Renderers 28 36 export * from "./renderers/BlueskyPostRenderer"; 29 37 export * from "./renderers/BlueskyProfileRenderer"; 38 + export * from "./renderers/GrainGalleryRenderer"; 30 39 export * from "./renderers/LeafletDocumentRenderer"; 40 + export * from "./renderers/TangledRepoRenderer"; 31 41 export * from "./renderers/TangledStringRenderer"; 42 + export * from "./renderers/CurrentlyPlayingRenderer"; 32 43 33 44 // Types 34 45 export * from "./types/bluesky"; 46 + export * from "./types/grain"; 35 47 export * from "./types/leaflet"; 48 + export * from "./types/tangled"; 49 + export * from "./types/teal"; 50 + export * from "./types/theme"; 36 51 37 52 // Utilities 38 53 export * from "./utils/at-uri"; 39 54 export * from "./utils/atproto-client"; 55 + export * from "./utils/blob"; 40 56 export * from "./utils/profile";
+174 -7
lib/providers/AtProtoProvider.tsx
··· 1 1 /* eslint-disable react-refresh/only-export-components */ 2 - import React, { createContext, useContext, useMemo, useRef } from "react"; 3 - import { ServiceResolver, normalizeBaseUrl } from "../utils/atproto-client"; 4 - import { BlobCache, DidCache } from "../utils/cache"; 2 + import React, { 3 + createContext, 4 + useContext, 5 + useMemo, 6 + useRef, 7 + } from "react"; 8 + import { ServiceResolver, normalizeBaseUrl, DEFAULT_CONFIG } from "../utils/atproto-client"; 9 + import { BlobCache, DidCache, RecordCache } from "../utils/cache"; 5 10 11 + /** 12 + * Props for the AT Protocol context provider. 13 + */ 6 14 export interface AtProtoProviderProps { 15 + /** Child components that will have access to the AT Protocol context. */ 7 16 children: React.ReactNode; 17 + /** Optional custom PLC directory URL. Defaults to https://plc.directory */ 8 18 plcDirectory?: string; 19 + /** Optional custom identity service URL. Defaults to https://public.api.bsky.app */ 20 + identityService?: string; 21 + /** Optional custom Slingshot service URL. Defaults to https://slingshot.microcosm.blue */ 22 + slingshotBaseUrl?: string; 23 + /** Optional custom Bluesky appview service URL. Defaults to https://public.api.bsky.app */ 24 + blueskyAppviewService?: string; 25 + /** Optional custom Bluesky app base URL for links. Defaults to https://bsky.app */ 26 + blueskyAppBaseUrl?: string; 27 + /** Optional custom Tangled base URL for links. Defaults to https://tangled.org */ 28 + tangledBaseUrl?: string; 29 + /** Optional custom Constellation API URL for backlinks. Defaults to https://constellation.microcosm.blue */ 30 + constellationBaseUrl?: string; 9 31 } 10 32 33 + /** 34 + * Internal context value shared across all AT Protocol hooks. 35 + */ 11 36 interface AtProtoContextValue { 37 + /** Service resolver for DID resolution and PDS endpoint discovery. */ 12 38 resolver: ServiceResolver; 39 + /** Normalized PLC directory base URL. */ 13 40 plcDirectory: string; 41 + /** Normalized Bluesky appview service URL. */ 42 + blueskyAppviewService: string; 43 + /** Normalized Bluesky app base URL for links. */ 44 + blueskyAppBaseUrl: string; 45 + /** Normalized Tangled base URL for links. */ 46 + tangledBaseUrl: string; 47 + /** Normalized Constellation API base URL for backlinks. */ 48 + constellationBaseUrl: string; 49 + /** Cache for DID documents and handle mappings. */ 14 50 didCache: DidCache; 51 + /** Cache for fetched blob data. */ 15 52 blobCache: BlobCache; 53 + /** Cache for fetched AT Protocol records. */ 54 + recordCache: RecordCache; 16 55 } 17 56 18 57 const AtProtoContext = createContext<AtProtoContextValue | undefined>( 19 58 undefined, 20 59 ); 21 60 61 + /** 62 + * Context provider that supplies AT Protocol infrastructure to all child components. 63 + * 64 + * This provider initializes and shares: 65 + * - Service resolver for DID and PDS endpoint resolution 66 + * - DID cache for identity resolution 67 + * - Blob cache for efficient media handling 68 + * 69 + * All AT Protocol components (`BlueskyPost`, `LeafletDocument`, etc.) must be wrapped 70 + * in this provider to function correctly. 71 + * 72 + * @example 73 + * ```tsx 74 + * import { AtProtoProvider, BlueskyPost } from 'atproto-ui'; 75 + * 76 + * function App() { 77 + * return ( 78 + * <AtProtoProvider> 79 + * <BlueskyPost did="did:plc:example" rkey="3k2aexample" /> 80 + * </AtProtoProvider> 81 + * ); 82 + * } 83 + * ``` 84 + * 85 + * @example 86 + * ```tsx 87 + * // Using a custom PLC directory 88 + * <AtProtoProvider plcDirectory="https://custom-plc.example.com"> 89 + * <YourComponents /> 90 + * </AtProtoProvider> 91 + * ``` 92 + * 93 + * @param children - Child components to render within the provider. 94 + * @param plcDirectory - Optional PLC directory override (defaults to https://plc.directory). 95 + * @returns Provider component that enables AT Protocol functionality. 96 + */ 22 97 export function AtProtoProvider({ 23 98 children, 24 99 plcDirectory, 100 + identityService, 101 + slingshotBaseUrl, 102 + blueskyAppviewService, 103 + blueskyAppBaseUrl, 104 + tangledBaseUrl, 105 + constellationBaseUrl, 25 106 }: AtProtoProviderProps) { 26 107 const normalizedPlc = useMemo( 27 108 () => 28 109 normalizeBaseUrl( 29 110 plcDirectory && plcDirectory.trim() 30 111 ? plcDirectory 31 - : "https://plc.directory", 112 + : DEFAULT_CONFIG.plcDirectory, 32 113 ), 33 114 [plcDirectory], 34 115 ); 116 + const normalizedIdentity = useMemo( 117 + () => 118 + normalizeBaseUrl( 119 + identityService && identityService.trim() 120 + ? identityService 121 + : DEFAULT_CONFIG.identityService, 122 + ), 123 + [identityService], 124 + ); 125 + const normalizedSlingshot = useMemo( 126 + () => 127 + normalizeBaseUrl( 128 + slingshotBaseUrl && slingshotBaseUrl.trim() 129 + ? slingshotBaseUrl 130 + : DEFAULT_CONFIG.slingshotBaseUrl, 131 + ), 132 + [slingshotBaseUrl], 133 + ); 134 + const normalizedAppview = useMemo( 135 + () => 136 + normalizeBaseUrl( 137 + blueskyAppviewService && blueskyAppviewService.trim() 138 + ? blueskyAppviewService 139 + : DEFAULT_CONFIG.blueskyAppviewService, 140 + ), 141 + [blueskyAppviewService], 142 + ); 143 + const normalizedBlueskyApp = useMemo( 144 + () => 145 + normalizeBaseUrl( 146 + blueskyAppBaseUrl && blueskyAppBaseUrl.trim() 147 + ? blueskyAppBaseUrl 148 + : DEFAULT_CONFIG.blueskyAppBaseUrl, 149 + ), 150 + [blueskyAppBaseUrl], 151 + ); 152 + const normalizedTangled = useMemo( 153 + () => 154 + normalizeBaseUrl( 155 + tangledBaseUrl && tangledBaseUrl.trim() 156 + ? tangledBaseUrl 157 + : DEFAULT_CONFIG.tangledBaseUrl, 158 + ), 159 + [tangledBaseUrl], 160 + ); 161 + const normalizedConstellation = useMemo( 162 + () => 163 + normalizeBaseUrl( 164 + constellationBaseUrl && constellationBaseUrl.trim() 165 + ? constellationBaseUrl 166 + : DEFAULT_CONFIG.constellationBaseUrl, 167 + ), 168 + [constellationBaseUrl], 169 + ); 35 170 const resolver = useMemo( 36 - () => new ServiceResolver({ plcDirectory: normalizedPlc }), 37 - [normalizedPlc], 171 + () => new ServiceResolver({ 172 + plcDirectory: normalizedPlc, 173 + identityService: normalizedIdentity, 174 + slingshotBaseUrl: normalizedSlingshot, 175 + }), 176 + [normalizedPlc, normalizedIdentity, normalizedSlingshot], 38 177 ); 39 178 const cachesRef = useRef<{ 40 179 didCache: DidCache; 41 180 blobCache: BlobCache; 181 + recordCache: RecordCache; 42 182 } | null>(null); 43 183 if (!cachesRef.current) { 44 184 cachesRef.current = { 45 185 didCache: new DidCache(), 46 186 blobCache: new BlobCache(), 187 + recordCache: new RecordCache(), 47 188 }; 48 189 } 190 + 49 191 const value = useMemo<AtProtoContextValue>( 50 192 () => ({ 51 193 resolver, 52 194 plcDirectory: normalizedPlc, 195 + blueskyAppviewService: normalizedAppview, 196 + blueskyAppBaseUrl: normalizedBlueskyApp, 197 + tangledBaseUrl: normalizedTangled, 198 + constellationBaseUrl: normalizedConstellation, 53 199 didCache: cachesRef.current!.didCache, 54 200 blobCache: cachesRef.current!.blobCache, 201 + recordCache: cachesRef.current!.recordCache, 55 202 }), 56 - [resolver, normalizedPlc], 203 + [resolver, normalizedPlc, normalizedAppview, normalizedBlueskyApp, normalizedTangled, normalizedConstellation], 57 204 ); 205 + 58 206 return ( 59 207 <AtProtoContext.Provider value={value}> 60 208 {children} ··· 62 210 ); 63 211 } 64 212 213 + /** 214 + * Hook that accesses the AT Protocol context provided by `AtProtoProvider`. 215 + * 216 + * This hook exposes the service resolver, DID cache, blob cache, and record cache 217 + * for building custom AT Protocol functionality. 218 + * 219 + * @throws {Error} When called outside of an `AtProtoProvider`. 220 + * @returns {AtProtoContextValue} Object containing resolver, caches, and PLC directory URL. 221 + * 222 + * @example 223 + * ```tsx 224 + * import { useAtProto } from 'atproto-ui'; 225 + * 226 + * function MyCustomComponent() { 227 + * const { resolver, didCache, blobCache, recordCache } = useAtProto(); 228 + * // Use the resolver and caches for custom AT Protocol operations 229 + * } 230 + * ``` 231 + */ 65 232 export function useAtProto() { 66 233 const ctx = useContext(AtProtoContext); 67 234 if (!ctx) throw new Error("useAtProto must be used within AtProtoProvider");
+322 -269
lib/renderers/BlueskyPostRenderer.tsx
··· 1 1 import React from "react"; 2 2 import type { FeedPostRecord } from "../types/bluesky"; 3 3 import { 4 - useColorScheme, 5 - type ColorSchemePreference, 6 - } from "../hooks/useColorScheme"; 7 - import { 8 4 parseAtUri, 9 5 toBlueskyPostUrl, 10 6 formatDidForLabel, ··· 13 9 import { useDidResolution } from "../hooks/useDidResolution"; 14 10 import { useBlob } from "../hooks/useBlob"; 15 11 import { BlueskyIcon } from "../components/BlueskyIcon"; 12 + import { isBlobWithCdn, extractCidFromBlob } from "../utils/blob"; 13 + import { RichText } from "../components/RichText"; 16 14 17 15 export interface BlueskyPostRendererProps { 18 16 record: FeedPostRecord; 19 17 loading: boolean; 20 18 error?: Error; 21 - // Optionally pass in actor display info if pre-fetched 22 19 authorHandle?: string; 23 20 authorDisplayName?: string; 24 21 avatarUrl?: string; 25 - colorScheme?: ColorSchemePreference; 26 22 authorDid?: string; 27 23 embed?: React.ReactNode; 28 24 iconPlacement?: "cardBottomRight" | "timestamp" | "linkInline"; 29 25 showIcon?: boolean; 30 26 atUri?: string; 27 + isInThread?: boolean; 28 + threadDepth?: number; 29 + isQuotePost?: boolean; 30 + showThreadBorder?: boolean; 31 31 } 32 32 33 33 export const BlueskyPostRenderer: React.FC<BlueskyPostRendererProps> = ({ ··· 37 37 authorDisplayName, 38 38 authorHandle, 39 39 avatarUrl, 40 - colorScheme = "system", 41 40 authorDid, 42 41 embed, 43 42 iconPlacement = "timestamp", 44 43 showIcon = true, 45 44 atUri, 45 + isInThread = false, 46 + threadDepth = 0, 47 + isQuotePost = false, 48 + showThreadBorder = false 46 49 }) => { 47 - const scheme = useColorScheme(colorScheme); 50 + void threadDepth; 51 + 48 52 const replyParentUri = record.reply?.parent?.uri; 49 53 const replyTarget = replyParentUri ? parseAtUri(replyParentUri) : undefined; 50 54 const { handle: parentHandle, loading: parentHandleLoading } = 51 55 useDidResolution(replyTarget?.did); 52 56 53 - if (error) 57 + if (error) { 54 58 return ( 55 - <div style={{ padding: 8, color: "crimson" }}> 59 + <div role="alert" style={{ padding: 8, color: "crimson" }}> 56 60 Failed to load post. 57 61 </div> 58 62 ); 59 - if (loading && !record) return <div style={{ padding: 8 }}>Loadingโ€ฆ</div>; 60 - 61 - const palette = scheme === "dark" ? themeStyles.dark : themeStyles.light; 63 + } 64 + if (loading && !record) return <div role="status" aria-live="polite" style={{ padding: 8 }}>Loadingโ€ฆ</div>; 62 65 63 66 const text = record.text; 64 67 const createdDate = new Date(record.createdAt); ··· 73 76 : undefined; 74 77 75 78 const makeIcon = () => (showIcon ? <BlueskyIcon size={16} /> : null); 76 - const resolvedEmbed = embed ?? createAutoEmbed(record, authorDid, scheme); 79 + const resolvedEmbed = embed ?? createAutoEmbed(record, authorDid); 77 80 const parsedSelf = atUri ? parseAtUri(atUri) : undefined; 78 81 const postUrl = parsedSelf ? toBlueskyPostUrl(parsedSelf) : undefined; 79 82 const cardPadding = 80 83 typeof baseStyles.card.padding === "number" 81 84 ? baseStyles.card.padding 82 85 : 12; 86 + 83 87 const cardStyle: React.CSSProperties = { 84 88 ...baseStyles.card, 85 - ...palette.card, 86 - ...(iconPlacement === "cardBottomRight" && showIcon 89 + border: (isInThread && !isQuotePost && !showThreadBorder) ? "none" : `1px solid var(--atproto-color-border)`, 90 + background: `var(--atproto-color-bg)`, 91 + color: `var(--atproto-color-text)`, 92 + borderRadius: (isInThread && !isQuotePost && !showThreadBorder) ? "0" : "12px", 93 + ...(iconPlacement === "cardBottomRight" && showIcon && !isInThread 87 94 ? { paddingBottom: cardPadding + 16 } 88 95 : {}), 89 96 }; 90 97 91 98 return ( 92 99 <article style={cardStyle} aria-busy={loading}> 93 - <header style={baseStyles.header}> 94 - {avatarUrl ? ( 95 - <img 96 - src={avatarUrl} 97 - alt="avatar" 98 - style={baseStyles.avatarImg} 99 - /> 100 - ) : ( 101 - <div 102 - style={{ 103 - ...baseStyles.avatarPlaceholder, 104 - ...palette.avatarPlaceholder, 105 - }} 106 - aria-hidden 107 - /> 108 - )} 109 - <div style={{ display: "flex", flexDirection: "column" }}> 110 - <strong style={{ fontSize: 14 }}>{primaryName}</strong> 111 - {authorDisplayName && authorHandle && ( 112 - <span 113 - style={{ ...baseStyles.handle, ...palette.handle }} 114 - > 115 - @{authorHandle} 116 - </span> 117 - )} 118 - </div> 119 - {iconPlacement === "timestamp" && showIcon && ( 120 - <div style={baseStyles.headerIcon}>{makeIcon()}</div> 121 - )} 122 - </header> 123 - {replyHref && replyLabel && ( 124 - <div style={{ ...baseStyles.replyLine, ...palette.replyLine }}> 125 - Replying to{" "} 100 + {isInThread ? ( 101 + <ThreadLayout 102 + avatarUrl={avatarUrl} 103 + primaryName={primaryName} 104 + authorDisplayName={authorDisplayName} 105 + authorHandle={authorHandle} 106 + iconPlacement={iconPlacement} 107 + showIcon={showIcon} 108 + makeIcon={makeIcon} 109 + replyHref={replyHref} 110 + replyLabel={replyLabel} 111 + text={text} 112 + record={record} 113 + created={created} 114 + postUrl={postUrl} 115 + resolvedEmbed={resolvedEmbed} 116 + /> 117 + ) : ( 118 + <DefaultLayout 119 + avatarUrl={avatarUrl} 120 + primaryName={primaryName} 121 + authorDisplayName={authorDisplayName} 122 + authorHandle={authorHandle} 123 + iconPlacement={iconPlacement} 124 + showIcon={showIcon} 125 + makeIcon={makeIcon} 126 + replyHref={replyHref} 127 + replyLabel={replyLabel} 128 + text={text} 129 + record={record} 130 + created={created} 131 + postUrl={postUrl} 132 + resolvedEmbed={resolvedEmbed} 133 + /> 134 + )} 135 + </article> 136 + ); 137 + }; 138 + 139 + interface LayoutProps { 140 + avatarUrl?: string; 141 + primaryName: string; 142 + authorDisplayName?: string; 143 + authorHandle?: string; 144 + iconPlacement: "cardBottomRight" | "timestamp" | "linkInline"; 145 + showIcon: boolean; 146 + makeIcon: () => React.ReactNode; 147 + replyHref?: string; 148 + replyLabel?: string; 149 + text: string; 150 + record: FeedPostRecord; 151 + created: string; 152 + postUrl?: string; 153 + resolvedEmbed: React.ReactNode; 154 + } 155 + 156 + const AuthorInfo: React.FC<{ 157 + primaryName: string; 158 + authorDisplayName?: string; 159 + authorHandle?: string; 160 + inline?: boolean; 161 + }> = ({ primaryName, authorDisplayName, authorHandle, inline = false }) => ( 162 + <div 163 + style={{ 164 + display: "flex", 165 + flexDirection: inline ? "row" : "column", 166 + alignItems: inline ? "center" : "flex-start", 167 + gap: inline ? 8 : 0, 168 + }} 169 + > 170 + <strong style={{ fontSize: 14 }}>{authorDisplayName || primaryName}</strong> 171 + {authorHandle && ( 172 + <span 173 + style={{ 174 + ...baseStyles.handle, 175 + color: `var(--atproto-color-text-secondary)`, 176 + }} 177 + > 178 + @{authorHandle} 179 + </span> 180 + )} 181 + </div> 182 + ); 183 + 184 + const Avatar: React.FC<{ avatarUrl?: string; name?: string }> = ({ avatarUrl, name }) => 185 + avatarUrl ? ( 186 + <img src={avatarUrl} alt={`${name || 'User'}'s profile picture`} style={baseStyles.avatarImg} /> 187 + ) : ( 188 + <div style={baseStyles.avatarPlaceholder} aria-hidden="true" /> 189 + ); 190 + 191 + const ReplyInfo: React.FC<{ 192 + replyHref?: string; 193 + replyLabel?: string; 194 + marginBottom?: number; 195 + }> = ({ replyHref, replyLabel, marginBottom = 0 }) => 196 + replyHref && replyLabel ? ( 197 + <div 198 + style={{ 199 + ...baseStyles.replyLine, 200 + color: `var(--atproto-color-text-secondary)`, 201 + marginBottom, 202 + }} 203 + > 204 + Replying to{" "} 205 + <a 206 + href={replyHref} 207 + target="_blank" 208 + rel="noopener noreferrer" 209 + style={{ 210 + ...baseStyles.replyLink, 211 + color: `var(--atproto-color-link)`, 212 + }} 213 + > 214 + {replyLabel} 215 + </a> 216 + </div> 217 + ) : null; 218 + 219 + const PostContent: React.FC<{ 220 + text: string; 221 + record: FeedPostRecord; 222 + created: string; 223 + postUrl?: string; 224 + iconPlacement: "cardBottomRight" | "timestamp" | "linkInline"; 225 + showIcon: boolean; 226 + makeIcon: () => React.ReactNode; 227 + resolvedEmbed: React.ReactNode; 228 + }> = ({ 229 + text, 230 + record, 231 + created, 232 + postUrl, 233 + iconPlacement, 234 + showIcon, 235 + makeIcon, 236 + resolvedEmbed, 237 + }) => ( 238 + <div style={baseStyles.body}> 239 + <p style={{ ...baseStyles.text, color: `var(--atproto-color-text)` }}> 240 + <RichText text={text} facets={record.facets} /> 241 + </p> 242 + {resolvedEmbed && ( 243 + <div style={baseStyles.embedContainer}>{resolvedEmbed}</div> 244 + )} 245 + <div style={baseStyles.timestampRow}> 246 + <time 247 + style={{ 248 + ...baseStyles.time, 249 + color: `var(--atproto-color-text-muted)`, 250 + }} 251 + dateTime={record.createdAt} 252 + > 253 + {created} 254 + </time> 255 + {postUrl && ( 256 + <span style={baseStyles.linkWithIcon}> 126 257 <a 127 - href={replyHref} 258 + href={postUrl} 128 259 target="_blank" 129 260 rel="noopener noreferrer" 130 261 style={{ 131 - ...baseStyles.replyLink, 132 - ...palette.replyLink, 262 + ...baseStyles.postLink, 263 + color: `var(--atproto-color-link)`, 133 264 }} 134 265 > 135 - {replyLabel} 266 + View on Bluesky 136 267 </a> 137 - </div> 138 - )} 139 - <div style={baseStyles.body}> 140 - <p style={{ ...baseStyles.text, ...palette.text }}>{text}</p> 141 - {record.facets && record.facets.length > 0 && ( 142 - <div style={baseStyles.facets}> 143 - {record.facets.map((_, idx) => ( 144 - <span 145 - key={idx} 146 - style={{ 147 - ...baseStyles.facetTag, 148 - ...palette.facetTag, 149 - }} 150 - > 151 - facet 152 - </span> 153 - ))} 154 - </div> 155 - )} 156 - <div style={baseStyles.timestampRow}> 157 - <time 158 - style={{ ...baseStyles.time, ...palette.time }} 159 - dateTime={record.createdAt} 160 - > 161 - {created} 162 - </time> 163 - {postUrl && ( 164 - <span style={baseStyles.linkWithIcon}> 165 - <a 166 - href={postUrl} 167 - target="_blank" 168 - rel="noopener noreferrer" 169 - style={{ 170 - ...baseStyles.postLink, 171 - ...palette.postLink, 172 - }} 173 - > 174 - View on Bluesky 175 - </a> 176 - {iconPlacement === "linkInline" && showIcon && ( 177 - <span style={baseStyles.inlineIcon} aria-hidden> 178 - {makeIcon()} 179 - </span> 180 - )} 268 + {iconPlacement === "linkInline" && showIcon && ( 269 + <span style={baseStyles.inlineIcon} aria-hidden> 270 + {makeIcon()} 181 271 </span> 182 272 )} 183 - </div> 184 - {resolvedEmbed && ( 185 - <div 186 - style={{ 187 - ...baseStyles.embedContainer, 188 - ...palette.embedContainer, 189 - }} 190 - > 191 - {resolvedEmbed} 192 - </div> 273 + </span> 274 + )} 275 + </div> 276 + </div> 277 + ); 278 + 279 + const ThreadLayout: React.FC<LayoutProps> = (props) => ( 280 + <div style={{ display: "flex", gap: 8, alignItems: "flex-start" }}> 281 + <Avatar avatarUrl={props.avatarUrl} name={props.authorDisplayName || props.authorHandle} /> 282 + <div style={{ flex: 1, minWidth: 0 }}> 283 + <div 284 + style={{ 285 + display: "flex", 286 + alignItems: "center", 287 + gap: 8, 288 + marginBottom: 4, 289 + }} 290 + > 291 + <AuthorInfo 292 + primaryName={props.primaryName} 293 + authorDisplayName={props.authorDisplayName} 294 + authorHandle={props.authorHandle} 295 + inline 296 + /> 297 + {props.iconPlacement === "timestamp" && props.showIcon && ( 298 + <div style={{ marginLeft: "auto" }}>{props.makeIcon()}</div> 193 299 )} 194 300 </div> 195 - {iconPlacement === "cardBottomRight" && showIcon && ( 196 - <div style={baseStyles.iconCorner} aria-hidden> 197 - {makeIcon()} 301 + <ReplyInfo 302 + replyHref={props.replyHref} 303 + replyLabel={props.replyLabel} 304 + marginBottom={4} 305 + /> 306 + <PostContent {...props} /> 307 + {props.iconPlacement === "cardBottomRight" && props.showIcon && ( 308 + <div 309 + style={{ 310 + position: "relative", 311 + right: 0, 312 + bottom: 0, 313 + justifyContent: "flex-start", 314 + marginTop: 8, 315 + display: "flex", 316 + }} 317 + aria-hidden 318 + > 319 + {props.makeIcon()} 198 320 </div> 199 321 )} 200 - </article> 201 - ); 202 - }; 322 + </div> 323 + </div> 324 + ); 325 + 326 + const DefaultLayout: React.FC<LayoutProps> = (props) => ( 327 + <> 328 + <header style={baseStyles.header}> 329 + <Avatar avatarUrl={props.avatarUrl} name={props.authorDisplayName || props.authorHandle} /> 330 + <AuthorInfo 331 + primaryName={props.primaryName} 332 + authorDisplayName={props.authorDisplayName} 333 + authorHandle={props.authorHandle} 334 + /> 335 + {props.iconPlacement === "timestamp" && props.showIcon && ( 336 + <div style={baseStyles.headerIcon}>{props.makeIcon()}</div> 337 + )} 338 + </header> 339 + <ReplyInfo replyHref={props.replyHref} replyLabel={props.replyLabel} /> 340 + <PostContent {...props} /> 341 + {props.iconPlacement === "cardBottomRight" && props.showIcon && ( 342 + <div style={baseStyles.iconCorner} aria-hidden> 343 + {props.makeIcon()} 344 + </div> 345 + )} 346 + </> 347 + ); 203 348 204 349 const baseStyles: Record<string, React.CSSProperties> = { 205 350 card: { ··· 241 386 time: { 242 387 fontSize: 11, 243 388 }, 244 - timestampIcon: { 245 - display: "flex", 246 - alignItems: "center", 247 - justifyContent: "center", 248 - }, 249 389 body: { 250 390 fontSize: 14, 251 391 lineHeight: 1.4, ··· 255 395 whiteSpace: "pre-wrap", 256 396 overflowWrap: "anywhere", 257 397 }, 258 - facets: { 259 - marginTop: 8, 260 - display: "flex", 261 - gap: 4, 262 - }, 263 398 embedContainer: { 264 399 marginTop: 12, 265 400 padding: 8, 266 401 borderRadius: 12, 402 + border: `1px solid var(--atproto-color-border)`, 403 + background: `var(--atproto-color-bg-elevated)`, 267 404 display: "flex", 268 405 flexDirection: "column", 269 406 gap: 8, ··· 290 427 display: "inline-flex", 291 428 alignItems: "center", 292 429 }, 293 - facetTag: { 294 - padding: "2px 6px", 295 - borderRadius: 4, 296 - fontSize: 11, 297 - }, 298 430 replyLine: { 299 431 fontSize: 12, 300 432 }, ··· 312 444 }, 313 445 }; 314 446 315 - const themeStyles = { 316 - light: { 317 - card: { 318 - border: "1px solid #e2e8f0", 319 - background: "#ffffff", 320 - color: "#0f172a", 321 - }, 322 - avatarPlaceholder: { 323 - background: "#cbd5e1", 324 - }, 325 - handle: { 326 - color: "#64748b", 327 - }, 328 - time: { 329 - color: "#94a3b8", 330 - }, 331 - text: { 332 - color: "#0f172a", 333 - }, 334 - facetTag: { 335 - background: "#f1f5f9", 336 - color: "#475569", 337 - }, 338 - replyLine: { 339 - color: "#475569", 340 - }, 341 - replyLink: { 342 - color: "#2563eb", 343 - }, 344 - embedContainer: { 345 - border: "1px solid #e2e8f0", 346 - borderRadius: 12, 347 - background: "#f8fafc", 348 - }, 349 - postLink: { 350 - color: "#2563eb", 351 - }, 352 - }, 353 - dark: { 354 - card: { 355 - border: "1px solid #1e293b", 356 - background: "#0f172a", 357 - color: "#e2e8f0", 358 - }, 359 - avatarPlaceholder: { 360 - background: "#1e293b", 361 - }, 362 - handle: { 363 - color: "#cbd5f5", 364 - }, 365 - time: { 366 - color: "#94a3ff", 367 - }, 368 - text: { 369 - color: "#e2e8f0", 370 - }, 371 - facetTag: { 372 - background: "#1e293b", 373 - color: "#e0f2fe", 374 - }, 375 - replyLine: { 376 - color: "#cbd5f5", 377 - }, 378 - replyLink: { 379 - color: "#38bdf8", 380 - }, 381 - embedContainer: { 382 - border: "1px solid #1e293b", 383 - borderRadius: 12, 384 - background: "#0b1120", 385 - }, 386 - postLink: { 387 - color: "#38bdf8", 388 - }, 389 - }, 390 - } satisfies Record<"light" | "dark", Record<string, React.CSSProperties>>; 391 - 392 447 function formatReplyLabel( 393 448 target: ParsedAtUri, 394 449 resolvedHandle?: string, ··· 402 457 function createAutoEmbed( 403 458 record: FeedPostRecord, 404 459 authorDid: string | undefined, 405 - scheme: "light" | "dark", 406 460 ): React.ReactNode { 407 461 const embed = record.embed as { $type?: string } | undefined; 408 462 if (!embed) return null; 409 463 if (embed.$type === "app.bsky.embed.images") { 410 - return ( 411 - <ImagesEmbed 412 - embed={embed as ImagesEmbedType} 413 - did={authorDid} 414 - scheme={scheme} 415 - /> 416 - ); 464 + return <ImagesEmbed embed={embed as ImagesEmbedType} did={authorDid} />; 417 465 } 418 466 if (embed.$type === "app.bsky.embed.recordWithMedia") { 419 467 const media = (embed as RecordWithMediaEmbed).media; 420 468 if (media?.$type === "app.bsky.embed.images") { 421 469 return ( 422 - <ImagesEmbed 423 - embed={media as ImagesEmbedType} 424 - did={authorDid} 425 - scheme={scheme} 426 - /> 470 + <ImagesEmbed embed={media as ImagesEmbedType} did={authorDid} /> 427 471 ); 428 472 } 429 473 } ··· 457 501 interface ImagesEmbedProps { 458 502 embed: ImagesEmbedType; 459 503 did?: string; 460 - scheme: "light" | "dark"; 461 504 } 462 505 463 - const ImagesEmbed: React.FC<ImagesEmbedProps> = ({ embed, did, scheme }) => { 506 + const ImagesEmbed: React.FC<ImagesEmbedProps> = ({ embed, did }) => { 464 507 if (!embed.images || embed.images.length === 0) return null; 465 - const palette = 466 - scheme === "dark" ? imagesPalette.dark : imagesPalette.light; 508 + 467 509 const columns = 468 510 embed.images.length > 1 469 511 ? "repeat(auto-fit, minmax(160px, 1fr))" ··· 472 514 <div 473 515 style={{ 474 516 ...imagesBase.container, 475 - ...palette.container, 517 + background: `var(--atproto-color-bg-elevated)`, 476 518 gridTemplateColumns: columns, 477 519 }} 478 520 > 479 - {embed.images.map((image, idx) => ( 480 - <PostImage key={idx} image={image} did={did} scheme={scheme} /> 521 + {embed.images.map((img, idx) => ( 522 + <PostImage key={idx} image={img} did={did} /> 481 523 ))} 482 524 </div> 483 525 ); ··· 486 528 interface PostImageProps { 487 529 image: ImagesEmbedType["images"][number]; 488 530 did?: string; 489 - scheme: "light" | "dark"; 490 531 } 491 532 492 - const PostImage: React.FC<PostImageProps> = ({ image, did, scheme }) => { 493 - const cid = image.image?.ref?.$link ?? image.image?.cid; 494 - const { url, loading, error } = useBlob(did, cid); 533 + const PostImage: React.FC<PostImageProps> = ({ image, did }) => { 534 + const [showAltText, setShowAltText] = React.useState(false); 535 + const imageBlob = image.image; 536 + const cdnUrl = isBlobWithCdn(imageBlob) ? imageBlob.cdnUrl : undefined; 537 + const cid = cdnUrl ? undefined : extractCidFromBlob(imageBlob); 538 + const { url: urlFromBlob, loading, error } = useBlob(did, cid); 539 + const url = cdnUrl || urlFromBlob; 495 540 const alt = image.alt?.trim() || "Bluesky attachment"; 496 - const palette = 497 - scheme === "dark" ? imagesPalette.dark : imagesPalette.light; 541 + const hasAlt = image.alt && image.alt.trim().length > 0; 542 + 498 543 const aspect = 499 544 image.aspectRatio && image.aspectRatio.height > 0 500 545 ? `${image.aspectRatio.width} / ${image.aspectRatio.height}` 501 546 : undefined; 502 547 503 548 return ( 504 - <figure style={{ ...imagesBase.item, ...palette.item }}> 549 + <figure 550 + style={{ 551 + ...imagesBase.item, 552 + background: `var(--atproto-color-bg-elevated)`, 553 + }} 554 + > 505 555 <div 506 556 style={{ 507 557 ...imagesBase.media, 508 - ...palette.media, 558 + background: `var(--atproto-color-image-bg)`, 509 559 aspectRatio: aspect, 510 560 }} 511 561 > ··· 513 563 <img src={url} alt={alt} style={imagesBase.img} /> 514 564 ) : ( 515 565 <div 566 + role={error ? "alert" : "status"} 516 567 style={{ 517 568 ...imagesBase.placeholder, 518 - ...palette.placeholder, 569 + color: `var(--atproto-color-text-muted)`, 519 570 }} 520 571 > 521 572 {loading ··· 524 575 ? "Image failed to load" 525 576 : "Image unavailable"} 526 577 </div> 578 + )} 579 + {hasAlt && ( 580 + <button 581 + onClick={() => setShowAltText(!showAltText)} 582 + style={{ 583 + ...imagesBase.altBadge, 584 + background: showAltText 585 + ? `var(--atproto-color-text)` 586 + : `var(--atproto-color-bg-secondary)`, 587 + color: showAltText 588 + ? `var(--atproto-color-bg)` 589 + : `var(--atproto-color-text)`, 590 + }} 591 + title="Toggle alt text" 592 + aria-label="Toggle alt text" 593 + > 594 + ALT 595 + </button> 527 596 )} 528 597 </div> 529 - {image.alt && image.alt.trim().length > 0 && ( 598 + {hasAlt && showAltText && ( 530 599 <figcaption 531 - style={{ ...imagesBase.caption, ...palette.caption }} 600 + style={{ 601 + ...imagesBase.caption, 602 + color: `var(--atproto-color-text-secondary)`, 603 + }} 532 604 > 533 605 {image.alt} 534 606 </figcaption> ··· 571 643 fontSize: 12, 572 644 lineHeight: 1.3, 573 645 } satisfies React.CSSProperties, 646 + altBadge: { 647 + position: "absolute", 648 + bottom: 8, 649 + right: 8, 650 + padding: "4px 8px", 651 + fontSize: 10, 652 + fontWeight: 600, 653 + letterSpacing: "0.5px", 654 + border: "none", 655 + borderRadius: 4, 656 + cursor: "pointer", 657 + transition: "background 150ms ease, color 150ms ease", 658 + fontFamily: "system-ui, sans-serif", 659 + } satisfies React.CSSProperties, 574 660 }; 575 - 576 - const imagesPalette = { 577 - light: { 578 - container: { 579 - padding: 0, 580 - } satisfies React.CSSProperties, 581 - item: {}, 582 - media: { 583 - background: "#e2e8f0", 584 - } satisfies React.CSSProperties, 585 - placeholder: { 586 - color: "#475569", 587 - } satisfies React.CSSProperties, 588 - caption: { 589 - color: "#475569", 590 - } satisfies React.CSSProperties, 591 - }, 592 - dark: { 593 - container: { 594 - padding: 0, 595 - } satisfies React.CSSProperties, 596 - item: {}, 597 - media: { 598 - background: "#1e293b", 599 - } satisfies React.CSSProperties, 600 - placeholder: { 601 - color: "#cbd5f5", 602 - } satisfies React.CSSProperties, 603 - caption: { 604 - color: "#94a3b8", 605 - } satisfies React.CSSProperties, 606 - }, 607 - } as const; 608 661 609 662 export default BlueskyPostRenderer;
+54 -112
lib/renderers/BlueskyProfileRenderer.tsx
··· 1 1 import React from "react"; 2 2 import type { ProfileRecord } from "../types/bluesky"; 3 - import { 4 - useColorScheme, 5 - type ColorSchemePreference, 6 - } from "../hooks/useColorScheme"; 7 3 import { BlueskyIcon } from "../components/BlueskyIcon"; 4 + import { useAtProto } from "../providers/AtProtoProvider"; 8 5 9 6 export interface BlueskyProfileRendererProps { 10 7 record: ProfileRecord; ··· 13 10 did: string; 14 11 handle?: string; 15 12 avatarUrl?: string; 16 - colorScheme?: ColorSchemePreference; 17 13 } 18 14 19 15 export const BlueskyProfileRenderer: React.FC<BlueskyProfileRendererProps> = ({ ··· 23 19 did, 24 20 handle, 25 21 avatarUrl, 26 - colorScheme = "system", 27 22 }) => { 28 - const scheme = useColorScheme(colorScheme); 23 + const { blueskyAppBaseUrl } = useAtProto(); 29 24 30 25 if (error) 31 26 return ( 32 - <div style={{ padding: 8, color: "crimson" }}> 27 + <div role="alert" style={{ padding: 8, color: "crimson" }}> 33 28 Failed to load profile. 34 29 </div> 35 30 ); 36 - if (loading && !record) return <div style={{ padding: 8 }}>Loadingโ€ฆ</div>; 31 + if (loading && !record) return <div role="status" aria-live="polite" style={{ padding: 8 }}>Loadingโ€ฆ</div>; 37 32 38 - const palette = scheme === "dark" ? theme.dark : theme.light; 39 - const profileUrl = `https://bsky.app/profile/${encodeURIComponent(did)}`; 33 + const profileUrl = `${blueskyAppBaseUrl}/profile/${did}`; 40 34 const rawWebsite = record.website?.trim(); 41 35 const websiteHref = rawWebsite 42 36 ? rawWebsite.match(/^https?:\/\//i) ··· 48 42 : undefined; 49 43 50 44 return ( 51 - <div style={{ ...base.card, ...palette.card }}> 45 + <div style={{ ...base.card, background: `var(--atproto-color-bg)`, borderColor: `var(--atproto-color-border)`, color: `var(--atproto-color-text)` }}> 52 46 <div style={base.header}> 53 47 {avatarUrl ? ( 54 - <img src={avatarUrl} alt="avatar" style={base.avatarImg} /> 48 + <img src={avatarUrl} alt={`${record.displayName || handle || did}'s profile picture`} style={base.avatarImg} /> 55 49 ) : ( 56 50 <div 57 - style={{ ...base.avatar, ...palette.avatar }} 58 - aria-label="avatar" 51 + style={{ ...base.avatar, background: `var(--atproto-color-bg-elevated)` }} 52 + aria-hidden="true" 59 53 /> 60 54 )} 61 55 <div style={{ flex: 1 }}> 62 - <div style={{ ...base.display, ...palette.display }}> 56 + <div style={{ ...base.display, color: `var(--atproto-color-text)` }}> 63 57 {record.displayName ?? handle ?? did} 64 58 </div> 65 - <div style={{ ...base.handleLine, ...palette.handleLine }}> 59 + <div style={{ ...base.handleLine, color: `var(--atproto-color-text-secondary)` }}> 66 60 @{handle ?? did} 67 61 </div> 68 62 {record.pronouns && ( 69 - <div style={{ ...base.pronouns, ...palette.pronouns }}> 63 + <div style={{ ...base.pronouns, background: `var(--atproto-color-bg-elevated)`, color: `var(--atproto-color-text-secondary)` }}> 70 64 {record.pronouns} 71 65 </div> 72 66 )} 73 67 </div> 74 68 </div> 75 69 {record.description && ( 76 - <p style={{ ...base.desc, ...palette.desc }}> 70 + <p style={{ ...base.desc, color: `var(--atproto-color-text)` }}> 77 71 {record.description} 78 72 </p> 79 73 )} 80 - {record.createdAt && ( 81 - <div style={{ ...base.meta, ...palette.meta }}> 82 - Joined {new Date(record.createdAt).toLocaleDateString()} 83 - </div> 84 - )} 85 - <div style={base.links}> 86 - {websiteHref && websiteLabel && ( 74 + <div style={base.bottomRow}> 75 + <div style={base.bottomLeft}> 76 + {record.createdAt && ( 77 + <div style={{ ...base.meta, color: `var(--atproto-color-text-secondary)` }}> 78 + Joined {new Date(record.createdAt).toLocaleDateString()} 79 + </div> 80 + )} 81 + {websiteHref && websiteLabel && ( 82 + <a 83 + href={websiteHref} 84 + target="_blank" 85 + rel="noopener noreferrer" 86 + style={{ ...base.link, color: `var(--atproto-color-link)` }} 87 + > 88 + {websiteLabel} 89 + </a> 90 + )} 87 91 <a 88 - href={websiteHref} 92 + href={profileUrl} 89 93 target="_blank" 90 94 rel="noopener noreferrer" 91 - style={{ ...base.link, ...palette.link }} 95 + style={{ ...base.link, color: `var(--atproto-color-link)` }} 92 96 > 93 - {websiteLabel} 97 + View on Bluesky 94 98 </a> 95 - )} 96 - <a 97 - href={profileUrl} 98 - target="_blank" 99 - rel="noopener noreferrer" 100 - style={{ ...base.link, ...palette.link }} 101 - > 102 - View on Bluesky 103 - </a> 104 - </div> 105 - <div style={base.iconCorner} aria-hidden> 106 - <BlueskyIcon size={18} /> 99 + </div> 100 + <div aria-hidden> 101 + <BlueskyIcon size={18} /> 102 + </div> 107 103 </div> 108 104 </div> 109 105 ); ··· 111 107 112 108 const base: Record<string, React.CSSProperties> = { 113 109 card: { 110 + display: "flex", 111 + flexDirection: "column", 112 + height: "100%", 114 113 borderRadius: 12, 115 114 padding: 16, 116 115 fontFamily: "system-ui, sans-serif", ··· 148 147 lineHeight: 1.4, 149 148 }, 150 149 meta: { 151 - marginTop: 12, 150 + marginTop: 0, 152 151 fontSize: 12, 153 152 }, 154 153 pronouns: { ··· 161 160 padding: "2px 8px", 162 161 marginTop: 6, 163 162 }, 164 - links: { 165 - display: "flex", 166 - flexDirection: "column", 167 - gap: 8, 168 - marginTop: 12, 169 - }, 170 163 link: { 171 164 display: "inline-flex", 172 165 alignItems: "center", ··· 175 168 fontWeight: 600, 176 169 textDecoration: "none", 177 170 }, 171 + bottomRow: { 172 + display: "flex", 173 + alignItems: "flex-end", 174 + justifyContent: "space-between", 175 + marginTop: "auto", 176 + paddingTop: 12, 177 + }, 178 + bottomLeft: { 179 + display: "flex", 180 + flexDirection: "column", 181 + gap: 8, 182 + }, 178 183 iconCorner: { 179 - position: "absolute", 180 - right: 12, 181 - bottom: 12, 184 + // Removed absolute positioning, now in flex layout 182 185 }, 183 186 }; 184 - 185 - const theme = { 186 - light: { 187 - card: { 188 - border: "1px solid #e2e8f0", 189 - background: "#ffffff", 190 - color: "#0f172a", 191 - }, 192 - avatar: { 193 - background: "#cbd5e1", 194 - }, 195 - display: { 196 - color: "#0f172a", 197 - }, 198 - handleLine: { 199 - color: "#64748b", 200 - }, 201 - desc: { 202 - color: "#0f172a", 203 - }, 204 - meta: { 205 - color: "#94a3b8", 206 - }, 207 - pronouns: { 208 - background: "#e2e8f0", 209 - color: "#1e293b", 210 - }, 211 - link: { 212 - color: "#2563eb", 213 - }, 214 - }, 215 - dark: { 216 - card: { 217 - border: "1px solid #1e293b", 218 - background: "#0b1120", 219 - color: "#e2e8f0", 220 - }, 221 - avatar: { 222 - background: "#1e293b", 223 - }, 224 - display: { 225 - color: "#e2e8f0", 226 - }, 227 - handleLine: { 228 - color: "#cbd5f5", 229 - }, 230 - desc: { 231 - color: "#e2e8f0", 232 - }, 233 - meta: { 234 - color: "#a5b4fc", 235 - }, 236 - pronouns: { 237 - background: "#1e293b", 238 - color: "#e2e8f0", 239 - }, 240 - link: { 241 - color: "#38bdf8", 242 - }, 243 - }, 244 - } satisfies Record<"light" | "dark", Record<string, React.CSSProperties>>; 245 187 246 188 export default BlueskyProfileRenderer;
+749
lib/renderers/CurrentlyPlayingRenderer.tsx
··· 1 + import React, { useState, useEffect, useRef } from "react"; 2 + import type { TealActorStatusRecord } from "../types/teal"; 3 + 4 + export interface CurrentlyPlayingRendererProps { 5 + record: TealActorStatusRecord; 6 + error?: Error; 7 + loading: boolean; 8 + did: string; 9 + rkey: string; 10 + colorScheme?: "light" | "dark" | "system"; 11 + /** Label to display (e.g., "CURRENTLY PLAYING", "LAST PLAYED"). Defaults to "CURRENTLY PLAYING". */ 12 + label?: string; 13 + /** Handle to display in not listening state */ 14 + handle?: string; 15 + } 16 + 17 + interface SonglinkPlatform { 18 + url: string; 19 + entityUniqueId: string; 20 + nativeAppUriMobile?: string; 21 + nativeAppUriDesktop?: string; 22 + } 23 + 24 + interface SonglinkResponse { 25 + linksByPlatform: { 26 + [platform: string]: SonglinkPlatform; 27 + }; 28 + entitiesByUniqueId: { 29 + [id: string]: { 30 + thumbnailUrl?: string; 31 + title?: string; 32 + artistName?: string; 33 + }; 34 + }; 35 + } 36 + 37 + export const CurrentlyPlayingRenderer: React.FC<CurrentlyPlayingRendererProps> = ({ 38 + record, 39 + error, 40 + loading, 41 + label = "CURRENTLY PLAYING", 42 + handle, 43 + }) => { 44 + const [albumArt, setAlbumArt] = useState<string | undefined>(undefined); 45 + const [artworkLoading, setArtworkLoading] = useState(true); 46 + const [songlinkData, setSonglinkData] = useState<SonglinkResponse | undefined>(undefined); 47 + const [showPlatformModal, setShowPlatformModal] = useState(false); 48 + const previousTrackIdentityRef = useRef<string>(""); 49 + 50 + // Auto-refresh interval removed - handled by AtProtoRecord 51 + 52 + useEffect(() => { 53 + if (!record) return; 54 + 55 + const { item } = record; 56 + const artistName = item.artists[0]?.artistName; 57 + const trackName = item.trackName; 58 + 59 + if (!artistName || !trackName) { 60 + setArtworkLoading(false); 61 + return; 62 + } 63 + 64 + // Create a unique identity for this track 65 + const trackIdentity = `${trackName}::${artistName}`; 66 + 67 + // Check if the track has actually changed 68 + const trackHasChanged = trackIdentity !== previousTrackIdentityRef.current; 69 + 70 + // Update tracked identity 71 + previousTrackIdentityRef.current = trackIdentity; 72 + 73 + // Only reset loading state and clear data when track actually changes 74 + // This prevents the loading flicker when auto-refreshing the same track 75 + if (trackHasChanged) { 76 + console.log(`[teal.fm] ๐ŸŽต Track changed: "${trackName}" by ${artistName}`); 77 + setArtworkLoading(true); 78 + setAlbumArt(undefined); 79 + setSonglinkData(undefined); 80 + } else { 81 + console.log(`[teal.fm] ๐Ÿ”„ Auto-refresh: same track still playing ("${trackName}" by ${artistName})`); 82 + } 83 + 84 + let cancelled = false; 85 + 86 + const fetchMusicData = async () => { 87 + try { 88 + // Step 1: Check if we have an ISRC - Songlink supports this directly 89 + if (item.isrc) { 90 + console.log(`[teal.fm] Attempting ISRC lookup for ${trackName} by ${artistName}`, { isrc: item.isrc }); 91 + const response = await fetch( 92 + `https://api.song.link/v1-alpha.1/links?platform=isrc&type=song&id=${encodeURIComponent(item.isrc)}&songIfSingle=true` 93 + ); 94 + if (cancelled) return; 95 + if (response.ok) { 96 + const data = await response.json(); 97 + setSonglinkData(data); 98 + 99 + // Extract album art from Songlink data 100 + const entityId = data.entityUniqueId; 101 + const entity = data.entitiesByUniqueId?.[entityId]; 102 + 103 + // Debug: Log the entity structure to see what fields are available 104 + console.log(`[teal.fm] ISRC entity data:`, { entityId, entity }); 105 + 106 + if (entity?.thumbnailUrl) { 107 + console.log(`[teal.fm] โœ“ Found album art via ISRC lookup`); 108 + setAlbumArt(entity.thumbnailUrl); 109 + } else { 110 + console.warn(`[teal.fm] ISRC lookup succeeded but no thumbnail found`, { 111 + entityId, 112 + entityKeys: entity ? Object.keys(entity) : 'no entity', 113 + entity 114 + }); 115 + } 116 + setArtworkLoading(false); 117 + return; 118 + } else { 119 + console.warn(`[teal.fm] ISRC lookup failed with status ${response.status}`); 120 + } 121 + } 122 + 123 + // Step 2: Search iTunes Search API to find the track (single request for both artwork and links) 124 + console.log(`[teal.fm] Attempting iTunes search for: "${trackName}" by "${artistName}"`); 125 + const iTunesSearchUrl = `https://itunes.apple.com/search?term=${encodeURIComponent( 126 + `${trackName} ${artistName}` 127 + )}&media=music&entity=song&limit=1`; 128 + 129 + const iTunesResponse = await fetch(iTunesSearchUrl); 130 + 131 + if (cancelled) return; 132 + 133 + if (iTunesResponse.ok) { 134 + const iTunesData = await iTunesResponse.json(); 135 + 136 + if (iTunesData.results && iTunesData.results.length > 0) { 137 + const match = iTunesData.results[0]; 138 + const iTunesId = match.trackId; 139 + 140 + // Set album artwork immediately (600x600 for high quality) 141 + const artworkUrl = match.artworkUrl100?.replace('100x100', '600x600') || match.artworkUrl100; 142 + if (artworkUrl) { 143 + console.log(`[teal.fm] โœ“ Found album art via iTunes search`, { url: artworkUrl }); 144 + setAlbumArt(artworkUrl); 145 + } else { 146 + console.warn(`[teal.fm] iTunes match found but no artwork URL`); 147 + } 148 + setArtworkLoading(false); 149 + 150 + // Step 3: Use iTunes ID with Songlink to get all platform links 151 + console.log(`[teal.fm] Fetching platform links via Songlink (iTunes ID: ${iTunesId})`); 152 + const songlinkResponse = await fetch( 153 + `https://api.song.link/v1-alpha.1/links?platform=itunes&type=song&id=${iTunesId}&songIfSingle=true` 154 + ); 155 + 156 + if (cancelled) return; 157 + 158 + if (songlinkResponse.ok) { 159 + const songlinkData = await songlinkResponse.json(); 160 + console.log(`[teal.fm] โœ“ Got platform links from Songlink`); 161 + setSonglinkData(songlinkData); 162 + return; 163 + } else { 164 + console.warn(`[teal.fm] Songlink request failed with status ${songlinkResponse.status}`); 165 + } 166 + } else { 167 + console.warn(`[teal.fm] No iTunes results found for "${trackName}" by "${artistName}"`); 168 + setArtworkLoading(false); 169 + } 170 + } else { 171 + console.warn(`[teal.fm] iTunes search failed with status ${iTunesResponse.status}`); 172 + } 173 + 174 + // Step 4: Fallback - if originUrl is from a supported platform, try it directly 175 + if (item.originUrl && ( 176 + item.originUrl.includes('spotify.com') || 177 + item.originUrl.includes('apple.com') || 178 + item.originUrl.includes('youtube.com') || 179 + item.originUrl.includes('tidal.com') 180 + )) { 181 + console.log(`[teal.fm] Attempting Songlink lookup via originUrl`, { url: item.originUrl }); 182 + const songlinkResponse = await fetch( 183 + `https://api.song.link/v1-alpha.1/links?url=${encodeURIComponent(item.originUrl)}&songIfSingle=true` 184 + ); 185 + 186 + if (cancelled) return; 187 + 188 + if (songlinkResponse.ok) { 189 + const data = await songlinkResponse.json(); 190 + console.log(`[teal.fm] โœ“ Got data from Songlink via originUrl`); 191 + setSonglinkData(data); 192 + 193 + // Try to get artwork from Songlink if we don't have it yet 194 + if (!albumArt) { 195 + const entityId = data.entityUniqueId; 196 + const entity = data.entitiesByUniqueId?.[entityId]; 197 + 198 + // Debug: Log the entity structure to see what fields are available 199 + console.log(`[teal.fm] Songlink originUrl entity data:`, { entityId, entity }); 200 + 201 + if (entity?.thumbnailUrl) { 202 + console.log(`[teal.fm] โœ“ Found album art via Songlink originUrl lookup`); 203 + setAlbumArt(entity.thumbnailUrl); 204 + } else { 205 + console.warn(`[teal.fm] Songlink lookup succeeded but no thumbnail found`, { 206 + entityId, 207 + entityKeys: entity ? Object.keys(entity) : 'no entity', 208 + entity 209 + }); 210 + } 211 + } 212 + } else { 213 + console.warn(`[teal.fm] Songlink originUrl lookup failed with status ${songlinkResponse.status}`); 214 + } 215 + } 216 + 217 + if (!albumArt) { 218 + console.warn(`[teal.fm] โœ— All album art fetch methods failed for "${trackName}" by "${artistName}"`); 219 + } 220 + 221 + setArtworkLoading(false); 222 + } catch (err) { 223 + console.error(`[teal.fm] โœ— Error fetching music data for "${trackName}" by "${artistName}":`, err); 224 + setArtworkLoading(false); 225 + } 226 + }; 227 + 228 + fetchMusicData(); 229 + 230 + return () => { 231 + cancelled = true; 232 + }; 233 + }, [record]); // Runs on record change 234 + 235 + if (error) 236 + return ( 237 + <div role="alert" style={{ padding: 8, color: "var(--atproto-color-error)" }}> 238 + Failed to load status. 239 + </div> 240 + ); 241 + if (loading && !record) 242 + return ( 243 + <div role="status" aria-live="polite" style={{ padding: 8, color: "var(--atproto-color-text-secondary)" }}> 244 + Loadingโ€ฆ 245 + </div> 246 + ); 247 + 248 + const { item } = record; 249 + 250 + // Check if user is not listening to anything 251 + const isNotListening = !item.trackName || item.artists.length === 0; 252 + 253 + // Show "not listening" state 254 + if (isNotListening) { 255 + const displayHandle = handle || "User"; 256 + return ( 257 + <div style={styles.notListeningContainer}> 258 + <div style={styles.notListeningIcon}> 259 + <svg 260 + width="80" 261 + height="80" 262 + viewBox="0 0 24 24" 263 + fill="none" 264 + stroke="currentColor" 265 + strokeWidth="1.5" 266 + strokeLinecap="round" 267 + strokeLinejoin="round" 268 + > 269 + <path d="M9 18V5l12-2v13" /> 270 + <circle cx="6" cy="18" r="3" /> 271 + <circle cx="18" cy="16" r="3" /> 272 + </svg> 273 + </div> 274 + <div style={styles.notListeningTitle}> 275 + {displayHandle} isn't listening to anything 276 + </div> 277 + <div style={styles.notListeningSubtitle}>Check back soon</div> 278 + </div> 279 + ); 280 + } 281 + 282 + const artistNames = item.artists.map((a) => a.artistName).join(", "); 283 + 284 + const platformConfig: Record<string, { name: string; svg: string; color: string }> = { 285 + spotify: { 286 + name: "Spotify", 287 + svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><path fill="#1ed760" d="M248 8C111.1 8 0 119.1 0 256s111.1 248 248 248 248-111.1 248-248S384.9 8 248 8Z"/><path d="M406.6 231.1c-5.2 0-8.4-1.3-12.9-3.9-71.2-42.5-198.5-52.7-280.9-29.7-3.6 1-8.1 2.6-12.9 2.6-13.2 0-23.3-10.3-23.3-23.6 0-13.6 8.4-21.3 17.4-23.9 35.2-10.3 74.6-15.2 117.5-15.2 73 0 149.5 15.2 205.4 47.8 7.8 4.5 12.9 10.7 12.9 22.6 0 13.6-11 23.3-23.2 23.3zm-31 76.2c-5.2 0-8.7-2.3-12.3-4.2-62.5-37-155.7-51.9-238.6-29.4-4.8 1.3-7.4 2.6-11.9 2.6-10.7 0-19.4-8.7-19.4-19.4s5.2-17.8 15.5-20.7c27.8-7.8 56.2-13.6 97.8-13.6 64.9 0 127.6 16.1 177 45.5 8.1 4.8 11.3 11 11.3 19.7-.1 10.8-8.5 19.5-19.4 19.5zm-26.9 65.6c-4.2 0-6.8-1.3-10.7-3.6-62.4-37.6-135-39.2-206.7-24.5-3.9 1-9 2.6-11.9 2.6-9.7 0-15.8-7.7-15.8-15.8 0-10.3 6.1-15.2 13.6-16.8 81.9-18.1 165.6-16.5 237 26.2 6.1 3.9 9.7 7.4 9.7 16.5s-7.1 15.4-15.2 15.4z"/></svg>', 288 + color: "#1DB954" 289 + }, 290 + appleMusic: { 291 + name: "Apple Music", 292 + svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 361 361"><defs><linearGradient id="apple-grad" x1="180" y1="358.6" x2="180" y2="7.76" gradientUnits="userSpaceOnUse"><stop offset="0" style="stop-color:#FA233B"/><stop offset="1" style="stop-color:#FB5C74"/></linearGradient></defs><path fill="url(#apple-grad)" d="M360 112.61V247.39c0 4.3 0 8.6-.02 12.9-.02 3.62-.06 7.24-.16 10.86-.21 7.89-.68 15.84-2.08 23.64-1.42 7.92-3.75 15.29-7.41 22.49-3.6 7.07-8.3 13.53-13.91 19.14-5.61 5.61-12.08 10.31-19.15 13.91-7.19 3.66-14.56 5.98-22.47 7.41-7.8 1.4-15.76 1.87-23.65 2.08-3.62.1-7.24.14-10.86.16-4.3.03-8.6.02-12.9.02H112.61c-4.3 0-8.6 0-12.9-.02-3.62-.02-7.24-.06-10.86-.16-7.89-.21-15.85-.68-23.65-2.08-7.92-1.42-15.28-3.75-22.47-7.41-7.07-3.6-13.54-8.3-19.15-13.91-5.61-5.61-10.31-12.07-13.91-19.14-3.66-7.2-5.99-14.57-7.41-22.49-1.4-7.8-1.87-15.76-2.08-23.64-.1-3.62-.14-7.24-.16-10.86C0 255.99 0 251.69 0 247.39V112.61c0-4.3 0-8.6.02-12.9.02-3.62.06-7.24.16-10.86.21-7.89.68-15.84 2.08-23.64 1.42-7.92 3.75-15.29 7.41-22.49 3.6-7.07 8.3-13.53 13.91-19.14 5.61-5.61 12.08-10.31 19.15-13.91 7.19-3.66 14.56-5.98 22.47-7.41 7.8-1.4 15.76-1.87 23.65-2.08 3.62-.1 7.24-.14 10.86-.16C104.01 0 108.31 0 112.61 0h134.77c4.3 0 8.6 0 12.9.02 3.62.02 7.24.06 10.86.16 7.89.21 15.85.68 23.65 2.08 7.92 1.42 15.28 3.75 22.47 7.41 7.07 3.6 13.54 8.3 19.15 13.91 5.61 5.61 10.31 12.07 13.91 19.14 3.66 7.2 5.99 14.57 7.41 22.49 1.4 7.8 1.87 15.76 2.08 23.64.1 3.62.14 7.24.16 10.86.03 4.3.02 8.6.02 12.9z"/><path fill="#FFF" d="M254.5 55c-.87.08-8.6 1.45-9.53 1.64l-107 21.59-.04.01c-2.79.59-4.98 1.58-6.67 3-2.04 1.71-3.17 4.13-3.6 6.95-.09.6-.24 1.82-.24 3.62v133.92c0 3.13-.25 6.17-2.37 8.76-2.12 2.59-4.74 3.37-7.81 3.99-2.33.47-4.66.94-6.99 1.41-8.84 1.78-14.59 2.99-19.8 5.01-4.98 1.93-8.71 4.39-11.68 7.51-5.89 6.17-8.28 14.54-7.46 22.38.7 6.69 3.71 13.09 8.88 17.82 3.49 3.2 7.85 5.63 12.99 6.66 5.33 1.07 11.01.7 19.31-.98 4.42-.89 8.56-2.28 12.5-4.61 3.9-2.3 7.24-5.37 9.85-9.11 2.62-3.75 4.31-7.92 5.24-12.35.96-4.57 1.19-8.7 1.19-13.26V128.82c0-6.22 1.76-7.86 6.78-9.08l93.09-18.75c5.79-1.11 8.52.54 8.52 6.61v79.29c0 3.14-.03 6.32-2.17 8.92-2.12 2.59-4.74 3.37-7.81 3.99-2.33.47-4.66.94-6.99 1.41-8.84 1.78-14.59 2.99-19.8 5.01-4.98 1.93-8.71 4.39-11.68 7.51-5.89 6.17-8.49 14.54-7.67 22.38.7 6.69 3.92 13.09 9.09 17.82 3.49 3.2 7.85 5.56 12.99 6.6 5.33 1.07 11.01.69 19.31-.98 4.42-.89 8.56-2.22 12.5-4.55 3.9-2.3 7.24-5.37 9.85-9.11 2.62-3.75 4.31-7.92 5.24-12.35.96-4.57 1-8.7 1-13.26V64.46c0-6.16-3.25-9.96-9.04-9.46z"/></svg>', 293 + color: "#FA243C" 294 + }, 295 + youtube: { 296 + name: "YouTube", 297 + svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300"><g transform="scale(.75)"><path fill="red" d="M199.917 105.63s-84.292 0-105.448 5.497c-11.328 3.165-20.655 12.493-23.82 23.987-5.498 21.156-5.498 64.969-5.498 64.969s0 43.979 5.497 64.802c3.165 11.494 12.326 20.655 23.82 23.82 21.323 5.664 105.448 5.664 105.448 5.664s84.459 0 105.615-5.497c11.494-3.165 20.655-12.16 23.654-23.82 5.664-20.99 5.664-64.803 5.664-64.803s.166-43.98-5.664-65.135c-2.999-11.494-12.16-20.655-23.654-23.654-21.156-5.83-105.615-5.83-105.615-5.83zm-26.82 53.974 70.133 40.479-70.133 40.312v-80.79z"/><path fill="#fff" d="m173.097 159.604 70.133 40.479-70.133 40.312v-80.79z"/></g></svg>', 298 + color: "#FF0000" 299 + }, 300 + youtubeMusic: { 301 + name: "YouTube Music", 302 + svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 176 176"><circle fill="#FF0000" cx="88" cy="88" r="88"/><path fill="#FFF" d="M88 46c23.1 0 42 18.8 42 42s-18.8 42-42 42-42-18.8-42-42 18.8-42 42-42m0-4c-25.4 0-46 20.6-46 46s20.6 46 46 46 46-20.6 46-46-20.6-46-46-46z"/><path fill="#FFF" d="m72 111 39-24-39-22z"/></svg>', 303 + color: "#FF0000" 304 + }, 305 + tidal: { 306 + name: "Tidal", 307 + svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M256 0c141.385 0 256 114.615 256 256S397.385 512 256 512 0 397.385 0 256 114.615 0 256 0zm50.384 219.459-50.372 50.383 50.379 50.391-50.382 50.393-50.395-50.393 50.393-50.389-50.393-50.39 50.395-50.372 50.38 50.369 50.389-50.375 50.382 50.382-50.382 50.392-50.394-50.391zm-100.767-.001-50.392 50.392-50.385-50.392 50.385-50.382 50.392 50.382z"/></svg>', 308 + color: "#000000" 309 + }, 310 + bandcamp: { 311 + name: "Bandcamp", 312 + svg: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="#1DA0C3" d="M0 156v200h172l84-200z"/></svg>', 313 + color: "#1DA0C3" 314 + }, 315 + }; 316 + 317 + const availablePlatforms = songlinkData 318 + ? Object.keys(platformConfig).filter((platform) => 319 + songlinkData.linksByPlatform[platform] 320 + ) 321 + : []; 322 + 323 + return ( 324 + <> 325 + <div style={styles.container}> 326 + {/* Album Artwork */} 327 + <div style={styles.artworkContainer}> 328 + {artworkLoading ? ( 329 + <div style={styles.artworkPlaceholder}> 330 + <div style={styles.loadingSpinner} /> 331 + </div> 332 + ) : albumArt ? ( 333 + <img 334 + src={albumArt} 335 + alt={`${item.releaseName || "Album"} cover`} 336 + style={styles.artwork} 337 + onError={(e) => { 338 + console.error("Failed to load album art:", { 339 + url: albumArt, 340 + track: item.trackName, 341 + artist: item.artists[0]?.artistName, 342 + error: "Image load error" 343 + }); 344 + e.currentTarget.style.display = "none"; 345 + }} 346 + /> 347 + ) : ( 348 + <div style={styles.artworkPlaceholder}> 349 + <svg 350 + width="64" 351 + height="64" 352 + viewBox="0 0 24 24" 353 + fill="none" 354 + stroke="currentColor" 355 + strokeWidth="1.5" 356 + > 357 + <circle cx="12" cy="12" r="10" /> 358 + <circle cx="12" cy="12" r="3" /> 359 + <path d="M12 2v3M12 19v3M2 12h3M19 12h3" /> 360 + </svg> 361 + </div> 362 + )} 363 + </div> 364 + 365 + {/* Content */} 366 + <div style={styles.content}> 367 + <div style={styles.label}>{label}</div> 368 + <h2 style={styles.trackName}>{item.trackName}</h2> 369 + <div style={styles.artistName}>{artistNames}</div> 370 + {item.releaseName && ( 371 + <div style={styles.releaseName}>from {item.releaseName}</div> 372 + )} 373 + 374 + {/* Listen Button */} 375 + {availablePlatforms.length > 0 ? ( 376 + <button 377 + onClick={() => setShowPlatformModal(true)} 378 + style={styles.listenButton} 379 + data-teal-listen-button="true" 380 + > 381 + <span>Listen with your Streaming Client</span> 382 + <svg 383 + width="16" 384 + height="16" 385 + viewBox="0 0 24 24" 386 + fill="none" 387 + stroke="currentColor" 388 + strokeWidth="2" 389 + strokeLinecap="round" 390 + strokeLinejoin="round" 391 + > 392 + <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" /> 393 + <polyline points="15 3 21 3 21 9" /> 394 + <line x1="10" y1="14" x2="21" y2="3" /> 395 + </svg> 396 + </button> 397 + ) : item.originUrl ? ( 398 + <a 399 + href={item.originUrl} 400 + target="_blank" 401 + rel="noopener noreferrer" 402 + style={styles.listenButton} 403 + data-teal-listen-button="true" 404 + > 405 + <span>Listen on Last.fm</span> 406 + <svg 407 + width="16" 408 + height="16" 409 + viewBox="0 0 24 24" 410 + fill="none" 411 + stroke="currentColor" 412 + strokeWidth="2" 413 + strokeLinecap="round" 414 + strokeLinejoin="round" 415 + > 416 + <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" /> 417 + <polyline points="15 3 21 3 21 9" /> 418 + <line x1="10" y1="14" x2="21" y2="3" /> 419 + </svg> 420 + </a> 421 + ) : null} 422 + </div> 423 + </div> 424 + 425 + {/* Platform Selection Modal */} 426 + {showPlatformModal && songlinkData && ( 427 + <div style={styles.modalOverlay} onClick={() => setShowPlatformModal(false)}> 428 + <div 429 + role="dialog" 430 + aria-modal="true" 431 + aria-labelledby="platform-modal-title" 432 + style={styles.modalContent} 433 + onClick={(e) => e.stopPropagation()} 434 + > 435 + <div style={styles.modalHeader}> 436 + <h3 id="platform-modal-title" style={styles.modalTitle}>Choose your streaming service</h3> 437 + <button 438 + style={styles.closeButton} 439 + onClick={() => setShowPlatformModal(false)} 440 + data-teal-close="true" 441 + > 442 + ร— 443 + </button> 444 + </div> 445 + <div style={styles.platformList}> 446 + {availablePlatforms.map((platform) => { 447 + const config = platformConfig[platform]; 448 + const link = songlinkData.linksByPlatform[platform]; 449 + return ( 450 + <a 451 + key={platform} 452 + href={link.url} 453 + target="_blank" 454 + rel="noopener noreferrer" 455 + style={{ 456 + ...styles.platformItem, 457 + borderLeft: `4px solid ${config.color}`, 458 + }} 459 + onClick={() => setShowPlatformModal(false)} 460 + data-teal-platform="true" 461 + > 462 + <span 463 + style={styles.platformIcon} 464 + dangerouslySetInnerHTML={{ __html: config.svg }} 465 + /> 466 + <span style={styles.platformName}>{config.name}</span> 467 + <svg 468 + width="20" 469 + height="20" 470 + viewBox="0 0 24 24" 471 + fill="none" 472 + stroke="currentColor" 473 + strokeWidth="2" 474 + style={styles.platformArrow} 475 + > 476 + <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" /> 477 + <polyline points="15 3 21 3 21 9" /> 478 + <line x1="10" y1="14" x2="21" y2="3" /> 479 + </svg> 480 + </a> 481 + ); 482 + })} 483 + </div> 484 + </div> 485 + </div> 486 + )} 487 + </> 488 + ); 489 + }; 490 + 491 + const styles: Record<string, React.CSSProperties> = { 492 + container: { 493 + fontFamily: "system-ui, -apple-system, sans-serif", 494 + display: "flex", 495 + flexDirection: "column", 496 + background: "var(--atproto-color-bg)", 497 + borderRadius: 16, 498 + overflow: "hidden", 499 + maxWidth: 420, 500 + color: "var(--atproto-color-text)", 501 + boxShadow: "0 8px 24px rgba(0, 0, 0, 0.4)", 502 + border: "1px solid var(--atproto-color-border)", 503 + }, 504 + artworkContainer: { 505 + width: "100%", 506 + aspectRatio: "1 / 1", 507 + position: "relative", 508 + overflow: "hidden", 509 + }, 510 + artwork: { 511 + width: "100%", 512 + height: "100%", 513 + objectFit: "cover", 514 + display: "block", 515 + }, 516 + artworkPlaceholder: { 517 + width: "100%", 518 + height: "100%", 519 + display: "flex", 520 + alignItems: "center", 521 + justifyContent: "center", 522 + background: "linear-gradient(135deg, #667eea 0%, #764ba2 100%)", 523 + color: "rgba(255, 255, 255, 0.5)", 524 + }, 525 + loadingSpinner: { 526 + width: 40, 527 + height: 40, 528 + border: "3px solid var(--atproto-color-border)", 529 + borderTop: "3px solid var(--atproto-color-primary)", 530 + borderRadius: "50%", 531 + animation: "spin 1s linear infinite", 532 + }, 533 + content: { 534 + padding: "24px", 535 + display: "flex", 536 + flexDirection: "column", 537 + gap: "8px", 538 + }, 539 + label: { 540 + fontSize: 11, 541 + fontWeight: 600, 542 + letterSpacing: "0.1em", 543 + textTransform: "uppercase", 544 + color: "var(--atproto-color-text-secondary)", 545 + marginBottom: "4px", 546 + }, 547 + trackName: { 548 + fontSize: 28, 549 + fontWeight: 700, 550 + margin: 0, 551 + lineHeight: 1.2, 552 + color: "var(--atproto-color-text)", 553 + }, 554 + artistName: { 555 + fontSize: 16, 556 + color: "var(--atproto-color-text-secondary)", 557 + marginTop: "4px", 558 + }, 559 + releaseName: { 560 + fontSize: 14, 561 + color: "var(--atproto-color-text-secondary)", 562 + marginTop: "2px", 563 + }, 564 + listenButton: { 565 + display: "inline-flex", 566 + alignItems: "center", 567 + gap: "8px", 568 + marginTop: "16px", 569 + padding: "12px 20px", 570 + background: "var(--atproto-color-bg-elevated)", 571 + border: "1px solid var(--atproto-color-border)", 572 + borderRadius: 24, 573 + color: "var(--atproto-color-text)", 574 + fontSize: 14, 575 + fontWeight: 600, 576 + textDecoration: "none", 577 + cursor: "pointer", 578 + transition: "all 0.2s ease", 579 + alignSelf: "flex-start", 580 + }, 581 + modalOverlay: { 582 + position: "fixed", 583 + top: 0, 584 + left: 0, 585 + right: 0, 586 + bottom: 0, 587 + backgroundColor: "rgba(0, 0, 0, 0.85)", 588 + display: "flex", 589 + alignItems: "center", 590 + justifyContent: "center", 591 + zIndex: 9999, 592 + backdropFilter: "blur(4px)", 593 + }, 594 + modalContent: { 595 + background: "var(--atproto-color-bg)", 596 + borderRadius: 16, 597 + padding: 0, 598 + maxWidth: 450, 599 + width: "90%", 600 + maxHeight: "80vh", 601 + overflow: "auto", 602 + boxShadow: "0 20px 60px rgba(0, 0, 0, 0.8)", 603 + border: "1px solid var(--atproto-color-border)", 604 + }, 605 + modalHeader: { 606 + display: "flex", 607 + justifyContent: "space-between", 608 + alignItems: "center", 609 + padding: "24px 24px 16px 24px", 610 + borderBottom: "1px solid var(--atproto-color-border)", 611 + }, 612 + modalTitle: { 613 + margin: 0, 614 + fontSize: 20, 615 + fontWeight: 700, 616 + color: "var(--atproto-color-text)", 617 + }, 618 + closeButton: { 619 + background: "transparent", 620 + border: "none", 621 + color: "var(--atproto-color-text-secondary)", 622 + fontSize: 32, 623 + cursor: "pointer", 624 + padding: 0, 625 + width: 32, 626 + height: 32, 627 + display: "flex", 628 + alignItems: "center", 629 + justifyContent: "center", 630 + borderRadius: "50%", 631 + transition: "all 0.2s ease", 632 + lineHeight: 1, 633 + }, 634 + platformList: { 635 + padding: "16px", 636 + display: "flex", 637 + flexDirection: "column", 638 + gap: "8px", 639 + }, 640 + platformItem: { 641 + display: "flex", 642 + alignItems: "center", 643 + gap: "16px", 644 + padding: "16px", 645 + background: "var(--atproto-color-bg-hover)", 646 + borderRadius: 12, 647 + textDecoration: "none", 648 + color: "var(--atproto-color-text)", 649 + transition: "all 0.2s ease", 650 + cursor: "pointer", 651 + border: "1px solid var(--atproto-color-border)", 652 + }, 653 + platformIcon: { 654 + fontSize: 24, 655 + width: 32, 656 + height: 32, 657 + display: "flex", 658 + alignItems: "center", 659 + justifyContent: "center", 660 + }, 661 + platformName: { 662 + flex: 1, 663 + fontSize: 16, 664 + fontWeight: 600, 665 + }, 666 + platformArrow: { 667 + opacity: 0.5, 668 + transition: "opacity 0.2s ease", 669 + }, 670 + notListeningContainer: { 671 + fontFamily: "system-ui, -apple-system, sans-serif", 672 + display: "flex", 673 + flexDirection: "column", 674 + alignItems: "center", 675 + justifyContent: "center", 676 + background: "var(--atproto-color-bg)", 677 + borderRadius: 16, 678 + padding: "80px 40px", 679 + maxWidth: 420, 680 + color: "var(--atproto-color-text-secondary)", 681 + border: "1px solid var(--atproto-color-border)", 682 + textAlign: "center", 683 + }, 684 + notListeningIcon: { 685 + width: 120, 686 + height: 120, 687 + borderRadius: "50%", 688 + background: "var(--atproto-color-bg-elevated)", 689 + display: "flex", 690 + alignItems: "center", 691 + justifyContent: "center", 692 + marginBottom: 24, 693 + color: "var(--atproto-color-text-muted)", 694 + }, 695 + notListeningTitle: { 696 + fontSize: 18, 697 + fontWeight: 600, 698 + color: "var(--atproto-color-text)", 699 + marginBottom: 8, 700 + }, 701 + notListeningSubtitle: { 702 + fontSize: 14, 703 + color: "var(--atproto-color-text-secondary)", 704 + }, 705 + }; 706 + 707 + // Add keyframes and hover styles 708 + if (typeof document !== "undefined") { 709 + const styleId = "teal-status-styles"; 710 + if (!document.getElementById(styleId)) { 711 + const styleElement = document.createElement("style"); 712 + styleElement.id = styleId; 713 + styleElement.textContent = ` 714 + @keyframes spin { 715 + 0% { transform: rotate(0deg); } 716 + 100% { transform: rotate(360deg); } 717 + } 718 + 719 + button[data-teal-listen-button]:hover:not(:disabled), 720 + a[data-teal-listen-button]:hover { 721 + background: var(--atproto-color-bg-pressed) !important; 722 + border-color: var(--atproto-color-border-hover) !important; 723 + transform: translateY(-2px); 724 + } 725 + 726 + button[data-teal-listen-button]:disabled { 727 + opacity: 0.5; 728 + cursor: not-allowed; 729 + } 730 + 731 + button[data-teal-close]:hover { 732 + background: var(--atproto-color-bg-hover) !important; 733 + color: var(--atproto-color-text) !important; 734 + } 735 + 736 + a[data-teal-platform]:hover { 737 + background: var(--atproto-color-bg-pressed) !important; 738 + transform: translateX(4px); 739 + } 740 + 741 + a[data-teal-platform]:hover svg { 742 + opacity: 1 !important; 743 + } 744 + `; 745 + document.head.appendChild(styleElement); 746 + } 747 + } 748 + 749 + export default CurrentlyPlayingRenderer;
+971
lib/renderers/GrainGalleryRenderer.tsx
··· 1 + import React from "react"; 2 + import type { GrainGalleryRecord, GrainPhotoRecord } from "../types/grain"; 3 + import { useBlob } from "../hooks/useBlob"; 4 + import { isBlobWithCdn, extractCidFromBlob } from "../utils/blob"; 5 + 6 + export interface GrainGalleryPhoto { 7 + record: GrainPhotoRecord; 8 + did: string; 9 + rkey: string; 10 + position?: number; 11 + } 12 + 13 + export interface GrainGalleryRendererProps { 14 + gallery: GrainGalleryRecord; 15 + photos: GrainGalleryPhoto[]; 16 + loading: boolean; 17 + error?: Error; 18 + authorHandle?: string; 19 + authorDisplayName?: string; 20 + avatarUrl?: string; 21 + } 22 + 23 + export const GrainGalleryRenderer: React.FC<GrainGalleryRendererProps> = ({ 24 + gallery, 25 + photos, 26 + loading, 27 + error, 28 + authorDisplayName, 29 + authorHandle, 30 + avatarUrl, 31 + }) => { 32 + const [currentPage, setCurrentPage] = React.useState(0); 33 + const [lightboxOpen, setLightboxOpen] = React.useState(false); 34 + const [lightboxPhotoIndex, setLightboxPhotoIndex] = React.useState(0); 35 + 36 + const createdDate = new Date(gallery.createdAt); 37 + const created = createdDate.toLocaleString(undefined, { 38 + dateStyle: "medium", 39 + timeStyle: "short", 40 + }); 41 + 42 + const primaryName = authorDisplayName || authorHandle || "โ€ฆ"; 43 + 44 + // Memoize sorted photos to prevent re-sorting on every render 45 + const sortedPhotos = React.useMemo( 46 + () => [...photos].sort((a, b) => (a.position ?? 0) - (b.position ?? 0)), 47 + [photos] 48 + ); 49 + 50 + // Open lightbox 51 + const openLightbox = React.useCallback((photoIndex: number) => { 52 + setLightboxPhotoIndex(photoIndex); 53 + setLightboxOpen(true); 54 + }, []); 55 + 56 + // Close lightbox 57 + const closeLightbox = React.useCallback(() => { 58 + setLightboxOpen(false); 59 + }, []); 60 + 61 + // Navigate lightbox 62 + const goToNextPhoto = React.useCallback(() => { 63 + setLightboxPhotoIndex((prev) => (prev + 1) % sortedPhotos.length); 64 + }, [sortedPhotos.length]); 65 + 66 + const goToPrevPhoto = React.useCallback(() => { 67 + setLightboxPhotoIndex((prev) => (prev - 1 + sortedPhotos.length) % sortedPhotos.length); 68 + }, [sortedPhotos.length]); 69 + 70 + // Keyboard navigation 71 + React.useEffect(() => { 72 + if (!lightboxOpen) return; 73 + 74 + const handleKeyDown = (e: KeyboardEvent) => { 75 + if (e.key === "Escape") closeLightbox(); 76 + if (e.key === "ArrowLeft") goToPrevPhoto(); 77 + if (e.key === "ArrowRight") goToNextPhoto(); 78 + }; 79 + 80 + window.addEventListener("keydown", handleKeyDown); 81 + return () => window.removeEventListener("keydown", handleKeyDown); 82 + }, [lightboxOpen, closeLightbox, goToPrevPhoto, goToNextPhoto]); 83 + 84 + const isSinglePhoto = sortedPhotos.length === 1; 85 + 86 + // Preload all photos to avoid loading states when paginating 87 + usePreloadAllPhotos(sortedPhotos); 88 + 89 + // Reset to first page when photos change 90 + React.useEffect(() => { 91 + setCurrentPage(0); 92 + }, [sortedPhotos.length]); 93 + 94 + // Memoize pagination calculations with intelligent photo count per page 95 + const paginationData = React.useMemo(() => { 96 + const pages = calculatePages(sortedPhotos); 97 + const totalPages = pages.length; 98 + const visiblePhotos = pages[currentPage] || []; 99 + const hasMultiplePages = totalPages > 1; 100 + const layoutPhotos = calculateLayout(visiblePhotos); 101 + 102 + return { 103 + pages, 104 + totalPages, 105 + visiblePhotos, 106 + hasMultiplePages, 107 + layoutPhotos, 108 + }; 109 + }, [sortedPhotos, currentPage]); 110 + 111 + const { totalPages, hasMultiplePages, layoutPhotos } = paginationData; 112 + 113 + // Memoize navigation handlers to prevent re-creation 114 + const goToNextPage = React.useCallback(() => { 115 + setCurrentPage((prev) => (prev + 1) % totalPages); 116 + }, [totalPages]); 117 + 118 + const goToPrevPage = React.useCallback(() => { 119 + setCurrentPage((prev) => (prev - 1 + totalPages) % totalPages); 120 + }, [totalPages]); 121 + 122 + if (error) { 123 + return ( 124 + <div role="alert" style={{ padding: 8, color: "crimson" }}> 125 + Failed to load gallery. 126 + </div> 127 + ); 128 + } 129 + 130 + if (loading && photos.length === 0) { 131 + return <div role="status" aria-live="polite" style={{ padding: 8 }}>Loading galleryโ€ฆ</div>; 132 + } 133 + 134 + return ( 135 + <> 136 + {/* Hidden preload elements for all photos */} 137 + <div style={{ display: "none" }} aria-hidden> 138 + {sortedPhotos.map((photo) => ( 139 + <PreloadPhoto key={`${photo.did}-${photo.rkey}-preload`} photo={photo} /> 140 + ))} 141 + </div> 142 + 143 + {/* Lightbox */} 144 + {lightboxOpen && ( 145 + <Lightbox 146 + photo={sortedPhotos[lightboxPhotoIndex]} 147 + photoIndex={lightboxPhotoIndex} 148 + totalPhotos={sortedPhotos.length} 149 + onClose={closeLightbox} 150 + onNext={goToNextPhoto} 151 + onPrev={goToPrevPhoto} 152 + /> 153 + )} 154 + 155 + <article style={styles.card}> 156 + <header style={styles.header}> 157 + {avatarUrl ? ( 158 + <img src={avatarUrl} alt={`${authorDisplayName || authorHandle || 'User'}'s profile picture`} style={styles.avatarImg} /> 159 + ) : ( 160 + <div style={styles.avatarPlaceholder} aria-hidden /> 161 + )} 162 + <div style={styles.authorInfo}> 163 + <strong style={styles.displayName}>{primaryName}</strong> 164 + {authorHandle && ( 165 + <span 166 + style={{ 167 + ...styles.handle, 168 + color: `var(--atproto-color-text-secondary)`, 169 + }} 170 + > 171 + @{authorHandle} 172 + </span> 173 + )} 174 + </div> 175 + </header> 176 + 177 + <div style={styles.galleryInfo}> 178 + <h2 179 + style={{ 180 + ...styles.title, 181 + color: `var(--atproto-color-text)`, 182 + }} 183 + > 184 + {gallery.title} 185 + </h2> 186 + {gallery.description && ( 187 + <p 188 + style={{ 189 + ...styles.description, 190 + color: `var(--atproto-color-text-secondary)`, 191 + }} 192 + > 193 + {gallery.description} 194 + </p> 195 + )} 196 + </div> 197 + 198 + {isSinglePhoto ? ( 199 + <div style={styles.singlePhotoContainer}> 200 + <GalleryPhotoItem 201 + key={`${sortedPhotos[0].did}-${sortedPhotos[0].rkey}`} 202 + photo={sortedPhotos[0]} 203 + isSingle={true} 204 + onClick={() => openLightbox(0)} 205 + /> 206 + </div> 207 + ) : ( 208 + <div style={styles.carouselContainer}> 209 + {hasMultiplePages && currentPage > 0 && ( 210 + <button 211 + onClick={goToPrevPage} 212 + onMouseEnter={(e) => (e.currentTarget.style.opacity = "1")} 213 + onMouseLeave={(e) => (e.currentTarget.style.opacity = "0.7")} 214 + style={{ 215 + ...styles.navButton, 216 + ...styles.navButtonLeft, 217 + color: "white", 218 + background: "rgba(0, 0, 0, 0.5)", 219 + boxShadow: "0 2px 4px rgba(0, 0, 0, 0.1)", 220 + }} 221 + aria-label="Previous photos" 222 + > 223 + โ€น 224 + </button> 225 + )} 226 + <div style={styles.photosGrid}> 227 + {layoutPhotos.map((item) => { 228 + const photoIndex = sortedPhotos.findIndex(p => p.did === item.did && p.rkey === item.rkey); 229 + return ( 230 + <GalleryPhotoItem 231 + key={`${item.did}-${item.rkey}`} 232 + photo={item} 233 + isSingle={false} 234 + span={item.span} 235 + onClick={() => openLightbox(photoIndex)} 236 + /> 237 + ); 238 + })} 239 + </div> 240 + {hasMultiplePages && currentPage < totalPages - 1 && ( 241 + <button 242 + onClick={goToNextPage} 243 + onMouseEnter={(e) => (e.currentTarget.style.opacity = "1")} 244 + onMouseLeave={(e) => (e.currentTarget.style.opacity = "0.7")} 245 + style={{ 246 + ...styles.navButton, 247 + ...styles.navButtonRight, 248 + color: "white", 249 + background: "rgba(0, 0, 0, 0.5)", 250 + boxShadow: "0 2px 4px rgba(0, 0, 0, 0.1)", 251 + }} 252 + aria-label="Next photos" 253 + > 254 + โ€บ 255 + </button> 256 + )} 257 + </div> 258 + )} 259 + 260 + <footer style={styles.footer}> 261 + <time 262 + style={{ 263 + ...styles.time, 264 + color: `var(--atproto-color-text-muted)`, 265 + }} 266 + dateTime={gallery.createdAt} 267 + > 268 + {created} 269 + </time> 270 + {hasMultiplePages && !isSinglePhoto && ( 271 + <div style={styles.paginationDots}> 272 + {Array.from({ length: totalPages }, (_, i) => ( 273 + <button 274 + key={i} 275 + onClick={() => setCurrentPage(i)} 276 + style={{ 277 + ...styles.paginationDot, 278 + background: i === currentPage 279 + ? `var(--atproto-color-text)` 280 + : `var(--atproto-color-border)`, 281 + }} 282 + aria-label={`Go to page ${i + 1}`} 283 + aria-current={i === currentPage ? "page" : undefined} 284 + /> 285 + ))} 286 + </div> 287 + )} 288 + </footer> 289 + </article> 290 + </> 291 + ); 292 + }; 293 + 294 + // Component to preload a single photo's blob 295 + const PreloadPhoto: React.FC<{ photo: GrainGalleryPhoto }> = ({ photo }) => { 296 + const photoBlob = photo.record.photo; 297 + const cdnUrl = isBlobWithCdn(photoBlob) ? photoBlob.cdnUrl : undefined; 298 + const cid = cdnUrl ? undefined : extractCidFromBlob(photoBlob); 299 + 300 + // Trigger blob loading via the hook 301 + useBlob(photo.did, cid); 302 + 303 + // Preload CDN images via Image element 304 + React.useEffect(() => { 305 + if (cdnUrl) { 306 + const img = new Image(); 307 + img.src = cdnUrl; 308 + } 309 + }, [cdnUrl]); 310 + 311 + return null; 312 + }; 313 + 314 + // Hook to preload all photos (CDN-based) 315 + const usePreloadAllPhotos = (photos: GrainGalleryPhoto[]) => { 316 + React.useEffect(() => { 317 + // Preload CDN images 318 + photos.forEach((photo) => { 319 + const photoBlob = photo.record.photo; 320 + const cdnUrl = isBlobWithCdn(photoBlob) ? photoBlob.cdnUrl : undefined; 321 + 322 + if (cdnUrl) { 323 + const img = new Image(); 324 + img.src = cdnUrl; 325 + } 326 + }); 327 + }, [photos]); 328 + }; 329 + 330 + // Calculate pages with intelligent photo count (1, 2, or 3) 331 + // Only includes multiple photos when they fit well together 332 + const calculatePages = (photos: GrainGalleryPhoto[]): GrainGalleryPhoto[][] => { 333 + if (photos.length === 0) return []; 334 + if (photos.length === 1) return [[photos[0]]]; 335 + 336 + const pages: GrainGalleryPhoto[][] = []; 337 + let i = 0; 338 + 339 + while (i < photos.length) { 340 + const remaining = photos.length - i; 341 + 342 + // Only one photo left - use it 343 + if (remaining === 1) { 344 + pages.push([photos[i]]); 345 + break; 346 + } 347 + 348 + // Check if next 3 photos can fit well together 349 + if (remaining >= 3) { 350 + const nextThree = photos.slice(i, i + 3); 351 + if (canFitThreePhotos(nextThree)) { 352 + pages.push(nextThree); 353 + i += 3; 354 + continue; 355 + } 356 + } 357 + 358 + // Check if next 2 photos can fit well together 359 + if (remaining >= 2) { 360 + const nextTwo = photos.slice(i, i + 2); 361 + if (canFitTwoPhotos(nextTwo)) { 362 + pages.push(nextTwo); 363 + i += 2; 364 + continue; 365 + } 366 + } 367 + 368 + // Photos don't fit well together, use 1 per page 369 + pages.push([photos[i]]); 370 + i += 1; 371 + } 372 + 373 + return pages; 374 + }; 375 + 376 + // Helper functions for aspect ratio classification 377 + const isPortrait = (ratio: number) => ratio < 0.8; 378 + const isLandscape = (ratio: number) => ratio > 1.2; 379 + const isSquarish = (ratio: number) => ratio >= 0.8 && ratio <= 1.2; 380 + 381 + // Determine if 2 photos can fit well together side by side 382 + const canFitTwoPhotos = (photos: GrainGalleryPhoto[]): boolean => { 383 + if (photos.length !== 2) return false; 384 + 385 + const ratios = photos.map((p) => { 386 + const ar = p.record.aspectRatio; 387 + return ar ? ar.width / ar.height : 1; 388 + }); 389 + 390 + const [r1, r2] = ratios; 391 + 392 + // Two portraits side by side don't work well (too narrow) 393 + if (isPortrait(r1) && isPortrait(r2)) return false; 394 + 395 + // Portrait + landscape/square creates awkward layout 396 + if (isPortrait(r1) && !isPortrait(r2)) return false; 397 + if (!isPortrait(r1) && isPortrait(r2)) return false; 398 + 399 + // Two landscape or two squarish photos work well 400 + if ((isLandscape(r1) || isSquarish(r1)) && (isLandscape(r2) || isSquarish(r2))) { 401 + return true; 402 + } 403 + 404 + // Default to not fitting 405 + return false; 406 + }; 407 + 408 + // Determine if 3 photos can fit well together in a layout 409 + const canFitThreePhotos = (photos: GrainGalleryPhoto[]): boolean => { 410 + if (photos.length !== 3) return false; 411 + 412 + const ratios = photos.map((p) => { 413 + const ar = p.record.aspectRatio; 414 + return ar ? ar.width / ar.height : 1; 415 + }); 416 + 417 + const [r1, r2, r3] = ratios; 418 + 419 + // Good pattern: one portrait, two landscape/square 420 + if (isPortrait(r1) && !isPortrait(r2) && !isPortrait(r3)) return true; 421 + if (isPortrait(r3) && !isPortrait(r1) && !isPortrait(r2)) return true; 422 + 423 + // Good pattern: all similar aspect ratios (all landscape or all squarish) 424 + const allLandscape = ratios.every(isLandscape); 425 + const allSquarish = ratios.every(isSquarish); 426 + if (allLandscape || allSquarish) return true; 427 + 428 + // Three portraits in a row can work 429 + const allPortrait = ratios.every(isPortrait); 430 + if (allPortrait) return true; 431 + 432 + // Otherwise don't fit 3 together 433 + return false; 434 + }; 435 + 436 + // Layout calculator for intelligent photo grid arrangement 437 + const calculateLayout = (photos: GrainGalleryPhoto[]) => { 438 + if (photos.length === 0) return []; 439 + if (photos.length === 1) { 440 + return [{ ...photos[0], span: { row: 2, col: 2 } }]; 441 + } 442 + 443 + const photosWithRatios = photos.map((photo) => { 444 + const ratio = photo.record.aspectRatio 445 + ? photo.record.aspectRatio.width / photo.record.aspectRatio.height 446 + : 1; 447 + return { 448 + ...photo, 449 + ratio, 450 + isPortrait: isPortrait(ratio), 451 + isLandscape: isLandscape(ratio) 452 + }; 453 + }); 454 + 455 + // For 2 photos: side by side 456 + if (photos.length === 2) { 457 + return photosWithRatios.map((p) => ({ ...p, span: { row: 2, col: 1 } })); 458 + } 459 + 460 + // For 3 photos: try to create a balanced layout 461 + if (photos.length === 3) { 462 + const [p1, p2, p3] = photosWithRatios; 463 + 464 + // Pattern 1: One tall on left, two stacked on right 465 + if (p1.isPortrait && !p2.isPortrait && !p3.isPortrait) { 466 + return [ 467 + { ...p1, span: { row: 2, col: 1 } }, 468 + { ...p2, span: { row: 1, col: 1 } }, 469 + { ...p3, span: { row: 1, col: 1 } }, 470 + ]; 471 + } 472 + 473 + // Pattern 2: Two stacked on left, one tall on right 474 + if (!p1.isPortrait && !p2.isPortrait && p3.isPortrait) { 475 + return [ 476 + { ...p1, span: { row: 1, col: 1 } }, 477 + { ...p2, span: { row: 1, col: 1 } }, 478 + { ...p3, span: { row: 2, col: 1 } }, 479 + ]; 480 + } 481 + 482 + // Pattern 3: All in a row 483 + const allPortrait = photosWithRatios.every((p) => p.isPortrait); 484 + if (allPortrait) { 485 + // All portraits: display in a row with smaller cells 486 + return photosWithRatios.map((p) => ({ ...p, span: { row: 1, col: 1 } })); 487 + } 488 + 489 + // Default: All three in a row 490 + return photosWithRatios.map((p) => ({ ...p, span: { row: 1, col: 1 } })); 491 + } 492 + 493 + return photosWithRatios.map((p) => ({ ...p, span: { row: 1, col: 1 } })); 494 + }; 495 + 496 + // Lightbox component for fullscreen image viewing 497 + const Lightbox: React.FC<{ 498 + photo: GrainGalleryPhoto; 499 + photoIndex: number; 500 + totalPhotos: number; 501 + onClose: () => void; 502 + onNext: () => void; 503 + onPrev: () => void; 504 + }> = ({ photo, photoIndex, totalPhotos, onClose, onNext, onPrev }) => { 505 + const photoBlob = photo.record.photo; 506 + const cdnUrl = isBlobWithCdn(photoBlob) ? photoBlob.cdnUrl : undefined; 507 + const cid = cdnUrl ? undefined : extractCidFromBlob(photoBlob); 508 + const { url: urlFromBlob, loading: photoLoading, error: photoError } = useBlob(photo.did, cid); 509 + const url = cdnUrl || urlFromBlob; 510 + const alt = photo.record.alt?.trim() || "grain.social photo"; 511 + 512 + return ( 513 + <div 514 + role="dialog" 515 + aria-modal="true" 516 + aria-label={`Photo ${photoIndex + 1} of ${totalPhotos}`} 517 + style={{ 518 + position: "fixed", 519 + top: 0, 520 + left: 0, 521 + right: 0, 522 + bottom: 0, 523 + background: "rgba(0, 0, 0, 0.95)", 524 + zIndex: 9999, 525 + display: "flex", 526 + alignItems: "center", 527 + justifyContent: "center", 528 + padding: 20, 529 + }} 530 + onClick={onClose} 531 + > 532 + {/* Close button */} 533 + <button 534 + onClick={onClose} 535 + style={{ 536 + position: "absolute", 537 + top: 20, 538 + right: 20, 539 + width: 40, 540 + height: 40, 541 + border: "none", 542 + borderRadius: "50%", 543 + background: "rgba(255, 255, 255, 0.1)", 544 + color: "white", 545 + fontSize: 24, 546 + cursor: "pointer", 547 + display: "flex", 548 + alignItems: "center", 549 + justifyContent: "center", 550 + transition: "background 200ms ease", 551 + }} 552 + onMouseEnter={(e) => (e.currentTarget.style.background = "rgba(255, 255, 255, 0.2)")} 553 + onMouseLeave={(e) => (e.currentTarget.style.background = "rgba(255, 255, 255, 0.1)")} 554 + aria-label="Close lightbox" 555 + > 556 + ร— 557 + </button> 558 + 559 + {/* Previous button */} 560 + {totalPhotos > 1 && ( 561 + <button 562 + onClick={(e) => { 563 + e.stopPropagation(); 564 + onPrev(); 565 + }} 566 + style={{ 567 + position: "absolute", 568 + left: 20, 569 + top: "50%", 570 + transform: "translateY(-50%)", 571 + width: 50, 572 + height: 50, 573 + border: "none", 574 + borderRadius: "50%", 575 + background: "rgba(255, 255, 255, 0.1)", 576 + color: "white", 577 + fontSize: 24, 578 + cursor: "pointer", 579 + display: "flex", 580 + alignItems: "center", 581 + justifyContent: "center", 582 + transition: "background 200ms ease", 583 + }} 584 + onMouseEnter={(e) => (e.currentTarget.style.background = "rgba(255, 255, 255, 0.2)")} 585 + onMouseLeave={(e) => (e.currentTarget.style.background = "rgba(255, 255, 255, 0.1)")} 586 + aria-label={`Previous photo (${photoIndex} of ${totalPhotos})`} 587 + > 588 + โ€น 589 + </button> 590 + )} 591 + 592 + {/* Next button */} 593 + {totalPhotos > 1 && ( 594 + <button 595 + onClick={(e) => { 596 + e.stopPropagation(); 597 + onNext(); 598 + }} 599 + style={{ 600 + position: "absolute", 601 + right: 20, 602 + top: "50%", 603 + transform: "translateY(-50%)", 604 + width: 50, 605 + height: 50, 606 + border: "none", 607 + borderRadius: "50%", 608 + background: "rgba(255, 255, 255, 0.1)", 609 + color: "white", 610 + fontSize: 24, 611 + cursor: "pointer", 612 + display: "flex", 613 + alignItems: "center", 614 + justifyContent: "center", 615 + transition: "background 200ms ease", 616 + }} 617 + onMouseEnter={(e) => (e.currentTarget.style.background = "rgba(255, 255, 255, 0.2)")} 618 + onMouseLeave={(e) => (e.currentTarget.style.background = "rgba(255, 255, 255, 0.1)")} 619 + aria-label={`Next photo (${photoIndex + 2} of ${totalPhotos})`} 620 + > 621 + โ€บ 622 + </button> 623 + )} 624 + 625 + {/* Image */} 626 + <div 627 + style={{ 628 + maxWidth: "90vw", 629 + maxHeight: "90vh", 630 + display: "flex", 631 + alignItems: "center", 632 + justifyContent: "center", 633 + }} 634 + onClick={(e) => e.stopPropagation()} 635 + > 636 + {url ? ( 637 + <img 638 + src={url} 639 + alt={alt} 640 + style={{ 641 + maxWidth: "100%", 642 + maxHeight: "100%", 643 + objectFit: "contain", 644 + borderRadius: 8, 645 + }} 646 + /> 647 + ) : ( 648 + <div 649 + style={{ 650 + color: "white", 651 + fontSize: 16, 652 + textAlign: "center", 653 + }} 654 + > 655 + {photoLoading ? "Loadingโ€ฆ" : photoError ? "Failed to load" : "Unavailable"} 656 + </div> 657 + )} 658 + </div> 659 + 660 + {/* Photo counter */} 661 + {totalPhotos > 1 && ( 662 + <div 663 + style={{ 664 + position: "absolute", 665 + bottom: 20, 666 + left: "50%", 667 + transform: "translateX(-50%)", 668 + color: "white", 669 + fontSize: 14, 670 + background: "rgba(0, 0, 0, 0.5)", 671 + padding: "8px 16px", 672 + borderRadius: 20, 673 + }} 674 + > 675 + {photoIndex + 1} / {totalPhotos} 676 + </div> 677 + )} 678 + </div> 679 + ); 680 + }; 681 + 682 + const GalleryPhotoItem: React.FC<{ 683 + photo: GrainGalleryPhoto; 684 + isSingle: boolean; 685 + span?: { row: number; col: number }; 686 + onClick?: () => void; 687 + }> = ({ photo, isSingle, span, onClick }) => { 688 + const [showAltText, setShowAltText] = React.useState(false); 689 + const photoBlob = photo.record.photo; 690 + const cdnUrl = isBlobWithCdn(photoBlob) ? photoBlob.cdnUrl : undefined; 691 + const cid = cdnUrl ? undefined : extractCidFromBlob(photoBlob); 692 + const { url: urlFromBlob, loading: photoLoading, error: photoError } = useBlob(photo.did, cid); 693 + const url = cdnUrl || urlFromBlob; 694 + const alt = photo.record.alt?.trim() || "grain.social photo"; 695 + const hasAlt = photo.record.alt && photo.record.alt.trim().length > 0; 696 + 697 + const aspect = 698 + photo.record.aspectRatio && photo.record.aspectRatio.height > 0 699 + ? `${photo.record.aspectRatio.width} / ${photo.record.aspectRatio.height}` 700 + : undefined; 701 + 702 + const gridItemStyle = span 703 + ? { 704 + gridRow: `span ${span.row}`, 705 + gridColumn: `span ${span.col}`, 706 + } 707 + : {}; 708 + 709 + return ( 710 + <figure style={{ ...(isSingle ? styles.singlePhotoItem : styles.photoItem), ...gridItemStyle }}> 711 + <button 712 + onClick={onClick} 713 + aria-label={hasAlt ? `View photo: ${alt}` : "View photo"} 714 + style={{ 715 + ...(isSingle ? styles.singlePhotoMedia : styles.photoContainer), 716 + background: `var(--atproto-color-image-bg)`, 717 + // Only apply aspect ratio for single photos; grid photos fill their cells 718 + ...(isSingle && aspect ? { aspectRatio: aspect } : {}), 719 + cursor: onClick ? "pointer" : "default", 720 + border: "none", 721 + padding: 0, 722 + display: "block", 723 + width: "100%", 724 + }} 725 + > 726 + {url ? ( 727 + <img src={url} alt={alt} style={isSingle ? styles.photo : styles.photoGrid} /> 728 + ) : ( 729 + <div 730 + style={{ 731 + ...styles.placeholder, 732 + color: `var(--atproto-color-text-muted)`, 733 + }} 734 + > 735 + {photoLoading 736 + ? "Loadingโ€ฆ" 737 + : photoError 738 + ? "Failed to load" 739 + : "Unavailable"} 740 + </div> 741 + )} 742 + {hasAlt && ( 743 + <button 744 + onClick={(e) => { 745 + e.stopPropagation(); 746 + setShowAltText(!showAltText); 747 + }} 748 + style={{ 749 + ...styles.altBadge, 750 + background: showAltText 751 + ? `var(--atproto-color-text)` 752 + : `var(--atproto-color-bg-secondary)`, 753 + color: showAltText 754 + ? `var(--atproto-color-bg)` 755 + : `var(--atproto-color-text)`, 756 + }} 757 + title="Toggle alt text" 758 + aria-label="Toggle alt text" 759 + aria-pressed={showAltText} 760 + > 761 + ALT 762 + </button> 763 + )} 764 + </button> 765 + {hasAlt && showAltText && ( 766 + <figcaption 767 + style={{ 768 + ...styles.caption, 769 + color: `var(--atproto-color-text-secondary)`, 770 + }} 771 + > 772 + {photo.record.alt} 773 + </figcaption> 774 + )} 775 + </figure> 776 + ); 777 + }; 778 + 779 + const styles: Record<string, React.CSSProperties> = { 780 + card: { 781 + borderRadius: 12, 782 + border: `1px solid var(--atproto-color-border)`, 783 + background: `var(--atproto-color-bg)`, 784 + color: `var(--atproto-color-text)`, 785 + fontFamily: "system-ui, sans-serif", 786 + display: "flex", 787 + flexDirection: "column", 788 + maxWidth: 600, 789 + transition: 790 + "background-color 180ms ease, border-color 180ms ease, color 180ms ease", 791 + overflow: "hidden", 792 + }, 793 + header: { 794 + display: "flex", 795 + alignItems: "center", 796 + gap: 12, 797 + padding: 12, 798 + paddingBottom: 0, 799 + }, 800 + avatarPlaceholder: { 801 + width: 32, 802 + height: 32, 803 + borderRadius: "50%", 804 + background: `var(--atproto-color-border)`, 805 + }, 806 + avatarImg: { 807 + width: 32, 808 + height: 32, 809 + borderRadius: "50%", 810 + objectFit: "cover", 811 + }, 812 + authorInfo: { 813 + display: "flex", 814 + flexDirection: "column", 815 + gap: 2, 816 + }, 817 + displayName: { 818 + fontSize: 14, 819 + fontWeight: 600, 820 + }, 821 + handle: { 822 + fontSize: 12, 823 + }, 824 + galleryInfo: { 825 + padding: 12, 826 + paddingBottom: 8, 827 + }, 828 + title: { 829 + margin: 0, 830 + fontSize: 18, 831 + fontWeight: 600, 832 + marginBottom: 4, 833 + }, 834 + description: { 835 + margin: 0, 836 + fontSize: 14, 837 + lineHeight: 1.4, 838 + whiteSpace: "pre-wrap", 839 + }, 840 + singlePhotoContainer: { 841 + padding: 0, 842 + }, 843 + carouselContainer: { 844 + position: "relative", 845 + padding: 4, 846 + }, 847 + photosGrid: { 848 + display: "grid", 849 + gridTemplateColumns: "repeat(2, 1fr)", 850 + gridTemplateRows: "repeat(2, 1fr)", 851 + gap: 4, 852 + minHeight: 400, 853 + }, 854 + navButton: { 855 + position: "absolute", 856 + top: "50%", 857 + transform: "translateY(-50%)", 858 + width: 28, 859 + height: 28, 860 + border: "none", 861 + borderRadius: "50%", 862 + fontSize: 18, 863 + fontWeight: "600", 864 + cursor: "pointer", 865 + display: "flex", 866 + alignItems: "center", 867 + justifyContent: "center", 868 + zIndex: 10, 869 + transition: "opacity 150ms ease", 870 + userSelect: "none", 871 + opacity: 0.7, 872 + }, 873 + navButtonLeft: { 874 + left: 8, 875 + }, 876 + navButtonRight: { 877 + right: 8, 878 + }, 879 + photoItem: { 880 + margin: 0, 881 + display: "flex", 882 + flexDirection: "column", 883 + gap: 4, 884 + }, 885 + singlePhotoItem: { 886 + margin: 0, 887 + display: "flex", 888 + flexDirection: "column", 889 + gap: 8, 890 + }, 891 + photoContainer: { 892 + position: "relative", 893 + width: "100%", 894 + height: "100%", 895 + overflow: "hidden", 896 + borderRadius: 4, 897 + }, 898 + singlePhotoMedia: { 899 + position: "relative", 900 + width: "100%", 901 + overflow: "hidden", 902 + borderRadius: 0, 903 + }, 904 + photo: { 905 + width: "100%", 906 + height: "100%", 907 + objectFit: "cover", 908 + display: "block", 909 + }, 910 + photoGrid: { 911 + width: "100%", 912 + height: "100%", 913 + objectFit: "cover", 914 + display: "block", 915 + }, 916 + placeholder: { 917 + display: "flex", 918 + alignItems: "center", 919 + justifyContent: "center", 920 + width: "100%", 921 + height: "100%", 922 + minHeight: 100, 923 + fontSize: 12, 924 + }, 925 + caption: { 926 + fontSize: 12, 927 + lineHeight: 1.3, 928 + padding: "0 12px 8px", 929 + }, 930 + altBadge: { 931 + position: "absolute", 932 + bottom: 8, 933 + right: 8, 934 + padding: "4px 8px", 935 + fontSize: 10, 936 + fontWeight: 600, 937 + letterSpacing: "0.5px", 938 + border: "none", 939 + borderRadius: 4, 940 + cursor: "pointer", 941 + transition: "background 150ms ease, color 150ms ease", 942 + fontFamily: "system-ui, sans-serif", 943 + }, 944 + footer: { 945 + padding: 12, 946 + paddingTop: 8, 947 + display: "flex", 948 + justifyContent: "space-between", 949 + alignItems: "center", 950 + }, 951 + time: { 952 + fontSize: 11, 953 + }, 954 + paginationDots: { 955 + display: "flex", 956 + gap: 6, 957 + alignItems: "center", 958 + }, 959 + paginationDot: { 960 + width: 6, 961 + height: 6, 962 + borderRadius: "50%", 963 + border: "none", 964 + padding: 0, 965 + cursor: "pointer", 966 + transition: "background 200ms ease, transform 150ms ease", 967 + flexShrink: 0, 968 + }, 969 + }; 970 + 971 + export default GrainGalleryRenderer;
+80 -336
lib/renderers/LeafletDocumentRenderer.tsx
··· 1 1 import React, { useMemo, useRef } from "react"; 2 - import { 3 - useColorScheme, 4 - type ColorSchemePreference, 5 - } from "../hooks/useColorScheme"; 6 2 import { useDidResolution } from "../hooks/useDidResolution"; 7 3 import { useBlob } from "../hooks/useBlob"; 4 + import { useAtProto } from "../providers/AtProtoProvider"; 8 5 import { 9 6 parseAtUri, 10 7 formatDidForLabel, ··· 39 36 record: LeafletDocumentRecord; 40 37 loading: boolean; 41 38 error?: Error; 42 - colorScheme?: ColorSchemePreference; 43 39 did: string; 44 40 rkey: string; 45 41 canonicalUrl?: string; ··· 53 49 record, 54 50 loading, 55 51 error, 56 - colorScheme = "system", 57 52 did, 58 53 rkey, 59 54 canonicalUrl, 60 55 publicationBaseUrl, 61 56 publicationRecord, 62 57 }) => { 63 - const scheme = useColorScheme(colorScheme); 64 - const palette = scheme === "dark" ? theme.dark : theme.light; 58 + const { blueskyAppBaseUrl } = useAtProto(); 65 59 const authorDid = record.author?.startsWith("did:") 66 60 ? record.author 67 61 : undefined; ··· 86 80 : undefined); 87 81 const authorLabel = resolvedPublicationLabel ?? fallbackAuthorLabel; 88 82 const authorHref = publicationUri 89 - ? `https://bsky.app/profile/${publicationUri.did}` 83 + ? `${blueskyAppBaseUrl}/profile/${publicationUri.did}` 90 84 : undefined; 91 85 92 86 if (error) ··· 113 107 timeStyle: "short", 114 108 }) 115 109 : undefined; 116 - const fallbackLeafletUrl = `https://bsky.app/leaflet/${encodeURIComponent(did)}/${encodeURIComponent(rkey)}`; 110 + const fallbackLeafletUrl = `${blueskyAppBaseUrl}/leaflet/${encodeURIComponent(did)}/${encodeURIComponent(rkey)}`; 117 111 const publicationRoot = 118 112 publicationBaseUrl ?? publicationRecord?.base_path ?? undefined; 119 113 const resolvedPublicationRoot = publicationRoot ··· 125 119 publicationLeafletUrl ?? 126 120 postUrl ?? 127 121 (publicationUri 128 - ? `https://bsky.app/profile/${publicationUri.did}` 122 + ? `${blueskyAppBaseUrl}/profile/${publicationUri.did}` 129 123 : undefined) ?? 130 124 fallbackLeafletUrl; 131 125 ··· 136 130 href={authorHref} 137 131 target="_blank" 138 132 rel="noopener noreferrer" 139 - style={palette.metaLink} 133 + style={{ color: `var(--atproto-color-link)`, textDecoration: "none" }} 140 134 > 141 135 {authorLabel} 142 136 </a> ··· 155 149 href={resolvedPublicationRoot} 156 150 target="_blank" 157 151 rel="noopener noreferrer" 158 - style={palette.metaLink} 152 + style={{ color: `var(--atproto-color-link)`, textDecoration: "none" }} 159 153 > 160 154 {resolvedPublicationRoot.replace(/^https?:\/\//, "")} 161 155 </a>, ··· 167 161 href={viewUrl} 168 162 target="_blank" 169 163 rel="noopener noreferrer" 170 - style={palette.metaLink} 164 + style={{ color: `var(--atproto-color-link)`, textDecoration: "none" }} 171 165 > 172 166 View source 173 167 </a>, ··· 175 169 } 176 170 177 171 return ( 178 - <article style={{ ...base.container, ...palette.container }}> 179 - <header style={{ ...base.header, ...palette.header }}> 172 + <article style={{ ...base.container, background: `var(--atproto-color-bg)`, borderWidth: "1px", borderStyle: "solid", borderColor: `var(--atproto-color-border)`, color: `var(--atproto-color-text)` }}> 173 + <header style={{ ...base.header }}> 180 174 <div style={base.headerContent}> 181 - <h1 style={{ ...base.title, ...palette.title }}> 175 + <h1 style={{ ...base.title, color: `var(--atproto-color-text)` }}> 182 176 {record.title} 183 177 </h1> 184 178 {record.description && ( 185 - <p style={{ ...base.subtitle, ...palette.subtitle }}> 179 + <p style={{ ...base.subtitle, color: `var(--atproto-color-text-secondary)` }}> 186 180 {record.description} 187 181 </p> 188 182 )} 189 183 </div> 190 - <div style={{ ...base.meta, ...palette.meta }}> 184 + <div style={{ ...base.meta, color: `var(--atproto-color-text-secondary)` }}> 191 185 {metaItems.map((item, idx) => ( 192 186 <React.Fragment key={`meta-${idx}`}> 193 187 {idx > 0 && ( 194 - <span style={palette.metaSeparator}>โ€ข</span> 188 + <span style={{ margin: "0 4px" }}>โ€ข</span> 195 189 )} 196 190 {item} 197 191 </React.Fragment> ··· 204 198 key={`page-${pageIndex}`} 205 199 page={page} 206 200 documentDid={did} 207 - colorScheme={scheme} 208 201 /> 209 202 ))} 210 203 </div> ··· 215 208 const LeafletPageRenderer: React.FC<{ 216 209 page: LeafletLinearDocumentPage; 217 210 documentDid: string; 218 - colorScheme: "light" | "dark"; 219 - }> = ({ page, documentDid, colorScheme }) => { 211 + }> = ({ page, documentDid }) => { 220 212 if (!page.blocks?.length) return null; 221 213 return ( 222 214 <div style={base.page}> ··· 225 217 key={`block-${idx}`} 226 218 wrapper={blockWrapper} 227 219 documentDid={documentDid} 228 - colorScheme={colorScheme} 229 220 isFirst={idx === 0} 230 221 /> 231 222 ))} ··· 236 227 interface LeafletBlockRendererProps { 237 228 wrapper: LeafletLinearDocumentBlock; 238 229 documentDid: string; 239 - colorScheme: "light" | "dark"; 240 230 isFirst?: boolean; 241 231 } 242 232 243 233 const LeafletBlockRenderer: React.FC<LeafletBlockRendererProps> = ({ 244 234 wrapper, 245 235 documentDid, 246 - colorScheme, 247 236 isFirst, 248 237 }) => { 249 238 const block = wrapper.block; ··· 258 247 <LeafletHeaderBlockView 259 248 block={block} 260 249 alignment={alignment} 261 - colorScheme={colorScheme} 262 250 isFirst={isFirst} 263 251 /> 264 252 ); ··· 267 255 <LeafletBlockquoteBlockView 268 256 block={block} 269 257 alignment={alignment} 270 - colorScheme={colorScheme} 271 258 isFirst={isFirst} 272 259 /> 273 260 ); ··· 277 264 block={block} 278 265 alignment={alignment} 279 266 documentDid={documentDid} 280 - colorScheme={colorScheme} 281 267 /> 282 268 ); 283 269 case "pub.leaflet.blocks.unorderedList": ··· 286 272 block={block} 287 273 alignment={alignment} 288 274 documentDid={documentDid} 289 - colorScheme={colorScheme} 290 275 /> 291 276 ); 292 277 case "pub.leaflet.blocks.website": ··· 295 280 block={block} 296 281 alignment={alignment} 297 282 documentDid={documentDid} 298 - colorScheme={colorScheme} 299 283 /> 300 284 ); 301 285 case "pub.leaflet.blocks.iframe": ··· 307 291 <LeafletMathBlockView 308 292 block={block} 309 293 alignment={alignment} 310 - colorScheme={colorScheme} 311 294 /> 312 295 ); 313 296 case "pub.leaflet.blocks.code": ··· 315 298 <LeafletCodeBlockView 316 299 block={block} 317 300 alignment={alignment} 318 - colorScheme={colorScheme} 319 301 /> 320 302 ); 321 303 case "pub.leaflet.blocks.horizontalRule": 322 304 return ( 323 305 <LeafletHorizontalRuleBlockView 324 306 alignment={alignment} 325 - colorScheme={colorScheme} 326 307 /> 327 308 ); 328 309 case "pub.leaflet.blocks.bskyPost": 329 310 return ( 330 311 <LeafletBskyPostBlockView 331 312 block={block} 332 - colorScheme={colorScheme} 333 313 /> 334 314 ); 335 315 case "pub.leaflet.blocks.text": ··· 338 318 <LeafletTextBlockView 339 319 block={block as LeafletTextBlock} 340 320 alignment={alignment} 341 - colorScheme={colorScheme} 342 321 isFirst={isFirst} 343 322 /> 344 323 ); ··· 348 327 const LeafletTextBlockView: React.FC<{ 349 328 block: LeafletTextBlock; 350 329 alignment?: React.CSSProperties["textAlign"]; 351 - colorScheme: "light" | "dark"; 352 330 isFirst?: boolean; 353 - }> = ({ block, alignment, colorScheme, isFirst }) => { 331 + }> = ({ block, alignment, isFirst }) => { 354 332 const segments = useMemo( 355 333 () => createFacetedSegments(block.plaintext, block.facets), 356 334 [block.plaintext, block.facets], ··· 359 337 if (!textContent.trim() && segments.length === 0) { 360 338 return null; 361 339 } 362 - const palette = colorScheme === "dark" ? theme.dark : theme.light; 363 340 const style: React.CSSProperties = { 364 341 ...base.paragraph, 365 - ...palette.paragraph, 342 + color: `var(--atproto-color-text)`, 366 343 ...(alignment ? { textAlign: alignment } : undefined), 367 344 ...(isFirst ? { marginTop: 0 } : undefined), 368 345 }; ··· 370 347 <p style={style}> 371 348 {segments.map((segment, idx) => ( 372 349 <React.Fragment key={`text-${idx}`}> 373 - {renderSegment(segment, colorScheme)} 350 + {renderSegment(segment)} 374 351 </React.Fragment> 375 352 ))} 376 353 </p> ··· 380 357 const LeafletHeaderBlockView: React.FC<{ 381 358 block: LeafletHeaderBlock; 382 359 alignment?: React.CSSProperties["textAlign"]; 383 - colorScheme: "light" | "dark"; 384 360 isFirst?: boolean; 385 - }> = ({ block, alignment, colorScheme, isFirst }) => { 386 - const palette = colorScheme === "dark" ? theme.dark : theme.light; 361 + }> = ({ block, alignment, isFirst }) => { 387 362 const level = 388 363 block.level && block.level >= 1 && block.level <= 6 ? block.level : 2; 389 364 const segments = useMemo( ··· 400 375 const headingTag = (["h1", "h2", "h3", "h4", "h5", "h6"] as const)[ 401 376 normalizedLevel - 1 402 377 ]; 403 - const headingStyles = palette.heading[normalizedLevel]; 404 378 const style: React.CSSProperties = { 405 379 ...base.heading, 406 - ...headingStyles, 380 + color: `var(--atproto-color-text)`, 381 + fontSize: normalizedLevel === 1 ? 30 : normalizedLevel === 2 ? 28 : normalizedLevel === 3 ? 24 : normalizedLevel === 4 ? 20 : normalizedLevel === 5 ? 18 : 16, 407 382 ...(alignment ? { textAlign: alignment } : undefined), 408 383 ...(isFirst ? { marginTop: 0 } : undefined), 409 384 }; ··· 413 388 { style }, 414 389 segments.map((segment, idx) => ( 415 390 <React.Fragment key={`header-${idx}`}> 416 - {renderSegment(segment, colorScheme)} 391 + {renderSegment(segment)} 417 392 </React.Fragment> 418 393 )), 419 394 ); ··· 422 397 const LeafletBlockquoteBlockView: React.FC<{ 423 398 block: LeafletBlockquoteBlock; 424 399 alignment?: React.CSSProperties["textAlign"]; 425 - colorScheme: "light" | "dark"; 426 400 isFirst?: boolean; 427 - }> = ({ block, alignment, colorScheme, isFirst }) => { 401 + }> = ({ block, alignment, isFirst }) => { 428 402 const segments = useMemo( 429 403 () => createFacetedSegments(block.plaintext, block.facets), 430 404 [block.plaintext, block.facets], ··· 433 407 if (!textContent.trim() && segments.length === 0) { 434 408 return null; 435 409 } 436 - const palette = colorScheme === "dark" ? theme.dark : theme.light; 437 410 return ( 438 411 <blockquote 439 412 style={{ 440 413 ...base.blockquote, 441 - ...palette.blockquote, 414 + background: `var(--atproto-color-bg-elevated)`, 415 + borderLeftWidth: "4px", 416 + borderLeftStyle: "solid", 417 + borderColor: `var(--atproto-color-border)`, 418 + color: `var(--atproto-color-text)`, 442 419 ...(alignment ? { textAlign: alignment } : undefined), 443 420 ...(isFirst ? { marginTop: 0 } : undefined), 444 421 }} 445 422 > 446 423 {segments.map((segment, idx) => ( 447 424 <React.Fragment key={`quote-${idx}`}> 448 - {renderSegment(segment, colorScheme)} 425 + {renderSegment(segment)} 449 426 </React.Fragment> 450 427 ))} 451 428 </blockquote> ··· 456 433 block: LeafletImageBlock; 457 434 alignment?: React.CSSProperties["textAlign"]; 458 435 documentDid: string; 459 - colorScheme: "light" | "dark"; 460 - }> = ({ block, alignment, documentDid, colorScheme }) => { 461 - const palette = colorScheme === "dark" ? theme.dark : theme.light; 436 + }> = ({ block, alignment, documentDid }) => { 462 437 const cid = block.image?.ref?.$link ?? block.image?.cid; 463 438 const { url, loading, error } = useBlob(documentDid, cid); 464 439 const aspectRatio = ··· 470 445 <figure 471 446 style={{ 472 447 ...base.figure, 473 - ...palette.figure, 474 448 ...(alignment ? { textAlign: alignment } : undefined), 475 449 }} 476 450 > 477 451 <div 478 452 style={{ 479 453 ...base.imageWrapper, 480 - ...palette.imageWrapper, 454 + background: `var(--atproto-color-bg-elevated)`, 481 455 ...(aspectRatio ? { aspectRatio } : {}), 482 456 }} 483 457 > ··· 485 459 <img 486 460 src={url} 487 461 alt={block.alt ?? ""} 488 - style={{ ...base.image, ...palette.image }} 462 + style={{ ...base.image }} 489 463 /> 490 464 ) : ( 491 465 <div 492 466 style={{ 493 467 ...base.imagePlaceholder, 494 - ...palette.imagePlaceholder, 468 + color: `var(--atproto-color-text-secondary)`, 495 469 }} 496 470 > 497 471 {loading ··· 503 477 )} 504 478 </div> 505 479 {block.alt && block.alt.trim().length > 0 && ( 506 - <figcaption style={{ ...base.caption, ...palette.caption }}> 480 + <figcaption style={{ ...base.caption, color: `var(--atproto-color-text-secondary)` }}> 507 481 {block.alt} 508 482 </figcaption> 509 483 )} ··· 515 489 block: LeafletUnorderedListBlock; 516 490 alignment?: React.CSSProperties["textAlign"]; 517 491 documentDid: string; 518 - colorScheme: "light" | "dark"; 519 - }> = ({ block, alignment, documentDid, colorScheme }) => { 520 - const palette = colorScheme === "dark" ? theme.dark : theme.light; 492 + }> = ({ block, alignment, documentDid }) => { 521 493 return ( 522 494 <ul 523 495 style={{ 524 496 ...base.list, 525 - ...palette.list, 497 + color: `var(--atproto-color-text)`, 526 498 ...(alignment ? { textAlign: alignment } : undefined), 527 499 }} 528 500 > ··· 531 503 key={`list-item-${idx}`} 532 504 item={child} 533 505 documentDid={documentDid} 534 - colorScheme={colorScheme} 535 506 alignment={alignment} 536 507 /> 537 508 ))} ··· 542 513 const LeafletListItemRenderer: React.FC<{ 543 514 item: LeafletListItem; 544 515 documentDid: string; 545 - colorScheme: "light" | "dark"; 546 516 alignment?: React.CSSProperties["textAlign"]; 547 - }> = ({ item, documentDid, colorScheme, alignment }) => { 517 + }> = ({ item, documentDid, alignment }) => { 548 518 return ( 549 519 <li 550 520 style={{ ··· 555 525 <div> 556 526 <LeafletInlineBlock 557 527 block={item.content} 558 - colorScheme={colorScheme} 559 528 documentDid={documentDid} 560 529 alignment={alignment} 561 530 /> ··· 572 541 key={`nested-${idx}`} 573 542 item={child} 574 543 documentDid={documentDid} 575 - colorScheme={colorScheme} 576 544 alignment={alignment} 577 545 /> 578 546 ))} ··· 584 552 585 553 const LeafletInlineBlock: React.FC<{ 586 554 block: LeafletBlock; 587 - colorScheme: "light" | "dark"; 588 555 documentDid: string; 589 556 alignment?: React.CSSProperties["textAlign"]; 590 - }> = ({ block, colorScheme, documentDid, alignment }) => { 557 + }> = ({ block, documentDid, alignment }) => { 591 558 switch (block.$type) { 592 559 case "pub.leaflet.blocks.header": 593 560 return ( 594 561 <LeafletHeaderBlockView 595 562 block={block as LeafletHeaderBlock} 596 - colorScheme={colorScheme} 597 563 alignment={alignment} 598 564 /> 599 565 ); ··· 601 567 return ( 602 568 <LeafletBlockquoteBlockView 603 569 block={block as LeafletBlockquoteBlock} 604 - colorScheme={colorScheme} 605 570 alignment={alignment} 606 571 /> 607 572 ); ··· 610 575 <LeafletImageBlockView 611 576 block={block as LeafletImageBlock} 612 577 documentDid={documentDid} 613 - colorScheme={colorScheme} 614 578 alignment={alignment} 615 579 /> 616 580 ); ··· 618 582 return ( 619 583 <LeafletTextBlockView 620 584 block={block as LeafletTextBlock} 621 - colorScheme={colorScheme} 622 585 alignment={alignment} 623 586 /> 624 587 ); ··· 629 592 block: LeafletWebsiteBlock; 630 593 alignment?: React.CSSProperties["textAlign"]; 631 594 documentDid: string; 632 - colorScheme: "light" | "dark"; 633 - }> = ({ block, alignment, documentDid, colorScheme }) => { 634 - const palette = colorScheme === "dark" ? theme.dark : theme.light; 595 + }> = ({ block, alignment, documentDid }) => { 635 596 const previewCid = 636 597 block.previewImage?.ref?.$link ?? block.previewImage?.cid; 637 598 const { url, loading, error } = useBlob(documentDid, previewCid); ··· 643 604 rel="noopener noreferrer" 644 605 style={{ 645 606 ...base.linkCard, 646 - ...palette.linkCard, 607 + borderWidth: "1px", 608 + borderStyle: "solid", 609 + borderColor: `var(--atproto-color-border)`, 610 + background: `var(--atproto-color-bg-elevated)`, 611 + color: `var(--atproto-color-text)`, 647 612 ...(alignment ? { textAlign: alignment } : undefined), 648 613 }} 649 614 > ··· 651 616 <img 652 617 src={url} 653 618 alt={block.title ?? "Website preview"} 654 - style={{ ...base.linkPreview, ...palette.linkPreview }} 619 + style={{ ...base.linkPreview }} 655 620 /> 656 621 ) : ( 657 622 <div 658 623 style={{ 659 624 ...base.linkPreviewPlaceholder, 660 - ...palette.linkPreviewPlaceholder, 625 + background: `var(--atproto-color-bg-elevated)`, 626 + color: `var(--atproto-color-text-secondary)`, 661 627 }} 662 628 > 663 629 {loading ? "Loading previewโ€ฆ" : "Open link"} ··· 665 631 )} 666 632 <div style={base.linkContent}> 667 633 {block.title && ( 668 - <strong style={palette.linkTitle}>{block.title}</strong> 634 + <strong style={{ fontSize: 16, color: `var(--atproto-color-text)` }}>{block.title}</strong> 669 635 )} 670 636 {block.description && ( 671 - <p style={palette.linkDescription}>{block.description}</p> 637 + <p style={{ margin: 0, fontSize: 14, color: `var(--atproto-color-text-secondary)`, lineHeight: 1.5 }}>{block.description}</p> 672 638 )} 673 - <span style={palette.linkUrl}>{block.src}</span> 639 + <span style={{ fontSize: 13, color: `var(--atproto-color-link)`, wordBreak: "break-all" }}>{block.src}</span> 674 640 </div> 675 641 </a> 676 642 ); ··· 701 667 const LeafletMathBlockView: React.FC<{ 702 668 block: LeafletMathBlock; 703 669 alignment?: React.CSSProperties["textAlign"]; 704 - colorScheme: "light" | "dark"; 705 - }> = ({ block, alignment, colorScheme }) => { 706 - const palette = colorScheme === "dark" ? theme.dark : theme.light; 670 + }> = ({ block, alignment }) => { 707 671 return ( 708 672 <pre 709 673 style={{ 710 674 ...base.math, 711 - ...palette.math, 675 + background: `var(--atproto-color-bg-elevated)`, 676 + color: `var(--atproto-color-text)`, 677 + border: `1px solid var(--atproto-color-border)`, 712 678 ...(alignment ? { textAlign: alignment } : undefined), 713 679 }} 714 680 > ··· 720 686 const LeafletCodeBlockView: React.FC<{ 721 687 block: LeafletCodeBlock; 722 688 alignment?: React.CSSProperties["textAlign"]; 723 - colorScheme: "light" | "dark"; 724 - }> = ({ block, alignment, colorScheme }) => { 725 - const palette = colorScheme === "dark" ? theme.dark : theme.light; 689 + }> = ({ block, alignment }) => { 726 690 const codeRef = useRef<HTMLElement | null>(null); 727 691 const langClass = block.language 728 692 ? `language-${block.language.toLowerCase()}` ··· 731 695 <pre 732 696 style={{ 733 697 ...base.code, 734 - ...palette.code, 698 + background: `var(--atproto-color-bg)`, 699 + color: `var(--atproto-color-text)`, 735 700 ...(alignment ? { textAlign: alignment } : undefined), 736 701 }} 737 702 > ··· 744 709 745 710 const LeafletHorizontalRuleBlockView: React.FC<{ 746 711 alignment?: React.CSSProperties["textAlign"]; 747 - colorScheme: "light" | "dark"; 748 - }> = ({ alignment, colorScheme }) => { 749 - const palette = colorScheme === "dark" ? theme.dark : theme.light; 712 + }> = ({ alignment }) => { 750 713 return ( 751 714 <hr 752 715 style={{ 753 716 ...base.hr, 754 - ...palette.hr, 717 + borderTopWidth: "1px", 718 + borderTopStyle: "solid", 719 + borderColor: `var(--atproto-color-border)`, 755 720 marginLeft: alignment ? "auto" : undefined, 756 721 marginRight: alignment ? "auto" : undefined, 757 722 }} ··· 761 726 762 727 const LeafletBskyPostBlockView: React.FC<{ 763 728 block: LeafletBskyPostBlock; 764 - colorScheme: "light" | "dark"; 765 - }> = ({ block, colorScheme }) => { 729 + }> = ({ block }) => { 766 730 const parsed = parseAtUri(block.postRef?.uri); 767 731 if (!parsed) { 768 732 return ( ··· 773 737 <BlueskyPost 774 738 did={parsed.did} 775 739 rkey={parsed.rkey} 776 - colorScheme={colorScheme} 777 740 iconPlacement="linkInline" 778 741 /> 779 742 ); ··· 855 818 ]); 856 819 } 857 820 } 858 - const sortedBounds = [...boundaries].sort((a, b) => a - b); 821 + const sortedBounds = Array.from(boundaries).sort((a, b) => a - b); 859 822 const segments: Segment[] = []; 860 823 let active: LeafletRichTextFeature[] = []; 861 824 for (let i = 0; i < sortedBounds.length - 1; i++) { ··· 915 878 916 879 function renderSegment( 917 880 segment: Segment, 918 - colorScheme: "light" | "dark", 919 881 ): React.ReactNode { 920 882 const parts = segment.text.split("\n"); 921 883 return parts.flatMap((part, idx) => { ··· 924 886 part.length ? part : "\u00a0", 925 887 segment.features, 926 888 key, 927 - colorScheme, 928 889 ); 929 890 if (idx === parts.length - 1) return wrapped; 930 891 return [wrapped, <br key={`${key}-br`} />]; ··· 935 896 content: React.ReactNode, 936 897 features: LeafletRichTextFeature[], 937 898 key: string, 938 - colorScheme: "light" | "dark", 939 899 ): React.ReactNode { 940 900 if (!features?.length) 941 901 return <React.Fragment key={key}>{content}</React.Fragment>; ··· 947 907 child, 948 908 feature, 949 909 `${key}-feature-${idx}`, 950 - colorScheme, 951 910 ), 952 911 content, 953 912 )} ··· 959 918 child: React.ReactNode, 960 919 feature: LeafletRichTextFeature, 961 920 key: string, 962 - colorScheme: "light" | "dark", 963 921 ): React.ReactNode { 964 922 switch (feature.$type) { 965 923 case "pub.leaflet.richtext.facet#link": ··· 969 927 href={feature.uri} 970 928 target="_blank" 971 929 rel="noopener noreferrer" 972 - style={linkStyles[colorScheme]} 930 + style={{ color: `var(--atproto-color-link)`, textDecoration: "underline" }} 973 931 > 974 932 {child} 975 933 </a> 976 934 ); 977 935 case "pub.leaflet.richtext.facet#code": 978 936 return ( 979 - <code key={key} style={inlineCodeStyles[colorScheme]}> 937 + <code key={key} style={{ 938 + fontFamily: 'Menlo, Consolas, "SFMono-Regular", ui-monospace', 939 + background: `var(--atproto-color-bg-elevated)`, 940 + padding: "0 4px", 941 + borderRadius: 4, 942 + }}> 980 943 {child} 981 944 </code> 982 945 ); 983 946 case "pub.leaflet.richtext.facet#highlight": 984 947 return ( 985 - <mark key={key} style={highlightStyles[colorScheme]}> 948 + <mark key={key} style={{ background: `var(--atproto-color-highlight)` }}> 986 949 {child} 987 950 </mark> 988 951 ); ··· 1020 983 gap: 24, 1021 984 padding: "24px 28px", 1022 985 borderRadius: 20, 1023 - border: "1px solid transparent", 986 + borderWidth: "1px", 987 + borderStyle: "solid", 988 + borderColor: "transparent", 1024 989 maxWidth: 720, 1025 990 width: "100%", 1026 991 fontFamily: ··· 1075 1040 blockquote: { 1076 1041 margin: "1em 0 0", 1077 1042 padding: "0.6em 1em", 1078 - borderLeft: "4px solid", 1043 + borderLeftWidth: "4px", 1044 + borderLeftStyle: "solid", 1079 1045 }, 1080 1046 figure: { 1081 1047 margin: "1.2em 0 0", ··· 1123 1089 }, 1124 1090 linkCard: { 1125 1091 borderRadius: 16, 1126 - border: "1px solid", 1092 + borderWidth: "1px", 1093 + borderStyle: "solid", 1127 1094 display: "flex", 1128 1095 flexDirection: "column", 1129 1096 overflow: "hidden", ··· 1170 1137 }, 1171 1138 hr: { 1172 1139 border: 0, 1173 - borderTop: "1px solid", 1140 + borderTopWidth: "1px", 1141 + borderTopStyle: "solid", 1174 1142 margin: "24px 0 0", 1175 1143 }, 1176 1144 embedFallback: { ··· 1180 1148 fontSize: 14, 1181 1149 }, 1182 1150 }; 1183 - 1184 - const theme = { 1185 - light: { 1186 - container: { 1187 - background: "#ffffff", 1188 - borderColor: "#e2e8f0", 1189 - color: "#0f172a", 1190 - boxShadow: "0 4px 18px rgba(15, 23, 42, 0.06)", 1191 - }, 1192 - header: {}, 1193 - title: { 1194 - color: "#0f172a", 1195 - }, 1196 - subtitle: { 1197 - color: "#475569", 1198 - }, 1199 - meta: { 1200 - color: "#64748b", 1201 - }, 1202 - metaLink: { 1203 - color: "#2563eb", 1204 - textDecoration: "none", 1205 - } satisfies React.CSSProperties, 1206 - metaSeparator: { 1207 - margin: "0 4px", 1208 - } satisfies React.CSSProperties, 1209 - paragraph: { 1210 - color: "#1f2937", 1211 - }, 1212 - heading: { 1213 - 1: { color: "#0f172a", fontSize: 30 }, 1214 - 2: { color: "#0f172a", fontSize: 28 }, 1215 - 3: { color: "#0f172a", fontSize: 24 }, 1216 - 4: { color: "#0f172a", fontSize: 20 }, 1217 - 5: { color: "#0f172a", fontSize: 18 }, 1218 - 6: { color: "#0f172a", fontSize: 16 }, 1219 - } satisfies Record<number, React.CSSProperties>, 1220 - blockquote: { 1221 - background: "#f8fafc", 1222 - borderColor: "#cbd5f5", 1223 - color: "#1f2937", 1224 - }, 1225 - figure: {}, 1226 - imageWrapper: { 1227 - background: "#e2e8f0", 1228 - }, 1229 - image: {}, 1230 - imagePlaceholder: { 1231 - color: "#475569", 1232 - }, 1233 - caption: { 1234 - color: "#475569", 1235 - }, 1236 - list: { 1237 - color: "#1f2937", 1238 - }, 1239 - linkCard: { 1240 - borderColor: "#e2e8f0", 1241 - background: "#f8fafc", 1242 - color: "#0f172a", 1243 - }, 1244 - linkPreview: {}, 1245 - linkPreviewPlaceholder: { 1246 - background: "#e2e8f0", 1247 - color: "#475569", 1248 - }, 1249 - linkTitle: { 1250 - fontSize: 16, 1251 - color: "#0f172a", 1252 - } satisfies React.CSSProperties, 1253 - linkDescription: { 1254 - margin: 0, 1255 - fontSize: 14, 1256 - color: "#475569", 1257 - lineHeight: 1.5, 1258 - } satisfies React.CSSProperties, 1259 - linkUrl: { 1260 - fontSize: 13, 1261 - color: "#2563eb", 1262 - wordBreak: "break-all", 1263 - } satisfies React.CSSProperties, 1264 - math: { 1265 - background: "#f1f5f9", 1266 - color: "#1f2937", 1267 - border: "1px solid #e2e8f0", 1268 - }, 1269 - code: { 1270 - background: "#0f172a", 1271 - color: "#e2e8f0", 1272 - }, 1273 - hr: { 1274 - borderColor: "#e2e8f0", 1275 - }, 1276 - }, 1277 - dark: { 1278 - container: { 1279 - background: "rgba(15, 23, 42, 0.6)", 1280 - borderColor: "rgba(148, 163, 184, 0.3)", 1281 - color: "#e2e8f0", 1282 - backdropFilter: "blur(8px)", 1283 - boxShadow: "0 10px 40px rgba(2, 6, 23, 0.45)", 1284 - }, 1285 - header: {}, 1286 - title: { 1287 - color: "#f8fafc", 1288 - }, 1289 - subtitle: { 1290 - color: "#cbd5f5", 1291 - }, 1292 - meta: { 1293 - color: "#94a3b8", 1294 - }, 1295 - metaLink: { 1296 - color: "#38bdf8", 1297 - textDecoration: "none", 1298 - } satisfies React.CSSProperties, 1299 - metaSeparator: { 1300 - margin: "0 4px", 1301 - } satisfies React.CSSProperties, 1302 - paragraph: { 1303 - color: "#e2e8f0", 1304 - }, 1305 - heading: { 1306 - 1: { color: "#f8fafc", fontSize: 30 }, 1307 - 2: { color: "#f8fafc", fontSize: 28 }, 1308 - 3: { color: "#f8fafc", fontSize: 24 }, 1309 - 4: { color: "#e2e8f0", fontSize: 20 }, 1310 - 5: { color: "#e2e8f0", fontSize: 18 }, 1311 - 6: { color: "#e2e8f0", fontSize: 16 }, 1312 - } satisfies Record<number, React.CSSProperties>, 1313 - blockquote: { 1314 - background: "rgba(30, 41, 59, 0.6)", 1315 - borderColor: "#38bdf8", 1316 - color: "#e2e8f0", 1317 - }, 1318 - figure: {}, 1319 - imageWrapper: { 1320 - background: "#1e293b", 1321 - }, 1322 - image: {}, 1323 - imagePlaceholder: { 1324 - color: "#94a3b8", 1325 - }, 1326 - caption: { 1327 - color: "#94a3b8", 1328 - }, 1329 - list: { 1330 - color: "#f1f5f9", 1331 - }, 1332 - linkCard: { 1333 - borderColor: "rgba(148, 163, 184, 0.3)", 1334 - background: "rgba(15, 23, 42, 0.8)", 1335 - color: "#e2e8f0", 1336 - }, 1337 - linkPreview: {}, 1338 - linkPreviewPlaceholder: { 1339 - background: "#1e293b", 1340 - color: "#94a3b8", 1341 - }, 1342 - linkTitle: { 1343 - fontSize: 16, 1344 - color: "#e0f2fe", 1345 - } satisfies React.CSSProperties, 1346 - linkDescription: { 1347 - margin: 0, 1348 - fontSize: 14, 1349 - color: "#cbd5f5", 1350 - lineHeight: 1.5, 1351 - } satisfies React.CSSProperties, 1352 - linkUrl: { 1353 - fontSize: 13, 1354 - color: "#38bdf8", 1355 - wordBreak: "break-all", 1356 - } satisfies React.CSSProperties, 1357 - math: { 1358 - background: "rgba(15, 23, 42, 0.8)", 1359 - color: "#e2e8f0", 1360 - border: "1px solid rgba(148, 163, 184, 0.35)", 1361 - }, 1362 - code: { 1363 - background: "#020617", 1364 - color: "#e2e8f0", 1365 - }, 1366 - hr: { 1367 - borderColor: "rgba(148, 163, 184, 0.3)", 1368 - }, 1369 - }, 1370 - } as const; 1371 - 1372 - const linkStyles = { 1373 - light: { 1374 - color: "#2563eb", 1375 - textDecoration: "underline", 1376 - } satisfies React.CSSProperties, 1377 - dark: { 1378 - color: "#38bdf8", 1379 - textDecoration: "underline", 1380 - } satisfies React.CSSProperties, 1381 - } as const; 1382 - 1383 - const inlineCodeStyles = { 1384 - light: { 1385 - fontFamily: 'Menlo, Consolas, "SFMono-Regular", ui-monospace', 1386 - background: "#f1f5f9", 1387 - padding: "0 4px", 1388 - borderRadius: 4, 1389 - } satisfies React.CSSProperties, 1390 - dark: { 1391 - fontFamily: 'Menlo, Consolas, "SFMono-Regular", ui-monospace', 1392 - background: "#1e293b", 1393 - padding: "0 4px", 1394 - borderRadius: 4, 1395 - } satisfies React.CSSProperties, 1396 - } as const; 1397 - 1398 - const highlightStyles = { 1399 - light: { 1400 - background: "#fef08a", 1401 - } satisfies React.CSSProperties, 1402 - dark: { 1403 - background: "#facc15", 1404 - color: "#0f172a", 1405 - } satisfies React.CSSProperties, 1406 - } as const; 1407 1151 1408 1152 export default LeafletDocumentRenderer;
+330
lib/renderers/TangledRepoRenderer.tsx
··· 1 + import React from "react"; 2 + import type { TangledRepoRecord } from "../types/tangled"; 3 + import { useAtProto } from "../providers/AtProtoProvider"; 4 + import { useBacklinks } from "../hooks/useBacklinks"; 5 + import { useRepoLanguages } from "../hooks/useRepoLanguages"; 6 + 7 + export interface TangledRepoRendererProps { 8 + record: TangledRepoRecord; 9 + error?: Error; 10 + loading: boolean; 11 + did: string; 12 + rkey: string; 13 + canonicalUrl?: string; 14 + showStarCount?: boolean; 15 + branch?: string; 16 + languages?: string[]; 17 + } 18 + 19 + export const TangledRepoRenderer: React.FC<TangledRepoRendererProps> = ({ 20 + record, 21 + error, 22 + loading, 23 + did, 24 + rkey, 25 + canonicalUrl, 26 + showStarCount = true, 27 + branch, 28 + languages, 29 + }) => { 30 + const { tangledBaseUrl, constellationBaseUrl } = useAtProto(); 31 + 32 + // Construct the AT-URI for this repo record 33 + const atUri = `at://${did}/sh.tangled.repo/${rkey}`; 34 + 35 + // Fetch star backlinks 36 + const { 37 + count: starCount, 38 + loading: starsLoading, 39 + error: starsError, 40 + } = useBacklinks({ 41 + subject: atUri, 42 + source: "sh.tangled.feed.star:subject", 43 + limit: 100, 44 + constellationBaseUrl, 45 + enabled: showStarCount, 46 + }); 47 + 48 + // Extract knot server from record.knot (e.g., "knot.gaze.systems") 49 + const knotUrl = record?.knot 50 + ? record.knot.startsWith("http://") || record.knot.startsWith("https://") 51 + ? new URL(record.knot).hostname 52 + : record.knot 53 + : undefined; 54 + 55 + // Fetch language data from knot server only if languages not provided 56 + const { 57 + data: languagesData, 58 + loading: _languagesLoading, 59 + error: _languagesError, 60 + } = useRepoLanguages({ 61 + knot: knotUrl, 62 + did, 63 + repoName: record?.name, 64 + branch, 65 + enabled: !languages && !!knotUrl && !!record?.name, 66 + }); 67 + 68 + // Convert provided language names to the format expected by the renderer 69 + const providedLanguagesData = languages 70 + ? { 71 + languages: languages.map((name) => ({ 72 + name, 73 + percentage: 0, 74 + size: 0, 75 + })), 76 + ref: branch || "main", 77 + totalFiles: 0, 78 + totalSize: 0, 79 + } 80 + : undefined; 81 + 82 + // Use provided languages or fetched languages 83 + const finalLanguagesData = providedLanguagesData ?? languagesData; 84 + 85 + if (error) 86 + return ( 87 + <div role="alert" style={{ padding: 8, color: "crimson" }}> 88 + Failed to load repository. 89 + </div> 90 + ); 91 + if (loading && !record) return <div role="status" aria-live="polite" style={{ padding: 8 }}>Loadingโ€ฆ</div>; 92 + 93 + // Construct the canonical URL: tangled.org/[did]/[repo-name] 94 + const viewUrl = 95 + canonicalUrl ?? 96 + `${tangledBaseUrl}/${did}/${encodeURIComponent(record.name)}`; 97 + 98 + const tangledIcon = ( 99 + <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 25 25" style={{ display: "block" }}> 100 + <path fill="currentColor" d="m 16.208435,23.914069 c -0.06147,-0.02273 -0.147027,-0.03034 -0.190158,-0.01691 -0.197279,0.06145 -1.31068,-0.230493 -1.388819,-0.364153 -0.01956,-0.03344 -0.163274,-0.134049 -0.319377,-0.223561 -0.550395,-0.315603 -1.010951,-0.696643 -1.428383,-1.181771 -0.264598,-0.307509 -0.597257,-0.785384 -0.597257,-0.857979 0,-0.0216 -0.02841,-0.06243 -0.06313,-0.0907 -0.04977,-0.04053 -0.160873,0.0436 -0.52488,0.397463 -0.479803,0.466432 -0.78924,0.689475 -1.355603,0.977118 -0.183693,0.0933 -0.323426,0.179989 -0.310516,0.192658 0.02801,0.02748 -0.7656391,0.270031 -1.209129,0.369517 -0.5378332,0.120647 -1.6341809,0.08626 -1.9721503,-0.06186 C 6.7977157,23.031391 6.56735,22.957551 6.3371134,22.889782 4.9717169,22.487902 3.7511914,21.481518 3.1172396,20.234838 2.6890391,19.392772 2.5582276,18.827446 2.5610489,17.831154 2.5639589,16.802192 2.7366641,16.125844 3.2142117,15.273187 3.3040457,15.112788 3.3713143,14.976533 3.3636956,14.9704 3.3560756,14.9643 3.2459634,14.90305 3.1189994,14.834381 1.7582586,14.098312 0.77760984,12.777439 0.44909837,11.23818 0.33531456,10.705039 0.33670119,9.7067968 0.45195381,9.1778795 0.72259241,7.9359287 1.3827188,6.8888436 2.4297498,6.0407205 2.6856126,5.8334648 3.2975489,5.4910878 3.6885849,5.3364049 L 4.0584319,5.190106 4.2333984,4.860432 C 4.8393906,3.7186139 5.8908314,2.7968028 7.1056396,2.3423025 7.7690673,2.0940921 8.2290216,2.0150935 9.01853,2.0137575 c 0.9625627,-0.00163 1.629181,0.1532762 2.485864,0.5776514 l 0.271744,0.1346134 0.42911,-0.3607688 c 1.082666,-0.9102346 2.185531,-1.3136811 3.578383,-1.3090327 0.916696,0.00306 1.573918,0.1517893 2.356121,0.5331927 1.465948,0.7148 2.54506,2.0625628 2.865177,3.57848 l 0.07653,0.362429 0.515095,0.2556611 c 1.022872,0.5076874 1.756122,1.1690944 2.288361,2.0641468 0.401896,0.6758594 0.537303,1.0442682 0.675505,1.8378683 0.288575,1.6570823 -0.266229,3.3548023 -1.490464,4.5608743 -0.371074,0.36557 -0.840205,0.718265 -1.203442,0.904754 -0.144112,0.07398 -0.271303,0.15826 -0.282647,0.187269 -0.01134,0.02901 0.02121,0.142764 0.07234,0.25279 0.184248,0.396467 0.451371,1.331823 0.619371,2.168779 0.463493,2.30908 -0.754646,4.693707 -2.92278,5.721632 -0.479538,0.227352 -0.717629,0.309322 -1.144194,0.39393 -0.321869,0.06383 -1.850573,0.09139 -2.000174,0.03604 z M 12.25443,18.636956 c 0.739923,-0.24652 1.382521,-0.718922 1.874623,-1.37812 0.0752,-0.100718 0.213883,-0.275851 0.308198,-0.389167 0.09432,-0.113318 0.210136,-0.271056 0.257381,-0.350531 0.416347,-0.700389 0.680936,-1.176102 0.766454,-1.378041 0.05594,-0.132087 0.114653,-0.239607 0.130477,-0.238929 0.01583,6.79e-4 0.08126,0.08531 0.145412,0.188069 0.178029,0.285173 0.614305,0.658998 0.868158,0.743878 0.259802,0.08686 0.656158,0.09598 0.911369,0.02095 0.213812,-0.06285 0.507296,-0.298016 0.645179,-0.516947 0.155165,-0.246374 0.327989,-0.989595 0.327989,-1.410501 0,-1.26718 -0.610975,-3.143405 -1.237774,-3.801045 -0.198483,-0.2082486 -0.208557,-0.2319396 -0.208557,-0.4904655 0,-0.2517771 -0.08774,-0.5704927 -0.258476,-0.938956 C 16.694963,8.50313 16.375697,8.1377479 16.135846,7.9543702 L 15.932296,7.7987471 15.683004,7.9356529 C 15.131767,8.2383821 14.435638,8.1945733 13.943459,7.8261812 L 13.782862,7.7059758 13.686773,7.8908012 C 13.338849,8.5600578 12.487087,8.8811064 11.743178,8.6233891 11.487199,8.5347109 11.358897,8.4505994 11.063189,8.1776138 L 10.69871,7.8411436 10.453484,8.0579255 C 10.318608,8.1771557 10.113778,8.3156283 9.9983037,8.3656417 9.7041488,8.4930449 9.1808299,8.5227884 8.8979004,8.4281886 8.7754792,8.3872574 8.6687415,8.3537661 8.6607053,8.3537661 c -0.03426,0 -0.3092864,0.3066098 -0.3791974,0.42275 -0.041935,0.069664 -0.1040482,0.1266636 -0.1380294,0.1266636 -0.1316419,0 -0.4197402,0.1843928 -0.6257041,0.4004735 -0.1923125,0.2017571 -0.6853701,0.9036038 -0.8926582,1.2706578 -0.042662,0.07554 -0.1803555,0.353687 -0.3059848,0.618091 -0.1256293,0.264406 -0.3270073,0.686768 -0.4475067,0.938581 -0.1204992,0.251816 -0.2469926,0.519654 -0.2810961,0.595199 -0.2592829,0.574347 -0.285919,1.391094 -0.057822,1.77304 0.1690683,0.283105 0.4224039,0.480895 0.7285507,0.568809 0.487122,0.139885 0.9109638,-0.004 1.6013422,-0.543768 l 0.4560939,-0.356568 0.0036,0.172041 c 0.01635,0.781837 0.1831084,1.813183 0.4016641,2.484154 0.1160449,0.356262 0.3781448,0.83968 0.5614081,1.035462 0.2171883,0.232025 0.7140951,0.577268 1.0100284,0.701749 0.121485,0.0511 0.351032,0.110795 0.510105,0.132647 0.396966,0.05452 1.2105,0.02265 1.448934,-0.05679 z"/> 101 + </svg> 102 + ); 103 + 104 + return ( 105 + <div 106 + style={{ 107 + ...base.container, 108 + background: `var(--atproto-color-bg)`, 109 + borderWidth: "1px", 110 + borderStyle: "solid", 111 + borderColor: `var(--atproto-color-border)`, 112 + color: `var(--atproto-color-text)`, 113 + }} 114 + > 115 + {/* Header with title and icons */} 116 + <div 117 + style={{ 118 + ...base.header, 119 + background: `var(--atproto-color-bg)`, 120 + }} 121 + > 122 + <div style={base.headerTop}> 123 + <strong 124 + style={{ 125 + ...base.repoName, 126 + color: `var(--atproto-color-text)`, 127 + }} 128 + > 129 + {record.name} 130 + </strong> 131 + <div style={base.headerRight}> 132 + <a 133 + href={viewUrl} 134 + target="_blank" 135 + rel="noopener noreferrer" 136 + style={{ 137 + ...base.iconLink, 138 + color: `var(--atproto-color-text)`, 139 + }} 140 + title="View on Tangled" 141 + > 142 + {tangledIcon} 143 + </a> 144 + {record.source && ( 145 + <a 146 + href={record.source} 147 + target="_blank" 148 + rel="noopener noreferrer" 149 + style={{ 150 + ...base.iconLink, 151 + color: `var(--atproto-color-text)`, 152 + }} 153 + title="View source repository" 154 + > 155 + <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 16 16" fill="currentColor" style={{ display: "block" }}> 156 + <path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/> 157 + </svg> 158 + </a> 159 + )} 160 + </div> 161 + </div> 162 + </div> 163 + 164 + {/* Description */} 165 + {record.description && ( 166 + <div 167 + style={{ 168 + ...base.description, 169 + background: `var(--atproto-color-bg)`, 170 + color: `var(--atproto-color-text-secondary)`, 171 + }} 172 + > 173 + {record.description} 174 + </div> 175 + )} 176 + 177 + {/* Languages and Stars */} 178 + <div 179 + style={{ 180 + ...base.languageSection, 181 + background: `var(--atproto-color-bg)`, 182 + }} 183 + > 184 + {/* Languages */} 185 + {finalLanguagesData && finalLanguagesData.languages.length > 0 && (() => { 186 + const topLanguages = finalLanguagesData.languages 187 + .filter((lang) => lang.name && (lang.percentage > 0 || finalLanguagesData.languages.every(l => l.percentage === 0))) 188 + .sort((a, b) => b.percentage - a.percentage) 189 + .slice(0, 2); 190 + return topLanguages.length > 0 ? ( 191 + <div style={base.languageTags}> 192 + {topLanguages.map((lang) => ( 193 + <span key={lang.name} style={base.languageTag}> 194 + {lang.name} 195 + </span> 196 + ))} 197 + </div> 198 + ) : null; 199 + })()} 200 + 201 + {/* Right side: Stars and View on Tangled link */} 202 + <div style={base.rightSection}> 203 + {/* Stars */} 204 + {showStarCount && ( 205 + <div 206 + style={{ 207 + ...base.starCountContainer, 208 + color: `var(--atproto-color-text-secondary)`, 209 + }} 210 + > 211 + <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" style={{ display: "block" }}> 212 + <path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Z"/> 213 + </svg> 214 + {starsLoading ? ( 215 + <span style={base.starCount}>...</span> 216 + ) : starsError ? ( 217 + <span style={base.starCount}>โ€”</span> 218 + ) : ( 219 + <span style={base.starCount}>{starCount}</span> 220 + )} 221 + </div> 222 + )} 223 + 224 + {/* View on Tangled link */} 225 + <a 226 + href={viewUrl} 227 + target="_blank" 228 + rel="noopener noreferrer" 229 + style={{ 230 + ...base.viewLink, 231 + color: `var(--atproto-color-link)`, 232 + }} 233 + > 234 + View on Tangled 235 + </a> 236 + </div> 237 + </div> 238 + </div> 239 + ); 240 + }; 241 + 242 + const base: Record<string, React.CSSProperties> = { 243 + container: { 244 + fontFamily: "system-ui, sans-serif", 245 + borderRadius: 6, 246 + overflow: "hidden", 247 + transition: 248 + "background-color 180ms ease, border-color 180ms ease, color 180ms ease, box-shadow 180ms ease", 249 + width: "100%", 250 + }, 251 + header: { 252 + padding: "16px", 253 + display: "flex", 254 + flexDirection: "column", 255 + }, 256 + headerTop: { 257 + display: "flex", 258 + justifyContent: "space-between", 259 + alignItems: "flex-start", 260 + gap: 12, 261 + }, 262 + headerRight: { 263 + display: "flex", 264 + alignItems: "center", 265 + gap: 8, 266 + }, 267 + repoName: { 268 + fontFamily: 269 + 'SFMono-Regular, ui-monospace, Menlo, Monaco, "Courier New", monospace', 270 + fontSize: 18, 271 + fontWeight: 600, 272 + wordBreak: "break-word", 273 + margin: 0, 274 + }, 275 + iconLink: { 276 + display: "flex", 277 + alignItems: "center", 278 + textDecoration: "none", 279 + opacity: 0.7, 280 + transition: "opacity 150ms ease", 281 + }, 282 + description: { 283 + padding: "0 16px 16px 16px", 284 + fontSize: 14, 285 + lineHeight: 1.5, 286 + }, 287 + languageSection: { 288 + padding: "0 16px 16px 16px", 289 + display: "flex", 290 + justifyContent: "space-between", 291 + alignItems: "center", 292 + gap: 12, 293 + flexWrap: "wrap", 294 + }, 295 + languageTags: { 296 + display: "flex", 297 + gap: 8, 298 + flexWrap: "wrap", 299 + }, 300 + languageTag: { 301 + fontSize: 12, 302 + fontWeight: 500, 303 + padding: "4px 10px", 304 + background: `var(--atproto-color-bg)`, 305 + borderRadius: 12, 306 + border: "1px solid var(--atproto-color-border)", 307 + }, 308 + rightSection: { 309 + display: "flex", 310 + alignItems: "center", 311 + gap: 12, 312 + }, 313 + starCountContainer: { 314 + display: "flex", 315 + alignItems: "center", 316 + gap: 4, 317 + fontSize: 13, 318 + }, 319 + starCount: { 320 + fontSize: 13, 321 + fontWeight: 500, 322 + }, 323 + viewLink: { 324 + fontSize: 13, 325 + fontWeight: 500, 326 + textDecoration: "none", 327 + }, 328 + }; 329 + 330 + export default TangledRepoRenderer;
+18 -91
lib/renderers/TangledStringRenderer.tsx
··· 1 1 import React from "react"; 2 - import type { ShTangledString } from "@atcute/tangled"; 3 - import { 4 - useColorScheme, 5 - type ColorSchemePreference, 6 - } from "../hooks/useColorScheme"; 7 - 8 - export type TangledStringRecord = ShTangledString.Main; 2 + import { useAtProto } from "../providers/AtProtoProvider"; 3 + import type { TangledStringRecord } from "../types/tangled"; 9 4 10 5 export interface TangledStringRendererProps { 11 6 record: TangledStringRecord; 12 7 error?: Error; 13 8 loading: boolean; 14 - colorScheme?: ColorSchemePreference; 15 9 did: string; 16 10 rkey: string; 17 11 canonicalUrl?: string; ··· 21 15 record, 22 16 error, 23 17 loading, 24 - colorScheme = "system", 25 18 did, 26 19 rkey, 27 20 canonicalUrl, 28 21 }) => { 29 - const scheme = useColorScheme(colorScheme); 22 + const { tangledBaseUrl } = useAtProto(); 30 23 31 24 if (error) 32 25 return ( ··· 36 29 ); 37 30 if (loading && !record) return <div style={{ padding: 8 }}>Loadingโ€ฆ</div>; 38 31 39 - const palette = scheme === "dark" ? theme.dark : theme.light; 40 32 const viewUrl = 41 33 canonicalUrl ?? 42 - `https://tangled.org/strings/${did}/${encodeURIComponent(rkey)}`; 34 + `${tangledBaseUrl}/strings/${did}/${encodeURIComponent(rkey)}`; 43 35 const timestamp = new Date(record.createdAt).toLocaleString(undefined, { 44 36 dateStyle: "medium", 45 37 timeStyle: "short", 46 38 }); 47 39 return ( 48 - <div style={{ ...base.container, ...palette.container }}> 49 - <div style={{ ...base.header, ...palette.header }}> 50 - <strong style={{ ...base.filename, ...palette.filename }}> 40 + <div style={{ ...base.container, background: `var(--atproto-color-bg-elevated)`, borderWidth: "1px", borderStyle: "solid", borderColor: `var(--atproto-color-border)`, color: `var(--atproto-color-text)` }}> 41 + <div style={{ ...base.header, background: `var(--atproto-color-bg-elevated)`, borderBottomWidth: "1px", borderBottomStyle: "solid", borderBottomColor: `var(--atproto-color-border)` }}> 42 + <strong style={{ ...base.filename, color: `var(--atproto-color-text)` }}> 51 43 {record.filename} 52 44 </strong> 53 - <div style={{ ...base.headerRight, ...palette.headerRight }}> 45 + <div style={{ ...base.headerRight }}> 54 46 <time 55 - style={{ ...base.timestamp, ...palette.timestamp }} 47 + style={{ ...base.timestamp, color: `var(--atproto-color-text-secondary)` }} 56 48 dateTime={record.createdAt} 57 49 > 58 50 {timestamp} ··· 61 53 href={viewUrl} 62 54 target="_blank" 63 55 rel="noopener noreferrer" 64 - style={{ ...base.headerLink, ...palette.headerLink }} 56 + style={{ ...base.headerLink, color: `var(--atproto-color-link)` }} 65 57 > 66 58 View on Tangled 67 59 </a> 68 60 </div> 69 61 </div> 70 62 {record.description && ( 71 - <div style={{ ...base.description, ...palette.description }}> 63 + <div style={{ ...base.description, background: `var(--atproto-color-bg)`, borderTopWidth: "1px", borderTopStyle: "solid", borderTopColor: `var(--atproto-color-border)`, borderBottomWidth: "1px", borderBottomStyle: "solid", borderBottomColor: `var(--atproto-color-border)`, color: `var(--atproto-color-text)` }}> 72 64 {record.description} 73 65 </div> 74 66 )} 75 - <pre style={{ ...base.codeBlock, ...palette.codeBlock }}> 67 + <pre style={{ ...base.codeBlock, background: `var(--atproto-color-bg)`, color: `var(--atproto-color-text)`, borderTopWidth: "1px", borderTopStyle: "solid", borderTopColor: `var(--atproto-color-border)` }}> 76 68 <code>{record.contents}</code> 77 69 </pre> 78 70 </div> ··· 119 111 description: { 120 112 padding: "10px 16px", 121 113 fontSize: 13, 122 - borderTop: "1px solid transparent", 114 + borderTopWidth: "1px", 115 + borderTopStyle: "solid", 116 + borderTopColor: "transparent", 123 117 }, 124 118 codeBlock: { 125 119 margin: 0, 126 120 padding: "16px", 127 121 fontSize: 13, 128 122 overflowX: "auto", 129 - borderTop: "1px solid transparent", 123 + borderTopWidth: "1px", 124 + borderTopStyle: "solid", 125 + borderTopColor: "transparent", 130 126 fontFamily: 131 127 'SFMono-Regular, ui-monospace, Menlo, Monaco, "Courier New", monospace', 132 128 }, 133 129 }; 134 - 135 - const theme = { 136 - light: { 137 - container: { 138 - border: "1px solid #d0d7de", 139 - background: "#f6f8fa", 140 - color: "#1f2328", 141 - boxShadow: "0 1px 2px rgba(31,35,40,0.05)", 142 - }, 143 - header: { 144 - background: "#f6f8fa", 145 - borderBottom: "1px solid #d0d7de", 146 - }, 147 - headerRight: {}, 148 - filename: { 149 - color: "#1f2328", 150 - }, 151 - timestamp: { 152 - color: "#57606a", 153 - }, 154 - headerLink: { 155 - color: "#2563eb", 156 - }, 157 - description: { 158 - background: "#ffffff", 159 - borderBottom: "1px solid #d0d7de", 160 - borderTopColor: "#d0d7de", 161 - color: "#1f2328", 162 - }, 163 - codeBlock: { 164 - background: "#ffffff", 165 - color: "#1f2328", 166 - borderTopColor: "#d0d7de", 167 - }, 168 - }, 169 - dark: { 170 - container: { 171 - border: "1px solid #30363d", 172 - background: "#0d1117", 173 - color: "#c9d1d9", 174 - boxShadow: "0 0 0 1px rgba(1,4,9,0.3) inset", 175 - }, 176 - header: { 177 - background: "#161b22", 178 - borderBottom: "1px solid #30363d", 179 - }, 180 - headerRight: {}, 181 - filename: { 182 - color: "#c9d1d9", 183 - }, 184 - timestamp: { 185 - color: "#8b949e", 186 - }, 187 - headerLink: { 188 - color: "#58a6ff", 189 - }, 190 - description: { 191 - background: "#161b22", 192 - borderBottom: "1px solid #30363d", 193 - borderTopColor: "#30363d", 194 - color: "#c9d1d9", 195 - }, 196 - codeBlock: { 197 - background: "#0d1117", 198 - color: "#c9d1d9", 199 - borderTopColor: "#30363d", 200 - }, 201 - }, 202 - } satisfies Record<"light" | "dark", Record<string, React.CSSProperties>>; 203 130 204 131 export default TangledStringRenderer;
+97
lib/styles.css
··· 1 + /** 2 + * Global CSS variables for AtProto UI components 3 + * 4 + * These variables can be customized in your application by setting them 5 + * at the :root level or within specific components. 6 + */ 7 + 8 + :root { 9 + /* Light theme colors (default) */ 10 + --atproto-color-bg: #f5f7f9; 11 + --atproto-color-bg-elevated: #f8f9fb; 12 + --atproto-color-bg-secondary: #edf1f5; 13 + --atproto-color-text: #0f172a; 14 + --atproto-color-text-secondary: #475569; 15 + --atproto-color-text-muted: #64748b; 16 + --atproto-color-border: #d6dce3; 17 + --atproto-color-border-subtle: #c1cad4; 18 + --atproto-color-border-hover: #94a3b8; 19 + --atproto-color-link: #2563eb; 20 + --atproto-color-link-hover: #1d4ed8; 21 + --atproto-color-error: #dc2626; 22 + --atproto-color-primary: #2563eb; 23 + --atproto-color-button-bg: #edf1f5; 24 + --atproto-color-button-hover: #e3e9ef; 25 + --atproto-color-button-text: #0f172a; 26 + --atproto-color-bg-hover: #f0f3f6; 27 + --atproto-color-bg-pressed: #e3e9ef; 28 + --atproto-color-code-bg: #edf1f5; 29 + --atproto-color-code-border: #d6dce3; 30 + --atproto-color-blockquote-border: #c1cad4; 31 + --atproto-color-blockquote-bg: #f0f3f6; 32 + --atproto-color-hr: #d6dce3; 33 + --atproto-color-image-bg: #edf1f5; 34 + --atproto-color-highlight: #fef08a; 35 + } 36 + 37 + /* Dark theme - can be applied via [data-theme="dark"] or .dark class */ 38 + [data-theme="dark"], 39 + .dark { 40 + --atproto-color-bg: #141b22; 41 + --atproto-color-bg-elevated: #1a222a; 42 + --atproto-color-bg-secondary: #0f161c; 43 + --atproto-color-text: #fafafa; 44 + --atproto-color-text-secondary: #a1a1aa; 45 + --atproto-color-text-muted: #71717a; 46 + --atproto-color-border: #1f2933; 47 + --atproto-color-border-subtle: #2d3748; 48 + --atproto-color-border-hover: #4a5568; 49 + --atproto-color-link: #60a5fa; 50 + --atproto-color-link-hover: #93c5fd; 51 + --atproto-color-error: #ef4444; 52 + --atproto-color-primary: #3b82f6; 53 + --atproto-color-button-bg: #1a222a; 54 + --atproto-color-button-hover: #243039; 55 + --atproto-color-button-text: #fafafa; 56 + --atproto-color-bg-hover: #1a222a; 57 + --atproto-color-bg-pressed: #243039; 58 + --atproto-color-code-bg: #0f161c; 59 + --atproto-color-code-border: #1f2933; 60 + --atproto-color-blockquote-border: #2d3748; 61 + --atproto-color-blockquote-bg: #1a222a; 62 + --atproto-color-hr: #243039; 63 + --atproto-color-image-bg: #1a222a; 64 + --atproto-color-highlight: #854d0e; 65 + } 66 + 67 + /* Support for system preference based theming */ 68 + @media (prefers-color-scheme: dark) { 69 + :root:not([data-theme]), 70 + :root[data-theme="system"] { 71 + --atproto-color-bg: #141b22; 72 + --atproto-color-bg-elevated: #1a222a; 73 + --atproto-color-bg-secondary: #0f161c; 74 + --atproto-color-text: #fafafa; 75 + --atproto-color-text-secondary: #a1a1aa; 76 + --atproto-color-text-muted: #71717a; 77 + --atproto-color-border: #1f2933; 78 + --atproto-color-border-subtle: #2d3748; 79 + --atproto-color-border-hover: #4a5568; 80 + --atproto-color-link: #60a5fa; 81 + --atproto-color-link-hover: #93c5fd; 82 + --atproto-color-error: #ef4444; 83 + --atproto-color-primary: #3b82f6; 84 + --atproto-color-button-bg: #1a222a; 85 + --atproto-color-button-hover: #243039; 86 + --atproto-color-button-text: #fafafa; 87 + --atproto-color-bg-hover: #1a222a; 88 + --atproto-color-bg-pressed: #243039; 89 + --atproto-color-code-bg: #0f161c; 90 + --atproto-color-code-border: #1f2933; 91 + --atproto-color-blockquote-border: #2d3748; 92 + --atproto-color-blockquote-bg: #1a222a; 93 + --atproto-color-hr: #243039; 94 + --atproto-color-image-bg: #1a222a; 95 + --atproto-color-highlight: #854d0e; 96 + } 97 + }
+95
lib/types/grain.ts
··· 1 + /** 2 + * Type definitions for grain.social records 3 + * Uses standard atcute blob types for compatibility 4 + */ 5 + import type { Blob } from "@atcute/lexicons/interfaces"; 6 + import type { BlobWithCdn } from "../hooks/useBlueskyAppview"; 7 + 8 + /** 9 + * grain.social gallery record 10 + * A container for a collection of photos 11 + */ 12 + export interface GrainGalleryRecord { 13 + /** 14 + * Record type identifier 15 + */ 16 + $type: "social.grain.gallery"; 17 + /** 18 + * Gallery title 19 + */ 20 + title: string; 21 + /** 22 + * Gallery description 23 + */ 24 + description?: string; 25 + /** 26 + * Self-label values (content warnings) 27 + */ 28 + labels?: { 29 + $type: "com.atproto.label.defs#selfLabels"; 30 + values: Array<{ val: string }>; 31 + }; 32 + /** 33 + * Timestamp when the gallery was created 34 + */ 35 + createdAt: string; 36 + } 37 + 38 + /** 39 + * grain.social gallery item record 40 + * Links a photo to a gallery 41 + */ 42 + export interface GrainGalleryItemRecord { 43 + /** 44 + * Record type identifier 45 + */ 46 + $type: "social.grain.gallery.item"; 47 + /** 48 + * AT URI of the photo (social.grain.photo) 49 + */ 50 + item: string; 51 + /** 52 + * AT URI of the gallery this item belongs to 53 + */ 54 + gallery: string; 55 + /** 56 + * Position/order within the gallery 57 + */ 58 + position?: number; 59 + /** 60 + * Timestamp when the item was added to the gallery 61 + */ 62 + createdAt: string; 63 + } 64 + 65 + /** 66 + * grain.social photo record 67 + * Compatible with records from @atcute clients 68 + */ 69 + export interface GrainPhotoRecord { 70 + /** 71 + * Record type identifier 72 + */ 73 + $type: "social.grain.photo"; 74 + /** 75 + * Alt text description of the image (required for accessibility) 76 + */ 77 + alt: string; 78 + /** 79 + * Photo blob reference - uses standard AT Proto blob format 80 + * Supports any image/* mime type 81 + * May include cdnUrl when fetched from appview 82 + */ 83 + photo: Blob<`image/${string}`> | BlobWithCdn; 84 + /** 85 + * Timestamp when the photo was created 86 + */ 87 + createdAt?: string; 88 + /** 89 + * Aspect ratio of the photo 90 + */ 91 + aspectRatio?: { 92 + width: number; 93 + height: number; 94 + }; 95 + }
+22
lib/types/tangled.ts
··· 1 + import type { ShTangledRepo, ShTangledString } from "@atcute/tangled"; 2 + 3 + export type TangledRepoRecord = ShTangledRepo.Main; 4 + export type TangledStringRecord = ShTangledString.Main; 5 + 6 + /** Language information from sh.tangled.repo.languages endpoint */ 7 + export interface RepoLanguage { 8 + name: string; 9 + percentage: number; 10 + size: number; 11 + } 12 + 13 + /** 14 + * Response from sh.tangled.repo.languages endpoint from tangled knot 15 + */ 16 + export interface RepoLanguagesResponse { 17 + languages: RepoLanguage[]; 18 + /** Branch name */ 19 + ref: string; 20 + totalFiles: number; 21 + totalSize: number; 22 + }
+40
lib/types/teal.ts
··· 1 + /** 2 + * teal.fm record types for music listening history 3 + * Specification: fm.teal.alpha.actor.status and fm.teal.alpha.feed.play 4 + */ 5 + 6 + export interface TealArtist { 7 + artistName: string; 8 + artistMbId?: string; 9 + } 10 + 11 + export interface TealPlayItem { 12 + artists: TealArtist[]; 13 + originUrl?: string; 14 + trackName: string; 15 + playedTime: string; 16 + releaseName?: string; 17 + recordingMbId?: string; 18 + releaseMbId?: string; 19 + submissionClientAgent?: string; 20 + musicServiceBaseDomain?: string; 21 + isrc?: string; 22 + duration?: number; 23 + } 24 + 25 + /** 26 + * fm.teal.alpha.actor.status - The last played song 27 + */ 28 + export interface TealActorStatusRecord { 29 + $type: "fm.teal.alpha.actor.status"; 30 + item: TealPlayItem; 31 + time: string; 32 + expiry?: string; 33 + } 34 + 35 + /** 36 + * fm.teal.alpha.feed.play - A single play record 37 + */ 38 + export interface TealFeedPlayRecord extends TealPlayItem { 39 + $type: "fm.teal.alpha.feed.play"; 40 + }
+23
lib/types/theme.ts
··· 1 + export type AtProtoStyles = React.CSSProperties & { 2 + '--atproto-color-bg'?: string; 3 + '--atproto-color-bg-elevated'?: string; 4 + '--atproto-color-bg-secondary'?: string; 5 + '--atproto-color-text'?: string; 6 + '--atproto-color-text-secondary'?: string; 7 + '--atproto-color-text-muted'?: string; 8 + '--atproto-color-border'?: string; 9 + '--atproto-color-border-subtle'?: string; 10 + '--atproto-color-link'?: string; 11 + '--atproto-color-link-hover'?: string; 12 + '--atproto-color-error'?: string; 13 + '--atproto-color-button-bg'?: string; 14 + '--atproto-color-button-hover'?: string; 15 + '--atproto-color-button-text'?: string; 16 + '--atproto-color-code-bg'?: string; 17 + '--atproto-color-code-border'?: string; 18 + '--atproto-color-blockquote-border'?: string; 19 + '--atproto-color-blockquote-bg'?: string; 20 + '--atproto-color-hr'?: string; 21 + '--atproto-color-image-bg'?: string; 22 + '--atproto-color-highlight'?: string; 23 + };
+37 -4
lib/utils/atproto-client.ts
··· 13 13 export interface ServiceResolverOptions { 14 14 plcDirectory?: string; 15 15 identityService?: string; 16 + slingshotBaseUrl?: string; 16 17 fetch?: typeof fetch; 17 18 } 18 19 19 20 const DEFAULT_PLC = "https://plc.directory"; 20 21 const DEFAULT_IDENTITY_SERVICE = "https://public.api.bsky.app"; 22 + const DEFAULT_SLINGSHOT = "https://slingshot.microcosm.blue"; 23 + const DEFAULT_APPVIEW = "https://public.api.bsky.app"; 24 + const DEFAULT_BLUESKY_APP = "https://bsky.app"; 25 + const DEFAULT_TANGLED = "https://tangled.org"; 26 + const DEFAULT_CONSTELLATION = "https://constellation.microcosm.blue"; 27 + 21 28 const ABSOLUTE_URL_RE = /^[a-zA-Z][a-zA-Z\d+\-.]*:/; 22 29 const SUPPORTED_DID_METHODS = ["plc", "web"] as const; 23 30 type SupportedDidMethod = (typeof SUPPORTED_DID_METHODS)[number]; 24 31 type SupportedDid = Did<SupportedDidMethod>; 25 32 26 - export const SLINGSHOT_BASE_URL = "https://slingshot.microcosm.blue"; 33 + /** 34 + * Default configuration values for AT Protocol services. 35 + * These can be overridden via AtProtoProvider props. 36 + */ 37 + export const DEFAULT_CONFIG = { 38 + plcDirectory: DEFAULT_PLC, 39 + identityService: DEFAULT_IDENTITY_SERVICE, 40 + slingshotBaseUrl: DEFAULT_SLINGSHOT, 41 + blueskyAppviewService: DEFAULT_APPVIEW, 42 + blueskyAppBaseUrl: DEFAULT_BLUESKY_APP, 43 + tangledBaseUrl: DEFAULT_TANGLED, 44 + constellationBaseUrl: DEFAULT_CONSTELLATION, 45 + } as const; 46 + 47 + export const SLINGSHOT_BASE_URL = DEFAULT_SLINGSHOT; 27 48 28 49 export const normalizeBaseUrl = (input: string): string => { 29 50 const trimmed = input.trim(); ··· 38 59 39 60 export class ServiceResolver { 40 61 private plc: string; 62 + private slingshot: string; 41 63 private didResolver: CompositeDidDocumentResolver<SupportedDidMethod>; 42 64 private handleResolver: XrpcHandleResolver; 43 65 private fetchImpl: typeof fetch; ··· 50 72 opts.identityService && opts.identityService.trim() 51 73 ? opts.identityService 52 74 : DEFAULT_IDENTITY_SERVICE; 75 + const slingshotSource = 76 + opts.slingshotBaseUrl && opts.slingshotBaseUrl.trim() 77 + ? opts.slingshotBaseUrl 78 + : DEFAULT_SLINGSHOT; 53 79 this.plc = normalizeBaseUrl(plcSource); 54 80 const identityBase = normalizeBaseUrl(identitySource); 81 + this.slingshot = normalizeBaseUrl(slingshotSource); 55 82 this.fetchImpl = bindFetch(opts.fetch); 56 83 const plcResolver = new PlcDidDocumentResolver({ 57 84 apiUrl: this.plc, ··· 97 124 return svc.serviceEndpoint.replace(/\/$/, ""); 98 125 } 99 126 127 + getSlingshotUrl(): string { 128 + return this.slingshot; 129 + } 130 + 100 131 async resolveHandle(handle: string): Promise<string> { 101 132 const normalized = handle.trim().toLowerCase(); 102 133 if (!normalized) throw new Error("Handle cannot be empty"); ··· 104 135 try { 105 136 const url = new URL( 106 137 "/xrpc/com.atproto.identity.resolveHandle", 107 - SLINGSHOT_BASE_URL, 138 + this.slingshot, 108 139 ); 109 140 url.searchParams.set("handle", normalized); 110 141 const response = await this.fetchImpl(url); ··· 161 192 } 162 193 if (!service) throw new Error("service or did required"); 163 194 const normalizedService = normalizeBaseUrl(service); 164 - const handler = createSlingshotAwareHandler(normalizedService, fetchImpl); 195 + const slingshotUrl = resolver.getSlingshotUrl(); 196 + const handler = createSlingshotAwareHandler(normalizedService, slingshotUrl, fetchImpl); 165 197 const rpc = new Client({ handler }); 166 198 return { rpc, service: normalizedService, resolver }; 167 199 } ··· 177 209 178 210 function createSlingshotAwareHandler( 179 211 service: string, 212 + slingshotBaseUrl: string, 180 213 fetchImpl: typeof fetch, 181 214 ): FetchHandler { 182 215 const primary = simpleFetchHandler({ service, fetch: fetchImpl }); 183 216 const slingshot = simpleFetchHandler({ 184 - service: SLINGSHOT_BASE_URL, 217 + service: slingshotBaseUrl, 185 218 fetch: fetchImpl, 186 219 }); 187 220 return async (pathname, init) => {
+37
lib/utils/blob.ts
··· 1 + import type { BlobWithCdn } from "../hooks/useBlueskyAppview"; 2 + 3 + /** 4 + * Type guard to check if a blob has a CDN URL from appview. 5 + */ 6 + export function isBlobWithCdn(value: unknown): value is BlobWithCdn { 7 + if (typeof value !== "object" || value === null) return false; 8 + const obj = value as Record<string, unknown>; 9 + return ( 10 + obj.$type === "blob" && 11 + typeof obj.cdnUrl === "string" && 12 + typeof obj.ref === "object" && 13 + obj.ref !== null && 14 + typeof (obj.ref as { $link?: unknown }).$link === "string" 15 + ); 16 + } 17 + 18 + /** 19 + * Extracts CID from a blob reference object. 20 + * Works with both legacy and modern blob formats. 21 + */ 22 + export function extractCidFromBlob(blob: unknown): string | undefined { 23 + if (typeof blob !== "object" || blob === null) return undefined; 24 + 25 + const blobObj = blob as { 26 + ref?: { $link?: string }; 27 + cid?: string; 28 + }; 29 + 30 + if (typeof blobObj.cid === "string") return blobObj.cid; 31 + if (typeof blobObj.ref === "object" && blobObj.ref !== null) { 32 + const link = blobObj.ref.$link; 33 + if (typeof link === "string") return link; 34 + } 35 + 36 + return undefined; 37 + }
+141 -1
lib/utils/cache.ts
··· 7 7 doc?: DidDocument; 8 8 pdsEndpoint?: string; 9 9 timestamp: number; 10 + snapshot?: DidCacheSnapshot; // Memoized snapshot to prevent rerenders 10 11 } 11 12 12 13 export interface DidCacheSnapshot { ··· 20 21 entry: DidCacheEntry | undefined, 21 22 ): DidCacheSnapshot | undefined => { 22 23 if (!entry) return undefined; 24 + // Return memoized snapshot if it exists 25 + if (entry.snapshot) return entry.snapshot; 26 + // Create and cache new snapshot 23 27 const { did, handle, doc, pdsEndpoint } = entry; 24 - return { did, handle, doc, pdsEndpoint }; 28 + const snapshot = { did, handle, doc, pdsEndpoint }; 29 + entry.snapshot = snapshot; 30 + return snapshot; 25 31 }; 26 32 27 33 const derivePdsEndpoint = ( ··· 78 84 derivePdsEndpoint(doc) ?? 79 85 existing?.pdsEndpoint; 80 86 87 + // Check if data has changed - if not, reuse existing snapshot 88 + if ( 89 + existing && 90 + existing.did === did && 91 + existing.handle === handle && 92 + existing.doc === doc && 93 + existing.pdsEndpoint === pdsEndpoint 94 + ) { 95 + // Data unchanged, return existing memoized snapshot 96 + return toSnapshot(existing) as DidCacheSnapshot; 97 + } 98 + 99 + // Data changed, create new entry (snapshot will be created on first access) 81 100 const merged: DidCacheEntry = { 82 101 did, 83 102 handle, 84 103 doc, 85 104 pdsEndpoint, 86 105 timestamp: Date.now(), 106 + snapshot: undefined, // Will be created lazily by toSnapshot 87 107 }; 88 108 89 109 this.byDid.set(did, merged); ··· 250 270 } 251 271 } 252 272 } 273 + 274 + interface RecordCacheEntry<T = unknown> { 275 + record: T; 276 + timestamp: number; 277 + } 278 + 279 + interface InFlightRecordEntry<T = unknown> { 280 + promise: Promise<T>; 281 + abort: () => void; 282 + refCount: number; 283 + } 284 + 285 + interface RecordEnsureResult<T = unknown> { 286 + promise: Promise<T>; 287 + release: () => void; 288 + } 289 + 290 + export class RecordCache { 291 + private store = new Map<string, RecordCacheEntry>(); 292 + private inFlight = new Map<string, InFlightRecordEntry>(); 293 + // Collections that should not be cached (e.g., status records that change frequently) 294 + private noCacheCollections = new Set<string>([ 295 + "fm.teal.alpha.actor.status", 296 + "fm.teal.alpha.feed.play", 297 + ]); 298 + 299 + private key(did: string, collection: string, rkey: string): string { 300 + return `${did}::${collection}::${rkey}`; 301 + } 302 + 303 + private shouldCache(collection: string): boolean { 304 + return !this.noCacheCollections.has(collection); 305 + } 306 + 307 + get<T = unknown>( 308 + did?: string, 309 + collection?: string, 310 + rkey?: string, 311 + ): T | undefined { 312 + if (!did || !collection || !rkey) return undefined; 313 + // Don't return cached data for non-cacheable collections 314 + if (!this.shouldCache(collection)) return undefined; 315 + return this.store.get(this.key(did, collection, rkey))?.record as 316 + | T 317 + | undefined; 318 + } 319 + 320 + set<T = unknown>( 321 + did: string, 322 + collection: string, 323 + rkey: string, 324 + record: T, 325 + ): void { 326 + // Don't cache records for non-cacheable collections 327 + if (!this.shouldCache(collection)) return; 328 + this.store.set(this.key(did, collection, rkey), { 329 + record, 330 + timestamp: Date.now(), 331 + }); 332 + } 333 + 334 + ensure<T = unknown>( 335 + did: string, 336 + collection: string, 337 + rkey: string, 338 + loader: () => { promise: Promise<T>; abort: () => void }, 339 + ): RecordEnsureResult<T> { 340 + const cached = this.get<T>(did, collection, rkey); 341 + if (cached !== undefined) { 342 + return { promise: Promise.resolve(cached), release: () => {} }; 343 + } 344 + 345 + const key = this.key(did, collection, rkey); 346 + const existing = this.inFlight.get(key) as 347 + | InFlightRecordEntry<T> 348 + | undefined; 349 + if (existing) { 350 + existing.refCount += 1; 351 + return { 352 + promise: existing.promise, 353 + release: () => this.release(key), 354 + }; 355 + } 356 + 357 + const { promise, abort } = loader(); 358 + const wrapped = promise.then((record) => { 359 + this.set(did, collection, rkey, record); 360 + return record; 361 + }); 362 + 363 + const entry: InFlightRecordEntry<T> = { 364 + promise: wrapped, 365 + abort, 366 + refCount: 1, 367 + }; 368 + 369 + this.inFlight.set(key, entry as InFlightRecordEntry); 370 + 371 + wrapped 372 + .catch(() => {}) 373 + .finally(() => { 374 + this.inFlight.delete(key); 375 + }); 376 + 377 + return { 378 + promise: wrapped, 379 + release: () => this.release(key), 380 + }; 381 + } 382 + 383 + private release(key: string) { 384 + const entry = this.inFlight.get(key); 385 + if (!entry) return; 386 + entry.refCount -= 1; 387 + if (entry.refCount <= 0) { 388 + this.inFlight.delete(key); 389 + entry.abort(); 390 + } 391 + } 392 + }
+120
lib/utils/richtext.ts
··· 1 + import type { AppBskyRichtextFacet } from "@atcute/bluesky"; 2 + 3 + export interface TextSegment { 4 + text: string; 5 + facet?: AppBskyRichtextFacet.Main; 6 + } 7 + 8 + /** 9 + * Converts a text string with facets into segments that can be rendered 10 + * with appropriate styling and interactivity. 11 + */ 12 + export function createTextSegments( 13 + text: string, 14 + facets?: AppBskyRichtextFacet.Main[], 15 + ): TextSegment[] { 16 + if (!facets || facets.length === 0) { 17 + return [{ text }]; 18 + } 19 + 20 + // Build byte-to-char index mapping 21 + const bytePrefix = buildBytePrefix(text); 22 + 23 + // Sort facets by start position 24 + const sortedFacets = [...facets].sort( 25 + (a, b) => a.index.byteStart - b.index.byteStart, 26 + ); 27 + 28 + const segments: TextSegment[] = []; 29 + let currentPos = 0; 30 + 31 + for (const facet of sortedFacets) { 32 + const startChar = byteOffsetToCharIndex(bytePrefix, facet.index.byteStart); 33 + const endChar = byteOffsetToCharIndex(bytePrefix, facet.index.byteEnd); 34 + 35 + // Add plain text before this facet 36 + if (startChar > currentPos) { 37 + segments.push({ 38 + text: sliceByCharRange(text, currentPos, startChar), 39 + }); 40 + } 41 + 42 + // Add the faceted text 43 + segments.push({ 44 + text: sliceByCharRange(text, startChar, endChar), 45 + facet, 46 + }); 47 + 48 + currentPos = endChar; 49 + } 50 + 51 + // Add remaining plain text 52 + if (currentPos < text.length) { 53 + segments.push({ 54 + text: sliceByCharRange(text, currentPos, text.length), 55 + }); 56 + } 57 + 58 + return segments; 59 + } 60 + 61 + /** 62 + * Builds a byte offset prefix array for UTF-8 encoded text. 63 + * This handles multi-byte characters correctly. 64 + */ 65 + function buildBytePrefix(text: string): number[] { 66 + const encoder = new TextEncoder(); 67 + const prefix: number[] = [0]; 68 + let byteCount = 0; 69 + 70 + for (let i = 0; i < text.length; ) { 71 + const codePoint = text.codePointAt(i); 72 + if (codePoint === undefined) break; 73 + 74 + const char = String.fromCodePoint(codePoint); 75 + const encoded = encoder.encode(char); 76 + byteCount += encoded.length; 77 + prefix.push(byteCount); 78 + 79 + // Handle surrogate pairs (emojis, etc.) 80 + i += codePoint > 0xffff ? 2 : 1; 81 + } 82 + 83 + return prefix; 84 + } 85 + 86 + /** 87 + * Converts a byte offset to a character index using the byte prefix array. 88 + */ 89 + function byteOffsetToCharIndex(prefix: number[], byteOffset: number): number { 90 + for (let i = 0; i < prefix.length; i++) { 91 + if (prefix[i] === byteOffset) return i; 92 + if (prefix[i] > byteOffset) return Math.max(0, i - 1); 93 + } 94 + return prefix.length - 1; 95 + } 96 + 97 + /** 98 + * Slices text by character range, handling multi-byte characters correctly. 99 + */ 100 + function sliceByCharRange(text: string, start: number, end: number): string { 101 + if (start <= 0 && end >= text.length) return text; 102 + 103 + let result = ""; 104 + let charIndex = 0; 105 + 106 + for (let i = 0; i < text.length && charIndex < end; ) { 107 + const codePoint = text.codePointAt(i); 108 + if (codePoint === undefined) break; 109 + 110 + const char = String.fromCodePoint(codePoint); 111 + if (charIndex >= start && charIndex < end) { 112 + result += char; 113 + } 114 + 115 + i += codePoint > 0xffff ? 2 : 1; 116 + charIndex++; 117 + } 118 + 119 + return result; 120 + }
+4073 -2861
package-lock.json
··· 1 1 { 2 - "name": "atproto-ui", 3 - "version": "0.2.0", 4 - "lockfileVersion": 3, 5 - "requires": true, 6 - "packages": { 7 - "": { 8 - "name": "atproto-ui", 9 - "version": "0.2.0", 10 - "dependencies": { 11 - "@atcute/atproto": "^3.1.7", 12 - "@atcute/bluesky": "^3.2.3", 13 - "@atcute/client": "^4.0.3", 14 - "@atcute/identity-resolver": "^1.1.3", 15 - "@atcute/tangled": "^1.0.6" 16 - }, 17 - "devDependencies": { 18 - "@eslint/js": "^9.36.0", 19 - "@types/node": "^24.6.0", 20 - "@types/react": "^19.1.16", 21 - "@types/react-dom": "^19.1.9", 22 - "@vitejs/plugin-react": "^5.0.4", 23 - "eslint": "^9.36.0", 24 - "eslint-plugin-react-hooks": "^5.2.0", 25 - "eslint-plugin-react-refresh": "^0.4.22", 26 - "globals": "^16.4.0", 27 - "react": "^19.1.1", 28 - "react-dom": "^19.1.1", 29 - "typescript": "~5.9.3", 30 - "typescript-eslint": "^8.45.0", 31 - "vite": "npm:rolldown-vite@7.1.14" 32 - }, 33 - "peerDependencies": { 34 - "react": "^18.2.0 || ^19.0.0", 35 - "react-dom": "^18.2.0 || ^19.0.0" 36 - }, 37 - "peerDependenciesMeta": { 38 - "react-dom": { 39 - "optional": true 40 - } 41 - } 42 - }, 43 - "node_modules/@atcute/atproto": { 44 - "version": "3.1.7", 45 - "resolved": "https://registry.npmjs.org/@atcute/atproto/-/atproto-3.1.7.tgz", 46 - "integrity": "sha512-3Ym8qaVZg2vf8qw0KO1aue39z/5oik5J+UDoSes1vr8ddw40UVLA5sV4bXSKmLnhzQHiLLgoVZXe4zaKfozPoQ==", 47 - "license": "0BSD", 48 - "dependencies": { 49 - "@atcute/lexicons": "^1.2.2" 50 - } 51 - }, 52 - "node_modules/@atcute/bluesky": { 53 - "version": "3.2.3", 54 - "resolved": "https://registry.npmjs.org/@atcute/bluesky/-/bluesky-3.2.3.tgz", 55 - "integrity": "sha512-IdPQQ54F1BLhW5z49k81ZUC/GQl/tVygZ+CzLHYvQySHA6GJRcvPzwEf8aV21u0SZOJF+yF4CWEGNgtryyxPmg==", 56 - "license": "0BSD", 57 - "dependencies": { 58 - "@atcute/atproto": "^3.1.4", 59 - "@atcute/lexicons": "^1.1.1" 60 - } 61 - }, 62 - "node_modules/@atcute/client": { 63 - "version": "4.0.3", 64 - "resolved": "https://registry.npmjs.org/@atcute/client/-/client-4.0.3.tgz", 65 - "integrity": "sha512-RIOZWFVLca/HiPAAUDqQPOdOreCxTbL5cb+WUf5yqQOKIu5yEAP3eksinmlLmgIrlr5qVOE7brazUUzaskFCfw==", 66 - "license": "MIT", 67 - "dependencies": { 68 - "@atcute/identity": "^1.0.2", 69 - "@atcute/lexicons": "^1.0.3" 70 - } 71 - }, 72 - "node_modules/@atcute/identity": { 73 - "version": "1.1.0", 74 - "resolved": "https://registry.npmjs.org/@atcute/identity/-/identity-1.1.0.tgz", 75 - "integrity": "sha512-6vRvRqJatDB+JUQsb+UswYmtBGQnSZcqC3a2y6H5DB/v5KcIh+6nFFtc17G0+3W9rxdk7k9M4KkgkdKf/YDNoQ==", 76 - "license": "0BSD", 77 - "dependencies": { 78 - "@atcute/lexicons": "^1.1.1", 79 - "@badrap/valita": "^0.4.5" 80 - } 81 - }, 82 - "node_modules/@atcute/identity-resolver": { 83 - "version": "1.1.4", 84 - "resolved": "https://registry.npmjs.org/@atcute/identity-resolver/-/identity-resolver-1.1.4.tgz", 85 - "integrity": "sha512-/SVh8vf2cXFJenmBnGeYF2aY3WGQm3cJeew5NWTlkqoy3LvJ5wkvKq9PWu4Tv653VF40rPOp6LOdVr9Fa+q5rA==", 86 - "license": "0BSD", 87 - "dependencies": { 88 - "@atcute/lexicons": "^1.2.2", 89 - "@atcute/util-fetch": "^1.0.3", 90 - "@badrap/valita": "^0.4.6" 91 - }, 92 - "peerDependencies": { 93 - "@atcute/identity": "^1.0.0" 94 - } 95 - }, 96 - "node_modules/@atcute/lexicons": { 97 - "version": "1.2.2", 98 - "resolved": "https://registry.npmjs.org/@atcute/lexicons/-/lexicons-1.2.2.tgz", 99 - "integrity": "sha512-bgEhJq5Z70/0TbK5sx+tAkrR8FsCODNiL2gUEvS5PuJfPxmFmRYNWaMGehxSPaXWpU2+Oa9ckceHiYbrItDTkA==", 100 - "license": "0BSD", 101 - "dependencies": { 102 - "@standard-schema/spec": "^1.0.0", 103 - "esm-env": "^1.2.2" 104 - } 105 - }, 106 - "node_modules/@atcute/tangled": { 107 - "version": "1.0.6", 108 - "resolved": "https://registry.npmjs.org/@atcute/tangled/-/tangled-1.0.6.tgz", 109 - "integrity": "sha512-eEOtrKRbjKfeLYtb5hmkhE45w8h4sV6mT4E2CQzJmhOMGCiK31GX7Vqfh59rhNLb9AlbW72RcQTV737pxx+ksw==", 110 - "license": "0BSD", 111 - "dependencies": { 112 - "@atcute/atproto": "^3.1.4", 113 - "@atcute/lexicons": "^1.1.1" 114 - } 115 - }, 116 - "node_modules/@atcute/util-fetch": { 117 - "version": "1.0.3", 118 - "resolved": "https://registry.npmjs.org/@atcute/util-fetch/-/util-fetch-1.0.3.tgz", 119 - "integrity": "sha512-f8zzTb/xlKIwv2OQ31DhShPUNCmIIleX6p7qIXwWwEUjX6x8skUtpdISSjnImq01LXpltGV5y8yhV4/Mlb7CRQ==", 120 - "license": "0BSD", 121 - "dependencies": { 122 - "@badrap/valita": "^0.4.6" 123 - } 124 - }, 125 - "node_modules/@babel/code-frame": { 126 - "version": "7.27.1", 127 - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", 128 - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", 129 - "dev": true, 130 - "license": "MIT", 131 - "dependencies": { 132 - "@babel/helper-validator-identifier": "^7.27.1", 133 - "js-tokens": "^4.0.0", 134 - "picocolors": "^1.1.1" 135 - }, 136 - "engines": { 137 - "node": ">=6.9.0" 138 - } 139 - }, 140 - "node_modules/@babel/compat-data": { 141 - "version": "7.28.4", 142 - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", 143 - "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", 144 - "dev": true, 145 - "license": "MIT", 146 - "engines": { 147 - "node": ">=6.9.0" 148 - } 149 - }, 150 - "node_modules/@babel/core": { 151 - "version": "7.28.4", 152 - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", 153 - "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", 154 - "dev": true, 155 - "license": "MIT", 156 - "dependencies": { 157 - "@babel/code-frame": "^7.27.1", 158 - "@babel/generator": "^7.28.3", 159 - "@babel/helper-compilation-targets": "^7.27.2", 160 - "@babel/helper-module-transforms": "^7.28.3", 161 - "@babel/helpers": "^7.28.4", 162 - "@babel/parser": "^7.28.4", 163 - "@babel/template": "^7.27.2", 164 - "@babel/traverse": "^7.28.4", 165 - "@babel/types": "^7.28.4", 166 - "@jridgewell/remapping": "^2.3.5", 167 - "convert-source-map": "^2.0.0", 168 - "debug": "^4.1.0", 169 - "gensync": "^1.0.0-beta.2", 170 - "json5": "^2.2.3", 171 - "semver": "^6.3.1" 172 - }, 173 - "engines": { 174 - "node": ">=6.9.0" 175 - }, 176 - "funding": { 177 - "type": "opencollective", 178 - "url": "https://opencollective.com/babel" 179 - } 180 - }, 181 - "node_modules/@babel/generator": { 182 - "version": "7.28.3", 183 - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", 184 - "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", 185 - "dev": true, 186 - "license": "MIT", 187 - "dependencies": { 188 - "@babel/parser": "^7.28.3", 189 - "@babel/types": "^7.28.2", 190 - "@jridgewell/gen-mapping": "^0.3.12", 191 - "@jridgewell/trace-mapping": "^0.3.28", 192 - "jsesc": "^3.0.2" 193 - }, 194 - "engines": { 195 - "node": ">=6.9.0" 196 - } 197 - }, 198 - "node_modules/@babel/helper-compilation-targets": { 199 - "version": "7.27.2", 200 - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", 201 - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", 202 - "dev": true, 203 - "license": "MIT", 204 - "dependencies": { 205 - "@babel/compat-data": "^7.27.2", 206 - "@babel/helper-validator-option": "^7.27.1", 207 - "browserslist": "^4.24.0", 208 - "lru-cache": "^5.1.1", 209 - "semver": "^6.3.1" 210 - }, 211 - "engines": { 212 - "node": ">=6.9.0" 213 - } 214 - }, 215 - "node_modules/@babel/helper-globals": { 216 - "version": "7.28.0", 217 - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", 218 - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", 219 - "dev": true, 220 - "license": "MIT", 221 - "engines": { 222 - "node": ">=6.9.0" 223 - } 224 - }, 225 - "node_modules/@babel/helper-module-imports": { 226 - "version": "7.27.1", 227 - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", 228 - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", 229 - "dev": true, 230 - "license": "MIT", 231 - "dependencies": { 232 - "@babel/traverse": "^7.27.1", 233 - "@babel/types": "^7.27.1" 234 - }, 235 - "engines": { 236 - "node": ">=6.9.0" 237 - } 238 - }, 239 - "node_modules/@babel/helper-module-transforms": { 240 - "version": "7.28.3", 241 - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", 242 - "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", 243 - "dev": true, 244 - "license": "MIT", 245 - "dependencies": { 246 - "@babel/helper-module-imports": "^7.27.1", 247 - "@babel/helper-validator-identifier": "^7.27.1", 248 - "@babel/traverse": "^7.28.3" 249 - }, 250 - "engines": { 251 - "node": ">=6.9.0" 252 - }, 253 - "peerDependencies": { 254 - "@babel/core": "^7.0.0" 255 - } 256 - }, 257 - "node_modules/@babel/helper-plugin-utils": { 258 - "version": "7.27.1", 259 - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", 260 - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", 261 - "dev": true, 262 - "license": "MIT", 263 - "engines": { 264 - "node": ">=6.9.0" 265 - } 266 - }, 267 - "node_modules/@babel/helper-string-parser": { 268 - "version": "7.27.1", 269 - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", 270 - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", 271 - "dev": true, 272 - "license": "MIT", 273 - "engines": { 274 - "node": ">=6.9.0" 275 - } 276 - }, 277 - "node_modules/@babel/helper-validator-identifier": { 278 - "version": "7.27.1", 279 - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", 280 - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", 281 - "dev": true, 282 - "license": "MIT", 283 - "engines": { 284 - "node": ">=6.9.0" 285 - } 286 - }, 287 - "node_modules/@babel/helper-validator-option": { 288 - "version": "7.27.1", 289 - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", 290 - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", 291 - "dev": true, 292 - "license": "MIT", 293 - "engines": { 294 - "node": ">=6.9.0" 295 - } 296 - }, 297 - "node_modules/@babel/helpers": { 298 - "version": "7.28.4", 299 - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", 300 - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", 301 - "dev": true, 302 - "license": "MIT", 303 - "dependencies": { 304 - "@babel/template": "^7.27.2", 305 - "@babel/types": "^7.28.4" 306 - }, 307 - "engines": { 308 - "node": ">=6.9.0" 309 - } 310 - }, 311 - "node_modules/@babel/parser": { 312 - "version": "7.28.4", 313 - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", 314 - "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", 315 - "dev": true, 316 - "license": "MIT", 317 - "dependencies": { 318 - "@babel/types": "^7.28.4" 319 - }, 320 - "bin": { 321 - "parser": "bin/babel-parser.js" 322 - }, 323 - "engines": { 324 - "node": ">=6.0.0" 325 - } 326 - }, 327 - "node_modules/@babel/plugin-transform-react-jsx-self": { 328 - "version": "7.27.1", 329 - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", 330 - "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", 331 - "dev": true, 332 - "license": "MIT", 333 - "dependencies": { 334 - "@babel/helper-plugin-utils": "^7.27.1" 335 - }, 336 - "engines": { 337 - "node": ">=6.9.0" 338 - }, 339 - "peerDependencies": { 340 - "@babel/core": "^7.0.0-0" 341 - } 342 - }, 343 - "node_modules/@babel/plugin-transform-react-jsx-source": { 344 - "version": "7.27.1", 345 - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", 346 - "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", 347 - "dev": true, 348 - "license": "MIT", 349 - "dependencies": { 350 - "@babel/helper-plugin-utils": "^7.27.1" 351 - }, 352 - "engines": { 353 - "node": ">=6.9.0" 354 - }, 355 - "peerDependencies": { 356 - "@babel/core": "^7.0.0-0" 357 - } 358 - }, 359 - "node_modules/@babel/template": { 360 - "version": "7.27.2", 361 - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", 362 - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", 363 - "dev": true, 364 - "license": "MIT", 365 - "dependencies": { 366 - "@babel/code-frame": "^7.27.1", 367 - "@babel/parser": "^7.27.2", 368 - "@babel/types": "^7.27.1" 369 - }, 370 - "engines": { 371 - "node": ">=6.9.0" 372 - } 373 - }, 374 - "node_modules/@babel/traverse": { 375 - "version": "7.28.4", 376 - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", 377 - "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", 378 - "dev": true, 379 - "license": "MIT", 380 - "dependencies": { 381 - "@babel/code-frame": "^7.27.1", 382 - "@babel/generator": "^7.28.3", 383 - "@babel/helper-globals": "^7.28.0", 384 - "@babel/parser": "^7.28.4", 385 - "@babel/template": "^7.27.2", 386 - "@babel/types": "^7.28.4", 387 - "debug": "^4.3.1" 388 - }, 389 - "engines": { 390 - "node": ">=6.9.0" 391 - } 392 - }, 393 - "node_modules/@babel/types": { 394 - "version": "7.28.4", 395 - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", 396 - "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", 397 - "dev": true, 398 - "license": "MIT", 399 - "dependencies": { 400 - "@babel/helper-string-parser": "^7.27.1", 401 - "@babel/helper-validator-identifier": "^7.27.1" 402 - }, 403 - "engines": { 404 - "node": ">=6.9.0" 405 - } 406 - }, 407 - "node_modules/@badrap/valita": { 408 - "version": "0.4.6", 409 - "resolved": "https://registry.npmjs.org/@badrap/valita/-/valita-0.4.6.tgz", 410 - "integrity": "sha512-4kdqcjyxo/8RQ8ayjms47HCWZIF5981oE5nIenbfThKDxWXtEHKipAOWlflpPJzZx9y/JWYQkp18Awr7VuepFg==", 411 - "license": "MIT", 412 - "engines": { 413 - "node": ">= 18" 414 - } 415 - }, 416 - "node_modules/@eslint-community/eslint-utils": { 417 - "version": "4.9.0", 418 - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", 419 - "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", 420 - "dev": true, 421 - "license": "MIT", 422 - "dependencies": { 423 - "eslint-visitor-keys": "^3.4.3" 424 - }, 425 - "engines": { 426 - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 427 - }, 428 - "funding": { 429 - "url": "https://opencollective.com/eslint" 430 - }, 431 - "peerDependencies": { 432 - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" 433 - } 434 - }, 435 - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { 436 - "version": "3.4.3", 437 - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", 438 - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", 439 - "dev": true, 440 - "license": "Apache-2.0", 441 - "engines": { 442 - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 443 - }, 444 - "funding": { 445 - "url": "https://opencollective.com/eslint" 446 - } 447 - }, 448 - "node_modules/@eslint-community/regexpp": { 449 - "version": "4.12.1", 450 - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", 451 - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", 452 - "dev": true, 453 - "license": "MIT", 454 - "engines": { 455 - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" 456 - } 457 - }, 458 - "node_modules/@eslint/config-array": { 459 - "version": "0.21.0", 460 - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", 461 - "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", 462 - "dev": true, 463 - "license": "Apache-2.0", 464 - "dependencies": { 465 - "@eslint/object-schema": "^2.1.6", 466 - "debug": "^4.3.1", 467 - "minimatch": "^3.1.2" 468 - }, 469 - "engines": { 470 - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 471 - } 472 - }, 473 - "node_modules/@eslint/config-helpers": { 474 - "version": "0.4.0", 475 - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.0.tgz", 476 - "integrity": "sha512-WUFvV4WoIwW8Bv0KeKCIIEgdSiFOsulyN0xrMu+7z43q/hkOLXjvb5u7UC9jDxvRzcrbEmuZBX5yJZz1741jog==", 477 - "dev": true, 478 - "license": "Apache-2.0", 479 - "dependencies": { 480 - "@eslint/core": "^0.16.0" 481 - }, 482 - "engines": { 483 - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 484 - } 485 - }, 486 - "node_modules/@eslint/core": { 487 - "version": "0.16.0", 488 - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.16.0.tgz", 489 - "integrity": "sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==", 490 - "dev": true, 491 - "license": "Apache-2.0", 492 - "dependencies": { 493 - "@types/json-schema": "^7.0.15" 494 - }, 495 - "engines": { 496 - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 497 - } 498 - }, 499 - "node_modules/@eslint/eslintrc": { 500 - "version": "3.3.1", 501 - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", 502 - "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", 503 - "dev": true, 504 - "license": "MIT", 505 - "dependencies": { 506 - "ajv": "^6.12.4", 507 - "debug": "^4.3.2", 508 - "espree": "^10.0.1", 509 - "globals": "^14.0.0", 510 - "ignore": "^5.2.0", 511 - "import-fresh": "^3.2.1", 512 - "js-yaml": "^4.1.0", 513 - "minimatch": "^3.1.2", 514 - "strip-json-comments": "^3.1.1" 515 - }, 516 - "engines": { 517 - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 518 - }, 519 - "funding": { 520 - "url": "https://opencollective.com/eslint" 521 - } 522 - }, 523 - "node_modules/@eslint/eslintrc/node_modules/globals": { 524 - "version": "14.0.0", 525 - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", 526 - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", 527 - "dev": true, 528 - "license": "MIT", 529 - "engines": { 530 - "node": ">=18" 531 - }, 532 - "funding": { 533 - "url": "https://github.com/sponsors/sindresorhus" 534 - } 535 - }, 536 - "node_modules/@eslint/js": { 537 - "version": "9.37.0", 538 - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.37.0.tgz", 539 - "integrity": "sha512-jaS+NJ+hximswBG6pjNX0uEJZkrT0zwpVi3BA3vX22aFGjJjmgSTSmPpZCRKmoBL5VY/M6p0xsSJx7rk7sy5gg==", 540 - "dev": true, 541 - "license": "MIT", 542 - "engines": { 543 - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 544 - }, 545 - "funding": { 546 - "url": "https://eslint.org/donate" 547 - } 548 - }, 549 - "node_modules/@eslint/object-schema": { 550 - "version": "2.1.6", 551 - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", 552 - "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", 553 - "dev": true, 554 - "license": "Apache-2.0", 555 - "engines": { 556 - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 557 - } 558 - }, 559 - "node_modules/@eslint/plugin-kit": { 560 - "version": "0.4.0", 561 - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.0.tgz", 562 - "integrity": "sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A==", 563 - "dev": true, 564 - "license": "Apache-2.0", 565 - "dependencies": { 566 - "@eslint/core": "^0.16.0", 567 - "levn": "^0.4.1" 568 - }, 569 - "engines": { 570 - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 571 - } 572 - }, 573 - "node_modules/@humanfs/core": { 574 - "version": "0.19.1", 575 - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", 576 - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", 577 - "dev": true, 578 - "license": "Apache-2.0", 579 - "engines": { 580 - "node": ">=18.18.0" 581 - } 582 - }, 583 - "node_modules/@humanfs/node": { 584 - "version": "0.16.7", 585 - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", 586 - "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", 587 - "dev": true, 588 - "license": "Apache-2.0", 589 - "dependencies": { 590 - "@humanfs/core": "^0.19.1", 591 - "@humanwhocodes/retry": "^0.4.0" 592 - }, 593 - "engines": { 594 - "node": ">=18.18.0" 595 - } 596 - }, 597 - "node_modules/@humanwhocodes/module-importer": { 598 - "version": "1.0.1", 599 - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", 600 - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", 601 - "dev": true, 602 - "license": "Apache-2.0", 603 - "engines": { 604 - "node": ">=12.22" 605 - }, 606 - "funding": { 607 - "type": "github", 608 - "url": "https://github.com/sponsors/nzakas" 609 - } 610 - }, 611 - "node_modules/@humanwhocodes/retry": { 612 - "version": "0.4.3", 613 - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", 614 - "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", 615 - "dev": true, 616 - "license": "Apache-2.0", 617 - "engines": { 618 - "node": ">=18.18" 619 - }, 620 - "funding": { 621 - "type": "github", 622 - "url": "https://github.com/sponsors/nzakas" 623 - } 624 - }, 625 - "node_modules/@jridgewell/gen-mapping": { 626 - "version": "0.3.13", 627 - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", 628 - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", 629 - "dev": true, 630 - "license": "MIT", 631 - "dependencies": { 632 - "@jridgewell/sourcemap-codec": "^1.5.0", 633 - "@jridgewell/trace-mapping": "^0.3.24" 634 - } 635 - }, 636 - "node_modules/@jridgewell/remapping": { 637 - "version": "2.3.5", 638 - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", 639 - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", 640 - "dev": true, 641 - "license": "MIT", 642 - "dependencies": { 643 - "@jridgewell/gen-mapping": "^0.3.5", 644 - "@jridgewell/trace-mapping": "^0.3.24" 645 - } 646 - }, 647 - "node_modules/@jridgewell/resolve-uri": { 648 - "version": "3.1.2", 649 - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", 650 - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", 651 - "dev": true, 652 - "license": "MIT", 653 - "engines": { 654 - "node": ">=6.0.0" 655 - } 656 - }, 657 - "node_modules/@jridgewell/sourcemap-codec": { 658 - "version": "1.5.5", 659 - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", 660 - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", 661 - "dev": true, 662 - "license": "MIT" 663 - }, 664 - "node_modules/@jridgewell/trace-mapping": { 665 - "version": "0.3.31", 666 - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", 667 - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", 668 - "dev": true, 669 - "license": "MIT", 670 - "dependencies": { 671 - "@jridgewell/resolve-uri": "^3.1.0", 672 - "@jridgewell/sourcemap-codec": "^1.4.14" 673 - } 674 - }, 675 - "node_modules/@nodelib/fs.scandir": { 676 - "version": "2.1.5", 677 - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", 678 - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", 679 - "dev": true, 680 - "license": "MIT", 681 - "dependencies": { 682 - "@nodelib/fs.stat": "2.0.5", 683 - "run-parallel": "^1.1.9" 684 - }, 685 - "engines": { 686 - "node": ">= 8" 687 - } 688 - }, 689 - "node_modules/@nodelib/fs.stat": { 690 - "version": "2.0.5", 691 - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", 692 - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", 693 - "dev": true, 694 - "license": "MIT", 695 - "engines": { 696 - "node": ">= 8" 697 - } 698 - }, 699 - "node_modules/@nodelib/fs.walk": { 700 - "version": "1.2.8", 701 - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", 702 - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", 703 - "dev": true, 704 - "license": "MIT", 705 - "dependencies": { 706 - "@nodelib/fs.scandir": "2.1.5", 707 - "fastq": "^1.6.0" 708 - }, 709 - "engines": { 710 - "node": ">= 8" 711 - } 712 - }, 713 - "node_modules/@oxc-project/runtime": { 714 - "version": "0.92.0", 715 - "resolved": "https://registry.npmjs.org/@oxc-project/runtime/-/runtime-0.92.0.tgz", 716 - "integrity": "sha512-Z7x2dZOmznihvdvCvLKMl+nswtOSVxS2H2ocar+U9xx6iMfTp0VGIrX6a4xB1v80IwOPC7dT1LXIJrY70Xu3Jw==", 717 - "dev": true, 718 - "license": "MIT", 719 - "engines": { 720 - "node": "^20.19.0 || >=22.12.0" 721 - } 722 - }, 723 - "node_modules/@oxc-project/types": { 724 - "version": "0.93.0", 725 - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.93.0.tgz", 726 - "integrity": "sha512-yNtwmWZIBtJsMr5TEfoZFDxIWV6OdScOpza/f5YxbqUMJk+j6QX3Cf3jgZShGEFYWQJ5j9mJ6jM0tZHu2J9Yrg==", 727 - "dev": true, 728 - "license": "MIT", 729 - "funding": { 730 - "url": "https://github.com/sponsors/Boshen" 731 - } 732 - }, 733 - "node_modules/@rolldown/binding-darwin-arm64": { 734 - "version": "1.0.0-beta.41", 735 - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-beta.41.tgz", 736 - "integrity": "sha512-XGCzqfjdk7550PlyZRTBKbypXrB7ATtXhw/+bjtxnklLQs0mKP/XkQVOKyn9qGKSlvH8I56JLYryVxl0PCvSNw==", 737 - "cpu": [ 738 - "arm64" 739 - ], 740 - "dev": true, 741 - "license": "MIT", 742 - "optional": true, 743 - "os": [ 744 - "darwin" 745 - ], 746 - "engines": { 747 - "node": "^20.19.0 || >=22.12.0" 748 - } 749 - }, 750 - "node_modules/@rolldown/pluginutils": { 751 - "version": "1.0.0-beta.38", 752 - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.38.tgz", 753 - "integrity": "sha512-N/ICGKleNhA5nc9XXQG/kkKHJ7S55u0x0XUJbbkmdCnFuoRkM1Il12q9q0eX19+M7KKUEPw/daUPIRnxhcxAIw==", 754 - "dev": true, 755 - "license": "MIT" 756 - }, 757 - "node_modules/@standard-schema/spec": { 758 - "version": "1.0.0", 759 - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", 760 - "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", 761 - "license": "MIT" 762 - }, 763 - "node_modules/@types/babel__core": { 764 - "version": "7.20.5", 765 - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", 766 - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", 767 - "dev": true, 768 - "license": "MIT", 769 - "dependencies": { 770 - "@babel/parser": "^7.20.7", 771 - "@babel/types": "^7.20.7", 772 - "@types/babel__generator": "*", 773 - "@types/babel__template": "*", 774 - "@types/babel__traverse": "*" 775 - } 776 - }, 777 - "node_modules/@types/babel__generator": { 778 - "version": "7.27.0", 779 - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", 780 - "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", 781 - "dev": true, 782 - "license": "MIT", 783 - "dependencies": { 784 - "@babel/types": "^7.0.0" 785 - } 786 - }, 787 - "node_modules/@types/babel__template": { 788 - "version": "7.4.4", 789 - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", 790 - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", 791 - "dev": true, 792 - "license": "MIT", 793 - "dependencies": { 794 - "@babel/parser": "^7.1.0", 795 - "@babel/types": "^7.0.0" 796 - } 797 - }, 798 - "node_modules/@types/babel__traverse": { 799 - "version": "7.28.0", 800 - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", 801 - "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", 802 - "dev": true, 803 - "license": "MIT", 804 - "dependencies": { 805 - "@babel/types": "^7.28.2" 806 - } 807 - }, 808 - "node_modules/@types/estree": { 809 - "version": "1.0.8", 810 - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", 811 - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", 812 - "dev": true, 813 - "license": "MIT" 814 - }, 815 - "node_modules/@types/json-schema": { 816 - "version": "7.0.15", 817 - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", 818 - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", 819 - "dev": true, 820 - "license": "MIT" 821 - }, 822 - "node_modules/@types/node": { 823 - "version": "24.7.0", 824 - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.7.0.tgz", 825 - "integrity": "sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw==", 826 - "dev": true, 827 - "license": "MIT", 828 - "dependencies": { 829 - "undici-types": "~7.14.0" 830 - } 831 - }, 832 - "node_modules/@types/react": { 833 - "version": "19.2.2", 834 - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", 835 - "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", 836 - "dev": true, 837 - "license": "MIT", 838 - "dependencies": { 839 - "csstype": "^3.0.2" 840 - } 841 - }, 842 - "node_modules/@types/react-dom": { 843 - "version": "19.2.1", 844 - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.1.tgz", 845 - "integrity": "sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==", 846 - "dev": true, 847 - "license": "MIT", 848 - "peerDependencies": { 849 - "@types/react": "^19.2.0" 850 - } 851 - }, 852 - "node_modules/@typescript-eslint/eslint-plugin": { 853 - "version": "8.46.0", 854 - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.0.tgz", 855 - "integrity": "sha512-hA8gxBq4ukonVXPy0OKhiaUh/68D0E88GSmtC1iAEnGaieuDi38LhS7jdCHRLi6ErJBNDGCzvh5EnzdPwUc0DA==", 856 - "dev": true, 857 - "license": "MIT", 858 - "dependencies": { 859 - "@eslint-community/regexpp": "^4.10.0", 860 - "@typescript-eslint/scope-manager": "8.46.0", 861 - "@typescript-eslint/type-utils": "8.46.0", 862 - "@typescript-eslint/utils": "8.46.0", 863 - "@typescript-eslint/visitor-keys": "8.46.0", 864 - "graphemer": "^1.4.0", 865 - "ignore": "^7.0.0", 866 - "natural-compare": "^1.4.0", 867 - "ts-api-utils": "^2.1.0" 868 - }, 869 - "engines": { 870 - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 871 - }, 872 - "funding": { 873 - "type": "opencollective", 874 - "url": "https://opencollective.com/typescript-eslint" 875 - }, 876 - "peerDependencies": { 877 - "@typescript-eslint/parser": "^8.46.0", 878 - "eslint": "^8.57.0 || ^9.0.0", 879 - "typescript": ">=4.8.4 <6.0.0" 880 - } 881 - }, 882 - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { 883 - "version": "7.0.5", 884 - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", 885 - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", 886 - "dev": true, 887 - "license": "MIT", 888 - "engines": { 889 - "node": ">= 4" 890 - } 891 - }, 892 - "node_modules/@typescript-eslint/parser": { 893 - "version": "8.46.0", 894 - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.0.tgz", 895 - "integrity": "sha512-n1H6IcDhmmUEG7TNVSspGmiHHutt7iVKtZwRppD7e04wha5MrkV1h3pti9xQLcCMt6YWsncpoT0HMjkH1FNwWQ==", 896 - "dev": true, 897 - "license": "MIT", 898 - "dependencies": { 899 - "@typescript-eslint/scope-manager": "8.46.0", 900 - "@typescript-eslint/types": "8.46.0", 901 - "@typescript-eslint/typescript-estree": "8.46.0", 902 - "@typescript-eslint/visitor-keys": "8.46.0", 903 - "debug": "^4.3.4" 904 - }, 905 - "engines": { 906 - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 907 - }, 908 - "funding": { 909 - "type": "opencollective", 910 - "url": "https://opencollective.com/typescript-eslint" 911 - }, 912 - "peerDependencies": { 913 - "eslint": "^8.57.0 || ^9.0.0", 914 - "typescript": ">=4.8.4 <6.0.0" 915 - } 916 - }, 917 - "node_modules/@typescript-eslint/project-service": { 918 - "version": "8.46.0", 919 - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.46.0.tgz", 920 - "integrity": "sha512-OEhec0mH+U5Je2NZOeK1AbVCdm0ChyapAyTeXVIYTPXDJ3F07+cu87PPXcGoYqZ7M9YJVvFnfpGg1UmCIqM+QQ==", 921 - "dev": true, 922 - "license": "MIT", 923 - "dependencies": { 924 - "@typescript-eslint/tsconfig-utils": "^8.46.0", 925 - "@typescript-eslint/types": "^8.46.0", 926 - "debug": "^4.3.4" 927 - }, 928 - "engines": { 929 - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 930 - }, 931 - "funding": { 932 - "type": "opencollective", 933 - "url": "https://opencollective.com/typescript-eslint" 934 - }, 935 - "peerDependencies": { 936 - "typescript": ">=4.8.4 <6.0.0" 937 - } 938 - }, 939 - "node_modules/@typescript-eslint/scope-manager": { 940 - "version": "8.46.0", 941 - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.46.0.tgz", 942 - "integrity": "sha512-lWETPa9XGcBes4jqAMYD9fW0j4n6hrPtTJwWDmtqgFO/4HF4jmdH/Q6wggTw5qIT5TXjKzbt7GsZUBnWoO3dqw==", 943 - "dev": true, 944 - "license": "MIT", 945 - "dependencies": { 946 - "@typescript-eslint/types": "8.46.0", 947 - "@typescript-eslint/visitor-keys": "8.46.0" 948 - }, 949 - "engines": { 950 - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 951 - }, 952 - "funding": { 953 - "type": "opencollective", 954 - "url": "https://opencollective.com/typescript-eslint" 955 - } 956 - }, 957 - "node_modules/@typescript-eslint/tsconfig-utils": { 958 - "version": "8.46.0", 959 - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.0.tgz", 960 - "integrity": "sha512-WrYXKGAHY836/N7zoK/kzi6p8tXFhasHh8ocFL9VZSAkvH956gfeRfcnhs3xzRy8qQ/dq3q44v1jvQieMFg2cw==", 961 - "dev": true, 962 - "license": "MIT", 963 - "engines": { 964 - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 965 - }, 966 - "funding": { 967 - "type": "opencollective", 968 - "url": "https://opencollective.com/typescript-eslint" 969 - }, 970 - "peerDependencies": { 971 - "typescript": ">=4.8.4 <6.0.0" 972 - } 973 - }, 974 - "node_modules/@typescript-eslint/type-utils": { 975 - "version": "8.46.0", 976 - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.46.0.tgz", 977 - "integrity": "sha512-hy+lvYV1lZpVs2jRaEYvgCblZxUoJiPyCemwbQZ+NGulWkQRy0HRPYAoef/CNSzaLt+MLvMptZsHXHlkEilaeg==", 978 - "dev": true, 979 - "license": "MIT", 980 - "dependencies": { 981 - "@typescript-eslint/types": "8.46.0", 982 - "@typescript-eslint/typescript-estree": "8.46.0", 983 - "@typescript-eslint/utils": "8.46.0", 984 - "debug": "^4.3.4", 985 - "ts-api-utils": "^2.1.0" 986 - }, 987 - "engines": { 988 - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 989 - }, 990 - "funding": { 991 - "type": "opencollective", 992 - "url": "https://opencollective.com/typescript-eslint" 993 - }, 994 - "peerDependencies": { 995 - "eslint": "^8.57.0 || ^9.0.0", 996 - "typescript": ">=4.8.4 <6.0.0" 997 - } 998 - }, 999 - "node_modules/@typescript-eslint/types": { 1000 - "version": "8.46.0", 1001 - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.0.tgz", 1002 - "integrity": "sha512-bHGGJyVjSE4dJJIO5yyEWt/cHyNwga/zXGJbJJ8TiO01aVREK6gCTu3L+5wrkb1FbDkQ+TKjMNe9R/QQQP9+rA==", 1003 - "dev": true, 1004 - "license": "MIT", 1005 - "engines": { 1006 - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1007 - }, 1008 - "funding": { 1009 - "type": "opencollective", 1010 - "url": "https://opencollective.com/typescript-eslint" 1011 - } 1012 - }, 1013 - "node_modules/@typescript-eslint/typescript-estree": { 1014 - "version": "8.46.0", 1015 - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.0.tgz", 1016 - "integrity": "sha512-ekDCUfVpAKWJbRfm8T1YRrCot1KFxZn21oV76v5Fj4tr7ELyk84OS+ouvYdcDAwZL89WpEkEj2DKQ+qg//+ucg==", 1017 - "dev": true, 1018 - "license": "MIT", 1019 - "dependencies": { 1020 - "@typescript-eslint/project-service": "8.46.0", 1021 - "@typescript-eslint/tsconfig-utils": "8.46.0", 1022 - "@typescript-eslint/types": "8.46.0", 1023 - "@typescript-eslint/visitor-keys": "8.46.0", 1024 - "debug": "^4.3.4", 1025 - "fast-glob": "^3.3.2", 1026 - "is-glob": "^4.0.3", 1027 - "minimatch": "^9.0.4", 1028 - "semver": "^7.6.0", 1029 - "ts-api-utils": "^2.1.0" 1030 - }, 1031 - "engines": { 1032 - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1033 - }, 1034 - "funding": { 1035 - "type": "opencollective", 1036 - "url": "https://opencollective.com/typescript-eslint" 1037 - }, 1038 - "peerDependencies": { 1039 - "typescript": ">=4.8.4 <6.0.0" 1040 - } 1041 - }, 1042 - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { 1043 - "version": "2.0.2", 1044 - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", 1045 - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", 1046 - "dev": true, 1047 - "license": "MIT", 1048 - "dependencies": { 1049 - "balanced-match": "^1.0.0" 1050 - } 1051 - }, 1052 - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { 1053 - "version": "9.0.5", 1054 - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", 1055 - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", 1056 - "dev": true, 1057 - "license": "ISC", 1058 - "dependencies": { 1059 - "brace-expansion": "^2.0.1" 1060 - }, 1061 - "engines": { 1062 - "node": ">=16 || 14 >=14.17" 1063 - }, 1064 - "funding": { 1065 - "url": "https://github.com/sponsors/isaacs" 1066 - } 1067 - }, 1068 - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { 1069 - "version": "7.7.3", 1070 - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", 1071 - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", 1072 - "dev": true, 1073 - "license": "ISC", 1074 - "bin": { 1075 - "semver": "bin/semver.js" 1076 - }, 1077 - "engines": { 1078 - "node": ">=10" 1079 - } 1080 - }, 1081 - "node_modules/@typescript-eslint/utils": { 1082 - "version": "8.46.0", 1083 - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.46.0.tgz", 1084 - "integrity": "sha512-nD6yGWPj1xiOm4Gk0k6hLSZz2XkNXhuYmyIrOWcHoPuAhjT9i5bAG+xbWPgFeNR8HPHHtpNKdYUXJl/D3x7f5g==", 1085 - "dev": true, 1086 - "license": "MIT", 1087 - "dependencies": { 1088 - "@eslint-community/eslint-utils": "^4.7.0", 1089 - "@typescript-eslint/scope-manager": "8.46.0", 1090 - "@typescript-eslint/types": "8.46.0", 1091 - "@typescript-eslint/typescript-estree": "8.46.0" 1092 - }, 1093 - "engines": { 1094 - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1095 - }, 1096 - "funding": { 1097 - "type": "opencollective", 1098 - "url": "https://opencollective.com/typescript-eslint" 1099 - }, 1100 - "peerDependencies": { 1101 - "eslint": "^8.57.0 || ^9.0.0", 1102 - "typescript": ">=4.8.4 <6.0.0" 1103 - } 1104 - }, 1105 - "node_modules/@typescript-eslint/visitor-keys": { 1106 - "version": "8.46.0", 1107 - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.0.tgz", 1108 - "integrity": "sha512-FrvMpAK+hTbFy7vH5j1+tMYHMSKLE6RzluFJlkFNKD0p9YsUT75JlBSmr5so3QRzvMwU5/bIEdeNrxm8du8l3Q==", 1109 - "dev": true, 1110 - "license": "MIT", 1111 - "dependencies": { 1112 - "@typescript-eslint/types": "8.46.0", 1113 - "eslint-visitor-keys": "^4.2.1" 1114 - }, 1115 - "engines": { 1116 - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1117 - }, 1118 - "funding": { 1119 - "type": "opencollective", 1120 - "url": "https://opencollective.com/typescript-eslint" 1121 - } 1122 - }, 1123 - "node_modules/@vitejs/plugin-react": { 1124 - "version": "5.0.4", 1125 - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.0.4.tgz", 1126 - "integrity": "sha512-La0KD0vGkVkSk6K+piWDKRUyg8Rl5iAIKRMH0vMJI0Eg47bq1eOxmoObAaQG37WMW9MSyk7Cs8EIWwJC1PtzKA==", 1127 - "dev": true, 1128 - "license": "MIT", 1129 - "dependencies": { 1130 - "@babel/core": "^7.28.4", 1131 - "@babel/plugin-transform-react-jsx-self": "^7.27.1", 1132 - "@babel/plugin-transform-react-jsx-source": "^7.27.1", 1133 - "@rolldown/pluginutils": "1.0.0-beta.38", 1134 - "@types/babel__core": "^7.20.5", 1135 - "react-refresh": "^0.17.0" 1136 - }, 1137 - "engines": { 1138 - "node": "^20.19.0 || >=22.12.0" 1139 - }, 1140 - "peerDependencies": { 1141 - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" 1142 - } 1143 - }, 1144 - "node_modules/acorn": { 1145 - "version": "8.15.0", 1146 - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", 1147 - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", 1148 - "dev": true, 1149 - "license": "MIT", 1150 - "bin": { 1151 - "acorn": "bin/acorn" 1152 - }, 1153 - "engines": { 1154 - "node": ">=0.4.0" 1155 - } 1156 - }, 1157 - "node_modules/acorn-jsx": { 1158 - "version": "5.3.2", 1159 - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", 1160 - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", 1161 - "dev": true, 1162 - "license": "MIT", 1163 - "peerDependencies": { 1164 - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" 1165 - } 1166 - }, 1167 - "node_modules/ajv": { 1168 - "version": "6.12.6", 1169 - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 1170 - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 1171 - "dev": true, 1172 - "license": "MIT", 1173 - "dependencies": { 1174 - "fast-deep-equal": "^3.1.1", 1175 - "fast-json-stable-stringify": "^2.0.0", 1176 - "json-schema-traverse": "^0.4.1", 1177 - "uri-js": "^4.2.2" 1178 - }, 1179 - "funding": { 1180 - "type": "github", 1181 - "url": "https://github.com/sponsors/epoberezkin" 1182 - } 1183 - }, 1184 - "node_modules/ansi-styles": { 1185 - "version": "4.3.0", 1186 - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 1187 - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 1188 - "dev": true, 1189 - "license": "MIT", 1190 - "dependencies": { 1191 - "color-convert": "^2.0.1" 1192 - }, 1193 - "engines": { 1194 - "node": ">=8" 1195 - }, 1196 - "funding": { 1197 - "url": "https://github.com/chalk/ansi-styles?sponsor=1" 1198 - } 1199 - }, 1200 - "node_modules/ansis": { 1201 - "version": "4.2.0", 1202 - "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.2.0.tgz", 1203 - "integrity": "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==", 1204 - "dev": true, 1205 - "license": "ISC", 1206 - "engines": { 1207 - "node": ">=14" 1208 - } 1209 - }, 1210 - "node_modules/argparse": { 1211 - "version": "2.0.1", 1212 - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 1213 - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", 1214 - "dev": true, 1215 - "license": "Python-2.0" 1216 - }, 1217 - "node_modules/balanced-match": { 1218 - "version": "1.0.2", 1219 - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 1220 - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 1221 - "dev": true, 1222 - "license": "MIT" 1223 - }, 1224 - "node_modules/baseline-browser-mapping": { 1225 - "version": "2.8.13", 1226 - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.13.tgz", 1227 - "integrity": "sha512-7s16KR8io8nIBWQyCYhmFhd+ebIzb9VKTzki+wOJXHTxTnV6+mFGH3+Jwn1zoKaY9/H9T/0BcKCZnzXljPnpSQ==", 1228 - "dev": true, 1229 - "license": "Apache-2.0", 1230 - "bin": { 1231 - "baseline-browser-mapping": "dist/cli.js" 1232 - } 1233 - }, 1234 - "node_modules/brace-expansion": { 1235 - "version": "1.1.12", 1236 - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", 1237 - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", 1238 - "dev": true, 1239 - "license": "MIT", 1240 - "dependencies": { 1241 - "balanced-match": "^1.0.0", 1242 - "concat-map": "0.0.1" 1243 - } 1244 - }, 1245 - "node_modules/braces": { 1246 - "version": "3.0.3", 1247 - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", 1248 - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", 1249 - "dev": true, 1250 - "license": "MIT", 1251 - "dependencies": { 1252 - "fill-range": "^7.1.1" 1253 - }, 1254 - "engines": { 1255 - "node": ">=8" 1256 - } 1257 - }, 1258 - "node_modules/browserslist": { 1259 - "version": "4.26.3", 1260 - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.3.tgz", 1261 - "integrity": "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==", 1262 - "dev": true, 1263 - "funding": [ 1264 - { 1265 - "type": "opencollective", 1266 - "url": "https://opencollective.com/browserslist" 1267 - }, 1268 - { 1269 - "type": "tidelift", 1270 - "url": "https://tidelift.com/funding/github/npm/browserslist" 1271 - }, 1272 - { 1273 - "type": "github", 1274 - "url": "https://github.com/sponsors/ai" 1275 - } 1276 - ], 1277 - "license": "MIT", 1278 - "dependencies": { 1279 - "baseline-browser-mapping": "^2.8.9", 1280 - "caniuse-lite": "^1.0.30001746", 1281 - "electron-to-chromium": "^1.5.227", 1282 - "node-releases": "^2.0.21", 1283 - "update-browserslist-db": "^1.1.3" 1284 - }, 1285 - "bin": { 1286 - "browserslist": "cli.js" 1287 - }, 1288 - "engines": { 1289 - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" 1290 - } 1291 - }, 1292 - "node_modules/callsites": { 1293 - "version": "3.1.0", 1294 - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", 1295 - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", 1296 - "dev": true, 1297 - "license": "MIT", 1298 - "engines": { 1299 - "node": ">=6" 1300 - } 1301 - }, 1302 - "node_modules/caniuse-lite": { 1303 - "version": "1.0.30001748", 1304 - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001748.tgz", 1305 - "integrity": "sha512-5P5UgAr0+aBmNiplks08JLw+AW/XG/SurlgZLgB1dDLfAw7EfRGxIwzPHxdSCGY/BTKDqIVyJL87cCN6s0ZR0w==", 1306 - "dev": true, 1307 - "funding": [ 1308 - { 1309 - "type": "opencollective", 1310 - "url": "https://opencollective.com/browserslist" 1311 - }, 1312 - { 1313 - "type": "tidelift", 1314 - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" 1315 - }, 1316 - { 1317 - "type": "github", 1318 - "url": "https://github.com/sponsors/ai" 1319 - } 1320 - ], 1321 - "license": "CC-BY-4.0" 1322 - }, 1323 - "node_modules/chalk": { 1324 - "version": "4.1.2", 1325 - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 1326 - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 1327 - "dev": true, 1328 - "license": "MIT", 1329 - "dependencies": { 1330 - "ansi-styles": "^4.1.0", 1331 - "supports-color": "^7.1.0" 1332 - }, 1333 - "engines": { 1334 - "node": ">=10" 1335 - }, 1336 - "funding": { 1337 - "url": "https://github.com/chalk/chalk?sponsor=1" 1338 - } 1339 - }, 1340 - "node_modules/color-convert": { 1341 - "version": "2.0.1", 1342 - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 1343 - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 1344 - "dev": true, 1345 - "license": "MIT", 1346 - "dependencies": { 1347 - "color-name": "~1.1.4" 1348 - }, 1349 - "engines": { 1350 - "node": ">=7.0.0" 1351 - } 1352 - }, 1353 - "node_modules/color-name": { 1354 - "version": "1.1.4", 1355 - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 1356 - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 1357 - "dev": true, 1358 - "license": "MIT" 1359 - }, 1360 - "node_modules/concat-map": { 1361 - "version": "0.0.1", 1362 - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 1363 - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 1364 - "dev": true, 1365 - "license": "MIT" 1366 - }, 1367 - "node_modules/convert-source-map": { 1368 - "version": "2.0.0", 1369 - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", 1370 - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", 1371 - "dev": true, 1372 - "license": "MIT" 1373 - }, 1374 - "node_modules/cross-spawn": { 1375 - "version": "7.0.6", 1376 - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", 1377 - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", 1378 - "dev": true, 1379 - "license": "MIT", 1380 - "dependencies": { 1381 - "path-key": "^3.1.0", 1382 - "shebang-command": "^2.0.0", 1383 - "which": "^2.0.1" 1384 - }, 1385 - "engines": { 1386 - "node": ">= 8" 1387 - } 1388 - }, 1389 - "node_modules/csstype": { 1390 - "version": "3.1.3", 1391 - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", 1392 - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", 1393 - "dev": true, 1394 - "license": "MIT" 1395 - }, 1396 - "node_modules/debug": { 1397 - "version": "4.4.3", 1398 - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", 1399 - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", 1400 - "dev": true, 1401 - "license": "MIT", 1402 - "dependencies": { 1403 - "ms": "^2.1.3" 1404 - }, 1405 - "engines": { 1406 - "node": ">=6.0" 1407 - }, 1408 - "peerDependenciesMeta": { 1409 - "supports-color": { 1410 - "optional": true 1411 - } 1412 - } 1413 - }, 1414 - "node_modules/deep-is": { 1415 - "version": "0.1.4", 1416 - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", 1417 - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", 1418 - "dev": true, 1419 - "license": "MIT" 1420 - }, 1421 - "node_modules/detect-libc": { 1422 - "version": "2.1.2", 1423 - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", 1424 - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", 1425 - "dev": true, 1426 - "license": "Apache-2.0", 1427 - "engines": { 1428 - "node": ">=8" 1429 - } 1430 - }, 1431 - "node_modules/electron-to-chromium": { 1432 - "version": "1.5.232", 1433 - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.232.tgz", 1434 - "integrity": "sha512-ENirSe7wf8WzyPCibqKUG1Cg43cPaxH4wRR7AJsX7MCABCHBIOFqvaYODSLKUuZdraxUTHRE/0A2Aq8BYKEHOg==", 1435 - "dev": true, 1436 - "license": "ISC" 1437 - }, 1438 - "node_modules/escalade": { 1439 - "version": "3.2.0", 1440 - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", 1441 - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", 1442 - "dev": true, 1443 - "license": "MIT", 1444 - "engines": { 1445 - "node": ">=6" 1446 - } 1447 - }, 1448 - "node_modules/escape-string-regexp": { 1449 - "version": "4.0.0", 1450 - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 1451 - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 1452 - "dev": true, 1453 - "license": "MIT", 1454 - "engines": { 1455 - "node": ">=10" 1456 - }, 1457 - "funding": { 1458 - "url": "https://github.com/sponsors/sindresorhus" 1459 - } 1460 - }, 1461 - "node_modules/eslint": { 1462 - "version": "9.37.0", 1463 - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.37.0.tgz", 1464 - "integrity": "sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==", 1465 - "dev": true, 1466 - "license": "MIT", 1467 - "dependencies": { 1468 - "@eslint-community/eslint-utils": "^4.8.0", 1469 - "@eslint-community/regexpp": "^4.12.1", 1470 - "@eslint/config-array": "^0.21.0", 1471 - "@eslint/config-helpers": "^0.4.0", 1472 - "@eslint/core": "^0.16.0", 1473 - "@eslint/eslintrc": "^3.3.1", 1474 - "@eslint/js": "9.37.0", 1475 - "@eslint/plugin-kit": "^0.4.0", 1476 - "@humanfs/node": "^0.16.6", 1477 - "@humanwhocodes/module-importer": "^1.0.1", 1478 - "@humanwhocodes/retry": "^0.4.2", 1479 - "@types/estree": "^1.0.6", 1480 - "@types/json-schema": "^7.0.15", 1481 - "ajv": "^6.12.4", 1482 - "chalk": "^4.0.0", 1483 - "cross-spawn": "^7.0.6", 1484 - "debug": "^4.3.2", 1485 - "escape-string-regexp": "^4.0.0", 1486 - "eslint-scope": "^8.4.0", 1487 - "eslint-visitor-keys": "^4.2.1", 1488 - "espree": "^10.4.0", 1489 - "esquery": "^1.5.0", 1490 - "esutils": "^2.0.2", 1491 - "fast-deep-equal": "^3.1.3", 1492 - "file-entry-cache": "^8.0.0", 1493 - "find-up": "^5.0.0", 1494 - "glob-parent": "^6.0.2", 1495 - "ignore": "^5.2.0", 1496 - "imurmurhash": "^0.1.4", 1497 - "is-glob": "^4.0.0", 1498 - "json-stable-stringify-without-jsonify": "^1.0.1", 1499 - "lodash.merge": "^4.6.2", 1500 - "minimatch": "^3.1.2", 1501 - "natural-compare": "^1.4.0", 1502 - "optionator": "^0.9.3" 1503 - }, 1504 - "bin": { 1505 - "eslint": "bin/eslint.js" 1506 - }, 1507 - "engines": { 1508 - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1509 - }, 1510 - "funding": { 1511 - "url": "https://eslint.org/donate" 1512 - }, 1513 - "peerDependencies": { 1514 - "jiti": "*" 1515 - }, 1516 - "peerDependenciesMeta": { 1517 - "jiti": { 1518 - "optional": true 1519 - } 1520 - } 1521 - }, 1522 - "node_modules/eslint-plugin-react-hooks": { 1523 - "version": "5.2.0", 1524 - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", 1525 - "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", 1526 - "dev": true, 1527 - "license": "MIT", 1528 - "engines": { 1529 - "node": ">=10" 1530 - }, 1531 - "peerDependencies": { 1532 - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" 1533 - } 1534 - }, 1535 - "node_modules/eslint-plugin-react-refresh": { 1536 - "version": "0.4.23", 1537 - "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.23.tgz", 1538 - "integrity": "sha512-G4j+rv0NmbIR45kni5xJOrYvCtyD3/7LjpVH8MPPcudXDcNu8gv+4ATTDXTtbRR8rTCM5HxECvCSsRmxKnWDsA==", 1539 - "dev": true, 1540 - "license": "MIT", 1541 - "peerDependencies": { 1542 - "eslint": ">=8.40" 1543 - } 1544 - }, 1545 - "node_modules/eslint-scope": { 1546 - "version": "8.4.0", 1547 - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", 1548 - "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", 1549 - "dev": true, 1550 - "license": "BSD-2-Clause", 1551 - "dependencies": { 1552 - "esrecurse": "^4.3.0", 1553 - "estraverse": "^5.2.0" 1554 - }, 1555 - "engines": { 1556 - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1557 - }, 1558 - "funding": { 1559 - "url": "https://opencollective.com/eslint" 1560 - } 1561 - }, 1562 - "node_modules/eslint-visitor-keys": { 1563 - "version": "4.2.1", 1564 - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", 1565 - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", 1566 - "dev": true, 1567 - "license": "Apache-2.0", 1568 - "engines": { 1569 - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1570 - }, 1571 - "funding": { 1572 - "url": "https://opencollective.com/eslint" 1573 - } 1574 - }, 1575 - "node_modules/esm-env": { 1576 - "version": "1.2.2", 1577 - "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz", 1578 - "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==", 1579 - "license": "MIT" 1580 - }, 1581 - "node_modules/espree": { 1582 - "version": "10.4.0", 1583 - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", 1584 - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", 1585 - "dev": true, 1586 - "license": "BSD-2-Clause", 1587 - "dependencies": { 1588 - "acorn": "^8.15.0", 1589 - "acorn-jsx": "^5.3.2", 1590 - "eslint-visitor-keys": "^4.2.1" 1591 - }, 1592 - "engines": { 1593 - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1594 - }, 1595 - "funding": { 1596 - "url": "https://opencollective.com/eslint" 1597 - } 1598 - }, 1599 - "node_modules/esquery": { 1600 - "version": "1.6.0", 1601 - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", 1602 - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", 1603 - "dev": true, 1604 - "license": "BSD-3-Clause", 1605 - "dependencies": { 1606 - "estraverse": "^5.1.0" 1607 - }, 1608 - "engines": { 1609 - "node": ">=0.10" 1610 - } 1611 - }, 1612 - "node_modules/esrecurse": { 1613 - "version": "4.3.0", 1614 - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", 1615 - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", 1616 - "dev": true, 1617 - "license": "BSD-2-Clause", 1618 - "dependencies": { 1619 - "estraverse": "^5.2.0" 1620 - }, 1621 - "engines": { 1622 - "node": ">=4.0" 1623 - } 1624 - }, 1625 - "node_modules/estraverse": { 1626 - "version": "5.3.0", 1627 - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", 1628 - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", 1629 - "dev": true, 1630 - "license": "BSD-2-Clause", 1631 - "engines": { 1632 - "node": ">=4.0" 1633 - } 1634 - }, 1635 - "node_modules/esutils": { 1636 - "version": "2.0.3", 1637 - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", 1638 - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", 1639 - "dev": true, 1640 - "license": "BSD-2-Clause", 1641 - "engines": { 1642 - "node": ">=0.10.0" 1643 - } 1644 - }, 1645 - "node_modules/fast-deep-equal": { 1646 - "version": "3.1.3", 1647 - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 1648 - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", 1649 - "dev": true, 1650 - "license": "MIT" 1651 - }, 1652 - "node_modules/fast-glob": { 1653 - "version": "3.3.3", 1654 - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", 1655 - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", 1656 - "dev": true, 1657 - "license": "MIT", 1658 - "dependencies": { 1659 - "@nodelib/fs.stat": "^2.0.2", 1660 - "@nodelib/fs.walk": "^1.2.3", 1661 - "glob-parent": "^5.1.2", 1662 - "merge2": "^1.3.0", 1663 - "micromatch": "^4.0.8" 1664 - }, 1665 - "engines": { 1666 - "node": ">=8.6.0" 1667 - } 1668 - }, 1669 - "node_modules/fast-glob/node_modules/glob-parent": { 1670 - "version": "5.1.2", 1671 - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 1672 - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 1673 - "dev": true, 1674 - "license": "ISC", 1675 - "dependencies": { 1676 - "is-glob": "^4.0.1" 1677 - }, 1678 - "engines": { 1679 - "node": ">= 6" 1680 - } 1681 - }, 1682 - "node_modules/fast-json-stable-stringify": { 1683 - "version": "2.1.0", 1684 - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 1685 - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", 1686 - "dev": true, 1687 - "license": "MIT" 1688 - }, 1689 - "node_modules/fast-levenshtein": { 1690 - "version": "2.0.6", 1691 - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 1692 - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", 1693 - "dev": true, 1694 - "license": "MIT" 1695 - }, 1696 - "node_modules/fastq": { 1697 - "version": "1.19.1", 1698 - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", 1699 - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", 1700 - "dev": true, 1701 - "license": "ISC", 1702 - "dependencies": { 1703 - "reusify": "^1.0.4" 1704 - } 1705 - }, 1706 - "node_modules/file-entry-cache": { 1707 - "version": "8.0.0", 1708 - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", 1709 - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", 1710 - "dev": true, 1711 - "license": "MIT", 1712 - "dependencies": { 1713 - "flat-cache": "^4.0.0" 1714 - }, 1715 - "engines": { 1716 - "node": ">=16.0.0" 1717 - } 1718 - }, 1719 - "node_modules/fill-range": { 1720 - "version": "7.1.1", 1721 - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", 1722 - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", 1723 - "dev": true, 1724 - "license": "MIT", 1725 - "dependencies": { 1726 - "to-regex-range": "^5.0.1" 1727 - }, 1728 - "engines": { 1729 - "node": ">=8" 1730 - } 1731 - }, 1732 - "node_modules/find-up": { 1733 - "version": "5.0.0", 1734 - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", 1735 - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", 1736 - "dev": true, 1737 - "license": "MIT", 1738 - "dependencies": { 1739 - "locate-path": "^6.0.0", 1740 - "path-exists": "^4.0.0" 1741 - }, 1742 - "engines": { 1743 - "node": ">=10" 1744 - }, 1745 - "funding": { 1746 - "url": "https://github.com/sponsors/sindresorhus" 1747 - } 1748 - }, 1749 - "node_modules/flat-cache": { 1750 - "version": "4.0.1", 1751 - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", 1752 - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", 1753 - "dev": true, 1754 - "license": "MIT", 1755 - "dependencies": { 1756 - "flatted": "^3.2.9", 1757 - "keyv": "^4.5.4" 1758 - }, 1759 - "engines": { 1760 - "node": ">=16" 1761 - } 1762 - }, 1763 - "node_modules/flatted": { 1764 - "version": "3.3.3", 1765 - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", 1766 - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", 1767 - "dev": true, 1768 - "license": "ISC" 1769 - }, 1770 - "node_modules/fsevents": { 1771 - "version": "2.3.3", 1772 - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 1773 - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 1774 - "dev": true, 1775 - "hasInstallScript": true, 1776 - "license": "MIT", 1777 - "optional": true, 1778 - "os": [ 1779 - "darwin" 1780 - ], 1781 - "engines": { 1782 - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 1783 - } 1784 - }, 1785 - "node_modules/gensync": { 1786 - "version": "1.0.0-beta.2", 1787 - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", 1788 - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", 1789 - "dev": true, 1790 - "license": "MIT", 1791 - "engines": { 1792 - "node": ">=6.9.0" 1793 - } 1794 - }, 1795 - "node_modules/glob-parent": { 1796 - "version": "6.0.2", 1797 - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", 1798 - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", 1799 - "dev": true, 1800 - "license": "ISC", 1801 - "dependencies": { 1802 - "is-glob": "^4.0.3" 1803 - }, 1804 - "engines": { 1805 - "node": ">=10.13.0" 1806 - } 1807 - }, 1808 - "node_modules/globals": { 1809 - "version": "16.4.0", 1810 - "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", 1811 - "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==", 1812 - "dev": true, 1813 - "license": "MIT", 1814 - "engines": { 1815 - "node": ">=18" 1816 - }, 1817 - "funding": { 1818 - "url": "https://github.com/sponsors/sindresorhus" 1819 - } 1820 - }, 1821 - "node_modules/graphemer": { 1822 - "version": "1.4.0", 1823 - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", 1824 - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", 1825 - "dev": true, 1826 - "license": "MIT" 1827 - }, 1828 - "node_modules/has-flag": { 1829 - "version": "4.0.0", 1830 - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 1831 - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 1832 - "dev": true, 1833 - "license": "MIT", 1834 - "engines": { 1835 - "node": ">=8" 1836 - } 1837 - }, 1838 - "node_modules/ignore": { 1839 - "version": "5.3.2", 1840 - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", 1841 - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", 1842 - "dev": true, 1843 - "license": "MIT", 1844 - "engines": { 1845 - "node": ">= 4" 1846 - } 1847 - }, 1848 - "node_modules/import-fresh": { 1849 - "version": "3.3.1", 1850 - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", 1851 - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", 1852 - "dev": true, 1853 - "license": "MIT", 1854 - "dependencies": { 1855 - "parent-module": "^1.0.0", 1856 - "resolve-from": "^4.0.0" 1857 - }, 1858 - "engines": { 1859 - "node": ">=6" 1860 - }, 1861 - "funding": { 1862 - "url": "https://github.com/sponsors/sindresorhus" 1863 - } 1864 - }, 1865 - "node_modules/imurmurhash": { 1866 - "version": "0.1.4", 1867 - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 1868 - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", 1869 - "dev": true, 1870 - "license": "MIT", 1871 - "engines": { 1872 - "node": ">=0.8.19" 1873 - } 1874 - }, 1875 - "node_modules/is-extglob": { 1876 - "version": "2.1.1", 1877 - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 1878 - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 1879 - "dev": true, 1880 - "license": "MIT", 1881 - "engines": { 1882 - "node": ">=0.10.0" 1883 - } 1884 - }, 1885 - "node_modules/is-glob": { 1886 - "version": "4.0.3", 1887 - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 1888 - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 1889 - "dev": true, 1890 - "license": "MIT", 1891 - "dependencies": { 1892 - "is-extglob": "^2.1.1" 1893 - }, 1894 - "engines": { 1895 - "node": ">=0.10.0" 1896 - } 1897 - }, 1898 - "node_modules/is-number": { 1899 - "version": "7.0.0", 1900 - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 1901 - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 1902 - "dev": true, 1903 - "license": "MIT", 1904 - "engines": { 1905 - "node": ">=0.12.0" 1906 - } 1907 - }, 1908 - "node_modules/isexe": { 1909 - "version": "2.0.0", 1910 - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 1911 - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", 1912 - "dev": true, 1913 - "license": "ISC" 1914 - }, 1915 - "node_modules/js-tokens": { 1916 - "version": "4.0.0", 1917 - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 1918 - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", 1919 - "dev": true, 1920 - "license": "MIT" 1921 - }, 1922 - "node_modules/js-yaml": { 1923 - "version": "4.1.0", 1924 - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", 1925 - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", 1926 - "dev": true, 1927 - "license": "MIT", 1928 - "dependencies": { 1929 - "argparse": "^2.0.1" 1930 - }, 1931 - "bin": { 1932 - "js-yaml": "bin/js-yaml.js" 1933 - } 1934 - }, 1935 - "node_modules/jsesc": { 1936 - "version": "3.1.0", 1937 - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", 1938 - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", 1939 - "dev": true, 1940 - "license": "MIT", 1941 - "bin": { 1942 - "jsesc": "bin/jsesc" 1943 - }, 1944 - "engines": { 1945 - "node": ">=6" 1946 - } 1947 - }, 1948 - "node_modules/json-buffer": { 1949 - "version": "3.0.1", 1950 - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", 1951 - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", 1952 - "dev": true, 1953 - "license": "MIT" 1954 - }, 1955 - "node_modules/json-schema-traverse": { 1956 - "version": "0.4.1", 1957 - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 1958 - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", 1959 - "dev": true, 1960 - "license": "MIT" 1961 - }, 1962 - "node_modules/json-stable-stringify-without-jsonify": { 1963 - "version": "1.0.1", 1964 - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", 1965 - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", 1966 - "dev": true, 1967 - "license": "MIT" 1968 - }, 1969 - "node_modules/json5": { 1970 - "version": "2.2.3", 1971 - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", 1972 - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", 1973 - "dev": true, 1974 - "license": "MIT", 1975 - "bin": { 1976 - "json5": "lib/cli.js" 1977 - }, 1978 - "engines": { 1979 - "node": ">=6" 1980 - } 1981 - }, 1982 - "node_modules/keyv": { 1983 - "version": "4.5.4", 1984 - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", 1985 - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", 1986 - "dev": true, 1987 - "license": "MIT", 1988 - "dependencies": { 1989 - "json-buffer": "3.0.1" 1990 - } 1991 - }, 1992 - "node_modules/levn": { 1993 - "version": "0.4.1", 1994 - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", 1995 - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", 1996 - "dev": true, 1997 - "license": "MIT", 1998 - "dependencies": { 1999 - "prelude-ls": "^1.2.1", 2000 - "type-check": "~0.4.0" 2001 - }, 2002 - "engines": { 2003 - "node": ">= 0.8.0" 2004 - } 2005 - }, 2006 - "node_modules/lightningcss": { 2007 - "version": "1.30.2", 2008 - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz", 2009 - "integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==", 2010 - "dev": true, 2011 - "license": "MPL-2.0", 2012 - "dependencies": { 2013 - "detect-libc": "^2.0.3" 2014 - }, 2015 - "engines": { 2016 - "node": ">= 12.0.0" 2017 - }, 2018 - "funding": { 2019 - "type": "opencollective", 2020 - "url": "https://opencollective.com/parcel" 2021 - }, 2022 - "optionalDependencies": { 2023 - "lightningcss-android-arm64": "1.30.2", 2024 - "lightningcss-darwin-arm64": "1.30.2", 2025 - "lightningcss-darwin-x64": "1.30.2", 2026 - "lightningcss-freebsd-x64": "1.30.2", 2027 - "lightningcss-linux-arm-gnueabihf": "1.30.2", 2028 - "lightningcss-linux-arm64-gnu": "1.30.2", 2029 - "lightningcss-linux-arm64-musl": "1.30.2", 2030 - "lightningcss-linux-x64-gnu": "1.30.2", 2031 - "lightningcss-linux-x64-musl": "1.30.2", 2032 - "lightningcss-win32-arm64-msvc": "1.30.2", 2033 - "lightningcss-win32-x64-msvc": "1.30.2" 2034 - } 2035 - }, 2036 - "node_modules/lightningcss-darwin-arm64": { 2037 - "version": "1.30.2", 2038 - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz", 2039 - "integrity": "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==", 2040 - "cpu": [ 2041 - "arm64" 2042 - ], 2043 - "dev": true, 2044 - "license": "MPL-2.0", 2045 - "optional": true, 2046 - "os": [ 2047 - "darwin" 2048 - ], 2049 - "engines": { 2050 - "node": ">= 12.0.0" 2051 - }, 2052 - "funding": { 2053 - "type": "opencollective", 2054 - "url": "https://opencollective.com/parcel" 2055 - } 2056 - }, 2057 - "node_modules/locate-path": { 2058 - "version": "6.0.0", 2059 - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", 2060 - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", 2061 - "dev": true, 2062 - "license": "MIT", 2063 - "dependencies": { 2064 - "p-locate": "^5.0.0" 2065 - }, 2066 - "engines": { 2067 - "node": ">=10" 2068 - }, 2069 - "funding": { 2070 - "url": "https://github.com/sponsors/sindresorhus" 2071 - } 2072 - }, 2073 - "node_modules/lodash.merge": { 2074 - "version": "4.6.2", 2075 - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", 2076 - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", 2077 - "dev": true, 2078 - "license": "MIT" 2079 - }, 2080 - "node_modules/lru-cache": { 2081 - "version": "5.1.1", 2082 - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", 2083 - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", 2084 - "dev": true, 2085 - "license": "ISC", 2086 - "dependencies": { 2087 - "yallist": "^3.0.2" 2088 - } 2089 - }, 2090 - "node_modules/merge2": { 2091 - "version": "1.4.1", 2092 - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", 2093 - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", 2094 - "dev": true, 2095 - "license": "MIT", 2096 - "engines": { 2097 - "node": ">= 8" 2098 - } 2099 - }, 2100 - "node_modules/micromatch": { 2101 - "version": "4.0.8", 2102 - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", 2103 - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", 2104 - "dev": true, 2105 - "license": "MIT", 2106 - "dependencies": { 2107 - "braces": "^3.0.3", 2108 - "picomatch": "^2.3.1" 2109 - }, 2110 - "engines": { 2111 - "node": ">=8.6" 2112 - } 2113 - }, 2114 - "node_modules/minimatch": { 2115 - "version": "3.1.2", 2116 - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 2117 - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 2118 - "dev": true, 2119 - "license": "ISC", 2120 - "dependencies": { 2121 - "brace-expansion": "^1.1.7" 2122 - }, 2123 - "engines": { 2124 - "node": "*" 2125 - } 2126 - }, 2127 - "node_modules/ms": { 2128 - "version": "2.1.3", 2129 - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 2130 - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 2131 - "dev": true, 2132 - "license": "MIT" 2133 - }, 2134 - "node_modules/nanoid": { 2135 - "version": "3.3.11", 2136 - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", 2137 - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", 2138 - "dev": true, 2139 - "funding": [ 2140 - { 2141 - "type": "github", 2142 - "url": "https://github.com/sponsors/ai" 2143 - } 2144 - ], 2145 - "license": "MIT", 2146 - "bin": { 2147 - "nanoid": "bin/nanoid.cjs" 2148 - }, 2149 - "engines": { 2150 - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 2151 - } 2152 - }, 2153 - "node_modules/natural-compare": { 2154 - "version": "1.4.0", 2155 - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", 2156 - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", 2157 - "dev": true, 2158 - "license": "MIT" 2159 - }, 2160 - "node_modules/node-releases": { 2161 - "version": "2.0.23", 2162 - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.23.tgz", 2163 - "integrity": "sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==", 2164 - "dev": true, 2165 - "license": "MIT" 2166 - }, 2167 - "node_modules/optionator": { 2168 - "version": "0.9.4", 2169 - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", 2170 - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", 2171 - "dev": true, 2172 - "license": "MIT", 2173 - "dependencies": { 2174 - "deep-is": "^0.1.3", 2175 - "fast-levenshtein": "^2.0.6", 2176 - "levn": "^0.4.1", 2177 - "prelude-ls": "^1.2.1", 2178 - "type-check": "^0.4.0", 2179 - "word-wrap": "^1.2.5" 2180 - }, 2181 - "engines": { 2182 - "node": ">= 0.8.0" 2183 - } 2184 - }, 2185 - "node_modules/p-limit": { 2186 - "version": "3.1.0", 2187 - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", 2188 - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", 2189 - "dev": true, 2190 - "license": "MIT", 2191 - "dependencies": { 2192 - "yocto-queue": "^0.1.0" 2193 - }, 2194 - "engines": { 2195 - "node": ">=10" 2196 - }, 2197 - "funding": { 2198 - "url": "https://github.com/sponsors/sindresorhus" 2199 - } 2200 - }, 2201 - "node_modules/p-locate": { 2202 - "version": "5.0.0", 2203 - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", 2204 - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", 2205 - "dev": true, 2206 - "license": "MIT", 2207 - "dependencies": { 2208 - "p-limit": "^3.0.2" 2209 - }, 2210 - "engines": { 2211 - "node": ">=10" 2212 - }, 2213 - "funding": { 2214 - "url": "https://github.com/sponsors/sindresorhus" 2215 - } 2216 - }, 2217 - "node_modules/parent-module": { 2218 - "version": "1.0.1", 2219 - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", 2220 - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", 2221 - "dev": true, 2222 - "license": "MIT", 2223 - "dependencies": { 2224 - "callsites": "^3.0.0" 2225 - }, 2226 - "engines": { 2227 - "node": ">=6" 2228 - } 2229 - }, 2230 - "node_modules/path-exists": { 2231 - "version": "4.0.0", 2232 - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 2233 - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 2234 - "dev": true, 2235 - "license": "MIT", 2236 - "engines": { 2237 - "node": ">=8" 2238 - } 2239 - }, 2240 - "node_modules/path-key": { 2241 - "version": "3.1.1", 2242 - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 2243 - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 2244 - "dev": true, 2245 - "license": "MIT", 2246 - "engines": { 2247 - "node": ">=8" 2248 - } 2249 - }, 2250 - "node_modules/picocolors": { 2251 - "version": "1.1.1", 2252 - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", 2253 - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", 2254 - "dev": true, 2255 - "license": "ISC" 2256 - }, 2257 - "node_modules/picomatch": { 2258 - "version": "2.3.1", 2259 - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 2260 - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 2261 - "dev": true, 2262 - "license": "MIT", 2263 - "engines": { 2264 - "node": ">=8.6" 2265 - }, 2266 - "funding": { 2267 - "url": "https://github.com/sponsors/jonschlinkert" 2268 - } 2269 - }, 2270 - "node_modules/postcss": { 2271 - "version": "8.5.6", 2272 - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", 2273 - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", 2274 - "dev": true, 2275 - "funding": [ 2276 - { 2277 - "type": "opencollective", 2278 - "url": "https://opencollective.com/postcss/" 2279 - }, 2280 - { 2281 - "type": "tidelift", 2282 - "url": "https://tidelift.com/funding/github/npm/postcss" 2283 - }, 2284 - { 2285 - "type": "github", 2286 - "url": "https://github.com/sponsors/ai" 2287 - } 2288 - ], 2289 - "license": "MIT", 2290 - "dependencies": { 2291 - "nanoid": "^3.3.11", 2292 - "picocolors": "^1.1.1", 2293 - "source-map-js": "^1.2.1" 2294 - }, 2295 - "engines": { 2296 - "node": "^10 || ^12 || >=14" 2297 - } 2298 - }, 2299 - "node_modules/prelude-ls": { 2300 - "version": "1.2.1", 2301 - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", 2302 - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", 2303 - "dev": true, 2304 - "license": "MIT", 2305 - "engines": { 2306 - "node": ">= 0.8.0" 2307 - } 2308 - }, 2309 - "node_modules/punycode": { 2310 - "version": "2.3.1", 2311 - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", 2312 - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", 2313 - "dev": true, 2314 - "license": "MIT", 2315 - "engines": { 2316 - "node": ">=6" 2317 - } 2318 - }, 2319 - "node_modules/queue-microtask": { 2320 - "version": "1.2.3", 2321 - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", 2322 - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", 2323 - "dev": true, 2324 - "funding": [ 2325 - { 2326 - "type": "github", 2327 - "url": "https://github.com/sponsors/feross" 2328 - }, 2329 - { 2330 - "type": "patreon", 2331 - "url": "https://www.patreon.com/feross" 2332 - }, 2333 - { 2334 - "type": "consulting", 2335 - "url": "https://feross.org/support" 2336 - } 2337 - ], 2338 - "license": "MIT" 2339 - }, 2340 - "node_modules/react": { 2341 - "version": "19.2.0", 2342 - "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", 2343 - "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", 2344 - "dev": true, 2345 - "license": "MIT", 2346 - "engines": { 2347 - "node": ">=0.10.0" 2348 - } 2349 - }, 2350 - "node_modules/react-dom": { 2351 - "version": "19.2.0", 2352 - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", 2353 - "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", 2354 - "dev": true, 2355 - "license": "MIT", 2356 - "dependencies": { 2357 - "scheduler": "^0.27.0" 2358 - }, 2359 - "peerDependencies": { 2360 - "react": "^19.2.0" 2361 - } 2362 - }, 2363 - "node_modules/react-refresh": { 2364 - "version": "0.17.0", 2365 - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", 2366 - "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", 2367 - "dev": true, 2368 - "license": "MIT", 2369 - "engines": { 2370 - "node": ">=0.10.0" 2371 - } 2372 - }, 2373 - "node_modules/resolve-from": { 2374 - "version": "4.0.0", 2375 - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", 2376 - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", 2377 - "dev": true, 2378 - "license": "MIT", 2379 - "engines": { 2380 - "node": ">=4" 2381 - } 2382 - }, 2383 - "node_modules/reusify": { 2384 - "version": "1.1.0", 2385 - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", 2386 - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", 2387 - "dev": true, 2388 - "license": "MIT", 2389 - "engines": { 2390 - "iojs": ">=1.0.0", 2391 - "node": ">=0.10.0" 2392 - } 2393 - }, 2394 - "node_modules/rolldown": { 2395 - "version": "1.0.0-beta.41", 2396 - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-beta.41.tgz", 2397 - "integrity": "sha512-U+NPR0Bkg3wm61dteD2L4nAM1U9dtaqVrpDXwC36IKRHpEO/Ubpid4Nijpa2imPchcVNHfxVFwSSMJdwdGFUbg==", 2398 - "dev": true, 2399 - "license": "MIT", 2400 - "dependencies": { 2401 - "@oxc-project/types": "=0.93.0", 2402 - "@rolldown/pluginutils": "1.0.0-beta.41", 2403 - "ansis": "=4.2.0" 2404 - }, 2405 - "bin": { 2406 - "rolldown": "bin/cli.mjs" 2407 - }, 2408 - "engines": { 2409 - "node": "^20.19.0 || >=22.12.0" 2410 - }, 2411 - "optionalDependencies": { 2412 - "@rolldown/binding-android-arm64": "1.0.0-beta.41", 2413 - "@rolldown/binding-darwin-arm64": "1.0.0-beta.41", 2414 - "@rolldown/binding-darwin-x64": "1.0.0-beta.41", 2415 - "@rolldown/binding-freebsd-x64": "1.0.0-beta.41", 2416 - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.41", 2417 - "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.41", 2418 - "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.41", 2419 - "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.41", 2420 - "@rolldown/binding-linux-x64-musl": "1.0.0-beta.41", 2421 - "@rolldown/binding-openharmony-arm64": "1.0.0-beta.41", 2422 - "@rolldown/binding-wasm32-wasi": "1.0.0-beta.41", 2423 - "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.41", 2424 - "@rolldown/binding-win32-ia32-msvc": "1.0.0-beta.41", 2425 - "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.41" 2426 - } 2427 - }, 2428 - "node_modules/rolldown/node_modules/@rolldown/pluginutils": { 2429 - "version": "1.0.0-beta.41", 2430 - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.41.tgz", 2431 - "integrity": "sha512-ycMEPrS3StOIeb87BT3/+bu+blEtyvwQ4zmo2IcJQy0Rd1DAAhKksA0iUZ3MYSpJtjlPhg0Eo6mvVS6ggPhRbw==", 2432 - "dev": true, 2433 - "license": "MIT" 2434 - }, 2435 - "node_modules/run-parallel": { 2436 - "version": "1.2.0", 2437 - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", 2438 - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 2439 - "dev": true, 2440 - "funding": [ 2441 - { 2442 - "type": "github", 2443 - "url": "https://github.com/sponsors/feross" 2444 - }, 2445 - { 2446 - "type": "patreon", 2447 - "url": "https://www.patreon.com/feross" 2448 - }, 2449 - { 2450 - "type": "consulting", 2451 - "url": "https://feross.org/support" 2452 - } 2453 - ], 2454 - "license": "MIT", 2455 - "dependencies": { 2456 - "queue-microtask": "^1.2.2" 2457 - } 2458 - }, 2459 - "node_modules/scheduler": { 2460 - "version": "0.27.0", 2461 - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", 2462 - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", 2463 - "dev": true, 2464 - "license": "MIT" 2465 - }, 2466 - "node_modules/semver": { 2467 - "version": "6.3.1", 2468 - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", 2469 - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", 2470 - "dev": true, 2471 - "license": "ISC", 2472 - "bin": { 2473 - "semver": "bin/semver.js" 2474 - } 2475 - }, 2476 - "node_modules/shebang-command": { 2477 - "version": "2.0.0", 2478 - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 2479 - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 2480 - "dev": true, 2481 - "license": "MIT", 2482 - "dependencies": { 2483 - "shebang-regex": "^3.0.0" 2484 - }, 2485 - "engines": { 2486 - "node": ">=8" 2487 - } 2488 - }, 2489 - "node_modules/shebang-regex": { 2490 - "version": "3.0.0", 2491 - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 2492 - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 2493 - "dev": true, 2494 - "license": "MIT", 2495 - "engines": { 2496 - "node": ">=8" 2497 - } 2498 - }, 2499 - "node_modules/source-map-js": { 2500 - "version": "1.2.1", 2501 - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", 2502 - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", 2503 - "dev": true, 2504 - "license": "BSD-3-Clause", 2505 - "engines": { 2506 - "node": ">=0.10.0" 2507 - } 2508 - }, 2509 - "node_modules/strip-json-comments": { 2510 - "version": "3.1.1", 2511 - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 2512 - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", 2513 - "dev": true, 2514 - "license": "MIT", 2515 - "engines": { 2516 - "node": ">=8" 2517 - }, 2518 - "funding": { 2519 - "url": "https://github.com/sponsors/sindresorhus" 2520 - } 2521 - }, 2522 - "node_modules/supports-color": { 2523 - "version": "7.2.0", 2524 - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 2525 - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 2526 - "dev": true, 2527 - "license": "MIT", 2528 - "dependencies": { 2529 - "has-flag": "^4.0.0" 2530 - }, 2531 - "engines": { 2532 - "node": ">=8" 2533 - } 2534 - }, 2535 - "node_modules/tinyglobby": { 2536 - "version": "0.2.15", 2537 - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", 2538 - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", 2539 - "dev": true, 2540 - "license": "MIT", 2541 - "dependencies": { 2542 - "fdir": "^6.5.0", 2543 - "picomatch": "^4.0.3" 2544 - }, 2545 - "engines": { 2546 - "node": ">=12.0.0" 2547 - }, 2548 - "funding": { 2549 - "url": "https://github.com/sponsors/SuperchupuDev" 2550 - } 2551 - }, 2552 - "node_modules/tinyglobby/node_modules/fdir": { 2553 - "version": "6.5.0", 2554 - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", 2555 - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", 2556 - "dev": true, 2557 - "license": "MIT", 2558 - "engines": { 2559 - "node": ">=12.0.0" 2560 - }, 2561 - "peerDependencies": { 2562 - "picomatch": "^3 || ^4" 2563 - }, 2564 - "peerDependenciesMeta": { 2565 - "picomatch": { 2566 - "optional": true 2567 - } 2568 - } 2569 - }, 2570 - "node_modules/tinyglobby/node_modules/picomatch": { 2571 - "version": "4.0.3", 2572 - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", 2573 - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", 2574 - "dev": true, 2575 - "license": "MIT", 2576 - "engines": { 2577 - "node": ">=12" 2578 - }, 2579 - "funding": { 2580 - "url": "https://github.com/sponsors/jonschlinkert" 2581 - } 2582 - }, 2583 - "node_modules/to-regex-range": { 2584 - "version": "5.0.1", 2585 - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 2586 - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 2587 - "dev": true, 2588 - "license": "MIT", 2589 - "dependencies": { 2590 - "is-number": "^7.0.0" 2591 - }, 2592 - "engines": { 2593 - "node": ">=8.0" 2594 - } 2595 - }, 2596 - "node_modules/ts-api-utils": { 2597 - "version": "2.1.0", 2598 - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", 2599 - "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", 2600 - "dev": true, 2601 - "license": "MIT", 2602 - "engines": { 2603 - "node": ">=18.12" 2604 - }, 2605 - "peerDependencies": { 2606 - "typescript": ">=4.8.4" 2607 - } 2608 - }, 2609 - "node_modules/type-check": { 2610 - "version": "0.4.0", 2611 - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", 2612 - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", 2613 - "dev": true, 2614 - "license": "MIT", 2615 - "dependencies": { 2616 - "prelude-ls": "^1.2.1" 2617 - }, 2618 - "engines": { 2619 - "node": ">= 0.8.0" 2620 - } 2621 - }, 2622 - "node_modules/typescript": { 2623 - "version": "5.9.3", 2624 - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", 2625 - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", 2626 - "dev": true, 2627 - "license": "Apache-2.0", 2628 - "bin": { 2629 - "tsc": "bin/tsc", 2630 - "tsserver": "bin/tsserver" 2631 - }, 2632 - "engines": { 2633 - "node": ">=14.17" 2634 - } 2635 - }, 2636 - "node_modules/typescript-eslint": { 2637 - "version": "8.46.0", 2638 - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.46.0.tgz", 2639 - "integrity": "sha512-6+ZrB6y2bT2DX3K+Qd9vn7OFOJR+xSLDj+Aw/N3zBwUt27uTw2sw2TE2+UcY1RiyBZkaGbTkVg9SSdPNUG6aUw==", 2640 - "dev": true, 2641 - "license": "MIT", 2642 - "dependencies": { 2643 - "@typescript-eslint/eslint-plugin": "8.46.0", 2644 - "@typescript-eslint/parser": "8.46.0", 2645 - "@typescript-eslint/typescript-estree": "8.46.0", 2646 - "@typescript-eslint/utils": "8.46.0" 2647 - }, 2648 - "engines": { 2649 - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 2650 - }, 2651 - "funding": { 2652 - "type": "opencollective", 2653 - "url": "https://opencollective.com/typescript-eslint" 2654 - }, 2655 - "peerDependencies": { 2656 - "eslint": "^8.57.0 || ^9.0.0", 2657 - "typescript": ">=4.8.4 <6.0.0" 2658 - } 2659 - }, 2660 - "node_modules/undici-types": { 2661 - "version": "7.14.0", 2662 - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz", 2663 - "integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==", 2664 - "dev": true, 2665 - "license": "MIT" 2666 - }, 2667 - "node_modules/update-browserslist-db": { 2668 - "version": "1.1.3", 2669 - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", 2670 - "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", 2671 - "dev": true, 2672 - "funding": [ 2673 - { 2674 - "type": "opencollective", 2675 - "url": "https://opencollective.com/browserslist" 2676 - }, 2677 - { 2678 - "type": "tidelift", 2679 - "url": "https://tidelift.com/funding/github/npm/browserslist" 2680 - }, 2681 - { 2682 - "type": "github", 2683 - "url": "https://github.com/sponsors/ai" 2684 - } 2685 - ], 2686 - "license": "MIT", 2687 - "dependencies": { 2688 - "escalade": "^3.2.0", 2689 - "picocolors": "^1.1.1" 2690 - }, 2691 - "bin": { 2692 - "update-browserslist-db": "cli.js" 2693 - }, 2694 - "peerDependencies": { 2695 - "browserslist": ">= 4.21.0" 2696 - } 2697 - }, 2698 - "node_modules/uri-js": { 2699 - "version": "4.4.1", 2700 - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", 2701 - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", 2702 - "dev": true, 2703 - "license": "BSD-2-Clause", 2704 - "dependencies": { 2705 - "punycode": "^2.1.0" 2706 - } 2707 - }, 2708 - "node_modules/vite": { 2709 - "name": "rolldown-vite", 2710 - "version": "7.1.14", 2711 - "resolved": "https://registry.npmjs.org/rolldown-vite/-/rolldown-vite-7.1.14.tgz", 2712 - "integrity": "sha512-eSiiRJmovt8qDJkGyZuLnbxAOAdie6NCmmd0NkTC0RJI9duiSBTfr8X2mBYJOUFzxQa2USaHmL99J9uMxkjCyw==", 2713 - "dev": true, 2714 - "license": "MIT", 2715 - "dependencies": { 2716 - "@oxc-project/runtime": "0.92.0", 2717 - "fdir": "^6.5.0", 2718 - "lightningcss": "^1.30.1", 2719 - "picomatch": "^4.0.3", 2720 - "postcss": "^8.5.6", 2721 - "rolldown": "1.0.0-beta.41", 2722 - "tinyglobby": "^0.2.15" 2723 - }, 2724 - "bin": { 2725 - "vite": "bin/vite.js" 2726 - }, 2727 - "engines": { 2728 - "node": "^20.19.0 || >=22.12.0" 2729 - }, 2730 - "funding": { 2731 - "url": "https://github.com/vitejs/vite?sponsor=1" 2732 - }, 2733 - "optionalDependencies": { 2734 - "fsevents": "~2.3.3" 2735 - }, 2736 - "peerDependencies": { 2737 - "@types/node": "^20.19.0 || >=22.12.0", 2738 - "esbuild": "^0.25.0", 2739 - "jiti": ">=1.21.0", 2740 - "less": "^4.0.0", 2741 - "sass": "^1.70.0", 2742 - "sass-embedded": "^1.70.0", 2743 - "stylus": ">=0.54.8", 2744 - "sugarss": "^5.0.0", 2745 - "terser": "^5.16.0", 2746 - "tsx": "^4.8.1", 2747 - "yaml": "^2.4.2" 2748 - }, 2749 - "peerDependenciesMeta": { 2750 - "@types/node": { 2751 - "optional": true 2752 - }, 2753 - "esbuild": { 2754 - "optional": true 2755 - }, 2756 - "jiti": { 2757 - "optional": true 2758 - }, 2759 - "less": { 2760 - "optional": true 2761 - }, 2762 - "sass": { 2763 - "optional": true 2764 - }, 2765 - "sass-embedded": { 2766 - "optional": true 2767 - }, 2768 - "stylus": { 2769 - "optional": true 2770 - }, 2771 - "sugarss": { 2772 - "optional": true 2773 - }, 2774 - "terser": { 2775 - "optional": true 2776 - }, 2777 - "tsx": { 2778 - "optional": true 2779 - }, 2780 - "yaml": { 2781 - "optional": true 2782 - } 2783 - } 2784 - }, 2785 - "node_modules/vite/node_modules/fdir": { 2786 - "version": "6.5.0", 2787 - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", 2788 - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", 2789 - "dev": true, 2790 - "license": "MIT", 2791 - "engines": { 2792 - "node": ">=12.0.0" 2793 - }, 2794 - "peerDependencies": { 2795 - "picomatch": "^3 || ^4" 2796 - }, 2797 - "peerDependenciesMeta": { 2798 - "picomatch": { 2799 - "optional": true 2800 - } 2801 - } 2802 - }, 2803 - "node_modules/vite/node_modules/picomatch": { 2804 - "version": "4.0.3", 2805 - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", 2806 - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", 2807 - "dev": true, 2808 - "license": "MIT", 2809 - "engines": { 2810 - "node": ">=12" 2811 - }, 2812 - "funding": { 2813 - "url": "https://github.com/sponsors/jonschlinkert" 2814 - } 2815 - }, 2816 - "node_modules/which": { 2817 - "version": "2.0.2", 2818 - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 2819 - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 2820 - "dev": true, 2821 - "license": "ISC", 2822 - "dependencies": { 2823 - "isexe": "^2.0.0" 2824 - }, 2825 - "bin": { 2826 - "node-which": "bin/node-which" 2827 - }, 2828 - "engines": { 2829 - "node": ">= 8" 2830 - } 2831 - }, 2832 - "node_modules/word-wrap": { 2833 - "version": "1.2.5", 2834 - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", 2835 - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", 2836 - "dev": true, 2837 - "license": "MIT", 2838 - "engines": { 2839 - "node": ">=0.10.0" 2840 - } 2841 - }, 2842 - "node_modules/yallist": { 2843 - "version": "3.1.1", 2844 - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", 2845 - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", 2846 - "dev": true, 2847 - "license": "ISC" 2848 - }, 2849 - "node_modules/yocto-queue": { 2850 - "version": "0.1.0", 2851 - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", 2852 - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", 2853 - "dev": true, 2854 - "license": "MIT", 2855 - "engines": { 2856 - "node": ">=10" 2857 - }, 2858 - "funding": { 2859 - "url": "https://github.com/sponsors/sindresorhus" 2860 - } 2861 - } 2862 - } 2 + "name": "atproto-ui", 3 + "version": "0.12", 4 + "lockfileVersion": 3, 5 + "requires": true, 6 + "packages": { 7 + "": { 8 + "name": "atproto-ui", 9 + "version": "0.12", 10 + "dependencies": { 11 + "@atcute/atproto": "^3.1.7", 12 + "@atcute/bluesky": "^3.2.3", 13 + "@atcute/client": "^4.0.3", 14 + "@atcute/identity-resolver": "^1.1.3", 15 + "@atcute/tangled": "^1.0.10" 16 + }, 17 + "devDependencies": { 18 + "@eslint/js": "^9.36.0", 19 + "@microsoft/api-extractor": "^7.53.1", 20 + "@types/node": "^24.6.0", 21 + "@types/react": "^19.1.16", 22 + "@types/react-dom": "^19.1.9", 23 + "@vitejs/plugin-react": "^5.0.4", 24 + "eslint": "^9.36.0", 25 + "eslint-plugin-react-hooks": "^5.2.0", 26 + "eslint-plugin-react-refresh": "^0.4.22", 27 + "globals": "^16.4.0", 28 + "react": "^19.1.1", 29 + "react-dom": "^19.1.1", 30 + "rollup-plugin-typescript2": "^0.36.0", 31 + "typescript": "~5.9.3", 32 + "typescript-eslint": "^8.45.0", 33 + "unplugin-dts": "^1.0.0-beta.6", 34 + "vite": "npm:rolldown-vite@7.1.14" 35 + }, 36 + "peerDependencies": { 37 + "react": "^18.2.0 || ^19.0.0", 38 + "react-dom": "^18.2.0 || ^19.0.0" 39 + }, 40 + "peerDependenciesMeta": { 41 + "react-dom": { 42 + "optional": true 43 + } 44 + } 45 + }, 46 + "node_modules/@atcute/atproto": { 47 + "version": "3.1.9", 48 + "license": "0BSD", 49 + "dependencies": { 50 + "@atcute/lexicons": "^1.2.2" 51 + } 52 + }, 53 + "node_modules/@atcute/bluesky": { 54 + "version": "3.2.11", 55 + "license": "0BSD", 56 + "dependencies": { 57 + "@atcute/atproto": "^3.1.9", 58 + "@atcute/lexicons": "^1.2.5" 59 + } 60 + }, 61 + "node_modules/@atcute/client": { 62 + "version": "4.1.0", 63 + "license": "0BSD", 64 + "dependencies": { 65 + "@atcute/identity": "^1.1.3", 66 + "@atcute/lexicons": "^1.2.5" 67 + } 68 + }, 69 + "node_modules/@atcute/identity": { 70 + "version": "1.1.3", 71 + "license": "0BSD", 72 + "peer": true, 73 + "dependencies": { 74 + "@atcute/lexicons": "^1.2.4", 75 + "@badrap/valita": "^0.4.6" 76 + } 77 + }, 78 + "node_modules/@atcute/identity-resolver": { 79 + "version": "1.1.4", 80 + "license": "0BSD", 81 + "dependencies": { 82 + "@atcute/lexicons": "^1.2.2", 83 + "@atcute/util-fetch": "^1.0.3", 84 + "@badrap/valita": "^0.4.6" 85 + }, 86 + "peerDependencies": { 87 + "@atcute/identity": "^1.0.0" 88 + } 89 + }, 90 + "node_modules/@atcute/lexicons": { 91 + "version": "1.2.5", 92 + "license": "0BSD", 93 + "dependencies": { 94 + "@standard-schema/spec": "^1.0.0", 95 + "esm-env": "^1.2.2" 96 + } 97 + }, 98 + "node_modules/@atcute/tangled": { 99 + "version": "1.0.12", 100 + "license": "0BSD", 101 + "dependencies": { 102 + "@atcute/atproto": "^3.1.9", 103 + "@atcute/lexicons": "^1.2.3" 104 + } 105 + }, 106 + "node_modules/@atcute/util-fetch": { 107 + "version": "1.0.4", 108 + "license": "0BSD", 109 + "dependencies": { 110 + "@badrap/valita": "^0.4.6" 111 + } 112 + }, 113 + "node_modules/@babel/code-frame": { 114 + "version": "7.27.1", 115 + "dev": true, 116 + "license": "MIT", 117 + "dependencies": { 118 + "@babel/helper-validator-identifier": "^7.27.1", 119 + "js-tokens": "^4.0.0", 120 + "picocolors": "^1.1.1" 121 + }, 122 + "engines": { 123 + "node": ">=6.9.0" 124 + } 125 + }, 126 + "node_modules/@babel/compat-data": { 127 + "version": "7.28.5", 128 + "dev": true, 129 + "license": "MIT", 130 + "engines": { 131 + "node": ">=6.9.0" 132 + } 133 + }, 134 + "node_modules/@babel/core": { 135 + "version": "7.28.5", 136 + "dev": true, 137 + "license": "MIT", 138 + "peer": true, 139 + "dependencies": { 140 + "@babel/code-frame": "^7.27.1", 141 + "@babel/generator": "^7.28.5", 142 + "@babel/helper-compilation-targets": "^7.27.2", 143 + "@babel/helper-module-transforms": "^7.28.3", 144 + "@babel/helpers": "^7.28.4", 145 + "@babel/parser": "^7.28.5", 146 + "@babel/template": "^7.27.2", 147 + "@babel/traverse": "^7.28.5", 148 + "@babel/types": "^7.28.5", 149 + "@jridgewell/remapping": "^2.3.5", 150 + "convert-source-map": "^2.0.0", 151 + "debug": "^4.1.0", 152 + "gensync": "^1.0.0-beta.2", 153 + "json5": "^2.2.3", 154 + "semver": "^6.3.1" 155 + }, 156 + "engines": { 157 + "node": ">=6.9.0" 158 + }, 159 + "funding": { 160 + "type": "opencollective", 161 + "url": "https://opencollective.com/babel" 162 + } 163 + }, 164 + "node_modules/@babel/core/node_modules/semver": { 165 + "version": "6.3.1", 166 + "dev": true, 167 + "license": "ISC", 168 + "bin": { 169 + "semver": "bin/semver.js" 170 + } 171 + }, 172 + "node_modules/@babel/generator": { 173 + "version": "7.28.5", 174 + "dev": true, 175 + "license": "MIT", 176 + "dependencies": { 177 + "@babel/parser": "^7.28.5", 178 + "@babel/types": "^7.28.5", 179 + "@jridgewell/gen-mapping": "^0.3.12", 180 + "@jridgewell/trace-mapping": "^0.3.28", 181 + "jsesc": "^3.0.2" 182 + }, 183 + "engines": { 184 + "node": ">=6.9.0" 185 + } 186 + }, 187 + "node_modules/@babel/helper-compilation-targets": { 188 + "version": "7.27.2", 189 + "dev": true, 190 + "license": "MIT", 191 + "dependencies": { 192 + "@babel/compat-data": "^7.27.2", 193 + "@babel/helper-validator-option": "^7.27.1", 194 + "browserslist": "^4.24.0", 195 + "lru-cache": "^5.1.1", 196 + "semver": "^6.3.1" 197 + }, 198 + "engines": { 199 + "node": ">=6.9.0" 200 + } 201 + }, 202 + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { 203 + "version": "5.1.1", 204 + "dev": true, 205 + "license": "ISC", 206 + "dependencies": { 207 + "yallist": "^3.0.2" 208 + } 209 + }, 210 + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache/node_modules/yallist": { 211 + "version": "3.1.1", 212 + "dev": true, 213 + "license": "ISC" 214 + }, 215 + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { 216 + "version": "6.3.1", 217 + "dev": true, 218 + "license": "ISC", 219 + "bin": { 220 + "semver": "bin/semver.js" 221 + } 222 + }, 223 + "node_modules/@babel/helper-globals": { 224 + "version": "7.28.0", 225 + "dev": true, 226 + "license": "MIT", 227 + "engines": { 228 + "node": ">=6.9.0" 229 + } 230 + }, 231 + "node_modules/@babel/helper-module-imports": { 232 + "version": "7.27.1", 233 + "dev": true, 234 + "license": "MIT", 235 + "dependencies": { 236 + "@babel/traverse": "^7.27.1", 237 + "@babel/types": "^7.27.1" 238 + }, 239 + "engines": { 240 + "node": ">=6.9.0" 241 + } 242 + }, 243 + "node_modules/@babel/helper-module-transforms": { 244 + "version": "7.28.3", 245 + "dev": true, 246 + "license": "MIT", 247 + "dependencies": { 248 + "@babel/helper-module-imports": "^7.27.1", 249 + "@babel/helper-validator-identifier": "^7.27.1", 250 + "@babel/traverse": "^7.28.3" 251 + }, 252 + "engines": { 253 + "node": ">=6.9.0" 254 + }, 255 + "peerDependencies": { 256 + "@babel/core": "^7.0.0" 257 + } 258 + }, 259 + "node_modules/@babel/helper-plugin-utils": { 260 + "version": "7.27.1", 261 + "dev": true, 262 + "license": "MIT", 263 + "engines": { 264 + "node": ">=6.9.0" 265 + } 266 + }, 267 + "node_modules/@babel/helper-string-parser": { 268 + "version": "7.27.1", 269 + "dev": true, 270 + "license": "MIT", 271 + "engines": { 272 + "node": ">=6.9.0" 273 + } 274 + }, 275 + "node_modules/@babel/helper-validator-identifier": { 276 + "version": "7.28.5", 277 + "dev": true, 278 + "license": "MIT", 279 + "engines": { 280 + "node": ">=6.9.0" 281 + } 282 + }, 283 + "node_modules/@babel/helper-validator-option": { 284 + "version": "7.27.1", 285 + "dev": true, 286 + "license": "MIT", 287 + "engines": { 288 + "node": ">=6.9.0" 289 + } 290 + }, 291 + "node_modules/@babel/helpers": { 292 + "version": "7.28.4", 293 + "dev": true, 294 + "license": "MIT", 295 + "dependencies": { 296 + "@babel/template": "^7.27.2", 297 + "@babel/types": "^7.28.4" 298 + }, 299 + "engines": { 300 + "node": ">=6.9.0" 301 + } 302 + }, 303 + "node_modules/@babel/parser": { 304 + "version": "7.28.5", 305 + "dev": true, 306 + "license": "MIT", 307 + "dependencies": { 308 + "@babel/types": "^7.28.5" 309 + }, 310 + "bin": { 311 + "parser": "bin/babel-parser.js" 312 + }, 313 + "engines": { 314 + "node": ">=6.0.0" 315 + } 316 + }, 317 + "node_modules/@babel/plugin-transform-react-jsx-self": { 318 + "version": "7.27.1", 319 + "dev": true, 320 + "license": "MIT", 321 + "dependencies": { 322 + "@babel/helper-plugin-utils": "^7.27.1" 323 + }, 324 + "engines": { 325 + "node": ">=6.9.0" 326 + }, 327 + "peerDependencies": { 328 + "@babel/core": "^7.0.0-0" 329 + } 330 + }, 331 + "node_modules/@babel/plugin-transform-react-jsx-source": { 332 + "version": "7.27.1", 333 + "dev": true, 334 + "license": "MIT", 335 + "dependencies": { 336 + "@babel/helper-plugin-utils": "^7.27.1" 337 + }, 338 + "engines": { 339 + "node": ">=6.9.0" 340 + }, 341 + "peerDependencies": { 342 + "@babel/core": "^7.0.0-0" 343 + } 344 + }, 345 + "node_modules/@babel/template": { 346 + "version": "7.27.2", 347 + "dev": true, 348 + "license": "MIT", 349 + "dependencies": { 350 + "@babel/code-frame": "^7.27.1", 351 + "@babel/parser": "^7.27.2", 352 + "@babel/types": "^7.27.1" 353 + }, 354 + "engines": { 355 + "node": ">=6.9.0" 356 + } 357 + }, 358 + "node_modules/@babel/traverse": { 359 + "version": "7.28.5", 360 + "dev": true, 361 + "license": "MIT", 362 + "dependencies": { 363 + "@babel/code-frame": "^7.27.1", 364 + "@babel/generator": "^7.28.5", 365 + "@babel/helper-globals": "^7.28.0", 366 + "@babel/parser": "^7.28.5", 367 + "@babel/template": "^7.27.2", 368 + "@babel/types": "^7.28.5", 369 + "debug": "^4.3.1" 370 + }, 371 + "engines": { 372 + "node": ">=6.9.0" 373 + } 374 + }, 375 + "node_modules/@babel/types": { 376 + "version": "7.28.5", 377 + "dev": true, 378 + "license": "MIT", 379 + "dependencies": { 380 + "@babel/helper-string-parser": "^7.27.1", 381 + "@babel/helper-validator-identifier": "^7.28.5" 382 + }, 383 + "engines": { 384 + "node": ">=6.9.0" 385 + } 386 + }, 387 + "node_modules/@badrap/valita": { 388 + "version": "0.4.6", 389 + "license": "MIT", 390 + "engines": { 391 + "node": ">= 18" 392 + } 393 + }, 394 + "node_modules/@emnapi/core": { 395 + "version": "1.7.1", 396 + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz", 397 + "integrity": "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==", 398 + "dev": true, 399 + "license": "MIT", 400 + "optional": true, 401 + "dependencies": { 402 + "@emnapi/wasi-threads": "1.1.0", 403 + "tslib": "^2.4.0" 404 + } 405 + }, 406 + "node_modules/@emnapi/runtime": { 407 + "version": "1.7.1", 408 + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz", 409 + "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==", 410 + "dev": true, 411 + "license": "MIT", 412 + "optional": true, 413 + "dependencies": { 414 + "tslib": "^2.4.0" 415 + } 416 + }, 417 + "node_modules/@emnapi/wasi-threads": { 418 + "version": "1.1.0", 419 + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", 420 + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", 421 + "dev": true, 422 + "license": "MIT", 423 + "optional": true, 424 + "dependencies": { 425 + "tslib": "^2.4.0" 426 + } 427 + }, 428 + "node_modules/@eslint-community/eslint-utils": { 429 + "version": "4.9.0", 430 + "dev": true, 431 + "license": "MIT", 432 + "dependencies": { 433 + "eslint-visitor-keys": "^3.4.3" 434 + }, 435 + "engines": { 436 + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 437 + }, 438 + "funding": { 439 + "url": "https://opencollective.com/eslint" 440 + }, 441 + "peerDependencies": { 442 + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" 443 + } 444 + }, 445 + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { 446 + "version": "3.4.3", 447 + "dev": true, 448 + "license": "Apache-2.0", 449 + "engines": { 450 + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 451 + }, 452 + "funding": { 453 + "url": "https://opencollective.com/eslint" 454 + } 455 + }, 456 + "node_modules/@eslint-community/regexpp": { 457 + "version": "4.12.2", 458 + "dev": true, 459 + "license": "MIT", 460 + "engines": { 461 + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" 462 + } 463 + }, 464 + "node_modules/@eslint/config-array": { 465 + "version": "0.21.1", 466 + "dev": true, 467 + "license": "Apache-2.0", 468 + "dependencies": { 469 + "@eslint/object-schema": "^2.1.7", 470 + "debug": "^4.3.1", 471 + "minimatch": "^3.1.2" 472 + }, 473 + "engines": { 474 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 475 + } 476 + }, 477 + "node_modules/@eslint/config-array/node_modules/minimatch": { 478 + "version": "3.1.2", 479 + "dev": true, 480 + "license": "ISC", 481 + "dependencies": { 482 + "brace-expansion": "^1.1.7" 483 + }, 484 + "engines": { 485 + "node": "*" 486 + } 487 + }, 488 + "node_modules/@eslint/config-helpers": { 489 + "version": "0.4.2", 490 + "dev": true, 491 + "license": "Apache-2.0", 492 + "dependencies": { 493 + "@eslint/core": "^0.17.0" 494 + }, 495 + "engines": { 496 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 497 + } 498 + }, 499 + "node_modules/@eslint/core": { 500 + "version": "0.17.0", 501 + "dev": true, 502 + "license": "Apache-2.0", 503 + "dependencies": { 504 + "@types/json-schema": "^7.0.15" 505 + }, 506 + "engines": { 507 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 508 + } 509 + }, 510 + "node_modules/@eslint/eslintrc": { 511 + "version": "3.3.3", 512 + "dev": true, 513 + "license": "MIT", 514 + "dependencies": { 515 + "ajv": "^6.12.4", 516 + "debug": "^4.3.2", 517 + "espree": "^10.0.1", 518 + "globals": "^14.0.0", 519 + "ignore": "^5.2.0", 520 + "import-fresh": "^3.2.1", 521 + "js-yaml": "^4.1.1", 522 + "minimatch": "^3.1.2", 523 + "strip-json-comments": "^3.1.1" 524 + }, 525 + "engines": { 526 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 527 + }, 528 + "funding": { 529 + "url": "https://opencollective.com/eslint" 530 + } 531 + }, 532 + "node_modules/@eslint/eslintrc/node_modules/ajv": { 533 + "version": "6.12.6", 534 + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 535 + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 536 + "dev": true, 537 + "license": "MIT", 538 + "dependencies": { 539 + "fast-deep-equal": "^3.1.1", 540 + "fast-json-stable-stringify": "^2.0.0", 541 + "json-schema-traverse": "^0.4.1", 542 + "uri-js": "^4.2.2" 543 + }, 544 + "funding": { 545 + "type": "github", 546 + "url": "https://github.com/sponsors/epoberezkin" 547 + } 548 + }, 549 + "node_modules/@eslint/eslintrc/node_modules/globals": { 550 + "version": "14.0.0", 551 + "dev": true, 552 + "license": "MIT", 553 + "engines": { 554 + "node": ">=18" 555 + }, 556 + "funding": { 557 + "url": "https://github.com/sponsors/sindresorhus" 558 + } 559 + }, 560 + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { 561 + "version": "0.4.1", 562 + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 563 + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", 564 + "dev": true, 565 + "license": "MIT" 566 + }, 567 + "node_modules/@eslint/eslintrc/node_modules/minimatch": { 568 + "version": "3.1.2", 569 + "dev": true, 570 + "license": "ISC", 571 + "dependencies": { 572 + "brace-expansion": "^1.1.7" 573 + }, 574 + "engines": { 575 + "node": "*" 576 + } 577 + }, 578 + "node_modules/@eslint/js": { 579 + "version": "9.39.1", 580 + "dev": true, 581 + "license": "MIT", 582 + "engines": { 583 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 584 + }, 585 + "funding": { 586 + "url": "https://eslint.org/donate" 587 + } 588 + }, 589 + "node_modules/@eslint/object-schema": { 590 + "version": "2.1.7", 591 + "dev": true, 592 + "license": "Apache-2.0", 593 + "engines": { 594 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 595 + } 596 + }, 597 + "node_modules/@eslint/plugin-kit": { 598 + "version": "0.4.1", 599 + "dev": true, 600 + "license": "Apache-2.0", 601 + "dependencies": { 602 + "@eslint/core": "^0.17.0", 603 + "levn": "^0.4.1" 604 + }, 605 + "engines": { 606 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 607 + } 608 + }, 609 + "node_modules/@humanfs/core": { 610 + "version": "0.19.1", 611 + "dev": true, 612 + "license": "Apache-2.0", 613 + "engines": { 614 + "node": ">=18.18.0" 615 + } 616 + }, 617 + "node_modules/@humanfs/node": { 618 + "version": "0.16.7", 619 + "dev": true, 620 + "license": "Apache-2.0", 621 + "dependencies": { 622 + "@humanfs/core": "^0.19.1", 623 + "@humanwhocodes/retry": "^0.4.0" 624 + }, 625 + "engines": { 626 + "node": ">=18.18.0" 627 + } 628 + }, 629 + "node_modules/@humanwhocodes/module-importer": { 630 + "version": "1.0.1", 631 + "dev": true, 632 + "license": "Apache-2.0", 633 + "engines": { 634 + "node": ">=12.22" 635 + }, 636 + "funding": { 637 + "type": "github", 638 + "url": "https://github.com/sponsors/nzakas" 639 + } 640 + }, 641 + "node_modules/@humanwhocodes/retry": { 642 + "version": "0.4.3", 643 + "dev": true, 644 + "license": "Apache-2.0", 645 + "engines": { 646 + "node": ">=18.18" 647 + }, 648 + "funding": { 649 + "type": "github", 650 + "url": "https://github.com/sponsors/nzakas" 651 + } 652 + }, 653 + "node_modules/@isaacs/balanced-match": { 654 + "version": "4.0.1", 655 + "dev": true, 656 + "license": "MIT", 657 + "engines": { 658 + "node": "20 || >=22" 659 + } 660 + }, 661 + "node_modules/@isaacs/brace-expansion": { 662 + "version": "5.0.0", 663 + "dev": true, 664 + "license": "MIT", 665 + "dependencies": { 666 + "@isaacs/balanced-match": "^4.0.1" 667 + }, 668 + "engines": { 669 + "node": "20 || >=22" 670 + } 671 + }, 672 + "node_modules/@jridgewell/gen-mapping": { 673 + "version": "0.3.13", 674 + "dev": true, 675 + "license": "MIT", 676 + "dependencies": { 677 + "@jridgewell/sourcemap-codec": "^1.5.0", 678 + "@jridgewell/trace-mapping": "^0.3.24" 679 + } 680 + }, 681 + "node_modules/@jridgewell/remapping": { 682 + "version": "2.3.5", 683 + "dev": true, 684 + "license": "MIT", 685 + "dependencies": { 686 + "@jridgewell/gen-mapping": "^0.3.5", 687 + "@jridgewell/trace-mapping": "^0.3.24" 688 + } 689 + }, 690 + "node_modules/@jridgewell/resolve-uri": { 691 + "version": "3.1.2", 692 + "dev": true, 693 + "license": "MIT", 694 + "engines": { 695 + "node": ">=6.0.0" 696 + } 697 + }, 698 + "node_modules/@jridgewell/source-map": { 699 + "version": "0.3.11", 700 + "dev": true, 701 + "license": "MIT", 702 + "optional": true, 703 + "dependencies": { 704 + "@jridgewell/gen-mapping": "^0.3.5", 705 + "@jridgewell/trace-mapping": "^0.3.25" 706 + } 707 + }, 708 + "node_modules/@jridgewell/sourcemap-codec": { 709 + "version": "1.5.5", 710 + "dev": true, 711 + "license": "MIT" 712 + }, 713 + "node_modules/@jridgewell/trace-mapping": { 714 + "version": "0.3.31", 715 + "dev": true, 716 + "license": "MIT", 717 + "dependencies": { 718 + "@jridgewell/resolve-uri": "^3.1.0", 719 + "@jridgewell/sourcemap-codec": "^1.4.14" 720 + } 721 + }, 722 + "node_modules/@microsoft/api-extractor": { 723 + "version": "7.55.1", 724 + "dev": true, 725 + "license": "MIT", 726 + "dependencies": { 727 + "@microsoft/api-extractor-model": "7.32.1", 728 + "@microsoft/tsdoc": "~0.16.0", 729 + "@microsoft/tsdoc-config": "~0.18.0", 730 + "@rushstack/node-core-library": "5.19.0", 731 + "@rushstack/rig-package": "0.6.0", 732 + "@rushstack/terminal": "0.19.4", 733 + "@rushstack/ts-command-line": "5.1.4", 734 + "diff": "~8.0.2", 735 + "lodash": "~4.17.15", 736 + "minimatch": "10.0.3", 737 + "resolve": "~1.22.1", 738 + "semver": "~7.5.4", 739 + "source-map": "~0.6.1", 740 + "typescript": "5.8.2" 741 + }, 742 + "bin": { 743 + "api-extractor": "bin/api-extractor" 744 + } 745 + }, 746 + "node_modules/@microsoft/api-extractor-model": { 747 + "version": "7.32.1", 748 + "dev": true, 749 + "license": "MIT", 750 + "dependencies": { 751 + "@microsoft/tsdoc": "~0.16.0", 752 + "@microsoft/tsdoc-config": "~0.18.0", 753 + "@rushstack/node-core-library": "5.19.0" 754 + } 755 + }, 756 + "node_modules/@microsoft/api-extractor/node_modules/typescript": { 757 + "version": "5.8.2", 758 + "dev": true, 759 + "license": "Apache-2.0", 760 + "bin": { 761 + "tsc": "bin/tsc", 762 + "tsserver": "bin/tsserver" 763 + }, 764 + "engines": { 765 + "node": ">=14.17" 766 + } 767 + }, 768 + "node_modules/@microsoft/tsdoc": { 769 + "version": "0.16.0", 770 + "dev": true, 771 + "license": "MIT" 772 + }, 773 + "node_modules/@microsoft/tsdoc-config": { 774 + "version": "0.18.0", 775 + "dev": true, 776 + "license": "MIT", 777 + "dependencies": { 778 + "@microsoft/tsdoc": "0.16.0", 779 + "ajv": "~8.12.0", 780 + "jju": "~1.4.0", 781 + "resolve": "~1.22.2" 782 + } 783 + }, 784 + "node_modules/@microsoft/tsdoc-config/node_modules/ajv": { 785 + "version": "8.12.0", 786 + "dev": true, 787 + "license": "MIT", 788 + "dependencies": { 789 + "fast-deep-equal": "^3.1.1", 790 + "json-schema-traverse": "^1.0.0", 791 + "require-from-string": "^2.0.2", 792 + "uri-js": "^4.2.2" 793 + }, 794 + "funding": { 795 + "type": "github", 796 + "url": "https://github.com/sponsors/epoberezkin" 797 + } 798 + }, 799 + "node_modules/@napi-rs/wasm-runtime": { 800 + "version": "1.1.0", 801 + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.0.tgz", 802 + "integrity": "sha512-Fq6DJW+Bb5jaWE69/qOE0D1TUN9+6uWhCeZpdnSBk14pjLcCWR7Q8n49PTSPHazM37JqrsdpEthXy2xn6jWWiA==", 803 + "dev": true, 804 + "license": "MIT", 805 + "optional": true, 806 + "dependencies": { 807 + "@emnapi/core": "^1.7.1", 808 + "@emnapi/runtime": "^1.7.1", 809 + "@tybys/wasm-util": "^0.10.1" 810 + } 811 + }, 812 + "node_modules/@oxc-project/runtime": { 813 + "version": "0.92.0", 814 + "dev": true, 815 + "license": "MIT", 816 + "engines": { 817 + "node": "^20.19.0 || >=22.12.0" 818 + } 819 + }, 820 + "node_modules/@oxc-project/types": { 821 + "version": "0.93.0", 822 + "dev": true, 823 + "license": "MIT", 824 + "funding": { 825 + "url": "https://github.com/sponsors/Boshen" 826 + } 827 + }, 828 + "node_modules/@rolldown/binding-android-arm64": { 829 + "version": "1.0.0-beta.41", 830 + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-beta.41.tgz", 831 + "integrity": "sha512-Edflndd9lU7JVhVIvJlZhdCj5DkhYDJPIRn4Dx0RUdfc8asP9xHOI5gMd8MesDDx+BJpdIT/uAmVTearteU/mQ==", 832 + "cpu": [ 833 + "arm64" 834 + ], 835 + "dev": true, 836 + "license": "MIT", 837 + "optional": true, 838 + "os": [ 839 + "android" 840 + ], 841 + "engines": { 842 + "node": "^20.19.0 || >=22.12.0" 843 + } 844 + }, 845 + "node_modules/@rolldown/binding-darwin-arm64": { 846 + "version": "1.0.0-beta.41", 847 + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-beta.41.tgz", 848 + "integrity": "sha512-XGCzqfjdk7550PlyZRTBKbypXrB7ATtXhw/+bjtxnklLQs0mKP/XkQVOKyn9qGKSlvH8I56JLYryVxl0PCvSNw==", 849 + "cpu": [ 850 + "arm64" 851 + ], 852 + "dev": true, 853 + "license": "MIT", 854 + "optional": true, 855 + "os": [ 856 + "darwin" 857 + ], 858 + "engines": { 859 + "node": "^20.19.0 || >=22.12.0" 860 + } 861 + }, 862 + "node_modules/@rolldown/binding-darwin-x64": { 863 + "version": "1.0.0-beta.41", 864 + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-beta.41.tgz", 865 + "integrity": "sha512-Ho6lIwGJed98zub7n0xcRKuEtnZgbxevAmO4x3zn3C3N4GVXZD5xvCvTVxSMoeBJwTcIYzkVDRTIhylQNsTgLQ==", 866 + "cpu": [ 867 + "x64" 868 + ], 869 + "dev": true, 870 + "license": "MIT", 871 + "optional": true, 872 + "os": [ 873 + "darwin" 874 + ], 875 + "engines": { 876 + "node": "^20.19.0 || >=22.12.0" 877 + } 878 + }, 879 + "node_modules/@rolldown/binding-freebsd-x64": { 880 + "version": "1.0.0-beta.41", 881 + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-beta.41.tgz", 882 + "integrity": "sha512-ijAZETywvL+gACjbT4zBnCp5ez1JhTRs6OxRN4J+D6AzDRbU2zb01Esl51RP5/8ZOlvB37xxsRQ3X4YRVyYb3g==", 883 + "cpu": [ 884 + "x64" 885 + ], 886 + "dev": true, 887 + "license": "MIT", 888 + "optional": true, 889 + "os": [ 890 + "freebsd" 891 + ], 892 + "engines": { 893 + "node": "^20.19.0 || >=22.12.0" 894 + } 895 + }, 896 + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { 897 + "version": "1.0.0-beta.41", 898 + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-beta.41.tgz", 899 + "integrity": "sha512-EgIOZt7UildXKFEFvaiLNBXm+4ggQyGe3E5Z1QP9uRcJJs9omihOnm897FwOBQdCuMvI49iBgjFrkhH+wMJ2MA==", 900 + "cpu": [ 901 + "arm" 902 + ], 903 + "dev": true, 904 + "license": "MIT", 905 + "optional": true, 906 + "os": [ 907 + "linux" 908 + ], 909 + "engines": { 910 + "node": "^20.19.0 || >=22.12.0" 911 + } 912 + }, 913 + "node_modules/@rolldown/binding-linux-arm64-gnu": { 914 + "version": "1.0.0-beta.41", 915 + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-beta.41.tgz", 916 + "integrity": "sha512-F8bUwJq8v/JAU8HSwgF4dztoqJ+FjdyjuvX4//3+Fbe2we9UktFeZ27U4lRMXF1vxWtdV4ey6oCSqI7yUrSEeg==", 917 + "cpu": [ 918 + "arm64" 919 + ], 920 + "dev": true, 921 + "license": "MIT", 922 + "optional": true, 923 + "os": [ 924 + "linux" 925 + ], 926 + "engines": { 927 + "node": "^20.19.0 || >=22.12.0" 928 + } 929 + }, 930 + "node_modules/@rolldown/binding-linux-arm64-musl": { 931 + "version": "1.0.0-beta.41", 932 + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-beta.41.tgz", 933 + "integrity": "sha512-MioXcCIX/wB1pBnBoJx8q4OGucUAfC1+/X1ilKFsjDK05VwbLZGRgOVD5OJJpUQPK86DhQciNBrfOKDiatxNmg==", 934 + "cpu": [ 935 + "arm64" 936 + ], 937 + "dev": true, 938 + "license": "MIT", 939 + "optional": true, 940 + "os": [ 941 + "linux" 942 + ], 943 + "engines": { 944 + "node": "^20.19.0 || >=22.12.0" 945 + } 946 + }, 947 + "node_modules/@rolldown/binding-linux-x64-gnu": { 948 + "version": "1.0.0-beta.41", 949 + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-beta.41.tgz", 950 + "integrity": "sha512-m66M61fizvRCwt5pOEiZQMiwBL9/y0bwU/+Kc4Ce/Pef6YfoEkR28y+DzN9rMdjo8Z28NXjsDPq9nH4mXnAP0g==", 951 + "cpu": [ 952 + "x64" 953 + ], 954 + "dev": true, 955 + "license": "MIT", 956 + "optional": true, 957 + "os": [ 958 + "linux" 959 + ], 960 + "engines": { 961 + "node": "^20.19.0 || >=22.12.0" 962 + } 963 + }, 964 + "node_modules/@rolldown/binding-linux-x64-musl": { 965 + "version": "1.0.0-beta.41", 966 + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-beta.41.tgz", 967 + "integrity": "sha512-yRxlSfBvWnnfrdtJfvi9lg8xfG5mPuyoSHm0X01oiE8ArmLRvoJGHUTJydCYz+wbK2esbq5J4B4Tq9WAsOlP1Q==", 968 + "cpu": [ 969 + "x64" 970 + ], 971 + "dev": true, 972 + "license": "MIT", 973 + "optional": true, 974 + "os": [ 975 + "linux" 976 + ], 977 + "engines": { 978 + "node": "^20.19.0 || >=22.12.0" 979 + } 980 + }, 981 + "node_modules/@rolldown/binding-openharmony-arm64": { 982 + "version": "1.0.0-beta.41", 983 + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-beta.41.tgz", 984 + "integrity": "sha512-PHVxYhBpi8UViS3/hcvQQb9RFqCtvFmFU1PvUoTRiUdBtgHA6fONNHU4x796lgzNlVSD3DO/MZNk1s5/ozSMQg==", 985 + "cpu": [ 986 + "arm64" 987 + ], 988 + "dev": true, 989 + "license": "MIT", 990 + "optional": true, 991 + "os": [ 992 + "openharmony" 993 + ], 994 + "engines": { 995 + "node": "^20.19.0 || >=22.12.0" 996 + } 997 + }, 998 + "node_modules/@rolldown/binding-wasm32-wasi": { 999 + "version": "1.0.0-beta.41", 1000 + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-beta.41.tgz", 1001 + "integrity": "sha512-OAfcO37ME6GGWmj9qTaDT7jY4rM0T2z0/8ujdQIJQ2x2nl+ztO32EIwURfmXOK0U1tzkyuaKYvE34Pug/ucXlQ==", 1002 + "cpu": [ 1003 + "wasm32" 1004 + ], 1005 + "dev": true, 1006 + "license": "MIT", 1007 + "optional": true, 1008 + "dependencies": { 1009 + "@napi-rs/wasm-runtime": "^1.0.5" 1010 + }, 1011 + "engines": { 1012 + "node": ">=14.0.0" 1013 + } 1014 + }, 1015 + "node_modules/@rolldown/binding-win32-arm64-msvc": { 1016 + "version": "1.0.0-beta.41", 1017 + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-beta.41.tgz", 1018 + "integrity": "sha512-NIYGuCcuXaq5BC4Q3upbiMBvmZsTsEPG9k/8QKQdmrch+ocSy5Jv9tdpdmXJyighKqm182nh/zBt+tSJkYoNlg==", 1019 + "cpu": [ 1020 + "arm64" 1021 + ], 1022 + "dev": true, 1023 + "license": "MIT", 1024 + "optional": true, 1025 + "os": [ 1026 + "win32" 1027 + ], 1028 + "engines": { 1029 + "node": "^20.19.0 || >=22.12.0" 1030 + } 1031 + }, 1032 + "node_modules/@rolldown/binding-win32-ia32-msvc": { 1033 + "version": "1.0.0-beta.41", 1034 + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.0.0-beta.41.tgz", 1035 + "integrity": "sha512-kANdsDbE5FkEOb5NrCGBJBCaZ2Sabp3D7d4PRqMYJqyLljwh9mDyYyYSv5+QNvdAmifj+f3lviNEUUuUZPEFPw==", 1036 + "cpu": [ 1037 + "ia32" 1038 + ], 1039 + "dev": true, 1040 + "license": "MIT", 1041 + "optional": true, 1042 + "os": [ 1043 + "win32" 1044 + ], 1045 + "engines": { 1046 + "node": "^20.19.0 || >=22.12.0" 1047 + } 1048 + }, 1049 + "node_modules/@rolldown/binding-win32-x64-msvc": { 1050 + "version": "1.0.0-beta.41", 1051 + "cpu": [ 1052 + "x64" 1053 + ], 1054 + "dev": true, 1055 + "license": "MIT", 1056 + "optional": true, 1057 + "os": [ 1058 + "win32" 1059 + ], 1060 + "engines": { 1061 + "node": "^20.19.0 || >=22.12.0" 1062 + } 1063 + }, 1064 + "node_modules/@rolldown/pluginutils": { 1065 + "version": "1.0.0-beta.47", 1066 + "dev": true, 1067 + "license": "MIT" 1068 + }, 1069 + "node_modules/@rollup/pluginutils": { 1070 + "version": "4.2.1", 1071 + "dev": true, 1072 + "license": "MIT", 1073 + "dependencies": { 1074 + "estree-walker": "^2.0.1", 1075 + "picomatch": "^2.2.2" 1076 + }, 1077 + "engines": { 1078 + "node": ">= 8.0.0" 1079 + } 1080 + }, 1081 + "node_modules/@rollup/pluginutils/node_modules/picomatch": { 1082 + "version": "2.3.1", 1083 + "dev": true, 1084 + "license": "MIT", 1085 + "engines": { 1086 + "node": ">=8.6" 1087 + }, 1088 + "funding": { 1089 + "url": "https://github.com/sponsors/jonschlinkert" 1090 + } 1091 + }, 1092 + "node_modules/@rollup/rollup-android-arm-eabi": { 1093 + "version": "4.53.3", 1094 + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.3.tgz", 1095 + "integrity": "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==", 1096 + "cpu": [ 1097 + "arm" 1098 + ], 1099 + "dev": true, 1100 + "license": "MIT", 1101 + "optional": true, 1102 + "os": [ 1103 + "android" 1104 + ] 1105 + }, 1106 + "node_modules/@rollup/rollup-android-arm64": { 1107 + "version": "4.53.3", 1108 + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.3.tgz", 1109 + "integrity": "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==", 1110 + "cpu": [ 1111 + "arm64" 1112 + ], 1113 + "dev": true, 1114 + "license": "MIT", 1115 + "optional": true, 1116 + "os": [ 1117 + "android" 1118 + ] 1119 + }, 1120 + "node_modules/@rollup/rollup-darwin-arm64": { 1121 + "version": "4.53.3", 1122 + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.3.tgz", 1123 + "integrity": "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==", 1124 + "cpu": [ 1125 + "arm64" 1126 + ], 1127 + "dev": true, 1128 + "license": "MIT", 1129 + "optional": true, 1130 + "os": [ 1131 + "darwin" 1132 + ] 1133 + }, 1134 + "node_modules/@rollup/rollup-darwin-x64": { 1135 + "version": "4.53.3", 1136 + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.3.tgz", 1137 + "integrity": "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==", 1138 + "cpu": [ 1139 + "x64" 1140 + ], 1141 + "dev": true, 1142 + "license": "MIT", 1143 + "optional": true, 1144 + "os": [ 1145 + "darwin" 1146 + ] 1147 + }, 1148 + "node_modules/@rollup/rollup-freebsd-arm64": { 1149 + "version": "4.53.3", 1150 + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.3.tgz", 1151 + "integrity": "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==", 1152 + "cpu": [ 1153 + "arm64" 1154 + ], 1155 + "dev": true, 1156 + "license": "MIT", 1157 + "optional": true, 1158 + "os": [ 1159 + "freebsd" 1160 + ] 1161 + }, 1162 + "node_modules/@rollup/rollup-freebsd-x64": { 1163 + "version": "4.53.3", 1164 + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.3.tgz", 1165 + "integrity": "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==", 1166 + "cpu": [ 1167 + "x64" 1168 + ], 1169 + "dev": true, 1170 + "license": "MIT", 1171 + "optional": true, 1172 + "os": [ 1173 + "freebsd" 1174 + ] 1175 + }, 1176 + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { 1177 + "version": "4.53.3", 1178 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.3.tgz", 1179 + "integrity": "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==", 1180 + "cpu": [ 1181 + "arm" 1182 + ], 1183 + "dev": true, 1184 + "license": "MIT", 1185 + "optional": true, 1186 + "os": [ 1187 + "linux" 1188 + ] 1189 + }, 1190 + "node_modules/@rollup/rollup-linux-arm-musleabihf": { 1191 + "version": "4.53.3", 1192 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.3.tgz", 1193 + "integrity": "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==", 1194 + "cpu": [ 1195 + "arm" 1196 + ], 1197 + "dev": true, 1198 + "license": "MIT", 1199 + "optional": true, 1200 + "os": [ 1201 + "linux" 1202 + ] 1203 + }, 1204 + "node_modules/@rollup/rollup-linux-arm64-gnu": { 1205 + "version": "4.53.3", 1206 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.3.tgz", 1207 + "integrity": "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==", 1208 + "cpu": [ 1209 + "arm64" 1210 + ], 1211 + "dev": true, 1212 + "license": "MIT", 1213 + "optional": true, 1214 + "os": [ 1215 + "linux" 1216 + ] 1217 + }, 1218 + "node_modules/@rollup/rollup-linux-arm64-musl": { 1219 + "version": "4.53.3", 1220 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.3.tgz", 1221 + "integrity": "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==", 1222 + "cpu": [ 1223 + "arm64" 1224 + ], 1225 + "dev": true, 1226 + "license": "MIT", 1227 + "optional": true, 1228 + "os": [ 1229 + "linux" 1230 + ] 1231 + }, 1232 + "node_modules/@rollup/rollup-linux-loong64-gnu": { 1233 + "version": "4.53.3", 1234 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.3.tgz", 1235 + "integrity": "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==", 1236 + "cpu": [ 1237 + "loong64" 1238 + ], 1239 + "dev": true, 1240 + "license": "MIT", 1241 + "optional": true, 1242 + "os": [ 1243 + "linux" 1244 + ] 1245 + }, 1246 + "node_modules/@rollup/rollup-linux-ppc64-gnu": { 1247 + "version": "4.53.3", 1248 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.3.tgz", 1249 + "integrity": "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==", 1250 + "cpu": [ 1251 + "ppc64" 1252 + ], 1253 + "dev": true, 1254 + "license": "MIT", 1255 + "optional": true, 1256 + "os": [ 1257 + "linux" 1258 + ] 1259 + }, 1260 + "node_modules/@rollup/rollup-linux-riscv64-gnu": { 1261 + "version": "4.53.3", 1262 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.3.tgz", 1263 + "integrity": "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==", 1264 + "cpu": [ 1265 + "riscv64" 1266 + ], 1267 + "dev": true, 1268 + "license": "MIT", 1269 + "optional": true, 1270 + "os": [ 1271 + "linux" 1272 + ] 1273 + }, 1274 + "node_modules/@rollup/rollup-linux-riscv64-musl": { 1275 + "version": "4.53.3", 1276 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.3.tgz", 1277 + "integrity": "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==", 1278 + "cpu": [ 1279 + "riscv64" 1280 + ], 1281 + "dev": true, 1282 + "license": "MIT", 1283 + "optional": true, 1284 + "os": [ 1285 + "linux" 1286 + ] 1287 + }, 1288 + "node_modules/@rollup/rollup-linux-s390x-gnu": { 1289 + "version": "4.53.3", 1290 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.3.tgz", 1291 + "integrity": "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==", 1292 + "cpu": [ 1293 + "s390x" 1294 + ], 1295 + "dev": true, 1296 + "license": "MIT", 1297 + "optional": true, 1298 + "os": [ 1299 + "linux" 1300 + ] 1301 + }, 1302 + "node_modules/@rollup/rollup-linux-x64-gnu": { 1303 + "version": "4.53.3", 1304 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.3.tgz", 1305 + "integrity": "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==", 1306 + "cpu": [ 1307 + "x64" 1308 + ], 1309 + "dev": true, 1310 + "license": "MIT", 1311 + "optional": true, 1312 + "os": [ 1313 + "linux" 1314 + ] 1315 + }, 1316 + "node_modules/@rollup/rollup-linux-x64-musl": { 1317 + "version": "4.53.3", 1318 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.3.tgz", 1319 + "integrity": "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==", 1320 + "cpu": [ 1321 + "x64" 1322 + ], 1323 + "dev": true, 1324 + "license": "MIT", 1325 + "optional": true, 1326 + "os": [ 1327 + "linux" 1328 + ] 1329 + }, 1330 + "node_modules/@rollup/rollup-openharmony-arm64": { 1331 + "version": "4.53.3", 1332 + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.3.tgz", 1333 + "integrity": "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==", 1334 + "cpu": [ 1335 + "arm64" 1336 + ], 1337 + "dev": true, 1338 + "license": "MIT", 1339 + "optional": true, 1340 + "os": [ 1341 + "openharmony" 1342 + ] 1343 + }, 1344 + "node_modules/@rollup/rollup-win32-arm64-msvc": { 1345 + "version": "4.53.3", 1346 + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.3.tgz", 1347 + "integrity": "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==", 1348 + "cpu": [ 1349 + "arm64" 1350 + ], 1351 + "dev": true, 1352 + "license": "MIT", 1353 + "optional": true, 1354 + "os": [ 1355 + "win32" 1356 + ] 1357 + }, 1358 + "node_modules/@rollup/rollup-win32-ia32-msvc": { 1359 + "version": "4.53.3", 1360 + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.3.tgz", 1361 + "integrity": "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==", 1362 + "cpu": [ 1363 + "ia32" 1364 + ], 1365 + "dev": true, 1366 + "license": "MIT", 1367 + "optional": true, 1368 + "os": [ 1369 + "win32" 1370 + ] 1371 + }, 1372 + "node_modules/@rollup/rollup-win32-x64-gnu": { 1373 + "version": "4.53.3", 1374 + "cpu": [ 1375 + "x64" 1376 + ], 1377 + "dev": true, 1378 + "license": "MIT", 1379 + "optional": true, 1380 + "os": [ 1381 + "win32" 1382 + ] 1383 + }, 1384 + "node_modules/@rollup/rollup-win32-x64-msvc": { 1385 + "version": "4.53.3", 1386 + "cpu": [ 1387 + "x64" 1388 + ], 1389 + "dev": true, 1390 + "license": "MIT", 1391 + "optional": true, 1392 + "os": [ 1393 + "win32" 1394 + ] 1395 + }, 1396 + "node_modules/@rushstack/node-core-library": { 1397 + "version": "5.19.0", 1398 + "dev": true, 1399 + "license": "MIT", 1400 + "dependencies": { 1401 + "ajv": "~8.13.0", 1402 + "ajv-draft-04": "~1.0.0", 1403 + "ajv-formats": "~3.0.1", 1404 + "fs-extra": "~11.3.0", 1405 + "import-lazy": "~4.0.0", 1406 + "jju": "~1.4.0", 1407 + "resolve": "~1.22.1", 1408 + "semver": "~7.5.4" 1409 + }, 1410 + "peerDependencies": { 1411 + "@types/node": "*" 1412 + }, 1413 + "peerDependenciesMeta": { 1414 + "@types/node": { 1415 + "optional": true 1416 + } 1417 + } 1418 + }, 1419 + "node_modules/@rushstack/node-core-library/node_modules/ajv": { 1420 + "version": "8.13.0", 1421 + "dev": true, 1422 + "license": "MIT", 1423 + "dependencies": { 1424 + "fast-deep-equal": "^3.1.3", 1425 + "json-schema-traverse": "^1.0.0", 1426 + "require-from-string": "^2.0.2", 1427 + "uri-js": "^4.4.1" 1428 + }, 1429 + "funding": { 1430 + "type": "github", 1431 + "url": "https://github.com/sponsors/epoberezkin" 1432 + } 1433 + }, 1434 + "node_modules/@rushstack/node-core-library/node_modules/fs-extra": { 1435 + "version": "11.3.2", 1436 + "dev": true, 1437 + "license": "MIT", 1438 + "dependencies": { 1439 + "graceful-fs": "^4.2.0", 1440 + "jsonfile": "^6.0.1", 1441 + "universalify": "^2.0.0" 1442 + }, 1443 + "engines": { 1444 + "node": ">=14.14" 1445 + } 1446 + }, 1447 + "node_modules/@rushstack/problem-matcher": { 1448 + "version": "0.1.1", 1449 + "dev": true, 1450 + "license": "MIT", 1451 + "peerDependencies": { 1452 + "@types/node": "*" 1453 + }, 1454 + "peerDependenciesMeta": { 1455 + "@types/node": { 1456 + "optional": true 1457 + } 1458 + } 1459 + }, 1460 + "node_modules/@rushstack/rig-package": { 1461 + "version": "0.6.0", 1462 + "dev": true, 1463 + "license": "MIT", 1464 + "dependencies": { 1465 + "resolve": "~1.22.1", 1466 + "strip-json-comments": "~3.1.1" 1467 + } 1468 + }, 1469 + "node_modules/@rushstack/terminal": { 1470 + "version": "0.19.4", 1471 + "dev": true, 1472 + "license": "MIT", 1473 + "dependencies": { 1474 + "@rushstack/node-core-library": "5.19.0", 1475 + "@rushstack/problem-matcher": "0.1.1", 1476 + "supports-color": "~8.1.1" 1477 + }, 1478 + "peerDependencies": { 1479 + "@types/node": "*" 1480 + }, 1481 + "peerDependenciesMeta": { 1482 + "@types/node": { 1483 + "optional": true 1484 + } 1485 + } 1486 + }, 1487 + "node_modules/@rushstack/ts-command-line": { 1488 + "version": "5.1.4", 1489 + "dev": true, 1490 + "license": "MIT", 1491 + "dependencies": { 1492 + "@rushstack/terminal": "0.19.4", 1493 + "@types/argparse": "1.0.38", 1494 + "argparse": "~1.0.9", 1495 + "string-argv": "~0.3.1" 1496 + } 1497 + }, 1498 + "node_modules/@standard-schema/spec": { 1499 + "version": "1.0.0", 1500 + "license": "MIT" 1501 + }, 1502 + "node_modules/@tybys/wasm-util": { 1503 + "version": "0.10.1", 1504 + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", 1505 + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", 1506 + "dev": true, 1507 + "license": "MIT", 1508 + "optional": true, 1509 + "dependencies": { 1510 + "tslib": "^2.4.0" 1511 + } 1512 + }, 1513 + "node_modules/@types/argparse": { 1514 + "version": "1.0.38", 1515 + "dev": true, 1516 + "license": "MIT" 1517 + }, 1518 + "node_modules/@types/babel__core": { 1519 + "version": "7.20.5", 1520 + "dev": true, 1521 + "license": "MIT", 1522 + "dependencies": { 1523 + "@babel/parser": "^7.20.7", 1524 + "@babel/types": "^7.20.7", 1525 + "@types/babel__generator": "*", 1526 + "@types/babel__template": "*", 1527 + "@types/babel__traverse": "*" 1528 + } 1529 + }, 1530 + "node_modules/@types/babel__generator": { 1531 + "version": "7.27.0", 1532 + "dev": true, 1533 + "license": "MIT", 1534 + "dependencies": { 1535 + "@babel/types": "^7.0.0" 1536 + } 1537 + }, 1538 + "node_modules/@types/babel__template": { 1539 + "version": "7.4.4", 1540 + "dev": true, 1541 + "license": "MIT", 1542 + "dependencies": { 1543 + "@babel/parser": "^7.1.0", 1544 + "@babel/types": "^7.0.0" 1545 + } 1546 + }, 1547 + "node_modules/@types/babel__traverse": { 1548 + "version": "7.28.0", 1549 + "dev": true, 1550 + "license": "MIT", 1551 + "dependencies": { 1552 + "@babel/types": "^7.28.2" 1553 + } 1554 + }, 1555 + "node_modules/@types/estree": { 1556 + "version": "1.0.8", 1557 + "dev": true, 1558 + "license": "MIT" 1559 + }, 1560 + "node_modules/@types/json-schema": { 1561 + "version": "7.0.15", 1562 + "dev": true, 1563 + "license": "MIT" 1564 + }, 1565 + "node_modules/@types/node": { 1566 + "version": "24.10.1", 1567 + "dev": true, 1568 + "license": "MIT", 1569 + "peer": true, 1570 + "dependencies": { 1571 + "undici-types": "~7.16.0" 1572 + } 1573 + }, 1574 + "node_modules/@types/react": { 1575 + "version": "19.2.7", 1576 + "dev": true, 1577 + "license": "MIT", 1578 + "peer": true, 1579 + "dependencies": { 1580 + "csstype": "^3.2.2" 1581 + } 1582 + }, 1583 + "node_modules/@types/react-dom": { 1584 + "version": "19.2.3", 1585 + "dev": true, 1586 + "license": "MIT", 1587 + "peerDependencies": { 1588 + "@types/react": "^19.2.0" 1589 + } 1590 + }, 1591 + "node_modules/@typescript-eslint/eslint-plugin": { 1592 + "version": "8.48.1", 1593 + "dev": true, 1594 + "license": "MIT", 1595 + "dependencies": { 1596 + "@eslint-community/regexpp": "^4.10.0", 1597 + "@typescript-eslint/scope-manager": "8.48.1", 1598 + "@typescript-eslint/type-utils": "8.48.1", 1599 + "@typescript-eslint/utils": "8.48.1", 1600 + "@typescript-eslint/visitor-keys": "8.48.1", 1601 + "graphemer": "^1.4.0", 1602 + "ignore": "^7.0.0", 1603 + "natural-compare": "^1.4.0", 1604 + "ts-api-utils": "^2.1.0" 1605 + }, 1606 + "engines": { 1607 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1608 + }, 1609 + "funding": { 1610 + "type": "opencollective", 1611 + "url": "https://opencollective.com/typescript-eslint" 1612 + }, 1613 + "peerDependencies": { 1614 + "@typescript-eslint/parser": "^8.48.1", 1615 + "eslint": "^8.57.0 || ^9.0.0", 1616 + "typescript": ">=4.8.4 <6.0.0" 1617 + } 1618 + }, 1619 + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { 1620 + "version": "7.0.5", 1621 + "dev": true, 1622 + "license": "MIT", 1623 + "engines": { 1624 + "node": ">= 4" 1625 + } 1626 + }, 1627 + "node_modules/@typescript-eslint/parser": { 1628 + "version": "8.48.1", 1629 + "dev": true, 1630 + "license": "MIT", 1631 + "peer": true, 1632 + "dependencies": { 1633 + "@typescript-eslint/scope-manager": "8.48.1", 1634 + "@typescript-eslint/types": "8.48.1", 1635 + "@typescript-eslint/typescript-estree": "8.48.1", 1636 + "@typescript-eslint/visitor-keys": "8.48.1", 1637 + "debug": "^4.3.4" 1638 + }, 1639 + "engines": { 1640 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1641 + }, 1642 + "funding": { 1643 + "type": "opencollective", 1644 + "url": "https://opencollective.com/typescript-eslint" 1645 + }, 1646 + "peerDependencies": { 1647 + "eslint": "^8.57.0 || ^9.0.0", 1648 + "typescript": ">=4.8.4 <6.0.0" 1649 + } 1650 + }, 1651 + "node_modules/@typescript-eslint/project-service": { 1652 + "version": "8.48.1", 1653 + "dev": true, 1654 + "license": "MIT", 1655 + "dependencies": { 1656 + "@typescript-eslint/tsconfig-utils": "^8.48.1", 1657 + "@typescript-eslint/types": "^8.48.1", 1658 + "debug": "^4.3.4" 1659 + }, 1660 + "engines": { 1661 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1662 + }, 1663 + "funding": { 1664 + "type": "opencollective", 1665 + "url": "https://opencollective.com/typescript-eslint" 1666 + }, 1667 + "peerDependencies": { 1668 + "typescript": ">=4.8.4 <6.0.0" 1669 + } 1670 + }, 1671 + "node_modules/@typescript-eslint/scope-manager": { 1672 + "version": "8.48.1", 1673 + "dev": true, 1674 + "license": "MIT", 1675 + "dependencies": { 1676 + "@typescript-eslint/types": "8.48.1", 1677 + "@typescript-eslint/visitor-keys": "8.48.1" 1678 + }, 1679 + "engines": { 1680 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1681 + }, 1682 + "funding": { 1683 + "type": "opencollective", 1684 + "url": "https://opencollective.com/typescript-eslint" 1685 + } 1686 + }, 1687 + "node_modules/@typescript-eslint/tsconfig-utils": { 1688 + "version": "8.48.1", 1689 + "dev": true, 1690 + "license": "MIT", 1691 + "engines": { 1692 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1693 + }, 1694 + "funding": { 1695 + "type": "opencollective", 1696 + "url": "https://opencollective.com/typescript-eslint" 1697 + }, 1698 + "peerDependencies": { 1699 + "typescript": ">=4.8.4 <6.0.0" 1700 + } 1701 + }, 1702 + "node_modules/@typescript-eslint/type-utils": { 1703 + "version": "8.48.1", 1704 + "dev": true, 1705 + "license": "MIT", 1706 + "dependencies": { 1707 + "@typescript-eslint/types": "8.48.1", 1708 + "@typescript-eslint/typescript-estree": "8.48.1", 1709 + "@typescript-eslint/utils": "8.48.1", 1710 + "debug": "^4.3.4", 1711 + "ts-api-utils": "^2.1.0" 1712 + }, 1713 + "engines": { 1714 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1715 + }, 1716 + "funding": { 1717 + "type": "opencollective", 1718 + "url": "https://opencollective.com/typescript-eslint" 1719 + }, 1720 + "peerDependencies": { 1721 + "eslint": "^8.57.0 || ^9.0.0", 1722 + "typescript": ">=4.8.4 <6.0.0" 1723 + } 1724 + }, 1725 + "node_modules/@typescript-eslint/types": { 1726 + "version": "8.48.1", 1727 + "dev": true, 1728 + "license": "MIT", 1729 + "engines": { 1730 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1731 + }, 1732 + "funding": { 1733 + "type": "opencollective", 1734 + "url": "https://opencollective.com/typescript-eslint" 1735 + } 1736 + }, 1737 + "node_modules/@typescript-eslint/typescript-estree": { 1738 + "version": "8.48.1", 1739 + "dev": true, 1740 + "license": "MIT", 1741 + "dependencies": { 1742 + "@typescript-eslint/project-service": "8.48.1", 1743 + "@typescript-eslint/tsconfig-utils": "8.48.1", 1744 + "@typescript-eslint/types": "8.48.1", 1745 + "@typescript-eslint/visitor-keys": "8.48.1", 1746 + "debug": "^4.3.4", 1747 + "minimatch": "^9.0.4", 1748 + "semver": "^7.6.0", 1749 + "tinyglobby": "^0.2.15", 1750 + "ts-api-utils": "^2.1.0" 1751 + }, 1752 + "engines": { 1753 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1754 + }, 1755 + "funding": { 1756 + "type": "opencollective", 1757 + "url": "https://opencollective.com/typescript-eslint" 1758 + }, 1759 + "peerDependencies": { 1760 + "typescript": ">=4.8.4 <6.0.0" 1761 + } 1762 + }, 1763 + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { 1764 + "version": "9.0.5", 1765 + "dev": true, 1766 + "license": "ISC", 1767 + "dependencies": { 1768 + "brace-expansion": "^2.0.1" 1769 + }, 1770 + "engines": { 1771 + "node": ">=16 || 14 >=14.17" 1772 + }, 1773 + "funding": { 1774 + "url": "https://github.com/sponsors/isaacs" 1775 + } 1776 + }, 1777 + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch/node_modules/brace-expansion": { 1778 + "version": "2.0.2", 1779 + "dev": true, 1780 + "license": "MIT", 1781 + "dependencies": { 1782 + "balanced-match": "^1.0.0" 1783 + } 1784 + }, 1785 + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { 1786 + "version": "7.7.3", 1787 + "dev": true, 1788 + "license": "ISC", 1789 + "bin": { 1790 + "semver": "bin/semver.js" 1791 + }, 1792 + "engines": { 1793 + "node": ">=10" 1794 + } 1795 + }, 1796 + "node_modules/@typescript-eslint/utils": { 1797 + "version": "8.48.1", 1798 + "dev": true, 1799 + "license": "MIT", 1800 + "dependencies": { 1801 + "@eslint-community/eslint-utils": "^4.7.0", 1802 + "@typescript-eslint/scope-manager": "8.48.1", 1803 + "@typescript-eslint/types": "8.48.1", 1804 + "@typescript-eslint/typescript-estree": "8.48.1" 1805 + }, 1806 + "engines": { 1807 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1808 + }, 1809 + "funding": { 1810 + "type": "opencollective", 1811 + "url": "https://opencollective.com/typescript-eslint" 1812 + }, 1813 + "peerDependencies": { 1814 + "eslint": "^8.57.0 || ^9.0.0", 1815 + "typescript": ">=4.8.4 <6.0.0" 1816 + } 1817 + }, 1818 + "node_modules/@typescript-eslint/visitor-keys": { 1819 + "version": "8.48.1", 1820 + "dev": true, 1821 + "license": "MIT", 1822 + "dependencies": { 1823 + "@typescript-eslint/types": "8.48.1", 1824 + "eslint-visitor-keys": "^4.2.1" 1825 + }, 1826 + "engines": { 1827 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 1828 + }, 1829 + "funding": { 1830 + "type": "opencollective", 1831 + "url": "https://opencollective.com/typescript-eslint" 1832 + } 1833 + }, 1834 + "node_modules/@vitejs/plugin-react": { 1835 + "version": "5.1.1", 1836 + "dev": true, 1837 + "license": "MIT", 1838 + "dependencies": { 1839 + "@babel/core": "^7.28.5", 1840 + "@babel/plugin-transform-react-jsx-self": "^7.27.1", 1841 + "@babel/plugin-transform-react-jsx-source": "^7.27.1", 1842 + "@rolldown/pluginutils": "1.0.0-beta.47", 1843 + "@types/babel__core": "^7.20.5", 1844 + "react-refresh": "^0.18.0" 1845 + }, 1846 + "engines": { 1847 + "node": "^20.19.0 || >=22.12.0" 1848 + }, 1849 + "peerDependencies": { 1850 + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" 1851 + } 1852 + }, 1853 + "node_modules/@volar/language-core": { 1854 + "version": "2.4.26", 1855 + "dev": true, 1856 + "license": "MIT", 1857 + "dependencies": { 1858 + "@volar/source-map": "2.4.26" 1859 + } 1860 + }, 1861 + "node_modules/@volar/source-map": { 1862 + "version": "2.4.26", 1863 + "dev": true, 1864 + "license": "MIT" 1865 + }, 1866 + "node_modules/@volar/typescript": { 1867 + "version": "2.4.26", 1868 + "dev": true, 1869 + "license": "MIT", 1870 + "dependencies": { 1871 + "@volar/language-core": "2.4.26", 1872 + "path-browserify": "^1.0.1", 1873 + "vscode-uri": "^3.0.8" 1874 + } 1875 + }, 1876 + "node_modules/acorn": { 1877 + "version": "8.15.0", 1878 + "dev": true, 1879 + "license": "MIT", 1880 + "peer": true, 1881 + "bin": { 1882 + "acorn": "bin/acorn" 1883 + }, 1884 + "engines": { 1885 + "node": ">=0.4.0" 1886 + } 1887 + }, 1888 + "node_modules/acorn-jsx": { 1889 + "version": "5.3.2", 1890 + "dev": true, 1891 + "license": "MIT", 1892 + "peerDependencies": { 1893 + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" 1894 + } 1895 + }, 1896 + "node_modules/ajv": { 1897 + "version": "8.17.1", 1898 + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", 1899 + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", 1900 + "dev": true, 1901 + "license": "MIT", 1902 + "peer": true, 1903 + "dependencies": { 1904 + "fast-deep-equal": "^3.1.3", 1905 + "fast-uri": "^3.0.1", 1906 + "json-schema-traverse": "^1.0.0", 1907 + "require-from-string": "^2.0.2" 1908 + }, 1909 + "funding": { 1910 + "type": "github", 1911 + "url": "https://github.com/sponsors/epoberezkin" 1912 + } 1913 + }, 1914 + "node_modules/ajv-draft-04": { 1915 + "version": "1.0.0", 1916 + "dev": true, 1917 + "license": "MIT", 1918 + "peerDependencies": { 1919 + "ajv": "^8.5.0" 1920 + }, 1921 + "peerDependenciesMeta": { 1922 + "ajv": { 1923 + "optional": true 1924 + } 1925 + } 1926 + }, 1927 + "node_modules/ajv-formats": { 1928 + "version": "3.0.1", 1929 + "dev": true, 1930 + "license": "MIT", 1931 + "dependencies": { 1932 + "ajv": "^8.0.0" 1933 + }, 1934 + "peerDependencies": { 1935 + "ajv": "^8.0.0" 1936 + }, 1937 + "peerDependenciesMeta": { 1938 + "ajv": { 1939 + "optional": true 1940 + } 1941 + } 1942 + }, 1943 + "node_modules/ansi-styles": { 1944 + "version": "4.3.0", 1945 + "dev": true, 1946 + "license": "MIT", 1947 + "dependencies": { 1948 + "color-convert": "^2.0.1" 1949 + }, 1950 + "engines": { 1951 + "node": ">=8" 1952 + }, 1953 + "funding": { 1954 + "url": "https://github.com/chalk/ansi-styles?sponsor=1" 1955 + } 1956 + }, 1957 + "node_modules/ansis": { 1958 + "version": "4.2.0", 1959 + "dev": true, 1960 + "license": "ISC", 1961 + "engines": { 1962 + "node": ">=14" 1963 + } 1964 + }, 1965 + "node_modules/argparse": { 1966 + "version": "1.0.10", 1967 + "dev": true, 1968 + "license": "MIT", 1969 + "dependencies": { 1970 + "sprintf-js": "~1.0.2" 1971 + } 1972 + }, 1973 + "node_modules/balanced-match": { 1974 + "version": "1.0.2", 1975 + "dev": true, 1976 + "license": "MIT" 1977 + }, 1978 + "node_modules/baseline-browser-mapping": { 1979 + "version": "2.8.32", 1980 + "dev": true, 1981 + "license": "Apache-2.0", 1982 + "bin": { 1983 + "baseline-browser-mapping": "dist/cli.js" 1984 + } 1985 + }, 1986 + "node_modules/brace-expansion": { 1987 + "version": "1.1.12", 1988 + "dev": true, 1989 + "license": "MIT", 1990 + "dependencies": { 1991 + "balanced-match": "^1.0.0", 1992 + "concat-map": "0.0.1" 1993 + } 1994 + }, 1995 + "node_modules/browserslist": { 1996 + "version": "4.28.0", 1997 + "dev": true, 1998 + "funding": [ 1999 + { 2000 + "type": "opencollective", 2001 + "url": "https://opencollective.com/browserslist" 2002 + }, 2003 + { 2004 + "type": "tidelift", 2005 + "url": "https://tidelift.com/funding/github/npm/browserslist" 2006 + }, 2007 + { 2008 + "type": "github", 2009 + "url": "https://github.com/sponsors/ai" 2010 + } 2011 + ], 2012 + "license": "MIT", 2013 + "peer": true, 2014 + "dependencies": { 2015 + "baseline-browser-mapping": "^2.8.25", 2016 + "caniuse-lite": "^1.0.30001754", 2017 + "electron-to-chromium": "^1.5.249", 2018 + "node-releases": "^2.0.27", 2019 + "update-browserslist-db": "^1.1.4" 2020 + }, 2021 + "bin": { 2022 + "browserslist": "cli.js" 2023 + }, 2024 + "engines": { 2025 + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" 2026 + } 2027 + }, 2028 + "node_modules/buffer-from": { 2029 + "version": "1.1.2", 2030 + "dev": true, 2031 + "license": "MIT", 2032 + "optional": true 2033 + }, 2034 + "node_modules/callsites": { 2035 + "version": "3.1.0", 2036 + "dev": true, 2037 + "license": "MIT", 2038 + "engines": { 2039 + "node": ">=6" 2040 + } 2041 + }, 2042 + "node_modules/caniuse-lite": { 2043 + "version": "1.0.30001759", 2044 + "dev": true, 2045 + "funding": [ 2046 + { 2047 + "type": "opencollective", 2048 + "url": "https://opencollective.com/browserslist" 2049 + }, 2050 + { 2051 + "type": "tidelift", 2052 + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" 2053 + }, 2054 + { 2055 + "type": "github", 2056 + "url": "https://github.com/sponsors/ai" 2057 + } 2058 + ], 2059 + "license": "CC-BY-4.0" 2060 + }, 2061 + "node_modules/chalk": { 2062 + "version": "4.1.2", 2063 + "dev": true, 2064 + "license": "MIT", 2065 + "dependencies": { 2066 + "ansi-styles": "^4.1.0", 2067 + "supports-color": "^7.1.0" 2068 + }, 2069 + "engines": { 2070 + "node": ">=10" 2071 + }, 2072 + "funding": { 2073 + "url": "https://github.com/chalk/chalk?sponsor=1" 2074 + } 2075 + }, 2076 + "node_modules/chalk/node_modules/supports-color": { 2077 + "version": "7.2.0", 2078 + "dev": true, 2079 + "license": "MIT", 2080 + "dependencies": { 2081 + "has-flag": "^4.0.0" 2082 + }, 2083 + "engines": { 2084 + "node": ">=8" 2085 + } 2086 + }, 2087 + "node_modules/color-convert": { 2088 + "version": "2.0.1", 2089 + "dev": true, 2090 + "license": "MIT", 2091 + "dependencies": { 2092 + "color-name": "~1.1.4" 2093 + }, 2094 + "engines": { 2095 + "node": ">=7.0.0" 2096 + } 2097 + }, 2098 + "node_modules/color-name": { 2099 + "version": "1.1.4", 2100 + "dev": true, 2101 + "license": "MIT" 2102 + }, 2103 + "node_modules/commander": { 2104 + "version": "2.20.3", 2105 + "dev": true, 2106 + "license": "MIT", 2107 + "optional": true 2108 + }, 2109 + "node_modules/commondir": { 2110 + "version": "1.0.1", 2111 + "dev": true, 2112 + "license": "MIT" 2113 + }, 2114 + "node_modules/compare-versions": { 2115 + "version": "6.1.1", 2116 + "dev": true, 2117 + "license": "MIT" 2118 + }, 2119 + "node_modules/concat-map": { 2120 + "version": "0.0.1", 2121 + "dev": true, 2122 + "license": "MIT" 2123 + }, 2124 + "node_modules/confbox": { 2125 + "version": "0.2.2", 2126 + "dev": true, 2127 + "license": "MIT" 2128 + }, 2129 + "node_modules/convert-source-map": { 2130 + "version": "2.0.0", 2131 + "dev": true, 2132 + "license": "MIT" 2133 + }, 2134 + "node_modules/cross-spawn": { 2135 + "version": "7.0.6", 2136 + "dev": true, 2137 + "license": "MIT", 2138 + "dependencies": { 2139 + "path-key": "^3.1.0", 2140 + "shebang-command": "^2.0.0", 2141 + "which": "^2.0.1" 2142 + }, 2143 + "engines": { 2144 + "node": ">= 8" 2145 + } 2146 + }, 2147 + "node_modules/csstype": { 2148 + "version": "3.2.3", 2149 + "dev": true, 2150 + "license": "MIT" 2151 + }, 2152 + "node_modules/debug": { 2153 + "version": "4.4.3", 2154 + "dev": true, 2155 + "license": "MIT", 2156 + "dependencies": { 2157 + "ms": "^2.1.3" 2158 + }, 2159 + "engines": { 2160 + "node": ">=6.0" 2161 + }, 2162 + "peerDependenciesMeta": { 2163 + "supports-color": { 2164 + "optional": true 2165 + } 2166 + } 2167 + }, 2168 + "node_modules/deep-is": { 2169 + "version": "0.1.4", 2170 + "dev": true, 2171 + "license": "MIT" 2172 + }, 2173 + "node_modules/detect-libc": { 2174 + "version": "2.1.2", 2175 + "dev": true, 2176 + "license": "Apache-2.0", 2177 + "engines": { 2178 + "node": ">=8" 2179 + } 2180 + }, 2181 + "node_modules/diff": { 2182 + "version": "8.0.2", 2183 + "dev": true, 2184 + "license": "BSD-3-Clause", 2185 + "engines": { 2186 + "node": ">=0.3.1" 2187 + } 2188 + }, 2189 + "node_modules/electron-to-chromium": { 2190 + "version": "1.5.263", 2191 + "dev": true, 2192 + "license": "ISC" 2193 + }, 2194 + "node_modules/escalade": { 2195 + "version": "3.2.0", 2196 + "dev": true, 2197 + "license": "MIT", 2198 + "engines": { 2199 + "node": ">=6" 2200 + } 2201 + }, 2202 + "node_modules/escape-string-regexp": { 2203 + "version": "4.0.0", 2204 + "dev": true, 2205 + "license": "MIT", 2206 + "engines": { 2207 + "node": ">=10" 2208 + }, 2209 + "funding": { 2210 + "url": "https://github.com/sponsors/sindresorhus" 2211 + } 2212 + }, 2213 + "node_modules/eslint": { 2214 + "version": "9.39.1", 2215 + "dev": true, 2216 + "license": "MIT", 2217 + "peer": true, 2218 + "dependencies": { 2219 + "@eslint-community/eslint-utils": "^4.8.0", 2220 + "@eslint-community/regexpp": "^4.12.1", 2221 + "@eslint/config-array": "^0.21.1", 2222 + "@eslint/config-helpers": "^0.4.2", 2223 + "@eslint/core": "^0.17.0", 2224 + "@eslint/eslintrc": "^3.3.1", 2225 + "@eslint/js": "9.39.1", 2226 + "@eslint/plugin-kit": "^0.4.1", 2227 + "@humanfs/node": "^0.16.6", 2228 + "@humanwhocodes/module-importer": "^1.0.1", 2229 + "@humanwhocodes/retry": "^0.4.2", 2230 + "@types/estree": "^1.0.6", 2231 + "ajv": "^6.12.4", 2232 + "chalk": "^4.0.0", 2233 + "cross-spawn": "^7.0.6", 2234 + "debug": "^4.3.2", 2235 + "escape-string-regexp": "^4.0.0", 2236 + "eslint-scope": "^8.4.0", 2237 + "eslint-visitor-keys": "^4.2.1", 2238 + "espree": "^10.4.0", 2239 + "esquery": "^1.5.0", 2240 + "esutils": "^2.0.2", 2241 + "fast-deep-equal": "^3.1.3", 2242 + "file-entry-cache": "^8.0.0", 2243 + "find-up": "^5.0.0", 2244 + "glob-parent": "^6.0.2", 2245 + "ignore": "^5.2.0", 2246 + "imurmurhash": "^0.1.4", 2247 + "is-glob": "^4.0.0", 2248 + "json-stable-stringify-without-jsonify": "^1.0.1", 2249 + "lodash.merge": "^4.6.2", 2250 + "minimatch": "^3.1.2", 2251 + "natural-compare": "^1.4.0", 2252 + "optionator": "^0.9.3" 2253 + }, 2254 + "bin": { 2255 + "eslint": "bin/eslint.js" 2256 + }, 2257 + "engines": { 2258 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 2259 + }, 2260 + "funding": { 2261 + "url": "https://eslint.org/donate" 2262 + }, 2263 + "peerDependencies": { 2264 + "jiti": "*" 2265 + }, 2266 + "peerDependenciesMeta": { 2267 + "jiti": { 2268 + "optional": true 2269 + } 2270 + } 2271 + }, 2272 + "node_modules/eslint-plugin-react-hooks": { 2273 + "version": "5.2.0", 2274 + "dev": true, 2275 + "license": "MIT", 2276 + "engines": { 2277 + "node": ">=10" 2278 + }, 2279 + "peerDependencies": { 2280 + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" 2281 + } 2282 + }, 2283 + "node_modules/eslint-plugin-react-refresh": { 2284 + "version": "0.4.24", 2285 + "dev": true, 2286 + "license": "MIT", 2287 + "peerDependencies": { 2288 + "eslint": ">=8.40" 2289 + } 2290 + }, 2291 + "node_modules/eslint-scope": { 2292 + "version": "8.4.0", 2293 + "dev": true, 2294 + "license": "BSD-2-Clause", 2295 + "dependencies": { 2296 + "esrecurse": "^4.3.0", 2297 + "estraverse": "^5.2.0" 2298 + }, 2299 + "engines": { 2300 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 2301 + }, 2302 + "funding": { 2303 + "url": "https://opencollective.com/eslint" 2304 + } 2305 + }, 2306 + "node_modules/eslint-visitor-keys": { 2307 + "version": "4.2.1", 2308 + "dev": true, 2309 + "license": "Apache-2.0", 2310 + "engines": { 2311 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 2312 + }, 2313 + "funding": { 2314 + "url": "https://opencollective.com/eslint" 2315 + } 2316 + }, 2317 + "node_modules/eslint/node_modules/ajv": { 2318 + "version": "6.12.6", 2319 + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 2320 + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 2321 + "dev": true, 2322 + "license": "MIT", 2323 + "dependencies": { 2324 + "fast-deep-equal": "^3.1.1", 2325 + "fast-json-stable-stringify": "^2.0.0", 2326 + "json-schema-traverse": "^0.4.1", 2327 + "uri-js": "^4.2.2" 2328 + }, 2329 + "funding": { 2330 + "type": "github", 2331 + "url": "https://github.com/sponsors/epoberezkin" 2332 + } 2333 + }, 2334 + "node_modules/eslint/node_modules/json-schema-traverse": { 2335 + "version": "0.4.1", 2336 + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 2337 + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", 2338 + "dev": true, 2339 + "license": "MIT" 2340 + }, 2341 + "node_modules/eslint/node_modules/minimatch": { 2342 + "version": "3.1.2", 2343 + "dev": true, 2344 + "license": "ISC", 2345 + "dependencies": { 2346 + "brace-expansion": "^1.1.7" 2347 + }, 2348 + "engines": { 2349 + "node": "*" 2350 + } 2351 + }, 2352 + "node_modules/esm-env": { 2353 + "version": "1.2.2", 2354 + "license": "MIT" 2355 + }, 2356 + "node_modules/espree": { 2357 + "version": "10.4.0", 2358 + "dev": true, 2359 + "license": "BSD-2-Clause", 2360 + "dependencies": { 2361 + "acorn": "^8.15.0", 2362 + "acorn-jsx": "^5.3.2", 2363 + "eslint-visitor-keys": "^4.2.1" 2364 + }, 2365 + "engines": { 2366 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 2367 + }, 2368 + "funding": { 2369 + "url": "https://opencollective.com/eslint" 2370 + } 2371 + }, 2372 + "node_modules/esquery": { 2373 + "version": "1.6.0", 2374 + "dev": true, 2375 + "license": "BSD-3-Clause", 2376 + "dependencies": { 2377 + "estraverse": "^5.1.0" 2378 + }, 2379 + "engines": { 2380 + "node": ">=0.10" 2381 + } 2382 + }, 2383 + "node_modules/esrecurse": { 2384 + "version": "4.3.0", 2385 + "dev": true, 2386 + "license": "BSD-2-Clause", 2387 + "dependencies": { 2388 + "estraverse": "^5.2.0" 2389 + }, 2390 + "engines": { 2391 + "node": ">=4.0" 2392 + } 2393 + }, 2394 + "node_modules/estraverse": { 2395 + "version": "5.3.0", 2396 + "dev": true, 2397 + "license": "BSD-2-Clause", 2398 + "engines": { 2399 + "node": ">=4.0" 2400 + } 2401 + }, 2402 + "node_modules/estree-walker": { 2403 + "version": "2.0.2", 2404 + "dev": true, 2405 + "license": "MIT" 2406 + }, 2407 + "node_modules/esutils": { 2408 + "version": "2.0.3", 2409 + "dev": true, 2410 + "license": "BSD-2-Clause", 2411 + "engines": { 2412 + "node": ">=0.10.0" 2413 + } 2414 + }, 2415 + "node_modules/exsolve": { 2416 + "version": "1.0.8", 2417 + "dev": true, 2418 + "license": "MIT" 2419 + }, 2420 + "node_modules/fast-deep-equal": { 2421 + "version": "3.1.3", 2422 + "dev": true, 2423 + "license": "MIT" 2424 + }, 2425 + "node_modules/fast-json-stable-stringify": { 2426 + "version": "2.1.0", 2427 + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 2428 + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", 2429 + "dev": true, 2430 + "license": "MIT" 2431 + }, 2432 + "node_modules/fast-levenshtein": { 2433 + "version": "2.0.6", 2434 + "dev": true, 2435 + "license": "MIT" 2436 + }, 2437 + "node_modules/fast-uri": { 2438 + "version": "3.1.0", 2439 + "dev": true, 2440 + "funding": [ 2441 + { 2442 + "type": "github", 2443 + "url": "https://github.com/sponsors/fastify" 2444 + }, 2445 + { 2446 + "type": "opencollective", 2447 + "url": "https://opencollective.com/fastify" 2448 + } 2449 + ], 2450 + "license": "BSD-3-Clause" 2451 + }, 2452 + "node_modules/fdir": { 2453 + "version": "6.5.0", 2454 + "dev": true, 2455 + "license": "MIT", 2456 + "engines": { 2457 + "node": ">=12.0.0" 2458 + }, 2459 + "peerDependencies": { 2460 + "picomatch": "^3 || ^4" 2461 + }, 2462 + "peerDependenciesMeta": { 2463 + "picomatch": { 2464 + "optional": true 2465 + } 2466 + } 2467 + }, 2468 + "node_modules/file-entry-cache": { 2469 + "version": "8.0.0", 2470 + "dev": true, 2471 + "license": "MIT", 2472 + "dependencies": { 2473 + "flat-cache": "^4.0.0" 2474 + }, 2475 + "engines": { 2476 + "node": ">=16.0.0" 2477 + } 2478 + }, 2479 + "node_modules/find-cache-dir": { 2480 + "version": "3.3.2", 2481 + "dev": true, 2482 + "license": "MIT", 2483 + "dependencies": { 2484 + "commondir": "^1.0.1", 2485 + "make-dir": "^3.0.2", 2486 + "pkg-dir": "^4.1.0" 2487 + }, 2488 + "engines": { 2489 + "node": ">=8" 2490 + }, 2491 + "funding": { 2492 + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" 2493 + } 2494 + }, 2495 + "node_modules/find-up": { 2496 + "version": "5.0.0", 2497 + "dev": true, 2498 + "license": "MIT", 2499 + "dependencies": { 2500 + "locate-path": "^6.0.0", 2501 + "path-exists": "^4.0.0" 2502 + }, 2503 + "engines": { 2504 + "node": ">=10" 2505 + }, 2506 + "funding": { 2507 + "url": "https://github.com/sponsors/sindresorhus" 2508 + } 2509 + }, 2510 + "node_modules/flat-cache": { 2511 + "version": "4.0.1", 2512 + "dev": true, 2513 + "license": "MIT", 2514 + "dependencies": { 2515 + "flatted": "^3.2.9", 2516 + "keyv": "^4.5.4" 2517 + }, 2518 + "engines": { 2519 + "node": ">=16" 2520 + } 2521 + }, 2522 + "node_modules/flatted": { 2523 + "version": "3.3.3", 2524 + "dev": true, 2525 + "license": "ISC" 2526 + }, 2527 + "node_modules/fs-extra": { 2528 + "version": "10.1.0", 2529 + "dev": true, 2530 + "license": "MIT", 2531 + "dependencies": { 2532 + "graceful-fs": "^4.2.0", 2533 + "jsonfile": "^6.0.1", 2534 + "universalify": "^2.0.0" 2535 + }, 2536 + "engines": { 2537 + "node": ">=12" 2538 + } 2539 + }, 2540 + "node_modules/fsevents": { 2541 + "version": "2.3.3", 2542 + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 2543 + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 2544 + "dev": true, 2545 + "hasInstallScript": true, 2546 + "license": "MIT", 2547 + "optional": true, 2548 + "os": [ 2549 + "darwin" 2550 + ], 2551 + "engines": { 2552 + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 2553 + } 2554 + }, 2555 + "node_modules/function-bind": { 2556 + "version": "1.1.2", 2557 + "dev": true, 2558 + "license": "MIT", 2559 + "funding": { 2560 + "url": "https://github.com/sponsors/ljharb" 2561 + } 2562 + }, 2563 + "node_modules/gensync": { 2564 + "version": "1.0.0-beta.2", 2565 + "dev": true, 2566 + "license": "MIT", 2567 + "engines": { 2568 + "node": ">=6.9.0" 2569 + } 2570 + }, 2571 + "node_modules/glob-parent": { 2572 + "version": "6.0.2", 2573 + "dev": true, 2574 + "license": "ISC", 2575 + "dependencies": { 2576 + "is-glob": "^4.0.3" 2577 + }, 2578 + "engines": { 2579 + "node": ">=10.13.0" 2580 + } 2581 + }, 2582 + "node_modules/globals": { 2583 + "version": "16.5.0", 2584 + "dev": true, 2585 + "license": "MIT", 2586 + "engines": { 2587 + "node": ">=18" 2588 + }, 2589 + "funding": { 2590 + "url": "https://github.com/sponsors/sindresorhus" 2591 + } 2592 + }, 2593 + "node_modules/graceful-fs": { 2594 + "version": "4.2.11", 2595 + "dev": true, 2596 + "license": "ISC" 2597 + }, 2598 + "node_modules/graphemer": { 2599 + "version": "1.4.0", 2600 + "dev": true, 2601 + "license": "MIT" 2602 + }, 2603 + "node_modules/has-flag": { 2604 + "version": "4.0.0", 2605 + "dev": true, 2606 + "license": "MIT", 2607 + "engines": { 2608 + "node": ">=8" 2609 + } 2610 + }, 2611 + "node_modules/hasown": { 2612 + "version": "2.0.2", 2613 + "dev": true, 2614 + "license": "MIT", 2615 + "dependencies": { 2616 + "function-bind": "^1.1.2" 2617 + }, 2618 + "engines": { 2619 + "node": ">= 0.4" 2620 + } 2621 + }, 2622 + "node_modules/ignore": { 2623 + "version": "5.3.2", 2624 + "dev": true, 2625 + "license": "MIT", 2626 + "engines": { 2627 + "node": ">= 4" 2628 + } 2629 + }, 2630 + "node_modules/import-fresh": { 2631 + "version": "3.3.1", 2632 + "dev": true, 2633 + "license": "MIT", 2634 + "dependencies": { 2635 + "parent-module": "^1.0.0", 2636 + "resolve-from": "^4.0.0" 2637 + }, 2638 + "engines": { 2639 + "node": ">=6" 2640 + }, 2641 + "funding": { 2642 + "url": "https://github.com/sponsors/sindresorhus" 2643 + } 2644 + }, 2645 + "node_modules/import-lazy": { 2646 + "version": "4.0.0", 2647 + "dev": true, 2648 + "license": "MIT", 2649 + "engines": { 2650 + "node": ">=8" 2651 + } 2652 + }, 2653 + "node_modules/imurmurhash": { 2654 + "version": "0.1.4", 2655 + "dev": true, 2656 + "license": "MIT", 2657 + "engines": { 2658 + "node": ">=0.8.19" 2659 + } 2660 + }, 2661 + "node_modules/is-core-module": { 2662 + "version": "2.16.1", 2663 + "dev": true, 2664 + "license": "MIT", 2665 + "dependencies": { 2666 + "hasown": "^2.0.2" 2667 + }, 2668 + "engines": { 2669 + "node": ">= 0.4" 2670 + }, 2671 + "funding": { 2672 + "url": "https://github.com/sponsors/ljharb" 2673 + } 2674 + }, 2675 + "node_modules/is-extglob": { 2676 + "version": "2.1.1", 2677 + "dev": true, 2678 + "license": "MIT", 2679 + "engines": { 2680 + "node": ">=0.10.0" 2681 + } 2682 + }, 2683 + "node_modules/is-glob": { 2684 + "version": "4.0.3", 2685 + "dev": true, 2686 + "license": "MIT", 2687 + "dependencies": { 2688 + "is-extglob": "^2.1.1" 2689 + }, 2690 + "engines": { 2691 + "node": ">=0.10.0" 2692 + } 2693 + }, 2694 + "node_modules/isexe": { 2695 + "version": "2.0.0", 2696 + "dev": true, 2697 + "license": "ISC" 2698 + }, 2699 + "node_modules/jju": { 2700 + "version": "1.4.0", 2701 + "dev": true, 2702 + "license": "MIT" 2703 + }, 2704 + "node_modules/js-tokens": { 2705 + "version": "4.0.0", 2706 + "dev": true, 2707 + "license": "MIT" 2708 + }, 2709 + "node_modules/js-yaml": { 2710 + "version": "4.1.1", 2711 + "dev": true, 2712 + "license": "MIT", 2713 + "dependencies": { 2714 + "argparse": "^2.0.1" 2715 + }, 2716 + "bin": { 2717 + "js-yaml": "bin/js-yaml.js" 2718 + } 2719 + }, 2720 + "node_modules/js-yaml/node_modules/argparse": { 2721 + "version": "2.0.1", 2722 + "dev": true, 2723 + "license": "Python-2.0" 2724 + }, 2725 + "node_modules/jsesc": { 2726 + "version": "3.1.0", 2727 + "dev": true, 2728 + "license": "MIT", 2729 + "bin": { 2730 + "jsesc": "bin/jsesc" 2731 + }, 2732 + "engines": { 2733 + "node": ">=6" 2734 + } 2735 + }, 2736 + "node_modules/json-buffer": { 2737 + "version": "3.0.1", 2738 + "dev": true, 2739 + "license": "MIT" 2740 + }, 2741 + "node_modules/json-schema-traverse": { 2742 + "version": "1.0.0", 2743 + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", 2744 + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", 2745 + "dev": true, 2746 + "license": "MIT" 2747 + }, 2748 + "node_modules/json-stable-stringify-without-jsonify": { 2749 + "version": "1.0.1", 2750 + "dev": true, 2751 + "license": "MIT" 2752 + }, 2753 + "node_modules/json5": { 2754 + "version": "2.2.3", 2755 + "dev": true, 2756 + "license": "MIT", 2757 + "bin": { 2758 + "json5": "lib/cli.js" 2759 + }, 2760 + "engines": { 2761 + "node": ">=6" 2762 + } 2763 + }, 2764 + "node_modules/jsonfile": { 2765 + "version": "6.2.0", 2766 + "dev": true, 2767 + "license": "MIT", 2768 + "dependencies": { 2769 + "universalify": "^2.0.0" 2770 + }, 2771 + "optionalDependencies": { 2772 + "graceful-fs": "^4.1.6" 2773 + } 2774 + }, 2775 + "node_modules/keyv": { 2776 + "version": "4.5.4", 2777 + "dev": true, 2778 + "license": "MIT", 2779 + "dependencies": { 2780 + "json-buffer": "3.0.1" 2781 + } 2782 + }, 2783 + "node_modules/kolorist": { 2784 + "version": "1.8.0", 2785 + "dev": true, 2786 + "license": "MIT" 2787 + }, 2788 + "node_modules/levn": { 2789 + "version": "0.4.1", 2790 + "dev": true, 2791 + "license": "MIT", 2792 + "dependencies": { 2793 + "prelude-ls": "^1.2.1", 2794 + "type-check": "~0.4.0" 2795 + }, 2796 + "engines": { 2797 + "node": ">= 0.8.0" 2798 + } 2799 + }, 2800 + "node_modules/lightningcss": { 2801 + "version": "1.30.2", 2802 + "dev": true, 2803 + "license": "MPL-2.0", 2804 + "dependencies": { 2805 + "detect-libc": "^2.0.3" 2806 + }, 2807 + "engines": { 2808 + "node": ">= 12.0.0" 2809 + }, 2810 + "funding": { 2811 + "type": "opencollective", 2812 + "url": "https://opencollective.com/parcel" 2813 + }, 2814 + "optionalDependencies": { 2815 + "lightningcss-android-arm64": "1.30.2", 2816 + "lightningcss-darwin-arm64": "1.30.2", 2817 + "lightningcss-darwin-x64": "1.30.2", 2818 + "lightningcss-freebsd-x64": "1.30.2", 2819 + "lightningcss-linux-arm-gnueabihf": "1.30.2", 2820 + "lightningcss-linux-arm64-gnu": "1.30.2", 2821 + "lightningcss-linux-arm64-musl": "1.30.2", 2822 + "lightningcss-linux-x64-gnu": "1.30.2", 2823 + "lightningcss-linux-x64-musl": "1.30.2", 2824 + "lightningcss-win32-arm64-msvc": "1.30.2", 2825 + "lightningcss-win32-x64-msvc": "1.30.2" 2826 + } 2827 + }, 2828 + "node_modules/lightningcss-android-arm64": { 2829 + "version": "1.30.2", 2830 + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz", 2831 + "integrity": "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==", 2832 + "cpu": [ 2833 + "arm64" 2834 + ], 2835 + "dev": true, 2836 + "license": "MPL-2.0", 2837 + "optional": true, 2838 + "os": [ 2839 + "android" 2840 + ], 2841 + "engines": { 2842 + "node": ">= 12.0.0" 2843 + }, 2844 + "funding": { 2845 + "type": "opencollective", 2846 + "url": "https://opencollective.com/parcel" 2847 + } 2848 + }, 2849 + "node_modules/lightningcss-darwin-arm64": { 2850 + "version": "1.30.2", 2851 + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz", 2852 + "integrity": "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==", 2853 + "cpu": [ 2854 + "arm64" 2855 + ], 2856 + "dev": true, 2857 + "license": "MPL-2.0", 2858 + "optional": true, 2859 + "os": [ 2860 + "darwin" 2861 + ], 2862 + "engines": { 2863 + "node": ">= 12.0.0" 2864 + }, 2865 + "funding": { 2866 + "type": "opencollective", 2867 + "url": "https://opencollective.com/parcel" 2868 + } 2869 + }, 2870 + "node_modules/lightningcss-darwin-x64": { 2871 + "version": "1.30.2", 2872 + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz", 2873 + "integrity": "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==", 2874 + "cpu": [ 2875 + "x64" 2876 + ], 2877 + "dev": true, 2878 + "license": "MPL-2.0", 2879 + "optional": true, 2880 + "os": [ 2881 + "darwin" 2882 + ], 2883 + "engines": { 2884 + "node": ">= 12.0.0" 2885 + }, 2886 + "funding": { 2887 + "type": "opencollective", 2888 + "url": "https://opencollective.com/parcel" 2889 + } 2890 + }, 2891 + "node_modules/lightningcss-freebsd-x64": { 2892 + "version": "1.30.2", 2893 + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz", 2894 + "integrity": "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==", 2895 + "cpu": [ 2896 + "x64" 2897 + ], 2898 + "dev": true, 2899 + "license": "MPL-2.0", 2900 + "optional": true, 2901 + "os": [ 2902 + "freebsd" 2903 + ], 2904 + "engines": { 2905 + "node": ">= 12.0.0" 2906 + }, 2907 + "funding": { 2908 + "type": "opencollective", 2909 + "url": "https://opencollective.com/parcel" 2910 + } 2911 + }, 2912 + "node_modules/lightningcss-linux-arm-gnueabihf": { 2913 + "version": "1.30.2", 2914 + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz", 2915 + "integrity": "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==", 2916 + "cpu": [ 2917 + "arm" 2918 + ], 2919 + "dev": true, 2920 + "license": "MPL-2.0", 2921 + "optional": true, 2922 + "os": [ 2923 + "linux" 2924 + ], 2925 + "engines": { 2926 + "node": ">= 12.0.0" 2927 + }, 2928 + "funding": { 2929 + "type": "opencollective", 2930 + "url": "https://opencollective.com/parcel" 2931 + } 2932 + }, 2933 + "node_modules/lightningcss-linux-arm64-gnu": { 2934 + "version": "1.30.2", 2935 + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz", 2936 + "integrity": "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==", 2937 + "cpu": [ 2938 + "arm64" 2939 + ], 2940 + "dev": true, 2941 + "license": "MPL-2.0", 2942 + "optional": true, 2943 + "os": [ 2944 + "linux" 2945 + ], 2946 + "engines": { 2947 + "node": ">= 12.0.0" 2948 + }, 2949 + "funding": { 2950 + "type": "opencollective", 2951 + "url": "https://opencollective.com/parcel" 2952 + } 2953 + }, 2954 + "node_modules/lightningcss-linux-arm64-musl": { 2955 + "version": "1.30.2", 2956 + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz", 2957 + "integrity": "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==", 2958 + "cpu": [ 2959 + "arm64" 2960 + ], 2961 + "dev": true, 2962 + "license": "MPL-2.0", 2963 + "optional": true, 2964 + "os": [ 2965 + "linux" 2966 + ], 2967 + "engines": { 2968 + "node": ">= 12.0.0" 2969 + }, 2970 + "funding": { 2971 + "type": "opencollective", 2972 + "url": "https://opencollective.com/parcel" 2973 + } 2974 + }, 2975 + "node_modules/lightningcss-linux-x64-gnu": { 2976 + "version": "1.30.2", 2977 + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz", 2978 + "integrity": "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==", 2979 + "cpu": [ 2980 + "x64" 2981 + ], 2982 + "dev": true, 2983 + "license": "MPL-2.0", 2984 + "optional": true, 2985 + "os": [ 2986 + "linux" 2987 + ], 2988 + "engines": { 2989 + "node": ">= 12.0.0" 2990 + }, 2991 + "funding": { 2992 + "type": "opencollective", 2993 + "url": "https://opencollective.com/parcel" 2994 + } 2995 + }, 2996 + "node_modules/lightningcss-linux-x64-musl": { 2997 + "version": "1.30.2", 2998 + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz", 2999 + "integrity": "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==", 3000 + "cpu": [ 3001 + "x64" 3002 + ], 3003 + "dev": true, 3004 + "license": "MPL-2.0", 3005 + "optional": true, 3006 + "os": [ 3007 + "linux" 3008 + ], 3009 + "engines": { 3010 + "node": ">= 12.0.0" 3011 + }, 3012 + "funding": { 3013 + "type": "opencollective", 3014 + "url": "https://opencollective.com/parcel" 3015 + } 3016 + }, 3017 + "node_modules/lightningcss-win32-arm64-msvc": { 3018 + "version": "1.30.2", 3019 + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz", 3020 + "integrity": "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==", 3021 + "cpu": [ 3022 + "arm64" 3023 + ], 3024 + "dev": true, 3025 + "license": "MPL-2.0", 3026 + "optional": true, 3027 + "os": [ 3028 + "win32" 3029 + ], 3030 + "engines": { 3031 + "node": ">= 12.0.0" 3032 + }, 3033 + "funding": { 3034 + "type": "opencollective", 3035 + "url": "https://opencollective.com/parcel" 3036 + } 3037 + }, 3038 + "node_modules/lightningcss-win32-x64-msvc": { 3039 + "version": "1.30.2", 3040 + "cpu": [ 3041 + "x64" 3042 + ], 3043 + "dev": true, 3044 + "license": "MPL-2.0", 3045 + "optional": true, 3046 + "os": [ 3047 + "win32" 3048 + ], 3049 + "engines": { 3050 + "node": ">= 12.0.0" 3051 + }, 3052 + "funding": { 3053 + "type": "opencollective", 3054 + "url": "https://opencollective.com/parcel" 3055 + } 3056 + }, 3057 + "node_modules/local-pkg": { 3058 + "version": "1.1.2", 3059 + "dev": true, 3060 + "license": "MIT", 3061 + "dependencies": { 3062 + "mlly": "^1.7.4", 3063 + "pkg-types": "^2.3.0", 3064 + "quansync": "^0.2.11" 3065 + }, 3066 + "engines": { 3067 + "node": ">=14" 3068 + }, 3069 + "funding": { 3070 + "url": "https://github.com/sponsors/antfu" 3071 + } 3072 + }, 3073 + "node_modules/locate-path": { 3074 + "version": "6.0.0", 3075 + "dev": true, 3076 + "license": "MIT", 3077 + "dependencies": { 3078 + "p-locate": "^5.0.0" 3079 + }, 3080 + "engines": { 3081 + "node": ">=10" 3082 + }, 3083 + "funding": { 3084 + "url": "https://github.com/sponsors/sindresorhus" 3085 + } 3086 + }, 3087 + "node_modules/lodash": { 3088 + "version": "4.17.21", 3089 + "dev": true, 3090 + "license": "MIT" 3091 + }, 3092 + "node_modules/lodash.merge": { 3093 + "version": "4.6.2", 3094 + "dev": true, 3095 + "license": "MIT" 3096 + }, 3097 + "node_modules/lru-cache": { 3098 + "version": "6.0.0", 3099 + "dev": true, 3100 + "license": "ISC", 3101 + "dependencies": { 3102 + "yallist": "^4.0.0" 3103 + }, 3104 + "engines": { 3105 + "node": ">=10" 3106 + } 3107 + }, 3108 + "node_modules/magic-string": { 3109 + "version": "0.30.21", 3110 + "dev": true, 3111 + "license": "MIT", 3112 + "dependencies": { 3113 + "@jridgewell/sourcemap-codec": "^1.5.5" 3114 + } 3115 + }, 3116 + "node_modules/make-dir": { 3117 + "version": "3.1.0", 3118 + "dev": true, 3119 + "license": "MIT", 3120 + "dependencies": { 3121 + "semver": "^6.0.0" 3122 + }, 3123 + "engines": { 3124 + "node": ">=8" 3125 + }, 3126 + "funding": { 3127 + "url": "https://github.com/sponsors/sindresorhus" 3128 + } 3129 + }, 3130 + "node_modules/make-dir/node_modules/semver": { 3131 + "version": "6.3.1", 3132 + "dev": true, 3133 + "license": "ISC", 3134 + "bin": { 3135 + "semver": "bin/semver.js" 3136 + } 3137 + }, 3138 + "node_modules/minimatch": { 3139 + "version": "10.0.3", 3140 + "dev": true, 3141 + "license": "ISC", 3142 + "dependencies": { 3143 + "@isaacs/brace-expansion": "^5.0.0" 3144 + }, 3145 + "engines": { 3146 + "node": "20 || >=22" 3147 + }, 3148 + "funding": { 3149 + "url": "https://github.com/sponsors/isaacs" 3150 + } 3151 + }, 3152 + "node_modules/mlly": { 3153 + "version": "1.8.0", 3154 + "dev": true, 3155 + "license": "MIT", 3156 + "dependencies": { 3157 + "acorn": "^8.15.0", 3158 + "pathe": "^2.0.3", 3159 + "pkg-types": "^1.3.1", 3160 + "ufo": "^1.6.1" 3161 + } 3162 + }, 3163 + "node_modules/mlly/node_modules/pkg-types": { 3164 + "version": "1.3.1", 3165 + "dev": true, 3166 + "license": "MIT", 3167 + "dependencies": { 3168 + "confbox": "^0.1.8", 3169 + "mlly": "^1.7.4", 3170 + "pathe": "^2.0.1" 3171 + } 3172 + }, 3173 + "node_modules/mlly/node_modules/pkg-types/node_modules/confbox": { 3174 + "version": "0.1.8", 3175 + "dev": true, 3176 + "license": "MIT" 3177 + }, 3178 + "node_modules/ms": { 3179 + "version": "2.1.3", 3180 + "dev": true, 3181 + "license": "MIT" 3182 + }, 3183 + "node_modules/nanoid": { 3184 + "version": "3.3.11", 3185 + "dev": true, 3186 + "funding": [ 3187 + { 3188 + "type": "github", 3189 + "url": "https://github.com/sponsors/ai" 3190 + } 3191 + ], 3192 + "license": "MIT", 3193 + "bin": { 3194 + "nanoid": "bin/nanoid.cjs" 3195 + }, 3196 + "engines": { 3197 + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 3198 + } 3199 + }, 3200 + "node_modules/natural-compare": { 3201 + "version": "1.4.0", 3202 + "dev": true, 3203 + "license": "MIT" 3204 + }, 3205 + "node_modules/node-releases": { 3206 + "version": "2.0.27", 3207 + "dev": true, 3208 + "license": "MIT" 3209 + }, 3210 + "node_modules/optionator": { 3211 + "version": "0.9.4", 3212 + "dev": true, 3213 + "license": "MIT", 3214 + "dependencies": { 3215 + "deep-is": "^0.1.3", 3216 + "fast-levenshtein": "^2.0.6", 3217 + "levn": "^0.4.1", 3218 + "prelude-ls": "^1.2.1", 3219 + "type-check": "^0.4.0", 3220 + "word-wrap": "^1.2.5" 3221 + }, 3222 + "engines": { 3223 + "node": ">= 0.8.0" 3224 + } 3225 + }, 3226 + "node_modules/p-limit": { 3227 + "version": "3.1.0", 3228 + "dev": true, 3229 + "license": "MIT", 3230 + "dependencies": { 3231 + "yocto-queue": "^0.1.0" 3232 + }, 3233 + "engines": { 3234 + "node": ">=10" 3235 + }, 3236 + "funding": { 3237 + "url": "https://github.com/sponsors/sindresorhus" 3238 + } 3239 + }, 3240 + "node_modules/p-locate": { 3241 + "version": "5.0.0", 3242 + "dev": true, 3243 + "license": "MIT", 3244 + "dependencies": { 3245 + "p-limit": "^3.0.2" 3246 + }, 3247 + "engines": { 3248 + "node": ">=10" 3249 + }, 3250 + "funding": { 3251 + "url": "https://github.com/sponsors/sindresorhus" 3252 + } 3253 + }, 3254 + "node_modules/p-try": { 3255 + "version": "2.2.0", 3256 + "dev": true, 3257 + "license": "MIT", 3258 + "engines": { 3259 + "node": ">=6" 3260 + } 3261 + }, 3262 + "node_modules/parent-module": { 3263 + "version": "1.0.1", 3264 + "dev": true, 3265 + "license": "MIT", 3266 + "dependencies": { 3267 + "callsites": "^3.0.0" 3268 + }, 3269 + "engines": { 3270 + "node": ">=6" 3271 + } 3272 + }, 3273 + "node_modules/path-browserify": { 3274 + "version": "1.0.1", 3275 + "dev": true, 3276 + "license": "MIT" 3277 + }, 3278 + "node_modules/path-exists": { 3279 + "version": "4.0.0", 3280 + "dev": true, 3281 + "license": "MIT", 3282 + "engines": { 3283 + "node": ">=8" 3284 + } 3285 + }, 3286 + "node_modules/path-key": { 3287 + "version": "3.1.1", 3288 + "dev": true, 3289 + "license": "MIT", 3290 + "engines": { 3291 + "node": ">=8" 3292 + } 3293 + }, 3294 + "node_modules/path-parse": { 3295 + "version": "1.0.7", 3296 + "dev": true, 3297 + "license": "MIT" 3298 + }, 3299 + "node_modules/pathe": { 3300 + "version": "2.0.3", 3301 + "dev": true, 3302 + "license": "MIT" 3303 + }, 3304 + "node_modules/picocolors": { 3305 + "version": "1.1.1", 3306 + "dev": true, 3307 + "license": "ISC" 3308 + }, 3309 + "node_modules/picomatch": { 3310 + "version": "4.0.3", 3311 + "dev": true, 3312 + "license": "MIT", 3313 + "engines": { 3314 + "node": ">=12" 3315 + }, 3316 + "funding": { 3317 + "url": "https://github.com/sponsors/jonschlinkert" 3318 + } 3319 + }, 3320 + "node_modules/pkg-dir": { 3321 + "version": "4.2.0", 3322 + "dev": true, 3323 + "license": "MIT", 3324 + "dependencies": { 3325 + "find-up": "^4.0.0" 3326 + }, 3327 + "engines": { 3328 + "node": ">=8" 3329 + } 3330 + }, 3331 + "node_modules/pkg-dir/node_modules/find-up": { 3332 + "version": "4.1.0", 3333 + "dev": true, 3334 + "license": "MIT", 3335 + "dependencies": { 3336 + "locate-path": "^5.0.0", 3337 + "path-exists": "^4.0.0" 3338 + }, 3339 + "engines": { 3340 + "node": ">=8" 3341 + } 3342 + }, 3343 + "node_modules/pkg-dir/node_modules/find-up/node_modules/locate-path": { 3344 + "version": "5.0.0", 3345 + "dev": true, 3346 + "license": "MIT", 3347 + "dependencies": { 3348 + "p-locate": "^4.1.0" 3349 + }, 3350 + "engines": { 3351 + "node": ">=8" 3352 + } 3353 + }, 3354 + "node_modules/pkg-dir/node_modules/find-up/node_modules/locate-path/node_modules/p-locate": { 3355 + "version": "4.1.0", 3356 + "dev": true, 3357 + "license": "MIT", 3358 + "dependencies": { 3359 + "p-limit": "^2.2.0" 3360 + }, 3361 + "engines": { 3362 + "node": ">=8" 3363 + } 3364 + }, 3365 + "node_modules/pkg-dir/node_modules/find-up/node_modules/locate-path/node_modules/p-locate/node_modules/p-limit": { 3366 + "version": "2.3.0", 3367 + "dev": true, 3368 + "license": "MIT", 3369 + "dependencies": { 3370 + "p-try": "^2.0.0" 3371 + }, 3372 + "engines": { 3373 + "node": ">=6" 3374 + }, 3375 + "funding": { 3376 + "url": "https://github.com/sponsors/sindresorhus" 3377 + } 3378 + }, 3379 + "node_modules/pkg-types": { 3380 + "version": "2.3.0", 3381 + "dev": true, 3382 + "license": "MIT", 3383 + "dependencies": { 3384 + "confbox": "^0.2.2", 3385 + "exsolve": "^1.0.7", 3386 + "pathe": "^2.0.3" 3387 + } 3388 + }, 3389 + "node_modules/postcss": { 3390 + "version": "8.5.6", 3391 + "dev": true, 3392 + "funding": [ 3393 + { 3394 + "type": "opencollective", 3395 + "url": "https://opencollective.com/postcss/" 3396 + }, 3397 + { 3398 + "type": "tidelift", 3399 + "url": "https://tidelift.com/funding/github/npm/postcss" 3400 + }, 3401 + { 3402 + "type": "github", 3403 + "url": "https://github.com/sponsors/ai" 3404 + } 3405 + ], 3406 + "license": "MIT", 3407 + "dependencies": { 3408 + "nanoid": "^3.3.11", 3409 + "picocolors": "^1.1.1", 3410 + "source-map-js": "^1.2.1" 3411 + }, 3412 + "engines": { 3413 + "node": "^10 || ^12 || >=14" 3414 + } 3415 + }, 3416 + "node_modules/prelude-ls": { 3417 + "version": "1.2.1", 3418 + "dev": true, 3419 + "license": "MIT", 3420 + "engines": { 3421 + "node": ">= 0.8.0" 3422 + } 3423 + }, 3424 + "node_modules/punycode": { 3425 + "version": "2.3.1", 3426 + "dev": true, 3427 + "license": "MIT", 3428 + "engines": { 3429 + "node": ">=6" 3430 + } 3431 + }, 3432 + "node_modules/quansync": { 3433 + "version": "0.2.11", 3434 + "dev": true, 3435 + "funding": [ 3436 + { 3437 + "type": "individual", 3438 + "url": "https://github.com/sponsors/antfu" 3439 + }, 3440 + { 3441 + "type": "individual", 3442 + "url": "https://github.com/sponsors/sxzz" 3443 + } 3444 + ], 3445 + "license": "MIT" 3446 + }, 3447 + "node_modules/react": { 3448 + "version": "19.2.0", 3449 + "dev": true, 3450 + "license": "MIT", 3451 + "peer": true, 3452 + "engines": { 3453 + "node": ">=0.10.0" 3454 + } 3455 + }, 3456 + "node_modules/react-dom": { 3457 + "version": "19.2.0", 3458 + "dev": true, 3459 + "license": "MIT", 3460 + "dependencies": { 3461 + "scheduler": "^0.27.0" 3462 + }, 3463 + "peerDependencies": { 3464 + "react": "^19.2.0" 3465 + } 3466 + }, 3467 + "node_modules/react-refresh": { 3468 + "version": "0.18.0", 3469 + "dev": true, 3470 + "license": "MIT", 3471 + "engines": { 3472 + "node": ">=0.10.0" 3473 + } 3474 + }, 3475 + "node_modules/require-from-string": { 3476 + "version": "2.0.2", 3477 + "dev": true, 3478 + "license": "MIT", 3479 + "engines": { 3480 + "node": ">=0.10.0" 3481 + } 3482 + }, 3483 + "node_modules/resolve": { 3484 + "version": "1.22.11", 3485 + "dev": true, 3486 + "license": "MIT", 3487 + "dependencies": { 3488 + "is-core-module": "^2.16.1", 3489 + "path-parse": "^1.0.7", 3490 + "supports-preserve-symlinks-flag": "^1.0.0" 3491 + }, 3492 + "bin": { 3493 + "resolve": "bin/resolve" 3494 + }, 3495 + "engines": { 3496 + "node": ">= 0.4" 3497 + }, 3498 + "funding": { 3499 + "url": "https://github.com/sponsors/ljharb" 3500 + } 3501 + }, 3502 + "node_modules/resolve-from": { 3503 + "version": "4.0.0", 3504 + "dev": true, 3505 + "license": "MIT", 3506 + "engines": { 3507 + "node": ">=4" 3508 + } 3509 + }, 3510 + "node_modules/rolldown": { 3511 + "version": "1.0.0-beta.41", 3512 + "dev": true, 3513 + "license": "MIT", 3514 + "peer": true, 3515 + "dependencies": { 3516 + "@oxc-project/types": "=0.93.0", 3517 + "@rolldown/pluginutils": "1.0.0-beta.41", 3518 + "ansis": "=4.2.0" 3519 + }, 3520 + "bin": { 3521 + "rolldown": "bin/cli.mjs" 3522 + }, 3523 + "engines": { 3524 + "node": "^20.19.0 || >=22.12.0" 3525 + }, 3526 + "optionalDependencies": { 3527 + "@rolldown/binding-android-arm64": "1.0.0-beta.41", 3528 + "@rolldown/binding-darwin-arm64": "1.0.0-beta.41", 3529 + "@rolldown/binding-darwin-x64": "1.0.0-beta.41", 3530 + "@rolldown/binding-freebsd-x64": "1.0.0-beta.41", 3531 + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.41", 3532 + "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.41", 3533 + "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.41", 3534 + "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.41", 3535 + "@rolldown/binding-linux-x64-musl": "1.0.0-beta.41", 3536 + "@rolldown/binding-openharmony-arm64": "1.0.0-beta.41", 3537 + "@rolldown/binding-wasm32-wasi": "1.0.0-beta.41", 3538 + "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.41", 3539 + "@rolldown/binding-win32-ia32-msvc": "1.0.0-beta.41", 3540 + "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.41" 3541 + } 3542 + }, 3543 + "node_modules/rolldown/node_modules/@rolldown/pluginutils": { 3544 + "version": "1.0.0-beta.41", 3545 + "dev": true, 3546 + "license": "MIT" 3547 + }, 3548 + "node_modules/rollup": { 3549 + "version": "4.53.3", 3550 + "dev": true, 3551 + "license": "MIT", 3552 + "peer": true, 3553 + "dependencies": { 3554 + "@types/estree": "1.0.8" 3555 + }, 3556 + "bin": { 3557 + "rollup": "dist/bin/rollup" 3558 + }, 3559 + "engines": { 3560 + "node": ">=18.0.0", 3561 + "npm": ">=8.0.0" 3562 + }, 3563 + "optionalDependencies": { 3564 + "@rollup/rollup-android-arm-eabi": "4.53.3", 3565 + "@rollup/rollup-android-arm64": "4.53.3", 3566 + "@rollup/rollup-darwin-arm64": "4.53.3", 3567 + "@rollup/rollup-darwin-x64": "4.53.3", 3568 + "@rollup/rollup-freebsd-arm64": "4.53.3", 3569 + "@rollup/rollup-freebsd-x64": "4.53.3", 3570 + "@rollup/rollup-linux-arm-gnueabihf": "4.53.3", 3571 + "@rollup/rollup-linux-arm-musleabihf": "4.53.3", 3572 + "@rollup/rollup-linux-arm64-gnu": "4.53.3", 3573 + "@rollup/rollup-linux-arm64-musl": "4.53.3", 3574 + "@rollup/rollup-linux-loong64-gnu": "4.53.3", 3575 + "@rollup/rollup-linux-ppc64-gnu": "4.53.3", 3576 + "@rollup/rollup-linux-riscv64-gnu": "4.53.3", 3577 + "@rollup/rollup-linux-riscv64-musl": "4.53.3", 3578 + "@rollup/rollup-linux-s390x-gnu": "4.53.3", 3579 + "@rollup/rollup-linux-x64-gnu": "4.53.3", 3580 + "@rollup/rollup-linux-x64-musl": "4.53.3", 3581 + "@rollup/rollup-openharmony-arm64": "4.53.3", 3582 + "@rollup/rollup-win32-arm64-msvc": "4.53.3", 3583 + "@rollup/rollup-win32-ia32-msvc": "4.53.3", 3584 + "@rollup/rollup-win32-x64-gnu": "4.53.3", 3585 + "@rollup/rollup-win32-x64-msvc": "4.53.3", 3586 + "fsevents": "~2.3.2" 3587 + } 3588 + }, 3589 + "node_modules/rollup-plugin-typescript2": { 3590 + "version": "0.36.0", 3591 + "dev": true, 3592 + "license": "MIT", 3593 + "dependencies": { 3594 + "@rollup/pluginutils": "^4.1.2", 3595 + "find-cache-dir": "^3.3.2", 3596 + "fs-extra": "^10.0.0", 3597 + "semver": "^7.5.4", 3598 + "tslib": "^2.6.2" 3599 + }, 3600 + "peerDependencies": { 3601 + "rollup": ">=1.26.3", 3602 + "typescript": ">=2.4.0" 3603 + } 3604 + }, 3605 + "node_modules/rollup-plugin-typescript2/node_modules/semver": { 3606 + "version": "7.7.3", 3607 + "dev": true, 3608 + "license": "ISC", 3609 + "bin": { 3610 + "semver": "bin/semver.js" 3611 + }, 3612 + "engines": { 3613 + "node": ">=10" 3614 + } 3615 + }, 3616 + "node_modules/scheduler": { 3617 + "version": "0.27.0", 3618 + "dev": true, 3619 + "license": "MIT" 3620 + }, 3621 + "node_modules/semver": { 3622 + "version": "7.5.4", 3623 + "dev": true, 3624 + "license": "ISC", 3625 + "dependencies": { 3626 + "lru-cache": "^6.0.0" 3627 + }, 3628 + "bin": { 3629 + "semver": "bin/semver.js" 3630 + }, 3631 + "engines": { 3632 + "node": ">=10" 3633 + } 3634 + }, 3635 + "node_modules/shebang-command": { 3636 + "version": "2.0.0", 3637 + "dev": true, 3638 + "license": "MIT", 3639 + "dependencies": { 3640 + "shebang-regex": "^3.0.0" 3641 + }, 3642 + "engines": { 3643 + "node": ">=8" 3644 + } 3645 + }, 3646 + "node_modules/shebang-regex": { 3647 + "version": "3.0.0", 3648 + "dev": true, 3649 + "license": "MIT", 3650 + "engines": { 3651 + "node": ">=8" 3652 + } 3653 + }, 3654 + "node_modules/source-map": { 3655 + "version": "0.6.1", 3656 + "dev": true, 3657 + "license": "BSD-3-Clause", 3658 + "engines": { 3659 + "node": ">=0.10.0" 3660 + } 3661 + }, 3662 + "node_modules/source-map-js": { 3663 + "version": "1.2.1", 3664 + "dev": true, 3665 + "license": "BSD-3-Clause", 3666 + "engines": { 3667 + "node": ">=0.10.0" 3668 + } 3669 + }, 3670 + "node_modules/source-map-support": { 3671 + "version": "0.5.21", 3672 + "dev": true, 3673 + "license": "MIT", 3674 + "optional": true, 3675 + "dependencies": { 3676 + "buffer-from": "^1.0.0", 3677 + "source-map": "^0.6.0" 3678 + } 3679 + }, 3680 + "node_modules/sprintf-js": { 3681 + "version": "1.0.3", 3682 + "dev": true, 3683 + "license": "BSD-3-Clause" 3684 + }, 3685 + "node_modules/string-argv": { 3686 + "version": "0.3.2", 3687 + "dev": true, 3688 + "license": "MIT", 3689 + "engines": { 3690 + "node": ">=0.6.19" 3691 + } 3692 + }, 3693 + "node_modules/strip-json-comments": { 3694 + "version": "3.1.1", 3695 + "dev": true, 3696 + "license": "MIT", 3697 + "engines": { 3698 + "node": ">=8" 3699 + }, 3700 + "funding": { 3701 + "url": "https://github.com/sponsors/sindresorhus" 3702 + } 3703 + }, 3704 + "node_modules/supports-color": { 3705 + "version": "8.1.1", 3706 + "dev": true, 3707 + "license": "MIT", 3708 + "dependencies": { 3709 + "has-flag": "^4.0.0" 3710 + }, 3711 + "engines": { 3712 + "node": ">=10" 3713 + }, 3714 + "funding": { 3715 + "url": "https://github.com/chalk/supports-color?sponsor=1" 3716 + } 3717 + }, 3718 + "node_modules/supports-preserve-symlinks-flag": { 3719 + "version": "1.0.0", 3720 + "dev": true, 3721 + "license": "MIT", 3722 + "engines": { 3723 + "node": ">= 0.4" 3724 + }, 3725 + "funding": { 3726 + "url": "https://github.com/sponsors/ljharb" 3727 + } 3728 + }, 3729 + "node_modules/tinyglobby": { 3730 + "version": "0.2.15", 3731 + "dev": true, 3732 + "license": "MIT", 3733 + "dependencies": { 3734 + "fdir": "^6.5.0", 3735 + "picomatch": "^4.0.3" 3736 + }, 3737 + "engines": { 3738 + "node": ">=12.0.0" 3739 + }, 3740 + "funding": { 3741 + "url": "https://github.com/sponsors/SuperchupuDev" 3742 + } 3743 + }, 3744 + "node_modules/ts-api-utils": { 3745 + "version": "2.1.0", 3746 + "dev": true, 3747 + "license": "MIT", 3748 + "engines": { 3749 + "node": ">=18.12" 3750 + }, 3751 + "peerDependencies": { 3752 + "typescript": ">=4.8.4" 3753 + } 3754 + }, 3755 + "node_modules/tslib": { 3756 + "version": "2.8.1", 3757 + "dev": true, 3758 + "license": "0BSD" 3759 + }, 3760 + "node_modules/type-check": { 3761 + "version": "0.4.0", 3762 + "dev": true, 3763 + "license": "MIT", 3764 + "dependencies": { 3765 + "prelude-ls": "^1.2.1" 3766 + }, 3767 + "engines": { 3768 + "node": ">= 0.8.0" 3769 + } 3770 + }, 3771 + "node_modules/typescript": { 3772 + "version": "5.9.3", 3773 + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", 3774 + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", 3775 + "dev": true, 3776 + "license": "Apache-2.0", 3777 + "peer": true, 3778 + "bin": { 3779 + "tsc": "bin/tsc", 3780 + "tsserver": "bin/tsserver" 3781 + }, 3782 + "engines": { 3783 + "node": ">=14.17" 3784 + } 3785 + }, 3786 + "node_modules/typescript-eslint": { 3787 + "version": "8.48.1", 3788 + "dev": true, 3789 + "license": "MIT", 3790 + "dependencies": { 3791 + "@typescript-eslint/eslint-plugin": "8.48.1", 3792 + "@typescript-eslint/parser": "8.48.1", 3793 + "@typescript-eslint/typescript-estree": "8.48.1", 3794 + "@typescript-eslint/utils": "8.48.1" 3795 + }, 3796 + "engines": { 3797 + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" 3798 + }, 3799 + "funding": { 3800 + "type": "opencollective", 3801 + "url": "https://opencollective.com/typescript-eslint" 3802 + }, 3803 + "peerDependencies": { 3804 + "eslint": "^8.57.0 || ^9.0.0", 3805 + "typescript": ">=4.8.4 <6.0.0" 3806 + } 3807 + }, 3808 + "node_modules/ufo": { 3809 + "version": "1.6.1", 3810 + "dev": true, 3811 + "license": "MIT" 3812 + }, 3813 + "node_modules/undici-types": { 3814 + "version": "7.16.0", 3815 + "dev": true, 3816 + "license": "MIT" 3817 + }, 3818 + "node_modules/universalify": { 3819 + "version": "2.0.1", 3820 + "dev": true, 3821 + "license": "MIT", 3822 + "engines": { 3823 + "node": ">= 10.0.0" 3824 + } 3825 + }, 3826 + "node_modules/unplugin": { 3827 + "version": "2.3.11", 3828 + "dev": true, 3829 + "license": "MIT", 3830 + "dependencies": { 3831 + "@jridgewell/remapping": "^2.3.5", 3832 + "acorn": "^8.15.0", 3833 + "picomatch": "^4.0.3", 3834 + "webpack-virtual-modules": "^0.6.2" 3835 + }, 3836 + "engines": { 3837 + "node": ">=18.12.0" 3838 + } 3839 + }, 3840 + "node_modules/unplugin-dts": { 3841 + "version": "1.0.0-beta.6", 3842 + "dev": true, 3843 + "license": "MIT", 3844 + "dependencies": { 3845 + "@rollup/pluginutils": "^5.1.4", 3846 + "@volar/typescript": "^2.4.17", 3847 + "compare-versions": "^6.1.1", 3848 + "debug": "^4.4.0", 3849 + "kolorist": "^1.8.0", 3850 + "local-pkg": "^1.1.1", 3851 + "magic-string": "^0.30.17", 3852 + "unplugin": "^2.3.2" 3853 + }, 3854 + "peerDependencies": { 3855 + "@microsoft/api-extractor": ">=7", 3856 + "@rspack/core": "^1", 3857 + "@vue/language-core": "~3.0.1", 3858 + "esbuild": "*", 3859 + "rolldown": "*", 3860 + "rollup": ">=3", 3861 + "typescript": ">=4", 3862 + "vite": ">=3", 3863 + "webpack": "^4 || ^5" 3864 + }, 3865 + "peerDependenciesMeta": { 3866 + "@microsoft/api-extractor": { 3867 + "optional": true 3868 + }, 3869 + "@rspack/core": { 3870 + "optional": true 3871 + }, 3872 + "@vue/language-core": { 3873 + "optional": true 3874 + }, 3875 + "esbuild": { 3876 + "optional": true 3877 + }, 3878 + "rolldown": { 3879 + "optional": true 3880 + }, 3881 + "rollup": { 3882 + "optional": true 3883 + }, 3884 + "vite": { 3885 + "optional": true 3886 + }, 3887 + "webpack": { 3888 + "optional": true 3889 + } 3890 + } 3891 + }, 3892 + "node_modules/unplugin-dts/node_modules/@rollup/pluginutils": { 3893 + "version": "5.3.0", 3894 + "dev": true, 3895 + "license": "MIT", 3896 + "dependencies": { 3897 + "@types/estree": "^1.0.0", 3898 + "estree-walker": "^2.0.2", 3899 + "picomatch": "^4.0.2" 3900 + }, 3901 + "engines": { 3902 + "node": ">=14.0.0" 3903 + }, 3904 + "peerDependencies": { 3905 + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" 3906 + }, 3907 + "peerDependenciesMeta": { 3908 + "rollup": { 3909 + "optional": true 3910 + } 3911 + } 3912 + }, 3913 + "node_modules/update-browserslist-db": { 3914 + "version": "1.1.4", 3915 + "dev": true, 3916 + "funding": [ 3917 + { 3918 + "type": "opencollective", 3919 + "url": "https://opencollective.com/browserslist" 3920 + }, 3921 + { 3922 + "type": "tidelift", 3923 + "url": "https://tidelift.com/funding/github/npm/browserslist" 3924 + }, 3925 + { 3926 + "type": "github", 3927 + "url": "https://github.com/sponsors/ai" 3928 + } 3929 + ], 3930 + "license": "MIT", 3931 + "dependencies": { 3932 + "escalade": "^3.2.0", 3933 + "picocolors": "^1.1.1" 3934 + }, 3935 + "bin": { 3936 + "update-browserslist-db": "cli.js" 3937 + }, 3938 + "peerDependencies": { 3939 + "browserslist": ">= 4.21.0" 3940 + } 3941 + }, 3942 + "node_modules/uri-js": { 3943 + "version": "4.4.1", 3944 + "dev": true, 3945 + "license": "BSD-2-Clause", 3946 + "dependencies": { 3947 + "punycode": "^2.1.0" 3948 + } 3949 + }, 3950 + "node_modules/vite": { 3951 + "name": "rolldown-vite", 3952 + "version": "7.1.14", 3953 + "dev": true, 3954 + "license": "MIT", 3955 + "peer": true, 3956 + "dependencies": { 3957 + "@oxc-project/runtime": "0.92.0", 3958 + "fdir": "^6.5.0", 3959 + "lightningcss": "^1.30.1", 3960 + "picomatch": "^4.0.3", 3961 + "postcss": "^8.5.6", 3962 + "rolldown": "1.0.0-beta.41", 3963 + "tinyglobby": "^0.2.15" 3964 + }, 3965 + "bin": { 3966 + "vite": "bin/vite.js" 3967 + }, 3968 + "engines": { 3969 + "node": "^20.19.0 || >=22.12.0" 3970 + }, 3971 + "funding": { 3972 + "url": "https://github.com/vitejs/vite?sponsor=1" 3973 + }, 3974 + "optionalDependencies": { 3975 + "fsevents": "~2.3.3" 3976 + }, 3977 + "peerDependencies": { 3978 + "@types/node": "^20.19.0 || >=22.12.0", 3979 + "esbuild": "^0.25.0", 3980 + "jiti": ">=1.21.0", 3981 + "less": "^4.0.0", 3982 + "sass": "^1.70.0", 3983 + "sass-embedded": "^1.70.0", 3984 + "stylus": ">=0.54.8", 3985 + "sugarss": "^5.0.0", 3986 + "terser": "^5.16.0", 3987 + "tsx": "^4.8.1", 3988 + "yaml": "^2.4.2" 3989 + }, 3990 + "peerDependenciesMeta": { 3991 + "@types/node": { 3992 + "optional": true 3993 + }, 3994 + "esbuild": { 3995 + "optional": true 3996 + }, 3997 + "jiti": { 3998 + "optional": true 3999 + }, 4000 + "less": { 4001 + "optional": true 4002 + }, 4003 + "sass": { 4004 + "optional": true 4005 + }, 4006 + "sass-embedded": { 4007 + "optional": true 4008 + }, 4009 + "stylus": { 4010 + "optional": true 4011 + }, 4012 + "sugarss": { 4013 + "optional": true 4014 + }, 4015 + "terser": { 4016 + "optional": true 4017 + }, 4018 + "tsx": { 4019 + "optional": true 4020 + }, 4021 + "yaml": { 4022 + "optional": true 4023 + } 4024 + } 4025 + }, 4026 + "node_modules/vscode-uri": { 4027 + "version": "3.1.0", 4028 + "dev": true, 4029 + "license": "MIT" 4030 + }, 4031 + "node_modules/webpack-virtual-modules": { 4032 + "version": "0.6.2", 4033 + "dev": true, 4034 + "license": "MIT" 4035 + }, 4036 + "node_modules/which": { 4037 + "version": "2.0.2", 4038 + "dev": true, 4039 + "license": "ISC", 4040 + "dependencies": { 4041 + "isexe": "^2.0.0" 4042 + }, 4043 + "bin": { 4044 + "node-which": "bin/node-which" 4045 + }, 4046 + "engines": { 4047 + "node": ">= 8" 4048 + } 4049 + }, 4050 + "node_modules/word-wrap": { 4051 + "version": "1.2.5", 4052 + "dev": true, 4053 + "license": "MIT", 4054 + "engines": { 4055 + "node": ">=0.10.0" 4056 + } 4057 + }, 4058 + "node_modules/yallist": { 4059 + "version": "4.0.0", 4060 + "dev": true, 4061 + "license": "ISC" 4062 + }, 4063 + "node_modules/yocto-queue": { 4064 + "version": "0.1.0", 4065 + "dev": true, 4066 + "license": "MIT", 4067 + "engines": { 4068 + "node": ">=10" 4069 + }, 4070 + "funding": { 4071 + "url": "https://github.com/sponsors/sindresorhus" 4072 + } 4073 + } 4074 + } 2863 4075 }
+65 -91
package.json
··· 1 1 { 2 - "name": "atproto-ui", 3 - "version": "0.3.1-1", 4 - "type": "module", 5 - "description": "React components and hooks for rendering AT Protocol records.", 6 - "main": "./lib-dist/index.js", 7 - "module": "./lib-dist/index.js", 8 - "types": "./lib-dist/index.d.ts", 9 - "exports": { 10 - ".": { 11 - "types": "./lib-dist/index.d.ts", 12 - "import": "./lib-dist/index.js", 13 - "default": "./lib-dist/index.js" 14 - }, 15 - "./components/*": { 16 - "types": "./lib-dist/components/*.d.ts", 17 - "import": "./lib-dist/components/*.js", 18 - "default": "./lib-dist/components/*.js" 19 - }, 20 - "./hooks/*": { 21 - "types": "./lib-dist/hooks/*.d.ts", 22 - "import": "./lib-dist/hooks/*.js", 23 - "default": "./lib-dist/hooks/*.js" 24 - }, 25 - "./renderers/*": { 26 - "types": "./lib-dist/renderers/*.d.ts", 27 - "import": "./lib-dist/renderers/*.js", 28 - "default": "./lib-dist/renderers/*.js" 29 - }, 30 - "./providers/*": { 31 - "types": "./lib-dist/providers/*.d.ts", 32 - "import": "./lib-dist/providers/*.js", 33 - "default": "./lib-dist/providers/*.js" 34 - }, 35 - "./utils/*": { 36 - "types": "./lib-dist/utils/*.d.ts", 37 - "import": "./lib-dist/utils/*.js", 38 - "default": "./lib-dist/utils/*.js" 39 - }, 40 - "./types/*": { 41 - "types": "./lib-dist/types/*.d.ts", 42 - "import": "./lib-dist/types/*.js", 43 - "default": "./lib-dist/types/*.js" 44 - } 45 - }, 46 - "files": [ 47 - "lib-dist", 48 - "README.md" 49 - ], 50 - "sideEffects": false, 51 - "scripts": { 52 - "dev": "vite", 53 - "build": "tsc -b && vite build", 54 - "lint": "eslint .", 55 - "preview": "vite preview", 56 - "prepublishOnly": "npm run build" 57 - }, 58 - "peerDependencies": { 59 - "react": "^18.2.0 || ^19.0.0", 60 - "react-dom": "^18.2.0 || ^19.0.0" 61 - }, 62 - "peerDependenciesMeta": { 63 - "react-dom": { 64 - "optional": true 65 - } 66 - }, 67 - "dependencies": { 68 - "@atcute/atproto": "^3.1.7", 69 - "@atcute/bluesky": "^3.2.3", 70 - "@atcute/client": "^4.0.3", 71 - "@atcute/identity-resolver": "^1.1.3", 72 - "@atcute/tangled": "^1.0.6" 73 - }, 74 - "devDependencies": { 75 - "@eslint/js": "^9.36.0", 76 - "@types/node": "^24.6.0", 77 - "@types/react": "^19.1.16", 78 - "@types/react-dom": "^19.1.9", 79 - "@vitejs/plugin-react": "^5.0.4", 80 - "eslint": "^9.36.0", 81 - "eslint-plugin-react-hooks": "^5.2.0", 82 - "eslint-plugin-react-refresh": "^0.4.22", 83 - "globals": "^16.4.0", 84 - "react": "^19.1.1", 85 - "react-dom": "^19.1.1", 86 - "typescript": "~5.9.3", 87 - "typescript-eslint": "^8.45.0", 88 - "vite": "npm:rolldown-vite@7.1.14" 89 - }, 90 - "overrides": { 91 - "vite": "npm:rolldown-vite@7.1.14" 92 - } 2 + "name": "atproto-ui", 3 + "version": "0.12.0", 4 + "type": "module", 5 + "description": "React components and hooks for rendering AT Protocol records.", 6 + "main": "./lib-dist/index.js", 7 + "module": "./lib-dist/index.js", 8 + "types": "./lib-dist/index.d.ts", 9 + "exports": { 10 + ".": { 11 + "import": "./lib-dist/index.js", 12 + "require": "./lib-dist/index.js" 13 + }, 14 + "./styles.css": "./lib-dist/styles.css" 15 + }, 16 + "files": [ 17 + "lib-dist", 18 + "README.md" 19 + ], 20 + "sideEffects": [ 21 + "./lib-dist/styles.css" 22 + ], 23 + "scripts": { 24 + "dev": "vite", 25 + "build": "vite build && tsc -b", 26 + "build:demo": "BUILD_TARGET=demo vite build", 27 + "build:all": "npm run build && npm run build:demo", 28 + "lint": "eslint .", 29 + "preview": "vite preview", 30 + "prepublishOnly": "npm run build" 31 + }, 32 + "peerDependencies": { 33 + "react": "^18.2.0 || ^19.0.0", 34 + "react-dom": "^18.2.0 || ^19.0.0" 35 + }, 36 + "peerDependenciesMeta": { 37 + "react-dom": { 38 + "optional": true 39 + } 40 + }, 41 + "dependencies": { 42 + "@atcute/atproto": "^3.1.7", 43 + "@atcute/bluesky": "^3.2.3", 44 + "@atcute/client": "^4.0.3", 45 + "@atcute/identity-resolver": "^1.1.3", 46 + "@atcute/tangled": "^1.0.10" 47 + }, 48 + "devDependencies": { 49 + "@eslint/js": "^9.36.0", 50 + "@microsoft/api-extractor": "^7.53.1", 51 + "@types/node": "^24.6.0", 52 + "@types/react": "^19.1.16", 53 + "@types/react-dom": "^19.1.9", 54 + "@vitejs/plugin-react": "^5.0.4", 55 + "eslint": "^9.36.0", 56 + "eslint-plugin-react-hooks": "^5.2.0", 57 + "eslint-plugin-react-refresh": "^0.4.22", 58 + "globals": "^16.4.0", 59 + "react": "^19.1.1", 60 + "react-dom": "^19.1.1", 61 + "rollup-plugin-typescript2": "^0.36.0", 62 + "typescript": "~5.9.3", 63 + "typescript-eslint": "^8.45.0", 64 + "unplugin-dts": "^1.0.0-beta.6", 65 + "vite": "npm:rolldown-vite@7.1.14" 66 + } 93 67 }
+59
src/App.css
··· 1 + /** 2 + * Demo app styles - separate from atproto-ui component styles 3 + * This demonstrates that atproto-ui components work well within 4 + * apps that have their own theming system. 5 + */ 6 + 7 + /* Root styles for the demo app */ 8 + body { 9 + margin: 0; 10 + padding: 0; 11 + background: var(--demo-bg); 12 + color: var(--demo-text); 13 + transition: background-color 200ms ease, color 200ms ease; 14 + } 15 + 16 + :root { 17 + /* Light theme for demo app */ 18 + --demo-bg: #eeeeee; 19 + --demo-text: #1a1a1a; 20 + --demo-text-secondary: #666; 21 + --demo-border: #ddd; 22 + --demo-input-bg: #fff; 23 + --demo-button-bg: #0066cc; 24 + --demo-button-text: #fff; 25 + --demo-code-bg: #f5f5f5; 26 + --demo-code-border: #e0e0e0; 27 + --demo-hr: #e0e0e0; 28 + } 29 + 30 + /* Dark theme for demo app */ 31 + [data-theme="dark"] { 32 + --demo-bg: #1a1a1a; 33 + --demo-text: #e0e0e0; 34 + --demo-text-secondary: #999; 35 + --demo-border: #444; 36 + --demo-input-bg: #2a2a2a; 37 + --demo-button-bg: #0066cc; 38 + --demo-button-text: #fff; 39 + --demo-code-bg: #2a2a2a; 40 + --demo-code-border: #444; 41 + --demo-hr: #444; 42 + } 43 + 44 + /* System preference dark mode */ 45 + @media (prefers-color-scheme: dark) { 46 + :root:not([data-theme]), 47 + :root[data-theme="system"] { 48 + --demo-bg: #1a1a1a; 49 + --demo-text: #e0e0e0; 50 + --demo-text-secondary: #999; 51 + --demo-border: #444; 52 + --demo-input-bg: #2a2a2a; 53 + --demo-button-bg: #0066cc; 54 + --demo-button-text: #fff; 55 + --demo-code-bg: #2a2a2a; 56 + --demo-code-border: #444; 57 + --demo-hr: #444; 58 + } 59 + }
+385 -348
src/App.tsx
··· 1 - import React, { 2 - useState, 3 - useCallback, 4 - useEffect, 5 - useMemo, 6 - useRef, 7 - } from "react"; 8 - import { AtProtoProvider } from "../lib/providers/AtProtoProvider"; 9 - import { AtProtoRecord } from "../lib/core/AtProtoRecord"; 1 + import React, { useState, useCallback, useRef } from "react"; 2 + import { AtProtoProvider, TangledRepo } from "../lib"; 3 + import "../lib/styles.css"; 4 + import "./App.css"; 5 + 10 6 import { TangledString } from "../lib/components/TangledString"; 11 7 import { LeafletDocument } from "../lib/components/LeafletDocument"; 12 8 import { BlueskyProfile } from "../lib/components/BlueskyProfile"; ··· 16 12 } from "../lib/components/BlueskyPost"; 17 13 import { BlueskyPostList } from "../lib/components/BlueskyPostList"; 18 14 import { BlueskyQuotePost } from "../lib/components/BlueskyQuotePost"; 15 + import { GrainGallery } from "../lib/components/GrainGallery"; 16 + import { CurrentlyPlaying } from "../lib/components/CurrentlyPlaying"; 17 + import { LastPlayed } from "../lib/components/LastPlayed"; 18 + import { SongHistoryList } from "../lib/components/SongHistoryList"; 19 19 import { useDidResolution } from "../lib/hooks/useDidResolution"; 20 20 import { useLatestRecord } from "../lib/hooks/useLatestRecord"; 21 - import { ColorSchemeToggle } from "../lib/components/ColorSchemeToggle.tsx"; 22 - import { 23 - useColorScheme, 24 - type ColorSchemePreference, 25 - } from "../lib/hooks/useColorScheme"; 26 21 import type { FeedPostRecord } from "../lib/types/bluesky"; 27 22 28 - const COLOR_SCHEME_STORAGE_KEY = "atproto-ui-color-scheme"; 29 - 30 23 const basicUsageSnippet = `import { AtProtoProvider, BlueskyPost } from 'atproto-ui'; 31 24 32 25 export function App() { ··· 37 30 ); 38 31 }`; 39 32 40 - const customComponentSnippet = `import { useLatestRecord, useColorScheme, AtProtoRecord } from 'atproto-ui'; 33 + const prefetchedDataSnippet = `import { BlueskyPost, useLatestRecord } from 'atproto-ui'; 41 34 import type { FeedPostRecord } from 'atproto-ui'; 42 35 43 - const LatestPostSummary: React.FC<{ did: string }> = ({ did }) => { 44 - const scheme = useColorScheme('system'); 45 - const { rkey, loading, error } = useLatestRecord<FeedPostRecord>(did, 'app.bsky.feed.post'); 36 + const LatestPostWithPrefetch: React.FC<{ did: string }> = ({ did }) => { 37 + // Fetch once with the hook 38 + const { record, rkey, loading } = useLatestRecord<FeedPostRecord>( 39 + did, 40 + 'app.bsky.feed.post' 41 + ); 46 42 47 43 if (loading) return <span>Loadingโ€ฆ</span>; 48 - if (error || !rkey) return <span>No post yet.</span>; 44 + if (!record || !rkey) return <span>No posts yet.</span>; 49 45 50 - return ( 51 - <AtProtoRecord<FeedPostRecord> 52 - did={did} 53 - collection="app.bsky.feed.post" 54 - rkey={rkey} 55 - renderer={({ record }) => ( 56 - <article data-color-scheme={scheme}> 57 - <strong>{record?.text ?? 'Empty post'}</strong> 58 - </article> 59 - )} 60 - /> 61 - ); 46 + // Pass prefetched recordโ€”BlueskyPost won't re-fetch it 47 + return <BlueskyPost did={did} rkey={rkey} record={record} />; 62 48 };`; 63 49 50 + const atcuteUsageSnippet = `import { Client, simpleFetchHandler, ok } from '@atcute/client'; 51 + import type { AppBskyFeedPost } from '@atcute/bluesky'; 52 + import { BlueskyPost } from 'atproto-ui'; 53 + 54 + // Create atcute client 55 + const client = new Client({ 56 + handler: simpleFetchHandler({ service: 'https://public.api.bsky.app' }) 57 + }); 58 + 59 + // Fetch a record 60 + const data = await ok( 61 + client.get('com.atproto.repo.getRecord', { 62 + params: { 63 + repo: 'did:plc:ttdrpj45ibqunmfhdsb4zdwq', 64 + collection: 'app.bsky.feed.post', 65 + rkey: '3m45rq4sjes2h' 66 + } 67 + }) 68 + ); 69 + 70 + const record = data.value as AppBskyFeedPost.Main; 71 + 72 + // Pass atcute record directly to component! 73 + <BlueskyPost 74 + did="did:plc:ttdrpj45ibqunmfhdsb4zdwq" 75 + rkey="3m45rq4sjes2h" 76 + record={record} 77 + />`; 78 + 64 79 const codeBlockBase: React.CSSProperties = { 65 80 fontFamily: 'Menlo, Consolas, "SFMono-Regular", ui-monospace, monospace', 66 81 fontSize: 12, ··· 71 86 lineHeight: 1.6, 72 87 }; 73 88 89 + const ThemeSwitcher: React.FC = () => { 90 + const [theme, setTheme] = useState<"light" | "dark" | "system">("system"); 91 + 92 + const toggle = () => { 93 + const schemes: ("light" | "dark" | "system")[] = [ 94 + "light", 95 + "dark", 96 + "system", 97 + ]; 98 + const currentIndex = schemes.indexOf(theme); 99 + const nextIndex = (currentIndex + 1) % schemes.length; 100 + const nextTheme = schemes[nextIndex]; 101 + setTheme(nextTheme); 102 + 103 + // Update the data-theme attribute on the document element 104 + if (nextTheme === "system") { 105 + document.documentElement.removeAttribute("data-theme"); 106 + } else { 107 + document.documentElement.setAttribute("data-theme", nextTheme); 108 + } 109 + }; 110 + 111 + return ( 112 + <button 113 + onClick={toggle} 114 + style={{ 115 + padding: "8px 12px", 116 + borderRadius: 8, 117 + border: "1px solid var(--demo-border)", 118 + background: "var(--demo-input-bg)", 119 + color: "var(--demo-text)", 120 + cursor: "pointer", 121 + }} 122 + > 123 + Theme: {theme} 124 + </button> 125 + ); 126 + }; 127 + 74 128 const FullDemo: React.FC = () => { 75 129 const handleInputRef = useRef<HTMLInputElement | null>(null); 76 130 const [submitted, setSubmitted] = useState<string | null>(null); 77 - const [colorSchemePreference, setColorSchemePreference] = 78 - useState<ColorSchemePreference>(() => { 79 - if (typeof window === "undefined") return "system"; 80 - try { 81 - const stored = window.localStorage.getItem( 82 - COLOR_SCHEME_STORAGE_KEY, 83 - ); 84 - if ( 85 - stored === "light" || 86 - stored === "dark" || 87 - stored === "system" 88 - ) 89 - return stored; 90 - } catch { 91 - /* ignore */ 92 - } 93 - return "system"; 94 - }); 95 - const scheme = useColorScheme(colorSchemePreference); 131 + 96 132 const { did, loading: resolvingDid } = useDidResolution( 97 133 submitted ?? undefined, 98 134 ); ··· 107 143 setSubmitted(nextValue); 108 144 }, []); 109 145 110 - useEffect(() => { 111 - if (typeof window === "undefined") return; 112 - try { 113 - window.localStorage.setItem( 114 - COLOR_SCHEME_STORAGE_KEY, 115 - colorSchemePreference, 116 - ); 117 - } catch { 118 - /* ignore */ 119 - } 120 - }, [colorSchemePreference]); 121 - 122 - useEffect(() => { 123 - if (typeof document === "undefined") return; 124 - const root = document.documentElement; 125 - const body = document.body; 126 - const prevScheme = root.dataset.colorScheme; 127 - const prevBg = body.style.backgroundColor; 128 - const prevColor = body.style.color; 129 - root.dataset.colorScheme = scheme; 130 - body.style.backgroundColor = scheme === "dark" ? "#020617" : "#f8fafc"; 131 - body.style.color = scheme === "dark" ? "#e2e8f0" : "#0f172a"; 132 - return () => { 133 - root.dataset.colorScheme = prevScheme ?? ""; 134 - body.style.backgroundColor = prevBg; 135 - body.style.color = prevColor; 136 - }; 137 - }, [scheme]); 138 - 139 146 const showHandle = 140 147 submitted && !submitted.startsWith("did:") ? submitted : undefined; 141 148 142 - const mutedTextColor = useMemo( 143 - () => (scheme === "dark" ? "#94a3b8" : "#555"), 144 - [scheme], 145 - ); 146 - const panelStyle = useMemo<React.CSSProperties>( 147 - () => ({ 148 - display: "flex", 149 - flexDirection: "column", 150 - gap: 8, 151 - padding: 10, 152 - borderRadius: 12, 153 - borderColor: scheme === "dark" ? "#1e293b" : "#e2e8f0", 154 - }), 155 - [scheme], 156 - ); 157 - const baseTextColor = useMemo( 158 - () => (scheme === "dark" ? "#e2e8f0" : "#0f172a"), 159 - [scheme], 160 - ); 161 - const gistPanelStyle = useMemo<React.CSSProperties>( 162 - () => ({ 163 - ...panelStyle, 164 - padding: 0, 165 - border: "none", 166 - background: "transparent", 167 - backdropFilter: "none", 168 - marginTop: 32, 169 - }), 170 - [panelStyle], 171 - ); 172 - const leafletPanelStyle = useMemo<React.CSSProperties>( 173 - () => ({ 174 - ...panelStyle, 175 - padding: 0, 176 - border: "none", 177 - background: "transparent", 178 - backdropFilter: "none", 179 - marginTop: 32, 180 - alignItems: "center", 181 - }), 182 - [panelStyle], 183 - ); 184 - const primaryGridStyle = useMemo<React.CSSProperties>( 185 - () => ({ 186 - display: "grid", 187 - gap: 32, 188 - gridTemplateColumns: "repeat(auto-fit, minmax(320px, 1fr))", 189 - }), 190 - [], 191 - ); 192 - const columnStackStyle = useMemo<React.CSSProperties>( 193 - () => ({ 194 - display: "flex", 195 - flexDirection: "column", 196 - gap: 32, 197 - }), 198 - [], 199 - ); 200 - const codeBlockStyle = useMemo<React.CSSProperties>( 201 - () => ({ 202 - ...codeBlockBase, 203 - background: scheme === "dark" ? "#0b1120" : "#f1f5f9", 204 - border: `1px solid ${scheme === "dark" ? "#1e293b" : "#e2e8f0"}`, 205 - }), 206 - [scheme], 207 - ); 208 - const codeTextStyle = useMemo<React.CSSProperties>( 209 - () => ({ 210 - margin: 0, 211 - display: "block", 212 - fontFamily: codeBlockBase.fontFamily, 213 - fontSize: 12, 214 - lineHeight: 1.6, 215 - whiteSpace: "pre", 216 - }), 217 - [], 218 - ); 149 + const panelStyle: React.CSSProperties = { 150 + display: "flex", 151 + flexDirection: "column", 152 + gap: 8, 153 + padding: 10, 154 + borderRadius: 12, 155 + border: `1px solid var(--demo-border)`, 156 + }; 157 + 158 + const gistPanelStyle: React.CSSProperties = { 159 + ...panelStyle, 160 + padding: 0, 161 + border: "none", 162 + background: "transparent", 163 + backdropFilter: "none", 164 + marginTop: 32, 165 + }; 166 + const leafletPanelStyle: React.CSSProperties = { 167 + ...panelStyle, 168 + padding: 0, 169 + border: "none", 170 + background: "transparent", 171 + backdropFilter: "none", 172 + marginTop: 32, 173 + alignItems: "center", 174 + }; 175 + const primaryGridStyle: React.CSSProperties = { 176 + display: "grid", 177 + gap: 32, 178 + gridTemplateColumns: "repeat(auto-fit, minmax(320px, 1fr))", 179 + }; 180 + const columnStackStyle: React.CSSProperties = { 181 + display: "flex", 182 + flexDirection: "column", 183 + gap: 32, 184 + }; 185 + const codeBlockStyle: React.CSSProperties = { 186 + ...codeBlockBase, 187 + background: `var(--demo-code-bg)`, 188 + border: `1px solid var(--demo-code-border)`, 189 + color: `var(--demo-text)`, 190 + }; 191 + const codeTextStyle: React.CSSProperties = { 192 + margin: 0, 193 + display: "block", 194 + fontFamily: codeBlockBase.fontFamily, 195 + fontSize: 12, 196 + lineHeight: 1.6, 197 + whiteSpace: "pre", 198 + }; 219 199 const basicCodeRef = useRef<HTMLElement | null>(null); 220 200 const customCodeRef = useRef<HTMLElement | null>(null); 221 201 222 - // Latest Bluesky post 202 + // Latest Bluesky post - fetch with record for prefetch demo 223 203 const { 204 + record: latestPostRecord, 224 205 rkey: latestPostRkey, 225 206 loading: loadingLatestPost, 226 207 empty: noPosts, 227 208 error: latestPostError, 228 - } = useLatestRecord<unknown>(did, BLUESKY_POST_COLLECTION); 209 + } = useLatestRecord<FeedPostRecord>(did, BLUESKY_POST_COLLECTION); 229 210 230 211 const quoteSampleDid = "did:plc:ttdrpj45ibqunmfhdsb4zdwq"; 231 212 const quoteSampleRkey = "3m2prlq6xxc2v"; ··· 236 217 display: "flex", 237 218 flexDirection: "column", 238 219 gap: 20, 239 - color: baseTextColor, 240 220 }} 241 221 > 242 222 <div ··· 264 244 flex: "1 1 260px", 265 245 padding: "6px 8px", 266 246 borderRadius: 8, 267 - border: "1px solid", 268 - borderColor: 269 - scheme === "dark" ? "#1e293b" : "#cbd5f5", 270 - background: scheme === "dark" ? "#0b1120" : "#fff", 271 - color: scheme === "dark" ? "#e2e8f0" : "#0f172a", 247 + border: `1px solid var(--demo-border)`, 248 + background: `var(--demo-input-bg)`, 249 + color: `var(--demo-text)`, 272 250 }} 273 251 /> 274 252 <button ··· 277 255 padding: "6px 16px", 278 256 borderRadius: 8, 279 257 border: "none", 280 - background: "#2563eb", 281 - color: "#fff", 258 + background: `var(--demo-button-bg)`, 259 + color: `var(--demo-button-text)`, 282 260 cursor: "pointer", 283 261 }} 284 262 > 285 263 Load 286 264 </button> 287 265 </form> 288 - <ColorSchemeToggle 289 - value={colorSchemePreference} 290 - onChange={setColorSchemePreference} 291 - scheme={scheme} 292 - /> 266 + <ThemeSwitcher /> 293 267 </div> 294 268 {!submitted && ( 295 - <p style={{ color: mutedTextColor }}> 269 + <p style={{ color: `var(--demo-text-secondary)` }}> 296 270 Enter a handle to fetch your profile, latest Bluesky post, a 297 271 Tangled string, and a Leaflet document. 298 272 </p> 299 273 )} 300 274 {submitted && resolvingDid && ( 301 - <p style={{ color: mutedTextColor }}>Resolving DIDโ€ฆ</p> 275 + <p style={{ color: `var(--demo-text-secondary)` }}> 276 + Resolving DIDโ€ฆ 277 + </p> 302 278 )} 303 279 {did && ( 304 280 <> ··· 306 282 <div style={columnStackStyle}> 307 283 <section style={panelStyle}> 308 284 <h3 style={sectionHeaderStyle}>Profile</h3> 309 - <BlueskyProfile 310 - did={did} 311 - handle={showHandle} 312 - colorScheme={colorSchemePreference} 313 - /> 285 + <BlueskyProfile did={did} handle={showHandle} /> 314 286 </section> 315 287 <section style={panelStyle}> 316 288 <h3 style={sectionHeaderStyle}>Recent Posts</h3> 317 - <BlueskyPostList 318 - did={did} 319 - colorScheme={colorSchemePreference} 289 + <BlueskyPostList did={did} /> 290 + </section> 291 + <section style={panelStyle}> 292 + <h3 style={sectionHeaderStyle}> 293 + grain.social Gallery Demo 294 + </h3> 295 + <p 296 + style={{ 297 + fontSize: 12, 298 + color: `var(--demo-text-secondary)`, 299 + margin: "0 0 8px", 300 + }} 301 + > 302 + Instagram-style photo gallery from grain.social 303 + </p> 304 + <GrainGallery 305 + did="kat.meangirls.online" 306 + rkey="3m2e2qikseq2f" 320 307 /> 321 308 </section> 309 + <section style={panelStyle}> 310 + <h3 style={sectionHeaderStyle}> 311 + teal.fm Currently Playing 312 + </h3> 313 + <p 314 + style={{ 315 + fontSize: 12, 316 + color: `var(--demo-text-secondary)`, 317 + margin: "0 0 8px", 318 + }} 319 + > 320 + Currently playing track from teal.fm (refreshes every 15s) 321 + </p> 322 + <CurrentlyPlaying did="nekomimi.pet" /> 323 + </section> 324 + <section style={panelStyle}> 325 + <h3 style={sectionHeaderStyle}> 326 + teal.fm Last Played 327 + </h3> 328 + <p 329 + style={{ 330 + fontSize: 12, 331 + color: `var(--demo-text-secondary)`, 332 + margin: "0 0 8px", 333 + }} 334 + > 335 + Most recent play from teal.fm feed 336 + </p> 337 + <LastPlayed did="nekomimi.pet" /> 338 + </section> 339 + <section style={panelStyle}> 340 + <h3 style={sectionHeaderStyle}> 341 + teal.fm Song History 342 + </h3> 343 + <p 344 + style={{ 345 + fontSize: 12, 346 + color: `var(--demo-text-secondary)`, 347 + margin: "0 0 8px", 348 + }} 349 + > 350 + Listening history with album art focus 351 + </p> 352 + <SongHistoryList did="nekomimi.pet" limit={6} /> 353 + </section> 322 354 </div> 323 355 <div style={columnStackStyle}> 324 356 <section style={panelStyle}> 325 357 <h3 style={sectionHeaderStyle}> 326 - Latest Bluesky Post 358 + Latest Post (Prefetched Data) 327 359 </h3> 360 + <p 361 + style={{ 362 + fontSize: 12, 363 + color: `var(--demo-text-secondary)`, 364 + margin: "0 0 8px", 365 + }} 366 + > 367 + Using{" "} 368 + <code 369 + style={{ 370 + background: `var(--demo-code-bg)`, 371 + padding: "2px 4px", 372 + borderRadius: 3, 373 + color: "var(--demo-text)", 374 + }} 375 + > 376 + useLatestRecord 377 + </code>{" "} 378 + to fetch once, then passing{" "} 379 + <code 380 + style={{ 381 + background: `var(--demo-code-bg)`, 382 + padding: "2px 4px", 383 + borderRadius: 3, 384 + color: "var(--demo-text)", 385 + }} 386 + > 387 + record 388 + </code>{" "} 389 + propโ€”no re-fetch! 390 + </p> 328 391 {loadingLatestPost && ( 329 392 <div style={loadingBox}> 330 393 Loading latest postโ€ฆ ··· 336 399 </div> 337 400 )} 338 401 {noPosts && ( 339 - <div 340 - style={{ 341 - ...infoBox, 342 - color: mutedTextColor, 343 - }} 344 - > 345 - No posts found. 346 - </div> 402 + <div style={infoBox}>No posts found.</div> 347 403 )} 348 - {!loadingLatestPost && latestPostRkey && ( 349 - <BlueskyPost 350 - did={did} 351 - rkey={latestPostRkey} 352 - colorScheme={colorSchemePreference} 353 - /> 354 - )} 404 + {!loadingLatestPost && 405 + latestPostRkey && 406 + latestPostRecord && ( 407 + <BlueskyPost 408 + did={did} 409 + rkey={latestPostRkey} 410 + record={latestPostRecord} 411 + /> 412 + )} 355 413 </section> 356 414 <section style={panelStyle}> 357 415 <h3 style={sectionHeaderStyle}> ··· 360 418 <BlueskyQuotePost 361 419 did={quoteSampleDid} 362 420 rkey={quoteSampleRkey} 363 - colorScheme={colorSchemePreference} 421 + /> 422 + </section> 423 + <section style={panelStyle}> 424 + <h3 style={sectionHeaderStyle}> 425 + Reply Post Demo 426 + </h3> 427 + <BlueskyPost 428 + did="did:plc:xwhsmuozq3mlsp56dyd7copv" 429 + rkey="3m3je5ydg4s2o" 430 + showParent={true} 431 + recursiveParent={true} 364 432 /> 365 433 </section> 434 + <section style={panelStyle}> 435 + <h3 style={sectionHeaderStyle}> 436 + Rich Text Facets Demo 437 + </h3> 438 + <p 439 + style={{ 440 + fontSize: 12, 441 + color: `var(--demo-text-secondary)`, 442 + margin: "0 0 8px", 443 + }} 444 + > 445 + Post with mentions, links, and hashtags 446 + </p> 447 + <BlueskyPost 448 + did="nekomimi.pet" 449 + rkey="3m45s553cys22" 450 + showParent={false} 451 + /> 452 + </section> 453 + <section style={panelStyle}> 454 + <TangledRepo 455 + did="did:plc:ttdrpj45ibqunmfhdsb4zdwq" 456 + rkey="3m2sx5zpxzs22" 457 + /> 458 + </section> 459 + <section style={panelStyle}> 460 + <h3 style={sectionHeaderStyle}> 461 + Custom Themed Post 462 + </h3> 463 + <p 464 + style={{ 465 + fontSize: 12, 466 + color: `var(--demo-text-secondary)`, 467 + margin: "0 0 8px", 468 + }} 469 + > 470 + Wrapping a component in a div with custom 471 + CSS variables to override the theme! 472 + </p> 473 + <div 474 + style={ 475 + { 476 + "--atproto-color-bg": 477 + "var(--demo-secondary-bg)", 478 + "--atproto-color-bg-elevated": 479 + "var(--demo-input-bg)", 480 + "--atproto-color-bg-secondary": 481 + "var(--demo-code-bg)", 482 + "--atproto-color-text": 483 + "var(--demo-text)", 484 + "--atproto-color-text-secondary": 485 + "var(--demo-text-secondary)", 486 + "--atproto-color-text-muted": 487 + "var(--demo-text-secondary)", 488 + "--atproto-color-border": 489 + "var(--demo-border)", 490 + "--atproto-color-border-subtle": 491 + "var(--demo-border)", 492 + "--atproto-color-link": 493 + "var(--demo-button-bg)", 494 + } as React.CSSProperties 495 + } 496 + > 497 + <BlueskyPost 498 + did="nekomimi.pet" 499 + rkey="3m2dgvyws7k27" 500 + /> 501 + </div> 502 + </section> 366 503 </div> 367 504 </div> 368 505 <section style={gistPanelStyle}> ··· 370 507 <TangledString 371 508 did="nekomimi.pet" 372 509 rkey="3m2p4gjptg522" 373 - colorScheme={colorSchemePreference} 374 510 /> 375 511 </section> 376 512 <section style={leafletPanelStyle}> ··· 385 521 <LeafletDocument 386 522 did={"did:plc:ttdrpj45ibqunmfhdsb4zdwq"} 387 523 rkey={"3m2seagm2222c"} 388 - colorScheme={colorSchemePreference} 389 524 /> 390 525 </div> 391 526 </section> 392 527 </> 393 528 )} 394 529 <section style={{ ...panelStyle, marginTop: 32 }}> 395 - <h3 style={sectionHeaderStyle}>Build your own component</h3> 396 - <p style={{ color: mutedTextColor, margin: "4px 0 8px" }}> 530 + <h3 style={sectionHeaderStyle}>Code Examples</h3> 531 + <p 532 + style={{ 533 + color: `var(--demo-text-secondary)`, 534 + margin: "4px 0 8px", 535 + }} 536 + > 397 537 Wrap your app with the provider once and drop the ready-made 398 538 components wherever you need them. 399 539 </p> ··· 406 546 {basicUsageSnippet} 407 547 </code> 408 548 </pre> 409 - <p style={{ color: mutedTextColor, margin: "16px 0 8px" }}> 410 - Need to make your own component? Compose your own renderer 411 - with the hooks and utilities that ship with the library. 549 + <p 550 + style={{ 551 + color: `var(--demo-text-secondary)`, 552 + margin: "16px 0 8px", 553 + }} 554 + > 555 + Pass prefetched data to components to skip API callsโ€”perfect 556 + for SSR or caching. 412 557 </p> 413 558 <pre style={codeBlockStyle}> 414 559 <code ··· 416 561 className="language-tsx" 417 562 style={codeTextStyle} 418 563 > 419 - {customComponentSnippet} 564 + {prefetchedDataSnippet} 420 565 </code> 421 566 </pre> 422 - {did && ( 423 - <div 424 - style={{ 425 - marginTop: 16, 426 - display: "flex", 427 - flexDirection: "column", 428 - gap: 12, 429 - }} 430 - > 431 - <p style={{ color: mutedTextColor, margin: 0 }}> 432 - Live example with your handle: 433 - </p> 434 - <LatestPostSummary 435 - did={did} 436 - handle={showHandle} 437 - colorScheme={colorSchemePreference} 438 - /> 439 - </div> 440 - )} 567 + <p 568 + style={{ 569 + color: `var(--demo-text-secondary)`, 570 + margin: "16px 0 8px", 571 + }} 572 + > 573 + Use atcute directly to construct records and pass them to 574 + componentsโ€”fully compatible! 575 + </p> 576 + <pre style={codeBlockStyle}> 577 + <code className="language-tsx" style={codeTextStyle}> 578 + {atcuteUsageSnippet} 579 + </code> 580 + </pre> 441 581 </section> 442 582 </div> 443 583 ); 444 584 }; 445 585 446 - const LatestPostSummary: React.FC<{ 447 - did: string; 448 - handle?: string; 449 - colorScheme: ColorSchemePreference; 450 - }> = ({ did, colorScheme }) => { 451 - const { record, rkey, loading, error } = useLatestRecord<FeedPostRecord>( 452 - did, 453 - BLUESKY_POST_COLLECTION, 454 - ); 455 - const scheme = useColorScheme(colorScheme); 456 - const palette = 457 - scheme === "dark" 458 - ? latestSummaryPalette.dark 459 - : latestSummaryPalette.light; 460 - 461 - if (loading) return <div style={palette.muted}>Loading summaryโ€ฆ</div>; 462 - if (error) 463 - return <div style={palette.error}>Failed to load the latest post.</div>; 464 - if (!rkey) return <div style={palette.muted}>No posts published yet.</div>; 465 - 466 - const atProtoProps = record 467 - ? { record } 468 - : { did, collection: "app.bsky.feed.post", rkey }; 469 - 470 - return ( 471 - <AtProtoRecord<FeedPostRecord> 472 - {...atProtoProps} 473 - renderer={({ record: resolvedRecord }) => ( 474 - <article data-color-scheme={scheme}> 475 - <strong>{resolvedRecord?.text ?? "Empty post"}</strong> 476 - </article> 477 - )} 478 - /> 479 - ); 480 - }; 481 - 482 586 const sectionHeaderStyle: React.CSSProperties = { 483 587 margin: "4px 0", 484 588 fontSize: 16, 589 + color: "var(--demo-text)", 485 590 }; 486 591 const loadingBox: React.CSSProperties = { padding: 8 }; 487 592 const errorBox: React.CSSProperties = { padding: 8, color: "crimson" }; 488 - const infoBox: React.CSSProperties = { padding: 8, color: "#555" }; 489 - 490 - const latestSummaryPalette = { 491 - light: { 492 - card: { 493 - border: "1px solid #e2e8f0", 494 - background: "#ffffff", 495 - borderRadius: 12, 496 - padding: 12, 497 - display: "flex", 498 - flexDirection: "column", 499 - gap: 8, 500 - } satisfies React.CSSProperties, 501 - header: { 502 - display: "flex", 503 - alignItems: "baseline", 504 - justifyContent: "space-between", 505 - gap: 12, 506 - color: "#0f172a", 507 - } satisfies React.CSSProperties, 508 - time: { 509 - fontSize: 12, 510 - color: "#64748b", 511 - } satisfies React.CSSProperties, 512 - text: { 513 - margin: 0, 514 - color: "#1f2937", 515 - whiteSpace: "pre-wrap", 516 - } satisfies React.CSSProperties, 517 - link: { 518 - color: "#2563eb", 519 - fontWeight: 600, 520 - fontSize: 12, 521 - textDecoration: "none", 522 - } satisfies React.CSSProperties, 523 - muted: { 524 - color: "#64748b", 525 - } satisfies React.CSSProperties, 526 - error: { 527 - color: "crimson", 528 - } satisfies React.CSSProperties, 529 - }, 530 - dark: { 531 - card: { 532 - border: "1px solid #1e293b", 533 - background: "#0f172a", 534 - borderRadius: 12, 535 - padding: 12, 536 - display: "flex", 537 - flexDirection: "column", 538 - gap: 8, 539 - } satisfies React.CSSProperties, 540 - header: { 541 - display: "flex", 542 - alignItems: "baseline", 543 - justifyContent: "space-between", 544 - gap: 12, 545 - color: "#e2e8f0", 546 - } satisfies React.CSSProperties, 547 - time: { 548 - fontSize: 12, 549 - color: "#cbd5f5", 550 - } satisfies React.CSSProperties, 551 - text: { 552 - margin: 0, 553 - color: "#e2e8f0", 554 - whiteSpace: "pre-wrap", 555 - } satisfies React.CSSProperties, 556 - link: { 557 - color: "#38bdf8", 558 - fontWeight: 600, 559 - fontSize: 12, 560 - textDecoration: "none", 561 - } satisfies React.CSSProperties, 562 - muted: { 563 - color: "#94a3b8", 564 - } satisfies React.CSSProperties, 565 - error: { 566 - color: "#f472b6", 567 - } satisfies React.CSSProperties, 568 - }, 569 - } as const; 593 + const infoBox: React.CSSProperties = { 594 + padding: 8, 595 + color: "var(--demo-text-secondary)", 596 + }; 570 597 571 598 export const App: React.FC = () => { 572 599 return ( ··· 577 604 margin: "40px auto", 578 605 padding: "0 20px", 579 606 fontFamily: "system-ui, sans-serif", 607 + minHeight: "100vh", 580 608 }} 581 609 > 582 - <h1 style={{ marginTop: 0 }}>atproto-ui Demo</h1> 583 - <p style={{ lineHeight: 1.4 }}> 610 + <h1 style={{ marginTop: 0, color: "var(--demo-text)" }}> 611 + atproto-ui Demo 612 + </h1> 613 + <p 614 + style={{ 615 + lineHeight: 1.4, 616 + color: "var(--demo-text-secondary)", 617 + }} 618 + > 584 619 A component library for rendering common AT Protocol records 585 620 for applications such as Bluesky and Tangled. 586 621 </p> 587 - <hr style={{ margin: "32px 0" }} /> 622 + <hr 623 + style={{ margin: "32px 0", borderColor: "var(--demo-hr)" }} 624 + /> 588 625 <FullDemo /> 589 626 </div> 590 627 </AtProtoProvider>
+3
tsconfig.app.json
··· 14 14 "verbatimModuleSyntax": true, 15 15 "moduleDetection": "force", 16 16 "noEmit": true, 17 + "emitDeclarationOnly": true, 18 + "declaration": true, 19 + "declarationDir": "dist-lib", 17 20 "jsx": "react-jsx", 18 21 19 22 /* Linting */
+6 -4
tsconfig.lib.json
··· 12 12 "allowSyntheticDefaultImports": true, 13 13 "esModuleInterop": true, 14 14 "resolveJsonModule": true, 15 + "noEmit": true, 16 + "emitDeclarationOnly": true, 15 17 "declaration": true, 16 - "declarationMap": true, 17 - "emitDeclarationOnly": true, 18 - "sourceMap": false, 18 + "declarationDir": "dist-lib", 19 + "sourceMap": true, 19 20 "outDir": "./lib-dist", 20 - "rootDir": "./lib" 21 + "rootDir": "./lib", 22 + "types": ["@atcute/bluesky", "@atcute/tangled"] 21 23 }, 22 24 "include": ["lib/**/*.ts", "lib/**/*.tsx"] 23 25 }
-1
tsconfig.lib.tsbuildinfo
··· 1 - {"fileNames":["./node_modules/typescript/lib/lib.es5.d.ts","./node_modules/typescript/lib/lib.es2015.d.ts","./node_modules/typescript/lib/lib.es2016.d.ts","./node_modules/typescript/lib/lib.es2017.d.ts","./node_modules/typescript/lib/lib.es2018.d.ts","./node_modules/typescript/lib/lib.es2019.d.ts","./node_modules/typescript/lib/lib.es2020.d.ts","./node_modules/typescript/lib/lib.dom.d.ts","./node_modules/typescript/lib/lib.dom.iterable.d.ts","./node_modules/typescript/lib/lib.es2015.core.d.ts","./node_modules/typescript/lib/lib.es2015.collection.d.ts","./node_modules/typescript/lib/lib.es2015.generator.d.ts","./node_modules/typescript/lib/lib.es2015.iterable.d.ts","./node_modules/typescript/lib/lib.es2015.promise.d.ts","./node_modules/typescript/lib/lib.es2015.proxy.d.ts","./node_modules/typescript/lib/lib.es2015.reflect.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.d.ts","./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2016.array.include.d.ts","./node_modules/typescript/lib/lib.es2016.intl.d.ts","./node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","./node_modules/typescript/lib/lib.es2017.date.d.ts","./node_modules/typescript/lib/lib.es2017.object.d.ts","./node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2017.string.d.ts","./node_modules/typescript/lib/lib.es2017.intl.d.ts","./node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","./node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","./node_modules/typescript/lib/lib.es2018.intl.d.ts","./node_modules/typescript/lib/lib.es2018.promise.d.ts","./node_modules/typescript/lib/lib.es2018.regexp.d.ts","./node_modules/typescript/lib/lib.es2019.array.d.ts","./node_modules/typescript/lib/lib.es2019.object.d.ts","./node_modules/typescript/lib/lib.es2019.string.d.ts","./node_modules/typescript/lib/lib.es2019.symbol.d.ts","./node_modules/typescript/lib/lib.es2019.intl.d.ts","./node_modules/typescript/lib/lib.es2020.bigint.d.ts","./node_modules/typescript/lib/lib.es2020.date.d.ts","./node_modules/typescript/lib/lib.es2020.promise.d.ts","./node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2020.string.d.ts","./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","./node_modules/typescript/lib/lib.es2020.intl.d.ts","./node_modules/typescript/lib/lib.es2020.number.d.ts","./node_modules/typescript/lib/lib.esnext.disposable.d.ts","./node_modules/typescript/lib/lib.esnext.float16.d.ts","./node_modules/typescript/lib/lib.decorators.d.ts","./node_modules/typescript/lib/lib.decorators.legacy.d.ts","./node_modules/@types/react/global.d.ts","./node_modules/csstype/index.d.ts","./node_modules/@types/react/index.d.ts","./node_modules/@types/react/jsx-runtime.d.ts","./node_modules/@atcute/lexicons/dist/syntax/did.d.ts","./node_modules/@atcute/lexicons/dist/syntax/handle.d.ts","./node_modules/@atcute/lexicons/dist/syntax/at-identifier.d.ts","./node_modules/@atcute/lexicons/dist/syntax/nsid.d.ts","./node_modules/@atcute/lexicons/dist/syntax/record-key.d.ts","./node_modules/@atcute/lexicons/dist/utils.d.ts","./node_modules/@atcute/lexicons/dist/syntax/at-uri.d.ts","./node_modules/@atcute/lexicons/dist/syntax/cid.d.ts","./node_modules/@atcute/lexicons/dist/syntax/datetime.d.ts","./node_modules/@atcute/lexicons/dist/syntax/language.d.ts","./node_modules/@atcute/lexicons/dist/syntax/tid.d.ts","./node_modules/@atcute/lexicons/dist/syntax/uri.d.ts","./node_modules/@atcute/lexicons/dist/interfaces/cid-link.d.ts","./node_modules/@atcute/lexicons/dist/interfaces/blob.d.ts","./node_modules/@atcute/lexicons/dist/interfaces/bytes.d.ts","./node_modules/@atcute/lexicons/dist/types/brand.d.ts","./node_modules/@standard-schema/spec/dist/index.d.ts","./node_modules/@atcute/lexicons/dist/syntax/index.d.ts","./node_modules/@atcute/lexicons/dist/interfaces/index.d.ts","./node_modules/@atcute/lexicons/dist/validations/index.d.ts","./node_modules/@atcute/lexicons/dist/index.d.ts","./node_modules/@atcute/lexicons/dist/ambient.d.ts","./node_modules/@atcute/client/dist/fetch-handler.d.ts","./node_modules/@atcute/client/dist/client.d.ts","./node_modules/@atcute/client/dist/credential-manager.d.ts","./node_modules/@atcute/client/dist/index.d.ts","./node_modules/@badrap/valita/dist/mjs/index.d.mts","./node_modules/@atcute/identity/dist/types.d.ts","./node_modules/@atcute/identity/dist/typedefs.d.ts","./node_modules/@atcute/identity/dist/utils.d.ts","./node_modules/@atcute/identity/dist/did.d.ts","./node_modules/@atcute/identity/dist/methods/key.d.ts","./node_modules/@atcute/identity/dist/methods/plc.d.ts","./node_modules/@atcute/identity/dist/methods/web.d.ts","./node_modules/@atcute/identity/dist/index.d.ts","./node_modules/@atcute/identity-resolver/dist/types.d.ts","./node_modules/@atcute/identity-resolver/dist/did/composite.d.ts","./node_modules/@atcute/identity-resolver/dist/did/methods/plc.d.ts","./node_modules/@atcute/identity-resolver/dist/did/methods/web.d.ts","./node_modules/@atcute/identity-resolver/dist/did/methods/xrpc.d.ts","./node_modules/@atcute/identity-resolver/dist/handle/composite.d.ts","./node_modules/@atcute/identity-resolver/dist/handle/methods/doh-json.d.ts","./node_modules/@atcute/identity-resolver/dist/handle/methods/well-known.d.ts","./node_modules/@atcute/identity-resolver/dist/handle/methods/xrpc.d.ts","./node_modules/@atcute/identity-resolver/dist/errors.d.ts","./node_modules/@atcute/identity-resolver/dist/index.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/actor/profile.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/feed/reaction.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/feed/star.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/git/refupdate.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/graph/follow.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/knot.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/knot/listkeys.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/knot/member.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/knot/version.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/owner.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/pipeline.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/pipeline/status.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/publickey.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/addsecret.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/archive.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/artifact.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/blob.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/branch.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/branches.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/collaborator.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/compare.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/create.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/delete.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/diff.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/forkstatus.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/forksync.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/getdefaultbranch.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/hiddenref.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/issue.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/issue/comment.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/issue/state.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/issue/state/closed.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/issue/state/open.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/languages.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/listsecrets.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/log.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/merge.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/mergecheck.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/pull.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/pull/comment.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/pull/status.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/pull/status/closed.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/pull/status/merged.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/pull/status/open.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/removesecret.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/setdefaultbranch.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/tags.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/repo/tree.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/spindle.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/spindle/member.d.ts","./node_modules/@atcute/tangled/dist/lexicons/types/sh/tangled/string.d.ts","./node_modules/@atcute/tangled/dist/lexicons/index.d.ts","./node_modules/@atcute/tangled/dist/index.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/server/defs.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/admin/defs.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/admin/deleteaccount.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/admin/disableaccountinvites.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/admin/disableinvitecodes.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/admin/enableaccountinvites.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/admin/getaccountinfo.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/admin/getaccountinfos.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/admin/getinvitecodes.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/repo/strongref.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/admin/getsubjectstatus.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/admin/searchaccounts.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/admin/sendemail.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/admin/updateaccountemail.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/admin/updateaccounthandle.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/admin/updateaccountpassword.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/admin/updateaccountsigningkey.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/admin/updatesubjectstatus.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/identity/defs.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/identity/getrecommendeddidcredentials.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/identity/refreshidentity.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/identity/requestplcoperationsignature.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/identity/resolvedid.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/identity/resolvehandle.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/identity/resolveidentity.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/identity/signplcoperation.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/identity/submitplcoperation.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/identity/updatehandle.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/label/defs.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/label/querylabels.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/label/subscribelabels.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/lexicon/schema.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/moderation/defs.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/moderation/createreport.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/repo/defs.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/repo/applywrites.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/repo/createrecord.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/repo/deleterecord.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/repo/describerepo.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/repo/getrecord.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/repo/importrepo.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/repo/listmissingblobs.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/repo/listrecords.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/repo/putrecord.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/repo/uploadblob.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/server/activateaccount.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/server/checkaccountstatus.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/server/confirmemail.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/server/createaccount.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/server/createapppassword.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/server/createinvitecode.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/server/createinvitecodes.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/server/createsession.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/server/deactivateaccount.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/server/deleteaccount.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/server/deletesession.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/server/describeserver.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/server/getaccountinvitecodes.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/server/getserviceauth.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/server/getsession.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/server/listapppasswords.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/server/refreshsession.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/server/requestaccountdelete.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/server/requestemailconfirmation.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/server/requestemailupdate.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/server/requestpasswordreset.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/server/reservesigningkey.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/server/resetpassword.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/server/revokeapppassword.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/server/updateemail.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/sync/defs.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/sync/getblob.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/sync/getblocks.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/sync/getcheckout.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/sync/gethead.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/sync/gethoststatus.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/sync/getlatestcommit.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/sync/getrecord.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/sync/getrepo.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/sync/getrepostatus.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/sync/listblobs.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/sync/listhosts.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/sync/listrepos.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/sync/listreposbycollection.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/sync/notifyofupdate.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/sync/requestcrawl.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/sync/subscriberepos.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/temp/addreservedhandle.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/temp/checkhandleavailability.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/temp/checksignupqueue.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/temp/dereferencescope.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/temp/fetchlabels.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/temp/requestphoneverification.d.ts","./node_modules/@atcute/atproto/dist/lexicons/types/com/atproto/temp/revokeaccountcredentials.d.ts","./node_modules/@atcute/atproto/dist/lexicons/index.d.ts","./node_modules/@atcute/atproto/dist/index.d.ts","./lib/utils/atproto-client.ts","./lib/utils/cache.ts","./lib/providers/atprotoprovider.tsx","./lib/hooks/usedidresolution.ts","./lib/hooks/usepdsendpoint.ts","./lib/hooks/useatprotorecord.ts","./lib/core/atprotorecord.tsx","./lib/components/blueskyicon.tsx","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/embed/external.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/feed/postgate.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/feed/threadgate.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/embed/defs.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/embed/images.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/embed/video.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/embed/recordwithmedia.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/labeler/defs.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/embed/record.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/richtext/facet.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/feed/defs.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/defs.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/notification/defs.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/actor/defs.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/actor/getpreferences.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/actor/getprofile.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/actor/getprofiles.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/actor/getsuggestions.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/actor/profile.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/actor/putpreferences.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/actor/searchactors.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/actor/searchactorstypeahead.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/actor/status.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/bookmark/createbookmark.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/bookmark/defs.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/bookmark/deletebookmark.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/bookmark/getbookmarks.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/feed/describefeedgenerator.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/feed/generator.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/feed/getactorfeeds.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/feed/getactorlikes.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/feed/getauthorfeed.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/feed/getfeed.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/feed/getfeedgenerator.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/feed/getfeedgenerators.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/feed/getfeedskeleton.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/feed/getlikes.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/feed/getlistfeed.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/feed/getpostthread.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/feed/getposts.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/feed/getquotes.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/feed/getrepostedby.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/feed/getsuggestedfeeds.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/feed/gettimeline.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/feed/like.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/feed/post.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/feed/repost.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/feed/searchposts.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/feed/sendinteractions.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/block.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/follow.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/getactorstarterpacks.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/getblocks.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/getfollowers.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/getfollows.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/getknownfollowers.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/getlist.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/getlistblocks.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/getlistmutes.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/getlists.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/getlistswithmembership.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/getmutes.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/getrelationships.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/getstarterpack.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/getstarterpacks.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/getstarterpackswithmembership.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/getsuggestedfollowsbyactor.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/list.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/listblock.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/listitem.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/muteactor.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/muteactorlist.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/mutethread.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/searchstarterpacks.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/starterpack.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/unmuteactor.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/unmuteactorlist.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/unmutethread.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/graph/verification.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/labeler/getservices.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/labeler/service.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/notification/declaration.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/notification/getpreferences.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/notification/getunreadcount.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/notification/listactivitysubscriptions.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/notification/listnotifications.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/notification/putactivitysubscription.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/notification/putpreferences.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/notification/putpreferencesv2.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/notification/registerpush.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/notification/unregisterpush.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/notification/updateseen.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/unspecced/defs.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/unspecced/getageassurancestate.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/unspecced/getconfig.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/unspecced/getpopularfeedgenerators.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/unspecced/getpostthreadotherv2.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/unspecced/getpostthreadv2.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/unspecced/getsuggestedfeeds.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/unspecced/getsuggestedfeedsskeleton.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/unspecced/getsuggestedstarterpacks.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/unspecced/getsuggestedstarterpacksskeleton.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/unspecced/getsuggestedusers.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/unspecced/getsuggestedusersskeleton.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/unspecced/getsuggestionsskeleton.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/unspecced/gettaggedsuggestions.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/unspecced/gettrendingtopics.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/unspecced/gettrends.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/unspecced/gettrendsskeleton.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/unspecced/initageassurance.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/unspecced/searchactorsskeleton.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/unspecced/searchpostsskeleton.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/unspecced/searchstarterpacksskeleton.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/video/defs.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/video/getjobstatus.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/video/getuploadlimits.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/app/bsky/video/uploadvideo.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/chat/bsky/actor/declaration.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/chat/bsky/actor/defs.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/chat/bsky/actor/deleteaccount.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/chat/bsky/actor/exportaccountdata.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/chat/bsky/convo/acceptconvo.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/chat/bsky/convo/defs.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/chat/bsky/convo/addreaction.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/chat/bsky/convo/deletemessageforself.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/chat/bsky/convo/getconvo.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/chat/bsky/convo/getconvoavailability.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/chat/bsky/convo/getconvoformembers.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/chat/bsky/convo/getlog.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/chat/bsky/convo/getmessages.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/chat/bsky/convo/leaveconvo.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/chat/bsky/convo/listconvos.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/chat/bsky/convo/muteconvo.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/chat/bsky/convo/removereaction.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/chat/bsky/convo/sendmessage.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/chat/bsky/convo/sendmessagebatch.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/chat/bsky/convo/unmuteconvo.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/chat/bsky/convo/updateallread.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/chat/bsky/convo/updateread.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/chat/bsky/moderation/getactormetadata.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/chat/bsky/moderation/getmessagecontext.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/types/chat/bsky/moderation/updateactoraccess.d.ts","./node_modules/@atcute/bluesky/dist/lexicons/index.d.ts","./node_modules/@atcute/bluesky/dist/utilities/embeds.d.ts","./node_modules/@atcute/bluesky/dist/utilities/list.d.ts","./node_modules/@atcute/bluesky/dist/utilities/profile.d.ts","./node_modules/@atcute/bluesky/dist/utilities/starterpack.d.ts","./node_modules/@atcute/bluesky/dist/index.d.ts","./lib/types/bluesky.ts","./lib/hooks/usecolorscheme.ts","./lib/utils/at-uri.ts","./lib/hooks/useblob.ts","./lib/renderers/blueskypostrenderer.tsx","./lib/renderers/blueskyprofilerenderer.tsx","./lib/utils/profile.ts","./lib/components/blueskyprofile.tsx","./lib/components/blueskypost.tsx","./lib/hooks/usepaginatedrecords.ts","./lib/components/blueskypostlist.tsx","./lib/components/blueskyquotepost.tsx","./lib/components/colorschemetoggle.tsx","./lib/types/leaflet.ts","./lib/renderers/leafletdocumentrenderer.tsx","./lib/components/leafletdocument.tsx","./lib/renderers/tangledstringrenderer.tsx","./lib/components/tangledstring.tsx","./lib/hooks/useblueskyprofile.ts","./lib/hooks/uselatestrecord.ts","./lib/index.ts","./node_modules/@types/argparse/index.d.ts","./node_modules/@babel/types/lib/index.d.ts","./node_modules/@types/babel__generator/index.d.ts","./node_modules/@babel/parser/typings/babel-parser.d.ts","./node_modules/@types/babel__template/index.d.ts","./node_modules/@types/babel__traverse/index.d.ts","./node_modules/@types/babel__core/index.d.ts","./node_modules/@types/estree/index.d.ts","./node_modules/@types/json-schema/index.d.ts","./node_modules/@types/node/compatibility/iterators.d.ts","./node_modules/@types/node/globals.typedarray.d.ts","./node_modules/@types/node/buffer.buffer.d.ts","./node_modules/@types/node/globals.d.ts","./node_modules/@types/node/web-globals/abortcontroller.d.ts","./node_modules/@types/node/web-globals/crypto.d.ts","./node_modules/@types/node/web-globals/domexception.d.ts","./node_modules/@types/node/web-globals/events.d.ts","./node_modules/undici-types/utility.d.ts","./node_modules/undici-types/header.d.ts","./node_modules/undici-types/readable.d.ts","./node_modules/undici-types/fetch.d.ts","./node_modules/undici-types/formdata.d.ts","./node_modules/undici-types/connector.d.ts","./node_modules/undici-types/client-stats.d.ts","./node_modules/undici-types/client.d.ts","./node_modules/undici-types/errors.d.ts","./node_modules/undici-types/dispatcher.d.ts","./node_modules/undici-types/global-dispatcher.d.ts","./node_modules/undici-types/global-origin.d.ts","./node_modules/undici-types/pool-stats.d.ts","./node_modules/undici-types/pool.d.ts","./node_modules/undici-types/handlers.d.ts","./node_modules/undici-types/balanced-pool.d.ts","./node_modules/undici-types/h2c-client.d.ts","./node_modules/undici-types/agent.d.ts","./node_modules/undici-types/mock-interceptor.d.ts","./node_modules/undici-types/mock-call-history.d.ts","./node_modules/undici-types/mock-agent.d.ts","./node_modules/undici-types/mock-client.d.ts","./node_modules/undici-types/mock-pool.d.ts","./node_modules/undici-types/snapshot-agent.d.ts","./node_modules/undici-types/mock-errors.d.ts","./node_modules/undici-types/proxy-agent.d.ts","./node_modules/undici-types/env-http-proxy-agent.d.ts","./node_modules/undici-types/retry-handler.d.ts","./node_modules/undici-types/retry-agent.d.ts","./node_modules/undici-types/api.d.ts","./node_modules/undici-types/cache-interceptor.d.ts","./node_modules/undici-types/interceptors.d.ts","./node_modules/undici-types/util.d.ts","./node_modules/undici-types/cookies.d.ts","./node_modules/undici-types/patch.d.ts","./node_modules/undici-types/websocket.d.ts","./node_modules/undici-types/eventsource.d.ts","./node_modules/undici-types/diagnostics-channel.d.ts","./node_modules/undici-types/content-type.d.ts","./node_modules/undici-types/cache.d.ts","./node_modules/undici-types/index.d.ts","./node_modules/@types/node/web-globals/fetch.d.ts","./node_modules/@types/node/web-globals/navigator.d.ts","./node_modules/@types/node/web-globals/storage.d.ts","./node_modules/@types/node/web-globals/streams.d.ts","./node_modules/@types/node/assert.d.ts","./node_modules/@types/node/assert/strict.d.ts","./node_modules/@types/node/async_hooks.d.ts","./node_modules/@types/node/buffer.d.ts","./node_modules/@types/node/child_process.d.ts","./node_modules/@types/node/cluster.d.ts","./node_modules/@types/node/console.d.ts","./node_modules/@types/node/constants.d.ts","./node_modules/@types/node/crypto.d.ts","./node_modules/@types/node/dgram.d.ts","./node_modules/@types/node/diagnostics_channel.d.ts","./node_modules/@types/node/dns.d.ts","./node_modules/@types/node/dns/promises.d.ts","./node_modules/@types/node/domain.d.ts","./node_modules/@types/node/events.d.ts","./node_modules/@types/node/fs.d.ts","./node_modules/@types/node/fs/promises.d.ts","./node_modules/@types/node/http.d.ts","./node_modules/@types/node/http2.d.ts","./node_modules/@types/node/https.d.ts","./node_modules/@types/node/inspector.d.ts","./node_modules/@types/node/inspector.generated.d.ts","./node_modules/@types/node/module.d.ts","./node_modules/@types/node/net.d.ts","./node_modules/@types/node/os.d.ts","./node_modules/@types/node/path.d.ts","./node_modules/@types/node/perf_hooks.d.ts","./node_modules/@types/node/process.d.ts","./node_modules/@types/node/punycode.d.ts","./node_modules/@types/node/querystring.d.ts","./node_modules/@types/node/readline.d.ts","./node_modules/@types/node/readline/promises.d.ts","./node_modules/@types/node/repl.d.ts","./node_modules/@types/node/sea.d.ts","./node_modules/@types/node/sqlite.d.ts","./node_modules/@types/node/stream.d.ts","./node_modules/@types/node/stream/promises.d.ts","./node_modules/@types/node/stream/consumers.d.ts","./node_modules/@types/node/stream/web.d.ts","./node_modules/@types/node/string_decoder.d.ts","./node_modules/@types/node/test.d.ts","./node_modules/@types/node/timers.d.ts","./node_modules/@types/node/timers/promises.d.ts","./node_modules/@types/node/tls.d.ts","./node_modules/@types/node/trace_events.d.ts","./node_modules/@types/node/tty.d.ts","./node_modules/@types/node/url.d.ts","./node_modules/@types/node/util.d.ts","./node_modules/@types/node/v8.d.ts","./node_modules/@types/node/vm.d.ts","./node_modules/@types/node/wasi.d.ts","./node_modules/@types/node/worker_threads.d.ts","./node_modules/@types/node/zlib.d.ts","./node_modules/@types/node/index.d.ts","./node_modules/@types/react-dom/index.d.ts"],"fileIdsList":[[52,53,438,492,509,510],[52,53,253,255,256,406,408,409,410,412,413,438,492,509,510],[52,53,253,257,406,407,408,415,438,492,509,510],[52,53,253,256,406,408,409,411,412,438,492,509,510],[52,53,408,410,414,438,492,509,510],[52,53,407,438,492,509,510],[52,53,255,256,407,408,419,420,438,492,509,510],[52,53,256,422,438,492,509,510],[52,53,255,438,492,509,510],[52,53,250,253,254,438,492,509,510],[52,53,252,253,254,438,492,509,510],[52,53,250,254,438,492,509,510],[52,53,252,438,492,509,510],[53,250,252,253,254,255,256,257,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,438,492,509,510],[52,53,250,251,438,492,509,510],[52,53,253,257,406,407,408,409,438,492,509,510],[52,53,257,406,407,438,492,509,510],[52,53,253,407,408,409,414,419,438,492,509,510],[52,53,153,407,438,492,509,510],[53,405,438,492,509,510],[53,438,492,509,510],[53,71,79,88,99,153,249,438,492,509,510],[53,88,250,438,492,509,510],[53,406,438,492,509,510],[248,438,492,509,510],[154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,438,492,509,510],[73,154,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,155,156,157,158,159,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,155,156,157,158,159,160,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,154,156,157,158,159,160,161,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,155,156,157,158,159,160,161,162,163,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,155,156,157,158,159,160,161,162,164,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,172,173,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,172,173,174,175,176,177,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,182,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,182,183,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,186,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,188,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,188,189,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,188,189,190,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,188,189,190,191,192,193,194,195,196,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,154,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,182,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[400,401,402,403,404,438,492,509,510],[258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,163,182,258,259,260,269,270,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,271,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,271,272,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,271,272,273,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,271,272,273,274,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,182,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,271,272,273,274,275,276,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,271,272,273,274,275,276,277,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,271,272,273,274,275,276,277,278,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,258,259,260,272,273,274,275,276,277,278,279,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,163,268,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,282,283,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,261,438,492,509,510],[73,163,182,258,262,263,264,265,268,269,271,438,492,509,510],[73,258,262,263,266,438,492,509,510],[73,182,258,262,263,264,266,267,269,271,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,182,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,267,272,273,274,275,276,277,278,279,280,281,283,284,285,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,268,272,273,274,275,276,277,278,279,280,281,283,284,285,286,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,268,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,268,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,268,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,268,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,268,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,268,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,271,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,268,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,268,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,268,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,268,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,271,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,268,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,268,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,182,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,258,259,260,262,263,264,266,267,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,268,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,268,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,182,267,268,271,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,269,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,271,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,271,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,271,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,271,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,269,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,269,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,269,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,269,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,269,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,271,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,269,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,269,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,269,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,269,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,271,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,182,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,267,269,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,269,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,267,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,182,186,271,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,265,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,265,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,270,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,271,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,182,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,271,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,270,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,270,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,268,271,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,268,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,268,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,268,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,269,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,271,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,182,271,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,380,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,266,267,376,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,380,381,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,380,381,382,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,380,381,382,383,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,380,381,382,383,384,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,380,381,382,383,384,385,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,380,381,382,383,384,385,386,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,380,381,382,383,384,385,386,387,388,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,390,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,438,492,509,510],[74,264,266,268,303,438,492,509,510],[400,438,492,509,510],[73,74,75,76,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[74,76,438,492,509,510],[438,492,509,510],[76,77,78,438,492,509,510],[71,88,89,438,492,509,510],[71,438,492,509,510],[71,89,438,492,509,510],[89,90,91,92,93,94,95,96,97,98,438,492,509,510],[71,88,438,492,509,510],[81,82,83,84,85,86,87,438,492,509,510],[74,438,492,509,510],[80,81,438,492,509,510],[74,81,438,492,509,510],[54,55,56,57,58,60,61,62,63,64,65,66,67,68,69,73,438,492,509,510],[61,66,438,492,509,510],[61,438,492,509,510],[66,67,68,438,492,509,510],[54,55,438,492,509,510],[54,56,57,58,59,438,492,509,510],[54,55,56,57,58,60,61,62,63,64,65,438,492,509,510],[69,70,71,72,438,492,509,510],[152,438,492,509,510],[100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,438,492,509,510],[73,75,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,134,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,135,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,136,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,137,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,138,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,139,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,140,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,141,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,145,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,146,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,147,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,148,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,149,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,150,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,151,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[73,75,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,134,135,136,137,138,139,140,141,145,146,147,148,149,150,156,157,158,159,160,161,162,164,165,166,167,168,169,170,171,173,174,175,176,177,178,179,180,181,183,184,185,187,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,259,260,272,273,274,275,276,277,278,279,280,281,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,372,373,374,375,377,378,379,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,438,492,509,510],[428,438,492,509,510],[428,429,430,431,432,438,492,509,510],[428,430,438,492,509,510],[438,489,490,492,509,510],[438,491,492,509,510],[492,509,510],[438,492,497,509,510,527],[438,492,493,498,503,509,510,512,524,535],[438,492,493,494,503,509,510,512],[438,492,495,509,510,536],[438,492,496,497,504,509,510,513],[438,492,497,509,510,524,532],[438,492,498,500,503,509,510,512],[438,491,492,499,509,510],[438,492,500,501,509,510],[438,492,502,503,509,510],[438,491,492,503,509,510],[438,492,503,504,505,509,510,524,535],[438,492,503,504,505,509,510,519,524,527],[438,484,492,500,503,506,509,510,512,524,535],[438,492,503,504,506,507,509,510,512,524,532,535],[438,492,506,508,509,510,524,532,535],[436,437,438,439,440,441,442,443,485,486,487,488,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,541],[438,492,503,509,510],[438,492,509,510,511,535],[438,492,500,503,509,510,512,524],[438,492,509,510,513],[438,492,509,510,514],[438,491,492,509,510,515],[438,489,490,491,492,493,494,495,496,497,498,499,500,501,502,503,504,505,506,507,508,509,510,511,512,513,514,515,516,517,518,519,520,521,522,523,524,525,526,527,528,529,530,531,532,533,534,535,536,537,538,539,540,541],[438,492,509,510,517],[438,492,509,510,518],[438,492,503,509,510,519,520],[438,492,509,510,519,521,536,538],[438,492,503,509,510,524,525,527],[438,492,509,510,526,527],[438,492,509,510,524,525],[438,492,509,510,527],[438,492,509,510,528],[438,489,492,509,510,524,529],[438,492,503,509,510,530,531],[438,492,509,510,530,531],[438,492,497,509,510,512,524,532],[438,492,509,510,533],[438,492,509,510,512,534],[438,492,506,509,510,518,535],[438,492,497,509,510,536],[438,492,509,510,524,537],[438,492,509,510,511,538],[438,492,509,510,539],[438,492,497,509,510],[438,484,492,509,510],[438,492,509,510,540],[438,484,492,503,505,509,510,515,524,527,535,537,538,540],[438,492,509,510,524,541],[52,438,492,509,510],[50,51,438,492,509,510],[438,450,453,456,457,492,509,510,535],[438,453,492,509,510,524,535],[438,453,457,492,509,510,535],[438,492,509,510,524],[438,447,492,509,510],[438,451,492,509,510],[438,449,450,453,492,509,510,535],[438,492,509,510,512,532],[438,492,509,510,542],[438,447,492,509,510,542],[438,449,453,492,509,510,512,535],[438,444,445,446,448,452,492,503,509,510,524,535],[438,453,461,469,492,509,510],[438,445,451,492,509,510],[438,453,478,479,492,509,510],[438,445,448,453,492,509,510,527,535,542],[438,453,492,509,510],[438,449,453,492,509,510,535],[438,444,492,509,510],[438,447,448,449,451,452,453,454,455,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,479,480,481,482,483,492,509,510],[438,453,471,474,492,500,509,510],[438,453,461,462,463,492,509,510],[438,451,453,462,464,492,509,510],[438,452,492,509,510],[438,445,447,453,492,509,510],[438,453,457,462,464,492,509,510],[438,457,492,509,510],[438,451,453,456,492,509,510,535],[438,445,449,453,461,492,509,510],[438,453,471,492,509,510],[438,464,492,509,510],[438,447,453,478,492,509,510,527,540,542]],"fileInfos":[{"version":"c430d44666289dae81f30fa7b2edebf186ecc91a2d4c71266ea6ae76388792e1","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"080941d9f9ff9307f7e27a83bcd888b7c8270716c39af943532438932ec1d0b9","affectsGlobalScope":true,"impliedFormat":1},{"version":"2e80ee7a49e8ac312cc11b77f1475804bee36b3b2bc896bead8b6e1266befb43","affectsGlobalScope":true,"impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb0f136d372979348d59b3f5020b4cdb81b5504192b1cacff5d1fbba29378aa1","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a680117f487a4d2f30ea46f1b4b7f58bef1480456e18ba53ee85c2746eeca012","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"51ad4c928303041605b4d7ae32e0c1ee387d43a24cd6f1ebf4a2699e1076d4fa","affectsGlobalScope":true,"impliedFormat":1},{"version":"196cb558a13d4533a5163286f30b0509ce0210e4b316c56c38d4c0fd2fb38405","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"170d4db14678c68178ee8a3d5a990d5afb759ecb6ec44dbd885c50f6da6204f6","affectsGlobalScope":true,"impliedFormat":1},{"version":"8a8eb4ebffd85e589a1cc7c178e291626c359543403d58c9cd22b81fab5b1fb9","impliedFormat":1},{"version":"0ff1b165090b491f5e1407ae680b9a0bc3806dc56827ec85f93c57390491e732","impliedFormat":1},{"version":"42c169fb8c2d42f4f668c624a9a11e719d5d07dacbebb63cbcf7ef365b0a75b3","impliedFormat":1},{"version":"ea72cc9550b89d2fd7b8ac2ab4a6ad5b179bf897de7859bba0dc7a934bbca734","impliedFormat":99},{"version":"aa45d08c94931e0b7a9a4c418b33ab895aaf240e192839b36866ad84198c062a","impliedFormat":99},{"version":"dbddbfd48c1d54d619891c895f6e8ff16d30717f4a0952e701387e8040d99f85","impliedFormat":99},{"version":"3361e3db8cb33aa91beaf33b3c79c108f2410e6414498e79d2c7da1838fdfc4d","impliedFormat":99},{"version":"4d54ec33bb701c533741e8abc4233d5f378805166d3a5999d234ae189702d93f","impliedFormat":99},{"version":"f1eed69ccd2798f31d0996306c51d648e19e6e09088f9a7f57c3dcb4367cef51","impliedFormat":99},{"version":"da276fcfe4fb73d74245eee5d1dfb7776bd450d77c591f6e03b54d60be5299b4","impliedFormat":99},{"version":"b402b88cf99c4dc208e5fd337e198e9ee703f48b239dbc8d08ec3b6389e5b55b","impliedFormat":99},{"version":"6f99fbd5ea27a199f84fbc41105525d207d8c6838d62babcbe12e5be0c4a0271","impliedFormat":99},{"version":"528939385e62838eb5631e339475ba93c2ce3ba7e3819cacd42d8ba9adfe5025","impliedFormat":99},{"version":"ef7d56a3fff2aa6476c694027c4844905d40ecc7e8b775dd8743dfd8378353fe","impliedFormat":99},{"version":"3894b5833c452b46d1c59f7d58a8c45e55bcc75a0248af65e1c9c9dd88afeac7","impliedFormat":99},{"version":"1ef2ed1e48da7d651f705bc0131d1028725841d4a97652ef0905367360ba3f73","impliedFormat":99},{"version":"47c221ec0b8802eb5887d6a1be6d7a33ddcd10116185a15c36803e0ae1c0539c","impliedFormat":99},{"version":"0d42fe6c9f1fab8c308ab1ec0ec2ad814a1bd2fb685e2f12cabc0c7732c089b9","impliedFormat":99},{"version":"74967284243720aad05a852617f2891ae384d7a6470c824169a351ad31cab9fb","impliedFormat":99},{"version":"76af14c3cce62da183aaf30375e3a4613109d16c7f16d30702f16d625a95e62c","impliedFormat":99},{"version":"19bc69921209ad7269f886c69e5f812499e133ce318e1aa5d53ac82427c1a477","impliedFormat":99},{"version":"31c17a52735cb1f6cc5a4c452857f568341f95424f07fdb5ee2fbcd6a4a4c094","impliedFormat":99},{"version":"06b419067158787fe33af288531a1df891b452a11e485896bded780b2ef70732","impliedFormat":99},{"version":"44c976b666ef022c74dc1405abb2b167346f9b8ebed3ab4bd9464711c8caa1f5","impliedFormat":99},{"version":"8e52008b516a7a7301f9d43884dc899019695eab471312b72be8a72f89850327","impliedFormat":99},{"version":"f47d865499c8b58d931d7f16e4432c69a3501cb324ead037804e8f292ff195a3","impliedFormat":99},{"version":"1e2f699820214b98d8d16c57137c7adb04b13f3ac573b4f0bbe7b7a601d09495","impliedFormat":99},{"version":"3fc902025baa4cbc0b4648466ac6be6117dc4b0e5b56d245d959839e58fdca8f","impliedFormat":99},{"version":"8ca7d6aee90a5a1d40d356c70c8d5b0ca55ab31a3d17ba73ffb51604674c48f4","impliedFormat":99},{"version":"8de5552b84830fba2143c18d43ebfc3c1289c67402c51a378c32daa7ff7adf32","impliedFormat":99},{"version":"651b59286248bd10267c630f728172866ae427f4036372bcd63f1502532454f8","impliedFormat":99},{"version":"1be150449268e28edc1a1d31acb2b9fa030aee87897a41856d50ddccc124ea53","impliedFormat":99},{"version":"ae0bff9b2245fc399295d0572519a2833ff1a47550b7fdddf96e648eca5271ea","impliedFormat":99},{"version":"0b903757cdc9fe17029ff023c454ae06941499fbf9ae0f733c5e7314555797aa","impliedFormat":99},{"version":"f7ff68ca4ababc2bea9fe21a476be0f6096b8f9f54d34f3408f921850b770e24","impliedFormat":99},{"version":"fa689046e96fc6bd92d2f6edcdb9c0c45efedcfe23443ae1fd4a470bf6e9eda3","impliedFormat":99},{"version":"cb54ec232cad4e0c94cebfd4f560de0907e65c1b55b62a7c1063ab73fe2b014d","impliedFormat":99},{"version":"39f0d3b66804b002c2f462c9ee61bfca709b607559893cccb4ade202f01028d6","impliedFormat":99},{"version":"1f0316a5da01034b17aed99fdd5ec8fe805bb65c5181587c8da353e7c1c31466","impliedFormat":99},{"version":"56442d4cc6dbee39651e056fa1497720913f1f801791b84e50e892cfbe078bd4","impliedFormat":99},{"version":"03cd861598cd715ca2bac8148c04a5f0ed2d21e90bf8db13de771be632f28c66","impliedFormat":99},{"version":"bd1578e4ca78d8de0d3dc05f95d147e45b4dfda47186ce874b3c0d7539e2098f","impliedFormat":99},{"version":"735c117db157cdfd07b4a18b777995e5ce23e535f49cbb12f5fd2c9111c5db18","impliedFormat":99},{"version":"303e57dc66fb6f7e6a79344e5135d48c73ed024cb311d2babf4df5b89fbcf3c8","impliedFormat":99},{"version":"d334f6d54e3907bf5a76f95119c4cc3f91220e96eb113487062d416c3bb70667","impliedFormat":99},{"version":"41178e3f5b546481e0a44eb7aaee78751843dffd525360d953550e8704880445","impliedFormat":99},{"version":"6d0cffb06c980b1ded7ed62302284696b2e9c88ed2608a36acee3ae30cebf88c","impliedFormat":99},{"version":"c57d47d923b6851e8880b395d0935d0b3bccc5c3691e7ce33abb247195b262ba","impliedFormat":99},{"version":"aedbbff1a84bb4cc113b3aa603afd19ea5a53e505744f971b715c412dae0505d","impliedFormat":99},{"version":"e04ad05711a15421294f32c07c87f23a99e792e44a2109700cec6e031038e5a8","impliedFormat":99},{"version":"05b4b78a0fe3f591b9f46700396ec760bf4785c238f8a27cbf78037357615994","impliedFormat":99},{"version":"54469d80797325cac80ddf053a12afe121953b9f327a3865925c1ea5fedc1e04","impliedFormat":99},{"version":"8ac43b3a5564c1b963aa0598ce3fe1d2b5673f220a2d0900a05cc03a2098433c","impliedFormat":99},{"version":"9555fc148c875680bb94cf7afd8c96cb6bd39575833f4d57755a3b8e3639937e","impliedFormat":99},{"version":"2dd5d9fe6995942adf82fff82e624e5aac2965a605587cc777c852981670f7c7","impliedFormat":99},{"version":"09ded16b94109529ea27304a7292084332eea0fec7960361650feaa57f738763","impliedFormat":99},{"version":"89bfc04207450b25e880200f4b1548391b539fc60bc2f2945fc0edfb23e23634","impliedFormat":99},{"version":"7c9600f96f56cb5356fb26046a60d5ea86f4e3a48709d316244395a8ca007029","impliedFormat":99},{"version":"8b10bff76988431e8f68b2a0dbb79df3ee0331753c4fac29b40ab62801f2aa06","impliedFormat":99},{"version":"724ce9a87bbacc89ff4ab317df599f77a55ee6545d76e056d8b36bb55f24c58b","impliedFormat":99},{"version":"79ddbd060c4878d83b491a4f8469794c8184f59ec9d1b022bc5b14c29215f590","impliedFormat":99},{"version":"c80b21e0bc14336675fe80924a468b9ecbda995c0b4705988f53c38dddf41922","impliedFormat":99},{"version":"aefa7fd02617fd165f8f06e921b8c0d8e60867af6634a622ddd017c158c5a505","impliedFormat":99},{"version":"bab81fad10b35ea3ec3886895b7b2e44716d7c73e009b1b3c6aabcff8dd28b42","impliedFormat":99},{"version":"78c2b0c973739c69dc21745ccb2c8dfaabd0bc97f27675a11eec5ddcb44f04e2","impliedFormat":99},{"version":"8883a6e862b5f07b07fccf8a0100ca73d35a2117fa2656d4368fbe089dc45ad5","impliedFormat":99},{"version":"9262edf59574bb4b69221a2289c08e9d8d9b83f51ac9838191dc43c176e26312","impliedFormat":99},{"version":"8f3e70c49f9abb6115f25ad78fc1d65edaa463f2d6d5a5a1554cc83bae5fb284","impliedFormat":99},{"version":"17aa7e05470aee99f362246e3b2fbccb3833d155b103bc85fcf3cd0166e8385d","impliedFormat":99},{"version":"c47eedce9426b4a330be6cc94f31ab0430557bf3d66b2f6fdaa8bc2a9fe3dc63","impliedFormat":99},{"version":"8fc134de25055444c3f7cf24895245a20009342b7d27fefe046a23f06050775d","impliedFormat":99},{"version":"5f291db565a8a521639a3f6414c1d7484b1692ced3fab25d5f6d9c7622412239","impliedFormat":99},{"version":"9d97d4c094e8fb4a39dc3c9c61a5ab3750df7f640f10d7cc1f0cc95254867a46","impliedFormat":99},{"version":"13b381b958471357ea0e5d55331fe8da40ef6dd444c765620f5ac6ed8604fea5","impliedFormat":99},{"version":"c7b04352ef5338a362cb852b254bcef5fd9f299611830722ca96bef2272a727d","impliedFormat":99},{"version":"5b7cc254748cfad68a29f1708899c3c053ab74088d08ab4a55488eb2a2a6ffc3","impliedFormat":99},{"version":"32d7684d69e6fb0d6b0b9526c81791c866e379d890969248ec033b76014e5ae3","impliedFormat":99},{"version":"3004fd440a0ce893bde0047ded249354f17fc5bf5f0e18cb443ad5875ce624af","impliedFormat":99},{"version":"616bd5a947e0f6c9b3b1115ff93e6bf6bde37f0f8874ad22ce1b94972210ecbb","impliedFormat":99},{"version":"e93070a564ab221196230b074e5316c1780fd97e32d134984662d77686a03da0","impliedFormat":99},{"version":"f14fb34a1756869066dcf0101061dc28a3125165a19033870b99da489aef7b8a","impliedFormat":99},{"version":"d8c6ddb39e8570cfe28b4bff78b60c3b0f8989b18f1cff11b65b3bce72cc8b7b","impliedFormat":99},{"version":"bc676aee1c0487b866e6c4879c44b4022726bd4aabdda10d8a869bfff2fc4fd1","impliedFormat":99},{"version":"94fdd74bb75c869bb49cff84e2cc0d96847e54550d07f190e6aa2f66f48df3cd","impliedFormat":99},{"version":"df87131c4e90121f3735d75f8687fd6593a2cf532f584f1c007929b2a30a5f9b","impliedFormat":99},{"version":"ede4c4fa5909299b5ef08f59bdca60f233b267dbd1cba1dad89977aca2d2a832","impliedFormat":99},{"version":"64e5054bb3a621b29863c2af6682d288c14635b2d14ffb5b446a17a63b88dd87","impliedFormat":99},{"version":"bb1fb4df5b57dd20edc2b411f0b0149f15ab5a106cdc8a953b4209f645034785","impliedFormat":99},{"version":"060c85a4fc9199e1f44449c4496e50da8803b007aa3fdd20f2285978060c33c0","impliedFormat":99},{"version":"0acc2626aeba6dec96b73ec578bc3bc823af3fce72c12c5309ac1863604c076b","impliedFormat":99},{"version":"9a761443a08143aab9c4de9693e72f6d8d23247186eb8889bcd10393dc3532c0","impliedFormat":99},{"version":"da1417971dd43589cf2f64e5f39da372a9413bbdaf4fc535b0a3bb132b1657e3","impliedFormat":99},{"version":"8889a09c6af3130c89f3447054fa5460754471e0a1f98a527e71fdfde899cb2f","impliedFormat":99},{"version":"ba77a7192b018f6e461de533baed7b4c7e574d708bb65217c42201c2ed10abfb","impliedFormat":99},{"version":"78ac78b6372510eeba34d59c12baf2f2d3e711b466161dce30d73c935340a8f7","impliedFormat":99},{"version":"a8d4f94ba30bf367db014cbef8d6ece4cb664e69aeba758567acb8c02b0bfe2c","impliedFormat":99},{"version":"8f489b6a9e3d21271875f468482bc0418341e23a0688734c3ee7e6b9ff74d7c4","impliedFormat":99},{"version":"787633e9a13f49fe7403439b33388a99637c899236a6cfbf381a063cdbe92542","impliedFormat":99},{"version":"e78023dc028d670a73c72661acbed753764a505e2f464d9d7e118046508c26bb","impliedFormat":99},{"version":"b0486c6fe4f9e68f2105cabed1c388aaf94c06774305d712013fdb5043e46bb7","impliedFormat":99},{"version":"b617febcd2b87748a5896415458836838cc7a047c9ba3c1f93e145ba972117bc","impliedFormat":99},{"version":"c2ed7a65f90e182168b8946ec12ff5aec58c10e9927b04745875843c0568846f","impliedFormat":99},{"version":"e4813e26203d7c6caee2675461cb8694d0a5a2a692fe955b3becdffb1b229726","impliedFormat":99},{"version":"90740a4740eb94a7cfa4c346de4ce38329d161423444f13d86153ad503571cc8","impliedFormat":99},{"version":"f419f04277f873a6c9cddb78465d66a7fc89453768283bc66610f4d563c1fa16","impliedFormat":99},{"version":"85c11e5e250abb4a591509a61e9db2202e7a186cadbd4184d77357f6d768ed1d","impliedFormat":99},{"version":"5fe57966bc656055ea2e4c1657dcc16edc32a08ef87dc30c09671004bdd4cc14","impliedFormat":99},{"version":"ead716385d47a7d5ee147bd5a7fdc0d156c989b4c8806a76f220649c6accde95","impliedFormat":99},{"version":"bc16ae537239eb39d5020afb0958f401befba9d0aa17bb8f895984c6c688569f","impliedFormat":99},{"version":"e551cfaaa5020ea281dbe01991d644059e60cb22b1dcc9634192db9238542723","impliedFormat":99},{"version":"21fc8b8d6387a8a5cc9e62c31fee3c8da8249fb3bc4a8ba79c5092057c892f7d","impliedFormat":99},{"version":"19082f3df1f25f7fb304a911d1a153c9391f464e3001080a524c995e4028a3c4","impliedFormat":99},{"version":"e0f6aafed1acaba5854688e6fdaf8d124383a9282c111b41e22c63f3eb3634ce","impliedFormat":99},{"version":"6562b25cdd9cf562a6d9c614d6294a5b4a5d53013a337b684198672aaa1d61e7","impliedFormat":99},{"version":"3a99f401d0459a24124f6510c9fd84c3ddc94cc9dda88bc092b2c328a2316f10","impliedFormat":99},{"version":"25f8badc9dcd1b4ed1b670442a5cb3bce3855aa2273600123ca82f7105cbd05f","impliedFormat":99},{"version":"df348ecd79b09037176daee7995ddd749a1862a11ed6ac4b0c8a3e7a27cfad27","impliedFormat":99},{"version":"36b1f70dafde83b308cf0d9605fe43900cd340320a5943c79085e39b7ce9c344","impliedFormat":99},{"version":"d5631a56aeb2279698572bf985113de7e1deee43c56cd9dd85aa2be1a41bb998","impliedFormat":99},{"version":"108a85619ed468d15c2f5ea49aa19be365c18a123d2c096cdb682533cafddee5","impliedFormat":99},{"version":"e8e65217abc06cbbd6f5d331cc2fecc278491350423f03ac47aec6978456716b","impliedFormat":99},{"version":"0ae17e04bf71b5eaa46a509bccf6d58cf793a33e39c27077820fb010d4f9521a","impliedFormat":99},{"version":"60d25f66f4b6ef80e0f66f3b2ffbdc88b9ee98d925838d5964fccaa792bb7bc6","impliedFormat":99},{"version":"fce7a2dfbc5f0e8cc50b843e3b4dc606a98832cd6d4a5ebe6ddd054a92dc2597","impliedFormat":99},{"version":"c30274fdea2366b5a293415a6a09124c85b42cc6c02b8d0fc72af5a05351f55e","impliedFormat":99},{"version":"5dd427cc3c26d8e97c7dc0b287e06297717f7a148829fb7fc5875e93bf40956c","impliedFormat":99},{"version":"3abfe64fea01a095950c9f1782ca2ef01ae5391fe5b7fe6443222e5a6adc5d08","impliedFormat":99},{"version":"17a168032c270ec761481e277ac16efeac6530b01870720c17ea6649c9db518b","impliedFormat":99},{"version":"b9e54097ce2e07b1911e42f1c578d9304ca3e2c824f989759bc2199d54e4db0a","impliedFormat":99},{"version":"52256083681cca90fcbf3796937308d94e1c8e3ced04a7974b49ec4209f2ab4f","impliedFormat":99},{"version":"7086e03c6bbd58177835da26104c3124e985afbd9a91b3a148e0cb88fbadcbf0","impliedFormat":99},{"version":"d46dc9978eefe051bc8f6679dc6b6a8be7594247effd2563ac488afee31ce9c7","impliedFormat":99},{"version":"2baba9d417f5388ecf1f2b1a9a58a4b6d4ed7df15509d60de9d7caf1f0043ba1","impliedFormat":99},{"version":"fa412c9f26d7be8ccbbd56ab3f1fad78eb9cf87af63fd8c6fb29dd0450b47622","impliedFormat":99},{"version":"4da7dcbb288a72cb7488728930efa47e46fb3dc042f25aa7d50468f0949bd1a0","impliedFormat":99},{"version":"b0b15e47e8d7e2875b28284ea08678baf6f4dcd420241046fc91743c905d0947","impliedFormat":99},{"version":"7eef51f067c640ef085973e8e13608a0b91c912297514e3264fa6596f328c9fe","impliedFormat":99},{"version":"4afc590f38f8051eec35231e6946ecf2151d7a23ad4e138047b01c800d94d9d0","impliedFormat":99},{"version":"4c42c37e1f02b327024ecb1edf1b5a12e4d45092bc51b405985a791ce32598e0","impliedFormat":99},{"version":"8adbcb728b2d3bd8282e1a657a45f6f9103a7eb43f6fbe36c554bfef17df9656","impliedFormat":99},{"version":"ae061bc7af2f9ea15a742b07e471c27fc4d82e2b940509f9e7da3f129595e03e","impliedFormat":99},{"version":"d15f78dca6c2afbdd2596cb17983fc60a79d95dc0142408d224d671f8b6564dc","impliedFormat":99},{"version":"2307f448951cae8a6b9bf7b09c114369e42d590c53fb99c99fb1cc34ead0f0dc","impliedFormat":99},{"version":"71ceec981852d2a8b0fb281799199344a6ec90aa55e13302916f38b48debd10a","impliedFormat":99},{"version":"5c943d5009f2f31841d04d8ba9e853a13201a9e81fb96234c90191f00a50a713","impliedFormat":99},{"version":"cf7f50328f9916c083247e28d938b986a9d9fd60ba956a90ce540ff676e3deff","impliedFormat":99},{"version":"9005e5cc014620c428d72c3333d6430f4be9ab113c7c41400ea4babe458907fb","impliedFormat":99},{"version":"5040c1eb043d900faf3cbc181831b7aefda2fa75bc08cac59897baefe2666e43","impliedFormat":99},{"version":"83e5ae91867c4b4d94ef5c43b9652401642b80f3a4b86af579390dc2fa97ed10","impliedFormat":99},{"version":"b87b16115bb301284968c766678ee98ab1c2276f1bc4e437945db172718a22b3","impliedFormat":99},{"version":"ec78470f53dc3905513b87992cae127a1d5b793ea42cd48c8ff809ebf576f19a","impliedFormat":99},{"version":"a22df7d38217bf9917cd51c7df7da7965d6a5f57b56b5e612f48ecb34a693c1e","impliedFormat":99},{"version":"df740e512060283334dc9f4d608bb7ddf9097b6e1613dd2b3145d1455bc4f73d","impliedFormat":99},{"version":"b7eea3116456adebb14baa549db35cd82759bdf2f5b161e8ba12768e634b10e8","impliedFormat":99},{"version":"930612d51e2a0cb1402f15a758d8bd025ee29b4c47a13d038faa3fc8ee16e3ba","impliedFormat":99},{"version":"da4d4b60a3c4a12f155b1ca908ff6500c81262168dd39bf6b7f2a632661beb4a","impliedFormat":99},{"version":"1c7a163091d67b9af010e10f5c43ceccde78320486d2901053b4d5af2b751b2a","impliedFormat":99},{"version":"6fb3541ebbb5e2a930fea38603d4c0cbfb4dfbbb7df8999396a8a90939131ef1","impliedFormat":99},{"version":"545dc958d8101a8e3c9932370a7b6c2f8599df0cd53449114fadd7f59fa9d6f6","impliedFormat":99},{"version":"cc8b39d1f46ad8e39ebbc27d5664594a82625199459a9ddbe54ef17b4239ce24","impliedFormat":99},{"version":"08c3b01490d49ce93d06bcb7593ef9ad02dc2d91cd583eb9cd0f3d2fa75e440a","impliedFormat":99},{"version":"6ba19623201e7dda0bda2eb91bc7d1ee6ed719be167f999564a42ad8535e2f9b","impliedFormat":99},{"version":"482f77de2d4972e66c7c6a3aa53b524e20eca97cdaa3220cd2ab7acd3a7a54f3","impliedFormat":99},{"version":"634708acac0aa7d170f03a37a9d8cf6a9febefad220477649f6ec3e1ac1f7adc","impliedFormat":99},{"version":"89b2f499dba3c24fdb44acef871860328553cc46a4802874e17de01d530056f8","impliedFormat":99},{"version":"0288e5f29c1d2b678afce4d682a7ce94c323b86c479f28a4a33928261a5fe4ef","impliedFormat":99},{"version":"4e0c84783c17101df536fa4018dad2c210ba3a41daca0c1df4957f7e8dbabbaf","impliedFormat":99},{"version":"bf17c4d237818052f7f3bdd00fa2433e5ee151e1dbbaa1700edd2d229bacfb03","impliedFormat":99},{"version":"862052995b61cdf46e9fdf9b83acb076975dcfe2f44e45c07b23ffa70f9dde0a","impliedFormat":99},{"version":"8a85e856fe6d7a45e4acac5406bf440ec274ac46171d08567d38a7ff36796c3b","impliedFormat":99},{"version":"b48976ad99fc88001f7c2757d84a6bcc5e8830f7e95fb3c73d774e7710b51aa0","impliedFormat":99},{"version":"40ec8dd574cfdd80de30ba61a0dda32c83d6b60b783ddd5c9afe21187a8b0353","impliedFormat":99},{"version":"4ef67ffb70b66a188eb391c50965ce59a997e5995a060cb0eb803e7937f80cc1","impliedFormat":99},{"version":"bd3f53621504b6b6fb460130652d71bedc7b48c4fe26e81a62f9976de519700a","impliedFormat":99},{"version":"1a94fffe1807952952587e8d392df98582a90f034abdce57217cdf8409a0a16d","impliedFormat":99},{"version":"b7b4608cddbb582012556d2016b1704bb77c9b320770cbde8b98ebbaccdc6056","impliedFormat":99},{"version":"7ff126c2720906e2edc4917be8a00ff52597dd050a0ba8deb82ae1dfff440432","impliedFormat":99},{"version":"53aaccfcf252817f557afc4e9aa18084dcc90e5c096411b9f60b6b7de4fcc41c","impliedFormat":99},{"version":"a7f0bf6a7172f6c4a33877693190c8dca6b5ca0bf0deb5130bfad368b61e16c8","impliedFormat":99},{"version":"fe428bc5c0d6ce416defb7a7e67fa6a10b182b7ee2c16b42419f9538cac0fe10","impliedFormat":99},{"version":"5f19171239190089286ae47ff6d0c9d6fd2b29342dfd0acf6cc6f66f9d1bb4d5","impliedFormat":99},{"version":"d2a502e2c30b775339bfea8c1d51d3dd5244980a3cd5063ba12227cfe03fef44","impliedFormat":99},{"version":"a64913d689476c4743b020c801672718d1a736ab243907396312b832b65cbdc4","impliedFormat":99},{"version":"2d7bd36015925a348793ebfbc2e2a1fbd390bf335be8b9ec780696ed6dde26d4","impliedFormat":99},{"version":"336e86ff9f1abe22105776c7e757e9580446aac47cf8429ca78e6ce980f284e9","impliedFormat":99},{"version":"1416b07f727c918e532f4134a45e3b07b0a116d9def6d9d347a00c50dc01060e","impliedFormat":99},{"version":"a44330e93e4a7f8759a73736215eef4590b74b3421d955d980ba3db8e6b5a7fe","impliedFormat":99},{"version":"ac84b7a6fdece6cbb0ee141a09b505890c3f11c83446f6304ab9d8e972eee60b","impliedFormat":99},{"version":"97ce0d7c831f1fa7934651c878f1af14090ba5d9ee471db035f465a7dc113202","impliedFormat":99},{"version":"cbcc2f6b5fa06c91e2a35cec35066fd14dacccf185dc8c64c5143381bc2d4b30","impliedFormat":99},{"version":"02bfa3730c6288cac5928a0fb08f01f8c236992b0ef57806c478f0f7bdb6eb83","impliedFormat":99},{"version":"5af40b9066886960f300ad8efd6dd8f77eddeb475903989841cf0385a1edf4c7","impliedFormat":99},{"version":"09d52052be4f3e0f4c8fd5d4954cb215a96e20bf6fade80f95706fbdd5cee318","impliedFormat":99},{"version":"f61822dc28d52652fd897fa846364a0c6e2f9d18c4488c104f4887b4627b3fb4","impliedFormat":99},{"version":"55a4f8c04961c6cb99a6d2c79a375e4ef107339c3ccfabd8d986f2a177dface2","impliedFormat":99},{"version":"a5433e2b1359ac2672f3dd287d58e0733fe778ef7dd71a4f913b01e794104119","impliedFormat":99},{"version":"19d3750d9f8f570936cea4be2a6feac27e1cb88391d7c54e3209f479019c1bb1","impliedFormat":99},{"version":"acc3dd66b849dbe92d07581baef23754c6bd3d4cc453d6d8f5d52e261304a3bc","impliedFormat":99},{"version":"e4813e26203d7c6caee2675461cb8694d0a5a2a692fe955b3becdffb1b229726","impliedFormat":99},{"version":"46ce3f884a6003b711e911505e2d1f5164cf8afb027c45e97c24959b8b6f23cc","signature":"deb5843390e2b62d099236b5831b18ce3f0acc31db078780c942cc78e0cbf798"},{"version":"d135fc23cbc0d02c33b0f8ed2be7df4311515064ffb370e826cd53b0d8622524","signature":"3651678bdeba3e39d96bcde883de468401f51943e3c7dc3220c4b7be5b0b52bb"},{"version":"246bf4998a6cef47739b4976189abe1afda3f566be0c6efdb3771b619e21dbde","signature":"f283ffd4999bb8027d29a0963b5e9796c80d42b774e452f38c95f2fb00747708"},{"version":"981ac80c705c3344e59e7901a57cefc7266812f5f5f99b10f1a85af715d58d3a","signature":"1f009a3450b7fda74839cda2709909e4954d55e56def759d215f937733eaf3f4"},{"version":"2241423b81ee7d79534911c32b9159d9668c21f63ae52d174e185b1decc538f7","signature":"201d60dd52e618046236c6d3fcbc68b5cc0265267c6e3cf680f414666b21ab44"},{"version":"dd12717c74416659bb5bd8a891daf5df0a93fa1de37d3b3e5814b87c14895f40","signature":"cb74476319bef6005353dc35d4cbbe462085eb62cadd2ea31369f74e946f8a28"},{"version":"80581c53a1991543fe881a3d7d4421ad45273d332bdccd39e0d4a2bfc21a4111","signature":"6d959ed0e5411cbc172b7f49650a5c915996433264be0c5c799449e9499e5bdb"},{"version":"959734acd7d29267ec7e15a4975ac091e0e806c65fe3367c19c791412720bd99","signature":"fb151c164a917f6ada3b9783fbee8518a8ea80695189b66920aa777aa76419af"},{"version":"b06d9380eb2fb5c35f16d03445b1963e8fef5647c592642f5d8dfbb11cebc1d0","impliedFormat":99},{"version":"33e160560eddf2de63ec16a76b8c1d91cba0f5906ff2f29819e07521d6382f6c","impliedFormat":99},{"version":"c35a50ae47731c15c54b6f359590d24776fdd74374bc85031afb800212181af0","impliedFormat":99},{"version":"f34a1a6965c0bbfa374873432849ec319413414ec186261e97ea70d5dc4d4654","impliedFormat":99},{"version":"a3f4b311af4127148f5dbb1a1ea80468a20725f10ae78001a8dada6e4a618696","impliedFormat":99},{"version":"790d03a802369d9a8ff78db3ece0cab418ec75a120dd5ab9aaeeb1c534493d3a","impliedFormat":99},{"version":"2aba871159bc6021308c5f1d05d7917e0c896c7436dcc3619038f381859fbd68","impliedFormat":99},{"version":"adaa0d941bbf9d3f11262c3739579aef70fea7af193718f8fd67e10a771fff8b","impliedFormat":99},{"version":"f178ad620e827581f2baf23c9c7fabb77d36ead92c15e149012934a30151dcf3","impliedFormat":99},{"version":"ef73187b0072b9b148b03acb62dd12615d704589772ce88e2e2e1bbf0255c802","impliedFormat":99},{"version":"417f252d9e1048c6b47d8a8a5a8e7ff5e9a4de37d6d3468152f2e8eb35b88c29","impliedFormat":99},{"version":"f3b2ef02288170cb72b7d412a7cc67dfd85dd24c168b78b77554f1ec515b5701","impliedFormat":99},{"version":"590460ef9a2cf9ab9e34504aba42d6daffe4ff7c347ded7bd8d9a989e0920c3b","impliedFormat":99},{"version":"da45f9cde46eaf3ef2d3135b5354bd3739897d72b406e0f0ec1f5455108580a1","impliedFormat":99},{"version":"cdfaab58a31962eb873192959e14bca891669fa0edfd469c9c35babc36e490a3","impliedFormat":99},{"version":"206d171772d21c82353069668d680a40df7489bde0446fb70f378256ad9d33ff","impliedFormat":99},{"version":"b6104978f6a9921d214c58df950900dc2a9319815a843d354881fd1bad7e62f0","impliedFormat":99},{"version":"1202e02184a9fcfafad7333bfac2da836eaff83653845e00c9495d9c82c9f635","impliedFormat":99},{"version":"6899200d51b7d7491d15521da878142c5fe50d711afe22e60e359f6db6c98088","impliedFormat":99},{"version":"c5e79b84695297cc596924039842c2ab7821470f1c97c4b1aa9d6a7f5f2d2e3f","impliedFormat":99},{"version":"630927db336d1990af0f696dec46f8844c44c507e3a72069f50754541dfcdf5b","impliedFormat":99},{"version":"b4e7867fcdc8d3c7a23b45cd2d705d2dc576a7f7a70156b17aadd7e01f334315","impliedFormat":99},{"version":"c89ac8740afdfc27b2166cad337e716fe843eba690167cbec823bd689f613e6b","impliedFormat":99},{"version":"23c280c11bce285e8f022b0009e083a1bdfc3839f348a38df9dde0c3c571820c","impliedFormat":99},{"version":"dd5be7220598df4a07b6281e01170d0dad5fcd74bcd27daad19619b1fdacc6e0","impliedFormat":99},{"version":"c526474a2770a981d08d9f00644e2a390475b0f9910888d426a6b2e6686b77ec","impliedFormat":99},{"version":"d5cd7c1300ee1f45cc7ef5afef746a1a34c701b94958532a88d265a9f0068063","impliedFormat":99},{"version":"a01c5aaacdd5362cda056105f2acea8b8c4699ce28ccfe641399dd0b49239419","impliedFormat":99},{"version":"6ca50db42bff8c322c4a7449cb09545ff575a1c4bd4fe6d32a9adb563f3fac2b","impliedFormat":99},{"version":"2a45ce8c09f2f343ac47fede405b833cd0ccb325f9b313fd2febfff8ccebd8bd","impliedFormat":99},{"version":"c67e3783cb681d6277dec8ada124cea535c8c7f4d99f5d6f0fed69bca38f3807","impliedFormat":99},{"version":"76ff4e5304fd22a8ebe6cb01ca297feaa0dbe14988ff43746345b55ab3504e19","impliedFormat":99},{"version":"361cb330385d846fbabf3d4db59be3655d45d7c76a483a03c71b0082014f4e9d","impliedFormat":99},{"version":"43b526d382577c18840fb6c10030753b82eb60a377c50233959437dc6493b047","impliedFormat":99},{"version":"7529eb5b698818410c1858e22ddd689fc3fb6f86d54af06872e40423574d15ab","impliedFormat":99},{"version":"3ee6957c2293a69d9f7ff232da8425d396e3115e9ba261a3e532d350e2bebdb0","impliedFormat":99},{"version":"6f70230fab4be1aebb2ef95828669b89dda35280965c55ce88aecaf94848f036","impliedFormat":99},{"version":"8d87cfe48ed90323bac6da16f46aff7fa293e32057cee38d14aab11e9f66e4c5","impliedFormat":99},{"version":"eaa88006a1ba314595330bf47f08eb4a468e7764a1060d6e133183aed7babe13","impliedFormat":99},{"version":"0645cd3e93a26c8a7c16595dc63a169d137f6b58bf50cca98449ea23b333475f","impliedFormat":99},{"version":"1586cdd29126d1a54dee78b46eae7b26c7d473bfd7eaa8bbfc5bf2a76946c545","impliedFormat":99},{"version":"accf489fbfb2dac5d38e71b2fe81687fd44d64b21b5631f6084b9acff57b4d48","impliedFormat":99},{"version":"0c5390e201ce2722d720a82c2105e07606576903e599ed3af15fb8e4e45ea2f4","impliedFormat":99},{"version":"b556cdad15c625405519814fac6ef355484a25c1cc9344e6e5dc110d57a8cdff","impliedFormat":99},{"version":"3e810c39b288e419bc933c293cf5703b948b73bbf07050527c9d73f7107c0c4e","impliedFormat":99},{"version":"9278bac0ed6d0d99fcee6f0f217399ec12edc1d10a9b3c0873c7b97a25223384","impliedFormat":99},{"version":"6f3dccb219fdfb3816c02e9a99d959c853c855c7b7beadecd3a3d3b0a374d953","impliedFormat":99},{"version":"2eeaf63552fd9c5d3ab821464d8f4a5db0de7132331acafafce577f58d871a39","impliedFormat":99},{"version":"9025d4254c18b31d9220e4d33dad5035507ee1e863d1858891e56ffe0eb2ff13","impliedFormat":99},{"version":"001a2571401e839a4b68cec0af11c6188f766ebba01cc1e1895027e3d35030b1","impliedFormat":99},{"version":"846715a4679c9be48434e2b6dfcc466588301a733f51ba0ea15e348fc7312528","impliedFormat":99},{"version":"0b77894d2bbddb9024a230e9d00eb9df633c8d190887f92959d9683a81286c39","impliedFormat":99},{"version":"fe438b40de8ec7fb4a1734f8a3c8315aafcc90dcd15512484e7dcafac310e856","impliedFormat":99},{"version":"96d53f66b4fa3ab1ef688b676450895730863e298e62dc6bc051442195aa1a5f","impliedFormat":99},{"version":"877f538909bb2120565ca0c39e93341e5a4a737bc5fda014c5148c3676fec8df","impliedFormat":99},{"version":"fba10fca31d18ed5fafacb21e2ed389ae5b347b552c5b7a69023a563e27fdf5d","impliedFormat":99},{"version":"600beaefece9011d792a4e165db46b9de5563e025e941aebd069b95cb30e7af5","impliedFormat":99},{"version":"bdc387fdccb98bd48da4cd4cbc8f29342586c2f8ac7215396547442c3b0ff8be","impliedFormat":99},{"version":"7ed291bf246832b2745528de9e68b2bd3e2fe7cdf32631665a326740c3905836","impliedFormat":99},{"version":"e61bc77843da1980c2b6851df589e730bbbdada172986ecb47101974f44aeb5a","impliedFormat":99},{"version":"00d79566e3d5682a968b44aed9eba1557b1f62c884546fee2bca88be8c477104","impliedFormat":99},{"version":"f82d26f23d5e3093ca86458544b54befaf0957a5535149f673976187a60f9e6b","impliedFormat":99},{"version":"9f0d621f43198d0db510779ba65ca3d1a8fbca37f408efa5e25ac5ca01f74875","impliedFormat":99},{"version":"9bc53a206914661c0f98bb869eeda7214778367683a5e3e0fe7c6eaa6c474556","impliedFormat":99},{"version":"71987002d6409ea81e705fbfb97afc644851c16d9fbb5e90fcb3bc3e00e4ac5d","impliedFormat":99},{"version":"70e86eda2938040292fac398debcbe47114a3b9bd6eb8f632a89dcd23ac0e2f0","impliedFormat":99},{"version":"6241345f59b24be6e85c159db51cfd937f853aa8020b38b2aac5345813b25a8d","impliedFormat":99},{"version":"583eb3b56fc84b730641e623070f6eefa3fbacae4e15a6a3f19e1b09c81a7685","impliedFormat":99},{"version":"1c96afc9b678d9f15ec1b045864ea6cff25c134fd594cdddd42d66d99c8663b5","impliedFormat":99},{"version":"cd37c2470a4ac1ad7e1bdbd29bc8953589a4da6a7326a3bfd885bb7b220ffcde","impliedFormat":99},{"version":"ce82368397e5c926481222b9adb2547e4f9e0206982ac71c301284d107e77ebb","impliedFormat":99},{"version":"602a7beeec46d5f481d8f017adc1e01314101dea37f8f9ba3debcf88c83a44d5","impliedFormat":99},{"version":"d4e62d466b6302ad6419cf38669dda1eabe141200b15928a120ec32423904fdb","impliedFormat":99},{"version":"7baac7cf35ef7ef1b049fdfaa215f66891fd677bd617ec7e9a89ca9d430406d1","impliedFormat":99},{"version":"7869a702c21d4fe08180df0919c6365d4662cbdd9e0cbfd17bae7222d10fae58","impliedFormat":99},{"version":"e2944368a3fc08ea1ecde61384f2aea35d8551f02e20373f26f19a1e15f33c01","impliedFormat":99},{"version":"1e13585db16f3406755c1f7a3b32a2003d0b04f83df215fafae61c665de938a1","impliedFormat":99},{"version":"5dbbbf480819904753f84c454eba9bebc455b19966195e97f6b365e7cdcae4b6","impliedFormat":99},{"version":"a96af1a20dbd8aeffb9dc6c2461c7d9d131979390a8b41ca6975f652e2a897a4","impliedFormat":99},{"version":"46f1bf29bd4165fe2bff54eecd23a31f45b1432ab50ba3a0304100697dce91b0","impliedFormat":99},{"version":"1b5cbd26dd659f174a672c6d81b3088c9f46ae0dfd160ce93d2afad5bb7151a6","impliedFormat":99},{"version":"261790ad96cccfe94b94e4825a11a719210f9251d430e05829ed4f0b3d90fe48","impliedFormat":99},{"version":"55eca0dcf8f3192e5906e73aa8c7b88d898b1351bba84c69f4c5c38ab4e43f6f","impliedFormat":99},{"version":"686832a82159a4ea4dd25329c3a99c0a94d9b2a83e7b4ceeb6dfa58bd6707aa6","impliedFormat":99},{"version":"ac339c5b90464b77c2f28dcc686944c9d084f62e680960619f6832471da398ef","impliedFormat":99},{"version":"5090c4c9eb11d488fe455e985891f55e90d65365933d5797b30c188fdbe8015c","impliedFormat":99},{"version":"959c4529d03aebf8f76af7e58797800a25a6a14f560228a69235edcac4e8bfde","impliedFormat":99},{"version":"e893479eb9d99a9c479248a70650f43d3630614ccd0ef07352e208a23988f7cd","impliedFormat":99},{"version":"04d51092411e37e0df07828195cf9e0462861523461eba25eb9dc52344ead7d6","impliedFormat":99},{"version":"a2bf25976a0749263db4e003c2db061217b6e63aaa674f3f2e9dbaeb75f0cf87","impliedFormat":99},{"version":"92bf26f78ac596c9f643b340974854edb633f4719c7d9ad812367883e90272b0","impliedFormat":99},{"version":"afc885e843cf91a18e1c9b674d958c5c71ad3b8d2c9762c6983025d4a30d0918","impliedFormat":99},{"version":"01ff8948288663a825d5d4b5a48fc4dd54adfd4136c00c11d2a01eaf19084340","impliedFormat":99},{"version":"fc61c6168137297ec33f5720835a8f1e7fc424b00e0faab2d24e980dd0bd03c2","impliedFormat":99},{"version":"0b1cdbb2aef2c6ce308de85e80148059f7e16bf727eb3830a2e3e744c4aba6ad","impliedFormat":99},{"version":"1568200178c3ffe44819798eab91cbede3b302ff487149b18aa814a9410645c9","impliedFormat":99},{"version":"3ccf7553bce15ff3fd0b3a0cf4ee9177e9835577aeaeff17c1c6e04a5fa60b4b","impliedFormat":99},{"version":"44182cb6be79f471d6c4a40937a8d6d183af1a87cb26a3bad310c613d006351e","impliedFormat":99},{"version":"261e48dbb899ec4e2de4b9a72b8127a3314d28828b357288bcdebf39be32c126","impliedFormat":99},{"version":"80b3a4c879b86f31611611d628c61546a3924a17609d2abce5af75ab1526bd17","impliedFormat":99},{"version":"69260d8b8cd174b1fa69eb05cad51051da0cb9bad809cf391c1d8234d4b403a6","impliedFormat":99},{"version":"79992568ff244f34b7112942a3d52eb9375885d7e1d8099fc1a17552d14c6fe5","impliedFormat":99},{"version":"dde1fa7a49e820b8801d01bfe9e9b7829d9c62e8eb82a29ef2c28f239aadb5f2","impliedFormat":99},{"version":"e0cd63cf24da521cea60545e5573cbd7eb13d024cca52cc342032e2db987e7b0","impliedFormat":99},{"version":"b1c80011f3a457bbf2e1dec4b6016e63121e60de3b4ff805f261f69016aeada5","impliedFormat":99},{"version":"0bc0511027cff18f7025fdb354850e43083e16d2af2a48da869e095b8df05616","impliedFormat":99},{"version":"70aa4b70c1ebd45e76e4dc63b414d0a7e12fd41ed860da7d9e42737e2a11559b","impliedFormat":99},{"version":"7602bb9744aa13918f0dc9713e4a84e9e97cb099317eaf164c042a636311963d","impliedFormat":99},{"version":"de557ce115571688c6a8dbd486281e4d5a8068ba9c8339ab483014d4aee792a0","impliedFormat":99},{"version":"d942ff22d0bd25a2f26c50d2cc59d6cde2bf7a6cd428e3dd26356033015391ad","impliedFormat":99},{"version":"06e3997ff9c559d21c94113cb949cd03bc44f16cd77c2d7bd42f85c9be29a70f","impliedFormat":99},{"version":"f0029f53c3acc648f4215bc446cd60d92e8c29a8e73cd4008c1e1b37f91eb811","impliedFormat":99},{"version":"b59791581c6df3f62a81a0e96fb3e833a2f5b36304bcb074d765fd79d2fba320","impliedFormat":99},{"version":"627109c27f42261a2148c5758e5529e0694e09ffb74c2cb20e86a7a3682134c5","impliedFormat":99},{"version":"233ab9a64155ad15a070b03a52f8192ace79a29c03a9d4f7cea88929afeb1d45","impliedFormat":99},{"version":"fa7781b202e5845b1609eb84653dfc54189ce4e891909259a9aea73cba9859e9","impliedFormat":99},{"version":"a54b716354950f63c6e8ad298bdc90f94dab416eaecb3d32e9c6dd1bccc79eb0","impliedFormat":99},{"version":"38e6306d5a856a848f6737da319f79b703006b16ced089b2c4e80d04efa58adf","impliedFormat":99},{"version":"0f1434bb4e24cb50e9e73f0144414af44c1610514cb1ba0665936fb4993a3db3","impliedFormat":99},{"version":"1f15564e79f492da5842d1fd5f29cae75d37737e5abb4690b3b4bb9e7e856f3b","impliedFormat":99},{"version":"91d60e5b5441b738133c095fa2d6a809a3c3c4b75556d7f13cc19df48e20de12","impliedFormat":99},{"version":"6beeccd58698b2f72df8cff766e658f4adf98ef39ce1402799d4c18db1b2d803","impliedFormat":99},{"version":"980b920f853e57fd46983d0f5a2e7164f2d2e9dac780aa04d4325aa235c0a75e","impliedFormat":99},{"version":"3a39f3263b853937eca381775fb7558b4867a2714a89d770ea98c30dd1fadaa7","impliedFormat":99},{"version":"ced0b20e13a057c20d802a11870ff310579c6e80a5e5e45166de9e5f0e88f8d3","impliedFormat":99},{"version":"62f73fab1b97e50ee8092499cd5a8b5085abf700b372c24aa53e1879a3d68979","impliedFormat":99},{"version":"a393c298d0678e3e0b610c1069e3721de31dcdf1f885d6ecd813b837330156aa","impliedFormat":99},{"version":"e4784320828932df26b306ec4839c8f9496b959173179a29b29163efe301a7b6","impliedFormat":99},{"version":"5dbb45a20780dd90e28869e05035e681c90afa007364f01c3c3cf14c4cc04467","impliedFormat":99},{"version":"c9e1e15b8ab027dbbe4a2d85c0669905497e0d55a09c702f06c79e57645e347b","impliedFormat":99},{"version":"4078ccf4490cf97463a7ff2f9e02ff30a36ed2e4b18e8566445838d0d4d603a3","impliedFormat":99},{"version":"727d10cd972ba9b52da4defa702f65739323f9ff9949a7e9c7bd55fa76c37ac5","impliedFormat":99},{"version":"9420bd92184bda15c9a04daf532afae98df4fbbb17a930983ca664e929fe6c6a","impliedFormat":99},{"version":"684ad94c713c5f22951e9f433d52786c8508447510005459b6d9764c75cd2c74","impliedFormat":99},{"version":"3e00971f3dcbbe00de774d5387485454c98b8873bb636b8e6bcd4d9915ee0a2d","impliedFormat":99},{"version":"931674e02ae4a041ad822756dd4dbd30236bb3b52e21201aabe678b734baedbf","impliedFormat":99},{"version":"940961ea4bd1da98cef1edca26d6380eeb0c3e06df2e9d7a29dcb57303fb0326","impliedFormat":99},{"version":"581f0278df053736226f58d9a4671e2bdba6508f8be23751247c846e82736a0a","impliedFormat":99},{"version":"ff7eebe9610f96732e29782294ee55529ca5ff804e2325ba992cab0c2ca4c05f","impliedFormat":99},{"version":"e0138d7c2408df5bcc623e3e3b496ffbc405421c7dd7ae6ecf897a657926e2c4","impliedFormat":99},{"version":"18bbffdecf7eed3cefa4a37f34dc879050e629231ba0bd011e2ec6f7503a6cfa","impliedFormat":99},{"version":"fd2e67b97e27962b7c2a6083a2ebf936e7dc2b2335286df2ef5cfc09eb8522b9","impliedFormat":99},{"version":"2e1ccba239f8919e62f83719bc95b4d47b1d1e0187cc6968b5481c86dbbffe3c","impliedFormat":99},{"version":"983bd1482518c10b3e7549f6fe3f51cb7b9868f38ea715cc0c19c8ad6c5c34ca","impliedFormat":99},{"version":"728cf2a025de44eb3e43b3e87d9c8bb2feafe8a34de5ba9b2158317b265125f0","impliedFormat":99},{"version":"54977f121205ea7c7a6c86b42d813dc55d7db6e69c9554a262fc64cae0c7eacf","impliedFormat":99},{"version":"2f94e898529d71f48c841206140ac13988a5ab275bddf852922ad75b7021537d","impliedFormat":99},{"version":"d27f8ee9a610635b566109a359d00923f7e8f286ab7936894671c39a006e8b1a","impliedFormat":99},{"version":"5822d798e08ca6c321c2e5deb337e3b6d6472f2133440c4a2468f0ddee71ab75","signature":"f3688333654359ade219d4e94fb2a91f12339e46c19e03e451714a21e577435c"},{"version":"8db3f96517a120bade1643b55b24ed75a18970f4d38221402d9eccdbb5106fdb","signature":"f9a16b54b8913022325e94f69c48805664e20b6556089e3f3506306b97fe129e"},{"version":"e34e93f5498ed7bc9c53a9ee97d679f90fb941b9ab4190b5ba0747184ef12ad3","signature":"6411762007a15dd690acee3a833c9d06863ca69119d48bca9527fe1f81789e17"},{"version":"012e4aced863fe99eee38c5f48f5d3e79b2afbc9aaa56bef5daadd5ee6464b39","signature":"4c73137788f0bbedcc9e0442183a89a07c3b30303ebc069e6ab02ced95c249f7"},{"version":"3e7b55ed03072f277b2f5d8555bc4707f62be805d9fda85cb9fb6a7c17238afc","signature":"a0cee837e5373cf7095c21e187a4580b8216a64ecd64aa80d19a6967e6d1bb59"},{"version":"e7434e5f90aaa3c85f4658f7e3d3dbe8fc90d286ec4338c282f90d3a6bda0e60","signature":"006d76e50e7f1e25a37da6d436aad571aeb2d646c47f833f9bff146080c9605d"},{"version":"f5c96a4ee0e61f5664d81620d619f5db8aee48c11dd320d767701570438cf0f4","signature":"52a7d02b1fe8db0b42f5259d721b5c7f6bea6d862b8c5ba4331b7169d058305f"},{"version":"65c1e989444a2f3f3f925187ac087ef5de0a880944945644a597a895057a5f1f","signature":"652b463ed1eaf99f278d254973cffb72ea7ef2e76ed166857abe2161fc04d04c"},{"version":"5a2672453bf725ec5acb835ae4d14225718773d493b82a18ddd09c0f1837399c","signature":"8e609a09273295280918847c8f011e60b4c35d8d6591355f4e803712f5f8d6c3"},{"version":"39ecf44f9a385a3b0a20112d827f6bdd6e4fe0ab6e9e46788c8046a13be528b4","signature":"b86992151f5eb07dd0c135d7c1507df75fdeadcbc317e6f37295cdd44f61babf"},{"version":"7fe45be306bc1197001c20c483e2573ce5675181128484669b22de5b58d3332d","signature":"cafc2d90a1946bf6b9447683f11a384aeca03cb10c38b8945e4ceb287f8a97fb"},{"version":"5442b92ed2b5d6f2fa515b8df5c198aaf5b244babf631bbadefa1226284ea7fb","signature":"2864072f8edbbc54e60c45c4d397ec8b00fc21f2524747065c5da1814d77d30a"},{"version":"64e4a36aabd778ea468c12dba55fb5990d2c711b295f1b580c6c859e667492d0","signature":"404049eff8654148369e62fb3e430ac039e762b0f5e25f1aeec5b5c35499710e"},{"version":"002a6f95435929fb339cf9495f6faecc314a30fc0b434f08b7ece78e5152339f","signature":"b46a7be2bec9c094170bd64ff5e51062de78828862893ccb070c57c58948abf4"},{"version":"3a32529dc96bdcfe52cb9331b2cce36d8e92b1164a34ceb4a7443359aec49061","signature":"b0f87819f7baf6659bf4531fcf0687f9333c26d56bf86c00a5162165d68a2aeb"},{"version":"4b854ba79ddff6d7b672f009655ddefd087ab142ad8e82558f48d387b0780ffa","signature":"a0ad37ab2c1f847fe8bb1e9bdfef18ee4719429f1ed808f8aa543d363f23069a"},{"version":"fb7a0827a700b2998bc668b649c22d0cb606ff9557b0990672449e9f518fda72","signature":"e034180f88ee9195af896f639e7cee117b277e3b765995424f8991b3f6b4dda2"},{"version":"d6bc387f53aaf1f3d8cb4c5ea4e4c84865e4fa26d42472ee446bac50e0f7125b","signature":"b871a827a3198ec8b0e0281e1a5dad54d3a3cd2b319f4fd162d55c35833d91f8"},{"version":"ab596340e3c0d463ad4207a8c70118746d30d011de74dc13cd576754169b3b8f","signature":"842f5c6f3899cd852c58d006876c188b06c9093b7372f967948198882a9c32ba"},{"version":"f56f0523d9dfee6fcddcb10d3a6429ba50954f50ec0df71e0ce11e3e7f3ee200","signature":"c261639266a388d9118c5d2c16c6d68f83f9631c30aceb6898dfb173194ab716"},{"version":"bd7c206bd2bc79d129d22f89abdf25968fa171c6956ac9d0a92c0bdf3d3c04b7","signature":"9ff2309cbe37c21de662b3cfffc8755c3620f1b604e32454506cd2da292fa127"},{"version":"dc3b172ee27054dbcedcf5007b78c256021db936f6313a9ce9a3ecbb503fd646","impliedFormat":1},{"version":"a28ac3e717907284b3910b8e9b3f9844a4e0b0a861bea7b923e5adf90f620330","impliedFormat":1},{"version":"b6d03c9cfe2cf0ba4c673c209fcd7c46c815b2619fd2aad59fc4229aaef2ed43","impliedFormat":1},{"version":"82e5a50e17833a10eb091923b7e429dc846d42f1c6161eb6beeb964288d98a15","impliedFormat":1},{"version":"670a76db379b27c8ff42f1ba927828a22862e2ab0b0908e38b671f0e912cc5ed","impliedFormat":1},{"version":"13b77ab19ef7aadd86a1e54f2f08ea23a6d74e102909e3c00d31f231ed040f62","impliedFormat":1},{"version":"069bebfee29864e3955378107e243508b163e77ab10de6a5ee03ae06939f0bb9","impliedFormat":1},{"version":"151ff381ef9ff8da2da9b9663ebf657eac35c4c9a19183420c05728f31a6761d","impliedFormat":1},{"version":"f3d8c757e148ad968f0d98697987db363070abada5f503da3c06aefd9d4248c1","impliedFormat":1},{"version":"d153a11543fd884b596587ccd97aebbeed950b26933ee000f94009f1ab142848","affectsGlobalScope":true,"impliedFormat":1},{"version":"c0671b50bb99cc7ad46e9c68fa0e7f15ba4bc898b59c31a17ea4611fab5095da","affectsGlobalScope":true,"impliedFormat":1},{"version":"d802f0e6b5188646d307f070d83512e8eb94651858de8a82d1e47f60fb6da4e2","affectsGlobalScope":true,"impliedFormat":1},{"version":"aa83e100f0c74a06c9d24f40a096c9e9cc3c02704250d01541e22c0ae9264eda","affectsGlobalScope":true,"impliedFormat":1},{"version":"1db0b7dca579049ca4193d034d835f6bfe73096c73663e5ef9a0b5779939f3d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"387a023d363f755eb63450a66c28b14cdd7bc30a104565e2dbf0a8988bb4a56c","affectsGlobalScope":true,"impliedFormat":1},{"version":"9798340ffb0d067d69b1ae5b32faa17ab31b82466a3fc00d8f2f2df0c8554aaa","affectsGlobalScope":true,"impliedFormat":1},{"version":"f26b11d8d8e4b8028f1c7d618b22274c892e4b0ef5b3678a8ccbad85419aef43","affectsGlobalScope":true,"impliedFormat":1},{"version":"cdcf9ea426ad970f96ac930cd176d5c69c6c24eebd9fc580e1572d6c6a88f62c","impliedFormat":1},{"version":"23cd712e2ce083d68afe69224587438e5914b457b8acf87073c22494d706a3d0","impliedFormat":1},{"version":"487b694c3de27ddf4ad107d4007ad304d29effccf9800c8ae23c2093638d906a","impliedFormat":1},{"version":"3a80bc85f38526ca3b08007ee80712e7bb0601df178b23fbf0bf87036fce40ce","impliedFormat":1},{"version":"ccf4552357ce3c159ef75f0f0114e80401702228f1898bdc9402214c9499e8c0","impliedFormat":1},{"version":"c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","impliedFormat":1},{"version":"68834d631c8838c715f225509cfc3927913b9cc7a4870460b5b60c8dbdb99baf","impliedFormat":1},{"version":"2931540c47ee0ff8a62860e61782eb17b155615db61e36986e54645ec67f67c2","impliedFormat":1},{"version":"3c8e93af4d6ce21eb4c8d005ad6dc02e7b5e6781f429d52a35290210f495a674","impliedFormat":1},{"version":"f6faf5f74e4c4cc309a6c6a6c4da02dbb840be5d3e92905a23dcd7b2b0bd1986","impliedFormat":1},{"version":"ea6bc8de8b59f90a7a3960005fd01988f98fd0784e14bc6922dde2e93305ec7d","impliedFormat":1},{"version":"36107995674b29284a115e21a0618c4c2751b32a8766dd4cb3ba740308b16d59","impliedFormat":1},{"version":"914a0ae30d96d71915fc519ccb4efbf2b62c0ddfb3a3fc6129151076bc01dc60","impliedFormat":1},{"version":"33e981bf6376e939f99bd7f89abec757c64897d33c005036b9a10d9587d80187","impliedFormat":1},{"version":"7fd1b31fd35876b0aa650811c25ec2c97a3c6387e5473eb18004bed86cdd76b6","impliedFormat":1},{"version":"b41767d372275c154c7ea6c9d5449d9a741b8ce080f640155cc88ba1763e35b3","impliedFormat":1},{"version":"3bacf516d686d08682751a3bd2519ea3b8041a164bfb4f1d35728993e70a2426","impliedFormat":1},{"version":"00b21ef538da5a2bbe419e2144f3be50661768e1e039ef2b57bb89f96aff9b18","impliedFormat":1},{"version":"0a60a292b89ca7218b8616f78e5bbd1c96b87e048849469cccb4355e98af959a","impliedFormat":1},{"version":"0b6e25234b4eec6ed96ab138d96eb70b135690d7dd01f3dd8a8ab291c35a683a","impliedFormat":1},{"version":"9666f2f84b985b62400d2e5ab0adae9ff44de9b2a34803c2c5bd3c8325b17dc0","impliedFormat":1},{"version":"40cd35c95e9cf22cfa5bd84e96408b6fcbca55295f4ff822390abb11afbc3dca","impliedFormat":1},{"version":"b1616b8959bf557feb16369c6124a97a0e74ed6f49d1df73bb4b9ddf68acf3f3","impliedFormat":1},{"version":"e843e840f484f7e59b2ef9488501a301e3300a8e3e56aa84a02ddf915c7ce07d","impliedFormat":1},{"version":"40b463c6766ca1b689bfcc46d26b5e295954f32ad43e37ee6953c0a677e4ae2b","impliedFormat":1},{"version":"249b9cab7f5d628b71308c7d9bb0a808b50b091e640ba3ed6e2d0516f4a8d91d","impliedFormat":1},{"version":"80aae6afc67faa5ac0b32b5b8bc8cc9f7fa299cff15cf09cc2e11fd28c6ae29e","impliedFormat":1},{"version":"f473cd2288991ff3221165dcf73cd5d24da30391f87e85b3dd4d0450c787a391","impliedFormat":1},{"version":"499e5b055a5aba1e1998f7311a6c441a369831c70905cc565ceac93c28083d53","impliedFormat":1},{"version":"54c3e2371e3d016469ad959697fd257e5621e16296fa67082c2575d0bf8eced0","impliedFormat":1},{"version":"beb8233b2c220cfa0feea31fbe9218d89fa02faa81ef744be8dce5acb89bb1fd","impliedFormat":1},{"version":"78b29846349d4dfdd88bd6650cc5d2baaa67f2e89dc8a80c8e26ef7995386583","impliedFormat":1},{"version":"5d0375ca7310efb77e3ef18d068d53784faf62705e0ad04569597ae0e755c401","impliedFormat":1},{"version":"59af37caec41ecf7b2e76059c9672a49e682c1a2aa6f9d7dc78878f53aa284d6","impliedFormat":1},{"version":"addf417b9eb3f938fddf8d81e96393a165e4be0d4a8b6402292f9c634b1cb00d","impliedFormat":1},{"version":"48cc3ec153b50985fb95153258a710782b25975b10dd4ac8a4f3920632d10790","impliedFormat":1},{"version":"adf27937dba6af9f08a68c5b1d3fce0ca7d4b960c57e6d6c844e7d1a8e53adae","impliedFormat":1},{"version":"18f8cfbb14ba9405e67d30968ae67b8d19133867d13ebc49c8ed37ec64ce9bdb","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"866078923a56d026e39243b4392e282c1c63159723996fa89243140e1388a98d","impliedFormat":1},{"version":"830171b27c5fdf9bcbe4cf7d428fcf3ae2c67780fb7fbdccdf70d1623d938bc4","affectsGlobalScope":true,"impliedFormat":1},{"version":"1cf059eaf468efcc649f8cf6075d3cb98e9a35a0fe9c44419ec3d2f5428d7123","affectsGlobalScope":true,"impliedFormat":1},{"version":"e7721c4f69f93c91360c26a0a84ee885997d748237ef78ef665b153e622b36c1","affectsGlobalScope":true,"impliedFormat":1},{"version":"d97fb21da858fb18b8ae72c314e9743fd52f73ebe2764e12af1db32fc03f853f","affectsGlobalScope":true,"impliedFormat":1},{"version":"f68328826a275104d92bd576c796c570f66365f25ea8bbaaa208727bce132d5f","impliedFormat":1},{"version":"7cf69dd5502c41644c9e5106210b5da7144800670cbe861f66726fa209e231c4","impliedFormat":1},{"version":"72c1f5e0a28e473026074817561d1bc9647909cf253c8d56c41d1df8d95b85f7","impliedFormat":1},{"version":"18334defc3d0a0e1966f5f3c23c7c83b62c77811e51045c5a7ff3883b446f81f","affectsGlobalScope":true,"impliedFormat":1},{"version":"8b17fcd63aa13734bf1d01419f4d6031b1c6a5fb2cbdb45e9839fb1762bdf0df","impliedFormat":1},{"version":"c4e8e8031808b158cfb5ac5c4b38d4a26659aec4b57b6a7e2ba0a141439c208c","impliedFormat":1},{"version":"2c91d8366ff2506296191c26fd97cc1990bab3ee22576275d28b654a21261a44","affectsGlobalScope":true,"impliedFormat":1},{"version":"5524481e56c48ff486f42926778c0a3cce1cc85dc46683b92b1271865bcf015a","impliedFormat":1},{"version":"beb77fcd86c8cee62c32b2fb82753f5bc0e171d938e20af3cb0b8925db78d60b","impliedFormat":1},{"version":"289e9894a4668c61b5ffed09e196c1f0c2f87ca81efcaebdf6357cfb198dac14","impliedFormat":1},{"version":"25a1105595236f09f5bce42398be9f9ededc8d538c258579ab662d509aa3b98e","impliedFormat":1},{"version":"aa9224557befad144262c85b463c0a7ba8a3a0ad2a7c907349f8bb8bc3fe4abc","impliedFormat":1},{"version":"a2e2bbde231b65c53c764c12313897ffdfb6c49183dd31823ee2405f2f7b5378","impliedFormat":1},{"version":"ad1cc0ed328f3f708771272021be61ab146b32ecf2b78f3224959ff1e2cd2a5c","impliedFormat":1},{"version":"8d86c8d8c43e04cc3dde9953e571656812c8964a3651203af7b3a1df832a34df","affectsGlobalScope":true,"impliedFormat":1},{"version":"0121911fcc364eb821d058cf4c3b9339f197eccbe298098a4c6be0396b607d90","impliedFormat":1},{"version":"c6176c7b9f3769ba7f076c7a791588562c653cc0ba08fb2184f87bf78db2a87c","impliedFormat":1},{"version":"6def204d0b267101d3a42300a7363f53406c5d86b932e76e2365bf89689a85c4","impliedFormat":1},{"version":"4f766affd1281935fe5f7fd5d7af693a7c26d81adef7c1aefb84b9cd573a9cbb","impliedFormat":1},{"version":"165a0c1f95bc939c72f18a280fc707fba6f2f349539246b050cfc09eb1d9f446","impliedFormat":1},{"version":"bbf42f98a5819f4f06e18c8b669a994afe9a17fe520ae3454a195e6eabf7700d","impliedFormat":1},{"version":"c0bb1b65757c72bbf8ddf7eaa532223bacf58041ff16c883e76f45506596e925","impliedFormat":1},{"version":"c8b85f7aed29f8f52b813f800611406b0bfe5cf3224d20a4bdda7c7f73ce368e","affectsGlobalScope":true,"impliedFormat":1},{"version":"7baae9bf5b50e572e7742c886c73c6f8fa50b34190bc5f0fd20dd7e706fda832","impliedFormat":1},{"version":"e99b0e71f07128fc32583e88ccd509a1aaa9524c290efb2f48c22f9bf8ba83b1","impliedFormat":1},{"version":"76957a6d92b94b9e2852cf527fea32ad2dc0ef50f67fe2b14bd027c9ceef2d86","impliedFormat":1},{"version":"5e9f8c1e042b0f598a9be018fc8c3cb670fe579e9f2e18e3388b63327544fe16","affectsGlobalScope":true,"impliedFormat":1},{"version":"a8a99a5e6ed33c4a951b67cc1fd5b64fd6ad719f5747845c165ca12f6c21ba16","affectsGlobalScope":true,"impliedFormat":1},{"version":"a58a15da4c5ba3df60c910a043281256fa52d36a0fcdef9b9100c646282e88dd","impliedFormat":1},{"version":"b36beffbf8acdc3ebc58c8bb4b75574b31a2169869c70fc03f82895b93950a12","impliedFormat":1},{"version":"de263f0089aefbfd73c89562fb7254a7468b1f33b61839aafc3f035d60766cb4","impliedFormat":1},{"version":"70b57b5529051497e9f6482b76d91c0dcbb103d9ead8a0549f5bab8f65e5d031","impliedFormat":1},{"version":"8c81fd4a110490c43d7c578e8c6f69b3af01717189196899a6a44f93daa57a3a","impliedFormat":1},{"version":"1013eb2e2547ad8c100aca52ef9df8c3f209edee32bb387121bb3227f7c00088","impliedFormat":1},{"version":"b827f8800f42858f0a751a605c003b7ab571ff7af184436f36cef9bdfebae808","impliedFormat":1},{"version":"363eedb495912790e867da6ff96e81bf792c8cfe386321e8163b71823a35719a","impliedFormat":1},{"version":"37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","impliedFormat":1},{"version":"125d792ec6c0c0f657d758055c494301cc5fdb327d9d9d5960b3f129aff76093","impliedFormat":1},{"version":"6b306cd4282bbb54d4a6bb23cfb7a271160983dfc38c67b5a132504cfcc34896","affectsGlobalScope":true,"impliedFormat":1},{"version":"ea713aa14a670b1ea0fbaaca4fd204e645f71ca7653a834a8ec07ee889c45de6","impliedFormat":1},{"version":"450172a56b944c2d83f45cc11c9a388ea967cd301a21202aa0a23c34c7506a18","impliedFormat":1},{"version":"9705cd157ffbb91c5cab48bdd2de5a437a372e63f870f8a8472e72ff634d47c1","affectsGlobalScope":true,"impliedFormat":1},{"version":"ae86f30d5d10e4f75ce8dcb6e1bd3a12ecec3d071a21e8f462c5c85c678efb41","impliedFormat":1},{"version":"3af7d02e5d6ecbf363e61fb842ee55d3518a140fd226bdfb24a3bca6768c58df","impliedFormat":1},{"version":"e03460fe72b259f6d25ad029f085e4bedc3f90477da4401d8fbc1efa9793230e","impliedFormat":1},{"version":"4286a3a6619514fca656089aee160bb6f2e77f4dd53dc5a96b26a0b4fc778055","impliedFormat":1},{"version":"7dfa742c23851808a77ec27062fbbd381c8c36bb3cfdff46cb8af6c6c233bfc1","affectsGlobalScope":true,"impliedFormat":1},{"version":"cb078cfcd14dc0b1700a48272958f803f30f13f99111c5978c75c3a0aa07e40e","affectsGlobalScope":true,"impliedFormat":1},{"version":"784490137935e1e38c49b9289110e74a1622baf8a8907888dcbe9e476d7c5e44","impliedFormat":1},{"version":"420fdd37c51263be9db3fcac35ffd836216c71e6000e6a9740bb950fb0540654","impliedFormat":1},{"version":"73b0bff83ee76e3a9320e93c7fc15596e858b33c687c39a57567e75c43f2a324","impliedFormat":1},{"version":"3c947600f6f5664cca690c07fcf8567ca58d029872b52c31c2f51d06fbdb581b","affectsGlobalScope":true,"impliedFormat":1},{"version":"493c64d062139b1849b0e9c4c3a6465e1227d2b42be9e26ec577ca728984c041","impliedFormat":1},{"version":"d7e9ab1b0996639047c61c1e62f85c620e4382206b3abb430d9a21fb7bc23c77","impliedFormat":1},{"version":"be1cc4d94ea60cbe567bc29ed479d42587bf1e6cba490f123d329976b0fe4ee5","impliedFormat":1}],"root":[[250,257],[406,426]],"options":{"allowSyntheticDefaultImports":true,"composite":true,"declaration":true,"declarationMap":true,"emitDeclarationOnly":true,"esModuleInterop":true,"jsx":4,"module":99,"outDir":"./lib-dist","rootDir":"./lib","skipLibCheck":true,"sourceMap":false,"strict":true,"target":7},"referencedMap":[[257,1],[414,2],[416,3],[413,4],[417,5],[418,6],[421,7],[423,8],[256,9],[255,10],[409,11],[424,12],[407,1],[253,13],[425,10],[415,10],[254,13],[426,14],[252,15],[410,16],[411,17],[420,18],[422,19],[406,20],[419,21],[408,21],[250,22],[251,23],[412,24],[249,25],[248,26],[155,27],[156,28],[157,29],[158,30],[159,31],[160,32],[161,33],[162,34],[164,35],[165,36],[166,37],[167,38],[168,39],[169,40],[170,41],[171,42],[172,43],[173,44],[174,45],[175,46],[176,47],[177,48],[178,49],[179,50],[180,51],[181,52],[182,43],[183,53],[184,54],[185,55],[187,56],[186,43],[189,57],[190,58],[188,43],[191,59],[192,60],[193,61],[194,62],[195,63],[196,64],[197,65],[163,43],[198,66],[199,67],[200,68],[201,69],[202,70],[203,71],[204,72],[205,73],[206,74],[207,75],[154,43],[208,76],[209,77],[210,78],[211,79],[212,80],[213,81],[214,82],[215,83],[216,84],[217,85],[218,86],[219,87],[220,88],[221,89],[222,90],[223,91],[224,43],[225,92],[226,93],[227,94],[228,95],[229,96],[230,97],[231,98],[232,99],[233,100],[234,101],[235,102],[236,103],[237,104],[238,105],[239,106],[240,107],[241,108],[242,109],[243,110],[244,111],[245,112],[246,113],[247,114],[405,115],[400,116],[271,117],[272,118],[273,119],[274,120],[275,121],[276,122],[277,123],[278,124],[279,125],[280,126],[281,127],[282,128],[283,129],[284,130],[261,43],[258,43],[262,131],[266,132],[264,133],[263,131],[268,134],[285,135],[286,136],[287,137],[288,138],[289,139],[290,140],[291,141],[292,142],[293,143],[294,144],[295,145],[297,146],[296,147],[298,148],[299,149],[300,150],[301,151],[302,152],[303,153],[259,154],[304,155],[305,156],[306,157],[260,158],[307,159],[269,160],[308,161],[309,162],[310,163],[311,164],[312,165],[313,166],[314,167],[315,168],[316,169],[317,170],[318,171],[319,172],[320,173],[321,174],[322,175],[323,176],[324,177],[325,178],[326,179],[327,180],[328,181],[329,182],[330,183],[331,184],[332,185],[333,186],[334,187],[335,188],[336,189],[265,190],[337,191],[338,192],[339,193],[270,43],[340,194],[341,195],[342,196],[343,197],[344,198],[345,199],[346,200],[347,201],[348,202],[349,203],[267,43],[350,204],[351,205],[352,206],[353,207],[354,208],[355,209],[356,210],[357,211],[358,212],[359,213],[360,214],[361,215],[362,216],[363,217],[364,218],[365,219],[366,220],[367,221],[368,222],[369,223],[370,224],[371,43],[372,225],[373,226],[374,227],[375,228],[376,229],[377,230],[378,231],[379,232],[381,233],[380,234],[382,235],[383,236],[384,237],[385,238],[386,239],[387,240],[388,241],[389,242],[390,243],[391,244],[392,245],[393,246],[394,247],[395,248],[396,249],[397,250],[398,251],[399,252],[401,253],[402,254],[403,254],[404,254],[77,255],[78,256],[76,257],[79,258],[90,259],[91,259],[92,259],[93,259],[98,260],[94,261],[95,261],[96,261],[97,261],[99,262],[89,263],[84,260],[88,264],[85,265],[86,260],[87,260],[82,266],[81,265],[83,267],[75,257],[74,268],[67,269],[68,257],[66,270],[72,271],[56,272],[60,273],[61,257],[62,257],[54,257],[55,257],[71,274],[63,257],[57,257],[58,257],[64,257],[65,257],[69,257],[59,257],[73,275],[153,276],[152,277],[100,278],[101,279],[102,280],[103,281],[104,282],[105,283],[106,284],[107,285],[108,286],[109,287],[110,288],[111,289],[112,290],[113,291],[114,292],[115,293],[116,294],[117,295],[118,296],[119,297],[120,298],[121,299],[122,300],[123,301],[124,302],[125,303],[126,304],[127,305],[128,306],[129,307],[130,308],[131,309],[132,43],[133,43],[134,310],[135,311],[136,312],[137,313],[138,314],[139,315],[140,316],[141,317],[142,43],[143,43],[144,43],[145,318],[146,319],[147,320],[148,321],[149,322],[150,323],[151,324],[430,325],[428,257],[80,257],[70,257],[427,257],[433,326],[429,325],[431,327],[432,325],[434,257],[435,257],[489,328],[490,328],[491,329],[438,330],[492,331],[493,332],[494,333],[436,257],[495,334],[496,335],[497,336],[498,337],[499,338],[500,339],[501,339],[502,340],[503,341],[504,342],[505,343],[439,257],[437,257],[506,344],[507,345],[508,346],[542,347],[509,348],[510,257],[511,349],[512,350],[513,351],[514,352],[515,353],[516,354],[517,355],[518,356],[519,357],[520,357],[521,358],[522,257],[523,257],[524,359],[526,360],[525,361],[527,362],[528,363],[529,364],[530,365],[531,366],[532,367],[533,368],[534,369],[535,370],[536,371],[537,372],[538,373],[539,374],[440,257],[441,375],[442,257],[443,257],[485,376],[486,377],[487,257],[488,362],[540,378],[541,379],[543,380],[50,257],[52,381],[53,380],[51,257],[48,257],[49,257],[8,257],[9,257],[11,257],[10,257],[2,257],[12,257],[13,257],[14,257],[15,257],[16,257],[17,257],[18,257],[19,257],[3,257],[20,257],[21,257],[4,257],[22,257],[26,257],[23,257],[24,257],[25,257],[27,257],[28,257],[29,257],[5,257],[30,257],[31,257],[32,257],[33,257],[6,257],[37,257],[34,257],[35,257],[36,257],[38,257],[7,257],[39,257],[44,257],[45,257],[40,257],[41,257],[42,257],[43,257],[1,257],[46,257],[47,257],[461,382],[473,383],[459,384],[474,385],[483,386],[450,387],[451,388],[449,389],[482,390],[477,391],[481,392],[453,393],[470,394],[452,395],[480,396],[447,397],[448,391],[454,398],[455,257],[460,399],[458,398],[445,400],[484,401],[475,402],[464,403],[463,398],[465,404],[468,405],[462,406],[466,407],[478,390],[456,408],[457,409],[469,410],[446,385],[472,411],[471,398],[467,412],[476,257],[444,257],[479,413]],"latestChangedDtsFile":"./lib-dist/core/AtProtoRecord.d.ts","version":"5.9.3"}
+2 -1
tsconfig.node.json
··· 12 12 "allowImportingTsExtensions": true, 13 13 "verbatimModuleSyntax": true, 14 14 "moduleDetection": "force", 15 - "noEmit": true, 15 + "declaration": true, 16 + "emitDeclarationOnly": true, 16 17 17 18 /* Linting */ 18 19 "strict": true,
+2
vite.config.d.ts
··· 1 + declare const _default: import("vite").UserConfig; 2 + export default _default;
+73 -4
vite.config.ts
··· 1 - import { defineConfig } from 'vite' 2 - import react from '@vitejs/plugin-react' 1 + import { defineConfig } from 'vite'; 2 + import react from '@vitejs/plugin-react'; 3 + import dts from 'unplugin-dts/vite' 4 + import { resolve } from 'path'; 5 + import type { Plugin } from 'vite'; 6 + 7 + // Plugin to inject CSS import as a side effect in the main entry 8 + function injectCssImport(): Plugin { 9 + return { 10 + name: 'inject-css-import', 11 + generateBundle(_, bundle) { 12 + const indexFile = bundle['index.js']; 13 + if (indexFile && indexFile.type === 'chunk') { 14 + // Inject the CSS import at the top of the file 15 + indexFile.code = `import './styles.css';\n${indexFile.code}`; 16 + } 17 + } 18 + }; 19 + } 20 + 21 + const buildDemo = process.env.BUILD_TARGET === 'demo'; 3 22 4 23 // https://vite.dev/config/ 5 24 export default defineConfig({ 6 - plugins: [react()], 7 - }) 25 + plugins: buildDemo 26 + ? [react()] 27 + : [react(), dts({ tsconfigPath: './tsconfig.lib.json' }), injectCssImport()], 28 + 29 + // Demo app needs to resolve from src 30 + root: buildDemo ? '.' : undefined, 31 + 32 + build: buildDemo ? { 33 + // Demo app build configuration 34 + outDir: 'demo', 35 + rollupOptions: { 36 + input: resolve(__dirname, 'index.html') 37 + }, 38 + sourcemap: false 39 + } : { 40 + // Library build configuration 41 + lib: { 42 + entry: resolve(__dirname, 'lib/index.ts'), 43 + cssFileName: resolve(__dirname, 'lib/styles.css'), 44 + name: 'atproto-ui', 45 + formats: ['es'], 46 + fileName: 'atproto-ui' 47 + }, 48 + cssCodeSplit: false, 49 + outDir: 'lib-dist', 50 + rollupOptions: { 51 + // Externalize dependencies that shouldn't be bundled 52 + external: [ 53 + 'react', 54 + 'react-dom', 55 + 'react/jsx-runtime', 56 + '@atcute/atproto', 57 + '@atcute/bluesky', 58 + '@atcute/client', 59 + '@atcute/identity-resolver', 60 + '@atcute/tangled' 61 + ], 62 + output: { 63 + preserveModules: true, 64 + preserveModulesRoot: 'lib', 65 + entryFileNames: '[name].js', 66 + assetFileNames: (assetInfo) => { 67 + // Output CSS to root of lib-dist as styles.css 68 + if (assetInfo.name && assetInfo.name.endsWith('.css')) { 69 + return 'styles.css'; 70 + } 71 + return 'assets/[name][extname]'; 72 + } 73 + } 74 + }, 75 + } 76 + });