From 25092a85bbd6874fc7a16ebb08221b17fa70aa92 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Tue, 2 Mar 2021 20:12:11 +0100 Subject: [PATCH] [MIRROR] Reworks plumbing reaction chamber, purity support (#3763) * Rework plumbing reaction chamber, purity support (#57071) Currently does four things: The reaction chamber now supports purity! It has a yellow (acid) and green (basic) input for buffers, aswell as a setting to automatically dispense either an acidic or alkalic buffer when above/below a certain pH! Now you can make a 100% pure meth factory! The buffer connects are on an alternate layer. Probably going to be less loved, but I removed the reaction chambers ability to pick reagents from the net. Instead, it will pull untill a set volume is reached. Then it'll start reacting. While this means that players will have to be more creative and use a wider array of machinery. Also new machine! Buffers! They fill the hole that reagent chambers left. They can be set with a threshold volume and will only start putting out chems when ALL of their neighbouring buffers also are also above this threshold. You might have a lot of one chem and have to wait for a more specialized chem to be produced, and with the cleverness of reaction chambers gone, bufferers can do just that: wait. I also removed all but two layers. I want to make it obvious what layer the buffer connects are on. Also layers are basically unusable and I'm gonna give them a rework very soon. I'll put the things back in then when they actually have something to contribute * Reworks plumbing reaction chamber, purity support Co-authored-by: Time-Green --- code/datums/components/plumbing/_plumbing.dm | 40 +++++- .../components/plumbing/reaction_chamber.dm | 49 ++++--- code/game/objects/items/RCD.dm | 3 +- .../objects/structures/lavaland/geyser.dm | 3 +- code/modules/plumbing/ducts.dm | 11 +- .../plumbing/plumbers/plumbing_buffer.dm | 122 ++++++++++++++++++ .../plumbing/plumbers/reaction_chamber.dm | 50 ++++--- icons/obj/plumbing/connects.dmi | Bin 0 -> 1525 bytes icons/obj/plumbing/plumbers.dmi | Bin 19504 -> 19168 bytes tgstation.dme | 1 + .../tgui/interfaces/ChemReactionChamber.js | 122 ++++++++++-------- 11 files changed, 291 insertions(+), 110 deletions(-) create mode 100644 code/modules/plumbing/plumbers/plumbing_buffer.dm create mode 100644 icons/obj/plumbing/connects.dmi diff --git a/code/datums/components/plumbing/_plumbing.dm b/code/datums/components/plumbing/_plumbing.dm index 6ceefcbccb8..d0636a0719b 100644 --- a/code/datums/components/plumbing/_plumbing.dm +++ b/code/datums/components/plumbing/_plumbing.dm @@ -21,9 +21,13 @@ var/recipient_reagents_holder ///How do we apply the new reagents to the receiver? Generally doesn't matter, but some stuff, like people, does care if its injected or whatevs var/methods + ///What color is our demand connect? Also it's not auto-colored so you'll have to make new sprites if its anything other than red, blue, yellow or green + var/demand_color = "red" + ///What color is our supply connect? Also, refrain from pointlessly using non-standard colors unless it's really funny or something + var/supply_color = "blue" ///turn_connects is for wheter or not we spin with the object to change our pipes -/datum/component/plumbing/Initialize(start=TRUE, _turn_connects=TRUE, _ducting_layer) +/datum/component/plumbing/Initialize(start=TRUE, _turn_connects=TRUE, _ducting_layer, datum/reagents/custom_receiver) if(!ismovable(parent)) return COMPONENT_INCOMPATIBLE @@ -31,12 +35,16 @@ ducting_layer = ducting_layer var/atom/movable/AM = parent - if(!AM.reagents) + if(!AM.reagents && !custom_receiver) return COMPONENT_INCOMPATIBLE + reagents = AM.reagents turn_connects = _turn_connects - recipient_reagents_holder = AM.reagents + if(custom_receiver) + recipient_reagents_holder = custom_receiver + else + recipient_reagents_holder = AM.reagents RegisterSignal(parent, list(COMSIG_MOVABLE_MOVED,COMSIG_PARENT_PREQDELETED), .proc/disable) RegisterSignal(parent, list(COMSIG_OBJ_DEFAULT_UNFASTEN_WRENCH), .proc/toggle_active) @@ -145,9 +153,9 @@ var/color var/direction if(D & initial(demand_connects)) - color = "red" //red because red is mean and it takes + color = demand_color else if(D & initial(supply_connects)) - color = "blue" //blue is nice and gives + color = supply_color else continue @@ -164,10 +172,10 @@ direction = "west" if(turn_connects) - I = image('icons/obj/plumbing/plumbers.dmi', "[direction]-[color]", layer = AM.layer - 1) + I = image('icons/obj/plumbing/connects.dmi', "[direction]-[color]", layer = AM.layer - 1) else - I = image('icons/obj/plumbing/plumbers.dmi', "[direction]-[color]-s", layer = AM.layer - 1) //color is not color as in the var, it's just the name of the icon_state + I = image('icons/obj/plumbing/connects.dmi', "[direction]-[color]-s", layer = AM.layer - 1) //color is not color as in the var, it's just the name of the icon_state I.dir = D I.pixel_x = duct_x @@ -308,3 +316,21 @@ /datum/component/plumbing/tank demand_connects = WEST supply_connects = EAST + +#define READY 2 +///Baby component for the buffer plumbing machine +/datum/component/plumbing/buffer + demand_connects = WEST + supply_connects = EAST + +/datum/component/plumbing/buffer/Initialize(start=TRUE, _turn_connects=TRUE, _ducting_layer, datum/reagents/custom_receiver) + if(!istype(parent, /obj/machinery/plumbing/buffer)) + return COMPONENT_INCOMPATIBLE + + return ..() + +/datum/component/plumbing/buffer/can_give(amount, reagent, datum/ductnet/net) + var/obj/machinery/plumbing/buffer/buffer = parent + return (buffer.mode == READY) ? ..() : FALSE + +#undef READY diff --git a/code/datums/components/plumbing/reaction_chamber.dm b/code/datums/components/plumbing/reaction_chamber.dm index 07ee12b108e..2366c0dbfe1 100644 --- a/code/datums/components/plumbing/reaction_chamber.dm +++ b/code/datums/components/plumbing/reaction_chamber.dm @@ -1,6 +1,6 @@ /datum/component/plumbing/reaction_chamber - demand_connects = WEST - supply_connects = EAST + demand_connects = NORTH + supply_connects = SOUTH /datum/component/plumbing/reaction_chamber/Initialize(start=TRUE, _turn_connects=TRUE) . = ..() @@ -10,25 +10,18 @@ /datum/component/plumbing/reaction_chamber/can_give(amount, reagent, datum/ductnet/net) . = ..() var/obj/machinery/plumbing/reaction_chamber/RC = parent - if(!. || !RC.emptying) + if(!. || !RC.emptying || reagents.is_reacting == TRUE) return FALSE /datum/component/plumbing/reaction_chamber/send_request(dir) var/obj/machinery/plumbing/reaction_chamber/RC = parent - if(RC.emptying || !LAZYLEN(RC.required_reagents)) + if(RC.emptying) + return + + process_request(amount = min(MACHINE_REAGENT_TRANSFER, RC.target_volume - reagents.total_volume), dir = dir) + + if(RC.target_volume > round(reagents.total_volume, CHEMICAL_VOLUME_ROUNDING)) //not enough yet return - for(var/RT in RC.required_reagents) - var/has_reagent = FALSE - for(var/A in reagents.reagent_list) - var/datum/reagent/RD = A - if(RT == RD.type) - has_reagent = TRUE - if(RD.volume < RC.required_reagents[RT]) - process_request(min(RC.required_reagents[RT] - RD.volume, MACHINE_REAGENT_TRANSFER) , RT, dir) - return - if(!has_reagent) - process_request(min(RC.required_reagents[RT], MACHINE_REAGENT_TRANSFER), RT, dir) - return reagents.flags &= ~NO_REACT reagents.handle_reactions() @@ -37,8 +30,24 @@ //everything for every chemical removed, wich isn't a good option either. RC.on_reagent_change(reagents) //We need to check it now, because some reactions leave nothing left. +///Special connect that we currently use for reaction chambers. Being used so we can keep certain inputs seperate, like into a special internal acid container +/datum/component/plumbing/acidic_input + demand_connects = WEST + demand_color = "yellow" + + ducting_layer = SECOND_DUCT_LAYER + +/datum/component/plumbing/acidic_input/send_request(dir) + process_request(amount = MACHINE_REAGENT_TRANSFER, reagent = /datum/reagent/reaction_agent/acidic_buffer, dir = dir) + +///Special connect that we currently use for reaction chambers. Being used so we can keep certain inputs seperate, like into a special internal base container +/datum/component/plumbing/alkaline_input + demand_connects = EAST + demand_color = "green" + + ducting_layer = SECOND_DUCT_LAYER + +/datum/component/plumbing/alkaline_input/send_request(dir) + process_request(amount = MACHINE_REAGENT_TRANSFER, reagent = /datum/reagent/reaction_agent/basic_buffer, dir = dir) + -/datum/component/plumbing/reaction_chamber/transfer_to(datum/component/plumbing/target, amount, reagent, datum/ductnet/net) - if(reagents.is_reacting == TRUE) //Let the thing react in peace - return - return ..() diff --git a/code/game/objects/items/RCD.dm b/code/game/objects/items/RCD.dm index aee6fcbeaa0..a3f36d3f485 100644 --- a/code/game/objects/items/RCD.dm +++ b/code/game/objects/items/RCD.dm @@ -1021,9 +1021,10 @@ RLD /obj/machinery/plumbing/tank = 20, /obj/machinery/plumbing/synthesizer = 15, /obj/machinery/plumbing/reaction_chamber = 15, - /obj/machinery/plumbing/acclimator = 10, + /obj/machinery/plumbing/buffer = 10, /obj/machinery/plumbing/pill_press = 20, //Above are the most common machinery which is shown on the first cycle. Keep new additions below THIS line + /obj/machinery/plumbing/acclimator = 10, /obj/machinery/plumbing/bottler = 50, /obj/machinery/plumbing/disposer = 10, /obj/machinery/plumbing/fermenter = 30, diff --git a/code/game/objects/structures/lavaland/geyser.dm b/code/game/objects/structures/lavaland/geyser.dm index fb1c6aa1d0e..22bee6024d7 100644 --- a/code/game/objects/structures/lavaland/geyser.dm +++ b/code/game/objects/structures/lavaland/geyser.dm @@ -76,8 +76,7 @@ var/target_layer = DUCT_LAYER_DEFAULT ///Assoc list for possible layers - var/list/layers = list("First Layer" = FIRST_DUCT_LAYER, "Second Layer" = SECOND_DUCT_LAYER, "Default Layer" = DUCT_LAYER_DEFAULT, - "Fourth Layer" = FOURTH_DUCT_LAYER, "Fifth Layer" = FIFTH_DUCT_LAYER) + var/list/layers = list("Alternate Layer" = SECOND_DUCT_LAYER, "Default Layer" = DUCT_LAYER_DEFAULT) /obj/item/plunger/attack_obj(obj/O, mob/living/user, params) if(layer_mode) diff --git a/code/modules/plumbing/ducts.dm b/code/modules/plumbing/ducts.dm index a98d6413295..8a3399c9f2b 100644 --- a/code/modules/plumbing/ducts.dm +++ b/code/modules/plumbing/ducts.dm @@ -89,10 +89,10 @@ All the important duct code: if(istype(AM, /obj/machinery/duct)) return connect_duct(AM, direction, ignore_color) - var/plumber = AM.GetComponent(/datum/component/plumbing) - if(!plumber) - return - return connect_plumber(plumber, direction) + for(var/plumber in AM.GetComponents(/datum/component/plumbing)) + if(!plumber) //apparently yes it will be null hahahaasahsdvashufv + return + . += connect_plumber(plumber, direction) //so that if one is true, all is true. beautiful. ///connect to a duct /obj/machinery/duct/proc/connect_duct(obj/machinery/duct/D, direction, ignore_color) @@ -402,8 +402,7 @@ All the important duct code: ///Default layer of our duct var/duct_layer = "Default Layer" ///Assoc index with all the available layers. yes five might be a bit much. Colors uses a global by the way - var/list/layers = list("First Layer" = FIRST_DUCT_LAYER, "Second Layer" = SECOND_DUCT_LAYER, "Default Layer" = DUCT_LAYER_DEFAULT, - "Fourth Layer" = FOURTH_DUCT_LAYER, "Fifth Layer" = FIFTH_DUCT_LAYER) + var/list/layers = list("Alternate Layer" = SECOND_DUCT_LAYER, "Default Layer" = DUCT_LAYER_DEFAULT) /obj/item/stack/ducts/examine(mob/user) . = ..() diff --git a/code/modules/plumbing/plumbers/plumbing_buffer.dm b/code/modules/plumbing/plumbers/plumbing_buffer.dm new file mode 100644 index 00000000000..4cece32aff6 --- /dev/null +++ b/code/modules/plumbing/plumbers/plumbing_buffer.dm @@ -0,0 +1,122 @@ +#define UNREADY 0 +#define IDLE 1 +#define READY 2 + +/obj/machinery/plumbing/buffer + name = "automatic buffer" + desc = "A chemical holding tank that waits for neighbouring automatic buffers to complete before allowing a withdrawal. Connect/reset by screwdrivering" + icon_state = "buffer" + buffer = 200 + + var/datum/buffer_net/buffer_net + var/activation_volume = 100 + var/mode + +/obj/machinery/plumbing/buffer/Initialize(mapload, bolt) + . = ..() + + AddComponent(/datum/component/plumbing/buffer, bolt) + +/obj/machinery/plumbing/buffer/create_reagents(max_vol, flags) + . = ..() + RegisterSignal(reagents, list(COMSIG_REAGENTS_ADD_REAGENT, COMSIG_REAGENTS_NEW_REAGENT, COMSIG_REAGENTS_REM_REAGENT, COMSIG_REAGENTS_DEL_REAGENT, COMSIG_REAGENTS_CLEAR_REAGENTS, COMSIG_REAGENTS_REACTED), .proc/on_reagent_change) + RegisterSignal(reagents, COMSIG_PARENT_QDELETING, .proc/on_reagents_del) + +/// Handles properly detaching signal hooks. +/obj/machinery/plumbing/buffer/proc/on_reagents_del(datum/reagents/reagents) + SIGNAL_HANDLER + UnregisterSignal(reagents, list(COMSIG_REAGENTS_ADD_REAGENT, COMSIG_REAGENTS_NEW_REAGENT, COMSIG_REAGENTS_REM_REAGENT, COMSIG_REAGENTS_DEL_REAGENT, COMSIG_REAGENTS_CLEAR_REAGENTS, COMSIG_REAGENTS_REACTED, COMSIG_PARENT_QDELETING)) + return NONE + +/obj/machinery/plumbing/buffer/proc/on_reagent_change() + if(!buffer_net) + return + if(reagents.total_volume >= activation_volume && mode == UNREADY) + mode = IDLE + buffer_net.check_active() + + else if(reagents.total_volume < activation_volume && mode != UNREADY) + mode = UNREADY + buffer_net.check_active() + +/obj/machinery/plumbing/buffer/update_icon() + . = ..() + icon_state = initial(icon_state) + if(buffer_net) + switch(mode) + if(UNREADY) + icon_state += "_red" + if(IDLE) + icon_state += "_yellow" + if(READY) + icon_state += "_green" + +/obj/machinery/plumbing/buffer/proc/attempt_connect() + + for(var/direction in GLOB.cardinals) + var/turf/T = get_step(src, direction) + for(var/atom/movable/movable in T) + if(istype(movable, /obj/machinery/plumbing/buffer)) + var/obj/machinery/plumbing/buffer/neighbour = movable + if(neighbour.buffer_net != buffer_net) + neighbour.buffer_net?.destruct() + //we could put this on a proc, but its so simple I dont think its worth the overhead + buffer_net.buffer_list += neighbour + neighbour.buffer_net = buffer_net + neighbour.attempt_connect() //technically this would runtime if you made about 200~ buffers + + add_overlay(icon_state + "_alert") + addtimer(CALLBACK(src, /atom/.proc/cut_overlay, icon_state + "_alert"), 20) + +/obj/machinery/plumbing/buffer/attack_hand_secondary(mob/user, modifiers) + . = ..() + + var/new_volume = input(user, "Enter new activation threshold", "Beepityboop", activation_volume) as num|null + if(!new_volume) + return + + activation_volume = round(clamp(new_volume, 0, buffer)) + to_chat(user, "New activation threshold is now [activation_volume].") + +/obj/machinery/plumbing/buffer/attackby(obj/item/item, mob/user, params) + if(item.tool_behaviour == TOOL_SCREWDRIVER) + to_chat(user, "You reset the automatic buffer.") + + //reset the net + buffer_net?.destruct() + buffer_net = new() + LAZYADD(buffer_net.buffer_list, src) + + attempt_connect() + else + return . = ..() + +/obj/machinery/plumbing/buffer/doMove(destination) + . = ..() + buffer_net?.destruct() + +/datum/buffer_net + var/list/obj/machinery/plumbing/buffer/buffer_list + +/datum/buffer_net/proc/destruct() + for(var/obj/machinery/plumbing/buffer/buffer in buffer_list) + buffer.buffer_net = null + buffer_list.Cut() + qdel(src) + +/datum/buffer_net/proc/check_active() + var/ready = TRUE + for(var/obj/machinery/plumbing/buffer/buffer in buffer_list) + if(buffer.mode == UNREADY) + ready = FALSE + break + for(var/obj/machinery/plumbing/buffer/buffer in buffer_list) + if(buffer.mode == READY && !ready) + buffer.mode = IDLE + else if(buffer.mode == IDLE && ready) + buffer.mode = READY + buffer.update_icon() + +#undef UNREADY +#undef IDLE +#undef READY diff --git a/code/modules/plumbing/plumbers/reaction_chamber.dm b/code/modules/plumbing/plumbers/reaction_chamber.dm index 75cfcfca2eb..1f4f0446c5f 100644 --- a/code/modules/plumbing/plumbers/reaction_chamber.dm +++ b/code/modules/plumbing/plumbers/reaction_chamber.dm @@ -6,10 +6,12 @@ buffer = 200 reagent_flags = TRANSPARENT | NO_REACT - /**list of set reagents that the reaction_chamber allows in, and must all be present before mixing is enabled. - * example: list(/datum/reagent/water = 20, /datum/reagent/fuel/oil = 50) - */ - var/list/required_reagents = list() + ///At what volume do we start reacting? + var/target_volume = 200 + ///If above this pH, we start dumping buffer into it + var/acidic_limit = 9 + ///If below this pH, we start dumping buffer into it + var/alkaline_limit = 5 ///our reagent goal has been reached, so now we lock our inputs and start emptying var/emptying = FALSE @@ -17,11 +19,21 @@ var/target_temperature = 300 ///cool/heat power var/heater_coefficient = 0.05 //same lvl as acclimator + ///Beaker that holds the acidic buffer. I don't want to deal with snowflaking so it's just a seperate thing. It's a small (50u) beaker + var/obj/item/reagent_containers/glass/beaker/acidic_beaker + ///beaker that holds the alkaline buffer. + var/obj/item/reagent_containers/glass/beaker/alkaline_beaker /obj/machinery/plumbing/reaction_chamber/Initialize(mapload, bolt) . = ..() AddComponent(/datum/component/plumbing/reaction_chamber, bolt) + acidic_beaker = new (src) + alkaline_beaker = new (src) + + AddComponent(/datum/component/plumbing/acidic_input, bolt, custom_receiver = acidic_beaker) + AddComponent(/datum/component/plumbing/alkaline_input, bolt, custom_receiver = alkaline_beaker) + /obj/machinery/plumbing/reaction_chamber/create_reagents(max_vol, flags) . = ..() RegisterSignal(reagents, list(COMSIG_REAGENTS_REM_REAGENT, COMSIG_REAGENTS_DEL_REAGENT, COMSIG_REAGENTS_CLEAR_REAGENTS, COMSIG_REAGENTS_REACTED), .proc/on_reagent_change) @@ -43,6 +55,11 @@ return NONE /obj/machinery/plumbing/reaction_chamber/process(delta_time) + if(!reagents.is_reacting && reagents.ph < alkaline_limit) + alkaline_beaker.reagents.trans_to(reagents, 1 * delta_time) + if(!reagents.is_reacting && reagents.ph > acidic_limit) + acidic_beaker.reagents.trans_to(reagents, 1 * delta_time) + if(!emptying) //suspend heating/cooling during emptying phase reagents.adjust_thermal_energy((target_temperature - reagents.chem_temp) * heater_coefficient * delta_time * SPECIFIC_HEAT_DEFAULT * reagents.total_volume) //keep constant with chem heater reagents.handle_reactions() @@ -62,17 +79,15 @@ /obj/machinery/plumbing/reaction_chamber/ui_data(mob/user) var/list/data = list() - var/list/text_reagents = list() - for(var/A in required_reagents) //make a list where the key is text, because that looks alot better in the ui than a typepath - var/datum/reagent/R = A - text_reagents[initial(R.name)] = required_reagents[R] - data["reagents"] = text_reagents data["emptying"] = emptying data["temperature"] = round(reagents.chem_temp, 0.1) data["ph"] = round(reagents.ph, 0.01) data["targetTemp"] = target_temperature data["isReacting"] = reagents.is_reacting + data["reagentQuantity"] = target_volume + data["reagentAcidic"] = acidic_limit + data["reagentAlkaline"] = alkaline_limit return data /obj/machinery/plumbing/reaction_chamber/ui_act(action, params) @@ -81,16 +96,6 @@ return . = TRUE switch(action) - if("remove") - var/reagent = get_chem_id(params["chem"]) - if(reagent) - required_reagents.Remove(reagent) - if("add") - var/input_reagent = get_chem_id(params["chem"]) - if(input_reagent && !required_reagents.Find(input_reagent)) - var/input_amount = text2num(params["amount"]) - if(input_amount) - required_reagents[input_reagent] = input_amount if("temperature") var/target = params["target"] if(text2num(target) != null) @@ -98,3 +103,10 @@ . = TRUE if(.) target_temperature = clamp(target, 0, 1000) + if("volume") + target_volume = round(text2num(params["target"])) + if("acidic") + acidic_limit = round(text2num(params["target"])) + if("alkaline") + alkaline_limit = round(text2num(params["target"])) + diff --git a/icons/obj/plumbing/connects.dmi b/icons/obj/plumbing/connects.dmi new file mode 100644 index 0000000000000000000000000000000000000000..32277ffac6597ef7b2f494150405ea7589c1c165 GIT binary patch literal 1525 zcmYjR3pCSv9RF_<8x4sRvgN8MuS`g#zsHV8r4i{Sa`R~G#`3xzT{J?qFwb3iOdgF| z6oq!@QSzMkqq>oC^SDUNjMmI9x7)p)^ZT9O`F_sloX$e$N~=f%0D!c! zwRQpk2zvbj60mh-3{n-h{^;UPIAa?c8Za2l2>=jdFs171>oB0~=nyn|yYOS=EW1HTk1Li671w~8UQEX`mPVX5zc3Wt$l*L0tr`x2}FMY2+K(vu#kx{ z*xt{H@9=mDPDk8D1%e!6-w-6-SqQvH z0k`i*y$3z_SU=yIswUkQ(%nHc7FTL{Qcpsd4Cx*}S5xIzvsHKlycait*_AX}4_wrf z)K!i(-d3GdA{BdpUAui^m}caH4VjP{mx1Vk&e5B?M*u(~%g)-uIV@)`_khDNs2CqA z^W~ZCrWlPJbUOk(1m3N+47@RnZdZaT?Vi?hER(1FWoMBb7;pPly_|M*ZAwtvQt_u) zbv(CP{OjVKH^0~Wc3k8#d|V!FOR5mMWXRph=CozWB+yW#mq?ZfuIN8HXOn*wMy!7i zx%?^RctH7;WNKU#d+;-dK{K*7X_<-C4X8}lXJ=10lt0p6a?8u%Q>a3EX8^zSHG$(P z_IhOhI$0RP_lepX?{ZpjkGN3AedH~wx!`(X(j=f==2XBhtv-?WIACe)OS_w8`}jp& zP^EUESK}~*#F`z{poB_EES9;FLECqa8xAulea+e<0S;kOeMDmI8YAdt7y0$i#THBD zlyXj@^n&9>fKE6d_RsJdMaBAN)o?(YrzmL<4CC?~=hW z$&n}tX_JNJA8<9K>I-V}HS{?Pm}By);ao1~%kjb}3*k(}LOl0_^9G~}9#i4V)E(Tn z$)4Y;-(LqA$Xu3rSDgVZju@vBqMNMFn3f(dfABo*obEh(SO>am3;Y&nD`BZ2pBh@@ znGw3GpodVaYe3k`5|$JUv<^)-D!2X5=~IOUwv!odL1tF;g%`|l0<3knehfRLC#n*O zrn2CAcuQgDa6$(Y`xq14MGgcf(wMk2=oMM`xce!z=7t(!h4fUAT;-u^j_0BLYR&SV zNII>BQw~-Hb;mO9O$rj_Y`&SYL2qNGYseU_^y<8B+M`f1l)PM-*^%&y9h+Sl5ZSZ1 zdLLDpRDA!&3c_Ezn{IM$}y|Q!=-#V^+%Id7C zx3Vjl(CNNp4D8Dps3h4Ji?*Zx3j(^!BA+UY!ikQzU}7W8X)4kV52#9jtTTTKt|Ma$X=knN$(L&X=U;`9k@V}sU&i56!Eks7tr^G6S( z3Qe}Dcb`7;r!flBJ9oedf%k{c=*}lARsPe1fAetTur$4sE)~64<`uqJDfFAN2~-#{ zfBxji>?aF>yXsm1jYseHlbqC<6&Gbq&2DsDUH z+=@sxNj!L&`azAe!iipaeD?tj{+s4?35E*2#k|L{@ee2hKxobG)u`zRP%U%AJb+L<#tHX@snHWuBF$p@?+B?Hj`oH84 zkWPDeXI83WRurm9Ywc|UJ)%f{&Bz#>tJ1G=^67k D@ZrwE literal 0 HcmV?d00001 diff --git a/icons/obj/plumbing/plumbers.dmi b/icons/obj/plumbing/plumbers.dmi index e45942fc24f9a0858290c148cba6e606e0d5b4fb..35adac58da26a68f870bc9613575a45353e2bdc5 100644 GIT binary patch literal 19168 zcma%j1yoe+_wFI28!2f8L1|P%kfEdn6a}Oa1q39dYlc$k5Gf@UM5MbJLOKRPX&4Zs zyJ6~{@$>ut@9)OCcP(JenRCwD@3Wu%?EMmvzr-r@K48%Vb!wrJ4wRYUuPaR;^hB z+9vrq=t1<0BIpbA6J?@H)gN!Ui zzAAm(MT5FoKu|b!A~r-xD{SLk^J3Hd{Y8z~XPejVX)#bAA{f7ie(!Hsxp_@7g1vuY zbbCX`+F6)*H(_M9sBz}J??DJxskI=H+-lxyPwLbA`Ot{`Kmh&s;8yf1FI>y@KVz6pd zHcDXKdev?Qm)-Jp59SF z2nN>(8x;*&bdeK!KfScOE%%r{%#V{JHuEBdy-j=867@UD@kfwmyV4yy{BXm7JQ00{ z)=zzJ0e}b4R8@NDlfKm)7;y1-GY<1O^Fi-+c#!V|lL>)$#L0c0h%aC0s_ZeG@{vCb z8MKR;okvkW=MIBveomPb)a32T9Uh*9U;`9>sG3AhDaVNzGjbI%CDKLJY8n#2`e-C_ zcpBNA6em$}y|?6U$l-rzKVt;!?25erlcog)dh~UFFk0p>KSg3=dMI+8w*0O5cG&b;@O-k2P-=e zq&8&xQ&|M2`K$=!76Mtk1DkEWVj!3y+CtO4eEA|pPJTWmKo{|lmpO{}(p1KrefD$( zpZ@r%7sc<|-^(~xN`3+&RxMyeEGvN!l_YI7v@a{Y6dM0 zKQ}vDayuP0`eL17*q{R>uEAgZv+KFaLZ|Nmu{uKM6vLs++r|{t8L!jTrhfa?k?tk~ zHtrfij$AMl&I|bzo*1+rs}u44WLBROK!vcM5$py~wOMIMiCI!~aYys^*ooS8^Og|# zqk-LCoh=}!W#C28;dFgWLSX%$I-LV?1b~1SB@8(I9!0O?d{-}SsYzXogr-=x6gFq( zh9uMq?c2Dwt4oNz}p}nb+2=ky;xyxD*hm2;j1Wyb$T+_@JzK7Z}im*H#aEs3Kf&@&skGvM}~N&?rYmUPnULE*quq*Rv&94 z0mzP#y{wzwT;pgUgYo3CkHaJ@pxl{wsMjDoU1Q4wIqS_@!#%a7`l)U+&zKT<#Nc&m zDm}YSnK>DGW-zC=bp}(}9WV^j_PXq2TeulFSa=8L^2=l6v*`g%h%+iiU(O+h4((pI zFZF7v5BarGevmlZ$zQ(OiK;6jMjW8?K?<0Obd_A-9S=bfktCkgmS=6zVPx%yM zDUFM-8N=UA-FFaT1M@6WMe`D^KXnHY6dn_;=#d# z*TAgz`JGOX_EDC890?js3=wrj7vA2S*UI-*xJqJQxE(Ze=y)G&m$4Wlnd=&#l}*Cq z%k(UvSo8rj=_EsO>^AUR?nx|V(29+We2#LuzzaVT;EjKG!qgW0Te*U<7Dkn3IEf3j*xoh?$xu!y)dWS)0{z%;q-(A zG$I1qN?TuUfny#=m#Sy{B4PBnH}K0nGH=cZRgM=~Gx-e`;J&B+sq*w5&{s3wW<};t zL&n`uHIrD5+r74@o`aT5eV(WT-A_bv;`X1#Tzf}*wB`QPaqQ@8Tvu6OJ1srOf$DJv z^(|iW7AN2J@^0x%6z%;fw?6CN{!xoipB%SQvV2b^$?C^!bylI)0p*|MA~Y~;H@SbU zunS+DRq$!URw4?Vw|isrh;8L$vFQT;p~s9tRa+7&rPLKB%u>@=)9~Y5i50^Xi5^Yw zR8bIgw5mLu7C_Tc;`Xk1Japh-nT}KAF+!H~&3H{7yN}E)<69tJr+Co2tQgc^w~r85 zVC8k(MbHo0X4hBU8Jkj9n8q(y?=Boz-g(PmWy24dhY|P0Fi>4#*vgfR3TM(jTO65> zW(%#t2>IcFj)0IR<50DyXThW5;;xWi`u;Ex_@y)`DvP~rqc1B#rz`loxM7>{WA(>6 z1+TZ=fe2MI6tgywki&AX9&}%BB@4qae4mY!lGx6ADE5LpYq z3Z+L#dBXe$%IX!|y-mvNY0-8V?&BTe*7caflMmHQ@kzB}w#RqzGxr##=E`+ln;CU( zba&%a;383cC{C2G_|)@DP>RQMU8Tby^7p9xI-~ zkJ0eoTMw_WQUxy(HsIVf(eDui#u8;}3Ml-B-O1!u9J7r9mrk36UiK%+Tnp(OGAvN` zwfd(~Z5@B@=QI^fMe^MQYQkP9a$O0%-XGCZm>40 zY}4K;Y`I}bEb8d0d4aF6UQjw3529L`+4kex+XLx(Co5=dV}} zO&(KtHIiT!tV|vRKHKNQSb{y+8k=vbSANjr3CSCMRfub0**{1TVR%c#PxwfXfQ~q4 zD0P2^Bs9USL&TEnH;dI#0&TFH7NO9)B^A~Uzrfle=RccwY-jO zS!Ih*m0!{AZQ2$f6UZi3e41BP_2VrjmGfff1~jCMT?+`yqoShfu`p#)?bV|jyHUgt zBra2-;1$!k<_W)VJZwOsvd`YVYWL!u8JuzHaH~zdXJ;<{qaW5f5dc`Zes}HEe%_BohfUYX3N|Oh^Mp9lr((mz z;aYck;*nhN`-kX`s|0+BZp5Lyv(kJC;p{Z;mIPiC*>2DmT_-d+udR&%v_e|vhrcZH zD^+>y85{d2qiIfKo_vEiF#tSIJEU>gqBI^>GIboTb)n4aV5&~B()znl9Q9$cTN(KB+=W_X*yHua7T8#RuH6AZz33#&7|@_D%;4i|pRv$GkTe{nb$9G|PLt zzTyne>7bAl??jDTxV8&-03MRrMaxa55XqT6y;-)lHnHQLw?U7fB#`rDkF@-EZ+R}S z(pye3?Vf(GeQLfOj@xvihBXil(?EpWnM))`H|J(405&BTR4`?b64wDWO?FZgYaWi7eAc1B^VxU7qt|h# z$VWXPTj1YtrAcahnaH11_O3YhZBgu8@T`OWC3FR-IjF)gvY-Noou+#BBQnF%KdSy-hwj=h%STyl4M_CRVzTuL=E%jv3L#wWo}6Oa zR|eA9weI(eQHKbhnrtCnOP)^smiEK;ExLvt))N&uf6NmKnxd={)1^43`O^p$7l<-Y zv!`w-kf_Yqtr%p0Sv+HX+be_rO1qYN;KPad*+E$0eK_HY!~R?~ud*fM+xRJ%0P9k) zkN5I9M+T}-&g_d&ri|Vc(Rb(-7N4$tY)joS%$yuk^I9Q(c z@e38M970Jhu;+b-vw@KedAC|J5MQ0+IemwtubiPJ(@U-4B#*dDrz{jdK%wWGc4*9( zs9Da@bR5F^>#8Ke19D-j%WrdB5Jb0Iq@~NqbBQGy+%=5MFF2#%#?i;&gqTa8a z_5gOwK_P=O{kLGsZ@zu=pM+yIj6&X*`Va4KSc4O*n+3}u#toLnForZg;Uc-gt=0c} zK`zLwWdHGdo({7E0>;Kxkv z>7BSc#R?G78G^|*7U+OFaQdw64dyhd*ueNz-lM<;P0WLe3rdBUN!LYmWizgX#{wPA zWH$@_t*&u3<^rtMics9(o6X(w;aexTXSY7YD%nSNzn{?zMS=~o!dd713cWRM;H-_6 zmtX}73mrR24TWJmU5bPigD&C(lYUrzV)MIzU|8V;b+-j{^&BjJ0zFk1o%=}&L3ZJc zXX4BV)9StYed7VICLLp>#L(UT9I_C*hO!k!4v?MoPvDYO#tG+NU8d`-sW-#;&6Y;C z87ev$wI+M$rgSsa@ndaZL+2dC;9`jLP@aU&hvXE_(Emao%A?9Q$j8kv&ROtjC{G|zn2tTYk$6h~Of9|WWZ+%U7LZ?@DDqz-IkDXi+ zPhSci7(Iyh2BM2PS@;cBQ*7`+LiO@- zjMDrwSWSMkqgZ%93Ey|eZM$mZHHstj>~W^rV14nloGGx+>%Kv7+tl+L9aeeKTbT5pTUS;PV%JJ3ThKt-ntbvdQHP4LuafnS|2 z#&*d4>z5HnXfv0nwzl>Q5rN|dOX}ZoQ(vu=pe|>D#l^+U9IaV(>ZN`NMe*STnx%7vaRw|>T=mrg1yBlg#Joa!*~Ps(|yTSi*@NwQODXs=}m za5CKFps~RhJemJ}>v&^~z}_=dh%=st{p?u4q6d2AVkL6x1W5_~ok6y7sO@Vu&~YF! zDdn+Zo%vKU*8XOstBkP4BNPVuv;0lo!8@aQTlFyac9$;@SvDl58w;?-O;Wm1^YTGhZm%`6hh$>eNis zyX*p0-5rNmm1gn2c=hSn^xfRGDG7xzPN;!5P-}UXkmKvMP=nm4!(jbqcS!p1FPq!r z8q138Oj#~Vw@1b^1+$%2g2w1nlvBB2?Wng=9?3Lq=o9#nkX7m+l&?y>4Yp`t3#=|WqFZh_E z6n=~iNHxQ2jswXIUsHLDl$ezU)`(IJNAIF!!#b=zJgRak zDi~gDp#XpqcVs*1XJUjADHbCFt_!_-@?m}5q(dYm7puw7Z$A%FTnnc^?HDlm^AHm4 zL1%aF@3uBk-rB2b2zMs5x;HD{6ZI_9nWV#s%m}KI^it-6qRjCW<$fcRCkh>NKC1w0 zM60=>&>3O;1lM#)a6R`P{dyz~>^aCU4VTp&(LRju<^;Yq(#xTFdw-rBL$GtZUc$R? zLK1bTDG;Y?VUhtS+<~d$4i{TqTES(IMh`yLn-4M>%|C=eS|0Qf2vm;0(zjG3mWb9M zWjs*g=QiGtmVo*L2ez?_PbmJKa!)Nx+iN-3r$t|8VhHOMm(vIZ(u-7Mk z8+C3Sc<&zAm67ID+?)0#oj>LbpT<53BMFlTo_ds(XaovPvt8gbqug-Z`yDJaLH@`8) zcC)P%>v`G{DFa7wubx-+0{-N>6C^Jg? z`YWCp+AwX41d+E=1rHUX=sBAVXA}bSQ?p>8i8&nS{`gz}TYQ!YL7LS+wzsK(Cdrp2 z68U0A0Va($ggka+u8lHI->tNe30`ZDeyat#NniG_u!^K{JrrJacp5C7Vxd%dR?9s+ z{oo~w!?24W!Nm8{yP_9A!k|e_a#nJ*<#ZU`2jMF_xyY^Tepe9m$RUMx`hf_6x%f=x zEW#9?<`IQJVH-Db))9?V8WZH%I>=t9tv=J950;OO~1Yte4iDC3J zQ0|$1cQe46>VkC@QBElvvJS=$@Cx8Q zS0<8TcJuUXkh5(DX1;$XX?=fLUJmmPZ*8fpJoNoqGaK0D(0{JwDUL3v{_igRKjDMk zHKj7V*>%hz3LebaE$9w(keDY)yR*@oa(W=c zG+#E3Gkj7y7_0+Sd0etAD`|pabQo#gbY`4kplM+_S8ZS3Fwep3Xy5}|M;nHO;Cz7W zyojoAwXO{O>ts3c=UqLhKjyUw0ocA^;0@>o|B`Puv9JDZ%L|qZs$-@*hyu1RRm>*E zlFC!&1)PgLf6FXBu;UBjzH?~PacAg-LakED)yPLCPS4{W!eYr)12GD2S zap{zH_+t9g!&J#r^Dl(%r>O-C!$rIBhI(?Aq2hxgm}41-QNt+~IgN~RDctm~JGCsz z3^u(z=P`(@O~FMADZoMw zO$vABY}FHZx6p`N?FhU7X*Y=o)p^$PmSJ$qp`?z`rmx@4px^nnC-B|b_nyh;rKu7st`?s4 zUvHd^XlrcGL`WnGERJ~3wHay2&Of~@hJ%g&u=+Mpep-qMP#cY)Z{3(}uPeA^WEO0I z!T6$Bu+IgsFOgb6YZO8uaZPpVTIY2fQx=?{)Y-ZH%l=FBIQ4j51}ExfZDk(}tnhR+ z1x^MSpPw$i#(x7gKcF`E+e37DdzK!Wodz_Vt&j};*NQH6(Ep&FFLqI-^>f%_S z2Xf#Y>`9&5>#^D?m)qEQOK+rXHDQCdgKGL1M`8t45OwwZYfPg>^-S@G3(UO-cfG7& zk`0FX@R1#XYjb5^XhN&(6eGoC@+P)iCVmLF)INsbDzaZ7;ilVl2I9Vp44pn=1U6pLq-M@(YSK;9u0H24 zCa$}bCX-^Z_xF)w)D4CpBm&ff!@D0%#p=G3PcUW}FcTfTnIHE|n1)1U9mW68=9b$= zd?C`fx(Jd5Q0xN{muIfTx3%HhH2reJGt|$Jf6!$o+Om=%b&+r_bQPKWp$_&zaHVdO zRs{4G@U5QRD;y)xkfZrk2ei|1dB$~RN^R1*&;B}g_^$$7;Fj(>^I(Xz091}?L_x=g zid#|eA|VgegVqCyn~?E$2dSz5H3IL+gE&?B9$ZjVm=9Y1)T2SGF+4i@Y<&rjM&JM( zpL;R_a%76DBNM9xWhG7rvc7*IG7zdluIS67R`%=Lzt5hz{}EtS_Y^bQ=>K~PUi|~! zf1Rn9ml$4x5#Dbm_Q$Rv7uQ&;9LI~xo0!x8VrvFcUnmK`3;!PO6Ns3xU*r@^feuJ*~dnf!0p{L$~p6|bj6dhamTq{-Fl zx^v0VRk{%Vf!Rc)0^F7pU{AZsK@%l+fWkz@dvv&b({TOq9zAw?X(}OG?@E!I+w}M^Qm&D9wT^ zD<|iR)Q1m3NU%ijVp)SB14T*2`AMEFXKOq|hbO;A%58!Z$^Sw8lye~=q3>fYv_RRe zrAu;gzUNQm$hjntUGbpqh2)0Vo}RLBJ@J*HcTbqHf~I;KXh;E? zIq$n@^Za_+>Gw+}6k9U|@erDqauAS1tn3ku3r4_L(agyQ> z&SPc>8r&hQo@22-0SMx+HM41i?dnk6ur(*(4!V$na$8LIIQx=;UBkVU&34t5_s&iA z>FbVbN5C6fAK;=N8v(%bQ@57GaXzn>%x_DP5ZOs%menOFtw>|A%`+_S76Vs!He$b-ftzz|o-{90d^0emu;N3W<)6 zxK_-BcoV^0tOVMN)o+%O2ZT22w&oDGbpwvcKxwons?luU@cq@19h{dPT;=SF#45=i_QOaHQatT)gTcUIi7!rkfDV%H6uG>qs&$2}u12 zX&kJIgA3`R)NLWSmw;C~#&vIJ&MDNa8(Ds53s-&ToC?-`%qtzl0(88nI@qf`8QVEo zywLfw5d*h?KMZiG#9;faktaJs+RRa-4{#47xTVfv&Cusl1@ySh{S@4yg`0^GcKKKS zb~Y#<$y4wHpokRrF%9_F^9iZJ_P1u;8jnu=i*{L-aGLDg2QuMME6`{0FtV%Shzy^$ ziI;B5NQRj0M>-``X(l4YN?l`VEF9}WM-k6I^`JtSujD~T%A`7aJGp$}Tcn3oizA6< zF*@nmr9PAB`@fez@sEZ^K9f2Ho#sDqT|1JM0DwCf1XcNx5ii&;>b14ER?9D+f0q5n zKY4%@`-_ZjFf~p^Nj7z!R^GJeD+8WHdtQS?WBmU(Af?QI(bW$9KB<+1MT1)vS2Obs zGp#Dy{S0Ow{ZF@cVlAs_6sO$iKm|xm8sNF)KUD@9@Qj)++%ls4Yd$d0L5biEFwPm$ z7B5q$C~VuLm!U66tjL-RM*r=hCD&FYB>u~;+yZS-xJE8TP(UlemB2kfc}&86|6iQP zG=L_In8)Lq!y#a7^z|%V{=YCjhd5iF?us!O+WKeQP-xjdbMnzAduSeXKK`8|d>oUk z{gXZ+n5(oaC`(OV@9;bDiO5ZV8Kp=Msvp%GW5yPgx=oiQU7uv5AUUzWhUaD9T8k4lMq#{r(p#YbKaCl zeKvcvqHMl6U19TL)<@#ZUG)Zm1`IvIjoqGYmvUbjdp=|n-0DPk8D@PR^R^Jy8Oc<@ zcEc6`E?v4r<^TTudjN20IkUA;3P*3ByXTbbZC&hhNkpJsqimGwjM48s0jH<$L46OK zih;s~d&GYb(#B6~$SiSlK`~ncDE3R2h9@T@sM)0e;Pbr?$)2;`$UqiA+-`^il$iQh z_8T{(LmYOAg7&BN$Lsi?dDDqrg*)?$|CRQF@*vJ4#%$oF4k^z*OEQE@Ptk&5Q4PnDI7i2{0Ey@>*yos zqbn-VGsg4*>uR!?V8(V26F4CMi=8c2{E__O6?*&htg^E0g!H~YmL0^O$NXg$b`J-T zV=y*XsizZX{gzlso4InEw2tZLg9uW5FSPK5lhP*V+77&9#W<)`ir zBwty8+}WgxZH?kEwCE{bTA2GQEm%yVF#BPQcx}N#%CLZBW4!dF*tq<1we8>~4==A} zkJQ1zLEjWeBGMePAkRiV|3~-}3L0FIiWsfU`cZQ8?e;&?9}C#*^GDYTh_yn(uWP?l z)Ba4#)L(b0BiNFHQW?;tEVCw5 z024hQ9yq^9SF$|F;G*vOO`)UECBP%kC!gUOdqjqu1qnO7rdG=pkp#FnCaiLGjG)T7 zfsKE0yWQu8ku#k=f8~lUYZ8v>V>?2b%)#}rt(}U z5k8M*rTWOcjQQT?7+iUdAS&beW>HDn|09IzgMj%8KBnlN%@VNsxD_Xs7P4fD7kWl0 zLzcX|OW#!BKG04tf5g~pIL&cHJY49Q;0_*k?v)xl>NhBYV&s6{#B9*BdU6_MN^|$y z)}TC{Dz^P#8p9_pq~aXr%Fjmixj*Np83zl1pzOTpPjeW;ebPGI=h7Rhzb^s+kZpol z9u4RTdQyJ_Eeu*C=Fkb%Tg*|rVpGuzafW1je*w*4q=1t9 z^H5!=H-=5-luw*TOif=1`e0~L1#y|Rk?6^aao(dR!}M&c%4#c*xeoHX6v&aSPX>94 zgxlS~2<1B2f@iNZQ3UeE6i$rmWsD!b0kbZbIi8xfQqeheO*Zf)Pf++-C&nfK(62`v~ufTrI zyK_GM>U7`lgFMWqbDegtne4K^gwBEcy%xO3OGj%})uxyj3UM(mC;3!GQSjqB5QL~T z+^$|^eTeq4X%P>693=<+z0ZM@p@+Xb&hozF zHv4))B*&i|Zv-;qQ#;m^6|!C)pp%FZP8T3$GVX1P(gAf2tFQdp86u0Es|Vu{(0+4x z@QZ46%h;IVY)07_0hlBJ3VgsYD0%YW@^L*oci>~Ax#dS}y123zQ|M4&i4)lWilv^U z_x^8U>0f_){}RK4+p26<7&?0}IVvnLRTpsh^ut(|_>vMGv9;Le$e9f{ukAA-BAb_$|jVVW1U@K}mS7 zKeP*l?~5*Vh{Rst1?NhD>@w{2Gr}Gd;tMhiVfeM-#lg_zMY`k(Nq}@n5&+vQN(pcP z&DBD*-;h=I+WG^~vtteiBYaEwa;;DHR*pCTr8=d*T)?c6h!@@nZN=EGcK*sIR;1E4 zk+#^B^C|mQEyuIpxH9hi+8G9t5(u8xy=HPo2474>dT_SlaTXAF`=tuBmfLg#z#q)L z9`p}C&B}t54$Y^U$!=ZzOAHUN>5)OX)kEV0MXkScI4gdab}w7$*_GDC{;XB``^*L! z44J%RqFtCU3sdGjJoF#{E+<_7_C!KerE!$~@dV#r_UlrN)TfU(DRu`*v@o*@-vj=> z#NN69m8jcquKcU=Ncdi!KIY!#1LJqkqIhYF zNkr!Wr<+f{FT`uY);uVeL{VaM09EP%N^3{WG1KoHZGJquqL&4~mjy4^nh$nfP$dc5 zzxvK_tq3vpLDVTKiu(D#8ra$39kMQB=fC1P;=>Gs;&Z0qlaO-He&)wGwS<3!3Xy}A zWPqe$>6uBNDSg3ktZ>0Ey*xt#AfTnX>q)YvVblD3Du*>7fnpDi;*@jEu zZ)r4-G3G6a!PessS&kJ;N@RciifU{VNf);}ovyWk&BUc7G}@MHCGkV6DxGA3D{xE+M`bZ&H_gG}v@2LN_pH z?_f8K>3fhY_Hj!{{gM3}j zn*?u>et1vif#X<_lAWEM?({8bX&cP>QHw8=XTi=LzgwS^V>G$#kk8Re*yh)S<>P2@ zZ$E9maDjtddC7YmA=m|IU=NdA0|T448$gN-=I6l$GV7!^8Z2?=La#&1jL^P63F;mZ z4>#;Ru{2*~9(NAz-6_cubT*cFUG*sXl0&ft&2dJuIYw(G5yCi1-nwN-R?IGT%qegD zYl?{u&jLGpyVQ*$S&|Ye5+>>wpQ&Dc#I|vC=<$roYrk2&v`cRr8Rc}B2kC$45U?P+ zuPu=T%s9VNq*L81|6hnEn5pj5)c|I!;}dV+DeXoGlyvHC!}x6ibL>@7*Jq-j2IN7J zV7RJ`ff-G60;K{#P9%Nh^a3FVz>^SuB_Z6AL}{PB!^2Wh4k|${muVax%d(@|9p(L` zn~}17k!6zGr0o4@zFz*-d++&LGH*U-(9KfF@V;>!ziNlh^V)W#<)-#NaBh9wxK{0@ZIp)FflNZR`7KzF{}SlFii=4$66`6(t{ z#_F~Zkr9c~b2gc?-%AgP`Cc5k4-Qb6aZT}>V*Q+Gjy;YeH;m0W_>Oi?J8zbgUtB!j zC`~C=!TvgG#9*$#J+WP=@w43DNPijt%(PrjUL^eGA)g7v*V9;)P|fv2I}ikdLeP%# zdN37Wb#0B1=b_erqu*7$fD3a&J*G^(L+ZD1Liu}ExTk#F;Q&ndd!OaFk6A0&$^Y?Q zQ4*ZgE|%?cx3R^&k4Sw&ea9ol%`|e5{(=%U0G0-3)$O_9T87t*>^VDTbnEBFF=&9JezOO)>Mz-Y1qTsWXw8 znRQN?9-KP9bUrBd))K=jmjVY)i@%BBrjfw%2Y;M_P1ZNjqJC`<2K%9Lf!HD)_IQ@S zrysiCWZo6`A`KXaQ5JCG(yBR|cFtXR!;3SI^FvB6^F5b+`aeT%=l?(A`fnbrsEaYb z1<(2rhqiORHsM)1OLgr|2oMS^ijv|vYL}KoSbrx0X4wv!mqBh*k0h|lHa)#eOZGcZ za4YB*5c6eOkg42y zi2lV7uP@=5Al>|<-P~CKbNUq#I@W%IJrM`|MlF}0MFsugc!yDzk+Y=%uEMp%`X+fT z?zj3tbia$QXNMX>>D*hpWYkbJp;=+prD&vfKS?GF9ezRRWhqhoma56;f+nVSnYo-s z_HavVW&O)C*&HQqY55jpCax&x=3b01KOY{E zw$FZAfq6y*IX4=>yryBW!tuGpNtYJRvU%?M0xkJW@LSg%5w zx|_^N{vN*8j&Z#Sbv44%-(s+|axj$8{ZM*HiW^vd^drKE2DDuVEfo5OeyeTQ?-t=> zWpID!H86qeTcI=X>t|gArIo=Ch(7Bp0vP(A5=4J}a%xlUJA}wR+?%TBV zt{BS0N&GksCP>_EGOvLt8bFG`s|JuomPfL{*jx3f>l!iA$bcK4)>gn1T&X6>XZ&|2 z>}FYRn8tsn)LjyzfsOH$rf>*fHjN+GrZG$q>Dk~XE$m@lI(i$*_AY67&1-wov{9qB zyn&%<0?kHlwfIS>Gv>;(E9LIp{h)^Ot`IycDYO_-i6;oqmpF@no$rOuH0Q05&)u*r z+atF*7Sm6D7*vc4Y**NK%bt#FUH(4n{Y>wj*Y1zZYZc?(=I%XixS45ZW=p*d46Qom zfXhei*l+xb_w9AuR3iJ+(ySH~d+a&4pKmexXvIi&9d@4avtrz`aaC#BY(&exnPSaH zp0~tCo!_VY?Af388L$|pUul`EIuHlh`cH}sja;p2+HH`EFhlBbNzq4HKEF(WvDph6 zp*z>}MKKg)&v$2=f1ikQktAiMv|0UbSn9qU0$Y_zI6y3a20dZV6 zNK}i5sh~T;Cd4vfe zAA=kCGsp)XU9rA(f_AEr349znRn>e?FHd)^JU4&q2)13Bcq`w%d4u&rPbkjCi_B=W zt#3f;9(a~&j6)~w*^fvVYZ0q`3brhxgXApZP32w1S3!qEHdD7mxyTmSW}r3M;QV+3 zc&Y%(D(yQfU>I1kFFjWYlxSObR=za?0vo{6v+W^L%lr+FcN+aOvt%v07oZlPwdj*%xZnDy)NnZ0lfT{RfUEj2zb)oSU=aKb^T1!T0VAlNlXJi z{YXK#`ndPCL2+P(wYnqsC)NU@GR7;OfY*~;8XlH!azHZigd^NiaQ!~zzLQ0b=VlR6 zS#yT$8Re9Vw;b%wrt?bao7pY&k?Y3{IP*hND-}-Q(;n7S0k97fKLs}YFU6DkGM~zd z^3-S-`7pRO*Sv7TxO#0O}nub5U56tGAN^#nvo0joo6^Q@i8o_NOcA#@#Z z`bq?ZmGj}_8vz(20)mA;u5vjZ5sD|f0XoJ*e7l*ge}QP0EOYYxflpfRQ?s8g zVK&|8_g<*unVvXW>kCb5*KObySmp2ygH$ex{a*pSNpOwH%h@{@j?N_9J0V}Y^H@-yNrwg4U>2V1rc9vli1rrJ3pqbphL*r2|RA)nCgZ0?aP92;LEU7^|6hz07f3REs!FR2E54wyZl+9vpm_ z=+L)(-_Sq;ox4tI`ngkryli!l_uoI%XAAJXcZ9^`()D*NE_Cf2ef`QN@J0pS@< zFrTq1_k_Vm?3i~hDlpvlU^!2aoX#)xD^V&)6+i}D73TeszlpKjmgd7;mr|XagQxDao_ju7sSQJ zY3&|J-v$7(7X1GO82liucZ6`@wic5W2vQ7E0aNuq9w14$h;~`&GH_D2Z{LOod01FP$0 z{TofU8{B^u1)OLOD&DI!lf)R0Rj2RC6&t!04pyG<@Qpe*;pSR(cI_sTh{4ws$R-%+ zj#yuEJrzx+dZ*b&lj&!>g`I|1?K>Qw{J7zGva%udlj`QoONo#D;8?Jq(~Gh!x8-0f zdMyQ^b(`KO^z0rZp)gOy_y<^{b19?lF|I_;XwYvxts1prekbs{Hic8Y`In3<+Tpf6 zvIHQmTU!wxUkTd%U0PDo)wna|PN@ZYG2h{p&%}~v14#$Qhyp|(#&%}~Fpm$y2M#5o z*>Mqiek}2nx>d?AFR$8#@(1Un)R4mD#63w{p~N|>gw|?;OFeOM;2D7TxaNsBKBqa4 zPTN!*UyZ++8!aLQ!dhv`5L8VK-Yyp8fOraV(+IJr3`yX%2HFr2%P~RdZf|b+{pV<` zhhsQC3v!$VOk+Ixikru+>6u?_(Fmxc3`!-d;19lV@QNWJL&Se?F6U%-eXjYmEffhJ z65mML@aNxUp?tj!$cSd&E>;82=Z=><@Nt5tX``?wG|dA3eJlXjwKvOBa;BRi^f`c~ z8LRV!Z&Nb0)$rJw_v5eDE_HgKHYz;9;2ORU?gk2PGGJ2$4bgY@`mtU$n}cLnF=tFD zf49;_G1+l~A7f@TRkZhNEi*HbP+5JVZ!fsyz;n+hZ((gL%vN^&7Bkg{QL-;;u`9R; zQ)V2y#q5R&=QRl`aQH8t1HB-Cm!Gi=z%S{&IM0wNzB~Ha?mKS5t*GwA)MsbdpN4}| zBE46Zfb|+tH6y+cP%qL}hTxlZ+NJyK$qwW6bYbt(85K=Y8?7%Fl2ekv1O9OY3sIsq zXdV#V#m+5f4;<9^#T$uy^d#{Oni!)dzCQ#0Lx!_nkSOMP&;0UV?zMYBi1m7*3iy-gG{vK&y)WDH{@v76#kR^zQ|+HNPx> zP<%fo1Ekd!$Bbb=S#^Pku)&i*nQ!Fn_o?`SS{HwOe^BJ@q8^O+fWNr?_SnfpIn-eK zkD^D0lDKu56#xy^@ziD<-Y!Cv>O!}}tw8Kmb$jBY$cl&KI&pJiFkM$^N!{E$qYw&4 zsPGZ=zvA@&7-anev>!FYivg6o@4sROjn2(ceIDij;+I~(_ioz4|LkuqRy;hkulDzm zeK*t3&wE>8zBl{zE0_PPu7#cd`8sUb-?gvzJpXRK{O`%CPt|AhSuJfj%C65{oo4&> z%&ottuIH&UoB#R!?X7q1zt8j6r>>8$`}x#Nee!`@yLMeMyV9{f-)Z+^$BNw8*sP~p zG9SGzeZTMZiv4-1v0S;6B)6Vpd$?_v^Q8w|@2A{QA`Kck5fveM^Y?A{`HJ+I zg4iOz-8%U|fA6F6L;Hbi2f7|Jtyr;Q%31s8bBa^eFFhT;c8|Vjzxsz8kEK8VQ%d=) z{c+0v>(+JagD2d#Xa8H4v`wgD)m8SSDZAgrm}UdRwE2>?pmpTFHHM+ z{yQ_nIm`4lKbFUY1qOBk=Y)aF>`d27eg3GeSpV_o-acS$a=UK#!gCKy66Ea~dieJ~ zF`jAe-~9iN%Qvf;K1{&Ha4S}7Gk&VRz5eKBfBU(D5&OPvU2j>o^<@iadlBdV4Xci*yTcAHm~ zfq8>=18|pS;kiQF6nW0Rs?CV9hA5V~r zXF#$8nC+COgfOW(x=by#f~?Vr=`EGF`MLM)cPp@2xh+BtdOmv;ZDT=eNdF%2mj})n zaB2fLN0r~sXAa?9<2d6r+oQKX->Tfxd(#fgltqWY;Uj!Owt)>8loG%-`gLy|USuCL ze|MkF;fGLR3~17$=m;^Esy0ty;70RWP$ z(_bn|@Xp57uXn)5TT4;*CQOdlFB zC5f>qkTTbO@A76aNV~w2B*v#mno_q|eaKuJCGyL@?EU55#~*3EekHr6P@}#qay|ND zgYvoH=}iShvoh7>Ytzxry7McX@(`6HTV~&KSWxwEoL>+H<5>n$>qv(x@8z1L!ZEi%EZn3vGK99H>Dt~sIV78 zt7=0{{cKOBm#f1Y)s+l}D?dTSf?3`8b)E%5^N}PRKYmejh~u;XKmgFwyl(23zL^o| z$8u0lL`kN6d*Dk>uI}^FtdVY4@qB!wFV&&_`t}S(5i8RT89u)lSZ=QI%ESbg2&hvD{y0Oc7RIO^ z)(B`)32IXPKV29fl8E1K57n-!_)>qT7^}q>C}H1zAait5_O1uX!WfK?upF}xDH3~{ zFWdO`?c1>Tg!GRjJRd)4+_-V0d9#};dB1FHrSW5Uc%56QhPQX+G3&1qS#9Mqcr^;% z>PN_tNJjUV0xr(ZdZz1Lp6jB<(lF%^$H2gHj}41XLYZN@)6*6bB-J=c;{$=Bsu}M& z?D9IhKT%@TAK!^5NPgI74<;s?U>%hpdBLIOSUK15wOIOtC9u)YL9}+|?q|&{FQ+Y! zP228sTjBb~gYo-XXgp*z@K5Q=Kc)4tj^}}j%E|ysOG~DMkO1Lo40>#Qd`<87q1A!i z<1aV7Z$e@@N!XwjckUW&2x3OPQ}XyGE%ngXGLwY(x6&zcv5jiMJI? zZJjKCRNl016se%UdSw1B z3S$%^r#v-8_5aSrXO@uDg)s}bCpFAx9TogwZS)I|__C)AITtv8i#T4EW=t9%gDy26 zX#Exs=S0A1e}6{|!#cS^n*`9w6Xl*wNkN-f2kI=!gQ(Sef+o-hZca|R7Mn(0uTZq$ z7Y4@}j&}Cn;(ct04nMlr?Y52(9s5;s0yfIPJ6e$gwmSVCXUNVIHyN{7-sn>!x4K>k z?$28#vT@gYRV2-?J$lCAHsQgeUA^@dVKGj4Y4(_;aI*Xan{t8|Tf<3FWPt|#+wI9S z79?n#SB~%adRcVeT8tiEuB>GlD_4H%eDa?8i4x-r>r1~MJD;#WQHu3w-TKpy!u=|i z5U|q2l z-OE09L=PlUGXuE_fx(r7iHHU5>V1>+Eh8) z(0?|jP!Gz4zQaZ6g3?*BIf*uYq)pO(H9P4d3{NwQ!|*W*hA|3W1kS2coh2pvf4>OL zFZI*(C@iISam->192ON-z^T|e1=|jMdiv~0$J}cNo5+*}np{A}J2ubu53S+ge->Tkk^zuTQBJUt|MOpZd0EMmOZ~)a>l4Yf&q@r9h{GXl+)t^Jr&w!W%BAS`5&?G&Os+PcT zAb~(CJ|Z6_f~@DL_&d=gjbg#c_UGeF8LPUeX@g%)^cMpj-|C!P3qt7VLtOxlb=j5EdFvH zXy72YzvBM~7{#Zxsq!v3TMs5x6bIr5))lmA1+~;~4UsJB2eG88$A9d&?sz$(YQ6=rY zy*R@!#QBIsyaw^y81hg>m5MXViPU&L=R+8Z|Khi&B21Nd9b<8rFm={#n83C29=RTB z_z(VYXaZi@cvzx!pB;~nt|4-7aU`fMnjUywRH1pU2H4mHk^on(R8U2cZJTjEKE(!=Vi;iAM>{~U3@y% zc~R$yytWS&sq!iLHDE89=+%o9`%PnPk8%phOknofu#h*p95A?mv+d7g{Jmr0)z0L3 z*m6NLr2(P%3fLf-YiCC>f;RD~BH!S%S17FMrvuXin$VnqxDG?hceFPv` z?Be2TUJ~x$T@=HI&90iK_&4ukG5b^DuoJvCnZ3jmQK3OfDoZn7xRD1HKA0Zud0o zej_OU<)-;9(irh1VE$@^{0A{~kydO0y)s)^f2fgu>>zw$Vkh97R~(3M2HN7OASY!v z!tr}!e@a0T-b!T##wy`|5pxkR?2R_KU+!<^uEYkza@fmTUl~>W<0fbBO&TSpNL+7f z639E~;yj=lk3~K5_oYBFtFP5U65Ht@0_H(3MCX);<8NWu)v9*l?zfANc+Lnj)vA@G zcr^0|>}kgl(V|`N(e!KW1XjX88e{P&DRK3t9x=)P;6CxAVMJzKpNG(eaknsRw&dbW zqE2@UOKN(YP4%SgnQHc-L0<;ZIPTatx&3ZvgH9YFB%hxIj~+mbA;$vgmRjvRx)9WQ zd-)XhdV6Cf5*Em}U@Z`$5@#5_o2jR&r3rMo)7U;sa{D7siIN9nz|ur4^0;!lqbMf% z^ZU0F(9j^1UKTj|uP4i`cFm8ruW&@9JUMzCm;2!ZTe*c?5k;m5hVgaVpfg22=l3rq zL%we`PrlxQdYubW)hj`KiYw7PDP%pAYv@qBz}A|6D^7r|rP1!OqF@ER(<$EbjZd&u z8EK#JJqN3a3VSwFyt}62I$#7S^vbGd#A*g4Sgu<_pwqRZN` z6Rvt6@bj#NaX+g|EiSw|j5A*;9dU1G)HpD90meZ_v)cH`@bfo+uA*(*V?4Wny#YL(KYb1(vp@uMG^uop#ynCt1`- z{pW5l$Ej8h8#7weHt#PT+Yert+0njW^X1&K;wO@omjw;?R|SxPCG{H3E~sn99S8KG z)3+nX{^^e|-VSq1V{S}Y!z1+J%(?F0j=}unny-lK{4md0en{))(q966lJ!*=5D}f#`LIx7v%aGK5 z%vD3;wv2p-a$ji3h-bvO3{UyfT{NA5tTZb1IT`Tf+?(OeIbIci8==l8d|lVjeX()K z1|vhI&EH*FBmK`e1b{Z9v_MAP8#qZywgoCmZ6;z+A^(Yag-oNLO6sm#Z!JZLiQBtC zB*h6|e8!lL>`4x2;Zp|%6cNvB$i0gZNe%5+5eLCt20uw8*1?|M_DVLVr;0y;udf?$ zueVdV>~K1kcwYhzrgH3C*{+n2Gz2DLt6&>;QpyKACuH#=cHKyfiXY1pfYiRT(bnwG zOh)gM8NV<-4}$}Q*|_`W-fGCF=g%DjjeEu&1D~^`kVgrWp~mO+WjA7^W}ci;wM4x6 zfm(TY6T=i0woh;j%i&;%WHeEglXlV1I|#h$V%G1c2D*vWYdra}lp)r%DJGhW(0b}O zw}~;m9~2eIa!T!F>(mXQ@smaqA*e3p>t?nKQsJ|!oFP<#6k08F%aoAkH#YH>%wga1 z=(G#6yleyfa%X*?aj`+=6{c^7PnY3mtrGCh3(&qF3zKm}nV)rj zC%iCeI4Md$zYL32ar+H@+Q5^}5$ScxSXo3{KJ9VG7}jR+qBn2C1h0jfZQYGT>)WIo47|7^E2{L>1(Vw1ETyt>iM{WM=-+$)pA zq)sJa!vT&qjOsZ_B%^vHISeSc+W6Xs!LNq%V{Bup}~CH4)+DrvZ%bbbIOh7T;I)`F{|>iecR*W zm}zG8z;-y&iM020f8`2qO4;RIdQRz2px&xM=H zc)|O~1%Pm!vHgI}B9#w_$Tk-Zs!s<-?{Thy5axoz7bIOpLq-o)eB0bu#PGkaba-uP zV9!@^au){wCPk=j=RxAAEcJ-~UK8eB8;)~wFNG}Y1&TpvjT z%T-uKO{yMK8co>RjaPFYu-^no7o2dzsOj#S?w9O1GQg2(<_Y1x-B#0zT^#$I`DDn~ zWg{vet2xepnctK-8~poY>6#;%f-amhi# zPPN~rU5{8Ua|8gQZbePt4gE8K5H1&f&Gs5)-%XgLq~z>Dz^X5hd-A${J{HSv8$cSu z-l*qIm{GxI94ke>!D4%dlKt&VQd2Fjq)iWaiaU=T?+&3;7$+)UUVLo!0+-zky?CUFy)4f- z)8j)}4CQ&^*&`b|3yA3TyO9WRy|#605752~LiO1=G3d}b1>%-t=6gBhvs<^D*OM>E z>kaR3r%g}*E;;ax&TAgVAsoa7sVk#Li=}x24^r#|FK>i5U8s6{2I|tA5A!r`?S-9^Dz&%_8O%&3%5-F=GEa40)KEBBiLU>#Z|#@CJx zu)$wK=b>V_Gp>QbE*URwEoH#nvm7P^WG$~D6R0HfmQ*&-+)aAOH~XN4*#;sm*|Y({;U9>b#eSJU*g-c`R%%lNu{b zM*T}~DopJ<4EtIQRvJ@yLZ!bHp3uECBHFA!=T-$}E{a0lhUG3J0(gWtRD9Kn(p)Ci zHSlA@e4#@E)BLyAgT73?z?ghi6hLi^9WeyqsQ|xA9y`zdte-k;?CaGKh2C5Qw~uWM zPmo$|iQD1E$!b-kX#s-l&Dw?SamMFv9oLPw%ec`xAx=72Xy5fW@j`7T!sNBXfE9x4}3-c~bH zwnKKmLHxvoDDVT46(YTwJql@l$(QCm+4QTcdTtblvt>U}&^0KW@_MU1d{MhDeBppUO&!6}F z`obx@=1t@rdkag9slU1pr33M-@Z(4IJ9k*mOG<98#|+rh|F}eaC-VV<97Qc)=&{R# zZ3{wK*Bn3Xn=m5>=dzmg{i2JEDB;ql%fGoVlQi>nw&IP)XTA3kFwgCU2M)IQ0*|xS zuR7^zmqYe`E{Y$hEzwi21RoH7T$LjQq8}n$~t#0d4#6D+78W&tM#c63m&G_zVSfH z<-~UxKZ{uJiTkCfCWiNL@L&v)m)O0{6gD_~SN~nsj-tzLfW}g#T!8x3)4P3C0 z!A^Ma?kRBiO-{49hXm0j9R+RtFa|E){_#ksd@|V=ze@5@iMCpzxPReJ+Hs~V;j7<% zi1qFVxs;nzZ(-3K1|g1Jh30k^U-2&$$VhrGA)A1e6^!t?J|n%5GqXjLcgWM>mFwGV z+_v2B+0f`ERx%2V(AsF{_Q3{xg(fOQ^lWnUn{Les0@tz8cI)A_TOf~=xlO3tM4nO8 zln&J&yNW0vdK|4gd}d9zrEh%OeM@RV?a3}b{(jq0*2Q58C?(lA2(=6<`-gKQ!V__y3LM>QK8WHsp~}+{zsx>tzJktU_`O;YVU}Wo z5Y7DV+$W5|gi!qc8nkuE=XKAL62H7e2T#0un}bLZ{R&Z*us6OAgj{lb&GnA`XT21@ z^w!dcU(1X;l_5;a5Jsfn z4Ee%(owMnu&}WaGf`rF@5xOEVsa(r#0_Pp!A8gsydSXTCA|F*$yEee8#0U4;H_c{}a}1{}(4h$A=f5$T{Zu7|Z#zw!yt|Y; zZPM(L&(!dTg;4N@e90F1apozpv@82U77zIXdRQ*tdL-XlvqdImUR z#(AI}xhV!Y?%j~N_ZGZwQsDGYZYC{slP-->UDvtgzc@J2nm7~7XkvT8?QV8MK-S2W zgvy_|kHg88RZRIP7}Tl>t1LfJqa-+PGFo8wndt_ z5Gc4(V3&trp#(!2v7~2ZKw<9hM;glRmcG7K`P-Q=NBrIB8IhlkD*~SPD$Va;SJ_vM z&Q%;m8AQVLs!e-EVdG(L6P1i13$x`F``CWp}tgvA-7-%%17(jWLz=Aty4^(HPZKg*DOHYMHZR4 zgIp^fqIEkwq;%)LXW(w^4cjM?U@uovJXP);2PJR?CGo!4cq~MTSja>8{8TrV^;^kjG%R{N z{R{KFY@ZtvWlHZfn=eNDTew>Qi%qGuBQH|?T*`iwGw-(d<@9yQQXzq?bHR={V>@Ug zAY%o-%1yh*5g|wT+S%c_=Z?cg1G8yqwA)7~M|i6?Yw&c4&XFF=4%0+(A}iQ$N#e+u zUqA_TWv|JxM&q_TLhQ9MEN^=`4r&7k(zb9LO*l~rR<#q5pC_ase=F2zeyRdk0D2GR zY^}Z1lye=^y@07vH^mZ!}n(MUG5;{HFYDC^w<4 z_Vjg%9LGGfuUD9M$%3W8oVwIC2#k#!t*(uN?LrVn&8e9$*6IWsx@7d=OwqIJ{Cw)g z{h2v;2ME43VaJkXbxiVj!b6P_R3#t+eG>~@JeE@_xElVhHT)vzDE4l<_unoHG(u|Q zb9zt`$Xl8SB)4C^N%u78##2mw1QU6Z5<;zUis#*&`C8EAVf0+=&ns(Q!+-*P2w6$* zt2X4potBet*C2T!s-Wkp*yQT^L}W>u5FXvJ^yuphAJHatZ;%$?N2V>8MKBYJr6ZN$ zRSj?{efo}Vh808QDS_)=^akG$NozR;g@xYq!cUIgpBl50 z!s3V)8dH0WmlT(Ac$DgM86tAJsg1zkkSE^IfA9B|GE;oc*wUWT#w*t1{AHF0_{rw8N$gPRb~U&FZlZs@x}JjwXsNUvL?T~f(R zk`hTW%=aXld6WJ1%0BySRjnh**GTC(kCrlYGp#|gqp2wwE6l3^M$sZSfS2gZtH}$K zLD*)?V&u1fR^*Ga8zKdf*}#G(QXP}EjJTaP$%{;ku!w}oOZ?dP9gtD#GiS^o^K2;_ zlwGymzhuXgZWh?on-$!z>MiG5j^gjY*z|9gLLC7n{6fm_vbu$p2e;?d4{NUrf_6Xv z(>8;n0{pRjn-!Z1XE3Ut6G1LN#~T%PHc4sGI?mJ)7STsfp5L8^@3&JR6qD$p6Zyg1 z)%hZ*$k*$?sB+3)h$F!S;}12VNP2-Cx_R!S1}cC`KjTCDk8G4bybXA;_)~^e*5+QX z5mFZ!x-wg#wcMzAT)}I8K1u-aihw`$<#Y>V*R(#?Oxu#W!R$g{I&5uy%t2>d4t!=GTp?d!D z=~`ppW(|vtk%8rGAdx|dstEWA@9>FW0KG^00Q1YbR-s|d9M zgIz&A)fj#|*9Qn7eL z_A~{GU6r{B9|rQ0AGc0a{+#Ga9g6qP^bmL?L;AP)dXFU}FD8bamU1Y=zkXUIDm2sL zP1@?2bg*avg3y1s{3J|3Pu0uUS3`nqa7%?-pEGN$T>Nj{uE=aN_k;y7L;0_(q^e(h zlzrN60TPY#ztS>X8QS|Prr&3z#H-y^>`#}`DX~x~06)_Jm!F(p4VN7$8lZu?{HiJS zL86e`sLN)Nec-^r^mtmM>LHEx- z$MTp@?#`fdf$O+2G~|9oIqVW2wY~g)Z^Wt@2M=D1`@X=B6z?LomraGr5cVYQ5!g$= zvy5!|-F#<<#+z>u4r4P4%hH_3QPbtjgtZW7xZjEpxhib@8!>W_RI?$iugr>k`9L4! z>Z9O-GoL@-%YtD{c1(ZH{$WV0Bt>e?)gLCTsu*C3SNY?6IDL+ZJEN9A>;kBxh#3B? z;FNWO-LYyka%;PdLRcH%Z@qv4`wRfYlYxbUFBsxtA}oDtvwVYJ=_wE4xWa0teu?XX zMdhS7Q~>(pv>LmUd4%;5L&-;`0Q|L<@b@*ujlHybB6w6`XJhjk>^~6VPxK1z4;b^f z=9+B|07F9_q?%ukK>~;0DSmc5 z4d-vVs}V8xDRA0!Iq>}X!BtH-RJwXceTKGC*;l%5#5z~HHt61A@q1Qc>+J$kT_1W* zS#7!?jZYtUUM81RVr9VZj`?F+Yr2nb$Otw(qzN}lkEEFnX16Oz3W;-gi$j)uYT*>t zo=HJq49vv30o(1QcGt4n1*Y_k&58}gQH0d-z$-SO(Jd3JRm1$kP|61*gK3wU8=_mk z`0e8vByNtKGNab#(NwoIk=?9vjzJ#I34A^-Z>M#0Od*a}x*pqVX$_+gi7;U#9GkHZ zk*hBIjXWut-Arm^-Z4@WVY<4>@9A(ZHrD!iHbRjGt~^%QU8azMugJO4U81qQnz+Mv z%=P7^ipFb3nBTC%aS+omn#XjRZWogq)n|24_{ZCwDR1SJ z=X#b*m&|Sb&ppNBJ0tIm4=^pl>yHD$;;?}_kx$IPhXeFXq6MuTaVOrDAXEJ0Wslgs z&V6oKrHau_WYE3D0K)rpLo5>ARW`e?cZ?L);j%Q_66OHBXe-@V> zi60FP4zA3H-#07{>k*sneHSt0-*8sraw)$uhMN9qEvqdk4YO>Tx>T*5VOR_By3tvO zm_HXAS^jFZPl&BDmCp=pa_9EGK`1GsKYm!iR)D{0RBB%4+Q#jk&d&j9d~SA8esa&- zTj?iMLSY5MvoG(wCApnvKkiY0NAWK6qaAMmJbR9Ke4pJOtj_>*ay00?9pANVN71-4 z=BYsWKLj{o#U$c;s|MeWY#-?LP6wV9LZm*{*8PiWSkDoXJEonGKAJ9NqJ8%eE9l+| zCvu?B|&04mM?&9+&$YNtb*` zjyFva=`Jug`=?wYeyS*qVZh+1;DThrz7dU@Z5g@Vo*>tdbFHfOzIMP%XmIt_{tTtm z%2AL^Y^VH#Z(sHchDciH!LvvvFxwPrBF4Dc5zwd@094;_&4pxn<-08|{F%8`85_{MCj|&-f1dyG?;W`9 zskfmjr}5F&|KG^-;z!~q!CZS`i9k|H;y0&u0lT4^{zEg4f594MEcyMPShEGp*J>Y9 z11qbFVNP=4I{a3TG3tLu7(ht>6L)G}P<*M}s%I((T2hI}{JpZ|3wXh%9V%WAVa z*R;Cd#dqoME=xch4u$>}uOSqBtNrTmYqB?J)rurM@ zT~^!d{+gXcqMy)%rZ_$L1f7i+KHRcNFM&Z75e9n6wL0q(0rcCnmw%hyUml{hnmD6g zc3FSIrmCN}D&udnN`!9!`o#%h$~~@tyW6_JPzF~hv0gKdhY=g#ofd-H|Cp`+@c^mu z+UKI#>}ba0W9QuVq;TZyUCm*;r!EQ>$~Yt9Bjrau>86#0wK49q{@Ba+2*M^bjF_i= z*aFls&vek1_C11>E4*n^F@<_x#&(w})7t;_MdIRXWYed0H^!w?nPH7x6;=0oG9xWz z`D1hC^L5OOu``%!7k(!2wqr_(i zn+kJ^u4B-rgT@!YK9yE?MQ=|YvX0Z^3fQR9ex16}M!*{7+Pvj{~pMD?-b-3&e; z!wpHV)<6s}LVVjG&NGk9#_~TU0dQ-pH=PZg(k(akdNMpYGYP+aOkeZ8`ovB&@b+0z z$k-ts2YT)%KSV+RmBUKWCdJHP!IM!p^HD zc@5*}p|lG3IUt6D?qlJ{mGI%J3Ad~GY~&8!zalhk?`XSdU|R5fJ9!zYJ)E0%p5V&O z6TiH(J+87sOqRvU5lerQJq3Em!Y5X&b|puK*AM0}NsERj@QQ%)09V=9dUh1cTgWnL z%Phmk_{1wPg%#q^TI-8$+U4y$dR}aRT0Ek-&nWLz{OUzS$3;R2mWKn=U-g4lLsW~vq*14 zd`)KCm#$TR6NZT8*N8k*t^aZ=3qcRqVZj}`aG)PA!k^P;fhDvDJ#(*VMl@J+uNv~+ zwAwg=ppS0+vq{G=18b*8Zb7Qlpl<1U5p$%^gKIPCn#znxN{NSQbbryh1yOM}R0KoG zkaN_E`%y3R(L--FwRsa!O05Q^$2R_UQ)r1T2cyuKHPbM_VoBvEVL;Ldv}{6 z&-9y&h_|orGHcjdDXT}{OZ?A&GB2y-*;rv;?}-Rs@=b`n^6gLs+u33C3IWD+U4yP*$BJ%HNczs^bUpXu;bIcN;Qi%u^EKP`M|{A{mriLi z0kIIXY`bCUTQ%W1tQ@8uBTz#X4?DrNO_O~rq&$yXF_hBd{_uXw=&tAx zC%uYgk|ra-#m((miiF_kj4O;19U@%7c4sXR_ah4Qc*U9&@jdUN<2KL|XC}h>!aoS6a5# zX;xGf*RyZpGX1N`fSEEww;JAPtwg2kcMjp*$2|@uFaMO4O;_?hf9YN``N4h|HM9HL zV9}4A*%li`N)TUAHOQIp``AO)riqgKXIN}VBFt-Fg+5mBG^%=i!d{|`uZRC5Q#C@T6Mg8gE zz;m5YbqyZle%3sGiq4qz+0M_wzHv3NQ#Vac311-ouClP}cT54bDeYmH@!h*c(w#Qs zBVZo&Jo3jl|MivkZp$hhi_`%pnS2MWX6N1vG_0g5$?(O^{n~H858l)yH6odY>!SQ| zuE#A^4{nmLg4ZQYknn?1o-lf|1t(EJJcj{?;r zeK^jjS#q&oIR^^ewgxKa5=8ig-ZVMnbad2$8Y|J3am|Z_N?etj3{H$sE{W>Y;I+1Y zKZcLU`PDO#l2n(T=b;zoixVF0YaJ4!q&)-3M(yj>Q~uR zdgm2)#V-38Rn7a(Gf@KW@Pm2umDvsKk4UkZ=ZetjYTi+diYgs5P(HeMso z;SFanO>v6A8X7l%>v4{CS41j0Y!OSjxc`~rv@wiCZJF%jxf?`#VG^)?bsXpFdJ?=N zIPf)v{KNWRMZ=yppff|>Clo6RES@v{bWPC0S&O}BjLz$3VnMQ|;d=yjfv)2gwqqZ= z-;(xg8c}lmn+_?Z@TTQdVr6qw+s_;-k@Q1~;Io%lnXoxW zjwtK{_9#r?9x&wObAjyWV6pPGafehiWq9X5Le8GK70vb&M~<>m#p z-xe{6)SzrKazVLc={x4dghky>{u+a3z>Ln4!{<|}#Hn(MTnGr~tn1s`vC{rIENMC{ z^u~f7*zq$v7nq?y$qSu+Cv0RlDB6aosq4bw2)Ey|zXt)>gefnTt9q=&N8zdPHVKIb zV`tSQ^zxG?drWp8QvX3^cGuS=e04+gpGH7IqTn9x_AX*NOcxc3rU=g1nb~{JfF-#t zeYvjh5>)j_svJf(@%9S>1>bU|8ABXg6QIcV9*p5U00RpWC-49QSel0Q99|6`h4MYu zjhn?3aRfs|mtzgok=5+Ce)A>TXlS2C7>6fx6auo4*&h~{{!Ew#@+A_B&BHsU8iCIN zxc`&{SV_mu_i_e-SAOC(r%A&+Iq~m*2v!p0|MVzTJj(A>B4us3CZs7nIeZ;K%T zc&-Jo02hOf-OXXZKeUa#3e_K7_)5ilTlSpvhDQx#SM1@$MTB8frwlUv8*c4WS=$f_7Du?eGXZKd=+%l?5&r}7fWg5*As+f% z<{(ayHLi1bxgMe-*x))4iG~wSVa?6lvyu!fz}l{J#K@ zk!`Jv1yQ+*%=78xMWYx$QmZ}}Jp{)txyr@mcJQ{9##`L^Q&`wPsX7ZI`k&C?PvrSR z{=pSF$xsZZ+3=IwibJ1s?C~IsV7oBalB zdbXhtZrS}pA)$p;^PP0XoiaQ&sm?QUCIrdk4L{<(~vM%V!# zizz@I;FGCm`IeQYGBf7#lGu!x7sc0fP1tu z36CRqx>@~#!HCsWQV&lH?nD=Y+sB|n%#Mgwva$_3#VOEte#5;DUl0XNyvw0T*5ve2 z#0&qYE%W!uwIxs@8C(8j?D7DaZi#LE_}&f2Q$}NAXc2JsiuX6=+I9gMdE%FcolNYu zeu6+&QPIyGpY`DqGNA5Y*y`;cx=Jk}Z?GJK4tI8SnttalNtN^wSyV(_>$}~SdgUK1fK9S90S9y}MQR4T5%>Anz2O32Ddiy#}f5 zyP-Zid)PJb6yK%RNe)a{P;7!Vp3+M>IX8p6gEmXWp=5{8CWlbmPK)z?EZ?<{wNF1_ zfQx}aFR%+=D#RWfzdL2~U{-Ol0(OC|;$t2H){g%WJ@a2vR7s+=7IAIp)3wgGQa6gN ztC_$dcR!vuSRc86ur`!AHqXsO#P+iK`A*(h`x2}}klN+<-RyYJ2>N+Mw5RAzxo^|Y z@%$Ejy>?jyXce#gx9K~c+KO{#^sh0Q5?6XB@BcqlZUm_V4_>if>00 zKk+xX=?*Uzh{6*_2pl1281v61SKfKc7f@1q$gBAB=X`iUN$qxr1UC8yBHAFzy7b2z zLjR5aH}(D2g%GN^%gu()8FBU(kubmhp^%ZLL8a=x-=yUAo^Ua?>$T zrkPs5557O-J=#zJ0Ux$;S4cl(dUv%iTKhi8kq;y$W0k1D`0sUs_43?PJk1O&8g+#pK!EZBZ!cwgzsIQ~VI#sA{Gl*bV zlERD z+1i5#qol|4X}v?NH&Y92AcUp!sX+!iwF(9Nn9Z-0z{Vs)bZk?i>KQ_X@~8b8N9-V9g&1~TxmLvt69&)R zr-B3fjNpRDuOV4@24H?k?Ds2sSa|Z42~)!>p4LCpt0-4wmyb-RU&U+HFE5m+mHpg@ zy3u{U3bg}!sOaZ?^Ti%ZX$qsZ&^_=mDze=wNSrr;OC-~%OaR?wN0ue)3aiGDy~+H> zuFIMUK$EQ_Y?n_pTRUi5`r{u6r~o^D z74zC1?NnB@xl(|VLRLQ-)hCsFb$L$*?4-@W!s>HP!;CWjJu^;ueucd{0?wV#3e8^{ z34Atq6KNyvZFJ@lGxe!7sz(O6GrUIpj^>a@5yEQHar$#?aAl01mBis+l6)&$2>}bk z&&v*zfD53n87`&fu<>apQk6*3b=BhYsqV~!h@r@8sQ>A$lw8s1#Hi&C0MzKy{}+JU zb73`lJOTc|aDfR8I?x-9+o#V81VP4lMH!fXlN5wI2WFr{{H!WP_NT6f^{|MspUz;C{^=tba5PUjZv9s3}Kf_GoXvd!IlsMcg;H$ztLnG zi;G}6BCnrDctQ~{8u-D1-gBveAW+KxfFtBpj6uowJ=ZBMD#4t;kGT%albltL)aBx; zvF0X5EBt*v(p~qddZYw+lPTNyb#FksxUd7vi-ETJrgFxfo?21qPSbLk4uyWhyJk7{8=uZo3b9>hRd- zidibRuqu0)ygZD)?_yD~NS_fB)OYsYd^hm<);p+&Zl?L|+v_!U&pHQ=avHX%&G9eY z@f8ZI2)QEBY&w-j`yG-H-&)k27riI5Eq>4-j<1eAh8)!D#blS8k|dTvMmXOSR~HI} z?wtYoAE-@}KMKEk0uMToJl@@$!v#*mxWQkmcSx!46s}EDbGYoZFf2)ylvg4n+{(#4 zMEfjEct0HtD(0R}5vxPvnro-FMT4gaBUKjz4>!^kuTo~I>|#VV#w%!SWVW>0Q6aHN z67XGXsZDKvrhYoQ4DK$oCJlf;!_bum;^^-DTHXEjxZ17l%zgSD@erNoTZ-F}ySV_4 zaeky9zjfIh&z<=``6|3c_Uo@TZ0$25sG$!U1sn7j=3KmRsx}xix!rzxtW%_7^39In z+_BuWl&^LTp{af);F(Nm&F>89zT}zPo~|VUD(n1{(aOW$=gmWVR&M1E_O!?H>j=!m z+TnM95=r8uwT}9I8CNpbzrbfW!jAcQ(|5%ukB}!$<0@6S9Er$vnH9oFCtlnsdM?HR zOvSj#=?aftNyv193chSNq1A5Efv86B)t1<%@&HNxQ`}Q3RFUfvd`mxnxjm{+>#eG=P6O z7h#VC(|_gVjt*5*`tw5SH4XrB4d>2APbFbROH5oSX zu6NImrUT{MhYvB_+u>XQ_qGp;L4>`vddnOZ77q_P4Y}*VLmuVN3&U3Sm3%Av&(EtI z{Rnx zab#t;PNbd0K0WzqFatR?y(3f=&(U<1KB10?FFsHU;qe178QJE(8y#FB9u1K-pavDx zJc8M*NpL(thaEdH*R}5+HsTQipvZ;m^;kdE^<5c4D!U0W^3Nv=GV_(#E#MDErR6_EshV+=_2x!ay08-n!E4NC028tiPoqn;3qZI0Eq_ zB2_z-HuI46^WNV^>ZOfF@(q0JPV?*k-)=wo56t|@r{%Z3&~%xTy3d|RPg>2-kw-&@v>2Xdb-gv&IV;Kfq;mN?m%FS*fir@hFY?LW z{k)LtXz}g-v{hg2Pi@&&Ew?=2Ri)kkot?Wb`|Y1_>)uDJ4Iz3(0jKs~ed*r#VCQqt z${Di{ufBy}mQvKPT=3oW^YgmQyr}dgZYQl7EdS2)*Sk}3UR`<(bCRsU-!Idf>p$w6 zSJZtxqA&FQZuRn&Z;MS2vVG!l@cUYjAfjGvVc=ysjS)2U@bqPT&1v3wzu)~2eAIco zZqoI#*Yj$$(mybM;&AZ$wl<8XuC+*)c^S}yr!VjSF-;nn(|-CfF%&&*yJo9demhy^ z2Ll^(z)sh{IUD#oN`d|3_`H8dx8Hfd*Z?x})(4CC@)isHqcjqX`fSZu?PSpL!c73&cU{WHJb}?Ay_);({jcvhuFQFT=XYdl-9Mmn zPSvR=GMs7zDr|jIzu37>|IMOZiZ5PCFrE)uux_!eZ0T2qhV%bF&RF~}X3DRxz-+nv zuis&Ylu1RoEepT0ubRpaocxKn8W=ubq-D;RY|Z1Zfq}N@Puav`mk?0Ll+!{%7Idz~ z29CZdroht}7V$Su*wku?>)4W(J<^JEEX+(88Lpq-A5;DlIC;Xo?7i6|p3UoLSf#)2 zJ7;$BxFd&V9&mq$pN#aZ6QVT?3E$q_?7X=-eR;2B;HfkFlCmauud@Uy|8?b!_Of$@ zr)NHzzo*na{Wg&2C-zXiWeQ&#(*&W4hBpV@yC*w(%>L2oF(Fv^{#t9R>%aqko?V~r ze}C8F&AC9kqPM+!k@FiQQhs>$qxYvb1xiPza?g&PkzO=()P*gLZ-M>EQrXO|LNx0WDWNzuXB&@`=O+z_{iXj z_?(Hm { const { act, data } = useBackend(context); - const [ - reagentName, - setReagentName, - ] = useLocalState(context, 'reagentName', ''); - const [ - reagentQuantity, - setReagentQuantity, - ] = useLocalState(context, 'reagentQuantity', 1); + const { emptying, temperature, ph, targetTemp, isReacting, + reagentQuantity, + reagentAcidic, + reagentAlkaline, } = data; - const reagents = data.reagents || []; return ( { {(_, value) => ( - {
{ )}> - - setReagentName(value)} /> - - - setReagentQuantity(value)} /> - -