From 2af1d6f159c54c895a120a143e8e094fa60ed3c2 Mon Sep 17 00:00:00 2001 From: Ben Thorner Date: Mon, 22 Feb 2021 16:38:27 +0000 Subject: [PATCH 01/12] iRemove redundant Docker tasks Nothing and no one uses these. --- Makefile | 54 ----------------------------- docker/Dockerfile | 80 ------------------------------------------- docker/Makefile | 33 ------------------ docker/VERSION | 1 - docker/entrypoint.sh | 33 ------------------ docker/tianon.gpg | Bin 61602 -> 0 bytes 6 files changed, 201 deletions(-) delete mode 100644 docker/Dockerfile delete mode 100644 docker/Makefile delete mode 100644 docker/VERSION delete mode 100755 docker/entrypoint.sh delete mode 100644 docker/tianon.gpg diff --git a/Makefile b/Makefile index da06fad25..48ba3342a 100644 --- a/Makefile +++ b/Makefile @@ -7,16 +7,6 @@ APP_VERSION_FILE = app/version.py GIT_BRANCH ?= $(shell git symbolic-ref --short HEAD 2> /dev/null || echo "detached") GIT_COMMIT ?= $(shell git rev-parse HEAD 2> /dev/null || echo "") -DOCKER_IMAGE_TAG := $(shell cat docker/VERSION) -DOCKER_BUILDER_IMAGE_NAME = govuk/notify-admin-builder:${DOCKER_IMAGE_TAG} - -BUILD_TAG ?= notifications-admin-manual -BUILD_NUMBER ?= 0 -DEPLOY_BUILD_NUMBER ?= ${BUILD_NUMBER} -BUILD_URL ?= - -DOCKER_CONTAINER_PREFIX = ${USER}-${BUILD_TAG} - CF_API ?= api.cloud.service.gov.uk CF_ORG ?= govuk-notify CF_SPACE ?= ${DEPLOY_ENV} @@ -79,50 +69,6 @@ freeze-requirements: ## create static requirements.txt ${VIRTUALENV_ROOT}/bin/pip install pip-tools ${VIRTUALENV_ROOT}/bin/pip-compile requirements.in -.PHONY: prepare-docker-build-image -prepare-docker-build-image: ## Prepare the Docker builder image - make -C docker build - -define run_docker_container - @docker run -it --rm \ - --name "${DOCKER_CONTAINER_PREFIX}-${1}" \ - -v "`pwd`:/var/project" \ - -e UID=$(shell id -u) \ - -e GID=$(shell id -g) \ - -e GIT_COMMIT=${GIT_COMMIT} \ - -e BUILD_NUMBER=${BUILD_NUMBER} \ - -e BUILD_URL=${BUILD_URL} \ - -e http_proxy="${HTTP_PROXY}" \ - -e HTTP_PROXY="${HTTP_PROXY}" \ - -e https_proxy="${HTTPS_PROXY}" \ - -e HTTPS_PROXY="${HTTPS_PROXY}" \ - -e NO_PROXY="${NO_PROXY}" \ - -e CI_NAME=${CI_NAME} \ - -e CI_BUILD_NUMBER=${BUILD_NUMBER} \ - -e CI_BUILD_URL=${BUILD_URL} \ - -e CI_BRANCH=${GIT_BRANCH} \ - -e CI_PULL_REQUEST=${CI_PULL_REQUEST} \ - -e CF_API="${CF_API}" \ - -e CF_USERNAME="${CF_USERNAME}" \ - -e CF_PASSWORD="${CF_PASSWORD}" \ - -e CF_ORG="${CF_ORG}" \ - -e CF_SPACE="${CF_SPACE}" \ - ${DOCKER_BUILDER_IMAGE_NAME} \ - ${2} -endef - -.PHONY: build-with-docker -build-with-docker: prepare-docker-build-image ## Build inside a Docker container - $(call run_docker_container,build,gosu hostuser make build) - -.PHONY: test-with-docker -test-with-docker: prepare-docker-build-image ## Run tests inside a Docker container - $(call run_docker_container,test,gosu hostuser make test) - -.PHONY: clean-docker-containers -clean-docker-containers: ## Clean up any remaining docker containers - docker rm -f $(shell docker ps -q -f "name=${DOCKER_CONTAINER_PREFIX}") 2> /dev/null || true - .PHONY: clean clean: rm -rf node_modules cache target ${CF_MANIFEST_PATH} diff --git a/docker/Dockerfile b/docker/Dockerfile deleted file mode 100644 index c9464a30b..000000000 --- a/docker/Dockerfile +++ /dev/null @@ -1,80 +0,0 @@ -FROM python:3.5-slim-jessie - -ARG HTTP_PROXY -ARG HTTPS_PROXY -ARG NO_PROXY - -ENV PYTHONUNBUFFERED=1 \ - DEBIAN_FRONTEND=noninteractive \ - NODEJS_VERSION=10.x \ - GOSU_VERSION=1.10 - -RUN \ - echo "Install base packages" \ - && ([ -z "$HTTP_PROXY" ] || echo "Acquire::http::Proxy \"${HTTP_PROXY}\";" > /etc/apt/apt.conf.d/99HttpProxy) \ - && apt-get update \ - && apt-get install -y --no-install-recommends \ - apt-transport-https \ - make \ - curl \ - git \ - build-essential \ - libxml2-dev \ - libxslt-dev \ - zlib1g-dev \ - zip \ - rlwrap \ - python-dev \ - libffi-dev \ - libssl-dev \ - libexif-dev \ - libfreetype6-dev \ - libjpeg-dev \ - liblcms2-2 \ - libtiff5-dev \ - zlib1g-dev \ - libpango1.0-dev \ - libcairo2-dev \ - libmagickwand-dev \ - ghostscript \ - jq \ - libjpeg62 \ - - && echo "Install nodejs" \ - && cd /tmp \ - && curl -x "$HTTP_PROXY" -sL https://deb.nodesource.com/setup_${NODEJS_VERSION} | bash - \ - && apt-get install -y --no-install-recommends nodejs \ - - && echo "Clean up" \ - && rm -rf /var/lib/apt/lists/* /tmp/* - -RUN \ - echo "Install global pip packages" \ - && pip install \ - virtualenv \ - awscli \ - wheel - -RUN \ - echo "Install Cloud Foundry CLI" \ - && curl -sSL "https://cli.run.pivotal.io/stable?release=debian64&source=github" -o /tmp/cloudfoundry-cli.deb \ - && dpkg -i /tmp/cloudfoundry-cli.deb - -COPY tianon.gpg /tmp/tianon.gpg - -RUN \ - echo "Install gosu" \ - && curl -sSL -o /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$(dpkg --print-architecture)" \ - && curl -sSL -o /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$(dpkg --print-architecture).asc" \ - && export GNUPGHOME="$(mktemp -d)" \ - && gpg --import /tmp/tianon.gpg \ - && gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu \ - && rm -r "$GNUPGHOME" /usr/local/bin/gosu.asc \ - && chmod +x /usr/local/bin/gosu \ - && gosu nobody true - -WORKDIR /var/project - -COPY entrypoint.sh /usr/local/bin/docker-entrypoint - -ENTRYPOINT ["/usr/local/bin/docker-entrypoint"] diff --git a/docker/Makefile b/docker/Makefile deleted file mode 100644 index 949b58b7b..000000000 --- a/docker/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -.DEFAULT_GOAL := help -SHELL := /bin/bash -DOCKER_IMAGE_TAG := $(shell cat VERSION) - -.PHONY: help -help: - @cat $(MAKEFILE_LIST) | grep -E '^[a-zA-Z_-]+:.*?## .*$$' | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' - -.PHONY: build -build: - docker pull `grep "FROM " Dockerfile | cut -d ' ' -f 2` || true - docker build \ - --build-arg HTTP_PROXY="${HTTP_PROXY}" \ - --build-arg HTTPS_PROXY="${HTTP_PROXY}" \ - --build-arg NO_PROXY="${NO_PROXY}" \ - -t govuk/notify-admin-builder:${DOCKER_IMAGE_TAG} \ - . - -.PHONY: bash -bash: - docker run -it --rm \ - -e UID=$(shell id -u) \ - -e GID=$(shell id -g) \ - govuk/notify-admin-builder:${DOCKER_IMAGE_TAG} \ - bash - -.PHONY: bash -bash-hostuser: - docker run -it --rm \ - -e UID=$(shell id -u) \ - -e GID=$(shell id -g) \ - govuk/notify-admin-builder:${DOCKER_IMAGE_TAG} \ - gosu hostuser bash diff --git a/docker/VERSION b/docker/VERSION deleted file mode 100644 index 0cfbf0888..000000000 --- a/docker/VERSION +++ /dev/null @@ -1 +0,0 @@ -2 diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh deleted file mode 100755 index a57515244..000000000 --- a/docker/entrypoint.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env bash - -set -eo pipefail; [[ "$TRACE" ]] && set -x - -if [[ "$(id -u)" -ne 0 ]]; then - echo 'docker-entrypoint requires root' >&2 - exit 1 -fi - -if [ -z "$UID" ] || [ "$UID" = "0" ]; then - echo "UID must be specified as a positive integer" - exit 1 -fi - -if [ -z "$GID" ] || [ "$GID" = "0" ]; then - echo "GID must be specified as positive integer" - exit 1 -fi - -USER=$(id -un $UID 2>/dev/null || echo "hostuser") -GROUP=$(getent group $GID | cut -d: -f1 || echo "hostgroup") - -if [ "$USER" = "hostuser" ]; then - useradd -u $UID -s /bin/bash -m $USER -fi - -if [ "$GROUP" = "hostgroup" ]; then - groupadd -g $GID $GROUP -fi - -usermod -g $GROUP $USER - -exec "$@" diff --git a/docker/tianon.gpg b/docker/tianon.gpg deleted file mode 100644 index 415d549079b141d4bf41be213006657b699ccd8b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61602 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

4Ph;HgWP(l~$U*-rvJK9V^;$ ziR}@~b+o#AZ3(s+_kK(5|HfBz3Krj6?qL`xvpaJyU`^HF0;lUZ3>vKqvK(+Uw>P~U ztBXy*5>GMd#*MLzOjg69E@Me+Q`YQG{FOMSwC$k?0j)XM!A^Ev;2B!{&a|BnAb<-J-6u>7qGpt7!MY}EDY4PK%#Ij-}bpx+kDRI=XCRscKP zQaI)JXHy6VO#rFUePD#(4?TG0S#Ux-pMm{<;_+YFqj-(*#Q{CYDL@Vlq7RdPB>``7 z5Bv?w{XQKXSJnjLloV=77K1z58v?NT`^-l;jy zSTci)b|_69@7!OG9O^Ke%&-dhk?X8^!Kh=oH_E@jc)XPV_z^5g392&}nH7Nqpo=AR=PuGSOqr^Tz6wWI1`bZ`VVM^ivP!Ek+nC;AHuqwluwq>jw_Mw8;F z$#wOE{#_D)P&4d4j=y{c0`_V$(V}EZ4 zr$!AXRwh3+ zmT-gVAfDu`Sa3b+#O|;weeAw7ACfm0la1O3N^IWs;wVZy@*FQ*YMqUHG3eERZnra& z=m^S4DsG#mwNGToqhRsK@ytd>%^-9MAI3^I1@F&4A5Pp|= zRIn#k@n%R~OX|>6g3co?$T~|NFP_hs+u9ZhRk2@GE?V#zSM{ZOW%ePSasUN!7hYca z7$df=#}1i@i=~#V=0maHxb}uyb13#EN|KFhHeE#Jb6|DtB~E?EorIe6U;T)mCD6I? zn+<9>0VVSjAMv~;RskL?KK8)4v~?hbuppx9-9{~1bJ4oM#bu# zWvucPisNvu!j4_PIkCwfbTGu!VJ%d-_(|*)TY{$B#>cv(f#-BK4K4v$uiX<7N)H(o@Am@vnjnl#8IPTsX z?A#0V=?+*pq>(Dp1=1yE9XZZIq<~u{$|CPHov2QV6lVfj-**dE9DK3Uf|s&zMxYnU z4M~yfx+OD9sg&7d$ZkaU@IXwoG6#0+{<>+C%z32+vmS%UwjeyuhN5<3RQX4GAQ+^Gt6MC@waKMm%R)uG8q7 zaqRQJ$O;&;@HW62Yu)R!WfWgmIh(WvL^m231hlu6CTYq z>DS0@XjdKcNGglvAoj9ni-@Nqd4;gEH)4}li5xp~e(&i$JKD5%A}pH-XzeT^q4Xph z-_Gq(FkrBHJ-%<;8T4nuaGO`uZ9&^7Pd_xTfaeSbTF;m+9;L3d+0`{(#DwZTB`HF3 z;MIBR%L&|RCbH23iZh-XEUFL2@!)_hx@3SnHYo~!8_D3P>`aW7mF8Ro?y(y$Zv)5VS#@41z4o>z~rp7M+zqt=Z_+On{DOB5RNgoXG{mSGlrnLFKT%FL4lwSV1 zxnQRNWn+NhX%?8Is68Z|KVP{BaM<(qFC>;9b&5~*foC_nZvY8z{QRBj$giNiSo1t= z+ZB8zm>7{!P5~l<@Amm-XA{gx9zV_Iu;3k-!@g}k|JX9YLGE_1dtADmEiqrD=Sgs& z9u;KN(IN({dvps!t^M;SaMA^6_@iqkm9dE81RoD@%CVR%B9zkk7Z5Fyf2Sm zR&|07<}K^$4L^Z6fP0dai|w4=^vXGGk(P4B+*E70ZJidfx7!zc!%MyyY!5~i`F&q~ z!HS}HXeyNKkZ<)evl}pK#{sE3_t=h_Q;4^u+^gV>*nc1hy)S3wSfX0-DZlB9DDJ=t zF=$J(LJ-_Nvx>+%VZjWFLc%;1JIMMbaBmG+`$pPJP^fo;Peh>uepY8sX{-CI3{}Ce znTNe%MK}S}=Eqjw@L1Ptvc5_C6OAL*)6f_El0)yN;WA`8E{ocXH!b!pF}4t9mJ1P6 z<0^sX`wFRYL=oxz{lM?*Kzhl`THgdfvUt_TxM~PZs&mn&gHw(oZK{NYg;yO?7s8bi zEETC{RM5n2;UT>GLr30^V~qt=aCk%c808fmL#A6>UN*m zxC=CM=hAdpyg*hEA6J+sOY`mjEMfjjfUIZ`0UO7T=U$XmELKm8RfDNwEftL4`%Bor!0_eg^1SjW zp6SNU;x1mo=p@(T`{!TNuW2yUL}Oex72>C*S(US+c9X(a>BX8pRxpTgTU8mTT!JC;4p_ zKKEzt2O|2P_9bG!>+9d-mvY6Qlvo%4#N)pNXweW6(5<+#%YR?|sN++NEzS)-r7?Q8~B^OZ~+CD;L5ruPST!4n% zU5P1)Kjw1-*Ft^?;=|v2-j}>kfF1atG(ybIOV#wmD2Jj?S4A_j_6vcawS-r@%Aw3E z*y3zhnxCF8v!4Mu+f*WK4(4j=Wrfy@AId*w%z@W)uR^m*sGbstx|wsx%G2?xKI5m} zPyom##SMz^UG&~h1v2cl0*=FgRboDm{(?QiK>G`wsVUsaHyRi4jv&tyW?qt$W122nk#`(nPmP0$lQ!dz{b)h;-DqrW zw({CHt!mJI>(vm}eKee?vuV&=CfU%?40`ijm&d&e@S?}`CB!mtM_TnxA{=vb|D*JM zu^cBF=udOx0Kc&zf!7hX@DmM_6QULb)Z49Jd!aa*oXHeheBY=PlgUynpqTLCPTip3 zY@tPTXgVyG_t9MFz4MfgQ@=O_IkOybOk=1bT{1paH;~iuV0Dk4yT(Hg!6cZo`Z`P?^#cZREi*ruzLcz#mQ~Xc|&(gD2mj zk2xb0M6TY(yvWP9tEsDGHL{cMK>;l69RG>Oe+UpkCL&<829(kFHp}zJ@LGAmrDsw7 zK=h5h`aXv-+NaVoBpNZBNKs7agvN5zlY~88!&LG>h#pg8Np+InB1nLcRch~iwaHp; z?+FaY*Xw-`rH6kXr2isP=L?pXu;4M1saZr5zuHH)m^4>@BhL+m0a`Fh(!3-7h#CE4 zH7A+GZ-HG`Lz~e!LxqFl+q@=hZ)&hRyJi$2cU#cn4NkCV+}l^(UKs>`v-V8D2Arj=`B7qYeRo97@D8R#(4T; zV0qxWxL~J@UFAXK`c$5?vyCXafHa%Gz>IYoA;38HAEnVOy6h#w!Pj^JY@`ZTd_HbL zEnO7vXkVvhuwpm0NgZ1G=QGfg%c*(Fm4wXAg$&WwjWLOILV&6s9SsN(-;RMb_Nvu- zlT`KEYMHke&r-pRt=QB>M-D=qMv{kU|3+byOdH@lh=>=!mJ!FtLAt+LN#QK|9#&j# zg*DL#NOB#Jg7f+Pk_q7iaTx&0&zOjv{nHIppILP4fvYB$_LI^ixeZUZ+*3&mPZXH> z<)Y&zw+kyNs(;}?tOSfopOq>!TOoJ90mNUWljn%HA&;Mr0hu9ebn_2UtLH+hR(7c$ z-?TYdJ6}gRhki}{t1BN4aNcBirR)3qL!H5Y2oQPBKLsdy77-AmI3cN@Q>(m{-v6xD zhIxM1cmQ(`Jb_I+GjS3D`=Gm0*QDn+Ujtht+!8eiah#x8Y)P|$U*{#KFmZE2n_d^c zt4P$}>Q11C3 zW#;5q;?$W&B$3iyptW-1r>0q}pu8%dJT~$h3QG8N#UuKRWakx^pzOf}mu@BeO-)&Esn?gmr|1rinP;F9^gZXLfKc9ztQ%5yTa1bcI5~|9=5WK6y zdYPbalD`^)pAXG8K-wScy5D@;1)xNz0YsCq()a`p9R5?=QEqIB+vKa+qAoWL?m z*lK{c^#H+l`T}I>pU>K`oEgxtI;jVK0-Su7u%F9+4PYQf1nj@+X8TyUOyFr^GHnmU z2|Hu?BRC8LKVUpA&X(vhAd)pfpCBm(0XMR1^|D;D$d$NI_|Jkkh#M}ScAkjUQXFhN z#4!qVLdOdBP<2}b@t7Cd?It%Ybd?gQU!!Zr?^T;^8+ew~l7jNa<a~pMGW?8@ooLxr)!jlsP_T3e7f)JADFe#pWD3Q~>4s0SZrIml4juTgE!Rl$erZBWq zYc>bsYD=qG;8YHf%>x0C?q+}KZ*T99S_Y~+k4|8hs$rl*?#rzv8X-FqCsTJqMMHB_ zLdt*7d#DI`4gd93(9+J#-r3U3#fje7-j+XH9261hUyExDO3_h?cqeI5Oj6n0%YP7Y|bYNjZBHAk+aLb$LY zFj_Sz{N?!e}qTnv@hlF@GRofQW!k!K8&J5d_Z9roShT1pK|>8REJ<0=*zjJ z1Ko0FAgA0=%XR}hJkw-$z#AZiofZqeB0XFNzbFG+@c=E4`k5Q8k!7i&6@6KmQb+aYqr@xs1!M4$)UaxJT1e2)&ih%Cwh?+b%62f3cJM_5WBrghocUvs z6h~L;T=lWW1>cC!WbY|6BTbJ8JGP}|2{j4^bx}m}FS>JaXkTu3~&PhC&1OeQ(>w1ypsO>-U|qe&l@eGGmdb z_AI;by>nmVt<+SMBe^quDY%p$V^C)aDEMwfsa*sR@xS&jVgG9BfNcnafdG(Q0e=T6 z6|pUIT)p}yl?}ufyBL5(qPLN^J1Pw-{tb#-#aVu2N@y5&N#%z9V*0IJgQ3Lvm(X?l zl99^Nn-PKH99W&#sjonMc3@MSvP{;>T|^bT?;63+FyFn|l~U-AjIoR*=cI+v8b)!l zwrD6BmV5Bx8n8!adgtZmfw*{B{QJQqr8DnJo2A2JgCxPcnneilnzQX15d|33B~iV3 zyf5$;IBAlu#=>1D1aZ=E*K7x)FdV z_}EYksl60`EP3)?3b@Buuv?%w$jg|YXu0%;bwabHPxkS%_Je(KOxWA3=ZOZsi#Fjv zi(`+aBws}9kvd5|X6PEz6DFt3CdBUEtl?u|6n^WE*|q(Ws?i^Y{;;6qw|M|z=ER^l|#&Jl5W;X zopEKYYUWBco8&h5`87jy2dL~R20JJyZR;Hp`3K$88=j3LcB-YKiInQn0Z2c*3!IsT zTMSG@?`&j8ig#&SY&dK1c`-79SB$hH$Uxh+f8g$MR?z@se9y|nsy5)Xqi86ZZreG$ zeI>^p0xd;9`&)Ey#f^IHmkbK>PiY--UhgO+SJ!p6<#Ym({G!xhT1&=u|C#!(32wQ< zG?F&2QFYuM9n~U|EAJX;u_H^slA&dh-x@^`l!29%G@uAy8x4|?j*-C2IDW3#T#D*T z=4c-k>vJ$}By}V8y}*wfG;taViPOT~%*2hoTVp(@{8=G#VHfYn3qy;ZlC*zQJ|M%& zl>)qzG(=flfixdDK!N)y9oQ+K>A9}tT>>i4!^Bg_0TjqM83WA)R$^Fxg^#&VHL54{ zg>KGpc+Uk@^a46{5$yzm&@Zu3{?`CO@*jApfcUZgjR&$_vvH{mcyC8K!WVb$OOG@x zn^&Y=2R7_cb+(aeCE@Kjk|=c11wP@vfD8`pb=MSQ{7;Tus{xpCab<|gOGEZQ&)%m4EIy^39`$3vJ>8v+#<_wi~hs9*7rKpsNf_3Zp zU#PMoAEr>m!w`*G8CC_JmK{TAKs_SY)=unAk_ua)FtLpJUIry}HT&e{WKmB?xkC<~ zk$bw&NRj-BvpKd_Fx@|-N7&=lqW4&I*acrqa-l%(yg-70eV-?@tT$DGY>-IC?C(lEC%yx2Or?BNRS z>TYn|bG@Gdfj$~GW4301I;dN%wwPJdGo395Y@7)vJzCu{{+6aG3m1Zlw(?38^oP;G z1T;1keV7BUd3MK}a^mLhwLU0B*xb^yrpRyl>`4%+)Am=vKTSGUxd~r6i8+x%_UULF z(0&9EyL&e?VbD68TDpp!d#|??6R;q?OW z5aVPcHAV%GQFO<&uo0 zgoXUu&M#ybaR-`Tj&o=#1gsHxP$fAf;GD{(kGQ@c2}(r_BBj#`{TIO1lcK_xU(WCP z3Wp&k>b zWSMCWOWDinO>UAc-3727{g^-b!e<%iPCz(cZ;B5{*qD@u+*ZzwtPf08 zXmu1-7}2a5u(;kWdwr{$y%=toRQUPL!s!ol$1>)-x~ zhr$=n-`PX6H{wl#BivcO2;qywK&6~_XGyB00;6&e)$e@<+u&3keiq8qAGDNgji=F` z%6<}mqQOy13figIZFLSyuM_3kENc_C-I|(NyMMwz-1#+EK`g9Q-|?rC4@c)jF2d1b ziV}U==A=Ulf*oL@0nTVjR~Hyt_XmCcM60@B<7y<3;KdagMr(uyPfo zh>NS!DfnleL}H(2VGJ@1DGZ@tQbvmilwu~>O;NaPVRQSTo0Q`?h+WQO{va*Lf!QHo zGja2bK;E-)FR}u6UX;fAtyqKMt>?h>QOL_8_PeVM|31ffXe(6-)~ zSHV!@h$?u%6;u1Ee?{<-CA7v5+lLS`z~XmLm&nTP#QRUOIW#>MN&w^yQA7zfY0^TX zO&6Rs$1Tuyk7X|^+m*9rMfOBD(tvI-#P#z?W}eX%_f$F5)5frxCNw!pV-%Jb9CfBI z{uDL*5Eq%J7$4!)_n|`e)aBu@dB_C1kfGE!skz?Iq^nO9-T7Sh%D76`CFqrfqAwEFI-<>5rz8=?yEw@ z?{8F*@DvFXYo63&RRpvyLuh*4M+M|W(!gr7POSG9Z9QY;s@$SjAjvr=$b-L8=kT0p zmvi~%NG|VkNntu%K04-jn4)Biy=R>F=6j|F1X9=PA8=$`f-lFof0F9V$YTO~pmoPcaifawr?XGz&tQj%|L7Px*hNK%Fi{{hz(jW|R11jAO-blA z3JmI@8y$cX)yB6Kff)64cu-h%)K$yhE<3q2kTISEC5-tNSR{(r%B9GFDHTAR zm~m3hQ<{bjsVS)+SNt~~kbhs0Q30>8_&a+viYr7|8Fh_* zMy-60uj4qAE6icSj|p3*Dr@{Gs`dS*V^Gd@R^_C*!_cl;nV>Djr=5Oe_2rA6RSz4@ zLL}u0oaxRH!;UAJcxMa$4yvyqMlg|_oTqn&{ z$tZh)6x9lLj_i?zi~wQK_ZBYOkP=r(I1|XZ*CSe!iLXPraMf)yTg9%gHlIs!k)edT zZ>U!xSzf`7%l*-xh|q^G9+hp4$x494dFDk)&C(_ZuF12v4KracVPk4^SHwzFCm%Hc z&#SDR%@UA#>xXN3rE}NkSJe{&FBXF<5aZ>4Cc8iXr7A!>ms%|k$a}$(*j%Y1Hm0G)W@aRv-oJY1eu4_C0ikkJgp@`3cKcn53pz0)lLIi&P@k&=Yb@?AGuJHE*-KS%g4=ON?74&%b?h2BvCDTw1dS zZLO2kEDI#_%M5;_b2`FQ3uYaG`13mZFC(FK7l#PqzhjkUk@peHpS>DiN(?aW;|hR# z<$>FVpw19GvBVdPFw~)>DJw^rCeqH-k#Vz@jo?nm8+S=*6_nMB?~qdQ5AKex@*or; zk~OKGnu#ssTN4;fZ|?4++T?pdI1M8p;MZJ?aMWEbU$Z#_5x-uz5~(*I_wLlV&c)Mt z$cxt%SND#H?YZ1l$0AXKwYM&|iL=DG^#Pwls)pVk4in*ywxbq4QOScc%N{g)#D<1?}oO%4zL{jVoZzx=X+9f{YP4z^A$-pDcP6+xD`BOtWkUpmw zM}*=@)AY}zT26oXMunAeKM<*O^VwgkrV=2RqMuJ_?JPgGg^d-@U_qf?qW_5pLf-!0 zcmM@>)m1!A)hs|Ed@*=w4fL|N_#zfA&DRkAx~%j#+)_{wr%1MNad%cTl{B8Z#wJK_Kqn~^!_Q>1pz_3$0eZ7EBXu8YGoIx` z-{Gp3&fFc3BTtO8;74KXLYG)Tc`2>PMa~TA$SLQ!5t1!bS)dw4G%kz$RcIZ5o z@rXO5A9ob{{X&nUYi)V;hX(*zT>8`At!FK(j^jS$$uNsB>Slc8=HH0y|cfiw1dUD~O$6$w(rnVjXtF1u1;G0SGr1dJEgp6jJJswA^^; zVFi=zY1$%9cy?SEyuwt&$)VsiYWTcL)LHG>wsg0-L$<5NO|zq^oF{1F5mP5}t|DH) zgA}@tE5<+ZKu(GK8;?gE%uzzpKvFz(gm1UPlrOI+{sctqA8rd#J3HL{Pgaw7Up;W| zYzZS4JM)Qo2y!y!J8?HJFE@B-v5l0qU^3A!nKKqE#N=fC=0f^D&a5-HDKA2_iw8#n zAcir%?GuZl;vN(|g_DKy4vSei!9^fP#czBdq{wQ6N%PpIm3~Xj`|^+GLUkG?T_a1n z>ASKjS-L)LOruB!DdfBnPXZiincfb-(&^TS;$k0T?Sfh`V@#TriM^ehw?$YX&^|lSaqJBBis~Q7I2TT8SuD@ zR!cRC3XJUZ)lm=(0$){?B0bVM9EwzNUMJ6cidu^1BPT81I&N#0`kfb2=bVQj$|<8h z{p`P!o=_Tl1t~7I=7W%j=bd?i!BdpGb-F9_a#w;)=t}3jKXN1W4{|E~Gt4D2jJ9^v z>Q(vyV`wjFppVX`$wa!b!`u5$Ja8GZ|HfmD>Mot;8k!~17vbAdL19TL9J(U^w<_BG zf`-Cd3uPSQ&(znl*q(u=wZ|mca+h)@+;)G_&%zE}{R3jR88a5Vqaya;dQJCN%i-gm z=$_5dQXi}nW>VU|3cYN0zDS~jUm?wFnPk>L*#V|wz~RHd*@=gqbOM2d%Oj18lgjGd zeFMjX5*lkn><(Fm9odpv2YxhS&!3nEpw{aQK#W_kr-dc=w93Y9ZSoF3H)giBkd--L zfv~!OPBaipQm-i)Ggk+Ihu0f`HpASsDBi7S>JHXYFu?QIh;Lww&Pl9(S{b2T5Ig5p zz@c}}n%qDYXb-C#_wSBkDxNp^9!8ed+FFRAytbi?Rw0d3genq+0>LcS={Yg3sCp$O z1)5ngdz1G3$b6`?3Ii=0H|5;27ANs8aUdQwd+xVVqb)dqhVApbR;0`KMPe`!>Cm?7gc2m`#V z9kxtx10`7rur38Ht8jC&UQRbjfL*Yr;)ZKIBj=uT_p&1i<<|SC+BpsyBO<8rIhcAi zEFJaM+Sd;wn)Ks`;;(cpx#t2Vb@@K%(fMb>mqzygeTm`UrD=RN``>u99YMOANodtF zKOuY@bnkXj1K&g2RQdvm_P9)CTo>gaiaSOR>Mh{Ygc%RQQ$uBqbNzsO-qJ&ww^M3Z zz|{<-d!9=l`4dSnRSKNC(unt^&e((W_S|8dSI0}sBb{I4SzoA!MRXK6HuD=?wx;hJ zl`p~1x;5N{uaItrle*-Z4}&9h-SSNRb)~WHe=+t>L82|)x^3CEZQC`=wr$(CT{X+L zJ=XIU0XmX==wZp%I1SF`A?D=zfVnCJoPQXq`kce7iPmHf3$DdaPzZUlvC7-ZC#a) ziK8)mKjj^LXyTO4**hroZFSwKU4`nafQ2}p!;B!$k!OQ51rjs7GVc_EZf0-}LhHrU ze0_G>r*@93%jj))Fw3AnCwv6VhyZw6-lS_8t2zTzQ$kqc2+L`A-{RW!sq1q&+Y{dQ zS@@KmdEW%2}9Egl7Lke3J3+ucmpn@=IUUALc|9AEH zFSTEZrc&r1Jh~|ZNFh>=0^aBTRu8R`Kl|i7s+h)phRw|Uj;U3@o(eYEkPv2{ZgZ(k z+Ki_T#AMz%g*;P&>0g4rfk6E+h=}ajOMxY z_3{fZE>8{U8<14HTo)mAk+g@<9`b645U{=euzHoIvtP&-VKq9CkT?IiEHn*Ht&IhU zaVypa%R1VO6Oqs(L?e8(Wu0UfBgmCZFUg@dp&NnRERH99Zk8L_Sw+Z?6n&>i-^#}Y zoY%o>Zr+GpnrA#_a1D0^w^k_AJ}ckja!?W3+fM@k(oq7R<~}YDX=R}gEaRv9LmStW z()(I2l)HDO5Yk$+;RlQ2ved!>_d5uyh3t(_UX{r|w}$Kygbn38c}YH(Vr2g5h6|1~ zw4+^|k0fAUJ~Yc>xN|~G<2tTwlzpJ?)S`y>;aMuJUu9(Gg8=lzWzyVMBrFBpb+wrn z{j@vf`dWqn!r}K&%|jQ)9g5Hz5NvjkGiP%;7g@*vP3QDEVZBWATq3)zN80@O(h@{P zp7aG%xTkFMlT;O~o)Jf9?+{y&86;nzI=1pf()N)mf569Ca7O!f)_UY*-em2H`<`nkmQbytObjGi-6#(vw^L zOg%WNHIc^1v-q3VdKfV2A*L6rXAy@|DimYwp=;BumV*-BjPHTwSmY{$l|~m4iC}KO zHFBNbRQwTn{10OkzRxa5Lro)wVL8^??u590xSyp{-0Lrj3fH&B3|%n=H16iDR_B1t zm+3Z(otzfXP458`S-~JWUMkJ_3NE8hEx$sm30mJ95r0cz^@m%J)8b(C?zDT1pJ6m> zDX)2WCSpfF<1mdCf_?o(j3CgMl(^E0Js5~$>u4Z}pO4x1RAv|yHdGKa*)rck? z0=2YQrqNy8j(|TZYb}MpeF^JGwdFSI7Wb3i{v_-^(&P(F=!y5U*f~EYzhO`Bc98>l{m-;!!|=R8&`xq1>eP zCxkAHtKMV|(lQCHXc;Zw-_S`h7*L+Oo>{|_1le_v@35={BhI`iyI?B>V@cG}cTyQG0XQI;btra?7fz7fe4DfS zoNg2kG9@Gh%^zF&c6$$5a&HFA;Z?t;z)R*oIS;`rVw99+2O95iXzRl^G z9h!2|X54%}`xO|jx3qvaW7;L^XEG8F-Ltwe=6Q&>=q57)dD2V zdKGlbHu_dY3W&+bHot-7x`wwf&i**ZQNG)kI5fZyfj^B|F(gn-e9TV|di>|_7A!;k zqWQuyF*r@wgQ6$W^}1TTqhXC-J-#iJ%GX6li0igcR4Gl4kFl7qif?dFIV%Bh@vU7B zkPA$?tjjIGkU0qC5+iO+hB>hEcltwuQVb=iVo3ZhkW_IY1?XnqUFd-?4ojtG=-v6f z!(oA*rp#M4NZ>rlDkz6hy*Ko+3@h`lPf0Aa<;0<#Qsc8g&y$~(?Q6^me8*yXi{}?l zDjT})!d%hK3#kir=APZ5!LjUoNxz(2Hd0l@>8g@Zl|4BaXiCM%c%<9g7^R~$U zMP36MLe>3tXCIfE_#5Y`W8Gn$#3!-}3&I@3Pj)A4J#E*IGA*{SD6b07%!bzP!2Il; zHa1OresM}t%xRg^kdghugNj173w<^6^aIj-^z~8-aJ*PNurJ2XkLph6&eO;v}o9K$d z1-EJFy*E(mE`)sKFg^QT$TxW!q`D9%6(duRU2~HhfQo!IVvr<6F$4}ZWxhCxa)x3< z<F<7@o_L~ zPlxtwX6R&P|4H8+)3RTHdrs@5YSFBasK&8>WQ9pf5kK}t4nykgC!5mb0Px48nnHgo zr#&bhgpiUBs}CO}%5ZfW3ra~wAB5f{?r{|gVs6DG6rYgIoU*17sCY;YYRY>}yVREp z1NIsCw3tE!l0_VAoNY?Qmh1uH6%f#jtp%&1+2}?afBAYmI^cpWnA`6`tNFXCF+WV)z_@u{2$h zciX)FJ61>;3`h7MJkTI>P&F*iC`cONf5gT;6X=jo%%uR(Y&USrXz(O{OIi9tDQs|u zk32G8-1xie3;XPWo71@>NhZfLNJJ`cGcV}@k`f@zfy=?J*aR5IV=uF#uVv?A2^-<> z+eL+*<(F$S+a*mD)SGw1+MUr09Z+GlyO=Cq7Px}H>#T*?XY6kPzV*cFQVg-> zPRaK+Qvj*Ts=Yp)-re`#k`fW0V3#-^P#d)oGVxLERhV2BA7~kwg!aWDK*%4cCi%co z@){1{g_eVWUK{XQnh0qX4yOSbBK-_6-MGg;Mxg>LNjY%!>Y_4C9MO}_QVw=OrLO*w zO}nso`P%(MK^)2D4Uj?uI`d>JivUF9xercd;OC0ZzBQmRO{fmduJjtjpQ1yBTpYWd zFWIRx(69}vT(RrG8@9Tu4u?k0!WC?f==ip?G`)WB9+CEpplt;p1vYG_@SWP6GR z9SLm0YnY7kUJJ2-(7CZ9dP#vWSh7`$Ygb({dNF=_o;JRVc$=??S}JTu_S^}fz_S;G z)AKQ=ssR!Ltl5|)B+#2&Blhp=0cHRG4<6yfo|a0L*mPXg@ISUw>c+lP+TOW3L(~E; zRsx1Ze|GAl5yK1tW(wGX-t1R8L&US<>Rh=Om0+Bv!V?u2cD9AxKRF-^chTk(G}=JP zCgFVU3(8O7V!%>o)RSO7gPUyeB8Hp*k$Z5GmYvuP>8{h$Ku`|(`gv&Sl0PNuO081U zeo>08UawZ2m-{!*l6_;CR}ryRa6DuT9bX|nYM8Rg9nex`Ovy>b_x=RJ*~Vep6U5y% zsP-Og-eB=44D&M@O%ao5GSXyx8OadBCAh>N1YO@OU~OQh3b5W4f{bhT5-kLOTB@Z` z*UA!`HAJa==0+(@I|GH+19Ff9l^eW*h&>aGFiO!K%r4jSw2Ksl?DDy8@ESuy<0$mF z_w>7E)HR~%t+$PCh(cP;d`7Sx>?f;^=)LE$PQXOx76vr!xSc#5Bt4`$WnIlrTA;-j0i<$I;A~2HgvBJy4KosQ7)F zCof4xN5ZD&lDy}kUUjj2psuF~WY_7Z?zR?hvn>A`50rfCfAEOz$zY-|DE*zu_jgG6 zD96>PWoal9y$0FJiHOn(tPo#Zo?`#S5;Ma^-FGkjxr&RUcTkA=9Qi! z=Eh-%w&BXM7C+rr%T|nKF1;;0+rtC4mjgO)^cH3FqkTj-3{6Ttn-H6?EnC(z=i|?k z97qq0#^emzUTs;Bkg1NzRr!#_hozl4OGv3~+FqdF3geb*?W1GDbv$Edewg;2O~UFM z;sdmLB%tsKcq-!?YK?xzdB@ITN1kxL@t$MXLX%oYg}zr*5?6Ju%R|lu2N~vqO(-gk zIta0-2tc&j`DZWJ>Qw!3m;d>=ouZN42_=&9LZ-&6tgHRoJwO4e?)PZQm=2%GC_d@f zY=lsEZDelt%Yu1%N`S&~YG-@EJVsB=C1#Y$i z3*npT>A@d~J9;AzD6u4Q3R$iWAdWfP+f1w*+chS7?+P_5lZ573VKxafD<$r%a~xz| zD@frBgGV3cO^<%Q`nX(~bU#CqI8|G(OtYua7?gBXXvQM4Qbo01T-8bZOi0*hj?G@D zqp$i5D^C!^A1u%)eGZaQ{FwB?bfz)CWcS{4Bh8BmW5P+VLHf`K8@YdPO_k+7v;M&Y zdP}M9 zxAZwmc>NhmFsAg5->s<=tU$1GH5R<;6Qa%y9S#9$92KOYM?m+{)-SJTn$6(t%#B50 zXI}kNc7NDk%ptLwLjE8JHmnTnBO|pSDBb#GMmDmjUS&pMo%qTh%+ z2p6Se5%E}cCpO!DS(zytb3Y1=W0%xqsODUq1*S~3`E^b*>tLS-G`0DZH0q*)fxN}0 zBg*@Nje8ec{iiJU^iPA>TPT|&@l_e&hAYJMVFo$X#E%x6zfx4uJXrzWTy4)qfIw{$ zf{89??5m>YxP;c!hS-cQCP;PEH+T;$H8~e50^!OK&gpEVQ%%;jt0`s#QmQ_N0Ai%{ z2ulu<_WQ^rf!fK)NVHdimI-osz{l%4QC>5C$oJ>V$=Gh9ibST;S5JS$11q!67@C`V^J^VzG&aP|@o-32yd$871 zbL9yR3BsTMBs*#^WVnBLMNkYHN$1=d`f?YFUv{N#0_{@&pehnnQ()O<^2E zK|VU%{#W%-{SWiepAG)Uo+QTVOPmxOwjBP-OF+%SweN0ytvKqG>HPTMN1MYZ;Np0EkP5mQ!gsr&6SR*OK0p?ZT zeZG!Emp+gW(g*W&iRxie1tETRvY`fzRCx+vaECYAXosvQBiL{GySDmFt~~1TJic{C zX!^DLKpWaG5#yvUo4afe#ZwQgkn+pazo2}&I*$_fn-&c+qzTzYzr_QcgvYmsioKU2 zPnLuaIL4;zBlMJzc^8c56L1738+6d%sqiNMyWbzB`zsbTGsZCWdDf$CBJa69Sk!S}HDg>^omE zUIGdGqaD*0uh|6wwVDRYMvp}U_>?KK0YKoa-2X0e9}qabrf!Wpz0anDV~?8Buyi*t z=lonj7VFv5D8v2bkz~f+^vnG^Kl645TL(2#u~iNC_#b}6(Kc#>1rXS6)Z!bqDCIG_ zB?IG(Lxs1r;osxFCZmtR~dU0MtNUd6JO=Uefjcw!00T7Y4QwS)=@FC3YPQ z%qq2#$wEs1wf8^*{O_hZYyi_g)dPCaXIKVV2`tSF{zpPfvt5FgO8aXnVgRKVE9Zv2 zD_hVOkSgw%J7l zv1E{;J}BZ^)OcoRHVD~1I+Aw}`r@dLM>4UrXJwlY@GK?IVhHDjoOs$1`ZxXKp=4w; zlO3EiYw@vh<2@!GX^Ho^EVQzl5|M?(fdY8j6LX6J7Ao;jnVBqIkFWwL?F@xLh%@{Iqe+c3X@z$%BtOd&>t>(v_ydN2L+SrS-y}`LQ)$4OclULxFR_)g#eh`GeX%-_Q5pV+9<@#{R zq66xrT{a5o4PoT_rvr#ppY&FWP!^^^3W;0>DS~x*qP&VQf{W>2XrL{D*_F3i2>=3d z4i4Hlb>Tl%BPvOlWYHGH>z$!?dp({&+N1we52U}Db^nY5L88?BgU5I`UJhM5n_M#v z{5P4j_D5jG-fcOb-sDAw0)J6K{^XOdSTUydZN-;4;C>ehe9b1o6^DDwqrPQo$RrOy(L6;B+ZSJ(&9mTfz-$*hQ;klA>+q#c zwIBXD!NjFGm=I`uO%yA>k~;)2xw00e7t}ngBV?ht64!2>DI^D)u_6?^k@!2Q{*Ube z1@PDQP=-Tg1q}l3H~X)F=1=$>Y>hp@#n3UAfkeLOpTdu2rtEbH2b0Qw8d!^TVe5!3jU- zL+IP!+WSP76$~V$q6L4CR zDJ_!%TSXT5z(8vX>JxGaJa+?{TB8Ck3||L|+Xyh`4XZzkRQ~IDaqke?6FNSqxJ=A0 z$T?$8IQc|fc}7FRL7xwQZVlU#l;vsbr@3(AZ#+JhmRTk8@H!xQjT)<8YDUgU&{~G= zv1-D?d6cCs)LIB4#nfhKO}F=2vZEKj9lqvm;U4lh1lUm9?;me+3i7a77v|J%fR+5! z%qqB4E_&?&Y&UBWo_a5oFpN!V|(Be2YrCqp~QvJ9?Z*j%%TpYi9#^Kq7S&o_^=6)Ok z!e0bI0@QFhio+BjTHkIg(5hOpv>6+dKVfzfK^Q@474{aDo#rYeZU?fs?eA)E*a8J5 zun@RzsM6ByQ)4lt&ma%`%vh0c5_kM`x_ti|K?sQA-wzl|MVZ@D-ZxG%sE7fxkuQ}2A?uu zCLXY?+vF_hMAF+YS`ZSU9|dmC1zXdBh(83z8~p^`FyD4xGGL@k%DPa|S1jcbt$t$% z_1C6HffkYedi%9FHRcYB<_^}H(=8(z#5iQoFQFHz`~X)S4vhx?C#SU9jo|$9&KG^F zs8S6v==;Dvro0^p!B+^b8Xe&}5*gL+F#J}81Myvjq(UQ1PeP0D0Xr&uU$?;0VgNh! z66qM!6fgiNy2hHO2_Ij^yslf@sp}a@pN*=UXFjKgvw9Md!jeaIT|iOm@707_TT7-` zpKkJ$9KlvNE*y0bQWvXb`pVO1&LJ)H>$%t9X{#6jFOJmsF{UU~lh<*X4%)9~=ft_^ z8*AhBWXWW^@n;9&Rg@2Es(5bW8r^wCvXHII?rEe|vJntv8|Y^mwBjv;()aDH6qahR zzX@p8NV4dTj>PWnXO>g-AUMG3+4ZD-1^isp{Ex^XpO!mNXcaI$#U#{!($0Nnl$Tr& zRg5d0fqhIKa0vL!%OiGYGKMAFS(wxNI5DeCSr_AXU87BFb0BMHzRL7UBC0Evy?D4a z0PO0LL-wjvdUc@`M6;9D!+#KfEq^>xfoNt&728z119O4!-*x`zW^~Mb7WPjlGyGWo z6?*6&nu-rCZ@q|#ERvKIZ397vzD72f2<4cmkn*YoBY>p-D>{hv|H2F?kP?-+AToxz zv$H)HJ-xk|J)Mn(Go6XC%Rh@1@c&9tMOBCYreV!oJI6f`jrvW5ePWk7(!4fMCFP`= zfWv%wqR7IuR}FTAzvIu|+1)t9OmczgV)@x1O+QzlSzf2JtHHo9?CS>Y5w?n6pa!O; zaIDi$l}1Si8QHG4u0@ZzNsR@&_B@X#L69dpG^|YmBeU3!Nyp30YE-yu%NdY}#cA67 zs@oggC-#IS=-f|d3}L*ouoD?)`4ZW6Jmk+!9Xv~(>#D4J2JJqAU@Z4pW$jF<N35& z5scjg;63S4_SbdzcPfqv@}xF7%BW@qr1$^n+%Be)cWI)Rme%LgTuXf|4jN5GYtQm!8(M$R z_c5OpiNhsURmU*(t#davAoN#M&+?yp4%$GXtJVyUvKpTe$fUCmlWlW8#~z5?+Z1{y z19d~3V@9FIdozNH<6tr7 z7Y-)WgtCOHVIf5;gf}zLxat$gu94>dYSX$}I2%|y+POHJ{D0`Q%pL%FCEI94*b{X# zA-VM3NR~mGUA2*tf4@4(3D;HHngDb%kdwotYlbS2ul~yy{ZF0N#u@@3EWvuFPNzVz zL#qY%NH^BDp&3hOHleyq-gLnUh&GCPEWKwj^%e6VZJG`zwrCBnC%K$_jOzPlbfM5B z@Q`%*kv?6xBXdtDSYkozZtDEX6?8-z4b8%TLUINg9`DZx1qP#>*-}y<1V~gJJTG4% z8uT+%J~$mD<{F?*GkDbe)obR!!v+N_9jN|u;F&$~5Z;X+?+kQv^j!BVs4oy1sOfeZ z^zuUa)W|(Z=eQG7PPa>5-0T{sIeRFoN?scN*$shf9SmfS!n$l0m87y>c11XziLR12 z3ddSq_&jth6nX|S#oppO!s>c(ek8Sv8PuDH^f6m)*D~O}rb>Ruzkbhu>a@h?;6L)2 zuxm~1H1WtiEC()1Jp&4xW3_+V-K>vSpD&3zJO%F*85yPFz!GN9rwVJQSBT*G76_lM z9_|n&Ian!Tqc4(t!P~UJwvw*y@~BdjWSUY=p(29Skm%Q40N8W)f!=i~rlxatoM!{{ zS&?AF$IUwdnY6en%#Z9;uxtQr^6YkAx|og}$u;M((r6nt9)PA^z(!mon6rNB^Ijf} zs9G*&zk(G0_SE=@VJ={RQgx91H8kK958gH-WoJLt@5V*RN(2V@Ph&9o8Ph5*yb8Er zxy7aRnfczzsY=#$>u=dOl_V^gm`4ogK1GoJj(bA5i={3lj3#V~$P&QyeN+E`>a?dQ z;NOgzPm<{|W)A!Qxp~9-P6XqJBxe_b%2)`5MbYDr`A2UHp$oZ;9@NSXS&!I7!q?ig z4zS41bd!2s7xig>1DhTJ1+7M|`EQmHyO&P!jBP1lnTLwwDdajutY3<}Z{a=IXLioA zd1HvTv99{xp%Ei>%yF{N8pP)o{R5IBN+0CHNJ>Q#-W&GFjvWduXX`U#J;&Rxqf6!r zN+pB6V&6Ow-}zn2k%cG>>+*IPLo)QMEkqXDTIr0aMAAonof(PKXwluubcadtT$SLo z;|X_uZ)|lnGmtXVD-Y*v@x*-;pyHv1e5($EWcpN3KiAfv@YJoi18BD|by5Hg;~oBY zi{t;O)4mtO|A=0;y);dL9gG3IV1y7$pv zBh@Gr$|%4s@}m-a9AsVdOl3OK54Ygv8ttHmRe_pu!O^Uv zr#Q?iZvN@r)Q2)6-nj(gbW;itZlA`a05~m6=gebc0D%I&m1T8j_zn)s$!uCC`yzHi zEiIAIgBa!7(Dr!qX227OzGG^&&jT90n+DVOEY2UE5DTtD_>DE^d>VvgY?t{fkG=^Y053mxsD^dC6c74%JAV{ z;)L%yo~<#RIxne{(t2$%Z)gHy5z*T^aQ@-juRGeJbkn`nfGb1|h1mS{5AZvGxHy}= zmEpjy-N5yNDj6AqxdfEQt`>Yr2hv!;DZwXMJ^TT1y{|YC#%G_h99h+GR`o)TzcKWP zE;9eZ<3DxU*KqhB_l4Gtb_<^!Z~{p!^1|gzLnRk7HVsM9Yvu(pHPY>OTO#>yM4c|_ zU*#e!PKq9Uw?(Z6`9f^r5V)~=!o|Gq#q5_E6fFEiO(0qGoQ6GH^RH5%05DCmhSb7M zt%v>7lr)JD1&S&|w?3ru>5#TmNXH<=L6R9A9bW*mJN>4WzbfUMl7mlg(g4)4tt}+UIQJRCRVfT?N6-+qCdL{+R~W>fNYZb3EDPa-JAc`li#&B}?js@izi}3f zN=J?lSogzxc;R}yo_!<_GW&g6p*B>Bn7Lnd1KN|VuCM1&+ure*B+~V zzbi#FHV|)G55i3Xi_Ly0Fqu!`x?DL1Z&o9*DqVkdOFVMCp9S&qJJ^r{z>)1p`Xz;$ zRys?pypn?oCC|Q8ye++>UacfkHShpZLy1tW&E#q#TP|eVMjKjVJ9Jdu+|CI@V^o_i z%QK`oN0oeU9`8iK8^tvV(5t&x)BKBuwQ)M`S3~sMDA^EFEA$yrX?4}?yFnnTYe%Uj zR(Yk#1Y>ov{Gh!Gd5KiETt`*v)af-trS5&!1Wpdb3HVjAmJ?0Nr`|ak)e>{oE$I<5 z|Kx9T?SJF(A3Cj4DFQ$Pl{}nrY`ky4{Eam3yOL=dV8-q@IfdWy87_bdek)IZB5C%a zy8ZCdITj@TZOCvcjb%5)cyVF!30m2E)I{D6H1fTJxL-hsfH+&3r1}Oq`r&66vDnb* zGpBUAcNgT5G7yjGWtWkMcT1jXCjb7vYzLCGjhtMi`@mFRTpzis?l#DU7j;5j+7D;r zW~gr&1aoDu)K>MMA8~^;&D6%e%+hjCt%Kf81yrksr|#)-yU=t|_Tjd*$tagE&5S3x z1z7KSpU|{5h%N$fv$3_gs<|vSsGWi*Uk)Cu@EqZh6G#3l55k9}3ULf{4{3X30a@@4 zHKX!&HF&psCntHx`1SdD%PR6Li^8@p1>nn4~v@+Rjq5rgq6Z{eAGl%M?^N;IoLY z$;|2t=|tKi?qvZrl>&y8yVqd%<$M5dH`F34t`jFcTvS<0v(_R284+cFeJfAQtt`&N zJ0p-s?Are|R{CFyi}HWyv~b#g4;6{U#3F!HvFuOnCDgGT1`TXfTZj#AxW_X2sSVtN zT(-Q1Y&j1NHF~1PE&5}0Me`m+R^`vLWT+|+0thkZJ(ls2ph!Jd6X)hzZ^#kGt|0h1 zx61eC;Mymm1RmL_Qu65{gKBNB`&4!2*`DaxSa$SOUScJNa+}k|#<_5cy8?*eOP!Rc zqJDZ~pew)^m6cpaKc))Cssf(?EhC#charSs*?F>KrhZf$HwbdU+m+6r>Zvx;#Sx92gv%hzlIxo5KV$cIAe97v3aqWt(O$W_8W({lj9rIw=C%{ zzIY(PIIK)qB8Kig_)l!cNVwk1r~@Q!0tal^*QZcB`kjsz%tnYjmi{>hi~x0xZMnLprd$u=qpKVb&O_d{4OU4P&SycFjFv)HDeF8@_jzb^7@}UC zuAH99+Vi?~>?BMta-dCP z0Dbc)auA$uX=SX$74bw-;ZBju70H2_r}{5*^PhCm@TPNBLjD3A)tJ6MO&1Nu(J|IT zS+9FV9|X!hHqv?X|2UystV9^*&{M}XOM!)1i&Ac&@{lQ2pQgiqd4B^$ zltWD)VLJ5QWn^J2CXw_8*nQg#(oBVRm1QhBt6Yi=FO~uHuie(TP&~eEL$l+sovEX*L&;c)CkH})ZtdTVNU!4 z8>DfsUj)b`_%_UI!CIm1&|z3?SXp)&joKI1G@e;GsAM}9O1n!O=sU?m<{7dy?cvhnP}J^8#t4)GzJD7LzdS(7eKy<|b1XTKTkL*y z(M%{?=}tgB=b*^I@l^}SN0$*Is@Xj%gxucYXg1h3By&!?dsf3wv62iyp&R$|L(IO> zD)Au7Se>hJxo$_xB#ukFhpS>wUMU4WDse$7h2IHsV%grAg!X8_tV^tdpPxW&^B!)k zN>F%byCy%$czZMGr{LMBInddiXUS@Vs3jly(hJ52AbRP%RIj@r?3<%|X)a9KL8jhp zK~HnC6qcELWyvc2q}A`O%%Sh0#lNxC6ZXv$8%#-dAaYBdo?Bk^@FEBYTVz{OIP=7| z3pqHZ$*sxb>A$O~&Cfe|87v64scSsJqU^)QCO7)^@jB6IfHe;9*^?v`Y>cUuAJN1} z(raD$EvKzMp%83?6Kw8$1rE|xdq^s^&rJs0PM8rp`*}Cr>OUDVMwys!6fKv}L7jsV zG?VdDG)SMOirE4WFPL8ICgq?1J_+bsNu9M|rn4lp$>oO7C)H*l4I1&m__3CoD7zYQyk*%Q9FW@bWEwQzwsA`F77*bX*M9_MW+j8D(ObP z5@~R3`*}>TLMGSk#VfakvNHvl8o;5j_wC2B`?a!JK+DUy$cm!?y!K;GfX$L_FFsP% z4^b6cw%!G9>Z)o1f3LNvc}{Go2PZyj_;{^|%h>D>_SO=woS3zT0DB{|&yZ_fwDfAV zohrc7OVazu5^ri?a$g4fPN*ewaSOIQd*mNBZ!Y>UgmPT2bw|q-@9MAtUc$q^=Tw283@}-Us>%>pL5gefvg30?m|H zOFYB)e;oAzV)RGIKeQANhdVqwU{1cb<{Ra^t7xWBTG9|oRh={FBK5jVxbo()Q-7vi z%mp*twK}0V>*>k`>ngElhR%7t*!WBa`5)r+{TmPXyrX{_n*Up;^+Eib6ZM4|8*SV& z{`V5aiPyI?OKX}c2mahFLPFuMsxZGpJJy-_uH0#CwIc(I*ntUZH$^0r$OfPu<4# z!a7sWG0J~_S58w7-oU3Q!BP^h-crzE?l1vvDUm#6TQZ2vPi7RluAb>l^ilze3IGu* zcVgR1@3wC&6q_LEg{%jwdVGJ%#ww|RSz}f%8r#{0IdU4j$SmYgxJN>2E1%sAWldJ> zIqvRUsXN8Bme0BnU3{)uOOK$P-yf*g z``r%Ze-Aqw`6JZM<}Np#uCLPTqy>hV>82oD>DL7&7)Wp8y$f7y`!1E8GI=b-7*`-{ z*P{DjCg2gP@7J`Y<8Ggb-J9<->n?d2@TKMQ{&5cJ zc?C=4_XJQVg4)F1ye9C1JQm zCHL%!8*joW+MYmi$fj=Utswb;<5udu8CCq zZKz)t&zxNugF2VdB+(off@4#e+_58kpAVe3EHSj7KqH6OH*GqD&$RSUz`esYJ=P-j zTfhC8Ev0c45zrXp-e!rpDyi>jEb|~MOc=`;I?N*cgZ{o=8+TW8X-5qWhO@gVAL(N% zf|L0RVuV+J=#tArr-%d#!F2$nY``6ZA4bCSZVvH~vV?xh=`9ss`x6D5JqaU}4FN9& zN9c=TdF{~H7_WBWc0pzKI!aq1_JTH@b`ZT~kwQ5-6aP;U+F_`HrEZ+Aut4VDCDQ!E< z4(jm;|CQh^l~s-;{NCfjNAFS0P|T>7=Js##7eJb@3$3M&#+Gtq8bD(&wJCie3^?gAuUKbHade%Up&a4g@9W02j7s%QVk<3DuT!r8wE z+jK!AdL(_$U+qQ<;h0iB@osHa2!ocNRrizA9&FJjjy zUzEO@$2|ZAYY31O+dUp%uC6IRsNL1(Y682FeVm|i0X^aep&dp+`$>Za6`PSV9xs3t z|J+{UE3yk$2#zP>hAxMRYctyH`1@hlKh+Mp)oUI3VUD)A!tiQAS?n|IyIZF}naDxg zzr3V_h~28>+lZMqTr=JKWJULr*Fve(DG+y3ZJPOMOi=)RWH2)s8!=I0bqr%!?=e2n zDH!gp+fLs!ngYSfDK*eCc=Z45kmXKCp=6Sm2C!Ji5?8Q zsyz6^%Cq4!R_lA6*jLZ-|a%D>>xmjtOWaf zf30KWdk0Kg*wrs5LH;OLuP4P&y7)34QN-1?HmucZ{9q0UQIy^vGlCXcfD~y|t^(2p zg^Ud`D_$C3PuRP%0y#cqn%f@q2*{v!v;F4@$YQW44zpMx&Ab`ENY_k2-C7 z0Q@(>>X_1E7@T~(fr9DX- zfA!=Jp$M#Ykf+PqJux2W#=(af3_;5Kc$0H_%qoVB4uZM!11u~k!#31G6MFZ_$9P*hq?2WVk#yn?CktQZ2W}~v z!`E*s;xSk-k@g^Rriie#l>;bx8T_{q`FpMj4w(~2@&I#kDXXPMsQ4NXn4OoISUvc> z($m_l)O~$dKaL|Lh&YyhV z;?PeU!{gq2+X_be_qVpqI!^^NXYFbvBWCFA*F-m`+dAtt7+py4QZGG3={ltUfye*U zY1u#jPHt47HkyFcItWQS{Hg2(l}0iB+gu7XJT`FulgPmw!5FnY6ShzzMAmv2|0qR# z|7SKE2o2NC-<>(ABJnr9p-*5Mm8l>{)n=BX9D1MR5w1 zf)RQiF7(8grd535O=g3^svH_(L*zc z=JPRF0F!#K?`QL7vc=vyBmgF?WJ{DDcG36Mf(iEgH$?Z3f?&AsrxUh+=2;g>(DFcW z?7nwU{OC(g_SegYS~vO(7LCnvML96+4%s574OOfTZ_;^YPXNt`W*N%;h1s|pC3F6b z$A9RwhT8}Lf3}O#Iw~LbI3;Yk4Mls{Y1bB~+rv-TIZdpAV(2a>agK6tmFLMy_Z#oh&&<759Ww0udEq#Z%0dm!pI&7pO78ffe0qtCLq%Z zHweNRwe7VwNkk%me8qI39C$VXZJxwQWa144ve=`Kj zuodLKst;2XUJf+RDLZwM8;_sCUA!jCVU;ahe21luF6CoYryk#ilP-o+E{irVFZU!= z+X?TU#`a=zL$pxU$(gl8wBw{D3xg4^#F7~NRCv>-GCf*I0?v5M5fkY0us>FSCTxV z)ed~Kx@%Cdq1?#1AUIemNtt7>Qg)v7p%nki3CZGNh9;=5&s6sl#>slEaQj<8%5z-~ z;D6%rKXlsAbod{ia)}JSAE^I_wRddNb&b+&)3$BfwpU`MZQHhO+qP}n=1SXk_NuP# zh+R9XPklLm;f)b9=6gSLT$g+b(5C2ANSB5qbyS6rPO!F9nUd+{nUPu4{ifa9v^c%W zsSl*>>K*fllwb{uQW|w0<&IkaiD-HvX-gw}g#ZtfMUDvBQZt)vYbhc6ojVx6AZ1Je zr0+ZUf+e|`TtVc^qqvT0)bUFu7tqF{ZK#yIuSdUtaNKomA4Vfb{9XGJuV zJiz9E;PG#rc3~g>6OK$DJ~1fH4EW>(HvizjLAs1zzXV{N$1>)Od)aY}wCcFVa0cC0 z$j6oqMuh;`-D?gr`khWuv%Fz9%^J5{nGY=b5m@@d`@$Z|Fr2=DpR3rCyxyR{64i$q zDAm}~i0GGW2nbVoa`x0d6(ct*w8l33t$`Gz{PEfDO^vg;-luxA&N zawTGl#vJCvoi)Z&5EZ#mOHE6Oazg^y+M_VliEnq+J#i&LfT{G%n_ZlNLnk)L%943p zbl@{5*?TSnStJ9dgZ@ws?|p6dI9}(qq)D-rZaiuSbE7FTqeV-%-L0&u0kG3*i6@GX z58{0|Ej71>^`^T9neHV=dUWKotLY9ysMya7IV0B?TP|AD(UsC6@x1K;D#_1!w@!7% zJ9MqwdkhYZA@oq7=8IZ?oy&Zaj4_w*IMLY<)G2p&e)L8$m2Qj9PEar>iajv4q!M}b zyowR4R@gi?=rm`aZ_dtH6pSnA;`J~hq{zCznWn)V!_Q2!wqQ+^G0cgG5(SJBDOip-919 z2{(d5wdaW3hX;QLBr~;q;&&C;zK(@IrMlx7`P;o-Y5O*tzqjv)^lhy z*d8PMR~6~IE_n_6Nd?7o4y&@n`F$PRGol5L#-CGcWOA+M2J^i?K$sSJQ?}3>*eoZg zpIu*hnl36o_#Wo`f2$faPlCVt6Pzd18wJ%_=G0(p#O(5y=5AJ%j_6t^0P>R0PNnc3 zgy3HK+Ff-xTo)5aOKwbW-N=azMofQeJuN8}j=Qpw-~JGn^&}}3Vzj)_gk;M9Is>Uf zckT-Vbe%KgP|L?=TQ)^HQ@g?5*QvHKZsy)fPt%=D`bJZkmX$W+IpLaADm|FOQr43%Hwe7HZ8%rCC@5SR=J4TII|>b;`gA!n@;WMl zbdVh+Y}|$h1vscfKnDO-UrU)PF}Q#(2!GgJGXCP~%j4kjb7{sGMXUck56~KSI@J35OcKmQ9geqMgJI@Y@QTMIAiTna_?P$>pP9#tbt^RdP=R-Nw?8r_ zSE)S~s`8Ipde;Q?hB;sa(yN(h&%kZ1Xy z^DT(WJafHF_qXarCOyp-#AADHe#B-Irr|(($GMS=cw|3tWIP1zB&ZVCFC1x3othc8 zc>aahm6X%$kEKX4@Um7_;Kk^b=cL;@AivY^0mnv&N4sGKyq`TeswM_lw^I_(JL4LE zcPqVLLH;dib(d*WU(+M=pKd6mzV<4sOO*^liF!9&oIDAXxL6WLB_(|J*+=@gu_gTp z*}sbk4>4}XI6?k|ke_php3AX{41@QfDBLXHk$8AOmjQ#Ae#b7E8V> zAOOuioS03C%C-G8MlTz5o@?I4CaeW_x#%HuDy2mA%58ud1_@b9IJMx!*!EPZms;0m z+gP6nd!O2=AG-;lf(Q<680$fOTAGyeB23Jo{Q@v!B@VJ@9*O^GC#COYcv7tv6d$AY zZJP_1BP;dos>*@%oMB8g?WWCP>bsHTh(=R|a%5;iBtx0(_*- zxg$f@(vw%pkKj&)`=5CHOQ*eE_?y)LSMQaC%mG$k2F3_wwN9qdPf@Ad9Xc6R9jz?s z{(*@xDZd+xn(sf>Z6!S2H~{ENooA1O?(b~!mL-XDrb0ZCAj`n~30yO|80*|7JjDL= z@T=GTFvJVt>Em(xol>25ex(DqF+4jHvLZf|2}87KH#WGauYPAoUl}igGBygE9`Mgk z{1{*ctllQTS;9`6uLolkdQlVO$?iviXHT<5)g;%doGpOxWKz$?KEp=np?U`2GpE`Q z_l`WT5ocQR3nP@MnB0QWe07K1tTxriXeTAA-ka_-`>gxaRwglLR1QMrkt;(;bM{IHZlKzziq#P0i?`>AVK06f$H$dq$~|1)kYdjQ0nz~SK3 z_o1JR0XL9-4Cc`nn*xpgG3soZ;TM+_7ZfuwWdYF5<3+z*O=kn#Ql4BCV~mk;0HLN{ z*pg3>xGfOU+7cN$xT2cX^1g%Qwa^7OGKT6Szonwb?Wf5!xY+;v*XmbUyVOL zwC+UPjAwR0(Y1Jn#jHucm@65_LfivlY;*aDA?>j7+ab08w}$HR&&OEfME*jFQ0Z;% zE{7qoU8*`ykOw4oLX_Y+u)+qqx7xEo+EJrJ3+q3fm zlkNdh%cPdOrK%v-*z{MP*qeHCV;IRGI&6|HzdNzA#_pjk#J~~Xz$HKYvKav07T~kl zbYI+>=R?=sFaA2jPDkH7L#<>(!`9CDa{Z65+TVxUFqFzNwyl|i_8M*krDKn;&bgM? z6tU(I7jU?W;<&&*1E7;VVG+s)65%Lj(qy^Ur^{1m(H)krtlyC&CpTO7+U-)AysS(8LT+UMkW*LL<5C(?DWXvx8m71^dcn{y@YXo=TLxxTvSBk z*k>YstXkwo`5mUq5?Oo}Agf35xmG6JMt$c_@Bqdl7OY;L6Bwe!^Y-Hv#_ncQ$k5`` zYxM<{m2ZN(HZ!$F(yBAv*RuO6eyJ29axo)t<8|{E*0L@Gii$}ga)ARJ_M=~mj z5Y(*`+UVYK)v=yBq_0|j@xNb9{~tQ-gB$!e#hM3i%4Wbeuo`}vgQ)c$F~M>}Hns>e zQcwvkkttmO(+o|Og40|mD>^$FkulfVP@$d7RNP3&xIb-lPR}DwU2&4zEf$G37J`MM z3H?#YAd?8s4qrlL{{?Y>2a1izct(+&{2=RNKPp(gkJ^fshp3>vwWKHww;LK5=DFb^ zd(!q-2{)F{kqOh;|;rJp?A4>-hE@8_h_ z%N|ZD!?&lEJYJK{YTg;U)g)A)7Etc{K^kjp+bHwJs5i|GpQobg-=a(2eu{Z;Ydu$E z1D*1QyO%Y>>jr3){&~I!rGyQw=wUA_trw|4xi^*s+qkd>n~2pnvdD=N$18On4&y#- z>-f3)ZbwC^L72(7sOTr0Q@mf zBHXt5t{Q`4kXy)d^cr@0&Ge zXU~)E2lN97Il>Z(+L#$#@%Hu%|1mxOA3E*J0Q`>^O8!ipLR;C5%?gF}HG$AHiEvK$ z@n?#GIYUIjFlbGgi>wIy5Fp;dVmKrT6thJ!2cPwCHzl-W-;kZDJt@Chu{b6kN=n~a zq0O>=^=p2xH^;gzTCe%X(P}KZt!Rh)if+|kG$%)#gM&7gxfKuUR~f zSsD?@k2`!u+&9#Pa<;{INzx;A=+=!&qr&om?Hox(+u@4umY!+uDH?0e9}(l zlAGrd^s2;ad^M|c$=}eTV1oXjymw2%k&cKXN@&ziSp^VNTE0)(N4Be}TB>cFTP0jL zqi~%pU~_ooOUAS~bD*S`YM`N#@0xx5k2w% zwgWc$VJp$ye9%*Jpm-ObkmkF*i}mvs(kemk<*jG0D0% z-LsS*%rm4&4XE0ubY^3%~?{N$qp4Vy8MNK76?x|WB?axqqQWyJ_Hzz)jX7M zLf-m)nAH>HLk({p-VC`L^BKBHpP;Ch;dkC8Z3mR6{&Zd0fAy_Y9yR}BDr9wWmIp`t}Jmqj&|wQ}!N zMSEK{ewzSAC8Wr!1$m2L92b5U@mp+b6$T{(0j-GZkLxl~vl6{`U2r^K2F_+bh}X+n z7=s&KN6N(z&JuUi_~Fo2tpp~lBt@Qo>a?VS0{o%UT8L8;`4h0{lvoS^EUF`+Q=xxu7y#vSE1y6bf&*d@?Nnjga{K#vC_O*6 z4_I(QAvZ?V$=pq(ZWUYf_sUybHuW_;G~Ylr&OG~XnKq>ihS$NqV*3XY5mwffk#Ck#4Z@3^`c#tM z(F(!ULn_h+M;)Js4cylH-QcCD!4yk|%2iJf+jYF2{q`*=*2@)$&bFyzCds;mJ3|-> z{iDPWL);8rcF-s>283>?0(`@v$PMZKj#{?$em&r{>97?(Eb==S6WVrP{b%*_afE3) zEg3X1=>^68X0j3SS;YYj-J5nW5O_@gB3@2(jDkm`nCB{iXkO) zK&%ij(9!C#W$71$e4(&j@bAkX6dCN`R(I~@6FjU=6Us1L2RqO$vE>wIS<2pheCYE# z{a80BSJ%#xyL)e`R7M;?dS?Ue_i50&v|zH);(e;)&a%2tQYeVV{LIG@tY!e@v($~( z6(L_cf?p}fM=PJvNq0W`P@L={JBT+cS$$~Y6?%uDbjcWEpBhs4I$E~rmt30?#6&Mt zOC5~oIP5`}a*>Ll!Kmc3mpb@N%`nkr;VB%NxjjoQ17U!CJnvVw1|A{2d0ejGto+cZ zPa2jcN2{gaCVY3Em;l*Ei3E~gMe%0imfXso|M+?St<-A2LjWWfz=LVb7$59{hij`? zGXbg#NLz0`h$GFx(HLrU=P9DHUJ-d=ZZ-bBI*zgF@(hi-Q=~7L1H6tP} z*7mZqSWOA`*i18gK+)I>H^sQyV0C_zP>i{!{U&7)5g62gibkeVV+*Vgp><>aM|gSM<|*CWBng>+&Y?k1UYL(1n|X37?7g z`<4qs14WkrCbw%b1sBX`3v>PE%3jI_{qW2s4dsAPXe2E z3l9$NeQo3cS1RarQg>apzy>N+01%{=M1}W7$hwrr*!A=I2{;&Mj5~n}Y`!8i&?V84 zR1NeG^-9n_vrF^CQXI9o7GylxS;Uu<8NZ?$^(Dm0UdbYAkm>u+XO90?somp+|K=-< z{Ne;?*)zm^zErqe5{#EHm;);9s=R{01n~BC9d$?gdt-jOYKsG0dkiN}vw&fdvS@Uj zIcY)-?f}vQOA}2|Pa$)boJ}ila9A!KK@sry*4jxKjnF7|g zuSGUB^LhL;ehAYHC>^KXNEIqoa$2G4->wpvy-EE8>kg8OfwWpM!YmUDvt{TJv}4M6 z^CNa649W8%Ejpjh079^8?bO1&I7iWTz7=mHll7dqGro~XMN|p*s?74o>`G4fhC** zjY1^uyeNI#X0#Kh z(5XC83YfEvf_Y)h6d=UzElY0+wI$w6Of3BeeyBR`yciJ-)T@Vi*ScBJeEzQCRcqC> zsAFNpW-#)5KSb!NcQ}#F9OFyXr9=|63GHHxR9=twV7bh}^uY!BgY6%9{9CCF^hN;4 z2&iYUkaJL?#)iyr3}u{DhGNbbG{t<7@Z&OmXD51yL$4j00^1*DNws+-eOTqW;VMq! z;sS@t4F#s{)Xh<$W7XERPttk=g#OJ$FH4=6Vu-{_=M2q{6CO~E!r|H0T(QP}SPYfH zGjJjU6dSF3TB6*bGweqFniQ%3l;Mi7YcqSi9jfuGJOIZ59a#D6%)+cnrJJ*7FlvNZ zq2lXY4c`_%SCjwdq*L&K-B2UWvt}JdLP2F=DxJtSoCSWdNQhMt+?*(x_5M64f zo~DnF@-!>dpgBkMCd!{AaroRYfM!q_WX3CkJAy9P;8u0Sl&4}-281qrV5)_{N91&F z;`n!*m*5-b-XlR*-Sqs18pgLSw#GIMMr_7p_9ZWR>rx_>Tt31rB|w7csxDjED8>{b zHX5`vhTvT!KFA)iae(R?U~Ikh~OTar5{j`V!XdRH~$;& zyba_upN3wp)rC?%a!Rz~#&DtZl&BGvJ%sU)GtDIIg48m5m^pFAQ8G;2D7fbNi-gCP zZk`}mDApepeEAqWRCH4o)wZnxb6=iyX~{A%pd%yfmEg+*I>1nP50|=&7BO#UZdT#Ea_vieE7Cm1SX5sG;|HR{8O6^@P z0>I*I)y1kQ$iUImP?nr!Pq@&eZ1Rn4`J7>XCF1b*{zJ}DoRN0w@YKU1YV!Y(k_SqhBi5xG2svAe1Z40=vE@<;Stj07P?!G8c@j=9e0reSZjXnj%t!U&9@|ONo_` z<{8X_jt5pvDu3ZrRQoVFm#p>&Qd7f4A}u`V=vC$MOeK%sgr%3z ztSbP~0BZ={f8Ec86jZvwYSt_cmzmqPk=&dHpidOKoYUCYA~tGf;B82v@_Ts#JDh8$ z5|N(EI$WUp(I3ag1A|+c3%RlRC`Ds~;h+Uy(M-RE4U4=K_66=U*QV%^r3Id2@Y6`@ z)=fUIrE9l&wz%}%JeY8zm1ZH99*Ws`ZJ!O|O>-oPqvhqJGUS(RAUU^CT4Mhb57}>y z|JdLDZ$oW&-QU~6n@*#C4AS~ac~4hkQL-Yjh8{eR``>N&HlTltWWvV1onoB}DKO(` zJ{B^FAZIlXM}qUG8%XNLHoh>{;Pkm>seQZHOd9F2!Z zVS#*vSKj<2NXdQjKWt~#EUo1q?Z?orV4>_5l^aC1l9-mqMKfA;vCyj{LhF7BPfoW# zgbIf%Dk^=%GH6Bny*p@2GWH>sG*%?14NIaFlQ%YHFhO=-WL?-pJ6X8T?v3}*XuYoB z>6y6>UpilnCJeB1Wn@mDBd8~u^7I}U?-LEF2rysbY7Hr4ng^z|y2uf}v6Ecbc{t4H zyI|KcoAv%#9$f09OHZq>BnB{4HiMOlFc9j)SFT$_82vFopni;hLj=<5C37vupMb%jfFJ~uMRs~`?)C+^=)>qcNJ6r=h1rT~A$;z98Q9wgR{H})j z!`k=ct(10tY}mNOHwoSoV6Pxq) zp|$pZKC%4o-Q(X%?Vb?)kNz+;;o}_B#XNri3+-T~*z(~kYCnO%P@K}r<4|=*8f6MinACC<fF$jy<6W|HE3DpIm&xmkNnU?K@j}M;)G-r6HCfLW#teZLpvY@^MBhNtG{2cw zq#T^4HqHP=6iFM4f+|N1GYIGY%^wFQ$DVc>T(BD97N}Av$fGC@SLrGwlE;b4C{r`^ zuEGq1Bujl(3*jS><`mzl<6JA`)`hULt_(|m1tIcWp3gk8TU(~p60ju9zEY3AEYJm5 z66?|hI}7ep!ie>T5>y>?#dyGaUN6hnDC?6#Bk?8ckAr#N*Et_1Hm36E#8AvvmAQaF zGZce$SCl6~CtylAeiH_6=Wvr7lqS#|z>YX}*tUriXWg3>gK{=d&nV5)Dt8W67?~Fz z^!oDH*bOi^pQcH~3(b%CMyW1OKNp#fktomuGB6bmw_GQ6*$R2t;U;$pvLG>oMx1^m zlED-UJ5+naD^?X1#eP5)8Ty(%-U=@}5)M>9SJfifWOowL;QKbkoiYixxb*sw^*jrj zbrIUwUwliCS*!T)7%T=LceI-CrowPWq5WWk9JT7VW6|^5tlJi`P?WFtJG8h6EOmi5 z+qioq5a|r%asN3z{#&IMj{5Ivy07Dbg^v=rYqqHvMgW}>__?RH{H2fq((CI|aEtIhCL;vWyiyphY zSUzqvM^0NnKiXG6H*QGr*7W;bNE2h!jMf$sc4BnmSo}?0*0kxu<|6E6pL6L;oSVu+0v-?q`D(tzc+CI^pu_n+-0<)0q7`x1Mo zMCXl2*6KDY>eSrnkbImVl>Ii{)R+dbA*DVjPEp=fv+r31 zLbo}UEpmg-op-j-<4{*Z0neMmFS8L8^~SnofUIDkt^P zIXPI%pePF?ipJ1|M>M^k*M)CP1nWr{*W5#Wxl882KM+_KY4ka@3bnOA8{cx{(QTe= z+3LsfF077=l3xW>*apz2otPLvK2pYFDo15vvBUckC;3S+{ zdQ$ZibFN3vl=!6SF$O8zF5Edjd?%!n2JK89a{g@=xUPE?Qn z$TswT=S3!{p>L)>F1WVBS_#Oga?R8Uwu)P)*Evq2pSbrnF;Ph`a*QFcXgJY<=AnLB zp!CK>MiG4CvYf0V@N~*E#kV=OlfxDfX25TJ_TybP>4>k$;C;zXlm8~V;>GrY_w+C{ zl)j#Uo%M>zNN)8tLUQ@%^nlOX{HIbYeDyaB$Ri+*UFqqLhlY(IhJ&d`$`CP%j@r+C zzy7psI;?_tw=?mm3~m&RmN>We+$p^kQ}&mCn&!i^JMf1?&^3Kl*Z8fPR{tzt{;cvr zLNE;k3B?8@q4<8su}Gb37{VQNqy_c`9}2?q=a8rbf1(UCNKI<474Gz-oP6(4JED6a zkIYE6tH&8OJw8q|G7t)n4$yCxPF)vs!EG*xt*s>&6hqG6aHgYOQA#EQa1FhM&3jrg zs`BUMF{+-3`VJcJxjd^=_qX58t zk?Qck5`X3(pT~2WwyCDPNyxX^bPZ)x@UN;tvM;ZM*{2AoMt18yRvEIBT7h`k(suxB z9<&fkWviey3JmuEel)H$dkXbLwstWlu$TIjoRu z8zL7%geOEsZg4IWM1LVjF0=Xkz`VYS&sJfg$p%zT!kRXoxYh!{J1ESd4F@NR2y9*z zGC9HWOHMC1@xs)1900`fW6TXs510$;O+*uKMHWU^e&!F$R!rhB?~6q?_m>4BSuDm% za?8o8G05vr!#6TH2FS*%75G$Q4VO5DL=IZWVLPeN0m51gb2gh|YL~3No?Rh6&`=LB z<+!c?`EpHtCNWy8$11f=hS*{L{wE&)QfiZl;J=VA*^85_Ev1KFjS|q`fSG;RNIXNOqdWO-$mZ?PdDxvpsRd^}WHku?!tPCHpB7j9~@>dv*J+1yOQWrQ`c29{*Bm!FK;9X(X-*sf&n=L$wfUOTDU~=tTdt z&9*U(H#vNq4qCymc;~AaPWl7)=e^b|@v%EM2aHchiY49CC!mV8q-{J%`${E;0({w| z(F*;r19w{D;^Lkbym1+|i~~Yxd#d@t%hO1Ox@w?>bL-(wWIAUXW!_e#m4Qv-t_NU+ zV17dyoSi_fUrM97MP2^Fp{r7apg?I!w2ZiVuJ;{CLzj+>>HjbY60UQTq%EzzCZ3iO z(G<(P5+LFgSIHXP{!s$p%NSw$NH%E}s6N_*m>epqf7wkR7WkKbpF=haIX9M`$>Ce< zxw>Y~BQbYlDB-xABUR?k*)&*z5Z|bb0Uw$eb#_gIe~jeh*gdf9jJ>ZT+$Y6Mn$7<1 zJWX5EB}-6y8@k7>wBeI~k=aKcsO63%rk1&}^ddkb^;mfGxSRM19bz7eo|8oSOS^JCppU2QfIn5g7^4PPmvt0l8#|(0<_2V%5-ikaA0AM;j7{F}N1|7n^9I!l% zJtb~X3JBZ$W-QHOn&`}vgTTsGW+4!ebXQ5|1STKDTL=)mznAZ4Q5X)I8R$N!Y`EPx zr#1y5UYGoVflMVa3DswtcYa86{@1midjG`ZUrKFNKLS9(H{0u)0#lx0>fCT3$OWJQ z*PR>weKcc3WWLC++7b9E^rMcYOOW{|gSqddJ_+Tr9;&twtT-Uh-|CO>EP$wTO&Cxh zGB;`qt7|CWct~`Rmt&NbE5vV{;DD#9^Z~*%auA)Q&CpBCw82oN8CU!7sf{Va5Px2c z&+@pPem3d8xddw5t}NI8=qkMGl3TE{Enb;SSw<$&Z~2~@u~=bQOSs^=l&J`|yBisc zUZAP0)tIXGCd^wC*6kK|RlMagW*}b|$}ul4J8aN2F51*RQ%+SzA9FE=aj4%>;yYe; zOqoZen z%UyB|$T(87d(lybw$t?%QO$JN&H4tD>p!^5D>fgR6nGkttuT%DQJN)iE?+_apnltlxsk>}-H3YWtAEB73QkuJGUh3#eGwxza>TQ-vapLqPYN^My-0zea=)gg}!6VK2esXxSa zHgP(fxf|69osC7Bl9>rnGx11%7ndK}YAEtmcHql1RlMUxH3{%NY!c*J_Rk3!yzeVX zLSFSJjIa-9+PWk$;%ZC+#)%ni#W9&b1DM6i_@H8{{r4l6aNm=Heb6x%9z*dPr+B9D zebQ|AD^}&(12Xb3tA`3aF=?EeQN`_vB-NN1jPQ#mOOp=z5A9bXdb*xb*^hB8+c8D7 zPXnx+lZ-Z%=th!zfN3p@I&Z&4SlP{Y@@xbY-nCYwWOIDT|31{#CQ1asKuRwg!E(W{ z=*oQFPsD9CTj(b@pnW8)YawByG1pRhYS;fJRYw$PO*?#?0b~Z5WIZnC8+WeV+vYr@ z#7IM}Df2iR-o*mkF;``FjEXWDe{T6{yZOVlomcGK?y|J&9M~An-@SqAK7<0~SQ-29 zJ-VYeVZWXNWe*Nf;2sb)j!OICq<5`%Qfcb!iiI0BT`~@0gAT!{+gABCn$&aV&2%U` zv$1ky2DnuyO24D5#RM|VoW@I*W_nx3v;3f5ww=Sz&a8zOGjSkQcp+XmM02eY)rq4y zla7EMH^lur=|ROpzn_&lVvgwV;Z(hFdw`wT{!3!@VHD~XQq5(UwHy>76~l)aY?iP< z6vR4M4scU!yfcU7x+1tNv`TtK+8AsHN|YYqkZkRL!Q;OwwNm-;KdOLVks}BAqFDne zJnPPxXa{7qI|On{A&-ILx!v}W2qHJ(s)R{1wqbCl$b!>tr`Qu6 z6fe7;_uz$d)Ig8T6cs{|_PvyzH&9w4VXWC>9+CYJ)(#-USP(Xmrbu>0LLO^>O(W_J|hu0u?;Wq>W|ILiSLpg2hQmt2{lPyB$zYg2kH53GAa-QQ}odN z>MnCvWv4{An5`^Dbu#k(FD`d)7Sjfrj*RU>M`!oa7&!tRl^VvnO zMtw`CLaBVLmV(8zqW;lt`qWV<1RR7iRM=Ui81CzCm*}=K*v4pQd+y<&g8~V;#oi{P zUC!|=a*n!Ej}(Rs1cZXx-&@9{YKIlWzZ$2Hb87G?^%y>K|DMk%8xL%88LiL|&>+Zz z+k-=6DC0f4G0g~911Gs z0Kvy4;7^kXST{lU88zJ&4h;6&kP_`T7*13WThO*%Gj;MKZs2?lt=1G<-{7)T z2I8*QG{l!W{H6=fhGJhuY~@MuQC#ZpojB`)WfJSKhh>Pz@MlhFWhSRk8$qzLWCoPu z-pyjq=qRP-E+y$o4INWjSgY!hS!))7Cdag?Bb@YRv@>~_&cm^Y5<5z5{u_9hZ3)nD z7*n6AqxJ@Gp;U=5rtD#s9iCdgmJeOt>$PQOFeQGu6#RYf_SkE*jJoUbRjy>mMDj^(4{ziqhS%^YvugF{`Iq|ssD_lkNZ;7rQ7UHy!V;sI#zy7O_kt5YhYOTlhh6P590_jahLM6l??-4sTmvqOA-@j z-UlLKW8@OoN7xgbh`yBxJRy^|ZUs|x=Kfu3ZiO?C3A$f>y@9y5 z`BKK3p8&S{X4}2)@{{yt*j5U(Al18PuSd>9NOXOw#_GKIpnx!jo)Kq5SRw=7Rks6U z+K(LC5&@X}2S#8p>wB?cE@{>~J@1}Z24-vx1JFj73}p<%SCM9!=)?+hFDlOlp0;}C zBGf$VjjoRxGczEFcYil2n3JBpS$nY1;u&8l%o~H9T!6^TinNf2geB@rTdRny+zu9i zE~6J-cjV#BY?yq54cmCAl=`TKy`U0n_o?C00^pKL-W-fqQvMb?ZYsqz-TsZ0<=H!7 z*Fwo&IQueX90tR@4$!v--UN=@FG(z=tBL8Mxl|8G!f(&B+2g#N#RXRB%rt#n*)F$z z&cIdB`HVye9ODOXb++{tA4gjz`xqwAJJ-2uyi%_=G@EZqfSIhM}~M9`8Nxr>6-!t04DiCR0pF^u-e)&er%q|Jvhi;7#r(3 z9A#;;yH?gEDKP<(YI?L;{{Xb1u$4BAL#Wb4twBYeW+kxQZ84FkYI1sXGvtZVUx%DMOyjhTi#Ozd%WnhB7Kfg!$F57I%Kw z@7Nq-N_iIo9r=g_K{NO*!><^Nj8soHci|uErzne{&rzEVB@wB5&q;snZF|6RQVha$ zFMI^_yTWbK^uu9O4DE?e=p{oPw!6g*uOGS-`__IMS0NE8dr2_-exzgwv3F2K3SvBf zfm)K+KwM7&c%M4@F>Qr@+=KHS$#KJVH;?i^TS(ZlbHVgi$E0<1=S|y_hf-s>NO8%o z+b(9BiU4)DI^0R6PQThcixg@Ex0+z2oTz37l~*DVH|y__xoaKSVcl+$5vytS`kA;j zQK0>DJpq8mHJk$$g@bl&JRQwBu;<@MnR=kmK8S z@m6(#6hA1$+Sr5Q)DsLm7%;vdztGV&9+q({o*OE$d6+j^ghrA$7xGU${?$<1+=~DZ z@hY;zSv!szf{+!wsZih;aOB@_o2eAqT||QU0*b6w09&$~V<2GDMnEx%1sOUB2RTL_ zCVMy}zF6j;*A-b^OJh#0N)kgOy`qD(>7HdG{v0!t7|4Iwb$oeMPbUEV+Xvr?UwIEfr-gsoVDm;9cHLx<=HD7u5zL~{1A%N^g zm*>y*@e?FrnatFev)OE7O&u-jZWlhOxs6N&r43KrI9F@=*_#6UV zD+YoXGb39;m|)=~Jp3>m`x_yI>yZX0>G$55yj8~b;rocTCpV>3H6=aH?|I|Qo^g5sh(913ul_`OaDwF zdH^R5Tx&&P5XX4u6+ZDs>qNh%29m4P1$jhn9vbd<&{9bb*MXMU-F&QJ|2T%yw*@q6 zwu6Md3|ih<-+tC^dxR5w(53?8Fe4;ua^&dq33~Igh}V-GzA~qP^IKdXnPn|7&j-2A z@S5tKEvt2$$0rs}U7w5|13ybp#1)*t;}=-NDQcCd-Gbj}p{OB08eb0*uXT|*QU>IX2Q zxX9-e)@+MliK48t@mf32L@llp;PCpq+|A*U8ZEw=Sm03>g^GR)<7@h8`ar4vDOmFn z_@$L^A!UM*V{-w-BUW4TmFp3X+TNmHK8f8ja2`zpw8d7{*Et!_)h&x^FWAs;w>mw` z?(z*Swi(C$1|i?-ILgzdd!q>g!&Fyar|+2g}0KP)0KQ73FJEqe{dP? z)BL@z<^>+5i&t0aCzt`Y=)67T<`}5DLPWHph}FXJa6<`+T5m+#4Y(wv|r($ zp}(MBxHrTy&}l6yWk_zSJ!nj`W?pqM^q#ilTBZ6+bQeOSz*zcFdJnp4+tyBrJv#Ws z$;bO4p4b2vYk2cL2Q1dK*;A}Gpn-A^7Lt-&;oIPsx}I(Q@3^@mv$I{#vGQo#wu#b; z+$<3Z(>7S;2FOlN&QrcgSUh6ZAT5^Zi!Zk! z5SMSf?W=7+mj(~Ua7=$$Lsp|%_zb;^lz{?n>l5r&9gMzZd6FBj##i03IDU{5XA&nU zkvaL?jnLhqo0JV0%p{%1yubK8N_~?mj0nkw!g&W^fF_m~7%=As(B1;F-33 z*^8%Y_D^~I8&bOjjslp@iV>3-*vW?4eXoMXsiBU8gn6X&;PxEO%d7-xY;~91f7jxyn-ckEAN@O) zN}g_Ic(%Ze^jd(PM@RMtQFn_0wN< zmJS3HTg8s4+*;%wG3N!}h2=aJM|K^QwHaY)?ca-0P2esV9;4~ho{l^pNid~u3?EVY z;AIzC9@`6gM-djBzO9YPe%maXkMeqhJOjNT6A2+s&=&!zZt^{VVVzz0oIHiS=kjo*@1ihw=nAy_-10|?mok#jzFUs~A z1lM1!yeuP1>4$Dd;=t$gp?ZSJ3Lz#tBPNPaYXs;%5qQe0NwJ|jEwA2Q%qvVaZNwqx zDrYb-Vg}-Q5lv`F@4UWs<1u6oF!#Ql?M~D~P0O@Szy6pK{F@eHc{y5^cjD>jMD zR32q>w0ZyEJD0z0v42NuF`0lLp0A9y+6VyM+xKlH5=fY8)KSO*<&)y5Q<^Jp-CnU) zqxjd;;YD2!;#+@jdp5L3wKD&Xbmdtlfv*^m=H zZKP&oTxC!j1X)F?T)!-b60Cinh@laHOG1kHEo5x@Rc=|47x=-b^j+OeR4V%paViqU zH=(STW}P(IzW1X_3(( z4qSZSD;tyyZ>iT9QK)Al&I@If0R^)F4QnQTgJ*vYIR4cwq9CH^*rc%4UB5IgTz$&kOR75%q&tEL{P~$Iap@P;hCpeq(0MRnjiI~~b zMhx;=$v)NS^7U0+@3s7~_3;P07wY8u_K_(015?uZcNG_?BEa&>B$6j!V`pgw=p z5)rm~mcA9drWBhbE-&FI32O;4So+C-IEMLmvqvJ$=dk)3S=BNp?7g*LAZ+cxT8 zFsrcnZCtCWU_VlEzMAY^{#_`QFLx@wWa@YRA!1UJV*risz^!`Hw#07D?5Mq9z@3<^ z%w*dawC(KXV}Wdq?jKg-?9@&qOnt3YPNaaR`WtSA`XcMLXHZ9VdIl#mGcJgG(sS8V>1?W`zAiXYH@4O0nK>RL%V2XW_HV5x+i$6Qh zP&(twif_`Ag(MYs34%}@U8rvHd@2J6=W{A>2pSDGYqlu#Eb{*$?)lL3@jP|EBobmv zMK_Bd`#a`@cwF1Vkj?6hv^W*=`-23WEC9lqa`7u0*{1fCLftog`(k)oDN?BJh=8@P zJY5V3U-RoI)hSmJhLLm#Sjr*@SSo5`IulLo^B_YCE1ghA1=5`MW=s^bh}3hweSt8Q z{EDC;pTj#p~U)LKr77$70qwZ2z6a zPe?+H;LhP>nXw*EI4&z6e-bDfzRP*+xI&QGUQ!%^oHAr&{nVj4fA1=E@NoDiUId=# zx(OIB2aW+%(*p3a4!@2HW>FfUEcVzxncA$RW(xu!o+Uwj(y^Gt>C6gjGd|^N= z$Lk`vm~H0}OHprnhA`6JW0**PVf}#Jgns0p*|0_Y)LA z5S+LJ`T9&Xl?`ahbYgo&R=7PFlB;0Vam6Dflj~DP>1ApZGaIF7a z{GqcwTvK^}R5WC;4gaz@loR8uIAgTwqs!J!V}y!${bKcbbVFCVCU^lC96je9zvj?iK3J95wa&-WCF^ffM4uIEb@2E=wft%ddTLrR*DL%k>zb9>Fx!k?Vz*&v&t5+B_6hkzwmWRV3(VD&Hwy2&A( zH$G&x@_l(9GcT>k=YcX7ZK+r^&VTRx>@UB>XobG1NB^9qP5P3I1!;>Q`Tr!Yff2wD z8;YItP$T*Lg08N+4K0G%B`od!H&?RbNR1YvseALMW;}ytFNORrXB~-&iBc~#LP}w) z?Eso~hUy{T;%g6 zqf1E4S)PHAMjLg0-u0|gel!;;2)4rRcR!1r3sLNYBDu{Y+9k4pc4o)RW@L8(ag5Oz z&|?-meeQya5*3zS(t=sWMy&q_#9A};wf!!Im@i@=N`5lf2Fn2jPPsw7qs*m%ZfP8J zAFe-1rK5u9mQYiK6%`&Eno=tsNGp%L=S?aw#Y2oG5{HZ)nr~!{V6HVz{-hGSmliJD zt`5t_{)b1o_#86$=OF{yZ$x?&YpQ13U4)Av(NF|sk?o&3%l$j5CNr0R+~*$~riZ92 zMv%=-s^(JoD`DfO()U&e-yXSj7$sBxzB4e2dDaXUf8bIAem<>(owxR(*u2Qkra>JK ztjaFxzq_-=UQhe({0%_r#%zB0%bnp#`3R4@Crijc;Xv+7V{msxjS<`040n1gXHjseTw%{(7JMPwMP0E%3wIECzkT1$66MsmqaggsWy)jP&hlliZQ&{Rq+& zlCQO--NG#i6_I;WbIcw8gyAv$Ug(Y=@~4`8ZBuF8{hhsjP4eS))!>F}G}i7g(xQ*z zX+J%2gZ)C#RkB+oSdjFkhQ?Lb&XPD<+Z@dfu}ff8Ma42ILFjYZe`_4L-pE+HFed)d z_xk5DN7D+`9`E3%(^NH;9(5)HQo^`miGvX(GL?52P!H`&d!jrK}}5T=A7 z629-Kfzsv8=UnH6a_v~E!>C$fL8h}{ruxeyhzU7f4M#6GKD5zmUfr#VGm?qqhYFgw zfMPqTJP!{FrMggD7X^xZ2gGex02KhaZks%vSu1fef#Xazc8!I~^|;DmxQ~3S~0laGHs3Eahnf%$IBn6cE2=|aiQ0_;=QwiQS4LrTm@<-R0PqsYQDUMaVYs=l1XO6=XVtm@Z4W z6&fY3d#bydW5g2IA#fOlbpI3^+<_j^9iM*aLV=vgwaVEt!zLS=dUV<+(bL!)N&!`= zN!g1PY0pq|*5A&33*I)SeYWWx;Vx>Buc=k}Ew*uJ5rMM1P5bW4vsDDors}kG6DENr z(Fu&Po2THDS{j8$;s`h7meJCBy~WxH9)s570rLtCBZtZNtSk zCD_PEuWXKT1xlaXyB<-h4yM4Hc{Irx>Q)Q=GF)5ZmnjAp#p2CJW|IXRxSL3*gvaTS zdVsH+J0>M3satgRL^a-$R{ZM&%==bvzdo^i{Ha)Z2DGw_KXQ@i^5Wo98bQiU3vrgl z(`}#(f1qn5OX!sD>6x#m)105pbP>f6oPok*`>+fa!q*Yh`_I5X&ZV*xIL`eFvQSp%8Lc^P%*_A-Q`-^ zgpZiuSqxnoo@btbW4_O$F?k6GbDhN}jV_V$y;hGb;mrJE9Qs8j9D03(B9|G$5cy_T zEoSvjI?h$bPcX+Uyc&b$Sr3=JPF_zy=3T`z{H>}ydQ@WcCJ>x}3=@W~`NA(p4|*iQ zSGuP%Hd2mzLp&`pbIlqtc%2+&WCF^rqP8Bj-P>F_w3dRNeyoo43zxZ8B8Cy{%$)N? z0n&`6GL&%Uy3=q!`KY?CTWp- z;ii9xksVx-Ya`+aiUt%y3+A(u@TkecBGQYfV5FSBRawmxmoh53iSMr(ee9y05wgR) zkf;r#(cq!NgwbU&puSe@MxQ62$(hLK0?%Utb&VQsX^t90dKjikW5ZFtvsHTElT`*r7qr zlxK#ylt{Y+figP{>^h%<(D9pg?iZ($)F9?)V9+!*CE%Bh*%E1&LN`vPk<@JVN8P!yRNYe+0O^|~@I%N!)=LbU4ZX8?<*I=b)dSA)g z#-33d9-maMA{Oqc33EA(GjKxaJo zy`&~jrLM?LFB1}nxJrR=N0KG^Yx@$N$Oc}`{a^CqGp^4B>OqBR@w* zW3)P5@`#@_05A2%G!(w!^~l#23iV6_sT?yi4wkFb7<>Ob5D_Ql$Et3DA;Iw!{amx)Xd}8ur&(d8agSj++>un z4N^O5?F>D~6gG0yeMnZ*6;nv%f8BISFEAM}rIn29(8ltJa~FOj5?9Q)bWVQ0Vc ziFZ(*NuItbIY8-dFzg{u9dX_{zfuIiU=t07yPck@@M3o_& zZ_DR6hk7RZ#F(j9E1N3dMJ}kjK?UuPFZ?XGxk2DHACHfDr@2P@e&utIpK$JoX|=pN z72JHs1;396lPp7N5a*I$#i!^Dn9?&fDGPRdRUkdNMl*Cg>bjUke@6GoULnWN_Y-I! zuxQOI3drN3MF1`9k~e-oe{e>7QG**|fqgr^aJ*RT-Hj&pYyhvWghE~1}3M3=a?r2~GW;{_r~ zS@WZ>ZAj-~vrmxX$(lOOW)ax4Wj@z5(14kQ=L|%5DaCtHycWa?PA)HW&2wpj>=v8q z495`hC$*i?17!J@_VEHv`IA@t9Mi90l@o{3F_EYBJFhbjo|04wzwBeM8zgN!X}|5d z|0J?O$m!rH=C;0F%*_`^ly&G074G>ew*z+H&88%7XTI|)95AAaj|x>V38=T1N_i82 zrY?uf`vH7q#BsZ;Bq1Nl53A2D{=>_za^r48Q~SrezT5G0^g5IAwc$YTl-*Cf=7i?2 zt^Zu`v1zB%p-)>42@in|^`6B~OYX4a=Z%@)BX5w+F?q94ZjplgytxRCrLJPs4lDkX z@QaPdcDJOuz^ewt=cSPv$NCuvW$7H<#LhPv;i!;g$;*zc2~f-rLEEkjbS8LO^qLAC zf1xJ0%|miQTgRLXYTmfJg=Fg%KkQ_sci4lK0oyrteM{Tl$=xSg<>o6jzy5D|nEw4- zkp>^FD&l~@!T$44r3Qm!i5s?PKnN;6#L?+>nv&XFg%bpoh7|o`NhWI zgbu50#i;)S@`2;SDMM1FBjAk{W$X6)$Ep2OmAA;?6DynJt>3V_b@0Bh{qa2BW!5xp z<_vrbXLXza%nCQx1RXreQ#(nE!&-2~EI{lO@JPq8z7qOV)~X>fOFZ4bE_`Y3)A3*u z8=dG+ZbXWvs}vUQUsRBssgXqf?qU^xo`QS3&!dvhWNF~)`&z7yEEo5=;@g+g5Kx7X z?J>Jb%DXk5X+*?_s4+}A{jZ%-PJ8h2naQ|}8siPWb;|=aP}6=|agpcU{`$F=0vyT2 zH+Jv2hpXBR?EW@y7JptuvGBr#r}`B83f&HNCW>4^I@N#)6yBdgo?U}i*>^OcBQR*I5Dwgy*?kJ`e0)dk+> zP{R?vD~>wTX=9}dYJE0l4+Ufe!>-OYiL9Ur8DNhoJGew)hH~hg8F0o^OdiVljaek? za58llv=tyWad-_7V<=r}H=YXnF|Y5sDrC0+DbW^%9D(H%puy=Lfym-r0p*E6PgxD& z`@BA|xhcTWpIEo-6&NBkp*ACZu8<2oL!Ks%0jz$UU%53&qQen$9p7C?{xD$aY&?(K z+^k!f!k3w=5M(7@wvSxTP-=y}gtL41b*`;%>=!Z z_A;?yOpeN{F8%d|yR&IYUIFsx$9q3JES?<+Uw<;xIbY5&+O(h_ZKA6If zeQ8CRM_fOKyX-M&?GNUn1LZ1FI)9`1p1peqj}Pe82`XYw3A^l;wYb7^^7){%bqdB^ zDl+8%?9WKV0Jk_(+eV!fW|QCq1FF?I2y(47?I)EsBSOHcQND~8_EvtShj+k!Smi3= zAN}MaE@HR17cNoVCM9Jed%WvF?#l4NH!|21251LIf>c9!90fxG4AYk-kykkLTM4MG zPg(e>w^fl%H@JDbC2V@_#oQ0FMf4L6wT5u3wrDCXOukd4xp zulSb%y-8FWi89GDFW-8?*}i$Id(pHk-WDoN1fOS*iEi;+W8F)5BQK0=CoaqN*+_*I z+cP*MYqcdER@Y7OFh%}&?a>h(bA35)hV|`Su&-IP;e{NP>UlcvY({Y=x(sOn^hv8<^<%tbC zmI29MhU1Q$`XEpoiNv!ISst9{e&yvY(1iW{>N=SFbQD zT2TKXPUJCTJ?os%PS9dD;^3w?lM!L4pVMZc;OgWn>w`u(D9*9p*a{~yro6>X!msu; z*gxI{5VcQ(xG(fRSOub|>FlC0HN2J5i$Ktu)(dzYw5;gw9o#X+Sqf8<)(IfY)_Oqw zJZzeAfTW25hl0VADH(7;Cjed9n99fp$XY^QJ0_whE4{Lm@3Xn)oLBt)eNWwam2FVV zXw?dSU|P;MkYl1uz_1#}Tl#(EByNK|%k%M4(+Rb?5P%8>0E+^rfc(?-06=gMPC zudqK99JJG)P1rx|T^Uy3J8g|qk@XJdrpl!Zdu6W?Eu6diW{tOy^x(B?^F(+56|MH3 zUh;)DIgucHwt=I*uGfeH!;tF}+D;pvIS=J%FmiMYeNldPbZ%&_+ig6H^UnUoMLt0U z$!|pg3ZItU)@IlBB9x8HOE>BX()<@7E_kLxmJ#_K!86WJ{Zg6qGePSz6XMj3B~+ol zL~`WcC4Dan2hnMDs%nE+aq|H?zuPRqr`;`Y!(JllZsIia)O6GZTv0}*`Y9>!G^P?R zZI>(z*>I(kY$VRU&+8t+Fv{e~osSHm^QVO=MBy<%Ypsvr&mG+uwuByPbW^?V#lb;? zI@Y-oCKn`*n&McW34&qg>YTjM8o6fdHP`(*Xk26(SHlDCi0U)O`z`zBeBhQOloZ%} zG<&f1j>>?g1x;@V8^*teauBbMC!G#>Cbn~^O*(h0BP-S{2j#uTKdT6)1DQAd1+R}R zg^o&)s~O&B{j!VD4m|Q{ z02vjfKlWiaypC+C^3DSL!cOnUhTLpok O3DZj$^<$K`0{$1kdt_b! From 36a806e8bfaa513dcf95534814dc36829ee5e8aa Mon Sep 17 00:00:00 2001 From: Ben Thorner Date: Mon, 22 Feb 2021 16:41:30 +0000 Subject: [PATCH 02/12] Switch to 'make' for running app processes These are simple enough that they don't need their own scripts. --- Makefile | 4 ++++ README.md | 2 +- scripts/run_app.sh | 4 ---- 3 files changed, 5 insertions(+), 5 deletions(-) delete mode 100755 scripts/run_app.sh diff --git a/Makefile b/Makefile index 48ba3342a..ba2855d57 100644 --- a/Makefile +++ b/Makefile @@ -22,6 +22,10 @@ VIRTUALENV_ROOT := $(shell [ -z $$VIRTUAL_ENV ] && echo $$(pwd)/venv || echo $$V ## DEVELOPMENT +.PHONY: run-flask +run-flask: + . environment.sh && flask run -p 6012 + .PHONY: help help: @cat $(MAKEFILE_LIST) | grep -E '^[a-zA-Z_-]+:.*?## .*$$' | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' diff --git a/README.md b/README.md index f2f06becf..6314f6eeb 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,7 @@ Your aws credentials should be stored in a folder located at `~/.aws`. Follow [A In the root directory of the application, run: ```shell -./scripts/run_app.sh +make run-flask ``` Then visit [localhost:6012](http://localhost:6012) diff --git a/scripts/run_app.sh b/scripts/run_app.sh deleted file mode 100755 index 67eb6dd17..000000000 --- a/scripts/run_app.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -source environment.sh -flask run -p 6012 From b2ae52fa114a7f1d7a8474de2ca4ada818ec4c74 Mon Sep 17 00:00:00 2001 From: Ben Thorner Date: Mon, 22 Feb 2021 16:42:23 +0000 Subject: [PATCH 03/12] Remove section about virtualenv This is covered generically in the Wiki [1]. [1]: https://github.com/alphagov/notifications-manuals/wiki/Getting-Started#development-environment --- README.md | 38 ++++---------------------------------- 1 file changed, 4 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 6314f6eeb..6428dc0b9 100644 --- a/README.md +++ b/README.md @@ -60,37 +60,7 @@ npm install npm rebuild node-sass ``` -### 4. Install and use `virtualenvwrapper` (optional) - -We suggest using a virtualenv to separate the python dependencies for this project from python dependencies for other projects. - -Install [virtualenvwrapper](https://virtualenvwrapper.readthedocs.io/en/latest/install.html): - -```shell -pip install virtualenvwrapper -``` - -Then follow the [virtualenvwrapper installation instructions](https://virtualenvwrapper.readthedocs.io/en/latest/install.html) docs to configure virtualenvwrapper for your terminal. - -Set up your virtualenv: - -```shell -mkvirtualenv notifications-admin -``` - -If you need to specify a certain version of python you can do this using `-p`, for example: - -```shell -mkvirtualenv -p ~/.pyenv/versions/3.6.3/bin/python notifications-admin -``` - -Activate your virtualenv: - -```shell -workon notifications-admin -``` - -### 5. Install Python dependencies +### 4. Install Python dependencies Install dependencies and build the frontend assets: @@ -104,7 +74,7 @@ Install dependencies and build the frontend assets: pyenv global 3.6.3 2.7.15 ``` -### 6. Create a local `environment.sh` file +### 5. Create a local `environment.sh` file In the root directory of the application, run: @@ -117,12 +87,12 @@ export WERKZEUG_DEBUG_PIN=off "> environment.sh ``` -### 7. AWS credentials +### 6. AWS credentials Your aws credentials should be stored in a folder located at `~/.aws`. Follow [Amazon's instructions](http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html#cli-config-files) for storing them correctly -### 8. Running the application +### 7. Running the application In the root directory of the application, run: From 8704f4dfdd3551638597f896b29676d06307c09d Mon Sep 17 00:00:00 2001 From: Ben Thorner Date: Mon, 22 Feb 2021 16:44:13 +0000 Subject: [PATCH 04/12] Revise section about AWS setup This is covered in Wiki in more detail. Note that only parts of the app itself (vs the API app) require these credentials. --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 6428dc0b9..e10a3e2a6 100644 --- a/README.md +++ b/README.md @@ -89,8 +89,7 @@ export WERKZEUG_DEBUG_PIN=off ### 6. AWS credentials -Your aws credentials should be stored in a folder located at `~/.aws`. Follow [Amazon's instructions](http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html#cli-config-files) for storing them correctly - +To run parts of the app, such as uploading letters, you will need appropriate AWS credentials. See the [Wiki](https://github.com/alphagov/notifications-manuals/wiki/aws-accounts#how-to-set-up-local-development) for more details. ### 7. Running the application From f6cdf999fec3ca83e658979bc1ba413fc6d4a98f Mon Sep 17 00:00:00 2001 From: Ben Thorner Date: Mon, 22 Feb 2021 16:48:16 +0000 Subject: [PATCH 05/12] Remove unused files in scripts/ --- scripts/__init__.py | 0 scripts/push-tag.sh | 55 --------------------------------------------- 2 files changed, 55 deletions(-) delete mode 100644 scripts/__init__.py delete mode 100644 scripts/push-tag.sh diff --git a/scripts/__init__.py b/scripts/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/scripts/push-tag.sh b/scripts/push-tag.sh deleted file mode 100644 index 5a74e9a05..000000000 --- a/scripts/push-tag.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/bash - -function pretty() { - local blue="\033[34m" - local reset="\033[0m" - while read line; do - echo -e "${blue}[publishing]${reset} ${line}" - done -} - -function warn() { - local orange="\033[33m" - local reset="\033[0m" - while read line; do - echo -e "${orange}[warning]${reset} ${line}" - done -} - -function get_sha(){ - REF=$(git log -n 1 -- VERSION --name-only) - SHA=$(echo $REF | awk '{ print $2 }') - - echo "checking out ${SHA}" | pretty - - git checkout $SHA -} - -function get_version(){ - VERSION=$(python setup.py --version) - echo "latest version is ${VERSION}" | pretty -} - -function push_tag_or_die(){ - TAG_EXISTS=$(git tag | grep -G "^${VERSION}$") - if [ "$TAG_EXISTS" ]; then - echo "Tag already exists, exiting" | warn - exit 0 - else - push_tag $VERSION - fi -} - -function push_tag(){ - git tag -a $VERSION -m "Version tag for ${VERSION}" - echo "Pushing tags to github ${VERSION} to Github" | pretty - git push origin --tags -} - -function main(){ - get_sha - get_version - push_tag_or_die -} - -main \ No newline at end of file From dfb767d57e5a992e60d299ce0f8904c42f3d3f31 Mon Sep 17 00:00:00 2001 From: Ben Thorner Date: Mon, 22 Feb 2021 16:53:54 +0000 Subject: [PATCH 06/12] Move bootstrap tasks into the Makefile This is more consistent with how we run all other tasks. Note that the virtual env setup is not generally applicable, and developers of this repo should follow the guidance in the README. --- Makefile | 5 +++++ README.md | 2 +- scripts/bootstrap.sh | 34 ---------------------------------- 3 files changed, 6 insertions(+), 35 deletions(-) delete mode 100755 scripts/bootstrap.sh diff --git a/Makefile b/Makefile index ba2855d57..b75f7d391 100644 --- a/Makefile +++ b/Makefile @@ -22,6 +22,11 @@ VIRTUALENV_ROOT := $(shell [ -z $$VIRTUAL_ENV ] && echo $$(pwd)/venv || echo $$V ## DEVELOPMENT +.PHONY: bootstrap +bootstrap: generate-version-file + pip3 install -r requirements_for_test.txt + npm install && npm run build + .PHONY: run-flask run-flask: . environment.sh && flask run -p 6012 diff --git a/README.md b/README.md index e10a3e2a6..83fc09861 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ npm rebuild node-sass Install dependencies and build the frontend assets: ```shell -./scripts/bootstrap.sh +make bootstrap ``` **Note:** You may need versions of both Python 3 and Python 2 accessible to build the python dependencies. `pyenv` is great for that, and making both Python versions accessible can be done like so: diff --git a/scripts/bootstrap.sh b/scripts/bootstrap.sh deleted file mode 100755 index 28243ca2d..000000000 --- a/scripts/bootstrap.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash -# -# Bootstrap virtualenv environment and postgres databases locally. -# -# NOTE: This script expects to be run from the project root with -# ./scripts/bootstrap.sh - -set -o pipefail - -function display_result { - RESULT=$1 - EXIT_STATUS=$2 - TEST=$3 - - if [ $RESULT -ne 0 ]; then - echo -e "\033[31m$TEST failed\033[0m" - exit $EXIT_STATUS - else - echo -e "\033[32m$TEST passed\033[0m" - fi -} - -if [ ! $VIRTUAL_ENV ]; then - virtualenv -p python3 ./venv - . ./venv/bin/activate -fi - -# we need the version file to exist otherwise the app will blow up -make generate-version-file - -# Install Python development dependencies -pip3 install -r requirements_for_test.txt - -npm install && npm run build From c7423bc8caa3c948c7f156bc7024d3b84984fe87 Mon Sep 17 00:00:00 2001 From: Ben Thorner Date: Mon, 22 Feb 2021 16:54:56 +0000 Subject: [PATCH 07/12] Swap FLASK_DEBUG for FLASK_ENV This achieves the same thing and gets rid of the warning about being in a production environment when the app starts up. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 83fc09861..f93f385af 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ In the root directory of the application, run: echo " export NOTIFY_ENVIRONMENT='development' export FLASK_APP=application.py -export FLASK_DEBUG=1 +export FLASK_ENV=development export WERKZEUG_DEBUG_PIN=off "> environment.sh ``` From ff035bfe8e8f8f36709c616d485c3561366dde87 Mon Sep 17 00:00:00 2001 From: Ben Thorner Date: Mon, 22 Feb 2021 16:56:09 +0000 Subject: [PATCH 08/12] Revise section on setup This is now closer to the recently revised README for the API repo. --- README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index f93f385af..24fac36fb 100644 --- a/README.md +++ b/README.md @@ -9,9 +9,9 @@ GOV.UK Notify admin application - https://www.notifications.service.gov.uk/ - Send batch emails and SMS by uploading a CSV - Show history of notifications -## First-time setup +## Setting up -### 1. Install Homebrew +### Install Homebrew Install [Homebrew](https://brew.sh), a package manager for OSX: @@ -19,7 +19,7 @@ Install [Homebrew](https://brew.sh), a package manager for OSX: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" ``` -### 2. Make sure you're using correct language versions +### Make sure you're using correct language versions Languages needed - Python 3.6.x @@ -32,7 +32,7 @@ Need to install node? Run: brew install node ``` -#### 2.1. `pyenv` For Python version management +#### `pyenv` For Python version management [pyenv](https://github.com/pyenv/pyenv) is a program to manage and swap between different versions of Python. To install: @@ -42,7 +42,7 @@ brew install pyenv And then follow the further installation instructions in https://github.com/pyenv/pyenv#installation to configure it. -#### 2.2. `n` For Node version management +#### `n` For Node version management [NPM](npmjs.org) is Node's package management tool. `n` is a tool for managing different versions of Node. The following installs `n` and uses the long term support (LTS) @@ -53,14 +53,14 @@ npm install -g n n lts ``` -### 3. Install NPM dependencies +### Install NPM dependencies ```shell npm install npm rebuild node-sass ``` -### 4. Install Python dependencies +### Install Python dependencies Install dependencies and build the frontend assets: @@ -74,7 +74,7 @@ make bootstrap pyenv global 3.6.3 2.7.15 ``` -### 5. Create a local `environment.sh` file +### Create a local `environment.sh` file In the root directory of the application, run: @@ -87,11 +87,11 @@ export WERKZEUG_DEBUG_PIN=off "> environment.sh ``` -### 6. AWS credentials +### AWS credentials To run parts of the app, such as uploading letters, you will need appropriate AWS credentials. See the [Wiki](https://github.com/alphagov/notifications-manuals/wiki/aws-accounts#how-to-set-up-local-development) for more details. -### 7. Running the application +### Running the application In the root directory of the application, run: From c1cbd9c34aaefef41d2d8c9f706baa4fe81108e7 Mon Sep 17 00:00:00 2001 From: Ben Thorner Date: Mon, 22 Feb 2021 17:01:37 +0000 Subject: [PATCH 09/12] Remove redundant parts of the README These aren't specific to this repo, and are covered more generally in the Wiki [1]. Note that: - The claim about needing multiple Python versions is not true. - The NPM instructions should be covered by the "make bootstrap". - The version of Node/NPM is covered by installing the latest one. [1]: https://github.com/alphagov/notifications-manuals/wiki/Getting-Started --- Makefile | 2 +- README.md | 33 --------------------------------- 2 files changed, 1 insertion(+), 34 deletions(-) diff --git a/Makefile b/Makefile index b75f7d391..3394adc18 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ VIRTUALENV_ROOT := $(shell [ -z $$VIRTUAL_ENV ] && echo $$(pwd)/venv || echo $$V .PHONY: bootstrap bootstrap: generate-version-file pip3 install -r requirements_for_test.txt - npm install && npm run build + npm install && npm rebuild node-sass npm run build .PHONY: run-flask run-flask: diff --git a/README.md b/README.md index 24fac36fb..e96db3e44 100644 --- a/README.md +++ b/README.md @@ -11,20 +11,10 @@ GOV.UK Notify admin application - https://www.notifications.service.gov.uk/ ## Setting up -### Install Homebrew - -Install [Homebrew](https://brew.sh), a package manager for OSX: - -```shell -/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" -``` - ### Make sure you're using correct language versions Languages needed - Python 3.6.x -- [Node](https://nodejs.org/) 10.15.3 or greater -- [npm](https://www.npmjs.com/) 6.4.1 or greater Need to install node? Run: @@ -32,16 +22,6 @@ Need to install node? Run: brew install node ``` -#### `pyenv` For Python version management - -[pyenv](https://github.com/pyenv/pyenv) is a program to manage and swap between different versions of Python. To install: - -```shell -brew install pyenv -``` - -And then follow the further installation instructions in https://github.com/pyenv/pyenv#installation to configure it. - #### `n` For Node version management [NPM](npmjs.org) is Node's package management tool. `n` is a tool for managing @@ -53,13 +33,6 @@ npm install -g n n lts ``` -### Install NPM dependencies - -```shell -npm install -npm rebuild node-sass -``` - ### Install Python dependencies Install dependencies and build the frontend assets: @@ -68,12 +41,6 @@ Install dependencies and build the frontend assets: make bootstrap ``` -**Note:** You may need versions of both Python 3 and Python 2 accessible to build the python dependencies. `pyenv` is great for that, and making both Python versions accessible can be done like so: - -```shell -pyenv global 3.6.3 2.7.15 -``` - ### Create a local `environment.sh` file In the root directory of the application, run: From 864f4bef66b035f96b84a46515b1730ed5c738a8 Mon Sep 17 00:00:00 2001 From: Ben Thorner Date: Mon, 22 Feb 2021 17:12:03 +0000 Subject: [PATCH 10/12] Revise README to be similar to API app This restructures the sections based on what we agreed for the API repo. --- README.md | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index e96db3e44..b4d416320 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,6 @@ GOV.UK Notify admin application - https://www.notifications.service.gov.uk/ -## Features of this application - - Register and manage users - Create and manage services - Send batch emails and SMS by uploading a CSV @@ -11,37 +9,24 @@ GOV.UK Notify admin application - https://www.notifications.service.gov.uk/ ## Setting up -### Make sure you're using correct language versions +### Python version -Languages needed -- Python 3.6.x +At the moment we run Python 3.6 in production. -Need to install node? Run: +### NPM packages ```shell brew install node ``` -#### `n` For Node version management - -[NPM](npmjs.org) is Node's package management tool. `n` is a tool for managing -different versions of Node. The following installs `n` and uses the long term support (LTS) -version of Node. +[NPM](npmjs.org) is Node's package management tool. `n` is a tool for managing different versions of Node. The following installs `n` and uses the long term support (LTS) version of Node. ```shell npm install -g n n lts ``` -### Install Python dependencies - -Install dependencies and build the frontend assets: - -```shell -make bootstrap -``` - -### Create a local `environment.sh` file +### `environment.sh` In the root directory of the application, run: @@ -58,15 +43,26 @@ export WERKZEUG_DEBUG_PIN=off To run parts of the app, such as uploading letters, you will need appropriate AWS credentials. See the [Wiki](https://github.com/alphagov/notifications-manuals/wiki/aws-accounts#how-to-set-up-local-development) for more details. -### Running the application - -In the root directory of the application, run: +## To run the application ```shell +# install dependencies, etc. +make bootstrap + +# run the web app make run-flask ``` -Then visit [localhost:6012](http://localhost:6012) +Then visit [localhost:6012](http://localhost:6012). + +## To test the application + +``` +# install dependencies, etc. +make bootstrap + +make test +``` ## Updating application dependencies From 423b4c78124ca6c4cc35720742382988b91efded Mon Sep 17 00:00:00 2001 From: Ben Thorner Date: Mon, 22 Feb 2021 17:15:09 +0000 Subject: [PATCH 11/12] Revise final sections of the README This makes a few additional changes to curb the length of this file, by moving length documentation (the picture is large) into a separate file, where other documentation could go. It also corrects the section on requirements, and attempts to make it more concise. --- README.md | 27 +++++++-------------------- docs/static-assets.md | 7 +++++++ 2 files changed, 14 insertions(+), 20 deletions(-) create mode 100644 docs/static-assets.md diff --git a/README.md b/README.md index b4d416320..90b9e7ae2 100644 --- a/README.md +++ b/README.md @@ -64,33 +64,20 @@ make bootstrap make test ``` -## Updating application dependencies +## Common tasks -`requirements.txt` file is generated from the `requirements-app.txt` in order to pin -versions of all nested dependencies. If `requirements-app.txt` has been changed (or -we want to update the unpinned nested dependencies) `requirements.txt` should be -regenerated with +### Updating application dependencies -``` -make freeze-requirements -``` +`requirements.txt` is generated from the `requirements.in` in order to pin versions of all nested dependencies. If `requirements.in` has been changed, run `make freeze-requirements` to regenerate it. -`requirements.txt` should be committed alongside `requirements-app.txt` changes. +### Automatically rebuild the frontend assets - -## Automatically rebuild the frontend assets - -If you want the front end assets to re-compile on changes, leave this running -in a separate terminal from the app +If you want the front end assets to re-compile on changes, leave this running in a separate terminal from the app ```shell npm run watch ``` -## Working with static assets +## Further docs -When running locally static assets are served by Flask at http://localhost:6012/static/… - -When running on preview, staging and production there’s a bit more to it: - -![notify-static-after](https://user-images.githubusercontent.com/355079/50343595-6ea5de80-051f-11e9-85cf-2c20eb3cdefa.png) +- [Working with static assets](docs/static-assets.md) diff --git a/docs/static-assets.md b/docs/static-assets.md new file mode 100644 index 000000000..76c18b143 --- /dev/null +++ b/docs/static-assets.md @@ -0,0 +1,7 @@ +# Working with static assets + +When running locally static assets are served by Flask at http://localhost:6012/static/… + +When running on preview, staging and production there’s a bit more to it: + +![notify-static-after](https://user-images.githubusercontent.com/355079/50343595-6ea5de80-051f-11e9-85cf-2c20eb3cdefa.png) From 86929df84ee0f83572818455459f19af76e9353e Mon Sep 17 00:00:00 2001 From: Ben Thorner Date: Mon, 22 Feb 2021 17:21:01 +0000 Subject: [PATCH 12/12] Remove other unused rules in Makefile These aren't referenced anywhere. Some are repeated in other rules, and if necessary it should be easy to type the commands. --- Makefile | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/Makefile b/Makefile index 3394adc18..1c7c7f485 100644 --- a/Makefile +++ b/Makefile @@ -43,28 +43,10 @@ virtualenv: upgrade-pip: virtualenv ${VIRTUALENV_ROOT}/bin/pip install --upgrade pip -.PHONY: requirements -requirements: upgrade-pip requirements.txt ## Install dependencies for running the app - ${VIRTUALENV_ROOT}/bin/pip install -r requirements.txt - -.PHONY: requirements-for-test -requirements-for-test: upgrade-pip requirements_for_test.txt ## Install all dependencies for running the app, development and testing - ${VIRTUALENV_ROOT}/bin/pip install -r requirements_for_test.txt - -.PHONY: frontend -frontend: - npm set progress=false - npm install - npm rebuild node-sass - .PHONY: generate-version-file generate-version-file: ## Generates the app version file @echo -e "__git_commit__ = \"${GIT_COMMIT}\"\n__time__ = \"${DATE}\"" > ${APP_VERSION_FILE} -.PHONY: build -build: frontend requirements-for-test generate-version-file ## Build project - npm run build - .PHONY: test test: ## Run tests ./scripts/run_tests.sh