From 87fe978f6d0021d622434256137c11995bc7ff20 Mon Sep 17 00:00:00 2001 From: Josh VanDeraa Date: Sat, 28 Mar 2026 12:13:11 -0500 Subject: [PATCH] updates for Nautobot 3. --- .github/workflows/ci.yml | 6 +- README.md | 15 +-- config/nautobot_config.py.ldap | 13 --- docs/create_ssl_cert.md | 2 +- docs/img/container_stack.png | Bin 38213 -> 34503 bytes docs/img/generate_container_stack.py | 163 +++++++++++++++++++++++++++ environments/Dockerfile-LDAP | 3 +- environments/docker-compose.ldap.yml | 8 +- poetry.lock | 26 +++-- pyproject.toml | 1 + 10 files changed, 201 insertions(+), 36 deletions(-) create mode 100644 docs/img/generate_container_stack.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 928e0fe01..a5ee76043 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,12 +8,12 @@ jobs: runs-on: "ubuntu-latest" steps: - name: "Check out repository code" - uses: "actions/checkout@v2" + uses: "actions/checkout@v4" - name: "Set up Python" - uses: "actions/setup-python@v2" + uses: "actions/setup-python@v5" id: "python-setup" with: - python-version: "3.9" + python-version: "3.12" - name: "Install yamllint" run: "pip install yamllint" - name: "Run yamllint" diff --git a/README.md b/README.md index 834a2d6ca..718e91e8c 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # nautobot-docker-compose -Network to Code has an existing published Nautobot Docker Image on Docker Hub. See [here](https://hub.docker.com/repository/docker/networktocode/nautobot). This project uses Docker Compose. The Docker compose file in this project pulls that Nautobot Docker image using the latest stable Nautobot release along with several other Docker images required for Nautobot to function. See the diagram below. This project is for those looking for a multi-container single-node install for Nautobot often coupled with backup & HA capabilities from their hypervisor manager. +Network to Code publishes Nautobot container images on GitHub Container Registry. See [ghcr.io/nautobot/nautobot](https://github.com/nautobot/nautobot/pkgs/container/nautobot). This project uses Docker Compose to build a local Nautobot image from those upstream artifacts and run it alongside the supporting services Nautobot requires. See the diagram below. This project is for those looking for a multi-container single-node install for Nautobot often coupled with backup & HA capabilities from their hypervisor manager. ![Container Stack](docs/img/container_stack.png) -By default, this project deploys the Nautobot application, a single worker container, Redis containers, and PostgreSQL. It does not deploy NGINX, SSL, or any Nautobot plugins. However, the project is extensible to allow users to tailor it to their specific requirements. For example, if you need to deploy [SSL](docs/create_ssl_cert.md) or [plugins](docs/plugins.md), see the docs linked. The web server used on the application is [pyuwsgi](https://uwsgi-docs.readthedocs.io/en/latest/). +By default, this project deploys the Nautobot application, a Celery worker, a Celery beat scheduler, Redis, and PostgreSQL. It does not deploy NGINX, SSL, or any Nautobot plugins. However, the project is extensible to allow users to tailor it to their specific requirements. For example, if you need to deploy [SSL](docs/create_ssl_cert.md) or [plugins](docs/plugins.md), see the docs linked. The web server used on the application is [pyuwsgi](https://uwsgi-docs.readthedocs.io/en/latest/). ## Docker Compose @@ -215,11 +215,12 @@ Example Output: ```bash ❯ docker container ls -CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES -143f10daa229 networktocode/nautobot:latest "nautobot-server rqw…" 2 minutes ago Up 2 minutes (healthy) nautobot-docker-compose_celery_worker_1 -bb29124d7acb networktocode/nautobot:latest "/docker-entrypoint.…" 2 minutes ago Up 2 minutes (healthy) 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp, 0.0.0.0:8443->8443/tcp, :::8443->8443/tcp nautobot-docker-compose_nautobot_1 -ad57ac1749b3 redis:alpine "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 6379/tcp nautobot-docker-compose_redis_1 -5ab83264e6fe postgres:10 "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 5432/tcp nautobot-docker-compose_postgres_1 +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +143f10daa229 yourrepo/nautobot-docker-compose:local "nautobot-server cel…" 2 minutes ago Up 2 minutes (healthy) nautobot-docker-compose-celery-worker-1 +bb29124d7acb yourrepo/nautobot-docker-compose:local "nautobot-server cel…" 2 minutes ago Up 2 minutes nautobot-docker-compose-celery-beat-1 +ad57ac1749b3 yourrepo/nautobot-docker-compose:local "/docker-entrypoint.…" 2 minutes ago Up 2 minutes (healthy) 0.0.0.0:8080->8080/tcp, [::]:8080->8080/tcp nautobot-docker-compose-nautobot-1 +5ab83264e6fe redis:6-alpine "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 6379/tcp nautobot-docker-compose-redis-1 +1c2d3e4f5a6b postgres:13-alpine "docker-entrypoint.s…" 2 minutes ago Up 2 minutes (healthy) 5432/tcp nautobot-docker-compose-db-1 ``` 2. Execute Create Super User Command and follow the prompts diff --git a/config/nautobot_config.py.ldap b/config/nautobot_config.py.ldap index 6ddfd11bc..d7f302aaa 100644 --- a/config/nautobot_config.py.ldap +++ b/config/nautobot_config.py.ldap @@ -19,19 +19,6 @@ TESTING = len(sys.argv) > 1 and sys.argv[1] == "test" # Redis # -# The django-redis cache is used to establish concurrent locks using Redis. -# -CACHES = { - "default": { - "BACKEND": "django_redis.cache.RedisCache", - "LOCATION": parse_redis_connection(redis_database=0), - "TIMEOUT": 300, - "OPTIONS": { - "CLIENT_CLASS": "django_redis.client.DefaultClient", - }, - } -} - # Redis Cacheops CACHEOPS_REDIS = parse_redis_connection(redis_database=1) diff --git a/docs/create_ssl_cert.md b/docs/create_ssl_cert.md index ca2093771..a4d00a738 100644 --- a/docs/create_ssl_cert.md +++ b/docs/create_ssl_cert.md @@ -4,7 +4,7 @@ By default the Docker image comes with a self signed certificate that is valid f ```yaml nautobot: - image: "networktocode/nautobot:latest" + image: "yourrepo/nautobot-docker-compose:local" env_file: - "local.env" ports: diff --git a/docs/img/container_stack.png b/docs/img/container_stack.png index 01add4bd9827b57e931590889928fae93036bafe..d25224571831d79104a3b7ca23890017e63bf52e 100644 GIT binary patch literal 34503 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 z zg-pU{Vdcu9c$f~@pXC`!`_^zx*Y2T(_Zt4}VRn?4hImYK)!@8q*fDps*7mRfn``6n zc<$`A2sF}5Vj^-gcfny*0n&$5czZ*=Zz5|pi~ z!8`glqBHWj;UVH@%AnuGDQO8idF3s{xo^zQa8YGlh?vd@O%*6m%=x7rtZ4bNvs*{( zS04gl&4k^($z=AjpDn)SaF_%RclBEqLfc!}mEFvS{7!3M!7}RhB5tWi``r9<95VP2 zBU^f3duvxDzK>iK(>|KUnYj{>4&U6yBYt!lb5`xv2Yf~}9xWI^E|WXcf}RZ zTV(6ZY(-5UiA&(UmU44zIuAx|_*QM|ElS8*-AKXr&0{*B9ku7ti;bYtE)dl7nXySa zVsT6)4|ypAF1@ny5_5>3!;&|R3(Mpr1rO1qHO--KCsuV_zEp2qZZT=j4l%QGA(Y2n zoKjB4xrGSAI4Zdxv14m6NUnGsfy(?s)9&1G$5~iK{nKQpRlh{x_epzBEhu ziuPyP&XTLU^)neLOb)!VntCt}C$pH0{ep2-UYs8Im-sW$ARxMA)8$GgW#?>nNUY$O z+4Dv79`{%TJ`=BYe&E77U-iyoz9kV`{FLC633)SL-hWHHBA&;5r6D<~{`Kn*4h9Fu z-DA_E%t=4V6y8cxi&Yi}MG&9C<=RJ&@|@RWt1Z&}K|#?dNk`sf1)adWj8AShjm2Hs zMh+h-q+QMX&8%bPl+SCqmu$|OsPPQ@{&y<}htD?R+ytGwm!leIwGmP}24}VyVZz7V zQOwwrxn+U8Oa1y8XM>A%(|*c=i`T3;Pj1=1eIv|#_0g~CSs#jhh6<6o#9X<~N<*gKJyn?}gptQb4LOczva zHp2ead?Ot*30cK>@i@{g6(0Q93maU#9*LifK~3J4WOi9{N4krvomm0F;$O?|+?Ghn z80v3C0?UyvlPe_s*04mskct6Lz`I!NMT}9*>DzQ%=Mjx!zYBjgeOYp33K}K%5ixN> z>UurKtF*NW%i4V&c)A%Lh$;9Lo`Ot>?DsomJEfp?AasYPp|=Zp$$>6xLt-&84GV=U zmn-jC`D!!Ir)InG>)ZD0?vPD>n(&G^o| zgr13TJ!bn!v&`o=fA-v904vzNjL6#BMot1uMsa;Ym9absZyH>`ri!SQ%ZpZhn!R(n z<$->s>A)CnZR!n7ns*_k5yA6hvDG)y?rDTqWS6%IRTrD$1j|zsq4Z)Jv6d4fQdx;$e2c8;pQm2 zqrQxUfILx}m>5GnpU<~2{EpP0UAU$`V)Cg-QU{FYeXxh0pPPB+w_Q6zMO+uI4Z@p0GX_kEq`%;c@c)__E` z{!>DZWHC2ac$&I*JB z`7<~fClyS~gG|B8gJpaZVMTNGmKc76(5I7R1v6*x_kh$N+n4R^JRjsPVR(gScz=N5_B6 z=_6X&(hu(NO+R>Pn){d9kY!rdv9;p1kUdiwe!?CTFhXI?O`HGQbnwnnNt3uZCmyf% zp1Ky}U-5RhONG@Y-2C>u3AiXALpsEmj4a2$y|Q9rF5Hwf*=D3XT@yffEriiL9o+fW zRE+AcuL%*MaJ+oXzI2$@&s1~YS12fXem%0ecIYc?u8=li#~B``ivy0-Y#n!Xix2Vf+KL{l0*`dh>{{z>Q( zeF^u{MeY>13LVJp#*lKLFja!*TV<$&s=|QKcc*p)Q>G3JYtvFSy&|^t&$=n(K_S ztvSDnf)#JAWoV&S^2rIxIjH(OEjq!61?*l6s4gCTb_?lOG+aXleC_jYn5 zQJ!9N4nQg8V5w3N0|X%2J}=5^bF=-D8CKnDS97K1U}u^<*3^AYD;s{>7JRh5CvG73 zJgg~jZ`?&t;+5?jv|b5%*?8Pabd;kzcd`&p87D>FS!n58C4)|`X0T4Nxjx`%hcO7o zPtp${?8gTQOF6efQs7BRlUA5`Nc;CVE3@T?@3Z`qiVXCBxgoxJQvI095IQh&J()dO z>oP$Ud9sOLz^nM4RoX226(IvUC?Dhv%%+OKF4>KwXh-v;nS!6FIf>n)CkTMxcjwKM zeTl|X+*Vz7P5(s{4edb_%H)-Ylk11grUOl?# zi=-ca=sR>WvUAe1h0ZYf|YseXkeddAmTK@JHNAc_ZA!7`w^{>X(SI6x9&A7G7*XJ;YJ>yTK z@(*tJE}n{_&>-44t(@A~dUuW~D4wASO+jVojk7Arm|8?69~CM84k|4>vAOi!EiO=c8JK1x zh+U3i4N#w2O3 zN>}v=QG;zXbNO&VqxuhW%A0>2T4J;zEXXkbddIMXlZL#!i^lPjCyrgx0yaX*cE^&2yO(u zCz}#RUZ=9-fxMwQj{C&&dxHJi7D61!mG?qz`n^P0B)Y~bF57za%|@ekxLM#Zl5`sB z$enw$$g{y6{Jyi$x4#i2&1K20Z=<6nGx5OPmejTo5F}OH1NE8rQ<-BftGw?8n}CGB z))kc;yfdpz%~dal2&keNFtV!K=r6Xk$}vO5Fy85S%M5)a%3 zko^F(w6-fmSHMYf=~PSVj;iU%8S2aox3$TP$Zcd$)8E6BJHG5+mgKh3El4Q410ee$ zH+SichV5#q>ZG$r?MEB&)rUYANH4A};;CVQ)Zq*&L!juH()o|Ww&WEA&jw`v< zqP2x?MMCLqAoO~S`pGp~rfz91Fe%v`W>nAJfJSp{r|`s=ZU8f)xw#d7{AE3?S)UIT zRrL@Z<$xi%IWX_2$&foR+wXL4zWW_$XlRD}?l>E=GI3$Rp22PZeiv%%nv`=avkr#? z`t(YJW9CkTN#i5T`Ay_!1L9P24{c;Ksp&x>xVOP0Ze-UjbE}c+%rD(UXl!bMC!hZY zic6}Lu=aK*Y}~R3HgDSp*Ijiij2PO-&(v66xPtnvnB8q{?NGS)0KERrBKYSu^I_=V zz&ODbmsZ0Mi`K!R2aoPh<=2xCm2#&iusi_SPfL0*NNySx-5-OSKBLVj!9QQHoXDM; z5)bE}F^42~QAriN`Tnm^QCSb4eEApLb+k$b`88+ONK^ivYB|JmCyg=FcvPCuuohH;8x1J&8s8wEs-}Ci zfIu+N*5-s2YovJ%&pc%&j2bCP>fC{uaMmfaVDX<@;ON80)1=Ob`ub-0^sD8tY3n}f zS{yO7H=KUb49G}N)TAqom2-KGk5=C6Zhae)lHy?M#KG{_iXG6WcN)aSMZ@N;`{0!0 zr^1nkjidDT7FEC_PcMMvq&Rr+?z7ywV?^C^@w~aE1)NUly?ggg_4^xk7nZ@7->!zD z{gu$x?u7Kz1UU5IQE=G7qv6Ttzg0AyCtvsmrcE9K7oU3w1Q&u^h&q7DoxtSb<|VaY z4@5CdH<|vNx14JwIUUK@&84Cj6<3lvju<(#w?-n38QGUMg8Ut?y!A8W7nCV+Hf-KQ zM7Z;&lOQH0N=+E!yF{KPzm3#4h zUV8Iq*tNS1ic72D#%qs-2cKL(?eH6}J(fssw%^pv_9M$|Bhq?ud}D$rG0}EKRc~u+1BXL8Hv&pI1QzbQANovl4M{V5#!$_7`iehmnmWz-K{JLzY>b08 z#H4WpVCjmTux3L6j2+n*O3G>=D>DfO^h@`ehkw6(E{qt~oASNBp#?twdKIi%R{-yP z^atE|;|YF!1FGd)x9^Ai!UIsaryL6Ql*@U9e%}0GqTm`5eZyTMGt!%RZaY)FnPEFz zC&}H_bI$l=lC4ipitLLo!j7FKnrm3#pMCWw*q&ER=S-D10=8>4QnZ8d6XRnv&z>~~hC+?>_V_Kj-vNtuQbG(IF=rG7m6X;{SD>$V!Y;lipI--X8oiUZzguf@S-WrWzP1|M0%BGRlN)7?fQApJ4fo*?%O*JuDDUr*f49Lt#go3^0P>YoTw!bF~^qGH5s^U-3+SU#$*Gdz^pnV|9Ve|P;OP1w9 zQE?Rv9+U;+NB4#5nnuXWXY)=-zaLX)8ycHwi;s&2vq4k{&ZIZ^Y+pyL6+JNI*Upe> zCY*NsB-pdB0?Nwk;Kl#`s=0=Su+vVMOz%BES#3KiYhm|=WPIhQ4X*|zxj zD7fL8xp4TwBS@mz?KVhBj)Mtf`@ui1JOYLc%9JIS2-jS42uztUfC_n(!w!9VrNRYg z&VUJH`pVLksjvRVXL;rRUehKGP$Ung;q4prkUZIJkd_(`M;IdyJ9n2+8hAZDHJ&OzYz74T_Y;lsL)RtitBjgKHD?g^S2w%8 zjZvSoa!eB&%ELnO*yWOkiMli!_L;u%;g?D}58ir>VcPsN^wvt;Y175$IBAasCT_2k zrUl=qt8a$8ANiW{^xroh=cZ0u@QlWOFG5pGE6t{gHWr)BF7Iv1CRLv9%LyCJp^nFQ zKK7Dwe(6~!Q5XsXK26%>HPfVXd1Z2L5e8q2EtpnC*Bdg7$zHO|Vr075FK+`8f>f@ulPpiz1B8E7I^$gJ2^Z~$I^|1XjNBZua|nI}!M@~x}j z=IJ+kJKXdHXOOgZ_cpi%?-(&83m(7cL|tB5`PLyYZBnuA(ozVfl-S)iC!5ixNmCsh zW*DaFhV`R+Qkm!6f`x8|CszUexn_;Lj-=1+J@LqhQ(+~+jg5YmB(l)cWe-9MAxChw zNFX6ZavKZAH;cBx%5{6mef6NJ1L4Rysw*mwrK<|bS~_#Gn+ydM5_ z-C@*y`0l4`Veo)7$Q_X87MHonMsA_=TIZ1HU1=A=TCsBCk({)g=w;HBR=nJPFH=0^n zy9z2{;jcTWJL|G@rhwfp!26$Xpzu+{vf!MP$3bIrJG}YfYACO4gyDlTVbt&}lGd@Y z4wy2o4=h<;0P*qYB_=s(G`F<+l?I=upMSR*4pcNizurmoE*~w}NO99sr$BQ{ zJG}epI;d}Gg~{W3!)f!!$j<}VSx^o?|B(-uoH+?f%Nq>hg$@L^=Dczq8V0tIAh>=# zZw*33MbF7hfMX9E3O_H|1tn#5Ff2C%jz4MytXR7b`u9$T3s0K>AAGqH_U^BtZ)$9A zgIlhd4d4Hg2itcZfXeD77|=HbE;wyG{QBo^Shcby~~BfkR1kCJ9@x%sNuo*s>#|r}pA)vB5%r3FL&flgiKWKgo8I(#Je$AKPZ-ZrP_L6j* zF}W|q#@gZ1vnNu#z5A(e`lmd`0IuZJ}oi(%ofc@$^Xlz!0C>V&xm=R!=3 z4Mq>oQY5vsNAE(HCd~gdIG0y0z1q4K`04k2C@!so{bltqpl>ovo7e|F`f3wZ7-L6e z!}+J-Y&9b6*;h?oSpp7v0heJsbJL<@FtbE=Kxg{Npo4v65pHDr`H$Vu(AWk?&dDX8 z?zk8SP1cv58Vj4Yl|g1&94z>02TVXoNekJ@>r%_#hu4okau^&mwLeKj#G*fT!-g%T zFlWX9*uJYA#*WAWhh2bu`)gt3kPO(qs{*Es>!qaQZyN5yR9)b5y5OhZcaiix?uemu zAKDVK(&OOomrR4&`WATk-PO?8&_egjp4Oiv{ZGH`qWDJf(4ZG;5V}iZvw5F<^^x)C zJuSiQ%uiNcjagcYrDNb%a@3QT&0?vXlXMRa2|j0fKUnZn9z6W~pR}aYltPn;G%^=B%`#)Fhg*BUsDLqvJi+-oU=V^Ls46NQ*41Ieg!m!+Q`1ISYuzpJ^ zOdOK~RW(hpYQui`W>FqEogz%1*aza{9LhV-nA96yczZPzm(@X0Nu67~Q2FiDrHc6S z?1AVy|8svqe(mylWXL1Q&t01Dt*a1fGn_J!8@EIK8B{|Hg154I@m;7C{P+~A_&sC(LfNrk?yX?)xjp0oOu$> zv2M48@n92AhBSRR`yiaiFLvZ7VB30H55K8}NP=s`r_k6ejU+RY&Yq;TS&VNEvyz)s zB5I0C;Zo+ZQ9DvQoZ^H?JKRF(LU0=bYS3-w;l5zQ6a@DSX`~K6MJ=l7>>BnX$Bp_7 zgsrCp`8_R!BU~fCfX3z)lHRnmue=x`n@3)i=*&uHKA4W+tk%PJy*^wWny1#Js6NGy z`~rlnCkN?`ErcVSBfo&A<`!xj`lYt&at6OoKsvP!O3&y_tz^laz~Cg~k!BDHaRshO>fr)>|R z6vs$$qZWX$<%Ayi3Jc*1*XXaP>1Q*P-0mdy#ob_&-83q?UV2Ld>?L-)cL}fo_mUL1 zfen4PsJ#?F`fKUx=HtCS&$7)$9t1Dka*h6)$`g{C${2Qkk>y+_B`3Z0>N-o+q;a^KHV~f6D@tI$IH~G3l;$mTU)<=gwPSc?bzg$MFWz`wYYU+T zV^WE_a9*ue2a@2N?5tm#+TF5h&ibSE6Dms2lhe^ibkD>N2I(DUlGwh8uiZ-v!Lba- z-vB+OGj4B(&ZFa3{?ooPsc@Hy4 zbknHlJowBY`Ktb>%RCXV*NjyR(y~G5;wKG|z#mQ00%VeNt3NXBz*mK0>GB}}ALJ2? zJj?V%)Oez)_es`q4}IaX3g8dvg9TF(oCnKfkR14$6>2_1NFPuBhn> z0W}g<4aXmWso>IDTzH>Tk?g!Q*N)WDwYhz$;%5H=JA(HXEZW76&p+`7hoDiF zwSz)X5UAZ>yi`{WY*G`DcU9GvA*25Bj;QC}`NdyR?+6(QZfHH%U1yFj%;3f{myw*U zgn~Z`UKbQeu6C<&3Cd|`+vDMmcfa^4pU;T*zWOQuf>Vx?mK_aq2+CKhqr#Mtk62!0 zB9k#q89Aml33+le)!dt7iy7M9rXjcycqz^Z%&Y3E+n^NA)N`lPsYqxVaYG~DB+#Cz zWZ11HyS#eJ|8P^yjlM=O*V1%dhA%SN$i-9^6v}TelT@~pOWieiYIl>&`gS)fBa)Rp z_+${4CsNtd#?m|JdIfNf4RaGZ#VvnWmQF`n6einOv3-q?S{5Vb6`+L&L6- z;BjdUcZz{HxB|ko5}b#T;Z2?8Mh<5aMsRH?UIU<*Twl19W*A9m1N`@sZ?WC&5pR5~ zUcdB=`C;207r3r3sT^qyW6}sQZW0AeH=5j?%7yvk)M6HxMz7GT#C#@tA|b0=6?azM zKmen@NnWjz)O-lr?XolH5B9kRlqgcXV83g3ZXj3g-pYe}pEwg5o~KUYg^s848*G?L zg6qj_)DHL5t)@7xfJ<|q(k9oZZTtohZV<7r&63JSTrpfJFB0J$NqoZ_F0Au@{r7QnPlBF)}@y|=o%>D8AO^q6wwBsf=t4`u4Y8a_igZxFtSxr|;#Itj)>; z(RUuCJbD+P@~9Us%>RN37j2iTxr}S3k>Ez^x&Atn+%$ZIliakzNwfnJ9=yYn+!g|g zq=)YS;f{x>O^)SE(-nr}AH4K=n@LR%7{MJj0ehfnbIRkfH4yzHx1m9et6kCclqYxm zga5L~ZJ}F`@X)^i{`Ig#a@jqVEb=-RU*`I3WL5WvITQdf+O zYT5{H2No;@2!dBHN;JAjKI~nS(6}I_%LZUa;e~S{M4~SfO z^W|^e88tnu2=0r>n!Q20+{{+Xo`Mh^142%3h&}!k5StpIb=C4Nr|ITM6hW1!H(>i) z8n7arYr4q{y3TwNzbD}^)NwUlB)rR*F3i`~RcpEdv9;1WvI<|r>(4`b-gc=_#l=JX zITwLr_$Y{)Is;l)EepUCq&%(t&+P$7D~uqr@+LV*^A({o>Z~gg+ZTuUbLOM%CmbE+ zcUQUHQOA5^X)RCbpjhf7gXnC8C)p($8lY|SMk2V7kf=x(JdQi@G>95ChNdBE-?;;t zzWNkgRh829#3YD6EJ(QUa(T`&3624SAn}r`p(Y~Q=%Or4)PYKRax;s%Jowx%Quh>0 zXGPZ+GCo{BQivXDixMPWd7WDrlD28lLduJ%VIzp#&XQuNfBi)en;IbQ_){Qe)*OhQ zG!5Ddc1h%RxuE`?*P(sKR*0T{5X7H+21`vh0#711X#xfLQ2+W1AT~Ecq(PM1-@Ftz zl*A^R?7@@-*Tb7pEyDQihL+VUpn1_kaF&(Qxvh6!+S_~ehLpSR*Tl6C8Vs)bdOB|3 zTL`Ti*VA$HlEn~r-?s-M5u$#g z5fc&Glms`F*qqgp#bLFm7)V@P5*FZor?2fN*4 z3N~t|%S{^HWPs9It*o7=4R^IPL(Ts^22o?jOBzDIfe?Gh;ShV+T&R2FC1~BU5yBp# z-neV9IEQA;IlC?R`Wt$4`RRZJQx>=E2mSXX)#EGiYmTg_gCe zXv21U;_2r=%+#6S7(NnOHgABihseqsBeoHV%|~ui5!@S8&mp%95K-Xl4h`RZ1yLhM zgQIVMNId%jsD1T$lBUj*{ov@^57O>>Kyz!|TdzRN`nAxyaUDdDn+Qo4UBRWRuEnlz zgU3vn4oT--V)#03JGMsNZ@`s9vyeDshKusEr)V}*)XxX?S=y}s~o2V;$1{Ism5z7n+2?@?4 z5ylvkeD7)brO_;N~3Tobd-D6r}V*}K@^M?25-EpJlylKT>v_(2Z)_W5| z=)sjuw0nJ+zGL5|7}LBt(u7!UTL?*r+}_CfL|PbAUDC)*Fuer#rt(CJ1h-&Lh*mdQ zAaheoXt(yM1q;Q7A%Ap!6hqiWEt5km;r)rfKzB7oT3onB62t@&o?_BrecZs#%ewAd4k9TEWcT=T3Bg@%de!%X}x0>;r&HQeWj?f{v z&exY}(oif>JR3w2S_=!JoRt;!ggJ*b#Eux%8Z|Jtwd~RRv(hiRygGVNZfi^4j_As_ zUrS^6#0(kMnsoGW^%bwbn1(CYr(bkgbKD`$UHRwQO4)yGYr*~F*gYHKqrhDP}oKl7lb);$GL75{xX zHT}ZNs-yZ3Y-=ejh$?;P-Ygt0ns&yyHBo~Gx7iaDUHW*K9%>_{58jiNeEcbOF{8$` z*wZtd`gdzsx+JVrc)?)3akIg+1lKS7YlKkbH@S=c@NHtv*Iy|X5+e=do4 zHZsCnoYL&7t+iDz_$)d3*!lHfvx!FW=xba~jh~m% zyM;Og6B9Wk2Ae1uXpo6+nad5h54A1%nECbnpMSl$@1y@$YD-LVHLP3~#}8Df{dr+R z%+TSjcs;6L|F)VRze{9mnb$2@93MM;M2n+$pZ2<6e~OPCF}kJiW6zZKzURRM(SwJ! z^640D2&3@2-+xWOHg}%~pD4v?OPaQBj%nVqDJJpIBO24rzM!UMXI?a_-A3`)yGa9r zB#s-sTd?z8?Bphm1{Hi0T@E)>B_QmnY;qHWT8}Y(!H^bYlU6Wsf#`CPFD@SIx3@m} zN=fIwo3A!Z+xQvk#uk8+o+X0Q<)mlF#YTbiX6--=3l_Qqw#QzC#+FvF2{w6oAv-N! zgi9GAnc1G-5c*>VJih0NmzDDi&p1(DuE^%TVH(OgOW$Vr4E=MuZEZ4IpR9up0q%x0 z(J);4AQ2jyS|R@N7oq*;YXkKO7AzQ(ySYUsl{8v96eGFRW`k>>H{jBTWdxJac+caG2lL?% z)P&Mpg!rdkR%d--eeB#ga;0;_VtUv^(6s!RTCI{3gBqHesGnQv*Je#W)@5bm1d6Vo zTc55MVh4ltJx6dIkuYm`m75vRcyB0vhC9W$!B%%fs2Ybqjz|^V(+@@N z1591l)s$M5-bFtW_Lb8wM16`j#nlk~Zj{+LWU~9xB-ryUm>a(2qQI%rYWd-W22;tI zrSvWVcZyR#ab@^sV$&baaFfgPgkvOU15=n3XM$W4`Qw>yH&fY_raAtR90)^4{eU1Ma>RiF&2-`1@|* z03*o~h|x;shTtBeQLAOADOHpkJF;*_HH4nfdX=6J4>n9ea9=PoyfF&Xo*Onwiny$T zX*B@t#1fv2c;SRMKm9J>-|Ls0eq7kL#|6IImHYjrU{wP1l3Xv@S$Q)usF@k2(JS@V?UDShvEE*BL$b8bwaMU2?g;wLo6Ere z0?P<>t;(|z$%Z)nI(T|vW29l4Ni%d98DI3>R_eKWrvA@|=)?Snk&%ss8}^Trw;KK^ z+WXm5QE@TR@EMM&`GE56+vI5tkn>vAC(FRS7dBIWzF;48LZDDG1IJ)UaDjudb6b zg7$vgVxyzr)kW-+!e2652pnGfC5rY}&IM>{ZBxSeUKsL(l$&|_<{xW^yEO|V#gnb0 zP#jyBCz})~UzJo9M(ntlD7y6WkC@38u`P5SuPk!FRYxJQZP47>rfYkv4litu0t7SC z1)IzvLvVfjn~s^!xz3s{`JIdK@(&idEd&NH|6qr!kC7JdVEyBYkdb?Di0<4qv#RV4 zGpgtM>#D_EyYdPC0H~I~_&vL7!9rm0(n0~QJvIiKT3Z#OD_{doJoI^+NlkZ{jokd+ z8{rwbU-+&EU)VxK;f3!3{x&b#jpRmzX5mKCJeVX8x&-$HW;ypHpF6UGiUkWDg{P9o zPeNigwY*yhj_WGnpEQ6@05&^XXTYoBjNEz$4V2!`ejSL_n=DxHjOV@qxc-D_>ORwJ znfgIbQc%asJ*`bav8-v8ooNKo_mU~A->5xhAf0HM1$s|H!^orO{cZV zWNpEYgQVoWe#xYeQPF)7S+h52m+MD{`GaVO0C%37&OHa9wOxcgWo_`~(gvt+GQT#E zl3;^lrzSvd?2Ad4Nv(Bu@twZ3FROOK^Iuhi!!E$2 zp)qj6%mg@fwg7McRNLim7}7fmCJc#z&;O{0Km&`#c}FCJ-3IXLw>41H;DYHRV&K?m z31GJaeEnAg#T%C!1E>aPY^y`x!8RGmA+C*q<7 z$V{=ro>J@^)?VY!)06Cw7-xgJMi=zYauB)weO9o)(Gyg^b9dpw4|+0-VJ)Zx@2F$G zyE-mSkxUuwqZy!0hdXwO(B=|h#nvX6J28%=0ZzK(?4l6A;HYFMt7`Aid-;pBWIN=f z*YVV?ss`AxuNCSVoKyh~ z?Hdi}%}s_MR@K9SYIzPi83S^nNL}8zy9JtCwYAlj!WMe>;r*jw-A*Rq{Le#_#wAtl zZt3#B&%Oig^nQbSMZx-A%`hk@irx{wEjC&r!^Ov>P@Jbft%QnNC*}Vg=Vee{zVua9 zP`}YLL^mm}=@OGI>imo^!6db5hl~2^|K_iYau-=gHo9NF&tV5RXiOYLM+vZfZws`x zV?QUrrSnpuUse>n{B;$){#`W;?h{3Y5`Wkc{iEUViSe*#O#|HbZaKBzPo0wlS*dn- z{;Nuwn9C>5xMulw&ok(SHVkPSJ6A+ zvzl66@aRY7kYC&i7aWxWy)*34+~$HGR!XY>$N|xC{VC~i_TkBpon}|QFD+5}Icw^j zZr@&2FA*g(#ir?6^f&L2SOq0*hS%6{gB95R@;1or6-8=xzbpq7l&EcDjJrlA-snNm zbUw6i6t&f{LJ0OZx;$(~b{}6(S!RLh2(E{>OhwhJBO4+o%>fTxmJRn@m<5N9kB2oo zn&6Y)YU%pO{?U+;Y=`Ar8=ejS6%N^;^Q$h9xdC_1fvHw!`Q*G zaQH+dc>+oQkAJPD_9y?W0N4rdwCX9@vxwC3)qq;t6 zSR9P#A43KD`{i|Np%O)?Yn0MTj8g|HB+CVmH8Bw6J0M@LmG60LVHIpGZ1MU%+xN6U z-rg3t`=V@!i;*n3yNg??aAP|k)%~P68=QYsDtxo7jwB&sPpRs#Az7Gx=i$JdD5$D) zLUnz+hrCrQUwj9qDb+T(prW?jEgou3NbnO5N+K=imz@oU@6nUr=naZ`ZXi@Vk=P96 z?okz8?7~LvAYB-x>18S+qm8|Yr|Vk_nn_~M934mPYHa(>7!^+vX4{@-m@_UO9=)m; zj2j#St9LZPx}8m}~#qcI5!BgV(`sUzY@nvWV7L+x1gy}7)RpO0!P5`OmBcuM2Y z2?_MP2}5FG^uQQ8M(K`~2DWiW4~l`fXdA5G*-UxV+U9~U|EML>TyS(M*%#`XTyWJ1 z=|s5ViZ;kAl9pH2Kik`e1SeJ7SKb2lTRY)EjYR6*@;&-z?JR1cJR3P6hVlXP5yOM| zjiMjl=1;lwcZ)a)j-br+B$@S@-N9}$-tW)TeJ!mby!2%`9Dh&>{QZXJdN^`wBHVOl7CiM)8N9u)3QjvT z1#USziwLr>tQGoaM}y0W6Z*M-M^$Y*y!l-v%%7DEcVC!I>ODSt?GDMYl>YL#FRw1_T&sA2^zl8T8(Yu++NYJt4Pug(vs}(*wwu? zdGOo1diZ9k)+bFp2LR?kXt!0!Dm$~FEw@&C0un&9xsiIBg)1#0S~ z3Sm=zQ_#NA8`x?m>iP%n%V_c8WK}nT^hOAU6^(Acno;d1pU`qGcuEs7xTG<&RFk<} z;FQCha`@XHFHq9C_ok~1)8?PS6I^OLNu$Q3XGzb-<%#e(E;bq-|H!)%+-S*Z^A*ZDbQe0%i$Qj#wHvZG0gGv|z+1U~cg-)kV) zKn)1h>gl87>G#{1kE(ZQf1~KbH{Iv`M$J#%HGNn}s_1?bol}*}in6LU`0Tf8IAlU1 z+AUme|(9`28hZlquMy5EQXAIXx?LJvdq zqBnQBJ?dp+R=Z9z~zgDC)wYUs@7-FMsVxO$&w)~=I!<8RqjZJE7bBe;Mt@Ux;{qAAELP`iA z}~KsNsZsu)FyoWM`dzMv`su}dP?2#v(xH6UR0i96u)0qbnEZ|v8}uIHbr}s zLcIUDg|J4*5S*celS=(-Z zV?k-!DTk%kW~W89?QLn`b&8VhMj**R`t++u`OE*nquGo@j!~x>3j9kP=`Qek2{waFboBlp5Xj? z-g-nr8(ba&uY7A;yC_6O*+e|wQ_>vu*t`3(&`IL7!!l|H_KIoy?AP+-;RE7Y*X^i} z#rXQ`mfEWR^;1VCG%edy7Y`8%Ap};cH7&vQ%LE%C64Xp(kc0fKQ4WDbCZ4AxI-JMM zOsmH>cb}}7_JZQ(Xo@F#zK$-t8}b@rnwy=%hMo1Xv&JPiCdb>|;w{@)8+YEZ+0{o( zORe9KS0DTKH>GJgX;JM{Mq;Tn!m3(`un9NX`^%FTlDd!jZSPj z`OwT-heHtm+E5!`*Vu0RZB2FjMe}=A&!3%MS6$a`e}7?ViYIG*I6*M-_coB&ydSz* zU@C%pLL|4r*XPy8UiWyOb~u!bwcG1ranpz2{(OE8A4h+E$vTMlC!OV+YBgPH4NXql zi=P&$b5BP&1QQY2^aS@rVtqL4i)?6ag$J%ogF9cY?BO@H5J`C8sx)Y5YF1Vf)sxy2 z$<0E3hgr$Z99lFZb!5kWoB$C`O&AmjU1b)63qkG{lQeK{SSWv8Fek|aw>Ftws@+_2 zE$8g&$B72rWNeao84XP>@bEPmaQlnKbF5jg&=ov%HA?Rm8mp~=(OB#**xYa^vEkZe zqM6nvb9QWPGGB%^y@{Nk=#EKo9M6O5)5F)KTO_v-P&{-^x=L+QIYglguOg6_Qh}DIF8ZU$7*(g|6e_zhx+DxT>COkJU0N z33R@X$KQ5(PrzX&QoBLFf`r^DY$V0;(j$M%fZLug@41h$5O#RvZ<)~0*sM&C zU0g$QFY0-)$!-cGo00V9NzG@bC`)dQ6i44nmy1-YNB^El`F-1S2ZH=X7D5S+{yme( zjO1oUGqRlPq&NNZFyETDxzU1!pb*@f)Yco+*zA>j`&*LR(qwcvU8)ObOr^=`B*PoV zee}94*-)pQ#L*2Nl?Tf@A8PP807Nhd(pbX4_`5fEbjL>W{M9GQ8y&bM3?X7Lj zJ+r3~v`H7eNo-H?`8`{*m8t5|JjBxaVz>fDV^a&w!b-o2ZjNhZG7fKk?pF6($iW|S z3Ea8rk%r42v3_oLO;XWS>8+LAem$!L65VK$B=8azaw@vvKofOp2jxh)M(Vj#DPRqY zQ!5k6sgE43_;_ZMh>F%o>^IlX1mms!&%J{MbHkTh6pV<*`mRY%NaR*5=5n7mKOM4u zDrBWHki@!A(gzDYMsOpQmk(1GsN?o@tk^YV39MAXin&8l*@?v1O($KWWt^${6WpGr z`5}BU*plR?hc99YhJNGBcbpxoHH9?oxT=zi{BBa*vaXL-qtZw4es*Ht`MS4mNcE~TR-I|C!Vg)oF5?{u@VsC(WcP1nZu zLT<%4=Rqwu3%N}}a3dHR-B?@5faHn+4ZY_$*H(T$Ya}uoVk-EdR#`^2(1UL>37U9n zb6nT$MQXZHn_Ek6{d0p&=8z#c!cbNBKyn3=elFcl?IT`lYo)ie_ht!Y@yy%4vH%?* zme!v_zh@F#IroFyMyk2lUq)Ma+LD1zwujPnBs=XpJg2&Oez>+a@5}r| zMMZT>yzqeFPHctI^3KDeff{nN)H-+^(FE5+-xlXHO0k5~iB=`o->mx8@lpAhc--?un$H!kM~G zW;9Nk8{MZl=Tz@dvXDy!4Et~F-s8|g;NqFF&~_Grmv*zU+OF+4*Qa50pV6~|3DXeV z7s(kk?Q#}Rx}aLzeRa8oVB1=9%k6rcj>hvhZYV(Tp-S@-TRHd8?d44sHw(E}Q zhZ#wAH!Hgus!c0ldqkT(q<&LsR{0l4I*xd!GyTWhOd@mky30}`j>@zlJF ziVp2H4g@bG^d+G?a<7@-fQ}3Z@5o^A05Qm0TUme2leOK9Kw`JHwZZMr6yhj$pYica zGIO%LM6ko{&+encK*nRaZUYxQ@{fTK9TgR_L>GLNhmK0-fR-;`JnAH;OfA8ENpt?1 zzin%8QoX0p*w_fSKE0cW?drf!P+ID1Qb}94#6#e_-uld5dgI4#$c6a$&|Oqi2!O%T z%)*05&-HEpWMp6W-OVEi>THo4 zpK{n!+O0nbtrDhlBlM*{dE0^~x$~hdbQC8;;QQlu;P-?Qgie+TGnAc(A-Eo$&3Iow zcA&SWrlznUw-L$P+uC|OKRdH^1ffc3Jskc_rKFy#XQCf}Jq;rZx>*crH$SzD)Z1_Z zlKiHp3#eWG_zi=}0LKuDhBzTeWOkdTOta_zSK|eJZ8F@O`N!(X3IMI;q0-*Ab7N1O zPT%n*L!pg`&R|4%Gmu^|sWjHFNfy>?lZD%ljney;r}H~xEe{rufA9T!GLam~eg1#e zfS=v;nhH!$ct-jsZX6QwQocJte8I_o!)JS>7+P=J!Uqiyi6z(~s9@YHUw32pK; z*)DkY)^V0p?*c4>TOhDDx4sSD-6ZFwH`_mP!*E4)w^a6!S=l5q5lY{U1~qJRGjun( zc~U>lwa0l??8CYS^-~y-ayZlkTE%Xd5g7*NhU_WuwP`KsEonhmPj);PGc=#WK z;MQmMC}9?<&4utOZ6*hfpME@yNRH&j?}>6azz!|&*o`ACNo_)epUxNpBu8?D1G({g zP&@g*+r~jcLINFIYPh*z5j;pFcR;(wsvHWC=ATi?&0vw*ya;_=F$96+c;>c|G|KFj zr*?&e@r`d=TZ9fBSOgCem^zC@4;5I%4n0@|4>By$Sm;jJdSblwJvUql_dWe;cRk92 zg^&Vr0XfkV^AiM=;70RUS>(20!57JeZkq?LYXqmo{ye|bd8eIVNp1@kypa5yQ|239 zQ^-z>B6gnewoXs$%&pPw&-BlhB)4Dz+|+Zwr%;zy$L;9WVF^w(N(bXvoe;QA+eFs?DavukIae4IsY3lWd|IFg@v(makv z5}A$o%%r+k9(tqft^*CCw?zTiv9fo$q%{^q02dy+T;LL2G!MFTEP~7Fl=gT|bELcI z{*S)=j?&K7LaGy?q@nxK;=1g)Uf$cU` zN^7LHEa3$v?OBspW60K40B+~I%G?R=RZVBa29>lJW*0%?P-e4;3T!@*Q?iMVz~)XUrx` zYviq6k;*o(*(E}wq*kT5OlW=kyE_R^$0)IJ6$&D)L~uMXQqx6FU00+%@KRl>EWY^e zCyyCr!9u9u9$nczdEQYc;9hli-*RUPCY=TbBrKWIvTLO{C=wi{yhL&glgRFZuNM9sh`hF7At*TUn7J~kC6c23Op?wLc~L@3?&a>% z+sJy(3~o%K>$|2swZ%I`aDUWvlHwYIYo)lftgs8vqqg12X#pCNOIm@aXG_Oj$bB?! z;M(OqxHh=;{P4?vf#Z@f*<@*}BR9ffw}A-EuqGHwZx)}E-knj;>3QBi1dRfs&ui>h zdI=Fkd_ZZ0~+N6a5D{= z3pkU|a+_T4_m=fjRbtCTXYWSCJpClFFQRv7PBsnM*$2_vO0TTcF4TV~5!xo};5c)r zO+>=WX^^m%Br~<+nWke?iOt5H%c*NfP0wWBK%e9*st@DxPr`JtHqf>Hl63*tykf|et;ew+qt zbMu2njL5BM0j%=qr1bWi;709my%k*or>f&78`bDCYm+0dfk|++t&I|!5nW1KN>4Jb zG0Cky-~HMCHN~YmG>8(^dVXl+zvv#MwQ6(W9I076r47!j+A^W3NOOJM`VnG$&UrZe{#2b5XGi=5 zjCg_u1m#>|wk*j}h|9H?$fP;;lT*4(4QIwXiR?_8OBv@`CHGfVcLky|y$i6OA3FIj zc=8V8+Qv#09Z9tYGYX}0?_%eyK+Eo^{3NEVQb3{S?cMw-@twA!Yoxf$K&@3>`Y7e& zvA-Lw=*;kjDhl(4lO1BDHn~JrN`a{}a%${(@`?WCI`SzNEOZ>aiZ1tOE5S-TTs1Vi zS;3j{P2~K_`8Kzr1*nAYh}T-cmoD;7a_#^nHj-D_GXX7;nk2YFY^g6@66$I=pTSZ$ zn?+~~Jq*#ET*^7A-0~qmQG;$G6xKG^8`PLq;EUWnYen}E&J&+wyIQj;l3Q+XGcOiK zcG-hX>I0WO<~X6ve{M&u=oTzMAg$;Iec^8EIzKy$roY^P++LpPExg+nA9N!&9&l2f zCpimqBf8T5rc_kvttbLoW@|`ospb}X5Q4tE=}4(Dym4x~p4jYGH*$LzE!J5C)X_yb zX5sujq?UUoIzn!FyIIf`(i@~}NpK6@4Z)){b&sQw=87@R3$fXtDnHuVJ>ux%H_5sF zYsDEx8Jr@8^6?aD&*E`}r(@+lw>R-yRj;nDd8xDCYazUlnwoNruQ_LMTJFf3x>$Z$nYu2J7V~9Z=$;! z(7d^x29n$XF|x6ja2x4m(09$N?aUCTO-Q-RLt5HrTCmVn(7b1zfT!ZeOKLi2ZEW35 z-C;5BHiCDg`^=5#I-{9eS_T!LWmvNixN-{}jBjv*!5}CjQXAdho#YOfiq69u`HZf4 zj340s?UK?`OHH?+L9d(~ztwZU&;hb~BXA(K(|{A)UkTgMiXaduDJii?Zh_FNSFga5 zJ3zz@bknn22p&kXcO|X`3*CW^kT4je?v^&VC+H1szT$Kyt_2I>NPJTfJj(9R3;XYs z(%JFe7A%+K1w;XgdmE7HxlGPsEHdDiqsWhC5iI;(@<2b z!|AHGv=mT5T|`qWwvOS3v{2xiMe7Xo<3+z}V!^Yk+(Q!>xNUYm>}RKE-i!~om9Dk9 z?Z1L32(_X~QdEHnrf_QG;%xPW%S#wvT8H;wxE@b4*3kj#CU#F&7_(kOwgir33P`g*uNcO%&8h@8Lzy7!}e{V5187Xy2 zBZ{I+f)XRq0_W=Kz=;aNpp#3-Vjm}YFZv*Z-wR-x9ZRf3FHN7kLsUB*&%$CJFDLPf zC6QyN^vr-{?kTfKVTe`Pl}fJHoE=M^*iAO;r#ck^6-O0N$HwOv=PFq8n57#Hhs(J# zpgmRcC@Sy`;QVPuQPWfKK)0;_jN$Oft081MAabLPW@fL z4>?*-nPI?~LYEpj6TFOodA$RH5SwOZG*H{p)B^r(=S@yGg2Rn+lU(HYP*Ft2zzLHVC@Ct#2_su0s4o|_8g%$pkuJSZhUm3NOBhQrOY2J%);!I4t8w@P+x8ip z(pk_92)_qR0B{Z+_RtQc4jlI2t;p_ZddPNh55FmQ1|Ge=sk;gM;QYWp5Cp^&h_TVv zU<@Gm4Y&+gwn6e^>|?$NVv|;&$wmhOLz;DBp^ss7r}fFPZFmg z#i!6EyG!8zK0kzM%+3`-M`=g07{5CFFl0ydDH3)d^Si`wiFLu8;)D``GC!4KvUL)t zly@+cw+)r4#E!d4x$JW4;2wEF{s#f?L+EACFLtrC`=YZ z6nlt)9h5Q3zmfyU0UjtyC>$tGWVK|VWZ7i6O4>>gOOVH@O!Z8q$128b(~ZW{_i^?+ z#%r{HV#;9(MZrZ`rPLNT6c0JJn6zLFj?7D0tD4Lk$u^s69%yiAJS7`*Af(fTEb zO=+#YRA@hYNxm&0{*Ck(DGf=E*otU%^l5Z~7=2_#oF~>9dKcI8*J#aX-V#zZE_Ui> zhI^kZI~_?KyVtBo)hl(hMl=!F9}%tnOZ~_F(@(xPZexTJj#4x-?F~Pjd+Q-nF)iuG zble>iu1U@d3Ww8nTX&y#C)d8%Vz{w}Br2sd|1!F9z1F+zdRl!F21EWDv87odZYg>E zEkk^zxsfPXIID&heULG{@sDLzV}*7ajzmAwi_xpG@}Z|%R@b9xlZw&)(Q1Yk zjc$Xd2Az*JLbW{gOEu@JIsGYOj+cI2KWHtOT+7j(rsnopl~80dO*x0R<=%5~fFuitFn&+)uEA6U=lm$f?|W*-VJ zF3#bX7IjRNRNDzV1k65W!Rw&8{l2{`sQ*ya)p;ux)0x%A)AXvID6X#7>+p2~Un8=^ z=1z0Id?wx${t>ef^OA8WI}p}u@U(p(K=I*zAaR)xTR2u2BY^Xv;t}mxRfc1!x4}C@ zVtr&IYktO0;M`d_-gUM#$u6*%H6@_vp!Bx8uiUQ;Svn|xkV9aT+K8Mh$uqlIR|e=^ zer#x&5Y0N_CiH&af&73srP^*@EOFSwOY%#0a@9U9luK~7eUX3 zNAEaSO$qQDnH&2^CHN@s6@iT1%6*ncf50(emj2QKgd0s{U$6a*Uhj0Sv&ti1Hzm`Gc{_OZwSy)mM_^fQ?XkudPWNznd zQ6K{>3A$jRqT#F|E5mJMXTxA%Y-eb~;BI68rw9nIJ2!CA#>Clx$lb=;)`{DlkL0gC zxPi-mRx^?i{k4m;6(5O)tOAj+oudg6JHr=-FC_eML_|cqj>e|kN+M$aEDn6dM`G^m zY|qWe=;r3e;KssW=V->r#KpzM_=TB~nVBBA2fdSrt+RnUy{!}JKPvfGJt8JfMvfNt z&K7pIM1SfvFtl@V<|85bbD)3!{iB^G?iT+!lC9G}PYZa0jDNN;GBJE%{CC~JqP&0B zaw}N4n^Aq~*RK==1<`pwRo9;z4Uy!*64a;ax$%BN znSwwLsjPazu7@!X3_C4e#7BmNVC@y&ra9pcr31^@BKA6R`7I0zJg7qJNP8S{ls|?0 zke=uN$La#ObD;&6Ctf@$?u<`np4h<7VGiBUTMHc=Uwlb96vvdils@Fsn>M79!i$Ev0) zRIyNOKAa~#==$1`PNx-xoSd9Lie9f1`yksbXOedVP2h10y!Nd7*Hpf6LVP?(vnX_o zU@b8UN?>NT@5zsrTFZHwo697u!B1FNfc;E6F+IJUN;$vtu^c|Up4V&XY*pKpM%Xnt zc=)TQgWSb*c}jDL47dP)v@GM!y%cQ)MaAu=9(n#JGAN|a;l6Lr+sJ;8;GdD8B@CsW zNX28zm_=PPv&hR4ST5INTJW(H&N zqv*Ap%UE-aCbGB=XNuvKl$7Q?q@|^=F8h#auj}#ky{|$l2_CZDHawsgb(|1wJFmn# z-|kndix_)e(Rx1KE*vKL9?H0vOR{;~DsDgCHa{StV@DZ#bcz)#si~;!ljnJGL3>Du zMy0JFxxW5rMHhXfX)v242s(PXKV#u`JGUOoL8iBsc8wxmz(p=9{q$-vd3ndRfL4rP|m*S z#zt0A?*wOlSl`nnCQ;1qJ_C^$mboGv;1RS+3!?Uk{&*a=Djt%CIk~~?eSwhhbAr79 zV&PD1!=6k@HeX4(1${L&({N45=V>tnwAb&_42oB;eVsdm z_V_2+8GqVlxsR|;s*eq+BAOa1NQOfpla{AqK#)nyz<>mN1DSvI^)b0$euH@$E5hw@ z@#r)8`O_a1oT$iY4=YfJtd*O9&$Cf!(&MK$g378#4$B0mF#e5v908yG;S}+rgD%g< z>w!S>*?2n?B5qNATjde2o3U|GZ;nmx!ZB19xerT-*ARdG zT#8D&LJ@M&Tz(%xuN4HpkC)9luLs-kTd@|~b^Cc$^>oSO)Mn+*Hq zh})SCz$>%vCMaw&#kCgW8y{-nZbWN(%%x`OFeb}6q&!m0zLakF zzlSY7NFDRvjIp#H7DS<-qZelB-k!5$PY5WcGx@%{tEQ|3^C+qoy`u8yH61mt+V-_N z0OnkQ7lR7UE9f%oIk0|f1!eb-$KL{Y-7(oWHEF8B!{^&oD?aK$^7|Vsjf^HiYNaVcek}h#&<$sF`H0v$Z_Sg zF>jt^c|CXQQ9j##T7tUqJ}q@$P<36|a=uJI;CZ{9RbAyfnfWaT5uS+Djd~f95F$!0 z9P?9@TCc!r_lnnC0%wxDRU=p_#+CX6FsFX9@FV%zvZ5&>A|huXiGIC8l@?=?%Rx$> zxbgecd3sv`JsTTFQW1ORc(O=S&J`*us%3lh0XsN3=cETS&8^o(7j(vFf%nHkW-jx^ z%#}fWx3z$xA~N3VA<_!J5*3cgQa>w_t+1+8N1v2^zp`Bo_7_=BG)t4mzbPCSy^lK><)~4rl+SZ^DNBQ+q1;-_+cP0 zdQWDz_T$4QI*w*by=;z)Bok3EF!tE!6%yu_)jpIW+u*P3EVQ|3&YF@qdssu7T#u~# z@E0k*jgZ%c$23Qp?x$9`kl%?Am8sl%Hfx&kh(ahKtACrZNgtYYnvlsdbfIKmDC$1g z7g=LtLq%;)G-_qMyXmJyiuv6A#S)Ft)BGnvXP5VL4A`enYQ1Qtuw$l8--aX6KEu!X zqjgR}cbaI4B6IG_`u!U3IIV?i1IMY4Rn2egbdU)Uyf19aragpxA6$*9+YO5e54WqV z&E{=Ix6ROULX~j>?v(?ngqk;_+l(c=~X*_oAXsMpmuiq6YT|9PWC78`Ti z0$jT_F`($Z$g3fq+Vy7b1&v89e7shm3ytSNeT0>8s-_aruag*bQ6Dpi5)1R&p4*;Q z0c}#?iTo7Gnr&2w!K9FT<-Pr22$Nm*cRkIoU7P)AK_E3lZP)J3kw0nu5`B z4Lmwo<37VoyOhO%%sWXru}aPUz?Vz;i#RQ3FrM_c1zh{5)HrQz6-1XI1s z@v#WEUB`(y>i{IU^}x{y`JfZ zq;d72h|gAv9FP7a+I!SigX(;9pf>H=@n$~1r>>I<%yjX5v2hh_@`vImhsb3*flU&p zq{3!lnL$k)EB&!6_PwL9lMK08jhbqN8z!^taKRG8=c#@Ck$C*+@W4(SxxW}I>*9_% zxalZ>V^ecS3XjFJDCKb8T%*reG`;L-0}S76?N>;@pGN}eZg# zsQvp7bs!U|=J@Vmi56p3MC$F`NYepNk^>T1_y z7rh*5o2CoOola3LuNA;1$Uc7KT0Ip5P*^iU7B^tk4KShCXskz2BfdD?M&-Y;JOqyu zOq8Q!>i5vOSS`QZS&2>+y^sZOC`Sx zs(p^UYDIzC<9I}+!PqwchLfFr%ngVBrxh5Mf1y8mmfm@C<^%ZE84Abc=L8BlWE*!8 zGQ$<;(0R-N?AtKjj))=mgG3!9>DH4z$Y_9RGVF4)h3Mn9W+|?oBC*~YyAP_p+hrK@dV1fQ0*!zWTCmePI$~XG`7>Sg5y1|egEXs=BWuHW$ z*@>%-1o|6K0+*Wc6|>H~A3Qd?5r;P0pnil!3wxJ#!$hH|b`*Rf-?1Nk_TWN$i4jwp zG&qhnZ7axf-jzr{MDnrM5&>ndudj0$Wv9c4F?bC**p8G$_ip^s_?<3kYhL93wCxD` zCb?7%XBLz)_;BuD6=NEZi)j8 zSACn1wRV55FAis=7O9>H2%s%xC0ZcGS7AsWG^`7)dH20+h$oQN4!dSUB9TO{g~u+v zq+*Y#5UYoZsz2gLIJr8dexmLAIYP&2nHCyapQfG5ol`si0}3oajI#B>FtK$>qe{0O z64MHz0Bxu9o{5?X*W;;JZ+49o-<5|(YGlB+22B5_u}ZSh{YUhSh%5B)D1T|^q2vRu zOkh;Zc~sT8i7ZAoP3r~o9p0CHUVT2miT`a(=Ne;0mE3Q)Nr5@&EPYjkC@hbAzXN%Jf0<*CvG!eqSra1A`jnpb+ z4_ERYoC-Fx4qc`cRSuAY4*R*&_0Ajy}hbtkqw9IHbw?3r|ntmfji zzjdOVHLjrA`V-RONby851V`3mEiB;Z%nk?>w?Dj_S`R#jl4XZ6FqjNa=cfw(ppA5(;$>AofPKqI& zT5YDH-Z`(+RyOANMgg+-JWX)Iwsir4Gc-xVd0)ID@IxTk#{K=)Py=kQPoIV%^z9J% z(mk~t_4KjXA|M1Z5@4(G9#no9}xMwsULWl;7^?#l^%|v8O2Z%j~gjP#k$H=Q{2s=9USjs z#f;1V6HS2|FZlhouHq0aoz|EOW1jA-BWCgBr3oRa$?>08-sdK*@^Nh~j^7muefJR) zoidc|^F!T~?^~wHIV0RQ$Cjy*>;jxHw8hj?o=r;A?=Q1FI5QHqr2sQZ6J{NyO{tW< z_a!9;%U*VEwFPAQJr?lqcH7b#S9^=@ij9Gvo>Fk2+!W4?EA2&^hgf2-F)QV z>$~3}dbFrVlTed(>))VDtQiDBjjU>5E=njvR(!;dC2ic~dds}kcSB!fpKBdDj*rjQ z-S+LZ?p(vVKVG$2^0n(hIDPKToIvRN;31o+t^XOHMf1va4PkG^e_bjph-&VP@fOx} zk~D68A1Q*zZ0^sk^EBVW1{~=VkOzHrQ*3H6Y)S&mnr(m;GY!jzeZHyZS3drDKZpJq zCL>|nT^Ms`;kYPL=ky)pLB~+kEMfQh`mu2 z@BV%wK9-u_05Zkp|PrME;HP&lRBkpjX4{;089STSqb}n6P%R|Z?bt^ z?MpSa-_*G{6NiS$vW3$#z$U{^9MnqkuKZG|EDxL|Af(ZAE}_<5p^x!MW7i|&)6aP9 zl5kuByt4JBv53>Kpdd#ZE*xTv8Dg@0=Spz?N&QMJKG;R$%8#t=X5c_4cG!|7H?~H zm~D*M&l;e`yjWrmYWyfz#G=lY zC!Iq0BWIylvK*SE3i`lGPok10N>R;2fi2+Ziz>;iLM>wi9`;UD>Hw&3!hiH_TXa@- z0cH*>AfCuwRTYDVmi8oSSaJ`rsMTz@8GCwqnn+X1Vg&&fASeja?RKGO&+oL-XuUV!Ys~r;> znZS7<+uUq_EZzOG7g|0^wiKEe43xNa`J!dR6TVXI2Q#v~hXFzlzvs<32Pq@tq-v>v zo9SdujK1$vv0Adu6pP2T@n?Q-4MY&$jXERf$lbz7ptzMMZ)%Ge(ZTHy-S4I9x63_@ zb8MEqVbH3z?)bi5i94UK;pn!{easeE(>4*|XApvcl5-BbkJ7i~6%_oURr>F)7xo1AyLuE*yp= zTBFx>c~}_d$%gLxd_6nsw%l#>JGT6J!ySP5XW(rKQmA5@yI7-tVL7PlwjN@Z z>$Bi8hQHthgdr@oT%UWK68T)Doo`5iYdxp+qbhCfmyQAtHZALFfY1HARSgrrMv`e& zy>)#$Zzg!IUT-FYRz?Iqo+fc!4ue2Qhzgy45S7+oxD~+Yo7|r+_i-@e{^3FqPwboh zapn20=i|yy6rr=x7$Y)DN<2c}$Na0amd%Q{hfTlDc)VHF6r7N7f?u&fJj_(wPX~B!<<&ep5dqGc|<Mbz_ugiS zcVdXmVVhO=trv`xk56|GwZ6hhKJ7~{=RuZ}3IUF@$_ja^j-fa3BRhCFU5JQ7rlMtF zkS~R9@gsIzz{JFaCI`FT?sT!;YK;}nwgr? zfU#Tv84aUNCeUuRc^u`)Fq~yfLRwn69}8odvR8Da952Hdi%sP$@z8W@{BeTkq7^15 zH@D_HyX{)p_4j^W0azO-v^Wm_zIb9`gu2afvc(H@dER^pK;&gTi^GnHFe|2d>%2 z;6HwulyL%Vc^@xHa(rTwof7cI(TQziUY!FKi<`B6&`esC zW|z#!#=VAM>6Oi3dpzx>3PXJz`UX2KWDkhppsBJ{p@L?1-+H;|36t>IyCuzu*6#M^ zGDiyE4~)g<*%5JX%gsD^ob-DK$H^lOVnkNuR3x0_f3aq%e77Ni0F$%7cY1$)dVJ{l z_`%+=`7aT50Z*X1h3SA^89{LI@Oyc`Q&Fxr0tVP)DgkHNdHADBKA%=KvP@1^qPo@`Fl1^UQQssnuj);kv zZ4sY2`9O~X>_-3vvHQhF7x6vSAp|q{u&m_D4{eUUw)fjv`Q*eHBo--?jastaD8_Dc zOb1C0DMM~wY|c9|>d9*aie8VP#LtF3LMlc&&eNjd5fO^t6E=KGW}hhU+pX;LZ*P)j zsuE*a&`#t0UJJiR8cx!bu14dq*gvehRk|vIIcCHtWyXHx&Zb&l4_aD9!NU>wcy0K; z<(%<$-_ql9H_FHOP%4)l2~FS*0(8B|)0`t-0)Fq-$dZT6EL<5G8I>nd8@GXM7{PeZYdUa1e+48_!p%-~39ugaKp-ST|-q6bCNB>%EB)_0#C%aY!~Ufprd zo&5W?kDvJ>_x+ZVW#oi$)#Mp<48i%bu4nP_Dq&ncqOfNKoT-@^8Ijex9luN)+P;@9u<(;c zP2Qjiue6_H&D%bBuAdkR9MR?_MMp+D%2(7)IyKp>sx5!`Jl~clEKGsxyU&+SJm1&x zyLgNO;$B9yyXdJWu*ANKUZy~__q>oO2aLRK5s4_1ssz?#a;SXaR21+r*j-d-&n_e8 z?%IY?2->1)tE_IX*iJtDP8{Z+vPJARoT(n>BU!pXpEzjsgE2azKWf8Wcb?4(f)zM# zXdc*6nE${AMvw4kV$}7ki`!poDKmL+iR&jLrssQ-49^3-tyk1yrM!NmEA5OkUWPTkmpw4b#-q@_hdjyva?#jAWN_Y%ON|Tv+Jp+U$gul z;$`@_%NWj05IXjP+{%gf>xp)Y~@QP7emt@#may#v|AcQYHq*hF%HzzY77>RG2ic!&B%P3L7Vop9==X%=l_Iw$?4;tCpc9G=U z+1_X>nCzv$i(GCQ6xdf``wn`{P(JwWA1i%|S*3GV1%1omCv(VL<(c1>3M%mkvfCqNl?FxA7@*5Irj9b7bJj1h3Yp))=>H2J)#@kmJ__Dih!ceCrb zB=8n+)1m#?`BC=C@q+i;Z?nqLTA}7X@#9k6ZTCBRq}gw03W;dmgH@CY1lf7D!($TS zGLGuYH9~2f+eQB;(7X=aj3o${X5`$YZ8os++!}XFX`LC2CMYNOWW&Yu_%iXf-O6tB ztJYi&Z|PSy0@)qqdS-}BUFN|?YIvQHb?Dns@={xmQjRSU=MW|PHw&deyY*HACSl)V6j*r))Kwnc^4(+)978AgVU}5x^fmk;p2$Pa?}St- z9W3&Cc>RyJw{#e0?-sdhNKg77Si?SIMC@&N-3)R<8cmixyKOCXyTdP{B=c{aC7SZm zAH|+>)V85noiuA7)&yFVT1;12=Fx{(0r{oN_8%^=;h$z|Uds_CyOo25!|;z2)cHwp z@vM52q6)7%A{^2_elN6kQ$gc3FOAc5eOSVtWB2_BRLsOjv7vh&l4)U4smo$c|Fs`|cle&=}(eat^~z!m#vzO8GGmg53?XO-A? zi;F}u>sbG9SUSWrx!ZOy^tez_{6|Z(cYs=oVK+I_Nb-7FrHoiphJsNitKXmHgB}U* zq}aJFAn`p_5J5h65M!1yUs&q;N-yj&hfPK;$-~btgoHZVY+Gojr&BXLuICelG{nJZ zR|wn5+2eJO3FpVH1X*b?v3A$tg0`F*pbP1u&812J1%|U%V6zoIwi_LV)K2kidC{-* zphH{Y+7Xprb5#v+2W>lDR1H9?gF7|&t#7W(lKOXY-i(m2=q*S#Y5gYhNenseXQbVz z)k0}p#wXAZrZI7j1-p&N(*2%rS_*l=4j6b>vyy^G1?os7YayNAzTp;&kaadZ1)Qr- zx;33Xc=0_>h+4=vVUKb?sF=hRuAH|DvqH!Ory_W|=rvf9dsvR_sTyY)v2#u+ss>cX~!7 zQ-=@_I@V~E`T(5{XLz~=7!mS*k27s0L)PnS>8_GCaqd%Bm87Jobv;PSEHPCs(~n6i zS!1{O&ePd?M#H+G~RO=X#Ojy=x`tlo)Mf!)4-QBE1d4NZGw=r`h+!oPr(CHLKh z1ckyAPu0RMliDQPX>a3Zjz;~=;9yIEcKnQYe=EO6cnbySH|yH!R0C#N4TK#u0Hz8r zyt|33aG1=hBDmD12~6viROF}Q9PdP}Zt1f!G~zQ9o{oDGIH~lC*Ejdm3MMT_FYxwQ zPAMJF8DOWdt&mkL@)9JJL{9Vu>>VR@&m1!pE91rr>ZZ1Bvn@32k{^7)4evZY+xy^7 z;LSlY37KoH7xD~#d)c7#(9_)4KY<}@?%JX%xsB?@aFY@3T)N|)BLuA&Pukf4t25cM zOOvlBV6@?H{T0w>hBJNv$b&Smi5>l%)-e0OxGP&QN2a1Gtd}A?_kij)M_-50=^-s! z9iDr7l5_Paj+(3x`Cg^!1$y=%8`Tt4jafSSeEIBKkYFNOmTul{wr|ty{(jO5!Bg-Q zyQa}Z@_{Z77teCH56|uSw7dY_PB0+pL(ABA71#CEg82bXww?x0XMgkreN5GXZnWLy zj|~TJiL)^Gx&U%2*le68E!gDCG}IV*?nL%>W3zYfbVH4QIMIw3meJ?in$)VSMf{lJOH;oQ3R!sOT z9_7`?SM$={=`Fq|8SR!5k!bcCfKIP8_|mZP7kbj zkMRL*%<2$4J~lyyd5|sv9c{vJRC*N6?)(T_0^nvhPR~mC1RLIZ{{B^!)COCC3c-Xq zi0hw(48kX?hTbRmnT@+wvh&4sLd-xBwKbBSlvet!-bu#GeS-IMviw1Yg^t$9ll4R6 z{WaOr#vCi1*9AQmh17SumB0_}M>I9>CpNuLKZuHTdDz^YB_w=VRCCIQ5Rt{la-sDAmd~C$^Z7;WtLA{Lj9)N!63-JCZa2 z4EN@+>#O?}2T~{Fs85%qMwswWbtmBWO{Ui*W2MRoChw@Kn&X?$zva4cbxWX1H_T#@ z;6nj4g1tyfRqyZG>cKLkR+ZxD{XC|f$4b#w9?8OZ!czQxap4Q%JrumV&$FVDOW`K_ zsn5ona`h@kK9#G2?z*~ZB{Kl0GHu&s`35(Hcm?b1HRxrpKL~4TLQ>3&Qku zC_+?5%l?`Rz_xK<^2iP~Oy{imFl|sYZ`#KGhR3jBe@ryOeR>kpQK_pW_%7vs#p%Yf zi0@-W$arKFuPih!x!!p&p}#LQJp29Lu-JDp{f>z9?*9FEZrM=_PK%tA$4t6@SO$!< zT>Vat^lrB02|`hnG{wx`VC*&)1rG#Hmw zR#eWeLKF)t4`t^qeDq@c#RN-e*kJw;>?lxgJNNXo*I8nKLyBjDDVRoMh}UD$MaE{k z;g-mAZ6}eRb`S?TjsG%Qo6G;-j8^tPRd2NDpt3L%qXZ?J|4Ap-;AKVCaCGecn+ zz;9DV0!%SptaqsMD_Hb4TFhE*z5Wkgt1ol)KY1+zQkd{vm=AMHa4>{S1}iL(^PEgJ z8_eR431^`Yu=BbHTzet0wzhhMs(JS(l;!zCK0Te*dHu;GrfnjKUJp~|Ty#BbuoTKY zW&&kuWOsi*=S$7R)HMnWOt0+HhUW==l~&UTFYjIm(<|pT&|RZDJ9*W!-`CRlyx4t# zV#8gjQ*R8*yt}%;wot7b1*DOk6m46@Ct#c{a#mgd|4&jaRo@r3W4(IFu3_1J5Xa2l z*aaELcSy{8!qFBM7BrqfAL4XAMCpD$rd8kgcz@`jIXi8bbY;}4@#%so*Zb1cD)UEl zCBRfvRNNtfjn3`=82~)s)qJ&Iiz?SIFBSz)11#pGphbp z37Qo6@K!Knp8PALnGeyi9g3&2vQ%eOXEKVJJm@r*&H|m3l9b2GsCpDe=!>1nZlm=3 zU-?YnsGXRLOVj4<<>7Y>$3{4i1k36EB>aF0sIZnzUp&BIOyY%kSfO|v!Q*1jdvW;d zALUaIK_wL{1Gt=I5o(gvF}CfZ-JUL^Z~8oBOKCTl#&DmnG*#lxjlJI<&%?uG(kXZ> z5#GN6>sQcdw<2OyJ@5JOmC5E-MdUm>I%)-?tZEM*IK@!*O}-I?mWJ zN$dsQXR8V*EwXhV>(yujW|0-ML%}eb_48wBWcC5X+;&-rTpw zF`C{Zji{$zXc{GMlXRrq&k!E;v3yo~c4 znrf(Bz1P)cr*ppXmi{YG%6(WFEoqMy0AZ@P;eHOW*=&;+1IaXeT#dz_KFi5mTkhkbnv-afl=x!(y4>KInive_Zg_rsv5IhQO## zYLfdP9xrDtmDi>(zVA0@-ZPPk#S#3Nb2^{h9uREGKFF7~hN_ru^f^H{ z51O?tL6n=%H~`K|l&UILyf$`qg#f>|L6*&CoDXYG$>WobRZ(Z9HgZk5reIxH1wO4= z&Lvuto}Lfqh%0ZVoWP9cxbB^_wPucw>6h$)Q$~C@wMx~ykP_s+KeW3u7w|r7jS3tC zM$7>dzE>B1AKEq)js>xS9Q@fbBq4v&oGg-WGtI`A`vIoBHs4CppNz+p*;&sNq0pug zN=Tz1NF>)_Wtpe%f5_({%JF2nazaM{6NE;X&n@@J z`8|UB0#~O@c6WET%=7rB6gWLp;k(b4t?b-6O*%o%CuM*{KsJ53-DjmLiOkc4$345m z&+_`b*rVpKpN9pE!m{Qc#o=LI10ZCrng2dpzg+v4ydp^jp~Uh?F9j{Df)4zkpL&|J zOGNU3fK!%iSNWc?xEQCbp7~$&+VY29=l4RPRt~Mv&m1dmvbgbB%~3*;@K>g2RNLz7 znVV2beO~U(fm41##|4%X-EPNo!yyJiG?qm|@2xes~WE@_j{KEhDd)#ZaRZ{8PNqL~YCj44 z3e9ZpyFgrZoh`&ItLFMr<5JRGA4Zz9HpTT#)~Fv|SK)tA(+n`nTUU-m^v7Qkm51ZI zB+m`$@;!?Ffxl=pe(lDv1}s%!(rGFN8U^4gyuzxn)Xq@L*DH6 zX4}usRc3JQ%5J{?m6xsiM_yKi4-#*v;n)e1t#^DBJz=WWB+b<0O&dLch6{nU*Q!~N z5E3rH^y{Ty04mKv{y&qk$V>TBzLovni%1PyJw}0nTW({%a9+&t1~K7*d>r7g_@2KM z^$MmM1}XAq%5quEhs8&yJIve=2zkFeCfNPL)av_D8#?>@48f4ZXb2?Jy)CZt?4)Hy zQOS}>YzOMLX}cn-fXP&YOlv?}kvi4r0F;McTQ?M=9-m*S=OhR)pIN%l6B8|{@V^9E zzw|G_is$oUG|{nureqnuad;{G+c*hCnn}@i|a+D)8i7Dkb znxFqytjxX$IwY)|AiV z<^JkI&q9jNH0&*|iScWfo_>$qqqa%vtK!1fB@xjUwaUZMMVmoniwSkcH`iN19nan; zz5Iw%P7u59hW=!B(_0DpXEt&?E~jM1ljYJhU;m7Q(Z`!#B81>1nURCiGFI@SxMX!DqDkgP65& z9zaFAOjqwCbcX<|D3~4Xa=h^+>c-!J${}^loAp2^K#fRa&o*chC4zb*zK|0#_O=QM z?L#|%wkHC#YMNA=nrNZ=x-XQ6s;h(tl>*r|hY4~Zq>XChl8|heHY=1;91wYwI7Lj( zbvXoeg+ncCRdHw=Q!K6fs{%3k&ez7#How8!+B)rmS<9a%0B&p3AMLe){zY;AMW~;W zBHv8^|25lc z%5#Xb-|aZ67Dlm&R!Wfssii76m9%ctob2v%$<&uojJ+aK@evWX!=PCbxcG$Rm>BJ5 zgK~2O-V30^vi@JBy<>b_kGr?qG`7*$Mw7<2Z8uJ1+qT`Pv27=fZ5xdno6pK`0~e@p@I+gt%^9p$4$~w81>WOlP=%l1h`WVu)uaNJwDV zNn35k$Kl%(T7@MalxsELZt;>CYhV)}ym75bE$uFny^%xEQe!CJE0gW-0@3z0yvPG4 zsc&!Ut)7Scr&j+1bA?JLmSwwc$2Gdy!NmN%BXW=;-Cj3-6Yx0V&`y4UPoS=Z!}@0oZ0+`N+WV59@_bJqONQC$x92gT{}p5D54UTbbJ>64Pni7nN-e<7~c zR1@p0(A&1w_X@`T0N<&MWo)S;96EPe{X?lX_HA-ndGB)wdFQXrh9DxqDc*O;Tk| z!jg(4o194~sRN7DMJGac%=77<{j+v83VGmlqXLWRR#lUujU7GoS)Ok4H^`V>x@nK7 zDE_?C!wqaXD&F0U*CmxNF$(Le#SFp1!b?VYj?LU9Mm>dIkFnlxt($2jyz=KPlG)Azzy1a{a+3p#AuvFHUzZ=?{nFLjv?W{y|mQ_vHnE>8IqvLcA zlK)m((PBDDO$#Qpkaw4D`!MCyv%n6=EeEt$2-T{3)B{(t@0IZ%YF0y}?d`(tO023O z$0-uL(H#A?G>$cr049QY9ulc-{DAx~Gi;<%@4a#{Hv98{Q2TVyme?dK>-Ta@$8v^oWK zWw1(v(V-E=u2bS!{H$+?K*+8Aza_U!|24U7&^*bSkRy^mk$6hcvT|4 zeT0YypPUd9Y`>p(s0qQT`<9i_xLiS4BDN7ABvf}$FPrFcG7XeH2sx|o?akZcfF@R za!mT0<||W_U!!A9@#@CsdC$@v6TL4h$IRfxblfz1_cv2OHd=-1HzA?A<`9OSDH1=5 zQ=7;slhn${>UKk*mTl3)Qly1U4;qf(C-O@{#gR8e2InEi;~Z==?QWq>Dv^iR@q+(0 zl2zrZ>y2X}NpwCvKI2?ViQywSE*Ag6yUKGn76+5Yc=a6e&bC^Rtc3Rw%wDWYbPc#p zBZ)iPL^pQ-#$Geceik&l97_?&E!ig zHQ8)J;~b^sIGrpkHQSMNKJ38e4;6(we!La!BpI z)0Az^paVOg|u+E+Ehh^qMI~2GNNb(l;SgFtRV z_ctKEGx2vJiR@4`5Stpzm#QG;=2@*aQf~qj)`u^q86a`3NMU6cg{Ch#A^3{l(f_1~AmVWbR&~8$^SIy0 zJGYv}eB03a)%vzM}3~XPdzq zyj6J>1;0S+^=a#iuYHYDek|PWvI$g3e`gOafT2gTji(@e(jC2o6$6#%_I3dKOYi-V z`ZG^BVnL6BLTNHh+#GVnYR>u>)4XdAAa2|QsqXKitVR7=8p#O;`FRBbG5Ta`uY$0K z#>k!Nogcfl$y)HP@Vk7qDHrvXJ<@t7EN!i2Gwn5HIWjU-j1<3{b1+gTT;qdqpUZhb zqtK+hVuwoAMrfp*Z~rmD$z+Px^4>3S2~bb{d}w@9%#xCyIm)&gq=_wVJkf8!O&3>F zE-ejS^c70C0=PPzI6e;o4}BXhf`%HuKjxWSf29j%ZY?Fj6;kzxVN|53(TNf1-Ejzl zX?8&3HVN`z;!P?a>#h-x{uZ8a$2tJD(SQlNrCFQ-cF$;CpGc$pFsA2W5X~IPryn{ zywL*Tb+skiY<8?d_sGd&zA0`Q-+Fk6Y?o|>jP40)-)JT5X3a{=G>%Iyx2|Eus;t5( z?4D9Oj%}@^$Wg0e(dT&RkH1Sn?N6X_%@dB0A5OZNm+zI7hvH1+W>>IuX3#~k^c%?- zR!m(Ojd(Smu*SxR6cNvF;T4i72Xz=<%O>}^)eQ%|+C;eph`lz3G2*5QzX;%E$TXxR z6MH;k;Oab+*f&*(UB(4eWA2mGs%SZKp93nd&!SCc6oF{|qpL2bwR)5cRs^*RufD%K zRu$|?;UC)?!*?shOa2ZD+badRK&8YY=w7Oc6y0))znie!F*9f{Y{8CKq zQaOo;O11L*)9lcF0z6b&S~ykQ=3DF@o|IJVv=3op`xCAt!l}xi+C{Ib+Nl;*qC2-N zox&;HoeWfX{;VmHmQ&0XJj!Y{;h=) zQY!bUZf!`2ruM+P4DXbd5;Q0$(kYi5zQs=E6wUUK;5B}PS+;X!C;#eY``wNZP^Vq( z#jUP?uL855?TM(!Fu1aS3X@`DGLC)*ng&T#W7vhtwjsq=f50CphZ8|^qzea1131`i zE2S}Fi6wDuf14Qxs7)=Bx5c4g;@}6f#%=$=G!{Au{dzge*pxH(FtdYVgvTCAv{Pea ztXl4a1Mf#p(Y%fU+nW`1q55~5aspK4>c8`fTm)JaP(fF&N43&vKZmIXvJGda#6l|r zQ2k)q#Akk^s7p~JGn6_=r-E+_3dY}V6`hl~43hUb{S7-@uo4!DK|7`7~)W;jcukJ`|X%_|+6D8&*Oa5DgBoqM^ntrBDIu+jvUMwAo1|?{&W?OaX zP&r|yezar&b2+oLoo)u?a`FV}6WGs;t+&HnfQYmYa2Cxk&Wve)hTeF+X7*8DH8>^& zkrK(IN25@8#6n^~VI|kjx7lD+wj2}KNWQJM75Ryz=(gNXgh?bEeKZAa6&xif{frQr zjAiV;PhL{SUL|V)TjHi$dgWP#2=0w_ zosrMh(XSo($t7O`iq~)fl`=+FUT6G+pJcMCp$;5|SJjP&)G9+mGsa6ym#|Lzk3Kk^ zQqtq!L%-%5|LYDx^o2sm4NucB8mqCxI3l`fs-#|$JUytK)0_NJ4_YZH6oNXov$E&@KSEPj4!^kNg9CVO(S~kvMa%%vz6f?pD|1TZ# z1hX{B-v2Fb!v{A`ySXXHHnsc!Ekj(2o0s;iA6BL@%gTl3ozER?^75G-zrRei3W>oz z-U^e3rfByS5@VB5L8t1Rb;r#}8YOb{fu12TDLN$!OTP3z+dYi_S-Rc8S-QS_9!i|I zGOi_mow_fJy&c6i?oG$^>#K~d1>eydrA*>1;9bx;C2vS$qaF*F)oIn6+uI}**f`A- z+9jDHMOoWi508itx!HE2JXs@fcEci;K6Mr|{&MB~9{2@yQdHV8u}f~*^0;nzPVJes z!j@K6^(T68SW27Xkhs@yOVX%pOYuw)@p4{2Zwz|+PemTVol+xYsk43UG~(6ZyiKp5 zX8Lvc*j6n%Yod~p;Ic;>B76M?v32EM8Q+X(HbU9`f!%)k7@9apwFS?JT4Yl~dXE0F zLLVGxKVLe>oD`2g`>zI{8iiV2om=YTh`5PSkZZ5PWHap3L_zR)=F3WOMZhKLl)vzbj=m^1^>Qa@SzGAIBGua9c54g&faG@xQn0i91B*lf}@a{u2SEL&(;ruF|Naq`>1)BySZW$iPtWjV!mc zT&snb5;4T`*>;l*_b}5O5)Q+NBIa!CqmNdNW{IB+7mq8J*m;XaOaZ4>!59|$%xTnm z()=W=I0O2fw6OsVq@c|R75Z$<(Ems2cE)=&s;H8t1NDS}R;T6+X6yX8fJR6+;nWZ6 zCx8~Ej(;@!_5s5^uyUzZq{3jfT_}SVIp7-DaP<`$6;pHj4_afz6c?}DIa4xtb5uLQ zZgjYChR1N=C6Iri8cs4I{~|J?=w5cj9CwI|G!mF$pxU-y#v%VTwN49dOi`J%ZE10S z)*6>ty-S&>uTrtlcQ(Ph9Y2D$&}=o2tupH#F23zvFNrsR;da)v2T2kr3FS##@Ztkm zrqPP=-x)flMQkD^dOO{1Imt*--M7mmCEafl`9c^r|BjL(p#M8c+7Uhut9M!JTQJ+5 zBd*hi?d%pR%wDE^!Bo2STaR<$@Fg50*#TWM|A(es?ub%+LIx=pSqqe#+Lmwk;|&-Q zE1rGgg7p3;1!9!8q4Dj3>okE{B8d$jzK7h1xWt)_NMK?U%Abe4R`&s-67-56!?rC2 zG#>ukgtJIMiVk;@0;!ojfk|9Q`h!kSfqNad))XT>wO0vRzmzYWK~CUEyIzCbGB}br zB0Zx(IEsz7l+>5(W+!QI={N|zO%l|ueJgrJ&Th1#cqLC<7bzpmo@rC)HO^jXpoGBo z1y0=7MKR$a@n(AdmLh2MmnW?fzBZLWpl6t9$On|A>}WGyxbha_Q<01#LMj^H4#(eK z3m4$t(7&LpQHYHW;?XejS2wHFwE&1f-51B}sXZ9au-02AL>Npu<==RcTM_wQZr^i^ z-mR6FXwX1fTFaHWx6i2A8FSrbC^V!S5+Y|ZY39WZwku$ir_CZ}zYK!YiI6ra_Z_ji z7?ib&TTUae%lAp@X!i_oNB1>0KOCh@b=vT$6jkwc&dGiMBSW~KJ}|ms z>c+tzxU|cf_5_oXt~cB1+2HFhM{Xy>Tx5iczVqb@3Zvzy^y+@MrflHH@L#{E1N|CL zbGP?xlF&p*adw>~QaB7_iTq0Rpb;GJj11Cj4u&j->NW-ovgr~7u0AY^5?G^H%J{3_ zb}XM#56Eg-9Fv^g{EMH?oZWJMeAb3DoQj~Iwcupt{U~v^ISfB`3D&wU@@Z!WUqd(v zz#S-%c{>hbS#G8W`Tqt2-MFPY|Gd;01_-q^M)b?4T?mSHAxc*>F#;MpN(srqpFcN~ zL0B}!)rkU&gef#i%x47#m`J(Q+R{cf^NhaKKsndc9r^Bpk`BtzwO2VebEvqu&q!E8 z7^kSEgY@qpl2tTd>Ik65@_|sWdx%sypJ(-}*Pp`TQpO0LTjNbJQbD*xpZLi&nHs(# z6b+^XvX<^y5s54xqNxRK!ktIg?vNivifi9IECOha1zCa*c_x~+IrLS(A|H}AHfLfS`Pl7(-G%VT$w zD>fW~O|l2i^zk0a2--SFd_>3zDu`z3=Mpmg0JyuMV$kZWIQ?U@6VLtr5OW4Gf<5lX z!=}31x}tsdtkFV_a7KE6xMyO%_HeRkiK4kjJNx1fiovodMYa8Y9GGVlfwO&C)$6S6ow~71pd?> zQhswHxU*4@nalPO9FTQe{MmlJMwI0QP#$ENKOAG@x)Tp?a%Zn)Zhw-J+mLCpK9cz5 zQ{-@bmz9|G921(Qmd>IJm9-4ID}v{rj5DRSZ#r3lXVnPp!>R4;Ssd5e z;XqEUKGzEf35t`fL_`MFn$pZV+#Sov=DiA9q#QcOjcty-`$ke&=Cs=e=hp~FRo%|y z5!yj=_rCbj2SDWQn!PffE~acBPT(zFJ({vtznP+ql%<_s*$bm2!fOApIezr!_coexihn2dBf^^PIlCJO+=T z5VEY3eDyGgV#fY=L^-G3Bcf~xu*u9Zq>t8z9E|l&N5ZMCWHw1FT`!-R{rw|R-BDtu zez&1jsrx3g&{(xu5B}bCL00~7W$`ii%O9%i*Tz^SA_Moyy!FMV9do)!)P>E;3<-2S zFFVji59vmL7M*ABl)>rC=7HeZiyJ2qyvZ!^@C{OlDN1 z6kWh(3# zRenJu-Nxl3B5yXz;MTK$1bc}&O%Djx2zjfB`UKf6sUe=|u=n+@>K**qTQj0pi**E) zU!%A_h2~bLws@;V(`nUcj=bJZ%I>5e?K9Yj#;2FELq-zi zy4UF{X^F?NwZ*P^ifL8huj}-&jh<|-Kwa!t4=19BN#M8*_3y?t@WHQkJ$>ftdd240 zNpw&~U8lABqny%iU-DdB$7u9YC1Q@KM((SEL0`j*=MU*8O7d^uvjz+IW@0xWn}D2U z5)N-$9h1&;$^6gkUACwOa9Y4wIq}9za&63Ev?tBmbs`foJ}wij9A`qpDQBH+Gi5fY zgm#+Vx(xAn%5TIQVtQ~Q<3S({Oi4+c&i)ZeVf;DQnPW9GCrZM;Stz)}<9MFA#WlO( z?h;lz7!r<|X{J2<{&b+OhOJ^#7}d4q3DD7hf^n!(eoi{a@HpguHj8{w95?;7w|@|2 z-Ejc&;yhEO!V$mjH6{P$HakJo*Qlssqte4A!(&$li&vl6{!fA!`c+V(t6Q6SeER{N zB!oI$g&g*ZFXj(s|MX4dbh1X*|HP&D{%>45Vast&hw+gK4u=WJ2Bt>hg2SM|H`5rkgwcc8XxoR~>=_NHtQxV13(dC;^6Xb`m(-*KgQto2>un6bPb8GB&d{Dm>3b_cN}*n@ClKKAL3Gk;)aLj6kt-xTxX<>yk{~4` z%W*m1IGig%1(XaIK$p6?RHOa}a;xLf4(9?Fwx1plSAwx&c6+{D4i3f2K@e~{LIG%2 zZ$;BaI6$H@Lxsqsvu?}zJShc?WLf5j;k$udA50Dc99nd52x1-(j5BoHpjdakI-^fM zEe*mvN)`cbl3#-S)?=Ci*y=QA!pNOK+X(E@3}zSL-CR_5ZP_Cq9$a?;rcvJR9}X5U zWT3MF%8Fe8u%_mvpcrg^K5P3BttQb21lHJW^5&UNW|dA*DHRrbesIlEKmfju_01&m zvg`f1Yd}R!r(g$@Ui%04%SG?Nx%WMn5Cj_f{Q!;)mQXO9f)kV*Jb+E_0L^u;UBKv| zWYr9Sc~LJfo&g7@t0IDB+<;z{;hC_s?Q%iOri8V%=;T#Ntb5VR>A0aO65CUMFKM_F zW)3{83J?eYU2cbfXAKRFfwHR3($G4qRaQelA!+{p!Qd{GYZywWeicAY>Pus@$+80j+;3mc7d+dZ!pyj+hZ@!m4xxTeH9AE?IWKfit9@<{c4`_QgL5^3!i5nPi zK&;LJ@Z*BdTD?@3E~UdAH(-nd=;^vP$FA&IT8nJ^^M8 zrn(%hCTsKWq&$Hyq0!L;z$cy*V9^^4fBd{tIaW&&j|I$i97U%64)E#QF9g*qCMtok z52~PfO0V2Mla5@A#mZPe5SMi)OyMUX2n>}%K>bl#`e7PTE4iDUnVGW*LBKOFID(4e z|N1eOm>pd!Q)6gY-g}-kA#_6oIA{D)5MRgu2zWtVU3}i>({EE2^wjOdzrcaw3h)IWRN?5(|{}%IJ3hJRJboS|VBYq(6YO*spjd zycv)K{|5R5;F7~1Ll8&z8mhR6@NjtzjgtI#U_2BK*h4@7eBE5KtkOZ@rw^cmku{zJdFwR1am}yv_wpgiCRy)Nw(E4R^ zygu8wRq{{Xt26^Uo-yrUyJN9kwm@NHB;c=={d+BEZC%M|y~dst;|Az$N=~f`b=>|W zQD+%zR2Bb;RK4YUI?StNGVw@_*>KCsW@X>yVXH$>iFZ!PtJV zitWOSL%VKMu>cBX8;r98`1=x41tt=y4uX`NUecoSLj%^uc z=ble#7;_hd#shvL%3%LQ2c)hIKgFbrTjZ~i2J??Cq@^RDjD1>acnfQ+bzK&OWI{Am zR~xO6F)&oiHiAVTc00`vTW}Pk?@Px{^?=FSG5#)(kf;02q2Kq{V>K*R%T!I$`PkMI z>fL|FMml)x3fzBfE{g+>xoy6t2`ZU4jTvVb|A>&Gcx0!XS$jMx%AWi5<0q?j5XEc& z7OyA!1kb(pP~tCQ8ZSJl6nbzk+;#;H-x)Q*D|`80vk3t>uUNnj4E;Fn6Swd;{~yfF zH#1Upt5!`V^WJZt7J)Be%+sp|WDp!)GgCnsgt#uK!>${ zAr6#GWS9F45crjCwLLHUy+Ny6RD|gQY0kyfIlmrh9d2}Rp`fBBp-oOqsO}v^`b%Gy zu-qk{k}^Q^8T3Jk$m2lMVxvRK?~J%}I-kLi(0)e0qmJ8AsSeW8NA=Uuj*Vd9d;6qO zov%tU)6_E`&V5h<_MPp#WbWj=cFw$c<`U?$C}7oj^R{*C#b*rmr3IAH#w)Jmjo60! z02g@%P~PEK4XHbcg}~!l;tSqDGz`h$Yf&rk#VxAty*>hp7j-mOlAu-cC#wS1IL=iN~ zF$U5x!5^L#)hca%hw?Hvo8lH&zUr880d8v2x2KD38`|cR_Na<3)1bYoa(!0ne&m z85dGD+aEGz$QiEguL}Yv6zaF$$rZg7py_m5vu2na(yGS|=#;Yu%vm1=m}B5_uElP1 z9D?t1HyaCPJw|;BYQw3MqS{*~iihNXx^ED2)2)5Sss~J|%brzUuMl{K%l&%d zH_&V_Pg)|s;GAe~%Ifw*eDDJlD22l|=LljI20zP(zyDAs#Bv3UKq3rTUbEVoSMw&C z4f+)5=qZcD)<$3@0bApilw2O-D0p;~g_xTm^;;oxr4)B|vMI5tf zNE#|e`k&TaCZ9#V3DEFoa<~m1>5#viv;HkAdb^Coy54g6l|NZGqMAS{l7Xkj;8NQW&+$bd1!vTLgcEBj?pNIPH^MRU{yye>a*7H+0J=|2r9 z`fP%s=No9=cY=9Z$8qdIq@sVj4K&aCCj1=XAh^*j7Z+7F_Ia_vHrB9sL~i|X^swRR zyDSoBQ@K{*xX*M=UoLp-trkI6GPhT*CpFyQz_5^XpSDcR3D5;oWU&+}a3K7%S1PpV$Kz8auL4#(k*@pCEzG8{2pmkCp+rHgHk|YXh4BX*W>h zX3@GzfctDCahlcFy3GSg@D>mA&6t3${C+sofFzY&NF!x}(84LCtSMF~_;gM1>E?Ny z*+8D{I1cH=Hl?^YKZBa?r*xTHtr$Telv_z%Ggt3aaElEX1c=@f1{k~qL=D)MOAZt+ zD3b}3Cdz*tNMEnlKP~T(Oj%XeXDjTR26srO=U1+-X&Y$Xdaru{$+vF_l`TKOz-w7_ z5D$mG9=3e@e01G3?{GMqy1Sng-B*U#AM*(|`Qr5g-PbXw0k%x7s*%fl8{a#1#!{l# z4%1?|h&ku1pTJWxyJAz)J7-#PbPgo*$Nsz;bB^dFZMd7dx(RH=@~E^aqsv`GD)mWk z>-}4=o3f_rHmy{^EH(9bz4F?Pvm5Y zmi_w4`V$2V?g=Q8Zph)+C$B-?Rc^M3MZ3Qw>h;V@<|{-aoQZ=5ZO@v-y#dRgH#1wE zEeD;z;t}QI;E!etF#N=V!4nEf72DUhUiV9UzxdBpoE$bNUx}YGfodm<+k$oq5b{_0%?N%y-R?d3$JDP|Xz7Y) zKN6ogE>nq65cA3rduA}^P=>&#EzMhQ`9P8F91B&Tt}tfb^ifGyp9;^kgy>lvIVc2d z!QI5vIdXWEi&{w_3pbW&s4AWuj$IgeAJ=?QAr5V~s}-96bbY72WTZCgjdMV-q>bJC zdjouZK@sBo>YRD1lAYaX-sIFq1~JnkxV(xtYmn2aXmYrs8@iG$SQ?9~%sgT?-Ft9+ zE7?>m2nz_|F~j_w13&k{g&Gd_4THBRmeSL~h1zPxwNbwOn>1i8GhI$?#>hLq{ek>qBD4DxH6FvVHA>(t=_mE@Xg zPX}_?f>Mr63QG9>{k~s(iE5}Od?ourMsGorPi`1JU(Dg_xfLfnoE05(#lVp29~@~- z6^_TRjOi~g(8MhTwTYh%Tje=WJw?pIUe<{6LT`UnIsE>yy^pez&^f828q)>|%UP)N zJ2fI0tYy)K2>-YJ+ZU~FpXK@x`?Tl%Zxo{6*V;)EGSvhr3w1)3aC<=M8+Cvix#tsx zuJeMJ&UN85+8LMdsC-M-6{?Fr8*3d>kq^BwcwCJd+Dt0z6@S$g9DTn_AlJHc4O-+| z7!W9o2RKve6TBw}stRq5U&eW)6@#ui6<#1f-&}~5{mdI-RSNl8$asw=!;Jci%Qqot zc`QOiJrXkKnxNv<3z4h+MUu(`A)HOiG0@?2$l-SdGvsJ^gzVOXSjWE?Q=dlobZ0e) z1|Xj`jh9KqI-Tx0t)B1;hdQ4)0;17ZJjbm9D?{6!hMsGS>DfvZ(?h#ySuBR}lyv&&^J+xiEMWu2gvyHis7z zBo^;T6RvK?0n3s-rk{tqf0sh{VQO8?t>n)qa_iDZsfPz~Xhz!8F09Uq%k9HKti_I5 zHMn>I&P+|E;n7i;cqLX*G}GYs(M+63`$geX!dG)uPzc2z47_-SN|O4#e=uI;*5g|o z`skVgLEx#`xLdBp&VG5LzEgp-GUUhSa{lC5)cI-QA^e=BhB+a@rm`nyjvh zF&Y*MRafnn`pA}SB$HV5-h#V)$Q`4y>r`W$pzX8k)ACHhLMp_t&08*_t7LJzs<&Kg zH}<)1hr5I)NBP^8Nv;DpIRmPeTZgN@undK=TThOZB+c?`z4ce9Bnmp3kQXm6*PL*x zW0U|PbSW_J42bUITK(7EBM*c;@X3myA#s(tyy&my_T1jkFe^S|cxX!}$kf+IqY(9k zti^V|NETm{(pnW%_LyPtAF#nGw8at_vgko;YIAo(v3zWmf4eyZoaj!i$#Fv81_gpC zZS}|~>#9ns(3ZMCL&W!M%ewhg=D1rugkF!%TO74l9yJOSrZyP8h{aMZ!aVM z!QN)e?W5tgxJF<%BjTvu;3ylY03IUF7Ql)(mefeL7bV z=Rl*4^;$#g6CsSlDf`tlb>Cru3+HqfEjw+baRIF^*XO>!7qOr0QtjG{Do5SI4qNHW z9G~ZRDXDmq@6IL*+x=0(jXvKWv{Gb$^L=acED`qKesC>K6~jX&htp5{q<-}U6_w-w zM1Z@wKMG@B80CSWkZ2y!3~C;}2DcFjiKB1?$<}c=o($zpD#;>xSAyb#py`ZUYH}E@ zPv5uo*0OUDl982v551k0&1I0&{rPOU2wdTW3*;qx`!v1>1Q+7&RC)ABI2(}_0V^Pb zP8=E$eut`>kn^|p3SNF)YG=9?5vuD3HxEq;|BZKhCpRyBI0RWkQP=tl{dg*)Q0STt zkJTkU6e@Bc(k_9LZvwdt%IAS5-&lRv9^{igf$s2TJ1~CZFD&MX;_TrO0YgNk6y)SH ziBw9bWfS@QsBbI;K`m}!dw)xA#v-bwjFl*qBC|374iEo|2Q^mCXo(WsaaTZ+3j!A# zR2ZHXQj`*S!k`930u4Cq(SlsJq&9pQ4K$<0iSX7f>0LP&x+Ijjt9rv_Bj^NNf`iS{ zdV~0LtLN;-2lxdQR9uG+$ynqvSW+o6X{Y<}JiDsEop?F9(8FPuwta)JO;0JkShpuj z`QbEjPhvl^Cfcue_`~_IifuB-Vtj&I7~Q$6`O*rWELq z`;0$BcawkRY3OgLtw58USA4OPKsgWbJs!;}CigLO)>WQb@ONMNFJxaGWbY zUi8Jn4o`brY?JF<^*Ae)pNRH1-X!nXSp=D-%BjpBRR+#vFW*{4wh`omg{>bjJiElD zSJ3hGYvnxl!n*mpyjR;PX|;a#OtZz5U9q04_c;MZlVXTs8Epo^fGu-X=rp$3`Bq8K$9dD2MsNG{@DxT?sMs$ ztuT3(O+P33xTZkNo70lnL4Tnbnxk&t)5zG8l+ZKTluK9sP+}@CV&9Q5->X2AHe)h> zz6I-F47&~-uEP2QC_0>`a|i0qlap?a{D5q>vqFc7(;hW!_`~Ti)%R*`3}std_i4KA zk|3n<@h_6gmprojEbR2O2V2eE4ZQ75yB@x=b_8xUfoQ(WFV$oig{;WXqIR}UfndQ& zW>AFF%0KK7&K~>)FTjtaBe@%L9jufebANjd)gC!G9o_uUkMRrNQ7on17T~Yrxb<(g z;iWmPC$}bqC5mQbX|P;Ye1aX6b1;_KOmhxgu#wp{&gwl{DIw8dK9?qO)4A7Q=zvuh zwxK*d05Lckp{w2M({_*4^}1CNjO_<9wJg_fuxXpGtDA4+IY~I0rWO;B6Hx@^+fY|i zNS`P|bP;4Lp>QkvV{L6KAdxs!i-Pe{=+;#t+co+-?^jfH3tUV-Ot}h~;96ydu5#z>AE@7-A)ziS_Y07IF#KyF1v*t zvQ9_!8x%dS&6xL!6+(eNw8B+fb@x*(`|j?p$m$Gi*!^=7x`L{6?i4$BRY7f~Qs>wr z##zx|CHr&z!J7LEF*&zQfb?kRi~k#w!RLayPMzFzlz^(I$l>0hHsX-8b_YLUbU%Sp zAfhhftBY3R(%pAEY9_*Uu_A+vDUNV?trNYBpB8p@)p+QUn@hm61mZ5(Nsn}O&qeh$ z)9gE2pPh~^N)PgV2vVpjNd#0}CB#^Y72wRtT*_FhWuhAW@OrJfA;dukiVCCDNhpw=l}B)6mE2YSzmW z$BkuhBw(z$VOmLWNxpBV9`L>Wq>hlO&RWIO)1Yo<6Qr}*^x_x3ZR%8)`u-9-2CE*O zkkXKWL8nOy3N;tph_G}C4uX;6uO}2X@Ci!u=x^*N!d9Bx1qa)?C=g=+;*N3yUM{Kk|_uh zzotp(O*+8alpwsSofPt2xcLxJB7Pz%!tvs!0)Jz%a7}ZKV$B=tUCz!ufTg zDw8QQ8eK&(wJQmu<00d4h{xl;fX^9k+mBfaSLLe+Yx{RhbIhIo%!t3loS9S04utRz zb?k4C6a+I16%;X$pRV+nBS1`b@vtt&!odMqNQdlQf zC~jXyY%C$;Dw_UD3%jG2C0$Vcz|MIh(!=&CZsQ%q;&%7cc>l;5gchX-XLDw&fIxta z{+`dxv{=wkbsLo6!*5X71&ux=A&T^|=Zx=eSymzQ85x$EPnWB;0Nr`d^Evnw^-a(LRcmcX5i&4gTukdP)M8WIMtfQvY)Mn7L9kerl!V!aNku0iLP)IO`(kBcz^=} z6)sg>wsceFUO3B366)m-TgsFk#w3I3WFu-&(K5-|(-$=?cNb8k5QISEP(scJUO?fD z;;bEnj9{Id8s2g;!4<^iyF`Q{$OksqWCwqb2o0y#Tild#DjaUxgT;?MYPQCAG`AU~ zqGe@SB7C~Dxa;>}PvYp4$;=+&{!7(HrwX^6q%?UJaQn5ub1eW?%@ER6yEu|ei z!FXLwSls*_$v#3)hA}WSFuFJ#!n+NFJWuWseCz?$x1sk;Zd$cF<1wvzVCM9TgPg!{ zPf@g`4h>%GRd09Z8U8$DGYHWVzaw~=Gtk~d;crrrTN{u)ou6f4rikc6ef^eIIs%zs z<7-u5sMPhvj~@M3Oew*P?L^t#WB$N_&>ySAn!>x_WcD6UxvmSCXaB+3SJ-_C38Y=V z@180X-@OePBk%Bb;r<03vJguWD zY!d}Q9Y82WhbayJ>6x#eVBOY#+HmTY!_myv!4-kR+XUFG?PV= zLf%K2O|*0{^_B$(?_NR-o+d~V*l_dHKSdf!ZQD3oS5!$Lw`SjddQ82)t`L6x3z6N1 zpNpd%^c;D@W{Hxi@#k|6d^tvv&x4s$g-4zk+-?t{Ut@m$3@3fayy?Uz0>qtQ%INlD zIlEVlrcD`jqt82{k*ss3NKM~pIpum0@V2(F9pHIf?8e|PJ75QeL;Bl+Nr6GN!`LqL zqROCBT607hAGoR*Y+CfYAeo!Y_jYBC`UGikngZ(^Gw|@{Fa2oyDRR7jsE!w)3A8f0 zr}d-vmiFuBSCgtirDD#YcZ}jP6Y}E!gnFcM2GIXC=c5UIOqB&CWEkOB3!(mGrcZ?0 z#VAI9$g%CSwRJI9O39E=JyJ=1aeJEsMt)IWUvE-J-R8a^A#>n2uIQaQg76*_e$OrT z2a84;x;3O2zGjssz+vrAD&v7nIh#+0{(3nCTszZ60+A zFj1nD-BJ&UYS@|zB2pCs3*qGrtvGC^XstiPzuMX$-M@kQ*__P5abt&zp271%i+oLV z7H|T}=y2AYK6-0h=`(GH$)vGez!6PoYrE&UQT?e0M+bzJJ`(OSj*8_W%L78agxeGy z{oFNmCTN38d&O6KgD&vpThe7b}< zaN9u)9)8fn8sdh!Uhpr>@;xZ`ol_9BhkU)g`{VO2wppPra=ou@)09ur1p+_#=_L!< zlJGHR)9g6un;XZW?C&Q#@UN93fsnI7h7j^FkmJIpxIpWub-gg=Yq1KRjzDrP=nLM~ z605)SodUT7E4nFNUTkWs76sSnd8$dp-YrIw7};YmEGQ*wZHBi@$<9!{Dh%vZuAc-s zHW#~ZZm*28`xY!r=;^2jSfq1#;f4i+^)Kw@JWj4ct_;$)igHHdHPs($+{ReGh|I)E z+8*n-XlUzEUSkO*zG1l68%tw)zb~?CQ7$??&XceVl!`dNzb@hu*fKq%C*xuk@ba51 zw1JnV5HFJ7VdsWKwK3gcgv+!B?&3UTOfl!Qqy{ABuL&jZzam5iDatluZS4IEVCmGx$3>-zmuVBZJZbD>R7QD$Ov?ilG=QN8}2#A#Mbz3-K zXYCwv&vPH^R?Ck72(x<3p*Id3mfrSb!hKXX$(!c~3hADDo3Y#fT>R)M7Cz9xJMKL3 z=97=7CHrWmi#A)d9avAnp zyw*9h#|{Pu!=h6I8aLM;BrC>m)B8Cp3()-|zQ`9cW6WBB7R$ZPWtxZYIZ`&0Q&TwH zQ8;p&;08HpcL(zui$KeDCBa@EpFqYvKl?{pItAq01{Ji3*SXuBx-l%iK}Szovwr4N z$Xve^iL?L(Ey4y>1;e1?8msD2rYS5j7hFg$aXe}?(!wW5NQyr93KGo2WCZcYvij88 zjo1lp3n~i7O3TGl>p}JE1XehtEQ@P3DPqT`TM#nT6kbWYf!oe#^a}o#Q?|8g zelDOoRcGd?p ze(k1~w-pE&vRX)RLkhJG>j=6_)~#ph2m5R%ON&0+W7maI=_PIyW{{s&`0dc=dT1

^jblY13g@&&qDECDXx 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 Yj^6csr_^%g0R&ubPM(fDdwSyk0RGL8djJ3c diff --git a/docs/img/generate_container_stack.py b/docs/img/generate_container_stack.py new file mode 100644 index 000000000..3f1c67fb3 --- /dev/null +++ b/docs/img/generate_container_stack.py @@ -0,0 +1,163 @@ +"""Generate the container stack diagram used in the README.""" + +from pathlib import Path + +from PIL import Image, ImageDraw, ImageFilter, ImageFont + + +WIDTH = 248 +HEIGHT = 440 +OUTPUT = Path(__file__).with_name("container_stack.png") + +TITLE_FONT = "/System/Library/Fonts/Supplemental/Trebuchet MS Bold.ttf" +BOLD_FONT = "/System/Library/Fonts/Supplemental/Arial Bold.ttf" +BODY_FONT = "/System/Library/Fonts/Supplemental/Arial.ttf" + + +def vertical_gradient(size, top, bottom): + """Create a vertical RGBA gradient.""" + width, height = size + image = Image.new("RGBA", size, 0) + pixels = image.load() + for y in range(height): + blend = y / max(height - 1, 1) + color = tuple(int(top[i] * (1 - blend) + bottom[i] * blend) for i in range(4)) + for x in range(width): + pixels[x, y] = color + return image + + +def rounded_panel(size, radius, fill_top, fill_bottom, stroke=None, stroke_width=0): + """Create a rounded rectangle panel with a vertical gradient fill.""" + panel = Image.new("RGBA", size, (0, 0, 0, 0)) + gradient = vertical_gradient(size, fill_top, fill_bottom) + mask = Image.new("L", size, 0) + mask_draw = ImageDraw.Draw(mask) + mask_draw.rounded_rectangle((0, 0, size[0] - 1, size[1] - 1), radius=radius, fill=255) + panel.paste(gradient, (0, 0), mask) + if stroke and stroke_width: + panel_draw = ImageDraw.Draw(panel) + for index in range(stroke_width): + panel_draw.rounded_rectangle( + (index, index, size[0] - 1 - index, size[1] - 1 - index), + radius=radius, + outline=stroke, + ) + return panel + + +def add_shadow(base, box, radius=10, offset=(0, 6), color=(24, 45, 74, 70)): + """Add a soft shadow behind a rounded rectangle.""" + shadow = Image.new("RGBA", base.size, (0, 0, 0, 0)) + shadow_draw = ImageDraw.Draw(shadow) + x0, y0, x1, y1 = box + x_offset, y_offset = offset + shadow_draw.rounded_rectangle( + (x0 + x_offset, y0 + y_offset, x1 + x_offset, y1 + y_offset), + radius=radius, + fill=color, + ) + base.alpha_composite(shadow.filter(ImageFilter.GaussianBlur(8))) + + +def build_diagram(): + """Create the Nautobot container stack image.""" + image = Image.new("RGBA", (WIDTH, HEIGHT), (0, 0, 0, 0)) + image.alpha_composite(vertical_gradient((WIDTH, HEIGHT), (241, 247, 252, 255), (220, 234, 245, 255))) + + overlay = Image.new("RGBA", (WIDTH, HEIGHT), (0, 0, 0, 0)) + overlay_draw = ImageDraw.Draw(overlay) + for y in range(42, HEIGHT, 28): + overlay_draw.line((18, y, WIDTH - 18, y), fill=(255, 255, 255, 34), width=1) + for x in range(28, WIDTH, 32): + overlay_draw.line((x, 42, x, HEIGHT - 22), fill=(255, 255, 255, 18), width=1) + image.alpha_composite(overlay) + + title_font = ImageFont.truetype(TITLE_FONT, 18) + label_font = ImageFont.truetype(BOLD_FONT, 11) + box_font = ImageFont.truetype(BOLD_FONT, 15) + box_font_small = ImageFont.truetype(BOLD_FONT, 13) + mini_font = ImageFont.truetype(BODY_FONT, 9) + + draw = ImageDraw.Draw(image) + draw.text((WIDTH // 2, 18), "Container Stack", anchor="mm", font=title_font, fill=(38, 68, 94, 255)) + draw.text((WIDTH // 2, 34), "Nautobot 3", anchor="mm", font=mini_font, fill=(83, 115, 140, 255)) + + vm_box = (23, 49, 225, 410) + add_shadow(image, vm_box, radius=16, offset=(0, 8), color=(28, 52, 79, 58)) + vm_panel = rounded_panel( + (vm_box[2] - vm_box[0], vm_box[3] - vm_box[1]), + 16, + (247, 251, 254, 255), + (233, 241, 247, 255), + stroke=(107, 128, 145, 255), + stroke_width=3, + ) + image.alpha_composite(vm_panel, vm_box[:2]) + + draw = ImageDraw.Draw(image) + draw.rounded_rectangle((39, 61, 209, 84), radius=10, fill=(226, 235, 242, 255)) + draw.text((124, 72), "VIRTUAL MACHINE", anchor="mm", font=label_font, fill=(81, 102, 116, 255)) + + containers = [ + ("Nautobot App", "Web UI + API", (89, 208, 176, 255), (62, 170, 140, 255), (20, 58, 66, 255), box_font), + ("Celery Worker", "Async jobs", (247, 197, 104, 255), (228, 167, 62, 255), (78, 50, 0, 255), box_font), + ("Celery Beat", "Scheduled tasks", (248, 221, 116, 255), (226, 187, 53, 255), (92, 71, 0, 255), box_font), + ("Redis", "Broker + cache", (248, 120, 110, 255), (219, 87, 80, 255), (255, 248, 248, 255), box_font), + ( + "PostgreSQL / MySQL", + "Database", + (131, 170, 245, 255), + (84, 118, 212, 255), + (248, 251, 255, 255), + box_font_small, + ), + ] + + box_left = 46 + box_right = 202 + box_width = box_right - box_left + box_height = 42 + start_y = 98 + gap = 12 + + for index, (title, subtitle, top_color, bottom_color, text_color, font) in enumerate(containers): + top = start_y + index * (box_height + gap) + bottom = top + box_height + add_shadow(image, (box_left, top, box_right, bottom), radius=11, offset=(0, 4), color=(18, 36, 58, 48)) + panel = rounded_panel( + (box_width, box_height), + 11, + top_color, + bottom_color, + stroke=(255, 255, 255, 70), + stroke_width=1, + ) + image.alpha_composite(panel, (box_left, top)) + + draw = ImageDraw.Draw(image) + draw.text((124, top + 15), title, anchor="mm", font=font, fill=text_color) + subtitle_color = text_color if index < 3 else (255, 243, 243, 230) if index == 3 else (240, 245, 255, 230) + draw.text((124, top + 29), subtitle, anchor="mm", font=mini_font, fill=subtitle_color) + if index < len(containers) - 1: + arrow_top = bottom + 3 + arrow_bottom = bottom + gap - 3 + draw.rounded_rectangle((122, arrow_top, 126, arrow_bottom), radius=2, fill=(122, 142, 158, 220)) + draw.polygon([(119, arrow_bottom - 1), (129, arrow_bottom - 1), (124, arrow_bottom + 6)], fill=(122, 142, 158, 220)) + + whale = Image.new("RGBA", (90, 40), (0, 0, 0, 0)) + whale_draw = ImageDraw.Draw(whale) + whale_draw.rounded_rectangle((10, 12, 66, 32), radius=10, fill=(79, 116, 205, 255)) + whale_draw.polygon([(66, 17), (88, 22), (66, 29)], fill=(79, 116, 205, 255)) + for x in (28, 38, 48): + whale_draw.rectangle((x, 4, x + 7, 12), fill=(102, 139, 224, 255)) + whale_draw.ellipse((52, 19, 56, 23), fill=(255, 255, 255, 255)) + image.alpha_composite(whale.filter(ImageFilter.GaussianBlur(0.2)), (79, 360)) + + draw = ImageDraw.Draw(image) + draw.rounded_rectangle((57, 425, 191, 431), radius=3, fill=(193, 207, 218, 150)) + return image + + +if __name__ == "__main__": + build_diagram().save(OUTPUT) diff --git a/environments/Dockerfile-LDAP b/environments/Dockerfile-LDAP index a62f22c86..c994839f2 100644 --- a/environments/Dockerfile-LDAP +++ b/environments/Dockerfile-LDAP @@ -17,12 +17,11 @@ CMD ["nautobot-server", "runserver", "0.0.0.0:8080", "--insecure"] RUN apt-get update && \ apt-get upgrade -y && \ + apt-get install -y libldap2-dev libsasl2-dev libssl-dev && \ apt-get autoremove -y && \ apt-get clean all && \ rm -rf /var/lib/apt/lists/* -RUN apt-get install -y libldap2-dev libsasl2-dev libssl-dev - COPY ./pyproject.toml ./poetry.lock /source/ COPY ../plugins /source/plugins # COPY ./packages /source/packages diff --git a/environments/docker-compose.ldap.yml b/environments/docker-compose.ldap.yml index 624a68824..b5328743a 100644 --- a/environments/docker-compose.ldap.yml +++ b/environments/docker-compose.ldap.yml @@ -29,7 +29,8 @@ services: - "-c" # this is to evaluate the $NAUTOBOT_LOG_LEVEL from the env - "nautobot-server celery worker -l $$NAUTOBOT_LOG_LEVEL --events" ## $$ because of docker-compose depends_on: - - "nautobot" + nautobot: + condition: "service_healthy" healthcheck: interval: "30s" timeout: "10s" @@ -49,13 +50,14 @@ services: - "-c" # this is to evaluate the $NAUTOBOT_LOG_LEVEL from the env - "nautobot-server celery beat -l $$NAUTOBOT_LOG_LEVEL" ## $$ because of docker-compose depends_on: - - "nautobot" + nautobot: + condition: "service_healthy" healthcheck: disable: true <<: *nautobot-base # --------------------------------- redis: - image: "redis:alpine" + image: "redis:6-alpine" env_file: - "local.env" - "creds.env" diff --git a/poetry.lock b/poetry.lock index 7e1c3a017..1e76416ff 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.3.2 and should not be changed by hand. [[package]] name = "amqp" @@ -798,7 +798,7 @@ files = [ [package.dependencies] Django = ">=4.2" -gprof2dot = ">=2017.09.19" +gprof2dot = ">=2017.9.19" sqlparse = "*" [package.extras] @@ -1244,7 +1244,7 @@ files = [ [package.dependencies] attrs = ">=22.2.0" -jsonschema-specifications = ">=2023.03.6" +jsonschema-specifications = ">=2023.3.6" referencing = ">=0.28.4" rpds-py = ">=0.7.1" @@ -1295,7 +1295,7 @@ librabbitmq = ["librabbitmq (>=2.0.0) ; python_version < \"3.11\""] mongodb = ["pymongo (==4.15.3)"] msgpack = ["msgpack (==1.1.2)"] pyro = ["pyro4 (==4.82)"] -qpid = ["qpid-python (==1.36.0-1)", "qpid-tools (==1.36.0-1)"] +qpid = ["qpid-python (==1.36.0.post1)", "qpid-tools (==1.36.0.post1)"] redis = ["redis (>=4.5.2,!=4.5.5,!=5.0.2,<6.5)"] slmq = ["softlayer_messaging (>=1.0.3)"] sqlalchemy = ["sqlalchemy (>=1.4.48,<2.1)"] @@ -1316,7 +1316,7 @@ files = [ ] [package.dependencies] -certifi = ">=14.05.14" +certifi = ">=14.5.14" durationpy = ">=0.7" google-auth = ">=1.0.1" oauthlib = ">=3.2.2" @@ -1614,7 +1614,7 @@ version = "12.1.1" description = "Python Imaging Library (fork)" optional = false python-versions = ">=3.10" -groups = ["main"] +groups = ["main", "dev"] files = [ {file = "pillow-12.1.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1f1625b72740fdda5d77b4def688eb8fd6490975d06b909fd19f13f391e077e0"}, {file = "pillow-12.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:178aa072084bd88ec759052feca8e56cbb14a60b39322b99a049e58090479713"}, @@ -1778,8 +1778,10 @@ files = [ {file = "psycopg2_binary-2.9.11-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c47676e5b485393f069b4d7a811267d3168ce46f988fa602658b8bb901e9e64d"}, {file = "psycopg2_binary-2.9.11-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:a28d8c01a7b27a1e3265b11250ba7557e5f72b5ee9e5f3a2fa8d2949c29bf5d2"}, {file = "psycopg2_binary-2.9.11-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5f3f2732cf504a1aa9e9609d02f79bea1067d99edf844ab92c247bbca143303b"}, + {file = "psycopg2_binary-2.9.11-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:865f9945ed1b3950d968ec4690ce68c55019d79e4497366d36e090327ce7db14"}, {file = "psycopg2_binary-2.9.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:91537a8df2bde69b1c1db01d6d944c831ca793952e4f57892600e96cee95f2cd"}, {file = "psycopg2_binary-2.9.11-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4dca1f356a67ecb68c81a7bc7809f1569ad9e152ce7fd02c2f2036862ca9f66b"}, + {file = "psycopg2_binary-2.9.11-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:0da4de5c1ac69d94ed4364b6cbe7190c1a70d325f112ba783d83f8440285f152"}, {file = "psycopg2_binary-2.9.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:37d8412565a7267f7d79e29ab66876e55cb5e8e7b3bbf94f8206f6795f8f7e7e"}, {file = "psycopg2_binary-2.9.11-cp310-cp310-win_amd64.whl", hash = "sha256:c665f01ec8ab273a61c62beeb8cce3014c214429ced8a308ca1fc410ecac3a39"}, {file = "psycopg2_binary-2.9.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0e8480afd62362d0a6a27dd09e4ca2def6fa50ed3a4e7c09165266106b2ffa10"}, @@ -1787,8 +1789,10 @@ files = [ {file = "psycopg2_binary-2.9.11-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2e164359396576a3cc701ba8af4751ae68a07235d7a380c631184a611220d9a4"}, {file = "psycopg2_binary-2.9.11-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:d57c9c387660b8893093459738b6abddbb30a7eab058b77b0d0d1c7d521ddfd7"}, {file = "psycopg2_binary-2.9.11-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2c226ef95eb2250974bf6fa7a842082b31f68385c4f3268370e3f3870e7859ee"}, + {file = "psycopg2_binary-2.9.11-cp311-cp311-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a311f1edc9967723d3511ea7d2708e2c3592e3405677bf53d5c7246753591fbb"}, {file = "psycopg2_binary-2.9.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ebb415404821b6d1c47353ebe9c8645967a5235e6d88f914147e7fd411419e6f"}, {file = "psycopg2_binary-2.9.11-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f07c9c4a5093258a03b28fab9b4f151aa376989e7f35f855088234e656ee6a94"}, + {file = "psycopg2_binary-2.9.11-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:00ce1830d971f43b667abe4a56e42c1e2d594b32da4802e44a73bacacb25535f"}, {file = "psycopg2_binary-2.9.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cffe9d7697ae7456649617e8bb8d7a45afb71cd13f7ab22af3e5c61f04840908"}, {file = "psycopg2_binary-2.9.11-cp311-cp311-win_amd64.whl", hash = "sha256:304fd7b7f97eef30e91b8f7e720b3db75fee010b520e434ea35ed1ff22501d03"}, {file = "psycopg2_binary-2.9.11-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:be9b840ac0525a283a96b556616f5b4820e0526addb8dcf6525a0fa162730be4"}, @@ -1796,8 +1800,10 @@ files = [ {file = "psycopg2_binary-2.9.11-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ab8905b5dcb05bf3fb22e0cf90e10f469563486ffb6a96569e51f897c750a76a"}, {file = "psycopg2_binary-2.9.11-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:bf940cd7e7fec19181fdbc29d76911741153d51cab52e5c21165f3262125685e"}, {file = "psycopg2_binary-2.9.11-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fa0f693d3c68ae925966f0b14b8edda71696608039f4ed61b1fe9ffa468d16db"}, + {file = "psycopg2_binary-2.9.11-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a1cf393f1cdaf6a9b57c0a719a1068ba1069f022a59b8b1fe44b006745b59757"}, {file = "psycopg2_binary-2.9.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ef7a6beb4beaa62f88592ccc65df20328029d721db309cb3250b0aae0fa146c3"}, {file = "psycopg2_binary-2.9.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:31b32c457a6025e74d233957cc9736742ac5a6cb196c6b68499f6bb51390bd6a"}, + {file = "psycopg2_binary-2.9.11-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:edcb3aeb11cb4bf13a2af3c53a15b3d612edeb6409047ea0b5d6a21a9d744b34"}, {file = "psycopg2_binary-2.9.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:62b6d93d7c0b61a1dd6197d208ab613eb7dcfdcca0a49c42ceb082257991de9d"}, {file = "psycopg2_binary-2.9.11-cp312-cp312-win_amd64.whl", hash = "sha256:b33fabeb1fde21180479b2d4667e994de7bbf0eec22832ba5d9b5e4cf65b6c6d"}, {file = "psycopg2_binary-2.9.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b8fb3db325435d34235b044b199e56cdf9ff41223a4b9752e8576465170bb38c"}, @@ -1805,8 +1811,10 @@ files = [ {file = "psycopg2_binary-2.9.11-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8c55b385daa2f92cb64b12ec4536c66954ac53654c7f15a203578da4e78105c0"}, {file = "psycopg2_binary-2.9.11-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:c0377174bf1dd416993d16edc15357f6eb17ac998244cca19bc67cdc0e2e5766"}, {file = "psycopg2_binary-2.9.11-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5c6ff3335ce08c75afaed19e08699e8aacf95d4a260b495a4a8545244fe2ceb3"}, + {file = "psycopg2_binary-2.9.11-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:84011ba3109e06ac412f95399b704d3d6950e386b7994475b231cf61eec2fc1f"}, {file = "psycopg2_binary-2.9.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ba34475ceb08cccbdd98f6b46916917ae6eeb92b5ae111df10b544c3a4621dc4"}, {file = "psycopg2_binary-2.9.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b31e90fdd0f968c2de3b26ab014314fe814225b6c324f770952f7d38abf17e3c"}, + {file = "psycopg2_binary-2.9.11-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:d526864e0f67f74937a8fce859bd56c979f5e2ec57ca7c627f5f1071ef7fee60"}, {file = "psycopg2_binary-2.9.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:04195548662fa544626c8ea0f06561eb6203f1984ba5b4562764fbeb4c3d14b1"}, {file = "psycopg2_binary-2.9.11-cp313-cp313-win_amd64.whl", hash = "sha256:efff12b432179443f54e230fdf60de1f6cc726b6c832db8701227d089310e8aa"}, {file = "psycopg2_binary-2.9.11-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:92e3b669236327083a2e33ccfa0d320dd01b9803b3e14dd986a4fc54aa00f4e1"}, @@ -1814,8 +1822,10 @@ files = [ {file = "psycopg2_binary-2.9.11-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9b52a3f9bb540a3e4ec0f6ba6d31339727b2950c9772850d6545b7eae0b9d7c5"}, {file = "psycopg2_binary-2.9.11-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:db4fd476874ccfdbb630a54426964959e58da4c61c9feba73e6094d51303d7d8"}, {file = "psycopg2_binary-2.9.11-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:47f212c1d3be608a12937cc131bd85502954398aaa1320cb4c14421a0ffccf4c"}, + {file = "psycopg2_binary-2.9.11-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e35b7abae2b0adab776add56111df1735ccc71406e56203515e228a8dc07089f"}, {file = "psycopg2_binary-2.9.11-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fcf21be3ce5f5659daefd2b3b3b6e4727b028221ddc94e6c1523425579664747"}, {file = "psycopg2_binary-2.9.11-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:9bd81e64e8de111237737b29d68039b9c813bdf520156af36d26819c9a979e5f"}, + {file = "psycopg2_binary-2.9.11-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:32770a4d666fbdafab017086655bcddab791d7cb260a16679cc5a7338b64343b"}, {file = "psycopg2_binary-2.9.11-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c3cb3a676873d7506825221045bd70e0427c905b9c8ee8d6acd70cfcbd6e576d"}, {file = "psycopg2_binary-2.9.11-cp314-cp314-win_amd64.whl", hash = "sha256:4012c9c954dfaccd28f94e84ab9f94e12df76b4afb22331b1f0d3154893a6316"}, {file = "psycopg2_binary-2.9.11-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:20e7fb94e20b03dcc783f76c0865f9da39559dcc0c28dd1a3fce0d01902a6b9c"}, @@ -1823,8 +1833,10 @@ files = [ {file = "psycopg2_binary-2.9.11-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9d3a9edcfbe77a3ed4bc72836d466dfce4174beb79eda79ea155cc77237ed9e8"}, {file = "psycopg2_binary-2.9.11-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:44fc5c2b8fa871ce7f0023f619f1349a0aa03a0857f2c96fbc01c657dcbbdb49"}, {file = "psycopg2_binary-2.9.11-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9c55460033867b4622cda1b6872edf445809535144152e5d14941ef591980edf"}, + {file = "psycopg2_binary-2.9.11-cp39-cp39-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:2d11098a83cca92deaeaed3d58cfd150d49b3b06ee0d0852be466bf87596899e"}, {file = "psycopg2_binary-2.9.11-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:691c807d94aecfbc76a14e1408847d59ff5b5906a04a23e12a89007672b9e819"}, {file = "psycopg2_binary-2.9.11-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:8b81627b691f29c4c30a8f322546ad039c40c328373b11dff7490a3e1b517855"}, + {file = "psycopg2_binary-2.9.11-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:b637d6d941209e8d96a072d7977238eea128046effbf37d1d8b2c0764750017d"}, {file = "psycopg2_binary-2.9.11-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:41360b01c140c2a03d346cec3280cf8a71aa07d94f3b1509fa0161c366af66b4"}, {file = "psycopg2_binary-2.9.11-cp39-cp39-win_amd64.whl", hash = "sha256:875039274f8a2361e5207857899706da840768e2a775bf8c65e82f60b197df02"}, ] @@ -2595,4 +2607,4 @@ test = ["pytest", "websockets"] [metadata] lock-version = "2.1" python-versions = ">=3.10,<3.14" -content-hash = "cc7135cf0f3fd67309d4c77ce911a01156523692f96a2abfc6fcba8596c546a3" +content-hash = "5a00118e8f072d749f4f2759dd736d04bc778c87c7d8814351cdf55b4c31b34d" diff --git a/pyproject.toml b/pyproject.toml index e6b0aab73..493d5e4b7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,6 +15,7 @@ nautobot = "3.0.8" [tool.poetry.group.dev.dependencies] invoke = "*" toml = "*" +pillow = "^12.1.1" [build-system] requires = ["poetry-core>=2.0.0,<3.0.0"]