From 36e78b48f167503da94c8085ec73d388a26018d3 Mon Sep 17 00:00:00 2001 From: Cyantime Date: Fri, 29 Sep 2017 02:28:43 -0400 Subject: [PATCH] Adds plasma research outpost. --- .../components/trinary_devices/filter.dm | 3 +- .../components/trinary_devices/mixer.dm | 6 +- code/game/area/Space Station 13 areas_vr.dm | 39 ++ code/game/machinery/atmoalter/meter.dm | 76 ++- code/game/machinery/bomb_tester_vr.dm | 384 ++++++++++++++ .../weapons/circuitboards/circuitboards_vr.dm | 12 +- .../game/turfs/flooring/flooring_decals_vr.dm | 6 +- .../examine/descriptions/atmospherics.dm | 3 +- code/modules/research/designs_vr.dm | 9 +- icons/obj/machines/bomb_tester_vr.dmi | Bin 0 -> 953 bytes maps/tether/tether-05-solars.dmm | 498 ++++++++++++++++-- vorestation.dme | 2 + 12 files changed, 950 insertions(+), 88 deletions(-) create mode 100644 code/game/machinery/bomb_tester_vr.dm create mode 100644 icons/obj/machines/bomb_tester_vr.dmi diff --git a/code/ATMOSPHERICS/components/trinary_devices/filter.dm b/code/ATMOSPHERICS/components/trinary_devices/filter.dm index ef43efca6b..5bc9f8d20f 100755 --- a/code/ATMOSPHERICS/components/trinary_devices/filter.dm +++ b/code/ATMOSPHERICS/components/trinary_devices/filter.dm @@ -236,8 +236,7 @@ dir = SOUTH initialize_directions = SOUTH|NORTH|EAST -obj/machinery/atmospherics/trinary/filter/m_filter/New() - ..() +obj/machinery/atmospherics/trinary/filter/m_filter/init_dir() switch(dir) if(NORTH) initialize_directions = WEST|NORTH|SOUTH diff --git a/code/ATMOSPHERICS/components/trinary_devices/mixer.dm b/code/ATMOSPHERICS/components/trinary_devices/mixer.dm index 7f1c7e1e1f..e8a3c1be74 100644 --- a/code/ATMOSPHERICS/components/trinary_devices/mixer.dm +++ b/code/ATMOSPHERICS/components/trinary_devices/mixer.dm @@ -181,8 +181,7 @@ obj/machinery/atmospherics/trinary/mixer/t_mixer //node 3 is the outlet, nodes 1 & 2 are intakes -obj/machinery/atmospherics/trinary/mixer/t_mixer/New() - ..() +obj/machinery/atmospherics/trinary/mixer/t_mixer/init_dir() switch(dir) if(NORTH) initialize_directions = EAST|NORTH|WEST @@ -227,8 +226,7 @@ obj/machinery/atmospherics/trinary/mixer/m_mixer //node 3 is the outlet, nodes 1 & 2 are intakes -obj/machinery/atmospherics/trinary/mixer/m_mixer/New() - ..() +obj/machinery/atmospherics/trinary/mixer/m_mixer/init_dir() switch(dir) if(NORTH) initialize_directions = WEST|NORTH|SOUTH diff --git a/code/game/area/Space Station 13 areas_vr.dm b/code/game/area/Space Station 13 areas_vr.dm index e20a95a55b..f59fb3d9e1 100644 --- a/code/game/area/Space Station 13 areas_vr.dm +++ b/code/game/area/Space Station 13 areas_vr.dm @@ -231,3 +231,42 @@ /area/shuttle/tether/transit name = "Tether Shuttle Transit" icon_state = "shuttle2" + +/area/rnd/outpost + name = "\improper Research Outpost Hallway" + icon_state = "research" + +/area/rnd/outpost/airlock + name = "\improper Research Outpost Airlock" + icon_state = "green" + +/area/rnd/outpost/eva + name = "Research Outpost EVA Storage" + icon_state = "eva" + +/area/rnd/outpost/chamber + name = "\improper Research Outpost Burn Chamber" + icon_state = "engine" + +/area/rnd/outpost/atmos + name = "Research Outpost Atmospherics" + icon_state = "atmos" + +/area/rnd/outpost/storage + name = "\improper Research Outpost Gas Storage" + icon_state = "toxstorage" + +/area/rnd/outpost/mixing + name = "\improper Research Outpost Gas Mixing" + icon_state = "toxmix" + +/area/rnd/outpost/heating + name = "\improper Research Outpost Gas Heating" + icon_state = "toxmix" + +/area/rnd/outpost/testing + name = "\improper Research Outpost Testing" + icon_state = "toxtest" + +/area/maintenance/substation/outpost + name = "Research Outpost Substation" diff --git a/code/game/machinery/atmoalter/meter.dm b/code/game/machinery/atmoalter/meter.dm index 13e390538b..32ea378248 100644 --- a/code/game/machinery/atmoalter/meter.dm +++ b/code/game/machinery/atmoalter/meter.dm @@ -4,6 +4,7 @@ icon = 'icons/obj/meter_vr.dmi' icon_state = "meterX" var/obj/machinery/atmospherics/pipe/target = null + var/list/pipes_on_turf = list() anchored = 1.0 power_channel = ENVIRON var/frequency = 0 @@ -13,12 +14,29 @@ /obj/machinery/meter/New() ..() - src.target = locate(/obj/machinery/atmospherics/pipe) in loc + spawn(5) + target = select_target() return 1 /obj/machinery/meter/initialize() + . = ..() if (!target) - src.target = locate(/obj/machinery/atmospherics/pipe) in loc + spawn(5) + target = select_target() + +/obj/machinery/meter/Destroy() + pipes_on_turf.Cut() + target = null + return ..() + +/obj/machinery/meter/proc/select_target() + var/obj/machinery/atmospherics/pipe/P + for(P in loc) + if(!P.hides_under_flooring()) + break + if(!P) + P = locate(/obj/machinery/atmospherics/pipe) in loc + return P /obj/machinery/meter/process() if(!target) @@ -88,35 +106,43 @@ /obj/machinery/meter/Click() if(istype(usr, /mob/living/carbon/human) || istype(usr, /mob/living/silicon/ai)) // ghosts can call ..() for examine - usr.examinate(src) - return 1 + var/mob/living/L = usr + if(!L.get_active_hand() || !L.Adjacent(src)) + usr.examinate(src) + return 1 return ..() -/obj/machinery/meter/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) - if (!istype(W, /obj/item/weapon/wrench)) - return ..() - playsound(src, W.usesound, 50, 1) - user << "You begin to unfasten \the [src]..." - if (do_after(user, 40 * W.toolspeed)) - user.visible_message( \ - "\The [user] unfastens \the [src].", \ - "You have unfastened \the [src].", \ - "You hear ratchet.") - new /obj/item/pipe_meter(src.loc) - qdel(src) +/obj/machinery/meter/attackby(var/obj/item/W, var/mob/user) + if(iswrench(W)) + playsound(src, W.usesound, 50, 1) + to_chat(user, "You begin to unfasten \the [src]...") + if(do_after(user, 40 * W.toolspeed)) + user.visible_message( \ + "\The [user] unfastens \the [src].", \ + "You have unfastened \the [src].", \ + "You hear ratchet.") + new /obj/item/pipe_meter(get_turf(src)) + qdel(src) + return + + if(ismultitool(W)) + for(var/obj/machinery/atmospherics/pipe/P in loc) + pipes_on_turf |= P + if(!pipes_on_turf.len) + return + target = pipes_on_turf[1] + pipes_on_turf.Remove(target) + pipes_on_turf.Add(target) + to_chat(user, "Pipe meter set to moniter \the [target].") + return + + return ..() // TURF METER - REPORTS A TILE'S AIR CONTENTS -/obj/machinery/meter/turf/New() - ..() - src.target = loc - return 1 - - -/obj/machinery/meter/turf/initialize() - if (!target) - src.target = loc +/obj/machinery/meter/turf/select_target() + return loc /obj/machinery/meter/turf/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) return diff --git a/code/game/machinery/bomb_tester_vr.dm b/code/game/machinery/bomb_tester_vr.dm new file mode 100644 index 0000000000..66d71f923d --- /dev/null +++ b/code/game/machinery/bomb_tester_vr.dm @@ -0,0 +1,384 @@ +#define MODE_SINGLE 1 +#define MODE_DOUBLE 2 +#define MODE_CANISTER 3 + +/obj/machinery/bomb_tester + name = "explosive effect simulator" + desc = "A device that can calculate the potential explosive yield of provided gases." + icon = 'icons/obj/machines/bomb_tester_vr.dmi' + icon_state = "generic" + anchored = 1 + density = 1 + idle_power_usage = 50 + active_power_usage = 1.5 KILOWATTS + + circuit = /obj/item/weapon/circuitboard/bomb_tester + + var/icon_name = "generic" + + var/obj/item/weapon/tank/tank1 + var/obj/item/weapon/tank/tank2 + var/obj/machinery/portable_atmospherics/canister/test_canister + + var/sim_mode = MODE_SINGLE + var/sim_canister_output = 10*ONE_ATMOSPHERE + + var/simulating = 0 + var/simulation_started = 0 + var/simulation_delay = 20 SECONDS + + var/simulation_results + + var/datum/gas_mixture/faketank + var/faketank_integrity + +/obj/machinery/bomb_tester/New() + ..() + default_apply_parts() + RefreshParts() + faketank = new + +/obj/machinery/bomb_tester/Destroy() + tank1 = null //Base machine Destroy() + tank2 = null //handles deleting contents + test_canister = null + ..() + +/obj/machinery/bomb_tester/dismantle() + if(tank1) + tank1.forceMove(get_turf(src)) + tank1 = null + if(tank2) + tank2.forceMove(get_turf(src)) + tank2 = null + simulation_finish(1) + return ..() + +/obj/machinery/bomb_tester/process() + ..() + if(test_canister && !Adjacent(test_canister)) + test_canister = null + if(simulating && world.time >= simulation_started + simulation_delay) + simulation_finish() + +/obj/machinery/bomb_tester/update_icon() + overlays.Cut() + if(tank1) + overlays += image(icon, "[icon_name]-tank1") + if(tank2) + overlays += image(icon, "[icon_name]-tank2") + if(stat & NOPOWER) + icon_state = "[icon_name]-p" + else + icon_state = "[icon_name][simulating]" + +/obj/machinery/bomb_tester/power_change() + ..() + update_icon() + if(simulating && stat & NOPOWER) + simulation_finish(1) + +/obj/machinery/bomb_tester/RefreshParts() + ..() + var/scan_rating = 0 + for(var/obj/item/weapon/stock_parts/scanning_module/S in component_parts) + scan_rating += S.rating + simulation_delay = 25 SECONDS - scan_rating SECONDS + +/obj/machinery/bomb_tester/attackby(var/obj/item/I, var/mob/user) + if(default_deconstruction_screwdriver(user, I)) + return + if(default_deconstruction_crowbar(user, I)) + return + if(default_part_replacement(user, I)) + return + if(istype(I, /obj/item/weapon/tank)) + if(!tank1 || !tank2) + user.drop_item(I) + I.forceMove(src) + if(!tank1) + tank1 = I + else + tank2 = I + update_icon() + updateUsrDialog() + to_chat(user, "You connect \the [I] to \the [src]'s [I==tank1 ? "primary" : "secondary"] slot.") + return + ..() + +/obj/machinery/bomb_tester/attack_hand(var/mob/user) + add_fingerprint(user) + interact(user) + +/obj/machinery/bomb_tester/interact(var/mob/user) + if(stat & NOPOWER) + return + + var/dat = "Bomb Tester" + + + dat += "Virtual Explosive Simulator v1.03" + dat += "
" + + if(simulating) + dat += "
Simulation in progress! Please wait for results.
" + + else + dat += "
Mode: [sim_mode==MODE_SINGLE?"Single Tank":"Single Tank"] -- [sim_mode==MODE_DOUBLE?"Transfer Valve":"Transfer Valve"] -- [sim_mode==MODE_CANISTER?"Canister":"Canister"]
" + dat += "
" + dat += "
Gas Sources
" + dat += "
[tank1?"\[[tank1.name]\]":"\[Primary Slot\]"] -- [tank2?"\[[tank2.name]\]":"\[Secondary Slot\]"]
" + dat += "
Connected Canister: [test_canister?"[test_canister.name] -- ":"None -- "][test_canister?"\[Rescan\]":"\[Scan for canister\]"]
" + if(test_canister) + dat += "
Canister Release Pressure: [sim_canister_output] Kilopascals
" + + dat += "
" + dat += "-1000|" + dat += "-100|" + dat += "-10|" + dat += "-1 ||| " + + dat += "+1|" + dat += "+10|" + dat += "+100|" + dat += "+1000" + dat += "
" + + dat += "

" + dat += "
BEGIN SIMULATION
" + + user.set_machine(src) + user << browse(dat, "window=bomb_tester") + onclose(user, "bomb_tester") + +/obj/machinery/bomb_tester/Topic(href, href_list) + if(..()) + return + if(stat & NOPOWER) + return + if(!usr.Adjacent(src)) + usr << browse(null, "window=bomb_tester") + usr.unset_machine() + return + if(simulating) + return + + if(href_list["set_mode"]) + sim_mode = text2num(href_list["set_mode"]) + var/text_mode + switch(sim_mode) + if(MODE_SINGLE) + text_mode = "single gas tank detonation" + if(MODE_DOUBLE) + text_mode = "tank transfer valve detonation" + if(MODE_CANISTER) + text_mode = "canister-assisted single gas tank detonation" + to_chat(usr, "[src] set to simulate a [text_mode].") + + if(href_list["tank"]) + var/tankvar = "tank[href_list["tank"]]" + var/obj/item/weapon/tank/T + if(vars[tankvar]) + T = vars[tankvar] + T.forceMove(get_turf(src)) + vars[tankvar] = null + else if(istype(usr.get_active_hand(),/obj/item/weapon/tank)) + T = usr.get_active_hand() + usr.drop_item(T) + T.forceMove(src) + vars[tankvar] = T + update_icon() + + if(href_list["canister_scan"]) + for(var/obj/machinery/portable_atmospherics/canister/C in orange(1,src)) + if(C && C == test_canister) + continue + else if(C) + test_canister = C + break + else + test_canister = null + + if(href_list["set_can_pressure"]) + var/change = text2num(href_list["set_can_pressure"]) + sim_canister_output = Clamp(sim_canister_output+change, ONE_ATMOSPHERE/10, ONE_ATMOSPHERE*10) + + if(href_list["start_sim"]) + start_simulating() + + updateUsrDialog() + +/obj/machinery/bomb_tester/proc/start_simulating() + simulating = 1 + update_use_power(2) + simulation_started = world.time + update_icon() + switch(sim_mode) + if(MODE_SINGLE) + if(!tank1) + simulation_results = "Error" + return + spawn() + single_tank_sim() + + if(MODE_DOUBLE) + if(!tank1 || !tank2) + simulation_results = "Error" + return + spawn() + ttv_sim() + + if(MODE_CANISTER) + if(!tank1 || !test_canister) + simulation_results = "Error" + return + spawn() + canister_sim() + +/obj/machinery/bomb_tester/proc/simulate_tank() //This is a heavily cut down version of check_status() from tanks.dm + faketank.react() + var/pressure = faketank.return_pressure() + if(pressure > TANK_FRAGMENT_PRESSURE) + if(faketank_integrity <= 7) + faketank.react() + faketank.react() + faketank.react() + pressure = faketank.return_pressure() + + var/strength = (pressure-TANK_FRAGMENT_PRESSURE)/TANK_FRAGMENT_SCALE + var/mult = ((faketank.volume/140)**(1/2)) * (faketank.total_moles**2/3)/((29*0.64) **2/3) //Don't ask me what this is, see tanks.dm + + var/dev = round((mult*strength)*0.15) + var/heavy = round((mult*strength)*0.35) + var/light = round((mult*strength)*0.80) + simulation_results += "
Final Result: Explosive tank rupture. [dev?"Extreme damage within [2.5*dev] meters. ":""][heavy?"Heavy damage within [2.5*heavy] meters. ":""][light?"Light damage within [2.5*light] meters. ":""]Hazardous shrapnel produced." + return 1 + else + faketank_integrity -= 7 + + else if(pressure > TANK_RUPTURE_PRESSURE) + faketank.react() + if(faketank_integrity <= 0) + simulation_results += "
Final Result: Tank rupture, minimal concussive force. Hazardous shrapnel produced." + return 1 + else + faketank_integrity -= 5 + + else if(pressure > TANK_LEAK_PRESSURE || faketank.temperature - T0C > 173) + faketank_integrity -= 1 + return 0 + +/obj/machinery/bomb_tester/proc/single_tank_sim() + faketank.volume = tank1.volume + faketank.copy_from(tank1.air_contents) + faketank_integrity = tank1.integrity + + simulation_results = "

Single Tank Ignition Test

" + simulation_results += "
" + + simulation_results += "
Initial gas tank status:
[format_gas_for_results(faketank)]" + + faketank.add_thermal_energy(15000) + + var/intervals = 0 + while(intervals < 10) + intervals++ + simulation_results += "
[intervals*2] seconds after ignition." + if(simulate_tank()) + break + simulation_results += "
Gas tank status:
[format_gas_for_results(faketank)]" + sleep(2) + + if(intervals == 10) + simulation_results += "
Final Result: No detonation." + +/obj/machinery/bomb_tester/proc/ttv_sim() + faketank.volume = tank1.air_contents.volume + tank2.air_contents.volume + faketank.copy_from(tank1.air_contents) + faketank_integrity = tank1.integrity + faketank.merge(tank2.air_contents) + + simulation_results = "

Tank Transfer Valve Mixture Test

" + simulation_results += "
" + + simulation_results += "
Initial gas mixture status:
[format_gas_for_results(faketank)]" + + var/intervals = 0 + while(intervals < 10) + intervals++ + simulation_results += "
[intervals*2] seconds after combining." + if(simulate_tank()) + break + simulation_results += "
Gas mixture status:
[format_gas_for_results(faketank)]" + sleep(2) + + if(intervals == 10) + simulation_results += "
Final Result: No detonation." + +/obj/machinery/bomb_tester/proc/canister_sim() + test_canister.anchored = 1 + faketank.volume = tank1.air_contents.volume + faketank.copy_from(tank1.air_contents) + faketank_integrity = tank1.integrity + + var/datum/gas_mixture/fakecanister = new + fakecanister.volume = test_canister.air_contents.volume + fakecanister.copy_from(test_canister.air_contents) + var/fakecanister_RFL = test_canister.release_flow_rate + + simulation_results = "

Canister-Assisted Single Tank Ignition Test

" + simulation_results += "
" + + simulation_results += "
Initial gas tank status:
[format_gas_for_results(faketank)]" + + var/intervals = 0 + while(intervals < 10) + intervals++ + simulation_results += "
[intervals*2] seconds after combining." + var/pressure_delta = sim_canister_output - faketank.return_pressure() + if(pressure_delta > 0) + var/transfer_moles = calculate_transfer_moles(fakecanister, faketank, pressure_delta) + transfer_moles = min(transfer_moles, (fakecanister_RFL/fakecanister.volume)*fakecanister.total_moles) + pump_gas_passive(src, fakecanister, faketank, transfer_moles) + if(simulate_tank()) + break + simulation_results += "
Gas tank status:
[format_gas_for_results(faketank)]" + sleep(2) + + if(intervals == 10) + simulation_results += "
Final Result: No detonation." + +/obj/machinery/bomb_tester/proc/simulation_finish(cancelled = 0) + simulating = 0 + update_use_power(1) + update_icon() + if(test_canister && test_canister.anchored && !test_canister.connected_port) + test_canister.anchored = 0 + if(cancelled) + return + if(simulation_results == "Error") + playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 50, 0) + state("Invalid parameters.") + else + ping("Simulation complete!") + playsound(loc, "sound/effects/printer.ogg", 50, 1) + var/obj/item/weapon/paper/P = new(get_turf(src)) + P.name = "Explosive Simulator printout" + P.info = simulation_results + +/obj/machinery/bomb_tester/proc/format_gas_for_results(var/datum/gas_mixture/G) + G.update_values() //Just in case + var/results = "" + var/pressure = G.return_pressure() + + results += "Pressure: [round(pressure,0.1)] kPa" + if(G.total_moles) + results += "
Temperature: [round(G.temperature-T0C)]°C" + for(var/mix in G.gas) + results += "
[gas_data.name[mix]]: [round((G.gas[mix] / G.total_moles) * 100)]%" + + return results + +#undef MODE_SINGLE +#undef MODE_DOUBLE +#undef MODE_CANISTER \ No newline at end of file diff --git a/code/game/objects/items/weapons/circuitboards/circuitboards_vr.dm b/code/game/objects/items/weapons/circuitboards/circuitboards_vr.dm index 931e535c1b..b88ba62452 100644 --- a/code/game/objects/items/weapons/circuitboards/circuitboards_vr.dm +++ b/code/game/objects/items/weapons/circuitboards/circuitboards_vr.dm @@ -35,4 +35,14 @@ origin_tech = list(TECH_ENGINEERING = 4, TECH_POWER = 3) req_components = list( /obj/item/stack/cable_coil = 20, - /obj/item/weapon/stock_parts/capacitor/super = 3) \ No newline at end of file + /obj/item/weapon/stock_parts/capacitor/super = 3) + +// Board for the bomb tester in bomb_tester_vr.dm +/obj/item/weapon/circuitboard/bomb_tester + name = T_BOARD("explosive effect simulator") + build_path = /obj/machinery/bomb_tester + board_type = new /datum/frame/frame_types/machine + origin_tech = list(TECH_PHORON = 3, TECH_DATA = 2, TECH_MAGNET = 2) + req_components = list( + /obj/item/weapon/stock_parts/matter_bin/adv = 1, + /obj/item/weapon/stock_parts/scanning_module = 5) \ No newline at end of file diff --git a/code/game/turfs/flooring/flooring_decals_vr.dm b/code/game/turfs/flooring/flooring_decals_vr.dm index 6f07c769af..d0f1e2e70c 100644 --- a/code/game/turfs/flooring/flooring_decals_vr.dm +++ b/code/game/turfs/flooring/flooring_decals_vr.dm @@ -6,4 +6,8 @@ /obj/effect/floor_decal/flesh/colour name = "flesh" icon = 'icons/turf/stomach_vr.dmi' - icon_state = "c_flesh_floor_edges" \ No newline at end of file + icon_state = "c_flesh_floor_edges" + +/obj/effect/floor_decal/industrial/outline/red + name = "red outline" + color = COLOR_RED \ No newline at end of file diff --git a/code/modules/examine/descriptions/atmospherics.dm b/code/modules/examine/descriptions/atmospherics.dm index e01600aa6d..cdf853f63d 100644 --- a/code/modules/examine/descriptions/atmospherics.dm +++ b/code/modules/examine/descriptions/atmospherics.dm @@ -157,7 +157,8 @@ //Meters /obj/machinery/meter - description_info = "Measures the volume and temperature of the pipe under the meter." + description_info = "Measures the volume and temperature of the pipe under the meter.\ + Using a multitool on this will cycle through any other pipes on the same tile." //Pipe dispensers /obj/machinery/pipedispenser diff --git a/code/modules/research/designs_vr.dm b/code/modules/research/designs_vr.dm index 1561696c16..75e96834f6 100644 --- a/code/modules/research/designs_vr.dm +++ b/code/modules/research/designs_vr.dm @@ -172,4 +172,11 @@ id = "thermoregulator" req_tech = list(TECH_ENGINEERING = 4, TECH_POWER = 3) build_path = /obj/item/weapon/circuitboard/thermoregulator - sort_string = "HABAF" \ No newline at end of file + sort_string = "HABAF" + +/datum/design/circuit/bomb_tester + name = "Explosive Effect Simulator" + id = "bomb_tester" + req_tech = list(TECH_PHORON = 3, TECH_DATA = 2, TECH_MAGNET = 2) + build_path = /obj/item/weapon/circuitboard/bomb_tester + sort_string = "HABAG" \ No newline at end of file diff --git a/icons/obj/machines/bomb_tester_vr.dmi b/icons/obj/machines/bomb_tester_vr.dmi new file mode 100644 index 0000000000000000000000000000000000000000..849dc5ead04c30876eecc4220b81c20f89203772 GIT binary patch literal 953 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H3?#oinD`S&l?M2PxE?rg0LVPLaoyrc{iVqX ztEW%#wlWtK6jW1FyL8od>rQQHY3b&I+-NWNV+;&a7#Om{L&T0}3(X7dEG_D*u27B9 zV6bPqPbzhDN3XE)M-oT*hI5hX6E#mPmP1tppJc?=8{bArPPib}tK2`>2f^@*0Z zuGYCT=Yuzd8eBAf@JQ#pkLF2+qMqIz7REuwmyNv?<~*8oWKxJiu%@l4{#Fg+$j)wK z)y*p;G?Gpnof$S|#%!*{#jA}K!WJs>wK|wDUGhvNtm#J8GAow^p2ely9i=UKo=I_L zdealab6dQ(ZfaURpWC8?@o;W(C;y^D$qWokfu1goAr*7pMkVGq8HnVVvuTwn-4+nt zE;;xAfAu~=pNjrV=_%_|Z|w6{`K;B< z&AZ@7soy<*)f)%0rXFl%3#gel`MWcxS%MFnxD-(H`KGh{Z^`H!M{{rg;6Nz7gPtE($tva3z#1DWOUi&10K1i6Yv1q-+5zc=pr z!hDHe!NXqRufu`Q%;##}zhR&A_t4wt>~ntJyUB0yo7K|(gZM8-t^56N`13669iIH2 z__uKm#GIGxOXL@T49cqvjQFnpY4`WPfpzKk=bw15_|1Qh)QkG{!u#1){5hB3aN_+N z5F@YQ6p#_NoJa3In;)2j3jSf678v!|X3G7&5=UZcIAq!lh{?{B=|4>lHT)S35h_?(UlWhfnZ_Fv+D X&dU#nZycBb%8Lx1u6{1-oD!M