+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+.
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..c92dd89
--- /dev/null
+++ b/README.md
@@ -0,0 +1,117 @@
+#
+:avocado: Easy Guacamole Installer & Jump-Host Builder
+
+
+
+
+
+This suite of build and management scripts makes setting up a secure Guacamole jump server a breeze. Its got installer support for TLS reverse proxy (self sign or LetsEncrypt), Active Directory integration, multi-factor authentication, Quick Connect & History Recording Storage UI enhancements, a custom UI theme creation template with dark mode as default, auto database backup, O365 email alerts, internal daemon security hardening options and even a fail2ban policy for defence against brute force attacks. There's also code in here to get you up and running with an enterprise deployment approach very similar to [Amazon's Guacmole Bastion Cluster](http://netcubed-ami.s3-website-us-east-1.amazonaws.com/guaws/v2.3.1/cluster/), if that's your thing!
+
+## Automatic Installation
+
+
To start building your Guacamole appliance, paste the below link into a terminal and just follow the option prompts **(no need for sudo, but you must be a member of the sudo group)**:
+
+```shell
+wget https://raw.githubusercontent.com/itiligent/Guacamole-Install/main/1-setup.sh && chmod +x 1-setup.sh && ./1-setup.sh
+```
+
+## Prerequisites
+
+
**Before diving in, make sure you have:**
+
+- **A compatible OS:**
+ - **Debian 12, 11 or 10**
+ - **Ubuntu 23.04, 22.04, 20.04**
+ - **Raspbian Buster or Bullseye**
+ - **Official vendor cloud images equivalent to the above versions.**
+ - (if your cloud image uses an IP of 127.0.1.1, [see here to use TLS with Nginx](https://github.com/itiligent/Guacamole-Install/issues/21))
+- **1 CPU core + 2GB RAM for every 25 users (plus minimum RAM & disk space for your selected OS).**
+- **Open TCP ports: 22, 80, and 443 (no other services using 80, 8080 & 443)**
+- **If selecting either of the TLS reverse proxy options, you must create an internal DNS record for the internal proxy site, and an additional public DNS record if using the LetsEncypt option.**
+
+## Setup Script Menu
+
+
**The main 1-setup.sh script guides you through the installation options in the following steps:**
+
+1. Setup the system hostname and local DNS name. (Must be consistent with DNS records for TLS proxy)
+2. Choose either a fresh local MySQL install or use a pre-existing remote MySQL instance.
+3. Pick an authentication extension: DUO, TOTP, LDAP/Active Directory, or none.
+4. Select optional console features: Quick Connect & History Recorded Storage UI integrations.
+5. Decide on the Guacamole front end: Nginx reverse proxy (http or https) or keep the native Guacamole interface on port 8080
+ - If you opt to install Nginx with self signed TLS:
+ - New server and client browser certificates are saved to `$HOME/guac-setup/tls-certs/[date-time]`
+ - Pay attention to on-screen instructions for client certificate import (no more pesky browser warnings).
+
+## Custom Installation Instructions
+
+
**If you want to make Guacamole your own and customise all the available options:**
+
+
+ - Exit `1-setup.sh` at the first prompt. (the script suite is now downloaded under `$HOME/guac-setup`)
+ - All the configurable options are clearly noted at the start of `1-setup.sh` under **Silent setup options**. Simply re-run the edited setup script when done making your changes.
+ - Certain combinations of the silent setup options will allow a fully unattended install.
+
+**Other useful custom install notes:**
+- **Caution: Be aware that running the auto-installer link again re-downloads the suite of scripts and will overwrite all script edits. You must run setup locally after editing the setup script.** If any other scripts are edited, their corresponding download links in the setup script must also be commented out in the main setup script else these will be overwritten even when setup is run locally. There should be no reason to edit any script other than the main `1-setup.sh`
+
+- Many of the scripts in the suite are **automatically adjusted with your chosen installation settings at 1st install** to form a matched set. This allows you to upgrade Guacamole or add extra features after the original installation without any configuration mismatches or errors. Editing any scripts other than the main setup may break this function.
+- Nginx is automatically configured to default to at least TLS 1.2, therefore ancient browsers or API connections using TLS 1.1 will not work out of the box. This can be reverted via the the `/etc/nginx/nginx.conf` file.
+- A daily MySQL backup job will be automatically configured under the script owner's crontab.
+- **Security note:** The Quick Connect option brings a few extra security implications; so be aware of potential risks in your particular environment.
+
+**For the more security minded, there's several post-install hardening script options available (manually applied):**
+
+- `add-fail2ban.sh`: Adds a lockdown policy for Guacamole to guard against password brute force attacks.
+- `add-tls-guac-daemon.sh`: Wraps internal traffic between the guac server daemon & guac application in TLS.
+- `add-auth-ldap.sh`: A template script for Active Directory integration and authentication management.
+- `add-smtp-relay-o365.sh`: A template script for email alerts integrated with MSO65 (BYO app password).
+
+## Customise & Brand Your Guacamole Theme
+
+
**Want to give Guacamole your personal touch? Follow the theme and branding instructions** [here](https://github.com/itiligent/Guacamole-Install/tree/main/guac-custom-theme-builder). To revert to the Guacamole default theme, simply delete the branding.jar file from /etc/guacamole/extensions then `TOMCAT=$(ls /etc/ | grep tomcat) && sudo systemctl restart ${TOMCAT} && sudo systemctl restart guacd && sudo systemctl restart nginx` and don't forget to clear your web browser cache.
+
+## Managing self signed TLS certs with Nginx (the easy way!)
+
+ - **To renew self signed certificates or to change the reverse proxy local dns name/IP address:**
+ - Just re-run `4a-install-tls-self-signed-nginx.sh` as many times as you like to create a new certificate for Nginx (accompanying browser client certs will also be updated). Look to this script's comments for further command line argument options and remember to clear your browser cache after changing certificates.
+
+## Active Directory SSO Integration
+
+
**Need help with Active Directory authentication?** Check [here](https://github.com/itiligent/Guacamole-Install/blob/main/ACTIVE-DIRECTORY-HOW-TO.md).
+
+## Upgrading Guacamole
+
+
To upgrade Guacamole, edit `upgrade-guac.sh` to relfect the latest versions of Guacamole and MySQL connector/J before running it. This script will automatically update the installed extensions too.
+
+## High Availability Deployment
+
+
Did you know that Guacamole can run in a load balanced farm with layered physical/virutual separation between the web front end, application and database layers? To achieve this, the MySQL, Guacamole and Nginx front end components are typically split into 3 systems (or containers). VLANs & firewalls between these layers help greatly with defence in depth security concepts too.
+
+ A simple benefit of using a separate MySQL backend server or MYSQL container means you can upgrade and test whilst keeping all your data and connection profiles intact. Just point this installer to your MySQL instance and immediately all your connection profiles and settings are right there!
+
+- **For the DATABASE layer:** Find the included `install-mysql-backend-only.sh` [here](https://github.com/itiligent/Guacamole-Install/tree/main/guac-enterprise-build) to install a standalone instance of the Guacamole MySQL database for your backend.
+- **For the APPLICATION layer:** You can use the main setup script to build as many application servers as you like. Simply run the main installer to point new installations to a separate remote backend database, just make sure to say **no** to both the "Install MySQL locally" option and any other reverse proxy install options.
+- **For the Front end**: There are so many choices available that are already very well documented. You could even use the Nginx scripts to build a separate TLS front end layer. Be aware that [HA Proxy](https://www.haproxy.org/) generally provides far superior session persistence/affinity under load balanced conditions [when compared to Open Source Nginx](https://www.nginx.com/products/nginx/compare-models/) as only Nginx Plus subscribers get all the proper load balancing stuff!
+
+### Installer script download manifest
+
+
The autorun link downloads these repo files into `$HOME/guac-setup`:
+
+- `1-setup.sh`: The parent installation script.
+- `2-install-guacamole.sh`: Guacamole source build & installer script.
+- `3-install-nginx.sh`: Nginx installation script.
+- `4a-install-tls-self-signed-nginx.sh`: Install / refresh self-signed TLS certificates script.
+- `4b-install-tls-letsencrypt-nginx.sh`: Let's Encrypt for Nginx installer script.
+- `add-auth-duo.sh`: Duo MFA extension install script.
+- `add-auth-ldap.sh`: Active Directory extension installer script.
+- `add-auth-totp.sh`: TOTP MFA extension installer script.
+- `add-xtra-quickconnect.sh`: Quick Connect console extension installer script.
+- `add-xtra-histrecstore.sh`: History Recorded Storage extension installer script.
+- `add-smtp-relay-o365.sh`: Script for O365 SMTP auth relay setup (BYO app password).
+- `add-tls-guac-daemon.sh`: Script to wrap internal guacd daemon to Guacamole web app traffic in TLS.
+- `add-fail2ban.sh`: Fail2ban (and Guacamole protection policy) installer script.
+- `backup-guacamole.sh`: MySQL backup script.
+- `upgrade-guac.sh`: Guacamole application, extension and MySQL connector upgrade script.
+- `branding.jar`: Template for customising Guacamole's UI theme.
+
+😄🥑
diff --git a/branding.jar b/branding.jar
new file mode 100644
index 0000000000000000000000000000000000000000..1e4f1a64979e0c2a09396d9e7c169e1b0783551b
GIT binary patch
literal 19175
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
L^h^w_g;#$9cgOc?
literal 0
HcmV?d00001
diff --git a/guac-custom-theme-builder/META-INF/MANIFEST.MF b/guac-custom-theme-builder/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..84bd8bc
--- /dev/null
+++ b/guac-custom-theme-builder/META-INF/MANIFEST.MF
@@ -0,0 +1,8 @@
+Manifest-Version: 1.0
+Name: branding
+Specification-Title: Custom Guacamole Theme CSS
+Specification-Version: 1.0
+Implementation-Title: Custom Guacamole Theme CSS
+Implementation-Version: 1.0
+
+
diff --git a/guac-custom-theme-builder/README.MD b/guac-custom-theme-builder/README.MD
new file mode 100644
index 0000000..94b9924
--- /dev/null
+++ b/guac-custom-theme-builder/README.MD
@@ -0,0 +1,23 @@
+
+## Custom branding & theme instructions ##
+
+1. Install the Java JDK: `sudo apt update && sudo apt -y install default-jdk`
+3. Modify `custom-theme.css` ,`guac-manifest.json`, `en.json` & `META-INF` as desired & add your logos to the images directory. (Logos must be .png files.)
+4. To commit your changes, run the below commands from within the custom-theme-builder directory, then refresh your browser to re-login to Guacamole:
+```
+# Run within the custom-theme-builder directory
+jar cfmv branding.jar META-INF/MANIFEST.MF guac-manifest.json css images translations META-INF
+sudo mv branding.jar /etc/guacamole/extensions
+sudo chmod 664 /etc/guacamole/extensions/branding.jar
+TOMCAT=$(ls /etc/ | grep tomcat)
+sudo systemctl restart guacd && sudo systemctl restart ${TOMCAT}
+```
+
+## Theme customisation hints: ##
+ - Do not change any of the theme's directory structure or file names. File contents can be carefully edited according to the following constraints:
+ - `MANIFEST.MF`: All values in here can be updated. Be aware that the "Name:" value MUST use same value in front of the the .jar creation command shown above in the 1st line e.g. `Name: branding` expects branding.jar
+ - `guac-manifest.json`: The "name:" value in here can be changed to anything. The "namespace:" value given in this file MUST match the namespace image path line found in `custom-theme.css`, eg.`background-image: url('app/ext/custom-namespace/images/logo.png');`
+ - It is preferable to give css a range of logo sizes as shown in the template. The "smallIcon" value in `guac-manifest.json` is used for browser tab favicons. As such this file can be kept to < 80x80 pixels. The example used is 64x64 pixels.
+ - Within `custom-theme.css`, you may need to experiment with the the height and width values under `.login-ui .login-dialog .logo` to scale your particular logo neatly within the dialog box. Another option is to make the login dialog box larger. Under `.login-ui .login-dialog`, experiment with adding a `max-width: 4in;` or similar. There's a ton of css options available and this template is just starting point, Google is your friend!
+ - An easy way to debug and preview potential style changes is to tweak various values by setting your browser to developer mode.
+ - Your changes may occasionally appear not to update, if so clear your browser cache before doing any further debugging.
diff --git a/guac-custom-theme-builder/css/custom-theme.css b/guac-custom-theme-builder/css/custom-theme.css
new file mode 100644
index 0000000..2e5f12e
--- /dev/null
+++ b/guac-custom-theme-builder/css/custom-theme.css
@@ -0,0 +1,245 @@
+/* Colour codes used */
+/* Guacamole grassy green: #88bf5b */
+/* Warning red #ff2233 */
+/* Main background charcoal #3f3f3f */
+/* Input fields dark charcoal #2b2b2b */
+/* Login dialog background black #000000 */
+/* All text: #ececec */
+
+
+/* General Style */
+body {
+ color: #ececec;
+ background-color: #3f3f3f;
+}
+pre {
+ color: #ececec;
+ background-color: #2b2b2b;
+ border: 1px solid #000000;
+}
+
+a[href]:visited {
+ color: #88bf5b;
+}
+a[href] {
+ color: #88bf5b;
+}
+
+div.location,
+input[type=text],
+input[type=email],
+input[type=number],
+input[type=password],
+textarea {
+ background-color: #2b2b2b;
+ color: #ececec;
+}
+
+
+/* Login */
+div.login-ui {
+ color: #ececec;
+ background-color: #3f3f3f;
+}
+.login-ui .login-fields .labeled-field input:focus {
+ background-color: #3f3f3f;
+ color: #ececec;
+}
+
+.login-ui .login-fields .labeled-field {
+ background-color: #3f3f3f;
+ color: #ececec;
+}
+
+.login-ui .login-dialog .logo {
+ background-image: url('app/ext/custom-namespace/images/logo.png');
+ width: 7em;
+ height: 7em;
+ -webkit-background-size: 7em auto;
+
+}
+
+.login-ui .login-dialog {
+ background-color: #000000;
+ color: #ececec;
+}
+
+.login-ui .login-dialog .version .app-name {
+ font-weight: 300;
+ text-transform: none;
+ text-align: center;
+ font-size: 2.25em;
+ color: #ececec;
+ font-family: arial black, sans-serif;
+}
+
+div.logged-out-modal .ng-scope {
+ color: #ececec;
+ background-color: #000000;
+}
+
+div.logged-out-modal .ng-scope button {
+ color: #ececec;
+ background-color: #3f3f3f;
+ border: 1px solid #ececec;
+}
+
+div.modal-contents {
+ color: #ececec;
+ background-color: #3f3f3f;
+}
+
+.logged-out-modal guac-modal {
+ color: #ececec;
+ background-color: #3f3f3f;
+}
+
+div.notification.ng.scope {
+ border: 1px solid #ececec;
+}
+
+.notification.error {
+ background-color: #ff2233;
+}
+
+.client-status-modal .notification.error {
+ background-color: #ff2233;
+}
+
+button.danger {
+ background: #ff2233;
+ }
+
+.login-ui.error p.login-error {
+ color: #ececec;
+ background-color: #ff2233;
+}
+
+
+/* Home */
+.recent-connections .connection:hover {
+ background-color: #88bf5b;
+}
+
+.menu-dropdown .menu-contents {
+ background-color: #2b2b2b;
+}
+.menu-dropdown .menu-contents li a {
+ color: #ececec;
+}
+.menu-dropdown .menu-contents li a:hover {
+ background-color: #88bf5b;
+}
+
+.list-item.selected {
+ background: #88bf5b
+}
+.list-item:not(.selected) .caption:hover {
+ background-color: #88bf5b;
+}
+.list-item .name {
+ color: #ececec;
+}
+
+.settings.connections .connection-list .new-sharing-profile {
+ opacity: .6;
+}
+
+.notification {
+ color: #ececec;
+ background-color: #2b2b2b;
+}
+
+
+/* Menus */
+.menu {
+ color: #ececec;
+ background-color: #3f3f3f;
+}
+
+.clipboard,
+.clipboard-service-target {
+ background-color: #2b2b2b;
+ color: #88bf5b;
+}
+
+.menu-dropdown .menu-contents li a.danger {
+ color: #ececec;
+ font-weight: 700;
+ background-color: #ff2233;
+}
+
+/* Connections */
+#connection-warning {
+ background-color: #3f3f3f;
+}
+
+.transfer-manager {
+ background-color: #2b2b2b;
+}
+.transfer.error {
+ background-color: #ff2233;
+}
+
+
+/* Settings */
+.page-tabs .page-list li a[href],
+.section-tabs li a {
+ color: #ececec;
+}
+.page-tabs .page-list li a[href]:hover,
+.section-tabs li a:hover {
+ background-color: #88bf5b;
+}
+.page-tabs .page-list li a[href]:visited {
+ color: #ececec;
+}
+
+.settings table.session-list tr.session:hover {
+ background-color: #88bf5b;
+}
+
+.location-chooser .dropdown {
+ background-color: #2b2b2b;
+}
+
+.settings.connectionHistory a.history-session-recording {
+ color: #88bf5b;
+}
+
+.settings.connectionHistory a.history-session-recording:after {
+ opacity: .0;
+}
+
+.user a,
+.user-group a,
+.connection a,
+.connection-group a {
+ color: #ececec;
+}
+.user a:hover,
+.user-group a:hover,
+.connection a:hover,
+.connection-group a:hover {
+ color: #ececec;
+}
+.user a:visited,
+.user-group a:visited,
+.connection a:visited,
+.connection-group a:visited {
+ color: #ececec;
+}
+
+.manage-user .notice.read-only {
+ color: #ececec;
+ background-color: #2b2b2b;
+}
+
+#filesystem-menu .header.breadcrumbs .breadcrumb:hover {
+ background-color: #88bf5b;
+}
+
+#guac-menu #zoom-out:hover,
+#guac-menu #zoom-in:hover {
+ background-color: #88bf5b;
+}
diff --git a/guac-custom-theme-builder/guac-manifest.json b/guac-custom-theme-builder/guac-manifest.json
new file mode 100644
index 0000000..29bbd48
--- /dev/null
+++ b/guac-custom-theme-builder/guac-manifest.json
@@ -0,0 +1,22 @@
+{
+
+ "guacamoleVersion" : "*",
+ "name" : "Custom Guacamole Theme",
+ "namespace" : "custom-namespace",
+ "smallIcon" : "images/logo-64.png",
+ "largeIcon" : "images/logo-144.png",
+ "translations" : [
+ "translations/en.json"
+ ],
+
+ "css" : [
+ "css/custom-theme.css"
+ ],
+
+ "resources" : {
+ "images/logo.png" : "image/png",
+ "images/logo-64.png" : "image/png",
+ "images/logo-144.png" : "image/png"
+ }
+}
+
diff --git a/guac-custom-theme-builder/images/logo-144.png b/guac-custom-theme-builder/images/logo-144.png
new file mode 100644
index 0000000000000000000000000000000000000000..8ed87ca29b56b299ad8042502fa061ce85d13508
GIT binary patch
literal 5342
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
literal 0
HcmV?d00001
diff --git a/guac-custom-theme-builder/images/logo-64.png b/guac-custom-theme-builder/images/logo-64.png
new file mode 100644
index 0000000000000000000000000000000000000000..2583ec045f709eef3e5896e2f4a27384d0da7b62
GIT binary patch
literal 1927
zcmV;22YC32P)Px+K}keGRCr$9TTP4Gii}Bbhebf4m`3wCmi
z!Z>zapbLP>9R>xA?*WZ-#s@osCiVrp`H=|bq?T=0no>U^rbPyk#z!qg#}Pe
zFrv#QzV`sgZKHZH?g0RFf^z_l-TYYa=>kv>9E9P-09Xrxl{3COGsGZxXJLHzxnTvt
zj2MvZ$_YEr1-$=H5G-i&>Top%G%tF4k->s)nvk}v>6J8Skp;?kMa9SjAbE{7
zG#G7+?AYdV7m}y+6A8eIT0s{8cG^K_xSJt5)Zw~>dqjN2ciV531Az5zQ1neKO@yQ+
z$t1$+^MGFsJ}(&nyWOBhpDPUDK?mS5lCF7(VtmSV0c#8BNzOPPoUFA!)#;KI$mB73
zf?&j-^XL59oVH-1;9DpQs6sb8^_Ov^@|(YFc1@s@o%+5C;ul%M$aR3cy6Y?r_WbiE
z{IOxmUAm(dE4o$HTSC&;djRly=->i`sgDkgZhU0)dj{~;q#GO){EPa&%!kwxQ&U{l
zDv1dwbRq8vsU^mka|(cO;ebyx-1aYtyuIYD0tcsP0b~t;ECg=AZ4*1&*P5NNvxxk7
znt4+I5Ou%W6VzD_=P=o*1nVMfrWIjT~z5byeKaIDqw&H=*Vq+mTa
z7AW%E(@{PmBrRXRv2f)6)lqgmD_E|BgAt+y#G1&d
zNR8NO-%MbwdjNFXT~j=;i4(F5AizJ2!!p&ZN09w~qB{SLpl>dE&r`>SbO`Vva5xQW
z7O-KWiv@WKmDZx?1L9NUxjBCnfc@;d^M~ZZ1`t0>@<>0#W59oOxNeWf7)>AS)4@&R~Z+M+F9u2l%rr1&f%%uZB;7t04=fN4ugY0O>;}Vk
zUDxY9x=xf00MnhZtsMDP>llzL2pWvT6s*o(I<#r!*658;IFbd#t+TL#Z7q7t#JAP)
zZXv?02{(8kOAq@PU=jKq&Z^_J`L#=z&87P5z;WLXf34KcA3nb#SfvIm1yo@z%_VOJ
zIUG?z5DJIyMM_K)xd%XBOH6-l)Hs`ht+Reo737H5+uC*0uMC}^tJdmVh*-`&2X
z{T5Hwb1U0Q&_a8?Nt+KjWos}`BaP<(eocQ#09O&=
zZ{R@RNyZb|#{g0mLWu6MrmDW>=J&$SAm3C}T03cms1M@4s8*Gn`
z$`Ic#s-QeR{pvnxbrRxO1VIXOO=V~J4MLfq#srnxHKwLb+ZE2Drvs41$?#o1M%R(Zm0Oy%0_>h<-iZyBe3%mMQwu&Pphp5_MUY|7T^E{{TcgZ`kj66;c2I
N002ovPDHLkV1m+!b{YTx
literal 0
HcmV?d00001
diff --git a/guac-custom-theme-builder/images/logo.png b/guac-custom-theme-builder/images/logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..1854ba1e7ddd245ac4674a01d2a59053fcb0802a
GIT binary patch
literal 10191
zcmeHtc|4Tg`!`aE2oVaEtYhp;WM9iV$lxAB6f#Q4PND3gMfU95Fout~EhD31RF;I9
z389dXrAS$den;Qud0yY&@A>0-J+J5W{P(+F$2j+OuIqg*=iD>*x$cvMvNAn%Q0O27
z1H+;7=ZtI_7?_~FKh}MK^DItq1pH&XVQXr@Q2XZi0=QuI(zn!SV5q;x{@ZOo7`ubA
zxL^$Ud-R9l&tCfz4G4U6Tnuf5LOY>^z2+U=aw)p|QbLF0omTrh&+Sw88aCnS-e@A(
zIj#e`-R5}vxnsg!bBSwrj(g!8PsS#{z$SD!$32DOoa31nyBRpK+Cf&oJSEfL6&F^SJGd)CR$Nud2}lniX`@xdo>
zb3;EyG0SG|&pThqM
zmLD}j22&6nXlrH1zzB$m=`c4S9-b2?0i8M}ub>D>Nl8~%PalwhwKd8Hkgc7otLsHK
zKES&o>;D)!}>=)hkC)z)8<%3_8
z8tBli!omPq41MFKb+DJ0SBU9ZhNld0v}6(gH)bkRK{WJ?7sVdRgk!YULw;n#@7H4d
z-vH=#fl%rY@UEr@*oz`ekN4)7`Z{uSF>{tGiw86Br)Y`Wx^?h*cQ?m}4i<`f=
zR-%+q=B!kieei{7$fGFpAc|mN4p*4_U0yxBW5%gRR6^3AA@hsB7`HQy?@6Fdi_pR-
zf*6XxiKlVn?OCW_&c#6smsYQR|8#v`oe?J4meZ#;!a9F%If?H{Q1-!HdPotx_yOFi
z9#RpN!h%bRfwWNO9MtI;$i0Z4i^{VP4lT+Q_;1nwngMsXBvdoMf39~npgwz`B3-fl
z)-1>&6I}B8YR*;L?O3-qm%f0G#YJXZ(gGf>;-p|Z+uG5BYcI;omctnj)J#D6Eq|zn
z>kkO~a7o@ov`ScMj)Q3}O%5+!Q4Y;e;wJ|mN8B4qsAB_+3@ANhOvN$&S7FgHXD*bv
z1v@OETa+T)@@GHkHOv5asi1wH{1(G5nyd+u27~q(7ZBlaEyBX*S5E}jaDOc$K*@m`
zTn878hc0UrcCDV#e2Nr$IlQGbIz-{Ib{)9F4csU}uip%(NjP12^JU!W^twb|KW#l3
znA-=pNFXdf2c^e_WJVRK&xK8Hll{OF!O^C3Yd*2R6e?D=O1k`|hKD0Wp
zkfFSw?oOh|w#^Q>8dtKyT~xfPbZ~s0mu|q*q3kEl@7_uqAQgS#&m9#}ybBHe;Rbni
zM`ptpsS@$*RGt}IMEIRu+rznQq}iDJ
z6SpCEAv|0q7oQ~Y-QLY(Ah`Xv7IrpNTem(`-nkh}ZaDl0G*QhQPL8s;T`ZtI!qGvI+1ws?kakwcVLOb7;(wX
zC-b{TqV=GU8zbD+LN&{w+{s{9sCMgVC@Fjk-&JTc0^;Rp4HnV%F%QL4V%EPgq|DXX
z!|%3$FPv~@xo#L`r~t}VN|5Z2bQhYI0$Hl3<@Rw558VxHwIWMfX#d`@__fi`@D~Z)
zd;Yi1%?kE%7kN?N{Q|EIk&68^o*YWeWAY_Z7lY3%n22s1Tfh4l(fPosr=IL!p;e9PYUJPxQF(Gn1)eAyyXG%?MBBZj}f<7Ye)AIT}@M5yl5x8(`&r;TonV>l`>rL
z`sjjwuo4j#u?w3o5Z}}I2bxZ0HYh$8;g$H2JH$Y65)bOg_
zu9Ma$$9q&UG5gp4u4pQ$Q#)=c)4PdjksEjz4wr}yVeF;)jPnjAK9i^dto1?vLpSmV
zr;-fpt6uBI!c6;cSkXB8>-9u8nywxZ(dFA@aYB?nErJho3~^
zK7K06Y^h*?8FRA#haPdUD>qp!hj@QF6d#m7(m$+`#^s%)LnT?cG*LArEe(5K8Uh*L
zf;Yp7Cp|=q=t1shFUKb`?sYTVt2~1FV<5fc+54|`m>=yKNuE7SWeV5Qk4o5={$Y^N
zCePm-H_wF+DtE-?Y;Q*YWQpCAxj%|NU6hRc%Pyudg&@ncJ1hM>lQsHP%TS9X>R64J;!W+|z}Dgr&SPgI`0}%66M`lwKkyl{k0I{C$jwv-
zoVt~#hP7it3N{Jy7OP9UJC~K(K4dK1({z+WX~*rH6A@v9kY;i4l|XEN62Ia%Mrp+k
z7Wrio7P$7EZCW`{jshF4rA1?btf>*!ddm8S~e)PnYXM
z7TOP9)iv8V-B-Kn_9LN~Ky#|mKKhW51YK&EtM{WC0?d;Pd+BeiofCrttyDiOtKECM!#aE=uF+~quLW0bw=E%9
zzafiLhD!N!T(${BuI*BK%PC<^zEb+z!gH32&U7BGTjwqdHVvEuQvdt#6^C
z;0m5TFW8EqT$>V8UgM~e**%wylMafP{2iQZNqg94UmY1WIIj3lpP|Wp+%>AE;i)x^
z`VmLsAmYi5@974txDEj~eTs*0wP$Co-2s+9E7(s=#nvnHr+h`>VDlNTaYSPdKS
z=!o4ato3lvHLr^^^24brAaeU0@*YhV)??+z#c!KN!Wd3?$aKNp&?=GtDp8!s5>VRt
zk!O{~z|P0+68H)JL{usx2)38=So>;F$FB9{d#sCKee~DZw*5F846ZgGBIL%iS`dXA
zB-rQ5K9aiSbZ3mRptiCl^x|ow?Qzrjbd7)*bfRLUi6ib>{-w_Ich;#7CwphaJ7zEV
zG+*9b8Vtc0eP76%bqP`lS9(_$Z{Hj#AqCr-b{$dW_PJ+X`^r>27DJqHSh#IG9%`Z(
zc2~z;@pTTLXNW*Hbc3XBXjlJJc3zo-H#|i`6{pzQr9B)n|Af~?)<^cf4)^5{flP?D
zY)M^tuSO#lCY;LCgk{EsEGO{`{KI9_>2xXOvY84blPy6rw(!X%gQK*}F9~ZfZuRDL
zf!A^CbXgs%uQKjAd{>GxxYHn73_2^bV#sdCkKjU_xIw!~cR*V>6xJ42`-Xn^M^~vR
zoOoeFkTFOmm6tZzM;-g&M~H#snw2CPD7WU4uaPEBFV2p)tE{Zl%@;&86_z>dJ1qcL
z=jQm&iPTgpm_}5P%#ehmQI^uDl3iX)Qp}7iPjcUdS}}7utlM?Tj9x}rFdl`tsq*3J
zlA3dHwdw;WnS2`=%|pp3YIS1U9C6>KmJi9CakhF`2G$Y4_}a64@6T~u_~)PggT};1
zUpXaDHONd1rG7%tg!slGwzHJ^4AGw7oa}q8
zutYt`-Ch1U=TiWIBo8JZsrbEl*a{vEz}p9!ANDt{d(TF1boS&GaKls7pakx7ewq(-&q&{(rpQz}57FMbt@FScXj)@menWr&ThQQe9r`rt^ZF9s0v0JjU8_H-&il$|KL$(f0gu~0@oK#Tt{xFVWqX>vy_~mZ
zMQjiwU+`!X6%4xEWcad18~tiSLytAz75xKGrGOcK!;POxBUCZ@VPoR4D
z2h<~qL*V&fjrEra5$M2;;|GmvBFb=wGRQRdl2FlN^v|q{wmH<7&|-e;4>(0ON%>;B
zufxivN4J>ql;LKmkHIF$GWO)gQmpL&I~=-=CLG85$ouNpytyj9yvy*H^Ee`LAz5vf
zDYBd@OPyx3M$+P(HF|9FZGW-;OM`LCmf+mY0Y4pThGwVzTuu8Fy*Wvzm~pG?M6`zB
zS4m=qpx(wnae7(;q%~Dl9yr5e@#Y9_tL!@bR9wkiftYD^;1F_NdR+m%}-Z?8Hp#
z!`&%h-*=Oc(Iz%k`Hk^)LJDwp_ED8Q++(l$sym__sP->qNLj}sET#341>dM^s@m8B
z)|cyz4%_IIQMljECbhZt=$;Gwb_el+bEjrGa)%s`{AHwzZKRL52XIMU{AmWVlKPsG
ziIw{C6qN$zu}8yB*I%o_@ow!o;6XcqQj_iQzCg-4OvIV+m=CDe@+%vy+i<+%I2!Jf
zts5HdkTTjyH@){tphnd>`maXUs^JIb1(SJKqy(A%l{;q_bqze{OfR@1KiAb3-XGB3
zWP_)LLH;|STOpG=FNDpC=!*u(08*`GZMk#rbbp
zP#$R=?ez|B0pqN2_U)tXa*A$4JJmZ#0BL}fyZ`PB&**T1>Of)~#K&CBf9%!b(*4Iu
z(#TnRL!iO|Z+e=GopA4YuB37diMQ7mz||Kwb#o|%7}NwOsQ?TkWbl2duPvF*th&jM
z-kds7#BVKy^Y`xOaB8D8JB^vg|7FytQw8f!__(-b{uI;$xB_s?Oz}owFk*H_oy(dN
zcD!vvaF@+eRhn4CMAAct2d`{u*Y2v{I7Ryclm@iLN7~xPR+Z1cx<)rr#Eko53
zZ(ly-#8Y_hL-wUz+RNy6iHt)<_m*Wr^=1CaV1SoH6I}8Rt3LDZ+Ha2zq9wlGOQNJ;MIQa
zdgwuxuwN0HuegeGwC5`~VfM8w$cG=!o+NJH`%YR2MY#QqS{-0sf&TP04EPX@voGT^
z!i6P&chffAmZE!%wAOXDgJ~uXq&>x4{~z>?kQ)V
zpsfWJ9kBs-Y=n0~XktOkY+T{+d$|KUB1LGgYAWfBYjE`s;s?OuqJCkeR`0_FG2>{1
zw#5BG_yQ?;+SgjN#m0Kq0UYhEEiq*nOH5&cd-RZeMQA~MIn%$@aT;iGio>OrwD1(2
zFvWs19Dzl2SWyE3c0lXa^BL^>;Mzm~4<(sSJD>Vim35Awvh|-S^-Tw}xgrbY!lrrG
zRas(jH+Qs2Riflze5J-)N8~`STrF$FC?#fN{-LCfsp}2BYWmiU%cj?N4-`Qa)yqhI
z$N(SLL$dwt`uW2{)`RbkAFlqfd40h{7x1&t2$+wjS~YwvWSw-hC^MFw;87{^3Ac3(
z?1W=`t249=KKL8d(4}_Su&WHzhkiEjinfKTzez1!YMUE7#DY8DQU+~U1pJD<4V4Z?
z{eB>a+XtU^Mj^Xph2f_#*z&!YrG_^McrCY<7H6vOp{7*9ZhgrvTYT7SHFV!!vunKf
zy8jqD1jRr+a^?J9=-+bK@!<=^iIw*jFNOZZ%T+T0z;nc9(}m9(1t1k7S8D0Lm&Dia
zh5EAt^LL>I-oWdI>pi0L(+~J@%fWvfZ{b9TlYnIpYIy5967AJenE|ym>lhv75V1WB
z_{LO{>%m5Mf^uIjJZC<7Aup=_eaplhP>4`|a7&5{m@^=*UkaR4Hf|6(Qo%2n%&VFA
z5VQRkQ=BUEBZ&8X&HC1wp~4YOisktc_d4kVz>#RETsHD~%>hgL1A|Wc;Kh!GWPX(S
z?I_r6qIlw1g|#~FN!rM=ZI$)!hXGlv@aatl!WqrGHBFU{&+I#AI?4uwH#bT!e<0SM
zabRX9X)+S#rC(>$nP-*qgiaw|ev2%w6JC_CD$Zp7iqpm>PIY8lcN`0hm#k6g`oQP=
zO_&Du<>$W<={p8(0qRGQ@WBR-u;wM><4&a&V^{T&Y-E~D-?zJevRnqFYMx!O(#e*u
zuyTECp$Ci=(98~|qUGLxxtclQ%SST$7gP;eU({|ZEAC@{c&AwFgNxgh>q4u-l)q*O
zbb5i--GCcI&Kfr^t$CEkam0EC9il$`=s+~ELa1wgGTVnycr)9)+v6+9X9xD{w;f>H
zv!b~vQz>F?^iMorkBL1ih!QiCuvaYrI!h;X
zl=244*eIU0E!oGKJyApI1Uv+Al8&Au9@6wOjLzmORa`KNJGtS7lC!n&_5i
z#g%p{SIjizA=|0^z$-iATunsYP`Vc9Ve#iY&Yr|u3G4L?*D
zD^bV943KOhw6T$$Vzz13Q$+2G(I>+dIPFsa#)cTdw^NKR%|OV=t|vkZdl;oq@R#T7
z2@{p&DcL-%ZKhOE8rTDPVt^bL&CE&*>Mj#pQY=Ax>}AKANZs~%IoEQIsM~j@4hKgV
z5kbWO@R4Ve)oJD7J8opZUK!$G@(h^fC|tXD)sJlr>d<+duws8YcDJa}L=*&BnTbW+
zNSki{8C%FPtTpNr@u&$D3V423d4xpHNx3LfdsMB1Jb~Yw?|uL!n+kY*Oy78zq7QDWyXt78Q^Zt)?|7fDJ)#9r`q=DfKYa+Pn1f@
zR3%QQQ5HNO1Gt>VrPGIcDPI*ioo1uW+FHQknxu|FZK=5j?fST|c_s!&uID
z3EXXQR821n`(bE{=w0);YA8+hU%WcKMlXJfKtj#_Z4`pxX_d#>Pv*$slMs<#vx}kS
zK16m$^45vb4<5RX!+OSEp}t^MRQX*M^x$dc`5Xv$vhJ@ZPgX0GTzvW|+&7f&)t@l*
zw&ePoOrLN~%|FE1HtkOu@*0gBN1h*dXV|psElAKI*z2&Fy$D-Q!(J$Dj5_vLI%0V}
zYLL)3s>#&%!20J_p4npM-|Ua7MtKsm3zs-2m8dTlyqfb+*C#sB
z |