From bbe78492405d7605292132e49f4b1ab0cff3d1c4 Mon Sep 17 00:00:00 2001 From: Niko Date: Sat, 31 Jul 2021 11:03:07 +0000 Subject: [PATCH 1/4] Fixes some basic grammatical mistakes (#3053) --- BUILDING_ON_FREEBSD.md | 7 ++-- BUILDING_ON_LINUX.md | 74 ++++++++++++++++++++---------------------- BUILDING_ON_MAC.md | 18 +++++----- BUILDING_ON_WINDOWS.md | 18 +++++----- CONTRIBUTING.md | 12 +++---- 5 files changed, 64 insertions(+), 65 deletions(-) diff --git a/BUILDING_ON_FREEBSD.md b/BUILDING_ON_FREEBSD.md index 74098237c..25f17f8b9 100644 --- a/BUILDING_ON_FREEBSD.md +++ b/BUILDING_ON_FREEBSD.md @@ -10,6 +10,7 @@ FreeBSD 13.0-CURRENT. 1. Install build dependencies from package sources (or build from the ports tree): `# pkg install qt5-core qt5-multimedia qt5-svg qt5-qmake qt5-buildtools gstreamer-plugins-good boost-libs rapidjson` -1. go into project directory -1. create build folder `$ mkdir build && cd build` -1. `$ qmake .. && make` +1. Go into the project directory +1. Create a build folder and go into it (`mkdir build && cd build`) +1. Proceed to compiling using the command + `qmake .. && make` diff --git a/BUILDING_ON_LINUX.md b/BUILDING_ON_LINUX.md index 401741a27..d9df2848b 100644 --- a/BUILDING_ON_LINUX.md +++ b/BUILDING_ON_LINUX.md @@ -4,27 +4,28 @@ Note on Qt version compatibility: If you are installing Qt from a package manage ## Ubuntu 18.04 -_most likely works the same for other Debian-like distros_ +_Most likely works the same for other Debian-like distros_ -1. Install dependencies `sudo apt install qttools5-dev qtmultimedia5-dev libqt5svg5-dev libboost-dev libssl-dev libboost-system-dev libboost-filesystem-dev cmake g++` +1. Install all of the dependencies using `sudo apt install qttools5-dev qtmultimedia5-dev libqt5svg5-dev libboost-dev libssl-dev libboost-system-dev libboost-filesystem-dev cmake g++` -### Through Qt Creator +### Compiling through Qt Creator -1. Install C++ IDE Qt Creator `sudo apt install qtcreator` +1. Install C++ IDE Qt Creator by using `sudo apt install qtcreator` 1. Open `chatterino.pro` with Qt Creator and select build ### Manually -1. go into project directory -1. create build folder `mkdir build && cd build` +1. Go into the project directory +1. Create a build folder and go into it (`mkdir build && cd build`) +1. Use one of the options below to compile it -#### Using QMake +### Using CMake -1. `qmake .. && make` +`cmake .. && make` -#### Using CMake +### Using QMake -1. `cmake .. && make` +`qmake .. && make` ## Arch Linux @@ -34,50 +35,47 @@ _most likely works the same for other Debian-like distros_ ### Manually -1. `sudo pacman -S qt5-base qt5-multimedia qt5-svg qt5-tools gst-plugins-ugly gst-plugins-good boost rapidjson pkgconf openssl cmake` -1. go into project directory -1. create build folder `mkdir build && cd build` +1. Install all of the dependencies using `sudo pacman -S qt5-base qt5-multimedia qt5-svg qt5-tools gst-plugins-ugly gst-plugins-good boost rapidjson pkgconf openssl cmake` +1. Go into the project directory +1. Create a build folder and go into it (`mkdir build && cd build`) +1. Use one of the options below to compile it -#### Using QMake +### Using CMake -1. `qmake .. && make` +`cmake .. && make` -#### Using CMake +### Using QMake -1. `cmake .. && make` +`qmake .. && make` ## Fedora 28 and above -_most likely works the same for other Red Hat-like distros. Substitue `dnf` with `yum`._ +_Most likely works the same for other Red Hat-like distros. Substitute `dnf` with `yum`._ -1. `sudo dnf install qt5-qtbase-devel qt5-qtmultimedia-devel qt5-qtsvg-devel libsecret-devel openssl-devel boost-devel cmake` -1. go into project directory -1. create build folder `mkdir build && cd build` - -### Using QMake - -1. `qmake-qt5 .. && make -j$(nproc)` +1. Install all of the dependencies using `sudo dnf install qt5-qtbase-devel qt5-qtmultimedia-devel qt5-qtsvg-devel libsecret-devel openssl-devel boost-devel cmake` +1. Go into the project directory +1. Create a build folder and go into it (`mkdir build && cd build`) +1. Use one of the options below to compile it ### Using CMake -1. `cmake .. && make -j$(nproc)` +`cmake .. && make -j$(nproc)` -### Optional dependencies +### Using QMake -_`gstreamer-plugins-good` package is retired in Fedora 31, see: [rhbz#1735324](https://bugzilla.redhat.com/show_bug.cgi?id=1735324)_ - -1. `sudo dnf install gstreamer-plugins-good` _(optional: for audio output)_ +`qmake-qt5 .. && make -j$(nproc)` ## NixOS 18.09+ -1. enter the development environment with all of the dependencies: `nix-shell -p openssl boost qt5.full pkg-config cmake` -1. go into project directory -1. create build folder `mkdir build && cd build` - -### Using QMake - -1. `qmake .. && make` +1. Enter the development environment with all of the dependencies: `nix-shell -p openssl boost qt5.full pkg-config cmake` +1. Go into the project directory +1. Create a build folder and go into it (`mkdir build && cd build`) +1. Use one of the options below to compile it ### Using CMake -1. `cmake .. && make` +`cmake .. && make` + +### Using QMake + +`qmake .. && make` diff --git a/BUILDING_ON_MAC.md b/BUILDING_ON_MAC.md index 3a6bcb37d..5d4182187 100644 --- a/BUILDING_ON_MAC.md +++ b/BUILDING_ON_MAC.md @@ -4,15 +4,15 @@ #### Note - Chatterino 2 is only tested on macOS 10.14 and above - anything below that is considered unsupported. It may or may not work on earlier versions -1. Install Xcode and Xcode Command Line Utilites -2. Start Xcode, settings -> Locations, activate your Command Line Tools +1. Install Xcode and Xcode Command Line Utilities +2. Start Xcode, go into Settings -> Locations, and activate your Command Line Tools 3. Install brew https://brew.sh/ -4. `brew install boost openssl rapidjson` -5. `brew install qt` -6. Step 5 should output some directions to add qt to your path, you will need to do this for qmake -7. Go into project directory -8. Create build folder `mkdir build && cd build` -9. `qmake .. && make` +4. Install the dependencies using `brew install boost openssl rapidjson` +5. Install Qt using `brew install qt` +6. Step 5 should output some directions to add Qt to your path, you will need to do this for qmake +7. Go into the project directory +8. Create a build folder and go into it (`mkdir build && cd build`) +9. Compile using `qmake .. && make` _If you want to use cmake instead of qmake, just replace the above qmake command with cmake_ @@ -21,7 +21,7 @@ If the Project does not build at this point, you might need to add additional Pa `brew info openssl` `brew info boost` -If brew doesn't link openssl properly then you should be able to link it yourself using those two commands: +If brew doesn't link OpenSSL properly then you should be able to link it yourself by using these two commands: - `ln -s /usr/local/opt/openssl/lib/* /usr/local/lib` - `ln -s /usr/local/opt/openssl/include/openssl /usr/local/include/openssl` diff --git a/BUILDING_ON_WINDOWS.md b/BUILDING_ON_WINDOWS.md index f46387614..a075761f8 100644 --- a/BUILDING_ON_WINDOWS.md +++ b/BUILDING_ON_WINDOWS.md @@ -1,8 +1,8 @@ # Building on Windows -**Note that installing all the development prerequisites and libraries will require about 30 GB of free disk space. Please ensure this space is available on your `C:` drive before proceeding.** +**Note that installing all of the development prerequisites and libraries will require about 30 GB of free disk space. Please ensure this space is available on your `C:` drive before proceeding.** -This guide assumes you are on a 64-bit system. You might need to manually search out alternate download links should you desire to build chatterino on a 32-bit system. +This guide assumes you are on a 64-bit system. You might need to manually search out alternate download links should you desire to build Chatterino on a 32-bit system. ## Visual Studio 2019 @@ -39,12 +39,12 @@ Note: This installation will take about 1.5 GB of disk space. ### For Qt SSL, we need OpenSSL 1.0 -1. Download OpenSSL for windows, version `1.0.2u`: **[Download](https://slproweb.com/download/Win64OpenSSL-1_0_2u.exe)** +1. Download OpenSSL for Windows, version `1.0.2u`: **[Download](https://slproweb.com/download/Win64OpenSSL-1_0_2u.exe)** 2. When prompted, install it to any arbitrary empty directory. 3. When prompted, copy the OpenSSL DLLs to "The OpenSSL binaries (/bin) directory". 4. Copy the OpenSSL 1.0 files from its `\bin` folder to `C:\local\bin` (You will need to create the folder) 5. Then copy the OpenSSL 1.1 files from its `\bin` folder to `C:\local\bin` (Overwrite any duplicate files) -6. Add `C:\local\bin` to your path folder ([Follow guide here if you don't know how to do it](https://www.computerhope.com/issues/ch000549.htm#windows10)) +6. Add `C:\local\bin` to your path folder ([Follow the guide here if you don't know how to do it](https://www.computerhope.com/issues/ch000549.htm#windows10)) **If the download links above do not work, try downloading similar 1.1.x & 1.0.x versions [here](https://slproweb.com/products/Win32OpenSSL.html). Note: Don't download the "light" installers, they do not have the required files.** @@ -82,7 +82,7 @@ Compiling with Breakpad support enables crash reports that can be of use for dev ## Run the build in Qt Creator -1. Open the `chatterino.pro` file by double-clicking or by opening it via Qt Creator. +1. Open the `chatterino.pro` file by double-clicking it, or by opening it via Qt Creator. 2. You will be presented with a screen that is titled "Configure Project". In this screen, you should have at least one option present ready to be configured, like this: ![Qt Create Configure Project screenshot](https://i.imgur.com/dbz45mB.png) 3. Select the profile(s) you want to build with and click "Configure Project". @@ -105,10 +105,10 @@ To produce a standalone package, you need to generate all required files using t To produce all supplement files for a standalone build, follow these steps (adjust paths as required): -1. Navigate to your build output directory with windows explorer, e.g. `C:\Users\example\src\build-chatterino-Desktop_Qt_5_15_2_MSVC2019_64bit-Release` +1. Navigate to your build output directory with Windows Explorer, e.g. `C:\Users\example\src\build-chatterino-Desktop_Qt_5_15_2_MSVC2019_64bit-Release` 2. Enter the `release` directory 3. Delete all files except the `chatterino.exe` file. You should be left with a directory only containing `chatterino.exe`. -4. Open a `cmd` window and execute: +4. Open a command prompt and execute: cd C:\Users\example\src\build-chatterino-Desktop_Qt_5_15_2_MSVC2019_64bit-Release\release C:\Qt\5.15.2\msvc2019_64\bin\windeployqt.exe chatterino.exe @@ -124,9 +124,9 @@ To produce all supplement files for a standalone build, follow these steps (adju You can now create a zip archive of all the contents in `releases` and distribute the program as is, without requiring any development tools to be present on the target system. (However, the vcredist package must be present, as usual - see the [README](README.md)). -## Building with CMake +## Using CMake -Open up your terminal with the Visual Studio environment variables, then: +Open up your terminal with the Visual Studio environment variables, then enter the following commands: 1. `mkdir build` 2. `cd build` diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8bd69a762..7135e908b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ # Chatterino code guidelines -This is a set of guidelines for contributing to Chatterino. The goal is to teach programmers without C++ background (java/python/etc.), people who haven't used Qt or otherwise have different experience the idioms of the codebase. Thus we will focus on those which are different from those other environments. There are extra guidelines available [here](https://hackmd.io/@fourtf/chatterino-pendantic-guidelines) but they are considered as extras and not as important. +This is a set of guidelines for contributing to Chatterino. The goal is to teach programmers without a C++ background (java/python/etc.), people who haven't used Qt, or otherwise have different experience, the idioms of the codebase. Thus we will focus on those which are different from those other environments. There are extra guidelines available [here](https://hackmd.io/@fourtf/chatterino-pendantic-guidelines) but they are considered as extras and not as important. # Tooling @@ -70,7 +70,7 @@ void myFunc() { ## Passing parameters -The way a parameter is passed signals how it is going to be used inside of the function. C++ doesn't have multiple return values so there is "out parameters" (reference to a variable that is going to be assigned inside of the function) to simulate multiple return values. +The way a parameter is passed, signals how it is going to be used inside of the function. C++ doesn't have multiple return values, so there are "out parameters" (reference to a variable that is going to be assigned inside of the function) to simulate multiple return values. **Cheap to copy types** like int/enum/etc. can be passed in per value since copying them is fast. @@ -122,11 +122,11 @@ void main() { } ``` -Generally the lowest level of requirement should be used e.g. passing `Channel&` instead of `std::shared_ptr&` (aka `ChannelPtr`) if possible. +Generally the lowest level of requirement should be used, e.g. passing `Channel&` instead of `std::shared_ptr&` (aka `ChannelPtr`) if possible. ## Members -All functions names are in `camelCase`. _Private_ member variables are in `camelCase_` (note the underscore at the end). We don't use the `get` prefix for getters. We mark functions as `const` [if applicable](https://stackoverflow.com/questions/751681/meaning-of-const-last-in-a-function-declaration-of-a-class). +All function names are in `camelCase`. _Private_ member variables are in `camelCase_` (note the underscore at the end). We don't use the `get` prefix for getters. We mark functions as `const` [if applicable](https://stackoverflow.com/questions/751681/meaning-of-const-last-in-a-function-declaration-of-a-class). ```cpp class NamedObject @@ -212,6 +212,6 @@ Keep the element on the stack if possible. If you need a pointer or have complex #### QObject classes -- Use the [object tree](https://doc.qt.io/qt-5/objecttrees.html#) to manage lifetime where possible. Objects are destroyed when their parent object is destroyed. +- Use the [object tree](https://doc.qt.io/qt-5/objecttrees.html#) to manage lifetimes where possible. Objects are destroyed when their parent object is destroyed. - If you have to explicitly delete an object use `variable->deleteLater()` instead of `delete variable`. This ensures that it will be deleted on the correct thread. -- If an object doesn't have a parent consider using `std::unique_ptr` with `DeleteLater` from "src/common/Common.hpp". This will call `deleteLater()` on the pointer once it goes out of scope or the object is destroyed. +- If an object doesn't have a parent, consider using `std::unique_ptr` with `DeleteLater` from "src/common/Common.hpp". This will call `deleteLater()` on the pointer once it goes out of scope, or the object is destroyed. From 0f0b0c03b8da14da11a8d99fad7ed87429f2b052 Mon Sep 17 00:00:00 2001 From: xHeaveny <69117321+xHeaveny@users.noreply.github.com> Date: Sat, 31 Jul 2021 14:47:56 +0200 Subject: [PATCH 2/4] Adding xHeaveny to Contributor List (#3072) --- resources/avatars/xheaveny.png | Bin 0 -> 31318 bytes resources/contributors.txt | 1 + resources/resources_autogenerated.qrc | 3 ++- src/autogenerated/ResourcesAutogen.cpp | 3 ++- src/autogenerated/ResourcesAutogen.hpp | 3 ++- 5 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 resources/avatars/xheaveny.png diff --git a/resources/avatars/xheaveny.png b/resources/avatars/xheaveny.png new file mode 100644 index 0000000000000000000000000000000000000000..0977b6402644c8a5dc238f978c2e15a8e8204d95 GIT binary patch literal 31318 zcmV({K+?a7P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>DdFx3;K~#8N&HV@1 zEy;Nv23A$)?vu~?bGkXqy_53{27?TcV1PhSjF4nWYsvDOS~UlZc}meAqMMs1UglOnjoScaVyvkhT#j`PIW6Q{>fjG2tNbco6r zn!)iEr%Rc#8M7HT4J(k+;<8YN$GBy1CbN-JA>;TJ)fk4siXvh-J8D!8H+-~Hs)Ea0 zShg^Of|_lpVviR%t6_RgW!ZAvmc^KJp9@Fj9mR&6*M!-ShQ~{FoQP^0@5-ddR7Y@h z)@6n%j0NtxMRZ_@OlCb!B5;}A5amV4h363)wK?mmB2;pW?%WoE7IZ@hOUhJCB!+i- z;XfpT?*;lrn*@iT1czK8VnYarWDS`?u!_H13`Np|^l>14&^2KP$j)FKRpBH!d{Ssv z(jRK&LP=986Xrm6fK~}d7y*M6P#2v8|8)J-GE0AjIY4}Z2@iXaNl*)+fE2Z%9-$jd zXTck_gbt;~(0O4*t~4CeuE{(VEK)_vgasWiAxxNAkuia$#fptMw-oo8;S0~BstO4q zh&*B0E>kcUNU0*MDQ;Os+-CVe6$7TmN+pVAyvSJw`4>FTMA4V|0e)f}_Vj%rkfGJd zuCk^+1{z=}CuOj&r-heJAaG_*j6;T^v#=oNCrH^>Ox zwQx$vo+POcqkX6ny)*iNUqzs}V_J@aOu4O4KLky+!FwPG-DqV)S5znI81<0-3gNN5 zKs%Yrp*#UuqoHJ&Py`HunWiaa0rivQsZPP|KuM3gfh=;Bb!67(0-g=MqD`nOg93y| z;W`{In40jp{@fk~{56yJ!W#*cp7>u+SxKg*Y)2CNK*9fh=$eOE6mk z-(Xp21E~Sl2cLkx0*IL@cy~|H{;*yX0)=Oz8Nf;Hc`!1Z+$LRn4aQ5%E3st6@*WUY z|0KD}fds5Tuc5!#Br`=-IKUT%%ks3ya)7Sz0@{XyCiVo4LU|~~NU<^ORQHPnhk7)A zCa?*n62{46$eKxLw+j?d$FXF=)MpMGG93r{;u42xDR5B~3AK#&!kG=r3DQ(@6Tp=N zpa6H+kzQnRP@Ccg>Zs>=sP&4L3LPyVD*>RD-%0UaroMH2}AC$9HH;Bx`p&w<0bHG-yMVld%jYezbYlp*ex@wC<9Ar&sR!+Sl z+>1z;6BL4jA~rB6$rOA;5h_G_zqb>88|)a zq|U?XG-{_x6CT7kS%mNgQY2Y4d<^e8Lfmc!Py*VbnuTG&{K+1fWgv(ZDfMYmTQNik zA;%_H1C*PB7il`iJJ0$mAH!o{C)$=NY;YJaCz?kV1ATK-f=YQ6bc?I!Qm$7edD5@g3(!9iI(A5bDf(Ev0aECU1nY!C*n$sW^a0FVLYbP3 zQ4M6~2;LsS7_4)uJlshWroGfn(!bi6*b81RMdL1bO*Plt}pG zNj&P^R7jFk1k=)a zE};gT1)>L*A}mK}3Rn=j0PaB+N5Bs?5HUq#VRwdQ`m_aXo%D(3L-r(G%XYE^O@~iG z%BY6~Nk>5wWWri`R5cob7yyoeaB4e_lOwdMG|NEpAZUW73G$Fo-mQuhgLhG;$YhYi z5mt~vSO!QWKp0h1FaSxnOjsW@4aFj7M0$wEQ*feIA{ap2!u0VwBt>|ofIJioI8ruz z24#dq&`1^_R+FTNS)x4<6daKp|{BHAR`yCh=7mc5895?kolr<1VtozNI}~m znIy?tQoMzr@gv@OwN?Rh1viBTp(N@(6;jp2T}U(BDkheQE^KA;A%Vl#l?1 zhqI7Usr_a^bPmpBm6hQNw?syhL$x@Itu;-Og}9fwC0$#xYc)yF^Y-?IY!owa_{ti?k0NrCXqTO7)sB ziU}VDPf1}F^hUr6PZxZ{zv05fUy0`Fvr zzzs^NINA(C<#E%6K7@=Yk~8$$)}s{UB3dr+^^_1!MgrJ~9BtyAWGlBx2N@_n6NrId z65POijZzIkg2%|KQIjLAKq1g{18n`XGYj~wbQJ^zOx#90{3y21$OA^!`1975>KPZ4XaCR+Q(hpn`(j-1k zOpy>k6MRbjHFL#YHZoy~%&=~#&IFN%kH32~GBT%%or^3bPXz+omH{iXY%o7TV?>3p zQLV2`djg|4-6Xt_gHlCQE42$;77#%j;V%FHAR#IaD2zK*AP9wS=!S+9V%;&cK~n>Y zU^oz5&LkZ(pdye2&RVb{gm3AAge{~>ns*?JLLW2u3I!4p9aK)uKo~HX zahAGDjt|S#k&u)O9;ruVz>|=AumY(S7%EyoM-jzDyRkodsLRAav=KpKBw0A2WkQ)q zOmr_usIVFm4dE|D2$fJQq5w;WqF3k}fTUn>M4%1e1sfr4&3llK6Y-~rhkb2kmv9yt zkA>ylCO-yxixkWxb)Z7Zu;}c1#74U*z2J&CDH=mv!EQLC244IHr*w&zsxd=O%K=|7 zL>z*?P@8EVI3gJaBk}OntC;)>N z91gHH;%a2Lwa4Mn=rj2#hX-gnND`!&MQTU&63H-}L6bHH!@&orRQCoEpPC6+*9st6 z(jT&L8moZSpc066f-Ph_z%odTx{WO)g-j4h$FDdJftU8zgO{evfrQwK|7Z)gAQ5$F z2SPT$j1GO0FpAEO7TKQZx{SOe6%+u_3Uo*3@Kh1bfcDdtNdQ#vdtM^frwET~0Y1px z28tn{A{R%ss8kC?TNw2Y=Yr6+i2%DuXEyK|XAl&kO_k+Eg0KvT%OOFq0+|lUMaVCK zIoPNS;3N$Y#jp>Erk#`FZc$bALNTp>Z6$DSGD15w#2vbDAatAt$uSWsqTXoY7&;)S63IZD z$YAlBw99t=0zx6Wi37-21*K#73K5{KBy0GiVbsV}RVG2J=^_CKr!?#;wS=ez2}l)? zKHLJvsDPnlf;9T=A({yyppvCAjou(nR!}57-2ulS6d^A}#D(b%WU{B7bz;RhHI0!> z8mr%R!3Sc5n)1?DeSWG0JA+%3hOp0Vi=u)qlR9Z5Di^-6TN*MGmiAfEQ4%5|28?tY zc1&`I1Tw%iG+NN0J4<9XB1j6FyB0hw@}{8)hJokdo0QqW08y8c%1g z;a3O>V9!~E%|J6*goF=pZJ-=ts|N~@No4s&4&H{mzksLMC8`Gsa2pCaFaik@u`HGm zzz2aBRiPOZp`%B1R{iyd3K<=A=n1<4xMK|6gxSJCpc2q_Vr4X@Kk4vkj zXp9h9k@lew>JP~Wvc`FF6zM>N6*(fE2#1i+DVL@(SK3~{13sp-ii8v_A0ubcAcdbP zqk)#7Olmzf9;cuV=r-Up6hPjjzd`|dQ6M%z?$|=_6w@^K2Z$LKQVq(eaY~AK5EW#H zBhf=dGa{XaOvk*?{U^s7kqz>I`xW7M;No=64#ou?pe#%cqCM802aP3%49G>Mi_YK9Pq@B`vUqafsGWWwb1dOPfA zav+Y%c|L$a$RgH*1n4hnM$0F^YYC875!XPrNCbogn4wDDB>YODMKIfh7lRlPUZdTV z%N;1$V{*s~7*R-;{6=oo zGIA^4+7zs)!x}Y4?=`NkN_1sHIODf-=xchbvDrQ6yOO3mrmO=OA?_&P__S z4B?$o5%DCI?5kp5CynGCx~hpQO_YfjHce8&cgy#6g4(rJlcuQP9sA=QFE}!?Q(Ny! zRcVRifGP+z5dj z#_MKJ4u>aU8)+0R6b4AjB+CO%;5eL)98~W)c_#r)MvkeE9N8|7=~5ge^9LJ78j{cQ zc&y?+mtEw3pu-v#ao~i*fpy)kOTW{JeyIHL7pNHu!zs~cyilm~G^Aq!;$aIgD6|#z zpfi@?)EKfs5HN5Xx?lpEf)HVSXsgT326F;H6Ei&xTsRah5y+LeT>_D&S}f1-s@yH% z5ZGcqZu6wah=Yb8d9XGuDct~sH!TVx^#Wd1gWTz2i&dh_DT1aofH)#8A}Xv~jwFWM zl+YZO1c3ld$OIu7&{gcfjeznz=w2fUXC94R(x^Lu1qp_%7Jtx;$t7+atEUQ(^+Cue z*v&RrF~elY1cC#=4x7OID6!Kg*0!%;UqnB2rF7g6l^^;};Q>42om8!9KH5~K1{gJ` zG=)r#;D~q>4Jo5d5WN77)7US>gm??xnJmLeJ!VaD7v^ayy9ACzjmN3*D`o7K;rYam zAYO`ua4%5kNM%E601O|Jg0nz*Ah=eAJ2jft04c+z>?ZT;ENC#h%uJuV0fljb0&v1H z4LfrX7)n{Rr(-+p2F)gt3qfNOg&EQcND54buB9tM=1*C=(y&4N!sh5B2@$HAP$}pJ zvO%oP=vo_PKL&tEP#VbY(_)0XA-6`R3OWd{8WWR6a3-0;g(pclUMNro&WH#O(L&o3 zP{MBbKsKVsQyYx?0%?)5sg;grIn^`{c`@RMT7X5+8|?4ZxLYH4M36;ISxT90(ic`) zITf@I{$Y3(mW{bl34A;aV}-jWN)mPQHm z7nvhW6%xij5|at03quqpFN%~%2SD6N<9xKmRZk)KlUY$_tC$Bm#1X3~fzN4hLc2Ki z5fWz=`bvx$KVb_jgFK9zC1MK70;Q2`GAgb|DM&{wY2AdGKsb7k3upmEHeJI;rc*-1Ko5&7q0uYwkf17UpWB}4%?KCyfon|p zs&NuTRZaEKJ>@R=o0-epavjqF&Ol8T%#S&)3dam766N;#s;W$73_(YzmxN5I zM$VApjFH5~&@#!9Bm~zaloLQOcmUc#Y#mJGhow(N1G+`o09dB(Ic=nP3n`Ir!qI6w z5q3r~13ds{0i!_YXe5pJC|s~WQpT$^7>gtm=a3^M`-~%{hArSQ*b+dnPBW9>C8(W} zBakYb20Nf-I2qA90VZcONJ%gVw3Cn&h66jZO<*)3KP(-T7tFn61Wo4P5E^DcqlE1M zRnP+(BZBZK){(K`B>~fukrpFhP7RR4y}Io+9j|5BW!noVT{4jh8KAQ!m^9dq=?KS{ z1}LBgXhad3GL-9!Rw>I8qzJld#WN%g;7gKZ2r^B$L1NWiOR)uNL}zGRh!jB9Hj%O} z)LtT#1O_yYOCmc;cIw>Rg3Jp9#9|(gu4~;;gO$aZrZckV(?zRlSrV2yQ{LTqL;a5k& z6XAn2T;myFEC`HFNs$5KEIFD@0}Q64hd|J1Y|V6*2GN&A05dOhyXsKbEIED^s#(q`pZdWUM&&5NC7R-Xn!XT$!XTB!tYA#;kB=2*22{NE2d5s1!}n#$p(0 zk#+QyDUgjR7%6u^<{~+~#Z;H$WMmg5;Vr`Inb+VDACw1LiTDO6%prYA;~z+a0ZLR+ zQDox+$uM@aD#8dX6JdaRL8(%io@%+Jxe_ZZhb2MDTWFf64zsC7Q6Y9BlT^hK?+%Ui zjnR$u@r{jeb+wa(Q7Q*$F2ZgRsXQJE*~?)cndB*40jQF2%cHR=Bmrqpk3~`%q)i!Z zgiSzM2M`=gRg0d8C(%L*%lHVDY6Va>3JpQrNKnvm6o4&)f#yHllr;7Ly+)+Vi3(9b zL!b-Jk1!VKm_zYLZ-qXwD;UU}6lDe4A~Kbv+_uP2plL)1=#%voG8b~X5<|W!%G^O_ zFJ-i&@~$3sN0wXR{sN4bISs>a6~Yp>U8Iw#SBRYs`cHGs42LKbsEY~7WTxTTUd3^P zT%`c{TCJrD%ZRRVYp-?UW7V2<_NY6*XqE!*S$rDkB~``cB}+97gb3hxtcPLdIa?$b!7W4b;?h7TH$6~hg>x+^2JK>}M;3iu{IQw#|e zNvw#Ausoaq;)W1mjIgi_fgLP{CR1S>ZGmdQqyhBUj&4CFCj5ftCBj{ZZN59E@U8+* z(nT1;u7)xi;36 zwCR!=;aJIVrdg$q$f=yBkJwQOjBnR-(JX-pU0zJ9tI`ZO~tmfJMkYFZSI`9?;X7I)bQ2|^LIS@{$Kg;x7Sjc zrH5ynI}TMmn+0A`4n(cYXX@6Bi{PO0gjId9-y47D&HZ2ho%L6*>_#zSJIH#$;+_gS z84~GK&u-6^L_ng{1UR12bxowz8T8Qw-~fwM0kZ=Z!K~o~1PFSXAml(}J33(|xj?j( zB2Z?kzv_3bKMJu3TKYo<2b|I_gWZ7`bf*JwnZ8PzVnqQRbSg)D1{1dp&y`6`3>Rl3 zLxBB&p#tnu8qoyS!|BifIE_;=N;8GiFuf_mq@*ACV|gCpryn$PY0;Du?zt{}cE|^N z{r#Jx-uXO=61uYM@eC{(b-RucI4#q6dZUXkguU%>bFEY{@A>3MD<)rk<9$Q$G?^XyJft?$a-$V?DrOz8xMVJSxzRogwgQu*Zj7f&B+p{%2VM5$iAiO{(IWXNY zJsKdRNlpMCL|5ViRH@GRxeZ3>O1mzqi{R{*UoE(0Ii79T92=x7kj%Eqpr2uH^=&I| zgVMzCbfNt6d|_BQf}|iz<8UlCG?KUXzxVlQe+?R0y#KLJ|JVQc=mYP2>L2|b=9p(b z^b;Ta^S@-8={NuJ-?{O^7Z&HOpZLWOpb>lR{H=4*+ZVgNgfFxH)t(+1W`(*kpU6`cn z92#UGN4%3jiEGjaeAU};zhfIVYKc>UoF+SvCg1@rL1fm|1E(;2pp2FyF&40|R3!k- z!~ktawhU5eIS5Ha10>Q4I#5hNoCf4kB`6oDcNt_{IThhgnWehr)WKhUuO@(HhMNP3 zT+p7XLAoWXDBo5-_jRX2XIeHwX8($ycS*gx^T?u(YwYwYjgKKF?-LG z&wTEG*t&25N#>fiF_=HtG7(4#3d2g7h}x43aDe`i%j zG28DO0P?bLT42r$e84z7UH;5R7LLyQ`~9drwu=HZjYjU6Nz54DU=z$NFk3KN}$WK;h zmiFIxDwsQ6on3h4*Zv_SF?H|52ba%pz5dGjJ8vpkocPEuo&NBT8!{V?hovfLVqC4- zS(FWWcKcx18&x)T#5hiAW~pm<4y8|o*__{Tr1G&xXQD#g*c*pA%*O*n(-Z*gK=4D; zc+u%R9NQ-N>SR70&C1at)KZ+toumpIMp8m5xefPJ5GM$=e(<6+LhnsT$EG1mJ(Qs@ z>H;h&rX$Ee&}7jHyv)&q!&zD+F-_c{m|<|sRWz_}AdbPZ6%Hh)u?(le{Dx6pb{mJ7 z4T=dT^O)&6o)7mAfNkUb-p={<&P_GgmHh+a9)|0bYTN+)Sj??JuX#9BS4u%M77FaDnk;-32e%=7;X9J@LTOJGb(F ztY9txNtzSyI8r%=?ZFffi?eu4W8DY|1VISl$aSFxLK0m_A5Z{!1qmP9wFeL~OuXb> z@R{sSR}A56tg3$?YNC+n8UT0X9k6IUOBsB{_G!=<&Y@^(8%-OA#|W3qpRQ-29;F0&s zzSBB{Q=-X0A(jsF(Lp*M{m$09s?Ve`|a0Xvu)?raY(zAcS#?%|JL z_|0GKtzJ}>N*=~rZ$Eu&eTSEh-T&asUH48OIa)fjT=9LUvp4+Cch|4nic@Ko8U~tA zL_&|g13(w*){noh)(yq29S9qE9s)*)=;UC7#88Pu<}{85u~0mq3l;jaHhJv_5Tr$k z0rn*O#edKZ01OOWL(oL@RA|VOMzJ}cjSW`x2K4>mD!IUY=j&HOYe#vILYp?IFuI_EzGO)AE zRd*X=Hh@U|4m0wpJ08xRSy7o%$ZA79U4X8Ip~Y6dbGg5MF^UP-x#ja<)}1}h{n@y? zeelfh7wNEe_K6}MhP$gUlG>qTvyc5)@7g&T9+d9>=#6!e#p254%~rj9^k{i`!F>Jv z_RUS!>ARM1+rAuRIY?$wpa;MKIH>iZ`y17UeE!v4Zr9TyG;JFSuq`vsQbsrR!3v3> z(F7{8Wzq!AeFApgMit16v_>dRJ75!yw$Nk_D)e3dgY;qY1!Ca|JzE%g1R^RB2KWQV zL5izy5>gq$0GFAHJ4nI6*?=~jW+4EzfWwFodJ+dvoCZ2=?lzq|z-PJET&R|(O0F^6 zvcvAq>cuw(yW7=@Io`RP4z9}azTwwZP85CW@RMiX_pv8FboaIOQMh$YW)Y3)$NLhD zWcoW`UlD+F@r8W21C)@A5ScLuH$cf?V)#2sWiZp?P zp8eF%UVQf3m!JRk`B%P^d7fWe0vkPh=NxKIQ@1-9P0i8-$h=TPWD)pe8N@l6y6Z^w z-aAXLyuBZ16^PN`b_NOL8PAaS!Vo892Xq5418_&AfYnb%r?DMYKk*EB1Kxl!@D)8f z4=6(~Y{$OP7&Jt~MThj5vuy|)CJ$z*Y1SmlQ-Ia?Oofz{(AD+?uA`8tAw)xibomLi z42eM%y)sK4bL&=R(JfEa8})J^=VpaU@^i1e$+EG`yZy}@YP3s}#lW)sz^ooVdDnw~ z{x3ebwBml@Tid-(2&*rbs=UbJAy8nfa+qmQ2reA}pI?MSnw3T4pGFQl;Q>Ood-AOC zX43Twd72#h$WJy-JL7y!YMzWw7yr?5uXLzjNxbNBwH;vYEp+ChUGf^JlYO5B?8tITP-r8x`C-*=84Es}Bf`DdO@4=%~h zmHc4e$UAv5fbw{$hIGrU)pN7n-rc==U3EsX$icPUFloob9wNNq)tsP~b6YCJKOiqr z5Rqq~B{Xpn$$3#I56Rt1nuXG|i=FG83$J!By^7A)?tToZ%)uL9H%n7f_kO}~{cvaF z#_P}SUw!Sq_um=i*3}!MaYna%$-;!t+C7B20u*T+au=Xr^1>9SrmQFKZhqs{{ayrQ z%Clr_gO$P$;1nv6G*1bFf_zBU+V~-3D)1y?i~0&MO;7_8LGTosZ|_;4s{(d}U!iW} zG|gNrLav5-QYxSy6_LhBXOlnVD{u(72#qc=t3)I1GN$XFW(By<9nYxDSl&!fUhtes zy<*>YKN1J`h3{SHZd_*3Sf(SHkEL*oN|P?t$p~&M?Mjs8oo+N1esX}b=awwS-QAMw z6?R1$zUx(C2%r@*OL(bixHM=8J2c!X@)LuXExT@6(hO$o>VgTTgbdEC1k0!ENAEg# z{plhaEq(mwPJHH2=?!Qy4EPG%6>doDa>v=?z736q_s~)sQ_oA?r=Lro0 zTMisg*lr=bG!Bb=lyqGwzNf)*Tcj-}J!aC39T?J_>Soq-LKw9K3wF*Y0Jow=7G5+X!|F zAAqGK2yhUHauOLJ*xNpVpC}9y!_r^KfT zvdZ&TP^*?(33EhHcBbYCmT!DZjxX|bUlvv6&(p2Y8M6#Ck5Mg4_cz37Z`AI)wV6x5 z`?>Mf^@US+Km70iS2tdLZtLwAk3aUo*69a~QP<>SWwwM>j1ueCW^Ze^CoH$@i@6zQ z+bqmf)f0!C&I5N&edD$EAOs5n4^O#B^DqK8A(IC}l0YFYx;DU(PLY9=4#?6;_8Lye zh_L~j9SVdukPFa|B=c2Qbf$N7Xsr<1ACV4QunAV-AnoG3s*Do1eI!;iTi+=m zZ=g$nFlMLfRP599?qB}pW;C|mdTZ~}t6!I+Jr#EmROwDox(NpzNc2@=PuZ5rJ-4zT z>a!M74WypP05_k@!)xTkY1_3c$L|7^mp~DN+El$hHv)JEE!!$prP;sorK10`BD+C1 zT2}Q4Sa}*1$>1O!4@}bwW{!t@m(c#f`bPiOO;sch|I%NYIdjLQul{y>t7yT`+}A2x|UsW zts*&KW@wtB&xY*_zgFyigJ!N#3(?%vueL0E+5lY$NBN)|jfUm9Q;R?S_m2O}-=~{+ zRb)2~`^%3P%P)1l z_j-P93(}FWFJvk||G~w-{)=;1GjnRxhy~vA)0I9D4PNtJW0ce#bKjZ@J@kRh9USQ}P1B^Y6`cGk@i?3(E_Ywf*9&-&{TS!c&%0l%`L_2OXyRGU=;yKna~wHS8)#0s@b4 zf!!s~5cS4Xdv~?$n(@|KGT);n&@1h1ywhKMCE0wff9<>d>)%Y)o{d+(Gq~||+I>fl z2BSxC9E1BU|Io*?aG0e%n&^gu={Gjt_$Js}ZRuo~$^G5o*3P(E_h)BB!-gzr z?(aP(T9?<>-(Ce-rvTtP9=sE&B+C#CCbkRF;UBqzpqt1jpc3@c{3yW5MD!$gV3GC} z{AMgGiU9}!TKZJz2T~vi4+9pJxCoTxG5|$s4oqKINQ3d!<+h8sXgE#Nss7kUWo@=M%riqaBuE5}YP#KZkGm2sS8 zdvD9Ut=m9_AS(}xv@O#el^xL1GHFNUT|ERpX)T(ngwwKTAIs7RKB3})0H03fV3fMv ztSqeIXjnV)pf@$EQr^A%^wt~Cfj}n1y(fP0vmg2o|MTa5^?$ti!ZUG}xwZOWZ*}+F z_pGVoc5OkL*1<5gWL9Za7MsGSd*+xe%=^#G|G~4@yL|vpo+lwO83_&v;zQ&>%NBk~ zKCdqu=oV^0PYj=8gnqy67|@f<`-ES5U)og%TRl4M3$up4ai=AG$h`@s4{lC($I%t` z7Pl)Ld5}M2mu6;~!OwmQNWz?I{_L~+JL}i^;O2Ps?eVSG6%R!)%Xzclkt%uyWp*|* z8&U+VnIopz+}%#s*47Qvy7#_&g^o_&F9eFZPjGYmA=K0_-O<~7P?L+ywLu!0Q=0dh z$Ah_3g;BPQS~yHxOWk#5#*pLfwQDt61qL?Dd`teq-~I<5|7(9kMx$%5yh!(rSmsCm z>Rty4$r6Nij)!+mEfy}TZ8j3wP)L1$8jrh;Gj>^%<6ghJ|5W|oJ{ zT;ZK=w6}?))AdV>z=IB;K_+VFZFYkSsO7hTNWZXOg+5W7z}^$-dwTX2-GvM5Vy3Me zLTyH?OnFH09S_@W!}F0h8Nzcs@6UW<;qJrDC^ybu9sR~{d}qAziX2{|aVwgoDT=sH z^K`P2KqdaHyKt91b8O|<9rgJmnG$nzbHga9O-+?c-p;vaVC<8&>Vo#baF7h(9VYVq z7imRX7G9td! zEPSQu#H4RQ6Ks+70Q)!+Hht?FGC(9y1xpoAM6N{P3a50(iJ1?)Z!V1G`cC{m{ZB9S zZ@yl1FDn@-)>jJ9-(^`(f{EI5qItG@=#kpO-KXw<^!R;eP1kBoH~Yh07KXh}>_8GW zQ0s>qss&Ab(B1e!(fgpUU{^v~wmm;@oISO?v~)B{3t`w^DL8uS#IfUtYqhDj-)vvG zusz-%9&C@1Y8|`x?#k?u?m!&0d79dyNapVQ@Gt+9-&lO)qu0LsU7p8C!Z$WL-~QEq zc=5~sc<1%cM}z&e$Sw_vfuwm2uvo`6|LV`4s@K3EkS%(Mh{CEA5+G#~i_ug3NQOjv zCW8>#dhio6HgtqA<_85HP@`^A(UF>F(>ZV@gc6!30tQ6!oYVvUBTTEpGp{NBs&oZEQo+|A|Xh26_<^)@bT-&_l-t;*rk@o+eI|D*jI zZ|`0>$4$9&`P>U%`24~4_MMMCnpkxCc)gQXUDK~SZ=N5oZ4AJC=~hTem=FwLFu;<8 z8inADEi^0&TbUS@{;y*InU4OBucQF{0cF)`8@?idKyOeKNglBU9Ea}X<+d_ByWEr( zGwB+n=LR+Il^?#lcIP2~dD^>hJ%9eiTf?>2)nHf88bbbUG37JWDKeU;r3%-qE}4}j z%WE}i-jO9YE%>dqb{OWspJOMN4zG9@pZ#()+NLJ{u?u{)$hokl?|ASbIEpZhahMPK z14EAHXJ^Au^}5MHr(N;gyG}0-4#uxO{n8uHzr23wdUw0m52JgZ_{8;>o<6wr!v5tq z2bp4ZeBPioZ5-|??c*p{`&q@!_N&KWu@2N+)L6i z#o7X3oAa#TMIkt?$DtE0WC=idwDAWDn3RbYP(b#z2i*P)8fsy0N(3n2z*8vffQDL5 zkV8L~O{p6)0Oh;hlvk?PYsOE0YWqWnLfr&( zsN7q)3-wg%<+<5fyDiRN-5!MLI1H<$dZT7LEP3nOU&zvqMxH-zL8CcK!pJ=S;1k10 z^hY$4soU^zgmx3I1YzHWwn0@E&|)f{_g+l{!jhltyf=)I(w4YcRc>Sr+)LPM;|^}E<2!p z{c*awW9{zks@&8|2NZy7y0uhhrb)wa;Fj<5g+HVKO3&T}A^Zjf)FEX(@z#XA4HF(f z*%=O|kyZGTVHPT-nxv9YF-;iwZHzvIyH^wWua`>x+}!+g-+X%5-f+RG;2eT~_{o!tN1B&j`gYC+ z-*4F;v!GjaNYUHB`fSBi$LGv@PRXD8se2yy*e4(R*a!CZv$x*pm4m9FiHM<;W2Jx+ zisz{uj(C{n``zxXoqUik&n_Z$%Jw%|KCU0VXX&1Yv%%=~U;qE6aj(>xz4OOE-P`Q& zG+(`X{@PY{eXkIfdh*fo2OnK9Eyu7bw6+4b^{suh!a|Xu*Y83NiT?X)zz1mM2L&F` zq8;HSv=0t5NI`mK69i%Oj3mTMG^H6%0OI0S3*nk>7kM7c&bieE8jqJoqftKh>T|2l z{|=J}?@jzvCf&@&<8b+&hwr+pQFh&uYj%3h!g8rIilxe~z4q07|B^CXrSFFY7f=R- zlJW5Yi~I4Q*Xi{VZXlPg9Dko%J9_6&{ZxH=>GjY5i>u%LlI1Tv_UHb_$@jhg)vx~k z`a7>LoW1|}Cq8A%^qDVw)ibKc?kIih+5Idm=tk>2q9IZ;(}bqf5qn0{CitWMbn@X3 z7YLWqHmw%AK@Rd#e9Yhq#So;z2EFAb*p6@lVFw_l2n8S%hG2J|sX(r7r7^d1?A41j ztE>n^#D1K}b;~^4l{}GoNY^#ZhE+O7_?UL{VW&t#SWURSHR@~)!u_?K-Oc@I@6s!* zSpUA4zL!Gx7{Ceg@ZiQf7jLc`+XL3_7oAS=&ZWWTjqRH+ey!MiLB#7aI$)z+n${4F zf&Y9oph>RbUNP9r!<~bhYulGDZ?CO8haL^n#jEFUUi#+miX!u>rF%d6kX7WDo_m^G z#^Q;4$HVbI``iEJKmB|E&%gPX|I+TwwIhoGUGoL(J2oh)Rc;_DBjN~6gU92;B%0zy zFoSa2#%L450bq-6_$Jna?$d=z2IfNv8>m%gId*_#ywOB%2i7QTM;3-~tY$Shd8~yR zN5i5&($QNL#K{myXwr*Oq`h)^f$l(8hyfM4b_8%&G0VDi16s6Ib&Go0_uNWts?}-t z_t!6gw*JvZ@_$%3C@%oA==H*@x5ihlrLVr-zqvKMc4eo1^Nr#4uc&lDOC2RQRJ5nk zA*_{dwWNDSkcnDmc|jSK;ogQ`{>t`ERxMXI*9O8r3gtfd>CZ0APCMnCCAnLlk)_hV z`kVhLq8)Ou<&#HG9i4sO1BYzS=SZ_@PBqKJ5Z#v`-OACcd7)1e9Z*B*!(@n4>jAL< zKY(h&Um$((R{aZs5e|eL%{UB`a4_iZ=gA0xK}w`xc$W(^)^yWCo?EMfYThadFob}I00p|R;g(qNLFC^1nK ziiBfBvJz;WhIuk9GC(=d$Y#JF<{UdRok#H?%%WJen!=D~Hn^H*xm7x07_*$0Ij@6T z6*QY*c@k?sRD3 z8B3_{{$?@SwS)*7b2^N{7)wm}w31iU<>LVt6|+1=gDzPp(k>8*r`gHF&C`dyOGc;cM}RF{f&)i*ni{P_05AUDbmHIMdeSA^C`D}#&B04 zaaN=v0;xwPQ{#i`dG9iK70#c2p=%%stKownmWqf zwrnH;lMml7*gz2j`xP?QAz`vBARn-f{asp=gr-fvavT8!Da2B%UN)U8+u6=O`k(d2 ztUFe<*)xshQ^HA1x2k+kkPrWRN}*aGFW@#JKyr_%VuLaXEDsA z0QwHMl`41uaR7S>P!FK-x_q*cslyI z|KvaZYyaKfZ?$Ig!r+-Yy;QagV1hhzVve%@B4ZXjOb@0}ETvoO^sScY6UA4&BuzJ& zj8EJy2naO@ThIt9a8btx(i;9Dc*3EO9MD`SuJ1axf;zL^2Od~HvOIHRZK#SE{oUT< z-Guv7t=${fy8AmyxWcQ+Q5)wr>^bB`S+Y%mf>pUWC)2UNaDVOSnc?1cI_iTt$9h5F zXyer)-q1~Y&nkGgKmub`)a}MGGk+7;ox zig#7i0Vz7x#T8CflxB(qp(3p>+;Q~unfY4fj??yZ%PR%^&ND}7dZ@Jj!r%M5kN)__ z^OP^tDeIpJgb&!a?3bH<{cQ8_o!!-^Sus{@WLVSHBX{%C@}ocf$#GnnnpuekePvjYEF9NJ)?Y3X zC;+Gb6Dt76Ci!?14qdAq|M*AeKK9{-PSP5*!`|+?s8?CP&+HnankrHicUd};=_XkQ zg&$8yVU=2m@*jEPo@0yd(o$}55%|J&tb3n)@Wc}zzx%G`QKSZYgZYLBt3KHhyIp=T z&Ktf_D_h@uW_4>nk!fG0iK4~qXeO1u_Y2`ybDVb-@WbYhaCIA-^gPpC@$~ivVyu}S z*T!ccgPy`=(akfZYW2j?>G@gno;xayn&kw1oP?Im-+t>tXnLYG8%!;hYqg@fTsm_9 zq0{qBKSab34ar4!b3JGrPJ}r-)7aX%HjMXk7y!5H0kY;XqUfJO`Y7;ZQ>7cxmEY`M z{nCrC96bMKoJ9xGa1U(!?)x6S^T!@FEbIle30WM{jl^c4oEEKwN_QYBr+)I@kNv#s z8YfTiMj5@OtNe(Mc416ath&Q$g00L}585oSXzYI+s;n?W$vj6aEI5)QX+<2RX{N{+ zAY5t`?MU*Y&;PqZ*U|KEAS`<9fu3c8Kkxurj{vB}Xnim}R-si$7l65PJhd>#X?a(; zPmKq@KOE*>Wq$7XlY2Yc$laV$>+sS0<_<5dUf&SzEF4IHZXzNGF825xTZjaYBtndjaNM8Si&|` zwNf-3k*3Tq<%pS^`x2q}CbIl2+4%v?|1+A4ZsJ{t2%y*BI)j~`!1 zGqY0RuEkr^b~?`XF1?8U6j{iMju9+4!Y?{E4sN}`!vp45t@_H*qxY=eI6q#0o|eWY z@BD#>zUM*{q^QVz+`Dy)mk%4&BlAm#nzM6nUEbImwPI(51vBY*M~1sZy37{c){uje z@}SbZ`-uk|^D_{FYo@bvR&S{K2g(bKER_~4JK? z2ZmSYrhEL@p?l9Z8n!w-YowXl*k+fmkK@SnO>yc-xmD+2O07!1y>pNah8Mp5jhSO- zqFz^`O`-S37bHFcqp6fW9b)$6x%~O(lg)hM*m^xF-}KQ%&MQ zdq5&>&FNwOhysFc5uvZ|^3&Ue7BHC1Mxnct=dEsHfv z{LmrMsJS!KZjy%ci|XF{ooanF>W<5^3;TP!S?|^3XOEh^XUct!#3JjPAj`DWe@>5t z$)u5GG99HbAg_Yc|0(4U@#_xL#S2*M_S;|CdE-kD+*3mjUV8r3jq|UM*Uv}So?8Fz zua&0mXdbUG({Kn_xLou;Mi?#iug zB9WOalBno(fS9>0WZ7qxazOKsBrRsA(OS_xu#-knV}#?vtkFHPai9=Q+STP>^8o0^ zgbuI|t>`UE3QpiOK_2vE2;Xt5Pds+y@Uk;q5z{_jZReh68jf0Di)zghi1jPa?tbex zes%M;FF@sk^%u=z*xnn4=x<5oJ3(%#4fz*Pb;8`kd93Uhl0h?4mo%Qje# z<*+Y&brq>Nt@w~d0uT}pwFl_MHdUU}+#y}4kuVi<1pOmjx6(f#$)ce&_%A6<-vDgU zvIaMR52q&6Pi-)7q@&h|-ad>bOLEb6VWj25X=MYdnQb{h8HU|c(+BoOQcF^rAYXjy)(|p}x)36Q0o?^e zchS)E3?ONuIb{BmLVeUZFU?of!$z=p3cNJG4!n??WxQwxC*8B@D9e-xRyw85b2aG6 zi&sahUA{Mz?U6+N!Y&Rk<#y5T-g=hBS7<#)6-h3OxF7Wr-2&RRO&?d+`$d+kBz`pO9(v|(d6ZZ_v+y z^z0D8A%Tf-7T)(CH12pjbDE`@qi$u{aLe_obNoATUq^5(RhHvyq?ad5nKz}p85#hiiI)n&w8%!ZI4Pt) z9u&jPjc!(}*3O)4&Nl)Y-woOHl)7@Wvoz-hfz|D%WuHdt>85EWOLQkb`_eZzcXr1# z(G8ifL^7N})7XiY!6$l6@Q4E-cYR|M3XL~IQF78S`m5`p0IRb%Vob7r-{y#;s{g%}-D=avrB+_7*cH|OiK zD_L*r+)Llwz3`T322s>zVSD|;D{S00JvM)6xpDmcP^cE(kEBqXK_gT#j5nW)M%S&{ zqG%pw&BG#S*sVjNR2Aj2i7-&aYP4Q#Un+X9%l;K359i(bekY%w=CvxV;W$+@Y_o8E zSftwA9_rbYHWZ^mgi^?3?Gm~ zc2D;Q&{`4X6(nmMOB)Ni$wT?v_UU#a{eU~VLlJi3_zym~T=&d4F%7z>hsQDKn&|iK zt82#2rDuo0$aw$u3hl*j;=;RA$XAPY>3SD~NPl^fo0LEC;F>F_;=uRusZ1 zz5l0wKB%>prm`b*1|ZoI>cY+bZ-4R9`FEn{U%IxwnZ&8(msL0h#H(h_vMupDUtQna z++j&%gSF-y^RsC_%doL)5|BG?es)VpbS2A6l@}vgzSN$}kNN zC`6-vG`a-WLUyj82xA{wQ!55B6?>BRS2pbldEoU|jm&TtLatMI+gk zdzU@0n)51H3wU~-_IN>y*244YULYCExGlrg`poopC+0?R<0hM}vqmZ7w)pn`Ion&|t*$P~1+fjIcN z(7Wi7Qv9G-yL31$Ar~Nb7B;FdP$RQE(=7!--LcE@SX67gC=~MVeqW9HtX`2Hc&N58 zWh@*zRGK@5(7+sDvI>$mX3TfDuR3Pc@kV)XjpYTG+5GaN>6c9_NV@Ie?s^u7XkQx9 zIzn*S*|Sd~`y-zuv;EN&fViSnnxc69o5k)0VN2y%%CKQ@%5Ko@>5#ubGkP?Un}vS; zuVfvxA%%0TOzZ0y=m_6if~+r=DkMkm=PRq9{X7H>`&U&=FIZk{z0!&sZLGt zFj6nRa84OM^qP%&Jn8Ugm$xqnmK1p!#hpG?&O!2?u)LEQuOrn@)Ad`IhrO-w?&fg!X4cuecJbA> z-r7_mixXKZnS*gM4gu(%30^6|=!Id@Y7}~+NlX!!Xb#i?B&U#o-jR4|4^jYlXO$V# z!Yb2hU9^@POa=!dWyL!JGPx0&2_>$r6-dYF$)ZX3{=1uwZM=D|c=;W5`Rcf}a(L?S zQGfZ7nNyED^AE|&p_$_kt6;9$Y8fEjNlYRIDe3R#oi$qynb}vpRgn%1(@Vo$oD3{w zG~Czc0nm}9{HP0%|2mHnr*TTuXMu#=t1$~{4H%#RDq8is?fRkK#;ebN@pm`(a??qK zD=w_F7vJa(27OvuzKDzQZZY1-4mNEQU=v%kY@s?BWd+FyAt0nnyyz#T%%pts1AS4H zOiG#9M;krFNn7A19%E%%?+S`DeMaj&(C9zi39N}fH|aqY&;XPH^`=qCSyr#`xjGFE z3Z#d2`kn9YZ0#d1^_*(pOdp9vW8v-(-TTDdb907k23N0ds!SxYJlG9E|MTGv8(+`I zBfC5eGenZ6Du;Y`h84rQ?|tNh_n58^gS{=WA8~;^c8lJs;nzWgm^WwmAYF!KJB&M~ z3etpSq2YUrowXaX7`19nG*XqS_1&-EQlo9vTa&|mx)??)RFB8q{Ue9xAoZkRtGj8M zA=?f0(+ymirwXYrQ7{rR$Pi7kf=WmS@Pv;Q^< zlGE<|;<9H?n?|6ll0ARQn7;?vk1U2(Wn~tI^T|K!t~`9zEMKAYnqTM;BzM6MA@U;?M{Hx?5^87nB?V5Co_Z%(9j6X(ZeZ=*~an(30CQf4UTd z{Y=D6S}8=vS(fw$L&PfA3kuY0@q$%vZN#-&B}Qwdki93AXK6-d|f45@`$FhUU?5U&oK62yM{-rB7=3DN=_XNv_>(#kK!O92xL+>-} zDVDq3qZ^MCRl0g}D~>W-6hHQ7KU$ePNoMhHrKFZA{=#SGKk;Dg!|y*jJu}17G#|AE zq~cbYU$4)dE!FF@hvp7?@poTq4+oOx^3?HZvTcZ#2A$paz3)Shf8dFe$LhQ7v>UQ- ze0Oyho)SkiEu2OmD6Nn=%}If{C-0i*lUnf7k42&D1W*iE*Q|a3sKMljJIH7$QT8w+J&Hgd1&Rt`yr+peEQ1+UH;rKQ%~TrDWh9Idye z?fy=5<(=mVLw}@&+#Vh9%b)&pzbJ)080NRS?r0by1u=ppNw>S+ZHszqc4lFzzHx11 zc4=v0rkY8yKQQguoG@#qw2nM<$EQB?2-4+yPFk0*s$mjdyVYCW*iVPOBI>y+E#jd} zhBQUDh(JThvY~^?MPC~Jq(?LYRCFYehH&pSZJ4!zk(n__gF`5nGR^>@-&k1 zKqV1S*|0prHuBt?S!n9#dzu>?QFE%^-WylSUa4HR-NF*a!eYZQ>5)5?Dy!J;o%bAT zG^QVas5)I@v_d;~;T)?sx1^Z4^WhH}m8sIq8Rl4zJv9H}Cz`HH3nq3W|IKHgmw8u@ zCz*5u(2op}h#)SU`gmbAgOZaKrN;dH&Q^bV=}xcNoNYC?uD(^s(blzVS+tkrZ1M0C zGNQpqOfSryxevtp$o==9nyT_FPgmyrn_Ir~W_4^BY9KONqDxg3(9^Go2_KVRDYUFvuk&qaGGlQPm zi0JINrsdZwr9%tBC{%6QK!RdbT^56WI0%vH3ofA z3e?FNd!N?*xuppbt$gV zU?_P6r3v_J@Zb(gw74Z4deS%%*ziD&k(76N(T4|s`sl^{Ol2a>`<{;+(leEP_nB&U zz=E=QQFaG|=+;`V z8rapk<5k%gzI-7|vUJ>$agV2Cparc;O;60DTO2u{oEBJ>$fv+Z>HIWKgcpJ|rCA1Z zj?bSG}CB%}j*Vvg1_@J3!3fg}Uc#r9Vt<%kg~SyVa{V zJLQVAFyrQ-LNJi2T3HF2v&Pl8lQZ`Q>3~8d)mU>=?mQ#H{D zRM{g(E0@LHOI9gh_ne%5{k1E%u3x6s>sD*={Rj%;ZEg1C10VQMoT((^tC#oAKmTl= z9B{ivrz*NKY17(Oav+Oz?vDGG=IdUG`Hph1b+C8-?Mpc`Po1i`W#`;G>G`YeJQ=4+ zpCv;^t4h*?SdiS%Q%Gn4KZ7P<_ga!5U5-$2VzACe+bkbS zIn>ezRJpfT2SU?ubQ+)Kkd*hvvG$;j!K6V^NT#|-CVoy_WJf7yS_TK zYE$3+`nAqM4vKC&e*3`K++oO(NG4fEsS9X6AcPPLlrqGN7U6*VDx|tdhjDU~R6&<} zVN+R_#Yk|MR6atywUO!-0~{df>3PW3OnPFM;UgucSmAk+20bjxx2001UF{Fqk;C;o zMq(0=`(k?+M8R}DcQA^4*LG~PyKfGn;_y*xWzK_*&$LX_GN(Vn{ds;g!(#Ri)2LQ(a!fs{i{X~U1q@H!Rje0P^`!^y&fLI!ekju zL~L56kk$*M836Q@RzXWvf{zHrl5{W_r3dXSj{3{ zu56HOj@;y+OIPO>TQabeAF#R&LI=gtgYArzCSiMmSB07@nFcGyMKQ|QkghsRrgHo! zi|!gLRgA?&)~pvnVBENLJxdaqAr88E3QAF;6r_l`?McHiYe&Ym)9!3^wl|W(W={1N ze(v5+d~{`H$xSkr=%6k{fY;ZBum)WCfWv z=aps?r=i(>w^R8)eSrx=B1KU4d;R#8xA%LI91llXnhGDue=dBV2VjFWZp=!zA!?_B z)(W?q!|w2V-+Z<_Qx2+T*$J|&s8rNwly7ZqiaaW!5#?Vnd0x={4`x8~sp$65$z^~^ zfl~B*9|~sV8hDYBggffR7bO>QyQD@^3z$jP`T{*4707Bq3@!Vhc^Bd2cR)^hYqO zb?A{l^XbQGRl76Fy9a}`f0d zwc}Q^ICm+1`nkRB?M)RO6mj1~x*Q=0XGJ)m{7XODf?7uAj}%PO`nhx|73iBpB}XwNV$W*9}38pDXD=feNuB(3`S!>6p_2p(vR5T_8g3O*?E+)-s$ zq$y=DFoHN$vs0y0XO_So;3(8+Ws*O@ouLq*8{G{^p86gO%&^>AIBfXF^Dpd|Ot<0D z#R`^eB8MW_DK(W-w^}Edd(7~fmDwXUQp>rSlvlFY=ceJ;>%++Yy)VDIxw8XuPHvp1 z`MA%JuBLs%0&ODzc1(CVX z0kUAA_6GXQT&7W zY=z8%PeL5J@tz9y2d#IPkKgg)OZ~0gez%tndI=YEdidTD-mE`;ii=qbCyj5w?aQsj z$3J-Z>^-gJLkqTR<{+-Jc=5&cy?t7-2}c!4D8M@tO1|jfvqhrkebOWc1Ox5eR3?`s zwZ+h&(z~j`el*I>EP9?b1g)%cm4TqqlWs=zD0w)K5|Y~Zg8-(3+qN_DC2^S3Iakd zjj^PM8W&maJ4Ag4As-hK+mD?&QEe{J5EhLlQol;Im1^UxV#rP=*7TkVPF9#sGcBw} z%Rh6r(T&1xn!1g;3L56(DKULKb7s7y72(z7tv zd;T35PL@S7iA)vCWNauHKG}pSV#v7g>O2LwL~$9We9|@gyQf zmg$$3>CnmtQD2ch5txDg7A;K%R_fZcHWyv3^lUe<9h#I>Fr%|SUR>~NWv}e9X4Pue zph=!eK@T3Y450t9Iey0pvDags%SxsymCSy~{E~ryCnzsx8S>qP9_Lc>EP8laK}&d| ziHDm!X!$QZe{ucVIeZ1~2xgvn-^V}u*Z%ssmoLZB7AVbo)d3iV-#q!z&-_d{PA$(n zdZ>Q=dVAR2E&$Sv!$vS0RA%QEW6ofort_3t<c-_8 zufOmT!3_*Th~szP_n-f*pXr6pThG3%A2+Hy@*WBgrcV6C&;1yPm*-kLTajIEb;q{h zwxSf2ta;}2%9D>Aec)cJ-mB}wT)G%O}6g?E*r%Tc_RW?;=WEzH9s?yN3 z=aK}7H$!`cM5Gc%jtn&&Wl<+jdU+hh<8GXEcJ@avz0x)V8fYB%ia0d=3KYnqD4t%F zH#YOV0Zz>wn}c-HV7KJ1BRm6MqS8WbwrS`bpb2w12-zqk^WPuH%UiNN5Dq~QTC9Cp z2~e+oPc0r<#1ZfM^&h`L5a#01(@x-eC2w;ro?9@Nmc50A#Uwd!JW&d~TFG8mV#85> z>3nwduxl%0dC{JoDRq15`gW%mD#!KGag=96nf2r0E|X*MwaJwhn%)L1QplNbs@veB z3pqM|hiJ)?^o!mo>*5)+eY*1_Pl58L3Dz>sGUOD7N^^z}@fZmN6k(y(Jm-02i_DO* zXM@6yvUm*08;^&7@Xd|a-wqRm3d^ds)Ktl7R*MrSt-T%IKH#n|TV=FSj56d|@&E@V zc|eb|M%q{f6;YEUOzHGsYpW9fF(KV0DHg3Am}1Ef+h-7rhsM+#aX zAxn%RGA?UvtsS+2xj%CzaXoZU99NZFhc3sc+@GS2&Z-BGW* zX+TEFz?T^dhoC_8h_WQ487oMGDIKE$IBEuY?c|jBk5*A~gVRG@qzn2(CWTLs;h5z; zWYXwkfe0+Kc+dgl7YeM%qc|QxU5qBBz`KS68!m=4DbH{|v>*uw$i=ykH#XYOJh#cr zY`Tf?rlL3ntDT;fjNawc% z6e$T}B$9l}bLlbG#96-24iLCF7)e5GgJLpX=qX*F!3!eqvwV=JgCZO9A_s2~MXJJH zK0;0iR*Uq3>H;-F%%SIHuwpdWCu63C(h%io@GdQedDhRe{Oxo7uRq8O%m&8GbZ*Hc$JF4ALJ&;pZg>g`- z%u^D8t{DCucO7@QIq3O@?NBcEhYDiV|3Op$-`m?6udR+$Vl@5W!;d>l)5Ak6wf<=H z_1CY)qudswwT(fX*-^$<*M`0;N@YLF)U~S}dIWR^?h`_W;2L@~Emj)FT-6$j_X;!NMZs0K@Ol7?} zuO*u^1E_D<7C*G;KltPa1sRl;Y$N`$dL_(K@II0C#q!MTkBTs~cDIlS^XqGDZ4;&<7MFOvA==x@v_+*+ zrO?F??M4^hzPh@VtZm8D_uMb+7Ij3MJ9hZgU;OENpZpjZnsjLUA6b-Dsgx=%STRhV zXQH@vUGzqAy`qAOX}fZ<$&VebBSCK(%&V&}J$2!&bK6Or6j_wfV$mr9fXWaj$?TG` zLQDpICu|@dk2dN=jOZYQu8A^UC=mT5Vxc3{7o8;_wP(nm0^yW__B59zOK)pPUj(3h z7(6$}X(GC@3XBNBgd-*+q@)IvBr}jF7LRyJ`@le;iBY<}dC>m7Z-u}8C~LS`w3vE1*dtt}eysMmxkk(42 zU;y8V1#!G%Bep;X2vqP?!g-qbtzaAzm5>e)By1@SSnQ#oJU5Qi>@xW(< zY=oGCRzbjFNViaXHY)NABrK0c`LLG{yB14}Jc5C!Bw}fQtF!%`7e`_Z571dC|Z|daPEQ&9sDTs;MbK_ac;4CCGbw>srP*d4VPb zh}b@>)t&lWgS=GR6SPv9nMcM!3p4%yDZ)K{=iyeln5oNp3D_tCUxxh@9&vc3eCJ7b zafz0`LT>fXf9LwQzP$lc1l<6R7{W)|!Bv(I53+t2o;$e?!;t#YbF#r!&@>N-LeC%- zv|^2BJNT!Csf}8Xi2^y^bpqlHjxAh|8;;>uO|%};r%N=HdFp50PCnaASTu;Fa}FB8 zfdZf#h<0>PM2Jg0mbRn)TXML^!a*|X#!){V^|p6+KK}>jf8#5golyD~t#Kg{hD?E! z96B=T4u2COO>-U&)xs1zw8$1`%#zD$HC`>TxhYYt0AR)5?iP(Iax^>_W;WFzV!qoR z-hA_tPBCeCMH#gr@{Kax_E;l#)h0i54<|QiNd1Y2+9L6z7HiK|Zc9 zJdH&eM2D~RToRHU-BC7qgb5Wz4KZX^ARcg0am85((Kc(MEm(@M}^(-sQucN{lD{1&i~7= z?(Pg^tHKV|RlOoBo@#mQSW6sg@adKTu076qoO20Zv*?;7NHM5X0SrcfA>4#GRcEK0 z#N4Z>)yr?v(|u`}8XZaRym#Tw6TwgX_|ZEa__(l-XfFq3lQ?u&Cq;s)!EmN$Rp6_^ zkgeW|Ez=E3$}X{9lwZ9Szx?{f9&$y~$kJiCg!H{#r0sOPrH1RQw{Fl)-YG(>^ti#y#WH$mL@EL&q*p~S4&wc8lPyLGN99JY4oaYTN+@(%TH(QUB@hFeOosFwScSCkJRexKI zcU8QP*v4s5c{8W62Qq&l5LC%1@t;hDF4w`#Ve)VbvRcv#&G9kl&LzUb?;8a6r}30S zN+RA`bOVNK7vY$qxiDx-L=JW7Rp>H3O^EmpdW$aMg=29pAS^BH2lX0GK%+>uU(o8= zH0y}2E2IOSgQOntBF^$r#>~~#;+6Az!saKJO5k}eMRoX-Xz$bAiiQNU%52N94SD7I zcE2~~R!2W@RTIHCKO{)>O`nP2|s zFMsGS9PGR$(ImR5oM_vJKl2~`mH+EsL(c%qwoB3e_rG-Uxi5d?+RMM|*gP6-YJzCP zWd8iG{NH}@|NPk-+v&|Ue(7?5Z6_SX{y2=1Q9GvRdH3SZmK^V?utRelk~U3qL*i*5 zk%48=r4pJp$O8uYPE(yJ8G;N5o?)@HHU|&_Epk+rl9Hea{C5Ib33Ourr1SGUz0FTL@*zx}`dFaN(^yLkS^B<#lHy==UD_52&V zTi0ba1nbD+Fhvanm*n0sh!1}3$&H)a-}vH}6dTbg@LzKY#8vSdt^6X-YY3fUEE)rcL$Seg^nzkgzo11A&_ZQE0dP1)>!I01Bx&(Vdf=J`Q=(Op z-~rebwrMwXN+9 z1{kEuEjkYp4&uue>5aNd_bAY4F8oXtuf6!n>o2{UMq7k<)FvTCj`xH8)mOgt^zZ%4 z-}~}!{m$x@1CJiBV-zZzo$@v|ZrwWfJViYXn&sJt+~xbm1Mo=)Xp-jz;6BShu8@%6 zL`9L0Xi>RnsEV;c51a$&Bf~-q$<*|40>tfWzJp%VRT!B=H)OT?(xIkipsr{ZA}Hd! z>B$f&?FbbLqL*aFWVM7v>>TG!BU)_4? zpVH-g?UO%T$eM0{e6K}YCrQY4ylR$a61ftsm~oqo3TDh4|M-)?@VBJX8b^7jmqu|i z9wx|0hv6uqRqm5yu#xrGWw)(Vk7t6VL#0CW1oRV#oX2|RA-c)&75O)kB-kP}gzkep zpu6DZ$eck>;FrFD0)!#MeOMT58w?0Fk)zNdIFi+A90gT_^fK(-V3tqgN8sf2FaY$2 zI4?Inn6wUMbS9t-bW3W4)swUUujnCyk6t)jqCd7UOHx7q7PmaRG*!4w)2Y~Q0|zq0 z3`*YKTfd$5uLJP@-5aCMP0vHvt0CjD zOb1XygU$*ZFrXe;NK~uLtH3+S=V11*ZWBLYPkc+YG#z@}lv8H3ya}VHzJf^u{((O< zEf=AKE~F575d>UJfmKs9CY)gGFvSnZn;uBIBC`PYiy%y}LHE-@1v%h=`XF;!q96?! zjp3mo$fD?U#F}U-(g@H5?j#F9ZLZ8JcW0GZW)3uDT0zV38_IB$Q+K_JSFYDZcKIuR zU8Nfec@2TvkG{McIsW(B#TGcJRREo7Fjxw!Ieq2>d0uKZ7q(WfndOF2JvvU4OoB#7 zKss5(A|B_-h$nh!R@fpEl_HkOK8*^SfigkmU2d4@yD(@%Ehvmk$9fuB2Jj$R0Vf2_ z!r?T=46aDyLO_{A)FgUrTix_#WC|b2X(ohe%miM zXaZwpZj|YIWI-u|QZ!JE1_`@DkDDjZfYZ=@2S`IG0l|mKNE5&vF%!K3`{UrqFlTa6 zkVDGX;BJmjPd<+a6f6*POr-yHHn`Qh_&G&OJAr^rxa_}$Lc+cM@edWfopf^hSNwqu zpxHoC8odGHtGt_!wzGrFa0VM54T&$1G6@LCukwWW z4=P0@0AHdBcL*UdJ+D@QfZ`N5vre$+;mpK>>RkC`<`9SM>2ZHV6<_M0f?epvU~-lww(Eh#OSj>h+3?cu zp;vmwCpwQd{2>edccqX@ppS&)MKID+*&d?>|2B)^Ej3t^<6SaGvxM+T@_}$+g)n)L zZy#R(Eg)L3760K_80M$%7L-S8sMhqviVp%ogdDf&PldJ;Icnq|W;n}ci7=F?;j zRJ0M^w#0u23pu&QSo907kA{-93o_)9l3=n!+67Qd`_hfo`X=FmQe`ks2oqYQJ5`}e z5{_0XbN~|M81!U#KoDEh?tr8Kdw|1$%Oi%Q962`)=t&qTt=p%^lIYIiEaUV{zX&-7 zWxq7gks3~gCTmjtfD~w0FBFgZvVBAq zHle+4qYhFENTB6RTd@NuAA$#r)T0Oe(wG5)HAGFBupq!e1f@X;?Hs5^XHhx^pfavatars/pajlada.png avatars/revolter.jpg avatars/slch.png + avatars/xheaveny.png avatars/zneix.png buttons/addSplit.png buttons/addSplitDark.png @@ -105,4 +106,4 @@ twitch/verified.png twitch/vip.png - \ No newline at end of file + diff --git a/src/autogenerated/ResourcesAutogen.cpp b/src/autogenerated/ResourcesAutogen.cpp index d4b48b970..008fb9d6a 100644 --- a/src/autogenerated/ResourcesAutogen.cpp +++ b/src/autogenerated/ResourcesAutogen.cpp @@ -9,6 +9,7 @@ Resources2::Resources2() this->avatars.mm2pl = QPixmap(":/avatars/mm2pl.png"); this->avatars.pajlada = QPixmap(":/avatars/pajlada.png"); this->avatars.slch = QPixmap(":/avatars/slch.png"); + this->avatars.xheaveny = QPixmap(":/avatars/xheaveny.png"); this->avatars.zneix = QPixmap(":/avatars/zneix.png"); this->buttons.addSplit = QPixmap(":/buttons/addSplit.png"); this->buttons.addSplitDark = QPixmap(":/buttons/addSplitDark.png"); @@ -61,4 +62,4 @@ Resources2::Resources2() this->twitch.vip = QPixmap(":/twitch/vip.png"); } -} // namespace chatterino \ No newline at end of file +} // namespace chatterino diff --git a/src/autogenerated/ResourcesAutogen.hpp b/src/autogenerated/ResourcesAutogen.hpp index 7277cc681..f5454954b 100644 --- a/src/autogenerated/ResourcesAutogen.hpp +++ b/src/autogenerated/ResourcesAutogen.hpp @@ -14,6 +14,7 @@ public: QPixmap mm2pl; QPixmap pajlada; QPixmap slch; + QPixmap xheaveny; QPixmap zneix; } avatars; struct { @@ -77,4 +78,4 @@ public: } twitch; }; -} // namespace chatterino \ No newline at end of file +} // namespace chatterino From 3238d1f801b94d6617ab4a29914df0508a897d03 Mon Sep 17 00:00:00 2001 From: ALazyMeme Date: Sat, 31 Jul 2021 23:24:56 +1000 Subject: [PATCH 3/4] Add ALazyMeme to the contributor list (#3097) Co-authored-by: pajlada --- resources/avatars/alazymeme.png | Bin 0 -> 21381 bytes resources/contributors.txt | 1 + resources/resources_autogenerated.qrc | 1 + src/autogenerated/ResourcesAutogen.cpp | 1 + src/autogenerated/ResourcesAutogen.hpp | 1 + 5 files changed, 4 insertions(+) create mode 100644 resources/avatars/alazymeme.png diff --git a/resources/avatars/alazymeme.png b/resources/avatars/alazymeme.png new file mode 100644 index 0000000000000000000000000000000000000000..66ac412bba7676beb1a257d6803ad26a523491a3 GIT binary patch literal 21381 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 TR+I2100000NkvXXu0mjfVq100 literal 0 HcmV?d00001 diff --git a/resources/contributors.txt b/resources/contributors.txt index 135b6abdb..13e67ea9b 100644 --- a/resources/contributors.txt +++ b/resources/contributors.txt @@ -43,6 +43,7 @@ matthewde | https://github.com/m4tthewde | :/avatars/matthewde.jpg | Contributor Karar Al-Remahy | https://github.com/KararTY | :/avatars/kararty.png | Contributor Talen | https://github.com/talneoran | | Contributor SLCH | https://github.com/SLCH | :/avatars/slch.png | Contributor +ALazyMeme | https://github.com/alazymeme | :/avatars/alazymeme.png | Contributor xHeaveny_ | https://github.com/xHeaveny | :/avatars/xheaveny.png | Contributor # If you are a contributor add yourself above this line diff --git a/resources/resources_autogenerated.qrc b/resources/resources_autogenerated.qrc index 85cbf9d7b..8890d5f05 100644 --- a/resources/resources_autogenerated.qrc +++ b/resources/resources_autogenerated.qrc @@ -1,5 +1,6 @@ + avatars/alazymeme.png avatars/fourtf.png avatars/kararty.png avatars/matthewde.jpg diff --git a/src/autogenerated/ResourcesAutogen.cpp b/src/autogenerated/ResourcesAutogen.cpp index 008fb9d6a..4395159b8 100644 --- a/src/autogenerated/ResourcesAutogen.cpp +++ b/src/autogenerated/ResourcesAutogen.cpp @@ -4,6 +4,7 @@ namespace chatterino { Resources2::Resources2() { + this->avatars.alazymeme = QPixmap(":/avatars/alazymeme.png"); this->avatars.fourtf = QPixmap(":/avatars/fourtf.png"); this->avatars.kararty = QPixmap(":/avatars/kararty.png"); this->avatars.mm2pl = QPixmap(":/avatars/mm2pl.png"); diff --git a/src/autogenerated/ResourcesAutogen.hpp b/src/autogenerated/ResourcesAutogen.hpp index f5454954b..ec5582ea2 100644 --- a/src/autogenerated/ResourcesAutogen.hpp +++ b/src/autogenerated/ResourcesAutogen.hpp @@ -9,6 +9,7 @@ public: Resources2(); struct { + QPixmap alazymeme; QPixmap fourtf; QPixmap kararty; QPixmap mm2pl; From 3cb1e5158ab360776a98954aff9e79b2b2f5d6d7 Mon Sep 17 00:00:00 2001 From: apa420 <17131426+apa420@users.noreply.github.com> Date: Sat, 31 Jul 2021 16:15:43 +0200 Subject: [PATCH 4/4] Added the ability to add nicknames for users (#2981) Co-authored-by: Mm2PL Co-authored-by: Rasmus Karlsson --- CHANGELOG.md | 1 + chatterino.pro | 4 + src/CMakeLists.txt | 6 ++ src/controllers/nicknames/Nickname.hpp | 77 +++++++++++++++++++ src/controllers/nicknames/NicknamesModel.cpp | 31 ++++++++ src/controllers/nicknames/NicknamesModel.hpp | 25 ++++++ src/providers/twitch/TwitchMessageBuilder.cpp | 12 +++ src/singletons/Settings.cpp | 2 + src/singletons/Settings.hpp | 3 + src/widgets/dialogs/SettingsDialog.cpp | 2 + src/widgets/settingspages/NicknamesPage.cpp | 48 ++++++++++++ src/widgets/settingspages/NicknamesPage.hpp | 18 +++++ 12 files changed, 229 insertions(+) create mode 100644 src/controllers/nicknames/Nickname.hpp create mode 100644 src/controllers/nicknames/NicknamesModel.cpp create mode 100644 src/controllers/nicknames/NicknamesModel.hpp create mode 100644 src/widgets/settingspages/NicknamesPage.cpp create mode 100644 src/widgets/settingspages/NicknamesPage.hpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 30ee83b3d..b4f669847 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Unversioned - Major: Newly uploaded Twitch emotes are once again present in emote picker and can be autocompleted with Tab as well. (#2992) +- Major: Added the ability to add nicknames for users. (#137, #2981) - Minor: Added autocompletion in /whispers for Twitch emotes, Global Bttv/Ffz emotes and emojis. (#2999, #3033) - Minor: Received Twitch messages now use the exact same timestamp (obtained from Twitch's server) for every Chatterino user instead of assuming message timestamp on client's side. (#3021) - Minor: Received IRC messages use `time` message tag for timestamp if it's available. (#3021) diff --git a/chatterino.pro b/chatterino.pro index 032423d65..b858cec90 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -162,6 +162,7 @@ SOURCES += \ src/controllers/ignores/IgnoreModel.cpp \ src/controllers/moderationactions/ModerationAction.cpp \ src/controllers/moderationactions/ModerationActionModel.cpp \ + src/controllers/nicknames/NicknamesModel.cpp \ src/controllers/notifications/NotificationController.cpp \ src/controllers/notifications/NotificationModel.cpp \ src/controllers/pings/MutedChannelModel.cpp \ @@ -315,6 +316,7 @@ SOURCES += \ src/widgets/settingspages/IgnoresPage.cpp \ src/widgets/settingspages/KeyboardSettingsPage.cpp \ src/widgets/settingspages/ModerationPage.cpp \ + src/widgets/settingspages/NicknamesPage.cpp \ src/widgets/settingspages/NotificationPage.cpp \ src/widgets/settingspages/SettingsPage.cpp \ src/widgets/splits/ClosedSplits.cpp \ @@ -391,6 +393,8 @@ HEADERS += \ src/controllers/ignores/IgnorePhrase.hpp \ src/controllers/moderationactions/ModerationAction.hpp \ src/controllers/moderationactions/ModerationActionModel.hpp \ + src/controllers/nicknames/Nickname.hpp \ + src/controllers/nicknames/NicknamesModel.hpp \ src/controllers/notifications/NotificationController.hpp \ src/controllers/notifications/NotificationModel.hpp \ src/controllers/pings/MutedChannelModel.hpp \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 207f8c104..e935e7366 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -96,6 +96,10 @@ set(SOURCE_FILES controllers/moderationactions/ModerationActionModel.cpp controllers/moderationactions/ModerationActionModel.hpp + controllers/nicknames/NicknamesModel.cpp + controllers/nicknames/NicknamesModel.hpp + controllers/nicknames/Nickname.hpp + controllers/notifications/NotificationController.cpp controllers/notifications/NotificationController.hpp controllers/notifications/NotificationModel.cpp @@ -428,6 +432,8 @@ set(SOURCE_FILES widgets/settingspages/KeyboardSettingsPage.hpp widgets/settingspages/ModerationPage.cpp widgets/settingspages/ModerationPage.hpp + widgets/settingspages/NicknamesPage.cpp + widgets/settingspages/NicknamesPage.hpp widgets/settingspages/NotificationPage.cpp widgets/settingspages/NotificationPage.hpp widgets/settingspages/SettingsPage.cpp diff --git a/src/controllers/nicknames/Nickname.hpp b/src/controllers/nicknames/Nickname.hpp new file mode 100644 index 000000000..67e7d3f40 --- /dev/null +++ b/src/controllers/nicknames/Nickname.hpp @@ -0,0 +1,77 @@ +#pragma once + +#include "controllers/accounts/AccountController.hpp" + +#include "util/RapidJsonSerializeQString.hpp" +#include "util/RapidjsonHelpers.hpp" + +#include +#include + +#include + +namespace chatterino { + +class Nickname +{ +public: + Nickname(const QString &name, const QString &replace) + : name_(name) + , replace_(replace) + { + } + + const QString &name() const + { + return this->name_; + } + const QString &replace() const + { + return this->replace_; + } + +private: + QString name_; + QString replace_; +}; + +} // namespace chatterino + +namespace pajlada { + +template <> +struct Serialize { + static rapidjson::Value get(const chatterino::Nickname &value, + rapidjson::Document::AllocatorType &a) + { + rapidjson::Value ret(rapidjson::kObjectType); + + chatterino::rj::set(ret, "name", value.name(), a); + chatterino::rj::set(ret, "replace", value.replace(), a); + + return ret; + } +}; + +template <> +struct Deserialize { + static chatterino::Nickname get(const rapidjson::Value &value, + bool *error = nullptr) + { + if (!value.IsObject()) + { + PAJLADA_REPORT_ERROR(error) + return chatterino::Nickname(QString(), QString()); + } + + QString _name; + QString _replace; + + chatterino::rj::getSafe(value, "name", _name); + chatterino::rj::getSafe(value, "replace", _replace); + + return chatterino::Nickname(_name, _replace); + } +}; + +} // namespace pajlada diff --git a/src/controllers/nicknames/NicknamesModel.cpp b/src/controllers/nicknames/NicknamesModel.cpp new file mode 100644 index 000000000..703c6661b --- /dev/null +++ b/src/controllers/nicknames/NicknamesModel.cpp @@ -0,0 +1,31 @@ +#include "NicknamesModel.hpp" + +#include "Application.hpp" +#include "providers/twitch/api/Helix.hpp" +#include "singletons/Settings.hpp" +#include "util/StandardItemHelper.hpp" + +namespace chatterino { + +NicknamesModel::NicknamesModel(QObject *parent) + : SignalVectorModel(2, parent) +{ +} + +// turn a vector item into a model row +Nickname NicknamesModel::getItemFromRow(std::vector &row, + const Nickname &original) +{ + return Nickname{row[0]->data(Qt::DisplayRole).toString(), + row[1]->data(Qt::DisplayRole).toString()}; +} + +// turns a row in the model into a vector item +void NicknamesModel::getRowFromItem(const Nickname &item, + std::vector &row) +{ + setStringItem(row[0], item.name()); + setStringItem(row[1], item.replace()); +} + +} // namespace chatterino diff --git a/src/controllers/nicknames/NicknamesModel.hpp b/src/controllers/nicknames/NicknamesModel.hpp new file mode 100644 index 000000000..f7947a7fa --- /dev/null +++ b/src/controllers/nicknames/NicknamesModel.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include + +#include "common/SignalVectorModel.hpp" +#include "controllers/nicknames/Nickname.hpp" + +namespace chatterino { + +class NicknamesModel : public SignalVectorModel +{ +public: + explicit NicknamesModel(QObject *parent); + +protected: + // turn a vector item into a model row + virtual Nickname getItemFromRow(std::vector &row, + const Nickname &original) override; + + // turns a row in the model into a vector item + virtual void getRowFromItem(const Nickname &item, + std::vector &row) override; +}; + +} // namespace chatterino diff --git a/src/providers/twitch/TwitchMessageBuilder.cpp b/src/providers/twitch/TwitchMessageBuilder.cpp index ed862ca4c..f79104799 100644 --- a/src/providers/twitch/TwitchMessageBuilder.cpp +++ b/src/providers/twitch/TwitchMessageBuilder.cpp @@ -690,6 +690,18 @@ void TwitchMessageBuilder::appendUsername() break; } + auto nicknames = getCSettings().nicknames.readOnly(); + auto loginLower = this->message().loginName.toLower(); + + for (const auto &nickname : *nicknames) + { + if (nickname.name().toLower() == loginLower) + { + usernameText = nickname.replace(); + break; + } + } + if (this->args.isSentWhisper) { // TODO(pajlada): Re-implement diff --git a/src/singletons/Settings.cpp b/src/singletons/Settings.cpp index c7acb3319..f81620914 100644 --- a/src/singletons/Settings.cpp +++ b/src/singletons/Settings.cpp @@ -23,6 +23,7 @@ ConcurrentSettings::ConcurrentSettings() , ignoredMessages(*new SignalVector()) , mutedChannels(*new SignalVector()) , filterRecords(*new SignalVector()) + , nicknames(*new SignalVector()) , moderationActions(*new SignalVector) { persist(this->highlightedMessages, "/highlighting/highlights"); @@ -32,6 +33,7 @@ ConcurrentSettings::ConcurrentSettings() persist(this->ignoredMessages, "/ignore/phrases"); persist(this->mutedChannels, "/pings/muted"); persist(this->filterRecords, "/filtering/filters"); + persist(this->nicknames, "/nicknames"); // tagged users? persist(this->moderationActions, "/moderation/actions"); } diff --git a/src/singletons/Settings.hpp b/src/singletons/Settings.hpp index 808e7656b..703fefbde 100644 --- a/src/singletons/Settings.hpp +++ b/src/singletons/Settings.hpp @@ -10,6 +10,7 @@ #include "controllers/highlights/HighlightBadge.hpp" #include "controllers/highlights/HighlightPhrase.hpp" #include "controllers/moderationactions/ModerationAction.hpp" +#include "controllers/nicknames/Nickname.hpp" #include "singletons/Toasts.hpp" #include "util/StreamerMode.hpp" #include "widgets/Notebook.hpp" @@ -23,6 +24,7 @@ class HighlightBlacklistUser; class IgnorePhrase; class TaggedUser; class FilterRecord; +class Nickname; /// Settings which are availlable for reading on all threads. class ConcurrentSettings @@ -37,6 +39,7 @@ public: SignalVector &ignoredMessages; SignalVector &mutedChannels; SignalVector &filterRecords; + SignalVector &nicknames; //SignalVector &taggedUsers; SignalVector &moderationActions; diff --git a/src/widgets/dialogs/SettingsDialog.cpp b/src/widgets/dialogs/SettingsDialog.cpp index ccd5fbee8..47db42b4d 100644 --- a/src/widgets/dialogs/SettingsDialog.cpp +++ b/src/widgets/dialogs/SettingsDialog.cpp @@ -17,6 +17,7 @@ #include "widgets/settingspages/IgnoresPage.hpp" #include "widgets/settingspages/KeyboardSettingsPage.hpp" #include "widgets/settingspages/ModerationPage.hpp" +#include "widgets/settingspages/NicknamesPage.hpp" #include "widgets/settingspages/NotificationPage.hpp" #include @@ -164,6 +165,7 @@ void SettingsDialog::addTabs() this->addTab([]{return new GeneralPage;}, "General", ":/settings/about.svg"); this->ui_.tabContainer->addSpacing(16); this->addTab([]{return new AccountsPage;}, "Accounts", ":/settings/accounts.svg", SettingsTabId::Accounts); + this->addTab([]{return new NicknamesPage;}, "Nicknames", ":/settings/accounts.svg"); this->ui_.tabContainer->addSpacing(16); this->addTab([]{return new CommandPage;}, "Commands", ":/settings/commands.svg"); this->addTab([]{return new HighlightingPage;}, "Highlights", ":/settings/notifications.svg"); diff --git a/src/widgets/settingspages/NicknamesPage.cpp b/src/widgets/settingspages/NicknamesPage.cpp new file mode 100644 index 000000000..2a464d7c0 --- /dev/null +++ b/src/widgets/settingspages/NicknamesPage.cpp @@ -0,0 +1,48 @@ +#include "NicknamesPage.hpp" + +#include "controllers/nicknames/NicknamesModel.hpp" +#include "singletons/Settings.hpp" +#include "singletons/WindowManager.hpp" +#include "util/LayoutCreator.hpp" +#include "widgets/Window.hpp" +#include "widgets/helper/EditableModelView.hpp" + +#include + +#include + +namespace chatterino { + +NicknamesPage::NicknamesPage() +{ + LayoutCreator layoutCreator(this); + auto layout = layoutCreator.setLayoutType(); + + layout.emplace( + "Nicknames do not work with features such as search or user highlights." + "\nWith those features you will still need to use the user's original " + "name."); + EditableModelView *view = + layout + .emplace( + (new NicknamesModel(nullptr)) + ->initialized(&getSettings()->nicknames)) + .getElement(); + + view->setTitles({"Username", "Nickname"}); + view->getTableView()->horizontalHeader()->setSectionResizeMode( + QHeaderView::Interactive); + view->getTableView()->horizontalHeader()->setSectionResizeMode( + 1, QHeaderView::Stretch); + + view->addButtonPressed.connect([] { + getSettings()->nicknames.append(Nickname{"Username", "Nickname"}); + }); + + QTimer::singleShot(1, [view] { + view->getTableView()->resizeColumnsToContents(); + view->getTableView()->setColumnWidth(0, 250); + }); +} + +} // namespace chatterino diff --git a/src/widgets/settingspages/NicknamesPage.hpp b/src/widgets/settingspages/NicknamesPage.hpp new file mode 100644 index 000000000..59b2f7102 --- /dev/null +++ b/src/widgets/settingspages/NicknamesPage.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "widgets/helper/EditableModelView.hpp" +#include "widgets/settingspages/SettingsPage.hpp" + +#include + +class QVBoxLayout; + +namespace chatterino { + +class NicknamesPage : public SettingsPage +{ +public: + NicknamesPage(); +}; + +} // namespace chatterino