From fa7ba28893746238a4c2bbb15473ef67c9325ccc Mon Sep 17 00:00:00 2001 From: goob10000 <65315624+goob10000@users.noreply.github.com> Date: Wed, 28 Jan 2026 15:18:16 -0800 Subject: [PATCH 01/14] notes on sim todo --- Docs/SimulationTodo.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 Docs/SimulationTodo.md diff --git a/Docs/SimulationTodo.md b/Docs/SimulationTodo.md new file mode 100644 index 0000000..baa9816 --- /dev/null +++ b/Docs/SimulationTodo.md @@ -0,0 +1,27 @@ +# Simulation Todo + +1. Better drag model that takes into account aeropackage (FS-3) +1. Individual wheel models + 1. Suspension + 1. Travel (x) + 1. Velocity (v) + 1. How will this react under acceleration in any direction (steering causes lateral acceleration) (throttle/brakes causes longitudinal acceleration) + 1. Wheel + 1. Brake temp (more complex soon) + 1. Wheel temp (more complex soon) + 1. Wheel rpm/speed +1. Differential + Drivetrain losses + 1. Energy loss due to chain, tripods, axle, hub/upright rubbing + 1. Model rolling resistance better + 1. Model limited slip differential + 1. Log losses so we have an idea of energy loss in the drivetrain +1. Motor Efficiency + Heating + 1. Function of temp and current draw + 1. Keep track of losses + 1. Efficiency loss goes into heat of motor. Need an estimate of its thermal mass and then change in temp. (Motor temp new var) +1. Cleaner logging + 1. Log everything without having to add more rows constantly + 1. Keep efficiency in mind +1. Tractive system heat generation (Not acc) + 1. Estimate how much heat is generated in the accumulator + 1. Not high priority unless we can get more data. From 0b688069916d9a5b3b19421924efe887973925e2 Mon Sep 17 00:00:00 2001 From: goob10000 <65315624+goob10000@users.noreply.github.com> Date: Thu, 29 Jan 2026 18:08:37 -0800 Subject: [PATCH 02/14] more notes --- Data/temp.py | 39 +++--------------------------- Docs/SimulationTodo.md | 55 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 35 deletions(-) diff --git a/Data/temp.py b/Data/temp.py index 587d9e0..9b5c197 100644 --- a/Data/temp.py +++ b/Data/temp.py @@ -3,8 +3,8 @@ import cantools.database as db from Data.DataDecoding_N_CorrectionScripts.dataDecodingFunctions import * -from Data.AnalysisFunctions import * -from Data.integralsAndDerivatives import * +from Data.FSLib.AnalysisFunctions import * +from Data.FSLib.IntegralsAndDerivatives import * from scipy.interpolate import CubicSpline dbcPath = "../fs-3/CANbus.dbc" @@ -70,38 +70,7 @@ etcRTDButton = "ETC_STATUS_RTD_BUTTON" etcBrakeVoltage = "ETC_STATUS_BRAKE_SENSE_VOLTAGE" -df = read("C:/Projects/FormulaSlug/fs-data/FS-3/10112025/firstDriveMCError30.parquet") -df = df.with_columns( - df["timestamp"].alias("Time") -) +df = read("C:/Projects/FormulaSlug/fs-data/FS-3/10082025/fixed_wheels_nathaniel_inv_test_w_fault.parquet") -df = read("C:/Projects/FormulaSlug/fs-data/FS-3/10112025/firstDriveMCError30-filled-null.parquet") -df = df.with_columns( - simpleTimeCol(df) -) - -fig = plt.figure() -ax = fig.add_subplot(111) - -ax.plot(df[t], df[frT], label=frT, c="blue") -ax.plot(df[t], df[flT], label=flT, c="red") -ax.plot(df[t], df[brT], label=brT, c="orange") -ax.plot(df[t], df[blT], label=blT, c="cyan") -ax.set_title("Suspension Travel during First Drive with MC Fault") -ax.set_xlabel("Time") -ax.set_ylabel("Suspension Travel (mm)") -ax.legend() -plt.show() - - -dfNullless = df.drop_nulls(subset=[frT, flT, brT, blT]) - -cs = CubicSpline(dfNullless[t], dfNullless[frT]) - -fig = plt.figure() -ax = fig.add_subplot(111) - -ax.scatter(dfNullless[t], cs(dfNullless[t]), label=frT, s=0.5) -ax.scatter(dfNullless[t], in_place_derive(cs(dfNullless[t])), label=f"Derived {frT}", s=0.5) -ax.legend() +plt.plot(df[busV]) plt.show() diff --git a/Docs/SimulationTodo.md b/Docs/SimulationTodo.md index baa9816..ef03388 100644 --- a/Docs/SimulationTodo.md +++ b/Docs/SimulationTodo.md @@ -25,3 +25,58 @@ 1. Tractive system heat generation (Not acc) 1. Estimate how much heat is generated in the accumulator 1. Not high priority unless we can get more data. +1. Steering model +1. Suspension Model + + +# New simulation architecture idea + + +```python +# Dynamic Vars +posX = 0 +posY = 1 +velX = 2 +velY = 3 +accelX = 4 +accelY = 5 + +arr = np.array((simSteps, 6+1)) +arr[0] = step0 + +def step(): + newPosX = step[posX] + step[velX] * t + +for i in range(simSteps): + arr[i+1] = step(arr[i]) +``` + +```python +# Dictionary Idea #1 +# Array of dictionaries where each time step gets its own dictionary +# Trivial to access a specific thing from any row + +arr = np.array((simSteps)) +arr[0] = step0 + +def step(): + newPosX = arr[posX] + arr[velX] * t + +for i in range(simSteps): + arr[i+1] = step(arr[i]) +``` + +```python +# Dictionary Idea #2 +# Dictionary of arrays. Each key is a column and each array is the length of the simulation +# Trivial to access columns which is typically how we access data + +arr = np.array((simSteps)) +arr[0] = step0 + +def step(): + newPosX = arr[posX] + arr[velX] * t + +for i in range(simSteps): + arr[i+1] = step(arr[i]) +``` \ No newline at end of file From b5aaf4c728f98dadeeecd6cf4ca91cd83bac18c5 Mon Sep 17 00:00:00 2001 From: goob10000 <65315624+goob10000@users.noreply.github.com> Date: Tue, 3 Feb 2026 17:22:54 -0800 Subject: [PATCH 03/14] trailing commas and removed unused import --- FullVehicleSim/params.json5 | 4 ++-- FullVehicleSim/state.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/FullVehicleSim/params.json5 b/FullVehicleSim/params.json5 index 32daac1..8f7cee4 100644 --- a/FullVehicleSim/params.json5 +++ b/FullVehicleSim/params.json5 @@ -46,7 +46,7 @@ "brakeSurfaceArea": 0.001180643, "brakepadThickness": 0.007874, "brakeMass": 0.408, - "maxBrakeForce": 1500 + "maxBrakeForce": 1500, }, "Magic": { "shape-factor": 0.696268618106842, @@ -149,6 +149,6 @@ "pressureYA": -3.086921788053587e-05, "pressureYB": -9.812999633140862e-05, "pressureYC": 0.9998338222503662, - "gysign": -0.10000000149011612 + "gysign": -0.10000000149011612, } } diff --git a/FullVehicleSim/state.py b/FullVehicleSim/state.py index 7976733..8bc12c4 100644 --- a/FullVehicleSim/state.py +++ b/FullVehicleSim/state.py @@ -1,5 +1,5 @@ import numpy as np -from paramLoader import Parameters, Magic +from paramLoader import Parameters from dataclasses import dataclass @dataclass From 66b9a820ccfb68c91c76619ffa215cca88299b2a Mon Sep 17 00:00:00 2001 From: goob10000 <65315624+goob10000@users.noreply.github.com> Date: Wed, 4 Feb 2026 11:39:48 -0800 Subject: [PATCH 04/14] making some progress --- FullVehicleSim/Mech/braking.py | 27 +++++++++--------- FullVehicleSim/Mech/general.py | 10 +++---- FullVehicleSim/engine.py | 51 ++++------------------------------ FullVehicleSim/main.py | 23 ++++++--------- FullVehicleSim/paramLoader.py | 42 ++++++++++++++++++++++++++++ 5 files changed, 75 insertions(+), 78 deletions(-) diff --git a/FullVehicleSim/Mech/braking.py b/FullVehicleSim/Mech/braking.py index 688d8e4..480f13e 100644 --- a/FullVehicleSim/Mech/braking.py +++ b/FullVehicleSim/Mech/braking.py @@ -1,5 +1,5 @@ from Mech import brakepadFrictionModel -from paramLoader import Parameters, Magic +from paramLoader import * import numpy as np from state import VehicleState # Docs: @@ -9,46 +9,47 @@ def brakePSI_toNewtons(psi:float) -> float: return psi * Parameters["brakeCaliperArea"] * 4.448222 # lb force to Newtons -def calcBrakeForce(prevWorld:VehicleState, inputs) -> tuple[float,float]: +def calcBrakeForce(worldArray:np.ndarray, step:int) -> tuple[float,float]: """ Calculate the brake force. FrictionCoeff(temp) * maxBrakeForce * 4 (for 4 wheels) - :param prevWorld: World State Previous + :param worldArray: World State Array + :param step: Current step index :return: Brake Force """ - frontBrakePSI = inputs[1] - rearBrakePSI = inputs[2] + frontBrakePSI = worldArray[step, varBrakePressureFront] + rearBrakePSI = worldArray[step, varBrakePressureRear] frontBrakeForce = brakePSI_toNewtons(frontBrakePSI) rearBrakeForce = brakePSI_toNewtons(rearBrakePSI) # Calculate Brake Force - frontBrakeForce:float = brakepadFrictionModel.calcFrictionCoeff(prevWorld.frontBrakeTemperature) * frontBrakeForce * 2 * Parameters["brakeDiscRadius"] / Parameters["wheelRadius"] - rearBrakeForce:float = brakepadFrictionModel.calcFrictionCoeff(prevWorld.rearBrakeTemperature) * rearBrakeForce * 2 * Parameters["brakeDiscRadius"] / Parameters["wheelRadius"] + frontBrakeForce:float = brakepadFrictionModel.calcFrictionCoeff(worldArray[step-1, varFrontBrakeTemperature]) * frontBrakeForce * 2 * Parameters["brakeDiscRadius"] / Parameters["wheelRadius"] + rearBrakeForce:float = brakepadFrictionModel.calcFrictionCoeff(worldArray[step-1, varRearBrakeTemperature]) * rearBrakeForce * 2 * Parameters["brakeDiscRadius"] / Parameters["wheelRadius"] return frontBrakeForce, rearBrakeForce -def calcBrakeCooling(prevWorld:VehicleState) -> tuple[float,float]: +def calcBrakeCooling(worldArray:np.ndarray, step:int) -> tuple[float,float]: """ Calculate the cooled brake temperature. :param prevWorld: World State :return: Change in Temperature """ - frontBrakeCooling = Parameters["ambientTemperature"] + (prevWorld.frontBrakeTemperature - Parameters["ambientTemperature"]) * np.e ** (-1 / Parameters["stepsPerSecond"]/50.2) - rearBrakeCooling = Parameters["ambientTemperature"] + (prevWorld.rearBrakeTemperature - Parameters["ambientTemperature"]) * np.e ** (-1 / Parameters["stepsPerSecond"]/50.2) + frontBrakeCooling = Parameters["ambientTemperature"] + (worldArray[step-1, varFrontBrakeTemperature] - Parameters["ambientTemperature"]) * np.e ** (-1 / Parameters["stepsPerSecond"]/50.2) + rearBrakeCooling = Parameters["ambientTemperature"] + (worldArray[step-1, varRearBrakeTemperature] - Parameters["ambientTemperature"]) * np.e ** (-1 / Parameters["stepsPerSecond"]/50.2) return frontBrakeCooling, rearBrakeCooling #q = (initTemperature - parameters["ambientTemperature"]) * parameters["brakeMass"] * parameters["brakeSpecificHeatCapacity"] #change = (q * parameters["brakepadThickness"])/(initTemperature * parameters["brakeThermalConductivity"] * parameters["brakeSurfaceArea"] #return initTemperature - change -def calcBrakeHeating(prevWorld:VehicleState, inputs) -> tuple[float,float]: +def calcBrakeHeating(worldArray:np.ndarray, step:int) -> tuple[float,float]: # Calculate Brake Force - frontBrakeForce, rearBrakeForce = calcBrakeForce(prevWorld, inputs) + frontBrakeForce, rearBrakeForce = calcBrakeForce(worldArray, step) # Guess energy increase based on kinetic energy decrease of the vehicle. # Assumption is 100% of kinetic energy lost goes into brake heating. speedChange = (frontBrakeForce + rearBrakeForce) / Parameters["Mass"] / Parameters["stepsPerSecond"] # momentum impulse - energyChange = 0.5 * Parameters["Mass"] * (prevWorld.speed - (prevWorld.speed - speedChange)) + energyChange = 0.5 * Parameters["Mass"] * (worldArray[step-1, varSpeed] - (worldArray[step-1, varSpeed] - speedChange)) tempChange = energyChange/(Parameters["brakeMass"] * Parameters["brakeSpecificHeatCapacity"]) # While this doesn't seem physically intuitive, it is based on the idea that the front and rear brakes share heat based on their contribution to total braking force. diff --git a/FullVehicleSim/Mech/general.py b/FullVehicleSim/Mech/general.py index ea4bb5b..9462ccd 100644 --- a/FullVehicleSim/Mech/general.py +++ b/FullVehicleSim/Mech/general.py @@ -1,5 +1,5 @@ from Mech.traction import calcCorneringStiffness -from paramLoader import Parameters, Magic +from paramLoader import * from state import VehicleState from Mech.braking import calcBrakeForce from Mech.aero import calcDrag @@ -7,12 +7,12 @@ from Mech.tireLoad import calcLoadTransfer import numpy as np -def calcResistiveForces(worldPrev:VehicleState, inputs): - if worldPrev.speed <= 1e-5: # Floating point error +def calcResistiveForces(worldArray:np.ndarray, step:int): + if worldArray[step-1, varSpeed] <= 1e-5: # Floating point error return 0 else: - frontBrakeForce, rearBrakeForce = calcBrakeForce(worldPrev, inputs) - return -1 * (calcDrag(worldPrev) + frontBrakeForce + rearBrakeForce) + frontBrakeForce, rearBrakeForce = calcBrakeForce(worldArray, step) + return -1 * (calcDrag(worldArray, step) + frontBrakeForce + rearBrakeForce) def calculateYawRate(prevWorld:VehicleState, steerAngle:float, initAcceleration:float, heading:np.ndarray, initYawRate:float, timeSinceLastSteer:float): """Calculate the yaw rate of the vehicle at the current state. diff --git a/FullVehicleSim/engine.py b/FullVehicleSim/engine.py index ec1eabe..0747a6d 100644 --- a/FullVehicleSim/engine.py +++ b/FullVehicleSim/engine.py @@ -1,4 +1,4 @@ -from paramLoader import Parameters, Magic +from paramLoader import * import numpy as np from state import VehicleState from Mech.braking import calcBrakeCooling, calcBrakeHeating, calcBrakeForce @@ -27,7 +27,7 @@ def calculateHeading(heading, yaw_rate, time_increment): return np.append(new_heading, 0) -def stepState(worldPrev:VehicleState, inputs): +def stepState(worldArray:np.ndarray, step:int): # Empirically we see that throttle can only go from about 0-.75. # TODO: Update later @@ -37,10 +37,10 @@ def stepState(worldPrev:VehicleState, inputs): delta = 1/Parameters["stepsPerSecond"] maxTraction = 180.0 # Needs a more complex implementation before being used. Potentially something akin to the gaussian kernel of the voltage histeresis model but for acceleration? Or literally based on the suspension travel. - voltage = calcVoltage() # Not yet implemented. Returns 120 for now. - maxPower = calcMaxPower(voltage) # Watts + worldArray[step, varVoltage] = calcVoltage() # Not yet implemented. Returns 120 for now. + worldArray[step, varMaxPower] = calcMaxPower(worldArray[step, varVoltage]) # Watts - resistiveForces = calcResistiveForces(worldPrev, inputs) + worldArray[step, varResistiveForces] = calcResistiveForces(worldArray, step) frontBrakeHeating, rearBrakeHeating = calcBrakeHeating(worldPrev, inputs) frontBrakeCooling, rearBrakeCooling = calcBrakeCooling(worldPrev) frontBrakeTemperature = worldPrev.frontBrakeTemperature + frontBrakeHeating - frontBrakeCooling @@ -70,43 +70,4 @@ def stepState(worldPrev:VehicleState, inputs): frontSlipAngle, rearSlipAngle = calcSlipAngle(worldPrev, inputs) maxWheelTorque = calcMaxWheelTorque(maxMotorTorque) - # cols = ["x", "y", "z", "vX", "vY", "vZ", "speed", - # "headingX", "headingY", "headingZ", - # "yawRate", "frontBrakeTemperature", "rearBrakeTemperature", - # "charge", "drag", "resistiveForces", - # "motorTorque", "motorForce", "netForce", - # "maxTraction", "wheelRotationsHZ", "motorRPM", - # "motorRotationsHZ", "current", - # "maxWheelTorque", "maxPower", "power", - # "voltage", "downForce", - # "frontBrakeForce", "rearBrakeForce", - # "frontBrakeHeating", "rearBrakeHeating", - # "frontBrakeCooling", "rearBrakeCooling", - # "frontSlipAngle", "rearSlipAngle"] - - log:list[float] = [position[0], position[1], position[2], - worldPrev.velocity[0], worldPrev.velocity[1], worldPrev.velocity[2], - worldPrev.speed, - worldPrev.heading[0], worldPrev.heading[1], worldPrev.heading[2], - worldPrev.yawRate, frontBrakeTemperature, rearBrakeTemperature, - charge, drag, resistiveForces, - motorTorque, motorForce, netForce, - maxTraction, worldPrev.wheelRotationsHZ, worldPrev.motorRPM, - worldPrev.motorRotationsHZ, current, - maxWheelTorque, maxPower, power, - voltage, - frontBrakeForce, rearBrakeForce, - frontBrakeHeating, rearBrakeHeating, - frontBrakeCooling, rearBrakeCooling, - frontSlipAngle, rearSlipAngle] - - worldNext = VehicleState( - position=position, - speed=speed, - heading = heading, - charge=charge, - frontBrakeTemperature = frontBrakeTemperature, - rearBrakeTemperature = rearBrakeTemperature, - yawRate = worldPrev.yawRate - ) - return worldNext, log + return None diff --git a/FullVehicleSim/main.py b/FullVehicleSim/main.py index c869c1c..a2cc348 100644 --- a/FullVehicleSim/main.py +++ b/FullVehicleSim/main.py @@ -4,7 +4,7 @@ import argparse import time -from paramLoader import Magic, Parameters +from paramLoader import * from state import * from engine import * @@ -50,10 +50,10 @@ "frontSlipAngle", "rearSlipAngle"] log = np.zeros((totalSteps + 1, len(cols))) - worldArray = np.zeros(totalSteps + 1, dtype=VehicleState) + worldArray = np.zeros((totalSteps + 1, 41), dtype=np.float32) # Set the inital time to 0 if not already 0 - timeSeries = df_controls['time'] - df_controls['time'][0] + timeSeries = df_controls['time'] - df_controls['time'][0] # Normalize to start at 0 # This takes the last time step and copies it out to the end of the simulation duration. # This has the effect of holding the last command constant until the end of the simulation duration. @@ -82,21 +82,14 @@ else: raise Exception("Unsupported interpolation method. Please use 'cubic' or 'linear'.") - worldArray[0] = VehicleState( - position=np.asarray([0,0,0], dtype=np.float32), - speed=0, - heading = np.asarray([1,0,0], dtype=np.float32), - charge=Parameters["vehicleSOC"], - yawRate = 0, - frontBrakeTemperature = Parameters["initialBrakeTemperature"], - rearBrakeTemperature= Parameters["initialBrakeTemperature"] - ) - - timeCol = np.arange(0, Parameters["simulationDuration"] + 1/Parameters["stepsPerSecond"], 1/Parameters["stepsPerSecond"]) + worldArray[0,varCharge] = Parameters["vehicleSOC"] + worldArray[0,varFrontBrakeTemperature] = Parameters["initialBrakeTemperature"] + worldArray[0,varRearBrakeTemperature] = Parameters["initialBrakeTemperature"] + worldArray[:, varTime] = np.arange(0, Parameters["simulationDuration"] + 1/Parameters["stepsPerSecond"], 1/Parameters["stepsPerSecond"]) start = time.time() for i in range(totalSteps): - worldArray[i+1], log[i+1] = stepState(worldArray[i], controlInputs[i]) # Step forward!! + stepState(worldArray, i) # Step forward!! ## This was above the stepState but I moved it down to make it clearer to read. # timeRunning += 1/stepsPerSecond # timeSinceLastSteer += 1/stepsPerSecond diff --git a/FullVehicleSim/paramLoader.py b/FullVehicleSim/paramLoader.py index 8e06320..2fab9c1 100644 --- a/FullVehicleSim/paramLoader.py +++ b/FullVehicleSim/paramLoader.py @@ -6,4 +6,46 @@ Magic = params["Magic"] Parameters = params["Parameters"] del params + +varTime = 0 +varThrottle = 1 +varBrakePressureFront = 2 +varBrakePressureRear = 3 +varSteerAngle = 4 +varPosX = 5 +varPosY = 6 +varPosZ = 7 +varVelX = 8 +varVelY = 9 +varVelZ = 10 +varSpeed = 11 +varHeadingX = 12 +varHeadingY = 13 +varHeadingZ = 14 +varYawRate = 15 +varFrontBrakeTemperature = 16 +varRearBrakeTemperature = 17 +varCharge = 18 +varDrag = 19 +varResistiveForces = 20 +varMotorTorque = 21 +varMotorForce = 22 +varNetForce = 23 +varMaxTraction = 24 +varWheelRotationsHZ = 25 +varMotorRPM = 26 +varMotorRotationsHZ = 27 +varCurrent = 28 +varMaxWheelTorque = 29 +varMaxPower = 30 +varPower = 31 +varVoltage = 32 +varFrontBrakeForce = 33 +varRearBrakeForce = 34 +varFrontBrakeHeating = 35 +varRearBrakeHeating = 36 +varFrontBrakeCooling = 37 +varRearBrakeCooling = 38 +varFrontSlipAngle = 39 +varRearSlipAngle = 40 print("Parameters loaded...") From 6ffbecb61982b7d11f81369b63279f8d4f9f1014 Mon Sep 17 00:00:00 2001 From: goob10000 <65315624+goob10000@users.noreply.github.com> Date: Thu, 5 Feb 2026 12:22:34 -0800 Subject: [PATCH 05/14] ok I think it works again --- FullVehicleSim/Electrical/powertrain.py | 21 ++-- FullVehicleSim/Electrical/tractiveBattery.py | 2 +- FullVehicleSim/Mech/aero.py | 9 +- FullVehicleSim/Mech/braking.py | 1 - FullVehicleSim/Mech/general.py | 13 +-- FullVehicleSim/Mech/steering.py | 18 +-- FullVehicleSim/Mech/tireLoad.py | 2 +- .../controls.json | 0 .../simulationControls.csv | 6 + .../simulationControls.csv | 6 - FullVehicleSim/basicViewer.py | 25 ++-- FullVehicleSim/engine.py | 109 ++++++++++++------ FullVehicleSim/main.py | 93 +++++++-------- FullVehicleSim/paramLoader.py | 54 ++++++++- FullVehicleSim/params.json5 | 3 + FullVehicleSim/state.py | 41 ------- FullVehicleSim/visualizeManual.py | 1 - 17 files changed, 217 insertions(+), 187 deletions(-) rename FullVehicleSim/{SimultionControlInputs => SimulationControlInputs}/controls.json (100%) create mode 100644 FullVehicleSim/SimulationControlInputs/simulationControls.csv delete mode 100644 FullVehicleSim/SimultionControlInputs/simulationControls.csv delete mode 100644 FullVehicleSim/state.py diff --git a/FullVehicleSim/Electrical/powertrain.py b/FullVehicleSim/Electrical/powertrain.py index 53d4bd9..f583df7 100644 --- a/FullVehicleSim/Electrical/powertrain.py +++ b/FullVehicleSim/Electrical/powertrain.py @@ -1,24 +1,23 @@ -from state import VehicleState -from paramLoader import Parameters, Magic +import numpy as np +from paramLoader import * -def calcMaxMotorTorque(worldPrev:VehicleState, resistiveForces:float, maxPower:float, maxTractionTorqueAtWheel:float): +def calcMaxMotorTorque(worldArray:np.ndarray, step:int, resistiveForces:float, maxPower:float, maxTractionTorqueAtWheel:float): ''' Motor Torque at the wheel minimum(rpm limited torque, power limited torque, perfect traction torque) ''' ## RPM Limited Torque (Motor Controller limits it to ~ this in practice. Maybe something more like 7490ish) - if worldPrev.motorRPM > 7490: + if worldArray[step-1, varMotorRPM] > 7490: return -1 * resistiveForces * Parameters["wheelRadius"] - if worldPrev.motorRotationsHZ != 0: ## If rolling, torque may be power limited. - maxPowerTorque = maxPower / worldPrev.motorRotationsHZ * Parameters["gearRatio"] + if worldArray[step-1, varMotorRotationsHZ] != 0: ## If rolling, torque may be power limited. + maxPowerTorque = maxPower / worldArray[step-1, varMotorRotationsHZ] * Parameters["gearRatio"] else: ## Avoid divide by 0 error but it's just the same as the max torque that the motor can deliver (180 Nm) maxPowerTorque = 180.0 # Nm at 0 rpm - perfectTractionTorque = Parameters["maxTorque"] - torque = min(perfectTractionTorque, maxPowerTorque, maxTractionTorqueAtWheel/Parameters["gearRatio"]) + torque = min(Parameters["maxTorque"], maxPowerTorque, maxTractionTorqueAtWheel/Parameters["gearRatio"]) return torque -def calcCurrent(power, voltage): +def calcCurrent(power:float, voltage:float) -> float: if (power / voltage) > Parameters["tractiveIMax"]: return Parameters["tractiveIMax"] return power / voltage @@ -29,10 +28,10 @@ def calcMaxWheelTorque(maxMotorTorque): ''' return maxMotorTorque * Parameters["gearRatio"] -def calcMotorForce(maxWheelTorque): +def calcMotorForce(maxWheelTorque:float) -> float: return (maxWheelTorque / Parameters["wheelRadius"]) -def calcMaxPower(voltage): +def calcMaxPower(voltage:float) -> float: return Parameters["tractiveIMax"] * voltage def calcVoltage(): diff --git a/FullVehicleSim/Electrical/tractiveBattery.py b/FullVehicleSim/Electrical/tractiveBattery.py index 7a10b44..d069f2f 100644 --- a/FullVehicleSim/Electrical/tractiveBattery.py +++ b/FullVehicleSim/Electrical/tractiveBattery.py @@ -1,2 +1,2 @@ -from FullVehicleSim.paramLoader import Parameters, Magic +from FullVehicleSim.paramLoader import * diff --git a/FullVehicleSim/Mech/aero.py b/FullVehicleSim/Mech/aero.py index 8be586d..6b5ecbc 100644 --- a/FullVehicleSim/Mech/aero.py +++ b/FullVehicleSim/Mech/aero.py @@ -1,9 +1,8 @@ import numpy as np -from paramLoader import Parameters, Magic -from state import VehicleState +from paramLoader import * -def calcDrag(prevWorld:VehicleState) -> float: - return 0.5 * Parameters["airDensity"] * Parameters["dragCoeffAreaCombo"] * prevWorld.speed**2 +def calcDrag(worldArray:np.ndarray, step:int) -> float: + return 0.5 * Parameters["airDensity"] * Parameters["dragCoeffAreaCombo"] * worldArray[step-1, varSpeed]**2 -def calcDownForce(prevWorld:VehicleState) -> np.ndarray: +def calcDownForce(worldArray:np.ndarray, step:int) -> np.ndarray: return np.asarray([0,0,0,0], dtype=float) diff --git a/FullVehicleSim/Mech/braking.py b/FullVehicleSim/Mech/braking.py index 480f13e..4a15070 100644 --- a/FullVehicleSim/Mech/braking.py +++ b/FullVehicleSim/Mech/braking.py @@ -1,7 +1,6 @@ from Mech import brakepadFrictionModel from paramLoader import * import numpy as np -from state import VehicleState # Docs: # https://docs.google.com/document/d/1oGsGDnY0DEKWpE3S6481A9yZ0F9qUEwWkSXJwTSz4E4/edit?tab=t.2rmbsj26c7w # The goal of these functions are to calculate the net force on the brakes, applied reverse to heading diff --git a/FullVehicleSim/Mech/general.py b/FullVehicleSim/Mech/general.py index 9462ccd..5bad33b 100644 --- a/FullVehicleSim/Mech/general.py +++ b/FullVehicleSim/Mech/general.py @@ -1,6 +1,5 @@ from Mech.traction import calcCorneringStiffness from paramLoader import * -from state import VehicleState from Mech.braking import calcBrakeForce from Mech.aero import calcDrag from Mech.steering import calcSlipAngle, calcYawRate @@ -14,7 +13,7 @@ def calcResistiveForces(worldArray:np.ndarray, step:int): frontBrakeForce, rearBrakeForce = calcBrakeForce(worldArray, step) return -1 * (calcDrag(worldArray, step) + frontBrakeForce + rearBrakeForce) -def calculateYawRate(prevWorld:VehicleState, steerAngle:float, initAcceleration:float, heading:np.ndarray, initYawRate:float, timeSinceLastSteer:float): +def calculateYawRate(worldArray:np.ndarray, step:int, initAcceleration:float, initYawRate:float, timeSinceLastSteer:float): """Calculate the yaw rate of the vehicle at the current state. This function computes the yaw rate by calculating tire loads, slip angles, cornering stiffness, and then applying the vehicle dynamics equations. @@ -32,9 +31,9 @@ def calculateYawRate(prevWorld:VehicleState, steerAngle:float, initAcceleration: ----- Slip ratio is fixed at 0.15. """ - tireLoad = calcLoadTransfer(initAcceleration * heading[0], initAcceleration * heading[1], initYawRate) - slipAngle = calcSlipAngle(initYawRate, prevWorld.velocity, steerAngle, Parameters) + tireLoad = calcLoadTransfer(initAcceleration * worldArray[step-1, varHeadingX], initAcceleration * worldArray[step-1, varHeadingY], initYawRate) + slipAngle = calcSlipAngle(worldArray, step) slipRatio = 0.15 - corneringStiffness = calcCorneringStiffness(tireLoad, slipAngle, slipRatio, prevWorld.speed, 80, 40, Parameters, Magic) # Works but unused - res = calcYawRate(initYawRate, prevWorld.speed, steerAngle, timeSinceLastSteer, corneringStiffness[0], corneringStiffness[1], Parameters) - return res \ No newline at end of file + corneringStiffness = calcCorneringStiffness(tireLoad, slipAngle, slipRatio, worldArray[step-1, varSpeed], 80, 40, Parameters, Magic) # Works but unused + res = calcYawRate(initYawRate, worldArray[step-1, varSpeed], worldArray[step, varSteerAngle], timeSinceLastSteer, corneringStiffness[0], corneringStiffness[1]) + return res diff --git a/FullVehicleSim/Mech/steering.py b/FullVehicleSim/Mech/steering.py index 44d4486..4c06198 100644 --- a/FullVehicleSim/Mech/steering.py +++ b/FullVehicleSim/Mech/steering.py @@ -1,9 +1,8 @@ # Steering model import numpy as np -from state import VehicleState -from paramLoader import Parameters, Magic +from paramLoader import * -def calcSlipAngle(prevWorld:VehicleState, inputs) -> tuple[float,float]: +def calcSlipAngle(worldArray:np.ndarray, step:int) -> tuple[float,float]: """ Calculate Slip Angle Based on yawRate, Velocity, and Steering Angle. @@ -15,15 +14,16 @@ def calcSlipAngle(prevWorld:VehicleState, inputs) -> tuple[float,float]: :param steerAngle: Description :return: (frontSlipAngle, rearSlipAngle) """ - steerAngle = inputs[3] - speed = np.sqrt(prevWorld.velocity[0] ** 2 + prevWorld.velocity[1] ** 2 + prevWorld.velocity[2]**2) - if prevWorld.yawRate == 0 or speed == 0: # WRONG. RELAXATION LENGTH. PROJECT + steerAngle = worldArray[step, varSteerAngle] + speed = worldArray[step-1, varSpeed] + yawRate = worldArray[step-1, varYawRate] + if yawRate == 0 or speed == 0: # WRONG. RELAXATION LENGTH. PROJECT return (0, 0) else: - bodySlip = np.arctan(prevWorld.velocity[1]/prevWorld.velocity[0]) + bodySlip = np.arctan(worldArray[step-1, varVelY]/worldArray[step-1, varVelX]) - frontSlipAngle = calcVirtualSlipAngle() + bodySlip + (Parameters["wheelBase"]*Parameters["frontWeightDist"]/100 * prevWorld.yawRate)/speed - steerAngle - rearSlipAngle = bodySlip - (Parameters["wheelBase"]*(100-Parameters["frontWeightDist"])/100 * prevWorld.yawRate)/speed + frontSlipAngle = calcVirtualSlipAngle() + bodySlip + (Parameters["wheelBase"]*Parameters["frontWeightDist"]/100 * yawRate)/speed - steerAngle + rearSlipAngle = bodySlip - (Parameters["wheelBase"]*(100-Parameters["frontWeightDist"])/100 * yawRate)/speed return (frontSlipAngle, rearSlipAngle) diff --git a/FullVehicleSim/Mech/tireLoad.py b/FullVehicleSim/Mech/tireLoad.py index 13fbe81..5eeb645 100644 --- a/FullVehicleSim/Mech/tireLoad.py +++ b/FullVehicleSim/Mech/tireLoad.py @@ -1,4 +1,4 @@ -from paramLoader import Parameters +from paramLoader import * def calcLoadTransfer(accelerationX, accelerationY, yawVelocity:float) -> tuple[float, float, float, float]: # TODO: add weight transfer for torsional compliancy diff --git a/FullVehicleSim/SimultionControlInputs/controls.json b/FullVehicleSim/SimulationControlInputs/controls.json similarity index 100% rename from FullVehicleSim/SimultionControlInputs/controls.json rename to FullVehicleSim/SimulationControlInputs/controls.json diff --git a/FullVehicleSim/SimulationControlInputs/simulationControls.csv b/FullVehicleSim/SimulationControlInputs/simulationControls.csv new file mode 100644 index 0000000..c19041a --- /dev/null +++ b/FullVehicleSim/SimulationControlInputs/simulationControls.csv @@ -0,0 +1,6 @@ +time,throttle,brakePressureFront,brakePressureRear,steerAngle +0.0,0.0,0.0,0.0,0.0 +10.0,1.0,0.0,0.0,0.0 +20.0,0.0,0.0,0.0,0.0 +30.0,0.0,300.0,300.0,0.0 +40.0,0.0,0.0,0.0,0.0 \ No newline at end of file diff --git a/FullVehicleSim/SimultionControlInputs/simulationControls.csv b/FullVehicleSim/SimultionControlInputs/simulationControls.csv deleted file mode 100644 index dd8b409..0000000 --- a/FullVehicleSim/SimultionControlInputs/simulationControls.csv +++ /dev/null @@ -1,6 +0,0 @@ -time,throttle,brakesFront,brakesRear,steerAngle -0.0,0.0,0.0,0.0,0.0 -10.0,1.0,0.0,0.0,0.0 -20.0,0.0,0.0,0.0,0.0 -30.0,0.0,500.0,1.0,0.0 -40.0,0.0,0.0,0.0,0.0 \ No newline at end of file diff --git a/FullVehicleSim/basicViewer.py b/FullVehicleSim/basicViewer.py index 07f28e7..1687a8e 100644 --- a/FullVehicleSim/basicViewer.py +++ b/FullVehicleSim/basicViewer.py @@ -2,22 +2,17 @@ import matplotlib.pyplot as plt df = pl.read_parquet("FullVehicleSim/simulation_output.parquet") +t = df["time"] -cols = ["x", "y", "z", "vX", "vY", "vZ", "speed", - "headingX", "headingY", "headingZ", - "yawRate", "frontBrakeTemperature", "rearBrakeTemperature", - "charge", "drag", "resistiveForces", - "motorTorque", "motorForce", "netForce", - "maxTraction", "wheelRotationsHZ", "motorRPM", - "motorRotationsHZ", "current", - "maxWheelTorque", "maxPower", "power", - "voltage", - "frontBrakeForce", "rearBrakeForce", - "frontBrakeHeating", "rearBrakeHeating", - "frontBrakeCooling", "rearBrakeCooling", - "frontSlipAngle", "rearSlipAngle"] -plt.plot(df["time"], df["motorForce"], label="motorForce") -plt.plot(df["time"], df["frontBrakeForce"] + df["rearBrakeForce"], label="Brake Force") +plt.plot(t, df["throttle"]*300, label="throttle") +plt.plot(t, df["brakePressureFront"], label="brakesF") +plt.plot(t, df["netForce"], label="netForce") +plt.plot(t, df["motorForce"], label="motorForce") +plt.plot(t, df["motorTorque"], label="motorTorque") +# plt.plot(t, df["motorRPM"], label="motorRPM") +plt.plot(t, df["speed"], label="speed") plt.legend() plt.show() + +df["speed"].max() \ No newline at end of file diff --git a/FullVehicleSim/engine.py b/FullVehicleSim/engine.py index 0747a6d..45abde5 100644 --- a/FullVehicleSim/engine.py +++ b/FullVehicleSim/engine.py @@ -1,6 +1,5 @@ from paramLoader import * import numpy as np -from state import VehicleState from Mech.braking import calcBrakeCooling, calcBrakeHeating, calcBrakeForce from Mech.aero import calcDrag, calcDownForce from Mech.steering import calcSlipAngle @@ -10,9 +9,10 @@ # Vibe coded but it looks about right so idk. # TODO: Verify that this is correct -def calculateHeading(heading, yaw_rate, time_increment): - initial_heading = heading[:2] - rotation_angle = yaw_rate * time_increment +def calculateHeading(worldArray:np.ndarray, step:int) -> np.ndarray: + time_increment = 1/Parameters["stepsPerSecond"] + initial_heading = worldArray[step-1, varHeadingX:varHeadingZ] # Yes this removes Z, we just want X and Y for this simplification + rotation_angle = worldArray[step-1, varYawRate] * time_increment cos_theta = np.cos(rotation_angle) sin_theta = np.sin(rotation_angle) @@ -27,47 +27,82 @@ def calculateHeading(heading, yaw_rate, time_increment): return np.append(new_heading, 0) -def stepState(worldArray:np.ndarray, step:int): +def stepState(worldArray:np.ndarray, step:int) -> np.ndarray: + """ + The order by which things get updated in this function is incredibly important. + If you calculate velocity before you calculate acceleration, + you would just wind up using the 0 that is present in the array at that index. + Update acceleration before you update velocity. This will also fail somewhat + silently so be cautious. - # Empirically we see that throttle can only go from about 0-.75. - # TODO: Update later - # Made it so you can just comment this out when it's fixed. - # Throttle, brakesFront, brakesRear, steering angle - # 0-1, PSI, PSI, Radians + The worldArray will also fail silently if it doen't contain a row before step. + The 0-1 evaluates to -1 so it just grabs the last row in the array instead of the + previous one. + + :param worldArray: The main world array. To work properly, the worldArray needs to contain a row (step) and a previous row (step-1) with the same format as the output of this function. The function will read from the previous row to calculate the new values for the current step. + :type worldArray: np.ndarray + :param step: The current step in the simulation + :type step: int + :return: The updated state array for the current step + :rtype: ndarray[Any, Any] + """ + + # Empirically we see that throttle can only go from about 0-.75. Currently not accounted for. + arr = np.copy(worldArray[step, :]) # This is the array that is updated and then returned. delta = 1/Parameters["stepsPerSecond"] - maxTraction = 180.0 # Needs a more complex implementation before being used. Potentially something akin to the gaussian kernel of the voltage histeresis model but for acceleration? Or literally based on the suspension travel. - worldArray[step, varVoltage] = calcVoltage() # Not yet implemented. Returns 120 for now. - worldArray[step, varMaxPower] = calcMaxPower(worldArray[step, varVoltage]) # Watts + arr[varMaxTraction] = 180.0 # Needs a more complex implementation before being used. Potentially something akin to the gaussian kernel of the voltage histeresis model but for acceleration? Or literally based on the suspension travel. + arr[varVoltage] = calcVoltage() # Not yet implemented. Returns 120 for now. + arr[varMaxPower] = calcMaxPower(arr[varVoltage]) # Watts - worldArray[step, varResistiveForces] = calcResistiveForces(worldArray, step) - frontBrakeHeating, rearBrakeHeating = calcBrakeHeating(worldPrev, inputs) - frontBrakeCooling, rearBrakeCooling = calcBrakeCooling(worldPrev) - frontBrakeTemperature = worldPrev.frontBrakeTemperature + frontBrakeHeating - frontBrakeCooling - rearBrakeTemperature = worldPrev.rearBrakeTemperature + rearBrakeHeating - rearBrakeCooling + arr[varResistiveForces] = calcResistiveForces(worldArray, step) + arr[varFrontBrakeHeating], arr[varRearBrakeHeating] = calcBrakeHeating(worldArray, step) + arr[varFrontBrakeCooling], arr[varRearBrakeCooling] = calcBrakeCooling(worldArray, step) + arr[varFrontBrakeForce], arr[varRearBrakeForce] = calcBrakeForce(worldArray, step) + arr[varFrontBrakeTemperature] = worldArray[step-1, varFrontBrakeTemperature] + arr[varFrontBrakeHeating] - arr[varFrontBrakeCooling] + arr[varRearBrakeTemperature] = worldArray[step-1, varRearBrakeTemperature] + arr[varRearBrakeHeating] - arr[varRearBrakeCooling] - maxMotorTorque = calcMaxMotorTorque(worldPrev, resistiveForces, maxPower, maxTraction) - motorTorque = min(Parameters["maxTorque"]*inputs[0], maxMotorTorque) # Nm + arr[varMaxMotorTorque] = calcMaxMotorTorque(worldArray, step, arr[varResistiveForces], arr[varMaxPower], arr[varMaxTraction]) + arr[varMotorTorque] = min(Parameters["maxTorque"]*arr[varThrottle], arr[varMaxMotorTorque]) # Nm - power = motorTorque * worldPrev.motorRotationsHZ # Watts - motorForce = calcMotorForce(motorTorque) # Newtons - netForce = motorForce + resistiveForces # Newtons + arr[varPower] = arr[varMotorTorque] * worldArray[step-1, varMotorRotationsHZ] # Watts + arr[varMotorForce] = calcMotorForce(arr[varMotorTorque]) # Newtons + arr[varNetForce] = arr[varMotorForce] + arr[varResistiveForces] # Newtons - acceleration = netForce / Parameters["Mass"] # m/s^2 + arr[varAcceleration] = arr[varNetForce] / Parameters["Mass"] # m/s^2 - current = power/voltage # Amps + arr[varCurrent] = arr[varPower] / arr[varVoltage] # Amps - charge = worldPrev.charge - current * delta / 3600.0 - position = worldPrev.position + worldPrev.velocity * delta - speed = max(0, worldPrev.speed + acceleration * delta) # Sometimes braking falls a tad below 0 so we just correct that because otherwise everything breaks - yawRate = worldPrev.yawRate - if inputs[2] == 0: - yawRate = 0 - heading = calculateHeading(worldPrev.heading, yawRate, delta) + arr[varCharge] = worldArray[step-1, varCharge] - worldArray[step, varCurrent] * delta / 3600.0 + arr[varPosX:varPosZ+1] = worldArray[step-1, varPosX:varPosZ+1] + worldArray[step-1, varVelX:varVelZ+1] * delta + arr[varSpeed] = max(0, worldArray[step-1, varSpeed] + arr[varAcceleration] * delta) # Sometimes braking falls a tad below 0 so we just correct that because otherwise everything breaks + arr[varYawRate] = worldArray[step-1, varYawRate] + if worldArray[step, varSteerAngle] == 0: + arr[varYawRate] = 0 + arr[varVelX:varVelZ+1] = arr[varSpeed] * worldArray[step-1, varHeadingX:varHeadingZ+1] + arr[varHeadingX:varHeadingZ+1] = calculateHeading(worldArray, step) - drag = calcDrag(worldPrev) - frontBrakeForce, rearBrakeForce = calcBrakeForce(worldPrev, inputs) - frontSlipAngle, rearSlipAngle = calcSlipAngle(worldPrev, inputs) - maxWheelTorque = calcMaxWheelTorque(maxMotorTorque) + arr[varDrag] = calcDrag(worldArray, step) + + arr[varFrontSlipAngle], arr[varRearSlipAngle] = calcSlipAngle(worldArray, step) + arr[varMaxWheelTorque] = calcMaxWheelTorque(arr[varMaxMotorTorque]) + arr[varWheelRotationsHZ] = arr[varSpeed] / Parameters["wheelCircumferance"] * 2.0 * np.pi + arr[varMotorRotationsHZ] = arr[varWheelRotationsHZ] / Parameters["gearRatio"] + arr[varWheelRPM] = arr[varWheelRotationsHZ] * 60.0 + arr[varMotorRPM] = arr[varWheelRPM] / Parameters["gearRatio"] + return arr - return None +def dynamicStepState(step:np.ndarray) -> np.ndarray: + """ + Interface for simulation step state that takes a single row with inputs and a previous step. + Separates this into 2 rows with the first row being the previous step and the second row being the current inputs. + Then calls stepState to get the new state for the current step. + + :param step: Step you wish to input (Array of all features) + :type step: np.ndarray + :return: Next step in the simulation given your contorl input and vehicle state. + :rtype: ndarray[Any, Any] + """ + arr = np.array([step, step]) + arr[1, 5:] = np.zeros((step.shape[0]-5)) + return stepState(arr, 1) \ No newline at end of file diff --git a/FullVehicleSim/main.py b/FullVehicleSim/main.py index a2cc348..62d0f5f 100644 --- a/FullVehicleSim/main.py +++ b/FullVehicleSim/main.py @@ -5,7 +5,6 @@ import time from paramLoader import * -from state import * from engine import * if __name__ == "__main__": @@ -29,30 +28,19 @@ raise Exception("Please provide a valid simulation controls file path using --simulation_controls or -c") ## Double check it has the correct columns - if df_controls.columns != ['time', 'throttle', 'brakesFront','brakesRear', 'steerAngle']: - raise Exception("Simulation controls file must contain the following columns: 'time', 'throttle', 'brakesFront', 'brakesRear', 'steerAngle'") + if df_controls.columns != ['time', 'throttle', 'brakePressureFront','brakePressureRear', 'steerAngle']: + raise Exception("Simulation controls file must contain the following columns: 'time', 'throttle', 'brakePressureFront', 'brakePressureRear', 'steerAngle'") totalSteps = int(Parameters["stepsPerSecond"] * Parameters["simulationDuration"]) steps = np.arange(0, Parameters["simulationDuration"], 1/Parameters["stepsPerSecond"]) - cols = ["x", "y", "z", "vX", "vY", "vZ", "speed", - "headingX", "headingY", "headingZ", - "yawRate", "frontBrakeTemperature", "rearBrakeTemperature", - "charge", "drag", "resistiveForces", - "motorTorque", "motorForce", "netForce", - "maxTraction", "wheelRotationsHZ", "motorRPM", - "motorRotationsHZ", "current", - "maxWheelTorque", "maxPower", "power", - "voltage", - "frontBrakeForce", "rearBrakeForce", - "frontBrakeHeating", "rearBrakeHeating", - "frontBrakeCooling", "rearBrakeCooling", - "frontSlipAngle", "rearSlipAngle"] - - log = np.zeros((totalSteps + 1, len(cols))) - worldArray = np.zeros((totalSteps + 1, 41), dtype=np.float32) - # Set the inital time to 0 if not already 0 + ## This is structured so the first row is the initial conditions (inputs don't matter and will just be left to 0), and the + ## rest are generated as the simulation progresses. This means that a simulation array will always be 1 longer than just the time steps + ## and duration would indicate. + worldArray = np.zeros((totalSteps + 1, len(VARIABLE_NAMES)), dtype=np.float32) + + # Set the inital time to 0 if not already 0. Eg. [1.79, 2.36, 3.13] becomes [0.0, 0.57, 1.34] timeSeries = df_controls['time'] - df_controls['time'][0] # Normalize to start at 0 # This takes the last time step and copies it out to the end of the simulation duration. @@ -61,8 +49,8 @@ df_controls = df_controls.vstack(pl.DataFrame({ 'time': [Parameters["simulationDuration"]], 'throttle': df_controls["throttle"][-1], - 'brakesFront': df_controls["brakesFront"][-1], - 'brakesRear': df_controls["brakesRear"][-1], + 'brakePressureFront': df_controls["brakePressureFront"][-1], + 'brakePressureRear': df_controls["brakePressureRear"][-1], 'steerAngle': df_controls["steerAngle"][-1]})) timeSeries = df_controls['time'] @@ -76,20 +64,29 @@ elif Parameters["interpolationMethod"] == "linear": controlInputs = np.zeros((len(steps), 4)) controlInputs[:,0] = np.interp(steps, timeSeries, df_controls['throttle']) - controlInputs[:,1] = np.interp(steps, timeSeries, df_controls['brakesFront']) - controlInputs[:,2] = np.interp(steps, timeSeries, df_controls['brakesRear']) + controlInputs[:,1] = np.interp(steps, timeSeries, df_controls['brakePressureFront']) + controlInputs[:,2] = np.interp(steps, timeSeries, df_controls['brakePressureRear']) controlInputs[:,3] = np.interp(steps, timeSeries, df_controls['steerAngle']) else: raise Exception("Unsupported interpolation method. Please use 'cubic' or 'linear'.") + ## Setup initial conditions. Leaves row 0 with no inputs (don't matter anyway since sim runs from 1 -> end) + ## Some other initial conditions based on input parameters. + worldArray[1:, varThrottle] = controlInputs[:,0] + worldArray[1:, varBrakePressureFront] = controlInputs[:,1] + worldArray[1:, varBrakePressureRear] = controlInputs[:,2] + worldArray[1:, varSteerAngle] = controlInputs[:,3] worldArray[0,varCharge] = Parameters["vehicleSOC"] worldArray[0,varFrontBrakeTemperature] = Parameters["initialBrakeTemperature"] worldArray[0,varRearBrakeTemperature] = Parameters["initialBrakeTemperature"] + worldArray[0, varHeadingX:varHeadingZ+1] = Parameters["initHeading"] + worldArray[0, varPosX:varPosZ+1] = Parameters["initPosition"] + worldArray[0, varVelX:varVelZ+1] = Parameters["initVelocity"] worldArray[:, varTime] = np.arange(0, Parameters["simulationDuration"] + 1/Parameters["stepsPerSecond"], 1/Parameters["stepsPerSecond"]) start = time.time() - for i in range(totalSteps): - stepState(worldArray, i) # Step forward!! + for i in range(1, totalSteps): + worldArray[i, :] = stepState(worldArray, i) # Step forward!! ## This was above the stepState but I moved it down to make it clearer to read. # timeRunning += 1/stepsPerSecond # timeSinceLastSteer += 1/stepsPerSecond @@ -109,18 +106,12 @@ # 'cooledBrakeTemperature', 'wheelRPM', 'wheelRotationsHZ', # 'rpm', 'motorRotationsHZ', 'charge', 'voltage', 'current', # 'power', 'maxPower', 'stepSize', 'timeSinceLastSteer'] + # print(VARIABLE_NAMES) - df = pl.DataFrame(log, schema=cols, orient="row") + df = pl.DataFrame(worldArray, schema=VARIABLE_NAMES, orient="row") # print(f"df shape: {df.shape}") # print(f"control inputs shape: {controlInputs.shape}") # print(f"timeCol shape: {timeCol.shape}") - df = df[1:].with_columns( - pl.Series(timeCol[1:]).alias("time"), - pl.Series(controlInputs[:,0]).alias("throttle"), - pl.Series(controlInputs[:,1]).alias("brakesFront"), - pl.Series(controlInputs[:,2]).alias("brakesRear"), - pl.Series(controlInputs[:,3]).alias("steerAngle") - ) df.write_parquet("simulation_output.parquet") @@ -131,30 +122,32 @@ torque = df['motorTorque'] yawRate = df['yawRate'] frontBrakeTemperature = df['frontBrakeTemperature'] - ax1 = plt.subplot(1,4,1) - ax2 = plt.subplot(1,4,2) - ax3 = plt.subplot(1,4,3) - ax4 = plt.subplot(1,4,4) - - ax1.set_title("Current vs Time") + ax1 = plt.subplot(411) + ax11 = ax1.twinx() + ax2 = plt.subplot(412) + ax22 = ax2.twinx() + ax3 = plt.subplot(413) + ax33 = ax3.twinx() + ax4 = plt.subplot(414) + ax44 = ax4.twinx() + + ax1.set_title("I (Blue)/V (Orange) vs Time") ax1.set_xlabel("Time (s)") - ax1.set_ylabel("Current (A)") - ax1.plot(t, current) + ax1.set_ylabel("Current (A) / Voltage (V)") + ax1.plot(t, current, label="Current") + ax11.plot(t, voltage, label="Voltage", color='orange') ax2.set_title("Speed vs Time") ax2.set_xlabel("Time (s)") ax2.set_ylabel("Speed (m/s)") ax2.plot(t, speed) - ax3.set_title("Voltage vs Time") - ax3.set_xlabel("Time (s)") - ax3.set_ylabel("Voltage (V)") - ax3.plot(t, voltage) - - ax3.set_title("Voltage vs Time") + ax3.set_title("Throttle (Blue)/Brakes (Orange) vs Time") ax3.set_xlabel("Time (s)") - ax3.set_ylabel("Voltage (V)") - ax3.plot(t, voltage) + ax3.set_ylabel("Throttle (0-1)") + ax33.set_ylabel("Brake Pressure (PSI)") + ax3.plot(t, df["throttle"], label="Throttle") + ax33.plot(t, df["brakePressureFront"], color='orange') ax4.set_title("rvt") ax4.plot(t, yawRate) diff --git a/FullVehicleSim/paramLoader.py b/FullVehicleSim/paramLoader.py index 2fab9c1..5249d9d 100644 --- a/FullVehicleSim/paramLoader.py +++ b/FullVehicleSim/paramLoader.py @@ -1,12 +1,16 @@ import json5 -Magic:dict -Parameters:dict +from typing import Dict, List, Tuple + +Magic: dict +Parameters: dict with open('params.json5', 'r') as file: params = json5.load(file) Magic = params["Magic"] Parameters = params["Parameters"] del params +# Variable definitions - maintain original order for compatibility + varTime = 0 varThrottle = 1 varBrakePressureFront = 2 @@ -48,4 +52,50 @@ varRearBrakeCooling = 38 varFrontSlipAngle = 39 varRearSlipAngle = 40 +varMaxMotorTorque = 41 +varAcceleration = 42 +varWheelRPM = 43 + +# Automatically generate schema from defined variables +def generate_variable_schema() -> Dict[int, str]: + """ + Generate a schema mapping variable indices to their names. + Preserves the order of definition in the file. + """ + schema = {} + + # Get all variables that start with 'var' from the current module + current_module = globals() + var_items = [(name, value) for name, value in current_module.items() + if name.startswith('var') and isinstance(value, int)] + + # Sort by value to maintain order + var_items.sort(key=lambda x: x[1]) + + # Create the schema + for name, index in var_items: + # Convert variable name to readable format + readable_name = name[3].lower() + name[4:] # Remove 'var' prefix and lowercase first letter + schema[index] = readable_name + + return schema + +def get_variable_names() -> List[str]: + """ + Get ordered list of variable names (without 'var' prefix). + """ + schema = generate_variable_schema() + return [schema[i] for i in range(len(schema))] + +def get_variable_mapping() -> Dict[str, int]: + """ + Get mapping from variable names to indices. + """ + schema = generate_variable_schema() + return {name: index for index, name in schema.items()} + +# Generate the schema on module load +VARIABLE_SCHEMA = generate_variable_schema() +VARIABLE_NAMES = get_variable_names() +VARIABLE_MAPPING = get_variable_mapping() print("Parameters loaded...") diff --git a/FullVehicleSim/params.json5 b/FullVehicleSim/params.json5 index 8f7cee4..99123d2 100644 --- a/FullVehicleSim/params.json5 +++ b/FullVehicleSim/params.json5 @@ -11,6 +11,9 @@ "initialBatteryTemperature": 20, // °C "vehicleSOC": 1.0, // Out of 1 "initSpeed": 0.0, // m/s + "initHeading": [1.0, 0.0, 0.0], // Vector pointing in the direction of the front of the car + "initPosition": [0.0, 0.0, 0.0], // Starting position of the car in the world frame + "initVelocity": [0.0, 0.0, 0.0], // Initial velocity vector in the world frame "airDensity": 1.230, "dragCoeffAreaCombo": 1.0858790012112278, // Combines area and drag coeff into one constant diff --git a/FullVehicleSim/state.py b/FullVehicleSim/state.py deleted file mode 100644 index 8bc12c4..0000000 --- a/FullVehicleSim/state.py +++ /dev/null @@ -1,41 +0,0 @@ -import numpy as np -from paramLoader import Parameters -from dataclasses import dataclass - -@dataclass -class VehicleState: - def __init__(self, position, speed, heading, charge, yawRate, frontBrakeTemperature, rearBrakeTemperature): - self.position:np.ndarray = position - self.speed:float = speed - self.heading:np.ndarray = heading - self.charge:float = charge - self.frontBrakeTemperature:float = frontBrakeTemperature - self.rearBrakeTemperature:float = rearBrakeTemperature - self.yawRate:float = yawRate - - #self.wheelRPM: np.array = np.asarray([0,0,0,0], dtype=np.float32) - #self.wheelRotationsHz: float = self.speed / self.WheelCircumference * 2.0 * np.pi - self.tires:np.ndarray = np.asarray([None, None, None, None])#, dtype=tire.Tire) # [FL, FR, BL, BR] - - @property - def velocity(self): - return self.heading * self.speed - - @property - def wheelRPM(self): - return self.speed / Parameters["wheelCircumferance"] * 60.0 - - @property - def wheelRotationsHZ(self): - return self.speed / Parameters["wheelCircumferance"] * 2.0 * np.pi - @property - def motorRPM(self): - return self.wheelRPM * Parameters["gearRatio"] - - @property - def motorRotationsHZ(self): - return self.wheelRotationsHZ * Parameters["gearRatio"] - - @property - def maxTractionTorqueAtWheel(self): - return Parameters["maxTractionTorque"] * Parameters["wheelRadius"] diff --git a/FullVehicleSim/visualizeManual.py b/FullVehicleSim/visualizeManual.py index 107e30e..5318590 100644 --- a/FullVehicleSim/visualizeManual.py +++ b/FullVehicleSim/visualizeManual.py @@ -3,7 +3,6 @@ import numpy as np import asyncio import platform -from state import VehicleState from engine import stepState #Simulated control inputs (since no file I/O in Pyodide) From e8b7c8bb1a16583de130d8468ac1f14155a2645c Mon Sep 17 00:00:00 2001 From: goob10000 <65315624+goob10000@users.noreply.github.com> Date: Thu, 19 Feb 2026 17:30:57 -0800 Subject: [PATCH 06/14] generated data for gaddiel --- Data/emeterDecode.py | 37 +++++++++++++++++++++-- endur1Curr.csv | 72 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 endur1Curr.csv diff --git a/Data/emeterDecode.py b/Data/emeterDecode.py index 9f93c99..3743894 100644 --- a/Data/emeterDecode.py +++ b/Data/emeterDecode.py @@ -1,5 +1,6 @@ from nptdms import TdmsFile import polars as pl +import numpy as np import matplotlib.pyplot as plt from Data.FSLib.IntegralsAndDerivatives import * from Data.FSLib.AnalysisFunctions import * @@ -9,10 +10,10 @@ autoxDaniel12File = "FS-3/compEmeterData/autoxDaniel12.tdms" accel1 = "FS-3/compEmeterData/216_univ-of-calif---santa-cruz-_250620-203307_ ACCEL-EV.tdms" accel2 = "FS-3/compEmeterData/216_univ-of-calif---santa-cruz-_250620-205609_ ACCEL-EV.tdms" -endur1 = "FS-3/compEmeterData/216_univ-of-calif---santa-cruz-_250621-154731_ ENDUR-EV.tdms" -endur2 = "FS-3/compEmeterData/216_univ-of-calif---santa-cruz-_250621-160530_ ENDUR-EV.tdms" +endur1 = "../fs-data/FS-3/compEmeterData/216_univ-of-calif---santa-cruz-_250621-154731_ ENDUR-EV.tdms" +endur2 = "../fs-data/FS-3/compEmeterData/216_univ-of-calif---santa-cruz-_250621-160530_ ENDUR-EV.tdms" -dfLaptimes = pl.read_csv("FS-3/compLapTimes.csv") +dfLaptimes = pl.read_csv("../fs-data/FS-3/compLapTimes.csv") firstHalf = dfLaptimes.filter(pl.col("Lap") < 12)["Time"].sum() secondHalf = dfLaptimes.filter(pl.col("Lap") > 11)["Time"].sum() @@ -93,7 +94,37 @@ def fileTodf(path): pl.Series(arr).cast(pl.Int64).alias("Lap") ) +l = [] +for i in np.unique(dfendur1["Lap"]): + # plt.plot(dfendur1.filter(pl.col("Lap") == i)[I]) + l.append(dfendur1.filter(pl.col("Lap") == i)[I]) +plt.show() + +shortest = min([len(x) for x in l]) +l2 = [x[:shortest].alias(f"Current_Lap_{i}") for i, x in enumerate(l)] +df2 = pl.DataFrame(l2) +plt.plot(df2.mean_horizontal()) +plt.show() + +from scipy.fft import fft, ifft + +f = fft(df2.mean_horizontal().to_numpy()) +# freq = np.fft.fftfreq(len(df2.mean_horizontal()), d=0.01) + +plt.plot(np.append(np.log(f[-len(f)//2:]), np.log(f[:len(f)//2]))) +plt.show() + +fFiltered = np.where(np.log(f) > 10, f, 0) +invF = ifft(fFiltered) +plt.plot(invF) +plt.plot(df2.mean_horizontal()) +plt.show() + +dfTableCurrOut = pl.DataFrame({"Current": df2.mean_horizontal().gather_every(100), "Time": np.arange(0, df2.height/100)}) +dfTableCurrOut.write_csv("endur1Curr.csv") + +df2.mean_horizontal() dfendur2 = fileTodf(endur2).filter(pl.col(t) > endur2_StartTime).filter(pl.col(t) < endur2_EndTime) diff --git a/endur1Curr.csv b/endur1Curr.csv new file mode 100644 index 0000000..322bda2 --- /dev/null +++ b/endur1Curr.csv @@ -0,0 +1,72 @@ +Current,Time +24.611364,0.0 +32.075455,1.0 +83.82,2.0 +103.79028,3.0 +1.6792728,4.0 +47.380276,5.0 +156.73936,6.0 +181.45502,7.0 +178.01755,8.0 +266.4711,9.0 +314.56467,10.0 +337.80002,11.0 +123.42737,12.0 +18.743092,13.0 +41.31073,14.0 +23.57373,15.0 +71.3661,16.0 +147.76573,17.0 +38.92582,18.0 +21.131275,19.0 +15.494909,20.0 +40.06673,21.0 +118.78701,22.0 +115.37664,23.0 +147.45909,24.0 +223.76947,25.0 +148.38336,26.0 +78.637184,27.0 +23.648548,28.0 +43.008003,29.0 +58.465275,30.0 +91.7551,31.0 +77.75927,32.0 +24.253273,33.0 +37.92873,34.0 +42.02046,35.0 +48.948368,36.0 +88.985916,37.0 +89.52327,38.0 +99.00618,39.0 +67.61691,40.0 +23.409546,41.0 +59.80364,42.0 +79.542,43.0 +83.21628,44.0 +128.63428,45.0 +151.5899,46.0 +113.44146,47.0 +91.6961,48.0 +24.420546,49.0 +25.824457,50.0 +60.09946,51.0 +69.13337,52.0 +98.356,53.0 +57.09346,54.0 +55.792725,55.0 +43.36391,56.0 +39.913273,57.0 +53.080276,58.0 +73.36591,59.0 +83.82373,60.0 +54.693638,61.0 +52.09064,62.0 +48.891186,63.0 +48.31355,64.0 +57.849186,65.0 +29.795094,66.0 +37.14237,67.0 +22.748,68.0 +34.09791,69.0 +30.930456,70.0 From deabc240f336afbf465aed2ccc214407f35aec80 Mon Sep 17 00:00:00 2001 From: Brian Lee Date: Tue, 31 Mar 2026 12:14:34 -0700 Subject: [PATCH 07/14] Add double bicycle yaw rate model --- .../yaw_rate_model/double_bicycle_model.py | 419 ++++++++++++++++++ 1 file changed, 419 insertions(+) create mode 100644 FullVehicleSim/yaw_rate_model/double_bicycle_model.py diff --git a/FullVehicleSim/yaw_rate_model/double_bicycle_model.py b/FullVehicleSim/yaw_rate_model/double_bicycle_model.py new file mode 100644 index 0000000..b0a78f2 --- /dev/null +++ b/FullVehicleSim/yaw_rate_model/double_bicycle_model.py @@ -0,0 +1,419 @@ +""" +Double Bicycle Yaw Rate Model for Formula Slug + +2DOF model (lateral velocity + yaw rate) for basic vehicle dynamics. +Based on Rajamani's bicycle model. +""" + +import numpy as np +from dataclasses import dataclass +from typing import Tuple, List +import matplotlib.pyplot as plt + + +@dataclass +class VehicleParameters: + """Vehicle parameters from 2025 FSAE Design Spec Sheet (Car #216)""" + + # Geometry (meters) - from 2025 FSAE Design EV Spec Sheet + wheelbase: float = 1.589989 # 1589.989 mm + Lf: float = 0.8535 # Calculated from 46.32% front weight distribution + Lr: float = 0.7365 # Calculated from weight distribution + track_width_front: float = 1.234008 # 1234.008 mm + track_width_rear: float = 1.186 # 1186 mm + track_width: float = 1.234008 # Using front track for compatibility + + # Mass properties (with driver) + mass: float = 300.0 # Vehicle + driver (from Formula Slug FS-4 specs) + mass_without_driver: float = 232.0 + cg_height: float = 0.3048 # 304.8 mm + yaw_inertia: float = 658.09 # Not in spec sheet, using previous value + + # Tire model (stiffness values not in spec sheet, using estimates) + # Tires: Front - Hoosier 16.0x6.0-10 LC0, Rear - Hoosier 16.0x7.5-10 LC0 + C_alpha: float = 180000.0 # Cornering stiffness estimate + C_alpha_front: float = 180000.0 + C_alpha_rear: float = 180000.0 + mu: float = 1.733 + longitudinal_inertia: float = 0.0 + + # Additional spec sheet info (for reference) + # Wheel rates: Front 30.647 N/mm, Rear 35.025 N/mm + # Roll rates: Front 407.25 Nm/deg, Rear 429.93 Nm/deg + # Natural frequency: Front 3.55 Hz, Rear 3.53 Hz + + def __post_init__(self): + tolerance = 0.0001 + wheelbase_check = self.Lf + self.Lr + assert abs(wheelbase_check - self.wheelbase) < tolerance, \ + f"Wheelbase math is wrong: {self.Lf} + {self.Lr} = {wheelbase_check} != {self.wheelbase}" + assert self.mass > 0, "Mass has to be positive" + assert self.yaw_inertia > 0, "Yaw inertia has to be positive" + assert self.C_alpha > 0, "Tire stiffness has to be positive" + + +@dataclass +class TireModel: + stiffness: float + max_slip_angle: float = 0.3 + saturation_method: str = "linear" + friction_coeff: float = 1.733 # Peak friction coefficient + + def lateral_force(self, slip_angle: float, vertical_load: float) -> float: + if self.saturation_method == "linear": + return self.stiffness * slip_angle + + elif self.saturation_method == "nonlinear": + # tanh saturation at high slip angles + # Saturates at F_max = mu * Fz (friction limit) + F_linear = self.stiffness * slip_angle + F_max = self.friction_coeff * vertical_load + return F_max * np.tanh(F_linear / F_max) + + return 0.0 + + +class DoubleBicycleModel: + """2DOF bicycle model: v_y (lateral velocity) and r (yaw rate)""" + + def __init__(self, params: VehicleParameters, tire_model: str = "linear"): + self.params = params + self.tire_front = TireModel(params.C_alpha_front, saturation_method=tire_model, friction_coeff=params.mu) + self.tire_rear = TireModel(params.C_alpha_rear, saturation_method=tire_model, friction_coeff=params.mu) + + self.state = np.array([0.0, 0.0]) + self.time_history = [] + self.state_history = [] + self.input_history = [] + + def get_slip_angles(self, v_y: float, r: float, v_x: float, delta: float) \ + -> Tuple[float, float]: + """Calculate front and rear slip angles""" + if abs(v_x) < 0.1: + return delta, 0.0 + + alpha_f = delta - np.arctan2(v_y + self.params.Lf * r, v_x) + alpha_r = -np.arctan2(v_y - self.params.Lr * r, v_x) + + return alpha_f, alpha_r + + def dynamics(self, state: np.ndarray, v_x: float, delta: float, + ax: float = 0.0) -> np.ndarray: + """Compute state derivatives [dv_y/dt, dr/dt]""" + v_y, r = state + + alpha_f, alpha_r = self.get_slip_angles(v_y, r, v_x, delta) + + # Static weight distribution (no load transfer) + # Front axle load: weight farther back (at distance Lr from front) + # Rear axle load: weight farther forward (at distance Lf from rear) + Fz_f = self.params.mass * 9.81 * self.params.Lr / self.params.wheelbase / 2.0 + Fz_r = self.params.mass * 9.81 * self.params.Lf / self.params.wheelbase / 2.0 + + Fy_f = self.tire_front.lateral_force(alpha_f, Fz_f) + Fy_r = self.tire_rear.lateral_force(alpha_r, Fz_r) + + # Account for both tires per axle + Fy_f_total = 2.0 * Fy_f + Fy_r_total = 2.0 * Fy_r + + # Lateral and yaw accelerations + a_y = (Fy_f_total * np.cos(delta) + Fy_r_total) / self.params.mass + v_x * r + dv_y = a_y + + M_yaw = self.params.Lf * Fy_f_total * np.cos(delta) - self.params.Lr * Fy_r_total + dr = M_yaw / self.params.yaw_inertia + + return np.array([dv_y, dr]) + + def integrate_step(self, v_x: float, delta: float, dt: float, + ax: float = 0.0, method: str = "rk4") -> None: + """Integrate one timestep using euler, rk2, or rk4""" + if method == "euler": + k1 = self.dynamics(self.state, v_x, delta, ax) + self.state = self.state + dt * k1 + + elif method == "rk2": + k1 = self.dynamics(self.state, v_x, delta, ax) + k2 = self.dynamics(self.state + 0.5*dt*k1, v_x, delta, ax) + self.state = self.state + dt * k2 + + elif method == "rk4": + k1 = self.dynamics(self.state, v_x, delta, ax) + k2 = self.dynamics(self.state + 0.5*dt*k1, v_x, delta, ax) + k3 = self.dynamics(self.state + 0.5*dt*k2, v_x, delta, ax) + k4 = self.dynamics(self.state + dt*k3, v_x, delta, ax) + self.state = self.state + (dt/6.0) * (k1 + 2*k2 + 2*k3 + k4) + + else: + raise ValueError(f"Unknown integration method: {method}") + + def simulate(self, v_x: float, steering_inputs: List[float], + dt: float = 0.01, method: str = "rk4") -> Tuple[np.ndarray, np.ndarray]: + """Run simulation with given steering input sequence""" + self.state = np.array([0.0, 0.0]) + self.time_history = [0.0] + self.state_history = [self.state.copy()] + self.input_history = [(0.0, v_x)] + + for i, delta in enumerate(steering_inputs): + t = (i + 1) * dt + self.integrate_step(v_x, delta, dt, ax=0.0, method=method) + + self.time_history.append(t) + self.state_history.append(self.state.copy()) + self.input_history.append((delta, v_x)) + + return np.array(self.time_history), np.array(self.state_history) + + def reset(self): + self.state = np.array([0.0, 0.0]) + self.time_history = [] + self.state_history = [] + self.input_history = [] + + +def validate_against_telemetry(csv_path: str, model: DoubleBicycleModel, + sample_window: int = 1000) -> dict: + """Load telemetry and extract stats for model comparison""" + try: + import pandas as pd + except ImportError: + print("Pandas required. Install with: pip install pandas") + return {} + + try: + df = pd.read_csv(csv_path, low_memory=False) + except Exception as e: + print(f"Failed to load {csv_path}: {e}") + return {} + + results = { + 'samples_loaded': len(df), + 'columns_found': [], + 'validation_data': {} + } + + if 'VDM_Z_AXIS_YAW_RATE' in df.columns: + results['columns_found'].append('yaw_rate') + yaw_telem = df['VDM_Z_AXIS_YAW_RATE'].dropna() + + if len(yaw_telem) > 0: + results['validation_data']['yaw_rate_min'] = yaw_telem.min() + results['validation_data']['yaw_rate_max'] = yaw_telem.max() + results['validation_data']['yaw_rate_mean'] = yaw_telem.mean() + results['validation_data']['yaw_rate_std'] = yaw_telem.std() + + if 'VDM_Y_AXIS_ACCELERATION' in df.columns: + results['columns_found'].append('lateral_accel') + lat_accel = df['VDM_Y_AXIS_ACCELERATION'].dropna() + + if len(lat_accel) > 0: + results['validation_data']['lat_accel_min'] = lat_accel.min() + results['validation_data']['lat_accel_max'] = lat_accel.max() + results['validation_data']['lat_accel_mean'] = lat_accel.mean() + results['validation_data']['lat_accel_max_g'] = lat_accel.max() / 9.81 + + if 'SME_TRQSPD_Speed' in df.columns: + results['columns_found'].append('speed') + speed = df['SME_TRQSPD_Speed'].dropna() + + if len(speed) > 0: + results['validation_data']['speed_min'] = speed.min() + results['validation_data']['speed_max'] = speed.max() + results['validation_data']['speed_mean'] = speed.mean() + + return results + + +def plot_response(model: DoubleBicycleModel, title: str = "Model Response"): + if not model.time_history: + print("No data. Run simulate() first.") + return + + time = np.array(model.time_history) + states = np.array(model.state_history) + steering = [inp[0] for inp in model.input_history] + + fig, axes = plt.subplots(3, 1, figsize=(12, 9)) + fig.suptitle(title, fontsize=14, fontweight='bold') + + axes[0].plot(time, np.rad2deg(steering), 'b-', linewidth=2) + axes[0].set_ylabel('Steering Angle (°)', fontsize=11) + axes[0].grid(True, alpha=0.3) + axes[0].set_title('Steering Input') + + axes[1].plot(time, states[:, 0], 'g-', linewidth=2, label='Lateral Velocity') + axes[1].set_ylabel('Lateral Velocity (m/s)', fontsize=11) + axes[1].grid(True, alpha=0.3) + axes[1].legend() + axes[1].set_title('Lateral Velocity') + + axes[2].plot(time, np.rad2deg(states[:, 1]), 'r-', linewidth=2, label='Yaw Rate') + axes[2].set_ylabel('Yaw Rate (°/s)', fontsize=11) + axes[2].set_xlabel('Time (s)', fontsize=11) + axes[2].grid(True, alpha=0.3) + axes[2].legend() + axes[2].set_title('Yaw Rate') + + plt.tight_layout() + return fig + + +if __name__ == "__main__": + print("\n--- FORMULA SLUG - DOUBLE BICYCLE YAW RATE MODEL ---\n") + + params = VehicleParameters() + print("Vehicle Parameters:") + print(f" Wheelbase: {params.wheelbase:.3f} m (Lf={params.Lf:.3f}, Lr={params.Lr:.3f})") + print(f" Track width: {params.track_width:.3f} m") + print(f" Mass: {params.mass:.1f} kg") + print(f" Yaw inertia: {params.yaw_inertia:.1f} kg·m²") + print(f" Tire stiffness: {params.C_alpha:.0f} N/rad") + + model = DoubleBicycleModel(params, tire_model="linear") + + # Test 1: Step steer + print("\nTEST 1: Step Steer") + v_x = 10.0 + duration = 3.0 + dt = 0.01 + num_steps = int(duration / dt) + + steering_step = np.concatenate([ + np.zeros(int(0.2 / dt)), + np.full(num_steps - int(0.2 / dt), np.deg2rad(5.7)) + ]) + steering_step = steering_step[:num_steps] + + time_sim, states_sim = model.simulate(v_x, steering_step, dt=dt, method="rk4") + + print(f"\nSpeed: {v_x:.1f} m/s ({v_x*3.6:.1f} km/h)") + print(f"Duration: {duration:.2f} s") + print(f"Results at end:") + print(f" Lateral velocity: {states_sim[-1, 0]:.3f} m/s") + print(f" Yaw rate: {np.rad2deg(states_sim[-1, 1]):.2f} °/s") + print(f" G-force: {v_x * states_sim[-1, 1] / 9.81:.3f}g") + + fig1 = plot_response(model, "Test 1: Step Steering") + fig1.savefig('/Users/brianlee/vscode_projects/formula_slug/fs_yawratemodel/test1_step_steer.png', dpi=150) + print("Saved to test1_step_steer.png") + + # Test 2: Ramp steer + print("\nTEST 2: Ramp Steer") + model.reset() + v_x = 8.0 + duration = 5.0 + num_steps = int(duration / dt) + + steering_ramp = np.concatenate([ + np.linspace(0, np.deg2rad(10), int(1.0 / dt)), + np.full(num_steps - int(1.0 / dt), np.deg2rad(10)) + ]) + steering_ramp = steering_ramp[:num_steps] + + time_sim, states_sim = model.simulate(v_x, steering_ramp, dt=dt, method="rk4") + + print(f"\nSpeed: {v_x:.1f} m/s ({v_x*3.6:.1f} km/h)") + print(f"Ramp rate: {np.rad2deg(10):.1f}°/s") + print(f"Results at end:") + print(f" Lateral velocity: {states_sim[-1, 0]:.3f} m/s") + print(f" Yaw rate: {np.rad2deg(states_sim[-1, 1]):.2f} °/s") + print(f" Steady-state G: {v_x * states_sim[-1, 1] / 9.81:.3f}g") + + fig2 = plot_response(model, "Test 2: Ramp Steering") + fig2.savefig('/Users/brianlee/vscode_projects/formula_slug/fs_yawratemodel/test2_ramp_steer.png', dpi=150) + print("Saved to test2_ramp_steer.png") + + # Test 3: Lane change + print("\nTEST 3: Double Lane Change") + model.reset() + v_x = 10.0 + duration = 4.0 + num_steps = int(duration / dt) + + freq = 0.5 + steering_dlc = np.deg2rad(10) * np.sin(2 * np.pi * freq * np.linspace(0, duration, num_steps)) + + time_sim, states_sim = model.simulate(v_x, steering_dlc, dt=dt, method="rk4") + + print(f"\nSpeed: {v_x:.1f} m/s ({v_x*3.6:.1f} km/h)") + print(f"Frequency: {freq:.1f} Hz (±10° amplitude)") + print(f"Results:") + print(f" Max lateral velocity: {np.max(np.abs(states_sim[:, 0])):.3f} m/s") + print(f" Max yaw rate: {np.rad2deg(np.max(np.abs(states_sim[:, 1]))):.2f} °/s") + print(f" Max G-force: {v_x * np.max(np.abs(states_sim[:, 1])) / 9.81:.3f}g") + + fig3 = plot_response(model, "Test 3: Double Lane Change") + fig3.savefig('/Users/brianlee/vscode_projects/formula_slug/fs_yawratemodel/test3_double_lanechange.png', dpi=150) + print("Saved to test3_double_lanechange.png") + + print("\n--- Done! ---") + + # Telemetry validation + print("\nTELEMETRY VALIDATION") + + try: + import pandas as pd + + print("\nLoading telemetry from 08102025Endurance1_FirstHalf.csv...") + telemetry_file = '/Users/brianlee/vscode_projects/formula_slug/workshops/data_for_dwshop/08102025Endurance1_FirstHalf.csv' + + df = pd.read_csv(telemetry_file, low_memory=False) + print(f"Loaded {len(df)} samples") + + columns_needed = [ + 'VDM_X_AXIS_ACCELERATION', + 'VDM_Y_AXIS_ACCELERATION', + 'VDM_Z_AXIS_YAW_RATE', + 'SME_TRQSPD_Speed', + 'TPERIPH_FL_DATA_WHEELSPEED', + 'TPERIPH_FR_DATA_WHEELSPEED', + 'TPERIPH_BL_DATA_WHEELSPEED', + 'TPERIPH_BR_DATA_WHEELSPEED', + ] + + available_cols = [col for col in columns_needed if col in df.columns] + print(f"Found {len(available_cols)}/{len(columns_needed)} expected columns") + + if 'VDM_Z_AXIS_YAW_RATE' not in df.columns: + print(" x VDM_Z_AXIS_YAW_RATE not found") + else: + print(" + VDM_Z_AXIS_YAW_RATE found") + + if 'VDM_Y_AXIS_ACCELERATION' not in df.columns: + print(" x VDM_Y_AXIS_ACCELERATION not found") + else: + print(" + VDM_Y_AXIS_ACCELERATION found") + + if 'SME_TRQSPD_Speed' not in df.columns: + print(" x SME_TRQSPD_Speed not found") + else: + print(" + SME_TRQSPD_Speed found") + + if 'VDM_Z_AXIS_YAW_RATE' in df.columns: + valid_yaw = df[df['VDM_Z_AXIS_YAW_RATE'].notna()]['VDM_Z_AXIS_YAW_RATE'] + + if len(valid_yaw) > 0: + print(f"\nYaw rate statistics from telemetry:") + print(f" Min: {valid_yaw.min():.1f} °/s ({np.deg2rad(valid_yaw.min()):.3f} rad/s)") + print(f" Max: {valid_yaw.max():.1f} °/s ({np.deg2rad(valid_yaw.max()):.3f} rad/s)") + print(f" Mean: {valid_yaw.mean():.1f} °/s ({np.deg2rad(valid_yaw.mean()):.3f} rad/s)") + print(f" Std: {valid_yaw.std():.1f} °/s ({np.deg2rad(valid_yaw.std()):.3f} rad/s)") + + high_yaw_mask = np.abs(valid_yaw) > 10.0 # 10 °/s threshold for turning + if high_yaw_mask.any(): + high_idx = np.where(high_yaw_mask)[0][0] + print(f"\nFound turning maneuver at sample {high_idx}") + yaw_val = valid_yaw.iloc[high_idx] + print(f" Yaw rate: {yaw_val:.1f} °/s ({np.deg2rad(yaw_val):.3f} rad/s)") + + print("\nTelemetry validation framework ready") + + except ImportError: + print("Pandas not installed - can't load CSV") + print("Install with: pip install pandas") + except Exception as e: + print(f"Error loading telemetry: {e}") + + plt.show() From ca4d41cd25f24dae73a2e9bcc6c8cfbce94bd356 Mon Sep 17 00:00:00 2001 From: goob10000 <65315624+goob10000@users.noreply.github.com> Date: Thu, 2 Apr 2026 10:18:48 -0700 Subject: [PATCH 08/14] sure --- Data/temp.py | 61 +++++++++++++++- Data/temp2.py | 95 +++++++++++++++++++++++++ Data/tempBlueMaxAnalysis.py | 138 ++++++++++++++++++++++++++++++++++-- Data/x.py | 34 +++++++++ 4 files changed, 320 insertions(+), 8 deletions(-) create mode 100644 Data/temp2.py create mode 100644 Data/x.py diff --git a/Data/temp.py b/Data/temp.py index 587d9e0..99f91c8 100644 --- a/Data/temp.py +++ b/Data/temp.py @@ -3,8 +3,8 @@ import cantools.database as db from Data.DataDecoding_N_CorrectionScripts.dataDecodingFunctions import * -from Data.AnalysisFunctions import * -from Data.integralsAndDerivatives import * +from Data.FSLib.AnalysisFunctions import * +from Data.FSLib.IntegralsAndDerivatives import * from scipy.interpolate import CubicSpline dbcPath = "../fs-3/CANbus.dbc" @@ -105,3 +105,60 @@ ax.scatter(dfNullless[t], in_place_derive(cs(dfNullless[t])), label=f"Derived {frT}", s=0.5) ax.legend() plt.show() + + +df = pl.read_parquet("C:/Projects/FormulaSlug/fs-data/FS-3/10112025/firstDriveMCError30-filled-null.parquet") + +df.select([a for a in df.columns if a.startswith("ACC") and a[9] == "T"]).mean_horizontal() + + +fig = plt.figure() +ax = fig.add_subplot(111) + +ax.plot(df[t], df[frT], label=frT, c="blue") +ax.set_title("Suspension Travel during First Drive with MC Fault") +ax.set_xlabel("Time") +ax.set_ylabel("Suspension Travel (mm)") +ax.legend() +plt.show() + + +heFR = "TELEM_FR_WHEELSPEED" +heFL = "TELEM_FL_WHEELSPEED" +heBR = "TELEM_BR_WHEELSPEED" +heBL = "TELEM_BL_WHEELSPEED" + +df = read("C:/Projects/FormulaSlug/fs-data/FS-2/Parquet/2025-03-06-BrakingTests1.parquet") +df = df.with_columns( + simpleTimeCol(df) +) + + +fig = plt.figure() +ax = fig.add_subplot(111) + +ax.plot(df[t], df[heFR], label=heFR, c="orange") +ax.plot(df[t], df[heFL], label=heFL, c="red") +ax.plot(df[t], df[heBR], label=heBR, c="blue") +ax.plot(df[t], df[heBL], label=heBL, c="cyan") +ax.set_title("HE Sensors") +ax.set_xlabel("Time") +ax.set_ylabel("idk lol, 0-32767") +ax.legend() +plt.show() + + +fig = plt.figure() +ax = fig.add_subplot(111) +ax1 = ax.twinx() + +ax.plot(df[t], df[heFR], label="frontRight", c="red") +ax.plot(df[t], df.select([heBL, heBR]).mean_horizontal(), label="meanBack", c="blue") +ax1.plot(df[t],df.select([heBL, heBR]).mean_horizontal() / df[heFR], label="ratio", c="green") +# ax.plot(df[t], df[rpm]*11/41, label="RPM", c="orange") ## Cursed until we have proper wheel speed calibration +ax.set_title("HE Sensors") +ax.set_xlabel("Time") +ax.set_ylabel("idk lol, 0-32767") +ax.legend() +ax1.set_ylim(0,2) +plt.show() \ No newline at end of file diff --git a/Data/temp2.py b/Data/temp2.py new file mode 100644 index 0000000..e90480f --- /dev/null +++ b/Data/temp2.py @@ -0,0 +1,95 @@ +import polars as pl +from Data.FSLib.AnalysisFunctions import * +from scipy.stats import linearregress + +rpm = "SME_TRQSPD_Speed" +lat = "VDM_GPS_Latitude" +long = "VDM_GPS_Longitude" +xA = "VDM_X_AXIS_ACCELERATION" +yA = "VDM_Y_AXIS_ACCELERATION" +speed = "VDM_GPS_SPEED" ## mph + +df1 = readValid("C:/Projects/FormulaSlug/fs-data/FS-3/08102025/08102025Endurance1_FirstHalf.parquet") ## 276,1075 +df1 = df1.insert_column(0, simpleTimeCol(df1)) +df1 = df1.filter(pl.col("Time") >= 276).filter(pl.col("Time") <= 1075) +df1 = df1.with_columns( + pl.col("Time") - pl.col("Time").min() +) +df1 = df1.insert_column(0, lapSegmentation(df1)) + +df2 = readValid("C:/Projects/FormulaSlug/fs-data/FS-3/08102025/08102025Endurance1_SecondHalf.parquet") ## 77, 862 +df2 = df2.insert_column(0, simpleTimeCol(df2)) +df2 = df2.filter(pl.col("Time") >= 77).filter(pl.col("Time") <= 862) +df2 = df2.with_columns( + pl.col("Time") - pl.col("Time").min() +) +df2 = df2.insert_column(0, lapSegmentation(df2)) +df2 = df2.with_columns( + pl.col("Lap") + df1["Lap"].max() + 1 +) + +df3 = readValid("C:/Projects/FormulaSlug/fs-data/FS-3/08172025/08172025_20_Endurance1P1.parquet") ## 72, 1120 -- Drop laps 8 and 9 +df3 = df3.insert_column(0, simpleTimeCol(df3)) +df3 = df3.filter(pl.col("Time") >= 72).filter(pl.col("Time") <= 1120) +df3 = df3.with_columns( + pl.col("Time") - pl.col("Time").min() +) +df3 = df3.insert_column(0, lapSegmentation(df3)) +df3_1 = df3.filter(pl.col("Lap") < 8) +df3_2 = df3.filter(pl.col("Lap") > 9).with_columns( + pl.col("Lap") - 2 +) +df3 = df3_1.vstack(df3_2) +df3 = df3.with_columns( + pl.col("Lap") + df2["Lap"].max() + 1 +) + +df1 = df1.select(df3.columns) +df2 = df2.select(df3.columns) + +df1f = df1._cast_all_from_to(df1, frozenset((pl.Int8, pl.Int16, pl.Int32, pl.Int64, pl.UInt8, pl.UInt16, pl.UInt32, pl.UInt64, pl.Float32)), pl.Float64) +df2f = df2._cast_all_from_to(df2, frozenset((pl.Int8, pl.Int16, pl.Int32, pl.Int64, pl.UInt8, pl.UInt16, pl.UInt32, pl.UInt64, pl.Float32)), pl.Float64) +df3f = df3._cast_all_from_to(df3, frozenset((pl.Int8, pl.Int16, pl.Int32, pl.Int64, pl.UInt8, pl.UInt16, pl.UInt32, pl.UInt64, pl.Float32)), pl.Float64) + +df = df1f.vstack(df2f).vstack(df3f) +df = df.drop("Time").insert_column(0, simpleTimeCol(df)) + +fig = plt.figure(layout="constrained") +ax1 = fig.add_subplot(111) +ax2 = ax1.twinx() +ax1.plot(df["Time"], df[rpm], label="RPM") +ax2.plot(df["Time"], df["Lap"], label="Lap") +fig.legend() +plt.show() + +for i in df["Lap"].unique(): + plt.plot(df.filter(pl.col("Lap") == i)[lat], df.filter(pl.col("Lap") == i)[long], label=f"Lap {i}") +plt.legend() +plt.show() + +# df.drop("Time").write_parquet("C:/Projects/FormulaSlug/fs-data/FS-3/PreparedData/CombinedEndurance_0810_0817_2025.parquet") +# df["Lap"].max() + +df = pl.read_parquet("C:/Projects/FormulaSlug/fs-data/FS-3/PreparedData/CombinedEndurance_0810_0817_2025.parquet") +df = df.with_columns( + (((df["ETC_STATUS_BRAKE_SENSE_VOLTAGE"]/1000)-0.33)/2.64*2000).alias("Brake_Pedal_Pressure_PSI"), + (df[xA]*9.81*df[speed]*0.44704*300/1000).alias("Braking_Power_kW") + ) + +fig = plt.figure(layout="constrained") +ax1 = fig.add_subplot(111) +ax1.scatter(df[long], df[lat], c=df[xA]*9.81*df[speed]*0.44704*300*-1/1000, cmap='viridis', s=2, alpha=0.3, label="Brake Power (kW)") ## convert mph to m/s by multiplying by 0.44704 +ax1.set_aspect('equal', adjustable='datalim') +plt.colorbar(ax1.collections[0], ax=ax1, label="Braking Power (kW)") +ax1.set_title("Track Map Colored by Braking Power (kW)") +fig.show() + +dfBraking = df.filter(pl.col("Braking_Power_kW") > 20).filter(pl.col("Brake_Pedal_Pressure_PSI") > 100) + +fig2 = plt.figure(layout="constrained") +ax2 = fig2.add_subplot(111) +ax2.scatter(dfBraking["Brake_Pedal_Pressure_PSI"], dfBraking["Braking_Power_kW"]) +ax2.set_title("Brake Pedal Pressure vs Braking Power (kW)") +ax2.set_xlabel("Brake Pedal Pressure (PSI)") +ax2.set_ylabel("Braking Power (kW)") +fig2.show() \ No newline at end of file diff --git a/Data/tempBlueMaxAnalysis.py b/Data/tempBlueMaxAnalysis.py index 65d1939..2bded34 100644 --- a/Data/tempBlueMaxAnalysis.py +++ b/Data/tempBlueMaxAnalysis.py @@ -1,8 +1,8 @@ import polars as pl import matplotlib.pyplot as plt -from Data.integralsAndDerivatives import * -from Data.fftTools import * -from Data.AnalysisFunctions import * +from Data.FSLib.IntegralsAndDerivatives import * +from Data.FSLib.fftTools import * +from Data.FSLib.AnalysisFunctions import * t = "Time" @@ -59,10 +59,136 @@ file2 = "../fs-data/FS-3/11222025/11222025_19.parquet" file3 = "../fs-data/FS-3/11222025/11222025_20.parquet" file4 = "../fs-data/FS-3/11222025/11222025_21.parquet" -file5 = "../fs-data/FS-3/11222025/11222025_23.parquet" +file5 = "../fs-data/FS-3/11222025/11222025_22.parquet" +file6 = "../fs-data/FS-3/11222025/11222025_23.parquet" -df = read(file1).vstack(read(file2)).vstack(read(file3)).vstack(read(file4)).vstack(read(file5)) +df = read(file1).vstack(read(file2)).vstack(read(file3)).vstack(read(file4)).vstack(read(file5)).vstack(read(file6)) df.insert_column(0, simpleTimeCol(df)) -basicView(df, cellVoltages=False, tempsInsteadOfVoltages=True) \ No newline at end of file +basicView(df.filter(pl.col(t) > 1200).filter(pl.col(t) < 1350), cellVoltages=False, tempsInsteadOfVoltages=False, faults=True) +mcErrorView(df) + +dfNoRegen = read(file1).vstack(read(file2)).vstack(read(file3)).vstack(read(file4)) +dfNoRegen = dfNoRegen.insert_column(0, simpleTimeCol(dfNoRegen)) +dfWeakRegen = read(file5) +dfWeakRegen = dfWeakRegen.insert_column(0, simpleTimeCol(dfWeakRegen)) +dfStrongRegen = read(file6) +dfStrongRegen = dfStrongRegen.insert_column(0, simpleTimeCol(dfStrongRegen)) + +fig = plt.figure(layout="constrained") +ax = fig.add_subplot(111) +ax.scatter(dfNoRegen[pedalTravel], dfNoRegen[torqueDemand], s=1, label="No Regen") +ax.scatter(dfWeakRegen[pedalTravel], dfWeakRegen[torqueDemand], s=1, label="Weak Regen") +ax.scatter(dfStrongRegen[pedalTravel], dfStrongRegen[torqueDemand], s=1, label="Strong Regen") +ax.legend() +ax.set_xlabel("Pedal Travel (%)") +ax.set_ylabel("Torque Demand (Nm)") +plt.suptitle("Regen Effect on Torque Demand vs Pedal Travel") +plt.show() + +fig = plt.figure(layout="constrained") +ax = fig.add_subplot(111) +ax.scatter(dfWeakRegen[pedalTravel], dfWeakRegen[busC], s=1, label="Weak Regen", alpha=0.2) +ax.scatter(dfStrongRegen[pedalTravel], dfStrongRegen[busC], s=1, label="Strong Regen", alpha=0.2) +ax.legend() +ax.set_xlabel("Pedal Travel (%)") +ax.set_ylabel("Bus Current (A)") +plt.suptitle("Regen Effect on Bus Current vs Pedal Travel") +plt.show() + +file7 = "../fs-data/FS-3/11222025/11222025_11.parquet" +file8 = "../fs-data/FS-3/11222025/11222025_12.parquet" +file9 = "../fs-data/FS-3/11222025/11222025_13.parquet" +file10 = "../fs-data/FS-3/11222025/11222025_14.parquet" + +dfEarlyRegen = read(file7).vstack(read(file8)).vstack(read(file9)).vstack(read(file10)) +dfEarlyRegen = dfEarlyRegen.insert_column(0, simpleTimeCol(dfEarlyRegen)) + +basicView(dfEarlyRegen, title="Early Regen Testing", cellVoltages=False, tempsInsteadOfVoltages=True, faults=True) + +fig = plt.figure(layout="constrained") +ax = fig.add_subplot(111) +ax.scatter(dfEarlyRegen[pedalTravel], dfEarlyRegen[busC], s=1, label="Early Regen", alpha=0.2) +ax.legend() +ax.set_xlabel("Pedal Travel (%)") +ax.set_ylabel("Bus Current (A)") +plt.suptitle("Regen Effect on Bus Current vs Pedal Travel") +plt.show() + +dfWeakNeg = dfWeakRegen.filter(pl.col(busC) < 0) +dfWeakPos = dfWeakRegen.filter(pl.col(busC) > 0) + +plt.plot(dfWeakNeg[t], in_place_integrate(dfWeakNeg[busC]*dfWeakNeg[busV], dt=60/5035)) +plt.plot(dfWeakPos[t], in_place_integrate(dfWeakPos[busC]*dfWeakPos[busV], dt=60/5035)) +plt.show() + +np.min(in_place_integrate(dfWeakNeg[busC]*dfWeakNeg[busV], dt=60/5035))/np.max(in_place_integrate(dfWeakPos[busC]*dfWeakPos[busV], dt=60/5035))*-1 + +fig = plt.figure(layout="constrained") +ax = fig.add_subplot(111) +# ax.plot(df[t], df["ETC_STATUS_HE1"]/3300, label="HE1") +# ax.plot(df[t], df["ETC_STATUS_HE2"]/3300, label="HE2") + +# ax.plot(df[t], df["ETC_STATUS_HE1"]/3300 - df["ETC_STATUS_HE2"]/3300, label="diffHE") +ax.plot(df[t], df["ACC_STATUS_PRECHARGE_DONE"].cast(pl.Int32)*60, label="PCH Done") +# ax.plot(df[t], df[rpm]) +ax.plot(df[t], df[busV], label="Bus V") +ax.plot(df[t], df["ACC_STATUS_SHUTDOWN_STATE"].cast(pl.Int32)*50, label="Shutdown State") +ax.plot(df[t], df["ACC_STATUS_GLV_VOLTAGE"]/1000, label="GLV V") +ax.plot(df[t], df["ETC_STATUS_RTD"].cast(pl.Int32)*40, label="RTD") + +ax.set_xlabel("Time (s)") +# ax.set_ylabel("Hall Effect Travel") +# plt.suptitle("Hall Effect Sensor Travel during BlueMax Testing") +ax.legend() +plt.show() + +## Graphs to make + +# 1. Wheel speed vs traction control +# 2. Regen Bit swapping a lot + Regen Mapping +# 3. Regen Power usage +# 4. Potential MC error due to ACC Board not reading shutdown properly +# 5. Tray Temp Sensors +# 6. ACC Weird Temp data +# 7. ACC Cell Temp Distribution +# 8. ACC Cell Voltage Distribution + +dfa = df.filter(pl.col(t) < 825).filter(pl.col(t) > 815) + +fig = plt.figure(layout="constrained") +ax1 = fig.add_subplot(211) +ax2 = fig.add_subplot(212) + +ax1.plot(dfa[t], dfa[heFL], label="FL Wheel Speed") +ax1.plot(dfa[t], dfa[heFR], label="FR Wheel Speed") +ax1.plot(dfa[t], dfa[heBL], label="BL Wheel Speed") +ax1.plot(dfa[t], dfa[heBR], label="BR Wheel Speed") + +ax1.set_ylabel("Wheel Speed (rpm)") + +ax2.plot(dfa[t], dfa[pedalTravel]/dfa[torqueDemand], label="Traction Control Ratio") +ax2.set_xlabel("Time (s)") +ax1.legend() +fig.show() + +fig = plt.figure(layout="constrained") +ax = fig.add_subplot(111) +ax.plot(df[t], df[busC]*df[busV], label="Regen Power") +ax.set_xlabel("Time (s)") +ax.set_ylabel("Power (W)") +plt.suptitle("Regen Power during BlueMax Testing") +fig.show() + +fig = plt.figure(layout="constrained") +ax1 = fig.add_subplot(211) +ax2 = fig.add_subplot(212) +ax1.plot(dfWeakRegen[t], in_place_integrate(dfWeakRegen[busC]*dfWeakRegen[busV], dt=60/5035)/3600000, label="Weak Regen Energy") +ax1.set_xlabel("Time (s)") +ax1.set_ylabel("Energy (kWh)") +ax2.plot(dfStrongRegen[t], in_place_integrate(dfStrongRegen[busC]*dfStrongRegen[busV], dt=60/5035)/3600000, label="Strong Regen Energy") +ax2.set_xlabel("Time (s)") +ax2.set_ylabel("Energy (kWh)") +plt.suptitle("Regen Energy during BlueMax Testing") +fig.show() \ No newline at end of file diff --git a/Data/x.py b/Data/x.py new file mode 100644 index 0000000..f2fde03 --- /dev/null +++ b/Data/x.py @@ -0,0 +1,34 @@ +import scipy +import scipy.integrate + +batemoData = scipy.io.loadmat("C:\\Users\\Goob\\Downloads\\OneDrive_2026-01-07\\Batemo Sponsorship\\Batemo Cell Data Molicel INR18650P30B\\Batemo Cell Data Package\\Molicel_INR18650P30B_measurement.mat", + simplify_cells=True) + + +header = batemoData["__header__"] +version = batemoData["__version__"] +globals = batemoData["__globals__"] ## Nothing +print(f"header = {header}") +print(f"version = {version}") +measurement = batemoData["measurement"] +firstLayerMeta = measurement['meta'] +Fu = measurement['fu'] + +## DCC (Discharge) +## CHC (Charging) +## DCP (Discharge Pulse) +## CHP (Charge Pulse) +## PRO (Profile Measurement) + + +# Each Has + # name + # T_amb (Ambient Temperature) + # t (Time Seconds) + # I (Current) + # V (Voltage) + # T_surf (Surface temperature, nominally 1xN but may be 2xN?) + + +for i in Fu['DCC']: + print(i['name']) \ No newline at end of file From 433fd2d064ffb50dd587fcf41336bf3b0b1d538a Mon Sep 17 00:00:00 2001 From: goob10000 <65315624+goob10000@users.noreply.github.com> Date: Mon, 6 Apr 2026 13:31:39 -0700 Subject: [PATCH 09/14] file name change --- Data/{x.py => BatemoDataAnalysis.py} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename Data/{x.py => BatemoDataAnalysis.py} (77%) diff --git a/Data/x.py b/Data/BatemoDataAnalysis.py similarity index 77% rename from Data/x.py rename to Data/BatemoDataAnalysis.py index f2fde03..ee4565b 100644 --- a/Data/x.py +++ b/Data/BatemoDataAnalysis.py @@ -1,7 +1,7 @@ import scipy import scipy.integrate -batemoData = scipy.io.loadmat("C:\\Users\\Goob\\Downloads\\OneDrive_2026-01-07\\Batemo Sponsorship\\Batemo Cell Data Molicel INR18650P30B\\Batemo Cell Data Package\\Molicel_INR18650P30B_measurement.mat", +batemoData = scipy.io.loadmat("C:/Users/Goob/Downloads/OneDrive_2026-01-07/Batemo Sponsorship/Batemo Cell Data Molicel INR18650P30B/Batemo Cell Data Package/Molicel_INR18650P30B_measurement.mat", simplify_cells=True) From 19d39136591f280d9ba25bec0db1e3e5eea1a180 Mon Sep 17 00:00:00 2001 From: goob10000 <65315624+goob10000@users.noreply.github.com> Date: Wed, 8 Apr 2026 15:11:06 -0700 Subject: [PATCH 10/14] small param changes --- FullVehicleSim/params.json5 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FullVehicleSim/params.json5 b/FullVehicleSim/params.json5 index a9edabe..edeedd7 100644 --- a/FullVehicleSim/params.json5 +++ b/FullVehicleSim/params.json5 @@ -3,7 +3,7 @@ "Parameters": { "stepsPerSecond": 300, "simulationDuration": 40.0, - "interpolationMethod": "linear", // "linear" or "cubic" + "interpolationMethod": "linear", // "linear" or "cubic", this is for interpolating the simultion controls. "ambientTemperature": 20, // °C "tractiveIMax": 300, // A @@ -28,7 +28,7 @@ "p_0": 82000, "load_0": 300, - "Mass": 300, + "Mass": 300, // kg "wheelBase": 1.65471, "a": 0.853506, "frontWeightDist": 46.46, From 9ecb2f80ce76ad767994ebeb9e4576589614b914 Mon Sep 17 00:00:00 2001 From: Gautham Vinod Date: Thu, 9 Apr 2026 13:33:48 -0700 Subject: [PATCH 11/14] Created Battery Thermal Schematics --- Docs/Battery_schematics.png | Bin 0 -> 205906 bytes Docs/fs3_batter_thermal_schematics.md | 3 +++ 2 files changed, 3 insertions(+) create mode 100644 Docs/Battery_schematics.png create mode 100644 Docs/fs3_batter_thermal_schematics.md diff --git a/Docs/Battery_schematics.png b/Docs/Battery_schematics.png new file mode 100644 index 0000000000000000000000000000000000000000..8e5a1f31e82047c112471690934729992f1fc7bf GIT binary patch literal 205906 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 W@{(wPkpvvXFj(hdk9b;@_(cY(Q?Z)HKFbpZ ziv!)6$6PHolRXPB%rV!{8VG5P`D2#SI&U`5J4~xJyEM(!zThliDO@}9eX#cQ_oIYA zBFSi3UVShBil*74N6nF6h&3sKmYi4T$41K|Q2yf&6+AJQ%tIkuLUBCu^=liOo0k}m zre6MW>;&QAU8vgKl*p;RosvLXkbfUMKWT!w_Y{2MLk65n#a=JI!~LZ%NZ->N@K?kT z^dpw9Cisb-&+8nFcV&HJ zd4xO6_x`o^vAuN#v4it_RL(!pe(*NIzP$DV`AAW8M?s&K<4Sk$m$uG}j`f+&MYE9| znSE-D-xo2)DQfjv#tKDO+z+Pkt2k6%?xn&xEVrnp#AWr^FOG)y_G)DU7A{0z{c=r` ziDhrmR##Ct*o4}?vpnnzMMdC#n)CA!(6ym>6{@5y?z>xaHQ4PR1p68wQ9cM6O&_nr z)?`&_rW9SC`5cFEQcqxTcK4k{+E4C_2Bx0!d`t7Ylj?R_M3`3(zn#-B@i^opZdNc~ z;k2RGwHJNn`YS`3AVvm9!sglX%AB@4xxm$t`^i=mh2u7u;S)pp`2Gp|EwP{}CdUUCSy5NpPh*tW37z6a0wFX1y-(VG=+K!!NKFKb6S)n#YQ zWxGAEK`Plk{;!mr5FCHCBv(Z{9JcGq%FXf!18dTTSZ)DGiNNo8M3sg!t z7lg%eiNOjNyH-NVO>}wel~rIk#wkzE`||lz5t!F|t_zySpqw9FL@)TKk9J&zV?4Kg zFp2fWD^~{eyztov+0S>rQ%;OH z&aNV*-#m?9Sy~D+YD%z_!ros}7xTWp14IAXs;8&a>yv%xKW#3T6Q3x*J=%yPLF0Lh zew@CjUmJENwqyNVzvPJQV0R5paFKbI*7#0r3i{as<7J!V6Z{XJpAd7#JyVnG%U#N0 zmA&v<-sR%HmiQC%rbj;eCsOtKi}M5YB$9}0$Vj@<78<>Xf7dBbqaFEeFUSa&bC8+% z+RtE{utm&Fg(Cz!5GL9m(#j-h2Cs+9F7EXykY@U1E={@qSUP6`K7M~!a`ng}gqO)Q zYYujWockp^+F-L1zkwM!q1(4C`Qzk6 zjkwgOHJ$5%hp^SizLj$UR(eszzx)TY;Rw>%&4m6|=hcj`Xr~5mb{UkaluNj~bF15x z_$GHBS4+9Cvg%twc;8Ftt=B-BBgc1H40$fzc&+D<7%y2npB|cJs;4!6J>r4Vhzl}a zIuz-*f;;0}Zu*mZgGN9QMyxR*@XXZvz8oC@!HZm)j-g^Xllig+q;((f==^xbtk9&| z>w(BO4+4%T>u%K+qbFuH%;sUBJuI5!^|01&UN{RM(P;)cBbc+_WNAk~P;|LE7ufaS zTROLT+p>GN@zYHP0h2rZDjG${u+-JqKzyB+>M0xPR2arE|227pG=fP9H`pqYGIQ-p z90&v^|2j!RTBzM!8twFgS)ovRi6E`8P_z8^Yg}=Yh{iIGoEQ@60*kuo@bT#Sv(MX; znb5vS+qQ@GRfit=hBP;vjFY{M7`6Daqr{0wpWMqCFAD(49%!>zUcylgX5`i{YwAIU z6x*?8KZ0lvM8se`Qxhkm`)X_vI>Itq))R{kLs89Wz`=!bim()xANj6<(r>UxJh9s+ z?KQL;{XsZJhHC6%xBvE%+*9n?e%;+ZX(a0A_F#75H{2ycc^|wqK6nY5k!Nib8R0h+ zr<&&V#1!GaU91>b;hercvc^%zB?l+*lS+?#Qior&QrEQ)(yw>D-VQEfGn-_uh``nS zsqwiM$QkxdO?+Xvhn+OZbd4Rs+eu)lZHy#SKL`l z=D_u<+h*F@ES9O>`2gFC$p{qEEHd?5*;HTTa0uGY*wMe}j!U8W zAv5Bom6e3>?4_-S7|A-|NZkDv7sUpJ#SrFX#;0!ZVcx_>30uEcOV{z7*6(v}+?=-J z(3hPwS5yoN7ch-@N|nRgv0xEG@}^15xRvAL!{MqkR)*7j3o-ng8qwq!`3Syh{}UH0 ztXsnu_M;DypDeo&eJEwre<3iv!q{{x`1xvkx^7*PQd}*5eki2&?)vw)MVvy<=I^gZ zQYD>%2!@cadLjXMeWLf*AcEnv#R)}r;X>fC@<2-RY|}`|_6m5{d4HVK*S@D*Yqb-x zy-vP&o|A^~SghR_0g~LfjaIL{pSU5YJJv=NdU;#BqiV)LQxZ^>UzWpbyDB@L>L@== z?~@wvWW#B2l2Q4xES#|#*PY)tsM_E8K-U;5Ams>pEY}C0VI4PLd}`T6-}%$V&>-wD zq>Q~{Lf;+QpE&by;-ltkjoG*+F#uPVQH2&f+dNJ6ZMw=99&bp(HvR&tk zlMM>2yNlFAE)tBzgc--u^}?!)6?Joj3ajd!YRawUw0v8L-{u37r9cx8MRTX(plJ`n zA?k!M$nFJZ>j^GTOr&#`lfbdt9DJ}Kd$J|dcB_!_C#bG^n;Ro9N!n2^Wn^`=^3fj~ zdjT)SQiIm77eCqlFQ$0)v>w9k0DcUczExabqD-7td>%lymzR}p@bmH4Jw zX9uwFIV|d3EoF6~oNG4%WWxzui&PcT+&&OFF*aTQ&I^zE=K*`jnZh1~HASHdAa{sR zHRMR~_6^5%NjKYW73Dyuj=YcPVJ*Mm*);9aeK~{cZ}Aydw;#U8t>m3dXLoRti9spd z4ZYJqav8UCJJ>@>l9pebi%p*wthEA_a+6@5oIwF zG~cr1&HsnFw~VT?@7jKqR+JDW6%YheT2f+B0xAL`O2ZmnAKOW}tu~dI&pYUXV2vYC-B3 zI>FZFTn$mLPq@T!oE6i#8~+`C6ZH0e=Sw>sr#q6D^(;Z3x=Cl}_0=ILBbHK96y$S2 zjn^e?s;i!I(=e@BMy+{J#%A)#>=1EMnC8Im8R92IBqS|>} z*6dcx>qwbK*z=u3EU7b2dUj!Mj=O=*6%$j5FIGMNG2gi+k63iGy;$??%o|Q7h_$v4 zZ~uW<=NSzjl+N5!f8$0OO` ziYLn^Ct33kbipBjfwu==wB_Z^Gdf!}hTbsx`JQRIThmHjAVpe}!~xv7W~lYxx0L4i z=P295%+?u>Np=rL{#eFh*6(dpViQNe;)c!MXL_X7!XSp&bBMvkDU3 zR?7h_h5fspn2DQ0N29%kHWLgnc*j0h>>{f8Z@!LBPe}?Ax_Qf=HKVW^sUK`df{AUd z1^=8vjjAtx3Q>3-Yu|m2Y9j3}pRuYZrNE4%nQ6iaO32P42{K86i~sVcFI8bM$jcUhZfh zbtV^$SxM}S<4siT?f_sb*k+6o{!ww}{>};=#$_TTX%%z(PejnvCk-H6-Phd+&r20hTLY(eDyVEHp0tkvQ6_yl8KDr`#B|nLr##$XVL1 zh4A=*ix<{exO4&Mgm=N|JSR5|HD>nht>4NmVB)75jLZy*{)TV+S}dqyy{ruSe5Hwe z7m*{e4`Wvr$GkcA>bew5tb_h4MLB9XpYW=}`}|UA`Jp`AawG%8Ar%{d#C(u+9$g+# zqiD|5BVv%2PN$XMfLX}kiqE%&T<b1*Q%5006hET!2dj?Hv! zO#$ChO@E7&gZZ9JG;>LsB;75kBNE!bj3H1m8C3)@-XA4|giVoTEvH2pr~1m+ZBNO# zxZe92@Cj>*6)u`QnkB>gozJoMK?|8^Fu3k(T8>EwGHZg4lmz*ag@6}E`D;hj-!~ZG z7}q~v9&K6tQ&;{IJo27mo@F~>EQBiJ5ga}H)OAL9L>_fj5{y}T0jj)1Jrp_|J>i_&rez*v8>vd*FAR#>$g(EPIe%v@3zH8xX4_HPi z_Wgs_#>ojNcJnNqRtrIVJIlGx7Jb}y1Kb%`HHR2sGs!ff0eE=<;Bs@W$@( zxp1xLZ>s#M%hv*})a>hqvgxz>jG}QltE=1($M_1WDK7?B=+QwExO`Ik@WZ0fcE0LaiYsh&ths_$2GB&2ln1254}W&8hn;p>=&1X z2ns!|#$mGj3(=QU*%s2qUHbigNxux0Hc$X-Vy+DrrCgAZDc_5pHJ@riZYz{Gyg@z{ zR;le2<@qb?H`Vt-2a5SGc# zl{<0)`+ZMC*lu19cY+GYw=bo^` zTIb$OoYgVd&xam&bMd>vd)RDIFhqV>$?Q1zY9W0(-OAbQDZj%#@-WTHrdtSQEFv}b z)z{YLp%oYVRd3!jCxX*_H=Gf|4oe*7IhWr-9R+%k2i{0`G84{fNjif;3fd5I;J&yN zosV5W+BfA7NG3i}tX4imvYcw-@HXHl;@?>ak;5>}D2yR9&}W+KRp=r7&^(B>O~)R0 zd3KAt&3SFnEHH~j(jML_Ab~nr)WtI`<5FmmyrfJ~h`Cu%V{wmE4Yudro_r_O400$6 zfANl8nuXb7PNAWZQcqMVMo(T^5Lz*>7;4Mc&JzmXYt@}!hNHz4Ing^e-Y77Kwku^j{Bf{3rp5b1>w2c^2F;7LItqMF zMtAWS&D;$Uq#uaZb3O>Pv_|qYhyaYt*3nB${GCL@1x`WtC6FIrug${we~a#L6n~+) zVk_M$@~V_K&T${=P4GwTl8WQ4%;&x0wfl{#<-c~Qgm*hm*dse%N^B|eP`M$*YIeG? zSD~s5p+Qaqd%&NHTi;XN^=Qk(VXS35Zm-!Gi+ee_>s!mnpEcqpWdnL^iI-CDB<>NS zN1L5^TcZGVGvFV3sl3tVddx$z1&ag;WH5L{mnm1zm7bc(?|=5~_l=2BiWK^Cz*Y%> z4&Ivn!uTr(Y@y+2Z|!K$U@;C`zqJqq;!4~td^(KvDi+i3d9fuNS0(#DJFb5UPOHBE zWp(oqk9e)7^=M~g#CTq6wn-zr^2{i`wb%-r?n6RWnho&>+&m5*rr7BiyQbK&RKo;yl&yDEO?=SiSFwU0-}>f zIBB(yT{v_EROF{v;d@*0UIOd16xY|Q_XfXPekjonI5k`tpui#%Q_FO|C)mg8xPI?O zgYeLZ9iel!CAH44=iTbYX9B*%G9Ng%e6N%AEaFIDCna$C)hUqZy!+!Lb~q-!=qCO& zHKz?VfS`}25xNZ5dzo^N2!aH|xnIf8KU+EtJI>(hCpnY2U#v|Ezd1fpGQ7ocz?w5; zH-O8)cqk=WT09!Xn9}8_7dHz*@V*q?|j(tT$jwyJjy8#xW)E< zDxTYZEl}>G>&9pCR_xf}MLm@<4nht3Io$Cd4n(O59DwTd;dY@(a zMN~7%M3PQF;1&4|w%sC(3mn}6pDnbA{fHnWi}+BB2xpbPv`5D&k}*h-VcVNeOO_e6 zx3J$6$gn@ak)S9vbzxWG;y%|+*o?q+mawzOo9N23)p$=*7d6+5lKqg4u)F}y4{pI5 z=U#)eOtrYagOq2yg7vNwQr`0{`7Ze>+<`3`s!z)Rb@>#NSzmC&|wDcjqquwS%ZQ?BgXNFv0 zi;3MDIh+=-IgqIS%p8zkv)RQ4Zv6tiPgi8*%GT;>-pgmz@xuCAXMReiJY-pzdYw^I zBLV6Y%x7sHEYxW>amNVU5QR0hRXrphmT)@eVVCVWeFtDJzM|NtUl+fNGXv{y={P0P zIkso4C7iBGj;xN=v;aD80W~&E?m;;*s}%j&Ab` zV`T5I7+~!74#i<>LN^P1O07}Gcm8jWXy9=|=C3&oO?LjiC=`)R8nHMQYEG(Y=nValFI5W7rix^@Xapd)VNzrQnEQ~XTL|H7GZ zLYafpnh(Nji%tI!$ghNM7#?&s&SqeN=RGuez;9$mn=d)QxQ9V895;X!!IxAD*F@{IhsySKw)Xp&|96 zcp^dRamvfH?JlJ#E-4k`7JV!e6KpI>mkFf)@RXdunbLWyq4D}7;V~`W$n=2O8fI z0hhzwVzZ*d`1Cd{os!7XSu38;hGIUuMh#!7nk*YYn!9@IN{en+^X;J^E1rl#k<{7U zMD6+Rl=9)qvV5LCoj7-=q?BXhCNtLTDc*sf{w0iYhk+$VtPTFtnVbon zUzIru^&YGB4}{mLl+^hX#ePeB5zePa%^_q=chKALNU`dbDW&typW~4~gy!70h#6h8 zGNK4f?U+fhu2#BjM9jZ26W6Wkx4LUG3j7~bQhDu5ZGtxu)cATgKGNq}fcCg5*Z9H0 zITq6WNx^Q3+9rxxvA}kKaUE1llYPh|SmM>I_S8Ku(E^@e;iLX_a?2e0a=oKkY}WC4 z@=F<;bX@el#3@`-t7N1EHsr4rR*L~Hj+Is^OHlcPW-if>VB2w_fykGMa*gGT`z@X7 z*B#L$Evwk~G^)3*UiU$VlAws~D5d?BJngFeCAfYSUrJcnU&tixw#AvguB_J7;?+Kr z%^`8*){z6fFa8Lux1OfWV{^NLL^d?;bV3ro_y*?izw{WXi+GCM43`}A-(XP<`Pk7W z=}zc8!Zsg>;c`aZtiKhb?OCC6nAqOq8=HS@(VS2wt99V7F0Zyg&dK8EbmkGO{b%Q4 z(9MGa^!*S!)R8>MJ68OItf0NO_axu)4!Yl3 zQslD)U+v3iUQHT}K=#&&_LY9Fhb{Z6{L_Og3OMbj#T!n=q!re#t4PauNU`RlQkM09 zGheuq@Y!=NWtLaU^S&JR&FZs{$TfS%yzn?nSF!BKLM92F4!=e|nf17i&5fgMeHCkr zr@J=f%XgA~a?Xs5F1xx*8}8vR#b>Jt+1h6%b*rM;ZH{Ox3$K#+jb0bRc5v`?!_)go z%Wg74FdXH#)wwFVSbfhEm3Djkm)tj2&K`#%%V*zVRor9cQV|@KlzEjeZ|(U`DLzTG zj@2j*fB$x`WsY?PWs&EXocF8z8tMiY$3GG{-!t1xFgTSVPI-ofpg~Pj3D`q3^>=Tj zb^31AW}hXAU=E7t<&>_>vtA6l?|3lRrHaqlA%2KS>%f;FHY1U|SVJd>6->!^X>Adg zl;qw3USXP?wR5O_sOT=<<@UAO$G@+W5^P7z-;hN28JrWTK7*-yjy;kQfbv=m^rSSn z#@Zbjpm{7gKf<Gu-!ZU2&Nu1z8bmUXm z9P78}1pH`tE3Ed7qRCG8am9is)3tV$m-pvix(f80Fe2bjUX!Np0aftAJ9~8O!#1;Q zTzsvyo@uh9^aKfv*}j6-kg62x5dTTnl%}=6JmujyTU>3Pusk1ek*W$#ZcHhg;NE1W zzaJZhSbC$!r=4Zzat~~O6byKG6RSK*=q&LUl3%NG95@$!nJHsf7_pLc>`qr&Z5~Q?B!SsLZ7QMXT?CwL6|YIvB?~?TA5?iUMyi%p zaHU|x#ktd?4rS`!VN8-%!#K;eMZs`xcsF3Ks2pC7vSC)+LIr@V-)W{q)3D$v8gn7znBt+0fRu zQ~2Zu(tKO06R8T)r^K4|-;lF?dmXMi=5zj9Pg}0~{1uuSl|8c=rUPm^-uxeN$0`1L z7x2wX&O>df@{$hltU{ zBJxtQ=2&m2XvlspZ2!C#E_td%B`QypZxUtEn;XrP9lnBNxHr`7 zw-Hz^m!z^M>g8;;`)L^`EZJI`B)+Qi0eD{RfrSR1lw2Ral#ncNWnW~}vw3i#`><~B z-p_J8K_5ZA$xYML81eu?@iGq}N_GB7Hqf7W(?>MQEyUr_#3^(0uB0{r%HYoRL*fcO zH60wrZFe~}2lKr1CdnMHttzX?_p_F-HM(63B@Gp=7Zj?e9P(3QFImi%;fb=Yr`5K6JNlvz#$+Ln9uE}Psy^=$Au}-#c4a*tAEf)U+fa2^?{~?A zp|_`8Dr-JF{r2CLXt9k;h&c@O539!yWY6fi@0e6!L-0F@;tD*#Jhd;62N^E$%Cqzr zYcJc~z)H7UPt?8fN}7DT$mBR58VlzZ6@+TtbHRrrGO`t!669{O7Sh;s>*-CZTFQXO zLI;aE2i=t+PIctf#On>zDkT0~Hx*jzLirxdl>t}Kom6YvvDatThsgGEwVWXRZ{1H+ zo-%1yJX%?WC>S>TX7p+=)ZX@`w5xV>$T9nUTlI+$+rZ;PTy(ImKLxw4v*e&XJgh+h zPa%Tj_iorYTo1;)PO-R$VXUn5{3%}1>m6}C*z<~KJ(Eb&O;Gb$IAGRk{U^)8E(d?F z{*g!kwY=Oakd!iC+ji0`=zCIM$T-t_hbiD;<)#dQ*O({i7d4s-ooY#s9CF8vZ(1eC zs*YW+wLZA4Y9Y=8g#uojMFQuuPZS21=_Wv(8AZrZNdLLhjm5#H`V7nOGY!&Y``7C8 zVO35rG|XV(azy_hC=&Lb#h!uhq(a>lP`^8P%3Vrv6S7z->-28wS9TMKIoWG&;hEk; z+Srg8s=-1uL6kzSZOP!$BOEQ;b#sT_thw4O>!Wss z1jTW0({Fbvt2}*@K3&`v_(?uux)=W?iL3ZL1I6$s{|;*)3&~SD`vkGbcrr0PAgkBl zva9Cf?!S8hz(VJ0eTAKHA}}lZ{sN1Vp4HbS@AVffOX}9r^iI47Ik=`)8!jD}v+{6+ z|N5^+hQSCOLL%Llmum;v&gh%(CSTun^bNEoEv@1MLc4#wxkNAPqvu0-Ci53YPoaQo zMjCKeEiRCoDE`MGv0ynAcf@yQt%sDaB`D&I74q%og1*2Pnc;2PKx;9>6#MU;S{uJw z8gM45GP2R9(kR-3T%=9^4yNCKn)l=HUaT#nz37YFfyC6B`8N6y-FU`plIZulgO+S1?DdXs z4nV?Yk+6DIWD0e2TYViWcV8_kPyEtLR~R>JGPT}j24frEc2Cykx=G6;_Wn^=@txKl zn2%dH*1UDUtM-VQ!xYorJN`<;HRtyNa*A#iG?JV*GKI0w*9g2not4=S4pNSv-XIZd zGe)Eavfc+7!j8~3OFn1XXheF{0=wyuaCTp2^F!G+_zz+1s0!B}cuTjeNWIFZN!f=Z zeW9bbL%6~C3l-Pn-%eYyoe;S%!Fs5FQ@GozPA)&9G4NE_7eQzox#yWryhBz7`!AR- zKr3&BpgJ^p*c5MsZSR?W8VtfSs@nPII+>|R) zS6l1>OUwK9#mySAB@fPlG&UuR;d)z|_GU!3GCdJK)hyD4;lZ?@6}F*-_BrFN{{5aU z9-uqAP4Q+C-PCzp``8j^wcd~|*?r4l;yto>SW8iJ7#XVo+D7CBhzW>iGvzp5e-JVJ zmQKlgo?BSn{Z@fEJa1yh{mD%41$A@(S!7@%NjKi`Ns7KrK}@8po7g<(i;~qxWTr8%;o+W{1EcN;3wIoeN}IDwCY1%pCwPU#kPda+kp#=r@p&F3-Olh zWt%%}XQ>sQncGM#A=mSFC^Sd$&#hASDsN<%G_zq;?}Xk%OQN*@11l@5Zsn+K8ljga ztNi6D3aw+;;*S53A~A8)#@4WJyuW?bji~a|y$~3E7<_ab4XJ4Tn0xDHRK;f#?y0A+ zW+W^;ZzypOkpL(za4vi{xvYIfIswJ4 z*%C4lZIZ>WWN~$-*Wra%Vy%IIP9$8!In?o|aFdGWaIcY}M4lrJa9$01ZWvE%PxA@F zNc~eO3{4X!E{xO<4$*b&H*HrtpA)*>P`ZF(hreU4H>FNByu@iC@gVx<<`b6>>BtoS zlg)om@kyDN+WRbN`+u4~Tqd++nemlrpJEtdvwFh+smqz)xH|u1F`z;CVM5P?3SJMqV28p5&=PN+6pRwa0z@XR^Jm~Ha? zlGXgfJjPmN1|NjKb4gF}1dg1Z;g-dHL^dBEloo!nGd5Vf%x6{w5Zh!OYJ7bI|VJd;7hKZj%>g7Ff8@ z90pa5tCfH`?}{2{pT5qiP9HsIn4(dbnj!& zT;Jrol{paC)~mx?U)n6Yo_65oR1jY9X)3+59_pEHMPZuMv;?By#uHoQ&^og^nHw8RNcRXi@v_=J4oa6?CvGbiECSdR1>?dePMp;uu$)S>=I`~UIJP1_!9 zP!0IkM}+U)jkTq-hJPsR@t?CRycTYN#Z)2f)(ta)!IGM0U&?F4$gk!A`tnO)3#1>` zdRc`_5nLKXqx6Ggz~l=MqjuvXfgGfs_w31# z{m^z5Ja-HR9zxQizYk$Uy{(XABPu^Da$O~izsa~cWE~HlJ=4|Sdm~fo)6PA__u6pa z(H9LYwHcdpQXA+@Gr|j2SvJt5`RItXv@`cKwdS~{w3>%{6uTEn&%!VoFU;_3cAX=N z)jONl9oZO*C=wkvS_E2BqAj24z+R;CcZUdy{hMkgKNxL2`k>nam}M<80$0wm%}2T( zy+pJky`_8gG)4u%j3pY2FNO%7?KzFVVTl4@djwc_cIsH3r7AaR@&wW&cU#G@vWvUN zP)C{HhPZz_oy{Wb+wQZC({LT8N(*cUB2A?$`&YjNLO}eXY;hFr2{HX-TxfP=`1dWI zRNoof*ErUHclOu%RFj9rZ!vkQU%lfR8m_|WF7Xxc`GtP5WR|3&uG;F>Y!iXG=JZNt zss6C2b$sM4L%-WAr5pS6P1h4vLX{P`VKjCxt_4``qyf7nyW{>XUs7ZH?Mnyjv;^EM zS>&Wnm$E#F&;=Q%UaQbT+G91ozz_BO-zu^?CkOoC7M^wff}4no4VP16TNsn<;ubTh z>CI2L6RnB`7c}MN;*=3>92x%n<5Ur~3385t?tpK-iK+a33F4D8f;AwLiPh{RKXR69 zw(_RHgO*K#`(Wu)oxqo}cNjj936Sqm455Q&$;cn)M~yx+cP2|X7dTplPiNjL_6PH# zT>?K62IdSTN7f_npclH*SLx9ZwTH82z#0et;te`fe$4hL{JtjH zk2%w@eU|l6j9IvGWZT9bOeYzQ{f9fwIi+odFG*8YJ$G%*S;k)1_=~z2HtClS&;KGh z^6siscXd_T8M7qzzj84n(c~K?2~s|Gzc=On9g`x#wItwW$nr7w<=ms3I&w`MWjj}Z zh(-s0m@7awLOD)H8e{Dwd6pxje7u>f7DZEGM&RI$u(!w!em&aLvap#z`jO8}#ZAe2 zgXma#jY9e5nlXznX17ULdM`Rv@v}*)Ld-L8f0NG1bQ}i0{3Y~xtKgh%D6ZmwJ%o!E z`FF(BxrYPp#Q!u6*Id8*vbqs_;GLh}pLy@AX*G~g+Eh9%lLs1?VS|RC^I_KihYWXc z>3DtbDkJHA{V@BXRCX(dO<;W83MVi#sRa6|Ap-azX$w{63gwi;|zr(GfGTP8pcFRC3k+Q}RsQ6`PnW&hwPgF4{2Zo#_xc7kSoh9r99vXD#&T@a zx^WhX>SbpCJ95t8?{LpfUf#$!$OUamszEe4T6=jp-G3Qrkddm-%WNi}XZa{#r4vsL zhPn0uE@{tu!Y}iqXRPfHvbK?74>I~YpG?L%();XNy8DEZWL%jHor4nyAn=k-5yN`y z7YpeH{F6QG`0WI+oPtNG{Q+x(9^0qV)5_P<>L@u>yG!6MbqRk2jhgQNJY%LdJnndD(!Vnv z@>ww3W0j;s*RS0im6O-N2&bdW3M#%Jiw~t={Iah}xhh#8;Qm%*-M7l2l+$&J)wyaH zCi}Djivs|lZ-!Bx)h|!fM_)891>oA~FUP|3cXqTL2wIRK+4W={7OYx9Hl30@;ybjp zpqaAL3gDY6yrh}Y(ZIKlNM{QdZe@GV5JQ^m!P)n2nw;RD^W5kQi~r+cBqFbh*wq3f3~!b9a6_H@Jz#Ks$h-93W~-F|)NYG9m&^gz34| zIDXiX858qFb*aP>=d=Q~tHsGmMrh(Ze$ezAbR!@b)u7kl5|3;c-vlL+nmGs5c|(In zb$IcCXg5fs`UxC}!W(m%&E_wNhio6xuNoq{jQA%feUg?7{zm3DLEY%T2}q?aootP* z7P<+2))++Dud(fJ3egEBg62FW%go&7Oxzt^MiboNl2#gt^R9|wN1OCma$#)TFoaOm z=jAoLYw&GNHN=V)N;rt=#vUf4*!Kd5SZgIxesEU?g^w{|E=?lMJ(f!c?PqpIi#Oz3Q*$PSU%cq2N}y@YoNexFF8u#e!89jG4&D5=mh# zyon9xCPtIbQ)pSgR?jz&ygm0R){$6&&TQ37|ordh0F>|S`6gE zPTS@=&$_-AuM{tNETDp{j+wiRFVG-m_~gja7WSGvIRG~9-S}qC=Ot^fP!j(knKW0j zZU_elf^qrYLh*Z!zuHWui+y1gjsLni&wr5doI=td$=_?}Y4z!ilR5a^A-k88RRyGs zGDr?0AUGOLY-q~)^h+WlQ!_7~OPK~`(L#;TyqAYs>ntpJJ8MpY&1SGUO=A@?Bonmw z>^rg6gM);JNLQuOQr2;S5K~KZl}U(Vw?)jmKDC?EDWqe3WrLu7=u512e zdG-zB^HSaaXW~L>65QZh7bA;P2`aL)jLc~!xDn1t&9D6zLo#2jw}Gg&V^ff-eEv@2LhAbd6;hR-?tyNy<{nW%+ zA#(VnDXyf9gNoPWog?TbT3{ubZV==o%5(P7a-3znyTW^uA=rnB!2JGhXOZVWoQbZe zT<(yiW{-wd( zOwqx*w!|r^?qYhsL_k;&_>;$BV?7)+PRlHeZcu<{Y9pV#Ie7#>CCe2`BsOa*L;8i|H+M*h)+-ySO`(b* zqO;r`tZ@A^+Dr3+g8mZ|I=|3T#r4ltrYo*xhI$Tj%aCp;Z9sKCvf&YAauy724YMex zrSiK;jS?1rAR7DsJJGRz?V)Lr_rzM{{%lUqEOxjR1!7)Y0W2!-!g8AKPof8 zmu)(^0@SK(4G$#IjEIu5t|UM63|8wem2>JhFRvvG&{R>+4>q~GL2l5q`4fGjJJ>-wSs)v)7sbCRg#li8*VR;ZO)`}=4Im^u=G zzDe1hM)xOX6qb2%Q@-7q%ETnEd_)uwRX@r>I#Dy|`savQezxWf<(yxzFbNSPRDLW zB=4nt@S|TG1T*88g6mTe7AiL%vr}DsO-y5+B{BbFJ zars_*%TnDFRc*tpT!L1m`j2F2B)s~AE2oU) zKqdyQN9IWH!lo-x^{L)dzv+`7uNPE&_|Z6(ZYO~q4rMKw3hqn>BvCZb(xUyzQy*n) zIGB^~a`zP?4g0}>oXcaBQjaD5G(0%XSsiOF@{Y61e5JBKHo&jIYzTZog%CW0#xjGe z1*DCaJ1ACf1rcDVd@c^`r?dKFxN7>Gw@HvtvQ(q^{p3@;=2_?pNae4 z)~A+>7LHBtGgF$)%*Oq`+m7|U_D;dSJAnT9BiM3CeLxWT3%#4n>gS}O zv$ZJIV`z`F(k)@&{rk5yw%2ldiK1l$)u3;edz>BQcluX{Ug+Mv5N3#|^@5E`;pg|_ zYnlpdNq4zS+UZfSspKW%y^4Ytv+1GB&6(LXO+vB`jH+yPRg7y|M^3!xfgzVB+H+p#pSw zW(@*L;BzT?zITXt10BP6`KOnUeY?@yHiHfEAum3)r~1d{m(D%6w~}`q(vN~xGHv%s zK}lqo2X>!Sil--mW^-dqnkIIMk5f@j#doCS6!~BRQh6=7Vy?MY!j&-AD z{M#EZIn9BQQvJmeI0=}6{VKz6x-fDL!(=ZXz?c66y})@Oc;S-e>r?xJF`KuDs5%%Uk4MRPBqot^yWeJavZ z^g6Y*!d@_VA=C$Q?uG|(DA8%?&R4@|LmaWb@*BNK?hO)op2|@GuwSk zY4caF2z*tn;X&tL&qWRR-wG}0^|JyKV9$uubERFR*-CwQ&yRHj8f7j|Z$uj+vUtje zam8gQz}3>NWV_DuCUDA?wa)yc{#H_kG82I6rK@mC{z^R)hHU5Sw~Sj*goY!%XIt4p zc1A4N>Ya)hLa&9;El>A#x>n0CKx7{$#^LEfq{PxzqPfQ6?Iux*}+D4-= zW3n9!aPxeB6@NODQBU4?z>JmhOmeX5Gb&}B!A*c&A)3F%ykN-g4gJNyiZ`t)<%=gj z16YW-m(-#;KPJlTf-AX++-2XAvs%ql%xpRESf!)$1a$cdgVfo@@Ov&lSls`}W>w73 zuLwVajK3%U@Ps85Nd%8^ zka~$-`tAMMBxS1t-$VK5#V0S)+ja_pD8)i@+OE{GNKVb&diIOCqqW}Xsbs6)&LVXd(&8&1l^vdBom0L!n^7xyuCB# ztWsLsDo+Uyes1d(WeykqQk%L(GTWg2i1YOPw@iL86T}t4x!|706(b<>mD8;JM`bws zx{)KY8|m8mRbjeM%?Q8M2vAiiAdy9k1E)ik3~A9MBa6FOobp36)bN*!=b~(d;jQgz zC|QgXOawAO!a0-vt7xFN&Td)F`<8>1AgwO&sXUBf_>d(5Wo2dRil&X0v+W5+U>lH+ ziEg;Jv}ylVbepR)RZ##KvR13lgJ7I9Wz$q@L_Ed|g8&Dt$LI&q zTQ}xJ!jGA?8@lX=mN^@_yJKllm_pVc5sLVXrxI2ma<6OPU#m)Dw}J)9gxQ)!&kY~t z50`iDFSG;)P;~-h!jQM-k}4T zfn8Ss2Zk-t!Hlv|u*UfJN9c70yMAd!DauxIULuH+v3J_XO6wS$|E#cYsVBSd+_{@`%MZ*Sjzjj z@|r|i2?(8SibzHTpAKHOe*-i5`iR26X6;<~kYCVwD6|Gk#&NvrUr%WoD&sq{^*4oX z_1xvIz*#w(V?nFoQgJ@5LhFPAy$^2jvrM?_U40_Yt9MP~#5x z>4gUhV*~t}_0~04i z4bN9wn&i1RftLjZ2H6+NrzWmiUh_@(^5yvzPcBaUF@uOF=lX5U6c@f10FKg+(@Xr2 zI3gk6U(F(jhCX%$^=RWC75%~Rd$mE#=#Ly*>UUIZeR%iwvzH#b?ts+ZgKuE6AwfvD z$9dH&l6gd-jzZ4o6VrJjb@SxrIM?I7s^qIAy;jBnH#cevsFT@t?~Cx|X8=H)Md>qg zzVzz(TxkZ7ilA))`TC=kKuYfFkB|Ws9hwl1A~P|%o{KoJkSGN)Lx{U-KR=T;c|+5p zPF%XI$PY@LeANuILL#D&iu5PHpkd3o`MTg%_KqKG1{Y!raYw&yLme!Nk4mM+aZa4N zANb|mRt*yL2OT1?`KeEC3SDJem0TH=>^Z8i+$ zP^V67vsJI9PwP_4tbz|(;7U1l2DU*sL^QJQ?*Dix{}>&X&42yY49-_Wa0s(=JlA}L zvs}8N@M8W;DjvqyL;OU+)^pBv0>(IhHBBHH;0d%~0Yi-9eRacc|GA^t42*QbNo5 z44K5X7hgQAdo1rOOxe}&SO*7j{P9@y^CBK3CU+?Fqo;>YT^J~6H68K%9YvXn^hzJI z4)A8NDSu#ZHIQH|=XV9%@fy5@F3>R1cJL&YweHJPnkY|UukDL@9OqR;Z%5>onaIZTf$Vj%TzC}N z51X}~|73b|DoZq@N;zyl!LA|D$q)fE_!Ap4pV-Fz60{^A3m%WPO-h+T0Sp;q17DxU zgjFGmz;!uv|EeW#+@PXEZFr_JmVEhYy7KC!%l@OBGMjx#`_6_jf1X(jH2z{<#esedBroB~ zrA)8WPDtP1KAUmLA#Qu_+o13WW!&$6Jx0hQUvBMniBovpZjX%`84s}nY82D-Y#U}F zdB-0*Fgru`aYg&{-&$ae<%w}Re!fypvpT69@r@cDsHFErSEV{a(M7Dbh}V#}x!t#T z&ZysCWS(a&=J@P|#Ww6S;h4LZ_Px(hW#{9$?hhk|ub%iFAfeC{=yJcDeTa-K$e)|6 zeA(>b97ebs1Q!E|kpXn1zRKW>xBnrbq>>$75qI~f0AT7#FW z2qERa1Agl`$h6!mn`SvN=-fLfUJ6pGu5gv0?e6x4`M}bI}BJ3 zyM(8g=FwPwxzv5uOl~xIK*g*tPY!o(OX1NDBp?gMaAIx%{%nqVeBYRHz zQ;pFuToQsBt9j^%l;YSjs|s%#4D>uOKreKJ@}?P-9xW4Z#dHX+{t(rlY9zI205pMx zj7n?|t@EbRi{+x3C`4GmMQ^efZC~+t!D?6>{N<$ZU~g8u>OoQgh5w`ioe4f;1D1xf z_JW*yAMLF4ebVd6w>MRN)N^(dvEO*gh}|@Wm`GRw1lrZBe%RaGXl|kz&FwEGYMS^9 zlVcRSg}NT%Y@gJ;IxUM?0{2?6C{9Ts&C{B9Hn673ch`@O%;QNwP!3s2m z&)bvWho4MjBA5QrtfiZw+R+m6`Al@Mj~5gy8DeOImz%LE!)u0wZGJjPd-U)I4=Ed^ z`%og8Kr4FgaqZFbafBH)=9D^4Q!jd`4*akIhVc_PQ(;=+VSs{|jN-i`iVya|jnM(K za_a)~v>Kw!oD-EzRAC(2)V@hzIkcl+JzbL<&Y%10$Sx)hocB(54rCJAta8D3pTa?k zx)wN1{t206E4F{N*b`A_)APaRyS^Cz@;=ft$7JobFYiMzNKap64bAXylgqlA@#Gb1 z?L!bFoY%diCBIG?zQNto#C_6g~2nnOu1LbS(4ZSQGhP2yq>wON;Q;y40N4W%XhQMAdiB12_Y!5* zftC(M+L{lb>o`wPG*75zX2d|>TIemi^)qtlRuu702;9>Jhmv@8UP8N{Ct(~|0@hbX*Ll29SE9z0 zoQHU$i0@7!HwYm{oj&7=^s!GGgu%*~Shk*xr;OP1Z;@qNEwF5B5T1nb2fUUV|9bLp zT?tlui5wI1#rMQhe{b5DQ00{IS?5>0hL6z&fz#L*;0YI^`oV@RUX2D$m?H|ZMzhI_ zaV$++B7HyH_89>qt;^$%xsG&e)RQF;rcfP|T6?2*J6jZP$)r>fcyNH6SV&}z;NocI zsk(YB{(UR9A#Z-S8V;TCzr)Vkbu&Moiz@Qpia#cRd)ymvg4_cJ7>s_j%*dE6T>qQ- z!ZWpVLiK+{&jmw!$Vx9Gh?mfDml}bhqwRrcP`Gp>hSssn-M-UUvzs0Uu-)**yXZe` ze%1KC&QK}uxYk&dW9_;be+Sv)mlo9w?TqW(8IHfTouqwjXnlhK-LeTVMX+?w*f{Eh z5RjZkmJWzF&~q8opUZJr8&}iL7=hY&9+sk@*MVkh{L0CxrP_;7F0a=`qxQ?^0$C+G zKwpyhL91KV`&wYd_Pug*oAc`lqL{1+s=O7}`Z3Jy#J7z5iMuoNltM>v5xkH7NKesB zKMf7M+=*!Eo%1JxCOveQ3_0r-DGR z^jOM63y#lwm3MP5rd(c!ji-$LplWrY`d}Qu2lfH@ex4gQ8_C7)`q3d7bH<*yEAH!l zmA`Z*1lZ(d3@w2ZkvY{a3CoYZxt$i&IjPza*e0ylI zL;-IlpcvO@Ud2hqncWc!tjpK%M!AR7J4Ccc@;IqhgNei3ne` zA>Ri_$Kqira-p;*7wQP7(#eG~?q~mRs9mzyW8n*Bsc)hI71{j{_UXfG;-zlbsi?k1 z$C^z|8Kd!cX;-bcJAw+)Sekc%zo_t6Ofh0|%M=Un*`d299J@AZTsD9LgdR6hA74Bg4nC9v~X7!-tl z6DXzy{E+S3|1Z?V-!NF436}+C3WDo{jJ+%;nx(v21DRa*obcQ&G;?Q0qKrG7{&{wE zl)siRCI#hEz(BO;1qmuZtla-*+>pM%?*H=-p{J{N?tfgJH}uL+h-vV|+6rahto0vgjDaak@ z?pGCmx*-Bx@HTgqWq0PwAyAxg{6)_hjx>Zx#t}aj7HC75p5AbF#i5S@Ml13ci00Q8 zGW9Cf{Hgd6DR6kQs3Z_p&_8O_e$RUY|KMDM0q-QwV=;FCdeo>V-&FEKWrY<}DqK1M z_TM8DZ-Nn*7Pg&#oTFcNcA%yFC~WvOsYaf`?cZ3}=;nmH z&L2MAt1q1S{{?iV>`^yvB*swknvgVMm~*3e8inhrGf#x1__Pl3eQ;K^{QsC=_|)~^ z&WG091>-ddIa9PkW=dCkndlnp@D+xpeh;05z>@>>!Da5qZo7eF;0VR$qXukb*Q@FW zwotoVHsg1AUTx0yrXiH1araSx9@a~)O!|u$44$Lg?H*dRiftxCUrj~)f$Kf_6iY60 z$-4C5w#t~Xed9D32CI$DEic9ppU5fu#?qE@^uFmQoJgyJ-I}G>!9-4qNKO(21jz!DC1;xa)oR`6oO|E<-gkWe?BQ^1yH~F@SIwGL zPyHT{o#~h-`By|4>5}LzS2bmr+ypw_=dx3#67+J?$bPOyPIL;y}#DbNg-Xq$on5I&gZ z_#dD^Rk}3W1yhhJfl3fdSA&1$j+c<(4P3+VEqyW8cP*g@IlpxNC;{sVa@QRIXc}Q6 zK7jyDS-_|CE@V&Lh5ps>yjq9)T4{_-vf)nulQh597`=V=EfAspMk^9OkWif({BF0- z2s}q38yNLC?ew0_Mxe8|ABr>xLp8Oj40pivqR14VFUyeY9e~Ehy{ySXh|3|n|O$9E0IK_!?kNlAyImcoef|vPMM~6O{)aS9S^bdSE4AI8VVLdJV z@n2v1DUxi6igJH$8$!9gm5I&~AG)$fP0@y=x}$pbsjpr(wxT|2-v3;`d4Cg%)-cBI=jxmQ|mg{zp9oVxUMqo0DQ^yH{xDoJ+t9-MVydi z_}fq6^Wc$BIYKed;i0{(;Cl@QGreFiGdxeLBQATH!|*a=pNMiUlx7hp%otgQm z2)*yb*uK#Oz7*KlM3p;0&ET22^oK6EHIlPH*aZ7;_f@@R#P%tKj=7kL;X|W#)Q?_` z-H?_I+8w2_e~Cr@xgANQTm&hDCIt$t-x_K-vwcs{?IIza{N?fnKVSU@F;=$o-ip5* z-vFc=u72-#0EssE7m3!q?++#~Z#YuVDZ)63Dh4LjkS@7Q(kbM-+wfZaow88!8-K$$VQ-Uv#l-e<^=q z)n)qQ9#ur%z~Ilx3?Oc2qk*|1e6I^%RpBalUjE>>gKC7iO#J?TAZ0nr86V&K9)=S; zs$bt362bqXbFwXEIJ4P*Z(b#p-|UrEOLb*N+|<74-a0eEsNSE4yZY4~=CV5G%gU69 zbW5GBeJi=$@Hi}hv@4>;ih$Or*gBc$Fyy#EdqVoY@w;D;6MxA<`3y|9J5cTw|5isoK`BlCq0qLf_v}os zwIM?Ln^$Z;+oeFVs;+mSaOmo4&qm;m6j5a$X#WQFG0SyTx){y7!wA#|Vbp<=O}VSb zr2)?`4EU0a2ok^{aiBMFdn2cG=G~)6mbw9w;Lek^?xVHAmTS`;d0Ti2wnQe}=x)qp z*Ux%KMBcS{;-7HFnJxnu7B}wqWQrb>xn1_b-EJTJKJaHH zY1b{cFAz{g(~^@@cnM4l&|GDh8Z~GQmPi7`OYb4)ER>v#?=sGreJMBEUx|fyeweX@ zWR9U>;)918lx~Lg(Ti|k4l4#e+UCFbXsP;pp}OPgoBt#{e7(6pDyO?b9wtV9K*ic;Z- zsmqkAX?AhXFmok!pN~my>-_33h%grP+xuH>-pJ6E$dUKvDnt7lC5ccGGB2HlO9hgm z_Y)K?-G_?(?epl`>$8Q#a$z$Aa7VQy>9X4#eZnRSh|yn3=lzwZ&Ej)7GI>{>1fNS> zs=HoJ?f{WTiZ2CrP=C%TI-{>&{$6djg~wCZr9FK|hpY1Jd>sRycPjFMZH!NZU!STIN-LrP?GHC#=`Tj(_ zp+7H_s#2=h*9=nUX(%uGt1Ezxoj>gA_FcR9%=U(k{FO< zZ>Y#S{~*I!zf6l#eXqg4f=xk$9qAu}<<9h>9(cnxcNq#+9&fmfkPBE6w*M zdO5&TL!!ED-p)Z7@NTG907IyBE~v?69GJf9-rrfwxkv6qh$wR(J@|QD3G+ng)h|M2 zsPh}`^!HqA<3^j@zJptWGGQ&y#!gl-8#P3-8o8bR;Oi@1&hZ#^u*`ZuJ=lrp1dvNf z1ZSxuI25B0S0zhQwNu&a4Zt$KZRXiM?B%^2Y9xZ7O+BVl1AVk*4|Z24{b;aU-JVJUwqQJHgm$DJNHoy+7T*tqQw%!r&()RksJ#U z1=S9$Z>xkG2#fQ5U} zuPORf+3P+sN+uH$1y-q96Lvcgvy0-PjBXV>KTDgl^*?=|gO_sA_ekWp|fqCe2uPwAuE{XAKtfD})e`31JlVM@0E- z35vCMJEv?0f3fuLZIo1G?NDwKvomqfH4*d|+0$=7I!xpsooah16yCKSv@MmHF#+Yp zR}>BI{e{+(p2ItaY=iw4q!y=oF3zPNHzk(uQwtK5x<|EBZE3X2_c(Pgb7Y}cJb0bKx^PXR<**Tlz5kC6t{)KfyjQm}K39@s$W>Lj3?pd=L)&^q< znh3|@R74(2WIr$h(0g|3-e=F>-VnS#i0ONdh`+(gXsWzP11Z3M(B(%asc8k08Uk8b zzXm%zi-!hoAje8-5Q5kC(FLp%DTZne8RRvtZB{|AP!mQufFuu@NTl==39`h6t>MNZ z6M;wUn^&1;1F2=me2jm+kSUg;EA67Mizea(9GA6!pqcSE|m1RQfq8{YxC*?cb*wSO_LbfI*Xz=Xi# zqK2RQ?}APTa?BE|HK+qAivf|reJJOgRtAv+LEV%@mHNsLQXr%%8*>C8q%cLE(K%Pz zUlYv3xBy9D{}HC5SSs&wk(N?<3!Xp5S%y%kAAqhdp<;J}zsgF6RI-sg{lh*i&O{_Z zs3N_%WD5g_@-O6-yXA19Q7)IMp4h|Gsc{#5F;w$hQrZJGA2NgogSD?XW7uRT8G@T5 z+oceCyUXL-PO?m~8T@e$9_Hgi70?_ePM>DWR=BJfCa6GpbSG$ehTceIHYZe2S(&4r zA)LgJjh{s^44DSFD4`Sv5U^_FSLRQm)=`4WUwr*oNqiXY3|+;jzScLZ%?)zpPIivo zs$t!y>P?+96-j}R^fPp)n#q%Dzhe7G&XG~h8Lkuyw4>ByN=z$P)OEG+e5JbtE@U^f zmmVOsX!SG={4iR0NFIiM2v!W=o`rYgBo!2SpP73!q)c>QygY=&Nl0T3L!zzus|BwicW5UBeUN5E0=q2C|vsKJw z>RjRqZr|)RizMbCi%`_Ax_lwX5g{D=P)j={-wJE2I$Mqqy^Uuke+9Ch>bq?KSl`J9 zDLY9zkSCApU9oUJCABrZ26@SBRnVzrb>TGBrVyxv2~7yKR0R7;_st5UGdfZ7$2kvo z9yfiAGqd65C7F9rMKb7nE%o{0=t|ehVRs)Cm5KmXH<}a+W3+E1A=~z?2_mVLCw&mq zd?wNMIBD7ah%a?PQaH*yN*1ZPh|Ev{mJwxR{Ha$n4xH^Q*?Wj!Kr8UqmA;tH}2rRkdKTQNGpdALj+-`{)V{A%A2Jw{bCD?2D%ze|^@{>=as zQyyTj);X1;JWZ3r7GrYnSLid%tJ)>AdyC!`ooe1mmE4<$*h~AkFpt{(wF9-ZmpXy} z=pWn>EkSbB^eoYZ55Z>?60oviy*_7ssgvS3!mWj=EQdZtpjLT&BEpWL zmO!OlzggXNFGv9C-TkzZ&ZA9LNBg1}COG!3{m@?t(+LHI@MN`N6QYyKCG70=RL)dp z)ZdBdZP|(7RizGOZ~$cDB#g=YPShpupv1A8VAX;JzbRfzJMN`_F-)+Cne%WB!1g2~ z7|d$l;CjN^OFER9iK_*?9zCkSX)1EAnV1W8uU)tr!gGK#A;wvIT?_fl4fTV@C69b+ znpl;f990qKRgUs-U`8rn4AT1I?sO~zYyW(5WGOY)TCs4dHIe>J0Ip7?wL3r+G~g0l zJ@f5q(saPf2tdF!qk3q}>Wk9Qx2Bgl+;4Ge>_nck0?cNJ2ZYUgBs3d9B1Sah$;O&{ zWN9alXZWSjc*7{&?TX7d6ss{wDoV>NZ@)X?Dq8V;x|8|63v|UK8JFFc3FrnIrrE=` zt8}e;(`drggcm516}ftiw@+o%rL9K(PSl<{pG3!R$nqhNp8H4$sE||QILN#oWsycP zr7pr~EoJ}Ju&dS17FD#I%%aKrh3lnk7=M-fO;|mlz-Xjb&ra>->gw+qV(KRXq@HJzqp0VhRRscaf zbVqlBU|jHsT-%$lOSR7WwG3s^Z}ZNYosGSG$I!zISxYsnDaBH)Ei1M^er8?W zAM1381b0&0M@K8dpf_zn$s_ctQ|Ff5zy+DHE(7Mg8T5|g9I6jonh@_3<(Gq)%Lv>h z=f#DUbIpXoy{63}C4OYLx$wQw}sP}l)uao@Q+sByb>1V>!4jjp4JM=bbao%-~)zue{qZgSLL?* zFTV~uhArRqeKroir=-|l^fn@}TC)VNiTa=Q#jumfFV!?k{Kf?4uyQ-s_s~uU`sWbE5@;Mj5{cXDm8bAHRERBpRXR5Ov`!dSMC@eC=e=i02yVe zdOLY!oFa=r0!lETJ@Rc1L$F)FbtbXRN^m=Op3g^;1J1B3WI2yQ##b9eUBzt89$-?-0BM#9gJ__i zb%Q%KkyJF*uE23pEnfB*lbbBcX7b}z{dsX@q?(64Ohco5wIA>#At$V|J{mEG`G5%7 z6=g#z3*ES z_+!Fi0TMwI>D zu0>Uvg!Na8*ayj1vUUpPMSfIpeng6SV8PXOaGS_JY_9e)pRFLxVFd*V`6u!pOnl#t zQ&}%5YmfWKdIq(VydY)G-C#02c9{M925PWwAU^%umZrtbWZg6RTDBr7my)LdW$gF; z7{QR7nbMlQ2uZ zIL<8?z~9L1@e&i#ez$=^tC4yv*L!3T$O()d-z=W3%LyK*;tUlGq1KP~E1JrWNc$1A zb7OKsN>lG#VrzfEER82oO7WM=h-UZ%wskwe@dl3K+jr7MsZZ+mJ5nRB;+v;N$srCWGC%+n2gX1gwpNT^rc5wJ&2lwn0vSl3E@i^^*u2nUOB} z9#zkDds=^N;uzJ!69F<(1@;B{bdvPrwMWXH(VG%pA}Kq2h`;QS)!DRU>?!5VDmPLr z&wqb?=q?KeO6a5&7Cag?Rm=5u$j*1;$atj*l4(y zg4?2V0#K0Y$5tiS_z>4>kbY)(e42BT%iDGlBB^oAnG9vqETu4lXAjuZjFTH-T3mvG zm{gMlEMkKM%d7~IYceG_p;P#vLYUvGMr8R_ zq>5o8wa!yeYZZ;F=G!ze;=adED0H}(EBrMc`q5$2!J^@=XXlSF5{^~M}D{n2kT z*>1DRJ4RbSUoq&q-Aodm>kIR-<^myPoMr+(R}%&DN%)IML){sO1Bz+{is+B>f2jIE(Yb{|AwtxFD=d1vQRJb(ql=78_ zNnkX>n2S4O;T}!KO1Z`_MeUI)@|yxmC$v1HDoMf$^Jyf4evd^{rL#ZNG*iEs;l4fY ztFK;6Rdk8;shQJ&8qM~r7PBtCCL>{sQ|XHulj){mLi`p|=j%UaI39|F>;}1%`7kFa zI<&IF3*xLWPQpoApm}A$kPG?*In*Xd{VHooekEw&`*8OQ?lH$_W3?sPP-gH{x!C&Z zp~1&c-mTf^P_(3ii}>a!_eQCCXNj$pkN^-- zYMv;M?Jp29`TK7Yy8aD?8WL(CBTCj@iYK_xL&(a;F_GNFwpK)F78K0z#hSZT;-CNj z#^mcSjp<{`pxg-tvq;rJ1ZY<6xjkFV$!bZo%u9zC4y1m&&+Z9nht$B{f_-l(-8Lk{8utPvp(K84l=gRPbhHi7C)FV zPdM=K8m{p6re&3~4o5%VI$t35x2K;I!8}@(CdxCe)@Wxso*K;Sm|FI~* zB=Da_0XuyEsbK5T-m7t>ECfSk2Ggn`^cA7XFBARCr==%5xQL|e!pmQI{&MR89Lr?Q zyk22oQ92*eegEP3OcvJ33w$?A4k<=lHf1b9tlI1t@%kfH_l5VzUQgid84>K{t;01Q z$jwN?-HyMqf7|IS2UL!s#GBW-XZRv{-?Ayu@=}UtVX2%78FnJbssF6CQ5#VLCh;w6 zv~rRrD4@i4=;w?Ocgug}O@E!K)*VlKCkRf1t>FkQu`I6xw7LdwXf-6Awflo>j+aVJY7BHqydb*3btANHSF<>eSdarONk8dg* z{Uls}bVLI8uCuAkSC2BE0T5`vp%e9#Tix~9=~ecBe5Ib@eWeg+{N!^z`{1$)FW^bN zquKuM^)>O|V1t|C4^^AR=T3U(oh?zgj`pL5R`;cl+hFs=s-;5B&D${D(~-Y_ zrJfp_&8U&WifacL_YcoDbsYeKwM=c5eFL4*TzhxL70xq%XEamxS3C^dmC-k&+7Ve1 z>|%J3z^yCC_uG6XOO~kM{2u#B?N47)EX80E*cT07tfcM1?o;?BS`I9f-JQoW5%vW* zQfrl>{R$utoh3_$DAVl)rU8g4>B`0cv9(4J6lB?>-R6s1P!zZ32E9_wx5n;Is zyp@^@5##W|237;)WY`5$)@L;SGakUJm}-&DG-X<0<#i*J655dLIoE$EDtZtsSo>|m`dA3Yh? zsnNM@8Ezg-l`G!TljAz739n>_D*~Lw!|6JQ@5>&LWsbs7A>QMt}g zBH9IGd0ut!NV-t!!rvyu3Qnd1u3Iu!Ac))jbEBi=_IOK{*jS$0m4KRuwWpS-M|Axa zQYpUC>3)oWuVbDz-p1*Q;(ca#@F%vxZ(Hu1wR`s;irp0%+x5=?0a`K`024B6W(XkX#H^Y#E!*T2Da@tP%L{|wq+3W_9pOp>U4 zD0v^MsPQmHCzhM%kno_lsHYt z+n}V>a!B~7mAe(!oAfj2`uEdIR76~UjO;!~?;W2~Bo-yp&xzE}G335#QVXaKoOwW{Tsh?A8GmFjhQa?YtEgE{>a_PBxYtx6gum13b z%D~iA_U^4iy&=u{vt_kWceCtRrM6@y?ABECic2nX)GB8cqs9-%I#&QZ{%YXfxI#_ z!w-MqU&PDxu|I$J6vIoXkYB|>hBaBv^4WxMK0;`>)BaW5zg$8Jy&UejS>eCD-O#mu z8Dk)_8ylSCea#@Uwnr)5T@t_#yE$-dEdTH;GCe*0wrEmZ+{jIBZaJ2#23e_HUrtHQ zYE;pE4Se{=&|19z2yQoA?Es8#r6S^5O5Hv$gYGG*SQd`+^mYdpOC~TJhPZFP{U$02 zswcmZnzi4Z!jkb!ENOljcRJF zQ?5~f>OU+1v7OpGWj6Oerv%&_&FRov z_L0m@b8Bv$u%oTU?GoKNv3>j^WA1f}?yc!PUUJ=(lW@6Ch1gM^A!J2W%Z*uhYq{Sh zLANA`HXGXOR-BL)bpg#g2}XLa;R$j1B&6mvbX`fLl*fvDbHq)_u=P0mwTnSs6N)iC z9m5ICmedgLPi&_Ru5Nv9QIpG796-J~e(xhce9yHbcB=6%h7b6O7T|t#3Lk?N@${eX z-ku~Jqb1U{SxMEc29;QO$e|*wPPJ`N@%G$f_C0+#)3}B?Vw?}3e}BSU{M0#GAn4LY zvyR`Xno+|OLO_tCo8JTFro)lK9Y8xrG_dWTFZiai=%9ncKlwQZU#&k+8NEgBt zyi6}>^FSP(nnQyMUEqNS-}`#6wUqL$B7l*eoG(sMFcRF|{xuD&x@%0P4O@9*0PVa2 z+HEJ-?f?GB6&X{K~?bPDP}=#_lC zrlvM2xY%zA)~1#N#dZd)!?T2p4%)TEM%Ef7_CJ|6{D{A(mJ$D4n{%w!J9bZ`u=zQ! zFl2^m&LYz|N)##)l?Gw=@pTu>|^{RAc!> z0h8TmGCxd&VPIl1P2NP!$28>6?%rgRBtuqmvsr{>eM_P^zm?vU@Q_;1s157by1#io z>u6$FXinBY(YA*k^?6;(1=G;b(AwME8^cE*?gpF=d#zzF{S&<#Uw(k)A+Wn&PPUp? zj3#bwHx<8U!araC4>T5T+ePa@qrEJ~pa^B9@>@%WuE{;dFOi6!(N3?@z+LXNxL+b* zco0{5DmW)J;2@uFIDhALzxy6%#%iOxi@Sx+U8uhuJhKDbwrG;0vvb$G02&&as(^E& zX%Zrmg8~|(10Te6^c{46+Xd&G628v&E{Gqo&bEKLZnB@&DJLXk3gzddhXmJ8e(!bF z8kTSo7rk!i`Ur(E6Jb(o6=*VK!EMqM6pfmbaf_PWUTF#fr?6Al_~WlLj67d{0o_QNS+W#AI_^*6;Lun z+nO5B8;x53Gyc&bRynnJo>V%4TKdE`#!_zKJsDV7m%AHc?9T}|SRlh6p#?#0PuCy5 z2orvZC5KP_2s0Wptq?QS?Aq~Oo@BQRAKnoOv@E`i?h1vFcy>)`;803MGfsCh}sK!h3;o((DO8pxpJx16t?<0FrXfbjhS|7Q3-$JN=8%enRTb2>c2y2o4 zZgeq>ux>Jto1S7ZzKrRsaI`_@c-Cm(N+kRK_>hu`9kXR%fjJ%u0sLLA+s4oF=pA5V z;riXQhG9pty!g4|JTlYZsfIZ?4|ioK^4wZoeC@u{7pP7gvl>=_mL?x(W8gzXudc<6 z7tbd7&}NC#+CfYfONW?zUufX`y%oA9x{fEPFTWIdR=>X1kc`+y!Ucc)W3S@paD1V) z8i1i~uay^*ugMTW>+_Rx1I;Z?Yx~b#;8vw}Ugr64VL7X3HOKM1o$NFwPSoc4m$gE# zbFTMhp48Kolbjq@+a%YQqoc57(!*s-!3*@{^?c}=PfU6rbEK$=2z54X%1&&DE&rU3 zs%X_seY>iO57DpeDDq&-8os^*QwQL!j((3&q_Qx6XP?E7!R9c#jX|r!l1QJYF?E*x}T|3 zQ^0|ziMouMbYLx9x2ZpG>_c(Is$QDah#0np*`)L|&*qlANyDJou3}U&lHu3IkNy41 zZgEzI9JY4dr>I|-p4o$qC{W?t)2+F&{gz}{Vapcxk3TTxvE3hZ%(}Dm?w;Z1E(j;r zZb_2tv>hnUdK5Txs>!`(loxl^x71~}JD2;yw81FvbjIC4;UQCv^i%_YhW3?tJV;BI zZ*X&W?*#?kU=URbDS^0a_#vsizhQ8?UnPpLXcy)HUnXO1X>kG~BDGQ}$?vjxo4)0p zaYQn~O~D2hGh{$WSy@>sp0*!iqQc{GnYiUiqIasoqXVZMB~i@InC698N~v;5Yr2*X zGq{Mz$i%$7ymJP8Op7A06h2ZDcSrU(8g7dYpcOI65pvVhn>+)BSu2$s7(Kk(=D81CE&JUJ{nE-qiaz^vKyx)@N=oe7LD+! zs%FaC%3MMhPh7b{hGc<1-J6@7rZ*mIxk>(@km*^v5W_p#J~S+~OuwHiFm#3zCq0b| zX^-vZCq6PxsA0wD`z_G01O$HCU#z-(vW zlH!B5@4Xv5qh3{>(+I~{JxYD6 z$TV;sNkva=S2oKeKRLfbFX*DXJ-=TJ`&5BdN7`G}tIR(#t=$y*I2vK3?q(U-0Owc9 z>0rjgabg{F^dO(4*(m8wonij=Wa`E1Uz8Z3p@*^u98<}3u#Gux$)jElTXLD8kv{v()##e zl!1HBAxrUxcoKV?tZL0koOv0>kOXDU4u!a11l{AlMi4O`^uGS2V{Ln7@Ju693z#|p zCym-_FRMQsnXW?T3ae)xb-gvlZ#q-Brd5VBK04G&ZxF2lTe z0y~kE@f@omg*sLA<$zs;^-6x{Tpo4_L>2lL$W)T!VH^0R)7;2c=GT!F&@tFH_C6`< ztz>4-J^LO076he~;QM_b`jumyLOYYUqXT0aD)s?{z)TxWCTAHZTi0)Rx36 zAwY$4IE&HexRlQ_e|rf59HJ=^#r0!Mdi4XB@OnN<+&4(`ed4(pTP7?2uCocg4T zDE(NWF#+yCMj~H-^j6C{)PAvU1Zn~eP2;fT>z)yfT0H+yfDh0GbM6(S4=SE$nurfN z`XbmT##5)nfSO6eR?_K_p1vK@3*~l3w0@cvMX;UWG zs4{9JaCo0&4W!ckZ) zq9u9VT+lf~U2-(et@FyV0$^3}(Q${T%SY;Jw?>u)Fzu_*yCgg2R5i zb+SMeCMzQPa!q_c0fZz!+*+PUhBFuV=Q@#_!`>Bl+niO1N>xUD$oT~54c${effMa# zw`$Jd%13OENQS3m7d>RZBp~Qi@UE?hm*V!~i~#98=H9?d+WLkD)z4f;l4?!N`-%?t z@8=iVy#F2y2?e7BWa(`YwXy*IY?hF1yFwInh+2ca((5f5ACsrDG1P}F_qNw3fth`6 zO~%g3>dp1(<{OkMDk}4Yy|uNM1lEs7QEnd`8fV;!dPXju&NSdv57Oh6aHeP2dVWm)lPhM>Wbab8>4Ta*xsW^&%d3eYf)_5H(K3QutF(4XS{?) z*LI-5)d&mn*_$}TE$CjC-uK6NKO(**dd@S7ic?Z@es_jSbFj?xoR>}$OtDhqW>u$sD@w;HdJ^1_L?5YVjUHoM+fmAquGjPn zcKGt5Cw(h&{|rRgSekz-EBHf%rVEFJKrhFbh2rFW7z3|Iu7V63r|=PWkaJfv!)H2? z8%90;vZo{;+U}G!cXTb}Np7qJ*+C0($4f_%h+s-OJmcx?#?Rm*$|E`IsX2TeolBt# z!%lSB8oTSFKeX>Nm6i(*?WPBae7d-QWY25vGbQz~WmeA!Rnzlbio{T_O1Otl2{-t8 zbjgnm^@bdk=H+^-T3ccW5f!4~Q)>Ae%$>^i{`fmmkKB>t+mGyG$a@1$htsrv*;{vO z_d~xl3M{kM#;5yB7VV4lC(>3z<3@XlN4Mog4S!#GYn7`p|~SouxDZRe@Xu1cZXT|6WcRS#3|a4<2z0H zvF$zlM&u~lB^+DNKWdC6k44%VyD+z#6a3cg&tt9PcM5hmad>o=<3}GepUPgN$E9qDC&0yx?{8#hKVg9q%Zp0DwD9S#t-sPa|F2R38B|=t6 zh*` zUiZOxluAN4v$*b&k@RC7QTiQak~f2C75hdn`3|9Dc-Ib_{Zfu0?Cn`>eo2OHY-XFf zUL%dfQ$K!q*^vT1N*}e}@)~|~;kq59{t_*()>ZS=X?$V3C|b@hr?`!6KCumcIm-e; z(QZ)84%aEMPmWJYYVo{$#}%2uhsw$9Os^27X_<*8J?6Fi&r%ngUK+YJzGXV+&Vm|7 z2f;TT?Rq_)HPn7uxqss_+Y~Q#OH6p< z^7q%Onf(PP3a;92^u6GfnPd=l8gyBlBNlPEkBrRBiQgyEmert48z`=6yys3a_1b8R_p^L!Vw6{%_~QCAyE~$o zS-v%sSMvZj>e14j0}T8muxpB@5Z~%nfcV=|N{&-K02JV+NQAvwfV;!zd9n3WdIRUE zZ3b2nt64o-KeWF1rF2@J+qg$BZ=jFpOf!#{Szo@Xm+D}mIGqTc*9lmVE|I+HE$%gG zYMA%_P;S2gl{^e7^YuZ`jP@R!QC~4NR!318wwA1W5`uzNsc$HUSfmCLQ@g&|*f76AQogtG*3Q!g;72^dQL*euLG6nN_4Wf$i$xe3Jj zMl13w6v|0JcAQj6(p3!Fj(~@fhB%c4_p- zt!w84o1D6!sk!Gl^t-`|_kxfqPrqQjLobUGyUWHmYRkrmtMgeHnRmg5UR> zmaT1;VcdvkeOL`B#%5ZrTGkL+j>BO|Z5Yq|}{KUHVw&S{%H?%l83*+ym& z+8g9h8^q0aJ* zbM0&Bjz6>e#h65nVv43fhIecL*`ayQ!%`EN$sc9>F||TCA4q4203es;Lguj$eXv-Pa zc>L~hZ?@N1wR~l?-0F$77`TPlM?;!6!c|)iu`=em`r=fMPc9@^a1tLn*FKqx6#IIf zA77Ni-@qHU<~>wKuj&a8iJ0%&a+iBKURzD8E1C0pD>hU(yYR!cewO|>K!lcayT#J@ zZ63}}PrtcE!F}co*_Y1qvqF+5iiQ+5(|4)RjX|l`6UCIS&n;fqFD3EMuao35+{9d& z_}dS%MEXIJE+xBfKVMn5(I`&stN@~11m~Ibq&eq#s2X+@-`!bMM>|(nOqWCXQ_C&X zGH-RcaXI?5Dn7(gh^|Y-@cKaHLFltHqF)wVa`0p{$ps0upR`Xfqde#xe^l5VDyyuo zf%n!Um8Ml^V>uptaDZ~h;R;M+66lWG{L623-@M9F7tq7+q!(}XoCxk#z4OD%bc2n< zXO90pvE_2Q@Yj~YdK>Pb=P3BO^#O?oF0r4>RFJbTw|>-=(N=OX-^#J4lQaXOUM6ks zE^*XGxo21`Q{gbS$&gqfgVkcl$1XLykYS&DwaO(lWdm%$6G0}BVQ+nKK#JC)dQ}46 z?~#y0{&c{;>^AZemwwgXH^V=c;#{-260-{*n-buV4s{3JKZpGxD`(CW2o2C7s^iWb z)#~mKV2@mBbtnFLy9QsG)Ye3DIcWU7FIq8rhXkEAZ^O^)+W0!BnCDhRI%F^EaW{&l zP6qSXwYt~1Y(JJ<&iX4UGYt4{n-6iFaC;#3LT)XkO*rpd-_nc#XSwlpiIyM-2l#o= zaQgc3f4y>V>IEG}1{$ML9v3JCaisoMyk`p?X{gAG3Kn@Ib)x8x`@yrXTIoDEC&POu zF8#nus8X8MhbN#n0F8mWMV@~O>0Q*s;bXzS9}=?C(Xg{ z@ZDZ?Y)W}EJ`!zxySKT&vhoYqlVac^^GGMpRH@;qQi|Ki!AoDttFn~yuscRPp&Pn_ zguN$k?zKrDztf+vyyEe5;s}HmD7h1OAzGR$v2B6bxe!_yPK-n1zA}x%fB!-c|C32Q zn>$9owDg8IhEp(y>{Fj#Kqq-^|DG)DR1@a8lPv-scJ`JG9aAT94K-s(0WLC}%pYkf zT+=3JMCv-+MBj@m$`=oJY{(;Try)A$GXyt845n1c56e-q_n!T2P;>ted(YXqkI)MK zcHGqwjkKJ}hx=hkpx*fFeaEp8q$GXPOGPz|{i2?#I!?QbgnGIJV{iPTyKg-JuR~;B z`$W~@fZ7t>Hk8LohDSh0Z#1fS=H`q?G-i76g~i{hcYHU-yXW6k@70s-uYa_}3%3^A z4V221ZUzbt<;KApnB~wAMZf%~&RxJfdGph~Wi{gGH`?p}39IApd(YW_`lL$K{@duw z!=iZMyK1qgLQX29Pt>$+c4(rF0dMe${1SS1)>S_F6f3KPwEk|EQN<9Xzj@zEQpYw) z{)w;z6%mB)NN%E_{r`@zVYvS&jlY*FcUNQncOn}r+{tLEX)N5LI{Y(dx#?~Tv^I66 z0+I=)?_i`2w4QC?<1C0Wx+CA@(yZuTDThvBwZrj{{o;AH*Nb1zsgtKY8iEC&KF-Uol-q7Japzf6N}>| zs4w7~i8uB(iYSuzVUX12#4V)pG;kdYdJdy_^$kKaLROtbhIFy?M$tcj%wS?)vFExY z81ZUvp%^Kc?$-uN4^BKHq!a+EPswNNcgWOl)r#iAS1oDnC7(n0%gnzXN6aT~dgFB% zRa<4O75^nVKdS|m0cL~zpH9k;nTlYfQm!Z7xXt~yDXD|@)|y@owmjImzx8Ny#iXi1d~gEBlttr?=#1}) zA!d=Y-=8m+mqT$X32Nl*V{Z8STz%GK|JkthtVWwY)JMaYH!|d6>IwU@zv`VGkV0B+ zQ*Mn%SuI*OsvIDjQIGqfUBGVhxFd%a@>J3CcRH_DdreK=zj~V}@$MevxDX2KEDuiK z>AkX=4b^VFBz3)E0L1gEdKGgovtL>AZFd9DK8qJ3!Ke-t0z=4I^g$&=I?3!h4%9}q zxF6{=hFRKAeEjDcItZVx&=o}ur`rB9f6};WnasurDAx$rQ1O~$}>AQd~M z8#==ysL(SMhmi62zVQE`r~^4aYx{7yIgnzsZEQ{CrYUqXNreCD9n$@;eY?U6 zogQ|VAO$138_Rp;e&}Tk47>J^22e1!lvM25^(B3LUiKAhSgXKTMK6o^;Lt0b-T{r& z93{KTTAjx$JMY)08f1%#FU?|X)XTsMt|P2Od@t2Kqrb!ox~0XG@K0iYW`Axm-x(m2$dZQ z8o>SXfip3}Nr=ltufN^sokDMZnnb8kW@csxmfmKSb}tWb2?+=j_pZzs<0O1d-qu>C zoSlIGI#_U&c=UI^=(gMkbg<(Li~TiIu7=75m_~cvYB$?cvA;fv4F7M9bIVyHv;xog zQXX#7y|Q%L?WGrJW1-#X*tpM3lKZ3d6;@*QgH{zY(n3NUCIh1AV*i|NQ~8L4t(1d4 zlzs+fcQ%|Ap<#Ol~ zOt<)_OaIZYKxDOK*z1(N6$wr0c@|1$N)N0oL(8apW~;&wbs3^s+k8omrD}Qs7f>P} z@LK>O1R!?HF#hg77Cy-el!sQ~l&xzBPx_k6p*kz101oGf$*Gb-(^Gk45&33y9@ z*Zchtq`@{5A>w2tq3>vVj{cxy1~00GA-2uAR91ZPP>BTj1bK9 zuTl)r1ZrwhefQdGHcCLomFaHBc;jkV`|YS637C?JA%C8;D$`PvtlQSjHxI5-VMDs4 z(gbsTZC=G&fEh7UlU?u9ekc&FUaq#20;~AQVv+A57i6;svcr2Vg<&w#HrZc1*l#;^ zkmZ1Fj$oKmp7wo7B4`zB;F?!{#9-PtD3n?l;eE%;d6&ocF<5N*1U$jJg#+Drh|Ic@ zwjys3NII6Y-C3^A+(dOodoyi+(tr#%L4$v;<8QP{?nQ5Z}wnk};FQ9Fudcuf*T*X(_;>8-bXhiA>i z@3)QND${C5q*vFYNC)>C<_|A}sNZJ`SgS{`WVT49bO|coB@i?TCi6lxAs?6^s43t; zKgK)r}S{nf~aZy9_fxck%^gm;nRHRpt(qD{!z3~t#rD5 z0t~UA7~`k(EC;4kR3|@srSU!POCQ_3HVU+sV2*w@U?_CPKJ&z+kHBlAkd{SINu;!KTBg=l+tDy=DH>PExjl}7 zDTUZRmmY)pm~Qz~9f8(e48g%HW|vN8oNwk(7=|wtmY$&)cq~{ezeHeUF$A^9EGwRd zk2Ya%YEC!=xiGW_{%#j48YtQ^H9Nm#1A?=V5{B3G2IkJEl!w^qlITZY)xrQf$uPu~ z^!c?BkhTr*vzomV!hJ`A44d=WK_wzN(ya0fG?;Wy+dnUwchL2me%QU{1Pm&Yv5D2v zX3@WrtlbrMt!Zg^@mcNVuv11zpKfp1ertH~Tlb(U(lTSf5b=E+A&`zHO74^5W1#k@ z6wDZKT8=y<)i=_sH?;D6@EhW>>`zlxK)FcT$;VLVcP>V|u)zj*NPYqwK7?14T*6vB z$C!t$1d{LgiHN(BKBlr5+8NsH*St|vQzNEURzcB>!{NH7<-!itNDt+XNU%IDw6zTz z9GD{J7hv6LR58`^H{n-EVc8iWM8$E-Zhh5Sw)QJmq?D{B)4Zea^}^J!UBW?} zbGs1pq!*hdDp}unRYsWOj`q?i*)nqKMP!;jd=`K^`HQVJvA)aMm#&SKzZRt3aT<6a zv$56o|FQR80a0!1wyqISBuSPG22`SCkRpRl5kycVCqbg*AQT`;GN>q$5m17HAP6X6 z5haKcM9Db|5{g(9>HMS6wdUGu-@W&_=iImZGT)q3jT)nm-v8Fx*Aju0+r;Wm<&ArI zgpQdWV1n+#JNMP&Ov9<-7+4q#6sKe6D1@Dk`6-M7pTgtWb95wChi7|F5H5=ff6bkP z@}{{TNt8RCGJRdBQlFaQ_V79wvw747bYn=V*ng*39!Bj;`O%ecWPj((Nu8@qCr(&X z;|q7DEWn@#{>FsR&?9O=u9OqIw{SPISuE`|7N54TOOjl^LgzbRCf_s4d_3O^^TH{c zLD+}UUP$P~m-G_m_692N%d34|qF+NW)N10@NO{NFcLqnUjHUit>07SrmwQ;M1EMY} z7M(OQjV{Lhh?ov&TOSUf(3LyvXeP<0NLSH1_cfBjQ8unRm|Vb`gfx&MVz|bumwm@r z@of2&Hu-TLj#=~`D7A85=u6&W3EtjL*}Rk`#uU+ai> z>Sq6xX~uNF&GB~1?$f;2+1{!T?uL}bmXK(F+ZtsFYE=66xU=(p$?@oBjGBV>`L(-Kx(P^9aA6ije!OrW9#LRsNDGSQmqk}?4lJsnNG`u= zJLBj(e2`6`fyF&3`SICx%AQ~mWeSs%41?>z8b<9(ftcxFk=u19hG`TS?A^*2ho>5R z(71MSrKi%d!L=y(>CHXq0szM zDXplEtpgd;{-Q8ln;mG6aFPerwJ)Qx!-KB4b^(OzuO6ZN9_-<k@=wJacVoNcM9Q6R*Jd(6Or5-;FHkJ}>?AvU=eH8G3hfC>39PtGn#V8B|E}c+I-Pg{`rjOe*}&s?qKbS=*04GZT*u zUI}^R3O@tCs$g&%G2iGx=34?^-J$i&&017ZA_5%j%5!zM>+)@UQ6&Cyf6Hg-`{ zU*gTW;_Uo2Oxh1GEGX<$5vx)Vr>3mt-qA4vQ<6MeX3yuwzt9g4XDDP~IU3^plU=^t zVOsD)`zky<6#T1LbktMcY@Ad1q(giyIZSRNj1~3FfJ| zu=N+r&6sIjvv4y;{>?!c(8$gw=2(>8v9kkf=_ z_KAQzG|P^q$4#)*4DFO~MO#_xZ*koJ>Bgz0q_QqcQuXBf$ww4avdq<$FU)(_BJCFD zE?uy-jd343HCHcHE^tbN4o<&m3#mIlQ@`Bl%zfK&cZ9fuQd<~hTu>;Oa9R0FsBbQo zRh2|Zoc>Vilt>-5YR@Ns_bKlR4%JZulP=Li?Du5Yl!N5Dnz|FVH(+W{CLmv4lA^Mbe{LZ7aIJhSJZ9bKAU@_|O<^jvXFBc67 zx~-}%TMkn*8ul4tx^ad|Y#LbvtEw)0i;1p4-Hj$eOciPSHASg)@rd~V84~Y#f9A1@ z%MHfX5{fG825t=1AizyE&zq_1aYUnYskpw41VK&G2@&=k`hs2kqsHb9A5re*gB|6}nrd!NpL^(fgp< z`+g1fGT}7c0*-aWSEQ{34moHk`~HA_p!4!H^$>$qz^QXMx%*e}{yetJgZ$|k9u7RQ zFIrF~;joIGS(vU3IUn()CPZ>>=}W!VAV|nUr$+(XaOkY++^0e?p~T&RvM9TGM;~;P zHl6CJ`bOE13zRQBi)F=6Xr)oGjop_GUgzU%pv1f*&0HF6Z*fI5tQR#g#Y&J*OkTgk)Sxg_L~eEG4EuP@Bjj|asRkhoL{_P5I_=W zCb&(e$&7t^Q|H7&ya-YlpKKjU|I=*zVdipFPLhXjUksCx#wRT)Rkk{AE>*5iOUSJ2 zS8^T}rl9<8fE{pF0Y_61e z&wUxR)aFMEk|-q9Jo!_9E&M1m3c~Q9(FAWi!3fP~2keryp{gTGa@G%02p0?)thmO& z)PEiVNCm?I2kmXiS-7>tsv50T4Jy)0%#V0ey8hB?s1Ki%;%)bk>M>0%@xEUW;O-zd zUE@_CV0yZ2nCnmjvvWkU+L3BLyGInP`VQ5HC!r7AJG}?#Y|rW#`DjIXd;)JA@iTGv zd)!_6xnE}_YP!_0tZ%0M*9%PWEXqer6kDiM76Y?GwzRL?nWj;CKujf~e5aDL{=pq)cF#R}Fk}P>|-V%j&T}O`et9?JCae1%W zy3Vc@u4_!6mpVAos-DJQu5c-hzeQng`@Lp4-{8xV#*`1@QAi;cbA!gP#VJY=ZJ+8Q)+&(i%^& zVl5xbm=q{h1E7w|^;nxKuVzI2Uml92pEKJ4MGs3z2HH|^G z@DC!W94PlI^#{mKW7w{~nLTf`5w<;iAhWfMYk-|*^zaU)A{?Z(mf?E#L^bNc;2)fu zbKk=^Ifg&}ylQ{kJ#_Z%TR~^sNO0e+5qd$hYT?00kEo;)C^EJcr>Wb|&+uGnZ0@D- z^|h=h`jsNH+v5{NyFgvrW%yQ>VfyBD5%~#Ub_N#^`LVZb`h>oQpw=()Oes89r6Qq% zO-LI5(2e%bO3%MA+oViT7L~vT=b3b2`-Hzb`cwYth7)>2e}=B#U;DOyMmvQfuIdXx z7$8}WZ!8YdlnY$70@Dsr29rFW5R=ijTABhM9R~YuRba^dCz^+4MO^wU#)~Y9V@au! zNW!(o|FB&J9J(fRi&`!)C?SIgd+YB<>xzs-3_YUPC*>k)8(Aw#)dNw1q5QW#`{xwm zdMDQ_cfB{?@W#)FZ!_4fPpio2s(uy2V97RrT(Pa{x+C~w9YG4Mx`U~)m)}8+@eIvk zN)`hA`}I4Ir39Bii314jS&67T78FF-D@(Nf}CW3Pp`dMJFF z#+z60o!Duv>ypWQqcS?1K2oWQ-Zq=@%$3B9jg1i$X7XGp*kyf_th2La5@Va0~fMSc(OGj;V1u8Dft;ZD4knzMsuR86)C7;Fq0 z3+P^>i})OHsnZHEw$5n_3VP1NXymF0Z5l=TDP^wD{@qyGb{-CXn_Xn=8bFm+wV#dg z9!!ev4jl<`o@>Wl;0{8`CE3V5x1}Ok2SNRDq`+*UbMA+8sjZ+}jy7)AiOmn}(m~Qe zvx^Js+P-LX8nYwlDt+9DK5}$oPewnX)-G<;NjcZvuFV7o}oZ=f*9*6xp6VS%H?>`Y$&gJ8N ze1~#x$P4>y5L`~FZDrn9M@6x1;LD_Ybg7nIv-$;Be~L)u(}vZ&529j*T`JdgAc)F4 zW@nK}g5d~6ja*3>4$jG9*lzpjtum_MYzMb>4LPPPJo>tE*c?EltQITXmf%(jULee% z;gPaNpumvq0hV5gw-JkJb@>hk0F=E~s#lEf4Y37cz_{O`R=M4%f-(i$+C?dEhD~I~ z*wgN?_WX&=8~%_-;OKsqcWDEHjSW7F2gO=TD<*iWhuYWc#W3xL)F|PldH2db=(QVM zgB=MIgXziJ5G||YnB)JPOg928B5K^UL)wU7e?Fx_jrH@Fw~*glr_&EWo;t+LOZ)F; z-Z%MOWWER_J|+e+(i6gh)b?3xU4|rMv<$z>_DooOS0~#4)r6&bDv)K6yVod_<@$6? zS>j2Y+;lk@!|P7EvXn_v!UMrutgs_(L%6(1W4I%_w z;CDa3zGSk(`iph_eM658-g!)c7PpVM?ywH~ib=xxKv`UOp?P@qL3(AzQE5NiH~Xx^ zT>G$URdDrt5(Yq@xEWD*kNuiyASa55lM7$Kix0Y`nq0qPy)kol#dFc8M*HK;4VHDb zd*hGX#yMLyVb9cMc<{|Kg)c53d4>nlIO+MCqO-;Mu(Dqo+W-;oRtu!Z+SbF>kkra( z#Z1@KD(>k!`*tL;!^w%EN!Pcq1`#Izqs+KzyjJIE-%lTo9k9=X`HN1t)AjV8MNJ8D zN>CgEC#)C8%4HTe1Qjkd8p3s3dq%fotvZy>hzf7G1R@7iYPKgi)-$eUFde7N?BoNJ zK6+9pHPkyo!S?nxGH;2(*KYpoglSXO=w}p(y@%Kc6i3=sz6xKT9SLAz*f>q9sHnRB zNou<=7NJ-Zi8a-iTW6_qbaMFAg-sxne`JQ4wN`$Z1kLa$_-y@U($OG>9xIv58J}qd zw!*Feil@eY1xNNT1_PD)yA+)IPI2hB+L?#R$}-P^si2@A4B=@D^vRMyLK&_2HW)26 z@*mUIgfK~pP48vIUy{^Wf2JTxPj5Vum-#m}Tpm)#dK;2kM{Z1I_;{UNX__$YJr_&H zBpQe4RD}|bERkaEjXm6}UwfY1qN#k-MywDKTN^C4)@#Er#Yrx&?INt7UK<#xjvl3+ zyCka`j)SdvqOr-bL8_4To)IoqT=3zp;i!Es6m{if1Nmh#AF!+X=nwRq9LfhxXY3hC zQMa97rrpC&WOj(dVLSwL;ey7TbL`mz`x$febVi+vHFDit%qMU4u3q$iw78$^RZ;9k zI7NNZ_&ylDJkG1mck*~7ZLsPD66nNpu3FJPle; z1(+L{^u!;RgO3?3txNkS)UISpvaRYpXgeb)dmHvVU1!gH>|HO;_vT%d_NFAmqAFhT z)8JpFq(S?h=Ajx|&1urq^$X5C>#@jZL4qSKcjIwKokavK{{a)&O#JxMzJyYp@A603 zdsNOHd_10S1P40jnJlf(7m*I4XS@C+{BG#lC|t z*F3bg|M5?B%^wzk2`>h-DIU<70u@Kr1xR}H_ec1L{^FMLybYAr8Q#oFCv5n>It&tc zKVjz`u-I&s>~n9}^YsBXTog)-Yp2=>=gWONg=VTF`+2^7AG=l(60k)^ zaHG#4ke$=S*6N3diS%yQ>McC*Lx*r)i$D%Ezv>t#?5`k++n_ZcxwKZJ`Iw705Qo&` z3uE?r@e-Xbc*jp5NW@So!Fhn=-(DfyYZZg?7d|K=M}mk~%P?8DLE9~wtos*!MygLh zRuPJciP6anS{pkbHsAb>RARQeIzo)65u#jWB;eq*w0y>^XCZ1o`0IhhjW@a#ntm^7 z-eLd5*W-0lM`IJq6@gUp)G4)4I6rV#6*QnMyH=>^RO<8n0CDc` z2D|rMrDI_Uo`e34B^IaQvIln{p%J{c(-~U17#xHZb*wTP1*l86ENUNV>YTzPQi8#^ zt!sYuxC0H-g~~cR^K>0fsH^%HYZ!s8UrqC z{E|xRP6ko%wUQgqa{(^etOO5!h)D0H-qrj>g9&Nxk|!R!8WvF^>v#3vw@$Hu5_WFm z-$)9@fyvGQhw=T1O*5_;F3ccagiUDy?6 zO_)T-D4FaK{w$nE=pPV|(xR&xjzavOC((4)l8IKxK@_x6h7@;jf9)gUhAX_6@mHl; z!a>L`_|bOw;0pg}W2t>p?cRJThT;d3yN`OV^zqn@siObH**8lE9}SkSTSJ7EkY9lp zJWU*ZsXomR+hGX8ELK2VX8@IIp7yu_9#`?OUq&mLzEmn0?<=f3pQ*sEl8VlzBP^o| z|Nr0kKfhN0iPQ4zN>FvN(MRM>2Z!>JcufR2-~)Ha6cnM3q&$5oy}T;O*p!kJRfk9>faVdN->S>?zDEOrSsnh(XV- z(XtBVwmlb$?k!u0eaUh9F`9go=jHRrKk4+wkUpBy{{BpyjM{=4ZpO@7bxY*H~&5Oil$kDo9NBt?3MINIlA zh9LLzz7lH6niG*jndJY*p$zdhhy26atkt1cw57~nJfm=m5h7CLdG1skzO#G9a0aD2 zn|v96+{+^Cw<3ApDD|bxRmyA(CmwtwvuJYrb{&slMfX7e&Cc;#X5lgSDWGbrb^NxT z>{gmQOdQ;6iH$Vb0FIXncs^M%KoHKC>wDPtNyIHggQSgbs|~zt zoBEc2V=^)?GzeLwLITMGh90DSTCoVl(LpqyEhyPCd1)h2K2=?Kb4WX$ld`QA0$@hB zSf9q5eJx5NY(VJ00Trs?=HIpg%lAHZFMEZDDrgq}IYqFwK&@bpRd10E-6LIWX+_sB9y<<}SYn zLGCcOJvJgM!42Jm58t!F-tL?44oGVM)5sDJoF~Q2J|lSK9x80Yx8Vtf<2ur!T9rRP zN!We=%Oj^fw^2%~;}nW5+?~7-fL?5ds0tyP-F;Q|=0=ipiy)Jzt$?y6m6>(mI= z)7r1}27lG9&S+O5pN!5DxmRo37bkvY$U;NY*|Az~S7;ze4Hk-rvFMRNdg zr_Xlfivc8l;=5?6!0$jdJ~a^rRzeaIR;N#&_9xR+ysw4cK8LycE!3VmlIKl1(v@nz zy*Lqqikf!rBORLXVQP2(P3g$xItCSR83VgehU4C+s zimo1Vrg9_-EzL#N)u`#Q5L6D!ugbT(r}e86{$WaLggkayJ_~x|#$}RftO+CS zqPMS~xosdqc$HA!eQ;|%vCSP8Ws4fhvhAQY55TdM z`0wu{mP;R;3wSPzA~`;O@L{$P{6C9lA`Rsyo>x0;w6s_c&Fi=;CAMT9c^Ec=;Cpo#hv=7%qyg+h;NLu zj|ZXA6-iT{#8r@=Yz&^?5U}aw@p90ue1a<}Pzs%kAA%@D>j*tlAsxfEZaeo1otEJxMe{eN9DWl{RO2RLCk18$Q<4ep{tuLL(Wm8=K1)>EA(-oJbJ8 z0Y7Zrv$_1mT;xsCypBH2P=wjYvxiTm6Iq;z?do>x5V)2$|Hg#CDMb>R@QR(fIrb5R zx1nu$<>di~S~82d-r|4IGd8MR2B))8U%gR;AC>38vRpC*R#nglRV&=K=ofg{Th>$` zK5ru?{G{-z8(NNM|FZT4ypemm(}Me{cRqsmx9IMGBrGxU4HY(t5Ccg7GpnmNI-lZp zg$dPvpOXGtQcp2N{g5A1x$-{wAxJlW^*>Bnwx%&&&6Xb9gTd9fW;QOP7M^8~_re!Sj6>e_Rln|8^a^+8t_NK@dxK}O6FD}YD_hItIeETLCCwGljnCYM0 zl9&;*pzNtiOZEwNQy!j>I(y>2B`AT1JICSk=52l-K-_)IZrvvB7MXMFP$6gOD+BeD zc6~8Eu<&lZDWA87Ix9ZsKP085mjjttrq7*`Vj^vGQvD2I7)J%Tx4q;|5CsJB@~WAa zD8j1y9T^dB^dC4lbAKV0SMR#xQSx;!*aZ8PIhjQAPV4l-aH4C|H*v*ZEfdPvy=-jo3Az>$4B9(X(x9K z){~BJMoF*Ta-MjqeWHSNDw>$DkdrO2YF84QYB2cevpGuqk^tg6UTh7!nICpK=`Tpp zu8t}Uz`(7-nMR&#u$FFn*k4aYWX_XYuda5j+IN$kllu_oFcU3aV4G1?g~jzd%_;eb zTVv1AmYE6yQX_%X6`f|IeNp)fCB0$@wg4zfOFkpJK5}S-Lm~O$M6*mA*UV9ht{*;y z(DB;m6YQ6<|ajwY}2-`qL=WkBL}vnL$j6 zvdf2tflaBRWp|YH%Vx-sSzZ&MxmJhq?cUhGoK?Oc>OL=in|*1{rB!z@-0rHHefCkueYB6NAtzq zsVEZ-!-?wTRC7Rbo=KFxu2dXjY1H8&@uk3f#E$6~iOjuimCUv?mmQN$nUbWfX6eZ= zKAzwN5aC)_)Yd#Z@<8n9Ah*8cpI-t3(dx=hM^wHkAKZgKarG5B%;`KKO%|s**Kne8 zTtP^oN>zE;^)urd)exNpH`(KBR|y}Ae}TSCvUM%3i52nHQ61U1vQsGSOvT+o{5|KS z0r^lz)pAvDu}zlRr8N7aVQc=G?X{0=8^fqer4PDt2(yZ8VU8^8*$nd64DffORf*5yLDcA5dV~U z@TxJ`a5&rx2sr#Rp#KHkoU<7W@#=U8@WkE9b>j;NWdTC+)Od0K*Z25G18&czFi#v( z@hB;{e9r29z?ecmf4W4Bc#M;FkO#8CQy6(2DrYt;We9=%txicr?+!Rw&n8m%`y=t9 zF+0xOYE^^~dv;~QSKF2aN2xnqyIn=Qp>Oc!bxwKvvmLA%^H*g-{4=ppQ~Ap@t<(0^ zgh8K!0*-Rx@=EEX-wVh~VVnXn@7nch0;VmWb4t*qUbcxeVm1=lIc*SAo;Nf)A;sk7 zEaN8eSgS>kU%u0DbIeqKJowo>A7Z1A%qY94shBa-&Lu{1^&_&WJ--Dmb*Jl}{J&6Yev&?_|@pv5U z7w?d{hNXOW(3>r#S<-V>ChC*bUdbE7on|E7*&Uc!$7JlPY^y3g3TyDsL}=4R z`%)s**qkWQSH}qLfY`xU+>Brcv*0v>DFhg=h(4)_o(MXltRJa?-Amoee6)P~VM{IeIh_$2SbBOYFkfO4aM}9CW3}3w(0} z-TpjL`qH%YdVdEJ?O4kma331@g%o){R3H~bVh!Ik7rs(0AYwiWt3+?`0#)CzA2g0* zsP|oGaXVv45|cA?To(tnZ=AnU(fj`Mcr9P~uhEw+<*N)`(L?Z6OL5lABh7=6a1^qE zk<|b5=${usxD;dYDymbDurrIF3n5fnDxW&-q=9z!cI}dGf{edk5t!hAcv0RCu}Lur z6K4x{qhsp*ImwfwifAgNOKA*jGbmRiP$=fXubc8yl5YY1)VbBl7}_9xza>>i9p$DzDEA4*a@YIc{N zCmJ#wm!4xjZm;8ta@lOlVXMk1cf4uYH>CF4C$QM+5iYI%SJbyoM64kYABc|$!=CC& zE+4U>BC_Aj<5i0nD>==uXItWSOx7xYLsb>%yBL330&>@8UhG!N*jeZgw-G%zE-@@~%l4Ej?!Vk3fA$|@aepjjb8w)&s&0}&odft=xJ zbo5<)NQm8>2AAe?ZdGuU(~220FVU)Y4j`=`enYs5CL1>nqi}$l(lVHN`+#;&a068$ z))I+vZ;9`_^&+PM-W|jnOnmfp^dtls;wt&~6oj1J2y9-mgBz4e&lzA%2N;TpFeT>A zc~VL7rK&KyxE3iAM1C92`e=mUO3KbHR%f+oKl98rQHqy{6%~#){(cpxqlhH%_pkd8 z*A$JHp*=^uJ|g0nEB`=#lcv~73pmA}eWgaw`zmZ3_0=9y{H8)tFvqsb@}+99J^{{D zEGRwVm53#a_S_<(pYU6Kz;em+6_fmyO6jrew4`?49N6x`}g{kM(o$@ z;T0evam|as3}YJf6gxJqK;vf$r>oxtt#}sXPoxn31R^aWxp>f$hUAS{;386ifZXx3 zK?Ls4-@hebB?wsZf1<(vo1v*`W&L^noxyijnk$cg*!@W4hN+v;6|_~13tQY}9UOc3h1$n@&1+K>y*`jgwRASayybaBkXbAR~g zFRyW4e0`A30{kBQVtGbk$;i!_cMxOSDj9t(v+d4nqvhz#B}-eKc25L3VTKm-9JhA_ zZ5d!?;ZZ~<0On1m6Q)>l~>E?fNI5qkJWEu7hzddpb+_5eB-U2{EB>bKVBxw{OWKPnZ z0_kACn-6+_8sXH*oCmR9XA};L26ZDv_@ay9}ovMoYs?^U8QO)T@L9_Z= zjmPfzza1NUnsOI0zmJWyYaQo_LD2o?pD&!PS9+JstHyuu)S&-ePdD)~ULuhby#U9K z|C%UvM)HIUIv7S_P>2#qf(>OqG|0X8xs3tu0@i+uYX8H28meyj6ZW*Yhv-uQZ;Ov2 zMDnB8r-(nW+H`BXMTxw%hWiEcxAWrvCj{ONc{cGQkBs4TWZu!SxzRkoVl&GWgj%4n zbOydh;BmY|T7YhJ-{UxJ#xLeOfn6nfeW-UV%o}oP{0AWbvU>0g0^AuUo-D<&k1AEOy*lYHnj&*8{5m4p{WU4Fqnb${e4R&`w{J_k) z2P{NXi-mH1i!8RTbUVP~{X1Qo;HwrwJPKSgw^%l~5wP|ue>wq1xW^rj{6FT76ZV<~ zmo%dldN|3K#Ps<>_$jjqr$OdyX+m)Xnf*s5=oku<6(kJ!>F+$L^I;UJXn z2lXW_#1VGob3~=x-Wo+~^Jk3;{@-4s{)MKvC+z&bMDQ;7FD{YW@$3J1t$j*4b4ta^ z20>okeMmvzzGsPA?lDPd^ZqmLJ0jqd+j+qN@6Os7h9KZ$D{%eS|FNh)A}s1T<^S_V z9dPC?+`f9q5_<04IU5M_yYmKu(fa?2!(@fV-?kjJSiTw@9pS@;xbm1I= zF$Z&kw)g}K3#{U>VrFJ9w)|rWmqe$$SR5{dLo6L(;qKTo>LtE<8)OfRE|^0q@OEP? z&qdeM&BMB_iOe=Te)`syk4SFxDPGl_${;YzFAtFZx5RV=qW>?%bVOBYeph_jKFxL( z0lp-iqeuyUrGSJ?BzTSKZbjvsGZBvxEBRN7#5Gsc407XQ)GqRr<-;0o+BG=Dy+Zrd zV`_}RX-{_6ah#DL!By2bFt$)Ea{(F(f+*RL8PVpt3M7S3iRU4L0{-He0ndK$Jc<0#rV>f?(GKQ7ZcC7sZ(Vp*R2Dumds ze-*Wod(f4gM)IJLnAyHABmV7*J4vqohi|!nmeIdA@ide?lZ=e4_=va8=MmTt1HDlg zsc!gwMe*}4)zK{Sbs-EP^m${PUuDHnkgYpRy`Jg~f`+dDWX z{h$aj{7~WzOpmDh`-6oqlA4E$qnG~14R=yx>l0eMsFmEhlqiuNEzkCi+Nkh;B&*;a z9iv(vfXH+^hY5O~K8j@hTj!tl5B|siREf4+cTb`DmC2WvSYY;jfgLs#=b@W(cTOF?YH`F*)(PYB`cBL2AWQweW6eB`D&@P*iqyZt@~@m2%fO$ z*Mx4H9f@I20+Z{v6l{)41+^COnN2c=<{&iz?LvlYVg_`8zyl&W=kPQ5$jr7P1Zlha z!54nVd-OEb%FucrZsfIh_J7QEAM!kfJaLD zi-gW<#u3JUayt*24`UA>SVd0OF$aqYY{SBlynoYRUc$rkM&1j^p;P?pms1EU-{p90 zX&!8UB)8w2!uAL0i=&@<2$LwnvEl#KJ{kl9z0^Or7qER2zQ?m?6bM%R9^mm2+;lIC zqR-!;SFkUp-`~F6S|L$yC3WP^@teX8h0<1eZ$Dw-;Him>HW;yx(dycpw)|$RnYPXn z__uKS`U1X4a3l46>(2!bfYJ|w3>EQ=EWQ~k?2v;6I0z9kGA>PYzv?su;Q1O5LEbnJg7iX`v6yz&gezPQXClqdt) z;YWiRehR-jdt=>fNsg>&<~}#uL#{1n`Vcg(YtEk;dLl|$_;!9*pNYC`?SxEr=et)9 zq6dfQ{w9(T{q$I7%pViI^$1H8&?!mq6UjCQ6B=;_Y!EQ(c6!v*yS>VZFhb?TzUTw9 z4L0KZ+b8UM$gBq=R?cJY<>%X$zuId*Yn0S@(Lqs7#7U`$qOul#JIXOSnP@LsI^^Ru zKX!J-in6osDBGJ4lL>KEX9nM3@YY3+W6B#nKRiL|v;g!?1dG?tm(O~4Y`qfP*uSzk?Lu7Wd<|fG zI?4=;p9j~S2~J77@P!M|;_400Jq^Px2F<09CF^=12p=u)$ z3E@Uym*pH=7jpt6*RwbzHoazmzC4)!e)Q=1mQgcion}OTxtd-=%WhcjnRIGS~lus8Hd4*k4+UCdiOphm(QwXkT$jO9U$9qWIiZyAOBAJVsA*`n;x z_XAkLb7z_C=K#dodG-3u1<>sI!`v=YZ`HxOMDE;|-id=wk%!ra9Oxs4>!!0gYg#}9 z9w~cgKE4CB$5T>x(?;CD@TBJE#H@OO!Y+rUG4$2;ggWFgbA`HwO0*iA)4sN-VxKs9#O8qmON)4R7DEM%7m{mtJ@%)_Pgu?mes6 z$A8#fLsM{`PraQ>NWRX||6%5Ob`05ar074ER7CJz44i0()QrdRV_jf-32@3jIZR{g z@gGZxK;hm5PKxc$&U$6}&s_5jB*1bHKv40sy+xAS-TWOk8RTr}#p-Tf@>_4yINnb_ z)n~(os4#5xS!E@s&(AGnL`i-|Lu@g{v#p)Po02I*Q<+-*!Y~sD<}*!i?v=SZV(rD+ zYz&B$oXrDTgZ;!>j9;gYqDM*Q@|CB}lI=OCidt&TvhV0d8r6*~`+!yzQo;{{P%A<^ zMg*bPiFKt-#z+aopMnfe*!<@|eQivk^v`#NnCUZWFisPWJyV@o7tM!~caV%tiYR{d zhONs`Yw%Dn@euHb7}0SYWwQOXPmFWlhQQsS@uJXo^EiH7wI&!+2&xk*z@vFAMuk`8 zamn&3Zx}{=<4Pxubo8b)7Sb~u2ZWTCC+EXsLEyNEN`+UGlF$^r5q9u5U2U!i6RN!= z_t4n;AatedBA&VP+9%%x9JZ&iZDf}8@V-W0=~||Nq$JK%w3c_e;g>OSyU@r|!13a0 zd7awTfk1Dq>F}fIf@)6KSBqfVwpMvpK763$5anfkOPj|3Rjou5C>Aa@cF9?74cbrd zo1hKt2lSTSX$-u(gES`QemPN@X4@2Okq}}Z{>GMVW&o~<&5xiQH4=Low8K7Lj||Hj zZEBS{b? z&%9{2d&7Y_7e;jwUeZ|~0D|xZ@gr4gd44{dMWBYg$=O)<-E|i-t3Sq+$`r%UBv`Q7 zk-Bp-aSk8fiq5>ZUOr^UKKXpvrs+9zUHzY1-c3;`w>Nnofdp-W=ubE#6ywg(L0VFhY6Ns;$wRQRC zfCV0#kEGsyxMI!$yCICtrA;npopEkEo%)PKy1MSey>M;sjM|6kdb$RILEQGO0##ib zBw|Zq{kNSh;zh*Vd}GSOaYsA15wxGsJ?&?PmiI6AdcAz&WJ6MKPRySTk_G_YZDvlB zcP?pj{gR#DY*P0z4I&r2Mq-nH@2gEN<>cLl-FLOSMJcO1%K>a#Rfw`Mf7cmwT}Bd# zLiAz)+dHG=PxdZ_9kB?k=%%g9x_w{CS0si;WZD6-V-NRd_o_(^jg^#LFdW=+G*0vq zL~fL1<~>lCa%}7K6PobeU}OlRg;yv4P3qm&i{B1vkjN(w^x#CPDj2;E6`y*YpO z`3aQlw1QzOf!O3>WAXLY#hOXvdohI7b;EmFnFGQ9uPTr?`c&<84TBp&Ov_3&?^vp{_*>_`TFO# zS=oGRJo82bS_`g@BfBrKsoHV2;q_Kw8VirVCd+}rZVxUZUSY7}&|zK=3a~4?n^b(l zwVh8>KZI&BkU8qjKui3V=s@dvL+nu@fJ+DD$C?BVA!=9<2I{$gM5WibrXTZ)_*TQ6 zj^qN}Tp+(jAb5=)Lz`5G$cFH7zIu7Yo3dBn@ljIAd;&yi&c?{53!xcg1`?vwTU%2y zrEUbWPqt8ATQCJ@1@05SC?r^rNbpA%Dv}Y31J@dkO_P^FI+=2^nipk>RwkwZs|7sdULz`lsk4rat2wy7~u2H+3%era;?^qDyw;Q4#( zYu+4@4sS~kvH1e!YPMM~kLbizPH&|NedmW3-Ndui+9g8vF99 z>3O1U7dfs@m#=)g@)e95*2^-x%Q8fod>Qc1LiWEMe%(HNzYY*t0;^lpsklH|N=J05 zyipHYR{D0bebiQD)Trx5fX3&zF!DjnVi3R9kB#5aruXxIozIADaD5-%?+YQug}Hm) zCK(3GEPmoAtO44cHrhD*3_GdxN=j<9kLB*YXqcz(waneSNB8;73~m&2@$WUqB6~H* zS1RlE+yWBBxVFRW2WQXsy|KnUIF5gO2vyCx@GeH7W2hStUcWBo z=9&q((sRAMZOx=SDR;X%n~&<7J{#o$2t~U|Nz*S}t+nKLNl1iEfn~1z$O!3ylbJ*| z%Ii;fe_8H~UFF(3z!nkmDO&}y(;*tt9t+7NR*#8uWww8+_pMKw1ag{6f*p#?!_WPK z=>`J3M5qSm{gJ1ww7=@f<#AbYGqPlvp^X;zU)k3qwET_P2!FeA1guk%wD6cvvkmiP z4s^*)zt&5B#=HQiHaEo!Gm=ZZ9mVFpSt81 z_u#{SW=_k>;D!V8A|E}j$lS+CO-Dj=k1istR)wUH4om74akKh+PwrtsGew#@2K4&_ z9gbM0WRnn=xHm*;bA`>FI@-?+C9StjT}YKJM>zI(3H;(Ro-%TUif@eR`XgUyeXr3~n z+%GI|G?+jCS4&3M_)gSP*T6Ha&cSFAO?QqJzh`ky;nC*%&M%JSz&Y#t_gm=xad=W6 zkdd)jR6o%VabmCw?PlLPpgzvLdSF2zfRY@$Uz1w~5FtI@;6ncOgl%0Cn-=&C7TKGM zb=frl-(q`DbeEmg-P#etaXsiZpNI@KSJtil(d~wQ4RIyW?eBZ@=lx4@>M!0Y^$uN} zE2Ge>SlYKBa8>sj+r*E3mp9+?s+ZTobZ!My<^?a=l!^};falPs2k<)e5rPXSG`5m+ zYupE3QF{(YMIkltmzt2rk^+<1$Nvmc#%PSb08!teC; z>)&Y#toLWUYdzCA+cD*-mHY6-!>|e(-puE%mG`r`pWrJ=csD-UpWbZ2INzE7f^lw1 z7IMevoVRcJSOn7>WHl) z;QJXk(2dI{cO|q^TQ|udV=X~@#0NNMQhC-*4SMGGpSn0#fR598#pmq00vrBeIaDFU z#Jl3&9{SRTEc`Ky-jp?qKqYhViTijcjl!R8up@X^!n=k#Wq9$iuQ7!mapke|q(1lP zg>EfQ3t1ePdi|A2 za!57WT{Ut?65KK3C|Cf`yd4`rd$=&}h-b7)ERHD~YW&K!4C{WY}GKEU^N zdR8x0Wk9a7K~-vm*C}fE%R|PGxQlnIGs*>zc)#D7?wRl;N?r97RD)To*yp3jV7fW3 z$`lAfAZah=Qot}268{%VzY`+xS_m%9DN*>I38{+HJ|03AJZs~j3r5gaes!Z_$cn_< zDM5F!HWx$6_g+@?>6>M2?1_|q_U*jSYFoO2s4up)Uf;(xE?oRZ%rOaUa+ZpN>TL9t zYe#oIXvi0?*N#;e^51>IG5(Y3+OKe?CdY;805YGzgVFUP4RY)}@E?ceum%;S>40RO zxPjnjbz_ry{M`#rG}X@bPw^&3$L~~4Qg{vrD>{&ilOJN=`h4E>MccE<{RiU4Y0&%V z7Y(K31+%aZ_8p@-gcf%izjWcC`r2VO_VE$#2cFfcFOWaSTc^84Nn)XUl| z!FILHx?d;Ok3F`7R>Swi7Gknn$pE31rKIrM=mcsZtE&V z?IvB_&wy^`$7yg-g)R3jrJ7OWZ;PhV;Z9o2u0jc!eMB`2qfEqDfCIo6fOp0Z{py9Q zxsb?>UOi?@aU|@+^Afs#N;i3hHu~7Gyk$Q`b>=vEVha2j~-WAGH z)oqYX7Y$~>J7xL!Ip_DeT-YlKMI##y{QzEFLrj*y)7kN1uf3{|<` zz&m`9b-R-^DpbYSTrO(SP~>7g(_;#!i#n}^ZCza`{tr)!i(4BmWT@{rpXIl1zNeE< zKUN=;)P5%0!Uk?B?VKNDPJ*GlYmiZ_|6C_#erh9e6seDZR(1@f>I-8PGZjtYD+$cg zD>lzNfGBW~CFGm|tTEoF>+XbvdTia~rz8m4B3_KM+Qo0Xp zdpR-NHP7US;-B(IJwy4kbqtR_UdN9N__)S03^vitv>Q}tM~6FmwnSq=J8PO{r~tW6;TZ-OO~+|EtVuyG>S?cNt=)uOQ`G=${-w3T5 zulMuyTrk4A^EPVl|2$j;=3l=iJEvz9nwBf@&A(;NeO2Vx-?!sK= z^o)}iS5MM?_aPMf#>mLX<>SYXddZ==4Gj&2p`oFtFv$gqz*|&?zq7-qopxWtqwkB) zV4L2Z_-|pdCP5!{a zYU{dN8j1s|;*Lsgl6WPb*v1grIgV>}J?2EWyLUTeWo0+tF2EHT!8cHQ+uu;MopYvD z#ZAd%QE-M#49^Se&;R4|BTBx@qnk#ytQy9j{xZYlO|+s?J6T{4$hspYmfYJXv6 zeoh2L^2;s8Sb@1}-A%Z@SA}MR0m3s)#+c7sQ5DL)@69pfp=JN!s+5`Ie)ufLMN_i^ zVrF~kLJE0|!Om{Ine;oe=eA+17il?_2ioTxB?Y z2;-yHn`;jwiy7_DZokD6hc)9)Ki6lrm1aw^M)A+GGZv!+{9xtP&5YJ)Zi4M&WM5o` z7c%tXwVJAIr-Wwq?L`O@{#*t|K!F2j*S&dAbSooTRu3S;J%b;we@jV7BgXrvIYC2BNDB!bo2H@HuD&0Ej zRGkio{?`?*TUj^D<{+asa}y@8sT-@YiC^~Sor&cC2Q<#<8H+kIA~Yk7^chHwg~O)J zLJp6PwT-Ls%N9WLA4lDaojMj}I06GU zPS3u3?_#eG!4`Ts_WqeK;#S2GP8%e+1l>*a98D#)cN@{dQ$drBz^16oFys=DsT8>w zf>0!+YK(h|S>IP$xiTc7eQkwLVjzg*#(ZRmE;c#<0(z-9Nw?JZ$V90WmnMNr^Tjsc z%(KAaXv!swIuQv_nt9%2g*QjibF2=hbjBg~+|NO@uB)_uV9|jDDAjF7Vw90&xc9c; zqw&R5+(Nvj{mY8@IzFABtPk;7ebIjPcO|q`FIOO+KXN3!{sr61x;$OWkJX_?&X?M+o0*z5mW!e3NJJ_~-BuQQSRZsm^nDs#$un9*I zO)>8aN41W0>g&N`TOFv*u|k8I1b8)c=OCXAO6R6!xlMw+-}n|ASvDxMLyV`aHyIg3 zetMoRfT#ftw|tyWhG(XGsFZ4$O?}>HkPDMGeHUM-k)O*0{!F4E*ez1cioI97+-65F zxG^U3^q)JcBKFsR@pE*8f@`u;$l*4OH{9gwRlJ`dKA0Z;T-ee2BV#E`QeN}-|FEY! zO?Xyon+%i~x$_Td8iZK%vAGCii1}%VY{U$;?fC+DH?_&i$mH9k6-Z@O32gc0uI-c0 zedzXRMB!YkQO{#ZEl#$s11c&iJ7@Lk?ipRXb{lG|y`|-wCe>8VR~N7sFT8!3HoBko z?EOSno-{T+J$cWBJZy}(tIoEWb9L+x zk9^%`T0D&r4C1m~)q4u%D^6*nv)W5l;B~|8vxaA+sUm3H-gNP-44AN;+m z^O_Z=)Q@DH3ouU1Y_G3O@yq<`BOFq z7~X(odQ_$wg6VsrQ$8{?U|xO1A5(Ei+d8j(fO}^ecHqOOT{<9BNOZaLXwPEYfvN|Z zys*JStDsafGQui67{$(7eWdWT$pq+mTtXI^@M>XD5iEPUSiZnV$gnO_t__qo;N6nl z$g2NsQgHOxH6*!g@nf9N$bH0L_S)mtU)}Bf`TUA+;c@MVf?FjlKqs#PSzb1=C%qX& zWJxfm4F@+K?#;FiF9f>vBV}olQi0X8BR$=wR4#Q4k$}7Hc2E(~1VsrO{W3c0h{a{J zyh9Qpp|>t>E>%SArLsDa+?sV<4u_uD{3@--Jh}(6V}6ncS@Q9>i~WTntlH;xMS6j? zN3kCE#Zhtyrhg+vKH0@v+&wyVh71lwIP_OOe04xRsOx|ac0Dou!!9Htt@;h8OlDc9 zIhO|?eCd%a1tm6QnI&kPI`Dlf^6TX(;%N4gL<=0WNa)$7` zfFdA?9zaY~I6X(Bljyi-FnKz*GI())RJ)m7rvFi{^v#L`T&;d(ur2e${{s_*O8-S6 z)-OM6FHPOSs@qQr=nU3xx9wj(nV)%JKeA%!I~F4(%nAZN0o!E-o`AN34)bc&4dB2m z^Xk8my*aH>%au8N!j^R|(Vb~_Q{7+&X_%ChbCdELpajOLdEc3TjZ^~ntzGU~1AF0| z8P=w>nj_h`no;SWda@`R-X|G|V)*zi>L4K8E%AX!Lgnt+n_l$)QuEA(AokJ{VlSzm zhgSp8c0jtryKVGb`<{E|v?;Q>2nN@lnwnbB($YeGxH+$WwOe{dw!{*InYvo&XH|a#_L)?ls-Bl&-u6(3RR~pz2&AJa^}*j*X{)+txxiimR&YILEzS3|YiY4xg)Ff<4X0 z5XV>K)96v)B$5TvU0HAv$;%`c78Q+0MMZ7+d=1kJ7B@@h#Zf8f^!}p#y^igriqr{y z5ClLUbRD;;G;Bz{clXl6>%J}u$P|z!48{e%3Pfu&$L;Cm`Vk!2Qux39tCv&iHo7vq zjiw^~gQ%hLwQFZDmpyy7y%}}o@?u@0@>@DRq4NxGhJza$%E2&F#7rSw&PPThMcFT* z*kj={OyHtE=U%gr%{}y24krGt)Z+Qr-6$cbZ|I)6h$;oS2=Y;n`Fw4;g4f@_enSYP zhip9a0ml5Z;m6;q9Om;rF(5bMTv-W-Rjq@X+0=UvuR8@JyI)BA;`zlMC)^n1*wPa2}Y5ACFwaYY{Y~sbg*WXtSlt?{phB0%AAe0I zfoRUPFn*)?2e@s-3oQ`(BOMc#bS`AiE*7z3s=h5~q`+0+2~>?=#~=$5U+t{#magm) zPr&O{jJqt=2>v?Y7(pHP_pVe;V2D>+c62@gZJQ_Z^8vfIrMNhBvSYrNlvsPeYJ9sF zTq>S*y{_i!x-G|&Q&qSpAt!u!Z=I>dg1R{78M+XB$Iq89V37w+x?zIzYPJfKwXlrO zZlD4K{sJFD7e%i3kA1`J$U>apK!xlNFgpQn3h`1XiWa?fNrhXv3=e(#VsiYj1%s`Q9DI=U)%Ley4W6&WYE}oQJ5%OXSQqCNA3TRJ@>JL!u68kHV3GB{PIx5U zL2tw=6-BmEJ3lIPvI`7=d!ASXBL=`fx>0B3YFd#OU;-&tEJM7xq`lBeUtXWGR{MGE z)`!dP2nqs*ZBPbdQ8&Vk5D0`-?JB7mKXR2F=sbnUb<=NF5-Dipw}duaXil{oKIHBB z@d&>SFu#aG7LH#_v%$WmOxn92#YNU}`a&`!0>gAn&|UOHgFegdTUSmGvHRvTYHzqF zE~K)*Y|$dq)CxGV&_mAJHydkn7WglRz{Yet8AwN}*#z+Z1;O8zEhy zRe3$MVh-RmCq27SF9(IjjJLM7cK`f&>)Fj$6Eib2_7)be9*5tYMAE7e>*`Zt%9y_z zMGrZC5m9wL8*umrk&hyl@#LXWufP9#x2eA4(&4Sq`9p2I68Gbno{aed<3d-R(WDN0 z=!chZ6cIM`@bGZ^h^O?GMH^M(-lt!ab1)$;`5p`Qc^1Sic>u0DS%u~O042D5{O^b5<6e)C@ zG<)+S+3sV5eh>R#L)(aZK=|Zv)6gZ=c1@TQMk#O&Dx1mqF z{j6V!%i&SLdX`6%e+tRpHs7t17=Y*UB=;8VEZ{OmiyZ`4m1mQX0vf3qmV)$@!G9Sv zl(s2OCo#ExSPW1Q-{JJ-m}Oa6Usex=ysUN6%$l*2w6O|fx1KlR^0r3wli;**3OPRf z^^fBNU+<=nG`_3|e8@rQHbOJ728qsfg65U-~8BOOmyU>L2nwzd+uFseQCW@Y*w z5A)vfr1ZEpF49W1TJ@Yc1lgZ)lSR7d8i6Kr)iXtS1&g9Hbl;(TPN)xinAN1c8BgEu zF>4R!ANaBD0Hy^uB#+Ty&Eix zYd8Y^Z3}-814La)IUk_(vVA=F_o@=7?Bw&_1PT5Xj`86yWv_euGWQKyB@;N$X^n0` z8r<}TV5@vSQWzy7woo#_Uszd5>i!Xe8^2mK=xeu$m&@ByIgz_jOZ{Pb8Wk$|#ZlgQ z>oLsC@$(tqcSA+xCE1(EN2rn(k|SYTfwSmTQ-XTA7$yIZR^I64)#EKuu;;j4;Atff9qhQyvA9+ zQR)S&zES=v!qq;ReJpp8Vc%Io)}42l#0AjBA5D^1_t4Hie^6+5qDrRh)qt#u%-1ir zi|Bjv@7)kgN~_Suyxx>G*lsTL2$eL=x7UQrimwY#gx7U~K$lPFZ!RD-#_;FJvTCoy z|EYz}KEv{gk*|b$o-UG^p{k2+pr4a7kuSX_U&WrW&-imWDdH~Mj&TPw zde@l`cPn7o{S}*9O`4q2&uV=`4~`K`zh3WE%-ZL#qd)wNLtxh$jpPhK?D&;WvZu4% zp&IGML$qUqiu%U})|Mr!%#=uW z($*iSn=u2V&l4yn=gw^ocZ)<-80I>Ph~j3BPtW5QiW`by?7Pqzu365N$X6?q>lqIF zo521e+N8sjJ%BTOctLsUden9Cf2u(NeFS~l(InpUEf^dv<9`W1{#!$B9LP_o-zYxP zn4~!g3y3`|e5DnBZX!QYl!NL83_6tw{9>ZB{YZVn8^&eh!nrU$qjBpAhe6*{g`ay) zV&d=pe1Dv-c0!J{?7kKEF`KVmV*oamfHc%Xk3RDQJLa?M*L^n2A_3{{d9aX>ITZO$ zzaVlb{GrK*csTAugZE$blbtKkBC@t4;&5hMC`bbc9J_b6I(%rf`{6C}dZq!C@Xyzm zKfOI#H_=n*Cibvj(H8u|O0RoFuM9S%j$V`TtTGR_Fm&iX0mRiu2U?a21!!U#*k<8{ z_h_R7B&#sZwg4wYxqKnYV2lD&%R;270p&6jSnEN}M}BWmh6ptZZpB$_(dLI5pONc9 z*MldsUswB_BWyUbjh-w&oAjz$dx29IrOF%x9s$0oL#qG^V|5X{%0L*V`F2BmpEfBxZJo;>r-Xd z>3QA+7Z1A-=$37?M$2r)mSR81G1G$^VfNvQ2QR&16nvUYV}Z87mWanMlW z?}&9oH3k?|v;W2I)i-u&RI|vlN~k`2@*CVh$TMhi>HF+m4~}(diK?p?CEP>o5-eVN)f}7H5;fRVw>J{lUQ3 zbA}~Y+Qz;#@pIYAbwh=0wSqsURdN3b+Wtwp)Y)l3n|04`j#(#c-pbYSi3K;TDwfR0 z9k$UsdFfvQmTdnrjI9fpv4I|&7)=kJ&p)|A-j35V5ZXtT(RKJfUx%c0)ZMbft;U_> zGvC6;LKu$7=dYKyo((-v{_E6|>VOcZ#lV}VKiwf}C7(67EpEOj?FqYV%`FRLm?%@! ze>#n|sp!tEnQ#hjF#ix9iEM1fu(1ivn+08GWp_x8kqZno#-=y-D`(LVt+mQv(_hsem0(~EJ zJ)E9%#2r9t_%sIhsJF(j>cDvg-;<)KQ;eemo&NO75yvOFuJ5?$l_@oFrWK+}s z2|k0F;cw^}wz6J=H$nB@?7Kq9u>E+pAOZ0gY~)&JpWna14SWnggGW;#|45vAwPO9D zvSQ$y-A34>Ud@-)HFxHNpH%X_+MB|gRF?DS@q@eMpI7$pK>OluZ0a{)SC|sN9%h|` z4%fM5Z?Wlcz5l^y;Uh0R(u@oY9NWM$;c^(!ch$`B51!GzYXi23IOp}=`=|;t@cuov z&*S2Rw$eX9)T5JAQ)*h;=V#BJol-PqLDAGX=$3CpN+F{`prk8e98X~xiu8kt)~P+i z8K|+g5fa?H6TMf#yuNPa%h4HakDIx@z$o zXiMGjcVqh{cEkB~EVM<+5MEe3T|H#&ryzNX{Oxo}bX9;H++^a{D9b7H%nES> zf#gd9xelZk*Kd1z8e1ycTtyVQO%bT(e$A-Gfh+HzRYss|{n}&dq+Gb3Vn!>N@OVv| z4DUh!(|t8ziIlEdCno*Mol{U%SVWLVxrpfQUq4rNeE>2Ycx&Q{eH0pnxemH5L!w*v z+}e@wiU-f3i?cv*i>%wunLFD6*vjNRzCYrQJ{f#^<0&t-n90SZ-$rIu^}2SOGwo-R zy`MlO`FEfKfwmG7S0NylYF74eZhNUZc_MF0OgM5b1vYxLb>oAvs3SiR1Jr+v*B1Gr zW&Q;P`aO{hC7U(dK~a-*9RuG!Y;#CBi6DoTBP=;1J}ren{I^dj!%g_EK%~TvHw(|!7RtLMz*O&Xf0sSHh8m2?}FP%D8bcNav zDj{cZ7JZ`%6C#h6k0!ecfjHAPvC2HEXrtbxk1UIG>FB)~s~vu-zghP&c4mfw zc}9Dw8}ftz|2qYJ1$a@IJiOWow|5u_9N>AbAUGlL{PNieXO7;0DlHPt0QAMRI%b^oz!U~fHrzQ z&z-n}`Ct@)Lc7}7*x28>lhc{+Q?ayE)Yaa8qtEPf;ep-^cP{+J^WkW9(fRwEi?xe3 z_nftJtL)lzYg;E9`<8qQV%YX0v3GF4@p2BTzt~hw5YHE#6}%^-8{rqsgVEzY@9F@l z8~T*E5jN4L3iaY+gJpy>{DY2n@7}%PMs*uY&HG$XaCm-E{PvPp)d)+wmojJ8-Q-5; zop2p*?+1yyVtq=Jaw1ik^Yw6jNS@Sr-dG;eMxT!bT`Aki4@2+BF3HU-(gmb6P;u!ucj8I&VG_ONI3JO>ChUnT)zEco0jCVWH7b!`A1Q%D} zuz3uUPmBf2%J)%# zaYcGG$Mrrf3Qn*3QP?{tw*YL>y^9KAFDK}Q>;OVlYb`kjn7n{soX^q_B})HzoFVIQ zS6gBl0K#JfIZalHC}T8jR1SSd(>fCgpc&{}wqjY;9K&7O_Kh&^;Pnfe*C7Bl|ISo? zYn!}N_Sx66(Eck)|H3=V08IodR9CUSesa2fGljB zqG>yp2mJ_gu027Q$(X8NpZMt39cI8$v8n2G$^+DrLfBfdqh5MX$wiEpMMHLjF2D)M zYlS`~zKI>t@m8ceAdMB$Ueo3~NPVc_T^j(%`Bxop>u~4Ac$wTo>w>g#+gqvvUd+Kx zvN~&r`idSgFUJ1@*~zrO)~nb4EbM#0_0Ua@b{TTxI&fF}B8?G2@q<$_bNRwGJi*ga zUDIPQVGhfIjRC5`|AQO3Lvw^scxhFUqxZfe=QgDtL(vC!>4o!#fIF42eOm&`KDO#%B(T;BYvgsG5s;ro1K5MOvmE3&dn zldY&`?YYe*`X)=oczoJ{I3?M;T$X^&EROQBhFX?-Ro)+we*Y(!pRWivipt`S$)#u{ zVy;{eLU>~*t7we+CuFD6=O?~D8&e=PNekAr77=3Vmrp))ciMLuokcr&eNginu07Yz zNFxU5IJTdV<0=WTN2t63CXUXTw?%_xyR%>EynO|N?@*I8IZttdly@AJ%Vvc2^snu^(5J_xCpVG z4tLUK+S%t2@QB~4$0|&^zYMTdy^SYC;9z;mEX1xzaYz4@3X4_~A%%BhiILHC%Y-qZ z@eJB0I0&2n6fqc5zL_;e-(@ez`kH-&GFM+o)_6WyWqF$G!*m&E)bS1VY#O8re(d=5 zl`I!txWHHL=^4*Un88;OML=r_Y9WU1G6Y}~m5tT8KE^ zU!G*-4!usM0gy$~y(Z$;k&cj`#L)InxC13C)hO>p#JMZhp0p{myxiR3EBg9lF}k*j z>gp6wUP$$NcdEih6ZrpgqdAK~I*9=9EX0-j+riWl5}?SN<`2V8UPj3B$L-dvY*>h# zE@@~=_&tkQbG7g7gfPF~W%{#*v98IU!k#b@)ox(8{TbeN+qc0zuJWR_ccl^gn`*m2 z%3ym-hf6Efj)A}3N=+@xj8OicW7|f_)v@hurQTewTRkDSx061PwB;KArnc!CIM8R- zqRl^U9jUAcXXZlQj(C$}ye_9FxzQG1_cdTxOL+bdcngIp%NO3}y4W5@C$_<)?G+^V z{rd)!I{^FMdnJ>Vzz($oCPF59tiqDcQb9LOjdASM#NlU#E{3$ zRbGL7!-d4evF=%{=Uj`V;^fYUE41(xN4IXL0NicFH~yO!I7e(Ch1#eM@Ps=~`5bDL zyDBzc%$!TtRR({5jVhAc9U8>eLNEjt6RajqbXOV9Zxi?Xnpq)lzHs+wGEl8I{Es`F z^4e|TOQP@dlJ)Eb;A=JcinrB1P4@by_9yv!su1uL#%ReL*S#$Y&z~RtC_S5SNa3K5 znl=m{K`r}U%_BHt<|Th|l`#xdBr);;c=@!eoLN2!10v3409S<1BP?uZ32i+Qxi6ii z0Y|d4VBOm~;l5*o8;QbfIkz(rv&($J_joV06Vta4$c+|mS0p)dE!V23BPZjW&Mx#t zDMLr7%%`ic)B0_>?FduLGT2|7P11G1>T$AcWliZvghvZYmzT~Q@n#ZR5>6)19Q`;U zzf>xJds<*3-zEM;`(te9c0x=OdnPJ)=qiWDY+h00+x3`sQyv0e5-7yZX43=Y3R%%{E zepiHcp{XsS+|~Q>DLrO1)yksbh((OyM`-aclQQ6x60Di=YOe6rp4eSF$UKb&kYm|? z;qhx$YC+rU-G z|7q-dd4xa5mh|RaYXQH{a!NS*XP+rFq}n*2`=OELDl%5A_vL#T92hlfzTHK71^M#k zg7a0u@7vni^sKUz5rCvR;2_$wG>;2%P#@1R8I<&GHd6f##%Amq=%~b{>crbzq-oj7 zUQjeIwC3Skibsx8oOJJfi;QPl8nh=R5{6_Qjw>3n8a^1n7Nj$Orn`DG^1R2qCfdAY z7nRx(xOj50!5i;EZ%&+KPLP;&#r>Nd9K9E#z4sLE8q+%Z^THN&1FD<%g4^UnA$tK^ z&2iGoGKnGz60br?H7uLd_Zrgg24U`)S3kd(nW=9j0*<>)1J1USoM) zH83f*HT6a3f5Dimv}bg{1|0{Zix+PR&PeCV_(-6CG!38JA|kU;@=Yc4;~f1;G-_&d z5(VVoMF`*TP~SRdCXzOdxyuXI-pr9n z9fy07jE0q^2A`ul7z-3P?r)9km9l;OR@*l6e~Cn@3OQWJGFiiG;uDZSsl_KM9ed*ix=x0&fU`1_s1-;ueoLOywL$U9g5VC z3Z-sivCnMo1N0(Dxjh-MGuqNd8$1~2eNX}oBv#iJgnM{*~)F>Hv|QY zCxDkitKX4vNSRqFGh6*C4uOr*@3nl)lGvYYS&^5P!Ine;i`sOp6Oqzt{TnAe2n!w} z=HF}J3~=17)zEs^gDss{Mh^C)ifWPmh$^0}x|KSqjUUwB&?UAP;bZ!u6Tdu!>2-4g zL`4R1!`S(#TxP}D9R8xd^}frE$8e;jI#PTf&%H8u7glzeH>rYR@Wd!%F>&Q?9vstr zHu~-4@Jn1Cw~kzh-mGk^>@_*!RWFXZ=R;eEPU>xX8~)6}2o{mbHgunm26}%$elkCY zO#^6spLF=qJqCqwj1TGby$k%_RDRa{r8hn>lQBObgj@KjPq=sg=(_%_p*!gw#uCau zCxnEAg8o>h#66f@VR*0TIyjT2Hj^R(L;AS$HnYpB&q&pqxmCcfa~f7!TSxWTusC-L-Kx)dVt9 zGu__Zytn9srmcaF$Lgy>{w@pA3GL3PBBjjr`c8^I#QDs@_38-mME_{^1?P|)KzST^ zF@fP(O292o9RQ7;ayALmEF@f}Bcw{6}Fe0X(-Q?K# zAE*<59T%FX`LGA-Ae;W^ew!@@=E~ew7fbm0YB~JQ?;Oy54!;w3K$X|L5)Qv<*Q2Cc z3CmrCi4&g~unuo7pjM_(K@|0+GWD}okIzZWn$1hQ?;e;<;qn}HsA8LTW-g9|4+?1P zn0^#*@mTm(!riOVvQ%YIaFv zTnkt>0SWwPG(8FJ%)L#atl@x-B3}|Jrr&Dq19VhT-w2Bowy|8(8xFES+meH(S+Unq zWf?>_8UB%cU1wN?P*hRoRP9^4H;s9Rt1ypU>44 z!^~OTmD?G*7s#OFx`T0Buy>oOQz=9*K1QDrO)s~=Bi;!;7NRpTB_a4cdyFVOzAny5 zO@f|ceblDvS#7;qLLxA^n=&T1o>w&7QfA%SziU7fs(`rCVQDw`)mY z{PhlZ+i75^XybkUx+*nWYw>$SPhI&ND#^j-GXGxKPFm%HoUbS02@l!dM3r(cV|=k>0)}zP&iG@hze3 zRX~imGAw$-0C!;n`5335g*B}SO>Mau76tg0?Os0YR(8ux=;grM1^}gSrCMMdSS&cl8Efn>#2WwDPE6daJE6xWBQ3IUrK?}*xz?NcS%0R`+ z&wSXxizi7JPb`#stP<29F`EE3E7i62Zbf8~$r}84&65uKY&lr|yG~qAu$a|?M=o2u z^fR4#>xsqS+QX*^Wism3R0r4zwm5I<=cYK}mdCJ(gZXDi%gA4<6hvRif6e6Z+{*5} z>B5%7FHVfINuT%4=*u(-G2XA*Br&^O>9BO_qU6rx+%_6Y;C;^#zNNRE^w%8T_u_Jp z@xMY?!zl&o;%4ex(D1u-Lt@?p;~U`hPcJktORZ{_R-TE(Ht8!RI665gT!6gZ=X;G3 zID=*9$=@lC&BqEuD%;LD)E z4dUzr3R4d`{Cv1``vWddop$pofSFz7^EhrEap575*!ME$^BgLjDZ`9zrXo)=)aOIN zF=7T5!va?2#}E1J4kDfzBHo%NHh4eG?@>lay#1i1y~}>~aJ9mTJJkw)s)GUr>nfiJ zacFTbh&4(Ob-Qup==>kTnxhpd=WyYjPT&i)^KfPQpTX$Em{#sc1yz0t^9x}oM>WGP zFs2Me(TVU)-0i<``}^M78-DHKpDlRkVmDs)J}o}7KECq7=c_rij0$oCt?Bj4^@{v6 zl*yW|GoHIu(d{!Zi@Q~XUMq1YU$V*&#uyZppmay;t(d?@{rNxl&^`g55BO^2pZ~zw z=2Zx^E11tP&;2B1e7buZFBdC%gUgpx8ey$QwR`B$rI9$8eRir$bz=Xem-Xwto-nWI zx0e)FPX)i@7IrEN7WB;TAbJ!!TA;+YP_Sj2-$`AB?GYExAB4}r*p%(C9e>_m z_2&t^PSUVW9HqQ$trKV0G?$-v_X!KWL83a7`j~$t7z+G?*q@`8Ta$Dt;X;=2lA>Cb z79TzN>0)$^L7sERzOR?wKeM@D-#vCwuh(nB?`Z^9*w%&H){mCGnxW}g7P0eme__l% zih612>8>T|wTqv^*cY3*6ELy>r4%^&n66bk6C8zRWTIUNGpdA3pKcBorfu|$v3%>Y z>9Nq^O3BzNr^gWwg~>cu2L+amoj3WQ4p*L44;((J-IRhE6rj{-hRqQE+Ju&v6&GDD z+Yt#WoBRlurHlK^52;Ps^3Xr{eLruJc7RZ28r!@wX;v*3G1;qldl!$A4zaC zF%MU#4H?(oc#y$$VGqHya@UeLKX;-M{}fqNV%8_GN)q(=e!Cxsqq^6n2hT62)-7n= zN@5?7=ry`qGaOO|94BrC)ztcLN=fN5#Bld=$tS{+(np9iGht}Ku!dm@Y?ns_vLzo| z%u=(2%di+?AD6R?Mq<5!6}tp+krrW5q?&#MT?DB#?>1)|-V(NwS*al`X&+!*9`U}G z_Lv;whxvZusKvF0zHAfu%H;rFAPilhAq@G-Yb?4@5qj&3$G@J}ES1Zqz~Fe&##$H+AP?rw|ZL=Mk;LRRYssG&=k48-~P^_KIJ~v*9Mk6=C%&Jmzm&hx?^-{vmCo^}O%K+& z`eytgo_|9*k+wlap@uhG#-EE@(QDY+%Sx;>NVXNU`hqvPEoL7qnGb(JF735@nEf2H zZyla^R(@6~u$$(?7tHbfjh0)m^U_y+ymJJ(Xn%mPg_N*!$meGb3i}&I1T@5*L%N^I zRw?`ptXB|KIT?2HQ!~Td73~}!jyk*{`q8{k3|A8W%WN5U%1*p*yLGkGS&hWn;pVl8 z@!)R&lpn&yjgtnG*+8A#lDOor4$W=F8t)+a#fVHF+#h@xWXw<@w<-$t2RGax2hlYH zA9;dO2^D*1H(I&B=Hcqqb0dnlRkgjb*@wU5kEu;AlZie z4^ra>Nb2^SuH0x%8SahZ`%SMrmWjgl*cr9^&|q6q%9TU+>Gn3Y`SHfgtruTgT9dzi zU{mixGXE5Jwz}n+{ER){Oy@0k%T;C0?pVqQJZ3jz_QY*=ZV$0anyGnQR6#3^nxD0c z2+hGX`jjOFdGio~f~I%GSj8dCmo13AbiNvVR!iM42~S1So}dJUs@P5YvjO70G(OET za4@V|+8Rw8<`Kj1c-&4m8rMktj^Wr3$G0QVp7xhUYy9vxr~c50^jg^ww$UeJv>4YM zsD*xof&mHXyd9J}N;8*p2&K#9^WIs#{^6N>wSa;(&BGKrTEWNR@n)u=JaMd4aa#Q3 zgJoHZbz=Z)!l<7drN3UUKqnT_@ogoktu5D=+-l@K_NYO zNP&`Ml?D#RhgH4IfxU1vGE{@KyDg=Se5CCzCrYrsJbHm&P-vWtozMIE`5aDZtrr7a ziv4BfZ2`I{&gfsiWboCiQtfh>tQQYfpL%kf%*Wcfum~)!nmt`Xt?D|6_AjTJW2Z0* zcM0A31{O4`|M~FA0ph{@{J~-`_dIL@P$UdQdo076QzQsc!g>0VmwtNz5T{4&w@Z7P zgzuRReK`S4lis(~=kYGUYN2lzojwFJ8h3TYC}c2X;myYRg$CU*+RU@hd_p11S3g}n@ej%_Lhk;2!5I(1?QKZGmJ zp3^gW*B^`*B5U4edmWt*HS{XFRDl}+u~E_oH3MLqbKNctceuE?CSz^Vo@XkOe*ouce=x@sghFO_Cb%5=y8_p@_m={9Pe5>RFwhWM zQd3gaU6SY7v!b;-{z$jws>IfO5LkB9CSwpsK8R!f7N?26{Mni6_Nm=meQYj9QBA3n z*#(jqMf%c+p2vwWkd+Zt`}}g4&Zp4U0zN8HV~~7_nTl4Vx05=@9auCc@uRPT-;A0$ zm;{y?Uq1NH$7BA3sAG$Oxjk!LXz-5{Y0pxkKM)Pn_tP0n3Z z)2dS$Xo;Z~SICc7vkO@zv3MU1o#C?aDOqnC*=PSL9?G8T-2W>|opPJ?WAc{QVhG>~ z08ErY*RAO+CDzX89|)VWMuT7~H1s zsV@lLy2n;_AfbXUz*Kxj``WYI*JnWY^nY34x}Jmx$rAzbpOLDzMxb8_?x4K=r{^r+ z3CMT}I>d5wS>0vHs4wTu_l6*T1S3aNc~w{a2+m>2&>I9a1YAoe%GB1&tAUlBDdLTZmoT2NX zRVl>hRHD!MlS(F*iDo3Z1?45hy`QLek2@ZU_=zBd{!9(6>@Z4c=>t{wslRx|@!adY z4lAt9|3S)gNCYN-TRA3n{Kk;{V&l4rpPm+dW!>Gv4BVX$Qn|;%u#C>O&xoA}FC(Tk z3^*QgX}|?9gaJW5$VWpIZ9dgm7lp2U4@M@b8^8NmmAh&5-I`P$qvd*HkBre;UmJqW z#lK6xyz(Ejw}!Vlnta~j(6v6t{?zA34m~qAU2@7S(Kc6yG%Q+~6)I@(b_&I_j1Edi zV5TMzVj-k{Ibjz$RpVWU>p<5g!iQpO5eS9ThClau`S*&d;{P^F{q}p73Vi$uxpODy zRJZFLk2|;?`&{9&^2yJS2%QeQjf6E>ZXyAXN(Q2-$;%V;QxYpQ|jmHiK@m#u{WSDR1Pb_k*Y;&*@Z zR^JNOC+@@+Xhh6|N`M-11t&-;`y*~&S<-ZqG1%C9NqWP1aw}_B4%!A@4?_vYk?l{o zLeqaqdW0-k0rA`C_^~7q-A{>l;0~{6Y$-=usNQm!)RSZ)& zZ<#y9x1ii@@$g*xv0F;V#;ngj)PGI+#)>n+SO`W?u7T7VP|Ry3tvaM6W!WqUA!NFa z8LJMq!pam7SYK=%)a$$U)6= ztf^c7=OPTYOlmK(u=1>(W%w!)5oEx!-ySRMS7v-WApV-BKeD3 zXmm=TV}EgLf%$TnCEEXY9~ziFX&u7Y{6|-jVAgF3av4@`AW+(Q2%bNIW(9wNqWPaR z((vRE(s$R1r64x;uaqv zM9|owj9b98gI!CKbu`}?W{FtWu-pWaw14aVH4@M3F{b*pDl(l9(w9OO|F=c13-9UCzc^E4#nG4SO~QNHx1|}^3G3wNJtGX3`5kNPmfe7< zt*gsyXsd18X;npq!R69mw3~E?cPs;zYJNMICLshyp4lSLO4Z40I6I3Xe1y!rCN9{C zIydo~x;Pdb5J?XbAq@>#=6(8fuyJUbYM<1oa`R`vLJga0krH0lI5cnK!Bv$=5Wr6^ z=GgHIu{b^cixt{ed^t+r*lHXK`7zourp@LWR65)Y;-Bx!E$PVwEwT!b9>;ITWq z&$ELXpbM=5t005@HC<3YFrSUSRTSekn^{wOi&<(T=5)M_Qg=6S!_YQIRcFpln+Y?) ztOG#e&s_(D$qQOx3*#MRBxm}frnWjHQ}m_G_2U_n`;NX1mit_l;LTiwkt+07_YvNB z$M)ZHid=;d|FL5ok09g_bo^5{p_ctCLbeYdvS4<1v$ep$|vimgOXN7MWpZXVjymuJ}${h-Px8K zRTBJPI=)rQf}H#)S@|cSJGDAB4lm-{EXx7|LtCf7c9v^ENVNZ17YImRz1VH<>7G>zYAV!G79Ez= zw8!(35<6?1;t;aLE`_qMN}C?%~Ne*oH%o+2W2R9d+!xuj)D;v&E$`OqL~aw<$sngncEx=e)KT{_kv6 zuw93*Bwbcc1)g=;|Ds_$g|k_!lq5(^;LeXNtO%n_PiGljy}D!6dC@%&NLtT-aAvDz zY#&Z_m;`ST#bIJN+CikuX${cyoJO`a=eEN_ie9x2ID7Ek9K2dlb{E7{Dud6 z0d~?eC7IkQDzNju^+4i^B?QzWg)QM=Zv$>vaS{X#JL0wRk4LV16*7VI;MIEX6z2QL zk*Nefg56BNQ@F=98?aJSk*?rpgc>2n0ZwQ8HH{8$F-BJ&y$U{dT87rC1oG6XXA;C_ zOfz-dTiKBzg)5eG6QbShV#gUaRIcQoA9_`|jozqpir@9quh~SP^kYf$6})h^n1;NEIfw#mn6a*wK7-Ng}NsLAEMHwVh>ijl~{35WiV@t~<*eX-b1L zSuS$yCasI8c!9;>m`YjWVv`V6Y1`~;BS@~|z-r3vZFX31H}SLB)&LNNPgjolizzVL zSY+`p^XEPBAYQ?zw64>J(#qwu>Oa-O%lm=T_b1<($R)c<_}lO$KL$!4ddd)t2Kerp z9<{mBaKAs_AL)QmiAX(otkcCJ8pYlMu5u+%=GDfK`qF}4nDas1nPihu%J~YCoe#>a z4Qu!5f#fP4Qpj;(#Pm}WIxzG-?*uNjaRW464;?Y%#Dz4aUbD}UuZQ=WYvQ8VjVY!^ zL?3OTv@F8Sb%17^8lU@{KFeGhd141l_zobZ9f&I@ z0@c1mL@{dcS$4NOW`LK=N#P>Ae~mwq)Vrps-+yUhi}x;*^2CGY!O3dFq#<+-}4%6*LA($-|y%5`{R4NeXqaf zs%Bo>^Lbw9JkB}yLj`D4gX+-zmG=~mkFjUIA&uQdU3k*#w|BZixBz7LdM{LMIA2iy z5H${Lc(-_w#MDEc!bacONi6SO010!sYDiwV`PCf?Ac_!7Oa1OPowbtX z8<4SrAjk>v{H_1cdangAS^}>Tw>@?J)qc3TdG4esvtF-yE~{tG%>D>38tHH&AhrC; zs7~Q{z%nVUKu9pUKLm_*h=9?6fY367cd`0n-+PRtBp3aV>ypG@_27wUkr;mBGMmta zRIeQ!o{Zi4)4UdQztNklu_cJ_wr196;M%5(pc6trkX@A8g;N_XzHbl&*0p?{L41!`d6*b*M^)pWkeCQ! zZ7Q?(X(+u-1ife}pR{Zq)sRq*EuOi8bOp90VyKA?K3AUV9`68>#veqF$$i%4jz?iJ z!7i4n6tR@ZHv{v$pYWp^zob@8gfVX}fF|scby}Y;t9PAM%{@%+jYh#pvA0M=0K zg)=sdwBrMhRfJszMt>ZEd5mpB384Ue8U5_Dyei?i}F(va|Ph8 z!cOe7l4lt=s$BkJs|nKo9y~Ea@y1x+i zvvzzNvr%~6J%EKk>&jP`hgQBNZBIy_XD-d|`f-@bX0XcvZx){utF~i5vs<_4+OT$1 zRu$qi;@GbYuHqkDwuXMuJU-x;Xh$89iyAoT*c%Uw7RzAHt*jyEG+SJ-hlXWjB9*D# zUT$@uaNy)Yqh*)oKb@|u0Fz*S@uL(P8jcpzWQZgkN!|YMPI?on^$-zsp7c9p?e7A>8Aiu0(viv7p!;L0JlcO zQ|K?`yWOvZc;WBL1EbAYVj1}CHu5!xC=4F4a?#)LoP<$XQ&6hokN%B!OP~GEJ-pXsXbz|E=`Po7W4t+I@S`q96PUqICfO?O+9>aL(8@TQbZ3C%w7GybEo`ilqSJ4{S z#rNJkD3K9{y%x9r(gJtd8@T0@%sF;O6R1x+7(KYb21` zo&EE*JEkX29F|v1n~2+U{0My>59LP)jzvMw9vk?=&un9=ufH2FGJ}T5jv-K$1dsxbc7xQPxi^nta#?@gbWV7$q4V+J-AnI1E=L`F5Nu`(UGZX z85w+swa;^eJ0nw?ICplB_HQ~KhI(sUVcD*j2T$Ol_-=>BjKEdS+q0sZ$?t+BlwMuX z82(n}xdt2F<`=|?y1ZMN#ZFyH_mj3G#mGR-v0%iz5hypF%R+f+F&I0{+2MiH2huBr zzjnM&GN}QJv2x{q+l{crm;0UW;~W+Ci4W2;EF^B_`I^`FHFfi`LxYI_2>lh%y#Zq>ImFQI8~3VY5j~nH3zFP0}P^HUAWa81T$suoeq& zMAXyQnT(7|VTlXS&>9OFM$Z zZY?CinxQMJNUlyRmH@mVRA}wZ{m=)&EAB0cX9+51UGA+8IU@G zg8{i4JW|%H_@&~q%&X?DAhL3d=xvfiV?Id899u2Z7q5y2OZw#|q?fY1AI z49s>mW~vz0@@=cU!aSs@PyOVwmxyNtMLJu#JIL+xBt^dm>z-BbGD=34LeC``XrzNj zldp<-%vtgkO=M4>xYx5%hqDnP7hqdHpnrm7j(42+|G_&t1svni26eX>e|JZkAoq5M zzjl0rerAu#)usi|g>m=(aSfcua&kI00y@G85dkEKgL7E~8Cq+-enNluYw!H7tTRDf z*>;B5f;xAfsy6=CMe0K2rF(ac?js1CGB|aRAk9^u$w%9L<#_pDzp&~WM2qX!Fqb}Q zjL$J>{ptE&#OxBj`8B$Yx;=CorMuWCJn|!~mc>>C5!TcX$b2?Uz=~h4s^XEIY6&5G z5p&vjpE%X~Qnjuqm8j&BG{imUcv3_b7Kv>Sk(}2{a#EBomU?qgUC3) z*Ztz-7xW?|#5WzOCfQ65+S}`*lX#<6e*$eWzn~!IS>X2V+x_*dt2=6q=^wP2T8lfR z&NHI-8`8z?GT3j4Hq#gTn8QQ;qmy|my0Ndrai@oid{(2UE*+Gs30k#!Lei%$5k+_x z@%1HU)#RSPd?NLBXTVTCY}68`DZLP_Hu_5f&Fkhq(?COGpU`11Ee!v&1jXwU0RmCq zPmXC%E{OO_gdv)8t5{RaiyE;;r@ll~>EZ3;P)t3K8HLL+!m}zzYQCRj0~x8Hp-mOn z%2QvGBYxf|Qr||Vn)S|#cwqpBs9v$h5cR)o z&klGk)3lY+ej1JStkiqo*{6I*w%=fvHepxbEfU*HIzX7UQ~0dxgro*qr@f=l)ouwP zeKp7H-850U2c2FtlDesD%@h||106q|ldRfq>De2w@C1_ek0R(d8}s1a&?qqa?`-mS zb=GwNV^R9!PIj`A@Px^IxCh>WY9DX9PKswRa-nC}=GE4+KU&ySG1=IK?c}oQ#BGG_ zuBD)$!P}6VUaw3ZbuRoY46PwnNN11~H(KXm+pEFdZ{{u^#3UU@4|v*~pGd@@ zH&sI`%R!0bDQ|ZuNE7L_#a2<5d&R(a17}Cl*Xh3FZPG1OPV2QaK-&E4w#gLB?{AO+ z62&dl-iKsx!49du^PcxX3#iWD5qBy`h*mN=t2enzd zi5g=$%}cu8MLM}5gbtU#=w3J4t7Rn>vIp1DmXj}7euJD8@x8?US@$5)t=B@(obl6N zbV(Se1WbiszJcRicD3Fufup!#Uvqi@;q@fA@2|V4OIAaBemSQFrg{oj#b+!EC|Pw3 z?gphH0gt-cIepl@;w-KGOqXnc0cpb}pl=N->WL+wQ=eWma$CA^t zNxR4KDM5WCrYP?8-Gus}@kzFsV`yulqf1)4RYd58CUQX8=*aU7_h{VZLd>xyxwku% zgnr(NYj3rEYY>Rt3X#-l=08qn|#5TOB1@E2n)^4`J ze8Cuf$ou(Ns2NAFLE;%Ay-W6&DDUZiZm)zMy*G7f6qjfAy^M!>s<9F&HI-!4!a6pI zk-4AK&H_1|EcD_wDh)Nw;_C6#OqVY)W4!|XBgPFJ+UJeg5P==(&YDU@r1(=Uzwp{K z=JIEorQ{S^LIER~@u?@^yFtg9(!>xB*!Ps>1GS~$QR^3_k`BahIX z`l$`XtvbT%PWLVZoQ}DVjcWL2tBO*Vk&m{1BI>ZHRnZAw(Tp*Pm!WhKejCk06p))o ziqf~QoiDR8%&I+l7|6+sLMZ>Lqd+s>_~F?L5vOd`mRrz_Q)uMyV^Xblh4Z;RrP_9BfC`H*Xb zEen$R&d0Wxf&*`{;B0w4hUW9tHG$Hg`OOjmy9OHH9sj!P)5K#&SD7c<+I%2{A)MGZ zuHHvM)ow7X$md<{Oa7NwJE`qi+xOUj zkh4^y$CKxuiV;*Bfp^QHHtC+&f&iT?6R)Cc;fAL9{$S5*=3svmpUDi1@aOlyGArl!=7--#9XUgOk2!d zp}b#`T|3)4uM=v3Lu%oDe1GWv8nP$NapjH3&fwNZT z%OJT%)=%2pL^kV*`+(hKulFG=%0_IX@8ay2Zl)O`HbWc9L7etu3g5Hc*)rw;_@}<_f)u(X_oMeFptcok~eT9x<`EO4p}kUOM~u zU!k!8{GZff;Q)Qhncjj>YY|>0uyj24`oq!NV;Z|o1zpvJOvk|y^HS>|;LR}ntF^@Ir~#HaCL>X&QQ z$fziMQatpBFEnEb&(cOC@&u^dYs`R8D?A&5FUT@R&v)y=_%#mb1LikWN@w<&w7xRB zwo!F{Uc$*6ur>f*2Uc`wGpWP^2zsxUx(Q@5!fuj+9X^(^#KP4}9zfL8J;$m8apB%l zhvG(pkfKbR8H6D#ajm#troy6+f`$w|XH?2fiM&tbKSkhAf;k)ow@!sy`QruuVrZA^ z?)D&S_S>!fHjIVBm9I&0&ezrTb@dhnBVus??|tZpat1Ig*0p|jKo@f}{NcO;9J%4b zmv@o~fJrd^+}r+_HqOq@`d^+OwS{C=_sB@9g}M1sC3SAC312hD9+`V-NS0(5NNO2u zQ6Ff8k51CJE*@bed4QOECNn-O-XZ-aQuG(Op+pq9yg0faT?;ZPNXiu{`Y?i7Df`F@ z<^#7sOQB{msnf-em*UR?5dw+PA-o(Xd*F5pW}fl+V(PQEp;{Jx>LK&J9W3?c!}?vY z5+7O@N@oLvjAp}L{Y#18Oq_)pN<_WOjeHM7ks$ki(4uJ|AV%agLQMrC$;qCVNciXp zECfZ<(9Rpt^uv>!vkF?Zfb$&wd7@BW=u&!d(jKW;^qlGDbO$is$#eExPiM|;t5+Y-Ghnc)C{cRP% zadadTHA8%Td^CLz{wN5HOz*ScO=ay|Wh+eD!6EjeJ(2QCwC6jzSD@>fd@9Sfb_X-^ zWr`rEuDae5Gh#Dwwt%7*K|}dp)RW{<;wmx92Mj{^n~6lR!E;KOx?i6=-|BEQ5>axH zGGve%ZuiC6zWkn12^DPhK@8Ud%)IC8!q7K35~!ikExOG;T^E;caxwY)0iPEgvTlap=f$A5btKsS z9rGhqcsh;Y>pivKBwL*H?g6Q`&hH7??<_`=BV;lLKz|Q&>_qC?^EpbuE~{3a`MQXV z*@6rd;h8HMtQ1mSb}SdjZ?X4uv>*lGycQ8@K{vVxMPEZ8UV&?945_Udi^UON3t(uL> z@}rBGRU8AE1@d%~9%*)$nLj9Pi>_o8ult>LFDgEKR`~}!r!zn7!5X~ThsDqv4C!o? zcS+!<&7T6Dlk(L2otErgHa5$i>3-nx31($6gvT4ZG!D9Nuzqg3NnAF(2JkFi^_|nWikH}UCo=Y&T%|> zA9se!Lc6lWe8rlG68ZS24sxo{xx5DqrSgn(_`W{|xXnNt4tY!G|H(;1(ozV8Kj^2E zcK2CQL+hopsUsg1Kf+q6PI-1Y`O%1_5P6jVlA5W=SDiz|R&t*up%9StFeVo;=dMFGAPVE5=hqn>* zm8FMZ{**iN-c40DyLCQmjC=Viei+yGuiJrS)UNdNJUmri3WYktE>xDVoCpz2GmlP? z2*+2f<7BM=pEQaA?>xRUXiXQ6sE;Wk6#hHT(E=O*5dks@1J9e>z@3Stsp%1Rjle5V zyJ|@**YEK1hG5^JH7c80Imh}IfbdUav{Vs7`Zr_d9nt>lr@!rOff@2mKk ztT8_g4FKZ0G__*!`7d{L_$K_ z@Y&kq$UMD~*GTn%Nm*t>t^z~imDzl_|M*>-&FqG0m(ZtBu)Lp;X4fm%S)n|(U;uv| zQ3cN)*0)F_rI8@!nJ;zyF}&)O-LoA|cafq*7)eq&SE>Fnc}arcuc;&>J;g#{Oy;Hh ztgPi_ZbAt+lzGz@CST21^}!|LfS~)iEJ<44nybU_ZnQ0m?ucRBliW47mtb%qHY_AV zbZ4_*#sB7yJ%2L2cCT!h6#O^SO95W-$S9_NFulZS0&xqF-Odf(c)4#JgH?UZdlPZ3 zz?>8KZhwn4tACnJQ`eL*_fZB&%rIvYnaGsHD<>x>mD>CE?ZHfk>-w9LQ|EDzM~(l$ zL2Au=#L;bhR`NTQVC%}rKqU(wc@$qEq7fMY&eb(OGbkWHdMzLwxHb*-2eYx>4}U%2 z$Hb3Pymd`Xd>+F1z5k;K4(d7-&F1Uj{`HYlgnU{g;2A%^yCO+kR$IwwInuT9qhsO< z;hlZveDlP=K2F8Kl0Jrq0K%`d?A_0pbHE=g5i)Cb?Scud$EB?Q{BgegqZpjjZ5-M(B{k|m}h9DI}<%Xfn%L0eOXC>OEOe0`S zXJ?9{cKoGH2<)QOGAD*i*_`GdpybC2G4 zBXkkvAGi^AM|av+hvOl;1^+=E^ttOjeSN1NtxbpKv$&*Sor~Mt3LG9{tANBh0rR^j zMY19+Qb#gAfo>mO%Bp2OFGObCz;gV@@~`vq5lW2MQ)SGa^`xF|Wf~1(12E%c4(Tqr z*0?oqlV62_OE#1mK^L;}{`E7pe2aN*iHfOQ;1Z5PDz@;`%6)tiHTw{U1ZJ20YrQfM zLmcqp^I#Q%O^al1M#7yxXhJ z0nhhs<;5OTcCOr?hy9EaDvIC}IBguL`*?kOd)hX^#5F;3OICLtJg|>HWchumMUL^_ z7Y7Ms^>1uiop+(FJn0pgGk*|pJo&=oUOIE1<6Yt~h#%(%znP|icpmur{B^en_| z@w+^;_mQC`RVGivZEQ2|D|Wp7BlF`GJOm?Y>H;)XYiW;v(|XRoTtF~d3x8h1v-t|@ zpg-ds9<4w1#*w;d9Qk65{r~+hX2;q?hhs~y;EbqiW5M0jP*jT$OlK3WF>2{@A;eVT5WubQ*~E&$?>M@=aRc1#Ajf?&E|~awW}BrLHeQU<$cUsi>xj)KT~1C zR>0&?qcX8By|A#*PlsF}(;vIbuB;>5uDq$~Xx8Xc`iD5<1iHm$isCT7&@qoyqR#Tv zOJEr#1kq>u`(j(=k4MkyzNOaZxe#OOnHyH(f#?Gaf1iqsCaUk4HDWkG58L-}%5k)={QZggCP3KW$w& z*@ug$S`I>J*4V-jOsv2r)=qwIZPG$*CCMl_$cLr#TZHqwzb@wYspe4NTUntxxWM-< zA$bJ_X6)s)wYAKMn@3Z2Oy`{M9^Qu2>M)zSu;sW2(Z#+eZnX_DxA;QM*)vOt)Z>3M zE7}PJ6|X6K`jB9;T&}cvhTTTwLKKwVLqtA@t=dDJdb>U28h~8`vh5nfGc@*x1q1|S z78R-O=gZc-GaL2!0VC;3(aV=drxzzXYSKO4+S&!HxTaX z&e$;W8jo3A%V@GE@sp=x&xKNtuN{kiO~_{zedr=jhcHh*Az`fg&yir3aWC`<;u>pP zm|r)%R~GC&+t^lm#Qj5S%g8z3e6@#1)J|hRt3#(|3%$p}eNhh|4l#+3**ghccB!&u zrVcr{K>W<%-2IGgVbir#r-YQef@Y>O-EH{D&~rJb{g;X-#pAxf*d{SgJ#s;QbiAr- z(%ZFiva+-j$99D0KgydqaZJl%^-3J3NDMJO;*Ehb{ev#-D;4>(o@`=rH!Od{DG#N| z7noW446^*?Fcro$g~<=lU%t`rmGtZi-)w>V5n%z+NnRr-e_H*ZvCrBEq364s)|ND= zFq=miZ;$wT>&u};S8CKsmx111qttZzrUNn###~&2o(FWajxAn-Se6e#_QO=4tMY4b&;Myrd}-s{7j-sM+3g7=YV9gn_l9Pi#MrdL^BXCgwRhAocV=lo>u6KeZ`DQVUpxpZ?LMP!;zbY!%JX$B=J&BaNR4F&s`L&-P z|8Bq1k6S-KNybumW~0RT7;6_WbeFj_65!Qmge;8Ue{8|2E-<2fSEZS~Dd*+2dd9x# ztgKJn0B?-{*=F^ZzBB}1EY+d>fB2$;+oSQ=HVj`e{=532(ED zx&@xJ(~N=JhTC+iK0^^pZ&k*u(AUv9rq}(+I)g!rocdpPmN-tU)BmzAHKTuoHZ~YC zBz3ZSa~V~9Ag+MFxFu`N2|aX>Jb|XQ^zfkeb=N)SOjk3|uF<~VU0P}~-7LKp4|bg; ztd#FF-!#8!7WvM6#$R{cD(^A!A%zNw?iSe*0H+{qTb2i9xZ+a)e&7r2{@>!&O@w%wOWk zm2IhW9~9K?4K%A%6GFdws@zFEuQ^;ys^TK*N;)$XzGz>^JBZuOIh>EHQV#XOlNiSq zso0{(TEsIK3I~&N7vmVICJcpG)YgV!-_EsqVXj5thi>$$i;^p9vs*LI^Z?;p5Tmmq zUiDZ;T%YC1Monl3?u9(Si;0WF23yw-RY|eZ7HCojarqiv{t;eGkM;qy3>?C;eeOhLlxBwtm_C z56w>3;=){`-p%x9pas!BQ^xw23ehjHOHpk06pKER&SWyjn+BYUG~GwdG84j&px?7A zwLQvT;GF{~A;+8caXzwIMZED+4fF>YMJFEdlUE#bjic7f9K3UI(g~Wpzv8=Y4CA|W zc)I+@*GJ@ymwN1c6c^@7eQ;yk_WamiL<=8m5tzZ&;=J%KX9C3~Jw969i;nO0M`6qw zYr_ntM4x#*o^CI_uw7&Itf(B0Xvxm5?))gYPDKbtU$olZ-rx0zw4WAO@eL;5weVpJ zFFqaRJJR7bGJdDNZuA06tPFyx=f2aV4W{Mgt7r21))8t``EiVGh$E2o(U#ypu1j>n zaFdlBoE`ayVzD{QniCV@-3*_t5f!P8%x($J7zJCPbg2|5O?&5KNu-Arml+TjOMw? z8(lz|EQe_yWli-=>gNYM&uwKJ*wel8P(80)W{UHHIcf3kW9tcD;!*KCrax2$sf20N zX}I-v)qQ)fhZcak1C(zey*-d&%cni_$)?rrc7}=O5wDRxd^U;peo&K8yOXj47wVe# z=_HGl+*{k_y-lIK)#Z&;t6f^-Ej}0~Q`+!6PXJ!WLmI9%CT*S5(;l}bUnQgBi>BIm z507g%d&&9Ok>Rc62^`CQzV5CFgQ=F=gw{x>X}&vKy`Pbenrn7sP7*NPfT^mXiC1)wZRgzP4?JX@4GuX5ey!gzGiw2yNv5-U(;H?qS`ti`}q*^T2$@M zBW-PXTA5f?xJpCzVUmiTM(E8-xTW1IFlKR6%HcZ*8-wI#BKs^(u2QP}VKODAmOstw z&v<<-ni;K zs1nmi4Sl!o<1_mGszPw!y$5p}*ODh3{fzgFOwYPTpk}(BS8H;Oa&gQ1nFc@*vt`)7 zQWd){DPJSbqiFut{$VMNc4ExBu+ttN)Q-$G!ztQy9J3|5bp<8C7;KI7E*J0uMjB7R zd0Dcb^QP@FpcH%!FX{&-Rd}m>ztp@@;IT{5AZv#4-m> zWu^DYzK*Z!bZT{Y`4cI_ps$2=2&LogKduS^C^oMQiWnyJ=z zP@7nH!tZDvSf+j>q)KO{54BfZX2Ubh0Z%Mi;bQ(jTy z-6u~|?kZunn|Yp2O-|3PC-`Svid2HYbKq+CuRy~%0#yur6Q0X%rrYs0m#nQN)6&zO zZA2_H41BQ#AMf^3bO+VAh;o)+-%{N+x{7n*MC3ed7)3V=1+QfAMHlZRbk|t&l(YrZ zVnvD0XVVwCyD%nB%ZdNh@wP(VI3r{DnF@kz6AmqpA5#O5TK(F3 zbZ+n|jdcfGa^s)mKLXA8gtRk(QC*dcmpbGqABdVcF`0T0cws8lEo%Pdi*gpdfU z)_3jI*!AzI@0~pQ=p%f)+g8j}ZBTA*Zt0$a-cK@Zw>PoYE-8_i;J?~p*GoB*XHMM2 z+GnpG+>^09CX7V88#t~x`3T%NaT-7R!%@VV>xHjN38YSsb*bG6`wSSDv^Mtl$wo2C z7m!*s(JHvJ{$Sj)k=3-ACMnh%21{`I1XZd~DfhY+@peuqshqv}eRK!^9gU`TzhL#a zm5W0#E5H)1N!8f#_NPBR+2z=PkM(qYvn%4jluaO`OVd{~-FxKTYFO#2YCZlyPnHBf z+dH{Y8S(rNHY7R>iG^Uq9t1j_%oH#FPU>n&Fcwi+Akw??d*vUx zA7S!n9M?vwmsfm}GgQh`-iy90-(EcDsfU{xGV9Y`)yQ#V4umjueO)j3$%kY+mNz8e zH?j1mV#l90EQoi1fu=JKJ!*WW=-7PK$^NBRO|x@KQR~ejUhFVf%4zw1MWf{k_~!nn zgOSNtM%8=jukdGlgeg0>xPEivtM%`rMf Date: Mon, 13 Apr 2026 18:45:53 -0700 Subject: [PATCH 12/14] Revise battery schematics markdown file --- Docs/fs3_batter_thermal_schematics.md | 50 +++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/Docs/fs3_batter_thermal_schematics.md b/Docs/fs3_batter_thermal_schematics.md index ff558d8..8e014dd 100644 --- a/Docs/fs3_batter_thermal_schematics.md +++ b/Docs/fs3_batter_thermal_schematics.md @@ -1,3 +1,49 @@ -## Battery Thermal Schematics +## Battery thermal schematics -![alt text](Battery_schematics.png) \ No newline at end of file +This diagram is a **lumped thermal network** view of a battery pack: nodes represent temperatures (cells, case, ambient), and arrows show **where conductive or convective heat transfer is modeled** between those nodes. + +![Battery pack thermal schematic](Battery_schematics.png) + +### What the blocks represent + +- **Battery_case** — The enclosure around the cell stack. In a simulation it is usually a single thermal mass (or a small set of masses) whose temperature couples perimeter cells and exchanges heat with the outside. +- **AIR** — The external fluid region on the **left and right** sides of the case. It is the sink (or source) for heat that leaves the pack through the case sides. + +### Cell layout and naming + +- Cells are arranged in a **3 columns × 10 rows** grid inside the case (30 cells total). +- The pack is split into **five segments**, **SEG0** through **SEG4**. Each segment has **six cells** in a **2×3** arrangement (two rows of three). +- Within a segment, cells are labeled **CELL0 … CELL5** following the pattern in the figure: top row **0, 1, 2** and bottom row **5, 4, 3** (so the horizontal order of indices differs between rows). + +Full cell IDs follow: **`SEG_CELL`** (for example `SEG0_CELL0`, `SEG1_CELL3`). + +### How to read the arrows (heat transfer paths) + +Arrows indicate **modeled heat flow directions** in the thermal circuit—not necessarily instantaneous physical flow at every instant (heat can still move “backward” through a resistance if the temperature gradient reverses). In practice: + +1. **Cell ↔ cell (double-headed arrows)** + - **Horizontal:** Between neighbors in the same row (e.g. `SEG0_CELL0` ↔ `SEG0_CELL1` ↔ `SEG0_CELL2`, and similarly on the bottom row). + - **Vertical:** Between the two rows within a segment, and **between the bottom of one segment and the top of the next** (e.g. down the stack from SEG0 through SEG4). + These paths represent **in-pack conduction** (and any equivalent series path through gaps, frames, or busbars, depending on how the model is parameterized). + +2. **Cell → Battery_case (single-headed arrows from cells outward)** + **Perimeter cells** connect to the case on the **outer boundary** of the grid: + - **Top** row of SEG0 → case above + - **Bottom** row of SEG4 → case below + - **Left** column (the cells on the left edge of the 3-wide grid) → case on the left + - **Right** column (the cells on the right edge) → case on the right + + Interior cells only “see” the case indirectly through other cells unless the model adds extra paths. These links are the **cell-to-housing** thermal resistances. + +3. **Battery_case → AIR (single-headed arrows from case to the side AIR blocks)** + Large arrows from the **vertical sides** of the **Battery_case** to **AIR** represent **heat rejection** from the pack shell to the ambient at the sides—typically **convection** (and any explicit **radiation** if folded into the same coefficient). This is where pack heat leaves to the environment in this topology. + +### Summary + +| Path | Typical meaning | +|------|------------------| +| Cell ↔ cell | Conduction / in-pack coupling between neighboring cells | +| Cell → case | Conduction from cell stack to inner surface of the housing | +| Case → air | Convection (± radiation) from outer case to ambient | + +Together, these paths define how heat generated in each cell propagates **laterally and vertically through the stack**, then **out through the case** to **air** on the sides—matching the structure shown in the schematic. From a7ef47c5a4f32c2066675467ca95433773c5511d Mon Sep 17 00:00:00 2001 From: Gautham Vinod Date: Sat, 16 May 2026 11:50:43 -0700 Subject: [PATCH 13/14] Modified schematics adding airflow --- Docs/fs3_batter_thermal_schematics.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/Docs/fs3_batter_thermal_schematics.md b/Docs/fs3_batter_thermal_schematics.md index 8e014dd..fe4bd07 100644 --- a/Docs/fs3_batter_thermal_schematics.md +++ b/Docs/fs3_batter_thermal_schematics.md @@ -38,12 +38,31 @@ Arrows indicate **modeled heat flow directions** in the thermal circuit—not ne 3. **Battery_case → AIR (single-headed arrows from case to the side AIR blocks)** Large arrows from the **vertical sides** of the **Battery_case** to **AIR** represent **heat rejection** from the pack shell to the ambient at the sides—typically **convection** (and any explicit **radiation** if folded into the same coefficient). This is where pack heat leaves to the environment in this topology. +### Airflow and airflow modeling + +The schematic does **not** draw velocity fields, ducts, or fan blades. **Airflow** here means how moving air changes **heat transfer**—not a separate fluid simulation inside this lumped network. + +In practice there are two related roles for air: + +1. **External (case → AIR)** — Air on the **left and right** of the enclosure carries heat away from the case surface. With little or no vehicle speed, this is mostly **natural convection**; at speed, **ram air** can increase the effective heat transfer to the side **AIR** nodes (sometimes folded into the same \(h\) or an added term). + +2. **Internal (fans)** — Accumulator fans push air through the cell stack (segment-to-segment along the air path). That is **forced convection** over cell and segment surfaces. In a lumped model this usually appears as **stronger coupling** between cells and/or a **higher effective \(h\)** on cooling paths—not as a mesh of air temperatures. + +**How airflow is modeled** in this style of thermal network: + +- Convection is written as **Newton cooling**: heat flow scales with surface area, temperature difference, and a coefficient \(h\) (see [BatteryThermal.md](../Data/BatteryThermalModel/BatteryThermal.md) for enclosure-to-air and fan-related forms). +- **Fan command** (e.g. `Fans:Value` / fan %) enters as a **parameter on \(h\)** (or on an equivalent thermal conductance): \(h = h_0 + f(\text{fan\%})\), fit from logs such as 0% vs 100% fan runs at known ambient temperature. +- **No CFD in the schematic**: mass flow, pressure drop, and duct geometry are not solved node-by-node; they are **collapsed** into \(h\), conductances, and optionally separate internal vs external resistances if the full sim needs them. + +If the detailed model adds **intra-cell convection** (fan cooling between cells), that may show up as extra links or as a fan-dependent term on cell temperatures even when the figure only highlights **case → AIR** to the sides. The arrows in the diagram remain the **thermal circuit**; airflow modeling chooses the **numbers** on those convection links. + ### Summary | Path | Typical meaning | |------|------------------| | Cell ↔ cell | Conduction / in-pack coupling between neighboring cells | | Cell → case | Conduction from cell stack to inner surface of the housing | -| Case → air | Convection (± radiation) from outer case to ambient | +| Case → air | Convection (± radiation) from outer case to ambient; \(h\) may depend on fan % and ram air | +| (implicit) Fan-driven cooling | Forced convection inside the stack; often modeled via \(h(\text{fan\%})\) or extra cell coupling, not drawn as AIR nodes | Together, these paths define how heat generated in each cell propagates **laterally and vertically through the stack**, then **out through the case** to **air** on the sides—matching the structure shown in the schematic. From 94cc460baa6d8e5a1687aa4397315a8a3829e0b9 Mon Sep 17 00:00:00 2001 From: Gautham Vinod Date: Sat, 16 May 2026 11:52:56 -0700 Subject: [PATCH 14/14] updated br_schematics --- Docs/fs3_batter_thermal_schematics.md | 38 +++++++++++++-------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/Docs/fs3_batter_thermal_schematics.md b/Docs/fs3_batter_thermal_schematics.md index fe4bd07..e2dc444 100644 --- a/Docs/fs3_batter_thermal_schematics.md +++ b/Docs/fs3_batter_thermal_schematics.md @@ -1,39 +1,39 @@ ## Battery thermal schematics -This diagram is a **lumped thermal network** view of a battery pack: nodes represent temperatures (cells, case, ambient), and arrows show **where conductive or convective heat transfer is modeled** between those nodes. +This diagram is a **lumped thermal network** view of a battery pack: nodes represent temperatures (packs, case, ambient), and arrows show **where conductive or convective heat transfer is modeled** between those nodes. ![Battery pack thermal schematic](Battery_schematics.png) ### What the blocks represent -- **Battery_case** — The enclosure around the cell stack. In a simulation it is usually a single thermal mass (or a small set of masses) whose temperature couples perimeter cells and exchanges heat with the outside. +- **Battery_case** — The enclosure around the pack stack. In a simulation it is usually a single thermal mass (or a small set of masses) whose temperature couples perimeter packs and exchanges heat with the outside. - **AIR** — The external fluid region on the **left and right** sides of the case. It is the sink (or source) for heat that leaves the pack through the case sides. -### Cell layout and naming +### Pack layout and naming -- Cells are arranged in a **3 columns × 10 rows** grid inside the case (30 cells total). -- The pack is split into **five segments**, **SEG0** through **SEG4**. Each segment has **six cells** in a **2×3** arrangement (two rows of three). -- Within a segment, cells are labeled **CELL0 … CELL5** following the pattern in the figure: top row **0, 1, 2** and bottom row **5, 4, 3** (so the horizontal order of indices differs between rows). +- Packs are arranged in a **3 columns × 10 rows** grid inside the case (30 packs total). +- The pack is split into **five segments**, **SEG0** through **SEG4**. Each segment has **six packs** in a **2×3** arrangement (two rows of three). +- Within a segment, packs are labeled **CELL0 … CELL5** in the schematic, following the pattern in the figure: top row **0, 1, 2** and bottom row **5, 4, 3** (so the horizontal order of indices differs between rows). -Full cell IDs follow: **`SEG_CELL`** (for example `SEG0_CELL0`, `SEG1_CELL3`). +Full pack IDs follow: **`SEG_CELL`** (for example `SEG0_CELL0`, `SEG1_CELL3`). The `CELL` suffix matches the figure labels; each node is one **2×10p pack**, not a single Li-ion cell. ### How to read the arrows (heat transfer paths) Arrows indicate **modeled heat flow directions** in the thermal circuit—not necessarily instantaneous physical flow at every instant (heat can still move “backward” through a resistance if the temperature gradient reverses). In practice: -1. **Cell ↔ cell (double-headed arrows)** +1. **Pack ↔ pack (double-headed arrows)** - **Horizontal:** Between neighbors in the same row (e.g. `SEG0_CELL0` ↔ `SEG0_CELL1` ↔ `SEG0_CELL2`, and similarly on the bottom row). - **Vertical:** Between the two rows within a segment, and **between the bottom of one segment and the top of the next** (e.g. down the stack from SEG0 through SEG4). These paths represent **in-pack conduction** (and any equivalent series path through gaps, frames, or busbars, depending on how the model is parameterized). -2. **Cell → Battery_case (single-headed arrows from cells outward)** - **Perimeter cells** connect to the case on the **outer boundary** of the grid: +2. **Pack → Battery_case (single-headed arrows from packs outward)** + **Perimeter packs** connect to the case on the **outer boundary** of the grid: - **Top** row of SEG0 → case above - **Bottom** row of SEG4 → case below - - **Left** column (the cells on the left edge of the 3-wide grid) → case on the left - - **Right** column (the cells on the right edge) → case on the right + - **Left** column (the packs on the left edge of the 3-wide grid) → case on the left + - **Right** column (the packs on the right edge) → case on the right - Interior cells only “see” the case indirectly through other cells unless the model adds extra paths. These links are the **cell-to-housing** thermal resistances. + Interior packs only “see” the case indirectly through other packs unless the model adds extra paths. These links are the **pack-to-housing** thermal resistances. 3. **Battery_case → AIR (single-headed arrows from case to the side AIR blocks)** Large arrows from the **vertical sides** of the **Battery_case** to **AIR** represent **heat rejection** from the pack shell to the ambient at the sides—typically **convection** (and any explicit **radiation** if folded into the same coefficient). This is where pack heat leaves to the environment in this topology. @@ -46,7 +46,7 @@ In practice there are two related roles for air: 1. **External (case → AIR)** — Air on the **left and right** of the enclosure carries heat away from the case surface. With little or no vehicle speed, this is mostly **natural convection**; at speed, **ram air** can increase the effective heat transfer to the side **AIR** nodes (sometimes folded into the same \(h\) or an added term). -2. **Internal (fans)** — Accumulator fans push air through the cell stack (segment-to-segment along the air path). That is **forced convection** over cell and segment surfaces. In a lumped model this usually appears as **stronger coupling** between cells and/or a **higher effective \(h\)** on cooling paths—not as a mesh of air temperatures. +2. **Internal (fans)** — Accumulator fans push air through the pack stack (segment-to-segment along the air path). That is **forced convection** over pack and segment surfaces. In a lumped model this usually appears as **stronger coupling** between packs and/or a **higher effective \(h\)** on cooling paths—not as a mesh of air temperatures. **How airflow is modeled** in this style of thermal network: @@ -54,15 +54,15 @@ In practice there are two related roles for air: - **Fan command** (e.g. `Fans:Value` / fan %) enters as a **parameter on \(h\)** (or on an equivalent thermal conductance): \(h = h_0 + f(\text{fan\%})\), fit from logs such as 0% vs 100% fan runs at known ambient temperature. - **No CFD in the schematic**: mass flow, pressure drop, and duct geometry are not solved node-by-node; they are **collapsed** into \(h\), conductances, and optionally separate internal vs external resistances if the full sim needs them. -If the detailed model adds **intra-cell convection** (fan cooling between cells), that may show up as extra links or as a fan-dependent term on cell temperatures even when the figure only highlights **case → AIR** to the sides. The arrows in the diagram remain the **thermal circuit**; airflow modeling chooses the **numbers** on those convection links. +If the detailed model adds **intra-pack convection** (fan cooling between packs), that may show up as extra links or as a fan-dependent term on pack temperatures even when the figure only highlights **case → AIR** to the sides. The arrows in the diagram remain the **thermal circuit**; airflow modeling chooses the **numbers** on those convection links. ### Summary | Path | Typical meaning | |------|------------------| -| Cell ↔ cell | Conduction / in-pack coupling between neighboring cells | -| Cell → case | Conduction from cell stack to inner surface of the housing | +| Pack ↔ pack | Conduction / in-pack coupling between neighboring packs | +| Pack → case | Conduction from pack stack to inner surface of the housing | | Case → air | Convection (± radiation) from outer case to ambient; \(h\) may depend on fan % and ram air | -| (implicit) Fan-driven cooling | Forced convection inside the stack; often modeled via \(h(\text{fan\%})\) or extra cell coupling, not drawn as AIR nodes | +| (implicit) Fan-driven cooling | Forced convection inside the stack; often modeled via \(h(\text{fan\%})\) or extra pack coupling, not drawn as AIR nodes | -Together, these paths define how heat generated in each cell propagates **laterally and vertically through the stack**, then **out through the case** to **air** on the sides—matching the structure shown in the schematic. +Together, these paths define how heat generated in each pack propagates **laterally and vertically through the stack**, then **out through the case** to **air** on the sides—matching the structure shown in the schematic.