From 2c88e60ed3e67b174a171b2531ebf9ae5b3f169a Mon Sep 17 00:00:00 2001 From: StanR Date: Mon, 24 Mar 2025 02:08:41 +0500 Subject: [PATCH 01/78] Add difficulty calculation benchmarks (#32542) --- .../BenchmarkDifficultyCalculation.cs | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 osu.Game.Benchmarks/BenchmarkDifficultyCalculation.cs diff --git a/osu.Game.Benchmarks/BenchmarkDifficultyCalculation.cs b/osu.Game.Benchmarks/BenchmarkDifficultyCalculation.cs new file mode 100644 index 0000000000..eaa4f5cc28 --- /dev/null +++ b/osu.Game.Benchmarks/BenchmarkDifficultyCalculation.cs @@ -0,0 +1,73 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.IO; +using BenchmarkDotNet.Attributes; +using osu.Framework.IO.Stores; +using osu.Game.Beatmaps; +using osu.Game.IO; +using osu.Game.IO.Archives; +using osu.Game.Rulesets.Catch; +using osu.Game.Rulesets.Mania; +using osu.Game.Rulesets.Osu; +using osu.Game.Rulesets.Taiko; +using osu.Game.Tests.Resources; + +namespace osu.Game.Benchmarks +{ + public class BenchmarkDifficultyCalculation : BenchmarkTest + { + private WorkingBeatmap osuBeatmap = null!; + private WorkingBeatmap taikoBeatmap = null!; + private WorkingBeatmap catchBeatmap = null!; + private WorkingBeatmap maniaBeatmap = null!; + + public override void SetUp() + { + using var resources = new DllResourceStore(typeof(TestResources).Assembly); + + using var archive = resources.GetStream("Resources/Archives/241526 Soleily - Renatus.osz"); + using var archiveReader = new ZipArchiveReader(archive); + + osuBeatmap = readBeatmap(archiveReader, "Soleily - Renatus (Gamu) [Insane].osu"); + taikoBeatmap = readBeatmap(archiveReader, "Soleily - Renatus (MMzz) [Oni].osu"); + catchBeatmap = readBeatmap(archiveReader, "Soleily - Renatus (Deif) [Salad].osu"); + maniaBeatmap = readBeatmap(archiveReader, "Soleily - Renatus (ExPew) [Another].osu"); + } + + private WorkingBeatmap readBeatmap(ZipArchiveReader archiveReader, string beatmapName) + { + using var beatmapStream = new MemoryStream(); + archiveReader.GetStream(beatmapName).CopyTo(beatmapStream); + + beatmapStream.Seek(0, SeekOrigin.Begin); + using var reader = new LineBufferedReader(beatmapStream); + + var decoder = Beatmaps.Formats.Decoder.GetDecoder(reader); + return new FlatWorkingBeatmap(decoder.Decode(reader)); + } + + [Benchmark] + public void CalculateDifficultyOsu() => new OsuRuleset().CreateDifficultyCalculator(osuBeatmap).Calculate(); + + [Benchmark] + public void CalculateDifficultyTaiko() => new TaikoRuleset().CreateDifficultyCalculator(taikoBeatmap).Calculate(); + + [Benchmark] + public void CalculateDifficultyCatch() => new CatchRuleset().CreateDifficultyCalculator(catchBeatmap).Calculate(); + + [Benchmark] + public void CalculateDifficultyMania() => new ManiaRuleset().CreateDifficultyCalculator(maniaBeatmap).Calculate(); + + [Benchmark] + public void CalculateDifficultyOsuHundredTimes() + { + var diffcalc = new OsuRuleset().CreateDifficultyCalculator(osuBeatmap); + + for (int i = 0; i < 100; i++) + { + diffcalc.Calculate(); + } + } + } +} From 8b11be5ac03d172a5b0cc3a7b58fbe12aded39af Mon Sep 17 00:00:00 2001 From: Jay Lawton Date: Mon, 24 Mar 2025 20:07:23 +1000 Subject: [PATCH 02/78] osu!taiko skills refactor (#32426) Co-authored-by: James Wilson --- .../Difficulty/TaikoDifficultyCalculator.cs | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index e0bc0e177c..83b02f0b30 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -108,35 +108,43 @@ namespace osu.Game.Rulesets.Taiko.Difficulty var stamina = skills.OfType().Single(s => !s.SingleColourStamina); var singleColourStamina = skills.OfType().Single(s => s.SingleColourStamina); - double rhythmRating = rhythm.DifficultyValue() * rhythm_skill_multiplier; - double readingRating = reading.DifficultyValue() * reading_skill_multiplier; - double colourRating = colour.DifficultyValue() * colour_skill_multiplier; - double staminaRating = stamina.DifficultyValue() * stamina_skill_multiplier; - double monoStaminaRating = singleColourStamina.DifficultyValue() * stamina_skill_multiplier; - double monoStaminaFactor = staminaRating == 0 ? 1 : Math.Pow(monoStaminaRating / staminaRating, 5); + double rhythmSkill = rhythm.DifficultyValue() * rhythm_skill_multiplier; + double readingSkill = reading.DifficultyValue() * reading_skill_multiplier; + double colourSkill = colour.DifficultyValue() * colour_skill_multiplier; + double staminaSkill = stamina.DifficultyValue() * stamina_skill_multiplier; + double monoStaminaSkill = singleColourStamina.DifficultyValue() * stamina_skill_multiplier; + double monoStaminaFactor = staminaSkill == 0 ? 1 : Math.Pow(monoStaminaSkill / staminaSkill, 5); double colourDifficultStrains = colour.CountTopWeightedStrains(); double rhythmDifficultStrains = rhythm.CountTopWeightedStrains(); double staminaDifficultStrains = stamina.CountTopWeightedStrains(); // As we don't have pattern integration in osu!taiko, we apply the other two skills relative to rhythm. - patternMultiplier = Math.Pow(staminaRating * colourRating, 0.10); + patternMultiplier = Math.Pow(staminaSkill * colourSkill, 0.10); strainLengthBonus = 1 + Math.Min(Math.Max((staminaDifficultStrains - 1000) / 3700, 0), 0.15) - + Math.Min(Math.Max((staminaRating - 7.0) / 1.0, 0), 0.05); + + Math.Min(Math.Max((staminaSkill - 7.0) / 1.0, 0), 0.05); double combinedRating = combinedDifficultyValue(rhythm, reading, colour, stamina, isRelax, isConvert); double starRating = rescale(combinedRating * 1.4); + // Calculate proportional contribution of each skill to the combinedRating. + double skillRating = starRating / (rhythmSkill + readingSkill + colourSkill + staminaSkill); + + double rhythmDifficulty = rhythmSkill * skillRating; + double readingDifficulty = readingSkill * skillRating; + double colourDifficulty = colourSkill * skillRating; + double staminaDifficulty = staminaSkill * skillRating; + TaikoDifficultyAttributes attributes = new TaikoDifficultyAttributes { StarRating = starRating, Mods = mods, - RhythmDifficulty = rhythmRating, - ReadingDifficulty = readingRating, - ColourDifficulty = colourRating, - StaminaDifficulty = staminaRating, + RhythmDifficulty = rhythmDifficulty, + ReadingDifficulty = readingDifficulty, + ColourDifficulty = colourDifficulty, + StaminaDifficulty = staminaDifficulty, MonoStaminaFactor = monoStaminaFactor, RhythmTopStrains = rhythmDifficultStrains, ColourTopStrains = colourDifficultStrains, From 0c3ee1938ed71d506d6c67ed3c719a58ffda9291 Mon Sep 17 00:00:00 2001 From: wulpine Date: Mon, 24 Mar 2025 20:04:40 +0300 Subject: [PATCH 03/78] Fix osu!catch SR buzz slider detection (#32412) * Use `normalized_hitobject_radius` during osu!catch buzz slider detection Currently the algorithm considers some buzz sliders as standstills when in reality they require movement. This happens because `HalfCatcherWidth` isn't normalized while `exactDistanceMoved` is, leading to an inaccurate comparison. `normalized_hitobject_radius` is the normalized value of `HalfCatcherWidth` and replacing one with the other fixes the problem. * Rename `normalized_hitobject_radius` to `normalized_half_catcher_width` The current name is confusing because hit objects have no radius in the context of osu!catch difficulty calculation. The new name conveys the actual purpose of the value. * Only set `normalized_half_catcher_width` in `CatchDifficultyHitObject` Prevents potential bugs if the value were to be changed in one of the classes but not in both. * Use `CatchDifficultyHitObject.NORMALIZED_HALF_CATCHER_WIDTH` directly Requested during code review. --------- Co-authored-by: James Wilson --- .../Preprocessing/CatchDifficultyHitObject.cs | 4 ++-- .../Difficulty/Skills/Movement.cs | 15 ++++++++------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/Preprocessing/CatchDifficultyHitObject.cs b/osu.Game.Rulesets.Catch/Difficulty/Preprocessing/CatchDifficultyHitObject.cs index 3bcfce3a56..9a7bbb4e9e 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/Preprocessing/CatchDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/Preprocessing/CatchDifficultyHitObject.cs @@ -11,7 +11,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty.Preprocessing { public class CatchDifficultyHitObject : DifficultyHitObject { - private const float normalized_hitobject_radius = 41.0f; + public const float NORMALIZED_HALF_CATCHER_WIDTH = 41.0f; public new PalpableCatchHitObject BaseObject => (PalpableCatchHitObject)base.BaseObject; @@ -29,7 +29,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty.Preprocessing : base(hitObject, lastObject, clockRate, objects, index) { // We will scale everything by this factor, so we can assume a uniform CircleSize among beatmaps. - float scalingFactor = normalized_hitobject_radius / halfCatcherWidth; + float scalingFactor = NORMALIZED_HALF_CATCHER_WIDTH / halfCatcherWidth; NormalizedPosition = BaseObject.EffectiveX * scalingFactor; LastNormalizedPosition = LastObject.EffectiveX * scalingFactor; diff --git a/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs b/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs index 559e9dafa0..b69bfb9215 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs @@ -12,7 +12,6 @@ namespace osu.Game.Rulesets.Catch.Difficulty.Skills public class Movement : StrainDecaySkill { private const float absolute_player_positioning_error = 16f; - private const float normalized_hitobject_radius = 41.0f; private const double direction_change_bonus = 21.0; protected override double SkillMultiplier => 1; @@ -55,8 +54,8 @@ namespace osu.Game.Rulesets.Catch.Difficulty.Skills float playerPosition = Math.Clamp( lastPlayerPosition.Value, - catchCurrent.NormalizedPosition - (normalized_hitobject_radius - absolute_player_positioning_error), - catchCurrent.NormalizedPosition + (normalized_hitobject_radius - absolute_player_positioning_error) + catchCurrent.NormalizedPosition - (CatchDifficultyHitObject.NORMALIZED_HALF_CATCHER_WIDTH - absolute_player_positioning_error), + catchCurrent.NormalizedPosition + (CatchDifficultyHitObject.NORMALIZED_HALF_CATCHER_WIDTH - absolute_player_positioning_error) ); float distanceMoved = playerPosition - lastPlayerPosition.Value; @@ -83,7 +82,8 @@ namespace osu.Game.Rulesets.Catch.Difficulty.Skills } // Base bonus for every movement, giving some weight to streams. - distanceAddition += 12.5 * Math.Min(Math.Abs(distanceMoved), normalized_hitobject_radius * 2) / (normalized_hitobject_radius * 6) / sqrtStrain; + distanceAddition += 12.5 * Math.Min(Math.Abs(distanceMoved), CatchDifficultyHitObject.NORMALIZED_HALF_CATCHER_WIDTH * 2) / (CatchDifficultyHitObject.NORMALIZED_HALF_CATCHER_WIDTH * 6) + / sqrtStrain; } // Bonus for edge dashes. @@ -102,10 +102,11 @@ namespace osu.Game.Rulesets.Catch.Difficulty.Skills } // There is an edge case where horizontal back and forth sliders create "buzz" patterns which are repeated "movements" with a distance lower than - // the platter's width but high enough to be considered a movement due to the absolute_player_positioning_error and normalized_hitobject_radius offsets + // the platter's width but high enough to be considered a movement due to the absolute_player_positioning_error and NORMALIZED_HALF_CATCHER_WIDTH offsets // We are detecting this exact scenario. The first back and forth is counted but all subsequent ones are nullified. - // To achieve that, we need to store the exact distances (distance ignoring absolute_player_positioning_error and normalized_hitobject_radius) - if (Math.Abs(exactDistanceMoved) <= HalfCatcherWidth * 2 && exactDistanceMoved == -lastExactDistanceMoved && catchCurrent.StrainTime == lastStrainTime) + // To achieve that, we need to store the exact distances (distance ignoring absolute_player_positioning_error and NORMALIZED_HALF_CATCHER_WIDTH) + if (Math.Abs(exactDistanceMoved) <= CatchDifficultyHitObject.NORMALIZED_HALF_CATCHER_WIDTH * 2 && exactDistanceMoved == -lastExactDistanceMoved + && catchCurrent.StrainTime == lastStrainTime) { if (isInBuzzSection) distanceAddition = 0; From 69c90f9926f7d4b4e07ab53d69a2e3d15af5a165 Mon Sep 17 00:00:00 2001 From: James Wilson Date: Sun, 6 Apr 2025 09:36:18 +0100 Subject: [PATCH 04/78] Use `Precision.AlmostEquals` to compare deviation lower bound (#32694) --- osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index a667d12a44..98ab39eb24 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using osu.Framework.Audio.Track; using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Difficulty.Utils; @@ -409,7 +410,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty double limitValue = okHitWindow / Math.Sqrt(3); // If precision is not enough to compute true deviation - use limit value - if (pLowerBound == 0 || randomValue >= 1 || deviation > limitValue) + if (Precision.AlmostEquals(pLowerBound, 0.0) || randomValue >= 1 || deviation > limitValue) deviation = limitValue; // Then compute the variance for mehs. From 30f9716db95ccaf47fa2366cbe11d7f17524c895 Mon Sep 17 00:00:00 2001 From: StanR Date: Wed, 9 Apr 2025 17:48:18 +0500 Subject: [PATCH 05/78] Reduce RX Ok multiplier (#32434) --- osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 98ab39eb24..7e2d68b9d8 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -136,10 +136,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (score.Mods.Any(h => h is OsuModRelax)) { - // https://www.desmos.com/calculator/bc9eybdthb + // https://www.desmos.com/calculator/vspzsop6td // we use OD13.3 as maximum since it's the value at which great hitwidow becomes 0 // this is well beyond currently maximum achievable OD which is 12.17 (DTx2 + DA with OD11) - double okMultiplier = Math.Max(0.0, overallDifficulty > 0.0 ? 1 - Math.Pow(overallDifficulty / 13.33, 1.8) : 1.0); + double okMultiplier = 0.75 * Math.Max(0.0, overallDifficulty > 0.0 ? 1 - overallDifficulty / 13.33 : 1.0); double mehMultiplier = Math.Max(0.0, overallDifficulty > 0.0 ? 1 - Math.Pow(overallDifficulty / 13.33, 5) : 1.0); // As we're adding Oks and Mehs to an approximated number of combo breaks the result can be higher than total hits in specific scenarios (which breaks some calculations) so we need to clamp it. From cf7fdc06277d0081a87bb44aba5115c9230098d7 Mon Sep 17 00:00:00 2001 From: StanR Date: Wed, 9 Apr 2025 18:37:26 +0500 Subject: [PATCH 06/78] Move difficulty calculation fields from `Slider` to `OsuDifficultyHitObject` (#32410) * Move difficulty calculation fields from `Slider` to `OsuDifficultyHitObject` * Remove redundant check * Use `LastObject` where possible * Update tests * Make `LazyTravelDistance` `double` --------- Co-authored-by: James Wilson --- .../OsuDifficultyCalculatorTest.cs | 14 ++-- .../Evaluators/FlashlightEvaluator.cs | 2 +- .../Difficulty/OsuDifficultyCalculator.cs | 3 +- .../Preprocessing/OsuDifficultyHitObject.cs | 80 +++++++++++-------- osu.Game.Rulesets.Osu/Objects/Slider.cs | 18 ----- 5 files changed, 56 insertions(+), 61 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs index defd02b830..75e6dc6f09 100644 --- a/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs @@ -16,21 +16,21 @@ namespace osu.Game.Rulesets.Osu.Tests protected override string ResourceAssembly => "osu.Game.Rulesets.Osu.Tests"; [TestCase(6.7331304290522747d, 239, "diffcalc-test")] - [TestCase(1.4602604078137214d, 54, "zero-length-sliders")] - [TestCase(0.43052813047866129d, 4, "very-fast-slider")] + [TestCase(1.4595591215544095d, 54, "zero-length-sliders")] + [TestCase(0.4339253366122357d, 4, "very-fast-slider")] [TestCase(0.14143808967817237d, 2, "nan-slider")] public void Test(double expectedStarRating, int expectedMaxCombo, string name) => base.Test(expectedStarRating, expectedMaxCombo, name); - [TestCase(9.6779746353001634d, 239, "diffcalc-test")] - [TestCase(1.7691451263718989d, 54, "zero-length-sliders")] - [TestCase(0.55785578988249407d, 4, "very-fast-slider")] + [TestCase(9.6779397290273756d, 239, "diffcalc-test")] + [TestCase(1.7680515258663754d, 54, "zero-length-sliders")] + [TestCase(0.56174427678665129d, 4, "very-fast-slider")] public void TestClockRateAdjusted(double expectedStarRating, int expectedMaxCombo, string name) => Test(expectedStarRating, expectedMaxCombo, name, new OsuModDoubleTime()); [TestCase(6.7331304290522747d, 239, "diffcalc-test")] - [TestCase(1.4602604078137214d, 54, "zero-length-sliders")] - [TestCase(0.43052813047866129d, 4, "very-fast-slider")] + [TestCase(1.4595591215544095d, 54, "zero-length-sliders")] + [TestCase(0.4339253366122357d, 4, "very-fast-slider")] public void TestClassicMod(double expectedStarRating, int expectedMaxCombo, string name) => Test(expectedStarRating, expectedMaxCombo, name, new OsuModClassic()); diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs index 9d05f0b074..d64a2c2f15 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs @@ -95,7 +95,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators if (osuCurrent.BaseObject is Slider osuSlider) { // Invert the scaling factor to determine the true travel distance independent of circle size. - double pixelTravelDistance = osuSlider.LazyTravelDistance / scalingFactor; + double pixelTravelDistance = osuCurrent.LazyTravelDistance / scalingFactor; // Reward sliders based on velocity. sliderBonus = Math.Pow(Math.Max(0.0, pixelTravelDistance / osuCurrent.TravelTime - min_velocity), 0.5); diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index eb2cb95972..5da6df236e 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -124,8 +124,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty // If the map has less than two OsuHitObjects, the enumerator will not return anything. for (int i = 1; i < beatmap.HitObjects.Count; i++) { - var lastLast = i > 1 ? beatmap.HitObjects[i - 2] : null; - objects.Add(new OsuDifficultyHitObject(beatmap.HitObjects[i], beatmap.HitObjects[i - 1], lastLast, clockRate, objects, objects.Count)); + objects.Add(new OsuDifficultyHitObject(beatmap.HitObjects[i], beatmap.HitObjects[i - 1], clockRate, objects, objects.Count)); } return objects; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 5e4c5c1ee9..4329a25f34 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -28,6 +28,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing private const float assumed_slider_radius = NORMALISED_RADIUS * 1.8f; protected new OsuHitObject BaseObject => (OsuHitObject)base.BaseObject; + protected new OsuHitObject LastObject => (OsuHitObject)base.LastObject; /// /// Milliseconds elapsed since the start time of the previous , with a minimum of 25ms. @@ -75,6 +76,24 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing /// public double TravelTime { get; private set; } + /// + /// The position of the cursor at the point of completion of this if it is a + /// and was hit with as few movements as possible. + /// + public Vector2? LazyEndPosition { get; private set; } + + /// + /// The distance travelled by the cursor upon completion of this if it is a + /// and was hit with as few movements as possible. + /// + public double LazyTravelDistance { get; private set; } + + /// + /// The time taken by the cursor upon completion of this if it is a + /// and was hit with as few movements as possible. + /// + public double LazyTravelTime { get; private set; } + /// /// Angle the player has to take to hit this . /// Calculated as the angle between the circles (current-2, current-1, current). @@ -86,14 +105,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing /// public double HitWindowGreat { get; private set; } - private readonly OsuHitObject? lastLastObject; - private readonly OsuHitObject lastObject; + private readonly OsuDifficultyHitObject? lastLastDifficultyObject; + private readonly OsuDifficultyHitObject? lastDifficultyObject; - public OsuDifficultyHitObject(HitObject hitObject, HitObject lastObject, HitObject? lastLastObject, double clockRate, List objects, int index) + public OsuDifficultyHitObject(HitObject hitObject, HitObject lastObject, double clockRate, List objects, int index) : base(hitObject, lastObject, clockRate, objects, index) { - this.lastLastObject = lastLastObject as OsuHitObject; - this.lastObject = (OsuHitObject)lastObject; + lastLastDifficultyObject = index > 1 ? (OsuDifficultyHitObject)objects[index - 2] : null; + lastDifficultyObject = index > 0 ? (OsuDifficultyHitObject)objects[index - 1] : null; // Capped to 25ms to prevent difficulty calculation breaking from simultaneous objects. StrainTime = Math.Max(DeltaTime, MIN_DELTA_TIME); @@ -107,6 +126,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing HitWindowGreat = 2 * BaseObject.HitWindows.WindowFor(HitResult.Great) / clockRate; } + computeSliderCursorPosition(); setDistances(clockRate); } @@ -161,14 +181,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing { if (BaseObject is Slider currentSlider) { - computeSliderCursorPosition(currentSlider); // Bonus for repeat sliders until a better per nested object strain system can be achieved. - TravelDistance = currentSlider.LazyTravelDistance * (float)Math.Pow(1 + currentSlider.RepeatCount / 2.5, 1.0 / 2.5); - TravelTime = Math.Max(currentSlider.LazyTravelTime / clockRate, MIN_DELTA_TIME); + TravelDistance = LazyTravelDistance * Math.Pow(1 + currentSlider.RepeatCount / 2.5, 1.0 / 2.5); + TravelTime = Math.Max(LazyTravelTime / clockRate, MIN_DELTA_TIME); } // We don't need to calculate either angle or distance when one of the last->curr objects is a spinner - if (BaseObject is Spinner || lastObject is Spinner) + if (BaseObject is Spinner || LastObject is Spinner) return; // We will scale distances by this factor, so we can assume a uniform CircleSize among beatmaps. @@ -180,15 +199,15 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing scalingFactor *= 1 + smallCircleBonus; } - Vector2 lastCursorPosition = getEndCursorPosition(lastObject); + Vector2 lastCursorPosition = lastDifficultyObject != null ? getEndCursorPosition(lastDifficultyObject) : LastObject.StackedPosition; LazyJumpDistance = (BaseObject.StackedPosition * scalingFactor - lastCursorPosition * scalingFactor).Length; MinimumJumpTime = StrainTime; MinimumJumpDistance = LazyJumpDistance; - if (lastObject is Slider lastSlider) + if (LastObject is Slider lastSlider && lastDifficultyObject != null) { - double lastTravelTime = Math.Max(lastSlider.LazyTravelTime / clockRate, MIN_DELTA_TIME); + double lastTravelTime = Math.Max(lastDifficultyObject.LazyTravelTime / clockRate, MIN_DELTA_TIME); MinimumJumpTime = Math.Max(StrainTime - lastTravelTime, MIN_DELTA_TIME); // @@ -217,11 +236,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing MinimumJumpDistance = Math.Max(0, Math.Min(LazyJumpDistance - (maximum_slider_radius - assumed_slider_radius), tailJumpDistance - maximum_slider_radius)); } - if (lastLastObject != null && !(lastLastObject is Spinner)) + if (lastLastDifficultyObject != null && lastLastDifficultyObject.BaseObject is not Spinner) { - Vector2 lastLastCursorPosition = getEndCursorPosition(lastLastObject); + Vector2 lastLastCursorPosition = getEndCursorPosition(lastLastDifficultyObject); - Vector2 v1 = lastLastCursorPosition - lastObject.StackedPosition; + Vector2 v1 = lastLastCursorPosition - LastObject.StackedPosition; Vector2 v2 = BaseObject.StackedPosition - lastCursorPosition; float dot = Vector2.Dot(v1, v2); @@ -231,9 +250,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing } } - private void computeSliderCursorPosition(Slider slider) + private void computeSliderCursorPosition() { - if (slider.LazyEndPosition != null) + if (BaseObject is not Slider slider) + return; + + if (LazyEndPosition != null) return; // TODO: This commented version is actually correct by the new lazer implementation, but intentionally held back from @@ -280,15 +302,15 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing nestedObjects = reordered; } - slider.LazyTravelTime = trackingEndTime - slider.StartTime; + LazyTravelTime = trackingEndTime - slider.StartTime; - double endTimeMin = slider.LazyTravelTime / slider.SpanDuration; + double endTimeMin = LazyTravelTime / slider.SpanDuration; if (endTimeMin % 2 >= 1) endTimeMin = 1 - endTimeMin % 1; else endTimeMin %= 1; - slider.LazyEndPosition = slider.StackedPosition + slider.Path.PositionAt(endTimeMin); // temporary lazy end position until a real result can be derived. + LazyEndPosition = slider.StackedPosition + slider.Path.PositionAt(endTimeMin); // temporary lazy end position until a real result can be derived. Vector2 currCursorPosition = slider.StackedPosition; @@ -310,7 +332,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing // There is both a lazy end position as well as the actual end slider position. We assume the player takes the simpler movement. // For sliders that are circular, the lazy end position may actually be farther away than the sliders true end. // This code is designed to prevent buffing situations where lazy end is actually a less efficient movement. - Vector2 lazyMovement = Vector2.Subtract((Vector2)slider.LazyEndPosition, currCursorPosition); + Vector2 lazyMovement = Vector2.Subtract((Vector2)LazyEndPosition, currCursorPosition); if (lazyMovement.Length < currMovement.Length) currMovement = lazyMovement; @@ -328,25 +350,17 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing // this finds the positional delta from the required radius and the current position, and updates the currCursorPosition accordingly, as well as rewarding distance. currCursorPosition = Vector2.Add(currCursorPosition, Vector2.Multiply(currMovement, (float)((currMovementLength - requiredMovement) / currMovementLength))); currMovementLength *= (currMovementLength - requiredMovement) / currMovementLength; - slider.LazyTravelDistance += (float)currMovementLength; + LazyTravelDistance += currMovementLength; } if (i == nestedObjects.Count - 1) - slider.LazyEndPosition = currCursorPosition; + LazyEndPosition = currCursorPosition; } } - private Vector2 getEndCursorPosition(OsuHitObject hitObject) + private Vector2 getEndCursorPosition(OsuDifficultyHitObject difficultyHitObject) { - Vector2 pos = hitObject.StackedPosition; - - if (hitObject is Slider slider) - { - computeSliderCursorPosition(slider); - pos = slider.LazyEndPosition ?? pos; - } - - return pos; + return difficultyHitObject.LazyEndPosition ?? difficultyHitObject.BaseObject.StackedPosition; } } } diff --git a/osu.Game.Rulesets.Osu/Objects/Slider.cs b/osu.Game.Rulesets.Osu/Objects/Slider.cs index e484efb408..94e98fbef7 100644 --- a/osu.Game.Rulesets.Osu/Objects/Slider.cs +++ b/osu.Game.Rulesets.Osu/Objects/Slider.cs @@ -68,24 +68,6 @@ namespace osu.Game.Rulesets.Osu.Objects } } - /// - /// The position of the cursor at the point of completion of this if it was hit - /// with as few movements as possible. This is set and used by difficulty calculation. - /// - internal Vector2? LazyEndPosition; - - /// - /// The distance travelled by the cursor upon completion of this if it was hit - /// with as few movements as possible. This is set and used by difficulty calculation. - /// - internal float LazyTravelDistance; - - /// - /// The time taken by the cursor upon completion of this if it was hit - /// with as few movements as possible. This is set and used by difficulty calculation. - /// - internal double LazyTravelTime; - public IList> NodeSamples { get; set; } = new List>(); [JsonIgnore] From 7a9d31adb6c05d532de0eaebc56afcdd14f7917b Mon Sep 17 00:00:00 2001 From: wulpine Date: Thu, 10 Apr 2025 18:47:11 +0300 Subject: [PATCH 07/78] Move osu!catch movement diffcalc to an evaluator (#32655) * Move osu!catch movement state into `CatchDifficultyHitObject` In order to port `Movement` to an evaluator, the state has to be either moved elsewhere or calculated inside the evaluator. The latter requires backtracking for every hit object, which in the worst case is continued until the beginning of the map is reached. Limiting backtracking can lead to difficulty value changes. Thus, the first option was chosen for its simplicity. * Move osu!catch movement difficulty calculation to an evaluator Makes the code more in line with the other game modes. * Add documentation for `CatchDifficultyHitObject` fields --------- Co-authored-by: James Wilson --- .../Evaluators/MovementEvaluator.cs | 65 ++++++++++++++ .../Preprocessing/CatchDifficultyHitObject.cs | 56 ++++++++++++ .../Difficulty/Skills/Movement.cs | 89 +------------------ 3 files changed, 123 insertions(+), 87 deletions(-) create mode 100644 osu.Game.Rulesets.Catch/Difficulty/Evaluators/MovementEvaluator.cs diff --git a/osu.Game.Rulesets.Catch/Difficulty/Evaluators/MovementEvaluator.cs b/osu.Game.Rulesets.Catch/Difficulty/Evaluators/MovementEvaluator.cs new file mode 100644 index 0000000000..618b183943 --- /dev/null +++ b/osu.Game.Rulesets.Catch/Difficulty/Evaluators/MovementEvaluator.cs @@ -0,0 +1,65 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Game.Rulesets.Catch.Difficulty.Preprocessing; +using osu.Game.Rulesets.Difficulty.Preprocessing; + +namespace osu.Game.Rulesets.Catch.Difficulty.Evaluators +{ + public static class MovementEvaluator + { + private const double direction_change_bonus = 21.0; + + public static double EvaluateDifficultyOf(DifficultyHitObject current, double catcherSpeedMultiplier) + { + var catchCurrent = (CatchDifficultyHitObject)current; + var catchLast = (CatchDifficultyHitObject)current.Previous(0); + var catchLastLast = (CatchDifficultyHitObject)current.Previous(1); + + double weightedStrainTime = catchCurrent.StrainTime + 13 + (3 / catcherSpeedMultiplier); + + double distanceAddition = (Math.Pow(Math.Abs(catchCurrent.DistanceMoved), 1.3) / 510); + double sqrtStrain = Math.Sqrt(weightedStrainTime); + + double edgeDashBonus = 0; + + // Direction change bonus. + if (Math.Abs(catchCurrent.DistanceMoved) > 0.1) + { + if (current.Index >= 1 && Math.Abs(catchLast.DistanceMoved) > 0.1 && Math.Sign(catchCurrent.DistanceMoved) != Math.Sign(catchLast.DistanceMoved)) + { + double bonusFactor = Math.Min(50, Math.Abs(catchCurrent.DistanceMoved)) / 50; + double antiflowFactor = Math.Max(Math.Min(70, Math.Abs(catchLast.DistanceMoved)) / 70, 0.38); + + distanceAddition += direction_change_bonus / Math.Sqrt(catchLast.StrainTime + 16) * bonusFactor * antiflowFactor * Math.Max(1 - Math.Pow(weightedStrainTime / 1000, 3), 0); + } + + // Base bonus for every movement, giving some weight to streams. + distanceAddition += 12.5 * Math.Min(Math.Abs(catchCurrent.DistanceMoved), CatchDifficultyHitObject.NORMALIZED_HALF_CATCHER_WIDTH * 2) + / (CatchDifficultyHitObject.NORMALIZED_HALF_CATCHER_WIDTH * 6) / sqrtStrain; + } + + // Bonus for edge dashes. + if (catchCurrent.LastObject.DistanceToHyperDash <= 20.0f) + { + if (!catchCurrent.LastObject.HyperDash) + edgeDashBonus += 5.7; + + distanceAddition *= 1.0 + edgeDashBonus * ((20 - catchCurrent.LastObject.DistanceToHyperDash) / 20) + * Math.Pow((Math.Min(catchCurrent.StrainTime * catcherSpeedMultiplier, 265) / 265), 1.5); // Edge Dashes are easier at lower ms values + } + + // There is an edge case where horizontal back and forth sliders create "buzz" patterns which are repeated "movements" with a distance lower than + // the platter's width but high enough to be considered a movement due to the absolute_player_positioning_error and NORMALIZED_HALF_CATCHER_WIDTH offsets + // We are detecting this exact scenario. The first back and forth is counted but all subsequent ones are nullified. + // To achieve that, we need to store the exact distances (distance ignoring absolute_player_positioning_error and NORMALIZED_HALF_CATCHER_WIDTH) + if (current.Index >= 2 && Math.Abs(catchCurrent.ExactDistanceMoved) <= CatchDifficultyHitObject.NORMALIZED_HALF_CATCHER_WIDTH * 2 + && catchCurrent.ExactDistanceMoved == -catchLast.ExactDistanceMoved && catchLast.ExactDistanceMoved == -catchLastLast.ExactDistanceMoved + && catchCurrent.StrainTime == catchLast.StrainTime && catchLast.StrainTime == catchLastLast.StrainTime) + distanceAddition = 0; + + return distanceAddition / weightedStrainTime; + } + } +} diff --git a/osu.Game.Rulesets.Catch/Difficulty/Preprocessing/CatchDifficultyHitObject.cs b/osu.Game.Rulesets.Catch/Difficulty/Preprocessing/CatchDifficultyHitObject.cs index 9a7bbb4e9e..18b24f731d 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/Preprocessing/CatchDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/Preprocessing/CatchDifficultyHitObject.cs @@ -12,14 +12,48 @@ namespace osu.Game.Rulesets.Catch.Difficulty.Preprocessing public class CatchDifficultyHitObject : DifficultyHitObject { public const float NORMALIZED_HALF_CATCHER_WIDTH = 41.0f; + private const float absolute_player_positioning_error = 16.0f; public new PalpableCatchHitObject BaseObject => (PalpableCatchHitObject)base.BaseObject; public new PalpableCatchHitObject LastObject => (PalpableCatchHitObject)base.LastObject; + /// + /// Normalized position of . + /// public readonly float NormalizedPosition; + + /// + /// Normalized position of . + /// public readonly float LastNormalizedPosition; + /// + /// Normalized position of the player required to catch , assuming the player moves as little as possible. + /// + public float PlayerPosition { get; private set; } + + /// + /// Normalized position of the player after catching . + /// + public float LastPlayerPosition { get; private set; } + + /// + /// Normalized distance between and . + /// + /// + /// The sign of the value indicates the direction of the movement: negative is left and positive is right. + /// + public float DistanceMoved { get; private set; } + + /// + /// Normalized distance the player has to move from in order to catch at its . + /// + /// + /// The sign of the value indicates the direction of the movement: negative is left and positive is right. + /// + public float ExactDistanceMoved { get; private set; } + /// /// Milliseconds elapsed since the start time of the previous , with a minimum of 40ms. /// @@ -36,6 +70,28 @@ namespace osu.Game.Rulesets.Catch.Difficulty.Preprocessing // Every strain interval is hard capped at the equivalent of 375 BPM streaming speed as a safety measure StrainTime = Math.Max(40, DeltaTime); + + setMovementState(); + } + + private void setMovementState() + { + LastPlayerPosition = Index == 0 ? LastNormalizedPosition : ((CatchDifficultyHitObject)Previous(0)).PlayerPosition; + + PlayerPosition = Math.Clamp( + LastPlayerPosition, + NormalizedPosition - (NORMALIZED_HALF_CATCHER_WIDTH - absolute_player_positioning_error), + NormalizedPosition + (NORMALIZED_HALF_CATCHER_WIDTH - absolute_player_positioning_error) + ); + + DistanceMoved = PlayerPosition - LastPlayerPosition; + + // For the exact position we consider that the catcher is in the correct position for both objects + ExactDistanceMoved = NormalizedPosition - LastPlayerPosition; + + // After a hyperdash we ARE in the correct position. Always! + if (LastObject.HyperDash) + PlayerPosition = NormalizedPosition; } } } diff --git a/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs b/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs index b69bfb9215..90055b9aa3 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/Skills/Movement.cs @@ -1,8 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System; -using osu.Game.Rulesets.Catch.Difficulty.Preprocessing; +using osu.Game.Rulesets.Catch.Difficulty.Evaluators; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Mods; @@ -11,9 +10,6 @@ namespace osu.Game.Rulesets.Catch.Difficulty.Skills { public class Movement : StrainDecaySkill { - private const float absolute_player_positioning_error = 16f; - private const double direction_change_bonus = 21.0; - protected override double SkillMultiplier => 1; protected override double StrainDecayBase => 0.2; @@ -23,12 +19,6 @@ namespace osu.Game.Rulesets.Catch.Difficulty.Skills protected readonly float HalfCatcherWidth; - private float? lastPlayerPosition; - private float lastDistanceMoved; - private float lastExactDistanceMoved; - private double lastStrainTime; - private bool isInBuzzSection; - /// /// The speed multiplier applied to the player's catcher. /// @@ -48,82 +38,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty.Skills protected override double StrainValueOf(DifficultyHitObject current) { - var catchCurrent = (CatchDifficultyHitObject)current; - - lastPlayerPosition ??= catchCurrent.LastNormalizedPosition; - - float playerPosition = Math.Clamp( - lastPlayerPosition.Value, - catchCurrent.NormalizedPosition - (CatchDifficultyHitObject.NORMALIZED_HALF_CATCHER_WIDTH - absolute_player_positioning_error), - catchCurrent.NormalizedPosition + (CatchDifficultyHitObject.NORMALIZED_HALF_CATCHER_WIDTH - absolute_player_positioning_error) - ); - - float distanceMoved = playerPosition - lastPlayerPosition.Value; - - // For the exact position we consider that the catcher is in the correct position for both objects - float exactDistanceMoved = catchCurrent.NormalizedPosition - lastPlayerPosition.Value; - - double weightedStrainTime = catchCurrent.StrainTime + 13 + (3 / catcherSpeedMultiplier); - - double distanceAddition = (Math.Pow(Math.Abs(distanceMoved), 1.3) / 510); - double sqrtStrain = Math.Sqrt(weightedStrainTime); - - double edgeDashBonus = 0; - - // Direction change bonus. - if (Math.Abs(distanceMoved) > 0.1) - { - if (Math.Abs(lastDistanceMoved) > 0.1 && Math.Sign(distanceMoved) != Math.Sign(lastDistanceMoved)) - { - double bonusFactor = Math.Min(50, Math.Abs(distanceMoved)) / 50; - double antiflowFactor = Math.Max(Math.Min(70, Math.Abs(lastDistanceMoved)) / 70, 0.38); - - distanceAddition += direction_change_bonus / Math.Sqrt(lastStrainTime + 16) * bonusFactor * antiflowFactor * Math.Max(1 - Math.Pow(weightedStrainTime / 1000, 3), 0); - } - - // Base bonus for every movement, giving some weight to streams. - distanceAddition += 12.5 * Math.Min(Math.Abs(distanceMoved), CatchDifficultyHitObject.NORMALIZED_HALF_CATCHER_WIDTH * 2) / (CatchDifficultyHitObject.NORMALIZED_HALF_CATCHER_WIDTH * 6) - / sqrtStrain; - } - - // Bonus for edge dashes. - if (catchCurrent.LastObject.DistanceToHyperDash <= 20.0f) - { - if (!catchCurrent.LastObject.HyperDash) - edgeDashBonus += 5.7; - else - { - // After a hyperdash we ARE in the correct position. Always! - playerPosition = catchCurrent.NormalizedPosition; - } - - distanceAddition *= 1.0 + edgeDashBonus * ((20 - catchCurrent.LastObject.DistanceToHyperDash) / 20) - * Math.Pow((Math.Min(catchCurrent.StrainTime * catcherSpeedMultiplier, 265) / 265), 1.5); // Edge Dashes are easier at lower ms values - } - - // There is an edge case where horizontal back and forth sliders create "buzz" patterns which are repeated "movements" with a distance lower than - // the platter's width but high enough to be considered a movement due to the absolute_player_positioning_error and NORMALIZED_HALF_CATCHER_WIDTH offsets - // We are detecting this exact scenario. The first back and forth is counted but all subsequent ones are nullified. - // To achieve that, we need to store the exact distances (distance ignoring absolute_player_positioning_error and NORMALIZED_HALF_CATCHER_WIDTH) - if (Math.Abs(exactDistanceMoved) <= CatchDifficultyHitObject.NORMALIZED_HALF_CATCHER_WIDTH * 2 && exactDistanceMoved == -lastExactDistanceMoved - && catchCurrent.StrainTime == lastStrainTime) - { - if (isInBuzzSection) - distanceAddition = 0; - else - isInBuzzSection = true; - } - else - { - isInBuzzSection = false; - } - - lastPlayerPosition = playerPosition; - lastDistanceMoved = distanceMoved; - lastStrainTime = catchCurrent.StrainTime; - lastExactDistanceMoved = exactDistanceMoved; - - return distanceAddition / weightedStrainTime; + return MovementEvaluator.EvaluateDifficultyOf(current, catcherSpeedMultiplier); } } } From 2aeb80a8bd0e3363e89d47dc6c39591de4a21384 Mon Sep 17 00:00:00 2001 From: James Wilson Date: Sun, 27 Apr 2025 12:30:05 +0100 Subject: [PATCH 08/78] Move all score-independent bonuses into star rating (#31351) * basis refactor to allow for more complex SR calculations * move all possible bonuses into star rating * decrease star rating scaling to account for overall gains * add extra FL guard for safety * move star rating multiplier into a constant * Reorganise some things * Add HD and SO to difficulty adjustment mods * Move non-legacy mod multipliers back to PP * Some merge fixes * Fix application of flashlight rating multiplier * Fix Hidden bonuses being applied when Blinds mod is in use * Move part of speed OD scaling into difficulty * Move length bonus back to PP * Remove blinds special case * Revert star rating multiplier decrease * More balancing --------- Co-authored-by: StanR --- .../Difficulty/OsuDifficultyCalculator.cs | 210 ++++++++++++++---- .../Difficulty/OsuPerformanceCalculator.cs | 43 +--- 2 files changed, 168 insertions(+), 85 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 5da6df236e..a5071f0441 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Collections.Generic; using System.Linq; @@ -15,12 +13,16 @@ using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Difficulty.Skills; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Osu.Objects; +using osu.Game.Rulesets.Osu.Scoring; +using osu.Game.Rulesets.Scoring; namespace osu.Game.Rulesets.Osu.Difficulty { public class OsuDifficultyCalculator : DifficultyCalculator { + private const double performance_base_multiplier = 1.15; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things. private const double difficulty_multiplier = 0.0675; + private const double star_rating_multiplier = 0.0265; public override int Version => 20250306; @@ -29,53 +31,65 @@ namespace osu.Game.Rulesets.Osu.Difficulty { } + public static double CalculateDifficultyMultiplier(Mod[] mods, int totalHits, int spinnerCount) + { + double multiplier = performance_base_multiplier; + + if (mods.Any(m => m is OsuModSpunOut) && totalHits > 0) + multiplier *= 1.0 - Math.Pow((double)spinnerCount / totalHits, 0.85); + + return multiplier; + } + protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) { if (beatmap.HitObjects.Count == 0) return new OsuDifficultyAttributes { Mods = mods }; var aim = skills.OfType().Single(a => a.IncludeSliders); - double aimRating = Math.Sqrt(aim.DifficultyValue()) * difficulty_multiplier; - double aimDifficultyStrainCount = aim.CountTopWeightedStrains(); + var aimWithoutSliders = skills.OfType().Single(a => !a.IncludeSliders); + var speed = skills.OfType().Single(); + var flashlight = skills.OfType().SingleOrDefault(); + + double speedNotes = speed.RelevantNoteCount(); + + double aimDifficultStrainCount = aim.CountTopWeightedStrains(); + double speedDifficultStrainCount = speed.CountTopWeightedStrains(); + double difficultSliders = aim.GetDifficultSliders(); - var aimWithoutSliders = skills.OfType().Single(a => !a.IncludeSliders); - double aimRatingNoSliders = Math.Sqrt(aimWithoutSliders.DifficultyValue()) * difficulty_multiplier; + double preempt = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.ApproachRate, 1800, 1200, 450) / clockRate; + double approachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5; + + HitWindows hitWindows = new OsuHitWindows(); + hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty); + + double hitWindowGreat = hitWindows.WindowFor(HitResult.Great) / clockRate; + + double overallDifficulty = (80 - hitWindowGreat) / 6; + + int hitCircleCount = beatmap.HitObjects.Count(h => h is HitCircle); + int sliderCount = beatmap.HitObjects.Count(h => h is Slider); + int spinnerCount = beatmap.HitObjects.Count(h => h is Spinner); + + int totalHits = beatmap.HitObjects.Count; + + double drainRate = beatmap.Difficulty.DrainRate; + + double aimRating = computeAimRating(aim.DifficultyValue(), mods, totalHits, approachRate, overallDifficulty); + double aimRatingNoSliders = computeAimRating(aimWithoutSliders.DifficultyValue(), mods, totalHits, approachRate, overallDifficulty); + double speedRating = computeSpeedRating(speed.DifficultyValue(), mods, totalHits, approachRate, overallDifficulty); + + double flashlightRating = 0.0; + + if (flashlight is not null) + flashlightRating = computeFlashlightRating(flashlight.DifficultyValue(), mods, totalHits, overallDifficulty); + double sliderFactor = aimRating > 0 ? aimRatingNoSliders / aimRating : 1; - var speed = skills.OfType().Single(); - double speedRating = Math.Sqrt(speed.DifficultyValue()) * difficulty_multiplier; - double speedNotes = speed.RelevantNoteCount(); - double speedDifficultyStrainCount = speed.CountTopWeightedStrains(); - - var flashlight = skills.OfType().SingleOrDefault(); - double flashlightRating = flashlight == null ? 0.0 : Math.Sqrt(flashlight.DifficultyValue()) * difficulty_multiplier; - - if (mods.Any(m => m is OsuModTouchDevice)) - { - aimRating = Math.Pow(aimRating, 0.8); - flashlightRating = Math.Pow(flashlightRating, 0.8); - } - - if (mods.Any(h => h is OsuModRelax)) - { - aimRating *= 0.9; - speedRating = 0.0; - flashlightRating *= 0.7; - } - else if (mods.Any(h => h is OsuModAutopilot)) - { - speedRating *= 0.5; - aimRating = 0.0; - flashlightRating *= 0.4; - } - double baseAimPerformance = OsuStrainSkill.DifficultyToPerformance(aimRating); double baseSpeedPerformance = OsuStrainSkill.DifficultyToPerformance(speedRating); - double baseFlashlightPerformance = 0.0; - - if (mods.Any(h => h is OsuModFlashlight)) - baseFlashlightPerformance = Flashlight.DifficultyToPerformance(flashlightRating); + double baseFlashlightPerformance = Flashlight.DifficultyToPerformance(flashlightRating); double basePerformance = Math.Pow( @@ -84,16 +98,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty Math.Pow(baseFlashlightPerformance, 1.1), 1.0 / 1.1 ); + double multiplier = CalculateDifficultyMultiplier(mods, totalHits, spinnerCount); + double starRating = basePerformance > 0.00001 - ? Math.Cbrt(OsuPerformanceCalculator.PERFORMANCE_BASE_MULTIPLIER) * 0.027 * (Math.Cbrt(100000 / Math.Pow(2, 1 / 1.1) * basePerformance) + 4) + ? Math.Cbrt(multiplier) * star_rating_multiplier * (Math.Cbrt(100000 / Math.Pow(2, 1 / 1.1) * basePerformance) + 4) : 0; - double drainRate = beatmap.Difficulty.DrainRate; - - int hitCirclesCount = beatmap.HitObjects.Count(h => h is HitCircle); - int sliderCount = beatmap.HitObjects.Count(h => h is Slider); - int spinnerCount = beatmap.HitObjects.Count(h => h is Spinner); - OsuDifficultyAttributes attributes = new OsuDifficultyAttributes { StarRating = starRating, @@ -104,11 +114,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty SpeedNoteCount = speedNotes, FlashlightDifficulty = flashlightRating, SliderFactor = sliderFactor, - AimDifficultStrainCount = aimDifficultyStrainCount, - SpeedDifficultStrainCount = speedDifficultyStrainCount, + AimDifficultStrainCount = aimDifficultStrainCount, + SpeedDifficultStrainCount = speedDifficultStrainCount, DrainRate = drainRate, MaxCombo = beatmap.GetMaxCombo(), - HitCircleCount = hitCirclesCount, + HitCircleCount = hitCircleCount, SliderCount = sliderCount, SpinnerCount = spinnerCount, }; @@ -116,6 +126,109 @@ namespace osu.Game.Rulesets.Osu.Difficulty return attributes; } + private double computeAimRating(double aimDifficultyValue, Mod[] mods, int totalHits, double approachRate, double overallDifficulty) + { + if (mods.Any(m => m is OsuModAutopilot)) + return 0; + + double aimRating = Math.Sqrt(aimDifficultyValue) * difficulty_multiplier; + + if (mods.Any(m => m is OsuModTouchDevice)) + aimRating = Math.Pow(aimRating, 0.8); + + if (mods.Any(m => m is OsuModRelax)) + aimRating *= 0.9; + + double ratingMultiplier = 1.0; + + double approachRateLengthBonus = 0.95 + 0.4 * Math.Min(1.0, totalHits / 2000.0) + + (totalHits > 2000 ? Math.Log10(totalHits / 2000.0) * 0.5 : 0.0); + + double approachRateFactor = 0.0; + if (approachRate > 10.33) + approachRateFactor = 0.3 * (approachRate - 10.33); + else if (approachRate < 8.0) + approachRateFactor = 0.05 * (8.0 - approachRate); + + if (mods.Any(h => h is OsuModRelax)) + approachRateFactor = 0.0; + + ratingMultiplier *= 1.0 + approachRateFactor * approachRateLengthBonus; // Buff for longer maps with high AR. + + if (mods.Any(m => m is OsuModHidden)) + { + // We want to give more reward for lower AR when it comes to aim and HD. This nerfs high AR and buffs lower AR. + ratingMultiplier *= 1.0 + 0.04 * (12.0 - approachRate); + } + + // It is important to consider accuracy difficulty when scaling with accuracy. + ratingMultiplier *= 0.98 + Math.Pow(Math.Max(0, overallDifficulty), 2) / 2500; + + return aimRating * Math.Cbrt(ratingMultiplier); + } + + private double computeSpeedRating(double speedDifficultyValue, Mod[] mods, int totalHits, double approachRate, double overallDifficulty) + { + if (mods.Any(m => m is OsuModRelax)) + return 0; + + double speedRating = Math.Sqrt(speedDifficultyValue) * difficulty_multiplier; + + if (mods.Any(m => m is OsuModAutopilot)) + speedRating *= 0.5; + + double ratingMultiplier = 1.0; + + double approachRateLengthBonus = 0.95 + 0.4 * Math.Min(1.0, totalHits / 2000.0) + + (totalHits > 2000 ? Math.Log10(totalHits / 2000.0) * 0.5 : 0.0); + + double approachRateFactor = 0.0; + if (approachRate > 10.33) + approachRateFactor = 0.3 * (approachRate - 10.33); + + if (mods.Any(m => m is OsuModAutopilot)) + approachRateFactor = 0.0; + + ratingMultiplier *= 1.0 + approachRateFactor * approachRateLengthBonus; // Buff for longer maps with high AR. + + if (mods.Any(m => m is OsuModHidden)) + { + // We want to give more reward for lower AR when it comes to aim and HD. This nerfs high AR and buffs lower AR. + ratingMultiplier *= 1.0 + 0.04 * (12.0 - approachRate); + } + + ratingMultiplier *= 0.95 + Math.Pow(Math.Max(0, overallDifficulty), 2) / 750; + + return speedRating * Math.Cbrt(ratingMultiplier); + } + + private double computeFlashlightRating(double flashlightDifficultyValue, Mod[] mods, int totalHits, double overallDifficulty) + { + if (!mods.Any(m => m is OsuModFlashlight)) + return 0; + + double flashlightRating = Math.Sqrt(flashlightDifficultyValue) * difficulty_multiplier; + + if (mods.Any(m => m is OsuModTouchDevice)) + flashlightRating = Math.Pow(flashlightRating, 0.8); + + if (mods.Any(m => m is OsuModRelax)) + flashlightRating *= 0.7; + else if (mods.Any(m => m is OsuModAutopilot)) + flashlightRating *= 0.4; + + double ratingMultiplier = 1.0; + + // Account for shorter maps having a higher ratio of 0 combo/100 combo flashlight radius. + ratingMultiplier *= 0.7 + 0.1 * Math.Min(1.0, totalHits / 200.0) + + (totalHits > 200 ? 0.2 * Math.Min(1.0, (totalHits - 200) / 200.0) : 0.0); + + // It is important to consider accuracy difficulty when scaling with accuracy. + ratingMultiplier *= 0.98 + Math.Pow(Math.Max(0, overallDifficulty), 2) / 2500; + + return flashlightRating * Math.Sqrt(ratingMultiplier); + } + protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) { List objects = new List(); @@ -153,7 +266,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty new OsuModEasy(), new OsuModHardRock(), new OsuModFlashlight(), - new MultiMod(new OsuModFlashlight(), new OsuModHidden()) + new OsuModHidden(), + new OsuModSpunOut(), }; } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 7e2d68b9d8..3ff6af9b0b 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -21,8 +21,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty { public class OsuPerformanceCalculator : PerformanceCalculator { - public const double PERFORMANCE_BASE_MULTIPLIER = 1.15; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things. - private bool usingClassicSliderAccuracy; private double accuracy; @@ -126,14 +124,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty effectiveMissCount = Math.Max(countMiss, effectiveMissCount); effectiveMissCount = Math.Min(totalHits, effectiveMissCount); - double multiplier = PERFORMANCE_BASE_MULTIPLIER; + double multiplier = OsuDifficultyCalculator.CalculateDifficultyMultiplier(score.Mods, totalHits, osuAttributes.SpinnerCount); if (score.Mods.Any(m => m is OsuModNoFail)) multiplier *= Math.Max(0.90, 1.0 - 0.02 * effectiveMissCount); - if (score.Mods.Any(m => m is OsuModSpunOut) && totalHits > 0) - multiplier *= 1.0 - Math.Pow((double)osuAttributes.SpinnerCount / totalHits, 0.85); - if (score.Mods.Any(h => h is OsuModRelax)) { // https://www.desmos.com/calculator/vspzsop6td @@ -210,28 +205,16 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (effectiveMissCount > 0) aimValue *= calculateMissPenalty(effectiveMissCount, attributes.AimDifficultStrainCount); - double approachRateFactor = 0.0; - if (approachRate > 10.33) - approachRateFactor = 0.3 * (approachRate - 10.33); - else if (approachRate < 8.0) - approachRateFactor = 0.05 * (8.0 - approachRate); - - if (score.Mods.Any(h => h is OsuModRelax)) - approachRateFactor = 0.0; - - aimValue *= 1.0 + approachRateFactor * lengthBonus; // Buff for longer maps with high AR. - + // TC bonuses are excluded when blinds is present as the increased visual difficulty is unimportant when notes cannot be seen. if (score.Mods.Any(m => m is OsuModBlinds)) aimValue *= 1.3 + (totalHits * (0.0016 / (1 + 2 * effectiveMissCount)) * Math.Pow(accuracy, 16)) * (1 - 0.003 * attributes.DrainRate * attributes.DrainRate); - else if (score.Mods.Any(m => m is OsuModHidden || m is OsuModTraceable)) + else if (score.Mods.Any(m => m is OsuModTraceable)) { // We want to give more reward for lower AR when it comes to aim and HD. This nerfs high AR and buffs lower AR. aimValue *= 1.0 + 0.04 * (12.0 - approachRate); } aimValue *= accuracy; - // It is important to consider accuracy difficulty when scaling with accuracy. - aimValue *= 0.98 + Math.Pow(Math.Max(0, overallDifficulty), 2) / 2500; return aimValue; } @@ -250,21 +233,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (effectiveMissCount > 0) speedValue *= calculateMissPenalty(effectiveMissCount, attributes.SpeedDifficultStrainCount); - double approachRateFactor = 0.0; - if (approachRate > 10.33) - approachRateFactor = 0.3 * (approachRate - 10.33); - - if (score.Mods.Any(h => h is OsuModAutopilot)) - approachRateFactor = 0.0; - - speedValue *= 1.0 + approachRateFactor * lengthBonus; // Buff for longer maps with high AR. - + // TC bonuses are excluded when blinds is present as the increased visual difficulty is unimportant when notes cannot be seen. if (score.Mods.Any(m => m is OsuModBlinds)) { // Increasing the speed value by object count for Blinds isn't ideal, so the minimum buff is given. speedValue *= 1.12; } - else if (score.Mods.Any(m => m is OsuModHidden || m is OsuModTraceable)) + else if (score.Mods.Any(m => m is OsuModTraceable)) { // We want to give more reward for lower AR when it comes to aim and HD. This nerfs high AR and buffs lower AR. speedValue *= 1.0 + 0.04 * (12.0 - approachRate); @@ -281,7 +256,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty double relevantAccuracy = attributes.SpeedNoteCount == 0 ? 0 : (relevantCountGreat * 6.0 + relevantCountOk * 2.0 + relevantCountMeh) / (attributes.SpeedNoteCount * 6.0); // Scale the speed value with accuracy and OD. - speedValue *= (0.95 + Math.Pow(Math.Max(0, overallDifficulty), 2) / 750) * Math.Pow((accuracy + relevantAccuracy) / 2.0, (14.5 - overallDifficulty) / 2); + speedValue *= Math.Pow((accuracy + relevantAccuracy) / 2.0, (14.5 - overallDifficulty) / 2); return speedValue; } @@ -338,14 +313,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty flashlightValue *= getComboScalingFactor(attributes); - // Account for shorter maps having a higher ratio of 0 combo/100 combo flashlight radius. - flashlightValue *= 0.7 + 0.1 * Math.Min(1.0, totalHits / 200.0) + - (totalHits > 200 ? 0.2 * Math.Min(1.0, (totalHits - 200) / 200.0) : 0.0); - // Scale the flashlight value with accuracy _slightly_. flashlightValue *= 0.5 + accuracy / 2.0; - // It is important to also consider accuracy difficulty when doing that. - flashlightValue *= 0.98 + Math.Pow(Math.Max(0, overallDifficulty), 2) / 2500; return flashlightValue; } From 4f298760de5964ee238cc4cb0ffc7ed8cf764e55 Mon Sep 17 00:00:00 2001 From: Nathan Corbett <75299710+Finadoggie@users.noreply.github.com> Date: Sun, 27 Apr 2025 04:57:51 -0700 Subject: [PATCH 09/78] Use sliders in acc pp if scorev2 is enabled (#32634) Co-authored-by: StanR --- osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 3ff6af9b0b..1e314cec3d 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -22,6 +22,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty public class OsuPerformanceCalculator : PerformanceCalculator { private bool usingClassicSliderAccuracy; + private bool usingScoreV2; private double accuracy; private int scoreMaxCombo; @@ -64,6 +65,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty var osuAttributes = (OsuDifficultyAttributes)attributes; usingClassicSliderAccuracy = score.Mods.OfType().Any(m => m.NoSliderHeadAccuracy.Value); + usingScoreV2 = score.Mods.Any(m => m is ModScoreV2); accuracy = score.Accuracy; scoreMaxCombo = score.MaxCombo; @@ -269,7 +271,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty // This percentage only considers HitCircles of any value - in this part of the calculation we focus on hitting the timing hit window. double betterAccuracyPercentage; int amountHitObjectsWithAccuracy = attributes.HitCircleCount; - if (!usingClassicSliderAccuracy) + if (!usingClassicSliderAccuracy || usingScoreV2) amountHitObjectsWithAccuracy += attributes.SliderCount; if (amountHitObjectsWithAccuracy > 0) From ce73dbbcc6a03c9495cfb948270edd64371cc7b9 Mon Sep 17 00:00:00 2001 From: StanR Date: Thu, 1 May 2025 15:52:43 +0500 Subject: [PATCH 10/78] Add diffcalc considerations for Magnetised mod (#33004) * Add diffcalc considerations for Magnetised mod * Make speed reduction scale with power too --- .../Difficulty/OsuDifficultyCalculator.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index a5071f0441..e865427862 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -139,6 +139,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (mods.Any(m => m is OsuModRelax)) aimRating *= 0.9; + if (mods.Any(m => m is OsuModMagnetised)) + { + float magnetisedStrength = mods.OfType().First().AttractionStrength.Value; + aimRating *= 1.0 - magnetisedStrength; + } + double ratingMultiplier = 1.0; double approachRateLengthBonus = 0.95 + 0.4 * Math.Min(1.0, totalHits / 2000.0) + @@ -177,6 +183,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (mods.Any(m => m is OsuModAutopilot)) speedRating *= 0.5; + if (mods.Any(m => m is OsuModMagnetised)) + { + // reduce speed rating because of the speed distance scaling, with maximum reduction being 0.7x + float magnetisedStrength = mods.OfType().First().AttractionStrength.Value; + speedRating *= 1.0 - magnetisedStrength * 0.3; + } + double ratingMultiplier = 1.0; double approachRateLengthBonus = 0.95 + 0.4 * Math.Min(1.0, totalHits / 2000.0) + @@ -217,6 +230,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty else if (mods.Any(m => m is OsuModAutopilot)) flashlightRating *= 0.4; + if (mods.Any(m => m is OsuModMagnetised)) + { + float magnetisedStrength = mods.OfType().First().AttractionStrength.Value; + flashlightRating *= 1.0 - magnetisedStrength; + } + double ratingMultiplier = 1.0; // Account for shorter maps having a higher ratio of 0 combo/100 combo flashlight radius. From 3165b147eeccf2ab14165571cec73a71c6981135 Mon Sep 17 00:00:00 2001 From: KermitNuggies <50683296+TextAdventurer12@users.noreply.github.com> Date: Tue, 13 May 2025 01:05:07 +1200 Subject: [PATCH 11/78] Use proportion of difficult sliders to better estimate sliderbreaks on classic accuracy scores (#31234) * scale misscount by proportion of difficult sliders * cap sliderbreak count at count100 + count50 * use countMiss instead of effectiveMissCount as the base for sliderbreaks * make code inspector happy + cleanup * refactor to remove unnecesary calculation and need for new tuple * scale sliderbreaks with combo * use aimNoSliders for sliderbreak factor * code cleanup * make inspect code happy * use diffcalcutils * fix errors (oops) * scaling changes * fix div by zeros * Fix compilation error * Add online attributes for new difficulty attributes * Formatting * Rebase fixes * Make `CountTopWeightedSliders` to remove weird protected `SliderStrains` list * Prevent top weighted slider factor from being Infinity --------- Co-authored-by: tsunyoku --- .../Difficulty/OsuDifficultyAttributes.cs | 20 ++++++++++++++ .../Difficulty/OsuDifficultyCalculator.cs | 10 +++++++ .../Difficulty/OsuPerformanceCalculator.cs | 24 +++++++++++++++-- .../Difficulty/Skills/Aim.cs | 6 +++-- .../Difficulty/Skills/Speed.cs | 10 +++++++ .../Difficulty/Utils/OsuStrainUtils.cs | 26 +++++++++++++++++++ .../Difficulty/DifficultyAttributes.cs | 2 ++ 7 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Difficulty/Utils/OsuStrainUtils.cs diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs index f7d8c649c1..deefeb915c 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -53,6 +53,22 @@ namespace osu.Game.Rulesets.Osu.Difficulty [JsonProperty("slider_factor")] public double SliderFactor { get; set; } + /// + /// Describes how much of is contributed to by hitcircles or sliders + /// A value closer to 0.0 indicates most of is contributed by hitcircles + /// A value closer to Infinity indicates most of is contributed by sliders + /// + [JsonProperty("aim_top_weighted_slider_factor")] + public double AimTopWeightedSliderFactor { get; set; } + + /// + /// Describes how much of is contributed to by hitcircles or sliders + /// A value closer to 0.0 indicates most of is contributed by hitcircles + /// A value closer to Infinity indicates most of is contributed by sliders + /// + [JsonProperty("speed_top_weighted_slider_factor")] + public double SpeedTopWeightedSliderFactor { get; set; } + [JsonProperty("aim_difficult_strain_count")] public double AimDifficultStrainCount { get; set; } @@ -97,6 +113,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty yield return (ATTRIB_ID_SPEED_DIFFICULT_STRAIN_COUNT, SpeedDifficultStrainCount); yield return (ATTRIB_ID_SPEED_NOTE_COUNT, SpeedNoteCount); yield return (ATTRIB_ID_AIM_DIFFICULT_SLIDER_COUNT, AimDifficultSliderCount); + yield return (ATTRIB_ID_AIM_TOP_WEIGHTED_SLIDER_FACTOR, AimTopWeightedSliderFactor); + yield return (ATTRIB_ID_SPEED_TOP_WEIGHTED_SLIDER_FACTOR, SpeedTopWeightedSliderFactor); } public override void FromDatabaseAttributes(IReadOnlyDictionary values, IBeatmapOnlineInfo onlineInfo) @@ -112,6 +130,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty SpeedDifficultStrainCount = values[ATTRIB_ID_SPEED_DIFFICULT_STRAIN_COUNT]; SpeedNoteCount = values[ATTRIB_ID_SPEED_NOTE_COUNT]; AimDifficultSliderCount = values[ATTRIB_ID_AIM_DIFFICULT_SLIDER_COUNT]; + AimTopWeightedSliderFactor = values[ATTRIB_ID_AIM_TOP_WEIGHTED_SLIDER_FACTOR]; + SpeedTopWeightedSliderFactor = values[ATTRIB_ID_SPEED_TOP_WEIGHTED_SLIDER_FACTOR]; DrainRate = onlineInfo.DrainRate; HitCircleCount = onlineInfo.CircleCount; SliderCount = onlineInfo.SliderCount; diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index e865427862..fa142e4429 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -56,6 +56,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty double aimDifficultStrainCount = aim.CountTopWeightedStrains(); double speedDifficultStrainCount = speed.CountTopWeightedStrains(); + double aimNoSlidersTopWeightedSliderCount = aimWithoutSliders.CountTopWeightedSliders(); + double aimNoSlidersDifficultStrainCount = aimWithoutSliders.CountTopWeightedStrains(); + + double aimTopWeightedSliderFactor = aimNoSlidersTopWeightedSliderCount / Math.Max(1, aimNoSlidersDifficultStrainCount - aimNoSlidersTopWeightedSliderCount); + + double speedTopWeightedSliderCount = speed.CountTopWeightedSliders(); + double speedTopWeightedSliderFactor = speedTopWeightedSliderCount / Math.Max(1, speedDifficultStrainCount - speedTopWeightedSliderCount); + double difficultSliders = aim.GetDifficultSliders(); double preempt = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.ApproachRate, 1800, 1200, 450) / clockRate; @@ -116,6 +124,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty SliderFactor = sliderFactor, AimDifficultStrainCount = aimDifficultStrainCount, SpeedDifficultStrainCount = speedDifficultStrainCount, + AimTopWeightedSliderFactor = aimTopWeightedSliderFactor, + SpeedTopWeightedSliderFactor = speedTopWeightedSliderFactor, DrainRate = drainRate, MaxCombo = beatmap.GetMaxCombo(), HitCircleCount = hitCircleCount, diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 1e314cec3d..3335609e6f 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -205,7 +205,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty aimValue *= lengthBonus; if (effectiveMissCount > 0) - aimValue *= calculateMissPenalty(effectiveMissCount, attributes.AimDifficultStrainCount); + { + double estimatedSliderbreaks = calculateEstimatedSliderbreaks(attributes.AimTopWeightedSliderFactor, attributes); + aimValue *= calculateMissPenalty(effectiveMissCount + estimatedSliderbreaks, attributes.AimDifficultStrainCount); + } // TC bonuses are excluded when blinds is present as the increased visual difficulty is unimportant when notes cannot be seen. if (score.Mods.Any(m => m is OsuModBlinds)) @@ -233,7 +236,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty speedValue *= lengthBonus; if (effectiveMissCount > 0) - speedValue *= calculateMissPenalty(effectiveMissCount, attributes.SpeedDifficultStrainCount); + { + double estimatedSliderbreaks = calculateEstimatedSliderbreaks(attributes.SpeedTopWeightedSliderFactor, attributes); + speedValue *= calculateMissPenalty(effectiveMissCount + estimatedSliderbreaks, attributes.SpeedDifficultStrainCount); + } // TC bonuses are excluded when blinds is present as the increased visual difficulty is unimportant when notes cannot be seen. if (score.Mods.Any(m => m is OsuModBlinds)) @@ -321,6 +327,20 @@ namespace osu.Game.Rulesets.Osu.Difficulty return flashlightValue; } + private double calculateEstimatedSliderbreaks(double topWeightedSliderFactor, OsuDifficultyAttributes attributes) + { + if (!usingClassicSliderAccuracy || countOk == 0) + return 0; + + double missedComboPercent = 1.0 - (double)scoreMaxCombo / attributes.MaxCombo; + double estimatedSliderbreaks = Math.Min(countOk, effectiveMissCount * topWeightedSliderFactor); + + // scores with more oks are more likely to have sliderbreaks + double okAdjustment = ((countOk - estimatedSliderbreaks) + 0.5) / countOk; + + return estimatedSliderbreaks * okAdjustment * DifficultyCalculationUtils.Logistic(missedComboPercent, 0.33, 15); + } + /// /// Estimates player's deviation on speed notes using , assuming worst-case. /// Treats all speed notes as hit circles. diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 6f1b680211..633f29d6ff 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -7,6 +7,7 @@ using System.Linq; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Difficulty.Evaluators; +using osu.Game.Rulesets.Osu.Difficulty.Utils; using osu.Game.Rulesets.Osu.Objects; namespace osu.Game.Rulesets.Osu.Difficulty.Skills @@ -41,9 +42,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills currentStrain += AimEvaluator.EvaluateDifficultyOf(current, IncludeSliders) * skillMultiplier; if (current.BaseObject is Slider) - { sliderStrains.Add(currentStrain); - } return currentStrain; } @@ -54,10 +53,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills return 0; double maxSliderStrain = sliderStrains.Max(); + if (maxSliderStrain == 0) return 0; return sliderStrains.Sum(strain => 1.0 / (1.0 + Math.Exp(-(strain / maxSliderStrain * 12.0 - 6.0)))); } + + public double CountTopWeightedSliders() => OsuStrainUtils.CountTopWeightedSliders(sliderStrains, DifficultyValue()); } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index bdeea0e918..334f763be3 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -2,11 +2,14 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Difficulty.Evaluators; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; +using osu.Game.Rulesets.Osu.Objects; using System.Linq; +using osu.Game.Rulesets.Osu.Difficulty.Utils; namespace osu.Game.Rulesets.Osu.Difficulty.Skills { @@ -21,6 +24,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills private double currentStrain; private double currentRhythm; + private readonly List sliderStrains = new List(); + protected override int ReducedSectionCount => 5; public Speed(Mod[] mods) @@ -41,6 +46,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills double totalStrain = currentStrain * currentRhythm; + if (current.BaseObject is Slider) + sliderStrains.Add(totalStrain); + return totalStrain; } @@ -55,5 +63,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills return ObjectStrains.Sum(strain => 1.0 / (1.0 + Math.Exp(-(strain / maxStrain * 12.0 - 6.0)))); } + + public double CountTopWeightedSliders() => OsuStrainUtils.CountTopWeightedSliders(sliderStrains, DifficultyValue()); } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Utils/OsuStrainUtils.cs b/osu.Game.Rulesets.Osu/Difficulty/Utils/OsuStrainUtils.cs new file mode 100644 index 0000000000..8a78192ee4 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Difficulty/Utils/OsuStrainUtils.cs @@ -0,0 +1,26 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.Linq; +using osu.Game.Rulesets.Difficulty.Utils; + +namespace osu.Game.Rulesets.Osu.Difficulty.Utils +{ + public static class OsuStrainUtils + { + public static double CountTopWeightedSliders(IReadOnlyCollection sliderStrains, double difficultyValue) + { + if (sliderStrains.Count == 0) + return 0; + + double consistentTopStrain = difficultyValue / 10; // What would the top strain be if all strain values were identical + + if (consistentTopStrain == 0) + return 0; + + // Use a weighted sum of all strains. Constants are arbitrary and give nice values + return sliderStrains.Sum(s => DifficultyCalculationUtils.Logistic(s / consistentTopStrain, 0.88, 10, 1.1)); + } + } +} diff --git a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs index 59511973f7..f2b5642236 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs @@ -26,6 +26,8 @@ namespace osu.Game.Rulesets.Difficulty protected const int ATTRIB_ID_AIM_DIFFICULT_STRAIN_COUNT = 25; protected const int ATTRIB_ID_MONO_STAMINA_FACTOR = 29; protected const int ATTRIB_ID_AIM_DIFFICULT_SLIDER_COUNT = 31; + protected const int ATTRIB_ID_AIM_TOP_WEIGHTED_SLIDER_FACTOR = 33; + protected const int ATTRIB_ID_SPEED_TOP_WEIGHTED_SLIDER_FACTOR = 35; /// /// The mods which were applied to the beatmap. From d22b3fb200284caada0e0e1731d112b368b0d5ec Mon Sep 17 00:00:00 2001 From: James Wilson Date: Wed, 14 May 2025 13:37:08 +0100 Subject: [PATCH 12/78] Remove track usage in difficulty and performance calculations (#33132) --- .../Difficulty/CatchPerformanceCalculator.cs | 6 ++---- .../Difficulty/OsuPerformanceCalculator.cs | 6 ++---- .../Difficulty/TaikoPerformanceCalculator.cs | 6 ++---- osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs | 5 +---- 4 files changed, 7 insertions(+), 16 deletions(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchPerformanceCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchPerformanceCalculator.cs index 62a9fe250e..4b38cfac50 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchPerformanceCalculator.cs @@ -3,13 +3,13 @@ using System; using System.Linq; -using osu.Framework.Audio.Track; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Mods; using osu.Game.Scoring; using osu.Game.Scoring.Legacy; +using osu.Game.Utils; namespace osu.Game.Rulesets.Catch.Difficulty { @@ -57,9 +57,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty score.Mods.OfType().ForEach(m => m.ApplyToDifficulty(difficulty)); - var track = new TrackVirtual(10000); - score.Mods.OfType().ForEach(m => m.ApplyToTrack(track)); - double clockRate = track.Rate; + double clockRate = ModUtils.CalculateRateWithMods(score.Mods); // this is the same as osu!, so there's potential to share the implementation... maybe double preempt = IBeatmapDifficultyInfo.DifficultyRange(difficulty.ApproachRate, 1800, 1200, 450) / clockRate; diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 3335609e6f..431bc24357 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; -using osu.Framework.Audio.Track; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Utils; using osu.Game.Beatmaps; @@ -16,6 +15,7 @@ using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Osu.Scoring; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; +using osu.Game.Utils; namespace osu.Game.Rulesets.Osu.Difficulty { @@ -81,9 +81,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty score.Mods.OfType().ForEach(m => m.ApplyToDifficulty(difficulty)); - var track = new TrackVirtual(10000); - score.Mods.OfType().ForEach(m => m.ApplyToTrack(track)); - clockRate = track.Rate; + clockRate = ModUtils.CalculateRateWithMods(score.Mods); HitWindows hitWindows = new OsuHitWindows(); hitWindows.SetDifficulty(difficulty.OverallDifficulty); diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index 9e049df87c..3c4e1164f1 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; -using osu.Framework.Audio.Track; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Difficulty.Utils; @@ -13,6 +12,7 @@ using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Rulesets.Taiko.Scoring; using osu.Game.Scoring; +using osu.Game.Utils; namespace osu.Game.Rulesets.Taiko.Difficulty { @@ -43,9 +43,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty countMeh = score.Statistics.GetValueOrDefault(HitResult.Meh); countMiss = score.Statistics.GetValueOrDefault(HitResult.Miss); - var track = new TrackVirtual(10000); - score.Mods.OfType().ForEach(m => m.ApplyToTrack(track)); - clockRate = track.Rate; + clockRate = ModUtils.CalculateRateWithMods(score.Mods); var difficulty = score.BeatmapInfo!.Difficulty.Clone(); diff --git a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs index 5c840a8357..a7eed0dda1 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs @@ -8,7 +8,6 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using JetBrains.Annotations; -using osu.Framework.Audio.Track; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Lists; using osu.Game.Beatmaps; @@ -181,9 +180,7 @@ namespace osu.Game.Rulesets.Difficulty playableMods = mods.Select(m => m.DeepClone()).ToArray(); Beatmap = beatmap.GetPlayableBeatmap(ruleset, playableMods, cancellationToken); - var track = new TrackVirtual(10000); - playableMods.OfType().ForEach(m => m.ApplyToTrack(track)); - clockRate = track.Rate; + clockRate = ModUtils.CalculateRateWithMods(playableMods); } /// From 9314ea94b5fa62cbe8b07e99ffd627eb440ccc32 Mon Sep 17 00:00:00 2001 From: Givikap120 <89256026+Givikap120@users.noreply.github.com> Date: Sat, 17 May 2025 02:38:12 +0300 Subject: [PATCH 13/78] Change effective misscount to be based on legacy score and combo at the same time (#33066) * implement stuff * fix basic issues * rework calculations * sanity check * don't use score based misscount if no scorev1 present * Update OsuPerformanceCalculator.cs * update misscount diff attribute names * add raw score misscount attribute * introduce more reasonable high bound for misscount * code quality changes * Fix osu!catch SR buzz slider detection (#32412) * Use `normalized_hitobject_radius` during osu!catch buzz slider detection Currently the algorithm considers some buzz sliders as standstills when in reality they require movement. This happens because `HalfCatcherWidth` isn't normalized while `exactDistanceMoved` is, leading to an inaccurate comparison. `normalized_hitobject_radius` is the normalized value of `HalfCatcherWidth` and replacing one with the other fixes the problem. * Rename `normalized_hitobject_radius` to `normalized_half_catcher_width` The current name is confusing because hit objects have no radius in the context of osu!catch difficulty calculation. The new name conveys the actual purpose of the value. * Only set `normalized_half_catcher_width` in `CatchDifficultyHitObject` Prevents potential bugs if the value were to be changed in one of the classes but not in both. * Use `CatchDifficultyHitObject.NORMALIZED_HALF_CATCHER_WIDTH` directly Requested during code review. --------- Co-authored-by: James Wilson * Move osu!catch movement diffcalc to an evaluator (#32655) * Move osu!catch movement state into `CatchDifficultyHitObject` In order to port `Movement` to an evaluator, the state has to be either moved elsewhere or calculated inside the evaluator. The latter requires backtracking for every hit object, which in the worst case is continued until the beginning of the map is reached. Limiting backtracking can lead to difficulty value changes. Thus, the first option was chosen for its simplicity. * Move osu!catch movement difficulty calculation to an evaluator Makes the code more in line with the other game modes. * Add documentation for `CatchDifficultyHitObject` fields --------- Co-authored-by: James Wilson * Move all score-independent bonuses into star rating (#31351) * basis refactor to allow for more complex SR calculations * move all possible bonuses into star rating * decrease star rating scaling to account for overall gains * add extra FL guard for safety * move star rating multiplier into a constant * Reorganise some things * Add HD and SO to difficulty adjustment mods * Move non-legacy mod multipliers back to PP * Some merge fixes * Fix application of flashlight rating multiplier * Fix Hidden bonuses being applied when Blinds mod is in use * Move part of speed OD scaling into difficulty * Move length bonus back to PP * Remove blinds special case * Revert star rating multiplier decrease * More balancing --------- Co-authored-by: StanR * Add diffcalc considerations for Magnetised mod (#33004) * Add diffcalc considerations for Magnetised mod * Make speed reduction scale with power too * cleaning up * Update OsuPerformanceCalculator.cs * Update OsuPerformanceCalculator.cs * add new check to avoid overestimation * fix code style * fix nvicka * add database attributes * Refactor * Rename `Working` to `WorkingBeatmap` * Remove redundant condition * Remove useless variable * Remove `get` wording * Rename `calculateScoreAtCombo` * Remove redundant operator * Add comments to explain how score-based miss count derivations work * Remove redundant `decimal` calculations * use static method to improve performance * move stuff around for readability * move logic into helper class * fix the bug * Delete OsuLegacyScoreProcessor.cs * Delete ILegacyScoreProcessor.cs * revert static method for multiplier * use only basic combo score attribute * Clean-up * Remove unused param * Update osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs Co-authored-by: StanR * rename variables * Add `LegacyScoreUtils` * Add fail safe * Move `countMiss` * Better explain `CalculateRelevantScoreComboPerObject` * Add `OsuLegacyScoreMissCalculator` * Move `CalculateScoreAtCombo` and `CalculateRelevantScoreComboPerObject` * Remove unused variables * Move `GetLegacyScoreMultiplier` * Add `estimated` wording --------- Co-authored-by: wulpine Co-authored-by: James Wilson Co-authored-by: StanR Co-authored-by: StanR --- .../Difficulty/OsuDifficultyAttributes.cs | 15 ++ .../Difficulty/OsuDifficultyCalculator.cs | 10 + .../OsuLegacyScoreMissCalculator.cs | 187 ++++++++++++++++++ .../Difficulty/OsuPerformanceAttributes.cs | 6 + .../Difficulty/OsuPerformanceCalculator.cs | 76 ++++--- .../Difficulty/Utils/LegacyScoreUtils.cs | 51 +++++ .../Difficulty/DifficultyAttributes.cs | 3 + .../Difficulty/DifficultyCalculator.cs | 10 +- 8 files changed, 331 insertions(+), 27 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Difficulty/OsuLegacyScoreMissCalculator.cs create mode 100644 osu.Game.Rulesets.Osu/Difficulty/Utils/LegacyScoreUtils.cs diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs index deefeb915c..0bbf1d3df6 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -75,6 +75,15 @@ namespace osu.Game.Rulesets.Osu.Difficulty [JsonProperty("speed_difficult_strain_count")] public double SpeedDifficultStrainCount { get; set; } + [JsonProperty("slider_nested_score_per_object")] + public double SliderNestedScorePerObject { get; set; } + + [JsonProperty("legacy_score_base_multiplier")] + public double LegacyScoreBaseMultiplier { get; set; } + + [JsonProperty("maximum_legacy_combo_score")] + public double MaximumLegacyComboScore { get; set; } + /// /// The beatmap's drain rate. This doesn't scale with rate-adjusting mods. /// @@ -115,6 +124,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty yield return (ATTRIB_ID_AIM_DIFFICULT_SLIDER_COUNT, AimDifficultSliderCount); yield return (ATTRIB_ID_AIM_TOP_WEIGHTED_SLIDER_FACTOR, AimTopWeightedSliderFactor); yield return (ATTRIB_ID_SPEED_TOP_WEIGHTED_SLIDER_FACTOR, SpeedTopWeightedSliderFactor); + yield return (ATTRIB_ID_SLIDER_NESTED_SCORE_PER_OBJECT, SliderNestedScorePerObject); + yield return (ATTRIB_ID_LEGACY_SCORE_BASE_MULTIPLIER, LegacyScoreBaseMultiplier); + yield return (ATTRIB_ID_MAXIMUM_LEGACY_COMBO_SCORE, MaximumLegacyComboScore); } public override void FromDatabaseAttributes(IReadOnlyDictionary values, IBeatmapOnlineInfo onlineInfo) @@ -132,6 +144,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty AimDifficultSliderCount = values[ATTRIB_ID_AIM_DIFFICULT_SLIDER_COUNT]; AimTopWeightedSliderFactor = values[ATTRIB_ID_AIM_TOP_WEIGHTED_SLIDER_FACTOR]; SpeedTopWeightedSliderFactor = values[ATTRIB_ID_SPEED_TOP_WEIGHTED_SLIDER_FACTOR]; + SliderNestedScorePerObject = values[ATTRIB_ID_SLIDER_NESTED_SCORE_PER_OBJECT]; + LegacyScoreBaseMultiplier = values[ATTRIB_ID_LEGACY_SCORE_BASE_MULTIPLIER]; + MaximumLegacyComboScore = values[ATTRIB_ID_MAXIMUM_LEGACY_COMBO_SCORE]; DrainRate = onlineInfo.DrainRate; HitCircleCount = onlineInfo.CircleCount; SliderCount = onlineInfo.SliderCount; diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index fa142e4429..7c8de87884 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -11,6 +11,7 @@ using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Difficulty.Skills; +using osu.Game.Rulesets.Osu.Difficulty.Utils; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Scoring; @@ -112,6 +113,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty ? Math.Cbrt(multiplier) * star_rating_multiplier * (Math.Cbrt(100000 / Math.Pow(2, 1 / 1.1) * basePerformance) + 4) : 0; + double sliderNestedScorePerObject = LegacyScoreUtils.CalculateSliderNestedScorePerObject(beatmap, totalHits); + double legacyScoreBaseMultiplier = LegacyScoreUtils.CalculateDifficultyPeppyStars(beatmap); + + var simulator = new OsuLegacyScoreSimulator(); + var scoreAttributes = simulator.Simulate(WorkingBeatmap, beatmap); + OsuDifficultyAttributes attributes = new OsuDifficultyAttributes { StarRating = starRating, @@ -131,6 +138,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty HitCircleCount = hitCircleCount, SliderCount = sliderCount, SpinnerCount = spinnerCount, + SliderNestedScorePerObject = sliderNestedScorePerObject, + LegacyScoreBaseMultiplier = legacyScoreBaseMultiplier, + MaximumLegacyComboScore = scoreAttributes.ComboScore }; return attributes; diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuLegacyScoreMissCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuLegacyScoreMissCalculator.cs new file mode 100644 index 0000000000..53837b78a0 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuLegacyScoreMissCalculator.cs @@ -0,0 +1,187 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using System.Linq; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu.Mods; +using osu.Game.Rulesets.Scoring; +using osu.Game.Scoring; + +namespace osu.Game.Rulesets.Osu.Difficulty +{ + public class OsuLegacyScoreMissCalculator + { + private readonly ScoreInfo score; + private readonly OsuDifficultyAttributes attributes; + + public OsuLegacyScoreMissCalculator(ScoreInfo scoreInfo, OsuDifficultyAttributes attributes) + { + score = scoreInfo; + this.attributes = attributes; + } + + public double Calculate() + { + if (attributes.MaxCombo == 0 || score.LegacyTotalScore == null) + return 0; + + double scoreV1Multiplier = attributes.LegacyScoreBaseMultiplier * getLegacyScoreMultiplier(); + double relevantComboPerObject = calculateRelevantScoreComboPerObject(); + + double maximumMissCount = calculateMaximumComboBasedMissCount(); + + double scoreObtainedDuringMaxCombo = calculateScoreAtCombo(score.MaxCombo, relevantComboPerObject, scoreV1Multiplier); + double remainingScore = score.LegacyTotalScore.Value - scoreObtainedDuringMaxCombo; + + if (remainingScore <= 0) + return maximumMissCount; + + double remainingCombo = attributes.MaxCombo - score.MaxCombo; + double expectedRemainingScore = calculateScoreAtCombo(remainingCombo, relevantComboPerObject, scoreV1Multiplier); + + double scoreBasedMissCount = expectedRemainingScore / remainingScore; + + // If there's less then one miss detected - let combo-based miss count decide if this is FC or not + scoreBasedMissCount = Math.Max(scoreBasedMissCount, 1); + + // Cap result by very harsh version of combo-based miss count + return Math.Min(scoreBasedMissCount, maximumMissCount); + } + + /// + /// Calculates the amount of score that would be achieved at a given combo. + /// + private double calculateScoreAtCombo(double combo, double relevantComboPerObject, double scoreV1Multiplier) + { + int countGreat = score.Statistics.GetValueOrDefault(HitResult.Great); + int countOk = score.Statistics.GetValueOrDefault(HitResult.Ok); + int countMeh = score.Statistics.GetValueOrDefault(HitResult.Meh); + int countMiss = score.Statistics.GetValueOrDefault(HitResult.Miss); + + int totalHits = countGreat + countOk + countMeh + countMiss; + + double estimatedObjects = combo / relevantComboPerObject - 1; + + // The combo portion of ScoreV1 follows arithmetic progression + // Therefore, we calculate the combo portion of score using the combo per object and our current combo. + double comboScore = relevantComboPerObject > 0 ? (2 * (relevantComboPerObject - 1) + (estimatedObjects - 1) * relevantComboPerObject) * estimatedObjects / 2 : 0; + + // We then apply the accuracy and ScoreV1 multipliers to the resulting score. + comboScore *= score.Accuracy * 300 / 25 * scoreV1Multiplier; + + double objectsHit = (totalHits - countMiss) * combo / attributes.MaxCombo; + + // Score also has a non-combo portion we need to create the final score value. + double nonComboScore = (300 + attributes.SliderNestedScorePerObject) * score.Accuracy * objectsHit; + + return comboScore + nonComboScore; + } + + /// + /// Calculates the relevant combo per object for legacy score. + /// This assumes a uniform distribution for circles and sliders. + /// This handles cases where objects (such as buzz sliders) do not fit a normal arithmetic progression model. + /// + private double calculateRelevantScoreComboPerObject() + { + double comboScore = attributes.MaximumLegacyComboScore; + + // We then reverse apply the ScoreV1 multipliers to get the raw value. + comboScore /= 300.0 / 25.0 * attributes.LegacyScoreBaseMultiplier; + + // Reverse the arithmetic progression to work out the amount of combo per object based on the score. + double result = (attributes.MaxCombo - 2) * attributes.MaxCombo; + result /= Math.Max(attributes.MaxCombo + 2 * (comboScore - 1), 1); + + return result; + } + + /// + /// This function is a harsher version of current combo-based miss count, used to provide reasonable value for cases where score-based miss count can't do this. + /// + private double calculateMaximumComboBasedMissCount() + { + int countMiss = score.Statistics.GetValueOrDefault(HitResult.Miss); + + if (attributes.SliderCount <= 0) + return countMiss; + + int countOk = score.Statistics.GetValueOrDefault(HitResult.Ok); + int countMeh = score.Statistics.GetValueOrDefault(HitResult.Meh); + + int totalImperfectHits = countOk + countMeh + countMiss; + + double missCount = 0; + + // Consider that full combo is maximum combo minus dropped slider tails since they don't contribute to combo but also don't break it + // In classic scores we can't know the amount of dropped sliders so we estimate to 10% of all sliders on the map + double fullComboThreshold = attributes.MaxCombo - 0.1 * attributes.SliderCount; + + if (score.MaxCombo < fullComboThreshold) + missCount = Math.Pow(fullComboThreshold / Math.Max(1.0, score.MaxCombo), 2.5); + + // In classic scores there can't be more misses than a sum of all non-perfect judgements + missCount = Math.Min(missCount, totalImperfectHits); + + return missCount; + } + + /// + /// Logic copied from . + /// + private double getLegacyScoreMultiplier() + { + bool scoreV2 = score.Mods.Any(m => m is ModScoreV2); + + double multiplier = 1.0; + + foreach (var mod in score.Mods) + { + switch (mod) + { + case OsuModNoFail: + multiplier *= scoreV2 ? 1.0 : 0.5; + break; + + case OsuModEasy: + multiplier *= 0.5; + break; + + case OsuModHalfTime: + case OsuModDaycore: + multiplier *= 0.3; + break; + + case OsuModHidden: + multiplier *= 1.06; + break; + + case OsuModHardRock: + multiplier *= scoreV2 ? 1.10 : 1.06; + break; + + case OsuModDoubleTime: + case OsuModNightcore: + multiplier *= scoreV2 ? 1.20 : 1.12; + break; + + case OsuModFlashlight: + multiplier *= 1.12; + break; + + case OsuModSpunOut: + multiplier *= 0.9; + break; + + case OsuModRelax: + case OsuModAutopilot: + return 0; + } + } + + return multiplier; + } + } +} diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceAttributes.cs index de4491a31b..f889ce3137 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceAttributes.cs @@ -27,6 +27,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty [JsonProperty("speed_deviation")] public double? SpeedDeviation { get; set; } + [JsonProperty("combo_based_estimated_miss_count")] + public double ComboBasedEstimatedMissCount { get; set; } + + [JsonProperty("score_based_estimated_miss_count")] + public double? ScoreBasedEstimatedMissCount { get; set; } + public override IEnumerable GetAttributesForDisplay() { foreach (var attribute in base.GetAttributesForDisplay()) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 431bc24357..1c9334d208 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -7,12 +7,12 @@ using System.Linq; using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Utils; using osu.Game.Beatmaps; -using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Difficulty.Utils; using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu.Scoring; +using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Osu.Difficulty.Skills; using osu.Game.Rulesets.Osu.Mods; -using osu.Game.Rulesets.Osu.Scoring; using osu.Game.Rulesets.Scoring; using osu.Game.Scoring; using osu.Game.Utils; @@ -95,30 +95,20 @@ namespace osu.Game.Rulesets.Osu.Difficulty overallDifficulty = (80 - greatHitWindow) / 6; approachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5; - if (osuAttributes.SliderCount > 0) + double comboBasedEstimatedMissCount = calculateComboBasedEstimatedMissCount(osuAttributes); + double? scoreBasedEstimatedMissCount = null; + + if (usingClassicSliderAccuracy && score.LegacyTotalScore != null) { - if (usingClassicSliderAccuracy) - { - // Consider that full combo is maximum combo minus dropped slider tails since they don't contribute to combo but also don't break it - // In classic scores we can't know the amount of dropped sliders so we estimate to 10% of all sliders on the map - double fullComboThreshold = attributes.MaxCombo - 0.1 * osuAttributes.SliderCount; + var legacyScoreMissCalculator = new OsuLegacyScoreMissCalculator(score, osuAttributes); + scoreBasedEstimatedMissCount = legacyScoreMissCalculator.Calculate(); - if (scoreMaxCombo < fullComboThreshold) - effectiveMissCount = fullComboThreshold / Math.Max(1.0, scoreMaxCombo); - - // In classic scores there can't be more misses than a sum of all non-perfect judgements - effectiveMissCount = Math.Min(effectiveMissCount, totalImperfectHits); - } - else - { - double fullComboThreshold = attributes.MaxCombo - countSliderEndsDropped; - - if (scoreMaxCombo < fullComboThreshold) - effectiveMissCount = fullComboThreshold / Math.Max(1.0, scoreMaxCombo); - - // Combine regular misses with tick misses since tick misses break combo as well - effectiveMissCount = Math.Min(effectiveMissCount, countSliderTickMiss + countMiss); - } + effectiveMissCount = scoreBasedEstimatedMissCount.Value; + } + else + { + // Use combo-based miss count if this isn't a legacy score + effectiveMissCount = comboBasedEstimatedMissCount; } effectiveMissCount = Math.Max(countMiss, effectiveMissCount); @@ -163,6 +153,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty Accuracy = accuracyValue, Flashlight = flashlightValue, EffectiveMissCount = effectiveMissCount, + ComboBasedEstimatedMissCount = comboBasedEstimatedMissCount, + ScoreBasedEstimatedMissCount = scoreBasedEstimatedMissCount, SpeedDeviation = speedDeviation, Total = totalValue }; @@ -325,6 +317,39 @@ namespace osu.Game.Rulesets.Osu.Difficulty return flashlightValue; } + private double calculateComboBasedEstimatedMissCount(OsuDifficultyAttributes attributes) + { + if (attributes.SliderCount <= 0) + return countMiss; + + double missCount = countMiss; + + if (usingClassicSliderAccuracy) + { + // Consider that full combo is maximum combo minus dropped slider tails since they don't contribute to combo but also don't break it + // In classic scores we can't know the amount of dropped sliders so we estimate to 10% of all sliders on the map + double fullComboThreshold = attributes.MaxCombo - 0.1 * attributes.SliderCount; + + if (scoreMaxCombo < fullComboThreshold) + missCount = fullComboThreshold / Math.Max(1.0, scoreMaxCombo); + + // In classic scores there can't be more misses than a sum of all non-perfect judgements + missCount = Math.Min(missCount, totalImperfectHits); + } + else + { + double fullComboThreshold = attributes.MaxCombo - countSliderEndsDropped; + + if (scoreMaxCombo < fullComboThreshold) + missCount = fullComboThreshold / Math.Max(1.0, scoreMaxCombo); + + // Combine regular misses with tick misses since tick misses break combo as well + missCount = Math.Min(missCount, countSliderTickMiss + countMiss); + } + + return missCount; + } + private double calculateEstimatedSliderbreaks(double topWeightedSliderFactor, OsuDifficultyAttributes attributes) { if (!usingClassicSliderAccuracy || countOk == 0) @@ -336,6 +361,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty // scores with more oks are more likely to have sliderbreaks double okAdjustment = ((countOk - estimatedSliderbreaks) + 0.5) / countOk; + // There is a low probability of extra slider breaks on effective miss counts close to 1, as score based calculations are good at indicating if only a single break occurred. + estimatedSliderbreaks *= DifficultyCalculationUtils.Smoothstep(effectiveMissCount, 1, 2); + return estimatedSliderbreaks * okAdjustment * DifficultyCalculationUtils.Logistic(missedComboPercent, 0.33, 15); } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Utils/LegacyScoreUtils.cs b/osu.Game.Rulesets.Osu/Difficulty/Utils/LegacyScoreUtils.cs new file mode 100644 index 0000000000..d1df378b47 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Difficulty/Utils/LegacyScoreUtils.cs @@ -0,0 +1,51 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Linq; +using osu.Game.Beatmaps; +using osu.Game.Rulesets.Objects.Legacy; +using osu.Game.Rulesets.Osu.Objects; + +namespace osu.Game.Rulesets.Osu.Difficulty.Utils +{ + public static class LegacyScoreUtils + { + /// + /// Calculates the average amount of score per object that is caused by slider ticks. + /// + public static double CalculateSliderNestedScorePerObject(IBeatmap beatmap, int objectCount) + { + const double big_tick_score = 30; + const double small_tick_score = 10; + + var sliders = beatmap.HitObjects.OfType().ToArray(); + + // 1 for head, 1 for tail + int amountOfBigTicks = sliders.Length * 2; + + // Add slider repeats + amountOfBigTicks += sliders.Select(s => s.RepeatCount).Sum(); + + int amountOfSmallTicks = sliders.Select(s => s.NestedHitObjects.Count(nho => nho is SliderTick)).Sum(); + + double totalScore = amountOfBigTicks * big_tick_score + amountOfSmallTicks * small_tick_score; + + return totalScore / objectCount; + } + + public static int CalculateDifficultyPeppyStars(IBeatmap beatmap) + { + int objectCount = beatmap.HitObjects.Count; + int drainLength = 0; + + if (objectCount > 0) + { + int breakLength = beatmap.Breaks.Select(b => (int)Math.Round(b.EndTime) - (int)Math.Round(b.StartTime)).Sum(); + drainLength = ((int)Math.Round(beatmap.HitObjects[^1].StartTime) - (int)Math.Round(beatmap.HitObjects[0].StartTime) - breakLength) / 1000; + } + + return LegacyRulesetExtensions.CalculateDifficultyPeppyStars(beatmap.Difficulty, objectCount, drainLength); + } + } +} diff --git a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs index f2b5642236..e01ce6fde5 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs @@ -28,6 +28,9 @@ namespace osu.Game.Rulesets.Difficulty protected const int ATTRIB_ID_AIM_DIFFICULT_SLIDER_COUNT = 31; protected const int ATTRIB_ID_AIM_TOP_WEIGHTED_SLIDER_FACTOR = 33; protected const int ATTRIB_ID_SPEED_TOP_WEIGHTED_SLIDER_FACTOR = 35; + protected const int ATTRIB_ID_SLIDER_NESTED_SCORE_PER_OBJECT = 37; + protected const int ATTRIB_ID_LEGACY_SCORE_BASE_MULTIPLIER = 39; + protected const int ATTRIB_ID_MAXIMUM_LEGACY_COMBO_SCORE = 41; /// /// The mods which were applied to the beatmap. diff --git a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs index a7eed0dda1..4a404c1e57 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyCalculator.cs @@ -28,11 +28,15 @@ namespace osu.Game.Rulesets.Difficulty /// protected IBeatmap Beatmap { get; private set; } + /// + /// The working beatmap for which difficulty will be calculated. + /// + protected readonly IWorkingBeatmap WorkingBeatmap; + private Mod[] playableMods; private double clockRate; private readonly IRulesetInfo ruleset; - private readonly IWorkingBeatmap beatmap; /// /// A yymmdd version which is used to discern when reprocessing is required. @@ -42,7 +46,7 @@ namespace osu.Game.Rulesets.Difficulty protected DifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap) { this.ruleset = ruleset; - this.beatmap = beatmap; + WorkingBeatmap = beatmap; } /// @@ -178,7 +182,7 @@ namespace osu.Game.Rulesets.Difficulty private void preProcess([NotNull] IEnumerable mods, CancellationToken cancellationToken) { playableMods = mods.Select(m => m.DeepClone()).ToArray(); - Beatmap = beatmap.GetPlayableBeatmap(ruleset, playableMods, cancellationToken); + Beatmap = WorkingBeatmap.GetPlayableBeatmap(ruleset, playableMods, cancellationToken); clockRate = ModUtils.CalculateRateWithMods(playableMods); } From 553a8601ed24fcdaeb4fd62db0ae672983a860b6 Mon Sep 17 00:00:00 2001 From: James Wilson Date: Sun, 18 May 2025 13:50:29 +0100 Subject: [PATCH 14/78] Add `AimEstimatedSliderBreaks` and `SpeedEstimatedSliderBreaks` performance attributes (#33181) --- .../Difficulty/OsuPerformanceAttributes.cs | 6 +++++ .../Difficulty/OsuPerformanceCalculator.cs | 25 +++++++++++-------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceAttributes.cs index f889ce3137..8577eff11f 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceAttributes.cs @@ -33,6 +33,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty [JsonProperty("score_based_estimated_miss_count")] public double? ScoreBasedEstimatedMissCount { get; set; } + [JsonProperty("aim_estimated_slider_breaks")] + public double AimEstimatedSliderBreaks { get; set; } + + [JsonProperty("speed_estimated_slider_breaks")] + public double SpeedEstimatedSliderBreaks { get; set; } + public override IEnumerable GetAttributesForDisplay() { foreach (var attribute in base.GetAttributesForDisplay()) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 1c9334d208..8802c4a1c2 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -55,6 +55,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty private double? speedDeviation; + private double aimEstimatedSliderBreaks; + private double speedEstimatedSliderBreaks; + public OsuPerformanceCalculator() : base(new OsuRuleset()) { @@ -155,6 +158,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty EffectiveMissCount = effectiveMissCount, ComboBasedEstimatedMissCount = comboBasedEstimatedMissCount, ScoreBasedEstimatedMissCount = scoreBasedEstimatedMissCount, + AimEstimatedSliderBreaks = aimEstimatedSliderBreaks, + SpeedEstimatedSliderBreaks = speedEstimatedSliderBreaks, SpeedDeviation = speedDeviation, Total = totalValue }; @@ -196,8 +201,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (effectiveMissCount > 0) { - double estimatedSliderbreaks = calculateEstimatedSliderbreaks(attributes.AimTopWeightedSliderFactor, attributes); - aimValue *= calculateMissPenalty(effectiveMissCount + estimatedSliderbreaks, attributes.AimDifficultStrainCount); + aimEstimatedSliderBreaks = calculateEstimatedSliderBreaks(attributes.AimTopWeightedSliderFactor, attributes); + aimValue *= calculateMissPenalty(effectiveMissCount + aimEstimatedSliderBreaks, attributes.AimDifficultStrainCount); } // TC bonuses are excluded when blinds is present as the increased visual difficulty is unimportant when notes cannot be seen. @@ -227,8 +232,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (effectiveMissCount > 0) { - double estimatedSliderbreaks = calculateEstimatedSliderbreaks(attributes.SpeedTopWeightedSliderFactor, attributes); - speedValue *= calculateMissPenalty(effectiveMissCount + estimatedSliderbreaks, attributes.SpeedDifficultStrainCount); + speedEstimatedSliderBreaks = calculateEstimatedSliderBreaks(attributes.SpeedTopWeightedSliderFactor, attributes); + speedValue *= calculateMissPenalty(effectiveMissCount + speedEstimatedSliderBreaks, attributes.SpeedDifficultStrainCount); } // TC bonuses are excluded when blinds is present as the increased visual difficulty is unimportant when notes cannot be seen. @@ -350,21 +355,21 @@ namespace osu.Game.Rulesets.Osu.Difficulty return missCount; } - private double calculateEstimatedSliderbreaks(double topWeightedSliderFactor, OsuDifficultyAttributes attributes) + private double calculateEstimatedSliderBreaks(double topWeightedSliderFactor, OsuDifficultyAttributes attributes) { if (!usingClassicSliderAccuracy || countOk == 0) return 0; double missedComboPercent = 1.0 - (double)scoreMaxCombo / attributes.MaxCombo; - double estimatedSliderbreaks = Math.Min(countOk, effectiveMissCount * topWeightedSliderFactor); + double estimatedSliderBreaks = Math.Min(countOk, effectiveMissCount * topWeightedSliderFactor); - // scores with more oks are more likely to have sliderbreaks - double okAdjustment = ((countOk - estimatedSliderbreaks) + 0.5) / countOk; + // scores with more oks are more likely to have slider breaks + double okAdjustment = ((countOk - estimatedSliderBreaks) + 0.5) / countOk; // There is a low probability of extra slider breaks on effective miss counts close to 1, as score based calculations are good at indicating if only a single break occurred. - estimatedSliderbreaks *= DifficultyCalculationUtils.Smoothstep(effectiveMissCount, 1, 2); + estimatedSliderBreaks *= DifficultyCalculationUtils.Smoothstep(effectiveMissCount, 1, 2); - return estimatedSliderbreaks * okAdjustment * DifficultyCalculationUtils.Logistic(missedComboPercent, 0.33, 15); + return estimatedSliderBreaks * okAdjustment * DifficultyCalculationUtils.Logistic(missedComboPercent, 0.33, 15); } /// From 4a343ceaf1bc7d9750de658db773b5e74ec7702d Mon Sep 17 00:00:00 2001 From: James Wilson Date: Wed, 21 May 2025 12:25:20 +0100 Subject: [PATCH 15/78] Move `Ruleset` and `DifficultyCalculator` allocations to global setup (#33220) --- .../BenchmarkDifficultyCalculation.cs | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/osu.Game.Benchmarks/BenchmarkDifficultyCalculation.cs b/osu.Game.Benchmarks/BenchmarkDifficultyCalculation.cs index eaa4f5cc28..01e50827ba 100644 --- a/osu.Game.Benchmarks/BenchmarkDifficultyCalculation.cs +++ b/osu.Game.Benchmarks/BenchmarkDifficultyCalculation.cs @@ -8,6 +8,7 @@ using osu.Game.Beatmaps; using osu.Game.IO; using osu.Game.IO.Archives; using osu.Game.Rulesets.Catch; +using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Mania; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Taiko; @@ -17,10 +18,10 @@ namespace osu.Game.Benchmarks { public class BenchmarkDifficultyCalculation : BenchmarkTest { - private WorkingBeatmap osuBeatmap = null!; - private WorkingBeatmap taikoBeatmap = null!; - private WorkingBeatmap catchBeatmap = null!; - private WorkingBeatmap maniaBeatmap = null!; + private DifficultyCalculator osuCalculator = null!; + private DifficultyCalculator taikoCalculator = null!; + private DifficultyCalculator catchCalculator = null!; + private DifficultyCalculator maniaCalculator = null!; public override void SetUp() { @@ -29,10 +30,15 @@ namespace osu.Game.Benchmarks using var archive = resources.GetStream("Resources/Archives/241526 Soleily - Renatus.osz"); using var archiveReader = new ZipArchiveReader(archive); - osuBeatmap = readBeatmap(archiveReader, "Soleily - Renatus (Gamu) [Insane].osu"); - taikoBeatmap = readBeatmap(archiveReader, "Soleily - Renatus (MMzz) [Oni].osu"); - catchBeatmap = readBeatmap(archiveReader, "Soleily - Renatus (Deif) [Salad].osu"); - maniaBeatmap = readBeatmap(archiveReader, "Soleily - Renatus (ExPew) [Another].osu"); + var osuBeatmap = readBeatmap(archiveReader, "Soleily - Renatus (Gamu) [Insane].osu"); + var taikoBeatmap = readBeatmap(archiveReader, "Soleily - Renatus (MMzz) [Oni].osu"); + var catchBeatmap = readBeatmap(archiveReader, "Soleily - Renatus (Deif) [Salad].osu"); + var maniaBeatmap = readBeatmap(archiveReader, "Soleily - Renatus (ExPew) [Another].osu"); + + osuCalculator = new OsuRuleset().CreateDifficultyCalculator(osuBeatmap); + taikoCalculator = new TaikoRuleset().CreateDifficultyCalculator(taikoBeatmap); + catchCalculator = new CatchRuleset().CreateDifficultyCalculator(catchBeatmap); + maniaCalculator = new ManiaRuleset().CreateDifficultyCalculator(maniaBeatmap); } private WorkingBeatmap readBeatmap(ZipArchiveReader archiveReader, string beatmapName) @@ -48,25 +54,23 @@ namespace osu.Game.Benchmarks } [Benchmark] - public void CalculateDifficultyOsu() => new OsuRuleset().CreateDifficultyCalculator(osuBeatmap).Calculate(); + public void CalculateDifficultyOsu() => osuCalculator.Calculate(); [Benchmark] - public void CalculateDifficultyTaiko() => new TaikoRuleset().CreateDifficultyCalculator(taikoBeatmap).Calculate(); + public void CalculateDifficultyTaiko() => taikoCalculator.Calculate(); [Benchmark] - public void CalculateDifficultyCatch() => new CatchRuleset().CreateDifficultyCalculator(catchBeatmap).Calculate(); + public void CalculateDifficultyCatch() => catchCalculator.Calculate(); [Benchmark] - public void CalculateDifficultyMania() => new ManiaRuleset().CreateDifficultyCalculator(maniaBeatmap).Calculate(); + public void CalculateDifficultyMania() => maniaCalculator.Calculate(); [Benchmark] public void CalculateDifficultyOsuHundredTimes() { - var diffcalc = new OsuRuleset().CreateDifficultyCalculator(osuBeatmap); - for (int i = 0; i < 100; i++) { - diffcalc.Calculate(); + osuCalculator.Calculate(); } } } From 60eaf088df5c75fdcf7ad54e27907bb13a145178 Mon Sep 17 00:00:00 2001 From: StanR Date: Thu, 22 May 2025 13:11:51 +0500 Subject: [PATCH 16/78] Buff precision difficulty rating in osu! (#28877) * Buff precision difficulty rating in osu! * Fix position repetition calculation * Fix aim evaluator crashing, move small circle bonus calculation, adjust the curve slightly * Refactor * Fix code quality * Semicolon * Apply small circle bonus to speed too * Fix formatting --------- Co-authored-by: James Wilson --- .../Difficulty/Evaluators/AimEvaluator.cs | 19 +++++++++++++++++++ .../Difficulty/Evaluators/SpeedEvaluator.cs | 3 +++ .../Preprocessing/OsuDifficultyHitObject.cs | 13 +++++++------ 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index d1c92ed6a7..15ccb8b1f0 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -34,6 +34,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators var osuCurrObj = (OsuDifficultyHitObject)current; var osuLastObj = (OsuDifficultyHitObject)current.Previous(0); var osuLastLastObj = (OsuDifficultyHitObject)current.Previous(1); + var osuLast2Obj = (OsuDifficultyHitObject)current.Previous(2); const int radius = OsuDifficultyHitObject.NORMALISED_RADIUS; const int diameter = OsuDifficultyHitObject.NORMALISED_DIAMETER; @@ -103,6 +104,21 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators * DifficultyCalculationUtils.Smootherstep(osuLastObj.LazyJumpDistance, radius, diameter) * Math.Pow(DifficultyCalculationUtils.ReverseLerp(osuLastObj.LazyJumpDistance, diameter * 3, diameter), 1.8) * DifficultyCalculationUtils.Smootherstep(lastAngle, double.DegreesToRadians(110), double.DegreesToRadians(60)); + + if (osuLast2Obj != null) + { + // If objects just go back and forth through a middle point - don't give as much wide bonus + // Use Previous(2) and Previous(0) because angles calculation is done prevprev-prev-curr, so any object's angle's center point is always the previous object + var lastBaseObject = (OsuHitObject)osuLastObj.BaseObject; + var last2BaseObject = (OsuHitObject)osuLast2Obj.BaseObject; + + float distance = (last2BaseObject.StackedPosition - lastBaseObject.StackedPosition).Length; + + if (distance < 1) + { + wideAngleBonus *= 1 - 0.35 * (1 - distance); + } + } } } @@ -139,6 +155,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators if (withSliderTravelDistance) aimStrain += sliderBonus * slider_multiplier; + // Apply high circle size bonus + aimStrain *= osuCurrObj.SmallCircleBonus; + return aimStrain; } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs index 769220ece0..ee9b46eecb 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs @@ -60,6 +60,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators // Max distance bonus is 1 * `distance_multiplier` at single_spacing_threshold double distanceBonus = Math.Pow(distance / single_spacing_threshold, 3.95) * distance_multiplier; + // Apply reduced small circle bonus because flow aim difficulty on small circles doesn't scale as hard as jumps + distanceBonus *= Math.Sqrt(osuCurrObj.SmallCircleBonus); + if (mods.OfType().Any()) distanceBonus = 0; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 4329a25f34..8ad72daeb5 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -105,6 +105,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing /// public double HitWindowGreat { get; private set; } + /// + /// Selective bonus for maps with higher circle size. + /// + public double SmallCircleBonus { get; private set; } + private readonly OsuDifficultyHitObject? lastLastDifficultyObject; private readonly OsuDifficultyHitObject? lastDifficultyObject; @@ -117,6 +122,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing // Capped to 25ms to prevent difficulty calculation breaking from simultaneous objects. StrainTime = Math.Max(DeltaTime, MIN_DELTA_TIME); + SmallCircleBonus = Math.Max(1.0, 1.0 + (30 - BaseObject.Radius) / 40); + if (BaseObject is Slider sliderObject) { HitWindowGreat = 2 * sliderObject.HeadCircle.HitWindows.WindowFor(HitResult.Great) / clockRate; @@ -193,12 +200,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing // We will scale distances by this factor, so we can assume a uniform CircleSize among beatmaps. float scalingFactor = NORMALISED_RADIUS / (float)BaseObject.Radius; - if (BaseObject.Radius < 30) - { - float smallCircleBonus = Math.Min(30 - (float)BaseObject.Radius, 5) / 50; - scalingFactor *= 1 + smallCircleBonus; - } - Vector2 lastCursorPosition = lastDifficultyObject != null ? getEndCursorPosition(lastDifficultyObject) : LastObject.StackedPosition; LazyJumpDistance = (BaseObject.StackedPosition * scalingFactor - lastCursorPosition * scalingFactor).Length; From ee055ba8f5a44f8f7bda903ba4fbdf87cbcc94ab Mon Sep 17 00:00:00 2001 From: Givikap120 <89256026+Givikap120@users.noreply.github.com> Date: Fri, 23 May 2025 01:27:16 +0300 Subject: [PATCH 17/78] Add spinners support to combo based estimated misscount (#33170) * add spinner support * Make `CalculateSpinnerScore` private & clarify comments --------- Co-authored-by: James Wilson --- .../Difficulty/OsuDifficultyAttributes.cs | 8 +-- .../Difficulty/OsuDifficultyCalculator.cs | 4 +- .../OsuLegacyScoreMissCalculator.cs | 2 +- .../Difficulty/Utils/LegacyScoreUtils.cs | 58 +++++++++++++++++-- .../Difficulty/DifficultyAttributes.cs | 2 +- 5 files changed, 62 insertions(+), 12 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs index 0bbf1d3df6..9cab454142 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyAttributes.cs @@ -75,8 +75,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty [JsonProperty("speed_difficult_strain_count")] public double SpeedDifficultStrainCount { get; set; } - [JsonProperty("slider_nested_score_per_object")] - public double SliderNestedScorePerObject { get; set; } + [JsonProperty("nested_score_per_object")] + public double NestedScorePerObject { get; set; } [JsonProperty("legacy_score_base_multiplier")] public double LegacyScoreBaseMultiplier { get; set; } @@ -124,7 +124,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty yield return (ATTRIB_ID_AIM_DIFFICULT_SLIDER_COUNT, AimDifficultSliderCount); yield return (ATTRIB_ID_AIM_TOP_WEIGHTED_SLIDER_FACTOR, AimTopWeightedSliderFactor); yield return (ATTRIB_ID_SPEED_TOP_WEIGHTED_SLIDER_FACTOR, SpeedTopWeightedSliderFactor); - yield return (ATTRIB_ID_SLIDER_NESTED_SCORE_PER_OBJECT, SliderNestedScorePerObject); + yield return (ATTRIB_ID_NESTED_SCORE_PER_OBJECT, NestedScorePerObject); yield return (ATTRIB_ID_LEGACY_SCORE_BASE_MULTIPLIER, LegacyScoreBaseMultiplier); yield return (ATTRIB_ID_MAXIMUM_LEGACY_COMBO_SCORE, MaximumLegacyComboScore); } @@ -144,7 +144,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty AimDifficultSliderCount = values[ATTRIB_ID_AIM_DIFFICULT_SLIDER_COUNT]; AimTopWeightedSliderFactor = values[ATTRIB_ID_AIM_TOP_WEIGHTED_SLIDER_FACTOR]; SpeedTopWeightedSliderFactor = values[ATTRIB_ID_SPEED_TOP_WEIGHTED_SLIDER_FACTOR]; - SliderNestedScorePerObject = values[ATTRIB_ID_SLIDER_NESTED_SCORE_PER_OBJECT]; + NestedScorePerObject = values[ATTRIB_ID_NESTED_SCORE_PER_OBJECT]; LegacyScoreBaseMultiplier = values[ATTRIB_ID_LEGACY_SCORE_BASE_MULTIPLIER]; MaximumLegacyComboScore = values[ATTRIB_ID_MAXIMUM_LEGACY_COMBO_SCORE]; DrainRate = onlineInfo.DrainRate; diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 7c8de87884..dd9d4d4c23 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -113,7 +113,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty ? Math.Cbrt(multiplier) * star_rating_multiplier * (Math.Cbrt(100000 / Math.Pow(2, 1 / 1.1) * basePerformance) + 4) : 0; - double sliderNestedScorePerObject = LegacyScoreUtils.CalculateSliderNestedScorePerObject(beatmap, totalHits); + double sliderNestedScorePerObject = LegacyScoreUtils.CalculateNestedScorePerObject(beatmap, totalHits); double legacyScoreBaseMultiplier = LegacyScoreUtils.CalculateDifficultyPeppyStars(beatmap); var simulator = new OsuLegacyScoreSimulator(); @@ -138,7 +138,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty HitCircleCount = hitCircleCount, SliderCount = sliderCount, SpinnerCount = spinnerCount, - SliderNestedScorePerObject = sliderNestedScorePerObject, + NestedScorePerObject = sliderNestedScorePerObject, LegacyScoreBaseMultiplier = legacyScoreBaseMultiplier, MaximumLegacyComboScore = scoreAttributes.ComboScore }; diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuLegacyScoreMissCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuLegacyScoreMissCalculator.cs index 53837b78a0..207ecde81a 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuLegacyScoreMissCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuLegacyScoreMissCalculator.cs @@ -74,7 +74,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty double objectsHit = (totalHits - countMiss) * combo / attributes.MaxCombo; // Score also has a non-combo portion we need to create the final score value. - double nonComboScore = (300 + attributes.SliderNestedScorePerObject) * score.Accuracy * objectsHit; + double nonComboScore = (300 + attributes.NestedScorePerObject) * score.Accuracy * objectsHit; return comboScore + nonComboScore; } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Utils/LegacyScoreUtils.cs b/osu.Game.Rulesets.Osu/Difficulty/Utils/LegacyScoreUtils.cs index d1df378b47..df1683fb29 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Utils/LegacyScoreUtils.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Utils/LegacyScoreUtils.cs @@ -12,9 +12,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Utils public static class LegacyScoreUtils { /// - /// Calculates the average amount of score per object that is caused by slider ticks. + /// Calculates the average amount of score per object that is caused by nested judgements such as slider-ticks and spinners. /// - public static double CalculateSliderNestedScorePerObject(IBeatmap beatmap, int objectCount) + public static double CalculateNestedScorePerObject(IBeatmap beatmap, int objectCount) { const double big_tick_score = 30; const double small_tick_score = 10; @@ -29,9 +29,59 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Utils int amountOfSmallTicks = sliders.Select(s => s.NestedHitObjects.Count(nho => nho is SliderTick)).Sum(); - double totalScore = amountOfBigTicks * big_tick_score + amountOfSmallTicks * small_tick_score; + double sliderScore = amountOfBigTicks * big_tick_score + amountOfSmallTicks * small_tick_score; - return totalScore / objectCount; + double spinnerScore = 0; + + foreach (var spinner in beatmap.HitObjects.OfType()) + { + spinnerScore += calculateSpinnerScore(spinner); + } + + return (sliderScore + spinnerScore) / objectCount; + } + + /// + /// Logic borrowed from for basic score calculations. + /// + private static double calculateSpinnerScore(Spinner spinner) + { + const int spin_score = 100; + const int bonus_spin_score = 1000; + + // The spinner object applies a lenience because gameplay mechanics differ from osu-stable. + // We'll redo the calculations to match osu-stable here... + const double maximum_rotations_per_second = 477.0 / 60; + + // Normally, this value depends on the final overall difficulty. For simplicity, we'll only consider the worst case that maximises bonus score. + // As we're primarily concerned with computing the maximum theoretical final score, + // this will have the final effect of slightly underestimating bonus score achieved on stable when converting from score V1. + const double minimum_rotations_per_second = 3; + + double secondsDuration = spinner.Duration / 1000; + + // The total amount of half spins possible for the entire spinner. + int totalHalfSpinsPossible = (int)(secondsDuration * maximum_rotations_per_second * 2); + // The amount of half spins that are required to successfully complete the spinner (i.e. get a 300). + int halfSpinsRequiredForCompletion = (int)(secondsDuration * minimum_rotations_per_second); + // To be able to receive bonus points, the spinner must be rotated another 1.5 times. + int halfSpinsRequiredBeforeBonus = halfSpinsRequiredForCompletion + 3; + + long score = 0; + + int fullSpins = (totalHalfSpinsPossible / 2); + + // Normal spin score + score += spin_score * fullSpins; + + int bonusSpins = (totalHalfSpinsPossible - halfSpinsRequiredBeforeBonus) / 2; + + // Reduce amount of bonus spins because we want to represent the more average case, rather than the best one. + bonusSpins = Math.Max(0, bonusSpins - fullSpins / 2); + + score += bonus_spin_score * bonusSpins; + + return score; } public static int CalculateDifficultyPeppyStars(IBeatmap beatmap) diff --git a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs index e01ce6fde5..5e792d1b75 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs @@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Difficulty protected const int ATTRIB_ID_AIM_DIFFICULT_SLIDER_COUNT = 31; protected const int ATTRIB_ID_AIM_TOP_WEIGHTED_SLIDER_FACTOR = 33; protected const int ATTRIB_ID_SPEED_TOP_WEIGHTED_SLIDER_FACTOR = 35; - protected const int ATTRIB_ID_SLIDER_NESTED_SCORE_PER_OBJECT = 37; + protected const int ATTRIB_ID_NESTED_SCORE_PER_OBJECT = 37; protected const int ATTRIB_ID_LEGACY_SCORE_BASE_MULTIPLIER = 39; protected const int ATTRIB_ID_MAXIMUM_LEGACY_COMBO_SCORE = 41; From ace74824b8f0a8fcc7a625538f51530a3bc0a9d2 Mon Sep 17 00:00:00 2001 From: Jay Lawton Date: Fri, 23 May 2025 21:57:37 +1000 Subject: [PATCH 18/78] Add a `consistency` factor to osu!taiko diffcalc (#33233) * add consistency attribute * write attributes to json for serialisation * comment change * fix json, add mechanical difficulty * write new attributes to database --------- Co-authored-by: James Wilson --- .../Difficulty/TaikoDifficultyAttributes.cs | 25 +++++++++++-- .../Difficulty/TaikoDifficultyCalculator.cs | 37 ++++++++++++++++--- .../Difficulty/DifficultyAttributes.cs | 4 ++ 3 files changed, 57 insertions(+), 9 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs index b8051054e7..eacf843487 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs @@ -10,14 +10,23 @@ namespace osu.Game.Rulesets.Taiko.Difficulty { public class TaikoDifficultyAttributes : DifficultyAttributes { + /// + /// The difficulty corresponding to the mechanical skills in osu!taiko. + /// This includes colour and stamina combined. + /// + [JsonProperty("mechanical_difficulty")] + public double MechanicalDifficulty { get; set; } + /// /// The difficulty corresponding to the rhythm skill. /// + [JsonProperty("rhythm_difficulty")] public double RhythmDifficulty { get; set; } /// /// The difficulty corresponding to the reading skill. /// + [JsonProperty("reading_difficulty")] public double ReadingDifficulty { get; set; } /// @@ -36,9 +45,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty [JsonProperty("mono_stamina_factor")] public double MonoStaminaFactor { get; set; } - public double RhythmTopStrains { get; set; } - - public double ColourTopStrains { get; set; } + /// + /// The factor corresponding to the consistency of a map. + /// + [JsonProperty("consistency_factor")] + public double ConsistencyFactor { get; set; } public double StaminaTopStrains { get; set; } @@ -48,7 +59,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty yield return v; yield return (ATTRIB_ID_DIFFICULTY, StarRating); + yield return (ATTRIB_ID_MECHANICAL_DIFFICULTY, MechanicalDifficulty); + yield return (ATTRIB_ID_RHYTHM_DIFFICULTY, RhythmDifficulty); + yield return (ATTRIB_ID_READING_DIFFICULTY, ReadingDifficulty); yield return (ATTRIB_ID_MONO_STAMINA_FACTOR, MonoStaminaFactor); + yield return (ATTRIB_ID_CONSISTENCY_FACTOR, ConsistencyFactor); } public override void FromDatabaseAttributes(IReadOnlyDictionary values, IBeatmapOnlineInfo onlineInfo) @@ -56,7 +71,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty base.FromDatabaseAttributes(values, onlineInfo); StarRating = values[ATTRIB_ID_DIFFICULTY]; + MechanicalDifficulty = values[ATTRIB_ID_MECHANICAL_DIFFICULTY]; + RhythmDifficulty = values[ATTRIB_ID_RHYTHM_DIFFICULTY]; + ReadingDifficulty = values[ATTRIB_ID_READING_DIFFICULTY]; MonoStaminaFactor = values[ATTRIB_ID_MONO_STAMINA_FACTOR]; + ConsistencyFactor = values[ATTRIB_ID_CONSISTENCY_FACTOR]; } } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index 83b02f0b30..0b9ef6a27f 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -115,8 +115,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty double monoStaminaSkill = singleColourStamina.DifficultyValue() * stamina_skill_multiplier; double monoStaminaFactor = staminaSkill == 0 ? 1 : Math.Pow(monoStaminaSkill / staminaSkill, 5); - double colourDifficultStrains = colour.CountTopWeightedStrains(); - double rhythmDifficultStrains = rhythm.CountTopWeightedStrains(); double staminaDifficultStrains = stamina.CountTopWeightedStrains(); // As we don't have pattern integration in osu!taiko, we apply the other two skills relative to rhythm. @@ -126,7 +124,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty + Math.Min(Math.Max((staminaDifficultStrains - 1000) / 3700, 0), 0.15) + Math.Min(Math.Max((staminaSkill - 7.0) / 1.0, 0), 0.05); - double combinedRating = combinedDifficultyValue(rhythm, reading, colour, stamina, isRelax, isConvert); + double combinedRating = combinedDifficultyValue(rhythm, reading, colour, stamina, isRelax, isConvert, out double consistencyFactor); double starRating = rescale(combinedRating * 1.4); // Calculate proportional contribution of each skill to the combinedRating. @@ -136,19 +134,20 @@ namespace osu.Game.Rulesets.Taiko.Difficulty double readingDifficulty = readingSkill * skillRating; double colourDifficulty = colourSkill * skillRating; double staminaDifficulty = staminaSkill * skillRating; + double mechanicalDifficulty = colourDifficulty + staminaDifficulty; // Mechanical difficulty is the sum of colour and stamina difficulties. TaikoDifficultyAttributes attributes = new TaikoDifficultyAttributes { StarRating = starRating, Mods = mods, + MechanicalDifficulty = mechanicalDifficulty, RhythmDifficulty = rhythmDifficulty, ReadingDifficulty = readingDifficulty, ColourDifficulty = colourDifficulty, StaminaDifficulty = staminaDifficulty, MonoStaminaFactor = monoStaminaFactor, - RhythmTopStrains = rhythmDifficultStrains, - ColourTopStrains = colourDifficultStrains, StaminaTopStrains = staminaDifficultStrains, + ConsistencyFactor = consistencyFactor, MaxCombo = beatmap.GetMaxCombo(), }; @@ -162,7 +161,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty /// For each section, the peak strains of all separate skills are combined into a single peak strain for the section. /// The resulting partial rating of the beatmap is a weighted sum of the combined peaks (higher peaks are weighted more). /// - private double combinedDifficultyValue(Rhythm rhythm, Reading reading, Colour colour, Stamina stamina, bool isRelax, bool isConvert) + private double combinedDifficultyValue(Rhythm rhythm, Reading reading, Colour colour, Stamina stamina, bool isRelax, bool isConvert, out double consistencyFactor) { List peaks = new List(); @@ -196,9 +195,35 @@ namespace osu.Game.Rulesets.Taiko.Difficulty weight *= 0.9; } + consistencyFactor = calculateConsistencyFactor(peaks); + return difficulty; } + /// + /// Calculates a consistency factor based on how 'spiked' the strain peaks are. + /// Higher values indicate more consistent difficulty, lower values indicate diff-spike heavy maps. + /// + private double calculateConsistencyFactor(List peaks) + { + // If there are too few sections in a map, assume it is consistent. + if (peaks.Count < 3) + return 1.0; + + List sorted = peaks.OrderDescending().ToList(); + + double topPeak = sorted[0]; + double secondTopPeak = sorted.Count > 1 ? sorted[1] : topPeak; + + // Compute the average of the middle 50% of strain values. + double midAvg = sorted.Skip(sorted.Count / 4).Take(sorted.Count / 2).Average(); + + // A higher ratio means the top sections are much harder than the average, indicating inconsistency. + double spikeSeverity = (topPeak + secondTopPeak) / 2.0 / midAvg; + + return 1.0 / spikeSeverity; + } + /// /// Applies a final re-scaling of the star rating. /// diff --git a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs index 5e792d1b75..20cac77f8b 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs @@ -31,6 +31,10 @@ namespace osu.Game.Rulesets.Difficulty protected const int ATTRIB_ID_NESTED_SCORE_PER_OBJECT = 37; protected const int ATTRIB_ID_LEGACY_SCORE_BASE_MULTIPLIER = 39; protected const int ATTRIB_ID_MAXIMUM_LEGACY_COMBO_SCORE = 41; + protected const int ATTRIB_ID_MECHANICAL_DIFFICULTY = 43; + protected const int ATTRIB_ID_RHYTHM_DIFFICULTY = 45; + protected const int ATTRIB_ID_READING_DIFFICULTY = 47; + protected const int ATTRIB_ID_CONSISTENCY_FACTOR = 49; /// /// The mods which were applied to the beatmap. From 01d9c526d9342943771da83bb0bbe3d8d011b28c Mon Sep 17 00:00:00 2001 From: Givikap120 <89256026+Givikap120@users.noreply.github.com> Date: Mon, 26 May 2025 13:16:48 +0300 Subject: [PATCH 19/78] Rebalance HD bonus (#33237) * initial commit * changed HD curve * removed AR variable * update for new rework * nerf HD acc bonus for AR>10 * add another HD nerf for AR>10 * Update OsuDifficultyCalculator.cs * fix speed part being missing * Update OsuDifficultyCalculator.cs * rework to difficulty-based high AR nerf * move TC back to perfcalc * fix nvicka * fix comment * use utils function instead of manual one * Clean up * Use "visibility" term instead * Store `mechanicalDifficultyRating` field * Rename `isFullyHidden` to `isAlwaysPartiallyVisible` and clarify intent * Remove redundant comment * Add `calculateDifficultyRating` method --------- Co-authored-by: James Wilson --- .../Difficulty/OsuDifficultyCalculator.cs | 98 ++++++++++++++++--- .../Difficulty/OsuPerformanceCalculator.cs | 11 ++- 2 files changed, 90 insertions(+), 19 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index dd9d4d4c23..c048fedd02 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -8,6 +8,7 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; +using osu.Game.Rulesets.Difficulty.Utils; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Difficulty.Skills; @@ -27,6 +28,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty public override int Version => 20250306; + private double mechanicalDifficultyRating; + public OsuDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap) : base(ruleset, beatmap) { @@ -42,6 +45,30 @@ namespace osu.Game.Rulesets.Osu.Difficulty return multiplier; } + /// + /// Calculates a visibility bonus that is applicable to Hidden and Traceable. + /// + public static double CalculateVisibilityBonus(Mod[] mods, double approachRate, double visibilityFactor = 1) + { + // NOTE: TC's effect is only noticeable in performance calculations until lazer mods are accounted for server-side. + bool isAlwaysPartiallyVisible = mods.OfType().Any(m => !m.OnlyFadeApproachCircles.Value) || mods.OfType().Any(); + + // Start from normal curve, rewarding lower AR up to AR5 + double readingBonus = 0.04 * (12.0 - Math.Max(approachRate, 5)); + + readingBonus *= visibilityFactor; + + // For AR up to 0 - reduce reward for very low ARs when object is visible + if (approachRate < 5) + readingBonus += (isAlwaysPartiallyVisible ? 0.04 : 0.03) * (5.0 - Math.Max(approachRate, 0)); + + // Starting from AR0 - cap values so they won't grow to infinity + if (approachRate < 0) + readingBonus += (isAlwaysPartiallyVisible ? 0.1 : 0.075) * (1 - Math.Pow(1.5, approachRate)); + + return readingBonus; + } + protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) { if (beatmap.HitObjects.Count == 0) @@ -85,9 +112,15 @@ namespace osu.Game.Rulesets.Osu.Difficulty double drainRate = beatmap.Difficulty.DrainRate; - double aimRating = computeAimRating(aim.DifficultyValue(), mods, totalHits, approachRate, overallDifficulty); - double aimRatingNoSliders = computeAimRating(aimWithoutSliders.DifficultyValue(), mods, totalHits, approachRate, overallDifficulty); - double speedRating = computeSpeedRating(speed.DifficultyValue(), mods, totalHits, approachRate, overallDifficulty); + double aimDifficultyValue = aim.DifficultyValue(); + double aimNoSlidersDifficultyValue = aimWithoutSliders.DifficultyValue(); + double speedDifficultyValue = speed.DifficultyValue(); + + mechanicalDifficultyRating = calculateMechanicalDifficultyRating(aimDifficultyValue, speedDifficultyValue); + + double aimRating = computeAimRating(aimDifficultyValue, mods, totalHits, approachRate, overallDifficulty); + double aimRatingNoSliders = computeAimRating(aimNoSlidersDifficultyValue, mods, totalHits, approachRate, overallDifficulty); + double speedRating = computeSpeedRating(speedDifficultyValue, mods, totalHits, approachRate, overallDifficulty); double flashlightRating = 0.0; @@ -108,10 +141,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty ); double multiplier = CalculateDifficultyMultiplier(mods, totalHits, spinnerCount); - - double starRating = basePerformance > 0.00001 - ? Math.Cbrt(multiplier) * star_rating_multiplier * (Math.Cbrt(100000 / Math.Pow(2, 1 / 1.1) * basePerformance) + 4) - : 0; + double starRating = calculateStarRating(basePerformance, multiplier); double sliderNestedScorePerObject = LegacyScoreUtils.CalculateNestedScorePerObject(beatmap, totalHits); double legacyScoreBaseMultiplier = LegacyScoreUtils.CalculateDifficultyPeppyStars(beatmap); @@ -151,7 +181,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (mods.Any(m => m is OsuModAutopilot)) return 0; - double aimRating = Math.Sqrt(aimDifficultyValue) * difficulty_multiplier; + double aimRating = calculateDifficultyRating(aimDifficultyValue); if (mods.Any(m => m is OsuModTouchDevice)) aimRating = Math.Pow(aimRating, 0.8); @@ -183,8 +213,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (mods.Any(m => m is OsuModHidden)) { - // We want to give more reward for lower AR when it comes to aim and HD. This nerfs high AR and buffs lower AR. - ratingMultiplier *= 1.0 + 0.04 * (12.0 - approachRate); + double visibilityFactor = calculateAimVisibilityFactor(approachRate); + ratingMultiplier *= 1.0 + CalculateVisibilityBonus(mods, approachRate, visibilityFactor); } // It is important to consider accuracy difficulty when scaling with accuracy. @@ -198,7 +228,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (mods.Any(m => m is OsuModRelax)) return 0; - double speedRating = Math.Sqrt(speedDifficultyValue) * difficulty_multiplier; + double speedRating = calculateDifficultyRating(speedDifficultyValue); if (mods.Any(m => m is OsuModAutopilot)) speedRating *= 0.5; @@ -226,8 +256,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (mods.Any(m => m is OsuModHidden)) { - // We want to give more reward for lower AR when it comes to aim and HD. This nerfs high AR and buffs lower AR. - ratingMultiplier *= 1.0 + 0.04 * (12.0 - approachRate); + double visibilityFactor = calculateSpeedVisibilityFactor(approachRate); + ratingMultiplier *= 1.0 + CalculateVisibilityBonus(mods, approachRate, visibilityFactor); } ratingMultiplier *= 0.95 + Math.Pow(Math.Max(0, overallDifficulty), 2) / 750; @@ -240,7 +270,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (!mods.Any(m => m is OsuModFlashlight)) return 0; - double flashlightRating = Math.Sqrt(flashlightDifficultyValue) * difficulty_multiplier; + double flashlightRating = calculateDifficultyRating(flashlightDifficultyValue); if (mods.Any(m => m is OsuModTouchDevice)) flashlightRating = Math.Pow(flashlightRating, 0.8); @@ -268,6 +298,46 @@ namespace osu.Game.Rulesets.Osu.Difficulty return flashlightRating * Math.Sqrt(ratingMultiplier); } + private double calculateAimVisibilityFactor(double approachRate) + { + const double ar_factor_end_point = 11.5; + + double mechanicalDifficultyFactor = DifficultyCalculationUtils.ReverseLerp(mechanicalDifficultyRating, 5, 10); + double arFactorStartingPoint = double.Lerp(9, 10.33, mechanicalDifficultyFactor); + + return DifficultyCalculationUtils.ReverseLerp(approachRate, ar_factor_end_point, arFactorStartingPoint); + } + + private double calculateSpeedVisibilityFactor(double approachRate) + { + const double ar_factor_end_point = 11.5; + + double mechanicalDifficultyFactor = DifficultyCalculationUtils.ReverseLerp(mechanicalDifficultyRating, 5, 10); + double arFactorStartingPoint = double.Lerp(10, 10.33, mechanicalDifficultyFactor); + + return DifficultyCalculationUtils.ReverseLerp(approachRate, ar_factor_end_point, arFactorStartingPoint); + } + + private static double calculateMechanicalDifficultyRating(double aimDifficultyValue, double speedDifficultyValue) + { + double aimValue = OsuStrainSkill.DifficultyToPerformance(calculateDifficultyRating(aimDifficultyValue)); + double speedValue = OsuStrainSkill.DifficultyToPerformance(calculateDifficultyRating(speedDifficultyValue)); + + double totalValue = Math.Pow(Math.Pow(aimValue, 1.1) + Math.Pow(speedValue, 1.1), 1 / 1.1); + + return calculateStarRating(totalValue, performance_base_multiplier); + } + + private static double calculateStarRating(double basePerformance, double multiplier) + { + if (basePerformance <= 0.00001) + return 0; + + return Math.Cbrt(multiplier) * star_rating_multiplier * (Math.Cbrt(100000 / Math.Pow(2, 1 / 1.1) * basePerformance) + 4); + } + + private static double calculateDifficultyRating(double difficultyValue) => Math.Sqrt(difficultyValue) * difficulty_multiplier; + protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) { List objects = new List(); diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 8802c4a1c2..e5e42e6d4f 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -210,8 +210,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty aimValue *= 1.3 + (totalHits * (0.0016 / (1 + 2 * effectiveMissCount)) * Math.Pow(accuracy, 16)) * (1 - 0.003 * attributes.DrainRate * attributes.DrainRate); else if (score.Mods.Any(m => m is OsuModTraceable)) { - // We want to give more reward for lower AR when it comes to aim and HD. This nerfs high AR and buffs lower AR. - aimValue *= 1.0 + 0.04 * (12.0 - approachRate); + aimValue *= 1.0 + OsuDifficultyCalculator.CalculateVisibilityBonus(score.Mods, approachRate); } aimValue *= accuracy; @@ -244,8 +243,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty } else if (score.Mods.Any(m => m is OsuModTraceable)) { - // We want to give more reward for lower AR when it comes to aim and HD. This nerfs high AR and buffs lower AR. - speedValue *= 1.0 + 0.04 * (12.0 - approachRate); + speedValue *= 1.0 + OsuDifficultyCalculator.CalculateVisibilityBonus(score.Mods, approachRate); } double speedHighDeviationMultiplier = calculateSpeedHighDeviationNerf(attributes); @@ -295,7 +293,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (score.Mods.Any(m => m is OsuModBlinds)) accuracyValue *= 1.14; else if (score.Mods.Any(m => m is OsuModHidden || m is OsuModTraceable)) - accuracyValue *= 1.08; + { + // Decrease bonus for AR > 10 + accuracyValue *= 1 + 0.08 * Math.Clamp((11.5 - approachRate) / (11.5 - 10), 0, 1); + } if (score.Mods.Any(m => m is OsuModFlashlight)) accuracyValue *= 1.02; From 63654ad1e0262f3daf14efb9ea611117aebe0404 Mon Sep 17 00:00:00 2001 From: Givikap120 <89256026+Givikap120@users.noreply.github.com> Date: Wed, 28 May 2025 15:59:23 +0300 Subject: [PATCH 20/78] Replace HD acc scaling adjust with reverse lerp util (#33271) --- osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index e5e42e6d4f..7ef3fc5407 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -295,7 +295,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty else if (score.Mods.Any(m => m is OsuModHidden || m is OsuModTraceable)) { // Decrease bonus for AR > 10 - accuracyValue *= 1 + 0.08 * Math.Clamp((11.5 - approachRate) / (11.5 - 10), 0, 1); + accuracyValue *= 1 + 0.08 * DifficultyCalculationUtils.ReverseLerp(approachRate, 11.5, 10); } if (score.Mods.Any(m => m is OsuModFlashlight)) From 366f2469efcddd825baef8c41e03099bab9e0acb Mon Sep 17 00:00:00 2001 From: Givikap120 <89256026+Givikap120@users.noreply.github.com> Date: Tue, 3 Jun 2025 11:29:16 +0300 Subject: [PATCH 21/78] Fix incorrect limit for sliderbreak estimation (#33110) * fix incorrect clamp * Add inline comment to explain `possibleBreaks` calculation * move limit to aim and speed functions * fix negative okMehAdjustment * fix cases where lazer effective misscount gets reduced * Simplify scope of changes * Correct variable name --------- Co-authored-by: James Wilson --- .../Difficulty/OsuPerformanceCalculator.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 7ef3fc5407..ac9ace2a24 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -202,7 +202,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (effectiveMissCount > 0) { aimEstimatedSliderBreaks = calculateEstimatedSliderBreaks(attributes.AimTopWeightedSliderFactor, attributes); - aimValue *= calculateMissPenalty(effectiveMissCount + aimEstimatedSliderBreaks, attributes.AimDifficultStrainCount); + + double relevantMissCount = Math.Min(effectiveMissCount + aimEstimatedSliderBreaks, totalImperfectHits + countSliderTickMiss); + + aimValue *= calculateMissPenalty(relevantMissCount, attributes.AimDifficultStrainCount); } // TC bonuses are excluded when blinds is present as the increased visual difficulty is unimportant when notes cannot be seen. @@ -232,7 +235,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (effectiveMissCount > 0) { speedEstimatedSliderBreaks = calculateEstimatedSliderBreaks(attributes.SpeedTopWeightedSliderFactor, attributes); - speedValue *= calculateMissPenalty(effectiveMissCount + speedEstimatedSliderBreaks, attributes.SpeedDifficultStrainCount); + + double relevantMissCount = Math.Min(effectiveMissCount + speedEstimatedSliderBreaks, totalImperfectHits + countSliderTickMiss); + + speedValue *= calculateMissPenalty(relevantMissCount, attributes.SpeedDifficultStrainCount); } // TC bonuses are excluded when blinds is present as the increased visual difficulty is unimportant when notes cannot be seen. @@ -364,7 +370,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty double missedComboPercent = 1.0 - (double)scoreMaxCombo / attributes.MaxCombo; double estimatedSliderBreaks = Math.Min(countOk, effectiveMissCount * topWeightedSliderFactor); - // scores with more oks are more likely to have slider breaks + // Scores with more Oks are more likely to have slider breaks. double okAdjustment = ((countOk - estimatedSliderBreaks) + 0.5) / countOk; // There is a low probability of extra slider breaks on effective miss counts close to 1, as score based calculations are good at indicating if only a single break occurred. From b982c3cd20c67264c6d38f6b518349af9e8e5e99 Mon Sep 17 00:00:00 2001 From: Eloise Date: Tue, 3 Jun 2025 14:47:42 +0100 Subject: [PATCH 22/78] Remove stamina skill buff from strain length bonus (#33380) Co-authored-by: James Wilson --- .../Difficulty/TaikoDifficultyCalculator.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index 0b9ef6a27f..9e265a3cc6 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -120,9 +120,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty // As we don't have pattern integration in osu!taiko, we apply the other two skills relative to rhythm. patternMultiplier = Math.Pow(staminaSkill * colourSkill, 0.10); - strainLengthBonus = 1 - + Math.Min(Math.Max((staminaDifficultStrains - 1000) / 3700, 0), 0.15) - + Math.Min(Math.Max((staminaSkill - 7.0) / 1.0, 0), 0.05); + strainLengthBonus = 1 + 0.15 * DifficultyCalculationUtils.ReverseLerp(staminaDifficultStrains, 1000, 1555); double combinedRating = combinedDifficultyValue(rhythm, reading, colour, stamina, isRelax, isConvert, out double consistencyFactor); double starRating = rescale(combinedRating * 1.4); From 6a9aeda5d4c9430e2e71592873c45194c20dcbb3 Mon Sep 17 00:00:00 2001 From: Eloise Date: Fri, 6 Jun 2025 14:46:33 +0100 Subject: [PATCH 23/78] Remove multipliers nerfing ez (#33415) --- .../Difficulty/TaikoPerformanceCalculator.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index 3c4e1164f1..c0929ef41e 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -68,9 +68,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty if (score.Mods.Any(m => m is ModHidden) && !isConvert) multiplier *= 1.075; - if (score.Mods.Any(m => m is ModEasy)) - multiplier *= 0.950; - double difficultyValue = computeDifficultyValue(score, taikoAttributes); double accuracyValue = computeAccuracyValue(score, taikoAttributes, isConvert); double totalValue = @@ -101,9 +98,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty difficultyValue *= Math.Pow(0.986, effectiveMissCount); - if (score.Mods.Any(m => m is ModEasy)) - difficultyValue *= 0.90; - if (score.Mods.Any(m => m is ModHidden)) difficultyValue *= 1.025; From 642b938358d85eba4d8d1c55a6c70ab21e69a6ae Mon Sep 17 00:00:00 2001 From: Wulpey Date: Sat, 7 Jun 2025 17:17:46 +0300 Subject: [PATCH 24/78] Reduce combo scaling for osu!catch (#33417) * Reduce combo scaling for osu!catch This is a conservative reduction, a middle point between the current scaling and the CSR proposals. * Reduce osu!catch combo scaling further 0.45 makes little difference so let's reduce it a bit more. --------- Co-authored-by: James Wilson --- .../Difficulty/CatchPerformanceCalculator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Catch/Difficulty/CatchPerformanceCalculator.cs b/osu.Game.Rulesets.Catch/Difficulty/CatchPerformanceCalculator.cs index 4b38cfac50..4b8bcb435c 100644 --- a/osu.Game.Rulesets.Catch/Difficulty/CatchPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Catch/Difficulty/CatchPerformanceCalculator.cs @@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Catch.Difficulty // Combo scaling if (catchAttributes.MaxCombo > 0) - value *= Math.Min(Math.Pow(score.MaxCombo, 0.8) / Math.Pow(catchAttributes.MaxCombo, 0.8), 1.0); + value *= Math.Min(Math.Pow(score.MaxCombo, 0.35) / Math.Pow(catchAttributes.MaxCombo, 0.35), 1.0); var difficulty = score.BeatmapInfo!.Difficulty.Clone(); From 6ae8a6838958672bcd6328c0b738787bbde9d29b Mon Sep 17 00:00:00 2001 From: Eloise Date: Sun, 8 Jun 2025 09:48:28 +0100 Subject: [PATCH 25/78] osu!taiko simplify pp summing and make performance attributes accurate (#33500) * Change pp summing and adjust multipliers * Add back convert consideration for hidden * And the other one whoops --------- Co-authored-by: StanR --- .../Difficulty/TaikoPerformanceCalculator.cs | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index c0929ef41e..20e2f955df 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -63,18 +63,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty // Converts are detected and omitted from mod-specific bonuses due to the scope of current difficulty calculation. bool isConvert = score.BeatmapInfo!.Ruleset.OnlineID != 1; - double multiplier = 1.13; - - if (score.Mods.Any(m => m is ModHidden) && !isConvert) - multiplier *= 1.075; - - double difficultyValue = computeDifficultyValue(score, taikoAttributes); - double accuracyValue = computeAccuracyValue(score, taikoAttributes, isConvert); - double totalValue = - Math.Pow( - Math.Pow(difficultyValue, 1.1) + - Math.Pow(accuracyValue, 1.1), 1.0 / 1.1 - ) * multiplier; + double difficultyValue = computeDifficultyValue(score, taikoAttributes, isConvert) * 1.08; + double accuracyValue = computeAccuracyValue(score, taikoAttributes, isConvert) * 1.1; return new TaikoPerformanceAttributes { @@ -82,11 +72,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty Accuracy = accuracyValue, EffectiveMissCount = effectiveMissCount, EstimatedUnstableRate = estimatedUnstableRate, - Total = totalValue + Total = difficultyValue + accuracyValue }; } - private double computeDifficultyValue(ScoreInfo score, TaikoDifficultyAttributes attributes) + private double computeDifficultyValue(ScoreInfo score, TaikoDifficultyAttributes attributes, bool isConvert) { double baseDifficulty = 5 * Math.Max(1.0, attributes.StarRating / 0.110) - 4.0; double difficultyValue = Math.Min(Math.Pow(baseDifficulty, 3) / 69052.51, Math.Pow(baseDifficulty, 2.25) / 1250.0); @@ -99,7 +89,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty difficultyValue *= Math.Pow(0.986, effectiveMissCount); if (score.Mods.Any(m => m is ModHidden)) - difficultyValue *= 1.025; + difficultyValue *= (isConvert) ? 1.025 : 1.1; if (score.Mods.Any(m => m is ModFlashlight)) difficultyValue *= Math.Max(1, 1.050 - Math.Min(attributes.MonoStaminaFactor / 50, 1) * lengthBonus); @@ -121,6 +111,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty double accuracyValue = Math.Pow(70 / estimatedUnstableRate.Value, 1.1) * Math.Pow(attributes.StarRating, 0.4) * 100.0; + if (score.Mods.Any(m => m is ModHidden) && !isConvert) + accuracyValue *= 1.075; + double lengthBonus = Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3)); // Slight HDFL Bonus for accuracy. A clamp is used to prevent against negative values. From c4b07413b1b5983ca05081d44679859d75eaccef Mon Sep 17 00:00:00 2001 From: Natelytle <92956514+Natelytle@users.noreply.github.com> Date: Sun, 8 Jun 2025 18:41:13 -0400 Subject: [PATCH 26/78] Refactor and re-comment osu! standard deviation calculations (#33218) * Refactor * Fix typo * Prevent double.PositiveInfinity from occuring * Fix leftover code branch * Fix some idiot putting Math.Max instead of Math.Min * Address NaN values --------- Co-authored-by: James Wilson --- .../Difficulty/OsuPerformanceCalculator.cs | 53 +++++++++---------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index ac9ace2a24..272fe9bb65 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Extensions.IEnumerableExtensions; -using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty.Utils; using osu.Game.Rulesets.Mods; @@ -398,7 +397,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty double relevantCountOk = Math.Min(countOk, speedNoteCount - relevantCountMiss - relevantCountMeh); double relevantCountGreat = Math.Max(0, speedNoteCount - relevantCountMiss - relevantCountMeh - relevantCountOk); - return calculateDeviation(attributes, relevantCountGreat, relevantCountOk, relevantCountMeh, relevantCountMiss); + return calculateDeviation(relevantCountGreat, relevantCountOk, relevantCountMeh); } /// @@ -407,45 +406,45 @@ namespace osu.Game.Rulesets.Osu.Difficulty /// will always return the same deviation. Misses are ignored because they are usually due to misaiming. /// Greats and oks are assumed to follow a normal distribution, whereas mehs are assumed to follow a uniform distribution. /// - private double? calculateDeviation(OsuDifficultyAttributes attributes, double relevantCountGreat, double relevantCountOk, double relevantCountMeh, double relevantCountMiss) + private double? calculateDeviation(double relevantCountGreat, double relevantCountOk, double relevantCountMeh) { if (relevantCountGreat + relevantCountOk + relevantCountMeh <= 0) return null; - double objectCount = relevantCountGreat + relevantCountOk + relevantCountMeh + relevantCountMiss; - - // The probability that a player hits a circle is unknown, but we can estimate it to be - // the number of greats on circles divided by the number of circles, and then add one - // to the number of circles as a bias correction. - double n = Math.Max(1, objectCount - relevantCountMiss - relevantCountMeh); - const double z = 2.32634787404; // 99% critical value for the normal distribution (one-tailed). - - // Proportion of greats hit on circles, ignoring misses and 50s. + // The sample proportion of successful hits. + double n = Math.Max(1, relevantCountGreat + relevantCountOk); double p = relevantCountGreat / n; - // We can be 99% confident that p is at least this value. - double pLowerBound = (n * p + z * z / 2) / (n + z * z) - z / (n + z * z) * Math.Sqrt(n * p * (1 - p) + z * z / 4); + // 99% critical value for the normal distribution (one-tailed). + const double z = 2.32634787404; - // Compute the deviation assuming greats and oks are normally distributed, and mehs are uniformly distributed. - // Begin with greats and oks first. Ignoring mehs, we can be 99% confident that the deviation is not higher than: - double deviation = greatHitWindow / (Math.Sqrt(2) * DifficultyCalculationUtils.ErfInv(pLowerBound)); + // We can be 99% confident that the population proportion is at least this value. + double pLowerBound = Math.Min(p, (n * p + z * z / 2) / (n + z * z) - z / (n + z * z) * Math.Sqrt(n * p * (1 - p) + z * z / 4)); - double randomValue = Math.Sqrt(2 / Math.PI) * okHitWindow * Math.Exp(-0.5 * Math.Pow(okHitWindow / deviation, 2)) - / (deviation * DifficultyCalculationUtils.Erf(okHitWindow / (Math.Sqrt(2) * deviation))); + double deviation; - deviation *= Math.Sqrt(1 - randomValue); + // Tested max precision for the deviation calculation. + if (pLowerBound > 1e-06) + { + // Compute deviation assuming greats and oks are normally distributed. + deviation = greatHitWindow / (Math.Sqrt(2) * DifficultyCalculationUtils.ErfInv(pLowerBound)); - // Value deviation approach as greatCount approaches 0 - double limitValue = okHitWindow / Math.Sqrt(3); + // Subtract the deviation provided by tails that land outside the ok hit window from the deviation computed above. + // This is equivalent to calculating the deviation of a normal distribution truncated at +-okHitWindow. + double okHitWindowTailAmount = Math.Sqrt(2 / Math.PI) * okHitWindow * Math.Exp(-0.5 * Math.Pow(okHitWindow / deviation, 2)) + / (deviation * DifficultyCalculationUtils.Erf(okHitWindow / (Math.Sqrt(2) * deviation))); - // If precision is not enough to compute true deviation - use limit value - if (Precision.AlmostEquals(pLowerBound, 0.0) || randomValue >= 1 || deviation > limitValue) - deviation = limitValue; + deviation *= Math.Sqrt(1 - okHitWindowTailAmount); + } + else + { + // A tested limit value for the case of a score only containing oks. + deviation = okHitWindow / Math.Sqrt(3); + } - // Then compute the variance for mehs. + // Compute and add the variance for mehs, assuming that they are uniformly distributed. double mehVariance = (mehHitWindow * mehHitWindow + okHitWindow * mehHitWindow + okHitWindow * okHitWindow) / 3; - // Find the total deviation. deviation = Math.Sqrt(((relevantCountGreat + relevantCountOk) * Math.Pow(deviation, 2) + relevantCountMeh * mehVariance) / (relevantCountGreat + relevantCountOk + relevantCountMeh)); return deviation; From 5df41c08f44196dde01e3e5107a4bcee73cc0b22 Mon Sep 17 00:00:00 2001 From: Eloise Date: Sun, 8 Jun 2025 23:47:26 +0100 Subject: [PATCH 27/78] osu!taiko new miss penalty using consistency factor (#33409) * New formulas for effective miss count and penalty * More elaborate comments * More comment stuff --- .../Difficulty/TaikoPerformanceCalculator.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index 20e2f955df..6deb2fdb04 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -56,9 +56,12 @@ namespace osu.Game.Rulesets.Taiko.Difficulty estimatedUnstableRate = computeDeviationUpperBound() * 10; - // The effectiveMissCount is calculated by gaining a ratio for totalSuccessfulHits and increasing the miss penalty for shorter object counts lower than 1000. - if (totalSuccessfulHits > 0) - effectiveMissCount = Math.Max(1.0, 1000.0 / totalSuccessfulHits) * countMiss; + // Effective miss count is calculated by raising the fraction of hits missed to a power based on the map's consistency factor. + // This is because in less consistently difficult maps, each miss removes more of the map's total difficulty. + effectiveMissCount = totalHits * Math.Pow( + (double)countMiss / totalHits, + Math.Pow(taikoAttributes.ConsistencyFactor, 0.2) + ); // Converts are detected and omitted from mod-specific bonuses due to the scope of current difficulty calculation. bool isConvert = score.BeatmapInfo!.Ruleset.OnlineID != 1; @@ -86,7 +89,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty double lengthBonus = 1 + 0.1 * Math.Min(1.0, totalHits / 1500.0); difficultyValue *= lengthBonus; - difficultyValue *= Math.Pow(0.986, effectiveMissCount); + // Scales miss penalty by the total hits of a map, making misses more punishing on maps with fewer objects. + double missPenalty = Math.Pow(0.5, 30.0 / totalHits); + difficultyValue *= Math.Pow(missPenalty, effectiveMissCount); if (score.Mods.Any(m => m is ModHidden)) difficultyValue *= (isConvert) ? 1.025 : 1.1; From 699fbb1a85eb986f8a4803e67f5e624802a1b7ea Mon Sep 17 00:00:00 2001 From: StanR Date: Mon, 9 Jun 2025 14:02:49 +0300 Subject: [PATCH 28/78] Decouple velocity change bonus from wide angle bonus (#33541) * Decouple velocity change bonus from wide angle bonus * Replace sin with smoothstep * Set multiplier back to 0.75 --------- Co-authored-by: James Wilson --- .../Difficulty/Evaluators/AimEvaluator.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 15ccb8b1f0..7a898ade1c 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -129,7 +129,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators currVelocity = (osuCurrObj.LazyJumpDistance + osuLastObj.TravelDistance) / osuCurrObj.StrainTime; // Scale with ratio of difference compared to 0.5 * max dist. - double distRatio = Math.Pow(Math.Sin(Math.PI / 2 * Math.Abs(prevVelocity - currVelocity) / Math.Max(prevVelocity, currVelocity)), 2); + double distRatio = DifficultyCalculationUtils.Smoothstep(Math.Abs(prevVelocity - currVelocity) / Math.Max(prevVelocity, currVelocity), 0, 1); // Reward for % distance up to 125 / strainTime for overlaps where velocity is still changing. double overlapVelocityBuff = Math.Min(diameter * 1.25 / Math.Min(osuCurrObj.StrainTime, osuLastObj.StrainTime), Math.Abs(prevVelocity - currVelocity)); @@ -147,9 +147,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators } aimStrain += wiggleBonus * wiggle_multiplier; + aimStrain += velocityChangeBonus * velocity_change_multiplier; - // Add in acute angle bonus or wide angle bonus + velocity change bonus, whichever is larger. - aimStrain += Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * wide_angle_multiplier + velocityChangeBonus * velocity_change_multiplier); + // Add in acute angle bonus or wide angle bonus, whichever is larger. + aimStrain += Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * wide_angle_multiplier); // Add in additional slider velocity bonus. if (withSliderTravelDistance) From 7066f3def7beae3e88e8c5cc97b7c4d1fa40e71a Mon Sep 17 00:00:00 2001 From: Eloise Date: Tue, 10 Jun 2025 11:31:11 +0100 Subject: [PATCH 29/78] osu!taiko changes to length bonus using consistency factor (#33582) * Implement new formulas for length bonus * Add comment(s) * Fix up HDFL thing --- .../Difficulty/TaikoPerformanceCalculator.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index 6deb2fdb04..2633218f7d 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -86,7 +86,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty difficultyValue *= 1 + 0.10 * Math.Max(0, attributes.StarRating - 10); - double lengthBonus = 1 + 0.1 * Math.Min(1.0, totalHits / 1500.0); + // Applies a bonus to maps with more total difficulty, calculating this with a map's total hits and consistency factor. + double totalDifficultHits = totalHits * Math.Pow(attributes.ConsistencyFactor, 0.5); + double lengthBonus = 1 + 0.25 * totalDifficultHits / (totalDifficultHits + 4000); difficultyValue *= lengthBonus; // Scales miss penalty by the total hits of a map, making misses more punishing on maps with fewer objects. @@ -119,11 +121,16 @@ namespace osu.Game.Rulesets.Taiko.Difficulty if (score.Mods.Any(m => m is ModHidden) && !isConvert) accuracyValue *= 1.075; - double lengthBonus = Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3)); + // Applies a bonus to maps with more total difficulty, calculating this with a map's total hits and consistency factor. + double totalDifficultHits = totalHits * Math.Pow(attributes.ConsistencyFactor, 0.5); + double lengthBonus = 1 + 0.4 * totalDifficultHits / (totalDifficultHits + 4000); + accuracyValue *= lengthBonus; + + // Applies a bonus to maps with more total memory required with HDFL. + double memoryLengthBonus = Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3)); - // Slight HDFL Bonus for accuracy. A clamp is used to prevent against negative values. if (score.Mods.Any(m => m is ModFlashlight) && score.Mods.Any(m => m is ModHidden) && !isConvert) - accuracyValue *= Math.Max(1.0, 1.05 * lengthBonus); + accuracyValue *= Math.Max(1.0, 1.05 * memoryLengthBonus); return accuracyValue; } From 87023b22ea84c2635c8d52d7bcddcdd394bae473 Mon Sep 17 00:00:00 2001 From: StanR Date: Tue, 10 Jun 2025 14:20:55 +0300 Subject: [PATCH 30/78] Remove wide/wiggle angle bonus rhythm requirements (#31409) * Remove aim angle bonuses angle restrictions * Remove unrelated change * Only apply acute bonus for similar rhythms * Cleanup * Fix incorrect multiplication order * Remove unrelated wide bonus change * Remove redundant check * Award less wide/wiggle bonus for sliders * Balancing --------- Co-authored-by: James Wilson --- .../Difficulty/Evaluators/AimEvaluator.cs | 71 ++++++++++--------- .../Difficulty/Skills/Aim.cs | 2 +- 2 files changed, 38 insertions(+), 35 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 7a898ade1c..828e217455 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -70,54 +70,57 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators double aimStrain = currVelocity; // Start strain with regular velocity. - if (Math.Max(osuCurrObj.StrainTime, osuLastObj.StrainTime) < 1.25 * Math.Min(osuCurrObj.StrainTime, osuLastObj.StrainTime)) // If rhythms are the same. + if (osuCurrObj.Angle != null && osuLastObj.Angle != null) { - if (osuCurrObj.Angle != null && osuLastObj.Angle != null) + double currAngle = osuCurrObj.Angle.Value; + double lastAngle = osuLastObj.Angle.Value; + + // Rewarding angles, take the smaller velocity as base. + double angleBonus = Math.Min(currVelocity, prevVelocity); + + if (Math.Max(osuCurrObj.StrainTime, osuLastObj.StrainTime) < 1.25 * Math.Min(osuCurrObj.StrainTime, osuLastObj.StrainTime)) // If rhythms are the same. { - double currAngle = osuCurrObj.Angle.Value; - double lastAngle = osuLastObj.Angle.Value; - - // Rewarding angles, take the smaller velocity as base. - double angleBonus = Math.Min(currVelocity, prevVelocity); - - wideAngleBonus = calcWideAngleBonus(currAngle); acuteAngleBonus = calcAcuteAngleBonus(currAngle); // Penalize angle repetition. - wideAngleBonus *= 1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), 3)); acuteAngleBonus *= 0.08 + 0.92 * (1 - Math.Min(acuteAngleBonus, Math.Pow(calcAcuteAngleBonus(lastAngle), 3))); - // Apply full wide angle bonus for distance more than one diameter - wideAngleBonus *= angleBonus * DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, 0, diameter); - // Apply acute angle bonus for BPM above 300 1/2 and distance more than one diameter acuteAngleBonus *= angleBonus * DifficultyCalculationUtils.Smootherstep(DifficultyCalculationUtils.MillisecondsToBPM(osuCurrObj.StrainTime, 2), 300, 400) * DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, diameter, diameter * 2); + } - // Apply wiggle bonus for jumps that are [radius, 3*diameter] in distance, with < 110 angle - // https://www.desmos.com/calculator/dp0v0nvowc - wiggleBonus = angleBonus - * DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, radius, diameter) - * Math.Pow(DifficultyCalculationUtils.ReverseLerp(osuCurrObj.LazyJumpDistance, diameter * 3, diameter), 1.8) - * DifficultyCalculationUtils.Smootherstep(currAngle, double.DegreesToRadians(110), double.DegreesToRadians(60)) - * DifficultyCalculationUtils.Smootherstep(osuLastObj.LazyJumpDistance, radius, diameter) - * Math.Pow(DifficultyCalculationUtils.ReverseLerp(osuLastObj.LazyJumpDistance, diameter * 3, diameter), 1.8) - * DifficultyCalculationUtils.Smootherstep(lastAngle, double.DegreesToRadians(110), double.DegreesToRadians(60)); + wideAngleBonus = calcWideAngleBonus(currAngle); - if (osuLast2Obj != null) + // Penalize angle repetition. + wideAngleBonus *= 1 - Math.Min(wideAngleBonus, Math.Pow(calcWideAngleBonus(lastAngle), 3)); + + // Apply full wide angle bonus for distance more than one diameter + wideAngleBonus *= angleBonus * DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, 0, diameter); + + // Apply wiggle bonus for jumps that are [radius, 3*diameter] in distance, with < 110 angle + // https://www.desmos.com/calculator/dp0v0nvowc + wiggleBonus = angleBonus + * DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, radius, diameter) + * Math.Pow(DifficultyCalculationUtils.ReverseLerp(osuCurrObj.LazyJumpDistance, diameter * 3, diameter), 1.8) + * DifficultyCalculationUtils.Smootherstep(currAngle, double.DegreesToRadians(110), double.DegreesToRadians(60)) + * DifficultyCalculationUtils.Smootherstep(osuLastObj.LazyJumpDistance, radius, diameter) + * Math.Pow(DifficultyCalculationUtils.ReverseLerp(osuLastObj.LazyJumpDistance, diameter * 3, diameter), 1.8) + * DifficultyCalculationUtils.Smootherstep(lastAngle, double.DegreesToRadians(110), double.DegreesToRadians(60)); + + if (osuLast2Obj != null) + { + // If objects just go back and forth through a middle point - don't give as much wide bonus + // Use Previous(2) and Previous(0) because angles calculation is done prevprev-prev-curr, so any object's angle's center point is always the previous object + var lastBaseObject = (OsuHitObject)osuLastObj.BaseObject; + var last2BaseObject = (OsuHitObject)osuLast2Obj.BaseObject; + + float distance = (last2BaseObject.StackedPosition - lastBaseObject.StackedPosition).Length; + + if (distance < 1) { - // If objects just go back and forth through a middle point - don't give as much wide bonus - // Use Previous(2) and Previous(0) because angles calculation is done prevprev-prev-curr, so any object's angle's center point is always the previous object - var lastBaseObject = (OsuHitObject)osuLastObj.BaseObject; - var last2BaseObject = (OsuHitObject)osuLast2Obj.BaseObject; - - float distance = (last2BaseObject.StackedPosition - lastBaseObject.StackedPosition).Length; - - if (distance < 1) - { - wideAngleBonus *= 1 - 0.35 * (1 - distance); - } + wideAngleBonus *= 1 - 0.35 * (1 - distance); } } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 633f29d6ff..137113092d 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills private double currentStrain; - private double skillMultiplier => 25.6; + private double skillMultiplier => 25.45; private double strainDecayBase => 0.15; private readonly List sliderStrains = new List(); From 19e9bffc11f026ebff2dc2831668e606c701f71f Mon Sep 17 00:00:00 2001 From: James Wilson Date: Wed, 11 Jun 2025 17:46:46 +0100 Subject: [PATCH 31/78] Q2 osu! PP rebalance (#33640) * Rebalance aim and speed * Rebalance star rating * Attempt further speed balancing * More balancing * More balancing * Buff aim a bit * More speed balancing * Global rebalance * Speed balancing * Global rebalancing * More speed balancing * Buff aim * MORE BALANCING * Revert "Rebalance star rating" This reverts commit f48c7445e12174c65b74edfef863cb3ae3cc29ff. --- osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs | 2 +- osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs | 2 +- osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs | 2 +- osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs | 2 +- osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs | 2 +- osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 828e217455..f8dcdfd5e7 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators public static class AimEvaluator { private const double wide_angle_multiplier = 1.5; - private const double acute_angle_multiplier = 2.6; + private const double acute_angle_multiplier = 2.55; private const double slider_multiplier = 1.35; private const double velocity_change_multiplier = 0.75; private const double wiggle_multiplier = 1.02; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs index d503dd2bcc..a2fcf8f11c 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs @@ -15,7 +15,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators { private const int history_time_max = 5 * 1000; // 5 seconds private const int history_objects_max = 32; - private const double rhythm_overall_multiplier = 0.95; + private const double rhythm_overall_multiplier = 1.0; private const double rhythm_ratio_multiplier = 12.0; /// diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs index ee9b46eecb..8cc0fc209a 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators private const double single_spacing_threshold = OsuDifficultyHitObject.NORMALISED_DIAMETER * 1.25; // 1.25 circles distance between centers private const double min_speed_bonus = 200; // 200 BPM 1/4th private const double speed_balancing_factor = 40; - private const double distance_multiplier = 0.9; + private const double distance_multiplier = 0.8; /// /// Evaluates the difficulty of tapping the current object, based on: diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index c048fedd02..c5d85602c6 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -22,7 +22,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty { public class OsuDifficultyCalculator : DifficultyCalculator { - private const double performance_base_multiplier = 1.15; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things. + private const double performance_base_multiplier = 1.14; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things. private const double difficulty_multiplier = 0.0675; private const double star_rating_multiplier = 0.0265; diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs index 137113092d..5816d27a5e 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Aim.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills private double currentStrain; - private double skillMultiplier => 25.45; + private double skillMultiplier => 26; private double strainDecayBase => 0.15; private readonly List sliderStrains = new List(); diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index 334f763be3..7fd1e044ae 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -18,7 +18,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills /// public class Speed : OsuStrainSkill { - private double skillMultiplier => 1.46; + private double skillMultiplier => 1.47; private double strainDecayBase => 0.3; private double currentStrain; From b783bb70e947c3d2367017cee58747d79a1ffa53 Mon Sep 17 00:00:00 2001 From: Givikap120 <89256026+Givikap120@users.noreply.github.com> Date: Fri, 13 Jun 2025 11:02:31 +0300 Subject: [PATCH 32/78] Optimize rhythm evaluation by replacing curve (#33423) * Update RhythmEvaluator.cs * add smoothstep bell curve * Update osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs Co-authored-by: StanR * Update osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs Co-authored-by: StanR * Rename variables --------- Co-authored-by: StanR Co-authored-by: James Wilson --- .../Difficulty/Evaluators/RhythmEvaluator.cs | 13 ++++++++----- .../Difficulty/Utils/DifficultyCalculationUtils.cs | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs index a2fcf8f11c..c00fa4c23e 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs @@ -68,16 +68,19 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators // calculate how much current delta difference deserves a rhythm bonus // this function is meant to reduce rhythm bonus for deltas that are multiples of each other (i.e 100 and 200) - double deltaDifferenceRatio = Math.Min(prevDelta, currDelta) / Math.Max(prevDelta, currDelta); - double currRatio = 1.0 + rhythm_ratio_multiplier * Math.Min(0.5, Math.Pow(Math.Sin(Math.PI / deltaDifferenceRatio), 2)); + double deltaDifference = Math.Max(prevDelta, currDelta) / Math.Min(prevDelta, currDelta); + + // Take only the fractional part of the value since we're only interested in punishing multiples + double deltaDifferenceFraction = deltaDifference - Math.Truncate(deltaDifference); + + double currRatio = 1.0 + rhythm_ratio_multiplier * Math.Min(0.5, DifficultyCalculationUtils.SmoothstepBellCurve(deltaDifferenceFraction)); // reduce ratio bonus if delta difference is too big - double fraction = Math.Max(prevDelta / currDelta, currDelta / prevDelta); - double fractionMultiplier = Math.Clamp(2.0 - fraction / 8.0, 0.0, 1.0); + double differenceMultiplier = Math.Clamp(2.0 - deltaDifference / 8.0, 0.0, 1.0); double windowPenalty = Math.Min(1, Math.Max(0, Math.Abs(prevDelta - currDelta) - deltaDifferenceEpsilon) / deltaDifferenceEpsilon); - double effectiveRatio = windowPenalty * currRatio * fractionMultiplier; + double effectiveRatio = windowPenalty * currRatio * differenceMultiplier; if (firstDeltaSwitch) { diff --git a/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils.cs b/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils.cs index 78df8a139b..362a26ec41 100644 --- a/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils.cs +++ b/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils.cs @@ -66,6 +66,20 @@ namespace osu.Game.Rulesets.Difficulty.Utils /// The output of the bell curve function of public static double BellCurve(double x, double mean, double width, double multiplier = 1.0) => multiplier * Math.Exp(Math.E * -(Math.Pow(x - mean, 2) / Math.Pow(width, 2))); + /// + /// Calculates a Smoothstep Bellcurve that returns returns 1 for x = mean, and smoothly reducing it's value to 0 over width + /// + /// Value to calculate the function for + /// Value of x, for which return value will be the highest (=1) + /// Range [mean - width, mean + width] where function will change values + /// The output of the smoothstep bell curve function of + public static double SmoothstepBellCurve(double x, double mean = 0.5, double width = 0.5) + { + x -= mean; + x = x > 0 ? (width - x) : (width + x); + return Smoothstep(x, 0, width); + } + /// /// Smoothstep function (https://en.wikipedia.org/wiki/Smoothstep) /// From d5ef8c85240b306020344ab35c8524783bdf36e3 Mon Sep 17 00:00:00 2001 From: Natelytle <92956514+Natelytle@users.noreply.github.com> Date: Wed, 18 Jun 2025 09:14:01 -0400 Subject: [PATCH 33/78] Replace error functions in DifficultyCalculationUtils with good-enough approximations (#33717) * Reimplement error functions * Fix bug with adjustment for negative values * Formatting --------- Co-authored-by: tsunyoku --- .../Difficulty/OsuPerformanceCalculator.cs | 2 +- .../Utils/DifficultyCalculationUtils.cs | 74 ++ ...ifficultyCalculationUtils_ErrorFunction.cs | 688 ------------------ 3 files changed, 75 insertions(+), 689 deletions(-) delete mode 100644 osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils_ErrorFunction.cs diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 272fe9bb65..5c593422fc 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -424,7 +424,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty double deviation; // Tested max precision for the deviation calculation. - if (pLowerBound > 1e-06) + if (pLowerBound > 0.01) { // Compute deviation assuming greats and oks are normally distributed. deviation = greatHitWindow / (Math.Sqrt(2) * DifficultyCalculationUtils.ErfInv(pLowerBound)); diff --git a/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils.cs b/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils.cs index 362a26ec41..c813627d51 100644 --- a/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils.cs +++ b/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils.cs @@ -116,5 +116,79 @@ namespace osu.Game.Rulesets.Difficulty.Utils { return Math.Clamp((x - start) / (end - start), 0.0, 1.0); } + + /// + /// Error function (https://en.wikipedia.org/wiki/Error_function) + /// + /// Value to calculate the function for + public static double Erf(double x) + { + if (x == 0) + return 0; + + if (double.IsPositiveInfinity(x)) + return 1; + + if (double.IsNegativeInfinity(x)) + return -1; + + if (double.IsNaN(x)) + return double.NaN; + + // Constants for approximation (Abramowitz and Stegun formula 7.1.26) + double t = 1.0 / (1.0 + 0.3275911 * Math.Abs(x)); + double tau = t * (0.254829592 + + t * (-0.284496736 + + t * (1.421413741 + + t * (-1.453152027 + + t * 1.061405429)))); + + double erf = 1.0 - tau * Math.Exp(-x * x); + + return x >= 0 ? erf : -erf; + } + + /// + /// Complementary error function (https://en.wikipedia.org/wiki/Error_function) + /// + /// Value to calculate the function for + public static double Erfc(double x) => 1 - Erf(x); + + /// + /// Inverse error function (https://en.wikipedia.org/wiki/Error_function) + /// + /// Value to calculate the function for + public static double ErfInv(double x) + { + if (x <= -1) + return double.NegativeInfinity; + + if (x >= 1) + return double.PositiveInfinity; + + if (x == 0) + return 0; + + const double a = 0.147; + double sgn = Math.Sign(x); + x = Math.Abs(x); + + double ln = Math.Log(1 - x * x); + double t1 = 2 / (Math.PI * a) + ln / 2; + double t2 = ln / a; + double baseApprox = Math.Sqrt(t1 * t1 - t2) - t1; + + // Correction reduces max error from -0.005 to -0.00045. + double c = x >= 0.85 ? Math.Pow((x - 0.85) / 0.293, 8) : 0; + double erfInv = sgn * (Math.Sqrt(baseApprox) + c); + + return erfInv; + } + + /// + /// Inverse complementary error function (https://en.wikipedia.org/wiki/Error_function) + /// + /// Value to calculate the function for + public static double ErfcInv(double x) => ErfInv(1 - x); } } diff --git a/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils_ErrorFunction.cs b/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils_ErrorFunction.cs deleted file mode 100644 index 4b89cbe7cc..0000000000 --- a/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils_ErrorFunction.cs +++ /dev/null @@ -1,688 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -// All code is referenced from the following: -// https://github.com/mathnet/mathnet-numerics/blob/master/src/Numerics/SpecialFunctions/Erf.cs - -/* - Copyright (c) 2002-2022 Math.NET -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -using System; - -namespace osu.Game.Rulesets.Difficulty.Utils -{ - public partial class DifficultyCalculationUtils - { - /// - /// ************************************** - /// COEFFICIENTS FOR METHOD ErfImp * - /// ************************************** - /// - /// Polynomial coefficients for a numerator of ErfImp - /// calculation for Erf(x) in the interval [1e-10, 0.5]. - /// - private static readonly double[] erf_imp_an = { 0.00337916709551257388990745, -0.00073695653048167948530905, -0.374732337392919607868241, 0.0817442448733587196071743, -0.0421089319936548595203468, 0.0070165709512095756344528, -0.00495091255982435110337458, 0.000871646599037922480317225 }; - - /// Polynomial coefficients for a denominator of ErfImp - /// calculation for Erf(x) in the interval [1e-10, 0.5]. - /// - private static readonly double[] erf_imp_ad = { 1, -0.218088218087924645390535, 0.412542972725442099083918, -0.0841891147873106755410271, 0.0655338856400241519690695, -0.0120019604454941768171266, 0.00408165558926174048329689, -0.000615900721557769691924509 }; - - /// Polynomial coefficients for a numerator in ErfImp - /// calculation for Erfc(x) in the interval [0.5, 0.75]. - /// - private static readonly double[] erf_imp_bn = { -0.0361790390718262471360258, 0.292251883444882683221149, 0.281447041797604512774415, 0.125610208862766947294894, 0.0274135028268930549240776, 0.00250839672168065762786937 }; - - /// Polynomial coefficients for a denominator in ErfImp - /// calculation for Erfc(x) in the interval [0.5, 0.75]. - /// - private static readonly double[] erf_imp_bd = { 1, 1.8545005897903486499845, 1.43575803037831418074962, 0.582827658753036572454135, 0.124810476932949746447682, 0.0113724176546353285778481 }; - - /// Polynomial coefficients for a numerator in ErfImp - /// calculation for Erfc(x) in the interval [0.75, 1.25]. - /// - private static readonly double[] erf_imp_cn = { -0.0397876892611136856954425, 0.153165212467878293257683, 0.191260295600936245503129, 0.10276327061989304213645, 0.029637090615738836726027, 0.0046093486780275489468812, 0.000307607820348680180548455 }; - - /// Polynomial coefficients for a denominator in ErfImp - /// calculation for Erfc(x) in the interval [0.75, 1.25]. - /// - private static readonly double[] erf_imp_cd = { 1, 1.95520072987627704987886, 1.64762317199384860109595, 0.768238607022126250082483, 0.209793185936509782784315, 0.0319569316899913392596356, 0.00213363160895785378615014 }; - - /// Polynomial coefficients for a numerator in ErfImp - /// calculation for Erfc(x) in the interval [1.25, 2.25]. - /// - private static readonly double[] erf_imp_dn = { -0.0300838560557949717328341, 0.0538578829844454508530552, 0.0726211541651914182692959, 0.0367628469888049348429018, 0.00964629015572527529605267, 0.00133453480075291076745275, 0.778087599782504251917881e-4 }; - - /// Polynomial coefficients for a denominator in ErfImp - /// calculation for Erfc(x) in the interval [1.25, 2.25]. - /// - private static readonly double[] erf_imp_dd = { 1, 1.75967098147167528287343, 1.32883571437961120556307, 0.552528596508757581287907, 0.133793056941332861912279, 0.0179509645176280768640766, 0.00104712440019937356634038, -0.106640381820357337177643e-7 }; - - /// Polynomial coefficients for a numerator in ErfImp - /// calculation for Erfc(x) in the interval [2.25, 3.5]. - /// - private static readonly double[] erf_imp_en = { -0.0117907570137227847827732, 0.014262132090538809896674, 0.0202234435902960820020765, 0.00930668299990432009042239, 0.00213357802422065994322516, 0.00025022987386460102395382, 0.120534912219588189822126e-4 }; - - /// Polynomial coefficients for a denominator in ErfImp - /// calculation for Erfc(x) in the interval [2.25, 3.5]. - /// - private static readonly double[] erf_imp_ed = { 1, 1.50376225203620482047419, 0.965397786204462896346934, 0.339265230476796681555511, 0.0689740649541569716897427, 0.00771060262491768307365526, 0.000371421101531069302990367 }; - - /// Polynomial coefficients for a numerator in ErfImp - /// calculation for Erfc(x) in the interval [3.5, 5.25]. - /// - private static readonly double[] erf_imp_fn = { -0.00546954795538729307482955, 0.00404190278731707110245394, 0.0054963369553161170521356, 0.00212616472603945399437862, 0.000394984014495083900689956, 0.365565477064442377259271e-4, 0.135485897109932323253786e-5 }; - - /// Polynomial coefficients for a denominator in ErfImp - /// calculation for Erfc(x) in the interval [3.5, 5.25]. - /// - private static readonly double[] erf_imp_fd = { 1, 1.21019697773630784832251, 0.620914668221143886601045, 0.173038430661142762569515, 0.0276550813773432047594539, 0.00240625974424309709745382, 0.891811817251336577241006e-4, -0.465528836283382684461025e-11 }; - - /// Polynomial coefficients for a numerator in ErfImp - /// calculation for Erfc(x) in the interval [5.25, 8]. - /// - private static readonly double[] erf_imp_gn = { -0.00270722535905778347999196, 0.0013187563425029400461378, 0.00119925933261002333923989, 0.00027849619811344664248235, 0.267822988218331849989363e-4, 0.923043672315028197865066e-6 }; - - /// Polynomial coefficients for a denominator in ErfImp - /// calculation for Erfc(x) in the interval [5.25, 8]. - /// - private static readonly double[] erf_imp_gd = { 1, 0.814632808543141591118279, 0.268901665856299542168425, 0.0449877216103041118694989, 0.00381759663320248459168994, 0.000131571897888596914350697, 0.404815359675764138445257e-11 }; - - /// Polynomial coefficients for a numerator in ErfImp - /// calculation for Erfc(x) in the interval [8, 11.5]. - /// - private static readonly double[] erf_imp_hn = { -0.00109946720691742196814323, 0.000406425442750422675169153, 0.000274499489416900707787024, 0.465293770646659383436343e-4, 0.320955425395767463401993e-5, 0.778286018145020892261936e-7 }; - - /// Polynomial coefficients for a denominator in ErfImp - /// calculation for Erfc(x) in the interval [8, 11.5]. - /// - private static readonly double[] erf_imp_hd = { 1, 0.588173710611846046373373, 0.139363331289409746077541, 0.0166329340417083678763028, 0.00100023921310234908642639, 0.24254837521587225125068e-4 }; - - /// Polynomial coefficients for a numerator in ErfImp - /// calculation for Erfc(x) in the interval [11.5, 17]. - /// - private static readonly double[] erf_imp_in = { -0.00056907993601094962855594, 0.000169498540373762264416984, 0.518472354581100890120501e-4, 0.382819312231928859704678e-5, 0.824989931281894431781794e-7 }; - - /// Polynomial coefficients for a denominator in ErfImp - /// calculation for Erfc(x) in the interval [11.5, 17]. - /// - private static readonly double[] erf_imp_id = { 1, 0.339637250051139347430323, 0.043472647870310663055044, 0.00248549335224637114641629, 0.535633305337152900549536e-4, -0.117490944405459578783846e-12 }; - - /// Polynomial coefficients for a numerator in ErfImp - /// calculation for Erfc(x) in the interval [17, 24]. - /// - private static readonly double[] erf_imp_jn = { -0.000241313599483991337479091, 0.574224975202501512365975e-4, 0.115998962927383778460557e-4, 0.581762134402593739370875e-6, 0.853971555085673614607418e-8 }; - - /// Polynomial coefficients for a denominator in ErfImp - /// calculation for Erfc(x) in the interval [17, 24]. - /// - private static readonly double[] erf_imp_jd = { 1, 0.233044138299687841018015, 0.0204186940546440312625597, 0.000797185647564398289151125, 0.117019281670172327758019e-4 }; - - /// Polynomial coefficients for a numerator in ErfImp - /// calculation for Erfc(x) in the interval [24, 38]. - /// - private static readonly double[] erf_imp_kn = { -0.000146674699277760365803642, 0.162666552112280519955647e-4, 0.269116248509165239294897e-5, 0.979584479468091935086972e-7, 0.101994647625723465722285e-8 }; - - /// Polynomial coefficients for a denominator in ErfImp - /// calculation for Erfc(x) in the interval [24, 38]. - /// - private static readonly double[] erf_imp_kd = { 1, 0.165907812944847226546036, 0.0103361716191505884359634, 0.000286593026373868366935721, 0.298401570840900340874568e-5 }; - - /// Polynomial coefficients for a numerator in ErfImp - /// calculation for Erfc(x) in the interval [38, 60]. - /// - private static readonly double[] erf_imp_ln = { -0.583905797629771786720406e-4, 0.412510325105496173512992e-5, 0.431790922420250949096906e-6, 0.993365155590013193345569e-8, 0.653480510020104699270084e-10 }; - - /// Polynomial coefficients for a denominator in ErfImp - /// calculation for Erfc(x) in the interval [38, 60]. - /// - private static readonly double[] erf_imp_ld = { 1, 0.105077086072039915406159, 0.00414278428675475620830226, 0.726338754644523769144108e-4, 0.477818471047398785369849e-6 }; - - /// Polynomial coefficients for a numerator in ErfImp - /// calculation for Erfc(x) in the interval [60, 85]. - /// - private static readonly double[] erf_imp_mn = { -0.196457797609229579459841e-4, 0.157243887666800692441195e-5, 0.543902511192700878690335e-7, 0.317472492369117710852685e-9 }; - - /// Polynomial coefficients for a denominator in ErfImp - /// calculation for Erfc(x) in the interval [60, 85]. - /// - private static readonly double[] erf_imp_md = { 1, 0.052803989240957632204885, 0.000926876069151753290378112, 0.541011723226630257077328e-5, 0.535093845803642394908747e-15 }; - - /// Polynomial coefficients for a numerator in ErfImp - /// calculation for Erfc(x) in the interval [85, 110]. - /// - private static readonly double[] erf_imp_nn = { -0.789224703978722689089794e-5, 0.622088451660986955124162e-6, 0.145728445676882396797184e-7, 0.603715505542715364529243e-10 }; - - /// Polynomial coefficients for a denominator in ErfImp - /// calculation for Erfc(x) in the interval [85, 110]. - /// - private static readonly double[] erf_imp_nd = { 1, 0.0375328846356293715248719, 0.000467919535974625308126054, 0.193847039275845656900547e-5 }; - - /// - /// ************************************** - /// COEFFICIENTS FOR METHOD ErfInvImp * - /// ************************************** - /// - /// Polynomial coefficients for a numerator of ErfInvImp - /// calculation for Erf^-1(z) in the interval [0, 0.5]. - /// - private static readonly double[] erv_inv_imp_an = { -0.000508781949658280665617, -0.00836874819741736770379, 0.0334806625409744615033, -0.0126926147662974029034, -0.0365637971411762664006, 0.0219878681111168899165, 0.00822687874676915743155, -0.00538772965071242932965 }; - - /// Polynomial coefficients for a denominator of ErfInvImp - /// calculation for Erf^-1(z) in the interval [0, 0.5]. - /// - private static readonly double[] erv_inv_imp_ad = { 1, -0.970005043303290640362, -1.56574558234175846809, 1.56221558398423026363, 0.662328840472002992063, -0.71228902341542847553, -0.0527396382340099713954, 0.0795283687341571680018, -0.00233393759374190016776, 0.000886216390456424707504 }; - - /// Polynomial coefficients for a numerator of ErfInvImp - /// calculation for Erf^-1(z) in the interval [0.5, 0.75]. - /// - private static readonly double[] erv_inv_imp_bn = { -0.202433508355938759655, 0.105264680699391713268, 8.37050328343119927838, 17.6447298408374015486, -18.8510648058714251895, -44.6382324441786960818, 17.445385985570866523, 21.1294655448340526258, -3.67192254707729348546 }; - - /// Polynomial coefficients for a denominator of ErfInvImp - /// calculation for Erf^-1(z) in the interval [0.5, 0.75]. - /// - private static readonly double[] erv_inv_imp_bd = { 1, 6.24264124854247537712, 3.9713437953343869095, -28.6608180499800029974, -20.1432634680485188801, 48.5609213108739935468, 10.8268667355460159008, -22.6436933413139721736, 1.72114765761200282724 }; - - /// Polynomial coefficients for a numerator of ErfInvImp - /// calculation for Erf^-1(z) in the interval [0.75, 1] with x less than 3. - /// - private static readonly double[] erv_inv_imp_cn = { -0.131102781679951906451, -0.163794047193317060787, 0.117030156341995252019, 0.387079738972604337464, 0.337785538912035898924, 0.142869534408157156766, 0.0290157910005329060432, 0.00214558995388805277169, -0.679465575181126350155e-6, 0.285225331782217055858e-7, -0.681149956853776992068e-9 }; - - /// Polynomial coefficients for a denominator of ErfInvImp - /// calculation for Erf^-1(z) in the interval [0.75, 1] with x less than 3. - /// - private static readonly double[] erv_inv_imp_cd = { 1, 3.46625407242567245975, 5.38168345707006855425, 4.77846592945843778382, 2.59301921623620271374, 0.848854343457902036425, 0.152264338295331783612, 0.01105924229346489121 }; - - /// Polynomial coefficients for a numerator of ErfInvImp - /// calculation for Erf^-1(z) in the interval [0.75, 1] with x between 3 and 6. - /// - private static readonly double[] erv_inv_imp_dn = { -0.0350353787183177984712, -0.00222426529213447927281, 0.0185573306514231072324, 0.00950804701325919603619, 0.00187123492819559223345, 0.000157544617424960554631, 0.460469890584317994083e-5, -0.230404776911882601748e-9, 0.266339227425782031962e-11 }; - - /// Polynomial coefficients for a denominator of ErfInvImp - /// calculation for Erf^-1(z) in the interval [0.75, 1] with x between 3 and 6. - /// - private static readonly double[] erv_inv_imp_dd = { 1, 1.3653349817554063097, 0.762059164553623404043, 0.220091105764131249824, 0.0341589143670947727934, 0.00263861676657015992959, 0.764675292302794483503e-4 }; - - /// Polynomial coefficients for a numerator of ErfInvImp - /// calculation for Erf^-1(z) in the interval [0.75, 1] with x between 6 and 18. - /// - private static readonly double[] erv_inv_imp_en = { -0.0167431005076633737133, -0.00112951438745580278863, 0.00105628862152492910091, 0.000209386317487588078668, 0.149624783758342370182e-4, 0.449696789927706453732e-6, 0.462596163522878599135e-8, -0.281128735628831791805e-13, 0.99055709973310326855e-16 }; - - /// Polynomial coefficients for a denominator of ErfInvImp - /// calculation for Erf^-1(z) in the interval [0.75, 1] with x between 6 and 18. - /// - private static readonly double[] erv_inv_imp_ed = { 1, 0.591429344886417493481, 0.138151865749083321638, 0.0160746087093676504695, 0.000964011807005165528527, 0.275335474764726041141e-4, 0.282243172016108031869e-6 }; - - /// Polynomial coefficients for a numerator of ErfInvImp - /// calculation for Erf^-1(z) in the interval [0.75, 1] with x between 18 and 44. - /// - private static readonly double[] erv_inv_imp_fn = { -0.0024978212791898131227, -0.779190719229053954292e-5, 0.254723037413027451751e-4, 0.162397777342510920873e-5, 0.396341011304801168516e-7, 0.411632831190944208473e-9, 0.145596286718675035587e-11, -0.116765012397184275695e-17 }; - - /// Polynomial coefficients for a denominator of ErfInvImp - /// calculation for Erf^-1(z) in the interval [0.75, 1] with x between 18 and 44. - /// - private static readonly double[] erv_inv_imp_fd = { 1, 0.207123112214422517181, 0.0169410838120975906478, 0.000690538265622684595676, 0.145007359818232637924e-4, 0.144437756628144157666e-6, 0.509761276599778486139e-9 }; - - /// Polynomial coefficients for a numerator of ErfInvImp - /// calculation for Erf^-1(z) in the interval [0.75, 1] with x greater than 44. - /// - private static readonly double[] erv_inv_imp_gn = { -0.000539042911019078575891, -0.28398759004727721098e-6, 0.899465114892291446442e-6, 0.229345859265920864296e-7, 0.225561444863500149219e-9, 0.947846627503022684216e-12, 0.135880130108924861008e-14, -0.348890393399948882918e-21 }; - - /// Polynomial coefficients for a denominator of ErfInvImp - /// calculation for Erf^-1(z) in the interval [0.75, 1] with x greater than 44. - /// - private static readonly double[] erv_inv_imp_gd = { 1, 0.0845746234001899436914, 0.00282092984726264681981, 0.468292921940894236786e-4, 0.399968812193862100054e-6, 0.161809290887904476097e-8, 0.231558608310259605225e-11 }; - - /// Calculates the error function. - /// The value to evaluate. - /// the error function evaluated at given value. - /// - /// - /// returns 1 if x == double.PositiveInfinity. - /// returns -1 if x == double.NegativeInfinity. - /// - /// - public static double Erf(double x) - { - if (x == 0) - { - return 0; - } - - if (double.IsPositiveInfinity(x)) - { - return 1; - } - - if (double.IsNegativeInfinity(x)) - { - return -1; - } - - if (double.IsNaN(x)) - { - return double.NaN; - } - - return erfImp(x, false); - } - - /// Calculates the complementary error function. - /// The value to evaluate. - /// the complementary error function evaluated at given value. - /// - /// - /// returns 0 if x == double.PositiveInfinity. - /// returns 2 if x == double.NegativeInfinity. - /// - /// - public static double Erfc(double x) - { - if (x == 0) - { - return 1; - } - - if (double.IsPositiveInfinity(x)) - { - return 0; - } - - if (double.IsNegativeInfinity(x)) - { - return 2; - } - - if (double.IsNaN(x)) - { - return double.NaN; - } - - return erfImp(x, true); - } - - /// Calculates the inverse error function evaluated at z. - /// The inverse error function evaluated at given value. - /// - /// - /// returns double.PositiveInfinity if z >= 1.0. - /// returns double.NegativeInfinity if z <= -1.0. - /// - /// - /// Calculates the inverse error function evaluated at z. - /// value to evaluate. - /// the inverse error function evaluated at Z. - public static double ErfInv(double z) - { - if (z == 0.0) - { - return 0.0; - } - - if (z >= 1.0) - { - return double.PositiveInfinity; - } - - if (z <= -1.0) - { - return double.NegativeInfinity; - } - - double p, q, s; - - if (z < 0) - { - p = -z; - q = 1 - p; - s = -1; - } - else - { - p = z; - q = 1 - z; - s = 1; - } - - return erfInvImpl(p, q, s); - } - - /// - /// Implementation of the error function. - /// - /// Where to evaluate the error function. - /// Whether to compute 1 - the error function. - /// the error function. - private static double erfImp(double z, bool invert) - { - if (z < 0) - { - if (!invert) - { - return -erfImp(-z, false); - } - - if (z < -0.5) - { - return 2 - erfImp(-z, true); - } - - return 1 + erfImp(-z, false); - } - - double result; - - // Big bunch of selection statements now to pick which - // implementation to use, try to put most likely options - // first: - if (z < 0.5) - { - // We're going to calculate erf: - if (z < 1e-10) - { - result = (z * 1.125) + (z * 0.003379167095512573896158903121545171688); - } - else - { - // Worst case absolute error found: 6.688618532e-21 - result = (z * 1.125) + (z * evaluatePolynomial(z, erf_imp_an) / evaluatePolynomial(z, erf_imp_ad)); - } - } - else if (z < 110) - { - // We'll be calculating erfc: - invert = !invert; - double r, b; - - if (z < 0.75) - { - // Worst case absolute error found: 5.582813374e-21 - r = evaluatePolynomial(z - 0.5, erf_imp_bn) / evaluatePolynomial(z - 0.5, erf_imp_bd); - b = 0.3440242112F; - } - else if (z < 1.25) - { - // Worst case absolute error found: 4.01854729e-21 - r = evaluatePolynomial(z - 0.75, erf_imp_cn) / evaluatePolynomial(z - 0.75, erf_imp_cd); - b = 0.419990927F; - } - else if (z < 2.25) - { - // Worst case absolute error found: 2.866005373e-21 - r = evaluatePolynomial(z - 1.25, erf_imp_dn) / evaluatePolynomial(z - 1.25, erf_imp_dd); - b = 0.4898625016F; - } - else if (z < 3.5) - { - // Worst case absolute error found: 1.045355789e-21 - r = evaluatePolynomial(z - 2.25, erf_imp_en) / evaluatePolynomial(z - 2.25, erf_imp_ed); - b = 0.5317370892F; - } - else if (z < 5.25) - { - // Worst case absolute error found: 8.300028706e-22 - r = evaluatePolynomial(z - 3.5, erf_imp_fn) / evaluatePolynomial(z - 3.5, erf_imp_fd); - b = 0.5489973426F; - } - else if (z < 8) - { - // Worst case absolute error found: 1.700157534e-21 - r = evaluatePolynomial(z - 5.25, erf_imp_gn) / evaluatePolynomial(z - 5.25, erf_imp_gd); - b = 0.5571740866F; - } - else if (z < 11.5) - { - // Worst case absolute error found: 3.002278011e-22 - r = evaluatePolynomial(z - 8, erf_imp_hn) / evaluatePolynomial(z - 8, erf_imp_hd); - b = 0.5609807968F; - } - else if (z < 17) - { - // Worst case absolute error found: 6.741114695e-21 - r = evaluatePolynomial(z - 11.5, erf_imp_in) / evaluatePolynomial(z - 11.5, erf_imp_id); - b = 0.5626493692F; - } - else if (z < 24) - { - // Worst case absolute error found: 7.802346984e-22 - r = evaluatePolynomial(z - 17, erf_imp_jn) / evaluatePolynomial(z - 17, erf_imp_jd); - b = 0.5634598136F; - } - else if (z < 38) - { - // Worst case absolute error found: 2.414228989e-22 - r = evaluatePolynomial(z - 24, erf_imp_kn) / evaluatePolynomial(z - 24, erf_imp_kd); - b = 0.5638477802F; - } - else if (z < 60) - { - // Worst case absolute error found: 5.896543869e-24 - r = evaluatePolynomial(z - 38, erf_imp_ln) / evaluatePolynomial(z - 38, erf_imp_ld); - b = 0.5640528202F; - } - else if (z < 85) - { - // Worst case absolute error found: 3.080612264e-21 - r = evaluatePolynomial(z - 60, erf_imp_mn) / evaluatePolynomial(z - 60, erf_imp_md); - b = 0.5641309023F; - } - else - { - // Worst case absolute error found: 8.094633491e-22 - r = evaluatePolynomial(z - 85, erf_imp_nn) / evaluatePolynomial(z - 85, erf_imp_nd); - b = 0.5641584396F; - } - - double g = Math.Exp(-z * z) / z; - result = (g * b) + (g * r); - } - else - { - // Any value of z larger than 28 will underflow to zero: - result = 0; - invert = !invert; - } - - if (invert) - { - result = 1 - result; - } - - return result; - } - - /// Calculates the complementary inverse error function evaluated at z. - /// The complementary inverse error function evaluated at given value. - /// We have tested this implementation against the arbitrary precision mpmath library - /// and found cases where we can only guarantee 9 significant figures correct. - /// - /// returns double.PositiveInfinity if z <= 0.0. - /// returns double.NegativeInfinity if z >= 2.0. - /// - /// - /// calculates the complementary inverse error function evaluated at z. - /// value to evaluate. - /// the complementary inverse error function evaluated at Z. - public static double ErfcInv(double z) - { - if (z <= 0.0) - { - return double.PositiveInfinity; - } - - if (z >= 2.0) - { - return double.NegativeInfinity; - } - - double p, q, s; - - if (z > 1) - { - q = 2 - z; - p = 1 - q; - s = -1; - } - else - { - p = 1 - z; - q = z; - s = 1; - } - - return erfInvImpl(p, q, s); - } - - /// - /// The implementation of the inverse error function. - /// - /// First intermediate parameter. - /// Second intermediate parameter. - /// Third intermediate parameter. - /// the inverse error function. - private static double erfInvImpl(double p, double q, double s) - { - double result; - - if (p <= 0.5) - { - // Evaluate inverse erf using the rational approximation: - // - // x = p(p+10)(Y+R(p)) - // - // Where Y is a constant, and R(p) is optimized for a low - // absolute error compared to |Y|. - // - // double: Max error found: 2.001849e-18 - // long double: Max error found: 1.017064e-20 - // Maximum Deviation Found (actual error term at infinite precision) 8.030e-21 - const float y = 0.0891314744949340820313f; - double g = p * (p + 10); - double r = evaluatePolynomial(p, erv_inv_imp_an) / evaluatePolynomial(p, erv_inv_imp_ad); - result = (g * y) + (g * r); - } - else if (q >= 0.25) - { - // Rational approximation for 0.5 > q >= 0.25 - // - // x = sqrt(-2*log(q)) / (Y + R(q)) - // - // Where Y is a constant, and R(q) is optimized for a low - // absolute error compared to Y. - // - // double : Max error found: 7.403372e-17 - // long double : Max error found: 6.084616e-20 - // Maximum Deviation Found (error term) 4.811e-20 - const float y = 2.249481201171875f; - double g = Math.Sqrt(-2 * Math.Log(q)); - double xs = q - 0.25; - double r = evaluatePolynomial(xs, erv_inv_imp_bn) / evaluatePolynomial(xs, erv_inv_imp_bd); - result = g / (y + r); - } - else - { - // For q < 0.25 we have a series of rational approximations all - // of the general form: - // - // let: x = sqrt(-log(q)) - // - // Then the result is given by: - // - // x(Y+R(x-B)) - // - // where Y is a constant, B is the lowest value of x for which - // the approximation is valid, and R(x-B) is optimized for a low - // absolute error compared to Y. - // - // Note that almost all code will really go through the first - // or maybe second approximation. After than we're dealing with very - // small input values indeed: 80 and 128 bit long double's go all the - // way down to ~ 1e-5000 so the "tail" is rather long... - double x = Math.Sqrt(-Math.Log(q)); - - if (x < 3) - { - // Max error found: 1.089051e-20 - const float y = 0.807220458984375f; - double xs = x - 1.125; - double r = evaluatePolynomial(xs, erv_inv_imp_cn) / evaluatePolynomial(xs, erv_inv_imp_cd); - result = (y * x) + (r * x); - } - else if (x < 6) - { - // Max error found: 8.389174e-21 - const float y = 0.93995571136474609375f; - double xs = x - 3; - double r = evaluatePolynomial(xs, erv_inv_imp_dn) / evaluatePolynomial(xs, erv_inv_imp_dd); - result = (y * x) + (r * x); - } - else if (x < 18) - { - // Max error found: 1.481312e-19 - const float y = 0.98362827301025390625f; - double xs = x - 6; - double r = evaluatePolynomial(xs, erv_inv_imp_en) / evaluatePolynomial(xs, erv_inv_imp_ed); - result = (y * x) + (r * x); - } - else if (x < 44) - { - // Max error found: 5.697761e-20 - const float y = 0.99714565277099609375f; - double xs = x - 18; - double r = evaluatePolynomial(xs, erv_inv_imp_fn) / evaluatePolynomial(xs, erv_inv_imp_fd); - result = (y * x) + (r * x); - } - else - { - // Max error found: 1.279746e-20 - const float y = 0.99941349029541015625f; - double xs = x - 44; - double r = evaluatePolynomial(xs, erv_inv_imp_gn) / evaluatePolynomial(xs, erv_inv_imp_gd); - result = (y * x) + (r * x); - } - } - - return s * result; - } - - /// - /// Evaluate a polynomial at point x. - /// Coefficients are ordered ascending by power with power k at index k. - /// Example: coefficients [3,-1,2] represent y=2x^2-x+3. - /// - /// The location where to evaluate the polynomial at. - /// The coefficients of the polynomial, coefficient for power k at index k. - /// - /// is a null reference. - /// - private static double evaluatePolynomial(double z, params double[] coefficients) - { - // 2020-10-07 jbialogrodzki #730 Since this is public API we should probably - // handle null arguments? It doesn't seem to have been done consistently in this class though. - ArgumentNullException.ThrowIfNull(coefficients); - - // 2020-10-07 jbialogrodzki #730 Zero polynomials need explicit handling. - // Without this check, we attempted to peek coefficients at negative indices! - int n = coefficients.Length; - - if (n == 0) - { - return 0; - } - - double sum = coefficients[n - 1]; - - for (int i = n - 2; i >= 0; --i) - { - sum *= z; - sum += coefficients[i]; - } - - return sum; - } - } -} From cf4d6bea72eefef1ca2e4e32fc483b50ee9f4686 Mon Sep 17 00:00:00 2001 From: Natelytle <92956514+Natelytle@users.noreply.github.com> Date: Fri, 27 Jun 2025 18:46:52 -0400 Subject: [PATCH 34/78] Implement difficulty evaluators in the osu! mania ruleset (#33411) * stuff * Implement evaluators * Typo * Fixes * clarifying comment * Fix CalculateInitialStrain * Remove debug line * Small code quality fix * Address comments, slight code quality fixes * Change comment for clarity --------- Co-authored-by: StanR --- .../Evaluators/IndividualStrainEvaluator.cs | 37 ++++++++++ .../Evaluators/OverallStrainEvaluator.cs | 61 +++++++++++++++ .../Difficulty/ManiaDifficultyCalculator.cs | 11 ++- .../Preprocessing/ManiaDifficultyHitObject.cs | 52 ++++++++++++- .../Difficulty/Skills/Strain.cs | 74 ++++--------------- 5 files changed, 172 insertions(+), 63 deletions(-) create mode 100644 osu.Game.Rulesets.Mania/Difficulty/Evaluators/IndividualStrainEvaluator.cs create mode 100644 osu.Game.Rulesets.Mania/Difficulty/Evaluators/OverallStrainEvaluator.cs diff --git a/osu.Game.Rulesets.Mania/Difficulty/Evaluators/IndividualStrainEvaluator.cs b/osu.Game.Rulesets.Mania/Difficulty/Evaluators/IndividualStrainEvaluator.cs new file mode 100644 index 0000000000..297beb2840 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Difficulty/Evaluators/IndividualStrainEvaluator.cs @@ -0,0 +1,37 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Utils; +using osu.Game.Rulesets.Difficulty.Preprocessing; +using osu.Game.Rulesets.Mania.Difficulty.Preprocessing; + +namespace osu.Game.Rulesets.Mania.Difficulty.Evaluators +{ + public class IndividualStrainEvaluator + { + public static double EvaluateDifficultyOf(DifficultyHitObject current) + { + var maniaCurrent = (ManiaDifficultyHitObject)current; + double startTime = maniaCurrent.StartTime; + double endTime = maniaCurrent.EndTime; + + double holdFactor = 1.0; // Factor to all additional strains in case something else is held + + // We award a bonus if this note starts and ends before the end of another hold note. + foreach (var maniaPrevious in maniaCurrent.PreviousHitObjects) + { + if (maniaPrevious is null) + continue; + + if (Precision.DefinitelyBigger(maniaPrevious.EndTime, endTime, 1) && + Precision.DefinitelyBigger(startTime, maniaPrevious.StartTime, 1)) + { + holdFactor = 1.25; + break; + } + } + + return 2.0 * holdFactor; + } + } +} diff --git a/osu.Game.Rulesets.Mania/Difficulty/Evaluators/OverallStrainEvaluator.cs b/osu.Game.Rulesets.Mania/Difficulty/Evaluators/OverallStrainEvaluator.cs new file mode 100644 index 0000000000..97782f7644 --- /dev/null +++ b/osu.Game.Rulesets.Mania/Difficulty/Evaluators/OverallStrainEvaluator.cs @@ -0,0 +1,61 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Framework.Utils; +using osu.Game.Rulesets.Difficulty.Preprocessing; +using osu.Game.Rulesets.Difficulty.Utils; +using osu.Game.Rulesets.Mania.Difficulty.Preprocessing; + +namespace osu.Game.Rulesets.Mania.Difficulty.Evaluators +{ + public class OverallStrainEvaluator + { + private const double release_threshold = 30; + + public static double EvaluateDifficultyOf(DifficultyHitObject current) + { + var maniaCurrent = (ManiaDifficultyHitObject)current; + double startTime = maniaCurrent.StartTime; + double endTime = maniaCurrent.EndTime; + bool isOverlapping = false; + + double closestEndTime = Math.Abs(endTime - startTime); // Lowest value we can assume with the current information + double holdFactor = 1.0; // Factor to all additional strains in case something else is held + double holdAddition = 0; // Addition to the current note in case it's a hold and has to be released awkwardly + + foreach (var maniaPrevious in maniaCurrent.PreviousHitObjects) + { + if (maniaPrevious is null) + continue; + + // The current note is overlapped if a previous note or end is overlapping the current note body + isOverlapping |= Precision.DefinitelyBigger(maniaPrevious.EndTime, startTime, 1) && + Precision.DefinitelyBigger(endTime, maniaPrevious.EndTime, 1) && + Precision.DefinitelyBigger(startTime, maniaPrevious.StartTime, 1); + + // We give a slight bonus to everything if something is held meanwhile + if (Precision.DefinitelyBigger(maniaPrevious.EndTime, endTime, 1) && + Precision.DefinitelyBigger(startTime, maniaPrevious.StartTime, 1)) + holdFactor = 1.25; + + closestEndTime = Math.Min(closestEndTime, Math.Abs(endTime - maniaPrevious.EndTime)); + } + + // The hold addition is given if there was an overlap, however it is only valid if there are no other note with a similar ending. + // Releasing multiple notes is just as easy as releasing 1. Nerfs the hold addition by half if the closest release is release_threshold away. + // holdAddition + // ^ + // 1.0 + - - - - - -+----------- + // | / + // 0.5 + - - - - -/ Sigmoid Curve + // | /| + // 0.0 +--------+-+---------------> Release Difference / ms + // release_threshold + if (isOverlapping) + holdAddition = DifficultyCalculationUtils.Logistic(x: closestEndTime, multiplier: 0.27, midpointOffset: release_threshold); + + return (1 + holdAddition) * holdFactor; + } + } +} diff --git a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs index 06b8018f2b..bcf16e6808 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/ManiaDifficultyCalculator.cs @@ -65,13 +65,22 @@ namespace osu.Game.Rulesets.Mania.Difficulty protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) { var sortedObjects = beatmap.HitObjects.ToArray(); + int totalColumns = ((ManiaBeatmap)beatmap).TotalColumns; LegacySortHelper.Sort(sortedObjects, Comparer.Create((a, b) => (int)Math.Round(a.StartTime) - (int)Math.Round(b.StartTime))); List objects = new List(); + List[] perColumnObjects = new List[totalColumns]; + + for (int column = 0; column < totalColumns; column++) + perColumnObjects[column] = new List(); for (int i = 1; i < sortedObjects.Length; i++) - objects.Add(new ManiaDifficultyHitObject(sortedObjects[i], sortedObjects[i - 1], clockRate, objects, objects.Count)); + { + var currentObject = new ManiaDifficultyHitObject(sortedObjects[i], sortedObjects[i - 1], clockRate, objects, perColumnObjects, objects.Count); + objects.Add(currentObject); + perColumnObjects[currentObject.Column].Add(currentObject); + } return objects; } diff --git a/osu.Game.Rulesets.Mania/Difficulty/Preprocessing/ManiaDifficultyHitObject.cs b/osu.Game.Rulesets.Mania/Difficulty/Preprocessing/ManiaDifficultyHitObject.cs index a67d38b29f..91b6a2b861 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/Preprocessing/ManiaDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/Preprocessing/ManiaDifficultyHitObject.cs @@ -12,9 +12,59 @@ namespace osu.Game.Rulesets.Mania.Difficulty.Preprocessing { public new ManiaHitObject BaseObject => (ManiaHitObject)base.BaseObject; - public ManiaDifficultyHitObject(HitObject hitObject, HitObject lastObject, double clockRate, List objects, int index) + private readonly List[] perColumnObjects; + + private readonly int columnIndex; + + public readonly int Column; + + // The hit object earlier in time than this note in each column + public readonly ManiaDifficultyHitObject?[] PreviousHitObjects; + + public readonly double ColumnStrainTime; + + public ManiaDifficultyHitObject(HitObject hitObject, HitObject lastObject, double clockRate, List objects, List[] perColumnObjects, int index) : base(hitObject, lastObject, clockRate, objects, index) { + int totalColumns = perColumnObjects.Length; + this.perColumnObjects = perColumnObjects; + Column = BaseObject.Column; + columnIndex = perColumnObjects[Column].Count; + PreviousHitObjects = new ManiaDifficultyHitObject[totalColumns]; + ColumnStrainTime = StartTime - PrevInColumn(0)?.StartTime ?? StartTime; + + if (index > 0) + { + ManiaDifficultyHitObject prevNote = (ManiaDifficultyHitObject)objects[index - 1]; + + for (int i = 0; i < prevNote.PreviousHitObjects.Length; i++) + PreviousHitObjects[i] = prevNote.PreviousHitObjects[i]; + + // intentionally depends on processing order to match live. + PreviousHitObjects[prevNote.Column] = prevNote; + } + } + + /// + /// The previous object in the same column as this , exclusive of Long Note tails. + /// + /// The number of notes to go back. + /// The object in this column notes back, or null if this is the first note in the column. + public ManiaDifficultyHitObject? PrevInColumn(int backwardsIndex) + { + int index = columnIndex - (backwardsIndex + 1); + return index >= 0 && index < perColumnObjects[Column].Count ? (ManiaDifficultyHitObject)perColumnObjects[Column][index] : null; + } + + /// + /// The next object in the same column as this , exclusive of Long Note tails. + /// + /// The number of notes to go forward. + /// The object in this column notes forward, or null if this is the last note in the column. + public ManiaDifficultyHitObject? NextInColumn(int forwardsIndex) + { + int index = columnIndex + (forwardsIndex + 1); + return index >= 0 && index < perColumnObjects[Column].Count ? (ManiaDifficultyHitObject)perColumnObjects[Column][index] : null; } } } diff --git a/osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs b/osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs index bb4261ea13..037b7e3511 100644 --- a/osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs +++ b/osu.Game.Rulesets.Mania/Difficulty/Skills/Strain.cs @@ -2,10 +2,9 @@ // See the LICENCE file in the repository root for full licence text. using System; -using osu.Framework.Utils; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; -using osu.Game.Rulesets.Difficulty.Utils; +using osu.Game.Rulesets.Mania.Difficulty.Evaluators; using osu.Game.Rulesets.Mania.Difficulty.Preprocessing; using osu.Game.Rulesets.Mods; @@ -15,23 +14,17 @@ namespace osu.Game.Rulesets.Mania.Difficulty.Skills { private const double individual_decay_base = 0.125; private const double overall_decay_base = 0.30; - private const double release_threshold = 30; protected override double SkillMultiplier => 1; protected override double StrainDecayBase => 1; - private readonly double[] startTimes; - private readonly double[] endTimes; private readonly double[] individualStrains; - - private double individualStrain; + private double highestIndividualStrain; private double overallStrain; public Strain(Mod[] mods, int totalColumns) : base(mods) { - startTimes = new double[totalColumns]; - endTimes = new double[totalColumns]; individualStrains = new double[totalColumns]; overallStrain = 1; } @@ -39,65 +32,24 @@ namespace osu.Game.Rulesets.Mania.Difficulty.Skills protected override double StrainValueOf(DifficultyHitObject current) { var maniaCurrent = (ManiaDifficultyHitObject)current; - double startTime = maniaCurrent.StartTime; - double endTime = maniaCurrent.EndTime; - int column = maniaCurrent.BaseObject.Column; - bool isOverlapping = false; - double closestEndTime = Math.Abs(endTime - startTime); // Lowest value we can assume with the current information - double holdFactor = 1.0; // Factor to all additional strains in case something else is held - double holdAddition = 0; // Addition to the current note in case it's a hold and has to be released awkwardly + individualStrains[maniaCurrent.Column] = applyDecay(individualStrains[maniaCurrent.Column], maniaCurrent.ColumnStrainTime, individual_decay_base); + individualStrains[maniaCurrent.Column] += IndividualStrainEvaluator.EvaluateDifficultyOf(current); - for (int i = 0; i < endTimes.Length; ++i) - { - // The current note is overlapped if a previous note or end is overlapping the current note body - isOverlapping |= Precision.DefinitelyBigger(endTimes[i], startTime, 1) && - Precision.DefinitelyBigger(endTime, endTimes[i], 1) && - Precision.DefinitelyBigger(startTime, startTimes[i], 1); + // Take the hardest individualStrain for notes that happen at the same time (in a chord). + // This is to ensure the order in which the notes are processed does not affect the resultant total strain. + highestIndividualStrain = maniaCurrent.DeltaTime <= 1 ? Math.Max(highestIndividualStrain, individualStrains[maniaCurrent.Column]) : individualStrains[maniaCurrent.Column]; - // We give a slight bonus to everything if something is held meanwhile - if (Precision.DefinitelyBigger(endTimes[i], endTime, 1) && - Precision.DefinitelyBigger(startTime, startTimes[i], 1)) - holdFactor = 1.25; - - closestEndTime = Math.Min(closestEndTime, Math.Abs(endTime - endTimes[i])); - } - - // The hold addition is given if there was an overlap, however it is only valid if there are no other note with a similar ending. - // Releasing multiple notes is just as easy as releasing 1. Nerfs the hold addition by half if the closest release is release_threshold away. - // holdAddition - // ^ - // 1.0 + - - - - - -+----------- - // | / - // 0.5 + - - - - -/ Sigmoid Curve - // | /| - // 0.0 +--------+-+---------------> Release Difference / ms - // release_threshold - if (isOverlapping) - holdAddition = DifficultyCalculationUtils.Logistic(x: closestEndTime, multiplier: 0.27, midpointOffset: release_threshold); - - // Decay and increase individualStrains in own column - individualStrains[column] = applyDecay(individualStrains[column], startTime - startTimes[column], individual_decay_base); - individualStrains[column] += 2.0 * holdFactor; - - // For notes at the same time (in a chord), the individualStrain should be the hardest individualStrain out of those columns - individualStrain = maniaCurrent.DeltaTime <= 1 ? Math.Max(individualStrain, individualStrains[column]) : individualStrains[column]; - - // Decay and increase overallStrain - overallStrain = applyDecay(overallStrain, current.DeltaTime, overall_decay_base); - overallStrain += (1 + holdAddition) * holdFactor; - - // Update startTimes and endTimes arrays - startTimes[column] = startTime; - endTimes[column] = endTime; + overallStrain = applyDecay(overallStrain, maniaCurrent.DeltaTime, overall_decay_base); + overallStrain += OverallStrainEvaluator.EvaluateDifficultyOf(current); // By subtracting CurrentStrain, this skill effectively only considers the maximum strain of any one hitobject within each strain section. - return individualStrain + overallStrain - CurrentStrain; + return highestIndividualStrain + overallStrain - CurrentStrain; } - protected override double CalculateInitialStrain(double offset, DifficultyHitObject current) - => applyDecay(individualStrain, offset - current.Previous(0).StartTime, individual_decay_base) - + applyDecay(overallStrain, offset - current.Previous(0).StartTime, overall_decay_base); + protected override double CalculateInitialStrain(double offset, DifficultyHitObject current) => + applyDecay(highestIndividualStrain, offset - current.Previous(0).StartTime, individual_decay_base) + + applyDecay(overallStrain, offset - current.Previous(0).StartTime, overall_decay_base); private double applyDecay(double value, double deltaTime, double decayBase) => value * Math.Pow(decayBase, deltaTime / 1000); From a75e0c3850d4e23a4b004cbf3d0ff0b188040f03 Mon Sep 17 00:00:00 2001 From: Givikap120 <89256026+Givikap120@users.noreply.github.com> Date: Tue, 8 Jul 2025 18:37:41 +0300 Subject: [PATCH 35/78] Refactor AR and OD calculations in osu! pp calculation (#34065) * Add AR and OD calculation functions * use created functions in perfcalc --- .../Difficulty/OsuDifficultyCalculator.cs | 27 ++++++++++++------- .../Difficulty/OsuPerformanceCalculator.cs | 7 ++--- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index c5d85602c6..2907f5f58e 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -69,6 +69,22 @@ namespace osu.Game.Rulesets.Osu.Difficulty return readingBonus; } + public static double CalculateRateAdjustedApproachRate(double approachRate, double clockRate) + { + double preempt = IBeatmapDifficultyInfo.DifficultyRange(approachRate, OsuHitObject.PREEMPT_MAX, OsuHitObject.PREEMPT_MID, OsuHitObject.PREEMPT_MIN) / clockRate; + return IBeatmapDifficultyInfo.InverseDifficultyRange(preempt, OsuHitObject.PREEMPT_MAX, OsuHitObject.PREEMPT_MID, OsuHitObject.PREEMPT_MIN); + } + + public static double CalculateRateAdjustedOverallDifficulty(double overallDifficulty, double clockRate) + { + HitWindows hitWindows = new OsuHitWindows(); + hitWindows.SetDifficulty(overallDifficulty); + + double hitWindowGreat = hitWindows.WindowFor(HitResult.Great) / clockRate; + + return (79.5 - hitWindowGreat) / 6; + } + protected override DifficultyAttributes CreateDifficultyAttributes(IBeatmap beatmap, Mod[] mods, Skill[] skills, double clockRate) { if (beatmap.HitObjects.Count == 0) @@ -94,15 +110,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty double difficultSliders = aim.GetDifficultSliders(); - double preempt = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.ApproachRate, 1800, 1200, 450) / clockRate; - double approachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5; - - HitWindows hitWindows = new OsuHitWindows(); - hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty); - - double hitWindowGreat = hitWindows.WindowFor(HitResult.Great) / clockRate; - - double overallDifficulty = (80 - hitWindowGreat) / 6; + double approachRate = CalculateRateAdjustedApproachRate(beatmap.Difficulty.ApproachRate, clockRate); + double overallDifficulty = CalculateRateAdjustedOverallDifficulty(beatmap.Difficulty.OverallDifficulty, clockRate); int hitCircleCount = beatmap.HitObjects.Count(h => h is HitCircle); int sliderCount = beatmap.HitObjects.Count(h => h is Slider); diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 966f8da261..49626eb7b6 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Extensions.IEnumerableExtensions; -using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty.Utils; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Scoring; @@ -92,10 +91,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty okHitWindow = hitWindows.WindowFor(HitResult.Ok) / clockRate; mehHitWindow = hitWindows.WindowFor(HitResult.Meh) / clockRate; - double preempt = IBeatmapDifficultyInfo.DifficultyRange(difficulty.ApproachRate, 1800, 1200, 450) / clockRate; - - overallDifficulty = (79.5 - greatHitWindow) / 6; - approachRate = preempt > 1200 ? (1800 - preempt) / 120 : (1200 - preempt) / 150 + 5; + approachRate = OsuDifficultyCalculator.CalculateRateAdjustedApproachRate(difficulty.ApproachRate, clockRate); + overallDifficulty = OsuDifficultyCalculator.CalculateRateAdjustedOverallDifficulty(difficulty.OverallDifficulty, clockRate); double comboBasedEstimatedMissCount = calculateComboBasedEstimatedMissCount(osuAttributes); double? scoreBasedEstimatedMissCount = null; From ddf9d6b8c8ce6ce47fa6cb9db55b98bfc2c04ac5 Mon Sep 17 00:00:00 2001 From: Jay Lawton Date: Tue, 22 Jul 2025 19:37:51 +1000 Subject: [PATCH 36/78] ensure `monolengthbonus` applies to new strain contribution only (#33635) * stamina fix * review changes * fix naming --------- Co-authored-by: StanR --- .../Difficulty/Skills/Stamina.cs | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs index 0e1f3d41cf..7c0c76d3ba 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs @@ -42,20 +42,28 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills protected override double StrainValueAt(DifficultyHitObject current) { currentStrain *= strainDecay(current.DeltaTime); - currentStrain += StaminaEvaluator.EvaluateDifficultyOf(current) * skillMultiplier; + double staminaDifficulty = StaminaEvaluator.EvaluateDifficultyOf(current) * skillMultiplier; // Safely prevents previous strains from shifting as new notes are added. var currentObject = current as TaikoDifficultyHitObject; int index = currentObject?.ColourData.MonoStreak?.HitObjects.IndexOf(currentObject) ?? 0; - double monolengthBonus = isConvert ? 1 : 1 + Math.Min(Math.Max((index - 5) / 50.0, 0), 0.30); + double monoLengthBonus = isConvert ? 1.0 : 1.0 + 0.3 * DifficultyCalculationUtils.ReverseLerp(index, 5, 20); - if (SingleColourStamina) - return DifficultyCalculationUtils.Logistic(-(index - 10) / 2.0, currentStrain); + // Mono-streak bonus is only applied to colour-based stamina to reward longer sequences of same-colour hits within patterns. + if (!SingleColourStamina) + staminaDifficulty *= monoLengthBonus; - return currentStrain * monolengthBonus; + currentStrain += staminaDifficulty; + + // For converted maps, difficulty often comes entirely from long mono streams with no colour variation. + // To avoid over-rewarding these maps based purely on stamina strain, we dampen the strain value once the index exceeds 10. + return SingleColourStamina ? DifficultyCalculationUtils.Logistic(-(index - 10) / 2.0, currentStrain) : currentStrain; } - protected override double CalculateInitialStrain(double time, DifficultyHitObject current) => SingleColourStamina ? 0 : currentStrain * strainDecay(time - current.Previous(0).StartTime); + protected override double CalculateInitialStrain(double time, DifficultyHitObject current) => + SingleColourStamina + ? 0 + : currentStrain * strainDecay(time - current.Previous(0).StartTime); } } From 56b072cfd9cf8c01d00ba3358ebd2f381e53ab3d Mon Sep 17 00:00:00 2001 From: Givikap120 <89256026+Givikap120@users.noreply.github.com> Date: Thu, 24 Jul 2025 18:41:36 +0300 Subject: [PATCH 37/78] remove high CS bonus from slider bonus (#34214) Co-authored-by: StanR --- osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index f8dcdfd5e7..5942448855 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -155,13 +155,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators // Add in acute angle bonus or wide angle bonus, whichever is larger. aimStrain += Math.Max(acuteAngleBonus * acute_angle_multiplier, wideAngleBonus * wide_angle_multiplier); + // Apply high circle size bonus + aimStrain *= osuCurrObj.SmallCircleBonus; + // Add in additional slider velocity bonus. if (withSliderTravelDistance) aimStrain += sliderBonus * slider_multiplier; - // Apply high circle size bonus - aimStrain *= osuCurrObj.SmallCircleBonus; - return aimStrain; } From 945db7b431d8abcb2918e191f23112ff17da4319 Mon Sep 17 00:00:00 2001 From: James Wilson Date: Fri, 25 Jul 2025 07:50:23 +0100 Subject: [PATCH 38/78] Fix backwards logic on visibility bonus (#34369) Co-authored-by: StanR --- osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 2907f5f58e..513352825f 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -51,7 +51,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty public static double CalculateVisibilityBonus(Mod[] mods, double approachRate, double visibilityFactor = 1) { // NOTE: TC's effect is only noticeable in performance calculations until lazer mods are accounted for server-side. - bool isAlwaysPartiallyVisible = mods.OfType().Any(m => !m.OnlyFadeApproachCircles.Value) || mods.OfType().Any(); + bool isAlwaysPartiallyVisible = mods.OfType().Any(m => m.OnlyFadeApproachCircles.Value) || mods.OfType().Any(); // Start from normal curve, rewarding lower AR up to AR5 double readingBonus = 0.04 * (12.0 - Math.Max(approachRate, 5)); @@ -60,11 +60,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty // For AR up to 0 - reduce reward for very low ARs when object is visible if (approachRate < 5) - readingBonus += (isAlwaysPartiallyVisible ? 0.04 : 0.03) * (5.0 - Math.Max(approachRate, 0)); + readingBonus += (isAlwaysPartiallyVisible ? 0.03 : 0.04) * (5.0 - Math.Max(approachRate, 0)); // Starting from AR0 - cap values so they won't grow to infinity if (approachRate < 0) - readingBonus += (isAlwaysPartiallyVisible ? 0.1 : 0.075) * (1 - Math.Pow(1.5, approachRate)); + readingBonus += (isAlwaysPartiallyVisible ? 0.075 : 0.1) * (1 - Math.Pow(1.5, approachRate)); return readingBonus; } From 28d36dd3bd6d50e713d05bd5ee8ffdd454b4be8e Mon Sep 17 00:00:00 2001 From: James Wilson Date: Fri, 25 Jul 2025 16:47:21 +0100 Subject: [PATCH 39/78] Move rating calculations to `OsuRatingCalculator` (#33265) * Move rating calculations to `OsuRatingCalculator` * Use `CalculateDifficultyRating` --- .../Difficulty/OsuDifficultyCalculator.cs | 200 ++---------------- .../Difficulty/OsuPerformanceCalculator.cs | 4 +- .../Difficulty/OsuRatingCalculator.cs | 199 +++++++++++++++++ 3 files changed, 216 insertions(+), 187 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 513352825f..337bda3221 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -8,7 +8,6 @@ using osu.Game.Beatmaps; using osu.Game.Rulesets.Difficulty; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Skills; -using osu.Game.Rulesets.Difficulty.Utils; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Difficulty.Preprocessing; using osu.Game.Rulesets.Osu.Difficulty.Skills; @@ -23,13 +22,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty public class OsuDifficultyCalculator : DifficultyCalculator { private const double performance_base_multiplier = 1.14; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things. - private const double difficulty_multiplier = 0.0675; private const double star_rating_multiplier = 0.0265; public override int Version => 20250306; - private double mechanicalDifficultyRating; - public OsuDifficultyCalculator(IRulesetInfo ruleset, IWorkingBeatmap beatmap) : base(ruleset, beatmap) { @@ -45,30 +41,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty return multiplier; } - /// - /// Calculates a visibility bonus that is applicable to Hidden and Traceable. - /// - public static double CalculateVisibilityBonus(Mod[] mods, double approachRate, double visibilityFactor = 1) - { - // NOTE: TC's effect is only noticeable in performance calculations until lazer mods are accounted for server-side. - bool isAlwaysPartiallyVisible = mods.OfType().Any(m => m.OnlyFadeApproachCircles.Value) || mods.OfType().Any(); - - // Start from normal curve, rewarding lower AR up to AR5 - double readingBonus = 0.04 * (12.0 - Math.Max(approachRate, 5)); - - readingBonus *= visibilityFactor; - - // For AR up to 0 - reduce reward for very low ARs when object is visible - if (approachRate < 5) - readingBonus += (isAlwaysPartiallyVisible ? 0.03 : 0.04) * (5.0 - Math.Max(approachRate, 0)); - - // Starting from AR0 - cap values so they won't grow to infinity - if (approachRate < 0) - readingBonus += (isAlwaysPartiallyVisible ? 0.075 : 0.1) * (1 - Math.Pow(1.5, approachRate)); - - return readingBonus; - } - public static double CalculateRateAdjustedApproachRate(double approachRate, double clockRate) { double preempt = IBeatmapDifficultyInfo.DifficultyRange(approachRate, OsuHitObject.PREEMPT_MAX, OsuHitObject.PREEMPT_MID, OsuHitObject.PREEMPT_MIN) / clockRate; @@ -125,19 +97,27 @@ namespace osu.Game.Rulesets.Osu.Difficulty double aimNoSlidersDifficultyValue = aimWithoutSliders.DifficultyValue(); double speedDifficultyValue = speed.DifficultyValue(); - mechanicalDifficultyRating = calculateMechanicalDifficultyRating(aimDifficultyValue, speedDifficultyValue); + double mechanicalDifficultyRating = calculateMechanicalDifficultyRating(aimDifficultyValue, speedDifficultyValue); - double aimRating = computeAimRating(aimDifficultyValue, mods, totalHits, approachRate, overallDifficulty); - double aimRatingNoSliders = computeAimRating(aimNoSlidersDifficultyValue, mods, totalHits, approachRate, overallDifficulty); - double speedRating = computeSpeedRating(speedDifficultyValue, mods, totalHits, approachRate, overallDifficulty); + var osuRatingCalculator = new OsuRatingCalculator(mods, totalHits, approachRate, overallDifficulty, mechanicalDifficultyRating); + + double aimRating = osuRatingCalculator.ComputeAimRating(aimDifficultyValue); + double aimRatingNoSliders = osuRatingCalculator.ComputeAimRating(aimNoSlidersDifficultyValue); + double speedRating = osuRatingCalculator.ComputeSpeedRating(speedDifficultyValue); double flashlightRating = 0.0; if (flashlight is not null) - flashlightRating = computeFlashlightRating(flashlight.DifficultyValue(), mods, totalHits, overallDifficulty); + flashlightRating = osuRatingCalculator.ComputeFlashlightRating(flashlight.DifficultyValue()); double sliderFactor = aimRating > 0 ? aimRatingNoSliders / aimRating : 1; + double sliderNestedScorePerObject = LegacyScoreUtils.CalculateNestedScorePerObject(beatmap, totalHits); + double legacyScoreBaseMultiplier = LegacyScoreUtils.CalculateDifficultyPeppyStars(beatmap); + + var simulator = new OsuLegacyScoreSimulator(); + var scoreAttributes = simulator.Simulate(WorkingBeatmap, beatmap); + double baseAimPerformance = OsuStrainSkill.DifficultyToPerformance(aimRating); double baseSpeedPerformance = OsuStrainSkill.DifficultyToPerformance(speedRating); double baseFlashlightPerformance = Flashlight.DifficultyToPerformance(flashlightRating); @@ -152,12 +132,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty double multiplier = CalculateDifficultyMultiplier(mods, totalHits, spinnerCount); double starRating = calculateStarRating(basePerformance, multiplier); - double sliderNestedScorePerObject = LegacyScoreUtils.CalculateNestedScorePerObject(beatmap, totalHits); - double legacyScoreBaseMultiplier = LegacyScoreUtils.CalculateDifficultyPeppyStars(beatmap); - - var simulator = new OsuLegacyScoreSimulator(); - var scoreAttributes = simulator.Simulate(WorkingBeatmap, beatmap); - OsuDifficultyAttributes attributes = new OsuDifficultyAttributes { StarRating = starRating, @@ -185,152 +159,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty return attributes; } - private double computeAimRating(double aimDifficultyValue, Mod[] mods, int totalHits, double approachRate, double overallDifficulty) - { - if (mods.Any(m => m is OsuModAutopilot)) - return 0; - - double aimRating = calculateDifficultyRating(aimDifficultyValue); - - if (mods.Any(m => m is OsuModTouchDevice)) - aimRating = Math.Pow(aimRating, 0.8); - - if (mods.Any(m => m is OsuModRelax)) - aimRating *= 0.9; - - if (mods.Any(m => m is OsuModMagnetised)) - { - float magnetisedStrength = mods.OfType().First().AttractionStrength.Value; - aimRating *= 1.0 - magnetisedStrength; - } - - double ratingMultiplier = 1.0; - - double approachRateLengthBonus = 0.95 + 0.4 * Math.Min(1.0, totalHits / 2000.0) + - (totalHits > 2000 ? Math.Log10(totalHits / 2000.0) * 0.5 : 0.0); - - double approachRateFactor = 0.0; - if (approachRate > 10.33) - approachRateFactor = 0.3 * (approachRate - 10.33); - else if (approachRate < 8.0) - approachRateFactor = 0.05 * (8.0 - approachRate); - - if (mods.Any(h => h is OsuModRelax)) - approachRateFactor = 0.0; - - ratingMultiplier *= 1.0 + approachRateFactor * approachRateLengthBonus; // Buff for longer maps with high AR. - - if (mods.Any(m => m is OsuModHidden)) - { - double visibilityFactor = calculateAimVisibilityFactor(approachRate); - ratingMultiplier *= 1.0 + CalculateVisibilityBonus(mods, approachRate, visibilityFactor); - } - - // It is important to consider accuracy difficulty when scaling with accuracy. - ratingMultiplier *= 0.98 + Math.Pow(Math.Max(0, overallDifficulty), 2) / 2500; - - return aimRating * Math.Cbrt(ratingMultiplier); - } - - private double computeSpeedRating(double speedDifficultyValue, Mod[] mods, int totalHits, double approachRate, double overallDifficulty) - { - if (mods.Any(m => m is OsuModRelax)) - return 0; - - double speedRating = calculateDifficultyRating(speedDifficultyValue); - - if (mods.Any(m => m is OsuModAutopilot)) - speedRating *= 0.5; - - if (mods.Any(m => m is OsuModMagnetised)) - { - // reduce speed rating because of the speed distance scaling, with maximum reduction being 0.7x - float magnetisedStrength = mods.OfType().First().AttractionStrength.Value; - speedRating *= 1.0 - magnetisedStrength * 0.3; - } - - double ratingMultiplier = 1.0; - - double approachRateLengthBonus = 0.95 + 0.4 * Math.Min(1.0, totalHits / 2000.0) + - (totalHits > 2000 ? Math.Log10(totalHits / 2000.0) * 0.5 : 0.0); - - double approachRateFactor = 0.0; - if (approachRate > 10.33) - approachRateFactor = 0.3 * (approachRate - 10.33); - - if (mods.Any(m => m is OsuModAutopilot)) - approachRateFactor = 0.0; - - ratingMultiplier *= 1.0 + approachRateFactor * approachRateLengthBonus; // Buff for longer maps with high AR. - - if (mods.Any(m => m is OsuModHidden)) - { - double visibilityFactor = calculateSpeedVisibilityFactor(approachRate); - ratingMultiplier *= 1.0 + CalculateVisibilityBonus(mods, approachRate, visibilityFactor); - } - - ratingMultiplier *= 0.95 + Math.Pow(Math.Max(0, overallDifficulty), 2) / 750; - - return speedRating * Math.Cbrt(ratingMultiplier); - } - - private double computeFlashlightRating(double flashlightDifficultyValue, Mod[] mods, int totalHits, double overallDifficulty) - { - if (!mods.Any(m => m is OsuModFlashlight)) - return 0; - - double flashlightRating = calculateDifficultyRating(flashlightDifficultyValue); - - if (mods.Any(m => m is OsuModTouchDevice)) - flashlightRating = Math.Pow(flashlightRating, 0.8); - - if (mods.Any(m => m is OsuModRelax)) - flashlightRating *= 0.7; - else if (mods.Any(m => m is OsuModAutopilot)) - flashlightRating *= 0.4; - - if (mods.Any(m => m is OsuModMagnetised)) - { - float magnetisedStrength = mods.OfType().First().AttractionStrength.Value; - flashlightRating *= 1.0 - magnetisedStrength; - } - - double ratingMultiplier = 1.0; - - // Account for shorter maps having a higher ratio of 0 combo/100 combo flashlight radius. - ratingMultiplier *= 0.7 + 0.1 * Math.Min(1.0, totalHits / 200.0) + - (totalHits > 200 ? 0.2 * Math.Min(1.0, (totalHits - 200) / 200.0) : 0.0); - - // It is important to consider accuracy difficulty when scaling with accuracy. - ratingMultiplier *= 0.98 + Math.Pow(Math.Max(0, overallDifficulty), 2) / 2500; - - return flashlightRating * Math.Sqrt(ratingMultiplier); - } - - private double calculateAimVisibilityFactor(double approachRate) - { - const double ar_factor_end_point = 11.5; - - double mechanicalDifficultyFactor = DifficultyCalculationUtils.ReverseLerp(mechanicalDifficultyRating, 5, 10); - double arFactorStartingPoint = double.Lerp(9, 10.33, mechanicalDifficultyFactor); - - return DifficultyCalculationUtils.ReverseLerp(approachRate, ar_factor_end_point, arFactorStartingPoint); - } - - private double calculateSpeedVisibilityFactor(double approachRate) - { - const double ar_factor_end_point = 11.5; - - double mechanicalDifficultyFactor = DifficultyCalculationUtils.ReverseLerp(mechanicalDifficultyRating, 5, 10); - double arFactorStartingPoint = double.Lerp(10, 10.33, mechanicalDifficultyFactor); - - return DifficultyCalculationUtils.ReverseLerp(approachRate, ar_factor_end_point, arFactorStartingPoint); - } - private static double calculateMechanicalDifficultyRating(double aimDifficultyValue, double speedDifficultyValue) { - double aimValue = OsuStrainSkill.DifficultyToPerformance(calculateDifficultyRating(aimDifficultyValue)); - double speedValue = OsuStrainSkill.DifficultyToPerformance(calculateDifficultyRating(speedDifficultyValue)); + double aimValue = OsuStrainSkill.DifficultyToPerformance(OsuRatingCalculator.CalculateDifficultyRating(aimDifficultyValue)); + double speedValue = OsuStrainSkill.DifficultyToPerformance(OsuRatingCalculator.CalculateDifficultyRating(speedDifficultyValue)); double totalValue = Math.Pow(Math.Pow(aimValue, 1.1) + Math.Pow(speedValue, 1.1), 1 / 1.1); @@ -345,8 +177,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty return Math.Cbrt(multiplier) * star_rating_multiplier * (Math.Cbrt(100000 / Math.Pow(2, 1 / 1.1) * basePerformance) + 4); } - private static double calculateDifficultyRating(double difficultyValue) => Math.Sqrt(difficultyValue) * difficulty_multiplier; - protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) { List objects = new List(); diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 49626eb7b6..11e9714ed8 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -209,7 +209,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty aimValue *= 1.3 + (totalHits * (0.0016 / (1 + 2 * effectiveMissCount)) * Math.Pow(accuracy, 16)) * (1 - 0.003 * attributes.DrainRate * attributes.DrainRate); else if (score.Mods.Any(m => m is OsuModTraceable)) { - aimValue *= 1.0 + OsuDifficultyCalculator.CalculateVisibilityBonus(score.Mods, approachRate); + aimValue *= 1.0 + OsuRatingCalculator.CalculateVisibilityBonus(score.Mods, approachRate); } aimValue *= accuracy; @@ -245,7 +245,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty } else if (score.Mods.Any(m => m is OsuModTraceable)) { - speedValue *= 1.0 + OsuDifficultyCalculator.CalculateVisibilityBonus(score.Mods, approachRate); + speedValue *= 1.0 + OsuRatingCalculator.CalculateVisibilityBonus(score.Mods, approachRate); } double speedHighDeviationMultiplier = calculateSpeedHighDeviationNerf(attributes); diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs new file mode 100644 index 0000000000..e505ed07e4 --- /dev/null +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs @@ -0,0 +1,199 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Linq; +using osu.Game.Rulesets.Difficulty.Utils; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.Osu.Mods; + +namespace osu.Game.Rulesets.Osu.Difficulty +{ + public class OsuRatingCalculator + { + private const double difficulty_multiplier = 0.0675; + + private readonly Mod[] mods; + private readonly int totalHits; + private readonly double approachRate; + private readonly double overallDifficulty; + private readonly double mechanicalDifficultyRating; + + public OsuRatingCalculator(Mod[] mods, int totalHits, double approachRate, double overallDifficulty, double mechanicalDifficultyRating) + { + this.mods = mods; + this.totalHits = totalHits; + this.approachRate = approachRate; + this.overallDifficulty = overallDifficulty; + this.mechanicalDifficultyRating = mechanicalDifficultyRating; + } + + public double ComputeAimRating(double aimDifficultyValue) + { + if (mods.Any(m => m is OsuModAutopilot)) + return 0; + + double aimRating = CalculateDifficultyRating(aimDifficultyValue); + + if (mods.Any(m => m is OsuModTouchDevice)) + aimRating = Math.Pow(aimRating, 0.8); + + if (mods.Any(m => m is OsuModRelax)) + aimRating *= 0.9; + + if (mods.Any(m => m is OsuModMagnetised)) + { + float magnetisedStrength = mods.OfType().First().AttractionStrength.Value; + aimRating *= 1.0 - magnetisedStrength; + } + + double ratingMultiplier = 1.0; + + double approachRateLengthBonus = 0.95 + 0.4 * Math.Min(1.0, totalHits / 2000.0) + + (totalHits > 2000 ? Math.Log10(totalHits / 2000.0) * 0.5 : 0.0); + + double approachRateFactor = 0.0; + if (approachRate > 10.33) + approachRateFactor = 0.3 * (approachRate - 10.33); + else if (approachRate < 8.0) + approachRateFactor = 0.05 * (8.0 - approachRate); + + if (mods.Any(h => h is OsuModRelax)) + approachRateFactor = 0.0; + + ratingMultiplier *= 1.0 + approachRateFactor * approachRateLengthBonus; // Buff for longer maps with high AR. + + if (mods.Any(m => m is OsuModHidden)) + { + double visibilityFactor = calculateAimVisibilityFactor(approachRate); + ratingMultiplier *= 1.0 + CalculateVisibilityBonus(mods, approachRate, visibilityFactor); + } + + // It is important to consider accuracy difficulty when scaling with accuracy. + ratingMultiplier *= 0.98 + Math.Pow(Math.Max(0, overallDifficulty), 2) / 2500; + + return aimRating * Math.Cbrt(ratingMultiplier); + } + + public double ComputeSpeedRating(double speedDifficultyValue) + { + if (mods.Any(m => m is OsuModRelax)) + return 0; + + double speedRating = CalculateDifficultyRating(speedDifficultyValue); + + if (mods.Any(m => m is OsuModAutopilot)) + speedRating *= 0.5; + + if (mods.Any(m => m is OsuModMagnetised)) + { + // reduce speed rating because of the speed distance scaling, with maximum reduction being 0.7x + float magnetisedStrength = mods.OfType().First().AttractionStrength.Value; + speedRating *= 1.0 - magnetisedStrength * 0.3; + } + + double ratingMultiplier = 1.0; + + double approachRateLengthBonus = 0.95 + 0.4 * Math.Min(1.0, totalHits / 2000.0) + + (totalHits > 2000 ? Math.Log10(totalHits / 2000.0) * 0.5 : 0.0); + + double approachRateFactor = 0.0; + if (approachRate > 10.33) + approachRateFactor = 0.3 * (approachRate - 10.33); + + if (mods.Any(m => m is OsuModAutopilot)) + approachRateFactor = 0.0; + + ratingMultiplier *= 1.0 + approachRateFactor * approachRateLengthBonus; // Buff for longer maps with high AR. + + if (mods.Any(m => m is OsuModHidden)) + { + double visibilityFactor = calculateSpeedVisibilityFactor(approachRate); + ratingMultiplier *= 1.0 + CalculateVisibilityBonus(mods, approachRate, visibilityFactor); + } + + ratingMultiplier *= 0.95 + Math.Pow(Math.Max(0, overallDifficulty), 2) / 750; + + return speedRating * Math.Cbrt(ratingMultiplier); + } + + public double ComputeFlashlightRating(double flashlightDifficultyValue) + { + if (!mods.Any(m => m is OsuModFlashlight)) + return 0; + + double flashlightRating = CalculateDifficultyRating(flashlightDifficultyValue); + + if (mods.Any(m => m is OsuModTouchDevice)) + flashlightRating = Math.Pow(flashlightRating, 0.8); + + if (mods.Any(m => m is OsuModRelax)) + flashlightRating *= 0.7; + else if (mods.Any(m => m is OsuModAutopilot)) + flashlightRating *= 0.4; + + if (mods.Any(m => m is OsuModMagnetised)) + { + float magnetisedStrength = mods.OfType().First().AttractionStrength.Value; + flashlightRating *= 1.0 - magnetisedStrength; + } + + double ratingMultiplier = 1.0; + + // Account for shorter maps having a higher ratio of 0 combo/100 combo flashlight radius. + ratingMultiplier *= 0.7 + 0.1 * Math.Min(1.0, totalHits / 200.0) + + (totalHits > 200 ? 0.2 * Math.Min(1.0, (totalHits - 200) / 200.0) : 0.0); + + // It is important to consider accuracy difficulty when scaling with accuracy. + ratingMultiplier *= 0.98 + Math.Pow(Math.Max(0, overallDifficulty), 2) / 2500; + + return flashlightRating * Math.Sqrt(ratingMultiplier); + } + + private double calculateAimVisibilityFactor(double approachRate) + { + const double ar_factor_end_point = 11.5; + + double mechanicalDifficultyFactor = DifficultyCalculationUtils.ReverseLerp(mechanicalDifficultyRating, 5, 10); + double arFactorStartingPoint = double.Lerp(9, 10.33, mechanicalDifficultyFactor); + + return DifficultyCalculationUtils.ReverseLerp(approachRate, ar_factor_end_point, arFactorStartingPoint); + } + + private double calculateSpeedVisibilityFactor(double approachRate) + { + const double ar_factor_end_point = 11.5; + + double mechanicalDifficultyFactor = DifficultyCalculationUtils.ReverseLerp(mechanicalDifficultyRating, 5, 10); + double arFactorStartingPoint = double.Lerp(10, 10.33, mechanicalDifficultyFactor); + + return DifficultyCalculationUtils.ReverseLerp(approachRate, ar_factor_end_point, arFactorStartingPoint); + } + + /// + /// Calculates a visibility bonus that is applicable to Hidden and Traceable. + /// + public static double CalculateVisibilityBonus(Mod[] mods, double approachRate, double visibilityFactor = 1) + { + // NOTE: TC's effect is only noticeable in performance calculations until lazer mods are accounted for server-side. + bool isAlwaysPartiallyVisible = mods.OfType().Any(m => m.OnlyFadeApproachCircles.Value) || mods.OfType().Any(); + + // Start from normal curve, rewarding lower AR up to AR5 + double readingBonus = 0.04 * (12.0 - Math.Max(approachRate, 5)); + + readingBonus *= visibilityFactor; + + // For AR up to 0 - reduce reward for very low ARs when object is visible + if (approachRate < 5) + readingBonus += (isAlwaysPartiallyVisible ? 0.03 : 0.04) * (5.0 - Math.Max(approachRate, 0)); + + // Starting from AR0 - cap values so they won't grow to infinity + if (approachRate < 0) + readingBonus += (isAlwaysPartiallyVisible ? 0.075 : 0.1) * (1 - Math.Pow(1.5, approachRate)); + + return readingBonus; + } + + public static double CalculateDifficultyRating(double difficultyValue) => Math.Sqrt(difficultyValue) * difficulty_multiplier; + } +} From 83765abe34da7f0e980dea3e3de6fceeeb88afe4 Mon Sep 17 00:00:00 2001 From: StanR Date: Sat, 26 Jul 2025 00:51:30 +0500 Subject: [PATCH 40/78] Make visibility-based bonuses be additive to `ratingMultiplier` instead of multiplicative (#34367) * Make visibility-based bonuses be additive to `ratingMultiplier` instead of multiplicative * Slightly buff low AR HD, slightly nerf low AR TC --- .../Difficulty/OsuRatingCalculator.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs index e505ed07e4..5d51eee1ba 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs @@ -61,12 +61,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (mods.Any(h => h is OsuModRelax)) approachRateFactor = 0.0; - ratingMultiplier *= 1.0 + approachRateFactor * approachRateLengthBonus; // Buff for longer maps with high AR. + ratingMultiplier += approachRateFactor * approachRateLengthBonus; // Buff for longer maps with high AR. if (mods.Any(m => m is OsuModHidden)) { double visibilityFactor = calculateAimVisibilityFactor(approachRate); - ratingMultiplier *= 1.0 + CalculateVisibilityBonus(mods, approachRate, visibilityFactor); + ratingMultiplier += CalculateVisibilityBonus(mods, approachRate, visibilityFactor); } // It is important to consider accuracy difficulty when scaling with accuracy. @@ -104,12 +104,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (mods.Any(m => m is OsuModAutopilot)) approachRateFactor = 0.0; - ratingMultiplier *= 1.0 + approachRateFactor * approachRateLengthBonus; // Buff for longer maps with high AR. + ratingMultiplier += approachRateFactor * approachRateLengthBonus; // Buff for longer maps with high AR. if (mods.Any(m => m is OsuModHidden)) { double visibilityFactor = calculateSpeedVisibilityFactor(approachRate); - ratingMultiplier *= 1.0 + CalculateVisibilityBonus(mods, approachRate, visibilityFactor); + ratingMultiplier += CalculateVisibilityBonus(mods, approachRate, visibilityFactor); } ratingMultiplier *= 0.95 + Math.Pow(Math.Max(0, overallDifficulty), 2) / 750; @@ -178,14 +178,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty // NOTE: TC's effect is only noticeable in performance calculations until lazer mods are accounted for server-side. bool isAlwaysPartiallyVisible = mods.OfType().Any(m => m.OnlyFadeApproachCircles.Value) || mods.OfType().Any(); - // Start from normal curve, rewarding lower AR up to AR5 - double readingBonus = 0.04 * (12.0 - Math.Max(approachRate, 5)); + // Start from normal curve, rewarding lower AR up to AR7 + double readingBonus = 0.04 * (12.0 - Math.Max(approachRate, 7)); readingBonus *= visibilityFactor; // For AR up to 0 - reduce reward for very low ARs when object is visible - if (approachRate < 5) - readingBonus += (isAlwaysPartiallyVisible ? 0.03 : 0.04) * (5.0 - Math.Max(approachRate, 0)); + if (approachRate < 7) + readingBonus += (isAlwaysPartiallyVisible ? 0.03 : 0.045) * (7.0 - Math.Max(approachRate, 0)); // Starting from AR0 - cap values so they won't grow to infinity if (approachRate < 0) From e54779ceee3d4d1450ac90bc10c8c2b9e8389393 Mon Sep 17 00:00:00 2001 From: Jay Lawton Date: Mon, 28 Jul 2025 00:31:46 +1000 Subject: [PATCH 41/78] Fix colour penalties being bypassed via repeated ratio variance (#33641) * fix a lil bit of colour * review comments * fix empty initialiser --- .../Difficulty/Evaluators/ColourEvaluator.cs | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs index b715dfc37a..d8d30e3fef 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Evaluators/ColourEvaluator.cs @@ -2,6 +2,8 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; +using System.Linq; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Utils; using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; @@ -24,7 +26,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators int consistentRatioCount = 0; double totalRatioCount = 0.0; + List recentRatios = new List(); TaikoDifficultyHitObject current = hitObject; + var previousHitObject = (TaikoDifficultyHitObject)current.Previous(1); for (int i = 0; i < maxObjectsToCheck; i++) { @@ -32,11 +36,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators if (current.Index <= 1) break; - var previousHitObject = (TaikoDifficultyHitObject)current.Previous(1); - double currentRatio = current.RhythmData.Ratio; double previousRatio = previousHitObject.RhythmData.Ratio; + recentRatios.Add(currentRatio); + // A consistent interval is defined as the percentage difference between the two rhythmic ratios with the margin of error. if (Math.Abs(1 - currentRatio / previousRatio) <= threshold) { @@ -45,14 +49,21 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Evaluators break; } - // Move to the previous object current = previousHitObject; } // Ensure no division by zero - double ratioPenalty = 1 - totalRatioCount / (consistentRatioCount + 1) * 0.80; + if (consistentRatioCount > 0) + return 1 - totalRatioCount / (consistentRatioCount + 1) * 0.80; - return ratioPenalty; + if (recentRatios.Count <= 1) return 1.0; + + // As a fallback, calculate the maximum deviation from the average of the recent ratios to ensure slightly off-snapped objects don't bypass the penalty. + double maxRatioDeviation = recentRatios.Max(r => Math.Abs(r - recentRatios.Average())); + + double consistentRatioPenalty = 0.7 + 0.3 * DifficultyCalculationUtils.Smootherstep(maxRatioDeviation, 0.0, 1.0); + + return consistentRatioPenalty; } /// From 803e30f50fd7ff37fb79ec27eb9a230e1936384a Mon Sep 17 00:00:00 2001 From: Eloise Date: Mon, 28 Jul 2025 15:58:54 +0200 Subject: [PATCH 42/78] osu!taiko consistency factor changes using object strains (#34327) * Calculate consistency factor from object strains * Use `totalDifficultHits` in performance calc --------- Co-authored-by: James Wilson --- .../Difficulty/TaikoDifficultyCalculator.cs | 90 +++++++++---------- .../Difficulty/TaikoPerformanceAttributes.cs | 3 - .../Difficulty/TaikoPerformanceCalculator.cs | 24 ++--- .../Rulesets/Difficulty/Skills/StrainSkill.cs | 2 + 4 files changed, 54 insertions(+), 65 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index 9e265a3cc6..d2229e9786 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -31,6 +31,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty private double strainLengthBonus; private double patternMultiplier; + private bool isRelax; private bool isConvert; public override int Version => 20250306; @@ -46,6 +47,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty hitWindows.SetDifficulty(beatmap.Difficulty.OverallDifficulty); isConvert = beatmap.BeatmapInfo.Ruleset.OnlineID == 0; + isRelax = mods.Any(h => h is TaikoModRelax); return new Skill[] { @@ -100,8 +102,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty if (beatmap.HitObjects.Count == 0) return new TaikoDifficultyAttributes { Mods = mods }; - bool isRelax = mods.Any(h => h is TaikoModRelax); - var rhythm = skills.OfType().Single(); var reading = skills.OfType().Single(); var colour = skills.OfType().Single(); @@ -122,7 +122,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty strainLengthBonus = 1 + 0.15 * DifficultyCalculationUtils.ReverseLerp(staminaDifficultStrains, 1000, 1555); - double combinedRating = combinedDifficultyValue(rhythm, reading, colour, stamina, isRelax, isConvert, out double consistencyFactor); + double combinedRating = combinedDifficultyValue(rhythm, reading, colour, stamina, out double consistencyFactor); double starRating = rescale(combinedRating * 1.4); // Calculate proportional contribution of each skill to the combinedRating. @@ -159,14 +159,47 @@ namespace osu.Game.Rulesets.Taiko.Difficulty /// For each section, the peak strains of all separate skills are combined into a single peak strain for the section. /// The resulting partial rating of the beatmap is a weighted sum of the combined peaks (higher peaks are weighted more). /// - private double combinedDifficultyValue(Rhythm rhythm, Reading reading, Colour colour, Stamina stamina, bool isRelax, bool isConvert, out double consistencyFactor) + private double combinedDifficultyValue(Rhythm rhythm, Reading reading, Colour colour, Stamina stamina, out double consistencyFactor) { - List peaks = new List(); + List peaks = combinePeaks( + rhythm.GetCurrentStrainPeaks().ToList(), + reading.GetCurrentStrainPeaks().ToList(), + colour.GetCurrentStrainPeaks().ToList(), + stamina.GetCurrentStrainPeaks().ToList() + ); - var rhythmPeaks = rhythm.GetCurrentStrainPeaks().ToList(); - var readingPeaks = reading.GetCurrentStrainPeaks().ToList(); - var colourPeaks = colour.GetCurrentStrainPeaks().ToList(); - var staminaPeaks = stamina.GetCurrentStrainPeaks().ToList(); + double difficulty = 0; + double weight = 1; + + foreach (double strain in peaks.OrderDescending()) + { + difficulty += strain * weight; + weight *= 0.9; + } + + List hitObjectStrainPeaks = combinePeaks( + rhythm.GetObjectStrains().ToList(), + reading.GetObjectStrains().ToList(), + colour.GetObjectStrains().ToList(), + stamina.GetObjectStrains().ToList() + ); + + // The average of the top 5% of strain peaks from hit objects. + double topAverageHitObjectStrain = hitObjectStrainPeaks.OrderDescending().Take(1 + hitObjectStrainPeaks.Count / 20).Average(); + + // Calculates a consistency factor as the sum of difficulty from hit objects compared to if every object were as hard as the hardest. + // The top average strain is used instead of the very hardest to prevent exceptionally hard objects lowering the factor. + consistencyFactor = hitObjectStrainPeaks.Sum() / (topAverageHitObjectStrain * hitObjectStrainPeaks.Count); + + return difficulty; + } + + /// + /// Combines lists of peak strains from multiple skills into a list of single peak strains for each section. + /// + private List combinePeaks(List rhythmPeaks, List readingPeaks, List colourPeaks, List staminaPeaks) + { + var combinedPeaks = new List(); for (int i = 0; i < colourPeaks.Count; i++) { @@ -181,45 +214,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty // Sections with 0 strain are excluded to avoid worst-case time complexity of the following sort (e.g. /b/2351871). // These sections will not contribute to the difficulty. if (peak > 0) - peaks.Add(peak); + combinedPeaks.Add(peak); } - double difficulty = 0; - double weight = 1; - - foreach (double strain in peaks.OrderDescending()) - { - difficulty += strain * weight; - weight *= 0.9; - } - - consistencyFactor = calculateConsistencyFactor(peaks); - - return difficulty; - } - - /// - /// Calculates a consistency factor based on how 'spiked' the strain peaks are. - /// Higher values indicate more consistent difficulty, lower values indicate diff-spike heavy maps. - /// - private double calculateConsistencyFactor(List peaks) - { - // If there are too few sections in a map, assume it is consistent. - if (peaks.Count < 3) - return 1.0; - - List sorted = peaks.OrderDescending().ToList(); - - double topPeak = sorted[0]; - double secondTopPeak = sorted.Count > 1 ? sorted[1] : topPeak; - - // Compute the average of the middle 50% of strain values. - double midAvg = sorted.Skip(sorted.Count / 4).Take(sorted.Count / 2).Average(); - - // A higher ratio means the top sections are much harder than the average, indicating inconsistency. - double spikeSeverity = (topPeak + secondTopPeak) / 2.0 / midAvg; - - return 1.0 / spikeSeverity; + return combinedPeaks; } /// diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceAttributes.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceAttributes.cs index 7c74e43db1..ef40c2e58b 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceAttributes.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceAttributes.cs @@ -15,9 +15,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty [JsonProperty("accuracy")] public double Accuracy { get; set; } - [JsonProperty("effective_miss_count")] - public double EffectiveMissCount { get; set; } - [JsonProperty("estimated_unstable_rate")] public double? EstimatedUnstableRate { get; set; } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index 2633218f7d..b510c8a796 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty private double clockRate; private double greatHitWindow; - private double effectiveMissCount; + private double totalDifficultHits; public TaikoPerformanceCalculator() : base(new TaikoRuleset()) @@ -56,12 +56,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty estimatedUnstableRate = computeDeviationUpperBound() * 10; - // Effective miss count is calculated by raising the fraction of hits missed to a power based on the map's consistency factor. - // This is because in less consistently difficult maps, each miss removes more of the map's total difficulty. - effectiveMissCount = totalHits * Math.Pow( - (double)countMiss / totalHits, - Math.Pow(taikoAttributes.ConsistencyFactor, 0.2) - ); + // Total difficult hits measures the total difficulty of a map based on its consistency factor. + totalDifficultHits = totalHits * taikoAttributes.ConsistencyFactor; // Converts are detected and omitted from mod-specific bonuses due to the scope of current difficulty calculation. bool isConvert = score.BeatmapInfo!.Ruleset.OnlineID != 1; @@ -73,7 +69,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty { Difficulty = difficultyValue, Accuracy = accuracyValue, - EffectiveMissCount = effectiveMissCount, EstimatedUnstableRate = estimatedUnstableRate, Total = difficultyValue + accuracyValue }; @@ -86,14 +81,13 @@ namespace osu.Game.Rulesets.Taiko.Difficulty difficultyValue *= 1 + 0.10 * Math.Max(0, attributes.StarRating - 10); - // Applies a bonus to maps with more total difficulty, calculating this with a map's total hits and consistency factor. - double totalDifficultHits = totalHits * Math.Pow(attributes.ConsistencyFactor, 0.5); + // Applies a bonus to maps with more total difficulty. double lengthBonus = 1 + 0.25 * totalDifficultHits / (totalDifficultHits + 4000); difficultyValue *= lengthBonus; - // Scales miss penalty by the total hits of a map, making misses more punishing on maps with fewer objects. - double missPenalty = Math.Pow(0.5, 30.0 / totalHits); - difficultyValue *= Math.Pow(missPenalty, effectiveMissCount); + // Scales miss penalty by the total difficult hits of a map, making misses more punishing on maps with less total difficulty. + double missPenalty = Math.Pow(0.5, 30.0 / totalDifficultHits); + difficultyValue *= Math.Pow(missPenalty, countMiss); if (score.Mods.Any(m => m is ModHidden)) difficultyValue *= (isConvert) ? 1.025 : 1.1; @@ -122,9 +116,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty accuracyValue *= 1.075; // Applies a bonus to maps with more total difficulty, calculating this with a map's total hits and consistency factor. - double totalDifficultHits = totalHits * Math.Pow(attributes.ConsistencyFactor, 0.5); - double lengthBonus = 1 + 0.4 * totalDifficultHits / (totalDifficultHits + 4000); - accuracyValue *= lengthBonus; + accuracyValue *= 1 + 0.4 * totalDifficultHits / (totalDifficultHits + 4000); // Applies a bonus to maps with more total memory required with HDFL. double memoryLengthBonus = Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3)); diff --git a/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs b/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs index 3ba67793dc..b6272bf56b 100644 --- a/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs +++ b/osu.Game/Rulesets/Difficulty/Skills/StrainSkill.cs @@ -116,6 +116,8 @@ namespace osu.Game.Rulesets.Difficulty.Skills /// public IEnumerable GetCurrentStrainPeaks() => strainPeaks.Append(currentSectionPeak); + public IEnumerable GetObjectStrains() => ObjectStrains; + /// /// Returns the calculated difficulty value representing all s that have been processed up to this point. /// From eaaca60b1dbb95b7029f699e761c1fc34e69c649 Mon Sep 17 00:00:00 2001 From: Eloise Date: Tue, 29 Jul 2025 20:03:13 +0200 Subject: [PATCH 43/78] osu!taiko new acc pp formula + rhythm difficulty penalty (#34188) * New acc curve * Penalise rhythm difficulty based on unstable rate * Rename mono acc stuff for more clarity * Fix nullable * Rename stuff * Get actual estimation for SS unstable rate * Double space my bad --------- Co-authored-by: James Wilson --- .../Difficulty/TaikoPerformanceCalculator.cs | 47 +++++++++++++------ 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index b510c8a796..fb106caf39 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -54,7 +54,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty greatHitWindow = hitWindows.WindowFor(HitResult.Great) / clockRate; - estimatedUnstableRate = computeDeviationUpperBound() * 10; + estimatedUnstableRate = (countGreat == 0 || greatHitWindow <= 0) + ? null + : computeDeviationUpperBound(countGreat / (double)totalHits) * 10; // Total difficult hits measures the total difficulty of a map based on its consistency factor. totalDifficultHits = totalHits * taikoAttributes.ConsistencyFactor; @@ -76,7 +78,27 @@ namespace osu.Game.Rulesets.Taiko.Difficulty private double computeDifficultyValue(ScoreInfo score, TaikoDifficultyAttributes attributes, bool isConvert) { - double baseDifficulty = 5 * Math.Max(1.0, attributes.StarRating / 0.110) - 4.0; + if (estimatedUnstableRate == null) + return 0; + + // The estimated unstable rate for 100% accuracy, at which all rhythm difficulty has been played successfully. + double rhythmExpectedUnstableRate = computeDeviationUpperBound(1.0) * 10; + + // The unstable rate at which it can be assumed all rhythm difficulty has been ignored. + double rhythmMaximumUnstableRate = 2 * rhythmExpectedUnstableRate; + + // The fraction of star rating made up by rhythm difficulty, normalised to represent rhythm's perceived contribution to star rating. + double rhythmFactor = DifficultyCalculationUtils.ReverseLerp(attributes.RhythmDifficulty / attributes.StarRating, 0.15, 0.35); + + // A penalty removing improperly played rhythm difficulty from star rating based on estimated unstable rate. + double rhythmPenalty = 1 - DifficultyCalculationUtils.Logistic( + estimatedUnstableRate.Value, + midpointOffset: (rhythmExpectedUnstableRate + rhythmMaximumUnstableRate) / 2, + multiplier: 10 / (rhythmMaximumUnstableRate - rhythmExpectedUnstableRate), + maxValue: 0.2 * Math.Pow(rhythmFactor, 2) + ); + + double baseDifficulty = 5 * Math.Max(1.0, attributes.StarRating * rhythmPenalty / 0.110) - 4.0; double difficultyValue = Math.Min(Math.Pow(baseDifficulty, 3) / 69052.51, Math.Pow(baseDifficulty, 2.25) / 1250.0); difficultyValue *= 1 + 0.10 * Math.Max(0, attributes.StarRating - 10); @@ -95,14 +117,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty if (score.Mods.Any(m => m is ModFlashlight)) difficultyValue *= Math.Max(1, 1.050 - Math.Min(attributes.MonoStaminaFactor / 50, 1) * lengthBonus); - if (estimatedUnstableRate == null) - return 0; - // Scale accuracy more harshly on nearly-completely mono (single coloured) speed maps. - double accScalingExponent = 2 + attributes.MonoStaminaFactor; - double accScalingShift = 500 - 100 * (attributes.MonoStaminaFactor * 3); + double monoAccScalingExponent = 2 + attributes.MonoStaminaFactor; + double monoAccScalingShift = 500 - 100 * (attributes.MonoStaminaFactor * 3); - return difficultyValue * Math.Pow(DifficultyCalculationUtils.Erf(accScalingShift / (Math.Sqrt(2) * estimatedUnstableRate.Value)), accScalingExponent); + return difficultyValue * Math.Pow(DifficultyCalculationUtils.Erf(monoAccScalingShift / (Math.Sqrt(2) * estimatedUnstableRate.Value)), monoAccScalingExponent); } private double computeAccuracyValue(ScoreInfo score, TaikoDifficultyAttributes attributes, bool isConvert) @@ -110,7 +129,10 @@ namespace osu.Game.Rulesets.Taiko.Difficulty if (greatHitWindow <= 0 || estimatedUnstableRate == null) return 0; - double accuracyValue = Math.Pow(70 / estimatedUnstableRate.Value, 1.1) * Math.Pow(attributes.StarRating, 0.4) * 100.0; + double accuracyValue = 470 * Math.Pow(0.9885, estimatedUnstableRate.Value); + + // Scales up the bonus for lower unstable rate as star rating increases. + accuracyValue *= 1 + Math.Pow(50 / estimatedUnstableRate.Value, 2) * Math.Pow(attributes.StarRating, 2) / 125; if (score.Mods.Any(m => m is ModHidden) && !isConvert) accuracyValue *= 1.075; @@ -132,17 +154,14 @@ namespace osu.Game.Rulesets.Taiko.Difficulty /// and the hit judgements, assuming the player's mean hit error is 0. The estimation is consistent in that /// two SS scores on the same map with the same settings will always return the same deviation. /// - private double? computeDeviationUpperBound() + private double computeDeviationUpperBound(double accuracy) { - if (countGreat == 0 || greatHitWindow <= 0) - return null; - const double z = 2.32634787404; // 99% critical value for the normal distribution (one-tailed). double n = totalHits; // Proportion of greats hit. - double p = countGreat / n; + double p = accuracy; // We can be 99% confident that p is at least this value. double pLowerBound = (n * p + z * z / 2) / (n + z * z) - z / (n + z * z) * Math.Sqrt(n * p * (1 - p) + z * z / 4); From dbb16fc83487a01a3f8c31852977e2025744fc2d Mon Sep 17 00:00:00 2001 From: Eloise Date: Wed, 30 Jul 2025 21:48:45 +0200 Subject: [PATCH 44/78] osu!taiko reduce multiplier for hidden on lazer (#34089) * Reduce multiplier for hidden on lazer * Refactor * Quality * The space --- .../Difficulty/TaikoPerformanceCalculator.cs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index fb106caf39..27ba31d918 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -61,10 +61,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty // Total difficult hits measures the total difficulty of a map based on its consistency factor. totalDifficultHits = totalHits * taikoAttributes.ConsistencyFactor; - // Converts are detected and omitted from mod-specific bonuses due to the scope of current difficulty calculation. + // Converts and the classic mod are detected and omitted from mod-specific bonuses due to the scope of current difficulty calculation. bool isConvert = score.BeatmapInfo!.Ruleset.OnlineID != 1; + bool isClassic = score.Mods.Any(m => m is ModClassic); - double difficultyValue = computeDifficultyValue(score, taikoAttributes, isConvert) * 1.08; + double difficultyValue = computeDifficultyValue(score, taikoAttributes, isConvert, isClassic) * 1.08; double accuracyValue = computeAccuracyValue(score, taikoAttributes, isConvert) * 1.1; return new TaikoPerformanceAttributes @@ -76,7 +77,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty }; } - private double computeDifficultyValue(ScoreInfo score, TaikoDifficultyAttributes attributes, bool isConvert) + private double computeDifficultyValue(ScoreInfo score, TaikoDifficultyAttributes attributes, bool isConvert, bool isClassic) { if (estimatedUnstableRate == null) return 0; @@ -112,7 +113,15 @@ namespace osu.Game.Rulesets.Taiko.Difficulty difficultyValue *= Math.Pow(missPenalty, countMiss); if (score.Mods.Any(m => m is ModHidden)) - difficultyValue *= (isConvert) ? 1.025 : 1.1; + { + double hiddenBonus = isConvert ? 0.025 : 0.1; + + // A penalty is applied to the bonus for hidden on non-classic scores, as the playfield can be made wider to make fast reading easier. + if (!isClassic) + hiddenBonus *= 0.2; + + difficultyValue *= 1 + hiddenBonus; + } if (score.Mods.Any(m => m is ModFlashlight)) difficultyValue *= Math.Max(1, 1.050 - Math.Min(attributes.MonoStaminaFactor / 50, 1) * lengthBonus); From 802e5594724c1e7bea0ddeb474210b23b515b854 Mon Sep 17 00:00:00 2001 From: StanR Date: Wed, 6 Aug 2025 21:10:00 +0500 Subject: [PATCH 45/78] Add DF flashlight rating reduction (#34081) * Add DF flashlight rating reduction * Use reverse lerp --- osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs index 5d51eee1ba..8793582847 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs @@ -138,6 +138,12 @@ namespace osu.Game.Rulesets.Osu.Difficulty flashlightRating *= 1.0 - magnetisedStrength; } + if (mods.Any(m => m is OsuModDeflate)) + { + float deflateInitialScale = mods.OfType().First().StartScale.Value; + flashlightRating *= Math.Clamp(DifficultyCalculationUtils.ReverseLerp(deflateInitialScale, 11, 1), 0.1, 1); + } + double ratingMultiplier = 1.0; // Account for shorter maps having a higher ratio of 0 combo/100 combo flashlight radius. From fa1fea02dcce596043b704e048c0ab575bc16873 Mon Sep 17 00:00:00 2001 From: James Wilson Date: Thu, 7 Aug 2025 19:13:00 +0100 Subject: [PATCH 46/78] Fix edge case that estimates sliderbreaks in impossible scenarios (#34544) * Test theory crafting * Place in more appropriate place * fix a bit better * Move things around * Reduce diff --------- Co-authored-by: StanR --- .../Difficulty/OsuLegacyScoreMissCalculator.cs | 13 +++++++++++++ .../Difficulty/OsuPerformanceCalculator.cs | 11 +++++++++++ 2 files changed, 24 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuLegacyScoreMissCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuLegacyScoreMissCalculator.cs index 207ecde81a..0d406ea72a 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuLegacyScoreMissCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuLegacyScoreMissCalculator.cs @@ -125,6 +125,19 @@ namespace osu.Game.Rulesets.Osu.Difficulty // In classic scores there can't be more misses than a sum of all non-perfect judgements missCount = Math.Min(missCount, totalImperfectHits); + // Every slider has *at least* 2 combo attributed in classic mechanics. + // If they broke on a slider with a tick, then this still works since they would have lost at least 2 combo (the tick and the end) + // Using this as a max means a score that loses 1 combo on a map can't possibly have been a slider break. + // It must have been a slider end. + int maxPossibleSliderBreaks = Math.Min(attributes.SliderCount, (attributes.MaxCombo - score.MaxCombo) / 2); + + int scoreMissCount = score.Statistics.GetValueOrDefault(HitResult.Miss); + + double sliderBreaks = missCount - scoreMissCount; + + if (sliderBreaks > maxPossibleSliderBreaks) + missCount = scoreMissCount + maxPossibleSliderBreaks; + return missCount; } diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 11e9714ed8..7230c52f9c 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -343,6 +343,17 @@ namespace osu.Game.Rulesets.Osu.Difficulty // In classic scores there can't be more misses than a sum of all non-perfect judgements missCount = Math.Min(missCount, totalImperfectHits); + + // Every slider has *at least* 2 combo attributed in classic mechanics. + // If they broke on a slider with a tick, then this still works since they would have lost at least 2 combo (the tick and the end) + // Using this as a max means a score that loses 1 combo on a map can't possibly have been a slider break. + // It must have been a slider end. + int maxPossibleSliderBreaks = Math.Min(attributes.SliderCount, (attributes.MaxCombo - scoreMaxCombo) / 2); + + double sliderBreaks = missCount - countMiss; + + if (sliderBreaks > maxPossibleSliderBreaks) + missCount = countMiss + maxPossibleSliderBreaks; } else { From dce4132209eb28f012a6ed7255f811612fc0045b Mon Sep 17 00:00:00 2001 From: Givikap120 <89256026+Givikap120@users.noreply.github.com> Date: Sat, 9 Aug 2025 22:40:37 +0300 Subject: [PATCH 47/78] Nerf Low AR HD bonus for slideraim (#34215) * Refactor slider factor calculation * Nerf low AR HD bonus for slideraim * finish merge * Fixes * Fix comment --------- Co-authored-by: James Wilson --- .../Difficulty/OsuDifficultyCalculator.cs | 6 ++---- .../Difficulty/OsuPerformanceCalculator.cs | 2 +- .../Difficulty/OsuRatingCalculator.cs | 15 ++++++++++----- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 337bda3221..8e87610dfb 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -98,11 +98,11 @@ namespace osu.Game.Rulesets.Osu.Difficulty double speedDifficultyValue = speed.DifficultyValue(); double mechanicalDifficultyRating = calculateMechanicalDifficultyRating(aimDifficultyValue, speedDifficultyValue); + double sliderFactor = aimDifficultyValue > 0 ? OsuRatingCalculator.CalculateDifficultyRating(aimNoSlidersDifficultyValue) / OsuRatingCalculator.CalculateDifficultyRating(aimDifficultyValue) : 1; - var osuRatingCalculator = new OsuRatingCalculator(mods, totalHits, approachRate, overallDifficulty, mechanicalDifficultyRating); + var osuRatingCalculator = new OsuRatingCalculator(mods, totalHits, approachRate, overallDifficulty, mechanicalDifficultyRating, sliderFactor); double aimRating = osuRatingCalculator.ComputeAimRating(aimDifficultyValue); - double aimRatingNoSliders = osuRatingCalculator.ComputeAimRating(aimNoSlidersDifficultyValue); double speedRating = osuRatingCalculator.ComputeSpeedRating(speedDifficultyValue); double flashlightRating = 0.0; @@ -110,8 +110,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (flashlight is not null) flashlightRating = osuRatingCalculator.ComputeFlashlightRating(flashlight.DifficultyValue()); - double sliderFactor = aimRating > 0 ? aimRatingNoSliders / aimRating : 1; - double sliderNestedScorePerObject = LegacyScoreUtils.CalculateNestedScorePerObject(beatmap, totalHits); double legacyScoreBaseMultiplier = LegacyScoreUtils.CalculateDifficultyPeppyStars(beatmap); diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index 7230c52f9c..c076b6cfe6 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -209,7 +209,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty aimValue *= 1.3 + (totalHits * (0.0016 / (1 + 2 * effectiveMissCount)) * Math.Pow(accuracy, 16)) * (1 - 0.003 * attributes.DrainRate * attributes.DrainRate); else if (score.Mods.Any(m => m is OsuModTraceable)) { - aimValue *= 1.0 + OsuRatingCalculator.CalculateVisibilityBonus(score.Mods, approachRate); + aimValue *= 1.0 + OsuRatingCalculator.CalculateVisibilityBonus(score.Mods, approachRate, attributes.SliderFactor); } aimValue *= accuracy; diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs index 8793582847..4d78db4788 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuRatingCalculator.cs @@ -18,14 +18,16 @@ namespace osu.Game.Rulesets.Osu.Difficulty private readonly double approachRate; private readonly double overallDifficulty; private readonly double mechanicalDifficultyRating; + private readonly double sliderFactor; - public OsuRatingCalculator(Mod[] mods, int totalHits, double approachRate, double overallDifficulty, double mechanicalDifficultyRating) + public OsuRatingCalculator(Mod[] mods, int totalHits, double approachRate, double overallDifficulty, double mechanicalDifficultyRating, double sliderFactor) { this.mods = mods; this.totalHits = totalHits; this.approachRate = approachRate; this.overallDifficulty = overallDifficulty; this.mechanicalDifficultyRating = mechanicalDifficultyRating; + this.sliderFactor = sliderFactor; } public double ComputeAimRating(double aimDifficultyValue) @@ -66,7 +68,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty if (mods.Any(m => m is OsuModHidden)) { double visibilityFactor = calculateAimVisibilityFactor(approachRate); - ratingMultiplier += CalculateVisibilityBonus(mods, approachRate, visibilityFactor); + ratingMultiplier += CalculateVisibilityBonus(mods, approachRate, visibilityFactor, sliderFactor); } // It is important to consider accuracy difficulty when scaling with accuracy. @@ -179,7 +181,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty /// /// Calculates a visibility bonus that is applicable to Hidden and Traceable. /// - public static double CalculateVisibilityBonus(Mod[] mods, double approachRate, double visibilityFactor = 1) + public static double CalculateVisibilityBonus(Mod[] mods, double approachRate, double visibilityFactor = 1, double sliderFactor = 1) { // NOTE: TC's effect is only noticeable in performance calculations until lazer mods are accounted for server-side. bool isAlwaysPartiallyVisible = mods.OfType().Any(m => m.OnlyFadeApproachCircles.Value) || mods.OfType().Any(); @@ -189,13 +191,16 @@ namespace osu.Game.Rulesets.Osu.Difficulty readingBonus *= visibilityFactor; + // We want to reward slideraim on low AR less + double sliderVisibilityFactor = Math.Pow(sliderFactor, 3); + // For AR up to 0 - reduce reward for very low ARs when object is visible if (approachRate < 7) - readingBonus += (isAlwaysPartiallyVisible ? 0.03 : 0.045) * (7.0 - Math.Max(approachRate, 0)); + readingBonus += (isAlwaysPartiallyVisible ? 0.03 : 0.045) * (7.0 - Math.Max(approachRate, 0)) * sliderVisibilityFactor; // Starting from AR0 - cap values so they won't grow to infinity if (approachRate < 0) - readingBonus += (isAlwaysPartiallyVisible ? 0.075 : 0.1) * (1 - Math.Pow(1.5, approachRate)); + readingBonus += (isAlwaysPartiallyVisible ? 0.075 : 0.1) * (1 - Math.Pow(1.5, approachRate)) * sliderVisibilityFactor; return readingBonus; } From 087f0565e6cfbb9197ae3d5167d64f2455090800 Mon Sep 17 00:00:00 2001 From: Jay Lawton Date: Thu, 28 Aug 2025 23:19:13 +1000 Subject: [PATCH 48/78] Implement `deltatimenormaliser` into rhythm grouping logic (#33403) * additions * review fixes * Formatting * comments + review * fix * fix renaming and namespace * balancing + round --------- Co-authored-by: tsunyoku Co-authored-by: StanR --- .../Data/SameRhythmHitObjectGrouping.cs | 41 +++++++++--- .../Difficulty/TaikoDifficultyCalculator.cs | 2 +- .../Difficulty/Utils/DeltaTimeNormaliser.cs | 66 +++++++++++++++++++ .../Difficulty/Utils/IntervalGroupingUtils.cs | 11 ++-- 4 files changed, 106 insertions(+), 14 deletions(-) create mode 100644 osu.Game.Rulesets.Taiko/Difficulty/Utils/DeltaTimeNormaliser.cs diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/Data/SameRhythmHitObjectGrouping.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/Data/SameRhythmHitObjectGrouping.cs index 9caa9b9958..256de13785 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/Data/SameRhythmHitObjectGrouping.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/Data/SameRhythmHitObjectGrouping.cs @@ -1,7 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Collections.Generic; +using System.Linq; using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Taiko.Difficulty.Utils; @@ -18,6 +20,8 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm.Data public readonly SameRhythmHitObjectGrouping? Previous; + private static readonly double snap_tolerance = IntervalGroupingUtils.MarginOfError; + /// /// of the first hit object. /// @@ -29,13 +33,13 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm.Data public double Duration => HitObjects[^1].StartTime - HitObjects[0].StartTime; /// - /// The interval in ms of each hit object in this . This is only defined if there is + /// The normalised interval in ms of each hit object in this . This is only defined if there is /// more than two hit objects in this . /// public readonly double? HitObjectInterval; /// - /// The ratio of between this and the previous . In the + /// The normalised ratio of between this and the previous . In the /// case where one or both of the is undefined, this will have a value of 1. /// public readonly double HitObjectIntervalRatio; @@ -48,16 +52,37 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm.Data Previous = previous; HitObjects = hitObjects; - // Calculate the average interval between hitobjects, or null if there are fewer than two - HitObjectInterval = HitObjects.Count < 2 ? null : Duration / (HitObjects.Count - 1); + // Cluster and normalise each hitobjects delta-time. + var normaliseHitObjects = DeltaTimeNormaliser.Normalise(hitObjects, snap_tolerance); + + var normalisedHitObjectDeltaTime = hitObjects + .Skip(1) + .Select(hitObject => normaliseHitObjects[hitObject]) + .ToList(); + + // Secondary check to ensure there isn't any 'noise' or outliers by taking the modal delta time. + double modalDelta = normalisedHitObjectDeltaTime.Count > 0 + ? Math.Round(normalisedHitObjectDeltaTime[0]) + : 0; + + // Calculate the average interval between hitobjects. + HitObjectInterval = normalisedHitObjectDeltaTime.Count > 0 + ? previous?.HitObjectInterval is double previousDelta && Math.Abs(modalDelta - previousDelta) <= snap_tolerance + ? previousDelta + : modalDelta + : null; // Calculate the ratio between this group's interval and the previous group's interval - HitObjectIntervalRatio = Previous?.HitObjectInterval != null && HitObjectInterval != null - ? HitObjectInterval.Value / Previous.HitObjectInterval.Value - : 1; + HitObjectIntervalRatio = previous?.HitObjectInterval is double previousInterval && HitObjectInterval is double currentInterval + ? currentInterval / previousInterval + : 1.0; // Calculate the interval from the previous group's start time - Interval = Previous != null ? StartTime - Previous.StartTime : double.PositiveInfinity; + Interval = previous == null + ? double.PositiveInfinity + : Math.Abs(StartTime - previous.StartTime) <= snap_tolerance + ? 0 + : StartTime - previous.StartTime; } } } diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index d2229e9786..92c6dac3a1 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty public class TaikoDifficultyCalculator : DifficultyCalculator { private const double difficulty_multiplier = 0.084375; - private const double rhythm_skill_multiplier = 0.65 * difficulty_multiplier; + private const double rhythm_skill_multiplier = 0.620 * difficulty_multiplier; private const double reading_skill_multiplier = 0.100 * difficulty_multiplier; private const double colour_skill_multiplier = 0.375 * difficulty_multiplier; private const double stamina_skill_multiplier = 0.445 * difficulty_multiplier; diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Utils/DeltaTimeNormaliser.cs b/osu.Game.Rulesets.Taiko/Difficulty/Utils/DeltaTimeNormaliser.cs new file mode 100644 index 0000000000..5e959f3f25 --- /dev/null +++ b/osu.Game.Rulesets.Taiko/Difficulty/Utils/DeltaTimeNormaliser.cs @@ -0,0 +1,66 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using System.Linq; +using osu.Game.Rulesets.Taiko.Difficulty.Preprocessing; + +namespace osu.Game.Rulesets.Taiko.Difficulty.Utils +{ + /// + /// Normalises deltaTime values for TaikoDifficultyHitObjects. + /// + public static class DeltaTimeNormaliser + { + /// + /// Combines deltaTime values that differ by at most + /// and replaces each value with the median of its range. This is used to reduce timing noise + /// and improve rhythm grouping consistency, especially for maps with inconsistent or 'off-snapped' timing. + /// + public static Dictionary Normalise( + IReadOnlyList hitObjects, + double marginOfError) + { + var deltaTimes = hitObjects.Select(h => h.DeltaTime).Distinct().OrderBy(d => d).ToList(); + + var sets = new List>(); + List? current = null; + + foreach (double value in deltaTimes) + { + // Add to the current group if within margin of error + if (current != null && Math.Abs(value - current[0]) <= marginOfError) + { + current.Add(value); + continue; + } + + // Otherwise begin a new group + current = new List { value }; + sets.Add(current); + } + + // Compute median for each group + var medianLookup = new Dictionary(); + + foreach (var set in sets) + { + set.Sort(); + int mid = set.Count / 2; + double median = set.Count % 2 == 1 + ? set[mid] + : (set[mid - 1] + set[mid]) / 2; + + foreach (double v in set) + medianLookup[v] = median; + } + + // Assign each hitobjects deltaTime the corresponding median value + return hitObjects.ToDictionary( + h => h, + h => medianLookup.TryGetValue(h.DeltaTime, out double median) ? median : h.DeltaTime + ); + } + } +} diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Utils/IntervalGroupingUtils.cs b/osu.Game.Rulesets.Taiko/Difficulty/Utils/IntervalGroupingUtils.cs index 5ab58ad4f3..fa39e8af50 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Utils/IntervalGroupingUtils.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Utils/IntervalGroupingUtils.cs @@ -8,6 +8,9 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Utils { public static class IntervalGroupingUtils { + // The margin of error when comparing intervals for grouping, or snapping intervals to a common value. + public static double MarginOfError = 5.0; + public static List> GroupByInterval(IReadOnlyList objects) where T : IHasInterval { var groups = new List>(); @@ -21,8 +24,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Utils private static List createNextGroup(IReadOnlyList objects, ref int i) where T : IHasInterval { - const double margin_of_error = 5; - // This never compares the first two elements in the group. // This sounds wrong but is apparently "as intended" (https://github.com/ppy/osu/pull/31636#discussion_r1942673329) var groupedObjects = new List { objects[i] }; @@ -30,11 +31,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Utils for (; i < objects.Count - 1; i++) { - if (!Precision.AlmostEquals(objects[i].Interval, objects[i + 1].Interval, margin_of_error)) + if (!Precision.AlmostEquals(objects[i].Interval, objects[i + 1].Interval, MarginOfError)) { // When an interval change occurs, include the object with the differing interval in the case it increased // See https://github.com/ppy/osu/pull/31636#discussion_r1942368372 for rationale. - if (objects[i + 1].Interval > objects[i].Interval + margin_of_error) + if (objects[i + 1].Interval > objects[i].Interval + MarginOfError) { groupedObjects.Add(objects[i]); i++; @@ -49,7 +50,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Utils // Check if the last two objects in the object form a "flat" rhythm pattern within the specified margin of error. // If true, add the current object to the group and increment the index to process the next object. - if (objects.Count > 2 && i < objects.Count && Precision.AlmostEquals(objects[^1].Interval, objects[^2].Interval, margin_of_error)) + if (objects.Count > 2 && i < objects.Count && Precision.AlmostEquals(objects[^1].Interval, objects[^2].Interval, MarginOfError)) { groupedObjects.Add(objects[i]); i++; From 90ac249f5eab5344ab52e0c1d397ce000c2788fc Mon Sep 17 00:00:00 2001 From: James Wilson Date: Sun, 31 Aug 2025 08:32:28 +0100 Subject: [PATCH 49/78] Move SpunOut penalty back to PP (#34838) This isn't a super common mod compared to every other one on the list, it's probably not worth the storage (and memory in case of stable) implications. We can look at revisiting this once we have actual spinner difficulty considerations --- .../Difficulty/OsuDifficultyCalculator.cs | 23 ++++--------------- .../Difficulty/OsuPerformanceCalculator.cs | 7 +++++- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs index 8e87610dfb..d7fa159d10 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuDifficultyCalculator.cs @@ -21,7 +21,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty { public class OsuDifficultyCalculator : DifficultyCalculator { - private const double performance_base_multiplier = 1.14; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things. private const double star_rating_multiplier = 0.0265; public override int Version => 20250306; @@ -31,16 +30,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty { } - public static double CalculateDifficultyMultiplier(Mod[] mods, int totalHits, int spinnerCount) - { - double multiplier = performance_base_multiplier; - - if (mods.Any(m => m is OsuModSpunOut) && totalHits > 0) - multiplier *= 1.0 - Math.Pow((double)spinnerCount / totalHits, 0.85); - - return multiplier; - } - public static double CalculateRateAdjustedApproachRate(double approachRate, double clockRate) { double preempt = IBeatmapDifficultyInfo.DifficultyRange(approachRate, OsuHitObject.PREEMPT_MAX, OsuHitObject.PREEMPT_MID, OsuHitObject.PREEMPT_MIN) / clockRate; @@ -127,8 +116,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty Math.Pow(baseFlashlightPerformance, 1.1), 1.0 / 1.1 ); - double multiplier = CalculateDifficultyMultiplier(mods, totalHits, spinnerCount); - double starRating = calculateStarRating(basePerformance, multiplier); + double starRating = calculateStarRating(basePerformance); OsuDifficultyAttributes attributes = new OsuDifficultyAttributes { @@ -157,22 +145,22 @@ namespace osu.Game.Rulesets.Osu.Difficulty return attributes; } - private static double calculateMechanicalDifficultyRating(double aimDifficultyValue, double speedDifficultyValue) + private double calculateMechanicalDifficultyRating(double aimDifficultyValue, double speedDifficultyValue) { double aimValue = OsuStrainSkill.DifficultyToPerformance(OsuRatingCalculator.CalculateDifficultyRating(aimDifficultyValue)); double speedValue = OsuStrainSkill.DifficultyToPerformance(OsuRatingCalculator.CalculateDifficultyRating(speedDifficultyValue)); double totalValue = Math.Pow(Math.Pow(aimValue, 1.1) + Math.Pow(speedValue, 1.1), 1 / 1.1); - return calculateStarRating(totalValue, performance_base_multiplier); + return calculateStarRating(totalValue); } - private static double calculateStarRating(double basePerformance, double multiplier) + private double calculateStarRating(double basePerformance) { if (basePerformance <= 0.00001) return 0; - return Math.Cbrt(multiplier) * star_rating_multiplier * (Math.Cbrt(100000 / Math.Pow(2, 1 / 1.1) * basePerformance) + 4); + return Math.Cbrt(OsuPerformanceCalculator.PERFORMANCE_BASE_MULTIPLIER) * star_rating_multiplier * (Math.Cbrt(100000 / Math.Pow(2, 1 / 1.1) * basePerformance) + 4); } protected override IEnumerable CreateDifficultyHitObjects(IBeatmap beatmap, double clockRate) @@ -213,7 +201,6 @@ namespace osu.Game.Rulesets.Osu.Difficulty new OsuModHardRock(), new OsuModFlashlight(), new OsuModHidden(), - new OsuModSpunOut(), }; } } diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index c076b6cfe6..777495570d 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -19,6 +19,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty { public class OsuPerformanceCalculator : PerformanceCalculator { + public const double PERFORMANCE_BASE_MULTIPLIER = 1.14; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things. + private bool usingClassicSliderAccuracy; private bool usingScoreV2; @@ -113,11 +115,14 @@ namespace osu.Game.Rulesets.Osu.Difficulty effectiveMissCount = Math.Max(countMiss, effectiveMissCount); effectiveMissCount = Math.Min(totalHits, effectiveMissCount); - double multiplier = OsuDifficultyCalculator.CalculateDifficultyMultiplier(score.Mods, totalHits, osuAttributes.SpinnerCount); + double multiplier = PERFORMANCE_BASE_MULTIPLIER; if (score.Mods.Any(m => m is OsuModNoFail)) multiplier *= Math.Max(0.90, 1.0 - 0.02 * effectiveMissCount); + if (score.Mods.Any(m => m is OsuModSpunOut) && totalHits > 0) + multiplier *= 1.0 - Math.Pow((double)osuAttributes.SpinnerCount / totalHits, 0.85); + if (score.Mods.Any(h => h is OsuModRelax)) { // https://www.desmos.com/calculator/vspzsop6td From 6a35b7237b31b18678de217742708f604100df7c Mon Sep 17 00:00:00 2001 From: James Wilson Date: Sun, 31 Aug 2025 13:04:56 +0100 Subject: [PATCH 50/78] Prevent Taiko difficulty crash if a map only contains 0-strains (#34829) * Prevent Taiko difficulty crash if a map only contains 0-strains * Add second check for safety This is accessing a different array of strains. I'd rather be safe than sorry. * Add guard in PP too * Make `MarginOfError` a const --- .../Rhythm/Data/SameRhythmHitObjectGrouping.cs | 2 +- .../Difficulty/TaikoDifficultyCalculator.cs | 12 ++++++++++++ .../Difficulty/TaikoPerformanceCalculator.cs | 2 +- .../Difficulty/Utils/IntervalGroupingUtils.cs | 8 ++++---- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/Data/SameRhythmHitObjectGrouping.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/Data/SameRhythmHitObjectGrouping.cs index 256de13785..89c150eb5f 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/Data/SameRhythmHitObjectGrouping.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/Data/SameRhythmHitObjectGrouping.cs @@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm.Data public readonly SameRhythmHitObjectGrouping? Previous; - private static readonly double snap_tolerance = IntervalGroupingUtils.MarginOfError; + private const double snap_tolerance = IntervalGroupingUtils.MARGIN_OF_ERROR; /// /// of the first hit object. diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index 92c6dac3a1..88791dd531 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -168,6 +168,12 @@ namespace osu.Game.Rulesets.Taiko.Difficulty stamina.GetCurrentStrainPeaks().ToList() ); + if (peaks.Count == 0) + { + consistencyFactor = 0; + return 0; + } + double difficulty = 0; double weight = 1; @@ -184,6 +190,12 @@ namespace osu.Game.Rulesets.Taiko.Difficulty stamina.GetObjectStrains().ToList() ); + if (hitObjectStrainPeaks.Count == 0) + { + consistencyFactor = 0; + return 0; + } + // The average of the top 5% of strain peaks from hit objects. double topAverageHitObjectStrain = hitObjectStrainPeaks.OrderDescending().Take(1 + hitObjectStrainPeaks.Count / 20).Average(); diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index 27ba31d918..22e390cd03 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -79,7 +79,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty private double computeDifficultyValue(ScoreInfo score, TaikoDifficultyAttributes attributes, bool isConvert, bool isClassic) { - if (estimatedUnstableRate == null) + if (estimatedUnstableRate == null || totalDifficultHits == 0) return 0; // The estimated unstable rate for 100% accuracy, at which all rhythm difficulty has been played successfully. diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Utils/IntervalGroupingUtils.cs b/osu.Game.Rulesets.Taiko/Difficulty/Utils/IntervalGroupingUtils.cs index fa39e8af50..38129b24e6 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Utils/IntervalGroupingUtils.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Utils/IntervalGroupingUtils.cs @@ -9,7 +9,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Utils public static class IntervalGroupingUtils { // The margin of error when comparing intervals for grouping, or snapping intervals to a common value. - public static double MarginOfError = 5.0; + public const double MARGIN_OF_ERROR = 5.0; public static List> GroupByInterval(IReadOnlyList objects) where T : IHasInterval { @@ -31,11 +31,11 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Utils for (; i < objects.Count - 1; i++) { - if (!Precision.AlmostEquals(objects[i].Interval, objects[i + 1].Interval, MarginOfError)) + if (!Precision.AlmostEquals(objects[i].Interval, objects[i + 1].Interval, MARGIN_OF_ERROR)) { // When an interval change occurs, include the object with the differing interval in the case it increased // See https://github.com/ppy/osu/pull/31636#discussion_r1942368372 for rationale. - if (objects[i + 1].Interval > objects[i].Interval + MarginOfError) + if (objects[i + 1].Interval > objects[i].Interval + MARGIN_OF_ERROR) { groupedObjects.Add(objects[i]); i++; @@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Utils // Check if the last two objects in the object form a "flat" rhythm pattern within the specified margin of error. // If true, add the current object to the group and increment the index to process the next object. - if (objects.Count > 2 && i < objects.Count && Precision.AlmostEquals(objects[^1].Interval, objects[^2].Interval, MarginOfError)) + if (objects.Count > 2 && i < objects.Count && Precision.AlmostEquals(objects[^1].Interval, objects[^2].Interval, MARGIN_OF_ERROR)) { groupedObjects.Add(objects[i]); i++; From 84309f57c5fd3f14422c150a44bcecafcb0dd894 Mon Sep 17 00:00:00 2001 From: StanR Date: Tue, 2 Sep 2025 14:22:12 +0500 Subject: [PATCH 51/78] Reduce rhythm difficulty if current object is doubletappable (#34877) * Reduce rhythm difficulty if current object is doubletappable * Buff rhythm multiplier --- .../Difficulty/Evaluators/RhythmEvaluator.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs index c00fa4c23e..9e6bae6c01 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs @@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators private const int history_time_max = 5 * 1000; // 5 seconds private const int history_objects_max = 32; private const double rhythm_overall_multiplier = 1.0; - private const double rhythm_ratio_multiplier = 12.0; + private const double rhythm_ratio_multiplier = 15.0; /// /// Calculates a rhythm multiplier for the difficulty of the tap associated with historic data of the current . @@ -26,6 +26,8 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators if (current.BaseObject is Spinner) return 0; + var currentOsuObject = (OsuDifficultyHitObject)current; + double rhythmComplexitySum = 0; double deltaDifferenceEpsilon = ((OsuDifficultyHitObject)current).HitWindowGreat * 0.3; @@ -173,7 +175,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators prevObj = currObj; } - return Math.Sqrt(4 + rhythmComplexitySum * rhythm_overall_multiplier) / 2.0; // produces multiplier that can be applied to strain. range [1, infinity) (not really though) + double rhythmDifficulty = Math.Sqrt(4 + rhythmComplexitySum * rhythm_overall_multiplier) / 2.0; // produces multiplier that can be applied to strain. range [1, infinity) (not really though) + rhythmDifficulty *= 1 - currentOsuObject.GetDoubletapness((OsuDifficultyHitObject)current.Next(0)); + + return rhythmDifficulty; } private class Island : IEquatable From a78c78ecdd8d8bee926afa155f2da5f9e46c885d Mon Sep 17 00:00:00 2001 From: James Wilson Date: Tue, 2 Sep 2025 11:19:34 +0100 Subject: [PATCH 52/78] Update difficulty calculation tests for osu ruleset (#34828) --- .../OsuDifficultyCalculatorTest.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs index 75e6dc6f09..e7a6d8ecff 100644 --- a/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs +++ b/osu.Game.Rulesets.Osu.Tests/OsuDifficultyCalculatorTest.cs @@ -15,22 +15,22 @@ namespace osu.Game.Rulesets.Osu.Tests { protected override string ResourceAssembly => "osu.Game.Rulesets.Osu.Tests"; - [TestCase(6.7331304290522747d, 239, "diffcalc-test")] - [TestCase(1.4595591215544095d, 54, "zero-length-sliders")] - [TestCase(0.4339253366122357d, 4, "very-fast-slider")] - [TestCase(0.14143808967817237d, 2, "nan-slider")] + [TestCase(6.6232533278125061d, 239, "diffcalc-test")] + [TestCase(1.5045783545699611d, 54, "zero-length-sliders")] + [TestCase(0.43333836671191595d, 4, "very-fast-slider")] + [TestCase(0.13841532030395723d, 2, "nan-slider")] public void Test(double expectedStarRating, int expectedMaxCombo, string name) => base.Test(expectedStarRating, expectedMaxCombo, name); - [TestCase(9.6779397290273756d, 239, "diffcalc-test")] - [TestCase(1.7680515258663754d, 54, "zero-length-sliders")] - [TestCase(0.56174427678665129d, 4, "very-fast-slider")] + [TestCase(9.6491691624112761d, 239, "diffcalc-test")] + [TestCase(1.756936832498702d, 54, "zero-length-sliders")] + [TestCase(0.57771197086735004d, 4, "very-fast-slider")] public void TestClockRateAdjusted(double expectedStarRating, int expectedMaxCombo, string name) => Test(expectedStarRating, expectedMaxCombo, name, new OsuModDoubleTime()); - [TestCase(6.7331304290522747d, 239, "diffcalc-test")] - [TestCase(1.4595591215544095d, 54, "zero-length-sliders")] - [TestCase(0.4339253366122357d, 4, "very-fast-slider")] + [TestCase(6.6232533278125061d, 239, "diffcalc-test")] + [TestCase(1.5045783545699611d, 54, "zero-length-sliders")] + [TestCase(0.43333836671191595d, 4, "very-fast-slider")] public void TestClassicMod(double expectedStarRating, int expectedMaxCombo, string name) => Test(expectedStarRating, expectedMaxCombo, name, new OsuModClassic()); From c7f50f35b7e6160f434cb8f5498c150aeaadd712 Mon Sep 17 00:00:00 2001 From: Eloise Date: Mon, 15 Sep 2025 09:43:26 +0100 Subject: [PATCH 53/78] osu!taiko final balancing before deploy (#34962) * Change maximum UR estimation + buff rhythm * Penalty for classic ezhd * Buff mono bonus to counterbalance logic fix * New miss penalty + slightly nerf length bonus * Adjust rhythm values * Adjust penalty and buff high SR acc * Exclude HDFL from hidden reading penalties * Make comment a lil nicer --------- Co-authored-by: James Wilson --- .../Difficulty/Skills/Stamina.cs | 2 +- .../Difficulty/TaikoDifficultyCalculator.cs | 2 +- .../Difficulty/TaikoPerformanceCalculator.cs | 27 ++++++++++++------- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs index 7c0c76d3ba..5e18163fe0 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Skills/Stamina.cs @@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Skills var currentObject = current as TaikoDifficultyHitObject; int index = currentObject?.ColourData.MonoStreak?.HitObjects.IndexOf(currentObject) ?? 0; - double monoLengthBonus = isConvert ? 1.0 : 1.0 + 0.3 * DifficultyCalculationUtils.ReverseLerp(index, 5, 20); + double monoLengthBonus = isConvert ? 1.0 : 1.0 + 0.5 * DifficultyCalculationUtils.ReverseLerp(index, 5, 20); // Mono-streak bonus is only applied to colour-based stamina to reward longer sequences of same-colour hits within patterns. if (!SingleColourStamina) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs index 88791dd531..cdb5a36f65 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyCalculator.cs @@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty public class TaikoDifficultyCalculator : DifficultyCalculator { private const double difficulty_multiplier = 0.084375; - private const double rhythm_skill_multiplier = 0.620 * difficulty_multiplier; + private const double rhythm_skill_multiplier = 0.750 * difficulty_multiplier; private const double reading_skill_multiplier = 0.100 * difficulty_multiplier; private const double colour_skill_multiplier = 0.375 * difficulty_multiplier; private const double stamina_skill_multiplier = 0.445 * difficulty_multiplier; diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs index 22e390cd03..df9da49c4b 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoPerformanceCalculator.cs @@ -86,17 +86,18 @@ namespace osu.Game.Rulesets.Taiko.Difficulty double rhythmExpectedUnstableRate = computeDeviationUpperBound(1.0) * 10; // The unstable rate at which it can be assumed all rhythm difficulty has been ignored. - double rhythmMaximumUnstableRate = 2 * rhythmExpectedUnstableRate; + // 0.8 represents 80% of total hits being greats, or 90% accuracy in-game + double rhythmMaximumUnstableRate = computeDeviationUpperBound(0.8) * 10; // The fraction of star rating made up by rhythm difficulty, normalised to represent rhythm's perceived contribution to star rating. - double rhythmFactor = DifficultyCalculationUtils.ReverseLerp(attributes.RhythmDifficulty / attributes.StarRating, 0.15, 0.35); + double rhythmFactor = DifficultyCalculationUtils.ReverseLerp(attributes.RhythmDifficulty / attributes.StarRating, 0.15, 0.4); // A penalty removing improperly played rhythm difficulty from star rating based on estimated unstable rate. double rhythmPenalty = 1 - DifficultyCalculationUtils.Logistic( estimatedUnstableRate.Value, midpointOffset: (rhythmExpectedUnstableRate + rhythmMaximumUnstableRate) / 2, multiplier: 10 / (rhythmMaximumUnstableRate - rhythmExpectedUnstableRate), - maxValue: 0.2 * Math.Pow(rhythmFactor, 2) + maxValue: 0.25 * Math.Pow(rhythmFactor, 3) ); double baseDifficulty = 5 * Math.Max(1.0, attributes.StarRating * rhythmPenalty / 0.110) - 4.0; @@ -109,16 +110,24 @@ namespace osu.Game.Rulesets.Taiko.Difficulty difficultyValue *= lengthBonus; // Scales miss penalty by the total difficult hits of a map, making misses more punishing on maps with less total difficulty. - double missPenalty = Math.Pow(0.5, 30.0 / totalDifficultHits); + double missPenalty = 0.97 + 0.03 * totalDifficultHits / (totalDifficultHits + 1500); difficultyValue *= Math.Pow(missPenalty, countMiss); if (score.Mods.Any(m => m is ModHidden)) { double hiddenBonus = isConvert ? 0.025 : 0.1; - // A penalty is applied to the bonus for hidden on non-classic scores, as the playfield can be made wider to make fast reading easier. - if (!isClassic) - hiddenBonus *= 0.2; + // Hidden+flashlight plays are excluded from reading-based penalties to hidden. + if (!score.Mods.Any(m => m is ModFlashlight)) + { + // A penalty is applied to the bonus for hidden on non-classic scores, as the playfield can be made wider to make fast reading easier. + if (!isClassic) + hiddenBonus *= 0.2; + + // A penalty is applied to classic easy+hidden scores, as notes disappear later making fast reading easier. + if (score.Mods.Any(m => m is ModEasy) && isClassic) + hiddenBonus *= 0.5; + } difficultyValue *= 1 + hiddenBonus; } @@ -141,13 +150,13 @@ namespace osu.Game.Rulesets.Taiko.Difficulty double accuracyValue = 470 * Math.Pow(0.9885, estimatedUnstableRate.Value); // Scales up the bonus for lower unstable rate as star rating increases. - accuracyValue *= 1 + Math.Pow(50 / estimatedUnstableRate.Value, 2) * Math.Pow(attributes.StarRating, 2) / 125; + accuracyValue *= 1 + Math.Pow(50 / estimatedUnstableRate.Value, 2) * Math.Pow(attributes.StarRating, 2.8) / 600; if (score.Mods.Any(m => m is ModHidden) && !isConvert) accuracyValue *= 1.075; // Applies a bonus to maps with more total difficulty, calculating this with a map's total hits and consistency factor. - accuracyValue *= 1 + 0.4 * totalDifficultHits / (totalDifficultHits + 4000); + accuracyValue *= 1 + 0.3 * totalDifficultHits / (totalDifficultHits + 4000); // Applies a bonus to maps with more total memory required with HDFL. double memoryLengthBonus = Math.Min(1.15, Math.Pow(totalHits / 1500.0, 0.3)); From 0a3844d3ef26a2eb2f1e7d74491bc7bae9a8cf3a Mon Sep 17 00:00:00 2001 From: James Wilson Date: Mon, 15 Sep 2025 10:46:27 +0100 Subject: [PATCH 54/78] Update tests (#35026) --- .../TaikoDifficultyCalculatorTest.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs b/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs index 76b86eb4d6..a4b33b7c15 100644 --- a/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs +++ b/osu.Game.Rulesets.Taiko.Tests/TaikoDifficultyCalculatorTest.cs @@ -14,13 +14,13 @@ namespace osu.Game.Rulesets.Taiko.Tests { protected override string ResourceAssembly => "osu.Game.Rulesets.Taiko"; - [TestCase(3.305554470092722d, 200, "diffcalc-test")] - [TestCase(3.305554470092722d, 200, "diffcalc-test-strong")] + [TestCase(3.3190848563395079d, 200, "diffcalc-test")] + [TestCase(3.3190848563395079d, 200, "diffcalc-test-strong")] public void Test(double expectedStarRating, int expectedMaxCombo, string name) => base.Test(expectedStarRating, expectedMaxCombo, name); - [TestCase(4.4472572672057815d, 200, "diffcalc-test")] - [TestCase(4.4472572672057815d, 200, "diffcalc-test-strong")] + [TestCase(4.4551414906554987d, 200, "diffcalc-test")] + [TestCase(4.4551414906554987d, 200, "diffcalc-test-strong")] public void TestClockRateAdjusted(double expectedStarRating, int expectedMaxCombo, string name) => Test(expectedStarRating, expectedMaxCombo, name, new TaikoModDoubleTime()); From 2749184c38eb1083057a9738af769fe82e7b41d0 Mon Sep 17 00:00:00 2001 From: James Wilson Date: Mon, 15 Sep 2025 11:46:00 +0100 Subject: [PATCH 55/78] Remove databasing of `MechanicalDifficulty` and `ReadingDifficulty` attributes (#35028) * Remove databasing of `MechanicalDifficulty` and `ReadingDifficulty` attributes * Update attribute IDs --- .../Difficulty/TaikoDifficultyAttributes.cs | 6 ------ osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs | 6 ++---- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs index eacf843487..c5cc04449c 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/TaikoDifficultyAttributes.cs @@ -14,7 +14,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty /// The difficulty corresponding to the mechanical skills in osu!taiko. /// This includes colour and stamina combined. /// - [JsonProperty("mechanical_difficulty")] public double MechanicalDifficulty { get; set; } /// @@ -26,7 +25,6 @@ namespace osu.Game.Rulesets.Taiko.Difficulty /// /// The difficulty corresponding to the reading skill. /// - [JsonProperty("reading_difficulty")] public double ReadingDifficulty { get; set; } /// @@ -59,9 +57,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty yield return v; yield return (ATTRIB_ID_DIFFICULTY, StarRating); - yield return (ATTRIB_ID_MECHANICAL_DIFFICULTY, MechanicalDifficulty); yield return (ATTRIB_ID_RHYTHM_DIFFICULTY, RhythmDifficulty); - yield return (ATTRIB_ID_READING_DIFFICULTY, ReadingDifficulty); yield return (ATTRIB_ID_MONO_STAMINA_FACTOR, MonoStaminaFactor); yield return (ATTRIB_ID_CONSISTENCY_FACTOR, ConsistencyFactor); } @@ -71,9 +67,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty base.FromDatabaseAttributes(values, onlineInfo); StarRating = values[ATTRIB_ID_DIFFICULTY]; - MechanicalDifficulty = values[ATTRIB_ID_MECHANICAL_DIFFICULTY]; RhythmDifficulty = values[ATTRIB_ID_RHYTHM_DIFFICULTY]; - ReadingDifficulty = values[ATTRIB_ID_READING_DIFFICULTY]; MonoStaminaFactor = values[ATTRIB_ID_MONO_STAMINA_FACTOR]; ConsistencyFactor = values[ATTRIB_ID_CONSISTENCY_FACTOR]; } diff --git a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs index 20cac77f8b..5e431dc357 100644 --- a/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs +++ b/osu.Game/Rulesets/Difficulty/DifficultyAttributes.cs @@ -31,10 +31,8 @@ namespace osu.Game.Rulesets.Difficulty protected const int ATTRIB_ID_NESTED_SCORE_PER_OBJECT = 37; protected const int ATTRIB_ID_LEGACY_SCORE_BASE_MULTIPLIER = 39; protected const int ATTRIB_ID_MAXIMUM_LEGACY_COMBO_SCORE = 41; - protected const int ATTRIB_ID_MECHANICAL_DIFFICULTY = 43; - protected const int ATTRIB_ID_RHYTHM_DIFFICULTY = 45; - protected const int ATTRIB_ID_READING_DIFFICULTY = 47; - protected const int ATTRIB_ID_CONSISTENCY_FACTOR = 49; + protected const int ATTRIB_ID_RHYTHM_DIFFICULTY = 43; + protected const int ATTRIB_ID_CONSISTENCY_FACTOR = 45; /// /// The mods which were applied to the beatmap. From 7852df639a86a07d3dea919721f07012433a1218 Mon Sep 17 00:00:00 2001 From: Givy120 <89256026+Givikap120@users.noreply.github.com> Date: Tue, 16 Sep 2025 16:31:14 +0300 Subject: [PATCH 56/78] Use DeltaTime in RhythmEvaluator to increase stability (#32790) * Update RhythmEvaluator.cs * Rename `StrainTime` into `AdjustedDeltaTime` --------- Co-authored-by: StanR --- .../Difficulty/Evaluators/AimEvaluator.cs | 16 ++++++++-------- .../Difficulty/Evaluators/FlashlightEvaluator.cs | 2 +- .../Difficulty/Evaluators/RhythmEvaluator.cs | 7 ++++--- .../Difficulty/Evaluators/SpeedEvaluator.cs | 2 +- .../Preprocessing/OsuDifficultyHitObject.cs | 10 +++++----- osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs | 2 +- 6 files changed, 20 insertions(+), 19 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs index 5942448855..dcf8ac0fed 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/AimEvaluator.cs @@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators const int diameter = OsuDifficultyHitObject.NORMALISED_DIAMETER; // Calculate the velocity to the current hitobject, which starts with a base distance / time assuming the last object is a hitcircle. - double currVelocity = osuCurrObj.LazyJumpDistance / osuCurrObj.StrainTime; + double currVelocity = osuCurrObj.LazyJumpDistance / osuCurrObj.AdjustedDeltaTime; // But if the last object is a slider, then we extend the travel velocity through the slider into the current object. if (osuLastObj.BaseObject is Slider && withSliderTravelDistance) @@ -52,7 +52,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators } // As above, do the same for the previous hitobject. - double prevVelocity = osuLastObj.LazyJumpDistance / osuLastObj.StrainTime; + double prevVelocity = osuLastObj.LazyJumpDistance / osuLastObj.AdjustedDeltaTime; if (osuLastLastObj.BaseObject is Slider && withSliderTravelDistance) { @@ -78,7 +78,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators // Rewarding angles, take the smaller velocity as base. double angleBonus = Math.Min(currVelocity, prevVelocity); - if (Math.Max(osuCurrObj.StrainTime, osuLastObj.StrainTime) < 1.25 * Math.Min(osuCurrObj.StrainTime, osuLastObj.StrainTime)) // If rhythms are the same. + if (Math.Max(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime) < 1.25 * Math.Min(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime)) // If rhythms are the same. { acuteAngleBonus = calcAcuteAngleBonus(currAngle); @@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators // Apply acute angle bonus for BPM above 300 1/2 and distance more than one diameter acuteAngleBonus *= angleBonus * - DifficultyCalculationUtils.Smootherstep(DifficultyCalculationUtils.MillisecondsToBPM(osuCurrObj.StrainTime, 2), 300, 400) * + DifficultyCalculationUtils.Smootherstep(DifficultyCalculationUtils.MillisecondsToBPM(osuCurrObj.AdjustedDeltaTime, 2), 300, 400) * DifficultyCalculationUtils.Smootherstep(osuCurrObj.LazyJumpDistance, diameter, diameter * 2); } @@ -128,19 +128,19 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators if (Math.Max(prevVelocity, currVelocity) != 0) { // We want to use the average velocity over the whole object when awarding differences, not the individual jump and slider path velocities. - prevVelocity = (osuLastObj.LazyJumpDistance + osuLastLastObj.TravelDistance) / osuLastObj.StrainTime; - currVelocity = (osuCurrObj.LazyJumpDistance + osuLastObj.TravelDistance) / osuCurrObj.StrainTime; + prevVelocity = (osuLastObj.LazyJumpDistance + osuLastLastObj.TravelDistance) / osuLastObj.AdjustedDeltaTime; + currVelocity = (osuCurrObj.LazyJumpDistance + osuLastObj.TravelDistance) / osuCurrObj.AdjustedDeltaTime; // Scale with ratio of difference compared to 0.5 * max dist. double distRatio = DifficultyCalculationUtils.Smoothstep(Math.Abs(prevVelocity - currVelocity) / Math.Max(prevVelocity, currVelocity), 0, 1); // Reward for % distance up to 125 / strainTime for overlaps where velocity is still changing. - double overlapVelocityBuff = Math.Min(diameter * 1.25 / Math.Min(osuCurrObj.StrainTime, osuLastObj.StrainTime), Math.Abs(prevVelocity - currVelocity)); + double overlapVelocityBuff = Math.Min(diameter * 1.25 / Math.Min(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime), Math.Abs(prevVelocity - currVelocity)); velocityChangeBonus = overlapVelocityBuff * distRatio; // Penalize for rhythm changes. - velocityChangeBonus *= Math.Pow(Math.Min(osuCurrObj.StrainTime, osuLastObj.StrainTime) / Math.Max(osuCurrObj.StrainTime, osuLastObj.StrainTime), 2); + velocityChangeBonus *= Math.Pow(Math.Min(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime) / Math.Max(osuCurrObj.AdjustedDeltaTime, osuLastObj.AdjustedDeltaTime), 2); } if (osuLastObj.BaseObject is Slider) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs index d64a2c2f15..55192df7af 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/FlashlightEvaluator.cs @@ -52,7 +52,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators var currentObj = (OsuDifficultyHitObject)current.Previous(i); var currentHitObject = (OsuHitObject)(currentObj.BaseObject); - cumulativeStrainTime += lastObj.StrainTime; + cumulativeStrainTime += lastObj.AdjustedDeltaTime; if (!(currentObj.BaseObject is Spinner)) { diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs index 9e6bae6c01..9349083951 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/RhythmEvaluator.cs @@ -64,9 +64,10 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators double currHistoricalDecay = Math.Min(noteDecay, timeDecay); // either we're limited by time or limited by object count. - double currDelta = currObj.StrainTime; - double prevDelta = prevObj.StrainTime; - double lastDelta = lastObj.StrainTime; + // Use custom cap value to ensure that that at this point delta time is actually zero + double currDelta = Math.Max(currObj.DeltaTime, 1e-7); + double prevDelta = Math.Max(prevObj.DeltaTime, 1e-7); + double lastDelta = Math.Max(lastObj.DeltaTime, 1e-7); // calculate how much current delta difference deserves a rhythm bonus // this function is meant to reduce rhythm bonus for deltas that are multiples of each other (i.e 100 and 200) diff --git a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs index 8cc0fc209a..a58c1d3685 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Evaluators/SpeedEvaluator.cs @@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Evaluators var osuCurrObj = (OsuDifficultyHitObject)current; var osuPrevObj = current.Index > 0 ? (OsuDifficultyHitObject)current.Previous(0) : null; - double strainTime = osuCurrObj.StrainTime; + double strainTime = osuCurrObj.AdjustedDeltaTime; double doubletapness = 1.0 - osuCurrObj.GetDoubletapness((OsuDifficultyHitObject?)osuCurrObj.Next(0)); // Cap deltatime to the OD 300 hitwindow. diff --git a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs index 8ad72daeb5..5e9fc10ef8 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Preprocessing/OsuDifficultyHitObject.cs @@ -31,9 +31,9 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing protected new OsuHitObject LastObject => (OsuHitObject)base.LastObject; /// - /// Milliseconds elapsed since the start time of the previous , with a minimum of 25ms. + /// capped to a minimum of ms. /// - public readonly double StrainTime; + public readonly double AdjustedDeltaTime; /// /// Normalised distance from the "lazy" end position of the previous to the start position of this . @@ -120,7 +120,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing lastDifficultyObject = index > 0 ? (OsuDifficultyHitObject)objects[index - 1] : null; // Capped to 25ms to prevent difficulty calculation breaking from simultaneous objects. - StrainTime = Math.Max(DeltaTime, MIN_DELTA_TIME); + AdjustedDeltaTime = Math.Max(DeltaTime, MIN_DELTA_TIME); SmallCircleBonus = Math.Max(1.0, 1.0 + (30 - BaseObject.Radius) / 40); @@ -203,13 +203,13 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Preprocessing Vector2 lastCursorPosition = lastDifficultyObject != null ? getEndCursorPosition(lastDifficultyObject) : LastObject.StackedPosition; LazyJumpDistance = (BaseObject.StackedPosition * scalingFactor - lastCursorPosition * scalingFactor).Length; - MinimumJumpTime = StrainTime; + MinimumJumpTime = AdjustedDeltaTime; MinimumJumpDistance = LazyJumpDistance; if (LastObject is Slider lastSlider && lastDifficultyObject != null) { double lastTravelTime = Math.Max(lastDifficultyObject.LazyTravelTime / clockRate, MIN_DELTA_TIME); - MinimumJumpTime = Math.Max(StrainTime - lastTravelTime, MIN_DELTA_TIME); + MinimumJumpTime = Math.Max(AdjustedDeltaTime - lastTravelTime, MIN_DELTA_TIME); // // There are two types of slider-to-object patterns to consider in order to better approximate the real movement a player will take to jump between the hitobjects. diff --git a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs index 7fd1e044ae..8fe3df4347 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/Skills/Speed.cs @@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty.Skills protected override double StrainValueAt(DifficultyHitObject current) { - currentStrain *= strainDecay(((OsuDifficultyHitObject)current).StrainTime); + currentStrain *= strainDecay(((OsuDifficultyHitObject)current).AdjustedDeltaTime); currentStrain += SpeedEvaluator.EvaluateDifficultyOf(current, Mods) * skillMultiplier; currentRhythm = RhythmEvaluator.EvaluateDifficultyOf(current); From 82ac42cae31639a3f031814b5c34604bea39fb6c Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Tue, 23 Sep 2025 13:42:31 +0900 Subject: [PATCH 57/78] Replace nested ternaries with ifs --- .../Data/SameRhythmHitObjectGrouping.cs | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/Data/SameRhythmHitObjectGrouping.cs b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/Data/SameRhythmHitObjectGrouping.cs index 89c150eb5f..59215c043b 100644 --- a/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/Data/SameRhythmHitObjectGrouping.cs +++ b/osu.Game.Rulesets.Taiko/Difficulty/Preprocessing/Rhythm/Data/SameRhythmHitObjectGrouping.cs @@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm.Data public readonly double HitObjectIntervalRatio; /// - public double Interval { get; } + public double Interval { get; } = double.PositiveInfinity; public SameRhythmHitObjectGrouping(SameRhythmHitObjectGrouping? previous, List hitObjects) { @@ -66,11 +66,13 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm.Data : 0; // Calculate the average interval between hitobjects. - HitObjectInterval = normalisedHitObjectDeltaTime.Count > 0 - ? previous?.HitObjectInterval is double previousDelta && Math.Abs(modalDelta - previousDelta) <= snap_tolerance - ? previousDelta - : modalDelta - : null; + if (normalisedHitObjectDeltaTime.Count > 0) + { + if (previous?.HitObjectInterval is double previousDelta && Math.Abs(modalDelta - previousDelta) <= snap_tolerance) + HitObjectInterval = previousDelta; + else + HitObjectInterval = modalDelta; + } // Calculate the ratio between this group's interval and the previous group's interval HitObjectIntervalRatio = previous?.HitObjectInterval is double previousInterval && HitObjectInterval is double currentInterval @@ -78,11 +80,13 @@ namespace osu.Game.Rulesets.Taiko.Difficulty.Preprocessing.Rhythm.Data : 1.0; // Calculate the interval from the previous group's start time - Interval = previous == null - ? double.PositiveInfinity - : Math.Abs(StartTime - previous.StartTime) <= snap_tolerance - ? 0 - : StartTime - previous.StartTime; + if (previous != null) + { + if (Math.Abs(StartTime - previous.StartTime) <= snap_tolerance) + Interval = 0; + else + Interval = StartTime - previous.StartTime; + } } } } From dbd48bc3a1ecfa8786815d208b7ab773c2be3e8a Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Mon, 6 Oct 2025 01:58:49 +0300 Subject: [PATCH 58/78] Fix mods deselection difference --- osu.Game/Screens/SelectV2/SongSelect.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/SelectV2/SongSelect.cs b/osu.Game/Screens/SelectV2/SongSelect.cs index 64262ed6ab..cff71c4fca 100644 --- a/osu.Game/Screens/SelectV2/SongSelect.cs +++ b/osu.Game/Screens/SelectV2/SongSelect.cs @@ -323,7 +323,13 @@ namespace osu.Game.Screens.SelectV2 { Hotkey = GlobalAction.ToggleModSelection, Current = Mods, - RequestDeselectAllMods = () => Mods.Value = Array.Empty() + RequestDeselectAllMods = () => + { + if (modSelectOverlay.State.Value == Visibility.Hidden) + Mods.Value = Array.Empty(); + else + modSelectOverlay.DeselectAll(); + } }, new FooterButtonRandom { From 743a94bd22b7c0ce280232a323963828a1f70d96 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Oct 2025 16:30:40 +0900 Subject: [PATCH 59/78] Re-remove duplicate error functions --- ...ifficultyCalculationUtils.ErrorFunction.cs | 688 ------------------ 1 file changed, 688 deletions(-) delete mode 100644 osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils.ErrorFunction.cs diff --git a/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils.ErrorFunction.cs b/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils.ErrorFunction.cs deleted file mode 100644 index 4b89cbe7cc..0000000000 --- a/osu.Game/Rulesets/Difficulty/Utils/DifficultyCalculationUtils.ErrorFunction.cs +++ /dev/null @@ -1,688 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -// All code is referenced from the following: -// https://github.com/mathnet/mathnet-numerics/blob/master/src/Numerics/SpecialFunctions/Erf.cs - -/* - Copyright (c) 2002-2022 Math.NET -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -using System; - -namespace osu.Game.Rulesets.Difficulty.Utils -{ - public partial class DifficultyCalculationUtils - { - /// - /// ************************************** - /// COEFFICIENTS FOR METHOD ErfImp * - /// ************************************** - /// - /// Polynomial coefficients for a numerator of ErfImp - /// calculation for Erf(x) in the interval [1e-10, 0.5]. - /// - private static readonly double[] erf_imp_an = { 0.00337916709551257388990745, -0.00073695653048167948530905, -0.374732337392919607868241, 0.0817442448733587196071743, -0.0421089319936548595203468, 0.0070165709512095756344528, -0.00495091255982435110337458, 0.000871646599037922480317225 }; - - /// Polynomial coefficients for a denominator of ErfImp - /// calculation for Erf(x) in the interval [1e-10, 0.5]. - /// - private static readonly double[] erf_imp_ad = { 1, -0.218088218087924645390535, 0.412542972725442099083918, -0.0841891147873106755410271, 0.0655338856400241519690695, -0.0120019604454941768171266, 0.00408165558926174048329689, -0.000615900721557769691924509 }; - - /// Polynomial coefficients for a numerator in ErfImp - /// calculation for Erfc(x) in the interval [0.5, 0.75]. - /// - private static readonly double[] erf_imp_bn = { -0.0361790390718262471360258, 0.292251883444882683221149, 0.281447041797604512774415, 0.125610208862766947294894, 0.0274135028268930549240776, 0.00250839672168065762786937 }; - - /// Polynomial coefficients for a denominator in ErfImp - /// calculation for Erfc(x) in the interval [0.5, 0.75]. - /// - private static readonly double[] erf_imp_bd = { 1, 1.8545005897903486499845, 1.43575803037831418074962, 0.582827658753036572454135, 0.124810476932949746447682, 0.0113724176546353285778481 }; - - /// Polynomial coefficients for a numerator in ErfImp - /// calculation for Erfc(x) in the interval [0.75, 1.25]. - /// - private static readonly double[] erf_imp_cn = { -0.0397876892611136856954425, 0.153165212467878293257683, 0.191260295600936245503129, 0.10276327061989304213645, 0.029637090615738836726027, 0.0046093486780275489468812, 0.000307607820348680180548455 }; - - /// Polynomial coefficients for a denominator in ErfImp - /// calculation for Erfc(x) in the interval [0.75, 1.25]. - /// - private static readonly double[] erf_imp_cd = { 1, 1.95520072987627704987886, 1.64762317199384860109595, 0.768238607022126250082483, 0.209793185936509782784315, 0.0319569316899913392596356, 0.00213363160895785378615014 }; - - /// Polynomial coefficients for a numerator in ErfImp - /// calculation for Erfc(x) in the interval [1.25, 2.25]. - /// - private static readonly double[] erf_imp_dn = { -0.0300838560557949717328341, 0.0538578829844454508530552, 0.0726211541651914182692959, 0.0367628469888049348429018, 0.00964629015572527529605267, 0.00133453480075291076745275, 0.778087599782504251917881e-4 }; - - /// Polynomial coefficients for a denominator in ErfImp - /// calculation for Erfc(x) in the interval [1.25, 2.25]. - /// - private static readonly double[] erf_imp_dd = { 1, 1.75967098147167528287343, 1.32883571437961120556307, 0.552528596508757581287907, 0.133793056941332861912279, 0.0179509645176280768640766, 0.00104712440019937356634038, -0.106640381820357337177643e-7 }; - - /// Polynomial coefficients for a numerator in ErfImp - /// calculation for Erfc(x) in the interval [2.25, 3.5]. - /// - private static readonly double[] erf_imp_en = { -0.0117907570137227847827732, 0.014262132090538809896674, 0.0202234435902960820020765, 0.00930668299990432009042239, 0.00213357802422065994322516, 0.00025022987386460102395382, 0.120534912219588189822126e-4 }; - - /// Polynomial coefficients for a denominator in ErfImp - /// calculation for Erfc(x) in the interval [2.25, 3.5]. - /// - private static readonly double[] erf_imp_ed = { 1, 1.50376225203620482047419, 0.965397786204462896346934, 0.339265230476796681555511, 0.0689740649541569716897427, 0.00771060262491768307365526, 0.000371421101531069302990367 }; - - /// Polynomial coefficients for a numerator in ErfImp - /// calculation for Erfc(x) in the interval [3.5, 5.25]. - /// - private static readonly double[] erf_imp_fn = { -0.00546954795538729307482955, 0.00404190278731707110245394, 0.0054963369553161170521356, 0.00212616472603945399437862, 0.000394984014495083900689956, 0.365565477064442377259271e-4, 0.135485897109932323253786e-5 }; - - /// Polynomial coefficients for a denominator in ErfImp - /// calculation for Erfc(x) in the interval [3.5, 5.25]. - /// - private static readonly double[] erf_imp_fd = { 1, 1.21019697773630784832251, 0.620914668221143886601045, 0.173038430661142762569515, 0.0276550813773432047594539, 0.00240625974424309709745382, 0.891811817251336577241006e-4, -0.465528836283382684461025e-11 }; - - /// Polynomial coefficients for a numerator in ErfImp - /// calculation for Erfc(x) in the interval [5.25, 8]. - /// - private static readonly double[] erf_imp_gn = { -0.00270722535905778347999196, 0.0013187563425029400461378, 0.00119925933261002333923989, 0.00027849619811344664248235, 0.267822988218331849989363e-4, 0.923043672315028197865066e-6 }; - - /// Polynomial coefficients for a denominator in ErfImp - /// calculation for Erfc(x) in the interval [5.25, 8]. - /// - private static readonly double[] erf_imp_gd = { 1, 0.814632808543141591118279, 0.268901665856299542168425, 0.0449877216103041118694989, 0.00381759663320248459168994, 0.000131571897888596914350697, 0.404815359675764138445257e-11 }; - - /// Polynomial coefficients for a numerator in ErfImp - /// calculation for Erfc(x) in the interval [8, 11.5]. - /// - private static readonly double[] erf_imp_hn = { -0.00109946720691742196814323, 0.000406425442750422675169153, 0.000274499489416900707787024, 0.465293770646659383436343e-4, 0.320955425395767463401993e-5, 0.778286018145020892261936e-7 }; - - /// Polynomial coefficients for a denominator in ErfImp - /// calculation for Erfc(x) in the interval [8, 11.5]. - /// - private static readonly double[] erf_imp_hd = { 1, 0.588173710611846046373373, 0.139363331289409746077541, 0.0166329340417083678763028, 0.00100023921310234908642639, 0.24254837521587225125068e-4 }; - - /// Polynomial coefficients for a numerator in ErfImp - /// calculation for Erfc(x) in the interval [11.5, 17]. - /// - private static readonly double[] erf_imp_in = { -0.00056907993601094962855594, 0.000169498540373762264416984, 0.518472354581100890120501e-4, 0.382819312231928859704678e-5, 0.824989931281894431781794e-7 }; - - /// Polynomial coefficients for a denominator in ErfImp - /// calculation for Erfc(x) in the interval [11.5, 17]. - /// - private static readonly double[] erf_imp_id = { 1, 0.339637250051139347430323, 0.043472647870310663055044, 0.00248549335224637114641629, 0.535633305337152900549536e-4, -0.117490944405459578783846e-12 }; - - /// Polynomial coefficients for a numerator in ErfImp - /// calculation for Erfc(x) in the interval [17, 24]. - /// - private static readonly double[] erf_imp_jn = { -0.000241313599483991337479091, 0.574224975202501512365975e-4, 0.115998962927383778460557e-4, 0.581762134402593739370875e-6, 0.853971555085673614607418e-8 }; - - /// Polynomial coefficients for a denominator in ErfImp - /// calculation for Erfc(x) in the interval [17, 24]. - /// - private static readonly double[] erf_imp_jd = { 1, 0.233044138299687841018015, 0.0204186940546440312625597, 0.000797185647564398289151125, 0.117019281670172327758019e-4 }; - - /// Polynomial coefficients for a numerator in ErfImp - /// calculation for Erfc(x) in the interval [24, 38]. - /// - private static readonly double[] erf_imp_kn = { -0.000146674699277760365803642, 0.162666552112280519955647e-4, 0.269116248509165239294897e-5, 0.979584479468091935086972e-7, 0.101994647625723465722285e-8 }; - - /// Polynomial coefficients for a denominator in ErfImp - /// calculation for Erfc(x) in the interval [24, 38]. - /// - private static readonly double[] erf_imp_kd = { 1, 0.165907812944847226546036, 0.0103361716191505884359634, 0.000286593026373868366935721, 0.298401570840900340874568e-5 }; - - /// Polynomial coefficients for a numerator in ErfImp - /// calculation for Erfc(x) in the interval [38, 60]. - /// - private static readonly double[] erf_imp_ln = { -0.583905797629771786720406e-4, 0.412510325105496173512992e-5, 0.431790922420250949096906e-6, 0.993365155590013193345569e-8, 0.653480510020104699270084e-10 }; - - /// Polynomial coefficients for a denominator in ErfImp - /// calculation for Erfc(x) in the interval [38, 60]. - /// - private static readonly double[] erf_imp_ld = { 1, 0.105077086072039915406159, 0.00414278428675475620830226, 0.726338754644523769144108e-4, 0.477818471047398785369849e-6 }; - - /// Polynomial coefficients for a numerator in ErfImp - /// calculation for Erfc(x) in the interval [60, 85]. - /// - private static readonly double[] erf_imp_mn = { -0.196457797609229579459841e-4, 0.157243887666800692441195e-5, 0.543902511192700878690335e-7, 0.317472492369117710852685e-9 }; - - /// Polynomial coefficients for a denominator in ErfImp - /// calculation for Erfc(x) in the interval [60, 85]. - /// - private static readonly double[] erf_imp_md = { 1, 0.052803989240957632204885, 0.000926876069151753290378112, 0.541011723226630257077328e-5, 0.535093845803642394908747e-15 }; - - /// Polynomial coefficients for a numerator in ErfImp - /// calculation for Erfc(x) in the interval [85, 110]. - /// - private static readonly double[] erf_imp_nn = { -0.789224703978722689089794e-5, 0.622088451660986955124162e-6, 0.145728445676882396797184e-7, 0.603715505542715364529243e-10 }; - - /// Polynomial coefficients for a denominator in ErfImp - /// calculation for Erfc(x) in the interval [85, 110]. - /// - private static readonly double[] erf_imp_nd = { 1, 0.0375328846356293715248719, 0.000467919535974625308126054, 0.193847039275845656900547e-5 }; - - /// - /// ************************************** - /// COEFFICIENTS FOR METHOD ErfInvImp * - /// ************************************** - /// - /// Polynomial coefficients for a numerator of ErfInvImp - /// calculation for Erf^-1(z) in the interval [0, 0.5]. - /// - private static readonly double[] erv_inv_imp_an = { -0.000508781949658280665617, -0.00836874819741736770379, 0.0334806625409744615033, -0.0126926147662974029034, -0.0365637971411762664006, 0.0219878681111168899165, 0.00822687874676915743155, -0.00538772965071242932965 }; - - /// Polynomial coefficients for a denominator of ErfInvImp - /// calculation for Erf^-1(z) in the interval [0, 0.5]. - /// - private static readonly double[] erv_inv_imp_ad = { 1, -0.970005043303290640362, -1.56574558234175846809, 1.56221558398423026363, 0.662328840472002992063, -0.71228902341542847553, -0.0527396382340099713954, 0.0795283687341571680018, -0.00233393759374190016776, 0.000886216390456424707504 }; - - /// Polynomial coefficients for a numerator of ErfInvImp - /// calculation for Erf^-1(z) in the interval [0.5, 0.75]. - /// - private static readonly double[] erv_inv_imp_bn = { -0.202433508355938759655, 0.105264680699391713268, 8.37050328343119927838, 17.6447298408374015486, -18.8510648058714251895, -44.6382324441786960818, 17.445385985570866523, 21.1294655448340526258, -3.67192254707729348546 }; - - /// Polynomial coefficients for a denominator of ErfInvImp - /// calculation for Erf^-1(z) in the interval [0.5, 0.75]. - /// - private static readonly double[] erv_inv_imp_bd = { 1, 6.24264124854247537712, 3.9713437953343869095, -28.6608180499800029974, -20.1432634680485188801, 48.5609213108739935468, 10.8268667355460159008, -22.6436933413139721736, 1.72114765761200282724 }; - - /// Polynomial coefficients for a numerator of ErfInvImp - /// calculation for Erf^-1(z) in the interval [0.75, 1] with x less than 3. - /// - private static readonly double[] erv_inv_imp_cn = { -0.131102781679951906451, -0.163794047193317060787, 0.117030156341995252019, 0.387079738972604337464, 0.337785538912035898924, 0.142869534408157156766, 0.0290157910005329060432, 0.00214558995388805277169, -0.679465575181126350155e-6, 0.285225331782217055858e-7, -0.681149956853776992068e-9 }; - - /// Polynomial coefficients for a denominator of ErfInvImp - /// calculation for Erf^-1(z) in the interval [0.75, 1] with x less than 3. - /// - private static readonly double[] erv_inv_imp_cd = { 1, 3.46625407242567245975, 5.38168345707006855425, 4.77846592945843778382, 2.59301921623620271374, 0.848854343457902036425, 0.152264338295331783612, 0.01105924229346489121 }; - - /// Polynomial coefficients for a numerator of ErfInvImp - /// calculation for Erf^-1(z) in the interval [0.75, 1] with x between 3 and 6. - /// - private static readonly double[] erv_inv_imp_dn = { -0.0350353787183177984712, -0.00222426529213447927281, 0.0185573306514231072324, 0.00950804701325919603619, 0.00187123492819559223345, 0.000157544617424960554631, 0.460469890584317994083e-5, -0.230404776911882601748e-9, 0.266339227425782031962e-11 }; - - /// Polynomial coefficients for a denominator of ErfInvImp - /// calculation for Erf^-1(z) in the interval [0.75, 1] with x between 3 and 6. - /// - private static readonly double[] erv_inv_imp_dd = { 1, 1.3653349817554063097, 0.762059164553623404043, 0.220091105764131249824, 0.0341589143670947727934, 0.00263861676657015992959, 0.764675292302794483503e-4 }; - - /// Polynomial coefficients for a numerator of ErfInvImp - /// calculation for Erf^-1(z) in the interval [0.75, 1] with x between 6 and 18. - /// - private static readonly double[] erv_inv_imp_en = { -0.0167431005076633737133, -0.00112951438745580278863, 0.00105628862152492910091, 0.000209386317487588078668, 0.149624783758342370182e-4, 0.449696789927706453732e-6, 0.462596163522878599135e-8, -0.281128735628831791805e-13, 0.99055709973310326855e-16 }; - - /// Polynomial coefficients for a denominator of ErfInvImp - /// calculation for Erf^-1(z) in the interval [0.75, 1] with x between 6 and 18. - /// - private static readonly double[] erv_inv_imp_ed = { 1, 0.591429344886417493481, 0.138151865749083321638, 0.0160746087093676504695, 0.000964011807005165528527, 0.275335474764726041141e-4, 0.282243172016108031869e-6 }; - - /// Polynomial coefficients for a numerator of ErfInvImp - /// calculation for Erf^-1(z) in the interval [0.75, 1] with x between 18 and 44. - /// - private static readonly double[] erv_inv_imp_fn = { -0.0024978212791898131227, -0.779190719229053954292e-5, 0.254723037413027451751e-4, 0.162397777342510920873e-5, 0.396341011304801168516e-7, 0.411632831190944208473e-9, 0.145596286718675035587e-11, -0.116765012397184275695e-17 }; - - /// Polynomial coefficients for a denominator of ErfInvImp - /// calculation for Erf^-1(z) in the interval [0.75, 1] with x between 18 and 44. - /// - private static readonly double[] erv_inv_imp_fd = { 1, 0.207123112214422517181, 0.0169410838120975906478, 0.000690538265622684595676, 0.145007359818232637924e-4, 0.144437756628144157666e-6, 0.509761276599778486139e-9 }; - - /// Polynomial coefficients for a numerator of ErfInvImp - /// calculation for Erf^-1(z) in the interval [0.75, 1] with x greater than 44. - /// - private static readonly double[] erv_inv_imp_gn = { -0.000539042911019078575891, -0.28398759004727721098e-6, 0.899465114892291446442e-6, 0.229345859265920864296e-7, 0.225561444863500149219e-9, 0.947846627503022684216e-12, 0.135880130108924861008e-14, -0.348890393399948882918e-21 }; - - /// Polynomial coefficients for a denominator of ErfInvImp - /// calculation for Erf^-1(z) in the interval [0.75, 1] with x greater than 44. - /// - private static readonly double[] erv_inv_imp_gd = { 1, 0.0845746234001899436914, 0.00282092984726264681981, 0.468292921940894236786e-4, 0.399968812193862100054e-6, 0.161809290887904476097e-8, 0.231558608310259605225e-11 }; - - /// Calculates the error function. - /// The value to evaluate. - /// the error function evaluated at given value. - /// - /// - /// returns 1 if x == double.PositiveInfinity. - /// returns -1 if x == double.NegativeInfinity. - /// - /// - public static double Erf(double x) - { - if (x == 0) - { - return 0; - } - - if (double.IsPositiveInfinity(x)) - { - return 1; - } - - if (double.IsNegativeInfinity(x)) - { - return -1; - } - - if (double.IsNaN(x)) - { - return double.NaN; - } - - return erfImp(x, false); - } - - /// Calculates the complementary error function. - /// The value to evaluate. - /// the complementary error function evaluated at given value. - /// - /// - /// returns 0 if x == double.PositiveInfinity. - /// returns 2 if x == double.NegativeInfinity. - /// - /// - public static double Erfc(double x) - { - if (x == 0) - { - return 1; - } - - if (double.IsPositiveInfinity(x)) - { - return 0; - } - - if (double.IsNegativeInfinity(x)) - { - return 2; - } - - if (double.IsNaN(x)) - { - return double.NaN; - } - - return erfImp(x, true); - } - - /// Calculates the inverse error function evaluated at z. - /// The inverse error function evaluated at given value. - /// - /// - /// returns double.PositiveInfinity if z >= 1.0. - /// returns double.NegativeInfinity if z <= -1.0. - /// - /// - /// Calculates the inverse error function evaluated at z. - /// value to evaluate. - /// the inverse error function evaluated at Z. - public static double ErfInv(double z) - { - if (z == 0.0) - { - return 0.0; - } - - if (z >= 1.0) - { - return double.PositiveInfinity; - } - - if (z <= -1.0) - { - return double.NegativeInfinity; - } - - double p, q, s; - - if (z < 0) - { - p = -z; - q = 1 - p; - s = -1; - } - else - { - p = z; - q = 1 - z; - s = 1; - } - - return erfInvImpl(p, q, s); - } - - /// - /// Implementation of the error function. - /// - /// Where to evaluate the error function. - /// Whether to compute 1 - the error function. - /// the error function. - private static double erfImp(double z, bool invert) - { - if (z < 0) - { - if (!invert) - { - return -erfImp(-z, false); - } - - if (z < -0.5) - { - return 2 - erfImp(-z, true); - } - - return 1 + erfImp(-z, false); - } - - double result; - - // Big bunch of selection statements now to pick which - // implementation to use, try to put most likely options - // first: - if (z < 0.5) - { - // We're going to calculate erf: - if (z < 1e-10) - { - result = (z * 1.125) + (z * 0.003379167095512573896158903121545171688); - } - else - { - // Worst case absolute error found: 6.688618532e-21 - result = (z * 1.125) + (z * evaluatePolynomial(z, erf_imp_an) / evaluatePolynomial(z, erf_imp_ad)); - } - } - else if (z < 110) - { - // We'll be calculating erfc: - invert = !invert; - double r, b; - - if (z < 0.75) - { - // Worst case absolute error found: 5.582813374e-21 - r = evaluatePolynomial(z - 0.5, erf_imp_bn) / evaluatePolynomial(z - 0.5, erf_imp_bd); - b = 0.3440242112F; - } - else if (z < 1.25) - { - // Worst case absolute error found: 4.01854729e-21 - r = evaluatePolynomial(z - 0.75, erf_imp_cn) / evaluatePolynomial(z - 0.75, erf_imp_cd); - b = 0.419990927F; - } - else if (z < 2.25) - { - // Worst case absolute error found: 2.866005373e-21 - r = evaluatePolynomial(z - 1.25, erf_imp_dn) / evaluatePolynomial(z - 1.25, erf_imp_dd); - b = 0.4898625016F; - } - else if (z < 3.5) - { - // Worst case absolute error found: 1.045355789e-21 - r = evaluatePolynomial(z - 2.25, erf_imp_en) / evaluatePolynomial(z - 2.25, erf_imp_ed); - b = 0.5317370892F; - } - else if (z < 5.25) - { - // Worst case absolute error found: 8.300028706e-22 - r = evaluatePolynomial(z - 3.5, erf_imp_fn) / evaluatePolynomial(z - 3.5, erf_imp_fd); - b = 0.5489973426F; - } - else if (z < 8) - { - // Worst case absolute error found: 1.700157534e-21 - r = evaluatePolynomial(z - 5.25, erf_imp_gn) / evaluatePolynomial(z - 5.25, erf_imp_gd); - b = 0.5571740866F; - } - else if (z < 11.5) - { - // Worst case absolute error found: 3.002278011e-22 - r = evaluatePolynomial(z - 8, erf_imp_hn) / evaluatePolynomial(z - 8, erf_imp_hd); - b = 0.5609807968F; - } - else if (z < 17) - { - // Worst case absolute error found: 6.741114695e-21 - r = evaluatePolynomial(z - 11.5, erf_imp_in) / evaluatePolynomial(z - 11.5, erf_imp_id); - b = 0.5626493692F; - } - else if (z < 24) - { - // Worst case absolute error found: 7.802346984e-22 - r = evaluatePolynomial(z - 17, erf_imp_jn) / evaluatePolynomial(z - 17, erf_imp_jd); - b = 0.5634598136F; - } - else if (z < 38) - { - // Worst case absolute error found: 2.414228989e-22 - r = evaluatePolynomial(z - 24, erf_imp_kn) / evaluatePolynomial(z - 24, erf_imp_kd); - b = 0.5638477802F; - } - else if (z < 60) - { - // Worst case absolute error found: 5.896543869e-24 - r = evaluatePolynomial(z - 38, erf_imp_ln) / evaluatePolynomial(z - 38, erf_imp_ld); - b = 0.5640528202F; - } - else if (z < 85) - { - // Worst case absolute error found: 3.080612264e-21 - r = evaluatePolynomial(z - 60, erf_imp_mn) / evaluatePolynomial(z - 60, erf_imp_md); - b = 0.5641309023F; - } - else - { - // Worst case absolute error found: 8.094633491e-22 - r = evaluatePolynomial(z - 85, erf_imp_nn) / evaluatePolynomial(z - 85, erf_imp_nd); - b = 0.5641584396F; - } - - double g = Math.Exp(-z * z) / z; - result = (g * b) + (g * r); - } - else - { - // Any value of z larger than 28 will underflow to zero: - result = 0; - invert = !invert; - } - - if (invert) - { - result = 1 - result; - } - - return result; - } - - /// Calculates the complementary inverse error function evaluated at z. - /// The complementary inverse error function evaluated at given value. - /// We have tested this implementation against the arbitrary precision mpmath library - /// and found cases where we can only guarantee 9 significant figures correct. - /// - /// returns double.PositiveInfinity if z <= 0.0. - /// returns double.NegativeInfinity if z >= 2.0. - /// - /// - /// calculates the complementary inverse error function evaluated at z. - /// value to evaluate. - /// the complementary inverse error function evaluated at Z. - public static double ErfcInv(double z) - { - if (z <= 0.0) - { - return double.PositiveInfinity; - } - - if (z >= 2.0) - { - return double.NegativeInfinity; - } - - double p, q, s; - - if (z > 1) - { - q = 2 - z; - p = 1 - q; - s = -1; - } - else - { - p = 1 - z; - q = z; - s = 1; - } - - return erfInvImpl(p, q, s); - } - - /// - /// The implementation of the inverse error function. - /// - /// First intermediate parameter. - /// Second intermediate parameter. - /// Third intermediate parameter. - /// the inverse error function. - private static double erfInvImpl(double p, double q, double s) - { - double result; - - if (p <= 0.5) - { - // Evaluate inverse erf using the rational approximation: - // - // x = p(p+10)(Y+R(p)) - // - // Where Y is a constant, and R(p) is optimized for a low - // absolute error compared to |Y|. - // - // double: Max error found: 2.001849e-18 - // long double: Max error found: 1.017064e-20 - // Maximum Deviation Found (actual error term at infinite precision) 8.030e-21 - const float y = 0.0891314744949340820313f; - double g = p * (p + 10); - double r = evaluatePolynomial(p, erv_inv_imp_an) / evaluatePolynomial(p, erv_inv_imp_ad); - result = (g * y) + (g * r); - } - else if (q >= 0.25) - { - // Rational approximation for 0.5 > q >= 0.25 - // - // x = sqrt(-2*log(q)) / (Y + R(q)) - // - // Where Y is a constant, and R(q) is optimized for a low - // absolute error compared to Y. - // - // double : Max error found: 7.403372e-17 - // long double : Max error found: 6.084616e-20 - // Maximum Deviation Found (error term) 4.811e-20 - const float y = 2.249481201171875f; - double g = Math.Sqrt(-2 * Math.Log(q)); - double xs = q - 0.25; - double r = evaluatePolynomial(xs, erv_inv_imp_bn) / evaluatePolynomial(xs, erv_inv_imp_bd); - result = g / (y + r); - } - else - { - // For q < 0.25 we have a series of rational approximations all - // of the general form: - // - // let: x = sqrt(-log(q)) - // - // Then the result is given by: - // - // x(Y+R(x-B)) - // - // where Y is a constant, B is the lowest value of x for which - // the approximation is valid, and R(x-B) is optimized for a low - // absolute error compared to Y. - // - // Note that almost all code will really go through the first - // or maybe second approximation. After than we're dealing with very - // small input values indeed: 80 and 128 bit long double's go all the - // way down to ~ 1e-5000 so the "tail" is rather long... - double x = Math.Sqrt(-Math.Log(q)); - - if (x < 3) - { - // Max error found: 1.089051e-20 - const float y = 0.807220458984375f; - double xs = x - 1.125; - double r = evaluatePolynomial(xs, erv_inv_imp_cn) / evaluatePolynomial(xs, erv_inv_imp_cd); - result = (y * x) + (r * x); - } - else if (x < 6) - { - // Max error found: 8.389174e-21 - const float y = 0.93995571136474609375f; - double xs = x - 3; - double r = evaluatePolynomial(xs, erv_inv_imp_dn) / evaluatePolynomial(xs, erv_inv_imp_dd); - result = (y * x) + (r * x); - } - else if (x < 18) - { - // Max error found: 1.481312e-19 - const float y = 0.98362827301025390625f; - double xs = x - 6; - double r = evaluatePolynomial(xs, erv_inv_imp_en) / evaluatePolynomial(xs, erv_inv_imp_ed); - result = (y * x) + (r * x); - } - else if (x < 44) - { - // Max error found: 5.697761e-20 - const float y = 0.99714565277099609375f; - double xs = x - 18; - double r = evaluatePolynomial(xs, erv_inv_imp_fn) / evaluatePolynomial(xs, erv_inv_imp_fd); - result = (y * x) + (r * x); - } - else - { - // Max error found: 1.279746e-20 - const float y = 0.99941349029541015625f; - double xs = x - 44; - double r = evaluatePolynomial(xs, erv_inv_imp_gn) / evaluatePolynomial(xs, erv_inv_imp_gd); - result = (y * x) + (r * x); - } - } - - return s * result; - } - - /// - /// Evaluate a polynomial at point x. - /// Coefficients are ordered ascending by power with power k at index k. - /// Example: coefficients [3,-1,2] represent y=2x^2-x+3. - /// - /// The location where to evaluate the polynomial at. - /// The coefficients of the polynomial, coefficient for power k at index k. - /// - /// is a null reference. - /// - private static double evaluatePolynomial(double z, params double[] coefficients) - { - // 2020-10-07 jbialogrodzki #730 Since this is public API we should probably - // handle null arguments? It doesn't seem to have been done consistently in this class though. - ArgumentNullException.ThrowIfNull(coefficients); - - // 2020-10-07 jbialogrodzki #730 Zero polynomials need explicit handling. - // Without this check, we attempted to peek coefficients at negative indices! - int n = coefficients.Length; - - if (n == 0) - { - return 0; - } - - double sum = coefficients[n - 1]; - - for (int i = n - 2; i >= 0; --i) - { - sum *= z; - sum += coefficients[i]; - } - - return sum; - } - } -} From 64fba9470dc3bc3c40d247c790dc6cb8986b965b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 7 Oct 2025 18:07:58 +0900 Subject: [PATCH 60/78] Invert conditional to read a bit better --- osu.Game/Screens/SelectV2/SongSelect.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/SelectV2/SongSelect.cs b/osu.Game/Screens/SelectV2/SongSelect.cs index cff71c4fca..516f8446ac 100644 --- a/osu.Game/Screens/SelectV2/SongSelect.cs +++ b/osu.Game/Screens/SelectV2/SongSelect.cs @@ -325,10 +325,10 @@ namespace osu.Game.Screens.SelectV2 Current = Mods, RequestDeselectAllMods = () => { - if (modSelectOverlay.State.Value == Visibility.Hidden) - Mods.Value = Array.Empty(); - else + if (modSelectOverlay.State.Value == Visibility.Visible) modSelectOverlay.DeselectAll(); + else + Mods.Value = Array.Empty(); } }, new FooterButtonRandom From 0ebc90462d2c06884e9004f670ab2800837e0865 Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Tue, 7 Oct 2025 18:42:42 +0300 Subject: [PATCH 61/78] Mute SFX when holding restart beatmap bind --- osu.Game/Overlays/HoldToConfirmOverlay.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Overlays/HoldToConfirmOverlay.cs b/osu.Game/Overlays/HoldToConfirmOverlay.cs index ac8b4ad0a8..6cdbc6450d 100644 --- a/osu.Game/Overlays/HoldToConfirmOverlay.cs +++ b/osu.Game/Overlays/HoldToConfirmOverlay.cs @@ -58,11 +58,13 @@ namespace osu.Game.Overlays }; audio.Tracks.AddAdjustment(AdjustableProperty.Volume, audioVolume); + audio.Samples.AddAdjustment(AdjustableProperty.Volume, audioVolume); } protected override void Dispose(bool isDisposing) { audio?.Tracks.RemoveAdjustment(AdjustableProperty.Volume, audioVolume); + audio?.Samples.RemoveAdjustment(AdjustableProperty.Volume, audioVolume); base.Dispose(isDisposing); } } From 568ddc2d2d7553fb1f214cbb9a6db4474343ba59 Mon Sep 17 00:00:00 2001 From: Denis Titovets Date: Tue, 7 Oct 2025 19:01:50 +0300 Subject: [PATCH 62/78] Fix `spinner-rpm` layering --- .../Skinning/Legacy/LegacySpinner.cs | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySpinner.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySpinner.cs index 5a95eac0f1..569e01ae56 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySpinner.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySpinner.cs @@ -62,24 +62,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - spin = new Sprite - { - Alpha = 0, - Anchor = Anchor.TopCentre, - Origin = Anchor.Centre, - Texture = source.GetTexture("spinner-spin"), - Scale = new Vector2(SPRITE_SCALE), - Y = SPINNER_TOP_OFFSET + 335, - }, - clear = new Sprite - { - Alpha = 0, - Anchor = Anchor.TopCentre, - Origin = Anchor.Centre, - Texture = source.GetTexture("spinner-clear"), - Scale = new Vector2(SPRITE_SCALE), - Y = SPINNER_TOP_OFFSET + 115, - }, bonusCounter = new LegacySpriteText(LegacyFont.Score) { Alpha = 0, @@ -103,6 +85,24 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy Scale = new Vector2(SPRITE_SCALE * 0.9f), Position = new Vector2(80, 448 + spm_hide_offset), }, + spin = new Sprite + { + Alpha = 0, + Anchor = Anchor.TopCentre, + Origin = Anchor.Centre, + Texture = source.GetTexture("spinner-spin"), + Scale = new Vector2(SPRITE_SCALE), + Y = SPINNER_TOP_OFFSET + 335, + }, + clear = new Sprite + { + Alpha = 0, + Anchor = Anchor.TopCentre, + Origin = Anchor.Centre, + Texture = source.GetTexture("spinner-clear"), + Scale = new Vector2(SPRITE_SCALE), + Y = SPINNER_TOP_OFFSET + 115, + }, } }); } From 1a522a19f10ec9a56de41abc5a3eb8c29b76e366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 8 Oct 2025 09:01:04 +0200 Subject: [PATCH 63/78] Disallow zero-length sliders from specifying a non-zero number of repeats (#35220) --- .../Objects/Legacy/ConvertHitObjectParser.cs | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs index c5a6c9e83d..3010373252 100644 --- a/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs +++ b/osu.Game/Rulesets/Objects/Legacy/ConvertHitObjectParser.cs @@ -476,12 +476,30 @@ namespace osu.Game.Rulesets.Objects.Legacy private ConvertHitObject createSlider(Vector2 position, bool newCombo, int comboOffset, PathControlPoint[] controlPoints, double? length, int repeatCount, IList> nodeSamples) { + var path = new SliderPath(controlPoints, length); + + // there are known instances of beatmaps (https://osu.ppy.sh/beatmapsets/594828#osu/1258033) which contain zero-length sliders with non-zero numbers of repeats. + // this was exploiting a bug in stable in which the slider repeats would be generated as objects but never actually judged as a hit *or* miss during gameplay, + // therefore increasing the theoretical possible max combo to be gained from a slider while in practice never giving that extra combo. + // due to lazer ensuring that an object has its nested part fully judged, this would result in broken behaviours + // (either the zero-length slider giving hundreds of combo for nothing if the repeats are judged as hit, or insta-failing the player due to HP if judged as miss). + // to remedy this in a way that seems least damaging, detect this situation via a heuristic and reset the number of repeats to zero. + // this technically *does not* match stable beatmap parsing or conversion, *does not* match in-gameplay behaviour of such broken sliders, + // and *will* fail conversion mapping tests, but again, this is supposed to be a least-worst measure to prevent exploits. + // it is also applied centrally to all rulesets rather than in specific ruleset converters because this failure scenario + // translates across rulesets (osu! and catch are both affected). + if (Precision.AlmostEquals(path.Distance, 0)) + { + repeatCount = 0; + nodeSamples = [nodeSamples[0], nodeSamples[^1]]; + } + return lastObject = new ConvertSlider { Position = position, NewCombo = firstObject || lastObject is ConvertSpinner || newCombo, ComboOffset = newCombo ? comboOffset : 0, - Path = new SliderPath(controlPoints, length), + Path = path, NodeSamples = nodeSamples, RepeatCount = repeatCount }; From 4337046680f1ed956d9de9add7fa76b7989f6a77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 8 Oct 2025 12:39:48 +0200 Subject: [PATCH 64/78] Add test assets covering correct layering of spinner SPM metre --- .../special-skin/spinner-clear@2x.png | Bin 0 -> 9933 bytes .../Resources/special-skin/spinner-rpm@2x.png | Bin 0 -> 14667 bytes .../Resources/special-skin/spinner-spin@2x.png | Bin 0 -> 20956 bytes .../Resources/special-skin/spinner-top@2x.png | Bin 0 -> 659281 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 osu.Game.Rulesets.Osu.Tests/Resources/special-skin/spinner-clear@2x.png create mode 100644 osu.Game.Rulesets.Osu.Tests/Resources/special-skin/spinner-rpm@2x.png create mode 100644 osu.Game.Rulesets.Osu.Tests/Resources/special-skin/spinner-spin@2x.png create mode 100644 osu.Game.Rulesets.Osu.Tests/Resources/special-skin/spinner-top@2x.png diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/spinner-clear@2x.png b/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/spinner-clear@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..8d1ac13c235d169a5412c1692980a8add6bac3e3 GIT binary patch literal 9933 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 ufI%lMT|D!!|4#A0UOakjJ6$EGJk}N%Yad(rP zrYN-tR`4$<0a3&!u|*$6tm1>OzLdU*eH7|l=}SRm&Mk>1P3T2Lz60m%?#wseH{Z|2KpKDT}Aqgxe4**-qjm{620M-^r0v3u`P6y@<3-)$+1GL(-UFBN6mL-M;x zIk&h|QSSRbo}8+tn$L$cOKOB=5wEqAT#=vQk#t6oqOmSb~4_o&#wmTsE55g-$Xwh>}a?R~Vp>TtnCIMF!J zGgdHB*Ji3J4|RQhe!ezu)v{t*H-jM14Xk5~3MNo_GOb7(rRA=^h6XQb5$9E$rK;3O zqHMORYg*rjBp;|v%icKAEYaH}*Ug$Ced;*N=s+%?Em|GpjOx6_6P{M3Zr03!Y&*%D z&4Ku;YLjFjT~_<&svAp}lP7boPw+CEEhyhV$J1(8zhh-J!Iy?+RbwlgPjE44oX=!c zR?cK=48ov##ZXkSSi_*KSs}{X@fxDCW+0k}qXj2bR!nADs~Rd< z=F2CgFdxEaXLojcnVd z$ftrMlSVGJUDL9e+i%~<=&TGX*}j`#ETb`7nyk=bzU6w1AQ89@@~BM_v9N~(6@g0( z*CyEOYkQ%Hr{k2gmTQ&0VlfM`5d?w3T;x(r5O!>g0*^7|x|mzU^?k>;G<6UK;b_*% zie|=mU9&V*&bCy~(~8Las%vJia7u=1YqneHVZ$&C-ITw*`s3@=FI68&I=-cv^NlV!7_}y5r00uw`LMhfbD;V{ut!#mOFT4)a%f zXRTQ6BxXox*9|HolrybY9IrCT8yn89+W8rt-Y{~zVr3?(c~bCw(>$%#%?y35&X;8F z#$C5OH?jiXM4UJT3C9+QxFSHFOI>d8$i!aMcYU?4n`Ve{KaXyv>%B&FhNRP+)iwPV zoWZ{Dnnoay6;TI8rtP4}5dkuo>3WQrzJYPy;6I$fIJE75&l#GfbG%pn&J=3|)KB7%$>wF|gdqpbP44w6|`=`NF2cG8w|c zj}WJ}hazEHhzgD)!}GaI_dvgP z4Bg@M8BBM-L(5~K69MZ4nT*3hP~MJ+yFK>SourMe!K>lgu!67@XijZYb8-VsI7-i?|jNj>(aQw3O+Q{AmyUpJerEzY&v2U`y_`~IIhE5v~ zZ~o$|KTo}O>4MteADp@V*|(ou+M_7#cV1mkE}nn;`u)GWfAx>f?a=A-JC1IWXBv4# z9@Gcn5=H}p0dfIQ03-ww0ttbHKtdoPkPt`+Bm@!y34w$_LLecK5J(6l1QG%XfrLOp zAR&+tNC+eZ5&{Wci_D-WD~{mRg_?>@eC zLEj;s`uf!P?ho&hIvQU-B@fTQ^6S(Vc|7~Z5qUU02A41z5DbtD zfC3;PkPt`+Bm@!y34w$_LLlM)iiFn|e_yy;&gsQt!|>b=p4-85I~fGnZE#vs0oAs literal 0 HcmV?d00001 diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/spinner-top@2x.png b/osu.Game.Rulesets.Osu.Tests/Resources/special-skin/spinner-top@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..aa0eb76b60e0d8918e31bdb3bc1f6d962452a63f GIT binary patch literal 659281 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%0DSIRg{@ zDVHkV9vd8&IuFX;s66d+meD)X<5M75^ctu-(cNgJTv4kgkw>W80&65l1>G6}wXy{i zMR6ahBd3%?1GmmR`rsJZf%P1G_j}SBGFnhwp?BqNw!9OeHsZTh&AaP&SwRCjHP_=g zZ*8tkQ=kLNc}0@3pqIcRMfp}y-H-G{zzNPkGWDg33Na>rl!*L;4==CI>SZ20Fe;7Z zR4U@_mo-X$%J2=N!#-0Nw3YJ*5h}QR#5zXOH4Hq*)?oKdvM1d_jJGFDov(-w6<5%( zM>XFs9vm)%to}1>K>t_z2+8Yp+=61!Fz7V^u*j0%lw%Wb`5eB(yZewjf_$gAqu}itHgU`;re&c&d#6o7L zhFs$x6rl&PjkUgcejt|Y&2xYkjAmTt7UoY_^S)D# z>rG)d%pzOpgEMr{23KE-`!64|y(ZfS2I(cFo}EX6H`9qFHsuu2vtFp*|4Oa*4j#h6 zFANrjGx0dKXRz%B?fXJfN}@3rUag&NOw-$ktgV4WZ5BT+ z!B1nn1ig;GdEx2MJxm8BnO?4JAZcI@W*Tt{8^I5I7(iKrys{-b>;xR(1pUwZPUe5} z!?9lY{^`misGFp=)#Zcj6iBkIK)S+Zbr1PZgcwZElUIlSA`jJvRn-^0YAz`U2EeL%N zbhIhQL5^kQHnmE*i@(=&oAIl*Hn?u~N(u+Hba>z9l8S0rL^+`pXYD=p0Zs2YoTXqN z$A2T3Zq&bzt!*EY#&{h%%TMCA33e9FUkhab^~IjI2owQg$SQwEE_Z&NN8IB2hhmbY zy$?PkS*%6nEUtss=s@DX1u}@L1f*IsCtd_ewIXf;zxrD^p%h8^--(~fij?@^r!FPD zsnXn706KV_w~r=D8g!LJs;B?nANYG^`4B8*ddcb%b4M|;Jp&csKUn_l1<_`9$Lv6p z0r7zOIuvRYfOgeQJZvpnYK#0Iq4ewn4ey&FU^vqS8LVP9OB^@k`KKf+GDhI5OFD2y z-@sl7=+N7ie}anUGTl~M_FMDjquM5{5s!PYKpnPq>lG?OKQe7@T1{?S$MRY{5gRKM zXaU?Rj-y21IVemO`*JvArw&$;La=;<4#@)QDU;E5S^Vtr<6$*( z7|msMOT4SE$lLu!OY9f@@@)+1Yk?l70|S3s<1`oDiOEm11dP#BlhLFqM>3fd}*@7178P4 zA+KbNMt!X}-W5m82TvT#*yJjiVc1t+pk?K7J~15*!kKF40%{Q%#z0bW0oyWwch=}$ z@Qe%<&JR=eN#ElL!RRAm&DS=|GQmw4shrIbkFYP-cRLl8)k`Ek1g5?JTy#kx9220m zS06+iQ{FkU{jDv#xv1)d5*R@$gg=>KJ*WwFHD*87hrAH$H^ob^e=zxJB5=el`sLSH zOEn0BO9G;8oc{LOOP+8{XW!H79>cFp(qUFKANl7J@MtsB5;18XcMen_y7M3d-?Y!jT zz&;=>e)%h{ewbN)%4q&1_Vv0!_=|VTq*urAs5T-3H5IYb!V+&6CJmN~jIWmIk0N2I zE-|Gz1zO5q*{97RY~Sef*yd~Fpw-mSCjpTqfl`b&R~c_8jm|u7j}Zj#OBoZGw4<${TeKK}(R?y%UWHIdf!)$MeV*O}#h_^GP zDBHu%W?myb+ba64dhf`NmE;P~>2+9qNwKlT2>#rZvg%a}K|;53W@A3;M+b-#9aUa% zb?ECW1MIAx6fWI{Y{OoYp6opn8}IIYw?3TttC}p3m>VMQZa%=0YptXg=dA6H+8ysp z72X)UdYw`aghdX#jTR!F865gv&4{O$kTGj0KwjZ~_42u~`$t43Lod)$;92>Op>7>Z zsFh%jcp(G8Uz~Optmoe}^W$LGDA^MA*!Kl6_hDYlA^NvW^km>KX!C8O;>E@p+>WF@ z=i8X?*ypfAQ!^O8M>~8Tamn9kiKRGO^aXj6r)l-i)_1-H7f6E)vt&%`GK;c}A!k$J z$rg_~wWcx&o(UOxrN=1BEQb6QXm?glahqMsW z;YDz01qyed9ENq^w6PDvNI{UZ^Gou{pYx)mf?}QVC`l*^r=a;CS+njsdnt)(l#cnc zOZ%}h)KrVwKbLcCyxNVY8kN!!U4xt#zlbp)?6~+ka zFBz-p4eLbWqK)8kt+X40A1c%Zjb)tWEb2(LMhxP!YPH4 z9(99k=iq2tA!C|{RKd?NPlE+xu6J#>QPX{?pY#x_glsv_hM@g}1URGMN_pmUS}LI06=#50=lT!V&AJT{|m?8@Ag;~Y4XMb?sJ z8vXn&uLthFdW581d$c@XoJ2qLrim^9j+Au9LKMrzW&>9lB+xsZ!^hjk3a~Qql3;bo ztNbgOwp)6T9I3BmIf}8VOw=?c0kQ#qYLdY&gDZTH;{#oTDt_}aZqIu{&WfRU$(b)7V z{6b-+$B9aKL}x_hV8#2Xy4E}foRY?XC~`tiyib>@iM-rIf3MlA=h+Lu6Cy(Y`J6}e zAnGIGi%oiC`yj5C6E7ha&zkgGXrg4+`w?!Jm>%VAzU#sMk0e)9BfsALva#iC7Hcp0 zqb8R#!x?kHsX$$nU%UG=uc?CJRM(CK$|_I6AscN7bIK4wCMG5J44L;4r~9;j83lf& zx0F(;vL|pEo+G z0d}&WHXkN|4A>TDg6xUs!sXtm=e)68zs&L_YemKRW+4_?sxad4d`0-w-sbWL+OwBB z{IkWkw&dntye9@*Y(<&+z^{sX*PObQU!TL>-CrrP86^_3<1y0IhB~|NeD!ueoM0TO z8V1-C=ob;H=2*_ipXD;=YSww29h9h;$lSQAX<6aegJJd~KEj91q?`7D?3{Ua=J>}= zv=;;`B1oEP<^;e!{vkJ#Ugw{Gkq;aGC%XP-IHB(aYTo~pgrR^dztjEhw5&?=JOxWLi_R@`U@-(nil=Xh>@Rje&cFuL`udJcB^mOQ8 z$c3n(Ml!4=!w8Z~9O`GR^2W*_YOt-tQZ{ zPAiABOZ<*0Hc{V*$sQl*0B?8)mU?);;7Ed=_ zDtI-ND0MOjRC_8}u(G2L8yFluZQj9xsF?7-hE=a>@7-mv`h-=@aNM>%FRbwGnOGA# zJP9dhIj^cN;iC9dRDZM9#O3x7le)Bw@L|_B=49;IBNiL z^UFMaRGUtO5+!9z3j>_!&Lknk9mZ8^{nCd?lf7DV$Uux?2gVx8rJ}3!!KDL9i=)8}#mf_uC!^o599xQozU7>9h$d8zoHPWS>2w`Q%Y_meCC2O{ zw1q$!4#NHt8d8?O*5YRbJAJ4NywGEx#*GX!f~rH+Et(0u;Sjvp<)H{WOHjP;U;NV! z%SUzl@An5^g7QGUO4HBFwJ{aC+Ef8XLizca3{2BrJJ>4peq+vJ#8?bioAK%8955z? zl%A8yOb+)B)@u4x*VqsyQe&F;8cczQ`_6?^(5f(>h6t8*r>%7MCQ=|UZ-2j(`P0lC zapXsP$qkB0c|mXm7-MoJMXl=!Rt8wKB%vqce@WwIBR>TU(myV~8NSm6S~Qp$RdTiU zWKD(U1b$iH%f8MSm$@do^kFOL8m}g&5L_Vn(*2~Rq{Lu3XQRobY?L*a>T_8zgd()s z%!2z|>44DUIzEzE)z{hmPtGW^0XF&82?I<0(yv`Wx7AzY%|8fgG&kPAn2Wid@4T~l z9JT_sX4T%=q&qv;0A=lG-39Co*HzyH`dM6QqZ-{yatc`|koH}MUsV;}I`u64js#+J z`M+Vu{OH7@cojKDqv`5TFO>kyQehY98T-;{#Kv>R7?B3FY~qPt&ST%V-aX7xPNEPV0=p&QFBmE1(lXG^Y3 z#a&i5Baz^9Xm~g#(~?u)WMwcpY%x)L9Zjo_=X+Hzuv4vCZ%F3#OE$kp5hK7CgC^U7P2 zhcrAVQfCgYa`>K%wYG@0vnRGas{5Y%7stpUK(DQ3LI(IwnDtd%N*Kx6eslf8RqFZq z^8FnC-{8JR!B%Tv8c_W@6ZL-4LBbNEKATmw+j3Z+<$JpPwoihuh@s18*u{CSxl5xQ zsZadTQ;B68gOUS)AN#&&b1yEbAuB1vw9NK>jsqLazhizack*%aWZ7YJ1px|vCL$A0 zDt>#j8FK9)b*%5$-As@ED0T+~OOQg7dNPbXcY0@e@ASWGSH06zTLhkx}Er!uWD za>t-+&z8VHpXo*`d(5_DV2xSgCulkLbJ>9I=H?lUJ;&r!mHqb(tS)GbMRk$7!uhU% zUzqA`d9A@UcOefcgeegvTieL(H?{C_tXXr)l%s$m&f()W)#DEA+5R*lthDp8;^5tZ z+YFE!Db0@^y1p(3YU_ENxz2`3I9T2`&W6rPrOnsM7)&rZzhR25xt>nAnVhF27X(NY zg^RpgKyT-LJG1F8+ehPAm!$gm`G=j~s@>Q3e(=NTcdc?|V!BM>B$> zAMWMvy~AG%=F+Gx(N&um3k?^I*`%B?K(Z(jN7M+=(o$`)+t}&93MOo3IN5-(1V0_6 z`ts#=>?#M&Rc#~xhpJ_cwOdJN);IuFwixi#@JgKgmvE`z2z+$MA%i5TTU`l8O`R8H z$F`!ZYTw`7aZP^l?LcnhrCMvL6v5Eq>?zjbX5xKjq=N(O_7-rNo zUuQzF`wh584miX(CbNFGk(sZMhh26EX3p`KNwQebfddugjJ!Y}V>(bOQ zJD62`vr|F$Spz#(8^Mb>DO%o|eDbcW zE4v%#3sp`WCqzhzO1al{`>1=Og!Y8*(Z)l?6lF^2tSC12q zL_9y9RkUW$Ol5;rm|UBkeN>YIdFRceyn7=AE*~-lc=Es5`$k-6AhyA! zioJ}rY*nnSzEM`R&MH=Z#IfJD=OW%@kXE`vty6@U`Nng{SWWmtCa+$J`=WnGgKMc< z{)x$;ELcUTTg#R4N3=A=`d|vWHCS!r@OMpI=o`23*TpiVE~bub?w zRW!ztLv@N|YV@`}VDeyIOQ(ccaFC9ldN9z(dHH>Oc^gCPm(x16u&^CS9NtiGvxbA8Hn|y#PCnP^l`xFNbnG?YVdhI>r&8Y0R!QH9=c)y z8&g_1Y(kLy+3IF|!k;@&W=%)0X2@nEj3H2xtg z|9zmoh46dyc2Gx+LLasjCWkKzTyStgztO2fC=J^9qR4B6pC1`EXRFBmR#zN;Xa5L( z9qEJJG#0A!q$x-O@&Qu`c=5b5a0IWZA~Rq1s^GKLhT~_q#$H z>t43#W;60!Bi#%t^CB8(!f%%|q{uL_$=ns?7 zP7TNiI}ibXWHft_4?4cYdzHSeO>ur!T5?xmqXG0jNOKXz`FLz04=?%DFu1Aw$AsUK zkRw3En*QZ@Fn9H$k6aPK^u@WP_+Q)I+K>Ed@6nz)|N(QqB|A3UAe53q!8Q^mH_IkW`Ek4n_Z z^sQPOqN<8>(P>M_;*L*KJotxkKUong`kt>82q7v!(9g%BZK zlkgCN3%T0&M*o2r|9hEiKUBc(Ndg$?Fu0kalG*p1o)(q~1L7#`Qnz;o-E+0BA|;A4ug3e5R5W<~*$TNi_U7gQHyy3H3`0|A z<@!SB%yT)bLGU?dBYPUBN1LhT#xB(x&G97>^L72>8FSi-{8fnU?UgN|B$@W!k_sXr z9%}Qhq}`9KDh%qN(02MwS+Gc%?X=CrSJJa@np@y` znsWV!9^o4j(u%^3=Zu>Qoss7V936f)nPkDAoq!+wJ3n_gQ?$35=y5LK@62~d8BsYb zlcsDvW$NJB7+q1gA#vmov_B`xTKtC#hZ|K|m9FT)D#~zNt;8GjREK?r+qlr)%A0w0 zWGnEwt(#Xxs3{Ifcn-P5q&lwZeZ+Ky=fqRuQX2KN$lxd1J5R-%&i^!FTSmQm9F~UR zm=3@$9u2hFVRBiS#1mXYIOI7vE7v%G;e>Afe~EJgG2Nl1qL9=3sf9b^5~>A90ypdBetyA0D;6gWi-Q76pqXEWH+W zt{479;x2=it>hpSFCg-wQEQws8d15%Sb8QfGSeG83l+#Rd&O>0h-m z)@*h}H+RUtiu@o_U)bQQ$N}yx2reth!_daUbYtAd<#d3{wwAs)bvtAAaQy^s2_vsG zi|*;sBYSz<7wEueKB0JVZ%+#9$=NIR!OU7Aalh*ZB={(42Xl}Zz3+mxl2pSRt_cd{{ zHi&y)n^5K8tewuBNyLG)J9Up|yfJznvrJS8{KQb&8rb$ZDmLVv2#JAql4kwBT2HEM zz2t*R)%-u7RNz|~`kt+(sq3VG&t5Cbh4N%ryl}xMGWTCZEQ2dd24Y%2`ZdJY8GE_s zVduVm8P}UVnQhp^49cYa`{Sumt|@*xy!tVz{9e|s752|SXK2n`WBP?llnL@U+=pGO43K4pD+yg zQnH+Mkoo$b>N@h=zdn(joXQM@GsP}E&GU*2&t2icKYtuI-*IQ-esPlHeQp&>@i!;e zwxRi(2gl$*ZF~xPw!8Y1RbSxf^|h-U1}}xQm=YFbXE+prq)vC|d3N42S09cb7aA=~ z2hlYN*KBWZOB%}+xvOrRin?{s>;4)_y4oh>#t(anahH9-11umZ6Wa?>g4S6kK)&qp z;ogA{L#CMxRuc5vFG&RdCqAa(eUp`4h7PYFJ?79+EV|6QS-^|Kg2r;l!3qp98E|jX z^`n*Qk9i`z?EF<2Dw$?AfRn=Ov?(3Z$!mW8Q`}>4x&t(QOW#bEqel z#FDShK9+mwFlh#v3HYM^D3rG^8`9hJYT^alQrJ($FauVGQhq_Go%ST?e{k6=(V}Yqm+vpRX@zRM{#ehE*N7Ev&Ip zNS|j1MlY(Oi;BHsP6RGo{S4!vtb| zeFToEz;;BA)QWHuT{^{C-FB9&{q51m_nA33@rQB$CVT!{u8jemxNXqWKCZ)h;Rh`= z;y6QUbAkPREbL+T%6J(lPuaK9;RHlxOGDjfje@NKYKrRe)CL_DNBF+vV0rdiu3Y-*j}yhn9?qzRNf6@>F0mQ1&-gU&VGyyD6^) z!vyg*gZhH5THv|2l`$-7l#ffc0?(OtNWb$PlUUHhsKV-`$b$T0AAK6ZcV&h4t&##9 zaGbsErT6>4kMvl2fHq51ZEMS)MvaH!xR$@Mh<_??^=t423z2NG5&P3)hzAV=@G?j6 zzPyh#Wp+#76v-{g{Y#QNcKZag4pzn4=VeuhSgyb?wmU_6esJC~B*T4xsee=EV5SwQ zkrq3{G-DdH(hu> z44NXFu5tExJ}G?whvrjm=B>{2bh*ur%uXPqI#OchE;=YkNt=7IE?MYBI3-&4;L&Wu zH6frlS@?mzBp-R*D0Xc}%Q$dNexj=gFg6Bxg1~H}{48_~Mj;G2ZlPo^uZf$#o5@*) zw*>LVklpA{FJ=kUjgo*yNa%@D)y+1}!(UG?gfRTeDo+W-mWiZ)3jOCX|Hml1dwkdl zaHzd&Vz}Tx)U!?yhtEu=M?S$e(c-x=I=3j+@xwdQntzGaHm&m}F!7Zz5O^H>K*R{j zmuFl!*6b{QESmpm4VnvJ9}}uMGVB$vOu4S^=joBBq&2D73VSjp`<1BNEp0##u;XsI zEJsLI$E14h>7&`6vug}w-S3S*`$H0IrztH$Vhj1oroc=21g>!woai{oa@|sK;&nZ?y73!O2v-U`ZTe?4=F&EIe zj9L7cZpp^tyi8k}_+1hev+Uuvk-+xw_q(mS_JW|>)z~boZvGQDTa$=;cr080p8^u)KDWU6tTr!ZdQc+%{gsge!{ChL-^N_R zecx(pZa)w4b@EbY5Im!xodt4?Y1Y46`rYC4ztR(kqL=~GECV6o z@B@z8#o_n0GRM*f7~0qh84Zhd!g zoHTn+rqE+p&z$Lp)Y!>t^;5+>E51`%N*q54|0b_Q2I5UwDLwY9D*~IOX3abC@)E^j6QpO38b-K_5 z#k}_eq4EN3#pN$GzKv$vQhgXGld4Axwd6g-)9n1li=s~e=pCa~epAzqSN5pHWM9g> z>>sTNTr#$ps9$l8*Xv>6F`_l_Pz)La`?WfGV&fQC37wdW(I5X* zysO$UBYpU0#Q~~e8omn(W4d5kkwU)zzlEX1*Bp3rfRr)`U-;%LEC=Tr2J{BTB`-ed z*Mz-_L&JaFd=-^+SBmnN+Q+8j&$1= zLOeZG2-f<3xma%=pB-T$6(kh~U#tmim5!zzr&VTB4Hs)oZ7~Qj`t11pB|LWjxvVTc zUewoOE=)gKSCtKuE)iFpZeUzo-u>l$)0^{}{92zL=E$aebKLN=a;}7oRc( zZe(1!X%bLEFPA1ZS(Vm|O~GQDP;;b!<2b{F^fLfRLP15~cVUahC$&^Tg$x4y1dz$$|%%ro9`LWv)s zRq29_)om6}*qJ7J0EH(8o1SF|%-DppcXT-Z6+kxvkj<|(We){d<;CI9t8-ZLK8_%_4`_=ZA+)hNaDu;n+ zJCNk9ezQYO4d!I-nqIdu9UM5=NQb{|84&_DkbXV!`v@Y`!Z|jOwWj`A@h5JQjr**E zY;a+Oj)D=zU)nFuZe!yBdv}9#Oxes;>6NQw$&aGrO1qf{dj`^h;(WKktUWf|x-p;U zboN21Ctl&NN+aYzTY@^>u6p+6Njhw9^VaOX2Fx+9^A@I4pc&pd+ikjxt~+&Usge)O z>(S@E`i$-*la#|_r$iTAfqY%m%2N#e^sJ1e=sCfU?=5L~Vih!EVrKh{K33l;TRTPX z86%Q(Q=%Vla@{ZiSa$UA1Bw??WT;BJbn0~b40|1anMU?J{542!cvv%1wPPODs~@It zm0xZ>s{+U_4e4PiHXa{tFnseW{`)!Z8F7dIY%&i!7fL_?UQo%zvVV6rb1~8vo+H(9 zXY=~?K0fMr0)U=)KUoC90}yR5fk6*p3!~9Z&A^jw_Z~#f07y;q;;l%s6trI zVBD`lL7Bx3Cx$*E!uqErC1u9(TlGNQ=7skL7lxOdGKDK}hMi~p~Q{}1jG@a9+Nw{5hPsnxDdDk@mNXm&HE1UN=4fS2)3 z*dLF`Y^lGyK}@L56S(-`L1en`DO+}NTtY4_;MdjUP=sVNeqc5xkQqNC%!lJ+b_InF z``(3#`L?5o^pVIwX@&f-Uhr7g!aiHtpZbNOO!9Ht8Xx&8r(!XS5(qh*&=R1*8~(O( z@4LyZhT5PHTWMjSUoKRnuVT)iuBB@@fojEiG@(N9wDk!elYw~u(D!}R{%_ynM-!8d zMCl~~FXeQw{^B_(9lb>cLD6$M zoP4{mWxwplbAXDUrUJu%ByO5-yBNJmnyYOgw!d^@QgUX00T3!n4IPhH%}QIcl=!LK z0}*=Z3n=Cco#@uViJV3L<|RLJEp5JWop2XXQjL56bAM2oq(OXM+=nBccc<1r;T~bp z9-+JEO}7j=xQ`_`Nuueucrg4lZ{FEl;*2!!czC1g!eN(gQd={*Inzd&e`c5_yy}ZV zBe8TkoNt&ZyU`Fz7DP53h`jdv#0ylAQ5|0?lzKE(zmYa7Zqc6EbA9JA{dx(X%2@V3 zF)m8|_HlNp-zZKPFo2!^_tiR|LGvZWN_DcFNc;a%FmLHDn4$ONThpdGSo;++*eDPm zHk(x;clHDOd1hikp8iVrUKaK|uJ4;r=PeVDYv@xUBJ?NDL~hQi$M)z$!M-@xESPTl zOfw-Baw>=LneS3iOT&4Ldgt2}J@hAO|5JOneOo_uf8VSw12OEtozq3Zxt%6SqGXfM zgDgEC;(c994PHKIv8BJfYN+0FxEtw$c>fN>KD?bTw_!3Rhm?DO{3#2bz8(4=y=`f2CZUZ^?TF5Ks;;dr!!}QwtwNggJvD5#Nlf9}OyLQKFIarH-V(1g zpLT?15fSezf-sk|KDiZ7JoT>%<`8|2?q>@rzk(k6hCId_eGH_n9F80|fThn0oXFAd zT*D5(fMextq&4V#!b3sTKI`X;f|(K-eAib7hI*r z;jkXJl%iRVNy(x)9jp+Qk9>CEn@Z(|XW|>hVLhmU=jxngP!5sWip;9mXa-6*kK8gq zeQ}@betU9_A2pISx)?Y&ajtb4U2*}+j~{-AG5N@vSVQWASs8|ZBu=jo?aeEHUzF}L zFFzO1UR;83W5ZoIT3qrviYc?zmcfoS8{oNc4xVKVmS$50d8zuAoj2!`(r&U~R{oq< z1I%(tREPhTvU-u}JUU1F9_}`e-AVG;g}5~-UX=D|-oM6hsT+t7!r6?>H;Rg9M((EV z2Tdc#S#tHOEt0raU+G?jxsoDA>8hXC%eXXF&Prv#+;Ok>LrWJgbXn%b zRu()X{tSCm-BDR89?Il~33h3ux(O3p?Jqc3>%R*JO5?iX4SE5y{LEu)gV;SG&ke@! zWj$YD5@KM>T3)?Yz-#fc|C_n3O(79D#&sP{k1nu2GRs6mAiOOmS6RA(TuS5+%$E9Z8gi`NkGNV$6@hQ@WWTP>Tpl&BAf0U6dW$2Cj6EWTVw7H1l{jtx4H`x1 zkI_}T`!s!AXl(9MC@yEknxpH3QaZr8E&6J9JcaYVZU`K$@AZ)A@ojVMVDEj`-jo#Y z`0jee^84Cw4yw~12l~swvTWH!8p#mJXIl90@QVzm5@(AO8|! zNPk&OJPu2|t#~wP8|pwYYd^Yd3!Usft1i|KTmEFJC>cd5+Adk!2mK->9ctA_=BWb8 zOD)0-s>cj8$g7rzx-W~2N;U%fT?sGgzRS!k!7T0MZXDtU&5K_T*KcwYs&hQS57H!| z_a)ctmm(G8{}PO6k9raju=Vu-o2_$8uzY>O4B1MWe+V7I`g{b7%S=N>XugiF4^`Yr zqNULYq0SJ(+YCBvsevREqy-DD7d~Z08%}26!BWJ1giGmsp9Jz0%ZFOQ@~6VQeZ6H-0|XBJp=ggW!!4Z&fm_KHSk^V}zs2MK zHEhC}F07yym3$o;owy-PX#k;P<5?<>;^~DC>U99GHdt|CmJW20$2F7}J0Bk19EG0P zT$gzNZ1o9~4-Q*v50@!~$5QDxz$F!CBs8Hvx=)&_dJ<24Jdhqyw>fFH3qZv)NXX(EgsUA?%1v$48LnuQE-ulQmM! zD!)qmoI`hf#;x@bzS~UR+B?tHGQ8b5?*qb%_BJ{NG>#hQ@Iwvz@MpP629IYs?_^`| z#I*QEa|u=Kc#UGqBc{4s_{bL*`--YQa0&OL_c&iJVny~WjdHR(%=|6Cv{cVpX*}<* z+Y~BuX*H7NZ_0ET|IASb;WuU5Z@Htdz8>@N#)`?}s+`Gw-th=Z0ZVMddXO|DZM#)j z=lS8E-5kvEkiwx3J60iCveucCDa zOa^7&IWYn1l7c!Om`!fG(=i8$oBsPApCG0h+&Ho7zbDTkue_Mzx1G3t3fGN>QCv`n z(lFzNfi8AFTKL!fZ{c_gyzqeDKcuZHfTNU<>=RG6{H%-D0+v9oNRIw_IALTi^$Ncy z7sSkRpt~XGo%_+dxLzh$gtA1-U~S}xbxDtg^Y)Hi=82FPgzl*et4c00hiKK}WXg20 zuLLj}<4Ial3nHF8J85`uOh;W>hHai1#Z`ll;#W6^MJPsPTdt4K?VWq#y_JYj(v*on zs`=w1cDqJ~MJ&)73s9M0FKqt%V%QADsc_&UnrVaCDVwD{Ys>A&h_V%TuhThKB&pIr85}+_KjFwxh`07)hR$-Qc?URU-tE2yJM|1oX`VXHuB9~ znQoLK<{Xh~)^U~8ba&g?wI~)wU=sYMs6?!3`#TQqyiPd9qqdD@`|A3iyi(}_Mf!|ZOt>zoreoq+%oci z%MsV!87`QalWwsM$^jhTR5o9tNHPd5GK&>+!29AyJMRCe=>M>;yCXpv;Uo#RpiHqM zbu0uaEASxp3O|~Kol$CI=+>8ex?Jxbb00jt3AMvNh#4a4 z@Q=*46Rq>}b}T>8RHRO{V7b~o=v5FMAO0L|Qds#;*bhpyMrN_B;TA7x4goQJX5}1^ z-%fmFqqhqOw(rO?mIron5vM{JtcWtZ$7}Gx0PwLV*01M&`oZ4|u7Hz3k<_-OWsB`U zDPfqLP#3TwSTJ(!9<@7rywFj6c%a_4dVY2$R?RttSl8v z_aaI5id#K>Cg5Q3C~vQ0BL0uFFwi9?vhkpvX~C|T=&9{?XX3@<=JN0tuGU&6~knUOJ`Lmr@B|6O| z<%2cW(ee!{{s;Snj`#ihe@&uXGW-t6x#x$n%~MNo9uN8S_2wpu9nZGe7srcj5t=Ya zPOqeMs#UfBA0FPqEeb$u9$uDirKCaWkZ|b^rMp2=l3Z+g{MHPpm`R~u}vD>7&j0eq$3zT8WZ&696uNewYp2ym2sjyyOHMySe z)%H-S_t*BwvRl~yEvwSoN_~>A2}b{}<kr>c2Pf!fxj+UdSr<-vxCpPluYJ5dL3oPiOZZ_23PB;dXhgE^!K!$e7r>0f3-b`}2h}mzGbf zLz5A;<BX z-BZ)=VNgdKM}%lVcBMU85B{i`VFpx}hZ43Y+jmsSM;4NJd8k&QM4EQ+60(jp>ezwE z|5S{zSxLP<4Xd389~Y(^A|X}2*RK5Km6nb)CGoY1F7&DqO10YhpE0tC;!qX-Cd@;0 zQY-tHzsrAGu`NI4seRC>pV_$sm~(O+SB%q;>Q>dpNW(T`rY!2je3t!iqNT_^j=!D*xw^#3k41{q=jhjD9n=02(1S`{mCi}DEXAWkU}yKkdH9%yXz~?IdVLZs3Ft;$UQzjB)Z}wm z{QoeYWPJ_uSbPJN4EJh0i972rfK+y4n6CPZ2-H!Ypm#dM*f{!JN%Y6|VR$=S*d) ze$5`vK_I5wC%_)1qCQIC?}T3bX#y1x`V;aM!YcXeh~6!Lcb|FB)EYkSqBNmYTjwCB z0_Kxh%`X8hk%PZrEPOD#F0L){*mJ`&!_^<2(<-kj;DU}43_r{~cdL4<-Q+h;y-^Cg zaXrWFw)GaL(^Ao6PV}-i7|chHmlnL*U?PFic`nxnkeHccL2(d7L3%|+IVoN|l*il> z+wB;(u^~$0Lm??1xcTt#`)9121z-2B!lHFP^NO_=b<^0N_YAk>T>?M8l?s$Dx9sWo z9N}mN&W8my`)XpsB=iLckAK1oa#=+nb!Z2lecxt;Ju zApW?G3zO@+b8*N-vY2WhX-31< zu7f8IXd<zLj3sO?qJ6X)s+p?QO7yTU9nrjds_8WAz({MPJOYuW4O4 zx7pA^2TqBM!*P4CIF$YWUKuIot;Q+(~|P+wpB@XT^Ijmad?MP1|j6IJ@9SvQhuX8Y#X@pX$3xO z^49ifG-t7_KtE>)-^FjyLsS29lUW8_#qMqt5`wKbPP4LzmxnXJr*MFy9#Uv>n(88T zyo0}805R-Hx0EJr!eJP>lASBci_5!laJ%S)TwZz=+@EqfoDpHf#m)ddr))@;_Qb7T z*&69wPFV5`;fspO6us8*b0edFbnb{ndZr zbXWeIQJV>Bogc@u2LW*WOe2aB8%%-DTlgC6LN!&KU1ZjzUnl|1A~}95OG2KpXBInC zZ-kp(UcR)uozz?U(P%j}_%+VW87>)}{u_j@VdRYuZ6cx0WtR6e&|>QO{}pnCK-!bR z77M1oDQ|#h7!rvX(v}BHg!72YBbL%dPT%EvCGG3>G+PDHjL$y&(V{^inRn?^v2R@% z=upy~@EGOYr6w2sab%br15)-3*hRqOXKIJSv^<_H32}84z&9(?o!Z=V1ytbN#U8BI zv95hkAsd9im|;U-o^_d{j3-tBo^RZZgI>a> zfZ;}6N{n9C?#XeKctc}xC5^xM$MaM@Ph6fv#4XUx`HRv_BvKIIYeFyL>NhC?k?_D` zlYCRiLxnzeM}UR%Y38IDM<2&dNTX9OPiC7M89JPw7^j7YM|P2He>Cav+cUR5=gR_Y zrC9dp)Yk5;G%I+>4L0uB4h&flSfTh#WAvvrLF<(;;Ww9nPo_3!>K#Hqb@o4FT6dF` zW^j0>`>Tf59iJWSbYo6B(eces%VTGQjaLzEA7YI!Uy-sJi1<4rj*|TnzmwO}8L6o5 z+l{po2gWNncEwjQiXT(-ui5YH32uaoG{X}g66z!?xTq5YNn*-AOOoTgGqfjHcz+L4 ze?_8whtaCt-Zc-FI3wfhGBGWkASH3Pflsm!6P6@FJgW~o- zYEW2wTZYY(xg0)i?i0l5Ia&T&4z}*R7nORm|Mr*WRoUf|2qIfIL-2YM4xSg;URDS| zz5N!Ea|77(l_~ldNrdi@#;UnVwq73c2Dz|>3+)KuMk!Y2!D_%SDKI;1yvjg}HTD#d z_TCh}v@%n3-kqGWyW!#5HK&zOEVQofI5_e#Bh}4St=%gE>Xw$CDzBEXRF&xbB)z_x z>UNnkHu9nNc1UxN4!@q!#)cw z|7&^|$TT}yKbt+BtbFUX2v-PUbD?e31Y&=

W!YOj!PTN}wwvh8OsLkzOE70b@!t|mVHrnLZ4$JyzC zdwV3*Xz=#UVLZ@_vkd3qcPsv4$hXRU0lAvLwYWILAXwp5x#{-F@_Sa@YF$UvSu{k9 z&GKDFbEpma{8TX@^Sd`JiqvGKIds(jc^^LgO7XBFoS!u8ONk!lqRH`CC`*-dz_H_% zpu|6cw8@qCyE5s2oy(GnYLCJxV;sF`A3@Z9r)%Gq_$T|oejisA6zrUbx>Gu7bhEI= zbiS3FYWidAV<2hIZ}aXQ0d2gUQ!o{vs5f}&vjN-3((27>eNvD!+NQ(dD8sEdZJ7Q!!I8@Ktx>~eSikF=UU2gY`ih6t}Qwm=1 zo$4+;FOr4BPii2LdB|uu-v=@=TWn_uGW+z3oeziH`u($|eyyDf!QXySa&pfW z_Y(D|mf}v5*K&ajI^xpOE9C=+wq6%cXEdWL7QaRvD%toc!C%5#JqIPPDCI;Sf2pxg zIG^Hc2so*ZBonu{ToEvcR_l(rfxVQ(S)vdd3sV3u+)4AN}LOqPis$XabZ;r!O&M=$m(!3Su@_)=b9$eU+bFSCbqTTk{O*^5J^4{H0KVY~RRwC|J5JUfAM zDi5Tla@YYhw1FW_hfW4oYm|O zGcYyB*Z5#ySkU7kakV#D-{8}I%AIRj?~^y%JZa;b_k0NCP)5e+=_~fXec}VpzUIM^ z`hZH8ZEwJD%ujTLYkvyk`cE_WuZv*rV8-^w=8Bm%By%N`!Vi?4x!jpr`F;sf z*?hEpY?Zyx5F7dTy~>0`QOos#DYzs#S*(aUH-H4J=cw>AQC8)t5upF^?caSI#zVQ- z#}d3-J9f)T)ahoA?iuY&$_J)#G3(o8wA)>o*$f$0-KPT%yY21-9=&`;5L>llbuOEA z0>Yyw9X)$;slt?ByuAH5;%R5Ou=0r(hv~|=P`yt@lu|c;*ILCb&EQCTgVm2qrL8uL z5M6+4ueaDvwgXq$S`S{+b9H*p@v;}2CM=?^qyPFx`TqnfZSpBV4s}&;Kjaw>NNPcGd-(Hg2>7-62+d1*e zb$B#qzOQ&yw6nX75Pk`ajX#ja_UP{SavealOJ{yGces_Y>wrDZt4WR6NBFjRPaSWaq2Tyx0MeZ?@`*5Crj<3|HZXu za)dcx$B@9>A$XmPW25B2L`DBeR27uiR2fxG6}eD|vLnG7i`CfBVJurM9i83W@wXLWdV0U7!L5ZcMg( zi5ITZOrFbhrPJnv7#zrIt{mkmWotum(R97tJ%habD*efvueLQSlEG=u7r@ZzB-ByT z`zI8hR|bk20wrVRc7U|iZioKM?hS32zwb+$Yz$Y|D%!~io1eCQ{$EuU73ZQxTjIvg z-a2qmZ%~J0x$4Qn_~o3VEk1a0F=F+S@5D6T3ls8N_JVRuLC>-|LzhoJ%-SMqjblm% zYL<#-WcyXRgk9+e%^yP|SDG_;iqBKj>k8I0NY;!`zNNG8C+k~+N7L2DgNNZTsf96N zr0o{tr={UbE1$pB4G7_XHg_bhG>qrEu>EL$;rb)cg zq1uuK`Qo>pj38$(W-uDescWVC@!4#9PCXb)Z&C9KYCwX^BC?tfFtm9a0TJ1N_V!lYV%{q zT@v=^&dfEWSBK2>&y&bfy4!3wy9912mQ~0ZYWLdGQS9q;6z;7n)pgc-rAQ(sT5Xbg z!=jIos?ZlS)0Vgw?yWQ6*$qh)!4&ZDN+`c>E9&<=HeY%On-THkH@n>(kMd_u-Evgc z5`@RUUF$IG)ayZe<}2fe=4WOtWl%Y!+QZc?W(#i8~HzBwz)r-0`%;oB?)lML-PK*LT(4vWri&&TAe~yaa~J@1nVb-Ja$f9 zCnw^W7kN|%#98^qMW+ckO?gkfG*uf0zvxrc+f|<*wcaxj4$gY+TeRMxu2PQ1lN+sX zrzA-u>j}fKi8QrLfpQ&45K7xqhK1Rf`1QZn9|*yH{zZ<0ZX`hqEh?lF56KqDvZW|A(QuqxQB56;p%V)koX zYrMWYY7$*y=p3yAb=3r(I;oWwXzfN`sKKPUo~RYttoabLB&;kqMW!UTY?f5g*2lOQ z5|Bj%zsfF5B9r)S(T)Ae=(-DmhO}2_Jo0LM>S{$;{0FaxU>K znDA)lB$9mi7VkkBFKx21-6gBEkp({UH{$3=GT|?`YoXCS_4y+04ik6&@c0GT8pCQfc*F3();su;a(+HsgtWh_xI2M{$hvsuEBCMqVZw3c7HS-~DwqHth|yzP7J(uBiGjE9F3t z#%AuGGRh%q-7E>_48->Etv_Q()Iy}^PWvz6+kkE^deavUr|ehRk1 zIXY8+g#%PfMxdLJ)0{j+j)F|#J2?_*3~U+%>tH=13Ys#Si4Hkay48{ zizRIjv<-Cu`}%itur;-w;Jytjs(PRhw?Dcy9hgSHC#;|Qx!hsxhI7nZ45$JwhJcDK zdmbk@eDamG>q1J{4mBgO3)uEqe~x7XGEMtM7S;EOp=<<)s~DVOpACHomEG$wX$huY zmMT{}Gc4Oz3BhFNZ#r}4bsadn0gvqGz7g5hteQn1E&l^F*&+F;rURDIOW+%n;C(xo z8rPMvL^Z0zA^)9capfLrM3z1eFH&%S{Fy#C@~Nc4W32K+vZQh$&1}{$n!E^qGnO$- zEsk_QuDHFhJqu%;+Jn`%1REAH?FkV4D`oyYa|Mz_Je`ig8*S=VLqKk;M$etdiulj>D*R168N$fM9Eei!1gdW6*0U^WtC z5t3z$Mx(`D>znQLgqSK{fIB*+z)5ewUzv0g^%P14 zWvTdy0o?uZ&Ztv_vTgG@^=3enZ>>6Pa~`texS3NifYwlX;Hp~F^*6yU&dfauR;{Hy zXKzy#rA?Y!M$cDw=wZ$dQU1$e*<^{5_i^1Ofr`6K1c370FFn!2boEY*2|dS|RoVv_@ceWpH}@MdEqBb=l_~qiSlhAVkaDSgk5b^QD@wJauG8G< zqqEg_FU$(49TC3(ZOAMz8EyAdJ=+xqx|Z-Uae8p(s|_pQxo0wpPzj$0XC4k=#l?qg zV4Vt=ByEERPbGs_&= zIYBp?YmQ4zaU=Nxd8>g|ZpWMgdUp{I(EMJ=gQl4i+O`yF0^98<~uRztshCCwOp)l|ZuGp)TFKL+B=j6KCio37x z1-}xJ9Ma<3wh+Sef+&(fYpPX^H1BwH*7r|tr~NV%VN8`ZY?dQqu)0V*R?>X3h+J@; zDlOkGo}U{S(SL)I+~i%|Ye5rG50DXTR@4@*VUBUxxG_V(f$cy8#U-C^Xp z*_O7ptGfNNA(}Wm@NYQVI8y;cP&MaxRL1;*`D`mcm{*y%sixzSKmX^tRqM|;rf z+>8La%I_15cxk^xgU^Zs{-H{a_In3VR)9x}Ry&t(JX-&rnD%yCcO^YdKE7raaJCQ& z^Ggv#iJE7GzP@M{k|s$5xUMXiMc7YRn1ony%|3py{J<<*rlBKcb25ol(A;zRjZFOo zb10M>p#4^sQ=B&L;HaX7;*@G*w~@w4A~klq=^-czB=nT z2z+-p`)_Ni_dqlUK++xPi0{LeTilc05k)bZhH(Oq)V(%eHjspiKLcYh+>Ck^^ZeA> zuBC9cf6mTX&+HjmHy1y*Dt4;WOhEZ*(6{ZR1vut%^*%T{bn?mHp?wo@g*9YZFuh{@ zoJab_?!Nt+ZEUQq?4hxQZ4apPz9fm`vHB?d@-hYoVHZ$SpC2E)rNCp{mOI$?GURgA z0#?)nN#=n;CXZQX$<~%V68N{8Jx+{iU~m85%Z^-J6dFYzBY^_SDYwMbFF3dJ&;d&q zr(2wJuO5Ps>rzUzJMugYOb^>=3K%<}<`kZp5y-zXBB@>l9}Erf6HcIZ(A$uRdo5d_ zG*tQbRpw%juf9i3CL6!tY_2F6rbN?|Y*xyxNHZa17UNG+z)pVID3A>ZnehHeF`KvQ zwJxnI+=`}ezxjHD1p@-a_jy|(FDpJtvK9i+MVn)O5v+&oxI>2+W?Ve~rcLInM3>Vl z;KI&oC-Yjfe-Pg^_#8^7P3C;z5hAPxdIHklSN_PvDd6BiD!zK{5f|Fmh<>?0;baBB zUa7%7I1(kG{Q`UL{~fp{EnwCrIDWeLjTl7SB=TJBMG{M|P+%ofc#_!J{ht4ow3*h| zv=$#vb2JD@pW2~dDA^T()}fJU?V9Pk(NJ87BPKeLq<7@ zD7MrL;S$*Fyr}Og?X=(>%{`UfWn%Nzg^rN*k3${oaEr>s<~j#`9atMPAMWulh#( zg}g6VIqaW82eEjQ0b}QbWJ3Bs8OBfU zbjI%~Xr@RZpHd+eZ~nD3x_nO&jVKw5u*XP~%P0#4{Al_Ya4!zIpI)OdhT3FM()L13HX@t4N0r_?rYz0@x$WF4bEv?t7$kdwnvhe*G<2*72#dWHJ#yxOH$; zRb-fKuiAqlP)y~D>G@PmRKxpju|S^2!0=EwXWo6?W%_D7)gIe&z`LB8c|-3;pxkpC zwhzs@m;h})U=MJ z0GBxN73(auGj$N}gOUjGkdLQ*fnazLgxbxvsHP;Vo6H< zzgI6CI6$_@UFlwvWd;e{#_#>@g^AvW(%%x}{&BvDg%|04DuM`*lzy>69U-x?k}4e| zM9nEnN-7(Kz4{61=iBUwB!8{ApUK!HYcij$67*rqBQBn_C`*5d*^nVfpRH~pWymtD zG<6h!rd!)Fmdq#U<#py_ zW`EFMY`6MAPN)V7KI{=*c0lQhEh(x4(a@l0;on%AV;P@09Rx?k!p?xsS1RrPVE2^& z-@NGVx9kzke<9@(r$t-Ee#Dr<6e&8Tj_^vh)9z(fH$S{1KW{?Lz4x#-9T~VZd*{h) zvWWQ}Jv!@)sjukWEkKrGJEn3w?}IAoyrYS6ECp%aD=GWX2VpcQ&bm9AmK-3nC+oZB zBh91cpVk}>DJHOi+uk|vNV@kvrEUS)+wwYDoIiy)%0BrVynzHG>4bY%B-a3b^t>{h zs>S#?MeHH|7(LA20n&-Sn-W~$F*xDspUr;n2A8)rkB=1Q*yQ#i!ne%m2-2U1S_|?U zJ&Cj{neUHV@7cYm#k5YkuQ8T9&yBojMF!G1>WW$_(~TU*Vt<;eK=A8_y<|SRXH(P1 z;3J#7iXb0ay;u|yy@x6bL7&#sq*Ai>+X<+NQf1lb(l7G(ct6pp&d0+vpyVi+LJ6t> z;5nY45iagsBRdqa>|HZ-fD*&}9b4x%i0MnN8eJ9iM+^>Pa>ucvSL2{8LuoetxBXf_ z_t(@s9FhL6LGk{c$hj@Pr@SY_3y$vad_jm{;43oig+M2=6g%uty*E`xE{}7fcgv!| zQAXrsp?*Z<^=|K-1s&@Ln~B8%cGVbxEQ!5i@EU z5~U_%zfy>#B)aP!St7fBomzH-2{?3r4UTNDco5&>p*^ERU7ctvjmJQaO+LNBz&#sk z#D08B<*8~G5!Gm?=c)BWr2!SXhWd<070(Uq!3pS9{W0-B!9WoE8Jv%53N3}{hqM6A zfOs}lGN2~MK-)bkL5!s9Dcvmpebr#WuFSLI*%f(G6bn6mwy6f9P`U$k#j|ftwR+{p zpRrjH?OFRsV9L#SK~iaIG^S{SIp)I8`KUy=;8SRhC3jzfB$kI6ERmH?Nq6h z%5+!J)3X>)W zoA+byx14mhu-6GEoL*V(T`8DW!@Sc?_f|V4+%%X;bsd#da?r#_QW~56Opn*TlaE37 zfo5Z^@|pPu4|}nBh@Y@aF_AZHQtQ(IgPrR1vc9qQHjb&Wq@x(aL|M-gv&ooFceUBY z-0!9Cfe(u>H(nAwyE)xr-fwuAj;X<%h}&%Q?WM>&~l zXn+ayJBJ9Hb}+oJtzUwzY_Wr#k4f;M(uh1kF7Q~!?(VVDzp9ZipfOMMo_|8zMKszv zp4UKxO3I3f2Sn=9@{e^*S$}=n5quOjV$@0oF4IRRrxyOV?0dd!ySdb3g=HcG(edJQS^V=3IX;r||nMe2dU`-@mJ~v_lHWp{nBQ*B?ktQ9l>f?gK%Q^E@ozVYG}f zc$0V2+S$s6Se~KwA0`@;p?#qP?fp#fw0Y!@Q2 zPQ3kJzgjVG`PXkkI>1~1;{e&sI-mQyXDt3ul&~S-`O#^UH}yV{t%TC3Hm)qd2RQ!S z?IzG1eL>!Nm-MpCOuDKApR*(sCX!myDFedxs5VNHF}*W3VK^(vtE*wV*|u|#dzJko zf#Nnp*X$6)@X z?ra=?YuinDHasue>342K+(H`1%~UopR44wItHOB96#I86M3*SK%RWOVH$?c8E1TRZ zTS+blIs7~j!Eam-5e!iMk);ahOVKrk*oy*ZVtCY~OEnf-Tk^Q87RCVmDTp-|34OtP zF>0Nvin24N?@MCRb5Hn1kQB6L{?@LDwzkV4O=5Z0%GyJ}YXd{+)I72Y@;yp9$l}yN zZyT{S{LLyd`f6U{p7|aZ2Bs*8mD6-JC3qm`0Wi1Tr=0~2=-9v~x@xTmgXLBKsOp;A z(QOz4;tjM{ChEQMYtp$vyRZSztA^h`=p{y5Ku)&gb1SKyG-2y%#DZsd-UIahH?Wsu%_23Z(p6i#mwHL zwkv7|QAvmm>3Gm?fgI(X zA-@v7kNHSoO`?C%6E1fTN!njrcc+}ga*W;s6};1B!?I`ZLF=a#FK>C2weLlly z#!2&Z0Zm}^St~$Eo)Lj*3kY97;&;HckCF2G7La_;L?$LTcuZ8t`>o+1X)h5;J6a=GkDF-u zk_-(oL0i+prY-KJ84+y!u~(Yk@JCBW1!dL#%FX{Q{U-zWiXhm5D9cN zlOUAf?TLT+4aij_ujzB_L25pXEjM z41^!-xdJknhgz0+P4Y)r9zQ#ynjW|`jt^~;oC~aPL1_pCVaDPA9k370c@Nl7XE!na zvq|aQh&ho5+ZEr)jqi&b)Cz;WEHd`VYut?xSU0gjksGolfsr|k2gzD%Hf zTeFO)52sWh0C4F3{q%7U*?d}>wZ~YPfQ=VmO9!VOfp2IFb^N3pOc*|!=5rYVt0(a2 zkVDoKfdLxEjl!|UHv^kp6~a$)J<6yM9z0wyQG9h0pO~GN2hmL$D4hFtvtF>XxU;14 z;~ZkzbpB6iXT*cK6bWhe{lqQ8i)xX^=XT=Z7sS|W$qQ`cK3SId1 z!esA)%>T6oZG@VOd5~AAy)?Is%&y_-+jQ#}R0ei?+0HeK_7 zwJ+>*$&k25gX&>edB_cl*}n&+L)&*Jel%Bnf{+P5P1|c)OQvzs9GP z1v9*drg@>+Zn4P5X8z>38v);XMYK9>&XF#F5-KD|gczlY^>R#hTn@E}gsZn%Yyz{U zm_loq)ThXQyTGAhBkfrs)3BNLgzidlbT8iZ^fvcktjnxYedU2^Lc)b(6v+ZE)vzku zn%9vsMafDxOL;XcjAo>w;$Stp`ef|8H9p&IE!KY>F#q1RMy-6@VeMm;EJS|62k*+@ zGPNj4M~aQ1wC>J#S^m(A9WVA^K8Q@b-09;x_8THb%z`YtnwHl_L*fHEY>AHxy^h8+ z7s-_!4@`(^m83<-q<3);{+*RiPi**+Sl%U~wue2z@fo#jGAeKa6SI4jhfj9d7rR^~ zkCYARlceF))sX5Ttxt!l{TF{j0`C}{w{XwyZPO-Jh_&FJ(?y$|V(YsZHU4>B7=kb8 z9r2yy?#2A7H05zG_9DyCMIU6;yI>z*XQ5|X<(Jkw z>jcQ%;7W2>b;ltl&{W`y<7ZF8Y!-(>afubiAtb4V;f738h{;hpHqf~C7{zsjt?Ma@ z=mWGx$o*1zY~?{WO>MbwAJfTev5-RO@@+ z_&0FHbIc*X&@Loa@rv9|kk0Lgm5Ovkf?e*pf;6cD51tar7bQnEeQpX@C*#jCV9pW~ zd7pj%ec^YpW4&Bj=x96?y#+h=s&={4DVNpjfo&w-u4eif>AZS<6m&sqL}Xfh{o#f9 zY+yx6Go7+KLzkb#)Cn?-W|D5(VLw3F)v-~Ej5H?m@vqtl&gzi$LWR8*!*rI6lIAXk z-Ud!mI0bN-j=n_`Ev1E({CmdyfUTF^g_<7BCh*9`(pdvq4nx7@SX{R7#bYp3SN(2D z=RG-oh&dLCYS_CB#+?nz$1{ACY(N@nadVv@!IsIdOss+rttH9tQt)_Y&Uv*$K@!?7 z6myzWiZy>!E&n07fBEc|hxkThlR~#lyy23+O=aJPWPc9PzqS4zJBa1eL)Evs>nW)3 zngBFW#cQDS=FV#oGNQI2JD7GxqnPXJm7v zIPZ%D2D>L0w^UtcaHJ%!1(X#$VJl$bNva<_|9inQ!xk?%x7N0SWX}I4wQy)K=5xrd zU}C)R`U(^VE(P${pg3#>+5}sv_*FOaQ;mgSNacGyV4XzHPvzcc>*U(<{Ky27HSd1A zZ6Y!NXEHiR@TSJUX0isC7HwZvVGpQG>nI?K4Nxy*D);w6nqYS7RQ{|(yCO>t!E;yi zZ(^vC+sN_rXDrFkcF^yqmw`Y!!!`P5BaP-?I=wzBhm-j&NSKr5=_}uq zjen)42g3-(N)P=o)tg%rU=7ZZJ)>lu?X5rM$tCaxi zcUzciMv|xgVB1-NSwe)(jo?IX0E9pP`{g$ZWEA9#!Cb<-WQ}vVA|m%d62!eI_Bn37 zwv_3gaw&TQJ~BwZeH24GQ0y%Jp}f9s@Jv94bO4JDrCEeqT4`67C?k@pv+nbJ!lr(; z?O|9w208XdKEWv1B$)n&Kf!HXdw29XGsP#mOz(MlPjuTs)|rTGvZkyqXy5Vb&FXbB zC)X;W3hK#)C{J)1i{x_7>gdMalQ@AGQrCmIJtkbb%TXhO2(P(4t162aJ;NdZoM|ZN zN!;8pl80gx-W{{$+dsQBVt#znwui&tJhV5H+49Tf;tFbOjPS>ZS(n5KZJ%r z(2PLk*S}k#bAt6F=n535p7h^-kOO8AnGXdmkUaTv4Y%|4Eglbsk&z_GeR7Z_`>54w z>8%`ri6A`hw(7Dh=%?2WhNhI2o#n37S6s+>^@W7~XTSWCY!34AI>HZvGJh82Q9E^t z3o167mc=M!``tCj*)2o;KD5R~AbrggZlcd@R`WfjSfupn_Fk+icX%3U`wt(5Cun+N z+x)u+B0D7d?=088+&yBe@)F{jDv=cEuXcQNHLMGv@SclA3s$^dswtqgK?; zUbKSxNKwY~R^=w5lapHzvH3tVpsG`ll<=?dxMG*3kEUvL4Br*e?YeDLgx~a$PgGZK zD(Xc3`W{(_zLE1~rxr&=B`_HgGaTVRyxJbl4tg5mp1$fFp;y39LKMjNh?>YFny33% zdc1wo+%$B~m{bi`^}F3&3vb~2MiMHo+sn(`=jooi120rxvMpPldIwG5%6|9B9(1T_ z2VUN;=je4?Q1_s))l0_yZd3(&MSN9lSqK)BY_>rzaY~Wm5|H*^;IOnpTM}ySmj>-hqDBkHt~wpw z!!>kQYQ;G|k}Lr!ji2Fa8qF)I-QmwOU$TO4)kHnl-U#`^_Jp6N1Pz3duj;pxMWhuw z^H|O6I=v%_rhQm@2g-XbYoJ-G0Qtn9=?b^rqteXHeKL>Knp_k z{2p&V!+WJMkA!QjwL!PQf?+;hXkpe*m(3s7=dV`+3i> z3OAQlEC8nYfXH5jwgepoW@VWMQJD&W;b78zr>$XkGuX!76Khwdt=v=0y;g6T_xx%c zL`Bzw=+x58(cHEBv^+``%$vck06HAUVyP@7ute_4EM5y+uK6E7VOLmeTv8bd{R`J{ zC#J7~^P0f;B%M#yGyPHTp_6k$e_NJ`mu?hiN7mPb z`~s1V0V~FbK1|>S#n^-Vvir>T-x0Ny50%QkZuPbjrjs(@REzf}EaWJ{#X2bpPicv;_IkW%Jj$~(qhA?R{$)X0~S;?S8GUwY#F_$jEvMbq> z$c;L*3<`*TXMH3+QYa$kyL{T>!@~;+8!zA~u^wH-dFzR->&_f~q^zo$JX1zCAH{G* z1F8pA=ZZV;-_RCT;JigQF6)GF6(W|hhclLMs&-Z0@2i+|>_yD#OWc;-yPrK%q)n{u z9X4~B?+9*wLl;UfY{^7b4`iC}x~2Qj=Ic&L$m5Bnzw-@vcq{h(4-aj!>rB3jIUBo1 zAL+@Ytg3Ue_s8_C91Dm2WNXXLAuFHVn`mn;==eM;E{c;xcjduM3jxgINA?m}Uv&An z{@*R*x!0SnWz;dv|HhR9ux98aN^p2IY}g*sNh5^efxP1DtxG51D-F&alA^7h2@AX| zGgI`x*lFrYvtr^&#$kVC2M~wk9%#|;mBy&w{R8+8mH{R(cD@3~VBc@5+>lzjd5{v7 zUJr%&IS-Hej9RCJch#!lhD7|<-_dp-7+(l#>`>(n>o^zhEL%X{Yw5zC^Lxgbcl7ng z5l0v-?l@DNXP=7(h-vd6r}>HkW^L(#>i$Nax9HsUPm@7h9RxH=+SwukwH9LU{w|=< z6X8JlVpqO!wF)M)9zCX!8)btaT%P(RrX{H3MtD&O3gb|*DeYN^jJ!^QpDPdhnbn47 zK#p$mAME-4?Y+6tP=RY0Va~iUuV{DPqsyFe&d({3O@B6$zeE){)IPdE|@6YE>k;*e46nA;V^S;FCp?ffO)|{t2 zvx1Q77d=-Vj!b`BGt(K4e`yyBI?S3|TT7Gyy(~v3)uYp|;!q*YpjUx4CwpB_YEK@` zSw@wC0@-V<|C3I_)E0H;Mv)ZnT`SNGYZ$l6=JhwFrlf7r^)Q6WrD zCQuWywxM%kg74rEe^e+9GR+ibxdx#EX)>4Qd%5(Cv$-)FJ;@oh$+I}4<)FV~$UJC1 zz`^kac|%C}{+qi+cbT=U9y=VzpEmt%!n-h)%z^%mv3{%frISdPwvbq?ZQjJ#rp%GC z>f|dyYOuLEYm!d#`SOt@f8*)ROE1Ie6`hd^t)r8$7o}_3a8UAeNXkWv>;>!A-!|62 zgpyu;d21nTtsLy5N6xMPQ^%xjK&9xp^r4-I$aLF$u_}(P14DEJWs?P4 z)faMD1V3TEED{@104i)xQ>ZqW@)ZBf_hHNFmdV|@@Q5uek|PSm`?db$FNy&QbbL)^ zf2PvfFH7~BR&(1rTii&8GcoKiUJTDqPLqXDihzQmU6EPD)O$BKUD9# zv6A_HpWRWHo3AhaVZXrv-~2g1^H20VEB&u3Ge(?V5|W#>q6plTp?2zQJaZy$Jbh?A zkXyr*F{+5T%P`V#K67{l-HQ?yH5tNm<*lx>U)*_$MR8vFcWKrr}Ejla<^%3h_cGPnL zS(6A0JgIdSv^5M)PDBQO8U;+1U%2H?`We^J2iRQ+|5#lYD##-=DB-{~3NvDFPq!(l zOk=RTZA1wurxmnEZq8IqUY==O4ceUuzNQNRCemQ~=%6)_dQs%FWXP2sWO23GC6PsK zg3b(dqK~{8^=_>vH6ywE_wcu+zP@s^Q!C%FG+cpByS^vh^Cs_-CWFHAaP%WuyJjb1 z+RyU9UM3tc&|1;F%ERGs(fv3a-4iarYmQ=ix%aoV zarMYZIvJqom+8eUX_{$PPWQF_2USJ@Qq|@n_pP&{*Y-qlOLaZI^enHOc^6-&G@xrV zn%-WiV_%VEt4bTJd|)4!GJkMDg$^J8HD#P5rj1QUqZ9&jlx2cV5M4AuY-ai#GnglG zV41*-vC6Ihd~=7=^vR*uzTGTrwDWn!L_Nof0Wj~#f%bO;s2_*3fog0qLKft)zI%^M zs=+yjhH6`_U8lo$(n(cvD^7NT4KZOXm^XqmE&B|jH#`+huXwoOq6D+~9Bnnjd4UXz zp=xwzDZ*96r}^sL@k+s&&ZlKNy3az+I9soU9z)v4X35z74l5miXLJJjZHU^(9*Sw2 zEn2=Q%nMH2q>v&aW_#J9`vM$0ARliQm#2#LvZ9#7%hif2tF5N)MYlQ0{fLB(hA+fS zJ8z$?s{|s12ScqcF0Harp9peY=nE?JW#0>U_q>=w24`{l0~gxtwS_(}1O3m$N?t$C zE|=16knD}8Yg9h|oQ%}Veup*K>f)*hSUJxC89xgj?Tm!Y9!1i-)?D8icOdg|a!VY0 zvJ7gnNU>7LCIdI78su?BFKDJ{O5w>+D73`|3jMu^JO-vX1WaEGyH>-nf>f#pQ_A;F zTB3~@=YDWm_3W&$f)$StiaK3=+Ko383N+CIQi-|6w_r?-a!M7PGL zAzWim@OUqnOv!O@^4>W^*%JIV0c;=IR&#$W`$coR>`A&7e33sLR6w}4Z^q%BcAvhA z&u6W2Q=WM0X~7p7cZ}T@v~V|^1=jg4Bccj;!Z^`cCAZW%u)jJFD2HASHna1?4 zn1>H|+h8%L7)3bVN!=Z6cAxpm_rbMk4lkoPrW zpH9PO%u&D;J_&av)a!Ys*Mk~wKWK2aoE?b zzS^fyC=HrLio60g@iYz|HaqX5XvQzfG$0?v%P8`txUc=oIArT^GYCJCJ^iVtO#AFn zdg0Pk>d5xeRNr-QtpS^2(tMC{*Pj!)srrS1gP7H@cIlWdbv+rs)Rxk;IOU~!V}zJo zCbEQD)$&+!S{9|0`rSVCMcEHFgD4WP9_?}`W_N`uMbcM1|?irt_ z%&`8tsaH05G8fS$BAC)i)5irRxb@-1VFU-PdOW!4?5DNQ6vU5e<&;6FLj*0clWsP6 zU(|`(J{mNbupGSfu*+Qv*t@ZidNgG@OcEi}5X3J^qgqDT>y^%#&jK2#R*1WqsFQJ) z;TAVKZ!ZCc2I{}hVE@wLCy{~uB2%R}9IO(DTXQ3XBH2{RRp%I=-CGeLm@e<9`sU#2 zn)glsV{}r5%6l42Nf!#6gW~gb>fR583}BzAwGgK@AY;j&%l;J}E9V<>TEvFt*n=uAv{?n*wDgx9juA{klf$jDEgo zO+MSA4gdmlYQF^2WF789H9kVGrh2T=B<;4=wq!4p@CCN|%G~2HwG(lZJ&rDc2d}Tu zhOd}7`KiiLl`rt1Ptkg`bv@9yw}oc&dCTM9@0i(0s~LTpnjI`%N8d6&@Cp81vS-V) zq^}>`@`N4~&GxGA`ZFXPsrAv;i(aB9t0bhZFPk4z*yty6=1E&tNBLfWs8&4X7L!v# zin(o3Wsk1Hq?wXha-`2TzQ4|?4{qz49cXV4fZZ6BYj)=F7OkmWsM%gXQyO!0jMY}~RV z{rRDdW{M<6O^$|-2kzAbOP(X+{$A{V4{A!^ehP(hyt05oHK>Aky&35KuVD9!?O~U2$>d-vIJ&HD{;?-R)2GzoVG0AJu3Si z{QL8}ZF?$1DxEBM`zRM09Vj&Ak5;1Tt82QPf)fIfm$4Cl_H&l88k?&D?WMt3Gq6ZRD-bF_FD@ihq=n8u8^q3MKUkA)g(SsbqI=(5Vjo zi{p)3J(K5M|gbnZ&<=ycx1Q@Fw7{+x)d=B^v0w#zTsax`y zcp2VYsbab}Y1^+(HAsDDGE>Ps~KOp6TT$$%*52Cl(n~^g^-7R|3&V3}8VC zC{*PMR6?mL!HK9@3AwN)9)NQ%q>>@Ww$E!E+ov7mXksE%czaoN!;fxWD{Og3g~{Za z$}RDQyyPv!Cn)@lr4B->f1bASdzei-)s+nm{6w>5fm+J?Imv^I7c6IHiE4@SWc z=*&KC%>1QnOka8tT;fs7$K$8Vn)DV*eKV|iHz?#M1R@oY=2h|>`3zb1$mZ0BkdMPj z^cLfA5|I0|%zVVCACd#4bEa}jiQK@Dbjh~9up4`HRwrmH57u(@{7`P5^3i@(<7aJ9 z#y3!_ZLBR2u21#4*KIwiFPk(1R_xz0`n7&9?_JYL<{nQbBsp2S|3epD1G@3rQybFT z@Y|SBmg`e(b(&4D&%(nhuU|)P)nrI};9+5BHZX>jj^9r${N4T#q0lQS=x5SMJmmae zHq@t_b91fr(A=(WlbT;?0=56*V=meM=Amy3>@dYzEPqj!S8Xv#VkkD4Q%L#rG)ss> zu}98=1cx-L_Zzg96-#$LqPsKCJ^m@E4q`^dz|<=o4J-=h&MD?leC_zFrQIWVkT zQu_MAxn~ovIoQ9TI={^EEF-|Zv2k_23~DQUwT+TL*AaM}eH;p6kB`O+eF~E0VDBke zmsjRy5WXv_Wnx{D4uUz0J3P==@Q|KlJ`cS=|#$O28AysDJ?l+po#k8DEdpirnp z0S>2sXgHVM7l9!M%ux|2Q9gOc{1%$qOJ1=7DnX-Ub~*Y+GajDHMvOuH44(qJnw|z5KeGJkI-w&Y zu*8}F7%aBs8P@#itjn|O6!oe%`^C1>Oay(X(p2lnNOepg+yd)z@d|oKG=hGlBKiD~ zQs3Yf*dM`;)yn?WR67(maTtGQFdfyx?iX$p%&Bdq$~ts6^%P_i{;RM1&_@X13`*G5 zrA>`<=5o~@kP%c(x5L!l_za2F2#PE1cC*GQZofBM_t#`Zjzfeu>4mXv>Se-F=Nh%2 z*wxbA*H{Fcq;K&R*v3x7C5=;Idlwv15-Bvq3u+}|R+fPH6;S!-RAWo?5izn;`o(!U z`oUlC4?y#p;621g-)w9QHh8rjBau!HbK)Kr*9X$k5--!avZ6L+x!sgPW z5;J(GnH#ujq|hi20QUc?Tyzdg1D6UO*8Oyv_v!x4yj+P~c=?n0t<{Iyta*FET<Ud4Hq>DQ$A7ed6F0L+BXdyd927Pw+sfsWgoV4X7+=# zI>5?BMx?$w(i+-cwb6B|s`43A&1rVWjmdAqUr=)bHITu!^5FnK0u4bj3X#D(&BGIG z8Hd;xAUwhScSlscKg)vtw-}(beeG|s$RMyWEQh?|MxlcWxmpxw;&No2gO;!>NsXzP zzH+kA53U;{;=|)&L3G! zx!zEGkQeh$0YzyhOhx1K?cM%B`<}STWMvuPDtY1>M zFB}-keNU~mAO|k_a1LB!Ke`b z#75O8fP6ipW#n(_rfp!s>xPToR}CkU8)HFg<-99y&iiYF=P%4+Eun|-7r$w&R@zpE zkCqr^4iLFl>RS6JL~;Vjq&okZIv+ZY?p2|!)xDPh4BnVX0B8I&zMIkFQ2X@#z;f%Z zqtP#InWIc1I`zml@80mz9rp0Otsa`>CC-nUMQe*z(dj%Naj1`D&uvKJF@_&H)Q$7G zZ}Qc&2HS|Wz3?O*jSIU3qX$sFmu90Zak_vQRMSrI)dDIaS7Y6ap$0;&vTt;FZX{V) zq!y1pFdVqZ8Le0t1M?ivc$wng<6)I(cNrnGZF=*p_STEcuKCpLtY9Nw)l;eM$3S5% zz?iw77~$_0YOMO`K9gt}eY!8zSPRtv1ec*%kEmqz^Z7&m8dZ?VYsY(E0MFXi@BaVA zM+0t2(|0c9tuYAL+%WF9HX|NhZ zRlt>>kJ@&}O*ZxYsh4perqxqvvwGA8$7XT3Lx1N6|JJz!Vf@A_wfwg$hlD-|8DaMkO*AS)J^6S1xBln zlv&j_A?TCRS(jxWc=%*31fa-aH-CF|nsIw6aMKcxOs0WJfsB3Jb@{Zseeze*2}LUM z&k}e%ZTK4pU1%58WZ`G0qeHnh{8mrnP|L>If<1G%Fo>oCob-gO!Ac99g6K1aE5Gku5d zBz25XKfRfk#TO{*K`QpY`nG0$dP=(SgF^2}7{!bB8IS!rK z(fU11cL4}1Hu(6ywd0{gaQf7M2tb0Mpku}uWX(6*{e1{as->G#jl`aP3`O?i@60S( zQ`UU5LTqUl)nr_H8?RVT1A9-tA2nObH-_bQ)UFba|FJpMC+k`gRg^t!LZF{_SInWm zNw+V~gIG$-sJ0nUk+Lzp)Joz2V;4GfsK_7(u3>`F0j2K* z!6adMToo+wQ@8Yy>^uydM- zdDbfcC5(tT-!V%Dd+c7a|2Y)49Iob3cNP#XV3J1|qCdMZ3}0V?4v2|cY+}rf>;U;O zTm!#SkEwS-d9;I4xjb(%eICn)3j*N615=S*YANVYyyBB7eJIKQ@*F>4Zpm^hSEF8g z|0D+h5}?0sYYa)hglw&bryVWba&ct}@ERk(2qxts+ORW>e*3q)EC`wNE?qaU8pMH+ z8ISOeAuL$q8%!=YJu^>C7`st(mw0D;SZk)}D(WmmfS2NyCRx%;=`JCUXIqD{jPXv? zZ+?39{34zp3Ul~p^FdjLW~iWKGnht^z!>#{ngyj(a}qHZckfkKFs4U_Mk}-=?kQkg zn>Re+vOntWwUUBLqkT%%QGytO$AcX}2AcIP@?@rr6Nla%dYje-mAI?A*-t@|3NJ-QMOS!GA0KYH z8M_rE%2RufK133jey;9 zK%PxEYN~6i`C~}_^v%M4{Nu!~h0Khso~=32vp`vMuj8>+L$##~Ra^$umu9bLM>2R4 z_4RJR(6Cx%y{J>dQAI*NO|rN2Q|d?QB@tpb0%J4j9S54YxCLTMe17)MoTY8;9iKC^ zu}wxjLdwrVr%`4|pT1zNb_g+)pOF=UzGRoX#!?o^@>ZsoU98OznE2Rs!q#b(n92H` z(OlS_$JJCuG?h5{?ubdF*O=G>c=!6}_Qc!$opCdm%%tE*T zTEKHYxz?!_{kc0nWb!vcxVqziVC6T>hlq%Px1pzc9bzDNFV5oC%G|Fd$JRhf%M>=s zXC=GGdmCDHXV!p3c2q4Nks&D=&wSA@mGm_zkMpy6`&niaQ$8l*#GSsil&di3N zytw?gM1!}r)~zoPS_7f4LLdC)+RuPrsWPVV_rUaFj>eB+IzK)TSyoh@gqGbrCzmXq#d zedqh?8g>R{4FLD-j~MB|$ZUV*@VEWPVKJ-Wya1%YphcdwgVpbXHHrn)Y~<{n6r@mN zah13tbGj=?mM4bXN@RJCJZ|2c+fX$+q6&xjge& zd+QUW*V{4&{I16s>ZWYQjW4hEv&U{=xxy%MCKu_ECq|LKwvv9*Ol<%M!k|Xalwlz5 z<@QAT_Do{%ea1AI%FCs9C>s(1PJ{MA$B1!1QIV?vt*8T-K2yBmJ!90eAFQ}Shr<0C zC+JB9e!5RwyEX;kI$)m(|+@1|JKk7n^Qt4kNWKkez~OQ4(dbcW3t*jUZM#+{c(Cz zS)8v!wCT^A4bc_2Q}9=us?Z#oT9s2E;uYd@ zKNp^IwkvpKmU9p!Xg#8k(MlVxar#s{_sO!~w-94}6753c(jN8Bl3bM{m(7YEX<+wz zrKv)WzYO%2EJ4YVnbqpHTzbQc1?y1$vCPcjmF`()S3$?fR?j_3D>%sf`YpugY_yGo z#&f4fG6&X^l{!lGiu(fMKPjMRwT;Tuo7bm~mJ=@$ul~|jPa(p!a|QP84$u4PVZvCA zO)ixS9$EOy`P-*vtA<9S4gPkQ zg{6u)=o5eHLV49v)vKF>BbDGpZN(^keuLGp{-t8}_qeUzu@v-Ial+^KNMgJg; z=muTh2Mq14aaJTIM_C>|8H1slX~~iH7z;Z~w~p+kjD4TaD)ycM>C}y{4VQYC;x5rR zf#0_PW`I(4@(8(sOLJECbXRbprYpyzjd5r7%{{r1`S)fuEkhD3FfiQMwAkJ20pFb* z#55wL4wLPqQWI@9k}tktW{Z)D^#)z{y?TFNNQc_Tb1=BbvF-@S!*n-+zV`9W1Vn$H zw=tZHSv(1ynzn6Y_@*l2-J2Rt-7h;DY+452m`qBg{S>iM_!OmdK|dz-;WFHLtyY2kAxlm0Y{N#+hWbx?zMxzZF2RP`|$=_ajpB`RJvV zXh1jvH&vWVd^#d0+1|a<)NqarA@m{>GkA?+ttpHIX+l4NQ=t0)hNv<}MKG(4^h`Y1 zCjvvGbo0qluulo{ymRW;iXk-bsNix{bIL2s8ftkCc^deaamMQ!ua9}iReCXHP7{TF>-?rve(D<&249ue#f{44N}zaVQI0A zRU0)WmMi4^Fe!bVQQN1nJ|T|xs>tYVNnHG5@=o3@k!w&OSc3+`qv9?S&?CMs6v}pu z2XL*l2435JTwF3|<@?q8)nnmxDVjGo`=r#KFye_awXcM!#?_VZoVuN`>Hfe|uFIq2 z+OxMrfCen}q>Mp1KAv^{0Df@`tG-iEZHo1Pdc|E z(}_Xd>~P=rgK!Q>J zg~OTJ%(Iu5Yn(hW*}*m}iJebzY0jqc*Z%8;JjS*b{nHYa!MN^?96`j}+VUECD*Y-M zaao&boudAz+xO1ZWNwgTZ!kCD$U1_&*d#wE0 zMcg8lFRLhnSCOvNO6GWFeS)j!Q8dd6nLT5|u~B%6|H$hFv2(KduNK_ZtCr#pQhB!_~6;`trU4IE*@} zq`{VZRU0~YKReww_i=Dn`G|?c4>k$*n-9rCM-~Bia*(mXvG49}ey-11+}41}t;w|) zr}0_~7-Ey4>qxD&Fr~qEGU|d!S{(yfw{9NKK4{PVvU#5gL*W0Ug$Q8+E-h%4WHt9{ zWcdo`tLv#_m595FCfJJwiF(ETP-C6=RNRa|NRRGc*zq6P?}sy^tp~KQXFR5wF9-TR z##FK%AO+unmD3fJCuq;Pb~s>A73ILE|D~#76g2k&nX9SYQDa1)Tip1-;tGeDRE8pB zqkRo?&j=B7*Cys)ybM~xmIrXNZ@Hb;7A6|d>;}nLYW}QF4G`FNRZ|=iG?33^vy-h? zb~f>OQ(!u~Xsiw|7x#P=#FPHX2{2gbqd3SC1w0FQUw6fz_!Z|Km0zTnGo`+zXaDO{#Hk+SC>q?b`5^Kp?S*ZuTFg%-_2y|#d`Di` z`?oByFOBB|ALXqs|1d=@Khy&;B7S(IeQ`ev|6N@2H-JB*-Pq7JYXyR16KdyD?k&K0 z)ZKIUZUDQ1jBcSHMZMZR#HZDdjPW%&Q^j{5uglAjnV!rtDeg}&xE}7mlZwt>4>+Y< zo*vh(A_No26~Py3j{lROfoPg81o^lzZBh2zp){&Ran3P8#zLR#7z5IGlWgYNV$j;R zDG{Xiaw(?=mw&&rHU2x(l*GoAv^ymGtpagzHtsWvi=gjTZO)J3p-5o~4 zHAF!YArf@OJO!Mh-oX4P5e9#~F=s>|3hVROJ#XzlSx(TSe??nqu9^Gw;e!cHdP4x0 zoZ^v0h>l793+20M*;&ZwE+%=iQt{}1YB_(FMy!TI_byN1CdK}q=-ul#U*gSgWcwLo z^iX}mTPE4E{Wtax;s{X}lgi&$2g=H~;!Mh&4}X97B2Rrl7I3x5u-4L{$%I0oOvopB zqiUy9hZWpjdM!|7GW zYQWb1rC^uc-|*x%7(<tzd9Z+jwB>k~r1QHkkUA ziW|AVd0GFbF_VA&ik2I|2#CC%jdISg-Xa0)<4{rz@_!rX^BTGN%y6aB@nm~x&yQ{g;^(gFTBMW56C%?%)9V&*Y>9kRq*ekW z0)go|hkCH>o9(H6>yVeLiKNmoq0aPqqx!&zPpGs3SCV#BOn0 z144hMOj^zyq)&4QMo7v5r7}jF!4@?TfT&f-NUZHnt5$WJNq7S*#zDxdlZn&7Z8anX zZtEDLBpN&=wL|(4G~ZyP&@P27JCFeFM6wU-#hutKJ_*7cL8t z>P3=15R(r$l(G0(-TvHN{^uy>z_5zv$I^Mh$54WC9`;d`z`PrU!^PtFb~DcX@>i5N zEbEbEvX{VFf!3VKNwZc5eTvp(h_s=};7BjLKLv>-vzw!K43xY2w={(Rw1OH`+s*W8Qkoc?R|!ei(-`>X7j7qMJT!Jz zPEZ3OoXmnoftXwkT+{PDyXa4+V9;RIfv>xUAMiERip@~0HNL^Cn6a#!i}-oT$+lgU z@DUu~$}W0rJlXO3tZQpH@KU2(b`AqHr=v93{$w@uS$RX8o7%q8cpki9&4k(UdT;w% zpvxtI;j(3$%Sv>`RU0d(@Q^=szNBh- zay{P))>u^2yeYn_QvoE`6c4tjDx*vd8F~b$&Q*8#$i_c)ZB7pf($CCYKmI2lkz*s+ z{xaqjl^znBbx%+H4p99inLx2h;DEKG&D|BbxVRU_YUgHFlK_U>h_zrDP~pWe;(1*9 zay65DQBuuM8awNAFHfe;?DsyYAL+eVkxa3E(%g1x_SDxf z?JeVSmDd-$X{6{}1$qmg{K%~r9vQvprtx;*fzC4MsT0e?4zT8DgS6q!C-C?Xx158O zJb)Z6)u}aA5AC&9!b>mg#_bNqT#@j|5@so&NM`8K$Psm!xs0dkC1AiTklP+$cBXcA zT0b)qzAPO{wei-^3Kxo)!D}!xsjT&FFE(snQKbp^Fp)mZCC>*@o-r9FzI48Bt-@AG zYGP18I3H5$+T{q7KVI5{vTs@bgcA(EWwD4W{bDiBvxV@3GsZ$?C$~=dJCDPq3E`|T znK|+Xv2vD?$YKb91Da{n(`rdS2$Y2gNpCf|4jtToQ;84=x+C|{`WPfgD?@tJ&DI*zdb<6mRAF-2rmc%ch-Y=w zO3dPgpE`k}Zru#(;FYR}Yr!~MfnAw}x&TYRbcR<+Cl6a#eWKn~{G?uJ=Xdwnas`D{ zG+CGO<=y4r)z6g&I(_5%XG3h-xol|YAdG1H%x)TQ<0UYdQT?X=zNNBQsO`+e z!o4x;!-(2GWj_5h`snvAS*Qim*%MCrQ#(#G750$OPs&iUqYt~yhx+-C`zbR1pZ{23 z_p9e-k+rXv|c^LZ~JRj8#T}Ff^jp4(yptv}DBejDX>eB@U&`3ApPDM28 zyEq54#DiXoNz>iD;_@8He9}FF;kt*dCL=^w6H!U6MpE%JdblffjG^;nt<&7F3e>6G z!ld}~dYvdP)^F1cf)&3SR6hKHJIy9KL4O|{B!vLQb$7d;4lQW>Nfa2?=y!9C^%I)u zmKm{%q3t56gWNcjT;frg51(eErD(e5tS%c0D>@LGq$b0KtUAGYY7PH)NSJJ{NLCkf zN-GR$ciD36|Kg%+*2&S4x175?_)N{225m;ThSfN{n&2Tud`^+F?}4cfWU!05$Ov(~ zm%FjMSDTUC$#?<~!=Ka=guA z>8ryz*3zuyI?(^XmY7g=;6#x_%-x*ZC-ehVETJ_g&1L`VR_4$(2&yarRw;t1Ym_AI z-rHm7-iHtN)aei0vM7VR!S{`}?+S6v0NaZ)Nliu%;KnzIu`$$0C5@=hs!AQMrc$S= zjMPuo>NeiAT4$!s0!OPwJK6NNp!ag?d031ZVy01Bju+pqI>MDNxz4JmL56gL8z1g# zB~n9+t)b1^I2=w>j$Ud`e)jP08U95GJtg7_Vcp=Dx(ZZUSsZ$n{Z?37=?-AX8}a@v zMdh}MoFWHBe*Wb{jsiQOdkf^@rn}d9+emfS5vhrQs4Wp4TRN#Cnl>R5(oKH7y|U@li558{(+(x=o86MSkNX_vi&qJxAt4iJk4wzD!pmnbGqni4?aI- zYuiF@uu~gw;lrJ8>GB~P@=FRQp*alEH^n(1KW zK1nFYpd+T;C`-s?wRW9hlM2HAiWK?%1V2ip_7=Ys6nSlUxYtt-aBD6;>IH4ufH3=& zukBC0XZgR8`*P+`Xm6Xz|62c4DmVZq^BAy!_piiUcgd9Ra0qU%=bF@LC7oZ?=1(7XF@fcQoK*$O(}`A3CwU*1)=+TKVDUu&$P(;&w`5S$R+ zsM#0r&|yqF3AcRlq`BFQC|>p+VgJoTo0T>+d=xXenk4n|WQa1v!h`2@?Ybq;Qgb== zgqHfY*Z2Aak4RtJ$pvFg1Feak3g4k;(*^~e@0C8w=l4nPv&gFOmpV8eFaM+3>=$w` z8)d&`z-UNyteaaIl@D3a)&ud&33wO*>VpRVj|W*3&X8uNQ`GJefWJ2fi@^6;m0}yF zULREmJVih@2W5wN!y!hM_i{_Djqh_Q7dmHT3?vyjxy>b!Er6BR}MRAlL-lHs1B zom$QUVop1{aQEY%f$f(;UwtmXfFSo#|79Y*c21j918W|CQ~^=5*)5*yw9capGds)7 zM09#=HBW}Q)72}NItI<_r}6uX8ZpkS5><813eVwI^LbqwfwCQY^~r(LDMzwYrs?no zCix%JW)0N#DB8HL0T;R2&n3I-QKB*^J(}1(8WJN0 zb4C6Dum0ijttZ-d*uH(b{sF`iaud`jSml zRMG$V!{r%9Qn@!V1l>enjR;*)UvKkY(89n_C<6aKx<3nZ@ks+{ zkb3Oec_^Aqf!@kkO?Fl|$ABvq?)&^y>MSkSWXd)l`u=~Tk_Z1mm?Cu@td^+ub z3Z!@T)MQ9*izFE&_wB&}t5m~rRYjp@613)PqYo!zS`=Ts2&M5TyHZw~J`KiTlt7K> zn@~n-=$M7W|9qRf^OVI9;2Cj@6lQU!4M^gSS}$*(wR5;#~uoZHD*giV1UQ2Wr(B2$Mltnye( z&yk;uS#Xd3ST zZNZ>0b~e?RT9W&m86k<_=`(8#g&I97!)1Y!fUl_|9y{{Gd^V{r?@QDhJ?ewYUN?`+ zT2{)SaZjcq4Mr$8=8uwiL!`L1#gppi3RB^mvsKzSFT5NnWbjuQ=Rm*J*K1&2YgPk~ zUyaw4ozMkdBv+lT6@hy?!{`MTE7lMlnDoYYL)>r6ro>5^6S3;D6NZ=;dziUh7KbAg znr97#9$rfW>JSKl-(GA6h962)zn&P8(pbA^!53V7cx#2JD!R6)lGjZ;g{YHK# zlKq(ZwRa+%kmy!ATS9(vun{mp&p)>T_WBW*oOLL)X6`sVBcL(a-E zdsC%MDP*)D(fev^f@I~bPe{4cxQTsl2RJTL}%A9?>IMW0Jg&EVNE0H1Yx^l|4jSR-W z3Uk|k{q29xU<;#FO<%5ENcOOGWS;BR&iBn^^E7GdRFnzyrDskO(4AC^4xhvW0sw9M z0I#)5{pRUI!awMrweM?(6krcBVrjKy6_!Lxa3KU-az73yu=A53X*va@>b!GtZuT)^ z=CfpOIwP%yHWov57A0V`9nXF1^u8-=Qp`-RvC;SaVdP$I#e%W7Dz^R*%P%{xU}yi2rR(sA!g2q1Cufhy zc1DV1@4ZE`$zB)P+u>}7tO%v-nU%9wHYc+qXI=)yci}I8RU|iVgW$F5Jr9au<36q9Ou?ed0x${n}2XfG>Lal{g=7yw531Kql zahrq(87&E6J&Xok3a^OOAXBe{J#9?A)P7ALw?X~#P1}4EquZABLStF`@eA*~;I#A+ zU5|Wc0+&XE?|4G-*IFloVj8;1>*_@d}kU_&dlzs9W$VTQ;I3w~{YhMj#wW-JA`hG%5ICSL#t zQT)w%-N5iR&!mI2Lr16iLoiBlHb1vuzx~nd3*+XoC(opZQ2eVOPL;+7C%$m*Yre^u z$9OR#w#wl2nw)riuK_+Yajiczn#HcTT?OoI-W5*kl7Yt|X4sba>&j~}tl8Pqv{?{w zr205hq|P{3P#Gu-i9|lm^&*oKUMnvTB;DE3BGrzvN*fKjeG(HPaGLBx|x> z>>G1$?8JC?Z+~j#%06}+%2GwjQ|sdsQyXzC<%kga)dgziRcA%gKUV4!j%Lk`PQ%!` z1{6l9qW_mh1eocV#Jn^_T?$IJSAg9)O3_!V+-uA9CICIN>xi*Gj zq$iv=)Sdh~`P>+f{xD5H6yj~y*B2lRwxArR1q#Lj$QyZOF~@K~OSiLEA*nNc?Vb^TOMgOji?F0)<$b$qtZO_j|fQfye;bxVhIoPLo_OG7idOA~I zH2^qs_{PsDo_r7=>Jj8FdcDtBJ3ZbULbt@* zdrF8!4N7uY|8(0%5N1h)7a<*nhNdkd1~}a09DW0)K^WgIhfwx zGDK+x4qT*~`z3B-K8aDwA)EUEuNoQ+mMZdvQA`F=SRb7Zz zSS28}CbC@~HMo^}P~+em^EhPUUm&&h(gUxN7q$+I)@c9(_ya~~u; z2qE#4g%ze<)SX4ve(V3v)K(BH*r3 zzjR>C9^CCKOT~0ovO}mkCEYys(q&RY-a4W2LY~~t(p2g{KlkYy0eO;D@xXQ=c)d1hzC>u4E3-rSmhFrgi=D)}w;GMK7EYJQdLElV>nTLjwr|0|SG)L4*L* z$)o?N)tl>#2H&N##>09mzlYIGKD4fJns9N12%Uv>G5I)zo0*fc%rQecVFchL6YMO>QhxIs1-iqprEWU-{FK>RTRy=)K{L8O*l#Btr z@oChZ(99;*SZX$AVWl?J`w7DET|a%2qUJ2eq{dR!Ak*34sNdZRtLOL+b$%Hj8`06h zRkM|AAABF%aTF#7S|j79nk)-EQ80tWmzGw{pErcoM5-qq+6)IWX_A41`MZ5gjl!8$ z+FDv~EJhG5QJy}UD)R$Bbo<}dl8ecg1jgJI(j+%adBT2KZmkyKf=7gFEOFS^VlX20 zP)@FdYm(yrDgNgB=THIYTXZ{22#dEq|75ir6^xn-qe8tH`k;b10QH5Drp518`c)y3 zy%9*H9gQ~LB2IZy+F<(QdxD?`(-k^GR+8ty*Rq%z1#uBfq1bUi#v+VA!mH>wh}3Q# zN7%INMflf>Y|f2wCu!a>dQGlnp&W*N`_fQPzI7ov^r;N+bvv8b0?9K{8#+bZd0S?5onlbtdh{`R z<`-px?Q~(27VmF?@eN(?sFDyH|xnVgQkYfa*uh`CY)GE z^Th3uH~6sHnAbFeJxyhZOdwHFJy~DOrUKAuH$Y$GyBGI&=t^cA{s!ptQKGO(yPWzq zCT)lk=uqEy*T%iUEuE?Ms%1~RZ}W%B3|H zen_TfPQvnpEmFOPH+h9up!rZZb+1=MMfNebr5a3v_ycbVL?Y)1Vl?i<5cY8lelH(~ z4^ckK8%vw70*V3|5OoMDm~q>M4m9(INtR%*@P90zi4W5u>GHcrVoawIa~Q5i5Qj8k+mgb03rK{C0*c$b!JA}*9%F52C2tMB@)E`tP#MjD1gWxy`>bUI=G`)RR3bhjX9rZr&Ro!*U{|hr52c`ekrb ze0j>uDxn>h#eemL;rwvArXDSLj{OU+HoDi4`#Uir!difd^KW{*j%9J1omP?60+%Qe%kUVL8 zd&!Lk#BW=y6f1CH(Z?nk(9bK+nnP!mMirc(#TWwb$BujJAmy0_H6`g1&CY6@>9B*U~c>WBeG*N1@{@TF609|1UICnEUfQMW<&DFWKR!HwF z8&;aXu^X8op4J29buLAljq0&SCH$-&d6j_i(CwqA{n_R4>FhmPy!&?p-K}-ZAsHPR z%WgsC$TAhn!8-qo!(@#u|XEWNi`SMt{R&Z{j-k^sCoH*8^9Q85~DNz zJ12SqqT(;@enVj)B?NbRvYb@qVSbHn^wj0F-)%4JwKqZ$6(hMnPPdG~J@#C}Pe7tjGEl(IEwoS4gHIlXW`Y&i9$hvL zG`8bSYa1BwFugV~xKTf8M-l1addKaSjdm!EVbrNcq?%KS9zcSgU->Z(AA_QztRhAF z?fR|fiR>+lf5;cr`#gq7V+mfS=+CH=*EtrrgA;1S_H!@DN=fKSZq;g<)Spus7iN=n zpY|Yl;GrJ^t1eOZ^KZ0|7}2I@L8PxQOglS~NF?$Z(r;%x$7$()Hg&EU6Iy(MDsBM3 zl(ZHIws(Jx1>jQ0_xmxc6Ke=>3EfII_=IMjEs>~)T4cwdt%v=R?D{faQE#(SS8*9 zU?gN=NCM2@vWpVCu2Nh?T!<%Y0i9s*gZ3j~r6W$0OQa;S&vH%6~WaT$1E96^z zLn4tjb;x4fqf}HJ5et;Q>Cs>EYNjp7JN0CWYUzQ~lcR66cipE^R_f!7q>;i{_H6Z; z!cDI;n4|lFoJ_lG@|^zI7@5a+ds8XvnbLHw95$$MtMGdEmVTS*))^|GI`BlMykm8L z{`Nzt^;91hLYALUSeh28QwM6kf*2YY7@Q%1b5rxZGFF|7S0s%78;;+hZ>KG4g)Jxr zh=*25!LQ`>3B9MYK6UedNKR#!06bj}+IXQ?M6lkV*}wXUz6`6YouD^mGNyv|CLL=| z(L^!&1e@-CsW*yNY-wgN-jkt`6PUr<+0)?sn>04lAXoVMEKLQHp48d8#V`gZPLg3b z_U9BzaRaE6Svja?T^frn)V$B$b;B{u1Ag;>SyoKpoY%nDvg->5jXn2pPowg7`MICU zY}&9B>#krlWVMB`ZWO$E;)OEV2hX2(ZuVdbC?zc*+g(I+31d z*JVf~atGn5qM9nE9dtx?vS)M~p6jvUxUoF`X zj@1X*=ljL^Udq<T0$Bu4AF7WO-kT3396NQIp{e#)rb3+T3OBOJMAj@9LWxCD3hIDvS67+%%6qeHR|~)@tYatKqmYT8TlRCiMjJgh^}5 z^fz4cAt3m)=Ydao%if3i!1cMA#uMK>f^UxZ&UxREip^IG|Hd;qe&x>2B_k`CP2Jt3 zLC0bB7e=ogHR1>#(4z_$YrWSTTHSjApO2cqHpV5_E}y;^&7&2fe@0(ZpD6jPYl4I> zI7T&9M36?FD{*iUrpvS+XVTW!E?y6xnZ=q7WF)Zs~G<8 zA$zACNS+ja343#Hc@3F(#`g=tjC|&<)0>xrRK5BSA*CR#1qsQ!FT0>!x#5xy>*`xv|>q4wPpz))3W@99A zQE9}hBA_wmn9Jk{VV2CYLH(>K@J3pRkO)c4op_J==mssjy~+E!aVh?|jz7VX(pR8J zA;ma*3)3K8YqxQUIw@bfP;qgH9k@n&kaT7X2kb~Dt}KVx+xmPr`lp6EJ13nmn~fPi zgNZn?tHSCkD)jWisuz3h22SZ4dX18(n#=@)8GX(#PNtc!l+3)Qbr*9HT96C~bVV48 zN*?_5=kUQHZxm!CHhuVPD42*>qjqf!g?B}xX^yj>xv_7pDWRX7?)fk-qrvsmFpkBp>>Jk;FH#l&vUglLW5(n z>b}}C@lE?8#C+0mu?vkOxowoRpp0e@w_#m{e2OiX?(#aIII*~GLfl<~3e`DytJk!( z^q&T9N4Kyb3=Y_2qxg2IuuO;wW5@Q^2^UqEbAP)rkIJaV6HoQsIumX$i738#Nhn@i z19EXey}}NCAK}A6o72gZ6m#gjBJiV6!zwIukY6XrJcZlk;8Bdkp9Lz7)K}Zj(PLX~ zc;?SOh}FP%8xZQAEO_7Soeaf|!u~M|ZF-uTOWiwM?hfDQ8zzmiyt$(xu+Jh094*-k zJ)CqKRyxcPuY%VvVc-$PGLhfoV4Q&P<~B30*o@ww1m~KpG>qUokw015zzk(`An90& z93@n<0A&!L0HR<^>2i4~2j6S$I~M>eh9y1Wy$`kHnu~V_RD$ePU8)1{`AGQ zvO$1=Ti?t(RoRWtb`D)$Rwp0sijDhw<@pXY~3&cF;eZSWD@*D}G1&b4$ ziDF}}&&&9(8Cl1j)GN2g1#!(x( zJK?>c0{s(u*@hOJ*Vr$u0QxGMUX`L&hO$XI`=>Q4il~^aT}E%lSwsO z-p12+zg~nNL+m`=Q?6JpWUI;i7~AvZ3SIenGQ7cd(#bY-ufIQxyLg-zFB%`WtG+4uiP^2qHbb*7wyx22sUW94)EGl1a!G3K&*LGs+?$d|H;BdD9nrgrn5bTGW zK{aHMW@2DqAfmm(P8_rbX*@Ty3a(46H12z7pJiPzITCg(h>2_+|L9XmDYkRW-3&RQ zOS^=_eg|_Ve?b;AsK{&5%d_SHUYRTb2TA*gfwm#|)6bZ7bfQt1wAR>(NWdU{X>JSm z#4YEw+b{b-dQGq9z7AU+IyQk|cWZ~eSLe}ta;-8{T7mT@lxyB{5v1i|Hp7x7VQ)Hj z8B%f9P={?e(Nu2dw8XwOuyLmpMz6<%3DTqdhonPPb|r+j4$|%R{T@370(Hm!S(AkV zh!TO>%4}||r18`c)mY6uS-Fmht6!I{acg|=TnFi1vK)r22sTbOQWCqVS+jJ4h#bmJ zAW3Uh+gLD(BanH7boz$8TADZj-j@J~&H>E0yd)z73dK26CUqAAAg8hK+IeE9c*Y0Z z4tk3Q<|(|mF|>Jr>ZBa4d7mKjygb38`~s~ZVupv%j7^p73}u!G^;?Zn9x9TZ7riG7 zW|P%BW1Sltd^fyvQ^6!2Pz~yDI(0}z^gqyXS;3k&)p;??b*of$6@0z7bQgCp-7b|I zpRK8b^-T2>eJuI4hhwc2ARimZx!$HgwPxc6nftb@H}2qx$Cg7iLcu4T=Qix1&itgP zkaG9qb`@5i)xBP<*Bh=XC+BzfxFB?h?t;2IaKc7IE#W_65lp~7Pz@Wizgw5EXlk~=QMFY*b z+>PQusO4!!hM#&hA4@&7Ifsd{PG$pg6s2xjh4+8bu7ebc($W=Qeppw}%J9W~ z-xeR>+_9x`9LkUEx%#E1E}p%fSa}J|HP^uRddRA=@xG%b zWeCS~nFGxR*N*%!0^gqVkw3j?QkCxOg_Q(bo6lE-mEKAjhweI0citwW9;3sv3tpe% z6}-B7QcdiKd&o9aAqp0@z;nT?1iRrD`@bti7JoG|xMevc+m@!lkzCeCg+@8o!2xMM z_eLmw-Lm#x0Y!3;_Ju^|lJg&?abO7fshmF9R2V98CF^~itfJ;iCT#Of#k@~%=5(jb^9dnB+4{& zh*<4qf(ZJ3a^gjIg3NpB@?=X^KE`O(_XKDzYUamsaVKLss@9|1UpSID-^NRCUUDZ+ zS-b8&BU?W;TsjlFpb&m< ze$Fje$go{AnsDBpteRRJD4xc#A@1USh^^^r|ZV5vSUbO zfuwtf{46()7UF@+dX7b&Cg1Q_R@U1!*WC4lxcg5Z;6Yh#0UZ3`Q~ZhFCxlzihk}&< zq5YiJ8T)ahRPfmsvAIQ^6xW$n&gx4ZvRQJnIy+y*?6Dgr|mc?D`dY%ro{D0EKN~|G4%-Bv%of~ z+)7RP%ARg^XtNLaET_~_`Tp5&5D9HSpJN*hsXDGk=Y=)0dT{Y;s7>iJjZ1D7@Obs< zA+GOl8>YEM_*z9r;F_yEUpJaiocXvR0M&FbUyr1-X!?=L99a26ARjOXBC@|T^KPKu zl#_Gwdfy6{zV1HlEZ&KBG7n^wau;b__(i zWj`MrY{i;!{ob|YlsEZ`elrqXq{@BtrC%nhwW=*D*5U$Ka6-yxxM`Qz_1kx;E`%hG zR4&q1m641(yZvyfP{TF=E;!0Gkn8$( z<>xdMb(d`f49?5Om6T1R8XK(fDmo=WiF@2J=0^JySMxzP9_QisPQBVTAcI$%7>Iyx zgbo>Nm)VzPP)>QcFQKrc>#r~M9>EBqk~t|(43Yc}=g z;#|}8g{RCO*CB?sm=A0Rki6QrjO5NvPVGO_h=qYfsT-#~4;b8UpOo?5GKel-{`7E6 z0Li>wPJAM6kZ*^Z@n54@*`Zsi`FYU1Cz+Xpz1H2#=^CpM*ahHGRFeBfzlh+d`||7e zer#F`Hx8Qk1h|b*1EED&bG(G@dcC znr(r_l*N$&)lIv|l;+6c3Rm_e1#rs;ELY3Nu3C+?!dDjqSEdWHR}@Q?aF6Mqs?$HH zRO_ye2h-`7z{D6XKjZ97u&{=vi}n3*MY%Lqk-F0O&4N5IKvspCs8P7`9<40(!J9ay za<8_=fqL0;K3&!?UK4UUKXskmP0H`ii~Hu7iKwOD2B#oy*v`osl6+m6%0}(tW}b;h zCTzdU*1&CuQveiW*ig|#p+!(wMCNUDV9_bkRQelohYzvDPGpGtyN#3|@i`pJNd<|$ zgyW0$1EV+kw@BLQ>w0PBy#z!7K!yeEz4YKsrQ@c65h(A-(j&kWo0^^au`*|h9q@D} zcm^{;a79pDEDB^J6n4InuzX_?`R}&LAQ2?N540i5ENTDS z@7LvQwbGyC(MEy@J4L*f=ZL@v+It+!eclZ?Ia=OOEr8@eFn3=wHE5@vYy>DezM-d#|22jzuQ&R1=Inj5 zr-k;l12+~TummI|c+uwg=6*QP7`|4;-+W*Sb$t94FSKuCURFK0 z=p2>^kb1m-Yr3og4aZY6Fd!jIKq5m}k$LtNi9#Y(95M4iy%9B?WWjoFxk2eQfG|4F zVa{DiQ+OdOYlkF<)w-SrlI$8D=^CDNoB(vhj%7V_p?apq=6dYb(<;lBpjGh9IUfRI z6kR;Rb-ViEY!Z0enwBw}WuEc8iWlwAnOh)Z`0XFEFtA0@#vknShU{MNM^s%|wBEMt zI)>$-ehsn1p8LO-_^K$w!ghh)-uD0CVUp3*``FG=*5dWOtNoF*P-uj+-3w9|*T` zz+}wymSFvlPjOBYD#>~>5`MyZaQ`}uNl6;2ul6r`_C!uaui$!|&LrAk zHY!}2_IDii&|L7hKJMR%!L7ju#Uk7iJKiY}PsYVJjCr)=hUHK--DRcI>MXtnU=v7` zCIz9s2n_2*$Ynh*GWt&uv5i^+a_I#T{^eU1%)_CFCXHk4JzY0iF(5&9M5HhpGk$6b z6r~4L0|b8B>nau;NcPn-=;x3;Lt$dZ3!6v$y%)U%SVrK0v7n+y-s-#GM^siiT%D`d zC#!Cl;1=g(8V6Q5@jxX2m6M@^QD^QyjQ1Q$OS_7#vf5w{T0gk9&Hei*7>fULLr(9A z#b`2L9stZxOX+(wMxm!kvAsF^w%DNKh_*bB4~JTH4n@#ujgzo4Dkd9U*i$A{7wb3h zHu%BgzM!0KUUrvfymU0XVJJO|L5Qn%E}oCU#;d(14mgJjzP(-Lw7$kmc^k!2$<};1 zJfET;zs0#Ftixok4XRfD66I29HQu#dH7feJi=v(deqZWxwF=^rnp{wKr|m!dIxdz& zlzNx&M|gS6YFS!`-?s4UHv!pP9)?$)om8P#V@o*WjGq3_$7Tm)SH~{5NV?xsh9uNH z)n?m~WPI1^h0V@f55!LO+&ZH;5RMy$+VP+t!OJ~9oe?<0Pl7tU9rZZl+*Vkr6JPZ67@G3)Q032<{7Q9CvmO7m9-01Gzl5V% zn%Nkt;VI>VpTTrSJx>y{TGQo9%r%MH-=xtm4PG(ae=tbBrIMPmBtFG)68*e>CXFWC zdp=T*L?Q!zBXLd7-P#jd`C7Z8s1s*vHgjEVCe!G@5vJ!c!Ig5JCa4VwMT|7-`@-0Q z)yziGhKd&F$gmal1CtMsTDpmD+M*D2zh1!ND;+0S_+y@&pQ;IX}UL$-)js<$CN zh~c4}idsaz&HIE=KQg*W<9x4HYC1t4rex%=lGD?_LzQovcDp}y(}+Z8`9&?k(Pw)L z9rU!o_-Ofwb`$dw+^lvpBb)5G{1WN(MF&g^&~9gdN<3F{h?Yqp>(A;_oPn)10fcvI zr*y`ibb>(d8V92^))DP>&zR!FGez_M^XcLtC`u*4eko;eyXBh!dB7ndAtXLRe_|lm zs<4O|CriAay~QT%8gaWa&j^s(_0Kezs4)@AJ>yvKj=rQnRD;rtY}CV=mFc+vLtb(? zEO)Dgj-g+QZ%y*T^tu?6-)NfCG0_Xtr*4{iw&^C(1)n{R7$MfFnCCF6uiuKZ{Ln+? z+b8ugV6nbBa6Eh7|0vgEswlLt!&MBVgn9-&p`rM9?Si5Ew>i(i^MC=(4lE{auNm$> zVQ$vUW@I`NSN`;ABnd1Dad_ZSoIY6<7ic_XwJvP<94tJ`erp57GiOYQlB9vawLRF( zQwi_+lTJ?^x?@D}N0&3cy2_6)lc%l$!J~EjY&k;F+=!Co6}$3G{oi%A)ZMXxUf$LS z#h>`dvS9)1;7HAY7lEsWlRZpS@^F5Ugxs4#*uF&PZ6LRKh_yWRX1=bEdx}Mv66(=~ z`Q1aS;4@XUl=Sf2qpwV%Q756PQM;kzueKN>W13l^a5Ms6cqXYNVcT;vVl=v;rol za$gfmruj;QBe$CqRzI3x`z)g@r=J3#&|;%H=`^w&}Zus}o8b>%x>M}#KaTx%|(Sa+%_+>e{3&F;$^61x=h zK9Z(4NeXO9gr-z^MfF7*qJ;gSANy3=V#{8S5`W@khdfldlBscgvtA?DHO6*F#!ql6 zA@09@3q@=wocnnGHK+4{$-&AB5cVK&IdPM};79@T-|hp=7R-0phj@#WLcl>~VfkJ= z{v8-n{vsK<13c;nzi)8)2YV3+KdmEkM2RCCbuZ$y{e!?L-$u-)pXzKuqO>Y=oblZ&eyKdTg<%Z?|6ZY6}D)R`=JG+wvV?`Zr}jaK*ZMA>CW#UWo$(V$A4f0 zOe~N#zYjO}SE_U0^-X9#xmiqYVO(IM%`kl zwesC7!`B>3sK*8-6sIINcr?E3xR^EU1{RihYCg>O?z0`KiYyMxmH$v;aijWE_z5D8 zv=^iT9it|D2?HtACa^72a(}?*h)4dZZM!1RB&2qC8|qEyxqqNr~92DPb^|!E*e^a`NLDxlg?j5e4h%=6QI_ zcU>hW2_;{Z^fd6f5+?+DGW;#~4*2gy ziwr6!!&JM-{~yR(MSoid}PZvK(*GO15PkYDgNm!QHV-%2l&{!c=6 zO@`9;@|$B@gd%Z(r?W?Y%r){7(=hZt>aV_>sIYwd!D9W3eS@tRIMZ0-w64{*8zj7r zL0~EKUZ&cP65CN7_rWb%b98`i}mO**mB0(*wHSqNFQuOZ%HT_r2WFHqkdnyR_ zR6aiNEIv__!4;_lEOz}U>W6K`@d6|%yIUuvGa&tBVL2`_#`xD(OP886aK=kZdK zK`1*@4d(+j@vqeNv~!*hu@bfrXLYLK_4gr9|EdKvDmn#5mAR4ybn`cdiaA$?a5V-U ziMX_0oX9g9vxtrkkhLw!x-d>NW@F)J@$64TE}&d{5og1L&nNYe*!lmhfCL6PNUHbGu| z<>GG5!3PIz`S8DLiFoG#%lid^Dq=tZ>NR|-i21a&>L$h?Z=XD&H?q*DKqnb+23!>q zjz8MQ2rIWT*sU+6KKi<$SXNVggDqJ*ZRelVW6->^5afl}cuG|7ecOa>3CJ-JX%BZ@ zrr#m-M(r{2E{HeF)XNqqyA4Ad-9#IL5nLs49OGf7Z~rX?LumfyJle%!jtf^92h^d4 zf^=J$m;E2-ZK&6r)9};B>qyT3T-8&x``KmUt;NKB>JmoGOQy4u_LDEqF_8)CcE9`*&uh7}HMhse1=O;|7?aPkp8cXc*ijUUtOmlZ z%M0yxg-jWr8PTUoj2?x1Ea<+ZCyaT!OkPa|2umMbqR0KX3?0L29qlOwW0GhyrV~#o zr=ICwuQU;9(Mex4T6TY3=Kx*rcG7J^<{95OIZ-x-US@Y3opW&~OcFjz7=;qF?Fx_t zr1xcdGK$exNt( zrcU~Aoyg$rv418Y^_{L`M)Sl+pjb4>LzZ1ozTXf3wE^azg)G%F89@CAgF8LX*Bf4I zqi-`)@sqn+zk!*y*fHdxb11Hh@yb(`O1GS>Ob}gx=IU5wrFz8o58q?fYf>uBS+l)5 z=NtD{>xo~5`ME^{BY5D!9}JfM5{WLI<)WVOgM}H5|Ct-OR4nyp?F&eaw0e^q2X=Vn zn%vzzIE+5L`8OjWnGo)6Yv*GP7vk1TzWUXw=t7_wLKxC{ZXr?W3%WLfX35 z3MDr~;{1$SXsfRBXgYa`Y(!JZ?+1}7x<2OCw#z0S_9+;&%af=Mv+ykP-SuFVC2!kZ zg>iW)VtvYM)5w)&EuH_Lfvq zU{rPuY04CDm~MI*-|kLPO^3M!U6dif)WAT*-U)c&T4p46u@I2R>@|Dj+vC|EfYT%x zJ_LHEG}y!DC3RV!Z|+=jXm0HU<}`*rx=MKSU|>Aqq0r2`-LGj0+6EuE0WLcQZW_do z(w-Ome32mk9$$hSA;e5Yze^`z^@>64s|?n!&7Q-J*Xwg=idGM<_op1H3}2irlJ1Z8 zS?ERdoH6`FGj zn@rV2)3n>G(E^Q<)W!_G?+s%d9XSjP@c05=8$hzO9^8?Nm+Js;m%`5EiHHGwt?_{B z2z7<23y%m<^nLHF6?iwS*h@+nY$+a1K}h1OIw`A@9t*XKOErSANZEY&A1)aF(E2CN&JC$yq?E( z9NNw_DJ<-&H12%A+1{H61iigGU~m0fHz%*~(pyRmZH=+q440BV4)E>I zZC`$YUa0jLdkM$&?d{s$QeEy{&y(>8HTIHXXj@g1foxq7#@SP3J7K==Up7aD-9aac zQcqnKgExd|LB+sdZ9on``5t{LACA)4rojclT=GdEEo*jlY|TK3UO-!5 zWigWt=%peDjDAZZr$zwIakX|73T_e+_-#M`QMrdvI>*PdLVABRT$0^J&H>p3&>|K~ zJiyzsKJkq62U_5v3gUW07}|E96g73Dt8coWPPIPSNc8=<;wP>g?8HdTy)S~fYFMg= z>>fbo{kKDbGI=YkhIcQKsxyl!i1vkw)HX~CqYt>>>aWHLX^X;5JV`%6wENBFlw36X z{lmQSKkL;9klM4({6)FWLK{x9Z2nswo*o(EXAtk>FQW1^KAuN!i7sBdw&Ntq zawXg;oF6oWTkI~8ovuE=AMz@{vBa7s?7})|`g=q`^Tcg5elpeXn#cJMgHhj`v_R+m z4Y5ch-cjgiDUu#n7I35Uz6x)V)STfUC&Y1>_i3uVu&CMd7I}0k6wOs*C(f)z0{#Hf z#7$mD{^2~68XIZ|l@e0T)c<8>qPmbdiy_o`WC1H?9s}EoGZA$o*#YQxQ7+%b;=f zTY&;~8i86r0h^@&%eLw0RBk6~?mIh|Q4q65{XjHL{3rwcR|w?pJh(}9{QD&7*%nFg zE*-Hs(VSDj(<5_9cdc1-Nz)+7MD4d0od*$j^_Qsa;*xf`g%UZD-qXJilCRGNn(gH% z*OuCR4;o5kuBRLA#gbbu1UdrA0^xi0!DevMbJwM=4)>0Oxl8nSi|fDCkFwL!$Z56! z@+|fYM&SH^kOF`M{bYlY=nvVevcgd2Tr=Xdkv(%5I{x9l`p^SXqEjcFic!R8)X6K& zK5m;?O29rnnDI1cS6+@Eut1gC9EY{VbqLy{Mrmnkq-lC)LDBQLPg+rHeqaw^#gQBT z;O5~CUA_BWS3#z_bny1*`F^FW5Y4Agvfm%HULR++UUc51PJ14Z0FC1PzhQft^8^nt53g zVw_Imwnq+WW((jpJX+8>UA5gE z-1V2LosfGxK+}WMcRerfSyb+dVS(>gz5y8)yBv@pAKGHkUpU#wf`t$ZWeY$Rn z{d}(`SjyMu+80~fKIdBvpY!#tSQ^`(Zz^4=@f?I6r0nl4)I`L(2BxJ=^Kl-~1*9NK zbPWv793nEW1N*Z=SC%>MSABd(VY&MNeE<~KI6ds?n;2oPL+L`Rcvc^wRQq(Rso@j7 zohpmkZXwra@;M1KP@5MX4l&7SNGh3~VAVtTcrfQ-yew~?$cA$M8*ti{Et`!E*%eb@ z5~M%eQ!MVH&HdmP;!$^7w}Le&EuedZAN-|gXc zpwFWTJ*&J)g4VN`Uz?uK5fdG0^ZE_G!ES+2lD!2lybH^F-pQpK0VoYWNcf#oe%{Vl z&^wd{2G^IOjS;M3Qtw4Tl)~dq!xS*EY_o*+F$4e^cPvuyr^ zyA+wO*S*z>qohvKC0Q$;4u`Mz)R``i}8@RXO_y#*CP z#WJNxmibAw>I-4<$V50I zz#TCgp?MqO>8la}>`x`AAQ{A>ahta6_;kU8`$8uym{Ch`-p?$&Zt1kaJ+lqH4aZgrbczrM0?4Z`!It+=vXz-*$b9T=FsxkRojV#%cGdWgq7;gfLSr^pjBDz!zsvaF;iAt)lL4ye{0J6kAWS+l|I&m@kpYVa)`I zP0;nv&JYNV%!P#b2wp+qkLFZ5`A>bt=d0$G_5mBRDDGjc@eu!t`Hhx@ezXFH{M}w( ze9lAF`CJ99f>iF5OuJ2Xn{YF{Sei<`a-3znO&K$A89fT*T+)C;BUz+=(D(O36us(1C$V~nU zAheL34yX9D*McJ2BX#a)v+- zC%?U&BPoavuA!|_eYZj8wRCpyHVE?^`ivK;Uss$h7ykzr&yHh4tKYcZ zfio^q`ty1}WboHoqPrm@yu3;r>yYw)069R$zaM=xOO7~yS8k#t!wV{O?Rzk!(FRw^PTq$Hr=z9?dvzO zchgQ_KQJw`^aOkw4|i2nRrP^!jy&@``{}=b!?&E9ZeUZhK*6|s5hCWoL#ZwG)ia7Q z@U&Kh)A+)grI-VG&xjQ8={-Om`58c=rl#{^Da}0Y5yQa?5EUX;n#UcfRU}_3$z^A8 zcBY)ySzNyZvp7pp&PNmmW-jj9&Qlt{>u~}xUjw6y;GQdP^AG;&FRwu*-4SZhh zX$mk-ee#RB@P}V-V@ns)pTxUvrYKf704YO-0854A0kyFJi4lf)FF80N!$*Uz%V&8e zfGK059W>n>pi6V>Ii2YYPEBp^GTe-Lng+J5`84<5^4l=AJ0PJ0%%M{=-X9R$%ZP^>LGv`SO>Ohp<`E#8rSO%~+FDP(0gnZ( z5A2(qVE5)N{!KThZMkO+8&<7m<85~}>+ig~zvb?A?A^W{7#C;fkbusrs;Y-`L7`*L zKF@yQZ(eIpeC~5`@adew4a74ESQg6$d#*63N``H zeeyGIlG1IGzAY3r=9CS|T(0L~<{~`=c#Icf?_`Ik!bZo_`JVuWE0`@5HgXvsKXd7q z*Uvuyti?vg@c(}Q$Nl4f@LNpo-T{m;UsU0y15*qSFK;gRq5s#N_RJS!VBIwCU<$tD zS=^iHELH`Z9&z;i%M2!COu$KVX-j>*JFv5pXz!vOh?MfYW;_o71bB84*Si!GGJ~$) zao&%G?(dI(W#L<0hGuPmJ0dCo}i@Jn+dVuCz5$(r*MNsH&=9v+6t4 zPlY9XRARfrsd)*|%V%oJyF$!-r|?XIn^V99@V&IX*MS{^85lr@n)&?zV6$l{yDL*a zi@p)pv9t}iMY{n4K^sktkN(EY`Is=%?g?-jfS#v01lGXrO}DV->Nl}@)u(_-V2rH! z@7AnP^U>wT%<1F}Fvg;l%X-U?JhnUJ)RQ>;l+*mslTT#j@yD_3=p$|MAuAbOG)!*< znilUm0$yT1z_l5x1u3%8Yka zvQ^HKf-e1a-7FU%K!%s4Ir4Z*P{E{4T~28Y{VXoeX3{tF-$qJ1Nm{!Nfbl`!cWl|* zY`Jrdue;-}ZtX3%wd-$PHQ2anHM`bsVq#(sFcmZO;%Xm;DeP5M^~}v<&-o_Y{OdRH z#OFR62d2R?RJ3^a!rv)gDmGMZ%P}2835Hq$Xi8rz#4?Z#LE5uGPXV)CDumQwF}Yg@ zZqZ+1rQC@oJZ(ndr5DrqT`Ei)DV1H^obo}H2#4~1zzVR{J2_L6Qt=n$S>o|-MElSv zKA6Tn{pWw)ef59N+iZbRz?mX-3D}WK^R@1uKqIjT=|de*>sf@OYsUd=Mg}xK(kA3 zOb1378ClBGV~%K-AA5oy`Iu8V;`Gz}uv1Rqn`z~?xXOxjK*^eD>*cCNK?J@dodNgkTPz` z!IYq-0!XCYG)_vtECE#MOMXr3Q;wG%prtv(+35{fFZMMBwr~GlwyoRX8}7Wv*4}al zYp%Pwx$nk1`WsiTWpej+U{XNma7|sWs(RR@rB8Cq`RBJU`G-I7$3N|9^uhb`_mZY> zTY`zD%I4|syb!qbjl0A{2{w8Ga2Bhf=Q-n&aj8%G40+uSi;b$IGh#81&+MP%lJs~l zKKo26aKvLB!cJdyWMZ)|{k}YnClt>quirq{jdQJ~B2+$m6JqY#%I$RgOaepmCM zUwhf$_KQCOES^`6{_5Q91JfLL{twy{e(KMB;mVctC&eu(MW&y(W*aC9V zA3y;qPNbe=7ISM+AswI3%`|dqxwt;dmD6MHLL1NxBt9VeM%)8-2Hf0!&u3Y4>u*O! z-a>$R1~>Jt@bPfqH-YCf_u34+8Q23Xk@Gg!auBMjV6&=f1@LdcvkKPm_X2x?Mu6sQ zV3PviMBlZ4%>M+e_XZj}O<+S@O@wmFci4cSP|PRBDR68`PRn?g)b&}aqDM^9&M8zp z*D=K16xJFvF<);8`jgYFzvaW+d)?cZ*mFBD0t{8CSzVg*;4?Yl#*7PKnBm1MIqbv} zIQ+CznN3d}DA{$x&O@n&}gMgU&k3gv`4#cwpF^Q)Xa);!+ z1kZhAGKet>FQqULCeBWe_jts~099`p9>()5F3Uo7^P=<8(z6$~P+liHL1kiT%b+yx zJI9io3|ng)4cRn@uKJK>@y`b+-)cm0AVJ(+?0e-+QXlJa?&DMrL|in{wOXJ$H3=$GdW zmDfvq7G@~GPHzfg6TC|>5*IKis4yIDx_5!1Ks;v<>crhM2u&&LvJM)T59FQfTPv&^ zn8)1q?Ks7X?G75x#fKE!>d`YJi{Z|TulEoA`meHm%}u}(=94PioB$SZ;Sc=|XFczi zum-v*a0TO9`J7bgU#h1&2~0|RC+(^DkBrM;vV70a#lGRhG}2j{owjSryA&Dfq-_91 zO8UB6{)}z+yyZJdNq-2=+te!QPXJ!`Af=>#BY4E}0GwCHd7IlQsH)1Ss>*_Y0$!eC zmjmwtHb}9cGT4lJeohyK_kK7v&!_4A5pX(9_`f0Sj2T z{LuEBAkz;&>kN)M^DIC5%riOkq!UtakVe(670b1G&T+Hy& z31QJa^$EEdrt9SMHx>RN70@mEd#-{m;4?wLGG)<5+#$*Ut zuAJV;=E|V5tU{j*8Fa1kS)8-aTXuEInVlUlf!p>C8*Tj^clqk;ZsyJ_uj}r)?k2Y1 zbsrNGJAr9&a|R}@s+v!#&duJ*PkN&N-#7kIcg}^6vuR+E(xnqLgjA)x1V6PcxhPA0 zumYIO?ZOVoY*kQEb}z0D+h^GAVK10&46J_39NI1Jb*=WUKN zi>fNvtg8BP;Qc^PV)uj{{Pxnhn(6X`EEt5e?*Y!hn%~2k3&YU}08I-HSWev*rz1J# zTq>a_7%Asw3ViJ4H1p`IMTg|Q2uagg$a)GkNsi4}o86ml<=$)F$mUg_1||Y(T6Jnx zsQD0_li3HR<9&=p%MWQ+d=q3Iefk+3an4zO)EQ@R=!qxV(jyLKWD#yH_yGD-#Mzii z_yi6{OjE-f1LTa%GO*MfYAnG{ZFh;~)O5{N^i0vR>(h|E>w4LtS*}#B@&qLHUIu!U z*UR&v%3!p-o{GFaqS*={dGYMda*-laz>ol_#31iA?Mq`(JKcLkRb623VA?m`vxe0- z+-j??y4LQx{JO!qo9|@DrcJ;k&;Ubm8C6wP54EO&srIbrJ*#`s-~29To^`HGgAa1i zodU3=dEi*)XB?fbK$GO4%m6e2M+kSN&BQEH z#i4Mfrp(bLph>QTp4QRzH0GY}T}n%LFoSLPev$PzzMARjEs>ILlx1_`+&p;5S?V(x znV!D|ynwma?x^jtK8gw55tY(!13C^uRTXSj)pIqs0dE7YkXZi!PR(vMpqVaWo_)Z{ zSo^y)%@gIf`Q&oU1%nEe&e8XL5umZneM;{MaOTu=jW;ErnbOSzwt_-XXnW9g&enTA z&zfuB!k$f60tSo#RHtS=PxF5XWNO9oVMZ3O;G3!B9C_AR&G8ppz)@$M>4%(nB8v}Q z#_$3x{$c3d0HV+jI5?4V?&65l;ywnZuEB;l<0}9s(k~VH!SJxv7!8icys=8t#CVT_ zK45@rWpo_F6p~8O2TSKu#=fJeoNg`g1Q^jihPYMpxs%Ch*#ISg={beHyeE(MqT4g~ zZ%XIYse81nSiGD*4rxMo1n$kme*pm*)t!#69fv+AnryE`twnmaGQ zo~?JT4mW34&*q#rf6vu_pH{dz&Dr1koaX=j!yjun3pT1>lvC-s3>9(?c_5SEgYQy!wax2t2TBYc;zp%`l>GhO95lPsHUb* z01J8ikG;XpeC|sf#|F~?c+oKls6#l?zP%e@m_kvloQ}&`n+CbhOc5Ud3g=|Xp}6I0 z=?W$(r>CQ11E8AcGd5FN`hfU=u>PjMW%J#C7l6L^0N|#T#^`;H($Wd{-`t2qsP2>2v00Lba*a(TWV;3B>60glD&^;r81 z0L%(5M{PV=_oZ_hNv?OkxcT4a3y_y{y0W!>qsY zU5xKp1&oSgwmLN{)O@fskQ8%(#jH5`nD)psALGZJf4(1m?s@jjfL?#w4Ax-X z03S@v{KHIvA*p(}6V6KHS(C}6uR1gV1X`xb=91=YxN9*X00ogm$K?7nnJ>FZ;~sSO zfK|vb(C*ohsmntFNT#CeP5~@J-b1;#k3L$#8Km>-dgYYzJVpi<+DzxkYlw2OBFl}L zRun&P+V3odmYQ&L_9DIyXVaQBe&kKUqP^?CuN|zp^$sR?Z3Q}U`m_~L)_>Pl zJtT0mYajok-|sK_>)-Vgk2{e`u#Qas%3#w{nt7>WI;pT4q1@NY1=c{G3!oEnpR{gi zp3-@pX>anL+>(wdUi9RS6jB;7$nMOT4K3oM?K+=1bopF>a^WJ)&o|jaVP5H*b1#5` zTQ3^q=V>sq2(JInulc|I#>?5eWBt5JNw3aL2gX@?^m+D_pZ+U9@{9{?YBHRX0w$CD zG5}&aS5uEHkaTmR-4&pB5vQCouBq!ji#s#Nyy)DFJ3uG>3w=l_=^iQR6MMFD&sDEr ze8<;-1?imdxi2Pk@TuteZu0xY4+5_R7Bctxd~k{*1EgLV&dnWEB~`FlRrM#p|4Xqi zMHTd&KwEHXdV0?8%p7xxBZYzv!|b=P_63*{11kZ}xU@)6JX@i-Pp)X5VP?c>1yD9E zpy}qt0zomK?n~CqaZLJHjP1e1&h@Ol;ceV^+lOIlM?lTCLd}|fKG#a=^}due@q;s6ZeN))wvm^!A^eSk8{zF|1qOW7h8V{_fCN&uEnqd3PN%a zyJIMr4<{xr=frjx35qKK?K(VzNpgkrxEl#*3cTz93P95}-a!|4a~KHhB;FZ-17@&e z?U%Uc%2xqeCEXtE^ET%oC4FI3N&hkCUQ@u^qdNMrk(z#WyiZb91sGLT@FP*}d`x0D zMGE@8sRFv(%jxIx&Mc|udw~_-hMLX)iB$2Z5UyY|IUW&s3HP5yj^&i|^c?NhY5^bV zm($N>J`%``dyGjj17z=QK+QdyZ|ANn|C;Uhd?8@d2-&w(p=Nbz&Q0N;sd!$*(j$-N zm^066j(_|`{!N%^ho5$uFFAY#!(&nGXBxVGxf+fX^>MUXO$LL2se4n}r8o~#*av(D zaAJr8Kng_7#edWtDo#*v+|^pC`vs&}5M-KIPJ?#J4#5ln%T7Y6lABVtjY8j~+~$@X zKTY|U;NlsXvp78|IYU(v&kzyM>G)|}R-VtxF4E%npg^PS>@2UV%=$*X#L8hQ9;M@-^gyt1A_F~My z5ol-`W@ccRA*Q}ZES-g^F%xHIBaTjKi#5_XJvXyCz+UoMpcdnMV8HhKE@$=Cf5)!% z7XubfO)Au^P;(9o|4c<}A%`7*0!N&8UUSOhpXkS)e*uS_a7>+|YDCO4|OT~N~K!If{1_WTa5RdfpmOihrSx+g^SGzJ z?$Sr*CavoVLZweSSFvyiYCtaoMwh~E7hmrme%UXv?Y`T9#mpB~=Vk{?u;SRq^5hr) zC5N4MZWNrvT|lL#o)d+I0GCSVM!@obgxTGTYifEv!&6~sYV)`Q5bvo#P@V@e^i1z` z35dpXH;`gOay32JyX_uUU-8RK?z=($49~%Nn{)2m)O!a^0pA}f>C2dVeI59q%zZs@ z4X}Z#N44rd%BmIuA4*lsCc^6d6@Zj(K9~h;>N^KGTXP&3qG?_U%}a$c1VAiR4KJNv zSt=Bi($Ez|HVIx5&$;6H{W?IkZ@lYx63o>70kp&59c)?kDOO+m_w3ttBQOH=P=VJ% zK^15oqz1qwFb(t=8Cl7pr<}qu7hGs3JpLk%JMTO@Mv`&OknEX8N9)UIQa%g7D{7|V`I4&uB`@;)<#(8ts! z5-6Oynbb^=!&lh0dxx#M`Ubz@tC!l1U%G5?@6|UmF|i#07>(Xmq2-*b{yV#BKO;+4 zHb3%5ui}NT{AEUHeG&}HAd?IpXWDW{eMQFPVnIfFmq0!bnNFUG{U!KHPCuW;J?dz@ zu%8T2bBZ=Ddw1N^Guh!;E>dLfxVfwuYjn}Wv@lUV1G9@le6b&?&`xRHt}D+c&ykXx zs;vk3YKNgW0$+REhr5sd&Z~h5V66V#F<o(LhMBoIkyK2VITG;fx`+d2u=(zfvi92F z1}1^A*}&vOP$|9CJ{2z0Uj=@KxmOop^J~E2!4$5EYd2N(A6!+BTKyLAmnrrs;KRUP zNkJbRL^Mx-vF1bxHyaBTEL`lf}2fV zH|-^-(67@3DDL_U3SASNWq1Kh?3wm||IJr(^~c^5P^ibeP)$pZ zl=Kx`_#>~g$2{}J?goQ?oaOF%TtYgApu_d7OmgZu2Tma;Ag8)4om>&UoJyXZnjnRN zBwntRF7rn$)&zOi)O2g0KRLxcSNYE6^MOQ*pK5c4nS-dUO0mPw>;8{8WxP=R8|_^h)oAJ9sc1sV-VY z1%ZPkmt}B#n&kcq=cbY}vP+X7X8A157z-N3X*5k;Q_sOrS16`A+X;dKpkpDsMnN2+ z>QrF!HpZhAeef4Vg zZr=b*3*>A#cvV#ys;Umy&&rcdvlsv4>+Koe_d-12CP~Fg<`FKZnHT;C6Ok7j?4Hu! zHHLyw2|y~4BXg!T@?4b95d|+f*OOaRI+=N4yrzmfpjOxp!|V2;fO) zf5wynLjza|gp9*RA*BHuxdQymcaFI5%mRc8NY#|&(M53I_4oMufAtqxf9vJIQs#@Q zbF+&o>F4vbm;N1xopz4(C!ljY7x!^jhcV>yHs!onSJ!4vN2dfk5%**Qokl)`bH-7L zK^Nn6PRM6%#yEK|6)EaUXKgw(E$rNMBdf1?IsJ({Bqja9N=vu7NKY5z#S6h+4ZfVY z*KNRCfd*I*@7Dl#QC0r|RrRRSQQ^!yUt;$GZv<`wdO(+;W)W=ab$~)a0DWK_cm~$| zK4ypO8Jd7V%u?~4a;5X++RSZ5S7v@s{o*~%U4ouD-5l9-Kuww+?AyME`>uZr>u>!J zU_USdGyo4zuvwwzL!fD366k>C9Ch~TocP!$+R0CPGDn|#zO6X+a331OypK;$K{tpj z?ChqD_hO29c4Hc*1gTU6NS4wIOb6{XZyQ~?ZLW+CzMx3B{VZT;9gE9lf zTs^!DBNH$C|5@k!R)N`op zbS2L%1O{f8e2_e^o_#9y(jC|_vES~z>N>yri(hT7{?u3d_gr-ouxE|{XH}KO zy~537&N;vR`M3X>UwF}z=!5rXaZUo}h-Obyk9g`|hMYKMCnfq&=ocN!AT#~_nxSW@ zs=6v?ZIfW1fk~sdBV}Ky4Hq{h<#h9SSBI#%BU`}mG`Eh;Y37c_575=+DGpD_?|_{1 zNz=g40{F)JKH(pH&9A}4K46sjqUzl21AR_^+Dq-RKl*wfU9^blDKG*|cH;O|fGyR< zot*kD@1!#=V=fCoUmTa8a|}H%GeP;%xGup{nWNKvb@?vf(_!PSZ)5$fe*zdV^Z;C% za|t)|J@=ggmIE&b`!R6lUVH}lNE8z4fExmCZlvf~ zPR};OR5=GUVtR(Ag3vasJ-asC#Oka5mhEf52n&uQkf{`&SoS8m||4cCjgR*%Af(;%mNM9=#_KCY;C~Q*16p=RmeTOcXM@HqkEi_E8VZ|2g)sDDVUTDm zr>5pHsTX4u*Sy>N0)1M4@g=h`oR%`X4s=LR=_`M=q-btB+%>_|gZRsA>nccN)v zinE{p-S*Od`eRN%w$J+&cxNF-f|Nm@_#tAp^;B zJjSU@RGpylEOCi7Ellp)!(HF_RrYQBe5&+slx6cECA|YCfeV4(13ML*Io1^L&jB=# z37~mBa4j&-BVJYYA4yd|8`kZXP^6@P6qt_pe!;ET9c%@3>9-d+m8SUvunWNe0wyXH zw49D!azw_JQqdcYrE2IJH|bk!KfrmK`b<7&Q-Nm>++oMPUuN|+|HPinSHuS$MpT`e z)u}m45uj0)9C1Q((&H}jQ=k3}PJH|mS$X_13@?DLj}4}w>j+qwDGpd8RlQAJnp*06 z=8*NDH9m$}{by}Vy1#DO8>tVND8AokoR zgW41?6d5Y0Tu@0TF7@@odr#2i?!lDZ`i(37^8flmclD>g%-S1n2lfJ^`af<}Rn>pb zAH2h>ee#Qb$baVV|G+MfRg)*Cg)Y#B%_J zt_C)|5MO)U-TvNR`2{xJe&u{hNv~Cd#M{_H=n?5LxBY8+D+C2YjH~_pP^&$1&3mk^oYp~`i0ANx{oRn@3*nx`k6hLEB0-iY)y*)simDAK4 z%WyLRRg*$QO^oTmV9;mN?H}Qu%m14FJFX3&ImB$LQ1j6WG`j$q`++_qBZsypKK7~h zgr9mT&-mq6aM4e`m=iBLo5hDL!5#XO(DlJRpEIdW=j6hSyFf=IZWzQJz)a5645*nw zqFIAA>h4Tc(PL|PI5hJ?k-2D?%wfrOYML^Sz8fz4MebODzXla%X&d>N-`tOwCrkQD z|71p&_gO!FA!WVM#SA93->&y>0P=RDUiR1e4q9EEvM$kMS(Xm zJ2WlB?)-VPtPD^YfOWuF)A|X=9cLFj`x$or^Pg_VoONY0ZVUbXE}#RNgK}_I zRaMB@0Mowq#=EU+26pPx9>>CVgaH`$Ukt8XfQ?Z3?~!=NvUA-EXDsLETm;ApYZm|i zQgUgc{~KgVtJis>Pa2v(Kc<@vP>H4g-)e?g#DI9w38E$X>zoeOSmMX};WbmiaENIw zx}beAS=&6;C7lbdL-LV3F)!T!Rvy3H+TKEL`r0MXAD=gcgeu%Lz}dTPLo>2)IftL} z1lpcBE<OVj={5GJp-9j&oV0GKeZZ@p1pifx&tE% zk7s&fC;N6>8LiD6gUtscCA|eE!%2Az*vZVjRsa^R%>|K`z7N>@$gPrIRUMmEi-Gq8 zFO=Ats48{`&;Z?R#e!xzTQft?y}(k;eiLhcq+I>na*8)#vs50>?o5p*K-n75i+&0* z+rk>zMJXkjlc-d5~|hDYwCGQHJ^y*WgL0dna!zB ze5#-FUC-dy^DbcVVGA&W{uI^?v~Ug>fR)dW6xX5`ei49~IW)!G1tP{cBCS07%RI=s z;^0(&hgl==r_q8!0+y8ifx9J&WdZJVZxo6V1xUq;(9R8!6!#&YVHS<$Gc`lm{h3@h zHoKEEr@NO^*yA~$@t9&{Cu4G&hH}BAG6a~ta(THx(5zMD%j@N$8pZwOwelDAot&TP zvwY67!!--fpCQlLf)B^|Z4>+ax-Vbim;U=Fx&E_XWBbOnF~um*i;=Uds;d5*e}d7` z#mx`>*{k?JuliMn8Dd(UnFn-YmffAIR3SZ|k6AkF5=ws;r(!}T&k9`7SZKCt=p`q+ z=lTB`A2@|HC+C|w*jN`CMCVXO$WwVeAsC``Ne;2$6fFwrY3Oj#J#IUcfiPw%AzAP z7a0;KWE^FbU6uf8?gLgm&tszvy12y{(s-?g9&PcS+Ty(%fVD8OXCrrA{&L2*UkWS+ z3}8N|rAtcsQ^9^8{HO=X&Hwf&f_zf&hpXb+#UoBt6>L`hKj2T~eHZW^;1Y3-^|esY z1581m02-R+SAkyy1(+u3=V+R_0MD{ZGQ&sE_Leg2Ol`S6$8M;C6&*;o~c=(X2_)wP>&@?{D1772e>3xb*=w>`rgT-G|G9D6G$LXKoUZc zoIx0j4Hz)VCWFB_+c@X&-gC|`I6a#jL#zBWc?ZIsagOx6ZItvi2ZKG`}~ zryPsqB<+%eSMiukgVHOE&(qn}W=m6C8%J~Yoo`<3U-}>aKKkZAeVPYuz6ls6fU`UL z=%XM1JFtaa_d1}x_P2kW^Ir2B8ZehZLj755ZeuawKtfu+!X5d5v+#=^%fLDrfIaPvCgo4|K~Ir`|O=zTnC;+!xH zTAH@~6YzNjGRwT0;}>LoI*$Ebti3C1Su;>c6UO6Mz;PfzWtMk<)3Q-bqn3r+n4!GZqwTt$pS&;XF*5j_!V;J~3>W96HsHVm4)AB5 ze@=V)3!h_q9K8Qv^TSi42k%-3Y)WG@ql!NI=z&fHCYau`-fzF+M)o=35IgXowE#Yn z>$F@)<9(eXL$58$(5zC6=yk$CCFEX|w_-xdt8^g+L*0-*RjD|nUlpQimiuT?agunu zMIG_pJf*iG-R}t?G|DxLKBfuEJZ{LZx{YYlavh#0XJafODi2TRfd~13h^T8g54#<( ztJ%aVz7vx4#lqU`!OaHDGxfmTtk`8Ac3=BcYXf{V#G2`hLYjE@WQV2m8CBr zxH$l(!S4e*1ndA7K6V8r!#rp&4Og{ zg0V@Je^c0KFU8uAV73dGfEi*K6#Mggk$%hjL2VGEz$EH^ZUS1$(u#FdelC3)Ov2{% zH*w3wzs~ww|2;XM^IZ;V_MoP+Gk4zSU=BLzG&|-w=l@?Lpk4M~Lz{rnEX>bG@kb1M zLcXm}UJ3Ne+cYVpfRE&LK;+?)uQJJ;Eq2HLl-Ev4SAuafyhH#7r;p=s%9&P@PR z$<^g~YyE(z^72|PZDroY4pW*^%3SsXX)8t1=WS$5cDS#XGHx5=9Igz>ZaKWBkJ|RW zYkhTY&#K+=p$F+cFSh9+TF$!rUbS8Kx#QT0;Ajqk+t=O6SO57F_NBl3=ixP9x)j(l z*1flnKKf^aAuz=;XFaFA;J&w!1TNuAc^w?57g2p+xBkoKXjGqpcLqGpYD zxwLzip^$5xVs0dcJ!%$&NW%fL+?zPwJTWO#gOwEBa6CChTXCF=aZoCg`kVHvv_7*$ z|F0x{)13de4}X-4|LdQ`b#~DIW*0+0LbAO3At!VC8-DG7zaDA9+RThe!y&n(qYT}g zn!ra3_Qvit_;wqHkCJFV?yj6W+(L8bV#J`HLG(Z>$z+!ZSen|J8$~>JDJ(? zZD1w96G)PNKG;tHYqpb1`k#h>$XZ}7FptZC2k7GoA3dv~2mmw1DQNaF+4eE6QLxaE>xXTx2e1yE3P@jIX|a2-9c>4dX+yzb0_#~jAFPXM&2EBX^{7(kY&%QUrH6IP);(jJm$Gl1U&!lk@rX&b^K+(tmr zZA{KYktbuC>s`0&F&%E<0O)zhcFDIn7N}L(y)adAId64u?~;>?Oq>$5tifK1I)`X^ ze$wZf9g9i(W1ZB!1H_g7)t`g(83`?$J2DaWawFjG_4o0$fBl4g@vr`Ac-0p!ip2Lz zqeMe%?4ytV8DS2X=d?FoU~m4NpJ%VtYitG>Q5*3TvT^V55^>M>1OWs^X72jqbYWjA z&PFbi@jt1}OsOy0 z%(-Gmquf^PCypEDx?woXGc<7bwSUfCSNxPbdoBRDDeDVsCNv8ygZ9JVZvbaINz#8e zCWsFM?g~lz6~Giv*yy7NHv6~$_{(&`n*shaa3Nq~7F0;k3&y4_0_JQ6o`JQW!R$~# z0L^&cQZ7vjNjh~-O#v3g{3lD!E%pt%*_dshZPsmRKL-;)gAI3G#BCS<3J>4+bzlHY z_DszkQU8wbhXDHnR_<|7JM84s{fINq<E(fXJ9xi^I}?nd1jWuMO@`K zDtD>uw#Aso(PJ!uWQIM$k`yBz1J8h;rFzBGr_Q^H>A8TG&pA1z|HZheOO8z~fvyc- zO4A^5nUykV9?6=aSofy`+^ZRoo#!$>FK5TLP9vbsyq&e|yPGjtpLcy8_3`6DTRmQw zs#2z`vxrKho+ghY#lypqQAM0ZI~JxKkMW z;3caQAIbMEAEU3z)KoTRb$sW(!b}KdX%;3zv5f|^TOQ`7ufLtm4}31bc>`E1PU#(G zr-4JkeinEdINKpU0sMDh_mHH2JD8i-KQYHnee^jt`#2c*6JW2j?X$qg<0fu}LD0B` z`jt_Dnnz*w5zLOo3)wjaC_~c<*>{5`?+1enYUbm>2Fl({<(lqGud&@yxm+gtNK5bA zBpC3(t)JuOOMjWo_g@T5j0H8HtkK5^n2nji0eh@HuAT7m*K^K0KETPZeFFzSV4Tf8>n70V3F3jLB}aycyCOIc``8VaR00`$y)Ys#ZZ zYKJ;^Rx#0G)&Psmacq>&;3#HerO#2UOAcNu_VYFqeJ4Qy*J$jY}U-Lee}@-oJ_#{R=?xQ zn{1bZ_F(OCPhp_xB_ti5T>rgh$LHIin1rQumt3AwFGa3nsYmiSr*&nZJM}fO>$<20 zY*{eXiFU|+Jj(0X1he>Tl5t^DXE| z2pdeo?rRTk>#n`t@4xvfVCkayPWRwuV{T?W^HWpob;N15e5X~6hB;eme7{KPk@EP_ zG17Wc4(a$;W;dd)VyvZzzYdIW`4P+e`cbf^QyXIC|8+4Y(he$Lu6vDGML_0rv!uITleg$Aw~V%zhT^j68ybra*?~tCV#sO@z90V-6BX*$S6*lf0a*-j2zBVU-Rh zVKf|Z-wpqR+b{n;rZ-=oylz=Iwr0=NT&(@j++Ojz+hFZUC;2gFKhKYN_PMsl;RpJ} zq)O#9*haYwgUmlG>w z=E)gdn4K=x@pAHb2EDSgc0LZ4?F3hU_EP_|H@%5158VN*VsS(dZib6?JMn@KkB)!- zJE6g74vX)ON8Zf%ZiV}OyaJ3Ii|-0HN?(=iI__YZ!I{{g;~AG(&R*^ljNU8@WN>huQbw+vO4QR^WGlha=zS zdf?K?x4DHUO!UzMn|-_q_|FM&djR-D;9CKD4!b1i`r5GoY>j*w@1^m*flQ=4ml@27 z*G^zla$J^Da%E`hzE*6n%9*w&;HO2O2LWo%&2sm(f5)9y{yuYCZwHnssM$-6)>!2 z&1tpj7jkTb)Lqn9%E6_tC3yR2hO;8QFZ$}#Oh+W=rH#ucS%Z%C{%r?F$4c+V%k~wx z(E4OuLyze`R?Bw-q77IYuXjCkKVSNnkGIeMr@x!O_Uo4c(*bZ!&_^Hrv&B3x%W>yD z$KLwKzhpSxZ$|x&N*fo;3SSqKoypO)WR4@PDc6`D+0ET$mN+>3V{93pZ(bA zv%mc-DdX|th#uVB!p{4hz_Wkg*V*gH<83$t?tu$FlKav~22&o!K?P_SV;el!pLx5J zk4<$rSb&P|0%DE>H4z{avT2YQ3;~SNK9UqYwppy_ZG#Eec+a(5|Mj;pKXntZ8eox0 z(yLdG@yk=dejYdiob3=F2mWiQSN8y}4P&8efDwy6`sk(TeHl8@ugyILE#4wRY|geaKGx{9gD8t-Fg41?D@ME~ zXPpcvMmchyqfN53EbqsN;}X~z(sWXv%*ax7$I6_cDtq&k#lop26aI!{?5%J;fmjgoS?rgaoXK}cE3_O*ZY_PW1PS6#+D=___!zLMikIKfYR z#dB@1Lk}EmxNpPg!MpB?Yg60|`{?7l7G!Av+;{V>ZF*{oBhEU7ot7;3c`;OBEaO z>K5nYNy?t{iN`p{qe{~WPw&K6;&||+2#NMZQY?Lo6g{IMwqzOXe$e55+oe~q;qL1f zRj$n*+%#r3-AfxRVc(;l&BW4y`3UzkPRg^*dE6SWq&)C>Kh(J}_C4wu?WEVdg)`sremn6M7qIt{`_l%ExoH^AgM;Z42b#n&1D662 zl5%2Nl4v(0oAHp@lLnUFlflu#h1|@dj@*}MUmg;O_oRJ}<$R!GI8+TDA@`M*b8ALD z!c5H%H`Wr1L;*r{yr>{mDqk@urHol^E>yay$D#nBd;Q?557h1ga8~)wOxKm2sbysB zTlC%ZoYaWI>an^@-%;?f`1`nJAUT7KH7Kq1)nH=LrxbGjg~9xRlD!z_ug?oo7b<4`|?Du#_8j`7HEl7 zOMdUwx7fsPEBvTaPO>E!qvBp6lTl?}W$NFiduKgz`=cS0}y1ef<%D5~&C*cNmXVOKqhzH=f%v+;du-JhqW>LaGM`v;1CwPht~kOq9-- z(Gc5ZpH;LaJ9FJpL@0>@;qHLnKl3vhEOFbrw>EKjQFqw!>lKHdtvCcVE2__vsqXvqb=05l5|p_;i# zY~KPr9qip$+Zi3bDY(;QBqhLNNY`UY+cG$62^=MF8zf*d*O%SVfu?NDBsJHOY#YE} z2~2NX$E}zB3U^=q=W))<0qf=G8c!;Kbp%Ys?`FUOPkl~%-iLnPF8HlK^RwUcZVr0- z(KeWbnawai19)OR3P_2eCP796tTqw}mVzf5oD)mV_HTtW9WYu+L31O!oy$JMqi+G2 z1(@0hK~9p_HGP_kdWGH=<()Vtl?B609&&<-iXkB&SlUJ=fCDbzo{yU^E*@IFV8rBe z0copZymSrmTtLapwv>ylMLBOWt5krAUMaGzWH)x{8@X+ zd*9CLHG9W(YwEk$w62eSvU4d@QyWL0`0YREqR)MX20o}e;OH%_x<18QS2lchNEb$? zSM2(7qAixxq)A^;f~4FNEVbRFzo~9*+bz9n9%`5Sf~q47Jay92IK*XKf`QY37WG&f zdw^N4Cygrtk#%c8QlT_apjZ==!}J+g)JxQb7!mpipPz%{U-(>}^75C*m35xQ5WQ;3 zfMsmmdI#5kIHKURtVpYgF=?Cv4SibY_?0NY218abp?fAU8(9fQez@6a#iu1sB!r<2e z=f&vhq4N(pukQX`pmQ18E<(v&w1PXIO^=vZPjk8nV*H>4EPAuwpufsc%PY< zCOKyD%$^JY5#sxqn2wp**+lNu(snWLX^%Ljy9xMchKVfPFf6?~tuQpQXcHjTGZQn_ z=jLFI07pUD7x}Xwov#3LUOogC;2y#lq-I0PI5r)qjF>{w*9yrvBG=Y7JxSi>D^N0e z3g>i-dh&ax=u0cW%F=Ktl{a-57setr0IN($^G>OD%_8k6llSSO^_x6+8)g0aQ>~rP z^)r(48e=8rR`pfNRQv^v)*-W>jrIL@--Bm7@4R;8=_j7$SD zCPtY76HIS-fcx*b&klL^3AXpHd)Np}+3uMEFZ=SVX}XiVj=GFX-I`KGs+a3@J&B}s zt3XQGmTIb3s2Ort(+N902g&tJzCR_CKtoIq^Ee~-BdIosvW4Zmky)3BGA3seZ<*;C z3m9_ZXuj|Uqj^}iQ)|2Kd$8Z|g|D&Y;X4gsmHH z=hllq#sjzhQ~Hb-I($(8hJB160L^8~cH`hv&bR*!X4)BV`C$$}_d^bBne9 z^nJ7ixPY0C8X}cBz9NLMjevRjk!0qIc1Oy32CY=t16bGb6&NYy5(`ku*X&RR7_x0lMJoV8uRbHqokyqBr(tj*}F7t7RT6@5OJmbaZvfon<8$5LH2EXst+hd|;qF3nj@m&VI7+|cw z^){QCpXI1?PGi-?QXdkH)F5ST&ZF0C!8Ej-GV1g1xVmS_c2%{yv?)=T4ap9vPf24| zN#xa_Pxd4I@^lf?lr)weC-SVEki}{8U@H>&^^^m=!Rk8BPt5kH-#82OOzh z2OWIkm}=qOJH`W^2Vbdt3N3Gyvte~{8o}g}0TYvZvtiv=8O`4ZEEx-8E&!Oh0A@l1 zU<>#ru&02nVc}x}*geQz4*@#`xH;EL()$bC;)^~$0Q_2de;M$nz`Ti)Xl7}uiBT8@ zZF=BFZoBlCc<_!-0|rbkG~l@7&4PNSW^yzk7@tk;~_HyWGAt^cZ2=kdH5NR;uJ# z`x>uOrx@_)`E)z2m+zry$GXpTeAHmBX=UTW9tG#X%lG4lq8`-!-RnL&(x%);8Rc`&*iE;4yt^lW z)o~osK8vk5q!CrxH^QRPs4M!F9Ii1uJ6dN~cH%XhrOjhY`XFMg*|-tM*GVj zeEaa)FaBGAAJ+f27DXRsfFQzANCKzh~lL z9^1WeGZ(jYbH{6E^W$yP_lb#afG?kN!fl%I_^J^CF=(;p3+K+w> zCScQj*Kqr{euW3`_@v$x#zzloK7kmTGr%-UR_)i0J^z)Q^R5ruDc}1R_J8VOOe~pT zZU%;P3FuR4xYfz4VxJoM&|(`F_2hEdmAqjpQ&F>?Tu*$5AR_7WU?{t^ zW`x$jYHXJBq&}4rp~7{$G}=Mr)9PGa)d5hkPl|e}z*JL4O3n5u^K;hH>r&omT28@T zS=Vi@pJQrIK~TlWN|Ooc%UE_|?er}nCZLrAxfKhK!FQAHK9#7%I3}lc*RP9pNY@{& zpv$ZSNFBzq+p-lLfAUFo>{%z<%n-l(#@m^nc?f9z*zdb2dJty7{QMTb>zdox`>6-p zfol)L3-ccekgD6!Bsm+EI)XeQ@nN$vk((}Zm4!yocs9fGlbGniVo}9|X?9S`< ztaL4RT=z;IOg&N!hAiJJF*PU>cXZE2LNZ1vatbK3bTq_Q@43_`mhQ~epZGlU^P7Mr zEQaWrn*(6Vr#3vqnuDKeJMX=ZkA_g0kK>s9SnZLmU@l`n)8Drart-dVGm*l?)L9Vy zCA$1Lt2({IhsaW$;SaHN`TsEzx`NrMn}e8Ri%^noMIxSQ@bwsnVI08riT!}vLXy5) zEYrZIUXs4!qX#zoSONSIa6)n_|7YME!p0oNQX2$~2RY|Mf_@fe9|m@U1YVZOeg=RE zJF*MZG%|QuuUi5$1>9`$YPwI>N$;cI3?`vX!sc~Xa`Pp>z=pd&2TZW-0~&uq$j^JG z<}hTLGpyQe-*)u5ujbtMe3VnZ_pR)6^g*IJG0WNWB_HNY0@;Hr3g%bSxEkSvZ&*3cwb~U6}s36Xlw?rAB>v-U=|b zv|hMnmr^{H(+LQf$9vYIyw;Q7S0JgdAa!4D^q_#Ff{c2+j8BVvXjYMXZ;<<^N(Kcu(>OEQ{muwUt)$DF2{N7Oeul{BsDD7F&AK!)Ta@c!R~91A zjc{qPo8F6~xv;*H(_4~^SDkQf|5I7ub03m*OTc zDWA#0fSNlZdQj8j=Dvj`tM_V8eZiaTWk3H%{*s^ib&fjoR3?|e%oc1oi#ed*Nza4r z7)YmqHYN>=agVF@sX8)}b5R+&PP3>h+RngZ23g}Z%e+&LO>ivgli!XBcq!6xahOcM zsq_>lEJMujIL7r_p_d4{b5G`QBm_XKO{lx)h)uhvCN|Wdr6Hkh3u974acp#Ko59IC zr(|6*@&NlN#6o6u-ELZq9HZ@ZnfW+)HzTvY`f5FolBua-b(zwz%1dyu=yLrz>kYQ7 z0|T$yD8s2Y_z-+Eu#{%!op-+fB zn*EOgw$jI9c|I8cLvFp~)7*L0=b(WNF!Fd70IX0Kc`~+5#+GRUKDmwSIGGgLRUcEc zAlYVhl5&%>dA%O6>3$&-Npkkx4mg)x_d6SyOBley$HFno1hc0>24q@h zXU2?_=B_kACFn)~mm(Rj*qO0?P~_OGjDs*3#PO!>rus;r=7xJN;g(UizQ-I)YsUNxjOH;C0Eq>@-qN5wxr--i zR+f&(Iw%E0SqlncYJEvJY!oIvX)zkPZihnhPJSPZ2V!4rOZ_4_wWqm&)H6WXV zk@^ir!!b-*mcj~Dg9Mt$=o(n3412uUq>BVyk5@vej{!hyqsn|<`P|~1G(Tnq$cizL z^glxCjwl&Mg&f~xUpfTX4z+Co;e-hV#cQkEpo6amsJI>Ly@Q?V#Enef04Jl(Nop z`*pY39*6D2p~pPMGF!cJL2p^IUP#4@+dV1~SFEB@|I}NjagVUM(|(ujT6e22o59TQ zPTiZ^Q2D(AvKq=Rm03EoT!~^rh9xvLj#dyfwpUVNi@IWeym~&tG)95w6H&j9V7CMJ zYFjsK^&7wXWq?Hkc=WRL#%S(A=C;nT_t9ste5aKblJsokW0H5)u%aOsMUsT)FH2Mv!H30d2Tjdy>A(P(4xim=5ZN$)Tc z+W3DLvlD>bwiBsuPvAP>-T*dtkCD=bXupr1vDwGt7|Vd4j$9E0h5FwkXT$(-k)OK& zolc6hAK5n*33lI(*=co-F_Y1lO4J*)w5=60Os#>kF`LNI$$2`Z9+9P|x@0jR)(3&< zKXls{x%rzv%ck`gh4g%KJAjV9110GGUBK3KYKG<}mM&exap!)oz4Bv!Y%lxy-{!dU zpJS8D2h41S`5A~owu`I32S{!x3s_yn!?oNJOH*kPSq>H7O}B=}ertvia&{oL2e_yb zu1w_u$MM7pwUloY#1S;gxjAH@)*Z0K>da`3ZUZx-{}AV&iW}yJCo6L^ai3M=o{}k& z41plZ#*$>%UgWqWz4t~+m{dL729yzWz*JBS`V(MfgUgIm-`f;)X3kLqCP8`nQ5EVEMc$uONaEm zb#NQBO?g!SeVfiRQuEtZU@Wju?)_hi9!t zJ<4_i0EY9}#3Y>Zy{~2er<@GLm2(k9Z~8d^Cb;v)uX5`}AGgsEZv#9jn@p5a?go;- z-VMxJ?9ZftN48-=Yq-Z)IqHf!9w9%F(kOV0^`q`OXA=7362)QR34zS?Hz2DI_1Swg zf}Qs{ot+MN0WjbF*_Qjfc<YIF(kZJd9`Y#w8K#NNPp(boC^HxC021$Ls3 z9@y;Tag8?uFG}yf3S3M?0cd*nQpRlDKwgL0%SBI9P^4sAMW=5D2nFMK(qCljLze`g89VTvN%@2XH9e#Sn_$^a9Qo`E?4`f> z`}UHb{Y{R2{#h(rHDGotKAf!)1firkkby)}Li;RpQcZ0(>4|kQ3`jsAl7G@6w{I;C z;8UAXJJC+6N96Cq+%&UjKh>GbE5O-|9Ol9vO_5#KvvkKh3|VxaLzxU-_qz)ST1&8n zRU$xXQy@ssqv%6^qhr9fU`3nW@jl+xbt)@%+nvp;e&~L)?)t1a&N}|a?$nnq?WO|O!_Z;uGFZ;{y#Dp= zr~m7JY0rPxTVVN0U}NtL+Q*Yvrf$FzZol|j_HV!aUsyl0fu&VC3BA?{K9O5dS-2JV z8V$YYcs;pP%F!!^DBY}k_X516-sYu$iJZUGpX)-(n0}slLe#*j1}u-2EP+oZ`O4Fh z#y~FSg#kF}eIV^G9N%WAV6P+gY|no48-n05&0>ij+*|_F4|CH+|H6j5Ze?PUJP{9~ zGBOJiKw|k?i}i*zxrxgdHV!Cc<4U)d{jSG|OsSd`D9t<5(m4>6nTd&IjlB+i9g~v> z16#(W>{>*U^a)@VMxOw`G@sW3$Em>ap;}o7>=fYU!970KOVRsy{NkzMg1$?CT`rTIOL@B?3{P~sGacx?`Hqw z52p<#n4N~vJXzCerg>crWh>_OnB~V~Jq<=OyD~8bWRTRNJxG%F^2sUH0nv7vB~HgC zz!KEKy(PzTVSQp4!4^%qi44nf{CegY0b8R?qD273gJ5My3b;&GyH(@JdOgeOjACqB zG2Nt0=?1HYIwCEvrQW3r_V{+YSdUh-Yl;WREH{_jal%~f01qAN{?K7kQ%f-GddC~% z)SrbH{Z()p+1J@usgt7Lb)B^&yl$&o-)X|Sw7P!t1l+rRZ?yip-{qX-TeP*6E*ti!>T-ee(!f~vz7bqVuzo2qD^8xEHDeJYcfq) zL1DUGq`sq0DFWr3jFiv!QY5vAn$roRv%2r%I?)o(W2~V1kJGB*B;vLzv(7lcik1i?y^3;!wza+ z_itH$FDrK5-S$56WNU*MRSN;ZOo);(_Vx7rbXDqjGSO55Pe&4Mw_>wXCoxwQSaF=` zfB~ti%7r8sqophMWPWA?n;!Uv;6B~*^97fsZ@WA_Nzxw#W-&V%vt<|y9TOpS|4y(r zmxh^;1Dm$LB)yNGvDwE2@MFM1NrL`y;I=BSrpV5nZC|zmPX~Jk*orcdTBW@#&3*=% zshL2~^xB#}(Wx|DUNfkvqsLS?2Bf;%B)G$UH~k}bUGeKoZ@NA}&A}5E{Odu@d0;bO z?0@tb?S&uxn7!f`f1eXx{5+QJG{Ni^n4bj$MI+or)0sd&yvc1g9|P{52Ia|NQ4<_i zR-=f-s?7akc%m7)gXMZGNwV|-Ap?(k4whx}+ID(!66&9)`W4hf9Zox#d2XePYY{bQ zM$zTGU1fF@Y?6`zhtx^88#sUxcWQ>JV7*emp?w$WeQHNsdus-%9-p_51N*!(j3~-$ zT{V%v-p;l=o!9jg$3p#{qO8Z;T4r9eL8ZKpAD-9i^>H;TD}`5V+xi^GvrDCn4MTvw z9J80b>=mP*{M$cH?9ENUh(4Zt(X%+0GClq9=-+?yFYL05zD$$!8rAhdw^fr<4qi;o zVS4?p8IQWZyt$Zyn)SWbkoql^mG^nSOMS`?)i%7sZN?}ouy{#hE+>y?GAQXpnfx)N z<3wU1Y)yB_Y8%TFz4D=%Ipj@qGqBU%%Q@{$Z)DYO2gcRXSq#y$M<;>J-14=5<-yx; z@D{Ai0%X_mtpjc*yR4Rnmxhe#rkM`Ud?(b%z_TY?A@5{Uq4aCV#T_(dTA}?+%(CrDJ;$=0H~q4L?knMUbOD$ z`(O!}!TOv3h1)Ot6{a@b5IHs4wn&(y%#H^ndr)&8LN>YAAt$zT-}CeKs^9nvKjrnW zWv9J&vDvLKH!V&v203R<)0xjKA%`d@Id?LHG3WGYkO9CJ+hV)L@fOD$V3}2!T|+JR zw_(I~NUx3j<8{k7}@G%V`PY)!X#P5a_}aEo^20ZzdegL)1_ zKuI^q@_jGZA0^0BGZ-zE9^+NblYAx~l8cyb21QgXh!ZjCgG4TKx-PgJlf=fglP40(Y=h`j&2jzY#Z5HOqRCzrGBXLj1 zr2crWNAhVSOFsQvj{&ZEz$Fi&k;W>m5w)cA$RH>X+Z-UqP?)85Aip;Ogq+mw{0yU` z&OEg}?PV_ohKcL$PyXM^qE9QajP-Ya$8Y+^KQcc(@;33v7#>po)+XwrocBJISmNOC z7VkX_FiH9A-7p$%sZJ|EMnvr-%EB~|DrnHLPf0#nM(cOk&InfSb`ZNC@)}?{FxUC{ zZu>SCD&JblLUYMqX!T3(ho?FUfk)+20!a&ZYnb%w4h(0JJ=>vH$uU5SuBnf)d zi6!a!M1Y#NeuCSt_!VZi+$5mp_6YAm%>@m0I-g^wy^d-pUGRfE=ZAiTW6nK?6}zrr zehTL2AcyHdp#j2R^t2ueWadCVo+zg_rrBlFqCP}Ip5A9eA;N_{yQL?Y6}b$OFVlpz znOxePXjk?-S)vo|ro}~aZWytu1I5@@13T*2suDVieCl0khA3s_=@l_6s-(mfIaQCT zz(pzJwW$wAaSU2lc^>K54oSLzx?X(_#rZ1URfEs9x~Y6{rv}neY`aT1V~_6!P`d%x zv3(uihSpt!AYCjg4L#nr?R=%IY%j~#WlVn;qnIvQM&r2Sj`L&BIn_2z&-g8u-53*| zlf5+kNfte^W8`<=e3$LK@2(v2jFXs59A*7|I;iZszIKX99b#T5br_X`K(|X@^!`#S z0qXpj)RR8al-{?r&N@?v)+;3Z(ML?St#hy*;A)>1(QHwSq=jup4_*ai)}0WGQ8saQkH+3;Fq@0X4k`HFr3mxfR&V%3b&4#8y+(@=JrHdo7^T^5UWTd2Q(RvKXyxn-+{_4k%u^?P70hY3^Iwa)g4{hG}JPdV%;e)JE2 zWAMH|{{{A3yEfPiv-Hu&lOuu=G_`s3ncw;wyYjNHF`+V6nY5}I_8NL!E|m&(q+QCg zl#bW=GOKHgFg}%;512Ah^}Z!-=I-fstmu#ItDN6)@MQGk(cxf*7EDVAGdz|QO~FkIZ&JMRFqQ~1HpJi0yO)vp33#39{#L!lkohb3&j=Q?iu#y|SZ)_EUHV)^fz z0B<}gtm0M8rd-n#=#4gxix4tGCO#15Dk(>kfn%%XIVOXkCMHBJ*J<($K1eejBUrwA zH}*K}wZKk`P?GLrQt-_&8hr-ravIw!P6SSi=gbWuLq8~3n=9#~2R8dy(6|8j{`CIy zz-52~LzSV&LdDk9_riiZ4eYJJWNGzSU8LP0JCf%MZ)@aZYf64B!Mcnk_Q!SuJOQ6A z$;sKuwQjM}nH&(Z?LH5ti-5(dWL-Uj7UJ*`EKAU*v$N zALFBWnBEM-`2?PeW4IY^4YO7|X=a9_fSMRt#+{_&;0euhBf!OKU}AU%L6X~z6ZK}P zcl2B9z>O%MCGn|F!z}@;xowfN8x0e*%R^_E0aYidX*PL?0^DP}$9e?{>W?tW zEBlhtL_wG>ErU1Go<^zI5f@tnQ#rE7YNr81s!RLP(m@t4jTC7+8Ukv`XJVxZ&iHzC z8(ro>dXOIP+b%`de&{itU)vZ{pf+9xuZyWvUtN(~{dp*up0`;6JR<1^yk>f#90XlA zQwQ}_pDRcyz(vcGBhglg1E+oSV4HzegQfo3H@s=^6aVmsgQvgvg~93E$`d*I=tJeK zcU^lO|MnYy;_Eg&KuFTPWZ6r8Xjc`eT>qPvRp4(tL)_DK&K2)SZ93p;QY6Pz=0H~6 zk0ra5s$(J5TTEV>35c22bsvECJ;pa#krM9i8S80zayiNvZpqY;IF>k`1acb3H+qjeh>Q{^EAB%_Tc6Y?ZX5x&u!oOH0!SYy2W!PlBNl3xFy1XvZ={G zlq_L49sj4Y4WbRRL403Y`o86IhM7DMTQ!i5{fOF8-M?B>W@oBb+93|y{ebh>d7tN` zbP5Y0N%sYoq*vAM4m$F>D(sE=NX-pAg+9|QZw z`|E)J783LZ49Dlv>|}0^LS}Xl*hhfFFv~MUwJ}grV;^-%FCEWQj?MI19j6ZI19{&> zrcO(Y&~QJu1`po$Ic~q=|1dSbT^I%Vq8>Q(Y|UYOHyisNdxo9;gCDWe-uN!|J?3D{ zU~U>1flAF$xA0h+ng!+jH~>W*X`AIiOl%{sBY2B$v#)LYNL|i(^BlinjC1`c-Lg;WgSEgF7SI2l}-4bAzw$y+JE5JYn z*rX0+TIxBY@8w)Hx0n~wdt%Y{9hpl)!AohQ%Sk=A=an2@>hO+za$M*7c(K#?W47I_ zCj;YSqh@R775#oonN~ZKt0Y~XfwozmZ>5vGwAo<-Ql((fy0lr>_J(onq5B=+$3OQ> z8%{RA`Ks%fpMEeNHX2X-=%WWW=l#wb?`XRnxEn`4{h3UFjcNv_$u(TVI&$z@F&Bh` zNjWd-a?ji9yp_s=EVZH4~qQvuVz+`TT`3$uqGiq}#nLy)ifS5N;FfbJXd!WaSb@ z!~ACyheUN}B)RCz?7N}~>)2@(oOK1SG^E%t)|qOs&{ zn3@RH#y|>)BIO5z$f*YAhx$E>Cwg+WLYa6I$nHv{|cwkPlV`Jb_m{Pk~f@H3wg zgZvqu_|ZonOaHGV{gc1`S9ayMzRsZj-I>XKtYT?bsVYoa_L37?j;rpoRvC|x-biZ<+L}e@K@e3tll;`;1d-hxFc1Xa|u%CII91%RXm!U3H-wL2?1lKzA{I zC!1$_Y>W5kc7UYpG80;L{!V40KpOu$xg6BwpwfL%40N@O%9e`b-C@^#&t#W_UI5H9 zKBa=kGIpE3f0U|7mvw}-c{lF=4m_kN@B+rOfiOrL`viYX9@mD%#Xyxs+J>b7Wm zFafQ>gSUU4+phQ+GY@B`W)5Ejpq|r9P_(^SU@J>j@68D>_&z)Phkt@&&wuX!H3piS zhS9v{&r~XtFd~7L_XYSz&G4*^vXsr(0Hn^;rl2X=ak1JDEjyJ<-MPJ7#?(zT9j601 zVR`C4GjWnc*`(!cvFT~31Xn-Ce7GK~6Y332q}}ETEUkbbq%ZY)Aq7mY1rSNivaF3? z^fOR)Xa&epxRA>Oa1L!7IbK8AK>DXF`>orhtVXBYyZ|2~#v1-u>!_i>M$g3*>9rO+ z!A3)D^`6Ta&NaX46JHJ{*93J~&)j@m+aEBTdx+tzv-i=bvuyQ>U~MM(cyVw5;pK2b zS&#;%H%7Bs4I!`EX6a!eb*J^B4y2qHCm?kIOiUUROZVcTyS~h5{sCZ#*1G+fn_cVm zYf`8_fN>Dm5ty+ZVlv2HR{$G>vAI`_b2b1E@u;GYp0U}-&cIIsJH`8JfX~E@)Cy2@ zEMrra`IvD$7wk-?DZ2q3A>=P39%$kN=j9X&?dO#4mh)FtHSX7J!0pXatq ze~FoguL718-*fNHf)?G(>}=#US;FC`zrtSii~q%*_mN*@|ECLu9rn77SD3*whx$ z4}(;`p)x9K!Q>?N6--q(%`w!l*6;+Nq($AiYo?~h`(ht1U}JU~4>p_$z)4H%os7Ve zaZ|H9)%eGfVNk`|ROxxOyUP#aZAYFw!2e#mvZ z*JUjCe+Fy@?1aOP@}KA0d`fSQieG>Z|1q)G|3xnq_!LGLwqy`PkY&m2FIR%P9ld?;XQNn zac$oK26)NZ@%li=9I1V+Q<@0%4{IoG_khEqHj2*c8FQBXZnhgWJZSJk5z5*^vs z2K4~jq^{K0@>Pi-qap0H$8qd&$SZ&rSO5!@Z?i5leqE!BwfO+<{|0`K4!{;Ljs{L6 zfYbmr4~=}AyYZ-^j~>|UCYRd^JOy|MW;?}JeZs0K z99G-y)>FDdvCoSFQdPNT@v2FYWf_FY(E2+*!>yNpjOi`kQKsgTjCJWeIl@EIIAWh8 zPirsu@W<>WKmEHLb>?Zb3782$6GeM~GH9BUohzl#61!5*Cw8WcK&|}z@@%%pb}$7?I?Y~?v_bhe?Gn^r zq3QkxT95e{`|9reU^U=bnI~)=`^{%EYu!>#S@!j-VBJL&NTG!!PcWOUg3rToK-)bhOhMcqPvhjaw z?UPsaQ-i#&V2j7T`M6^5xnd{Y_K_cH@Bh!g!v4n|8`7;g`sm|{8%vm;eyDx=_x_d} zZoP(_Mb;=o^Y7O888Hv?`nPJDC%RHR$Z=jx&UqmlC+{!vURNn#3Q2wWr~q|-Y3+1} zT;C~7*$VXlGEQ?#c{Q8ivEQt6t*+eA>m=4LV?&DxZRTh2UG`f!I_-_GXW6nnfSKM* zbkRHmErpo}M>l`%U)XftI&VwBvg3Ig!#e>=f)_K>uCC-k1R#HJGTA`CSC$u)FjPz9 zHFu4n=DXEkL1!T4eUaa&4PcK$UdghR$8JLO)VAX|K*qAL| zvAmvL&6AmrNYq=4#j-(=I-|#u>dfXtxz21fG!diEhwl75cU@@hW1|`X?$x1$+*qkCuiUm9d7bJjCBg@HD#t|L#^JfPS=WWbv~$7a&RJAM-I;}xq7U3%ZvoP&h-{D#EL!VYA|Ec zLo2d3)Ou5)$0v%r)Ta9%XuIyWmOT!AisSM{&Mx|nsd)>>cOcD&hS32 zR@^sXb|S{EBFA4yBcT>XLeudZ-z6}YhhyoZXKePdjrkou3hWo}ZvZ|I%&H4|0y;gd zYq+dW1?cxiu;)WlUkRh2WxxcBHF{8UK4!s|al{!H*eieOkNxa-e1J7;_hoJh=BEJ{q^HW03A9#Z z!k3dt-y_G8oSc}w2WYs^3_NPFEGsuBvqGVzdI{qqaIA6_kLp|0m&!B?rb0;31#!uV z@gWw?-6>Az7Udm}V`HfpogQ^ywGmLo%BWau>cpHM*3!Pp8C@A1IZA1)RWiHuKDQ^V zJ5?v6EI_N|%3>N(^vjwYgSfiO;`&*5)L(w~`kX9fWWW9n6gZ~+2XklYwran~xOJak z>H;_y$9Q$_Mbv<9ZT3@3FmYLTVI67T>-MFN;#8`0F){q842K+0;s$DJRJtw;6Dz%X zDVtZ4N%1#~uxYRv;H0NK-GAyYe!so+gKvxb@0KSpTd9wJ3_j#5fBCOm^tn&d$_az| z+J}OPvR*8f?_n zg;meoTmn2iy7BA(#-?@m*hH{4Ef&)EB#no&Ox?+H_53_cA{FG3Si^r){?zqT>)9+8Hj2i zQS_ZQ#^A@PXWlB7s@E(_UDy6=In(c-eut#LMj4teVSFlrl0974SIgo{srdNtZ7c5; zW3}VEkoPIWlwl0}587={-v6B~(cf-OJE+;^)P~2-HX6y1F_*Mo%hm0dlP|8;xV>W>UPQ#NlJt>?-s$NSOg3N%Deq1ExraAP9_i?OmQ+}BiF9J%Mj`2kT zVn|u)q`#vPtk~@Uc0c5$@ytBWqYrxx^BpEZbO4*g`exu%;Dcbh*3-#kDS07L54ku|&RX#* zj^~z`nONFBkYfiKu&j)QQvDM!n1qe@UBPYN`Z=~fc!}iH>?P=n3vitQHveC@^QXP! z&35*Ce#(w~&a;_VwuHGU7>x>$JE3Q320pznn8Jp&Tt_*xsR^M9&9I@aE|&J0fs@`# zB5^BBf!7A%7O(t5=uD+&Y zESI+uu#~zbYQV4)2=)6b!9!>Vmso^j`* zOyUj(81=g8cBr>?kzo)*qD*&uzbW*QN`k(ekVN1Ek-ID9MYZ{;gZYJiQIXF^BYRr<8x{XG#a<}G_ zOLyk-f4`97?8Cs4MIqnrCFu?3H~Gx$Ec+gPrmfg{6~lS?ZJ0Rs8{m+BBRGK-#`qa0 z=e;+*3g~wW@SKN2jv()ob5M)5=^6cy3qwAfZ!)V3m-aV)I~kWzw|1)wT`=wJX_9=x7A zulRMguK$KGH5Xg>cd=Q}D874e;M1PVi$40hcJ6zAnthI1%lu5p&Z$T5UI3G>!)!32 zwt3o$rBX z3i1N9gIZSK&6t#kdMj69-iQ`q)UJDj&82{ z{qkRANiI9erL+&F4DJPJ12Mp7ntpJAFx~D6 zIB#{mb<`#l==h)N``2N-M0FV|7|k_nciT;wT-wuP>gN-wUh>N3`V`F7e#d(GSx6bL zn5cloXvIdr+P(JWgy)}W4{hA!H(z=cFx#67_3;FY#>RWsIZG$)spmc0m)V4kGKg4+ zJ0i+-AjS2aNNlc{P#s1|a+N{_0|o=5mcumZqMcFi6WZ z8cIS-`Nl2nutY&Mi*h*ykWMaV04nG8)XD785SH)U21{41@o#_P^UO}ISJqq4+}vU9 zH<;hz^Ru(I*HO=6<*qw1oD)ifCpZ0cuo3sYWkxYf=fb)S@f|M|WrXvTXwO86V z(t9x%5(Z{k(tb+}P64zsV5RK6HUU$c?%~cWe}jkb{xr}!IO9RIc-4C9ypbgv zGqvaWy;S31+4#`wdh|6NK0Z2J&|S`_0=_C2+{$^p3z&j3Pi1FVS1w8)GxTh-eJtZh zj@5Pyjq(eo`>l{3D%e+bscO^fX5%}ieXh%zmCnUcux6UN)y&iajI5)nG_(F}oyuul zj%nal05d?$zk?6TOs(k=VASknuNb-do1X*U3Vy_%`|~5e{Y&kFAOGQCHf*MkKAtcU zte{K&_7i^Tm%d;YTa+0tKb%rQpcqCDD{?%S(r=Nhd#qP!Te?l>YOF<+5Kszg#)g-m ztuVi>J8vlEgk@nQSTfDS@j5f|+~Tvc^7?7wNQK(`JGAK1S#ptlpp2=}9cwSN| z?eOP=p1B#U&Gk24;&)u~X&Vi(HlZ`AK~ykNY-Izjl*bife;$7~py6WhV+LveP)b$GRjCQy)R-rlv!>LvVzxEQ zt{unl*k*vci=V9er7_Y`@X?rf`mE=`ry<~S+i8_-3wSQ9W zbZef@!3C`BVnyobIX<6aL7)MbjL40C|4{E_u%3>6?=u!Su%c58_y zKAsI(O1VpicKI%fv|PbUvw}tC-Li50OjKG4HTd6UEJAgx>$6UpJb>B}9(271`>g^O z5?Z_E9ekLP+{>tJe| zu;sO^SLrh>vb%ZMBNIxc{#VM_wovGMJ4p9 zZOi*walJJx3d-0n>heeSTRu<2WSr?1>%%#0`DzBIy#9Mwx$D8e^r8U*dvJ4t>FEvJ z^v!?g;d}39VhN66nLv;qg+2c6SW@N~we$z9HDNaA=K#Z#qq>)>F$e6Cu{xyVi<`KS z`jDP|awjYwr)IoqJ)Z3$o}<>ReG#kHoY?XG^#yv?c76XCCFzsEL%9DtaE}tH7BF@N z&WiS?fK34e9~|IjuYiu|fz3V+1Kt3a5Nsom9HJO{p zo9!h(^T&451+Qgt#U#_4!G}e{riS*)W5qM5nOM9|o@s4Z+{i5$z7}O2;?RcCFcY?9 zRO<^=eI&sUf?$kyL$^cUWt{NAZ%HIkJx5(HXX>7hm*WS_vc_%oueEkefFB+ zSOVhS0kRkE*DNU49Hc6qkTwKdD0AEvzX8wN(>_yRS|>D0S!xPpDl5S2A>dlU1aErR zyX-@M`mrUu9&m61H;q2}Sp2NbiQyHW{4!ttr+;HUwiK*H6S0Y^HtKXAg+ZSc6AMj1 zMx8K3z)N9%R%}Q2bgTfNDxyNi3kv2IlYYA2tGu1adMZ<0H*0oksm4v|e;Quu{xz?; z;pRElh)n9FF=OhO&(GqAJ?ok6X|H&GBBAu)=8g(w^xbpox9qk{Kf`DUZG!wIx4hmA zvO_wBddeU_6PV^;HA6xSNDY@8Z+d=~+@A{2#j9>=`b=Hjq+>C0?F!Z=%XZ$4Jr935 zuo{@#foa>kT<Y*cUrPym zyJhGpbbGomy&QNh`qb(!vhXU&TkN;mWx4<@!p*gGrd5*~&fF{3q_a z{%?Wl@$Q4Y1pV>oS7HTkWzC__XfJs0uh{cG_)EUuu}3hR#fLK}5+xzIHA{yMed-n< z$O!jJoPu6}$UTU%ZkQ8gn-0ipL?YFdayg|k30%yw_9*9M@Y4j`k*65Q4vbmSF4LCs zL}i+XGfCD92`yGIGNnpaMunI&qGmdsuFTR+I`RbO9oml^t{_x5PFFrODcIVbBeI@) zwzRQIZ6x8;bvtz^cv*pS<+{-wb*{C#E-mNUZ#_~fli>bIv-V^VbuL~X&VuC)aP1*u?D&SJ`D`OUipew z4L|Z{zs5nwoe&QO^F6rP#}gnXncnc==rjN2zxfS!T+b3}mbe4R5WDL_Q7{ut4fga{ zO>?2(X_t{*1+I3m${oEY%DVcM)h0taQKWTuq8gp|1#$sxLuYirJ?GlCG!YzQv_=?r|Nw0n-t5@#}Ow-3=dDdA1(+`hs{`$ZAhI{U?!DIr*Eq$LY zkrPyEqpGa95dedh$*mn@E4x*-1bv{|N9e1opD;o zxn^11(MKN!EaCbuUS^;F%m2z0LzX~2p;UsEb(#?|c~kQ{ih9aPkwUGCRR(y)#0@q3 z(!F43S~^Y7*WE&SQKZ*T*P*hXdd<`8yGq}UEYHtnwEpZ`-Ei_aib&@Z+u}q$0IZxk z2z5_y3DBCG#ST5~865qB^J2ngv>3+yy(B$+81A|DvUc00pYqW>v_WD|O3q9ZHm~XP z25CE(HC2_B4w}}Yj2jj=QEyH1>ld?%O$Jlyh-fDJyjD)Ov`t;ftOaXxr(N0WunT}y z9pI*Se|NjLJr-wlS=W)&1n_O}&jF4Z+bNy`JPVi$aC0Wunuh=f&_@q!eiz3o;6nk@ z0emqWx99*e>5!f)gYH1!tzc`wiU;C?x?WQ-N^=$R0@?6KW|xpWABb~$u18)66EK>e z<=&hAlJz(JDX;-p#^V?LAfr2%<_v2NImyob;IG?x@BexBKJs9OGcY%kB-DxoD77fN z5jIF5Votp6?!v;78B#NFak!L$ia4PsFw7E86#cFcsCdaMQnvtY#S=>I7qPBpMk!xU z0#NJxpDtv+LTcq~o5QkM0U8y_`&|hUPHpz04?h|T9#Z5y>|%1bxKwuxwRGQj6M|aG z?AXy<3GfNcR( zOZhq+YS6Ap8=3=CQzWGQD(f%1qz~z`PKWtVc^PXpTUi@dAfz@5Q^~7N31Xm!;2iK*2EI+Q(YokkKzdo zix%f+VfiYvXTIhYEM2`{03OhXFOuKx!=u|S`4pS(z0(GhxVqn`oSTkeDdm8eN2Re& zi|rJ~rHLqk;WBpDo4=cNCxF+SND6?GXY-36vs2YC$2;tH(0S~%*C{dK=-dBUasl(H z!e&OJ&jUAWo{jB5N;?Rc3S43~fX%hNkx&n8emBPt0O!W~O~8e~tOA?Gdmpn*11p0G zdOYN(ktVd5w2uZ&rQ(Gt5CK|}_O-M`-2z&s@`JQqEZHc?Me#l<&bN_`CUiwldmo{d$f)9Zvxoet&*Tu~^0d=PCmFfHF zhG$^Vj9kuj0BT@X(*VqK5^soOV>@}4Hkf59Q)&PZ$HexWmq~Il#c@PrskvEVN*P|d zBLdl>(^{On<`y-w&9r53$-zsIMe_?vnFf|0L~{8iEDfs5Krx;otxG+0m&e#=s+XlN;^@PGrL4RD zM*sX@{dXQ7%`jO^p0whAgD?^eDDyrG3$kWtVlCAr(r#^+3gbvaubSVG@AIPEkba;O zkS={ICc4V|QEaQu3#5H5D~~g=33nZbNLznT9qoAZj_!e*Ctg z&cp&HvnR7b5Y;n}QImkw5Xc13%p@YB%~TH-?@fN(BUrj}6?+}=8emri=eLtfx_7Mm zw$_`#&8xvbPYo2aK(T+|Hx}yH4S`Rr?Tv(bVDq~*4h7x|5J2Q-fO{$ldLcb`>IGmv zj(sukGB9yv$xksZ*~-UQ;wmWBVtdZPN$H55x21YAt5fTq0C#xswtwQ@YyOD2x%(bx zP_vF6)SLlk*z>Sc?feh_rk(TdpJlHj4q|=^=BFQ-!8D-OMk=FFbJ!%qn_7Q`DJZCB zJO&~o_kxM+fH$JADsLwplLtJiy^Z%tUgg>0J%f;W=2j%+o(+J=048ya$9u`^l#cNd zeIr7oWa^HbLV=T77ABwy^#h7krZT#XlC2R@7^G0=Dl-9!DmIJNvh#AAbulwbFie`>7$#&p0mEs8#Jt-)qyR`ZQW0 z%cic|v`=1-(!0TPm452yAwS<%ra-7aXYbDWm&561BWswh*PoLzR_klfFmxqH?0pa) z`NNM5&VJ(sX=2t`oY6-g6M&Dt`rkh3SA6};K8Oi9>U&Z->5{@_Kgh9OGavEVU`X?G z<|yC0-jk&tS$6IB+P6W-So{*v3dP^o0ug2ZZURu(7&xY?uI3B(Qz4{ z7^X6aEPqOA3-WV|br8gOJ{ZEghi>WzeYVDq~*-WSL|z&C+QV|^&gNI*_HK+Skm;CSE%z?RlX zgFbcW^l@66S|H~44cZ{FEEA{+8O)5=mg<$6rfjH&Iig3|y8!Z)Cd{X?I+Jo-8T04k>%>ZdN>8nDnudX*Zw=z)5#bL3IRItlXLc zJ$0_H3h43lFzBw#oT5J0hg5MB*K!3z(OWm5SW3}NB#WlNTK8z6aH6gIP|iOT`($3t zUFWvsu&(@cE&!wUi|!NxdThNfGlvw2EFH*|%~><0wC{jhCo{QlF0YxC26Y({t8=W$ zP)A<8iajgsRM!h-QybBjA=p;%L)PrWM}PNM+DqU2mgJ+pSfh_VmayTL+wAjy@jvXL z`7O3Y?^&G;e9cGMabJu5HPap!&{K02>qLW(X`m z>=dlcWie)XIJO@g%QE`tfz9udI2ZW-SbqTcd?e5}VAz#YQ}!u#uoc)B_(5P_@-C~A z)d*OLt{YIWEKTX})`htA3N|=^GT(eB7gVK%W7&uXlJjc2LrI#piajZ9$T%A>+~~U@)osc#g+n?rsewk7FRv))$`alTzR#*% z?ESy`)9vLSd@Im;S^6T5J_Z1zOaJjgzx0b=z+y`k#(4I#>5lI03LfUo^`%zJ>Ag(T zYt(FS*Xx=}+iRvO?u8^@`XL5}HT#=dc3wKrlk1fUB2Vv~INqhrmfWquT1(e0hma?G zoO>RV`Rp{T-eakq{5`LP<+~NE%^uv`aWTov%zAFQ_!G9}!HoFy^ zOkejTS5M_!h!ZY!?Bop~Kh)T-PXFrEPCXl0=S-4Wdqx8GmM6x1#W<*Gt~rnR98m-MmbL2R~r7f$9gPgbt0FjTNp{nUd>?)CM_q zSce)Y*Hy~cWnIhaYq#mpc=b|*f`>Jzl_vJJZ`mE&I~ac`8C#rcE5KFis=iAKdgich z>0=2lVp`3ZIxQV4tSPf`y6sxZ?y@4RqcS|Rf2pD)pQ_8>QGc(p&FaaJihEAZ16t=a zt$_!Eqv^X(thD$3{ExR+efS3fTg1%GKKfY7ruFOE=l}d4xp!(klN8Z0$)@*N**}h* z@7~dz>+e|)uiNvwZM{a-X=XgX$Ub9ynv06nUC7V#n1%wNt?p-au1|Damhx^&h4n02 zDq)zV327f}>XfB;C>X)A)w{6Q+Ls1yF}L8k zHphoQ%3~92bMzTZW@~JL?*niSuv-AY8{&2UQ04ASA3d=7B#+kv&yDq~fUg9gi2|Dn zaOU^2eLj9j=K-%l@AjrkrnVPUDneqeCPA%|lD8}~R|BBfZ}OVzBNl5gn1Ja`_j1qG zzs1J;z7Rm|1mKTRHtyRQVDu-U1bqhB#L8U`ZqI(}&)AE9^mqNh6OQxw8Ek$=5@g#W ztVc1aDwACoV0d==$lKk)vi#bK?HRZXpfkdnk-z(v^IDSJ4wK9%wk4@|Vr!BHCE}*; zNd0Dz>PmG=&P+fZ8N-0cAyYGHll``wK*7G`ai$KH$MI;9B9;&Sgl)%uJ_f_SjTI&rlWQ1^|Ur8 zv!X3c4M?8AYH6R0Gt?wd@1M0FieBFY&(Vo2H7hEv?G=mO#JEp#cc;(al04n;ylzIG z!1m-~oo_7JY{+M4uw4(>sh#w?R{%Sqz))`}bEnttB#p3F)F`Bh%U_NR9yoH+3Pl>+wmBHS)-{ zdGPaCz2<4a%$V<>FO-qcqm;1g>jW^xX!I$Z>uUzUg2i#bGvhbD6}TT*8FKUkdz`HY zHlNI~e=-c33AW~aB0=vq2dW*zwgN|n%lb;xzEzL(T8~+O6r*g4a1yU94&2)U3 z>vLiW%*||I-Sxl6LwA2XdO5-48%{4l_mBV%+3%_6+Y5f|_x;q@zm1i~j+aq8?F*9lUgq@xnzvi!uABf#$4TuJ3A!!%mFxFZ zt4rnPVAQ{b%>6Xc-a0W*O5iA1>DH{^gemK^0_~bIu@pQ^@0Ez6thEZjtIdjJMIV|} zL8AxP;dPs}EW69BM)%2QQue6^khDy9=dJs=^1b%23p_2_Fg>Tv&!z(;EpA+Tu;%)A_*0RbBs4&QIufYe`cBSuL0EiWP$|`oV)UO~f zEVA|`@51Ovz)q0I20HGm#e4H~e9Zz?8Jk?|3IjNu z2rWHZjGUL<5NR= zfT?0CgW2(2Fe@ZG*3y_ismz=V80IocI?B%}0?RmV0h~JZMIzVHTG~$OE~avdGV+Y{ zik8>yE1#_`6HGPo`7A$UB8(F$~4JWJx;vI!$78=WEZTR^c`{Rbc}70F zlxJE)N)#XU7g}4*_ZdJWx&P6Q8$^57GON>Zz|%y7dt#-g@)r9I!xLj7ss=KHEVIHo z0J&@$)D)?f$qE%c_}M)rRV*XGRz9LYGp1|Fe1reHSkX=TL2R2IBip<^8B2_x{|EPrUwT-kq46i!J)-pPwd%SAYJSeDl+v37$|* z3`!VOrn}-9Z z21#uuB&IDnAr-$A*P6su46SKQH@+pbIcT|gEg#7jF(=syLtoi;L-uow!|pNK%u+inz}*O zJ@;P?i86bMBsq^d$}q#DqRMP3 zn~{A2f}&uy*O!Ajzi7=2)xMgvf$P5dZ*E@Xh%LWcg;cx*jHMp0e>)m(#SWFTSNnuf zS+cnF_wL19M62_W)%@Sj7LZDvT1sDh)*7as3R}T;vPpmEkAJAW`XfIGVF<9e zqK`f%nclF$zWg`;le->X$C8fpB-_MTEZEx0{%##+LRzKerCZs7rU93Gej!%TVOxEh zRSCTGyE<=2Ck%^YtYr6hgzT3-cMObVJQlAhhaz|~u#9cPdCY(lUif_WJm^SZdQm-t z^r<99+;-WQxc7$3y-i@Pk#k}KC>ztsYB6y4*cZoIm*JlkYOky!Yq;J>@kfAjZ;5%V zhN8txs)pv*%*WQ!bQq0b#V-4@$03geocDU$_BSAkKHrS-aquD3ZlennXN2^8I`Ey% zz|OI4ANuHl%_rGs{Jx+m1AGyNTiV&Ea?{|1HYrKFcY)Fl%L#cxS3w}o?XW>v*{Vb)YIFR6bMCYeJ#*Hd^B)bdrS zI`zE*WKm!|lA`#oZ5i+R*&l7M{*ku=qckDB7^06p2LF$>`N@m8_%oknsJS-Pu%^Q- zs1U*wE?sqMjTBzhuLfX+eB1T6EALA=yecMgHwBdR`aTi$Dwvw>VL-Xa6LC*Y)lvHJok?Zrc5Ouob)s*Mz^a`}>0T6BHV{_v8{N7qU zYg@I0KGTh$HP~bA3t6`FQ3;%P>hOinx7od}?aJ!_m}4~hEXL*a4ETb@!N6(p8=nba zb0S>Q4+2)vM-Oa1N#cdTD`WjTz&FM_ppRWJP4}9Hx(PMsT{aYcGoOZ-wR`x zsH=7_kagV_04KnPyFSIe*ZwYZb9aUFntd0rHGK#6OQq+VShZ@ucKVxt(w_T)U$cFV zSZlLWFh3im4D-xTEVNX)Rh6k*nZz%^2F+ik2tLm0rGZg8P5}(dyDJ8!)JXyuKIOs?RE z|2Me#f_HsiY@P1G%{~?vYjZkSn;Y(7iQdz6212hzk0K|qD+9COGDzrtcTklFRr(si zO~!^vTdhv*r`HM3stnKls7=i(r*m^Krv^u<4FvNfntPE}Bu!+SX}-jUcc3ypnuo~= z22Xp%3t74ALE~AQJ-GR}MSxzT+b{V7>u|h3mI3iR zxtQ6&n)lryx8vaYos4}dFVD|5Sf#FO9l4F9zR?g??sg!1u6D z&{C>V37Uwl&<>&&go>QhU}vr?vowi)&Ej|+`s!x#w^SFTgwSYfbOnjq#} z=W1xF?HV@k_@SpfjbqP$c09X{*m2Q^vNkuYyOBFCzmU;9w274ZNzx;j%Q!bZLpaH3 zs>-(%<9T^*a;uYT8^I2(rR;fK2SQ5wt`pdogN;(v86Uy`)~tOo%T^sxvo`BkXx8Rq z0I;3W=*!?&Kz&hNpx7(G%|VP&HYOvXwZN|Q(F2=L@c4e4l~O{fQ+b57>E-68i~SVxfy2`3o^#qk+n#57sBW7d)jc>@6=oq!#i zJ+f|=;L@}n$C}LkCkc9NZ|Mi00N@PZ$RfrnN#ZK(Dq+)QW0PE0?J8R3kt}56p0+hv zPjetOn3&p8XJ(7V6)=-JTnu4SKQ&`Pmvg#R#z9{6xeFK^16EmGwyw)+%B1#L9c(Mp z7fhJ6ML&#Ud(E=Mqj=W3n%S;Fdv6ElY9U0``0LIqR`Sz4|@W{3lKw|Y1G z&~Nk-$%R>@1*xKDX39R7YlkWns^2l` zxHzW1&y{uQHmN(mm$G9_izp^PI?a__>QMHn)ZrD&zn+}y&JCOzd}J(QF@`eSS^_$g zjNJ^MpM{kxC+x&mzLaIl)&SFs#(<|c6Pg63x&4yQvGLwJZ7_*t;~&fJ=&`*u)a=L2 zqHMg1-+;AvjxfhhK4;1D?WsXjnIT^v~Jq~4$LtY2~%#W9( zZkmY3 z%`Hg=TmqNref49V0(JpjA3qR585%Whq}W!mFG)+8P)!Yh@~f%ixfltBSVDi(4MJLdjF%6V#lxO-tp;^P!Q^#+%RY6u@+#|B$C?$+ zC=aLIIo~Swq}3P#;sjhXJv$6AB!vT7wYm?x5`Oaj3ft&-c&`;@i7j1#1|Ba7=qNqk znrtsU3j|;t_nXu0rK7X-bt`b-sx|)pU;UZE3C}+_#zVtimfpvraY(=Z%a?Nb7r%r9 ztsAZxpD(k^WUT-dz2o+^P4}Gf`y2^jzgMj5G9^cMi1b{qkX9`=*I50ZYnN@1KRF98fFadiW@?s{I zA0puVV{l2|UM}kT8YH%t+)@tb52T!Z1iI$ zvI*ClBv7+E6?8N*{RkY7eQA4YPg#+;<(ock`PiIqreJ&OzAOb7G{+Mfqv!ALNup$U zLNm-QnG)r8ELETS=_w(31Oj{-ra(}c*HVE1uW;uvAeS{^L|Tz!QQj+)!oB0+%L|~0 zVnSK_n#y=dsw*}qP^%2f4hCQiMApD-=i=1i(w=K>r8+~1>94+9-l%oeV_Yx5&;+_! zCwo#@vcm9Dck&X1mSem!2D0KcJ%}qaw(B+8sFenEfT5-)g7t6C z>*Jx`roVN?SL!;d>q(i%JEAu4tIs3%$-z~fQZd7;>$s>D%nX+cq+5VZy5zCl+#I&+ z?koJnSHA>U-R&;jGdCZ1*5=I2gQMFn`m}Fezrh9*kpG5Z+GBtxHKJkAR2FWcxX6GZ z`MDs}VDg-RY3|OX5=-VqO$IHg9;i%POLnL{w`qC#VULEeYR@Cs^N>h^$B;3x1B`@p z-G!Zd8$S9h*c^r7EEo$Er-ib1ODIb=g*oy8;gY_DKAvE}W*<)jejwIw2^soqEis39 zEtho6RMh+WY{MbRvQj9eiaNgrY8_kB(S-)qoMl5?v&dEP`Er{}G+vE-Wcd`$PnHZz^=)ywT8{nmv2%`gF13s5K4 z>-PnVQ;t^7(WNtop8)CZrg zu;RTgE}vh?yp+DSE@L7+@7l1TtjiQ&l@tXXj7zKfTz@Cj7_83sSUu1)&LOyim8xxv z0Y_n?hrcj!&{Lio;HJ|@A3OeeYB2oHC%@^JfBDOLt?yP0j7tNe z`((2fb6#Z|1xsBX4ZOpoN4HhiaU&lv9-T0$KZh0fui7WFQXWXZ)5XiRFFxizh2-AE zlGZ2ZYLD@sIHtP~VFZ5cbI)eKV~zo477ZxagPR5zcV2S|>#n<))-W49k`q56^+tf( z4q%ug>9=A(*+^8&5c^!8y8wg;5gW5a-O0x#_Nc{beX&uwNo@kF0|~j&w*mjxL}+sP zLGm5;MP(jT#{igTH2OO3SL;K@0vie~2hIs6^sT{g-4O2&2KJ?oCm68Vf2QvR_DqIB z>wqS1=q~H7K&LS7)&Oq=_N{ei)Cd3+fTIe z9sk1m8~-$BE|%#Na!@i7lPL z;s#lxP#MIGI(WpXqh%m5gX)Gwdj<-O<5-ljB1deLX<&&(8Z~1XKvx$-z^tXZz_MWw zmS^EpeTK>6?m*14Vo|0A%MqeJ$+<%u6UVu*9ut!~_D7h01Z56A*F1Gn4q<<1I8CT}L)Ke&FK~2@hUpEb)$^3f3YV|sgIMxKi zsq%3*8MCwuR#}{X%9Sp(cAp<&dmp}Ed+H0%R>oToZtn2&Si%*9G5s;*)%3btU1n_gZD(!X0$d0-%1MVcf&K!- zGl3HV0GZSBc+ z?gxLvPyU{_vSh_1vs=JN`FjIRb+2i+)fwc0l=>j0HgK77jLI?t(@V=^m-k}46Qc-+ z>_nbE49D|KWzJWV+e%DLvsAZU5;I6)*-!{PiA7vcAy1(A3g!kvNP>R4$jpLdZfvjD#fmSmHUKqfrI{Hr5JT{>3XW4$mv($HL^bxu)S zH@4U|1fK>w|BQ3y-}_rX#j?Hj05;P{A3Oe;%7#~d^6P%prQgJ2i-y(I#ZD6+eJyfY z=J0XtwL(2X9qLC?r#UYa4b_B@3oxsObYochUfeI7dZJ7}UYzb&@zrUD4w5`gA`PZZW>4{Y`^3A_hb5iH9K zfd>Jr*_ya4`lB4i58@=?^&P)uwfU9V87WgFmyx76;&84xKcsAnb(9G@fGr!Y=bjsW zhv_X>151nVoG(%dx<7%X=OYe2>819<5B(lToqeuj*l-pjZpvwP8Bq45(!X>)f#b-w z!tlqMAauEW0zY$~%*6FN%GBE9N6sq`1jy%<+X3^~ZkC*TwQN)&QuW*iLrsmqizgA6 z&&D$o6j#Z7w?T>}aEsD-r4EyNU5-(IrBrt*h3zmeunuD&D?v_at6~Y3lIj$-Gr5H3 zBGjFa;;LlTdo5OgTiw;x%+Y+_Meak5GFRDnFmf#5t5Rc&ZRNwF%CSq(P|rQRR1WF| zIHnKZ?!|47V*Fq9-;25nutB?9Y?I$w2^yz7aGFQfMe12FqGDUke6E;K3aFx)J~V3A z;?ArhMJ`m6@*d^t&!PrQT)`$;PPJ4v9q;`o}NKWDVz4iBGUDEPud5`0e$KL z?z!%F*z&-a<6<&+0!h$$02%?Web>*!9eg> z&u)HAL2UVM;rd-8}&GJm;BR(cI{Q)@`-eRi0G80dtH9)s}AeO zo8Z-t51q<_;~T%e=`z}@lu z3=v=AOj^jwwHP-*YngzNbL+=*lsxA|8wns4`FO*NMBCO>aoKAB3^fLJ%}GH5dWW!V z<#N^>_TrFM&+6r2I~xhr`*gkg?>xn5_<7uJ`Tytpv4z6eo*Pc+TViaoDN+j_0vyoe zaElq(>|=M}hhqJ1;A=^0FfRMk`A1Xu`g1MR|EeFO&lq zOu+o?H22@~Cv05z$vCG;wny}NH7&khn^>{Sq3x`9{M_jDANUA6?YT2EQv@`JdzL)Z zgJ>(I2b2hi6;tW%UNAtl-Z(zhlfOe=piizyfEiAgMRsl>gNr$5pW#ZMO9{Qrn#k9w z<*DMT?jA>B`2ir+8%~OOkdw-0`IFhUG27^n!RjSIL8uDsQihgS^-@O#plT?1>tc$p z`!$q(Ru%lskXdf;c-ZtYb=8jOW!RW@-N%3KWjX?ra;`bk1i+T#l*wpXw^K)% zpRyyTYq77Cj~4<3AJ5!T$$y>7LCIB8wshOCn(Sf-yA(C*WAopt0-GI;P8O`!UC{lQ z0QuUNx}BQci2|Aq6u*13LaHuh)v?)TfSs7&?H_&L;LO**JjPCQ?6~Nok4e^De~VrG z@z1dp7<5da>5r)UI#K1f9viMJ-II9TW`6Z`PGbBx#XZ+qFBP@&O}~S&Xezndw?miMIdX7d&HiVxdd*V> z*c=-R0B+X%#@Fxp?+jcAqc1`$lhiL@93HIA5ip-*=?8|9&~EgxNP*2h-T<5&>t6wG zPliF7V^bH;OOl|U3cQ9KX0eFPs9F7^tY>JTi78O4XKpYP#%5j@!=Yemf;;PP`)lsM z{cnI-F$-EK3A*=rHN#j6wzAjZ&$btS*~h2wEx%Zx}Y{)Q@B$QO5I zXBr9s8q_m^7^?A%o42we4czk0+mrl4={?CgP}_CsZ`z*|y5|{8OYZ9)pNUz##`fHv zdF+?jQAmYE&J$W07$0>AYFm9G0aSD$Lq4)fTnCK%f;8YDnDk7iFJU+6+=(?M~SYDQA`JF!qx8Baj#7O;Jm?aT*%{ig>f zJpUXbB@2D@vEy>~&G5~C{es=T?nWkRc4d7ZQ#F9>_fBxLp3so?yeen)1dn1kH9Nho zubv#$_KG~6`8wyK2Iydxr~afx?m3>*sT7KeRF~%3lyQ_SCQ2l54A0|9z~)A<*CBh4 zp8BHm0$>^T;O3$^k4c!`FuL`kPqTUbdYf1p&nlU@84~n({>Y$ZR>J9Xh&5qvX2Vut zhQ^Mhq7x;XIPVGJL{f4!C5V8@;G`9 z_NkyQzaH2%k8p5LG`lhpumDXItj)@zwloS#^~AoiJW*}{01w^saqhqMPhoa_{CHXX z67(lzOaTLqIQ@0@ybt{jYfn9e(L4-=tYVIdi-gN}qMXilS0-ibs&i%5-!YxROz*MS zl-P_;{hiIn8dz?-Nh0mcJ~d%QCS=4sfv^#d;bkH#$2Es$gbAQq8-5rjGz7yc7w>{y z)xlyz!JsjT^j+)IP`P;#Ua$?jat|_|apHA;PmNl#>S{7lI2{h|r59sSw$6WA zhmXlu<^no1t}Qv=)=|A|sLdH<+Zbnf^I9H=0%ryA*WIr=34_vw!!q(I+KK4s`hROuX znx;X}lm{uh^f7xL=n2`A8D&6=5ko2 zZV{D|H3M8&vqP8wKkoVGvdf+a0<((-6zs!*0ry^ex!-fmMfuBsmr2MqEml^u2{;MJ zs{oEd;xHn~0W zP|3pIVS8!?;At%nN))&h=4PU(D|-`5+hkuG{J&-M{a@wY>wcH{soR37X$uT$`XZH} z`{T#fjC`6)m+sn5e(gu>-1q(}dmXvfXSZUb`2c$?06&>Mj8}65=MhFD)C}MP=(d(w zl1aiH;btIt3Wfv5f$mJC6fvI>*|nfj~VT>8MTpovIET^|N&H}#S&As~!XxTdPHO9pbig9%#T z-sy5B+iR1U^0HUeE6&s9dws1Q7F(T#1Mg8xNx^Vc&|Pp` zZQFIf{w&9{QeFFr^aDyIkoL`z%-l<0x{x~4?HsQRPFK8G0psF3rG0SAyK~5IUx8uG zA6c7%Xqoai=H!0X=LWT`(~Iwm3)q47v0`DH0;SSM-ba-iP|cV0{B?dd%1wctdi2vq z@A|bLW#^su+_6sSee`CcQ=9DT|MFSx-*O+5fOn`8G)ji1tV?wHfoPuQ+SOdzlzW~R z6BO=%OPzABsLYkC`+@eyWiv$|y_T@+354cXADQhn0QqMWpeI8i* zjHk52&pM5;LF>WI9r&!J=3le34{-Zs7y9((Ih&Y#d=H1p_=MfM*9$ZEO7Iw}jF3K|zk2q>n`cZ1(Y# zF!uqt0=O!fxeQAe^zI+t6mYys(4lkoMx8ziB%whYWXW*67XXw(Vos8yE0Z&Wno}FD z<-Y5GkC`ps4p6i85{Cuv(-7Fiiro+6jJN-SKkE(eW%({EnAwcsDxuEIKyZ=OBx!bu zUa50Tyt*O_P0<@y3SnYnrtc75vVvW7oN+#wq*VwoQ`iSlUuIw$m}hrEi+u*&rAsgiI#KdarjtL;$d;4~^3dhvIt%qP4y z55nqpHN3NoFd0=+ETCpY4Jb<0Iu0H0j9-A7mbST+@xrCPW;~YcL?uF0OzXVOy)qBW z4(f`16u`9tx;6V*zMr)NyrqhC@?$(xy8!aN09k7`S($6tDucB-@EPDG&wok#-k*IJ zuxtmK3H8xGUrh{e_|oNm)i=HwBqs&-G{!3hobK=r#`}LTAE#I8_lj#J%6zO$-dypO zIw!PybjQ)=Oifq~vitl`(AIVa3vcpYX!-!bE6x zQ9bMQzgy?7Yc8?}Z@)G_H*0PMPqJ^hmkV%jxI1K1sm%1uU)p9^R(7>0ThCNx5=QJN zl?N-+h9y=(D_zj#2k5ddfXy}mdmQpSCMWmTe6c%LlHOfLa&2CTkG_akY}EzNwfXdT zhM$YiYfG>-*8+Rd$07kX`*=IBZ&0zn1Z;@yBUu=47{m;)IzY{R%MrcYu_fxM+g2pT zQVLM3=vDmxUDP1~o)a)Py`KAT{sT5Y^wkjEwEl*?&=C~&H3vPz&imotuoGVVYT5wi zXH+IlxboqWT-wMpjsRY3h14=zHN2Xjs0phc<(bJtu{3SP**F-9yP_;DenHD&S@ zKw9pv)`KwH9Q{aZAS1S`QBo;!c4bX!sG*3LprNuY$A?$tWSe)nw+mP|-WaKFMnlQf zwONfuVhMHwxD@#~b9k3YjD9a_f3Lc}+-`L%DeF0Lpni=cehFEp|B(Ty2;1obWh#IATflso#1Vz7xV)=Ll9VaI zj5+WnU~hQm+uDnN__gUF;_;3?`j}+X1NYfC{^hf_VKn6v0NXAz*Zt$m)g$kEVrsmJ zUT3(nrpFg|xek}jST(Vhj;$0N)nuo4<$jj?M8W(lCVJ|y4zskBhuz61Kg1mD@MoVo zvF}rkdUU{M&)nReX(ZTi=Z$vfm0w{r!kfkBls8qV*9MrGFn2Z2fBwFiqVrkZhNWX% zW+J_q9C1`K5!=O?9aE~Z3^1aM0;qAkq-+|(PJ5ofE(e^R{6rS>cd*K}xtY=MQ{eZ@ zQ;-f;79#KRbAUBLU>hby$)3U5TuvW57})INWZ-qN{&nCQm7rI7Hf7zDbNVcBUMvx* zLVrWvsM!B5w5xy+O65O7T<;v=Mt0Hy_zo1#9= zf9f4>w53r^1-iHH)Cls>Dl+pz&Rnr5H76wnQ>W@feqW`p7Uy?2{jC)SVR}4qoPI}S z$sl(9+fMbU(4#UL()0nvy0AjU9H{`4OD43|mHL|Ymj-3Bovq+&CRW%F|MW)&Pd)!k zVCxPt6Y8UX#u|;T{M6UE;X79_0koP8KQ@ht7v-wOi!$Y?vTj?=#l{=q$#1gCOIhXb zmGMGla_1E@G>@UAoM&Ivrc8Fp%%$TYQR8}b-PP0?Qg4|a1`}h-*gxm6`$2n+jy?Ab zp!L_MMFnn709!`4U3Q^wy8i(iEWzTL*AhV_OTbk+?q>3v62njvW^Y!SIRT)8%kvS^ zrri9aEIBs=t~dDB3Wq@lYYK9zEIri|4(XH22JCg%i(ttfH9(Iqv_rbSf0XMEv;a3R zXXIb1^JTG+aZKdeoR4K1co0|>lJtG(qX#y3@MrhKk^FUY0Gm?)3Dop@fdp_8uUmmb zfY(;J7DT67JRp{cgp3NR1b!k{*ZrpK%?xS|pc!nq>wog_?SB*Juw+NyoSuZB<`!U* zqtALH=f3+_ZQtXLW;g>r1Z%-&tP=h-Fz`AFw9HJ$n>;Wp@>@m_2g*Zgm6VX^TaAvy zA}-~gZ_s!`S`0F98vA5+)5M?%OYEPhCowaVjJ!wyAFn98G;On}-%8cBNaG6vE0SZg zkZaSGn=rO_nsOH)gBN841d{!N|9K61;a#TW1z4i{z1y(Ik+4FlTea!hP8TDle&2m! z`Vd<8&FVHwmY^35OQGz=bMI00Hk{25VZ2THe~t{Hm`vHIr8R zS+cEkLMMNA9;1=NcH4({f9#{|d)Se&u>YRKKo^6fq`7F>)*{bM#r(O zE{E0Iy?cKV^>L;OfiX-|^QtLzNH3$Fm@|Nafo}D6w5r^7-75ux)>p7nE15l!qum`} z0(R`VXR&1UKEPbh+FUeYK;!=FuVmeImxMX4+@lP4nUKpsr7|@WaRLkS2H8oSSl8Lk zL|hSbp~_LyEZ3_))QUlnUvqRwRWx_!F8iIzE_*yPfKA^4;HK^yUruvv+UWDZL-P5H zY-T}lqcefsl0*9DNSSkRur^oF#|{EE`#2A{AlAPM+>+RuBUxP6B`ww*usrHJl88b& zE=)};Tn=h;pa8DYwzSVJwtLE@84I}%VTTR|u;szac;J>lVs367uzUyKfc;5!V;=#V z{+~(E>psHSKm5zK+x~kqyA>Y}@sw)7;%{VtwInwu)=T#lt8=Qzjmtrt`dSn-a7)MN z47KIs)O081)KsfVFe?C36Nkatd0fsZCDKmyIqFInyJ(r|i6!={XFxT5j?reA6cO(m zZgHH0i(I>68tN${i{|h%mDy@}N@nNy@l08tutk-{DYAE0#;5d0&)xIB4hCe&Xsgbx zlE|u2kuH?1m-@Z39c6bHFzVLPP6=r0=h7_$HbKd)DXX&vnUtNIk5TrdH|e(=Te2oA zIbiYq*Z#Q6v2srCU}f8qr&is;k+x*JySUZ6w5_QkKvUa1&_t4L2mtA zV?o%Vm63;;l%x3EWt+)oh_b2*L#iTkNS8TlJ;`FV*^sNqpvoaT1%BoUrw-owiyvgg zidDcC9^dGrj|pJfF8=rzxqHK1HmUdc4mRXiW`D>1!^hW4l`^BkL&`cjCbCdfN`woW z+iI1F?jL)dDE8s94>2oi#W}k4r^1=Ef5kpWLCvC492>&ukY}AZIQ-+FbOkT?&Q8({*dV{*953(6tSQZ^e6uf)sy+uW>)TU za69b>f6-6*-gmQX^%7>MfDr*0rXwoL?9SP@VwyWU?4_ldROdSTM+$i>xrL%Bw0Wf( z)JdE%&GQlt?{yf473?_$5sXYabq73-RT&BKVwTupj;C|*l6FurIlHwIwIPSFm5PTM zuZ~aU%Km8kUaVUwWs?o{c6HV+4-+5;#>ns(^S=AxPoqF&y2~l(sFHoH$CPkC#u&ot z++`)GY8^nW)=>cFwexr75^mkbQeJ;gs2@DXn=&Z?j`XLSVW=I`%Vf>4p_K3EW3(=j zfJ>SBx1wNmZG>zTpSKk`W$U^-!{s_ug8*sKG!OMPO8cu(=LYR|)2~C^+O4RY`S^TZ z{_5{(FL?Xw(nRv(6@Bz!z~u0ji?8vkzi|-&ZG7S+E8ld0m6cK6qcD9lX|H0t*T)x% z5Cu*3{#Ujo_t`3UWeKh-VBFmoDw(_0gK@0$UM7lOsXME5l)*O-?6S)WKkj*F0!wzx zwW$X;>j-Z3T~~e6@4xLDw*l5#1~*g7O~=wuGY!%hSVp>vRv@sd@s1!*C!)p#Wlbv=y7MR{q`7<8_gL49S02^HhzC|Qbv0@8(KR5%}HRalT zI7Tang^|!sJkHSrn|-`E7J#n+w*yUbYkCJ`GcQ}hDCqUTYH}D#+YriDgH}_puxf@y zo=n@I$fudF>9us7HUY!AY3{$}zp&}v&j!Fdu^m87zDx6J&H$U(?ZA`l?DzcU=xHy$ zz}oMaSu zTT6yJQJsSGfV%@N%2}R4jeaGjrg_v8ZJyCN;$Nn^%nWB#N5NZkowllirV#B>PNE{)U3doof+X(n+jIB zv@;e6?O^j2QakM@;{ZT4Yts5%+OZDc$HA+yrMQi&iA#B3(Y&oLY(4?)^5G?0QNKUR ztZ`++R7xpjycEZYQIJdCR?q!y^1UtkmBUP4g%xU^8H1^voX@t()8?@t1Pe`{(7|3+ z#w3h+xK4d?gu&Wzd|?7se&o#(^x^6S| zAn9hGS~baAU@(p_Kr6<$OSj}&=pKvIN$zuQU)lO-9%X5^9KWdi#sR30<#wTlmtO0k;M11VNrL^ z_wQIq>hO4e)103kWpko^QGa?xxY0@S0`jCAHuSoc4yZE&I&wWv;fcPuJ0E} zlJ0e`O<**-6d!#DL}KF(ET|;?Sjn|H3v2{d0{aIhWIRsM1Dky;2i_Gx-fh6eG0Qee zGITF;Y*O%n=A)jM0wkErUX5mdh9nTB;+C8BBly8}9fA9$fd2 z=^Xrtf3saQpyn(G9QS;C?gxI`k2vEwHk`-i=KzE8o`U2XvS>)biXiS0eefTJOq_>f+y(+tK{1uD5{#1g-w2CVi*F zMO=YT6qMAwt+fe_b&Wg>QwN*{w~RTmEWi1y<%E<0aPn6>C~TXeVxI&b92__Q`II3k9?aPy6fJ&=EsVGfznbm>n5? zsEN=Wmw%Z}_pPH%;PC}=3e>)}q)-cjN8A`q&3^>&v`8hEeFbtFEeA~76i0NAcc!jb zQLhykf?3|ywCei0Xz^(yq?!w~~J+Rrw3&OJBfiD2}0jPw!DjaDwTmGIC4xsHsoR6Y2%gEb2~ZK^!jzKk?bQ zhX*^ENoj>sZ^~zr`{LQ1y>JG0k)n%Hkg^Xb9gfp}#fJ-JO6frEV1*313bR6@Tey{W z&a>!uuT`v%+Qryf0d`iPN_Xhzqy5s*vI=_XzOr5${}8A~HMK;$%OFZk5M-nF+d6Wa zD#KA9jH|Nl9l)~F8J?Ef#7YOq-MJpMj915+O2Z4cUauX!$-t!os(D>A0_0uFCD}U7(75F7TzU6^wGy8cU^UhU-8+mFb5^LS^I%dtGEOptU*VO@`vPI=^_fy4i`sq z4ehQrS*av)Xx;g^rq}zb&4_y9S0}DC?MSy`q@Fw}`xY-EkC)GO9#}pwf68;u3Q%Ld ze=b^7tj)%~H($xRYcFv#%mz8XC6EkECJp8}-O#@2_g;l7*yfcfd0!pW;W3VFCMU~Wx+lCU*50ZVx53*KdC zz4Mn@bKpKcvla7Uy4SSiibwp7fIO=gx@Mh;i(}KaLN9BwJ^lT|xCfG}ILY=!90DxG-EnnqH}Gf?qJF@Ob5x_FoO{!(WqAiq zlm(THWRO*fu1UVHET<|TUxz7&GB1^>Sh3>b;L4apacVD|Ky^PR3{rVDX-87l2m?+C z=3dKSw>@WAw>+=J?+poIMJm>BX}g4VIHSAO&ad^jv-`rS^6E;i>&1g)l}FL?!&0zQJ{JYyQzR3wqFxtCxpx732BxgbHqMD%5z(4q zr00Ma3?)~$a&5Pp?W*ev6np6_r!1x-4_(Lg#48tcWeRuaK2=6lL;(b=VcQ(|5d4BS zet&z>J71M#V8-^3KKd8{TkTt)`3m=My`PDitzC|gHH(lgEgh#ZRxKbC1l2uXt0{y+ z<)ZshPm(%)jn!j_dLkp2jm4};Wl}k%lNMJ8^Hhfy{jj7~H8oF^a%zN_i6!nZ0**NI zSrZ37?MPr|2LprNgPUq1wD~^2^^(uo%;p&;vinyMH}dx*r@V5*NU6ERu+*}A94C}> zc>YmSJX1M17TXdh3BD8FhJr6!VazxHHG}KxpN@@RZM1I z3wIFL^rs5!iF0#=KGbW}fQtZDRIH}LNxhU#$D)De-jp`Vm0c?Goq@R8CVL%(+aLLtv z{S{Zz0IR>_6(BgCC^Y^aHD2;wZmQEjIO9X)+jZ0|_Oc^&-*vsygT?E|D+NodaZDLL z22A$Cp3vUXML7;@A`U@sZO$9jP z9ps#{p-c-k8Hy$XhA3&`E%9Kru3lLPc(-f?tc35vR#;!mfVfZPF#0o&$ zIt+}glu8x`Jyw92(ucCYYPeMcT443(=g9U5^xWij=whT)o_h_#Vm0%r1`rDnRY1Xl zL@&(dx@}BY;+{W8Sr9fkRxg(OEM-k6D{|Xv;GsX+q79HXb)T%$DW#8o$RllNBFF763nU;UZyhgrZ?y~ zE~l>w1({qJOwEGH2BwC!)Xxm8T1($y88}$02OHE>ZAK$lzSA!3cF?)%^8XkC%ew5N zQ;7QbysE>i@!>b2%*`a{|Cr-!VDIFRzA+S>y9cn6EHVjOY|V!WMqaNW~?||BvN0^y1yJ&f!DReR!q{hDPB#D**TLW`X67vL&x;`UV4ZPL43&$}o zYO{~Z5xNA4>f_8h2Ibz}ADWn)xL#_yMhe~Frq?XRn!%@0=kEsBcDnmOEvqd7Fb(T! zTJnol=js*X#LIT-P_l9zI!6)5)ep6vmI@s;O+Db!v~`>E)cw!Rs02`swVD*+T74xw z?_lP1=4iBn=%mufk{YWZrnFs@_YT&Pjm=+Le12XLN0go2je%(Wl%)L#D1*8}Zw%xl+2FGnBRl^0&bUF&aWqGI_=Sm&nt zm`Ax^ue06-a5CnetIYIq{gV9P)UP$GHAgF$;nV^*w=PDes9ba`SEksJdc01TVJ71{ zk3Jo8@`)1%9(F_ko6cg1p0zmvY~`+Rf1NE4ZD61Ya)pE;11ML6%nT;d0uT)lGJP=< zs97*Ha~Z?k>O7FCZU9XE5Xj)Hs`UiLR|cmJ$VOldc0b^3makq5%sxQ~NG^Zthw;&c z;2R*j!^?Ru9BcDLaY%nK$YTcvYqPPy(F2=(>;t?L0PG?dT@6@bYz_tBq+o0kWoCi1 z!V#;ck1KVH@=mTfFcbUI;rdiQT}^!YD#9Oh?JB51>ug$Qwj5?O;8W@_4_iR;o*%f5>oB2is3 z#BsT?dY%b%FvR(f+??Un_uV@vah|343ZjCwM;Mx(`YAGTW&Xr53J_G(r>G;ndX{-u z3`$xC07-RA-X{mIet7{yUpUMUD<}$GFK?rw%VS4_Aa2Jr^|51`B`ODQ@LteAy<~;YV)3&^@rqg zL@x!(5-xJTSp_zE4f-QXB|HFO+c>z_=cTfBD-C#RGa#4CpJ~oF{abnE1YhLs)RYg> z-x7Q*^NQAnNO)?;3xl$Paa-nq)8U1dmwtMgBUSVLCWDbWdy2BnvApPWlNTVWX>L5d z?bQIX%>XMf-u&So8a(yc8R*-joUle6 z&f8Gd4HKSY(R^)3kG|6O?Elw zdGOu$-D7mbb52R*haDPyzD@bIueZM)BhylSGW0i)3+4E-`4I2XBd7UH{gIZB8fb=>T92ee}TQc3^8h71#v+ z#h?n)!Pcx@(P1hO_zQrE@;6v%z4Ym=>D^l8>zd?OU#mrPb2b!QyI>{{9Kl6r-5GskyYogl+@T0(=aNKr$nV1 zWg{K1OgFQJCGfJ$!z#B2SBbo3H}RBbQ$fyXzhD(BL#oig8ZIbcoCl6axdaMlS-YAB zVd`8cj-d_9j99EpiR%auPyjquGtatn<&~^3+2(c8?zF3#?=yu0Q3c>rkz>b7;H}Pu zr3NcT6_N@Fjk+yGjPnGytD}3WKS%DTZbMClw11}Hciqoz(bQPCTu@n&3gnf*n=<{Cv@Y+9`k^l4#fiEV%vR*q*rczN&0UkNptKcHRrv%Jz>w`j}+q{`G#v7rw?OW__Y&w%6CxyiX18y7KQzS?aVW)Pk^W z3@KlwTj?H)l=($nj@MVc|CaT4$@h`#N-kPl&)n*~ojReG_m_Fo_3tqcOn@JC_USBJ zwmUGlsKCKKCfWM%-R;hAe~tNB7))ez8z-j$1503`8Cm{KY{zlDGyOvXIUPw&7Vjex z*&>c_8Sqd0TB?WWO=fk9W4qpjs|5EZPKT3A+y9fJFIh8Qj{ca!9}@=Aoon-cYhNg@~g<5j>lin-2pkfwjQC3z=)P2R8fI3wR3v*d@R%={7Vh@@aatMEM51063O9 z056|}uJ(!b#p-6^WI;u3Ba>VIEzcZ|++W{sh zlSO%tHqE5|1k~!e%32&R1A^#(u5&b6raQXYE}dt)CG)~0 z5vE0H_LPBslR9#EAz8+?JGJ~x*OBs_k@F&Y0rFKqt#unpcx_UJQRjgznUd7sDZFOr zb$`e7VY1U-s>7s79D>WQPj_xMZB)Zu+p3wFdT2E?sKHBRsuy5!SGs`0`Mn!#t>opJ z|FsUUgev3GSy%@H*QHMi-Ved%p`G{a^V=)l`8|L?PGCYG{d3oF^qntW!X0-r6e+IOXH6II4`GfZ`SqoK9~P`#$Ia%^?p=F~<- z+7H>UuJbkm)}Hco_C4;XMRzUgS(_8U%;>JGzG0gmSjS*8=i4uyX#kU4m~Q$EQA}EA zq6Jz0j6=?s85|VCSV(@rWjH1VMoKaPhr-N=TE0`ut#H_N-;>#O_Y;5_VQp@ABcTPT zs{unsqpyR12Xr>IEi}9^37i6~0;c2h+8XP7EHrDg2R8foKHwN&Bly>VDb1}pF2`mv z3_2co*%(fhJn1SWN?4WgN|U^p7VkaErtM-56#G({7LMr~?)gU^T=zc$l${(u>+!fG zs`e*n0_`clIqIx8a?TI^y6t)BLCkIiA7;~SkjMQqbHtaL-A;O&rZTKmx>2!{fC8E}=GhDH#LG#3&RZUK_dK2)L@IGKisy*AAa! ze=t_C4V`*_>i{$B2a(Qwy5H$KrW^EhZLa{bR8A+SDQ${`Rt*o-0EV*t+Kfk~!20my zsg0s8tH7(0tX;^!D??2RgBaN+0BQZ*ufREgrVp((C}$#Tcfd{d5yup!TBTWp34mQN zTa^`*m+JTG(!MZ(1>6)#V`chP=c~l61{_V8khRNtVQMDlqRdzQ?o|2rJRj#(PSDgh z{d`L!SCQ$d;7$(&w1A4#MG_%Z;R%Co_|g8^yjy~$E2 z2Q+F*VfDUvEYYwctxA*nOik-zslY@;AS7+M>zJgFuvhGE6O%NeF1?n@T()a^3>RZI zQr_{jPoCl=r+4a)$kAD|_a5ztb4~@?B63IXCFx+m1nY0Q*6+FI(noS-HoT>04)gRJ zl?+$Y^Nc))OF6?y5^)D7EAtH8FrqzgiS*HMT57|v)P`qJ6EGUCYP_7+Q|Qw&aLM?C z{76TzboFZ19CRMA^fBbx^aVIh*Xv_yu<;H?qc33QnG^zzX2yz}~gCq|l!RxKxeE3))XUuy#(Tcmh!{ zivTvK9=d{uZvS(bT@Nf4N2(ZW{49nt0kENhUl2s-F5_00NAfwbX7LUw%Hw%%TYp z*rI&yOC0YaWfb~=WoJV2wwl49Z(YDV^b93 zn$cRbkhC5buoUpxID^`Ww_twfdMfZ)_o2VrF(zVOe{T?QQ~}tMo$5tD^14@2+xk0d z)8I$#alr6RAAKjwcG&}%V*5rPeM~YnwUO_9Fa z05yRXYK^E)fOJUky>3UX0LnHp|UGXE%LP~z(TSK$a$v*dxt?{@HWShniW1vbO-?R>l^hVGD&e}$3X zRA_y4VDwmHXW&@@sLlZMfgNp*eFp-&(?<_%KF0Xo$bIlIaB=!^)@;oJ>`ch}>A-nZ zVOFdw4aT4)(;pL-CfOWFSeog*lut{%|9{Th_w&FVf5gm|?*Pk-M@S7{grKG`62qV^ zz_NDY%in9Kzxk(a=r!HcbtrPHIY&av(Qa)pdfDc)U+VEDP=IwEBcy@z&zg! zEv=L5O~;F*!Vz2{TsR-Cf!)m6t^wsrxlUyu%30tN^pMoSGLY`!^q78F?w&Gp`SUd9W9p z|DyJiw_T9NY<={xU7x*1SAXSlZomB|26BI?S?wiQS*Dqw1B|3@0}2+X9PiSGY^!}v zE5ooNH?J2tL)|(ihboY=K6Pc1=k2-f0vwex%BGjocDc{W{i^u86=S~%U z8)5#!|386Dw?C#h6*!DA5sGC~fSvmT2gG_Gj|$lA0o}o zdMxwN#?dPbtn0~N8Jg(+1d0}5Xqy1{5f9z@*KEG;b3luwzfnHA*bJ=XnHPL$bkgfS z=*xDRWNsSZ5s;1q@?mMVjTDxo2;dbPQ^LuJnPGyUc)TycPm4C)D!Nx;pcC~+WFsOM zAkz(zu_uReZ(=54P}Q595SUpG_t!E@8H;^Q8sv~2l4mX2duH<+oR$7opX`d&r_O1gka)g4vO zYkWRLIkW&i>pB!1%KfUpuip8rE1;=@`P7lxtPOs=kUx9z**=D+6tlVj3jRy`Hts8{ z#zvmDX}RLnyZUL}Y3sEA+TXgJG1m!YJGC*OhxTLJGhTHXgt!R0#`{0b!*~5%$fuV8Y%jLvBF(G0P*nGgEM2-AC%^tjIq7@e z&61S^o1M-#9z5xeJ^kIX4BJW4=h$Y}ggxl$e2>ZB+w1Qf2>Ve&QWlWfRM0)=j*;A% z7@iD|G+A{lG6`tP_)PVBGWN0DpE&Q#+yvaCt~9%u%#95FoWR_0G_NRFAwM=T?6D@m zffp{nCF@X_RaSvRX+5{Ca~q`#bO-Yyx1qpLmA9`UA$hB6W?G&1%R7t=khXMxx9qOd zNxI5$stiD@s?ai~z?@3kHju0j^Pi<-& ztt;(|Z8c!157kH?9n4eRdGbc;bYz=Vw~5+yA5^H4)@8e^(|>M5x3!w33I%(63V7=N zhx_-w|IM&+Rj{Ru?Gt_UF~RhP4P2Sz==J@eycv0w>Y@wKukV%J0Hq$MK%m#DbhO>^ z=cHqc8Z@l16E7!!i+h2j>%bEuQ-I1^y--iGsG40|qd>8vGmj zxq*xPg@uSyfP(^a3Oxy1qxRhc+??P)7(KAr$3DQDV*Sg&ZQX3mPQ#!hftRB(J`r6) zIVgZhz`CCNED-{v66mt$!InA&(P58eJJ%+1{`5_A^31YN>+FsQkirAzl}r+nW} z*)v}GHXAI#=BA?JEKg`)mLI0^j9d{n$OO#k+`J*E2guXD+<+>?%M35&2MX#n$#-e# zcnFX%RjaP!WD_EBXI3j*0m9^bEd!CtI;CMP_Q(0VlS9rG49Vwdj%7eu9*#BKHSbfw zfGWX=REJ8CT_myS@imB4=erZL4=(`8G3k0;I;>!r0vZ*tWL6)qY(9M&8OQpdONOV6 zxbicv_m!-S0_-c9ELyzDHcyANg0UuS9IPh1x`N`dP?`G_`eIAlvgF>pKEE0qD*B_U zC;e=_eqOeUz3JL!0S2b_Iv=P@lcWyDu@`-(mSdVuVpMfkOdY4bz1J@K8MwryEzid# z5K?oc)_M7AW2iD`X?j&dv-0|;=Pm6zRayiI=}RY5%fX%cv#rdFMsdtbUiHesb6)n` z^kC6PAKUBs%iDEdzk<8&yqO8`it%4DDkH3GTla6Kn@y>8)Z6Qc!7^8HJpqc3XWvJa zscdcDUgv=Bo~W}rpQcW@)Yq_r1?ojTRan9N%=bfvz(LP=>cpN$92&r;)5l@~Hw}P$ zul<(acguIY4R9N%;w=#}(z8=~ro#YDktNJdJP|T5%)zqJtdsUj8ZH{HNvvbP`Wt{{ zHC*n$4ge+PUG+RA1K4G&SF!s6XM}`$e!+2rg_opPxi&X28hr)WEHkm<_SzQ8+vTLF zY%Z<_Q?b70(XuvsV6%_c0*3?ZflGk7ZDeSY)@Q;n=oRrr?0CW{wozHAwzMv<3V!Nw zic;iy1`{xx-Nc4F{tHtNUj$4RoT~BB&m@k3jVxKYKhJv8&yJq@qSrH+g!!2~bBAkk zxaf3t@}@OB_E@3-x{TJ`>g0jt)4o3S=c+I~jw9!F!3CtuPT?ZBFbYO$x|yeqo^PBP zG|N)(+?(v6t{|u8sc9kW8VA@5y5(&UzIt}f;EV4526go2@k*UTm)-(3YT)Q;rZ zzdH3x{X`%S`?d5_+pQlOO!w*e3Zt+?;nK-8@%jNNA8+-#p8NPKU9sB=ch!7})_jOi zxukbL1i9DXlhI|kAlu|S*p(m6)##-wUn#YGT614&n7mQOO_@_t!8&~qtRCE5$OQsa z*9@FguePOshK}!@{+7I8nmQdJebByWS#?l67rF5^|-T-orQK&Vd2>M7I?>L!bKPo!9p?>UE4AFrYJ z8M!x!!lrU#PxiFC@3+tV!OwgeVEwb!q6z~h*|`2r?*7h2Hk!xU036)CFex=a7RxF& zu&lHr6nRFxuX8$jut43x(u{O2mivOKArSdF5O<4XtK(X1FJ=d=Bd?Z^z#8mw;OR^* z-yfJ^@kb>`cSiG90oUq7TloOCFu6AO6xQZ+5YG1Pc1Z7|(TB$VDYxd=fICy-+i^1V zkvO5B20WiC%xlEL)T%g_@mfYsmZqood0T7HnmD8fsOj!Je9zyrVco~0?~~g@f-d1t zmK$~Yer#gJnj`G2cl?SyZ%jV;FmD9TcWEXX^WIonaex7CQBDGE1JTpW|g)ARy!c2|6 z8Mw6V4$(e_MR5Uv3d0^{A9yyL83WX~6*5><=B~0OHA<Tg}7<*1FBL<+Ch*fF_C!^{<*0#19{v)ZfP{eqS{gq3wGnyyk~$OM&HE$!9`6TLQ?)kcIh zTO7qNG!;iZj*)ApZue^PxTRxAc+fJi!=7_8u+yTu2KAEk31EhG-?@Y>8#XW);F=?| zLfkEpSg2U#ff1wuk+41%C=LUj0n8_2-E^pc zR|l}UhBEqS^r7(@;Ar3h;9J0~fSTJPL7xh={guEfG)nq~tQ$pGS`^4M>KvS{08gdN zmIp87!Mpw@+_#o4q8o}oF(l~WT()}8V|eykKE{#Hc^(cnoG)}cHFd{wzDNwKC|RcO zQ#pCnDec;Ts&+JS^v0a_SO@(r_POVrm|!iV84cV@^9;vorVo{)du&UeR|Y6)neUl$ z+K5}bb&ljkx~Zlt`aq$RmI6jr$CTKGi>o$uP_m?Cn;IEaOw944g_>DF2h+01^H_#= z%XUi*a9!8<2Rf0WnH9yY+mYP0Jq4j1=x_u_AJWp|-aSn7j@+cK#gWQ&U-h?_3?{L! zX4iIoE-iJ z;7N6qEXXbyx7Wr?WxhH+ms%W9hJx26Q(UfF=CK%%_gVKdg_qZ8J@?`>nG0UTtKa(l z6NjC0!ge+i>Z5-Ko41=T`Zo7%T*pLpZ!PZO-T~4#>TFdMA@!7@!Y{oy*Y7pT{L7e3 z*43%q$D4m?ACxUQCP%kXM3)&`!R)7C^5-&noBc2L{sY>Q>$=W`zg6el*f|3YG;$6^ zV$NBClqFGAj+X3a%X*fd!*5$ovK5@;Q?zmxgP3zB2nK*e&biS*qjL^7ol~`bT5peW z*O+6C;_VBd(YH~n#~HUy)vjIpR9Ee)J@;I5TK@ddw%Ua+zLt#_o_k8_Y!dd3v&LuW8i`35>mwFxfQb4Vu@0RWY<}8aYr(Wr#GA;_^Fvtj^<oYV@4p!hf+}TYD)mC#(o5N14`z=( z#Qtr+&2Z+?0&3b4H4Ji2ei#%`bM;x*^M;@O?{>*+-atKv4`=bf3M4QWT^=HC@c~gm zDbw<{CMG^2Q9!5$t(<=aX2beEY+UBKz2LQR0Rfg!i^PqfOfvc!r=NWS|x$Q}qU}~I_Fq4!a zM#7v!wd;HVuIL$~D}1z0OZ5vElxCVEPF2eE$N|Y@aFs4s+3}LpYmeV^cT>-O-6X;} z)RZ~TC$~L*lqs4qNs-8P&eHi0cb&@$?M$vQ)TLe9tOHbG+nC3DLw~n|rK*9Lv-T{} zlT&cZVyZM512bXg>bVLZ6#UoJc~^Jc_9Z6$%VM@mT7d4ie^RJRgZfx4NTB zKjBGAyNfZJ8YY1(ld+O9V;3o}W8BKJz{Aqe|r9B-yKXV)mGhz@<;Bfio_-pt|to*A_6S;nWN- zpVl}H+urBM{->**_kF|a8moGkRdH+**_F6~hg6)%%p_*f1>iDd>51EUDQgub4>gaP zn_@O=<&(*78R5IqqpK=6E+!>Zh3!@8d>UAD_A8m(aM>yHEcHcT7Jcga0lc|YSQ0`D zcOAPgHZBLQ1BT^O7uIG~($UXe2y3$gHoJIdG5gtDv^8gw6m*vl@_nXUkl&Y2eP*it zo@g~_e&4rp&5#ZyLnk7Gv+BceaFoMO{|VEFzX9~S>*0iB2pnVenb+9s|Mq{f^IrOL z>H*%=V1~)8ml>GMf~g&^X-;7r>{1p)G&+rxI^&7?>91H~)#Fq7By}3TJ(v;$yoh)^`+)tJ|_a^2^ZS|K>!<-;N zCGF4eNd@aQTnnoXXj(2O?h{kNX=hk#D62AtOMlnCzkZe7Qcy5uJ?9}Hx*J%_y`g4h zMh^1mb+7B&BcF7zx*X%}-}^nimwnf3ftlwBSm>gQK1X-#_lLi6m(Pa&&`3ij6Y}SE zK0&tl(E7Z66q#prwD&=t@1LjJOSvpe+u*9_-v0ddtR7vLx2M%OQ8JTdf>H9omQ@uO zzvkt@#3{$x?4k!uHQ&_P^yB*vQjH)H2^%p2pb74PmNOzKiXr|3`ArqfXhRtX2O)2i z50>5ou|7>5GnF)xY{Z;4-N59U&1^X9Ri(#ho@E1KKMCMxA2>)e{3`fyJx5r}8`R>$ zfY$)4f!Uz7d8G6Q=M;dmB8v{#?4lswKOM9+cQ1gg>GHBW2P`X~<~gmoZ|YPowzMI_ z_NpwGkKRzFuJ{2H2Xvt7fjb=8`+g4Y{BZe=qW~{Jwx$EVXr|_>vu?20{GI>8IWK+* z^(@{Dv8Z{12XHR1B+LJe7}$h$$U`WyGQBM4v=oipKuATN!7CBUs|+K~rW!gKzac!M6ZU@9w>~_vYuGB)Kkj26PTgOIFgj`2t+H( zDgn0Cl^AQ+esoKK5@C9_84|ezkzpFP<;=vWOBMEMP3e@d%!o$7%69NJ2ik-wA|ENN z+uPY8T1J_EsVh7!OheS+J!kP+I^QMk*q-3LmcMVhf`2W8T9h2-n3GN^XaYI{h`)fxOuC?>Suz5# zGFGFk_fkKyFO^7al`&mpc6#dDQI-kYW4RcaBWmN&AAz;!z8*%`1G9_A6!P-VnbxM> zy-jlm@PK+_;JJpzGmLA1s{^pv0LRN`6R-tXOCBAt*#+MZ+yHh6xDOa)Y|Z3D061rh zP5)a+BR74?pU4V$TAaz%(NIWF&sDFfg2rLh6TRl0%aXhQ&8 zgE^1`D3D00Cum}Z8z`il$NM9IjO93300TvLO<1a>J;H2It7=MEIG%|0E3q~)^U~9&`Cp$3mwodAp?6HEbfoAD+m9CcF;2Rs*(*^;WRaW5k?5f$@7$s zC%;1mOgXtx4TCh@SyUhLtd!O?+*o&Os&9(M$)S?@k2Y8P++jV}R3sbd3DBtfS>iOF zI&r(25#`7A*0!`bo|^)=3Fw-FnYk0akxLDb7#_v4+BWyx1jM9#oB+||m`uh9u$wb@ zEiS5&P~vk)2t9xCyZ)bqZ31Fuz<+M|qbc&p_xKyNuhl+0D!It)!b0>f3+( z?axs(^)pCfhZmt>yUH zyP1=;Q4P;p4Eb_EG|5)TP3QCfM`3a5M7h;qXIyvzXJ2_~7>k}d(Se&IOzqp{+wZ%T zdH_`q3)=mWXhCFMf`FWknMDA!fZMsAWib+xIxSilgyRQ7ilgc0l6IOCWXxK$j*?WA zeAcsp6`Nkfn)O!~e8o>OtxaD*xlv#zUVjzGle8c0U!G}<7S`rua7eF#{e`u8e$m_P z(M1PrN~{V_=wAVz0!SH}`KJM<3uX9wQ^O#A$|aFc+mX|UELrxz4^hvmEvsBLNkq=PLYZNCJ5{V-B4HS0Zp-ayWI3pq zhDr^mbx35t&55z#lwH?mB<0QXZF#h_TU*o36VOd*o9bqrt#@Jsa3^7hIGY8ySG;FiMyD#h-&~VwP=h!M`Y|A-G z@28A`B)>IbXtkJqXqlV^nS;bRaGnDfCE5*tNa`?cdm3{6Xv)5(-4DRlGiu-ew||Va z=bZB#u{OKtqR-QhJnfI%eIE|qYmwOyBf}UAHtgpGIw_>Vcv)JC?hpeC{|34SLeO>8ers<0}i|B1Jmq! z;8u~SQ%KDaSUb%X{LnEvPKZr zl9VjVOomMS9uQYUifHWEvgNEj_jLuZ8!SN(y$8(U&CTFXVwpaN0-eq?j29P)#MuCB z&J@gPT`>__O&0=ecJUp+4ZvaWn+wg?7m$YT0RSBq7pqsIkt=?Oj;A7LUIKAlrCOQg zL)aESmDFGLz=6ZN-ovqdpDz!}-bny8ISmYhtaQXjS$odQ?Dc>5zjFQ!FSFq+=0hw3 zaPshoqRftoc~BJ|QjQ09r3ko&Iuen;C|XAAy zMiRgx`?MX&m|DodtkzPIsfh!+Yx{YVbXfW&Qzw7YG@~n zs_PovdTI3?Kla_>U9XESp3UgN^f4a3<6fp|=w**W?X$CN0O@y5a3anmjXFkp z91U;R)70;tJ#UkY3eR1|6_{G{nRbv5;SuLm=SZsE|*cNg$>^rVUKo_gVn z(9}Hs*P5EI{oDVMbFRIf;Vd)_1&~v5IT;{1juTl`S_TY@gF~XOia}hTQ;@Q}!WJ84 zBC|4VmNF*$14ac{{=g-QVi&M6MWIv^ul!Ecq|Eb`!Wl|{xhMr7VKOTj(&a;$JR*7r7nqlKe_y@UFTAP&Q?VXT!6JUW}#|&hVX134c(TryYk=U*?tlx zgO0dg{7zfiTMHoVY08_Pnl=N5JeAjSpxL~Y*jn~&cg{rtq||sO0n$7{slc(dnsg<=Ujh=6*P#ycsvW5;94)7yWG+o1fMQx+0CFj-p>5UU zE%2KHS%(kO4>6na`Ux#-=@#&XVGui6=;m#+ux6})be(1?c}$6 z&MwDuDHGC^@^*tcPtDAdNkxyxPBMZ#O!jPf(dDeW@Vq5tAmlHg`*wt>!@KP1`){M3 zgI-T;cuXXX46`sk37V>!itcWB^kT3m>s5#uX{rej)6gwL_6^)|;b&&9hViB`aYb+G zC=&KW4a?VG!n(6x9IzEmQ6nMGmy3x|?Oz5zP9-I=u{O_7v^EF8IpwpG5*@JF z#oK^41BZZH6Kzdz1vrZpf2rd-@<{SHO{ejMmJpenl`uO^&4+~Tnf$GKFgLTG{o8+! z;mpIp#K{6RmuL#QGBuB|am&l?4S)B)`j%_1_qiFYse@shVO2cmO53k6Dn%D4d!`zj zWhP9Gp#l>(7xz=jj)k(C_iPcpuqw?xHZS`{M|Agc$jG21us}t(GHf$ro>>`ZFDT4hU~dRdITwzU7@Usg#DE|YvvQ9i6M>} zsHhPVS?cHl^ee5MsgVy_lCG~Ez-$|=EZjXlHyO$Y8p^_JV{NAAPmFaeme0=%C}5W{ zVzNPNaM||+#M1wJ_xL?$^qPK;>vUdCKuZ^0MiOA3DuVTq#i^i@Uh}aIVd05E44#1c z$UR98GP^#eUH=aiAdLWCD6i%_0`{8a6Bm}VOcUaLi)=T_k`%UV*2l!MIg_acRA|xZ z6g}`%8#B8xZTn-7QGx3{BwPq`<2uX(r@_e$gW61d+E|_XT&vnMCt88Va35y(UU-g#kK&^; z$?Q2BR3$iE@g2)_c4b+HUpf({xRC~x^zli?g0e-8($lOzcMIpf_$md1I&iZ+PLiQ) z5146o+;=la_wBW+AB}eK@Srm+n8+Fqpc!SvEQ*Q(CYJA|9`zHjAO%*%F=W{vQ%?t6 zeF@4%id#r!hf+tzI+gX3iI~lzyTj2W&D5{3HO_?ZDGzeVv;I<=UDBN&g#wwTj4@uFEZG zGcYtC;Us850$!CAbmz#fcQbY1OQj>Oo}~wrzW|JajLg!PQf6NB(~)|jV|of42;h}~I~pcsEKf02V<1g~&BNM_iSl+z zc&^u&|IL{YcwROKK^NFVSb|NrL?XwUPmpRi>1j9F(pyXUb`3%K-NM)vW+k4~YwhP% z!*b)v_Uj@Cc}ldn>*v?G9xi_bp#WppS++0uEz^aeEd$T6J~h%pZv_S3HO;Y7bExw1 zP&RqY`vQha>f}xfgVS`uT3!{B>(~(BFL9c;yvcdrXZl|$+w^=}8@pY~ktMC<_nl>K z>iWCn*zU>wqoHi;y1XrZ_mBMm=U;zyr?vSUL>K+JgHP?}vHKoi2voU82d<33_N);l zVCA7wdkdG1u{Hp+1>`hk^rygR1}Vg2=J&C;u=71*r=!uHO7GsDeX6I)wJO9p9hHm; z|BnsWvZ|`if5~;gSU0J1YMOts_t6K~`}loWuehTVNfrStj89JHx1slJ6<=f`c?1_{ zMze^x>li6}h8rgPML9E1XZteU?ouYb{{zUW5A9WFzl_N>mlkl&PXPek7l9q^rr{!r8 zPyUpeB>)k^+$4ZERTU{LNosodRE5bob>Ise-t(8hl%}A+z_c~}1k=xtvi7`J*lYgw zfAzDkxyA>xnAaE5WrL+aLgK(}IS>_g$#hZ622F2m zHwtm3w^cd2tz`fr5W(>km0=@mnTKG+B_3N{8d4n7Wy0~6&lUgj_-!Q6vi()-{q1r?a65qfZk|v!%q!Y zBvF7^U!w17V5&)(fsvkos|qx!%!3-{c$Nkp?h_r%mvAxU(uoGo?i)E~F29h=1-Jr= z4&)5N6kK%6^eq!DOBV*HgnPRgmnVNS)^I%kF4t+s26a~kE+M2GV6sjp2v8tfe^<&H z7yVT+V6yDDyWGdBlRFD`<(U^$-}5u?EWOekU3Bs68dFUBqqpB@#~E0a>t(hZ^R!HM zI#@ng1v%K4gOYjuxgVvsAbh%AdI-JVJU=t|060+A;_g^w zijJ3S->~4R;gmhCkVNF>^_U@N^Vc9aPaMKF55YyN(pptCBXhcg)JF7yu znEE0nLX)e{WbKxh1$^aX;0=BP-+cktSwmCbjQeBJ*95Y(r?9;ExD2=)7?e+4`hsJ? z8sKbTBVEvcfxkrj&2kQIfo5x-f{wSOqt5`>0N=SFhuk`F{$05eTH zm*pPJP4D3Fjz4BN{RA+662V1h=|&A4WAz!=*=zphzh}#fu4OP&rcWz80VEvRIS;U7eTBpn#b1C6V&oi4J?E4dLOM zY8F8-Nh)nNE2}jnygc}&O@;BPGnVrVoyu^TvvFK#Jcg4;?gA|W^BLoeR>nZ?avsWv zS&y>Wav5Gv)8VCD_#@>|W|REpbfe2lcy2PKkuxVU5HtH*BKF2!dTFZ}_^=r;oEuQr zHFZ6p9t>%khNi9=4u;gjA>MdsjC+87s$Re6z5a;zdp)YE!ul0e)nlaJr#~{v$mocV z*a$sF=#_4{DgbAt;Lv;<&B4pEA=gb3dJpDiPGTC9=||>u#P6bdqWx5hj%cp!sK-%ex~j779i7eBQb4X&PEb&H7-}8 zODcs-cSx9?u6;_%`joJQk?MJ!Frm-rh&1{c^4gozDQY zWn`G{FWaDvw7sJ8iSh1{Sto`J9mS_3o8k<;n=Q-o@ zi+Y={yrh2krl-Qzr2-Jz3jj};V(%k&`}E4R7?wBv@K&Tg@{$`<)xQyST#%B2rRl?kKnBPYlWq}4Abr*t2Y@A_i9I8I7 z+ww}bKlGO{djyzhyIyqLNxtr~Bo_nvP;Z6$7U*B3JZ| zU{e7%cL2vbVDp6;FD-!NEL68cld&~Db3rdLSJDFB4s2fFt(8yLIZ&Cnq$|@i&IVMO z@K#c$2VU14-u34kKlIho`P$-jDozP)O-@pqj<90m)%L2N{#D=d|D~UsH#io6ssPSO zI<=|uoo@38YL>E5XgaVBbtDcXZs(S&nY$oe0XPiHF^cx3lnocF2&j3Oc@##GA$810 zY_oeQV_+UqE8Js!n1zSB8&rnH+*AU<3Q-gr96V~+xTaOKzgWA@td|X1R&mr+3e;ZAFY(5!sy{l?r|S0^9qGCCd-O;9^hZW)bYgAlgn1Ha?MIstX^f~E0+86RV!G&Vg-{E%NU=WWMXWBF~+P9-V@e_Skjs2 z*Py8jE6Q4o>vJ%@-90*NHzn2}{RcUd#Q@cmRRCPUdd~-UTAzD6P^my->?$*0Dh1ao z83ZH7QW>LGnWzaUm!+0_3uD=m^u|`hECGgdS72cwCa>q--sj~kQS$R5O_cMI{-%8J z?=5YKk3-eTRHu8Ad&EgX$|-oHjNuvJ(oN?yZ~O7T!LQ$bA20+)=%R~f9tQM!J0IRY zc>3`ts!P_L=L__s(Ec-kYhfX|4{~F#e5JK)mt&`ZXlot$Z?pJa!{xctHi4?mlXp4S z-E;yhtiy8v8E@$eV_i-b38);fp&D4dVuhb~{Z%}C)91^YK0pUHpy8z2sFkoCWvtfSITByD%J$kUHQ+#5qv*t?aK(AO>m_gqZ~pF{8S8T#uRKiF-@t zOyi**4?v{=qJ;sONF@aD(5Uc`4(?@}Rr9I(&iuCE(kG6AqKR1^*g-5ir2bbp9+=JI zgl?3O<7NP*up<|Y^qa5)C=u#4tutp-=0-ot2+(>G#u!Q4((h=S`PN}A?8^vThAs($ zz1j>zre}^bb?g{N4<59m2M#tz_aCtRd-ic?*FFyK-pA4X2krRbBOE<^te!b^ldb8|3NHw6j}eRNx7t<~^hSZ=S2swuw|CPo+^9i=}x&dOyI{jrtHeEk0a zoNJf++VyLF)yDO#Idh$@*|5G@yJ5YpTD!(qty|0L)oXm&gKLuyjl)Ae8K*DecPE)G~U_>Ae%c!4}qLs%z*O5y%Ay)xo9bU{sn)?g^Ny1AbTV zQ}>Z&sYg@MwOwfHp{v*RT#G3VXU(ECnVifKJ~@>lQaw#nOtf}~lUs!N_t>L&Y|OgyFU zN}0Z}llQ~1d?gca%IcJNx|{_r$5!oV7nzhAY#fTd?{Z-7lpDWy(dWqS9o3$P?({8J zU*py*<1z;aD>rkI<^gQ}dF4)FLtKb~f4vl_77v8$J_}x_ z+gr<}6p*I5pQgEoUiBJ0b_61p`|LQSuLoWZJRC@PLtv`>-CV%UU1i-1C^}&CI^g?( z0r>5}R2YJ1Dd))dSzs0L-N0(nNNN*qFld~pEInP{J%p|>A(2q1M9}$-@uW*~M&%-8lnb zb8sY2O;<%`(Y}QEcx|ScI(n1?`}W(RJ$ror&YkRgYS%YEJ8j>N-Fy?wtdH(K$jp(W z96oT&XXj>MdbaG{Xv>EI2FbGoXR#8D^%Z;IMNHABHmF%#1KGF-CvQ zM7@0F^8Shqt9{L;4ZiWLjke*O&A##MGkwEZXRvgea;MT^p%+o*dJUv_4i2`!BbxJvipx}X|;VbK1*`Rt31$0S3 zT5UrKBTr8?5BpdGkR-<>9)A|N;;ak!jvxDO9{I-Iz_0@ux_FktV0wzj?tO$AY8$2J zo&bJwFX!N3z8?l5<5b9FEo^4mS(zFsP^!zW?QCxY*@RREe#Uh2L~mN2F9|p)eX=L> z#ImnU?&PzM3j}(t0&gV!-oZCtbt&u5Ig@=)J_d|&Dn-ZI908`9oe$h@v&VkW#+Hxc zH8h6FY^n=AMD%&eqT%M4%6XM~V)mbBDPK4q=pr6~)xy6F_mP#l8ypv@p`fdauU4Y)^EEJp9FM&7&+^eIBp)iC^}M zU-cHN2Ut_%Cf17zTAG1X^Zk~EZDAkB%3?Mh9+%WIJ9oX;HYrswv@d|E28B&Y0aq=6 z>yC*&pGEh(U|u5zNzB&=j$4HhK*sVHoCtD8l+m$}{!k2q%K0=(9hu-{V5_=^_0_x{ zj9~$56?aU%T?N?jMDZa{S=48L4ivhi&$d}j=L}Q5bfkS5yTKBmH5Rl)cQ2UZQ2u%Y zR)bA5;Mn1V9N4?p_if){yS8p)=VRM!?~^+@^z@$k(9XRa*>i}aQ^#O>1{lVllO(B+ zr4|JzAr=dYN_c80Jv}`I)5kfwW6yBsgJnH5(1*z}RxX?DFI%^&S+jYgopI4wcGh`Y z{H%-5ZO%OVY&M;>+172^$g0sbOiby#Z^$J-=4;yMmxbuGQ%|n3se5Y9^Eb zN>~DHB`Nl)#;mue)ho*{1z}CJAyX4CIgXLvV~IvCBop-H^{c+9OQmwG7Om6;1EFPk z0or?>u)(#6{68w&U5~3kIvHa)*T;;1rJjV%*&@S$C#G2~sr|0kkTOtfuu1T@|G+zV z-|xSdr|-VEb0h8IS&9l6+LI4F;s=lK^Rt$1qE7TRJu&9VLi#5f0UR?KjRdsRjFyy1 z8bb}&bbsB}&fd&{&}{NJtyh`ml5G&SDT5QOADJM@S>G~&CzD;-q>w8XqW>r5y=&uz z=ljNsE@0o24|A$T2X0mX?B04G2X{Q-n=iY}94!9Fd&tJa1MAWfR+xB-uZoMxWDxoXq3Osu_}xm{lr zVDsc?Z7#mN2a?4M-rR~e+cDb$Ht#*`gn^Txv!siR^MLCLa5*S#7y`!%qw^f#%);87 z>wwJ{MqB{=AOP4M;741uG_&t>h3@;^dLy=q(U}RMCjqdqoHf@oK<)A}B9lR{tUJE% zV;ny8@sK>_CkdqVCF+)UjM33EdC3p`8!mqBcUsdxGX#_L@d!e?1;$}`fK^}~0K56D z^59IT|JU(2QExNX&&*vOB0?38?}oa{MzD{F>>0uFJ$xq|C#2Y8l!)a@n8`80qWfPM zsTR;TJgiYSzzy&q;gu$el#%88DMSi)_7}bdkHC%Gb|I}Q$U`Kbr;%g z*+E*`Vc$wWvqu3j!?SssfgL`$pM6j7VCUo8*t7L1c0RGqc0K-7ePG*84(!?Q#||BV z>FEGqDl9q{IzHnxi-iHQ%KDs|e@> zP)nB<7)Ag}!jAj8vZ8ZMS<&wePP~?x_p~ryJ(mcu(D%18SrhQN)pMhTndMFzuB^@c z|2$q$>iLqXTrhCGQ+82+Yp*5E5vt*p+u_KN2I&wqwkO&6yM zxY^^_)7#kd=)IhI*=1B#Fhd7C$!amoBrQDn4irof$I~nqD1;dd_XffkD6&Gm0gvWH zWj}WjbdA|_)|BhfhzwE3bTBE}H=fS~M|K$w}e zmTVuV(Oub^{(R^`l?A1L(oz1Z&r??r%8n3_tUtbNu`(FZ$-^GA_LI zVmo8=S-yI79TNqZc3@bTWe&J_ekG~wSgwcZE{sG45=$9n2`anD^OR`3&8SO{B|w+z zcAAx{V^Bi5Tw2q+UgXL7cs zq{mQQ(N;#MGBR5xC_I}?k?;ge&0Ns+oM&<&E|VgV1F5=A{~x_jRL;5nN?>vc8<+WM z{C?PHcJ{FEdhm9;;?3{yUca(>fW2%$B261Ki+yvC&vk%x3Ooa9T!w%Ryz2gkv z$4lDmH)#BzIH9|Ilw~swTu|7WMq5~X%8N0ONseCX&>=4AO1Gk{C!_&aeQ4@gj_&$1 zW~c5B>76A`32ja1)QaOUzJ?pV{};I8+kX@XZw5glGn)}N3=`c)F%U9j-h;{+H9cz)SmLUGkKWeIu9(9t^iE zI+~+qKo*(MQ9wJ~W|D$yIr~ZhiY%Qpch(d@G=}KOIqgowy1yx4qG?kKX2h~;qHo2l zreEekYG9UzgNOFoo~_$_+XIiV?d}I{$HR}-yB~X+!#j8Rk-bNN**a)Pme08S;>AZ7 z7F-s|8J<%E4m`PQ_)V~rhrVWOD+;6R%95(eZBFJf({;Dy2`$&rl*&BlAAKU@$*@b z%zd$el^d^OV#DRkJ^lH`u#isyt<4@V%dozKs`ofnU4qU6yUv(sbtfF7#YE_KO14Ol zNjz3qo106z`koHhJiX()fvYf{pebxkXoRH+IlwtA7x1?M7kuk`Lp2#SEHQ;a08j#* zs^x>tn+F}=|5*<2{Y3dK{ZkQ4JcZbr$AJ~qi{Ji_nybF!r>xh<2eV-6m||d{sosu7 zpi*9bEJvwqUNZ#+Da9xUGW%?Dn_)ARHPAK$r#x{-4=he6`V*D58i1Gug*qeP=rR34 z+ZWQuJ@8@OW3kwN%C-tKFUKM}q?i4j@)s%re}$o-Os}}jv)fo1Yw0DWg@>?sI2xT=&V@h(;*yk``%d>XRG)q!@!btWyf*=T1P}e3HmA z?Ne=oltJpqFJc9v`^b-{7Oa|3QxK+Y3z4MHkN`iW!7I_3&0Z zRv+_qz2#Ut81Jt4h~f--ziYqottWLYeNG4~T#qm1T9exrV1lH~No#$-3fodPr+}7P zzZT0Utsud2%-Y$imK?(qEnrWWt8BXPJkGl0LJsYCG)yp`8qtLTJ@##XjJ;bQVBI-q zqdGM>cyA|xv_3u2 z=OJ3W=DI{p4WrAJv-a$laro(*fTkrKeG#n9lcopThk7gSw_{v_>8yrHZK0!Ce7pp> z5V#i@4OrGu;H<*h+*(+iO$ThAp0N!0$#R3;4!&R5n%T$0X9l<$_)glwS_D?Az`m>^ zNQN2$2{;y7aq>61N=AL+Vdc!% zQ67~+|I(wTN;zyL{c&JWhHZ`k5yZ3zDvBPb5q@* zmgbTdUFMg+^cuVJx~u(yi!b%{qw8$4yyFgmXhLLd+MM~o%MwP9i9wc;4C*QY<`U+p zlMj|PE6P&c%fwX1Wt|R6+dx5O?P*%2rNC=$Qj-A_nZZ-b??*GiJk=2mJBvI(3v1lb zx|JOn!HgCrZsNG4^_jQmb&9M28CWdGvn<_Qf0v$@1RPf27&RR!itD`ihL`qU^WCql zKmPmg5-s5_x>$4{Z#y2}-W=Gs+cs`m?r}m$05-Y*^H64a3ya!YBpfVFJ5Tm8Wpk#o zd=j!=`w&U(PR~P9ueF&AdHkyB=29+UPnwp|cSwB}#d^qpqiZ`u@mvO`J38<92f}DZw5_6*(tun&4a8V8@=p=mlasc>_t_=e{bKv4;-bgZ>H+~4csQ70&8>^0S%r}tSPL``+xxywlK_=eqmDq zIG+X%bin568E-0rtNX$4EdTkgKxX)hyuS7eTk}lPuw-&$@)!vaVc z|KDO4ZlH!ZR03)yCQ=649?&w8p_9=6gaT7Q%48DUhz~GRT~Q3TsJ)Wtd`1>#Ww;v_ z+gHhpW4H&(G9Dc_EHX+>v_4Dw&@cr7^Hd~x{v)O#PRlYO1T1M~W+^Z!V5a^c@eh}f zI)ZCC4cM_}hP~Uj`?mWZvd3?~x7vF9z4eoKKjOQ$?}X_iKpiwO`yG&Zx`CZ#=Jv?m z{lgkJ+AJm+e8~U{{NWkc5zcrQ%Qx;)6|2Dqx7oTE!`dG)>?Bdxl5E|}#a(8d{(@%5RrVDd-Zk_l^w#j|0Mqr-x z3t44({R@p;!b9tHG;(=~mIS!;fXY-&8`KU=>LhZ$Uw&N6^?#*o!lbvPpRLQ=+Bw%; z2`md^Q#x?-lww>@H#;A`%Z?x1=PS=xZ_NM@olD|#-f;rhNTG8?U{GGf92f6{IM`}J zR$Dl(Xi<0sJqLyWfw7!Rz5s#W%4WP4_E(0CC=vQsJn&q3WNGHV1@@k(X0vvLE?svVPVwcR9IPdFO0+T$+c4* zqe`}ABW$7PRf3*{wq=g!@vp~+U_7o7*_8!UbivaN2rlqp*=_#2W0(h~X8G#@kYxTi z^AB~a%1;kkn^uk+!%Un|f}47&*D+yk3E<*@<@$cs`Z6xh>lE;jW9aOA3~TwDntz1! z@;=a;zoLEb(F4`f4?gS<-+G5Va?72z{jP_HyS6^*Gl!3a*}NBqHf9$UXzKdZaIo{i z$JzPdqulf-pJMsB>wA}6eUV@G%4@j()i1LvUUW5QuR51yKmj>zn448;IiID<^GEo$YX?l7N-sRYY zF6Sxc%J7tfcuJ9PPc&6VW7;RlGbDF^*Y~ZoPf9Wsbfc!V=Mz=RuFoZ0a+wrw%J;Lb zxR^B?*K=^slLhLe12<2ZHdjE!!6zQ!;P%IC_2%`Ii^bgL$5-x{q=36c@<=&^fR$!t zn_Ky=w_k%ND7s;IxY){W^O~DpVTDrcg^lSnfXfA2VU#kIcB5%6vHb>x@d-d+nc`*r z*zy&uJLgp#-2VBX8F_NRP5r)jt<65LgSx(jesvvH3yt1$b@WBVxdofr9^?|6BC~h2 zusY8w+mCg?=IIr$C~V6^;P(PU@-%dk@xq{h0pAX+BaKMiP=;EPqHa|(Wtp+|D%DXG zmS2eN$SX0EqQ9EIFY!{tI=a6IDcGb6Udz#xn`V~I1 z`MtgKufN1^c>PQLhS$E#F2Cw(HcgztcyL!2lSgHsJ_SX}at`=NyEQeJIpD0xwf^Ssc`LVm{3}7)W3kai7Y5T)JoV@{ zpTX&41YAJx^Bl;_B}9~|-p<-o(6R-v^p<@AcdbwLk6SvC7~!}vtQ~mGCz$nK*8SsL zdM2l#_2_;i<+4+%lQRhrYaZ~R4dHo1|!Y;!{TdU@${nZYf` z2;;9xQY=!pM!8X?ld5{KX3NVM8QH{OunXufCLR5G1m3;0c^aCpgMS~`28grEI;$_H zON)<}179uUz7e1X=8D|j8HKgEwF5R!zxd$-PJX2z*Ce2(w`gnL0KBmU(F|09N>G)| zeY$+CDjy?XA5wFxDq(Z>z?+8S``*jUp|1oU*W%fl`TEmATXP5;+9hqAuHECWzI7z3&6dw3Y*xLF4HhGUty1S`l&C|mZhYQ7%I z`WC~Aba1R`t!e_F3HN7AE_EW0Kuo1Cve|cGAN2w>>EP2e_SDl)_|`k`v4_5VTlLs2 zch%b-e8i9K+*clC741M~7hM=I64F*0j_%l7-@RiOcYpM&{MF|5)rBv+%wF>Pm-$Ox z_X;k*@!e5()=LGh>uEDW5&%FMrur96@h_q2?3t#h39y_akU6u}UHeZVpnA6;}&0WWf0|3Vw~&uo9MV%gPGxE?fNPac8o4PmUGRnA zp+b{rD98O{-{FKv9M4VkI2HIMIWKx#GB#>xZw;(mzrH@>iVJz{)~|4SL^vC#O*;Cq zX6GaK*zEBE{qYgXg=Phu#)#&u;rZzl6CemYA5=;azCEX!1Q2|)7;R=>-x{8C_pQ6-w62Z;I zYi+7=R6Tfrs&^;7{#$S>Y}Nec&pNS1#8tqhz%9W*r~;c#BE5rde30$@K-sq@BQV1o#f<( zFAZ(YLd{;g3@}F88kPgd|*V%%wO5R{3dle59<=`PLp#O4TT(VrEytcW$HbH z;i>=`K<2+u&<<{Z$yC3!0BL_pu#t5)1=Qy-S7hTGFcn_%m8sxn513S6%1798e(E0DG zuYAL`y!6{%?Js%NE9`=^E@2g;_&ms|3>8OHsKv3@bn;q3M`f~brd}wOCUW=Y5F1Rw0Be*;ZTzu9=&1=8wjeHZ>e1_?CU36gp zwtL&t9NNF%*Kb;>fWCr|ZLGzdN!TWwnH!SpN(BzJ?`n@$c4Z#6K$mrIQ3{j#GyP{g zKc>g~K6$RB&zClr`W)9t_wxwEj+xonmtWcxH{^~Xe#)^n4QSZ6^#P9V-NE|v&!rj8 z-<*|!H-S6p$t_)B5fLvyC`73(M?BN9Dxw%3%~}hP8r{qRn?Je*ns*#;7KW(IxTY?O z5pYc&z8;nf5Q-Id^vQA7opl2Tw|}lYKS!3B)+VLR`|#$gxW5tT;fA`Tr!%}bi;U&K zwZQE`cC0C6mxBev+Eg&Cr#fKs^oZ{V&H%p|d@JAq)pq$HkH%@>x}2@4qZH56(iPk^ zwOBTpy&y6&%U^O<=Wwu}BYXag;mqT}sI*_hU%(HZqpVna1+VzAU-C1rxWWdrm^VZ~ z&I15hK)>>r5(0omU@vSV?vI6iDdD&aB{0x}%$=A59~qChTtgOS`AU6iEM=9_mMqRd z2gYfI{$^fBW#m~l z3G1SZUeM^N=k{!Ul093u@rA$qT>t#*FKAx!#+Uiazx{R9wKu$kv&T017%&8eAyqvB zL~Y=qma&vXIlr<+N7LK*9`QZW^YlZ{QxWxk&rQU#L$-l|ElgDNL_5>N{^@{Nj!C=Y zI+moIll{LXb-J|2_5VYdP0B(_T#eI^ee!hA+;~H;A5&-KOm8r~780gsJeFb~!!o>h z!*{)v_x<*}II?$d2W&pm=wf(e=f2*7J$tA&ouBq=0^TPXpJ{rzqmcunuG^FPq(ceY zbHf}btF+~BUS7-SvnGF_Xr0-_iWH9_&$Qg#Tz^)Yf!Z>;9oeLD(kPfx(+A&t#YK#d zuV7~8SO;vLng(DT*s;y`J@trfxaeH0!o7)5X3*FS2DLa4nUi2~JQYSiAtgMlZ=@fn z3OHG63@;rvpTSoEPoaPZhtse=t_l)jF0BLH0-?jTg9)8f1HBPgx%mc0M>jAxw+9$m zDq62%B2?q`?a<#wRb4>i+FvQf{@F-Le-W?|*hMrDg(H9!Q1gt!+8lPk=F*N0B@NxF zs=H~L<562P{M8QyUYG#B6IhExp7$0z0d+PfH(ZYGwx&M^4ALV^uD-xt{^P&wTdsYn)w6h0Llq2yh^gd;yO>kRHU%*)P;e}y zfLm$~R1qE2-L2FYO?#@+MFx=3$Q|>Q&51>Wpu$X)Ycnt@-K~6;YnZ5W8O~Lbt8J8W zu1@C`0nW&H6^+t7g}m&Or$VYZk>zfZNct)X%c*>i#93jI=IQL9^AySKzwBqKn>kYM z+ySuX&|V(B^KS0@+?VaaFW=g1z4u|C-M1g812c2{t4vD6vMhFFu)d^pJU&aiLDW752 z{QqA1Y5}@sek_TwPo6ZE_Wc&>%l~g=;w}6|8Knc@y6dm+UH#hY>#w};V?fhQJUxTx zqQ`+9hnihGcT`+mhRg!OXC^%faNin6ZfcWAgE)E|orKC6)XI*||3)Tx9t)aT@??F| zziCyLOuR(6!W!~p#jso#)6^uc#eJPBNnLkP_PCvK$pyahyfc}3@BtyVbVfp_MjHJH zbH@%;yC1rzx#X2^rq{!~hM3LLG?;-E_M!un)MZ1pBb>6fuswtBr5RpsSa-wl_`oiE zS}=+A;Fext)|7fm`ng57_S|>?f)Nr9!T8AKCUQi-MQ^aCAonXaUCG3TOPG6l2O5h{ zN6*){uWL_7Z(r_H*H2J2-=J4rfEjr5Vv)Hl;8+cCW=Tii2JGp8 z&7~dR1zZC55KZ%_I-bi%Q*rdo%zY4FG_EP$S+Y3o2NTf#C> zJMIvUS9X@l!g>oDm!TVtj7GI5c5$tV+lcAt9>B{2bb8#ad~pwYmJz5lBUbInHrB<0=ary&gB=x~N7?|+c{ zZ~B_u^SQ4yTfcF)AKbnJ7z8kL?0J6K>!Q=->;pAN_U@~1dCzCK<)dHipMTwZo0osb ztD4t+=bP=C>#ny=tbuanHVXVCz-2zLmP7~HFLg9e?!mT!y(xh`OB>9kCNe5u?ro8$ zM}rLZz1>ha1$8}c6YwGYO*QIU8SP5jUkF-Pi-|6}sF*o?+;(rg^qCa5$55UNV7Vz>uJfG9 zYLpQyYqy-$+jQ=E^_~as)!I66^VHGFZT3EPFEdAv+2q>gFoXy>R2AMhWfUdYmqSA^ z5i-moNEqL5ygVZf6RUl1LVe|rDYdy6zYrWZZKA51Q3I!sM;XF>u4e z{vO(`ztbiC-94}_%`vz6I;b!bLnW;I)X4NK`^mB3X_IC3QB`&Bgq*0c$L9Z*@u>~Zxu&&+UryO5?Ljs_- zgRtLwxnm4_kbFaOaZFk=H z4Abel=$P|!?A*HDW@#9w@+L9n$d<=JFF6xGDSU zHVw-;R(UG838*P;)=8m!1}Zl(N_j7;C!A&hXdTjb)xh#)%j&bPyqJ4FWv8spW_SM@ z`?oz}hj(pb`T8rVfX4A+#$$<1zu^!GCV1-9;HShy|_P& z*>#xZv#fe9+@Gn5(7C|_@KUR$ zn(KN6dGov;CqWVtV<9sjIJtYwXUx(KEzQY{plQ0@h><%jOEWDgi|QiD`ot)x#l=}f zA`VO)=8@a(uy2By)%~CO>TvsA4>L1!uxuSI(ihbdVqSOAIjh&~-?p>9@%KN>Er0dp z-izLPEw6jWTl_U|exqHo{!$+Y24J}(3WqM=so6|mq{fFOVF&H zFciZwo!_=Oc{zqKdc>?EX&-1>eQu^;ZyZ7o9wOB zdr9x-^ajf(Y?Umva4pMZG6m1~&GkQ}EsZ*or@&|k{hl7XHB9UEuwLr1#K>9Bxq_E@ zq-O8(#YO6(glF%zV^D3r{Ne_R+Vv>_Y<4N>hURA--1{_pw?4>OS6)fEcnn9c@0c#` z=HMdArRJ+1GAqo1peutxOegm^er)ilhiQq1CWMsr*vN3-7Vy=>jcypOcK^6Iw+i~N zraYwDPB7MSDG*Zyt0_Iv+}(#&l>y(>w?% z)5_emK--JVq1XqyIc61B%80wT0NfHTj7X*2SY(fCzDi_Q5}fm_Y_4$P_foBwdfkJG zQ7MD!ibm$DW1+21IcKI?pTQvyu<~H{oKA(~;7NO3qyfw@Ptr;=qYuTNg|$g6tII9v zLY8Q2dR2}y0#wC*Z2Q(nx%-P>vAaL^h31hj-|h!@?`VqaUjQ?03Cc-y(M7LhM>NbF zK3sqOy`SgnAG^8#;g`I(dCfcD#9P1TZCrWw)xLrrLtvnTHr2t+?yrPRnCaW6WTC)( zL_ks{(OZ(LsDoG(n9WUcr0P7azQwF3Hv|%ZGaRFhC8Xe~)82lP?WlgS3yYT2ja-f? zZ5MWAs>7)pbbB}!Er79mi?1WXddvPl@^gc$%*hZ~h1u)B^NoD)*WShS^l@OE#YPvM zGy1;mJN?kXgT7(?%CiRDFBS-OS1!V?@NZoE^_B7n&i;Nq9Pn8ViesD;iF66$o#UXt=Fx3H@ODnDfz8yFY z_5k>-0GpnC2p0J-2VO}UN|8|3Tm^=JQweL+<2uUs3JN1FU>#+B1x+*H=>B&xJ9Upb zBA;Sli1Yl!5SZc2E8b?;f8Rf5eAO6(8Kw3`P;=h-+zl^Cms!qo41dIhJOZK>1>h{p zCZHfCEYFWq_NCAZ1IU_aB84`on=LM8LuJ{5PN!AMo-FGvd5<(4A^;qbgut{iO!YN| z;p&vHQMc3b(Y3onRi%S_Ng2{8+r@mt+6f04SgKN}5#q6tQupDRW7VU#-|2UK@{847 zpZ?Nt*WC{?J$)4Dr6xd2AJpukV;7A>NmGC5#@l)5#(Vpp|Fcgvum7Pp+nc}lZCris zHNJ`whTwxFz1e}}o-|2YPt&+t9cOc`$XHhnnB{{_a+bD6yOXYmRWiAfkKNmS3$uQZ z3`|6SV*<)14$7t^jFj0ZDdAZgl&C_^Hgy@u%l5D-f~z4?ebE3g2!N@-!$aG|j3|i! zS~LaRyzYjV^e=qL<->cw^wnpek=#WW)$qX1gVmt}2dr9uZmLPEk$`gfcv;pZvJ}?l zsGd*ANam~>HMVqYdHb^X*0jj{IC{Kx?OfSc`_^2WJpoD~*Voj{AYrh3tiP;NUC?IT zma|#4aXovE?3P1z;N~gBx^DJ7dY>KJzsFZ^KEvuk01Ry&h{Q3W6FWqcpm<;Ev_&D? z$k?w5nwRe3UM=6tHn-q)fD%y}+&uVAG-X==BqjC1RbNPFE%ZgM2@m1k7_2?}B|Lra zyGt5%ZwX$91~^Ug5KZ$qR$YUWyFKFIc?Z6TxEQ#sXl;%K*5(kHDZu7g#YE`I4%l2; z@qNG=up6P-1)vN~`B47O0c(KoY&GPu%!R}ytvIqVh5AsHWy=69T@H@uQ-{CIv4fu| z7wM$lcrQSp#AW#yYtDV8z5GZ14Xe)F;DhOT2W^X5jwLE0$Se-$ChvR(sLOa9oK+B6 zGO>&sm`iyTJ}V$-0q)#GYJAeYx`OO+FsOZJRfYA2y9G)OWmyx%E8K`6swPAL5#%gd zolusolrIl(NxwHrn8^fs1vY;UqeOs}hi?hlFLB~j!mE_`>_s&-4N@ReFzJ2)GzY-b zd!FW=&wshP^W&edANkTZ*t>0e19PRX9hZmn>3pwt(U}bmhL7KJ50BsS(8%ZC^~w5m z-~VQN%lEv^uf6catftQZn9CW1PNqke4@lb`Z}ojTEX)0E39&%fnG(4pcnVCKmLlf}NX=gNBu1kw0WjrkBK&I-}N*P(-$UW%#UF((o5=~xQmbIEBaSF)$H*dj= zJvUiH8Mirbol7k>U~4vStTvo`R=wxZdrqTk-cP%G`0)0}Ir!A$wr0y2SOwl-!IU=M zNO3a2$_4B)gAl>c0*``~`lxW`h0P;76c1_Ufktdl_AmRH1xJa@6&5_uur0hyxqI&5 z>cRZgE8J@7e*%qj)fv|^zIqEYhwe*BAaaD~4=mUE)I_L$8n5r7>Rp2yafUV55l(3F zCl=#HM)BrgK-(0|=vZNEo?A?Wc9iuUu(lyqxIr9^W`a+JqT#*3e?32&~yskC*b4 z_F|Qo_b4MkQcMNFbdz+b#5l+@*-$m{E4)jqfN7k^AGn`8KK1$L)(?M{ZC|^mXlIsE zEa!z4U36i zbRR8)0Cj0Px(hS0gk=oNjLoMEOw<89XH1$p=aLy&#VS|F@*@Kh$EMBb04V5X+0 z$M6g;SZJ!b?x&M5A<{`S*9jYmwm#a(^H&pTk$8L!qeXAI246NY*=)M#Jns8kb($Cm z`Dwt~)GM;j;eC5;@3x2if|tLNs)E|(IXVAeHbR)=Wvmr1#yF5M9Jc^YQov1bN|DF{ zuI4oyBe>~NcFn;f5E`7>WmX`NS7dgh9H){_!3;iXIS4s)w~n4Nupz|ht50IL|S}0dT>A=1$x0d=5SzbZUy#sz~<73 z?*Oga#pMbtHEPM7(>hM>BZo0n1>3DgZeTtB&+t)y#{xXy_TwOPK+Aclgah(_l;2x@qu_Y~9c-4jD2FJ;Qd z;|pU1Z861~bDbjvAghQ2OW9UExm*j$iy4p`aCA6ZJ$Bpee%nVs+uZT7&$0cEM}TAP z?97g>*~JS|hjRiL4tC!22!HlZpBVY_`#xX4^(Wr$-~NujVOO7VH51@-z)(S_{Ch^( zHge7S_*cv2PTzSdx9;N!SmrHEO(S<5&)I{r-D9y_e=SeL&ROZ?-*bIW$djZr$;6X- zv}|5q+c9NuB*(}SXDojnSmvCc0iw$83Xz^4PntIbUUc1cy{lhwb^XCLAL^Ey2-@BJc-4d_;RG$ z6&2uNT}W*o9j{n>_6_WQ=z|5nsZREFBl|95duemy_v1W9#nthgqA#mWGAp~dI0Lx0 z0Go9n^7Vj&1>ZWemqJS;d0kPC6C+qK0{ zpmkT41DUd141@0H$o}^NM;Dla?&RSofjP-ZWRF@Az+KL@@A&`OC9nM+>Kbo`g{^48 zR417KL{=fn;4J1p80dZ&IP-N{X3OnqYP;kNB~k@IWJE%)Nh$j~h|@&`4NXji;$Ooo zGAS#{?+L8bsFew5N_tGu7y6^FH!N&6koMp{pVBXRfn|T0=?=@Lz(TIC23l4mZ&Txl z`S}GOErW`^2lsLRm%nDWfACZF-Jkjjhn{{4XaYOafIK=-vy0A2efZZ5&fmG^Q9k#l zpQyg=C*RID0Zy*mc!e#S2RQL8RXCT2P?HQzF9$IS({x8wj7d_T%@S}mOG8)O)udgt zCVAv~nFi#k;tH(B$Qi1nphNiEGI1p5&ZV6uY}?E;z&+PQRrmFrMHT*}2{h8&WW7Uf z*6N9QoNUX}^Akqw0624OwY}=wU&B{F^7$~Z=%R}g1x4nXJv(;U3`3uwuK=aaj~8QI zJkF!Hq?miW7eqHVGd*)}(Z@6~T?^|xO;uOccbm)l0z`IF8Gh>OY_j*UhnPCJkJXzuz!0p#n?@!* z0|6%hkQPmW0JD;!9`oLsXeZQQHlNl`C}U=#;5mQ68H74iOCk=uD$E>@PF4*#P1JuV z-XQbfrBN800P6nQL`{bZR-Ji06D!VQ`smj3-pKQ8BD9#gdoX+&Z|;Ep)kNY_?5~=H z!v4&Ld@lvQ02~KK0`@fn%$3aM&Ba9Ma0hIj+VLvjb-+`KRwqEFGas|S`oh-i(-L`J zR=62W#Je(+88g{d%z>1SR`r2qz_A1GrJlME7^RDNr%wY_b@^NVmS6dnpTPQfJws#_ z>i?IE+qan3gz{n5N$YbW@R+$kgZx|9SF3Firo|f-{kAO8` zJNNG5uFu@)x4ieGJo4pl_|bj4OVP0f_oW@E*+m!q@)_{h&G$6FdGjOvFMaq6&3FB+ zcku0RdpqZiokbsP4rsu|c^h%#CJy}62qpyz6~L5oYP_bPrI0MdXqf})CZC<9W@y?gT86@bY>Eee1cVk z?OB**x|z8YoC1~FrzyFyJ@Ptow6VSI?FK_qCILn*OE;J8!bok`%Jdc{d(sD`CTbhc zJKL9SUdPPi2RW6ZV{LkH0q!ppeu}kcZ-@_cb4feL|H&Yt&`VIgf! z`J6FxF5c`OvlsEeI4l(&KEb#gxCFQb7#9h~qXpR90zB3Mo2P#K zNcm6vMxorAGBx90(bjwk@KV~slnM~C(5aM}Sw0yf6QBy)BFmFfu56zD#nVwAe1?- zUb*X@+`f%(ngQ9@-}|xpu`l1w%*=tZb!0CagS?ZOWzz;p7g(IqM4WbdD_n`UF@N z_LJ+NUcnCqYhzuWuwj+mm;uMyHp|-_*C{xYfiyYj3?%Du$lJRBurr?PHrBrY=VWcD zfy=JEs(0meSJpT0c)C0iJmO zWPLLJj$|wMxJ|V{+v*C(YfmdLtEBy&rMoBVN;t`Hh>^3&(eI|LR?V>W3@AN8Wxxaw zu?ARk=9#_q=Wed|KmHJ>XmsFa(b+uk_(Oi~_19DNp!RURIqpVbVnV!k-NG~2C5ynq z-=L`()7iX?yP9AqWZ+Gy7Z2|QRk<0WLp!BhU~$I2q$%w;1CL`*2S-xUi}t1^GXqK? zA6qugs?9H9_oE*xBeBtioa^V!EGStH>FD>-G>_2hT}N33O(+?5Z5l9(v!{!RWhMLg zR$vg^(R&5hTwPMpHy6pqnGV=IHRGbfxZDpsTK=PkiD{6=09XaQsh#euxdKTJTnS~R zfigF%#5ui^6!bm}XZLVy|GOCsc8OuoV$#r0C*WlW%&_T_Z?hNwz(4oNHIodcajbx3 zh8fY&MzkF*IG2}IRN_(}8MKBDZh-mY7+7?%spS7xBF$&4RHL;N6CjgP&fUd0$ni)! z6p+?q#prJ^z*V9s0H0uzCSesgqK(Nsi<3-u%qj?J_U@!%Sed=F01S)MrmKu-d_L&y zsJCdIW`xa~0{H;gw)IiF{o|kWo8S8}fAs5j!t{~ya9#GSJ}5g-vy0ATXauHb>#zR# zXSnyqJFA<1jwo1w9`C19Env#brt5%XA_w2OEtf!b+FHtA?zL^Ip)J zqAmbKo=%;hcr8X5S?a!!142ld>@`QiTACD>6NaU^?39DWW&a#FbOD1C2XqMqL=%7| zVex{1E+)^EaNe|T=75bOEBqy|ePW0LCN-j zTZj>sFt@Wwm{?hssiPgO0-1RvK;r`SfHUA#fJW(8vmu%?{__-f6V^JRyvk`bnT&;i zrLtd|)~{*l8G_OP%h#>;^;@>^&?yT1b>RhTnQC@F{-DiGH}prUwv-Du3!u7(`_iIj z=KSvAdx@ZR3Eni~zAh}xc?}Ag7%ls|2;0WR%AkOx9>$}T@I*sQUVxI>!Un7lt2STD z=;(Up=Ju3lr=4nAn+qu0hv5#qxdVFF0rH|E%Xx~*V&eJ&Ts~FKT~+X~0dNFZQM5MK z0y{cj^VE#D0q1~y9(+fOVUV&mr-2(<*_!!CLDJ6=C4GxGz5q?CrAdgg&K#x=fApK5 zFN-tL$qqlo>TH0cEZ=Y~Fa4o^<7>B^ZG#ywOPGp<7EhJ9q03;_1ndf_=wZYaT;M1g zBUPz4b<2;G-kdh-BxX_}q8>`p7Tj?&Nlh1*^2p}Q^pl7Sp)S)IZ~-wzrxVI2HkAqw zCEOje$fB*lAp*3fGk-y|2{Lw70u~U7&>{1p(lphw&j?t*h*CWA@Pl^S2S3@|`oT~6 zV_&MIp$om(MiV=vXJXlI_-H@nwo0DVE4A) zk%5H?fZ(pjiraHzR3JA%5m3}T1!{A{Ay?oA3J8pj~;Pha=QVZ$Yf*~UBcpa-AA-_^GWKYe@TElPqb%6cULRS zr8_OunWc6+?HU~3hCG~@wx=i0k@T1vS=ok!@-7BN%Erz5`?0FWhI2McZKqarQ2`D6 zw>`qt;r*=Iv?0C-D4J~mQ3*3@pcLaEtRX&l9U^HYng|6DvxLVRE3iV{iJ5bFGygq# zNShwpY#vZmxu96Gln8qkfYd|#8d$#eVwSBrkGb7Xm$i1%wKf+~N9vAV4{oPF^21;g z&_qFGsp?rnOU?$a2DTMEtRHZ(W5o|*Q(yjJhfs4@J_HH_`}6e#(|o4^Psu% zpZk_??S!7VOk0Ak3%HpZ1R>jd^V_Oo7&LeMeva;aA8?dp!(Rho@&{DWCV8ib(^~YIg0aYC=YM44^RY-%c0tjh< z2i9nKkrR+K(QFde_EKEIf^3i+)F7;AXfg*p^2kGc{e2&8zVY6Vv+ef#%GzQGbP}Rt zYIe~@Ri1YZJMVdX_}f4GzxrSO$W8uz|Mw5^9pCX?oXuK#;DcbMkUMJU3>^g{bteHC zB|W;uJv?l0)qu>~h9&9r%Kr2STqgA>V5bbwP~MU@8suq`o}L#yM^dgtVicsHL~Nr+ zGbcT^vRbn=*vwSak~DTy+AC*(TB>uGAI}nb0vm!~apjA8m%jM2`qoeG=zxbsL>JZI z=;0|la`3Q9vEexz+0pI!cSH6euFGkHuKK|q_DlLZcVWCMs2Tn$c9Kt`v}x8aAblH& z91hG4!dlBGTJ9e97dEG7pk~s4lk`8tRR0mM_2+H@#zc#-OGiJoqTN!FaX zfj9;%>EgJT5fQ=toG?xTypb`Xo({)C3OixDdoxdVX&MMZWrbNO&%RKvc>zr=Z1a-A zSAjR>S!j5?UxP7GoGEb=l-~;mQb1e0f$a4BQ0F3Ttz&eAXA%=99nyPLrrOJ>m_(%fTN3o&W|J zkeQGTW`Qe!SJE1Z0T8A@rrM6Go~8ntIn&cBXogc9JMbRr*#`=X#h?RD3cGfK7k%5` z=fanN8_kf?*NG0L;~vwj^_*K-6BxANdvPWgg9XQ(I6D^p&lA^#%8*D!byPe}+8F@R z;#?m0k#>?WQ4N`?D^cpnyG*NsCTFrw(J^%_v?nbvkg& zQ+)DtNeiDo_*mJtb?a8%|KESD`pqBv2hCso!hdDk?YEZBf1+d9JipOJ2XGGW{`gnx z|L`~e9slm1{DOVXFNL#NK?1CoSR9+?%xH7 zHOoQN?DyhHR;3n3zn5d^@0LM+)*m~19yFC)_I0Tz?61rv2b6tjo`5de2sy4S=g*2X zi9$n;m+CtghVdE8*4TBgyrB>YoD+*Kx-bS))76m!2Q4!yHc)v6lWp>9m#1WBOmXsv z6A@V6A$ryZ`J0A4g8_@lF}%H;M%qW_6JSzA>a%1WIr~zL;>Zolaz2fh$@z8XoW=O~ zGGNH58r`ISkK_CH*#2#g0w83OYctP0-%`>>#T+O%4=TeW-UO^6kKBei18fw9u`021t`c3% zvM&CeI`nyt9sXo#>)3O|kn|bI;)-wk8M7WfoF#S&j)PZaKxLrW;ly7 z0oc|j9^)JD|3q`kdp^R}TkdIKx@=v33d{&QU3AgKC@{jz?!)!R{@Z&-?)c2D{saH` zhnw$x=MQr6DbHzNk~4u)!cU%Bn1X}4Ibq(AGcKb^njXqb(y|4}%u>5u zO+}<{mE!q)Zo5*xf-5@U&l#@dya!vLmM7k>C0YvW`N*Az^*<~hKISqAd7In9c?t1* zI-5*W*SFI5cVf0m`XPNmN;=twMa25zkbX}AhO6L?J_QU)nKOW=%eqq_I>zP|z*~WR zz~jJNNJIDVA^dF$P<9#cS{58qn-RaL@r1PAO2c zi!QpbVxBiT*m3t`!~glS|K0x8&;L_Ca@QyA7z3LCs}drjw?aSn^XKD1|gJs7F1yY8hq^Vb7y$rxxvD+k-K8EMz^0H1&PFTq3#DtY1;qm`8 zluf=_Q-&@)up%-*WM}z)n2y#}gykL0X!m-Qwo%&7{J zW!n=e2id0S@P;~^D`?W5@}4uQ<$i4`lSYQJW(h@}urMWZjrzQ->3LS8p^(s*o*QMv zXZ=?LtUhBStIyt8zB#9AbocRGv+wZ-nLd0F>*W`{gA0mpaa<+Yg_x1oGw*{C!B4Y< z!cg*4 zqLK5gVfa@8D*`swgpB1qKo2jr!AJO3rCHgB}S zYyr!vdD9sI2;IEQBv~m}%9;fbvn*FOpK2HMCp}mnnv5J>?QYFLoY$43mB@ulft5m5T=6x9$2c8wQADomJOvWvHo%lFbl^KxAeGCsTZMI&v5>@^BLJE{1~v-p-M5cV|IwdUzy9O@ck^d||KHV*-1Oz3vpWjdDVt)` zMHgKZ1FxyM`ljFiME%cy`2Xks`PY7hdyhQEDA+_h80BKzgC%L#2A(huLl@hUnw}`r zs0L$_@Zq7nqg`$+o4B^^lz4F%dz>Nr_{$w$zr}pzMeR$O(XAonBwE z*9^q#zzc&D%d$dEvfK;^6_@45gb2o4_{Kt8Vw&omgA@Dj{BfGHlNtZm~ zEpWn@3=fmJY=et=^KJ_Jk!%JmERfnvoh=q$VbyZ^awy7+RdXNeC1CwrMI+wcH< zI&nbjZZe>;QZ~+Vm30bKS}8APQfZ!=8K@zSj#$OX97OajI6jz~0R?T*5aD;vcbZ0M zOKFdph?onAS;~g>7TByVOin8wm_J$oVkM`^-El|3RGoATk?FZ9SP$$yqp=zsElJY9ecUluoakt8pi^W(BiIbD&<3+ULNjdpku{S zpU}R;olx~*^`;jUJ;=eyB6KYhKy}*jwiyQX-QY*CN^pe*P`?)!Yl=I%0Yi~$927ik zV_|Ks>NGZ=|9B&CJ#Z_qOOR+a4e}tG+AE;unY4z3Tatd88V7~-)xz~SDa=my=C9eB z_3Zt?*a_HR`Dy$hmLKoRnZW|b=iR)OqF*|D!e4@usu@8q(gZN` zQcDGHf$^bf-l|tp%D7t0Mjg(W65!w!R3WWhl)}xT`*|n_Se&`jhl_hSFQUVV;WA4U z88&V*GLI})^sxw71X6XIVHR&E2duDZT^K@!d32MUUv@&IPUm4;4;TSI-qhT6(^u_F zfBYW5>%*U`kL}+HRAq*$>R!;g=wiv63k~Y8zvm01Pu%tR@a}(fr~T+p{UjHTo<%+X z3TK`Gh1Q}^88zfm=47d}MLRRq$oF<2!Zdwc9Ke&VE>EX!(FZkYW42vidtBO(>gTmO z66Y@PSzTDDOX?KBvlX0C?K<+`n`_%?s=Ld6S`NK_r0I33=S4SM!Y=??1vrgAhO-T;u0{pb zJ@3F(9C;CO4e*IV{u>n&p@YB{;4EPM^Y4z{F*e@;^oua+aex*#bPpyp7XWXfHB{HDXV<6NJChS|jSAmLMm334wckC9X4}Jouf!=eN`t3_VThq$_(~!&G@Kb)-TYlOx z%!il(krP;eKQG@sz>*eIvk4lLLiaW^nTe`!s!|4sLdYR)I<$gPPdW-T6G!%--|0pG zUdxt{df+7|#Q_D&Jvi2RH0nV#I;)a;PFZg;<$iv>Wr9PRYVP1h*%oH*T-cZeOtm;* ztc>^ojd_BamWk=yf}}xa8f(3hc3y+sd+TlX=l}R$`)~coKWM)4hkwDb{d)?aIdNKm znq73!g_W1I$+l%vmy9+&@WRLUvywBY2z;G;c-q&QVC5` z60H(2GSvrGwrH+X>6Q%UDW7bvHG+B`!H)R8oPe%52pLkv6Rg1!?~FwDxz%Y|>$UtC zT93*9L;n98mlc>1z{Qi_L0PW}IhtylNQJ51pbx>$JO9GoC0Ad#2(7R#x_%C3rluIo z4N__KuHmd$PL$XKNMH7K9?n$2gz_+$rcp7NN>pgFkhQRb%RupVV_7WFA*EM@Z< zbZ$h_OAPhjF{>zb;xUV{3Z4{1mZ#y-UxHYtg|u|TV|u%nF*ufFv{a?Z`OJu`)~1y* zRN>$?OsqJA)n{JyEK22h`}${%rK!<_;VzoNLqKjkjgp`$G!4u^JZ zE%($oV5eOwO&48sVZa0&AAD1L^W*)0`(yu{-~GUE+YSyf4&Emx&Ey6e`pHcy0n7XW ztBlcCqD{}zbI`!F9ihUMiRiiRV+syr4(1A=`T|A**6yTk$^Is3_Ib)b7|Qa>BgH06 z%gbY10c0ufnI@p;z=(#agYpnqKep1Zxb_O5ccOiM7hTxY(c?BZJ8e~qoJ1oTjt4G{KsNq}t{=#Rn5&DRuS%5Vu?7cR?v;3)O* z9`L!mb6uF8#tFtM;F@y$M$*yefCHt>S-_eO*nIxtZxpf9Z;s&_ra_LzvtRxgt2V!c7ysbD z_7xk~GMp*@6&3)?C|DefYzS;dcLDn>Flf9GX@jASCnH;z2S%ya$=%(eQ+W*cc|g`G z!-XxHse`*yqLOtM9)|PZ)krCVsxEpe<=ElUG(6~BI#Dp%=9#QcS?8rpI4_|rW!X(M zOvARo1WiTJ&A^q3qvjN&VB^5SLx=eEAHS>m?H~L5&HMiOe`Lo)_mz8T8PGe;U&y-X zqKl%vIe6-hN9+IoxBk8VyI=U1e)I0T=m8UfZP}t{W+ot}OX7uTIVqEv-lS=j%5<#4 zCILLv7!42Gb90}ZX=RCdkb{DEMm%2f8wvZWfruIzWeG1P`&$mo==Y3yYbM7tO{ve@ zJvJbf#S{|}3F$2@>d0#Gn^`ny`PR>3L z!$^%t)N?V5i)qNda>F_%*Q|a4Gd6w6=xiR^y@SKMwqwQQM-Xc@V2u|?8AFEaJ(6cM z^T4o>De8cE)WD1xg5ot1n3<;IHLK>wiDKMqL<)AOM?EJD2zA953)I6QK^+TmgJnv8sOv zn4!>WTMUB+<@dg}P;zOHERTsiU(1p*dQnElFAr(y_3VC*9ezIy_5`-3zkoabDMm-n zwCld-pW2z1T)}V-96V{g>vSy&LdQ;5U*t^lXaalC%U_^!3~)Jp7TyLubwW3&avNI@ z?R2u4E}do<@DHPejNBkVn__l^Q2oPA5}e3g-q_q7)P9lYOl!KfDS)Q;liu&-n!PESnVSHq@mCHkDiO=Y#I3E*Y)Q$s#g1~U z#V9Dvl~2m2W@Bw3lP|JPPo9$lu7;dzW!^Tx^0ljb%Qvk#<;Qtl^q4xf-wr&z6>oqF z!;*{+0|Y1}zqbG-v&c9O91p~vNOEZd`?IlO!XTwA3iH!rwkqIJ0xr(mF zM)M^KYFc5`j&S*R{4D3c_$@R;%$tbX;f1A1mCXJC9t>;D09`<$zbecsJlf92*(Y=D zNXyp9P&6oM*F=_RWNAiPi^T_mj6hW&IHr$h`HitmOrJL}O8ZQ6?#g;1fGKQM#0aVU zvC>FoSUOgmh7BWVd_1)wehMm;@V@1Pn2M zz!c!iSWU_}l<%q?hpNStY6t*Znj6mQhcvnppjTE-&N zV`;gtYVM5BL+Mt#gn8M-I7FI7}Uc88yD7aZ4 z7zC`W4y?^dU^B4312#{7d^gZ5Y|R1S!q$x63IA~~2QFnnVft0VlH6G-TqRHJs(h@1 zx!I@w+6f&FodPbI{yf%cVB6!ibsH`{9Rmp5Bz3fi-&4x!-uo zJDvc>gE3I|0@g(rU5o(B<_OGL0%%S8~@bM|CTWDp=WhSnkb z88HMz@Rs3=gA_?p;B#|3qC5J!(G_;tRhO47H4BR_y0FpV%#gwC92Hm<@2mFP-8~wZ zCCNcKOIz95dLQZQZ_Xr4q#`U$h%4bKBRV$|TDUl6e*dS`>h|sVcWqbO`)mRp8@U`u zr4wTFe^Xli`1nM%@{El@)q$I*bQmyb_HBEdnPW%j^~>5|^yBg}p*{#!=}m+~G~U7W zCf9ozlXsS0yx8!R22RXa#NE>jL^lr-I#$+dy1fEJfU1b1Py>Lx~iZj>RvtMf0 ze)m6S*_!3lbHT|Rkd$&`eti@!c8d=JkAP+Y(+rOqT*^p6UDpdxr!!}?I6X)wq{}6O z>$wB+TijzyaF6K)m9QKgkHD$U)&-b0ZpRHn%!8CUl6ukQHbP5wuJ_n$X^@=yL9Pk!SYfaic_7hQDG1qLjGsp;lJzxtQ< zuYUHQ^YQyXV?*$X-0#l>_-cFldG^YHN^Ph?Q25(6a3?pc$r!KzZOp!PYE!ao17^7G$E8I>n#IdoAMmHUw`iTKAgoMf^LEKUg1~)(t<8#oM|%RtQN-n zcMmSz7%{E9)UU4MWnU6=Au~LiUaqn{7->_W@R*nH29B5C6w=|fx~Of!{J!Oh6q%`D z!KjFEzTClN6s+d~3hP}Trezx;A_EhTGm4mn@?Pq~!pmQ7{$R!J+EH6Ax>t>X@=%S1EG#vW%?SFMs{V#v~7x?{;{0@6L`v0wshGfDn z$_Kakyk}-)BZe7PCHo7A>0uvD_sl}Gz0?>yGX`d;Bi3bd+*Z>KT`yp; zIw>pYY|50C^XtOG%*>0eRZTs81$2}B;(LaNc4=k$xNgcmmt1x+YtLD)gR?HWXbHmx zLuLmv?QRt*7%%Tuxq*;p;9O1^%B3-PHfxcU$k?NlPYz0^j8Rv^qD(v4 zWVzjqTtn;5&E>-}R8lbQE4AO2G9LExrV#E{pS2MfJ>?CAx_9h~<2!b7=;Ddz(* z*sg)&z(~Q^HUQQEo6mjpfwu#Dfd_z@gsrKcxk6oj?Sjoj+*?Gnb>tJbt0qPQa9Iz$ zp5gex4=|j4NPwBs#WcuSc+3Km)s=7hzc}~0*HaInY2qwYVs@iIm|@Wc4igr)rH#u+ zIr&trf|0>MCs%B5VaZqo9+6op3|EsO;`%(7FxG1>CCk1pQ`S~kt?@U+<9N^yjb%(a zRYy@t6K7wS6no1xiaan6s-l#6Y<7m5{^~>idq49}nved{ud(mRM@z>$*1d3b(M1<0 zn3_J$&f6cZ|I^?8PyDyv{BQn5v%7$s%D77zik<^=TCPNv%AI{za4}8)R8yRMou)!d z`urs?Hu(}X=2h7McK zJGZ~(!Yv|~)I}FC~Km7Ix-<5BIctL6Rg^Bc>(B}C2S&80W&m%yKp}i*r_suo4t7QOyg=`bHT=3jJM}X zO8R6;M_=9no6mi`0(c2F@azIeHD@9stJBjsUbK)N{wO>nNnkM;0o8TZM%-M*UH@vRoM+ zS*+#|A1ZNnFSaS9KjaU?0E}j{dXWtZxTc^NK$8l1@bURmv-8OY6zBN zX5d1?mJ+sG31N|j{VgW_41o=k>zfO&yab>FAQl*17&cosb8~aM#MK3nYkp=(Jr1hMqEVb#y8pd9$hH?Jb>wA`PnbQr7nm&fzVXbXi!Qq8T+;{j$N$^=>=*y?Z1BPKKsX zs@7&Md8DAACH1fn_Mw{D0j4gw-eMd?o<^^cGOfr#R&z$sq$@=iXee!H}5 zIc6PFykA{}I^9V_UYC_wp8Iqu71Zb&TGK_(;gIw@h4kVrH9w`LZt6XK({Dz0N!v z53?$IU4(I>;qis1Qe$6vVbIJ!6JVDRD>huh#ELT%*gS5al@)G5|mlrDxuGtyg_+jT1t81 z!+~f}g?V6J%B-GM$^tbk&Wwc_Hc#aeT+Wr@W&!>M7e;K^4+jW!8({{}ZQewpoKvX6 zfHVC6_6l3d!S4C$*ZJe0{e|Yw{^>6bpT6t%(y2}^adRLqpDw!S;?#+8pjY4et{d%N z|MWlizx>L(eU_$JkzquzD-6b?&SVAvm@xh_XYiao7{CfSjwia3vVV36k04r|u&wKa~{SM+f zVZ1fq71#wAUXm7Rgm!lMgwYnsMPz<(3-p0K{GP~$7y^ZUdTZB8R+AL8VsqAFRR z^p*0OoZO?iA(*nOvFsjALiT9|9<2ra^#$l{cqpRarHekMNg0v4i1nCg2x~v;ldD#; zY{d#02X}F*8VDWTwS(z{`&HUbGe@KUgPRb2;x!aA1IuAF&D(?gnG-Ss9Sp)Tg1KzW zvtlq+k^%v+h{w!b~eiFb;m+YZwn&BNd z(^yq-BEb>NRDd*31v;^~3^+5%daes#JOeB%xZA1@*nIBdjlemvo)Buw;2NJcbOg<0uZsR9Ka%wsAw(U~0g7QIw2$0S5mk%s|Qo?BA(!-($ZD%Kp@ zAtpy542#P+CO1YXWh&ZkfXR!fN$tT=-6}oRxJieb*vDFYLF|<~VgLREeB#%BxBjEQ z`H!2gzw13Pef&92JMW^4F1i>6#)pr6>E8Z-{#(DwAAbA~IK;FUa1+|ie#~+soE&%y z6=mR=94j@))ZkH5oc2{~^2d1*HfGV(~Zj$0VyS|$M{O{;bRrt?&ITnTw5haO+P zoXIt-mISET0h>LJ9o);2y*uK6eojR$VFe^C1$=(gCeMAtsFL>!Q(p*(WFM;ZcuLI) ztWq5z&QHWrL1n4`6=LR@Z{%%}~>FCuGb3>m7wimYMP=HOHY@aFrDX%4swg;Z4`Dgkt%ttW# z#0fJKGeJ4C~YgwMd)B8?h2y2c~#*?DPM^}MRZv&)$|Hqs)Fj?uYIHW)4%sG zo4@>Lzrv1(?*;m0tIE>26NU?SAmd=D+`)|6KjrAN?8axGE$y{>8h3jE5s z&Hhtzsezm&6@Rwp22U3EuffjPyt&zO{#kj-Xct}Nx2D%cgkC@}bNO!IGFI`hPwph1 zO-9If&+h+x5+~QdoZqHt*xD`={z6!%{YJa?XBAiFkuo&1x{@$OgOheG1lT3h8m2v* z$hZe4mQVElkIrV?wF^IW4TKIJwnMv~Drthrg|4ou#H>FI(;HbmB!YgWq=-k55=)+O z6)5Qia9pz|<5)Y$n*|1FqJ3i#^vt5Ng!b&v8-bN)UIDDoiNRCXM5u+eS=T$L>j%RB zTkcrqQ5UXyra#kwtANRZrMci~Gv)84zz~-|b7X#M;4;CbO0C-?+lGxTa#n%2Z z77~sc0SQyHN=<}vRsW!`Sp~M{%+Zem$AHo2%Z=+K*OBXLt~vYVT>bWcWMj+6d^i^d z9aZ>msLDE&=8j{abbK76(Borgjn8+!9)Ql6mt)L#v}J#zl9@5UyhT_{9MiLDRWr=0 za=8CV{>t354$FOn}>gJJ+8I}{KmK%5|?=q0j3`~p!d@%t@6nju$AUOvLo>*$e5da}wAL~{i*R`Dj z`qaRh$u)l7CFe_tF1lz5bMv|}zz{hM15eV)HMGxBefh8`eMH!haX1p$iagmVZy&Bi zwXiH6t!Uk@{U6|x5-$BpE08Je%}$85m1`F`#mQLpF_M0_bT>Qbtq zL>Ks}Y9PeH?b{g62IJvGzo4oDS|bKLF^do4!&5vY3VbQ1vh%Vm7Ot~O2tI&}1@V|+ z8OG`n+$?2me!uy0uFOrtgq>)m9y7U-R;;^(i4~iG0eSfIaGm%fw)KFccyk|4qZ%Mk z#qaai2ufu)77>>f&~lKcqcc?qMjL>&9kBWA$6E?I|7byyhq-YO1Sj-0!0UkCg5A(F zpxjbZ7h&*;I836E!Q8P=GdF!tVu0c=AUEY{Mn})&Mc?@kZ2fuX`EX9?_3FAE7CcMO z3uQ%?m{4BdE+&{haIE>ufB$Fv$6x*xyJzZg#(;iI$<}^bGPq>Gt&y^wOt$5#z=Ro^=&d<< zU8Z#_5SN?u;=VA4@m97I!NEO%p6;3;lN~FRCu3&iTBUi$Y5H5+0U-3)QeO-OlS4s| z213g)&cEaWV59>e78YF`cdzTZTvK{q3OQ$=vi5 z))P=OBKEpt^qFuFeao`DFen{7`X)pYisA8L1u@+{VjKcg1_GCk!L=jEZT>N<=G!PU zj!vYTmyb6vvHBb)*Iy8DpyvY^_h&(O(|{rM;1TeBI&*=wyFe-3dlByF z3umL9cBVnIKviA#rk~;5>)-0lFq-M$7H60wwY;pe;I8IDQ!@g8t|miO*+-bQZX(DW z>Gm<5z0?7evXxMBET!8x!N|vR*VM9oeqA}1P6N9+l+9LEV3MwGrQO8ofg?wb*{6Qv5B(2+;vew!cfA{Cjswe2LoH3G zi!PREbdKrA>gI#L@*aNiAN?!;`hk0G3~UrY&0~^Ob<5M0-A<6_EexZa)hS~iSw@$m zySdMQr>u+HV*Mz1A>Tc91JA#^N|Pt&OA{C3vU~ZofDcx-i_vIqx`8r0rR^SBn|jX5 zetA<;u*VAkVdtKI4opmTz~%y@3!{gn>Q|P059{K+ZrM7MteSR4A}&nt?4HU~!?Pqg zDX)D+##j_rc1*UpPP()MkXoj7AD8XAU;8ms%UHq6(5L4UG`RzN(5zp+VJ*<_`V|fQ zl*C_-?A&2f2M+{)hJYmmd9;K$WyCQln3;^h0-Mto?IX`7v443;N>=GEE9*vIlVH;UN&@VmBNBQ$yo`%u|fxo)Ny zPiSFHWmm?KKyf{ppAoW|YSJ_%dI%b#WIlXENkoM^ZK%T}%|V@;=vQ$3912X^`KeS6wS zRDmQDbfjILuSN_Py0rq1rr>A5JG>20ulr;CL>^pDUKb(Dp<3~OYOeMgkpM2Nz=Oy+1 zI1_6xwHLkpAG3VJ8isR%Mmqo=*nmzZN*ox1p={CMj5AJU9pHwG{)bV3ISU=A*5i&V z)x&hkRkz0ux-c!>{kcxSJ*iC>|o$u`tuJofA~}Xh#PY)UG)9rgt`Zy zMigtz%P}@>I-}We=Ee@#TtIZ;FlpBB_0$#J6IP;oZf1sM<~;H}_B}dDq7L49%5=&k zha9{#K|~XhWS-F~jP7(&DIC)iMrI5P=PhqU8(1uDOAu8{_IH=%O#VZd`>rnV!m;u3 zRm)(aV{GQ(r=Ee(z5^WDvmFydpk%hrgZ!6f>sb{t5<{AInpuJc5Yhoji?C2e08z(r zkI!g}CcmK#VeDu@12mM6?^hXFFGJyo`yJi`Usac?2_WU#17lFdW{G`(XZN zcIo8eMG$ZPq@!ARoCjPegu$2reYp6-tSc$$BOS2$%wrYsGT`ZA8Z@nJP5BJViGNl3 zk7$n+u+k^5Qn!T)p`#5|qMtePaq8KJU%>i-Gr%&gdh^e5#%0$roQ;4ors>~+sZw`Y zN=Gc3m4YxptI*j>$~E!f5ZeK=jm+vW-)3TNWa0Skm^@Sn-#rfYuvA(jw$JAs*yTZi z81|&Pm!W2H*AtBuyp$+{&rWcSDEk`npc<*L5%8zCJ#8QU#sB7i`SbsZ$8P-^(CZw} zyXc~eB@!dRXnn^Azh=MubHBuAAODh7;3Ij0Mhw-pL{q30M3fz!ob5*&qftRh0U%mg zL|)3Z0g$nwv5d<$$mjmrUC4uBQ2-8ei8}>_a{xI3M@WTb79M1nm=Hg;u#+ zqXpKdfk`3r@L-d3jxBE<;JAs_4~8abG{lqasYFZ|lz0$+WemQ6vBmb^L2x)uzEJy%ieSV<*`uK|FjP%C3K4r;d z&CWFkcRcCC*@mi@iLc7d6B(5%dE!b^!KiRaweaY@P>IVqU@>!%QcsGBh=_GUNeb-@ zCPj{Ue14h`kX(RQv}1#@$w`*2x#%Q6Km9pih8j>&*W0n?iTN~k%aSBIyVvMsc@n@T38Nr z`&iD*;vf(#Q1`v;DgVDFqozE^F67RbxJ1auU59Cub%sk>3vV=D>a}2k709A#L0f&zqvrqqz->v`jr~gTP z&nG@k@qq;@PT%nI>7t7+PET-ie0a~tZnaCa#a zNRXI&82K365*Kc7F~ZO>Q?{)0y=7U`$5UW0J~APfiptVBv$CjaP{QI8P(zqblHRW= ztqKyTc~PF;YYEWe3T~^(Z4Hcpoqf((WwNiPi!Rz?g39|<~%S4gu`AdzF^5bL(aix81%XbUMP?NY^ znj>k8xZGPf%*3)~jIS8)Sl~+{45&G>Zzr=;$EbP`$G}vHe}m&5h%h37R`w4Fy$4cF zDH}2--HGY#7=eH@FJBhenQ`1aU*2Q7dPrLb@-&Z9H_W#~%y(sc9Xp-|sy?jPcrmaD z1HR{#VCK2bCi@xI4`Kj;ty!7Op6dBfEfM1c<3iwkG3Jio=JB#_L-~w$z~>yua6d+Cj->#O-~mBC=4ZN^Wv5|mBiDZC zKd^P@UugAQNN_eVi$3Jwq$=J{?AxLncY zhNryTxL8_>#)(8e-7SD-WtuJ?XUGDxvuu+WQgBVx4;1(kV$kF&T#aG<9yS6z_3&2S z_s{=*^MQZ&pV0Wf=7XQT-G1dC{EC0#!OznZa5D+ZBtisWa~a?} zc}h1a8&kq_Ew?NTtvfBN8j}e*K-rHHRleRKXK?9pv$`B|@UtBuahLQ|Cy&fvN$ayv zpGdc(K(;>mE8xt{n_;2@A-+{~;rLip^+!fb0L63yB{$E(SwOflyxZ?f-L40=_*b?| zXkQ>9Ozq@Yo-sLFP0ZR;#&ct(XU^?XhPgIX`yCAneV{1|e|*^lqZ8vxVxqlEM>oKk z*}a#Uqlc+_BFySC9xh~(c4sPFXIt^Wo^&O1K_%4fU{;%DT$rYiV|nMG$FWjhNHve+ z`XEgw)aCL~fOB&FMU0HB0fr}&wDs(h%8JfrGq@jTN<3Ub6_tu5L#1NlexkI^6@|4~ zCD>Y1&h1fPSz&Fi>VVC~$1BQ-+*3~MEYQe@fGiJyYl~h$8twL-n)8*>FRFa{(qdY0 z4;r6g>hOmd4xa$Vo^9-<>lNT|D>IB!*|dOac@-X14GPb@cC^a-QOyc0ZE+2 zQek62sqY4aV|%GT&R|8r6i?_ZN}q`z$iYlAQBn{3C(_|t70QPugtB3KSsVVAdP3hX zLewA+jO?7n{VC_!a6&q|8(7)qU{wX96<&ki`jOB1AO7us(tP2!evjG1hl?&puX{=A zqKht0BXDzK_|T_r>;2Nt{X0JO*p2jn(LAkNfd&)f8rR2&wavMP?NPH+kP9~jQZq%J zHeJpZQxXA5UE3#2qcrW4+{DN9_a*v&F5qhB81LEnYX?5_WF9dB!t&Hvvv$U=={&1} zHKptsXKrHMniU47f4_HD#7& zKw=Kc>hW`Scm^2e?0G=hsc9&hlYG#>3z$%H>G!2B`Tvnn3@Pac$0jHG{fUY0y>v;u zw;Ryo_@R9qKd>)k5^7fAyiuKGIeOV3W6W?bS;)E*$+B?Mm3?r+__6{IvvScK)?$Vw zfQbxR@R+bT7Okuh5))!kR0NbUb*jOze9bvbtUgnL&BcI@r+{<1(+nTO>!(whL#q_% zPUzkawy4bftAW)8M{APLbOAKad1mS89kBUQ;BYz7!xk5GFJ&f+Y0wA@4Rc+QYAdSH zm3#tnUhdYp>06kY`eJEcfAMpBr*wGB`dKzz@+K~Q35iSIizg21B-Hy-BumSd+(4m}$n2Nq#&|Z>>WRcba5;>|Mc!gP>jt5PnCgGU zwefr;m$$lOdYBC|LWI->%O@G}UJphqIC}WFeeQq#q5t{M{Q{4C>2m-D&^Nm1qKht0 zujm02!$&@Um;LHL`c*!&^~+SiNN$)ziyq}dOn_qgwQS213lf7OM2UK#_lY+*&UmBiPoHN1N{XyC@zud$5bJ^B_uivzu73)`bz-AZi zfz$Ly7#kmV#9iMK#r&i;9_}M>w{3SAy0j7n9?lvSWe4 z8+{p+q3I#V(8E|S3|A8kPcw@kDprN>I=hF3eJeccoE+RDI49YbCK7R|>w0;BjxXQH zs#fY(|`Irr>ZJ3Ttzs12#`Q zE-WTM+Y3@Wqc-%KhFZ+4TlGq z&+Bs%&b3vgxg#UksKJvDZngLPlV5B;@XvpV{ZBnyI=sDb(jDQvROeBupD@HPui>JfuLKM7^j%9ay_zF8?d!&*Y(z( zv0kB|F1pYd?f3eOj*I|!oFGpVieyuN!}cvVMKw2tK?oxR`}b zPjojkn!LWCEId{LSA`7dMm_^zSINd*53KHh&Bd`bYhWM6Svv3D3`qUZ*u14FJV}~e*<@QK9B#2rQ>vy z5eNFFg2%ruH*}H`ZbIwOnO`TCx0ada#91MBJZ^X#v?xd#!C5mLlUb;0J{>@RjysP2 zP69Bj+9Rc=T)z}ow>lyt$b{)y9&lJGP+_AZP=nw0i7z&P`m_JE`O@$G2{SWCigZMe zF1qNVix-Na(7hkNmH+gQ|AXDM^H%EteE}2|2us|_O#wv*Lz$WiC?@Qw>^KQXnKGvU za!2!4(vq31AOIvSZsVCQpeG;662lKdp!r1n9hGf!$l=yceum=Zcp&IAHA$LeU<8n)=4b9DhY z=ajKoKF14bY4eGvqj$jONIAj#3Q9Z(2y$IMNE-V30){RyEH?~l&r1@wbQgrYf~J{b z=E%oju=5l%O!1Ro8q@%@oN@V^?V?xzgjt2xgL#n6%8n`wOoc;6JrDYu4wd0hirIW; z>hpgcFkvlfhB;JV0T`?*+&!6vRSU^dCW48?{Zx0=l|~<|lO)yLJxgg1scuy;JaRR% zD$O++0MDoNo5h1!{^AryvgIfuI1S$G!+0O2kI&lYfBjGV&;H&&=b#DDph|H*DUbia)Q{am}!bB(lwK^dZwF^YlZ>6W=RWuA$qsnjWh z(PBCB@NC{!U$bKS7ohj2O^N$?#%?X^6-7-6eYo7LT$-SOC zm8aot{YWmwp%W1?NWV+i32Je=?k-@jNwvwON%|YC4JPaN86E3@&871mUja>Xbk9!a zrlzQRi4{mN`N1&6yvImxvfyJ8DsyoMv$CgoylJyE2{n=>YIlN;zb$BY#x_aTAQtMj zc>M4^G|5%IZTY$j8JS$Kz~(7pBIGBmw>lU+hSysYxkGg!l(ZCeQRGD95@3s_ql=GC z1#B#z$qv{&v6H*5m*Zgj z`4O3gmb|IBx~!RW29hFcIm5 zP>DHpSWY_>5OWevAXXRr&44;dOCJJ`Z{UaB^Kf17N&3sE;iI zkH~WuOp00PXh5Il6t?Cpb4Nc}bO=UYV1UjHFj8Iix}RqAVE_g=39 zHM{7dix+r|0#<+KH$LJ2?Z5nY9<6uTxTYk7C&oS&2HP40XKo`eW1i8w79P0yfbp_{ZL zzxUgX%i8;;w2#QY>!eUPFRehR9@g?>1kA%285yICr4j~IOdZ_E^pOK*mE3TdsJ4U1 zv6&~jlzMN(boP+yZh;JwO+-YX(=prw*VBpHMflA?-(5nwyP7ncbP!(Jmd_R#cmre0 zRpj`_+P0W%DT_k$0D4uu$1>*S8oziqMZ=vM&C0r7971*po0XVDGa zPvM)f24*ps7KP-OS=8xtK9F(dNG$c%t0 zhT$FoSjRHziW%-!R`;;cF{m5-miK+i{`l|yllu1e{S`1MonOTZG4i2n7hQDGft%j^ z)qj4E|EK@@U)aeZmL(JG6?g)mS&~c=Sy^g`=`P<@F-Ou&mEGkFaRv^@jYT|@BF|V? z(pIzln3w<~O3V3l3@?}Sl1NU04%GykdYd;&&0%7 z=ZxMKU8<}vU$xxE#wR@D0VMZ>C19g&6HQx*#C=@)kJvY;X_kvomWkUyyx$VTAD2YA z6kLsERgzz~=kgeOU$z?v<;=`>7j+MRg~_V*dmF3M7a*~xeagthgq-y*PW5#3sY3@j zwr7vWv1c&VX?>Wu;ie|K#Oym2+%Czc(I>(nX6>2jbr;NiB^ABw=PIcNW&Qk1Li}za z6B0a@10^z5mA)WB_=Gd2 z&j`31foRwiqTxZHUp#G=cfjVt+|ZW;N6Lwu7BCaZ`LBQ*7Hk@1EtdESLRs=eG@&9? z1?2Q*z|65v!tiNjYcAdmeaXZ$lPfRbs<-?cldG3mJqYJe)33Fo79rwTF1nW!C#>en zqxvEWRz{%H4TzXzadRU&qE?N86|}Xspplj zYD}6Pbxo=QriRHsCrAPGU~~jOeq@Hv|K=b2d;a0SuD9L#RiK|<DHDF&h?4n;k#w-?b3!Me4z}{1Q5xc zlH0>oRysWovRw>M+!L@Pe2@ERcpOtCWeklBY{}i$tpe7sUq^qo0&L6qR+k8JKHU5tvRgXjuCyYXcZf4U53CNgZW*Wk9O6YZPlcojjENX$$q> zumx&wR*9X1Cx%D1fa7EnIWEO3V0?0HNlm_Y@Ak&=gGcP}?w#OZm0%E-EQc^f;xlj) zEHOg%{5e|wL^6?y(|P%3E=?)rtbEEcIw^?Zr55)f+ZG=B^Tz;-J7WQJGg!IdVi;YO z>ujEMqL}l{qM~kg(lk#B>sFb&N=?`Qyv4*Bz_~41(sf~Nt^hVIEFHZAHZKZ~f+=9G zg{?U#0;aEE0g+GpBf?0iz9LvcU8t&%o?gLl_I75bzZ9s%Cyly%lIu`(Z59}WtTJ)*F6A67bhg@=xjRI#FBs%FhR2>cZWCIGJK&;KVd)fZ zpnR(xVflkh8Oy~!*ZIcANP&muxGCp^0$=pRV!DHteEV8%`V!)eA%iMKFX-cb(R5= zn)aOBV{uyol!fI4)YtnrmO%}OJTV6|a?=wM>;2C+P&&@7IfaRIq3 zlvC1?g`30FsXUGq%l5E7WcZbjRS?IVR=~^XD*?};20~c&0Yd-Ho@0sq~LGs+i}DW z*c>ki@N7A0Gm_h{_Va_{o_;we5OFpnf3lRQ!g5HHRvH2{17@c_eS&PwEPRPE#OmUL z{uaORl|O_TG&MN5`@9(qK0li*4r=c6qQju_mFk?JZt7rStOId#s25XEFM_6l*4Kd^Wo5pKBF)_+6rr5}2K(=8%H!r37GVU{pagBjUkdkENyBnb1pR#q6i+T+?i0%=IuN3ZR^H$8l`Cz8KAxmyODKCW1^kuGNdo$r-p~1Q zqE@9E5D`IG@<4q7$HJ$2c z#CXTpTvB1cpgDecpEq-0Rp4O-4+YIiR3it`#B}w5P?mPM`8_zMhY@3%sbPfKO#xIr z5_kgh(o2Jk%u%nD5nmHe(>t`IXkdKB8BDA>FJMKdyq;#u_X?P1ICu>A8dJ?2gDR1_ zbI%Q@7H8nS0vIT$86+T&m+a~d1smvq%{`SGM{Zojo>CY8gv&3;GS6#>zZ~8f(T)o`uIfxHo6_bguoFOwn zp;I#hqR~%<e=2@#@{uPRMvPmPMq0#q70cs%8SmqiaCXjSU)dB<@Rz!V~T zR7bYB$0N+ogkkf7Lly_2L`{;iZ)AfK*s5V$JVzb@-jNBc>QUYE$*i!Qq8!hlKk-1~(6&wu(q`N9)7(Fgh@ksDi@M?K8ofUe+K4q||Zde!kb zIuRSVf)Fi$iLgu4fx9KCuEMkoY@|FDT(#<4%2*Dpwz9pnj9I=vn% zcO9FzD~V}cSe`;|_N^7kypj$2yLElLGkPADA0v<8{b4yHSHW$M+k5?9M?_dsVL;QH z+P{y%%rs`0q@Ft}l~zGm=K-K3dM$*R%A%1Ob_?DMRVkMq*UBa#(P(A@hLz(GNk^Du zQqHe;6WKJGF>%5st8&Wr=;S2J*IoeFX)uPYfSP*v1o%Py|G?yX1b+3!3SSJkd0ufn zALIr?#a9KE7uM!#TB8FtDM00*d?FP#{+$KRZ#NBUfBFPLR-sE|7Yu+Rf~>EISpz6+Inew~SKq(^Wu0C!kOkB;D- zMM^vtQ`AEzULwsDG0pYMX(i?3X--Kj2GL2LTMbo^cpaCwXm})e=16w8R`!$@KY}anGZP(=5 z*|u%hZkjYT+2)RuZQHh8lg;cVP4kRLixj0vh7V8B@X6aZaX zf_7o%d4|8#zpj50oitvBL4KzDJLpk1*BmMOA@$ji7{Jgy$fZ8D0^en>z z0#*Z5QOML5lpq^X-yvCi1bQfZ1VGvzktrute}Yk18^~J)P)O=gaD^S5TVy1jL{7XX z=s!~1tpIQf2P=`}>~nmbKfPCfzI2-%Q+PoYPHQXum&|!m0L}CEz!ckqafv%!H;bV8*GLx6;9xg8HoD$-Q@5P6xIMu2do6C>Sg_!D1SThh<~GxSTk9i-xG_pi zB+G0Vl`Y^x#sy;9QL}SLy+f}`C}d0=*EHEs6gRYfFtNANK9-4gTWC2fBG;Md#QaC) zJb7;oF(4ufAz7S?O$vD2ixy7sQ*@UDal^lZ-7^g|D$b6{JdD z>#-vB@4d8jT%6~$TtOPvV9K-WDzIX~U#m8yA@Uuz3-?d5vORfp%2F8S?VqX=jcer& z{O4q4wGGrJw=*A@PfyKCK~9`)5(MnHl%Crg64KR zvqQUvvRyjdzqLX9>94?dgM=6`b3lRE!`@3MIS8%i=KLNd`T+$M4A+By-2E8KB;Ogb^oimS73*Z%Q-HpZX6F{10|I~BKNY;0_CPgAfe{I0OUNhz5 zQ=7(u_rTvdb69W&}qV{-Q+dK?MVrW#@9)T9!AnJWJyIu%TdVc#nW#P$v zCGFM${-na(9a39R$Eq!eC0jCaqREN(a{)_MM(f_ zo&8{)?P0kFKV(8Y!rdpC5}w!Mjsw~EwhGon&?AENvF{iC9sO9Z1s3zzNLWYi-O_f> zxG5z>eq%}au^17DT2tdyb)Ng9+WO|H{7n6C<`i9ZoOZHU3>AHcJm=Is_xT)DS*#<^j7wd=8p?Ilx^C@LLXKT4~|NUnO7~*?h*xGXX=ySRm4HprI8RIk9t}jLZu2y++DqYO^4p+(un76O)#}w$>WS=w zn+$lvhCrEM#&ea>ze=euRxg|>s;v0sMOuzCE?`_AC75?J>cQYYSe{%}xlKtlYoMK- z!^$2?aM^JF)V9HrGcH#I1Y$>EIVdqQ9w(AT%FwnT&1XyW^;-l<&m<@tLM~pX5|dhQ zAL(j-$q}R)NDAk9u#f*rwxz=9j4HnWG-4AFa8P@Dn&C7}GD~91&3pHeqRWBSsRhoq zAeSA7!6%?I>!c*r@eXQ|*U&=CFMQj7@+Kt&oYhq-MGg=5wdl@&|0T1)$;#jQb9C_- z#&TDc_$!iZ_*ypO)ut79Y{{IP`Yk5HmxYlUG>#<23#==#Gj4h}(3+cFcJDdzXJpBR zvS&}N=PDa-LIT<8So1o>sM;2%GSVm&`d)7JEoJ#Z)~?z573vhJ2YLQ1YS#+=^ws^54}w}!2gnlO825^L+gQknirede8hrYZ4f6T_~m zo#$;?5(#Y55AkO??A1TP?x+O=P37X8wNt;c)590y-!0uB$*>FKxGiosQ>e24C;_Se zo);j&UoR3Z)z}`|+T{zRB^1z-NwsQ*b`7`@PmMxOz58lGa9-J&zP4KgM05Xi-y<`z zkSh=9qn}!`CeqjB+*K_@Okv2`f@VV{LA$7)8A#J!W}m#~AU4 z*}_mSXKTqgP0A`s2R-U!3WfD|az1D-PL13!V$WkjWMTc0N95*-aKM|}RRKZSI-Y?h zU$j+(DS9yS6fX|x&O1RFb~?(Gy3mN``Q-9A%A*awI$9bKQx^+X1gNA~O-G~f8j1it zw{N^w+t-RyZMT1xkoT=A5fS%!Ee)68xy{mgXED-SW$7bRKl)x(olImAB?uoR1nm(x z(kucvgMOEt+mt|RBZ5-DRjTwmy9pMJpRdOhR(T{H_DFc3)oU)kccEIyn-7G+%c6TQ zzfFpGXF=JTaz6jPdimA;l>1@&@$6s(DK%E|UlreLjdi?c*WG@vV!0#w`rz^Y4J{mR z-G?+o17Vm0X>;Z;Xhh3syF-9)r7Il&Ob!n_ht8e6bjtMo=OJqUoTqG4ghv7>J7Z}L zfcOc1)9pfQD0=pVHVkIbYt2gNkj68Rd2Zw2S*aU6Yyn3{#ejc?jxA8%j3)Upv5PFe zY+#0az;0nn+^<-fe=oA>{CR9%c9UGg8SL#iaW{(YVCZ)c;OtmKy?zg4Ba_MH>XxU^ zH?HavWe9K2+{tRZ0{pi*>^x(v0sbQAiFytm`BTCHeYq3iSQ36?tB*JQ2smV+m!qb# zROJ>smn`G~-DnsG!CxVI5f`CqIc&IYI45f2RBHPfj-LHZMYmfXErg0uMkAFqr0pA> ziT%Zr;p&FrjLZ7%In#HGn1T8SgZ%0Z>Iw`)-cdPJ6)_Txve;xRx$-L}E-_&H5hrhq zxcFd{U`!Ksr!qX2okwjY<9=P`Wu6+W-FV~69Ppsz7ld3L&WoX5(RUHOYZ!`0h*UqE z;xPs}6s?;~9pF)HI_O;ronMoBsJcOWBx2f$KTZLZVR4Xma~!(^WYP@hP za8pwSY>*O4eAfKE>kT9=fGEem44ys3&}K%9tCda5bbOw>`fTmK%Kaj52Xs`p|0s0N z-<_WQ{4Y=sj{;(HIOvYz^X=*tTA;6Im^Pm-g#eU7gqSX^6kKXjGN;)}of~E)T0*F& zU3FvQ1D8eI@)xDgFnJ$ogaM)q6pP3?;?sD+#x%UJFSXOM$tn{VlybWcotu>f^Xgj4 z+-42>jbi0wo`B%Qc}PTT!N=goX8}xgRn>yvz>;R6y zvEnSII4zMwP?4U$WO~K279l8jz9Ko$EKLH=wKXmFe;UEvIdB(5s^Di1o0;qeqFNLX z@!}2*4^|hJ|BQ_5AIM+=Dpq0eTqVj<`aKeKOzvQ8#G2u}*oS%6p;|JNj z6qTZ^RIY4@_t3h#w(>4A(C_374=iUn7lKINJGk7{#tjV0smncNEXUOg{lnA`MxDF~ z-F^=_3i)~!srxDmM=V|aUv@-6R3gbfkd$}nD>3MaW>Wg{nHS1_oR1UJR zWkNLm+bwjSn^1mOzx_iF1BfSgogP%Pk4> zGK*b>d9A+cQ&He)aNCaes1a-;-Rw#X%|oyPQ%~%L-n+|=#9_qE*bbFj>Q(^hLgejz z)_&mV?VRc6rN8hl)D{!0sCJB<(c;8sC`jWt+87?e9J2H$6Q1I`M{AVML)fW3iD-3r zEOS5Fm0;g+&_g#D>C58RKy8Qs=#ZpzwU#M&`F|$OBTtc*zfWJE>)Sgi&|W?>>k@z1 zvD2J6aS!(X!7-_>Xp1uHyEChZ4*n3Lm&_&%qO3L`SfSndP3TXk+Kf*}wr&7vI1Wk? zEY`vR{PH>5)kgf@PCPBtq=q_2de#5mXGy*aN3G=scXnfZ&I#REKziDH(Q-2tC1CuU zA#U^e2hrm+Fw!&|rx=Jz+-9k6d0{PSiA6FCL|RVvagZq$Dcz{XRZ4gdlS7{D^R+Xx z^A*TD&1o-duP~B95^t~xldoer9fBF!SeSJRj8UsYPTs0u1S*t$j|(;(3z2Us5-83< zWEm`Ibx4Yj0(WYj@k9Y9j8BNv#wVSTsKqTrth)YPlF295G0P4+#}2cW?nz#?2t+GX zz1b}t)e{9`Zq9mam6`HxJbV=w5~(L!64=30tl#M@VnxU!VYxwgPi-7{(+Oy9ENFGj z1W#&6x-Wp}WW{6IwDeP}%uM2uR8GB$g^E02;@nu>upTx7M8C}4qf03!OWN~AI`Bn=C-?pDw&mkU zSKk6>&h&q8{vTgD`=78bdHXfDdouCj3E|cp3lgvHnx2NFoX?UqYea!x{}Yjc7LDsv zW<|?HPq6C^YWwrhzbHSZFNgZK3;mqrS)+7Jq2gjAe%R+(DBTzqXHRJ;4EWdFeL zLwjDcM6F%l1)m3fBMx|83$2QtM884yCUZ;mM1$$o^M(y2f^i+R%ewLg6`rEEqw15o ziaJuW(tf|DznDvv2vHMtAx+KOd!8hyBVUsG)Xd8Yn~<6E%*d=^YQy+I5*&I@enn0y z8x88|GgZZu4U(CEVLB_hdmun>-K~Kd^kh+hiM<>>f!0!49})GF&d3Bded}pU4%~U{ zgLcz#?GreH3FLj*tLZ3piI~j&f&uIW;(rM%->;i z8k~Keu$Yt1m5f#wMwwPQh=~j7EJSM4<5w&iX`GE&xy~I4dofh=n-)k*M7>hfHzik_ zmRDcP-FL>vFLpRWs=>xyn9e9}l%o>tIwmTm7> zizD~4<2D)AEP$tVupSy3O2faJmBc#}ZMWPf)ay1$L@?7kJR4n!<7Z>8bci*!uyik0 z{6s{T@@&FSZLMK5SYL7_O@R72>H;gX!0wII!r(9#4QlA-NT`GAlUsAV{1^W@WZn*J z@|K@V!zutQy^1tZ77!7sPY~yto{eBg?g;(#!By+n50PX4T8QdnjP8WSQXQkmKgGAi zmF2&CP{+yR&y;*qjSwaaVKXNjdSgyuS_z)GXdC~tgAIh}IO{)Hy9-8;%?_-JF#9B~ z=k^m7pBMbSEM1FO`8xxe>6A87Q&PLT2cLmIGhnnJCYLac*&+oJuPZKi@(^|*i#B?~ zB<33jEzMI{Xe-Zo2w6UQ%ey~Lf$AhwMPAMee@I#TSg2(Q&yK3{Gswd;7 zpj_3;lYxPv;{=!gI{_5|Xn`zb@W4T1{-$4?j2OHe@`?Ysuo?RX|M^hO-Q0CtJ=V!3 zh4;TZwgy?YY;g0#7fOMLN-qN+xwVKVRv@sy7Ar?h*+gNzZ%$Gk0#0j@R*vNC8u;Ds zRS#Q`O@3b4!ix(DBQBVDXX0O$1s-3ZZ6#(;COQ-Z(oE(le3+Z=pGWB%FrMy~Bp#}_ z(5D`E&e%~;I+pzBbTa


eKR3NG?SOr+&-tt85Vv)IsL~!uQpKU|)K8Ur;j;%+Yr#}-hcuy+mRQ~jQo(bepej<%mOOv&?PIJ?|5D z-1V;ZIDfX7*=t*Hja{`1myNI2`OEr+{Sm(pRVz5 z$h`eA*Dh^AVE%AGaN`SG+O#AGqXOCP{o5|UiM*p;{*nK!(QE<&Rvgl3`8GS|`xlgN ztO;=ttF&lC#NQuAMh5oU#UaHbdx{ni0N<3qjo3;dAi3J(?kGdMXgA-oTwb|^u`cn} zo&l*-9ng*M)IFrV*7`xeeI3z+{rUHZ>Bz?2iFT;b5cXmA^^MJDRwsHUSL^g~6sGPB zBYG@hE17BRIE)OO<{L36nE>h%{v~!D*{` z9mI*h7nnA$qYYKMMY=fY*$E{_7PC-q>fnhoR;YeXFy^!1`r<<{#19glELCAb%+qnb zAZ*ff&|jl~JfAO-x53w(*dXkhn6lN{|H;_YgnfIgKMqA+5QDCzgRI}uErCEEVj$3y zT_XuIl2Km$$i@pu<3^0vPb!ar2}_T;6klYkN4IY~Va8`2#|~!v$_Xp#I%mE_NIgejE`$k#vFEZWv~rwUn;v*fx!y2F7}uYpup(z8C1)P?73ZTtuzNZ8`8e~= zty4Fc)*D_CMCk+Zfl-Nz06#S7_*u{bnv3#T;H!*^kev|3 zU9-kZexE1OsK8#Lgq%)u5DUXbJHHNdjxQTo;C0>(6QqOMVr-^cs94x~Njm+Z0%_}E z$R;;tb=E~i(AJ56eJTQ_hc|nB?;sT+VPyHCPZ#FjQKR}sc6oDvFS@OTjG7n|0b|0+ zyDk(1Q=~|Fw4hU@eB10tseBPcv~BN_?kl4Yay0)NHL>o${~_AcMxvydZ@J^GyDJ;hlQADD=F$1ic+R<`(-S%E_%=>S|6QA0 zAHw#ZIVsR`IW%yxlx^NQtyNZjp0fn-3czQAV~5(=`>ljG*^MU!^|*o2?uQ&@OG~&) zivZ9sIleTT+~hjo;nE1Tc9DXM(O+?D{cC*=4pM<51Xb{15_-w3C$cm-omnKjqhRye z%C2!0GF1xg}~vyVHbQ4=Z3OHdqXYA4lF^{ zqu>*5f^V@~*SFpanRCYg zbKU?o8~H~3KQIU)$;69Pmcc5_zJp57ZEh@Jz{K>-j+i(F;n&3Ug*OD=rep|5##O0L z9FcNNylOd9(KLb7hGRS*0;1`j_ATyC`D1QdA-rc%Tav(TvkU-LbY+;nzfXLavP5d` zt>4ELQH^6NZdeiUYUW)XzWp?s`62XmVstz6Cl^*q0BkwD^q);JML)X!E577kbI^;| z`y&O~8jLq=3j`i`qViFTkkN&o#tJFDt_7$%i*;03j6Cb(|?1dF1fXBz)`oR zw!Ufc)nU-4G$!aKW@YNFn(J3rJuiu;vrvd-_4lBX$%@Yy<<8`vIKV_ABaM8ui#;00XA3a!w2`a1V1bfJvW0B@uD9vg4$kVrt z^53_!TEfz(+8|lRDzM1j;!?4*H#vX!g=5;io< z@rjCw7FDQgl-u2qsv{`J$f+xOvJT;Pkj=;E|PO(}xgL zHK3OVIv#`}S?tS&e>2?6$@R|`_B;T`26=eW`!Ot-4Fq6&b1eeqnhIkPH_S5$=~_!1 zU8UU9y*hY)ruQ0PZg+PrxLp)lR5bUM8B~RJPKK8_aM3i=byz{BQW#OQ&Nru_BFz{U9_p|B=K0f2mbnTxc+NO*L zy!XDWt*`dRK!UK6lg2%yl_So2rTvT9yNUq0s$Da|eqOYdJpRmE0;ploeh;PdDiXp9 zF@w!X#m~e9q?%KU55k>dMqbR|6#9a9b6PJ}1k9as0^zBR`(rshshobKmVgg8H=vLi zM|6zi-kjDK=lD|9WpyX%=@>{|}uT-l?J%xmKh3EDy9sYQv zk9D0A%QL1z)%xiAt$9)TrleRSW&%V5q&kz-I!aZ`(32l$9uQ>?DiyTUs8jEDeG8E4 zy&Rh$GVu)<8?SwjX2_1fG1B@_;(g|NNxE3|_)$9rtUM$g(f=A9wOAsbi5b>~isE>8 ziYvqWa3fTd$Baii^_F&%*tKUC-O&IzE zjuvMK&>GBQAbA?IsJT`3EJcpL;i4KTMldT#uq*m1pvlp`CE~HjTj!t5@XRK=WIW!~ z-;xheHC`HCjgO?xTEmgF%}dzUE8xPiJSNxq&c}G>7w!sr507pZ6ndag3|D8FS`l6RUr$wZ}`*w+~ z;*(^*~TlouRD1v3#f7n7GAO5vtB8aPv4! zT&}rcz<+!m`P}oLk|03dC{!;x64*kQPKE~c?8|&7y)kK?UDu(oQY@?89%d;lP;{s+ zMY*Xl_pu)q7Ph;WVyp=GB(CH3>%s7EaR_v% zx+|g{&gU0EGreYVh%x)x>=4(y=cX|_ zIKXeeY)r#c#1`t3R^>|mnUK1RP;zbEH7DXLN6!25fdEPXW=P&e?8X_s_T+8HTLF3; zv6$fYK(C(KIn>wCGM^`D;pMmM?hg%5A#Zrrz_p@Wum6%K-A(?N5aZ{8w99e=~ENwXx|>Hx}VomkA=Sw%?#^LUpR1w&NbZH9Sgl(u#X-7>SCd zMARXfKW(nfw;fL70m^kr&y*Y-$*ax|Xl!$@9^L*0)DX?9_zgnxJm>Ovw`EKcE0=#b zvJA(L#7NjoSp^*2=G8PYELNO}qbGpUqJQ6Ed-W{n`;;(Qki4|q$ee3zyRrzp%Z62I zuqVp%RteTk5F@B58&ZxLW9Vvly8KBJ$9ZIKiiw4c!`cF&tXVxgu{y-HhLmagLx&{? zC)zd1O|^O8fp{DCOwNl)kSiCd_qWMC${RBjJ$w+{(96z!@$H~p=6NSd9|SV00Ny9A zvvfa@ZM?mLmCXS0%y9?a7rGrw%iNh*!jXxXGw-)|INvZFdOy}X3>1{bCe97o+`cqy zc-N@x3Ia!vot)RgZgjzjPRZXP2^Rtv-$WZ5B#SZI*f-Uczq8nML~J&59RvXU0^Dj9 zn~DeNUgXQq6+A!E_vUVP|JToT{{MeKQe02EZ+qFP4(Ji~87`Rs8FJH3H4+6tChR5L z5_rZ`D4 zVb~Ct`|=KyXJ8u45WxQxvP;f(`+Qk~zndVX+-S#OjRuvlMvDvOcU;5NjY6@kA9mpy zY%lB#*J-U`zHT12@TJ%OYDRwgvAK%QIt;-ss8a9yzBk1R=#9OD}H||3jCc3CpDzS-gP#isdjuE;@tG?i)>wb zoHOu&t{y3_^M1~!HqVhrXBO7Q;nd6eqH;Oj7Nrn%uEE{bH+7+w<9(xhw2!@N)Grb6kv6>Te}&i}tBGx> z>#xAezR{N&AZ>jJ-{CY9iFj7j^FxomBmS3pF$^n|WfpTA1pJw0KVK%V-8k+vryEw>H1MikS#f2m ze7d4pT`;D7>+1z3R5k!rn+jCHUw8hOo^c>)FuiECq;ei#=d7~?qU3#&i;oGCe$p+# zlm-o!ic8-M_^LG>x8lotf?{Q*T|SFJ8Qqp+#w!%6qZ1!ZfMes8eb@kmV`j8mu%932 zzYHDf8VYJGYb5_J7Y#R1Uqu)?M{fIAz$Q0^P3b7jo{kE(L z0dJ|*&@ax-pehKw;QO>bt{`XOO?1h_Y*dX9;@X=w?RaCA2-LKe7ZoU_U@2En`0~;% z=cZx&Rvb;PF>hniYqAYowseLMDbowKjqizP2__mI3vFIw4xF4`Dd(7K@MUFDCE?=S zgxXih9b+pVxV{zQFCfCPT%+wrMyyw{jO}3Ms!$z%e@xgyvDWpLs$}vQ_4v-?&rfxh z{|7)vezOnroqIw#RENQ%Otj`&6udugG=v7n1r<-dcUlBo%S^X=WHL9cj0Q`n8MWmzd5h177RX<*&vSroUhB)U@c{sUf0GX5vs znb1X?%(SL)*QN48(V{xRU{C0cL-}cX;%`xf=7J6J zsFzfv#JR);-(@q}cCMfODPPo^DVdF6Zpxqf&#$wkfM- z(kS6$&a-ju1v#e4>sJhU7AYKp$wCfc@Dl?XQpLp6P@|*3!vjt?*U$FU%&tnLw{*hi zp~4-&sA?Z47ur*Y*;0vaS2=Itd=}KcjFAMvhavK>FeTH`uR>FUvysxhV`e)3ZGI^b z5)$>&FC{p8?jFM(`<>f)f|Uj+dq+mRb>taJSL*tn^r+Fv)Mg)_h=ZS$Y409R_!IsJ zD-`yV#YbUV07*npeU*1bZootHZYWvguXc!--c>;e@AyE&CAf?h=`+79mp&@1fqpWS zSnQ`fzB0Pom&jT7OZ>LnDRTm0rFb;b`hmrbg7ZvR@qF)00&MhUsBgMm1N%~wDkpz- zunY74yD@@Yn0FIXw)$V+z4;+4DD0-;?nTUg z(mU-Ea1n!m9>a2gMf)pkQTh?)3)^i?XllKE_v-5D=lyKiO223Afa%hay`$|ITb`<} zdtIds#32K7gY2-1!HPE)<{x*q=^|nh>G~Wb>hC;%)viIb+hKc9DIC>}iM0`Y_$gB< z%8H@0(ba3nW{IF&0A;4>_XXr;M9fWcAfxF4)8#8tw7lHW1L(#11^Ea6E3fnBDYCsH zcEBWx*m`Zel7Vn4bf%7VDMecH)rcBrEqb)m)F9^x2Hd<6-M>;rv!)|#it(lu$?6Y+ zA+2aXAtY4ljATPgal|`J_>F+T6xd<&rtb>4Oa~`Wxd(G1(_ZVF4R=9Z7Y<>U52RxM4h_X|9)}_SoR=@qCdmJ<`jUgFm17L3iVV z0oxAQD$4)IO&B_}347l@4nK!%znbOTLkk0jIU@l%z6hl`mKsegoDORPzvl0>7_c6# z9VhY`%tb76>30eaT{Y=)AcZrw9GS{GnePr#npd%Avwi|`LD1WqGlR=BBVCBh3 z+1W%;9ZNWR*ZUidheeOEJN?_yZNYA3i~EINWO3ob#`4g*Ki|KazV9oQ0(3X~jc6G* zK_U{y6N*6xL+<5rrnY7=G{wmEjcC3cae~Uj;5=h{x!(wWBdd-S5SzKl35ZZxc{dqo z?k~l>+fxN6mG}c!GLv4@wLRdl%+8_%f43L1d>?Ph@k91UH`vb`6sj6~2ve6f3w9B% zDU+0%8-Ec-C8iImhA*GTS<#2AWEd7iM#lM~Kc^0^fHccDd6`dmmt}fGgw4-+A@t~M zq(a$J(&4!el}5Sey=uF<`-9i@YZv0XC-!OHfZji4Ce$oUwVXOHV|!oayQd#Ex!agd zs(6ouQvkmT3hi5->FOH@LCtan%2n zkFg-*WpOWe;C~!NK@^_(J*fP1fi!SRH>zGeDM};(hV?sr`x21+?AIpEZ- z^OjM#3Bq?wYL6ti2Taco%dX@1=@R7l$aSOomEWfG2~X~v+$ZEvo)%a-zT$5sjq;-H z%Y?{jXQjwqBarAt3M;F290ohGhb;!kdEj<(&j91)-pFgw5$8M*4Rv8ypxNk?A}?I0 zL4jWQ23+ho2$1_RVT9jM;Fab$-`vC0dpDCB4iB;;iIAdE3hGb!T1NGI?_yH! zADBuQYFY`k^-^NTBgwL&C5!U)#%=lR^ujnDIERbp?d<>4iEi$W)-cvtm zKUA)%J(rFf1WNOD77G)a|kkjo@+!!X`@Z0lbZ6``>SWoL!f-JHq|P zA^y*~io`9IzS=qcx%U;o^E4?qh3^f!HTEvsBY{WK3S;dCOSyk(xRicjy{ip{eP9Tm z?>{AMC#{UUp$7q-3SNN%3YEjwh#wN0`ucLz$v=OO8ADl_SU`3s%rw}6nAAzl9Y5lj zZh}LxAWaF?CntYf?_2LRxT0G%QV0@M((o#w(!IP>@8{rQuN&A|E_RYxH(yg4;fsF& zQ}S(!z`NhoY}{_@Zcgi+$(c))mlY1D33Jz*za_*p+K5h0EVy*^-uLFyVP0x;g9lY> zZ9Mw8=Ite%?;`SdQbvK^Wwe;dJ)-^`a;uXhTIwU@T1(Y_WrIY zX5-wDfrJ*<8Vi%mXS<5!BTGQynX>z~Q8kAN#gk{)Qeq5awLibYsHg(GAjPW%NP;Kh z6T-R*tnH@4u=2=@QlYHsuSXVcEPmHOEuX&1J%#&v!-u5%jSbOfSL(l>R=f3l!`rz2 zsN{R|uYf-jhOlgDDey6I#a#Uj7sl^RbSYu7^DQm~RjKrNbf@%!2trdfpv0eN6sgx` zkIVRuq|pjldF&xRT9ACl7Q@-2#$T=pqEp-0wvDgqveLZj-MCYDi?l!Yc}V;*-{^Dk zwYEB_jFn6JWG^%$Z0oJ?czuNK|E+PGWNc(7e1qyJ2xCK7~wi6hg zT1o^1*`qQclVhqcDPqB$qAG?Et9Crq+2LkRx{ ze%IoBmtub<(MwP_;9l!1;NwIgm*wfl@WRFac;kX73|?WotFM1(*NZexwHSG0YSNQ3 z;yOB(2N+AoWt(T@Ssf~4!a4$64US54GHN8sl!u#l?utS+C4c1lx*oj3iLY%;%3siV zJ)e1X8=~+^yN=3}JzqSuSRognmck<-+ARs%>Ieom#*3z%p}r`fuNFb_77x%>d!sWG zy026=ZtcWbl~2)3r#nciN;jZi6B3d+Kd(mR>`uw`H!gJ2s=!rlizt$TvC#9tic;l4ybaNttCv4!A_Umns|5w5K(*7WqTnTyoQ^X8K4*NA;t^ z%e91y?+q#1Eo90PIdvNN0)$?MGAkjfX|0=4(ZU`w&R!Wn199LUhF#ubPr1fcLfOrd zS;IZePHbY{SI%iey=H7pEtzY0^vVY?*!Jc}13Q*vBkvp453dlGDE^t3k% zeFdM3Z0sRZrxH{<$86vI0Nti}J5n5BuViXI(T>emv2oQsA41iBj`@r41<(B_%64e$ zDek%4ns%Q~p1HJreHqwgt9$jn){IpMqWsdpTQ&?5rG7ZpM<}fy8ExMMZQm~2fzhH@ zu$v7?TAG~qhLJ{z)B1R8P?LIlvjR5tFVdfnLqN>4l)y-=r*G;`x`WD)DihEmFhYp>@T64 za8iyfO0a5dB#qqaATmM@V7ym7PZ6S`!MfqP0||R%3MApX8(R3N%?JWhxnz3tN^DI> zj6^KH3T{hLTSteHsL6Xi!6rHl>_=kaCLS4CQxHM687)US7TOJi1Q{zfbQPQIo$H?G zQqz^B7Kfr1)&F5XvZjMqQv9qkm|M|!Z zq5wOS$Dh}3lUA3{#Ble?2-?DgOLbX9(G3FOE&ORL(Ok9}Rpmr$eJVm#4UW>{+y@SD zso2X4tTGky+~$|#>F=v?`3fX_ig=rpjGUc!)m;%xnbXCPPn3VxIO;R>&u9DL*`+M# z|9vL|8DVN7FtDxW)csAaFh+#<>7#SSZbE+g@8G9XM)@WoGhtAUdWz@YDu#OON6e); z(nH{aAbV>J9IxlKGmTyCeIZX)Mgd@Iu-1xlI_=Oq+$Rb*x>!-b+xZ`6N%eQglGMsb zm(*fxTP+$Eq}7yNXWV)TuI+i`s1NN0c&^F5EO?D{?N$tYCrIu9**c$q8l-nxjbg$~ zyYH;QmH z;?;+#)RhWOo@_jBYBok!*qxB?1S#pkwI2HSze$@%xfsgeEi{Kh2oxbP8~_XIOu*q9 zT2u>gMyfGRu_7aHKqgSgZvkO;m5AeeOJS>LQJBxEH%X%kcH_+p_m4};V@2I5!4ez% z3@9{-aJS-_q(|Qw%v#qfdw0x7q1sfX_qVT&jn}OwC`11J|0jf-4IRRN%U#j=c=`I2 z2UL4;z)5gxX0|t54Ca!z0s z=1PP?J0H+r!Zp2iWa7_sdtj7~1uUm{-u#Rr#IGGU@`XM3ttiC;_F-M2_u!;nx8#C+ z^P}M*)SuLptC9tF`aXeIQ3DL~>sMq88;sq{$*Uwf1!C1oqYiwRiEJH{SScl=t&5e$ z|CaQd8#4=wO?C@ak{M2}F9XEZ9V5H2y!QY2^5XA!plCD9>;+Ysp0`v(oZwVseXBd=d zjNJ%oP_+S!I~rzg5caz2gl+L((#hI!5ev?j=L>FVkRQsyBGM!)cRMp0X?1$czDSwO z0i8VJjCHW_cET9&+#Ffl&37+~Ga)735Ym!PV;b{V{cCgm4eC9#R7(9~PTr~f&XiwN z3)O^w4`7tVt>no&g|Ar1x6bgRfjiQkqz}`d)kb!XFLugqD>;Gxo26zYhu4aXf*yp7 z_6u{rc-?kB4m^g})3dy*kV>c}QXpyC)W&$nNT!9%lx@V_GaLHdyiCyZ$ea={GAhS6 zWA6HvmI9Yy&|FM%({pxLX3gAhe#AnW5os-_cAwA_!B-q^*^qt9V3Jtp>IUO{U$7`T z(>ww%RnWQjbK?Isz|

`eR8?zi1_EgEO63h%mDB$l_ORY*OjE=2BPMcTlc0^`9JAzQCCo1PH zq~z89QO_ffO7q6ZIK_;a2z~mGeBzPG)rcVV87)m#V;BxBqEJc0j3b}>t(3wy_TeO-0$ZIwwoFg{63fIt!~!i%{a zSVv~xR<(Y>QJm3c1?Q~tD`{u1t|<1YQBs@4h1CpvbaHi&psN~)m-qwSKj>@9PU!@E z542bALh%fEm7k`&O`{B4Uk=T8f)=VK9QPR&gpw#0j`KUHc;OpB;d_Ktpgh08D~9m} zU8#W-YiDZJ;FqFEdKspJp zs^finW}~lT3b{*|fa4xFhSLd@#NJC#Efoyw6BIr8TRX-T%CH%suW{TFVI8h!8e>|e zGsfn_EnA|ySJXL7&OEZ5+y6(?S9Zk#Ez2^v6Wk$z;6AupfZ%SyWpHer+p!G`K`poj~2lh6gy39ke=DIu!fX{pzkdJli86NCZf8O5sW^~vRY#Rv5prBt@;6- z%il+R>Fv%Q!*oD8(^ZmuRNn)u!Ay<^zMKM|z=)5%H^W+$llpVD1Gu>6lCMc`sk zq1$4nVmoL~Hxuc`tqST)P~x6)o~p?{_&+1*+SQw`!5GCw#e?qCXtC{mihlz0-=$^s z;#XsI41)^(b6;p~+f1ws6guGpJ5$VJZ187FJ{}Vl0l4pCUOyauwv7pg(So0<)4JZ zk6G9mZcS=|^hV%uGT{Y5kE>6{>wO=Im}cyphrO-*V-g3{EySuXb;%R!Hv1b|RVYmR z%p1tgT~3^O{3TMYe6rD4TV~1CXexicPmHHx3$eD!GP4W%cXql6B@8nu-B6p2rf2EX z@g1qr9cn<)?~RfERQ#YJA>J-j4Gr&!tmn}NSRw?HVPLHyLaV8GpAu&QOIa`r1m?}K zh!Q9dbq==$zt%KfHToT?ku{H#3QN-8P|-bMsY@9I?J^>N6S`bri1rPIOmp?&-FU%L zudgv5>E>-g_67JX_~$!d<5w~e69gPJHJgHm^%6L+8V2H2aXLA{RmnTs`LQKk!v~M| z=AX=ymDb1}orJB2NE44qRUPqM!&f&y@(=2}u1Uuz*4=;p-^huzjR;(}`}YG&RBhdV zPh1)dkKTYDB$<_1@9ceGSUrr*e?>If=t~45#R&q^Wgf)8kO`?20iQ6A_&7x0o1=sf zL{i&s%w*zM<`T*Xxgg6@7`UTnE2##jOvKk;bYKfkJ4#n?eLXhll8f{MUXJNiyWi)o z{}v~r3ng>3hTppcw$;%$#soG0QvR{0M*hSvMpSsA8<;|h-k58K62H><1M=3MX(t+R zr{n($-KLp*z32&R#Iid1Vj+72iDSdK`e{%6$$=idnepOJSPQUV0c|~h2Fc%zIzCK< zmbZHF5-6Eu^{?%Bmue;_3Fdwhe}=RP<_6yaDY=Q;JmNMDt7?{v6y3>r%cP3#JFw^! z?{unJxEYs*B?svaH(L=2d6bg||IG@(V_ycB$%IxXh>DKpv-&lcDae&SKjJ{thQCaG z2mjmev+~cY<5&M7?3nCkY$8j?1+0=c-7oGpCs$mn@3z?!iAF2sp9&bhIOqWWktN+- z!H7k*KteS8Ron&;=_PtE}HGeCrEifZ--?N}!En!=1Rl$9eW^Cd2 znina=3n1lT%d^8%sXy8F3^BK~vy`iIg>hMDg!!4)8vEZB3nFA3;bK-C|xs=1z+x!*bo3anCbulgEWV zMOy&Yb~=Hk^uJ2 zadFV?u#Z_Rla%3eIigo_-#SPn4Y}tc4tLP?ScIA-q>Y% z00t^dxgBk=SgxRt<+(L39-*K}?ME1-TZ1nfr|bH->XszS$@CY8!zTYU!$r91ly2lSK{IFEc?Ag5?VPYeiElQ< z)bL5xvNF*Mr+@j{+z5w_r)eDeHU20)2O?>0fn!!UwU&v=Og3@udPkSM4unQ0+$6#t1d5+jyPC=7X4a zpzG@+2dMEEM=KOmIu+H&v}*Yj=6hu7oobbXiA*{2uRNofESnXEzto7lF?n50=Wjm69i3B4dIce0wr+?U^a66x{8bonm=a zm9kSVIR$c`93bCsl}N;s^M_hG`z3%7q40;D|B!SVy`#C|$k@nZ$KigbS=sYBgxNR= zs2af`f6f`!C?~#sfm2oQ9d%x3q~Awgtqs|su<#U`zJ-!0+_al^JU@JXvvEMXG$yb} zsCsQebxl2X#lof3S{Qb&pb!Bf>U9OMQ9k_+6kWT9+9S-JO-ucc&uP=~i@~6L=?Q+{ zcnk=lMkhuH5l7h~ct;gvz+7Tc-W*t+0p4@0SnyY$tKecSZ&n!`s>3L8kXcP%7m>re zYa2_7k0Y;qgVH;LkyJXm5SO|RVHD&SrqJly{(x1x9_ANU!`?|KPb#YPPhlw-lT`0q zB^euA{8F*f6Y791oN$HTNN1*8s7@_qn<~NuJ~?qKPRzdOJzza%Sq?y9bTj9y+E7Qq zb45O#IvZF5d-sfjTHv`D@){F<6&oavOVGm*-qh(vYU)2eb3QU3VP2##3z{F&@=bHt zY@Y8km^~7V-v7KlmB%7N69()MDMo&PT1YuGH>fhzGE4u7!)za1!>adwy&hp_Cdohu zYWPnBJ3y-pYc{LA!>z_aMo~n3@fCJK3#_Rk1pwh&YhAmf60fLq3iALm`_c796^-pK zSX#ECQ-KhE)tF#ZjI^ViZ+U+V;j@NOLPh$?u+4sv@~X~IU|xdQU5%_W8##f>%hBys z6T}OSt>F5aXV$T+5?QrsvihjBs0)ypF-3`bKI@j@YfVJzZ!_Z^5(+`qkpLjIxz-5; zxvPyYCUr>4vBxlnfE!@85BS8@Y0B8Sd-EyXNO?Oc#g%AoxI+|i^>Y0n_uu44alp>0 z5v+7B0^$3ADIV6gBS7#5-TNJg_eUUtldkV?9z zJ_ygcEYu)E0QCm6m1oCGxSOLOvj{(>3{}QZFU<4ON6RPhAl%9eNFvz@ou-IqsY2-!FE0DN?TlsMFq_}Q~W$%9tEyWuDmNftw zEH4(wxA8e;E|}!0aTz)x^zI1b_uwqvPg&(|miVRv#mo|F_ic%fS&%YlU~XPeh>*!a zd}}%H2TS=$cD=U~qo91@6u@C}lT|>hjl%>1T)r6;1G=P!z>^Ah3dY|rt|EvXZ+mTF zQp##PkSm^V9{EK{UMeE5ONQub1m{86RFYj#ulJ7Lz&%(|U-Kf8;<)r(nECMga`^3R zv4hD$VcwHN!UKi%P8fpNRPPun2YI_4)(8JEx~sMP3JU2(Q3ke!^u;eR2DFlslOlpR zlj$DUFD(!{Ha)HP?b|qqYrh{wi}6aP;T~jllkbxs-Eg^Y@G9iK*h&HyKb%tX_z`HS};w$3%S);&~D_xZ`eyz;)U)dz{vtT<@tS|umD z0$x2xk*D}sTu4KgfyzsBwC<(E$spbIReo^B+NMTe%}H|9CJGAuh3PB5}jyld?H>^@iI8XqY7FKyw~px*0Y&pyTsft{9F_~ z$kCb!lX1HbO(YJ>%eOX60hqopqF=e7dk(_2&*H8$g}2WRq}G_(nc`1ng>aOJ?%tno zf3tL}$?b7QCdoYE#&zedkYm_E@!wP`vOXk0uS&>H?$?DA?51FwNg`y^G6OB&^mE7sec$WIoU$zeVe%C+Vr}730CN>$N#^gI*pXEG5B#eyY_ci z%SQ} z(kLdD!2U>WvaN(xct67p9-j$U2Q~x{U2}s$JYsRfR<}OED%{KK?Nd z!K`{X!AF=4Y*;0vf_{BTPF@+)PYXZ2=&VodIe+R3yX=PfVDwg1V(!sD8WZ7hl8pnR zzfn5hMNJy@Mr;-B>gYzHIwy>lg_JQK*=qH#n)=b0jcUVXS{!wvpa)*ElDYH^|MHihzPg@<{2b8{ z3RmCz*IAS$Yfc5r4k;G6?q);2@W7?|OPdd)TTE^|%q*tMgk{wG8M=44_(9I* zWG8^NSIfX|xN z?hDH@+(XtL1e$}Ie6*TCqMQs_#bZ8AX{7}z{+h(Hqorojmw>_2xH`v0FyuZI-vC|L zcN(#48=sdQ6Fmvf%G;7P6O>(~!h~%7{p$eFcA8C8R$-}tCH5)$eR_2g*CRT*M(GVs z3Fa~Di>`xQd5q0nOB+Mxm=z&2Q>J=gst_*MAbFy*_D@YKjV*PVco(b1joAXW;~tn& zYZBZKB0)V5H-mv*yU&Nw6MIIhMUk69*KlvZ{ zhdmNp#4bniO6^I7ar_Po(=^l<#(#;P2LloqAv_4i>XQj*wyxT` z0oQ8qJgErA^~`z?XnkWQ;{ zM_zZ|BnD+=gusz&d9No24V4LSx~zY`KY`%wR6@x8-5|_WyU1(g0ouo94TrBAFMGEu z@&85QkIdZH(Mgxp3qik-SC&aP3YEs)+xR+?DnBQeRJSrt#g_*Chv6v!$-ZO_c`^K| z_E7QSvN~17weP^Yy3M>7o2Qt2O)w>&*PoT<53y8%=by1{p39@vTT!Dm4?c#n!v;`( zQ-Ow`>HNqCIks*YG(R%>7R@=foLh5tAO0$$0FhXa&m8gt2tRYIt^T>zVo1t}@izZ8 z@DTbycl^)#L6XMV|*p z$4^FVFb5?>iKLg<;?^0KBpuDOribT)vT42IC0kEVEkwtSQ~yqV^Bzbc#Jx$S7R+C$ zW)aAAw;)U23P1wGK^vh_#fWy*=&?C)?h1^R5-rJ6p^bMpY7?4Ppnvq}4s7=2E8pMc zueRCIm=FJwc21@^>R8@G*4D7cDyA^e>-Cpb8PO$mk6H5yedo5^#w0ePK~J_LsAWZ2 z;XrZHqVkzzqe<7(A|;SU%KpCs3rrfJqCeDKnwpCpI0xV7gE#2kr(&D`S-uYj9!_lx zf`=Ul?ptI22Y^s*Z#iC$kVGA1tkv+H$G;odcRrm z@FiK+5ve``LjtsW(h*=Z)HV_D#y4ciqQ(Aftal_t)q-rnCtPs7Ohjab)t)ADN9yMa zIGkVfbZFgtHE3?zkkCVm(~AqSq6MErp)~R+OO>b)equ2Nd>nFEO8}vhgvqtVL~dV7 zT5q5G{naUYxbp90V_#Ya&C)by6*z_Zhpg24r>ILOk~MN>2t9xks~yq99F$+V9YH|{ zm|_+)la*p4PakAhfAU}J5dq5{C$yrd%1f3#ChO+c;pP;Lz}bL^N-cjsu$ucXYb|A} z@m~NGxFI0~rkV)UxJ&Au!dm_}q924FLRT2Zb!O&SA-=``0j~wo*v3P2AFs0kk6>RS zMKO2;3E+b{j>R5{+ro|oGZY*WgpwG>Shg|rJZBf&Qr-WS?UxNhf}>Wokol9ZV3io0 znl0#A`!S`OH;Bg4MigV$xx*aTZ)?Ls71Kp5T_s^LP-?(#lbW zLiXtZTD`7tDd_SehP&-L5)g-FYpPY$Vw0|k$|c7rA#j^8^LO2ROmXati#W65YuIR? z{16OASl_MAPoz(CNv%DM>^&IVOu+nKf-w7h0`2Pe#%?Z(-UB?PTOZAA7exI5kTOq+ zzBa~u@ZiVko`4mu!+?&MzDh(?Z%A#~CKf;$KQP-i6$iqv)%T4~!m#6DnYSO``fcaJ zQ@)XE#>Ls9Co_1?l^1SypXxEmiQ`2U*6bjNJIk|IFkQd#r^WYUryYdyY;_bxeh%in zP_Kil$nCf}l(3l`@}b#{X@P8<+WOINV3xIbpCql}2&(jcj?B^?+?5OQS3X%zUQXFm z><5cL*azXxOh+L1>7ZjPHqj{}%m17O+?;`pJmFaD*Wd4JCWS^Q~;z;(6r+yf6wp4~H&>yeNH0>FVbQt?@`%9ye{iy8K z3n-;I-uuz`GsXNIJt4RZ^`A{{t&{y8suM(5FW182fKSE!az;TIy4u#{fAUmYt-mhnob-XN}Dh4Z=tKepys|iWWj3PyAv$N9bOr&c*6_ zUq19xF)X!YtGY=YMhl7et4p)nD6Py&On5nPWTWF;_FP`T$+avKX}*!_HvxLSSNff!os7c#=$UhTHS($jOQxlYUUsxH-4mO;(RTerXb=z zW`z*(lP&OpJ))K-J5OuLub7Oapy@1T2|Wa^IoFpf3zG7wGC>s(1s6zJ9kn&06fI(b zf;32Rd#%aZ9y3n>Q44MnFq(=AY5fb6DQw&nlo3JtOdLH~lS z4q128sy7|9E(VI?+G@?914fr|x3i9BXCpATzY>Ua%L==dU+>dhY_ELLR>kd=GZ2Sa zJ``m3lz5Tj$2%L_fJJC+2 zb6NAh3Mn1#x%n?I@VP!01as#~tMW3%$Z>n!LKaQ8y%jbNR1!%si@TdH6iQ){N=tYg`x}|KS*r ze+%Vfq4DkVutqCWo31oV>e&xH^aD@nv2RvSb5mr1O>K5)v=Ycz{hm7&j#}JEJz@10 zTu&f1?}j5NpWZfV$CK$Jc)!Mrima0@9V81k2DvWKUQSQ#AQoa&N=EDGQI`WpJ^Vyc zRC4E*1j~_e;tsm5(`_gaxN&Q0_XgJ_?4Rt-@av^fP1q|H509*Ht@AdCmaOoDq*qq%xReJtqsv_yCTa**GatDIM|wj!z33Ri=*=#S(p`VbApx=b{*4r z45z1Zj$t(D0~&}*QZ+1?KA+-TP0aWjjJZi<|5%uB|MsYSXCM2j^QSdF3^wt*72@wO z7BSwX)u?c@Q<0vad2Ut>^<^$j#q<~#Q2-~*jElgA9sTY= zTS86K#G*FQ!;%C4C+7A++KEKpnbKku9@Zb1Ss7*dC?sLuAeeae_w^d4{FsC$89=MK?7iNWfzcC;(!+{k_ zo_ZVNY;c+ce4>$T@xiBshFq@KH?LgpIpjV5gym@`g1Gb|2EKWA=5WUVVP>yOHwYpF zN-QlTSQNfjlDFJ>p)(YQNu)9Q)5xl8D#VPOyC|-vf`h*Z@%~)6P4bQOSzaWOu} zB8(*B+I)vDsnW|mD^j4C%9%iOMUQr)xSO{PCVx?CzP2Z{n4TL%!JfKrSzlkpu2rF= zs7>rS*Er;$=2tS;%lK#XZPp0uct5n6m?#HRP1{L}ZAt0s61k{EtqWwq3)(zl4l@A9O_ICxplxSPSUw_pv8B;UmsW z9ous#M|H7ue$f;rA|8COU!C>a<_(Co_YA0ldB8Ui>U#X|#ULrd!Z9*|zQN5$h9=jb zgt1o%sO%_xDjE|1Z-e4|D@D}5eNEmuQOlT9O@5P`=lff&0i|EI?MuIWgZ;BKku8XX z^gsds{5P*aUh>l5VTGxJ)WOTz?IX^_re)Sfhi0{pk3RMrk~)YE4~}DgM5D@pKZ|5{ z&&6>s#(wnj+%8T`e5TG3)!1ibXpE@3wd_|;Zc~v&?CS?LAQyjJDe;rR$&J7ArMbmN z{;bW}bgVAfTC6@YPqh+JaG9N*DqUC{GYHX=U9GCl}%JRVZN) zxsS0Q!HH=T?h^?euk@fcyGSi?&7f4C2t9rp{n2EBHTw953iLy#4rHKawPL3Jg`1}? zm~ONlY6v;*S<-LC3mTt?-pu?nF}7JiSQ6^;BiN)#8&=C_O8zmn`n^G7e`h1SY632i?ur;R!R+-hgWz znzNzTF{z`u1XbRWa3xBy0)o?;WfPPUjh1{raSq#Lor*jHL^@WA0kyg?YCYhQQ(C4~EF>8vBMb6)$TA34E)AeF7&T{#zZakHa;BGgr&itPqkyU#6 zV@T=aPDXT89Pw_r*OfCHz2UB# zK_N6{N@CD|$p(OMwvnA4?fb^4fxgQ@W^E_2r)%=!i_K!et#)rZ6FL z)fX0&y~}z*#~w`woEFM9|6Kj*$6!a7T*eKxO+F3J{vn1d>9 zQi;^BYuQl_yyn9VDFe4|jqEz_R=bAJrq`kW7!Z5h|2s{cmcp{~F?v4Ie!b{;1j1^V zY&ld3ykf6ex$?3Zfi~wtI5)!@+vA(V&rW3xS~0DDP7J-v3Y5=+ldNmg9a#CR1B2+^Fv&m)RF>}TKi#Aa`3LY zYzLxgBpcsDWnYBqgc0m$0CKVLcVia@9A8}sS+FokSi$K( zqAS>-j4wX91OwBcj@7@z34#gcAk8n>$FU|L>_IM9t`i^W6dTQ^$7lTA(Z!UP-qb$f zIw#WJ44)RHW(I|OZcbfT4yEc!gJd#2`uApHv6*Sk1zM=;*0$Oc#(%yVvyx$JUnM|a zeIXk|e{4t6sHB%vptZ+uc1>B>i@j1`j?h_9&-H$pcd0~vBSg?EnEHTEt5YxU3zK@C zpXcM&2aCi3SOgP(YBq5+kU~YXN?8$rq+T}GH$Qf>y!MBt+};`MBrRXUmBDh`4?rPy zGbQo(eX}M{G|ayJ9DFkSu^R{pe4&Q!F^v2-GXL|`b}#tm{1JIsp5%nPtM}X_7`&d- zu>?dKFzDow=<}Q5O&Uz=Wv}bGJwdK$^mwW?7Q9{J_6kkX(Of9~HuK+v?w1}2N&YOS zBW8DWZ{8U=nsA%(e0PG!6IxtV5))k<>t2hI>Gq+nSwv8oQ=x$nQT*;M%KCjyQgSX| z#6m_MjZE|>A?Q!Fd%qoXLb5vUXYB=sWp8v)HqNteqH9VzedEtk7bq$p#8$b(b5*^R zRIh%N2hC6ru;wZhQ@k(zos&>_ZMRmx*auBknBb#a(6^F}87TK_+!Q%PAf&zVnWDyBm{K8`gCT0`}un+RGO;v-uN*!p1SJ}tfY=hFJ+Wj)3+H7p?N ze@Z;cxbf#w(L1R?FAGxY^8?|;w(QdHa^-*Mw(_XA&k;pYlQR~I73gF8OG4#Vvj~2v zk6N0rkYo!RFHU67Pml{58AB~BN$v`G^=;Ywk4MLY5Z&m_(!Dit4)W7V6!ZcrytQNy zDd?wVx@A&tuG=>%>I^OoK<)$g3l=^_>q$Tk+^M;hlc;l>)Ao>bhGBzN{`8;){-$63 zu;$n01vRZ7!|SDAAj_fJ_?UgQHKYzH@-mswRK(8$sS7C**b>tZI!M?5QslZ@24j?x zBH<;)Ws#Rlc(67G{6A+9rWc^{ql}R81}D_+i#cK+ACi& zwZzZ#dVmJtp_8&yr~a8K6P^D^1KL!_S<**{AyjewERip1?4s&$^cFhsC zmY3dI)llmBlgsFEE>?HJuCsdCuirC`Upm-C;FMT5v-@n&nMvd7TPgL-#JZwXRIvE3 zRNbVd?V!*PQst!#2QUqZJGVsUc!9NQ*#x;{Nf7tsz^}{|r(#ec4DIoE#w+dKDJR(6 z?DF%9z}LaG_ie1-FQuDc`%Xea-(Wb)nrG4^pKwd(;y0>TE_DI~0psCAfSSWpQ# zGVCj)E3^*BhgoOK>hdm!QD~3Y8l3c8M1PN+B>FR><+~GU9}Ktp*kufjU`1qajo}Tv z)Uz8sA{K#Bj`gk6Z~)L2S02Adjg|54(%X11&k+~jT) zG!qbL8Ro}RUd{qB9%@a-W75G$w6E{I4tF}V-Uqk!WH#1Y*Ne;q9ig1IQ>>3nzlDPh zWxn#+4-sST;=cu8Rj_k%a6H!8d42v28Z-ZjFXYZfNR8&1y?j+?Rs3U+dG7rBJz|h? zG*S2X+j7iL4C5ALPv2!aQ&{Ox(ogZY#8p}&QuRg^dAv>NM@(j}k)?&CQ)W7p1E<2j zB2jITDpvvSf%0@qc3%)BY{6~)Li9Kk@xkW|D_PoEQP2Z=NI^?MW>JB9XN_L+OTs&y zZb|XplU~*0qxxceO7yZ4F6{~ok;yH-WAi@gOZc@)%sOX9htt47;K&PCPcsf7LrGcld-|jQ z^X&NI`%OG}H(PfK$K=1hL@$= zz?zy2V$wbA34@-R`usHVi^Z8Tg37o{kj7(lWi7LsQ^Q<#x*M@OU z?&HL6z3weO#ST&`X|3Zx57tBnn})0;D8Z-GAPfL>Oo%2E;()kh*ks_z2%DLNu#^=s zRLRaW3E*)pFd?Q9;J~lz2*pnuu zqN3@(;ImK0abX3O3Myq?!$hMi!J%<}$Gj~&1NxeRRZl?%$84h_02La-jz)+f{hS(Y zby8ah0993cu4fQVN@UJj*v_0R=ijsNd;jJuciiQ&*3$4m8Rh>`i>iQymz&bgiK_Tb zamNj}uLx)QGx{JsOhZH$LyfG= zQlYM<29$go=x4*>O)0ixN=y>sg!ml+lwYv0>ruw{RGHbWK%WM$7v8tjnfuYoYiNVN zX??}lBBr+$Ao+xQ=}v8mHw{0ue$@vvynfih`VDu^gd#KIB@G*_dm7JT>E?!Kr4;P@ z?PIl+cqNyRL)tMh2LhLPH1O&Q^fXpRXoaZ#K&tH-4dyH z|8H8RhEk$H!WQ0H`NQ5 z|9yX$s^b@1*_e_dTZDd3Ge0sabA?|Lbcgtyfd}`rb33Q|*M_`#^^Y9=S3TJyIZ_is zTzk`y$$SnHS%OMOo5ntm2`_fc)meXq$l!%RJAg4It`I_ZtmBv?C zIt(V(n|BR}ZN3jAP~R;M0@|r&<#%{qQ8+nGUidsN(DhQ3%DZhl+&v3-#GnNcE=K?d zFb2B&PE4bMTgna@2GcaH5Q|Ov1TezCU%0V7Mw#Rrgkck>@keUJL~*W-qe~9y{bpKF z@u>B#n;BaA8WV#$sdGj=o#LwtrT!5vMuD z6=c%SH7qZ)zoUKNu>Hlhg}?X~+5oo5H^a8^T*i{~m!sp2u->KM;;&3r)hb0QDa{;% z%>*|u#YN4u*mxFnNm}+`Ko11BXCi&w>`&vnjoWH7Kh7pwP75g+d}F8jXW9b)4}k*U zL_QKSz3hCLIR(adDCLs=G~W4(8dhSI(M+cEO`jYIHP3H}|8v1qxOkLRn+ z+R7r0L#@`4rROV}*Iv1a~4-F3Cpt$1--jCe2i@zE*f}3a(R4!G?Poqjo4Ii=5 zxm_ZC!-c$+9=fThIp?;AFGGYh$@i7N=9M)_mPw-alxvmQp!*Kg0zO+d%CM_HYIc|! zY}#;a-{zH`d%dD~h&(h5Rk6Gs4RB%-ZJZJ#5XG3CTRmj@>cfBCfE>Amo@E*gS$Mfk zb4DC=R)^40855&uv7$rE%_9V8txqZ31vpGfCU+anewgDYXVQF+tUb*ImJq}r$s-_j* zF-$>LM|e>q9G5i}5Wo*B=FA4^#*^zWWx0fC)UJ-1IzvHWH0j*qH$2S4#o~_A$I00^ z^Fkg`xSpQ8NB7<67f(xc88sirlqsjaf8n-Mto|2+$4At?;SN3#H34q~`lSKxVw;Hv zRhfEjEaR%ybSTS?zhaN2q=sc`J1f3rKTiJrHNx_l1TB&i%pD0< zL3H{ty}YLG^qVkS4tk&i!(*99IfuvffUd;H9OS%AJ8FO0u@Q-NQ4|D@b`pL(T)t&nn3Pag@NKcXAW8Jf@+SNLCF9I@(EiA+E)n)V3=Y`6d_@d@a6lN)ZTtT#T5U(1 z{#TH|Yfd8zwn4pZZbuFRAcKW$dXs>#U?1%4M#ny%{op*iLGFjhdXvgT>>$rW5aQW3 z5@l!^L*C>unZcZxddG>c(J)48=a@WZW*sT_`i!hv(r+Q^Q%!zF+>DXZw}mS;&vtch z5oZ$=6*?GMxh)BaMoC5Si4?t!5SH`|x_#z_H55ZMxflJ1@tG}9+DV;qC7QV?$jgT0 znG15Bg9Kiltz|pzVe+9C9t`0%k2G_4BY&*JyW@^r-Q~94;`d?wl0}6kkP8lVAQ%tm zfvk*hu$Y5+ZgDviH!cub-S0{~_33oiBq^uIc-01;@1zGlo+TN4d_q-uWxC^o`^R)S zqDIsKQy^ulOElh3D@6PBdN31+X`wdpM9A4V&;xi#$!nf~Uj_`bAtWu1H+OX`=SP9z z`oHzL`(3e1F6S;1*ohMP&5`nPZ8aInc3}{d+ymBUpKmV(j8@>{*zb@oeUbkt`}&WwTIf1&5WhE3zLMG*&m0uw z$ERKJ(O(^MVCbi-ra(S`V$3FTT5gHN)OKmLWpR(csYsHw90LY+FnDA$=r^H0#-dfsPhNn zjGdl8@nj_=1k96?a*rOs?-H#9iLuwAVsU;>SSHV&7xrLWu}(Yf6)nivuK;{Y+ES|z z^&Jj2w19pZW3Qke-UFv;#^KJ)k791AR^XZ%sItxFlclmRc>d)T5Dzpb-kR)fyqq-g zhGVQ0k)9>X2mYZV?})-m7W&=CB}Ee=P|`R!B4%pmEFG`*dt4p#bW-=h0I*|a8xY?W zH=6B@*^lZ!vTf3t9aZP8u7RNhlCAx4d6ZE~!VCyY09n>PMKw=T_WzAjzMi5(aU(uj zJ&pnWx^*{2`pPL8G&~mNt(MDE5Rw^z%LMqgHn}6Yu5uoq@`{J9%z~)5)Opd;cJ??3 z>E?QfeSD?y47i{ce+Vp-`9Jahk*WFB+?(=>qR}%doU!@#ffz&3($2|g^myR4`SR-H zq`Dx2+mNTVQF_r#bExHEIo8=y`zS@*B?oHD*fEI#SJ0#3hj2}kw!zB@FnQJ_R=_dU z{@f7re6a>5-h4ous_QtbG`9>mXh3)%PiqliSc6Ju*us4 zoTL`ppS*n6oqm}D%wL_Q6G|iSUYdqatP^XB`teuQYYj~AArNzMoUyVT+V?6ifW{`s?|l-AqP5j+HzdihmVXip6c8BR=~d2;F^ok;oDIaV z%K!&N1X`z?%wndIy*k7z?!;VxmT?DYq0U>!Jqv%IHDGvTP$A1maR67;A$)ib>Pf!j z%-lUuVil~5lIrI2-94O(D2PHjIxcTe9_Y!om#$Q=2UXe|?d1EV!EoZ69HQ8g^Hx>CcjqfSG zfL|zfj^cvJA>J$X+?g8{8&4T0^NaXR76HUNUw*F!L6r(X0pd)+?O-ociEp}E(Ah?Z zes17EKAhS{u^qD`6-HWdLHpq$UAzZv5y<7QY1AGSoh2IeAGS5IvDFt+PW#f3gwjE6 zD9mfkJ$Gq5Kv=2k2s-huv+3KB@MM`ow^S^ah5hH-gDf2oJsv+p1bV}s5Ql~xp#sZn z`sH2-$b%s%s}v>7M-c!CYd5oMvf#?`_~S!;H<$wOAhBQ~VUNbb8mORp)Ex%MyQH@G zosUN%J!0^xo;TPxVii2$Pv}dMd2rx`Zs2~#0-&ppMxO!Jn zs~WqE8(!xykSufp7vz_m-fa`&U|bc>o^P|zoHz@ne*-p5m1vp_ z%crVLYZIsvh4&WUCo%^tbyX-)8+EaAe3w4>CP~90_fOa&%y*d`h^ZcacxD@T6E5`d zn{?ED_0ob<`6;d=npNnD3+<`sCFlJ=R|(11+ZG+3d$iLF@;8ADjx5KlKRoi`0$rpJ zB!H{vD3hlPLkU?pXu8rX8SK33Jl2$H2wj&sNZ_*BA4c`j#9BEW;LG>g%WVa%XMF{- z5f)R$Gg8y1m=^-(E^ zucKUf{a*x;y*L`Z){=`vGH!=F=2FhRUCtaHzrII<<45&hud{0=n1PR^aLNFt) z$%UT!24}>wIXi(c)3(OsyMiOmbsm z!Nl9wQbV_CDI}c{Plom-$R11HNJ{aU+JBV5fcp2w$-wNvKpRqR#hly?Y?LAJzEWok z^C7KRRRlQwg2{a^s8rgwb&c%Lw}3Hb=3|7JTXt9>ZvQEYwoCD4pJ%DVkc$rOu3Pta zMSDeCs10{M!zgi>Lt7=SKotL;g&@)1OXRHg(t&lkr&UEzu2&`9PdDOBATe+Fxx-$i zGzUGfL7xFPpi~e?c6IjdF$>$F69&VeYO;IpwQnbfV``PC3@E$P-sE84B|L&WS9~h>cn8#7cg*dINeTu zo=J8-if$G0?4#;1xzqXwx&}pYC*|TOo$FOT?mnvfE#{6Y5}a%8i%v9yj_dH|>Lf|VT_8N#U1yg{$HX$ zfSlF&{)oHXw$AXj0AK{e3ywuLKl^BTBQNB5hnILu5pJ4%4TF(=1U+0J#@mgF$x~^n zk{tg$pa?JZ9qxAbdMn^{I_j=f9k6ynIK;up?a5RR)hI(em++aXG7}#)b zz|8D7KXWrSI67l9b8~aU>AAn&{>^2W8UO>Ci6jgzs_-%SoNCcU7Y6j}2X1+|ckA7E zaMjDtrvjPqj5ndRm)( zbTP}?i_U7k?)Idu>g+Cwd3q0-{)PaeD(f-=$tG#<+PAm`0JTZ}FHj2r>9Ra5D@38DObGz2fNZPd zLwUQf$M1WHT~F-*`b!Xm>0$xrbJ!mpv;NrFJd-&Z_c|2B&v4>3a5knC-{?9N^sN6WFYP z<>g~Q9ezk%{$32MeOCKUgIsvThcv_63v+bzIZQ+MlLUI!zzCbJ{C1YFKf~)mYFK6% z9zi~%EXVJLRr8>yl}fw<3Lsh-pJ5gUtg6cQ$mX;#Oq{@ijgw9m1`UXfC~92YC)!i~Ja9QdZT9+W zU*|PgEgXRe;<Y$zjvzgW>9=|JYkpO@O zXgL8G^;|{3(p@|<)TqqkdSR=&v_Ar>Qbx+94$|s=@7~fC8u=VeuSi-va@$=+UvnJb z^aD4$_vK!HbgUT}9d#lZ$MHyIEVK9p<^XXYaBDC(z)RB&CzO*8$^iEWbc%jx(*O`t+O2dd-VjpP%TcVNqStSrTEf?| zw<>!#!$UO9ajM>GOgcELw3AaY-+VSFuwpaneiEa>SEmN57Dx03=mE!Zf4UfrUjf|s zd;yzdz^an2I}Hp&qlcx#y@*AGq#(x?n)@H89Jk~3eF1b`44CPs5V$hS#EOg9bm?2M z3Vb+!E~54X;*cIRC>=`inD8AR!dAZIc70LT#!)5f3bWWD#rwpf(_lGrs_7B14WsOp z-)M=xgDU{4qRCNn#L98vtVCr{jo|eFyX}4N<^GR&$A?md(C#^CmWK+Q^#qYwA^N*Vw96t9|+M6*e(8!5AY=AFK}) zX&4eGSxNU2up~)|vkJEg7zrib3U+p>?OmMgsDQe<nA&(sln^p5+0<}}vo?V>k6iuL=r;{XU#GXRQK085-m-4t4JFyT@0T}A3+D)Rg> z67gLN_jyT`4|N+JSkVSVpwmkkH8=LaAUEPo>w)B#QpQ8a;~qd;D|Pio#sE8+fc{AY zQH`cKOw$|zJ1b2Xi&%+vkTP2pIwe`(fU^*1^pTb~NA)w90=AdsE1yq|&GAAxHQ;C% zz{WK63pn9Wk;bqfu2=GuyZ@P_p`Thd{^eYramkxlb>@{6ZOvG#TLgUzD>9UE1B>U% zBYUwh6-6}GBWNnG2xg_TkT)!|Dlq_(|0i?YE6j`tI2y#M>ja>jZ!_+)J$qX-@(mU+ za>Gkmsvh)5;h`_y+Hv8EZ zZn3j3IFBvoZ}Cl=&urGMUvI0|tYP`cie|hB;`f3!RhZNB@|U@GR+z~b&w2yVIy1s| zWuOE{<2ax+1Dl}oiE5JGib<*!8?du4tjfMtgUhnxL-_uKAWyX>iL+pDJ@ zf5M-9>?wQliKm8ppW4I0{rj0dcnp{eKvTbbdL7VtGNMaIA3k==Qny)4eV%W#cn*8OlgIYjU3cCe?(x$rx)=gg z^|qh-PF``rE2zPm0P4wvTVU;prfklRv;@3FnVOzp{PH)yZ!#cKiiCE0++SIr;k)aB zvvG3<{ONC(bZrGn5inBm4glBRhm>y;mZT}plViQg-j+7Y???b*%k_mlnXIuM_|uPX zt+(I**y$~4(WRr;z5b|G{XT|*l7Yh*B-d2Rp#pCr2Y^fD4c%61kF(}z^^Je%<<;~ z*qkhk%~9Y8P)o|;=JHuY#2gKT#pn4Bb$wT9$H-}r9y`nE=q5H^_8p9jVf6rSagC4X z%#6@^h2_Xbl6@na6ZgpY3}q^Sc^%C*$5i*=dZs`^S!))WP?3kcjG6vs6Tr8Dsseq( zGCf{7H~lf#|Kwi3`A>h315ZCxZbYMtE)BhlG(!JA2#%Z+tk}H1zv-+qe9Oh>`URI= zXy;#kF=wB5PIJcQ&9;91dRsBNf(h^*6bT%>4E}rwHUN_JI!~m3J)fu*b2Byf5Ef_d z)S5HD>adQmPWw;;v%o4{%{c2;jC0Y7O=cHdLGwy{7C6RibKu~C>i>Y9Pi}kC9((A~ z=8^j!vu%$)(R+I9({p=v?}Mr1;ekH_^gBT0If^d&%p5x6U%l~W`~FvcH!B&XR?y>F z^6j(*RBP?uTfv#Eye~N2JpZ1d8Ajd?Cyz%Sd8FR@@YXI3{j`m_{)Ml(%HQ#$-^WV& zOh-?SJYCzwx5L!DCkODcOpi7P^t4PKCYQb*Un3z~S^~ zroeLP!+=W~PD~HaSb6b+LP=uz4Jv>r6i_mxsJnwDvnA%y&sh*yz>8*Q?BpyluL(Fs zLIrdz{0?to%2okS|4(|q0-H-81P_St@Hjp^0CD!m0Qp2=qtY zPti1VCyl~QT65kjSa;4#XlmSj-kLwSpO>38mcHQ+?;>a`F`P5mvP}$m)eDwT-1CM z$YlNcjkeOp7!5sm0Wp~qHfFf>)ulCeXbpc;;8Pr7O@uYG3=9({j6Cy8yYjb)j1}4d zUM4~ZWn1u5_X=zkW43n9nOySCk6nJ955FCb({SL}{^8S4@32Q7ezf<%y$|?XsYt;E})gxZkkqGBiw=a|UG^map@C@VcJsBbP(S^&)c<9#2Twro0e&!3YtAYo>7SzvXt|xMr7iI-92#d$Sr{zTEr$ zQN!`bAoj9QjDpHSU^I()Pq<$_YB*#MMomxF@9{;w(F?oiW=5dX9BZI(OvCuUfxz-~ zcRaM$a1eHC`3vsz7)V)9U~ifLx`shnq8cfTP3BIybo6IlZv{+K*ZVP}uw}!bMyT&r zKuo?^M6xik7IV2?VYD_b+H+XucII19Mw`2aS11+*Loicvy|d40|ES!_5^ ziHfpSNR({`!?}m3>#aa_8nDX-z*^3{>^m8q=u;2#YuoHNfkuXo<%7x*RDT+XFeUr}Fh*(Gc_ z_gvO4TWgc^`dn7eGcXMxPc6$mN4&*VRO&$<2?{pG!GuYDBm)^uPa_*3masOU2J&)c z&|)EB-=kv3IF)Z%zQHcIbc4O-(rbM7yWn6w)jYj@d++hbAGiDOzR&Nz?cVy4dmd)T zw(U$GJX~t(1EbF%Ev<_#3>fJ@cIOlI?RVbkH@xmL)!A%y8PChKGa_BLExyh)lzFA~ zs1x-938HyDEh+M&z)@Xk_LcCg{wytD09a2oIup8#wGog4 zm}D&gr_-+3;dvT+s{5IQ1$|B1v2T|>`t`e;(;ZaoqQ}It<@81>*Nff?$Y(%tIVa6x zvVsRVN{$)f99EA2i3HrE2)LM}{F(b)-X z0WJeRcCvxZabN||3&uenjDywz=dhU2yHr(`%|z$Hf#xn?-)Um{GRxYtUde_FUZ-l@ zkp&!eCgaRa?m=NP)9DZmeh2_Q%rieR+)Ucwm{p|>Vj3hGpe9rX!$M}bg^mx}->j1L zS)o#|2hdwfVHMsVhlAVq+t>c&4>+*n!NT%2y6EDC%gU^SllKTK)^F&abM^Vn<=0(p zSHJ99zv9}fIs2S*Su?(h@j?b~3M+92tZC8q%Ac2--H_@{dECzgc$9F$>73V3FuLf?%dcgL5JF0u`y1zLc&B3~uWqkE&|Ng)GPP=Ty z`OFC*CeITE6itRV>Kd-up=#QrVd=fouI}KS-xb?oGuX&nA7Yh2V5gP)*$V{ek!CLY1{P$zSetne)r9VCfn6G_ zuuxa5)0@;ZOZq9pLJC%Cf9xwmIdJB+Bds?w>Z9Ic?zGWl)u?Ie1Gv{1J3 zA!X@MJyL(arGe0LU_-{zYymsxz;>6fS3Do)L1Vy*()d}Rk+j84<#XbpAZD98wpHMM zkfyo249dqTwJcF)SPhK*wG;Z}nza;UJ?27s{9Ynbi_J*sMeYUkE9bOyY9U3_N)=__ zvOO9MIntrJ7tpk9Hv%cVD*H(KNfn*hEnwMd8Wp~0Ijfqw4kgvx5~1?2uGfdb40hZ5 z-(5fOxlaQm*4Orzu@AF*|=hZPXNq2 zf-?=cXlz+#QjjQ3=wn&tsib_KW^Orq!<3yuj2wiN_cdjfCZLM^7Fj2Q&QQOAui-l` z`xIdp8-)EUV5N=QwOcN>8@62B{J>kk%MLVC)nku6YIojtx8L^l+pD{7xoh~?eOsA1 zyuZ{k0*o%egs6)y45+KyzI2yA_Wx|-es>yp5`ihFZwNm~6AK-m~XZ;x3+L zF`&-tsWe^!FiQO-VTlP+OPV*duv2s0%sksMPs|cSTI?4ae^m zw!4~}C{P{tX%xWCS)(4yG=Z(zfZuz|ZOk6ouaXvBI{MNNxy*WuuUKwXh1WGsqPr^> zn#D{^4YQC5>)=+d^=7{A*pXnEyLfbXY(S{mK~u)vRcllFr&3mCeXJbI-7$;%#qxlA zITknpzlfx*XzoEd1-ORlWJ}sJ1>)xacAAvq>|EZ)cnW{*YDPY-Y7i!#jiED{>7gIN4wOp7fN&yCZ6U1 zn3!1AKl`e0vNB(B9oN6|rM&1R*ZMi{i(g%d-vUYpMT{`U$fi3a%=s_T@P`1&%W|p9#tl17hR}|+wk!_AMf3H_dQ(m z@{8yJ!xLaxTKpc^XrXM*&RS$^eUaM@jRas_L>j#G4UCjszH!SP%p5uhjBz?e7qg=q zFFmjRk-zsNoMY>mPGnJB9J{kD15e)B$+H|%96pqb`zzTh2MY7@Ifw|j-0I47Y>4%= zrjwID}b3su4n0F=0=JBwj2-3y288-PTseeg3yLUvaJt(XgF;Te(erm z?zHbqI)Jm!#Pa1-y<#4mXgi3Gq? zpsee=fxRaI*!1VPt|8E{;lkIlV&la$LlKfTP(vIG-wVJO9m_46<^)g_hw>fAg1L~) z++cv>%O*3PF-6`e$HYrJEVL63KxANg;*J;n2UBCH(3aFg$||ut6G6fAMQy)?9YY)ttTlY%2=0 zJ_MfyW+Y8qj1W>megP6w)`~i(N+BbE;TQ7`(fQ3;lC7y-vF$l2JQ^D0?y*u1a-dh! z@#A+}KuWz^!X7OOsBWd(AI1E#4O_VK4O{Gc-|+41oIcpQ_n!Ow=C9pix7>J3eeccp zvVZ3;V2+&0*+my49NvA%Z~n^H?VT_GE|$@!Zo669(F%`cwM+}MO#6lwR%O18b|5m3 z7AC04-@k&bs4<$2n?^XK2eo34D5*I=HfO-DUC62et#h6A{2 z*d+!unl+&JMtTdz`VvR))WzFdOnKy)pQd&bj+rt-rC&(eKdxW~a z3z#Jbshm9g6a-l2U~~hUE`Bp3V^9y&Jg1!^5MKr=lT&JCS-uMqBeERLs#a=~8Mqmx zY{VjCpC+lP@w-6)WG$kWdfbR;REXZF3*r%GhX^=oe*_;)V|RYwJ^s+=KPxHdr(1N< z#c*CGWMWnS(yOm+u6g}S{H1Ssb#wJ~*Kzi`vuqM*N_zPeIfy_GBG?HfQ%K5J3y9&7 zy(t5Nyuz$+N!(ybSS=Z2)RQ{MLDu|t>b}CzAgfdAc1>MxH;JGLsq2N!$=MTY{JfXG z+P>|juV(kp9`4Jx(kolWQrns98Hb;y|5xD_Lxu-?6Z zma%c*W!VDg>KN7{;5}bLf43EYG~y`zQM}&|6`Wem=+8Wix|zcN&xbS>Aa{Q=Xkup= zK+n_xExlkg))!~=!!1HSF58X(J4)8~Wxyv-7O**5(#$siHD&NzK6P2YnMH)qT_nvo zp5O|q3h+m0{GlXyJqv#hfJ}cD>l?8C%{;SQ+fAPm<24NXpoIY&LEmjf3Rp33~jL}uL<;AbEx4igO?EHHNdw1M* zw|)6@H}Sb8^@3$R?9}T)w#F zjL!Bbb!TQiCP2i(H8)dqB=IoFBSoNEzE_kq^xN*3+x^%sV3gA#x-ejdi8ZVJ$Ntfe z`n9VrV>X!5=pTxH9YxoOEZQ$1?AwY)vuop213HmF9l9xIoO5&lIuR_aTU z-s=LS>T#NIj6{pn$?tvDzIMwPp2>tq-d8CIntKH4|DU&HXEaeyGY~`KyG9>4>NR)Y zbTcr0+RJBk(J(na&iKj|4nSc?Iyg~V(#kevE6(d@8b&k=_9kBF`d;4z$tJ^13}YfQ zAz}gHhA>mvJIBH{$1w*BOi+*DryE8D*i`r42vBF)P}aq5O~@rJ$HakNf7E-uk%do% zE;(m(!o02vQ-7{(1)eGd$G0lg&-x(tD3Y`o;nj4xkK6Z5|;G@zRQ z9$2kTluRh;>9K=r(VsI6*U6XgboKBAH}m;4b&L9(N@t3Cb`gmHGt2Kq7je~u*5xRL ziAc+o8R@XOKL&?(9QLpO#UFCu>4$*v(+G^~q60LGH#vRQo^e+1syDvaU-fOTZ(j1c zS8@Kim-vc#y-YhMz?uM-DI+kJK|*g=AyBtuqvobVi4hN!bs9+;dbXdD57N}YLBkZx zNSU6}{v2E_A={+gsivC#Kgl+2p2dM|d57`Btrn)nQkRTvCs@ZmHS(2!8&E3g_GF%h5wuOSi)J<|qK@>v5; z7At^tEjcwFKF$2|wK`C~Ub0vNq5dNEHCL78DG~nc0b3RiG&bts6c&TYOa-`4QxEP2 zjsv4hoS8Pu^7U7;{`}Ws6;P*nQF@cB9;u_oLXq+#DcV?IgBo6HF1v>Eh9@!r2B=&w zBoA_v)`?yyF|5qkSTOkVQqF{s?tm%65Dkt>^hcl>V)uUXBmUS;pDl%ZEZykXnq7Es zH6Oy{%KqioU)#L=ZEv(!zWMcj)wS2yy8a|p0kx(=*Q!j)M3XDk{7M)Q>O8JGUtuxV zDJO9>)qOODO$H2^!2qITm8H#Dl3MEdxd^{y;UI~gTlW-Xm3inzMAQ z2Br(lG6Gz(=8WpHZ~tz-=i9%lesJr<)fYa0qkZ}#pRK=fEu~vhNo=PmXzDL*wT09c!BH}um%Gj z{Q4a{`Op(D2>GlooY58I{I$lW>j{eX@?tNRM4wV6EHtN{?KM= z{3s|W6LFvN(GC^MQ)6<9il*6Vi~wtbacwkh%2}JxKy$cU5a$i)szB|r z0CW=5)vcKM1Quw~$ydCXryNblc8W7R2lC2f?*KNkcf)G73M$z zIz0lbCIBX-3_wid?~P&GZo99!_1%BU%*+vBq66c)I1SjDz0oyWw$v|v^UIspf7iD) zFMi{z?VMF-cpq#4J`Kb)Co!!-U+ybScNU``0qEkkR2S1wEF`)2GX`XW6G|Fc%JgUl zIW<*X(^1i#FXH1yLZW?^z! z_2d8eM|jQoud-nvHD#FvmaNwlbU=YEQ$}F&U7jI1&$- z6X_b$dgWare=aBQ2A;d6t0A-LL~LR_=$VmI^32cvAKc0NLt)A~>VKMRb-E|W??{=L zzU#)X!t`NHL+@CdrzgpyH?d-ck1bnPv@~%n^brnj@mdT3UsZG|U23&(uXrwIZ8}4v zS_%Q9QSdMz@)nn^!o9(qdBY zVW;f<^33m}3I?-yeFOwgvoJ7gl8(1-A}b=*(aas*oR(Nq0L>=Jjq!xFSpf$y_T!ul zTyQdgO)DMiI4~ngO2cCBem08=)8**mB!)r;K6n7?9YBAHv&?1~9o_iXY3Th?7!Klv zC?F&`qZI?Ia1UAv1b6VDJwaLNal}y>7QjS^U}m_aB{$OXvWvwRu8;z6L~wyvwyaM= zu*$rk<51kv95ECsZMWVie*C~}bL;#5f*lXuSq2!!5{fRm2vF24FvY<)_0oMvG`R$zYYi9UA4>)zVVg#K`gaQasXR<6qfAv{ zawsS&?ad_yC5-&{BcQUhiwYdk;7T1>leWrsOcZf(|2iqRl)w}b~dwI)wuPm>nsY9_N z;dwuhDl3^5*ZSL;m>R9?wQgIOvpc?sp1KbV!N2n5uQNS;=(N!D?xF$e-fMs4HT>W^ ze~^j!e6`%fCI{=F-67m^kh1+U_w0F)txrt9^2vp=egQISE}&_sBV~9hGdm|VmcOzw zBdRK^G}f)m)C8ck2)w2#^NFUWCq_pJW7m;7rLHzF508Dxw%t!P_k8(wA@Q8X(M3J6 za#i(BVAI?oUh9HC>P6@zXn#!82CP)zxL%yuOM2K&-rpp%IPOhZPgs|j1d+2xaWp41 zdVEA(%`izaf8#{gcK1-fSuto?KrBt2O#=paeM~wv4H=*$pk|EXN-wi;3yHNrG;7NK z#t*;|+;WhZoQtGDa<5dL@e)dz`|KSgnYju*P7hQDD=0hgd ztm|F*syFbKA9}mL`mJx|+znfN6ey|YsF{tVz=c~lVHiq!RwV#{)Qh*9Iy4K1_l<%H1KLencxQ(|BD&jHqcWM_c>*D^3AzH?aNth;Bq9tZ2<3@HAJvXH8 zHf^>cFf3(8z-~DA5?=hbF5xGC{6~6Uxba5+@cTa2eDRYvap1}AKvUT7Bb;v0MGvNq z`E6gn(~f@6fEDHcIG-SBXFg^CVf$jSc9ucUH&lA@1F$Vix!6GNr)HFZ|EmWdG;3`mccYFaDz2CzmMn4!&W zG8d5?rRTC&>bU>wxAD{?j{{?z?$LzPnT z*%@@!n`uv^E6ZcmiLT_=Z=X^X3)T_3|9ruIP-%(o?JrK;Y!lZGX4 zh!Polb7TzmJi5KQQb^O@wN3>1)9^S~qUqk! z4*6lN1IyI7SqEQMj*}WP!0RLv zVu7PnPtw!f6A)4WQw?i#_$GfJu*5jT#DzP*KQ+Tc>rHgHC2PZx&^lX*(z(eY`s__y z)7!Hha$}@+=k&~ZUK%7O!(?p^`&v`#5S)oAusd)3nlpXm1w+i}qGEFOYWkxi-gsm+ z$}GCx@GhP{LC#c^L(rM_+)?UxX^IwNk zs#T_9pju;ixk(G?h+`#<+yYa_aIEYZ0KcGxsWX-F$?xcCcg!k;@;RUKjRoT(ivVnJ zad*Hde?p3RGz&sx2ZSP3%^$n`jKNi%f? z{gUmuCxVn0CsAQl=H^C;{-g}Na(7#Zk((A+uHl8{3>7LdkO+|hqX1~85W26_*8*+_ z<4D}qRXzNzOPYEQSjhxWAd$0fDH~UZi_)oBczE1&=Gw}p4^hN*xSN6S-qvHM*;O&}^ zkb$eAyz8;%+u#{<&?Cb&Ad~2nC*95 zbTcX2A(nM-fT({NMCr^R8uB>#AOOeX4c$1g6R;+N1z^REykvHUzX9mP@CMABm`d)A z$M%-rVx_&}j;_q{vIP(I;aJort<31ToyOX;1~k-un5G$m^)V}c3s$g63+!A(Th+i! zA0pvL4_fRP>F&&gT-?90yhwplDW9x;89cUsInfiK~Q# z6-|9VZ~*8nVMbXERBX8L^(><6u4L_2H2(f3>;muigvHoZ=c+U35|Wsxi*I z?BeS6-~Tqg?FYV_7hQEdlk@53t^gUDS}ow53~KT$f*cT4Ku|%iEX-O-;wgw3`vWs& zHEOhEwC08-`GjSzJt_smzNXIbxl=5juwXM&2u&l*y2H%yK}~^@fwT_1tkrEd0d?cw zxUvDC2Acu;;4eA%61)B%{S*JuAOFGLM?d;;-v5^$u5bO!tw1qoW0a*FUGzD;`>@@4 z``!M1*T0>9c8?@rUbfk)V`kvEREDfB3~seo%-muPq6$?XJb z-Cwz--umEUnudPb8VGgaz$laJ*HDdM%`A@L!jv<>X~0|X0CAPHkjCxtp-qFkiq5Jw zMg`tL)Rl+;r#H-VOXruOxsfR_Ryp1Tpi-qAA*7dsWlRUH)1r3hd@BS|veW!pb?U(p zU>37}{sbt?Zh?tuxyX5PJt@%6K7ofW_qJg&*^QaZwK>EEG7d*}AFghF_aD^3o^Ea7D-&lJx|@w2WpaF(88vScr;r1NJ(chPXO=hww2YDeHLkx-*=P3A98@AXLfAjC~eed|5-p4=wDc=1j@2hXV z=@vMC1Q_cK+m>wffLXuu8~3s2XAW?dt<6)$bNLCZg?*W)rsphgvSZ4+6m*nw%FbGZ zJ}0`b?q8L~+wZ)qzU%G>PY?asE(N{%iGT7Vyyen2(10~xF338&RY4Ut=sUHCwHA{eOy<{SIyHuMc5`O`QA+A?V>{zFz_if%LFXhwB zlqO8PHu-ZG`3;(>p=3Cf2GEhYAEn{8&)rnq&{yz6h%TJ5u`!=qxn`cSO<~!&%o7@z z_VnYNb@o~`^6Mzq;LOYF`gR@6*79y){&!25M4v@1kjZjuG z0mTX=o!t|rXxxVk9L&s(Qr2?DUQC|-vQ2=@)O63~okiP)D``=`Cn^4FypyDZyHuk3 z)j8nV_J0%h@#OdB6VJJGyiWLvGz_CqJ^0u|!+SpWb$zusty!C0G>j}8XL9wb`0^gd z+eG6aq6x4Q4SS;dxD#E%0h(a)V=~bZP<&ii1|pn`3-zcfg0ZEj0-XWG#Djafcyf5t z03n?`@<2U8MFxS@2?0oT2Q2Jc_Ud_s#1hiklyw?qTQfX@H^*UQ-Mo)UK%bDoMfuE^ zt-xzBWIzW6I*XUZD6l3|VQ)!Ar?52-6kzk>=h8fAG>8|^#(a3u*L>z-gfL+Q){j8_ zG*HRuTtZPCx;I_)Iz}hwO@quJ8dqWQK^)yRM2F3Qn7(e|fo)jE#B^}ev<%0rO4v{q zG3VI8aE*JZXCBH-Q%cP-Du_C&W+!(4rUN8{Y82aX&m+yPA9xotGl#kq^iwRlsG;Y&lY&7Lu z2Q)Gu%2-nQz=0Tf%9t`BHFd8AEHRg|jz->&9LP-i)^@X%ED{~iJWDrY$yx$#w=j+} zlLSMeDJBPfV9VGV{?2!QKi~eAH}yXH$xrep|NAfNuYdX$;7I49zT~1B?0Rrl@4kl~ zAEA-})9{TS^!pV{#%;Hjzo)y+44y@9$*LtoM{ z)4%XFSNY%hr+=68tBp*j*Kb*QA|udzz2yvI6cqEsuU0b%6l}|%lexT%>(Dc+N2*i2 zLqO2^&=mGOqcncanU$f8TjF_wwnOh6*y@pyq`NCfyzr3sfPTsJz4OMevh(q6 zovh0Xjj=hojOA-rnVA^rxxR4gy%N8Pueb-2f(78ubAvwj?8cMu1z2>qi(C`fmc*GH zGm-T$%p1+$1dv~u8fQvtd&cPK*jHA|P#kbzi~8)zcMUxk@l-|*JTyO4*% z4Y?m}4eTxJE_^P5&GAAj?W-etS$`Ibittpd5@lwpIC68E=04zPX@@VBR9UHOj`7u3 zu=bo+%P2rum*u}AnRcL#X#+R~YVjYlU!#Qh1+b81Yg2RM$jd&iIP_P2d!@1r027=QA+@A@Xd`SoHl zG}!^1OCtJAA3W-J-hNLt`=-XnsF)*!0GKL&ASNZAf`zhw1{~<-cIIY0W(%cUw`u#b z9H4wM2f}Ont#{luy!ZC|yX$*N#}wn6)-^x(%YWBifA%YU4yZMuNG2cU8nRF%_V?;^ zuAo*b-K4C3TGO{n#N#Dt>YhJ)GX2{8IVXUqg0PS~r6*-TQ}E@vld??Z*cm(9W$Ya{ z>mnDu(dko4#fUNkk8icNz{s)MpK^~P2`D?_mi#~abT4-8YoK-id8{BH^TD zEiY&J`U|Oti5s|-wn#au!obt;0%l+Yn!16-o7zfQ$Iar)jN~xp21KEyLd` z{k9+fLA&ni>zM#%z>g?fN1t2wi@ec{lJCb(GfD8yt>ToBocLb=xzwr5+Iydws9dkgh`hkD& zJ-qXE-^&QtbPE|p)@N+x6u8uDa^dDa0*(scS+->%_ipZ-p0hDql05QBFRdqnmU&i& zEV{Nq-!TMClw)W)l$C0_zl__<-#q5aXeh|50H(AlHxB9p58i!O{oqZvm!8FV;Y1h9 zSFU1W`HDiH&L5BNGESe@F)%Z^<{ZbQE>GFvv@$Gnls?maaVTvGnW8~=Q-yfV8yw2^ z$n-3K-OF~0R%bj9<$Dl?G#odR8`XizsH)y+eoq+;=V*ME7z%PyzN_}8S3ndNZra|N z780w0v0ylk{PhIfYzhg&OE&l!&n2)q2Gk{$x+xzopynE$Nf1ARctu_b&QTz4Cf$Dl~zHEk`jge=z*DOW~nGXWxbWl3bHFjM#H=S}5XM1K1s=-g zX~^U*ow5!Cl1!646-)Iga|40gaahcSEM*r8Fe&xx08Riri**3rW{Q(ABu&e!L%C{e zMsQXKL}~_6zN-mBp7JkXV|EVm4oO*|`Bbig*pa$)(Jdteu>+{FLy zC;nFRUElSc{XhSUciFrD;Jt%KZ@)jhTl6^9qKgXX^&Y)%YxC$+Tm9VgHqiry`Ss-S zUWni{ThB74r7ulDN-Se!hQ9%KNHj7-=A~*eOZ~~V1Ybx~&n;aiV5TMM-0@zPokjCH zpWw6PUBpYdEGwdsHYCpF>AM5*nVV>L6Shg6DqEqt+-B+jhd82ZB>LIOtsb;TX;DPOE#FX{$-fji#D|N}eRraRr zP`*c}Ft7qF;*O>^lzT-O5r#qO++rx#K2P0>EY74xfCDxU9{Au#HEl)sAiZl9=0&1QO zJj?>4VqsyWVJia*DdxwYxp*BArQXEc0G$GC9s>3Oy(Pvdb0XleV$-n3xtmEum&EmVula89=K5=`G*5b@<3Vk9I~`OEMgo z89C?ri}?rt`v10TmtD*Zcq4sbhPem8E*anF`zKn|Y37C{&p&-OD=Sd{TApc9w&euu z1dO%vY18;N({-6dOE|9H=UIk_WQl1}H9>Tp{FE#bZ@Ito?2!N(OH=b?ySN-c&=lX1 zdPjk$_wTH}@#!0Zy31&IL4^YqE7q@PbaF!8#RJ*Npe(x?gbdCoHRs{sTu4mdrDQPe zb?K-aP-iU<^~!}W8Bw}uEm=m6SxguQ+?2Fc%2;Af7|o0$HlkhuhDV&CvL2^>4CZj3 zP1z2Z=wzkuQ_@MNGfPPrNvtW^-VN>8n9KJg#XxARIHU7y1DhkjvH)yGNA&*U)6g}S z(3lUM%43$gxxcsx_m(i|QL*9NS2MYK171^lEY*}rI)ymHnO%$(#Bj%rvT2^)Z6dg5 zN?4CZK@t2k3+2G^us(ib=sLp^QLFH^MTFLJ0ltxO*!$R1&Fvp}7qhdwpGTqXE;_cy zabTu@{&m+?|KN9inP2_$|6RS~Z+tJS7~?qDATyE6oks~^qkEoaYzgDf31NDi7A(rh zbuC>%*W9EgA3Q~go;+RJP1%zRa4*+za1vc>OD1GQZwt%Q&dD@2O;g$0Ks|}jCOu?6 z*aG+T$=_bqWt|+%^Ys24kjlGZ+L>)RyB7Wi@8kQJU!> z4&3VRkprh{xR*cEjGSANfu!jqgc#_UJkR94MQ^3#x5u`&t5zwiG-+^lJk89YMJL=d zpjm!b*6&ybdM28vo{&H2gWqw}SBDSYdfy9Dr?(qJ^sD6?Hh6#3A`8yla43KzSTc+4 z9t?cVG&3j^)v^8jYLl64=^TVv;R#r2cxnP-^6si)*HM4dN`K+FS;QtH%QW0brEavd zsfd_KVZS)^zGGG6(%B8h`j1PjO|ZpN3AD)v3xM&2bDDyJCy&)3jJDzHpVg zLveEq1N03bbhTc|v@}p9Vmu?GFqpya_{e*G+wHfM>(uC?i<28Oz$|OeIJf$azx#vD z_x#L{bLrXVy938XhdU$WRch3ekQ|i(q3Px7PMU5LrX?Bp7s{&$eoWB{@-=4d>Dw5% z>R3r#!W;?h%$?uc%czcDXs5I{ty@4;)#8wornWkP> zrJke>kQ?$?lCqk=3kYuS8Pibq&5V*medz?FJ`dZpGxeU9bbil`dvo@vKEIqiECP%A ztk2Agaz?zF#>)Az#Dz8` zq&cYerZ*}at!xVIEHhwp4dAJzW1fm$6&H%V&n2)q1}qCN0R&)kHL!ta8ajd}hC@?7 z4E6RCU~BrRh02%nweqZMSb4@ZG);K&3o5Spl$C`-dBlzaH4l=MZx7`SQ&6RpkNXFs zo>IN~nMJC&VM#WnmHHFPhoC9nQdkays)F7Kw(a&in!7*t{-WP7Nf%w5yeKv)EbG1c zhu+5b|NXz^uXyEanFMAFLlbb*K}t3e8n){y6JRuea2jUf#A*3}AKhJmN@eq@=zY5r zxDEu=3vNLgjS1M7n+SoL3*-^cnWnJinwNRFr$o;jq_Moc<_kCJaZg!kEp84iZ$(;{ zZc9y=l4Itf*LZsjz=vR~7~#j>^j*B>6|e05`Mcj!{o$|w$v5>k?lncS^h>x3Ni zv_yI)%iz-QdLG(nA_BU4QqBNZhj=wH(sgB}>!hxjIGdvpfydO|vS<(s>KomOiVZhu83-l0ju@K zu?CIPPiJ$8H&bBX$_Po){n|_*QR9Q$$u6!-@WXWr96h-B(d;YB=ZQ1=vyzHFQ9vUr zz-ALZ8-cYfDh$lB^}6Wb_W_5NcpCa78!vnqWNeSgluCm-wv zz+IfgXehdX{R>|4vg)7z`G4_W{9(?+2%bT`_tGXC{V7T!W%UQl|9hgWg zST=Mn>kW6IBUwT;3T80wu>-5*S(m4Q84@O)35YL;GD5|zJu)n#q@G!5`TR0UnrOjB zh}mhBdMMP@rm1DG(=80BX?$ir9iU3s5MuIBCFyVRqZf&W(H5%(0#Alv>H5QE`D|d* zv#qf?9)P1dF%BAIk&(MJxGo;X{b67b+U!d%-DQ0F`K;aYYB2DeVJR?T0&1wpFMuV0 zxy;{KL{1&6DsVZ5S)7>^+P8K`CLL7}{jC-t0%Y+8A{)qrb}8?(s=#{i$d^CIeV_dV z;3om_cA$&yJPv_ltlY4vdgs6V`^|rR&+qWVKl05UgaGoPdg;ri@o>E-o>Ubn?t ztc|It3=OR(hO#gdz0I72q6T}qot&`|$_bDv11i(H@`-8 z&zZ0&IO_>msO1-XBU!@0)b{8EtG>gc;dvcoY+N+j2ibAP-^=~Ob!S{;|KnHwL+|(B z^&7o6zVmHBnJ%EAi{~RMrVkwV`|o{-S<%@P26=ldZ1P6ayfs=Gm|B0Xg`10hwt!2m zZMgHHd+RTM@f*O%l44nPG0VD(&#r#{-~T<{c+M*rgwc)XvMioS&$XMo<=3J<_uC^n zeYau@MoXj&Q~?l?x>O4qF%V43=(8;Y9=&}MELoQJBtWajWg`twCvlyhEX zI;Cw|*?O$N{C;x(F8j&{J_8J2kUG6xcz^loH7r}d7Q8rwlMd8@B ztd5?%*-kxpf^SXFck=M(S@^X9YSy0jQkHMHn5GUMXcl`6%+x6yJc#cCQa%ycufU`3 zg&FQfVQrT0URae5#B_9%cl|06-Yx`k)V&;V$D*ERIZi1R*rhiA8@)w~OYSJA7zQ2M zb-?fV(7TyCwgZ@;i!M$MOLMGu{kOk`ANprM>#uwLTNnrCz=qj-fUpP!&}##y+5jR~ z#zIVwt^xolmF1ZRs%@7uOEGP8lH!&+yh(KLOG#PlP zdeKfUOM~cKD{iAwGpNp{^eb8OoILYG`vD|vT{3e;r#n6G=HSAhlSubNwN)$d9@wp) z`(l0nH|~1j%2{+VT)u8iHMwFXKCdU~C8Zn(r;MlFiSFeJFk0+;a4geykxs%JPjbH+ zWvm1x(tQ)w?q>;^!Bi!9 zt=gJFeH{N*EL+PR?>uqMbLqgFCUdoG)7k6+b*m$K?u@>_5Gc=mHW`~E1=L&-fKAHZ zWd%iDWSHJ4X_3O#+ynHM5~4142`gED-fI~dGaW_8aQ9?J)B-C~ce8*4>olvZD}PgG zbu$I!@t9(676v8-fE6b#BWhk4_Wx(^J)kAI%4^~MRo^suq>(hr0SSQskr5b?!6w;c zFgZHg&&D><29t9ZIVT5#{lJ)P449m4lcNyIGm<9H4RdeT{{P22Yu#_{wcocI-I18l z^rv+--PNZ~o$9VSbH~-+FkHrQ|Vm?2Mfe-+`P8Dza znEsBmgrwr(D1CNVro5M70T9Nmy<+pTb_~}(-5VSFxor*fX==D;vAD$#YnUhu%W%># zJ{!e@qr$0y{|@OEgRNzNYIvLOW(vUeegU8T-yZ{JcV5HfEQoQ84qmM}d=sYEtR;Ie z*ft`&qKigfB*wMCD$M0f2T_<_0?KX(?F4LuOZAEHeP8621BC%-`ji0Mr^+x5HaN8% zORbJ-tZ+|Kj41EWb=vtU%Z-!bUZ?HJl#3621G z?gcOe;y12!X1w85FB_cmu9r<*|Lj`;m~EdDS4WIvuz2zLm*Xerp4&!_&@4Ec`du1( z6vmuIpP}2dudRV~b1Zufg_Km5+xgPhzcT#h7yoCRI(pE=@c)_xJ?2jMt0z1jC*p9< z7ZMrHh^LyBMOlShum0MFvX;Xy0OoyM=9c!oEEXOq`<39N2Qk%La70rs(I2IMRvM0n z*St&{lx3}{?B38R@2}4`3v`=)%h&6&C>Q`If%xu!e{=ZlPdB0lI*j8`oEr_W;pokn zUNeQhhi4EVXI^H#Nl+fTlGdF_Nss|zms7U&0g8a8l;@5`gm7h0P0$YXNM_Sxux%rA z{}ez5D#Mstwwsh~*Ub5?x}p!~K@Mx-@WSCS^fNI#=mH2Rlfp(L zK~B3VWleX$LSt+Kz$yC^*qm;uUkhzAfs`k|`AQlG`Pr;60Nd5N4LyGfV3_vcL3FY8 z00ubh#NWW`4M$x~#owB<^dvCchxqO%KQ#RLH@@0H&29|HT?H|Yh5yUa zJmr+`Pu}osKKDIu!fkJUYxF?u1wz+g5@U|OdrLr*d`9OYZc;cUt%^FM$lEnV9pWe& z|8K@5)f7ZNM}7@Mz!tH78i10jE)A+r6 zK8WxAz}vb%efD2q!{$vbRb?Np>KMlW^Ox?9?|C@v?jn1H+IT?`F@xHumtd9ANdsKcU&=EU_EFSD(5Gzf7hGhDbIUi+IS=wwMBPKK2!hC+bXC^JrNQKq8LG#sxVAr+k|GkjZeMqj(XfX$i4*zA)v2HUQq|Cn%aT3Ukk7ER-~hMz{C`A>5qTffA`}b z0I=&SNZA<2IQj;oaBz$J+;i}(_r5M3`-gvoBd6AJ7Qmujq5{AT{(M|E}x)5^W;yPhk}f>l(0uPHmjBx;Qoo#{^$(A1Q29Sb?*Kliwl>a9GC z9aH)D4vAL1Ppz7h0DgMjkNYou`hmZY?()e|&Tk0D2HIU+(fX#I$f8 z7F-AGAB0i3JZ3Ud$ZEZ6Ul_pN-vB^Fd(7aNYgG5TJtdi8G2+x@5@JCY+Jb#M)2 zOsp%iftC>nvHB;XZ5PuZHMp=WsO1mxic-LIETQ_L${ckRGGo&_m_#hiF~0Y)f5Da? zf44D-1LGJEZuYPC)=nIL;&I*Yz2fP3_CLLex4*^N7y_}k^?czO846^jdr0m{0PxR@ z7y)n!buTrbLFn_ROUDueBihN6YJ;V+PE*UUG$EgbG*gWS0A*N+hNEmJYpuOdH+SQ5 zN;xJ>y1KH^G~A@g`{H>98AJAiZv%xjmfP$nVZIz48xCfYtL!zO;iN35+GSb+ST$}k zZrg5|5VLJb>tT2LZT`~--ahfyFMbl%AAcl(oekvNZ!r!To&5aA=fy=kF9{<+TcnH& zbJ$-8Ae1p#FGU-_NiF01(*lc-&n(C>(f0Y|r#`cI!S~J`v#bt^vBxadAAeN;moNQ` z?twSH7YK0Q$U3X_HKyh`0bK<13s}MolxLY`($g=BsyUY~oOxhg+7$}!<@)s5l8&SQ zs*ZR~Uhs@YhH8pyd8sC(Tofi_=Dkcmy|lI0v<7mxcC|kZ4jQojnGb##7k%f)WAm{? zI(n?#xB(lFI+6gW7myh3WUWmzrxu5FFO)C4C6gf&UG60H`Q7Oae~uuzsYVL9_ZnLRNDkRqL5K1QC$!Mue_)6~ew`s^4^UKn6e4 z9y-e}G*|}{;Q9akt^PY7`!@jl#;ITXImR&yU^uw(-R~NI^AE3yKY0A(xp`&-_5fTI zO~V{CtjNd{9jgmvCQOo27M|clI+mwS3S?W>LChg_I#z)ObrOQq-pZ|1_BSck2^{vi zpLLkuNRFe=XKizo`hF5RsdT1Mw(FL3M`#q9q%;NnM}DIk4pGXuYbwgNto+I9WEmV# zrsuuT{!U$YG+*$9b!{Nam#4-dcdgE8Ge zO<@|6o`6EbR#biD2yql=F`TsvevZv4LBlY1>EP9KA!NJW5Blt_vQ2z?z1zjV*7FKO znl4zg`T=%N>DQ4+8LzI zHkv#g+I~RS_6yPJY+Hf0p(g_UA#t7ei*o?y)s0P4{8S*ho?O8*bNskVGr!jw08_$# zwgJ9c+)x-U*`!jUJPjlm?) z_ZCfH{uw*A*Ey{_xt^yRRh`LwT0iCbj7%~IMFS%eFvs0;FFx$V%*Krq5B|Hq;B(&dmblAp?m$X% zs|R!xi1JS4HZ|I_

E{g3g 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 Date: Wed, 8 Oct 2025 13:30:59 +0200 Subject: [PATCH 65/78] Add failing test --- .../TestSceneBeatmapCarouselArtistGrouping.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselArtistGrouping.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselArtistGrouping.cs index 1178f89da6..cf71df914a 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselArtistGrouping.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapCarouselArtistGrouping.cs @@ -283,5 +283,18 @@ namespace osu.Game.Tests.Visual.SongSelectV2 CheckHasSelection(); } + + [Test] + public void TestManuallyCollapsingCurrentGroupAndOpeningAnother() + { + SelectNextSet(); + ToggleGroupCollapse(); + SelectNextGroup(); + AddUntilStep("no beatmap panels visible", () => GetVisiblePanels().Count(), () => Is.Zero); + + SelectNextSet(); + SelectNextSet(); + AddUntilStep("no beatmap panels visible", () => GetVisiblePanels().Count(), () => Is.Zero); + } } } From 9ba99660786a2c25e73c866d70a492576ca02cac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 8 Oct 2025 13:39:19 +0200 Subject: [PATCH 66/78] Fix current beatmap set being incorrectly expanded after collapsing group with current selection Noticed in passing. See preceding commit for failure scenario. Regressed in https://github.com/ppy/osu/pull/35163. --- osu.Game/Screens/SelectV2/BeatmapCarousel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs index 93356fef92..e75ad7e8ed 100644 --- a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs +++ b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs @@ -371,7 +371,7 @@ namespace osu.Game.Screens.SelectV2 if (userCollapsedGroup) { - if (grouping.BeatmapSetsGroupedTogether && CurrentGroupedBeatmap != null) + if (grouping.BeatmapSetsGroupedTogether && CurrentGroupedBeatmap != null && CheckModelEquality(group, CurrentGroupedBeatmap.Group)) setExpandedSet(new GroupedBeatmapSet(CurrentGroupedBeatmap.Group, CurrentGroupedBeatmap.Beatmap.BeatmapSet!)); userCollapsedGroup = false; } From 30412ba3f2c5b6debb9a0e3b930da6cc156852db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 2 Oct 2025 12:02:45 +0200 Subject: [PATCH 67/78] Fix song select V2 not preserving selection after an update operation Because the detached store exists and has a chance to actually semi-reliably intercept a beatmap update operation, I decided to try this. It still uses a bit of a heuristic in that it checks for transactions that delete and insert one beatmap each, but probably the best effort thus far? Notably old song select that was already doing the same thing locally to itself got a bit broken by this, but with some tweaking that *looks* to be more or less harmless I managed to get it unbroken. I'm not too concerned about old song select, mind, mostly just want to keep it *vaguely* working if I can help it. --- .../Database/RealmDetachedBeatmapStore.cs | 37 ++++++++++++++++++- osu.Game/Screens/Select/BeatmapCarousel.cs | 15 +++++--- 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/osu.Game/Database/RealmDetachedBeatmapStore.cs b/osu.Game/Database/RealmDetachedBeatmapStore.cs index 6954bb320a..f9f84c52e5 100644 --- a/osu.Game/Database/RealmDetachedBeatmapStore.cs +++ b/osu.Game/Database/RealmDetachedBeatmapStore.cs @@ -82,6 +82,34 @@ namespace osu.Game.Database return; } + if (changes.InsertedIndices.Length == 1 && changes.DeletedIndices.Length == 1) + { + lock (detachedBeatmapSets) + { + var deletedSet = detachedBeatmapSets[changes.DeletedIndices[0]]; + var insertedSet = sender[changes.InsertedIndices[0]]; + + // this handles beatmap updates using a heuristic that a beatmap update will preserve the online ID. + // it relies on the fact that updates are performed by removing the old set and adding a new one, in a single transaction. + // instead of removing the old set and adding a new one to the collection too, which would trigger consumers' logic related to set removals, + // move the deleted set to the index occupied by the new one and then replace it in-place. + // due to this, the operation can be presented to consumer in a manner that permits them to actually handle this as a replace operation + // and not trigger any set removal logic that may result in selections changing or similar undesirable side effects. + if (deletedSet.OnlineID == insertedSet.OnlineID) + { + pendingOperations.Enqueue(new OperationArgs + { + Type = OperationType.MoveAndReplace, + BeatmapSet = insertedSet.Detach(), + Index = changes.DeletedIndices[0], + NewIndex = changes.InsertedIndices[0], + }); + + return; + } + } + } + foreach (int i in changes.DeletedIndices.OrderDescending()) { pendingOperations.Enqueue(new OperationArgs @@ -138,6 +166,11 @@ namespace osu.Game.Database detachedBeatmapSets.ReplaceRange(op.Index, 1, new[] { op.BeatmapSet! }); break; + case OperationType.MoveAndReplace: + detachedBeatmapSets.Move(op.Index, op.NewIndex!.Value); + detachedBeatmapSets.ReplaceRange(op.NewIndex!.Value, 1, [op.BeatmapSet!]); + break; + case OperationType.Remove: detachedBeatmapSets.RemoveAt(op.Index); break; @@ -160,13 +193,15 @@ namespace osu.Game.Database public OperationType Type; public BeatmapSetInfo? BeatmapSet; public int Index; + public int? NewIndex; } private enum OperationType { Insert, Update, - Remove + Remove, + MoveAndReplace, } } } diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 9ccb8170f3..0d75ddb0f0 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -237,26 +237,29 @@ namespace osu.Game.Screens.Select private void beatmapSetsChanged(object? beatmaps, NotifyCollectionChangedEventArgs changed) { + IEnumerable? oldBeatmapSets = changed.OldItems?.Cast(); + HashSet oldBeatmapSetIDs = oldBeatmapSets?.Select(s => s.ID).ToHashSet() ?? []; + IEnumerable? newBeatmapSets = changed.NewItems?.Cast(); + HashSet newBeatmapSetIDs = newBeatmapSets?.Select(s => s.ID).ToHashSet() ?? []; switch (changed.Action) { case NotifyCollectionChangedAction.Add: - HashSet newBeatmapSetIDs = newBeatmapSets!.Select(s => s.ID).ToHashSet(); - setsRequiringRemoval.RemoveWhere(s => newBeatmapSetIDs.Contains(s.ID)); setsRequiringUpdate.AddRange(newBeatmapSets!); break; case NotifyCollectionChangedAction.Remove: - IEnumerable oldBeatmapSets = changed.OldItems!.Cast(); - HashSet oldBeatmapSetIDs = oldBeatmapSets.Select(s => s.ID).ToHashSet(); - setsRequiringUpdate.RemoveWhere(s => oldBeatmapSetIDs.Contains(s.ID)); - setsRequiringRemoval.AddRange(oldBeatmapSets); + setsRequiringRemoval.AddRange(oldBeatmapSets!); break; case NotifyCollectionChangedAction.Replace: + setsRequiringUpdate.RemoveWhere(s => oldBeatmapSetIDs.Contains(s.ID)); + setsRequiringRemoval.AddRange(oldBeatmapSets!); + + setsRequiringRemoval.RemoveWhere(s => newBeatmapSetIDs.Contains(s.ID)); setsRequiringUpdate.AddRange(newBeatmapSets!); break; From 7b1e3cd537e9c65109010bbf2e87ffa84bc69f8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 8 Oct 2025 15:08:35 +0200 Subject: [PATCH 68/78] Fix carousel sometimes crashing when attempting to select next random set I'm not exactly sure on the reproduction scenario here, but I have had switching ruleset with converts disabled crash on me a few times today. It appears to happen sometimes when after the switch the expanded group no longer exists in the set mapping, because a filter just ran and removed that group from set of possible groups because there'd be no beatmaps under it. I tried to manufacture a quick test but it's not a quick one to test because filtering intereference is required to reproduce, I think. I will try again on request but I mostly just want to get this fix out ASAP before I finish up for the day. --- osu.Game/Screens/SelectV2/BeatmapCarousel.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs index e75ad7e8ed..b959886c7c 100644 --- a/osu.Game/Screens/SelectV2/BeatmapCarousel.cs +++ b/osu.Game/Screens/SelectV2/BeatmapCarousel.cs @@ -1012,13 +1012,13 @@ namespace osu.Game.Screens.SelectV2 private bool nextRandomSet() { - ICollection visibleGroupedSets = ExpandedGroup != null + ICollection visibleGroupedSets = ExpandedGroup != null && grouping.GroupItems.TryGetValue(ExpandedGroup, out var groupItems) // In the case of grouping, users expect random to only operate on the expanded group. // This is going to incur some overhead as we don't have a group-beatmapset mapping currently. // // If this becomes an issue, we could either store a mapping, or run the random algorithm many times // using the `SetItems` method until we get a group HIT. - ? grouping.GroupItems[ExpandedGroup].Select(i => i.Model).OfType().ToArray() + ? groupItems.Select(i => i.Model).OfType().ToArray() // This is the fastest way to retrieve sets for randomisation. : grouping.SetItems.Keys; From 422392233bb7f41732d62daf13e87ad19c8936aa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 8 Oct 2025 23:18:35 +0900 Subject: [PATCH 69/78] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 64bdd985f6..4be825cea9 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -10,7 +10,7 @@ true - + diff --git a/osu.iOS.props b/osu.iOS.props index d945420306..891e9377be 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -17,6 +17,6 @@ -all - + From 79c367d20868ed56d0d83ce391c42068ddd99a78 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 9 Oct 2025 15:28:15 +0900 Subject: [PATCH 70/78] Fix test scene leaks through RealmRulesetStore/RealmAccess --- osu.Game.Tests/Database/RulesetStoreTests.cs | 14 ++++++------- .../TestScenePlayerLocalScoreImport.cs | 8 ++++++++ .../Visual/Multiplayer/QueueModeTestScene.cs | 12 ++++++++++- .../TestSceneDrawableRoomPlaylist.cs | 12 ++++++++++- .../Multiplayer/TestSceneMultiplayer.cs | 11 +++++++++- .../TestSceneMultiplayerMatchSongSelect.cs | 9 +++++++++ .../TestSceneMultiplayerMatchSubScreen.cs | 12 ++++++++++- .../TestSceneMultiplayerPlaylist.cs | 12 ++++++++++- .../TestSceneMultiplayerQueueList.cs | 12 ++++++++++- .../TestSceneMultiplayerSpectateButton.cs | 12 ++++++++++- .../TestScenePlaylistsSongSelect.cs | 12 ++++++++++- .../Visual/Multiplayer/TestSceneTeamVersus.cs | 12 ++++++++++- .../TestSceneAddPlaylistToCollectionButton.cs | 12 ++++++++++- .../TestScenePlaylistsRoomCreation.cs | 12 ++++++++++- .../TestScenePlaylistsRoomSubScreen.cs | 12 ++++++++++- .../Ranking/TestSceneSoloResultsScreen.cs | 9 +++++++++ .../Ranking/TestSceneStatisticsPanel.cs | 20 +++++++++++++++++-- .../SongSelect/TestSceneCollectionDropdown.cs | 12 ++++++++++- .../TestSceneManageCollectionsDialog.cs | 12 ++++++++++- .../SongSelect/TestSceneTopLocalRank.cs | 9 +++++++++ .../SongSelectV2/SongSelectTestScene.cs | 8 ++++++++ .../TestSceneBeatmapLeaderboardSorting.cs | 8 ++++++++ .../TestSceneBeatmapLeaderboardWedge.cs | 8 ++++++++ .../TestSceneCollectionDropdown.cs | 12 ++++++++++- .../TestSceneDeleteLocalScore.cs | 15 ++++++++++++-- .../UserInterface/TestSceneModPresetColumn.cs | 8 ++++++++ .../TestSceneModSelectOverlay.cs | 9 +++++++++ .../UserInterface/TestScenePlaylistOverlay.cs | 12 ++++++++++- osu.Game/Tests/Visual/OsuTestScene.cs | 3 +++ 29 files changed, 292 insertions(+), 27 deletions(-) diff --git a/osu.Game.Tests/Database/RulesetStoreTests.cs b/osu.Game.Tests/Database/RulesetStoreTests.cs index ddf207342a..29aec73770 100644 --- a/osu.Game.Tests/Database/RulesetStoreTests.cs +++ b/osu.Game.Tests/Database/RulesetStoreTests.cs @@ -24,7 +24,7 @@ namespace osu.Game.Tests.Database { RunTestWithRealm((realm, storage) => { - var rulesets = new RealmRulesetStore(realm, storage); + using var rulesets = new RealmRulesetStore(realm, storage); Assert.AreEqual(4, rulesets.AvailableRulesets.Count()); Assert.AreEqual(4, realm.Realm.All().Count()); @@ -36,8 +36,8 @@ namespace osu.Game.Tests.Database { RunTestWithRealm((realm, storage) => { - var rulesets = new RealmRulesetStore(realm, storage); - var rulesets2 = new RealmRulesetStore(realm, storage); + using var rulesets = new RealmRulesetStore(realm, storage); + using var rulesets2 = new RealmRulesetStore(realm, storage); Assert.AreEqual(4, rulesets.AvailableRulesets.Count()); Assert.AreEqual(4, rulesets2.AvailableRulesets.Count()); @@ -52,7 +52,7 @@ namespace osu.Game.Tests.Database { RunTestWithRealm((realm, storage) => { - var rulesets = new RealmRulesetStore(realm, storage); + using var rulesets = new RealmRulesetStore(realm, storage); Assert.IsFalse(rulesets.AvailableRulesets.First().IsManaged); Assert.IsFalse(rulesets.GetRuleset(0)?.IsManaged); @@ -79,7 +79,7 @@ namespace osu.Game.Tests.Database Assert.That(realm.Run(r => r.Find(rulesetShortName)!.Available), Is.True); // Availability is updated on construction of a RealmRulesetStore - _ = new RealmRulesetStore(realm, storage); + using var _ = new RealmRulesetStore(realm, storage); Assert.That(realm.Run(r => r.Find(rulesetShortName)!.Available), Is.False); }); @@ -104,13 +104,13 @@ namespace osu.Game.Tests.Database Assert.That(realm.Run(r => r.Find(rulesetShortName)!.Available), Is.True); // Availability is updated on construction of a RealmRulesetStore - _ = new RealmRulesetStore(realm, storage); + using var _ = new RealmRulesetStore(realm, storage); Assert.That(realm.Run(r => r.Find(rulesetShortName)!.Available), Is.False); // Simulate the ruleset getting updated LoadTestRuleset.Version = Ruleset.CURRENT_RULESET_API_VERSION; - _ = new RealmRulesetStore(realm, storage); + using var __ = new RealmRulesetStore(realm, storage); Assert.That(realm.Run(r => r.Find(rulesetShortName)!.Available), Is.True); }); diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs index 046ae6d953..0e6fd8f519 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePlayerLocalScoreImport.cs @@ -257,6 +257,14 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("score in database", () => Realm.Run(r => r.Find(Player.Score.ScoreInfo.ID) != null)); } + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (rulesets.IsNotNull()) + rulesets.Dispose(); + } + private class CustomRuleset : OsuRuleset, ILegacyRuleset { public override string Description => "custom"; diff --git a/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs b/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs index 0e8093f459..184bb33c2f 100644 --- a/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs +++ b/osu.Game.Tests/Visual/Multiplayer/QueueModeTestScene.cs @@ -6,6 +6,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Extensions; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Platform; using osu.Framework.Screens; using osu.Framework.Testing; @@ -36,6 +37,7 @@ namespace osu.Game.Tests.Visual.Multiplayer private BeatmapManager beatmaps = null!; private BeatmapSetInfo importedSet = null!; + private RulesetStore rulesets = null!; private TestMultiplayerComponents multiplayerComponents = null!; @@ -46,7 +48,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { BeatmapStore beatmapStore; - Dependencies.Cache(new RealmRulesetStore(Realm)); + Dependencies.Cache(rulesets = new RealmRulesetStore(Realm)); Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default)); Dependencies.CacheAs(beatmapStore = new RealmDetachedBeatmapStore()); Dependencies.Cache(Realm); @@ -115,5 +117,13 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("wait for player", () => multiplayerComponents.CurrentScreen is Player player && player.IsLoaded); AddStep("exit player", () => multiplayerComponents.MultiplayerScreen.MakeCurrent()); } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (rulesets.IsNotNull()) + rulesets.Dispose(); + } } } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs index 7e19f45a00..c8216c54be 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneDrawableRoomPlaylist.cs @@ -8,6 +8,7 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; @@ -37,13 +38,14 @@ namespace osu.Game.Tests.Visual.Multiplayer { public partial class TestSceneDrawableRoomPlaylist : MultiplayerTestScene { + private RulesetStore rulesets = null!; private TestPlaylist playlist = null!; private BeatmapManager manager = null!; [BackgroundDependencyLoader] private void load(GameHost host, AudioManager audio) { - Dependencies.Cache(new RealmRulesetStore(Realm)); + Dependencies.Cache(rulesets = new RealmRulesetStore(Realm)); Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default)); Dependencies.Cache(Realm); } @@ -436,6 +438,14 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("wait for items to load", () => playlist.ItemMap.Values.All(i => i.IsLoaded)); } + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (rulesets.IsNotNull()) + rulesets.Dispose(); + } + private partial class TestPlaylist : DrawableRoomPlaylist { public new IReadOnlyDictionary> ItemMap => base.ItemMap; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index 083b5b14fb..4c487c8288 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -51,6 +51,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { public partial class TestSceneMultiplayer : ScreenTestScene { + private RulesetStore rulesets = null!; private BeatmapManager beatmaps = null!; private BeatmapSetInfo importedSet = null!; private BeatmapSetInfo importedSet2 = null!; @@ -67,7 +68,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { BeatmapStore beatmapStore; - Dependencies.Cache(new RealmRulesetStore(Realm)); + Dependencies.Cache(rulesets = new RealmRulesetStore(Realm)); Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, API, audio, Resources, host, Beatmap.Default)); Dependencies.CacheAs(beatmapStore = new RealmDetachedBeatmapStore()); Dependencies.Cache(Realm); @@ -1247,5 +1248,13 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("wait for join", () => multiplayerClient.RoomJoined); } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (rulesets.IsNotNull()) + rulesets.Dispose(); + } } } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs index 9c85bdd57a..e6f3d7e5ac 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSongSelect.cs @@ -8,6 +8,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Extensions.TypeExtensions; using osu.Framework.Platform; using osu.Framework.Screens; @@ -170,6 +171,14 @@ namespace osu.Game.Tests.Visual.Multiplayer .All(b => b.Mod.GetType() != type)); } + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (rulesets.IsNotNull()) + rulesets.Dispose(); + } + private partial class TestMultiplayerMatchSongSelect : MultiplayerMatchSongSelect { public new Bindable> Mods => base.Mods; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs index aa4c4949fb..792bff63d3 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerMatchSubScreen.cs @@ -7,6 +7,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Extensions; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; using osu.Framework.Platform; @@ -44,6 +45,7 @@ namespace osu.Game.Tests.Visual.Multiplayer public partial class TestSceneMultiplayerMatchSubScreen : MultiplayerTestScene { private MultiplayerMatchSubScreen screen = null!; + private RulesetStore rulesets = null!; private BeatmapManager beatmaps = null!; private BeatmapSetInfo importedSet = null!; private Room room = null!; @@ -51,7 +53,7 @@ namespace osu.Game.Tests.Visual.Multiplayer [BackgroundDependencyLoader] private void load(GameHost host, AudioManager audio) { - Dependencies.Cache(new RealmRulesetStore(Realm)); + Dependencies.Cache(rulesets = new RealmRulesetStore(Realm)); Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default)); Dependencies.Cache(Realm); Dependencies.CacheAs(new RealmDetachedBeatmapStore()); @@ -462,6 +464,14 @@ namespace osu.Game.Tests.Visual.Multiplayer AddAssert("settings still open", () => this.ChildrenOfType().Single().State.Value, () => Is.EqualTo(Visibility.Visible)); } + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (rulesets.IsNotNull()) + rulesets.Dispose(); + } + private partial class TestMultiplayerMatchSubScreen : MultiplayerMatchSubScreen { [Resolved(canBeNull: true)] diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs index c6a203c77a..44177c080c 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerPlaylist.cs @@ -7,6 +7,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Extensions; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Platform; using osu.Framework.Testing; @@ -28,6 +29,7 @@ namespace osu.Game.Tests.Visual.Multiplayer public partial class TestSceneMultiplayerPlaylist : MultiplayerTestScene { private MultiplayerPlaylist list = null!; + private RulesetStore rulesets = null!; private BeatmapManager beatmaps = null!; private BeatmapSetInfo importedSet = null!; private BeatmapInfo importedBeatmap = null!; @@ -35,7 +37,7 @@ namespace osu.Game.Tests.Visual.Multiplayer [BackgroundDependencyLoader] private void load(GameHost host, AudioManager audio) { - Dependencies.Cache(new RealmRulesetStore(Realm)); + Dependencies.Cache(rulesets = new RealmRulesetStore(Realm)); Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default)); Dependencies.Cache(Realm); } @@ -290,5 +292,13 @@ namespace osu.Game.Tests.Visual.Multiplayer .Single() .Items.Any(i => i.ID == playlistItemId); } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (rulesets.IsNotNull()) + rulesets.Dispose(); + } } } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerQueueList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerQueueList.cs index d7659351bb..2f54551fa8 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerQueueList.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerQueueList.cs @@ -7,6 +7,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Extensions; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Platform; @@ -26,6 +27,7 @@ namespace osu.Game.Tests.Visual.Multiplayer public partial class TestSceneMultiplayerQueueList : MultiplayerTestScene { private MultiplayerQueueList playlist = null!; + private RulesetStore rulesets = null!; private BeatmapManager beatmaps = null!; private BeatmapSetInfo importedSet = null!; private BeatmapInfo importedBeatmap = null!; @@ -34,7 +36,7 @@ namespace osu.Game.Tests.Visual.Multiplayer [BackgroundDependencyLoader] private void load(GameHost host, AudioManager audio) { - Dependencies.Cache(new RealmRulesetStore(Realm)); + Dependencies.Cache(rulesets = new RealmRulesetStore(Realm)); Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, API, audio, Resources, host, Beatmap.Default)); Dependencies.Cache(Realm); } @@ -168,5 +170,13 @@ namespace osu.Game.Tests.Visual.Multiplayer var button = playlist.ChildrenOfType().ElementAtOrDefault(index); return (button?.Alpha > 0) == visible; }); + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (rulesets.IsNotNull()) + rulesets.Dispose(); + } } } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs index 12bc3c1418..fe9ea632cf 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerSpectateButton.cs @@ -6,6 +6,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Extensions; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; @@ -32,12 +33,13 @@ namespace osu.Game.Tests.Visual.Multiplayer private Room room = null!; private BeatmapSetInfo importedSet = null!; + private RulesetStore rulesets = null!; private BeatmapManager beatmaps = null!; [BackgroundDependencyLoader] private void load(GameHost host, AudioManager audio) { - Dependencies.Cache(new RealmRulesetStore(Realm)); + Dependencies.Cache(rulesets = new RealmRulesetStore(Realm)); Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default)); Dependencies.Cache(Realm); @@ -162,5 +164,13 @@ namespace osu.Game.Tests.Visual.Multiplayer private void assertReadyButtonEnablement(bool shouldBeEnabled) => AddUntilStep($"ready button {(shouldBeEnabled ? "is" : "is not")} enabled", () => startControl.ChildrenOfType().Single().Enabled.Value == shouldBeEnabled); + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (rulesets.IsNotNull()) + rulesets.Dispose(); + } } } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs index 066c981cd2..7135ff930d 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestScenePlaylistsSongSelect.cs @@ -7,6 +7,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Platform; @@ -31,6 +32,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { public partial class TestScenePlaylistsSongSelect : OnlinePlayTestScene { + private RulesetStore rulesets = null!; private BeatmapManager manager = null!; private TestPlaylistsSongSelect songSelect = null!; private Room room = null!; @@ -40,7 +42,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { BeatmapStore beatmapStore; - Dependencies.Cache(new RealmRulesetStore(Realm)); + Dependencies.Cache(rulesets = new RealmRulesetStore(Realm)); Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default)); Dependencies.CacheAs(beatmapStore = new RealmDetachedBeatmapStore()); Dependencies.Cache(Realm); @@ -189,6 +191,14 @@ namespace osu.Game.Tests.Visual.Multiplayer AddAssert("mod select visible", () => this.ChildrenOfType().Single().State.Value, () => Is.EqualTo(Visibility.Visible)); } + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (rulesets.IsNotNull()) + rulesets.Dispose(); + } + private partial class TestPlaylistsSongSelect : PlaylistsSongSelect { public new MatchBeatmapDetailArea BeatmapDetails => (MatchBeatmapDetailArea)base.BeatmapDetails; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs index 05136ebee1..2e08b494bd 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneTeamVersus.cs @@ -7,6 +7,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Extensions; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Platform; using osu.Framework.Testing; using osu.Game.Beatmaps; @@ -27,6 +28,7 @@ namespace osu.Game.Tests.Visual.Multiplayer { public partial class TestSceneTeamVersus : ScreenTestScene { + private RulesetStore rulesets = null!; private BeatmapManager beatmaps = null!; private BeatmapSetInfo importedSet = null!; @@ -37,7 +39,7 @@ namespace osu.Game.Tests.Visual.Multiplayer [BackgroundDependencyLoader] private void load(GameHost host, AudioManager audio) { - Dependencies.Cache(new RealmRulesetStore(Realm)); + Dependencies.Cache(rulesets = new RealmRulesetStore(Realm)); Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, null, audio, Resources, host, Beatmap.Default)); Dependencies.Cache(Realm); } @@ -182,5 +184,13 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("wait for join", () => multiplayerClient.RoomJoined); } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (rulesets.IsNotNull()) + rulesets.Dispose(); + } } } diff --git a/osu.Game.Tests/Visual/Playlists/TestSceneAddPlaylistToCollectionButton.cs b/osu.Game.Tests/Visual/Playlists/TestSceneAddPlaylistToCollectionButton.cs index abfc5c4d0e..7a11581d27 100644 --- a/osu.Game.Tests/Visual/Playlists/TestSceneAddPlaylistToCollectionButton.cs +++ b/osu.Game.Tests/Visual/Playlists/TestSceneAddPlaylistToCollectionButton.cs @@ -7,6 +7,7 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Platform; using osu.Framework.Testing; @@ -25,6 +26,7 @@ namespace osu.Game.Tests.Visual.Playlists { public partial class TestSceneAddPlaylistToCollectionButton : OsuManualInputManagerTestScene { + private RulesetStore rulesets = null!; private BeatmapManager manager = null!; private BeatmapSetInfo importedBeatmap = null!; private Room room = null!; @@ -33,7 +35,7 @@ namespace osu.Game.Tests.Visual.Playlists [BackgroundDependencyLoader] private void load(GameHost host, AudioManager audio) { - Dependencies.Cache(new RealmRulesetStore(Realm)); + Dependencies.Cache(rulesets = new RealmRulesetStore(Realm)); Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, API, audio, Resources, host, Beatmap.Default)); Dependencies.Cache(Realm); @@ -112,5 +114,13 @@ namespace osu.Game.Tests.Visual.Playlists } ]; }); + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (rulesets.IsNotNull()) + rulesets.Dispose(); + } } } diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs index 2e90f08d47..44c2e7eb55 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs @@ -8,6 +8,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Platform; using osu.Framework.Screens; using osu.Framework.Testing; @@ -32,6 +33,7 @@ namespace osu.Game.Tests.Visual.Playlists { public partial class TestScenePlaylistsRoomCreation : OnlinePlayTestScene { + private RulesetStore rulesets = null!; private BeatmapManager manager = null!; private TestPlaylistsRoomSubScreen match = null!; private BeatmapSetInfo importedBeatmap = null!; @@ -40,7 +42,7 @@ namespace osu.Game.Tests.Visual.Playlists [BackgroundDependencyLoader] private void load(GameHost host, AudioManager audio) { - Dependencies.Cache(new RealmRulesetStore(Realm)); + Dependencies.Cache(rulesets = new RealmRulesetStore(Realm)); Dependencies.Cache(manager = new BeatmapManager(LocalStorage, Realm, API, audio, Resources, host, Beatmap.Default)); Dependencies.Cache(Realm); } @@ -220,6 +222,14 @@ namespace osu.Game.Tests.Visual.Playlists }); }); + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (rulesets.IsNotNull()) + rulesets.Dispose(); + } + private partial class TestPlaylistsRoomSubScreen : PlaylistsRoomSubScreen { public new Bindable SelectedItem => base.SelectedItem; diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs index 0eed6c9f5f..87f65111b0 100644 --- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs +++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomSubScreen.cs @@ -11,6 +11,7 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Bindables; using osu.Framework.Extensions; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Platform; @@ -38,6 +39,7 @@ namespace osu.Game.Tests.Visual.Playlists { public partial class TestScenePlaylistsRoomSubScreen : OnlinePlayTestScene { + private RulesetStore rulesets = null!; private BeatmapManager beatmaps = null!; private BeatmapSetInfo importedSet = null!; @@ -46,7 +48,7 @@ namespace osu.Game.Tests.Visual.Playlists { BeatmapStore beatmapStore; - Dependencies.Cache(new RealmRulesetStore(Realm)); + Dependencies.Cache(rulesets = new RealmRulesetStore(Realm)); Dependencies.Cache(beatmaps = new BeatmapManager(LocalStorage, Realm, API, audio, Resources, host, Beatmap.Default)); Dependencies.CacheAs(beatmapStore = new RealmDetachedBeatmapStore()); Dependencies.Cache(Realm); @@ -579,6 +581,14 @@ namespace osu.Game.Tests.Visual.Playlists AddUntilStep("mods set", () => SelectedMods.Value.Count == 1 && SelectedMods.Value.OfType().Any()); } + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (rulesets.IsNotNull()) + rulesets.Dispose(); + } + private partial class TestPlaylistsScreen : OsuScreen { public TestPlaylistsScreen(PlaylistsRoomSubScreen screen) diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneSoloResultsScreen.cs b/osu.Game.Tests/Visual/Ranking/TestSceneSoloResultsScreen.cs index cd8f234f04..e86ed8cd89 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneSoloResultsScreen.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneSoloResultsScreen.cs @@ -7,6 +7,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Extensions; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Platform; using osu.Framework.Testing; @@ -531,5 +532,13 @@ namespace osu.Game.Tests.Visual.Ranking AddAssert("only one score with ID 12345", () => this.ChildrenOfType().Count(s => s.Score.OnlineID == 12345), () => Is.EqualTo(1)); AddUntilStep("user best position preserved", () => this.ChildrenOfType().Any(p => p.ScorePosition.Value == 133_337)); } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (rulesetStore.IsNotNull()) + rulesetStore.Dispose(); + } } } diff --git a/osu.Game.Tests/Visual/Ranking/TestSceneStatisticsPanel.cs b/osu.Game.Tests/Visual/Ranking/TestSceneStatisticsPanel.cs index b682ec7265..88e381a468 100644 --- a/osu.Game.Tests/Visual/Ranking/TestSceneStatisticsPanel.cs +++ b/osu.Game.Tests/Visual/Ranking/TestSceneStatisticsPanel.cs @@ -12,6 +12,7 @@ using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Bindables; using osu.Framework.Extensions; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; @@ -219,8 +220,15 @@ namespace osu.Game.Tests.Visual.Ranking Tags = [ new APITag { Id = 1, Name = "song representation/simple", Description = "Accessible and straightforward map design.", }, - new APITag { Id = 2, Name = "style/clean", Description = "Visually uncluttered and organised patterns, often involving few overlaps and equal visual spacing between objects.", }, - new APITag { Id = 3, Name = "aim/aim control", Description = "Patterns with velocity or direction changes which strongly go against a player's natural movement pattern.", }, + new APITag + { + Id = 2, Name = "style/clean", + Description = "Visually uncluttered and organised patterns, often involving few overlaps and equal visual spacing between objects.", + }, + new APITag + { + Id = 3, Name = "aim/aim control", Description = "Patterns with velocity or direction changes which strongly go against a player's natural movement pattern.", + }, new APITag { Id = 4, Name = "tap/bursts", Description = "Patterns requiring continuous movement and alternating, typically 9 notes or less.", }, ] }), 500); @@ -403,6 +411,14 @@ namespace osu.Game.Tests.Visual.Ranking return hitEvents; } + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (rulesetStore.IsNotNull()) + rulesetStore?.Dispose(); + } + private class TestRuleset : Ruleset { public override IEnumerable GetModsFor(ModType type) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneCollectionDropdown.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneCollectionDropdown.cs index 8fcbcb2fbc..8525e33a33 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneCollectionDropdown.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneCollectionDropdown.cs @@ -7,6 +7,7 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Extensions; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; @@ -28,6 +29,7 @@ namespace osu.Game.Tests.Visual.SongSelect { public partial class TestSceneCollectionDropdown : OsuManualInputManagerTestScene { + private RulesetStore rulesets = null!; private BeatmapManager beatmapManager = null!; private CollectionDropdown dropdown = null!; @@ -37,7 +39,7 @@ namespace osu.Game.Tests.Visual.SongSelect [BackgroundDependencyLoader] private void load(GameHost host) { - Dependencies.Cache(new RealmRulesetStore(Realm)); + Dependencies.Cache(rulesets = new RealmRulesetStore(Realm)); Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, Audio, Resources, host, Beatmap.Default)); Dependencies.Cache(Realm); @@ -269,5 +271,13 @@ namespace osu.Game.Tests.Visual.SongSelect CollectionFilterMenuItem item = dropdown.ChildrenOfType().Single().ItemSource.ElementAt(index); return dropdown.ChildrenOfType().Single(i => i.Item.Text.Value == item.CollectionName); } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (rulesets.IsNotNull()) + rulesets.Dispose(); + } } } diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneManageCollectionsDialog.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneManageCollectionsDialog.cs index 475d8ec461..b690bb2708 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneManageCollectionsDialog.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneManageCollectionsDialog.cs @@ -5,6 +5,7 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Extensions; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; @@ -27,13 +28,14 @@ namespace osu.Game.Tests.Visual.SongSelect protected override Container Content { get; } = new Container { RelativeSizeAxes = Axes.Both }; private DialogOverlay dialogOverlay = null!; + private RulesetStore rulesets = null!; private BeatmapManager beatmapManager = null!; private ManageCollectionsDialog dialog = null!; [BackgroundDependencyLoader] private void load(GameHost host) { - Dependencies.Cache(new RealmRulesetStore(Realm)); + Dependencies.Cache(rulesets = new RealmRulesetStore(Realm)); Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, Audio, Resources, host, Beatmap.Default)); Dependencies.Cache(Realm); @@ -379,5 +381,13 @@ namespace osu.Game.Tests.Visual.SongSelect private void assertCollectionName(int index, string name) => AddUntilStep($"item {index + 1} has correct name", () => dialog.ChildrenOfType().Single().OrderedItems.ElementAtOrDefault(index)?.ChildrenOfType().First().Text == name); + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (rulesets.IsNotNull()) + rulesets.Dispose(); + } } } diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs index 93b9efed6a..cb0845ede8 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneTopLocalRank.cs @@ -6,6 +6,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Extensions; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Platform; using osu.Framework.Testing; @@ -211,5 +212,13 @@ namespace osu.Game.Tests.Visual.SongSelect AddUntilStep("No rank displayed", () => topLocalRank.DisplayedRank, () => Is.Null); } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (rulesets.IsNotNull()) + rulesets.Dispose(); + } } } diff --git a/osu.Game.Tests/Visual/SongSelectV2/SongSelectTestScene.cs b/osu.Game.Tests/Visual/SongSelectV2/SongSelectTestScene.cs index e3b02e5905..ac8591699a 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/SongSelectTestScene.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/SongSelectTestScene.cs @@ -190,5 +190,13 @@ namespace osu.Game.Tests.Visual.SongSelectV2 } protected void WaitForSuspension() => AddUntilStep("wait for not current", () => !SongSelect.AsNonNull().IsCurrentScreen()); + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (Rulesets.IsNotNull()) + Rulesets.Dispose(); + } } } diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardSorting.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardSorting.cs index 6e3fafdd6a..a37700f6be 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardSorting.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardSorting.cs @@ -151,5 +151,13 @@ namespace osu.Game.Tests.Visual.SongSelectV2 }, }); } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (rulesetStore.IsNotNull()) + rulesetStore.Dispose(); + } } } diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardWedge.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardWedge.cs index 8fcb3d7acc..1c3a5e4bab 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardWedge.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneBeatmapLeaderboardWedge.cs @@ -578,5 +578,13 @@ namespace osu.Game.Tests.Visual.SongSelectV2 }, }; } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (rulesetStore.IsNotNull()) + rulesetStore.Dispose(); + } } } diff --git a/osu.Game.Tests/Visual/SongSelectV2/TestSceneCollectionDropdown.cs b/osu.Game.Tests/Visual/SongSelectV2/TestSceneCollectionDropdown.cs index 774d4a00ce..8cee78e0b8 100644 --- a/osu.Game.Tests/Visual/SongSelectV2/TestSceneCollectionDropdown.cs +++ b/osu.Game.Tests/Visual/SongSelectV2/TestSceneCollectionDropdown.cs @@ -7,6 +7,7 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Extensions; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; @@ -29,6 +30,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2 { public partial class TestSceneCollectionDropdown : OsuManualInputManagerTestScene { + private RulesetStore rulesets = null!; private BeatmapManager beatmapManager = null!; private CollectionDropdown dropdown = null!; @@ -38,7 +40,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2 [BackgroundDependencyLoader] private void load(GameHost host) { - Dependencies.Cache(new RealmRulesetStore(Realm)); + Dependencies.Cache(rulesets = new RealmRulesetStore(Realm)); Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, Audio, Resources, host, Beatmap.Default)); Dependencies.Cache(Realm); @@ -260,5 +262,13 @@ namespace osu.Game.Tests.Visual.SongSelectV2 CollectionFilterMenuItem item = dropdown.ChildrenOfType().Single().ItemSource.ElementAt(index); return dropdown.ChildrenOfType().Single(i => i.Item.Text.Value == item.CollectionName); } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (rulesets.IsNotNull()) + rulesets.Dispose(); + } } } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs index f7bdda6b57..c2277f2c7c 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneDeleteLocalScore.cs @@ -9,6 +9,7 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Extensions; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Cursor; using osu.Framework.Platform; @@ -37,6 +38,7 @@ namespace osu.Game.Tests.Visual.UserInterface private readonly ContextMenuContainer contextMenuContainer; private readonly BeatmapLeaderboard leaderboard; + private RulesetStore rulesets = null!; private BeatmapManager beatmapManager; private ScoreManager scoreManager; @@ -71,7 +73,7 @@ namespace osu.Game.Tests.Visual.UserInterface { var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); - dependencies.Cache(new RealmRulesetStore(Realm)); + dependencies.Cache(rulesets = new RealmRulesetStore(Realm)); dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, dependencies.Get(), Resources, dependencies.Get(), Beatmap.Default)); dependencies.Cache(scoreManager = new ScoreManager(dependencies.Get(), () => beatmapManager, LocalStorage, Realm, API)); Dependencies.Cache(Realm); @@ -151,7 +153,8 @@ namespace osu.Game.Tests.Visual.UserInterface AddStep("click delete option", () => { - InputManager.MoveMouseTo(contextMenuContainer.ChildrenOfType().First(i => string.Equals(i.Item.Text.Value.ToString(), "delete", System.StringComparison.OrdinalIgnoreCase))); + InputManager.MoveMouseTo(contextMenuContainer.ChildrenOfType() + .First(i => string.Equals(i.Item.Text.Value.ToString(), "delete", System.StringComparison.OrdinalIgnoreCase))); InputManager.Click(MouseButton.Left); }); @@ -178,5 +181,13 @@ namespace osu.Game.Tests.Visual.UserInterface AddUntilStep("wait for fetch", () => leaderboard.Scores.Any()); AddUntilStep("score removed from leaderboard", () => leaderboard.Scores.All(s => s.OnlineID != importedScores[0].OnlineID)); } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (rulesets.IsNotNull()) + rulesets.Dispose(); + } } } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs index b7c1428397..c202442f9c 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModPresetColumn.cs @@ -469,5 +469,13 @@ namespace osu.Game.Tests.Visual.UserInterface Ruleset = rulesets.GetRuleset(3).AsNonNull() } }; + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (rulesets.IsNotNull()) + rulesets.Dispose(); + } } } diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs index 017d246461..6127be481c 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneModSelectOverlay.cs @@ -7,6 +7,7 @@ using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input; @@ -1057,6 +1058,14 @@ namespace osu.Game.Tests.Visual.UserInterface private ModPanel getPanelForMod(Type modType) => modSelectOverlay.ChildrenOfType().Single(panel => panel.Mod.GetType() == modType); + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (rulesetStore.IsNotNull()) + rulesetStore.Dispose(); + } + private partial class TestModSelectOverlay : UserModSelectOverlay { public TestModSelectOverlay() diff --git a/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs index 2672854e19..b6d9bad5bb 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestScenePlaylistOverlay.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Extensions.ObjectExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Platform; @@ -21,6 +22,7 @@ namespace osu.Game.Tests.Visual.UserInterface { protected override bool UseFreshStoragePerRun => true; + private RulesetStore rulesets = null!; private BeatmapManager beatmapManager = null!; private const int item_count = 20; @@ -30,7 +32,7 @@ namespace osu.Game.Tests.Visual.UserInterface [BackgroundDependencyLoader] private void load(GameHost host) { - Dependencies.Cache(new RealmRulesetStore(Realm)); + Dependencies.Cache(rulesets = new RealmRulesetStore(Realm)); Dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, Realm, null, Audio, Resources, host, Beatmap.Default)); Dependencies.Cache(Realm); } @@ -62,5 +64,13 @@ namespace osu.Game.Tests.Visual.UserInterface // Ensure all the initial imports are present before running any tests. Realm.Run(r => r.Refresh()); }); + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (rulesets.IsNotNull()) + rulesets.Dispose(); + } } } diff --git a/osu.Game/Tests/Visual/OsuTestScene.cs b/osu.Game/Tests/Visual/OsuTestScene.cs index 1cb7b2c840..9b0b66a18c 100644 --- a/osu.Game/Tests/Visual/OsuTestScene.cs +++ b/osu.Game/Tests/Visual/OsuTestScene.cs @@ -332,6 +332,9 @@ namespace osu.Game.Tests.Visual if (MusicController?.TrackLoaded == true) MusicController.Stop(); + if (realm?.IsValueCreated == true) + Realm.Dispose(); + RecycleLocalStorage(true); } From 6af5158bb4c1f86d4284543cf5d38306eec6d67d Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 9 Oct 2025 15:55:48 +0900 Subject: [PATCH 71/78] Fix undisposed Realm subscription --- osu.Game/Overlays/Toolbar/ToolbarButton.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Toolbar/ToolbarButton.cs b/osu.Game/Overlays/Toolbar/ToolbarButton.cs index 221282ef13..5b75b8419c 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarButton.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Linq; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; @@ -77,6 +78,8 @@ namespace osu.Game.Overlays.Toolbar protected readonly Container BackgroundContent; + private IDisposable? realmSubscription; + [Resolved] private RealmAccess realm { get; set; } = null!; @@ -184,7 +187,8 @@ namespace osu.Game.Overlays.Toolbar { if (Hotkey != null) { - realm.SubscribeToPropertyChanged(r => r.All().FirstOrDefault(rkb => rkb.RulesetName == null && rkb.ActionInt == (int)Hotkey.Value), kb => kb.KeyCombinationString, updateKeyBindingTooltip); + realmSubscription = realm.SubscribeToPropertyChanged(r => r.All().FirstOrDefault(rkb => rkb.RulesetName == null && rkb.ActionInt == (int)Hotkey.Value), + kb => kb.KeyCombinationString, updateKeyBindingTooltip); } } @@ -234,6 +238,13 @@ namespace osu.Game.Overlays.Toolbar ? $" ({keyBindingString})" : string.Empty; } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + realmSubscription?.Dispose(); + } } public partial class OpaqueBackground : Container From 6da6edd1d1a55c633cc3815b63bf35c0a14f445f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 9 Oct 2025 08:55:38 +0200 Subject: [PATCH 72/78] Fix shift-clicking not working on extra size beatmap cards Was broken due to double assignment to `Action`. --- osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtra.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtra.cs b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtra.cs index 75fdc7d7e8..222acbc039 100644 --- a/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtra.cs +++ b/osu.Game/Beatmaps/Drawables/Cards/BeatmapCardExtra.cs @@ -280,8 +280,6 @@ namespace osu.Game.Beatmaps.Drawables.Cards } createStatistics(); - - Action = () => beatmapSetOverlay?.FetchAndShowBeatmapSet(BeatmapSet.OnlineID); } private LocalisableString createArtistText() From 6eaf91d31abbbdfe9b2b851a48da4a1de0cbf30f Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Thu, 9 Oct 2025 16:34:55 +0900 Subject: [PATCH 73/78] Fix test failures during individual runs --- osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestScene.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestScene.cs b/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestScene.cs index c687815270..75932bbfef 100644 --- a/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestScene.cs +++ b/osu.Game/Tests/Visual/OnlinePlay/OnlinePlayTestScene.cs @@ -32,9 +32,6 @@ namespace osu.Game.Tests.Visual.OnlinePlay protected override Container Content => content; - [Resolved] - private RulesetStore rulesets { get; set; } = null!; - private readonly Container content; private readonly Container drawableDependenciesContainer; private DelegatedDependencyContainer dependencies = null!; @@ -100,7 +97,11 @@ namespace osu.Game.Tests.Visual.OnlinePlay Room[] rooms = new Room[count]; // Can't reference Osu ruleset project here. - ruleset ??= rulesets.GetRuleset(0)!; + if (ruleset == null) + { + using var assemblyRulesetStore = new AssemblyRulesetStore(); + ruleset = assemblyRulesetStore.GetRuleset(0)!; + } for (int i = 0; i < count; i++) { From e33de9b658d9c62bfae35d9e2556d2fc0577eb4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 9 Oct 2025 09:46:32 +0200 Subject: [PATCH 74/78] Add test demonstrating failure scenario --- .../TestSceneSongSelectNavigation.cs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneSongSelectNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneSongSelectNavigation.cs index d325ce8b36..f161c4cea0 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneSongSelectNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneSongSelectNavigation.cs @@ -10,10 +10,12 @@ using osu.Framework.Extensions.TypeExtensions; using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Configuration; +using osu.Game.Database; using osu.Game.Graphics.UserInterface; using osu.Game.Online.Leaderboards; using osu.Game.Overlays; using osu.Game.Overlays.Mods; +using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Screens; @@ -24,6 +26,7 @@ using osu.Game.Screens.Play; using osu.Game.Screens.Ranking; using osu.Game.Screens.SelectV2; using osu.Game.Tests.Beatmaps.IO; +using osu.Game.Tests.Resources; using osuTK.Input; namespace osu.Game.Tests.Visual.Navigation @@ -271,6 +274,33 @@ namespace osu.Game.Tests.Visual.Navigation AddUntilStep("selected beatmap is still osu! ruleset", () => Game.Beatmap.Value.BeatmapInfo, () => Is.EqualTo(selectedBeatmap)); } + /// + /// Note: This test was written to demonstrate the failure described at https://github.com/ppy/osu/issues/35023, + /// but because the failure scenario there entailed a race condition, it was possible for the test to pass regardless + /// unless was increased. + /// + [Test] + public void TestPresentFromResults() + { + BeatmapSetInfo beatmapToPresent = null!; + BeatmapSetInfo beatmapToPlay = null!; + AddStep("manually insert beatmap to be presented", () => + { + Game.Realm.Write(r => + { + var beatmapSet = TestResources.CreateTestBeatmapSetInfo(3, [r.Find("osu")]); + r.Add(beatmapSet); + beatmapToPresent = beatmapSet.Detach(); + }); + }); + AddStep("import beatmap", () => beatmapToPlay = BeatmapImportHelper.LoadQuickOszIntoOsu(Game).GetResultSafely()); + AddStep("set global beatmap", () => Game.Beatmap.Value = Game.BeatmapManager.GetWorkingBeatmap(beatmapToPlay.Beatmaps.First())); + playToResults(); + AddStep("present beatmap from results", () => Game.PresentBeatmap(beatmapToPresent)); + AddUntilStep("back at song select", () => Game.ScreenStack.CurrentScreen is SoloSongSelect); + AddUntilStep("presented beatmap is current", () => Game.Beatmap.Value.BeatmapSetInfo.Equals(beatmapToPresent)); + } + private Func playToResults() { var player = playToCompletion(); From b477790d3eeb697cd62f99f9da13af746c7f11bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 9 Oct 2025 09:49:48 +0200 Subject: [PATCH 75/78] Fix wrong beatmap shown when presenting a beatmap from results screen - Closes https://github.com/ppy/osu/issues/35023. - Supersedes / closes https://github.com/ppy/osu/pull/35107. --- osu.Game/Screens/SelectV2/SongSelect.cs | 33 ++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/SelectV2/SongSelect.cs b/osu.Game/Screens/SelectV2/SongSelect.cs index d8fa5fa0a1..e8843876d3 100644 --- a/osu.Game/Screens/SelectV2/SongSelect.cs +++ b/osu.Game/Screens/SelectV2/SongSelect.cs @@ -43,6 +43,7 @@ using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays; using osu.Game.Overlays.Mods; using osu.Game.Overlays.Volume; +using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Scoring; using osu.Game.Screens.Footer; @@ -63,7 +64,7 @@ namespace osu.Game.Screens.SelectV2 /// This will be gradually built upon and ultimately replace once everything is in place. ///

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�w^4XP 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

[Cached(typeof(ISongSelect))] - public abstract partial class SongSelect : ScreenWithBeatmapBackground, IKeyBindingHandler, ISongSelect + public abstract partial class SongSelect : ScreenWithBeatmapBackground, IKeyBindingHandler, ISongSelect, IHandlePresentBeatmap { /// /// A debounce that governs how long after a panel is selected before the rest of song select (and the game at large) @@ -1123,6 +1124,36 @@ namespace osu.Game.Screens.SelectV2 #endregion + #region IHandlePresentBeatmap + + void IHandlePresentBeatmap.PresentBeatmap(WorkingBeatmap workingBeatmap, RulesetInfo ruleset) + { + cancelDebounceSelection(); + + var beatmapInfo = workingBeatmap.BeatmapInfo; + + // Don't change the local ruleset if the user is on another ruleset and is showing converted beatmaps. + // Eventually we probably want to check whether conversion is actually possible for the current ruleset. + bool requiresRulesetSwitch = !beatmapInfo.Ruleset.Equals(Ruleset.Value) + && (beatmapInfo.Ruleset.OnlineID > 0 || !showConvertedBeatmaps.Value); + + if (requiresRulesetSwitch) + { + Ruleset.Value = beatmapInfo.Ruleset; + Beatmap.Value = workingBeatmap; + + Logger.Log($"Completing {nameof(IHandlePresentBeatmap.PresentBeatmap)} with beatmap {workingBeatmap} ruleset {beatmapInfo.Ruleset}"); + } + else + { + Beatmap.Value = workingBeatmap; + + Logger.Log($"Completing {nameof(IHandlePresentBeatmap.PresentBeatmap)} with beatmap {workingBeatmap} (maintaining ruleset)"); + } + } + + #endregion + #region Beatmap management [Resolved] From 3fc3a535215e864be213fb6f9fcd59f662bb5fe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 9 Oct 2025 10:17:55 +0200 Subject: [PATCH 76/78] Fix weird xmldoc issue Rider was fine with it... --- .../Visual/Navigation/TestSceneSongSelectNavigation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneSongSelectNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneSongSelectNavigation.cs index f161c4cea0..4295e9e88e 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneSongSelectNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneSongSelectNavigation.cs @@ -277,7 +277,7 @@ namespace osu.Game.Tests.Visual.Navigation /// /// Note: This test was written to demonstrate the failure described at https://github.com/ppy/osu/issues/35023, /// but because the failure scenario there entailed a race condition, it was possible for the test to pass regardless - /// unless was increased. + /// unless was increased. /// [Test] public void TestPresentFromResults() From e3459eccf270e864837eed1c37ccf3e43f2e9e41 Mon Sep 17 00:00:00 2001 From: dnfd1 Date: Thu, 9 Oct 2025 08:36:01 -0700 Subject: [PATCH 77/78] convert origin of rotation to screen space for selections multiple objects in skin editor --- osu.Game/Overlays/SkinEditor/SkinSelectionRotationHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/SkinEditor/SkinSelectionRotationHandler.cs b/osu.Game/Overlays/SkinEditor/SkinSelectionRotationHandler.cs index c8799ad5ba..2438abe5d9 100644 --- a/osu.Game/Overlays/SkinEditor/SkinSelectionRotationHandler.cs +++ b/osu.Game/Overlays/SkinEditor/SkinSelectionRotationHandler.cs @@ -82,7 +82,7 @@ namespace osu.Game.Overlays.SkinEditor foreach (var drawableItem in objectsInRotation) { - var rotatedPosition = GeometryUtils.RotatePointAroundOrigin(originalPositions[drawableItem], actualOrigin, rotation); + var rotatedPosition = GeometryUtils.RotatePointAroundOrigin(originalPositions[drawableItem], ToScreenSpace(actualOrigin), rotation); UpdatePosition(drawableItem, rotatedPosition); drawableItem.Rotation = originalRotations[drawableItem] + rotation; From 94c7489c1ca41a5ce49affc52eccee7ab0539087 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 10 Oct 2025 13:36:28 +0900 Subject: [PATCH 78/78] Add some logging when `FindWithRefresh` triggers a slow realm refresh --- osu.Game/Beatmaps/BeatmapManager.cs | 1 + osu.Game/Database/RealmExtensions.cs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index a3e7c1365e..b828d88591 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -284,6 +284,7 @@ namespace osu.Game.Beatmaps /// /// Returns a list of all usable s. + /// IMPORTANT: This should not be used outside of tests. Consider using instead. /// /// A list of available . public List GetAllUsableBeatmapSets() diff --git a/osu.Game/Database/RealmExtensions.cs b/osu.Game/Database/RealmExtensions.cs index c84e1e35b8..1bb6b0aba4 100644 --- a/osu.Game/Database/RealmExtensions.cs +++ b/osu.Game/Database/RealmExtensions.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using osu.Framework.Logging; using Realms; namespace osu.Game.Database @@ -29,6 +30,7 @@ namespace osu.Game.Database // It may be that we access this from the update thread before a refresh has taken place. // To ensure that behaviour matches what we'd expect (the object generally *should be* available), force // a refresh to bring in any off-thread changes immediately. + Logger.Log($"{nameof(FindWithRefresh)} triggered a realm refresh because it couldn't find the requested guid {id}"); realm.Refresh(); found = realm.Find(id); }