From ad07a75d0aef3cf4543ecf536a52553ffb135637 Mon Sep 17 00:00:00 2001 From: jordan Date: Thu, 19 Feb 2026 21:54:27 -0700 Subject: [PATCH] feat: add source content to source registry, signed assertions, feed endpoint, dashboard enhancements - Add `content: Option` to SourceRecord with rkyv schema evolution (LegacySourceRecord compat deserializer for backward compatibility) - Add MAX_SOURCE_CONTENT_LEN (1MB) limit with API validation - Strip content from list responses, include in single-source GET - Update Go SDK RegisterSourceRequest with Content field - FCM pipeline extracts PDF text via pdftotext and passes to registration - Dashboard impact panel fetches and displays source content with expand/collapse - Add feed endpoint, dashboard feed panel, and signed assertion support - Update data-structures.md, API docs, and storage docs Co-Authored-By: Claude Opus 4.6 --- ai-lookup/services/api.md | 8 +- ai-lookup/services/sdk.md | 2 +- ai-lookup/services/storage.md | 12 +- applications/aphoria/src/bridge.rs | 2 + .../aphoria/src/community/pattern_store.rs | 3 +- applications/aphoria/src/episteme/corpus.rs | 2 + .../aphoria/src/episteme/local/queries.rs | 2 +- applications/aphoria/src/hosted.rs | 1 + applications/aphoria/src/llm/extractor.rs | 1 + applications/aphoria/src/llm/ontology.rs | 1 + applications/aphoria/src/llm/prompt.rs | 1 + applications/aphoria/src/remote/cache.rs | 2 +- applications/aphoria/src/remote/client.rs | 26 +- applications/aphoria/src/report/json.rs | 4 +- .../aphoria/src/resolution/tier_verdict.rs | 14 +- applications/aphoria/src/types/result.rs | 6 +- .../src/app/layered/page.tsx | 15 +- .../src/app/skeptic/page.tsx | 16 +- .../src/components/audit/audit-panel.tsx | 10 +- .../src/components/audit/audit-row.tsx | 96 ++++++- .../src/components/feed/feed-row.tsx | 62 ++++- .../layered/layered-query-results.tsx | 29 +- .../layered/layered-results-view.tsx | 5 + .../src/components/layered/tier-accordion.tsx | 127 ++++++++- .../src/components/skeptic/claim-row.tsx | 64 ++++- .../src/components/skeptic/query-form.tsx | 232 ++++++++++++++-- .../src/components/skeptic/query-results.tsx | 29 +- .../sources/impact-detail-panel.tsx | 188 +++++++++++-- .../src/components/sources/source-row.tsx | 14 + .../src/components/sources/sources-panel.tsx | 29 ++ .../stemedb-dashboard/src/lib/api/client.ts | 19 ++ .../stemedb-dashboard/src/lib/api/types.ts | 13 + .../stemedb-dashboard/tsconfig.tsbuildinfo | 2 +- crates/stemedb-admin/src/client.rs | 12 +- crates/stemedb-api/src/dto/create.rs | 8 + crates/stemedb-api/src/dto/mod.rs | 10 +- crates/stemedb-api/src/dto/responses.rs | 28 ++ crates/stemedb-api/src/dto/source_registry.rs | 9 + crates/stemedb-api/src/dto/subjects.rs | 34 +++ crates/stemedb-api/src/handlers/admin.rs | 218 ++++++++++++++- .../src/handlers/aphoria_helpers.rs | 1 + crates/stemedb-api/src/handlers/assert.rs | 41 ++- crates/stemedb-api/src/handlers/feed.rs | 94 +++++-- crates/stemedb-api/src/handlers/layered.rs | 1 + crates/stemedb-api/src/handlers/mod.rs | 10 +- crates/stemedb-api/src/handlers/query.rs | 1 + crates/stemedb-api/src/handlers/rejected.rs | 89 ++++++ .../src/handlers/source_registry/handlers.rs | 22 +- .../src/handlers/stemedb_claims.rs | 48 ++-- crates/stemedb-api/src/handlers/subjects.rs | 97 +++++++ crates/stemedb-api/src/lib.rs | 14 +- crates/stemedb-api/src/main.rs | 6 +- crates/stemedb-api/src/routers.rs | 10 +- crates/stemedb-api/tests/http_basic.rs | 122 ++++++++- crates/stemedb-core/src/lib.rs | 2 + crates/stemedb-core/src/limits.rs | 19 ++ crates/stemedb-core/src/serde.rs | 258 ++++++++++++++++++ crates/stemedb-core/src/signing.rs | 187 +++++++++++++ crates/stemedb-core/src/testing.rs | 9 + crates/stemedb-core/src/types/assertion.rs | 9 + .../stemedb-core/src/types/source_record.rs | 47 +++- crates/stemedb-ingest/Cargo.toml | 2 + crates/stemedb-ingest/src/error.rs | 20 ++ .../stemedb-ingest/src/worker/processing.rs | 205 +++++++------- crates/stemedb-ingest/src/worker/run.rs | 22 +- .../src/worker/tests/signatures.rs | 85 ++++++ .../src/worker/tests/validation.rs | 7 + .../src/worker/tests/validation_boundaries.rs | 5 + .../stemedb-ontology/src/dto/conversions.rs | 2 + crates/stemedb-ontology/src/dto/requests.rs | 4 + crates/stemedb-ontology/src/dto/responses.rs | 4 + .../src/pharma/extractors/mod.rs | 1 + crates/stemedb-query/src/engine/mod.rs | 7 +- crates/stemedb-query/src/materializer/mod.rs | 2 +- crates/stemedb-sim/src/agent.rs | 1 + crates/stemedb-storage/src/hybrid_backend.rs | 20 ++ .../src/key_codec/global_keys.rs | 30 ++ crates/stemedb-storage/src/key_codec/mod.rs | 8 +- crates/stemedb-storage/src/key_codec/tests.rs | 42 +++ crates/stemedb-storage/src/serde_helpers.rs | 10 + .../src/source_registry/generic.rs | 4 +- .../stemedb-sync/src/anti_entropy/sync_ops.rs | 6 +- docs/data-structures.md | 57 +++- sdk/go/steme/assertion.go | 9 + sdk/go/steme/query.go | 3 + 85 files changed, 2651 insertions(+), 348 deletions(-) create mode 100644 crates/stemedb-api/src/dto/subjects.rs create mode 100644 crates/stemedb-api/src/handlers/rejected.rs create mode 100644 crates/stemedb-api/src/handlers/subjects.rs diff --git a/ai-lookup/services/api.md b/ai-lookup/services/api.md index 9be1208..41e14c9 100644 --- a/ai-lookup/services/api.md +++ b/ai-lookup/services/api.md @@ -1,6 +1,6 @@ # API Surface -**Last Updated:** 2026-02-03 +**Last Updated:** 2026-02-19 **Confidence:** High ## Summary @@ -41,10 +41,10 @@ Episteme exposes an HTTP API via `axum` with auto-generated OpenAPI 3.1 document | `GET` | `/metrics` | Prometheus metrics (Phase 8B) | ✅ Implemented | | `GET` | `/api-docs/openapi.json` | OpenAPI 3.1 spec | ✅ Implemented | | `GET` | `/swagger-ui` | Interactive API docs | ✅ Implemented | -| `POST` | `/v1/sources` | Register source with human-readable metadata | ✅ Implemented | -| `GET` | `/v1/sources/{hash}` | Get source record by hash | ✅ Implemented | +| `POST` | `/v1/sources` | Register source with metadata and optional content | ✅ Implemented | +| `GET` | `/v1/sources/{hash}` | Get source record by hash (includes content) | ✅ Implemented | | `PATCH` | `/v1/sources/{hash}/status` | Update source status (deprecate/quarantine) | ✅ Implemented | -| `GET` | `/v1/sources` | List/search sources (filter by tier or query) | ✅ Implemented | +| `GET` | `/v1/sources` | List/search sources (content stripped for performance) | ✅ Implemented | ### Cluster Gateway Endpoints (stemedb-cluster) diff --git a/ai-lookup/services/sdk.md b/ai-lookup/services/sdk.md index 58b16fd..12e13a0 100644 --- a/ai-lookup/services/sdk.md +++ b/ai-lookup/services/sdk.md @@ -1,6 +1,6 @@ # SDK - Go Client Libraries -**Last Updated:** 2026-02-01 +**Last Updated:** 2026-02-19 **Confidence:** High ## Summary diff --git a/ai-lookup/services/storage.md b/ai-lookup/services/storage.md index 833be0b..8248511 100644 --- a/ai-lookup/services/storage.md +++ b/ai-lookup/services/storage.md @@ -1,6 +1,6 @@ # Storage -**Last Updated:** 2026-01-31 +**Last Updated:** 2026-02-19 **Confidence:** High ## Summary @@ -91,6 +91,16 @@ let value: MyType = deserialize(&bytes)?; This provides unified error handling across all store implementations (VoteStore, IndexStore, TrustRankStore, AuditStore, TrustPackStore, QuotaStore). +For types with schema evolution (rkyv compat), use the dedicated compat functions: + +```rust +use crate::serde_helpers::deserialize_source_record_compat; + +let record: SourceRecord = deserialize_source_record_compat(&bytes)?; +``` + +Available compat deserializers: `deserialize_source_record_compat` (SourceRecord). For assertions, use `stemedb_core::serde::deserialize_assertion_compat` directly. + ## Write Path ``` diff --git a/applications/aphoria/src/bridge.rs b/applications/aphoria/src/bridge.rs index 0ae3d6e..4c8b693 100644 --- a/applications/aphoria/src/bridge.rs +++ b/applications/aphoria/src/bridge.rs @@ -146,6 +146,7 @@ fn claim_to_assertion_with_tier( visual_hash: None, epoch: None, source_metadata: serde_json::to_vec(&source_metadata).ok(), + narrative: None, lifecycle: LifecycleStage::Approved, signatures: vec![signature_entry], confidence: claim.confidence, @@ -235,6 +236,7 @@ pub fn authored_claim_to_assertion( visual_hash: None, epoch: None, source_metadata: serde_json::to_vec(&source_metadata).ok(), + narrative: None, lifecycle, signatures: vec![signature_entry], confidence: 1.0, // Authored claims have full confidence diff --git a/applications/aphoria/src/community/pattern_store.rs b/applications/aphoria/src/community/pattern_store.rs index 27b6029..6da2ebe 100644 --- a/applications/aphoria/src/community/pattern_store.rs +++ b/applications/aphoria/src/community/pattern_store.rs @@ -79,7 +79,7 @@ impl StemeDBPatternStore { return Ok(None); }; - let assertion = stemedb_core::serde::deserialize::(&bytes).map_err(|e| { + let assertion = stemedb_core::serde::deserialize_assertion_compat(&bytes).map_err(|e| { AphoriaError::Storage(format!( "Failed to deserialize assertion {}: {}", hex::encode(hash), @@ -389,6 +389,7 @@ impl PatternAggregator { visual_hash: None, epoch: None, source_metadata: Some(metadata_bytes), + narrative: None, lifecycle: stemedb_core::types::LifecycleStage::Approved, signatures: vec![], // Bootstrap patterns are unsigned (no signing key available) confidence: 1.0, // Pattern aggregates are high confidence diff --git a/applications/aphoria/src/episteme/corpus.rs b/applications/aphoria/src/episteme/corpus.rs index 4f768a2..84b3889 100644 --- a/applications/aphoria/src/episteme/corpus.rs +++ b/applications/aphoria/src/episteme/corpus.rs @@ -114,6 +114,7 @@ pub fn create_authoritative_assertion_with_metadata( visual_hash: None, epoch: None, source_metadata: serde_json::to_vec(&metadata).ok(), + narrative: None, lifecycle: LifecycleStage::Approved, signatures: vec![signature_entry], confidence: 1.0, @@ -170,6 +171,7 @@ pub fn create_authoritative_assertion( visual_hash: None, epoch: None, source_metadata: serde_json::to_vec(&source_metadata).ok(), + narrative: None, lifecycle: LifecycleStage::Approved, signatures: vec![signature_entry], confidence: 1.0, diff --git a/applications/aphoria/src/episteme/local/queries.rs b/applications/aphoria/src/episteme/local/queries.rs index c6a405d..c11f41f 100644 --- a/applications/aphoria/src/episteme/local/queries.rs +++ b/applications/aphoria/src/episteme/local/queries.rs @@ -342,7 +342,7 @@ impl LocalEpisteme { let assertion_key = stemedb_storage::key_codec::assertion_key(&subject, &hash_hex); self.store.get(&assertion_key).await.ok().flatten().and_then(|bytes| { - stemedb_core::serde::deserialize::(&bytes) + stemedb_core::serde::deserialize_assertion_compat(&bytes) .map_err(|e| warn!(hash = %hash_hex, error = %e, "Failed to deserialize")) .ok() }) diff --git a/applications/aphoria/src/hosted.rs b/applications/aphoria/src/hosted.rs index 7678ca6..e852a19 100644 --- a/applications/aphoria/src/hosted.rs +++ b/applications/aphoria/src/hosted.rs @@ -854,6 +854,7 @@ mod tests { visual_hash: None, epoch: None, source_metadata: Some(b"{\"file\":\"test.rs\"}".to_vec()), + narrative: None, lifecycle: LifecycleStage::Approved, signatures: vec![SignatureEntry { agent_id: [2u8; 32], diff --git a/applications/aphoria/src/llm/extractor.rs b/applications/aphoria/src/llm/extractor.rs index c5371fe..172c493 100644 --- a/applications/aphoria/src/llm/extractor.rs +++ b/applications/aphoria/src/llm/extractor.rs @@ -438,6 +438,7 @@ mod tests { visual_hash: None, epoch: None, source_metadata: serde_json::to_vec(&source_metadata).ok(), + narrative: None, lifecycle: LifecycleStage::Approved, signatures: vec![], confidence: 1.0, diff --git a/applications/aphoria/src/llm/ontology.rs b/applications/aphoria/src/llm/ontology.rs index 2482c4a..43b8c2d 100644 --- a/applications/aphoria/src/llm/ontology.rs +++ b/applications/aphoria/src/llm/ontology.rs @@ -255,6 +255,7 @@ mod tests { visual_hash: None, epoch: None, source_metadata: serde_json::to_vec(&source_metadata).ok(), + narrative: None, lifecycle: LifecycleStage::Approved, signatures: vec![], confidence: 1.0, diff --git a/applications/aphoria/src/llm/prompt.rs b/applications/aphoria/src/llm/prompt.rs index 9312b82..1a1fccb 100644 --- a/applications/aphoria/src/llm/prompt.rs +++ b/applications/aphoria/src/llm/prompt.rs @@ -109,6 +109,7 @@ mod tests { visual_hash: None, epoch: None, source_metadata: serde_json::to_vec(&source_metadata).ok(), + narrative: None, lifecycle: LifecycleStage::Approved, signatures: vec![], confidence: 1.0, diff --git a/applications/aphoria/src/remote/cache.rs b/applications/aphoria/src/remote/cache.rs index 064cb19..4b49141 100644 --- a/applications/aphoria/src/remote/cache.rs +++ b/applications/aphoria/src/remote/cache.rs @@ -47,7 +47,7 @@ impl ClaimCache { pub fn save(&self, claims: &[AuthoredClaim], remote_url: &str) -> Result<(), AphoriaError> { let now = SystemTime::now() .duration_since(SystemTime::UNIX_EPOCH) - .map_err(|e| AphoriaError::Io(std::io::Error::new(std::io::ErrorKind::Other, e)))? + .map_err(|e| AphoriaError::Io(std::io::Error::other(e)))? .as_secs(); let cache = ClaimCacheFile { diff --git a/applications/aphoria/src/remote/client.rs b/applications/aphoria/src/remote/client.rs index cb0f894..7a0b699 100644 --- a/applications/aphoria/src/remote/client.rs +++ b/applications/aphoria/src/remote/client.rs @@ -179,9 +179,7 @@ impl RemoteClaimStore { } } - Err(last_error.unwrap_or_else(|| { - AphoriaError::Hosted("Max retries exceeded".to_string()) - })) + Err(last_error.unwrap_or_else(|| AphoriaError::Hosted("Max retries exceeded".to_string()))) } /// Perform the actual HTTP request. @@ -211,8 +209,8 @@ impl RemoteClaimStore { http_request.call() }; - let response = response - .map_err(|e| AphoriaError::Hosted(format!("HTTP request failed: {e}")))?; + let response = + response.map_err(|e| AphoriaError::Hosted(format!("HTTP request failed: {e}")))?; if response.status() >= 200 && response.status() < 300 { let body = response @@ -230,8 +228,7 @@ impl ClaimStore for RemoteClaimStore { fn save_claim(&self, claim: &AuthoredClaim) -> Result<(), AphoriaError> { let request = CreateClaimRequest { claim: claim_to_dto(claim) }; - let response: CreateClaimResponse = - self.request("POST", "/v1/claims", Some(&request))?; + let response: CreateClaimResponse = self.request("POST", "/v1/claims", Some(&request))?; if response.stored { info!(claim_id = %claim.id, "Claim stored remotely"); @@ -324,10 +321,9 @@ impl RemoteClaimStore { warn!(operation, "Remote unreachable, using cached claims"); fallback() } - OfflineFallback::Fail => Err(AphoriaError::Hosted(format!( - "{}: remote unreachable", - operation - ))), + OfflineFallback::Fail => { + Err(AphoriaError::Hosted(format!("{}: remote unreachable", operation))) + } OfflineFallback::Queue => { warn!(operation, "Remote unreachable, queue not implemented (using cache)"); fallback() @@ -425,14 +421,11 @@ fn is_network_error(err: &AphoriaError) -> bool { #[cfg(test)] mod tests { use super::*; - use crate::config::types::hosted::SyncMode; + use crate::SyncMode; #[test] fn test_remote_store_requires_url() { - let config = HostedConfig { - url: None, - ..Default::default() - }; + let config = HostedConfig { url: None, ..Default::default() }; let result = RemoteClaimStore::new(&config); assert!(result.is_err()); @@ -474,6 +467,7 @@ mod tests { let config = HostedConfig { url: Some("https://example.com".to_string()), project_id: Some("test-project".to_string()), + team_id: None, api_key_env: "TEST_API_KEY".to_string(), sync_mode: SyncMode::RemoteOnly, offline_fallback: OfflineFallback::Skip, diff --git a/applications/aphoria/src/report/json.rs b/applications/aphoria/src/report/json.rs index f25c83b..e300550 100644 --- a/applications/aphoria/src/report/json.rs +++ b/applications/aphoria/src/report/json.rs @@ -98,8 +98,8 @@ impl ReportFormatter for JsonReport { // Add tier-aware verdict if available if let Some(ref tier_verdict) = conflict.tier_verdict { - conflict_json["tier_verdict"] = serde_json::to_value(tier_verdict) - .unwrap_or(serde_json::Value::Null); + conflict_json["tier_verdict"] = + serde_json::to_value(tier_verdict).unwrap_or(serde_json::Value::Null); } // Add primary tier if available diff --git a/applications/aphoria/src/resolution/tier_verdict.rs b/applications/aphoria/src/resolution/tier_verdict.rs index aac6aac..a89c8ed 100644 --- a/applications/aphoria/src/resolution/tier_verdict.rs +++ b/applications/aphoria/src/resolution/tier_verdict.rs @@ -87,7 +87,9 @@ impl TierAwareVerdict { /// Returns a human-readable string describing the tier-aware verdict. pub fn display(&self) -> String { match self { - TierAwareVerdict::SingleTier { tier_name, verdict, sources, max_confidence, .. } => { + TierAwareVerdict::SingleTier { + tier_name, verdict, sources, max_confidence, .. + } => { format!( "{} {} - {} source{}, max confidence {:.2}", verdict.symbol(), @@ -159,12 +161,7 @@ impl TierAwareVerdict { }) .collect(); - Self::MultiTier { - primary_tier, - primary_verdict, - tier_verdicts, - conflict_score, - } + Self::MultiTier { primary_tier, primary_verdict, tier_verdicts, conflict_score } } } @@ -250,8 +247,7 @@ mod tests { }, ); - let verdict = - TierAwareVerdict::from_multi_tier(&tier_breakdown, 1, Verdict::Block, 0.92); + let verdict = TierAwareVerdict::from_multi_tier(&tier_breakdown, 1, Verdict::Block, 0.92); assert_eq!(verdict.effective_verdict(), Verdict::Block); assert_eq!(verdict.primary_tier(), 1); diff --git a/applications/aphoria/src/types/result.rs b/applications/aphoria/src/types/result.rs index fbee63e..35576a8 100644 --- a/applications/aphoria/src/types/result.rs +++ b/applications/aphoria/src/types/result.rs @@ -235,11 +235,7 @@ impl fmt::Display for ConflictResult { writeln!(f, " {} {}", verdict_str, self.claim.concept_path)?; } - writeln!( - f, - " Concept: {}", - self.claim.concept_path - )?; + writeln!(f, " Concept: {}", self.claim.concept_path)?; writeln!( f, " Your code: {} ({}: L{})", diff --git a/applications/stemedb-dashboard/src/app/layered/page.tsx b/applications/stemedb-dashboard/src/app/layered/page.tsx index 08bd2cd..f84077e 100644 --- a/applications/stemedb-dashboard/src/app/layered/page.tsx +++ b/applications/stemedb-dashboard/src/app/layered/page.tsx @@ -1,12 +1,23 @@ import { Header } from "@/components/layout/header"; import { LayeredQueryResults } from "@/components/layered"; -export default function LayeredPage() { +interface LayeredPageProps { + searchParams: Promise<{ subject?: string; predicate?: string }>; +} + +export default async function LayeredPage({ searchParams }: LayeredPageProps) { + const params = await searchParams; + const initialSubject = params.subject; + const initialPredicate = params.predicate; + return ( <>
- +
); diff --git a/applications/stemedb-dashboard/src/app/skeptic/page.tsx b/applications/stemedb-dashboard/src/app/skeptic/page.tsx index 6339872..fc5db5d 100644 --- a/applications/stemedb-dashboard/src/app/skeptic/page.tsx +++ b/applications/stemedb-dashboard/src/app/skeptic/page.tsx @@ -1,12 +1,26 @@ +"use client"; + +import { useSearchParams } from "next/navigation"; +import { Suspense } from "react"; import { Header } from "@/components/layout/header"; import { QueryResults } from "@/components/skeptic"; +function SkepticContent() { + const searchParams = useSearchParams(); + const subject = searchParams.get("subject") ?? undefined; + const predicate = searchParams.get("predicate") ?? undefined; + + return ; +} + export default function SkepticPage() { return ( <>
- + Loading...
}> + + ); diff --git a/applications/stemedb-dashboard/src/components/audit/audit-panel.tsx b/applications/stemedb-dashboard/src/components/audit/audit-panel.tsx index 7eea8a9..bba9b68 100644 --- a/applications/stemedb-dashboard/src/components/audit/audit-panel.tsx +++ b/applications/stemedb-dashboard/src/components/audit/audit-panel.tsx @@ -29,14 +29,14 @@ export function AuditPanel({ initialFilters }: AuditPanelProps) { try { const client = new StemeDBClient(); - // Convert time range to from/to timestamps + // Convert time range to from/to timestamps (Unix seconds — backend uses seconds, not ms) let fromTs: number | undefined; let toTs: number | undefined; if (currentFilters.timeRange !== "all") { - const now = Date.now(); - const rangeMs = TIME_RANGES_MS[currentFilters.timeRange as TimeRangeKey] ?? TIME_RANGES_MS["24h"]; - fromTs = now - rangeMs; - toTs = now; + const nowSecs = Math.floor(Date.now() / 1000); + const rangeSecs = Math.floor((TIME_RANGES_MS[currentFilters.timeRange as TimeRangeKey] ?? TIME_RANGES_MS["24h"]) / 1000); + fromTs = nowSecs - rangeSecs; + toTs = nowSecs; } const data = await client.auditQueries({ diff --git a/applications/stemedb-dashboard/src/components/audit/audit-row.tsx b/applications/stemedb-dashboard/src/components/audit/audit-row.tsx index e47194b..f9ce774 100644 --- a/applications/stemedb-dashboard/src/components/audit/audit-row.tsx +++ b/applications/stemedb-dashboard/src/components/audit/audit-row.tsx @@ -1,6 +1,7 @@ "use client"; -import { useState } from "react"; +import { useState, useCallback } from "react"; +import Link from "next/link"; import type { AuditEntry } from "@/lib/api/types"; import { formatTime, formatDate } from "@/lib/format"; import { ResultBadge } from "./result-badge"; @@ -10,6 +11,36 @@ interface AuditRowProps { entry: AuditEntry; } +function CopyableHash({ hash, label }: { hash: string; label?: string }) { + const [copied, setCopied] = useState(false); + + const handleCopy = useCallback( + (e: React.MouseEvent) => { + e.stopPropagation(); + navigator.clipboard.writeText(hash).then(() => { + setCopied(true); + setTimeout(() => setCopied(false), 1500); + }); + }, + [hash] + ); + + return ( + + ); +} + export function AuditRow({ entry }: AuditRowProps) { const [expanded, setExpanded] = useState(false); @@ -30,6 +61,15 @@ export function AuditRow({ entry }: AuditRowProps) { ? `${entry.agent_id.slice(0, 8)}...` : "-"; + // Build cross-navigation URLs when subject is present + const hasSubject = Boolean(entry.params.subject); + const crossNavParams = hasSubject + ? new URLSearchParams({ + subject: entry.params.subject!, + ...(entry.params.predicate ? { predicate: entry.params.predicate } : {}), + }).toString() + : null; + return (
-
+
+ {/* Metadata grid */}
Query ID: @@ -107,16 +148,51 @@ export function AuditRow({ entry }: AuditRowProps) { {entry.contributing_assertions.length}
+ + {/* Contributing assertions */} {entry.contributing_assertions.length > 0 && ( -
- Top contributors: -
- {entry.contributing_assertions.slice(0, 3).map((ca) => ( -
- {ca.assertion_hash.slice(0, 12)}... (weight: {(ca.weight * 100).toFixed(0)}%) -
- ))} +
+
+ Assertion Hash + Source Hash + Lifecycle / Weight
+ {entry.contributing_assertions.slice(0, 3).map((ca) => ( +
+ + + + + {ca.lifecycle} + + {(ca.weight * 100).toFixed(0)}% + +
+ ))} +
+ )} + + {/* Cross-navigation links */} + {hasSubject && crossNavParams && ( +
e.stopPropagation()} + > + + View in Skeptic → + + + View in Layered → +
)}
diff --git a/applications/stemedb-dashboard/src/components/feed/feed-row.tsx b/applications/stemedb-dashboard/src/components/feed/feed-row.tsx index a2c2611..8c66879 100644 --- a/applications/stemedb-dashboard/src/components/feed/feed-row.tsx +++ b/applications/stemedb-dashboard/src/components/feed/feed-row.tsx @@ -1,6 +1,7 @@ "use client"; import { useState } from "react"; +import Link from "next/link"; import type { AssertionObject } from "@/lib/api/types"; import { formatRelativeTime, formatUnixDateTime } from "@/lib/format"; import { Badge } from "@/components/ui/badge"; @@ -26,6 +27,10 @@ function formatValue(obj: { type: string; value: string | number | boolean }): s return str.length > 60 ? `${str.slice(0, 57)}...` : str; } +function investigateHref(entry: AssertionObject): string { + return `/skeptic?subject=${encodeURIComponent(entry.subject)}&predicate=${encodeURIComponent(entry.predicate)}`; +} + export function FeedRow({ entry }: FeedRowProps) { const [expanded, setExpanded] = useState(false); @@ -34,11 +39,13 @@ export function FeedRow({ entry }: FeedRowProps) { return (
setExpanded(!expanded)} + className="rounded-lg border border-border transition-colors" > {/* Main row */} -
+
setExpanded(!expanded)} + > {/* Time */}
{formatRelativeTime(entry.timestamp)} @@ -66,20 +73,36 @@ export function FeedRow({ entry }: FeedRowProps) { {formatValue(entry.object)}
- {/* Source Class */} + {/* Source Class + Investigate icon */}
{entry.source_class} - - {expanded ? "\u25B2" : "\u25BC"} - +
+ e.stopPropagation()} + > + + + + + + + {expanded ? "\u25B2" : "\u25BC"} + +
{/* Expanded details */} {expanded && ( -
+
e.stopPropagation()} + >
@@ -116,6 +139,29 @@ export function FeedRow({ entry }: FeedRowProps) {
)} + {/* Narrative */} + {entry.narrative && ( +
+ Narrative: +

+ {entry.narrative} +

+
+ )} + {/* Investigate link */} +
+ e.stopPropagation()} + > + + + + + Investigate in Skeptic + +
)} diff --git a/applications/stemedb-dashboard/src/components/layered/layered-query-results.tsx b/applications/stemedb-dashboard/src/components/layered/layered-query-results.tsx index 3c39b20..2951a2b 100644 --- a/applications/stemedb-dashboard/src/components/layered/layered-query-results.tsx +++ b/applications/stemedb-dashboard/src/components/layered/layered-query-results.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState, useCallback } from "react"; +import { useState, useCallback, useEffect, useRef } from "react"; import { StemeDBClient, type LayeredResponse, ApiError } from "@/lib/api"; import { QueryForm, type QueryParams, EmptyState, ErrorState } from "@/components/skeptic"; import { LayeredLoadingSkeleton } from "./layered-loading-skeleton"; @@ -12,8 +12,14 @@ type QueryState = | { status: "success"; data: LayeredResponse; params: QueryParams } | { status: "error"; error: string; params: QueryParams }; -export function LayeredQueryResults() { +interface LayeredQueryResultsProps { + initialSubject?: string; + initialPredicate?: string; +} + +export function LayeredQueryResults({ initialSubject, initialPredicate }: LayeredQueryResultsProps) { const [state, setState] = useState({ status: "idle" }); + const hasAutoQueried = useRef(false); const executeQuery = useCallback(async (params: QueryParams) => { setState({ status: "loading", params }); @@ -33,6 +39,18 @@ export function LayeredQueryResults() { } }, []); + // Auto-execute query when initial subject+predicate are provided (e.g., from audit trail links) + useEffect(() => { + if (initialSubject && initialPredicate && !hasAutoQueried.current) { + hasAutoQueried.current = true; + executeQuery({ + subject: initialSubject, + predicate: initialPredicate, + includeSourceMetadata: true, + }); + } + }, [initialSubject, initialPredicate, executeQuery]); + const handleRetry = useCallback(() => { if (state.status === "error") { executeQuery(state.params); @@ -48,7 +66,12 @@ export function LayeredQueryResults() {

Layered Consensus Query

- +
{/* Results Section */} diff --git a/applications/stemedb-dashboard/src/components/layered/layered-results-view.tsx b/applications/stemedb-dashboard/src/components/layered/layered-results-view.tsx index 4a00af1..a0d486b 100644 --- a/applications/stemedb-dashboard/src/components/layered/layered-results-view.tsx +++ b/applications/stemedb-dashboard/src/components/layered/layered-results-view.tsx @@ -112,6 +112,11 @@ export function LayeredResultsView({ data }: LayeredResultsViewProps) {

Confidence: {(data.overall_winner.confidence * 100).toFixed(0)}%

+ {data.overall_winner.narrative && ( +

+ {data.overall_winner.narrative} +

+ )}
)} diff --git a/applications/stemedb-dashboard/src/components/layered/tier-accordion.tsx b/applications/stemedb-dashboard/src/components/layered/tier-accordion.tsx index 87a6a14..74f5001 100644 --- a/applications/stemedb-dashboard/src/components/layered/tier-accordion.tsx +++ b/applications/stemedb-dashboard/src/components/layered/tier-accordion.tsx @@ -1,7 +1,10 @@ "use client"; +import { useState, useEffect } from "react"; +import Link from "next/link"; import { cn } from "@/lib/utils"; -import type { LayeredTier } from "@/lib/api/types"; +import type { LayeredTier, SourceRecordDto } from "@/lib/api/types"; +import { StemeDBClient } from "@/lib/api"; import { SourceTierBadge, ConflictGauge, tierLabels, type SourceTier } from "@/components/skeptic"; function getConflictStatus(score: number): "Unanimous" | "Agreed" | "Contested" { @@ -10,6 +13,17 @@ function getConflictStatus(score: number): "Unanimous" | "Agreed" | "Contested" return "Contested"; } +function formatTimestamp(unixSeconds: number): string { + const date = new Date(unixSeconds * 1000); + return date.toLocaleString(undefined, { + year: "numeric", + month: "short", + day: "numeric", + hour: "2-digit", + minute: "2-digit", + }); +} + interface TierAccordionProps { tier: LayeredTier; isExpanded: boolean; @@ -21,6 +35,20 @@ export function TierAccordion({ tier, isExpanded, onToggle }: TierAccordionProps const tierLabel = tierLabels[safeTier] || tier.source_class; const conflictStatus = getConflictStatus(tier.conflict_score); + const [sourceRecord, setSourceRecord] = useState(null); + const [sourceLoading, setSourceLoading] = useState(false); + + useEffect(() => { + if (!isExpanded || !tier.winner || sourceRecord || sourceLoading) return; + setSourceLoading(true); + const client = new StemeDBClient(); + client + .getSource(tier.winner.source_hash) + .then(setSourceRecord) + .catch(() => {}) + .finally(() => setSourceLoading(false)); + }, [isExpanded, tier.winner, sourceRecord, sourceLoading]); + return (
+ + {/* Assertion timestamp */} +
+
+ Asserted at +

+ {formatTimestamp(tier.winner.timestamp)}

+ {/* Narrative */} + {tier.winner.narrative && ( +
+ Narrative +

+ {tier.winner.narrative} +

+
+ )} + + {/* Source registry details */} + {sourceLoading && ( +
+

+ Loading source details... +

+
+ )} + {!sourceLoading && sourceRecord && ( +
+
+ + Source Registry + + + View in Source Registry → + +
+
+
+ Label +

{sourceRecord.label}

+
+
+ Status +

{sourceRecord.status}

+
+ {sourceRecord.url && ( + + )} + {sourceRecord.notes && ( +
+ Notes +

{sourceRecord.notes}

+
+ )} +
+ Created +

{formatTimestamp(sourceRecord.created_at)}

+
+
+ Updated +

{formatTimestamp(sourceRecord.updated_at)}

+
+
+
+ )} + {/* Assertion hash */}
Assertion: diff --git a/applications/stemedb-dashboard/src/components/skeptic/claim-row.tsx b/applications/stemedb-dashboard/src/components/skeptic/claim-row.tsx index 6320a93..31e8d87 100644 --- a/applications/stemedb-dashboard/src/components/skeptic/claim-row.tsx +++ b/applications/stemedb-dashboard/src/components/skeptic/claim-row.tsx @@ -1,7 +1,10 @@ "use client"; +import { useState, useEffect } from "react"; +import Link from "next/link"; import { cn } from "@/lib/utils"; -import type { ClaimSummary } from "@/lib/api/types"; +import type { ClaimSummary, SourceRecordDto } from "@/lib/api/types"; +import { StemeDBClient } from "@/lib/api"; import { SourceTierBadge } from "./source-tier-badge"; import { WeightBar } from "./weight-bar"; import { HashDisplay } from "./hash-display"; @@ -33,6 +36,23 @@ export function ClaimRow({ claim, isLeading, isExpanded, onToggle }: ClaimRowPro : "active") as SourceStatus; const valueStr = formatValue(claim.value); + // Fetch full source record when expanded + const [sourceRecord, setSourceRecord] = useState(null); + const [sourceLoading, setSourceLoading] = useState(false); + + useEffect(() => { + if (!isExpanded || sourceRecord || sourceLoading) return; + setSourceLoading(true); + const client = new StemeDBClient(); + client + .getSource(claim.source.source_hash) + .then(setSourceRecord) + .catch(() => { + // Source may not be in registry — that's fine + }) + .finally(() => setSourceLoading(false)); + }, [isExpanded, claim.source.source_hash, sourceRecord, sourceLoading]); + return (
+ {/* Full value */} +
+
+ Value +
+

+ {valueStr} +

+
+ Type: {claim.value.type} +
+
+ {/* Source info */}
@@ -98,7 +131,7 @@ export function ClaimRow({ claim, isLeading, isExpanded, onToggle }: ClaimRowPro {statusIcons[status]} {status} - + · {tierLabel} (T{tier}) @@ -113,6 +146,33 @@ export function ClaimRow({ claim, isLeading, isExpanded, onToggle }: ClaimRowPro {sourceUrl} )} + {/* Source registry details (fetched) */} + {sourceLoading && ( +
+ Loading source details... +
+ )} + {sourceRecord && ( +
+ {sourceRecord.notes && ( +

+ {sourceRecord.notes} +

+ )} +
+ Created: {new Date(sourceRecord.created_at).toLocaleDateString()} + {sourceRecord.updated_at !== sourceRecord.created_at && ( + Updated: {new Date(sourceRecord.updated_at).toLocaleDateString()} + )} +
+ + View in Source Registry → + +
+ )}
{/* Supporting agents */} diff --git a/applications/stemedb-dashboard/src/components/skeptic/query-form.tsx b/applications/stemedb-dashboard/src/components/skeptic/query-form.tsx index a00feee..fb2c21a 100644 --- a/applications/stemedb-dashboard/src/components/skeptic/query-form.tsx +++ b/applications/stemedb-dashboard/src/components/skeptic/query-form.tsx @@ -1,9 +1,10 @@ "use client"; -import { useState } from "react"; +import { useState, useEffect, useRef, useCallback } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { DatePicker } from "@/components/ui/date-picker"; +import { StemeDBClient } from "@/lib/api"; export interface QueryParams { subject: string; @@ -15,22 +16,162 @@ export interface QueryParams { interface QueryFormProps { onSubmit: (params: QueryParams) => void; isLoading: boolean; + initialSubject?: string; + initialPredicate?: string; } -export function QueryForm({ onSubmit, isLoading }: QueryFormProps) { - const [subject, setSubject] = useState(""); - const [predicate, setPredicate] = useState(""); +export function QueryForm({ onSubmit, isLoading, initialSubject, initialPredicate }: QueryFormProps) { + const [subject, setSubject] = useState(initialSubject ?? ""); + const [predicate, setPredicate] = useState(initialPredicate ?? ""); const [includeSourceMetadata, setIncludeSourceMetadata] = useState(true); const [asOfDate, setAsOfDate] = useState(undefined); + // Autocomplete state + const [subjectSuggestions, setSubjectSuggestions] = useState([]); + const [predicateSuggestions, setPredicateSuggestions] = useState([]); + const [showSubjectDropdown, setShowSubjectDropdown] = useState(false); + const [showPredicateDropdown, setShowPredicateDropdown] = useState(false); + const [activeSubjectIndex, setActiveSubjectIndex] = useState(-1); + const [activePredicateIndex, setActivePredicateIndex] = useState(-1); + + const subjectRef = useRef(null); + const predicateRef = useRef(null); + const debounceRef = useRef | null>(null); + + // Sync initial values when they change (e.g., from URL params) + useEffect(() => { + if (initialSubject !== undefined) setSubject(initialSubject); + }, [initialSubject]); + + useEffect(() => { + if (initialPredicate !== undefined) setPredicate(initialPredicate); + }, [initialPredicate]); + + // Fetch subject suggestions with debounce + const fetchSubjects = useCallback((query: string) => { + if (debounceRef.current) clearTimeout(debounceRef.current); + debounceRef.current = setTimeout(async () => { + if (!query.trim()) { + setSubjectSuggestions([]); + setShowSubjectDropdown(false); + return; + } + try { + const client = new StemeDBClient(); + const resp = await client.listSubjects(query, 20); + setSubjectSuggestions(resp.subjects); + setShowSubjectDropdown(resp.subjects.length > 0); + setActiveSubjectIndex(-1); + } catch { + setSubjectSuggestions([]); + setShowSubjectDropdown(false); + } + }, 200); + }, []); + + // Fetch predicates when subject is selected + const fetchPredicates = useCallback(async (subj: string) => { + if (!subj.trim()) { + setPredicateSuggestions([]); + return; + } + try { + const client = new StemeDBClient(); + const resp = await client.listPredicates(subj); + setPredicateSuggestions(resp.predicates); + } catch { + setPredicateSuggestions([]); + } + }, []); + + // Close dropdowns on click outside + useEffect(() => { + function handleClickOutside(e: MouseEvent) { + if (subjectRef.current && !subjectRef.current.contains(e.target as Node)) { + setShowSubjectDropdown(false); + } + if (predicateRef.current && !predicateRef.current.contains(e.target as Node)) { + setShowPredicateDropdown(false); + } + } + document.addEventListener("mousedown", handleClickOutside); + return () => document.removeEventListener("mousedown", handleClickOutside); + }, []); + + const handleSubjectChange = (value: string) => { + setSubject(value); + fetchSubjects(value); + // Clear predicate suggestions when subject changes + setPredicateSuggestions([]); + }; + + const selectSubject = (value: string) => { + setSubject(value); + setShowSubjectDropdown(false); + setActiveSubjectIndex(-1); + fetchPredicates(value); + }; + + const handlePredicateChange = (value: string) => { + setPredicate(value); + // Filter existing predicate suggestions locally + if (predicateSuggestions.length > 0) { + setShowPredicateDropdown(true); + setActivePredicateIndex(-1); + } + }; + + const selectPredicate = (value: string) => { + setPredicate(value); + setShowPredicateDropdown(false); + setActivePredicateIndex(-1); + }; + + const filteredPredicates = predicateSuggestions.filter((p) => + p.toLowerCase().includes(predicate.toLowerCase()) + ); + + const handleSubjectKeyDown = (e: React.KeyboardEvent) => { + if (!showSubjectDropdown || subjectSuggestions.length === 0) return; + if (e.key === "ArrowDown") { + e.preventDefault(); + setActiveSubjectIndex((i) => Math.min(i + 1, subjectSuggestions.length - 1)); + } else if (e.key === "ArrowUp") { + e.preventDefault(); + setActiveSubjectIndex((i) => Math.max(i - 1, 0)); + } else if (e.key === "Enter" && activeSubjectIndex >= 0) { + e.preventDefault(); + selectSubject(subjectSuggestions[activeSubjectIndex]); + } else if (e.key === "Escape") { + setShowSubjectDropdown(false); + } + }; + + const handlePredicateKeyDown = (e: React.KeyboardEvent) => { + if (!showPredicateDropdown || filteredPredicates.length === 0) return; + if (e.key === "ArrowDown") { + e.preventDefault(); + setActivePredicateIndex((i) => Math.min(i + 1, filteredPredicates.length - 1)); + } else if (e.key === "ArrowUp") { + e.preventDefault(); + setActivePredicateIndex((i) => Math.max(i - 1, 0)); + } else if (e.key === "Enter" && activePredicateIndex >= 0) { + e.preventDefault(); + selectPredicate(filteredPredicates[activePredicateIndex]); + } else if (e.key === "Escape") { + setShowPredicateDropdown(false); + } + }; + const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); + setShowSubjectDropdown(false); + setShowPredicateDropdown(false); if (subject.trim() && predicate.trim()) { onSubmit({ subject: subject.trim(), predicate: predicate.trim(), includeSourceMetadata, - // Convert Date to Unix timestamp (seconds) asOf: asOfDate ? Math.floor(asOfDate.getTime() / 1000) : undefined, }); } @@ -41,32 +182,81 @@ export function QueryForm({ onSubmit, isLoading }: QueryFormProps) { return (
-
+ {/* Subject with autocomplete */} +
- setSubject(e.target.value)} - disabled={isLoading} - /> +
+ handleSubjectChange(e.target.value)} + onFocus={() => { + if (subjectSuggestions.length > 0) setShowSubjectDropdown(true); + }} + onKeyDown={handleSubjectKeyDown} + disabled={isLoading} + autoComplete="off" + /> + {showSubjectDropdown && subjectSuggestions.length > 0 && ( +
+ {subjectSuggestions.map((s, i) => ( + + ))} +
+ )} +

The entity you want to query

-
+ + {/* Predicate with autocomplete */} +
- setPredicate(e.target.value)} - disabled={isLoading} - /> +
+ handlePredicateChange(e.target.value)} + onFocus={() => { + if (filteredPredicates.length > 0) setShowPredicateDropdown(true); + }} + onKeyDown={handlePredicateKeyDown} + disabled={isLoading} + autoComplete="off" + /> + {showPredicateDropdown && filteredPredicates.length > 0 && ( +
+ {filteredPredicates.map((p, i) => ( + + ))} +
+ )} +

The property or relationship to analyze

diff --git a/applications/stemedb-dashboard/src/components/skeptic/query-results.tsx b/applications/stemedb-dashboard/src/components/skeptic/query-results.tsx index 6773a74..d434da6 100644 --- a/applications/stemedb-dashboard/src/components/skeptic/query-results.tsx +++ b/applications/stemedb-dashboard/src/components/skeptic/query-results.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState, useCallback } from "react"; +import { useState, useCallback, useEffect, useRef } from "react"; import { useRouter } from "next/navigation"; import { StemeDBClient, type SkepticResponse, ApiError } from "@/lib/api"; import { Button } from "@/components/ui/button"; @@ -20,9 +20,15 @@ type QueryState = | { status: "success"; data: SkepticResponse; params: QueryParams } | { status: "error"; error: string; params: QueryParams }; -export function QueryResults() { +interface QueryResultsProps { + initialSubject?: string; + initialPredicate?: string; +} + +export function QueryResults({ initialSubject, initialPredicate }: QueryResultsProps) { const [state, setState] = useState({ status: "idle" }); const router = useRouter(); + const hasAutoQueried = useRef(false); const handleViewAudit = useCallback( (subject: string, predicate: string) => { @@ -56,6 +62,18 @@ export function QueryResults() { } }, []); + // Auto-execute query when initial subject+predicate are provided (e.g., from URL params) + useEffect(() => { + if (initialSubject && initialPredicate && !hasAutoQueried.current) { + hasAutoQueried.current = true; + executeQuery({ + subject: initialSubject, + predicate: initialPredicate, + includeSourceMetadata: true, + }); + } + }, [initialSubject, initialPredicate, executeQuery]); + const handleRetry = useCallback(() => { if (state.status === "error") { executeQuery(state.params); @@ -71,7 +89,12 @@ export function QueryResults() {

Conflict Analysis Query

- +
{/* Results Section */} diff --git a/applications/stemedb-dashboard/src/components/sources/impact-detail-panel.tsx b/applications/stemedb-dashboard/src/components/sources/impact-detail-panel.tsx index 9357b80..c978172 100644 --- a/applications/stemedb-dashboard/src/components/sources/impact-detail-panel.tsx +++ b/applications/stemedb-dashboard/src/components/sources/impact-detail-panel.tsx @@ -1,8 +1,8 @@ "use client"; -import { useCallback } from "react"; -import { FileJson, FileText } from "lucide-react"; -import type { SourceImpactResponse } from "@/lib/api/types"; +import { useCallback, useEffect, useState } from "react"; +import { ChevronDown, ChevronUp, FileJson, FileText } from "lucide-react"; +import type { SourceImpactResponse, SourceRecordDto } from "@/lib/api/types"; import { StemeDBClient } from "@/lib/api"; import { Button } from "@/components/ui/button"; import { @@ -20,11 +20,90 @@ interface ImpactDetailPanelProps { onClose: () => void; } +function CopyableHash({ hash }: { hash: string }) { + const [copied, setCopied] = useState(false); + const handleCopy = () => { + navigator.clipboard.writeText(hash); + setCopied(true); + setTimeout(() => setCopied(false), 1500); + }; + return ( + + ); +} + +function CopyableAgent({ agent }: { agent: string }) { + const [copied, setCopied] = useState(false); + const handleCopy = () => { + navigator.clipboard.writeText(agent); + setCopied(true); + setTimeout(() => setCopied(false), 1500); + }; + return ( + + ); +} + +function StatusBadge({ status }: { status: string }) { + const colorMap: Record = { + active: "bg-green-500/15 text-green-700 dark:text-green-400", + inactive: "bg-muted text-muted-foreground", + quarantined: "bg-red-500/15 text-red-700 dark:text-red-400", + pending: "bg-yellow-500/15 text-yellow-700 dark:text-yellow-400", + }; + const classes = + colorMap[status.toLowerCase()] ?? "bg-muted text-muted-foreground"; + return ( + + {status} + + ); +} + export function ImpactDetailPanel({ isOpen, impact, onClose, }: ImpactDetailPanelProps) { + const [sourceRecord, setSourceRecord] = useState( + null + ); + const [contentExpanded, setContentExpanded] = useState(false); + + useEffect(() => { + if (isOpen && impact?.source_hash) { + const client = new StemeDBClient(); + client + .getSource(impact.source_hash) + .then(setSourceRecord) + .catch(() => setSourceRecord(null)); + } else { + setSourceRecord(null); + setContentExpanded(false); + } + }, [isOpen, impact?.source_hash]); + const handleExport = useCallback( (format: "csv" | "json") => { if (!impact) return; @@ -54,6 +133,35 @@ export function ImpactDetailPanel({ {impact ? (
+ {/* Source Info */} +
+
+ + Source + + +
+
+ +
+
+
+ + Assertions + + + {impact.assertion_count} + +
+
+ Agents + + {impact.affected_agents.length} + +
+
+
+ {/* Export buttons - only when there's data to export */} {impact.assertion_count > 0 && (
@@ -84,31 +192,60 @@ export function ImpactDetailPanel({

{impact.summary}

+ {/* Source Content */} + {sourceRecord?.content && ( +
+
+

+ Source Content + + ({sourceRecord.content.length.toLocaleString()} chars) + +

+ +
+
+
+                    {sourceRecord.content}
+                  
+
+
+ )} + {/* Affected Assertions */} {impact.affected_assertions.length > 0 && (

Affected Assertions ({impact.affected_assertions.length})

-
- - - - - - - - {impact.affected_assertions.map((hash) => ( - - - - ))} - -
- Hash -
- {hash} -
+
+ {impact.affected_assertions.map((hash, idx) => ( +
+ +
+ ))}
)} @@ -121,12 +258,7 @@ export function ImpactDetailPanel({
{impact.affected_agents.map((agent) => ( - - {agent} - + ))}
diff --git a/applications/stemedb-dashboard/src/components/sources/source-row.tsx b/applications/stemedb-dashboard/src/components/sources/source-row.tsx index 84199f9..239a906 100644 --- a/applications/stemedb-dashboard/src/components/sources/source-row.tsx +++ b/applications/stemedb-dashboard/src/components/sources/source-row.tsx @@ -1,5 +1,6 @@ "use client"; +import Link from "next/link"; import { ExternalLink, Eye, Ban, RotateCcw } from "lucide-react"; import type { SourceRecordDto } from "@/lib/api/types"; import { Button } from "@/components/ui/button"; @@ -8,6 +9,7 @@ import { TierBadge } from "./tier-badge"; interface SourceRowProps { source: SourceRecordDto; + assertionCount?: number; onViewImpact: (source: SourceRecordDto) => void; onBlock: (source: SourceRecordDto) => void; onRestore: (source: SourceRecordDto) => void; @@ -15,6 +17,7 @@ interface SourceRowProps { export function SourceRow({ source, + assertionCount, onViewImpact, onBlock, onRestore, @@ -43,6 +46,17 @@ export function SourceRow({ {updatedDate !== createdDate && ( Updated: {updatedDate} )} + {assertionCount !== undefined && ( + + {assertionCount.toLocaleString()} assertions + + )} + + View Feed → +
{source.url && ( diff --git a/applications/stemedb-dashboard/src/components/sources/sources-panel.tsx b/applications/stemedb-dashboard/src/components/sources/sources-panel.tsx index f03a9a6..937c45d 100644 --- a/applications/stemedb-dashboard/src/components/sources/sources-panel.tsx +++ b/applications/stemedb-dashboard/src/components/sources/sources-panel.tsx @@ -35,6 +35,9 @@ export function SourcesPanel() { const [impact, setImpact] = useState(null); const [isLoadingImpact, setIsLoadingImpact] = useState(false); const [isProcessing, setIsProcessing] = useState(false); + const [assertionCounts, setAssertionCounts] = useState>( + new Map() + ); const fetchData = useCallback(async () => { setState({ status: "loading" }); @@ -66,6 +69,31 @@ export function SourcesPanel() { fetchData(); }, [fetchData]); + // Lazily fetch assertion counts for all sources after list loads + useEffect(() => { + if (state.status !== "success" || state.data.sources.length === 0) return; + + const sources = state.data.sources; + const client = new StemeDBClient(); + + const fetches = sources.map((source) => + client + .getSourceImpact(source.hash) + .then((data) => ({ hash: source.hash, count: data.assertion_count })) + .catch(() => null) + ); + + Promise.allSettled(fetches).then((results) => { + const counts = new Map(); + for (const result of results) { + if (result.status === "fulfilled" && result.value !== null) { + counts.set(result.value.hash, result.value.count); + } + } + setAssertionCounts(counts); + }); + }, [state]); + // Fetch impact when block dialog opens useEffect(() => { if (dialogState.type === "block") { @@ -221,6 +249,7 @@ export function SourcesPanel() { (`/v1/feed?${params}`); } + async listSubjects(q?: string, limit = 100): Promise { + const params = new URLSearchParams({ limit: String(limit) }); + if (q) params.set("q", q); + return this.fetch(`/v1/subjects?${params}`); + } + + async listPredicates(subject: string): Promise { + return this.fetch( + `/v1/subjects/${encodeURIComponent(subject)}/predicates` + ); + } + async health(): Promise { return this.fetch("/health"); } @@ -160,6 +175,10 @@ export class StemeDBClient { return this.fetch(`/v1/sources?${params}`); } + async getSource(hash: string): Promise { + return this.fetch(`/v1/sources/${encodeURIComponent(hash)}`); + } + async getSourceImpact(hash: string): Promise { return this.fetch(`/v1/sources/${hash}/impact`); } diff --git a/applications/stemedb-dashboard/src/lib/api/types.ts b/applications/stemedb-dashboard/src/lib/api/types.ts index 084b142..2599a9a 100644 --- a/applications/stemedb-dashboard/src/lib/api/types.ts +++ b/applications/stemedb-dashboard/src/lib/api/types.ts @@ -62,6 +62,7 @@ export interface AssertionObject { timestamp: number; version: number; }>; + narrative?: string; } export interface LayeredTier { @@ -209,6 +210,7 @@ export interface SourceRecordDto { status: "active" | "deprecated" | "quarantined"; url?: string; notes?: string; + content?: string; created_at: number; updated_at: number; } @@ -347,6 +349,17 @@ export interface FeedResponse { has_more: boolean; } +// Discovery types (subject/predicate autocomplete) +export interface ListSubjectsResponse { + subjects: string[]; + total_count: number; +} + +export interface ListPredicatesResponse { + subject: string; + predicates: string[]; +} + export class ApiError extends Error { public userMessage: string; diff --git a/applications/stemedb-dashboard/tsconfig.tsbuildinfo b/applications/stemedb-dashboard/tsconfig.tsbuildinfo index d7c94f5..52d929f 100644 --- a/applications/stemedb-dashboard/tsconfig.tsbuildinfo +++ b/applications/stemedb-dashboard/tsconfig.tsbuildinfo @@ -1 +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.es2021.d.ts","./node_modules/typescript/lib/lib.es2022.d.ts","./node_modules/typescript/lib/lib.es2023.d.ts","./node_modules/typescript/lib/lib.es2024.d.ts","./node_modules/typescript/lib/lib.esnext.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.es2021.promise.d.ts","./node_modules/typescript/lib/lib.es2021.string.d.ts","./node_modules/typescript/lib/lib.es2021.weakref.d.ts","./node_modules/typescript/lib/lib.es2021.intl.d.ts","./node_modules/typescript/lib/lib.es2022.array.d.ts","./node_modules/typescript/lib/lib.es2022.error.d.ts","./node_modules/typescript/lib/lib.es2022.intl.d.ts","./node_modules/typescript/lib/lib.es2022.object.d.ts","./node_modules/typescript/lib/lib.es2022.string.d.ts","./node_modules/typescript/lib/lib.es2022.regexp.d.ts","./node_modules/typescript/lib/lib.es2023.array.d.ts","./node_modules/typescript/lib/lib.es2023.collection.d.ts","./node_modules/typescript/lib/lib.es2023.intl.d.ts","./node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts","./node_modules/typescript/lib/lib.es2024.collection.d.ts","./node_modules/typescript/lib/lib.es2024.object.d.ts","./node_modules/typescript/lib/lib.es2024.promise.d.ts","./node_modules/typescript/lib/lib.es2024.regexp.d.ts","./node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2024.string.d.ts","./node_modules/typescript/lib/lib.esnext.array.d.ts","./node_modules/typescript/lib/lib.esnext.collection.d.ts","./node_modules/typescript/lib/lib.esnext.intl.d.ts","./node_modules/typescript/lib/lib.esnext.disposable.d.ts","./node_modules/typescript/lib/lib.esnext.promise.d.ts","./node_modules/typescript/lib/lib.esnext.decorators.d.ts","./node_modules/typescript/lib/lib.esnext.iterator.d.ts","./node_modules/typescript/lib/lib.esnext.float16.d.ts","./node_modules/typescript/lib/lib.esnext.error.d.ts","./node_modules/typescript/lib/lib.esnext.sharedmemory.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/next/dist/styled-jsx/types/css.d.ts","./node_modules/next/dist/styled-jsx/types/macro.d.ts","./node_modules/next/dist/styled-jsx/types/style.d.ts","./node_modules/next/dist/styled-jsx/types/global.d.ts","./node_modules/next/dist/styled-jsx/types/index.d.ts","./node_modules/next/dist/server/get-page-files.d.ts","./node_modules/@types/node/compatibility/disposable.d.ts","./node_modules/@types/node/compatibility/indexable.d.ts","./node_modules/@types/node/compatibility/iterators.d.ts","./node_modules/@types/node/compatibility/index.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/domexception.d.ts","./node_modules/@types/node/web-globals/events.d.ts","./node_modules/undici-types/header.d.ts","./node_modules/undici-types/readable.d.ts","./node_modules/undici-types/file.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.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/agent.d.ts","./node_modules/undici-types/mock-interceptor.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/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/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/filereader.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/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.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/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/canary.d.ts","./node_modules/@types/react/experimental.d.ts","./node_modules/@types/react-dom/index.d.ts","./node_modules/@types/react-dom/canary.d.ts","./node_modules/@types/react-dom/experimental.d.ts","./node_modules/next/dist/lib/fallback.d.ts","./node_modules/next/dist/compiled/webpack/webpack.d.ts","./node_modules/next/dist/shared/lib/modern-browserslist-target.d.ts","./node_modules/next/dist/shared/lib/entry-constants.d.ts","./node_modules/next/dist/shared/lib/constants.d.ts","./node_modules/next/dist/server/config.d.ts","./node_modules/next/dist/lib/load-custom-routes.d.ts","./node_modules/next/dist/shared/lib/image-config.d.ts","./node_modules/next/dist/build/webpack/plugins/subresource-integrity-plugin.d.ts","./node_modules/next/dist/server/body-streams.d.ts","./node_modules/next/dist/server/lib/cache-control.d.ts","./node_modules/next/dist/lib/setup-exception-listeners.d.ts","./node_modules/next/dist/lib/worker.d.ts","./node_modules/next/dist/lib/constants.d.ts","./node_modules/next/dist/lib/bundler.d.ts","./node_modules/next/dist/server/lib/experimental/ppr.d.ts","./node_modules/next/dist/lib/page-types.d.ts","./node_modules/next/dist/build/segment-config/app/app-segment-config.d.ts","./node_modules/next/dist/build/segment-config/pages/pages-segment-config.d.ts","./node_modules/next/dist/build/analysis/get-page-static-info.d.ts","./node_modules/next/dist/build/webpack/loaders/get-module-build-info.d.ts","./node_modules/next/dist/build/webpack/plugins/middleware-plugin.d.ts","./node_modules/next/dist/server/require-hook.d.ts","./node_modules/next/dist/server/node-polyfill-crypto.d.ts","./node_modules/next/dist/server/node-environment-baseline.d.ts","./node_modules/next/dist/server/node-environment-extensions/error-inspect.d.ts","./node_modules/next/dist/server/node-environment-extensions/console-file.d.ts","./node_modules/next/dist/server/node-environment-extensions/console-exit.d.ts","./node_modules/next/dist/server/node-environment-extensions/console-dim.external.d.ts","./node_modules/next/dist/server/node-environment-extensions/unhandled-rejection.d.ts","./node_modules/next/dist/server/node-environment-extensions/random.d.ts","./node_modules/next/dist/server/node-environment-extensions/date.d.ts","./node_modules/next/dist/server/node-environment-extensions/web-crypto.d.ts","./node_modules/next/dist/server/node-environment-extensions/node-crypto.d.ts","./node_modules/next/dist/server/node-environment-extensions/fast-set-immediate.external.d.ts","./node_modules/next/dist/server/node-environment.d.ts","./node_modules/next/dist/build/page-extensions-type.d.ts","./node_modules/next/dist/server/route-kind.d.ts","./node_modules/next/dist/server/route-definitions/route-definition.d.ts","./node_modules/next/dist/server/route-definitions/app-page-route-definition.d.ts","./node_modules/next/dist/server/lib/cache-handlers/types.d.ts","./node_modules/next/dist/server/response-cache/types.d.ts","./node_modules/next/dist/server/resume-data-cache/cache-store.d.ts","./node_modules/next/dist/server/resume-data-cache/resume-data-cache.d.ts","./node_modules/next/dist/client/components/app-router-headers.d.ts","./node_modules/next/dist/server/render-result.d.ts","./node_modules/next/dist/server/instrumentation/types.d.ts","./node_modules/next/dist/lib/coalesced-function.d.ts","./node_modules/next/dist/shared/lib/router/utils/middleware-route-matcher.d.ts","./node_modules/next/dist/server/lib/router-utils/types.d.ts","./node_modules/next/dist/trace/types.d.ts","./node_modules/next/dist/trace/trace.d.ts","./node_modules/next/dist/trace/shared.d.ts","./node_modules/next/dist/trace/index.d.ts","./node_modules/next/dist/build/load-jsconfig.d.ts","./node_modules/@next/env/dist/index.d.ts","./node_modules/next/dist/build/webpack/plugins/telemetry-plugin/use-cache-tracker-utils.d.ts","./node_modules/next/dist/build/webpack/plugins/telemetry-plugin/telemetry-plugin.d.ts","./node_modules/next/dist/telemetry/storage.d.ts","./node_modules/next/dist/build/build-context.d.ts","./node_modules/next/dist/shared/lib/bloom-filter.d.ts","./node_modules/next/dist/build/webpack-config.d.ts","./node_modules/next/dist/build/swc/generated-native.d.ts","./node_modules/next/dist/build/swc/types.d.ts","./node_modules/next/dist/server/dev/parse-version-info.d.ts","./node_modules/next/dist/next-devtools/shared/types.d.ts","./node_modules/next/dist/server/dev/dev-indicator-server-state.d.ts","./node_modules/next/dist/next-devtools/dev-overlay/cache-indicator.d.ts","./node_modules/next/dist/server/lib/parse-stack.d.ts","./node_modules/next/dist/next-devtools/server/shared.d.ts","./node_modules/next/dist/next-devtools/shared/stack-frame.d.ts","./node_modules/next/dist/next-devtools/dev-overlay/utils/get-error-by-type.d.ts","./node_modules/@types/react/jsx-runtime.d.ts","./node_modules/next/dist/next-devtools/dev-overlay/container/runtime-error/render-error.d.ts","./node_modules/next/dist/next-devtools/dev-overlay/shared.d.ts","./node_modules/next/dist/server/dev/debug-channel.d.ts","./node_modules/next/dist/server/dev/hot-reloader-types.d.ts","./node_modules/next/dist/server/lib/i18n-provider.d.ts","./node_modules/next/dist/server/web/next-url.d.ts","./node_modules/next/dist/compiled/@edge-runtime/cookies/index.d.ts","./node_modules/next/dist/server/web/spec-extension/cookies.d.ts","./node_modules/next/dist/server/web/spec-extension/request.d.ts","./node_modules/next/dist/server/after/builtin-request-context.d.ts","./node_modules/next/dist/server/web/spec-extension/fetch-event.d.ts","./node_modules/next/dist/server/web/spec-extension/response.d.ts","./node_modules/next/dist/build/segment-config/middleware/middleware-config.d.ts","./node_modules/next/dist/server/web/types.d.ts","./node_modules/next/dist/build/webpack/plugins/pages-manifest-plugin.d.ts","./node_modules/next/dist/shared/lib/router/utils/parse-url.d.ts","./node_modules/next/dist/server/route-definitions/locale-route-definition.d.ts","./node_modules/next/dist/server/route-definitions/pages-route-definition.d.ts","./node_modules/next/dist/build/webpack/plugins/flight-manifest-plugin.d.ts","./node_modules/next/dist/build/webpack/plugins/next-font-manifest-plugin.d.ts","./node_modules/next/dist/shared/lib/deep-readonly.d.ts","./node_modules/next/dist/next-devtools/userspace/pages/pages-dev-overlay-setup.d.ts","./node_modules/next/dist/server/render.d.ts","./node_modules/next/dist/shared/lib/mitt.d.ts","./node_modules/next/dist/client/with-router.d.ts","./node_modules/next/dist/client/router.d.ts","./node_modules/next/dist/client/route-loader.d.ts","./node_modules/next/dist/client/page-loader.d.ts","./node_modules/next/dist/shared/lib/router/router.d.ts","./node_modules/next/dist/shared/lib/router-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/loadable-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/loadable.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/image-config-context.shared-runtime.d.ts","./node_modules/next/dist/client/components/readonly-url-search-params.d.ts","./node_modules/next/dist/shared/lib/hooks-client-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/head-manager-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/app-router-types.d.ts","./node_modules/next/dist/client/flight-data-helpers.d.ts","./node_modules/next/dist/client/components/router-reducer/ppr-navigations.d.ts","./node_modules/next/dist/client/components/segment-cache/types.d.ts","./node_modules/next/dist/client/components/segment-cache/navigation.d.ts","./node_modules/next/dist/client/components/segment-cache/cache-key.d.ts","./node_modules/next/dist/client/components/router-reducer/fetch-server-response.d.ts","./node_modules/next/dist/client/components/router-reducer/router-reducer-types.d.ts","./node_modules/next/dist/shared/lib/app-router-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/server-inserted-html.shared-runtime.d.ts","./node_modules/next/dist/server/route-modules/pages/vendored/contexts/entrypoints.d.ts","./node_modules/next/dist/server/route-modules/pages/module.compiled.d.ts","./node_modules/next/dist/build/templates/pages.d.ts","./node_modules/next/dist/server/route-modules/pages/module.d.ts","./node_modules/next/dist/server/route-modules/pages/builtin/_error.d.ts","./node_modules/next/dist/server/load-default-error-components.d.ts","./node_modules/next/dist/server/base-http/node.d.ts","./node_modules/next/dist/server/response-cache/index.d.ts","./node_modules/next/dist/server/route-definitions/pages-api-route-definition.d.ts","./node_modules/next/dist/server/route-matches/pages-api-route-match.d.ts","./node_modules/next/dist/server/route-matchers/route-matcher.d.ts","./node_modules/next/dist/server/route-matcher-providers/route-matcher-provider.d.ts","./node_modules/next/dist/server/route-matcher-managers/route-matcher-manager.d.ts","./node_modules/next/dist/server/normalizers/normalizer.d.ts","./node_modules/next/dist/server/normalizers/locale-route-normalizer.d.ts","./node_modules/next/dist/server/normalizers/request/pathname-normalizer.d.ts","./node_modules/next/dist/server/normalizers/request/suffix.d.ts","./node_modules/next/dist/server/normalizers/request/rsc.d.ts","./node_modules/next/dist/server/normalizers/request/next-data.d.ts","./node_modules/next/dist/server/normalizers/request/segment-prefix-rsc.d.ts","./node_modules/next/dist/build/static-paths/types.d.ts","./node_modules/next/dist/server/base-server.d.ts","./node_modules/next/dist/server/lib/async-callback-set.d.ts","./node_modules/next/dist/shared/lib/router/utils/route-regex.d.ts","./node_modules/next/dist/shared/lib/router/utils/route-matcher.d.ts","./node_modules/sharp/lib/index.d.ts","./node_modules/next/dist/server/image-optimizer.d.ts","./node_modules/next/dist/server/next-server.d.ts","./node_modules/next/dist/server/lib/types.d.ts","./node_modules/next/dist/server/lib/lru-cache.d.ts","./node_modules/next/dist/server/lib/dev-bundler-service.d.ts","./node_modules/next/dist/server/use-cache/cache-life.d.ts","./node_modules/next/dist/server/dev/static-paths-worker.d.ts","./node_modules/next/dist/server/dev/next-dev-server.d.ts","./node_modules/next/dist/server/next.d.ts","./node_modules/next/dist/server/lib/render-server.d.ts","./node_modules/next/dist/server/lib/router-server.d.ts","./node_modules/next/dist/shared/lib/router/utils/path-match.d.ts","./node_modules/next/dist/server/lib/router-utils/filesystem.d.ts","./node_modules/next/dist/server/lib/router-utils/setup-dev-bundler.d.ts","./node_modules/next/dist/server/lib/router-utils/router-server-context.d.ts","./node_modules/next/dist/server/route-modules/route-module.d.ts","./node_modules/next/dist/server/load-components.d.ts","./node_modules/next/dist/server/web/adapter.d.ts","./node_modules/next/dist/server/app-render/types.d.ts","./node_modules/next/dist/build/webpack/loaders/metadata/types.d.ts","./node_modules/next/dist/build/webpack/loaders/next-app-loader/index.d.ts","./node_modules/next/dist/server/lib/app-dir-module.d.ts","./node_modules/next/dist/server/web/spec-extension/adapters/request-cookies.d.ts","./node_modules/next/dist/server/async-storage/draft-mode-provider.d.ts","./node_modules/next/dist/server/web/spec-extension/adapters/headers.d.ts","./node_modules/next/dist/server/app-render/cache-signal.d.ts","./node_modules/next/dist/server/app-render/dynamic-rendering.d.ts","./node_modules/next/dist/server/request/fallback-params.d.ts","./node_modules/next/dist/server/app-render/work-unit-async-storage-instance.d.ts","./node_modules/next/dist/server/lib/lazy-result.d.ts","./node_modules/next/dist/server/lib/implicit-tags.d.ts","./node_modules/next/dist/server/app-render/staged-rendering.d.ts","./node_modules/next/dist/server/app-render/work-unit-async-storage.external.d.ts","./node_modules/next/dist/shared/lib/router/utils/parse-relative-url.d.ts","./node_modules/next/dist/server/app-render/app-render.d.ts","./node_modules/next/dist/server/route-modules/app-page/vendored/contexts/entrypoints.d.ts","./node_modules/next/dist/client/components/error-boundary.d.ts","./node_modules/next/dist/client/components/layout-router.d.ts","./node_modules/next/dist/client/components/render-from-template-context.d.ts","./node_modules/next/dist/server/app-render/action-async-storage-instance.d.ts","./node_modules/next/dist/server/app-render/action-async-storage.external.d.ts","./node_modules/next/dist/client/components/client-page.d.ts","./node_modules/next/dist/client/components/client-segment.d.ts","./node_modules/next/dist/server/request/search-params.d.ts","./node_modules/next/dist/client/components/hooks-server-context.d.ts","./node_modules/next/dist/client/components/http-access-fallback/error-boundary.d.ts","./node_modules/next/dist/lib/metadata/types/alternative-urls-types.d.ts","./node_modules/next/dist/lib/metadata/types/extra-types.d.ts","./node_modules/next/dist/lib/metadata/types/metadata-types.d.ts","./node_modules/next/dist/lib/metadata/types/manifest-types.d.ts","./node_modules/next/dist/lib/metadata/types/opengraph-types.d.ts","./node_modules/next/dist/lib/metadata/types/twitter-types.d.ts","./node_modules/next/dist/lib/metadata/types/metadata-interface.d.ts","./node_modules/next/dist/lib/metadata/types/resolvers.d.ts","./node_modules/next/dist/lib/metadata/types/icons.d.ts","./node_modules/next/dist/lib/metadata/resolve-metadata.d.ts","./node_modules/next/dist/lib/metadata/metadata.d.ts","./node_modules/next/dist/lib/framework/boundary-components.d.ts","./node_modules/next/dist/server/app-render/rsc/preloads.d.ts","./node_modules/next/dist/server/app-render/rsc/postpone.d.ts","./node_modules/next/dist/server/app-render/rsc/taint.d.ts","./node_modules/next/dist/shared/lib/segment-cache/segment-value-encoding.d.ts","./node_modules/next/dist/server/app-render/collect-segment-data.d.ts","./node_modules/next/dist/next-devtools/userspace/app/segment-explorer-node.d.ts","./node_modules/next/dist/server/app-render/entry-base.d.ts","./node_modules/next/dist/build/templates/app-page.d.ts","./node_modules/next/dist/build/rendering-mode.d.ts","./node_modules/@types/react/jsx-dev-runtime.d.ts","./node_modules/@types/react/compiler-runtime.d.ts","./node_modules/next/dist/server/route-modules/app-page/vendored/rsc/entrypoints.d.ts","./node_modules/@types/react-dom/client.d.ts","./node_modules/@types/react-dom/static.d.ts","./node_modules/@types/react-dom/server.d.ts","./node_modules/next/dist/server/route-modules/app-page/vendored/ssr/entrypoints.d.ts","./node_modules/next/dist/server/route-modules/app-page/module.d.ts","./node_modules/next/dist/server/route-modules/app-page/module.compiled.d.ts","./node_modules/next/dist/server/route-definitions/app-route-route-definition.d.ts","./node_modules/next/dist/server/async-storage/work-store.d.ts","./node_modules/next/dist/server/web/http.d.ts","./node_modules/next/dist/server/route-modules/app-route/shared-modules.d.ts","./node_modules/next/dist/client/components/redirect-status-code.d.ts","./node_modules/next/dist/client/components/redirect-error.d.ts","./node_modules/next/dist/build/templates/app-route.d.ts","./node_modules/next/dist/server/route-modules/app-route/module.d.ts","./node_modules/next/dist/server/route-modules/app-route/module.compiled.d.ts","./node_modules/next/dist/build/segment-config/app/app-segments.d.ts","./node_modules/next/dist/build/utils.d.ts","./node_modules/next/dist/server/lib/router-utils/build-prefetch-segment-data-route.d.ts","./node_modules/next/dist/build/turborepo-access-trace/types.d.ts","./node_modules/next/dist/build/turborepo-access-trace/result.d.ts","./node_modules/next/dist/build/turborepo-access-trace/helpers.d.ts","./node_modules/next/dist/build/turborepo-access-trace/index.d.ts","./node_modules/next/dist/export/routes/types.d.ts","./node_modules/next/dist/export/types.d.ts","./node_modules/next/dist/export/worker.d.ts","./node_modules/next/dist/build/worker.d.ts","./node_modules/next/dist/build/index.d.ts","./node_modules/next/dist/server/lib/incremental-cache/index.d.ts","./node_modules/next/dist/server/after/after.d.ts","./node_modules/next/dist/server/after/after-context.d.ts","./node_modules/next/dist/server/app-render/work-async-storage-instance.d.ts","./node_modules/next/dist/server/app-render/create-error-handler.d.ts","./node_modules/next/dist/shared/lib/action-revalidation-kind.d.ts","./node_modules/next/dist/server/app-render/work-async-storage.external.d.ts","./node_modules/next/dist/server/request/params.d.ts","./node_modules/next/dist/server/route-matches/route-match.d.ts","./node_modules/next/dist/server/request-meta.d.ts","./node_modules/next/dist/cli/next-test.d.ts","./node_modules/next/dist/shared/lib/size-limit.d.ts","./node_modules/next/dist/server/config-shared.d.ts","./node_modules/next/dist/server/base-http/index.d.ts","./node_modules/next/dist/server/api-utils/index.d.ts","./node_modules/next/dist/build/adapter/build-complete.d.ts","./node_modules/next/dist/types.d.ts","./node_modules/next/dist/shared/lib/html-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/utils.d.ts","./node_modules/next/dist/pages/_app.d.ts","./node_modules/next/app.d.ts","./node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts","./node_modules/next/dist/server/web/spec-extension/revalidate.d.ts","./node_modules/next/dist/server/web/spec-extension/unstable-no-store.d.ts","./node_modules/next/dist/server/use-cache/cache-tag.d.ts","./node_modules/next/cache.d.ts","./node_modules/next/dist/pages/_document.d.ts","./node_modules/next/document.d.ts","./node_modules/next/dist/shared/lib/dynamic.d.ts","./node_modules/next/dynamic.d.ts","./node_modules/next/dist/pages/_error.d.ts","./node_modules/next/error.d.ts","./node_modules/next/dist/shared/lib/head.d.ts","./node_modules/next/head.d.ts","./node_modules/next/dist/server/request/cookies.d.ts","./node_modules/next/dist/server/request/headers.d.ts","./node_modules/next/dist/server/request/draft-mode.d.ts","./node_modules/next/headers.d.ts","./node_modules/next/dist/shared/lib/get-img-props.d.ts","./node_modules/next/dist/client/image-component.d.ts","./node_modules/next/dist/shared/lib/image-external.d.ts","./node_modules/next/image.d.ts","./node_modules/next/dist/client/link.d.ts","./node_modules/next/link.d.ts","./node_modules/next/dist/client/components/unrecognized-action-error.d.ts","./node_modules/next/dist/client/components/redirect.d.ts","./node_modules/next/dist/client/components/not-found.d.ts","./node_modules/next/dist/client/components/forbidden.d.ts","./node_modules/next/dist/client/components/unauthorized.d.ts","./node_modules/next/dist/client/components/unstable-rethrow.server.d.ts","./node_modules/next/dist/client/components/unstable-rethrow.d.ts","./node_modules/next/dist/client/components/navigation.react-server.d.ts","./node_modules/next/dist/client/components/navigation.d.ts","./node_modules/next/navigation.d.ts","./node_modules/next/router.d.ts","./node_modules/next/dist/client/script.d.ts","./node_modules/next/script.d.ts","./node_modules/next/dist/server/web/spec-extension/user-agent.d.ts","./node_modules/next/dist/compiled/@edge-runtime/primitives/url.d.ts","./node_modules/next/dist/server/web/spec-extension/image-response.d.ts","./node_modules/next/dist/compiled/@vercel/og/satori/index.d.ts","./node_modules/next/dist/compiled/@vercel/og/emoji/index.d.ts","./node_modules/next/dist/compiled/@vercel/og/types.d.ts","./node_modules/next/dist/server/after/index.d.ts","./node_modules/next/dist/server/request/connection.d.ts","./node_modules/next/server.d.ts","./node_modules/next/types/global.d.ts","./node_modules/next/types/compiled.d.ts","./node_modules/next/types.d.ts","./node_modules/next/index.d.ts","./node_modules/next/image-types/global.d.ts","./.next/dev/types/routes.d.ts","./next-env.d.ts","./next.config.ts","./src/components/audit/constants.ts","./node_modules/clsx/clsx.d.mts","./node_modules/tailwind-merge/dist/types.d.ts","./src/lib/utils.ts","./src/components/audit/result-badge.tsx","./src/components/audit/latency-indicator.tsx","./src/components/audit/confidence-indicator.tsx","./src/lib/api/types.ts","./src/lib/format.ts","./src/components/audit/audit-row.tsx","./src/components/ui/input.tsx","./src/components/audit/audit-filters.tsx","./src/components/audit/audit-empty-state.tsx","./node_modules/class-variance-authority/dist/types.d.ts","./node_modules/class-variance-authority/dist/index.d.ts","./node_modules/@radix-ui/react-accessible-icon/dist/index.d.mts","./node_modules/@radix-ui/react-context/dist/index.d.mts","./node_modules/@radix-ui/react-primitive/dist/index.d.mts","./node_modules/@radix-ui/react-collapsible/dist/index.d.mts","./node_modules/@radix-ui/react-accordion/dist/index.d.mts","./node_modules/@radix-ui/react-dismissable-layer/dist/index.d.mts","./node_modules/@radix-ui/react-focus-scope/dist/index.d.mts","./node_modules/@radix-ui/react-portal/dist/index.d.mts","./node_modules/@radix-ui/react-dialog/dist/index.d.mts","./node_modules/@radix-ui/react-alert-dialog/dist/index.d.mts","./node_modules/@radix-ui/react-aspect-ratio/dist/index.d.mts","./node_modules/@radix-ui/react-avatar/dist/index.d.mts","./node_modules/@radix-ui/react-checkbox/dist/index.d.mts","./node_modules/@radix-ui/react-arrow/dist/index.d.mts","./node_modules/@radix-ui/rect/dist/index.d.mts","./node_modules/@radix-ui/react-popper/dist/index.d.mts","./node_modules/@radix-ui/react-roving-focus/dist/index.d.mts","./node_modules/@radix-ui/react-menu/dist/index.d.mts","./node_modules/@radix-ui/react-context-menu/dist/index.d.mts","./node_modules/@radix-ui/react-direction/dist/index.d.mts","./node_modules/@radix-ui/react-dropdown-menu/dist/index.d.mts","./node_modules/@radix-ui/react-label/dist/index.d.mts","./node_modules/@radix-ui/react-form/dist/index.d.mts","./node_modules/@radix-ui/react-hover-card/dist/index.d.mts","./node_modules/@radix-ui/react-menubar/dist/index.d.mts","./node_modules/@radix-ui/react-visually-hidden/dist/index.d.mts","./node_modules/@radix-ui/react-navigation-menu/dist/index.d.mts","./node_modules/@radix-ui/react-one-time-password-field/dist/index.d.mts","./node_modules/@radix-ui/react-password-toggle-field/dist/index.d.mts","./node_modules/@radix-ui/react-popover/dist/index.d.mts","./node_modules/@radix-ui/react-progress/dist/index.d.mts","./node_modules/@radix-ui/react-radio-group/dist/index.d.mts","./node_modules/@radix-ui/react-scroll-area/dist/index.d.mts","./node_modules/@radix-ui/react-select/dist/index.d.mts","./node_modules/@radix-ui/react-separator/dist/index.d.mts","./node_modules/@radix-ui/react-slider/dist/index.d.mts","./node_modules/@radix-ui/react-slot/dist/index.d.mts","./node_modules/@radix-ui/react-switch/dist/index.d.mts","./node_modules/@radix-ui/react-tabs/dist/index.d.mts","./node_modules/@radix-ui/react-toast/dist/index.d.mts","./node_modules/@radix-ui/react-toggle/dist/index.d.mts","./node_modules/@radix-ui/react-toggle-group/dist/index.d.mts","./node_modules/@radix-ui/react-toolbar/dist/index.d.mts","./node_modules/@radix-ui/react-tooltip/dist/index.d.mts","./node_modules/radix-ui/dist/index.d.mts","./src/components/ui/button.tsx","./src/components/audit/audit-export.tsx","./src/components/audit/audit-list.tsx","./src/components/audit/audit-loading-skeleton.tsx","./src/lib/api/client.ts","./src/lib/api/index.ts","./src/lib/types.ts","./src/lib/constants.ts","./src/components/shared/error-state.tsx","./src/components/audit/audit-panel.tsx","./src/components/audit/index.ts","./src/components/circuit/constants.ts","./src/components/circuit/state-badge.tsx","./src/components/circuit/circuit-card.tsx","./src/components/circuit/circuit-summary.tsx","./src/components/circuit/circuit-list.tsx","./src/components/circuit/circuit-loading-skeleton.tsx","./src/components/circuit/circuit-empty-state.tsx","./src/components/circuit/circuit-panel.tsx","./src/components/circuit/index.ts","./src/components/skeptic/constants.ts","./src/components/skeptic/source-tier-badge.tsx","./src/components/skeptic/weight-bar.tsx","./src/components/skeptic/hash-display.tsx","./src/components/skeptic/conflict-gauge.tsx","./src/components/skeptic/status-badge.tsx","./src/components/skeptic/empty-state.tsx","./src/components/skeptic/loading-skeleton.tsx","./node_modules/lucide-react/dist/lucide-react.d.ts","./src/components/skeptic/error-state.tsx","./src/components/skeptic/trust-bar.tsx","./src/components/skeptic/claim-row.tsx","./src/components/skeptic/claims-table.tsx","./src/components/skeptic/weight-distribution.tsx","./src/components/ui/date-picker.tsx","./src/components/skeptic/query-form.tsx","./src/components/skeptic/query-results.tsx","./src/components/skeptic/index.ts","./src/components/layered/tier-accordion.tsx","./src/components/layered/cross-tier-summary.tsx","./src/components/layered/layered-loading-skeleton.tsx","./src/components/layered/layered-results-view.tsx","./src/components/layered/layered-query-results.tsx","./src/components/layered/index.ts","./src/components/quarantine/constants.ts","./src/components/quarantine/reason-badge.tsx","./src/components/quarantine/quarantine-row.tsx","./src/components/quarantine/quarantine-metrics.tsx","./src/components/quarantine/quarantine-filters.tsx","./src/components/quarantine/quarantine-empty-state.tsx","./src/components/quarantine/quarantine-list.tsx","./src/components/quarantine/quarantine-loading-skeleton.tsx","./src/components/shared/confirmation-dialog.tsx","./src/components/quarantine/quarantine-panel.tsx","./src/components/quarantine/blocked-sources-panel.tsx","./src/components/quarantine/index.ts","./src/components/sources/status-badge.tsx","./src/components/sources/tier-badge.tsx","./src/components/sources/impact-ripple.tsx","./src/components/sources/source-row.tsx","./src/components/sources/impact-preview.tsx","./src/components/sources/block-dialog.tsx","./src/components/sources/restore-dialog.tsx","./src/components/ui/sheet.tsx","./src/components/sources/impact-detail-panel.tsx","./src/components/sources/sources-loading-skeleton.tsx","./src/components/sources/sources-empty-state.tsx","./src/components/sources/sources-metrics.tsx","./src/components/sources/sources-filters.tsx","./src/components/sources/sources-panel.tsx","./src/components/sources/index.ts","./src/lib/auth/api-key.ts","./node_modules/next/dist/compiled/@next/font/dist/types.d.ts","./node_modules/next/dist/compiled/@next/font/dist/google/index.d.ts","./node_modules/next/font/google/index.d.ts","./src/components/layout/sidebar.tsx","./src/app/layout.tsx","./src/app/page.tsx","./src/components/layout/theme-toggle.tsx","./src/components/shared/api-status.tsx","./src/components/layout/header.tsx","./src/app/audit/page.tsx","./src/app/circuit/page.tsx","./src/app/layered/page.tsx","./src/components/ui/tabs.tsx","./src/app/quarantine/page.tsx","./src/app/skeptic/page.tsx","./src/app/sources/page.tsx","./src/components/ui/badge.tsx","./src/components/ui/card.tsx","./src/components/ui/separator.tsx","./.next/dev/types/cache-life.d.ts","./.next/dev/types/validator.ts","./node_modules/@types/estree/index.d.ts","./node_modules/@types/json-schema/index.d.ts","./node_modules/@types/json5/index.d.ts"],"fileIdsList":[[97,143,460,461,462,463],[97,143],[97,143,269,507,510,649,650,654,655,656,658,659,660],[97,143,508,509,510],[97,143,269,508],[85,97,143],[85,97,143,529,530,531],[85,97,143,529,536],[85,97,143,530],[85,97,143,529,530],[85,97,143,269,529,530],[85,97,143,529,530,545],[85,97,143,529,530,533,534,535],[85,97,143,269,529,530,549],[85,97,143,529,530,533,535,543],[85,97,143,529,530,533,534,535,543,544],[85,97,143,269,529,530,544,545],[85,97,143,529,530,533,553],[85,97,143,530,544],[85,97,143,529,530,533,534,535,543],[85,97,143,529,530,541,542],[85,97,143,529,530,544],[85,97,143,529,530,533],[85,97,143,529,530,544,568],[85,97,143,529,530,544,562,569],[97,140,143],[97,142,143],[143],[97,143,148,176],[97,143,144,149,154,162,173,184],[97,143,144,145,154,162],[92,93,94,97,143],[97,143,146,185],[97,143,147,148,155,163],[97,143,148,173,181],[97,143,149,151,154,162],[97,142,143,150],[97,143,151,152],[97,143,153,154],[97,142,143,154],[97,143,154,155,156,173,184],[97,143,154,155,156,169,173,176],[97,143,151,154,157,162,173,184],[97,143,154,155,157,158,162,173,181,184],[97,143,157,159,173,181,184],[95,96,97,98,99,100,101,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,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],[97,143,154,160],[97,143,161,184,189],[97,143,151,154,162,173],[97,143,163],[97,143,164],[97,142,143,165],[97,140,141,142,143,144,145,146,147,148,149,150,151,152,153,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],[97,143,167],[97,143,168],[97,143,154,169,170],[97,143,169,171,185,187],[97,143,154,173,174,176],[97,143,175,176],[97,143,173,174],[97,143,176],[97,143,177],[97,140,143,173,178],[97,143,154,179,180],[97,143,179,180],[97,143,148,162,173,181],[97,143,182],[97,143,162,183],[97,143,157,168,184],[97,143,148,185],[97,143,173,186],[97,143,161,187],[97,143,188],[97,138,143],[97,138,143,154,156,165,173,176,184,187,189],[97,143,173,190],[85,89,97,143,192,193,194,196,455,501],[85,89,97,143,192,193,194,195,412,455,501],[85,89,97,143,192,193,195,196,455,501],[85,97,143,196,412,413],[85,97,143,196,412],[85,89,97,143,193,194,195,196,455,501],[85,89,97,143,192,194,195,196,455,501],[83,84,97,143],[97,143,514,526],[97,143,514],[97,143,458],[97,143,201,203,207,218,408,438,451],[97,143,203,213,214,215,217,451],[97,143,203,250,252,254,255,258,451,453],[97,143,203,207,209,210,211,241,336,408,428,429,437,451,453],[97,143,451],[97,143,214,306,417,426,446],[97,143,203],[97,143,197,306,446],[97,143,260],[97,143,259,451],[97,143,157,406,417,506],[97,143,157,374,386,426,445],[97,143,157,317],[97,143,431],[97,143,430,431,432],[97,143,430],[91,97,143,157,197,203,207,210,212,214,218,219,232,233,260,336,347,427,438,451,455],[97,143,201,203,216,250,251,256,257,451,506],[97,143,216,506],[97,143,201,233,361,451,506],[97,143,506],[97,143,203,216,217,506],[97,143,253,506],[97,143,219,428,436],[97,143,168,269,446],[97,143,269,446],[85,97,143,269],[85,97,143,378],[97,143,304,314,315,446,483,490],[97,143,303,423,484,485,486,487,489],[97,143,422],[97,143,422,423],[97,143,241,306,307,311],[97,143,306],[97,143,306,310,312],[97,143,306,307,308,309],[97,143,488],[85,97,143,204,477],[85,97,143,184],[85,97,143,216,296],[85,97,143,216,438],[97,143,294,298],[85,97,143,295,457],[97,143,645],[85,89,97,143,157,191,192,193,194,195,196,455,499,500],[97,143,157],[97,143,157,207,240,292,337,358,360,433,434,438,451,452],[97,143,232,435],[97,143,455],[97,143,202],[85,97,143,363,376,385,395,397,445],[97,143,168,363,376,394,395,396,445,505],[97,143,388,389,390,391,392,393],[97,143,390],[97,143,394],[97,143,267,268,269,271],[85,97,143,261,262,263,264,270],[97,143,267,270],[97,143,265],[97,143,266],[85,97,143,269,295,457],[85,97,143,269,456,457],[85,97,143,269,457],[97,143,337,440],[97,143,440],[97,143,157,452,457],[97,143,382],[97,142,143,381],[97,143,242,306,323,360,369,372,374,375,416,445,448,452],[97,143,288,306,403],[97,143,374,445],[85,97,143,374,379,380,382,383,384,385,386,387,398,399,400,401,402,404,405,445,446,506],[97,143,368],[97,143,157,168,204,240,243,264,289,290,337,347,358,359,416,439,451,452,453,455,506],[97,143,445],[97,142,143,214,290,347,371,439,441,442,443,444,452],[97,143,374],[97,142,143,240,277,323,364,365,366,367,368,369,370,372,373,445,446],[97,143,157,277,278,364,452,453],[97,143,214,337,347,360,439,445,452],[97,143,157,451,453],[97,143,157,173,448,452,453],[97,143,157,168,184,197,207,216,242,243,245,274,279,284,288,289,290,292,321,323,325,328,330,333,334,335,336,358,360,438,439,446,448,451,452,453],[97,143,157,173],[97,143,203,204,205,212,448,449,450,455,457,506],[97,143,201,451],[97,143,273],[97,143,157,173,184,235,258,260,261,262,263,264,271,272,506],[97,143,168,184,197,235,250,283,284,285,321,322,323,328,336,337,343,346,348,358,360,439,446,448,451],[97,143,212,219,232,336,347,439,451],[97,143,157,184,204,207,323,341,448,451],[97,143,362],[97,143,157,273,344,345,355],[97,143,448,451],[97,143,369,371],[97,143,290,323,438,457],[97,143,157,168,246,250,322,328,343,346,350,448],[97,143,157,219,232,250,351],[97,143,203,245,353,438,451],[97,143,157,184,264,451],[97,143,157,216,244,245,246,255,273,352,354,438,451],[91,97,143,157,290,357,455,457],[97,143,320,358],[97,143,157,168,184,207,218,219,232,242,243,279,283,284,285,289,321,322,323,325,337,338,340,342,358,360,438,439,446,447,448,457],[97,143,157,173,219,343,349,355,448],[97,143,222,223,224,225,226,227,228,229,230,231],[97,143,274,329],[97,143,331],[97,143,329],[97,143,331,332],[97,143,157,207,210,240,241,452],[97,143,157,168,202,204,242,288,289,290,291,319,358,448,453,455,457],[97,143,157,168,184,206,241,291,323,369,439,447,452],[97,143,364],[97,143,365],[97,143,306,336,416],[97,143,366],[97,143,234,238],[97,143,157,207,234,242],[97,143,237,238],[97,143,239],[97,143,234,235],[97,143,234,286],[97,143,234],[97,143,274,327,447],[97,143,326],[97,143,235,446,447],[97,143,324,447],[97,143,235,446],[97,143,416],[97,143,207,236,242,290,306,323,357,360,363,369,376,377,407,408,411,415,438,448,452],[97,143,299,302,304,305,314,315],[85,97,143,194,196,269,409,410],[85,97,143,194,196,269,409,410,414],[97,143,425],[97,143,214,278,290,357,360,374,382,386,418,419,420,421,423,424,427,438,445,451],[97,143,314],[97,143,157,319],[97,143,319],[97,143,157,242,287,292,316,318,357,448,455,457],[97,143,299,300,301,302,304,305,314,315,456],[91,97,143,157,168,184,234,235,243,289,290,323,355,356,358,438,439,448,451,452,455],[97,143,278,280,283,439],[97,143,157,274,451],[97,143,277,374],[97,143,276],[97,143,278,279],[97,143,275,277,451],[97,143,157,206,278,280,281,282,451,452],[85,97,143,306,313,446],[97,143,199,200],[85,97,143,204],[85,97,143,303,446],[85,91,97,143,289,290,455,457],[97,143,204,477,478],[85,97,143,298],[85,97,143,168,184,202,257,293,295,297,457],[97,143,216,446,452],[97,143,339,446],[85,97,143,155,157,168,201,202,252,298,455,456],[85,97,143,192,193,194,195,196,455,501],[85,86,87,88,89,97,143],[97,143,148],[97,143,247,248,249],[97,143,247],[85,89,97,143,157,159,168,191,192,193,194,195,196,197,202,243,350,394,453,454,457,501],[97,143,465],[97,143,467],[97,143,469],[97,143,646],[97,143,471],[97,143,473,474,475],[97,143,479],[90,97,143,459,464,466,468,470,472,476,480,482,492,493,495,504,505,506,507],[97,143,481],[97,143,491],[97,143,295],[97,143,494],[97,142,143,278,280,281,283,496,497,498,501,502,503],[97,143,191],[97,143,528,531,532,535,536,537,538,539,540,546,547,548,549,550,551,552,553,554,555,556,557,558,559,560,561,562,563,564,565,566,567,568,569,570,571],[97,143,173,191],[97,110,114,143,184],[97,110,143,173,184],[97,105,143],[97,107,110,143,181,184],[97,143,162,181],[97,105,143,191],[97,107,110,143,162,184],[97,102,103,106,109,143,154,173,184],[97,110,117,143],[97,102,108,143],[97,110,131,132,143],[97,106,110,143,176,184,191],[97,131,143,191],[97,104,105,143,191],[97,110,143],[97,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,132,133,134,135,136,137,143],[97,110,125,143],[97,110,117,118,143],[97,108,110,118,119,143],[97,109,143],[97,102,105,110,143],[97,110,114,118,119,143],[97,114,143],[97,108,110,113,143,184],[97,102,107,110,117,143],[97,143,173],[97,105,110,131,143,189,191],[85,97,143,269,492,583,653],[97,143,269,592,653],[97,143,269,616,653],[97,143,269,508,647,648],[97,143,269,492],[97,143,269,627,628,653,657],[97,143,269,610,653],[97,143,269,643,653],[97,143,269],[85,97,143,269,520,573],[97,143,269,513,523],[85,97,143,269,520,522,524,525,573,574],[97,143,269,516],[85,97,143,269,524,525,575,576,578,579,580,581],[85,97,143,269,517,519,520,521],[97,143,269,513,517,518,519,522,524,525,574,575,576,582],[97,143,269,513,516],[97,143,269,520,521,573,584,585],[85,97,143,269,520,586],[85,97,143,269,578,579,580,581,587,588,589,590],[97,143,269,516,520],[97,143,269,584,585,586,587,588,589,590,591],[97,143,269,516,584],[97,143,269,610],[97,143,269,611,612,613,614,615],[85,97,143,269,578,610,613,614],[85,97,143,269,492,520,573,611,612],[97,143,269,516,520,610],[97,143,269,651,652],[85,97,143,269,482,492,516,601],[85,97,143,269,516,601],[85,97,143,269,573,578,579,580,581,601,625],[97,143,269,617,618,619,620,621,622,623,624,626,627],[97,143,269,617],[85,97,143,269,520,619,621,622],[85,97,143,269,578,579,580,581,620,622,623,624,625],[85,97,143,269,520,521,573,596,618],[97,143,269,516,617],[85,97,143,269,516],[85,97,143,269,573],[97,143,269,573],[97,143,269,516,520,593,594,595,596,603],[85,97,143,269,520,604],[97,143,269,516,593],[97,143,269,573,601],[97,143,269,593,594,595,596,597,598,599,600,602,603,604,605,606,608,609],[85,97,143,269,523,573,607],[85,97,143,269,492,573,578,593,597,598,599,600,602,605,606,608],[97,143,269,516,520,593],[85,97,143,269,520,573,601,633],[85,97,143,269,520,573,578,601,633,636],[97,143,269,520,601,631],[97,143,269,629,630,631,632,633,634,635,637,638,639,640,641,642],[85,97,143,269,573,601],[97,143,269,520,573,601,629,630],[97,143,269,601],[97,143,269,520],[85,97,143,269,578,579,580,581,632,634,635,637,638,639,640,641],[97,143,269,516,580],[85,97,143,269,516,527,572],[85,97,143,269,516,572],[85,97,143,269,516,572,601],[97,143,269,520,577],[97,143,269,514,515]],"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":"feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569","impliedFormat":1},{"version":"ee7bad0c15b58988daa84371e0b89d313b762ab83cb5b31b8a2d1162e8eb41c2","impliedFormat":1},{"version":"27bdc30a0e32783366a5abeda841bc22757c1797de8681bbe81fbc735eeb1c10","impliedFormat":1},{"version":"8fd575e12870e9944c7e1d62e1f5a73fcf23dd8d3a321f2a2c74c20d022283fe","impliedFormat":1},{"version":"2ab096661c711e4a81cc464fa1e6feb929a54f5340b46b0a07ac6bbf857471f0","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":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true,"impliedFormat":1},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true,"impliedFormat":1},{"version":"959d36cddf5e7d572a65045b876f2956c973a586da58e5d26cde519184fd9b8a","affectsGlobalScope":true,"impliedFormat":1},{"version":"965f36eae237dd74e6cca203a43e9ca801ce38824ead814728a2807b1910117d","affectsGlobalScope":true,"impliedFormat":1},{"version":"3925a6c820dcb1a06506c90b1577db1fdbf7705d65b62b99dce4be75c637e26b","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a3d63ef2b853447ec4f749d3f368ce642264246e02911fcb1590d8c161b8005","affectsGlobalScope":true,"impliedFormat":1},{"version":"8cdf8847677ac7d20486e54dd3fcf09eda95812ac8ace44b4418da1bbbab6eb8","affectsGlobalScope":true,"impliedFormat":1},{"version":"8444af78980e3b20b49324f4a16ba35024fef3ee069a0eb67616ea6ca821c47a","affectsGlobalScope":true,"impliedFormat":1},{"version":"3287d9d085fbd618c3971944b65b4be57859f5415f495b33a6adc994edd2f004","affectsGlobalScope":true,"impliedFormat":1},{"version":"b4b67b1a91182421f5df999988c690f14d813b9850b40acd06ed44691f6727ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"df83c2a6c73228b625b0beb6669c7ee2a09c914637e2d35170723ad49c0f5cd4","affectsGlobalScope":true,"impliedFormat":1},{"version":"436aaf437562f276ec2ddbee2f2cdedac7664c1e4c1d2c36839ddd582eeb3d0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e3c06ea092138bf9fa5e874a1fdbc9d54805d074bee1de31b99a11e2fec239d","affectsGlobalScope":true,"impliedFormat":1},{"version":"87dc0f382502f5bbce5129bdc0aea21e19a3abbc19259e0b43ae038a9fc4e326","affectsGlobalScope":true,"impliedFormat":1},{"version":"b1cb28af0c891c8c96b2d6b7be76bd394fddcfdb4709a20ba05a7c1605eea0f9","affectsGlobalScope":true,"impliedFormat":1},{"version":"2fef54945a13095fdb9b84f705f2b5994597640c46afeb2ce78352fab4cb3279","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac77cb3e8c6d3565793eb90a8373ee8033146315a3dbead3bde8db5eaf5e5ec6","affectsGlobalScope":true,"impliedFormat":1},{"version":"56e4ed5aab5f5920980066a9409bfaf53e6d21d3f8d020c17e4de584d29600ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ece9f17b3866cc077099c73f4983bddbcb1dc7ddb943227f1ec070f529dedd1","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a6282c8827e4b9a95f4bf4f5c205673ada31b982f50572d27103df8ceb8013c","affectsGlobalScope":true,"impliedFormat":1},{"version":"1c9319a09485199c1f7b0498f2988d6d2249793ef67edda49d1e584746be9032","affectsGlobalScope":true,"impliedFormat":1},{"version":"e3a2a0cee0f03ffdde24d89660eba2685bfbdeae955a6c67e8c4c9fd28928eeb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811c71eee4aa0ac5f7adf713323a5c41b0cf6c4e17367a34fbce379e12bbf0a4","affectsGlobalScope":true,"impliedFormat":1},{"version":"51ad4c928303041605b4d7ae32e0c1ee387d43a24cd6f1ebf4a2699e1076d4fa","affectsGlobalScope":true,"impliedFormat":1},{"version":"60037901da1a425516449b9a20073aa03386cce92f7a1fd902d7602be3a7c2e9","affectsGlobalScope":true,"impliedFormat":1},{"version":"d4b1d2c51d058fc21ec2629fff7a76249dec2e36e12960ea056e3ef89174080f","affectsGlobalScope":true,"impliedFormat":1},{"version":"22adec94ef7047a6c9d1af3cb96be87a335908bf9ef386ae9fd50eeb37f44c47","affectsGlobalScope":true,"impliedFormat":1},{"version":"196cb558a13d4533a5163286f30b0509ce0210e4b316c56c38d4c0fd2fb38405","affectsGlobalScope":true,"impliedFormat":1},{"version":"73f78680d4c08509933daf80947902f6ff41b6230f94dd002ae372620adb0f60","affectsGlobalScope":true,"impliedFormat":1},{"version":"c5239f5c01bcfa9cd32f37c496cf19c61d69d37e48be9de612b541aac915805b","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"7e29f41b158de217f94cb9676bf9cbd0cd9b5a46e1985141ed36e075c52bf6ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac51dd7d31333793807a6abaa5ae168512b6131bd41d9c5b98477fc3b7800f9f","impliedFormat":1},{"version":"f123246a7b6c04d80b9b57fadfc6c90959ec6d5c0d4c8e620e06e2811ae3a052","impliedFormat":1},{"version":"acd8fd5090ac73902278889c38336ff3f48af6ba03aa665eb34a75e7ba1dccc4","impliedFormat":1},{"version":"d6258883868fb2680d2ca96bc8b1352cab69874581493e6d52680c5ffecdb6cc","impliedFormat":1},{"version":"1b61d259de5350f8b1e5db06290d31eaebebc6baafd5f79d314b5af9256d7153","impliedFormat":1},{"version":"f258e3960f324a956fc76a3d3d9e964fff2244ff5859dcc6ce5951e5413ca826","impliedFormat":1},{"version":"643f7232d07bf75e15bd8f658f664d6183a0efaca5eb84b48201c7671a266979","impliedFormat":1},{"version":"21da358700a3893281ce0c517a7a30cbd46be020d9f0c3f2834d0a8ad1f5fc75","impliedFormat":1},{"version":"70521b6ab0dcba37539e5303104f29b721bfb2940b2776da4cc818c07e1fefc1","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab41ef1f2cdafb8df48be20cd969d875602483859dc194e9c97c8a576892c052","affectsGlobalScope":true,"impliedFormat":1},{"version":"d153a11543fd884b596587ccd97aebbeed950b26933ee000f94009f1ab142848","affectsGlobalScope":true,"impliedFormat":1},{"version":"21d819c173c0cf7cc3ce57c3276e77fd9a8a01d35a06ad87158781515c9a438a","impliedFormat":1},{"version":"98cffbf06d6bab333473c70a893770dbe990783904002c4f1a960447b4b53dca","affectsGlobalScope":true,"impliedFormat":1},{"version":"ba481bca06f37d3f2c137ce343c7d5937029b2468f8e26111f3c9d9963d6568d","affectsGlobalScope":true,"impliedFormat":1},{"version":"6d9ef24f9a22a88e3e9b3b3d8c40ab1ddb0853f1bfbd5c843c37800138437b61","affectsGlobalScope":true,"impliedFormat":1},{"version":"1db0b7dca579049ca4193d034d835f6bfe73096c73663e5ef9a0b5779939f3d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"9798340ffb0d067d69b1ae5b32faa17ab31b82466a3fc00d8f2f2df0c8554aaa","affectsGlobalScope":true,"impliedFormat":1},{"version":"f26b11d8d8e4b8028f1c7d618b22274c892e4b0ef5b3678a8ccbad85419aef43","affectsGlobalScope":true,"impliedFormat":1},{"version":"5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","impliedFormat":1},{"version":"763fe0f42b3d79b440a9b6e51e9ba3f3f91352469c1e4b3b67bfa4ff6352f3f4","impliedFormat":1},{"version":"25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","impliedFormat":1},{"version":"c464d66b20788266e5353b48dc4aa6bc0dc4a707276df1e7152ab0c9ae21fad8","impliedFormat":1},{"version":"78d0d27c130d35c60b5e5566c9f1e5be77caf39804636bc1a40133919a949f21","impliedFormat":1},{"version":"c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","impliedFormat":1},{"version":"1d6e127068ea8e104a912e42fc0a110e2aa5a66a356a917a163e8cf9a65e4a75","impliedFormat":1},{"version":"5ded6427296cdf3b9542de4471d2aa8d3983671d4cac0f4bf9c637208d1ced43","impliedFormat":1},{"version":"7f182617db458e98fc18dfb272d40aa2fff3a353c44a89b2c0ccb3937709bfb5","impliedFormat":1},{"version":"cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","impliedFormat":1},{"version":"385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","impliedFormat":1},{"version":"9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","impliedFormat":1},{"version":"0b8a9268adaf4da35e7fa830c8981cfa22adbbe5b3f6f5ab91f6658899e657a7","impliedFormat":1},{"version":"11396ed8a44c02ab9798b7dca436009f866e8dae3c9c25e8c1fbc396880bf1bb","impliedFormat":1},{"version":"ba7bc87d01492633cb5a0e5da8a4a42a1c86270e7b3d2dea5d156828a84e4882","impliedFormat":1},{"version":"4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","impliedFormat":1},{"version":"c21dc52e277bcfc75fac0436ccb75c204f9e1b3fa5e12729670910639f27343e","impliedFormat":1},{"version":"13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","impliedFormat":1},{"version":"9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","impliedFormat":1},{"version":"4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","impliedFormat":1},{"version":"24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","impliedFormat":1},{"version":"ea0148f897b45a76544ae179784c95af1bd6721b8610af9ffa467a518a086a43","impliedFormat":1},{"version":"24c6a117721e606c9984335f71711877293a9651e44f59f3d21c1ea0856f9cc9","impliedFormat":1},{"version":"dd3273ead9fbde62a72949c97dbec2247ea08e0c6952e701a483d74ef92d6a17","impliedFormat":1},{"version":"405822be75ad3e4d162e07439bac80c6bcc6dbae1929e179cf467ec0b9ee4e2e","impliedFormat":1},{"version":"0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","impliedFormat":1},{"version":"e61be3f894b41b7baa1fbd6a66893f2579bfad01d208b4ff61daef21493ef0a8","impliedFormat":1},{"version":"bd0532fd6556073727d28da0edfd1736417a3f9f394877b6d5ef6ad88fba1d1a","impliedFormat":1},{"version":"89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","impliedFormat":1},{"version":"615ba88d0128ed16bf83ef8ccbb6aff05c3ee2db1cc0f89ab50a4939bfc1943f","impliedFormat":1},{"version":"a4d551dbf8746780194d550c88f26cf937caf8d56f102969a110cfaed4b06656","impliedFormat":1},{"version":"8bd86b8e8f6a6aa6c49b71e14c4ffe1211a0e97c80f08d2c8cc98838006e4b88","impliedFormat":1},{"version":"317e63deeb21ac07f3992f5b50cdca8338f10acd4fbb7257ebf56735bf52ab00","impliedFormat":1},{"version":"4732aec92b20fb28c5fe9ad99521fb59974289ed1e45aecb282616202184064f","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"bf67d53d168abc1298888693338cb82854bdb2e69ef83f8a0092093c2d562107","impliedFormat":1},{"version":"b52476feb4a0cbcb25e5931b930fc73cb6643fb1a5060bf8a3dda0eeae5b4b68","affectsGlobalScope":true,"impliedFormat":1},{"version":"e2677634fe27e87348825bb041651e22d50a613e2fdf6a4a3ade971d71bac37e","impliedFormat":1},{"version":"7394959e5a741b185456e1ef5d64599c36c60a323207450991e7a42e08911419","impliedFormat":1},{"version":"8c0bcd6c6b67b4b503c11e91a1fb91522ed585900eab2ab1f61bba7d7caa9d6f","impliedFormat":1},{"version":"8cd19276b6590b3ebbeeb030ac271871b9ed0afc3074ac88a94ed2449174b776","affectsGlobalScope":true,"impliedFormat":1},{"version":"696eb8d28f5949b87d894b26dc97318ef944c794a9a4e4f62360cd1d1958014b","impliedFormat":1},{"version":"3f8fa3061bd7402970b399300880d55257953ee6d3cd408722cb9ac20126460c","impliedFormat":1},{"version":"35ec8b6760fd7138bbf5809b84551e31028fb2ba7b6dc91d95d098bf212ca8b4","affectsGlobalScope":true,"impliedFormat":1},{"version":"5524481e56c48ff486f42926778c0a3cce1cc85dc46683b92b1271865bcf015a","impliedFormat":1},{"version":"68bd56c92c2bd7d2339457eb84d63e7de3bd56a69b25f3576e1568d21a162398","affectsGlobalScope":true,"impliedFormat":1},{"version":"3e93b123f7c2944969d291b35fed2af79a6e9e27fdd5faa99748a51c07c02d28","impliedFormat":1},{"version":"9d19808c8c291a9010a6c788e8532a2da70f811adb431c97520803e0ec649991","impliedFormat":1},{"version":"87aad3dd9752067dc875cfaa466fc44246451c0c560b820796bdd528e29bef40","impliedFormat":1},{"version":"4aacb0dd020eeaef65426153686cc639a78ec2885dc72ad220be1d25f1a439df","impliedFormat":1},{"version":"f0bd7e6d931657b59605c44112eaf8b980ba7f957a5051ed21cb93d978cf2f45","impliedFormat":1},{"version":"8db0ae9cb14d9955b14c214f34dae1b9ef2baee2fe4ce794a4cd3ac2531e3255","affectsGlobalScope":true,"impliedFormat":1},{"version":"15fc6f7512c86810273af28f224251a5a879e4261b4d4c7e532abfbfc3983134","impliedFormat":1},{"version":"58adba1a8ab2d10b54dc1dced4e41f4e7c9772cbbac40939c0dc8ce2cdb1d442","impliedFormat":1},{"version":"2fd4c143eff88dabb57701e6a40e02a4dbc36d5eb1362e7964d32028056a782b","impliedFormat":1},{"version":"714435130b9015fae551788df2a88038471a5a11eb471f27c4ede86552842bc9","impliedFormat":1},{"version":"855cd5f7eb396f5f1ab1bc0f8580339bff77b68a770f84c6b254e319bbfd1ac7","impliedFormat":1},{"version":"5650cf3dace09e7c25d384e3e6b818b938f68f4e8de96f52d9c5a1b3db068e86","impliedFormat":1},{"version":"1354ca5c38bd3fd3836a68e0f7c9f91f172582ba30ab15bb8c075891b91502b7","affectsGlobalScope":true,"impliedFormat":1},{"version":"27fdb0da0daf3b337c5530c5f266efe046a6ceb606e395b346974e4360c36419","impliedFormat":1},{"version":"2d2fcaab481b31a5882065c7951255703ddbe1c0e507af56ea42d79ac3911201","impliedFormat":1},{"version":"a192fe8ec33f75edbc8d8f3ed79f768dfae11ff5735e7fe52bfa69956e46d78d","impliedFormat":1},{"version":"ca867399f7db82df981d6915bcbb2d81131d7d1ef683bc782b59f71dda59bc85","affectsGlobalScope":true,"impliedFormat":1},{"version":"0e456fd5b101271183d99a9087875a282323e3a3ff0d7bcf1881537eaa8b8e63","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e043a1bc8fbf2a255bccf9bf27e0f1caf916c3b0518ea34aa72357c0afd42ec","impliedFormat":1},{"version":"b4f70ec656a11d570e1a9edce07d118cd58d9760239e2ece99306ee9dfe61d02","impliedFormat":1},{"version":"3bc2f1e2c95c04048212c569ed38e338873f6a8593930cf5a7ef24ffb38fc3b6","impliedFormat":1},{"version":"6e70e9570e98aae2b825b533aa6292b6abd542e8d9f6e9475e88e1d7ba17c866","impliedFormat":1},{"version":"f9d9d753d430ed050dc1bf2667a1bab711ccbb1c1507183d794cc195a5b085cc","impliedFormat":1},{"version":"9eece5e586312581ccd106d4853e861aaaa1a39f8e3ea672b8c3847eedd12f6e","impliedFormat":1},{"version":"47ab634529c5955b6ad793474ae188fce3e6163e3a3fb5edd7e0e48f14435333","impliedFormat":1},{"version":"37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","impliedFormat":1},{"version":"45650f47bfb376c8a8ed39d4bcda5902ab899a3150029684ee4c10676d9fbaee","impliedFormat":1},{"version":"fad4e3c207fe23922d0b2d06b01acbfb9714c4f2685cf80fd384c8a100c82fd0","affectsGlobalScope":true,"impliedFormat":1},{"version":"74cf591a0f63db318651e0e04cb55f8791385f86e987a67fd4d2eaab8191f730","impliedFormat":1},{"version":"5eab9b3dc9b34f185417342436ec3f106898da5f4801992d8ff38ab3aff346b5","impliedFormat":1},{"version":"12ed4559eba17cd977aa0db658d25c4047067444b51acfdcbf38470630642b23","affectsGlobalScope":true,"impliedFormat":1},{"version":"f3ffabc95802521e1e4bcba4c88d8615176dc6e09111d920c7a213bdda6e1d65","impliedFormat":1},{"version":"ddc734b4fae82a01d247e9e342d020976640b5e93b4e9b3a1e30e5518883a060","impliedFormat":1},{"version":"ae56f65caf3be91108707bd8dfbccc2a57a91feb5daabf7165a06a945545ed26","impliedFormat":1},{"version":"a136d5de521da20f31631a0a96bf712370779d1c05b7015d7019a9b2a0446ca9","impliedFormat":1},{"version":"c3b41e74b9a84b88b1dca61ec39eee25c0dbc8e7d519ba11bb070918cfacf656","affectsGlobalScope":true,"impliedFormat":1},{"version":"4737a9dc24d0e68b734e6cfbcea0c15a2cfafeb493485e27905f7856988c6b29","affectsGlobalScope":true,"impliedFormat":1},{"version":"36d8d3e7506b631c9582c251a2c0b8a28855af3f76719b12b534c6edf952748d","impliedFormat":1},{"version":"1ca69210cc42729e7ca97d3a9ad48f2e9cb0042bada4075b588ae5387debd318","impliedFormat":1},{"version":"f5ebe66baaf7c552cfa59d75f2bfba679f329204847db3cec385acda245e574e","impliedFormat":1},{"version":"ed59add13139f84da271cafd32e2171876b0a0af2f798d0c663e8eeb867732cf","affectsGlobalScope":true,"impliedFormat":1},{"version":"05db535df8bdc30d9116fe754a3473d1b6479afbc14ae8eb18b605c62677d518","impliedFormat":1},{"version":"b1810689b76fd473bd12cc9ee219f8e62f54a7d08019a235d07424afbf074d25","impliedFormat":1},{"version":"2beff543f6e9a9701df88daeee3cdd70a34b4a1c11cb4c734472195a5cb2af54","impliedFormat":1},{"version":"bfffea552cca245df227337223c7554b35df629ba1d4e09edee4521ce7f24827","impliedFormat":1},{"version":"be1cc4d94ea60cbe567bc29ed479d42587bf1e6cba490f123d329976b0fe4ee5","impliedFormat":1},{"version":"42bc0e1a903408137c3df2b06dfd7e402cdab5bbfa5fcfb871b22ebfdb30bd0b","impliedFormat":1},{"version":"9894dafe342b976d251aac58e616ac6df8db91fb9d98934ff9dd103e9e82578f","impliedFormat":1},{"version":"413df52d4ea14472c2fa5bee62f7a40abd1eb49be0b9722ee01ee4e52e63beb2","impliedFormat":1},{"version":"db6d2d9daad8a6d83f281af12ce4355a20b9a3e71b82b9f57cddcca0a8964a96","impliedFormat":1},{"version":"446a50749b24d14deac6f8843e057a6355dd6437d1fac4f9e5ce4a5071f34bff","impliedFormat":1},{"version":"182e9fcbe08ac7c012e0a6e2b5798b4352470be29a64fdc114d23c2bab7d5106","impliedFormat":1},{"version":"5c9b31919ea1cb350a7ae5e71c9ced8f11723e4fa258a8cc8d16ae46edd623c7","impliedFormat":1},{"version":"4aa42ce8383b45823b3a1d3811c0fdd5f939f90254bc4874124393febbaf89f6","impliedFormat":1},{"version":"96ffa70b486207241c0fcedb5d9553684f7fa6746bc2b04c519e7ebf41a51205","impliedFormat":1},{"version":"3677988e03b749874eb9c1aa8dc88cd77b6005e5c4c39d821cda7b80d5388619","impliedFormat":1},{"version":"a86f82d646a739041d6702101afa82dcb935c416dd93cbca7fd754fd0282ce1f","impliedFormat":1},{"version":"ad0d1d75d129b1c80f911be438d6b61bfa8703930a8ff2be2f0e1f8a91841c64","impliedFormat":1},{"version":"ce75b1aebb33d510ff28af960a9221410a3eaf7f18fc5f21f9404075fba77256","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"02436d7e9ead85e09a2f8e27d5f47d9464bced31738dec138ca735390815c9f0","impliedFormat":1},{"version":"f4625edcb57b37b84506e8b276eb59ca30d31f88c6656d29d4e90e3bc58e69df","impliedFormat":1},{"version":"78a2869ad0cbf3f9045dda08c0d4562b7e1b2bfe07b19e0db072f5c3c56e9584","impliedFormat":1},{"version":"f8d5ff8eafd37499f2b6a98659dd9b45a321de186b8db6b6142faed0fea3de77","impliedFormat":1},{"version":"c86fe861cf1b4c46a0fb7d74dffe596cf679a2e5e8b1456881313170f092e3fa","impliedFormat":1},{"version":"c685d9f68c70fe11ce527287526585a06ea13920bb6c18482ca84945a4e433a7","impliedFormat":1},{"version":"540cc83ab772a2c6bc509fe1354f314825b5dba3669efdfbe4693ecd3048e34f","impliedFormat":1},{"version":"121b0696021ab885c570bbeb331be8ad82c6efe2f3b93a6e63874901bebc13e3","impliedFormat":1},{"version":"4e01846df98d478a2a626ec3641524964b38acaac13945c2db198bf9f3df22ee","impliedFormat":1},{"version":"678d6d4c43e5728bf66e92fc2269da9fa709cb60510fed988a27161473c3853f","impliedFormat":1},{"version":"ffa495b17a5ef1d0399586b590bd281056cee6ce3583e34f39926f8dcc6ecdb5","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":1},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":1},{"version":"aa14cee20aa0db79f8df101fc027d929aec10feb5b8a8da3b9af3895d05b7ba2","impliedFormat":1},{"version":"493c700ac3bd317177b2eb913805c87fe60d4e8af4fb39c41f04ba81fae7e170","impliedFormat":1},{"version":"aeb554d876c6b8c818da2e118d8b11e1e559adbe6bf606cc9a611c1b6c09f670","impliedFormat":1},{"version":"acf5a2ac47b59ca07afa9abbd2b31d001bf7448b041927befae2ea5b1951d9f9","impliedFormat":1},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":1},{"version":"d71291eff1e19d8762a908ba947e891af44749f3a2cbc5bd2ec4b72f72ea795f","impliedFormat":1},{"version":"c0480e03db4b816dff2682b347c95f2177699525c54e7e6f6aa8ded890b76be7","impliedFormat":1},{"version":"e2a37ac938c4bede5bb284b9d2d042da299528f1e61f6f57538f1bd37d760869","impliedFormat":1},{"version":"76def37aff8e3a051cf406e10340ffba0f28b6991c5d987474cc11137796e1eb","impliedFormat":1},{"version":"b620391fe8060cf9bedc176a4d01366e6574d7a71e0ac0ab344a4e76576fcbb8","impliedFormat":1},{"version":"3e7efde639c6a6c3edb9847b3f61e308bf7a69685b92f665048c45132f51c218","impliedFormat":1},{"version":"df45ca1176e6ac211eae7ddf51336dc075c5314bc5c253651bae639defd5eec5","impliedFormat":1},{"version":"106c6025f1d99fd468fd8bf6e5bda724e11e5905a4076c5d29790b6c3745e50c","impliedFormat":1},{"version":"ee8df1cb8d0faaca4013a1b442e99130769ce06f438d18d510fed95890067563","impliedFormat":1},{"version":"bfb7f8475428637bee12bdd31bd9968c1c8a1cc2c3e426c959e2f3a307f8936f","impliedFormat":1},{"version":"6f491d0108927478d3247bbbc489c78c2da7ef552fd5277f1ab6819986fdf0b1","impliedFormat":1},{"version":"594fe24fc54645ab6ccb9dba15d3a35963a73a395b2ef0375ea34bf181ccfd63","impliedFormat":1},{"version":"7cb0ee103671d1e201cd53dda12bc1cd0a35f1c63d6102720c6eeb322cb8e17e","impliedFormat":1},{"version":"15a234e5031b19c48a69ccc1607522d6e4b50f57d308ecb7fe863d44cd9f9eb3","impliedFormat":1},{"version":"148679c6d0f449210a96e7d2e562d589e56fcde87f843a92808b3ff103f1a774","impliedFormat":1},{"version":"6459054aabb306821a043e02b89d54da508e3a6966601a41e71c166e4ea1474f","impliedFormat":1},{"version":"2f9c89cbb29d362290531b48880a4024f258c6033aaeb7e59fbc62db26819650","impliedFormat":1},{"version":"bb37588926aba35c9283fe8d46ebf4e79ffe976343105f5c6d45f282793352b2","impliedFormat":1},{"version":"05c97cddbaf99978f83d96de2d8af86aded9332592f08ce4a284d72d0952c391","impliedFormat":1},{"version":"72179f9dd22a86deaad4cc3490eb0fe69ee084d503b686985965654013f1391b","impliedFormat":1},{"version":"2e6114a7dd6feeef85b2c80120fdbfb59a5529c0dcc5bfa8447b6996c97a69f5","impliedFormat":1},{"version":"7b6ff760c8a240b40dab6e4419b989f06a5b782f4710d2967e67c695ef3e93c4","impliedFormat":1},{"version":"c8f004e6036aa1c764ad4ec543cf89a5c1893a9535c80ef3f2b653e370de45e6","impliedFormat":1},{"version":"dd80b1e600d00f5c6a6ba23f455b84a7db121219e68f89f10552c54ba46e4dc9","impliedFormat":1},{"version":"b064c36f35de7387d71c599bfcf28875849a1dbc733e82bd26cae3d1cd060521","impliedFormat":1},{"version":"05c7280d72f3ed26f346cbe7cbbbb002fb7f15739197cbbee6ab3fd1a6cb9347","impliedFormat":1},{"version":"8de9fe97fa9e00ec00666fa77ab6e91b35d25af8ca75dabcb01e14ad3299b150","impliedFormat":1},{"version":"803cd2aaf1921c218916c2c7ee3fce653e852d767177eb51047ff15b5b253893","impliedFormat":1},{"version":"dba114fb6a32b355a9cfc26ca2276834d72fe0e94cd2c3494005547025015369","impliedFormat":1},{"version":"7ab12b2f1249187223d11a589f5789c75177a0b597b9eb7f8e2e42d045393347","impliedFormat":1},{"version":"ad37fb4be61c1035b68f532b7220f4e8236cf245381ce3b90ac15449ecfe7305","impliedFormat":1},{"version":"93436bd74c66baba229bfefe1314d122c01f0d4c1d9e35081a0c4f0470ac1a6c","impliedFormat":1},{"version":"f974e4a06953682a2c15d5bd5114c0284d5abf8bc0fe4da25cb9159427b70072","impliedFormat":1},{"version":"50256e9c31318487f3752b7ac12ff365c8949953e04568009c8705db802776fb","impliedFormat":1},{"version":"7d73b24e7bf31dfb8a931ca6c4245f6bb0814dfae17e4b60c9e194a631fe5f7b","impliedFormat":1},{"version":"d130c5f73768de51402351d5dc7d1b36eaec980ca697846e53156e4ea9911476","impliedFormat":1},{"version":"413586add0cfe7369b64979d4ec2ed56c3f771c0667fbde1bf1f10063ede0b08","impliedFormat":1},{"version":"06472528e998d152375ad3bd8ebcb69ff4694fd8d2effaf60a9d9f25a37a097a","impliedFormat":1},{"version":"50b5bc34ce6b12eccb76214b51aadfa56572aa6cc79c2b9455cdbb3d6c76af1d","impliedFormat":1},{"version":"b7e16ef7f646a50991119b205794ebfd3a4d8f8e0f314981ebbe991639023d0e","impliedFormat":1},{"version":"42c169fb8c2d42f4f668c624a9a11e719d5d07dacbebb63cbcf7ef365b0a75b3","impliedFormat":1},{"version":"a401617604fa1f6ce437b81689563dfdc377069e4c58465dbd8d16069aede0a5","impliedFormat":1},{"version":"6e9082e91370de5040e415cd9f24e595b490382e8c7402c4e938a8ce4bccc99f","impliedFormat":1},{"version":"8695dec09ad439b0ceef3776ea68a232e381135b516878f0901ed2ea114fd0fe","impliedFormat":1},{"version":"304b44b1e97dd4c94697c3313df89a578dca4930a104454c99863f1784a54357","impliedFormat":1},{"version":"d682336018141807fb602709e2d95a192828fcb8d5ba06dda3833a8ea98f69e3","impliedFormat":1},{"version":"6124e973eab8c52cabf3c07575204efc1784aca6b0a30c79eb85fe240a857efa","impliedFormat":1},{"version":"0d891735a21edc75df51f3eb995e18149e119d1ce22fd40db2b260c5960b914e","impliedFormat":1},{"version":"3b414b99a73171e1c4b7b7714e26b87d6c5cb03d200352da5342ab4088a54c85","impliedFormat":1},{"version":"4fbd3116e00ed3a6410499924b6403cc9367fdca303e34838129b328058ede40","impliedFormat":1},{"version":"b01bd582a6e41457bc56e6f0f9de4cb17f33f5f3843a7cf8210ac9c18472fb0f","impliedFormat":1},{"version":"0a437ae178f999b46b6153d79095b60c42c996bc0458c04955f1c996dc68b971","impliedFormat":1},{"version":"74b2a5e5197bd0f2e0077a1ea7c07455bbea67b87b0869d9786d55104006784f","impliedFormat":1},{"version":"4a7baeb6325920044f66c0f8e5e6f1f52e06e6d87588d837bdf44feb6f35c664","impliedFormat":1},{"version":"12d218a49dbe5655b911e6cc3c13b2c655e4c783471c3b0432137769c79e1b3c","impliedFormat":1},{"version":"7274fbffbd7c9589d8d0ffba68157237afd5cecff1e99881ea3399127e60572f","impliedFormat":1},{"version":"6b0fc04121360f752d196ba35b6567192f422d04a97b2840d7d85f8b79921c92","impliedFormat":1},{"version":"65a15fc47900787c0bd18b603afb98d33ede930bed1798fc984d5ebb78b26cf9","impliedFormat":1},{"version":"9d202701f6e0744adb6314d03d2eb8fc994798fc83d91b691b75b07626a69801","impliedFormat":1},{"version":"a365c4d3bed3be4e4e20793c999c51f5cd7e6792322f14650949d827fbcd170f","impliedFormat":1},{"version":"c5426dbfc1cf90532f66965a7aa8c1136a78d4d0f96d8180ecbfc11d7722f1a5","impliedFormat":1},{"version":"9c82171d836c47486074e4ca8e059735bf97b205e70b196535b5efd40cbe1bc5","impliedFormat":1},{"version":"f374cb24e93e7798c4d9e83ff872fa52d2cdb36306392b840a6ddf46cb925cb6","impliedFormat":1},{"version":"42b81043b00ff27c6bd955aea0f6e741545f2265978bf364b614702b72a027ab","impliedFormat":1},{"version":"de9d2df7663e64e3a91bf495f315a7577e23ba088f2949d5ce9ec96f44fba37d","impliedFormat":1},{"version":"c7af78a2ea7cb1cd009cfb5bdb48cd0b03dad3b54f6da7aab615c2e9e9d570c5","impliedFormat":1},{"version":"1ee45496b5f8bdee6f7abc233355898e5bf9bd51255db65f5ff7ede617ca0027","impliedFormat":1},{"version":"97e5ccc7bb88419005cbdf812243a5b3186cdef81b608540acabe1be163fc3e4","affectsGlobalScope":true,"impliedFormat":1},{"version":"3fbdd025f9d4d820414417eeb4107ffa0078d454a033b506e22d3a23bc3d9c41","affectsGlobalScope":true,"impliedFormat":1},{"version":"a8f8e6ab2fa07b45251f403548b78eaf2022f3c2254df3dc186cb2671fe4996d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fa6c12a7c0f6b84d512f200690bfc74819e99efae69e4c95c4cd30f6884c526e","impliedFormat":1},{"version":"f1c32f9ce9c497da4dc215c3bc84b722ea02497d35f9134db3bb40a8d918b92b","impliedFormat":1},{"version":"b73c319af2cc3ef8f6421308a250f328836531ea3761823b4cabbd133047aefa","affectsGlobalScope":true,"impliedFormat":1},{"version":"e433b0337b8106909e7953015e8fa3f2d30797cea27141d1c5b135365bb975a6","impliedFormat":1},{"version":"9f9bb6755a8ce32d656ffa4763a8144aa4f274d6b69b59d7c32811031467216e","impliedFormat":1},{"version":"5c32bdfbd2d65e8fffbb9fbda04d7165e9181b08dad61154961852366deb7540","impliedFormat":1},{"version":"ddff7fc6edbdc5163a09e22bf8df7bef75f75369ebd7ecea95ba55c4386e2441","impliedFormat":1},{"version":"6b3453eebd474cc8acf6d759f1668e6ce7425a565e2996a20b644c72916ecf75","impliedFormat":1},{"version":"0c05e9842ec4f8b7bfebfd3ca61604bb8c914ba8da9b5337c4f25da427a005f2","impliedFormat":1},{"version":"89cd3444e389e42c56fd0d072afef31387e7f4107651afd2c03950f22dc36f77","impliedFormat":1},{"version":"7f2aa4d4989a82530aaac3f72b3dceca90e9c25bee0b1a327e8a08a1262435ad","impliedFormat":1},{"version":"e39a304f882598138a8022106cb8de332abbbb87f3fee71c5ca6b525c11c51fc","impliedFormat":1},{"version":"faed7a5153215dbd6ebe76dfdcc0af0cfe760f7362bed43284be544308b114cf","impliedFormat":1},{"version":"fcdf3e40e4a01b9a4b70931b8b51476b210c511924fcfe3f0dae19c4d52f1a54","impliedFormat":1},{"version":"345c4327b637d34a15aba4b7091eb068d6ab40a3dedaab9f00986253c9704e53","impliedFormat":1},{"version":"3a788c7fb7b1b1153d69a4d1d9e1d0dfbcf1127e703bdb02b6d12698e683d1fb","impliedFormat":1},{"version":"2e4f37ffe8862b14d8e24ae8763daaa8340c0df0b859d9a9733def0eee7562d9","impliedFormat":1},{"version":"d38530db0601215d6d767f280e3a3c54b2a83b709e8d9001acb6f61c67e965fc","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"4805f6161c2c8cefb8d3b8bd96a080c0fe8dbc9315f6ad2e53238f9a79e528a6","impliedFormat":1},{"version":"b83cb14474fa60c5f3ec660146b97d122f0735627f80d82dd03e8caa39b4388c","impliedFormat":1},{"version":"2b5b70d7782fe028487a80a1c214e67bd610532b9f978b78fa60f5b4a359f77e","impliedFormat":1},{"version":"7ee86fbb3754388e004de0ef9e6505485ddfb3be7640783d6d015711c03d302d","impliedFormat":1},{"version":"1a82deef4c1d39f6882f28d275cad4c01f907b9b39be9cbc472fcf2cf051e05b","impliedFormat":1},{"version":"7580e62139cb2b44a0270c8d01abcbfcba2819a02514a527342447fa69b34ef1","impliedFormat":1},{"version":"b73cbf0a72c8800cf8f96a9acfe94f3ad32ca71342a8908b8ae484d61113f647","impliedFormat":1},{"version":"bae6dd176832f6423966647382c0d7ba9e63f8c167522f09a982f086cd4e8b23","impliedFormat":1},{"version":"20865ac316b8893c1a0cc383ccfc1801443fbcc2a7255be166cf90d03fac88c9","impliedFormat":1},{"version":"c9958eb32126a3843deedda8c22fb97024aa5d6dd588b90af2d7f2bfac540f23","impliedFormat":1},{"version":"461d0ad8ae5f2ff981778af912ba71b37a8426a33301daa00f21c6ccb27f8156","impliedFormat":1},{"version":"e927c2c13c4eaf0a7f17e6022eee8519eb29ef42c4c13a31e81a611ab8c95577","impliedFormat":1},{"version":"fcafff163ca5e66d3b87126e756e1b6dfa8c526aa9cd2a2b0a9da837d81bbd72","impliedFormat":1},{"version":"70246ad95ad8a22bdfe806cb5d383a26c0c6e58e7207ab9c431f1cb175aca657","impliedFormat":1},{"version":"f00f3aa5d64ff46e600648b55a79dcd1333458f7a10da2ed594d9f0a44b76d0b","impliedFormat":1},{"version":"772d8d5eb158b6c92412c03228bd9902ccb1457d7a705b8129814a5d1a6308fc","impliedFormat":1},{"version":"802e797bcab5663b2c9f63f51bdf67eff7c41bc64c0fd65e6da3e7941359e2f7","impliedFormat":1},{"version":"8b4327413e5af38cd8cb97c59f48c3c866015d5d642f28518e3a891c469f240e","impliedFormat":1},{"version":"7e6ac205dcb9714f708354fd863bffa45cee90740706cc64b3b39b23ebb84744","impliedFormat":1},{"version":"61dc6e3ac78d64aa864eedd0a208b97b5887cc99c5ba65c03287bf57d83b1eb9","impliedFormat":1},{"version":"4b20fcf10a5413680e39f5666464859fc56b1003e7dfe2405ced82371ebd49b6","impliedFormat":1},{"version":"c06ef3b2569b1c1ad99fcd7fe5fba8d466e2619da5375dfa940a94e0feea899b","impliedFormat":1},{"version":"f7d628893c9fa52ba3ab01bcb5e79191636c4331ee5667ecc6373cbccff8ae12","impliedFormat":1},{"version":"1d879125d1ec570bf04bc1f362fdbe0cb538315c7ac4bcfcdf0c1e9670846aa6","impliedFormat":1},{"version":"f730b468deecf26188ad62ee8950dc29aa2aea9543bb08ed714c3db019359fd9","impliedFormat":1},{"version":"933aee906d42ea2c53b6892192a8127745f2ec81a90695df4024308ba35a8ff4","impliedFormat":1},{"version":"d663134457d8d669ae0df34eabd57028bddc04fc444c4bc04bc5215afc91e1f4","impliedFormat":1},{"version":"144bc326e90b894d1ec78a2af3ffb2eb3733f4d96761db0ca0b6239a8285f972","impliedFormat":1},{"version":"a3e3f0efcae272ab8ee3298e4e819f7d9dd9ff411101f45444877e77cfeca9a4","impliedFormat":1},{"version":"43e96a3d5d1411ab40ba2f61d6a3192e58177bcf3b133a80ad2a16591611726d","impliedFormat":1},{"version":"58659b06d33fa430bee1105b75cf876c0a35b2567207487c8578aec51ca2d977","impliedFormat":1},{"version":"71d9eb4c4e99456b78ae182fb20a5dfc20eb1667f091dbb9335b3c017dd1c783","impliedFormat":1},{"version":"cfa846a7b7847a1d973605fbb8c91f47f3a0f0643c18ac05c47077ebc72e71c7","impliedFormat":1},{"version":"30e6520444df1a004f46fdc8096f3fe06f7bbd93d09c53ada9dcdde59919ccca","impliedFormat":1},{"version":"6c800b281b9e89e69165fd11536195488de3ff53004e55905e6c0059a2d8591e","impliedFormat":1},{"version":"7d4254b4c6c67a29d5e7f65e67d72540480ac2cfb041ca484847f5ae70480b62","impliedFormat":1},{"version":"a58beefce74db00dbb60eb5a4bb0c6726fb94c7797c721f629142c0ae9c94306","impliedFormat":1},{"version":"41eeb453ccb75c5b2c3abef97adbbd741bd7e9112a2510e12f03f646dc9ad13d","impliedFormat":1},{"version":"502fa5863df08b806dbf33c54bee8c19f7e2ad466785c0fc35465d7c5ff80995","impliedFormat":1},{"version":"c91a2d08601a1547ffef326201be26db94356f38693bb18db622ae5e9b3d7c92","impliedFormat":1},{"version":"888cda0fa66d7f74e985a3f7b1af1f64b8ff03eb3d5e80d051c3cbdeb7f32ab7","impliedFormat":1},{"version":"60681e13f3545be5e9477acb752b741eae6eaf4cc01658a25ec05bff8b82a2ef","impliedFormat":1},{"version":"9586918b63f24124a5ca1d0cc2979821a8a57f514781f09fc5aa9cae6d7c0138","impliedFormat":1},{"version":"a57b1802794433adec9ff3fed12aa79d671faed86c49b09e02e1ac41b4f1d33a","impliedFormat":1},{"version":"ad10d4f0517599cdeca7755b930f148804e3e0e5b5a3847adce0f1f71bbccd74","impliedFormat":1},{"version":"1042064ece5bb47d6aba91648fbe0635c17c600ebdf567588b4ca715602f0a9d","impliedFormat":1},{"version":"c49469a5349b3cc1965710b5b0f98ed6c028686aa8450bcb3796728873eb923e","impliedFormat":1},{"version":"4a889f2c763edb4d55cb624257272ac10d04a1cad2ed2948b10ed4a7fda2a428","impliedFormat":1},{"version":"7bb79aa2fead87d9d56294ef71e056487e848d7b550c9a367523ee5416c44cfa","impliedFormat":1},{"version":"d88ea80a6447d7391f52352ec97e56b52ebec934a4a4af6e2464cfd8b39c3ba8","impliedFormat":1},{"version":"55095860901097726220b6923e35a812afdd49242a1246d7b0942ee7eb34c6e4","impliedFormat":1},{"version":"96171c03c2e7f314d66d38acd581f9667439845865b7f85da8df598ff9617476","impliedFormat":1},{"version":"27ff4196654e6373c9af16b6165120e2dd2169f9ad6abb5c935af5abd8c7938c","impliedFormat":1},{"version":"bb8f2dbc03533abca2066ce4655c119bff353dd4514375beb93c08590c03e023","impliedFormat":1},{"version":"d193c8a86144b3a87b22bc1f5534b9c3e0f5a187873ec337c289a183973a58fe","impliedFormat":1},{"version":"1a6e6ba8a07b74e3ad237717c0299d453f9ceb795dbc2f697d1f2dd07cb782d2","impliedFormat":1},{"version":"58d70c38037fc0f949243388ff7ae20cf43321107152f14a9d36ca79311e0ada","impliedFormat":1},{"version":"f56bdc6884648806d34bc66d31cdb787c4718d04105ce2cd88535db214631f82","impliedFormat":1},{"version":"190da5eac6478d61ab9731ab2146fbc0164af2117a363013249b7e7992f1cccb","impliedFormat":1},{"version":"01479d9d5a5dda16d529b91811375187f61a06e74be294a35ecce77e0b9e8d6c","impliedFormat":1},{"version":"49f95e989b4632c6c2a578cc0078ee19a5831832d79cc59abecf5160ea71abad","impliedFormat":1},{"version":"9666533332f26e8995e4d6fe472bdeec9f15d405693723e6497bf94120c566c8","impliedFormat":1},{"version":"ce0df82a9ae6f914ba08409d4d883983cc08e6d59eb2df02d8e4d68309e7848b","impliedFormat":1},{"version":"796273b2edc72e78a04e86d7c58ae94d370ab93a0ddf40b1aa85a37a1c29ecd7","impliedFormat":1},{"version":"5df15a69187d737d6d8d066e189ae4f97e41f4d53712a46b2710ff9f8563ec9f","impliedFormat":1},{"version":"1a4dc28334a926d90ba6a2d811ba0ff6c22775fcc13679521f034c124269fd40","impliedFormat":1},{"version":"f05315ff85714f0b87cc0b54bcd3dde2716e5a6b99aedcc19cad02bf2403e08c","impliedFormat":1},{"version":"8a8c64dafaba11c806efa56f5c69f611276471bef80a1db1f71316ec4168acef","impliedFormat":1},{"version":"43ba4f2fa8c698f5c304d21a3ef596741e8e85a810b7c1f9b692653791d8d97a","impliedFormat":1},{"version":"5fad3b31fc17a5bc58095118a8b160f5260964787c52e7eb51e3d4fcf5d4a6f0","impliedFormat":1},{"version":"72105519d0390262cf0abe84cf41c926ade0ff475d35eb21307b2f94de985778","impliedFormat":1},{"version":"d0a4cac61fa080f2be5ebb68b82726be835689b35994ba0e22e3ed4d2bc45e3b","impliedFormat":1},{"version":"c857e0aae3f5f444abd791ec81206020fbcc1223e187316677e026d1c1d6fe08","impliedFormat":1},{"version":"ccf6dd45b708fb74ba9ed0f2478d4eb9195c9dfef0ff83a6092fa3cf2ff53b4f","impliedFormat":1},{"version":"2d7db1d73456e8c5075387d4240c29a2a900847f9c1bff106a2e490da8fbd457","impliedFormat":1},{"version":"2b15c805f48e4e970f8ec0b1915f22d13ca6212375e8987663e2ef5f0205e832","impliedFormat":1},{"version":"205a31b31beb7be73b8df18fcc43109cbc31f398950190a0967afc7a12cb478c","impliedFormat":1},{"version":"8fca3039857709484e5893c05c1f9126ab7451fa6c29e19bb8c2411a2e937345","impliedFormat":1},{"version":"35069c2c417bd7443ae7c7cafd1de02f665bf015479fec998985ffbbf500628c","impliedFormat":1},{"version":"dba6c7006e14a98ec82999c6f89fbbbfd1c642f41db148535f3b77b8018829b8","impliedFormat":1},{"version":"7f897b285f22a57a5c4dc14a27da2747c01084a542b4d90d33897216dceeea2e","impliedFormat":1},{"version":"7e0b7f91c5ab6e33f511efc640d36e6f933510b11be24f98836a20a2dc914c2d","impliedFormat":1},{"version":"045b752f44bf9bbdcaffd882424ab0e15cb8d11fa94e1448942e338c8ef19fba","impliedFormat":1},{"version":"2894c56cad581928bb37607810af011764a2f511f575d28c9f4af0f2ef02d1ab","impliedFormat":1},{"version":"0a72186f94215d020cb386f7dca81d7495ab6c17066eb07d0f44a5bf33c1b21a","impliedFormat":1},{"version":"d96b39301d0ded3f1a27b47759676a33a02f6f5049bfcbde81e533fd10f50dcb","impliedFormat":1},{"version":"2ded4f930d6abfaa0625cf55e58f565b7cbd4ab5b574dd2cb19f0a83a2f0be8b","impliedFormat":1},{"version":"0aedb02516baf3e66b2c1db9fef50666d6ed257edac0f866ea32f1aa05aa474f","impliedFormat":1},{"version":"ca0f4d9068d652bad47e326cf6ba424ac71ab866e44b24ddb6c2bd82d129586a","affectsGlobalScope":true,"impliedFormat":1},{"version":"04d36005fcbeac741ac50c421181f4e0316d57d148d37cc321a8ea285472462b","impliedFormat":1},{"version":"9e2739b32f741859263fdba0244c194ca8e96da49b430377930b8f721d77c000","impliedFormat":1},{"version":"56ccb49443bfb72e5952f7012f0de1a8679f9f75fc93a5c1ac0bafb28725fc5f","impliedFormat":1},{"version":"20fa37b636fdcc1746ea0738f733d0aed17890d1cd7cb1b2f37010222c23f13e","impliedFormat":1},{"version":"d90b9f1520366d713a73bd30c5a9eb0040d0fb6076aff370796bc776fd705943","impliedFormat":1},{"version":"bc03c3c352f689e38c0ddd50c39b1e65d59273991bfc8858a9e3c0ebb79c023b","impliedFormat":1},{"version":"19df3488557c2fc9b4d8f0bac0fd20fb59aa19dec67c81f93813951a81a867f8","affectsGlobalScope":true,"impliedFormat":1},{"version":"b25350193e103ae90423c5418ddb0ad1168dc9c393c9295ef34980b990030617","affectsGlobalScope":true,"impliedFormat":1},{"version":"bef86adb77316505c6b471da1d9b8c9e428867c2566270e8894d4d773a1c4dc2","impliedFormat":1},{"version":"a46dba563f70f32f9e45ae015f3de979225f668075d7a427f874e0f6db584991","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"2652448ac55a2010a1f71dd141f828b682298d39728f9871e1cdf8696ef443fd","impliedFormat":1},{"version":"02c4fc9e6bb27545fa021f6056e88ff5fdf10d9d9f1467f1d10536c6e749ac50","impliedFormat":1},{"version":"120599fd965257b1f4d0ff794bc696162832d9d8467224f4665f713a3119078b","impliedFormat":1},{"version":"5433f33b0a20300cca35d2f229a7fc20b0e8477c44be2affeb21cb464af60c76","impliedFormat":1},{"version":"db036c56f79186da50af66511d37d9fe77fa6793381927292d17f81f787bb195","impliedFormat":1},{"version":"bd4131091b773973ca5d2326c60b789ab1f5e02d8843b3587effe6e1ea7c9d86","impliedFormat":1},{"version":"c7f6485931085bf010fbaf46880a9b9ec1a285ad9dc8c695a9e936f5a48f34b4","impliedFormat":1},{"version":"14f6b927888a1112d662877a5966b05ac1bf7ed25d6c84386db4c23c95a5363b","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"622694a8522b46f6310c2a9b5d2530dde1e2854cb5829354e6d1ff8f371cf469","impliedFormat":1},{"version":"d24ff95760ea2dfcc7c57d0e269356984e7046b7e0b745c80fea71559f15bdd8","impliedFormat":1},{"version":"a9e6c0ff3f8186fccd05752cf75fc94e147c02645087ac6de5cc16403323d870","impliedFormat":1},{"version":"49c346823ba6d4b12278c12c977fb3a31c06b9ca719015978cb145eb86da1c61","impliedFormat":1},{"version":"bfac6e50eaa7e73bb66b7e052c38fdc8ccfc8dbde2777648642af33cf349f7f1","impliedFormat":1},{"version":"92f7c1a4da7fbfd67a2228d1687d5c2e1faa0ba865a94d3550a3941d7527a45d","impliedFormat":1},{"version":"f53b120213a9289d9a26f5af90c4c686dd71d91487a0aa5451a38366c70dc64b","impliedFormat":1},{"version":"83fe880c090afe485a5c02262c0b7cdd76a299a50c48d9bde02be8e908fb4ae6","impliedFormat":1},{"version":"13c1b657932e827a7ed510395d94fc8b743b9d053ab95b7cd829b2bc46fb06db","impliedFormat":1},{"version":"57d67b72e06059adc5e9454de26bbfe567d412b962a501d263c75c2db430f40e","impliedFormat":1},{"version":"6511e4503cf74c469c60aafd6589e4d14d5eb0a25f9bf043dcbecdf65f261972","impliedFormat":1},{"version":"078131f3a722a8ad3fc0b724cd3497176513cdcb41c80f96a3acbda2a143b58e","impliedFormat":1},{"version":"8c70ddc0c22d85e56011d49fddfaae3405eb53d47b59327b9dd589e82df672e7","impliedFormat":1},{"version":"a67b87d0281c97dfc1197ef28dfe397fc2c865ccd41f7e32b53f647184cc7307","impliedFormat":1},{"version":"771ffb773f1ddd562492a6b9aaca648192ac3f056f0e1d997678ff97dbb6bf9b","impliedFormat":1},{"version":"232f70c0cf2b432f3a6e56a8dc3417103eb162292a9fd376d51a3a9ea5fbbf6f","impliedFormat":1},{"version":"9e155d2255348d950b1f65643fb26c0f14f5109daf8bd9ee24a866ad0a743648","affectsGlobalScope":true,"impliedFormat":1},{"version":"0b103e9abfe82d14c0ad06a55d9f91d6747154ef7cacc73cf27ecad2bfb3afcf","impliedFormat":1},{"version":"7a883e9c84e720810f86ef4388f54938a65caa0f4d181a64e9255e847a7c9f51","impliedFormat":1},{"version":"a0ba218ac1baa3da0d5d9c1ec1a7c2f8676c284e6f5b920d6d049b13fa267377","impliedFormat":1},{"version":"8a0e762ceb20c7e72504feef83d709468a70af4abccb304f32d6b9bac1129b2c","impliedFormat":1},{"version":"d408d6f32de8d1aba2ff4a20f1aa6a6edd7d92c997f63b90f8ad3f9017cf5e46","impliedFormat":1},{"version":"9252d498a77517aab5d8d4b5eb9d71e4b225bbc7123df9713e08181de63180f6","impliedFormat":1},{"version":"b1f1d57fde8247599731b24a733395c880a6561ec0c882efaaf20d7df968c5af","impliedFormat":1},{"version":"9d622ea608d43eb463c0c4538fd5baa794bc18ea0bb8e96cd2ab6fd483d55fe2","impliedFormat":1},{"version":"35e6379c3f7cb27b111ad4c1aa69538fd8e788ab737b8ff7596a1b40e96f4f90","impliedFormat":1},{"version":"1fffe726740f9787f15b532e1dc870af3cd964dbe29e191e76121aa3dd8693f2","impliedFormat":1},{"version":"371bf6127c1d427836de95197155132501cb6b69ef8709176ce6e0b85d059264","impliedFormat":1},{"version":"2bafd700e617d3693d568e972d02b92224b514781f542f70d497a8fdf92d52a2","affectsGlobalScope":true,"impliedFormat":1},{"version":"5542d8a7ea13168cb573be0d1ba0d29460d59430fb12bb7bf4674efd5604e14c","impliedFormat":1},{"version":"af48e58339188d5737b608d41411a9c054685413d8ae88b8c1d0d9bfabdf6e7e","impliedFormat":1},{"version":"616775f16134fa9d01fc677ad3f76e68c051a056c22ab552c64cc281a9686790","impliedFormat":1},{"version":"65c24a8baa2cca1de069a0ba9fba82a173690f52d7e2d0f1f7542d59d5eb4db0","impliedFormat":1},{"version":"f9fe6af238339a0e5f7563acee3178f51db37f32a2e7c09f85273098cee7ec49","impliedFormat":1},{"version":"1de8c302fd35220d8f29dea378a4ae45199dc8ff83ca9923aca1400f2b28848a","impliedFormat":1},{"version":"77e71242e71ebf8528c5802993697878f0533db8f2299b4d36aa015bae08a79c","impliedFormat":1},{"version":"98a787be42bd92f8c2a37d7df5f13e5992da0d967fab794adbb7ee18370f9849","impliedFormat":1},{"version":"332248ee37cca52903572e66c11bef755ccc6e235835e63d3c3e60ddda3e9b93","impliedFormat":1},{"version":"94e8cc88ae2ef3d920bb3bdc369f48436db123aa2dc07f683309ad8c9968a1e1","impliedFormat":1},{"version":"4545c1a1ceca170d5d83452dd7c4994644c35cf676a671412601689d9a62da35","impliedFormat":1},{"version":"320f4091e33548b554d2214ce5fc31c96631b513dffa806e2e3a60766c8c49d9","impliedFormat":1},{"version":"a2d648d333cf67b9aeac5d81a1a379d563a8ffa91ddd61c6179f68de724260ff","impliedFormat":1},{"version":"d90d5f524de38889d1e1dbc2aeef00060d779f8688c02766ddb9ca195e4a713d","impliedFormat":1},{"version":"a3f41ed1b4f2fc3049394b945a68ae4fdefd49fa1739c32f149d32c0545d67f5","impliedFormat":1},{"version":"b0309e1eda99a9e76f87c18992d9c3689b0938266242835dd4611f2b69efe456","impliedFormat":1},{"version":"47699512e6d8bebf7be488182427189f999affe3addc1c87c882d36b7f2d0b0e","impliedFormat":1},{"version":"6ceb10ca57943be87ff9debe978f4ab73593c0c85ee802c051a93fc96aaf7a20","impliedFormat":1},{"version":"1de3ffe0cc28a9fe2ac761ece075826836b5a02f340b412510a59ba1d41a505a","impliedFormat":1},{"version":"e46d6cc08d243d8d0d83986f609d830991f00450fb234f5b2f861648c42dc0d8","impliedFormat":1},{"version":"1c0a98de1323051010ce5b958ad47bc1c007f7921973123c999300e2b7b0ecc0","impliedFormat":1},{"version":"ff863d17c6c659440f7c5c536e4db7762d8c2565547b2608f36b798a743606ca","impliedFormat":1},{"version":"5412ad0043cd60d1f1406fc12cb4fb987e9a734decbdd4db6f6acf71791e36fe","impliedFormat":1},{"version":"ad036a85efcd9e5b4f7dd5c1a7362c8478f9a3b6c3554654ca24a29aa850a9c5","impliedFormat":1},{"version":"fedebeae32c5cdd1a85b4e0504a01996e4a8adf3dfa72876920d3dd6e42978e7","impliedFormat":1},{"version":"b6c1f64158da02580f55e8a2728eda6805f79419aed46a930f43e68ad66a38fc","impliedFormat":1},{"version":"cdf21eee8007e339b1b9945abf4a7b44930b1d695cc528459e68a3adc39a622e","impliedFormat":1},{"version":"bc9ee0192f056b3d5527bcd78dc3f9e527a9ba2bdc0a2c296fbc9027147df4b2","impliedFormat":1},{"version":"330896c1a2b9693edd617be24fbf9e5895d6e18c7955d6c08f028f272b37314d","impliedFormat":1},{"version":"1d9c0a9a6df4e8f29dc84c25c5aa0bb1da5456ebede7a03e03df08bb8b27bae6","impliedFormat":1},{"version":"84380af21da938a567c65ef95aefb5354f676368ee1a1cbb4cae81604a4c7d17","impliedFormat":1},{"version":"1af3e1f2a5d1332e136f8b0b95c0e6c0a02aaabd5092b36b64f3042a03debf28","impliedFormat":1},{"version":"30d8da250766efa99490fc02801047c2c6d72dd0da1bba6581c7e80d1d8842a4","impliedFormat":1},{"version":"03566202f5553bd2d9de22dfab0c61aa163cabb64f0223c08431fb3fc8f70280","impliedFormat":1},{"version":"4c0a1233155afb94bd4d7518c75c84f98567cd5f13fc215d258de196cdb40d91","impliedFormat":1},{"version":"e7765aa8bcb74a38b3230d212b4547686eb9796621ffb4367a104451c3f9614f","impliedFormat":1},{"version":"1de80059b8078ea5749941c9f863aa970b4735bdbb003be4925c853a8b6b4450","impliedFormat":1},{"version":"1d079c37fa53e3c21ed3fa214a27507bda9991f2a41458705b19ed8c2b61173d","impliedFormat":1},{"version":"5bf5c7a44e779790d1eb54c234b668b15e34affa95e78eada73e5757f61ed76a","impliedFormat":1},{"version":"5835a6e0d7cd2738e56b671af0e561e7c1b4fb77751383672f4b009f4e161d70","impliedFormat":1},{"version":"5c634644d45a1b6bc7b05e71e05e52ec04f3d73d9ac85d5927f647a5f965181a","impliedFormat":1},{"version":"4b7f74b772140395e7af67c4841be1ab867c11b3b82a51b1aeb692822b76c872","impliedFormat":1},{"version":"27be6622e2922a1b412eb057faa854831b95db9db5035c3f6d4b677b902ab3b7","impliedFormat":1},{"version":"a68d4b3182e8d776cdede7ac9630c209a7bfbb59191f99a52479151816ef9f9e","impliedFormat":99},{"version":"39644b343e4e3d748344af8182111e3bbc594930fff0170256567e13bbdbebb0","impliedFormat":99},{"version":"ed7fd5160b47b0de3b1571c5c5578e8e7e3314e33ae0b8ea85a895774ee64749","impliedFormat":99},{"version":"63a7595a5015e65262557f883463f934904959da563b4f788306f699411e9bac","impliedFormat":1},{"version":"4ba137d6553965703b6b55fd2000b4e07ba365f8caeb0359162ad7247f9707a6","impliedFormat":1},{"version":"6de125ea94866c736c6d58d68eb15272cf7d1020a5b459fea1c660027eca9a90","affectsGlobalScope":true,"impliedFormat":1},{"version":"8fac4a15690b27612d8474fb2fc7cc00388df52d169791b78d1a3645d60b4c8b","affectsGlobalScope":true,"impliedFormat":1},{"version":"064ac1c2ac4b2867c2ceaa74bbdce0cb6a4c16e7c31a6497097159c18f74aa7c","impliedFormat":1},{"version":"3dc14e1ab45e497e5d5e4295271d54ff689aeae00b4277979fdd10fa563540ae","impliedFormat":1},{"version":"d3b315763d91265d6b0e7e7fa93cfdb8a80ce7cdd2d9f55ba0f37a22db00bdb8","impliedFormat":1},{"version":"b789bf89eb19c777ed1e956dbad0925ca795701552d22e68fd130a032008b9f9","impliedFormat":1},{"version":"4e2bcf03609885297fc50894bbc98bba5fd87314f4928607ba3cce55ba0f758c","affectsGlobalScope":true},"7ad303e40d4fddf44f156129e397511953a71481c5cfd86b1862649aaaf240cc",{"version":"b5dfc894c0b7557f5608426a7706d3d06e5ea4e692c390591220de07b95b5100","signature":"435a1e418e8338be3f39614b96b81a9aa2700bc8c27bc6b98f064ff9ce17c363"},{"version":"1fcda46aa50e28629f590ed076b2665534f4e3e37a82bb175f5e89a05a899af4","signature":"0ab8b69798ae8c82ab1dc9e4561b38fc6ebb2831ac400025248c79e71bbd7450"},{"version":"c57b441e0c0a9cbdfa7d850dae1f8a387d6f81cbffbc3cd0465d530084c2417d","impliedFormat":99},{"version":"51954e948be6a5b728fcfaf561f12331b4f54f068934c77adfc8f70eea17d285","impliedFormat":1},{"version":"7c8c3dfc0cdd370d44932828eb067ef771c8fe7996693221d5d4b90af6d54f2d","signature":"512960c0e955a2324b34354dac25e3e4d431a1af4cd33077935eda5e95c8b7e1"},{"version":"637ba401e988f8015ac63e6442d66f2e7075c255a0f724f938fe13d9f3a07d56","signature":"cf45e31c18f3dcc0108f3a048f41faabf5cb8bdc3abfe7d9cf04117ecd51953a"},{"version":"9315a990ae2ab955de57ac9245ab4e81b8721eb3cb93657a47ec7a5043618f33","signature":"7559880017b339fb1639c7cb347abb191b5dad5840cdaf1abb7c66bd6264469e"},{"version":"404ada78dd509dd45900cd61f05dcd625f522bba61db3459f118f0381797a512","signature":"4c7eb443cd26541bdf8ca2e8c850d8b898bf81a328f8623be0016e4eaf7e14e2"},{"version":"e5287147eff9b851a51db2eec40641e145f52773d0b5b2144e6a49d245cf3a54","signature":"9823497dd68348a82349f81dca194ae69f0a3b2ac0c3da4b6194c6b4721e3d34"},{"version":"8083b431527d46566cb0184580c8d0073a3f5031fefbda2a5362b76c7115efe5","signature":"9eddc6aa521983a0798dab419767998c652baf50ca8cae412b06386185ead253"},{"version":"09e5e068e44753d52600ede5065f3ac8fbb8f7484ff602039fe3069bd8812ca6","signature":"28427465c0c2bbba1c9a7a7dbd097de6271ab39d892e929626420a0bb90c260a"},{"version":"56b7fd30208addbcc2468cfda4f5bc0a55342211deaab61ee35b1c352b1622f1","signature":"f774a7e8875649db68f5952801f001f3c316560ede472e5663af7a8c9c18f938"},{"version":"c44b79c4a8330d58abdaa037ed2528f49ee1bd9c903a6df157a4fa553a94e253","signature":"5e167eeed008f7aca224011e14ff21f7de30719195f32162f7f49d970420e5b3"},{"version":"1abc9a90914e34d26e7284a3aaab7036959dffd12dfee4b8f177da45f3823d18","signature":"50b5991a0d649da68f02eb124e15755d575d0cc38d0feaa11d9e390f19e1a543"},{"version":"2fbe402f0ee5aa8ab55367f88030f79d46211c0a0f342becaa9f648bf8534e9d","impliedFormat":1},{"version":"b94258ef37e67474ac5522e9c519489a55dcb3d4a8f645e335fc68ea2215fe88","impliedFormat":1},{"version":"024829c0b317972acf4f871bf701525f81896ad74015f1a52d46ae6036205cb9","impliedFormat":99},{"version":"a9373d52584b48809ffd61d74f5b3dfd127da846e3c4ee3c415560386df3994b","impliedFormat":99},{"version":"caf4af98bf464ad3e10c46cf7d340556f89197aab0f87f032c7b84eb8ddb24d9","impliedFormat":99},{"version":"0943a6e4e026d0de8a4969ee975a7283e0627bf41aa4635d8502f6f24365ac9b","impliedFormat":99},{"version":"1461efc4aefd3e999244f238f59c9b9753a7e3dfede923ebe2b4a11d6e13a0d0","impliedFormat":99},{"version":"7ec047b73f621c526468517fea779fec2007dd05baa880989def59126c98ef79","impliedFormat":99},{"version":"8dd450de6d756cee0761f277c6dc58b0b5a66b8c274b980949318b8cad26d712","impliedFormat":99},{"version":"904d6ad970b6bd825449480488a73d9b98432357ab38cf8d31ffd651ae376ff5","impliedFormat":99},{"version":"dfcf16e716338e9fe8cf790ac7756f61c85b83b699861df970661e97bf482692","impliedFormat":99},{"version":"31c30cc54e8c3da37c8e2e40e5658471f65915df22d348990d1601901e8c9ff3","impliedFormat":99},{"version":"36d8011f1437aecf0e6e88677d933e4fb3403557f086f4ac00c5a4cb6d028ac2","impliedFormat":99},{"version":"8085954ba165e611c6230596078063627f3656fed3fb68ad1e36a414c4d7599a","impliedFormat":99},{"version":"2c57db2bf2dbd9e8ef4853be7257d62a1cb72845f7b976bb4ee827d362675f96","impliedFormat":99},{"version":"6b5f886fe41e2e767168e491fe6048398ed6439d44e006d9f51cc31265f08978","impliedFormat":99},{"version":"56a87e37f91f5625eb7d5f8394904f3f1e2a90fb08f347161dc94f1ae586bdd0","impliedFormat":99},{"version":"6b863463764ae572b9ada405bf77aac37b5e5089a3ab420d0862e4471051393b","impliedFormat":99},{"version":"68b6a7501a56babd7bcd840e0d638ee7ec582f1e70b3c36ebf32e5e5836913c8","impliedFormat":99},{"version":"89783bd45ab35df55203b522f8271500189c3526976af533a599a86caaf31362","impliedFormat":99},{"version":"6da2e0928bdab05861abc4e4abebea0c7cf0b67e25374ba35a94df2269563dd8","impliedFormat":99},{"version":"e7b00bec016013bcde74268d837a8b57173951add2b23c8fd12ffe57f204d88f","impliedFormat":99},{"version":"26e6c521a290630ea31f0205a46a87cab35faac96e2b30606f37bae7bcda4f9d","impliedFormat":99},{"version":"71acd198e19fa38447a3cbc5c33f2f5a719d933fccf314aaff0e8b0593271324","impliedFormat":99},{"version":"044047026c70439867589d8596ffe417b56158a1f054034f590166dd793b676b","impliedFormat":99},{"version":"89ad9a4e8044299f356f38879a1c2176bc60c997519b442c92cc5a70b731a360","impliedFormat":99},{"version":"fd4f58cd6b5fc8ce8af0d04bfef5142f15c4bafaac9a9899c6daa056f10bb517","impliedFormat":99},{"version":"2a00cea77767cb26393ee6f972fd32941249a0d65b246bfcb20a780a2b919a21","impliedFormat":99},{"version":"440cb5b34e06fabe3dcb13a3f77b98d771bf696857c8e97ce170b4f345f8a26b","impliedFormat":99},{"version":"5bc7f0946c94e23765bd1b8f62dc3ab65d7716285ca7cf45609f57777ddb436f","impliedFormat":99},{"version":"7d5a5e603a68faea3d978630a84cacad7668f11e14164c4dd10224fa1e210f56","impliedFormat":99},{"version":"2535fc1a5fe64892783ff8f61321b181c24f824e688a4a05ae738da33466605b","impliedFormat":99},{"version":"cbfd5ef0c8fdb4983202252b5f5758a579f4500edc3b9ad413da60cffb5c3564","impliedFormat":99},{"version":"9f7a3c434912fd3feb87af4aabdf0d1b614152ecb5e7b2aa1fff3429879cdd51","impliedFormat":99},{"version":"99d1a601593495371e798da1850b52877bf63d0678f15722d5f048e404f002e4","impliedFormat":99},{"version":"1179ef8174e0e4a09d35576199df04803b1db17c0fb35b9326442884bc0b0cce","impliedFormat":99},{"version":"9c580c6eae94f8c9a38373566e59d5c3282dc194aa266b23a50686fe10560159","impliedFormat":99},{"version":"cc3738ba01d9af5ba1206a313896837ff8779791afcd9869e582783550f17f38","impliedFormat":99},{"version":"a80ec72f5e178862476deaeed532c305bdfcd3627014ae7ac2901356d794fc93","impliedFormat":99},{"version":"4a5aa16151dbec524bb043a5cbce2c3fec75957d175475c115a953aca53999a9","impliedFormat":99},{"version":"7a14bf21ae8a29d64c42173c08f026928daf418bed1b97b37ac4bb2aa197b89b","impliedFormat":99},{"version":"c5013d60cbff572255ccc87c314c39e198c8cc6c5aa7855db7a21b79e06a510f","impliedFormat":99},{"version":"69ec8d900cfec3d40e50490fedbbea5c1b49d32c38adbc236e73a3b8978c0b11","impliedFormat":99},{"version":"7fd629484ba6772b686885b443914655089246f75a13dd685845d0abae337671","impliedFormat":99},{"version":"13dcccb62e8537329ac0448f088ab16fe5b0bbed71e56906d28d202072759804","impliedFormat":99},{"version":"233267a4a036c64aee95f66a0d31e3e0ef048cccc57dd66f9cf87582b38691e4","impliedFormat":99},{"version":"ccb9fbe369885d02cf6c2b2948fb5060451565d37b04356bbe753807f98e0682","impliedFormat":99},{"version":"cd98acc71988e234da58315ba3d98b9592dfc91e646cebaafc1d205609ce5eae","signature":"6526c0c717c72f5bf7406b7e30f659c8fa717779bc91f5acd75d5aacf3538c81"},{"version":"11e68c033fdb70e1679da12dc4b28d972eadc080706f004bd1a35204bd4ab1e8","signature":"9a6f416f1affb6e80601662c648b8044c8ef2e29ac7c361452929922feac1a7e"},{"version":"4990e4db21902ea579df93462cad953ae5999b7b2ffef7c717e8bb89136bfc8f","signature":"8b8009eb4b85a5427120395d0e14b09e98aa3405debdb9856310fe483e6f1635"},{"version":"2aee0b10b030d30b17d7f209c9f8e04f15003f0cf398f931596b4527fc20366d","signature":"bd5ff0a222d1bf3f946cea793373823c0d825ed32d7b0aa1a9b6826869647606"},{"version":"203e5da05d75208139daa4c2eb0ac5920d8d8658a0b64caa89ba5d091e7f0d1f","signature":"db0f21003be8d241ee7b2015f7e9da660baf2b0df1a7395854c0e8e7372330fc"},"b2c5b0dbb95b3d01cb4e244c2caa199828d6c1d825c657b7c8289ed75bd1b75d",{"version":"a751b107c997575cc1663c83990ca2a57a2afd20f84db806e46dc7fe43462212","signature":"3f89d0dc76db56c5572c5a6320dc5c9c9d06aee6e6017046846a584243a3187a"},{"version":"e5f0fe6f397c20a40a3081b17b919ee176fa5a64bf13cc85afc156a34c68f9a9","signature":"6c993c3de03245ec8b13b5f9a6a120140c32ff0726f9ceab829e1a91a3d5a365"},{"version":"d069de3a0b5d290992e07994435a566472f45c205d9063fd9248b78b1f18d055","signature":"181d3d2b1fde5383f956de47b4167afe714162fbe527e3ec7ced7b6a721ac0b3"},{"version":"7b26babdb8f6d7c613c306774e6344a9f906bc6137a45411abfce80ff47133c7","signature":"a02afe8e783fff375ad32fef935861b597c9e55a857cf5bbdc1cc6208f89e95a"},"291bedfa6f99d0789469f781778fc8b04a52d64e3a4acfbb0e3147eabdcd7574",{"version":"fa1fce9c6eee2f0469573c2ceb0532b6d0fc318c8c90651e70f53db54291da52","signature":"a5f9ac5b5f3d49f819e094fdbffadb6ee122bf8afe2aa1287cd734db77c8e867"},{"version":"2899fdb96853a762ffa3b1b87f07f6ed2cd1ff01694315d1c77ed1965961738e","signature":"e62331fe066698dc4ef6f11156b8c8e94ed213ce0bca377d1822000550b59227"},{"version":"63825877d01fb510a016b83ea912d16723f7ac69e6eb0be2362c43aa29d3e9bb","signature":"ecb7f171b247d393dbf56b5dad49a225e3a1447d4f330cf2dfdfb8a8d2d83337"},{"version":"2bf6dd65f5e701f312a0d9c85f7d5487d6f39f37f68600d61582d488aaeefc43","signature":"39a99c2d331b851f350715aec36b1762bf4ec8c74c8c0719aac976eab5d90b03"},{"version":"6a584c73348dbeaf93d13334e5d5a31e5a6cf6e07a308d2dd0332b9840214858","signature":"3d406ad304fc6a89843dea4fdab881c22cdbe3f056d16b1f60ea6e0b8a7f43c7"},{"version":"a4a1f2173e9a16e66cff4f5d8a0382771ee88e9675e48ca8c138f4d241e1fda6","signature":"a709e61e18be65b7fea9af899e162dfc1cff7871e41703a4ca71fa625968fcf7"},{"version":"26e13fb86799603b1466b9dd61d09176a0a514a62353f1691c4b381c7affd933","signature":"4c461c5ef657d516139314509aa907f547f15e5270f183c301e80d8b04566e50"},{"version":"798541acd745cf9ad5f6b866dce4dc76514b94e2a80d8d7589bbcea2c96905c2","signature":"9da824a4605d14f726000b1b02201c5bc779db984f1014273bd3d5281773950f"},"c4e62c45813a3f9c94dafe8aedde5901bc9a7062272e9b5b9594dd9c23476d5d",{"version":"2ce6960a92287faa8db1a354c46acfe5b2f413735446b4a31178949b7a76ec80","signature":"4e9f7b1d8b2bd823899b17eb86c158d275b4a431c2b61bf22384d67ee2a947c3"},{"version":"d2dd7f5664c9544e3e0c6ea420501d7788aa08e9aa343e1b494343d5e59acafc","signature":"6f0bbd59319d2743cfe7c0d8662f2d3c61e5e71ee0a22e2ec4ee599cb1edad5c"},{"version":"584d05cbeb95e046ec4a2b09e5b6319516d023077f951786960517c5e14323d7","signature":"257dcfa3a17211c30f5465c462718d05ef93b5fa1a8dede18dd18644d2db9585"},{"version":"83958c64cf2b6bbbb07a41a54d8192e9f1154ea77536de5c1e2860449b324c90","signature":"484da7e31d644a9fa3474e4dcbb512c49d7fa36d8c66e784881f44312ef5b159"},{"version":"a0d37f7bb1216d24c3098c0389c517d251c0f3bc4952ff59e84c58f149e34117","signature":"4a0acc246b4db680771238bbf2ac463c6fd89fdb63e118bc90f62178ffcabcb8"},{"version":"80efad9069a3de8cc57a7ccadff8c885b0d523f93b8eff02747463a849575ead","signature":"05c3da4bf74c562be8ee6d7e6ca3815d609185f6220a37914b23c9cd1eaecef1"},{"version":"db78d48db56d85e7335d5f44c71e34c624a7aec4b133579c52e73e08610d6767","signature":"6d3e9eba92764290200af96fe981214b49cf6aecc5d1f2f07bd0e85a444fe9cd"},{"version":"4dbf867fef63c9e2da157f54c1aab87da23e47d3e7aa42d109a149a6f3b27191","signature":"cf6187ef6f3cd756a46fd2625bc3ab570f8a18b9fcb19758dbd8edf2ab33ef43"},{"version":"d7dfba64b7350cb9501c544fe8ceba1b2455b42029d22b1a4fd02e94a6783525","impliedFormat":1},{"version":"32b1bf8067bdd69ec60fb1b89e02542fcdf48137c954cd24347987abc75d9253","signature":"acff1cc908d36a8fd8bf87dfb1d1a77a648b30cc05492f42616b3526b9df3ee9"},{"version":"0749bc9e06a09965ba080243ade7b0429a1084442bd47c5fcc98fbfc282b5fc6","signature":"dba5e1f9665f2b884a6ecab153ca04c5a65bbfc24c334aa46e5ed01ac4545cf1"},{"version":"5935b23690c79ef7afe038fbfda057ebc0292b2e2ca9240e300e2105a302b1e0","signature":"b741b233eb5fc90bcb185913b28a6352ea60ad06894c0723c87a2dda67fc07bb"},{"version":"855aca681fa70da14a638dfcde1d5d32fb07f965b6f902de56273f0963107802","signature":"d8e18d8dc04a5742372b2ca6d25ba1b1828c4ff8f6d0f62975884b751d79d41a"},{"version":"1608a3c7c24e2b8f08895b3900e08c358c547510ead3e2dbe1ea207fc7b2616d","signature":"95738327dec0765473fb6594fea782fef739f0c09a62495bededfe6f226a18c8"},{"version":"e9723bcca0b3778d6b283a7ea5aad1543a88fc7e8135d93eee38572e77eead05","signature":"acaf510f21581df355507afa1144677354247b210d55ecfa6962fa0d737eb7aa"},{"version":"dfb654161469a15d4337429c2d512513ade1136a6622ac4b738391611c056516","signature":"6f76f8ba8e98b7750208fb276de24524fbe6ec2155171ca577d927730641e041"},{"version":"413223c50b4e21563858e9179fde6cf80a5d6594f3c900beee5890ad056d19fb","signature":"209a6588ccbaf1f727a1a09d845fe823d9c7f21e98becb55c015a512e98e7c23"},"b3e982f365b9a2aa114eb18456524815db81373eaf2465c8234ce45b0d77a2db",{"version":"7768989e6df9a462b76103e1e8ef3184f6bbcba5957607d2858593562c03dc70","signature":"96d4643a12c310191eb8f9786e23b01119cd9e47147874f36ee6579ffeb33b5a"},{"version":"5dc48f5f3317a23913d8d88670eba92bf5709017225f0205a5df702984e8b55c","signature":"f6d0b28169314b71d949de60e4b8507e8212a28db9ea8b5aece79ba9e705c277"},{"version":"effcdc084e0149aaef939b53e00d705e88a65e2cecb6a26cb1f8e6a60356256e","signature":"df0e4873fe49e9666bbe89a3b8642f0cdcd888dedad7790ee13caaaabe3e29aa"},{"version":"e40da3c15940c4549500ea4a6e7752f719b313422c5577eb06a2dd9a9a1fef2c","signature":"89d925b8f8c8b9ca0d502787f40211439874b3af27d58ec45822c273334781c8"},{"version":"d4f9641d46da49a4d5b9650f4e743a28544bd91813f57372534521784904a427","signature":"1c82fc081b6e2929fad0686af09e129d53032f4779957572a87a38684f0b10a0"},"3c1693189dbd35b7c4beb8b8f8af3026df466840dc4d0ce6083678c9aba0ce3a",{"version":"f0ddd7290f7cb65447dba0851c3bf5ee1bcbbd6f2a9bc80b1e2ec8cf703d4c16","signature":"27892e35900d71ec247fda0e9fbfa31fe65a548728a70c026a9ca0c77bf0cc75"},{"version":"1f8933fc4d16a669667708455892725875fba6ea94ab415b1c579e76b23865ca","signature":"d32fd4471300ac4b3ed12214aa7ff39ef553733ea0ddee8c1fe46f555842d2b2"},{"version":"5d5bb6dc61034b4671a6ff5a23e506c12c14ac5979f71bd12c5553f8096e8d61","signature":"83bc5c4c2542019ec400b9e4632c70f838fd13ea97d2d4a4846176e53377e9fa"},{"version":"5bc7641943ffb91587d22889405c33209129e509f7f6cff4cdd627395c3c6690","signature":"3da83e1eca7015686fe30a435d79a0235852e7caf081a264db524a9a3d04f389"},{"version":"2004ba1fd4a7ee6dbffb3cf6790cf1d7c6e903330874ab97a2c45cfc364a71ea","signature":"2b51fd9d4735f434b95ba5e1443eb6b6d4ca6d4f9b2ae381860ea25cfe0ff9a3"},{"version":"b5ea1b88fbdf3a603e46987214f94227b41ddcf2be9d2aa3c2e77f43c007a2c7","signature":"84be61889b9aef6f4c23ac6fc8b40493abe31046f8f773933928a49b6d3a750f"},{"version":"0415760b0963802ca7429458ecc4e8e5dd1af12d34432c7f27de65604eba10e3","signature":"7a5393ad5a28775566b7d99844899d4c011a7c62ad20e06a6a9cdee779aa4bf1"},{"version":"23fcdd9fe5cec4384cee4a676abb92a2e3fadb82d0b0ad5cd3bb4c278ad77c85","signature":"65b84d35ac1de303cf7597643a6f3823f9314fe686f26cae5cee69a354d1fd45"},{"version":"b38d44699fcee65352d1091e35589109daa5740346a9f2f73c0b99a71cd3fcdb","signature":"34c2b9b80211b5a29523302d0916848ea96dbdfe3874449d7784deec101e0a2f"},{"version":"110bc06b62d8e96aecbf75dddca586d6885f7413b6ae729f1550ac012c985825","signature":"af5a709fd768fc524a76e4ab5b463a1515cd2c4f85e4150a387f5f02f2e9c392"},{"version":"90d681ab9c839ce3a932587a78d92efed70c9a22299223ee96bd9192a4b1d682","signature":"ec46a382669cad4c3a90fff53dbe8fea79efb74b114081417c5d378ef4961d0f"},"b6981662ce567c8a5b79b7a3e34dcc0e01bc34eee885950f147e55d56d1a1fbb",{"version":"e45fe0a539ca1e323f67438a40eec77a3191a0b26f27f95b49d0e3983eb372e0","signature":"b1f30d7fd29269a04cf5d74a6a4939f15f8f85b5ca9f56ba7023b53ad8fd2d3e"},{"version":"a9438a811154bf7f071ce731ad647f778ade1165132a04b4d8e71cdbd644c1cd","signature":"0f76e17f51f50434e9f61943cc134d4d864c21c517abb45adebcad14dc6cdf9d"},{"version":"e33b78d531939737c1aeee219dd4d8701459ae9d0f4f28b9479f9042e0c9eca7","signature":"46e74b0147b5cb2fb79baa80af9a0c3c353cbbbc9f26d1f1bf41de5e25e01295"},{"version":"a6c055bc1d52d848b21f30e7554add5dda2042c28d38f51c7406c9f0a27361a2","signature":"0e7fc58f08b7af73a462060ad9d6edfda75942f09fe3f4e86a1108b285f88cbd"},{"version":"5a028bc8cc79498b290a9ca7909c407abde3203f610d2e79708690641784aa7e","signature":"32aec89dfb03ff065ee8d7cdd89f8ba3f2df0a3bd8b9333669951fabc5959d9b"},{"version":"94a09fefd6024bb809ba7a71fbb1145f5401cf6debedb8be1f2fc1b764927fec","signature":"b61e206c530b657835b91b7b51c0ab683897b96e21751f167a160659484fc85d"},{"version":"773003e7c9c2eca0fac0aa5aea0afab776da16dc058960bb4d03190a6324488c","signature":"56936e183715c01af69a0dbf7aa06c3b216306c37b2fcb0318af04cf2cb2b252"},{"version":"923b2f0dc28afb09d57f5311216498e7a687b84959a6ba841e01657a2d256d2c","signature":"236977546854f19cb495fad14e19a624cbd9e919c3bc4e1840a4268d5fab0c9f"},{"version":"fc8a0dc854530763cf17978eba7a9f78e347ae073b26910c4d9b63d2aa43c247","signature":"c2e5287247bfabcf3c25a77148d0022ccff4a8e3c453112b5343a3c931341fe2"},{"version":"6e264da0496126aa575f5e5f9468283a1b6fa71abbb6797976eeffe40169ac27","signature":"63cec187dc61104e7b4daea9eebc3c4d0dd4da00327030473e58c8bfa3ebef87"},{"version":"02996fe0ea7c79d35429bcb2ca3443c56bedaba453b50ddaca673bcb877286fd","signature":"5863859a6c71f48270e2697742da89e00ad384476d8a720b9c21b3ff44fa2eab"},{"version":"2f5c3c8c00032eae2e4b94c9f783264d90cc8b4c4471596e4164ab8e164b8bb3","signature":"dff479a4c6d8026b0d4f3c0cdee6d159f46cc0fdebb13b0e3635d2b3dda1a572"},{"version":"755de32723e5ff49bf7961cc8f158d8b162cf9fa5aaeaf1e14d6cb87dc9e9b4f","signature":"495a55b824c998b6a588db9cd03ca3a65fb61495548807a392c367b82964f2f7"},{"version":"d29ee5bf3f2a5df0099bd26b80c890185e2abab56ea383abf3e06acc3720265b","signature":"552ff451c492073126b9300c5602ee9f05ed2e6af3c5860bf343cbdcbeccddc2"},"acbfc1c551dbf2e90284957b5a3851f6b9ceb6c5894b330c316133c9c52d83e7",{"version":"44aa743b5d821c699a88aae7059b5dc5798ef8580d867151b6e3f9e560e391ff","signature":"b8e76f70a321dd557f360cd6b5ddc324f04b668e96727ca50dd8d781227418b7"},{"version":"fe93c474ab38ac02e30e3af073412b4f92b740152cf3a751fdaee8cbea982341","impliedFormat":1},{"version":"f5705d196b442afbdbd971b6e44bad96f4e32afb53cebfa2e5afe3140017bfc6","impliedFormat":1},{"version":"1e00b8bf9e3766c958218cd6144ffe08418286f89ff44ba5a2cc830c03dd22c7","impliedFormat":1},{"version":"e48e3fcb69f062b06e7f2f949ceab65c52cc828155564fa0ff04622f609ce468","signature":"ff53dc24dd9f26eaca109b151c98025c3e47f72426866ab0bcd101e453dbc9dd"},{"version":"0c2a5e8e57f004cab6b15a36549162312dec7f04c28ec96155343c911af5f585","signature":"0c6f146bf5402327aa93d97c9e263e92bb63b4d87f2af155416cc7d0490a8224"},{"version":"82da3b5d80b919c10349d90236af940eaa861124b89f02ff21ba33fa3dace4c9","signature":"f5b5d4d2565e15fa4ea35249f6dfac49afe8d18383b09d6f2732010ea11ff387"},{"version":"e2051f3cda20e2cd81864802384b1058150085180f513e09a6115f9149dac450","signature":"d37676a4a785fdfca846f0072e1a73ed12a65474687006de46dde9f3e8955151"},{"version":"d3544b1daeb8e64aa8a9c0fc4ee74ef651c8cef67cff6ee2a1d9a32c99ed8048","signature":"81d4a86b11c11f29e32721433b59ad00d86ea0f3d29d5a62d004749643a7b359"},{"version":"6467beee18728a8596981186fbcf84a337a3ed0371843c6e2f71a2d714145948","signature":"c3cae5e74334bd48d834797d51e4f92c768fda9d2730da98258050f3a6270180"},{"version":"2bed8666717c7098829d24f99cbff26ccddd96494bad4e74693856d7e7b07bc2","signature":"f87853211625c35e9f5f4ca2d19531c0558918b55393576d2370a247532feff3"},{"version":"d458eb8260e5c5e6bb102b5fb9e1e330c5b7c25da4eb8c881a850aa99dbdb09f","signature":"65731e729672bb4c7a046a3052100348f8635af635fb7db2a1705932e1e05b79"},{"version":"3a6dbf000168315a57e0f331efc6c971e80f2ea49c83598b134c51bfa96b349d","signature":"6ac8ee5fa055cc96adfdf5633e880b951083945633409b284765dfa3d366d8e6"},{"version":"87d9e9fbc18d985156978d3e83bfc538c61e76362f4efd0e0956005c9f9bbede","signature":"f9f7b608197d9af5c280783e2b0159fa15da2bd2279521052c42d4b531f20412"},{"version":"0ef2df2c275c5d16191fc95ee0285917bb5be384068ea2e16a1b38a0809de47a","signature":"b4518efd230db6d5d48e4de5550505c6bcb8694af1e7d0de02c864fe40a2e17e"},{"version":"3aba1bf5c2d5fc655953f043c40464f7c95959518a49cf3c47cc9ad5d3c863a3","signature":"75304ca36ffeb1ff8704bd1ab02d4c56d90fc806f621f58a8bbc0b63ef8f4c46"},{"version":"f9d5e1672848926188f4987f39f30b6de4c6acac8ae012985f940513d961e506","signature":"368dabd96cecdd63aa60650ea1fa8a0b0d72238c5d9bdef5e2cb74450f8b1b7f"},{"version":"6dbd83d8aa66b16389225ca9fbce387c03c5b8196a34e0f7bab97a2d18480f6c","signature":"f4b667f3df658bb0c1d30273253fb779d866e21d040f8373ceac9d551339737e"},{"version":"2040cdff27cd1ed771e0ebbd15abcd73d31f2f1e4be6664bd6816fffd2a87476","signature":"1a6115819fa1e86a8fdfdef41f15eb65ba315a1ab6079a7db3f018bf72f4c0c2"},{"version":"bbd16f077778bb123cc86a16384751f53bfd22cee5cfdf6715862bdcd711cf12","signature":"b9f1bf3713fc43fd9e929b746540e6d606807cc121fe59d4454efdf3b009c18a"},"d1986184a09a52db8228cb2bb2a61a8c05c9354e5b93cec8e2628d8579c892d7",{"version":"6b7c5de2c74e5a7583c8618ecc559e57765acc1fcc46faa494d6caaeb1c2cd25","signature":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"},{"version":"151ff381ef9ff8da2da9b9663ebf657eac35c4c9a19183420c05728f31a6761d","impliedFormat":1},{"version":"f3d8c757e148ad968f0d98697987db363070abada5f503da3c06aefd9d4248c1","impliedFormat":1},{"version":"96d14f21b7652903852eef49379d04dbda28c16ed36468f8c9fa08f7c14c9538","impliedFormat":1}],"root":[[510,513],[516,525],[573,600],[602,644],[648,665]],"options":{"allowJs":true,"esModuleInterop":true,"jsx":4,"module":99,"skipLibCheck":true,"strict":true,"target":4},"referencedMap":[[664,1],[510,2],[665,3],[511,4],[512,5],[252,2],[528,6],[532,7],[537,8],[541,9],[538,9],[539,10],[540,11],[531,10],[546,12],[529,6],[536,13],[547,6],[533,9],[548,12],[534,9],[550,14],[551,15],[549,9],[545,16],[552,17],[554,18],[555,19],[556,6],[557,20],[543,21],[535,9],[530,6],[558,10],[559,22],[544,10],[560,10],[561,20],[562,9],[563,10],[564,6],[565,10],[566,22],[567,23],[569,24],[568,9],[570,25],[571,15],[553,9],[542,2],[666,2],[667,2],[668,2],[140,26],[141,26],[142,27],[97,28],[143,29],[144,30],[145,31],[92,2],[95,32],[93,2],[94,2],[146,33],[147,34],[148,35],[149,36],[150,37],[151,38],[152,38],[153,39],[154,40],[155,41],[156,42],[98,2],[96,2],[157,43],[158,44],[159,45],[191,46],[160,47],[161,48],[162,49],[163,50],[164,51],[165,52],[166,53],[167,54],[168,55],[169,56],[170,56],[171,57],[172,2],[173,58],[175,59],[174,60],[176,61],[177,62],[178,63],[179,64],[180,65],[181,66],[182,67],[183,68],[184,69],[185,70],[186,71],[187,72],[188,73],[99,2],[100,2],[101,2],[139,74],[189,75],[190,76],[195,77],[412,6],[196,78],[194,79],[414,80],[413,81],[192,82],[410,2],[193,83],[83,2],[85,84],[409,6],[269,6],[527,85],[526,86],[514,2],[84,2],[601,6],[459,87],[464,1],[454,88],[216,89],[256,90],[438,91],[251,92],[233,2],[408,2],[214,2],[427,93],[282,94],[215,2],[336,95],[259,96],[260,97],[407,98],[424,99],[318,100],[432,101],[433,102],[431,103],[430,2],[428,104],[258,105],[217,106],[361,2],[362,107],[288,108],[218,109],[289,108],[284,108],[205,108],[254,110],[253,2],[437,111],[449,2],[241,2],[383,112],[384,113],[378,6],[486,2],[386,2],[387,114],[379,115],[491,116],[490,117],[485,2],[303,2],[423,118],[422,2],[484,119],[380,6],[312,120],[308,121],[313,122],[311,2],[310,123],[309,2],[487,2],[483,2],[489,124],[488,2],[307,121],[478,125],[481,126],[297,127],[296,128],[295,129],[494,6],[294,130],[276,2],[497,2],[646,131],[645,2],[500,2],[499,6],[501,132],[198,2],[434,133],[435,134],[436,135],[211,2],[244,2],[210,136],[197,2],[399,6],[203,137],[398,138],[397,139],[388,2],[389,2],[396,2],[391,2],[394,140],[390,2],[392,141],[395,142],[393,141],[213,2],[208,2],[209,108],[264,2],[270,143],[271,144],[268,145],[266,146],[267,147],[262,2],[405,114],[291,114],[458,148],[465,149],[469,150],[441,151],[440,2],[279,2],[502,152],[453,153],[381,154],[382,155],[376,156],[367,2],[404,157],[443,6],[368,158],[406,159],[401,160],[400,2],[402,2],[373,2],[360,161],[442,162],[445,163],[370,164],[374,165],[365,166],[419,167],[452,168],[322,169],[337,170],[206,171],[451,172],[202,173],[272,174],[263,2],[273,175],[349,176],[261,2],[348,177],[91,2],[342,178],[243,2],[363,179],[338,2],[207,2],[237,2],[346,180],[212,2],[274,181],[372,182],[439,183],[371,2],[345,2],[265,2],[351,184],[352,185],[429,2],[354,186],[356,187],[355,188],[246,2],[344,171],[358,189],[321,190],[343,191],[350,192],[221,2],[225,2],[224,2],[223,2],[228,2],[222,2],[231,2],[230,2],[227,2],[226,2],[229,2],[232,193],[220,2],[330,194],[329,2],[334,195],[331,196],[333,197],[335,195],[332,196],[242,198],[292,199],[448,200],[503,2],[473,201],[475,202],[369,203],[474,204],[446,162],[385,162],[219,2],[323,205],[238,206],[239,207],[240,208],[236,209],[418,209],[286,209],[324,210],[287,210],[235,211],[234,2],[328,212],[327,213],[326,214],[325,215],[447,216],[417,217],[416,218],[377,219],[411,220],[415,221],[426,222],[425,223],[421,224],[320,225],[317,226],[319,227],[316,228],[357,229],[347,2],[463,2],[359,230],[420,2],[275,231],[366,133],[364,232],[277,233],[280,234],[498,2],[278,235],[281,235],[461,2],[460,2],[462,2],[496,2],[283,236],[444,2],[314,237],[306,6],[257,2],[201,238],[290,2],[467,6],[200,2],[477,239],[305,6],[471,114],[304,240],[456,241],[302,239],[204,2],[479,242],[300,6],[301,6],[293,2],[199,2],[299,243],[298,244],[245,245],[375,55],[285,55],[353,2],[340,246],[339,2],[403,121],[315,6],[450,136],[457,247],[86,6],[89,248],[90,249],[87,6],[88,2],[255,250],[250,251],[249,2],[248,252],[247,2],[455,253],[466,254],[468,255],[470,256],[647,257],[472,258],[476,259],[509,260],[480,260],[508,261],[482,262],[492,263],[493,264],[495,265],[504,266],[507,136],[506,2],[505,267],[572,268],[341,269],[515,2],[81,2],[82,2],[13,2],[14,2],[16,2],[15,2],[2,2],[17,2],[18,2],[19,2],[20,2],[21,2],[22,2],[23,2],[24,2],[3,2],[25,2],[26,2],[4,2],[27,2],[31,2],[28,2],[29,2],[30,2],[32,2],[33,2],[34,2],[5,2],[35,2],[36,2],[37,2],[38,2],[6,2],[42,2],[39,2],[40,2],[41,2],[43,2],[7,2],[44,2],[49,2],[50,2],[45,2],[46,2],[47,2],[48,2],[8,2],[54,2],[51,2],[52,2],[53,2],[55,2],[9,2],[56,2],[57,2],[58,2],[60,2],[59,2],[61,2],[62,2],[10,2],[63,2],[64,2],[65,2],[11,2],[66,2],[67,2],[68,2],[69,2],[70,2],[1,2],[71,2],[72,2],[12,2],[76,2],[74,2],[79,2],[78,2],[73,2],[77,2],[75,2],[80,2],[117,270],[127,271],[116,270],[137,272],[108,273],[107,274],[136,267],[130,275],[135,276],[110,277],[124,278],[109,279],[133,280],[105,281],[104,267],[134,282],[106,283],[111,284],[112,2],[115,284],[102,2],[138,285],[128,286],[119,287],[120,288],[122,289],[118,290],[121,291],[131,267],[113,292],[114,293],[123,294],[103,295],[126,286],[125,284],[129,2],[132,296],[654,297],[655,298],[656,299],[649,300],[650,301],[658,302],[659,303],[660,304],[525,305],[574,306],[524,307],[575,308],[576,309],[582,310],[522,311],[519,309],[513,305],[583,312],[518,313],[517,313],[586,314],[590,305],[588,315],[589,309],[591,316],[587,317],[584,305],[592,318],[585,319],[612,320],[616,321],[613,309],[615,322],[614,323],[611,324],[653,325],[648,326],[651,327],[627,328],[617,305],[628,329],[622,305],[621,330],[623,331],[624,309],[620,330],[626,332],[619,333],[618,334],[652,335],[625,336],[581,337],[604,338],[605,339],[597,340],[593,305],[599,305],[602,341],[596,114],[610,342],[600,309],[608,343],[609,344],[594,340],[598,340],[603,309],[595,340],[606,345],[634,346],[637,347],[633,348],[631,309],[643,349],[635,350],[632,351],[639,352],[641,305],[638,309],[640,353],[642,354],[629,355],[630,355],[661,356],[573,356],[662,335],[607,335],[523,335],[663,357],[636,358],[657,356],[577,353],[578,359],[520,305],[644,305],[580,305],[521,305],[579,305],[516,360]],"affectedFilesPendingEmit":[665,512,654,655,656,649,650,658,659,660,525,574,524,575,576,582,522,519,513,583,518,517,586,590,588,589,591,587,584,592,585,612,616,613,615,614,611,653,648,651,627,617,628,622,621,623,624,620,626,619,618,652,625,581,604,605,597,593,599,602,596,610,600,608,609,594,598,603,595,606,634,637,633,631,643,635,632,639,641,638,640,642,629,630,661,573,662,607,523,663,636,657,577,578,520,644,580,521,579,516],"version":"5.9.3"} \ No newline at end of file +{"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.es2021.d.ts","./node_modules/typescript/lib/lib.es2022.d.ts","./node_modules/typescript/lib/lib.es2023.d.ts","./node_modules/typescript/lib/lib.es2024.d.ts","./node_modules/typescript/lib/lib.esnext.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.es2021.promise.d.ts","./node_modules/typescript/lib/lib.es2021.string.d.ts","./node_modules/typescript/lib/lib.es2021.weakref.d.ts","./node_modules/typescript/lib/lib.es2021.intl.d.ts","./node_modules/typescript/lib/lib.es2022.array.d.ts","./node_modules/typescript/lib/lib.es2022.error.d.ts","./node_modules/typescript/lib/lib.es2022.intl.d.ts","./node_modules/typescript/lib/lib.es2022.object.d.ts","./node_modules/typescript/lib/lib.es2022.string.d.ts","./node_modules/typescript/lib/lib.es2022.regexp.d.ts","./node_modules/typescript/lib/lib.es2023.array.d.ts","./node_modules/typescript/lib/lib.es2023.collection.d.ts","./node_modules/typescript/lib/lib.es2023.intl.d.ts","./node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts","./node_modules/typescript/lib/lib.es2024.collection.d.ts","./node_modules/typescript/lib/lib.es2024.object.d.ts","./node_modules/typescript/lib/lib.es2024.promise.d.ts","./node_modules/typescript/lib/lib.es2024.regexp.d.ts","./node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts","./node_modules/typescript/lib/lib.es2024.string.d.ts","./node_modules/typescript/lib/lib.esnext.array.d.ts","./node_modules/typescript/lib/lib.esnext.collection.d.ts","./node_modules/typescript/lib/lib.esnext.intl.d.ts","./node_modules/typescript/lib/lib.esnext.disposable.d.ts","./node_modules/typescript/lib/lib.esnext.promise.d.ts","./node_modules/typescript/lib/lib.esnext.decorators.d.ts","./node_modules/typescript/lib/lib.esnext.iterator.d.ts","./node_modules/typescript/lib/lib.esnext.float16.d.ts","./node_modules/typescript/lib/lib.esnext.error.d.ts","./node_modules/typescript/lib/lib.esnext.sharedmemory.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/next/dist/styled-jsx/types/css.d.ts","./node_modules/next/dist/styled-jsx/types/macro.d.ts","./node_modules/next/dist/styled-jsx/types/style.d.ts","./node_modules/next/dist/styled-jsx/types/global.d.ts","./node_modules/next/dist/styled-jsx/types/index.d.ts","./node_modules/next/dist/server/get-page-files.d.ts","./node_modules/@types/node/compatibility/disposable.d.ts","./node_modules/@types/node/compatibility/indexable.d.ts","./node_modules/@types/node/compatibility/iterators.d.ts","./node_modules/@types/node/compatibility/index.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/domexception.d.ts","./node_modules/@types/node/web-globals/events.d.ts","./node_modules/undici-types/header.d.ts","./node_modules/undici-types/readable.d.ts","./node_modules/undici-types/file.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.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/agent.d.ts","./node_modules/undici-types/mock-interceptor.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/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/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/filereader.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/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.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/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/canary.d.ts","./node_modules/@types/react/experimental.d.ts","./node_modules/@types/react-dom/index.d.ts","./node_modules/@types/react-dom/canary.d.ts","./node_modules/@types/react-dom/experimental.d.ts","./node_modules/next/dist/lib/fallback.d.ts","./node_modules/next/dist/compiled/webpack/webpack.d.ts","./node_modules/next/dist/shared/lib/modern-browserslist-target.d.ts","./node_modules/next/dist/shared/lib/entry-constants.d.ts","./node_modules/next/dist/shared/lib/constants.d.ts","./node_modules/next/dist/server/config.d.ts","./node_modules/next/dist/lib/load-custom-routes.d.ts","./node_modules/next/dist/shared/lib/image-config.d.ts","./node_modules/next/dist/build/webpack/plugins/subresource-integrity-plugin.d.ts","./node_modules/next/dist/server/body-streams.d.ts","./node_modules/next/dist/server/lib/cache-control.d.ts","./node_modules/next/dist/lib/setup-exception-listeners.d.ts","./node_modules/next/dist/lib/worker.d.ts","./node_modules/next/dist/lib/constants.d.ts","./node_modules/next/dist/lib/bundler.d.ts","./node_modules/next/dist/server/lib/experimental/ppr.d.ts","./node_modules/next/dist/lib/page-types.d.ts","./node_modules/next/dist/build/segment-config/app/app-segment-config.d.ts","./node_modules/next/dist/build/segment-config/pages/pages-segment-config.d.ts","./node_modules/next/dist/build/analysis/get-page-static-info.d.ts","./node_modules/next/dist/build/webpack/loaders/get-module-build-info.d.ts","./node_modules/next/dist/build/webpack/plugins/middleware-plugin.d.ts","./node_modules/next/dist/server/require-hook.d.ts","./node_modules/next/dist/server/node-polyfill-crypto.d.ts","./node_modules/next/dist/server/node-environment-baseline.d.ts","./node_modules/next/dist/server/node-environment-extensions/error-inspect.d.ts","./node_modules/next/dist/server/node-environment-extensions/console-file.d.ts","./node_modules/next/dist/server/node-environment-extensions/console-exit.d.ts","./node_modules/next/dist/server/node-environment-extensions/console-dim.external.d.ts","./node_modules/next/dist/server/node-environment-extensions/unhandled-rejection.d.ts","./node_modules/next/dist/server/node-environment-extensions/random.d.ts","./node_modules/next/dist/server/node-environment-extensions/date.d.ts","./node_modules/next/dist/server/node-environment-extensions/web-crypto.d.ts","./node_modules/next/dist/server/node-environment-extensions/node-crypto.d.ts","./node_modules/next/dist/server/node-environment-extensions/fast-set-immediate.external.d.ts","./node_modules/next/dist/server/node-environment.d.ts","./node_modules/next/dist/build/page-extensions-type.d.ts","./node_modules/next/dist/server/route-kind.d.ts","./node_modules/next/dist/server/route-definitions/route-definition.d.ts","./node_modules/next/dist/server/route-definitions/app-page-route-definition.d.ts","./node_modules/next/dist/server/lib/cache-handlers/types.d.ts","./node_modules/next/dist/server/response-cache/types.d.ts","./node_modules/next/dist/server/resume-data-cache/cache-store.d.ts","./node_modules/next/dist/server/resume-data-cache/resume-data-cache.d.ts","./node_modules/next/dist/client/components/app-router-headers.d.ts","./node_modules/next/dist/server/render-result.d.ts","./node_modules/next/dist/server/instrumentation/types.d.ts","./node_modules/next/dist/lib/coalesced-function.d.ts","./node_modules/next/dist/shared/lib/router/utils/middleware-route-matcher.d.ts","./node_modules/next/dist/server/lib/router-utils/types.d.ts","./node_modules/next/dist/trace/types.d.ts","./node_modules/next/dist/trace/trace.d.ts","./node_modules/next/dist/trace/shared.d.ts","./node_modules/next/dist/trace/index.d.ts","./node_modules/next/dist/build/load-jsconfig.d.ts","./node_modules/@next/env/dist/index.d.ts","./node_modules/next/dist/build/webpack/plugins/telemetry-plugin/use-cache-tracker-utils.d.ts","./node_modules/next/dist/build/webpack/plugins/telemetry-plugin/telemetry-plugin.d.ts","./node_modules/next/dist/telemetry/storage.d.ts","./node_modules/next/dist/build/build-context.d.ts","./node_modules/next/dist/shared/lib/bloom-filter.d.ts","./node_modules/next/dist/build/webpack-config.d.ts","./node_modules/next/dist/build/swc/generated-native.d.ts","./node_modules/next/dist/build/swc/types.d.ts","./node_modules/next/dist/server/dev/parse-version-info.d.ts","./node_modules/next/dist/next-devtools/shared/types.d.ts","./node_modules/next/dist/server/dev/dev-indicator-server-state.d.ts","./node_modules/next/dist/next-devtools/dev-overlay/cache-indicator.d.ts","./node_modules/next/dist/server/lib/parse-stack.d.ts","./node_modules/next/dist/next-devtools/server/shared.d.ts","./node_modules/next/dist/next-devtools/shared/stack-frame.d.ts","./node_modules/next/dist/next-devtools/dev-overlay/utils/get-error-by-type.d.ts","./node_modules/@types/react/jsx-runtime.d.ts","./node_modules/next/dist/next-devtools/dev-overlay/container/runtime-error/render-error.d.ts","./node_modules/next/dist/next-devtools/dev-overlay/shared.d.ts","./node_modules/next/dist/server/dev/debug-channel.d.ts","./node_modules/next/dist/server/dev/hot-reloader-types.d.ts","./node_modules/next/dist/server/lib/i18n-provider.d.ts","./node_modules/next/dist/server/web/next-url.d.ts","./node_modules/next/dist/compiled/@edge-runtime/cookies/index.d.ts","./node_modules/next/dist/server/web/spec-extension/cookies.d.ts","./node_modules/next/dist/server/web/spec-extension/request.d.ts","./node_modules/next/dist/server/after/builtin-request-context.d.ts","./node_modules/next/dist/server/web/spec-extension/fetch-event.d.ts","./node_modules/next/dist/server/web/spec-extension/response.d.ts","./node_modules/next/dist/build/segment-config/middleware/middleware-config.d.ts","./node_modules/next/dist/server/web/types.d.ts","./node_modules/next/dist/build/webpack/plugins/pages-manifest-plugin.d.ts","./node_modules/next/dist/shared/lib/router/utils/parse-url.d.ts","./node_modules/next/dist/server/route-definitions/locale-route-definition.d.ts","./node_modules/next/dist/server/route-definitions/pages-route-definition.d.ts","./node_modules/next/dist/build/webpack/plugins/flight-manifest-plugin.d.ts","./node_modules/next/dist/build/webpack/plugins/next-font-manifest-plugin.d.ts","./node_modules/next/dist/shared/lib/deep-readonly.d.ts","./node_modules/next/dist/next-devtools/userspace/pages/pages-dev-overlay-setup.d.ts","./node_modules/next/dist/server/render.d.ts","./node_modules/next/dist/shared/lib/mitt.d.ts","./node_modules/next/dist/client/with-router.d.ts","./node_modules/next/dist/client/router.d.ts","./node_modules/next/dist/client/route-loader.d.ts","./node_modules/next/dist/client/page-loader.d.ts","./node_modules/next/dist/shared/lib/router/router.d.ts","./node_modules/next/dist/shared/lib/router-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/loadable-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/loadable.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/image-config-context.shared-runtime.d.ts","./node_modules/next/dist/client/components/readonly-url-search-params.d.ts","./node_modules/next/dist/shared/lib/hooks-client-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/head-manager-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/app-router-types.d.ts","./node_modules/next/dist/client/flight-data-helpers.d.ts","./node_modules/next/dist/client/components/router-reducer/ppr-navigations.d.ts","./node_modules/next/dist/client/components/segment-cache/types.d.ts","./node_modules/next/dist/client/components/segment-cache/navigation.d.ts","./node_modules/next/dist/client/components/segment-cache/cache-key.d.ts","./node_modules/next/dist/client/components/router-reducer/fetch-server-response.d.ts","./node_modules/next/dist/client/components/router-reducer/router-reducer-types.d.ts","./node_modules/next/dist/shared/lib/app-router-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/server-inserted-html.shared-runtime.d.ts","./node_modules/next/dist/server/route-modules/pages/vendored/contexts/entrypoints.d.ts","./node_modules/next/dist/server/route-modules/pages/module.compiled.d.ts","./node_modules/next/dist/build/templates/pages.d.ts","./node_modules/next/dist/server/route-modules/pages/module.d.ts","./node_modules/next/dist/server/route-modules/pages/builtin/_error.d.ts","./node_modules/next/dist/server/load-default-error-components.d.ts","./node_modules/next/dist/server/base-http/node.d.ts","./node_modules/next/dist/server/response-cache/index.d.ts","./node_modules/next/dist/server/route-definitions/pages-api-route-definition.d.ts","./node_modules/next/dist/server/route-matches/pages-api-route-match.d.ts","./node_modules/next/dist/server/route-matchers/route-matcher.d.ts","./node_modules/next/dist/server/route-matcher-providers/route-matcher-provider.d.ts","./node_modules/next/dist/server/route-matcher-managers/route-matcher-manager.d.ts","./node_modules/next/dist/server/normalizers/normalizer.d.ts","./node_modules/next/dist/server/normalizers/locale-route-normalizer.d.ts","./node_modules/next/dist/server/normalizers/request/pathname-normalizer.d.ts","./node_modules/next/dist/server/normalizers/request/suffix.d.ts","./node_modules/next/dist/server/normalizers/request/rsc.d.ts","./node_modules/next/dist/server/normalizers/request/next-data.d.ts","./node_modules/next/dist/server/normalizers/request/segment-prefix-rsc.d.ts","./node_modules/next/dist/build/static-paths/types.d.ts","./node_modules/next/dist/server/base-server.d.ts","./node_modules/next/dist/server/lib/async-callback-set.d.ts","./node_modules/next/dist/shared/lib/router/utils/route-regex.d.ts","./node_modules/next/dist/shared/lib/router/utils/route-matcher.d.ts","./node_modules/sharp/lib/index.d.ts","./node_modules/next/dist/server/image-optimizer.d.ts","./node_modules/next/dist/server/next-server.d.ts","./node_modules/next/dist/server/lib/types.d.ts","./node_modules/next/dist/server/lib/lru-cache.d.ts","./node_modules/next/dist/server/lib/dev-bundler-service.d.ts","./node_modules/next/dist/server/use-cache/cache-life.d.ts","./node_modules/next/dist/server/dev/static-paths-worker.d.ts","./node_modules/next/dist/server/dev/next-dev-server.d.ts","./node_modules/next/dist/server/next.d.ts","./node_modules/next/dist/server/lib/render-server.d.ts","./node_modules/next/dist/server/lib/router-server.d.ts","./node_modules/next/dist/shared/lib/router/utils/path-match.d.ts","./node_modules/next/dist/server/lib/router-utils/filesystem.d.ts","./node_modules/next/dist/server/lib/router-utils/setup-dev-bundler.d.ts","./node_modules/next/dist/server/lib/router-utils/router-server-context.d.ts","./node_modules/next/dist/server/route-modules/route-module.d.ts","./node_modules/next/dist/server/load-components.d.ts","./node_modules/next/dist/server/web/adapter.d.ts","./node_modules/next/dist/server/app-render/types.d.ts","./node_modules/next/dist/build/webpack/loaders/metadata/types.d.ts","./node_modules/next/dist/build/webpack/loaders/next-app-loader/index.d.ts","./node_modules/next/dist/server/lib/app-dir-module.d.ts","./node_modules/next/dist/server/web/spec-extension/adapters/request-cookies.d.ts","./node_modules/next/dist/server/async-storage/draft-mode-provider.d.ts","./node_modules/next/dist/server/web/spec-extension/adapters/headers.d.ts","./node_modules/next/dist/server/app-render/cache-signal.d.ts","./node_modules/next/dist/server/app-render/dynamic-rendering.d.ts","./node_modules/next/dist/server/request/fallback-params.d.ts","./node_modules/next/dist/server/app-render/work-unit-async-storage-instance.d.ts","./node_modules/next/dist/server/lib/lazy-result.d.ts","./node_modules/next/dist/server/lib/implicit-tags.d.ts","./node_modules/next/dist/server/app-render/staged-rendering.d.ts","./node_modules/next/dist/server/app-render/work-unit-async-storage.external.d.ts","./node_modules/next/dist/shared/lib/router/utils/parse-relative-url.d.ts","./node_modules/next/dist/server/app-render/app-render.d.ts","./node_modules/next/dist/server/route-modules/app-page/vendored/contexts/entrypoints.d.ts","./node_modules/next/dist/client/components/error-boundary.d.ts","./node_modules/next/dist/client/components/layout-router.d.ts","./node_modules/next/dist/client/components/render-from-template-context.d.ts","./node_modules/next/dist/server/app-render/action-async-storage-instance.d.ts","./node_modules/next/dist/server/app-render/action-async-storage.external.d.ts","./node_modules/next/dist/client/components/client-page.d.ts","./node_modules/next/dist/client/components/client-segment.d.ts","./node_modules/next/dist/server/request/search-params.d.ts","./node_modules/next/dist/client/components/hooks-server-context.d.ts","./node_modules/next/dist/client/components/http-access-fallback/error-boundary.d.ts","./node_modules/next/dist/lib/metadata/types/alternative-urls-types.d.ts","./node_modules/next/dist/lib/metadata/types/extra-types.d.ts","./node_modules/next/dist/lib/metadata/types/metadata-types.d.ts","./node_modules/next/dist/lib/metadata/types/manifest-types.d.ts","./node_modules/next/dist/lib/metadata/types/opengraph-types.d.ts","./node_modules/next/dist/lib/metadata/types/twitter-types.d.ts","./node_modules/next/dist/lib/metadata/types/metadata-interface.d.ts","./node_modules/next/dist/lib/metadata/types/resolvers.d.ts","./node_modules/next/dist/lib/metadata/types/icons.d.ts","./node_modules/next/dist/lib/metadata/resolve-metadata.d.ts","./node_modules/next/dist/lib/metadata/metadata.d.ts","./node_modules/next/dist/lib/framework/boundary-components.d.ts","./node_modules/next/dist/server/app-render/rsc/preloads.d.ts","./node_modules/next/dist/server/app-render/rsc/postpone.d.ts","./node_modules/next/dist/server/app-render/rsc/taint.d.ts","./node_modules/next/dist/shared/lib/segment-cache/segment-value-encoding.d.ts","./node_modules/next/dist/server/app-render/collect-segment-data.d.ts","./node_modules/next/dist/next-devtools/userspace/app/segment-explorer-node.d.ts","./node_modules/next/dist/server/app-render/entry-base.d.ts","./node_modules/next/dist/build/templates/app-page.d.ts","./node_modules/next/dist/build/rendering-mode.d.ts","./node_modules/@types/react/jsx-dev-runtime.d.ts","./node_modules/@types/react/compiler-runtime.d.ts","./node_modules/next/dist/server/route-modules/app-page/vendored/rsc/entrypoints.d.ts","./node_modules/@types/react-dom/client.d.ts","./node_modules/@types/react-dom/static.d.ts","./node_modules/@types/react-dom/server.d.ts","./node_modules/next/dist/server/route-modules/app-page/vendored/ssr/entrypoints.d.ts","./node_modules/next/dist/server/route-modules/app-page/module.d.ts","./node_modules/next/dist/server/route-modules/app-page/module.compiled.d.ts","./node_modules/next/dist/server/route-definitions/app-route-route-definition.d.ts","./node_modules/next/dist/server/async-storage/work-store.d.ts","./node_modules/next/dist/server/web/http.d.ts","./node_modules/next/dist/server/route-modules/app-route/shared-modules.d.ts","./node_modules/next/dist/client/components/redirect-status-code.d.ts","./node_modules/next/dist/client/components/redirect-error.d.ts","./node_modules/next/dist/build/templates/app-route.d.ts","./node_modules/next/dist/server/route-modules/app-route/module.d.ts","./node_modules/next/dist/server/route-modules/app-route/module.compiled.d.ts","./node_modules/next/dist/build/segment-config/app/app-segments.d.ts","./node_modules/next/dist/build/utils.d.ts","./node_modules/next/dist/server/lib/router-utils/build-prefetch-segment-data-route.d.ts","./node_modules/next/dist/build/turborepo-access-trace/types.d.ts","./node_modules/next/dist/build/turborepo-access-trace/result.d.ts","./node_modules/next/dist/build/turborepo-access-trace/helpers.d.ts","./node_modules/next/dist/build/turborepo-access-trace/index.d.ts","./node_modules/next/dist/export/routes/types.d.ts","./node_modules/next/dist/export/types.d.ts","./node_modules/next/dist/export/worker.d.ts","./node_modules/next/dist/build/worker.d.ts","./node_modules/next/dist/build/index.d.ts","./node_modules/next/dist/server/lib/incremental-cache/index.d.ts","./node_modules/next/dist/server/after/after.d.ts","./node_modules/next/dist/server/after/after-context.d.ts","./node_modules/next/dist/server/app-render/work-async-storage-instance.d.ts","./node_modules/next/dist/server/app-render/create-error-handler.d.ts","./node_modules/next/dist/shared/lib/action-revalidation-kind.d.ts","./node_modules/next/dist/server/app-render/work-async-storage.external.d.ts","./node_modules/next/dist/server/request/params.d.ts","./node_modules/next/dist/server/route-matches/route-match.d.ts","./node_modules/next/dist/server/request-meta.d.ts","./node_modules/next/dist/cli/next-test.d.ts","./node_modules/next/dist/shared/lib/size-limit.d.ts","./node_modules/next/dist/server/config-shared.d.ts","./node_modules/next/dist/server/base-http/index.d.ts","./node_modules/next/dist/server/api-utils/index.d.ts","./node_modules/next/dist/build/adapter/build-complete.d.ts","./node_modules/next/dist/types.d.ts","./node_modules/next/dist/shared/lib/html-context.shared-runtime.d.ts","./node_modules/next/dist/shared/lib/utils.d.ts","./node_modules/next/dist/pages/_app.d.ts","./node_modules/next/app.d.ts","./node_modules/next/dist/server/web/spec-extension/unstable-cache.d.ts","./node_modules/next/dist/server/web/spec-extension/revalidate.d.ts","./node_modules/next/dist/server/web/spec-extension/unstable-no-store.d.ts","./node_modules/next/dist/server/use-cache/cache-tag.d.ts","./node_modules/next/cache.d.ts","./node_modules/next/dist/pages/_document.d.ts","./node_modules/next/document.d.ts","./node_modules/next/dist/shared/lib/dynamic.d.ts","./node_modules/next/dynamic.d.ts","./node_modules/next/dist/pages/_error.d.ts","./node_modules/next/error.d.ts","./node_modules/next/dist/shared/lib/head.d.ts","./node_modules/next/head.d.ts","./node_modules/next/dist/server/request/cookies.d.ts","./node_modules/next/dist/server/request/headers.d.ts","./node_modules/next/dist/server/request/draft-mode.d.ts","./node_modules/next/headers.d.ts","./node_modules/next/dist/shared/lib/get-img-props.d.ts","./node_modules/next/dist/client/image-component.d.ts","./node_modules/next/dist/shared/lib/image-external.d.ts","./node_modules/next/image.d.ts","./node_modules/next/dist/client/link.d.ts","./node_modules/next/link.d.ts","./node_modules/next/dist/client/components/unrecognized-action-error.d.ts","./node_modules/next/dist/client/components/redirect.d.ts","./node_modules/next/dist/client/components/not-found.d.ts","./node_modules/next/dist/client/components/forbidden.d.ts","./node_modules/next/dist/client/components/unauthorized.d.ts","./node_modules/next/dist/client/components/unstable-rethrow.server.d.ts","./node_modules/next/dist/client/components/unstable-rethrow.d.ts","./node_modules/next/dist/client/components/navigation.react-server.d.ts","./node_modules/next/dist/client/components/navigation.d.ts","./node_modules/next/navigation.d.ts","./node_modules/next/router.d.ts","./node_modules/next/dist/client/script.d.ts","./node_modules/next/script.d.ts","./node_modules/next/dist/server/web/spec-extension/user-agent.d.ts","./node_modules/next/dist/compiled/@edge-runtime/primitives/url.d.ts","./node_modules/next/dist/server/web/spec-extension/image-response.d.ts","./node_modules/next/dist/compiled/@vercel/og/satori/index.d.ts","./node_modules/next/dist/compiled/@vercel/og/emoji/index.d.ts","./node_modules/next/dist/compiled/@vercel/og/types.d.ts","./node_modules/next/dist/server/after/index.d.ts","./node_modules/next/dist/server/request/connection.d.ts","./node_modules/next/server.d.ts","./node_modules/next/types/global.d.ts","./node_modules/next/types/compiled.d.ts","./node_modules/next/types.d.ts","./node_modules/next/index.d.ts","./node_modules/next/image-types/global.d.ts","./.next/types/routes.d.ts","./next-env.d.ts","./next.config.ts","./src/components/audit/constants.ts","./node_modules/clsx/clsx.d.mts","./node_modules/tailwind-merge/dist/types.d.ts","./src/lib/utils.ts","./src/components/audit/result-badge.tsx","./src/components/audit/latency-indicator.tsx","./src/components/audit/confidence-indicator.tsx","./src/lib/api/types.ts","./src/lib/format.ts","./src/components/audit/audit-row.tsx","./src/components/ui/input.tsx","./src/components/audit/audit-filters.tsx","./src/components/audit/audit-empty-state.tsx","./node_modules/class-variance-authority/dist/types.d.ts","./node_modules/class-variance-authority/dist/index.d.ts","./node_modules/@radix-ui/react-accessible-icon/dist/index.d.mts","./node_modules/@radix-ui/react-context/dist/index.d.mts","./node_modules/@radix-ui/react-primitive/dist/index.d.mts","./node_modules/@radix-ui/react-collapsible/dist/index.d.mts","./node_modules/@radix-ui/react-accordion/dist/index.d.mts","./node_modules/@radix-ui/react-dismissable-layer/dist/index.d.mts","./node_modules/@radix-ui/react-focus-scope/dist/index.d.mts","./node_modules/@radix-ui/react-portal/dist/index.d.mts","./node_modules/@radix-ui/react-dialog/dist/index.d.mts","./node_modules/@radix-ui/react-alert-dialog/dist/index.d.mts","./node_modules/@radix-ui/react-aspect-ratio/dist/index.d.mts","./node_modules/@radix-ui/react-avatar/dist/index.d.mts","./node_modules/@radix-ui/react-checkbox/dist/index.d.mts","./node_modules/@radix-ui/react-arrow/dist/index.d.mts","./node_modules/@radix-ui/rect/dist/index.d.mts","./node_modules/@radix-ui/react-popper/dist/index.d.mts","./node_modules/@radix-ui/react-roving-focus/dist/index.d.mts","./node_modules/@radix-ui/react-menu/dist/index.d.mts","./node_modules/@radix-ui/react-context-menu/dist/index.d.mts","./node_modules/@radix-ui/react-direction/dist/index.d.mts","./node_modules/@radix-ui/react-dropdown-menu/dist/index.d.mts","./node_modules/@radix-ui/react-label/dist/index.d.mts","./node_modules/@radix-ui/react-form/dist/index.d.mts","./node_modules/@radix-ui/react-hover-card/dist/index.d.mts","./node_modules/@radix-ui/react-menubar/dist/index.d.mts","./node_modules/@radix-ui/react-visually-hidden/dist/index.d.mts","./node_modules/@radix-ui/react-navigation-menu/dist/index.d.mts","./node_modules/@radix-ui/react-one-time-password-field/dist/index.d.mts","./node_modules/@radix-ui/react-password-toggle-field/dist/index.d.mts","./node_modules/@radix-ui/react-popover/dist/index.d.mts","./node_modules/@radix-ui/react-progress/dist/index.d.mts","./node_modules/@radix-ui/react-radio-group/dist/index.d.mts","./node_modules/@radix-ui/react-scroll-area/dist/index.d.mts","./node_modules/@radix-ui/react-select/dist/index.d.mts","./node_modules/@radix-ui/react-separator/dist/index.d.mts","./node_modules/@radix-ui/react-slider/dist/index.d.mts","./node_modules/@radix-ui/react-slot/dist/index.d.mts","./node_modules/@radix-ui/react-switch/dist/index.d.mts","./node_modules/@radix-ui/react-tabs/dist/index.d.mts","./node_modules/@radix-ui/react-toast/dist/index.d.mts","./node_modules/@radix-ui/react-toggle/dist/index.d.mts","./node_modules/@radix-ui/react-toggle-group/dist/index.d.mts","./node_modules/@radix-ui/react-toolbar/dist/index.d.mts","./node_modules/@radix-ui/react-tooltip/dist/index.d.mts","./node_modules/radix-ui/dist/index.d.mts","./src/components/ui/button.tsx","./src/components/audit/audit-export.tsx","./src/components/audit/audit-list.tsx","./src/components/audit/audit-loading-skeleton.tsx","./src/lib/api/client.ts","./src/lib/api/index.ts","./src/lib/types.ts","./src/lib/constants.ts","./src/components/shared/error-state.tsx","./src/components/audit/audit-panel.tsx","./src/components/audit/index.ts","./src/components/circuit/constants.ts","./src/components/circuit/state-badge.tsx","./src/components/circuit/circuit-card.tsx","./src/components/circuit/circuit-summary.tsx","./src/components/circuit/circuit-list.tsx","./src/components/circuit/circuit-loading-skeleton.tsx","./src/components/circuit/circuit-empty-state.tsx","./src/components/circuit/circuit-panel.tsx","./src/components/circuit/index.ts","./src/components/ui/badge.tsx","./src/components/feed/feed-row.tsx","./node_modules/lucide-react/dist/lucide-react.d.ts","./src/components/feed/feed-empty-state.tsx","./src/components/feed/feed-list.tsx","./src/components/feed/feed-loading-skeleton.tsx","./src/components/feed/feed-panel.tsx","./src/components/feed/index.ts","./src/components/skeptic/constants.ts","./src/components/skeptic/source-tier-badge.tsx","./src/components/skeptic/weight-bar.tsx","./src/components/skeptic/hash-display.tsx","./src/components/skeptic/conflict-gauge.tsx","./src/components/skeptic/status-badge.tsx","./src/components/skeptic/empty-state.tsx","./src/components/skeptic/loading-skeleton.tsx","./src/components/skeptic/error-state.tsx","./src/components/skeptic/trust-bar.tsx","./src/components/skeptic/claim-row.tsx","./src/components/skeptic/claims-table.tsx","./src/components/skeptic/weight-distribution.tsx","./src/components/ui/date-picker.tsx","./src/components/skeptic/query-form.tsx","./src/components/skeptic/query-results.tsx","./src/components/skeptic/index.ts","./src/components/layered/tier-accordion.tsx","./src/components/layered/cross-tier-summary.tsx","./src/components/layered/layered-loading-skeleton.tsx","./src/components/layered/layered-results-view.tsx","./src/components/layered/layered-query-results.tsx","./src/components/layered/index.ts","./src/components/quarantine/constants.ts","./src/components/quarantine/reason-badge.tsx","./src/components/quarantine/quarantine-row.tsx","./src/components/quarantine/quarantine-metrics.tsx","./src/components/quarantine/quarantine-filters.tsx","./src/components/quarantine/quarantine-empty-state.tsx","./src/components/quarantine/quarantine-list.tsx","./src/components/quarantine/quarantine-loading-skeleton.tsx","./src/components/shared/confirmation-dialog.tsx","./src/components/quarantine/quarantine-panel.tsx","./src/components/quarantine/blocked-sources-panel.tsx","./src/components/quarantine/index.ts","./src/components/sources/status-badge.tsx","./src/components/sources/tier-badge.tsx","./src/components/sources/impact-ripple.tsx","./src/components/sources/source-row.tsx","./src/components/sources/impact-preview.tsx","./src/components/sources/block-dialog.tsx","./src/components/sources/restore-dialog.tsx","./src/components/ui/sheet.tsx","./src/components/sources/impact-detail-panel.tsx","./src/components/sources/sources-loading-skeleton.tsx","./src/components/sources/sources-empty-state.tsx","./src/components/sources/sources-metrics.tsx","./src/components/sources/sources-filters.tsx","./src/components/sources/sources-panel.tsx","./src/components/sources/index.ts","./src/lib/auth/api-key.ts","./node_modules/next/dist/compiled/@next/font/dist/types.d.ts","./node_modules/next/dist/compiled/@next/font/dist/google/index.d.ts","./node_modules/next/font/google/index.d.ts","./src/components/layout/sidebar.tsx","./src/app/layout.tsx","./src/components/layout/theme-toggle.tsx","./src/components/shared/api-status.tsx","./src/components/layout/header.tsx","./src/app/page.tsx","./src/app/audit/page.tsx","./src/app/circuit/page.tsx","./src/app/layered/page.tsx","./src/components/ui/tabs.tsx","./src/app/quarantine/page.tsx","./src/app/skeptic/page.tsx","./src/app/sources/page.tsx","./src/components/ui/card.tsx","./src/components/ui/separator.tsx","./.next/types/validator.ts","./.next/dev/types/cache-life.d.ts","./.next/dev/types/routes.d.ts","./.next/dev/types/validator.ts","./node_modules/@types/estree/index.d.ts","./node_modules/@types/json-schema/index.d.ts","./node_modules/@types/json5/index.d.ts"],"fileIdsList":[[97,143,460,461,462,463],[97,143],[97,143,269,507,656,660,661,662,663,665,666,667,672],[97,143,269,507,510,656,660,661,662,663,665,666,667],[97,143,508,509,510],[97,143,269,508],[85,97,143],[85,97,143,529,530,531],[85,97,143,529,536],[85,97,143,530],[85,97,143,529,530],[85,97,143,269,529,530],[85,97,143,529,530,545],[85,97,143,529,530,533,534,535],[85,97,143,269,529,530,549],[85,97,143,529,530,533,535,543],[85,97,143,529,530,533,534,535,543,544],[85,97,143,269,529,530,544,545],[85,97,143,529,530,533,553],[85,97,143,530,544],[85,97,143,529,530,533,534,535,543],[85,97,143,529,530,541,542],[85,97,143,529,530,544],[85,97,143,529,530,533],[85,97,143,529,530,544,568],[85,97,143,529,530,544,562,569],[97,140,143],[97,142,143],[143],[97,143,148,176],[97,143,144,149,154,162,173,184],[97,143,144,145,154,162],[92,93,94,97,143],[97,143,146,185],[97,143,147,148,155,163],[97,143,148,173,181],[97,143,149,151,154,162],[97,142,143,150],[97,143,151,152],[97,143,153,154],[97,142,143,154],[97,143,154,155,156,173,184],[97,143,154,155,156,169,173,176],[97,143,151,154,157,162,173,184],[97,143,154,155,157,158,162,173,181,184],[97,143,157,159,173,181,184],[95,96,97,98,99,100,101,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,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],[97,143,154,160],[97,143,161,184,189],[97,143,151,154,162,173],[97,143,163],[97,143,164],[97,142,143,165],[97,140,141,142,143,144,145,146,147,148,149,150,151,152,153,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],[97,143,167],[97,143,168],[97,143,154,169,170],[97,143,169,171,185,187],[97,143,154,173,174,176],[97,143,175,176],[97,143,173,174],[97,143,176],[97,143,177],[97,140,143,173,178],[97,143,154,179,180],[97,143,179,180],[97,143,148,162,173,181],[97,143,182],[97,143,162,183],[97,143,157,168,184],[97,143,148,185],[97,143,173,186],[97,143,161,187],[97,143,188],[97,138,143],[97,138,143,154,156,165,173,176,184,187,189],[97,143,173,190],[85,89,97,143,192,193,194,196,455,501],[85,89,97,143,192,193,194,195,412,455,501],[85,89,97,143,192,193,195,196,455,501],[85,97,143,196,412,413],[85,97,143,196,412],[85,89,97,143,193,194,195,196,455,501],[85,89,97,143,192,194,195,196,455,501],[83,84,97,143],[97,143,514,526],[97,143,514],[97,143,458],[97,143,201,203,207,218,408,438,451],[97,143,203,213,214,215,217,451],[97,143,203,250,252,254,255,258,451,453],[97,143,203,207,209,210,211,241,336,408,428,429,437,451,453],[97,143,451],[97,143,214,306,417,426,446],[97,143,203],[97,143,197,306,446],[97,143,260],[97,143,259,451],[97,143,157,406,417,506],[97,143,157,374,386,426,445],[97,143,157,317],[97,143,431],[97,143,430,431,432],[97,143,430],[91,97,143,157,197,203,207,210,212,214,218,219,232,233,260,336,347,427,438,451,455],[97,143,201,203,216,250,251,256,257,451,506],[97,143,216,506],[97,143,201,233,361,451,506],[97,143,506],[97,143,203,216,217,506],[97,143,253,506],[97,143,219,428,436],[97,143,168,269,446],[97,143,269,446],[85,97,143,269],[85,97,143,378],[97,143,304,314,315,446,483,490],[97,143,303,423,484,485,486,487,489],[97,143,422],[97,143,422,423],[97,143,241,306,307,311],[97,143,306],[97,143,306,310,312],[97,143,306,307,308,309],[97,143,488],[85,97,143,204,477],[85,97,143,184],[85,97,143,216,296],[85,97,143,216,438],[97,143,294,298],[85,97,143,295,457],[97,143,652],[85,89,97,143,157,191,192,193,194,195,196,455,499,500],[97,143,157],[97,143,157,207,240,292,337,358,360,433,434,438,451,452],[97,143,232,435],[97,143,455],[97,143,202],[85,97,143,363,376,385,395,397,445],[97,143,168,363,376,394,395,396,445,505],[97,143,388,389,390,391,392,393],[97,143,390],[97,143,394],[97,143,267,268,269,271],[85,97,143,261,262,263,264,270],[97,143,267,270],[97,143,265],[97,143,266],[85,97,143,269,295,457],[85,97,143,269,456,457],[85,97,143,269,457],[97,143,337,440],[97,143,440],[97,143,157,452,457],[97,143,382],[97,142,143,381],[97,143,242,306,323,360,369,372,374,375,416,445,448,452],[97,143,288,306,403],[97,143,374,445],[85,97,143,374,379,380,382,383,384,385,386,387,398,399,400,401,402,404,405,445,446,506],[97,143,368],[97,143,157,168,204,240,243,264,289,290,337,347,358,359,416,439,451,452,453,455,506],[97,143,445],[97,142,143,214,290,347,371,439,441,442,443,444,452],[97,143,374],[97,142,143,240,277,323,364,365,366,367,368,369,370,372,373,445,446],[97,143,157,277,278,364,452,453],[97,143,214,337,347,360,439,445,452],[97,143,157,451,453],[97,143,157,173,448,452,453],[97,143,157,168,184,197,207,216,242,243,245,274,279,284,288,289,290,292,321,323,325,328,330,333,334,335,336,358,360,438,439,446,448,451,452,453],[97,143,157,173],[97,143,203,204,205,212,448,449,450,455,457,506],[97,143,201,451],[97,143,273],[97,143,157,173,184,235,258,260,261,262,263,264,271,272,506],[97,143,168,184,197,235,250,283,284,285,321,322,323,328,336,337,343,346,348,358,360,439,446,448,451],[97,143,212,219,232,336,347,439,451],[97,143,157,184,204,207,323,341,448,451],[97,143,362],[97,143,157,273,344,345,355],[97,143,448,451],[97,143,369,371],[97,143,290,323,438,457],[97,143,157,168,246,250,322,328,343,346,350,448],[97,143,157,219,232,250,351],[97,143,203,245,353,438,451],[97,143,157,184,264,451],[97,143,157,216,244,245,246,255,273,352,354,438,451],[91,97,143,157,290,357,455,457],[97,143,320,358],[97,143,157,168,184,207,218,219,232,242,243,279,283,284,285,289,321,322,323,325,337,338,340,342,358,360,438,439,446,447,448,457],[97,143,157,173,219,343,349,355,448],[97,143,222,223,224,225,226,227,228,229,230,231],[97,143,274,329],[97,143,331],[97,143,329],[97,143,331,332],[97,143,157,207,210,240,241,452],[97,143,157,168,202,204,242,288,289,290,291,319,358,448,453,455,457],[97,143,157,168,184,206,241,291,323,369,439,447,452],[97,143,364],[97,143,365],[97,143,306,336,416],[97,143,366],[97,143,234,238],[97,143,157,207,234,242],[97,143,237,238],[97,143,239],[97,143,234,235],[97,143,234,286],[97,143,234],[97,143,274,327,447],[97,143,326],[97,143,235,446,447],[97,143,324,447],[97,143,235,446],[97,143,416],[97,143,207,236,242,290,306,323,357,360,363,369,376,377,407,408,411,415,438,448,452],[97,143,299,302,304,305,314,315],[85,97,143,194,196,269,409,410],[85,97,143,194,196,269,409,410,414],[97,143,425],[97,143,214,278,290,357,360,374,382,386,418,419,420,421,423,424,427,438,445,451],[97,143,314],[97,143,157,319],[97,143,319],[97,143,157,242,287,292,316,318,357,448,455,457],[97,143,299,300,301,302,304,305,314,315,456],[91,97,143,157,168,184,234,235,243,289,290,323,355,356,358,438,439,448,451,452,455],[97,143,278,280,283,439],[97,143,157,274,451],[97,143,277,374],[97,143,276],[97,143,278,279],[97,143,275,277,451],[97,143,157,206,278,280,281,282,451,452],[85,97,143,306,313,446],[97,143,199,200],[85,97,143,204],[85,97,143,303,446],[85,91,97,143,289,290,455,457],[97,143,204,477,478],[85,97,143,298],[85,97,143,168,184,202,257,293,295,297,457],[97,143,216,446,452],[97,143,339,446],[85,97,143,155,157,168,201,202,252,298,455,456],[85,97,143,192,193,194,195,196,455,501],[85,86,87,88,89,97,143],[97,143,148],[97,143,247,248,249],[97,143,247],[85,89,97,143,157,159,168,191,192,193,194,195,196,197,202,243,350,394,453,454,457,501],[97,143,465],[97,143,467],[97,143,469],[97,143,653],[97,143,471],[97,143,473,474,475],[97,143,479],[90,97,143,459,464,466,468,470,472,476,480,482,492,493,495,504,505,506,507],[97,143,481],[97,143,491],[97,143,295],[97,143,494],[97,142,143,278,280,281,283,496,497,498,501,502,503],[97,143,191],[97,143,528,531,532,535,536,537,538,539,540,546,547,548,549,550,551,552,553,554,555,556,557,558,559,560,561,562,563,564,565,566,567,568,569,570,571],[97,143,173,191],[97,110,114,143,184],[97,110,143,173,184],[97,105,143],[97,107,110,143,181,184],[97,143,162,181],[97,105,143,191],[97,107,110,143,162,184],[97,102,103,106,109,143,154,173,184],[97,110,117,143],[97,102,108,143],[97,110,131,132,143],[97,106,110,143,176,184,191],[97,131,143,191],[97,104,105,143,191],[97,110,143],[97,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,132,133,134,135,136,137,143],[97,110,125,143],[97,110,117,118,143],[97,108,110,118,119,143],[97,109,143],[97,102,105,110,143],[97,110,114,118,119,143],[97,114,143],[97,108,110,113,143,184],[97,102,107,110,117,143],[97,143,173],[97,105,110,131,143,189,191],[85,97,143,269,492,583,659],[97,143,269,592,659],[97,143,269,623,659],[97,143,269,508,654,655],[85,97,143,269,600,659],[97,143,269,634,635,659,664],[85,97,143,269,492,617,659],[97,143,269,650,659],[97,143,269],[85,97,143,269,520,573],[97,143,269,513,523],[85,97,143,269,520,522,524,525,573,574],[97,143,269,516],[85,97,143,269,524,525,575,576,578,579,580,581],[85,97,143,269,482,517,519,520,521],[97,143,269,513,517,518,519,522,524,525,574,575,576,582],[97,143,269,513,516],[97,143,269,520,521,573,584,585],[85,97,143,269,520,586],[85,97,143,269,578,579,580,581,587,588,589,590],[97,143,269,516,520],[97,143,269,584,585,586,587,588,589,590,591],[97,143,269,516,584],[97,143,269,595],[97,143,269,520,573,594,596],[85,97,143,269,578,579,580,581,597,598],[85,97,143,269,482,516,520,521,593],[97,143,269,599],[97,143,269,617],[97,143,269,618,619,620,621,622],[85,97,143,269,578,617,620,621],[85,97,143,269,492,520,573,618,619],[85,97,143,269,482,516,520,578,617],[97,143,269,657,658],[85,97,143,269,482,492,516,595],[85,97,143,269,516,595],[85,97,143,269,573,578,579,580,581,595,632],[97,143,269,624,625,626,627,628,629,630,631,633,634],[97,143,269,624],[85,97,143,269,520,626,628,629],[85,97,143,269,578,579,580,581,627,629,630,631,632],[85,97,143,269,520,521,573,604,625],[97,143,269,516,624],[85,97,143,269,516],[85,97,143,269,573],[97,143,269,573],[85,97,143,269,482,516,520,578,601,602,603,604,610],[85,97,143,269,520,611],[97,143,269,516,601],[97,143,269,573,595],[97,143,269,601,602,603,604,605,606,607,608,609,610,611,612,613,615,616],[85,97,143,269,523,573,578,614],[85,97,143,269,492,573,578,601,605,606,607,608,609,612,613,615],[97,143,269,516,520,601],[85,97,143,269,520,573,595,640],[85,97,143,269,520,573,578,595,640,643],[97,143,269,520,595,638],[97,143,269,636,637,638,639,640,641,642,644,645,646,647,648,649],[85,97,143,269,573,595],[97,143,269,482,520,573,595,636,637],[97,143,269,520],[85,97,143,269,578,579,580,581,639,641,642,644,645,646,647,648],[97,143,269,516,580],[85,97,143,269,516,527,572],[85,97,143,269,516,572],[85,97,143,269,516,572,595],[97,143,269,520,577],[97,143,269,514,515]],"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":"feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569","impliedFormat":1},{"version":"ee7bad0c15b58988daa84371e0b89d313b762ab83cb5b31b8a2d1162e8eb41c2","impliedFormat":1},{"version":"27bdc30a0e32783366a5abeda841bc22757c1797de8681bbe81fbc735eeb1c10","impliedFormat":1},{"version":"8fd575e12870e9944c7e1d62e1f5a73fcf23dd8d3a321f2a2c74c20d022283fe","impliedFormat":1},{"version":"2ab096661c711e4a81cc464fa1e6feb929a54f5340b46b0a07ac6bbf857471f0","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":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true,"impliedFormat":1},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true,"impliedFormat":1},{"version":"959d36cddf5e7d572a65045b876f2956c973a586da58e5d26cde519184fd9b8a","affectsGlobalScope":true,"impliedFormat":1},{"version":"965f36eae237dd74e6cca203a43e9ca801ce38824ead814728a2807b1910117d","affectsGlobalScope":true,"impliedFormat":1},{"version":"3925a6c820dcb1a06506c90b1577db1fdbf7705d65b62b99dce4be75c637e26b","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a3d63ef2b853447ec4f749d3f368ce642264246e02911fcb1590d8c161b8005","affectsGlobalScope":true,"impliedFormat":1},{"version":"8cdf8847677ac7d20486e54dd3fcf09eda95812ac8ace44b4418da1bbbab6eb8","affectsGlobalScope":true,"impliedFormat":1},{"version":"8444af78980e3b20b49324f4a16ba35024fef3ee069a0eb67616ea6ca821c47a","affectsGlobalScope":true,"impliedFormat":1},{"version":"3287d9d085fbd618c3971944b65b4be57859f5415f495b33a6adc994edd2f004","affectsGlobalScope":true,"impliedFormat":1},{"version":"b4b67b1a91182421f5df999988c690f14d813b9850b40acd06ed44691f6727ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"df83c2a6c73228b625b0beb6669c7ee2a09c914637e2d35170723ad49c0f5cd4","affectsGlobalScope":true,"impliedFormat":1},{"version":"436aaf437562f276ec2ddbee2f2cdedac7664c1e4c1d2c36839ddd582eeb3d0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e3c06ea092138bf9fa5e874a1fdbc9d54805d074bee1de31b99a11e2fec239d","affectsGlobalScope":true,"impliedFormat":1},{"version":"87dc0f382502f5bbce5129bdc0aea21e19a3abbc19259e0b43ae038a9fc4e326","affectsGlobalScope":true,"impliedFormat":1},{"version":"b1cb28af0c891c8c96b2d6b7be76bd394fddcfdb4709a20ba05a7c1605eea0f9","affectsGlobalScope":true,"impliedFormat":1},{"version":"2fef54945a13095fdb9b84f705f2b5994597640c46afeb2ce78352fab4cb3279","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac77cb3e8c6d3565793eb90a8373ee8033146315a3dbead3bde8db5eaf5e5ec6","affectsGlobalScope":true,"impliedFormat":1},{"version":"56e4ed5aab5f5920980066a9409bfaf53e6d21d3f8d020c17e4de584d29600ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ece9f17b3866cc077099c73f4983bddbcb1dc7ddb943227f1ec070f529dedd1","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a6282c8827e4b9a95f4bf4f5c205673ada31b982f50572d27103df8ceb8013c","affectsGlobalScope":true,"impliedFormat":1},{"version":"1c9319a09485199c1f7b0498f2988d6d2249793ef67edda49d1e584746be9032","affectsGlobalScope":true,"impliedFormat":1},{"version":"e3a2a0cee0f03ffdde24d89660eba2685bfbdeae955a6c67e8c4c9fd28928eeb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811c71eee4aa0ac5f7adf713323a5c41b0cf6c4e17367a34fbce379e12bbf0a4","affectsGlobalScope":true,"impliedFormat":1},{"version":"51ad4c928303041605b4d7ae32e0c1ee387d43a24cd6f1ebf4a2699e1076d4fa","affectsGlobalScope":true,"impliedFormat":1},{"version":"60037901da1a425516449b9a20073aa03386cce92f7a1fd902d7602be3a7c2e9","affectsGlobalScope":true,"impliedFormat":1},{"version":"d4b1d2c51d058fc21ec2629fff7a76249dec2e36e12960ea056e3ef89174080f","affectsGlobalScope":true,"impliedFormat":1},{"version":"22adec94ef7047a6c9d1af3cb96be87a335908bf9ef386ae9fd50eeb37f44c47","affectsGlobalScope":true,"impliedFormat":1},{"version":"196cb558a13d4533a5163286f30b0509ce0210e4b316c56c38d4c0fd2fb38405","affectsGlobalScope":true,"impliedFormat":1},{"version":"73f78680d4c08509933daf80947902f6ff41b6230f94dd002ae372620adb0f60","affectsGlobalScope":true,"impliedFormat":1},{"version":"c5239f5c01bcfa9cd32f37c496cf19c61d69d37e48be9de612b541aac915805b","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"7e29f41b158de217f94cb9676bf9cbd0cd9b5a46e1985141ed36e075c52bf6ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac51dd7d31333793807a6abaa5ae168512b6131bd41d9c5b98477fc3b7800f9f","impliedFormat":1},{"version":"f123246a7b6c04d80b9b57fadfc6c90959ec6d5c0d4c8e620e06e2811ae3a052","impliedFormat":1},{"version":"acd8fd5090ac73902278889c38336ff3f48af6ba03aa665eb34a75e7ba1dccc4","impliedFormat":1},{"version":"d6258883868fb2680d2ca96bc8b1352cab69874581493e6d52680c5ffecdb6cc","impliedFormat":1},{"version":"1b61d259de5350f8b1e5db06290d31eaebebc6baafd5f79d314b5af9256d7153","impliedFormat":1},{"version":"f258e3960f324a956fc76a3d3d9e964fff2244ff5859dcc6ce5951e5413ca826","impliedFormat":1},{"version":"643f7232d07bf75e15bd8f658f664d6183a0efaca5eb84b48201c7671a266979","impliedFormat":1},{"version":"21da358700a3893281ce0c517a7a30cbd46be020d9f0c3f2834d0a8ad1f5fc75","impliedFormat":1},{"version":"70521b6ab0dcba37539e5303104f29b721bfb2940b2776da4cc818c07e1fefc1","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab41ef1f2cdafb8df48be20cd969d875602483859dc194e9c97c8a576892c052","affectsGlobalScope":true,"impliedFormat":1},{"version":"d153a11543fd884b596587ccd97aebbeed950b26933ee000f94009f1ab142848","affectsGlobalScope":true,"impliedFormat":1},{"version":"21d819c173c0cf7cc3ce57c3276e77fd9a8a01d35a06ad87158781515c9a438a","impliedFormat":1},{"version":"98cffbf06d6bab333473c70a893770dbe990783904002c4f1a960447b4b53dca","affectsGlobalScope":true,"impliedFormat":1},{"version":"ba481bca06f37d3f2c137ce343c7d5937029b2468f8e26111f3c9d9963d6568d","affectsGlobalScope":true,"impliedFormat":1},{"version":"6d9ef24f9a22a88e3e9b3b3d8c40ab1ddb0853f1bfbd5c843c37800138437b61","affectsGlobalScope":true,"impliedFormat":1},{"version":"1db0b7dca579049ca4193d034d835f6bfe73096c73663e5ef9a0b5779939f3d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"9798340ffb0d067d69b1ae5b32faa17ab31b82466a3fc00d8f2f2df0c8554aaa","affectsGlobalScope":true,"impliedFormat":1},{"version":"f26b11d8d8e4b8028f1c7d618b22274c892e4b0ef5b3678a8ccbad85419aef43","affectsGlobalScope":true,"impliedFormat":1},{"version":"5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","impliedFormat":1},{"version":"763fe0f42b3d79b440a9b6e51e9ba3f3f91352469c1e4b3b67bfa4ff6352f3f4","impliedFormat":1},{"version":"25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","impliedFormat":1},{"version":"c464d66b20788266e5353b48dc4aa6bc0dc4a707276df1e7152ab0c9ae21fad8","impliedFormat":1},{"version":"78d0d27c130d35c60b5e5566c9f1e5be77caf39804636bc1a40133919a949f21","impliedFormat":1},{"version":"c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","impliedFormat":1},{"version":"1d6e127068ea8e104a912e42fc0a110e2aa5a66a356a917a163e8cf9a65e4a75","impliedFormat":1},{"version":"5ded6427296cdf3b9542de4471d2aa8d3983671d4cac0f4bf9c637208d1ced43","impliedFormat":1},{"version":"7f182617db458e98fc18dfb272d40aa2fff3a353c44a89b2c0ccb3937709bfb5","impliedFormat":1},{"version":"cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","impliedFormat":1},{"version":"385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","impliedFormat":1},{"version":"9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","impliedFormat":1},{"version":"0b8a9268adaf4da35e7fa830c8981cfa22adbbe5b3f6f5ab91f6658899e657a7","impliedFormat":1},{"version":"11396ed8a44c02ab9798b7dca436009f866e8dae3c9c25e8c1fbc396880bf1bb","impliedFormat":1},{"version":"ba7bc87d01492633cb5a0e5da8a4a42a1c86270e7b3d2dea5d156828a84e4882","impliedFormat":1},{"version":"4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","impliedFormat":1},{"version":"c21dc52e277bcfc75fac0436ccb75c204f9e1b3fa5e12729670910639f27343e","impliedFormat":1},{"version":"13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","impliedFormat":1},{"version":"9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","impliedFormat":1},{"version":"4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","impliedFormat":1},{"version":"24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","impliedFormat":1},{"version":"ea0148f897b45a76544ae179784c95af1bd6721b8610af9ffa467a518a086a43","impliedFormat":1},{"version":"24c6a117721e606c9984335f71711877293a9651e44f59f3d21c1ea0856f9cc9","impliedFormat":1},{"version":"dd3273ead9fbde62a72949c97dbec2247ea08e0c6952e701a483d74ef92d6a17","impliedFormat":1},{"version":"405822be75ad3e4d162e07439bac80c6bcc6dbae1929e179cf467ec0b9ee4e2e","impliedFormat":1},{"version":"0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","impliedFormat":1},{"version":"e61be3f894b41b7baa1fbd6a66893f2579bfad01d208b4ff61daef21493ef0a8","impliedFormat":1},{"version":"bd0532fd6556073727d28da0edfd1736417a3f9f394877b6d5ef6ad88fba1d1a","impliedFormat":1},{"version":"89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","impliedFormat":1},{"version":"615ba88d0128ed16bf83ef8ccbb6aff05c3ee2db1cc0f89ab50a4939bfc1943f","impliedFormat":1},{"version":"a4d551dbf8746780194d550c88f26cf937caf8d56f102969a110cfaed4b06656","impliedFormat":1},{"version":"8bd86b8e8f6a6aa6c49b71e14c4ffe1211a0e97c80f08d2c8cc98838006e4b88","impliedFormat":1},{"version":"317e63deeb21ac07f3992f5b50cdca8338f10acd4fbb7257ebf56735bf52ab00","impliedFormat":1},{"version":"4732aec92b20fb28c5fe9ad99521fb59974289ed1e45aecb282616202184064f","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"bf67d53d168abc1298888693338cb82854bdb2e69ef83f8a0092093c2d562107","impliedFormat":1},{"version":"b52476feb4a0cbcb25e5931b930fc73cb6643fb1a5060bf8a3dda0eeae5b4b68","affectsGlobalScope":true,"impliedFormat":1},{"version":"e2677634fe27e87348825bb041651e22d50a613e2fdf6a4a3ade971d71bac37e","impliedFormat":1},{"version":"7394959e5a741b185456e1ef5d64599c36c60a323207450991e7a42e08911419","impliedFormat":1},{"version":"8c0bcd6c6b67b4b503c11e91a1fb91522ed585900eab2ab1f61bba7d7caa9d6f","impliedFormat":1},{"version":"8cd19276b6590b3ebbeeb030ac271871b9ed0afc3074ac88a94ed2449174b776","affectsGlobalScope":true,"impliedFormat":1},{"version":"696eb8d28f5949b87d894b26dc97318ef944c794a9a4e4f62360cd1d1958014b","impliedFormat":1},{"version":"3f8fa3061bd7402970b399300880d55257953ee6d3cd408722cb9ac20126460c","impliedFormat":1},{"version":"35ec8b6760fd7138bbf5809b84551e31028fb2ba7b6dc91d95d098bf212ca8b4","affectsGlobalScope":true,"impliedFormat":1},{"version":"5524481e56c48ff486f42926778c0a3cce1cc85dc46683b92b1271865bcf015a","impliedFormat":1},{"version":"68bd56c92c2bd7d2339457eb84d63e7de3bd56a69b25f3576e1568d21a162398","affectsGlobalScope":true,"impliedFormat":1},{"version":"3e93b123f7c2944969d291b35fed2af79a6e9e27fdd5faa99748a51c07c02d28","impliedFormat":1},{"version":"9d19808c8c291a9010a6c788e8532a2da70f811adb431c97520803e0ec649991","impliedFormat":1},{"version":"87aad3dd9752067dc875cfaa466fc44246451c0c560b820796bdd528e29bef40","impliedFormat":1},{"version":"4aacb0dd020eeaef65426153686cc639a78ec2885dc72ad220be1d25f1a439df","impliedFormat":1},{"version":"f0bd7e6d931657b59605c44112eaf8b980ba7f957a5051ed21cb93d978cf2f45","impliedFormat":1},{"version":"8db0ae9cb14d9955b14c214f34dae1b9ef2baee2fe4ce794a4cd3ac2531e3255","affectsGlobalScope":true,"impliedFormat":1},{"version":"15fc6f7512c86810273af28f224251a5a879e4261b4d4c7e532abfbfc3983134","impliedFormat":1},{"version":"58adba1a8ab2d10b54dc1dced4e41f4e7c9772cbbac40939c0dc8ce2cdb1d442","impliedFormat":1},{"version":"2fd4c143eff88dabb57701e6a40e02a4dbc36d5eb1362e7964d32028056a782b","impliedFormat":1},{"version":"714435130b9015fae551788df2a88038471a5a11eb471f27c4ede86552842bc9","impliedFormat":1},{"version":"855cd5f7eb396f5f1ab1bc0f8580339bff77b68a770f84c6b254e319bbfd1ac7","impliedFormat":1},{"version":"5650cf3dace09e7c25d384e3e6b818b938f68f4e8de96f52d9c5a1b3db068e86","impliedFormat":1},{"version":"1354ca5c38bd3fd3836a68e0f7c9f91f172582ba30ab15bb8c075891b91502b7","affectsGlobalScope":true,"impliedFormat":1},{"version":"27fdb0da0daf3b337c5530c5f266efe046a6ceb606e395b346974e4360c36419","impliedFormat":1},{"version":"2d2fcaab481b31a5882065c7951255703ddbe1c0e507af56ea42d79ac3911201","impliedFormat":1},{"version":"a192fe8ec33f75edbc8d8f3ed79f768dfae11ff5735e7fe52bfa69956e46d78d","impliedFormat":1},{"version":"ca867399f7db82df981d6915bcbb2d81131d7d1ef683bc782b59f71dda59bc85","affectsGlobalScope":true,"impliedFormat":1},{"version":"0e456fd5b101271183d99a9087875a282323e3a3ff0d7bcf1881537eaa8b8e63","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e043a1bc8fbf2a255bccf9bf27e0f1caf916c3b0518ea34aa72357c0afd42ec","impliedFormat":1},{"version":"b4f70ec656a11d570e1a9edce07d118cd58d9760239e2ece99306ee9dfe61d02","impliedFormat":1},{"version":"3bc2f1e2c95c04048212c569ed38e338873f6a8593930cf5a7ef24ffb38fc3b6","impliedFormat":1},{"version":"6e70e9570e98aae2b825b533aa6292b6abd542e8d9f6e9475e88e1d7ba17c866","impliedFormat":1},{"version":"f9d9d753d430ed050dc1bf2667a1bab711ccbb1c1507183d794cc195a5b085cc","impliedFormat":1},{"version":"9eece5e586312581ccd106d4853e861aaaa1a39f8e3ea672b8c3847eedd12f6e","impliedFormat":1},{"version":"47ab634529c5955b6ad793474ae188fce3e6163e3a3fb5edd7e0e48f14435333","impliedFormat":1},{"version":"37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","impliedFormat":1},{"version":"45650f47bfb376c8a8ed39d4bcda5902ab899a3150029684ee4c10676d9fbaee","impliedFormat":1},{"version":"fad4e3c207fe23922d0b2d06b01acbfb9714c4f2685cf80fd384c8a100c82fd0","affectsGlobalScope":true,"impliedFormat":1},{"version":"74cf591a0f63db318651e0e04cb55f8791385f86e987a67fd4d2eaab8191f730","impliedFormat":1},{"version":"5eab9b3dc9b34f185417342436ec3f106898da5f4801992d8ff38ab3aff346b5","impliedFormat":1},{"version":"12ed4559eba17cd977aa0db658d25c4047067444b51acfdcbf38470630642b23","affectsGlobalScope":true,"impliedFormat":1},{"version":"f3ffabc95802521e1e4bcba4c88d8615176dc6e09111d920c7a213bdda6e1d65","impliedFormat":1},{"version":"ddc734b4fae82a01d247e9e342d020976640b5e93b4e9b3a1e30e5518883a060","impliedFormat":1},{"version":"ae56f65caf3be91108707bd8dfbccc2a57a91feb5daabf7165a06a945545ed26","impliedFormat":1},{"version":"a136d5de521da20f31631a0a96bf712370779d1c05b7015d7019a9b2a0446ca9","impliedFormat":1},{"version":"c3b41e74b9a84b88b1dca61ec39eee25c0dbc8e7d519ba11bb070918cfacf656","affectsGlobalScope":true,"impliedFormat":1},{"version":"4737a9dc24d0e68b734e6cfbcea0c15a2cfafeb493485e27905f7856988c6b29","affectsGlobalScope":true,"impliedFormat":1},{"version":"36d8d3e7506b631c9582c251a2c0b8a28855af3f76719b12b534c6edf952748d","impliedFormat":1},{"version":"1ca69210cc42729e7ca97d3a9ad48f2e9cb0042bada4075b588ae5387debd318","impliedFormat":1},{"version":"f5ebe66baaf7c552cfa59d75f2bfba679f329204847db3cec385acda245e574e","impliedFormat":1},{"version":"ed59add13139f84da271cafd32e2171876b0a0af2f798d0c663e8eeb867732cf","affectsGlobalScope":true,"impliedFormat":1},{"version":"05db535df8bdc30d9116fe754a3473d1b6479afbc14ae8eb18b605c62677d518","impliedFormat":1},{"version":"b1810689b76fd473bd12cc9ee219f8e62f54a7d08019a235d07424afbf074d25","impliedFormat":1},{"version":"2beff543f6e9a9701df88daeee3cdd70a34b4a1c11cb4c734472195a5cb2af54","impliedFormat":1},{"version":"bfffea552cca245df227337223c7554b35df629ba1d4e09edee4521ce7f24827","impliedFormat":1},{"version":"be1cc4d94ea60cbe567bc29ed479d42587bf1e6cba490f123d329976b0fe4ee5","impliedFormat":1},{"version":"42bc0e1a903408137c3df2b06dfd7e402cdab5bbfa5fcfb871b22ebfdb30bd0b","impliedFormat":1},{"version":"9894dafe342b976d251aac58e616ac6df8db91fb9d98934ff9dd103e9e82578f","impliedFormat":1},{"version":"413df52d4ea14472c2fa5bee62f7a40abd1eb49be0b9722ee01ee4e52e63beb2","impliedFormat":1},{"version":"db6d2d9daad8a6d83f281af12ce4355a20b9a3e71b82b9f57cddcca0a8964a96","impliedFormat":1},{"version":"446a50749b24d14deac6f8843e057a6355dd6437d1fac4f9e5ce4a5071f34bff","impliedFormat":1},{"version":"182e9fcbe08ac7c012e0a6e2b5798b4352470be29a64fdc114d23c2bab7d5106","impliedFormat":1},{"version":"5c9b31919ea1cb350a7ae5e71c9ced8f11723e4fa258a8cc8d16ae46edd623c7","impliedFormat":1},{"version":"4aa42ce8383b45823b3a1d3811c0fdd5f939f90254bc4874124393febbaf89f6","impliedFormat":1},{"version":"96ffa70b486207241c0fcedb5d9553684f7fa6746bc2b04c519e7ebf41a51205","impliedFormat":1},{"version":"3677988e03b749874eb9c1aa8dc88cd77b6005e5c4c39d821cda7b80d5388619","impliedFormat":1},{"version":"a86f82d646a739041d6702101afa82dcb935c416dd93cbca7fd754fd0282ce1f","impliedFormat":1},{"version":"ad0d1d75d129b1c80f911be438d6b61bfa8703930a8ff2be2f0e1f8a91841c64","impliedFormat":1},{"version":"ce75b1aebb33d510ff28af960a9221410a3eaf7f18fc5f21f9404075fba77256","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"02436d7e9ead85e09a2f8e27d5f47d9464bced31738dec138ca735390815c9f0","impliedFormat":1},{"version":"f4625edcb57b37b84506e8b276eb59ca30d31f88c6656d29d4e90e3bc58e69df","impliedFormat":1},{"version":"78a2869ad0cbf3f9045dda08c0d4562b7e1b2bfe07b19e0db072f5c3c56e9584","impliedFormat":1},{"version":"f8d5ff8eafd37499f2b6a98659dd9b45a321de186b8db6b6142faed0fea3de77","impliedFormat":1},{"version":"c86fe861cf1b4c46a0fb7d74dffe596cf679a2e5e8b1456881313170f092e3fa","impliedFormat":1},{"version":"c685d9f68c70fe11ce527287526585a06ea13920bb6c18482ca84945a4e433a7","impliedFormat":1},{"version":"540cc83ab772a2c6bc509fe1354f314825b5dba3669efdfbe4693ecd3048e34f","impliedFormat":1},{"version":"121b0696021ab885c570bbeb331be8ad82c6efe2f3b93a6e63874901bebc13e3","impliedFormat":1},{"version":"4e01846df98d478a2a626ec3641524964b38acaac13945c2db198bf9f3df22ee","impliedFormat":1},{"version":"678d6d4c43e5728bf66e92fc2269da9fa709cb60510fed988a27161473c3853f","impliedFormat":1},{"version":"ffa495b17a5ef1d0399586b590bd281056cee6ce3583e34f39926f8dcc6ecdb5","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","impliedFormat":1},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":1},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":1},{"version":"aa14cee20aa0db79f8df101fc027d929aec10feb5b8a8da3b9af3895d05b7ba2","impliedFormat":1},{"version":"493c700ac3bd317177b2eb913805c87fe60d4e8af4fb39c41f04ba81fae7e170","impliedFormat":1},{"version":"aeb554d876c6b8c818da2e118d8b11e1e559adbe6bf606cc9a611c1b6c09f670","impliedFormat":1},{"version":"acf5a2ac47b59ca07afa9abbd2b31d001bf7448b041927befae2ea5b1951d9f9","impliedFormat":1},{"version":"8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881","impliedFormat":1},{"version":"d71291eff1e19d8762a908ba947e891af44749f3a2cbc5bd2ec4b72f72ea795f","impliedFormat":1},{"version":"c0480e03db4b816dff2682b347c95f2177699525c54e7e6f6aa8ded890b76be7","impliedFormat":1},{"version":"e2a37ac938c4bede5bb284b9d2d042da299528f1e61f6f57538f1bd37d760869","impliedFormat":1},{"version":"76def37aff8e3a051cf406e10340ffba0f28b6991c5d987474cc11137796e1eb","impliedFormat":1},{"version":"b620391fe8060cf9bedc176a4d01366e6574d7a71e0ac0ab344a4e76576fcbb8","impliedFormat":1},{"version":"3e7efde639c6a6c3edb9847b3f61e308bf7a69685b92f665048c45132f51c218","impliedFormat":1},{"version":"df45ca1176e6ac211eae7ddf51336dc075c5314bc5c253651bae639defd5eec5","impliedFormat":1},{"version":"106c6025f1d99fd468fd8bf6e5bda724e11e5905a4076c5d29790b6c3745e50c","impliedFormat":1},{"version":"ee8df1cb8d0faaca4013a1b442e99130769ce06f438d18d510fed95890067563","impliedFormat":1},{"version":"bfb7f8475428637bee12bdd31bd9968c1c8a1cc2c3e426c959e2f3a307f8936f","impliedFormat":1},{"version":"6f491d0108927478d3247bbbc489c78c2da7ef552fd5277f1ab6819986fdf0b1","impliedFormat":1},{"version":"594fe24fc54645ab6ccb9dba15d3a35963a73a395b2ef0375ea34bf181ccfd63","impliedFormat":1},{"version":"7cb0ee103671d1e201cd53dda12bc1cd0a35f1c63d6102720c6eeb322cb8e17e","impliedFormat":1},{"version":"15a234e5031b19c48a69ccc1607522d6e4b50f57d308ecb7fe863d44cd9f9eb3","impliedFormat":1},{"version":"148679c6d0f449210a96e7d2e562d589e56fcde87f843a92808b3ff103f1a774","impliedFormat":1},{"version":"6459054aabb306821a043e02b89d54da508e3a6966601a41e71c166e4ea1474f","impliedFormat":1},{"version":"2f9c89cbb29d362290531b48880a4024f258c6033aaeb7e59fbc62db26819650","impliedFormat":1},{"version":"bb37588926aba35c9283fe8d46ebf4e79ffe976343105f5c6d45f282793352b2","impliedFormat":1},{"version":"05c97cddbaf99978f83d96de2d8af86aded9332592f08ce4a284d72d0952c391","impliedFormat":1},{"version":"72179f9dd22a86deaad4cc3490eb0fe69ee084d503b686985965654013f1391b","impliedFormat":1},{"version":"2e6114a7dd6feeef85b2c80120fdbfb59a5529c0dcc5bfa8447b6996c97a69f5","impliedFormat":1},{"version":"7b6ff760c8a240b40dab6e4419b989f06a5b782f4710d2967e67c695ef3e93c4","impliedFormat":1},{"version":"c8f004e6036aa1c764ad4ec543cf89a5c1893a9535c80ef3f2b653e370de45e6","impliedFormat":1},{"version":"dd80b1e600d00f5c6a6ba23f455b84a7db121219e68f89f10552c54ba46e4dc9","impliedFormat":1},{"version":"b064c36f35de7387d71c599bfcf28875849a1dbc733e82bd26cae3d1cd060521","impliedFormat":1},{"version":"05c7280d72f3ed26f346cbe7cbbbb002fb7f15739197cbbee6ab3fd1a6cb9347","impliedFormat":1},{"version":"8de9fe97fa9e00ec00666fa77ab6e91b35d25af8ca75dabcb01e14ad3299b150","impliedFormat":1},{"version":"803cd2aaf1921c218916c2c7ee3fce653e852d767177eb51047ff15b5b253893","impliedFormat":1},{"version":"dba114fb6a32b355a9cfc26ca2276834d72fe0e94cd2c3494005547025015369","impliedFormat":1},{"version":"7ab12b2f1249187223d11a589f5789c75177a0b597b9eb7f8e2e42d045393347","impliedFormat":1},{"version":"ad37fb4be61c1035b68f532b7220f4e8236cf245381ce3b90ac15449ecfe7305","impliedFormat":1},{"version":"93436bd74c66baba229bfefe1314d122c01f0d4c1d9e35081a0c4f0470ac1a6c","impliedFormat":1},{"version":"f974e4a06953682a2c15d5bd5114c0284d5abf8bc0fe4da25cb9159427b70072","impliedFormat":1},{"version":"50256e9c31318487f3752b7ac12ff365c8949953e04568009c8705db802776fb","impliedFormat":1},{"version":"7d73b24e7bf31dfb8a931ca6c4245f6bb0814dfae17e4b60c9e194a631fe5f7b","impliedFormat":1},{"version":"d130c5f73768de51402351d5dc7d1b36eaec980ca697846e53156e4ea9911476","impliedFormat":1},{"version":"413586add0cfe7369b64979d4ec2ed56c3f771c0667fbde1bf1f10063ede0b08","impliedFormat":1},{"version":"06472528e998d152375ad3bd8ebcb69ff4694fd8d2effaf60a9d9f25a37a097a","impliedFormat":1},{"version":"50b5bc34ce6b12eccb76214b51aadfa56572aa6cc79c2b9455cdbb3d6c76af1d","impliedFormat":1},{"version":"b7e16ef7f646a50991119b205794ebfd3a4d8f8e0f314981ebbe991639023d0e","impliedFormat":1},{"version":"42c169fb8c2d42f4f668c624a9a11e719d5d07dacbebb63cbcf7ef365b0a75b3","impliedFormat":1},{"version":"a401617604fa1f6ce437b81689563dfdc377069e4c58465dbd8d16069aede0a5","impliedFormat":1},{"version":"6e9082e91370de5040e415cd9f24e595b490382e8c7402c4e938a8ce4bccc99f","impliedFormat":1},{"version":"8695dec09ad439b0ceef3776ea68a232e381135b516878f0901ed2ea114fd0fe","impliedFormat":1},{"version":"304b44b1e97dd4c94697c3313df89a578dca4930a104454c99863f1784a54357","impliedFormat":1},{"version":"d682336018141807fb602709e2d95a192828fcb8d5ba06dda3833a8ea98f69e3","impliedFormat":1},{"version":"6124e973eab8c52cabf3c07575204efc1784aca6b0a30c79eb85fe240a857efa","impliedFormat":1},{"version":"0d891735a21edc75df51f3eb995e18149e119d1ce22fd40db2b260c5960b914e","impliedFormat":1},{"version":"3b414b99a73171e1c4b7b7714e26b87d6c5cb03d200352da5342ab4088a54c85","impliedFormat":1},{"version":"4fbd3116e00ed3a6410499924b6403cc9367fdca303e34838129b328058ede40","impliedFormat":1},{"version":"b01bd582a6e41457bc56e6f0f9de4cb17f33f5f3843a7cf8210ac9c18472fb0f","impliedFormat":1},{"version":"0a437ae178f999b46b6153d79095b60c42c996bc0458c04955f1c996dc68b971","impliedFormat":1},{"version":"74b2a5e5197bd0f2e0077a1ea7c07455bbea67b87b0869d9786d55104006784f","impliedFormat":1},{"version":"4a7baeb6325920044f66c0f8e5e6f1f52e06e6d87588d837bdf44feb6f35c664","impliedFormat":1},{"version":"12d218a49dbe5655b911e6cc3c13b2c655e4c783471c3b0432137769c79e1b3c","impliedFormat":1},{"version":"7274fbffbd7c9589d8d0ffba68157237afd5cecff1e99881ea3399127e60572f","impliedFormat":1},{"version":"6b0fc04121360f752d196ba35b6567192f422d04a97b2840d7d85f8b79921c92","impliedFormat":1},{"version":"65a15fc47900787c0bd18b603afb98d33ede930bed1798fc984d5ebb78b26cf9","impliedFormat":1},{"version":"9d202701f6e0744adb6314d03d2eb8fc994798fc83d91b691b75b07626a69801","impliedFormat":1},{"version":"a365c4d3bed3be4e4e20793c999c51f5cd7e6792322f14650949d827fbcd170f","impliedFormat":1},{"version":"c5426dbfc1cf90532f66965a7aa8c1136a78d4d0f96d8180ecbfc11d7722f1a5","impliedFormat":1},{"version":"9c82171d836c47486074e4ca8e059735bf97b205e70b196535b5efd40cbe1bc5","impliedFormat":1},{"version":"f374cb24e93e7798c4d9e83ff872fa52d2cdb36306392b840a6ddf46cb925cb6","impliedFormat":1},{"version":"42b81043b00ff27c6bd955aea0f6e741545f2265978bf364b614702b72a027ab","impliedFormat":1},{"version":"de9d2df7663e64e3a91bf495f315a7577e23ba088f2949d5ce9ec96f44fba37d","impliedFormat":1},{"version":"c7af78a2ea7cb1cd009cfb5bdb48cd0b03dad3b54f6da7aab615c2e9e9d570c5","impliedFormat":1},{"version":"1ee45496b5f8bdee6f7abc233355898e5bf9bd51255db65f5ff7ede617ca0027","impliedFormat":1},{"version":"97e5ccc7bb88419005cbdf812243a5b3186cdef81b608540acabe1be163fc3e4","affectsGlobalScope":true,"impliedFormat":1},{"version":"3fbdd025f9d4d820414417eeb4107ffa0078d454a033b506e22d3a23bc3d9c41","affectsGlobalScope":true,"impliedFormat":1},{"version":"a8f8e6ab2fa07b45251f403548b78eaf2022f3c2254df3dc186cb2671fe4996d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fa6c12a7c0f6b84d512f200690bfc74819e99efae69e4c95c4cd30f6884c526e","impliedFormat":1},{"version":"f1c32f9ce9c497da4dc215c3bc84b722ea02497d35f9134db3bb40a8d918b92b","impliedFormat":1},{"version":"b73c319af2cc3ef8f6421308a250f328836531ea3761823b4cabbd133047aefa","affectsGlobalScope":true,"impliedFormat":1},{"version":"e433b0337b8106909e7953015e8fa3f2d30797cea27141d1c5b135365bb975a6","impliedFormat":1},{"version":"9f9bb6755a8ce32d656ffa4763a8144aa4f274d6b69b59d7c32811031467216e","impliedFormat":1},{"version":"5c32bdfbd2d65e8fffbb9fbda04d7165e9181b08dad61154961852366deb7540","impliedFormat":1},{"version":"ddff7fc6edbdc5163a09e22bf8df7bef75f75369ebd7ecea95ba55c4386e2441","impliedFormat":1},{"version":"6b3453eebd474cc8acf6d759f1668e6ce7425a565e2996a20b644c72916ecf75","impliedFormat":1},{"version":"0c05e9842ec4f8b7bfebfd3ca61604bb8c914ba8da9b5337c4f25da427a005f2","impliedFormat":1},{"version":"89cd3444e389e42c56fd0d072afef31387e7f4107651afd2c03950f22dc36f77","impliedFormat":1},{"version":"7f2aa4d4989a82530aaac3f72b3dceca90e9c25bee0b1a327e8a08a1262435ad","impliedFormat":1},{"version":"e39a304f882598138a8022106cb8de332abbbb87f3fee71c5ca6b525c11c51fc","impliedFormat":1},{"version":"faed7a5153215dbd6ebe76dfdcc0af0cfe760f7362bed43284be544308b114cf","impliedFormat":1},{"version":"fcdf3e40e4a01b9a4b70931b8b51476b210c511924fcfe3f0dae19c4d52f1a54","impliedFormat":1},{"version":"345c4327b637d34a15aba4b7091eb068d6ab40a3dedaab9f00986253c9704e53","impliedFormat":1},{"version":"3a788c7fb7b1b1153d69a4d1d9e1d0dfbcf1127e703bdb02b6d12698e683d1fb","impliedFormat":1},{"version":"2e4f37ffe8862b14d8e24ae8763daaa8340c0df0b859d9a9733def0eee7562d9","impliedFormat":1},{"version":"d38530db0601215d6d767f280e3a3c54b2a83b709e8d9001acb6f61c67e965fc","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"4805f6161c2c8cefb8d3b8bd96a080c0fe8dbc9315f6ad2e53238f9a79e528a6","impliedFormat":1},{"version":"b83cb14474fa60c5f3ec660146b97d122f0735627f80d82dd03e8caa39b4388c","impliedFormat":1},{"version":"2b5b70d7782fe028487a80a1c214e67bd610532b9f978b78fa60f5b4a359f77e","impliedFormat":1},{"version":"7ee86fbb3754388e004de0ef9e6505485ddfb3be7640783d6d015711c03d302d","impliedFormat":1},{"version":"1a82deef4c1d39f6882f28d275cad4c01f907b9b39be9cbc472fcf2cf051e05b","impliedFormat":1},{"version":"7580e62139cb2b44a0270c8d01abcbfcba2819a02514a527342447fa69b34ef1","impliedFormat":1},{"version":"b73cbf0a72c8800cf8f96a9acfe94f3ad32ca71342a8908b8ae484d61113f647","impliedFormat":1},{"version":"bae6dd176832f6423966647382c0d7ba9e63f8c167522f09a982f086cd4e8b23","impliedFormat":1},{"version":"20865ac316b8893c1a0cc383ccfc1801443fbcc2a7255be166cf90d03fac88c9","impliedFormat":1},{"version":"c9958eb32126a3843deedda8c22fb97024aa5d6dd588b90af2d7f2bfac540f23","impliedFormat":1},{"version":"461d0ad8ae5f2ff981778af912ba71b37a8426a33301daa00f21c6ccb27f8156","impliedFormat":1},{"version":"e927c2c13c4eaf0a7f17e6022eee8519eb29ef42c4c13a31e81a611ab8c95577","impliedFormat":1},{"version":"fcafff163ca5e66d3b87126e756e1b6dfa8c526aa9cd2a2b0a9da837d81bbd72","impliedFormat":1},{"version":"70246ad95ad8a22bdfe806cb5d383a26c0c6e58e7207ab9c431f1cb175aca657","impliedFormat":1},{"version":"f00f3aa5d64ff46e600648b55a79dcd1333458f7a10da2ed594d9f0a44b76d0b","impliedFormat":1},{"version":"772d8d5eb158b6c92412c03228bd9902ccb1457d7a705b8129814a5d1a6308fc","impliedFormat":1},{"version":"802e797bcab5663b2c9f63f51bdf67eff7c41bc64c0fd65e6da3e7941359e2f7","impliedFormat":1},{"version":"8b4327413e5af38cd8cb97c59f48c3c866015d5d642f28518e3a891c469f240e","impliedFormat":1},{"version":"7e6ac205dcb9714f708354fd863bffa45cee90740706cc64b3b39b23ebb84744","impliedFormat":1},{"version":"61dc6e3ac78d64aa864eedd0a208b97b5887cc99c5ba65c03287bf57d83b1eb9","impliedFormat":1},{"version":"4b20fcf10a5413680e39f5666464859fc56b1003e7dfe2405ced82371ebd49b6","impliedFormat":1},{"version":"c06ef3b2569b1c1ad99fcd7fe5fba8d466e2619da5375dfa940a94e0feea899b","impliedFormat":1},{"version":"f7d628893c9fa52ba3ab01bcb5e79191636c4331ee5667ecc6373cbccff8ae12","impliedFormat":1},{"version":"1d879125d1ec570bf04bc1f362fdbe0cb538315c7ac4bcfcdf0c1e9670846aa6","impliedFormat":1},{"version":"f730b468deecf26188ad62ee8950dc29aa2aea9543bb08ed714c3db019359fd9","impliedFormat":1},{"version":"933aee906d42ea2c53b6892192a8127745f2ec81a90695df4024308ba35a8ff4","impliedFormat":1},{"version":"d663134457d8d669ae0df34eabd57028bddc04fc444c4bc04bc5215afc91e1f4","impliedFormat":1},{"version":"144bc326e90b894d1ec78a2af3ffb2eb3733f4d96761db0ca0b6239a8285f972","impliedFormat":1},{"version":"a3e3f0efcae272ab8ee3298e4e819f7d9dd9ff411101f45444877e77cfeca9a4","impliedFormat":1},{"version":"43e96a3d5d1411ab40ba2f61d6a3192e58177bcf3b133a80ad2a16591611726d","impliedFormat":1},{"version":"58659b06d33fa430bee1105b75cf876c0a35b2567207487c8578aec51ca2d977","impliedFormat":1},{"version":"71d9eb4c4e99456b78ae182fb20a5dfc20eb1667f091dbb9335b3c017dd1c783","impliedFormat":1},{"version":"cfa846a7b7847a1d973605fbb8c91f47f3a0f0643c18ac05c47077ebc72e71c7","impliedFormat":1},{"version":"30e6520444df1a004f46fdc8096f3fe06f7bbd93d09c53ada9dcdde59919ccca","impliedFormat":1},{"version":"6c800b281b9e89e69165fd11536195488de3ff53004e55905e6c0059a2d8591e","impliedFormat":1},{"version":"7d4254b4c6c67a29d5e7f65e67d72540480ac2cfb041ca484847f5ae70480b62","impliedFormat":1},{"version":"a58beefce74db00dbb60eb5a4bb0c6726fb94c7797c721f629142c0ae9c94306","impliedFormat":1},{"version":"41eeb453ccb75c5b2c3abef97adbbd741bd7e9112a2510e12f03f646dc9ad13d","impliedFormat":1},{"version":"502fa5863df08b806dbf33c54bee8c19f7e2ad466785c0fc35465d7c5ff80995","impliedFormat":1},{"version":"c91a2d08601a1547ffef326201be26db94356f38693bb18db622ae5e9b3d7c92","impliedFormat":1},{"version":"888cda0fa66d7f74e985a3f7b1af1f64b8ff03eb3d5e80d051c3cbdeb7f32ab7","impliedFormat":1},{"version":"60681e13f3545be5e9477acb752b741eae6eaf4cc01658a25ec05bff8b82a2ef","impliedFormat":1},{"version":"9586918b63f24124a5ca1d0cc2979821a8a57f514781f09fc5aa9cae6d7c0138","impliedFormat":1},{"version":"a57b1802794433adec9ff3fed12aa79d671faed86c49b09e02e1ac41b4f1d33a","impliedFormat":1},{"version":"ad10d4f0517599cdeca7755b930f148804e3e0e5b5a3847adce0f1f71bbccd74","impliedFormat":1},{"version":"1042064ece5bb47d6aba91648fbe0635c17c600ebdf567588b4ca715602f0a9d","impliedFormat":1},{"version":"c49469a5349b3cc1965710b5b0f98ed6c028686aa8450bcb3796728873eb923e","impliedFormat":1},{"version":"4a889f2c763edb4d55cb624257272ac10d04a1cad2ed2948b10ed4a7fda2a428","impliedFormat":1},{"version":"7bb79aa2fead87d9d56294ef71e056487e848d7b550c9a367523ee5416c44cfa","impliedFormat":1},{"version":"d88ea80a6447d7391f52352ec97e56b52ebec934a4a4af6e2464cfd8b39c3ba8","impliedFormat":1},{"version":"55095860901097726220b6923e35a812afdd49242a1246d7b0942ee7eb34c6e4","impliedFormat":1},{"version":"96171c03c2e7f314d66d38acd581f9667439845865b7f85da8df598ff9617476","impliedFormat":1},{"version":"27ff4196654e6373c9af16b6165120e2dd2169f9ad6abb5c935af5abd8c7938c","impliedFormat":1},{"version":"bb8f2dbc03533abca2066ce4655c119bff353dd4514375beb93c08590c03e023","impliedFormat":1},{"version":"d193c8a86144b3a87b22bc1f5534b9c3e0f5a187873ec337c289a183973a58fe","impliedFormat":1},{"version":"1a6e6ba8a07b74e3ad237717c0299d453f9ceb795dbc2f697d1f2dd07cb782d2","impliedFormat":1},{"version":"58d70c38037fc0f949243388ff7ae20cf43321107152f14a9d36ca79311e0ada","impliedFormat":1},{"version":"f56bdc6884648806d34bc66d31cdb787c4718d04105ce2cd88535db214631f82","impliedFormat":1},{"version":"190da5eac6478d61ab9731ab2146fbc0164af2117a363013249b7e7992f1cccb","impliedFormat":1},{"version":"01479d9d5a5dda16d529b91811375187f61a06e74be294a35ecce77e0b9e8d6c","impliedFormat":1},{"version":"49f95e989b4632c6c2a578cc0078ee19a5831832d79cc59abecf5160ea71abad","impliedFormat":1},{"version":"9666533332f26e8995e4d6fe472bdeec9f15d405693723e6497bf94120c566c8","impliedFormat":1},{"version":"ce0df82a9ae6f914ba08409d4d883983cc08e6d59eb2df02d8e4d68309e7848b","impliedFormat":1},{"version":"796273b2edc72e78a04e86d7c58ae94d370ab93a0ddf40b1aa85a37a1c29ecd7","impliedFormat":1},{"version":"5df15a69187d737d6d8d066e189ae4f97e41f4d53712a46b2710ff9f8563ec9f","impliedFormat":1},{"version":"1a4dc28334a926d90ba6a2d811ba0ff6c22775fcc13679521f034c124269fd40","impliedFormat":1},{"version":"f05315ff85714f0b87cc0b54bcd3dde2716e5a6b99aedcc19cad02bf2403e08c","impliedFormat":1},{"version":"8a8c64dafaba11c806efa56f5c69f611276471bef80a1db1f71316ec4168acef","impliedFormat":1},{"version":"43ba4f2fa8c698f5c304d21a3ef596741e8e85a810b7c1f9b692653791d8d97a","impliedFormat":1},{"version":"5fad3b31fc17a5bc58095118a8b160f5260964787c52e7eb51e3d4fcf5d4a6f0","impliedFormat":1},{"version":"72105519d0390262cf0abe84cf41c926ade0ff475d35eb21307b2f94de985778","impliedFormat":1},{"version":"d0a4cac61fa080f2be5ebb68b82726be835689b35994ba0e22e3ed4d2bc45e3b","impliedFormat":1},{"version":"c857e0aae3f5f444abd791ec81206020fbcc1223e187316677e026d1c1d6fe08","impliedFormat":1},{"version":"ccf6dd45b708fb74ba9ed0f2478d4eb9195c9dfef0ff83a6092fa3cf2ff53b4f","impliedFormat":1},{"version":"2d7db1d73456e8c5075387d4240c29a2a900847f9c1bff106a2e490da8fbd457","impliedFormat":1},{"version":"2b15c805f48e4e970f8ec0b1915f22d13ca6212375e8987663e2ef5f0205e832","impliedFormat":1},{"version":"205a31b31beb7be73b8df18fcc43109cbc31f398950190a0967afc7a12cb478c","impliedFormat":1},{"version":"8fca3039857709484e5893c05c1f9126ab7451fa6c29e19bb8c2411a2e937345","impliedFormat":1},{"version":"35069c2c417bd7443ae7c7cafd1de02f665bf015479fec998985ffbbf500628c","impliedFormat":1},{"version":"dba6c7006e14a98ec82999c6f89fbbbfd1c642f41db148535f3b77b8018829b8","impliedFormat":1},{"version":"7f897b285f22a57a5c4dc14a27da2747c01084a542b4d90d33897216dceeea2e","impliedFormat":1},{"version":"7e0b7f91c5ab6e33f511efc640d36e6f933510b11be24f98836a20a2dc914c2d","impliedFormat":1},{"version":"045b752f44bf9bbdcaffd882424ab0e15cb8d11fa94e1448942e338c8ef19fba","impliedFormat":1},{"version":"2894c56cad581928bb37607810af011764a2f511f575d28c9f4af0f2ef02d1ab","impliedFormat":1},{"version":"0a72186f94215d020cb386f7dca81d7495ab6c17066eb07d0f44a5bf33c1b21a","impliedFormat":1},{"version":"d96b39301d0ded3f1a27b47759676a33a02f6f5049bfcbde81e533fd10f50dcb","impliedFormat":1},{"version":"2ded4f930d6abfaa0625cf55e58f565b7cbd4ab5b574dd2cb19f0a83a2f0be8b","impliedFormat":1},{"version":"0aedb02516baf3e66b2c1db9fef50666d6ed257edac0f866ea32f1aa05aa474f","impliedFormat":1},{"version":"ca0f4d9068d652bad47e326cf6ba424ac71ab866e44b24ddb6c2bd82d129586a","affectsGlobalScope":true,"impliedFormat":1},{"version":"04d36005fcbeac741ac50c421181f4e0316d57d148d37cc321a8ea285472462b","impliedFormat":1},{"version":"9e2739b32f741859263fdba0244c194ca8e96da49b430377930b8f721d77c000","impliedFormat":1},{"version":"56ccb49443bfb72e5952f7012f0de1a8679f9f75fc93a5c1ac0bafb28725fc5f","impliedFormat":1},{"version":"20fa37b636fdcc1746ea0738f733d0aed17890d1cd7cb1b2f37010222c23f13e","impliedFormat":1},{"version":"d90b9f1520366d713a73bd30c5a9eb0040d0fb6076aff370796bc776fd705943","impliedFormat":1},{"version":"bc03c3c352f689e38c0ddd50c39b1e65d59273991bfc8858a9e3c0ebb79c023b","impliedFormat":1},{"version":"19df3488557c2fc9b4d8f0bac0fd20fb59aa19dec67c81f93813951a81a867f8","affectsGlobalScope":true,"impliedFormat":1},{"version":"b25350193e103ae90423c5418ddb0ad1168dc9c393c9295ef34980b990030617","affectsGlobalScope":true,"impliedFormat":1},{"version":"bef86adb77316505c6b471da1d9b8c9e428867c2566270e8894d4d773a1c4dc2","impliedFormat":1},{"version":"a46dba563f70f32f9e45ae015f3de979225f668075d7a427f874e0f6db584991","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"2652448ac55a2010a1f71dd141f828b682298d39728f9871e1cdf8696ef443fd","impliedFormat":1},{"version":"02c4fc9e6bb27545fa021f6056e88ff5fdf10d9d9f1467f1d10536c6e749ac50","impliedFormat":1},{"version":"120599fd965257b1f4d0ff794bc696162832d9d8467224f4665f713a3119078b","impliedFormat":1},{"version":"5433f33b0a20300cca35d2f229a7fc20b0e8477c44be2affeb21cb464af60c76","impliedFormat":1},{"version":"db036c56f79186da50af66511d37d9fe77fa6793381927292d17f81f787bb195","impliedFormat":1},{"version":"bd4131091b773973ca5d2326c60b789ab1f5e02d8843b3587effe6e1ea7c9d86","impliedFormat":1},{"version":"c7f6485931085bf010fbaf46880a9b9ec1a285ad9dc8c695a9e936f5a48f34b4","impliedFormat":1},{"version":"14f6b927888a1112d662877a5966b05ac1bf7ed25d6c84386db4c23c95a5363b","impliedFormat":1},{"version":"6ac6715916fa75a1f7ebdfeacac09513b4d904b667d827b7535e84ff59679aff","impliedFormat":1},{"version":"622694a8522b46f6310c2a9b5d2530dde1e2854cb5829354e6d1ff8f371cf469","impliedFormat":1},{"version":"d24ff95760ea2dfcc7c57d0e269356984e7046b7e0b745c80fea71559f15bdd8","impliedFormat":1},{"version":"a9e6c0ff3f8186fccd05752cf75fc94e147c02645087ac6de5cc16403323d870","impliedFormat":1},{"version":"49c346823ba6d4b12278c12c977fb3a31c06b9ca719015978cb145eb86da1c61","impliedFormat":1},{"version":"bfac6e50eaa7e73bb66b7e052c38fdc8ccfc8dbde2777648642af33cf349f7f1","impliedFormat":1},{"version":"92f7c1a4da7fbfd67a2228d1687d5c2e1faa0ba865a94d3550a3941d7527a45d","impliedFormat":1},{"version":"f53b120213a9289d9a26f5af90c4c686dd71d91487a0aa5451a38366c70dc64b","impliedFormat":1},{"version":"83fe880c090afe485a5c02262c0b7cdd76a299a50c48d9bde02be8e908fb4ae6","impliedFormat":1},{"version":"13c1b657932e827a7ed510395d94fc8b743b9d053ab95b7cd829b2bc46fb06db","impliedFormat":1},{"version":"57d67b72e06059adc5e9454de26bbfe567d412b962a501d263c75c2db430f40e","impliedFormat":1},{"version":"6511e4503cf74c469c60aafd6589e4d14d5eb0a25f9bf043dcbecdf65f261972","impliedFormat":1},{"version":"078131f3a722a8ad3fc0b724cd3497176513cdcb41c80f96a3acbda2a143b58e","impliedFormat":1},{"version":"8c70ddc0c22d85e56011d49fddfaae3405eb53d47b59327b9dd589e82df672e7","impliedFormat":1},{"version":"a67b87d0281c97dfc1197ef28dfe397fc2c865ccd41f7e32b53f647184cc7307","impliedFormat":1},{"version":"771ffb773f1ddd562492a6b9aaca648192ac3f056f0e1d997678ff97dbb6bf9b","impliedFormat":1},{"version":"232f70c0cf2b432f3a6e56a8dc3417103eb162292a9fd376d51a3a9ea5fbbf6f","impliedFormat":1},{"version":"9e155d2255348d950b1f65643fb26c0f14f5109daf8bd9ee24a866ad0a743648","affectsGlobalScope":true,"impliedFormat":1},{"version":"0b103e9abfe82d14c0ad06a55d9f91d6747154ef7cacc73cf27ecad2bfb3afcf","impliedFormat":1},{"version":"7a883e9c84e720810f86ef4388f54938a65caa0f4d181a64e9255e847a7c9f51","impliedFormat":1},{"version":"a0ba218ac1baa3da0d5d9c1ec1a7c2f8676c284e6f5b920d6d049b13fa267377","impliedFormat":1},{"version":"8a0e762ceb20c7e72504feef83d709468a70af4abccb304f32d6b9bac1129b2c","impliedFormat":1},{"version":"d408d6f32de8d1aba2ff4a20f1aa6a6edd7d92c997f63b90f8ad3f9017cf5e46","impliedFormat":1},{"version":"9252d498a77517aab5d8d4b5eb9d71e4b225bbc7123df9713e08181de63180f6","impliedFormat":1},{"version":"b1f1d57fde8247599731b24a733395c880a6561ec0c882efaaf20d7df968c5af","impliedFormat":1},{"version":"9d622ea608d43eb463c0c4538fd5baa794bc18ea0bb8e96cd2ab6fd483d55fe2","impliedFormat":1},{"version":"35e6379c3f7cb27b111ad4c1aa69538fd8e788ab737b8ff7596a1b40e96f4f90","impliedFormat":1},{"version":"1fffe726740f9787f15b532e1dc870af3cd964dbe29e191e76121aa3dd8693f2","impliedFormat":1},{"version":"371bf6127c1d427836de95197155132501cb6b69ef8709176ce6e0b85d059264","impliedFormat":1},{"version":"2bafd700e617d3693d568e972d02b92224b514781f542f70d497a8fdf92d52a2","affectsGlobalScope":true,"impliedFormat":1},{"version":"5542d8a7ea13168cb573be0d1ba0d29460d59430fb12bb7bf4674efd5604e14c","impliedFormat":1},{"version":"af48e58339188d5737b608d41411a9c054685413d8ae88b8c1d0d9bfabdf6e7e","impliedFormat":1},{"version":"616775f16134fa9d01fc677ad3f76e68c051a056c22ab552c64cc281a9686790","impliedFormat":1},{"version":"65c24a8baa2cca1de069a0ba9fba82a173690f52d7e2d0f1f7542d59d5eb4db0","impliedFormat":1},{"version":"f9fe6af238339a0e5f7563acee3178f51db37f32a2e7c09f85273098cee7ec49","impliedFormat":1},{"version":"1de8c302fd35220d8f29dea378a4ae45199dc8ff83ca9923aca1400f2b28848a","impliedFormat":1},{"version":"77e71242e71ebf8528c5802993697878f0533db8f2299b4d36aa015bae08a79c","impliedFormat":1},{"version":"98a787be42bd92f8c2a37d7df5f13e5992da0d967fab794adbb7ee18370f9849","impliedFormat":1},{"version":"332248ee37cca52903572e66c11bef755ccc6e235835e63d3c3e60ddda3e9b93","impliedFormat":1},{"version":"94e8cc88ae2ef3d920bb3bdc369f48436db123aa2dc07f683309ad8c9968a1e1","impliedFormat":1},{"version":"4545c1a1ceca170d5d83452dd7c4994644c35cf676a671412601689d9a62da35","impliedFormat":1},{"version":"320f4091e33548b554d2214ce5fc31c96631b513dffa806e2e3a60766c8c49d9","impliedFormat":1},{"version":"a2d648d333cf67b9aeac5d81a1a379d563a8ffa91ddd61c6179f68de724260ff","impliedFormat":1},{"version":"d90d5f524de38889d1e1dbc2aeef00060d779f8688c02766ddb9ca195e4a713d","impliedFormat":1},{"version":"a3f41ed1b4f2fc3049394b945a68ae4fdefd49fa1739c32f149d32c0545d67f5","impliedFormat":1},{"version":"b0309e1eda99a9e76f87c18992d9c3689b0938266242835dd4611f2b69efe456","impliedFormat":1},{"version":"47699512e6d8bebf7be488182427189f999affe3addc1c87c882d36b7f2d0b0e","impliedFormat":1},{"version":"6ceb10ca57943be87ff9debe978f4ab73593c0c85ee802c051a93fc96aaf7a20","impliedFormat":1},{"version":"1de3ffe0cc28a9fe2ac761ece075826836b5a02f340b412510a59ba1d41a505a","impliedFormat":1},{"version":"e46d6cc08d243d8d0d83986f609d830991f00450fb234f5b2f861648c42dc0d8","impliedFormat":1},{"version":"1c0a98de1323051010ce5b958ad47bc1c007f7921973123c999300e2b7b0ecc0","impliedFormat":1},{"version":"ff863d17c6c659440f7c5c536e4db7762d8c2565547b2608f36b798a743606ca","impliedFormat":1},{"version":"5412ad0043cd60d1f1406fc12cb4fb987e9a734decbdd4db6f6acf71791e36fe","impliedFormat":1},{"version":"ad036a85efcd9e5b4f7dd5c1a7362c8478f9a3b6c3554654ca24a29aa850a9c5","impliedFormat":1},{"version":"fedebeae32c5cdd1a85b4e0504a01996e4a8adf3dfa72876920d3dd6e42978e7","impliedFormat":1},{"version":"b6c1f64158da02580f55e8a2728eda6805f79419aed46a930f43e68ad66a38fc","impliedFormat":1},{"version":"cdf21eee8007e339b1b9945abf4a7b44930b1d695cc528459e68a3adc39a622e","impliedFormat":1},{"version":"bc9ee0192f056b3d5527bcd78dc3f9e527a9ba2bdc0a2c296fbc9027147df4b2","impliedFormat":1},{"version":"330896c1a2b9693edd617be24fbf9e5895d6e18c7955d6c08f028f272b37314d","impliedFormat":1},{"version":"1d9c0a9a6df4e8f29dc84c25c5aa0bb1da5456ebede7a03e03df08bb8b27bae6","impliedFormat":1},{"version":"84380af21da938a567c65ef95aefb5354f676368ee1a1cbb4cae81604a4c7d17","impliedFormat":1},{"version":"1af3e1f2a5d1332e136f8b0b95c0e6c0a02aaabd5092b36b64f3042a03debf28","impliedFormat":1},{"version":"30d8da250766efa99490fc02801047c2c6d72dd0da1bba6581c7e80d1d8842a4","impliedFormat":1},{"version":"03566202f5553bd2d9de22dfab0c61aa163cabb64f0223c08431fb3fc8f70280","impliedFormat":1},{"version":"4c0a1233155afb94bd4d7518c75c84f98567cd5f13fc215d258de196cdb40d91","impliedFormat":1},{"version":"e7765aa8bcb74a38b3230d212b4547686eb9796621ffb4367a104451c3f9614f","impliedFormat":1},{"version":"1de80059b8078ea5749941c9f863aa970b4735bdbb003be4925c853a8b6b4450","impliedFormat":1},{"version":"1d079c37fa53e3c21ed3fa214a27507bda9991f2a41458705b19ed8c2b61173d","impliedFormat":1},{"version":"5bf5c7a44e779790d1eb54c234b668b15e34affa95e78eada73e5757f61ed76a","impliedFormat":1},{"version":"5835a6e0d7cd2738e56b671af0e561e7c1b4fb77751383672f4b009f4e161d70","impliedFormat":1},{"version":"5c634644d45a1b6bc7b05e71e05e52ec04f3d73d9ac85d5927f647a5f965181a","impliedFormat":1},{"version":"4b7f74b772140395e7af67c4841be1ab867c11b3b82a51b1aeb692822b76c872","impliedFormat":1},{"version":"27be6622e2922a1b412eb057faa854831b95db9db5035c3f6d4b677b902ab3b7","impliedFormat":1},{"version":"a68d4b3182e8d776cdede7ac9630c209a7bfbb59191f99a52479151816ef9f9e","impliedFormat":99},{"version":"39644b343e4e3d748344af8182111e3bbc594930fff0170256567e13bbdbebb0","impliedFormat":99},{"version":"ed7fd5160b47b0de3b1571c5c5578e8e7e3314e33ae0b8ea85a895774ee64749","impliedFormat":99},{"version":"63a7595a5015e65262557f883463f934904959da563b4f788306f699411e9bac","impliedFormat":1},{"version":"4ba137d6553965703b6b55fd2000b4e07ba365f8caeb0359162ad7247f9707a6","impliedFormat":1},{"version":"6de125ea94866c736c6d58d68eb15272cf7d1020a5b459fea1c660027eca9a90","affectsGlobalScope":true,"impliedFormat":1},{"version":"8fac4a15690b27612d8474fb2fc7cc00388df52d169791b78d1a3645d60b4c8b","affectsGlobalScope":true,"impliedFormat":1},{"version":"064ac1c2ac4b2867c2ceaa74bbdce0cb6a4c16e7c31a6497097159c18f74aa7c","impliedFormat":1},{"version":"3dc14e1ab45e497e5d5e4295271d54ff689aeae00b4277979fdd10fa563540ae","impliedFormat":1},{"version":"d3b315763d91265d6b0e7e7fa93cfdb8a80ce7cdd2d9f55ba0f37a22db00bdb8","impliedFormat":1},{"version":"b789bf89eb19c777ed1e956dbad0925ca795701552d22e68fd130a032008b9f9","impliedFormat":1},{"version":"4e2bcf03609885297fc50894bbc98bba5fd87314f4928607ba3cce55ba0f758c","affectsGlobalScope":true},"7b550dda9686c16f36a17bf9051d5dbf31e98555b30d114ac49fc49a1e712651",{"version":"b5dfc894c0b7557f5608426a7706d3d06e5ea4e692c390591220de07b95b5100","signature":"435a1e418e8338be3f39614b96b81a9aa2700bc8c27bc6b98f064ff9ce17c363"},{"version":"1fcda46aa50e28629f590ed076b2665534f4e3e37a82bb175f5e89a05a899af4","signature":"0ab8b69798ae8c82ab1dc9e4561b38fc6ebb2831ac400025248c79e71bbd7450"},{"version":"c57b441e0c0a9cbdfa7d850dae1f8a387d6f81cbffbc3cd0465d530084c2417d","impliedFormat":99},{"version":"51954e948be6a5b728fcfaf561f12331b4f54f068934c77adfc8f70eea17d285","impliedFormat":1},{"version":"7c8c3dfc0cdd370d44932828eb067ef771c8fe7996693221d5d4b90af6d54f2d","signature":"512960c0e955a2324b34354dac25e3e4d431a1af4cd33077935eda5e95c8b7e1"},{"version":"637ba401e988f8015ac63e6442d66f2e7075c255a0f724f938fe13d9f3a07d56","signature":"cf45e31c18f3dcc0108f3a048f41faabf5cb8bdc3abfe7d9cf04117ecd51953a"},{"version":"9315a990ae2ab955de57ac9245ab4e81b8721eb3cb93657a47ec7a5043618f33","signature":"7559880017b339fb1639c7cb347abb191b5dad5840cdaf1abb7c66bd6264469e"},{"version":"404ada78dd509dd45900cd61f05dcd625f522bba61db3459f118f0381797a512","signature":"4c7eb443cd26541bdf8ca2e8c850d8b898bf81a328f8623be0016e4eaf7e14e2"},{"version":"b7a10caea1fef41558718f7f5fd2b6059fefa19e20dacaf0e00e4a148d0edf15","signature":"179c32825074eb8a28212c2fca939bf63dcb58c100becfebc8340a967f4b08f1"},{"version":"8083b431527d46566cb0184580c8d0073a3f5031fefbda2a5362b76c7115efe5","signature":"9eddc6aa521983a0798dab419767998c652baf50ca8cae412b06386185ead253"},{"version":"0238cceac218e7ae50805af6343035e4acb5a94e333beecee456b74472fcb88f","signature":"28427465c0c2bbba1c9a7a7dbd097de6271ab39d892e929626420a0bb90c260a"},{"version":"56b7fd30208addbcc2468cfda4f5bc0a55342211deaab61ee35b1c352b1622f1","signature":"f774a7e8875649db68f5952801f001f3c316560ede472e5663af7a8c9c18f938"},{"version":"c44b79c4a8330d58abdaa037ed2528f49ee1bd9c903a6df157a4fa553a94e253","signature":"5e167eeed008f7aca224011e14ff21f7de30719195f32162f7f49d970420e5b3"},{"version":"1abc9a90914e34d26e7284a3aaab7036959dffd12dfee4b8f177da45f3823d18","signature":"50b5991a0d649da68f02eb124e15755d575d0cc38d0feaa11d9e390f19e1a543"},{"version":"2fbe402f0ee5aa8ab55367f88030f79d46211c0a0f342becaa9f648bf8534e9d","impliedFormat":1},{"version":"b94258ef37e67474ac5522e9c519489a55dcb3d4a8f645e335fc68ea2215fe88","impliedFormat":1},{"version":"024829c0b317972acf4f871bf701525f81896ad74015f1a52d46ae6036205cb9","impliedFormat":99},{"version":"a9373d52584b48809ffd61d74f5b3dfd127da846e3c4ee3c415560386df3994b","impliedFormat":99},{"version":"caf4af98bf464ad3e10c46cf7d340556f89197aab0f87f032c7b84eb8ddb24d9","impliedFormat":99},{"version":"0943a6e4e026d0de8a4969ee975a7283e0627bf41aa4635d8502f6f24365ac9b","impliedFormat":99},{"version":"1461efc4aefd3e999244f238f59c9b9753a7e3dfede923ebe2b4a11d6e13a0d0","impliedFormat":99},{"version":"7ec047b73f621c526468517fea779fec2007dd05baa880989def59126c98ef79","impliedFormat":99},{"version":"8dd450de6d756cee0761f277c6dc58b0b5a66b8c274b980949318b8cad26d712","impliedFormat":99},{"version":"904d6ad970b6bd825449480488a73d9b98432357ab38cf8d31ffd651ae376ff5","impliedFormat":99},{"version":"dfcf16e716338e9fe8cf790ac7756f61c85b83b699861df970661e97bf482692","impliedFormat":99},{"version":"31c30cc54e8c3da37c8e2e40e5658471f65915df22d348990d1601901e8c9ff3","impliedFormat":99},{"version":"36d8011f1437aecf0e6e88677d933e4fb3403557f086f4ac00c5a4cb6d028ac2","impliedFormat":99},{"version":"8085954ba165e611c6230596078063627f3656fed3fb68ad1e36a414c4d7599a","impliedFormat":99},{"version":"2c57db2bf2dbd9e8ef4853be7257d62a1cb72845f7b976bb4ee827d362675f96","impliedFormat":99},{"version":"6b5f886fe41e2e767168e491fe6048398ed6439d44e006d9f51cc31265f08978","impliedFormat":99},{"version":"56a87e37f91f5625eb7d5f8394904f3f1e2a90fb08f347161dc94f1ae586bdd0","impliedFormat":99},{"version":"6b863463764ae572b9ada405bf77aac37b5e5089a3ab420d0862e4471051393b","impliedFormat":99},{"version":"68b6a7501a56babd7bcd840e0d638ee7ec582f1e70b3c36ebf32e5e5836913c8","impliedFormat":99},{"version":"89783bd45ab35df55203b522f8271500189c3526976af533a599a86caaf31362","impliedFormat":99},{"version":"6da2e0928bdab05861abc4e4abebea0c7cf0b67e25374ba35a94df2269563dd8","impliedFormat":99},{"version":"e7b00bec016013bcde74268d837a8b57173951add2b23c8fd12ffe57f204d88f","impliedFormat":99},{"version":"26e6c521a290630ea31f0205a46a87cab35faac96e2b30606f37bae7bcda4f9d","impliedFormat":99},{"version":"71acd198e19fa38447a3cbc5c33f2f5a719d933fccf314aaff0e8b0593271324","impliedFormat":99},{"version":"044047026c70439867589d8596ffe417b56158a1f054034f590166dd793b676b","impliedFormat":99},{"version":"89ad9a4e8044299f356f38879a1c2176bc60c997519b442c92cc5a70b731a360","impliedFormat":99},{"version":"fd4f58cd6b5fc8ce8af0d04bfef5142f15c4bafaac9a9899c6daa056f10bb517","impliedFormat":99},{"version":"2a00cea77767cb26393ee6f972fd32941249a0d65b246bfcb20a780a2b919a21","impliedFormat":99},{"version":"440cb5b34e06fabe3dcb13a3f77b98d771bf696857c8e97ce170b4f345f8a26b","impliedFormat":99},{"version":"5bc7f0946c94e23765bd1b8f62dc3ab65d7716285ca7cf45609f57777ddb436f","impliedFormat":99},{"version":"7d5a5e603a68faea3d978630a84cacad7668f11e14164c4dd10224fa1e210f56","impliedFormat":99},{"version":"2535fc1a5fe64892783ff8f61321b181c24f824e688a4a05ae738da33466605b","impliedFormat":99},{"version":"cbfd5ef0c8fdb4983202252b5f5758a579f4500edc3b9ad413da60cffb5c3564","impliedFormat":99},{"version":"9f7a3c434912fd3feb87af4aabdf0d1b614152ecb5e7b2aa1fff3429879cdd51","impliedFormat":99},{"version":"99d1a601593495371e798da1850b52877bf63d0678f15722d5f048e404f002e4","impliedFormat":99},{"version":"1179ef8174e0e4a09d35576199df04803b1db17c0fb35b9326442884bc0b0cce","impliedFormat":99},{"version":"9c580c6eae94f8c9a38373566e59d5c3282dc194aa266b23a50686fe10560159","impliedFormat":99},{"version":"cc3738ba01d9af5ba1206a313896837ff8779791afcd9869e582783550f17f38","impliedFormat":99},{"version":"a80ec72f5e178862476deaeed532c305bdfcd3627014ae7ac2901356d794fc93","impliedFormat":99},{"version":"4a5aa16151dbec524bb043a5cbce2c3fec75957d175475c115a953aca53999a9","impliedFormat":99},{"version":"7a14bf21ae8a29d64c42173c08f026928daf418bed1b97b37ac4bb2aa197b89b","impliedFormat":99},{"version":"c5013d60cbff572255ccc87c314c39e198c8cc6c5aa7855db7a21b79e06a510f","impliedFormat":99},{"version":"69ec8d900cfec3d40e50490fedbbea5c1b49d32c38adbc236e73a3b8978c0b11","impliedFormat":99},{"version":"7fd629484ba6772b686885b443914655089246f75a13dd685845d0abae337671","impliedFormat":99},{"version":"13dcccb62e8537329ac0448f088ab16fe5b0bbed71e56906d28d202072759804","impliedFormat":99},{"version":"233267a4a036c64aee95f66a0d31e3e0ef048cccc57dd66f9cf87582b38691e4","impliedFormat":99},{"version":"ccb9fbe369885d02cf6c2b2948fb5060451565d37b04356bbe753807f98e0682","impliedFormat":99},{"version":"cd98acc71988e234da58315ba3d98b9592dfc91e646cebaafc1d205609ce5eae","signature":"5841c8f5528b440d77c0a80903e0d86b87e5e05c036889e89e7aefcdecc53988"},"11e68c033fdb70e1679da12dc4b28d972eadc080706f004bd1a35204bd4ab1e8","4990e4db21902ea579df93462cad953ae5999b7b2ffef7c717e8bb89136bfc8f",{"version":"2aee0b10b030d30b17d7f209c9f8e04f15003f0cf398f931596b4527fc20366d","signature":"bd5ff0a222d1bf3f946cea793373823c0d825ed32d7b0aa1a9b6826869647606"},{"version":"165473c42e3512ee1882beadc181cab09d2c3eba88833b271daa46cbdd4693a1","signature":"9787c05bb67015c4fc5d14690b735b9b4752b91df22e795de03e3c83826e6087"},"b2c5b0dbb95b3d01cb4e244c2caa199828d6c1d825c657b7c8289ed75bd1b75d",{"version":"a751b107c997575cc1663c83990ca2a57a2afd20f84db806e46dc7fe43462212","signature":"3f89d0dc76db56c5572c5a6320dc5c9c9d06aee6e6017046846a584243a3187a"},{"version":"67820a444327f9fcdce1a5851792652ac63526ec4e33c3ce00b11be6e9474c5d","signature":"bcada47b653e53eb93cbf5ef16ec8800a1a46fa017b778db7b4fee24fa06c18c"},{"version":"d069de3a0b5d290992e07994435a566472f45c205d9063fd9248b78b1f18d055","signature":"181d3d2b1fde5383f956de47b4167afe714162fbe527e3ec7ced7b6a721ac0b3"},"7b26babdb8f6d7c613c306774e6344a9f906bc6137a45411abfce80ff47133c7","291bedfa6f99d0789469f781778fc8b04a52d64e3a4acfbb0e3147eabdcd7574",{"version":"fa1fce9c6eee2f0469573c2ceb0532b6d0fc318c8c90651e70f53db54291da52","signature":"a5f9ac5b5f3d49f819e094fdbffadb6ee122bf8afe2aa1287cd734db77c8e867"},{"version":"2899fdb96853a762ffa3b1b87f07f6ed2cd1ff01694315d1c77ed1965961738e","signature":"e62331fe066698dc4ef6f11156b8c8e94ed213ce0bca377d1822000550b59227"},"63825877d01fb510a016b83ea912d16723f7ac69e6eb0be2362c43aa29d3e9bb","2bf6dd65f5e701f312a0d9c85f7d5487d6f39f37f68600d61582d488aaeefc43","6a584c73348dbeaf93d13334e5d5a31e5a6cf6e07a308d2dd0332b9840214858",{"version":"a4a1f2173e9a16e66cff4f5d8a0382771ee88e9675e48ca8c138f4d241e1fda6","signature":"a709e61e18be65b7fea9af899e162dfc1cff7871e41703a4ca71fa625968fcf7"},{"version":"26e13fb86799603b1466b9dd61d09176a0a514a62353f1691c4b381c7affd933","signature":"4c461c5ef657d516139314509aa907f547f15e5270f183c301e80d8b04566e50"},"798541acd745cf9ad5f6b866dce4dc76514b94e2a80d8d7589bbcea2c96905c2","c4e62c45813a3f9c94dafe8aedde5901bc9a7062272e9b5b9594dd9c23476d5d",{"version":"6dbd83d8aa66b16389225ca9fbce387c03c5b8196a34e0f7bab97a2d18480f6c","signature":"73a68f6952a1d7ef44f439032cc7328d6cd34acdc57cf8045f6510d69ecbc08a"},{"version":"84f61f05753286befc63dc17eefe13ed7ab77877908a28e7d7066ff5983102e1","signature":"e08a900531dbdb55ba7f894df91b72a64b3b7390c019159b46035e92307fa9fe"},{"version":"d7dfba64b7350cb9501c544fe8ceba1b2455b42029d22b1a4fd02e94a6783525","impliedFormat":1},{"version":"483f4f8b19fc7eed40eb09fa0bef3757cce2ef26a23a9ed16cebfa20c732320b","signature":"a27e0707b924b0ab9494e0174fa7582aaa1704e5bf5c9b1ea8da40b944c9b3e3"},{"version":"f9822826f782b087ffb9c63ae488f2221e8cc9b43213f4e12fcc58f6ad513deb","signature":"d10bdb1011ec5334e8082aac922317e2de136d65fa777e7e36264d576d96d206"},{"version":"7981ecac7d742ae6e974bba0455e0a4bb6ef13ed2718f067e6fd19a821a0f4a7","signature":"d45c4084470849b5925d80c9328894e2fa9c5ff50567b6c88b754c0c2efe35d1"},"058ba4216abff36109da3535b96894aeae28ed488d8f7560125544c0445b9377","f836e3665ec5a892217ab488835c1f7e0a1d7717664c6ed4acf7dd41380b3f6c",{"version":"2ce6960a92287faa8db1a354c46acfe5b2f413735446b4a31178949b7a76ec80","signature":"4e9f7b1d8b2bd823899b17eb86c158d275b4a431c2b61bf22384d67ee2a947c3"},{"version":"d2dd7f5664c9544e3e0c6ea420501d7788aa08e9aa343e1b494343d5e59acafc","signature":"6f0bbd59319d2743cfe7c0d8662f2d3c61e5e71ee0a22e2ec4ee599cb1edad5c"},{"version":"584d05cbeb95e046ec4a2b09e5b6319516d023077f951786960517c5e14323d7","signature":"257dcfa3a17211c30f5465c462718d05ef93b5fa1a8dede18dd18644d2db9585"},{"version":"83958c64cf2b6bbbb07a41a54d8192e9f1154ea77536de5c1e2860449b324c90","signature":"484da7e31d644a9fa3474e4dcbb512c49d7fa36d8c66e784881f44312ef5b159"},{"version":"a0d37f7bb1216d24c3098c0389c517d251c0f3bc4952ff59e84c58f149e34117","signature":"4a0acc246b4db680771238bbf2ac463c6fd89fdb63e118bc90f62178ffcabcb8"},{"version":"80efad9069a3de8cc57a7ccadff8c885b0d523f93b8eff02747463a849575ead","signature":"05c3da4bf74c562be8ee6d7e6ca3815d609185f6220a37914b23c9cd1eaecef1"},{"version":"db78d48db56d85e7335d5f44c71e34c624a7aec4b133579c52e73e08610d6767","signature":"6d3e9eba92764290200af96fe981214b49cf6aecc5d1f2f07bd0e85a444fe9cd"},{"version":"4dbf867fef63c9e2da157f54c1aab87da23e47d3e7aa42d109a149a6f3b27191","signature":"cf6187ef6f3cd756a46fd2625bc3ab570f8a18b9fcb19758dbd8edf2ab33ef43"},{"version":"32b1bf8067bdd69ec60fb1b89e02542fcdf48137c954cd24347987abc75d9253","signature":"acff1cc908d36a8fd8bf87dfb1d1a77a648b30cc05492f42616b3526b9df3ee9"},{"version":"0749bc9e06a09965ba080243ade7b0429a1084442bd47c5fcc98fbfc282b5fc6","signature":"dba5e1f9665f2b884a6ecab153ca04c5a65bbfc24c334aa46e5ed01ac4545cf1"},{"version":"edddac680b535ff380e31173e38596d23675d18a02e878fba598fe38d1e33483","signature":"b741b233eb5fc90bcb185913b28a6352ea60ad06894c0723c87a2dda67fc07bb"},"855aca681fa70da14a638dfcde1d5d32fb07f965b6f902de56273f0963107802","1608a3c7c24e2b8f08895b3900e08c358c547510ead3e2dbe1ea207fc7b2616d",{"version":"e9723bcca0b3778d6b283a7ea5aad1543a88fc7e8135d93eee38572e77eead05","signature":"acaf510f21581df355507afa1144677354247b210d55ecfa6962fa0d737eb7aa"},"4e235218e67e3c029884dd1d8d527c78468a61ef0c80836636e5aa2815b4279d","a743fc9a6b3857721a7858364c606a6907e72c9d7e5eb4cd85dfc4d2984f085c","b3e982f365b9a2aa114eb18456524815db81373eaf2465c8234ce45b0d77a2db",{"version":"87e72027a486382ed75e9a0c65d155a4a1715311ae27c64c297ab9f83c9d7a63","signature":"96d4643a12c310191eb8f9786e23b01119cd9e47147874f36ee6579ffeb33b5a"},"5dc48f5f3317a23913d8d88670eba92bf5709017225f0205a5df702984e8b55c",{"version":"effcdc084e0149aaef939b53e00d705e88a65e2cecb6a26cb1f8e6a60356256e","signature":"df0e4873fe49e9666bbe89a3b8642f0cdcd888dedad7790ee13caaaabe3e29aa"},"983f91dcbafafd201611a7eb7412c4b0f788346eed3a714c28a077a81eccaf01",{"version":"9793761b7b35cdba65178e5009a8bdb51adac871d2b4c1b00fc0c41307a84502","signature":"1676cb0b45689b45b919099e0c012f3e491dabaa54a124d9dac9dbd8818645ae"},"3c1693189dbd35b7c4beb8b8f8af3026df466840dc4d0ce6083678c9aba0ce3a",{"version":"f0ddd7290f7cb65447dba0851c3bf5ee1bcbbd6f2a9bc80b1e2ec8cf703d4c16","signature":"27892e35900d71ec247fda0e9fbfa31fe65a548728a70c026a9ca0c77bf0cc75"},{"version":"1f8933fc4d16a669667708455892725875fba6ea94ab415b1c579e76b23865ca","signature":"d32fd4471300ac4b3ed12214aa7ff39ef553733ea0ddee8c1fe46f555842d2b2"},"5d5bb6dc61034b4671a6ff5a23e506c12c14ac5979f71bd12c5553f8096e8d61",{"version":"5bc7641943ffb91587d22889405c33209129e509f7f6cff4cdd627395c3c6690","signature":"3da83e1eca7015686fe30a435d79a0235852e7caf081a264db524a9a3d04f389"},{"version":"2004ba1fd4a7ee6dbffb3cf6790cf1d7c6e903330874ab97a2c45cfc364a71ea","signature":"2b51fd9d4735f434b95ba5e1443eb6b6d4ca6d4f9b2ae381860ea25cfe0ff9a3"},{"version":"b5ea1b88fbdf3a603e46987214f94227b41ddcf2be9d2aa3c2e77f43c007a2c7","signature":"84be61889b9aef6f4c23ac6fc8b40493abe31046f8f773933928a49b6d3a750f"},"0415760b0963802ca7429458ecc4e8e5dd1af12d34432c7f27de65604eba10e3",{"version":"23fcdd9fe5cec4384cee4a676abb92a2e3fadb82d0b0ad5cd3bb4c278ad77c85","signature":"65b84d35ac1de303cf7597643a6f3823f9314fe686f26cae5cee69a354d1fd45"},{"version":"b38d44699fcee65352d1091e35589109daa5740346a9f2f73c0b99a71cd3fcdb","signature":"34c2b9b80211b5a29523302d0916848ea96dbdfe3874449d7784deec101e0a2f"},"110bc06b62d8e96aecbf75dddca586d6885f7413b6ae729f1550ac012c985825","90d681ab9c839ce3a932587a78d92efed70c9a22299223ee96bd9192a4b1d682","b6981662ce567c8a5b79b7a3e34dcc0e01bc34eee885950f147e55d56d1a1fbb","e45fe0a539ca1e323f67438a40eec77a3191a0b26f27f95b49d0e3983eb372e0","a9438a811154bf7f071ce731ad647f778ade1165132a04b4d8e71cdbd644c1cd",{"version":"e33b78d531939737c1aeee219dd4d8701459ae9d0f4f28b9479f9042e0c9eca7","signature":"46e74b0147b5cb2fb79baa80af9a0c3c353cbbbc9f26d1f1bf41de5e25e01295"},{"version":"d50262aebcc2c9c9bfc2dd5535f4b6fea5cb72fefe9d86a4a04f417431429b9a","signature":"e189881e6632e61b3a618aa4cc5f2eb2baf7f561b3451c9bb93c94730e5c1cf8"},"5a028bc8cc79498b290a9ca7909c407abde3203f610d2e79708690641784aa7e","94a09fefd6024bb809ba7a71fbb1145f5401cf6debedb8be1f2fc1b764927fec",{"version":"773003e7c9c2eca0fac0aa5aea0afab776da16dc058960bb4d03190a6324488c","signature":"56936e183715c01af69a0dbf7aa06c3b216306c37b2fcb0318af04cf2cb2b252"},{"version":"923b2f0dc28afb09d57f5311216498e7a687b84959a6ba841e01657a2d256d2c","signature":"236977546854f19cb495fad14e19a624cbd9e919c3bc4e1840a4268d5fab0c9f"},{"version":"6ad3e10e7e23dc44358e16f7c29824023b809a2b9afdd7d2e0730ac84c182ac7","signature":"c2e5287247bfabcf3c25a77148d0022ccff4a8e3c453112b5343a3c931341fe2"},{"version":"6e264da0496126aa575f5e5f9468283a1b6fa71abbb6797976eeffe40169ac27","signature":"63cec187dc61104e7b4daea9eebc3c4d0dd4da00327030473e58c8bfa3ebef87"},{"version":"02996fe0ea7c79d35429bcb2ca3443c56bedaba453b50ddaca673bcb877286fd","signature":"5863859a6c71f48270e2697742da89e00ad384476d8a720b9c21b3ff44fa2eab"},"2f5c3c8c00032eae2e4b94c9f783264d90cc8b4c4471596e4164ab8e164b8bb3",{"version":"755de32723e5ff49bf7961cc8f158d8b162cf9fa5aaeaf1e14d6cb87dc9e9b4f","signature":"495a55b824c998b6a588db9cd03ca3a65fb61495548807a392c367b82964f2f7"},{"version":"da19701cea3f013b1e62e677450b048ca2f4c3ff8e7c6d1eacdd6269eff666b8","signature":"552ff451c492073126b9300c5602ee9f05ed2e6af3c5860bf343cbdcbeccddc2"},"acbfc1c551dbf2e90284957b5a3851f6b9ceb6c5894b330c316133c9c52d83e7",{"version":"44aa743b5d821c699a88aae7059b5dc5798ef8580d867151b6e3f9e560e391ff","signature":"b8e76f70a321dd557f360cd6b5ddc324f04b668e96727ca50dd8d781227418b7"},{"version":"fe93c474ab38ac02e30e3af073412b4f92b740152cf3a751fdaee8cbea982341","impliedFormat":1},{"version":"f5705d196b442afbdbd971b6e44bad96f4e32afb53cebfa2e5afe3140017bfc6","impliedFormat":1},{"version":"1e00b8bf9e3766c958218cd6144ffe08418286f89ff44ba5a2cc830c03dd22c7","impliedFormat":1},{"version":"b43b4a4c9d9d2ef5452f0439e735d09e95ae71788aa1c6c5a564c2b9128d255c","signature":"ff53dc24dd9f26eaca109b151c98025c3e47f72426866ab0bcd101e453dbc9dd"},{"version":"0c2a5e8e57f004cab6b15a36549162312dec7f04c28ec96155343c911af5f585","signature":"0c6f146bf5402327aa93d97c9e263e92bb63b4d87f2af155416cc7d0490a8224"},{"version":"e2051f3cda20e2cd81864802384b1058150085180f513e09a6115f9149dac450","signature":"d37676a4a785fdfca846f0072e1a73ed12a65474687006de46dde9f3e8955151"},{"version":"d3544b1daeb8e64aa8a9c0fc4ee74ef651c8cef67cff6ee2a1d9a32c99ed8048","signature":"81d4a86b11c11f29e32721433b59ad00d86ea0f3d29d5a62d004749643a7b359"},{"version":"6467beee18728a8596981186fbcf84a337a3ed0371843c6e2f71a2d714145948","signature":"c3cae5e74334bd48d834797d51e4f92c768fda9d2730da98258050f3a6270180"},"e669bff6c13476bc0b8df225ea0bea8e6f7ca42fe5ee8c6a388c129afb2dde6f","2bed8666717c7098829d24f99cbff26ccddd96494bad4e74693856d7e7b07bc2","d458eb8260e5c5e6bb102b5fb9e1e330c5b7c25da4eb8c881a850aa99dbdb09f",{"version":"67e476eac231deb65297ccb55125cb2d369da9754c8563e8efaf3c6f401e2df8","signature":"533d3b90e68fb6fa386294d307e926424be69155fea75a464f7d4cdee2fba5a4"},{"version":"87d9e9fbc18d985156978d3e83bfc538c61e76362f4efd0e0956005c9f9bbede","signature":"6f3f957c96636ca2de4458705c17b3a0de56bd955d5c1d07823a1d1e7596a87c"},"0ef2df2c275c5d16191fc95ee0285917bb5be384068ea2e16a1b38a0809de47a","2b44e7c5ce8c7c4e2899318c7342c99239a4af2e6dda333ed65ddfddbe41123d","f9d5e1672848926188f4987f39f30b6de4c6acac8ae012985f940513d961e506",{"version":"2040cdff27cd1ed771e0ebbd15abcd73d31f2f1e4be6664bd6816fffd2a87476","signature":"1a6115819fa1e86a8fdfdef41f15eb65ba315a1ab6079a7db3f018bf72f4c0c2"},{"version":"bbd16f077778bb123cc86a16384751f53bfd22cee5cfdf6715862bdcd711cf12","signature":"b9f1bf3713fc43fd9e929b746540e6d606807cc121fe59d4454efdf3b009c18a"},"add05973a6ae359411b8d63179b9f0c2825422541098b73690b5a0258be1b448","d1986184a09a52db8228cb2bb2a61a8c05c9354e5b93cec8e2628d8579c892d7",{"version":"4e2bcf03609885297fc50894bbc98bba5fd87314f4928607ba3cce55ba0f758c","affectsGlobalScope":true},"6b7c5de2c74e5a7583c8618ecc559e57765acc1fcc46faa494d6caaeb1c2cd25",{"version":"151ff381ef9ff8da2da9b9663ebf657eac35c4c9a19183420c05728f31a6761d","impliedFormat":1},{"version":"f3d8c757e148ad968f0d98697987db363070abada5f503da3c06aefd9d4248c1","impliedFormat":1},{"version":"96d14f21b7652903852eef49379d04dbda28c16ed36468f8c9fa08f7c14c9538","impliedFormat":1}],"root":[[510,513],[516,525],[573,594],[596,651],[655,673]],"options":{"allowJs":true,"esModuleInterop":true,"jsx":4,"module":99,"skipLibCheck":true,"strict":true,"target":4},"referencedMap":[[671,1],[672,2],[673,3],[510,2],[670,4],[511,5],[512,6],[252,2],[528,7],[532,8],[537,9],[541,10],[538,10],[539,11],[540,12],[531,11],[546,13],[529,7],[536,14],[547,7],[533,10],[548,13],[534,10],[550,15],[551,16],[549,10],[545,17],[552,18],[554,19],[555,20],[556,7],[557,21],[543,22],[535,10],[530,7],[558,11],[559,23],[544,11],[560,11],[561,21],[562,10],[563,11],[564,7],[565,11],[566,23],[567,24],[569,25],[568,10],[570,26],[571,16],[553,10],[542,2],[674,2],[675,2],[676,2],[140,27],[141,27],[142,28],[97,29],[143,30],[144,31],[145,32],[92,2],[95,33],[93,2],[94,2],[146,34],[147,35],[148,36],[149,37],[150,38],[151,39],[152,39],[153,40],[154,41],[155,42],[156,43],[98,2],[96,2],[157,44],[158,45],[159,46],[191,47],[160,48],[161,49],[162,50],[163,51],[164,52],[165,53],[166,54],[167,55],[168,56],[169,57],[170,57],[171,58],[172,2],[173,59],[175,60],[174,61],[176,62],[177,63],[178,64],[179,65],[180,66],[181,67],[182,68],[183,69],[184,70],[185,71],[186,72],[187,73],[188,74],[99,2],[100,2],[101,2],[139,75],[189,76],[190,77],[195,78],[412,7],[196,79],[194,80],[414,81],[413,82],[192,83],[410,2],[193,84],[83,2],[85,85],[409,7],[269,7],[527,86],[526,87],[514,2],[84,2],[595,7],[459,88],[464,1],[454,89],[216,90],[256,91],[438,92],[251,93],[233,2],[408,2],[214,2],[427,94],[282,95],[215,2],[336,96],[259,97],[260,98],[407,99],[424,100],[318,101],[432,102],[433,103],[431,104],[430,2],[428,105],[258,106],[217,107],[361,2],[362,108],[288,109],[218,110],[289,109],[284,109],[205,109],[254,111],[253,2],[437,112],[449,2],[241,2],[383,113],[384,114],[378,7],[486,2],[386,2],[387,115],[379,116],[491,117],[490,118],[485,2],[303,2],[423,119],[422,2],[484,120],[380,7],[312,121],[308,122],[313,123],[311,2],[310,124],[309,2],[487,2],[483,2],[489,125],[488,2],[307,122],[478,126],[481,127],[297,128],[296,129],[295,130],[494,7],[294,131],[276,2],[497,2],[653,132],[652,2],[500,2],[499,7],[501,133],[198,2],[434,134],[435,135],[436,136],[211,2],[244,2],[210,137],[197,2],[399,7],[203,138],[398,139],[397,140],[388,2],[389,2],[396,2],[391,2],[394,141],[390,2],[392,142],[395,143],[393,142],[213,2],[208,2],[209,109],[264,2],[270,144],[271,145],[268,146],[266,147],[267,148],[262,2],[405,115],[291,115],[458,149],[465,150],[469,151],[441,152],[440,2],[279,2],[502,153],[453,154],[381,155],[382,156],[376,157],[367,2],[404,158],[443,7],[368,159],[406,160],[401,161],[400,2],[402,2],[373,2],[360,162],[442,163],[445,164],[370,165],[374,166],[365,167],[419,168],[452,169],[322,170],[337,171],[206,172],[451,173],[202,174],[272,175],[263,2],[273,176],[349,177],[261,2],[348,178],[91,2],[342,179],[243,2],[363,180],[338,2],[207,2],[237,2],[346,181],[212,2],[274,182],[372,183],[439,184],[371,2],[345,2],[265,2],[351,185],[352,186],[429,2],[354,187],[356,188],[355,189],[246,2],[344,172],[358,190],[321,191],[343,192],[350,193],[221,2],[225,2],[224,2],[223,2],[228,2],[222,2],[231,2],[230,2],[227,2],[226,2],[229,2],[232,194],[220,2],[330,195],[329,2],[334,196],[331,197],[333,198],[335,196],[332,197],[242,199],[292,200],[448,201],[503,2],[473,202],[475,203],[369,204],[474,205],[446,163],[385,163],[219,2],[323,206],[238,207],[239,208],[240,209],[236,210],[418,210],[286,210],[324,211],[287,211],[235,212],[234,2],[328,213],[327,214],[326,215],[325,216],[447,217],[417,218],[416,219],[377,220],[411,221],[415,222],[426,223],[425,224],[421,225],[320,226],[317,227],[319,228],[316,229],[357,230],[347,2],[463,2],[359,231],[420,2],[275,232],[366,134],[364,233],[277,234],[280,235],[498,2],[278,236],[281,236],[461,2],[460,2],[462,2],[496,2],[283,237],[444,2],[314,238],[306,7],[257,2],[201,239],[290,2],[467,7],[200,2],[477,240],[305,7],[471,115],[304,241],[456,242],[302,240],[204,2],[479,243],[300,7],[301,7],[293,2],[199,2],[299,244],[298,245],[245,246],[375,56],[285,56],[353,2],[340,247],[339,2],[403,122],[315,7],[450,137],[457,248],[86,7],[89,249],[90,250],[87,7],[88,2],[255,251],[250,252],[249,2],[248,253],[247,2],[455,254],[466,255],[468,256],[470,257],[654,258],[472,259],[476,260],[509,261],[480,261],[508,262],[482,263],[492,264],[493,265],[495,266],[504,267],[507,137],[506,2],[505,268],[572,269],[341,270],[515,2],[81,2],[82,2],[13,2],[14,2],[16,2],[15,2],[2,2],[17,2],[18,2],[19,2],[20,2],[21,2],[22,2],[23,2],[24,2],[3,2],[25,2],[26,2],[4,2],[27,2],[31,2],[28,2],[29,2],[30,2],[32,2],[33,2],[34,2],[5,2],[35,2],[36,2],[37,2],[38,2],[6,2],[42,2],[39,2],[40,2],[41,2],[43,2],[7,2],[44,2],[49,2],[50,2],[45,2],[46,2],[47,2],[48,2],[8,2],[54,2],[51,2],[52,2],[53,2],[55,2],[9,2],[56,2],[57,2],[58,2],[60,2],[59,2],[61,2],[62,2],[10,2],[63,2],[64,2],[65,2],[11,2],[66,2],[67,2],[68,2],[69,2],[70,2],[1,2],[71,2],[72,2],[12,2],[76,2],[74,2],[79,2],[78,2],[73,2],[77,2],[75,2],[80,2],[117,271],[127,272],[116,271],[137,273],[108,274],[107,275],[136,268],[130,276],[135,277],[110,278],[124,279],[109,280],[133,281],[105,282],[104,268],[134,283],[106,284],[111,285],[112,2],[115,285],[102,2],[138,286],[128,287],[119,288],[120,289],[122,290],[118,291],[121,292],[131,268],[113,293],[114,294],[123,295],[103,296],[126,287],[125,285],[129,2],[132,297],[661,298],[662,299],[663,300],[656,301],[660,302],[665,303],[666,304],[667,305],[525,306],[574,307],[524,308],[575,309],[576,310],[582,311],[522,312],[519,310],[513,306],[583,313],[518,314],[517,314],[586,315],[590,306],[588,316],[589,310],[591,317],[587,318],[584,306],[592,319],[585,320],[596,321],[597,322],[598,310],[599,323],[594,324],[600,325],[619,326],[623,327],[620,310],[622,328],[621,329],[618,330],[659,331],[655,332],[657,333],[634,334],[624,306],[635,335],[629,306],[628,336],[630,337],[631,310],[627,336],[633,338],[626,339],[625,340],[658,341],[632,342],[581,343],[611,344],[612,345],[605,346],[601,306],[607,306],[609,347],[604,115],[617,348],[608,310],[615,349],[616,350],[602,346],[606,346],[610,310],[603,346],[613,351],[641,352],[644,353],[640,354],[638,310],[650,355],[642,356],[639,357],[646,321],[648,306],[645,310],[647,358],[649,359],[636,360],[637,360],[593,361],[573,361],[668,341],[614,341],[523,341],[669,362],[643,363],[664,361],[577,358],[578,364],[520,306],[651,306],[580,306],[521,306],[579,306],[516,365]],"affectedFilesPendingEmit":[673,670,512,661,662,663,656,660,665,666,667,525,574,524,575,576,582,522,519,513,583,518,517,586,590,588,589,591,587,584,592,585,596,597,598,599,594,600,619,623,620,622,621,618,659,655,657,634,624,635,629,628,630,631,627,633,626,625,658,632,581,611,612,605,601,607,609,604,617,608,615,616,602,606,610,603,613,641,644,640,638,650,642,639,646,648,645,647,649,636,637,593,573,668,614,523,669,643,664,577,578,520,651,580,521,579,516],"version":"5.9.3"} \ No newline at end of file diff --git a/crates/stemedb-admin/src/client.rs b/crates/stemedb-admin/src/client.rs index 34a6300..fbb0a43 100644 --- a/crates/stemedb-admin/src/client.rs +++ b/crates/stemedb-admin/src/client.rs @@ -95,10 +95,8 @@ impl AdminClient { } // Gateway returns different format than /admin/ranges, so convert it - let shard_response: ShardInfoResponse = response - .json() - .await - .context("Failed to parse shard info response")?; + let shard_response: ShardInfoResponse = + response.json().await.context("Failed to parse shard info response")?; Ok(shard_response.into()) } @@ -125,10 +123,8 @@ impl AdminClient { } // Gateway returns {"ranges": [...]} so we need to unwrap it - let wrapper: RangesWrapper = response - .json() - .await - .context("Failed to parse ranges response")?; + let wrapper: RangesWrapper = + response.json().await.context("Failed to parse ranges response")?; Ok(wrapper.ranges) } diff --git a/crates/stemedb-api/src/dto/create.rs b/crates/stemedb-api/src/dto/create.rs index 7dccfb2..a696d59 100644 --- a/crates/stemedb-api/src/dto/create.rs +++ b/crates/stemedb-api/src/dto/create.rs @@ -132,6 +132,14 @@ pub struct CreateAssertionRequest { #[serde(skip_serializing_if = "Option::is_none")] pub source_metadata: Option, + /// Free-text narrative explaining methodology, limitations, bias, and caveats. + /// + /// Makes the assertion self-contained: pick it up, read it, understand the + /// full claim without dereferencing anything. Max 64 KB. + #[serde(skip_serializing_if = "Option::is_none")] + #[schema(example = "Based on STEP 1 trial (n=1961). Limitation: 68-week duration only.")] + pub narrative: Option, + /// Unix timestamp when the assertion was created. /// If not provided, defaults to the current time. /// **Important for v2 signatures:** Provide this field to preserve the diff --git a/crates/stemedb-api/src/dto/mod.rs b/crates/stemedb-api/src/dto/mod.rs index c8c7f94..d319d6e 100644 --- a/crates/stemedb-api/src/dto/mod.rs +++ b/crates/stemedb-api/src/dto/mod.rs @@ -29,6 +29,7 @@ pub mod responses; pub mod skeptic; pub mod source_registry; pub mod stemedb_claims; +pub mod subjects; // Re-export all public types for backward compatibility // This allows existing code to use `use crate::dto::*;` without changes @@ -51,7 +52,7 @@ pub use query_params::{FeedParams, QueryParams}; // From responses module pub use responses::{ AssertionResponse, ChangeEntryDto, ErrorResponse, HealthResponse, LayeredQueryResponse, - ProvenanceResponse, QueryResponse, SourceWarningDto, TierResolutionDto, + ProvenanceResponse, QueryResponse, RebuildIndexesResponse, SourceWarningDto, TierResolutionDto, }; // From audit module @@ -131,4 +132,9 @@ pub use aphoria::{ }; // From stemedb_claims module -pub use stemedb_claims::{AuthoredClaimDto, AuthoredValueDto, CreateClaimRequest, CreateClaimResponse}; +pub use stemedb_claims::{ + AuthoredClaimDto, AuthoredValueDto, CreateClaimRequest, CreateClaimResponse, +}; + +// From subjects module +pub use subjects::{ListPredicatesResponse, ListSubjectsParams, ListSubjectsResponse}; diff --git a/crates/stemedb-api/src/dto/responses.rs b/crates/stemedb-api/src/dto/responses.rs index 2d128d6..ffe20d3 100644 --- a/crates/stemedb-api/src/dto/responses.rs +++ b/crates/stemedb-api/src/dto/responses.rs @@ -88,6 +88,10 @@ pub struct AssertionResponse { #[serde(skip_serializing_if = "Option::is_none")] pub source_metadata: Option, + /// Free-text narrative explaining methodology, limitations, bias, and caveats. + #[serde(skip_serializing_if = "Option::is_none")] + pub narrative: Option, + /// Warning if this assertion cites a quarantined or deprecated source. /// /// Present when the assertion's source has a non-Active status in the @@ -217,6 +221,30 @@ pub struct TierResolutionDto { pub resolution_confidence: f32, } +/// Response from the admin rebuild-indexes endpoint. +/// +/// Reports how many assertion indexes were rebuilt, how many were +/// skipped (e.g., deserialization failures), and how long the +/// operation took. +#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)] +pub struct RebuildIndexesResponse { + /// Number of assertions whose indexes were rebuilt. + pub rebuilt_count: u64, + + /// Number of keys that were skipped (deserialization failures). + pub skipped_count: u64, + + /// Wall-clock time for the operation in milliseconds. + pub elapsed_ms: u64, + + /// Human-readable status message. + pub status: String, + + /// First error encountered (for diagnostics). Absent when all succeed. + #[serde(skip_serializing_if = "Option::is_none")] + pub first_error: Option, +} + /// Response from a LayeredConsensus query. /// /// Provides per-tier resolution results plus an overall winner. diff --git a/crates/stemedb-api/src/dto/source_registry.rs b/crates/stemedb-api/src/dto/source_registry.rs index 6b14af5..06dcd42 100644 --- a/crates/stemedb-api/src/dto/source_registry.rs +++ b/crates/stemedb-api/src/dto/source_registry.rs @@ -31,6 +31,10 @@ pub struct RegisterSourceRequest { /// Optional curator notes about the source. #[serde(skip_serializing_if = "Option::is_none")] pub notes: Option, + + /// Optional full-text content of the source document. + #[serde(skip_serializing_if = "Option::is_none")] + pub content: Option, } /// Response from registering a source. @@ -78,6 +82,10 @@ pub struct SourceRecordDto { /// Optional curator notes. #[serde(skip_serializing_if = "Option::is_none")] pub notes: Option, + + /// Optional full-text content of the source document. + #[serde(skip_serializing_if = "Option::is_none")] + pub content: Option, } impl From for SourceRecordDto { @@ -92,6 +100,7 @@ impl From for SourceRecordDto { created_at: record.created_at, updated_at: record.updated_at, notes: record.notes.clone(), + content: record.content.clone(), } } } diff --git a/crates/stemedb-api/src/dto/subjects.rs b/crates/stemedb-api/src/dto/subjects.rs new file mode 100644 index 0000000..ceeb995 --- /dev/null +++ b/crates/stemedb-api/src/dto/subjects.rs @@ -0,0 +1,34 @@ +//! DTOs for subject and predicate discovery endpoints. + +use serde::{Deserialize, Serialize}; +use utoipa::{IntoParams, ToSchema}; + +/// Query parameters for `GET /v1/subjects`. +#[derive(Debug, Deserialize, IntoParams)] +pub struct ListSubjectsParams { + /// Optional prefix filter for subject names. + #[param(example = "sema")] + pub q: Option, + + /// Maximum number of subjects to return (default 100, max 1000). + #[param(example = 100)] + pub limit: Option, +} + +/// Response for `GET /v1/subjects`. +#[derive(Debug, Serialize, ToSchema)] +pub struct ListSubjectsResponse { + /// List of matching subject strings. + pub subjects: Vec, + /// Total number of subjects matching the filter (before limit). + pub total_count: usize, +} + +/// Response for `GET /v1/subjects/:subject/predicates`. +#[derive(Debug, Serialize, ToSchema)] +pub struct ListPredicatesResponse { + /// The subject these predicates belong to. + pub subject: String, + /// List of predicate strings for this subject. + pub predicates: Vec, +} diff --git a/crates/stemedb-api/src/handlers/admin.rs b/crates/stemedb-api/src/handlers/admin.rs index c205a11..be9688a 100644 --- a/crates/stemedb-api/src/handlers/admin.rs +++ b/crates/stemedb-api/src/handlers/admin.rs @@ -1,14 +1,14 @@ //! Admin handlers for maintenance operations. use axum::{extract::State, Json}; -use tracing::instrument; +use tracing::{info, instrument, warn}; use crate::{ - dto::{DecayTrustRanksRequest, DecayTrustRanksResponse}, + dto::{DecayTrustRanksRequest, DecayTrustRanksResponse, RebuildIndexesResponse}, error::Result, state::AppState, }; -use stemedb_storage::{GenericTrustRankStore, TrustRankStore}; +use stemedb_storage::{GenericIndexStore, GenericTrustRankStore, IndexStore, KVStore, TrustRankStore, key_codec}; /// Default half-life for trust rank decay (30 days in seconds). const DEFAULT_HALF_LIFE_SECONDS: u64 = 30 * 24 * 60 * 60; @@ -68,3 +68,215 @@ pub async fn decay_trust_ranks( status: "Decay operation completed".to_string(), })) } + +/// Rebuild secondary indexes (Redb) from assertion data (Fjall). +/// +/// This is a repair operation for when Redb indexes are missing or stale +/// while Fjall assertion data is intact. It scans all assertion data from +/// Fjall and reconstructs the S:, SP:, SUBJECTS:, HASH_SUBJECT:, and SRC: +/// indexes in Redb, then corrects the META:assertion_count. +/// +/// This endpoint is idempotent — running it multiple times is safe because +/// the index store uses append-with-dedup semantics. +#[utoipa::path( + post, + path = "/v1/admin/rebuild-indexes", + responses( + (status = 200, description = "Index rebuild completed", body = RebuildIndexesResponse), + (status = 500, description = "Internal server error", body = crate::dto::ErrorResponse), + ), + tag = "admin" +)] +#[instrument(skip(state))] +pub async fn rebuild_indexes( + State(state): State, +) -> Result> { + let start = std::time::Instant::now(); + metrics::counter!("stemedb_http_requests_total", "method" => "POST", "path" => "/v1/admin/rebuild-indexes").increment(1); + + info!("Starting index rebuild: scanning Fjall for all assertions"); + + // Capture current time once for FEED index fallback (timestamp:0 assertions) + let now = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map(|d| d.as_secs()) + .unwrap_or(0); + + // Scan all assertion key-value pairs from Fjall + let assertion_kvs = state.store.scan_fjall_assertions().await?; + let total_keys = assertion_kvs.len(); + info!(total_keys, "Found assertion keys in Fjall"); + + // Create an IndexStore backed by the same HybridStore + let index_store = GenericIndexStore::new(state.store.clone()); + + let mut rebuilt_count: u64 = 0; + let mut skipped_count: u64 = 0; + let mut first_error: Option = None; + + for (key, value) in &assertion_kvs { + // Extract subject from key + let subject = match key_codec::extract_subject(key) { + Some(s) => s.to_string(), + None => { + let msg = format!( + "extract_subject failed: key_len={}, first_bytes={:?}", + key.len(), + &key[..key.len().min(40)] + ); + warn!("{}", msg); + if first_error.is_none() { + first_error = Some(msg); + } + skipped_count += 1; + continue; + } + }; + + // Extract hash_hex from tag (tag is "H:{hash_hex}") + let tag = key_codec::extract_tag(key); + let hash_hex = match tag.strip_prefix(b"H:") { + Some(hex_bytes) => match std::str::from_utf8(hex_bytes) { + Ok(s) => s.to_string(), + Err(e) => { + let msg = format!("hash_hex UTF-8 error for subject={subject}: {e}"); + warn!("{}", msg); + if first_error.is_none() { + first_error = Some(msg); + } + skipped_count += 1; + continue; + } + }, + None => { + let msg = format!( + "tag strip_prefix H: failed for subject={subject}: tag={:?}", + String::from_utf8_lossy(tag) + ); + warn!("{}", msg); + if first_error.is_none() { + first_error = Some(msg); + } + skipped_count += 1; + continue; + } + }; + + // Deserialize the assertion to get predicate and source_hash. + // Uses compat deserialization to handle legacy data (pre-narrative schema). + let assertion: stemedb_core::types::Assertion = + match stemedb_core::serde::deserialize_assertion_compat(value) { + Ok(a) => a, + Err(e) => { + let msg = format!( + "deserialize failed for subject={subject} hash={hash_hex}: {e} (value_len={})", + value.len() + ); + warn!("{}", msg); + if first_error.is_none() { + first_error = Some(msg); + } + skipped_count += 1; + continue; + } + }; + + // Decode assertion hash from hex + let hash_bytes: [u8; 32] = match hex::decode(&hash_hex) { + Ok(bytes) if bytes.len() == 32 => { + let mut arr = [0u8; 32]; + arr.copy_from_slice(&bytes); + arr + } + Ok(bytes) => { + let msg = format!( + "hash decode wrong length for subject={subject} hash={hash_hex}: got {} bytes", + bytes.len() + ); + warn!("{}", msg); + if first_error.is_none() { + first_error = Some(msg); + } + skipped_count += 1; + continue; + } + Err(e) => { + let msg = format!( + "hex decode failed for subject={subject} hash={hash_hex}: {e}" + ); + warn!("{}", msg); + if first_error.is_none() { + first_error = Some(msg); + } + skipped_count += 1; + continue; + } + }; + + // Rebuild S: and SP: indexes (includes SUBJECTS: discovery index) + if let Err(e) = + index_store.add_to_indexes(&subject, &assertion.predicate, &hash_bytes).await + { + warn!(%subject, %hash_hex, error = %e, "Failed to add to indexes"); + skipped_count += 1; + continue; + } + + // Rebuild HASH_SUBJECT: reverse index + let hs_key = key_codec::hash_subject_key(&hash_hex); + if let Err(e) = state.store.put(&hs_key, subject.as_bytes()).await { + warn!(%subject, %hash_hex, error = %e, "Failed to write hash_subject index"); + } + + // Rebuild SRC: source index + if let Err(e) = + index_store.add_to_source_index(&assertion.source_hash, &hash_bytes).await + { + warn!(%subject, %hash_hex, error = %e, "Failed to add to source index"); + } + + // Rebuild FEED index: use assertion.timestamp as best-available proxy + // for ingestion time. Fall back to current time for timestamp:0 assertions. + let feed_ts = if assertion.timestamp > 0 { assertion.timestamp } else { now }; + let feed_idx_key = key_codec::feed_key(feed_ts, &hash_hex); + if let Err(e) = state.store.put(&feed_idx_key, subject.as_bytes()).await { + warn!(%subject, %hash_hex, error = %e, "Failed to write feed index"); + } + + rebuilt_count += 1; + } + + // Correct the assertion count: total = rebuilt + skipped (both are real assertions). + // The count key stores a u64 in little-endian format. + let total_assertions = rebuilt_count + skipped_count; + let count_key = key_codec::assertion_count_key(); + let count_bytes = total_assertions.to_le_bytes(); + state.store.put(&count_key, &count_bytes).await?; + + let elapsed_ms = start.elapsed().as_millis() as u64; + + info!( + rebuilt_count, + skipped_count, + elapsed_ms, + "Index rebuild complete" + ); + + metrics::histogram!("stemedb_http_request_duration_seconds", + "method" => "POST", + "path" => "/v1/admin/rebuild-indexes", + "status" => "200" + ) + .record(start.elapsed().as_secs_f64()); + + Ok(Json(RebuildIndexesResponse { + rebuilt_count, + skipped_count, + elapsed_ms, + status: format!( + "Rebuilt indexes for {} assertions ({} skipped) in {}ms", + rebuilt_count, skipped_count, elapsed_ms + ), + first_error, + })) +} diff --git a/crates/stemedb-api/src/handlers/aphoria_helpers.rs b/crates/stemedb-api/src/handlers/aphoria_helpers.rs index 5cfb76d..b288ee1 100644 --- a/crates/stemedb-api/src/handlers/aphoria_helpers.rs +++ b/crates/stemedb-api/src/handlers/aphoria_helpers.rs @@ -143,6 +143,7 @@ pub fn observation_dto_to_assertion( visual_hash: None, epoch: None, source_metadata, + narrative: None, lifecycle: LifecycleStage::Approved, signatures, confidence: dto.confidence, diff --git a/crates/stemedb-api/src/handlers/assert.rs b/crates/stemedb-api/src/handlers/assert.rs index a4abd52..f2b7d3f 100644 --- a/crates/stemedb-api/src/handlers/assert.rs +++ b/crates/stemedb-api/src/handlers/assert.rs @@ -10,6 +10,7 @@ use crate::{ state::AppState, }; +use stemedb_core::limits::MAX_NARRATIVE_LEN; use stemedb_core::types::{ Assertion, HlcTimestamp, LifecycleStage, ObjectValue, SignatureEntry, SourceClass, }; @@ -44,6 +45,18 @@ pub async fn create_assertion( // Convert DTO to internal Assertion type let assertion = dto_to_assertion(req)?; + // Verify Ed25519 signatures BEFORE writing to WAL. + // This prevents poison records that would permanently block the IngestWorker. + stemedb_core::signing::verify_assertion_signatures(&assertion).map_err(|e| { + metrics::counter!("stemedb_assertions_rejected_total", "reason" => "invalid_signature") + .increment(1); + ApiError::InvalidRequest(format!("Signature verification failed: {}", e)) + })?; + + // Validate subject does not contain null byte separator (mirrors IngestWorker check) + stemedb_storage::key_codec::validate_subject(&assertion.subject) + .map_err(|e| ApiError::InvalidRequest(format!("Invalid subject: {}", e)))?; + // Serialize to WAL format (includes record type header) let payload = serialize_assertion(&assertion) .map_err(|e| ApiError::Serialization(format!("Failed to serialize assertion: {}", e)))?; @@ -93,14 +106,33 @@ fn dto_to_assertion(req: CreateAssertionRequest) -> Result { return Err(ApiError::InvalidRequest("At least one signature is required".to_string())); } + // Validate narrative length + if let Some(ref narrative) = req.narrative { + if narrative.len() > MAX_NARRATIVE_LEN { + return Err(ApiError::InvalidRequest(format!( + "narrative exceeds {} bytes (got {})", + MAX_NARRATIVE_LEN, + narrative.len() + ))); + } + } + // Use provided timestamp or generate a new one // IMPORTANT: For v2 signatures, the timestamp must match what was signed - let timestamp = req.timestamp.unwrap_or_else(|| { - std::time::SystemTime::now() + let timestamp = match req.timestamp { + Some(0) => { + return Err(ApiError::InvalidRequest( + "timestamp must be a valid Unix epoch (> 0). \ + Omit the field to use server time." + .to_string(), + )); + } + Some(t) => t, + None => std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .map(|d| d.as_secs()) - .unwrap_or(0) - }); + .unwrap_or(0), + }; // Use provided HLC timestamp or default // IMPORTANT: For v2 signatures, the HLC timestamp must match what was signed @@ -122,6 +154,7 @@ fn dto_to_assertion(req: CreateAssertionRequest) -> Result { visual_hash, epoch, source_metadata: req.source_metadata.map(|s| s.into_bytes()), + narrative: req.narrative, lifecycle: req.lifecycle.map(Into::into).unwrap_or(LifecycleStage::Proposed), signatures, confidence: req.confidence, diff --git a/crates/stemedb-api/src/handlers/feed.rs b/crates/stemedb-api/src/handlers/feed.rs index 97b17d1..2650b75 100644 --- a/crates/stemedb-api/src/handlers/feed.rs +++ b/crates/stemedb-api/src/handlers/feed.rs @@ -1,4 +1,7 @@ //! Handler for the `/v1/feed` endpoint (newest-first assertion browsing). +//! +//! Uses a dedicated FEED index (`\x00FEED:{inverted_ts}:{hash_hex}`) for +//! O(page_size) reads instead of loading all assertions into memory. use axum::{extract::State, Json}; use tracing::{instrument, warn}; @@ -10,15 +13,16 @@ use crate::{ state::AppState, }; -use stemedb_query::Query; +use stemedb_core::serde::deserialize_assertion_compat; +use stemedb_storage::{KVStore, key_codec}; use super::query::assertion_to_dto_with_warning; /// Browse all assertions in newest-first order with pagination. /// -/// Returns assertions sorted by timestamp descending, useful for -/// "what was just written?" dashboards and dev workflows. No lens -/// resolution is applied — this is a raw chronological feed. +/// Returns assertions ordered by ingestion time descending (when the system +/// received each assertion), useful for "what was just written?" dashboards +/// and dev workflows. No lens resolution is applied — this is a raw feed. /// /// # Pagination /// @@ -45,36 +49,57 @@ pub async fn feed( metrics::counter!("stemedb_queries_total", "endpoint" => "feed").increment(1); let query_start = std::time::Instant::now(); - // Fetch all assertions (no subject filter) - let query = Query::builder().limit(usize::MAX).build(); - let query_engine = state.query_engine(); - let result = query_engine.execute(&query).await?; + // Scan the FEED index — keys are in newest-first order (inverted timestamp). + let feed_prefix = key_codec::feed_scan_prefix(); + let entries = state.store.scan_prefix(&feed_prefix).await?; - let mut assertions = result.assertions; - - if assertions.len() > 10_000 { - warn!( - count = assertions.len(), - "Feed scanning large assertion set; consider adding index-backed pagination" - ); - } - - // Sort by timestamp descending (newest first) - assertions.sort_unstable_by(|a, b| b.timestamp.cmp(&a.timestamp)); - - let total_count = assertions.len(); + let total_count = entries.len(); let limit = params.clamped_limit(); let offset = params.offset; let has_more = offset + limit < total_count; - // Apply offset + limit pagination - let page: Vec<_> = assertions.into_iter().skip(offset).take(limit).collect(); + // Paginate the index entries (cheap — no assertion data loaded yet) + let page_entries: Vec<_> = entries.into_iter().skip(offset).take(limit).collect(); - // Convert to DTOs (no source enrichment for speed) - let assertion_responses = page - .into_iter() - .map(|a| assertion_to_dto_with_warning(a, None)) - .collect::>>()?; + // Fetch actual assertion data only for the current page + let mut assertion_responses = Vec::with_capacity(page_entries.len()); + for (key, value) in &page_entries { + let hash_hex = match extract_hash_hex_from_feed_key(key) { + Some(h) => h, + None => { + warn!(key_len = key.len(), "Malformed FEED index key, skipping"); + continue; + } + }; + let subject = match std::str::from_utf8(value) { + Ok(s) => s, + Err(e) => { + warn!(error = %e, "Invalid UTF-8 in FEED index value, skipping"); + continue; + } + }; + + let assertion_data_key = key_codec::assertion_key(subject, hash_hex); + let data = match state.store.get(&assertion_data_key).await? { + Some(d) => d, + None => { + warn!(%hash_hex, %subject, "FEED index references missing assertion data, skipping"); + continue; + } + }; + + match deserialize_assertion_compat(&data) { + Ok(a) => match assertion_to_dto_with_warning(a, None) { + Ok(dto) => assertion_responses.push(dto), + Err(e) => { + warn!(%hash_hex, error = %e, "Failed to convert assertion to DTO, skipping"); + } + }, + Err(e) => { + warn!(%hash_hex, error = %e, "Failed to deserialize assertion, skipping"); + } + } + } metrics::histogram!("stemedb_query_latency_seconds", "endpoint" => "feed") .record(query_start.elapsed().as_secs_f64()); @@ -88,3 +113,16 @@ pub async fn feed( changes_since: None, })) } + +/// Extract the hash_hex portion from a FEED index key. +/// +/// Key format: `\x00FEED:{16 hex chars (inverted ts)}:{64 hex chars (hash)}` +/// Prefix `\x00FEED:` = 6 bytes, inverted_ts = 16 bytes, `:` = 1 byte → 23 bytes offset. +fn extract_hash_hex_from_feed_key(key: &[u8]) -> Option<&str> { + // \x00FEED: = 6 bytes, inverted_ts = 16 hex chars, : = 1 byte + const HASH_OFFSET: usize = 6 + 16 + 1; // 23 + if key.len() <= HASH_OFFSET { + return None; + } + std::str::from_utf8(&key[HASH_OFFSET..]).ok() +} diff --git a/crates/stemedb-api/src/handlers/layered.rs b/crates/stemedb-api/src/handlers/layered.rs index fcc5165..55d7fcd 100644 --- a/crates/stemedb-api/src/handlers/layered.rs +++ b/crates/stemedb-api/src/handlers/layered.rs @@ -178,6 +178,7 @@ fn assertion_to_dto(assertion: stemedb_core::types::Assertion) -> Result, +} + +/// A WAL record that was permanently skipped by the IngestWorker. +#[derive(Debug, Serialize, Deserialize, ToSchema)] +pub struct RejectedRecordDto { + /// WAL offset where the record was found. + pub offset: u64, + /// The record type (Assertion, Vote, Epoch). + pub record_type: String, + /// Why the record was rejected. + pub reason: String, + /// When the record was skipped (Unix timestamp). + pub timestamp: u64, +} + +/// Response listing rejected WAL records. +#[derive(Debug, Serialize, Deserialize, ToSchema)] +pub struct RejectedRecordsResponse { + /// List of rejected records. + pub rejected: Vec, + /// Total number of rejected records found. + pub count: usize, +} + +/// GET /v1/admin/rejected +/// +/// List WAL records that were permanently rejected by the IngestWorker. +#[utoipa::path( + get, + path = "/v1/admin/rejected", + params( + ("limit" = Option, Query, description = "Maximum records to return (default: 100)") + ), + responses( + (status = 200, description = "Rejected records listed", body = RejectedRecordsResponse), + (status = 500, description = "Internal server error", body = ErrorResponse) + ), + tag = "admin" +)] +#[instrument(skip(state))] +pub async fn list_rejected( + State(state): State, + axum::extract::Query(params): axum::extract::Query, +) -> std::result::Result, (axum::http::StatusCode, Json)> +{ + let limit = params.limit.unwrap_or(100); + let prefix = key_codec::rejected_records_scan_prefix(); + + let entries = state.store.scan_prefix(&prefix).await.map_err(|e| { + tracing::error!(error = %e, "Failed to scan rejected records"); + ( + axum::http::StatusCode::INTERNAL_SERVER_ERROR, + Json(ErrorResponse { + error: "Failed to retrieve rejected records".to_string(), + code: "REJECTED_SCAN_ERROR".to_string(), + }), + ) + })?; + + let mut rejected = Vec::new(); + for (_key, value) in entries.into_iter().take(limit) { + let json_str = String::from_utf8_lossy(&value); + if let Ok(dto) = serde_json::from_str::(&json_str) { + rejected.push(dto); + } + } + + let count = rejected.len(); + Ok(Json(RejectedRecordsResponse { rejected, count })) +} diff --git a/crates/stemedb-api/src/handlers/source_registry/handlers.rs b/crates/stemedb-api/src/handlers/source_registry/handlers.rs index ad4edbe..5cec176 100644 --- a/crates/stemedb-api/src/handlers/source_registry/handlers.rs +++ b/crates/stemedb-api/src/handlers/source_registry/handlers.rs @@ -7,6 +7,7 @@ use axum::{ response::{IntoResponse, Response}, Json, }; +use stemedb_core::limits::MAX_SOURCE_CONTENT_LEN; use stemedb_core::types::{SourceRecord, SourceStatus}; use stemedb_storage::{GenericIndexStore, GenericSourceRegistry, IndexStore, SourceRegistry}; use tracing::instrument; @@ -56,12 +57,24 @@ pub async fn register_source( return Err(ApiError::InvalidRequest("Label cannot be empty".to_string())); } + // Validate content size + if let Some(ref content) = req.content { + if content.len() > MAX_SOURCE_CONTENT_LEN { + return Err(ApiError::InvalidRequest(format!( + "Content too large: {} bytes (max {})", + content.len(), + MAX_SOURCE_CONTENT_LEN + ))); + } + } + // Get timestamp let timestamp = current_timestamp(); // Create the record let mut record = SourceRecord::new(hash, req.label.clone(), req.url, req.tier, timestamp); record.notes = req.notes; + record.content = req.content; // Register in the store let registry = GenericSourceRegistry::new(state.store.clone()); @@ -206,7 +219,7 @@ pub async fn list_sources( let registry = GenericSourceRegistry::new(state.store.clone()); - let sources: Vec = if let Some(query) = ¶ms.query { + let mut sources: Vec = if let Some(query) = ¶ms.query { // Search by label registry.search(query, limit).await?.into_iter().map(Into::into).collect() } else if let Some(tier) = params.tier { @@ -227,6 +240,11 @@ pub async fn list_sources( all.into_iter().map(Into::into).collect() }; + // Strip content from list responses to avoid returning megabytes + for dto in &mut sources { + dto.content = None; + } + let count = sources.len(); Ok(Json(ListSourcesResponse { sources, count })) } @@ -629,7 +647,7 @@ async fn build_impact_response( if let Ok(Some(data)) = store_get_with_timeout(&*state.store, &assertion_key).await { if let Ok(assertion) = - stemedb_core::serde::deserialize::(&data) + stemedb_core::serde::deserialize_assertion_compat(&data) { for sig in &assertion.signatures { let agent_hex = hex::encode(sig.agent_id); diff --git a/crates/stemedb-api/src/handlers/stemedb_claims.rs b/crates/stemedb-api/src/handlers/stemedb_claims.rs index 6e8b88a..9e8b4cb 100644 --- a/crates/stemedb-api/src/handlers/stemedb_claims.rs +++ b/crates/stemedb-api/src/handlers/stemedb_claims.rs @@ -3,12 +3,16 @@ //! These endpoints provide claim storage DIRECTLY in StemeDB (not `.aphoria/claims.toml`). //! Used for remote/hosted mode where claims are stored in the knowledge graph. -use axum::{extract::{Path, State}, http::StatusCode, Json}; +use axum::{ + extract::{Path, State}, + http::StatusCode, + Json, +}; +use ed25519_dalek::{Signer, SigningKey, VerifyingKey}; use tracing::info; -use ed25519_dalek::{SigningKey, Signer, VerifyingKey}; -use stemedb_core::types::{Assertion, LifecycleStage, ObjectValue, SignatureEntry}; use stemedb_core::signing::compute_content_hash_v2; +use stemedb_core::types::{Assertion, LifecycleStage, ObjectValue, SignatureEntry}; use stemedb_ingest::worker::serialize_assertion; use stemedb_storage::{key_codec, KVStore}; @@ -86,10 +90,7 @@ pub async fn create_claim( state.commit_buffer.append(payload).await?; - Ok(( - StatusCode::CREATED, - Json(CreateClaimResponse { id: req.claim.id.clone(), stored: true }), - )) + Ok((StatusCode::CREATED, Json(CreateClaimResponse { id: req.claim.id.clone(), stored: true }))) } /// List all claims, optionally filtered. @@ -129,7 +130,7 @@ pub async fn list_claims( let hash_hex = hex::encode(&hash_bytes); let assertion_key = key_codec::assertion_key(&subject, &hash_hex); if let Some(data) = state.store.get(&assertion_key).await? { - if let Ok(assertion) = stemedb_core::serde::deserialize::(&data) { + if let Ok(assertion) = stemedb_core::serde::deserialize_assertion_compat(&data) { if let Ok(dto) = assertion_to_dto(&assertion) { claims.push(dto); } @@ -189,10 +190,11 @@ pub async fn get_claim( let hash_hex = hex::encode(hash_bytes); let assertion_key = key_codec::assertion_key(&subject, &hash_hex); - let data = state.store.get(&assertion_key).await? - .ok_or_else(|| ApiError::NotFound(format!("Claim not found: {}/{}", concept_path, predicate)))?; + let data = state.store.get(&assertion_key).await?.ok_or_else(|| { + ApiError::NotFound(format!("Claim not found: {}/{}", concept_path, predicate)) + })?; - let assertion = stemedb_core::serde::deserialize::(&data) + let assertion = stemedb_core::serde::deserialize_assertion_compat(&data) .map_err(|e| ApiError::Serialization(format!("Failed to deserialize assertion: {e}")))?; assertion_to_dto(&assertion) @@ -237,10 +239,11 @@ pub async fn delete_claim( let hash_hex = hex::encode(hash_bytes); let assertion_key = key_codec::assertion_key(&subject, &hash_hex); - let data = state.store.get(&assertion_key).await? - .ok_or_else(|| ApiError::NotFound(format!("Claim not found: {}/{}", concept_path, predicate)))?; + let data = state.store.get(&assertion_key).await?.ok_or_else(|| { + ApiError::NotFound(format!("Claim not found: {}/{}", concept_path, predicate)) + })?; - let mut assertion = stemedb_core::serde::deserialize::(&data) + let mut assertion = stemedb_core::serde::deserialize_assertion_compat(&data) .map_err(|e| ApiError::Serialization(format!("Failed to deserialize assertion: {e}")))?; // Mark as deprecated (append-only: create new version) @@ -328,12 +331,13 @@ fn dto_to_assertion(dto: &AuthoredClaimDto) -> Result { visual_hash: None, epoch: None, source_metadata: serde_json::to_vec(&metadata).ok(), + narrative: None, lifecycle, signatures: vec![], // Signatures added by ingestion pipeline confidence: 1.0, // Authored claims have full confidence timestamp: std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) - .unwrap() + .unwrap_or_default() .as_secs(), hlc_timestamp: Default::default(), vector: None, @@ -360,10 +364,14 @@ fn assertion_to_dto(assertion: &Assertion) -> Result { let concept_path = assertion .subject .strip_prefix("claim://") - .ok_or_else(|| ApiError::Internal("Invalid subject format: missing claim:// prefix".to_string()))? + .ok_or_else(|| { + ApiError::Internal("Invalid subject format: missing claim:// prefix".to_string()) + })? .rsplit_once('/') .map(|(cp, _)| cp) - .ok_or_else(|| ApiError::Internal("Invalid subject format: missing predicate separator".to_string()))? + .ok_or_else(|| { + ApiError::Internal("Invalid subject format: missing predicate separator".to_string()) + })? .to_string(); // Convert object value @@ -393,11 +401,7 @@ fn assertion_to_dto(assertion: &Assertion) -> Result { .and_then(|v| v.as_str()) .unwrap_or("equals") .to_string(), - provenance: metadata - .get("provenance") - .and_then(|v| v.as_str()) - .unwrap_or("") - .to_string(), + provenance: metadata.get("provenance").and_then(|v| v.as_str()).unwrap_or("").to_string(), invariant: metadata.get("invariant").and_then(|v| v.as_str()).unwrap_or("").to_string(), consequence: metadata.get("consequence").and_then(|v| v.as_str()).unwrap_or("").to_string(), authority_tier: source_class_to_tier_string(assertion.source_class), diff --git a/crates/stemedb-api/src/handlers/subjects.rs b/crates/stemedb-api/src/handlers/subjects.rs new file mode 100644 index 0000000..54ac1f4 --- /dev/null +++ b/crates/stemedb-api/src/handlers/subjects.rs @@ -0,0 +1,97 @@ +//! Handlers for subject and predicate discovery endpoints. +//! +//! These endpoints scan existing Redb indexes to expose the subjects +//! and predicates known to the system, enabling autocomplete/typeahead +//! in the dashboard. + +use axum::{ + extract::{Path, State}, + Json, +}; +use tracing::instrument; + +use crate::{ + dto::subjects::{ListPredicatesResponse, ListSubjectsParams, ListSubjectsResponse}, + error::Result, + extractors::QsQuery, + state::AppState, +}; + +use stemedb_storage::{key_codec, KVStore}; + +/// List all known subjects, with optional prefix filtering. +/// +/// Scans the `\x00SUBJECTS:` index in Redb. Supports prefix filtering +/// via the `q` parameter for typeahead/autocomplete use cases. +#[utoipa::path( + get, + path = "/v1/subjects", + params( + ("q" = Option, Query, description = "Prefix filter for subject names"), + ("limit" = Option, Query, description = "Max results (default 100, max 1000)") + ), + responses( + (status = 200, description = "List of subjects", body = ListSubjectsResponse), + (status = 500, description = "Internal server error", body = crate::dto::ErrorResponse) + ), + tag = "discovery" +)] +#[instrument(skip(state), fields(q = ?params.q, limit = ?params.limit))] +pub async fn list_subjects( + State(state): State, + QsQuery(params): QsQuery, +) -> Result> { + metrics::counter!("stemedb_queries_total", "endpoint" => "list_subjects").increment(1); + + let prefix = if let Some(ref q) = params.q { + key_codec::subjects_index_key(q) + } else { + key_codec::subjects_scan_prefix() + }; + + let entries = state.store.scan_prefix(&prefix).await?; + let total_count = entries.len(); + let limit = params.limit.unwrap_or(100).min(1000); + + let subjects: Vec = entries + .iter() + .filter_map(|(k, _)| key_codec::extract_subject_from_subjects_key(k)) + .take(limit) + .collect(); + + Ok(Json(ListSubjectsResponse { subjects, total_count })) +} + +/// List all predicates for a given subject. +/// +/// Scans the `{subject}\x00SP:` index in Redb to find all predicates +/// that have been asserted for this subject. +#[utoipa::path( + get, + path = "/v1/subjects/{subject}/predicates", + params( + ("subject" = String, Path, description = "The subject to list predicates for") + ), + responses( + (status = 200, description = "List of predicates for the subject", body = ListPredicatesResponse), + (status = 500, description = "Internal server error", body = crate::dto::ErrorResponse) + ), + tag = "discovery" +)] +#[instrument(skip(state), fields(%subject))] +pub async fn list_predicates( + State(state): State, + Path(subject): Path, +) -> Result> { + metrics::counter!("stemedb_queries_total", "endpoint" => "list_predicates").increment(1); + + let prefix = key_codec::subject_predicate_scan_prefix(&subject); + let entries = state.store.scan_prefix(&prefix).await?; + + let predicates: Vec = entries + .iter() + .filter_map(|(k, _)| key_codec::extract_sp_key(k).map(|(_, p)| p)) + .collect(); + + Ok(Json(ListPredicatesResponse { subject, predicates })) +} diff --git a/crates/stemedb-api/src/lib.rs b/crates/stemedb-api/src/lib.rs index 4757246..9401f73 100644 --- a/crates/stemedb-api/src/lib.rs +++ b/crates/stemedb-api/src/lib.rs @@ -66,7 +66,7 @@ pub use state::AppState; // Re-export the path items for OpenAPI use handlers::{ - admin::__path_decay_trust_ranks, + admin::{__path_decay_trust_ranks, __path_rebuild_indexes}, admission::__path_get_admission_status, api_keys::{ __path_create_api_key, __path_list_api_keys, __path_revoke_api_key, __path_rotate_api_key, @@ -83,8 +83,8 @@ use handlers::{ }, constraints::__path_constraints_query, epoch::__path_create_epoch, - feed::__path_feed, escalation::{__path_list_escalations, __path_resolve_escalation}, + feed::__path_feed, gold_standard::{ __path_create_gold_standard, __path_list_gold_standards, __path_remove_gold_standard, __path_verify_agent, @@ -104,6 +104,7 @@ use handlers::{ __path_list_sources, __path_quarantine_source, __path_register_source, __path_restore_source, __path_update_source_status, }, + subjects::{__path_list_predicates, __path_list_subjects}, supersede::__path_supersede, trace::__path_trace, vote::__path_create_vote, @@ -132,6 +133,7 @@ use handlers::{ store_source, get_provenance, decay_trust_ranks, + rebuild_indexes, list_escalations, resolve_escalation, create_gold_standard, @@ -168,6 +170,9 @@ use handlers::{ revoke_api_key, rotate_api_key, update_api_key, + // Discovery (subject/predicate autocomplete) + list_subjects, + list_predicates, ), components( schemas( @@ -215,6 +220,7 @@ use handlers::{ dto::ProvenanceResponse, dto::DecayTrustRanksRequest, dto::DecayTrustRanksResponse, + dto::RebuildIndexesResponse, dto::EscalationEventDto, dto::EscalationLevelDto, dto::EscalationListResponse, @@ -284,6 +290,9 @@ use handlers::{ dto::RotateApiKeyResponse, dto::UpdateApiKeyRequest, dto::UpdateApiKeyResponse, + // Discovery (subject/predicate autocomplete) + dto::ListSubjectsResponse, + dto::ListPredicatesResponse, ) ), tags( @@ -302,6 +311,7 @@ use handlers::{ (name = "quarantine", description = "Content defense quarantine management"), (name = "circuit_breaker", description = "Per-agent circuit breaker management"), (name = "source-registry", description = "Source metadata registry and impact analysis"), + (name = "discovery", description = "Subject and predicate discovery for autocomplete"), ), info( title = "Episteme (StemeDB) API", diff --git a/crates/stemedb-api/src/main.rs b/crates/stemedb-api/src/main.rs index 91f0a93..0cbcf07 100644 --- a/crates/stemedb-api/src/main.rs +++ b/crates/stemedb-api/src/main.rs @@ -276,11 +276,7 @@ async fn main() -> Result<(), Box> { info!("API server listening on {} (plaintext)", config.bind_addr); info!("Swagger UI available at http://{}/swagger-ui", config.bind_addr); - axum::serve( - listener, - app.into_make_service_with_connect_info::(), - ) - .await?; + axum::serve(listener, app.into_make_service_with_connect_info::()).await?; } Ok(()) diff --git a/crates/stemedb-api/src/routers.rs b/crates/stemedb-api/src/routers.rs index 8aab393..ee1fca6 100644 --- a/crates/stemedb-api/src/routers.rs +++ b/crates/stemedb-api/src/routers.rs @@ -410,6 +410,7 @@ fn build_api_routes(config: &SecurityConfig) -> Router { .route("/v1/claims", post(handlers::create_stemedb_claim)) // Admin write endpoints .route("/v1/admin/decay-trust-ranks", post(handlers::decay_trust_ranks)) + .route("/v1/admin/rebuild-indexes", post(handlers::rebuild_indexes)) .route("/v1/admin/escalations/:id/resolve", post(handlers::resolve_escalation)) .route("/v1/admin/gold-standards", post(handlers::create_gold_standard)) .route( @@ -449,7 +450,10 @@ fn build_api_routes(config: &SecurityConfig) -> Router { // Claims endpoints (StemeDB-backed) .route("/v1/claims", get(handlers::list_stemedb_claims)) .route("/v1/claims/:concept_path/:predicate", get(handlers::get_stemedb_claim)) - .route("/v1/claims/:concept_path/:predicate", axum::routing::delete(handlers::delete_stemedb_claim)) + .route( + "/v1/claims/:concept_path/:predicate", + axum::routing::delete(handlers::delete_stemedb_claim), + ) .route("/v1/admin/escalations", get(handlers::list_escalations)) .route("/v1/admin/gold-standards", get(handlers::list_gold_standards)) .route("/v1/concepts/resolve", get(handlers::resolve_alias)) @@ -459,6 +463,7 @@ fn build_api_routes(config: &SecurityConfig) -> Router { .route("/v1/admission/status", get(handlers::get_admission_status)) .route("/v1/admin/quarantine", get(handlers::list_quarantine)) .route("/v1/admin/quarantine/:hash", get(handlers::get_quarantine)) + .route("/v1/admin/rejected", get(handlers::list_rejected)) .route("/v1/admin/circuit-breaker/:agent_id", get(handlers::get_circuit_status)) .route("/v1/admin/circuit-breakers/tripped", get(handlers::list_tripped_circuits)) .route("/v1/admin/api-keys", get(handlers::list_api_keys)) @@ -466,6 +471,9 @@ fn build_api_routes(config: &SecurityConfig) -> Router { .route("/v1/sources/:hash", get(handlers::get_source)) .route("/v1/sources/:hash/impact", get(handlers::get_source_impact)) .route("/v1/sources/:hash/impact/export", get(handlers::export_source_impact)) + // Discovery endpoints (subject/predicate autocomplete) + .route("/v1/subjects", get(handlers::list_subjects)) + .route("/v1/subjects/:subject/predicates", get(handlers::list_predicates)) .layer(RequestBodyLimitLayer::new(config.read_body_limit)); // P5.1: Configurable limit // Add Aphoria endpoints when feature is enabled diff --git a/crates/stemedb-api/tests/http_basic.rs b/crates/stemedb-api/tests/http_basic.rs index 267c136..61c1c5a 100644 --- a/crates/stemedb-api/tests/http_basic.rs +++ b/crates/stemedb-api/tests/http_basic.rs @@ -61,12 +61,9 @@ async fn test_health_check_over_tcp() { // Serve with ConnectInfo injection (the fix for the 500 bug) tokio::spawn(async move { - axum::serve( - listener, - app.into_make_service_with_connect_info::(), - ) - .await - .expect("server"); + axum::serve(listener, app.into_make_service_with_connect_info::()) + .await + .expect("server"); }); // Give the server a moment to start @@ -74,10 +71,7 @@ async fn test_health_check_over_tcp() { // Make a raw HTTP/1.1 request over TCP let mut stream = tokio::net::TcpStream::connect(addr).await.expect("connect"); - let request = format!( - "GET /v1/health HTTP/1.1\r\nHost: {}\r\nConnection: close\r\n\r\n", - addr - ); + let request = format!("GET /v1/health HTTP/1.1\r\nHost: {}\r\nConnection: close\r\n\r\n", addr); stream.write_all(request.as_bytes()).await.expect("write"); let mut response = String::new(); @@ -95,3 +89,111 @@ async fn test_health_check_over_tcp() { let json: serde_json::Value = serde_json::from_str(body).expect("json parse"); assert_eq!(json["status"], "healthy"); } + +// ============================================================================ +// Signature Verification Tests (pre-WAL validation) +// ============================================================================ + +/// Test: POST /v1/assert with invalid signatures returns 400 (not 201). +/// +/// Regression test for the "assert returns 201 but data is silently dropped" bug. +/// Previously, the API accepted structurally valid but cryptographically invalid +/// signatures, wrote them to the WAL, and returned 201. The IngestWorker would +/// then silently reject them, permanently blocking the ingestion pipeline. +#[tokio::test] +async fn test_assert_invalid_signature_returns_400() { + use serde_json::json; + + let env = common::create_test_env().await; + let app = create_router(env.state); + + // Construct assertion with structurally valid but cryptographically invalid signature. + // agent_id is a SHA-256 hash (not a valid Ed25519 public key). + // signature is random 64 bytes. + let body = json!({ + "subject": "test/bug_regression", + "predicate": "has_value", + "object": {"type": "Text", "value": "hello"}, + "confidence": 0.9, + "source_hash": "0".repeat(64), + "signatures": [{ + "agent_id": "a".repeat(64), + "signature": "b".repeat(128), + "timestamp": 1700000000 + }], + "timestamp": 1700000000 + }); + + let request = Request::builder() + .uri("/v1/assert") + .method("POST") + .header("Content-Type", "application/json") + .body(Body::from(serde_json::to_vec(&body).expect("json"))) + .expect("Request"); + + let response = app.oneshot(request).await.expect("Request"); + assert_eq!( + response.status(), + StatusCode::BAD_REQUEST, + "Invalid signature should return 400, not 201" + ); + + let body = axum::body::to_bytes(response.into_body(), usize::MAX).await.expect("Body"); + let json: serde_json::Value = serde_json::from_slice(&body).expect("JSON"); + + // Verify error message mentions signature + let error_msg = json["error"].as_str().unwrap_or(""); + assert!( + error_msg.contains("Signature") || error_msg.contains("signature"), + "Error should mention signature failure, got: {}", + error_msg + ); +} + +/// Test: POST /v1/assert with valid Ed25519 signature returns 201. +#[tokio::test] +async fn test_assert_valid_signature_returns_201() { + let env = common::create_test_env().await; + let app = create_router(env.state); + + let body = common::create_signed_assertion_json("test/valid", "has_value", 42.0); + + let request = Request::builder() + .uri("/v1/assert") + .method("POST") + .header("Content-Type", "application/json") + .body(Body::from(serde_json::to_vec(&body).expect("json"))) + .expect("Request"); + + let response = app.oneshot(request).await.expect("Request"); + assert_eq!(response.status(), StatusCode::CREATED, "Valid signature should return 201"); + + let body = axum::body::to_bytes(response.into_body(), usize::MAX).await.expect("Body"); + let json: serde_json::Value = serde_json::from_slice(&body).expect("JSON"); + assert_eq!(json["status"], "created"); +} + +/// Test: POST /v1/assert with null byte in subject returns 400. +#[tokio::test] +async fn test_assert_null_byte_subject_returns_400() { + let env = common::create_test_env().await; + let app = create_router(env.state); + + // Use a properly signed assertion but with null byte in subject + let body = common::create_signed_assertion_json("test\x00injected", "has_value", 1.0); + + let request = Request::builder() + .uri("/v1/assert") + .method("POST") + .header("Content-Type", "application/json") + .body(Body::from(serde_json::to_vec(&body).expect("json"))) + .expect("Request"); + + let response = app.oneshot(request).await.expect("Request"); + // Should fail with 400 due to null byte in subject + assert_eq!( + response.status(), + StatusCode::BAD_REQUEST, + "Null byte in subject should return 400" + ); +} diff --git a/crates/stemedb-core/src/lib.rs b/crates/stemedb-core/src/lib.rs index 3b46c95..136b62b 100644 --- a/crates/stemedb-core/src/lib.rs +++ b/crates/stemedb-core/src/lib.rs @@ -48,6 +48,7 @@ mod tests { visual_hash: Some([1u8; 8]), epoch: Some([2u8; 32]), source_metadata: None, + narrative: None, lifecycle: LifecycleStage::Approved, signatures: vec![SignatureEntry { agent_id: [2u8; 32], @@ -103,6 +104,7 @@ mod tests { visual_hash: None, epoch: None, source_metadata: None, + narrative: None, lifecycle: stage, signatures: vec![], confidence: 1.0, diff --git a/crates/stemedb-core/src/limits.rs b/crates/stemedb-core/src/limits.rs index c51edc2..2efd41e 100644 --- a/crates/stemedb-core/src/limits.rs +++ b/crates/stemedb-core/src/limits.rs @@ -55,6 +55,25 @@ pub const MAX_OBJECT_LEN: usize = 4096; /// in the source metadata instead of the raw bytes. pub const MAX_SOURCE_SIZE: usize = 10 * 1024 * 1024; +/// Maximum allowed narrative length in bytes (64 KB). +/// +/// Narratives are free-text explanations of methodology, limitations, bias, +/// and caveats that make an assertion self-contained. This limit prevents +/// unbounded memory growth while allowing rich context. +/// +/// # Example +/// - Valid: A 2 KB explanation of trial methodology +/// - Valid: A 10 KB narrative covering bias, limitations, and caveats +/// - Invalid: A 100 KB embedded document in the narrative field +pub const MAX_NARRATIVE_LEN: usize = 65_536; + +/// Maximum allowed source content length in bytes (1 MB). +/// +/// Source content is the extracted full text from PDFs or other documents. +/// This limit prevents unbounded memory growth while allowing typical +/// research papers and regulatory documents. +pub const MAX_SOURCE_CONTENT_LEN: usize = 1_048_576; + /// Default limit for paginated query results. /// /// Applied when no explicit limit is provided in the query parameters. diff --git a/crates/stemedb-core/src/serde.rs b/crates/stemedb-core/src/serde.rs index d90065c..a18419e 100644 --- a/crates/stemedb-core/src/serde.rs +++ b/crates/stemedb-core/src/serde.rs @@ -44,6 +44,11 @@ use rkyv::validation::validators::DefaultValidator; use rkyv::{Archive, CheckBytes, Deserialize, Serialize}; use thiserror::Error; +use crate::types::{ + Assertion, HlcTimestamp, LifecycleStage, ObjectValue, SignatureEntry, SourceClass, + SourceRecord, SourceStatus, +}; + /// Default scratch buffer size for serialization. /// /// 4KB is sufficient for most assertions. Larger payloads will trigger @@ -88,6 +93,7 @@ pub enum SerdeError { /// visual_hash: None, /// epoch: None, /// source_metadata: None, +/// narrative: None, /// lifecycle: LifecycleStage::Proposed, /// signatures: vec![], /// confidence: 1.0, @@ -156,6 +162,131 @@ where .map_err(|e| SerdeError::Deserialization(e.to_string())) } +// ============================================================================ +// Legacy Assertion (pre-narrative schema) +// ============================================================================ + +/// Assertion struct matching the pre-narrative rkyv layout. +/// +/// The `narrative: Option` field was added between `source_metadata` +/// and `lifecycle`. rkyv doesn't support schema evolution, so data serialized +/// before that change needs this struct to deserialize correctly. +#[derive(Archive, Deserialize, Serialize, Debug, Clone, PartialEq)] +#[archive(check_bytes)] +struct LegacyAssertion { + pub subject: String, + pub predicate: String, + pub object: ObjectValue, + pub parent_hash: Option<[u8; 32]>, + pub source_hash: [u8; 32], + pub source_class: SourceClass, + pub visual_hash: Option<[u8; 8]>, + pub epoch: Option<[u8; 32]>, + pub source_metadata: Option>, + // narrative: Option did NOT exist in this version + pub lifecycle: LifecycleStage, + pub signatures: Vec, + pub confidence: f32, + pub timestamp: u64, + pub hlc_timestamp: HlcTimestamp, + pub vector: Option>, +} + +impl From for Assertion { + fn from(legacy: LegacyAssertion) -> Self { + Self { + subject: legacy.subject, + predicate: legacy.predicate, + object: legacy.object, + parent_hash: legacy.parent_hash, + source_hash: legacy.source_hash, + source_class: legacy.source_class, + visual_hash: legacy.visual_hash, + epoch: legacy.epoch, + source_metadata: legacy.source_metadata, + narrative: None, + lifecycle: legacy.lifecycle, + signatures: legacy.signatures, + confidence: legacy.confidence, + timestamp: legacy.timestamp, + hlc_timestamp: legacy.hlc_timestamp, + vector: legacy.vector, + } + } +} + +/// Deserialize an assertion with backward compatibility. +/// +/// Tries the current `Assertion` layout first. If that fails, tries the +/// legacy layout (before `narrative` field was added) and converts. +/// +/// This allows the system to read assertions written before schema changes +/// without requiring a data migration. +pub fn deserialize_assertion_compat(data: &[u8]) -> Result { + // Try current format first (fast path for new data) + if let Ok(assertion) = deserialize::(data) { + return Ok(assertion); + } + + // Fallback: try legacy format (no narrative field) + let legacy: LegacyAssertion = deserialize(data)?; + Ok(legacy.into()) +} + +// ============================================================================ +// Legacy SourceRecord (pre-content schema) +// ============================================================================ + +/// SourceRecord struct matching the pre-content rkyv layout. +/// +/// The `content: Option` field was added after `notes`. +/// rkyv doesn't support schema evolution, so data serialized +/// before that change needs this struct to deserialize correctly. +#[derive(Archive, Deserialize, Serialize, Debug, Clone, PartialEq)] +#[archive(check_bytes)] +struct LegacySourceRecord { + pub hash: [u8; 32], + pub label: String, + pub url: Option, + pub tier: u8, + pub status: SourceStatus, + pub created_at: u64, + pub updated_at: u64, + pub notes: Option, + // content: Option did NOT exist in this version +} + +impl From for SourceRecord { + fn from(legacy: LegacySourceRecord) -> Self { + Self { + hash: legacy.hash, + label: legacy.label, + url: legacy.url, + tier: legacy.tier, + status: legacy.status, + created_at: legacy.created_at, + updated_at: legacy.updated_at, + notes: legacy.notes, + content: None, + } + } +} + +/// Deserialize a source record with backward compatibility. +/// +/// Tries the current `SourceRecord` layout first. If that fails, tries the +/// legacy layout (before `content` field was added) and converts. +pub fn deserialize_source_record_compat(data: &[u8]) -> Result { + // Try current format first (fast path for new data) + if let Ok(record) = deserialize::(data) { + return Ok(record); + } + + // Fallback: try legacy format (no content field) + let legacy: LegacySourceRecord = deserialize(data)?; + Ok(legacy.into()) +} + #[cfg(test)] mod tests { use super::*; @@ -176,6 +307,7 @@ mod tests { visual_hash: Some([1u8; 8]), epoch: Some([2u8; 32]), source_metadata: None, + narrative: None, lifecycle: LifecycleStage::Approved, signatures: vec![SignatureEntry { agent_id: [2u8; 32], @@ -303,6 +435,7 @@ mod tests { visual_hash: None, epoch: None, source_metadata: None, + narrative: None, lifecycle: LifecycleStage::Proposed, signatures: vec![], confidence: 0.0, @@ -330,6 +463,7 @@ mod tests { visual_hash: None, epoch: None, source_metadata: Some(metadata.as_bytes().to_vec()), + narrative: None, lifecycle: LifecycleStage::Proposed, signatures: vec![], confidence: 0.85, @@ -357,6 +491,7 @@ mod tests { visual_hash: None, epoch: None, source_metadata: None, + narrative: None, lifecycle: LifecycleStage::Proposed, signatures: vec![], confidence: 1.0, @@ -371,4 +506,127 @@ mod tests { assert_eq!(assertion, recovered); assert!(recovered.source_metadata.is_none()); } + + #[test] + fn test_legacy_assertion_compat_deserialize() { + // Simulate data serialized with the pre-narrative struct layout. + let legacy = LegacyAssertion { + subject: "Semaglutide".to_string(), + predicate: "reduces_weight".to_string(), + object: ObjectValue::Text("significant".to_string()), + parent_hash: None, + source_hash: [1u8; 32], + source_class: SourceClass::Clinical, + visual_hash: None, + epoch: None, + source_metadata: Some(b"{}".to_vec()), + lifecycle: LifecycleStage::Approved, + signatures: vec![SignatureEntry { + agent_id: [2u8; 32], + signature: [3u8; 64], + timestamp: 1000, + version: 1, + }], + confidence: 0.95, + timestamp: 1700000000, + hlc_timestamp: HlcTimestamp::default(), + vector: Some(vec![0.1, 0.2]), + }; + + let bytes = serialize(&legacy).expect("serialize legacy"); + + // Current format should fail (different layout) + assert!(deserialize::(&bytes).is_err()); + + // Compat function should succeed + let recovered = deserialize_assertion_compat(&bytes) + .expect("compat deserialize should succeed"); + + assert_eq!(recovered.subject, "Semaglutide"); + assert_eq!(recovered.predicate, "reduces_weight"); + assert_eq!(recovered.confidence, 0.95); + assert_eq!(recovered.signatures.len(), 1); + assert!(recovered.narrative.is_none()); // Wasn't in legacy + assert!(recovered.source_metadata.is_some()); + assert_eq!(recovered.timestamp, 1700000000); + } + + #[test] + fn test_current_assertion_also_works_via_compat() { + // Current-format assertions should work via the compat path too. + let assertion = Assertion { + subject: "test".to_string(), + predicate: "works".to_string(), + object: ObjectValue::Boolean(true), + parent_hash: None, + source_hash: [0u8; 32], + source_class: SourceClass::Expert, + visual_hash: None, + epoch: None, + source_metadata: None, + narrative: Some("This is a narrative.".to_string()), + lifecycle: LifecycleStage::Proposed, + signatures: vec![], + confidence: 1.0, + timestamp: 0, + hlc_timestamp: HlcTimestamp::default(), + vector: None, + }; + + let bytes = serialize(&assertion).expect("serialize"); + let recovered = deserialize_assertion_compat(&bytes) + .expect("compat deserialize should succeed for current format"); + + assert_eq!(recovered, assertion); + assert_eq!(recovered.narrative, Some("This is a narrative.".to_string())); + } + + #[test] + fn test_legacy_source_record_compat_deserialize() { + // Simulate data serialized with the pre-content struct layout. + let legacy = LegacySourceRecord { + hash: [42u8; 32], + label: "RFC 7519".to_string(), + url: Some("https://tools.ietf.org/html/rfc7519".to_string()), + tier: 0, + status: SourceStatus::Active, + created_at: 1000, + updated_at: 2000, + notes: Some("JWT spec".to_string()), + }; + + let bytes = serialize(&legacy).expect("serialize legacy"); + + // Current format should fail (different layout) + assert!(deserialize::(&bytes).is_err()); + + // Compat function should succeed + let recovered = deserialize_source_record_compat(&bytes) + .expect("compat deserialize should succeed"); + + assert_eq!(recovered.hash, [42u8; 32]); + assert_eq!(recovered.label, "RFC 7519"); + assert_eq!(recovered.tier, 0); + assert_eq!(recovered.notes, Some("JWT spec".to_string())); + assert!(recovered.content.is_none()); // Wasn't in legacy + } + + #[test] + fn test_current_source_record_also_works_via_compat() { + let record = SourceRecord::new( + [1u8; 32], + "Test".to_string(), + None, + 2, + 1000, + ) + .with_content(Some("Full text content".to_string())); + + let bytes = serialize(&record).expect("serialize"); + let recovered = deserialize_source_record_compat(&bytes) + .expect("compat deserialize should succeed for current format"); + + assert_eq!(recovered, record); + assert_eq!(recovered.content, Some("Full text content".to_string())); + } } diff --git a/crates/stemedb-core/src/signing.rs b/crates/stemedb-core/src/signing.rs index def8861..8fafad8 100644 --- a/crates/stemedb-core/src/signing.rs +++ b/crates/stemedb-core/src/signing.rs @@ -21,6 +21,140 @@ //! ``` use crate::types::{Assertion, ObjectValue}; +use ed25519_dalek::{Signature, Verifier, VerifyingKey}; + +/// Errors from signature verification. +/// +/// Error messages are written for API consumers who may not understand Ed25519 +/// cryptography, explaining what fields must contain and common mistakes. +#[derive(Debug)] +pub enum SignatureError { + /// No signatures present on the assertion. + Empty, + + /// Unknown signature version. + UnknownVersion { + /// The unrecognized version number. + version: u8, + /// Which signature in the list. + index: usize, + }, + + /// The agent_id bytes are not a valid Ed25519 public key. + InvalidPublicKey { + /// Which signature in the list. + index: usize, + /// The underlying error detail. + detail: String, + }, + + /// The signature does not verify against the message. + VerificationFailed { + /// Which signature in the list. + index: usize, + /// The signature version. + version: u8, + /// The underlying error detail. + detail: String, + }, +} + +impl std::fmt::Display for SignatureError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Empty => write!( + f, + "Assertion must have at least one signature. \ + Each signature requires: agent_id (32-byte Ed25519 public key, hex-encoded as 64 chars), \ + signature (64-byte Ed25519 signature, hex-encoded as 128 chars). \ + SHA-256/SHA-512 hashes cannot be used as agent_id or signature" + ), + Self::UnknownVersion { version, index } => write!( + f, + "Signature {index}: unknown version {version}. \ + Supported versions: 1 (signs '{{subject}}:{{predicate}}'), 2 (signs BLAKE3 content hash)" + ), + Self::InvalidPublicKey { index, detail } => write!( + f, + "Signature {index}: agent_id is not a valid Ed25519 public key ({detail}). \ + agent_id must be a 32-byte Ed25519 public key (hex-encoded as 64 chars). \ + Common mistake: using SHA-256 or other hashes as agent_id. \ + Generate a keypair with Ed25519 (e.g., ed25519-dalek, crypto/ed25519, or openssl)" + ), + Self::VerificationFailed { index, version, detail } => { + let message_desc = match version { + 1 => "'{subject}:{predicate}' (UTF-8 bytes)", + 2 => "the BLAKE3 content hash of the assertion", + _ => "unknown", + }; + write!( + f, + "Signature {index}: Ed25519 verification failed ({detail}). \ + For v{version} signatures, signature must be Ed25519_sign(private_key, {message_desc}). \ + Common mistakes: (1) using SHA hashes instead of Ed25519 signatures, \ + (2) signing the wrong message, (3) agent_id doesn't match the signing key" + ) + } + } + } +} + +impl std::error::Error for SignatureError {} + +/// Verify all Ed25519 signatures on an assertion. +/// +/// Supports two signature versions: +/// - **Version 1 (legacy):** signs `"{subject}:{predicate}"` — only protects those fields +/// - **Version 2 (enterprise):** signs the BLAKE3 content hash — protects ALL fields +/// +/// All signatures must be valid for the assertion to be accepted. +/// +/// This function is used at both the API boundary (fail fast with 400) and in the +/// IngestWorker (defense in depth). Keeping it in `stemedb-core` avoids duplication. +pub fn verify_assertion_signatures( + assertion: &Assertion, +) -> std::result::Result<(), SignatureError> { + if assertion.signatures.is_empty() { + return Err(SignatureError::Empty); + } + + // Pre-compute v1 message (subject:predicate) — only used if v1 signatures exist + let v1_message = format!("{}:{}", assertion.subject, assertion.predicate); + + // Pre-compute v2 content hash — only if any v2 signature exists + let v2_content_hash: Option<[u8; 32]> = if assertion.signatures.iter().any(|s| s.version == 2) { + Some(compute_content_hash_v2(assertion)) + } else { + None + }; + + for (idx, sig_entry) in assertion.signatures.iter().enumerate() { + let message_bytes: &[u8] = match sig_entry.version { + 1 => v1_message.as_bytes(), + 2 => v2_content_hash + .as_ref() + .ok_or(SignatureError::UnknownVersion { version: 2, index: idx })?, + v => { + return Err(SignatureError::UnknownVersion { version: v, index: idx }); + } + }; + + let verifying_key = VerifyingKey::from_bytes(&sig_entry.agent_id) + .map_err(|e| SignatureError::InvalidPublicKey { index: idx, detail: e.to_string() })?; + + let signature = Signature::from_bytes(&sig_entry.signature); + + verifying_key.verify(message_bytes, &signature).map_err(|e| { + SignatureError::VerificationFailed { + index: idx, + version: sig_entry.version, + detail: e.to_string(), + } + })?; + } + + Ok(()) +} /// Compute the canonical content hash for v2 (enterprise) signing. /// @@ -37,6 +171,10 @@ use crate::types::{Assertion, ObjectValue}; /// - `source_metadata`: Variable-length, domain-specific /// - `lifecycle`: Can change over time /// +/// **Narrative IS included** because it is content-bearing (methodology, limitations). +/// Changing the narrative changes the assertion's meaning. When `None`, no bytes +/// are added, preserving backward compatibility with pre-narrative hashes. +/// /// # Format /// /// The hash is computed over: @@ -93,6 +231,12 @@ pub fn compute_content_hash_v2(assertion: &Assertion) -> [u8; 32] { hasher.update(b":"); hasher.update(&assertion.timestamp.to_le_bytes()); + // Narrative (only when present, so None preserves backward-compat hash) + if let Some(ref narrative) = assertion.narrative { + hasher.update(b":narrative:"); + hasher.update(narrative.as_bytes()); + } + *hasher.finalize().as_bytes() } @@ -123,6 +267,7 @@ mod tests { visual_hash: None, epoch: None, source_metadata: None, + narrative: None, lifecycle: LifecycleStage::Approved, signatures: vec![], confidence: 0.95, @@ -246,4 +391,46 @@ mod tests { } } } + + #[test] + fn test_content_hash_changes_with_narrative() { + let mut assertion = test_assertion(); + let hash_none = compute_content_hash_v2(&assertion); + + assertion.narrative = + Some("This drug carries a boxed warning for thyroid C-cell tumors.".to_string()); + let hash_some = compute_content_hash_v2(&assertion); + + assert_ne!(hash_none, hash_some, "Narrative should change the content hash"); + } + + #[test] + fn test_content_hash_backward_compat_narrative_none() { + // Capture a hash with narrative: None + let assertion = test_assertion(); + let hash1 = compute_content_hash_v2(&assertion); + + // Build the same assertion again independently + let assertion2 = Assertion { + subject: "Semaglutide".to_string(), + predicate: "has_boxed_warning".to_string(), + object: ObjectValue::Boolean(true), + parent_hash: None, + source_hash: [1u8; 32], + source_class: SourceClass::Regulatory, + visual_hash: None, + epoch: None, + source_metadata: None, + narrative: None, + lifecycle: LifecycleStage::Approved, + signatures: vec![], + confidence: 0.95, + timestamp: 1704067200, + hlc_timestamp: HlcTimestamp::default(), + vector: None, + }; + let hash2 = compute_content_hash_v2(&assertion2); + + assert_eq!(hash1, hash2, "narrative: None must produce identical hash for backward compat"); + } } diff --git a/crates/stemedb-core/src/testing.rs b/crates/stemedb-core/src/testing.rs index 555abe1..70e2e40 100644 --- a/crates/stemedb-core/src/testing.rs +++ b/crates/stemedb-core/src/testing.rs @@ -49,6 +49,7 @@ pub struct AssertionBuilder { visual_hash: Option<[u8; 8]>, epoch: Option<[u8; 32]>, source_metadata: Option>, + narrative: Option, lifecycle: LifecycleStage, signatures: Option>, agent_id: [u8; 32], @@ -77,6 +78,7 @@ impl AssertionBuilder { visual_hash: None, epoch: None, source_metadata: None, + narrative: None, lifecycle: LifecycleStage::Approved, signatures: None, // Will use agent_id to build default agent_id: [1u8; 32], @@ -199,6 +201,12 @@ impl AssertionBuilder { self } + /// Set the narrative (free-text methodology, limitations, caveats). + pub fn narrative(mut self, narrative: &str) -> Self { + self.narrative = Some(narrative.to_string()); + self + } + /// Provide explicit signatures (overrides the default single-signature behavior). pub fn signatures(mut self, signatures: Vec) -> Self { self.signatures = Some(signatures); @@ -226,6 +234,7 @@ impl AssertionBuilder { visual_hash: self.visual_hash, epoch: self.epoch, source_metadata: self.source_metadata, + narrative: self.narrative, lifecycle: self.lifecycle, signatures, confidence: self.confidence, diff --git a/crates/stemedb-core/src/types/assertion.rs b/crates/stemedb-core/src/types/assertion.rs index fbf8892..cbfca46 100644 --- a/crates/stemedb-core/src/types/assertion.rs +++ b/crates/stemedb-core/src/types/assertion.rs @@ -33,6 +33,15 @@ pub struct Assertion { /// Schema is domain-specific (journal info, social metrics, etc.). /// Use `Vec` for rkyv zero-copy compatibility. pub source_metadata: Option>, + /// Free-text narrative explaining methodology, limitations, bias, and caveats. + /// + /// Makes the assertion self-contained: pick it up, read it, understand the + /// full claim without dereferencing anything. Not structured into categories + /// because there are too many kinds of information to pre-categorize. + /// + /// Included in v2 content hash (narrative is content-bearing). + /// Max length: `limits::MAX_NARRATIVE_LEN` (64 KB). + pub narrative: Option, /// The lifecycle stage (Proposed, UnderReview, Approved, Deprecated, Rejected). pub lifecycle: LifecycleStage, diff --git a/crates/stemedb-core/src/types/source_record.rs b/crates/stemedb-core/src/types/source_record.rs index 6d8a25f..6ed515f 100644 --- a/crates/stemedb-core/src/types/source_record.rs +++ b/crates/stemedb-core/src/types/source_record.rs @@ -102,6 +102,10 @@ pub struct SourceRecord { /// Optional curator notes about the source. /// Examples: "Deprecated in favor of RFC 9068", "Under review for accuracy" pub notes: Option, + + /// Optional full-text content of the source document. + /// Populated by pipelines that extract text from PDFs or other formats. + pub content: Option, } impl SourceRecord { @@ -122,6 +126,7 @@ impl SourceRecord { created_at: timestamp, updated_at: timestamp, notes: None, + content: None, } } @@ -137,7 +142,13 @@ impl SourceRecord { updated_at: u64, notes: Option, ) -> Self { - Self { hash, label, url, tier: tier.min(5), status, created_at, updated_at, notes } + Self { hash, label, url, tier: tier.min(5), status, created_at, updated_at, notes, content: None } + } + + /// Set the full-text content of the source document. + pub fn with_content(mut self, content: Option) -> Self { + self.content = content; + self } /// Returns the tier label based on the tier number. @@ -186,6 +197,7 @@ mod tests { assert_eq!(record.created_at, 1000); assert_eq!(record.updated_at, 1000); assert!(record.notes.is_none()); + assert!(record.content.is_none()); } #[test] @@ -263,5 +275,38 @@ mod tests { crate::serde::deserialize(&bytes).expect("Failed to deserialize SourceRecord"); assert_eq!(record, recovered); + assert!(recovered.content.is_none()); + } + + #[test] + fn test_rkyv_roundtrip_with_content() { + let hash = [42u8; 32]; + let record = SourceRecord::new( + hash, + "FDA Approval Letter".to_string(), + None, + 0, + 1000, + ) + .with_content(Some("Full text of the FDA approval letter...".to_string())); + + let bytes = crate::serde::serialize(&record).expect("Failed to serialize SourceRecord"); + let recovered: SourceRecord = + crate::serde::deserialize(&bytes).expect("Failed to deserialize SourceRecord"); + + assert_eq!(record, recovered); + assert_eq!(recovered.content, Some("Full text of the FDA approval letter...".to_string())); + } + + #[test] + fn test_with_content_builder() { + let hash = [1u8; 32]; + let record = SourceRecord::new(hash, "Test".to_string(), None, 0, 1000) + .with_content(Some("content".to_string())); + assert_eq!(record.content, Some("content".to_string())); + + let record_none = SourceRecord::new(hash, "Test".to_string(), None, 0, 1000) + .with_content(None); + assert!(record_none.content.is_none()); } } diff --git a/crates/stemedb-ingest/Cargo.toml b/crates/stemedb-ingest/Cargo.toml index 3898b30..d56c0bf 100644 --- a/crates/stemedb-ingest/Cargo.toml +++ b/crates/stemedb-ingest/Cargo.toml @@ -23,6 +23,8 @@ ed25519-dalek = { version = "2.1", features = ["rand_core"] } uhlc = "0.7" # Async traits async-trait = "0.1" +# Metrics +metrics = "0.23" [dev-dependencies] tempfile = "3.10" diff --git a/crates/stemedb-ingest/src/error.rs b/crates/stemedb-ingest/src/error.rs index 8b16921..5987e6b 100644 --- a/crates/stemedb-ingest/src/error.rs +++ b/crates/stemedb-ingest/src/error.rs @@ -32,3 +32,23 @@ pub enum IngestError { #[error("Input validation failed: {0}")] InputValidation(String), } + +impl IngestError { + /// Returns true if retrying this exact WAL record could succeed. + /// + /// Transient errors (I/O, storage engine) may resolve on retry. + /// Permanent errors (invalid signature, bad input, corrupt serialization) + /// will never succeed — the bytes in the WAL are immutable. + pub fn is_retryable(&self) -> bool { + match self { + // I/O and storage errors: disk might recover, RocksDB might unblock + IngestError::Wal(_) | IngestError::Storage(_) => true, + // The WAL record bytes are immutable — these will never pass + IngestError::InvalidSignature(_) + | IngestError::InputValidation(_) + | IngestError::Serialization(_) => false, + // Worker errors are ambiguous; treat as retryable to be safe + IngestError::Worker(_) => true, + } + } +} diff --git a/crates/stemedb-ingest/src/worker/processing.rs b/crates/stemedb-ingest/src/worker/processing.rs index ca6ceb9..2f063dd 100644 --- a/crates/stemedb-ingest/src/worker/processing.rs +++ b/crates/stemedb-ingest/src/worker/processing.rs @@ -4,9 +4,8 @@ use super::record_types::RECORD_HEADER_SIZE; use super::{IngestWorker, RecordType}; use crate::error::{IngestError, Result}; -use ed25519_dalek::{Signature, Verifier, VerifyingKey}; use stemedb_core::serde::deserialize; -use stemedb_core::signing::compute_content_hash_v2; +use stemedb_core::signing; use stemedb_core::types::{Assertion, Epoch, Hash, Vote}; use stemedb_storage::key_codec; use stemedb_storage::{IndexStore, KVStore, VoteStore}; @@ -82,10 +81,77 @@ impl IngestWorker { let record_type = RecordType::try_from(record.payload[0])?; let data = &record.payload[RECORD_HEADER_SIZE..]; - match record_type { - RecordType::Assertion => self.ingest_assertion(data).await?, - RecordType::Vote => self.ingest_vote(data).await?, - RecordType::Epoch => self.ingest_epoch(data).await?, + let ingest_result = match record_type { + RecordType::Assertion => self.ingest_assertion(data).await, + RecordType::Vote => self.ingest_vote(data).await, + RecordType::Epoch => self.ingest_epoch(data).await, + }; + + if let Err(e) = ingest_result { + if !e.is_retryable() { + // Permanent failure: the WAL record bytes are immutable and will + // never pass validation. Advance the cursor past this poison record + // so it doesn't block all subsequent ingestion. + let skip_offset = self.current_offset; + self.current_offset += bytes_read; + + let cursor_key = key_codec::cursor_key(); + // Best-effort cursor persist. If this fails, on restart we will + // re-encounter this record, classify it as permanent again, and + // skip it. No data is lost. + if let Err(persist_err) = + self.store.put(&cursor_key, &self.current_offset.to_le_bytes()).await + { + warn!( + offset = skip_offset, + error = %persist_err, + "Failed to persist cursor after skipping poison record" + ); + } + + warn!( + record_type = ?record_type, + offset = skip_offset, + new_offset = self.current_offset, + error = %e, + "Skipped permanently invalid WAL record" + ); + + // Store rejection metadata for admin observability. + // Best-effort: failure to persist metadata should not block ingestion. + let rejection_key = key_codec::rejected_record_key(skip_offset); + let now = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map(|d| d.as_secs()) + .unwrap_or(0); + let rejection_json = format!( + r#"{{"offset":{},"record_type":"{:?}","reason":"{}","timestamp":{}}}"#, + skip_offset, + record_type, + e.to_string().replace('"', "'"), + now + ); + if let Err(store_err) = + self.store.put(&rejection_key, rejection_json.as_bytes()).await + { + warn!( + offset = skip_offset, + error = %store_err, + "Failed to store rejection metadata" + ); + } + + metrics::counter!( + "stemedb_ingest_records_skipped_total", + "reason" => e.to_string() + ) + .increment(1); + } + + // Return the error so the run loop can log it. + // For permanent errors the cursor has already advanced; + // for transient errors the cursor is unchanged (will retry). + return Err(e); } let prev_offset = self.current_offset; @@ -170,6 +236,16 @@ impl IngestWorker { // This enables O(1) lookup of "which assertions cite this source?" self.index_store.add_to_source_index(&assertion.source_hash, &assertion_hash).await?; + // Write feed index: \x00FEED:{inverted_ts}:{hash_hex} -> subject + // Uses server clock (not assertion.timestamp) for ingestion ordering. + // This separates "when the claim was made" from "when the system learned about it". + let ingested_at = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map(|d| d.as_secs()) + .unwrap_or(0); + let feed_idx_key = key_codec::feed_key(ingested_at, &hash_hex); + self.store.put(&feed_idx_key, assertion.subject.as_bytes()).await?; + // Insert into vector index if present and assertion has a vector if let (Some(ref vector_index), Some(ref vector)) = (&self.vector_index, &assertion.vector) { @@ -282,6 +358,17 @@ impl IngestWorker { ))); } + // Validate narrative length + if let Some(ref narrative) = assertion.narrative { + if narrative.len() > stemedb_core::limits::MAX_NARRATIVE_LEN { + return Err(IngestError::InputValidation(format!( + "narrative exceeds {} bytes (got {})", + stemedb_core::limits::MAX_NARRATIVE_LEN, + narrative.len() + ))); + } + } + // Validate timestamp: reject if more than 1 hour in future (clock skew protection) let now = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) @@ -300,109 +387,19 @@ impl IngestWorker { /// Verify all Ed25519 signatures on an assertion. /// - /// Supports two signature versions: - /// - Version 1 (legacy): signs `"{subject}:{predicate}"` - only protects those fields - /// - Version 2 (enterprise): signs the BLAKE3 content hash - protects ALL fields - /// - /// For v2 signatures, the content hash is computed from the assertion with - /// empty signatures (canonical form), so tampering with any field except - /// signatures will invalidate the signature. - /// - /// All signatures must be valid for the assertion to be accepted. + /// Delegates to `stemedb_core::signing::verify_assertion_signatures` which + /// is the single source of truth for signature verification logic, shared + /// between the API handler (fail fast) and this worker (defense in depth). fn verify_assertion_signatures(&self, assertion: &Assertion) -> Result<()> { - if assertion.signatures.is_empty() { + signing::verify_assertion_signatures(assertion).map_err(|e| { warn!( subject = %assertion.subject, predicate = %assertion.predicate, - "Assertion has no signatures" + error = %e, + "Signature verification failed" ); - return Err(IngestError::InvalidSignature( - "Assertion must have at least one signature".to_string(), - )); - } - - // Pre-compute v1 message (subject:predicate) - only used if v1 signatures exist - let v1_message = format!("{}:{}", assertion.subject, assertion.predicate); - - // Pre-compute v2 content hash using the shared utility from stemedb-core. - // This must match exactly what the signing code uses in compute_content_hash_v2(). - // The hash covers: subject, predicate, object, source_hash, source_class, confidence, timestamp. - let v2_content_hash: Option<[u8; 32]> = - if assertion.signatures.iter().any(|s| s.version == 2) { - // Debug: show exact number format for comparison with signing - let object_str = match &assertion.object { - stemedb_core::types::ObjectValue::Number(n) => format!("Number({:.17})", n), - other => format!("{:?}", other), - }; - let confidence_str = format!("{:.17}", assertion.confidence); - let hash = compute_content_hash_v2(assertion); - debug!( - subject = %assertion.subject, - predicate = %assertion.predicate, - object = %object_str, - source_hash = %hex::encode(assertion.source_hash), - source_class = ?assertion.source_class, - confidence = %confidence_str, - timestamp = %assertion.timestamp, - content_hash = %hex::encode(hash), - "Computed v2 content hash for verification" - ); - Some(hash) - } else { - None - }; - - for (idx, sig_entry) in assertion.signatures.iter().enumerate() { - // Determine which message was signed based on version - let message_bytes: &[u8] = match sig_entry.version { - 1 => { - // v1 (legacy): signs "{subject}:{predicate}" - v1_message.as_bytes() - } - 2 => { - // v2 (enterprise): signs the content hash computed by compute_content_hash_v2 - v2_content_hash.as_ref().ok_or_else(|| { - IngestError::InvalidSignature( - "v2 signature present but v2_content_hash was not computed".to_string(), - ) - })? - } - v => { - return Err(IngestError::InvalidSignature(format!( - "Unknown signature version {} for signature {}", - v, idx - ))); - } - }; - - // Reconstruct the verifying key from the stored agent_id - let verifying_key = VerifyingKey::from_bytes(&sig_entry.agent_id).map_err(|e| { - IngestError::InvalidSignature(format!( - "Invalid public key for signature {}: {}", - idx, e - )) - })?; - - // Reconstruct the signature - let signature = Signature::from_bytes(&sig_entry.signature); - - // Verify the signature - verifying_key.verify(message_bytes, &signature).map_err(|e| { - IngestError::InvalidSignature(format!( - "Signature {} (v{}) failed verification: {}", - idx, sig_entry.version, e - )) - })?; - - debug!( - agent_id = %hex::encode(&sig_entry.agent_id[..8]), - signature_idx = idx, - version = sig_entry.version, - "Signature verified" - ); - } - - Ok(()) + IngestError::InvalidSignature(e.to_string()) + }) } /// Ingest a vote into the KV store via VoteStore. diff --git a/crates/stemedb-ingest/src/worker/run.rs b/crates/stemedb-ingest/src/worker/run.rs index 66a12eb..ba27b35 100644 --- a/crates/stemedb-ingest/src/worker/run.rs +++ b/crates/stemedb-ingest/src/worker/run.rs @@ -3,7 +3,6 @@ //! Contains the continuous ingestion loop that tails the WAL. use super::IngestWorker; -use crate::error::IngestError; use std::sync::atomic::Ordering; use std::time::Duration; use stemedb_storage::KVStore; @@ -72,18 +71,17 @@ impl IngestWorker { debug!("Error during shutdown (expected): {:?}", e); break; } - match &e { - IngestError::InputValidation(msg) => { - warn!("Rejected invalid input: {}", msg); - } - IngestError::InvalidSignature(msg) => { - warn!("Rejected invalid signature: {}", msg); - } - _ => { - error!("Ingestion error: {:?}", e); - } + + if e.is_retryable() { + // Transient error: back off and retry the same record + error!("Transient ingestion error (will retry): {:?}", e); + tokio::time::sleep(Duration::from_secs(1)).await; + } else { + // Permanent error: step() already advanced the cursor past + // the poison record, so continue immediately to process the + // next record without sleeping. + warn!("Permanent ingestion error (record skipped): {}", e); } - tokio::time::sleep(Duration::from_secs(1)).await; } } } diff --git a/crates/stemedb-ingest/src/worker/tests/signatures.rs b/crates/stemedb-ingest/src/worker/tests/signatures.rs index 00359a5..3c96a0a 100644 --- a/crates/stemedb-ingest/src/worker/tests/signatures.rs +++ b/crates/stemedb-ingest/src/worker/tests/signatures.rs @@ -25,6 +25,7 @@ async fn test_rejects_invalid_signature() { visual_hash: None, epoch: None, source_metadata: None, + narrative: None, lifecycle: LifecycleStage::Proposed, signatures: vec![SignatureEntry { version: 1, @@ -83,6 +84,7 @@ async fn test_rejects_unsigned_assertion() { visual_hash: None, epoch: None, source_metadata: None, + narrative: None, lifecycle: LifecycleStage::Proposed, signatures: vec![], // No signatures! confidence: 0.95, @@ -112,6 +114,88 @@ async fn test_rejects_unsigned_assertion() { ); } +/// Test: Invalid signature advances cursor past poison record so subsequent records process. +/// +/// This is the core regression test for the "assert returns 201 but data not queryable" bug. +/// Previously, an invalid-signature record would cause the IngestWorker to retry the same +/// offset forever, blocking all subsequent records. +#[tokio::test] +async fn test_invalid_signature_skips_and_continues() { + let dir = tempdir().expect("Failed to create temp dir"); + let wal_dir = dir.path().join("wal"); + let db_dir = dir.path().join("db"); + + // Record 1: Invalid signature (poison record) + let bad_assertion = Assertion { + subject: "Bad".to_string(), + predicate: "poison".to_string(), + object: ObjectValue::Text("should be skipped".to_string()), + parent_hash: None, + source_hash: [0u8; 32], + source_class: SourceClass::Expert, + visual_hash: None, + epoch: None, + source_metadata: None, + narrative: None, + lifecycle: LifecycleStage::Proposed, + signatures: vec![SignatureEntry { + version: 1, + agent_id: [1u8; 32], // Invalid Ed25519 public key + signature: [2u8; 64], // Invalid signature + timestamp: 1000, + }], + confidence: 0.95, + timestamp: 1000, + hlc_timestamp: HlcTimestamp::default(), + vector: None, + }; + + // Record 2: Valid signature (should be processed after skipping record 1) + let good_assertion = create_signed_assertion("Good", "valid"); + + let mut journal = Journal::open(&wal_dir).expect("Failed to open journal"); + let store = HybridStore::open(&db_dir).expect("Failed to open store"); + + // Write both records to WAL + journal.append(serialize_assertion(&bad_assertion).expect("ser")).expect("append bad"); + journal.append(serialize_assertion(&good_assertion).expect("ser")).expect("append good"); + + let journal = Arc::new(Mutex::new(journal)); + let store = Arc::new(store); + let mut worker = + IngestWorker::new(journal, store.clone()).await.expect("Failed to create worker"); + + // Step 1: Should fail with InvalidSignature but advance cursor past the poison record + let result1 = worker.step().await; + assert!(result1.is_err(), "Should reject invalid signature"); + assert!( + matches!(result1.unwrap_err(), IngestError::InvalidSignature(_)), + "Should be InvalidSignature" + ); + + // Step 2: Should succeed — the cursor moved past the poison record + let result2 = worker.step().await; + assert!( + result2.is_ok(), + "Should process valid record after skipping poison, got: {:?}", + result2 + ); + let bytes = result2.expect("step 2"); + assert!(bytes > 0, "Should have read bytes from the valid record"); + + // Verify the good assertion was stored + let count_key = key_codec::assertion_count_key(); + let count_entry = store.get(&count_key).await.expect("get").expect("should have count"); + let count = u64::from_le_bytes(count_entry.try_into().expect("8 bytes")); + assert_eq!(count, 1, "Exactly one assertion should be stored (the good one)"); + + // Verify rejection metadata was recorded + use stemedb_storage::KVStore; + let rejected_prefix = key_codec::rejected_records_scan_prefix(); + let rejected = store.scan_prefix(&rejected_prefix).await.expect("scan rejected"); + assert_eq!(rejected.len(), 1, "Should have exactly one rejected record entry"); +} + /// Test: Multi-signature assertions require all signatures to be valid. #[tokio::test] async fn test_multisig_all_must_be_valid() { @@ -136,6 +220,7 @@ async fn test_multisig_all_must_be_valid() { visual_hash: None, epoch: None, source_metadata: None, + narrative: None, lifecycle: LifecycleStage::Proposed, signatures: vec![ // Valid signature diff --git a/crates/stemedb-ingest/src/worker/tests/validation.rs b/crates/stemedb-ingest/src/worker/tests/validation.rs index e7f0fd5..aea9572 100644 --- a/crates/stemedb-ingest/src/worker/tests/validation.rs +++ b/crates/stemedb-ingest/src/worker/tests/validation.rs @@ -29,6 +29,7 @@ async fn test_rejects_high_confidence() { visual_hash: None, epoch: None, source_metadata: None, + narrative: None, lifecycle: LifecycleStage::Proposed, signatures: vec![SignatureEntry { version: 1, @@ -86,6 +87,7 @@ async fn test_rejects_negative_confidence() { visual_hash: None, epoch: None, source_metadata: None, + narrative: None, lifecycle: LifecycleStage::Proposed, signatures: vec![SignatureEntry { version: 1, @@ -213,6 +215,7 @@ async fn test_rejects_oversized_subject() { visual_hash: None, epoch: None, source_metadata: None, + narrative: None, lifecycle: LifecycleStage::Proposed, signatures: vec![SignatureEntry { version: 1, @@ -273,6 +276,7 @@ async fn test_rejects_oversized_predicate() { visual_hash: None, epoch: None, source_metadata: None, + narrative: None, lifecycle: LifecycleStage::Proposed, signatures: vec![SignatureEntry { version: 1, @@ -335,6 +339,7 @@ async fn test_accepts_exact_max_subject_length() { visual_hash: None, epoch: None, source_metadata: None, + narrative: None, lifecycle: LifecycleStage::Proposed, signatures: vec![SignatureEntry { version: 1, @@ -393,6 +398,7 @@ async fn test_accepts_exact_max_predicate_length() { visual_hash: None, epoch: None, source_metadata: None, + narrative: None, lifecycle: LifecycleStage::Proposed, signatures: vec![SignatureEntry { version: 1, @@ -446,6 +452,7 @@ async fn test_rejects_nan_confidence() { visual_hash: None, epoch: None, source_metadata: None, + narrative: None, lifecycle: LifecycleStage::Proposed, signatures: vec![SignatureEntry { version: 1, diff --git a/crates/stemedb-ingest/src/worker/tests/validation_boundaries.rs b/crates/stemedb-ingest/src/worker/tests/validation_boundaries.rs index 5b916c3..a1617cc 100644 --- a/crates/stemedb-ingest/src/worker/tests/validation_boundaries.rs +++ b/crates/stemedb-ingest/src/worker/tests/validation_boundaries.rs @@ -29,6 +29,7 @@ async fn test_rejects_infinite_confidence() { visual_hash: None, epoch: None, source_metadata: None, + narrative: None, lifecycle: LifecycleStage::Proposed, signatures: vec![SignatureEntry { version: 1, @@ -172,6 +173,7 @@ async fn test_rejects_future_timestamp() { visual_hash: None, epoch: None, source_metadata: None, + narrative: None, lifecycle: LifecycleStage::Proposed, signatures: vec![SignatureEntry { version: 1, @@ -237,6 +239,7 @@ async fn test_accepts_near_future_timestamp() { visual_hash: None, epoch: None, source_metadata: None, + narrative: None, lifecycle: LifecycleStage::Proposed, signatures: vec![SignatureEntry { version: 1, @@ -287,6 +290,7 @@ async fn test_accepts_zero_confidence() { visual_hash: None, epoch: None, source_metadata: None, + narrative: None, lifecycle: LifecycleStage::Proposed, signatures: vec![SignatureEntry { version: 1, @@ -337,6 +341,7 @@ async fn test_accepts_one_confidence() { visual_hash: None, epoch: None, source_metadata: None, + narrative: None, lifecycle: LifecycleStage::Proposed, signatures: vec![SignatureEntry { version: 1, diff --git a/crates/stemedb-ontology/src/dto/conversions.rs b/crates/stemedb-ontology/src/dto/conversions.rs index e2c7acb..c4862eb 100644 --- a/crates/stemedb-ontology/src/dto/conversions.rs +++ b/crates/stemedb-ontology/src/dto/conversions.rs @@ -24,6 +24,7 @@ pub fn assertion_to_request(assertion: &Assertion) -> CreateAssertionRequest { .source_metadata .as_ref() .map(|b| String::from_utf8_lossy(b).into_owned()), + narrative: assertion.narrative.clone(), // Include timestamps for v2 signature verification timestamp: Some(assertion.timestamp), hlc_timestamp: Some(HlcTimestampDto { @@ -94,6 +95,7 @@ mod tests { visual_hash: None, epoch: None, source_metadata: None, + narrative: None, lifecycle: LifecycleStage::Approved, signatures: vec![SignatureEntry { agent_id: [1u8; 32], diff --git a/crates/stemedb-ontology/src/dto/requests.rs b/crates/stemedb-ontology/src/dto/requests.rs index b2bd133..0fcfba4 100644 --- a/crates/stemedb-ontology/src/dto/requests.rs +++ b/crates/stemedb-ontology/src/dto/requests.rs @@ -41,6 +41,10 @@ pub struct CreateAssertionRequest { #[serde(skip_serializing_if = "Option::is_none")] pub source_metadata: Option, + /// Free-text narrative explaining methodology, limitations, bias, and caveats. + #[serde(skip_serializing_if = "Option::is_none")] + pub narrative: Option, + /// Unix timestamp when the assertion was created. /// Required for v2 signatures to verify correctly. #[serde(skip_serializing_if = "Option::is_none")] diff --git a/crates/stemedb-ontology/src/dto/responses.rs b/crates/stemedb-ontology/src/dto/responses.rs index a58ce2b..605d3b1 100644 --- a/crates/stemedb-ontology/src/dto/responses.rs +++ b/crates/stemedb-ontology/src/dto/responses.rs @@ -66,6 +66,10 @@ pub struct AssertionDto { /// Structured source metadata as a JSON string (optional). #[serde(skip_serializing_if = "Option::is_none")] pub source_metadata: Option, + + /// Free-text narrative explaining methodology, limitations, bias, and caveats. + #[serde(skip_serializing_if = "Option::is_none")] + pub narrative: Option, } /// Response from a query operation. diff --git a/crates/stemedb-ontology/src/pharma/extractors/mod.rs b/crates/stemedb-ontology/src/pharma/extractors/mod.rs index 46ccd18..8c0cf3d 100644 --- a/crates/stemedb-ontology/src/pharma/extractors/mod.rs +++ b/crates/stemedb-ontology/src/pharma/extractors/mod.rs @@ -233,6 +233,7 @@ impl MedicalClaim { visual_hash: None, epoch: None, source_metadata, + narrative: None, lifecycle, signatures: Vec::new(), confidence: self.confidence, diff --git a/crates/stemedb-query/src/engine/mod.rs b/crates/stemedb-query/src/engine/mod.rs index c266db3..4e9231c 100644 --- a/crates/stemedb-query/src/engine/mod.rs +++ b/crates/stemedb-query/src/engine/mod.rs @@ -236,9 +236,12 @@ impl QueryEngine { Ok(changes) } - /// Deserialize an assertion using the canonical serde module. + /// Deserialize an assertion with backward compatibility. + /// + /// Tries current format first, then falls back to legacy (pre-narrative) + /// format for assertions serialized before the schema change. pub(super) fn deserialize_assertion(&self, data: &[u8]) -> Result { - stemedb_core::serde::deserialize(data) + stemedb_core::serde::deserialize_assertion_compat(data) .map_err(|e| QueryError::Deserialization(e.to_string())) } diff --git a/crates/stemedb-query/src/materializer/mod.rs b/crates/stemedb-query/src/materializer/mod.rs index c3dbc61..c10f148 100644 --- a/crates/stemedb-query/src/materializer/mod.rs +++ b/crates/stemedb-query/src/materializer/mod.rs @@ -362,7 +362,7 @@ impl Materializer { for hash in hash_list { let key = key_codec::assertion_key(subject, &hex::encode(hash)); if let Some(data) = self.store.get(&key).await? { - match stemedb_core::serde::deserialize::(&data) { + match stemedb_core::serde::deserialize_assertion_compat(&data) { Ok(assertion) => candidates.push(assertion), Err(e) => { debug!( diff --git a/crates/stemedb-sim/src/agent.rs b/crates/stemedb-sim/src/agent.rs index 7642e37..5cf945d 100644 --- a/crates/stemedb-sim/src/agent.rs +++ b/crates/stemedb-sim/src/agent.rs @@ -57,6 +57,7 @@ impl Agent { visual_hash: None, epoch: None, source_metadata: None, + narrative: None, lifecycle, signatures: vec![SignatureEntry { agent_id: self.verifying_key.to_bytes(), diff --git a/crates/stemedb-storage/src/hybrid_backend.rs b/crates/stemedb-storage/src/hybrid_backend.rs index 92fe0b3..aba8938 100644 --- a/crates/stemedb-storage/src/hybrid_backend.rs +++ b/crates/stemedb-storage/src/hybrid_backend.rs @@ -106,6 +106,26 @@ impl HybridStore { Ok(Self { fjall, redb, _temp_dir: Some(temp_dir) }) } + + /// Scan all assertion key-value pairs from the Fjall backend. + /// + /// This scans all keys in Fjall and returns only those with the `H:` tag + /// (assertion data). Used by the admin rebuild-indexes endpoint to + /// reconstruct missing Redb secondary indexes. + /// + /// Returns `Vec<(key, value)>` where keys are `{subject}\x00H:{hash_hex}`. + #[instrument(skip_all)] + pub async fn scan_fjall_assertions(&self) -> Result, Vec)>> { + let all_fjall = self.fjall.scan_prefix(b"").await?; + let assertions: Vec<(Vec, Vec)> = all_fjall + .into_iter() + .filter(|(key, _)| { + let tag = key_codec::extract_tag(key); + tag.starts_with(b"H:") + }) + .collect(); + Ok(assertions) + } } #[async_trait] diff --git a/crates/stemedb-storage/src/key_codec/global_keys.rs b/crates/stemedb-storage/src/key_codec/global_keys.rs index e2fc4eb..7cbb891 100644 --- a/crates/stemedb-storage/src/key_codec/global_keys.rs +++ b/crates/stemedb-storage/src/key_codec/global_keys.rs @@ -113,3 +113,33 @@ pub fn assertion_count_key() -> Vec { pub fn trust_rank_scan_prefix() -> Vec { global_key(b"TRUST:", b"") } + +/// Rejected WAL record key: `\x00REJECTED:{offset}` +/// +/// Stores metadata about WAL records that were permanently skipped +/// by the IngestWorker (invalid signatures, validation failures, etc.) +pub fn rejected_record_key(offset: u64) -> Vec { + global_key(b"REJECTED:", offset.to_string().as_bytes()) +} + +/// Rejected records scan prefix: `\x00REJECTED:` +pub fn rejected_records_scan_prefix() -> Vec { + global_key(b"REJECTED:", b"") +} + +/// Feed index key: `\x00FEED:{inverted_ts_hex}:{hash_hex}` +/// +/// Uses inverted timestamp (`u64::MAX - ingested_at`) so lexicographic +/// scan order = reverse chronological (newest first). +/// Value stores the subject so the feed handler can construct the +/// assertion key without a reverse lookup. +pub fn feed_key(ingested_at: u64, hash_hex: &str) -> Vec { + let inverted = u64::MAX - ingested_at; + let suffix = format!("{}:{}", hex::encode(inverted.to_be_bytes()), hash_hex); + global_key(b"FEED:", suffix.as_bytes()) +} + +/// Feed index scan prefix: `\x00FEED:` +pub fn feed_scan_prefix() -> Vec { + global_key(b"FEED:", b"") +} diff --git a/crates/stemedb-storage/src/key_codec/mod.rs b/crates/stemedb-storage/src/key_codec/mod.rs index c32740a..cb9748a 100644 --- a/crates/stemedb-storage/src/key_codec/mod.rs +++ b/crates/stemedb-storage/src/key_codec/mod.rs @@ -57,10 +57,10 @@ pub use subject_keys::{ // Global keys pub use global_keys::{ assertion_count_key, audit_agent_index_key, audit_agent_prefix, audit_key, audit_scan_prefix, - cursor_key, epoch_key, escalation_key, escalation_scan_prefix, gs_verified_key, quota_key, - quota_limit_key, superseded_key, supersession_index_key, supersession_index_prefix, - supersession_key, trust_pack_key, trust_pack_scan_prefix, trust_rank_key, - trust_rank_scan_prefix, + cursor_key, epoch_key, escalation_key, escalation_scan_prefix, feed_key, feed_scan_prefix, + gs_verified_key, quota_key, quota_limit_key, rejected_record_key, rejected_records_scan_prefix, + superseded_key, supersession_index_key, supersession_index_prefix, supersession_key, + trust_pack_key, trust_pack_scan_prefix, trust_rank_key, trust_rank_scan_prefix, }; // Index keys diff --git a/crates/stemedb-storage/src/key_codec/tests.rs b/crates/stemedb-storage/src/key_codec/tests.rs index 9d49770..c9301ce 100644 --- a/crates/stemedb-storage/src/key_codec/tests.rs +++ b/crates/stemedb-storage/src/key_codec/tests.rs @@ -229,3 +229,45 @@ fn test_global_keys_sort_first() { let subject = assertion_key("Apple", "abc"); assert!(global < subject, "Global keys should sort before subject keys"); } + +#[test] +fn test_feed_key_newest_first_ordering() { + let k_older = feed_key(1000, "aaaa"); + let k_newer = feed_key(2000, "bbbb"); + // Newer timestamp should sort BEFORE older (inverted for newest-first) + assert!(k_newer < k_older, "Newer feed keys should sort before older ones"); +} + +#[test] +fn test_feed_key_same_timestamp_tiebreak() { + let k1 = feed_key(1000, "aaaa"); + let k2 = feed_key(1000, "zzzz"); + // Same timestamp: lexicographic tiebreak on hash_hex + assert!(k1 < k2); +} + +#[test] +fn test_feed_key_starts_with_scan_prefix() { + let prefix = feed_scan_prefix(); + let k = feed_key(1000, "abc123def456"); + assert!(k.starts_with(&prefix), "Feed key should start with feed scan prefix"); +} + +#[test] +fn test_feed_key_format() { + let k = feed_key(0, "deadbeef"); + // \x00FEED: prefix + assert_eq!(&k[..6], b"\x00FEED:"); + // With ingested_at=0, inverted = u64::MAX, hex = "ffffffffffffffff" + assert_eq!(&k[6..22], b"ffffffffffffffff"); + // Separator + assert_eq!(k[22], b':'); + // hash_hex + assert_eq!(&k[23..], b"deadbeef"); +} + +#[test] +fn test_feed_scan_prefix() { + let prefix = feed_scan_prefix(); + assert_eq!(prefix, b"\x00FEED:"); +} diff --git a/crates/stemedb-storage/src/serde_helpers.rs b/crates/stemedb-storage/src/serde_helpers.rs index 1526de9..6433e9d 100644 --- a/crates/stemedb-storage/src/serde_helpers.rs +++ b/crates/stemedb-storage/src/serde_helpers.rs @@ -44,6 +44,16 @@ where stemedb_core::serde::deserialize(data).map_err(|e| StorageError::Serialization(e.to_string())) } +/// Deserialize a SourceRecord with backward compatibility for the pre-content layout. +/// +/// Maps deserialization errors to [`StorageError::Serialization`]. +pub fn deserialize_source_record_compat( + data: &[u8], +) -> Result { + stemedb_core::serde::deserialize_source_record_compat(data) + .map_err(|e| StorageError::Serialization(e.to_string())) +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/stemedb-storage/src/source_registry/generic.rs b/crates/stemedb-storage/src/source_registry/generic.rs index 2701563..9128b56 100644 --- a/crates/stemedb-storage/src/source_registry/generic.rs +++ b/crates/stemedb-storage/src/source_registry/generic.rs @@ -7,7 +7,7 @@ use tracing::{debug, instrument}; use super::SourceRegistry; use crate::error::{Result, StorageError}; use crate::key_codec; -use crate::serde_helpers::{deserialize, serialize}; +use crate::serde_helpers::{deserialize_source_record_compat, serialize}; use crate::traits::KVStore; /// Generic SourceRegistry implementation backed by any KVStore. @@ -80,7 +80,7 @@ impl SourceRegistry for GenericSourceRegistry { match self.store.get(&key).await? { Some(data) => { - let record: SourceRecord = deserialize(&data)?; + let record: SourceRecord = deserialize_source_record_compat(&data)?; Ok(Some(record)) } None => Ok(None), diff --git a/crates/stemedb-sync/src/anti_entropy/sync_ops.rs b/crates/stemedb-sync/src/anti_entropy/sync_ops.rs index 4309411..570cd69 100644 --- a/crates/stemedb-sync/src/anti_entropy/sync_ops.rs +++ b/crates/stemedb-sync/src/anti_entropy/sync_ops.rs @@ -9,8 +9,8 @@ use crate::error::Result; use metrics::{counter, gauge}; use std::collections::HashSet; use std::sync::atomic::Ordering; -use stemedb_core::serde::deserialize; -use stemedb_core::types::{detect_clock_skew, Assertion, HlcTimestamp}; +use stemedb_core::serde::deserialize_assertion_compat; +use stemedb_core::types::{detect_clock_skew, HlcTimestamp}; use stemedb_rpc::proto::{FetchRequest, GetLeavesRequest, RootExchangeRequest}; use stemedb_storage::crdt::AssertionTransfer; use stemedb_storage::KVStore; @@ -201,7 +201,7 @@ impl AntiEntropyWorker { } // Extract subject and HLC timestamp from the assertion data - let (subject, remote_hlc) = match deserialize::(&transfer.data) { + let (subject, remote_hlc) = match deserialize_assertion_compat(&transfer.data) { Ok(assertion) => (assertion.subject.clone(), assertion.hlc_timestamp), Err(e) => { warn!( diff --git a/docs/data-structures.md b/docs/data-structures.md index 5bcd1c0..c24f22d 100644 --- a/docs/data-structures.md +++ b/docs/data-structures.md @@ -1,6 +1,6 @@ # StemeDB Data Structures -> **Last Updated:** 2026-01-31 +> **Last Updated:** 2026-02-19 > **Source:** `crates/stemedb-core/src/types.rs` This document describes the core data structures in StemeDB (Episteme). These types form the foundation of the "Git for Truth" knowledge graph. @@ -417,6 +417,50 @@ pub struct TrustPack { --- +## The SourceRecord (Source Registry) + +The Source Registry maps content-addressed source hashes to human-readable metadata. This enables the dashboard to show "FDA Approval Letter for Wegovy" instead of a raw BLAKE3 hash. + +```rust +pub struct SourceRecord { + /// Content-addressed hash of the source (BLAKE3, 32 bytes). + pub hash: [u8; 32], + + /// Human-readable label. + pub label: String, + + /// Optional URL where the source can be accessed. + pub url: Option, + + /// Authority tier (0-5), matching SourceClass. + pub tier: u8, + + /// Current status (Active, Deprecated, Quarantined). + pub status: SourceStatus, + + /// HLC timestamp when the record was created. + pub created_at: u64, + + /// HLC timestamp of the last update. + pub updated_at: u64, + + /// Optional curator notes about the source. + pub notes: Option, + + /// Optional full-text content of the source document. + /// Populated by pipelines that extract text from PDFs. + /// Max size: 1 MB (MAX_SOURCE_CONTENT_LEN). + pub content: Option, +} +``` + +**Key Points:** +- **Status lifecycle:** Active → Deprecated or Quarantined (curator-driven) +- **Content field:** Stores extracted document text (e.g., from `pdftotext`). Stripped from list responses (`GET /v1/sources`) to avoid returning megabytes; included in single-source responses (`GET /v1/sources/{hash}`) +- **rkyv compat:** Uses `deserialize_source_record_compat()` for backward compatibility with data written before the `content` field was added + +--- + ## Serialization All types use `rkyv` for zero-copy deserialization: @@ -433,6 +477,17 @@ let assertion: Assertion = deserialize(&bytes)?; **Critical Rule**: Never use raw `AllocSerializer` in production code. Always use `stemedb_core::serde::{serialize, deserialize}`. +### Schema Evolution (rkyv Compat) + +rkyv does **not** support schema evolution. When a field is added to a struct, old data can't be deserialized with the new struct. The solution is a legacy compat pattern: + +| Type | Compat Function | Legacy Struct | +|------|----------------|---------------| +| `Assertion` | `deserialize_assertion_compat()` | `LegacyAssertion` (pre-`narrative`) | +| `SourceRecord` | `deserialize_source_record_compat()` | `LegacySourceRecord` (pre-`content`) | + +All assertion deserialization should use `deserialize_assertion_compat()`. All source record deserialization should use `deserialize_source_record_compat()`. When adding fields to rkyv structs in the future, always add a legacy compat deserializer following this pattern. + --- ## Relationship Diagram diff --git a/sdk/go/steme/assertion.go b/sdk/go/steme/assertion.go index 505fed4..41e21b9 100644 --- a/sdk/go/steme/assertion.go +++ b/sdk/go/steme/assertion.go @@ -45,6 +45,9 @@ type Assertion struct { // Semantic embedding vector (optional) Vector []float32 `json:"vector,omitempty"` + + // Free-text narrative explaining methodology, limitations, bias, and caveats (optional) + Narrative *string `json:"narrative,omitempty"` } // AssertionBuilder provides a fluent API for building assertions. @@ -150,6 +153,12 @@ func (b *AssertionBuilder) WithEpoch(epochHex string) *AssertionBuilder { return b } +// WithNarrative sets the free-text narrative (methodology, limitations, caveats). +func (b *AssertionBuilder) WithNarrative(narrative string) *AssertionBuilder { + b.assertion.Narrative = &narrative + return b +} + // WithVector sets the semantic embedding vector. func (b *AssertionBuilder) WithVector(vector []float32) *AssertionBuilder { b.assertion.Vector = vector diff --git a/sdk/go/steme/query.go b/sdk/go/steme/query.go index b1ffd85..e58dce5 100644 --- a/sdk/go/steme/query.go +++ b/sdk/go/steme/query.go @@ -174,6 +174,9 @@ type AssertionResponse struct { // Semantic embedding vector (optional) Vector []float32 `json:"vector,omitempty"` + + // Free-text narrative explaining methodology, limitations, bias, and caveats (optional) + Narrative *string `json:"narrative,omitempty"` } // CreateResponse represents the response from a create operation.