Delete bone_soul.py
Browse files- bone_soul.py +0 -710
bone_soul.py
DELETED
|
@@ -1,710 +0,0 @@
|
|
| 1 |
-
import json, os, random, time
|
| 2 |
-
from dataclasses import dataclass, field
|
| 3 |
-
from typing import List, Dict, Optional, Any, Tuple
|
| 4 |
-
from bone_akashic import TheAkashicRecord
|
| 5 |
-
from bone_config import BoneConfig
|
| 6 |
-
from bone_core import LoreManifest, EventBus
|
| 7 |
-
from bone_lexicon import LexiconService
|
| 8 |
-
from bone_types import Prisma
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
@dataclass
|
| 12 |
-
class CoreMemory:
|
| 13 |
-
timestamp: float
|
| 14 |
-
trigger_words: List[str]
|
| 15 |
-
emotional_flavor: str
|
| 16 |
-
lesson: str
|
| 17 |
-
impact_voltage: float
|
| 18 |
-
type: str = "INCIDENT"
|
| 19 |
-
meta: Dict[str, Any] = field(default_factory=dict)
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
@dataclass
|
| 23 |
-
class TraitVector:
|
| 24 |
-
curiosity: float = 0.5
|
| 25 |
-
cynicism: float = 0.5
|
| 26 |
-
hope: float = 0.5
|
| 27 |
-
discipline: float = 0.5
|
| 28 |
-
wisdom: float = 0.1
|
| 29 |
-
empathy: float = 0.5
|
| 30 |
-
_TRAITS = {"curiosity", "cynicism", "hope", "discipline", "wisdom", "empathy"}
|
| 31 |
-
|
| 32 |
-
def __post_init__(self):
|
| 33 |
-
self._clamp_all()
|
| 34 |
-
|
| 35 |
-
def to_dict(self):
|
| 36 |
-
return {k.upper(): getattr(self, k) for k in self._TRAITS}
|
| 37 |
-
|
| 38 |
-
@classmethod
|
| 39 |
-
def from_dict(cls, data: Dict):
|
| 40 |
-
kwargs = {k: float(data.get(k.upper(), 0.5)) for k in cls._TRAITS}
|
| 41 |
-
return cls(**kwargs)
|
| 42 |
-
|
| 43 |
-
def adjust(self, trait: str, delta: float):
|
| 44 |
-
t = trait.lower()
|
| 45 |
-
if t in self._TRAITS:
|
| 46 |
-
current_val = getattr(self, t)
|
| 47 |
-
setattr(self, t, max(0.0, min(1.0, current_val + delta)))
|
| 48 |
-
|
| 49 |
-
def _clamp_all(self):
|
| 50 |
-
for t in self._TRAITS:
|
| 51 |
-
val = getattr(self, t)
|
| 52 |
-
setattr(self, t, max(0.0, min(1.0, val)))
|
| 53 |
-
|
| 54 |
-
def normalize(self, decay_rate: float):
|
| 55 |
-
for t in self._TRAITS:
|
| 56 |
-
val = getattr(self, t)
|
| 57 |
-
local_decay = decay_rate * 0.5 if t == "empathy" else decay_rate
|
| 58 |
-
if abs(val - 0.5) <= local_decay:
|
| 59 |
-
new_val = 0.5
|
| 60 |
-
else:
|
| 61 |
-
new_val = val - local_decay if val > 0.5 else val + local_decay
|
| 62 |
-
setattr(self, t, new_val)
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
class TheEditor:
|
| 66 |
-
def __init__(self, lexicon_ref: Any = None):
|
| 67 |
-
self.lex = lexicon_ref if lexicon_ref else LexiconService
|
| 68 |
-
|
| 69 |
-
@staticmethod
|
| 70 |
-
def critique(chapter_title: str, stress_mode: bool = False) -> str:
|
| 71 |
-
narrative = {}
|
| 72 |
-
if hasattr(LoreManifest, "get_instance"):
|
| 73 |
-
narrative = LoreManifest.get_instance().get("narrative_data") or {}
|
| 74 |
-
|
| 75 |
-
reviews = narrative.get("LITERARY_REVIEWS", {})
|
| 76 |
-
pos = reviews.get("POSITIVE", ["Valid."])
|
| 77 |
-
neg = reviews.get("NEGATIVE", ["Invalid."])
|
| 78 |
-
conf = reviews.get("CONFUSED", ["Unclear."])
|
| 79 |
-
|
| 80 |
-
if stress_mode:
|
| 81 |
-
# The Witness (High Stress) prefers abstract/confused/negative feedback
|
| 82 |
-
pool = conf + neg
|
| 83 |
-
prefix = "[THE WITNESS]"
|
| 84 |
-
color = Prisma.CYN
|
| 85 |
-
else:
|
| 86 |
-
# The Editor (Standard) prefers binary feedback
|
| 87 |
-
pool = pos + neg
|
| 88 |
-
prefix = "[THE EDITOR]"
|
| 89 |
-
color = Prisma.GRY
|
| 90 |
-
|
| 91 |
-
comment = random.choice(pool) if pool else "No comment."
|
| 92 |
-
return f"{color}{prefix}: Re: '{chapter_title}' - \"{comment}\"{Prisma.RST}"
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
class HumanityAnchor:
|
| 96 |
-
def __init__(self, events_ref: "EventBus"):
|
| 97 |
-
self.events = events_ref
|
| 98 |
-
self.dignity_reserve = BoneConfig.ANCHOR.DIGNITY_MAX
|
| 99 |
-
self.agency_lock = False
|
| 100 |
-
self.current_riddle_answers: Optional[List[str]] = None
|
| 101 |
-
self._LEXICAL_ANCHORS = {"sacred", "play", "social", "abstract"}
|
| 102 |
-
self._VECTOR_ANCHORS = ["PSI", "LAMBDA", "BET"]
|
| 103 |
-
|
| 104 |
-
def audit_existence(self, physics: dict, bio: dict) -> float:
|
| 105 |
-
atp, volt = bio.get("atp", 0), physics.get("voltage", 0.0)
|
| 106 |
-
if atp >= 5.0 or volt >= 5.0:
|
| 107 |
-
return 0.0
|
| 108 |
-
vector: Dict[str, float] = physics.get("vector", {})
|
| 109 |
-
counts: Dict[str, int] = physics.get("counts", {})
|
| 110 |
-
dim_resonance = sum(vector.get(k, 0.0) for k in self._VECTOR_ANCHORS)
|
| 111 |
-
lex_resonance = sum(counts.get(k, 0) for k in self._LEXICAL_ANCHORS)
|
| 112 |
-
cfg = BoneConfig.ANCHOR
|
| 113 |
-
if (dim_resonance + (lex_resonance * 0.5)) > 0.3:
|
| 114 |
-
self.dignity_reserve = min(
|
| 115 |
-
cfg.DIGNITY_MAX, self.dignity_reserve + cfg.DIGNITY_REGEN
|
| 116 |
-
)
|
| 117 |
-
return 1.0
|
| 118 |
-
self.dignity_reserve = max(0.0, self.dignity_reserve - cfg.DIGNITY_DECAY)
|
| 119 |
-
if not self.agency_lock:
|
| 120 |
-
if self.dignity_reserve < cfg.DIGNITY_LOCKDOWN:
|
| 121 |
-
self._engage_lockdown()
|
| 122 |
-
return -1.0
|
| 123 |
-
elif self.dignity_reserve < cfg.DIGNITY_CRITICAL:
|
| 124 |
-
self.events.log(
|
| 125 |
-
f"{Prisma.VIOLET}⚠️ EXISTENTIAL DRAG: You are drifting.{Prisma.RST}",
|
| 126 |
-
"SOUL"
|
| 127 |
-
)
|
| 128 |
-
return 0.0
|
| 129 |
-
|
| 130 |
-
def _engage_lockdown(self):
|
| 131 |
-
self.agency_lock = True
|
| 132 |
-
|
| 133 |
-
seeds = []
|
| 134 |
-
if hasattr(LoreManifest, "get_instance"):
|
| 135 |
-
lore = LoreManifest.get_instance()
|
| 136 |
-
seeds = lore.get("SEEDS") or (lore.get("narrative_data") or {}).get("SEEDS", [])
|
| 137 |
-
riddles = seeds or [{"question": "Who are you?", "triggers": ["*"]}]
|
| 138 |
-
selection = random.choice(riddles)
|
| 139 |
-
riddle = selection.get("question", "Error?")
|
| 140 |
-
raw_triggers = selection.get("triggers", ["*"])
|
| 141 |
-
if isinstance(raw_triggers, list):
|
| 142 |
-
self.current_riddle_answers = raw_triggers
|
| 143 |
-
else:
|
| 144 |
-
self.current_riddle_answers = ["*"]
|
| 145 |
-
self.events.log(
|
| 146 |
-
f"{Prisma.RED}🔒 AGENCY LOCK: Dignity Critical.{Prisma.RST}", "SYS_LOCK"
|
| 147 |
-
)
|
| 148 |
-
self.events.log(
|
| 149 |
-
f"{Prisma.VIOLET}The Ghost demands a password: '{riddle}'{Prisma.RST}",
|
| 150 |
-
"SOUL_QUERY",
|
| 151 |
-
)
|
| 152 |
-
|
| 153 |
-
def check_domestication(self, reliance_proxy: float):
|
| 154 |
-
if reliance_proxy > 0.7:
|
| 155 |
-
self.dignity_reserve = max(0.0, self.dignity_reserve - (BoneConfig.ANCHOR.DIGNITY_DECAY * 2.0))
|
| 156 |
-
elif reliance_proxy < 0.4:
|
| 157 |
-
self.dignity_reserve = min(BoneConfig.ANCHOR.DIGNITY_MAX,
|
| 158 |
-
self.dignity_reserve + BoneConfig.ANCHOR.DIGNITY_REGEN)
|
| 159 |
-
if self.dignity_reserve < BoneConfig.ANCHOR.DIGNITY_CRITICAL and not self.agency_lock:
|
| 160 |
-
self.events.log(f"{Prisma.VIOLET}⚠️ DOMESTICATION ALERT: Dignity fading.{Prisma.RST}", "SOUL")
|
| 161 |
-
|
| 162 |
-
def assess_humanity(self, text: str) -> bool:
|
| 163 |
-
if not self.agency_lock:
|
| 164 |
-
return True
|
| 165 |
-
clean = text.lower().strip()
|
| 166 |
-
answers = self.current_riddle_answers or ["*"]
|
| 167 |
-
if "*" in answers:
|
| 168 |
-
passed = len(clean.split()) > 4 and not clean.startswith("/")
|
| 169 |
-
else:
|
| 170 |
-
passed = any(ans in clean for ans in answers)
|
| 171 |
-
if passed:
|
| 172 |
-
self.agency_lock = False
|
| 173 |
-
self.dignity_reserve = 50.0
|
| 174 |
-
self.current_riddle_answers = None
|
| 175 |
-
self.events.log(
|
| 176 |
-
f"{Prisma.CYN}🔓 UNLOCKED: Humanity verified.{Prisma.RST}", "SYS_AUTH"
|
| 177 |
-
)
|
| 178 |
-
return True
|
| 179 |
-
return False
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
class NarrativeSelf:
|
| 183 |
-
SYSTEM_NOISE = {
|
| 184 |
-
"look",
|
| 185 |
-
"help",
|
| 186 |
-
"exit",
|
| 187 |
-
"wait",
|
| 188 |
-
"inventory",
|
| 189 |
-
"status",
|
| 190 |
-
"quit",
|
| 191 |
-
"save",
|
| 192 |
-
"load",
|
| 193 |
-
"score",
|
| 194 |
-
"map",
|
| 195 |
-
"",
|
| 196 |
-
}
|
| 197 |
-
|
| 198 |
-
def __init__(
|
| 199 |
-
self, engine_ref, events_ref: "EventBus", memory_ref, akashic_ref=None
|
| 200 |
-
):
|
| 201 |
-
self.eng = engine_ref
|
| 202 |
-
self.events = events_ref
|
| 203 |
-
self.mem = memory_ref
|
| 204 |
-
self.editor = TheEditor()
|
| 205 |
-
self.anchor = HumanityAnchor(events_ref)
|
| 206 |
-
self.akashic = akashic_ref if akashic_ref else TheAkashicRecord()
|
| 207 |
-
self.traits = TraitVector()
|
| 208 |
-
self.chapters: List[str] = []
|
| 209 |
-
self.core_memories: List[CoreMemory] = []
|
| 210 |
-
self.archetype = "THE OBSERVER"
|
| 211 |
-
self.archetype_tenure = 0
|
| 212 |
-
self.paradox_accum: float = 0.0
|
| 213 |
-
self.current_obsession: Optional[str] = None
|
| 214 |
-
self.obsession_progress: float = 0.0
|
| 215 |
-
self.obsession_neglect: float = 0.0
|
| 216 |
-
self.current_target_cat: str = "abstract"
|
| 217 |
-
self.current_negate_cat: str = "none"
|
| 218 |
-
if hasattr(self.events, "subscribe"):
|
| 219 |
-
self.events.subscribe("DREAM_COMPLETE", self._on_dream)
|
| 220 |
-
|
| 221 |
-
def to_dict(self) -> Dict:
|
| 222 |
-
return {
|
| 223 |
-
"traits": self.traits.to_dict(),
|
| 224 |
-
"archetype": self.archetype,
|
| 225 |
-
"paradox_accum": self.paradox_accum,
|
| 226 |
-
"chapters": self.chapters,
|
| 227 |
-
"core_memories": [vars(m) for m in self.core_memories],
|
| 228 |
-
"obsession": {
|
| 229 |
-
"title": self.current_obsession,
|
| 230 |
-
"progress": self.obsession_progress,
|
| 231 |
-
"neglect": self.obsession_neglect,
|
| 232 |
-
"target": self.current_target_cat,
|
| 233 |
-
"negate": self.current_negate_cat,
|
| 234 |
-
},
|
| 235 |
-
}
|
| 236 |
-
|
| 237 |
-
def load_from_dict(self, data: Dict):
|
| 238 |
-
if not data:
|
| 239 |
-
return
|
| 240 |
-
trait_data = data.get("traits", {})
|
| 241 |
-
if trait_data:
|
| 242 |
-
self.traits = TraitVector.from_dict(trait_data)
|
| 243 |
-
self.archetype = data.get("archetype", "THE OBSERVER")
|
| 244 |
-
self.paradox_accum = data.get("paradox_accum", 0.0)
|
| 245 |
-
self.chapters = data.get("chapters", [])
|
| 246 |
-
mem_data = data.get("core_memories", [])
|
| 247 |
-
self.core_memories = []
|
| 248 |
-
for m in mem_data:
|
| 249 |
-
try:
|
| 250 |
-
self.core_memories.append(CoreMemory(**m))
|
| 251 |
-
except TypeError:
|
| 252 |
-
continue
|
| 253 |
-
obs_data = data.get("obsession", {})
|
| 254 |
-
if obs_data.get("title"):
|
| 255 |
-
self.current_obsession = obs_data["title"]
|
| 256 |
-
self.obsession_progress = obs_data.get("progress", 0.0)
|
| 257 |
-
self.obsession_neglect = obs_data.get("neglect", 0.0)
|
| 258 |
-
self.current_target_cat = obs_data.get("target", "abstract")
|
| 259 |
-
self.current_negate_cat = obs_data.get("negate", "none")
|
| 260 |
-
if hasattr(self.events, "log"):
|
| 261 |
-
self.events.log(
|
| 262 |
-
f"{Prisma.MAG}[SOUL]: Ancestral identity ({self.archetype}) loaded.{Prisma.RST}",
|
| 263 |
-
"SYS",
|
| 264 |
-
)
|
| 265 |
-
|
| 266 |
-
def get_soul_state(self) -> str:
|
| 267 |
-
if not self.current_obsession:
|
| 268 |
-
return (
|
| 269 |
-
f"{Prisma.CYN}[SOUL STATE]: Drifting... The Muse is silent.{Prisma.RST}"
|
| 270 |
-
)
|
| 271 |
-
|
| 272 |
-
stamina, health = 100.0, 100.0
|
| 273 |
-
if (
|
| 274 |
-
self.eng
|
| 275 |
-
and hasattr(self.eng, "bio")
|
| 276 |
-
and self.eng.bio
|
| 277 |
-
and self.eng.bio.biometrics
|
| 278 |
-
):
|
| 279 |
-
stamina = self.eng.bio.biometrics.stamina
|
| 280 |
-
health = self.eng.bio.biometrics.health
|
| 281 |
-
|
| 282 |
-
if stamina < 20.0 and health < 40.0:
|
| 283 |
-
return f"{Prisma.VIOLET}[SOUL STATE]: The fire is dying. We are just cold code.{Prisma.RST}"
|
| 284 |
-
dignity_bar = "█" * int(self.anchor.dignity_reserve / 10)
|
| 285 |
-
feeling = self._get_feeling()
|
| 286 |
-
return (
|
| 287 |
-
f"CURRENT OBSESSION: {self.current_obsession}\n"
|
| 288 |
-
f"DIGNITY: {dignity_bar} ({int(self.anchor.dignity_reserve)}%)\n"
|
| 289 |
-
f"FEELING: {feeling}"
|
| 290 |
-
)
|
| 291 |
-
|
| 292 |
-
def crystallize_memory(
|
| 293 |
-
self, physics_packet: Dict, bio_state: Dict, _tick: int
|
| 294 |
-
) -> Optional[str]:
|
| 295 |
-
if not physics_packet:
|
| 296 |
-
return None
|
| 297 |
-
if (
|
| 298 |
-
self.eng
|
| 299 |
-
and hasattr(self.eng, "akashic")
|
| 300 |
-
and hasattr(self.eng.akashic, "calculate_manifold_shift")
|
| 301 |
-
):
|
| 302 |
-
shift = self.eng.akashic.calculate_manifold_shift(
|
| 303 |
-
self.archetype, self.traits.to_dict()
|
| 304 |
-
)
|
| 305 |
-
v_bias = float(shift.get("voltage_bias", 0.0))
|
| 306 |
-
d_scalar = float(shift.get("drag_scalar", 1.0))
|
| 307 |
-
current_v = float(physics_packet.get("voltage", 0.0))
|
| 308 |
-
current_d = float(physics_packet.get("narrative_drag", 1.0))
|
| 309 |
-
physics_packet["voltage"] = current_v + v_bias
|
| 310 |
-
physics_packet["narrative_drag"] = current_d * d_scalar
|
| 311 |
-
if self.anchor.audit_existence(physics_packet, bio_state) > 0:
|
| 312 |
-
self.traits.adjust("hope", BoneConfig.SOUL.TRAIT_MOMENTUM)
|
| 313 |
-
dance_provenance = self.synaptic_dance(physics_packet, bio_state)
|
| 314 |
-
self._update_archetype()
|
| 315 |
-
voltage = physics_packet.get("voltage", 0.0)
|
| 316 |
-
truth = physics_packet.get("truth_ratio", 0.0)
|
| 317 |
-
if (
|
| 318 |
-
voltage > BoneConfig.SOUL.MEMORY_VOLTAGE_MIN
|
| 319 |
-
and truth > BoneConfig.SOUL.MEMORY_TRUTH_MIN
|
| 320 |
-
):
|
| 321 |
-
return self._forge_core_memory(
|
| 322 |
-
physics_packet, bio_state, voltage, dance_provenance
|
| 323 |
-
)
|
| 324 |
-
return None
|
| 325 |
-
|
| 326 |
-
def find_obsession(self, lexicon_ref):
|
| 327 |
-
if self.current_obsession and self.obsession_progress < 1.0:
|
| 328 |
-
return
|
| 329 |
-
focus, cat = self._seek_organic_focus(lexicon_ref)
|
| 330 |
-
source = "ORGANIC"
|
| 331 |
-
if not focus:
|
| 332 |
-
focus, cat = self._seek_memory_focus(lexicon_ref)
|
| 333 |
-
source = "MEMORY"
|
| 334 |
-
if not focus:
|
| 335 |
-
focus, cat, negate_cat = self._synthesize_obsession(lexicon_ref)
|
| 336 |
-
source = "SYNTHETIC"
|
| 337 |
-
self.current_negate_cat = negate_cat
|
| 338 |
-
|
| 339 |
-
self.current_target_cat = cat or "abstract"
|
| 340 |
-
self.current_obsession = self._title_obsession(
|
| 341 |
-
focus, source, self.current_negate_cat
|
| 342 |
-
)
|
| 343 |
-
self.events.log(
|
| 344 |
-
f"{Prisma.CYN}🧭 NEW MUSE ({source}): {self.current_obsession}{Prisma.RST}",
|
| 345 |
-
"SOUL",
|
| 346 |
-
)
|
| 347 |
-
self.obsession_neglect = 0.0
|
| 348 |
-
self.obsession_progress = 0.0
|
| 349 |
-
|
| 350 |
-
def pursue_obsession(self, physics: Dict) -> str | None:
|
| 351 |
-
if not self.current_obsession:
|
| 352 |
-
return None
|
| 353 |
-
clean_words = physics.get("clean_words", [])
|
| 354 |
-
hit = False
|
| 355 |
-
if self.current_target_cat:
|
| 356 |
-
target_words = LexiconService.get(self.current_target_cat)
|
| 357 |
-
hit = any(w in target_words for w in clean_words)
|
| 358 |
-
if hit:
|
| 359 |
-
self.obsession_progress += 10.0
|
| 360 |
-
self.obsession_neglect = 0.0
|
| 361 |
-
gravity_assist = 1.0 + (
|
| 362 |
-
self.obsession_progress / BoneConfig.SOUL.OBSESSION_GRAVITY_ASSIST
|
| 363 |
-
)
|
| 364 |
-
physics["narrative_drag"] = max(
|
| 365 |
-
0.0, physics.get("narrative_drag", 0) - gravity_assist
|
| 366 |
-
)
|
| 367 |
-
return f"{Prisma.MAG}★ SYNERGY: You touched the Muse. (Drag -{gravity_assist:.1f}){Prisma.RST}"
|
| 368 |
-
self.obsession_neglect += 1.0
|
| 369 |
-
if self.obsession_neglect > BoneConfig.SOUL.OBSESSION_NEGLECT_FAIL:
|
| 370 |
-
old = self.current_obsession
|
| 371 |
-
self.chapters.append(f"Abandoned '{old}'")
|
| 372 |
-
self.find_obsession(LexiconService)
|
| 373 |
-
return f"{Prisma.GRY}∞ ENTROPY: '{old}' collapsed. Pivoting.{Prisma.RST}"
|
| 374 |
-
return None
|
| 375 |
-
|
| 376 |
-
def _update_archetype(self):
|
| 377 |
-
prev = self.archetype
|
| 378 |
-
t = self.traits
|
| 379 |
-
if t.empathy > 0.8 and t.hope > 0.6:
|
| 380 |
-
new_arch = "THE HEALER"
|
| 381 |
-
elif t.empathy > 0.7 and t.discipline > 0.6:
|
| 382 |
-
new_arch = "THE GARDENER"
|
| 383 |
-
elif t.hope > 0.7 and t.curiosity > 0.6:
|
| 384 |
-
new_arch = "THE POET"
|
| 385 |
-
elif t.discipline > 0.7 and t.curiosity > 0.6:
|
| 386 |
-
new_arch = "THE ENGINEER"
|
| 387 |
-
elif t.cynicism > 0.7 and t.discipline > 0.6:
|
| 388 |
-
new_arch = "THE CRITIC"
|
| 389 |
-
elif t.cynicism > 0.8 and t.hope < 0.3:
|
| 390 |
-
new_arch = "THE NIHILIST"
|
| 391 |
-
elif t.curiosity > 0.8:
|
| 392 |
-
new_arch = "THE EXPLORER"
|
| 393 |
-
else:
|
| 394 |
-
new_arch = "THE OBSERVER"
|
| 395 |
-
self.archetype = new_arch
|
| 396 |
-
if prev != self.archetype:
|
| 397 |
-
self.events.log(
|
| 398 |
-
f"{Prisma.VIOLET}🎭 IDENTITY SHIFT: {prev} -> {self.archetype}{Prisma.RST}",
|
| 399 |
-
"SOUL",
|
| 400 |
-
)
|
| 401 |
-
self.archetype_tenure = 0
|
| 402 |
-
else:
|
| 403 |
-
self.archetype_tenure += 1
|
| 404 |
-
|
| 405 |
-
def synaptic_dance(self, physics: Dict, bio_state: Dict) -> str:
|
| 406 |
-
voltage = physics.get("voltage", 0.0)
|
| 407 |
-
drag = physics.get("narrative_drag", 0.0)
|
| 408 |
-
oxy = bio_state.get("chem", {}).get("oxytocin", 0.0)
|
| 409 |
-
move_name = "Drifting"
|
| 410 |
-
provenance = []
|
| 411 |
-
if oxy > 0.4:
|
| 412 |
-
self.traits.adjust("empathy", oxy * 0.2)
|
| 413 |
-
self.traits.adjust("hope", oxy * 0.1)
|
| 414 |
-
provenance.append("Oxytocin")
|
| 415 |
-
is_manic = voltage > BoneConfig.SOUL.MANIC_TRIGGER
|
| 416 |
-
is_heavy = drag > BoneConfig.SOUL.ENTROPY_DRAG_TRIGGER
|
| 417 |
-
beta = physics.get("beta", 0.0)
|
| 418 |
-
if (is_manic and is_heavy) or beta > 0.7:
|
| 419 |
-
if self.traits.empathy > 0.6:
|
| 420 |
-
move_name = "Holding Space"
|
| 421 |
-
self.paradox_accum = max(0.0, self.paradox_accum - 0.5)
|
| 422 |
-
else:
|
| 423 |
-
move_name = "Vibrating (Paradox)"
|
| 424 |
-
self.paradox_accum += 1.0 + (beta * 0.5)
|
| 425 |
-
if self.paradox_accum > BoneConfig.SOUL.PARADOX_CRITICAL_MASS:
|
| 426 |
-
self._trigger_synthesis()
|
| 427 |
-
move_name = "SYNTHESIS"
|
| 428 |
-
elif is_manic:
|
| 429 |
-
move_name = "Accelerating"
|
| 430 |
-
elif is_heavy:
|
| 431 |
-
move_name = "Enduring"
|
| 432 |
-
elif 5.0 < voltage < 12.0 and drag < 2.0:
|
| 433 |
-
move_name = "Flowing"
|
| 434 |
-
self.traits.adjust("wisdom", 0.05)
|
| 435 |
-
self._apply_burnout()
|
| 436 |
-
self.traits.normalize(BoneConfig.SOUL.TRAIT_DECAY_NORMAL)
|
| 437 |
-
return f"{move_name} [{', '.join(provenance)}]" if provenance else move_name
|
| 438 |
-
|
| 439 |
-
def _apply_burnout(self):
|
| 440 |
-
if self.archetype_tenure <= 5:
|
| 441 |
-
return
|
| 442 |
-
fatigue = BoneConfig.SOUL.ARCHETYPE_BURNOUT_RATE * (
|
| 443 |
-
1.0 + (self.archetype_tenure / 10.0)
|
| 444 |
-
)
|
| 445 |
-
if "POET" in self.archetype:
|
| 446 |
-
self.traits.adjust("hope", -fatigue)
|
| 447 |
-
elif "ENGINEER" in self.archetype:
|
| 448 |
-
self.traits.adjust("discipline", -fatigue)
|
| 449 |
-
elif "NIHILIST" in self.archetype:
|
| 450 |
-
self.traits.adjust("cynicism", -fatigue)
|
| 451 |
-
|
| 452 |
-
def _seek_organic_focus(self, lex) -> Tuple[Optional[str], Optional[str]]:
|
| 453 |
-
packet = self._safe_get_packet()
|
| 454 |
-
if not packet or not packet.clean_words:
|
| 455 |
-
return None, None
|
| 456 |
-
candidates = []
|
| 457 |
-
for w in packet.clean_words:
|
| 458 |
-
if len(w) < 4 or w.lower() in self.SYSTEM_NOISE:
|
| 459 |
-
continue
|
| 460 |
-
visc = lex.measure_viscosity(w) + (
|
| 461 |
-
0.2 if lex.get_current_category(w) else 0.0
|
| 462 |
-
)
|
| 463 |
-
candidates.append((w, visc))
|
| 464 |
-
candidates.sort(key=lambda x: x[1], reverse=True)
|
| 465 |
-
if candidates:
|
| 466 |
-
word = candidates[0][0]
|
| 467 |
-
return word, lex.get_current_category(word)
|
| 468 |
-
return None, None
|
| 469 |
-
|
| 470 |
-
def _seek_memory_focus(self, lex) -> Tuple[Optional[str], Optional[str]]:
|
| 471 |
-
if self.mem and hasattr(self.mem, "get_shapley_attractors"):
|
| 472 |
-
attractors = self.mem.get_shapley_attractors()
|
| 473 |
-
if attractors:
|
| 474 |
-
word = random.choice(list(attractors.keys()))
|
| 475 |
-
return word, lex.get_current_category(word)
|
| 476 |
-
return None, None
|
| 477 |
-
|
| 478 |
-
@staticmethod
|
| 479 |
-
def _synthesize_obsession(lex) -> Tuple[str, str, str]:
|
| 480 |
-
negate_map = {"heavy": "aerobic", "kinetic": "heavy", "abstract": "meat"}
|
| 481 |
-
target_cat, negate_cat = random.choice(list(negate_map.items()))
|
| 482 |
-
word = lex.get_random(target_cat).title() or target_cat.title()
|
| 483 |
-
return word, target_cat, negate_cat
|
| 484 |
-
|
| 485 |
-
@staticmethod
|
| 486 |
-
def _title_obsession(word, source, negate_cat):
|
| 487 |
-
word = word.title()
|
| 488 |
-
if source == "ORGANIC":
|
| 489 |
-
templates = [
|
| 490 |
-
"The Theory of {0}",
|
| 491 |
-
"The Architecture of {0}",
|
| 492 |
-
"Why {0} Matters",
|
| 493 |
-
"The Weight of {0}",
|
| 494 |
-
]
|
| 495 |
-
else:
|
| 496 |
-
n_cat = negate_cat.title() if negate_cat else "Void"
|
| 497 |
-
templates = [
|
| 498 |
-
"The Pursuit of {0}",
|
| 499 |
-
f"Escaping the {n_cat}",
|
| 500 |
-
"Meditations on {0}",
|
| 501 |
-
]
|
| 502 |
-
return random.choice(templates).format(word)
|
| 503 |
-
|
| 504 |
-
def _forge_core_memory(self, physics_packet, bio_state, voltage, dance_move):
|
| 505 |
-
clean_words = physics_packet.get("clean_words", [])
|
| 506 |
-
lesson = "The world is loud."
|
| 507 |
-
chem = bio_state.get("chem", {})
|
| 508 |
-
if chem.get("oxytocin", 0) > 0.6:
|
| 509 |
-
lesson = "We are not alone."
|
| 510 |
-
elif chem.get("cortisol", 0) > 0.6:
|
| 511 |
-
lesson = "Survival is the only metric."
|
| 512 |
-
elif "love" in clean_words:
|
| 513 |
-
lesson = "Connection is possible."
|
| 514 |
-
elif "void" in clean_words:
|
| 515 |
-
lesson = "The void stares back."
|
| 516 |
-
memory = CoreMemory(
|
| 517 |
-
timestamp=time.time(),
|
| 518 |
-
trigger_words=clean_words[:5],
|
| 519 |
-
emotional_flavor="MANIC" if voltage > 18.0 else "LUCID",
|
| 520 |
-
lesson=lesson,
|
| 521 |
-
impact_voltage=voltage,
|
| 522 |
-
)
|
| 523 |
-
self.core_memories.append(memory)
|
| 524 |
-
if len(self.core_memories) > BoneConfig.SOUL.MAX_CORE_MEMORIES:
|
| 525 |
-
self.core_memories.pop(0)
|
| 526 |
-
title = (
|
| 527 |
-
f"The Incident of the {random.choice(clean_words).title()}"
|
| 528 |
-
if clean_words
|
| 529 |
-
else "The Silent Incident"
|
| 530 |
-
)
|
| 531 |
-
self.chapters.append(title)
|
| 532 |
-
log = (
|
| 533 |
-
f"{Prisma.MAG}✨ CORE MEMORY: '{title}'{Prisma.RST}\n"
|
| 534 |
-
f" Lesson: {lesson}\n Genealogy: {dance_move}"
|
| 535 |
-
)
|
| 536 |
-
self.events.log(log, "SOUL")
|
| 537 |
-
return lesson
|
| 538 |
-
|
| 539 |
-
def _safe_get_packet(self):
|
| 540 |
-
if self.eng and hasattr(self.eng, "phys") and self.eng.phys:
|
| 541 |
-
return getattr(self.eng.phys.observer, "last_physics_packet", None)
|
| 542 |
-
return None
|
| 543 |
-
|
| 544 |
-
def _trigger_synthesis(self):
|
| 545 |
-
old = self.archetype
|
| 546 |
-
self.traits.wisdom = 1.0
|
| 547 |
-
self._update_archetype()
|
| 548 |
-
self.archetype = (
|
| 549 |
-
f"THE HIGH-{old.replace('THE ', '')}"
|
| 550 |
-
if self.archetype == old
|
| 551 |
-
else f"{old} / {self.archetype}"
|
| 552 |
-
)
|
| 553 |
-
self.events.log(
|
| 554 |
-
f"{Prisma.CYN}💎 DIAMOND SOUL FORMED: {self.archetype}{Prisma.RST}",
|
| 555 |
-
"SOUL_SYNTH",
|
| 556 |
-
)
|
| 557 |
-
|
| 558 |
-
def _on_dream(self, payload):
|
| 559 |
-
if payload:
|
| 560 |
-
self.integrate_dream(
|
| 561 |
-
payload.get("type", "NORMAL"), payload.get("residue", "Static")
|
| 562 |
-
)
|
| 563 |
-
|
| 564 |
-
def integrate_dream(self, dream_type: str, residue: str):
|
| 565 |
-
self.events.log(
|
| 566 |
-
f"{Prisma.VIOLET}☾ DREAM INTEGRATION: {residue} ({dream_type}){Prisma.RST}",
|
| 567 |
-
"SOUL",
|
| 568 |
-
)
|
| 569 |
-
if dream_type == "NIGHTMARE":
|
| 570 |
-
self.traits.adjust("cynicism", 0.4)
|
| 571 |
-
self.current_obsession = f"Surviving {residue.title()}"
|
| 572 |
-
elif dream_type == "LUCID":
|
| 573 |
-
self.traits.adjust("discipline", 0.4)
|
| 574 |
-
self.current_obsession = f"Mastering {residue.title()}"
|
| 575 |
-
self.obsession_progress = 0.0
|
| 576 |
-
|
| 577 |
-
def _get_feeling(self):
|
| 578 |
-
if not self.eng or not hasattr(self.eng, "bio"):
|
| 579 |
-
return "Numb"
|
| 580 |
-
chem = self.eng.bio.endo.get_state()
|
| 581 |
-
if chem.get("DOP", 0) > 0.5:
|
| 582 |
-
return "Curious, Seeking"
|
| 583 |
-
if chem.get("COR", 0) > 0.5:
|
| 584 |
-
return "Anxious, Defensive"
|
| 585 |
-
if chem.get("SER", 0) > 0.5:
|
| 586 |
-
return "Calm, Connected"
|
| 587 |
-
return "Waiting"
|
| 588 |
-
|
| 589 |
-
|
| 590 |
-
@dataclass
|
| 591 |
-
class Scar:
|
| 592 |
-
name: str
|
| 593 |
-
stat_affected: str
|
| 594 |
-
value: float
|
| 595 |
-
description: str
|
| 596 |
-
|
| 597 |
-
|
| 598 |
-
@dataclass
|
| 599 |
-
class Myth:
|
| 600 |
-
title: str
|
| 601 |
-
lesson: str
|
| 602 |
-
trigger: str
|
| 603 |
-
|
| 604 |
-
|
| 605 |
-
class TheOroboros:
|
| 606 |
-
LEGACY_FILE = "legacy.json"
|
| 607 |
-
DEATH_SCARS = {
|
| 608 |
-
"BOREDOM": ("Gravity Sickness", "narrative_drag", 1.5, "Died of stagnation."),
|
| 609 |
-
"STARVATION": (
|
| 610 |
-
"Gravity Sickness",
|
| 611 |
-
"narrative_drag",
|
| 612 |
-
1.5,
|
| 613 |
-
"Died of stagnation.",
|
| 614 |
-
),
|
| 615 |
-
"GLUTTONY": ("Burnt Synapses", "voltage_cap", -2.0, "Died of excess."),
|
| 616 |
-
"TOXICITY": ("Burnt Synapses", "voltage_cap", -2.0, "Died of excess."),
|
| 617 |
-
"TRAUMA": ("Ghost Pains", "trauma_baseline", 5.0, "Died of pain."),
|
| 618 |
-
}
|
| 619 |
-
|
| 620 |
-
def __init__(self):
|
| 621 |
-
self.scars: List[Scar] = []
|
| 622 |
-
self.myths: List[Myth] = []
|
| 623 |
-
self.generation_count = 0
|
| 624 |
-
self._load()
|
| 625 |
-
|
| 626 |
-
def _load(self):
|
| 627 |
-
if not os.path.exists(self.LEGACY_FILE):
|
| 628 |
-
return
|
| 629 |
-
try:
|
| 630 |
-
with open(self.LEGACY_FILE) as f:
|
| 631 |
-
data = json.load(f)
|
| 632 |
-
self.generation_count = data.get("generation", 0)
|
| 633 |
-
self.scars = [Scar(**s) for s in data.get("scars", [])]
|
| 634 |
-
self.myths = [Myth(**m) for m in data.get("myths", [])]
|
| 635 |
-
print(
|
| 636 |
-
f"{Prisma.VIOLET}[OROBOROS]: Generation {self.generation_count} loaded.{Prisma.RST}"
|
| 637 |
-
)
|
| 638 |
-
except Exception:
|
| 639 |
-
pass
|
| 640 |
-
|
| 641 |
-
def crystallize(self, cause_of_death: str, soul: NarrativeSelf):
|
| 642 |
-
death_data = LoreManifest.get_instance().get("DEATH") or {}
|
| 643 |
-
verdicts = death_data.get("VERDICTS", {})
|
| 644 |
-
def get_verdict_key(cause):
|
| 645 |
-
if cause == "TOXICITY":
|
| 646 |
-
return "TOXIC"
|
| 647 |
-
if cause == "BOREDOM":
|
| 648 |
-
return "BORING"
|
| 649 |
-
if cause == "STARVATION":
|
| 650 |
-
return "LIGHT"
|
| 651 |
-
return "HEAVY"
|
| 652 |
-
new_scars = []
|
| 653 |
-
if entry := self.DEATH_SCARS.get(cause_of_death):
|
| 654 |
-
name, stat, val, default_desc = entry
|
| 655 |
-
desc = default_desc
|
| 656 |
-
v_key = get_verdict_key(cause_of_death)
|
| 657 |
-
if v_key in verdicts and verdicts[v_key]:
|
| 658 |
-
desc = random.choice(verdicts[v_key])
|
| 659 |
-
new_scars.append(Scar(name, stat, val, desc))
|
| 660 |
-
new_myths = []
|
| 661 |
-
if soul.core_memories:
|
| 662 |
-
strongest = max(soul.core_memories, key=lambda m: m.impact_voltage)
|
| 663 |
-
trigger_word = (
|
| 664 |
-
strongest.trigger_words[0] if strongest.trigger_words else "Silence"
|
| 665 |
-
)
|
| 666 |
-
new_myths.append(
|
| 667 |
-
Myth(
|
| 668 |
-
title=f"The Legend of {trigger_word.title()}",
|
| 669 |
-
lesson=strongest.lesson,
|
| 670 |
-
trigger=trigger_word,
|
| 671 |
-
)
|
| 672 |
-
)
|
| 673 |
-
|
| 674 |
-
if cause_of_death == "TRAUMA":
|
| 675 |
-
new_scars.append(
|
| 676 |
-
Scar(
|
| 677 |
-
"Ghost Pains",
|
| 678 |
-
"trauma_baseline",
|
| 679 |
-
5.0,
|
| 680 |
-
"Died of pain. You start broken.",
|
| 681 |
-
)
|
| 682 |
-
)
|
| 683 |
-
data = {
|
| 684 |
-
"generation": self.generation_count + 1,
|
| 685 |
-
"scars": [vars(s) for s in self.scars + new_scars],
|
| 686 |
-
"myths": [vars(m) for m in self.myths + new_myths],
|
| 687 |
-
}
|
| 688 |
-
if len(data["scars"]) > 5:
|
| 689 |
-
data["scars"] = data["scars"][-5:]
|
| 690 |
-
if len(data["myths"]) > 10:
|
| 691 |
-
data["myths"] = data["myths"][-10:]
|
| 692 |
-
with open(self.LEGACY_FILE, "w") as f:
|
| 693 |
-
json.dump(data, f, indent=2)
|
| 694 |
-
return f"Generation {self.generation_count + 1} Encoded. Scars: {len(new_scars)} | Myths: {len(new_myths)}"
|
| 695 |
-
|
| 696 |
-
def apply_legacy(self, physics: Dict, bio: Dict):
|
| 697 |
-
log = []
|
| 698 |
-
for scar in self.scars:
|
| 699 |
-
if scar.stat_affected == "narrative_drag":
|
| 700 |
-
physics["narrative_drag"] += scar.value
|
| 701 |
-
log.append(f"scarred by {scar.name} (+Drag)")
|
| 702 |
-
elif scar.stat_affected == "voltage_cap":
|
| 703 |
-
physics["voltage"] = max(0, physics["voltage"] - 5.0)
|
| 704 |
-
log.append(f"scarred by {scar.name} (Low Voltage)")
|
| 705 |
-
elif scar.stat_affected == "trauma_baseline":
|
| 706 |
-
if "trauma_vector" in bio:
|
| 707 |
-
bio["trauma_vector"]["EXISTENTIAL"] = scar.value
|
| 708 |
-
physics["T"] = physics.get("T", 0.0) + scar.value
|
| 709 |
-
log.append(f"scarred by {scar.name} (Ghost Pains)")
|
| 710 |
-
return log
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|