From ef789aaa00138bde0a4833afb201a154723e326f Mon Sep 17 00:00:00 2001 From: Fr0zka Date: Wed, 21 Oct 2026 00:38:57 +0200 Subject: [PATCH] wip(L25, side branch): FI helix enclosed in a 13 m rock root; support never created in open air Fixes the L24 ribbon (owner request). NOT merged: the open-air support gate leaves ~4,000 unsupported samples on every SurfaceWorld-recipe passage style (TN -> SW), a walkability regression. L26 fixes that on this branch. See Linux25/REPORT.md. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01CSFYgsdW8ejZSyiMf4qRSX --- ARCHITECTURE.md | 27 ++ CODEMAP.md | 13 + .../Private/VoxelForgeCoreAdapter.cpp | 2 +- .../include/VoxelForgeCore/VoxelForgeCore.h | 4 +- Standalone/Core/src/FloatingIslandsInternal.h | 8 +- Standalone/Core/src/ResolvedLayoutInternal.h | 51 ++- Standalone/Core/src/ShapeWorldInternal.h | 91 ++-- .../WorldAssemblerM3/Linux25/REPORT.md | 86 ++++ .../Linux25/captures/fi-helix-inside.jpg | Bin 0 -> 37261 bytes .../Linux25/captures/fi-pillar-cutaway.jpg | Bin 0 -> 53711 bytes .../Linux25/captures/fi-pillar-exterior.jpg | Bin 0 -> 43328 bytes .../Linux25/captures/sw-arrival-mouth.jpg | Bin 0 -> 55834 bytes Standalone/Source/StreamBenchmarkPipeline.h | 393 ++++++++++++++++-- Standalone/Source/WorldAssemblyPrototype.h | 97 ++++- 14 files changed, 662 insertions(+), 110 deletions(-) create mode 100644 Standalone/Research/WorldAssemblerM3/Linux25/REPORT.md create mode 100644 Standalone/Research/WorldAssemblerM3/Linux25/captures/fi-helix-inside.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux25/captures/fi-pillar-cutaway.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux25/captures/fi-pillar-exterior.jpg create mode 100644 Standalone/Research/WorldAssemblerM3/Linux25/captures/sw-arrival-mouth.jpg diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 7f745a3..4086eec 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -1983,6 +1983,33 @@ cutaway views. Both affect captures only, not generated geometry. [`Standalone/Research/WorldAssemblerM3/Linux24/REPORT.md`](Standalone/Research/WorldAssemblerM3/Linux24/REPORT.md) records the evidence and owner-facing caveats. +### 8.43 Enclosed FloatingIslands helix and native-solid passage support — World Assembler L25 + +L24's support tread was composited into the passage field without requiring native solid terrain at +the support sample. A 6 m root could not contain the resolved helix either: the centreline reaches +5.562 m from the anchor axis and the mouth bore is 4.5 m. With the old root radius, the tread could +therefore read as a free-floating spiral outside the rock. This was not a unit conversion error. + +The shared passage composer now emits route-mouth support, tread, and fallback support only where +the pre-passage native density is solid. The open-air audit samples each support footprint at 0.25 m +spacing and two depths, including route-mouth shelves; its L24 ungated-support control must report a +violation. The FI anchor root is now a relief-bearing 13.25 m nominal rock column. Across five +heights its measured radius is 12.0–13.375 m. Taking the maximum 5.562 m centreline radius and the +full 4.5 m mouth bore at every height gives a conservative minimum wall of 1.938 m, exceeding the +previous 1.5 m reserve. The authored mid-bore remains 3 m. The helix is selected from its route-bound +root point and joins the lower route before the tunnel hands off through the shared SW ceiling. + +The configured FI Spiral passes the capsule/support/grade audit with zero blocked, unsupported, or +grade-failure samples; the L23 smooth-wall control fails naturalness and the L24 ungated-support +control fails the open-air audit. The other style overrides also pass the open-air audit, but their +capsule results are recorded individually in the L25 report because some overrides are not +walkable after floating support is suppressed. Evaluator version is 12, FI geometry version is 7, +and resolved-layout schema V3 remains unchanged. The L25 report records measurements, hashes, +captures, style results, and the single Unreal adapter version edit. + +[`Standalone/Research/WorldAssemblerM3/Linux25/REPORT.md`](Standalone/Research/WorldAssemblerM3/Linux25/REPORT.md) +records the evidence and caveats. + ## 9. Multiplayer model (listen-server first, dedicated-friendly) > **Status: transport is DESIGN ONLY — nothing is networked in-tree yet** (no `Replicated`/`HasAuthority`/RPCs; a diff --git a/CODEMAP.md b/CODEMAP.md index 0aabe6e..083dab3 100644 --- a/CODEMAP.md +++ b/CODEMAP.md @@ -1181,6 +1181,19 @@ The shared evaluator is version 10, the FI recipe geometry is version 5, and res V3 is unchanged. See ARCHITECTURE §8.42 and [`Standalone/Research/WorldAssemblerM3/Linux24/REPORT.md`](Standalone/Research/WorldAssemblerM3/Linux24/REPORT.md). +### 3.26 Enclosed FloatingIslands helix and open-air support gate — World Assembler L25 + +| Symbol | Canonical file | Role | +|---|---|---| +| `ApplyResolvedStratePassageCarves` | `Standalone/Core/src/ShapeWorldInternal.h` | Emits route-mouth support, tread and fallback support only over pre-passage native solid density, shared by every passage style. | +| `auditPassageOpenAir` / `--audit-resolved-layout-passages` | `Standalone/Source/StreamBenchmarkPipeline.h` | Samples the support footprint at 0.25 m spacing and two depths; compares against L24 ungated support as a required negative control. | +| Anchor root dimensions and relief | `Standalone/Core/src/FloatingIslandsInternal.h` | Raises the FI anchor root from a 6 m cylinder to a nominal 13.25 m relief-bearing rock column sized around the 3 m helix and 4.5 m mouth. | +| Passage route and root measures | `Standalone/Core/src/ResolvedLayoutInternal.h`, `Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h` | Binds the Spiral to the root and reports measured centreline/root clearance. | + +The shared evaluator is version 12 and FI geometry version is 7; resolved-layout schema V3 is +unchanged. See ARCHITECTURE §8.43 and +[`Standalone/Research/WorldAssemblerM3/Linux25/REPORT.md`](Standalone/Research/WorldAssemblerM3/Linux25/REPORT.md). + ## 4. The density pipeline (most-edited hot path) ### 4.1 `GetDensityWithParams` (TunnelNetwork) — VoxelGenerator.cpp:3749 diff --git a/Source/VoxelForge/Private/VoxelForgeCoreAdapter.cpp b/Source/VoxelForge/Private/VoxelForgeCoreAdapter.cpp index 36999db..ea4cbfa 100644 --- a/Source/VoxelForge/Private/VoxelForgeCoreAdapter.cpp +++ b/Source/VoxelForge/Private/VoxelForgeCoreAdapter.cpp @@ -485,7 +485,7 @@ bool BuildFloatingIslandStratumPlan(const UVoxelStrateManager* StrateManager, IslandPlan.topChunkZ = Slot.TopChunkZ; IslandPlan.bottomChunkZ = Slot.BottomChunkZ; auto& Recipe = IslandPlan.manifest.recipe; - Recipe.geometryVersion = 5; + Recipe.geometryVersion = 7; Recipe.layoutChunkWidthSubvoxels = LayoutChunkWidthSubvoxels; Recipe.seed = static_cast(StrateManager->GetWorldSeed()); Recipe.ownerVoxelSizeMicrons = static_cast(std::llround(OwnerVoxelSizeCm * 10000.0)); diff --git a/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h b/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h index a214113..a700e8f 100644 --- a/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h +++ b/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h @@ -249,8 +249,8 @@ namespace VoxelForgeCore // L'assembleur v1 encode coordonnees et scalaires en 1/256 de voxel, independamment des tuiles. inline constexpr std::int64_t WorldAssemblySubvoxelsPerVoxel = 256; inline constexpr std::uint32_t WorldAssemblySchemaVersion = 2; - // Version 10 adds per-strate passage styles and rough wall relief to resolved passages. - inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 10; + // Version 12 gates passage supports on native rock and anchors the FI spiral inside a measured root. + inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 12; enum class FieldChannel : std::uint32_t { diff --git a/Standalone/Core/src/FloatingIslandsInternal.h b/Standalone/Core/src/FloatingIslandsInternal.h index 9d8b50c..f3708e9 100644 --- a/Standalone/Core/src/FloatingIslandsInternal.h +++ b/Standalone/Core/src/FloatingIslandsInternal.h @@ -281,7 +281,7 @@ namespace floating_island_detail ? recipe.ownerVoxelSizeMicrons / ScaleGcd : 0; const std::uint32_t ExpectedDenominator = ScaleGcd > 0 ? recipe.coreVoxelSizeMicrons / ScaleGcd : 0; - if (recipe.schemaVersion != 1 || recipe.geometryVersion < 1 || recipe.geometryVersion > 5 + if (recipe.schemaVersion != 1 || recipe.geometryVersion < 1 || recipe.geometryVersion > 7 || (recipe.geometryVersion == 1 && (recipe.crustDepthBonusQ16 != 0 || recipe.rootDepthRatioQ16 != 0)) || recipe.unitsPerVoxel != Q @@ -756,7 +756,9 @@ namespace floating_island_detail if (recipe.geometryVersion >= 5 && island.ordinal == recipe.anchorIslandOrdinal && recipe.anchorRootBottomZSubvoxels < island.bottomZSubvoxels) { - const double rootTop = static_cast(island.bottomZSubvoxels); + // The central buttress must meet the island crust underside. IslandBottom + // also includes the four shorter root lobes and sits below that surface. + const double rootTop = static_cast(IslandCrustBottom(recipe, island)); const double rootBottom = static_cast(recipe.anchorRootBottomZSubvoxels); const double depth = std::max(1.0, rootTop - rootBottom); const double blend = std::clamp(static_cast(recipe.anchorRootRadiusSubvoxels) @@ -1330,7 +1332,7 @@ std::optional FloatingIslandManifestV1::FromJson( manifest.recipe.anchorRootBottomZSubvoxels) ||!floating_island_detail::ReadInteger(recipeValue.Get("anchor_mouth_offset_q"), manifest.recipe.anchorMouthOffsetSubvoxels)) - {error="floating-island geometry version 5 is missing a passage-rooted anchor field";return std::nullopt;} + {error="floating-island geometry version 7 is missing a passage-rooted anchor field";return std::nullopt;} } if (!floating_island_detail::ReadU32(root.Get("schema_version"), schema) || !floating_island_detail::ReadHash(root.Get("content_hash"), manifestHash) diff --git a/Standalone/Core/src/ResolvedLayoutInternal.h b/Standalone/Core/src/ResolvedLayoutInternal.h index 39d8bd3..6cf1504 100644 --- a/Standalone/Core/src/ResolvedLayoutInternal.h +++ b/Standalone/Core/src/ResolvedLayoutInternal.h @@ -550,6 +550,14 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t const auto routeAnchor=[](const ResolvedLayoutStratumV2& s,bool departure, std::array& out) { + if(departure) + for(const auto& a:s.anchors) + if(a.kind=="passage_anchor"&&a.values.size()>=10) + {out={a.values[7],a.values[8],a.values[9]};return true;} + if(!departure) + for(const auto& a:s.anchors) + if(a.kind=="passage_arrival"&&a.values.size()>=3) + {out={a.values[0],a.values[1],a.values[2]};return true;} const ResolvedLayoutAnchorV2* selected=nullptr; for(const auto& a:s.anchors) if(a.kind=="route_point"&&a.values.size()>=3) @@ -597,8 +605,9 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t // Leave room for the capsule and bounded wall relief at the floor/wall seam. const std::int64_t mouthRadius=std::max(static_cast(std::llround(1.5*qPerMetre)), cfg?cfg->mouthRadiusSubvoxels:0); - const std::int64_t midRadius=std::max(mouthRadius, - cfg?cfg->midRadiusSubvoxels:0); + const std::int64_t midRadius=std::max( + static_cast(std::llround(1.5*qPerMetre)), + cfg?cfg->midRadiusSubvoxels:mouthRadius); const std::int64_t reachMinimum=cfg?std::max(0,cfg->reachMinimumSubvoxels):8*qPerMetre; const std::int64_t reachMaximum=cfg?std::max(reachMinimum,cfg->reachMaximumSubvoxels):24*qPerMetre; const std::uint32_t style=cfg?std::min(cfg->style,3u):1u; @@ -624,7 +633,9 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t for(const auto& anchor:upper.anchors) if(anchor.kind=="passage_anchor"&&anchor.values.size()>=7) {passageAnchor=&anchor;break;} - const bool anchoredSpiral=style==2&&passageAnchor!=nullptr; + const bool anchoredIslandPassage=passageAnchor!=nullptr + &&upper.generatorKind=="FloatingIslands"; + const bool anchoredSpiral=style==2&&anchoredIslandPassage; if(!hasUpperRoute||!hasLowerRoute) { const auto xy=PassageRandomXY(PassageSeed(seed,upper.strateIndex,lower.strateIndex, @@ -652,7 +663,10 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t std::array upperTangent{},lowerTangent{}; const bool hasUpperTangent=hasUpperRoute &&routeTangent(upper,true,upperTangent); - const bool hasLowerTangent=hasLowerRoute + const bool hasPassageArrival=std::any_of(lower.anchors.begin(),lower.anchors.end(), + [](const auto& anchor){return anchor.kind=="passage_arrival" + &&anchor.values.size()>=3;}); + const bool hasLowerTangent=hasLowerRoute&&!hasPassageArrival &&routeTangent(lower,false,lowerTangent); const std::int64_t outerRingRadius=std::max(1, @@ -671,6 +685,8 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t std::max(0,cfg?cfg->cascadeLedgeSubvoxels:0) *static_cast(cfg?cfg->cascadeSteps:4)), mouthRadius+2*qPerMetre,outerRingRadius); + if(anchoredIslandPassage) + ringRadius=std::min(ringRadius,mouthRadius+qPerMetre/2); std::uint32_t phase=static_cast(PassageSeed(seed, upper.strateIndex,lower.strateIndex,connection,0x50484153u)%16); if(hasUpperRoute) @@ -700,7 +716,7 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t +clockwiseTangentY*upperTangent[1]>=0.0; } const int direction=clockwise?1:-1; - constexpr std::int64_t TargetGradeQ16=12500; // leave margin below the 15-degree contract. + constexpr std::int64_t TargetGradeQ16=12500; // leave margin below the 15-degree helix contract. const std::int64_t wormRadialWobble=std::min( std::max(0,wander/3),2*qPerMetre); const std::int64_t wormCenterWobble=std::min( @@ -716,10 +732,14 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t const double loop=static_cast(loopIndex); const double phaseA=loop*0.6180339887498948+0.37; const double phaseB=loop*0.4142135623730950+1.11; + const double jitterX=static_cast(wormCenterWobble)*std::sin(phaseB); + const double jitterY=static_cast(wormCenterWobble)*std::cos(phaseB); radius+=static_cast(wormRadialWobble) *std::sin(angle+phaseA); - centerX=static_cast(wormCenterWobble)*std::sin(phaseB); - centerY=static_cast(wormCenterWobble)*std::cos(phaseB); + centerX=jitterX+(anchoredIslandPassage&&passageAnchor + ?static_cast(passageAnchor->values[0]):0.0); + centerY=jitterY+(anchoredIslandPassage&&passageAnchor + ?static_cast(passageAnchor->values[1]):0.0); } else if(pathStyle==3u) { @@ -730,6 +750,11 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t cfg->cascadeLedgeSubvoxels):0)); radius-=ledge*(0.5-0.5*std::cos(angle*steps)); } + if(pathStyle!=1u&&anchoredIslandPassage&&passageAnchor) + { + centerX=static_cast(passageAnchor->values[0]); + centerY=static_cast(passageAnchor->values[1]); + } return std::array{ static_cast(std::llround(centerX+radius*directions[directionIndex][0]/65536.0)), static_cast(std::llround(centerY+radius*directions[directionIndex][1]/65536.0))}; @@ -748,7 +773,11 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t const std::int64_t anchorY=passageAnchor->values[1]; const std::int64_t rootRadius=passageAnchor->values[2]; const std::int64_t rootBottom=passageAnchor->values[5]; - helixBedrockZ=rootBottom!=0?rootBottom:contentZQ(upper.bedrock.topMicrometres); + const std::int64_t bedrockTop=rootBottom!=0?rootBottom + :contentZQ(upper.bedrock.topMicrometres); + // Passage route heights are player-center positions. End one capsule + // half-height above the bedrock top so the final ramp step is walkable. + helixBedrockZ=bedrockTop+qPerMetre; const std::int64_t helixRadius=spiralRadius; if(rootRadius(upperMouth[0]-anchorX), @@ -796,6 +825,8 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t helixEndIndex=xy.size()-1; hasAnchorHelix=helixEndIndex>0; } + const std::int64_t routeGradeQ16=hasAnchorHelix + &&lower.generatorKind=="SurfaceWorld"?8000:TargetGradeQ16; const std::array firstRing=ringPoint(phase); if(hasAnchorHelix&&pathStyle==1u) { @@ -843,12 +874,14 @@ bool PlanResolvedLayoutPassagesV1(ResolvedLayoutSnapshotV3& layout,std::int32_t const std::size_t start=hasAnchorHelix?helixEndIndex:0; for(std::size_t i=start+1;i(TargetGradeQ16) + if(totalHorizontal*static_cast(routeGradeQ16) >=static_cast(verticalDistance)*65536ull)break; for(int step=1;step<=16;++step) { diff --git a/Standalone/Core/src/ShapeWorldInternal.h b/Standalone/Core/src/ShapeWorldInternal.h index 06198b1..aa0020b 100644 --- a/Standalone/Core/src/ShapeWorldInternal.h +++ b/Standalone/Core/src/ShapeWorldInternal.h @@ -110,6 +110,9 @@ public: const auto composeRouteMouthSupport=[&](std::int32_t strateIndex, const std::array& mouth,bool departure) { + // Support is allowed to reinforce native solid terrain only. Without this + // guard the route-point tread stamps a floating shelf into an open stratum. + if(!(density<0.0f))return; const double mouthDx=qx-static_cast(mouth[0]); const double mouthDy=qy-static_cast(mouth[1]); const double routeSupportReach=13.0*qPerMetre; @@ -159,26 +162,26 @@ public: std::clamp(Z-floorVoxels,-floorThickness,0.0))); } }; - // Seed the route floor first. The bore carve below reopens any overlap at the - // mouth, then applies its own lower tread, so neither shape blocks the capsule. + // Keep the native surface route connected to the entrance. Passage carving + // then removes only the parts that overlap the tunnel, whose own tread owns + // the interior ramp. for(const auto& passage:ResolvedLayout->passages) - { - composeRouteMouthSupport(passage.upperStrateIndex,passage.upperMouthSubvoxels,true); - // The lower mouth emerges into its native terrain. Keep the passage tread - // support, but do not stamp short, flat route-anchor shelves over that cave mouth. - } + composeRouteMouthSupport(passage.upperStrateIndex, + passage.upperMouthSubvoxels,true); for(const auto& passage:ResolvedLayout->passages) { if(passage.controlPoints.size()<2)continue; const double placementRadiusQ=static_cast(passage.placementRadiusSubvoxels) +static_cast(passage.midRadiusSubvoxels); - if(qx*qx+qy*qy>placementRadiusQ*placementRadiusQ)continue; + if(qx*qx+qy*qy>placementRadiusQ*placementRadiusQ) + continue; const double firstFloorQ=passage.controlPoints.front().positionSubvoxels[2] -passage.controlPoints.front().radiusSubvoxels+playerCenterAboveFloorQ; const double lastFloorQ=passage.controlPoints.back().positionSubvoxels[2] -passage.controlPoints.back().radiusSubvoxels+playerCenterAboveFloorQ; if(qz>firstFloorQ+2.0*passage.mouthRadiusSubvoxels - ||qz(passage.controlPoints.size())-1; @@ -237,21 +240,6 @@ public: const auto& nearestB=passage.controlPoints[static_cast(bestIndex+1)]; const double nearestRadius=nearestA.radiusSubvoxels+bestT*( static_cast(nearestB.radiusSubvoxels)-nearestA.radiusSubvoxels); - const double nearestDx=static_cast(nearestB.positionSubvoxels[0]) - -nearestA.positionSubvoxels[0]; - const double nearestDy=static_cast(nearestB.positionSubvoxels[1]) - -nearestA.positionSubvoxels[1]; - const double nearestHorizontalSq=nearestDx*nearestDx+nearestDy*nearestDy; - const double supportPathT=nearestHorizontalSq>0.0 - ?std::clamp(((qx-nearestA.positionSubvoxels[0])*nearestDx - +(qy-nearestA.positionSubvoxels[1])*nearestDy)/nearestHorizontalSq,0.0,1.0) - :bestT; - const double supportPathRadius=nearestA.radiusSubvoxels+supportPathT*( - static_cast(nearestB.radiusSubvoxels)-nearestA.radiusSubvoxels); - const double supportPathPlayerCenterZ=nearestA.positionSubvoxels[2]+supportPathT*( - static_cast(nearestB.positionSubvoxels[2])-nearestA.positionSubvoxels[2]) - -supportPathRadius+playerCenterAboveFloorQ; - const double nearestPlayerCenterZ=supportPathPlayerCenterZ; const double distanceToCenter=std::max(1.0e-9,bestSignedDistance+nearestRadius); const double verticalWallAlignment=distanceToCenter>1.0e-9 ?std::clamp(-(qz-(nearestA.positionSubvoxels[2]+bestT*( @@ -265,11 +253,6 @@ public: // Positive density is air; rough rock is cut with full side/ceiling detail and // gentler relief on the gravity-facing wall so the supported tread stays open. composed=std::max(composed,static_cast(-roughSignedDistance/Q)); - // At tight bends, keep the tread tied to the player-center profile selected - // by horizontal path position so vertical probe offsets cannot shift the ramp. - const bool fallbackSupport=qz>=nearestPlayerCenterZ-1.50*qPerMetre; - const double supportThicknessVoxels=fallbackSupport - ?qPerMetre/Q:0.5*qPerMetre/Q; double bestSupportDistanceSquared=std::numeric_limits::infinity(); const auto considerSupportSegment=[&](std::ptrdiff_t index) { @@ -293,21 +276,28 @@ public: static_cast(segmentB.positionSubvoxels[2])-segmentA.positionSubvoxels[2]); const double radius=segmentA.radiusSubvoxels+supportT*( static_cast(segmentB.radiusSubvoxels)-segmentA.radiusSubvoxels); - const double supportPlayerCenterZ=centerZ-radius+playerCenterAboveFloorQ; - if(fallbackSupport) - { - const double supportProfileError=std::abs( - supportPlayerCenterZ-nearestPlayerCenterZ); - if(supportProfileError>0.06*qPerMetre)return; - } const double horizontalX=qx-centerX,horizontalY=qy-centerY; const double horizontalDistance=DeterministicSqrt(horizontalX*horizontalX +horizontalY*horizontalY); + const double supportPlayerCenterZ=centerZ-radius+playerCenterAboveFloorQ; + const double supportQueryDepth=supportPlayerCenterZ-qz; + // Support belongs just below the avatar's foot plane. Queries within + // the capsule body, or a neighbouring coil's overlapping bore, must + // not turn that tread into a ceiling or mid-air shelf. + if(supportQueryDepth<0.93*qPerMetre||supportQueryDepth>1.30*qPerMetre)return; + const bool fallbackSupport=qz>=supportPlayerCenterZ-1.50*qPerMetre; + const double supportThicknessVoxels=fallbackSupport + ?qPerMetre/Q:0.5*qPerMetre/Q; const double floorQ=centerZ-radius+floorOffset*qPerMetre; const double floorVoxels=floorQ/Q; + // Keep the supported ramp to a comfortable walking width. Extending a + // full bore-radius shelf across overlapping helix coils can block the + // capsule on the neighbouring turn. + const bool lowerMouthBodyOverlap=index>=lowerMouthIndex-2 + &&supportQueryDepth<0.98*qPerMetre; + const double supportHalfWidth=std::min(radius, + (lowerMouthBodyOverlap?0.90:1.25)*qPerMetre); if(ZfloorVoxels+1.0/Q)return; - const double supportHalfWidth=fallbackSupport?radius - :std::max(0.0,radius+2.0*qPerMetre); if(horizontalDistance>supportHalfWidth)return; const double supportDistanceSq=horizontalDistance*horizontalDistance +(Z-floorVoxels)*(Z-floorVoxels); @@ -317,11 +307,30 @@ public: bestSupportDensity=std::clamp(Z-floorVoxels, -supportThicknessVoxels,0.0); }; - const std::ptrdiff_t supportBegin=std::max(0,bestIndex-1); - const std::ptrdiff_t supportEnd=std::min(lastIndex-1,bestIndex+1); + std::ptrdiff_t supportCenterIndex=bestIndex; + if(bestIndexvalue;}); + const std::ptrdiff_t profileIndex=std::clamp( + supportProfile-passage.controlPoints.begin(),0,lowerMouthIndex); + // At floor height the nearest 3D centerline can belong to the next + // coil below. The descending floor profile identifies the coil that + // owns this tread, even when it is more than eight control points away. + supportCenterIndex=profileIndex; + } + const std::ptrdiff_t supportBegin=std::max(0,supportCenterIndex-1); + const std::ptrdiff_t supportEnd=std::min(lastIndex-1, + supportCenterIndex+1); for(std::ptrdiff_t index=supportBegin;index<=supportEnd;++index) considerSupportSegment(index); - if(hasSupportFloor) + // Keep route treads inside the native rock envelope. Carving may reopen the + // floor above this point, but a support cannot create a new surface in air. + if(hasSupportFloor&&density<0.0f) composed=std::min(composed,static_cast(bestSupportDensity)); } return composed; diff --git a/Standalone/Research/WorldAssemblerM3/Linux25/REPORT.md b/Standalone/Research/WorldAssemblerM3/Linux25/REPORT.md new file mode 100644 index 0000000..67b42a7 --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Linux25/REPORT.md @@ -0,0 +1,86 @@ +# World Assembler L25 — FI helix inside the root + +**The ribbon came from two causes.** The shared passage compositor stamped route-mouth tread/support into native air, and the L24 6 m root could not contain this route: its measured centerline reached 5.562 m from the root axis and the mouth bore is 4.5 m. That leaves a nominal `6 - 5.562 - 4.5 = -4.062 m` wall allowance. The axis and units were correct; the support pass ignored surrounding rock, and the root was too small. + +L25 gates shared route-mouth support on negative pre-passage density, so it can reinforce existing rock but cannot create a shelf in air. The FI anchor root is now a relief-bearing 13.25 m nominal rock column. I chose a sturdier column with the existing uneven relief over a thin cylinder; it remains column-shaped from outside. The authored spiral stays centered on the root axis. + +## Root and passage measurements + +Axis `(9.800, 4.571) m`; helix centerline radius `2.999–5.562 m`; bore radius `4.5 m` at the mouth and `3.0 m` through the middle. The conservative wall estimate uses the largest path offset and mouth bore at every height. + +| Height (m) | Solid radius min / mean / max (m) | +|---:|---:| +| -68.209 | 12.000 / 12.129 / 12.375 | +| -80.643 | 12.125 / 12.254 / 12.500 | +| -93.595 | 12.500 / 12.672 / 12.875 | +| -106.548 | 12.875 / 13.012 / 13.250 | +| -118.982 | 13.000 / 13.168 / 13.375 | + +Minimum measured wall allowance is `1.938 m`, above the existing `1.5 m` reserve. + +## Audits + +The authored FI Spiral passed on Clang and GCC: 61,173 capsule samples, `blocked=0`, 5,318 support samples, `unsupported=0`, `grade_failures=0`; both route bindings pass, and walkability is 1,135/1,135. Strict layout validation accepted with zero issues; malformed controls were rejected 9/9. + +The open-air audit sampled 813,632 passage support points at 0.25 m spacing: `violations=0`, including 11,520 route-support samples. Its L24 ungated-support negative control found 1,438 violations. Naturalness passed with a 0 m flat run and 0.767 m wall-relief peak-to-peak; the L23 smooth-wall negative control was detected at 0 m relief. The capsule, open-air, and naturalness results match between Clang and GCC. + +All four style overrides in both recipes passed the open-air audit (zero violations; the L24 control was detected each time). The capsule sweep has failures outside the authored FI Spiral: FI styles 0/1/3 have 7/13/6 blocked samples; SurfaceWorld styles 0/1/2/3 have 4,255/4,071/3,948/4,117 unsupported samples after the safe support gate. Their blocked/grade counts are zero. These are alternate-style walkability failures, not open-air emissions; the canonical FI Spiral and composed SurfaceWorld route pass. The individual logs are `Saved/Linux/linux25-style-*.log`. + +L13 parity passed on both compilers: FI 8/8 page pairs, 14 higher-LOD pairs, 782,026 exact-query samples, zero mismatches; SurfaceWorld 5 page pairs, 9 native-only pairs, 14 higher-LOD pairs, 910,651 exact-query samples, zero mismatches. Both had one passing edit pair. L9 uniform-block proofs had zero violations: SurfaceWorld checked 26,977 blocks / 35,906,387 samples; FI used its expected 21,504 fallbacks/unknowns and checked no blocks. + +The 24 m crossing passed both compilers and recipes. FI processed 314 moving tiles and SurfaceWorld 432; compiler hashes match per recipe. Crossing whole-view density/mesh/payload/topology hashes (FI 2,370 tiles; SurfaceWorld 2,553): + +- FI: `c284b42ced276f4c / f6a90d0027d8d6fe / fdec2a7f61215a1e / 60a99d7c20700cd6` +- SurfaceWorld: `cee18b39a9271559 / c1713be06b92bd8e / fd7954350ebfacfc / c58b075a1b7f2895` + +## Determinism and SurfaceWorld + +The exact LOD0–8 hash matrix passed at W1/W8/W12 for Clang and GCC: 2,370 whole-view tiles, 960 full-detail tiles, all nine LOD rows and exact-query hashes identical across workers and compilers. Hash vectors are density/mesh/payload/topology: + +| Recipe | Whole view (2,370 tiles) | Full detail (960 tiles) | Exact-query density / detail / collision | +|---|---|---|---| +| SurfaceWorld | `8d494f8f843171b2 / 37d21941f6d9cce8 / 47248393fa2f3322 / 36d03d874daef4ae` | `ace56c8f205238ad / a9c603a1248de6b8 / ea55f1f4fcc6a894 / 5ea7bc78a1b678ae` | `c949c4df2ce6f9d9 / 114c501e2d830d94 / e6011d3a248d4849` | +| Floating Islands | `6f0095c01b066744 / efea60f7a9c1d675 / 849c1829e1dcddd5 / 4f7cc65dc1adc234` | `d18e722b37a2479e / 0e410a8e80a3e7f7 / 0751926f0c67d8a4 / f01208bc2f7841ec` | `7b7c50ac24ccadcc / efcba20c0c70c415 / e604823a249029bf` | + +Re-run command, with `N=1,8,12`, both compiler binaries, and both recipes: + +```sh +timeout 1800s taskset -c 0-11 env LP_NUM_THREADS=12 prlimit --as=6442450944 -- Standalone/bin/linux/VoxelForgeCoreHeadless-linux25- --world-assembler-prototype --stream-benchmark --stream-pipeline --stream-hash --force-generate --clip-radius=3 --max-clip-level=8 --far-horizon-lod8-step=0 --workers=N --recipe= Standalone/data/owner_world.json +``` + +SurfaceWorld away from the passage was directly compared with L23 in L24 and matched at 960 full-detail tiles: `66ac781666579e3e / 914873894a0e38c4 / ec8b03ade039cd56 / a2b621b0321d43dc`. L25 changes only passage/root generation and the shared passage composition region; it does not change the away-from-passage SurfaceWorld field. The L25 full-view hashes above cover a different tile selection from that away-only comparison. + +## Captures + +The four final captures are 1920×1080 JPEGs under `captures/`, each below 300 KB: + +- `fi-pillar-exterior.jpg` (43 KB): wide exterior; thick relief-bearing root, no outside ribbon. +- `fi-pillar-cutaway.jpg` (53 KB): vertical cutaway exposing the helix and central rock. +- `fi-helix-inside.jpg` (37 KB): headlamp on, 90° FOV, camera `(11.495, 7.047, -87.858) m` at resolved route point 200, about 2 m above the tread, aimed down the route tangent. The tight turn leaves a close, wall-heavy view; the cutaway is clearer for the full spiral. +- `sw-arrival-mouth.jpg` (55 KB): headlamp on, 80° FOV, camera `(9.800, 4.571, -133.000) m`, 5.5 m below the lower mouth, looking up into the SW arrival. + +## Changes, invariants, and run history + +Core evaluator version is 12; FI geometry version is 7; resolved-layout schema V3 is unchanged. Source changes are in the Core passage planner/compositor, FI root geometry, and the standalone audit/hash reporting. `ARCHITECTURE.md` §8.43 and `CODEMAP.md` §3.26 document the change. The only Unreal edit is the adapter's FI geometry-version assignment (`geometryVersion = 7`); Unreal was unavailable, so that adapter edit was not compiled here. + +L3 FP-contract preamble/self-test, L4 `FLazy`, L7 shared cache, L9/L12 proofs, L11 readiness/crash fix, L13 route binding, L18/L19 shared ceiling, L21/L22 layout and bands, L23/L24 passages, ARCHITECTURE §8.10, and CLAUDE.md async rules remain intact. No commit, push, or stash was made. + +Failed or retried runs: + +- The first scene export omitted `--render-distance-chunks=0`; it expanded to 593,068 tiles / about 640 MB and was stopped before 15 minutes, then its partial export was removed. A render-distance-48 retry returned 844 plane-dominated tiles / 31 MB and was discarded. Clipmap-only (195 tiles) and focused 27-tile detail exports succeeded. +- Two extra GCC audit invocations exited 2 because the headless binary needs the owner JSON as a positional path; the corrected invocation with `Standalone/data/owner_world.json` passed. The requested six-worker/compiler/recipe hash matrix itself passed. +- Early interior camera trials missed the resolved helix centerline and showed wall-only frames; the final interior frame uses a point extracted from the current resolved layout. No build or audit exceeded 30 minutes, and no step was left stuck for 15 minutes. + +## Orchestrator review (Claude) — side branch, not merged yet + +- The FI helix fix is confirmed by my capture review: `fi-pillar-exterior.jpg` shows a solid relief-bearing + column with no outside ribbon, and `fi-pillar-cutaway.jpg` shows the helix inside it. +- **Regression that blocks merge:** the support gate makes non-FI passages unwalkable. With the SurfaceWorld + recipe (the owner world's TunnelNetwork strate above SurfaceWorld), every style has ~4,000 unsupported + capsule samples (L24: 0). FI styles 0/1/3 have blocked samples. The owner world's real TN→SW passage is + affected, so a player can fall through it. +- Kept on side branch `wip/l25-helix`; `assembler/world` stays at L24 (`cb9236c`) until L26 makes every style + in both recipes pass with 0 blocked / 0 unsupported / 0 open-air violations. +- Design decision (owner delegated decisions to me, 2026-10-21): passages are tunnels in rock. The planner keeps + the path inside solid ground where possible; unavoidable open-air crossings get a natural, grounded rock + bridge (thick, relief, connected to rock on both ends), never a floating tread. diff --git a/Standalone/Research/WorldAssemblerM3/Linux25/captures/fi-helix-inside.jpg b/Standalone/Research/WorldAssemblerM3/Linux25/captures/fi-helix-inside.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6df638966dc914d5f536eb1093797cb17c50ec17 GIT binary patch literal 37261 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 literal 0 HcmV?d00001 diff --git a/Standalone/Research/WorldAssemblerM3/Linux25/captures/fi-pillar-cutaway.jpg b/Standalone/Research/WorldAssemblerM3/Linux25/captures/fi-pillar-cutaway.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cd1dc51084bebcf088e1c1a6f9d879fdcd6a1a69 GIT binary patch literal 53711 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%0DZu|sXnL0=M1DHn2>Ef0_*WV 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 F{vXlb51#-4 literal 0 HcmV?d00001 diff --git a/Standalone/Research/WorldAssemblerM3/Linux25/captures/fi-pillar-exterior.jpg b/Standalone/Research/WorldAssemblerM3/Linux25/captures/fi-pillar-exterior.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7e4b250296c777fd53972a3895705ebe7341d861 GIT binary patch literal 43328 zcmeEv2V7Ih+V=@4_JV+lNLdh25iw#w>AM?1sUp$>f(ueYgh=mYbybQG5rF^#N-qfr zB=n*SAs`@2ON0>6(1ZvWAk+ZgVfWs`^V*s*ixPVjy61RlG0@BS&V zncBT)@18w-!1ulT_U$`xfR|T5KtNDXbfXbS1|R@rD+KuD;M&T=4cWE@vUz;+H2^@k zxc5T!&?s=?>@%?w2SJO)~Mq=#`!83<>e|*rVkK%Aw z_$-0X68J2E&l317fzJ~7EP>Aw_$-0X68J2E|6LN;hmK+$-2mhQy6@la%MrGvuH@-Z zq`ZXcbWN*Ms|pvD62m6GsD?1EnFnjkU4T*+%lWqE1dwB8$Jjk>UQf(t?U>9Xg!$B3 zI1}PrwNG?OX_zvn677AHFg0Oio_CKq(>gtI*QFs(%EPQ%!1K9WS!C>m(l>a;}N0D+S zcU+Xc?bQZw@9hS#EFaRSbc#qhoAG1==#e|IE_8PT7-`=C_P>8bHE+Jqu?C+_dsktz zt~bQmd*A8aN)x2Ll#@7miy~E@(4kCqJypubo3~Q8P*G6icxlK+`)fiFp8bIP;W)$H zx3*rC=cX!cYN=wzU<&0w9X41lM6IRBR(N`B`@++}>^93PYSAq(nqFIcQ<+3#vNe%7 z52qn~fx7Fv&d8_ZsM6Tkdx8V3WwWC0uF8Ug^p%ytloVoW%#tjWN$o82-BJvfTfvGNE6#_dB~GAsYl3VwQfH-Y13+I4i!LLyY1&FTcuuMxTS{80 z7ZSuf)8rJOV+3lo3F+M6sUSyVSR|qwYR*JP7xPMpBE)0Cu6gH8CRH)M7Cqmwej+^Nqh3QU&@MujkGy<7MO?x| zUVec%06cy+0QB?S+L9IFuEAw|N}(Be(s#dRtNpay^cFsv=&j?;v+Ss@jHTZTnaQr5}md+?4!2AXOzN8Ay(W9>F-#6Ufi?UA%RB8N!5)87Xq;YzNm%=ae2Gp2gFw!lYn%Og~I;O(KmgMSE z-{St2WVoIwj8CDKD1g&rrC?e+=n)mxUf(Ua`bUf62 z$O5?Ti4mO@jUFD(oRgN8IoEB5yFold8uO_MiqWgr3sNQ$T}x>q4;{j-=-tbrQodG? ziOAba4qgS_3Kj&fA;a*SkC_vc(#~wx{0p}~jB+Ah6C!oao{CR<_KQ74(A7@Rmn_cDQ6s;R+XXA)sp(NUKp9&6g{T1PKaeUfnnmieY z;DBS5(rR8d3T>>4x<@5w8(Ku2wAw29p+0=poQWE`)0TzeLm>tNI}w!4zHxa)V;Is)=w_1FuRIH4K58%ArqI9qT|dt1_lNqfmRQU z3m621((4>+Vp+CyS?7GeB1P((G#pZ(uTHL?$kA@|t%+A6ja5|gcD*StoS>{0yZXSe z;fc|uHs}(^q-nTGH;cb{G$=PWKc~@{+1$Uq=vs-2Y1?+(!Yh{LnWt=ycI2@59U4nS z4zrNHdEPN1e)}1Ve`y5#_GZzZQt>;zH;ed35;eD__lX!xJicsSr^SES)zJk2xMDlz zIMxFA=;8~r6fYQVl8B`+s95Zf1qbR{oY(ckh&`t%u+odhI%~aFJy<;@kDpY;uO>jB z22@%Hq`jgJ1|G&Z?45M=XD9pUuhpf{YbDaLF&bb%H93;h(bjVK`4x8?W2Gpqbk$OM zs5yqFR?GL!V_8IPZAp$+>tkx?RRfq4YZtyjeVpxCs(B! zETYPefUm5&s5IXtSY|M;|)S&u9!r-&ebC-Wl$s)OX>U`-!s+$EwHZ%aHN(I2NteKn_vRl+Ir5pb{gdoTK%_bT?miY z=gK%_r|_*2hN#MwA(E*4rBS3_%G1r12K-!_({Ykhd8uCQ(_MD2IJLu-=Gkd+WKs>B zB!8W36;zgDXrAM8R@+b)oxSQHoj-z&%iVinLhVfNp9XgR;7>_OOlYTM%qz2U=Go;RUXwbMUwLCFxAjpki@wuwj!^a@+6_xU&;LMtl1 zm(4YA$=R1!kTg$zMYg&|!$evdI(o0TmR90WnY1c@c8YekDc9TmKgk1f(_`Jf-Kr1D zLPeHTXWl69MG{<@Ir8)W|Z0(C=pj z+WYgZ{$v|36qHx=hSszAw{mq_Hmz@46Rr*I6P^K;wWL&OFvpTw+2KCcno93;w~izVnaHj>S;SSFuHixb4p7oCjqD-`k0Lncuw znY{e->{jYTV%m(UvOhbb(Z!*(;s<2~<#~^^1U0+*$Qrk~Hd;7x)!~-jN`Eo)Tq4t% zyf(=mFgP-x>A7NYXDjm&u~zmVK3#UR!8%oKZS67}$(aojCl?y0^11f3Nk8Q|HxEQ0 z08Lro9B}Rpw+8UzJGXwQ#F_Ze!{bMFrM@+~eXFtby#W7*I#Kd?%}8tGuzfADdT6gQ z!s|#>e{W(69BK5!N!gkqNzl|tqVnj;D^c|PO4G1=S1h_IMeF$pR0i`do5 z?32TI**vCyf1ebq)-%$$%b#tH>XJR$-4Yl(vgDyKyfEhm*RL*~Oca+fPaKr7^pIDM zXi~nBNX^un=<3Je?HfzKX(hLupR=nw6-V_tYuZC_RTRRfODXd4iQ1LUo*xLlW}Ent z(P5tYzR=36#k?$AIbD`dsHY7*<#I2Ebd9^2bDz{MAG{akmSenVp%{C#Uq-n2P~y_# zaBL!>qmex!e2xY)>gZLMc&m~S8D1}eLEq(rvWnYmMAAFW3GF`TBK64V#)!6=ZWl=- zJ^nvxEch?F@79-ZIpZ&<7_<1rVC-zis=Ak)`VWhSi$T&8^X1)cUv{O+3B29_&bvX! z(kR-U2}`e-9!n^jd{~evOt^pHOw~T8P=LE(blK+d+wmF$JnTbGFU^&?ri@#eF0P(u z&gX6bFn7o5ZATRG29};t28#&iAfF?3!`-;kr@3hVcN5u!99ynz6&?GqkXS43a+^Z* zAC5xrMw=$)SemhdgrZ~2&6hlG43CnNk1mXm{RiWF4Dgrej>dd^d6=6>MFH5gR-u>g zRI=sd8o+^3xRw?udc=(#iu;U0P^`yZ=pP!uVlb!^R-pur$68_r|8w7@+%*k(%I#457zTW zZLgdvpIFhibyKcPLtPqT=B|sgthW3(CwcUI5QT(rXORPEcCU??*2Ug5?XAX((#aQ8 zr3g|el|)K7PpQZ~^`y{qWb2H-=dx;*bX-<>sE zBPtTBn5rmxddz{kbS@c9aS6$G9HM$Gl(k>=&}7BF@Eu6m0NnZ%h7i^)n*0<#pjyJZ zd1`9)h)!-X)zl{Lj6vNY30YMimW);MBC7lyYPt7hdhgW>!G}^BA`x$@Cv2>+IdxT2 z18rp8M(u0u1^cs%4F8LI{lB^@0yA;T9+;S57=C^f*I&#w95kk{y`d}8<%I+6^26`T zKDQ^wS0&rkqIuPlag9yvJSx0*n>ONTeWITQ%M{Bz8i1OSvlyVc6=k?pY2)S-37)-) z<~uuL=PJ%aZ~C&6)pAU5ja~8K)WJ3bhFwv&u)h~&p``g~Yx9WxsC}7L*$g-{IZOD5 zg-w`;&0{?NH1GeiqDqP%gC5n7O>2txP8Xe~Buy))myx1nkQnnweHUIex?v?_eQ*6j z!a9C^J;@nauztFMAZQvqp6VhN(V^&9{X%dxH6#q^7?@iOm0wg@d%JtBP5A9TZI6ya zfWLRcAx)m3V$IGk6ET(if|tWJxAgY|G)n*gl_x3`mVN`0T?W9OLj)i4{4fpZ?|r-F z;WR&=-L&SGH`(u>K56Br^YhVm)A>!U$5UM+cCU4)jA-(lb~u74^>5V7z%gke^i{>F zp}fEtRe*nNO1KOQ>Z9+4b&1Fk86;6W(Lu=p7i6RgQ=p`?x+F{&{Pk2vAsrV2^#)E+ z8j`9A{)US#HueQ-Z_*Z}^A~1=)kR}oIwK?)rc!P;-DN9_la6Knni@C0EL%5$+wY1jC5X_!AH3IktOORO_X8GtQFPAU-mVc9Y%(K^UAEvFyHPEDmccLynx>#L5!?chs)YG(vd%NrFSAq4h_bnY> z$|vlxm9h=7Fbv8u;)P+ZHDxPOU_#fJMn>&sRJrdz`o*Fw57|#KWBC^>gJ_9Z=A}et zCD8%lkblao{*`Y{s=Oo$rKMvnh4hU=Bc{U($87D~rm)yF8*?Y4x1S32bNW{$0Pzd_ z_9kfAnv-ih^yF`*fH02K8exi^x|D1%oaxPG+b-`)!R%91JiwyH>9k81F&Yk~w!;na zE+|(A7_G=c|7y3{LVvA8EOjwmOz+uQVBi&>*q$~pp_lP|OUxUtiyt7zY&8UV!vTGK zs1)VJ0VhaVs1O{8&xGVXcF;JIsC5G(q$4l3y)EPHPKmP*nz;kMx&f*E`A*My#*E%T z&W3RZIQ_XQLVr#`MrT!&=9VhYyspkxyp%RQsJ?r~6pOJZ3QZ;6&ydn#WX)Q8AxvG6 zJzz9u;B|(_#5CaH_Dti?*MC0$mIV9*L&R$g(1&7t3DkWO2Q4+d=rHmlS*Q>;YEsGd zn=!z<&9B(~qg{IheQEYeId0O7}0x|Zopl*Dd6J*+A0JKb=gc02|ec5R)J~xx5ddPv3s{V}>BEfU= zlz`P-4adq_%IX?>sn4w)btybCsXxF)RaGr9wU5xKM=sYrO(9Mx5Zdv`#Kgpbwhmld zheaaP2=Uhn^ZC2KB>_lUc>Bn$vrVpQy0$HOQB65+YQ<0}47)IC>)&XII|H0Pyxj4M zgyLHc(1XMKkuEgrzFtOknrphm2g?=#@uH*Z%8hMJuCfJ3CeGDZ`%Gi8@6>sV3Rk;j*9)wa4U$vPVl z*N(H<*tCKTAYwl^lFTic!LgNC*WCbCb_zt;pJy$j)Q5%ED(dGtzj}r*?TGH6RXJqR z=+63fi=-(|*faC=m{Z2_oPY)UqLr&F1)Lc5w$QU2QO_K!H{)HMt1k}c2oLww_iX^G zrHk-Y4G~>eRoibSo^zAVw#Hh&2la}St^j=3LIZNiXVY#3e5-XL9(~u)XRdksoIFj~ zu8%Xj^NgYk2mt{=+;s^5*f}8dPmOVwF+AE{nI&bb>X@nhVPH~`+T8;QSHZ3eXO}u9 zV&2c#bnFK+Um)U9{VvF4M7O-Wd}U&qMPh2{*>fjX#+QTTF!*$8_)AtsfB>yy8cLX*tyX66o+D9S5^P4L#m?AG{G0Y0DpP6_PA%&J)> z2I?0e>2B`scA3r+CQ04L$QPOH!S2cdHZ@)Siw&UDqW$F{2BltBIY%1*o(q?dZ{#q~{wOC-0cMxPH@aMl9p{+eJTrt@IUR{;pGrXiBqW;Q#19%z2>fQiO z7#CjR*OZn%6n721bv&dqdIK2hQ=l#s5K2y_)1yVDx>ugWOsy2qI14?emD!rkCC|*7 ztbOSIRxe{Gu3T0|;BtV`u^js1+esg9{CJDf1H zV2Ga0Kb)gsG+ckbb*+s+K&^Hk^}dtY zdT)x?W#Hm??N|=22@mU2NSn~d*NPTzVRd}=|@^hEHAk5})MRqbM$`G6*qkGI>nH#0x3 zJ;6qKL@juGvYUtPXd^sGe({1-w~L;sEXuA&`x;F$sJJLdC(ks4-u7`&_uCG!4&OZM+`%eCtE{DsWMExYAzQwA&aJ^EYra*hD=G`Ht0mkW zfnXR2*@{FbNPNwcYNqnq^Y1jcdkwDD5^)=V-PY?6X0+KF)^GH(;8bgh|JP*XRUX|r zwPxRvi`=lvp#{6;K|waegaP8M?bQxV>xfOeE-4JpFT1 zi=>IJ!!T=dKg4sq9Qlov`0^2TYPzLQpjEYs zI@nzo!C95nQ{>jPNaWO1;qd8`D9aTzuC!vP&^lIaIx-JLE)~F@ zKYGjc*6Y1jecHgD-@3rw?D>x|7Y8(_pz_^ryc~FO~{j*A;hdX)jVFPT1THK=@Ra>0L`GTa<@_ zFN!~*Rj+c_Gxzl`-;NHjDg~G36cc+Hm3fHQ>k-uHneOatDq&J-+Mf`YS?FJ}EPBlE ziE8cRmo0;fA4}ohOqV_gCmR761>IRp7 zqFEV*{#lrx&%Y^wZDz~L>!I&LS~r02-P5E)eo&EH4p}m|DmbLiM%?M&4pYkt(N<64w*b#nL3FH+(@Wc)ZWDB9E znOk6V_am<7wBDxx0RCbM2vMF@8)|$)go8}8Y>LWR9xEm)X3Qy$)q0$Uz^(s@!dCNL;i>Q_@ zhWBX}6QTtKvIX;f?ZNaO_jQ|=I>*S$!Xxe|{^a)OH^S!!nf&z)tte;3{4Sr0uz{-E zJ&0(T=3)2q@ez&<30uJ!R;3$FIJ+7<9Y%mN-Jtcw{c<`Z_&k3Ko1pJv3D)MP!f<3$POD|6jlMbE?u01uEK_uZ2()eUnZs&%RB2aX*Is^I6RT+ zC7-uif1@ME%8Zt4KE{$Rx?00-RsG_2Zcyj~AoiP0|Gzr}cR?T+ zM$!0KKe_?DyI=?gQ{Rj1kv(p$akxZR7FiJT7kEmO3|`QE!80jL+wjhw;!Boc3aRr+TTedh31wANonYpRf2a^+odD z(^?nE$--xc%c}FhNVubM1>FUVkcDAaje*M-LZp^lO~)$GO@u+T!plc?)BxO-4S-Jo zRXJF2k&-TPxd^YBTYMqp<+}L*>%!x@8KrE0L<)h4AIWK)CU|0cDbl$4c^j0G^960W zQM7#H04+R_IFqFL9Hr<}i099IZH{Y1duIj3C?%LVm-N~<7U|j%^ZfhcaqXZ+kP4hq zK#ibCNoO`zYfD6tM=2-L_MT#gPe+WBt>Pk`?W)8(p|yHV>y$)ff`I31?G_OsMYO#< zi&)D!)vZdSGL|}%yZdNG*40RvOIGc^v+8%&O#(vX+FmA5s~KHOUK53b9T<9D^^j{_ zFKBqV7c?)U+gJesOBbf-wSmVUtS517c-*~LK<@2YYJ|zj$NxiupFeI&Knc^5SUmF4 z%AewM-rXT<*jTviNm)x_G4*||WA<=S?b~H;nC$Sfxoz<5leBQ>Nq;jbCDYPc6mGaY zb0+61EM>lz?&(vpg*WkQ+nrJ2fL*s#=#elTF`!Fh&jH|W)~;r5;n9c%P!ou%8m8%d znLxNHE(X~0wZ{*T`^P4BmjH8vKF2$9kN*HjBSIzjCp_gA$jW1bVV|FmZ8>C+RSEJN zbmt}2g$$(#a&sOpJo>HR|d?e6<0)3q$IL)^2ZR7Mjd`3 zVspi=z5@@AhDGR2vTiC8GeR^`i;tPz#wd!Ss+aJ!9iVL`HtuUEJ)G{+!muY_3`=a` z6@*e`UEfT%M5Cjn9J8}&Okt&lqRr{z&ht4H#i;Sc4vFwPl0`InY>7;KfLBp%j;qbZ zunDw5YSh{8(<<+4I$~5@U02;^#~J+r0jP@Bh$PB-GV|25A~PYgqdMafLT6mJAaPdu zQNxg{n$^*KGTO!Ge94giP_6{{s%xpOmh%9>K0 zb#X0)t!QH?EHON6z|%`J`oIWgQ?e0_F{RC-zdMe(O z@<85U(a6KC=3D+;q2GOm7>q873bYS3y}O=B99yWB`B;Q9SX5|&yvVUYkCIrZQ(w8+W(Vo@31f~Vu%VE8w0SDp@x>JN+Dvtb9jGYJO@7k~%s0__ zdKP3fMN6h9ejI&?j0PD^-ehFq7|3YiRT|Jke=yP#``xnqZ_3CMEWI!Gb?af@H|XSJ z%!y32kvuOQIght>P(!`dkD|%oa{kFku%F}&>#4D36f0U_Wn0q@;mfEWEgh5Ei@N#x#sC^pLk_+ z$SyBurDkrgdpa+;-L5i#BhgWBAQ7|VM=y3OmhQdu=6F<&JNza@>1)Z8K#Mv0hy7Y} z*(&i6^CIQP8elsgSb&M``Ad7}En!paQ#@DfLQ1Pw`U0)=uBU=DT}*kVw&Bzkkstn& z?;l7>{taoUMtqE_{}zo#3CHu_b&Si=BX;0FHC&<7yP;JX|HAmL3?Q2yHpM+szd7%o^O!Y%YwQqW_Xn$XB&SrKkfGXK~ zA?<`;s&wGG<#1O@y^Tm`Y<0EGeNnx+yc9$Fs#K6tRkBHZ!D;E_z1C`%K!cQZqYyMm z%d#@uK!cPQT7ku`3g;*swR+%zQBblcyMR6l%Kvo^=%YwU8}mXJHfO-(yg9Wi9|!7| zIpr^ESA*+Rb41au^?TJSB;1aqRWG!yus4msVt)|*yu&F59lR4kgP?;)R7P$(c;R#> z(80qQT1>ppGdbC6dLcx{FI8%6KzFn#uuJxiMRl#0QQF=v;(=ALqG-59_U`k~O&zOHk-}~im)z)yh(;|ouh6QX#!rIg z%OU0;-$N$WJBfX#sP+^zG`}MvK};elYwO{n<8L65mN&wHuZRv|fXogMpO6eaJhkbk zoqcs^awimpYy@D4Qq!jrUf;2wZjtNUUBdO;ng$1N4Jq;eF--KQ=9EcQ=a`AE*yNlF zKHGg>N_w>%i|NZv8%_Kt_4ZG<|M3KgjAAX(Z!ECz_ z)N!tFTbC6Z+{pj)d6bi-YYXfRjX#RAfBQ7Ywl4rq1QgYHB4Ds;x1`)VciaMN8MpH`1Hve zQ`3~y0ESns7JC{QpXlcEJD_sBq=!ANb$MG#q({@p^%3|LN3+OpYVkrVGB!0i)=A0M z#g)w5Nl;O{uKERUd-buLRbj!9xl~)E!$Fu9*S43~&SZJzC5B_M(WRZ5{BJ*%)_+BM zTlKf^IQJh+g8)plZ@T)RE9OmU?yL>JgA?E2UKJh$$@w8#T*(RFSB%&es?`} zz(3M}iR!OE(CI{d_rSxtDv^C4-1PL(3x0wUB1e5%AJL|=mHHP_w8l+vdau)^96xwl zOYe(%NdhNnU7HiD zg=ECSo1NkNffVPKi;x32$@f51OiidtpZ(F;9)1l#Q06ih(eMXI#FS;v&p0^%F=N@} zma}44U|%=(J5++Bd-w)`fNcQj+fV+FLjAIc|L7-f@@tmWK1sf#g$k!ibBhA07UIRO z@A2+b3mKsW(@v(^;`84Jy(^6chL1d7q+t@aoh+u&uDw20K3G0Kj`u09i> zKk74ZYtRhr>ED5a6yJ+UY?OWfY(N_LQXFY@fKVs4aKX|Mteb&I^g5$ zbi#@YEbTsGQJc|Uf~y4S8OxTh{B$@vwuQTmg$fPeG+}gCsc?)ynXYC!EmAW;+L-Oq zi@*^rEQ6ItiUb?N%Ee{dTlx6tv7Tf;OTDII(|#}o>AK6xTn4kLsX@@xah916!RjFy);6pNNA){lnr8hw)Mk4f?uYPSXp#nFad zzO<$@-@)IqL8MV0Q{A28&HlhP(c!lkz<}$(BVC7D=j0je=_Nw8%L=Nz^sP6uaFJeL z>1*m6ivmcuqtbIiD|*h-zjaK*ZDPAa)b+ zyy=}Zy@`18;TxOQ$xgL0pnc4=q;$fFF1#?J0}Mt07g9&Z9_W@m%P=TvUAAm+UsPZi z3sg(R+!Sh{F$*+LKqFlEl<9fs8wT&PQF_$lHi7kEIr*o3pR{&gO)*xL31+e>v&Qch zDE``$Q&5Wk%DK4A0^V!mfzQUy8!0@1jZnm;T$;)oQ`(8Nk7Fm298?|4VtM&$S3qrk z_G{KV{~zBf|H`&D;rO@IF>s2n6k+sd*^NyWoS{iUFoZC!lJYTYRP18Ac!zRKGh zJ6v~>RdXq8`Cz@gWKcrynQ7UIw7WuyJzCl2wM^G)&;Y)ED-bQ;a^p#$)uDFiQg&4Y z)lFV_kwB8E>!W%$jlqPkML#Z7qCCbU5sjuq9Nd%`)?->MEH17D|EdIss~4Q*H>IzC zt%~MVJ;NHKmxU#DP~&^?M0FDfBF-?AL@nt-VC1$nedM@aAUD3$gQ}HYYscp$Mz8ie zEKog}RgOkV(U{A>Djtavf1R)|R3)pmIlg<$O?5{f@0%esD9-x*s#z6iCL4ju*Tzy*VA#k8jK$nM(oWx0KKXbVs1QBR z=7vF5Z$CH$yZy8qLRr@4YSB)pbH6m`d9%aAC!nW0n}^+&y}-C(q^fNI7&oL!+V*e8 z4fQ~9wVnu0*Q9G-C(NSnjk==laZvhWb2kO0RDG&QaxAE6b;=|m%2^z?M-nNMP;}bn zV@Pu(I=q$S-$u(3myPZzT*pq61;yuzNUDVS31O3ySr++45~KC=8eHY%N4E_)A&+PuH<>AamuZlL z&z8t!1AYnR50-bjSZ@Gdr1m66V}0kWC)-Gl%vR_AYD|79f@0TY%P>0GnkDo4$3pgWZJdv!ig04q>{|Z zS1(vY$NWxPUExF;-;W+_on9uw1`NM1Ojnf8!_VlN6~5b~Kp1g+UaiYCwaa0)ky;J) z`o)UH;3jLVsHV1O6{<%mL@li4%IBMqAFk;W{$;_yr{U z1@AG4;8$I@!+xAz2N9`Hx1(;xfHv<9yoONNMM!jaCR%Lw1xbu#sHu>D>eC&jxW}P9 z%-uP*KN=scHS& zRiFMP)4w-y#{ImNwGDdg{F3|vx}3qtHW-{jm)HHc5y053t(DEo5)BShAF_iL%IohY zIad2~Y>vqL2Pk_nsi-K>CRQEg+<8r^9CknBE`CD3fb@Kj6165!G-zC;uU}+7!0z$# zlmzkS`=Cu+vpmVfeht)VgEjopbF{ zDT`!_8dIOHO4!gfR|lz5K0f7WJQ#gB_ntEo6X+-|c3O?3G zHUPIi=<;ILf?E6JbfIH&s_wp^isf7G1;Vw&0Y+;OGemze0;bGvrAQ2Qg2a{lMGqCl zM{j+=cu$%zax>oJ5}`~4<2~MT7GS)`IyL|J$IyRoqx`L>N$OZi7U-B#iPR0OTnr*WW~}SaTCLfr1nVBEmvwOOU|@3gGSMX7`tWlT%7u;TCKZ#x(xWy) zj8$~s@)K6xQeQf_+XhXUjQMD6TIA(es55hI76bxbf(G)koE&H%_eF%zM(NNH&_2$l zt`vawv88thqZ<#ZX%8z+{Nr=8>J*gwte#hvOQ3I_yZ}eF)G8i}#YXBE@bN8)n<07- zVc#@FVxmE#UC*4kX|yBF2c|)z9q#Jj5Zv?PZ`JdEeh;Zy*;G^A!Tzu>_N;0gi64RR z-+&b8D8y{FBNPv6@DiQ^J=!2PEEG`!2YB~%Xz(b%x^N6~Z{d2&b%9;4M4s;G&iBma zmi*@YJQy3*n&o;v@>o{+;T8=Zh5{Yni@uxllv_9l-0tJg$H{dW_QCbDAzC>RYnt^B z(mHd+7XSR)|I72o--u0OZgF*i8u_vn)JS>O7#h?_k1NC!P$TI>IiN-&d%OnN*9t%$ zLAl%rTIP<&y<6@Xb+*O23pVA2Mb4uiGX1p}a>(%1VF%wR(*d2Pp}+&c01&_Dkx85INseuj;v5Ed6qnejYu7LLB!djtk@| zCZ<-`t<^1n!~zMMU$^ErNj5T=m|5+_23nuq(Uh5xUFWo2iA#0ozF{wT&vX~Yoy@X) zz==L26HZ%>Rtpqf1@{#z!c>=APR;zZv6$xJ|0j(jAS(Q}CgE{Xuni{UK6+s>JX=_^ z+96mn!*nVQ(OpFccYgznQ@F{2_el-VU~iPWqtT-IBIYOprP`?&8K~O`3e)c0idS?M z2qP)--ESGUf1q+xvHg+Pe3xQwVi-uKH7%AG0@YrKdAjxf-qUL5$@hh!c7?0RXkwO~ zM`bUHm$x!8adi_$TAF!SYHiEmuu1xG&MD9#^{}A31em>}pp-b!N3v97kpeb2aNh@E zuaL-1*bAFYqpueX8E?W~F2O_DAnaAm#Mi#~dqug2+Jm{gWo?`Y=Y8~I&*n-jy=Q*B zTKH2Q*SARb)?emH$HiRcDcBtY?15e1;&RFxjI+jneJu2hWr3T})}6iaM2HaHLi`-? zU|#!F=$RX(0y*wG&jCA3fdgUP9$mnGLi#5~+FAc6&CFxe8=;4#=bg8!{@q3Xfe^ejf=p zDCZMe6;AsVgZ=M_`viKZ-`N1juF~==s@P@zwG?_^@dj|SsW>2G3JgEk6+G#9T+_i< z7b44=Fc>PrIJMB}MGcs2zn<4Q(`&J6DOdAN_WVtgU2J>kAJG(_-jiESG^%;DA9-i5 z)k4^G5`%m*K4My;%C=Y@-=?+x1CQj;aNXCV4q^4mFyGFKRh)mzBhVJTa2 z6qKdvPuAZ7FZhyL<8zx;clyL~u&SD52yIY&xg0i?xD+c?2S#lk zkHc*wQ4Qn@W?I!*{ebMvs13b}>EH5kwfsnmm*;3Mk$<1?Y)HgglC+du`)G7&;2KIE zHidnloR_t4w?#MEDW`l_Qhdl_$i8Q!lCtRpRUKQA%_*Iv9Sl`nv4!9)XtCKDJ z0T6`hHWmW|t}2fJvY%~j=zhYKs0HK--U4~~OQr9vL$}k?6(92KE+IeqQcGMZRFSs~ zaTQXLAN+#%-fZvMm+(&oY#QjI?8{Q-m=fz97ekuc8*#>%2#FP_Iy1)4cy# z>D^Y*ilPbT*@5RvDbkx7wg;(69t76%kbk#-@ zV%jIa3zi$!Bf~UuK4kzpi}8vo2KI8*uk%vlb6k{|ekWMUcwq^)S2$Bu^-w?P+=`vs zTmnUZ7VvSQOm zSRiY8ppHWf16L)gJy9lx>~2~=HiUDn0+soj--;y`cEynqU2%9Bb8yBFi=Y%AiJ*Xx zruM}!QV;`N}mhPD zG@qY1SFaw!f>GYwf>TPNt}z$z1?>*?5#o=_#JCti^)HNty z?7Q!+Uu+RS061R<;17ASjW+w@=&p<00v~!auI~=cBWVa_o&_oTAm*^^3qRm`>y5Jp zFHCnCj6^g;5K~EUfKE*3>4)3D@aq=Q<$B^#3)-l5em&E+$g)4;tw}S z5C{F}zd6ia{3nI;>E+;9c`u^}5<3`R59bYqV4A6Z)2rNVC*l;qb8A38F#ancDS z?48~hHRg9J787}UIa{5dYJ`}Uva4IbX8F*Rrm+J}83o0^0>1RxTUZ23j~F&2wAe2i zjy~^L>zisxSaa^L*Z^GI<-BrZG#-DlP!%mqb==Ig%ecI*Xdru zB2WKy68`y4Th?-CKr1!P6bJMWe{>=Do8ph_g-V=of^5Hc5sZBD{lJYl1`-vbMj&^N zW!&O9f!4?{0fAX9h7jP~b$4VdxXz>B8wdmF-<%AU{GinZJot22+&PZf00hYE2@|c- zqU^)Qi2aAh#{bFD@OMD_Inm48BpC_gvuYwMuaEK`B*3Ye1}N7Ur*cME7BhFk zHQnfB``2-JQD?n9UM*%CGzPyNuG5(fY>9Li zuQ_GRtJ(((j6H~JLkYN4U{f?RB#Yb7T@L3aP#}4I9+*x&ni9# z(dG>|tzg2Erey_YqB?rBoc_?wSEM`hjJO=rg#am|7=Eo6pv9=M2M%sw`RA~Ezxgak zOl=j;gov8H1;Rjr8|o4Owal;p4xhEy#T8c0`<#m}A{6%C93mJW`g89FfI}imfl61B zhg@u{7bnj>6#MkI|G+eZ`)iGVq*%K!Bu?^3nq0kW5{hagA3LNE1dijVX@_oXj#8Q3jWTNso%l zk%wvT^cn+i#vW!(y1}<6_`>LQ|~*GvZYVp~k2Ai3(KL!+j_=mhxso9c^GHjk;vr3ABVHSf3e^Kr4VqgK1z67aYcD~b$HM?c0P+djxl%*p53kNY z^#DjC&%MyU=MIp|AW1!K6kn(ygs28d>JuabB1lrtY|~8dMoh0T1s-ly{Xxa2InYY} z(6~dnl$WR%#+OCPE~WGNmN(YG!PP}-qB-WwXUF60+|CE4dYd;iH3atkY4iJNrXjfh zJG2^MTU=N2A@JA8uL7H{MSYC?XfNlU&9^om&u5pnsz<2d(o9c!O%YHGaO)zP%reN= zQ*ZLM-WFb1@djmyGHpi}$gY?LQB#ZgV3GQ$d^FBf;P0vaKbLn4yAzz<#lyb%a1*je zQtj#Xi4(w=f-zgcNi*}O!EBd~(iLlG5cG-HqTk^Ey7xG^66QNF z$Z`*_v<2*;{oXspe^H>_H6c{S`q{KBU{~mtU;Of)_u+TDybzW1?z3mLRL;*NNS4#| zyogguQQ#h6;8w(X9dCf!Q>-Cz4|#o%`(>b@ZfTd@699}G*9QT>SGK7j04U3Qa1#K;Pg6huFv~%LrS+}{Bu!Wjf{QQ?y~Nh(&=O;f zsOmR|BfZ-;7h#l}4zgnz-jgup$qFz^{_ht0mf^nDBN*E-#R*x2f2hQ<(9KQQZf79B z>H=3D?s&*kYYB4KPPPbu1U6X!CX3M65613Z?Dhe7(7NjRL}Po8NxT?j53(9KbK|l5 z#p6wz$p4Wp?+IY{^}kewTk$|?u-0+R1h{W|0o!oyt6+5w3M7R;6WjSooc%A^|DzJ; zLx1=MQuJ2}$3+}gGo4MnQhxwjaEHH%85^TOww%Y2Z)mza>U1h&bXvFctXb|9(Ddv$ zG>eXU>%2TXR~fX7;@zb0pZ9TI7mVUusyC;5g6@IHw)?Xp#?`Y=P@@quJ}XH5rgEEb zKk&b5Ui_6x{yV;MHsQ5QgZp&Cccg~th32+p z9OqIv2Sg`|Kiv*L>jcRj*`#*>cSoaV0a5_$41me^$~`G*t|JB^xQK1HHZQs^5HaN+ zs%WnB9EeYT!!6uNnASM*bIC=DL`9cgtCv>K+sFQCjo(#>8RX{-|BkY*5jf3LOHMKC@& zJ5mP5C(CMcjKKILpL}k3;;Jwv`~~BdOkdM5Yp}n}QQ>Jt60>=zHz$Ub@Q}bVy z6stHk*9AP&&U!9GLO+QW>}k|%gKLfX!?g*JtE{U8W6ANZZeG#%Gajo- z%vH&$hKMu6c!|~G)p45Ikj3P7segaX|Gp>w?U8Y3S}TiO{+Ka5@{W`&q8FFrYSAJP ziLfiPg*Gl4dS{fepLh@Ab63)_z!c$cjb|e2`#LrNCEs;Lx$-jiZf2CT@&qz#)vjvD zFvzjoqmGU)IN7}TGfnI7EBwDSH+OJx5qfqlcFhHVO+GdY*Z|TNa&IfSY8-Kbfb>!E zuzqv=^(|-+5BcH*9FP#O-=u?|0JQ9*e;mygAm$&2av=gYZ~!cGWXttxi(~wD01p%3 zdGzp47MTdnYWK3Tk9BhjyZlmAz%X?IIO{tg$|v23T|rJP&=yfSMRn3Tsk>n>FJ^_@ z?5GQRDYhYvtL8#4k#uf8*%^{0!knG%Ox`vv0 zFGgwKwhqrC>GJm_(fR#I1)O28!TZ58C@Xh~e@7lwfxUzU6 zTCH_kDFXFDu%QqOA`7UfG=RGxih)RZ1cF4DAQ4b72vWmyZLNe?7E*+D=@}s8F#r?emyfJ7i2`+XVHQJi zUV(|XwdKiQ-Jn|;>h_pcPdP1V9Qfu*Jnhqt$)2u}YBiNx?RF_#KP4r@IS%ak<9k2j zZ*akzz7-$<_yujTaenHI%z&jZproY7QZfzzI2?%*WRubUjfSp**^18_n>O7Hd|Ylc zT^6d6hX*hRNCzxeSBb<#N*YQO5*AvLx53AbKQZ8W>I;ST{>?{8s8Qv*6UES9Bx?Ky zPyXVT3l%bW(m@b^i}g*vOv!BxhIR#!yv(5SAnC%8hRUry3r5zVo!__Le4VGBLs~Y}VpU2CDSAPXBt2Gpk{iuhDVKNa8z`>|LS?%X z2d|cp_M3khAGvz7@M8Npm9E_JasurZ<3!O$J_671y`;&~RsYU^cD*n&PCT6r?uxT>5Pf?J#x_x9b^^t-i8Zkg~VEHp2hkQkzhCLEI1x1PbROm#Cur8(` zT%1=@HqH=NGtrd*MUR;o3~%i~)-y6Q&02)}wl!UteoU5a(yN&!Med8_DoZyuu*H`C z-TYz(lx0UF-pF*fD@WIjl5qPDC6H%ttesp^_`8@bU$)yHvHX^0{f|h4H!XUtueEGS zRZMTDlKVGH8YjDzh*lBKi&GH$5q{J5&L1j1987BeETq;TM$PJNXez6roIfY3tdIaKP6&@Pv8N_%2WqWDHNNg%>m$Ue zW8*`1wHGRjC;MChY#MV_*yVD$0TaOgA`*#x2qZwswTl?MU4Ac$Yn6b;-Rtccrpdx* zVzjP5fTNswJcNgoz~f(XyL;5cus>MlPoqmZC{xHf*vti?r@rr^`8VPJeXH=`e-^$) zhM{o_6?GYV@=UnC{PAHptnM)Pl&o}=LSeRFNZ2-NFmgByZRrmr(dhvIb3_u5s>uFx zUZKo9^5n$6hY-ge`?fUC99g%AviIOrf~Qdoiw%cvyfL)&AIat%M~bBPdo6oav07@< znRts7Sv^&Xx1AG|$+iYM{$3Jnan4L?+u>=sT&8g4?rRzLJl(@|S-yPFTeO}({RRuX z$%A}x8DY!b*0XCS+cI%78iT!UjIL!McV!@l0YXdpCtGxi@W;2z5*Xf(K z<>o2@LO&0x3=Po(xV-b9xJS8jK0r3}vnOiC z9b{_nV1$eJ!WA!+oiDtf1>QCRJeOt&Bt&~ep(c(WwhiO8TcELzcW{Q_S1OnUjs0Y5 zd8)X(3O$!S3;1wedJw>e3;Nq8&p^|A3XI!#1o9r=OtyTquXQ){ zlOv!>{8roRf`*97&JL~LRD?s%Sunm+A@I9|!#iXbAE~9~PPKcxCq6bXFSsB#?XPayYiDzlNCe z9k|o_J`3$-3X5q70{U;nb17w$K;Bl);?8tJAzn0Ew zxVA3&MDj0mo8NgS3%qk%gFtox=rd_^L0>!`Zzu>znFRnUHi9_yj#(s=>uE?ieu#pN z>FeD`@+^1J6qvB2aD!N#{KUmjip)sdhrW`VCQ1n3rWtSGA)I9eq541VY0Nh^F^ZB_ zVRAA=9l$!zdISN1^rL1spV+VSpSk@YIN)B?xh!{d;siGpZub-v=GZb-a%&<$Urtbo zVzu|>w;i%e^2#z!k(w`<6$oY4(`6$70z0bCJ2*tw2fXN=3^8BnB@4XMtpB1uO1pRB zXc}zLMjU5@>_@bQ<;ZO@4KYc<&RVOTs`F0nd!o-4%Ow zA~Zh4o&-C^*91gZQt%Lg?|1xPMusHnStda1TL8cnbjWHX7h`N!184>u@<%8j6zWS1 zWY^Waj=fu9_)yYSa&d%c$~S0}eV_9XVaM%2mq6*<+6=t@v+AK=)R2wFK3AkZ43W@rtm;l&ar+OAPSNMD0G{00(|{+35VHYKE_YTJ@Z=)o zatPN$17)%bYrX@7g1_>wI5AG}pgTtM>k@e&!w;4T?_<;W?yBp`QW9=flWJuQ@ZqY< zM6hwx?SoowG{dHolVJtGyZgrK$;@rOfHD>=eO0^p{nuLHEeo@+y#@pV2sfGt!No&! zpJ*io=*pS`kAa>$DGM~?)V~7Mw*exo)E8>gHAj6L0Z`wz;f{8V5YZ5e=3ai32~4Bt%uE z>F2H>$hF-`Im5@dZ$f>6KsfV8VN67vH_f;u-RtoLvdi&%TqiIKsEd472KqEDUpU|G zf29pyIs89#_-7Ifty(Yu=bkK>7JpZjG=^4CNQ$x=rDF1A^=tfpvyyGQ`2)v=6Klc_ zkea5WcF>_V&aTlwh(}Cc43*qd2K{9JGqFoA=;Z6^H*kh^k+Y4M4JD+BpIg6F6BSK9VI{=P-VSKohVngl!3wV8>KUZOiL3?Dt$Tc_ez zba8iB zrLjHFd}<$dd!HTn%94yHjSmT>#XienGra7vm)#s9K^ IjeztfAYy<}r1$pE4Z7{$U3b6dfBp&FekXS(XU=)gd(PaImX&3|t8>QHVz-=( zoU)AEPC2mB4)y|eR#rAvHg-l?vt|tk2M1iDD_A%=IafE(Elw_OE-o&(8pVRTP3XTGAg2(n|Ufs8a53Lw5VFCQW+hM`* zG0Cm_kCxsU2kgE7%8ReO27K(yd)N>xW*uN!2e9kFN*myW7c=o;`G6)^0%P2-8F&8m zV$XzcjLizT{%rn5Q^kXf3d;y1531~SBN}E7^Zp!Q<|q91y?=g&$iI5rg_fnz>*7#f z=981s?j!8wSdi!GF}>~sTT!=gl&DXX@)d`otM0q0G6fz>T|DMN2ixlFi?!F>SZ5Ka zaB=&{$g{@zGiS5Vy3__eyKGOVuv6eR6Cw^jI8cdf>j!mqpbkjlII2Ic%@aI_-)6Lj zc9&uqe8XMb-!eEP`oA_CkPR=}z^UqwECdVz03sLy$(DDSK0LPlK(zk+8rBB@JD%j9 z`1Q~3h6HOj>2`XV_fNSA4JGPZ$Nh5?K9odhd&Q58M}LY*E}_<2(lmTie&BC*7xvaL zGhAE&#?l@)@`gIc?(J*&1WX@(0yb8v;aHc_UM3ZTwFwe2DVJYHU(FsX_5j0qH$HOb zy#y-C2>jdq8teHSbPm~pc2#6o^+zs+T`$;wyAZBSuxTIBHu61d>j#Y8wvU`9 zrUIC<>rEvDhi>OqfbLO9n-fbFmm9y*6*uezesD}@nU!+Vx-B9oMY!P9YuZc(&e^X4oze()!_JphHh$d zQJ5@ee5+UA)mKiMw|0gRT%#;sq~1?ocja7~goOXEcm1<13hY0$Xav1+ z*G@^IJ1#ytX)ab0buBEOHsW(M@_P;ve^60NS-&Q=j zn{G^9*J}=Vi)juh$K*u-){pR(=2J|r_i`L}}u;c+>p*>x*$?udN7sUx6PtKL;Hll58mGaf|fp**1Hkr#kUrUYKauDYMnIrIflu`B(^odIPv`Y^ae;T*~X z^6-zsnShmm%>+ymlBvqd)C@4y6C5ZgezjSWEQsSCe@aOhlsN1cnEsF;a&{ll`4%th zUCdK(5%7b{y)Q4hr>MqiWE3&feo$uI}d1B7in{&?Vi(pmqj8UI#@Q71> zs9LAS#sP~t#}!Z}Yw&(VrYg{6YH&$;)~?FO#j&(I)R4A2w_R$gI;7<^fzb#)Edj8) z#n}Dl3x2J?xXtIalhAjo5hKr*3JZ7Sjg;L`_SCep@BcD5_D-s?t|qSaOtIQb>4@(s zrJAePV!fU`x%=J9etW?;tq(+YIXm?#%GDR!Nu>oH>a(3bn)YIptoxome<{AFA?jwD zt?G+NwGm&@2-gAQJ1#!ggIogxg$v0lSL}=Lj177X7q&OnMmT>P!or!0jZP!u3SN*R41##b^?B=AfWc6qQBk5#;rh*Y~!CGZL%782}oZ~?cRDv_)PQO8;w5>TGN98eBQkB>G@MENZ*ORjTg!#rV}{dK|OG3o4O@4BB$ zL?mt|ul+`p7N+;nmCo6oFF{A@^w|VsZhk16OK&^Nlxr%b(W}uv_<&i|+RQx!n<8_6S%o^c-gjn!EwUj7|1w(euJ_ zgL&&cTQCLnH)V0JZJgU>ajZE|I@{ zl?(UwIfp#pcMgHW#_~LoZQldXN?{eEaNB~NaL6%n_`x2O%EKk9Z#+l4@e})WPjIN9 zc*4}-Qbm@7?nWUjB4-I~`@ltUyb?RZs36eFi}8KlR;XmKCOb~yjgPz9?x+{EFP`l^ z$+Pokq#At=O)c*zuSzW>EBP+Jv$8E*0aMx2a|PU9E>phrs?_-Q&)ipWjNgq3FAj~| zzb|+{aDoI-RskijUvDxUt=CS$VjwhWoyGNOzxNk${?B=4ji-w~+b=}8#n(Jh|bmYq6xWVHBF zGQDY}epBI+Y|zmTF@wDaMYxo&4d!@ex3~8!%qlb+2@kg?ZOhrFZWgtqsX47Ibc-}h zFRGtd0T!fzZIU^0Q(h~e%CoOLbPcMD&ECaH#y_3% z`eN%TAD&|T_O=}b0165y7zJSuMbJTrmy2|&Byn0AR{L>U28X)i*MuH*OTcsx_@03^ zLU*B{Fb`GhW8^EU-(w~E>;^D){fzsW%5m$IaG1@GV4chY``XsqcPZAUW675HfRhmK z>R0@-^p2EP%F)$5FL+^RegC9|Kho1rjtpVBl3Cl@-*A!FtK(3n$JkS3?ELxnSId&- z;25-C_FS07#Q>%+$lAQ)2Tv}S`c_dmzYHpy+W5+J=2^8CU=(X^wa=>Ss(H^0upDvt zm>!Rg}=x|9A;1b;Rj<4rd102>-+iD~R z%Z$goUMe(PoKs4R{G36PAEWBZQp1*&J(k0skUgfCKQz5_XT660s2G0uD8Kx=|9nG$ z@5Gd&e#4x*snEAf@zuo(Re58bVeSiiriPox zJVV{hI3hK6wv>OTzTcnzhVwF7EyHY74Q~;=19cxinz*X*D0trN<={k=l-I3G8Ppe% z$xefhmm@cY8T#Do`TVjqZI1%|nP%)Dxk!1uY{RQQ&G>y`W+mr{dVt7K7tpt2f!~DL zhk;A|!%&22hO2{(#O;1kfpV4XQlmnV3n5@mV=|9{b-RGV1tv>FXb)3eNo%ZEAF{!Z zG0GHMK+6a4;x=JzF!Yls0N~yus~3D*Vy9YqG9BJtS}zr+-hcXfspl~^ znSuk?92*`V&EFxQ*OQ-IFgzz(&C7OkmP>j#gH{wd{H66vH}+t#=<$PsS@mVKh$Ynm zFPvA9CTqu*Hg#bM|5Rb_MI32j6x~kK#MZt^AWd9WSL5(clf~BeH}aY39+>t}+-GpR zR=qGlPvFy}tXqu!{woD*+xwgK1ST?SJ-^%^5HCDwl0WV(`J~7%`of&jfwG4Dl%yM} zF`q|iVn@ea<784}Xk!{-qnqMnvZ#IU$U}vj>f;Ynk8CcJKVm9!gr`cT(;=kvVZBu#ITB4|)y62GVzI}eL(#4S2&Z(y-ub1d(g*ec^}O6O&${)r`YoI> z1rV<$o^2q?Q>`R$v3ck{Si>fQNX*6tq6n@ z=|Z)uJb2L}Ek2a&IZC6|%~91uYAvY=?qUynUz*J6%sLLr(x}BdrsitcI{Vy>sxF#% z==7P$7yj^hv>>g>E^u*bSoq~&Q~G(u^F_O|O>9Grth8m_y^@~4Mi@=SebwuXoqxKJ z5KsIQGrENI?)v*0xIN}G_iC$a=X@;fNNM-%R+{R(yS-dfbxhsCe8(FqhXVfqQ@6>~lU&o}+>X^L97?YNfv|mQ$ z!%v^x>F0SI992>ehnGG}3=EhK=YNk#?1 zO6qY&IZ-FWp$4b*c-*n_3uW5^!a-mmfoB&mHe_f3lTYEdoj{)mbB>oQ;x1;3GyErF zz*-{;OEP3F${{rYxNPh0BCmg|eV8g7GY;7nY>6BOTe2&*W>4OCdoevH`lI7Ska}wD z%o(-#wCcsX=WET>Wv>ldHmjxAPx;ssF00yVxV4&}*E_!Eaxv%Dyfb%7-G}eACr0~S zqO8gMkqIs{kWCzz=K#;dkSs_dnFP+E_gK~4pqspICa_5Y z`*}i)yS~OVsJk$}j;ibWg3p|_pBB^Um6rDGiQSUY#mN0Wo~i}j+!psDKj(TyZaPHt zYMQ94(aoRp;%7xW@R!1-qcEC!ntS1;4kF^FV_A7UckR}SHj6E78+w>tnwU!Iv#tH+ z5kek>;Rm^te(94brwj{*0OwoKOhGJq$Ou}w2LK2r5ulADFk_g3eyko#X$BaPcPgbM zOj($WQev8~TQOq>e%`5dFlIeJrjGX;7-NQZNNm%m5Am$W%{hI!&7&^1%NBSnH)rNg zq@^Uq2WAVN3A+^6oKt9DWYp==;aigyuk1LeejqBurFWM+ZOXBp>JypT6(PnM@3R7w ztenHnzYOaxXMnf=&B|f)1oZYXB<+`u0^s}3o|r<dux7jZ3^b8vfDpozegPBW1V`f8TEYu>ry*{gB95v21Hw$gu~Tp$B!aNk5MWp~ z5SX3Aku4=nXK@O0raH4KM_0g)_b(U+?fGT2{W{df5#}(-EurmohdP@-d{$mVtyY_U zmD6!;oLrcGa?>2U=G0TVlBqkgmyi311>2IV!mP2MZ5Fp* zEDSVW0rBcNh3}pQQ)8nf2MwDtNQ;GrwCn9V95UZjrM)WBN_%pnP))gNG40N@Icv*) zANQeN4KZ@)+?m<2@%Ay@`)<=UP8TJ3Hc}W50T=XZE!z8C>L2e6!E@gW_lt2xVm2t9 z7SCJBjSf!ra9G zR_jDug+5k@jN>`L*-g|Ns<%2y;W6Xv*3d^V zIPciSojW_?Ti@wbpi(fr0-}tZrmhW0j_X>zbvN&xO1ZD2sFXWR?+dKA&CZEWvU);R zXm2b;&h}+X78cej^DTURP)`?IO!F4Jo#no zwe~KzDHBV-iO<^IbHh4cQr-JpyVOz*?AqIl4w$kMe)BEg-DLTusD5{snEBnl+3C8* zqTAWZU2Rk5Q|{(s_P%%fy2Ko6pBeeYPWXt`j19*o`TlUpsp!Q((ZG12M(5(Dk)YiE zcWH4ucLDGKpeCm;gnzvREtIe(#F4s{StrA>=094GGaMn=Zs1Db2Zmr*D6#>LFPlh6 zuH)dtVvn(}g$#>S06P=3R-En6F(Iw*VAQ~xz;sZ@0c?|rxP*HqXQh60qtv6Vxvw5Q z7TNCmq%XTOE7(}t@@r!;4yAqPVXx7*j1bnyoIE6*^E9}iP;bVa=VtXOk0VD?Q@$Cs zvmN}OHN=$N=?ZNFU9RgZJr+kQM8`V_=%|AIf%+!<_2J0UBA^^H5sh8I0R{)#FW~v> zR{{X_JdxEEY6@U=9@&_l5`w8L9U=zcjOTAA>6~G78}rv4F&SawUf}i9Ojci}!3vA~sYn2?*Pq1Upf&;|}j= z2|LYp;avhWX+UKk!u1y6;>Ae3XI=f{$J|f2sz?y3PquKS@YqE<)hFPmyA9t^cuopD zmXHWKs`%I%3{>}HFTh~JsvM($anHo5^$%;Qx^Xk9O4J=~(|PWuuZHt7CL9O0K1!>g z1r$rASK2yc8x2NE4tkkCSON2LQ%8;#Rs;n17HvN|vNvjOYH9^=+q!6U;hY80zWje> z(!OWUFr&-Lk+0eeo!f=?6nN4?o2M+qHZ5)E8I2$8?P3!Z?59s0xc1AB`~8h?bP80r ze=OcXHy8H?*-9JF=2=88rJYy-1|eh9GqYd3$7Vz}MS7nUd*)SrFsi3r`{c4r3(eQ2 z(c8zMti9{1x5JExV92EH*(L$X3#t^tnc+zNkCuD|+(fMuYPQ0^K#raSA(kt2)tjXG z*EL;Wd_CVYUY2{$fDj1>@Ye-cZCmf8eq3YMkBhFz#cYn-gUHAgzTt4SlFHt2WL-mz zIt*V08;=^_3H^esK0P)rH1t%fjzd%ns3wy=Uh3=&ZU4CR!}iKEmEHBJ289L%^OTZT zlEPudqqO)9#+J`KyJSyl8n+oI0PwX6)P&<8d++Dxk4D*|;UW=bcfhLrz%BFxFJct5 z6(mL&=@Nz8RVjnA=L3q*qNGgiB(N2sGIM7WNTY)n9eS)rL?1ub*BYbcb_%~z7j6nD zBDqEV*pei%$1vO^&&WIP0>!I3vwWKThKpfcUWJuTEA!AK@f}umRbU& z7yAV9*wjdiwHbKzS1vV2DKYKWEjS>z5nv(Y7dV~?0pl}1tt^5N0kZxC*f13Rt(Q7~ zg%)_+{Xs^}3A#RJF3{#jNE2L~YBL=xywcg6)m1rM@7-nd$s}z|$hc>2awfB&)3#YK zC!o!?KEJgqBGV*yP%+E#rGBiZF z)f8&$dsl7Y>a%=r`8#Ln|Gs$MBwn>7n;g4no*6PWWp18U);8gopA)xeQu;S{0c$*0xXn(4X5dr7A=Dei2N)w$+1R??%K!FLycq1m{%W-HNBMP z3gk*@X3NH5o#k68Q;VvhAInH(MVwdU?nzr7Kv)O>@M0JM9NmHr778?2crhndITiHG zH=_zS|4>j2$4A(hPGOV09ZNzcXtz^H*y5zCg>jIo2qCK}_BXyxKY7wjd&6XZc`XeZ z5q&n!m{=0_s?mPlbHH9W9C$!N?KAjtpTZ)52_bGwA_xz>XH!f>Al=N>?IjoqL_Qr& zz+OhU2$%#22sfq>*;E>VlQpuFLMpkqZ{tuFrv2#4ZoLztL-LNr+fE$J6zaRKr8iLe zvIpX)trkLv>b?;EO+O(pYK&umWmMM#?8n99A(JYFp*}~n?Spjk-3kjQX!P1?Y94r+4cPWn={wibiE7Rnp_+zJGL|}%KaR; z@ts4&p*ESr2<`qkN}zI_H8$i65Jxyb2nj6977 zomYTHVNrJ#IYzglK)6qOQRYQ)N?GCV;eyh+VVWCRB*$ZY#IR!3rLxEWd%^(=L0|8y zw1Mv?7qGpa?V|7Ty{>7l@J-I!dwwpv;i2MH`-IV~f3o-%X#J}Hesc@U{q|K4^*u{5 z=L`Ap9vLIEI*q=ql@`=9(ovO`ngZi1Kxaz#@hGj?c!{ebV0h-$nh@8jmVj=G1kLL~-C~R($Z2ejbWDjw|9IQ+jiH(Qo$Kq`)Yq}I?iqT&+B7CeF0ca*;7>vKnaY9UbEaK5 z4v0SBFo1Fn@d?xFfIzqZs=#~~JcQWwwvCwX#*+Sq+D_-06MW{Ijem#4eKR_-IaqJNzULTd$INeLw31!Wn&5DPypz z$eF-eRSLHDwu;*oLIB!S^|KxGR=Bi}>{wno&Yc_nm@{MU3<@@4s4Arf zE>M(D9vDN`Zmx}qq07vSFX7fai79i-jIZ~JudT1+6+Pn3txWThZ8aO3oR`3UG`W;* z^uk-(dreegb@Nan+s&IB>2jH|S_c%Zy2)KBDMxc#^5+iGR7P`(->GnNeLM}O$0w5F zrGtJ7!E4;O)8F)<-!Jezfzdw%n6k!#5<>bYJYmF6TL`)Fo-&I{G5cmkDbXi@d=Cg=iig6)aPEU^Z--#-E=YH&a96N=xktjT5 z{hCc;)dpZa+>&@P19vJBl>?_45y*AoevO2UNzhOr@&NKfawijUw37*37RPznVmPW{ zc0dwGser)2c%f=V;8vO$uwSo>zXWo-V3Q^PrhPCqhX?^Aqg9w1V{H*{wXBJ*o3b)t z)kZ_9w`IJZeD*Og)|Ted$(m@tEhdv$Z8RK|K4xZ6cX9rb<)`AmdhZTe zYpQRbV^7qLS3&+NcM!Br5_@+s~tIGQGyLtXQR#bO+1#tKjTK$65 zbIPs;aZWnV#r*i^H~q=cujU{3`%_bnUSyLdvpw{hs<7of^UMDwznWSu2{!c+t1!J3 zm+I)D-0f?(bZlmHbi(`LHu*zaf}aLw-Rd$Lo9@l8x=6(ELKPo^r}W)F4|-5=bK(Ma zD^c(nK@hA%IFBL9&?s;sknEErfe(h@gE&(TJFxUnh}_R642KJ^SpK{{kiBD3skPKuf4%t&&T3KWiuAwGvhj<6t5<avws5Z4(eZ`VqsZqw8-bZ|n=830T)TxZmPM)Wv zom_vRffo(~3=n|hL;#Kyi1IOqzy=g~8AIenKwZ~W@bfDe`hBnc)gGE22@5-gM^>47 z#7il7tcL1oKTu?qLI*zfJ1jG*l1C)zUV9%zn3`-iZx5a-EV_c96FiUssZpD)ymDWH zbFuZR+eGf_UjUH(Y{XQj07n>)fRF3)X3~m-#9bSX+6wNw2$w&07f}!f<56e?FLO%L z*9r$JpTeWB7Aig_>e1goi^CQp6b^GT1FZP@T|#hJ2gcuz_+9?kpFjfqP|ycv2b!ui zjzw<ijBoN`hzIub8Dczvvkn!nibYI1DUwJ+^LUsWZ; zQ~lHmX&=i-sRG(~YVp^$lMvir_0L}(=fF`Qiv9mQ6p-IM4m~D@TP%pld>zr-(vL|*VKP-XKh=cX5o zY05=A4v#wKPPx$Jh8iV!o;^`firsyOq{2wR6h~mV4*dlYjtszvd^{%@L9ZJy++KM6 zuYKL$bmJd4QDOv+G#DFO8(I5EB}Z^~>9E6Kk@iwvb%EK)E&A9+on_iw#&X94eJ`CD zBZ5GAB5ow!u%5#G29JmCNZ%>Q-kbuolZjYyBr}%4c7YMfhS6-80LB5zDKJwL+T@dn za$};ua$N$~*>FVlY&eDIfWTuse)3az1Ey=kY5btXKA4UIM8pZK{sVeO zm7*bA;%*66K=1d(9fDBFGiKK4*8*pM#ylQWPT*E8D;BUob^a|1NeLJ=S7GFhuSn@hGo9(5R-ELn--m{=G zX1^rzsIQ{zLE+l&i8&olmGRtZ>yUdRWzYRcaL90!Gf|i*kOG8W&0WknLy#c>)hhDM zaxiTCzZD1cdUkYy1AWh~HIzxo4?k#M@Xq|1!qz(_m)jmdx6D|uXdRQ5;WFE?`(f3h z=B|-xb6dTGRTYjTe}#ayXk_ZZ<-E6;=a`>Bh&2Tc4s59QUF`iv3}7=+-4+EC{-uB& zFDCaM^pCZOf~P1j;Kr~c%mylu{Y0>-J4krd)75zV)ahygeo=oIQAkdHt=Fc&%Vziv zxIoIZ9P&nA`2qxeQaF&@N|fyn-Hat&+U?cmuXyB}w)Uk2+MHMW3SnkhQ<_-6mCujf=!nD2bN?|jO{$G+l*J0yr5Ad!OOKtTj51; z!$EP*V1R=Jkn$6Nd=yi8G!qIHU|SgFmyNIc|9pioF2%u-TUJB&I3k?dae480j=fm0 zUD4*oa~V{nur~=j?>^JhVx3>eznL}n8ZA`+h@X(wV>6Ykjg)M_wD@C*2nU7RB{6|p zF_E(8WQIN~3#LGW9zTbO`tQT!5?H%|kT~pfg~JpD2KgXx0n4B0zw-npUk6Rq$8<5j z=J$}(A+i|~^wIw82Ai${JHB5yU0w(W8UB-~kIj!xa3)Syp^|qt)h=R&-aC~4AtBVd zNFh{-GgT?JwACtABdSE%d%CIAl^$h(e||Bo{7c`m8zZfl7I+nhHdowFf}vv=P5*}r z?DXclEq{0I{~Mp+n?UpAQ4j5M&Zf`G&Gj|GsR%=K-(s=GKy~+`*5-(%95t!Yfv@81 z4+R00YZMfme}ExD#`y$>x*3PADj)Ek4I!LoXw+)cV42t4f^M=d;I=aQIQ+x5Q{9C{l9 z(0L;yEN$`lL7TwjVPCH4>gMMBd6B~H%hj5nbQ{YtWAY{;n4OEIVvq1V`wS69cBU+# zaF`te7j9)iWG9~M%v`iZCs5Zr3mObT`dRQEK&}CmV5lrOPf$3I`APC8;+nSMxbKOB zVZXB+s-MCk6PoFd&E7$h2z*|`(CYh8Z=VHyCIZA>{LDZQ#w*WPScclmYD*xRn(z9} z%ujZEx|NP}iOky%PI&t`g)MK^y*QUX7-Y8s+|sVkN50Gxp36ls{_Ng_*JxGjlz$EE zdH%oX!km4r3Q#fc$K;=aJVJ>BVbe7hq1(L7aRhE7L6qpU z#=SE+KgA;QJfMdcO4MDRwj#=z`pRE@V>PKfvD9$3dIe}3WK`a1i4!Ui&Kmoa zlXvNhe3MNr{oy0|S=xm65rq-o8>glM=FiJKAS-)y9oJdt>JBZih>yM8J@~0!qj}ac z&2aeor{=K6oa)E@d{DxSfI90p>38iVrHj6H!UQzPzQDRGQClsOR(oL5yc>Ilog`zT61E*1$DJ@8F=2 zUX46O*>nCSqRhe6)8X(1Oj)$as7FI-#zAru+7Ql0D8va2QHDAilt}pVLT}a|8@IzB zKYR;{@irKF-G+-vmLrJ#2dZWQY!KQG_{R%_x2vK|fVOhHa5MEXjqVUBzu2*@Zf*s5 z(#HnoPlX@Raa@J$9(`Bif1uwQEeX(6qo>4%-f-j0S2b7e_AxjYW~io2Vzd&+fLV;q zf3na#tIUP`-G#HiW*3z0nr^6T=$bg=(7vqXJu@}tRWS6Jv;?G#NYBeUn2-l9X~;E_qFppqp3Ds6T46J-n}OQx|P<;ME`Bq z=-w$8bc;DoY|bAlWcMa@?$L>;ykW~+te@UOErGBw(m-P&-`EJP9GX3|LtpDZ(1F~Cspo%->EeI83L-A) zXdTos;K$@X$0Q`6z=#4L2&GhT6cpy*&`tS72zSPpBXn;I7G9Zi%PjTIEK162$~Q@< zdX!eJ?lmLb@6=Ojd&6g)k1>tboWERl-u=~^mT@kIY%={T^zdB)ohuTm>!FP`1bfCu z85do0qBu>DY*ciTfd%L^JKC7Hrl(DHx)_Y6ulG zlU`}LH8Q!=Q!-34O!P+NaJ_x+gnSrk;sj0!q!P~BRvvJ**~u0a( z%}2k$M~VT$5wWMe)wk_(Jf9di58)4OsjDf#s##Zaw(E)VxbD_ba~_V}$z0-4e^Dq6 z;(&h3A5Y(aG7u7I*WiECInW>c&EB7FvNN#tAJ42(XON7;QP`O{ur<|Gckd&wrspyu z(v-qjZ^X9y7UxX7@}}@yy?>5lTa?Eu(*b|gPy1j3GXF&)luZ~t<#l*hMYx=#&*ZlK zGFzH%dVDKzxkeB|EdrVV20Iwi=d0bE0;xhg*IR!|=N5uU`c4*+(VcKD#{&NuS{H38 z!gxdk3NRk^QlPud1k-$&IK*GtT(n5JUMwrxTsdoguh#Od_PD0zv+MO#$cD&twGS2Y z#Ex-stEq2UY?)aBL79zRt$A5p%7mcloHvQCk;OeGj^wbRT`wB@5moe_74%PB0-9bYCN? zIHT)u)qvmJ%a8jET3-byvsXp=YPo;+QJ7^?~zy_Y!= z4HZFyh~f(vt>AXK0D~6D&P2$%%Dlk}RtH$Az^tbTqY_ND+kQ+te<=m>yM8eaIDCh8 zD{!iiCki{6EP}l(ulZeX@#;05bOTNe$<{=^J1TwZMSDFIQVL@a?++Y1%duxrCY@az z#%aT7N6jWPn~o(+&T^9W^n_M>4!e#!8^}%WQY1?`wMGcUncLK@fbC(K_Pz(N>Kc}EypU{y<>%*jioY1B_Lh97K8Co_h<(;H3`V4eRax$z$e zclm5@81(Y#bsuCSJMA?Ny_hM8T3}t-fmO{?8fR&1I?e(zF?8^3r4H@o=jf2HDEmUy^6K?cXKUJn-&*>&y@5wxhZP zolu5;&~|?1=U{+BII$7ZbVL}}*1E3G3}S-tX+LX|-6W$6S7OAR*KPmr_XWxH?} z12wl$K@fnNNZ3W~2O{szq3~%I)UFo1)}tyY^4cFvk8Ry?lCMqboF4U*V#0Hzk2*vB zyl{N)5_M?d%;6u^EyRO17>v<|i?j<(3Y9zy&6J7JtRuCi?%oqD6pE`m4x`DSawhGVfXeB|#)( zx&v8Qq#zqfi#p7tbc=)xl0Nwb=7v*P@TkAXPq}(S`w`N8n6mz*Dxz-ax^oCod4uEH zk8u46B#`7fKSnSbWjUadfmcgFBJ@hQe@yLv5p3Z$cK9!jhgAal>P+d?XF`~m{7`hl z(C4c#g&hSdeT#edu7K<-&eWkItCu4grnEuXt6t`D>q@-X%q$MRw>I&t9-mJe$;@za z-I>!}j;6ja6ZaEVeTCn(_fK}%h7SJc`JWvB^$_Oq*rRZmJ?Z5bYSbsyHhlpz#|fu> zqIt!kyQyl)d1f`bZ?g)1P)br64(W-Q9dpU^$jyn`oaoejz0gc+->)_O?bbJZ;%rOR zUF-S5A*bCU=syprdj)4~!@7#vdb}D(R>0AF%A-@9Bnbp1@ch3TLJ9y1`Y_I>&n5vG zX@YF;64p3ao@o4;q=|B+oa6>2=*ICS?xPo4tG0nQEc~(TKE6 zOt#YXGE(N?VpemetbSvAao=)T1Sy@qm<{(2oO*1w$tz8By=WBG*3*|WN4i)BU$$N& zJ$Cw__B(6)E_?mp;f|81qo>TR13FAbhAl^uw@_dOv#NBtsVa|v2NbF0`_!2*6 zGWNVYWl+!`n@C{&L|`+4B$>%i95B|h8^^&&?*$M5AiwWm*e|Q)H;xpV4*c!t*B5-i zw|oGIjehrmm*6PyA10$=d%X5ay5ET%4X+q#GmmT5us>#PGhnG|pEX#xsID~U`hnkl z@leM;5jj+eL(FZs4@Hd6^jYQQnT4Hn8rURGfU>+(P6;rdMvpO`A-kPG5FoH#)MC8| z^LmLWyhObvEx^LhnhvY+;=~;E`hgkKE&vULgWM`u`ufH@CCF^M~3*DdxIo`PnWwQ1| z!%Ncb-OA%N+FqI}yXF7#tA2lCl|{kQy%Z!J8p_@nc~97<7k9TFN_#Q(ree6$92)4! zd7C9Q#Y!jIRM~&hp+aO>14b>7PGN>ong?)5phf_W5h64RnCmEsphbWn=D%zayEBQR zo*juw#VD3s5~A0 z+2k7pTW#H6F2Abn_K?c%w0Nt|;JFTsX8ysF6J)*lEoD1G6?QZkj$0?v!F5Mv-^lHa0Xi!NA)fYy<}$sevlpJxxnZ( z45XmbAyzp7bp6Nji^^nzPUAPxln_VYb*Okkd1c7u|FvK;evYxL(a27Hy*WxTtvDdK zpnp!dOfEDoHlri{P;-0^b%Ay4xN*fB>n_n$+xe{O7ak2|JM6s+l3#=zaVb^2vyV;3 z!tk|TzJ(r;faJyr%%g`)+(u1KiCFT9NBH$g9)=?XkJ8P^tJpU#kx;iK1S4FCGIceuT>^zTSPj%v2>KgGZq-?xt7zvVG&!?sr8AxgU4o z{`kmT7niTpoMy|A3pB2()#_A`0E6&_A8iT&``Iqp>}kLZz)T{TY0tEQ0EC3F>T%B zB8O^wi@kQI-fg z_pbzpn{O-|ds#J$1V^M_&lKK|BJ1zx-hLlh!)h>neWQ;ar)K3XYlrEoY4XqY89cEH zzvU%4RyBBWURq~zrt7L&dRO+MlI^t1#*Offe^9=X)1vSlkhE-%@Zl~&w-pf3KJ30r z(VII}aHef)+ANHk+7Z42bor8YTbMkZg?{8EMk1;JpVm_X%1fbp7(IUIb;CC{qBFGi z(1a@S+=4PhOnD--Y)lj+Mo^Fm4W0KqrW-?l@;y=Ha`GoM)88QhU!5Je0&a^gE7UZr z+l^UTN*UC6yvTA}G@KbD`_vf6$Y*4KODy=cMO@vXjR;%ZIa(lrM<>;33(-R^^-2SV zUYZUCK8>Rf%KAIWjrszj;o;EC`o|aGjFFaUWmSs zOs5y*US#L~K{uu`G-^NLib}VKYMLtPE0Iju&&A=E|pAsGUg`55u=uW#_-#|Q!Uxm5Fd`mpA1b%)_DYT9)VgNTrI zRR(>cslM8^gY7xpHDgDY7CmQ2nrW_9P@L27DC_oJb^XtDHQ=dUG+%pDDJ0KF&7snB zclY3Uk6BURMIRAqvq}{f_TJXdv*+VlY4N_+_A0a03%aTrH)VQH7S(y@sBM=`2(*XHd+D6h)|A{XYmJ0Ig~|mQ z(6MAl0r&x0(i8bEDGzhmwM(ffM;~enc`etN#gTW9WX7y}-lP^l3#`gaPU1OACX#sjNBACC>EES(8X*r{!>}lR~s(el@?ah=+mSbaH zPoXNkrzdhEZ#b(UKF6m6zAK?)Q1X$5ZpBn-t7WKZa)DIlo5GtVbLRUWHtmSQOjHxG*?jppJpG#eMnvh3J#;a8HkAU!JJwp51PbG!kyRDs zhd>jAk~=s6HW#OnoeXx!S00VrT1d3JB3NkFd^PC!2yJnIY9wS~Hgof~W!co$AEM3X zj}&Iq>*VcOmQ@{rr`+6Us3Yd^qI-1r9O?)p8M2ZKbYJ**H!^j~)%lRiJw_jYCq{r-;48nxX#L+V z*n&PiG7EdqKrbl1)MuLAJ>naY*GN`4E}ULzA9#$aMvE|`);!SeHot2uvzscFF>Fb< zBnzzaxPM#m>PhqsK2UHl^#_mFTAzsu8O#X_@;&~@D3kx{q&&=La`!ZdxQFVKxt>|? zjzZhVLSHPMk9w*9R37sag!u4{z2a97@uKlYA!rPtB?S5mp9MvAz&$gdkDo0J-{i2* zK)RJ#=p2myJ^~7-;CyLg(fh9kEDCo^VS4!4Opc>dIsGNzE88Rj{FyA3h-^`6rcNb9 zVQ0s-(S?VVwr;0*JvWm>y^c43s%#Y52idmHU0|%+Thu3!p5oVaADb;WM3em~v3&m2 zsh|x)kENPI#H@6cg0zjUm)@IWA5{d4y`}JB7#6h^>@P>&YAnoz+N5F@JC<- z6jpx>Xsgfy2Qxa$8L|< zh?<~VoT>B$E%a^xJYLFH_ryf8I_x+h7F{>gO&ze`%yPlAXX9sNw;iau4jgL)DhTeG zKPUez@VSO{LXRzCd||^3xh_FT=njc5frBprfHeeYb0xr5Mz$&=6AfZQ4y=bm${r-` z0AI2=7`$W8&Vi0+L~%0_bC&W8T!7$N9FHPNIGW*#324~)ez95sYK5T=Ig+*`c2h6A z4P#Q}l6hIeUzLNm@J%#KFGuq(`$0hTgOdkXMV4UJ(`WXN$JfT%x_pe=DsZH*7bBLWqRt;eALGG zuk!P&kBryl&5r!+ySvUSbfoPty{e@~iT3El+}OV~>!LL`tuGH)-t3Cf&}_}4#z)rI z2=@)OdJY#Q(T2+Abpz}cOJ7>fJS^MsAk-z)UOnVzQC;3xITyT0F4h!cH zvFJm5q(=}$=jD|qzCjc|=Vm1`ga~H6pfU_|<%JIs#SS-V61JAwD%$&oGl@L$l4P=R27UPl)6=ecI1b3EgG##Yl{>0wjmm&c$a-Esh;VgGv`*VyzZthd%m- zFKA~s#xiCr#e#FI)>fRNN-v%Kh#$V@{01j^rF0CYCQ1Gu+TH`8iF9ippHLM+u^>|A zvKFKY2uKgB=qg=NK$?n3C(=7)t%!mJ2}&2FDT09Xrm_$vLZo*PF@)ZG^M5Aj?z(sH zch}$d{U@23cP7asnVIvxr#$C52ntq#E(InA=vWwmCJ~L zDz70rMR4#rfGiVA!#*^Uwa4bAvVCN`JWWen()=WXCzq_Q7l+y>Gnww~i)_UOce#$# zUu*Ksu2?+h?R)R>-~Wn#+xs=G)6eYa$va1JyyBg6MIJHaeZyW}Y}$NgJ6Wk@g%zHH zIh8Y`zH;R2UXzQr3q&k_!OH@j0lhWS03^X%1lYg{$AUb?3kG6Nsqc8EhNhYKHK60_ zjS~vC>YL4uWJL=7x(;b&$6&d184!Lg`-671sdu&+;wLRm)NnuDbVTO1o$$um-D*dF zxre3_ruVblw!D=XiO<+$SY#O#zdkW$MZ%M6Svj_WLvJALw)3akPp^F_7jay0oAuMG z^3m5cV12o3qD-z~y0zG@^+AQFBab5G)|s0@H3|w|)pMl2#n5z4PapG-%4fUBTf8V^ zu_u${-#-RmppId>2Z2~FT8c|;&G4@Be)f(KzA4x{i|AfbmSi*&tklvIVg{(e6O?O} zW8AZ4Z}z4cI4CP!8Y!7++D~?#(Ve+G*uUDuw`>)g?%kRBF5PD_O}be%IN!!9`%IgU znUcTJ?26-ir{+fB0^3ta9aU~qh>kJk)2=?1b|)ja>)?P@kzm3Hd_3y+i37F(A+X3n z@CE+uQlb8yuM^r4pnegWmz|CU9l&6dPM0ASyCoZYIPC+IoqT6};&ypk)0UShnMSGB z^dY&iJB=1f30WkYB9ocG>Y#~P*PcQ`^AXER?sPlLaN7@W@#sMjaXDN3ri8~SQ`VoW zPwmvcIHh$&pT9^f5JNr&YOFQ1xbyKIQhT2@ut?F_Y30{TEv=Sa)oEV77rb9TzB zx3r%ufG+=TS_%9t`*-{QZ66?!`n9dX8_FFf+kF*rL`4Uj!;<-_jGswiEULV-z9$cT za50+cvJKd$^abH48msefTJp|y({`-fUVJ|A-wyY8J5W}3RQC~=H<5azJxLlp^mbF; z^^-~$PgZJ-c@?nEznu4VDw7$S9_{T(r;-ws=DjPATz|~Y6o;zM$nP>P1iV8*fWuJB$N`rX=G6(i`D~df*rWP8E~P zJ-^V07#6l5Q*Lj@_?#*PfXpy-FoFrMnX+a4~tGUXV?wB%O=b6RMNL6G}5!29Eia<;i64 zH0LRHswI2k@BB;`EI|KD5DR!%X(KY!P5@jQL(`SVhesO%s81GMp%RJO zh%vXkw`bGM}j>&ut-_e!>!=!^5O7-~* z3YKRYG*9o*9BX_Mm>#-Ej)U2350rVBf7H2+yYqprJ7tj?&^udMU{q4I;4qb4TlYp; z(rDXpMCufb%E#ByaK(5)MaV#+r2yR(!z1H?EF;N$2R`D5uHx1ShU6cCTuUK{?b8N_ zwX?HMh)xg>=LK$B+UWsEgn^=D9q~ZF6?A|Gn+|lo42|fw}S6o78GE|F*ztVkO`{2dP37sL@2QOT{qn~DRmp*s6 z3NQPX9<~0yf6NDPf9Po>p3#0({d{O)Vro3HH@B;5vAFAM-%FSJfs)8x-1U<=faWT4 zYirh)sFW1ff4cl)a4m!f{q5gQ|0HVn^@E$DCxSOTBfbCJEhbVHvdlT_S%~G?@GEO+JoC+rPHy+JIB}McZc>?8c4M3@7O%Pf{YgDP@x+ORDPqdH(oj}K-AQ8iCE3N z&KmQ%p}q}x$uc{2`AwvxiFSqfArXSS;8W!-nZhgzRqs>chS174(RI3dQJJ`W!QzGU zL+9f+@GemPIZsp#~X*E`)vM^D=xQRiC=C+Th5#tr~oMn-lTZ2D_140>TOU#|{o zEwiJBGZq*mP{7_@#tRrDdpXZD17#mj9C_h>2uZ z(YcUU>j^Pa$pML7KkG9G4>Z>H4ynr3wM)hKl8clh*d3x@@z?0genE<6Gxn}_8LXIJ zuu8}fSvReJK~E@75JqI0MIl5R&mp0JPEcsW9rqW3^rcZaZMu*akbL?i$uwO(0B9$I zvJU^B<|JSTPYWpV2o?=RB5UzTMhq1gu)U&uvtz?0vKC8kJO*s5j5)pi%gKC-Y<6+R z^BU)_Shk7SDvJdiWC_b*LQiAh>4DA4p5+zK&Dj5=iLp2_;{* zj+^U&z98%Aor^Lg-n)AJogo5Da~7A@W|vP;%7z?>LFxW=T{}Z|>EhfE-cu`S`2_9=m~b=oE6$c3%$2{H{yXUKPapEt`FnMKM!wX{|FP0n8=N0jkF*^PKY3!%H8y;JJCq?uMn?Sk zWTkto!%X_Y`{xORJ3ftt2(pB7+62urYW|jrav$ zKqhktLPCL{YY0O;DjpwV)KirHYSTu;4lolg#~nNuDsSQRl)f0a+JZJ6PJ^02S!j77 z=nRDAE`E+n;N;ZGV=##MG~~o!5YcOqQ=!KUI9%uQw;X)qWRFPRTy?#nRx;aROcD1e zgutNWijhV7tBsz0HR;mpox^YRm+g&^Q8~pYp7sW3_d3QyaaMXy;k#S;6@^Xd>1PUX zKAt*zrF2e-HNYA6kvDT3Xf3KF2&w8Mr$X0xwBmCCDUs0Xo+fiXVKh7BlCN#I%w9S>eC?F`-a{6VX{V;zQqww4v1R#jag;lYNwI1L>uug#3dxDk|& zhRI)0&NWNKS1#|7|mQ~O-S1Mcuo6;I8O zjT^bc9%P#TEb;U-%cF ztzZhM>_34vpdW|k-O8Yv!MZT9ZR?xT*|F|#g#*S*XY!*Dk<3N3@m13R4s=M*_v32+Kfx)nx;?I5WH0G zD8K8}aC4n2@NZJ}!Ep_>mlN9tiE_McnSJGQtWq|*eyq}7^-^+jC6kmSS!CE!gaTDFK5o&_K^1#0>*YiJ`^g| z7&+uB#D;i`Et%r(aGECDSPU$ihff!m@rK_zJ|;_8<#|aOuIgrsmM>$4U+~O4hG&f@ z@Q)+?r`A^#(CEB>o}Wl>^Uhqq(z#naPCyzyrkoi5c59Ac&-T~)Ih zus8L!_aoCSrta)|XmKtMgj;JC!Ffa~jr#4yC34@@F!D1^5OK3M5SR+=~c2`1t}-=~OQi_+iR$fFLYbpx%B~4II-P?2MbS zTOHaEuc_Dl*_YIPmtV9FkQop2`#PJvXvMmQk$8)Rg@KfAOI!l2C|(_C3?U`054MTg z<otlwxOdOij*>%79*#0JmdV|x0onyH5pI`6U=NR|xEYkNon~c=Avu0#Y)m1PL zjMrGng^d?Dx`^@Q4DGP3*7yIFc+{NDra0|kLJ``5qKau8J_W^Xf;x<9$bVQCVA7)| za1c245CJ3-zdj$Sj@wWa{g%NvlwcIJfuJq7A6OAZqa3&C7ea;GcqC?s4-HF;dB>6#I?Pk?%X@c zD1D3*(R=JV56bN}AOI9S$dh1NUOGNY2!Wr0j|&6gJPz@00Bx*!^HQ-#><;KEHod@a z%s)SL6;iZ*O4^Lzc69A$v_0|!%MFyd+ff;ZbA-X7F~e=_AmT7qekbJHuux(H13?GO zRKcpYgWL3?QL~cOoyFt~a@V4kOLM(wOZ`;Kh1sc&I|&e8_2*wWr)t%#T2EC{jxOA* z?00%Q5I0;R?q-K9W&i!m$-&fKb=nf~K8Wr}fE|A{Khc^3=-#y^02APC2XsApp-W)) zm)p3XIn-by>u_|ja`;?pvze3Dvek!%UxKD+B&~m+X8w;Iduw+KK{Jt{A=*Z2GV+Bq z;l1yzDWpMaVz{qk`$Em+TuEQERo#5o)o`6NI@R-1C5koqizC_or6&|fX%qer&0+;; zXLRjQ|KsvorWk*Wj`@c{hX8S7jrPRxvc0$7lTTV`i2pQJ92HXbr2O)#{oZHkD*U63 zuhaWXS6sF2TBL+hkop)ST-^o%LXwwBp{Jji<}ZmU5A)s#$kDP#1rnYJB6Z-kLDr+$ zr8LHckR!(hdVqN$w|xf3H7_}<^Z5RP^(8RsGZ8PTie}MMmTg@YOGHc%CKh6@f zmYDst<9uh-tDSaX^Vb!MEMj}!O&Db+938am&hB+C?#qo)q=*}OEd*FSzn&h@mP{Iv zx3N3-T&{BTZ9+CkE?wMLqY`!0f%IMmfEJ2u1$&lm&mdiw^V{Bt)qaqhNaIi++(tEec&&fLi9 z{(+ILJE}5{t^~-f5#GF8HkVxW&s%-JnlpR-a8-u+IB)lYd42gJdGCZTd10}8NqVuq z%|HD=z9fD~Xr}8>vg^2`In=uy#&tE zRt@nkKNIN&@`V#15<)J~l}XnPH}<)tbaUzEyukIM4jCNllQ!29pFHZwo&(0nwTme_28c1){BiOzzVuY3{W;XX!Z&_D)L$Ckx)GkbM$%FF2jgQ()Z6Do zTb|^r%yRX{NQ*j7&Su2EwKH8|8}Z1WTd>NmAeQ@)^N#FZ^xNPuz(d@=i#um4jQJJ1 z`b176Fa;odN*|6c4(7a|*A1k%hI{!h{YWqLBaK&=cYHxA{g{G3)e~FuiW21B`M&(Q z@+s0o5YH8+ClSO8&c`XW%Mpa}eQ2&93{ygQAp}T<6IJ=ra*XDTN57DQRcg_Wp5E}HA+8dCwqI%t z6y+*$fP8Ihd1Ilo{fxpw=P+=Z%ydM~-j)tajy%k)Wr^DVxDnlfhU^w!P*fQ4vtkcZ|3$|C<7Ns=5FNaEgIKs%T}_h! z{j^d{THk>rmoodL&aBXkcb^x`H}(bGXu99Jzah)Av{NaoYb3X6X2y|n@$_OO_f3)M zt(?brYaj2j#>nb2v|_hfqRKuD%fM(!%cvH;jpucS>>_6=UH)|Ql{A0zq^Pnb!{xH) zMx`2*)Q>SdXYgq$0#plq3{liL6F`0m=@7qXGfZK98iy7eUk5ykXr!E8j;{@IB5|7L z=`%-s9C3nRM80Cjsm*4lX#f@zph}4gUP+RdcZHo&0KmEm(u&3 zG>#+iIZaN)woGeAL`xAws6|88BlEPFflEXG`?TjF^gpkiCHgXn#{&}E&BF&)UyHrI zpe4qW+O%q(IK3-6SBxliB*y&k%y`9NgP;NBsLe@wW)ep&yIg0LV}hZrm5su_8eQ8C z8^qo^;omr?liFSzODA%NKRLEqCE1bwqxz*9Z=LGBxgK*x;|@(}`8WMfeePD~FA=pc zK6ytxIvJNiaWpl%h&m!WA6Hv=<8o$-y%h|E31XXPr)SI@_!RF%ZqWDX)0TGS;1Ai$ z*DtK-NGW0D%X99)Guyy1m-jN~b_&5Gx$L!vIqOea=Wdrb z`?h>Cc4K{A_nG3%p;r_d{B9d}fjka(?y&7=O}Wvalsyrj+eLy@WD{1bmQ#u5)30~5VYO#+jFi%PqF{a=b4`CZ|Ke?XTQYn zLy6wex~0H8nr)2iskTQV#X#jjYaC$2EU~7o7={i6DqS{C+p{91|?s8NE zwlGgD2dV>MQOgE+!wg?)K_+}pPAi*_`j?6aaOXO=jM#S@aQV615Xo7%@QfT9yZiV&{hHI@ z8N!Gd#%-YWAL>B&x*Ll@<1G)6bI*8UMSnX@E3ESGD83(ZKB6}^GjSfWGRZ*9@CA9@ z-0K{$=~^33=0Z2oF2tA|ZZm2Zn;pCF_`GnNR0<8Jy(SF*ZTT&~{|oX)zDz5zKP&sz z@necw;4SeUpUuNba8^)evM4i`8i~OFRZO*0G@J4&iggiR&Aa&C_OyALbA2PxScgy3 z$5Jl3q}gGyrn%`;u7yQ{VjP=e%||xre0t4Mq+St!pzX)v_fnk#2#!$M}TmjbkWnh zx7JBt?TxJ*fgsm7th+ukx?IUGpzOYIfmGcy+~Nul^<}@YIp{sPtdJsv+HS)#E9UmV9~Y(9MF& zEVtd<9^&OMwT-=@%O6)9zbx{gqV4>;bQf>}<9~x@%0?GXZK$LuhM0DYY~#+kr3Xbh zKWuhzd8un`GNMk`@UR2VHDq@C0G@YxI?o$CMMgxn=nI=U9`VWQGu$gcwjBA4?1BPT zM{?O=FggA}7rYr5v5U1R1YhI;J3G>Oml4GHIC2{7C|M8}HQ~3&FAYFN27U><9Rs)7 zc_257=B7~RMq9Qr$mTc(Yg)m#HG7c(vdh_Z0j5tI@X-~5fqYg5821@;*>&~KA`PfJ z96TvIf9ieI#mDP0;CPyBrg&_+St6L~m>$C?OWY`7wqTk8RY2sA8<1!m>xLhYI2Lg9 zK=uIGO6!o_0F7e6f>#7nlVhPLDDo3JzWf{g*FVM(e3L{a^X-+E@2K`e!Ik7wpB}Dk zFPv)8(l$6_`UTldN{-nXT}GAXOq1ag2M5_-{RTdKL0A1_C zypzjvlQ#9ENk;xuPucY&-7LbCm0!kJ&P8tMk-H1A^BNn zgK^6*h(wnBBIrO z*bR!aE6O<`F0Idy9j(^%8?sQs8$_l^D6VOEG>9#`P)O`nAyQFMtIKQenyJg1>)NBw zEEX*bMc&0koySxR9De2aL^>+!bDg^doi8KHL$LT+ZBylX@me zc3$?$cKL;u-$#vdKU}R=XZ8xc!4bm&fTc%DQ+k9j{?yQ`)nR&rj}B_qp5mL2^8BFh zRxr|(Z~U9g`_pzY#zR(RMJ>|de}Em21`NZ&nUkDCw!y zd+UH~BX89{|^t@t@NYtK>8?qb`aBnn1xneLHQsQO6a!6?!^$B7-Q`sMv`=s&% z!{|uJLp(JkX6*DqVU|h-$EnSmjUE>MlCu6MA1F`iLmPj8X@DBXSSVR4sJAxWa;2&> z*#dS+jma7bgfy?4Sky5A^{*LFN&krX$@3LQv6CxtGYrQ``x#9vJYPfW1R^8&iV?Un zK#0EGwrFw<^3}meTQMLUSPTFO)ls(-jphsm8T$Ktg5dvYhdic(y(25nfuA!w{5R={ zsIHvIRY(3(&tt(0y}t8%ucn%v!zvbPx{r1DBj88D$l9GRVIp=>%Tue)j0eP@H;o|0$# zg8psC{BrZ_@p28(myStBz0KFhyY}_&spl_MQ5?x7zi1eMfKG_trl84y@VX8CYzs(w&b#*fc7z@zk?z%(D0$XoW%3Rs`p+r&fXvwpOkf zcRAET365-`&CwApnCP!<^0oT2%sk1#W4GrNfV0r`z}WRJ(h|`xT$kUNfbt} ztSBC*ByVHeyQH`z(b_rMnsHsv%weDVkZft5u_}kd-s`6e&v7DZgLU@~d|=Mfj@}AY zbyQxy>psZ`+~U%m{SEcNExtUT+doEN6HxIZN$gElR^7^>N9k5Q*&Gs8qPNZKpi8L) zE7^mGvI{(u2$F`EDH7OF zqzGZdHX$BRltwGSWmplHlAD-Ko}b5Wfi%5(oq3G>&H7vP0DZ z4C5_`0pJr1iBN9Rj@MMO0zrphjKPi$>~=`hSI2{5i!zYI1Y^s(f775L0s_v}AfOOk z7smp{juD}CaWwU1P5HA2<&SGnQ<5Z_UeD!Fn%V&c;VkyWT_MLgu>SrKw-loS* zytCM0GUV6gg+40%J&SHgQZOHznSL?so12Ql0!9Xaz?t$)MMd?fHB!H%NaLFLt{%mYh4Ik;OPlCpN<)6n^ce7^#E=?4gd_eM z=0{b`Pl_qceyW^zi*Y8~4=%-Sr|iiMPb5wa0O7=TeyOh5@aM4-+UZ$CydCGB?Tr1$ z0Y2oLLl5$4G)~rbHX0kGI~DJ4Ht(4(9V3S~^+)Qy zO$*qRIOp$Mny21&^Pb@<&(Tpxc7yCU_xKB^Rj<`9#nzFA+{|rn22qyx+~`;(m>Xv; z>1)Ck|JqjO$l@#ommPxz5q9WcAzzNXCQ?7}&Bf zSU{d27om35^Iw^jze+7gGNW^55r&zERw1s#G+h`!WnwzYLQk?Nd9BOu7cI_$r)2vG zZFI0lNXB#`is`SI`VmkJkbxqe_$x_(BvX(UqBrKj^N4?hx)rnn+j1}HW8j{s1Y@!% zwr_!(Jmnkwv*+>CFHA5%d7{gl%u*weQ05v)Pe|HW09mEZulq?*TZ8q5xASW~<{Ngw zU5b>;3z!nrSNYf*!p4HC0F?59-KDa}<(+pK*D#=A$6YDQ6t4 z>CQB~!jPZ4KNM!^Ek^}b-RYt7*3Fwu`Zi8+V9%c)5}@D8sfFjdSBGV~fIEkgwZ=q8 zfQ!sVcXJ$qZ23U%?ttd%U_kF?MDumPXkz;SRACqK9FZ{Y#$Sf~Sy~PO#CK4;Gq^WU zsOex~Zy+9)76|8#j>|$>au6dtfk5G#?V^xa^^FMvMfq%FfT0#k3*RG$VSL0eY|~{| z)5Gd9szXW#BNk%BC=nr-kbsjUpbew)@2Po3mECQOtjV|Bd&5{Zlv2Vkj(gZWu0vS4 zI+;aJ+*Qucl?yhGZw0$n1n^#A*&d+RdNUSyIU|5oL6_+`L`p^Rm)|zvZ$Km(2iEx>G6m%-shTCU!|R$*zV6;EEQek<2~!zH-xe+EJu15 z8d(ooCWrS`j`%F~(drv~n0)o>yQBY48!Y&gHI1Ah*OaP(FxOHR2Euz9+sq;@d;Chx zy2w$~=A9wI+GR$5b0kW^`mfy> zYZw@3(tYBuq>uXk5;sy5z6F5=J3VY-H%1mXAzZ7tdx}lTmv@UKF(FqZObw2=wWK z(V(Ain3bKC}F-^eQk{o6j;GG?fK=VwPrC zd^0;Q;=f%LFgqR2H|RndD=JNNO%B^Q-4RZAth&`DMtFi#X*(LulMPxArYNl`AP62~ zHnemmuj!@VwxMHUAiZJb6U>==P+8%LEf%db3t>8}AdHGMa|^x;zK_OOiAL81VHTi6 z1TF_50uX#l0f469W#EedM{Rr@3q);MemYHL%~oeNe&8k5xQ%aAua{)R$>7@D^f6L< zu5YH;%S@zX*Qq0DhWQcvW*Fa~T-Ddw#gMOqQjZ|&cQ>PjDGa7hO)CVtDTPMTLCBS1R2VVtMO5ypyiH40{>x$i<0f!D!w>?K+lM~s4{94E_o}=+x3>J z@KMHg@~}?U7aO(*&-kxcrB=Ro&o&M>^rMCosFKagvX`iop75CNlUGb#V(a5IGAu-c zWFw)91Dh1mt{9Idu}h&_;JW$+6}7kY_OO{!hl&>p3lm-^Xjm5{-_nT>qJU6|gar?; zlOOJSwb2&{+|e|pILKOpBqlVm5Z~j3CPI^8nF8Y0^eJVd9H#~chIp;{nl7)q8(6X8 z=~2S;kv@oIkuf3-^B(1z#&cW3y0;=~-CMV9bN>y3A1JpY6kY`jj8=_}BkD>6%b42+h+Xwv9ap{w?~i(OTtPK*6qET7lVqOSITtM|-smU<} z4^|3M)UnCDyVKX)4kU@6KX(1W7qNG2JV^Y}-hSOX4elI0EnlW7W6=|Q8;_p5e>(j> z@F2({Z-#O^o4M7_+KQQ_s3;OYg8F^?H&*sIPsMcbR_-ad);-u0j?n7XtK}Yr@hr9Dl_JTr;v&NEQIYtSXv{Mg^aP{P4gFdO}T< z0A&4rU2IZuvEylqytG_qp(lU*)a(6v%n9_{7(M=w2cXWJ1ZvnU%~!lGR>JWcjj{pT zB0WyNV7GqW3D7MOr?0k_;J2XnpsgCx3i=353tIC;pd1wJ7^7_*4|Gps8RF;#7}IL8 zIS9+!b!nI5v-1Jf#fle!Vo;1}AO+TR`as~uz|KwNd&SA?;Z9`VM&vYcV&{ax0l(q4 z>s_^De7g{Irj0;X*E*@M7fTJkmWG_9sa&YS1#l|B(gT+iyaH@m9*CX$+67VAdjQa)HVQSjiC5 z(`8mRl}`<5p+*TCkF2Q$&%|NFH5LY2`4 zDD75a3H3|pr&QS~68oNCSbhY7yG5-pi1-|Fr^7(bgx{zOA*w6nj7OQT_>x0ZxWm%) zc!{EdMw-U$)?o8+N(7nr6~C_a7VI(kc+B>z?Z^=PTaj z@@6T(ucPjrFFH;r@YZloCANzd_V%je&(Bi`T$-6hMr{RVIPp?+oS3^spk7RBv8q>T zpSPSb9=(K1m+n*8H85)V>yf)aPw)h89pFpFGUXlCb$Ecu1?NB0@B8mEJwg$d7(HE- z0hP;|@!a!YnZPMUo88eh?r&%2&_@HWCs%G&&y_EATbQgwtt5)<*dcVK_VRhW;-~X0 zDCa32K^{Qtgo|aP{3E>5LXxdOPsGJI)0vRXX(jZre>{<;ll*4=7++|Y-?f}QyS(ULvgl>MnEMB+P{gD==|qLU@&L6!vp~!Ej`6jj>jsrx zt`pH2IOW2^CxvfX@9dBN(?S1H6FU8`XaEEXqjt=cj}Nv#7$=p)bn~cq+ziR@X3J4n zv7AdJ;1o!o<`;Quyg8FiaK5;DrDxX_&D?5lI?b9KD2Nurk=)DNr_0(W59WAfz6>|J zdO;7p>1nt8T}%>|2XfDBQ0giOdVPDKi88-Gpoi7}J+Bh;nW_j3IzGelU5f!-OWf39 z>c~Emap=x{fkMo8jl}c?!F8F0jK!d6JBS42;75FA->N2udtezy!XFilziP!#9;Qn z?&dwr@#so%h3<}rikev7KJlV;tnZB>?3IXJyF@5`4k$8epv6G1k7f`tpg)tQK!KVA zF)Mf@I`)WJU4mdJB8SC5M7s@5-yy`&!7*sJYYKGxuNd#0r2~VRsrnb%ZI9mi=!|+a zXkuWDNPVDJ6ar^N3hOYW4O9z*#DIT}4nF-&>Vu%eV71&$Fl)4?r%-|`TYZR*cDQ5p zrJVr*7V$1UVd->%@TCIle%SpDpZd$RNlv*+8+W|7&Pt&tY`oM|Ny4t1?0DxmDG+K! z?X>(8%@MKEOBFJ$*HdH^miEXWn=&miRV>V|UIZ`M4(khlIqW~#{M{}N=JM|8r>(*bj=5FO#VQ_( zEy?lzf;`nOS+;8U)Y&^x`>1)SKl8fhpw>k8zQH9wM>~r{@d9j)YZk#*v-?05;9KHS zKqW$L@vjfmO!)30giKCFPk%v5W_hW8s$+h^F0(GP57IrMhc9J9Nvdh~atng6o)lo_ zeGg2W3K2m9J<%32Xenh^UBC2to4TLwzZ4OQON+mp^bzgKq5DQtQSi{03tk?r5)$tZ z+5k@ELbwG)1X7@PEdoDsTg^wN;ZblYThoD7Q}b~{5fA=Wk>cfe@KtRnQU;Ab?NTRl zEI8u`_gRr0HYJ{C1thOW)`uYAU7ofG3{302l7?rfhyyDWi|FdBqXggR0&a7RE~xTr zcQdrn8ymg5F$jiNKE_UmP}z~b;CW8Mct*!C%Qi88c>W7ATL@K^G&;j)?v)uzkC>ZI zs*bp=j)oUW3`sSo*~Ho|k|A@&CS%TZr8U3^%KvCC88rIFE-B-Rl1E94?{kK@ty*Vd z_pXwSM+cU&R%x zOMG9CB8MJjx?6g+++ef^JuJGz{MeN0oyMhnA2=!-P=%J>q6X}IM!5k$7=FkpnQ0Mf z03W)&VxKdZn&IdB1?iPhdNF7I9DQ}vGvIc^WO=85?wJ|==A2Kf(kDrq+!kBy8c&)v z-hjJ^4FF3FB_1{ zm;80S(>`lyTbb9o#zrjHSND)a!g4!Db~RPqEd2;q4ecoY4}=~;z6Z;T)i}30N3_~> zb&eN}m2U6M8)<$sJ-XD*PT4D$aAA3VjKEjeStdSLE@3~EGwvF07`~&7%_!sj^Kc$Z zf{}aHbQYPVUrK=X1AlMbdM{>q;8aDDH9#n{dsUIe_aSC5K;IQ0W>K&pqD%TmBMm&mG0&)Lk{>mP5;ByB9l* zi;a3IFQb)jzjzAf4tNDnZvo9YKr@E^fVtH4$JIFou|&pS(S*RY6cFP5iTXPQ$PxlF zSH?2s%UV|FTAEd@_8qTe?a@~od>ti>K$+GLdTmgOWa}khUt@SjR;pl}a^u z&~S=b`KX99d0&XMj}MkvsjxHIba|)7p`WeEN@G5=ItF!V#_{h$ma;BGpj-q(NdnLn zy@k*Wo#17(jv?AjTy|s$f_?)Pd_}zY@HfXbAal-C(mDq5;ZZu+&l2od`RVc~83xNX z81^2Cc{{z zkUA2U^#Jk);6|(|^lZZPEO7#GPC?$}Lii+U@)qD9Uvs!Q*-N4HbW*xEh+GW+SXYAc z`K(!6mxsOen<{*lRrBTs$ED>R-1uZNp(nDrYl_K&0f z!xk`<{b@jU*l2h1P~IovXjkX5Qq+kl;k5ia8IP-NhFoKBNEG>#+E!GO-#Qn!40aTj zkCmRjqnMg}p=zRcXt^82&QxN{7i8mY?buT!4Rf6{{yfd3O5a$V)t)p^OilBw+)o_= zoeot_Q4Q~JW-!t~4Fs)q&A_&~OS9CHus|Y5?fZgQfUTuOS&r>m;tZqgGnq&`9=}PO zOTPC$(3M=6vPjJqPMLcjWAyZLLi2A^i&%Ykl3b)RR^L?XXy{2@Yc{Q;n<}1#Z&b$B z4n6+3Wy01pGhAfQ=jF@HTB1$Ue79=%8;R>;wNE~Lh>#|WbghIoP8T{Fr`$jP5*@wQ zWHSymkLVDPOLWAp=Ycrz?=uYNinPGeS9wJZrFBgppSOy(!)vIkJi7_clNW-pzIOoO z#9HvlCG#?H+`fd0C>N30CXmkJR@!fBDBIHdpRjcJpRlYcfW(iZ$D(>4%}k@2VhBo2 zh1z7$fC;cq*<21q$C}#Pu#CPTKA-pr-pV|lxIR)^K|m6&Nk>)nY`4;Cf^6YbH~T~K z(S!%Nb2Vo7y)1lJ{Q0}Ocgs^}a&qqem)ixWaeBbALSf#Bxl%m#Tm(6 zz#|CqTfl033W_jDst~;hmdk6#t6E9HVt(vdUfE!Wt;^wNtM`q4GBQ4$$(_-AXO~kt z?u$s6CCen=IJWkl&Z*X@re?kRlg7&0bIA`zmX`hyQBZEMU;owrk)XoS{=2NIkb<*F zqD4mDMpoDSZ^g_z#>$ntjN6XX&0A84^`E=kW`_r<3YFa1=25OqwGEW1j}4W*g!Ym8 zoCzp(`L^FNOCJCAXaDf(yHQmGkkT&@p95aYnfGnA_su2uE%>fl1>Yj}I%q%gOOugo zh%)T#?d^#%G@ZybKN+^#7zTWNWunKVgK zqMl~DSJK+S!QFXR-zNIC9@uWsj(&Y)4kS0!RTpeJb*6jUxWRU_iT=QpcLA(B)EK=0 zHSQ!n!!Syg57;|bN(1t78Frpxwh4{tj~n@|_cy$vw^r1_Ys^n=i=&JMuQbLaT$dIz zez}0V&yR#E8|O;5`~K8={op_i7vO5sW4O2vyqu_`Nv>?3*auFq3ZYx!Kp<8``(e5q z9IzSv3Vp$}1&qv=4zMOWA)@sAHo6a;8SLEU7?0#xIH`G9xa!(AxdU=J6;ID+SNsa= z{7_k%QOzXtb^pW5A_qT?gb0F=<{rfFLES3)4-4NPW&k)Aa$gp1XEbRBj5(UnA~X=j zx-}7nP6I*HQc+n&=oJbJy?0F5T1rOe%`83{I&?sttmHaTV0rOi&1@;Be2rzbWp7B- za{d>D5}wh|x9fGJTd7Y>amB~-q^LQn@7S{{-<(g{UX{1L4n_avF5xTi^L;5z@Hbva zj#^xfI#I3be}y%(q0%zA%dBx?LEBE;SVBpnk2n%jmRMaR^CWzy(|$6a=0(F!%7`I1 z2RLHkp#~>b9fLN3ZwwwxW>9`r6R@NaK(8|xkPy}nnrP&{iS<2^N_d%Snf%5hc2 zao?VOaGGe-Iy#^T`r1ZU|4WDGpN@n!H<}Q|65scfr`|3RZ=TKUCi3*OQzqPuoB;FU zaKm_Umq=j?$U_1g0ANsTg48!^$$!mKYg4e`+`+MiH-Lvmb zUeZ_QkL@6KvQ@`Fetn~ZxR5D_9NfQ@zx22uj(3M&M?mCO7cA^}xD@Yb&2~(3WY_Ew z4@h8Fe#O%n{QLY@1%T6C4tSD+Yt=l?L$_f;i}tE_qF>#D_AtSqF@Wnx>n=lQK~S7z zjvET6tmrzApvX#mx(l-xUa;Uj|4lrex(2nZXupc7IY0CUfg}e>_7mp^0AT^X&jU1{ zjSxhQ;c9?1UPjjfYl2D0&E*EwwdmMbUX}M7txX&6knLRB77IF(yavdum#W_FeFr0F zNa!Ob*|MLPn^DcbIF_hTKP$E^>|hyY%3; z@;vGH)M~4W@MEgtDm%y-HS_sT9wrvTul}bKeSMXSmvgIEPk^kd{mhDll+n|yglSK! zkfgP2!|3rC5jR!No=E?lrrjCOp0qbl%IDPEPcGWN{eU{SLcE6h2gWK=uVxn)Xe}>! zaEdK5AH5@Sb8@~jncu(IX`zgxGQsSD)*TB9Wx_sfS;3REnwD;U;NgmB-oWxRg+<)W zSmpQB;^|0@p4*`~{p<JuZgO=AAp{(S1W~X)JfiobU5cZ{MPrb|!#B?>5wv zH59Kq_Y&mnB*sQdB{C;E#E3`53N@ngnjaASpSxKQxHE$Oajm02fBheAh@O0fj>10r zT;3W_kL8oi-Q6?!*yxp^4SzJ!7iD z*%^+bo>b|`UXKvFiw6`&0eL)71YnG)$=4^0|Lrx1J4zfZkfv$s4%xrgnk}&wfFh-#N{;b>arhX+p}YAMh6Br>yA8tD zsF}9r^a5QFLA>OozGS%m*dMd(=1H@J2&7alGtExVK z9xEA5RxBwUP)be-HQn{5!=h@)ZqS9x$ttY$I{u76yJA8BDOVK|Y^ zaZG2Ji|+QhF4((?d!(BvTI|kCTJe>fnDR6%Zfhe2E=I&|hu@i@-4zY=X|q~$v7)}Y z%BqC6S<7MaC*MkA2dDDYgLA7MobM;H2e?gB22!6td$uq|5-%EYXb;dIQ8{|x9s2iw zpBON}H~;(A_l^I3Eam&-p2QPdOD%$f9nhtN^RC+Pu zufx1oW4FVNA`f1fB(tY|d67I?9-YA-VB`ZWaL%Oz7zSY2fq@YkWOP78cf-g?(-NTp zqmvVmT>-us9j^Yp@f@^Fl=06FV9*{HAOv|Diz&e4NolVzHAlVhEL2JFJ%Eqe@4bf( z%?JQ!Nxo_RDNNN-Gj@hb8AzK=q08Y$)8OJz$kNlVXF&)r5QjEVlMhcDvNpxmEFb0L zx>T1frrk7uZq|5kykz-$vVyduT+Q+!e&cbAJ>D_K)5K(r@J7n#`O_WGbK6l5%?X$E zTaNn+sDvZ~r4f=yR}&Tv`QsDgD+cTDKZV^4O83`T>i4hwb?b-I>Hd0vzuETk-yKX2 zZF*QeTDSa=B2{+4o8a~H9b(zp{yvh<->+0npCu+gzq2t(TFEzU#-Vt!w4kw(RL)i= zIOo#M)a- zSh&@rn)j|Y;m>ZqvGO%(D_%ViG4dPbw|7Ab6Y`G8&~KD{`sA%KA2&v6Lz2jZB-%Oi z0ocB!Eskw8lo!wG7U6~L8L1XVYDQxMG1bkrh`eI;zc8-{B97yyM$A&5q->I7^Dg0z z%TRjLoWUn^*nriwtJw87^-Dypp@+isS6}yk)Mw^r_D7iaT`B&J@%-5lK=F|Q0Hud6 zEwRo$0E1G8Wvdhn5a@fT4wsl1u*p6< zHfJz)V5(H5rf-2ddb@3aynN(X|FjgLyE;bhNsM7@@6h<{?817o>T^QYpN{qeO*%+X zi~IV1I#gPIWcuM0u^%}&qH zpMU7r{N0<6(pQ*2={jQi3M6nDef=Z8kHCn;Cy9Slo4U5YTjy zwaO*}o8;oXJ+b__!!wugN~^&GJ?sXXj!a*ADwyvrmjJh2d2I==aA5jYW^|+G?9dCK zya28_lyF?~4FHi)a5ex704s*#3DEWPZ}U~aZ&(8Gh6Xd9_)c|!_;)7PPLfs`{>U=;HF#R@+;mgKAL zN<8DRT2My5-CY(ncQDU$84wC}u8WG|a=d->tq)42#*`RFOfR^(h;XN%jF zukZemRX!5@?d^YchkV=rU)TR9fy4juEt{&Q0-g*(U9;51#&n+z$<=lmdDH^eN%DkF z#Efgq7S9V_6&MaZ4q$TqznCCmfz|(7qtJAt#mR8eE$xxgc2bjRF|}O*5XK89Om?~u z<_RHbp(m=9mOTcpmH7OB&0PyvlII@BuIp5`vz@k;cv;U@tGtwX2|;MvskNi!+1fHf zW3C9x3wcSz06n$zsm!*@OJ1<%jEa<|fj5MmC|QzPVv-S(5*iwLK~NCzydPS+p3_d* zF6ZTWz6-qHd-=XU@Atm{|L_0%6WYugUM1fyy}iNFwWvOe&LaM#vb@U{YrK`h$Er3T zI<7S~Ct%it``z*Bw+@BV%(;|E(kI!bjJ}O!@JhmBvx$A3RCJx><#oKfbo~cUuu30T zdo=2Fm2~*rQyL6TL+00SrwFna^E2G9ZcX*a>6SB&J}QAPug#0^GRHsD2G z@sc-Zwv)}Gq_JyWvl;_lvVhU-e~5(CnKli`@sAUS`eKJ_-gF3~2$VuNyR6t3?Z2Hm zgy=oVWNo)>&9Yiyt8hEQ z$}Ja?uJbcJduhQg{f+!gN7t6?QXx0kOVg}qiQO4{McFYCWN~x<ijTQiE! zrUh-K1i9tvdpKGK>(>4{8$E)Qsu$rM0XrLJNzjjjvM9q!Y8;SaucmHYX7`T`@CN|t z`?kbK?0B^ z5KpZ9HEwD7GT;MrdTZV3c{z0^jCObEa3rJE;@CCJ%l|lziN9EQ*wn3#;V~VI*)e_e z=2ar8FP%;Yq`Sai?(w3~HQ-Qdtrjf2lSU6Fzx^ZrDbKcUYRbym(3njI|M#n6Yh!E4 z8XB&L(@MJkxa3aqynoeE9RvNSm)V6PF*kZ|uO@Rt)!s5ao>n25qYMzWL~*f%%rG}U z=U#S`7JfFx6LazkuFRk5&!kIl^M`{wEVjkbcZBgKmO2JM^L8U(;a5lXYjX3bNP;9% z9%0U0NA!0^@19Ul5wQHedYUk<+nNO4MYW0t+7gn~PHHFP=`>tzSlN;NSO~muGg>hJ zR`c=Q*g}SUY!)EXb9*k!4TH?2S z$Zdq!uW^pdcmw`WXbf_L*@3KIrLI;RNMX$yB@=e&rUC}g)PT4t0@xoZlw#ZwYHuDj z3NT0GC7OiIU--@MYkf@2Xjhc+; zEC52bz?Rv?4M7!GLmwUy3C+99roffD#$sKMb zhg~gB-503N&jxtx&cr%Pa=tDo*!MkSL>@iez#iU6HYpzN8i9RTCu#P`1|}@LKDWmp zxGAx)a+m-Esm6l~FF(0Z?)&vw!FrRz%tTs910Dc=3m}}E@ITN=7D?U+%-gsy@pgz{ z%XxMq#v5Qm>jAl=c`l~wk^(BpF=xD_Eu`jUVFSnNMqqbi1OVFeae(onclUfx<0s%m zgHUJ_&oIrK?R1Ch1?xHwLZ0aP(g8cOO=rfMB|#3B_x0xyFy*$cLggC;By&e7}XAHW&kE+qVmM zQHlAb%`zx{^ZPlmMgK!Urd$Ihjw4jY%Af4+w*$CLt_3#2ER_f1yy@&4@=Aga0jcK~ z4c_hX?j>WxKc1;V6{tCPPv zAg%@9#X?_Es`wr7{G|n)`|YLl3i+U3X`t`Sx_fviOPN7Vfk$rEAIH&d4VuxbH`=3i zy2l;=bV!tc2&`hK zR2)v+=8$L9ZBH#*`w7!GxIi4ung1DoiOWy+t8;&{Yu{l*UNcG?FhK=7Ge1jZc54@% zO)N6=zkG=O%sEh08ks(TNW(W;oD+yfg-nIpxp}jw!C6)q3a)=nvI(*3Jf>N-9M8$~ zB468pMf=*d)BXu8Lyu;@d-_E#`Q7r^7zBsuIV>}v=yPyu1flreVDuYGzq8P`#y_!Vq4W*)8xiTS*z0vIUNgyITgeO%oEW|ccO-c|ZL)5Tfh=*)z z9vrUHw?2A!qigfq4mM|Ay&n^Snz4=2rkhpj&M18xza;^mUgw-yd!Rei^f|$+$%LRZ zi1jV~13JE69&n2|kEQjr7i#ct&h@`Mj6d;jk$rf2b%>ti-WzfwBtKC|qg9W-|_sI5@ z4s56|1k1^x&MpMw=)BJKVfbo(L2B5V73Vy%Niq`PhFf5IDARxO*C{Qx^7O?sz zFYa-_oNb%~e0Ervx!tOL!&x}z&p2zIIJZKstq^GnjBt7yP`m@blj(98g#WRFFoSyl z3?0bUmNhf;PpN1gR&mh5QM0gYEzO2iyB@j$m0#YNSivGvkNeD)bGp=K*JxdcQi zu*NtF-Ld1@F2A)sJ#(o`mZn7MrX-C7{E*pFjjM=z7s<{4YVpUhy1NDv~ zcVolie2m)$|2TfUevq7x%n3YJb7ET!2*HgmSGkoK3KqTGec(>8@6 zMRz(VL6lT#XX2;9Z`cWRb1b5#CvL z1y5rH*N{H?S$Vym5`&FbGBIBGA!WDG-tahq;A@*EnI&=lQA3oA%$R`E>M~o(@DJHr z8!(Iv#ykCYaS_QuScQWNx0_0$yXN@>%wx(mL&340BMr-bASHqFW`{1MFawImOiGYl}3 zhk^lW`s+Z*{ss<#,8> firstUnsupported{}; std::array,8> firstSupportMasks{}; std::size_t firstBlockedCount=0,firstUnsupportedCount=0; + std::array firstDeepUnsupported{}; + std::array firstDeepSupportMask{}; + bool hasDeepUnsupported=false; bool passed=false; }; const double coreMetres=static_cast(World.CoreVoxelSizeMicrons)/1000000.0; @@ -547,6 +550,13 @@ namespace StandaloneStreamBenchmark if(supportedProbesstrates.end()?nullptr:&*it; }; + const auto controlSnapshot=CoreSnapshot.withoutResolvedLayoutPassages(); + VoxelForgeCore::World blockedWorld(controlSnapshot); + std::string blockedCompileError; + const bool blockedCompiled=controlSnapshot + &&blockedWorld.compile(ShapeRequest,Scheduler,blockedCompileError); + if(!blockedCompiled) + { + Streamer.Stop(); + std::fprintf(stderr,"[ResolvedPassageBlockedControl] compile_failed=%s\n", + blockedCompileError.c_str()); + return 10; + } + struct FPassageOpenAirAudit + { + std::uint64_t supportSamples=0,violations=0,legacyViolations=0; + std::uint64_t routeSupportSamples=0,routeSupportViolations=0; + std::array,8> firstViolations{}; + std::size_t firstViolationCount=0; + }; + constexpr double PassageSupportAuditSpacingMetres=0.25; + constexpr std::array PassageSupportAuditDepthsMetres{{0.125,0.375}}; + constexpr std::array,16> PassageSupportAuditDirections{{ + {{1.0000000000000000,0.0000000000000000}}, + {{0.9238795325112867,0.3826834323650898}}, + {{0.7071067811865476,0.7071067811865476}}, + {{0.3826834323650898,0.9238795325112867}}, + {{0.0000000000000000,1.0000000000000000}}, + {{-0.3826834323650898,0.9238795325112867}}, + {{-0.7071067811865476,0.7071067811865476}}, + {{-0.9238795325112867,0.3826834323650898}}, + {{-1.0000000000000000,0.0000000000000000}}, + {{-0.9238795325112867,-0.3826834323650898}}, + {{-0.7071067811865476,-0.7071067811865476}}, + {{-0.3826834323650898,-0.9238795325112867}}, + {{0.0000000000000000,-1.0000000000000000}}, + {{0.3826834323650898,-0.9238795325112867}}, + {{0.7071067811865476,-0.7071067811865476}}, + {{0.9238795325112867,-0.3826834323650898}}}}; + const auto auditPassageOpenAir=[&](const VoxelForgeCore::World& Field, + const VoxelForgeCore::World& Native, + const VoxelForgeCore::ResolvedLayoutPassageV1& passage) + { + FPassageOpenAirAudit audit; + const auto inspect=[&](double xMetres,double yMetres,double floorMetres, + double depthMetres,double supportThicknessMetres,bool routeSupport=false) + { + if(depthMetres<=0.0||depthMetres>supportThicknessMetres+1.0e-6)return; + ++audit.supportSamples; + audit.routeSupportSamples+=routeSupport; + const VoxelForgeCore::Vec3d sample{xMetres/coreMetres,yMetres/coreMetres, + (floorMetres-depthMetres)/coreMetres}; + const float nativeDensity=Native.densityAt(sample); + const float passageDensity=Field.densityAt(sample); + const float legacySupportDensity=std::min(nativeDensity, + static_cast(-depthMetres/coreMetres)); + if(nativeDensity>=0.0f&&legacySupportDensity<0.0f) + ++audit.legacyViolations; + if(nativeDensity>=0.0f&&passageDensity<0.0f) + { + audit.routeSupportViolations+=routeSupport; + if(audit.firstViolationCount(std::ceil( + supportRadiusMetres/PassageSupportAuditSpacingMetres)); + for(std::size_t radialStep=0;radialStep<=radialSteps;++radialStep) + { + const double radial=std::min(supportRadiusMetres, + radialStep*PassageSupportAuditSpacingMetres); + for(const auto& direction:PassageSupportAuditDirections) + inspect(xMetres+direction[0]*radial,yMetres+direction[1]*radial, + floorMetres,depthMetres,supportThicknessMetres,routeSupport); + } + }; + for(std::size_t segment=1;segment(1,static_cast( + std::ceil(length/PassageSupportAuditSpacingMetres))); + for(std::size_t sample=0;sample<=intervals;++sample) + { + if(segment>1&&sample==0)continue; + const double t=static_cast(sample)/intervals; + const double centerX=ax+(bx-ax)*t,centerY=ay+(by-ay)*t; + const double centerZ=az+(bz-az)*t; + const double radius=qToMetres(a.radiusSubvoxels) + +(qToMetres(b.radiusSubvoxels)-qToMetres(a.radiusSubvoxels))*t; + const double floorZ=centerZ-radius+0.20; + for(const double depth:PassageSupportAuditDepthsMetres) + inspectFloorDisc(centerX,centerY,floorZ,radius,depth,1.0); + } + } + const auto upperStratum=std::find_if(ResolvedLayout->strates.begin(), + ResolvedLayout->strates.end(),[&](const auto& value) + {return value.strateIndex==passage.upperStrateIndex;}); + if(upperStratum!=ResolvedLayout->strates.end()) + { + std::array route{}; + std::size_t routeCount=0; + for(const auto& anchor:upperStratum->anchors) + if(anchor.kind=="route_point"&&anchor.values.size()>=3) + { + if(routeCount(1, + static_cast(std::ceil(length + /PassageSupportAuditSpacingMetres))); + const double routeRadius=a.values.size()>=4 + ?std::max(0.75,qToMetres(a.values[3])):0.75; + for(std::size_t sample=0;sample<=intervals;++sample) + { + if(segment>1&&sample==0)continue; + const double t=static_cast(sample)/intervals; + const double centerX=ax+dx*t,centerY=ay+dy*t; + const double centerZ=az+dz*t; + for(std::size_t radialStep=0;radialStep<=static_cast( + std::ceil(routeRadius/PassageSupportAuditSpacingMetres));++radialStep) + { + const double radial=std::min(routeRadius, + radialStep*PassageSupportAuditSpacingMetres); + for(const auto& direction:PassageSupportAuditDirections) + { + const double x=centerX+direction[0]*radial; + const double y=centerY+direction[1]*radial; + if(std::hypot(x-mouthX,y-mouthY)>RouteSupportReachMetres)continue; + const double floorZ=centerZ-RouteFloorOffsetMetres; + for(double depth=RouteSupportDepthStepMetres; + depth<=RouteSupportThicknessMetres+1.0e-6; + depth+=RouteSupportDepthStepMetres) + inspect(x,y,floorZ,depth,RouteSupportThicknessMetres,true); + } + } + } + } + } + return audit; + }; + if(Assembly) + for(const auto& stratum:ResolvedLayout->strates) + { + if(stratum.generatorKind!="FloatingIslands")continue; + const auto anchor=std::find_if(stratum.anchors.begin(),stratum.anchors.end(), + [](const auto& value){return value.kind=="passage_anchor"&&value.values.size()>=7;}); + const auto islandPlan=std::find_if(Assembly->floatingIslands.begin(), + Assembly->floatingIslands.end(),[&](const auto& value) + {return value.strateIndex==stratum.strateIndex;}); + if(anchor==stratum.anchors.end()||islandPlan==Assembly->floatingIslands.end())continue; + const auto ordinal=islandPlan->manifest.recipe.anchorIslandOrdinal; + if(ordinal>=islandPlan->manifest.plan.islands.size())continue; + const auto& anchorIsland=islandPlan->manifest.plan.islands[ordinal]; + const double axisX=qToMetres(anchor->values[0]); + const double axisY=qToMetres(anchor->values[1]); + const double rootBottom=qToMetres(anchor->values[5]); + const auto& islandRecipe=islandPlan->manifest.recipe; + const std::int64_t crustRatioQ16=islandRecipe.thicknessRatioQ16 + +islandRecipe.crustDepthBonusQ16; + const std::int64_t crustDepthQ=(anchorIsland.radiusSubvoxels*crustRatioQ16 + +32768)/65536; + const double rootTop=qToMetres(anchorIsland.topZSubvoxels-crustDepthQ); + const double nominalRootRadius=qToMetres(anchor->values[2]); + double helixMinimumRadius=std::numeric_limits::infinity(); + double helixMaximumRadius=0.0; + for(const auto& passage:ResolvedLayout->passages) + if(passage.upperStrateIndex==stratum.strateIndex) + for(const auto& point:passage.controlPoints) + { + const double z=qToMetres(point.positionSubvoxels[2]); + if(zrootTop)continue; + const double radial=std::hypot( + qToMetres(point.positionSubvoxels[0]-anchor->values[0]), + qToMetres(point.positionSubvoxels[1]-anchor->values[1])); + helixMinimumRadius=std::min(helixMinimumRadius,radial); + helixMaximumRadius=std::max(helixMaximumRadius,radial); + } + if(!std::isfinite(helixMinimumRadius))continue; + double minimumMeasuredRootRadius=std::numeric_limits::infinity(); + std::uint64_t rootRaySamples=0; + constexpr std::array RootHeightFractions{{0.01,0.25,0.5,0.75,0.99}}; + for(const double fraction:RootHeightFractions) + { + const double z=rootTop+(rootBottom-rootTop)*fraction; + double minimumRadius=std::numeric_limits::infinity(); + double maximumRadius=0.0,meanRadius=0.0; + constexpr std::size_t DirectionCount=32; + constexpr double RayStepMetres=0.125; + const std::size_t raySteps=static_cast(std::ceil( + (nominalRootRadius+2.0)/RayStepMetres)); + for(std::size_t direction=0;direction=0.0f)break; + radius=probeRadius; + } + minimumRadius=std::min(minimumRadius,radius); + maximumRadius=std::max(maximumRadius,radius); + meanRadius+=radius; + ++rootRaySamples; + } + meanRadius/=DirectionCount; + minimumMeasuredRootRadius=std::min(minimumMeasuredRootRadius,minimumRadius); + std::printf("[PassageRootRadiusMeasure] strate=%d z_m=%.3f solid_radius_min_m=%.3f mean_m=%.3f max_m=%.3f nominal_root_m=%.3f rays=%zu\n", + stratum.strateIndex,z,minimumRadius,meanRadius,maximumRadius, + nominalRootRadius,DirectionCount); + } + const auto firstRootPassage=std::find_if(ResolvedLayout->passages.begin(), + ResolvedLayout->passages.end(),[&](const auto& passage) + {return passage.upperStrateIndex==stratum.strateIndex;}); + const double mouthBoreRadius=firstRootPassage==ResolvedLayout->passages.end()?0.0 + :qToMetres(firstRootPassage->mouthRadiusSubvoxels); + const double midBoreRadius=firstRootPassage==ResolvedLayout->passages.end()?0.0 + :qToMetres(firstRootPassage->midRadiusSubvoxels); + const double maximumBoreRadius=std::max(mouthBoreRadius,midBoreRadius); + std::printf("[PassageRootMeasure] strate=%d axis_m=(%.3f,%.3f) helix_centerline_radius_min_m=%.3f max_m=%.3f mouth_bore_radius_m=%.3f mid_bore_radius_m=%.3f nominal_root_m=%.3f measured_min_root_m=%.3f minimum_wall_m=%.3f samples=%llu\n", + stratum.strateIndex,axisX,axisY,helixMinimumRadius,helixMaximumRadius, + mouthBoreRadius,midBoreRadius,nominalRootRadius,minimumMeasuredRootRadius, + minimumMeasuredRootRadius-helixMaximumRadius-maximumBoreRadius, + static_cast(rootRaySamples)); + } const auto mouthInContent=[&](std::int32_t index,const std::array& mouth) { const auto* stratum=findStratum(index);if(!stratum)return false; @@ -667,6 +938,8 @@ namespace StandaloneStreamBenchmark return zUm>=stratum->content.bottomMicrometres&&zUmcontent.topMicrometres; }; std::uint64_t passageCount=0,passagePasses=0,blockedControls=0,naturalPasses=0; + std::uint64_t openAirViolations=0,openAirLegacyViolations=0,openAirSamples=0; + std::uint64_t openAirAudits=0; for(const auto& passage:ResolvedLayout->passages) { std::vector> path;path.reserve(passage.controlPoints.size()); @@ -680,6 +953,11 @@ namespace StandaloneStreamBenchmark } const FWalkAudit passageAudit=auditPlayerPath(Shape,path,0.125,0.125,0.25,3,0.45); const FPassageNaturalnessAudit naturalAudit=auditPassageNaturalness(Shape,passage); + const FPassageOpenAirAudit openAirAudit=auditPassageOpenAir(Shape,blockedWorld,passage); + openAirSamples+=openAirAudit.supportSamples; + openAirViolations+=openAirAudit.violations; + openAirLegacyViolations+=openAirAudit.legacyViolations; + ++openAirAudits; const auto radialSquared=[](const std::array& p) {return p[0]*p[0]+p[1]*p[1];}; const bool mouthsInRadius=radialSquared(passage.upperMouthSubvoxels) @@ -706,15 +984,32 @@ namespace StandaloneStreamBenchmark static_cast(naturalAudit.wallSamples), static_cast(naturalAudit.missingWallSamples), naturalAudit.passed?"PASS":"FAIL"); + std::printf("[PassageOpenAirAudit] id=%s support_samples=%llu violations=%llu l24_ungated_violations=%llu route_support_samples=%llu route_support_violations=%llu spacing_m=%.3f status=%s\n", + passage.stableId.c_str(),static_cast(openAirAudit.supportSamples), + static_cast(openAirAudit.violations), + static_cast(openAirAudit.legacyViolations), + static_cast(openAirAudit.routeSupportSamples), + static_cast(openAirAudit.routeSupportViolations), + PassageSupportAuditSpacingMetres, + openAirAudit.violations==0?"PASS":"FAIL"); + for(std::size_t i=0;i departure{{anchors.back()->values[0], - anchors.back()->values[1],anchors.back()->values[2]}}; + const auto rootedMouth=std::find_if(stratum.anchors.begin(), + stratum.anchors.end(),[](const auto& anchor) + {return anchor.kind=="passage_anchor"&&anchor.values.size()>=10;}); + const std::array departure= + rootedMouth!=stratum.anchors.end() + ?std::array{{rootedMouth->values[7], + rootedMouth->values[8],rootedMouth->values[9]}} + :std::array{{anchors.back()->values[0], + anchors.back()->values[1],anchors.back()->values[2]}}; binding&=equalPosition(passage.upperMouthSubvoxels, departure); } if(passage.lowerStrateIndex==stratum.strateIndex) { - const std::array arrival{{anchors.front()->values[0], - anchors.front()->values[1],anchors.front()->values[2]}}; + const auto passageArrival=std::find_if(stratum.anchors.begin(), + stratum.anchors.end(),[](const auto& anchor) + {return anchor.kind=="passage_arrival"&&anchor.values.size()>=3;}); + const std::array arrival=passageArrival!=stratum.anchors.end() + ?std::array{{passageArrival->values[0], + passageArrival->values[1],passageArrival->values[2]}} + :std::array{{anchors.front()->values[0], + anchors.front()->values[1],anchors.front()->values[2]}}; binding&=equalPosition(passage.lowerMouthSubvoxels, arrival); } @@ -831,43 +1139,45 @@ namespace StandaloneStreamBenchmark routeAudit.firstUnsupported[i][1],routeAudit.firstUnsupported[i][2], routeAudit.firstUnsupported[i][3]); } - const auto controlSnapshot=CoreSnapshot.withoutResolvedLayoutPassages(); - VoxelForgeCore::World blockedWorld(controlSnapshot); - std::string blockedCompileError; - const bool blockedCompiled=controlSnapshot - &&blockedWorld.compile(ShapeRequest,Scheduler,blockedCompileError); - if(blockedCompiled) - for(const auto& passage:ResolvedLayout->passages) + for(const auto& passage:ResolvedLayout->passages) + { + std::vector> path;path.reserve(passage.controlPoints.size()); + for(const auto& point:passage.controlPoints) { - std::vector> path;path.reserve(passage.controlPoints.size()); - for(const auto& point:passage.controlPoints) - { - const double playerZ=static_cast(point.positionSubvoxels[2] - -point.radiusSubvoxels)+1.13*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel - *1000000.0/World.CoreVoxelSizeMicrons; - path.push_back({qToMetres(point.positionSubvoxels[0])/coreMetres, - qToMetres(point.positionSubvoxels[1])/coreMetres,playerZ/256.0}); - } - const FWalkAudit blockedAudit=auditPlayerPath(blockedWorld,path, - 0.125,0.125,0.25,3,0.45); - blockedControls+=blockedAudit.blocked>0&&!blockedAudit.passed; - std::printf("[ResolvedPassageBlockedControl] id=%s blocked_capsule_samples=%llu detected=%s\n", - passage.stableId.c_str(),static_cast(blockedAudit.blocked), - blockedAudit.blocked>0&&!blockedAudit.passed?"true":"false"); - } - else - std::fprintf(stderr,"[ResolvedPassageBlockedControl] compile_failed=%s\n",blockedCompileError.c_str()); - if(blockedCompiled) - for(const auto& input:routeAuditInputs) - { - const FWalkAudit controlRoute=auditPlayerPath(blockedWorld,input.path, - input.supportStart,input.supportStep,input.supportMaximum, - input.minimumSupportProbes,input.supportProbeRadius); - std::printf("[ResolvedStrateRouteBlockedControl] strate=%d blocked=%llu unsupported=%llu status=%s\n", - input.strateIndex,static_cast(controlRoute.blocked), - static_cast(controlRoute.unsupported), - controlRoute.passed?"PASS":"FAIL"); + const double playerZ=static_cast(point.positionSubvoxels[2] + -point.radiusSubvoxels)+1.13*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel + *1000000.0/World.CoreVoxelSizeMicrons; + path.push_back({qToMetres(point.positionSubvoxels[0])/coreMetres, + qToMetres(point.positionSubvoxels[1])/coreMetres,playerZ/256.0}); } + const FWalkAudit blockedAudit=auditPlayerPath(blockedWorld,path, + 0.125,0.125,0.25,3,0.45); + blockedControls+=blockedAudit.blocked>0&&!blockedAudit.passed; + std::printf("[ResolvedPassageBlockedControl] id=%s blocked_capsule_samples=%llu detected=%s\n", + passage.stableId.c_str(),static_cast(blockedAudit.blocked), + blockedAudit.blocked>0&&!blockedAudit.passed?"true":"false"); + } + for(const auto& input:routeAuditInputs) + { + const FWalkAudit controlRoute=auditPlayerPath(blockedWorld,input.path, + input.supportStart,input.supportStep,input.supportMaximum, + input.minimumSupportProbes,input.supportProbeRadius); + std::printf("[ResolvedStrateRouteBlockedControl] strate=%d blocked=%llu unsupported=%llu status=%s\n", + input.strateIndex,static_cast(controlRoute.blocked), + static_cast(controlRoute.unsupported), + controlRoute.passed?"PASS":"FAIL"); + } + const bool l24OpenAirControlDetected=openAirLegacyViolations>0; + std::printf("[PassageOpenAirNegativeControl] source=L24_ungated_support unsupported_samples=%llu detected=%s\n", + static_cast(openAirLegacyViolations), + l24OpenAirControlDetected?"true":"false"); + std::printf("[PassageOpenAirAuditSummary] interfaces=%llu samples=%llu violations=%llu l24_negative_control=%s status=%s\n", + static_cast(openAirAudits), + static_cast(openAirSamples), + static_cast(openAirViolations), + l24OpenAirControlDetected?"DETECTED":"MISSED", + openAirAudits==passageCount&&openAirViolations==0&&l24OpenAirControlDetected + ?"PASS":"FAIL"); const bool l23SmoothWallDetected=!looksNatural(0.0,0.0); std::printf("[PassageNaturalnessNegativeControl] source=L23_smooth_unrelieved_wall relief_p2p_m=0.000 threshold_m=%.3f detected=%s\n", MinimumWallReliefMetres,l23SmoothWallDetected?"true":"false"); @@ -877,6 +1187,7 @@ namespace StandaloneStreamBenchmark MinimumWallReliefMetres,naturalPasses==passageCount&&l23SmoothWallDetected?"PASS":"FAIL"); const bool auditPassed=passageCount>0&&passagePasses==passageCount &&naturalPasses==passageCount&&l23SmoothWallDetected + &&openAirAudits==passageCount&&openAirViolations==0&&l24OpenAirControlDetected &&routePasses>0&&routePasses==routeWalkPasses&&routePasses==routeBindings &&routeBindingFailures==0 &&blockedCompiled&&blockedControls==passageCount; diff --git a/Standalone/Source/WorldAssemblyPrototype.h b/Standalone/Source/WorldAssemblyPrototype.h index 757f84a..4c1a010 100644 --- a/Standalone/Source/WorldAssemblyPrototype.h +++ b/Standalone/Source/WorldAssemblyPrototype.h @@ -540,7 +540,7 @@ namespace StandaloneWorldAssemblyPrototype FIntVector(0,0,islandSlot->TopChunkZ)); const FStratePassageConfig& passage=islandSlot->Definition->PassageConfig; recipe.seed=static_cast(owner.Seed); - recipe.geometryVersion=5; + recipe.geometryVersion=7; recipe.ownerVoxelSizeMicrons=owner.OwnerVoxelSizeMicrons; recipe.coreVoxelSizeMicrons=owner.CoreVoxelSizeMicrons; recipe.ownerToCoreScaleNumerator=owner.OwnerVoxelSizeMicrons/static_cast(divisor); @@ -573,17 +573,22 @@ namespace StandaloneWorldAssemblyPrototype recipe.anchorPlacementRadiusSubvoxels=ownerVoxelsToCoreQ(passage.DistanceMax); const std::int64_t spiralRadius=ownerVoxelsToCoreQ(passage.SpiralRadius); const std::int64_t mouthBore=std::max(ownerVoxelsToCoreQ(passage.MouthRadius), - ownerVoxelsToCoreQ(12.0)); + ownerVoxelsToCoreQ(36.0)); const std::int64_t bore=std::max(ownerVoxelsToCoreQ(passage.MidRadius), - ownerVoxelsToCoreQ(12.0)); - const std::int64_t wallReserve=ownerVoxelsToCoreQ(12.0); - // Put the mouth near the island rim, with enough island and root around the - // first coil to read as a cave entrance instead of a hole in open air. - recipe.anchorMouthOffsetSubvoxels=spiralRadius+mouthBore+ownerVoxelsToCoreQ(4.0); - const std::int64_t excursion=std::max(ownerVoxelsToCoreQ(passage.Wander),spiralRadius); - recipe.anchorRootRadiusSubvoxels=excursion+bore+wallReserve; + ownerVoxelsToCoreQ(24.0)); + const std::int64_t wallReserve=ownerVoxelsToCoreQ(20.0); + // Retain a 4.5-metre mouth for capsule clearance while keeping the long + // ramp at three metres to leave more rock around the first coil. + recipe.anchorMouthOffsetSubvoxels=ownerVoxelsToCoreQ(40.0); + const std::int64_t supportOverhang=ownerVoxelsToCoreQ(16.0); + const std::int64_t rootTaperReserve=ownerVoxelsToCoreQ(10.0); + const std::int64_t mouthEnvelope=recipe.anchorMouthOffsetSubvoxels+mouthBore; + const std::int64_t treadEnvelope=spiralRadius+bore+supportOverhang; + recipe.anchorRootRadiusSubvoxels=std::max(mouthEnvelope,treadEnvelope) + +wallReserve+rootTaperReserve; recipe.anchorIslandMinimumRadiusSubvoxels=std::max(recipe.minimumRadiusSubvoxels, - recipe.anchorMouthOffsetSubvoxels+mouthBore+ownerVoxelsToCoreQ(4.0)); + std::max(recipe.anchorMouthOffsetSubvoxels+mouthBore+ownerVoxelsToCoreQ(4.0), + recipe.anchorRootRadiusSubvoxels+wallReserve)); recipe.anchorRootBottomZSubvoxels=recipe.layoutMinimumZSubvoxels +recipe.boundarySealSubvoxels; @@ -713,6 +718,39 @@ namespace StandaloneWorldAssemblyPrototype [&](const auto& p){return p.strateIndex==slot.StrateIndex;}); if(it!=assembly.floatingIslands.end()) { + std::size_t passageMouthRouteIndex=it->manifest.plan.route.empty()?0 + :it->manifest.plan.route.size()-1; + std::size_t resolvedRoutePointCount=it->manifest.plan.route.size(); + if(it->manifest.recipe.geometryVersion>=5 + &&!it->manifest.plan.route.empty() + &&it->manifest.recipe.anchorIslandOrdinalmanifest.plan.islands.size()) + { + const auto& rootedIsland=it->manifest.plan.islands[ + it->manifest.recipe.anchorIslandOrdinal]; + const double qPerMetre=static_cast( + VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel)*1000000.0 + /owner.CoreVoxelSizeMicrons; + const double thresholdQ=static_cast( + it->manifest.recipe.anchorMouthOffsetSubvoxels)+qPerMetre; + for(std::size_t reverse=it->manifest.plan.route.size();reverse>1;--reverse) + { + const std::size_t index=reverse-1; + const auto& point=it->manifest.plan.route[index].positionSubvoxels; + const double dx=static_cast(point[0]-rootedIsland.centerSubvoxels[0]); + const double dy=static_cast(point[1]-rootedIsland.centerSubvoxels[1]); + if(std::hypot(dx,dy)>thresholdQ) + { + passageMouthRouteIndex=std::min(index+1, + it->manifest.plan.route.size()-1); + break; + } + } + // Stop the island surface route immediately before it enters + // the outer coil. The helical passage owns the walkable path + // from its mouth inward. + resolvedRoutePointCount=passageMouthRouteIndex>1 + ?passageMouthRouteIndex-1:passageMouthRouteIndex; + } const auto recipeBottom=fixedToMicrons(it->manifest.recipe.layoutMinimumZSubvoxels); const auto recipeTop=fixedToMicrons(it->manifest.recipe.layoutMaximumZSubvoxels); if(recipeBottom!=bottom||recipeTop!=top) @@ -737,10 +775,17 @@ namespace StandaloneWorldAssemblyPrototype it->manifest.recipe.anchorPlacementRadiusSubvoxels, it->manifest.recipe.anchorRootBottomZSubvoxels, a.radiusSubvoxels}; + if(!it->manifest.plan.route.empty()) + { + const auto& routeMouth=it->manifest.plan.route[ + passageMouthRouteIndex].positionSubvoxels; + passageAnchor.values.insert(passageAnchor.values.end(), + {routeMouth[0],routeMouth[1],routeMouth[2]}); + } s.anchors.push_back(std::move(passageAnchor)); } } - for(std::size_t n=0;nmanifest.plan.route.size();++n) + for(std::size_t n=0;nmanifest.plan.route[n];ResolvedLayoutAnchorV2 anchor; anchor.kind="route_point";anchor.stableId="route/"+std::to_string(n); @@ -788,6 +833,32 @@ namespace StandaloneWorldAssemblyPrototype {const auto& p=plan->route[n];ResolvedLayoutAnchorV2 a;a.kind="route_point";a.stableId="route/"+std::to_string(n); a.units="1/256 Core voxel";a.values={p.positionSubvoxels[0],p.positionSubvoxels[1],p.positionSubvoxels[2],p.radiusSubvoxels}; s.anchors.push_back(std::move(a));} + const auto upperAnchorStratum=std::find_if(out.strates.begin(),out.strates.end(), + [](const auto& candidate) + {return candidate.generatorKind=="FloatingIslands" + &&std::any_of(candidate.anchors.begin(),candidate.anchors.end(), + [](const auto& anchor){return anchor.kind=="passage_anchor" + &&anchor.values.size()>=7;});}); + if(upperAnchorStratum!=out.strates.end()) + { + const auto rootAnchor=std::find_if(upperAnchorStratum->anchors.begin(), + upperAnchorStratum->anchors.end(),[](const auto& anchor) + {return anchor.kind=="passage_anchor"&&anchor.values.size()>=7;}); + const std::int64_t arrivalZMicrometres=top-seal-1250000; + if(rootAnchor!=upperAnchorStratum->anchors.end() + &&arrivalZMicrometres>=bottom+seal&&arrivalZMicrometresstrateIndex); + arrival.units="1/256 Core voxel"; + arrival.values={rootAnchor->values[0],rootAnchor->values[1], + static_cast(std::llround( + static_cast(arrivalZMicrometres) + *WorldAssemblySubvoxelsPerVoxel/owner.CoreVoxelSizeMicrons))}; + s.anchors.push_back(std::move(arrival)); + } + } } out.strates.push_back(std::move(s)); } @@ -803,9 +874,9 @@ namespace StandaloneWorldAssemblyPrototype config.connections=authored.Connections; config.style=static_cast(authored.Style); config.mouthRadiusSubvoxels=std::max(ownerVoxelsToCoreQ(authored.MouthRadius), - ownerVoxelsToCoreQ(12.0)); + ownerVoxelsToCoreQ(36.0)); config.midRadiusSubvoxels=std::max(ownerVoxelsToCoreQ(authored.MidRadius), - ownerVoxelsToCoreQ(12.0)); + ownerVoxelsToCoreQ(24.0)); config.reachMinimumSubvoxels=ownerVoxelsToCoreQ(authored.ReachMin); config.reachMaximumSubvoxels=ownerVoxelsToCoreQ(authored.ReachMax); config.distanceMinimumSubvoxels=ownerVoxelsToCoreQ(authored.DistanceMin);