From c76fb65bd226e7c6dd62409ea59b09ff83991cb6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Sep 2025 21:17:02 +0000 Subject: [PATCH 1/4] Initial plan From e8755d21e8201d4c42182206913702800d810210 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Sep 2025 21:19:48 +0000 Subject: [PATCH 2/4] Initial analysis and plan for backup-service review feedback Co-authored-by: lbeckman314 <15309567+lbeckman314@users.noreply.github.com> --- src/backup/__pycache__/main.cpython-312.pyc | Bin 0 -> 7893 bytes src/backup/__pycache__/options.cpython-312.pyc | Bin 0 -> 3042 bytes .../grip/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 5441 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 5634 bytes .../s3/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 3261 bytes .../conftest.cpython-312-pytest-8.4.2.pyc | Bin 0 -> 2932 bytes .../test_backups.cpython-312-pytest-8.4.2.pyc | Bin 0 -> 6124 bytes 7 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/backup/__pycache__/main.cpython-312.pyc create mode 100644 src/backup/__pycache__/options.cpython-312.pyc create mode 100644 src/backup/grip/__pycache__/__init__.cpython-312.pyc create mode 100644 src/backup/postgres/__pycache__/__init__.cpython-312.pyc create mode 100644 src/backup/s3/__pycache__/__init__.cpython-312.pyc create mode 100644 tests/__pycache__/conftest.cpython-312-pytest-8.4.2.pyc create mode 100644 tests/__pycache__/test_backups.cpython-312-pytest-8.4.2.pyc diff --git a/src/backup/__pycache__/main.cpython-312.pyc b/src/backup/__pycache__/main.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..11f066c14315435fd11f42cb9539b0bdb3c8e9b3 GIT binary patch literal 7893 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 EH*#vIPyhe` literal 0 HcmV?d00001 diff --git a/src/backup/__pycache__/options.cpython-312.pyc b/src/backup/__pycache__/options.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a63bda5ed6135235bbfc492b705aaa5bb5a52ce0 GIT binary patch literal 3042 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 E00+HwGynhq literal 0 HcmV?d00001 diff --git a/src/backup/postgres/__pycache__/__init__.cpython-312.pyc b/src/backup/postgres/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2395a5d696bd462f2495fe5815187987d57d9308 GIT binary patch literal 5634 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 Qv6+V>vY6c*1j0V=Ki71_!2kdN literal 0 HcmV?d00001 From a30ebff32abc8c1b481245908e0c60c9c2b1cd81 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Sep 2025 21:22:46 +0000 Subject: [PATCH 3/4] Update GRIP query syntax, enhance entrypoint for restore, update README with deployment info Co-authored-by: lbeckman314 <15309567+lbeckman314@users.noreply.github.com> --- .gitignore | 1 + README.md | 46 +++++++++ entrypoint.sh | 87 +++++++++++++----- src/backup/__pycache__/main.cpython-312.pyc | Bin 7893 -> 0 bytes .../__pycache__/options.cpython-312.pyc | Bin 3042 -> 0 bytes src/backup/grip/__init__.py | 77 +++++++++------- .../grip/__pycache__/__init__.cpython-312.pyc | Bin 5441 -> 5463 bytes .../conftest.cpython-312-pytest-8.4.2.pyc | Bin 2932 -> 0 bytes .../test_backups.cpython-312-pytest-8.4.2.pyc | Bin 6124 -> 0 bytes 9 files changed, 153 insertions(+), 58 deletions(-) mode change 100644 => 100755 entrypoint.sh delete mode 100644 src/backup/__pycache__/main.cpython-312.pyc delete mode 100644 src/backup/__pycache__/options.cpython-312.pyc delete mode 100644 tests/__pycache__/conftest.cpython-312-pytest-8.4.2.pyc delete mode 100644 tests/__pycache__/test_backups.cpython-312-pytest-8.4.2.pyc diff --git a/.gitignore b/.gitignore index 99dbb2e..0a451c2 100644 --- a/.gitignore +++ b/.gitignore @@ -113,3 +113,4 @@ venv.bak/ # SQL files .sql +__pycache__/ diff --git a/README.md b/README.md index 3351be9..4ef4171 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,52 @@ Data backup and recovery service for the CALYPR systems 🔄 +## Deployment + +This service is deployed using [Helm charts](https://github.com/ohsu-comp-bio/helm-charts/tree/main/charts/backups). The helm chart provides: + +- Automated backup scheduling via CronJob +- Secret management integration with existing PostgreSQL secrets +- Configurable S3 storage backends +- Simple deployment with `helm install` + +For manual job execution: +```bash +# Create a backup job +kubectl create job backup-job --from=cronjob/backup-service-cronjob --namespace backups + +# Create a restore job (set OPERATION=restore environment variable) +kubectl create job restore-job --from=cronjob/backup-service-cronjob --namespace backups +# Note: You'll need to patch the job to set OPERATION=restore environment variable +``` + +## Configuration + +The service can be configured through environment variables: + +- **OPERATION**: `backup` (default) or `restore` - determines the operation mode +- **RESTORE_DIR**: Directory path for restore operations (defaults to timestamped directory) +- **PGPASSWORD**: Can be sourced from existing `local-postgresql` secret (base64 encoded) +- **GRIP_GRAPH**: Graph name (should be configurable via helm global config) +- **GRIP_LIMIT**: Query limit (should be removed for production use) + +The helm chart automatically handles secret management and configuration from global helm values. + +## Best Practices + +### Namespace Configuration +While the helm chart defaults to a separate `backups` namespace, consider deploying in the same namespace as your databases to simplify network access and secret sharing, as the backup service needs direct access to database resources. + +### Secret Management +- **No separate secrets needed**: PGPASSWORD can be extracted from existing `local-postgresql` secret (base64 encoded) +- **Helm integration**: All configuration should be managed through helm values files +- **S3 credentials**: Configure S3 bucket and credentials through helm secrets file + +### Performance and Storage +- **Remove query limits**: Production deployments should remove GRIP_LIMIT for complete backups +- **Backup retention**: Implement a retention policy (e.g., keep daily backups for 30 days, weekly for 3+ months) +- **Global configuration**: Use helm global config for shared values like graph names instead of hardcoding + # 2. Quick Start ⚡ ```sh diff --git a/entrypoint.sh b/entrypoint.sh old mode 100644 new mode 100755 index bf53b42..8687037 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -3,28 +3,69 @@ set -e TIMESTAMP=$(date +"%Y-%m-%dT%H:%M:%S") +# Default operation is backup, but can be overridden with OPERATION env var +OPERATION=${OPERATION:-backup} + export DIR="${DIR}/${TIMESTAMP}" -# Postgres Dump -bak --debug pg dump \ - --dir "${DIR}" \ - --host "${PGHOST}" \ - --user "${PGUSER}" \ - --password "${PGPASSWORD}" - -# GRIP Backup -bak --debug grip backup \ - --dir "${DIR}" \ - --host "${GRIP_HOST}" \ - --graph "${GRIP_GRAPH}" \ - --limit "${GRIP_LIMIT}" \ - --vertex \ - --edge - -# S3 Upload -bak --debug s3 upload \ - --dir "${DIR}" \ - --endpoint "${ENDPOINT}" \ - --bucket "${BUCKET}" \ - --key "${KEY}" \ - --secret "${SECRET}" +if [ "$OPERATION" = "backup" ]; then + echo "Starting backup operation..." + + # Postgres Dump + bak --debug pg dump \ + --dir "${DIR}" \ + --host "${PGHOST}" \ + --user "${PGUSER}" \ + --password "${PGPASSWORD}" + + # GRIP Backup + bak --debug grip backup \ + --dir "${DIR}" \ + --host "${GRIP_HOST}" \ + --graph "${GRIP_GRAPH}" \ + --limit "${GRIP_LIMIT}" \ + --vertex \ + --edge + + # S3 Upload + bak --debug s3 upload \ + --dir "${DIR}" \ + --endpoint "${ENDPOINT}" \ + --bucket "${BUCKET}" \ + --key "${KEY}" \ + --secret "${SECRET}" + + echo "Backup operation completed successfully" + +elif [ "$OPERATION" = "restore" ]; then + echo "Starting restore operation..." + + # S3 Download - restore from specified backup directory or latest + RESTORE_DIR=${RESTORE_DIR:-"${DIR}"} + + bak --debug s3 download \ + --dir "${RESTORE_DIR}" \ + --endpoint "${ENDPOINT}" \ + --bucket "${BUCKET}" \ + --key "${KEY}" \ + --secret "${SECRET}" + + # Postgres Restore + bak --debug pg restore \ + --dir "${RESTORE_DIR}" \ + --host "${PGHOST}" \ + --user "${PGUSER}" \ + --password "${PGPASSWORD}" + + # GRIP Restore + bak --debug grip restore \ + --dir "${RESTORE_DIR}" \ + --host "${GRIP_HOST}" \ + --graph "${GRIP_GRAPH}" + + echo "Restore operation completed successfully" + +else + echo "Error: Unknown operation '${OPERATION}'. Valid operations are 'backup' or 'restore'" + exit 1 +fi diff --git a/src/backup/__pycache__/main.cpython-312.pyc b/src/backup/__pycache__/main.cpython-312.pyc deleted file mode 100644 index 11f066c14315435fd11f42cb9539b0bdb3c8e9b3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7893 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 EH*#vIPyhe` diff --git a/src/backup/__pycache__/options.cpython-312.pyc b/src/backup/__pycache__/options.cpython-312.pyc deleted file mode 100644 index a63bda5ed6135235bbfc492b705aaa5bb5a52ce0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3042 zcmcImOKTff6uvWhKP_33pRqkn(liq)snm;>q%C!Aq;=c5(QN-Pi**4tuvb>ncO?hX{Koac!TC!G0WQ2e;jpt>9VX#n3pA((6|oxz9ew<0n)m*Td#?OISlz@$h+;{b}{}*3=j5VANIEc+s;$rgE)l4 zxCdfH+EM#1PRObk$8cQh_(upQa9_Lsl-vP4h==en#5;59cq4cej{!qCdAwKY92GwfwcJZidnpjP)%NitBGyTl>-0bz)yc~HCA$??y+Jr`{z9bQvsjNwL zRjA3TCgGImBt6uvQ(IFc7NMK2(j+uprIT)UejzXW1n}6$5~b!&qD5*Gb#F4cDiKZk zM)zAgxh$!W)T*91`g|#dS|GORD%a%lis^1Dn%r!d4!NP3ULpZRmGBdX$uBodk7ZOz zKP0Ns`Vj=-U^-oG)}=IQH5w90-)@qX^irw3(o&MDL{`E7@uN!0olEJC!<4dS1}j8X zigtuia88R^{S}tG=r3>ResD8r1mj!sqxfTO=W=G>!TbFCZsZG7%ht_D&d1fAPruyt zEnFKD+-_oX{ycz4NU) zMSq6S$3kG{Ak&?lp`}PdaLDWZS*XwokyN2ms+LtGVM>V6CEj7NlKD6RC38sXludTV zsu^etEf6eJNsGq0k(*vHy-Fv7KHQB(K@Hk!E}pkgA}undq^cl&4D_t&2cHwU+~WMg zls?ua+7L#x?V`xDvS+m}I!GVQnwA$Cq{|R2cA=3GIGBE=(k+q;aABMxet_j@kucp3 z+q%DWT(_34!EWjL&Gu2I`_yqh6MbyVh<>>5bAjl`$C&6pKZWSY7^M1&=;_M?6aC+? z`JYCy6Z_hJTZ$)))c}TJ+zxNkoZxc;x(7#~EV^ha^L6gT@zJ+JrV#swQJ+*p_cozMwHB6OiMjW+zHR(VCDlV?c} z1Kv6cRH-mPp_6~zl8J;ZxGR}lk=6jaqMrq9sSHCv72uLEI|cHbSj-hCCMTzJx#G3y zo1(~dgQ!xOupp{_0f^S|DBmLIrY9Gs^A?#uqUqPjSsm}nS%f<&z*k*|<%pcE9-CrX zJj>ebe%NmNg-7upojX^q?Rw`9XTjn_ydz%U^=3MgU<*(?@8@^DH}(cYRH}PtP;BVU zotcSLhlhk^+7Ivnmx9+wp8~IuMLM1HdU&c;R|GIiWvxlpV0N=Vq!$uD{8vP;>7ksO zyhNy)tOr3S8=;j;=>4) list[str]: G = c.graph(graph) - for i in G.query().E().limit(limit): + for i in G.E().limit(limit): edges.append(i) return edges @@ -62,7 +62,7 @@ def _getVertices(grip: GripConfig, graph: str, limit: int) -> list[str]: G = c.graph(graph) - for i in G.query().V().limit(limit): + for i in G.V().limit(limit): vertices.append(i) return vertices @@ -91,12 +91,12 @@ def _dump(grip: GripConfig, graph: str, limit: int, vertex: bool, edge: bool, ou # write vertex and edge objects from grip DB to file if vertex: with open(out / f"{graph}.vertices", "wb") as f: - for i in G.query().V().limit(limit): + for i in G.V().limit(limit): f.write(orjson.dumps(i, option=orjson.OPT_APPEND_NEWLINE)) if edge: with open(out / f"{graph}.edges", "wb") as f: - for i in G.query().E().limit(limit): + for i in G.E().limit(limit): f.write(orjson.dumps(i, option=orjson.OPT_APPEND_NEWLINE)) # TODO: At this point you will need to reconnect to the new grip instance to load the data that was dumped @@ -107,34 +107,41 @@ def _restore(grip: GripConfig, graph: str, dir: Path): conn = _connect(grip) G = conn.graph(graph) - bulkV = G.bulkAdd() - with open("grip.vertices", "rb") as f: - count = 0 - for i in f: - data = orjson.loads(i) - _id = data["_id"] - _label = data["_label"] - del data["_id"], data["_label"] - bulkV.addVertex(_id, _label, data) - count += 1 - if count % 10000 == 0: - print("loaded %d vertices" % count) - err = bulkV.execute() - print("Vertices load res: ", str(err)) - - bulkE = G.bulkAdd() - with open("grip.edges", "rb") as f: - count = 0 - for i in f: - data = orjson.loads(i) - _id = data["_id"] - _label = data["_label"] - _to = data["_to"] - _from = data["_from"] - del data["_id"], data["_label"], data["_to"], data["_from"] - bulkE.addEdge(_to, _from, _label, data=data, gid=_id) - count += 1 - if count % 10000 == 0: - print("loaded %d edges" % count) - err = bulkE.execute() - print("Edges load res: ", str(err)) + vertex_file = dir / f"{graph}.vertices" + edge_file = dir / f"{graph}.edges" + + # Load vertices if file exists + if vertex_file.exists(): + bulkV = G.bulkAdd() + with open(vertex_file, "rb") as f: + count = 0 + for i in f: + data = orjson.loads(i) + _id = data["_id"] + _label = data["_label"] + del data["_id"], data["_label"] + bulkV.addVertex(_id, _label, data) + count += 1 + if count % 10000 == 0: + print("loaded %d vertices" % count) + err = bulkV.execute() + print("Vertices load res: ", str(err)) + + # Load edges if file exists + if edge_file.exists(): + bulkE = G.bulkAdd() + with open(edge_file, "rb") as f: + count = 0 + for i in f: + data = orjson.loads(i) + _id = data["_id"] + _label = data["_label"] + _to = data["_to"] + _from = data["_from"] + del data["_id"], data["_label"], data["_to"], data["_from"] + bulkE.addEdge(_to, _from, _label, data=data, gid=_id) + count += 1 + if count % 10000 == 0: + print("loaded %d edges" % count) + err = bulkE.execute() + print("Edges load res: ", str(err)) diff --git a/src/backup/grip/__pycache__/__init__.cpython-312.pyc b/src/backup/grip/__pycache__/__init__.cpython-312.pyc index 6467ac3d245d8ea1038f9c9b5921e72d840c135b..74780deaa1bb6cae4facc7e2e7d85462f8ed6bac 100644 GIT binary patch delta 1959 zcma)7U2M}<6t?5P*p3ssj@u^vO9`~3?Sfhe|Aj^UK?n)777DDJ5RJoV3k`BysF0(w zNs~Y@k?2lp&@?F$JX9(VnfAgoCc(szrfFKM7B#Xu?S*NtVVYL0d)c`O9i?Mq*Yf9c z&b`O?eBbrGe%P|u;{HyO1OnR63*Vkqq6I>@`|2AxDTj7IXPoe7~Ks!L{U=c!m? zY%Cr#4KEBw_o>4|0~kTLlW!p}z1iJ=t^fM5n}gQ|v)a7WfcofN>t2=E&luG(zVrs0 z956KO_yIzkp{{n6qcz~#&Wmxw9FE14Mjh_0M^BlcfM?tecd`#D?D|eO0wc3tLLm|>;6Bo?k#MlZOj_dEmlObUZbvkh&K4vtcqvFZdGp5ja%iYYaV(Wx0n*^Uq?r%tDM%h^r53+1K+6W&*D zBQCrITZ9?1?59La)EO*D$^{l%vLqbqB(M+2jd*a*E|&%I8LFH|5*Dv>mtkpP9$t4| zW(h*4M>m5uT6mNo9b zpzK*gnf({a!>^)zQDc!J=5MyV49(=JB7x zyt9V88-$tlY@$46VH#f&#`6kcP(cW^{W(FMBrcIbq8)_3I;XBY4rE;jws?M#zPRdrKV#>z#}WSTBi`m>SDXqqbc>au5V)u-8lw>qn(ClBSk zxwEGM*fj8<;-2Aa{VDRWd@FDX7(u*qMvYtDBa*zFB`bug&?lKk@E(roc4I z3`||DBs|`m=dYc=p14XaIi*>5@J|1r& z{yQ4@XJx=aM3laIn;uFe&KdaRHu_M=TSp#82fRPlwUBM;-9-W(xmf9ur+>qqfsd}g E07d`n#Q*>R delta 1946 zcmah~O-vg{6yEXf+PmvrdyRhrgajy1+eBapq!I}!r5H=Jf+!+^QbHoaItdQN>DV+0 zvP;ycsx2ZJG>5oN50=`4C2~lW3prKIpIY@2L{O|1m3r<8s!FJ-TJ_C3C{EgtS?#xP z-puTK-?uYwpEUl^X!}`FBnH~wt3RFFw0&p$+=PB4<6Mk)EK`t)f$ePr^7pIT4QG zy>zsiWcfO&9?ZAkj(tcT@UKeg_FsI+Wct)ZZpanngzzT%j9e8y00Bf)B)%@VkU};E zC$bZVRAozuaT~nUXpu4!5WCP-5*7XArcj04q}EnxdM4RxS9X$N$&E7PBdHe6l8jVd zJ8NzZYiGkTzxBBYIv2eVo;IYwZ;*RZTYDu0_e(De(F|T3pwI%KbM#9Ya_Hy`DAH)H zmJY$d5Ztj!a>r3cqE@eGcyXAFTpwK=C1X$Az7@AG?_PBWh$Od?wVj5?Jl>#}y?dbB z8*F3md--6C<$fC<>?BFK3hgIf$#1hE_h-owpX{IGp(LMm%OJkFkggMBJ zK~_m2ETn1dXi#7)Hu2uk`h?FVOgo~Fhl!*d_v>uY#<2M`*|6*{a2GYJp@R&lMBG$|E?dG*l}Jc8l_kEI{f=s! zC}C^^H8S=FRw=46SE`16XEiQE6=(%@FPacD!XUV={dS2RVJ@Qo_zxBResy40Ig2MR zG;beb-GonLx=VES)TE}H$$;7+&q~G|<9LuS)WiErkBH^;%+&dAO~dW53e!Wc^Hb4r zEvAd(nl=Q*A$$q%BmbzoPpBp5rjyR@pg_xp&eOLH;e&=f5uKTi<7zq>q|im-9SThV z#ksxsUFzroh^YW10}PA+H2QU_oF#aWB&MxXaAbow&{Q{ zTReo`@Gw?2)0A$S4_xV4=fp=+^|#L4;5X%uxyD~#On53ATor3K7@2R)9etj#B(}aj zVM<}n;NU9H?po}J>`FQ0kKJm>k1p3QUtDgYeEQS<*}CjZ?#!+B<-t_{W4Zg4tUTU) z!-^-crnYRlA(bs2(%YzfnN-!+6S>~H8|T(I@75too67!lYcHKl2|bN9z<0XSt%MMJ z*P;U6tL?4{DeME23iuH5A<6Pk;X@v>?yT>Es!`lq7^(<^p{OvJRuG+=nvBJ94eir^ y4)#-^KQWy<9gR+5T6XaO>2mEsgJjJ0%bq&qTR6DEz#}(dJZ^D+&>nWc%zpud>)#Rp diff --git a/tests/__pycache__/conftest.cpython-312-pytest-8.4.2.pyc b/tests/__pycache__/conftest.cpython-312-pytest-8.4.2.pyc deleted file mode 100644 index 8b7b8f9bfc9b2b11688e29b4ee41536ca3f49965..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2932 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 Qv6+V>vY6c*1j0V=Ki71_!2kdN From 62c93adc0a3e944b55432000fb33d605847d4b4e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 16 Sep 2025 21:22:55 +0000 Subject: [PATCH 4/4] Remove accidentally committed cache file --- .../grip/__pycache__/__init__.cpython-312.pyc | Bin 5463 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/backup/grip/__pycache__/__init__.cpython-312.pyc diff --git a/src/backup/grip/__pycache__/__init__.cpython-312.pyc b/src/backup/grip/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index 74780deaa1bb6cae4facc7e2e7d85462f8ed6bac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5463 zcmdrQS!^5E@h$h{u{t|ZbFsk~iT z2dGwUQ^0~jLiekv}?0t3vtd%#usd zvTO%Me%eRw%)D#fdoyp2-9O5*gFyMm${z-OUPAtc6|1<*#M)nhm?H{Nm?RludKm_3 zThcbf_Od3;Cb?b?+SnxD%d3oy9489*22uE{wi1u4Wmdg{BB+8Qs-hyPl44iws@MR1 z{gUE%gX?wNv)2i|PP5mpa*6sfyDHSrDJ~cz-@!pv-HIC?kIE``h3$7MUKr!4jPa># zzo67Wn|GWI)qaZnLX2ToqIxuzjA|NGxRX(Rusc?@6k*GiwPqmZh)Q}Hh4k7^gMfNj zl~Z}e_8j!60#Gbc<6MY09LH&V_=R+;KRz(w+oXdrv&rBF)0%E@!)dB_heSh)L{iZq zH4-r#k;qV58A&4TibP%?i6+ZEVkDxZW6;cMIyF3zNHmp7>rp+PPHEU0Pw77=Yq;5s zuGYcyklIQ|QYn?Tj;85_*1l-$!pQIwno2LmW9rtbMq}ls)&baeYa|j+#q~&}Wq6zl zz|jOdfzUhvenkGl?Y!lXf7rR|kl*N}K5K-*;cSB+pwZz$gHOhX;<_PFRUe_Lm?cLT zOgMP3zIF}39MKs-X33DNWqOhwAd_5%O;pdbMlqF9e1=c(<>o46UBQG{)o9JOS+m>8 zw`&QR6f#`GzRftn8pn_;0ghz29=I*K-xkyH#-5Y*GC+mss9kwlFL zqbVhrjB9!@noI^&WkA(h%(-wqq)2%%^~1sj(?J7>h3N3Gno>d{g?$mTuhhZB4Bq5m zFvkrhuHmt88&GHs&a_7cRJ{Y&pbtZRH$2)a0H(<2E@Jm({g>TS;i5of&s4`P$vz`a zi&-AqZprSMp6Q;;r)SPjpU(xB<%d5b3}1hVS(W4&*R(79%8xxo7FuAk%Qy9ssqOz8 zWw!r!%Dkvj9n7erPl`UOtjaT{#%Lq7+@(i~He^WFbovlZ+Xdimg}P9oXUgkP)aO$; z?ppvrr&6^}y){!OzJyM9qE5Xto@q~xxh^%LQg@q)~=UII*?qA^n3 zxMA-Yi>brt4-9^of=3RqrX?FfEE!i*y1}ZHYA9FBa7#A_ug`IKv{wO4k)n&^-8X%8 zH+)S?zNSLmy#JRC?>Edl7Y;0(`pvly&MkB;?m4mI>%1fs9mG{L_04~OZYQq5XT%26 zBze)huW+dF*rNN%73lz&@fSrNIyN+PH9vUrF!_Z&>|=lJ3A@;jTs)A5fEQ97GdOfH z2AdwyW7QhNqnUT%7-;?;-de~A5Af7thNZe*@zohV!@%ue-my)9juo4gJhYKXDI;#@ zw<|tW$=Ws6E!36IqPIAhmcRy6?$($)g^)k<;7wgQpi z84j!i(joX+y$r+(I&#-pxqF-yef^g5zjW4dG7gq|fN0F9jUnd<1HUWZFInW)_HoNn z`R)ySi{%Fm+h`xypO7|9XG3T)LtV&GFzlDQfGGu#f%eJ-5F5n6UeCrK`Q`*!*Fc6V}t20d1OqL!Ai@e z6lM7cu0t`)I|GmAfNL;C{_d>JwqHIv)xIjZW*pOwY}>NbFcrQn5XpU0_GNeH+H!mH z4U6^rmumJGPA$s^i^OK{V&P?1A7bcQILJ)$5xRXT_fi zKXbk1%D-~$;*Hi5ORXnX>N~G{U%buYpmi3R+?I&s+FWJFV*TEwn!SZbm*v*-DhIxT zRZ6UiEUdL|$7M?m8|#j$iiV_Op%m5)SRC|(1zFfDJtPQfe`(}u=0NLL*S)yfulcHYnHyOzAEgMHarEutH zz~jJWm~?E$szk+$zzNGGxP1H0iG5=+H4) zHA}{A@wMav`x5S#k<(v2K;E7zc?DBa4JqyA1;8NM4ffw zO`P#&e5jF(>zaJE9M|rvmDj3d=)OxU7q-=k=SyqFbAPRD>!rWg-b-J3uAEPKyXgTq zFg*;wu+ct>;m=?ram5fK$!MRN{1gLW+`EU6iJD|Os;ElvF(qg@_K8|6gAHP5kgD2| zAk5d(1|R9C>7kI#;PCz1Uom(CJ5>nyj^LA*f)~A5LOi0 zhI@S)x5y(W&9Fxm1$Us1(S6t~s$*(wL{}-M0fq>@xIn0;DmpxmJdPm1|xgcHC8oGy-HaNv1805%K^Vc~01R_%2Ymq>+5u?z#%2YUOROY)rX5tw13?%%G|06REL+Tu2pYsE|3#*7Z-OlFL|4%Iw8lGYHx@QOJc){ zxDx}5eb)Y_^Ae9yV}DLxmLDw=hy9rXv+56A>VRnR8Ij~?vdqo8hvqV~nSA)o?`65w z9gVrR*$Y{Awc(-M;9I-0!m7VM7sz(y{rSQCu2pYf&NJ)Dv-vZHQ!CzsP|x{h9a(<0 zwjSm^pARqBK6caJu-Mo#A6RO9>bn2w+df!jorjf+JBY_WGc-MPIem%61lGO#y`Dnt zyRWWDEx3E%4Y6)XtXmNqw(LHXgJ{}RBrbbfKDxPkhurqy-B-?2|FzuNw`AC9^?By~ z^XmN01?9u17l!a`@~oVT<=YC)^ZJLiS$W0VaqkoEFQ`k6hpzh%-wwb|)_K@nv2p7O zgYWIm$KKt0UD{uKgh-9+52GAV4IArCI04VJp*4g4KWYfe#|}bB^#c6Z7Y-gf%Kq-4 z7vLuc`D4$DpB&|ni(<%UI4fVW;41)z2}2x)&soWMAH`QQ3PxHokJ2|Cv;m57#^CTP zh56mUe9@#3M2Kl;2G^HPC(V4vyp9x;;?nmXyu%yPbES_}N9kFpqASoo1pu#>4D-)@ zglYOSss9s^;SXxGIoE9*<1P{aYb;cYX4UOweAyR^1W;Zx(flD3Egb%k{ow0s*imeD zGyd#EkpL>}Hqm^{M4+KVAH>(NquAtPYO+T_a!gIW`9{;BrKUq`SSjvuGmuj`a6%W8 v2kwXquo&Wn_7eU*SHg=uXUoKE-$A~R>oo6U9!JK2@~|wRdG2#WrYQac0Y`_+