From 55e87b48357dfa4d738a5fb47fe92582ebbccf99 Mon Sep 17 00:00:00 2001 From: Mrinal P R Date: Wed, 25 Mar 2026 17:42:12 +0530 Subject: [PATCH 1/3] feat: add crossplane toolset Signed-off-by: Mrinal P R --- README.md | 1 + docs/data-sources/builtin-toolsets/.nav.yml | 1 + .../builtin-toolsets/crossplane.md | 102 ++++++++++++++++++ docs/data-sources/builtin-toolsets/index.md | 1 + docs/why-holmesgpt.md | 2 +- holmes/plugins/toolsets/crossplane.yaml | 101 +++++++++++++++++ images/integration_logos/crossplane-icon.png | Bin 0 -> 91169 bytes 7 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 docs/data-sources/builtin-toolsets/crossplane.md create mode 100644 holmes/plugins/toolsets/crossplane.yaml create mode 100644 images/integration_logos/crossplane-icon.png diff --git a/README.md b/README.md index 9f0227db29..d42593d2c2 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ HolmesGPT integrates with popular observability and cloud platforms. The followi | [Azure SQL **Azure SQL**](https://holmesgpt.dev/data-sources/builtin-toolsets/azure-sql/) | Database health, performance, connections, and slow queries | | [Confluence **Confluence**](https://holmesgpt.dev/data-sources/builtin-toolsets/confluence/) | Private runbooks and documentation | | [Confluence MCP **Confluence (MCP)**](https://holmesgpt.dev/data-sources/builtin-toolsets/confluence-mcp/) | Private runbooks and documentation (MCP) | +| [Crossplane **Crossplane**](https://holmesgpt.dev/data-sources/builtin-toolsets/crossplane/) | Troubleshoot Crossplane providers, compositions, claims, and managed resources | | [Coralogix **Coralogix**](https://holmesgpt.dev/data-sources/builtin-toolsets/coralogix-logs/) | Retrieve logs for any resource | | [Datadog **Datadog**](https://holmesgpt.dev/data-sources/builtin-toolsets/datadog/) | Query logs, metrics, and traces | | [Docker **Docker**](https://holmesgpt.dev/data-sources/builtin-toolsets/docker/) | Get images, logs, events, history and more | diff --git a/docs/data-sources/builtin-toolsets/.nav.yml b/docs/data-sources/builtin-toolsets/.nav.yml index 4846964465..9ce3232aca 100644 --- a/docs/data-sources/builtin-toolsets/.nav.yml +++ b/docs/data-sources/builtin-toolsets/.nav.yml @@ -12,6 +12,7 @@ nav: - Confluence: confluence.md - Connectivity Check: connectivity-check.md - Coralogix: coralogix-logs.md + - Crossplane: crossplane.md - DataDog: datadog.md - Docker: docker.md - Elasticsearch / OpenSearch: elasticsearch.md diff --git a/docs/data-sources/builtin-toolsets/crossplane.md b/docs/data-sources/builtin-toolsets/crossplane.md new file mode 100644 index 0000000000..7a2d520036 --- /dev/null +++ b/docs/data-sources/builtin-toolsets/crossplane.md @@ -0,0 +1,102 @@ +# Crossplane + +By enabling this toolset, HolmesGPT will be able to troubleshoot Crossplane-managed infrastructure by inspecting providers, compositions, claims, composite resources, and managed resources across the full resource hierarchy. + +## Prerequisites + +Crossplane must be installed on your Kubernetes cluster. HolmesGPT uses `kubectl` to query Crossplane custom resources, so no additional CLI tools are required. + +HolmesGPT needs read access to Crossplane CRDs. If you use Kubernetes RBAC, ensure the service account has permissions to `get` and `list` the following API groups: + +```yaml +# Add to your ClusterRole +- apiGroups: ["pkg.crossplane.io"] + resources: ["providers", "providerrevisions"] + verbs: ["get", "list"] +- apiGroups: ["apiextensions.crossplane.io"] + resources: ["compositeresourcedefinitions", "compositions"] + verbs: ["get", "list"] +# For managed resources, add the specific API groups used by your providers. +# Example for AWS provider: +- apiGroups: ["s3.aws.upbound.io", "rds.aws.upbound.io", "ec2.aws.upbound.io"] + resources: ["*"] + verbs: ["get", "list"] +``` + +## Configuration + +=== "Holmes CLI" + + Add the following to **~/.holmes/config.yaml**: + + ```yaml + toolsets: + crossplane/core: + enabled: true + ``` + + --8<-- "snippets/toolset_refresh_warning.md" + + To test, run: + + ```bash + holmes ask "Which Crossplane managed resources are failing and why?" + ``` + +=== "Robusta Helm Chart" + + ```yaml + holmes: + customClusterRoleRules: + - apiGroups: ["pkg.crossplane.io"] + resources: ["providers", "providerrevisions"] + verbs: ["get", "list"] + - apiGroups: ["apiextensions.crossplane.io"] + resources: ["compositeresourcedefinitions", "compositions"] + verbs: ["get", "list"] + toolsets: + crossplane/core: + enabled: true + ``` + + --8<-- "snippets/helm_upgrade_command.md" + +## Common Use Cases + +```bash +holmes ask "Which Crossplane managed resources are failing and why?" +``` + +```bash +holmes ask "Are all Crossplane providers healthy?" +``` + +```bash +holmes ask "Trace the claim my-database in namespace production and find which managed resource is broken" +``` + +```bash +holmes ask "Why is my S3 bucket not becoming ready?" +``` + +## Capabilities + +--8<-- "snippets/toolset_capabilities_intro.md" + +| Tool Name | Description | +|-----------|-------------| +| crossplane_list_providers | List all installed Crossplane providers with their health status | +| crossplane_get_provider | Get detailed status of a specific provider including conditions | +| crossplane_list_provider_revisions | List provider revisions to check for upgrade issues | +| crossplane_list_provider_configs | List ProviderConfigs to check credential configurations | +| crossplane_get_provider_config | Get detailed ProviderConfig including credential source | +| crossplane_list_xrds | List all CompositeResourceDefinitions (XRDs) | +| crossplane_get_xrd | Get details of a specific XRD including schema and versions | +| crossplane_list_compositions | List all Compositions | +| crossplane_get_composition | Get details of a Composition including resource templates | +| crossplane_get_claim | Get a claim's status, conditions, and composite resource reference | +| crossplane_get_composite_resource | Get a composite resource with its composed resource references | +| crossplane_list_managed_resources | List managed resources of a specific kind with sync status | +| crossplane_get_managed_resource | Get full details of a managed resource including conditions and events | +| crossplane_get_resource_events | Get Kubernetes events for a specific Crossplane resource | +| crossplane_list_managed_by_composite | List all managed resources owned by a specific composite resource | diff --git a/docs/data-sources/builtin-toolsets/index.md b/docs/data-sources/builtin-toolsets/index.md index 6cb4138306..9fccd721ce 100644 --- a/docs/data-sources/builtin-toolsets/index.md +++ b/docs/data-sources/builtin-toolsets/index.md @@ -80,6 +80,7 @@ HolmesGPT includes pre-built integrations for popular monitoring and observabili - [:simple-kubernetes:{ .lg .middle } **Kubectl Run**](kubectl-run.md) - [:simple-argo:{ .lg .middle } **ArgoCD**](argocd.md) - [:simple-cilium:{ .lg .middle } **Cilium**](cilium.md) +- [:material-cloud-sync:{ .lg .middle } **Crossplane**](crossplane.md) - [:material-magnify:{ .lg .middle } **Inspektor Gadget**](inspektor-gadget.md) - [:material-microsoft-azure:{ .lg .middle } **Azure Kubernetes Service**](aks.md) - [:material-heart-pulse:{ .lg .middle } **AKS Node Health**](aks-node-health.md) diff --git a/docs/why-holmesgpt.md b/docs/why-holmesgpt.md index a6d9e67b8b..3f82472081 100644 --- a/docs/why-holmesgpt.md +++ b/docs/why-holmesgpt.md @@ -59,7 +59,7 @@ HolmesGPT ships with read-only integrations for every major observability vendor - **Logs**: Loki, Elasticsearch/OpenSearch, Datadog, Coralogix, Splunk - **Traces**: Tempo, Datadog, NewRelic - **Dashboards**: Grafana -- **Infrastructure**: Kubernetes, Docker, Helm, ArgoCD, OpenShift, Cilium, KubeVela +- **Infrastructure**: Kubernetes, Docker, Helm, ArgoCD, Crossplane, OpenShift, Cilium, KubeVela - **Cloud**: AWS RDS, Azure SQL, Azure AKS, GCP - **Databases**: PostgreSQL, MySQL, ClickHouse, MariaDB, SQL Server, MongoDB Atlas - **ITSM**: ServiceNow diff --git a/holmes/plugins/toolsets/crossplane.yaml b/holmes/plugins/toolsets/crossplane.yaml new file mode 100644 index 0000000000..96c7614d8b --- /dev/null +++ b/holmes/plugins/toolsets/crossplane.yaml @@ -0,0 +1,101 @@ +toolsets: + crossplane/core: + description: "Tools for troubleshooting Crossplane managed resources, compositions, providers, and claims" + docs_url: "https://holmesgpt.dev/data-sources/builtin-toolsets/crossplane/" + icon_url: "https://raw.githubusercontent.com/crossplane/crossplane/master/docs/media/logo.svg" + llm_instructions: | + You have tools to debug Crossplane-managed infrastructure-as-code resources. + Crossplane uses a resource hierarchy: Claims -> Composite Resources (XRs) -> Managed Resources. + Providers are controllers that reconcile managed resources against cloud APIs. + + ALWAYS follow this investigation order: + 1. Check provider health with crossplane_list_providers - a broken provider causes all its managed resources to fail + 2. If investigating a specific resource, trace its hierarchy from claim down to managed resources + 3. Check status.conditions on each resource level: + - Synced=False usually means a provider/API error (wrong credentials, quota exceeded, invalid config) + - Ready=False but Synced=True means the resource is still provisioning or waiting for a dependency + - Installed/Healthy conditions on providers indicate controller health + 4. Look at events for detailed error messages + 5. Compare spec vs status for drift detection + + When a managed resource fails: + - First check if its provider is healthy + - Then check the ProviderConfig for credential/connectivity issues + - Then look at the managed resource's conditions and events for the specific API error + + {% if tool_names|list|length > 0 %} + The following Crossplane tools are available: {{ ", ".join(tool_names) }} + {% endif %} + + DO NOT tell the user to check resources manually. Investigate on their behalf using the available tools and report your findings with specific details. + tags: + - core + prerequisites: + - command: "kubectl api-resources --api-group=pkg.crossplane.io --no-headers 2>/dev/null | grep -q providers" + + tools: + - name: "crossplane_list_providers" + description: "List all installed Crossplane providers with their health status, installed version, and package reference" + command: "kubectl get providers.pkg.crossplane.io -o wide 2>&1" + + - name: "crossplane_get_provider" + description: "Get detailed status of a specific Crossplane provider including conditions (Installed, Healthy), revision, and package info" + command: "kubectl get providers.pkg.crossplane.io {{ provider_name }} -o yaml 2>&1" + + - name: "crossplane_list_provider_revisions" + description: "List provider revisions to check for version rollout issues or stuck upgrades" + command: "kubectl get providerrevisions.pkg.crossplane.io -o wide 2>&1" + + - name: "crossplane_list_provider_configs" + description: "List ProviderConfigs of a specific type to check credential configurations. The provider_config_kind should be the full CRD kind (e.g., providerconfigs.aws.upbound.io, providerconfigs.gcp.upbound.io)" + command: "kubectl get {{ provider_config_kind }} -o wide 2>&1" + + - name: "crossplane_get_provider_config" + description: "Get detailed ProviderConfig including credential source and configuration" + command: "kubectl get {{ provider_config_kind }} {{ config_name }} -o yaml 2>&1" + + - name: "crossplane_list_xrds" + description: "List all CompositeResourceDefinitions (XRDs) which define the schema for composite resources and claims" + command: "kubectl get compositeresourcedefinitions.apiextensions.crossplane.io -o wide 2>&1" + + - name: "crossplane_get_xrd" + description: "Get details of a specific CompositeResourceDefinition including its schema, claim names, and offered versions" + command: "kubectl get compositeresourcedefinitions.apiextensions.crossplane.io {{ xrd_name }} -o yaml 2>&1" + + - name: "crossplane_list_compositions" + description: "List all Compositions which define how composite resources map to managed resources" + command: "kubectl get compositions.apiextensions.crossplane.io -o wide 2>&1" + + - name: "crossplane_get_composition" + description: "Get details of a specific Composition including its resource templates and patch sets" + command: "kubectl get compositions.apiextensions.crossplane.io {{ composition_name }} -o yaml 2>&1" + + - name: "crossplane_get_claim" + description: "Get a Crossplane claim's full status including conditions, composite resource reference, and connection details. The claim_kind is the plural form (e.g., postgresqlinstances, buckets)" + command: "kubectl get {{ claim_kind }} {{ claim_name }} -n {{ namespace }} -o yaml 2>&1" + + - name: "crossplane_get_composite_resource" + description: "Get a composite resource (XR) including its status, conditions, composed resource references, and connection details. The xr_kind is the plural form (e.g., xpostgresqlinstances, xbuckets)" + command: "kubectl get {{ xr_kind }} {{ xr_name }} -o yaml 2>&1" + + - name: "crossplane_list_managed_resources" + description: "List managed resources of a specific kind with their sync and ready status. The resource_kind is the plural form (e.g., buckets.s3.aws.upbound.io, instances.rds.aws.upbound.io)" + command: "kubectl get {{ resource_kind }} -o wide 2>&1" + + - name: "crossplane_get_managed_resource" + description: "Get full details of a specific managed resource including conditions (Synced, Ready, LastAsyncOperation), external name, and provider config reference" + script: | + #!/bin/bash + echo "=== Resource Status ===" + kubectl get {{ resource_kind }} {{ resource_name }} -o yaml 2>&1 + echo "" + echo "=== Events ===" + kubectl get events --field-selector involvedObject.name={{ resource_name }} --sort-by='.lastTimestamp' 2>&1 + + - name: "crossplane_get_resource_events" + description: "Get Kubernetes events for a specific Crossplane resource to find error messages and status transitions" + command: "kubectl get events --field-selector involvedObject.name={{ resource_name }} --sort-by='.lastTimestamp' 2>&1" + + - name: "crossplane_list_managed_by_composite" + description: "List all managed resources owned by a specific composite resource by label selector" + command: "kubectl get managed -l crossplane.io/composite={{ composite_name }} -o wide 2>&1" diff --git a/images/integration_logos/crossplane-icon.png b/images/integration_logos/crossplane-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..94280b87bc667f8700a8c06d52561f7354f3b6a8 GIT binary patch literal 91169 zcmeEviCa$F_xLuugfeDI61t=^RR}LqB&mcD-fJink`TgiO_^PyQpgY@yoORJ=eijp z!@WXecrTd}Ufjr(?^=8Bvrq5u_b+_T^LU)I&f06Qy{5hP+WWk%^7eACRijA_LP)KF z16+Lxsl5;XRj&#V-#_=-!hgSn4j4I$5W80RuR=sp?>U56l7X&${2~&HAO1b~sXtl% zZ|>92kTj`|~t{b{B>9TK)dv*6M+q?8;pO=<@e7}DAvRjO;S&+Zw`i~1YHHfur zb2{ekxEGgh-MUp7dMI~2`WREMV!3DNs-VAN=TXl_S8u;q z(~cal7K5R+Mxlv zi@1|FEW>qv@oPud%&_r$KKR?7u&_)2RN?jX)BYBt=WvR4Q3}3WO7fvI)00mIICY5e zT)yvn@XTYd7beCXMsXTumJbIae_vAYD# zv52q3Bj-Q$(qEWxEd6wcN_Sq3&zQw!VaQbaHuPV8`_`H1ufnIluixw8*L4?$1s`G* z4E+U8@A_BwKN)JiqtmE`BLh-TasjnytMH>4I%4jHuT#z~oBys@Z~Las_}g2yaE>ll zAIgTC7;2jMY24`E%dZ}5n8HRR&phwP`m*yKI$}~}J57~Gv&>Vb?_2ZidNOMjIz?e( z?bx9sK3esfHtyZS?uK7JO-mf*^5%5Wl|LCNhd_mt+n&*VrtO?}Y}x#$E0)aobo0W& zJHr?)^X7_hf|A#Ge=9v%$LHvSHV)n!E*wAT&r~g)XwAo@HMky-2dv^voqH(ctD^Z? zX&UUR81sBsO7}6gBg(j8n%7mxx4oTr`@6PQ$;EZ#?1xa@!P7HcxKdVg6Om@z%DbIX z-MirKg8g+2EnoNYd$V=e-1TM@O?qd^nb2SDGW)jsfrU|1Yc}R2DfUyc^ zcB6-mSh(!#(5M=6kFVY(cf*f8aK?%rA<|WAKDuzfIA?LXI&8$}eiy8UVPY5%v)Ix$4&U$}j_?Mpt?tM9aN zGalNLwuYPi55Cz}bdkH}+LfGReeUc-AkMEFzE#$0KmFJQU5*;ckenxQ6-%A-@`kn8 zop#jet*O*`{9tAo`n5_&*EOeBcemdPw$qffx_LCYm%X52-ir%O)^wdc`|k1sZ)UyT zLDI?V@q=f-KF_Rhg?lXX9|suz58L5BGal3;jf#)0@%y>mZfn!U)#}kNXAit5`OZ3e>XmFlB;cQGjeC&2EQ3o_s*Y@!f@ghlgi(? z>DJ6zKHn@$ZYEUFK7DKTWYk_ZY+W}+&Ry&7sVHlscsO*_aJd*f#`_U-mp_=5%G(r^ z8mn1bgY0ST%hVN7MGETtaq|?+Edv@eo6NgaR({47lV@gkZpr`dwYnmjzEwCgGoyMIz zvwQxGc@#-jf`Q~y`nLPj7JKbNYLVEe8(qCK)4VB$)P5TJo6`H z?wgk)>AM-XCR@2@o15JAsX)rI8?bpt8>*1@y8Ze< zP)YZq^Nxfpx~#l56|bWc)>}O}?w0&5jSz$NxYrGC2ajMTDUDIoJbGBzC^y%i-8#-A z(ugnh%}{;juqgqTu7kqgQ{Zn#pQ2r>Dv^}icjvDvn{aDR9XBTUkWHM;{Mb#mrmXY1 zF}N|&KDGGfoVvj;KJARtbS95_3Rm~HBz!e5v9fBouO`ve+u7>L!6|1pT&zQ}QZ{p1 z{%gR(GuPj*mi%pB4dPIJ+&4{Et0VDg3v_iUqCQn2cPKi+D|qAl>6-{yT9SV$xny-w zW>;p(_KL@j-CKAvrBBhSUn-KdSN1nK@W{U@rD6!+1Jvh$J#=-;jEd^Fxe_r?J=5gC z*wIV~20sPo6tm$yc?;`RBC*j&&1Q~ib-UUj=Ch0XbL;!=m-Fi6#RD()RVEJeHkiHd zXk`adIK`x(cURbc9G!5zXn9_}TNOxbQk@?SZtr_DJ*5TZs&oezLg~>>Ll-wM>10)V za1|m&l?K=!sKM3On>)MqIT~{JBHxWQh&&|n@RFj`3Uu)DSsv51`?6~Ke!G$N4!}ch zRy#PtY$iDS(j^S*yFw=r2KOWNP?Ynj1%!-!d93Qe5fz!a#WvzGBX^l)10vOWS?Ts` z5MfgX%B<&3&TN|_h2f)?=G8k>m1vjt`tRqv`UmJNC!bUp*>8c0)oiAjS1rMv2s z{9cs#p1zacDw4W{-5IPE?v#-h55T~7qzb;Y<5SKA@1f=` zUE@JfuDT_`4jIsORTyyKvJ27VOu5(Fw1wHq=MWf1f6l0S(8-Ot^=s~kQrC9fw!38y zgZUMVV9t>`elZYjMl%meQ4*OuiG|?-U`Zb<6Y0+{-oohhTe$2DHCpfAQ&!<~l(UmN zA?7D9eeD!?Xx|%)6sF{{Zrrl$y~DakMXmXI3vt?T8TIr;wE`&X#2^advodLPPw*y042WJNVD8xC%s`70^iCKZ z2K4OMo{-p-I%YHf1}9_rrhG%eX$#J3HnXwW&n^&KVwYcvN}qcF?LVif$?GpE3{`5q zA19r7kX`QeyYqXN?73YD`H^=jbb7Sje=90|eN?|$6^L~2TR^4T1sQc%PMM`>`e&77 z$`4S{+dt}`JqaRqRYvClrxTmH=~kb`6@In4pK$|PmnL0mvVUyjdUWiwxTk2-JiM+( zy=>9$@#hZkV#muPi!%n_n&VUzx3Y=cOd+)$b0Xg%ArQhMb`61f&`E;`J9*=J6H!8_2w$JXRVbizCA^Z}outaZR?@Taa;TX8mG$@NgaB-8%m z;kExql|3{`z%0S)$?hp<7A&O=j6jJ&lr}HaJU^V3?F`Uuf=^>12}}vEty|*xIZ1a!*GR8 za$$IVv%6+9#}9h%cu_eEuoSwzeD+WyzZSN&k)m|$-ieNs^u>LJ;f>8s?FLWQ?k&6b zbKkGswvV)=uO>Vl&pdmN58CY^kW>@s){IN4CiORwpqPx!d1Yy3_j*`MAfG(1c=5+B z)8@*N}Wt`R(LQkku3q?uG#xLD}YX1&X1b& zx50EB!Em@s%KGR8JG6pN(?Aum$wxsD>+C5C>Bl$RwGQA(B_2hq4g>uAzhizrvAE0D zLFP5Ml`QoRE3)4^HhmK~yuoP$5OLo_rK!EkRa*?RaQfJRWAZ^Kvi-t?OAfw!QAGx)nE*($KZHW5H54`v^=DzjTkTa z?MCyd4$uSeIEYV|5ow!lja=vZc`(EtZFH7f_Q+dvPTirtC(lxFjzjFJ z<@-T$jU4lfdg)f8$?blxYvtd%J2002`dUpkBWl>Us zJ$jNfa$Zxj&#m_l4W`_x7(*~}LoVm#iFEEf>N;(1$ImU13NZw64=y`Y7~T*(_}C0o zp=&ntlCBVd;F`anQmGTYb0DqvABrkHWdl>7^v>4m$-ctEFsAgyp&bDT9Y9uh3Cwf+ zTXaKxOfMLHor`oTcNoXjkn0cA?YJznBrq^Tq!orw^`||2@IV@z-kyb$jxnnc?@exo~e&U%Z=ivKq zA8mvO2)4mDrn4K6Ak2<*Ou8y-qS8Bb+uj(~Ho$#2_bi7#t@kfQ>sy3$mdqVoFvgr# zpydC!Wwn98IBJg{bdwx76b8!eq32VLoX;i7X8Rnjld_L@-Jq2djtxQp47tEnXYh$?6wSojA3IetBsov0on~l@7xl?A+zMk^Rgn1lHu&x1j2XzLp!|hbUt8d@8DuxkRCX>c5)qYE0sZeWI89kqB3I!)}xzoOEA z?be|Kv$|&7AI#IiH(evwM%6n5^tI=Eb(z-IoBEZxGmF5ov?XEvx2qj#3~{J8*KFo} z;AS}utR}a1WYV5YhUO%ntNXEkG(-n^Ef{)M)&XiYQU&hgCf+%(x?4Res0H|)^Ufu{ z8kF~6+~4*&WwP?ZZ=cJ_iGU5Uf0}CG4ea|fvw+?aHQ3f%$@+1hm_cd zef1qzO!X<(&K!Ao_;c_iNPZzj1KUWB83zy2{x3IAZf8pat+KxB0jcK^$YZ_$%kl|s z7;cma-IxW>alk}3ruF_Li~?lrBnVz57np)V{$O*ic8!PE2($NNQGDd+ocwd8$yo&N ziPT}K&zQ~`!i0j}9iU*z*eid;21;fU3f z%zI!t@|_azYpIoLuRTf`-o7)nBmd24VFB*hqw!hVeiht!6ty1tD|h2Nd)<1@h)=c|yH~_H~vokhQfSOoF{Tq2SCDz||YD>GtfS9gS(9XCcG;)dRceGukzK z+QMV?DS@NB02u*wwEnJV8(|EU_02!oZ-w>ADC!LIRi4?7Jy00l-0Wv3bWHPgWfy#Z zg2No9veQq(5$&OTN32kMW)?h4f6u>r^5OClYRWDfm_qf9r$*1OXI7ITd^0s`G`OIr ze{1AOzQsqq19}U9l(aJv$w^-mHFPGO8suBWarG$XyDbUV>E!G%a7~%h;)N|KyX4%z zY}%J+;DY)6qXaEVi8rVv^@yun>uEKC8lacvHV}{1up~h&K#UuH5SMC2d(wa;Fn$#dV>B|q4@yqrQ zQqr>WsY__@@Yof2xbWoKsL!)@qE-yn8%n~84zs*&7M~RzMnjr_c^@&Dd^4K~Gho*) z@IbUj7=yAc4FTiQ(A8arw%A{`zwl%iXNt0(qZH@alstG2+LcB`*n3fve*O{z7EO1t z+F8x)Z};RG)0#mu|IKukYJ(IU8nNk6+mP8pQxx-^;(oX0@J#W9F6bH}%6Y3WLQA!J z*moP#lx_$(RO2ezJRA#?!E_9|Do{a7ft=?Q* z|1o~#Rg6!C*q-5Gr|YACl2(QeUSmel8NnfN#_&U1s!$i-;}>>%eblT1)VJGnYOgdf zI=FFZ?XkuHK-`KmuO`F)MD}NfEd5RM3{uaMG3YjsF}QX$WiZy1GuWLo*o84znKS6a z7utI)Dfu>@3DgkRu3%y^ccJQWsPqH{NwoF3q-Hh%RqZ%|D-AFL=w!?C1Tp~7(R zRcu_H!37yCxi;ZdR`Y}=NsnB!&(DGPQe0gY@0OknqAHL#Qniq>(6M2ssRoF4GVfT+ zU%4_qP1bWhD^ot@I(%4t_^^7krNb(1&81+@rBIzpft+i@gjTf=6I!v~!bD#>QyCU4 zOqf5(3x^}y;grczuVUAAzBdL#b%5wcmi>KlJ6m?hUOd|>UPgtkzwjs~Ve3UIm*U?U zhxy$ZhleG7i(YM}#b=J!mInGb^~mVwJS69<{EJ z1Qw?9`5IH_vl|sB9X4YkZu&VebyOVnL!DVkpUa=2dJR+fu%EY1K0N#f8Xt+*vk#td6W)MnwxFtMvg zPbaKe;|9XR2HKAh9jc3aehgl`}nb$~<(U#-s3SGRNP}1kTeHN93%injS zoTuM^`=^YgwL6$#r8pS&x*v#PFj)yR@seFA7}v-tzGN+DSLB$k*js zra=)I3*2=N8xPQ2d;REOuKWpU9bGk2rc-pfAnd`fggg0uSsr+^3>d0MiuIIk2r%)0}pn_ws83ajBt$A4@q%wLb}bJrJjC8?!TeWuRgY=Q~Sk1Y_4l{C-vIMO&jJ^#}a$fLn03Z%tM~l%A z$i?K~_|4WWQZS8_rsek&3QVFS;fFi4%TA|_?ET=(J(ogcMrw3#C@?pBQ*cxIIFqfE zW#@+>76vAP;%*=T$3qvAuF>aGHjim1!U#P+T!g(Fh?~ik`h%J$r8=K*#b@)FJz4MA zn#FB*aQsK>cW-cNkz%@sLT7e41D{_V(vXhvDWAjEy54ncJ8*h2Lu)dCGT-vhg>bTy z2GxklEHbav+;zM)IJ)~Wd+cZIcn!6`BP-wg;Ik3}W#0YCMzDFzByR8>A$EZdS5z22H{pyvGzIw4FDDPON9MtAnx5 z9q83*+@dBIFJTuX>p7c;P5jsxFbGI7=05-L7)q=1p1t`PT43uP!4r+gaFj=@*dtDL z42Yp0=>|F2g817{#+$dG(kT50T%;;BxJv(|UYoRO?i^}Pv(~wI{P<@`oc-da*BNij zU>z)B2(7z}M&8`OJn2!7Yg1=-UAuwu!Z8R~M%j0nR{nPELc#VvF)E?X z(>+L3^KkvwtfLF*>=Fu+O=*#rd5R8d$DZE-bztJpB54-~wy~H}dv9?3tLH5rW>aXy!7HGsqbEj{?xJN-XMUQm+4Yha zE5nhF!F7up7;Ru`y7@(S9HR6Ub^Zq5>4K26>p#Z7#V40x&p<_Itb-Q2BGj*8lCA{I~?1?t-Q_JvvbT)q!^l;!#dgPf*bh&D%yNP=@+nU6Xr<#}wLr zd^V%fPh5l(Z|*9^eb5{i4er!&27)aHMSq?A^HFy4sa9XkBEVtP(G)7GIfsJdr)+9U z^CU8)rN_cecLyGE|8E}3M0=81kZ!@<_?1*A2Akb^LG!>EBbV)@thqe{)>!mt{t8$# zeVh3Ohi>rSo!2O1P}rs~A8tkcqzX6h!fFCq_tR-{tus1~Lq3qP@esJ&%BZ5`L@tcE zU}*H57pxV0Pd%SKe9h~=Wz<~Fn=wZ!hG1}aXA7CyXR9dRQ*R;2zF7W)CYuh`VJ5^a zGMJ`(?m7ky?6vJzeAv*^<6+zx>l3*#r523rOni#G21kyd zCRe~xBk9do-8=&wNu9b$Z!b(4zUFF;GB2c&9}f|4FqKDIVsLy(rBibQF}aX8MEQPx zi<8!{PflndvKKd;n$&RYPaubSch}@$?(RbvTq&tm+7gG>e+R&%yK=W^JabhJF zycWM6dUQAs8NiFwI%qh=;wkvUQshpm7C!C7qK%&(twnh0Hk(wNxdQ{^ z>}LdXiD$EYwFsQltepZ;4f0*rb3A$tOj3Z?Q!^g_S~gN*}%6>O4H)6 zRbqX4MvvNZE2Uu!A6gc=`cfn>*@sV?^+#c&&a|%`HmM$LPCU4f8iJuUb98;pF$KAs z0^(_&{n<77_BQK`{PyGwb>yim%}yNd6kly3Ht_R^zEU#*CbBLXe4H8% z`Q-)Vz@)`hScHN}olV%(rmC&>uK6dR^^z9Li*9ZF2aC_eopqlNj$;FpxvN5_6 zDkrfjQ<(SWrUm$XV6)AZ=3o__wD3TtvR?^EtbuO2qIm%&u@Ff7d1GXU>n2SAMQXwV zsLfcM-pZ!j!geKQNyputR@8!9O)VB$^7Qw&qS%XCc}%*o{=}$&#yCKd)C1VugfDD{ z-*t=`_~;&5fo6k8PXE*KM3lE@EIdd%58ar|Eh zDKSmzM9?ccP+Z^UU{o3SqW*rm3Y&%#SE9vkzp90HIWSotPQsVoO_-b5ctHTT#)4qG zmL8L|ZL;=YFi7NQ0X@Rw3iAW$Xe>P@CBk~j`2;l;54KyEXhXy3{=?XLUZ3bIa>h1H zb~Q7ZETW&^cT-wdMp=xcKGqsl)|bixRMu$VqGLF7N*`AFHjZ07G3)!pDey?5WfrAY zL)gfpJWAc8d>ij-I*1y1eKsk0%-k|@d_3Y$s+ZKs7esNr16_&KMgRH(U#uO)?7|A} zHTPVT*FJcMdGw=E*7$Y;&!StWr=gWg$5;9OD$m^1ehmsjTg(Q6Bw_}REubVaT$Ae; z!i?XRE+ynxmN%FmhD6JbI&}2lXpbdFXrPli)}x0k90Ffg3#iu=Y1)A0_1z9$qYHp1 zaG zbVmaY$vi<(K1BH@=k|sb!|`w=d69>Gw_cNsy5_~Pf_+A zY;ncPBZ-L=CuON4bv1lpzWm5EuT9^trr`r(g&9p}=GB;enQsm*K+~{UW78lkq3|Db zL^rR=UjhxgP2b0lM&L8kr1Lx9I*u6HyD^Q~{a&!O&CicBWH%+x83nLy*jk5(U_wS7u8KbeI@Z7AfY zZ8DBGhISI-tO;mJ)1iLsM7%c24hjHhV{*hQ-+wQlLw0tev&-0i!VNtZ-iA9sU9&13!*G)P<9L>Pwf0!Py_;9ql(UF$!jIROfMdTH_=tvDxirf6w-;|W9}JF99`_X| zP4gB$?V4q;JBG3puitda$;RkME`r@uo3-usliX4?BWG(Si)y!0uZ3{$th?LKIlVni z&h#6Z_?rE*B{&(IKW*u;ypR95!I?U`j<1cm$Y0p2_MPKh-=7mcP$Wx0`qJ~`vs@2+ zbgs;7+&MaUGi9)vPdk(A#|}|~%~msuC?3O>2QJV+HmvgfO$Rc@Rc92BP4Rx!&odN$T}e1<<5wqM^kVT zkrwi4J`?I!Ryp=K1TS97S=>DCE#=?Ar`_7E@5ZA1^7)Ls;8@1i z`62fKLjD39@PR_X_`v1(SiF=eaXWb4w!-^+vDFHwJ@*goN=+}5rAE3sF$3GQ!MW4H zWw)Qr#jjI~;$~yG&;>IM&zU-_L&-nUw7Gk9jSDkb^X*J&y5J*pN5f>JO@r0pMa-+u zupC7j#BHmMPrLfpZuQ@RMF_oXy4{lecJiGx=(8r`TPr)Goh0X!YlF@ zn90=4>r-d`_5&Y73ZR~{0=bdzgd9mKyX1;vtqt+x_BXI4zK+n1VX2F58Xqu3u>oPl zY`_J4`WpR|@$C@hyTqOw!fuC+TDKo_IymkIL!u(X0shO4N7Z|pnH<}JUhs5 zco(;3N$mmAHC$vS#I%dd?#AXayZftdQpF8=#>!~EHD91-tSkXm+{2j84zm+qQlpu4 zTGWTSCd>6$vLLVFY!2dV5@5426R-XP6R%4Finks{>3n;ic7}>fBV*a2TX|4ARjDor zS}ym3qEBP$BsbV`Z2d@#s@!gO`D4H9LyVXCpsz21VB>{(~8*%PQto?%-9;lPuzKGL_!~ z>7EN-GX)G`S*-ro?_s_0W$jhIODesGZ|UILz#K#G!yF^OgHO9q4YLIU52zNe|JjSE zb0A)t$je*fy}=xoLrrPcR;TFxbK4yEq3EIcy?oj^nDX=lwIZ!#i#&NkKpd96|-PeN{Vr<=LKW7Nru3-cny{z>4z|9dppk` zHEl2fzA9p#ZHt%^ANTpB->{v_I-3RuqFOj1roJ~2!g*jgsEG2)%27W1Y9rFWodg8JksOPg)-B0X-l(5N+FbWnh$@op* zRCtyZVDi{^4c^C&ObZr5%0R$w4D7VqmLlF%4cs^Q;P z&pvZtA!37-dQ>TG+Iv2h5xm(sI!zMnYPcuY`-Tll!6{@+Ks$D(lIhNp&Z1|H-r!g* z-~dI$&E@ammgKQB7~Z=uuRNQ!06@|V*r5Nuu|;nj*8w&mC3-E&p$hBanoKry%9;A_ znLtFX!6>(b45mxY=moU%9?x8rN^R0=sIu%R%xCXoY#QkMUq3O*a~;}oBHIg;PP3S6r~<^-437Ma zp6bm$q0+RbmNelpfXHIgq>3Tel6;VpJhqqZU8l}ceB}tE8a*2dX1N29ks@|l?ZBnw zV=xxNIgUBmb8jNz7G@`YSm9inxQf0`1#uPU7Nj&B`V?nf8}@xxV(mrAD6s=DpJ`u2 zHp1+}y8=`5zsOa$)F1#Q2JZHgGSj0%fduiT|=RDDZ{lGv& zy|d!0!o5u_jpvE58Iijw;XX!bZzwj(e~uZ2($Hiuhky3LfciZErmr6?aPaCdueMpcA^bM9UjKki7wQorA}X3GqQc_u(zM!e%#{HJ5NA*Bk>y?0H5fK20AcjO9>=eDcx$23k*jNLn1GLYc_(Ftu6} zHsUa5we>*{-j&&GU4zqwV(5t*=bVvgZ*!k^nvR?(v%Tm)X~L7}4E*jsi@uZuh~z1Y zkv4xN^+YkXhM-$NhlVhzV)dc_{yZ^v#*06S{E6F^KEtZ^uiC$2Mv0P@R zY&p*EEuxPE*R22A{bl@>uV~31I1<}~zq}O)M_f^fLaw4lzG4GrPQoe)umH z!dPNoo}-_aZLGrrRGSq?4*xvc3@vaYEVxMLh-eJTmaW)mBEKKU6{_VV7)fCF<%-hT zx$up3V#461G!f|fUv7*GKTR8EERD@ir`2v5P>iY8fIn;+NYxoUj!C2N-sZ07=bSGqZ`K zzb?9m+;6N4BWd4FVb_}5Xs?)1cqvT;+55+Jo{9I_EN<0x44>A#Z+bp$3@H|A%J@`T zrj7fA9PQOa*O1-3cFmYh%dZ>lm<;cqH9`3mL+U19OrR<l3GfjR$rGzcxL8VG;J# z6U3CyDoB>Uv5|)VIF7cX9RlK=6ZXr(p-p?iqh=cu)~gRz=y5vS4(jnSq7}Z{&0hV| zhP(na>(e`8vrS9_2gO@OfZM zZ1{@VnRVdH`|Xy6rZxhQb`Z8MG;@c0sWKDPKToSf;H#ndYId!KLq}rx*NkF>UwxU< z79Qo{Ncegj76dip*{fd~pZ?UWZ|QIJeM5LZQ6D%E-jgY;uz}-b5toj-5+12KoY3A2x?8(g^$+Ux@*TwMWkV1F3wVXYwU9`JCeCk z+7)~V)JkWNeBij*vP-OE=5Pa+*6a${nsAU(?LzSKkCP2KhW*+w3*(<$f1C9O>M;uVm6v2L&+0bX0UqTnCgN{r?&07~m%>0R zIuFHokk39p)-Eoi(Z{xpN0mg=>v@Pahvo12e^ZZ|h}bfeq(}`WJEi3~yPNO^KI8GN zV3Ygne}kvJ!pCn+X~itl$VIZ=*Y8lWEb!*%(2?B6lSNWDkWhW*5V}@$K=Pu11jG)6 zxyw5}_+|X8SN)J~J_~2s-cBcwp?x4CxyAK-N|^Jtp*LNsYzBt(_Cdwist4yr`|^JG zWucuG07z>KJ`?$5Lvs1|e=Wx%r?v~enuX4WwJG@%mtN@8+M+;M^7O+`t2pFe!Z`RD`=q);y z$IG7r=-!M44$`{!I%GyWno+D(Ys~27rbhx1{Xr`ro8waTmvT+h0_fLWZ?UQE-J4E9 z^h1e!mPK(QdJG%3Pl}r(T|PNY%V>rc9to=o>B6EWE#Y3C!^YpVF^$-{7&l6LLsQp( zeFnh2REt?{+SBovZW|yoC%ZG2WhK)sdu>xL0y=?7y+Jsp+dE^3kk+v|E$yig(0^CK}#%2kzijcGeL!Yo~LUPF77=q#z7)bDOtR`pq(f&d+MAsP@zmJH4e&4*HEb`EW^-kqEk*zB)r$B!$>x=+Oy2R%zi!dJ*MNeJ%MP> zY0zT|N=VzBv0XxyrccCnEZ`Q*^G`atvp8c%WNNHla! zBpYJsS$bS64n!yS`ET7NYY-H%Vt$%Ub5?0B5Y&4o&|^-nEKWwNmiHvS63Z??WO z#u(``8-Q7@G2g!Zel-Wr(pdK1?FZHV#qHZfV`A>&tA6+@1(LH9B{-L4vt%#o z>Qzb@N;9O{juVt{6eB$I%Y=4-IMEe`-#>H?O2(9Zz-9?bzR_~op?N?^W8s=iyiItQ z%m_?3G@@PBgD!2Z#Lq_iQ2M*HhW1wh`m29nhKn7>6;oE{v$TjA1y7bUvDwznk#H{! zV7$C9rMy_9+4N_^a%B-Y3c@a=44no6_JGZx;?*x^4lLJlX2cW>L3Qzyg1*&9^n-g6 z#in&rb`rHNennDN)O0c3tBGPMo$1P}wt%@2mPN#{+`SFe5{t*#|8}YgudGon5B{~q z8jB^jn7;k)4u_b6=Yup&KrS**DXX(lT+O(QqF)6WG#L_5i&}m+w6z~g994Ny*`N-KcKYeF8#sz<< zmy&$Vq|4=AKA-s;%4;}&9^?pV^DKJeT6)EV$|zVuL6_)`-IvjD_A!gioz)r7-9^E| zf)w-dvV9}1Ma(dGV~Gm~-R3L$a*aG8gm(k`#+Lq&;*;Xbt)k(cbY`6Ho8^PdSfNez znDq#~)PWQ2-Ux|mVY88Jlwdx&Vg-+69}B3SFYqT8h%FAH?vq^9hn7e8aF(uhhA<>$ zKd?pf)AGqNoElVYAK=6KGF38Z!*YI42gYY-z>b9skyx|MCkGZXv`rS{@fv9rXh?JZ zku9}-PP7Xnit~*1(HY3!(yqi z`O!{jm+4U2Arp%y&VzgMlv&Y5s$97_a=2jOEP5`cDCCC@4PWB^(GtqXfrZFZRlwy#jDzD5y(1$0m3^+p?5{XW+R&*$1>mdL`2$fS!hDBuna} z7!2%FNu@4IIy4GrT7&LKX!Ni5F^^h>8VZ@V7hY@V`Xm}9+1zv6J3|f`h5h|%I z>mR_O-Z*;xiNz2m6btjyp8_4>Wg(8!q2S(2xCd9D%N@9r|HRH4W;DS_Ax~gNd}-T9RO!A zbXY$N!MTqppMC>g1(Zi&z+sH{oF#egSPhsrt+yaH31e1Qdc?6FJf&eD1N@ zBjL`SSq|Ju1JDGjHaO7w`_sbU zUaBKVn8Q{A@!oqP6}2A8WC?dNRNvu0xVU(`hQGPi1s>Be;i1<%<^ynVz^{T6BZj>~ z8l;qMOX95yCM1^2LOY@vmg_WKaU{iLd-(+d!y04}FPYaE7@H_sybQ~PDV5>;p+5p% ziUk2#^*LqW+WH~}UqB{n(FY`5I+JCFgxu0Jq!{`!mg-iLl}i6ESs@_<GE;12Y}1*))#rh zE0Ov&kuL;|hNs3TrNoROZP5OlnN9*QJV^%R@aBc3BQeHbXCj2VfkLd07_3om(}+%CEw|zT5EFq8MJLP(g0~@#AXSw%9upeB`qr z5UiHQV*lUW?LZ3B2QSJo;7F-TJeGKg7=R6h@`khd%z1$h*wgop3z(;XZ5M4r1gyD$ ztrf6!qHT(R)e^8=0b3{977JJ{0jnWk)kIsq+yW6*6L@^X0AO=PAh|83^S4TtLfVNG zqZrp8^g5`*R6G#|LsUE!Ch$Z|j})OGRK)6tl}ZHFizP;=NUrq!+dT-F4HO%aPKoh8 zRWz)G*cYXny3=oK2TWWV}2(TTb|RxDd?qj*Ll`)MO+EISGqR)**$&k-=(-(;{} z0w(fDd69rM6LZ&k-$9_r*d!8on@&w)+0Xr#R z(?r{70ed50;R3c$wDl9P9|G1zz!r+O^#zRYtb;ewxJv~yLA1Ro@SX~oPQWGzdK(3d zuP%UIsDRB9ZM_AI7pno!LBM7SdZq&QQNW%l{z2}D3}ma4zYu>har(oNB{~eERsK={ z(GC=fD-p~*Q=E(35n0MsCHW!#V%GH+d4hJDVjbFFRDy!TSAy$~qLX9+n<-#Z1niiA z{VHJZ1?*n|>nQrzC15iJ>^A{BCSWZE?7e`!6|ioik0Sy$Pr#-NScZVv3D_3_doEzz zL?8PEY@UDx3Rs4KwGpr{0``}HbrpT|6R_C=c1BpjR95o~cDPqdPdg*xt*7%(m@Hk<;rQ*+E33@uVD+z5@i?QiMhFn9139nf#W)+<< z{2BrlDi);mm6Zk2k5!z(28)RFl0~9vgQZ{wV~Hl*+t9=bfts31+W|^hlxW%u7)^{Q zp2*+_h&)ddEbzpXq!AUK0W?vkZS4h~;7>C|zyyDq83HEwldCJR>ViMnM!*DreA@%M zt1kHCIV8daf3k^aEBKRb1x)ZKdkUD~PYw|5w#b{$gk23f2mAZewiFp!{XZQYd;fUV$A!#1q|FIGrP!-{_h z6CG=;mC?ltDQLO~m`cx8ftjoHSfLW=nXB|B3OtowxPYnjsw%LTD!qmRrqUA$#!Ho+ zNHAWi^xTxTlT~`d1x%$EC}1kRIRd8AtD?Z1)wT@;OvP)hz|z&QGgVP$s91=T21=OK z!bhSYGQ5Tfn2NVWz*-5s+X9BW>FiRXu^xBI+2uTZ@8oSzAE0Lelw4BAuOZkKs+5|f zrUGW*zsp0&5n)d7X@aEo80UQR-&O!ECS%T1P@;F zaaYACb^P-`LI#NlDbE)KMcJGLE74F_UpPSu|M4|AbfOaE-zfq?)uO*D1U*#=nhTgJ zEoT8!CF3t(suUs=n5bA1DOSK#dg%hD(#sbxm0qa=6BSD$H4`wEo{NB~^a2D-r5CBd zM8y(5K@c#N-dO=t={*oImELy+CMuTj@s5D079&cQv|`CDA(e%yvY>a5))luqZ?krN z;U-c$%j977Q z6hxd<_46O+h2NAFF-fc&q-(Ci#)L`4i=ZUR=J2~!JWfe%l~}Vuph-iNQ9ck-BRiB> zsHU1ELh#}w`c+fNEFmKDR!JcZVqr}pl>Aewqc(1(%q%KMnGB^1D$|D*25XA6k}ObW z2emXsJ}LgAW*wxNG9&oo2}gE0^B)lr@4S@f<(WT%AtTnHKp39B<45qlpebVC@WVr ztt8fp=DLV!miQ{x)}Dp;1q!lA9|!NU}b@ls{a&o0B+V=-+L zUR{QIy{Zp>b{eY9BK;)(%1TqKrj`8IHpt#h$VDsUS4%KR6rNYApr48zoE3{A^`M2m zw$QoEPk0gHB;0{yDa(Adwn#*AQLkF1IC~>)PpB)YDE7jvbR#%`>L?_Oc)@! zsN`x%~c_65Dv{%f(Z&iwPH&?Dxy6)B?rOBL%>g_(XTtVn_VrM8`_h`*l-D^g$& z)wZ1!OH~VwL`nHIPAbnzQ6!Q5F$@%;#)4bm%>>~!mdc-Goh<4uWTTRdcTp$n%gQ9T zO_gb(!rp$BJyBBjQYTHZT2OON_!f?DOE`EZ={+QD2O>b5r=@m7=`sE#+4 z$8u?~sv|{I;zHHpxj=sLeQlyq3ufdnm$aptOGsNeJyX@NM8&bX${*j& zhNZ45znhA2;O9)d+m}jO-cnWEf7~b~qO#}4qlso_IT#nS=C^V%?t>biaxiYtnm#J* z2+xzG@oK*TN_1MT@|Uh;!mCvW2~{@k>Wd{d(N;arL>a3(p)``qPdi@iIFMVVG*DG~ ztg^glqY6-~6wG4P)L$B@C{9hwZ$_6r5DgTo?Q zA@eaM&61k)ak2jj6r*9;wFbYlgFI6y$mJW6)+v7(+Jf0TC*6!^aMB3o8t`L`IHvWA z8k~H9e7!9t8S#9P^Q>dX zI~7U$b0uyy8n-!TTEjNx738j5cCOrNnQE2nj3=WCvhw%TU5$nkpipKRvx2N7X|9YU z*K95qzs8v70EG=BGsxvhqGq0vQo3;qv%zC;UAQaFf9J9P8Y>;Ly-MEUMlNW%ixKij1(_wV3Njb8{LBbB zjw1)K$yY(Cw76_Wh2yueow2|HMfSt$^dfp#VHY-ONxr%{THl#o! z(Yf$#Xa1?06GpGMl*V80J#|Fm-Y)4nhlOre`ho5B z^hH-EBh2VGPQ=lQE*JhAKz%x3Ap4ud`O9c*yV;7q4DCw4A1B&Mw5?_Xo35K@)6_(A z{uOOH(Vd=OIPIc!*+1^Y_wThPPz< z*~=KCd=%~ZD6A-wWI;KRZbz{NdIckPS95m%HNqXXis3FDNdH&p)??CHv57LO@X(g= zU}D6trzM9nVR1=%a(+#WSpP3+6*MwQo_H|N*3Z+RXLaH%&m;c@^kh2tIW6BFS@@6As3vQS$#*}ArGm>OyCNue;y>v~;CL;2jYiN>@>T|gZ4l&k0h!)NIS zMsq+SXV=ciF?7|KhSHUc9y%HEuz*|NAfr(fbA#|QCd?BE=PgErvpC@{#)R4I zEe$my%q6+f$k6n47{ks+o=kpn#rO>fBhiIc=9G;G=*|cD(-_&BBO8m(ohN0~WG&e=O0F}t%Fm6A-kHamrpC(l zWL6(yl!ZzsR#CsvwJh%ovX!3i6=h;)b(u3$v?EhDT+FcRBb zCJ9T=@}W)Y!6=xvE*}Qvhs^4$8^sT86~;rhktlUsqkWA=;lGNF!pz8RQru`LmWUC% z!&w?ChZ^IuG*tT2m@ZF4`xzOEj^}k%jrpy}l)S=7l3LDhRbyyfj%zfbXqzx-Rb!|X zgElmZAF>~lj;*nLbC@LkjlvbV#r0-sB#0Uucde1$8gROBuD1asn<8AW`f zm{Bl*sDRG|m=MJP7`SFs3}XTn_05=*c@qlv76A{{P5Yt|w8Gc46_29Wzz8wb z-x*vXE}Ifw4}=?;5)K5yasMIAIWA$sF-&SkQ$@?~0Nq*9#2qI;xg_jOB$3~SBbzKt z$Z3w;&lI^8AZME*Z{x__O_BK$*xwZSF-Hb(kuQvC=6#^N)f9OZM>biFk^I_#Y-fsm zgCm=|eED4EPnjYg;K)@>dA0+}uBOOuIdXLq z$2S1sYNmuEfUv167XmJU)Yg>3Dn>!O!DRG5?8^qPeQy&U-awpSwTUN3CV+nTGHu0l zXvLUbY^d?@gFNgUTS=IDa=OmI?o$&>A#VcQ9;RZS4nr*3Wac0fpzm!>`Mm@DYF3)G z?J5`$jj5M$6&4bj#iqCrC(z6{h4Q{|F_B~}#F%uZOA!t4`a>o?q-)OYfkSiL#PcN6K)w%qnDl%W^hL0V z-6wo;8e`f+ouTJ_O`H)@2=Wc7VZy^b@Mq)(CautQ0fpH8AHu*|+(Wh; z4{&6YDTQ7R0OZ@I$UOns#guZ`IzT>aiX6z1O(}!sG$2{&#LSQ** zZxR6|$6+v3GKme4hhSEsO#Bb>2G-goO&iw?Oz|jFQF?*g>zTHq5456;$*|G2V6~mG4@Bb}I&zx4n9F zY{l3iRo!k{^a^Yq;lAkeMNN1mokhtWM}K(uPB}NM-n!ERXx<0d_wEIIC_4FnZY?73KnlktSE`4RT!^*QLND)Aa34FS|~2@ zcQ92C8Pdjy!?&U>@Omeh5&B?<@tn8w~t_VC|71l?XiY$>0p$uwrsK!+FuV z7o#U&#bkAc^P-(t3{Sv{$?vG(rJ{;=RMcBc21i95EsNm^dd1|jLD0h_FocL)ecEEO z+92o!tMoPqdd1|oOVATXhN)bX=K>VH(L&xvd5+@GB#6%c4k z>fL^luOx+4e(K$RB8?D*1Hp1C-)D=X&f+izh1s(yjW&p%)}kQ1g||{1;ifQgq2#(a z$WCD}hts@E#qjELdWpsGM74><@WAvD@ota8UR!b9=uI&^!JjztO7W_STai6fo~sJ} zdZ=Zq3jTN|S*4Dug1-Qjzp8@2fMWCne*wkl3H}1Wd^382KW~*@eZil%O0T})&s(Ke zU-0Lx(yK4{n^BCO;BQ7TdV;?h#pntCW)!0*_;XO{l@$E_RSYKhb5QHxJ{lo^6@v-> z9MpPC3jY2o1{3`8jQ@(PN(%n|Qu!+>_-n25GEwkys2EJt+gjy?yJPe@reZLpr}Cma z$D-6v4i$qTJ(ZW{g6BiUV1iy#l^1tGFQFJr&}*vl!aXmV&8-*=>8ZR}BE4cTq^I)2 z{Vhtb7);RXsPghqls#DthIlG3zKB;0hIlG3afnw8hIlG3c=_vOF_^$pS#c5Mid0*d zFY?C9lg|{qvZ4o%Auj-na?zfXtoVw6_^Ui{uZku=6*qIJHv}iLsP*LjrPA;GEG^Ap z%THTUSdq9QldopJ1`m)Dsl?A}($sPy-zfJf6>64qzO<~! zQD78@v?&Y@LDPCMH3l(=G(tvkUxeZbJ8yKwIy?n`I!hHM_|vJpcnbb>;vy_fg)aEh ziL=NQCiv4;ROt!+bSf{NfxVkUw$Diqb>= zFv$#Ajr@tj%oGp#6X$Lz4EYmxqG%dD!JoYa)>}#NXRpejlHkuCGXRiEf~qGc-xy)68zb#{hLHz@>6IKdq{|={Fx-OINPf-NP>f-6ptSj zRPgBQf(kydSLKoLCUt~J}MvPu&7EbP^c#YsvkV@6MvpGNSfSLLS>{OMKs zX#{_IRel=5pI((8UxCtfm?}Sw;7_m0Pb2u#tMbzb{`9K+Lc}dAyn;hhF3~5-SUdEp z{6fU_c5&2_B7}&`ws=UM!h~+gb6=3m7Waq=`6ebiV;l4?)znd|urOiA zQ)z8W5X282Q&>;*VD49h~2RHboyRT#>zlS&Wem!iT@ern22dz4>_N)P2{t(Hak4Nzey zzduwM%I~HML-|>&b)ftPs4$e@A1VyxcTY$)pBF-gjwnj3kGiibQuQentn9jwEM2{HXtSY+Xw zf7-9CzwEEZoh#ed9TV0q#s6l>P4?l2Ae%iop4|e*j=50xdaEbr3rCzQ_ZN5bc*K&j zBX<=r)t8j*`5~F(?_UT6{I=8gh63&zlMVM@vCJNhDqP|sd#uP z+y#?RYnzGohKcLEG#`|(_(|e2C6THjOx%a0xq<~u+~K0L#Vv%vTRfC2=@7!u)t1&E z4Bo#`@TLk_k~+2WTVZqzsBsn%Uc^T=Y2kHZsURNkq_AF?qUj=bI=YW!B?`+P1z5W; z+u5RJwS9zOoK*(--6Wb~L}Vo(65guUh%3!R;@6TW9ws=Hs*1*G#I?X;c~C3igA|fM z;PH3Y6u~4ROkDdV(rSdM^@bo!+*v1*C&E--Gzi1gw^Aj9sr>ybV5?RB_8?4^!8nAe z{53(C${$|(FXlfk5kanE0mh0VCLldr$fD9z2(=+*PXGFhcH*A!AIW&^;3OPe86q_U z&7&kbGhW$QdR<%L(W|%WbyjD1ZR)Lh*&pR6c4_E))i@ZI@c=g= zv#^uYTlFjXy+3LdG0kXg91N>bfX?EQK2aUW5S2lkS#`K#)3!z-;Oa~ZJCd}S#S+w4 zMm$_~X>nHOZ$m1A!F*cwQPv(6OY4a+jD~2n2y?))8iX}Pm_5SajaQ}KN(jS9 zik2YET$Gi^APkj5c0(8@fRyVa3==@gB@qU1EYo`BzlA~2ViHeD%|4IWsz_-ZnW_g_ zQA~S84KcpLqy&S}0 zqX6})05L6-UKOB)5R6_G-~tp(hcjX{sA=l?b~bHNGhscYL>wW_(CVn~I+RDeH;7kW z;E9X_G{3VzBmEIg&GMv@A^PAG6TFi0lZ2-eu)mRAeIJ zT@jNHiAMeFqr%Ybx*}$N5-pN9kv=L+rH6X|3a$G(5r81~aQ1GDZxtnBD8*Am#fUCa z=#V}7)pDzaT;kgC*dJ>8`6DQpi`c0X7TeAg zhV;a?Gkp#it+v>9rZB8SY&%mJE*iwPGlgNjV%wR*Fq?Q+6zVzTMQl4$JY1J_#ST{A zyAs>F^c6(pPi*T_81g5!btw$_6Wh8JhWu3&TT0}TNMS>2!@X-dxK^Xv^eshU zjYDwRuf>gL-AwGvnxcbcH5t@&91V|9%hl}e?A|B?Xg2XpaAW}-VVvdsoDjzK^aij$+KC{tMs+$?? z-FijzL>i6+>mosZ9)^BKP&Hw(w4n&wAO@>;G{WwP^?`Pf3PZeZ2(uHi7by>DWiDvR z)r5!lL>@@e4|V7s;_-|&w5%;pxPGZ$R zPpuahHNUGc+;TKS*d>w1RDG0)TtfcvQ6h2)`NKzv$R*?tA0?vCU$VbAmZ z=eX2+^u??{u=59lLa@*o?xzqbL5y1suC=5q2oswVM9M>$s*4o`EQzfx^^26Kk0U!aH6uZ&l;ovwG=tc2UAf%p70Q7M{M`-{v z4Te8gJTWPn)f-1 z>L3l+^SXv_q@_Ywsrquy=1OPzb5^&+^drQAO~CfnEm^XM)KNFvt~fz)NNPaZ2V+U1 z4`doMaKPB}XId-pxzFJA{)3|d=EP8!+2OL`Ns85z?t;9tkG85sq`9mSy`mqNQHo`Q zNep|i{XQYnSd?2kA6T5sn|`e?edw(tea>mE>)F${bM<0Su%W+WH%dg13V*1%f4 z^n3amxfT+C?$~#woN2)pOyhEy!IsWVYN7CAgd>*Hr_QlfL_3R#CR(x@qG(YnEZ6c~ zowgBjgjoc+*S_ZEiWgHFIgGi2I=64_=@*g@`~LFR**0~E(Va=G2h5cCDRp)Udf|kL zYxJP8i&l9TuWoBx9or?jebtTmCR0Gk=x&nrEc3TeFZTRHtn z!^~_FkfT1+-lWCM!K$sAbhQjILLjLJcmerlYyy@qrY@ws!1%3V?4S^oteS7y)yh%% zYt_COyT24kD0gM#s)L6fOzNe;Kb>IHd`N7g&=Mq!g|VfjVeoAgbbQ6bts2pjm~61b zuI`!6>G^VzL)61xPn{0>%R!bV8o={u98HV8kY_6YaVBmnvfv62zUI%aLkic@Hf(pTi{Z0tRV;-Bn8xtGsqj_xGO- zQ~r_vfM#ACzOe?;G+;sxxY~x!I`olrUcrk7HbmE&Y24Mgz#sGz>B$@U_U2V0HDN1k z%}g)vu;*6vV+e$Z<%91It&D0EYECY|s;xk$XaKng!QHrkvB5<4VcKDgba|;v=g!;? zxApfnBR#;w`FZ2;T>43>0*1K%`yg8E9rszZHWCiCYvz7^)_1z zlrD+ms+o}b(CyrvZ$zpJP3dRVL-`y65kxtB_JBI17wn;CKfCX$R9OS6d~u>p7h(@G zFIo*VkR_=321HoYySMRZl0>9F7BoGum&XK8BH==_K<<6JVS}ENe$8U1Dj_@u` zESLu+EePMmx&)3B$)Dd`twe0$z|KnUvfch`T+KF0&p6+W__tnpV(7#ar1sb$W6uXV zDs6FIwVcgLua9@=N%S5}5YAa!{$Q1Y?J=xe|62(%hq-ccZzH|3+@r@ z^sBTM%!UE-&uVMEd)Lb0Xh2yq4LZBgtb{{Ovu6!yTgs6* zi2Ur2h^K8CNHL^B&hU%$mqhN(Mv|f9jaQ2NhC!Sq=<$k;CCEkQdubbiezX|gw%_Po z6o*V2PJ6s)Od^qCkIt}k(t4W_(bR`0dOw(|r=6{S&rDjt)L!3aYo^j~)4*OCDmbOk zT`ZuzJ2<+!Qf$uhUE`vab71=NFUQug-gdPbeb|I;R&`9?e<)|UwL;*?4Jt;;|C{5R z$`PJOaLfB>)@ny+^_zW4N$9<_eA7=wH9L`f2zf;u+85q zS#2z&aA@vZCT!|QFn?y+jlLS9fnbU4!oYX5py{VJOk-@%C0;3a;~%AaIzsp44)ecb zJ!SHBqOk%DXqCP+a631wh6M?L%TEhVwwg-|N^e@wDKtR&%XMGO*YrKxuGS>GKu!yo zX;!=lauQ6lHqy6WDQPL=SvI;XU=4=cmHICJ%gm&*(45M_`xLJ9b(P+$sr=;xy;qCu zg2i9&dy3gtOgs7V1a4uTo_(+mX$ZT|myaJ+>Xm*#Cw!qRBB?CMdElFUN}uatvsQ9_ z_H4A<#A~(51qi0~4v#-HYP8~Ok?%0bKD^DkYNm^05?&owtC_-CF8KEP$e95Z$y2t# zlrWK)6ih<>N8UpR3|D*{?P*Z_v-zcF5?eT~RX_dk4Ejkj zQ#_KH%3t-UI1e0;Y(0zgVrxONhAHev`i*?x3j3sJO(#+xrk&m?2Ni{tMnaPphfXRa ztKke#eK1}cIPffcGHXQVuyJ4(-q|JWyXT|aGLto&v#ITDNM+_DO9Mh$DC0+`rG0U= zuJTvom(N~A6&?6&&i!&txs;~OT!$-Ia){!T({S2AMUf_yCK`B2B6=}6{N|vbmN)vg zB^p>JL|;jsu87nURz;d4slMIM-LWJ3NKnD`OPV%o@2&VT8aULftvUNi9TLGj9O>qX zgNlPLJ)vrNP(hOZ+#j>eG3Rt4?LXGxa_*~yeMJ)|(Qo8zD7&I;UrI5I`~8Ua6YEt? zpG3AhQXk?$t1CKX675C!H0&;&WoU34wo$cB-%Yi#_9!$XkAQekXX+{*bX6*D3xdCu zv-~YFz=5&oO@S|zddq?)?ReJGVaALS{k# zvGF(hSvv~4<=+!Ws}SdH%zQQcyG^K4@*FR@HfD3w@nhAAGaR*O_~hu7Wm$BAPslBp z0DG-^87EIkUCimEAD)&>v8qsgs2?~pX7sJ+^=_N zrszp87)SQX;)K5(-7v7a^~^i0ARGkNUQvwQ@J=PTkF8sixOZRteq~m$hr49bhdGBG zNf_*xubn<(>@*1#Rn{G7|Lyw$ z>t)?A&bNcYH-u}8o+zrcSkVVf3lNn1?VV{QG$q;a%U?SgzICPpi&AfLB|Y;;-w!j& zYqzns$sTX^?(?ak)GU7h3$iOcCf6(%8W;BDik5z&6FI1pSLBF(X~#y8ld#X_e|$fk zBO5Ciw;{S5+kV83()vNHZ;gw#1m0%fz^RBml=?98j~^*@%nhZ0xn(b#HXFY{;XM|H zxcp(x*Mdb6B#2jk{>RV{$$u*}-1!*Idv~bNp%R(I)R{~^J{5ZOiz3@L6i==VvQ0E| zhT}w9u0qZ_~Rg-2SQq*0V>05(+bKxVV(aUE|9eyN*l9g;Ylk6!Y z#-3kfrZ9PR0jSjb9I8@1nUa#ad{*qSkf~4TnwYQ4_Z*v1QT`L;Tlz-=6;Ur*n!Ja= zQ|z|yF)wEpR+J%XBbP3`vFSjCvJ^qb&kKdFjY+P)h~DpH2HsirT5ps5J7XZ7u3efb z(@^a8kJPI;eZMntV#_ee+{J5XK?-2;<;(l&<35p8*np@wZ7d7=zUSSvSD9QFd^gXx zVm%R}f6%m<_hQ8uYG5Nu3RgzrPc}i3(ph{cP6jRdEj_)T+qY+tM3)V%v_9oEbU-Z@ z3!V*&$m1)cUccH+G+Y(RczAjH0zxVvJa6grX~fafabIo8a~Am_wg0^$Qw9jE`jS=+ z8ba-LWhypypKs-~;bYHVF{lXntG>s)nYqhMGY7P-S0^wfMX>0RPAlt^#D3 zzxpmvOtX=1IBZR)6T|EdHqyV$4Iqua?7gyV#S^8o@(lc!J_@~2<>kG*R*h-EY`P02u3E6?`}OqT=&Db}wh&k2OVKD#ptjqUdr@I#O*bE67WRIt{TdSTfFR2RJ!LjHj+F zE5Cp>s1lg6km&TNdmC-FHCY#G%g^Yt^*fX3?+e**tF27x1=r4z#c(2F*i@xKu?qFt z<7tCNDjg9L2Mwwz!!cTIU)CUZ1#2akd$L<;&}Fj^FpC};LmT9zeCH?bK4{S(Sc~27z^ve{1PDDsVn|1m>$n z){n5GN?4yX0>?1qWa_>&xugNkHyaM6Q~TIW8I{Jt(8Jf)#>}Mt^fK}q%ukE2{&ZA$ zD$R7}df#4go9mlp!EV>E!og$DuV>o|A^bkoi}du44lVmt*4Kf~G2hCz5DYMRk=Kf^ z^KI-V@&X2boub1up0GgSLSKRU{+3GTNrlv>iP_w`N-1Z!QkN@tqf7J(iZdo1g~nIljxk7u&z|*jd$_5& z3{JSV=cyq>54QHD7$gfO6@9a>d-r(kDxcq;88X8kbS6!-RF?cwOPJ4cdnikgaVNF)$3pS(w0A*Ur#aEE#&OL!-E~msB{RNSm86To zTFT0W_<^5lSd~f*QkQ6gJ06X^5Ha$S!paBO z*Vq1h_padLv%yktP}k1K_ffep6U;GW&AWFE9Zqd_)wBa$Djn%HbV?vYu^dSU;NOa| z)X)JK*}2_eGhI1oxD^|KK}uDNbHJi>`&!ew({OSDRN;fJmUWDUvPPCygX}CRzjdcH zm4jfqvwPJgf93!>*6%4qEWtgI^OXhdkI_|RTfo}tODDx3K;ccQsW2Qo$=nvsQX1C2 z_40mb+g_p4#D~V8td+lZj81zPSyi)K*pG#V zH}bHaGLqG_1NLaO!`>aLw!1_VP^r%MyEvxpqw%p2Mgvx2_MO8&+gcB4Z@vTGG5Ziy zcc&}cDT&M+F6k5(@T5qW^2(T( zcEEhyYn!u;Eo}Yg-u!X@MR)3y{HgS=pz(Bd%qr_CV~1<&LMPuS9FVu2VQ4HsDK9uW zO?JrfsAYZD`i^GyG`7O%-pi)wEdXP%SzljSnuGYYUaVq&aNLb z#VoOx*89Y9&4PoAUv%EIZo|X-pJ&_Y>fNto`FW1l>#H8r#(N&VyS9EO%{1B)a`K2KRB)b(pYtEa^{+xUPZA3wCf?|EVU%PlLg=nYSv zVVJbNVB^aY@@P)LWlgqpJyQXH{ zs6q3>fr!QIcD)Z(VKFzo74Y%l;sfW8$ty~H0`;iS_^%9eKycdXJ7UD}hDx))ui1UR zum6FGHnHFt*9>v)eW(tgd4Q{=kL>X@r~83!n@a`ry4XJ?w*ee}nUh@0de8%SVOML; z1WP`^9V2OO%@t0Lqx!~`JIn0R&tLMO?m9Ll@967p$6y>x4Oes`cN{QzFJ_)r5H zaJ*jsMf{i!mz;PVD3;3K8;pqfQU`P?WV5r)Fq5W{ParMXFZ;rt(@jQb&1=HMC2E@) zHg(RNNlNgHgluzp6cx2L%BP)UJlAJ_-Y6Tw9W+hi&EsKalhU6J{tv=)*c6jKS?}(; zpXrtmfQDbUzS=FWT(XHG$mSp#oqx_?pQc<1#<}fV&O#wNenK@YiuOs5&u40S!ktiq zG%mc!$6NWz7}L#F^lb%mZ0wqP+;zyQ?@;;hg7YT&Z~Ozshjh_)#q#QRj{5drBoN}3 zv8s#(9HV<`T3kdW>nk0@AS`N-&h}pO+LkH53%}WxuzGj*xGz_lk938}2VyBCUS3vD zaaFXX=qOxtwA=QDpZEwVf+zJzCIlBq!n)ll)&*NOo_WOObc&9jd4DV8N864w(sadz zujiKs2bAjqzV-MSFzlr~SVfcc)w_pVPpN9X_j!3>V@CINC#h*^vt3!XNaF>XrslS) zPN&v8$$#rXr#Jb5QtQG&W0IP0pHh(Xpog3Lwb(yFr`k0;wfq6}l>Cl&(Z(K6-@luh z;Jp5Cuu|=24f5}k);5e*Mtrt5x_kHT1=b7GFWp`c6*l&cB{)Cv_n*|iJj0UZL)!rH zauS~&bkiM>1Mpp$qlb-c9S^aO$vQ7TCOufA%UOW!~2jesVdhrN=RcoW>5`ub1tDF;tT+ zXf9v3WCsQwO$SJIT+!`mJTdA?@HqrpUU>i4LP?t{GFBd7$JGOa@ZRE4;J6j;_H( zFR$@)J4dJN>y|)m?D%KnC`5!?+%PBZFZ888b$eET7(BQNK7RIZ zu-ojw8&_fc^bN7GPEi~!ws_0s_dP6s-x}=ZR?t;9>M`_ngV-MDR`UAz{SVt^E`H0S zsHpaDv4R=FXFhe=9<=jO8gI+5wORJt8XR+X(2&=2ePCFer+qkU&6q~)*c>@~aMWD| zU8C7vFo4M_(+c8)@%J|8bmCX!EqUZjGba3GE$dl{y9*(oNWABi2GbRVSj+@)7J_Kf zpXpQ~8vECGU+lV!n+cnaD`;S3&6ZkCmD(&}SA&E#^H`p~=W%S0NN8obIh}hSn!^qU z@>@)@hp)%$3QTuB{}>nE;Nw-TGPy`Fagv!+J15_Uc6C3srT+b`BNaPO4liUqBR`^r z;a0w<*$_6JNVCA3kYKjIpdan1T9(hVOQ#!h;fpFB##E8A)SBr?~EGpC$|oR zuu6WJ>SI?&jACYAcJOvrw!?|fy`b4utr*SDK%&I66xcjz{Ih?1 zgm-S&>i&2b1f^+rQLDbCMs0)A|MX^i0xcM^ z=G^MVdu)BvBX2!J7KL%CKilb{gW!=E^H=f@m3G&|h#*J2*ngn~#`TeU~ zAMDiokmG2kU7KK)N;bvpo^ZbJ`e%XD<7>gp`{{VoAEORXx1<*9P6KyN4R({wGjmF% z59#&*Ha?DDeA$}L(DsVh^c6r^wO{}Fw?~cmQ?<{`0N(0QTlGfaO_}IO5Wh`m@DD%f zWs%T(#4+%ngMVw`v}3ES62c&c9$+5z-``E!9agW6ga3zd!@=-f=w4%ooh@snA%J6b zdUqsh&`ifs$uEaPZ|>Zi^R?pdOyLc1yp-sNzniu{dQhiY@ys2QTK9V7YkkyQ# zX&d4F_1q;JN+&ROZI3wgdbGLz{m+Kdibj!X{33d8Of?IR(VX+yi8p53u*$%qZgoje zj>&wa&z+$0v{5Ey*;oc_fVlg8)-zP!R0*O>zgzEMUAq7bK3TkTvDOP3LhW;D>w`|v zoW=a|gXQf9+UboPW>DcJ)L^zt|7n^1^wX9Do%XZY*tRAt>@*X@PkLY2Q=T_0H+lKS z@_XhhTTVom1RYNb?rNuZawv4jIo~Z1_T#df&d*4r9)J&vqw(uZ#ux9VHF8*XBRzZ< zoTu>b*y6x;JBY`Mlh)+ZWja;eTM;#D?;vJ1KU^Q_R@;5et8?R-ByFDVW5L-xW!c9=rei zzU@cV)8Fn!-CG&ub(jXYr90G}T+q5#=VNSTEnS3g4;icrjYy?(oMl~b#+^1q-)>j; z=$h6&sU{v#LaRhN4@QwRJ^EYc>}63~sH1z7!VOV59rFgz+OINIBMJN}oX?tf%f?&B zzd8Ar0#9z7xZSR5-Ma&rj5hGgnV#lD22+4;oNrGika+%hxW30To6Og={HQ`&Hb3b6 z^o;KgeWuq@_OyxK6%lHPQl3Aw}ij2}ez~IpH^(ASM z{99*#rvvfTwpA~rvXqH?;HZqy@?buA?lWy^#+G*a@Ex?_+8e%A>y5YG(SOaWt5aFq zv-o&5v~uvGOhjm-ncNHmc&jQth_jna2l9qqw6)TPD%;tx`M_0F-^h0$6_tL`xp>xw z&Rp8L_5Nr|0TniFXqESeEyyX7YfR^33fJbDbS8L3hmO?1dCSrPH!83Io}M2BBIbuE zQZvWQoWnNOdkd+oWJlli_40bx*zRA`L8(gC@cy@$NHwKhl|3hSQO4yI_rR_hRn{^l zZQ<-AAziZK><+}tOPG*A3%Z5deEjEm>pW^``>|dYFTKxfdSFlX!i2;jvyK8Jz#6bV=Had0qT(OcJ&H+NyOYaia4>DmjAn!9jJrY!COdB_JKzQ{KA3lu zwnh8h7Z3kAzTj#3wUj-dOXvGZ!~DB-ZquJJu|c3YzB!&S?A!72iglWK@?=?0Kem5D z^u3{H$*|G1E`N)JQMBK6mjWC!4!7>w`BNh%I;lPPw+!Qtjmq47qx^8XdWjfS)A~i5 zdU+?xunv{lL)48JdQ*kX`77^rQ08<>OTWM674mV%w}WLoJ(R0Iw2Kq@s5aD6RJ*mO zpHr9asl&ddoZCPzW^Jlk-P5TQ$mj#V93=gIkE-3eKl1wRi>Q)xD!&n>5~kl=^kHJd zu4!~NwefexrU8<=)7uM^XPrQNJ?!l$@9e$Gc z>h!92FZR*{Y@~cj(^0oJ{_IuoK0Re_OJ}A>(s-_s`jNDiD_Z++NuGY=ZC>Jt@}Zv{ zeoX#;yXZ&vySqO=`}xCT_UD+N!GFIksekYzf9AFypZ|G#`rGz)w@Snu%eghQ(Xk(& zr>+_E>H9Fogr3KYi8QY$J@QAelf$Whzx;e{)#Y2I$RD>O&wqLx`FQ^03fh@-iVAw} z9ue^M)AzA#EYT3sZky3;kQ04hZ*T9M_fA_c-rh~!Yetxm@vw75yDan^n?fmEEWruc zQolcp47Xt}M)SVZbSgio9PbyBo9xj4 z`-i)ye-!kDPej*h>nUYjPTM`pBeI~aYvd1KWW4;le^{)9dJC0yGkv25CdXwuGYUkf zL764ldOQR<+g3&SxNO}`!?w!La-}mHF!WEmi)&{v7_sP$^;o@V(g}bI8ekij6f6{# zSHa4^x%lzQ^RaSGU5`6ZIgM%p84_AB7z&dddlzHfYRi}in zQFbEeZ>HMr8{x}1@KfWQj1fQbHWmO5(ehOkA#d{w8f`mw_=amc2mZ~%i5oVOKUd{M zXbuTQ`gnu;c|*a6E*HxZEV~#lw_2fk>f#ZxjEac2QCF#mK>{&}U_W)^&OMPzp&r}v z9bme~L7~c(gc|7`u$C`)uhyor=p_R`5kV7{#0o)6r-W|Hm8(w4YqWQ74`vzZjC??l z)%E`IWXO%VmWm6a{PZZhB)1!`Uk8ic)lS9|m(Ph|`(Y8d)O1kW3jvBf4Z5DIg3a|4 zSNWxy*xX!9?vde+weZaw%7+;?_aq9nf;BdmAGx3_mettYmfYYI?O9}T8nQSHg{rMC z+M;iOh(|C_+b}m|XR|Ot`mxKLKb~FXdWgA!R8GS%=TeKo=k|DPb4_MJDCG;@-fnT^ z(4orPA`5VEYxiQsJJpIYnanU%4x172nTm)_>8LiP79u(#Vp~2N)6?cSzHkC2xwhCX z{ZL?~v0H-p%k|Wn_CYy3TFATHFcP~Z55h3i)U8BY;fYu4KS9PWhsI)cw%ktd?pWna0N}Imu-BwXkx=F6~``G-dT=)?x%b70o zI2AjUy#^lJK+p9rkd?vb*9HPfTXlSTSmg4J9-KWHoz zHuj_&60Z(>RDfxPi1-ujoYP5M<` zr=&dUv8-{q?Hg=9y6d`@vFr55i|>yYH7e0^Kwz0FUFTkzF=WV=K@)lpc)ab(qdSd& zg9B)o@-abH*jiMH7g$>gvgRU`k=`8Ua^_B#jcHl@5wwDy>E4FJP9D{%G87 zdANt3)>$ri(Yc)A{(*6#N)Rhqt`g*nc0yXVzqn`Sh?y13g78;kCP<%iPREX|nkSr< zaAfQJtBSKkpKC{n3Uvdp!c-JU4hrNqEZ!7hpOLZg2s?qW1cZenEDvG7AD*QK&cjP$es&G=p%AR1z1vNl*`=x|J}=VGs^aHCbcOn>R0m+w@zz z1cXU)QJO))DUX8RoUU_TOgCGQSwEb@Kfs*|T6h}WT?85i%ywh2L8*&19?{N3iOdo6 zBk@C(`+$ah8r=-%1ktP++9AO%3profPbxv-Ba(V3;wrYgeN)HY6 z9Wj@ZGZD)My>Q}k`#3ZZ?2u%zdz!Hw)w{xmp@3nZ`tNOYN_^&d@tLgG@1m8S+qw%F ziqbQtT{YriyLm321yG3fq8sZ#)N@q>QKl!tme>dwx|>NZ<(or^)fjOYBjq z^3>)B08bl%gJZ0ZA8(o})s}%%_&Q-R`trx4lex=lyG&GKoV~#t2+*d>ES9E{mV8hW^*l60JsB2!5SBY)es8@oc{E1k)EO%>mmc6 z#Ly;NaoDBeterm}xu1T98z*T9D#Z^}`Fsmeu^fpMvr!&Jm|G^_3=zfRl}IH7J0ccA zw5gabvSY^Z;jWAqsXiH-& zN}dra*B@JvjoQ@_J<15NjwiX%qC0Xi&59l?*7sBiV*h4i|8~ULIYO+7=p29q(dV^C z=gfea5w(>(rsQR2uIEk%*@Wh@Wb2E2zAjmEky}SOtND7Sm^3Yt`?g)zz85qW>lN?7 zoyw7C`YY2*Sg<3yKLreDtbNxy^7+0JdTKsv$Fif;)Hpf|?Mte*w?5F*sw!TgT5o_! z^-<1~?)2g?H-z=uAYfw<*1}uB79y-dH38cpVDhbftAHL^iehds)D8?CS%Xe+--8{w zr)`PLh~|Iil!3yUsNedheLea9A^fL&f1#Lt%|A~KJ$%1T;a0X;r?^mJ@u$-Wg);hL zUz;Hlq1e|J=uh-V@5~mZ>5P4?3lRkM>qI5k{hmCcNllZZ5PH6~P;T-Qhnf0lS3X)^ zV++9``GFHwD(01v_o6uaB4Reqnp<&-$Zv^NtL!X!?)#B*4l+bY{&CxML$CbpRV~CC`iATo}9aj=Re&wLZ zFP{T@^7U0o)VjePF7CPA_BX!hD~Z03{^aW!DJOo;sLGcLT2bRE6tU35st53uhXxs5Uf>0g|P1|$T!DC zta2q`VM5fWu+9p3%41PuEz!q*fmTOTTM*>QHz<$tY9xq08##+Y9;XsSfj(1V7%*2W z7XFsxfQneOL^LiN2cQ%v>dhBBRrCUqhOLaRbER`a2^nopKg@QuNC2VAR!BPR?3<+O zd<@HNR4~>!7w2@jG}ef*I#N!I8%)|q&I`0?bPh=)Az=+h9cfAxu3>UK3M2$QYDcsQ z@#Wpj%q`?3W8%)abg_!5(b+|`OQx=#%+p&MU6BKiF*G1 z{g_zcnSf`c*l<~{Mpu$F6{B!9MjA;|p&+Z#BPUITi?A9eV&W~d!5*D1vQI>fw9~M^ zeE#4XB3(i*lUfUH9f0Obj|&lN6=p5)Zlb>E>j~H&DhyXA15}uK4)<2oCl|Giw&rAf z=8^8shsJQ@q3v00T`ai{JqWr;^lfhM7VA`POmlXujeas92b~Z33lh6U$9=dkl`lVO zMh`A>LzTT^$7PzB3$;$o`SO!g5=%nK&Sx*L+rErw=Ki64Y!LfO0@h-v@V)FYX1m`f zUX;ZJPYa*j0)~;r35S&f49ZWd6C%1ZW<4L6l2J5d-+2eokg_gfE$oSr9kM2tt%ZLB zV)5z#SUUT}387eOK6J7MVdx%`%0k&Z(bFJn1S|=Y<&*ltbhar}~pB7tA(@Jk)|Ncg1=zeWQ~siNw`FYEBjI;h(4Yk2$`9>uib z|GGLDR`yKc$3Ms}vFJH6I*{F}qKwM?%CpL|8odd+y*&*AUitidHN^_LeLWjiNk#aK zn<%UX(>X){w2tHNPG;G(ln=4^Yy+8;mBr(Qbuq9nS!5GhF3QXn0D^|}_P zYAfR4h7CQxipE{Qu#0w<-7DB?kXqr=j~8_lfJyi7bs#&}ZK($z)Q2@m*889r0K`|7 zg3|At;wwYxAX1<^Yo2f?kZu@?_u93?XB1YDe)2dWGSzm+jI{FMq-ymeKu2xD*0e3= zNA}N1#Sx3js;gX3K5v8CT+qamvy#}`r3F*^Ua8gyq|M3?ma&eWIMhx1m&ij|r{pY^fUtkOZ^jF8kDr4w;*mbB~Dgu9dX zb0uhkpQg66(znRwEpCVc>Z>nl*sy}7?xQt}ok+c3i3ZZqB6}{+wIb|P(<{Y4ww!?{ zW+DVXWEEz7A*5!(z?8WY?t{SGg;ED?-n)lPf}CS?mwPC-y5ZmwK?|(t!F%PW5u3x> z2MhahM|7sfg5)p47{@FF_HgG@QVycgQ8dYby50U#!YkQNmhjr z#*%$S<7tikA8cV+m}o_KF6GQ%>Gtz2yuaE9p4G%QWCXQO{kI)BwsYO`J1m4)FWM;s{+H-fTtoVVYsyM% z-wmdc+sTWGW4iL=H|`~jJ0SldwO6l1gTB#Y4v#AP&&)J~i8 z`b+2p*p$@;^NV&Q-y`v*S)9e&-=OevVHop0j_ooFsVu5!o1q z_3_0W5Smv?0WyX}+EAY%BI@yLhF{9ZvP7f#emj$M5vPn!HAFcvgF+ovSqc6mc~JyGZG*BKrymS zoVk&Ep14&y|3vULI7TGhnA+ZQ!4p0Y*Q1&}Ip)jUHtnPZv-bG?95EWS(0EvkO4)YE zE{psosi%S2*-haJEj@#DK69|N05WM(74U$J&J=6(qfNEt-yu^V9bmg5Hz!58DKx&M zPuv6^QQkLyIseOj%D4zp`Uy)BN~!EMLP98N5K~=8OzzX<^hO7H6wXpSI|ZGunhyC! zHayz`qe`d3Thrv2)ga@jLXPK`A|y2Anw73b%yU>}$eV=ejNLcm`-Aftv(}c3%{=?{ zD_?}{6+5W9mLuFN>%0>OfaH=o3e5@_peWGivu(`+3Nl$bQd->|aa3H6%TE0Ix?fe@ znlx-OTDJSNzn1PH4O7BTcjdQI_KH!i^G<$ATkWx{oaRdU@YwOwC{_B~hlLx=ZsjEn zIF&kL8;o(uOL#1rl&p`N2VP0LTw?a6Zm+*|V#(~Oq^{vOeD->LUiLJzQ87J0Y;u-R zG9S0sUnVtqc4eBG!|BtfH$$aK<3(eu(P?_ux_4vFkS-qw_BqkY0T5O~%6ry3tiXBb)cPhq=WY|*w?kFNEr{j#$3>@R9Dc%qdqF-zeqrsr9yLGj zLk>26+YOp$TSu6h0|^P6Uq(5%nXcP)YRL4^v7Z4U8oPAJkj!hxqK>x-*9F))jAbr6n#0|_UGE;}lf z?bJj}bg}q)@+`{wB)8c|%j!m5PdItvDD};h->!d@>OJ8TAFcuH1sOA6 zH_ZPsrjuOeTYTPyd>FcYZ$vYPOXkOb)hr#c{P1tj+0dHern80%I7h@SN9y}IHT9}(BUn2m!RSZ@4{z+ ziNZ|TE~*?k=V%L^y(?9rkz52`Rc}fq=1~z-_e4Ev;QsL!0 z63yY47cep(z*l*8IGSp@|I#xpCshm^D~bnT!+X$7OGcYVl(#WPUTlldn`rM7zC~v( z=G94A9yOXJAfy;V?VlcNeA8BL`K``Q@9Brz`axOYA!(*IsMd+*$Lj=nv8V;vhApM1 z7Lv>bBSrA$04?2+9u!WsAHZFPZ{nJWbeZmiJ3&GjisgYdG|3rktl`FInS8ufni;=U}nqjP<#%uKqP|8@nh^i5WZa6i7s#_`xrwtl`J#r&_n!`}3YZv{x#l7@u&u zok*3`+IpMgsIf0K6ShHOAi8c16b_tj#+Ss-%c7_qNtzS8zTdjJ12eBBCxfMsxA9~X zM7mFhLVJhyQ}VXFK0DFH?c70@uZ&i;Re2(W{Q~yB&7w&}ZLI5lbCP>R82ctvT6$8^m=jPozjgK|NBA?8j{I?Mv$uY&t($)el339OjTKEM z-5)3Sw4PGOx^zH^?MIhItxX6{+|Q>5{|!QcJZYH2!!;kNc-NT%A~9rWbBxAl}akne?>UfgN-_j#QB_R7bM zRRQHsKilQoJFP=|s1GlclUKbSCtqyfIcM^P{2f%v2co%@7r);B9dPAfW@~B32b|0A z``9tZlcijsAD^OMmpcE{1S`iJ7YEl(9lpJ0HSzObwpPgKU#BLl>Z|_}bE3^4Iw|CJ z<)c0t*)7z+&FWruu+`OV8-2Q;JC+c9y#=h(=>r}jbU5qQ%-1Q`o?UuZX7I*ChxsEzjQP!(uSb?0+~s~*N1pD3 z(6>u?WJ#9G46f1Ycg~-?@ac&~AN`dmNW?*FYba{dgbbgT*W0c3z3S!;kZXfT8^zgb zxz`83uPq(=r#pI%9YK4^&bs=1-iNU~u>m#Jo{y84PwoCO?R!BVyQA|ncK*qYfQ#@& zbm!=BXjy%5mn_FlQxBINNGF@tI@W6SWzi}I)}{_IgRNez3mi77<@OEsAG0-F-|@tB zZ0xBC)v0`R$G+{lHa%l`LU2n<-dRPB&IsP(DLbtO&Y67U+nH`|z9&|44{VIkN1cVj z5VZUAtNneVBfK)NWj2v3g%>v+>{D>B(a0A?TbS&TH zXyW#kFI@R?3Ds)JkB>TJK8*^S+;n?#R=EKOo+HXwQHAvL_RQBey?1>1d!fbK;ATD2 zwtVFtfb>Xo1M$d9DfBBlcvathd7JWnbap#8J-mIZys2-@Im7;tYMC-u)MCzEyWm9$ zo6{2_HyW=`S`vTP>(N7xZ*RfBrdlAB$R+(w_ss44Zi8i zLtg$er7*r^!je&$jrRAM{pIv->e`t_jsP*}o+IAg#xY)X4)hbkwl`-4UwP3`>*qSxdwOWv3&CdoC`2}X^qXaC zz2w;}*9&_G%$-qm`%~l_n>!a@?s{P7w8b?dx?hJU|K2zaVF#iaDs+HXN(N@vKi%p%TAFjqpi+NdzSD%d-BOYlK(B$HcGM_m@Ay-un|alJ3y{lF0wB68Z7q zR2>>+m$j85BJ=9KB3B$~cUp`4(7cO#o%@gPSQ+x2q6SEA|84*OaT40WK{TRd?!n#& zApb9LMDGjyKOmQ1T%Z=xKYsOyDvkfWEFK>QKVZbkbxN_`-TS*GcGb=QA0a%= A!T Date: Wed, 25 Mar 2026 21:35:34 +0530 Subject: [PATCH 2/3] feat: address review comment Signed-off-by: Mrinal P R --- .../builtin-toolsets/crossplane.md | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/docs/data-sources/builtin-toolsets/crossplane.md b/docs/data-sources/builtin-toolsets/crossplane.md index 7a2d520036..0d80c1108d 100644 --- a/docs/data-sources/builtin-toolsets/crossplane.md +++ b/docs/data-sources/builtin-toolsets/crossplane.md @@ -78,25 +78,3 @@ holmes ask "Trace the claim my-database in namespace production and find which m ```bash holmes ask "Why is my S3 bucket not becoming ready?" ``` - -## Capabilities - ---8<-- "snippets/toolset_capabilities_intro.md" - -| Tool Name | Description | -|-----------|-------------| -| crossplane_list_providers | List all installed Crossplane providers with their health status | -| crossplane_get_provider | Get detailed status of a specific provider including conditions | -| crossplane_list_provider_revisions | List provider revisions to check for upgrade issues | -| crossplane_list_provider_configs | List ProviderConfigs to check credential configurations | -| crossplane_get_provider_config | Get detailed ProviderConfig including credential source | -| crossplane_list_xrds | List all CompositeResourceDefinitions (XRDs) | -| crossplane_get_xrd | Get details of a specific XRD including schema and versions | -| crossplane_list_compositions | List all Compositions | -| crossplane_get_composition | Get details of a Composition including resource templates | -| crossplane_get_claim | Get a claim's status, conditions, and composite resource reference | -| crossplane_get_composite_resource | Get a composite resource with its composed resource references | -| crossplane_list_managed_resources | List managed resources of a specific kind with sync status | -| crossplane_get_managed_resource | Get full details of a managed resource including conditions and events | -| crossplane_get_resource_events | Get Kubernetes events for a specific Crossplane resource | -| crossplane_list_managed_by_composite | List all managed resources owned by a specific composite resource | From 8e603f08e1a8421c2076bf26b67d8ce5915642a1 Mon Sep 17 00:00:00 2001 From: Mrinal P R Date: Mon, 20 Apr 2026 06:13:49 +0530 Subject: [PATCH 3/3] docs: alphabetize Coralogix/Crossplane in README data sources table Signed-off-by: Mrinal P R --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0e7dda7341..38c94d5722 100644 --- a/README.md +++ b/README.md @@ -49,8 +49,8 @@ HolmesGPT integrates with popular observability and cloud platforms. The followi | [Azure SQL **Azure SQL**](https://holmesgpt.dev/data-sources/builtin-toolsets/azure-sql/) | Database health, performance, connections, and slow queries | | [Confluence **Confluence**](https://holmesgpt.dev/data-sources/builtin-toolsets/confluence/) | Private runbooks and documentation | | [Confluence MCP **Confluence (MCP)**](https://holmesgpt.dev/data-sources/builtin-toolsets/confluence-mcp/) | Private runbooks and documentation (MCP) | -| [Crossplane **Crossplane**](https://holmesgpt.dev/data-sources/builtin-toolsets/crossplane/) | Troubleshoot Crossplane providers, compositions, claims, and managed resources | | [Coralogix **Coralogix**](https://holmesgpt.dev/data-sources/builtin-toolsets/coralogix-logs/) | Retrieve logs for any resource | +| [Crossplane **Crossplane**](https://holmesgpt.dev/data-sources/builtin-toolsets/crossplane/) | Troubleshoot Crossplane providers, compositions, claims, and managed resources | | [Datadog **Datadog**](https://holmesgpt.dev/data-sources/builtin-toolsets/datadog/) | Query logs, metrics, and traces | | [Docker **Docker**](https://holmesgpt.dev/data-sources/builtin-toolsets/docker/) | Get images, logs, events, history and more | | [Elasticsearch **Elasticsearch / OpenSearch**](https://holmesgpt.dev/data-sources/builtin-toolsets/elasticsearch/) | Query logs, cluster health, shard and index diagnostics |