From 472b8812c59eeadbadc6316bc09250a1cc007007 Mon Sep 17 00:00:00 2001 From: pooneyy <85266337+pooneyy@users.noreply.github.com> Date: Sun, 12 Oct 2025 00:31:00 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat(billion-mail):=20add=20billion?= =?UTF-8?q?=20mail=20application=20with=20docker=20compose=20s=E2=80=A6=20?= =?UTF-8?q?=E2=80=A6etup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - add environment configuration file (.env.simple) with default settings - implement data.yml with comprehensive form fields for service configuration - add docker-compose.yml with multi-service architecture (core, rspamd, dovecot, postfix, roundcube) - include chinese and english readme documentation - add application metadata and logo files - configure network settings and service dependencies - set up data persistence paths for all services - configure mail service ports (SMTP, IMAP, POP3) and management ports --- apps/billion-mail/4.6.1/.env.simple | 52 +++++ apps/billion-mail/4.6.1/data.yml | 254 +++++++++++++++++++++ apps/billion-mail/4.6.1/docker-compose.yml | 158 +++++++++++++ apps/billion-mail/README.md | 83 +++++++ apps/billion-mail/README_en.md | 81 +++++++ apps/billion-mail/data.yml | 24 ++ apps/billion-mail/logo.png | Bin 0 -> 11097 bytes 7 files changed, 652 insertions(+) create mode 100644 apps/billion-mail/4.6.1/.env.simple create mode 100644 apps/billion-mail/4.6.1/data.yml create mode 100644 apps/billion-mail/4.6.1/docker-compose.yml create mode 100644 apps/billion-mail/README.md create mode 100644 apps/billion-mail/README_en.md create mode 100644 apps/billion-mail/data.yml create mode 100644 apps/billion-mail/logo.png diff --git a/apps/billion-mail/4.6.1/.env.simple b/apps/billion-mail/4.6.1/.env.simple new file mode 100644 index 000000000..97f3792e4 --- /dev/null +++ b/apps/billion-mail/4.6.1/.env.simple @@ -0,0 +1,52 @@ +# Default Billion Mail Username password +ADMIN_USERNAME=billion +ADMIN_PASSWORD=billion + +# Manage Safe entrance +SafePath=billion + +# BILLIONMAIL_HOSTNAME configuration, Postfix myhostname configuration +BILLIONMAIL_HOSTNAME=mail.example.com + +# pgsql NAME and USER and PASSWORD configuration + +DBNAME=billionmail +DBUSER=billionmail +DBPASS=NauF7ysRYyt9HTOiOn4JjIAL3QcRZnzj + +# REDIS PASSWORD configuration +REDISPASS=zKLnZQr3riFpcS2lEy3MOtfncztaCGKp + + +## MAIL Ports +SMTP_PORT=25 +SMTPS_PORT=465 +SUBMISSION_PORT=587 +IMAP_PORT=143 +IMAPS_PORT=993 +POP_PORT=110 +POPS_PORT=995 +REDIS_PORT=127.0.0.1:26379 +SQL_PORT=127.0.0.1:25432 + +## Manage Ports +HTTP_PORT=80 +HTTPS_PORT=443 + +# You can use this script to set the time zone for your container. +# See https://en.wikipedia.org/wiki/List_of_tz_database_time_zones for a list of timezones" +# echo -e "Use a column named "TZ identifier" + note the column named "Notes"" + +TZ=Etc/UTC + +# Default containers IPV4 intranet segment +IPV4_NETWORK=172.66.1 + +# Enable fail2ban Access restrictions, specify that the IP exceeds the access limit +FAIL2BAN_INIT=y + +# Console ip whitelist Disabled:false Enabled:true +IP_WHITELIST_ENABLE=false + +# Number of days to keep log backup +RETENTION_DAYS=7 \ No newline at end of file diff --git a/apps/billion-mail/4.6.1/data.yml b/apps/billion-mail/4.6.1/data.yml new file mode 100644 index 000000000..2fae1e9b0 --- /dev/null +++ b/apps/billion-mail/4.6.1/data.yml @@ -0,0 +1,254 @@ +additionalProperties: + formFields: + - default: ./data/billionmail + envKey: CORE_DATA_PATH + label: + en: Core service data path + zh: Core 数据持久化 + required: true + type: text + edit: true + rule: paramCommon + + - default: ./data/rspamd + envKey: RSPAMD_DATA_PATH + label: + en: Rspamd service data path + zh: Rspamd 数据持久化 + required: true + type: text + edit: true + rule: paramCommon + + - default: ./data/dovecot + envKey: DOCECOT_DATA_PATH + label: + en: Dovecot (IMAP/POP3) service data path + zh: Dovecot (IMAP/POP3) 数据持久化 + required: true + type: text + edit: true + rule: paramCommon + + - default: ./data/postfix + envKey: POSTFIX_DATA_PATH + label: + en: Postfix (SMTP) service data path + zh: Postfix (SMTP) 数据持久化 + required: true + type: text + edit: true + rule: paramCommon + + - default: ./data/roundcube + envKey: ROUNDCUBE_DATA_PATH + label: + en: Roundcube service data path + zh: Roundcube 数据持久化 + required: true + type: text + edit: true + rule: paramCommon + + - default: "80" + envKey: HTTP_PORT + label: + en: HTTP PORT + zh: HTTP 端口 + required: true + type: number + edit: true + rule: paramPort + + - default: "443" + envKey: HTTPS_PORT + label: + en: HTTPS PORT + zh: HTTPS 端口 + required: true + type: number + edit: true + rule: paramPort + + - default: "143" + envKey: IMAP_PORT + label: + en: IMAP PORT + zh: IMAP 端口 + required: true + type: number + edit: true + rule: paramPort + + - default: "993" + envKey: IMAPS_PORT + label: + en: IMAPS PORT + zh: IMAPS 端口 + required: true + type: number + edit: true + rule: paramPort + + - default: "110" + envKey: POP_PORT + label: + en: POP PORT + zh: POP 端口 + required: true + type: number + edit: true + rule: paramPort + + - default: "995" + envKey: POPS_PORT + label: + en: POPS PORT + zh: POPS 端口 + required: true + type: number + edit: true + rule: paramPort + + - default: "25" + envKey: SMTP_PORT + label: + en: SMTP PORT + zh: SMTP 端口 + required: true + type: number + edit: true + rule: paramPort + + - default: "465" + envKey: SMTPS_PORT + label: + en: SMTPS PORT + zh: SMTPS 端口 + required: true + type: number + edit: true + rule: paramPort + + - default: "587" + envKey: SUBMISSION_PORT + label: + en: SUBMISSION PORT + zh: SUBMISSION 端口 + required: true + type: number + edit: true + rule: paramPort + + - default: 127.0.0.1:5432 + envKey: SQL_PORT + label: + en: Postgres DB Address Port + zh: Postgres DB 地址端口 + required: true + type: text + edit: true + + - default: DB_BILLIONMAIL + envKey: DBNAME + label: + en: Postgres DB Name + zh: Postgres 数据库名 + required: true + type: text + edit: true + + - default: BILLIONMAIL + envKey: DBUSER + label: + en: Postgres DB User Name + zh: Postgres 数据库用户名 + required: true + type: text + edit: true + + - default: BILLIONMAIL_ + envKey: DBPASS + label: + en: Postgres DB Password + zh: Postgres 数据库密码 + required: true + type: password + edit: true + rule: paramComplexity + random: true + + - default: 127.0.0.1:6379 + envKey: REDIS_PORT + label: + en: REDIS Address Port + zh: REDIS 地址端口 + required: true + type: text + edit: true + + - default: REDISPASS_ + envKey: REDISPASS + label: + en: Redis Password + zh: Redis 密码 + required: true + type: password + edit: true + rule: paramComplexity + random: true + + - default: mail.example.com + envKey: BILLIONMAIL_HOSTNAME + label: + en: Billionmail myhostname + zh: Billionmail 邮箱域 + required: true + type: text + edit: true + + - default: "False" + envKey: IP_WHITELIST_ENABLE + label: + en: Console ip whitelist + zh: 控制台 ip 白名单 + required: false + type: select + edit: true + values: + - label: "True" + value: "true" + - label: "False" + value: "false" + + - default: "7" + envKey: RETENTION_DAYS + label: + en: Number of days to keep log backup + zh: 保留日志备份的天数 + required: false + type: text + edit: true + + - default: y + envKey: FAIL2BAN_INIT + label: + en: Enable fail2ban Access restrictions + zh: 启用fail2ban访问限制 + required: false + type: select + edit: true + values: + - label: "Yes" + value: "y" + - label: "No" + value: "n" + + - default: Etc/UTC + envKey: TZ + label: + en: Time Zone (TZ identifier) + zh: 时区 (时区标识符) + required: false + type: text + edit: true diff --git a/apps/billion-mail/4.6.1/docker-compose.yml b/apps/billion-mail/4.6.1/docker-compose.yml new file mode 100644 index 000000000..274dc9be2 --- /dev/null +++ b/apps/billion-mail/4.6.1/docker-compose.yml @@ -0,0 +1,158 @@ +name: billionmail + +services: + core-billionmail: + image: billionmail/core:4.6.1 + container_name: ${CONTAINER_NAME} + hostname: billionmail-core-manage + volumes: + - ${CORE_DATA_PATH}/ssl:/etc/ssl/mail + - ${CORE_DATA_PATH}/ssl-self-signed:/etc/ssl/ssl-self-signed + - ${CORE_DATA_PATH}/conf/core/fail2ban/filter.d:/etc/fail2ban/filter.d + - ${CORE_DATA_PATH}/conf/core/fail2ban/jail.d:/etc/fail2ban/jail.d + - ${CORE_DATA_PATH}/logs/fail2ban:/var/log/fail2ban + - ${CORE_DATA_PATH}/postgresql-socket:/opt/billionmail/postgresql-socket + - ${CORE_DATA_PATH}/php-sock:/opt/billionmail/php-sock + - ${CORE_DATA_PATH}/rspamd-data:/opt/billionmail/rspamd-data + - ${CORE_DATA_PATH}/webmail-data:/opt/billionmail/webmail-data + - ${CORE_DATA_PATH}/.env:/opt/billionmail/.env + - ${CORE_DATA_PATH}/conf:/opt/billionmail/conf + - ${CORE_DATA_PATH}/logs:/opt/billionmail/logs + - ${CORE_DATA_PATH}/logs/core:/opt/billionmail/core/logs + - ${CORE_DATA_PATH}/core-data:/opt/billionmail/core/data + - /var/run/docker.sock:/var/run/docker.sock:ro + environment: + - TZ=${TZ} + - FAIL2BAN_INIT=${FAIL2BAN_INIT:-y} + cap_add: + - NET_BIND_SERVICE + - NET_ADMIN + - NET_RAW + ports: + - ${HTTP_PORT}:80 + - ${HTTPS_PORT}:443 + restart: always + networks: + - 1panel-network + + rspamd-billionmail: + image: billionmail/rspamd:1.2 + container_name: ${CONTAINER_NAME}-rspamd + hostname: billionmail-rspamd + environment: + - TZ=${TZ} + - REDISPASS=${REDISPASS} + - RETENTION_DAYS=${RETENTION_DAYS:-7} + volumes: + - ${RSPAMD_DATA_PATH}/conf/rspamd/local.d:/etc/rspamd/local.d + - ${RSPAMD_DATA_PATH}/conf/rspamd/statistic.conf:/etc/rspamd/statistic.conf + - ${RSPAMD_DATA_PATH}/conf/rspamd/rspamd.conf:/etc/rspamd/rspamd.conf + - ${RSPAMD_DATA_PATH}/rspamd-data:/var/lib/rspamd + - ${RSPAMD_DATA_PATH}/logs/rspamd:/var/log/rspamd + restart: always + networks: + - 1panel-network + + dovecot-billionmail: + image: billionmail/dovecot:1.5 + container_name: ${CONTAINER_NAME}-dovecot + hostname: billionmail-dovecot + cap_add: + - NET_BIND_SERVICE + volumes: + - ${DOCECOT_DATA_PATH}/conf/dovecot/conf.d:/etc/dovecot/conf.d + - ${DOCECOT_DATA_PATH}/conf/dovecot/dovecot.conf:/etc/dovecot/dovecot.conf + - ${DOCECOT_DATA_PATH}/conf/dovecot/rsyslog.conf:/etc/rsyslog.conf + - ${DOCECOT_DATA_PATH}/logs/dovecot:/var/log/mail + - ${DOCECOT_DATA_PATH}/ssl:/etc/ssl/mail + - ${DOCECOT_DATA_PATH}/ssl-self-signed:/etc/ssl/ssl-self-signed + - ${DOCECOT_DATA_PATH}/vmail-data:/var/vmail + - ${DOCECOT_DATA_PATH}/rspamd-data:/var/lib/rspamd + - ${DOCECOT_DATA_PATH}/postgresql-socket:/var/run/postgresql + environment: + - DBNAME=${DBNAME} + - DBUSER=${DBUSER} + - DBPASS=${DBPASS} + - TZ=${TZ} + - BILLIONMAIL_HOSTNAME=${BILLIONMAIL_HOSTNAME} + - REDISPASS=${REDISPASS} + - RETENTION_DAYS=${RETENTION_DAYS:-7} + ports: + - "${IMAP_PORT}:143" + - "${IMAPS_PORT:-993}:993" + - "${POP_PORT:-110}:110" + - "${POPS_PORT:-995}:995" + restart: always + ulimits: + nproc: 65535 + nofile: + soft: 20000 + hard: 40000 + networks: + - 1panel-network + + postfix-billionmail: + image: billionmail/postfix:1.6 + container_name: ${CONTAINER_NAME}-postfix + hostname: billionmail-postfix + volumes: + - ${POSTFIX_DATA_PATH}/conf/postfix/main.cf:/etc/postfix/main.cf + - ${POSTFIX_DATA_PATH}/conf/postfix/master.cf:/etc/postfix/master.cf + - ${POSTFIX_DATA_PATH}/conf/postfix/conf:/etc/postfix/conf + - ${POSTFIX_DATA_PATH}/conf/postfix/sql:/etc/postfix/sql + - ${POSTFIX_DATA_PATH}/conf/postfix/rsyslog.conf:/etc/rsyslog.conf + - ${POSTFIX_DATA_PATH}/logs/postfix:/var/log/mail + - ${POSTFIX_DATA_PATH}/ssl:/etc/ssl/mail + - ${POSTFIX_DATA_PATH}/postfix-data:/var/spool/postfix + - ${POSTFIX_DATA_PATH}/rspamd-data:/var/lib/rspamd + - ${POSTFIX_DATA_PATH}/postgresql-socket:/var/run/postgresql + environment: + - TZ=${TZ} + - DBNAME=${DBNAME} + - DBUSER=${DBUSER} + - DBPASS=${DBPASS} + - REDISPASS=${REDISPASS} + - BILLIONMAIL_HOSTNAME=${BILLIONMAIL_HOSTNAME} + - RETENTION_DAYS=${RETENTION_DAYS:-7} + cap_add: + - NET_BIND_SERVICE + ports: + - "${SMTP_PORT}:25" + - "${SMTPS_PORT}:465" + - "${SUBMISSION_PORT}:587" + restart: always + networks: + - 1panel-network + + webmail-billionmail: + image: roundcube/roundcubemail:1.6.10-fpm-alpine + container_name: ${CONTAINER_NAME}-roundcube + hostname: billionmail-roundcube + depends_on: + - dovecot-billionmail + - postfix-billionmail + volumes: + - ${ROUNDCUBE_DATA_PATH}/webmail-data:/var/www/html + - ${ROUNDCUBE_DATA_PATH}/conf/webmail/mime.types:/var/roundcube/config/mime.types + - ${ROUNDCUBE_DATA_PATH}/conf/webmail:/var/roundcube/config + - ${ROUNDCUBE_DATA_PATH}/conf/php:/usr/local/etc + - ${ROUNDCUBE_DATA_PATH}/php-sock/:/var/run/ + environment: + - TZ=${TZ} + - ROUNDCUBEMAIL_DB_TYPE=pgsql + - ROUNDCUBEMAIL_DB_HOST=pgsql + - ROUNDCUBEMAIL_DB_NAME=${DBNAME} + - ROUNDCUBEMAIL_DB_USER=${DBUSER} + - ROUNDCUBEMAIL_DB_PASSWORD=${DBPASS} + - ROUNDCUBEMAIL_DEFAULT_HOST=dovecot + - ROUNDCUBEMAIL_DEFAULT_PORT=${IMAP_PORT} + - ROUNDCUBEMAIL_SMTP_SERVER=postfix + - ROUNDCUBEMAIL_SMTP_PORT=${SMTP_PORT} + - ROUNDCUBEMAIL_REQUEST_PATH=/roundcube + restart: always + networks: + - 1panel-network + +networks: + 1panel-network: + external: true \ No newline at end of file diff --git a/apps/billion-mail/README.md b/apps/billion-mail/README.md new file mode 100644 index 000000000..c1c0c6aca --- /dev/null +++ b/apps/billion-mail/README.md @@ -0,0 +1,83 @@ +
CcapCU zz|b^|$x5K$nDBHHy8lW-2R6We@C2hQAhn>W??Sy?<8!xDB&!T&v(tjtlZX?4+xE zvE>IS9~1w2G65_{m-xrWDj4>Hl1j)>?ijy%Uo?7Du2FmvV*W!> tvkqs96`fy2}Lab?o<+_hJ|%-gM^ z+bwBR9CACg+N*``1$nG6wQUYjF4n0)Xmf8NT!^@t@22Kfm+3&%4kxi~*0yE|3rrIW zfa93!AX+frUiHoRuBHk>_UnLfihk?to^ySB+dIUyOk|k2*7_y U08odujM}XTb<^@civnIvLC%6&67DFOfTxGIPW?r%Vw#UO}A8hr2$6p%Y}NBUBZ&Z0V}iqAgZ zSt;0ZCV4gQ3U3#^N{pt=?+_Tex&3XTJF gyJi_EK2hD-zGZvXbAkQ zytv-9!*^eaX*I+)90oRapZ<5Od049|#Rau15rMVre#)~o>QmCwWklmDpDuMaJ_qHr z5^Aqk%XixaxGqL&Y@=4QxjCf0LFt(Y6z{q4g26z)A`qIv3Y+Yem}>E;0NJ3z(N#dg zZ*Whn*09*j+D6WniII<-ReT;>h~JRNNEOlAcSm#Dd+I5Jf3nXYFelT|2_3JOtmFJ} zN^PAhH7!}pJbWPHv)m>g}2jN$+N4%H+LIFzq5a17%DRQU6*}&!&>v(NqA&W5=GH zQF|SdQJ{?Z2kdio(Do_OD)>}EMxK}9RMPS#g(#WEfN|p$V`+H5&M^0udKT5L_u>QL zZ67VLh|IHoGkbC{k%@Qg%e}>XPB+(d?g-=3DW{~LK)jDiU=HK;%ZS2WH=|n0OslFd z7fG*cG~+R6n##ag=F~aK$`KOzuu$8sYJk>X!r|LZSVUg4sC{75C!ZW-{z)SXX!R+J zJS3Hw< Cl&&8BLd#bgV8T8^Pj?hR&nbVNVTZ-bYJ3Y>D-84gI6sR+ahYdcoSznW%wmjq$ z`%Zlg8_q#9C<52=0SY(2B8WuX<{}k5_}GkPG JT&< BW+aLeO^RvrjhEHewb)x`ht;Ua1W<@?*zElZa^gnU`@4li6K)qs;; zmHQ>(9~73fc#Cyz;vkFk)3&Xr&k>>bk*S2Qa>AhXH=J(x?)!<8k4IZ(JU`ESgY_Wy z9DmSQec<<`*W|V>n1O;t#be;hQB!-a2Y(+M<6c@Mssv+8ftbj4t~zvh HcExgL;l95drw z(O{Hv=?SwyoRCl->fw1^)WolFlpaaFf5_L2SuPncP&kNyvb|{ $GOW;M$Z*MuvZD`x&H7jpgH7>DTV|t5GGDAl)8O3lOk3*sncYq7et&eAe&Tc z+w sY=@SY<6O^$igi4^_qQ+hlrK*mjH=ZL7j~6pT0^k*ufQVj8V@N=iT^_rpAxCCNA+OiJT_`a0 z@)bEGfk2(R5+d`7GqNgQMe9;AUcFiCe)IkI>HB*Xyq|e0r0*6FFOGk0X?qW<5{lLA zx^ed>xL^M0DDL{eI% @FQCN;>=xrUZ(#h}$9k(EbX9s 53dYH`*9d^TJ#kH`Ay3@YtL=*64lp@rJg2^B*Am^ zz@Ybm2Mr?33O{+b@9j`ByJxXqS%Mo?VKeoN=C|5G#gE7+DNdFMmDx5g)DP8-@8K6h zGQV*ai kzA&7t4{i z4*y}-U{?^bh_~R%jZLlA-n5>}-AGL;4Ld&wW4!pTYIo6cwsWIiR2Ro$Etu@w T(=$e6`hR=Hf6Z{F&s(hxumj?l-wy@6ume{C9C%cA017+>^z#X zvLCPAyu@F+HfHp@I}&I1AkZRc5WO`*%lLU;lebXdZoTVnsi~dyuOf4^O^`}2LlY>A z^o(As&*M*1X{(6zv^7?wO;A_sNO;4i{yZ%%*bdk4GdKNNnI0&GeMhNc@o*#smS2J} zlIl^bV}x4}DrGBOZ}y!KOk{r0y7X}3z3E%zTrZWtuWKI~r@|wpM{CrLxSfgJGh)iO z%%Y^I_EZDV79 JK1D_C||z(72+J+?BM|uFi*qt<)%82+UHy%9$$SRi1D- z5xP{E?U&iO+VgsOivgDv0NnKW4P5ZkMYxIgnkg2vCjP+tx)Z%VY<_x~&`Qb!Nz2{1 zn158-U5PitCUa~4WNO2wjxHs=qOzFB=fsTl*bN%<68lQ!7lG*=Rd+Eold5iReeFS3 z;k%3a;T@PYAXC!R;omCeX5j_qh61V{;&OS4W=7%R95GiVykvk%8)X;-C3$iZTyAAu z8dK>;UF$wq=woy4(}5L!6rQ4hs91k*p~&ZybMOP3#Tb_-0^?~zZ@ b7i1m15-y-rgGxv*wHl5*p%S)o|0AJe` zYR(t$E`sfU&%xhyxW^5qZ4Gcmo8gB~k0*YbX7BmP=ftt$JY<)nKbmfT;(~e%->kQ~ zX=kzBq*xtoiSyY7u;EPey`RwAMYCc7O8r#RW!{ls)*b|R(n!cSlrLxrDnt|No7q9Q zr7*!fQ}p_Eu7eTXev3B$P>hC?KomzRQ$PRCk6>D{0UOKmdmNogiY$IpJB=ne`1p|$ ztVI)&L9zOt16ZXp-DWt4@+w~&j4IDO7(Ccsj-uN6wxKSXQ=QZ9 s^5GRCXs9I@(Rnzs#?bfimzc&NoN< zQ05>8^?=vdZwCVxNm={ChP8TrmrP>Jh2t5Q-F?MWoNjX(doF8H%B$H`dV}CLIEk#5 z<$;6`kB$Yyb3pGpS30QW!MsChoDR+ACc^xwQDz8(Kyw+6SwH&jbO+oXGDSFN7GKe3 zC$_v_V*V 5RnQv+TPBw{JC$7oL(k>2k@}dB@jv E(goF@4J~Q*+uj~=ZsKM^?j&Z*%&0Jr+@UCZoNGUJ8@;U zTZy_*l)F)GJo{KCp9Sv)&|zPfOAYQ&GJZzLWm^s)-Rp#m&0CX(2uk@*g+!K35rO#1 z8nZ`g$b@1dHS=gO9h-9|J356zBJ3j)IEby~HVBta{oRq0eo@BIrqOH+;_&qFN8~MJ zDGc~zkLVbX;vS;uaIuDu)?}5L?+^AVS)_ONM S2aoTW`#}{z$d6u8SLjP( zK4qF9=Cj1KEvF#%lgZ9-vA&{7vdhMyDTA-qXOpkk@R+%jlz%s{$Yw8OO`KM7CC9|{ zvMzQMWQkq;d(TnZ)>w3uSb@q0cz(cV19@r5YQPX-k%CS;Am0Z#9>L`sq2dY^Lr7c^ zJuyU?G(@)t0lj#nvc&MNpG-=stZwZ9l~T_^M427F)Na6*m*q{_BKw>m7V>h>G*(_O z&+PI`yP0b+K&T(&oRg&f*Xvo0A}LBmV6KgZ9DQ{-B-l$_IDM~A|I{i-rtu)c1M3c# zf!t58>K32Ap!~_R5zx16e g1}31$9T`Z%!84D|!%^F~OWNrf7Z zq&PS(vx$y9CP!|`T26-P+IHhK!m7=cA6_WL4}S^#Gdbuu$D(d7xt`KYmqW~e*&H_r zcLeH8$Yd&^b;S~Je5ml<)toF~PrUf}adHypN0|T!%Wl#h63ce!Ue@v%WPJ8vl5CcC z+^R{aMI+%t=` @s>|LV?k0XXAw6Fh82hic~| zm6|m5Zp5O&bWP;C>-aKEm9w$grMSE369CO3 Hch1I}0wXbz0HOT9<=USs z1V}uL(tbtF%!W+DG`%P-c|_*Jl$E7LNK%5EN9Jau0uPQLzVlh(^b-i0k7S3GqIow! za|b=C4%;J{!NvQ*4rAI#lCuY}V1AR{Nl%gB9J8;R9FLK(2QH4M DreCGm^{Vpyj>;r3^%j}a-cJfRuVK?Q-9C(aLW?edW zxwZq=md =mi>4_kua8!lz@KOSLJqY{ zp@!wi^(k0%FQVDAMQz)pQug&%-h}730X2iDC;!;I!`f=mzbS8f%XKu0nxmz$R!7pw z6uG#2W2Rd4Yo9N)zxAc}5Z+3oxV1^@ r@m%&bIY#!$~*uyu8cR^k(7J5%D 0& 1kc8JR9bElY| zB`Yvi>I4%aEkDs(pp2xvQ?53Tg@$Wgx{CY$^)!Mx{1|^RH_%cav38-;TupWG>qupv z@X_89Tg2jxBFs4siSRZk;;@E=1kCv}=g>+nC!B1P3|pGeTZz_O>~l$4a*UYZ9^@O? z{YU=3mN>|NCMH(Iv_?~`F3($a{ywX0I*vP->=|<;^>`PAl}1;Uwxbm4Z-$}XoMY76 z{gGzG!^ka*6Ub~&p=o&})8BAw&1nuGlQZPHy#IWa6(1V4-W(^*Sh2$AEJ)B@DkOpm z?IKZns&idAo`Ff)$GLhnw!fj^kn)>aexNFniT>(Y^&ePSo?%${^DBQyM3HdBJny;I zEc>q#P$4;=8-zOo?MXC#f;r9P8TMK78kpnr4{t;1dJMXZA-QWqecg2ipqEckj3xeb z;LA&djKtjv$G8V_I|xA0_wBJX@me%}J #%zpjAJGao&P+k_+B& ZO04DaG9fo6GM;b{nmBKNf$}+1USg?sG*vs*g5QiBO zdABbbiP5fv%&65gDl$T1U>4Uk@gXF4K27<&Awxoz&q<&I7j;!OOX53G?wPZLDSO@X z>-tf8K^Kj!IqK>u0|WIoVD}=s1xC|3CuNeHMTswGNx5)XdSLU8YLI0{$tmx4eF*99 zN14-hVJ!tzl-Fuxl;Mr#%4|icb)$ U;z2yFOQ Xut$L|L*zyJTPalpO2m?#W~|o z?u3q>5 0I(}%RgWwuGds_)8UCi@aO6|Y2CK-3jomWFBWdag{%iHQyKerzV%K;T zd3%N`@jSd4%5q8^l8nLufgVm5WP^@U|JYF)Ae`#Rl8zSyw%9m15ZqY?A!1fP33csg zsW%l#T=W<8xuqga7A(;V;+ihSG|FHr+g}%G?v32q1~IIk^uZlB9tM`L2u=TpstZP3 zD9%Mle0my~h4-R-A)ikl0^2Wop=_R} #DauG_zM(73R3vUh7rq6@==DxyD6(_Y6hW{#z<^167P{U{X^<)r1xt1==unM$b7~oUW|zxy zz>_*e0?&*nmQE+cTnctuCi)=SMNP`x=g(GLr&nh!ve2v3*(}od7xGpqGXayL@hh4r z9z^64le;?F3_#f+bnuQmwgSm9`RC*`A>7Ul07ADo HM{uaf2a$1YrHFq`>pYX{+_1^ocZNApWY&|i=IA?o z+o+>1u9?b|^wlD# %|O@YpTYP8ghKq>UZ+qyB1Lnt0d4W)9yJ zA{j*_u%hhY);{ub#AV0~blKPRHTZ^PXd~@cNpry@a30Z01-6(h((B1^tml(2j7|#U zP)HY;7&NIjWul0jGvtyOAW!SAg6G5; i5Yk 7pou*ST)Dtw=nkT0;tR`pCAC#(9`jQWCDK0bLi)yF9U`pE= zj_j7n3biEX(#0QtVS~wh^MBMK=|nRF_cc{ReSgwz@Z=~yaHlW$saPzhE^}qZRxEJn zZnKf}7mr_;SKyr6KLN~B(>oK6ryFLtkXWlIll<6|RxaUEe?^r+e7pl+3+sA^PAMEv zx^w%E3J};W8El>$#XoU_!Z;88(vtJk%}q1DWK4YN(zw7r**3qxh%O;|RH6xV{q7QC zL;B{-bw8?;=zndfzf$Wnr_eGh&W}oTn_&!Wx+uw8kgVihZb?Otb66BIa@ya91#l)J zG9`uosZ}!aOj|`AJR+i$SHLHF#>X}cLr83mVnfaS&cVbzIVlgZ$1gCo;Sfw7uQDw3 z7@7Zl+y>}T0^o)}%6_%x0~PG+cl|DkZsYHo7Lqo7|2&FKk*sT@h_DWgElUn8Y3nSx z>_HSsxcrZXBNzPllA6V5us!z(ZnF4O>+3|@6BaY-7Fl$m+`y|Zpgv_&tb)<*NG*tc z2k1ip_!~$tE4eH-V;;Sl{}6W2{~MvviFdOUVJZ2jB)Y0R_X%%})WMR^>H@dw{G!VO z)@2kk^d uC7whx6dRw 9+lO{9vLE}k3u36X*@a)5LI+L_rSK-d4i6t#jM%DFnq1rQ zKciNZ>9#EJ4kwJqlDN(lBupw!L~Ve74I!Vjcda?~H*8XQQUR{Epn{WjK~8v7G? zZlV>3p;96-Y#|+CtQdpcdqD3ZkUJQ#XHtXBOX9i%U})i-LB5+13T>M{j7pdE(iIrD z@`%1INXpn+a9x@wiCd|cDsVULojRDWUh*c^h)DY=nj9%mGNo!Qcv^Hi&VZEdJBRuf z@pbmqnNP-Sm&%3ZjS+sQXkVDk&e7+t3u|iY kf4Xw> z^#gzAHn~Vi!+9gQ;%ict8oG=hQpb*=b!|_}t{PWRe8Gx=d6MXre_E3@pL)C5sXXjN z{-BtGF|Qg}$cv$)l#0EFaoA4hk>Ak;HH4>T6EMzxdn1yo9!!+ftZ8q~)_hYD@R0#*0!y+SG7Bh36lI1zxvHjv3ok3)7`>Do> 9Wmeu%OjP}1VvbERNdY(t-#ke8ZHWp`b+ z`8BFrCDqmK=7x39C+nHH*-+|vp;{tgOJ26+Ax_JGHvs`4ajFSc4l|m`$PuN+HPZ&Z z1XZ(^FopBkO{rJ$pWC2rxQ %&uw`)y=AG+tvRV-5i8^ss}>&5#YgDgQsXE>wsBa0i*U&tX|d`{BMyS!Sj7FK zAsu&6NTg^LSpRPp3&A7B#wVP)Wi7H%REa5X71!Y~Fs9uXHc}{`Gc;yWbGU2_sA^?j z%^4# T&hz=8YgNVvz_=e!ue9jei!5|n}DnpZGv#2Y_- zZ #C2gI7QyS!Z^E7a--HKui6AP`fzjgDt2Y$N@K? z?{YA2f3oq_+T2VQay0}_JOwfc-jc6>>z|k1r;q>iI)rkxUhJ*HOJW@>qnei`_=sSV zMa28&Zhlim>;@?!JS|0DKAIQUBGcLTQ084uK=-PUacbK9qGKEDX~DV>C{X^FFpD>J zWA5B}y;YF5^Kpcu`-W%NrzsXKozJRNWBzpElZ8*=A0y%zHIG?F6T#@*MHCB1Tx>tR z;kN4sHSao;>upy(wH}#3udmN`9TnWRKEe9V1T!9pG|sw4wD*Koqt8 KRo_>&Spsl6h&_QRp=$Ss8@>Vm>JJ(#m=2i;tv@$OWk@U6Ai9`p|) zimMqE;hCc*D4LP$+V<$1hCiuqLWQ+7($wL#%Jd2?+(IR|YqgHb)b~px?;**Liy0J; z&%dlk4Ejdmz3}QkQ55h*w13uKRk#(w^sU&fDiZ1^!kOiewj4Ki`5-fjzC;(PW5J-H z@HKUj;-k8U&TD|0FB*~9qxGu-cBszRrw5j=lf?f+@