From af8206c529b9ce7a84f5a3689bc2e6cbc03e0ac6 Mon Sep 17 00:00:00 2001 From: Sheldan <5037282+Sheldan@users.noreply.github.com> Date: Tue, 26 Dec 2023 15:42:02 +0100 Subject: [PATCH] [AB-xxx] adding bonk image generation command fixing offline streamer handling not being able to handle streamer without current sessions --- .../imagegeneration/command/Bonk.java | 147 ++++++++++++++++++ .../service/ImageGenerationServiceBean.java | 12 ++ .../image-generation-config.properties | 3 + .../migrations/1.5.19/seedData/command.xml | 7 +- .../service/ImageGenerationService.java | 1 + .../twitch/service/StreamerServiceBean.java | 3 +- .../image-gen/python/endpoints/bonk.py | 99 ++++++++++++ .../image-gen/python/endpoints/pat.py | 4 +- .../image-gen/resources/img/newspaper.png | Bin 0 -> 30053 bytes 9 files changed, 272 insertions(+), 4 deletions(-) create mode 100644 abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/java/dev/sheldan/abstracto/imagegeneration/command/Bonk.java create mode 100644 python/components/image-gen/python/endpoints/bonk.py create mode 100644 python/components/image-gen/resources/img/newspaper.png diff --git a/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/java/dev/sheldan/abstracto/imagegeneration/command/Bonk.java b/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/java/dev/sheldan/abstracto/imagegeneration/command/Bonk.java new file mode 100644 index 000000000..feff46de1 --- /dev/null +++ b/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/java/dev/sheldan/abstracto/imagegeneration/command/Bonk.java @@ -0,0 +1,147 @@ +package dev.sheldan.abstracto.imagegeneration.command; + +import dev.sheldan.abstracto.core.command.UtilityModuleDefinition; +import dev.sheldan.abstracto.core.command.condition.AbstractConditionableCommand; +import dev.sheldan.abstracto.core.command.config.CommandConfiguration; +import dev.sheldan.abstracto.core.command.config.HelpInfo; +import dev.sheldan.abstracto.core.command.config.Parameter; +import dev.sheldan.abstracto.core.command.execution.CommandContext; +import dev.sheldan.abstracto.core.command.execution.CommandResult; +import dev.sheldan.abstracto.core.config.FeatureDefinition; +import dev.sheldan.abstracto.core.interaction.InteractionService; +import dev.sheldan.abstracto.core.interaction.slash.SlashCommandConfig; +import dev.sheldan.abstracto.core.interaction.slash.parameter.SlashCommandParameterService; +import dev.sheldan.abstracto.core.service.ChannelService; +import dev.sheldan.abstracto.core.templating.model.AttachedFile; +import dev.sheldan.abstracto.core.templating.model.MessageToSend; +import dev.sheldan.abstracto.core.templating.service.TemplateService; +import dev.sheldan.abstracto.core.utils.FileService; +import dev.sheldan.abstracto.core.utils.FutureUtils; +import dev.sheldan.abstracto.imagegeneration.config.ImageGenerationFeatureDefinition; +import dev.sheldan.abstracto.imagegeneration.config.ImageGenerationSlashCommandNames; +import dev.sheldan.abstracto.imagegeneration.service.ImageGenerationService; +import net.dv8tion.jda.api.entities.Member; +import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +@Component +public class Bonk extends AbstractConditionableCommand { + public static final String MEMBER_PARAMETER_KEY = "member"; + + @Autowired + private ImageGenerationService imageGenerationService; + + @Autowired + private TemplateService templateService; + + @Autowired + private ChannelService channelService; + + @Autowired + private FileService fileService; + + @Autowired + private InteractionService interactionService; + + @Autowired + private SlashCommandParameterService slashCommandParameterService; + + private static final String BONK_EMBED_TEMPLATE_KEY = "bonk_response"; + + @Value("${abstracto.feature.imagegeneration.bonk.imagesize}") + private Integer imageSize; + + @Override + public CompletableFuture executeAsync(CommandContext commandContext) { + Member member; + List parameters = commandContext.getParameters().getParameters(); + if(parameters.isEmpty()) { + member = commandContext.getAuthor(); + } else { + member = (Member) parameters.get(0); + } + File bonkGifFile = imageGenerationService.getBonkGif(member.getEffectiveAvatar().getUrl(imageSize)); + MessageToSend messageToSend = templateService.renderEmbedTemplate(BONK_EMBED_TEMPLATE_KEY, new Object()); + // template support does not support binary files + AttachedFile file = AttachedFile + .builder() + .file(bonkGifFile) + .fileName("bonk.gif") + .build(); + messageToSend.getAttachedFiles().add(file); + return FutureUtils.toSingleFutureGeneric(channelService.sendMessageToSendToChannel(messageToSend, commandContext.getChannel())) + .thenAccept(unused -> fileService.safeDeleteIgnoreException(messageToSend.getAttachedFiles().get(0).getFile())) + .thenApply(unused -> CommandResult.fromIgnored()); + } + + @Override + public CompletableFuture executeSlash(SlashCommandInteractionEvent event) { + event.deferReply().queue(); + Member targetMember; + if(slashCommandParameterService.hasCommandOption(MEMBER_PARAMETER_KEY, event)) { + targetMember = slashCommandParameterService.getCommandOption(MEMBER_PARAMETER_KEY, event, Member.class); + } else { + targetMember = event.getMember(); + } + File bonkGifFile = imageGenerationService.getBonkGif(targetMember.getEffectiveAvatar().getUrl(imageSize)); + MessageToSend messageToSend = templateService.renderEmbedTemplate(BONK_EMBED_TEMPLATE_KEY, new Object()); + // template support does not support binary files + AttachedFile file = AttachedFile + .builder() + .file(bonkGifFile) + .fileName("bonk.gif") + .build(); + messageToSend.getAttachedFiles().add(file); + return FutureUtils.toSingleFutureGeneric(interactionService.sendMessageToInteraction(messageToSend, event.getHook())) + .thenAccept(unused -> fileService.safeDeleteIgnoreException(messageToSend.getAttachedFiles().get(0).getFile())) + .thenApply(unused -> CommandResult.fromIgnored()); + } + + @Override + public CommandConfiguration getConfiguration() { + List parameters = new ArrayList<>(); + Parameter memberParameter = Parameter + .builder() + .name(MEMBER_PARAMETER_KEY) + .type(Member.class) + .templated(true) + .optional(true) + .build(); + parameters.add(memberParameter); + HelpInfo helpInfo = HelpInfo + .builder() + .templated(true) + .build(); + + SlashCommandConfig slashCommandConfig = SlashCommandConfig + .builder() + .enabled(true) + .rootCommandName(ImageGenerationSlashCommandNames.IMAGE_GENERATION) + .groupName("memes") + .commandName("bonk") + .build(); + + return CommandConfiguration.builder() + .name("bonk") + .module(UtilityModuleDefinition.UTILITY) + .templated(true) + .supportsEmbedException(true) + .async(true) + .slashCommandConfig(slashCommandConfig) + .parameters(parameters) + .help(helpInfo) + .build(); + } + + @Override + public FeatureDefinition getFeature() { + return ImageGenerationFeatureDefinition.IMAGE_GENERATION; + } +} diff --git a/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/java/dev/sheldan/abstracto/imagegeneration/service/ImageGenerationServiceBean.java b/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/java/dev/sheldan/abstracto/imagegeneration/service/ImageGenerationServiceBean.java index 20e67122d..148ed7580 100644 --- a/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/java/dev/sheldan/abstracto/imagegeneration/service/ImageGenerationServiceBean.java +++ b/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/java/dev/sheldan/abstracto/imagegeneration/service/ImageGenerationServiceBean.java @@ -19,6 +19,9 @@ public class ImageGenerationServiceBean implements ImageGenerationService { @Value("${abstracto.feature.imagegeneration.pat.url}") private String patUrl; + @Value("${abstracto.feature.imagegeneration.bonk.url}") + private String bonkUrl; + @Autowired private HttpService httpService; @@ -40,4 +43,13 @@ public File getPatGif(String imageUrl) { } } + @Override + public File getBonkGif(String imageUrl) { + try { + return httpService.downloadFileToTempFile(bonkUrl.replace("{1}", imageUrl)); + } catch (IOException e) { + throw new AbstractoRunTimeException(String.format("Failed to download bonk gif for url %s with error %s", imageUrl, e.getMessage())); + } + } + } diff --git a/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/resources/image-generation-config.properties b/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/resources/image-generation-config.properties index 1d794bd8f..75f5ca648 100644 --- a/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/resources/image-generation-config.properties +++ b/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/resources/image-generation-config.properties @@ -6,3 +6,6 @@ abstracto.feature.imagegeneration.triggered.imagesize=128 abstracto.feature.imagegeneration.pat.url=http://${PRIVATE_REST_API_HOST}:${PRIVATE_REST_API_PORT}/memes/pat/file.gif?url={1} abstracto.feature.imagegeneration.pat.imagesize=128 + +abstracto.feature.imagegeneration.bonk.url=http://${PRIVATE_REST_API_HOST}:${PRIVATE_REST_API_PORT}/memes/bonk/file.gif?url={1} +abstracto.feature.imagegeneration.bonk.imagesize=128 \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/resources/migrations/1.5.19/seedData/command.xml b/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/resources/migrations/1.5.19/seedData/command.xml index 3bfa810e5..a6686b484 100644 --- a/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/resources/migrations/1.5.19/seedData/command.xml +++ b/abstracto-application/abstracto-modules/image-generation/image-generation-impl/src/main/resources/migrations/1.5.19/seedData/command.xml @@ -9,12 +9,17 @@ - + + + + + + \ No newline at end of file diff --git a/abstracto-application/abstracto-modules/image-generation/image-generation-int/src/main/java/dev/sheldan/abstracto/imagegeneration/service/ImageGenerationService.java b/abstracto-application/abstracto-modules/image-generation/image-generation-int/src/main/java/dev/sheldan/abstracto/imagegeneration/service/ImageGenerationService.java index e150e5582..654fed0d6 100644 --- a/abstracto-application/abstracto-modules/image-generation/image-generation-int/src/main/java/dev/sheldan/abstracto/imagegeneration/service/ImageGenerationService.java +++ b/abstracto-application/abstracto-modules/image-generation/image-generation-int/src/main/java/dev/sheldan/abstracto/imagegeneration/service/ImageGenerationService.java @@ -5,4 +5,5 @@ public interface ImageGenerationService { File getTriggeredGif(String imageUrl); File getPatGif(String imageUrl); + File getBonkGif(String imageUrl); } diff --git a/abstracto-application/abstracto-modules/twitch/twitch-impl/src/main/java/dev/sheldan/abstracto/twitch/service/StreamerServiceBean.java b/abstracto-application/abstracto-modules/twitch/twitch-impl/src/main/java/dev/sheldan/abstracto/twitch/service/StreamerServiceBean.java index 572e17003..9b219cf9d 100644 --- a/abstracto-application/abstracto-modules/twitch/twitch-impl/src/main/java/dev/sheldan/abstracto/twitch/service/StreamerServiceBean.java +++ b/abstracto-application/abstracto-modules/twitch/twitch-impl/src/main/java/dev/sheldan/abstracto/twitch/service/StreamerServiceBean.java @@ -314,7 +314,8 @@ public void processOfflineStreamer(AServer server, Streamer streamer, Map featureModeService.featureModeActive(TwitchFeatureDefinition.TWITCH, aLong, TwitchFeatureMode.DELETE_NOTIFICATION))) { + aLong -> featureModeService.featureModeActive(TwitchFeatureDefinition.TWITCH, aLong, TwitchFeatureMode.DELETE_NOTIFICATION)) + && streamer.getCurrentSession() != null) { Long channelId = streamer.getCurrentSession().getChannel().getId(); Long messageId = streamer.getCurrentSession().getId(); messageService.deleteMessageInChannelInServer(streamer.getServer().getId(), channelId, messageId).thenAccept(unused -> { diff --git a/python/components/image-gen/python/endpoints/bonk.py b/python/components/image-gen/python/endpoints/bonk.py new file mode 100644 index 000000000..9cfd2eac0 --- /dev/null +++ b/python/components/image-gen/python/endpoints/bonk.py @@ -0,0 +1,99 @@ +from __main__ import app + +from PIL import Image, ImageOps +from flask import request +import requests +import validators +import logging +import io + +from utils import flask_utils + + +bonk_angles = [40, 45, -5, 0, 5, 45, -40, 45, -30, -5, 50, 40, 5, 0, -45, 15, 5, 40, 0, -45, 5, -40, 60, -50, -40] +allowed_content_length = 4_000_000 +allowed_image_formats = ['image/png', 'image/jpeg', 'image/jpg', 'image/gif'] +gif_speedup_factor = 2 + + +def get_avatar_height_factor(angle): + return max(0.1, angle * -1 / 45) + +@app.route('/memes/bonk/file.gif') # to directly embed, discord _requires_ this file ending, it seems +def bonk_animated(): + url = request.args.get('url') + if not validators.url(url): + return 'no valid url', 400 + session = requests.Session() + response = session.head(url) + content_type = response.headers['content-type'] + + if content_type not in allowed_image_formats: + return f'Incorrect image type {content_type}', 400 + + actual_content_length = int(response.headers['content-length']) + if actual_content_length > allowed_content_length: + return f'Image too large {actual_content_length}', 400 + + image_file = requests.get(url, stream=True) + input_image = Image.open(io.BytesIO(image_file.content)) + original_input_image = input_image + old_width, old_height = input_image.size + with Image.open('resources/img/newspaper.png') as newspaper_image: + newspaper_image = newspaper_image.convert('RGBA') + newspaper_width, newspaper_height = newspaper_image.size + newspaper_ratio = old_width / newspaper_width + desired_new_newspaper_width = int(newspaper_width * newspaper_ratio) + desired_newspaper_height = newspaper_height + if newspaper_ratio > 1: + newspaper_image = newspaper_image.resize((desired_new_newspaper_width, desired_newspaper_height)) + else: + newspaper_image = ImageOps.contain(newspaper_image, (desired_new_newspaper_width, desired_newspaper_height)) + new_newspaper_width, new_newspaper_height = newspaper_image.size + new_total_height = new_newspaper_height + if content_type == 'image/gif': + logging.info(f'Rendering bonk for gif.') + frame_count = original_input_image.n_frames + old_frames = [] + for frame_index in range(frame_count): + input_image.seek(frame_index) + frame = input_image.convert('RGBA') + old_frames.append(frame) + frames = [] + current_factor = 1 + for index, old_frame in enumerate(old_frames): + angle = bonk_angles[index % len(bonk_angles)] + frame = Image.new('RGBA', (old_width, new_total_height), (0, 0, 0, 0)) + current_factor *= (1 - get_avatar_height_factor(angle)) + current_factor += 0.2 + current_factor = min(1, current_factor) + avatar_height_factor = current_factor + target_height = int(max(1, old_height / 2 * avatar_height_factor)) + old_frame = old_frame.resize((int(old_width / 2), target_height)) + target_position = int(old_height / 2 + (1 - avatar_height_factor) * old_height / 2) + frame.paste(old_frame, (int(old_width / 2), target_position), old_frame) + rotated_news_paper = newspaper_image.rotate(angle, center=(0, new_newspaper_height)) + frame.paste(rotated_news_paper, (0, 0), rotated_news_paper) + frames.append(frame) + return flask_utils.serve_pil_gif_image(frames, (int(original_input_image.info['duration']) / gif_speedup_factor)) + else: + + frames = [] + logging.info(f'Rendering bonk for static image.') + input_image = input_image.convert('RGBA') + current_factor = 1 + for angle in bonk_angles: + frame = Image.new('RGBA', (old_width, old_height), (0, 0, 0, 0)) + current_factor *= (1 - get_avatar_height_factor(angle)) + current_factor += 0.2 + current_factor = min(1, current_factor) + avatar_height_factor = current_factor + target_height = int(max(1, old_height / 2 * avatar_height_factor)) + frame_input_image = input_image.resize((int(old_width / 2), target_height)) + target_position = int(old_height / 2 + (1 - avatar_height_factor) * old_height / 2) + frame.paste(frame_input_image, (int(old_width / 2), target_position), frame_input_image) + rotated_news_paper = newspaper_image.rotate(angle, center=(0, new_newspaper_height)) + frame.paste(rotated_news_paper, (0, 0), rotated_news_paper) + frames.append(frame) + return flask_utils.serve_pil_gif_image(frames, 50) + diff --git a/python/components/image-gen/python/endpoints/pat.py b/python/components/image-gen/python/endpoints/pat.py index 72eb8cb0f..b33c9d76e 100644 --- a/python/components/image-gen/python/endpoints/pat.py +++ b/python/components/image-gen/python/endpoints/pat.py @@ -54,7 +54,7 @@ def pat_animated(): resized_background = ImageOps.contain(background_image, (desired_new_pat_width, pat_height)) resized_background_images.append(resized_background) if content_type == 'image/gif': - logging.info(f'Rendering pet for gif.') + logging.info(f'Rendering pat for gif.') old_frames = [] for frame_index in range(frame_count): input_image.seek(frame_index) @@ -70,7 +70,7 @@ def pat_animated(): return flask_utils.serve_pil_gif_image(frames, int(original_input_image.info['duration'])) else: frames = [] - logging.info(f'Rendering pet for static image.') + logging.info(f'Rendering pat for static image.') input_image = input_image.convert('RGBA') for background_image in resized_background_images: frame = Image.new('RGBA', (old_width, old_height), (0, 0, 0, 0)) diff --git a/python/components/image-gen/resources/img/newspaper.png b/python/components/image-gen/resources/img/newspaper.png new file mode 100644 index 0000000000000000000000000000000000000000..cd8afbaf10917af7b32205e90340365ef6491460 GIT binary patch literal 30053 zcmafacRbX8{P_FM-ZNy+D7%ELvqBQGvq#DvA+nC_geWbuB9*MHWZZG2D6-2sqwH}K z4(IOsI-l?N_wUa`kJCL~&)4hudhYc~GdDG4qUWWDAc*Obk-h~4!NH$!h?W|B{EHYq z03Vbgx|ghI!A~^p^;GbGx*(%#ArMq{Nd5=Y&~sw~U!DxTXcuZ3cq262?UpAL9v&{| z9pD?{;TGg67kKMt-i8J*1PMcz^mVKv^4F&B-1qzyBec8O6o_?c9WVD?u81s3%AY-@ zTXOvuT)h2(%pLKbm+r<&OX4=HG@;^DI*$|?#kE<*gYtP?{jwi<{mOwZaf<$WER|;e z@%!Mpp`pX+5$hwLsGWB!>l3Y#NKR~ZS+j4{USY^)%;q7Cl6J~^(Xp?*a&xorgs|xU z_s1;9;+{&?^pVT-r(2s;jYXa+4CP6rx!Io2{U49`V{d#sg7o!&3s@KjZ+$*O(#4b7 z&;A~hcSddJO!WUNNs;a{)43;aJk!W!lU{WD@D9QFKLDo9B-A6)cMoLC=|qCMe1Ybj zfqI&#ZSKG^1Hw z{jY0QurL8844p=O3xVJ6W`jgu!e(9Zh=3sl97aeZWbTS2Z-^8@s5?8(sTu+sK=(RO zz1gDLI^<0wsJQ^aVoZba;lIwnIg`m}OOltZcs%bwm6wTX>m4s+1UG)EReFKY%xq2R z#Yny$whLU(s5UTq-ryaVU$lw+Uy0t8{MEV&j_;;7hwI*RmYk@UIr-RvSD;s^M1o0= z)`(7;htclwqZ?ALbxdx(Mh;X zcQ%NOpK;6)@#xLfH^k72U-%k>)}3~rT1BUFm6sOAo-qbuBEC0#UKW^&i}tAf!WLeP zOP|G_$6bWTOiDTGTHTEOFyKcVx>b5`RB9jd^Q>&eQNKxshm1-|eZP}NEiFzPAI=oY zh6dO90z(or8e>aF1CVVNgv7QPCaZ@4-_2u!@83q>2i&caybP>15Qc7#B)BzE(ukVjgJB zKfV3>4k2sbj5ibge`Oev{s*6EaVtJ1qN28huZ>uu(5CzX>N9ThiV%=TO5s0GxQ|sz z$7<U_h?{Mow&MMJ@#&8> zL1HMIr?(HU-NxYd^4m_ssh7@)i5?V2YYCwue78B9L%$g-}V!2@XaN(EnXgA~`53!#!j??Aud?Dg4#b364 z#sLVVYug#PDwVc=%xbF}G8x(bGF!odk(5BMeNSG~@ig)M1j{W}f=SvN`K|BRHZSq} zR-zlb9{9{eM;4yZ?wg-K2LSd(xdHKrNtq24N;&d(V0@0pXNzId0}x*Vj(1MN5O);` z0*XU)GYB~uzdO4LH^}S7iu${;ANO$wuSUWGc2?OI2?AlTtJ~#!o7k*RN5cIbK;{qN zDM#z+$rz(seb{U4MGAAvRYs>ZpEMRm35&kO%vGae_;+oM<~HRkxkybDSzF?nsFK$<|G?T55iyMBTOr4Ej3jScJbxWI@PN5t^P6L9`BSEnxi`f{v!)Hlr%LNA_;C z{6&QwUz@~O-GymNCM;$i8g{3k)(sYApwuths%wEonK*gtcM+>ASCpPt=*76GJwwyT z=Nl+#M7)B*Bc#ULS-yR{e(%$v;Fp~AR6@e+F@Wv6h@&ar6lSDrSrC4A!nWG!?U{(P zfe+E|PplD80sp=OE@-45uWgh`3$MiLlzHq<8r1&kSlx8&@^Kq#m)xd{FN*x=NT>=6 z?pmPW^Q|XMbxByQhE1$LeVhc~Islt#3VU2is)<=$xpN_Ehu47=6k;5X)`m_H zAJiMK$L5_)7z2s@pVU0aTejmG&GtkP4yE@#G;GSr%#N?qJg_*kit(lVU8VIc zFjm*lg-kMzO6S(+(c24ivhpdUwUTZOg5AJ)d#f$?`B4+8Rm0J_{f|Sq8=+&{*fK;c z9{3yiy55VsBh7EAb%Jcd9lL;9PPY7%bX`izuGeMToNUol6@yts$BLkcIX!Z~d}sUe z5OBJrdHwc0t!CVsw>YALe1?tU}N_W0q*6{sk(x`miv+DMj$x|w`bjPuiNB$pmf z#O$|AiFb9@W3aI}*7V+T@?zR~mrJJwj#$2dwU6e>YoBdnubg>?PANo`$7n*3WAip7 zo%C`y_PjbN$bXx=!0(4|k~rJWN#?_e#V$9}l+`MeW6Ldp`bbM(RI&o@@Al0Hy(RU# z<-hDTT?;hMsoCFtsh9}}dzKM-NZ=$w4^l5~4RFf~=b3u1kL7SpH%0P|MC$pXo@aEa zeO@f^`6iFB)c<{sOktG(naO{DtI5)lawO(fqM@;d;vV{d+pTwy;%uzj<;x;()i1_B zh&b`$k~Q`F{a3GEHEdp9poQ2jWQGuT@5J;W5ikt;@}ilWyLeeW*1k2qv1&S5Vg!42 zCMQuL!zK8o2pPFoWc|e^AMJ^jcIHm(;k-PZd{Ks<4YwwjIqVOI->@yY#zsa)d^Hv0 z2Z2_%0%3i%3`YZrP!_6(!9y&;nwYvznNjI6Q3l$>^l2{j6GkY)eYWggARlUez%7GkeuzT&i$w{f6K^tQM+&U#Rn~$2nE4 zbEOrC(-PCI!8G*-hz&;8?BaOjjdH3o!K74b4q%yA8{J4pOM-Mp5*+xY^hGv>gN=el zt`E8)mX^!9^4Q66()m;)p=4A{0v8e8XM|oG{@6h5$vsm!)mBx3$e3H#J}mlo@IB$* zIYWKszk2wn*ghnLAq77PoErJ0J~R2%!=8cVin6Fz{}mGxE0)8IgTMe`QS3J6F6!Ca z;QNvL-(808q9R|V{n>%jcliTrQ#UR^NdW`a^}59+ll#mb*QH(&E)@PD5Q6I_1m64m z`7Cc9Oi^9Wp}RhKN%qM5>?G%`83n$>4Haz8U?#e9RjVk=rKL7h3^g~Uf@D6VsJP7+ z&h@yuu7&z?k0wg_WY+8?LD9BvKt+~;TOO+&++0$MvJ=0*8MS=JHbBm5X=N>9Oe21GZwC^2xd>B{IMy(lyUkW_=hUB6zIeUwGj&}f znY;fR=7$2+0J!Adg20!UQA51Z7j4{7%04-=uaibF9v+Gk&in27)=${k-wwF!)H;9; zmvb6XmdBpY>74_lmW}ZbcyhSX28nDjr0homuzx18w8*}Fq*<)z)RuIRLxr+4a!;+{ z@(IIjCp&Lu1^)H}|FEVi@13k$pW$Y7quh8~N2AW!y= z5P^-Dzl|+;@xu19v1419?W*8`)!F!MUM?#8!HyA!qhPlO3Z2q4`)XwWn2uY_Cr!^O z?&$qN_r>dMP7ga!nq*|T-@c`L2hp|8{@7;6$+YC&gE`64M~4gQ4A4v1;u9)lA#!_6 zW06#1VvMCyu>i;1;g;qdqs+f>AwBf$iDoWP+B9xQmhLG9_OXK@Ag!|R}3$a#r5Wp+lbBH9WycK0?2b3>dNWm@MMPbwt zNdDv(ducM4=PJrot`3H}&;0w%bINce>$W4Rac0xwZYf~~v$ONIwJnhf8i?EK%|~z( z1f0(bVwOEZ#t+v+OFM^=xyX+&GIFU@D<9$h2^-&+N5;bfR{s8qomlN-)FtQnF_4zPU!h6<=I8l zy{u#D(rOxW0XoVH9ZR+P>X%L_=e8iO_L+Foq%e~vdyKkD0A^4D8N2dRX6{}VecK_9 z?KyFZOBFSyM$SKDj@?Wca5I=+N?HWMg+x7(iX*Oj4j*qj9KDSMz9-4DJ9pRZ`Kb*# z4U6#<;}0Iu(Tyk&C=GX$eZ$xyVeg^oDO@&pzX&h0?|QhmClkx#VVCNMy|06>M_YLd zrAwE;8IF!LixY8~-l+=JqG4N}PjN%KB%)ZbgrY~OUAO_3d_&!#;C3gKO+=@U&XJDJ zP1A28>^3SrBBh-LH0eF#w#M`T*Mv@%+5QX2)|c6|T7-@}B}$n$)+YIa9QIGbUbwQ} zG<(;o;1%Y<@yF+ix6r+ox`|c@Q1;-yP)AV+aU(TR507J5d@vC7I`#=!1y^M2#(lU4 zuiXEw@VxhouZwY76iZAKmvC)e8}VBbI~g?9g^O^9_#N9FLOi6SO2GfvzFE%&%ecX@ z>4>TzTyH(sz4#~~#_=>~%msSaYwhRy4?@T!y$fWU?AoR%Q4W+#ADyboKU#PAcWp1F zMKGS@@aP$TVlmg2oRneuP#3Un#TIDzVm_*oGC`+>FnO}V7rr68kSkB0k5EepGM~DO z{;6Q;a)8Edrt}AHomLBIWuX&O-~&heY;;h$S?bG zXU8jR&vj{_1#d_|F56;@wy|caoSm2Z3$A|3*a&{@4OGD=i=i;@xw-wYOyzr@3mZQb z;kEq-9^evMT^Ept)c!w_DqCKh@`!M*7p~@)kt2~5DjQnnqiqU_gACbf0vzemzJNQf z#>V@@&wc=sMSqdU5E+pqBZ;|)<)(AA)c-m=23OP`k1_O&3-Jl+o+=HOM61?ocZ?825~a zI~r=7xA+1e41w@ri~ILCZz?_MTAuIEKYQD;Y^c3-H9WWVQWg`->8X{EAJ<-W#U+2y z+%XK$pkWgbTm)HKHL0Cn^K4qvTRPwx9vgo|J+d7oZe0r_IgY9*4|p{^s^64KE6cnD z%;#^4x z1d+duP$CCb=dvCp55a+n+W#!@^zokvkcQ-&tI|JkaR5%>mCW@*f*61j1Qv=6C78Dz z7#b(dhc1#gCQSRMAzB!s{dMO0PPs<I7`ohjWeV`YAe5G%G1oZ0Qj$!U-@NXbqu zzrbB=U+&?s<)328+7Y>;H(a~?FqPTg(^F#Wb4F4gh}#REBp*FFgLaX>G%0gW@^0)R zi6m{L4@Y;u7T3BU%lh}r>NO?yc7~gaTMK_ydm3A1Wn?{kLVs>0Md{LhyK-f2yx=gi zVItSXX)LnILcWC6>`$veqjLe{$pi!q7P&OZ)&!m^7D86Z%hOfV}*nos>x&txaa*Lo-Cff))1vW>qy zz^RAykz6;Ph!d+CB`O0#vD+*+TA8C~b2_JFJ+p3mb>GZ%bq}?>g8&woAuAshEYG75 zbUk`_>o%--B)}u2`F)9hnGtOvrO|KCW1}eaZATQxXB%z+MP5~j$9|OCYDh87Zw*>W zd^|xBC@=HECQx;HW3A*w7_>0r;t+Zaq--JePXU}GMI-x1pV37?4G#N`Ra@3U}hr&TL-P$xeJ z!iH%&WE%F<#^k+NP{o*ff|owe@S8;z#Dm}H!noH%Pc#~TsZv9AZG1_5?j2`Po3x(u zyp}QF)$Zl)a8c8iu>L=C902@t`{XY;@rddC#C}`DOhIb`)!>Lg4Z~3lW*r! z4MdF(z3L}EHZJ*%a4_=l2wkmxT2tLrQQ{;?n_4C(2kLjf+57e<7IWQ5G!yKoFuj)* z3WWHA<+!Tp+>iCk#K*P3y>a*Do5zOCBpBZ54rH{d&wJrm@nU2{%6mf2k_Xs^mN;@o zBS8>)99QK?W8ar)wb}C_juhlkwiGmBekx=BoTc$$wM<&x9=Cvhh^%KKlu|QV}A^>`IiqI6=kX0 z{9+Boy161r-*Ye>RbX^{ig;0%$~YQ4Ctlga4G z@4Fg2ArUymAk4JYS4+&Ng0gjia=3ikkDB?8EIqT;B|Xi6oN1n**fbjBrds&m{mmp( zdVPKaqfrui1NFyCZq-QLZ2aHPw747H(eu}keegIVHdG>N5lhfyBch*FLg!hMk+wsV zO}9VJ{ykTyrJN8XRr3DGpf=4=x{onj++8tIuP=~B#`?^I=_bLCp?*GzmXQ9Zp!Oni z$}T?~FCXPvf26~?f)<(#Q;E3SE^OL&1z^yJG0e<>Uq9i9!aLNG8F^kFk&RYq1V4R4}YY#Gp{Vd3d<%U=~s$Ea1FU->9NG zGjt&{PQ;T6ZP~c_N!Na%Xk#}Vh%^7(6WrdvJXA{Z5h~*1%ikCrO`HJ@e#&8^kmW(| zYsGiCn-%s|>bKSc&YrZrRisn8GWj*BHRr)<$V0LINf<;vo$`Mr!G;6>*P4`!9K*2V zRI(;xl4~V1b!o#CL$L9AaEj#k2&EPDP>W0H3XvCrZKX7SCs6EI1otHfnnw$p*%wIbT(~aj4Y_>FQgfQNjWz#IDeTP2j|7?PT5PnNJp!|C z=(cl0(6A#vm4YiFlhwVSqyVlEi3VXt%h^TL6g>9mthryr!VFh;%yxF?t*%y5jA2>X zBgYnswHEKiu{8lkPRq~~oz_{Oi~C7OZJ_WvAVMxTR52dfj-#JceQ5(l$eU+oST;NA zonYBPw1%e)a_a-bd9}MlwIQ!hx222m2W$EpJ+UsJyR*bfIJ>sFd;ysSz$erljz(K+ zoE(};>2d3xdj|;R5dB}7aXuB9-`A&Y)u|I;iFf;i=q7!dL!(O`kq(4iK7%dd2<$|V z{p_Kuk@c-19oXl#%)Udv`?)6h)>AKbJhf4!cMazi<_(MGEglK>WSiOfl{UF4^qT>M za01YOoJZEnZgs&Jk&u@IT4*Yyio{WC$(sDUC=OI4Ov?AxnP0e~+sl3p+;*eX)+VI4 z?h+B1;Nn_jGjucgNL{`0pee?`GB3dYQ@E`*aO0g{s&g9D1vpl_rp>6Wf)idaP@yxP zZN0#1E^!0PF`fYAT~l*$Guw>>gf&B&U7CWQ=tNr9a%@(P2r!;{j3%r^_G8QE>}MLh z)utDmOE^g;w81l`0O|F+ptc9xAu3=)2H)F^)M%Ep8b`axHVuU<7w8(ax2r?uQUR}q zmSsb&??Z1ipk?pBS(&B_M7#nPgrQ3($wew)JevcFjHJCo8|RlZgUqSF#5jz{>r0aA z=Wdu``E09c6?lSTt=zboFxA9nOe_ZwGs&QzAg^LNMDD-qwCGxw+!D0hFroVB<{rwU zLp8AhxmNsefECXzp3gG{DAyXrle};Et@XK~vH-0-$Xtpg+e!omiBwUM2$(=!-TMJg zj!zrN&uL)D%hOz^Hj?B>y`Vv_aQ0DHU8_@cNPx^9a`$frkkGbtve)uHPCJpIW*v_X z!l_KM$}eyfd)P|_`0xE|HPx~N*FRNyqXOe$%pPBa_|}2y2F3}#NGJe(6y*3D3hdWa z`ClKFIoTD@8{&392?Pa1($^UM%)a>)@s6OWYaH*Qp_aXVM>K^BV$wh{9)dy^mLiZi zH3A5Q*+0n9A4&3$f9N4*JU;bv&7V>jL_7gRRYtc>$^E5&;>oq%4*qMGXNrUbgov8z zSE`}n_=W#xoSMc_DjCeUvGjv7*eQb%etN4474tx)$b;ztN3KOvfz77PuLExRT51#9 zdqSz5o8L445R;~E*g-$g1IXCw@N9z-g-54#uiu5 zxYzoL_~T`^7&WTo|7HOcVrRsJLQ7Z+TZI&L)GwJFcY^cLkx6K2bD50y#}`nhjO zSu|UqE%~pptZazS^!%Ikr=p_rcGs?5Y6%!xR1Kq50pmytl9~wKK31{>iHlcWQrj3{C2Nw}UyDNIfNs}2A6v!7*T~S8+ zMSNs3-}dcDZe4lY=zj>!g1#FgGIG*Ib8yJ)ESv4Edxd87(E2P35L~T}e`Vz+D>UDBG1Bjm`}EQqWT!9UdgC_2J-!cg~&}uXL^z}pE}8Kdhg(aw!>^_q&UCL zhZEH!8>-U_Zr2`LGe6H}aHcy(mJuMkZGm@S#}Cm2AgBba>Scqyou;JXSm7^Re{9{J z5C~_8%k*q`B^udr`M(p$z?? zu;dz9WJjP#fVsZ?)`&zz>dm^N&82=vk?_iF?dHFH8NTV`Ze|4-Aoi?RgFKAw48-7-EOVw?u&L>^~+GGZHF{ zksHsGh;OtRsVhjmfaG;m`$J&EG%qKUmggT<`L5O(%0OQpg7U!~O#*DjXt3AJFzQZ- zb%%ulheCd@+NTrdwDGehpKEq^=Rm^)@RkOY)VKBU6zJ&Db;)99|Hilphdx`V#)zlM zZ@gyrb8-qRvpTAB=29#JnE`hgK@S&|h=4Q@^!HT}bC;jDG`)O1wg2i|=6yJ=NRYeD z(O(fnGFdG&5i+QF}h6lQhm zsAL4Rl_=?|eoEIY2V&F~fFQxp60 z4~jY}EKc&}N%-aVE)gKbug5sOmx@t5nW^F4rB>1 zE~w-rc^?*1WsT~C4BAQah;9B0lGoQbVMlL-Fk~yq3%Jeq2)Fs%1llS_%W}aAZG9-P zDkI1t=!ln$$sk}Fwm1nn7D`_YX-G94iPt@OO_wi3oij_^r(0h)do|hnLCPU88xSy^+RQVQLXEl9+=Sx4e1Ob)_JrD(lgeIdrFIoA7Jvw8p#CxSq z{gmiz@!-&Kq#Nzb8m_Mu7R&NHR=g(U{kDFG144!7ywNNRPFUC?4zRNl=OQ2A7VOEC zGTo=@6lnh$5ViYV2abH z(9^+UE-lYoWEBWeC1M1=@295QV)?>_v~=rjkPE*K+1cwODSB7=qylmkA6*jRr#}<@ zE+IW7?w3-Kw-c^dIBVI?M~=qAoAsC;%sq?STYSBFDm=ti(7&1}rFTX}3*@e}+YX%v z`Izn41C!3|)NW3#sdi5>_%GUsjOy-Tb+lm_rLNXBH|00ShAf2~^$ESqE) zPS2OGCo!%DP1iD8@eAyAzrk(kR>+8~)JUPRZ4dDoH4!dRpc!=uJXD{nH0|uKd z+Mv1!?_RCTR&nD->+=+3dk1bufss1W%zf>|Dy70|$FM`X+ub;lAQv>u0kl^QgDkf) zsNW#)>_-M4_XNv4)TVdcGP>f6RF|h3`*bXPV1jQLiaKye1Q!(QMV68xT%(iCp0UlO z-0V(x)r*k;>DBq-LOz(5^75|b1Bv*G$BoKfX9-0hNnuU`bl~egv{?-+U4L@Mx@EWT zypp|a=@EZt7XJy==L<%06Fvf)(bSBjo1myq1EzYaiu!k}Mpq-&3(CEe*4NKg_bS8{ zX;F#mRcd`k`$k^ZIfX%j1b9iCJZW%}nEYa~D6(~+bM;B(tLe~iabW>i>_T1KKvpi7 z01pNkCzoCBEK zMxge|gO@6fMpmx01n=`cmksBpCRSW?7Fv7k*V)>3l1KxZLASebjbx_^ZP{@)y`L6; zKT6)%*DGvN8V-l!mo4Fng)GI^qLd|$XCNLTO*fM3p9w&ug`Mb>ZBDyie|J>NVVzmI zvF9ldU;OM~Vzko75T$j`R?-m7_~m)@vdB@93WgK}Vlhjye~|_CuB&mNS^QTd02ZqI zYNW%a>HgOmx3Nqn!3>Jh$J)~v$>E*!>$Lc1L)xmvd$l+4LV^rXB)Na>3`|}23r6M3 zp6d+%Rx(b#+oAq!c&qXRtot0=dYZe~>MUjS!d-2-9^4)U7xYh%3_{Lk)n|S$DKr?L z7(Tx_RyDlh6|Tk;w!F>2gSOJ0Sr0=y+#KFXvEspZF~H}8TaV5XqPpR6kOHA#W(T)< zmXX489`i>ZM$P%W>mrj8Sauz-@ zIw6n2UI4J1WV=sGsxrmu0Ye(rU{nETKN^Pl6NvuoJ=!%t`gC^Jp|gwAYW-PhEI zz7|j+>ArKzDH000;I0r*a4`L_X)H1KMV!M<+E3S5(^|WEO6RRb*YBUHyX*1E&is4q+_Mn))$bHwif^$7;!yw+bO5GV*=u+}K4&wgQg;GYZ@^)(@!s%<>_FiS?z_Hp~bid3t|N)i7V9*4=Xs3T7=L%S0i=y?W0jq*Vd0oTiN^_ zBCQ;~FxdUil+)M7#w)5cRN#bfr{f_EstN!>WT4Z>K!aZ?ZRjt`KKu;|sg1@@d4+~z zgU#jW-;c!Ae;N&lnN3oRFM7^R>*ZYb6=$18rCsEKpHNAi#pb4Vv1S?6G}OE;McFhb z__QW}9bl6^(hQK34GQ*OEYTj{%Dx0_R86g`g=8{HPzE{x3~ke4CRJLAW(G+mhFwXa zvi4;H;}qA2BC{AWDQ~}~*jUo!_*$zKtUqIzwa%Yk!hvxS;(}s8I3k20MV);s4i$f_ zSp1!zvCeLglFXX1r0Ka}WISV#eUl=3E)~rpG=i1KxX1&L)MF6uCO=*VfRdF)(*CwpEVM^#dr1*fj}`8LxxlH?IN zcxmtJ>f?w#4d_@ChpvCwAeWm?71!^``g9Lq+KOXOLq^!j43NAQd>?9EQQl(r}(VU8;Pbj-Qan{N0h76z#3m>c1RZnTUyYrj-g zU_J~76iPqtd0NP$hyD?wp24auDjsBgWIa{bzMsQEiQCP^(mQlzz}Dc=YaF^wYNZhkFWyR)Dw}n3eLtmp{4R zUB}Pu_|6JMKVpIzQtM@xA)}=DUMktC3ul1mje_xH2Db~f0v{&iN|u+go2q$T=Xfh^j5<{aZ69Ld2qiLDU(6q7s<;2WdX$lV3%p*9hEZ- zrB@$VOhv}sZcflfqs>oMywB>UgRlS5wtw@V^BdZ@*-dU4NCQOULKv*T ztT`>{gRgc0@9vjd{`47-p7xMpyGL;R<<*YuMYxGLB|y_CX@9}28Sw7vG4D2dN^$_> z3R#3p6TPpE2QYHFFOpiK)n=^V_#_5+8Y`w~_w`L7CINb~K%!Lg^APupR7>i>4CZ;O z)s-sAjYw~Pqb2qGIP)7r>g7lCavA^?q$+$y@p%7fHU+rRXAe7POVwbx_#3rpUllba zDXA%cJVwXtlnDv-4Ah|!8j`GT_#qe&Ue;r|*u2!~-jhXNIm&0>NR`26U&KM%jN>bq-2_9J8h4K`-hAtql3)dw>zNj{j}{efk?tnF4d@{4VsjcB-=602 zv1O5XWRQXI?~X({3>Iq#MI0*^s*wr~OT@Un_kYuDUG~dI3`k$;a$#JA(cJoZS*P`t z4h39o85NunxdP*cefp2aLYeooT$P?!k9V&pN!Zc%3r0-V)TtY;-qu8%!3~vBDLJL# zv=~W5G#kVX+>8hQ@Uq;)j=`SiA07mRtEG0oG?LtzjPNjypYX|2i+H_g5Qjn<3(s`0 zXkk#uAWF2vG0}(|8Tvtf3#p*_pf#*Qk84--DvCnJ>MIbwvhl-$V8^ULdRm_TJx0G2 zY9g`TsD6sQM#_TM0CtzUdYaYFI%;nqN=ucRFx(Q?j+3MbqSQWjOj+bP#`vM`8@ao| zfr?diN8POoFTLyB`0-JaR7z7Z|H!C!!nMW7Ye_@}MYa1c>ONhLK2xtYnjYD=s`>0H z^6xZ=jj-xq*PFrg+T;)xtjsa}45r;H-yhv5&k&n`)ib`y4wq7<`g`L1I!c3?K#3{h zbcGckfl{%gxXCB>XxQQoUap#X76;wHRBLk>63h_nE`A#zUTf#0hF zsWz?DAw;sCUAD)$gI6?T*joSELFAZ^n?&IH(ew+|LSbl6kgcv~|S&EP9!64wyyPSq1rOh9RQkMHM z;eFU=3m|Gn*x5l+APLQyMW~9-vSymRad_WY*TVdE*0p&4WPIHBtpf%O+AOGC$h!lM zc01-Ql`oE*?_oO47$v8%LXx+E(S6Ghp=Dw%`#Uh-a}_;u7Tw@ zE{qZHQhJ%qm|#U}Ow%id<26vwu~;LzUR^c0|Mt#hFm9c@^D?JFNTraKCryB`x>$?u zFGyOir)YJ>bCf}T$7Cz3j8MAUq+geUhf1NtH1f5w=xY zZU`tDnuu&3YM)Aykoi3(Tw1?420EBQyT291-LEE@=^tKmmY*5iQ8ymfiiu|Kek}>; zEN%&BkZ>)f4=vF@E3S~&@!~ZtKk`&ELNnPC(ggOnOpMSw!t2}|%9Qlof34-=dc~;M z+&~YnZoBZ=wFP~){Ln)?h@TzsP+%5iT{*LJ8RVvoEITn4#_zcse*}bsCPIABy#8aDWTG}mIBmY} zd&dF20GT)?MZ!*b)~s3oSvwLvnf?GR^#W!vfXF+p+!u$Hvo!|}MoWVdlW}y7LXMYi z-p%@FOK47%?{mQ)hs}-)%Nz~Wved4Ze6ao>Gs`p)T@{ds&g8j=)_g$oacG%?N)0Q z+~On;EVoWI^pgS*WGaQg*|^4Xgt!a_F@2v@zI3cO?OjyJ#hjw>$n>;#lt*m}#bM0d zSu+|ChI0c(PpZzEd1|XT__xF^^EUJx9qlejaCrEb_MYY(!7?vVCnE%?8RBjN1}=_n zwFwMajmHAP$lG+bR36mcRMC3B5D;fkpKNNl-hVHE5veA_1(}f-FZ?3v>QxC0b##@h z@c;7Gj!I9|11+A+M(NVE@@)QO#LitRvAT%!gE;p$Boih06 zTyx|3sp*zm6d))ajitE+T0`3H1Fa6FALbnl!rbu>ohV#DinhLO3~G>Ga_M$foBpu{ znQ7@y0>K~;7@#xf(RDRy|6*F^@p2ls2s2|u-s;fiCP(xwoL~z2;@QQ;Ebq<65%2ko z-m$BJO7(l1v>)#EQApVysocWgB+D4rV2k9{Ttp|38duzQIINEDRsxxs$1Oj*uMc*F zA3}eb1-B-1?{|YfwLqZliDbkDZ(-zRU~oa1Haue?`G-$fwbMZJ4{~q}X4i&)(gw1H znyYel9F?}*y`Aus$2w#*Zit8YyDnZD0 zQC5XVPG0A{-tC;a=g?O;D-Q!h3?e*?YU7n4gD)A><|I>*z)N&Wvt!hIrUde$iYSzd za$|O?VYYE+{m!o{liCC@lGHsR!1vW#UFWX?0JFzdSpZdC+{115cn;!m+l#Es$#uI? ze-M#E_l5UB5#X|K!&&gynMxbMMBhYAV|TCJGW-J`^32D zd{=9K`OH_8H@aRUYDSLwCo8bhU2yq$-T}1a*Q`|tW&(K;-`8)xAdWpD)3l9T6V{ix z$D)Z8yqa-Q8zi>56XEqcV_8=G+mkC1uOJ|{0Wr2@IjM7n>zo8;U+8X(!S)?zy@63&O~)|v`{Ob6(=MxbgSii!cxEvkOPNk7YHvx zfE8O+L>@eeX&yR>Ke6&GlwH11lge%BbizFciODFu(Pft-QU2Spj|{r%I$}SLWVN8j zBw+^)313vX^bmhN%*SXW|IKjxHFJGSh!Guh1cJFJ=JM0DA zmoB>p-}yeEJYOSqL$VvpC&}~gN><_4Y2%7IP`=HMU9BmX3kB#DWEmVv|Dv~! zaLqN@m`kUF_ZKun)m}d)666H4+FAREloM3hXIS)>Iqlb# z8+xt(#Du8{DA~*2&-(pn?@xF#tCVed<}`i8tpMt@r`wAR8fmj;&hyQ1G$<)_iK2xJ zl0Qh<`o0p47Q>zmpg;r&Ag43mQ3FtZLQdC&qr|8G%9GU85l6@472nt%tc)1W)> z6URCVvf05P$FqpVU_|(DJ10C=HB0KGB2|L|z z-W8?13MW*6j~}Oe{Nv-Rlf>WLg-2JkjAlt6P0qy6*A6LY@P2?{w3Q3)zF4l) zr~<>bt52%Do4ze})owrK5wMvyLwMJZO9edn;a5MPD4VDU1ATMwq=b@jr@IhD@n#zP z4$hOt5Kb7A0;g65@yX}f4_ytfyROiyhTUvUMhK5rWg(j!DwWVFsrr{kFGGMzAC?g zIJ*w`m15UXV!tRpH_gX0Mj2sSF^z7VZhKESTNEOh<#yW`n-Nxr0IVrkMb)tI5<&ab z_xz(?39BAYE8nm>2bzh)RZ1~dZ5b{@87@81Y;BEf@b}QJ&1X?`vtUK#{NL}*#)qKW zj_*uy4*jzcNfxq$_;OUm9s|j=Ti@H4BQGyc>PfG{_sk8$NlRhYpQovFE|m;;lo4aiDjTY|b-o8=_Vc&D^`Jm$d=3L?A9v-^>uFg+si&K-F9#nV zpHyHVCWqLRH?6=ZZh0E)cKxhg>Y0!3k1ockgsGis3*KVqZRXdXr^K+55z`;;T7IL` zjVp_t>xr1F?LZCqxrSZHI^5fI^YEbfZlJgIcD3)J#mirQFRjkF#rU7-a%ZcsVK7jL z3sPM(5_05Ox{~ZBESP>~idRbFhhMmYVvgk~&3fjn*^xmM40j!`vJxgEE9dSu3pN}^Zi zv%5LW$zVStUl=X|uad_kBd3AJBvB2oo-fFnrSDa`T47UjRm#;jgyXTND0_ye>%U#L zYFgZD$5Z4Ig)ze~@E}c$10;N9dmea8)SwL%ib0B?G-^Mz+@}fOe4z}rlVl1^`ARM5 ze9Oz(cJAJ_7hi^3V#iGrReFSY8v_xxw+w3Z7>n?8R2!``dKIj2eic~FakVE8Q>1< zz_2%oq3IZryh@qe5E8djbrZF}Q2)m;>n~l|gkWff0mZ7Xub0wFsw8`JC7UbTjKEuc z{#E)w#`ou+^MH~4&KC)<7EfiQvFf3;ePF=VWz4RTTC)Gf6)yf`4G4eZsx+pld$n~O@x zh-?ZfG=liYAiO^#qLh5D`y5> zo+;!Z>SKpOV7MliJ7HWFgpLaW6}XqYfXOGlBiP-m~uVLUeeLH~sVCCz*KFH;S~XboScUVN2m@RBwO zhzP}FPaS5Qn?5@`P|wmqWsA3*ciW5Q@5S9N;sOJdJPxJwK1}CdK`+c%oBZrAO~ii2 zNk-b6p_~wVSkgEG)=66bhvC-;=3XuD;@LuNaW1_zsB!Vx4H`h!Tw|({TU39HPZl&h zPq^0dO#%M&SwTDQi&P@(mlAeWEp;Z$D-k|M>IYXO4l8MY%30&q!z-n{)wwce9tsiT zavF~A&6@r5OCf$ga5-8j@4mvZxx#4L5iOu4>FN7`LDjEDwTUQlVRrj>_Idq4_p`;sW>5>qnyBnlC zMTx^JAt9iMbeD8D$N{9JOH#T+O1i#{|J(0|9~b+~+H2OVXJ(!?Yj$r>+^{umh*ZrO z?8DA~;3l(lM~aYz5_V2ZK)y1L{Ym=pQhM7R@iQLU0f1NRztlRzP{Hz%FSQ5E*g-jM zRK>vM0@uSF9&|NG=ZxEAOo2!~ma6OTKF8{D_Ay@=paZMugy(g=PP zB0&KfNJu9^EGdM9LyL~kryTGy5+mu(P4MP*COJTrk7xAu#l+Wb#~*%EkE4e05)ucANBJ5VO8SC5wl1V5-D)X^?+cPUQW~&S70FT z?!VH4kx_Yz!?C-hMABcnSi{O}p5Vx_*SFVNp2G@cptcT{+tff`3e<_x7qb2 zb30%@yffU()Waj_OVo+h-WO^?Bg!A54sPZm-iTD+1CE;j%FCC%+@ijd z@hjDdvUI^tOz%C4qGM*=Z`{AwKTp*+FnPg1-sR@f=b0HFB3t52M}B4u zJ0w~u)=1IGukxkjKJ#-jte@517pzMtoao)t1?AN53qy~ZMgllP>~`4!@TMi6X!y-w zrU=T)X|_=pcih0nsFQ$tMM=|IfaLKT%48>!t}c4m&y6_6LIT`y+Gi1}y~$%31Jy?? zner?|9W&dNTZ{E76Hprb^J5gDDm&z;fnhZy1z^?-GeV-3E@?&0dMTs*xtz^zIKz6S zRyxSkr-=#UbshZy?{b2`YsIWehi{0u-Yw3MK#3dpXzuR;t(y7cZIEx+F?Yf%ASmd3 z!TJoVqWu_EBpp}c=+LngEj=UG$A+o~kr@G!CAHefO0S6wLo`{%A{qIL~*k zyqYL+-){yvdQm8nnw%;lG7;3ZnSA(^(U`MDc)pFDFk<;fgcd9{Y34$I-AyPudx3lP zSm%T76B5h23D6yQJ6lkSIHCyuxUmBwgy9;hIJ3eYJ?W zIdVfPEct>~J>=SXCd)DI+c&mS9E2V3^I!M+CW80V2UXNMxNk3()?Z-<(b*ncH}muR zZoZZhsSeRcN8+pT%)r7fR8di}@bA3p(v$AMS523gIK}s6AnZu4*@_zy@#I}dU7Mx?iAIZP?0T_XGWi*T&p)|GhdvF+Jo-3Kf1M=LYIr=Hi$? zzuB%@Kq}%%QB`k9kyjpo4udEws|b&M;XhP*hL&MYi=d89_^M?phAw_nMGhvDdZ~E zI9-LKb9-ZHKh;X+iHhv*+d%-A% zAuloKqzEI@kosbxk%WcZoO)@};;d3>l%=r)As*2rF~j|7Gj?={a0Va3WVlmkHyrjc z?*$yyfIB54BV)1PV*0N6=DMw-2DMv! zD?V#a9K#|#8dn<@DdwcxqAXIrn?gemhq@K5#=|C(=Zv-L6a}$!jYnMyyEE~H>+kGq z;-+Jv3vW-Tt-yu>)ndxxno0i!2frB5n@CC7aKZ}jBEXJ~Mlde#E;OBP9p`3#-~UFF zRchZy99fs~QirGqA0ui6sgD?Qbg%T&)Mny?_uX&FqBCQ3d+m8tU{HOD&hp4kYw~2) zTio-V7!3A(_^(gP{95ol#w%m%Wr+GS+R)Cof)vOaqz9vC&ap&4O4L&yA z0?`ZpIpZ3a_n^@Pgx_#Ke{OJA^R(f1xqt7>(t4eRGsa9-!m;e>9edEjg*sW+kRa6) ze$f)4@np&rdfKt6(tLYDH>cWkWr6T-A-_?^?2eg#NX%11JzM)v5S*krpQG-rYYddt zRC3&OSWQi)KTV(Zk)9|p=w`EErlcB;PW{HoT)MCR_RQJ2&ze`?ps0L2)ncNcdElU@ z&zl}b-TooEJESVn%n#*vI@Pw1!ZDf3^e1*Af}`o)XI~T)^rsF4`zBwEgbeWo&7Cv< zcq)3Ja$!W(Sj5V9R>GdJfau1`o#wco=fOsb_`zl>dV!^^rkbN)``~oBoNf9hUPkr%CqyTpqunVx~5M=-0VEnSC+rif^S+)8yOjfHX|8VtRiJ???Yw| zQ-I|}LEvo}E~WD)y&$p75sTIFkfIV(aEzBD=`vz2Y6tf!#W^`a=2^ue*BhDy;2@$0 z#W|MdZxj^pk0vLA-uo}I%J~UtdLN;*vQiSYW2w8jNi#U#Jkg|>Mg}~|%1D>L@{M#_ z2=^PuSKsW(QiL;eKtO;xTPu0e zfXyeO(eVaDP!(==Fxn`CompdCHOW)w7d6#ko-xr@F^oQ&iP{39hgnqkBB#uG=XuCL zFg#6pGe2JrW_(MU)`6p}qH5{=TJCaY{`gJXc6kod!{FcAGI`=uZMkm5DEDokV^HRC zf{xh3YAmJulL~!~?EN^ah;(FzeE`rCK@x$0T3*ElwH!_M6>DSw6A)ks#PA$;_p`wq z7*HBttkSX7v+c%mG+-OYVVb$+z8b5sx5CnKsu=4aKu&@2JQJOc<4I+RB0F4&rmaCutTA?KlgbtS@>4;mo z#q8{`4h|2`+!IrLeCb|U*gFpE*TyW&2>QPHD)>qo61FmE0>p+esbfA_a(Kg4d--J5 z7!=Fx$R0^&v8Op*n_}IOsKltOtPEFb^sCg7*JEyF@=;w?8c1sOdi8VY!*4Gi@7%hn zx!0ef5(~H`co^+oZo1)Gv$HUoU(EzUK(N*|!6zF-ro~EHe#Dw!MzN zbZAHVKZQ1!5N72AQm&b@LkgsV2W z$iC>}h|Frc%B?$!gviD> zD^N_7oB!Zo%%8C+^R=f@h$rIeO6~<8Z?NY&RU;O+*AEXZRRG=zL&Y_4Ij&-U+_vAH zv@q1GeA<;e6SbdJCpOenRmD8-4|Qs8E@>fftMe!dIR@uH_ojYvY%KWeR}v*F|GgW@ zZ}tIj|El%ImoH45pV^U)>b_fc!;^+IZ9RBxswvzx*}Q(<=)wxbRhd+L8%75JbDwiw zFOx-S;*T#0_>-|Ji?lhdoc=;j{BFuspGtTjn`U0g^>AbRgS{HzDd{Le{G`hTx$i%O z3_iTuc5svns;JBI-~zp+LO^ppRb{pa7Z9gzFv?M8+_SKsHtFl-?Q8Tjw={t#@Hof0 z7ZRCcnbp2D?lQD`!dp1xw_A8{Km9-fjb1Cw9(`@#jdo8bk~zf9XfPslcH3 z*|TTr9M*e!Y+xji+OO|m$luTylG`N%wbcJIEo5xUNI7NiJaum!dEB)fl0w*{3 zw_<4Qe5iuZhv8o~#?wKt=`(6+DQTJVG7zHTt{b`vpJzhd;*%jb7@|Nl&l@pQql(4@ z#?&E@8O0fT_O*rCwWKbe_|(%=`g_>v6(y%BWtTTS{dlYv%u2{Vk2<&FuG7msCm}%x zM26f3y}-@uDKO=&D(%=KFpJbfF5vd6ugj_#G91q*eq1`Mne+I#;N|y`sm8Sz3>)v^FCE zEK?>9;_7oI3^C@sA$WT*(Q+TP57}faLzDWSJyy4PW1e))dD7T z)`|6eHj>Mcod36h9yI-NKamfdivrkNrPvM|x4z6Tu=KL64UP5ToGUX(K&vTNj>c)! zwvX=Wzy~faEGkdt@L0;=;uN)I%FLwBp5_I@K~YwPOF`oimX+AJo*HMs9FT0_{T5Bf z-vO`d;j6aW;MHaP1FiM;!ld?eIp-BXW`OSvNqyV9g?*1dR0m>hCb@jllqwSv8FX+GyvaPS$M;vqDEsZ^BXs zIkh-#x+I=3lHh)LDz-`QdcKmTi?dTVtSh@K{MpCjt_dy$tV$oP%Bq%}Cu5+#t>&*R zg~E3ZBn-^He)=GOpgg2+X#C}?#nLaftzrw>%-&iYv*~Pe^n(Mcf=of|7(U7SA_SRE zf&Mt99@!}8qs_0)^8m}-f!02w{+wL-Rf>79oMOE`MRr4fF))@kiJRJYj9eQ+kKY*o zoH3%>-wAfe&RKIL?NMi&zmpr*DAmyEG|T~E|2&)u2_TN#0pOlUvrawxYoaGNNN(@a z^zh6l9E?qU0vwH6YOA(vxRkDL<`lh~+z^(9UACDu4~FLMnN&!l^^&wVy)h6eJ@hR| z-XLz8%7B4-j>gs>D0o7#?%^SFB$t|+UF`9hrpdzG!BX?Bgp`pjvl#JY^-}-Ftgto1 zUCZ37R}&r1EE(&_pm(co-*3!G6Y-9uZr@vM0kBial311P7+X{*_3F#gBO!K#{=U?W zpOy7kh(09}nQu3vnh53%20XFC=1d$I|9!vlhEiT$`7WM+D8D$SEtu}-X0jyci>rh7 z7pZy>7elyd{nmN@!q1<}QBG62mB?BWr!Z|@>w9{hJ+mmOYOdzUgN(Tt8qITMaf-kb;6OmraqibM)HY?`R#dy=L7YxJ93u-$xS+@0ezu&fl@ZHiXdObL`qAv^1=jDG~ltv`qUHc(=0^lC+ z!6jQ&L!V^_0NZ{0n)kN6WVCnt4HI*0hlXkB)iDq{6&3X_;tz8iEn<8)GMXh;zz2T0 zl?yaw$#zP!7o4fYLb<<9gi-CVwb#S(q1yNW@<9I~bnvg*ocF61;DG8top{T}rlPD| z@zsCYMBQKiQ|Ok4L}6i#_t-{f*R%|b!$#Vzm#*`l_jya1OgD9WY|!YWrnMdcmXCX> zN04sc*_c&U(J}+-I;1I#34O%b+MM+9Uu!-tE-cW!UMT4%CDr&cI&GolsKnk%vI`wF z&Pb^5@_LS&#UU)LDF8}@1Wqq^4D;1xVA1BCv&|{lm@jeP{O2WtBa;{}H8nP6?`zRm zTw2kO5xBn_VeS@l)nwquWsaS0^2-NeD(-7KYJILd5&;KoQMz1L16XEVP6hb93u7rz zKfe<89k`Q_>?GLIMKxa1Ppo#{_h=zNPm+|Z=()ZY8Q-a`JvK6&&(atA>9?^ZnfNPY z$Kk9QDQi!J>+8Uyz{RW_0OWA=F%f(=X4Tcz4(DUy-aZBcOo^}96F&|0HI>`gTIF5M z8rW|w6&L5^Pu+eBvv3<68W_--QJko49zdG8J&~OAjRS$Uk3u_5b-3|Za_Bolx?+w# zM@oRd-X{g*Yz6(FGjye{rLV}QhXI;LuVXTNhy=`uiaZk!y3VJb_aOQqoTaqw!HNa$ z3~3)NcL1TKv;qQOTmz&=I-c5F8P!!WZNX?@m_~CV6~A(RRP2M%4?Oe)k?e)q zRGQX|r8mL2QS;%^5Ush0(Ew((4378i6D>eQ0fiIuG zAd}Va2p|ejz)MppMurFuA|a6=i@~qW@RTkj0F1Iiw2O-~8`UIEt~7AF|Kfcmj_3tC z)D_+~h}CGm5k4BUIYUxZXNYhDD2m3%f(^kASdD{c~ zkL2^#AeiTmI~>WU=6?Mt%Ej^QJ;mol+u;r>pC^wV^aGg=8W1aa|0V;;jQ6JV$4|_k z`JZQdFD8Hgb}niy<)}8KN9#H_3y$tx)9le9La~VI1w08)i3Egq*k~AU38V*k>&(hM ze4y|mx?@y9{8+A3@J*C8K+o?t4UMlp0ip0C4+u_~8J<<6VD2 zcOr_e4zWb)HPk6Vp$`MlP8{$s?JCY|a{ioQTZv|Pi$P15gbS!j+%}m3`>sP0?X9gG zjC_Id(|dAit`)V%LkhO*{8Jd0x0*e_RsI2A;k9Ys>RFFxg$X`?{K1q58hjX(lB3_s z*LxqoV*;qi_#3G5&KCTt_mTI;`Z5LUJ8)Mb^W}2H5Wa(yK1DK4NkNU*C;6r;3VaLy{1x70p~)OlY?3a}|CVJNS~`yCaGTN8 zkplW&&7}kC@iA~PI725GI{9enQ@QA^iQ2bD$%sp9Y9+knXj|*h@Gn^BmeSdv^m5?BG zf^t0MQSadBD(@Lp$L5)nH?dlQM1oo1VvYGp@n?}MKDwcjlb9eI7an352Y3`wjXo=C z6M1|HNt&PEq&%&up)05=`A#2jbQLhZR6{z3^9fr<-cZx!1*7$pU}ZB>Wi{O)6VPCf z_RlbtrJ?Y6yr4g%l$X>tnQAUhGzp(;;+!;zh~=-*92ePX5(jePNH4lG6c`)~Qv^~~ z`*%Fe-ND571p1J+ga|v!d^B&TPF~z&M?SWTOsiadO%h8Iszv zZQ^X>F+Tng4z9r0#0_uV(y-`M9ANqEEr+a`-1W{vn#Oha=WT9fe1K$3bzS7*} za}`B1fJ`2E^d9?6V)W&rdHxAVk~}y5Y{_4AZ3EdGdf#_s)3T6^B$t5+jnQvu zyDj?Ee)IiK77~(8=eEfDM2{kde3D>!F!mygfGfMvu|5N_&k+CnbvhVoExqlXH$&=b z=WQ`ac~v;}>ldn=2a06F{73jwY~6EVMrZbfk*!KXvlk-iVdZ<=*i>N_QWHP>Uf0a% z8+Gk(ka2Kw>We%{ENW^(c^X^y?51R=IZU?Gu&zS}4UdkJAT@K@z32#?tz8-P6?wXO zrIofLX&It{TjFQ{rQj);N3bOPv~#KYMe&_bqMbUjn9k(XS|moZ>T-Z84q12Az4XVL zzL645x@xv@u0v1)raawI)E~vZ;5Q3~(|zDM2-0tp|Cqc&d)LBx530p*|4r?)FRLl* zEdgS4NaFkVuTmbl&8O})&CSiDvs2CkE#x{H($A$62d?Q_D9s4C;{`QQ{+ebzqPXMu zqlrtVty4Y>|Ag^rO|Z=V-FR17i016Erp-F+pz(*_k_Rqhxa#i#r9;n|@hQFA#M12_nq1Ec)z zo}NXRgOn_f!Jj+1k;t0ZvE9C7+FC_fG!Nf%43lNNli%EO9Uys#0?~=na6^N~Rlm#6 zX}m>FjG)4Jgbr0}BS*2G*>=>V9Z?hT$X-iJt9~5`(A#ap!^WX!xWx6#wJi7^#f~UL zBMJT7NP#(p`p;_9e%1ra>!emC(G=9dq2xaOAH6xaX7wISHHffrOu`kOY#{H4vU)%P z6U4Bz1T#0F&fcD)@HoMKCoBM1j_8%R;TO88(CtaeOqHwtd3~kp^apuH(9nBDW<`7m{F|MK5fT6#kxV~@T2<(iS$TL6HW{l#&jed71Iz9u#8h67zb-dJT3=fLFQ5#AKqD#5}HYal;_qwL6VVCN1hCEB{FR{yG)Wp^Oo=`Vw*H+)*63&Z^1f~j?Y*@2t-B$ zuPj|vBx5QYiVN{a0V_LeWX^`9`pUCm>NtFWsN4E5wW%fO`5|Xnj6G<&lesBiQVRxe zC5RhX)ik#D9hXfSjBLWST(Y@LG3;Dcm@HU))Xc@vX|12ITW3%$KN`|xLtNxJ$iGf|`*?b{4Nt*p6-LUfw}it!$B>u3ffn-rwFy97^&F=YUu?ZbwN900_N@ziN8GLAvf78j>Dc zzX>IU3~eUq^Sa{DE&|H76;ysf!D%O4UhabB<&O87J)3Ft>HX*wBg$o{p{(eaP8o5Ar+zP&A-<@ zge_jfi9>ZJ5nB$BcG75`M-agosDc21*s;R?Yv6$ro*&6=*c6SG3%0GSv1GE*^i;ws zmpr$rt!sFnY>+_Nd5D)KznUQb=^#UNZcg1<@rACR3z z9cJ-AS-%|f=9c%P3ON@%rp0rCMI@{jQ5G#rlVWjSa@U&#P~RDYtij9F3aGwF}@M*>mbNrT!DH z;rmax=dP{blKY`t&k?}E#A{PyK!oK7*5Yu7=WUj7l7eJ}owI8=c&mX6?%DNAm?b)U z4*~gmb}{eaJ+_Q$!^D(Du^O1!@cS)$3j4O!@@cb@X~ovlN7diFG6BEmbyUMwI84=k z`UeYs0&v`ed7>C^GJi@+j=J{N?I)15R?vDPA}YFaie?T&jb!9`=Hc538zpjn`7laj zXlUq+6$u_(lwu9uqrqET9^~B)-0u%Pnj(wUn%?DYA(W)eRMBa1x6-DDLuza@M1xLE zE?R%W&Ctw?P|S+7JLl#^I#(*!6fbytmhmpf=H?<}&T$*XpKdop%1R;sjiVCFy--qO z$EDtpx7AB5Ly7V->7C5SfI-{ub#%IoVh;oFD~c6)h&+}g#wSjzD@mV7E2O*iWHiW8 zU+2y^WA^d^u5}_`JBcVo#>0R85`gfWjhIE=?M6r z3(Ay@{pr13;P^_?ZE}YMH(K_Cd;HoBg@?Oj>d5nA>{oc&&5%zV1YD`>3;S-uBZ^Zi>Tlf(g(h5?k=X{2^Z z^WvA^?XIMsk`AYru(=ieX!k#KrGd@e-#-qsVCr)l))hX26~IaxGWkiw@b~$73-v>6 zxK8&O6+lnd6D3P0#LL~dCCtlnxEiXFhf;r!QttE+blD(L>8$<&1lbVdl}k;;)a423 z!)f%qPBU0qA{U*gn9qGZC!Aeo-@o@YktCGs9&o!U>wQGjIPpnu!eyVp>rSkz`4(L`Cm%+$d+Dbaek*ph8LRq~kkp!?;9Jw_t8 zMOxRhd?Vrkx5MwEfJF#Io+{akyx*E|MIj^xnPVKpA1kX-ex7GR4I*!{u%>bF+E)Jg zDcWg=KEQlpmaovXaijd*NbuTk^Gg4Q3S&$P-D4egg^`vL-Ox2ropKKizuwX+{#BQ=`-NV@WW8j&y+)Tk+cUe7HVdwKG? z_V_Sp8q5Iw|K%)kZTnH6D>U^x?j8qUI71|`_xEe=4Hxv8JFsSR4^)$_CRqFKHmfgQ zvB<$OXa(Za+$EKBS>w)-E9$?YwJn#Bfz;s)zdu(-hmBkOw)+wQ0fE)mNXF9ga%l}1 zSmtS!f+-ByqQpA&)Hl?RyUw_{t+`q8Y5KQTm2PG5d`>tF*0^(;zkQ3@^OZ@q8vEj6 zZKg_)SWMy(vGNRSk=znu#s2QhH|5--G$t*;%ZxcmMMPRg$7Ufq&ZQ3jUHRiq#K-q- zc+|IYZR0HqE?s0O)9m}P|9c7XIY{GAaLKk}e)}HA7x#DpzEaDXpDbVsge^{yE!I56a}nE$u{PkJzrdUvwW}Z>9{TM_!d7X=O8oP?=x@z^1ybV0PQ9{ zm(e`3DLLEQ```tO@|L~#V1>t~jjglr-qJ3WYdgF5{!mxL#G~dnr!KY%t!>T3s2--w znzl-Ic+DU)RDgfZk_HD+o^&>M=L$Zwg9dsJBq1C_(FO=F+`HDg4u>8z_H>n5qu*UrKYQL*41D!U6pA8dWc*9MCMdRp?tS*6i zv}ia|I6U~m;!yI+Z9mjdEd(5q3a^tPx>aUo z@tHL`t+iwhfPe)0eLRA=ou^{&e@B&|V}V?fX9cZ1MzP=i_e?H;un4@tv(kvgI)rv1 zE#Ib_qffn6g&L!7sX0WRY*dI58vT1TL>*YRYp063YBgBs3J!uE-2j2u-%>L=Sb-7v zX}fVI+1;>~nt1;7TWL@org~ga7?7iEwSZzRR=;~5*dL&aYWWrh*w$jTTBh)wBf0rc z=qdOg{)l+eZK(DEU%Ky{1^8w~?Y|B7(8x9tcH@IdqV~kN$Lv8|SWkeDDcyR{!6hK7o75X(mo?8msI95Ve6