From b09e519584d42db7b479a7c7d13f5f66b1862285 Mon Sep 17 00:00:00 2001 From: kevinz000 Date: Sun, 16 Jul 2017 17:13:03 -0700 Subject: [PATCH] Beam Rifle Zooming Rework + Click catcher memes + bunch of other random stuff that players won't use (#28551) Click catcher now supports mousemove/mousedrag. Basically, mouse location can now be captured even if the user isn't mousing over a visible location Added procs to allow for projectiles to be fired with just an angle for pixel projectiles, instead of requiring a target turf and pixel x/y Added procs to get angle of user's mouse from their viewpoint (Time to rework gang machine guns again!) Beam rifles now have different zoom modes Free directional zooms out and tracks the angle of your mouse from the center of the screen. However, you can't target with very good accuracy on this (Shots can't be properly aimed on non dense objects/lying down mobs.) Locked directional zooms like free directional but doesn't automatically turn if your aim changes. Center view, just increases your view in all directions (2x weaker) No zoom mode, in which you just retain your normal view. You can select beam rifle zooming rates to be instant or stepped. Stepped zooming rates zoom out 5 tiles per second. This will likely help with people not being able to use it without lagging because their computers aren't as beefy! Beam rifles no longer require zoom to be fired Beam rifle aiming beams now instantly update instead of on process Beam rifle aiming beams are now one object instead of 150. This'll help with the lag caused by it during gameplay that I've observed. Angular penalty reduced by 0.1 for a nice even number. Instances of client.view = have been replaced with client.change_view() as that'll properly update the click catcher Hopefully shooting yourself in the face when you hit a blob tile or whatnot is fixed with the new and improved code.. --- code/__HELPERS/maths.dm | 38 ++ code/_onclick/autoclick.dm | 34 +- code/_onclick/click.dm | 15 +- code/_onclick/hud/hud.dm | 1 + code/modules/admin/verbs/randomverbs.dm | 4 +- code/modules/client/client_defines.dm | 1 + code/modules/client/client_procs.dm | 26 +- code/modules/mob/dead/observer/observer.dm | 8 +- code/modules/mob/living/carbon/inventory.dm | 2 +- code/modules/mob/login.dm | 2 +- code/modules/mob/mob_defines.dm | 2 + code/modules/projectiles/gun.dm | 4 +- code/modules/projectiles/guns/beam_rifle.dm | 496 +++++++++++++++----- icons/mob/actions.dmi | Bin 195446 -> 195578 bytes 14 files changed, 472 insertions(+), 161 deletions(-) diff --git a/code/__HELPERS/maths.dm b/code/__HELPERS/maths.dm index c5e3a972180..41d2f721f59 100644 --- a/code/__HELPERS/maths.dm +++ b/code/__HELPERS/maths.dm @@ -182,3 +182,41 @@ GLOBAL_LIST_INIT(sqrtTable, list(1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, gaussian_next = R2 * working return (mean + stddev * R1) #undef ACCURACY + +/proc/mouse_angle_from_client(client/client) + var/list/mouse_control = params2list(client.mouseParams) + if(mouse_control["screen-loc"]) + var/list/screen_loc_params = splittext(mouse_control["screen-loc"], ",") + var/list/screen_loc_X = splittext(screen_loc_params[1],":") + var/list/screen_loc_Y = splittext(screen_loc_params[2],":") + var/x = (text2num(screen_loc_X[1]) * 32 + text2num(screen_loc_X[2]) - 32) + var/y = (text2num(screen_loc_Y[1]) * 32 + text2num(screen_loc_Y[2]) - 32) + var/screenview = (client.view * 2 + 1) * world.icon_size //Refer to http://www.byond.com/docs/ref/info.html#/client/var/view for mad maths + var/ox = round(screenview/2) - client.pixel_x //"origin" x + var/oy = round(screenview/2) - client.pixel_y //"origin" y + var/angle = NORM_ROT(Atan2(y - oy, x - ox)) + return angle + +/proc/get_turf_in_angle(angle, turf/starting, increments) + var/pixel_x = 0 + var/pixel_y = 0 + for(var/i in 1 to increments) + pixel_x += sin(angle)+16*sin(angle)*2 + pixel_y += cos(angle)+16*cos(angle)*2 + var/new_x = starting.x + var/new_y = starting.y + while(pixel_x > 16) + pixel_x -= 32 + new_x++ + while(pixel_x < -16) + pixel_x += 32 + new_x-- + while(pixel_y > 16) + pixel_y -= 32 + new_y++ + while(pixel_y < -16) + pixel_y += 32 + new_y-- + new_x = Clamp(new_x, 0, world.maxx) + new_y = Clamp(new_y, 0, world.maxy) + return locate(new_x, new_y, starting.z) diff --git a/code/_onclick/autoclick.dm b/code/_onclick/autoclick.dm index 23d07e29688..29a704ee7a3 100644 --- a/code/_onclick/autoclick.dm +++ b/code/_onclick/autoclick.dm @@ -24,17 +24,6 @@ active_mousedown_item.onMouseUp(object, location, params, mob) active_mousedown_item = null -/client/MouseDrag(src_object,atom/over_object,src_location,over_location,src_control,over_control,params) - mouseParams = params - mouseLocation = over_location - mouseObject = over_object - mouseControlObject = over_control - if(selected_target[1] && over_object && over_object.IsAutoclickable()) - selected_target[1] = over_object - selected_target[2] = params - if(active_mousedown_item) - active_mousedown_item.onMouseDrag(src_object, over_object, src_location, over_location, params, mob) - /mob/proc/CanMobAutoclick(object, location, params) /mob/living/carbon/CanMobAutoclick(atom/object, location, params) @@ -63,9 +52,6 @@ /obj/item/proc/onMouseUp(object, location, params, mob) return -/obj/item/proc/onMouseDrag(src_object, over_object, src_location, over_location, params, mob) - return - /obj/item var/canMouseDown = FALSE @@ -90,3 +76,23 @@ mouseLocation = location mouseObject = object mouseControlObject = control + if(mob && LAZYLEN(mob.mousemove_intercept_objects)) + for(var/obj/item/I in mob.mousemove_intercept_objects) + I.onMouseMove(object, location, control, params) + +/obj/item/proc/onMouseMove(object, location, control, params) + return + +/client/MouseDrag(src_object,atom/over_object,src_location,over_location,src_control,over_control,params) + mouseParams = params + mouseLocation = over_location + mouseObject = over_object + mouseControlObject = over_control + if(selected_target[1] && over_object && over_object.IsAutoclickable()) + selected_target[1] = over_object + selected_target[2] = params + if(active_mousedown_item) + active_mousedown_item.onMouseDrag(src_object, over_object, src_location, over_location, params, mob) + +/obj/item/proc/onMouseDrag(src_object, over_object, src_location, over_location, params, mob) + return diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 5c47e1f44d5..6029ebd3f67 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -437,9 +437,15 @@ mouse_opacity = 2 screen_loc = "CENTER" -/obj/screen/click_catcher/New() - ..() - transform = matrix(200, 0, 0, 0, 200, 0) +/obj/screen/click_catcher/proc/UpdateGreed(view_size_x = 7, view_size_y = 7) + screen_loc = "CENTER-[view_size_x],CENTER-[view_size_y]" + var/list/ret = list() + for(var/X in 0 to (view_size_x * 2)) + for(var/Y in 0 to (view_size_y * 2)) + var/obj/screen/click_catcher/CC = new() + CC.screen_loc = "EAST-[X],NORTH-[Y]" + ret += CC + return ret /obj/screen/click_catcher/Click(location, control, params) var/list/modifiers = params2list(params) @@ -447,13 +453,12 @@ var/mob/living/carbon/C = usr C.swap_hand() else - var/turf/T = params2turf(modifiers["screen-loc"], get_turf(usr)) + var/turf/T = screen_loc2turf(screen_loc, get_turf(usr)) params += "&catcher=1" if(T) T.Click(location, control, params) . = 1 - /* MouseWheelOn */ /mob/proc/MouseWheelOn(atom/A, delta_x, delta_y, params) diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm index 1bb3ba52234..3afdabb0ab7 100644 --- a/code/_onclick/hud/hud.dm +++ b/code/_onclick/hud/hud.dm @@ -143,6 +143,7 @@ return 0 screenmob.client.screen = list() + screenmob.client.apply_clickcatcher() var/display_hud_version = version if(!display_hud_version) //If 0 or blank, display the next hud version diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index daa58da386f..4aa98602512 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -649,9 +649,9 @@ Traitors and the like can also be revived with the previous role mostly intact. set desc = "switches between 1x and custom views" if(view == world.view) - view = input("Select view range:", "FUCK YE", 7) in list(1,2,3,4,5,6,7,8,9,10,11,12,13,14,128) + change_view(input("Select view range:", "FUCK YE", 7) in list(1,2,3,4,5,6,7,8,9,10,11,12,13,14,128)) else - view = world.view + change_view(world.view) log_admin("[key_name(usr)] changed their view range to [view].") //message_admins("\blue [key_name_admin(usr)] changed their view range to [view].") //why? removed by order of XSI diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm index 06e921399e8..51cf83d0ae8 100644 --- a/code/modules/client/client_defines.dm +++ b/code/modules/client/client_defines.dm @@ -49,6 +49,7 @@ preload_rsc = PRELOAD_RSC var/global/obj/screen/click_catcher/void + var/list/obj/screen/click_catcher/click_catcher_tiles // Used by html_interface module. var/hi_last_pos diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index d9325cebe5f..f4186f53f42 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -310,10 +310,8 @@ GLOBAL_LIST(external_rsc_urls) send_resources() - if(!void) - void = new() - - screen += void + generate_clickcatcher() + apply_clickcatcher() if(prefs.lastchangelog != GLOB.changelog_hash) //bolds the changelog button on the interface so we know there are updates. to_chat(src, "You have unread updates in the changelog.") @@ -644,12 +642,32 @@ GLOBAL_LIST(external_rsc_urls) if ("key") return FALSE +/client/proc/clear_click_catcher() + if(!LAZYLEN(click_catcher_tiles)) + return + for(var/I in click_catcher_tiles) + screen -= I + qdel(I) /client/proc/change_view(new_size) if (isnull(new_size)) CRASH("change_view called without argument.") view = new_size + apply_clickcatcher() + +/client/proc/generate_clickcatcher() + if(!void) + void = new() + screen += void + +/client/proc/apply_clickcatcher() + clear_click_catcher() + generate_clickcatcher() + click_catcher_tiles = void.UpdateGreed(view,view) + for(var/obj/screen/OS in click_catcher_tiles) + screen += OS + /client/proc/AnnouncePR(announcement) if(prefs && prefs.chat_toggles & CHAT_PULLR) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 430ee651794..7f24b13f511 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -326,7 +326,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp if(mind.current.key && copytext(mind.current.key,1,2)!="@") //makes sure we don't accidentally kick any clients to_chat(usr, "Another consciousness is in your body...It is resisting you.") return - client.view = world.view + client.change_view(world.view) SStgui.on_transfer(src, mind.current) // Transfer NanoUIs. mind.current.key = key return 1 @@ -468,16 +468,16 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp views |= i var/new_view = input("Choose your new view", "Modify view range", 7) as null|anything in views if(new_view) - client.view = Clamp(new_view, 1, max_view) + client.change_view(Clamp(new_view, 1, max_view)) else - client.view = world.view + client.change_view(world.view) /mob/dead/observer/verb/add_view_range(input as num) set name = "Add View Range" set hidden = TRUE var/max_view = client.prefs.unlock_content ? GHOST_MAX_VIEW_RANGE_MEMBER : GHOST_MAX_VIEW_RANGE_DEFAULT if(input) - client.view = Clamp(client.view + input, 1, max_view) + client.change_view(Clamp(client.view + input, 1, max_view)) /mob/dead/observer/verb/boo() set category = "Ghost" diff --git a/code/modules/mob/living/carbon/inventory.dm b/code/modules/mob/living/carbon/inventory.dm index 306b929130a..a85fca7c4d1 100644 --- a/code/modules/mob/living/carbon/inventory.dm +++ b/code/modules/mob/living/carbon/inventory.dm @@ -44,7 +44,7 @@ var/mob/dead/observe = M if(observe.client) observe.client.screen -= I - I.loc = src + I.forceMove(src) I.layer = ABOVE_HUD_LAYER I.plane = ABOVE_HUD_PLANE I.appearance_flags |= NO_CLIENT_COLOR diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm index 8e732940a19..bed14bdff42 100644 --- a/code/modules/mob/login.dm +++ b/code/modules/mob/login.dm @@ -39,7 +39,7 @@ if(client) client.click_intercept = null - client.view = world.view // Resets the client.view in case it was changed. + client.change_view(world.view) // Resets the client.view in case it was changed. if(!GLOB.individual_log_list[ckey]) GLOB.individual_log_list[ckey] = logging diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index 9809ef4bbb8..c9272c8d6bb 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -141,3 +141,5 @@ var/list/progressbars = null //for stacking do_after bars var/list/can_ride_typecache = list() + + var/list/mousemove_intercept_objects diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 5a21c92f799..39f08d2519a 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -482,11 +482,11 @@ if(WEST) _x = -zoom_amt - user.client.view = zoom_out_amt + user.client.change_view(zoom_out_amt) user.client.pixel_x = world.icon_size*_x user.client.pixel_y = world.icon_size*_y else - user.client.view = world.view + user.client.change_view(world.view) user.client.pixel_x = 0 user.client.pixel_y = 0 return zoomed diff --git a/code/modules/projectiles/guns/beam_rifle.dm b/code/modules/projectiles/guns/beam_rifle.dm index 0133edaa19f..704b27c5eff 100644 --- a/code/modules/projectiles/guns/beam_rifle.dm +++ b/code/modules/projectiles/guns/beam_rifle.dm @@ -1,4 +1,16 @@ +#define ZOOM_LOCK_AUTOZOOM_FREEMOVE 0 +#define ZOOM_LOCK_AUTOZOOM_ANGLELOCK 1 +#define ZOOM_LOCK_CENTER_VIEW 2 +#define ZOOM_LOCK_OFF 3 + +#define ZOOM_SPEED_STEP 0 +#define ZOOM_SPEED_INSTANT 1 + +#define AUTOZOOM_PIXEL_STEP_FACTOR 48 + +#define AIMING_BEAM_ANGLE_CHANGE_THRESHOLD 0.1 + /obj/item/weapon/gun/energy/beam_rifle name = "particle acceleration rifle" desc = "An energy-based anti material marksman rifle that uses highly charged particle beams moving at extreme velocities to decimate whatever is unfortunate enough to be targetted by one. \ @@ -12,22 +24,13 @@ force = 15 materials = list() origin_tech = "" - recoil = 5 + recoil = 4 ammo_x_offset = 3 ammo_y_offset = 3 modifystate = FALSE - zoomable = TRUE - zoom_amt = 17 - zoom_out_amt = 20 weapon_weight = WEAPON_HEAVY w_class = WEIGHT_CLASS_BULKY ammo_type = list(/obj/item/ammo_casing/energy/beam_rifle/hitscan) - var/hipfire_inaccuracy = 2 - var/hipfire_recoil = 10 - var/scoped_inaccuracy = 0 - var/scoped_recoil = 3 - var/scoped = FALSE - var/noscope = FALSE //Can you fire this without a scope? cell_type = /obj/item/weapon/stock_parts/cell/beam_rifle canMouseDown = TRUE pin = null @@ -37,13 +40,14 @@ var/aiming_time_left = 7 var/aiming_time_increase_user_movement = 3 var/scoped_slow = 1 - var/aiming_time_increase_angle_multiplier = 0.6 + var/aiming_time_increase_angle_multiplier = 0.3 var/lastangle = 0 + var/aiming_lastangle = 0 var/mob/current_user = null - var/list/obj/effect/temp_visual/current_tracers = list() + var/obj/effect/projectile_beam/current_tracer - var/structure_piercing = 2 //This doesn't always work! + var/structure_piercing = 2 //Amount * 2. For some reason structures aren't respecting this unless you have it doubled. Probably with the objects in question's Bump() code instead of this but I'll deal with this later. var/structure_bleed_coeff = 0.7 var/wall_pierce_amount = 0 var/wall_devastate = 0 @@ -60,19 +64,122 @@ var/delay = 65 var/lastfire = 0 + //ZOOMING + var/zoom_current_view_increase = 0 + var/zoom_target_view_increase = 10 + var/zoom_speed = ZOOM_SPEED_STEP + var/zooming = FALSE + var/zoom_lock = ZOOM_LOCK_AUTOZOOM_FREEMOVE + var/zooming_angle + var/current_zoom_x = 0 + var/current_zoom_y = 0 + var/zoom_animating = 0 + var/static/image/charged_overlay = image(icon = 'icons/obj/guns/energy.dmi', icon_state = "esniper_charged") var/static/image/drained_overlay = image(icon = 'icons/obj/guns/energy.dmi', icon_state = "esniper_empty") + var/datum/action/item_action/zoom_speed_action/zoom_speed_action + var/datum/action/item_action/zoom_lock_action/zoom_lock_action + /obj/item/weapon/gun/energy/beam_rifle/debug delay = 0 cell_type = /obj/item/weapon/stock_parts/cell/infinite aiming_time = 0 recoil = 0 - scoped_recoil = 0 - hipfire_recoil = 0 - hipfire_inaccuracy = 0 - scoped_inaccuracy = 0 - noscope = 1 + pin = /obj/item/device/firing_pin + +/obj/item/weapon/gun/energy/beam_rifle/equipped(mob/user) + set_user(user) + . = ..() + +/obj/item/weapon/gun/energy/beam_rifle/pickup(mob/user) + set_user(user) + . = ..() + +/obj/item/weapon/gun/energy/beam_rifle/dropped() + set_user() + . = ..() + +/obj/item/weapon/gun/energy/beam_rifle/ui_action_click(owner, action) + if(istype(action, /datum/action/item_action/zoom_speed_action)) + zoom_speed++ + if(zoom_speed > 1) + zoom_speed = ZOOM_SPEED_STEP + switch(zoom_speed) + if(ZOOM_SPEED_STEP) + to_chat(owner, "You switch [src]'s digital zoom to stepper mode.") + if(ZOOM_SPEED_INSTANT) + to_chat(owner, "You switch [src]'s digital zoom to instant mode.") + if(istype(action, /datum/action/item_action/zoom_lock_action)) + zoom_lock++ + if(zoom_lock > 3) + zoom_lock = 0 + switch(zoom_lock) + if(ZOOM_LOCK_AUTOZOOM_FREEMOVE) + to_chat(owner, "You switch [src]'s zooming processor to free directional.") + if(ZOOM_LOCK_AUTOZOOM_ANGLELOCK) + to_chat(owner, "You switch [src]'s zooming processor to locked directional.") + if(ZOOM_LOCK_CENTER_VIEW) + to_chat(owner, "You switch [src]'s zooming processor to center mode.") + if(ZOOM_LOCK_OFF) + to_chat(owner, "You disable [src]'s zooming system.") + reset_zooming() + +/obj/item/weapon/gun/energy/beam_rifle/proc/smooth_zooming(delay_override = null) + if(!check_user() || !zooming || zoom_lock == ZOOM_LOCK_OFF || zoom_lock == ZOOM_LOCK_CENTER_VIEW) + return + if(zoom_animating && delay_override != 0) + return smooth_zooming(zoom_animating + delay_override) //Automatically compensate for ongoing zooming actions. + var/total_time = SSfastprocess.wait + if(delay_override) + total_time = delay_override + if(zoom_speed == ZOOM_SPEED_INSTANT) + total_time = 0 + zoom_animating = total_time + animate(current_user.client, pixel_x = current_zoom_x, pixel_y = current_zoom_y , total_time, SINE_EASING, ANIMATION_PARALLEL) + zoom_animating = 0 + +/obj/item/weapon/gun/energy/beam_rifle/proc/set_autozoom_pixel_offsets_immediate(current_angle) + if(zoom_lock == ZOOM_LOCK_CENTER_VIEW || zoom_lock == ZOOM_LOCK_OFF) + return + current_zoom_x = sin(current_angle) + sin(current_angle) * AUTOZOOM_PIXEL_STEP_FACTOR * zoom_current_view_increase + current_zoom_y = cos(current_angle) + cos(current_angle) * AUTOZOOM_PIXEL_STEP_FACTOR * zoom_current_view_increase + +/obj/item/weapon/gun/energy/beam_rifle/proc/handle_zooming() + if(!zooming || !check_user()) + return + if(zoom_speed == ZOOM_SPEED_INSTANT) + current_user.client.change_view(world.view + zoom_target_view_increase) + zoom_current_view_increase = zoom_target_view_increase + set_autozoom_pixel_offsets_immediate(zooming_angle) + smooth_zooming() + return + if(zoom_current_view_increase > zoom_target_view_increase) + return + zoom_current_view_increase++ + current_user.client.change_view(zoom_current_view_increase + world.view) + set_autozoom_pixel_offsets_immediate(zooming_angle) + smooth_zooming(SSfastprocess.wait * zoom_target_view_increase * zoom_speed) + +/obj/item/weapon/gun/energy/beam_rifle/proc/start_zooming() + if(zoom_lock == ZOOM_LOCK_OFF) + return + zooming = TRUE + +/obj/item/weapon/gun/energy/beam_rifle/proc/stop_zooming() + zooming = FALSE + reset_zooming() + +/obj/item/weapon/gun/energy/beam_rifle/proc/reset_zooming() + if(!check_user(FALSE)) + return + zoom_animating = 0 + animate(current_user.client, pixel_x = 0, pixel_y = 0, 0, FALSE, LINEAR_EASING, ANIMATION_END_NOW) + zoom_current_view_increase = 0 + current_user.client.change_view(world.view) + zooming_angle = 0 + current_zoom_x = 0 + current_zoom_y = 0 /obj/item/weapon/gun/energy/beam_rifle/update_icon() cut_overlays() @@ -85,9 +192,10 @@ /obj/item/weapon/gun/energy/beam_rifle/attack_self(mob/user) projectile_setting_pierce = !projectile_setting_pierce to_chat(user, "You set \the [src] to [projectile_setting_pierce? "pierce":"impact"] mode.") + aiming_beam() /obj/item/weapon/gun/energy/beam_rifle/proc/update_slowdown() - if(scoped) + if(aiming) slowdown = scoped_slow else slowdown = initial(slowdown) @@ -95,140 +203,160 @@ /obj/item/weapon/gun/energy/beam_rifle/Initialize() . = ..() START_PROCESSING(SSfastprocess, src) + zoom_speed_action = new(src) + zoom_lock_action = new(src) /obj/item/weapon/gun/energy/beam_rifle/Destroy() STOP_PROCESSING(SSfastprocess, src) - ..() - -/obj/item/weapon/gun/energy/beam_rifle/zoom(user, forced_zoom) - . = ..() - scope(user, .) - -/obj/item/weapon/gun/energy/beam_rifle/proc/scope(mob/user, forced) - var/scoping - switch(forced) - if(TRUE) - scoping = TRUE - if(FALSE) - scoping = FALSE - else - scoping = !scoped - if(scoping) - spread = scoped_inaccuracy - recoil = scoped_recoil - scoped = TRUE - user << "You bring your [src] up and use its scope..." - else - spread = hipfire_inaccuracy - recoil = hipfire_recoil - scoped = FALSE - user << "You lower your [src]." - update_slowdown() - -/obj/item/weapon/gun/energy/beam_rifle/can_trigger_gun(var/mob/living/user) - if(!scoped && !noscope) - user << "This beam rifle can only be used while scoped!" - return FALSE - . = ..(user) + set_user(null) + QDEL_NULL(current_tracer) + return ..() /obj/item/weapon/gun/energy/beam_rifle/emp_act(severity) chambered = null recharge_newshot() -/obj/item/weapon/gun/energy/beam_rifle/proc/aiming_beam() - var/atom/A = current_user.client.mouseObject - if(!istype(A) || !A.loc) - return - var/turf/T = get_turf(current_user.client.mouseObject) - if(!istype(T)) +/obj/item/weapon/gun/energy/beam_rifle/proc/aiming_beam(force_update = FALSE) + var/diff = abs(aiming_lastangle - lastangle) + check_user() + if(diff < AIMING_BEAM_ANGLE_CHANGE_THRESHOLD && !force_update) return + aiming_lastangle = lastangle var/obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam/P = new P.gun = src P.wall_pierce_amount = wall_pierce_amount P.structure_pierce_amount = structure_piercing P.do_pierce = projectile_setting_pierce - P.preparePixelProjectile(current_user.client.mouseObject, T, current_user, current_user.client.mouseParams, 0) if(aiming_time) var/percent = ((100/aiming_time)*aiming_time_left) P.color = rgb(255 * percent,255 * ((100 - percent) / 100),0) else P.color = rgb(0, 255, 0) - clear_tracers() - P.fire() - -/obj/item/weapon/gun/energy/beam_rifle/proc/clear_tracers() - for(var/I in current_tracers) - current_tracers -= I - var/obj/effect/temp_visual/projectile_beam/PB = I - qdel(PB) - -/obj/item/weapon/gun/energy/beam_rifle/proc/terminate_aiming() - stop_aiming() - clear_tracers() + var/turf/curloc = get_turf(src) + var/turf/targloc = get_turf(current_user.client.mouseObject) + if(!istype(targloc)) + if(!istype(curloc)) + return + targloc = get_turf_in_angle(lastangle, curloc, 10) + P.preparePixelProjectile(targloc, targloc, current_user, current_user.client.mouseParams, 0) + P.fire(lastangle) /obj/item/weapon/gun/energy/beam_rifle/process() if(!aiming) return - if(!istype(current_user) || !isturf(current_user.loc) || !(src in current_user.held_items) || current_user.incapacitated()) //Doesn't work if you're not holding it! - terminate_aiming() - return + check_user() + handle_zooming() if(aiming_time_left > 0) aiming_time_left-- - aiming_beam() - process_aim() + aiming_beam(TRUE) + +/obj/item/weapon/gun/energy/beam_rifle/proc/check_user(automatic_cleanup = TRUE) + if(!istype(current_user) || !isturf(current_user.loc) || !(src in current_user.held_items) || current_user.incapacitated()) //Doesn't work if you're not holding it! + if(automatic_cleanup) + stop_aiming() + set_user(null) + return FALSE + return TRUE /obj/item/weapon/gun/energy/beam_rifle/proc/process_aim() - if(current_user.client.mouseParams) - var/list/mouse_control = params2list(current_user.client.mouseParams) - if(isturf(current_user.client.mouseLocation)) - current_user.face_atom(current_user.client.mouseLocation) - if(mouse_control["screen-loc"]) - var/list/screen_loc_params = splittext(mouse_control["screen-loc"], ",") - var/list/screen_loc_X = splittext(screen_loc_params[1],":") - var/list/screen_loc_Y = splittext(screen_loc_params[2],":") - var/x = (text2num(screen_loc_X[1]) * 32 + text2num(screen_loc_X[2]) - 32) - var/y = (text2num(screen_loc_Y[1]) * 32 + text2num(screen_loc_Y[2]) - 32) - var/screenview = (current_user.client.view * 2 + 1) * world.icon_size //Refer to http://www.byond.com/docs/ref/info.html#/client/var/view for mad maths - var/ox = round(screenview/2) - current_user.client.pixel_x //"origin" x - var/oy = round(screenview/2) - current_user.client.pixel_y //"origin" y - var/angle = NORM_ROT(Atan2(y - oy, x - ox)) - var/difference = abs(lastangle - angle) - delay_penalty(difference * aiming_time_increase_angle_multiplier) - lastangle = angle + if(istype(current_user) && current_user.client && current_user.client.mouseParams) + var/angle = mouse_angle_from_client(current_user.client) + switch(angle) + if(316 to 360) + current_user.setDir(NORTH) + if(0 to 45) + current_user.setDir(NORTH) + if(46 to 135) + current_user.setDir(EAST) + if(136 to 225) + current_user.setDir(SOUTH) + if(226 to 315) + current_user.setDir(WEST) + var/difference = abs(lastangle - angle) + if(difference > 350) //Too lazy to properly math, detects 360 --> 0 changes. + difference = (lastangle > 350? ((360 - lastangle) + angle) : ((360 - angle) + lastangle)) + delay_penalty(difference * aiming_time_increase_angle_multiplier) + lastangle = angle /obj/item/weapon/gun/energy/beam_rifle/on_mob_move() - delay_penalty(aiming_time_increase_user_movement) + check_user() + if(aiming) + delay_penalty(aiming_time_increase_user_movement) + process_aim() + aiming_beam(TRUE) /obj/item/weapon/gun/energy/beam_rifle/proc/start_aiming() aiming_time_left = aiming_time aiming = TRUE + process_aim() + aiming_beam(TRUE) + zooming_angle = lastangle + start_zooming() /obj/item/weapon/gun/energy/beam_rifle/proc/stop_aiming() + set waitfor = FALSE aiming_time_left = aiming_time aiming = FALSE + QDEL_NULL(current_tracer) + stop_zooming() + +/obj/item/weapon/gun/energy/beam_rifle/proc/set_user(mob/user) + if(user == current_user) + return + stop_aiming() + if(istype(current_user)) + LAZYREMOVE(current_user.mousemove_intercept_objects, src) + current_user = null + if(istype(user)) + current_user = user + LAZYADD(current_user.mousemove_intercept_objects, src) /obj/item/weapon/gun/energy/beam_rifle/onMouseDrag(src_object, over_object, src_location, over_location, params, mob) - current_user = mob + if(aiming) + process_aim() + aiming_beam() + if(zoom_lock == ZOOM_LOCK_AUTOZOOM_FREEMOVE) + zooming_angle = lastangle + set_autozoom_pixel_offsets_immediate(zooming_angle) + smooth_zooming(2) + return ..() -/obj/item/weapon/gun/energy/beam_rifle/onMouseDown(object, location, params, mob) +/obj/item/weapon/gun/energy/beam_rifle/onMouseDown(object, location, params, mob/mob) + if(istype(mob)) + set_user(mob) + if(istype(object, /obj/screen) && !istype(object, /obj/screen/click_catcher)) + return + if((object in mob.contents) || (object == mob)) + return start_aiming() - current_user = mob + return ..() /obj/item/weapon/gun/energy/beam_rifle/onMouseUp(object, location, params, mob/M) + if(istype(object, /obj/screen) && !istype(object, /obj/screen/click_catcher)) + return process_aim() - if(aiming_time_left <= aiming_time_fire_threshold) + if(aiming_time_left <= aiming_time_fire_threshold && check_user()) sync_ammo() afterattack(M.client.mouseObject, M, FALSE, M.client.mouseParams, passthrough = TRUE) stop_aiming() - clear_tracers() + QDEL_NULL(current_tracer) + return ..() /obj/item/weapon/gun/energy/beam_rifle/afterattack(atom/target, mob/living/user, flag, params, passthrough = FALSE) + if(flag) //It's adjacent, is the user, or is on the user's person + if(target in user.contents) //can't shoot stuff inside us. + return + if(!ismob(target) || user.a_intent == INTENT_HARM) //melee attack + return + if(target == user && user.zone_selected != "mouth") //so we can't shoot ourselves (unless mouth selected) + return if(!passthrough && (aiming_time > aiming_time_fire_threshold)) return if(lastfire > world.time + delay) return lastfire = world.time - . = ..() + stop_aiming() + return ..() /obj/item/weapon/gun/energy/beam_rifle/proc/sync_ammo() for(var/obj/item/ammo_casing/energy/beam_rifle/AC in contents) @@ -298,6 +426,25 @@ HS_BB.do_pierce = do_pierce HS_BB.gun = host +/obj/item/ammo_casing/energy/beam_rifle/throw_proj(atom/target, turf/targloc, mob/living/user, params, spread) + var/turf/curloc = get_turf(user) + if(!istype(curloc) || !BB) + return FALSE + var/obj/item/weapon/gun/energy/beam_rifle/gun = loc + if(!targloc && gun) + targloc = get_turf_in_angle(gun.lastangle, curloc, 10) + else if(!targloc) + return FALSE + var/firing_dir + if(BB.firer) + firing_dir = BB.firer.dir + if(!BB.suppressed && firing_effect_type) + new firing_effect_type(get_turf(src), firing_dir) + BB.preparePixelProjectile(target, targloc, user, params, spread) + BB.fire(gun? gun.lastangle : null, null) + BB = null + return TRUE + /obj/item/ammo_casing/energy/beam_rifle/hitscan projectile_type = /obj/item/projectile/beam/beam_rifle/hitscan select_name = "beam" @@ -330,6 +477,7 @@ var/impact_structure_damage = 0 var/impact_direct_damage = 0 var/turf/cached + var/list/pierced = list() /obj/item/projectile/beam/beam_rifle/proc/AOE(turf/epicenter) set waitfor = FALSE @@ -351,20 +499,29 @@ /obj/item/projectile/beam/beam_rifle/proc/check_pierce(atom/target) if(!do_pierce) return FALSE + if(pierced[target]) //we already pierced them go away + loc = get_turf(target) + return TRUE if(isclosedturf(target)) if(wall_pierce++ < wall_pierce_amount) loc = target if(prob(wall_devastate)) - target.ex_act(EXPLODE_HEAVY) + if(istype(target, /turf/closed/wall)) + var/turf/closed/wall/W = target + W.dismantle_wall(TRUE, TRUE) + else + target.ex_act(EXPLODE_HEAVY) return TRUE if(ismovableatom(target)) var/atom/movable/AM = target if(AM.density && !AM.CanPass(src, get_turf(target)) && !ismob(AM)) - if(structure_pierce++ < structure_pierce_amount) + if(structure_pierce < structure_pierce_amount) if(isobj(AM)) var/obj/O = AM O.take_damage((impact_structure_damage + aoe_structure_damage) * structure_bleed_coeff * get_damage_coeff(AM), BURN, "energy", FALSE) + pierced[AM] = TRUE loc = get_turf(AM) + structure_pierce++ return TRUE return FALSE @@ -396,22 +553,69 @@ handle_impact(target) /obj/item/projectile/beam/beam_rifle/Collide(atom/target) + paused = TRUE if(check_pierce(target)) permutated += target return FALSE if(!QDELETED(target)) cached = get_turf(target) + paused = FALSE . = ..() /obj/item/projectile/beam/beam_rifle/on_hit(atom/target, blocked = FALSE) + paused = TRUE if(!QDELETED(target)) cached = get_turf(target) handle_hit(target) + paused = FALSE . = ..() /obj/item/projectile/beam/beam_rifle/hitscan icon_state = "" - var/tracer_type = /obj/effect/temp_visual/projectile_beam/tracer + var/tracer_type = /obj/effect/projectile_beam/tracer + var/starting_z + var/starting_p_x + var/starting_p_y + var/constant_tracer = FALSE + var/travelled_p_x = 0 + var/travelled_p_y = 0 + var/tracer_spawned = FALSE + +/obj/item/projectile/beam/beam_rifle/hitscan/Destroy() + paused = TRUE //STOP HITTING WHEN YOU'RE ALREADY BEING DELETED! + spawn_tracer(constant_tracer) + return ..() + +/obj/item/projectile/beam/beam_rifle/hitscan/proc/spawn_tracer(put_in_rifle = FALSE) + if(tracer_spawned) + return + tracer_spawned = TRUE + //Remind me to port baystation trajectories so this shit isn't needed... + var/pixels_travelled = round(sqrt(travelled_p_x**2 + travelled_p_y**2),1) + var/scaling = pixels_travelled/world.icon_size + var/midpoint_p_x = round(starting_p_x + (travelled_p_x / 2)) + var/midpoint_p_y = round(starting_p_y + (travelled_p_y / 2)) + var/tracer_px = midpoint_p_x % world.icon_size + var/tracer_py = midpoint_p_y % world.icon_size + var/tracer_lx = (midpoint_p_x - tracer_px) / world.icon_size + var/tracer_ly = (midpoint_p_y - tracer_py) / world.icon_size + var/obj/effect/projectile_beam/PB = new tracer_type(src) + PB.apply_vars(Angle, tracer_px, tracer_py, color, scaling, locate(tracer_lx,tracer_ly,starting_z)) + if(put_in_rifle && istype(gun)) + if(gun.current_tracer) + QDEL_NULL(gun.current_tracer) + gun.current_tracer = PB + else + QDEL_IN(PB, 5) + +/obj/item/projectile/beam/beam_rifle/hitscan/proc/check_for_turf_edge(turf/T) + if(!istype(T)) + return TRUE + var/tx = T.x + var/ty = T.y + if(tx < 10 || tx > (world.maxx - 10) || ty < 10 || ty > (world.maxy-10)) + return TRUE + return FALSE /obj/item/projectile/beam/beam_rifle/hitscan/fire(setAngle, atom/direct_target) //oranges didn't let me make this a var the first time around so copypasta time set waitfor = 0 @@ -423,6 +627,12 @@ var/old_pixel_x = pixel_x var/old_pixel_y = pixel_y var/safety = 0 //The code works fine, but... just in case... + var/turf/c2 + var/starting_x = loc.x + var/starting_y = loc.y + starting_z = loc.z + starting_p_x = starting_x * world.icon_size + pixel_x + starting_p_y = starting_y * world.icon_size + pixel_y while(loc) if(++safety > (range * 3)) //If it's looping for way, way too long... return //Kill! @@ -437,6 +647,8 @@ transform = M var/Pixel_x=sin(Angle)+16*sin(Angle)*2 var/Pixel_y=cos(Angle)+16*cos(Angle)*2 + travelled_p_x += Pixel_x + travelled_p_y += Pixel_y var/pixel_x_offset = old_pixel_x + Pixel_x var/pixel_y_offset = old_pixel_y + Pixel_y var/new_x = x @@ -473,23 +685,21 @@ if(loc == get_turf(original)) if(!(original in permutated)) Collide(original) + c2 = loc Range() - -/obj/item/projectile/beam/beam_rifle/hitscan/Range() - spawn_tracer_effect() - if(!QDELETED(src) && loc) - cached = get_turf(src) - -/obj/item/projectile/beam/beam_rifle/hitscan/proc/spawn_tracer_effect() - QDEL_IN((new tracer_type(loc, time = 5, angle_override = Angle, p_x = pixel_x, p_y = pixel_y, color_override = color)), 5) + if(check_for_turf_edge(loc)) + spawn_tracer(constant_tracer) + if(istype(c2)) + cached = c2 /obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam - tracer_type = /obj/effect/temp_visual/projectile_beam/tracer/aiming + tracer_type = /obj/effect/projectile_beam/tracer/aiming name = "aiming beam" hitsound = null hitsound_wall = null nodamage = TRUE damage = 0 + constant_tracer = TRUE /obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam/prehit(atom/target) qdel(src) @@ -499,37 +709,67 @@ qdel(src) return FALSE -/obj/item/projectile/beam/beam_rifle/hitscan/aiming_beam/spawn_tracer_effect() - var/obj/effect/temp_visual/projectile_beam/T = new tracer_type(loc, time = 5, angle_override = Angle, p_x = pixel_x, p_y = pixel_y, color_override = color) - if(istype(gun) && istype(T)) - gun.current_tracers[T] = TRUE - -/obj/effect/temp_visual/projectile_beam +/obj/effect/projectile_beam icon = 'icons/obj/projectiles.dmi' layer = ABOVE_MOB_LAYER anchored = TRUE - duration = 5 - randomdir = FALSE light_power = 1 light_range = 2 light_color = "#00ffff" + mouse_opacity = 0 + flags = ABSTRACT + appearance_flags = 0 -/obj/effect/temp_visual/projectile_beam/New(time = 5, angle_override, p_x, p_y, color_override) - duration = time +/obj/effect/projectile_beam/proc/scale_to(nx,ny,override=TRUE) + var/matrix/M + if(!override) + M = transform + else + M = new + M.Scale(nx,ny) + transform = M + +/obj/effect/projectile_beam/proc/turn_to(angle,override=TRUE) + var/matrix/M + if(!override) + M = transform + else + M = new + M.Turn(angle) + transform = M + +/obj/effect/projectile_beam/New(angle_override, p_x, p_y, color_override, scaling = 1) + if(angle_override && p_x && p_y && color_override && scaling) + apply_vars(angle_override, p_x, p_y, color_override, scaling) + return ..() + +/obj/effect/projectile_beam/proc/apply_vars(angle_override, p_x, p_y, color_override, scaling = 1, new_loc, increment = 0) var/mutable_appearance/look = new(src) look.pixel_x = p_x look.pixel_y = p_y if(color_override) look.color = color_override - var/matrix/M = new - M.Turn(angle_override) - look.transform = M appearance = look - ..() + scale_to(1,scaling, FALSE) + turn_to(angle_override, FALSE) + if(!isnull(new_loc)) //If you want to null it just delete it... + forceMove(new_loc) + for(var/i in 1 to increment) + pixel_x += round((sin(angle_override)+16*sin(angle_override)*2), 1) + pixel_y += round((cos(angle_override)+16*cos(angle_override)*2), 1) -/obj/effect/temp_visual/projectile_beam/tracer +/obj/effect/projectile_beam/tracer icon_state = "tracer_beam" -/obj/effect/temp_visual/projectile_beam/tracer/aiming +/obj/effect/projectile_beam/tracer/aiming icon_state = "gbeam" - duration = 1 + +/datum/action/item_action/zoom_speed_action + name = "Toggle Zooming Speed" + button_icon_state = "projectile" + background_icon_state = "bg_tech" + +/datum/action/item_action/zoom_lock_action + name = "Switch Zoom Mode" + button_icon_state = "zoom_mode" + background_icon_state = "bg_tech" diff --git a/icons/mob/actions.dmi b/icons/mob/actions.dmi index a9651492cd0743d031e5dc01d29b0c8609dc33bd..6742ca68c771f99bb90d3e515f0c9da07a48e054 100644 GIT binary patch delta 17297 zcma*Oby!s0_dYx`bV!%fP|~GzhomT=(yd6hC=F-mE|CzWQ)%h$kVd+@o1q!t9X`+V zd*5&T{&?rQ&biLndG=asuYK=(?KwZkxxT=OVFH`PKH9VZ7?0++-^f}h~+vPTBPuvM?G(HCV)dgEHa!r;lcD=;%f;DY*}bSO<{ z1f_3UIwGPYzq$E506s+1(+a1LTV&i; zPE(3q{~jqVn9n&pJ=vJYoBe`pyP<7D!^|xhImx8yur02gY5h#WdBE-zIhnwCKxQQ>2oS%O#u=p< z?s5*m8ddV1H}TO3UCAZnROEcy!e7>E=Ay2`lbi&>v!-BU%7tMnEHnDCH8kYFF9OTq zM6&Y*-ph009&>FUgU^)Usj;uaGd`v&CF!%8m*v@SCvtz;Kwq&%0E!}@cNs(PsxzBUc!Vs z7P?E@v@e&M`REu<`L4!J+4N7jPqcoxm^+Ycj}kb{T&}o8o!$k#KDTgqGLd|w8(=OsABB1^t{V3UkFrMeT=%?gJ6MMraDlsH((m{r-Er&*dBd+RU3&Ig|Dt3UKA zUTsNi4EJA>tBIK7O@QqiDLStGlY;gyi2_%+Pt3!f!@rT>F5DacNJ5-6iO+LLzBS0o zyh9dW>P90q#}W5F_xik4zln&3te0K!XACVp-labYMPE_4-YA!S>Hq$jS#`75yWtJ! zu)UQZ!mH%|YR60MS}SNxhCIu5!}F^zo3T)0O#IIL{FAPz6=2vvwqFlwyTEn()(T~M z;#L`3$e8y@;bdBM)M!Jn)}QA_VO8ZAc>HmKGR#XGC?Dq9+I}2eg}YOF*Iv6eSro)s zSd2O+d(Ze~*|97lmf=(|jwke7v-Mxf2ptGT7>tbU6o`TO> zQ8KP$1E1eu76BBs5n&+5T>a+Pq)Z|KR@l#ZQ)lbXr+4QA}*_^^=cy6Dm;26Sj_373hUV3 zRsAOy!`CWN5)(%O{$D#w3}vh4-rBRd{I1NLm7N1>eYQzk8yPM?3EW72hz;KnA2gzg z3AX+oQxS-Z-y|qYn{sL&BPtxd^}DTNDWJRCP;r^d$Jf^@yX_kLsRTYIpw7>k4FBY9D1Jft0sxQh zCq9)ZnuFogOq(R$&zwtA(&C=5Ud?&awm0(aCaS&FCR_1EJyonDuZNGl&kfuVesHpS zd=Dbo`H@z@vY_uDgb^Hs0j>_hfDBdu0Wf-00+K@5U-O^X@+V&tRvz(p=~JDLt0K5|_^KTV{|g#Y%9*sU_|~+$G%(rb>94yO^I7 z#lU?UPiE$)zriK=>i>A1G}4sta&sGH;|MSk_F%IZp%$0?lreu1mbP_54lFnW*DK*X zr?mlksE}ba+5yu8gMk~Ja#tSo?A+^smA>BIPlx;*0m+-U`sNXVmsClvG%M$FQ1nAbS=cJZ*XiF|v=YPz7C zV|J`Q7w_yb{8+PIqn_a?*`^ri48S6G9DOx9HlbywT>Ej*)ai8Vb+)*1exnjt9aLJ- z@+etQZt?Iu6yaXYnL%s`t)sG`%CJS$BcqPPMfD8eGEBPKhz9r4 z`a(ppYUIy<6`X_Sx`!WI1BQp!3 zxy6}?%@r?+ao1`=i#rkS409hF#;;6EnXBD4sHxKL^uI}~*9d+6K@N#ItJ29SEPR<% zu#U=-v8C=oqwHuuRSKpOwB?=SF&(DcI~EW6dpB3>tm$IQ;XGaKU_3mz_!3dJ(*6?l z?`OCAOxdgP({1)e(O^1!I-WWJlStOg%uI3xWB3h7mJNcDo%>$e`j^@PeX9oq>b`=t z{Mlrbm^xfqZAwVw3dg&U{&^5Z>OG^HxbN@Z&!~kRTht>a_vdXWs#IURkk!|xs&hTG z7cH_M(K~@}kLG!&hP&B~bBiZTK6mFV2`+kTT()AkUe-wjQBvj||>N@MY+?Zwy8_ zwr4BHX=G&*m_tYBWLEs~B~4_jy9QDk+ql5h^J@d7A1+MMvSVY`+@0kitGC2yQXF&q zgu;db?ARIJ5dlnU@0-^FqeE!Kcd-CByiv z4iL6ri)4<>rm*EZ%=f@a)1u^N2fS4!|gjZc6L-wuU{;zBDjzZD>U7L_sav@oS)^zXBM zEmUZ}je?c}gnh@y@3ouSqEYM-@dq;|lMz$bd|0D;X%TgcSzpDoi;WFt1Y%QaG_v8S zE!*A;WbSl#5>ByoKMBBPKGRgIlUm!1AX$( zof-s%U=06qdA~S~$LV!tmYC5BaRk2q*c>Y4?Ff_R&rDC3MuX{oLs5SNCk3_q#3aFz zHbQ`<@AF5KX8xvr1C6nQ1eq0<7gI(+u)eIBr=@H!F3^pBeM-l|&aJAjU`DxN`_%CJ zX(tPltpI)uwp9Mf1)N8XfrC+oJOE=S`RqqaZUUY@8vSc67YP6HrUejs_g z=D3SW^IEsuT%gK+J`AZkLnhHcd&F$jEy}~S+7;<6K2hVedg|0e#W)i!t3krB22FV{ zm^+{9ZR~X%Sd^wttbF6r0Ue0EKqX?jgOI8<7{1OJ!OSe9vJ!1%WJIU-V-68Hd2lQ-Ht$DS@XE@H^v$uU1acoY%?7hw=One^R$SpFL08 z=axjl3Vq$7Ku>et8v*te6Exa-=nd^GL2^gN$cdBeP5fJpECxKSrLvo{!?H&i%G8ux zP?pSRQpW$guxjl}7{`Or6xXbTspIW3-X;6?3wMg`%S(K*PTh(P==Nlyf4$wIrl-oN zFA^D6u6)TVNhuX#-*sCA3@E7&GQ1V>e<-U8Mv3#ig}hC8-hwY_luM1A>2Fnnx$i(G z{Yv|(3GuP8p=NO_eFRt#l@7GG(1_uAu90Oi^yzf(8y=`;BiRN7LZ+Br97wnX!Iu;M z#A(K|60LvJmH)))5L{AcVElIVVvA%%r?3apb=6#&`0c4FFhLv8)93ti@9A2?8$qSYv-^^ff;ITNw9d2^$m8= zIGj9GS`6}aT@AR7``cJAH0F`bh$4`un!YiHMZMi~G@BLxy_x%k`LOz<<5Ix7x|ruY zc8jjhcZ*-t)?*} z)X}>qJ|gQz{Y~y-aB4LH z6)}WR$)3fXI(@$I#BjpyN=X*aDoXg!( zr1_>$Zylc-32S+ktt{<_VLw4G*QHXb%iS5r%BTu{dwaGYEG+zI{E|YYt?$e1W~EM7 z8A9J4E5=+t_*}Iq^3nzAtNkzl+symbBP2lENtG5`29gy^8Ddc5XpXyQnpdO5q*n&4 zC_(!BHWvtG)P(r>Z9C_}R4JYb)inDHcPYLrh7ZifAKb*LPAb_U+J$b~S9|4Z#}oPv z%gC!!+t@pB$9mD(=j0DdEVL!AHMkVxY&Tfu){htfsh4KUiGb6y064Cw=urBxEymYD zyxYpR$KAmnluzyE>&6vPPwd|5@IaddOD$iSNW;-RK4Qz5!s&I1yenDeB^hEIaN0et zE-QWIZ6GMgLh5~NV*x8H&{tYlF`S{27mAhtt4Jv#UOX`1{hdTSJM_zwkqgzLSw-M~ z_L8t!^je8^LtFLrLpx2P)wBQWLpI_QIhaWNkFmA1v>2)yY2xGKRf7qhl~=OG$u{4U zLp93+^|y?&)sa?sIxsk0_$b=Bql6|XSlFlw>$2?JV62%6)|$eZpdnNYjd-cF*C?{1L`WIl8ddI918EfGfZpEln*a}B$K*7d}k zOr)Oh#spTEgmi_yPF1L_il6UiSZC)N+A5>YV1rRwEYiG#1Z=bzSy;#wqiN+;Rk@>R z3NDVZXFC795~WZ=B{E;AQ4dZp0;X`EJP*PhDG>fFOvtKtCF5p*Y7+Pb>4eoacT%Tx zx)(X>1EmzypTbBl&!w1t$kMmfK_-Z;(5hhVg^sJ=Q;e69*K~3?DPd1o^Pf0)*{AI{ zq@a(^&aaJL`xAmZN4rZw%0zlCw(t2&iRzkV`zZP1}VR@jnITZ z;`OW0s^dnGgaiu89qsQ0@sZz-nc`9-f=%S<6MVc!i{OdxEP7@4jp0sHa$0Yw_03br61*Oqm`wVeT%+>+x?%uUZvr1N$zIO zaTZR*1Qibl*T5qRWPyaPYG7Up*5Hj?F&{MbuyFQ%g=RI~VM^ZY@zuA3Lw-;|8YGr= zzK<HqA zk8yBtZmY=2$W{i$4mH3_mfnqNm}{OWzd3<5mUmadRoP42m4K@kHIW8sob1;N#Slu- za4mGKwKLP`>bQFr>n%>b$4oJk(Gm-)cWL<<<(6hK(neC}ZemwJX3$_}ybQ$sc4~Eh z?LPGXtB4AC8-dGhXkCGB7~F_YOitOnhd#r-A-f=RD7<$5wjguERd% z={;}|(uL?^ZlGO6aTTmu9={Zx8~+=|kvUUVQcm@NTXf_*5fjXuVkF@<874Li!zJY? ze95zAyxfGQ#Iwuxd%l(fx(?qfZOC?qvx?Bua)#{z1u^k=fQCucOO`gmOBFZ6FO6m&AU%%Ta?zIkS2MSSZSU3J}xXR-EFNS zzra-nB^MXL-rnB24jg6S%AqQHhQq`-En%&IxOn%ZO2%h?O?e{w`#Qov)9S9YofGKL z;}63RjeWh&Up4$IXOqU-Q8Z#f!1x5Vyb0^3b)are30p{*f-}MGJ*2f{)h1DY5b_ex z({t?IS2$Q|1;K)X&?TsC$*~6@dNqO*aP5`-OPvnc&aMvDmpywhF?!1Rkx+C2J*o5Y z8sSeUN7e@Th<#gzoiTeiZf@{v&|S$BvXQW(Q!cEiF@6giJspX`-=LRDN@MMfAa!Fv z4v22>6A`IR_kp>XbgDZ!mC1%8X<|hqs~KBi0_665xO>^5=|h~uJ)wP}R(4R>+dS3n z@pKUGr2o2n`l8djAW2sutpB)yAA{YY-c{tZ>t7CLtA`RUO#}ZTH(@ks_ib13*wF?1 z`jsEXln;A-#mQECH91B?ibA?%!USotDD7pAJveSFMjo7Z`lFf^zV)6lUnH$ z+?l1^OW!e+DBK~_rDge*5t!Ed4A{GnCU;msEKAHIs&Ku&kpD}u;ikOGaMnVc%MCD* zLaMZ&EvGdXqn}=VNLwAuftK#w8rFyQuFQ#NTC7}LnpF;qQAja|T-*O1o0!PV$N<2k zq@+;@mr47y+t)h|utmM%a(VgjwNJCPoh(--AyrnU)^-#ts7!rC zQN*7Qlu3f&?m|tR*WXpdccAIuI-g66V8+?4KAX@+v$Ec9xwdO`I{MBzcTo4L@pD(> zP6t~#SG1jty+6h#9dgQpK1D;1{0ZT@M!-mt>V|CJujyksN&(s2 zpufK9a14GzrM|~Aq`v&o5iA8RnJnw+C7JssJs9Xb=DXt!eAnwimST&Z3jW8;5B89=qN z8oT!~qqrCk2~H@m??@6uGT#n_pvUBo`!2aw1|Lm?Yrk_fct#Sf=-{KDwZMAamn7T( z?{$sEB)zB>%z8bp%Eh&VOKWHMcapG5#Ut&`L)i7(%`3CZ7(fs7peJwIVEmt*&n~`W zrw0O~H>cJ7P3shG`_*dN30(TcQIrDMNTmhXJ|XD+!-(|4V;WwcPqK%yMi2bfIte2G zkYkkEwEQ*=5Jjb7TUIO;GTk*qA?iO#MDfw9)%wfDXXiy^e)%rMcIVV=HQWmP! zTKZmUn4JQE2{?Rsn2Visrd<&u9GTiBMs`10gEpSp&j~;5b&*t>u~^dGpJ&&2lqEqY z_$1^!f4gxmtXZSi&(vv+D^&{6jVe_dZGK%eY8Ghyl<+*4dl_+_7fuTiR`I}G;s%>Be#J`j`;&k6 zFfyV2Cz%%B(@iq2M3>weF4~LJkMd9I=Tipc{*@?1%N;nUt}Jy$PoNzE6b5J{D967G zW`L#lT${t|>O`rP(cPZNPBfX6&93Y5RZT~-&kGEVAsQaq zlo~mS@IyJ*rREzS43@*0hyiGHclLLorKw{)@yCgnXzVL1nae&>_yEm?Btaq!tqkij z^>3Jh040lPW(FufB)UjOB-^FEe}Y;6UDq`L?Lbb^GM9n(4Tye;9W{qN{3W`(D|utv zd1q4CErnz@nN(w$l#$N{EvY)MQ?IS<^`a|RqR|+H4${|~2pfaY@F9V0e~Os)eAPZQ zAwdR(AMDY`H7#kglRRx9Pd@NXA`!_)&x!*U4C+j>n}g%xb-UjZhsPkK@7*_PB4{Nj zQ84g2?!Mmz@KN~=zDRd|#CzI$FZc2#?w7c@vh!_h++;yi-EX>XE1l6!Hyyq`z5Q*! z&HBdRx~S(SZ*29(RBdlNsXvby@6B&TU{*v>HAB-Fd&0$Ca3|_56NSbhGJtQ7bL|+F z_Jp{RcIByLkK^o#|e4Hx{xEtX)j$FrAuMdCKT!(!c zy{)|1{TxlNFJc=|R0*rcX4xGHf^n;2@qgje#}B3O@k)LE^`m(tH?Xrcl64jjim+Fnz&xO-`@JFa)Xv^Zl1)l&Oc5!56_hZe@+|eSp(;RZ@Sy3b* z^x{#v{4TisFnk7RBgk9@0faq5DGQCO+>PK0ONk{l$>hSnH0&-GtXe~!=D=4-mmp3WIs_a@jz~qRmnO3Qb~tTpbVD$$o%iMpguc=3m`p`w7QB+mTqMbjwapKacks{=|t3k6#Mb8ySC269H&KcEn z++RV(4HNOVtyn%x39V_ad_2_oB%NmFliOk1cqI(Hv~F?mS{dZS!U*QL2XfuPe{L=+ z^JGpp_RnfAe6=~#fXm(g#_Wf~)@}O>L3<<+riL z>gC{6c5+Z?{A=WOYi?3|sWKnq6yokYxzhJt;6ncEERCv4TpJ`y;c}SXHFQU>S7HJm zG8C{uX~%AC`pF${$MyX5)#snp^QeepF1KX2d^XDkY8NW0y#DlNG!SPy8@7L5Z z;z@~diI*a=FDOPtr0&YyfJA^#@I~hi>ycbBXzr$k13M6= zyeDz7vfA4>G?(RLI9V7jE4G3!tcFUrMEdFLkD;JVox_)`fl!<$Yl@KbF15YcYWyLI z3yXGB)-meA^JjZgz8h^?zh?*`wt@USl1l24L;a`3?>dld-Y3HRaH%{uxh1aZIoy`| z+~Nd=^l7}p*?Mx3)O9qQ^MlTw*u;n#2&01Tbi9WzZe;;h;3Z>3nBd01_dF7E@&XpL zMdxIUvl#J@a=RMC^{x(St0{xZa@q1rg^9-MMkyltML#68Q?yPj*8ilDq9vZqK%jub z?nDtX5D?N`pr}&ejs|rPX`pV2^@jAvRpEKjcN4pv>A`6BnpKg?mw@>3N%P?LAYpBkpp z(b@a>RD2>-@=wYXIk8wd1GjnZJhe30#SR$=QkGDlam!}szCwTZ>&xN$~7#ZO0@!_AF#;gFi$M z9P{=0t{1?-TZ=yxQ{5oWo06DSN`nWRjcGiPNbcv;7UQj>si>em zp9`TRJ_}Wy&GsOFeD7NUT8}OI_3gYgt;rH&=!xS|xO}s^^LxTN#s@#}euQT%jq6IK zr%NbNZXUv)_;en^1faY|#^J~V`+KQjUy@6tOH!(QLqL`zCGAa^p>RFV=u<;l6< z46X!FMt)f5T!|x@J3Z851*L|=&xEUGWH4avMX%IBoYB$p_-K||q(9WNj_21#^KGKL zwD*&n?aXb6o178Cdu|}`68`;Jot}0H7n_&Yp(Lks^Ut{hpzhTxs_a{?K_zI2;{9UE zqAEV!1B;8>D5{qUY}txnNrZP{c9!W0>@vhP3h=0Bi^F_3R!$rKjky|A{ElLK&r9^C zqGZ~&gUHXZY}z&aBDLtEf_nvr!;f&CL5*(d?4^wjh7Fu)2s(S+X??HU#GWRvpQuB8 zu}2MT3G5SF9bNh6?PQLqepm zZ%6D!R^LZu{5ccl?vz1Z%X^3D95oSfc!#AX)z&CDM+7#aHA{N?dZ z@(;<7a4n~we|>?U^NzBSUGqf)-@-kZ#?!$%$lZwWr=8{b@F*w-h zj7~}O!CX?+H%)bgl>Yu(wAM&>{#U2yq~f{uT)!MDQP$Ty^1&w?mdMb#)3YXBiod^L zBaJ35&UfO%w|Hgod*9gDE|KALYx5T`l)n2=g-S~kn|L%Ue!U9F#R3Z8CPSTD!m+Lm z1s%|liHRUuiH3n#jI+^z#V*Wg7Q(6N>7QRNsib_odiGDFqFOWfXeiK^GV`}!H~OuN zJsKycWefxa+GydFV(`qE3+Au@CTTz0-!nqvIX?I3)zO%!9h$9~U4sp*YmK1{^jMY< zo_pH-qXEaDO-`N>9@xfiTZ~LV*vGap=_zSR; z2_up5ujTjaxHG`DQP|?d9gag+_e$U3fk)1vzg^@vkfW=O^G4m}fxy$ep%wVKy^{7I z68J2!Z%N0H4{ue{4Av9yE))O4iMtddfA_pBQ;XIMQ{bzMylFXYu6khVG%u416P2Y{ z;H_61X;d|P)8$;dW52(*cQK+I6*NlTloxe-hYto(NdZ^9w!0@`>AAzJ-O-bcz8Py- zofie|7_N$GyZ0o2%ajqv@vShRM5?9vZz5^Hp3~aZYJ0CZ$%YvRARkEE&_j%*Mpk>^ z-NEthto?mjcVXBPZm}#UsK2{oH>2@6;Oa?(-k0S;(BUZaj_~@9q zzC7jQ$4}dc_aTkcCi8!$Ek=kZs^s(Y12 zr9f;B2uhJ7k#)U7K|w&@uF}vD`7ukZ*Z1@v5)&wvWBuPQh$t&zW&RTkU6cRyJ)wLP z*ah=jZ}fX&Me4Oo$=DFC{?~W<_Vp9}tM>eFe1}i?t--|XvQMrWE|I^r30065a=+W(b}_#>F!bzmN~)uy?Sz%$oCB>HIJf_469mwhrOOC zlG^RVDZlP{%=*zX}yMNssuwF`J=rEhwa@cz$wy*82qw4JpuuMSc5sim2Qkdw6Hp z(9?1G#c}QIRk6odZg$f~;+JmUes7hDjn&&j14?$2%iKMI#s!k=)%%~7OpqMV2gh0i zO@v_etVEFa?eGB4xWw(C_hbBd#1~_Hm6^L!u?sVbNODWBP&tNJC8jTq&I_90V4TE0 z&75C%_fxE4Z#u*HiQFd*1a}CUc{uJu=H?8Ze;*$oZ+#^yx8^>Fhz**%_wcscUMI`>vfa9$ze5K%>!NP$TDC<{8zSBiSP_x;H`}7+dN0ji=6^5QWMS ziTD{Sok09ZKSO=akGCF5=Kkk~FLmR_A1dS13=dTDFqNyyzQvhsdiY9)@Kew;*05)K zn&Yn!S(e5p*RccZttug!3G4t9wK>4;mdxsKi|?0jW>O zk~6pIxAhZuS3b8npa8AV0@kqCgds*hRWhTvAnzK1G;g4`GL03X z@;(~)ij=7IFx2%tx4nIV!17*wKEzV|F1NjHA*S6dt+LhF-=-vG&y^1^5!vSY*`|nb zNpnB=bcxV69m?2Ke=(h?e=~xAFL_f}S2wd6JkMR$o#fq(9N$$d{KHdj1+@}H;KF@^=*=M z)_4pzu|H7mue9xwoHQ!9emE11#4q-}mNs8%{P7$>xcA>(mS^VxIq!~FI)A-Y3yAeD z{|?2O5AZ8fON}i4%~R6ca3{W)yL&i_Day{?8~c8LZx4BRCAmWSGf>*{7Y(!0dommC z+D&V7$+@9V^9hlayu7@oN&@HO_9j(f$rluNm3+m74VTNp{Y{P^S8*z`RfYG;1?{FR zHXV~ZD?T6K?YG!YDW~C_XZ=fR{BcXAno0PpUZC zK5o4iL+;OY%tmi(Ch4CDxfZ5QqPX3|dDz)c`sCkVtX6wpTLqfl zaDKR-wlJOq7Wv9mP;Jt>O!vb#EcnUudUknAr249luWtfjaSlGX{tES+uN)7Vg=Tv1 zR4!>ln}aZ|%s?PwnTHT|m|ja1CT_epDETt0JCNgL_wTy*imzY49-ntz+^@#x!8C5L z(3>xBZW?u{j1jqbS#UGWaj17fLKzArizPUr#-V#5{M4~{`mj>^COY4z@0}rL;9JbF zLE{03$wi^$=lKDObT@OoUYg%vgB7NcIa_UBKM88A8w^$KjaWzevY%$9xgUMM!~t(=klg zQcRPo$d^S8)tHP<{ra7|aEvrmYUXaIpajB827r$CN)E+8$fI6|rnyS=`fSpAL$xpo z_g>XJtvpS8{yNNX-6kbyW>EQNTiejjLv3v|Oc5x4T3JC0D{|Kn0SwGI733k7mUnXF zJJb;!JowHucWl3hhBBOYNAOtA!ReFrre|=eWWBlxxriV+OuT`#e8D#Dxsyd9fo7U* z?Wf6(I#H6%j$tiwi7GT`AVQsSrX;Dmj0&EU1~~|}=jXG39L)L|z5qB}nzrA*I}`9O zvlK2~Y29;a_*fVmO|VKBDpk+GOL4DZCiE;DY(dF?f z4;vdBmaYwX#%0f|lZNkE5+(L>q74w(l-sz9O|bXl@a#A=VppTw`SjqYZT{lY&*3bR z6$M`VqlRY9Ir?F^DW;-bOlHVv9D%*?__c=h$2i4 zyq((Zaf$Ofnw5HR@SXP6%u{4bO`APF_C%mpCTDu3-J40*T*03YKV&I-JzWf3HfM-v z3NLj1h?HTxWOZ4p`(8sK&2xAyym^P{)#=FQ>Q(BghpX+BoJrJdQ41re8u)7i@)UpX z$N@8X-bPaQwD*cI(52A6oDXBchiUJ3_xE-2Kxgig>oi~z82ll|wQpg8w|KtmzzTZ% zm&A5v7V^O+<-H5k4()f=u%m(ei{wiODvrAs3K1ACg&3f;NiF$w;v4bjif+(-H&A2) zz*$>ci;UmY)m;xG9%3jG>rLfJRI8Ra#-7RxEEpS$LNcirax_({qE!ccok`XAK8Un#e$Pd^DP`bVD zd}P0xAv?(n-ca*8gr8JOj*OM*AAFxm(yP-V2mD3EV9m&xJC_|3*0R2K?9Y6eEY48+ zhw-$Baca$lLqrwV&7@r_^9N&#-a@S9_jq0sefJ&@+Dk7^7UwcksADSJtYY9Nay=S~ z-oEi!O49*=y96V6Dm5$DlO4iaoPE@QZE%%cx#OnVIdUT4@Yec9{>)ilVy`ZmxgcMG9T1vtfI*F9*~?pgtF}E8 z0Kb&egI0%KP5WzvxPv#L7(_nB1>7SIB^*_j(c-nrO^dIycGqIIBZe85yR}}UByT!I z_vP55QEt@~Nk?uT^MOk1KK4|L?0rCcd@d$ceE&nlHOMT=rMS83Fh#N(O)L+-evJ{n zE(t5Sdq;cVbL#3->&AJ2PsUnInCuD+30V2|;_#k(*ArL1Uqrr$+H`x=C`4$30dQ}V zgCGXq@deVqVZ%Xe_t9p9hsKB9n~=e)+uhqjGGBsR2&^r(R#{T0$FPszVR#UEqXr2N zbnm{nDKyNuWT2RRUX9QsPNO}>SUM`@F&#C-vw*CJ6}X zNY~uzqPjVjymurgeX=)3yHicwRcr=~cVc`GUzbCCuD#t+m|vwp+N=Y`m&(J8J3`<= z!o??*Vb?Gf8uL+JujehNG@p0CxLX;c;$D_3 z9;|}3^S!juuDm27Frq)TgXKd_w1iJT6(8G)8mB1?b0gQE>dUu{*okr!plqYeTSl)* z1Fpx%-@1K*WwH#XcyIJ-(11N8?g8@MJ~UQinl4|$R(MFx2g1~uFVL7Tu*LC*41PTv zLozhnuYQlQh#$iao2G?vj^W1yq-SB9yrx|kl*nIPp&D52?CvTsy0)M@?i5;&4Dc>j z=*X3)h&cLbymKx_o-@ZG-inEL22Si9Y>)N!JL7bkZ0V6~l;Q{8lfv2?f#ey$woel0 z@H5J($nY79C9Nivxz}L-vc&B9BS~PQ>dz+VP7l=@bs(f=*(6*V{pP?z1J!RwfjXsX z?JkMy&&(Ia3MgtJS=d$78vvf0q&x0 zENaEI_DfMH*Qye+QlP@F4=}t@_=8w;`YlGDcaFpj0|GIV_j3(*K9C29haTy&JQ}%S z)<0Gt48AI?Zujw5d}k9^Y~IdzK62QG-&}kadT1SUc6hmHA?eOUGV0 zJl(s^3OdXV*l-~M_L3W|mK4yo=PA89oq{5TADhxO_P0{8FPcwZ@b^ui93ph89mg_J zWgzyQaj4wi&MB0}&Mr41~>vLTD4ocTHKdG*Vx!jx?2R(;Dg@`nT25 zEwc^o<%>iP$Wy14(KViHWXC5T74>{47pj>#&S1{s?!YOkh{8hgXjsmt5P`3!_L?(mH|EMjKc)eGHfdqbMg7Dam}O~ZL9d10*= zL-sYhipA_K48x!_Du;Xrx6K-FDex59<{@8VaTRn&M7RujD_zz7fkR+^TurK1>drA7 z)82shWNel*DX64Xux%f^KJ#fl;Q@f$y#>5-dTx~nRWZ8nnOX1tGPzh6nVFdhYi8t> zgp`(-^JUZH*3(a_&$>Pf-ue>f0pBPuf8#yVdbDzg4_vmdDMGy~ARy+KNu`mbzA)x< zHxJ{P`N2=1q{V=C_c*c1eZ{t_Z?{SVone<))wjjs0H2uQS>u{BV)Fd8s)J91cV32Yo{-dnq&}fl9-3nQ-uHde z1cx)bhC9P|i`&O1*BDh$VBK=fK}4$)>V6+_d2ku75KfCE4mz-rn|v+F+ln?VQu=*p z{{RccO?NaD|ED+Q5MHb>Ah;M-%~b+SrU2T;Kyv$)<82PcFh~-?;r9p}e%XA+B6u9F zD%(O7x;7V(;D*C;8a&re)waMS>$Ljxx0;|^38tq%cAoc4mnR_K<0D+`J91`0Mc?)1C7gm zFg(|$Q<8wT)wEl3U|F{DZqx4;es!$^#w;2Lw?X%sty0%KikSDHN-8L667|QHm?+ZM z-ef~i0DrX6c)VsMHe&S+G!+HistuD14R?SPQPbK-5poP7)mSy343a`R9w{QXuQ|64 z)!yGwwpxqsJaKRQAJ+%o#3l|gLKG<@tB>q1k|q}}?hw0U-*^Ya`KNTL1gZZ!uRbQ>Nrx!@XIHVWLAaBS^Rl~(}oW)qc|h?LjV=j>gzhh!cop9cmUPy+2A8i}0Z8HV~lxoeQ;*wX)!OE|dQ^h-}v68J~pNaO7oe%UP=_%qOBHX(;4 zF||C96xr58rA^8x)Fq_NCnI^u<~VN}K$%b{Nl&LUO!BVsKLwD=r~{A8t)4VM7WLpyU-=j|W8Uw-d4#La-SKrr54L;ryrbge>Hg`4 zA(9I}J@yg>c6)Pih?|ED)emXLS7tTq)>O-RKpvPW)*m_dwULS< z=%@ZyI!#4M#i(r__YZ2qJ>mhqTfV@m5=|P|?3)=$6U6ZZ(NZ{-N|&lBX<=Zoe0)Oi z&lkrs_x7r~1Q;Mm2L`NGb!lKhn&{($P=$F{Oj`fOsiS8nI*0LN=3`nOIK!f{@u+ zbVB#Z(edd(+O0@Azt-L627AG;EF(>Z`XC+yB!NA-!~c$l_GLIAouB?(166iG%A?|A zgrWGp!7uE$I0X;p_S@xD(I~Ybtixy`>MloD>^hMwmu&Dv{DRPb(*x~a-70Gn45P3T z`K+CJK762fYHLa%0q*)6M+FA%@LhaNH|M+T>VGY@gF;`kg=sIzXj3x>VPM>KZAtinC=Cfl>AXG-g7irsQBn-J)yp(#E z+8*G4=TXNL87v}?hj3VKsU2U+fD{XyuL%in^!7mhw?w78)ZOn5=D#!Q^1VJNEWoIy z6I$u`XJ!P7)H}e5{Il9k;hDbfHf=e{|La*gu&Yq%1l)6fG%E#q>&hfnW&vzSM5Vp~ zI^porkuN@?|BuP8d9}VK#9TVN=F7BqS>7 z5>9t=UN$>b#rv=Hi2y$`n8I>b+@W^m>Du3?D&O`QkXk!IeL=|j&xCm2BEkd0+PSj0 fkoZ4s@!Ui0F9|54%n06skUwR4Rk>nW6Tkll?Ls-n delta 17120 zcma)jby!s0`sgrpHz-{S(h5j-cXxvV(n#l~kp@MOE(N5!yL$jZx+SD@r~&S9&UerA zJNMo{F3+=vJ!`$I-i|f5SC~*JW(e&P#GT#E0qLHX;W6N-_93JbC4iSN7-BokNO zBWQe)LXbn?_!5io0w3L-b6Fq_YrSxU&kge;dmT*BK>vTnC8@wQ$oOx>6S&(^zv5RImWc!c@f&I zd)M7Wdf6DZg|nZyEli(JBDp0Ln}BnCM8EW0Q{s|9^S1>Po)3vPn1WkVbp_9{p{
  • DeGhl1<@&ED&WFwJiA_ueBGu*uj!FnTk$2O>LPsQTqM%O`C}62YrK`7tiL< ztx@ZRQk6A1M$0vS4pkNec1uC8KB|EgwUDtQSqog+Vt6Ae;2Edk?S1I1 zxxUnKI|MT&IlgjjUGOw#ggn#;oMhtu-5?VrW%9UmTgDl$c^}G8P^?7XdqB{m;Rk8y zp9z9k`eo-x5Z|Jteh}+>aS%;Sv`qMDB5;PZ>Qv)0EBzSlQf{@%^HetC^D()V!i zu6Ru5Q4+7)gPXlhPsj~5^01{VPcCHb`9AGOX+#%#|8sfT0`b?W)r+R>oHpmUHVxe3 z0qwJoe(vpz{w$JbInnBG&xMCOlbq5N2Nf=ljtDGeT>u+)TB|bLx5vo=+6!X!?xynV z+gt^qm$&D?UDB>5n7s!TCq1B@K~_^Q2jRyFj4{;vMkoTjR?X+oeH_2CcRxF@ujlD* z^6p8f&Sh=oy0ANreYm7beV;CqmNrW!wa+y*n+WDUCJwLsMoN0W(tJ;CDRVez{do=+ z6mFN^0ch)Oh`HE2=qOwY>=Mw4yS|D(I`g9QMlBGzI=sqnx+#$^`0?3^q=iG5NYXL z7jYYK#oQ%U@`4EHJS8|>u_e}~zd~hFv`n+@2e5yKSX18fZbY(9cK3wkJ+Hh%e=8@N z=d}z{m1GTX3Z(Y((Yx!;>VQ9_;20Y+voynqI5H~ znm6{nFvQ=JtZ^jgjYvw(1~X$7jQouWaAPx!5kfS4S<4MtEE1s_W&X!l5kspR zUz__E15|ci-QvR=v+T5nN3R-)1m_JV9cYgLqmGNHH4}Wl<}`om>OpCDD(ecILCHF0 zxdn-ER8w-=coiRBIm!%KH+^#h=WhL3@Al^VQIEVfdGtAKGd?l_bfT`a>0k=UVfNVM zD`~Ou=yd|z!NCMt9Ap$X1k0ZhBCqN@jXY0}2a!=lvweS8?3Bm`+z*a;{Kf0!q&gVk znhI$&#Z{uRBGinUT@xBPGfeh3hwhI053H~8Ol9>z#+-n5yA|UAp$BS)#RR?=dMte* zv8WNTs0a3xa8DHosvvioJLY;Z@UN_X+0(0bckAY)L28ZQZrNAkp8rqR|}acOu}wP z{rvj)SUM5?c~vv`f_jyyjuq(w?bmwIkMBNkTuop3wjCqix*9P>&h;pSeTZIhj82$*2MwamX|JIuQ|29e4ul5X zp5M|0h^7$1G?aDnCMYokrkPmNZ&=)cfe)}NMUHSOv?z)8+Du}f(lyKMnl{9nZhRdi z9UYy$nXbSJ+4!r`Ne`Xfs^ED4a&6elz$?0klkhivfG$$=<(^sRZ2o}nwv8amgjumT6gPuQo`ICNTG^2j#kOBQy;u$0xuJF)eVEbc3M8x}Mw0glqDDM$`|9-fl zP+9ZlH$Rd$$a_*6NWf!$_39K~G%y*Ar-08#!$XXyq3Qn-7yUQk_3jr{j0(i`tTjC( zpYHadA=5oe?B{QKPhiykXYxr&No$=!h~XBk9>*psG~MrO$sbmX#HsIM0=Wr33yra8IQv?*y-qBSwZUpVdG>m}plYf_`&zvlp}Sd=LWBO<^9nxar1fG$s+*l#AZ~q3}k{K1f7T1qS)T4F)Pb+T|5TY7O!Ia_Z6V zxd_yBd9?*2Y*$mub@Yaj<7tw@55Z;|rjP+8B#`D_HZI~A}eRs0vrWiLXx^U6wVYEi8cUTN3HSt2==zzU}zZdu- zU}9pxdAq9|8oBH-cX zNFVmL$9b^&Y!RpY>;gLjh8a7MQqJBeF>X3hQB&kV{ZvFXt$Q9&=T9^ubTJbcLgx$h z!q-2V*tigibU^kBG2I=4`3RsC**bGG%cLXhR=p3h^h8P@97mK;pqjg0+LBSKa&xv+ zG{gaFTgRlPnNp82NXB?nMGjN0VDj`u2jWmE{dx3>UQP;-aV6)G_AzL}i z8Iz=lcU4H+!Dhnoqp&ZucQlo&%3<+s%(K_Q{Mk*zK&$t;UjPa&RZM@sOmA!je7eIxAW`fz(!MD#TxE03|TjhI$C5NF=1{# zh#f>h`heolrL7tM`bygyPvz73!h-XiA|0t zOawfgnryXtyD)@2M4`gNo~J z3hG#DY2GKD4lpoL4r+~?xx|0p)9mbgXV%e~w1syfshY%uYMVYWw^SZ23VJ3i(NcH` zk?VxBQ!U#Ah#ZUu@;F`z5%w*fsIeCCfhwVbj9kZfK!NaaeA@Kv{*YtX);^uPo zZx$5phzNoLb@+{1JUJ8;6qKY>Y^ZYaf^>Qyba!r)axnF+@@1;84B%JDJ$pCNQaO|e z!)Jw}_ws*NmdR~}r?P_fG#SDZSYncr^o}iuZ~gDw zXN`e~ma}tp$~C91q*t0mzge1^>ZqYq0-oRBnqzvgLQyg>f)QhBN^IM>Qb(b6g-&%(k=Fko>Z$7$91B?2=MmV<^f z2FBYGm$|9u5erId*_jKjor|(~pnznp>>+ks>#vIitA&p9)X~~bv-=zIg@6or3xJvQ{Mqt<6;l0RFx{%_IxE^IVj^P_5jb@~tX4&+UT)8fiHw zSlabmPE_<$KfkuYo1-o~*_^m$0Mm=>=#W%bSBp7_k4n+hJ#PUeZ|7`-08T<}obwdEmPHD}VCZgXP?mO+6!-v2%@+<%p)Bkh1L7bS-S$GihZ}3JyTb;TMTds<{fZ75 z?XSoDqL{{-or(sd;!i1NNlF7cB~mRfD$as01Uo)*zdYtf<2 z{iZ9T|F3Cmm;VI<{AVXmFy9OfiWAhZ`dRc$OycJ1-zKG`2vSN6jwbgjVcb8M`e|J@ zUmwlzO7YOO6%&?hSSC{b*do7DU#NQ1E*LN757`lY)wR1KVs+BnHt&mm zODuSyc zG6*m`4#m1q85GkQw;7?Es0Mw{=&&nqLixh@NHh>PLn|nVYByUx*%ovVp!3>r@h!!~ zSSE20qDGsrI~{Sbl|%TKKY!jaFf#h`K7*s{Dt*<({H5NhY{E4SB>PKUqCC=3WbEZD zptcf`1&rWwEP?Mv31=%#i{7uzpFT2o+bH?gTv^PP4~pE=tE;Qyt08INP_z8jDfd(L zzQ3Hkgv1L4>QpgD$K**8k`=C97;MXg@lKtFXg?hi~m8I`P6vF5AUVk^~v{_S< zh>0@L9%&lcMJ|myjyrzkAg4J_!??%YuF;ZT%tcaMOr!j_*KCVB;CBl;>8nF8(RM+c zp9TUbbv%bBL`wl*l9O+g4Ggx6!#lH)BRhUMu-P~k53J{#uCF!RyX4dZ=){Y~E;m1Z z7R~9zBGxJMT{{32BDchG+%tLGYQ!49*lQWU4q<@^Yv&NrfrUD|gv`v4eA#$9IJMwJ zyYWIk-1zg75{m(h&gEoOBsrmDAO4wEGJID%Lm&fCU#15{M7=kP0B4&40`_j$h zugl%k^hM7)G5qeR2>_K`Jac1&{m5FdVW+uH!uwx^)aLMKKCR^WW>j?2fT_3i-xUv(AyBnM(v@uGiqK@WbDogs z5K*>DoHzx3;kE%X&)4n2ft$fbvAFk1`ug?ez?yLR zytbJ3hrrhL>9Ze_eXn1Ttx9=H`tWcHH50EofyCzrJ18&)qKzRZf!i*wvI!ltyc zD^C`k+Vi-1XDp|23k=9sJsv@4(8GDnu!94N1Ngt8FF;gtGyOH}9CC<*O7qbI?F1TX z>7W4!wpTgwp##<(?Z;q`&@X5rq-;}a()OI@Zh}po>wzC>LNXDx`_s&|VP(Khe4Hbl zPJi}m%kWj`b1tj3@|GhFgf$!E%xttjzKGSOUKa(GFiFECpkYB!1P8r1Dw1~ij$R5o zQ<^0N>Fl;@U~%Y?kjIUr42xiJe}Kw~@lkbpLcjKn96(b+?c16O6IGYAo*bqLY7ICz z^*DR{A0s0quGLqlSsnE7SMn>Mg_FxWq#d=r6{q8rt17OiG z{tal5wG5D?U-@(#)Iw%(YT!q4O1xWLnVZFyA_rO&5j$9jNOW9f}+#&Cvolvrw>f4-E^AF5o{GU;TAZ|CTjPboJCd zr=Bm+v+W(eO0h?og|-pdX+OCW(?A?$Plv5-C>>{#Yh8Eg`wEs%Q8Jn-#^YcuAU)k> z_)unitqT-*d+Q@iVNZ%N1~zDX`}!($){t!w0S zLp(7s!iAO563{WNp)Gkl9M9to1=J85s7~O+ZB@f_WXX zCS7nIQxg>vth6YqtW?YGJ;ev;%efuiQhbUf=iS>p;We!uYIsEB)nU<)?E9%%cwwss z3g7QKqnkKx~5E){Gg6!w?rVV6}>OAnn+!0oV#JUFw2g75f%ic@$={S#S8Eaj;lv;xV^Exvn)^7J;K!|{U@b{;-?exA(VI3`e)+N3Oh z2p1@i2-Vwzg777z-{IG>=CSi~ITfs4^sW7VSp~+_+)^C&qR-}&(vH~oxUBzs^%D+R zFH~RFgiVzZ3nv6KoDR7|!Ks{z6f(`cz=3aG*3)Du!P zY}PiqNK-;@P_Vnh_iPOvB6hD31KaD5Gd))#t1Jf=nsERXa*Jpw8V)qigSp%(Rd4U6 zhZ>(t+n#ew85q8G2pa2fhv8vj!l!qAW`A+gPqdo?0f;C){`GnU^{tTgYqF3Ef$fry z2#;BS4BbiDS9B4GeoX&bN!(4bQD?_ab|RY6K|}WrfAr)tznRyjUoo$*U|a-2@braW zR?V~6E?s~!y7=SGzeo2DIuzm7(D=aonj!IT#>9m90f&}dkpG;b2Eg_+Og%7`(_zcZ-oR7+2u^ICcpW)fLc&k1!dso zG?5?x$+xFY<8=iO0<`@o$|R8C+xECWT3A@LJHE{e(pX4aO$$-F4KWrA6tOHAK+rpv zAt51Q*1~$@b79j)=L46d}9WibrP#_nxEO*KdfG{rdUsdY2X1&O5`+{5-2TY9nBQfU4{om$;sk~+z3AV zW%?p^duj95(xhXl!YR_{JBvbqHJuuR#LoDPP&4_r88s<7H6rLte-(SbWE~OJ8Vgu| z#sA7UhKvUT5f!KRA^kCwD?M=hV~#5u=SA+Ll#&wG=PzHXj#A%Xr3oP2bKPwYrHFJ< z5~Ab*NyX}b}888h6MeFgf5Qd=B5Mf8sr$1>I_YBOMQKnBU6KXx@9g8xUFN)Tn= z7)z>rz1b=*fxJF0<*`d^qiDiW?lMN4a0c^cg+3+`=Ns0lz3{Vu2rU3v;h*K{uz zJpVGzW&{1E0|9{zzI~f>uZVGf@PH^YiyRNaTMQRY+>G+*J@22qqoud^BJOa5-uQ6G zT;5K%>;@d(3oKg>>fn%@+p(>ccMtj0c9n;W)c?t`Rce9OR96QZpr$MY@nQF&wBT?G zQZo)Dl8%k@6{A0l1oQb*l9Fgzl5AO2nIYW2(I!%$zlnXtN8x5U6YzDa3zv3BxUbGjnVbKcUoR9|j z{rW4~es9-?P-`Q+*6KT=?PEGk5{^fSdL1p+QSj>~`VwU#?=tXwn6c!)N6BU#O^}O4 zOVn(6do#Cj*kb0J0zj8bU-5v$ z(ivOER=IhzISVfMvF5{UJyF2?ZGI~F@MmY@ugM}wURZ!V7s;V&ucD|!|AKYk5H2Fu zO7y_g&#^`ic`!;}hB%4A>D9Q@lLFq^B$z;P5NN%E>;VRypp)U6t6~OFM@nL#Ht?%8 z@X!5S|1TP!5vah@)mlk1MAYy7JK9hoI*)ktulI0)%C?m$83>(vfY%EyDyeYM>1_ij z_OhbF!oqyMWwlBMZEyU6U21_;w_dFsqc1hO(36a1AOFfp#l8!;*-B}ib%dA97EYJ6{xSCGeSKIA@Pw)-kPTc~}RjpF0pzdM>v2k5sJ6$AYsSmj9ljyDg^=0jcV)b$s zZ_tqB?tR<&BgOST9`h-xR~rC(3wrjSQUHs{oMeLyn|EPd-OP?R(_ai#Giq&dO*f)| z%I|94PQNRrcZI&@Hrr`o3VBVL(q<;_lc zT3wKNn8~VE%5Z%$?QKEx^r92W!}VJs<+S_J{b06ZlgG=$e@y^!mo)wAz$R%kR!~Tb zA1xf4eg7zuU^Zg7ZrW=88zr3Br{Ti=r@h_tjpTNAo&d7I!n&7Zc%e3cd)LcBCmuV* z9*j14EvSsxYxRv0`=tk{4n~gE%9ubVK07m$+ulxvVM;@LR5+IamSYh4LV z{iS#7%vH{!Ahx=TLlMmzDKGjg0%uf+rI;5-o@BP>wlLNBScvW69K zXG=kOGF{Gm>2eF{eAX6n$<fN%}$}5|ZK+ z2z)vsT@x*nbbdp&Y+>C@gA41epV_2HDGv)^YM`RJnm{&=;?(QXCh~2?8a*Vlo*|1O-+LdMj>$Wu*K3grnY0r(KLOoslJ&XwaDOFr&6Al3oIRHvn0$Dk z>L(j(`PQP-guFoD;LXw+953W~{JZh1VZnzIuSyG*X*9AEpNCz(g;hw8UcSQ!n{f#c zm~3N-MD4u|PZn)?K$xjYzY+2TqqJs;3dBKo+JL$&ho+aSV;>s~Z?GH6%FA(T-k|0T z)(GH&4tc(;shC@0zB*=2<>-B(6EANgdGR6Vo_oTOKZMbjL0nx6R`3HKh>VskDPC*N zLxTD1e1Tq{d@wRh`sAo~T1FN-PJ#?v)o1koa*1qI;}6Li5SV0aBD}M(uuksl8?8-8 z9NaMZg|(Km3T0c|uYB)Ixn!5-vKj*I7h;s?WKDv+uz%bX2?(pB=ww#F(9Ki%Xb%U?qRr#q&=R-|QWk&|jPhwV#i-v~O^TA#($?2E<{^ z`LW|6Y!-Rmr+F-MGmbIcUD(*z%@N=3m6)y)4yyPAtoSSah&e&`f|u}`pvBQrL?_8m zWvBv--yH4{?PUr3CZwfB!Id&IMEEL0z-vzv6u5kRkK(#LioWkR=X{du)ZW#DD_Saa zKFYNhj!iB>g%j{|EydPD3D5Hn`ztLI=IbA~=NlcN_I@eK%V3@q!DTQ#z=;P>1o@~B zmX0DY6+e(&EPU8c(cJ9+d46llzDE6{exv4#f!jLx2O{IN4Fe11CshsS^A5utkeA5# z?B)^%@*!xuj#~nul1_v~m?%eH+gT#E|LTisemxtRX~Tzy`c$^q>y^{Z%1s2MKvCE% zxvfKH{r8j8w!6xu`{a)iz`h5MLjtsckKUh#>JISq=M@g@t#^3jyx6mee8{cYVz^)> zqbC}$ohgl0hW>69OFRRiq(%Qar%FhRf)~&O%m)n$K6S~-O}1OD;wz$c_gSs7t@ze= z{c8TiQHmy$6fG1KILlR5Mp-)cMF_CpCoQ>Wyeal0aWJ+}UaD~ga%O8)zxPptlv3YF zzhY&b26TBFppr?}*ehdY!Ph3A%!Pw+MPZd-5cykswCFO&sNk&E26}?NdNvQCn$PA& z2?wcrwvndl#Wvz4I$&P4Iu)sm2@R0{kERKT$QMGOXc3dPKF6Kt?(87vRWVLqMs=BFX4hFb<)|Z9 zDVl7ASGHZ@br9QW#OO@|{0J4{R^P7EO;F&b!SypBE_y(ohin&#%GP1fkBvQ-43wsd z$PYvw${qg>8jG!pgX^vX*a7`_>|qI+TQQ2&{W8o!IqFXf&G&OR^Rl3$YMyO=M$pK} zvcgfc1xM@*v#Ow5-S#q>P*CVYFo!&z3Q*cy}NnzmD+?hq6*X z2b-#<7g!a153T*%kcfuFjZkpqD;23~lLk}@;6jaJ;t0J5S`=XT@N)F-WX~dnx0CGu zwj!07fFzfotZ@goI@Bv`Q2e04MrOU~xm41yR$g@m1_b4`tz}H@^NX7(F)<@zfYtV3 zG+JUMor&Oc;LAa{zu)$wLXmCE9iBdicmK~`*@UgFpU>G-()K<6yK`6T8eetUD_?Szf;M;|^68&R*e32eKew%hE7yKP}v)gzS$;~;q>#F{Lw zXJ8@_isUwPMt0QTza?U^-Rg=^ll-8|{dV6RLwh$BTe4cJI;dWA4#H@(?p3l84H3o~ z5Sp8{9uZXpaXL)i?R}$ucm}Hc3;c@ju4k`6v&9g0T;f|Mf2JT}auz6H@9cTe^q@*h znchon`W)-}>J|~k;;%10NF|#kDpEQsX>L+~rmMBv6)lv=m>?V{1o-KtMs&B@Z&egc zgphjEsnYmTct2cMzQGOio*y<<&qd`plgbi<@}0p>&EHdDoL7JC$dkY|0sce^1s%Bj zxv5!%=_9dR#AFGENp!Il2P@{OAc6|G8~)}d^a+11{>vXJ1k#&H&@j$i`P<;{?q|;f zqBuB+i+f#3nH@s<7e=RQ3SDF-h)5vqjTQY`dmP;{nx5g5QART%e~bB4pc@1 zs<=Z&xy{LaF{pn}*TenY_12oyNKe&0(gz_Q%E5M3KD~*KcvBpeS|N%>)r9{1*`R|O z3+3tmvn@Sw|Km@s`H?6Q4`0pb|!oy$I^03fWpidfDp6!!TAm|R`rt-<_t&Vjy0A*EF(s52;Fy_|V z)ix_Mw#Hq+jPL=1Ay4$-c}w9ynXwFSj$C!jXM#3t7JmQro!=K|rxMGz8gEURC_;{* ztR;EpwP0&=&V~E#v za>~7r-W1e&rA@TQrd4cHk%1smiY_rU-L)KpL;97Fr^aX>~r2}9?5;$X}6RAR)n zzy7K0pFe+|EtD1)V>nLH(#>ve$8-N_Pk}<5?w*E63Tc44^#B+`U~zFX8bbwjWJkQn z<2xb{>^g0q_m{^)1ZnUNII)?Q93AJwBdneyQI6sBAU;gu^A3J#(cSL3s?7ZpY1ab8w_2Od3ZEESe&$IENX78+-6XnLO zlUemQfKBO4VP6j^>AG5uL&dwDcK=tP=W++9@u5X0l1SN@dfKf%S}I*hV=zmm9ri>y zy6BNDpRPj>NKBG2H2$G(R^^Q!hY>G*;(c+k^5D>OLYKP_A3nfe=>0f8@2t*1w=Rzj z?sjf3Q^0rzFUs?nWTa_)ey~Rh)T4!7KKMTX+V4fxuTy%d9+}|h3(65aI#7;?XrrBY z$Zf`-^nxizgtgH|jELBUbfCRK(pbda$^tOoHd}c?I*` zB<`cgU2}2q@J_@sd)2^hl@l~C``jI;^uD|mhro=%S-H`HRli!Q4Z0v7Ko!sLdIY=? z3Wx6WNF`Qh!!N>U+;LMWy0}!Wzc%)NFm^CC0le?a7E-9hQ0kYX6J-;G{7MVsFVU(O zrG+1i*maTX!mEBEPV8ElR=M1&msle8=vzF}ZM*Bv$?A@YzZ3oJx+eM<75ghbsy@sW zhpzd|m!Dt|t2M=SH(oS;o*GE5tp&KB_T#=6$yx2>ac-HLuEq%+s+rV=<1J-2d#AU~NsEtgNe!Aox%J0sjcU}8Jqo`#&n9Lmy0V;{oV>)G)}nUjr(P0qXSp;(TI&jRa}kcC?F?93kXqsiY*g0;9c{BA&ye>Q*Uyol3X zr7V)kIHYe_D1&{I0naadb;LQklbC&W=!2uDEnh#5+c^spQ>D=F)6D^gi2U#VA50e> zj~1^^K@TSpqEhj5dV=Rtc826JI)pCDMn%b#%OKqfmt-k3ro)z(>{>3TW1ScJo$1mA z64Um5I6ja=k9eyvQ*l5%2=W@z>I8lil5)|qLr%iE*lUR4>DyZXrb;ntbq(uELzjv!QJTa2Oulem`)E)b~{sU(flSp z=_iuww@1&eav){+jexPpwyL?i+R~S8*lsx1eHk8xZ9#%LqhBjPAcEefN;Dm(78Jo| zBc6)1jGJ;~FNzWw8JYNM$u)jeq?N|+@5;|Qh;Ts4sx7VSQKrG&x$bJspI6)jqO5eZ zfA~qnoaHUn>}yu-a-r1f%fEY?@h}SUh%!6UW(zu;xFgiiP$@G`3q(M)Y%V~5BisJMUHBOUnq;;yEuhH zFRg)i@q8mbjSZ&+V&KbdcQP7Qn7_rYv)L>TBtKO>4!2}aMtM}8RA(=$m)Ze1teXWr zgWsC*Iy!B^(Z>%8*w_({uU>7EU5y}?K=LJYlrx4xa`nQEf9z+3FN`bP{na%N6;S>2 zD@qn9r*+q-1R0)Jetc*g){BWknwV%sFP`Cl7HLYgEdbMemz^zXy*25<2t~-5^|ib> z7foxn&y0MA9f?Pg#w+d+SkbuE;bdz4Cz5agw7S{a=OlZvR&H$1!)Ba-ia2+w# zK6p-m&U7#{^Kbo_JzBdas-3Gad5>})A2Dq?z9W*oXf&p34MSPyM2M)-Sz0kZg| z%~8>EP@>0>IhtL0u5pOs|D0ZE5RsePsk^5|VOIE;HZ;9OT2K^-M?>7(UZo+`$e5 z!UU2|MVPN&+|NZHy(^WsUcIE}#?P!?cJHJL>$vT9kz5CT^MpG^?wHt|Egf`YNp;Wyxzc4Ubbs+z~fDZK6yD@UlD zlFy08n+ErRBjZQ7_N%VV&gA!-t?0-FDamVAdOL9?{BVz&_pe1BjFPx_A%68?qr;)} znuSaRXRZnXR{{@#@o45@ zG-j;5{q}8uUSI!TQyQn>hwKpgI~e_%E4JPp9lqSgFQq_aAs{QG1O)oai|Bq`67L_6 zcDM7b>?$3Da|HSv2wci(+djV{%wv6`6W0@(O_R#cBMai@eI7%@r{C|p zo$`LGLA;I@^%<4N_=#pDP9&U8%vVHg_oKNn)ZgL8=?#-crBMQaA4aWd7`o}q>E zsM1tfN7T2I(j|K%tu;*=Z!Le=()rGDi`%Hb9Lm6qppY)vAi4=bA0!hEL25u zbC9}cfPh_#2xb+}s;!4z`{e?1PIN*B!}41l$1vY3b1ce({a7t(w|lO?fA0ULm|6>? zjvvEryensO;QY>OH{0EISJ601Zvdyjs;r;U!{XnsnSq?bo%IeRN3fxX_ojVdB}X&K zy=o2TuZuc|cbG0>S7==4pgVT+55%O z+{gRFWefDGDxZ%%r*{ST-;vQ@$X!=yPX}(_EN*`M`BhAqQWsszmr4{BRKgPBm(ru6 zlVINAx_Jvpb=B3|w%NJ0yIa|EHL7$K&@Bfl^^Op)7pS+_vjzfoQlbYo9-MPG$jZHe zt0x253bI^n5L9P@8pFTTc-RNpUGov2kmelRS-El&0u^o0G)~-vvq!yc*h6f9ANyLy zYR4qR79Y)=8N@`9`sI&n$WoorIm%(H)_Ffd;4i<{@><9OaTG^zm9X2sDbML&d;o-F z3e{#M(@2>)WHv5D!U$Rr06f?Ms=IPQ_F&%|a{^NV$@7;*re5Q##UK>05n?Ax)DszQ z%o~py(cBGjH>))&P~ZN27vKZuby;-*VKX$n(DkMo6W#zSOpfl!uz|~C(0(N0I=X5J zky#<$N%?Z19X{j3+;QflyM@H1j!Tmf2WaIbM5&@9DRIG0?T8w^6M*N?@u%Qx?SFQ*4?|V-+qxpk3g&CT5*N6<@z2-@Zi?$Q?pNw5d1vO{(#na zG8?}M$7qDzKulMiWo$IP7oJ zq)Y@90~Mp<+FdXxu(7c*Y2Q~NhxGuPxq4GHVHsCQBgKGHCc(QhrwYA^XenYcFNCT! zTylD_!IhZEoDnPIM#adXF3&F2z+9S>e@{ZGKdyWHE!_S@cz!L{oJKX?d;eBAL1c%6 zpo8Slw^z3lukr_f>O_``-}%< zu81p#Mc!+e{^HAQ#A`eJB7AOoa6}Lr`1wIgwmLpqF`2X5-pd|H7rP%0&Dz+VC9*ja zr!ANq%Oh=4;clwE76_QbeFom{Dc50fM%Z!C3$8kTlDIt{6((?5l&F{;%)ZtFmE{5$ zq_<&s0FBY3=^Z2N>YF13dLRl9H_)25I=JP(=y&Ed+R|^ZxLU}rgCfoq-0R=D{c7OC z{dLax?6haRXHZ1^CdG=1FVSCYq~w>qB*1Vg?b?VHpgj@MwFN^y11;RZ&>w2n$`Q>p z1L0z~qn~KFkNC~)4bc7Ux*_Oik2z3=7EvC_$ibbofy)Wq)kfheLiZpWGnn80{@j7- zfWYIB{Kff~fuSR#C$%lgJu7DNSaW`Rhu#Ty@t$!Hhe6(^ro7hd5aBAikIH<@np??1 z5aiLDEfUv9EI8Ur9i6!Zzc$Fl?yyQkjUg7}?fi-6=49X75+gTTulu z?`IFRUqTE8_|{BYc%v_V%#{)_-<6`((mfa{Q1@)DE$wyqBdsK}8N!miT5k7B{Ck)4 z8=~M>E2qG%4?#TUuLuwT@b$H!8t;s=&WBzU7xh1yHkk_Bpt+?9_0Hu(Ndl%YSQ5|SlKOyQMn*fA8=9l+^F zTK;%r^RJHMKQQSqek-Uy(pq75fbAj;$j!s!)*)ZP%piCSh`M4+f?o3L?egzx+-j|j zb@d;s$|6U0vKiJ-$5D$0kas|CFZb=_kwkn-N;dWsH9{?aT)+#bz(%n%9T@wh=`{Q{ z+%tLciZIaF`9Z|>ukBrKRtO>d15q%muL)#M0(_ka9{Vch|MpxUNzJLojI14H5v_sc zAgVt{rV;4t>+3FP%&i@Xe^CLvJ3O--+IL!(5f>NlT*W7$MwpwQe?Em5zMNoJbSRiA z={70f=IuIAs+H}**?N7~L;b+{w`zcj1u+mFPdx9XePbtD`Eq{v04UDe0!$hzhm(Y$J|6a7uy4i)+}^~wQFc!{cHS3&&uGTN(akkonr@IRAFoe0Y3o!s=V=Lc zAlrtg_3${o`TTfqU)7b5w7la2MAjJrNLSLD;XgL4_gXzn%A@JgC1zw!5IC)eJ|v`j zOU|WBF*yp!K!;F{iOrqV)@xN4y($2-dE5aW&gKVu`gh*<^uWFTpG!}V`yU`8JULjI zX-7aWeBFks4X69tOZeqL(N|Cg0{J4d$D(uI9<^1sgE`!<4L#-e&MR(ZbEw_)UI%l9 z{23LqkM@-SyD9Jrlw0TRq8#D0NK%ZE)o$p7=z2M$Yps?$@WfNXVbt`%b@7_?aigs0 z6L$^D9M?yGsZ+eK(6nZ42!iJqta%Yq;xGvl8`tHYwA$lxJ%=kuxN!!Ew*ol*8=OVY z&b+18(DF}7+BT`~Z&6pWflL9yg475UK|6S;kPO#@iz#yOEx${o5r9_{hN$2?_>Ug!|i$A42fX_$oE`!W+dp-N_IT;8n?R62(H{zf1Ij_B6CkSe4Dvvt*Smqx! zaNeL)Y1mGP&lD~8@7-lM%@G93Y{a9bppA~XYlFldDO0|M`(}E9fBdtrkL@lhwL!GU zt3gJ($ZN&B9h(G+s1vBa?Vgf1PYVL4A5}sF^#{oZqXi4S1E&!G-SNk-XHtQt6)h&| znjXnJup1`IVj}kHpL4^P9Y;U{(c{wKtt4|!-@gAl^dsNfWuP6^OE@gBqai^WL+szk z+96LyHp>Cy(HX6Xec3b3f+60jmc#uQjb#nL(}$>Z$2RXV`^e=BwGM!?1<2w$xCK024i?< zAC8{|){6&kp%9n|Lfij92mSD{ibtpsTrbg~cd3c3h!K254W}Lz<%F3%Onp&|-rafH zSk{$I2kZx93dyPEX;bJw1l^&xzE_~((y$)wj#I3hJ~x0oDrUaMoIs+j5e9%)z7!Eg z&!4ynzPsK$&{7BRsIrIf46RU_UdBtvTUsewlp10JKMBa}Rp9fVTxavd;_s+({uv>f zEF5?TXQrVDkL-ZkzmuSoLHc;D%DXT}9~0G;pmo$qVBm!Wglgc;q{v4HvwxF?0NYTz zGw-nUI{zN%UPC}y8-|~QW_V;-I`C0}dUW5wK+TgAo>gyzTW^f5q$aw{!<{8m`Shj{l%|*`4i!@L3&~;$eM}{ zUiimXeEDzL@0%V119^8;eeU2V2A;;mRJD?D;u;cZsHr8$o0)A1if*CW$x{#8V3UFncR6DuRoGeR!C zLb&(?S{Oq7-*TE=$p(^^;8@y-H)yWG%0X8l~{dqN^1bzmc{0l-V*0tU7u?` zfZI#_KGn}lb2SJDwi+|{$I~emO20c