From bfe9d7b89afcb3b123c53e6008568315295e9c31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Fri, 13 Dec 2024 18:09:41 +0100 Subject: [PATCH 01/22] Index page content --- dev-site.yml | 4 +-- documentation/antora.yml | 4 +-- .../modules/ROOT/pages/01-pattern.adoc | 29 +++++++++++++++-- .../modules/ROOT/pages/_attributes.adoc | 2 +- .../ROOT/pages/developer-resources.adoc | 2 +- documentation/modules/ROOT/pages/index.adoc | 31 ++++++++++++++----- site.yml | 2 +- 7 files changed, 56 insertions(+), 18 deletions(-) diff --git a/dev-site.yml b/dev-site.yml index 69da4a9..1818b85 100644 --- a/dev-site.yml +++ b/dev-site.yml @@ -4,7 +4,7 @@ runtime: site: title: Solution Patterns for Cloud Native Architectures (Dev Mode) url: http://localhost:3000/ - start_page: solution-pattern-template::index.adoc + start_page: solution-pattern-event-mesh-for-microservices::index.adoc content: sources: @@ -12,8 +12,6 @@ content: branches: HEAD start_path: documentation asciidoc: - attributes: - title: Red Hat Solution Patterns (Dev Mode) extensions: - ./lib/remote-include-processor.js - ./lib/tab-block.js diff --git a/documentation/antora.yml b/documentation/antora.yml index f922ae3..8566f37 100644 --- a/documentation/antora.yml +++ b/documentation/antora.yml @@ -1,5 +1,5 @@ -name: solution-pattern-template -title: Template Tutorial +name: solution-pattern-event-mesh-for-microservices +title: Event Mesh For Applications version: master nav: - modules/ROOT/nav.adoc diff --git a/documentation/modules/ROOT/pages/01-pattern.adoc b/documentation/modules/ROOT/pages/01-pattern.adoc index 33fca49..03a75c3 100644 --- a/documentation/modules/ROOT/pages/01-pattern.adoc +++ b/documentation/modules/ROOT/pages/01-pattern.adoc @@ -1,7 +1,32 @@ == The story behind this solution pattern -A description of the story that was used to build the demo and architectures of this SP. +Cabs is a fictional transportation company. Engineers at Cabs were struggling +with their transactional-style, monolith application. They recently +started an effort to modernize it. + +The team saw a recent https://www.youtube.com/watch?v=Rc5IO6S6ZOk[talk on _Event Mesh_]. +The talk presented the advantages of moving beyond transactional architectures +in favor of eventual consistency. By leveraging event meshes with technologies +like Knative, developers can achieve decoupled, reliable microservices without +extensive re-engineering. This solution addresses inefficiencies and aligns +distributed systems with real-world business processes. The team had figured +out they could leverage the _CQRS_ pattern together with _Knative's Event Mesh_ +to modernize their application in a non-extrusive way. == The Solution -This is a summary of the solution +The core of this solution is an event mesh—a dynamic, flexible layer that +routes, retries, and processes asynchronous events across distributed +components. Using _Knative Eventing_ and _CloudEvents_, this pattern enables: + + * *Reliable delivery* of events with retry mechanisms. + * Simplified *asynchronous workflows*. + * *Decoupling* of services to improve scalability, testability and resilience. + +The approach of Cabs engineering team is to extract well-defined services, using +the _CQRS_ pattern to identify _Commands_ from _Queries_, and model the +_Commands_ as _Events_. Those events will be routed to the _Event Mesh_ with +regular _HTTP_ messages. The _CloudEvents_ library ensures the proper +serialization of the events to and from the _HTTP_ messages. The _Event Mesh_ +will handle not only the persistence of the events in-flight, but also all the +required logic of retry in case of endpoint failure. diff --git a/documentation/modules/ROOT/pages/_attributes.adoc b/documentation/modules/ROOT/pages/_attributes.adoc index ad2bb5a..11fd746 100644 --- a/documentation/modules/ROOT/pages/_attributes.adoc +++ b/documentation/modules/ROOT/pages/_attributes.adoc @@ -1,2 +1,2 @@ :experimental: -:source-highlighter: highlightjs +:source-highlighter: highlightjs \ No newline at end of file diff --git a/documentation/modules/ROOT/pages/developer-resources.adoc b/documentation/modules/ROOT/pages/developer-resources.adoc index 4c8b5f2..3ca4c1f 100644 --- a/documentation/modules/ROOT/pages/developer-resources.adoc +++ b/documentation/modules/ROOT/pages/developer-resources.adoc @@ -4,7 +4,7 @@ :doctype: book -= Developer Resources +== Developer Resources * Add link to the git repo of the code * Add links to whitepapers, ebooks, learning paths, product pages diff --git a/documentation/modules/ROOT/pages/index.adoc b/documentation/modules/ROOT/pages/index.adoc index e76e7f1..65e5930 100644 --- a/documentation/modules/ROOT/pages/index.adoc +++ b/documentation/modules/ROOT/pages/index.adoc @@ -1,28 +1,43 @@ -= Solution Patterns: Template Name += Building Apps around the Event Mesh :page-layout: home :sectnums: :sectlinks: :doctype: book -A brief introduction of this solution pattern. +Understanding how to structure an application can be challenging. Different +architectural patterns often lack insight into how to build day-to-day solutions +that are often at least as complex as the business they operate in. -_Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum_ +This solution pattern is written to make it obvious and to show simple, yet +elegant, correct, and comprehensive way of building software, either in +greenfield or even in legacy projects. This solution leverages the +https://www.redhat.com/en/technologies/cloud-computing/openshift/serverless[Red Hat Serverless] +Eventing component, which implements the https://www.redhat.com/en/topics/integration/what-is-an-event-mesh[Event Mesh] pattern. -*Contributors:* _Your Name(s) here (can add links to your profile)_ +*Contributors:* https://github.com/cardil[Chris Suszynski] ++++
++++ [NOTE] ==== -Solutions Patterns help you understand the art of the possible with Red Hat's portfolio, and not intended to be used as is for production environments. You are welcome use any part of this solution pattern for your own workloads. +Solution Patterns help you understand the art of the possible with Red Hat's +portfolio, and not intended to be used as is for production environments. You +are welcome to use any part of this solution pattern for your own workloads. ==== [#use-cases] == Use cases -Common use cases that can be address with this architecture are: +Event mesh pattern simplifies the operational complexity of distributed +applications, making architectures more resilient and scalable. -- xyz -- xyz +Common use cases that can be addressed with this architecture include: + +- *Correctness* and *consistency* across distributed applications and services, + without the hassles of _Event Sourcing_. +- *Modernising* legacy applications by extracting smaller *microservices* into a + distributed and eventually consistent system. +- *Enabling communication* with external services, that can be easily tested + using a common *developer toolkit*. include::01-pattern.adoc[] diff --git a/site.yml b/site.yml index 801df30..39a0fc4 100644 --- a/site.yml +++ b/site.yml @@ -4,7 +4,7 @@ runtime: site: title: Solution Patterns for Cloud Native Architectures url: https://redhat-solution-patterns.github.io/solution-patterns/ - start_page: solution-pattern-template::index.adoc + start_page: solution-pattern-event-mesh-for-microservices::index.adoc content: sources: From 7f6da47625ed3ddbe13b4280044c6cb4b1fb0d3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Wed, 18 Dec 2024 14:10:51 +0100 Subject: [PATCH 02/22] Adding CI --- documentation/modules/ROOT/pages/01-pattern.adoc | 6 +++--- .../modules/ROOT/pages/02-architecture.adoc | 14 ++++++++++---- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/documentation/modules/ROOT/pages/01-pattern.adoc b/documentation/modules/ROOT/pages/01-pattern.adoc index 03a75c3..793724f 100644 --- a/documentation/modules/ROOT/pages/01-pattern.adoc +++ b/documentation/modules/ROOT/pages/01-pattern.adoc @@ -19,9 +19,9 @@ The core of this solution is an event mesh—a dynamic, flexible layer that routes, retries, and processes asynchronous events across distributed components. Using _Knative Eventing_ and _CloudEvents_, this pattern enables: - * *Reliable delivery* of events with retry mechanisms. - * Simplified *asynchronous workflows*. - * *Decoupling* of services to improve scalability, testability and resilience. + - *Reliable delivery* of events with retry mechanisms. + - Simplified *asynchronous workflows*. + - *Decoupling* of services to improve scalability, testability and resilience. The approach of Cabs engineering team is to extract well-defined services, using the _CQRS_ pattern to identify _Commands_ from _Queries_, and model the diff --git a/documentation/modules/ROOT/pages/02-architecture.adoc b/documentation/modules/ROOT/pages/02-architecture.adoc index fba8860..b4c70e1 100644 --- a/documentation/modules/ROOT/pages/02-architecture.adoc +++ b/documentation/modules/ROOT/pages/02-architecture.adoc @@ -1,4 +1,4 @@ -= Solution Pattern: Name Template += Building Apps around the Event Mesh :sectnums: :sectlinks: :doctype: book @@ -7,12 +7,18 @@ Introduction for the architecture of this solution pattern. -== Common Challenges - [#tech_stack] == Technology Stack -// Change links and text here as you see fit. + +The solution employs Command Query Responsibility Segregation (CQRS) to separate commands and queries: + +Commands are modeled as asynchronous events and handled by the event mesh. + +Queries are synchronous operations safe to retry. + + + * Red Hat supported products ** https://www.redhat.com/en/technologies/cloud-computing/openshift[Red Hat OpenShift] ** Red Hat Application Foundation From f7f4257520e055b34a965f900d402b8b8a73f68f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Thu, 9 Jan 2025 21:42:22 +0100 Subject: [PATCH 03/22] Arch --- .../modules/ROOT/pages/02-architecture.adoc | 60 ++++++++++++++----- 1 file changed, 45 insertions(+), 15 deletions(-) diff --git a/documentation/modules/ROOT/pages/02-architecture.adoc b/documentation/modules/ROOT/pages/02-architecture.adoc index b4c70e1..5dca202 100644 --- a/documentation/modules/ROOT/pages/02-architecture.adoc +++ b/documentation/modules/ROOT/pages/02-architecture.adoc @@ -5,34 +5,64 @@ = Architecture -Introduction for the architecture of this solution pattern. +The architecture of an event mesh-enabled system is a paradigm shift from +traditional transactional designs to an eventual consistency model. This design +aligns better with real-world processes, where different parts of a system may +operate asynchronously yet collaboratively. In this section, we explore the +technologies, flow, and structure that make the event mesh architecture +resilient, scalable, and developer-friendly. + +The solution employs _Command Query Responsibility Segregation (CQRS)_ to +separate commands and queries. Commands are modeled as asynchronous events and +handled by the event mesh. Queries are synchronous operations safe to retry. [#tech_stack] == Technology Stack +Here's the list of technologies used in this solution and its examples: -The solution employs Command Query Responsibility Segregation (CQRS) to separate commands and queries: +* Red Hat supported products +** https://www.redhat.com/en/technologies/cloud-computing/openshift[Red Hat OpenShift] + — Orchestrate containerized applications. Based on https://kubernetes.io/[Kuberentes]. +** https://www.redhat.com/en/technologies/cloud-computing/openshift/serverless[Red Hat OpenShift Serverless] + — Provides the _Event Mesh_ and _Serverless_ capabilities. Based on https://knative.dev[Knative]. +** https://swc.saas.ibm.com/en-us/redhat-marketplace/products/red-hat-amq[Red Hat AMQ Streams] + — (Optional) Provides a persistence for _Event Mesh_, likely needed in production. Based on https://strimzi.io/[Strimzi]. +* Other open source technologies: +** https://cloudevents.io/[CloudEvents] — Provides a standard for event metadata +** Rust and https://access.redhat.com/products/quarkus[Quarkus] — Implementation examples. +** https://opentelemetry.io/[OpenTelemetry] — (Optional) Facilitates tracing for observability. -Commands are modeled as asynchronous events and handled by the event mesh. +[#in_depth] +== An in-depth look at the solution's architecture -Queries are synchronous operations safe to retry. +//// +Technical description including all or some of the following: architecture ired diagrams. In-depth details of the decisions made and solutions used. Description of each service and what it is used for. Description of any integration. +//// +=== Problem Analysis +Traditional transactional systems enforce strict consistency, which slows +applications and distorts business logic. In our example, Cabs app, must +account for a real-life events like exiting a cab, even if dependent systems +(e.g. invoicing) experience downtime. Throwing errors, while keeps the +consistency in already stored data, loses the new data from real life events. +This leads to a bad impression by the end-users, and distorts the actual +business process. -* Red Hat supported products -** https://www.redhat.com/en/technologies/cloud-computing/openshift[Red Hat OpenShift] -** Red Hat Application Foundation -*** https://access.redhat.com/products/quarkus[Quarkus] -*** https://www.redhat.com/en/technologies/cloud-computing/openshift/openshift-streams-for-apache-kafka[Kafka Streams] -* Other open source products: -** https://www.postgresql.org/[PostgreSQL database] -** https://helm.sh/[Helm] +=== Solution Breakdown +Split services into independently operating microservices with distinct responsibilities. -[#in_depth] -== An in-depth look at the solution's architecture +Utilize CQRS to separate commands (asynchronous state changes) from queries (synchronous, retry-safe reads). + +=== Event Mesh Flow + +Events like CompleteTransit are published as CloudEvents to a Knative broker. + +Triggers route events dynamically to the appropriate microservices. -Technical description including all or some of the following: architecture ir ed diagrams. In-depth details of the decisions made and solutions used. Description of each service and what it is used for. Description of any integration. +Services process events, update state, and emit new events for downstream consumers. === Using images From f9b6f36a2272d15517bfcca94a2665392b5a7a17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Thu, 16 Jan 2025 22:24:55 +0100 Subject: [PATCH 04/22] Architecture chapter --- .../modules/ROOT/pages/02-architecture.adoc | 195 +++++++++++------- 1 file changed, 115 insertions(+), 80 deletions(-) diff --git a/documentation/modules/ROOT/pages/02-architecture.adoc b/documentation/modules/ROOT/pages/02-architecture.adoc index 5dca202..48fea0e 100644 --- a/documentation/modules/ROOT/pages/02-architecture.adoc +++ b/documentation/modules/ROOT/pages/02-architecture.adoc @@ -36,105 +36,140 @@ Here's the list of technologies used in this solution and its examples: [#in_depth] == An in-depth look at the solution's architecture -//// -Technical description including all or some of the following: architecture ired diagrams. In-depth details of the decisions made and solutions used. Description of each service and what it is used for. Description of any integration. -//// +Building applications around the Event Mesh is a solution that can be applied +either to existing applications or to greenfield projects. The existing +applications can be divided by their domain boundaries. The divided parts might +become modules, or even external services. Those modules will issue commands, +directed towards the Event Mesh, which will be routed towards the configured +endpoints. === Problem Analysis -Traditional transactional systems enforce strict consistency, which slows -applications and distorts business logic. In our example, Cabs app, must -account for a real-life events like exiting a cab, even if dependent systems -(e.g. invoicing) experience downtime. Throwing errors, while keeps the -consistency in already stored data, loses the new data from real life events. -This leads to a bad impression by the end-users, and distorts the actual -business process. +Traditional transactional systems enforce strict consistency, which slows +applications and distorts business logic. In our illustrative Cabs app example, +we must accommodate real-world scenarios, such as exiting a cab, even when +dependent systems (e.g., invoicing) encounter disruptions. Disregarding errors, +which preserve the integrity of existing data, discards the newly generated data +from genuine events. This results in a negative user experience and distorts +the actual business process, leading to potential customer dissatisfaction. === Solution Breakdown -Split services into independently operating microservices with distinct responsibilities. - -Utilize CQRS to separate commands (asynchronous state changes) from queries (synchronous, retry-safe reads). +The concept of employing the Event Mesh as a central, reliable hub for dispatching +commands, as events, lies at the heart of this solution. This approach aligns +closely with the Command Query Responsibility Segregation (CQRS) pattern, which +distinctly categorizes commands and queries. Commands, in this context, are +modeled as asynchronous events, designed to undergo processing by the event mesh. +On the other hand, queries are synchronous operations, safe to retry, ensuring +no loss of data integrity due to transient errors. + +The primary responsibility of the Event Mesh is twofold: firstly, it persists +the incoming events, thereby maintaining a record of changes in the system's +state. Secondly, it routes these events to their respective endpoints, ensuring +that the appropriate microservices are notified and can subsequently update +their internal states based on the event data. + +The mesh's inherent resilience is further bolstered by its exponential backoff +strategy, which it employs when encountering operational failures. This mechanism +ensures that the system retries the operation until it succeeds, thus mitigating +the risk of data loss or system disruption due to transient issues. + +By integrating the Event Mesh into the system architecture, several architectural +benefits are achieved: + + * **Decomposition of the application into independently functioning services**: + This approach facilitates a division of labor, with each service handling + specific responsibilities. This not only enhances maintainability but also + fosters scalability, as services can be independently scaled based on their + demands. + + * **Correction of systemic issues**: + The Event Mesh's error-handling mechanism, through retries and event + persistence, aids in minimizing the impact of failures on the end user. + This is crucial as it prevents bugs and outages from becoming visible to + the user, thereby preserving the system's perceived responsiveness. + + * **Enhanced system performance**: + The system becomes more responsive, as the end user no longer needs to + wait for multiple, often independent, operations to complete successfully. + The Event Mesh's event-driven model, coupled with the retries and event + persistence, ensures that critical state changes are propagated swiftly and + reliably, thereby improving the overall user experience. === Event Mesh Flow -Events like CompleteTransit are published as CloudEvents to a Knative broker. - -Triggers route events dynamically to the appropriate microservices. - -Services process events, update state, and emit new events for downstream consumers. - -=== Using images - -image::red_hat_open-hybrid-cloud.png[width=30%] - -{empty} - -=== Embedding HTML + * Events are published as CloudEvents to a Knative's Event Mesh. + * Triggers route events dynamically to the appropriate endpoints. + * Services process events, update state, and emit new events for downstream + consumers. -++++ -
-

Embed HTML by surrounding it with with four +s before and after.

- View the ascii doc to learn more -
-++++ +image::https://www.plantuml.com/plantuml/svg/VP1DJiCm58JtFiMZ-rmWYwgqeHkeX2WNUBK7Ok4ubdyYzVQuZKbe5TZ5olTcFiqcHFOnTKOyn1OTIC8d0xPLdwBH5iBb_rfgnpRIwWMVBC_qwDoAED3ul4MUBKSzW9u6vES1eRsYMzz_mT-YZS-W3tJeLUwyOdlW23zeYJkK8vyuZ52p5O9bRk687uTYLgrB4zNqcav6XvPsR6GocTsZQ8d2L1aV3slQzVP3-uuKpCNgB1JkEwQpzI_FcjxoL5XgcUvdMioVL4soi-iuIOQcE5N259RYPgKYMNJ-3lfdkMPRqp7s7lJkjQFBvWihR61Lwimt[width=100%] +//// +Online editor: +https://www.plantuml.com/plantuml/uml/VP1DJiCm58JtFiMZ-rmWYwgqeHkeX2WNUBK7Ok4ubdyYzVQuZKbe5TZ5olTcFiqcHFOnTKOyn1OTIC8d0xPLdwBH5iBb_rfgnpRIwWMVBC_qwDoAED3ul4MUBKSzW9u6vES1eRsYMzz_mT-YZS-W3tJeLUwyOdlW23zeYJkK8vyuZ52p5O9bRk687uTYLgrB4zNqcav6XvPsR6GocTsZQ8d2L1aV3slQzVP3-uuKpCNgB1JkEwQpzI_FcjxoL5XgcUvdMioVL4soi-iuIOQcE5N259RYPgKYMNJ-3lfdkMPRqp7s7lJkjQFBvWihR61Lwimt + +@startuml +!theme cerulean-outline +participant "Legacy App" as Legacy +participant "Knative Event Mesh" as Broker +participant "Drivers Module" as FeeService +participant "Database" as DB + +activate Legacy +Legacy -> Broker : Publish CalculateFee Event +Broker --> Legacy: Confirm delivery +deactivate Legacy + +Broker -> FeeService: Route CalculateFee Event +activate FeeService +FeeService --> Broker: Publish DriverFeeCalculated Event +deactivate FeeService + +Broker -> Legacy: Route DriverFeeCalculated Event +activate Legacy +Legacy -> DB: Store Trip Data +deactivate Legacy +@enduml +//// -=== Different decorators - -[TIP] -==== -This is a Tip -==== - -[NOTE] -==== -This is a NOTE -==== - -[WARNING] -==== -This is a WARNING -==== - -[IMPORTANT] -==== -This is IMPORTANT -==== - +The diagram illustrates the flow of events between the legacy application, the Knative Event Mesh, the fee calculator service, and the datastore. -=== Creating tables - -[cols="1a,1a,1a"] -|=== -| *Column A* | Column *A* | _Column C_ -| -* Lorem Ipsum -* Lorem Ipsum +=== Supporting Legacy Systems -| -* Lorem Ipsum -* Lorem Ipsum +One of the strengths of an event mesh architecture is its ability to integrate seamlessly with legacy systems, making them more resilient and adaptable. Legacy applications can be retrofitted to produce and consume events through lightweight adapters. For instance: -| -* Lorem Ipsum -* Lorem Ipsum -|=== + * A monolithic Java application can send events for specific operations, like CompleteTransit, instead of handling all logic internally. + * Event listeners can be introduced incrementally, enabling the legacy app to subscribe to events like DriverFeeCalculated without refactoring its core logic. + * This approach decouples old systems from rigid workflows, allowing for gradual modernization while ensuring operational continuity. +=== Improving Resilience in Traditional Applications -=== Content that can be copied +Traditional systems often rely on synchronous calls and transactions, which can cascade failures across components. Replacing these with asynchronous event-driven communication reduces dependencies. -Click below to copy the content -[.console-input] -[source,shell script] ----- -oc version #openshift cli client -oc login --token= --server= ----- +For example, invoicing and notification services in an e-commerce platform can process OrderPlaced events independently, ensuring that downtime in one service does not block the entire order workflow. +Retry mechanisms provided by the event mesh guarantee that transient failures are handled gracefully without data loss. [#more_tech] -== About the Technology Stack - -If you want to include more details about the tech stack you used, this is the place. \ No newline at end of file +== More about the Technology Stack + +It's worth noting that _Knative's Event Mesh_ is completely transparent to the +applications. The applications publish and consume events, usually via +_HTTP REST_, and the only thing that is required is the _CloudEvents_ format. + +The _CloudEvents_ format provides a common envelope for events with metadata +that every event needs, such as identifier, type, timestamps, or source +information. The format is a CNCF standard supported by a number of projects and +doesn't enforce the use of any library. + +This makes the investment in _Knative's Event Mesh_ safe in terms of vendor +lock-in. Architects can be assured that their options remain open and that +solutions can be easily reconfigured down the road. + +What's more, relying on well-known and easy-to-deploy _CloudEvents_, typically +over _HTTP_, makes testing simple and straightforward. Developers don't need +complex development environments because the _Event Mesh_ integration can be +easily tested with regular _REST_ send or receive tests that most developers +are familiar with. From 5c2c042f96a01beb2ae75d1c67ee71b9362c1e27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Fri, 17 Jan 2025 13:54:35 +0100 Subject: [PATCH 05/22] Reword the architecture chapter --- .../modules/ROOT/pages/02-architecture.adoc | 119 +++++++++--------- documentation/modules/ROOT/pages/03-demo.adoc | 32 +++++ 2 files changed, 95 insertions(+), 56 deletions(-) diff --git a/documentation/modules/ROOT/pages/02-architecture.adoc b/documentation/modules/ROOT/pages/02-architecture.adoc index 48fea0e..b37f7e9 100644 --- a/documentation/modules/ROOT/pages/02-architecture.adoc +++ b/documentation/modules/ROOT/pages/02-architecture.adoc @@ -12,10 +12,6 @@ operate asynchronously yet collaboratively. In this section, we explore the technologies, flow, and structure that make the event mesh architecture resilient, scalable, and developer-friendly. -The solution employs _Command Query Responsibility Segregation (CQRS)_ to -separate commands and queries. Commands are modeled as asynchronous events and -handled by the event mesh. Queries are synchronous operations safe to retry. - [#tech_stack] == Technology Stack @@ -36,34 +32,38 @@ Here's the list of technologies used in this solution and its examples: [#in_depth] == An in-depth look at the solution's architecture -Building applications around the Event Mesh is a solution that can be applied -either to existing applications or to greenfield projects. The existing -applications can be divided by their domain boundaries. The divided parts might -become modules, or even external services. Those modules will issue commands, -directed towards the Event Mesh, which will be routed towards the configured -endpoints. +Building applications around the Event Mesh is a solution that can be applied +both to existing and new projects. For existing applications, domain boundaries +can guide the division into modular components, which may evolve into separate +services. These modules will generate commands intended for the _Event Mesh_, +which will then route these events to their designated endpoints. The _Event +Mesh_ will allow for such transition, gradually making the system not only more +responsive but also better suited to the real-world business logic. === Problem Analysis -Traditional transactional systems enforce strict consistency, which slows -applications and distorts business logic. In our illustrative Cabs app example, -we must accommodate real-world scenarios, such as exiting a cab, even when -dependent systems (e.g., invoicing) encounter disruptions. Disregarding errors, -which preserve the integrity of existing data, discards the newly generated data -from genuine events. This results in a negative user experience and distorts -the actual business process, leading to potential customer dissatisfaction. +Traditional systems often enforce strict transactional consistency, +which can impede application performance and compromise business logic. +For instance, upon the completion of a ride-sharing service at the end-user's +destination, the system should reliably capture this real-world event, irrespective +of any potential operational disruptions affecting dependent services (e.g., +invoicing). + +In such scenarios, transactional applications typically return an error, resulting +in an adverse user experience and a deviation from the genuine business process, +potentially leading to customer dissatisfaction. === Solution Breakdown -The concept of employing the Event Mesh as a central, reliable hub for dispatching -commands, as events, lies at the heart of this solution. This approach aligns -closely with the Command Query Responsibility Segregation (CQRS) pattern, which -distinctly categorizes commands and queries. Commands, in this context, are -modeled as asynchronous events, designed to undergo processing by the event mesh. -On the other hand, queries are synchronous operations, safe to retry, ensuring +The concept of employing the _Event Mesh_ as a central, reliable hub for +dispatching commands, as events, lies at the heart of this solution. This +approach aligns closely with the Command Query Responsibility Segregation +(_CQRS_) pattern, which distinctly categorizes commands and queries. Commands, +in this context, are modeled as asynchronous events, designed to undergo +processing by the _Event Mesh_. On the other hand, queries are synchronous operations, safe to retry, ensuring no loss of data integrity due to transient errors. -The primary responsibility of the Event Mesh is twofold: firstly, it persists +The primary responsibility of the _Event Mesh_ is twofold: firstly, it persists the incoming events, thereby maintaining a record of changes in the system's state. Secondly, it routes these events to their respective endpoints, ensuring that the appropriate microservices are notified and can subsequently update @@ -74,7 +74,7 @@ strategy, which it employs when encountering operational failures. This mechanis ensures that the system retries the operation until it succeeds, thus mitigating the risk of data loss or system disruption due to transient issues. -By integrating the Event Mesh into the system architecture, several architectural +By integrating the _Event Mesh_ into the system architecture, several architectural benefits are achieved: * **Decomposition of the application into independently functioning services**: @@ -84,7 +84,7 @@ benefits are achieved: demands. * **Correction of systemic issues**: - The Event Mesh's error-handling mechanism, through retries and event + The _Event Mesh_'s error-handling mechanism, through retries and event persistence, aids in minimizing the impact of failures on the end user. This is crucial as it prevents bugs and outages from becoming visible to the user, thereby preserving the system's perceived responsiveness. @@ -92,52 +92,59 @@ benefits are achieved: * **Enhanced system performance**: The system becomes more responsive, as the end user no longer needs to wait for multiple, often independent, operations to complete successfully. - The Event Mesh's event-driven model, coupled with the retries and event + The _Event Mesh_'s event-driven model, coupled with the retries and event persistence, ensures that critical state changes are propagated swiftly and reliably, thereby improving the overall user experience. -=== Event Mesh Flow +=== _Event Mesh_ Flow - * Events are published as CloudEvents to a Knative's Event Mesh. + * Events are published as _Cloud Events_ to a _Knative_'s _Event Mesh_. * Triggers route events dynamically to the appropriate endpoints. * Services process events, update state, and emit new events for downstream consumers. -image::https://www.plantuml.com/plantuml/svg/VP1DJiCm58JtFiMZ-rmWYwgqeHkeX2WNUBK7Ok4ubdyYzVQuZKbe5TZ5olTcFiqcHFOnTKOyn1OTIC8d0xPLdwBH5iBb_rfgnpRIwWMVBC_qwDoAED3ul4MUBKSzW9u6vES1eRsYMzz_mT-YZS-W3tJeLUwyOdlW23zeYJkK8vyuZ52p5O9bRk687uTYLgrB4zNqcav6XvPsR6GocTsZQ8d2L1aV3slQzVP3-uuKpCNgB1JkEwQpzI_FcjxoL5XgcUvdMioVL4soi-iuIOQcE5N259RYPgKYMNJ-3lfdkMPRqp7s7lJkjQFBvWihR61Lwimt[width=100%] +image::https://www.plantuml.com/plantuml/svg/XPBHhjGW48RlUOgnzzi7wCNcsDGOeySOZG_0qkcMB8NA33MDyTsbb6CNNUCT_FF_tv0PdeYbvp0PyOf7d10coUYrFBd0HbiKTDDsbbvEi5rvdH5cPzPK4yguq4FrPa7By8mqLl1302WtpSvkMlNUIjOBGklT3Nq5al8nshu531WjShZ9L4adyLE8mPaUFLJFMda7X7xH2kalUESZsXDysGs9aRKiHNylMLuauM7lsdjdrvRGTtPnMcbxBR2xYe-mHo23i_TFy4V7Uj1AidQsODyNihuDuIxw0QzIhK0hCKxb68xgwtbEkFrQF34xkbt8Wsgt9hbowjrtUphdtJJmALoCfX5msoozk6glhoFNvvY51hxEiG6cBcBF7OQqIOWSzAI9NpZbSg0sE73zpwuPUehlAeCDV7Q1yO4lZ_w_ldBafVdnK-lpyM4QU8jCeEtWG5vY2lgz98h-ANNyXjyJomfuLCxt99xGzc4olm00[width=100%] //// -Online editor: -https://www.plantuml.com/plantuml/uml/VP1DJiCm58JtFiMZ-rmWYwgqeHkeX2WNUBK7Ok4ubdyYzVQuZKbe5TZ5olTcFiqcHFOnTKOyn1OTIC8d0xPLdwBH5iBb_rfgnpRIwWMVBC_qwDoAED3ul4MUBKSzW9u6vES1eRsYMzz_mT-YZS-W3tJeLUwyOdlW23zeYJkK8vyuZ52p5O9bRk687uTYLgrB4zNqcav6XvPsR6GocTsZQ8d2L1aV3slQzVP3-uuKpCNgB1JkEwQpzI_FcjxoL5XgcUvdMioVL4soi-iuIOQcE5N259RYPgKYMNJ-3lfdkMPRqp7s7lJkjQFBvWihR61Lwimt +Editor: https://www.plantuml.com/plantuml/uml/XPBHpfGm48Nl-nGZz_00N6nMWZ56rnYD3z0jmz9iQR7JOeZntIsK1f1D_hjsvZjdcZEzakFM-LwnTwx37g7d3gtakV5EIOsCdb8FtF8UvgkR1eJ1g6dfCQ6CRo3xCA9sS4FgClZ308Jf1wFdMlPPSoT7XCgQ9zeCEAt7WFtow34Wl7tofRESs5_6MgCQj93TfB062Eqe1TB9lBR1sXByYC3YiTRMKk0RxlYT4svuNUt9kZgQVjAZaKBgny4sLl6LxIQ8nedzt_YhSRAL8kHXzC5xtrZhSmWxwHTyS341JUImZp6Sk--7OR6Br_qJ4r77mXfKDGzPEtbZVklyikwcX6_-hYHrWFDcAL65bO_E5PUWXH9-3c40BbDOr6t0iaa8FcX9aai-n-L0eR2TwTTJasaUtdKKbl3TU8TdBaN_9dUEV8DVFxMuR1-cX8_e2AHk3V1xK44JMopDtrJRRqY9fGfO5COsnDWLTUDxzGy0 @startuml -!theme cerulean-outline -participant "Legacy App" as Legacy -participant "Knative Event Mesh" as Broker -participant "Drivers Module" as FeeService -participant "Database" as DB - -activate Legacy -Legacy -> Broker : Publish CalculateFee Event -Broker --> Legacy: Confirm delivery -deactivate Legacy - -Broker -> FeeService: Route CalculateFee Event -activate FeeService -FeeService --> Broker: Publish DriverFeeCalculated Event -deactivate FeeService - -Broker -> Legacy: Route DriverFeeCalculated Event -activate Legacy -Legacy -> DB: Store Trip Data -deactivate Legacy +!theme materia-outline +skinparam linetype polyline + +cloud "Event Mesh" { + component "Knative Broker" as Broker + queue "Kafka" as Kafka +} + +folder "Micro services" { + component "Drivers Service" as DriversService + database "Drivers DB" as DriversDB + component "Invoicing Service" as InvoiceService + database "Invoicing DB" as InvoiceDB + component "Notification Service" as NotificationService +} + +component "Legacy system" { + component "Legacy App" as Legacy + database "Legacy Database" as DB +} + +Legacy -down-> Broker: Publish events +Legacy .right.> DB : Update data +Broker .right.> Kafka : Persist events +DriversService .left.> Broker: Publish events +Broker --> DriversService: Route events +Broker --> InvoiceService: Route events +Broker --> NotificationService: Route events +DriversService ..> DriversDB: Gets info about drivers +InvoiceService ..> InvoiceDB: Update Invoice records @enduml //// -The diagram illustrates the flow of events between the legacy application, the Knative Event Mesh, the fee calculator service, and the datastore. - === Supporting Legacy Systems -One of the strengths of an event mesh architecture is its ability to integrate seamlessly with legacy systems, making them more resilient and adaptable. Legacy applications can be retrofitted to produce and consume events through lightweight adapters. For instance: +One of the strengths of an _Event Mesh_ architecture is its ability to integrate seamlessly with legacy systems, making them more resilient and adaptable. Legacy applications can be retrofitted to produce and consume events through lightweight adapters. For instance: * A monolithic Java application can send events for specific operations, like CompleteTransit, instead of handling all logic internally. * Event listeners can be introduced incrementally, enabling the legacy app to subscribe to events like DriverFeeCalculated without refactoring its core logic. @@ -150,7 +157,7 @@ Traditional systems often rely on synchronous calls and transactions, which can For example, invoicing and notification services in an e-commerce platform can process OrderPlaced events independently, ensuring that downtime in one service does not block the entire order workflow. -Retry mechanisms provided by the event mesh guarantee that transient failures are handled gracefully without data loss. +Retry mechanisms provided by the _Event Mesh_ guarantee that transient failures are handled gracefully without data loss. [#more_tech] == More about the Technology Stack diff --git a/documentation/modules/ROOT/pages/03-demo.adoc b/documentation/modules/ROOT/pages/03-demo.adoc index 2a335cb..d97c195 100644 --- a/documentation/modules/ROOT/pages/03-demo.adoc +++ b/documentation/modules/ROOT/pages/03-demo.adoc @@ -9,6 +9,38 @@ Include here content related to potential existing demos: blogs, articles, recorded videos, walkthrough guides, tutorials. +image::https://www.plantuml.com/plantuml/svg/VP1DJiCm58JtFiMZ-rmWYwgqeHkeX2WNUBK7Ok4ubdyYzVQuZKbe5TZ5olTcFiqcHFOnTKOyn1OTIC8d0xPLdwBH5iBb_rfgnpRIwWMVBC_qwDoAED3ul4MUBKSzW9u6vES1eRsYMzz_mT-YZS-W3tJeLUwyOdlW23zeYJkK8vyuZ52p5O9bRk687uTYLgrB4zNqcav6XvPsR6GocTsZQ8d2L1aV3slQzVP3-uuKpCNgB1JkEwQpzI_FcjxoL5XgcUvdMioVL4soi-iuIOQcE5N259RYPgKYMNJ-3lfdkMPRqp7s7lJkjQFBvWihR61Lwimt[width=100%] + +//// +Online editor: +https://www.plantuml.com/plantuml/uml/VP1DJiCm58JtFiMZ-rmWYwgqeHkeX2WNUBK7Ok4ubdyYzVQuZKbe5TZ5olTcFiqcHFOnTKOyn1OTIC8d0xPLdwBH5iBb_rfgnpRIwWMVBC_qwDoAED3ul4MUBKSzW9u6vES1eRsYMzz_mT-YZS-W3tJeLUwyOdlW23zeYJkK8vyuZ52p5O9bRk687uTYLgrB4zNqcav6XvPsR6GocTsZQ8d2L1aV3slQzVP3-uuKpCNgB1JkEwQpzI_FcjxoL5XgcUvdMioVL4soi-iuIOQcE5N259RYPgKYMNJ-3lfdkMPRqp7s7lJkjQFBvWihR61Lwimt + +@startuml +!theme materia-outline +participant "Legacy App" as Legacy +participant "Knative _Event Mesh_" as Broker +participant "Drivers Module" as FeeService +participant "Database" as DB + +activate Legacy +Legacy -> Broker : Publish CalculateFee Event +Broker --> Legacy: Confirm delivery +deactivate Legacy + +Broker -> FeeService: Route CalculateFee Event +activate FeeService +FeeService --> Broker: Publish DriverFeeCalculated Event +deactivate FeeService + +Broker -> Legacy: Route DriverFeeCalculated Event +activate Legacy +Legacy -> DB: Store Trip Data +deactivate Legacy +@enduml +//// + +The diagram illustrates the flow of events between the legacy application, the Knative _Event Mesh_, the fee calculator service, and the datastore. + [#demo-video] === Watch a demonstration From 2a5ba67a9bdbc08781a7e9120c8ca3fd21d01f65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Mon, 20 Jan 2025 22:52:26 +0100 Subject: [PATCH 06/22] Reword the Event Mesh flow of the Architecture chapter --- .../modules/ROOT/pages/01-pattern.adoc | 2 +- .../modules/ROOT/pages/02-architecture.adoc | 57 +++++++++++++++---- 2 files changed, 46 insertions(+), 13 deletions(-) diff --git a/documentation/modules/ROOT/pages/01-pattern.adoc b/documentation/modules/ROOT/pages/01-pattern.adoc index 793724f..1474baa 100644 --- a/documentation/modules/ROOT/pages/01-pattern.adoc +++ b/documentation/modules/ROOT/pages/01-pattern.adoc @@ -4,7 +4,7 @@ Cabs is a fictional transportation company. Engineers at Cabs were struggling with their transactional-style, monolith application. They recently started an effort to modernize it. -The team saw a recent https://www.youtube.com/watch?v=Rc5IO6S6ZOk[talk on _Event Mesh_]. +The team saw a https://www.youtube.com/watch?v=Rc5IO6S6ZOk[talk on _Event Mesh_]. The talk presented the advantages of moving beyond transactional architectures in favor of eventual consistency. By leveraging event meshes with technologies like Knative, developers can achieve decoupled, reliable microservices without diff --git a/documentation/modules/ROOT/pages/02-architecture.adoc b/documentation/modules/ROOT/pages/02-architecture.adoc index b37f7e9..8fa31cc 100644 --- a/documentation/modules/ROOT/pages/02-architecture.adoc +++ b/documentation/modules/ROOT/pages/02-architecture.adoc @@ -21,9 +21,9 @@ Here's the list of technologies used in this solution and its examples: ** https://www.redhat.com/en/technologies/cloud-computing/openshift[Red Hat OpenShift] — Orchestrate containerized applications. Based on https://kubernetes.io/[Kuberentes]. ** https://www.redhat.com/en/technologies/cloud-computing/openshift/serverless[Red Hat OpenShift Serverless] - — Provides the _Event Mesh_ and _Serverless_ capabilities. Based on https://knative.dev[Knative]. + — Provides the _Event Mesh_ and _Serverless_ capabilities. Based on https://knative.dev[Knative] project. ** https://swc.saas.ibm.com/en-us/redhat-marketplace/products/red-hat-amq[Red Hat AMQ Streams] - — (Optional) Provides a persistence for _Event Mesh_, likely needed in production. Based on https://strimzi.io/[Strimzi]. + — (Optional) Provides a persistence for _Event Mesh_, likely needed in production. Based on https://strimzi.io/[Strimzi] project. * Other open source technologies: ** https://cloudevents.io/[CloudEvents] — Provides a standard for event metadata ** Rust and https://access.redhat.com/products/quarkus[Quarkus] — Implementation examples. @@ -49,9 +49,10 @@ destination, the system should reliably capture this real-world event, irrespect of any potential operational disruptions affecting dependent services (e.g., invoicing). -In such scenarios, transactional applications typically return an error, resulting -in an adverse user experience and a deviation from the genuine business process, -potentially leading to customer dissatisfaction. +In such scenarios, transactional applications typically return an error, which +prevents any data from being changed, and causes the loss of real-world intent +of end-users. This results in an adverse user experience and a deviation from +the genuine business process, potentially leading to customer dissatisfaction. === Solution Breakdown @@ -60,10 +61,11 @@ dispatching commands, as events, lies at the heart of this solution. This approach aligns closely with the Command Query Responsibility Segregation (_CQRS_) pattern, which distinctly categorizes commands and queries. Commands, in this context, are modeled as asynchronous events, designed to undergo -processing by the _Event Mesh_. On the other hand, queries are synchronous operations, safe to retry, ensuring -no loss of data integrity due to transient errors. +processing by the _Event Mesh_. On the other hand, queries are synchronous +operations, safe to retry, ensuring no loss of data integrity due to transient +errors. -The primary responsibility of the _Event Mesh_ is twofold: firstly, it persists +The primary responsibility of the _Event Mesh_ is twofold. Firstly, it persists the incoming events, thereby maintaining a record of changes in the system's state. Secondly, it routes these events to their respective endpoints, ensuring that the appropriate microservices are notified and can subsequently update @@ -96,12 +98,39 @@ benefits are achieved: persistence, ensures that critical state changes are propagated swiftly and reliably, thereby improving the overall user experience. + * **Improved business alignment**: + By embracing an eventual consistency model, the _Event Mesh_ aligns + closely with the inherent nature of most real-world business processes. + Unlike traditional transactional systems that strive for immediate, + irreversible consistency, the _Event Mesh_ allows for a more flexible and + adaptive approach to data consistency. This results in better alignment with + business requirements, as it supports scenarios where multiple services + collaborate and synchronize their operations, making the whole state + eventually consistent, without the constraint of strict, synchronous + consistency. + === _Event Mesh_ Flow - * Events are published as _Cloud Events_ to a _Knative_'s _Event Mesh_. - * Triggers route events dynamically to the appropriate endpoints. - * Services process events, update state, and emit new events for downstream - consumers. +The event-driven flow enables eventual consistent collaboration and state +synchronization between services, fostering a resilient, scalable, and +developer-friendly system architecture. + +A usual flow may look like: + +1. An end-user application sends a request, which forms a _Command_ event + in the end transferred to the _Event Mesh_. +2. The _Event Mesh_ (Broker) persists the event in Kafka (Kafka). After successful + persistence _Event Mesh_ returns the success information, and at this point + the operation could already be considered successful, from the end-user point + of view. +3. The _Event Mesh_ routes the event to the appropriate endpoint based on the + event's metadata and configured rules. +4. The receiving service receive the event and process it, updating their + internal states and potentially emitting new events for downstream consumers. + The potential events are transmitted to the _Event Mesh_. +5. The dispatch loop continues until the event queue is empty and all the events + are processed successfully. The failures are being automatically retried by + the _Event Mesh_ using exponential backoff algorithm. image::https://www.plantuml.com/plantuml/svg/XPBHhjGW48RlUOgnzzi7wCNcsDGOeySOZG_0qkcMB8NA33MDyTsbb6CNNUCT_FF_tv0PdeYbvp0PyOf7d10coUYrFBd0HbiKTDDsbbvEi5rvdH5cPzPK4yguq4FrPa7By8mqLl1302WtpSvkMlNUIjOBGklT3Nq5al8nshu531WjShZ9L4adyLE8mPaUFLJFMda7X7xH2kalUESZsXDysGs9aRKiHNylMLuauM7lsdjdrvRGTtPnMcbxBR2xYe-mHo23i_TFy4V7Uj1AidQsODyNihuDuIxw0QzIhK0hCKxb68xgwtbEkFrQF34xkbt8Wsgt9hbowjrtUphdtJJmALoCfX5msoozk6glhoFNvvY51hxEiG6cBcBF7OQqIOWSzAI9NpZbSg0sE73zpwuPUehlAeCDV7Q1yO4lZ_w_ldBafVdnK-lpyM4QU8jCeEtWG5vY2lgz98h-ANNyXjyJomfuLCxt99xGzc4olm00[width=100%] @@ -142,6 +171,10 @@ InvoiceService ..> InvoiceDB: Update Invoice records @enduml //// +The diagram illustrates the example flow of events between the applications, +the Knative _Event Mesh_, and the datastores which persist settled state of the +system. + === Supporting Legacy Systems One of the strengths of an _Event Mesh_ architecture is its ability to integrate seamlessly with legacy systems, making them more resilient and adaptable. Legacy applications can be retrofitted to produce and consume events through lightweight adapters. For instance: From 3e83a6eb4518d76ea49271fe2ad9c16a9a173e51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Wed, 22 Jan 2025 13:38:58 +0100 Subject: [PATCH 07/22] Differences with Event Sourcing and Service Mesh --- .../modules/ROOT/pages/01-pattern.adoc | 40 ++- .../modules/ROOT/pages/02-architecture.adoc | 266 ++++++++++-------- 2 files changed, 166 insertions(+), 140 deletions(-) diff --git a/documentation/modules/ROOT/pages/01-pattern.adoc b/documentation/modules/ROOT/pages/01-pattern.adoc index 1474baa..bfb24a0 100644 --- a/documentation/modules/ROOT/pages/01-pattern.adoc +++ b/documentation/modules/ROOT/pages/01-pattern.adoc @@ -1,32 +1,28 @@ == The story behind this solution pattern -Cabs is a fictional transportation company. Engineers at Cabs were struggling -with their transactional-style, monolith application. They recently -started an effort to modernize it. +Cabs is a fictional transportation company. +Engineers at Cabs were struggling with their transactional-style, monolith application. +They recently started an effort to modernize it. The team saw a https://www.youtube.com/watch?v=Rc5IO6S6ZOk[talk on _Event Mesh_]. -The talk presented the advantages of moving beyond transactional architectures -in favor of eventual consistency. By leveraging event meshes with technologies -like Knative, developers can achieve decoupled, reliable microservices without -extensive re-engineering. This solution addresses inefficiencies and aligns -distributed systems with real-world business processes. The team had figured -out they could leverage the _CQRS_ pattern together with _Knative's Event Mesh_ +The talk presented the advantages of moving beyond transactional architectures in favor of eventual consistency. +By leveraging event meshes with technologies like Knative, developers can achieve decoupled, reliable microservices without extensive re-engineering. +This solution addresses inefficiencies and aligns distributed systems with real-world business processes. +The team had figured out they could leverage the _CQRS_ pattern together with _Knative's Event Mesh_ to modernize their application in a non-extrusive way. == The Solution -The core of this solution is an event mesh—a dynamic, flexible layer that -routes, retries, and processes asynchronous events across distributed -components. Using _Knative Eventing_ and _CloudEvents_, this pattern enables: +The core of this solution is an event mesh—a dynamic, flexible layer that routes, retries, and processes asynchronous events across distributed components. +Using _Knative Eventing_ and _CloudEvents_, this pattern enables: - - *Reliable delivery* of events with retry mechanisms. - - Simplified *asynchronous workflows*. - - *Decoupling* of services to improve scalability, testability and resilience. +- *Reliable delivery* of events with retry mechanisms. +- Simplified *asynchronous workflows*. +- *Decoupling* of services to improve scalability, testability and resilience. -The approach of Cabs engineering team is to extract well-defined services, using -the _CQRS_ pattern to identify _Commands_ from _Queries_, and model the -_Commands_ as _Events_. Those events will be routed to the _Event Mesh_ with -regular _HTTP_ messages. The _CloudEvents_ library ensures the proper -serialization of the events to and from the _HTTP_ messages. The _Event Mesh_ -will handle not only the persistence of the events in-flight, but also all the -required logic of retry in case of endpoint failure. +The approach of Cabs engineering team is to extract well-defined services, using the _CQRS_ pattern to identify _Commands_ from _Queries_, and model the +_Commands_ as _Events_. +Those events will be routed to the _Event Mesh_ with regular _HTTP_ messages. +The _CloudEvents_ library ensures the proper serialization of the events to and from the _HTTP_ messages. +The _Event Mesh_ +will handle not only the persistence of the events in-flight, but also all the required logic of retry in case of endpoint failure. diff --git a/documentation/modules/ROOT/pages/02-architecture.adoc b/documentation/modules/ROOT/pages/02-architecture.adoc index 8fa31cc..c2daf93 100644 --- a/documentation/modules/ROOT/pages/02-architecture.adoc +++ b/documentation/modules/ROOT/pages/02-architecture.adoc @@ -5,12 +5,9 @@ = Architecture -The architecture of an event mesh-enabled system is a paradigm shift from -traditional transactional designs to an eventual consistency model. This design -aligns better with real-world processes, where different parts of a system may -operate asynchronously yet collaboratively. In this section, we explore the -technologies, flow, and structure that make the event mesh architecture -resilient, scalable, and developer-friendly. +The architecture of an event mesh-enabled system is a paradigm shift from traditional transactional designs to an eventual consistency model. +This design aligns better with real-world processes, where different parts of a system may operate asynchronously yet collaboratively. +In this section, we explore the technologies, flow, and structure that make the event mesh architecture resilient, scalable, and developer-friendly. [#tech_stack] == Technology Stack @@ -19,11 +16,14 @@ Here's the list of technologies used in this solution and its examples: * Red Hat supported products ** https://www.redhat.com/en/technologies/cloud-computing/openshift[Red Hat OpenShift] - — Orchestrate containerized applications. Based on https://kubernetes.io/[Kuberentes]. +— Orchestrate containerized applications. +Based on https://kubernetes.io/[Kuberentes]. ** https://www.redhat.com/en/technologies/cloud-computing/openshift/serverless[Red Hat OpenShift Serverless] - — Provides the _Event Mesh_ and _Serverless_ capabilities. Based on https://knative.dev[Knative] project. +— Provides the _Event Mesh_ and _Serverless_ capabilities. +Based on https://knative.dev[Knative] project. ** https://swc.saas.ibm.com/en-us/redhat-marketplace/products/red-hat-amq[Red Hat AMQ Streams] - — (Optional) Provides a persistence for _Event Mesh_, likely needed in production. Based on https://strimzi.io/[Strimzi] project. +— (Optional) Provides a persistence for _Event Mesh_, likely needed in production. +Based on https://strimzi.io/[Strimzi] project. * Other open source technologies: ** https://cloudevents.io/[CloudEvents] — Provides a standard for event metadata ** Rust and https://access.redhat.com/products/quarkus[Quarkus] — Implementation examples. @@ -32,105 +32,69 @@ Here's the list of technologies used in this solution and its examples: [#in_depth] == An in-depth look at the solution's architecture -Building applications around the Event Mesh is a solution that can be applied -both to existing and new projects. For existing applications, domain boundaries -can guide the division into modular components, which may evolve into separate -services. These modules will generate commands intended for the _Event Mesh_, -which will then route these events to their designated endpoints. The _Event -Mesh_ will allow for such transition, gradually making the system not only more -responsive but also better suited to the real-world business logic. +Building applications around the Event Mesh is a solution that can be applied both to existing and new projects. +For existing applications, domain boundaries can guide the division into modular components, which may evolve into separate services. +These modules will generate commands intended for the _Event Mesh_, which will then route these events to their designated endpoints. +The _Event Mesh_ will allow for such transition, gradually making the system not only more responsive but also better suited to the real-world business logic. === Problem Analysis -Traditional systems often enforce strict transactional consistency, -which can impede application performance and compromise business logic. -For instance, upon the completion of a ride-sharing service at the end-user's -destination, the system should reliably capture this real-world event, irrespective -of any potential operational disruptions affecting dependent services (e.g., -invoicing). +Traditional systems often enforce strict transactional consistency, which can impede application performance and compromise business logic. +For instance, upon the completion of a ride-sharing service at the end-user's destination, the system should reliably capture this real-world event. +The capture should be performed regardless of any potential operational disruptions affecting dependent services (e.g., invoicing). -In such scenarios, transactional applications typically return an error, which -prevents any data from being changed, and causes the loss of real-world intent -of end-users. This results in an adverse user experience and a deviation from -the genuine business process, potentially leading to customer dissatisfaction. +In such scenarios, transactional applications typically return an error, which prevents any data from being changed, and causes the loss of real-world intent of end-users. +This results in an adverse user experience and a deviation from the genuine business process, potentially leading to customer dissatisfaction. === Solution Breakdown -The concept of employing the _Event Mesh_ as a central, reliable hub for -dispatching commands, as events, lies at the heart of this solution. This -approach aligns closely with the Command Query Responsibility Segregation -(_CQRS_) pattern, which distinctly categorizes commands and queries. Commands, -in this context, are modeled as asynchronous events, designed to undergo -processing by the _Event Mesh_. On the other hand, queries are synchronous -operations, safe to retry, ensuring no loss of data integrity due to transient -errors. - -The primary responsibility of the _Event Mesh_ is twofold. Firstly, it persists -the incoming events, thereby maintaining a record of changes in the system's -state. Secondly, it routes these events to their respective endpoints, ensuring -that the appropriate microservices are notified and can subsequently update -their internal states based on the event data. - -The mesh's inherent resilience is further bolstered by its exponential backoff -strategy, which it employs when encountering operational failures. This mechanism -ensures that the system retries the operation until it succeeds, thus mitigating -the risk of data loss or system disruption due to transient issues. - -By integrating the _Event Mesh_ into the system architecture, several architectural -benefits are achieved: - - * **Decomposition of the application into independently functioning services**: - This approach facilitates a division of labor, with each service handling - specific responsibilities. This not only enhances maintainability but also - fosters scalability, as services can be independently scaled based on their - demands. - - * **Correction of systemic issues**: - The _Event Mesh_'s error-handling mechanism, through retries and event - persistence, aids in minimizing the impact of failures on the end user. - This is crucial as it prevents bugs and outages from becoming visible to - the user, thereby preserving the system's perceived responsiveness. - - * **Enhanced system performance**: - The system becomes more responsive, as the end user no longer needs to - wait for multiple, often independent, operations to complete successfully. - The _Event Mesh_'s event-driven model, coupled with the retries and event - persistence, ensures that critical state changes are propagated swiftly and - reliably, thereby improving the overall user experience. - - * **Improved business alignment**: - By embracing an eventual consistency model, the _Event Mesh_ aligns - closely with the inherent nature of most real-world business processes. - Unlike traditional transactional systems that strive for immediate, - irreversible consistency, the _Event Mesh_ allows for a more flexible and - adaptive approach to data consistency. This results in better alignment with - business requirements, as it supports scenarios where multiple services - collaborate and synchronize their operations, making the whole state - eventually consistent, without the constraint of strict, synchronous - consistency. +The concept of employing the _Event Mesh_ as a central, reliable hub for dispatching commands, as events, lies at the heart of this solution. +This approach aligns closely with the Command Query Responsibility Segregation (_CQRS_) pattern, which distinctly categorizes commands and queries. +Commands, in this context, are modeled as asynchronous events, designed to undergo processing by the _Event Mesh_. +On the other hand, queries are synchronous operations, safe to retry, ensuring no loss of data integrity due to transient errors. + +The primary responsibility of the _Event Mesh_ is twofold. +Firstly, it persists the incoming events, thereby maintaining a record of changes in the system's state. +Secondly, it routes these events to their respective endpoints, ensuring that the appropriate microservices are notified and can subsequently update their internal states based on the event data. + +The mesh's inherent resilience is further bolstered by its exponential backoff strategy, which it employs when encountering operational failures. +This mechanism ensures that the system retries the operation until it succeeds, thus mitigating the risk of data loss or system disruption due to transient issues. + +By integrating the _Event Mesh_ into the system architecture, several architectural benefits are achieved: + +* **Decomposition of the application into independently functioning services**: +This approach facilitates a division of labor, with each service handling specific responsibilities. +This not only enhances maintainability but also fosters scalability, as services can be independently scaled based on their demands. + +* **Improved business alignment**: +By embracing an eventual consistency model, the _Event Mesh_ aligns closely with the inherent nature of most real-world business processes. +Unlike traditional transactional systems that strive for immediate, irreversible consistency, the _Event Mesh_ allows for a more flexible and adaptive approach to data consistency. +This results in better alignment with business requirements, as it supports scenarios where multiple services collaborate and synchronize their operations, making the whole state eventually consistent, without the constraint of strict, synchronous consistency. + +* **Avoidance of systemic issues**: +The _Event Mesh_'s error-handling mechanism, through retries and event persistence, aids in minimizing the impact of failures on the end user. +This is crucial as it prevents bugs and outages from becoming visible to the user, thereby preserving the system's perceived responsiveness. + +* **Enhanced system performance**: +The system becomes more responsive, as the end user no longer needs to wait for multiple, often independent, operations to complete successfully. +The _Event Mesh_'s event-driven model, coupled with the retries and event persistence, ensures that critical state changes are propagated swiftly and reliably, thereby improving the overall user experience. === _Event Mesh_ Flow -The event-driven flow enables eventual consistent collaboration and state -synchronization between services, fostering a resilient, scalable, and -developer-friendly system architecture. +The event-driven flow enables eventual consistent collaboration and state synchronization between services, fostering a resilient, scalable, and developer-friendly system architecture. A usual flow may look like: -1. An end-user application sends a request, which forms a _Command_ event - in the end transferred to the _Event Mesh_. -2. The _Event Mesh_ (Broker) persists the event in Kafka (Kafka). After successful - persistence _Event Mesh_ returns the success information, and at this point - the operation could already be considered successful, from the end-user point - of view. -3. The _Event Mesh_ routes the event to the appropriate endpoint based on the - event's metadata and configured rules. -4. The receiving service receive the event and process it, updating their - internal states and potentially emitting new events for downstream consumers. - The potential events are transmitted to the _Event Mesh_. -5. The dispatch loop continues until the event queue is empty and all the events - are processed successfully. The failures are being automatically retried by - the _Event Mesh_ using exponential backoff algorithm. +1. An end-user application sends a request, which forms a _Command_ type event, which is transferred to the _Event Mesh_. +2. The _Event Mesh_ (Broker) persists the event in a queue (e.g. Kafka). +After successful persistence _Event Mesh_ returns the success information. +At this point, the operation could already be considered successful, from the end-user point of view. +It will eventually settle correctly in all downstream systems. +3. The _Event Mesh_ routes the event to the appropriate endpoint based on the event's metadata and configured triggering rules. +4. The endpoints receive the events and process them, updating their internal states and potentially emitting new events for downstream consumers. +The potential events are transmitted to the _Event Mesh_. +5. The dispatch loop continues until the event queue is empty and all the events are processed successfully. +The failures are being automatically retried by the _Event Mesh_ using exponential backoff algorithm. image::https://www.plantuml.com/plantuml/svg/XPBHhjGW48RlUOgnzzi7wCNcsDGOeySOZG_0qkcMB8NA33MDyTsbb6CNNUCT_FF_tv0PdeYbvp0PyOf7d10coUYrFBd0HbiKTDDsbbvEi5rvdH5cPzPK4yguq4FrPa7By8mqLl1302WtpSvkMlNUIjOBGklT3Nq5al8nshu531WjShZ9L4adyLE8mPaUFLJFMda7X7xH2kalUESZsXDysGs9aRKiHNylMLuauM7lsdjdrvRGTtPnMcbxBR2xYe-mHo23i_TFy4V7Uj1AidQsODyNihuDuIxw0QzIhK0hCKxb68xgwtbEkFrQF34xkbt8Wsgt9hbowjrtUphdtJJmALoCfX5msoozk6glhoFNvvY51hxEiG6cBcBF7OQqIOWSzAI9NpZbSg0sE73zpwuPUehlAeCDV7Q1yO4lZ_w_ldBafVdnK-lpyM4QU8jCeEtWG5vY2lgz98h-ANNyXjyJomfuLCxt99xGzc4olm00[width=100%] @@ -171,45 +135,111 @@ InvoiceService ..> InvoiceDB: Update Invoice records @enduml //// -The diagram illustrates the example flow of events between the applications, -the Knative _Event Mesh_, and the datastores which persist settled state of the -system. +The diagram illustrates the example flow of events between the applications, the Knative _Event Mesh_, and the datastores which persist settled state of the system. + +[NOTE] +==== +Notice the applications aren't pulling the events from the queue. +In fact they aren't aware of any. +The _Event Mesh_ is the one controlling the flow, and retrying when needed. + +There are *no additional* libraries needed to consume events from _Event Mesh_. +The _Event Mesh_ pushes the events as _CloudEvents_ encoded as _REST_ messages. +==== + +=== _Work Ledger_ analogy + +A good way of thinking about the _Event Mesh_ and its persistent queue backend is the _Work Ledger_ analogy. +Like in olden days, the clerk was keeping his to-do work in the _Work Ledger_ (e.g. a tray for paper forms). +Then he was picking the next form, and processing it, making changes within the physical file cabinets. +In case of rare and unexpected issues (e.g. Invoicing dept being unavailable), the clerk would just put the data back onto the _Work Ledger_ to be processed later. + +The _Event Mesh_ is processing the data in very similar fashion. +The data is held in the _Event Mesh_ only until the system successfully consumes it. + +=== Differences from the _Event Sourcing_ + +The _Event Mesh_ pattern could be mistaken for _Event Sourcing_, as both are Event-Driven approaches (_EDA_) to application architecture. +However, _Event Mesh_ has few improvements over the shortcomings of _Event Sourcing_ approach. + +The data is held in the _Event Mesh_ only until the system successfully consumes it, settling the data in various datastores to a consistent state. +This effectively avoids the need to keep the applications backward compatible with all the events ever emitted. +Introducing breaking changes in the event schema is as easy as making sure to consume all the events of given type from the _Event Mesh_. +This also works for the systems which can't have downtime windows. +The applications could have short-lived backward compatible layers for such situations. +When all the events are processed, the backward compatible code may be removed simplifying the maintenance. + +Because in the long-term, the regular datastores are the source of truth for the system, all traditional techniques for application maintenance apply well. +It is also, easier to understand for developers, as it avoids sophisticated event handlers logic, and reconciling into the read database abstraction. + +=== Differences from the _Service Mesh_ + +Worth pointing out are the differences from the _Service Mesh_ pattern. +The _Service Mesh_ pattern is intended to improve the resilience of synchronous communications which return the response. +The _Service Mesh_ effectively raises the uptime of the dependent endpoints by retrying and backoff policies. +The uptime can't be raised to 100%, though, so _Service Mesh_ still can lose the messages. + +The table below captures the key differences: + +[cols="^1,^2,^2"] +|=== +|| Service Mesh | Event Mesh + +| +*Similarities* + +2+| +* Flexibility +* Robustness +* Decoupling + +| +*Differences* +| +* Synchronous +* Request and Response +* Better for queries + +| +* Asynchronous +* Events +* Better for commands + +|=== === Supporting Legacy Systems -One of the strengths of an _Event Mesh_ architecture is its ability to integrate seamlessly with legacy systems, making them more resilient and adaptable. Legacy applications can be retrofitted to produce and consume events through lightweight adapters. For instance: +One of the strengths of an _Event Mesh_ architecture is its ability to integrate seamlessly with legacy systems, making them more resilient and adaptable. +Legacy applications can be retrofitted to produce and consume events through lightweight adapters. +For instance: + +* A monolithic legacy application can send events for specific operations, instead of handling all logic internally in transactional fashion. - * A monolithic Java application can send events for specific operations, like CompleteTransit, instead of handling all logic internally. - * Event listeners can be introduced incrementally, enabling the legacy app to subscribe to events like DriverFeeCalculated without refactoring its core logic. +* Event listeners can be introduced incrementally, enabling the legacy app to subscribe to events without refactoring its core logic. - * This approach decouples old systems from rigid workflows, allowing for gradual modernization while ensuring operational continuity. +* This approach decouples old systems from rigid workflows, allowing for gradual modernization while ensuring operational continuity. === Improving Resilience in Traditional Applications -Traditional systems often rely on synchronous calls and transactions, which can cascade failures across components. Replacing these with asynchronous event-driven communication reduces dependencies. +Traditional systems often rely on synchronous calls and transactions, which can cascade failures across components. +Replacing these with asynchronous event-driven communication reduces dependencies. -For example, invoicing and notification services in an e-commerce platform can process OrderPlaced events independently, ensuring that downtime in one service does not block the entire order workflow. +For example, invoicing and notification services in an e-commerce platform can process events independently, ensuring that downtime in one service does not block the entire workflow. Retry mechanisms provided by the _Event Mesh_ guarantee that transient failures are handled gracefully without data loss. [#more_tech] == More about the Technology Stack -It's worth noting that _Knative's Event Mesh_ is completely transparent to the -applications. The applications publish and consume events, usually via +It's worth noting that _Knative's Event Mesh_ is completely transparent to the applications. +The applications publish and consume events, usually via _HTTP REST_, and the only thing that is required is the _CloudEvents_ format. -The _CloudEvents_ format provides a common envelope for events with metadata -that every event needs, such as identifier, type, timestamps, or source -information. The format is a CNCF standard supported by a number of projects and -doesn't enforce the use of any library. +The _CloudEvents_ format provides a common envelope for events with metadata that every event needs, such as identifier, type, timestamps, or source information. +The format is a CNCF standard supported by a number of projects and doesn't enforce the use of any library. -This makes the investment in _Knative's Event Mesh_ safe in terms of vendor -lock-in. Architects can be assured that their options remain open and that -solutions can be easily reconfigured down the road. +This makes the investment in _Knative's Event Mesh_ safe in terms of vendor lock-in. +Architects can be assured that their options remain open and that solutions can be easily reconfigured down the road. -What's more, relying on well-known and easy-to-deploy _CloudEvents_, typically -over _HTTP_, makes testing simple and straightforward. Developers don't need -complex development environments because the _Event Mesh_ integration can be -easily tested with regular _REST_ send or receive tests that most developers -are familiar with. +What's more, relying on well-known and easy-to-deploy _CloudEvents_, typically over _HTTP_, makes testing simple and straightforward. +Developers don't need complex development environments because the _Event Mesh_ integration can be easily tested with regular _REST_ send or receive tests that most developers are familiar with. From aeabc6d32cab3fec20e97caaec4a56d04459a4ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Thu, 23 Jan 2025 13:58:10 +0100 Subject: [PATCH 08/22] Reformat table --- .../modules/ROOT/pages/02-architecture.adoc | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/documentation/modules/ROOT/pages/02-architecture.adoc b/documentation/modules/ROOT/pages/02-architecture.adoc index c2daf93..04ce2ca 100644 --- a/documentation/modules/ROOT/pages/02-architecture.adoc +++ b/documentation/modules/ROOT/pages/02-architecture.adoc @@ -181,26 +181,27 @@ The uptime can't be raised to 100%, though, so _Service Mesh_ still can lose the The table below captures the key differences: -[cols="^1,^2,^2"] +[cols=".^1,.^2,.^2"] |=== || Service Mesh | Event Mesh | *Similarities* -2+| +2+a| + * Flexibility * Robustness * Decoupling | *Differences* -| +a| * Synchronous -* Request and Response +* Request and response * Better for queries -| +a| * Asynchronous * Events * Better for commands @@ -219,10 +220,10 @@ For instance: * This approach decouples old systems from rigid workflows, allowing for gradual modernization while ensuring operational continuity. -=== Improving Resilience in Traditional Applications +=== Improving Resilience in Applications Traditional systems often rely on synchronous calls and transactions, which can cascade failures across components. -Replacing these with asynchronous event-driven communication reduces dependencies. +Replacing these with asynchronous event-driven communication reduces dependencies and makes the system _Eventually Consistent_. For example, invoicing and notification services in an e-commerce platform can process events independently, ensuring that downtime in one service does not block the entire workflow. From e4a7720add922b45a0594914d7f36b8340b7192c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Thu, 23 Jan 2025 18:40:17 +0100 Subject: [PATCH 09/22] Polishing the nitpicks from the review --- .../modules/ROOT/pages/02-architecture.adoc | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/documentation/modules/ROOT/pages/02-architecture.adoc b/documentation/modules/ROOT/pages/02-architecture.adoc index 04ce2ca..6e77f8b 100644 --- a/documentation/modules/ROOT/pages/02-architecture.adoc +++ b/documentation/modules/ROOT/pages/02-architecture.adoc @@ -7,6 +7,7 @@ The architecture of an event mesh-enabled system is a paradigm shift from traditional transactional designs to an eventual consistency model. This design aligns better with real-world processes, where different parts of a system may operate asynchronously yet collaboratively. + In this section, we explore the technologies, flow, and structure that make the event mesh architecture resilient, scalable, and developer-friendly. [#tech_stack] @@ -94,7 +95,7 @@ It will eventually settle correctly in all downstream systems. 4. The endpoints receive the events and process them, updating their internal states and potentially emitting new events for downstream consumers. The potential events are transmitted to the _Event Mesh_. 5. The dispatch loop continues until the event queue is empty and all the events are processed successfully. -The failures are being automatically retried by the _Event Mesh_ using exponential backoff algorithm. +The failures are being automatically retried by the _Event Mesh_ using exponential backoff algorithm by default. image::https://www.plantuml.com/plantuml/svg/XPBHhjGW48RlUOgnzzi7wCNcsDGOeySOZG_0qkcMB8NA33MDyTsbb6CNNUCT_FF_tv0PdeYbvp0PyOf7d10coUYrFBd0HbiKTDDsbbvEi5rvdH5cPzPK4yguq4FrPa7By8mqLl1302WtpSvkMlNUIjOBGklT3Nq5al8nshu531WjShZ9L4adyLE8mPaUFLJFMda7X7xH2kalUESZsXDysGs9aRKiHNylMLuauM7lsdjdrvRGTtPnMcbxBR2xYe-mHo23i_TFy4V7Uj1AidQsODyNihuDuIxw0QzIhK0hCKxb68xgwtbEkFrQF34xkbt8Wsgt9hbowjrtUphdtJJmALoCfX5msoozk6glhoFNvvY51hxEiG6cBcBF7OQqIOWSzAI9NpZbSg0sE73zpwuPUehlAeCDV7Q1yO4lZ_w_ldBafVdnK-lpyM4QU8jCeEtWG5vY2lgz98h-ANNyXjyJomfuLCxt99xGzc4olm00[width=100%] @@ -137,7 +138,7 @@ InvoiceService ..> InvoiceDB: Update Invoice records The diagram illustrates the example flow of events between the applications, the Knative _Event Mesh_, and the datastores which persist settled state of the system. -[NOTE] +[TIP] ==== Notice the applications aren't pulling the events from the queue. In fact they aren't aware of any. @@ -147,6 +148,14 @@ There are *no additional* libraries needed to consume events from _Event Mesh_. The _Event Mesh_ pushes the events as _CloudEvents_ encoded as _REST_ messages. ==== +[NOTE] +==== +The exponential backoff algorithm used by _Event Mesh_ is configurable. +It uses the following formula to calculate the backoff period: `+backoffDelay * 2^+`, where the backoff delay is a base number of seconds, and number of retries is automatically tracked by the _Event Mesh_. + +A dead letter sink can also be configured to send events in case they exceed the maximum retry number, which is also configurable. +==== + === _Work Ledger_ analogy A good way of thinking about the _Event Mesh_ and its persistent queue backend is the _Work Ledger_ analogy. @@ -225,7 +234,7 @@ For instance: Traditional systems often rely on synchronous calls and transactions, which can cascade failures across components. Replacing these with asynchronous event-driven communication reduces dependencies and makes the system _Eventually Consistent_. -For example, invoicing and notification services in an e-commerce platform can process events independently, ensuring that downtime in one service does not block the entire workflow. +For example, invoicing and notification services in a ride-sharing platform can process events independently, ensuring that downtime in one service does not block the entire workflow. Retry mechanisms provided by the _Event Mesh_ guarantee that transient failures are handled gracefully without data loss. @@ -237,10 +246,10 @@ The applications publish and consume events, usually via _HTTP REST_, and the only thing that is required is the _CloudEvents_ format. The _CloudEvents_ format provides a common envelope for events with metadata that every event needs, such as identifier, type, timestamps, or source information. -The format is a CNCF standard supported by a number of projects and doesn't enforce the use of any library. +The format is a _CNCF_ standard supported by a number of projects and doesn't enforce the use of any library. This makes the investment in _Knative's Event Mesh_ safe in terms of vendor lock-in. Architects can be assured that their options remain open and that solutions can be easily reconfigured down the road. What's more, relying on well-known and easy-to-deploy _CloudEvents_, typically over _HTTP_, makes testing simple and straightforward. -Developers don't need complex development environments because the _Event Mesh_ integration can be easily tested with regular _REST_ send or receive tests that most developers are familiar with. +Developers don't need complex development environments because the _Event Mesh_ integration can be easily tested with regular _REST_ testing that most developers are familiar with. From 360f9fba952a7ffedb455b73e5fe6cafc00460a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Fri, 24 Jan 2025 17:17:30 +0100 Subject: [PATCH 10/22] Begin with the demo --- documentation/modules/ROOT/nav.adoc | 5 +- .../modules/ROOT/pages/02-architecture.adoc | 8 +-- documentation/modules/ROOT/pages/03-demo.adoc | 66 +++++++++++++++++-- 3 files changed, 65 insertions(+), 14 deletions(-) diff --git a/documentation/modules/ROOT/nav.adoc b/documentation/modules/ROOT/nav.adoc index 436ff5a..103ce16 100644 --- a/documentation/modules/ROOT/nav.adoc +++ b/documentation/modules/ROOT/nav.adoc @@ -9,11 +9,8 @@ ** xref:02-architecture.adoc#more_tech[{module}.{counter:submodule2}. More about the technology stack] * xref:03-demo.adoc[{counter:module}. See the Solution in Action] -** xref:03-demo.adoc#_demonstration[{module}.{counter:submodule3}. Demonstration] +** xref:03-demo.adoc#_initial_application[{module}.{counter:submodule3}. Initial application] ** xref:03-demo.adoc#_run_the_demonstration[{module}.{counter:submodule3}. Run this demonstration] -*** xref:03-demo.adoc#_before_getting_started[{module}.{counter:submodule3}. Pre-requisites] -*** xref:03-demo.adoc#_installing_the_demo[{module}.{counter:submodule3}. Installing the demo] -*** xref:03-demo.adoc#_walkthrough_guide[{module}.{counter:submodule3}. Walkthrough guide] * xref:04-workshop.adoc[{counter:module}. Workshop] ** xref:04-workshop.adoc#_installing_the_workshop_environment[{module}.{counter:submodule4}. Installing the workshop environment] diff --git a/documentation/modules/ROOT/pages/02-architecture.adoc b/documentation/modules/ROOT/pages/02-architecture.adoc index 6e77f8b..b35590b 100644 --- a/documentation/modules/ROOT/pages/02-architecture.adoc +++ b/documentation/modules/ROOT/pages/02-architecture.adoc @@ -97,13 +97,13 @@ The potential events are transmitted to the _Event Mesh_. 5. The dispatch loop continues until the event queue is empty and all the events are processed successfully. The failures are being automatically retried by the _Event Mesh_ using exponential backoff algorithm by default. -image::https://www.plantuml.com/plantuml/svg/XPBHhjGW48RlUOgnzzi7wCNcsDGOeySOZG_0qkcMB8NA33MDyTsbb6CNNUCT_FF_tv0PdeYbvp0PyOf7d10coUYrFBd0HbiKTDDsbbvEi5rvdH5cPzPK4yguq4FrPa7By8mqLl1302WtpSvkMlNUIjOBGklT3Nq5al8nshu531WjShZ9L4adyLE8mPaUFLJFMda7X7xH2kalUESZsXDysGs9aRKiHNylMLuauM7lsdjdrvRGTtPnMcbxBR2xYe-mHo23i_TFy4V7Uj1AidQsODyNihuDuIxw0QzIhK0hCKxb68xgwtbEkFrQF34xkbt8Wsgt9hbowjrtUphdtJJmALoCfX5msoozk6glhoFNvvY51hxEiG6cBcBF7OQqIOWSzAI9NpZbSg0sE73zpwuPUehlAeCDV7Q1yO4lZ_w_ldBafVdnK-lpyM4QU8jCeEtWG5vY2lgz98h-ANNyXjyJomfuLCxt99xGzc4olm00[width=100%] +image::https://img.plantuml.biz/plantuml/svg/TPFDReGW483lFCNKkpw0XytMRDCqxJQRDdq05iULB885j35Dtxs8k2xxSuEPRpvm1jV6KcsxHf07MsE3m51t0gbCLMS5bqZCaSkMQjh0kBL3Yz0gCVWSOK9r9IHFFKeBMpHr0hy4WAccLNAC9Q-IMjuZ55eTKIT0JLWwxBl33Xr2goFr6RyYVuHKIfIe8TbofXKOr3rdQAxa6-tKsi3d17X7Y8MGuqjgwPuQNF1DSKvkYbZw8dl56PU7I3j5yPPsAGZYm5wAtvNb5MUk7qf6xlF4V81hmbdf6nue6y0Cnc9prOQGVMnRhvksqHK3CNzuCUf3B2tLZqnNOIevxBgzuAO676TgPYhJ_53RRELg8OUlrgdH-ybKjm1-XexPkTPoOsTFF1R815OZVUVK84tTlUB273xSmyGRN3oW-zoDPb_0brVDLijJoU4PhG4kAmLqxwgWd58aFjzNdTx1gMCX0XgPqgKXQvIb-_d-0G00[width=100%] //// -Editor: https://www.plantuml.com/plantuml/uml/XPBHpfGm48Nl-nGZz_00N6nMWZ56rnYD3z0jmz9iQR7JOeZntIsK1f1D_hjsvZjdcZEzakFM-LwnTwx37g7d3gtakV5EIOsCdb8FtF8UvgkR1eJ1g6dfCQ6CRo3xCA9sS4FgClZ308Jf1wFdMlPPSoT7XCgQ9zeCEAt7WFtow34Wl7tofRESs5_6MgCQj93TfB062Eqe1TB9lBR1sXByYC3YiTRMKk0RxlYT4svuNUt9kZgQVjAZaKBgny4sLl6LxIQ8nedzt_YhSRAL8kHXzC5xtrZhSmWxwHTyS341JUImZp6Sk--7OR6Br_qJ4r77mXfKDGzPEtbZVklyikwcX6_-hYHrWFDcAL65bO_E5PUWXH9-3c40BbDOr6t0iaa8FcX9aai-n-L0eR2TwTTJasaUtdKKbl3TU8TdBaN_9dUEV8DVFxMuR1-cX8_e2AHk3V1xK44JMopDtrJRRqY9fGfO5COsnDWLTUDxzGy0 +Editor: https://editor.plantuml.com/uml/TPFDReGW483lFCNKkpw0XytMRDCqxJQRDdq05iULB885j35Dtxs8k2xxSuEPRpvm1jV6KcsxHf07MsE3m51t0gbCLMS5bqZCaSkMQjh0kBL3Yz0gCVWSOK9r9IHFFKeBMpHr0hy4WAccLNAC9Q-IMjuZ55eTKIT0JLWwxBl33Xr2goFr6RyYVuHKIfIe8TbofXKOr3rdQAxa6-tKsi3d17X7Y8MGuqjgwPuQNF1DSKvkYbZw8dl56PU7I3j5yPPsAGZYm5wAtvNb5MUk7qf6xlF4V81hmbdf6nue6y0Cnc9prOQGVMnRhvksqHK3CNzuCUf3B2tLZqnNOIevxBgzuAO676TgPYhJ_53RRELg8OUlrgdH-ybKjm1-XexPkTPoOsTFF1R815OZVUVK84tTlUB273xSmyGRN3oW-zoDPb_0brVDLijJoU4PhG4kAmLqxwgWd58aFjzNdTx1gMCX0XgPqgKXQvIb-_d-0G00 @startuml -!theme materia-outline +!theme cerulean-outline skinparam linetype polyline cloud "Event Mesh" { @@ -121,7 +121,7 @@ folder "Micro services" { component "Legacy system" { component "Legacy App" as Legacy - database "Legacy Database" as DB + database "Legacy DB" as DB } Legacy -down-> Broker: Publish events diff --git a/documentation/modules/ROOT/pages/03-demo.adoc b/documentation/modules/ROOT/pages/03-demo.adoc index d97c195..db1bed7 100644 --- a/documentation/modules/ROOT/pages/03-demo.adoc +++ b/documentation/modules/ROOT/pages/03-demo.adoc @@ -1,4 +1,4 @@ -= Solution Pattern: Name Template += Building Apps around the Event Mesh :sectnums: :sectlinks: :doctype: book @@ -7,6 +7,59 @@ == Demonstration +Let's take a look at the example. +We'll be looking at a Cabs ride-sharing application, that mimics real-world solutions of similar kind. +The application is written in a popular Java framework. + +=== Initial application + +Here's a method from the Cabs application that handles the completion of transit: + +[WARNING] +==== +The following example should be considered an anti-example! +==== + +[source,java] +---- +@Transactional // <1> +public void completeTransit(Long driverId, UUID requestUUID, Address destinationAddress) { + destinationAddress = addressRepository.save(destinationAddress); // <2> + TransitDetailsDTO transitDetails = transitDetailsFacade.find(requestUUID); + if (!driverService.exists(driverId)) { + throw new IllegalArgumentException("Driver does not exist, id = " + driverId); + } + Address from = addressRepository.getByHash(transitDetails.from.getHash()); + Address to = addressRepository.getByHash(destinationAddress.getHash()); + Money finalPrice = completeTransitService.completeTransit( + driverId, requestUUID, from, to); // <2> + Money driverFee = driverFeeService.calculateDriverFee( + finalPrice, driverId); + driverService.markNotOccupied(driverId); // <2> + transitDetailsFacade.transitCompleted(requestUUID, + Instant.now(clock), finalPrice, driverFee); // <2> + awardsService.registerMiles(transitDetails.client.getId(), + transitDetails.transitId); // <2> + invoiceGenerator.generate(finalPrice.toInt(), + transitDetails.client.getName() + " " + + transitDetails.client.getLastName()); // <2> + eventsPublisher.publish(new TransitCompleted( + transitDetails.client.getId(), transitDetails.transitId, + transitDetails.from.getHash(), destinationAddress.getHash(), + transitDetails.started, Instant.now(clock), Instant.now(clock)) + ); // <2> +} +---- + +There are a number of problems with that method: + +<1> It uses the `+@Transational+` annotation, and modify number of data stores. +This means that when one of those operations fails, the whole processing will be rolled back. +In effect, the end-user will receive a nasty error message. +<2> It merges different, business domains. +This makes it hard to understand and maintain. +It isn't required to all of those operations complete at the same time. + Include here content related to potential existing demos: blogs, articles, recorded videos, walkthrough guides, tutorials. image::https://www.plantuml.com/plantuml/svg/VP1DJiCm58JtFiMZ-rmWYwgqeHkeX2WNUBK7Ok4ubdyYzVQuZKbe5TZ5olTcFiqcHFOnTKOyn1OTIC8d0xPLdwBH5iBb_rfgnpRIwWMVBC_qwDoAED3ul4MUBKSzW9u6vES1eRsYMzz_mT-YZS-W3tJeLUwyOdlW23zeYJkK8vyuZ52p5O9bRk687uTYLgrB4zNqcav6XvPsR6GocTsZQ8d2L1aV3slQzVP3-uuKpCNgB1JkEwQpzI_FcjxoL5XgcUvdMioVL4soi-iuIOQcE5N259RYPgKYMNJ-3lfdkMPRqp7s7lJkjQFBvWihR61Lwimt[width=100%] @@ -41,26 +94,27 @@ deactivate Legacy The diagram illustrates the flow of events between the legacy application, the Knative _Event Mesh_, the fee calculator service, and the datastore. -[#demo-video] -=== Watch a demonstration - In this video you can see xpto: -video::3yULVMdqJ98[youtube, width=800, height=480] +video::Rc5IO6S6ZOk[youtube,width=800,height=480] Next, you can learn how to walkthrough this demo. == Run the demonstration === Before getting started -To run this demo, you will need xpto. Adding to that, make sure to have: + +To run this demo, you will need xpto. +Adding to that, make sure to have: * ABC * XYZ * XPTO === Installing the demo + Installation guide and basic test of the demo installation if needed === Walkthrough guide + How to run through the demo From 74aeae3d98ce455c52bc518d50ba6e6b00793fb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Thu, 30 Jan 2025 14:21:17 +0100 Subject: [PATCH 11/22] Section about example flaws in the demo --- documentation/modules/ROOT/pages/03-demo.adoc | 59 +++++++++++++++---- 1 file changed, 48 insertions(+), 11 deletions(-) diff --git a/documentation/modules/ROOT/pages/03-demo.adoc b/documentation/modules/ROOT/pages/03-demo.adoc index db1bed7..f8ff997 100644 --- a/documentation/modules/ROOT/pages/03-demo.adoc +++ b/documentation/modules/ROOT/pages/03-demo.adoc @@ -7,19 +7,19 @@ == Demonstration -Let's take a look at the example. +Let's take a look at the following example. We'll be looking at a Cabs ride-sharing application, that mimics real-world solutions of similar kind. The application is written in a popular Java framework. === Initial application -Here's a method from the Cabs application that handles the completion of transit: - -[WARNING] +[IMPORTANT] ==== -The following example should be considered an anti-example! +The following example should be considered as suboptimal, most likely a counterexample! ==== +Here's a method from the Cabs application that handles the completion of a ride. + [source,java] ---- @Transactional // <1> @@ -51,16 +51,53 @@ public void completeTransit(Long driverId, UUID requestUUID, Address destination } ---- -There are a number of problems with that method: +[CAUTION] +==== +There are issues with the above method. + +<1> It uses the `+@Transational+` annotation, and modify number of unrelated data stores. +// This means that when one of those operations fails, the whole processing will be rolled back. +// In effect, the end-user will receive a nasty error message. + +<2> It merges different, business domains. +// This makes it hard to understand and maintain. +// It isn't required to all of those operations complete at the same time. +==== + +Similar methods are, unfortunately, quite common in business applications. +At first glance, many developers don't see any problems with similar code. +Let's break down the problems in detail. + +==== Overuse of transactional processing -<1> It uses the `+@Transational+` annotation, and modify number of data stores. +The transactional processing has been the cornerstone of many business applications. +However, in most cases, the transactional processing isn't the best fit for real-world processes. + +In our example, when the ride finishes, that's a real-world situation. +However, the example uses the `+@Transational+` annotation, and operate on number of unrelated data. This means that when one of those operations fails, the whole processing will be rolled back. In effect, the end-user will receive a nasty error message. -<2> It merges different, business domains. -This makes it hard to understand and maintain. -It isn't required to all of those operations complete at the same time. -Include here content related to potential existing demos: blogs, articles, recorded videos, walkthrough guides, tutorials. +[NOTE] +==== +Outages from the dependant services must not invalidate the main intent. +In fact, all the operations in this example could happen independently, and at different, yet reasonable times. +==== + +==== Bundling of different logical domains + +Our example is also very chatty, and hard to understand at first glance. +In fact, this is quite common in similar applications. +The code starts small, easy to understand. +When new features are added, it keeps growing as developers cramp new instructions into methods like `+completeTransit+`. + +Of course, the developers could re-architect the code, to extract instructions to a separate blocks, but that is just a half-measure. +Still, the application will do all the operations, starting from `+completeTransit+` method in the same time, and withing the same _"script"_. + +=== Refactoring + +In this section, we'll refactor the Cabs application. +The refactoring will be limited to make the process easy to understand. image::https://www.plantuml.com/plantuml/svg/VP1DJiCm58JtFiMZ-rmWYwgqeHkeX2WNUBK7Ok4ubdyYzVQuZKbe5TZ5olTcFiqcHFOnTKOyn1OTIC8d0xPLdwBH5iBb_rfgnpRIwWMVBC_qwDoAED3ul4MUBKSzW9u6vES1eRsYMzz_mT-YZS-W3tJeLUwyOdlW23zeYJkK8vyuZ52p5O9bRk687uTYLgrB4zNqcav6XvPsR6GocTsZQ8d2L1aV3slQzVP3-uuKpCNgB1JkEwQpzI_FcjxoL5XgcUvdMioVL4soi-iuIOQcE5N259RYPgKYMNJ-3lfdkMPRqp7s7lJkjQFBvWihR61Lwimt[width=100%] From 5995862ec7ad245c3f9b285de4fe9f2693f0bcf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Tue, 4 Feb 2025 12:40:11 +0100 Subject: [PATCH 12/22] A demo section written in 3/4 --- documentation/modules/ROOT/pages/03-demo.adoc | 170 ++++++++++++++++-- 1 file changed, 156 insertions(+), 14 deletions(-) diff --git a/documentation/modules/ROOT/pages/03-demo.adoc b/documentation/modules/ROOT/pages/03-demo.adoc index f8ff997..47f3389 100644 --- a/documentation/modules/ROOT/pages/03-demo.adoc +++ b/documentation/modules/ROOT/pages/03-demo.adoc @@ -56,12 +56,7 @@ public void completeTransit(Long driverId, UUID requestUUID, Address destination There are issues with the above method. <1> It uses the `+@Transational+` annotation, and modify number of unrelated data stores. -// This means that when one of those operations fails, the whole processing will be rolled back. -// In effect, the end-user will receive a nasty error message. - <2> It merges different, business domains. -// This makes it hard to understand and maintain. -// It isn't required to all of those operations complete at the same time. ==== Similar methods are, unfortunately, quite common in business applications. @@ -98,6 +93,158 @@ Still, the application will do all the operations, starting from `+completeTrans In this section, we'll refactor the Cabs application. The refactoring will be limited to make the process easy to understand. +The scope of the refactoring will be the extraction of drivers module, which is already a separate domain in the codebase. +Within the scope of the `+completeTransit+` method, we'll need to shift the way we calculate the fee for the driver. +The calculation will be done asynchronously, and when the driver module publishes the calculation result, it will be saved back into the database. + +The base for the refactoring is the _Event Mesh_ pattern, and the asynchronous communication will be done with _Cloud Events_. + +==== Drivers module + +The functionality around drivers is already quite separated in the codebase, so it is a good staring point to extract into a separate module. +The drivers module will become a standalone web service, deployed on the _Kubernetes_ cluster. +The implementation of the drivers module will be done with _Rust_ for this example. + +Here's the _Rust_ code for calculate fee functionality. +The entrypoint is the _Cloud Event_ of type `cabs.drivers.calculate-fee` we are expecting the _Event Mesh_ will route. + +[source,rust] +---- +impl Service { + pub async fn calculate_fee(&mut self, ce: Event) -> Result<()> { + let fee_event = Self::parse_fee_event(ce)?; // <1> + let subject = fee_event.id.clone(); + + let drv = self.repo.get(&fee_event.entity.driver_id).await?; + + let fee = drv.calculate_fee(&fee_event.entity.transit_price); // <2> + + let fee_event = DriverFeeEvent { + driver_id: fee_event.entity.driver_id, + fee, + }; // <3> + + let mut builder = fee_event.to_builder(); // <3> + if let Some(id) = subject { + builder = builder.subject(id); + } // <3> + let ce = builder.build().map_err(error::ErrorInternalServerError)?; // <3> + + Sender::new(&self.config).send(ce).await?; // <4> + + Ok(()) + } + // [..] +} +---- + +In the above code, we are doing the following: + +<1> We are parsing the internal, business logic, fee event from the _Cloud Events_ envelope. +<2> We are calculating the fee for this event, using some business logic. +<3> We are wrapping the calculated fee into the _Cloud Events_ envelope. +<4> We are sending the fee back to the _Event Mesh_ using _HTTP REST_ client. + +Of course, in order for this method to be called, we need to route the event from the HTTP listener: + +[source,rust] +---- +pub fn routes() -> impl HttpServiceFactory + 'static { + web::resource("/").route(web::post().to(recv)) +} + +async fn recv( + ce: Event, + state: web::Data, + binding: web::Data, +) -> Result { + log::info!("Received event:\n{}", ce); + + let mut svc = service::new(state, binding).await?; + + match ce.ty() { + "cabs.drivers.calculate-fee" => svc.calculate_fee(ce).await, + _ => Err(error::ErrorBadRequest("unsupported event type")), + }?; + + Ok(HttpResponse::Ok().finish()) +} +---- + +Let's see also the _Cloud Event_ sender, that uses the _HTTP REST_ client to send events to the _Event Mesh_: + +[source,rust] +---- +impl Sender { + pub async fn send(&self, ce: Event) -> Result<()> { + log::debug!("sending {} event to {}:\n{:?}", ce.ty(), &self.sink, ce,); + + let response = self + .client + .post(&self.sink) // <1> + .event(ce) + .map_err(error::ErrorInternalServerError)? + .send() + .await + .map_err(error::ErrorInternalServerError)?; + + match response.status().is_success() { + true => Ok(()), + false => { + log::error!("failed to send event: {:#?}", response); + Err(error::ErrorInternalServerError(format!( + "failed to send event: {}", + response.status() + ))) + } + } + } +} +---- + +[NOTE] +==== +<1> The client uses _POST_ method, to send the _JSON_ representation of the event to the sink. +The _sink_ is the URL of the target, in this case the url of the _Event Mesh_. +==== + +==== Event Mesh + +In this section, we'll use the _Event Mesh_ setup to communication between the different parts of refactored code. + +Here's the _Event Mesh_ central component configuration, the _Broker_, which will be used in this example. +The _Broker_ here is the _Knative_ component, and will be deployed in the _Kubernetes_ cluster. + +[source,yaml] +---- +apiVersion: eventing.knative.dev/v1 +kind: Broker +metadata: + name: default + namespace: demo +spec: + delivery: + backoffDelay: PT0.2S # <1> + backoffPolicy: exponential # <2> + retry: 10 # <3> +---- + +<1> The `backoffDelay` is the delay between retries, and us use `+200ms+` initially. +<2> The `backoffPolicy` is set to `exponential`, which means that the delay will be doubled each time. +<3> The `retry` is the number of times we retry before giving up. + +[IMPORTANT] +==== +Because the policy is `exponential`, the maximum time the _Broker_ will be retrying is 6 min and 49 sec. +In the above configuration, after that time is reached, the event will be dropped. +==== + +[NOTE] +==== +A `+deadLetterSink+` could be configured for the _Broker_ to send the events that failed to be delivered in time to a back-up location. +Events captured in a back-up location can be re-transmitted into the _Event Mesh_ later. +==== + image::https://www.plantuml.com/plantuml/svg/VP1DJiCm58JtFiMZ-rmWYwgqeHkeX2WNUBK7Ok4ubdyYzVQuZKbe5TZ5olTcFiqcHFOnTKOyn1OTIC8d0xPLdwBH5iBb_rfgnpRIwWMVBC_qwDoAED3ul4MUBKSzW9u6vES1eRsYMzz_mT-YZS-W3tJeLUwyOdlW23zeYJkK8vyuZ52p5O9bRk687uTYLgrB4zNqcav6XvPsR6GocTsZQ8d2L1aV3slQzVP3-uuKpCNgB1JkEwQpzI_FcjxoL5XgcUvdMioVL4soi-iuIOQcE5N259RYPgKYMNJ-3lfdkMPRqp7s7lJkjQFBvWihR61Lwimt[width=100%] @@ -131,7 +278,7 @@ deactivate Legacy The diagram illustrates the flow of events between the legacy application, the Knative _Event Mesh_, the fee calculator service, and the datastore. -In this video you can see xpto: +In this video you can see the above example presented by Red Hat' employee https://github.com/cardil[Chris Suszynski]: video::Rc5IO6S6ZOk[youtube,width=800,height=480] @@ -141,17 +288,12 @@ Next, you can learn how to walkthrough this demo. === Before getting started -To run this demo, you will need xpto. -Adding to that, make sure to have: - -* ABC -* XYZ -* XPTO +// TODO: Add instructions how to run === Installing the demo -Installation guide and basic test of the demo installation if needed +// TODO: Installation guide and basic test of the demo installation if needed === Walkthrough guide -How to run through the demo +// TODO: How to run through the demo From 66b1614e2da878c966f023bdd06ed9433742c638 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Tue, 4 Feb 2025 19:00:55 +0100 Subject: [PATCH 13/22] Finished the demo, and the whole solution --- .../images/red_hat_open-hybrid-cloud.png | Bin 254961 -> 0 bytes .../ROOT/assets/images/solution-odc.png | Bin 0 -> 115310 bytes documentation/modules/ROOT/nav.adoc | 6 - documentation/modules/ROOT/pages/03-demo.adoc | 626 +++++++++++++++++- .../modules/ROOT/pages/04-workshop.adoc | 13 - .../ROOT/pages/developer-resources.adoc | 12 +- 6 files changed, 614 insertions(+), 43 deletions(-) delete mode 100644 documentation/modules/ROOT/assets/images/red_hat_open-hybrid-cloud.png create mode 100644 documentation/modules/ROOT/assets/images/solution-odc.png delete mode 100644 documentation/modules/ROOT/pages/04-workshop.adoc diff --git a/documentation/modules/ROOT/assets/images/red_hat_open-hybrid-cloud.png b/documentation/modules/ROOT/assets/images/red_hat_open-hybrid-cloud.png deleted file mode 100644 index 709f8bb87671b6ccfc03290e05ea9986de4c504a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 254961 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

H6%zJ0P7 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%0AnsQi`>WjOzf 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

6njhG3Zej>Bp4+2O6QnuCfr{}eSi2IM;A_p} zWR=+@#wM22;P)MAoo$(6VB;a63Ji{czC) z;=r2tC@#`|(RxK>gJ-?`<`va#KT@;TzLA&OhiKW~LIti21WIwjp0(O5eAB=n%Jo`Cv2K$ZEgo`E=2N4?W4qa(vb=>F4)zEGEjR|U|gChIA9vyil?z>y<5imHST7hHs21=;BIf6F2U-^T(ov4ZoYZ_{+qS} zjsy1NrZpVT#5S+J-ccj?cAo6xZR7_>pG=aLSyPirAUm5WV|H6)v2HS20lY;C(7QFP z41Vx~@Oq`-&SYT=Wpd=4GhBTpiGhyfWc)@7kQiHkcP=UP5iIOeG%e}`1*OM^e>#D* zVJ`=U9W;$G3=d5bw4R&f{(VEo-~8QY{=z~M(@Q=vF&7XoiCLQ!u;faK{Z%2@-rA9{ zr1Kciq9)xvRGb|O)L6s|MZkg@v7h*K%J1W1;31q0FC7N=Hs&U~F3mpcy>pMvVTidP z7TgV3-E2($Z<&Uj0~}p8_WlXO74rxGkEbi^ixbpK0WRb!jne3{n^)8}W(wJwc^=7b zT8jRx>AwSRq=OsYG&*ZlS}^l;wAG~E+aVfB#}s;&vA?L<=o_t zClx-47HAmvCWkorK=t!wGXH2k$P@hu9ix%OX#r5UfRpYhyDDC0TL=~r_D zb_jljS~U*EY$M@|4264PIrwxgc6ig|FVxy=nKCT?%4JPnKZ<4&oUT~OnHSIvpqr@h zq|O$cnVJiH?zz#K^#k{ZD=2r&Aap)-U;LH)D|?8DnH5MT>eBm-wNES*& zCJ*YnZ=Q3i($aJB1vZ`XnEM}^JGmM!`I#>~XA{$P{KnSI>S^q%olKZvp>gBFwR)-J z+u|f%jY{8#365LOZVvue)PT%b8HzVaCIRR6qrITH8#$Tx3PFZu3wOTuhV}N1Jh%UC zt^Rv($WXE0gpc+l;w2Ho$(p)vAO|^4Z0COLTt#Z)JyoUDAhGQ*j@Xc<6Ug6_VIaOe zv3RJHk)s{J$RN6z6G?x2#HR+l>*W<#gkkDf&z!wz@S{)9@$A=U6r(QykhD|C(|ntT z_y>2Tinkha@t)yO%fPtrOh=b_9(sV^^lNd?Yj_I6hf=NTGfxyX&v|??yLe`q@n2Fc zQjdpY%{xrey*x#i@?YOqq#HeMsKzh(H;lA-hjJ%Op;gQB<4vwjc-x!Bgdws^ET+#Gu8 zQvQr<<1%vW0ZMt}zPI(AZ!uq>3A~pYJ1KiMg~d4dhQ1ne90HlKI=3t0|H;^Bkd?}i z_9HRd=l@Q3Ic!R|sb%kAl~dtYL12u;;5{dDi+)JRkzVv?*f8KDm?q$EltlR_ymC)-%d9DEd-A00uWRm_`q(hk~D z1J75!&*wAJhfgttzwo5(Wt+MoBpp>5pSfzBQ*F_IrbD9-43smWS8Lq(%;G!-Jn)2J z7AZCt#0HN?t7G{m!JLhJp-36*Z}G`l>uJa=KTWOKwG=%e8nD!jxJ%xjC;0zF(`X1N z%i#?I|J#e+26SODF{Y2qL#TNzmw{pVQAuRq?E%timOQ)`0g57%fCje%WjRW|U|I~J z)0S?`bn>AQ-)UH>x~LbM{A{&4oB`I~6V(PR?aX4kKtp}nwQ*Lj@vrPr5E$pcIU9KE zY$L^R7Tra@8l@b0YGn?cON}o(wqg`CWEQ=0rZjVf0(Ag5R#YI>d z$OmhOyv^pOCK7&sE$DW)zy9RUPGX>cFjnWO?a`5gKfSRkr_eLFb7cw8HH(B` zu%UJEcjx8n^;SUgQCrOh{~i*?9<>#+)zZ=;!gF!U+v^@APx?%{rF>$tjXRNC4njI) z;RywgcJ{Kib+y6#gf)MG>Zkm^7)iDrWJ(33GP<>~8w3LpPgYd5vcoDj)*lXabcI~K zpXB3>tn=|8uNS;Tu?=0LFJ~>o>o$tX+g}X28`k{k5;dAEU`Q(!wEcqht2Lki0e3Rg z@)`I>VjBdZXZJ1J3=D*27?N90>c6w10scimN3w7yjm{etI?CHNDce5@F%MIxcdvp_ zIhN6THC0#k-U8Ec8xn!#UR7v&zLmrd6DFhKipL8DxuU`=zmh$(077l(FeZA+wwBqSvPc*2xBvNju#Qt_@K14C$koc_mc^a5{0uk;`KN#q+EXq@smgq>75 z;~-(;Iv;T9#+|mOziMx53R|4=J@{oa5Xt#!P5=(&(UkWI+` zT?dWt`}6ywZfwfvI1&Z593Y~Z)ieLIVDlA1njs9T?HrL~XTV0$F zOU_ZZTAmtARA~aIl?AE{Oy|c0Y(=xwsZU;+eXl`G0bsMlrza`#@`d}S zNC=7VRfnmaO<$;ZnhZV3k!^QwM7--hY_L2HVKoMZ&#^iTKRcx_Z2LWMfPHQ-oa46t z6Gkz4F8ys#==$0qsu61_tw$u#snQ{nTEm&qGx@=f+Knh7l&@dwe0t>ev>j~^Q z4;bcMTl`KXraF!GE%}wl)ARwodxki$UctsjXfBxK@ay1Q$Rw-SfW2{_)X@S#r`9B+ zW82yAO^Lme`LcZMA8a461`V-9h$u)b5aUGay=5U)-Vc^(D+%1ATjeQ z(tPR5w9%0j7#`bGcmFO1z;B8g0hb|_=Oa9|(dUnLE;Sya(%Mgdy^KiGp@`U9WHr|# z8IykOkS}G-b6$tZWtZMu!vH6}u!U7$6{z3UFQRQGnts%XL4Bh7h&RmZdh`hf#zORb zbgI4~hjCB20=|?H^3AQ+;*jTJ7~dbMV~%G!MZ|+tq*FWY=N9Tq7e2mY05cB%Q3ht^CC@xv|$aGvFY&|voMx0P9)_2bw@nGYv z^DkWf7~^|3^NxTlG)4=hwP3$TSHTnwNnat`_Xka<21*4QV@3MjmFeBj2l=NEsX#jB zHOVP}m{5Y<>ZWR8a${8_-nB@soxwz>k<}-YMFGJN=`-KE6sDZCl`?udyemu%n=h>3 zmCR;zY0ueY^R>QYNkBa7@1s52ciprlQUEBKXEwdmuw|Z zrCft40B1#f)--9N`xC$kyn_9aH!o3~NK;UMt&BR+rj{fW@KxSyI^UKlxlIg)as-_a zcyh@CCqLJor7PA_|E1L{!BC#*#ESE4#unA!Nr~5KMfZ#D7W78u ziLk2j7cq)UBfvV+o|@%S=6I?B!LNr=ts3dg-D^UO{0k;X(Pm z8_}m5y=o>6Kha|Fl$cpMl?V}+4dGT5X}e>z6#Ml~1~x@Jwc!4@N3~sJ+}$uUGKFZ> z$#(MwD4(BQUu@vT*Cn@Kxl~Oww5~xQ5Yau9g6}X^C4YuIBteJR1#zFsGbzLh+W|oG za|4=gsX1-Ef$~0l1+km9>1SBHTZ`>@m9dPQur_)<*1>zU{)b(lDg{A9f#&4vkszTX z#mSMcq-uU1U9jZ#lHK*w%!sSw#sa$K%$;Tex*l$F7g-vzXJ^=J`*Y|e-+u8q5YT@o z1T$?9ePP$7HWZ57Z@DrF_Kts!yaq{AMEZyARt&G-k(HuBmj+LUXaxVoS)rBGTMs4N zUE2*+tFC#I;vYg`fCSSl4Q*n}{v81LRJW!Q>1*a1kmOXxAN@xkvKLQB8MDX~10To~CZR0V_Ok!{FDIqB?Z8wcHXzV#Z zUMf}yn!3j?nLod=l@sWYeX|dSMpCs^m=^Q~YQxHb5~}xvL4=&WPsw!T0SSTKbM3{2 zbXl36e3~I09<;3)dSzMNe-3Tjm8F|vRk8L6Kgo1wd&7$9`O*1H0MG{F>x58tJL05y zhiUI#tdL~OI2>z<&B>XL!-t}L)aRlYB;RKBT?NxN(96Z@7&u`ET&sS<6d@CS%ZvxI zixk;s&OBSFTKL&MAO2!?%hNyEr>h`U`lZ!H%Av8AV`+GU?&XRU2l4B$gH3pFs-UiaLz?%v>~zz?o3-IsK(sW``O1n_{Yu^9#}*7xb%(INm7!I?MIoN)NMM4sM~D zgzuE#*@_bn9j6{#E>bmUnS%S9{Iob;k)WvSodo_&Jbi{%l*&&b2(oH@a7dFpX`r{v zY)X}Ss-Tbf{xcMUjF#u5&AKBrUaW@6O@>*M>m;Wxu>8jkG?B2;i({#%f?0=h;dF9CuN;lGV z$~An_{|`2PQM!lc`KTMOZtY{cI~*iKA zVQ!>!i-d&4zcVaF3rf8cn`_c3?CN$xwwWmxRVt&e422D&Pk)(>Df%;>mBo?LT{vGl>ku zLzsrC5uFC^E}=pJ4o0gzCS0dAG;cq)%hJK-+xyfxULG8HZ&EQI@%+f(+qnqoC(D|S z{TgiFSRsgDkjx~T+)+QeSAzo4ftD7_95tC_<+W#n3~je7e-X(|^C{buXIEI=d=kkB zoj@NhBA_p+bi!IU-#EmK`Y69Cgw(f+EVUN}q&Gn0xB6%fs9Jt&{R~#lOF|*ef4*lfhp4l)DkWc^SoMG6=r~o} zr}^?zgtT=@1Z``h>Z5N14Dyd$mpV=)TpNH!>+|C!V=!jCd{*~Whqgk1j?wB~&Krzx zaOyBUTylJdo>4`=Qb9({)>$f~(f(K6?9nSGUeGTyO9_)d0w%17%3X_G$$sf|g3^Ks z=u`cKl#41rU%?D|-l$^cOjhNbjh@&$th+#U6UTwacLKkjRY`vi#J9InRd(yAYl@~Z z$3}wXb*^deDw*x3E^b%xR5hq=k)PZdEVf;( zNtOvn2vwHgQ1;1Jl$Ck7O_QJ-kQ=V-Ly`RSF_%((1#dk=!s%Se9u39t(mBU_+qMj| z2APq?eOyhS-D11UwjE=~qsOD?oW)kVcB1B@ZMQdX;)mmfKjP-mI?$==NnHtZ0a}Y~ zjld_7R8jJ=A}P=Z2viZK4KIML-18>2gRE(1vsR_*1d^ipp_kB#tt0=_r#?<3rHSD_ zI;v~^Qye52Dp!nG4hk@eoN?Yb;wM|~aa)YsbUgf~-;=j;Zb9x{nCrDc#7yxwu@qD0 z4gp0*MH7whagnIAs}7wjRQHc*er{%%K{IujX0C3p>z^k~K!X{|OnMe5I^Co3C~RN5P067fw$t0$s-BD`JV z00EL>z6=fCUVA%c*pJv@x|>;G$Ssd8is$wV=tb#Vxx;&#rT?Tg0`$4VU|w?rXI2@N z_1(K@VkWNxh%baZ_1T77Jk^@o9(ERUHh%af zmH2!wZf;HXSDx6lPhl-Vk|BtkO!IWy#0trBUcG%7%R(I`J@cKzKV-UN3VIv|SgQE_ z4C`c)sJ@aa4=kiYOz(#kDmFy^)La+9>q)`MA)pBQsVq;>o7ax^b zkB4(>RvYv8x+khDT<9h1^DV#E7}d+S00Xk}Y4g2P0+LDvWd>i($P=Aht+Dnq-g(+) zLyF%`Scq3upnR4LQQqLR@}la&Mbi`>!3~&mHHM#=bItciajK+JHkp=v$L(H!6$R1y z$}R6LN9+O%$Y_xzB`3=Q`N$$3jy!l%>+PQSjMG*WXtX2Z)s}QR$*P6Xv)LgF>b9#* zJ62alzvhlNdWpSo6VP(W@u`;3)KwZUPmmNp%y1!Zbksk|$R8#0VO?3Qsp7Nmj^K-1 zUH4Kosef#cyK+5RI&n!u^yfEZAg8%#2e#};scN1LxTBZl35gk=&G+BlU`k$F!sWR=Xj{>*U5=<5 zXLQt%CxADA^DuZ!k@0vMGC?31%B^)kFmbCm>8P)tup;oR*EZ}wYyxSj;RCVlUw82W z+e%h18Sua66-P4NUwjkN1H*vzijCQ45E^}S_ySjHUKd+7PuQ^maZ9k36$ zWILcZsT}w5+Bp7k0)%RU6G7oRtQfNfNRdv~ebWCAy}=hpIOX834iX$jl1pAJsM zHnNT5{M>SAs%T7f_)S<7{3ElFZ&WfkfOYiKbQMUSxF@HyH{EAOj6r1SB{!kR;;1b7 zs>BkOqq)T1%%blhbSe`4prEJ4Z)-jRfYUIbC3b%t%Fq;`hhaN2(E{)vml4IC>a#!c zcJk^Sr%1y(4co8CouRN%^7cuqc4-sJA9XP<;6Rx@E``I5JwR~|xv@P>7y7J3>XzA32poc;$IKFE+r1==MXp4_K9UpM>e3A{bE;Wn}lvQ#D#9$ zU3OM=nv%x?;h}HEN?>ZV?;*$ifdVttzH|6c&a}tX>J;^v>lDk4rbZh*Lw0R9dJj41 zexX|mf0(siPsewaZ*a5DWHn?!P-Z$+;GZogY^Oc0>pVu2<@>VYdQbM9Ygx-_g{&@+ z{i9GQn3~n9WKEnp_7JbZ%}hysvgw7=X}ldtr8(3=8n9LiT;XJxV!4*GDRBVHM44@1 zV6qYM!b8M-%VeNIYr|P>Fkf2WTWw11O9 zV}@)rb;rznU|?jl>hl%h;rVim(W;;GsmR^eNrh80`7MvxqRfUy?KH56U2llA zW6Hk&P0FM>9^1vDq^ojL%%iM!@?>#I<1W;F}V?<+h&8RIFjxsG!>eKE1}`Dt4>K~vjswb4{_e0Tu8HS%R*-B;9M zNMN99t(4I_&Uh6QaECy{UmTXy8^zlLMl#5RuC*Hptw}@wRZT>k&{*v|1u%Hz1Q^p2 zi|?hAUDt3$Ls4#G9?GmD7%uuqec7UlFI%C}TEXNTtb)p{f^y>RoM#rN6{cLTjWski zDrf1xNap#d7+iae2%dn>CN{p%+tJ$3b!u)i#OM$MFTGWeg9h{0$Z#qF!^g1u{Vegv zbm^|xB(311M%UxqQk-}0+)1eDiS|r2Wa%LKI4jz&GjF<63sP5?E%0`^E!@v@7)uo0 z`4X1%J9WzF=j1ODB^Pg%seRfm6c^V|9B5lxvdkD?gZigf$K$ARU$>#Cs=0k!ZuS~A^Bl+o4>k!R*VuH z^D4>cm^$^`3W-w-)k3G)IBK+mYNgkH%Bb0h`a8#c4<0Oo?TY)heU46(XI2LZ$$j0j zd>_2sRWu;rZpoy2&gDGb%Qf>5i@P{$mJ*ggRL0)2rE8}lkKI5*&*B^R=gBK{%VQ&c z60UbPveU|$px2qFNn|ye*Ox)qU2}(6lt!g(%&B3kT>enRZEJO3@xAl@lQmxD^Fobp z-B?3J1T@Mw(5PySTzUfT?V3iR`D6&MSP8exaZ*w&pgU%|D~};`^k3kUfnR2#Kr*;a zp9d)Ri3L0GU8oC;goyBtV%J+7KuFS@gLb*>u7Isk3lh&HznhN&3GSjYrVgZx9et}X z{3b0E2d1GOCPd|vs|%Q%gHmXl&U%r9jyA8>9n-T4Wu8^J8a&p3#GWP#Wqn@igk^dpw? zxsYRK;pRNVn%^Uj7}M--)(k>ybN+$$3&%m{lz}U3f8U(==ovl5hL0Csl%IQ*H?}|~ zdhDBpz?F>Xi+944gg3qM=Z+Hwe*PB;{1G=Wg*FY`MQ@81PUpW;@n)ZSd2hVPv_r0) zDigNAp*vcG^fsy+AJ0O{d1T7Er5s_Zn|vXH-?}HY_nAn(22F%L`)&w}Mh7EIry?Qi z7-V~iA3Ce7tSmRMik~bBs*Vw$y{=p&`5*CH3>wwbp;I~D^u$iJFaH64xrcQK3dBk^ z=-GA@ceXMWu^m4aMSl71Zv>nneuAma>FcJv$2)p7NW?zdTzPQOs9sR^O`BBpVcG7l z)ij^&0h!A}CHNkqKMkpSj;>-V?_21?kp^;Sy1ROnQZpdo!CWw8pq;4Iv{1;`5osf^ z!{sL+Jer&LmY(r(&R`?Yl;Y#vM|#1i0RgMoXY-Ke-+H4yqpq%=5I*6tF;gVDB~pX+ z8br3XwMlYI_CqL8{!mJIcjd=PQb`VvGXhCgWG58H-TXdA#7AYlM0x|N?d~MsWbWWC za~h=ikUWNhP)AAZN*P=Hy^z3@SCm1MZEisxVy=5iLtZ?y=YcCX^FUzvYEI&}lBvwL zl{@%0=u?Oz-@Hc|0>Wg%o=Q(ocR~#R-)~hy!_=bVFKzqky|%un^G8E6lD={OoR!0{ zh7%rGfcMQvRv}p_u3WH%j+U#Av;FF$D;=WKruPE!P+tL3$w#^Z-*Ge{fQQ4T^p;&P zdL{oMZrx5dBB&0IuShj5VNsb&BH=Se?4_V?ktKj|E!JE!OM)OeLoaDe&u zVta7KXPjtam_fOEk8KaIzwF4m?`+%3oq;l1bKHBiO~WoIwQ&gy*ge}2VwVbl$Wis> zMz+{;`_10P)wzld9@!QB?vgaq@6v6gH*#y6PD$bhw1@YO>F>w<&#MssD)xG3z_+$W z;da8KMJ=>>sFr>9C&EQ5P{(HnyIzd-h0kUvi$_4-&BfwaX#)cs>MCdR>K$3L|k1{W76PJVA3X~DX-IL z<5)Xl%GmaPL<$=ERWK7@SlO~ zXO6EpRE@>o7d_s2kZ1k`bdVWdn@8YQQ$1aaEC)0!%NC@>7zkgoz_MZ4sw!&{bCGJcj)h~i&C9?YTy{>HvP5;wVtt4Y<|x6r=6^OLW&x$ zO{+7p*%kq&`xzb>z>gGrt&$O?DX0uyt>-M9WrrvOtFFwL!oaQUJ0BqW*6hZ#KVIvu z#I-IOM#!#YyZ(^v83>TcjgWc%VsEF}i@oF|944BtJ|bt-S(JK9O>hd<*b{$d`7HY{ zpOTg}{`+qGKPet1=nUfZS3dtkg4|7AU#fCs@d-Za9t)wZ$=`Y0;BwSOB_6PLjjtO( z`Up);P1Sb{ue5X97M))Du5KhIbQuO9$IrBEk45Opfn?0d_F-HRa?xS73pZUnWNz1M zD6!$2^qFJToOd{%dOvqZSG`07Ge}~qu^NkJf_IcoK* zuc;A2GW~(8DAr!*#Y>J`!MH^|)%wWQ45HKV^$Db*oT~B%$r;j7{T-iiUrz$`Lv`xZ zjNQlEK=H~*kubKN1x9TjPGUZP?Dz5fea*b(yd+9}862yr8&Mu3 zwfb*=@TG`6KeB!HY=&+~;5MUB#x<-XzN&@-PFS00KOQ{~XrCPN+~JOljHGQpeE4t} zv{sqbZ$RyL&D(~@Nu5bR0j~D5e4};$wV^h7p2>mbfGsy6@DyYLP%5Nz6DfnsdaMjv$6icw;(`52)=i z(y~tfyUk3Bid7U;RHxTmZ_sj$miqKk^+dYWyVcN^Xt*e%c(FFvK8ypkp)Vcs-bS zLXnA=SAoIf*B$653_6m?vIl4W`(oCt@u=R8bcZA4WIpsL2RBbY`lVMgPR|>@@C|O= zQf63>d%kkY4r=pr#HsW@Okb_T80Tc@7buixbQ&hG=-hzx&b0L7i6PQa%l=o5`c21I z3mVV~I$L6A^YjzwtV%lJQ0%V;teS|+&!?b&?fUAz#$jS?OQN(HXVw5ZYRVTlsd*%Wnmq?8m495q8=J|w6#ef|AWe^-BtlrEh} z)`3?nF8gBLFU&pF0$)WEZUtxt9li`wEz;EOA*1M>+G@)bGXv! zMjJudR>5-AO3Jn!7X;d4Z;NEwRt2`Qe#a0SaXms!1I;O7rZ*;u3=4eIIZ0XWq zhSHaASNvXFx~@MsrEZLjoO3^Owy{KJFms4B14D@PmSu8W4$s5XD8x?Lbcbj&D|Ly0atAM*Y8fg@}phc8_@*Dz;S$Wxo;Zu0aaq_Y?8d~XMo^bQ?-@?dw zu1}`qS`CQ;)7M{kv5rN4Y6FAS;Hd<8j^4$!ZK@0RcXOP-(J&K*IYJ{ro13v|-7Q(c23 zJN#`w;c!F%mJkA|T|m7-tF}2ZNemkrdX#?t%K;dBoO3Hp<;K@<-^O~)vch0sZavI- zj5(NouOyAvmP;)g-9D$au`(0Wx$KL$_=MoUgTJn&R_`SMe~&Y)sN`4(bu&NW^U>#{qKOCYn}u?xJ{gO@vQiL1xkR zoT;~j{S-y&(Ll02t5ZqQUFlf~h34zvi8fE`c(Ib~&>kx;^NJeAD#>!Ce)Mi>aa#-hwJLtt>|C&wZ8@n*Dp z{WVnI?N)8n(AI(?rf#k~=L6$4wtIhX)!t7CjjAeh2X~R72?AcZ{&eyhz=b2Qk-=M> zlOjXUMh~81HF{?nVSiSlYKSmbOgDZj)2Ko$x%p-Fp&91;Z9~)_P_#7oZ?Si(hSjn7 z8q4RRn`o|CGLY{rzl)uCX1*yV&!3 z>8$FjR!y-Lsm<%R@G!xZB~@9RJ;o<+`))NZa*VIK+4MH6L#v)&oPeBon$~PC&%T{x z8a{;u0_n!sV*g;vOIj<^&(F_agUFN#PpgGLz4kGRm#&IJF~eeR1Ls{~L4$dA-{Op{F*S(^yO83Tp!=*&cCf&kbZs>8~4BCT$N*_2L$bUldNcT1)s= zT_I?*l162;Y2sSnycpfePE(8kqm}geBQGlVZkqU%GQoZ*QO1%DNT$WH97mT#TBQG( zb0)2<#jAs^hERy5?T=rv)XmX<$Zyg*>djZKV?0n&U|?9hE&fL5E*sDPxgN6U7cG|O z=ny8?353E^BYI`uf8=FdOkR;Ze)o%aM{jH2q=;|8+OPW41J_VUH|D2nE&Q^U^PvVe zVl|CdM}qlVsHUO#ar8qC$-~YR#QsJ(Ni&^4ufza|o-78lB=7sv8+{%LlYh@baNimp zpm5_xLFp1;4bOn(QP-v*X5pxv#Rjm?Q|J(zx+wfr{P%5fJFO>sJ>;jVuiV$h;7_lg z{;>J}$(42KTb3IYSGw*n!W|+u`{U2Qi&Swy4~jW_}a>8ZhHrYw#K~B9^KyHs`aTt9$HdX0KKfPdnd& zQn}Fi2jwyvx5VSEu^)p@n1w-ASINoH6o2_7DHI#j@sKHpk%da% zj6R(1ryv@CwOwbzMGPMwLcB$-lG?WM?6fH4to~>a{m3`Pmqq04f8amO0dXauOLp*y zyF=Ha0^g$>p{Y7e-{Tgk_fBRJDcx-|j-D?gaR}2ZYmcRmV?NH;qczUxpt>X9>9F!}Fe`Fl zy)Uf!+g}LV3mxZev1Mh#lO1Uh(U(NN@5HvWJSIjxMRH9>;;wwh$d)7rCE0tV$;di{`;jLN9ry?p z@V(uiP#uPjUsi9dGiuf5)x zU%HT3p5!7}s-P+FF=j+{;Z+=6W?8;WOC;of^j2=hH{KS71Ui27U(2GFED4swJw3gH1#ko; zVD_VtV-S?ven+HRBtBwJMQ!ni!gwQ^IaDumr|ew{Y%8%^k?prWtz?4sZ{@JFK0&%N zqY!78+|dmYzeTcw2di76tQ9=Ju_%!^9YM;S))RHP&bRKF-l(VG>7Mlb$jP(H7fd6a z!t{cjv)Ej7Xk`QCeqWaZh*>H{%rRYu9z&bWU-wJTFuMO#ii82&0~h80yc+T+ib7-S zI0W$xcNFipJ-Sl%MRM=O0UVlX$y{-`8|UC?{Uar4b8M7Fs3>IGc0*sYwUz8}v%a>t zsOz zZq`L;=p_g@$5YpU7(3Lt30miDDGG7n7493onF|O1tTI{`0e4YuVp$c_`8KNt7jpIy zh6guMr2Dk_MA{Ed#RU9`q#$O8Dg}cgi~czWe1htC|Ca95^ooN9)h*OO<4$a0+P8^n zTr>yXh`o}7xo689la}fB<%w^!$ZW7>j1ID$<7D|my!D@Wa;2&-1e-Q|@V%INbJR8U zpMcUUg>bfPNglw8fc6Z{uFeiX%6WP^EA5HOE>t-LK{@$%_Own#?D;k%m3F@zF-X-+ zHS_u2>an7^b&~QG4nO){?e^TowY(>d(%U@3OjEwH>WrSR8?A$lSL0K+EZ@Hv;$~hr z|8NKsf%cYM>+XB>lfC0s6@UO*&@=F> zasXgil&>&0>$)oB4oJNR9>DJtx%ZQ|MwKyNBr88Ze=4Q7$^4@R-jIo+Z6ml5MQ8fQ zO=TV11|K}6e%^@Ns?nb@Om)iP9${F~yGG(i%)9Af`l}q`&#yhB>&3`YHBUBw7oSjW z+e_~(wNLBJL{{&jihFC}HArY#zO2#%T~oI*)`x5oS^Ji^+aHtv+1|a|Krlx_2jh8G zT@u*_h71Hvom7kO+!BY>`13iY1GUY zNR9^%L4?AWON<53&#Q^)kFtt72Zn^r1eaM?6``% z8s5;3M-A9kZoIB*c@CgM`uz*}suKla8TBi9B&*r49FGs`9!nfVfoLtpve)?w-!Of;Do+p-pvH~d%;6~XyEGsVi=chMgRYE#`aGe zg%&~zH~nt8N;~M%Vq|!NPEVeSG0AE)qy%p~u0~E4vEbH1Ty8vTevv6sT2^Ks?yB}c zkhXoydmF&OZBtC<_*Q|4jzv;Gd)a`x1B!kxE$f6&GP*l zTR=yg$*L9ZwGQOA9|Z+sZ0+)>TfH^%;776+#iAPaP?O1R!%KLp7yuH|0l|Y z*v4;V*txTY!NkdSif_I%Vyry2(`Vy&z0O;yjkCqhHKv?aeGE!jf!MgmBcCv+=_eYU zKCav(rFn&PR^_kNER>4v5YA%Lxc(b`l9+7I%4?rJW7zLMfI4~6neG#qw-?_rxY#FC z6@36A+HZqE{Ods#Gz%wt?rbl95t{3MZ_)ND=+J~1`r!YXj^EpQ5&*#m->yWMhB6!K zqrSdA*4tn=p-|sKHESk0^G&<|!)ERMdX=n5qg6isTgBp-GT)A(GlO%l*G00q;d_6tQvOWBO>GzVTca~-4j{;)P{7b;-?5vbk-)HzaexRYjw3;^$-tG02u<5ewz)j7{q;twZF|DAw zcdAWOZK#cyxwQY|X$o2pKceHRf?&CTZkQ#TA_^33x(O4yG z;$2p#so3h$2LG1Ft#(e=Uh$dSs1b(FUk(<9u1>(-QNFaj`QzQzpuw@WEMHbtZlWyQ zl$j@chw{9`^YNL|%zIgBw+~;2Dzh~q9x8kd_1xhjPeYi!(0<5UU#;tLdAg6dl>Y1Y zL3@$nM>OBcb%$1jLP{Oyv9Ml`8PKUJ(r#;b0gy#Qx_aJEsv}UF^LjyupU3?J`ZsuH zjO66}U%19!`FC}#&r}6E81ZTGhI^H+*z$J2mSas*1+Q0d`dYF-m5cTmneOc@E+@09 zXieqT>ioHlbLU=I8vV;~{r-VCb^4v6U7}NBxUpW8J|2elcHhJK__=o=-fLPFG{tfKOoq}uLhs}w)3i;AxFuN6-zg%G}AZz)EJ+-x`hxuY}L>uS5` z+4b3Xn~M9jWlV;p?Be@H%MeN`4~25u`eh9bZ|(GkYTG~NV+{d)BeVtlm*9dN<#}4E z>k8Xz9tO%7_5*-02dZ4`+lKkn1vT~H=ZTLH6!boF31Se@z!bvHYTx@3O@H!%QRqKk z(Mhe!IQt9oJG$xw;-iMZV;9Ma`J_(m!A{-$o>^0?h5p+^0jLWNEO*qD+fZN*XKp7Q zdH*4Qv^3nO=*+ikxA=6n+Nl=rcaFNHtL55$K{aR8FWLIp=4mU7++c0Gl{71?eReui zkg793HvE==hEb+(wS;pCrdN93-HXxS`>4YMm)hn@P7q{~0nJIPFKY{6o}6X;1Us{a z+O+Dz*e4+@(sEFW#3QIJH`S^kCD1wQH2;oBvb;UQ=hl1eaw=--aykO-zwQ9kh!EEe z52ue$swSTA%sBglren*5@>zY9-4L@ztNZdQu5^TLCWW zug}HTX{fGipK^qg#6+d__m3Pc0!r;i3%=6emtI>Bs#dhqjhQP}x`pPE(}U%u6NjDO z-cwNtPo?3+a{xwSjTs1#KY6UDGK&0N#@PCS^Gw!LWED5~;S6Mde+;P|Tl@{9@elk1 zA`!!6?EJU-ScKPSc4Q-$+eQ<9&QMiO-}L*j5NJO%AJv<_IDGBw`^O*Nv;KT#2B-z6 z--eA(s8Ge#Pusa@eW{8wBjgvUaMP0Kl1TT>r!fL_3&P9?N@xy4B807aOvz#Z-A{!= z)KpYSb5rgX<1Wripqcy$V9U%1>&L(ya^q5j_BH2kK>`Ke>1cNhq1k+!8`Hn2uff#F)KSefIo}n7R9@E2~TW8$G@_=RX3#R!yi`?UybPL>1hQz8P!lz5HYf}3iAJa^%jx| z1pCrVD;?+1;rc=2uxhb#^vsf{-|Bxx&*q)SaSP#XvMcuXZpWx-)^z!_Q7uc!E66 z*jH$woFacpGrA0)j)Zzejbz>{EHZ8p?=$@hB^V-nJ~Ll}hI$$9$_gh52|4xM@)rfS zg@Ot)S6xop?PVEgC1fCLPr!SLQ`%%c$652&FZQPCMc*svS}#_g|Ng<#4~5eHeAYx? z_C`@f(RO~Unb^%8SKaI&Tx?pkvy5BdGL7rt)aDZ1d8mX1YABcc{ijA$7R=bT2LBN)6(sst8XAE@3x<9@e`a;<{1?!(%3Z&%#K6wBw*)WaN!=Ux{29A_=n|$KOL??x%S+&$Mw{o7>90 z%i%WCs(w-3`?-r(Eb@6vW=hIct`ds6I4qBiAJ5l?TNG!e23M{$RJMgDlNWq>MPBM_ z_0Z*0l*3+L+nk2isW$|nU6;ebZz<+6`1zK`8z)uMR2q-%K(3gXCQ(Xyz0p*)p>Ef- zXCm8a7c<{}B{k_Q%t(Vk52D57V|Cl6uiGwhu{Fue_A;`TIbZvOr&Q4*4u(HjB@}W$ zJ*!(Yi zmG^9y8(t2CRL%LiO-rTHMYE~hv6i0aIIDcIPbF%<2j6={+(Hnz!#N+7sm#0BS zfW&7|t;4yFnOVOqjN2;uKc!tr2pFmsQbMlz8~$+~l=Btn&UQlmD`6Aa-_pg4IrIi<=EK821Wg3h~L_~?lg;v zULhq$qxC|~&jteE7w&s*v>q`YAOh-FTov7+L^L`D@dA2*NvO|sOQzf_kcM1Jduhy1 zW8jJUOobcbXOPzp32=MrVgAb|uk~qgK?7tyD&@*l6>-e?{376Dx~zy_%x2~v7^gYl zfNTELm@EYm?D07*^%g^gmt8tzxzT@$fmYb`bgoHgx$`9Vo}iqk#(Mj$z~F`nOO*{E zc{B5}(BW{Ao7{ zdLP4w9)~au6CntV3Lth`E{X1l4G9?`it+*b>q0dF5NPas=6@+9WjuO{uDRzE2c~B2 z9(ySeCg{v@8LD`kY57m5T?ZgD+0FD2Dvk0t3f~fJ_n$VO?iE$=1~+pOUR#8~D6bcs zZW*lvvq*AMQr&3%GqTr`=fNK9@!}brAnIPaCHduVTtGp5n&81Qal#1SEhI%9Epcg4 zg~V#nncj@7$0-_54VrvM*!GM$0S9yyZ~=%x*4%QQ3;B~<(OSh7WG<2cSS}%5PYf2N z3aCj)drl0V=O=Icy#mlTQ{TZ-G5_`ju!0N}&AHQ?cYFWK<^QJ|?ezpX=)S65|LIe! zl7x>pdY<_5iw+N6uA>T68!^%xNm+76M~K4qT5oC&|dek6r;<$<=I z0V}zHe*(@4IsBvyKG1j6u8}xLjC_H9r#@qPFm>==!P1bQ-bRK&8Sz``;o|YwXZVf< zk)W2}!3_Q?dEki@J&6Osv2sU}yla-g3KR=fs2-(Wbs-E-}sC}2@y-+SF z0J(U;ovdE>4nqZ#SQI-yZ#@ZO6!V9pDR~wfJN|ngp{?up3!@c@p|Ru>sJ43Rryrss@T6qFoTfcv)?a9$ zIpCAEU3wm*k@mMt3=u50{dNb5N&5ZU@HuazSf0c{RkLP!x*?`=KkNO-O77L8v;Ny=2E#78i@jwYGI{@=q)3?w%4$F+4# z|NLV%ZC!nR2vDzkbVmZ=jesL4e#;Wa8nG z-(@2PMnC;$jbQ+}-wLkyKEB20_o*m3M#pFH80aBWf>PesnA8ZtAG1K4Ozw$_!Emj6 zDy0M8Mvw$Ze|E)km*vx)Nyq>B-EF9V4(!A+v;4CNRq|Elmm2CqSY|Tsf_uAUp8bab)_{#}TuRbb?m#UY1Ep_Uj(|{1)rDYup zKrtQs@bCJf(W4K@MZLg++wo+BoY#H+G;M`Dd2VH~u?KVTmzIX()_gG951@g5o~K3b zSq6uWvjH&f@6xmf+@jABpGy>>i{-of_f8WZ$HK&ioPOJ8VT*%5<`AYT8*9?wu9HCs zbX<3Fasy7vr>Ki&ZpZ(NVSyl=B$QWouo7`b1I$4HdfkjsMmgpZZefK^cJ7LnYh33V zcTxTgmc4D8P)B3()70@6^Y<=-aoIsY6V=kr)pH1>w*;QhoO`$SNNLLtlQkzAy1d>Q z26AA`1L50mMcj*Bis=Ah?s$6W=aFYTbn2Z+#kjSRaayhM{o*N>RS)Q)T&Eai6hd?U zJ_MOj1=K#np$hk_LLLX7c!`l7jqb>#ngODG3BAAn90)6v`1zvYChQ;px84bSOhMpC zYT#K>Wn!xy*J!UHwcoLaWzx%Lcptceb_xxIb>H7=rf$L#$2o>+WFR9!CAFd-G!>X@ z_Csl{c)~(u14Ks67k29$?AN{Ad&#I1PGYO5&c(?(2r{(|4#k8k?JWkHi8x!@l}T9g zJvFyWM_U7zrn5{g|FqX+<1)3-hog zHe1umrq=-4+2kAcsaMcJkuOoIAsV~eJOUPG_r*6=hw(CE+nK9FJSf4;CSg{RCIjo|+sB=C6WK?aIxeCf^APDCj`-O5**8lb23F#_iixyr0v=69WNf z`@oUV+Iol(em}%piHVI(`qlMFs=#YTpNWw^RX7-L3=_6tMk8e) zvY|kg*oD}a4$eR=;`&6(!Utx4q%bQ*PjL|71#HDbmf=rRiSg|vKB0a~idOsqyLQ>j z19@n3AuZ1LDl74XEE6=H$U2XrWamV$x0b9#jJgWReiXX9eDw71!&r3%@5%1K{qx|- z29&Lo63=~#x@2MM*cib!IXQ`^9qK+p55dJ?L%4NLu#x+pqqNTRib_hnmo2?H#KPJ$ zV2-ifU8{APbJ@X(9*jpqn1?yBa3xsH-lvn5G|`tSeyfEjmFdzh9 zCykGXE9`wb`X8742L1)@o*PJpRVIGE!eHl8WHLAR=hPk`m?Onksw;N3UFRI+tl-1X z?+3LqASNQ*sVjSYdpfU4&gR4_q`4F%PmReFd>jAJMzKt^=hV24-C6s^w8O3U3#{)s zEe}~N=T6LVtF(n7lDYj;T9tx;@M_6q$Lzv6FQEjX~;mZo?z!FQ_E~zQ&8$(x987W6}a;C#eE_K0WZacgdzzC zbN6?bSz?VX%LjjWPig(WV{>HbYB}OK9IkBWya=RI(uAaEdaa-s2W`Wd(i>cs-vA}L zec$S(=szxS_gfIKRWZyEtjf?+AZ95a$MDO1jd&6Pc@XQ@dLoodRRER1H}_S3dCvW> ztZ0fqykRAWkHe$4NbtQZD?24aJm<3*!J2=f5a6>@CYP-Z@v z1S}b_L(g7b8syP~qso*@_$&H+Dx=tg-&i9ODBz7f4}RRgp!VA`AHbq1=%5EURiqc6 z$ex3h$(icP;w>=kXzkEb7u8V>exOIu90sReTjYrM-wH%y#H1aUy z2ghRn+@Gs#@rFI>4tx`_LjV1}u=6*uAVardGU^iqnLQ=@TQ@h5k-&Fw)|kBiW^eTQ z`N#r(=pu4c0SNOuA{R~{;UU1dyc+$yp~80%CT*#6dYjD$9@}#g0%UXp{S1x!=5){G z`6A`xM7e=byrejVH-j!zihd3k&4lqiui+Y^9)Qmm+Ui!~o7SL!fC0v-+bPnm{nv(> zPByAmA?-)ptKGhaW;jUg1f%fG((+fhnd2Y;u@5a+6(4e3w(Q`xe%|Xt_QH-1({~V`wJT zawtj?UQ8I}(w=+r%H+cX1h7CC^rrY>kzJ^*LyarH`g7XRd zep#o_@B97ZcU|wRtIJ#G^*Ybzz3<2Uxc@Ryk)T4*uhNBSU{W=iv;Ie=&a1&(2i@8& z00xz<5JVJ>s{BOJBU2*zlJIl9HmblpCq-&b_ROUhfsT2V)7Sql1{t2=tz;DUSjvaM znXu>sA5P|?mSpnW(9s~zNIGxcI5Ol)w(hfIca0-Uzk<;8P=U}KYI<_C|St& z^!QTitux!0J=F@aL2&H$DvB zKYF)$1qC3J@I}c~MW~y+AOJ8D8ra92jt{~3=#}~#5P5U;qJ5GW;n8zds9i&s37YTb zGsO=x@(i7{d%M|;#8jbnN8KDeV6rB|!MW34k~&N!W|>m6cao>}hqYaYN8_qCt|j|X z+>6f3C+=UMnjPj&cjTWcCjevR#IpJj68Z8bEy|anV$ay8O>~lxL4BK-Fc?%>kZy)H zAeWa}3z+SFPZntIm^W*uvTg34?Ha9>y!mSfluNa=0X%topn%(JT0C$`cJzVJMe6-~ ztPmJZ_o`B(fq}7BN4WsR08YB0j}mBso~!^Q+dcO`J*09&A+Cat5jHl`nFh9Gy~em} z4b+Cxbob5@9zbi?GeD!AteA?dBKMU%v|g&2r;UTDs-t2gj`nT8fH<7gMCbi2Q3Nx^ zhknams^2TaE^y0P829*^bd8IuV|riXlQJ#bl4-whD@dfEhWSA|M;!6 z`t~JF^RH{+Qz8$l#aRESwivVXr#G}ke64d=nRuE5;_`A1RZ>zi=564npa;ADNP+TI zV;LC##(Ud;$czh!M~4=<%Wou?VC(gL-iPF*eEiVFjo@aPW-<>7Xn(cJMsLn70LDZK zKe|Rvy;JAz`OjyHA(#gSU$mT>I0L;FwSktR+k)JB!1#!#xJCko=*QhTxyoW?Wc%bp}rY^WOz zuDyAp9@farGcZg;!V?3c=FSv1v32P1YaU0C+>f0gGn;+`jZ)`;VJMu7m8kOMY57;_ zLSY|6)2>Dc03!ZfEtW;_zYR0Dq`?7bIquSR%8pkvcMD`91L`K$^YRIjkoWPdMIE-2 zD1D7U)BCNvFDC6ySK$y9y#$0jyLUsNmPCH%TmBpM=a6?l|0|tWP+(Dr{SH33G9bO{aMi|u{ksZ^X8o#Cd%qjfciE1j2rGr#4S`gZhX*mSm@<}~1 z;}HfEvAk7bJ?y$(UE^G62h>&m*J7W zbVpaJvLqS01UvnE)R4l@$UU{eZgYkUWlYd5cq)HjnRf2HtH`fE_i=pWk=$)l zgbe|m4!Km1$3#$vG%zSV;3>2^aK?T>+D;&)l>6tJH?GLO%AGl#eoL=x%dkGOUR~BI zzGUbejBfG|p1Io0{dMfq-~PK^yh`)nmcd3vh)j;e_bg|JG~e`WozmMTd!9@iM)I7I zRm!VZY0XqytU{Grazd5c{JwLh5xV~b-0Jh4@}}L(9Uk#*BGE_YU3hYT=Agg?=kr3XW7SHXzKyiHC)qv&F#Qj9>7j4P7g127U zvDkwmzMBS#V;35RKG=3?gdgTeqV);$6Aw&0r4>}vn*WGz##=)vZeC)mCl-PZDzpxJ zd^j(mtHBdSBLCXnP;A9py8c*D(rf=~Cy;$VMS4A?f33X9!qEGeW&!5v>2Bjhw!2&~ zpaQ)t7_(o!-cAnmH+OBpWJ*8?mFxQeL*~UFcHB1Z@w&t>k%b_yY-+YWr`3Yh51 z`E+N*EZ||o=F+t^#{=D@TBhTJS`$OJ1K0Y;u`IlsHem{jd3=#mLJDS3YE|B96!44` zHeQGM$i9&5AMCe0B`)EtEsiNWvd3gA+n>*FNBvs*9c#mV>eMN!`){E-LHG|v8WU;* zv@v_!_&phMp0#s+?4 zr8eG(n#_gd#-~y4>}IR$#WO8fcESHP?%cKt`?4{ZMl`$bdqrpZ{-~)vlTIDV-3Q9J zb7u9;7VW(6hV`%Y{&YXs7;m}OvI{wL#5&AO1K7z)>q}8g>(~l_qE=3mxosw9ghcer zh1}#quj5a)%TIGWCYnD*%$8j|rRkm%BVTbrDjI4bY7JS=Y1LW_!8G~#2|i?u{o{=_ z6M@kPCY-};GR{F!vi@l);jT2R@u?>lPS|uyu_`LTSapvjvOxE{zwJPjj*6Td0H7=4 zGB#?BR3500<_9Xx8UwnxsM_ZCr|0xR3Qa^OQfC9l*`L9t*>p{S3PlUWjyMkB=``1XL`&?tn$5AWB7{*lz026@*0Z zzx-y6aW5YgKzYe&(Cy4M|NRwGX|8N`JZqiQxjTvV;2SILzFs-OyvcK?`U&1f{Z z9fvO&fKbVJqtV;d1}K6a@(CMK3iMdG7-+okg4;v(+;cZ6uKOzVtYYEuTu*LPhSkLC zDa{zNa=ZWGtebbRbA&BV5`lgqP}FKdNjgv9DK+u}7hqGu`vhtCvFihnrlO3o^6ovd zHx!1Ld_I4OQT=YrpyU#}V#S(qjHz!h7$GG2PDE+XaY4c0k1K;bD8^PqsCj_|5Dq-Q zePztRmYr65J5lz#!XadUM(e zsy*hGwP4|?r0?F}X_26lFiLmu@=mvrDNepyr#<;E=KW1PD3sM>n-cx;Xgv%{b9YaL zZ5YJ0R+oNGS#DR%I|TfZP^)l>J_*R~AZ72f{J zSgb60{+Tja>0{T4aU$Pkj%+Whz~w1N{xX}ujR{CVNDNDtuz2CVE_n7kbXvh!tskKI z@9MRGA$`O!?0(f8PUUT~s zPf2|NPWsD=duqX*@@mCu$Ukj4pyJEM$jA$;PVQ=6VvjLxO2`St1fX`FxbVGU$ms|7Ow#CG|$j`6#nlsRRk$TVM4=lvQr*Dgc#<&A87o1@NI zn2`t0)(*o@&HKSq6=VOrT?NF#n8J&}fj(eJGiMZpvJurcsJoJn4K@rBW3Ion(70rH zG*Bg2zLO+Ef`lQJ`%tUeKO3t0RK@Vj{}#WWI6*vEcLZL^ zPFUcJBi=CdzkfYPkA7U>Eo7Rwo#x)Zo)AVgdP?!Zz=c;g_s8=E>iiU}Kj07^=lWA3 z^U9dzSd-D66R^2th|~-AhD-V~pR$Bdd;BKgR^2EAUBHQ)gWA;4Vcnj&com**Munq;PC97!nk3(WS*=JePj{?y| zWMo_3`zI96$_iD@*Ja#3S{Uk(!WdXM02<3O<(NQsY<)0qn8w9AZG8_0*HVrQ51@?s zS{foa_M@ece%x&BT#uno(Ahrj!cSS(WxTXT#cgJraNUdNl--vNCwI$10eHg}CP_l) z{Ij7ZdV{uV(>!8@N%yvS{zx{m7QS`*Ld=P*Bg!{pUO!)Oc6LAlj3DQ_h9@7?cn01K z@|gW%R&0$k(l2#*@#Vw@7l9cHsfuLt>B___XA zRH^-O+CpOSC@KzXGvV&jQtDr?EuF&vrbC@p;^G(`WX)OJ}#zwpK zjJ$)R?M@wXjj#3rhX~IZdy8}RL+dXeuj4iDohc2!nh$>}?&~(*r4RxsG7Q4DFH}mfI%jcT zu@oAvP#luJ*}I`VWSS)B-aXL{)^8+ZwKe2Vsr{ViH$ z*Co>WtFIcbRREpg)uP6`PpVlqV)r=S9w@>t&kiOsO50EaA_S?xY9`*X4QaqVop9^9 zb}hGof6F5JU>Quhmatysd-s#9GrV7&vRAhLeD-U%PBeb+aaM88CzBfCcy*iQMM41J zC_yAAN#9On3BRP>qw?KTmHW4EdyVcSY=G865*Ate^EZwyTmM}#);BB+vQtpFzd`DV z#oR?hse8WMp`5uLik`Os`}mHD(~%lOIDk~&ex2jGnU4AudfHJhjp8kH+uf_`hfyK_ zE!6JXh1sPnfA;d`v7%o?=uGgc4BAgpMW283mTK+i!2NwqPo;G1u0X|SyHr=sZ&I8M zM2aqY2uf$Vfmf-&Acvd#bjLNa-&O0)(Gl>LT%$8H!m5oklQ)5fV*jWelB2;O;2Zg} z?wAmr8+x$u;o^OyyE}CQ!dN(r0RAu+xRT8Wqzgsyqtp9V@T1c&sA!?{0c9v74ZYb4%*W3Y zNSfrh@F$0chW6MswaKt={O7nQ1Ye8It$jI++B8=lf}piUf9IfUvZa|+CMbwTcrx1y zaQTjDHNs51)EY&RVMFgJ6S^OYW}FpKiEqyb4AKbw5i`S!vl$ z{RTyjQ{k3YgWY|ES@LyO?fiNeLX)cYOE5=;_kV4mWi{!FblW2@_dt*KWtsLQfRLNm zVd7^Z9I{CQ(nl&*{D9ptc<4CjlXsEtjRCj8T zJ_x(VWL*~x4O4CoGrf~A?TOVfY8s)<>m)gBax(Ul9x#KrW27{8`@q5Y0Xr=Boj)gf zYTs?1&OLpT@s2`VxN@{~u{Y&GX=o!McyGgVKrB`y+1?k}k?aZGeT0le`o7`?GLEVB zu`Y5Cx`DN&Y2jF3D(lZ}0uS}Fa#pkT(1o{E>FM;}WhDh@*F;o5)H#-r#1Q)0h>!0c zso#4hYx2co97P-t_i%9V$xYZtbgh}SRUH?t_Zyq|IPp<5(Y0d6ZqO}Za&b-m)pwf& zv+Hy{qO}J}O4c$^%U$eL>tB~kM{(*FTx#j%&)qLaOrW40ycOQCpgp2kL_4gosmeq@ zjQ)tme~&}P(y{cY2m4uZ)ejEnoN6t;djmk6R;`tnjPpIpFDc$HrV22`%DIo-$D0Ug zO5DC3%vt8-XtL;4zdl>>Tg+}}yfObQ)(rmxs}iv-!61NNc|>fw%S+Ym_k)=TP$C2u zbU?zubTPyLqRt8Gq|XxxFYRum+`7d0_&%$YgZ!#!%;SVX^tQH{6k>`$=K?{;|FF6& zP$Hn3p!3He)Y}7HsH=n}8x_FC97>#k0r3GC74jHhWRM|vErOO0pkYQR+JMzODnebNz6E&m z?!Y=Rr&DTWWE^1}BuD1C$-2*VopwtJ#mnRyJXLd7Yk9CYY|eXMWb_YHm6l;%cO{?8 zTL~wD9P(7>w|vMv&els{dC{;Ybu>^)89+R}!aZ$Q$5+b^u20gt$rG$eD8`*AC9~Ev zuf2?{jOAa}>E_{}f90NHIMnM}A|I+a(l+lDKiwi%?0A7pSU(Se4!cGx$2L8c^eJ?EJ-gy30Y0N8C z`NgUcAZwW#dFx~Ny@~%)d(s|oU)D2qW9QwuRBg0JhcNyqd)^0I+*WM{(WgtKGV81M z$gJa~YAzsEur0yrQ;xg3y1p{~#2hn93vKGlj7gu349|_XlNQMey|FpauJr0oixj`B zg+p-Pp`Dw*OiR{ezPRj>IdEPEJ{VJhmg7m)s=VX5lw~AlOTBrD7b)_k>>_PDK}qIm zY%QM|s)l&8kDjVA@WWbyaFv;6T&K7!m>(m2di~ssSBs`~UuDF0TCCPofU99q2s{WT zn863fsGz(6Yx5|T4q^mCU3p$khN{vA?5Y>ej|@ZON`mCk3HTU+>+AF<$2+U&D`hlv_bJr zFdB$u1}CBVyEc>Z3{Y^pQKA>wA|JNKUdTHzv3%d`b?k`k#y96+_5rS7d3yx&u?s~_ zUR?6Iab}u&-zi3}9&?bn~mC`Sfg*rC0<-wh^r=l1sCXu(ViQGIiqyT$Lx z%Wk~#>Ci@in?b`jG@XR5YKrb(80Q{OV8hL2z1ALdc?N=;yJ!Mq&tudg3>`n>hZ6?z z!baua*y!}m@A4@|Y_4PpUAJiQOtZ_oLMH>4_Dd}zJrDJouHMa`7F>@6Gp9QBIo#I1 zesKK?%xLWpqhJ})0+wTR-z!8u_k;D8B~Nh};dmkDusn?Yr9E@LDk3F9L*&pcM&v4! zO0idN3diEKOHl6>wPt>n}7sC1_mseVs!Z58fwOeFvtZa>Vc)FEe@Z%EKJmo4ae z@_Nxid(Zjv=ig>KWu3Ix<5NT7Qt{cS(xal^Sd^pO&wW8TM)}&h8Be5+$&VyIvpk(f zbFm-yezHYBEY$y`u5Twb{LxrNB|YSq@WZj_uokkd6D^kKFt~NVUrvZTMg*~SmgpAt z39fxlQ`*fhNJjq+l{pn+zu}89!bzWQidhe+wky9;J5V3aFsRy`ydFi!^{iEuD$)4$ zKB8K^g^XK1N#WVrg+;oKQ~A(2FErr<_sY$suan z`vfSjr4%ovr~2yS%@5bHPbMgGUNm>EU8KIqL6wEop&akXp6^Y+-}*u4rCY?3C}W$O zP@C_*mM`3?v;JwHxZ~Td;F=`5=A?+W6#bl$jIpEQ&u($I(-TmrrAOoMxjoYE8+iOV zWJ>4D`ab%cU7LY`t%J|~uDr15A7;vbzO0?s7ihU7XpC2&D3#?<)LS=t$mXtn&wc-6 z!_59^h-n@`UUK3L4qUAwMX~FZ6@Y~;iG2zGsf`rc=BYE5mh8#t>7E#k7*9PLF45IE z$vU6Cr2gl8&Zm=q7pn`|203<|6=n=o31rRgg7{4zgD6zb8J`rVbmc!ie}CO`|Dr6c zIeQN)5IL=eWtbWw3XenLzM8%a<+5*#0TKuebU{x5&4pNRoWNCl)tE~U~ z?1jXmF8)}3QYp!2gXW1ZkMMp!oq|}g28}_LKcb7uEy5ZUixGC;{aZYS4=PtIocQr4 z_1bnU2eEVIhfkxs`-yIx>Ji3wcT2vaj>YMDZHwvYy~^IN^0?#gKD2l=0E9<>=e=Xb z5)F^O)2I{zZ}-$_bb*#Gs8i-%O(=E+9pt|tYPb;R^cPd_`O{uL2z!x`<-gEx?|mcX z^LV<^-IvxsM_8@MUB^9L8iWhpW-XjDKB=cA;fOC~`6oolIMVZ_d-cBDv)d0`h&U-M z#sSqa%U<~8vBQWgOwdo=epYdIHVr3p6O;2_OxxlS<%-fvIfLRG zow$u#0z&7+D>oNMSWFi8vxM(BzWt0!D!BX7>qkGGFpgo+PgDKVx2V*T*YR}s__~Qd zm;=l!?`cJTw$=OS1BXsjv>oGxt=`-)Ph(9UBTkLMP?Hofb`)L%sQP`**acOy^>Oo3c z2`dBm1qHJ{WW#8;UFY38?eVf-r0ZU#*CGR`N$e4`aViS`S4_1b=Sy`%QIW3f)s{a7 zHX-krwj~I5*MQx2o}Z$Y+7|X6PM^q|7T-n%EKc|Bvv_Io^yHsGL)=_L#0A=^CL@7m zoyDlJ)84pVGexDTGOo0CiRqe;PekJnG8_k##vXJ~LC23m%fZZSs50~V`}^lUd}2b4 z>ER{GW9;z8_0VrW28$g*(RFCEUz>riqDZ#H=)uQRUHizp_B#0hgE;4rdq^xq!yo1` zVUsdFdq9bD{OUxXQHF=uu7D!YU0xcuHlPfbqTmqGigaE9HB(Sn9j`{4GQ5&H(bc~Nc<@O=dWmhAwFBPkavd~olpL$RfOs;1xrOng!b8f|SI{E$Rd zTs7%zpM!GQnw!PxNh^z&zdbGHOl+p(UE(alZbcMu=h?H@FKg@YFE5tSd^jdj(KbR$ zcR!mURT|=A1&sed-}2(gr{RNaXc}RNr>AdV(3@c!azWG7Q`**VS$dXCzQDAFiz-Lz zr9I6FVs~DjDjyIixO8ZvA(?TGWBFb|>a_Rz#WM|_uTQ!TUR5qx<@}QMpYcT0bMIBf z5WJKzg|(ObhnO6(infQeVAWokH**R;eGXIB7>*+(^c1kaz$OOx9c%gto4Z?x??CpA zhalQ9j!QL!Ury5E@U-=wW?e5}W>Dj;;;c7|H|i7Lv!PleFc@ZWL%D2rw}s3)t3{>T zy_3u?mO1Oc|9-pveZ`(jrdM>sS})2lf&{piXhtlFuWT-0x4+lO=qnkh0g z&D-soK7I^}#;(AtorMmHGL=-~}8uJ~xOTRUv+~X>asM(@Kz>4~%|AbXkn^6+N*CcGF+nJP#&vb(s=wb36m%*| z9pjHlu<5vNQm3PJa?15g%bXPdkhIbV+0Hv|Io|`J(xvL;^!mF+2;w~N(nHh_1Gc(n zU`C^l*;hLrdf`o(Y349P*~KbrV6lL(COl}|k5-7Klg zz3a-e1AW{%>z{g8u3CQS{!rT(S^mgPxzQ#s3MY1g`?A4pH>-KtkEVIKZ@_!n-Xj2d z$l+QXESf0wEE=1d%+gnQC{Dd}7Td(UtiJJ;H~yGW>e}}G?X4`n5ssIL0d$fRW0wpofU(J6YlCEC;!IN zEx5`Fw0XiwI9-Q1CdY(9gua`~hD4iU-2V5+aEJ$OWd5An<--S(ph#Y4MO2hrTF9+O z?+0Na9QP?D#iQIC^Kv7fR~?ADr@zkc%D9N@J#5qFNo$6L>!IXJAr^-%*4$KPQ*Wd! z~mwnL#eXNV)=K=fzOrc$o_i2fz@{k;=V_{HRyq>HAZJ!=xA5Hbj z$dI@@Pu+(lk6PS$SWUiRR|ty*S6a+5!WNa+<4zjS<)(CfIme8@V}1LQ#O=&}r=i0o z<7EwVMT)UTb;v*9xQOV+@w!7?yonxm&)){V_z6S|wGOgS>%go+9i*=5X#(*$XauPe znkQzLX;?@%YuhzPslFBFHJ%ob$z1vV*0K8|QYt0fK=H>Ia;SAPA3f&$F}gNyKd%3g zmzluST3YC>aUDsuCVM2kREosD?*9YDM@RT?Bg41};PFy}Z{ViQC?K%AFqJ^;Q>)N|VTxu2w_llQx;E z{Hhe(DUxrY$IQ`lh@>yusfeND)J3*0zv3nZInO2ufh%_$wnd7qo2r1}AxUV?Z866o z&O(o4`0Ht$-SYXg-NC!NtlUC2FGZ12X?Vun;)LCMum#3mmvO>UydIaL>DbmxbCFM> z;ZD+e7C(sR9f}RGrVh}ATCksq0kI|0qvtdAbh@0xX?%$qS-X@(Yd*7J0%3T>#N*cy zGR0LV$GpyO7qtQm2+pfbDb4>CDL*348F`}PHHpW(a#U-kK|~buoD`=nbN1;cW}&~N>?$UMLKdI%pZS@UI#-Ga zJ=4zqc?2@3N0VkbeJ$+qi1Q3&&=q>8MU$cAaBvPul^#<-4hGgM2C7+xNX71pdz{C0 zpx|$TB_q85H)Sgu^%SY^*4No5_X-Z1N;R8CzXe9|196v78A^5!m&=r#8&C_EL8@HBA#@ zLwpM^uq_`{G=6ZFXGNtl?fQHkKMv~JIeCA zUc20S+z9!endE+QhoAK%cVyrWpl(wfG%GAC`CRER+`{ZFp7c8-oF4KfD7|;Tf85J6#rT z35W;+mlWSzvFls_D~Szx#%1$%1#95+?`FolI#0L-A8B~n#BXyJ4f$Luq$dFGHDj$9 z={-*2F+Gp+LZ4Pm_S1&A?PElqYfbkUwwAF}AAwM@N8l0Pc1YUXh1tnb|nJX3CRFmVCi%BUT-ljxOm7P4C<| zm&UKvuXXLyf|8n+RPn3NM$1w5zgxBbw590A{`P|J(363pa|uzYf#>&#fPGk)ZIo=f zMyJNYMOn;$#m{f^< zeY5s_EMGQyE7*4^U{h8a*=Kk`-)inXYuey->1!TB9`g$- zit5ptPDbvANhByjp>mwbdPb7!S^!B}){ z(5Ptg^-pjkfCwo;Bv$ZLC_5bnR7o>qE;z(_Y)dBm4RalYqv}Mf%+dZlHCjok%`QCE z6HLpKbmd3%lY!pdD&!u^=k7`lEDoxu#Qaoj)AZBfP4v7Unb&c7)NmiO7%t^!g3;)i z{V+1fj1o2dsL4hB3hrBj;!bDr#h9XnAgA%G*VNN zz~`iCLX^ z0DMQNj3g4o2oHk=hBtot?a1e;G+EV%UmC6EvN=urT9%gg+&(l2SCGM#L~pn1RV6_l zP7Z!v9bqHUx^gA0K_8MySTU8|5C}n{QZ}f-k+#I{P1Au;48(HKSaeSEx(%Q{A;HyQ5c-!Q2Dt_nHu)Wf|tXOfM5|QR~O7nsa;nJb! znIhVJc(Yr#UV3=62F##*YAC0eZuHh+$#zs7-OB~$%|*uDBYSwGKZ!Z)0|osse0RG_ zM^_jBE5VbwDfh5XFv`k-=KhBeH$)gm)eiJY#^8BmBd1rk7o&Bo*A}= z^9XMnhFv7d|F5=lA?1a5iNXcijrNGa5tF#)T>re5nQ0-G{cm?pynQL$T+y76b8}&$pj@sJiopXenOIvo8B{>Tk(h6ik4RvD85ONpmhwRCxHa zhF~O1+j&0nw=t^C)~*v?EtYs}WW`rZ>Tx`Fu;aYFR-*?ogN7(%<3_y9%Ggg8=pQ)L zb(SVW)TK-cwmIw|9275tb>I2$USy_vDfSE3j^tn|(P`@OBlq~ok$@>c9U+-LWnJD+ zb1LCWB`iz9FnSQs>J|qQFr^#53b8@5@2Lg!5nHf9YyR?)LZui(LH0?bVxKsQ|VC?xd zmaxvSi+HjGKEkVM1!}+?W6t{kV1J~g#T1{V#UaSY7gl0FI5KkssZ($zeW>D^Zhp>4 zd^0i1rF(CZPE;wCxpF`xy8S;0OsI}m)0fgN+*J^fN8-G1e4rVYhA(E~oQ^TVbRFF{ zs(`9p{{MUAnClR->tA25=8(SCqsJSH^`B`L|Re;pUm40U`YTY<$*;g zh||Fhf`9*qNJ@vok8&Kcy@7AkuuFMcCf;pK%#QsiYU;gWf#jdIxk%g%sHiirX)2z@ z)-U`ROeR*sY80}`UPwCv&O`8hqq)zBctB$0ODG>~Y%k9h;?K}`XiWmI{V=yU2*mL~00Bxu98Haum3{wM43#cH_EvQYS6H@~M( z6kH&PLISi~uzzMk!*4IBxDOdAw9ka%%amZ{s9%ow;tX)Sk_$$QJ9`8G`tKhjV4H>2 z5PUTolV;5-(@X40sne9=S)1E%PxD(;ma5kP{!YNO|GOiFa$tVTcA(`D37x2MJ-;YmZeJ1snhl zln}WG`cOX6f+#Qi;ay~PJjeq40o_Odk2v-RK<{GfwFxJX36y%+YI^Oe`$@!46ssXT zqNQQlf_TfUWuS6ZiQ$q2mlKM(90QAu?XVll3GM}wL$MuR3LX#QCYBYc z9)T9>&J_bb;4;-`it&}j$@bLe9rhgu*rfPiXL{?vdn8YRntGSprHxwf=C`s-Je@?*t)d){mvB^*?ZzDaLQ;PeFUFY;7Hifp|cVLYjND2iwnP>- z|N7Np2FWsnKtM7>MV5&``&GW4FJARGhnLvTEd4X>5rbZs=n{kld@p0PjvzLRaCsw} z^;~i4a;1+6WtVn4ndm#D@Prke4W$F?9Nrw_XNv0(bV|r=ukqG(5-O4hctL0m`M!!+K=Ld!|?(*Y3}1qFpTx914w zKY>AV9SHZXgfHIWb3lIc6AE}|UVCihgPXz(tRyrD z?TN?oK#Y;f69Z6TpJa+`gAy%gHJIK_0r@DsAutB4j$w%;0(-g7h-*QL!}Y*FiFg}# zsNgnS|GVRRRBgutk%{Y>jC_3&5)#@2zvv@RHr7?9^Xk#xL!kMn1E!z zr=YH59?X?P6bW%-Li(CrJ&VcU0Xk~pC+Z4<2WxX{0XnY?E)nm)9)>3b7&;2kia_D> z?%lgm18DyFd_#cgPUkjSVViGg`v4m%RyA>u@A*IGK-~mlhoek)Sb4!6W3QuXna0x- z+%jXE~;Uhv)IqagHt6GxANA$N(DX?vb<^t8c3C85H96)kQXD zqr@-t6g0_1z(%Ce=UPzoge9_R4G|FLY@pYq0Od;% z%B5iMUMb7;Uw{oQ@>g>7Qu`0$03t~|Cpf$cFdpOcsgBz^03@H}*)Z_3F#cmOKZ6XR zZ?ug@91d{jH&3h@@&&)_a0E9ceAqx3+Mi5NSIdu{d4Lw3WQ$bFNO@p}^ zfkYWZ`T@YA%svp0;PRkThp0fST-oVN7*3mO>%krS|7SP8@lXAFz<$EAS>2=qoJ1=6 zwje&yZRCZ@z|xHqTna%;(>&_{yE=%pp~&8kZ-2{Os9b7Lr(7lh6frjm(8lPqJ>K9w zNb=fPR|l<~QK2hvdkDqF*Nlss!Zif8RdKM^koaK}v}AcqO@N@-cZhliK|v;ego?ud zCTx`o@2WvcOV~Qn+p(>=0`*mY=Y_#|XQn9{k=3YyqwiBtQzU*GIRk`kqU`Nu?ASipQbxdOIWm)^)6LwX&+Jfp4rK#EG~F=+h%b*UZ3 zme3ylpG&23_EC;F@~%Qd0?~<1p?t43H`p9#sLgy#|8*qn;nN<^TDbl`>~LnPJc6&> z@OxW-oF-oq5Q}}9c9ke|=(xjFfM%B~6Ro|+2WG|-1+33)q&araV5R3c(m^$>1XYJV z{)M5ykB_p5aYCmcRqiXxrmUMA_HZ+_!)W`!__Y#Dj%5yqBiukHSp;aLIE-8RFBq?l z=zu*MFJJ0?B#?Seh^z*IV0YFJQ|-6`q!ntW@xQH54Gu0YF0c4zT9gpI_+Xs90rQz_ zKaS(XNzce}nEEuvOEv`ZCLFX* z2ev+BEqqPqk$oAwN%S3$9zM*ZS?Ob6=L0_T><*pr^N`GW05ff7DxhR*&cjI=JRbfh zvn4@A30A&zEB~+7hw2}5PUEt^wrF+xi7B<_xg?O2QhC^=?zl1r!~|nMtBlJ}W=TVq z*K~W(o!#gEr4myXHeQ9s90;0W`&Km7lJI!E!ZoGBL-l)nbV*xUS{&5O*MH_8){G?} z%sCIr97ofB=vbL`7T>k&A&|7TaI*g+V8};3LVM_i$5)*!REjVqe)J(8B+q~T47e#x z4)H+@^8;3klQ60ft(}46pwf@}cdQ zjN>GfPOCG)nC|vZsPYW}nT`~1Nx_T=if5coO_5ISQf;WS3<3aM3|Oph+$sfR8T?Qw z`E-{@aOaJEo`PYvd}>QPYz&DH%v1s6sul;W7KUI1f!o5L%r-YG{{_e@vZ773WjZqX znq*e)w8{uW!FmWjAk?~so+t{p$)Fr?<52w;3K*V6;1Id>fezpq_mjte^E%Kz=SvqwfG@MV@3@ zM)P6&Li{T10(OBCi0mT@rIG-PJ29PS204{s!M$0#{k{{<#`&dqYy``_E z_56p~9+G4P?<(&ur8qwh2asEt)oD3?ksHAKR}eASx#^9s9bkm0x3F6Bo__V6lOP!+ z2ZHBj*R#~rsQvU%tXy1K+aDa6AIB}?wd!Ih4lLx6H$u)RIA17?hh>5q$U5;2={?E_ zX?cUP1<^DSo}nsDMBd+Ff3Sc5HDa77zro?TJd_;DSrslxHI;z@`Y)l`SFcWV$w-oY zJ(2_&FmR=4r+ZC5G7cCi=qS92c)H9uR|xV80iTxF<)2KHlM%!~|Js-D_MfW4_D``o zq_rWeqpe@-VWTTLNVV>gdFaFD2r-M$;fzX)f)4GUPze!$rHtCrYBT2m=pthl6c`#y zR1O1ffVLQ()b-n$xaI(~DR}?IA;!BPQ2O~pWMu5fX^)C8z&yBxb}vr&cF2FK`~JXIjP^je;?3q zmkXhR3aFq5OATkzr`vgdi+xyZ$}cuTF-iBS!@CL~8MHeehYrMW0&?Uy^~fACtO+9{ zG3KM|Wf~6*OW#>`u#2RDG)PqN*d%s0wWcOEwU7SLSMfAFM9<6x9TijA3*gZL7TyuF zfDQZJV@Sg8eQTua4X^#SxM6sFU^4zaY)HGT5@>nTAHE@Sb7QUvd| z=Ss?ly%DxB>_uUwberrOFBE}|jEt;}&G6aT*y(0g5R{^nloY<$${9r$ugoDzry~_JY0EPQb6KvvXkQw013MI z@-7StY`s60lJqSQ#>*s9p5rBcItf}H|GfxGWjVz+*jm@q7pfB+=Vdrug!)^9$bhZPbAceCvJouMpEEtAH$ zGk|u=xM|JpkL^O$4i>~jMSbt$85b0qYWs1@tZ*Grdpc5<;SeyAXJzrpe&p8GK*|Pw zz5fiKw^Kr_-hSXP`OZyrGdzZ6f=Dgc=O8+$$;|Bg(m|1uQ%6Od#&oZi*xib%RpyQ7 zhOE`-8=KqEVSXW@1-VRQK4JSXkiTj2QyGaSRGl1f|3`X)QP62VVbyU`?7sR(GI2TV zV1eZIgOQYPm$DZ?@ISzE-E4z|TEG2JpMWCKDK=Afk|uJXJ{r6q=eHvkO%zkMPEGrz z19v>n1Y^?siND9WeQTh#kB^Co;XTdarXvTj-??ZZL%pa5SQs|?02yeP z%mTkA6e$*aGa`1D<@TtN7>gXF>)z#VKUL4XEjbVjHq@4Rq61|SM3E%ae&+%*zIa;| zba>Ck{>+F-Qa;kLe$IP+<)>Ps-9Zu?GI(9F+9yYMUKcG86Oz|yON=cr1V1}4Gs}Hsv5)pT+ zn);2A55$K}!+@J9EOilq|8R*z_aWR|$}hwyP~0Xp)T!#TJl0Zk!mKJ}j}LGbFU2 zGh#l!L{QXV9zu6LQsrWJEaO?~A+qS3xq_#kFMpN&#|J0pI`mqSdvLu}dAdi8C%>;j zV2=?;5+d2HijP-`mf4GLqlmD|wFj)i&Z+wnfGy%Cbj_{Fq7G8q;^Chu9tfp*Q!&4w zUn+&H9W0soAm~_kxr<5g%*?M4D=n#hwR($oH41AF%@1jfI;RY0{@2M%@%HpFc_gsd z)9jQM4TMEt8BY5k29Pyp2}?l>NMYUY{9Z`55~THy1SKXl3;}0w`*>FQ7oGh|;pl4q zXthS%y@>-#jaS>1rbW59r@jkCUE&oxKq>O9uG&{)Wcv=Vb!Y({>l^bfp}}W{cjB#F zMw9O@h_Z>x1E6?66WP0Jmw{Ftz<280a(zdyqXfd4wV>_wQscwG)iWuo$Me@H`Mum8 z_pkmI;2&DfkGv)HH6CJ{A_SYhLPoP=AFvotQjd<UPPHW~QmZQM~A+fm_;U$$Fv3iD)B89$P?{`+u!%283LNvBas~m8a zi*TQB)wug1sE0xr4IW+RI*-PNJMWU1;x>@1S(AfK&Q6I0tP7~Utfy3xmV5d6Gd zQ-#sP2O*J!7~@!@267m5g{U+zS?kapDQhEw0W(15RXrH%-p@e$E%APCZS$}&A+l?X)6xl>6gwBOW8=ET6o}W~y zW;0a#lKXAu37zcU+XF`ztCZgSWTRitPEBjKg9SOzA#`prrven)wg-wwDnegVt%!Q6 zN{Td|EZk4tM>Z_ua1Lk$dgJK?Mbf0&f{s1i!jLY)h)Uh-c37pr&(BX@7i0IGw8f#N zp+&+y=cL!Kv(xb{X$!@^XZcxV^=I;ig-gcQ1$cyma4?=#Xxwm-_$=gaKE?1>p)99Z ziNRP6r>35s0Q6-x%ho1TVCk+(bnmLk9YA$d^?`-UysZ=XQ>@$?hlq+{4`!tJOyrf9wwQZaiVAKgQ962EQnIjSksq zvSm^L61+7uplCctEQVt-Uy)hY$hU9bW=sw$KqSO(Vjz*gG=3^r{CWlUbXLWmK`JDq zhq7JUpO8Zx&!g7?dVM=sD79fS_4`+y)Ye}Ic-D;nd)NMY=FLQ*RaBNnWH2&XFI|88Eq4LDO!u_R3E^CYBpC>*@tuL|y<+~ez)Yjn(=6UGdN0$=h1SXuVPx~p zQ_I}&nVFg7w5J{O*Da!#OYwiKqf%s7oTm%VSk*dhdLNlws+V3@;9qW9=Pq8v zjJMm-k+49iwpqd8>5d(yvW-Nh2S%dr*k5))?@VPv;V2bp$Bk+S?V=<>bJ9W%W;VR^ zezjP_%?CJUbQszm3^5P2=jE9q zC3LEys5jY4Ywmp&&!Cu&>gFJG)No-OhHx8<;+01&Y(!PML<;c2somdRRG%~0)~{Wt zrw|CtdSbECsE$eBRZ@j~>nrlpBg>_(+*_&2nb+ITX_C4t@s!>R zWqsmf)#*QbXZC*O3xp%s5^+KSsw2BjJL~_j_1^JR|NZ}XPRF~0$}FYqm8=HYoMdmQ zD7zFQqs;75QT9mLnTd>2HYZ6W;~*;{BYS0LejhL89M|vj`{#YTF1NhA#`Cf7_xt0S z|8S@6E}DXikkj|HHCP<=xq^m8Yu}eAUMVnfpI{{O{*c+-;R zcTT*}s_}n8O^eE=hYvLDe6F1`W1Obx@kBM}AQXfA9xL5WafSfuC02Wl81FBS>ar`=~*qR#g=sc7E9X=w?a8HH;i|E~IXX z+YmeXcA*HOB*vINaL3vhCfY+HHnE>iaTx-V2Y$n|ZQe}4^jdxYep? z=&3$m?HA|DMh=e}@0mBh>u;2@cAc8Lq5tVoOzMaaJx98s2v6y-C694_^~CugcB)YL zCp^67dSQZZY7@UAD^B=mrtRbnZnG%P6Sb6aHnWC=-30sjgs)c2|k?@*oeDZ~;iAg=zACZ_K*_u%@10jIf$VBw~3QQKOY`(_0=FwkjuxY#nNj0x|iPhU5om9)vYFrJbStHaR z2tpMKNNEFYSHIeA0ck1_s0LJT3Sg2vd}vRi1ZYoe2)tZpJ#z%5LFKai^AQ5DEY>n| zpOqIIiqJvs#T6ERUIzgsGUd0X!P(93vn9>HpYU1E+c8@$-Kfb*zJ)&xw{-{T7JLGR3u7rW2teIYwU!J6fi z)=gD%<^`Z|@Q*=)Lgs+A*PlA$$Cs>^nh#>ogT>?7;bm@1Tzr!$EgE6fo1S`ChCMhC zUM}EAqpQ!Co4ux6Wc>Z{ZTB?u@uAE!TPE_)F>lo`(7=*R?wMp)S|i-SRYVUP(XIUS zhK&&&%Y$qJ4x-RrXMuoU3;^F^MaYVW5`s70uCNXno12^0UDP$?yng*US>rp?Mj2Iv z05fFHtdzXRP4#~D=(}pVwM91`50BD8!`n{~R{C+X(tVi&@af5Kjp$S72$du6foJJkTLMW7DlS;5rH7 zz>ns~+Z!`jzaMNj-dxcYv+MJ|HK~uc`&i)^{wuRuwQlll3f`l@Pe|?cyUxB1+tk6K zlVNVAnvjJs@py>n$UgY=&ZzFJGua`p@mt2c#0&}2Q0Zj&If3A&yMO8 z%SW%-zT_}=39{_o$cjAg@|hNSJA=LFXYprRti*o0lX%99dLfIMwj(SQuxW2U+bB_N zTh=brK}2_016FU}I;$!K>HY%3#(R!8G8W5Ljlg}Rl;NYG7swiuhJ{=|T!$I|^h|$^ z;>ju2dqEFNL7aQ6HxRfjFmF;mwH*#?+q@AvICw=7QdRGWwPCL?w~fHC%_z52hpz!p z0VlqNX^@1QyC1Q@#xeNVy@(U3XftWvR&j;2bsh!i%ixV0Q*yhIu6t&THgw%XWBQLJ zdNfMUH=RRB5wDEC=UdVWyiZR_xxhGA`2-e$e3zk^e2M}|3y z25i;u%y{L>l0$9}R2R#;`*w&#z!w4PFaX7{Nh@i_+iwa^cqOXK?ffle69Ccp<#^jG zNO<`&8hhP+vW1352t7UZT>*Pa@&W~=1au~!H5~#`NkN2D zwB|YTX&UAHOVYgI=;0G4-U2RwGr#sZ=o_PsM|xJ4T6Xc+@!Gn&JC3hvhu2^`pNmQm znROHwdqU{o+=gb9=5JE-@x@O2awN0|Q}4irR0)8l!ZJe?ML^l*9oP?S;s(mLyf!R% zp}k)PorT07CDST#{VQ*bv8$c4uw{5uym+Ba-|A?KVPap<`vA|zc&W%*zRBzgl_v|~ zKxEGdlP>gH&IE@2vG4?4nxDh||I?ec1)>P$B}f1#ZBcIsftiK}#7q)IY>n8?CE5a@ zUrSs2MV%B6k8(ldev}5i%RFB3I`qnmPcXX& zdN^QL!1hvDqY!A0O?4C`LMwn)PK&<=NYsXKUaO;!EMeX z-+SZ?UmI89R`!J(K+zkyyg(T1>A8;MmwL+So$_VGMZwX~pXXG3gtVlVcTw*sqc|aR z;x|p9CjJczG*BrxK$SS)pOO$TT)3O^t||6-!sKhB>z%5z+Cm&mSXG0Wq^g$nFyH35 zWC*{Gya*O*xG3!l4G=fnPDV|)7DXPTll@!f`aC0DobDAwz<~~vvA4hQyfOKJ>N)w% z8DVN6dvM1r!xBD{0`q2ugiVroaaB;RI$|u{onIBEu>De?=%jKMa{mir6xIXejZ@t* zOW0Vl{XuDbYQwozVaFv$fgL|Mc3M%W+stNK?xzBN;#*MlVpye;wP*L_ULX5`>e`SG z=Nvv5z;07yg*Wm%jKvM_~j(*UrgKDCpmAnYL&qzWXuD+d^E~amxqh+iJ+> zt6S(diY)(;+~RUuc-_J*aj`dWMfgGJ%h5u-4+@aK38kAGtHm|QnrfsQmobd{fzzYCXj8(0#&jG9Wrrg&26^uk zw`dW6kIPIx4uq>yb90+o{^JP7W^IkTg|#mo>W~Ck#|Da=eNBrgiX2 z^T_mslY2z($Mx>Jc7%S)={*jHG<={JRm}1^;4nMj7t5xey^?^*Sg0bi$Axe6HFc(_ zHA(vpZz_b7`!56MhnC#^13%WfuBz^sSO2$ls-e%nSFsZYf=UQZ*up&jh_1+h^G7Ac zd*eM^O|Zt8fmJi+jC!%d==p)d$9rIl=Edg{&e@MMLc>3zmtFgFNm!3=8`LfmeYAV& z?7L5q3dAFMle+0?AVA0gA_((u#ge1>c}+}iX8GRUbEH=Q`@~)YtRy8^^?CEC?ktYK zpqmYVvbr$myB*@KFKz3f8oQt2iY$=<05U!U_akpIloFc}x#}jcZ{>|yEzS3?bW@<$ zo3sZw2_6p1bS4El+0cB8W)4X%Jb)(Mci8@kEL#`;4LqewJ`hftSIP4L5xCz# z)o80p*p1NxMa7=u%3Z`8w|fIVi92|I9`WKB1T)B`5&KfsS2LlNs!n|C>150Khxfv8HQ$t#Y5T`m zev%t+Glk>L!d*xP0u})S`tshX4S|ulKS?(q#ZUp-`;xWHc-GsSzBy7;NZFNXZ}4t6 zY;FxpN@DvzFd!BI6x0Ro&uHkakllHI|A-_{uG^B$i>9gC7u=RdNGGE44bu}ODy zxMTt&u4Xt}471m7+)#n&Zgo_5)O+#t-9DVp@l-j1{nQ{uaPGf*Ae6s-HR}WLqt~TE zL?(CQfzG+PIUo2J6v)LjOsgu-Ch_Q!O?2cXw_SCEbgkQSbu#-4XR`?cMuq-z!2FqP zMPTcA#<%_tTSp%89c;Um83;B(OA6ebXZ2H6KCE2r6p$l%R>-`Hg%irn$tnMBzX)sM zJ@3nT>pjlBkuV#56_RARzl)jH9S~Y+!(u+z6o`X=r8u_lUxeJ38TUEHSY$urNrELe z&^O(9JKgoJ?hmpa8VYd%M&`-W$h1-54*8_`ekaLeGuQIUaucprFpbq@kv1gU zIKU)v>HG(3VtNZ*TL?lOeTR{VSy${hE*UQ9&qk$5l1V-Z_>ke3_^23k{#7^VuMIsB zEN^-srj`CArn< z0-irt5%(%}z*V6{YT#VvO^n5-MJQq}N&gw7HI#)}LF;5@zK($bpVZxXs)34q$A^>% z{jjZK&if)1PHxBO-n^39VTM@jQ@+b=fDn-fRDd;2?o9&tH~xcy!0zr+-YF?zO?c3=vD24&w+rN4#MdgdvH=p z&4&Q(Q`rE)|3=0%5Y3y0L+g(iIdcj}O}q^uIt-!nIUS$ZXLsj@g?vN@)K#ypU)NSV zwD&*9B`!|RQ5c%>(Z(-~}aL9RQ90?e7o;-cO|btLW{{m(&8= zL9b7XUvwfMS7D>Zz28^%H}{JR3AgIdfH}RLLn^&WbS8Y9CpjlJQnyhPp2980MkT^$8MyF zwFvU4JS+ z;o;$tb8M`TAsCue`jVXjnc|KkNuZ`i_}$Q z(Kg#R0{S5kXJ2BfZ{%-uB?oo+>$9hM2hfH zf~8kp&YoC>e#^1^ac~yfk&6mMTmisXpOciVdS%hqW&XE(A->V zuD)9I^S8J&G)TB95e~XsU!cg3kVszL=-8nXC^q-D8s{CvMtZdS2a}N0fwB|LM1W5R z%ghhAX=O{xjD7qqApP?Ux~h|1(++qWFpS6nX*5+Km`iF(3L5i2hXtlqkqP+aWnP`e z{W3)G4xZwu*ljrgDIW3IjgSbm$v{(Zbm~cJlZ|_MN!~3(#VvVe_~0Pw=ejogdFzAA z!2YjwZVDqpDua2+n`nGTt4FeyU@utQRj|QwSd;!lKUEA(B^nJ~5H~*6&qt<*K+dgY z7^M9!(7OOAVJJCR`jw|&JH{8h#$4cbWeG$LQfTi;Jv~figk@7CK1~@GfPkG7cWD-> z{9*v$z*IMV2R@vRj?Tc-Juv?EUM0<6LQ)x;fw4nVjRAYF0$7$QlVyn*-U`qD{bENR zJ_e=Xe;;xfWAV1Lz@}#`)*Fb(lw^mZoP)RC!|l6wiyv_)1Ewzvl$+`Vhad~jPvYs) zQUaN$0}N{CiAUiCjHbLizQ!2qFz+DGx3ZnE=`OqybQ`MAepZtq2+mci%-}W4ajJr4 z95Eucmt?e0Wfefvp)KYy1>ug+27G-3fjLhUg9+?ZA2bGm#{jY_+B<#}7%W00*Ix82 z$1W&E1}q_oLl=6hlDG}^T(UPda#w=LCG8oAb^j~?Yf56wSGV{0gzU}jqq+;l^>20+ zA_^CiYU>>hXuNbrx$F2I7%&0*c^YDIxyC4`D~kH9u86@%G+Ro5+>iD!zv$Sn(>w z*H|$fL?dT)kBTp*P!IP-xGS<&CeJ9_K#YDIF9eP=6~=D6%>YrEmv!$A@s%Ri_zp`S z3)FR~w)JvZOuR@G-hQtL_Jcn427A|fx+kSB&P&b>8a5yK?~NnBeXg(X!~Nz0TVo+A zDuw*HbN_Qp2LWX6@AT@dAQlhchQ9|21PQ@|QqfErZSo|pJ5kMO<}0plifzIUU_V!h z{O8DSF)>tv`)~i0^mGYs6ShFu1-|$!_x!Q#DCX^5j}D-o+^Be&cR65-+x*wlo9rf0 zf3wOxXiasH6$D>NHsxIM{THF>8M9Y4;+U!UFXTXDbo<_a2Vvd{{Yw7(<8l13I-+x3 zah~{AUyz+hk`m(1CIGc0`4h)qdxBGsKa)6%>5#{5o*kXYns_NYr};27EluGflL%r# z(AtWG3ZDc+Ndc=f?S@+%2v2+tm4%;r(U6w0{Z}ASjyCIke@j25;0`n-^p5oq+z}gg{M19ElzrQmfb}e79OI&W|!TiIWaj3Bh*j%gEB4 zpqXSftOY58?Qa-Qw+#Eo5pC~yYl%PwToCF~4lD<^03GQ<#u#2=9guRYzMNw`9+d>-%;4GY?oKMu>N%8)s^O;%3vwKjh+}*Y1s=c?Uq9DsR`vPWH3`q9OF4z{5S&lv!`>2~2Ush-x9Gm9KMZ zHP|A@pyK$q^T$jVY`j9|^1bp3y z#Uga;IEDT@t_Zuw!4%-apI3A6Mj7W*aVme;5%8Pr@f3 z0d{n|r_Y7NqXBqOZKSzWnzsKyiV9t1rrH6B{i^ z)e&On)BSV=KlN!#Y605;{Kqr>ZjJE zQ%I){AYMkov2@dKvH#PP68hk$pnFhB%H%$CcGe5W{qrof_YizBAlG2G?`{{#5poWz zusFerGZTkp3EqH)BNrHC3Nf5D@i(b4^0+a%RT#;se_P4vv{?z+4ZqEz;sczI8UT(R zz0T8Z<4oe&Zn4C~1}Vs22e^xb7yV4+2f6&0?f;JkK10`pz?fQezY0lay9F~4rp(OD zmb0Wcmap{!>jI7!9~u_bZgr{U@e!7^u(jvRD5jEd1uDM`#7q7@Pmt&7zEjzb=P$dHW^EK4FURX3 zdMw+H;03aZrrw`8Xw$@ubWOmlYDrGtk^`l2pyumWp$GBN(Kp3|22DVq^?9ju8ZK& zxq3nT6OfZGqVf*mZ7y0zAj!Ee`wSQXB9B;E^uUUE)RFJ?9djb7=ZxW5mhG1TdPl&J zit5<)64WPTX==XAGvk@oTW47>enmVdb}t%Q6pZ)J^PIxNIn{Ka)Y^fEl|%=~Nf>($ zoK-UBPyy86m}XN|-` zYRQn9#3O>ZDO$AVyY0I{ghQ1YdVB>d?1j?_fP9=2D&R(eVH6b=ij;gg*g{j;RL;#u z&mE3O5S3op-FJw-19cvanFVSs`{d5pNoDtbmsP$5g!ZlFTFB?~yJ7+zLA4{y@7PFL zsAPP;s%>Tr9L6)rc-)lT<)cTo2BG1g;g^T?jBsx~_~3kEl9p&k!j8{w`3#-MtyTv7 z$3+LL_;!_hs+8w!CJ5dmXN5;g;jf=3c|;EG*btc%JW|l?*nsP;%Zn0@7?oY}U)Oo0 z90UJOg#K(j(i7}$4UPR) z`JW#|Z*Ohjf%703@{khpo1dtP&5e>$fCufjCH;B#4 zEl2m)L(JU6o-%eXYpTyDbj2|cdlvfyV&!oSi1)iQO$FvD$2$XAcO5=iF`572DlH#w z`Uq_|$%P&A^7KAtZRWvGPDc_f`8{n@#%1OF@7ekoj1L>>nqvNGNB2-O19+kPX*%9n zMIl{<{g0n%-A7D5tr9AfZ68wriBZojDHTFU^r0dZsx1fJCsocbI4ikNyurOjM9`J^ zDj<3$-kd1GviUI1AuXkT*!9ZY5FbsnEkMF00TQm20GR4f@y1WQAKQQLEQ=Y5LjEJQ zPY)oy(Aom8>D!hKHI0zz!!EVCJA_Y<)ImssX}aPf=pcNH(D>e<0ht=kmg>z{`F7e4`2a~4@2;7=>Ma2Ir*^_DAPyz2w0Ci3}^|6Jua0c!=8ucK51@dcW&Bl+*k z(-=~p6QqamOk9VefOyW103411-O|Bq0$uOtncnHEaxp6p%r`&VD>fag~py6fh z$WDhT5RifN$_V?gNY#CQlQ9=cCvkPc@s>Ph^7U|IlriO^B;kjRsSojx2L&BoJu1<8TIpiFGC899)EbCg&-xe(? zK>v)A;D%BtCdX2frUg-E`R%89Y97DPuau-c`0ii(Mty zhArlhzf<|z-Q>5Hod065i@vwzKv~ab{tqcIe`ihOW*C%W3|S;3^bdVwD%MTP8FUWx zpCTC}4E?G69%0{XTKKtKP$7gGP>wo)EO8zLAdJ6lYAf`VPEsTJv5Ja{+Sm&%cyyc% z3e*Zh5GpZ0Uq2Ze7%7H4op`(rxI26W_(lwQLGh9a^_QcmR&0oYQ+J*B6m zRZF19kc5|pYX;H^&Mceb`whM2+(s@L5OdW&10OT>H*-VnMT|;=g!iwFNMVFQcbVSt zZ~|EFIrNspD?KM31PfqrG(NCv<&nHV=Gy8g@8fRfRgBT-2f1x6p1}p!rvHgWzrBkyVDB+37$3-4S>!;QBre zvOvV6mXOp!%0n5n$yiSLKyWc|n&_bJtnWTR51!)lgXhFhf~JAIU+M!Rc7gC{e54LS z5*2Gsw|f)mVXTnR%J?$5&JuS z;W!9G4;DHHeAR_9RociE;Zz;9N9(D3IHyCL!JYVndvQ{~5phhrlJoUnZ#9AnxJlV_{D*FsMR0-W0wH)~ zIAn1UBZfq%=UWM9qv{ewmb`^j2Ut*H2THy=3#lrRrx>>aiOX3N7@NHTSp-3$Z}zvq zih{;Zp@=8I56dDZArX@?!0t^{*Mb-<-XFQpIoW-#>LDyj;pj@98vvOfyI^GeFcDu} z_>vRebn9~=qN_^8`V4lfFaOq0q+})>k081x{6w)655)39ojxF%r#(EG)Km2Vnw>66 zCIF3Py2-D;1M{|vM1m|=p(O6^eLaFHJwYF;x1r|v#A2cYhv0kuH4H%V`vs5%*Ozlm z&UTNdR#rk;u2V>vKrC@@%p+b%?zjnTEB<|ihk1$c5f*9TsjS+v@{CR7AYwfwJ1SM# zI{Vag!|N=9ZTKdC9^g1t%6;LQ(*8Q?7ieEWWxx00<8i_xp=0?%V#C8fGJrQZ3*O}4 zQCUMjJM)9m_Z-^bnBCwAwN9p9a!(aC{sX`yQUHlU-BYIyg{GcQoP;xZuNTetJsa=B zEtcqi60u64jZy19>v*l8d3#VY^JZ5|wOi4WWr;3&Ej@@E&*ae2=`_YbZjj!KRnEaD<8lQomg^ z8Z3P(KFNypR{80vsYP$%X02NRH*b2OJ;zu^3;;U)mxUdn$4k1kBQmFAqw8MSF=FP7 zyhDsSI87w8-OinX>$;%Kh*t+Vi3}hqil$-z$3Y_ zjT49QQybE0kd{ z`~DFT67X1+YMhu3S)5nk;`vmSPBsDVJ)vG>%cV||zzlB&ZNk!XKfte&pt4$Qf;HIi zHo=}dw2}XB%I5b3kr285;U1}d#uISiAln2Du9oIzm~4Jz$2_%Y=TeUq)rR7Dc&3e7 z8uf!3VKzH6SPeW4`@emS>eyNLKkvSV-`lnhA79LgXeri-3y-mt=r!6&_-^IAaHqj2 zia(PDy(u7QLF(B6$JB&*E4o3kI!PO%$o|tgkZIB-ny_clMGahlTUNag0X1(IwZZ?FRd1<85RDiGOtFA=H~o3Oa@0DjrG-`?2;++KTHCE*j*-HgJN&?bx7CtNkH5p?hdNDbXIM6u*ft0 z1JQh-axx*=q@IL8ciYZtg1WfEQd_&nbvW*n%S>OAzyLwuVcWM-*=1mFL+z{@qwsd; z^>>jtlP_~WP|jEEZG54@m{5@hcU1?}t@us4)t!HD>kal%`?L<4UDGO2j8;AUFP~+R zl43;DljYm=Tmb@kU(!K59k?QSa7D*dei{zgGK}@WOOMcq6G!;p=gJ;H9AMEvfrM(< z`&-|uGtRu)K1W*#Lk={(^Jl^D7+Hx-5<=rqL4<7+HW4%}&wvO!W#O5g>zg_=iaWf_ z4W?M1Set8%x?cBG8JJ!aWkHniRm%}ks36-1ND@qZj(8fSHVz4^e79GPmVEzyUMT0? zNoLR-Dzw`N1L>pjxY~72l?cB?4x3t9KQ4Usbs@`UInR|*?xLAWin+&#)1={puFV=+ zk(jO_f28jQ$*(}?JJZeE=sml4xYi6E!yah{5I7^H0AW>C0Pl>V+AKxveLd`!XMW~R z&sMy+`R&yy*WYHN?KugXibr8h1_}*gmQmhUGKgUVzGEpQ>pi?u>JtB6JQyPo-3}<^ zm%LK7+>0`$SPs4k@$Jlu(T5g_`NM(}sZmB@2m(?=^r!DyI<%X7L@A&LrT{=y=HV+D zL^%2X|HZ|l;uE*2zWvl^!YJlRyxS9xIG zqN%F-MHJcFmv5YAz8h%0pxtkwp z=^=c#k|WA+*b|iy2V->VbI)q8;Zq05=NfzjxzIkQw z#r}o2w5ZP88|q@SRkVRiSKi%J{*ejfnDa1*Fg{gg-TCGz*~l9q)hL0;1H6}NK&{PV z`iO{4epZkReafxBLXUs*ZuqKKSs{BnT+c*t`3>;FIyi>O6wxJ&Jc-E-nqotA1K)B@&l%GghL1;U1urz3 zp0$X^$$+qIpzekhQV)W(QV1-{teYQg8A?y^Jf%=MTv469%Bu^)WENHbb24D>UwuQv znY2Le&Z(Jr4)=f6!b||g%A#`KE0s^XYLeYeKLD$u(l9^4P4=K+dx->dTSb{PY$VzPpxjHCYiw{%VBB?zTO}??TnutBR)zEby`p>W(?KQHD;> zM|eTZ1b~{yV1!fT{=1g@y$R^{G5R~{&!f-oxQ{*ol53(R8ao$+!(=%vu)vF%niVxm z(^1kc=_twGl?;&+Zeaz9F+dm`1UPc!=|)MNXAcB4xi+T3gGV||cGZGzkl=L1W;r4? ze*5-qGgx%}8!FaXsikgq5T<3VooW{rzrGQvYs8bR5Qr>Huk+fNW4`vqy`rxFF65lm zg>8!0i60YO^FESmauVZj-FEa`M2$^g3rK@4njh>%75z;72aSRbt5fv*GDujG1P%4C zC>C42`Hl10o#rBztC0w<;x>>OR*l53lmRBa?P4E341UIm)I76r>|!MsT6GZ3ltL@( zo?_uC$MdW^4iu))nB`(ZH5cUAL4+I|y8DoSet|()TrbrX2(eEw5R9LTOW$n+LsT^O z`@|U`Xl#U_j|YT7iPv=?P{a%t;~Z@7f8Fme>0qd8nC{U&Sj_beMw4>3tQ?8&bPenu zjHsGh9TK%mghi0tHrmL<(#BDnfM!G@xr-u8Bu9y}c+As(r5-4*fUyrx{6__VOTFWe z!KsP`R>H@)?(yQ_Q)G^ z3EBSW*3&FAD7rmmnX+3So{SzJ#nrtBMq4m7dg96pjiT6R~%kFld$R5enLqodWV(umTZ>5hpNJahh3!G?*6R!?Lj~H^@Vm|yt^F!J53uj z{Plb(KOdrXiht;Z_Nu#}T@^3@4%D?8=fAIBwJ;sJ^?*A%21D7P%cs{i%L6XU({1g} z*h+5TKk-O2IlVZhdi$+}Lq}SoXbFVK$DuuJQ2 zR$tkF@ms7Mghij+D|h?-xdQ;cW!`v(W*WE^@762WL0(jZW;9wWM>i*awi%4P9nyf@ z8*|So(Em{~S$}PAD!OCdS?rjZ$}bKPA$3Um(9V;~l8DNHge*xgEqHhjp<>I;@eaBH z8v*lez2zXsvZohynMuq$SDhsU5NXsKLsCwq{98?t*gU z*OL?|139`p7=BI{^5dD*5<#pzDF^UKt@E>xkp`gGUYvUr5IR%bR#NWp(06SWDxS2} z-}@bUTs)eRWgn0y$vj%Qli@!Pp=H>xQUb+F5pd|F?A^r)9_YIk9R-c%!Bz4Stxb1b zn8oL+E)$_)NH&g9g|x@i-kuj8eYhlbZFNj?RSUghKv!E1~fN7dJc|xz8sF z4RPy9u`eJ=U={1ec>cK3)%PQ4hd8IWu~_)qG=d>dpK=xFp9Siz8IZ-aNrmqGQZs$M z_!3iu=x!5IiZ%54g=ZN9>lZ}-W)v(zs6XxMf!E$$*b47`C=%!}c(LQ-joIIL#L33V zxtTe2Kfq?8%hwn6iw1%u20?G^N#SE@j}0U$gXH|2M^& z_ek?c#JO`5a3#~_yiir-|Ls5#UqCzzHyavm$d#CvBs?TGH6c)jBlhbteXH}$rxjTq zn7i>&y8x_Do|d@yd@KHYGeUA1ez?`F|hkU`oofs|D7D7eijxQY6|US zNEfCMcd@WuX(E5G_)a&`v_ZLz2|X51N%r5+5P1 zbg1_sQYgnSzET44Ip^uqr&DGCyL!0U(Ey5j;tRp}9>>`&YNZkdWR<)Td0QGS-it6M z*Fl;t>71;}dl8#%QLY6YBHRlJ zNct>dyu5YaQTc>9a&F$Pme{VsJD7bWM=&syHXmCak$6Boi9d24g_@;nGFyelzTQa9 zBDmD*(;Q=j1ROc6!5EHV8z#%+^@O}PmNU^RNI)+aclj(Wu->XJLJM0$=d)sCP8w)P z;OXVaK*L>IAm z%gH@4ahjRiRo)M1KTr0^$UTCS3BwJmdl}FHa>CT(PXdeP2Y!}T5@mE?r0K*}M*&jud!`U!__k%eS6OhSvnR30{rxp&9JvpSb}wu1y$5FA) zLpqM{P7Ja4?e~##TYAPI3!QIjJc)myA0m^-wtASvt8c zq5h{KFbpG#o&C~6J#4$7(c2q=PxO^qz-W$>Y>o~EDl*(Y^yDOuGEW_p}zl-!q{(tDvcA$c{Ri$#ry6sTK zXQ_rab#1TOET&Ki5%*7P3$YNfmvhL4wAF74LHL7z+r#Y6^7_g6SwtDrdoGsX zg15e(>;V%wx0mM)2-4|Q+K^2g&C4Jsc|-wK;-}Vo48k{`1&Lvdkwr6-AxzRooLNj% zeUQ8X&Itd94VzMs>EV=;>UnBU`#(zW9mdG?;N{Lm2&)KkRMVJ>4CO?RI6bL|=g)ay zQABRJi3&8Yd@&YbhT)UZ4viI{A5jZv8-WTCz1e7)_+PijN`}ma=TbbCE)e}xl_FO0 z{8ZOFUg=0}kQNg)`fHi`EvW#xe3!hZKoVD>3km=`j9W9-~tLi*ZY z1Z)8$Nnq^GjSQN}Xt|y-h(J&+0!@V>*jjNiZg`iE3ufe_;mUMSxq}n0VFPwaH%pIN z%LCeaDUfI&HUEI&(wq?pmxKep3Zby1LbgJ(1Y&FiGrsZ{Gc#VZ<9os4FFwO!q1m&@ z!XQxvc%da5{V?)T4`PxUdv>Pdq!#osCJtPc1toz^s5Ec4T{cH{)vA*M!J!0Mp7#YZ zWef2}64WIMWJ?<&VT6d?3<9%;a=do}cu0Prpu-?!VZzZPJe!>Z)x!~))fe4$!bG1a zPr)&?R&>(C9e;@kX{wS>gcPPfLG+30rwb57gAQ~Q-HE#J`pPGIFTkz`P}`T&PWbXS zrKulzF6HLbv1AXM^hD1gptEM64|)4uhs8|t=JYoq%|Fc`8xgdndk3AP1{eM-`NvG{ zqxkhNHOOqbkAhE}ZI;=y7pJ12r;{&`mN*{MMu9n^&`f|SPt|LApp|hWT20E)>Na+ozw4Mi{jB-tU zEM&tFT~-LPf{02V(yoK;>qpeJPnPJKS6cR#mpM#yXcs$A3qVm3eA$p#uN11|4&kTX zE8q##N04Fy)z?tyw2BG4_XF+^jYvsr1J7zKbNy9jb{LckD?y$9YFOIWur21v#EmJH zLR=`jq8T)1tF1r`rW{?YQ4|}cw&W!Pva6K?Z6Bzj?PPxX(grN8t!@lEyuJZBWGgZ_^(0@78to2wx<)I2S@pELZ9|eNy;j+_#kT%PJYYw z7kfWKiuB`%;P|R8X2IkIJsd z`Wzi%PNAL%vc0EZeWSPU%OEUVr+o;{JH>03Y*`jvleOhpr0aF$G@CDZ*pm5jtBz(Q zSRF$SBp50%AW)JY3DASNXDDbX9!B7mQN5n4>M#wYZeHJ@S5J^OoOf)LS~^s_=(Rp> ze7nms{f}|=_PK))nY~Nr^W3%VgaOl`gjEbdHqk0jQ-g|!=vfnJuKtEW&#LS<ftR5Tt>K%bv0BFewFq(#ZEliS%h}c?z(dZ&B`zs{NKU@fl6` zzmJaeAw`0+$|f(;wiW}n>zd}B0B>b%_;-X1$LzWM!9lv?EO?W^%N7pBPKLZ?S3f=e zAnNP^cnPC_pz#v}o7o(!8b|_Bq7umkx~y^3>GS6bYN^b)O5gI3nBQAQlN| zvy0F~VTYr*f8k8_-{c#zS_59FAlof#LA=)RyAlIoaL{qt1S%q+q8-J*JL(v?30@2aU#->2MiJ$CP4eOu9~Pfqjz(MqQ>xTIUkvNt;~vff zU|Glr8pn=uU(xWv77sM>1k=OFhQbaSY}GYty<|>oG)+7OQGAza@MSh-%Ctl9>3L^T zbt>Mj^CY(9k6#&uNJJZVQ|zyY;{x^0>hk?AO}gjLhrx8C4q_&hB05MaIbay<*s|(i zd~3lGAQ=OWAcTgGGP3=Y_IAvodHo)Rz=^cCHcg2>2R?~s?==iw0mkt@KmDjdmx;X3 zsD?Y0F(~nYS{+TP1NpP!cYHlPVe7j|!m{~@O(5f*RCw;lj>@Su}l4BJDdp!+3vU38XfQpPac11L3VGv6+@_fA1v8kOAh zgQiKQ4i3;eZ~^RzKUbVToTHTDpp=~P1|SSu-<|ZhXJU8K+(DsCq2DlS{n$+_eA0uw zfcj4J1jE);cLIyCPyymVwx-5u$5N}6h=>1@a_>O2=jOVz@ohuJ-0>xWEqgo&sFsV0 zSC}w=fJUInI3ne^!SCB zCUnVUR*dyIl=&~UOT&jl-+$VaR^PB(op;8Psyk151v6QpCLi-=hrk)@?x1uEjAoHTtvYi>WFHu05sj=(tz!hFZDvq9tYgqxHsjq!kBXse>XL)+1^RP!DAw+Q6*! zznek%bD#^d*X7gpg!Wva29lG~uB?~|5P|C;Pf*M>=||0O2D7v`5Cg2pQ(^juO{5}O zcT0!vWjU`y@lExYZ{)dwh$hNjbjXk=uS8$**)V6r+z(-&=z{6Zsdv;X^0njV=wRmo zt$HG`q??~TG+cK$2n+7o=p0L|q}!=y#P@j|i_s9wA#+wQ&5Y3(F$_nV#3c0+F#Na< zi>D;N(y6s*5POvB&>Gez6GEQ5JFI29tuskk@M)mb9`)tZe@WQtC zR>j%%*;e_F=9)Ws9QHX)ntL=>BsdF98>YW5xY_b(zXP3>X^g<-Sr|d|xQsH?+jKK| zE}J5fhP$KFYCl4oOAN}LZe9?|poO)S4>EipYYvC>LIsi-_2Du*C}tE~A&U&i=%=vC z*@(-eWHJW5hzEw%=G*C^_chY6+nX&*1iu6@ zLD-XUx@hcGru(-sB{jy-+JkZ4(PO(WM7y+F7C5f|S`$=v|0T2kJ@W)ZT$s2X$}s(y z`4c1TY9{QSR!A7Fs6z_z@+KC}kw#yQ1Fw~l$DQ`lXtxa-O7pj8bd2#*_FntE(USOx z_KASJwjP^t`s22gRn8~_8jZZ5!b|Nh6F`m!ntML$VNUMTxpWuP&aot zBz!X>B{g+OX0ph`!$dj#E3>$R#fw|RKOzdrWl~DWEP#(dXW5vHWIRG_=(=wY(TgCTI?fKuDlf zJIg&vcn-#$@q+BA`rN@ZN>RH=??pF=x9X=Q0n>X9piz^roD{wvTEFufLN%Ru<$8XL zM)+2lFqV<7pwGBODC&TrIOg)*fz)T)?S!Kp%wmInxXjgyJXo-aYrRwT*xQX1lyyv^ z`}Kn143I9JdG^%x3QI&r{W(%V5T4@1Ba_8mdkFio{MC8wqgj%mXdx6fC4L)0SZEi> zo41a%q-!<_HzW&4l90Z95@fvuK5CqcmP>6$rarHJOL@uIV<8gRDS43piWwj4i_^ie z5Hgz+&+bMR&O3~?Dud_>KLS^mT<*JHeo**USE~!I()k`^I1U7t2LWXiDt71BvxZ?A zgqoWQ9f?1hc?6)i=p}Etl4~VFxNXpbHVRJq>9C0-XRMVjU|JClJsQ((_iz0Egkct-lqJ?v^JQ6hR@!aRdLXqHYMQ6=2BksP z?L5hj9#+6%FJDfYpYD}OJPgtn@!d|}Z;=d(naYsFmHmA2h$#&6^@nr@02r4yukFaU z44=NM&QWml+ZQNO?0k^r3)Kl83l#4iN1Hz_H=KWW^P36t9m1&JE&y^+iL^|DtT_#T zVzQBg!w3wq!bh}TBJ~i4Y6OHv*5LS+&xuQogNDzr#Em^9f@DHA-5n8H?bl7K()4o8Q<(y=@9 zqjpFj+iI5X^65i}=0Xa&l!s4oER)6}SP|&)D_6l-e3=dZ=sv7s>_cu`g#1G0C3Pfs z)H!dcm^D7)cxIf`;jycF;kXsJEz^sM$~V>DkC*6(Fm`59-U6wyrdG6Jj3;#I((WAX zK*TsM0LY3PY3_S4{0dP*5DKF(Q)#kTn4W=!Rm!m3@4jb)^7gIarcla7EjdFYcg=R- zFMSZ)?uoF8Ox>LQYaype$>{`*3>?l^}SQx;TUvmOz6Yj8iEGrB`XUiPqIP}*@=X+;MeM`!jrQJmbS>oM) zD=P-uFoRcGgXLTpi)k1v^9D=)R>HYza9rwxD1E~7(ww4pv4iC(KKao|7_az|02}d@ zyHF2QJN$ySh|@-$$7+f5^i!B{tOj+G86s%A0n0o z2WZX_&a2y@tdL?v@Vmp{C&;G;j0)m-v$S5^JJ~} zy$2dX9U$oh5dUGAWaU53r)wQb0UIORU2rcFGX@tLBcykIAf*4I%8*KGjPYOnheq-# z#Edx9K??X3mM(ryl`grI#BS=ypy=_=0$=H(IX}_?Q>sI?OVA!L=F*I}))nuUWidrj z9OMguvh2^8Ev(G!Xpva8xv>WTIfH>08dYC`+>t~BwU%K%3epN;nixbexhcs(;S~Hm!dw8s}_I#Bm1uEb&%(wnqUwd8fBdlbqn0LfHme3@hI0hJ_pfbXy zfshkEAfs}Gy%WZr(Yc3cF6MFJ9eZl)1WLXty#h-rv4PSf9qA)F?F%l1jes~%bP)ih z)YP1fCj!Mvh+IbRNeLiTW5Y*W$reh{C5BhogGNXl7)DsnJw!C@9`j8A4fvpXAw96h zYpf<6e1d*V18fSb1e(PsyO?H3xcj*fiF#znJhD65H6}>Q3rPNR`_Fl{d!4%z)e`}A z;v;uT`h)y4;I!)I8fBR0W#d@SZOT*noxlEl5&r=9xHcD|VEr3nsccDd zUVrwiK5VW84I9QNgT~D}9~jF12zMy<36d~=it@^Yy;>XR7ODN7U?F~bSY?h|IIcTC zs*gcME0wH_Wd@p+aCJMH+2yLYTSM11^W+<;&8(vzvfs6cF@|Qc$43bo+mMexJYo}q zAnJ;452+1{`IUJKtVhVyX4iH>izzwmkhaE|zwbMOQ zZ}e_JQ2J>G@ff?Gc-LRuUn2)6Jm+U_j0+(DV=Qz;7)b9qsZp++vegeNETmwwdSw#r z=^uW9(%i zir*hejx-_W&8&%uiel$~H(7ngG#E12tNSi$l3j(c)$PUenqA+A&$_`3+kP=iAw^RV za2U$=!%uU|EBMBu7*O=l++DbYw~olV=MgoxeBm$BAeqB4M!B31dY&RN2P^W3VOhK0VJXY zm?}5^^gk2wL*({hP9r_osb)jo%(!)_Q(b$Fi@|peZf35)sn}#@md=$1*FNJw&mZG@ zE@A1&3M9gLHC7AdSa3%X^s$?g_`1_Hhw){kKBWoN(a`!YR+6ant z8xsOPlIbq;*lIQXyXWae_rHdDFIR4B$6d}hnub?q4(_VCqXmL>&NWoFwP3JkW9@?(}g4M(S2A67dXP)^`k`tRVj; z=zEetC&Ab)c5URfKg5ctc71PtZO|Djkn$KIG|KW%;P#9ktnd2Cz-2qDt|-wk{_y9A zl~17Vpj`fRddJ}*9K<}|Xta6wH;vo-TO=JQ;82oJW^j;SW+z$kP1;7|h*IZkm$7Ku zL_ldXX4|0n7Zf>NJOL1}atb(|=lazk$YWxlw0OZRR46g&0zDE;hv%tXAJ3vAlyO7C zDG=7NhOpi}s``q#ckszndR%PxjLu9??la$#_DhwBjwpUU_0y8fHX5Sz6;N=XdYl80MCEr3me6|KM@bGjShGC@POcEN=M8j? zPw%BGUWd?oxh|8E1<69VgAR#;3cz6$Kw;F|rdL1{d=m%W*=DN-w^AG{l|WdJ%t~7e zmZKw4{|LML6f(FYO7x;?T;{Z=%+}=z8{m$F;;r#%rYbA!FE|*Se1t8s|Z1?=y@BP!ebg z1L)fgKmhwfu~U@I$u8#-EY#_FDywAJT&+G891CdZbWC z6&OTMRsFA0tbNH*GB2uC*LqtZk~2cs#ksj@+DbwHRr6fTZZ8P#P*&_Jj7`rm@XaiS zR2$gPJWsGejV4n3ozv4;wE7x+4m#icj~I3h5kYW>w6wI1=Zh-`-8YsD4&nizhJMIt z5GPMAcZD0vZv+OE8&+rW-p7hNd>&8j!ou97nsb%Q;;KR_zgeK~T1Ib!B7hZXfKceF z#Z-F!4cLCjp5_@3%ZEkEop(UIw3};~l@45Rbp!q`yxi+ZQvtj@3oSdZ&^kqPEp{}@ z{~d3@vR8vSXvxOjHe3YG;30ZV5Q0|l{UfGr2&LNh-U4$erbGxV((j*08PZ-hCOD1y zbE09Zr6dm`)Jz`T>oTST?KB0iofI?*4g$qs^r>cN<_`k(t+*%gtTEU5r8L)!P8fI0 zTP{T|nZ7td6^K|!=!lnM^G3^j@1yM}H$R@&DpQYvZKd{rW1_;Tc^{~jWKreQl~q69 zKD)oyq*7#+n$RQiVgD5#qH?>7p*s09=7YgTuIIE%*VBYw9OO-zq@VGFrE5CQR;DK zHKe+op3Qok`f3;HUisdRY2ohX)bsL4S@zpBBU-T<#~50uFByJ5Y5@CiMfx}WkN(Bj z?q5e1^L*`m!h^ko;tUAgX-Uk9%!5T&ukN9hV-2C&Ff(sJ7ac{`~ zZe(I7X?}r=wqU#!SX#RtNVQ9CCc~*&|1o`~A2LzzY z$=A;O_wlkfmpa&*w|##KkOrCbDy{HwFjU5w9d&cWY+TQoGL+4k3OxPTljJQFQqGSV zZ50sR#c%%UmgO`yPd20e-nF^`ms-1~h0;B1InW=Z+RgS1e^J zG7@AYeWRa5n>y0>=$bOK2rphB)hjJhuG_#QpkkzQL&c813mB>41^A>W& z`L1Mn+=Imo^rQuF5syTgmU+&bZ1pF%;Y>X{^weqZ!(- z1>!(jjyHwHy6>oUdy9i&M#+AbrbDSF9)RguagIvZSHh|nCB^ZhIC&9as$5G=u3UfJFgyL=K@hjhdT6J;N~5HiNcq~TG@JHZlIBW ziXG};*+d!IHjBvP2YJ*aGRj8)!U=<2bf?xXKKd>NLR5;59redFZhJd(E*2o(KY8jF zV0^kQ@eN7FncIU6NkWoi`MEbFA+EECmb`#q?}&S>;tjk)x2gye`-CSRYX5R`_4LzO_oX zr&?${SyllJv`zzKpzRo9pr9Im6&UG%fZ62wT4KL+^i>foY2eYR^%u?jA$Bkq(Q2Y@ zCib1~=DJ;g;=ypLe2(jJ*9TX_E9vaQF}f2M!}uqI(+%8weDEc+NWWE)QIj|4x&i?? zqu4xB+<5qt-YXF(juJHY?`OXd`So;kFZNE8YzC(?vx@gUl{3mFpZSxVjioabhxbT+ zxiB}r!hZ5RD=^J-xo@pxIB`*zabwTV^7>_WDw)O>ZOP9XG$)#?ip#P(OhcwG6(-Cp znFgoztw~*$-6R*7vpVMtzT}^i-jsqpPEa4?2cwaVH(|Ur$@}BUqB-~Dw$ye*SS>^w zyOGR4)Ij_JqZU2(wxIQ8@(u$|%(rA35HwA-LgPiBAR{eJ%jzj(2Igt zyhb&A@c<*%LmgJ&F^d!*TbZBZFKC=mEv{~;H^y0td)xaYcvboQd|OoPNLqH&BH4SR z|4{ZW0DSS}%}FvqKAi-AGGVAlhiN3^(wJ@`-U{4pO@*0#RYhbB6+t&bf=BvvikQDE zo{m}`bJz)DEW9>r-cM5L#Z66alqJYH5tF;F)Dp0@Nj({=K84NDoguyUa3(6^L+hnR z1jI(Z-u}v#SqokZQ-1xFXHd4J007hlnN9KsE5=M_g6_{GZ#9bZniM)`H6gIv4#zC_ zJT?fpPj-~2=tr4L1~3d7w{Sf@sAHYS5_ybErnbTl|Itehsk%XX@b!}PDnzsgGdhF| zr=qd~=4}sq@-PPIdy?uyUlY#&1PgI^=4(?I+aaGz^0=y#f`p3FKQ*FT@>-x?=3dkD+g;!DrQ_hq+d!%JZ|ewCDT z5^G;9nS1Iez^}SH-t6b2^zm5Zre*NfU2^`fKVbR~tAjXa(AW(bbt7;To+%WK>9&n> z0svVD<_|oP;V2v-R#b+2GXz8hYA8px&HlvElg;O}wWH%+17?=`v$gtPXHnM;WcrVviYR_y)Rz2;Ti4N(n5nNhsv!4T zkQ)EybEtYxkF94u0C$5F(z{b^KWvm_tl$SF=5s5>WZ&kPtCdn8X!e|Kq}H(2@1P<# zAnuiGNSA87ryhHCqiPZ>tZ=7_X7DDt6IGKF*`-lOg)bHg^tSHBz80JVqgSst1AI~) zF6s=#ewm$h@D|E55Xc*DM4O)gkh%2y9%#-0Q^>uOKAHAH=;o`J!=E&4`*p8I`74dW z#3X*bAe&DnZvSd|PGtqOjSj#}4+d-gCKtMfK-+Jc#H_oY7y!ZDRyU-gd7R<>GEe2~ z2-#O9ot}E6u2d$M9UBufTV&Hh3o&p7b zlJhO&y5Zl@7tqCTv9q2?Vd1#h^uRmu;yWY84#lR&p^@sQ5s~WprA97QW`VP*`j^9U zH23_8_qhB@Ryo^F)F6!&v^u?{U*R~OMNX25sOS?`j5bj0M^HY)2dm&+82@gLUBM+q zhK2=^&u}yQ5LnxjM)$jZQ^9-+b-_)+vDvevmQ(wy>Wn%EuxZ4O!ft~7a88{%P z#h-^D+uR=vXf0&Mp0*4brK_siUu*3;Wt?!YNW?*>50mdnt%4#BGl1A(fK+Cf2mG=g zZ4Q)uK+Qh7-hfl+xf0%F^P>(-f_>dg1*29CltGr4VL}=$dg$EqsvCvS)rL57k=#4bq40zD7rllE!pCio^lBKnC#?6&NP3> zX&mh~u>cW@7AcZIL8G_nJChd_62b%^NeCci5u$Ll#{l=Nu6(by>Zd?$qZ5~S%JD%! z4b5i}Hns{myH1@Sv`w+17d7@cbKnTPJ)}`!_9n;R6F&28F@@iN1pGyu5u$G<|Mh?= zxFvvi$l>MIUO}*a;IsrQnWJ0u^|xe{mttuNwcG$DdCmG5(CvxvXX7}_SX_DWI96X5 zE1hD(N@a`ccjfYHTgW9zBXl~6CYko^LxQPxyzZzjr3ddAdG6C37Jl9W>}Uz=;Pn^NrVTz$f~`Sr*(Vfp2{j&!wpZ9hT1qhg&-F%Y_l z-hTxJ1szx|hDA4V=r)x9qgR?dg>kHmw@Mg`V_IHtN@od-r3?d3)(Y%`OyG3SqiE+C zFVoIGGi=CQ3xzk=Y^-8M)zvt#88XYn*oq~w^-hj;hVCw)Xb ziQTY|f}pG6j)12P$qS|<{Fkit^pcr$3v>OowVCVOy!V){Ywg_1x<@LMAbMk`C!Qgt z-f1EEPJ?WQ(a(HwzsA5j89r+EkJ~a56_{QfIrG&;SmEm{Cs{A+D+086Q5p^-W`mzB z;GHt9f14I#2 z(;xC(cWI>bAAfihdBr^bf8#C*^F%B_?ldwo;_k%2`xhhuLxPIk^wkypf|G#JC>G?K zmBxY#U`OPNIPFXL#j`kNM^*-gXDbi9x!P0fj`b?MzRcC}ALrVPg9~%#;C4P~dCoJ& zkh7Xy#*Qb&+&$3v_8hij=r{?y&X=CggJc=N z8pWGq(>8Hauaw^2qN8OeuEko(_Ncirx&Zzcs(^HeB56C4tiW4seL zlCE^)dF(D*lGY?=o%N##ZNAkPl=hF`PS4qSQ^sy6{cLl*z3pdpV-kSJ&vzDJjMnAP z>%9guzs~&7C#(lafY(CBqBI+*XF(u~;?faN767VOhJm#Xap00;X2zO~CHu<~!{R1s z5KZtw2;w#Q=>1NO@LdI*f+RTjupB4(mg&b8YcUV}0B|IA@k_E`1DVch2v$ZCQ6@=< zq>8JH1O$6yvhzr~icmw%gKl5Bx^mdLQvcOb``Y!xW#=NiT|&OM$p!o*k7h|VRx9`z zkzt~^>N_}ETanMG-Ianh^WAVv=D4#+>ujmeP_}qf_*MHXtJ%KpJ1Yn?1*0c#baop+ zyN*bNy}hv{`(R>l7}3Q1Kl`oT965nd1;iF)CiTSjWIkRcN9u}E;HO@x#BI8;?FgUz z`;7rRL_D)_GUXtP6jv?IWp8&8_APlh#ZsAG0Z+Lu^#2Nl7P zn=7r%z>~YPR!j0nqU5VQ_xV?+yPzh!J1w+T1sY9+s+NT>*}yt5mpZh5$acJY4f^04 zy8-ne#0`M{t2dik&Tt(J`Yazc5C1?jx+Cy=a&&ZZ`&SHX-Ocju5mnruz$%_2GS#fV zXPU7)edAg>)Q`mEWL3peNwh-`u{sR>mapJSDB>zq5@mL zy0%Goa6*ac%4gyC><)6Bt{>)gSAJ9vrI$@tGMaqUYkw>0*A9Mbb91 zML{|QM4WD66H=?nEZw>GyMxxmT{`a$lBE1lqMbICoaLY9A2v419a;x{H2?YOxP|1T zB#MM?khuiM#ai+>Vo?dclR5SQ0QFB8KsiG+OP_3TG_M$=!4v5AkCH?1eVvrW1_=p; zTSHo3zzk4D{j(Uqu{sxE_IVzCKdTi2U_}^2r9d$&u!L17hTq=?Jnqf= zMmhk>J!W`+-b0%Y4R6`6sd8=9+P*r&dpZ;P-LKG3Ic36RHki9%i#+lW2y{^saxdm* z0Qypu6)@P{}6HcQV*+aO@Qf%ETt!7yB?C2BxE{$I{(?P5;vUzih+L^M9fsOl^Kg z?ZHuUyM+xqWrA*TSXNyEB|{kWor6Rl`OnqzTTfm&r~XiamJW=fp_5hxMZq|cD;T7o zSb45Mk2yhj)>-BHxwZDlz&nMaA~~LNd0Uz7La=Do9wyjBKXZEVqCFFpKR!(UaB(87 zPJ`1JQSHdv^{x&U$8iVFZ4QaSTZW>H;u!!H4MmFddmpPWgg5l5oQFsp{+4sYBp(+l z#OS}LlI%Acfw0QS;$n+jRy55YUnUr(f<&$<>h+wfHhYN79st=hMX42B{+%dU2e1?I z=MeR$uK9>qq6M+{DqWOyhe~`M^JOEPcXv`B`n(<9>+C2}cx{QD#cLAeWSki^o$kgU zL&EoJyL@+rvyJ$)obr1O2aWRKaa*cAW0+K{PygH<>$kaT)WOb&axe6f5)-9n=eV9- zzTJ6G7(UG;uE@54dNEUKQM!t;{5&8m+m-XU-qjO+y#)mqvyAF)3gmGIRY3( z$r#sGU2NEvD$|`t-mLWwada&hh|1U%cK}V2bPoBqldEJ1YAUoG^UC;9@8L?06KK@w ze?u+#>%e9-lhF(_$){Z#Ua5@iUf=D~_NxOQ z$DvS#Cum_Z1nSw~cV~rLS>>#%4J1piBEV8HZ>n5>lj@fK<{)q!jzW>TL5cwzZ24U75)sGQ=FwgKua0ImRZs&C63VcM4l+CfV_N|xU0)uJbeT% zUAh#|uE@LJo!H%RWiP%i5To};dU#(Si>mZz-h?e!&FlOo1if9IFR-naGa~b$>T1FQ#~Gt|=584Djnj70@z#%V6woqD+oXShkON4@kH-4} zK@{A{&wwQ^9Q#|a<4IZH8Cs2 zKrzsNQa{z;jg(a0%a?@ZX*+~7sidO8f=q#ziIW6pyzd2{KhK)3U>F%1v9VUV+yAT3 z_I07{ukP3;`_htMF=Ikae1l8Q84-qMO?)Y@P&BX!{`u?N(V(5of)0~Xqh3Pg*!IR) ztO6XEH2I$z*o6Mz^pdF#5w+^J(-4YzSXO}uDB+#uppD~g^cZT=^(`MZCgXZ7kJ@8v zPMSxBT0WaK_ou)$-VnGniYlG} z&zI&Vw-9*!@Kh1A!PySnZHSo3())JW=yb|mSiW;>daH$-XwE4sjB(%?SD;1$VW;=}Dz{alA}!;)595brIS` z`RYJ}wNKGHxPLB%b@3s{a5>pO)+8^n#-6CmQXw?c(cPNmf^Fs34OEll;l%7i*)kY$ zxnB~WG5qfX0Ewc1(GY$x@JpR5pO`|R2Gk-? z1<5xk3!LEd;I1ikybppC58VapQF>W*hotdJN(7w2^y)!V^aKF&M1V7Dj=O+v67`oT z>*jr6N6qo|+A~F>jk%qgY;Y4bPF_?SY&&8KF-$sYTZtF;J3Lq|FUr`xLAyUrxkh3$ z%f22-HoNKhT)g<4PmQs=Q;(laRLbibcXohIqdGO%T7`p!0=)Ztp!L|EvkD_!hUiXKp_yCALTKCgSz9c2a zjaU%}+EwEm7f(!HF%CU(7FPA>90AenH1&jsU+VEo0^e5*DOJ%r;Wy9@60F!4B*X8P*LfFfI$cD{FWDjDxHbTC>rS_uTjU%?Zt{ol#N5d z{m^|IcytS>(ATTO7rsDyfk=`QoOKy&Ed}Z0&saH2=AZU{K3bE&M)PkE8Vfe8taayi z+V{Z2)AC0;K{|g#*;xBCG?XZbt=;Tnr<#jUlZZQU3en=zXjyeImrG4=iUwr^qR2zJ z^iU$GnWEe@#=M$h5t=4D^Rp_|>Tg7GkSu-_iI8BH5Nxv?Yl@{A7?7ZehbSwvL%utyG5ReSi2&lxBnVeVK0JtKA$N%Kz6F>9B;Qx$K-@;K=-Wo~NOkA`?$LEePU z^UsZO=l9r9mXkr2V3EO38_S#q6hl7M7V8#VCQqB&fS58rD%1~qk&KHW{T*`_k*b5WGr35J3w5x)M$faVmR1o zOfR#|9JJi=n7!>KzjbpL8@(KsO=+oZN8%aJNOK7;9N;&9Kt*=5@faKD6J)&*zG(l z)8p~YL;K!6tHC*>t}Z$S0YPtOJG^Eu48q3o@OczPLLuzz*kGPd)2z}9$Hv=T1?jGU zolK+-CWn}@>sKP2fj_Orw+C=L-l4<=MsDso6>AY;8I-VuW~_G{H;u!N9FZMOTis%TlJA3nW50XtMAxkoEdr1kXTdUDt`u)m{t;* zA(~eX;5!1tR3>G*mmKzKK8r-sv$tq1*rhnFQnz7co0OG6IwCc=mO)E`sGTIOa%Yd> zdw0mNPhTs}NrC{m&tX=7>k-e)D-hR^-v6N9zPP zR#yz<mA*RgWxy(;8We8{(&ngEq7T3`c zBW0PR){b3fx5E5{ug*DCaj5-dcM@5{U5_sOG8x1G@=AMMS{11*~52MwTJHgp>N@W z2*{9*_eyHmbnCVzTqof50GpD2jJ@9awR9*X=acu~A0+v0XDKbO@*c5TeF8Cb_-yzi z$$|ozOf4oUmz@qyan65{+1I^q9hjkdabVxsBZpWUtJ>XZo3nepM?7t|(kAM9F(_o0 z67>E&FJa)2hRL4ZS~HxJ3ogN>Gf5KI+q7mn5%W*w`?XKixdo7n3{~-=1A*uVv8C4r zgIT)XKf)u~0DJPon}crOA7nb5zX~ExAnBM#dm5VmDZoJxDQYFbUgW+D7CXl5t+bk$ zCzIzCfA)bxP#rG6A7wWUn}11K;rs{wl=5R*p1qa&5vsbgyfc47s1z2?W5iY@y$o#B$}KYiN#;0+PM{;aaPyu9p+ANF9s zD1+S>#b^PHZLX%ATouHrC8XH%CSV%qXnoTv3S3GEsdv8fxhxZ<_)QO#_LiNPz=J)1 zBjqWcBdPbg3C+D;W%pzj{5&c)_}XBtbuJm^*C3FY_HZ3eU!H82L4l!`eW`~|dvmmx zL!pww1?rnDI$hRNeh3+-fK926>Wh~+h7uwk`s!QX2aAJ6<#FCxKm@b+zpcyxg=n4O z7x3SH-K`kJ+|*xN+tIc9^V$?>R%C8vvpItFSYvK3>_6$8tx-9i69U*MQ*>N%O*cuI za~|kGl|ei~+M(NS+vi_pM-kvtGo%__?&5jb8&_B;;&fQH7!M$^3rKb4N0}GgbC*o|lo7pcc{TeGjpMu< zMA@l>raG#-H-^6hl-BZJWd4fwgx$>IqqQFG*lJS{{dx5@iRP!W7ABi~Y_^1+7fl;M zJoLSXt|F%OPF>rBt3yudd zG#KQsNrtj1H4dDZIF3bd>}IS`KcUldYn=ygYB+tI@EllIbZ@9#eCj%g9q2_Gx_#Rr zmnQ0BXWj!%xb!^AmK_p1L%(+jmL#l2A~D^tL+(_Xb^i-NZPccJe|wu@m`;=BY@FJm zi$)y{X6-QRNrVLmYZ~_Er2`heVQ1ZH^S85tRU$>O$rw_PF;k+mad zxbC~6^@moeLN|V5_(`5Ub?wBqV*UbVkR{3w+7oncOG{e z)LFI^hWgzMYxUI>bp~IgMVlfx{s4(J|+#z>P~ihr>_^yI4e;$}3X zGxk+>E*LFZn99$>If8G->Yg;v$UB$WJAKC%YG`a7J3@`jaq->Gx&eCl6&~OWUybuNQuTHC{tcOXQHb}%;=|2E}o9wh~re0{Q)C~2@c zUx=^_c&18j&N~-BP3EP0!=%ClP1+JBHs#^=?$+FIBm|0LRaLsoYA0A+K<7@hM12Gv z#sLF>a~LQm8y(OJM2Ic>&+RJKDF!j%;|YGpuykeC9pd#OB;ryLS)*tZCfvw{(mNpF z0IgqlFI_3!khvR0oBm4d75j!|M3ns1T?%!*uc`&d>;rz?gQi>b0=T?tH^9 zV17>fMryQBtXTe{RNLJ{zCSp5^MXw}<49gZ?X=v&uBHLdPs0`vP=R5ZPo%Aw&Ojew zCkCrDFw;%5uhb-h;b*%Aj22eu0{$5=a;iJ6w4302hr@>;>IQnO`p+HFrmrbxRtFA6 zwi>BH|{x5bYT0keEG$C^<61fj`Xu55-*$JxrGe;;zCsyS0aSPOF<=bxr=HJVe@}JmJ z92pAGDQ=g@w>+zsm-Z$SQBHk@)$PLgECmH1@F6J#r4K$)a$;gFRJ2D|^dv_k^kV|X zkGw?N^|BpHDV%T$U%?p8bTMcLneHt?qjA3EF3pARXWJ7GruW;;`ysH@J3TN7aLM0d zgj$6mzy_KYorFsa+kNPSyOb{-CZ4%h*P5Y)!!w)kUK@RjJN$P#UroUWXQOcw+uc{hf#Q z9SfE?HD54e3B8fD8hs5@x(GBJ)fNkQb>=*OngV!z%SEoVWMuciYxzed=o$@p&&>A| za$2D3w#=kR<-@ep*FYd^Tam}|=XF%&b*PRhgv9^wudXUF1s7y z+@(-4xNC?7<1VDpK+UYwMJXHoVbKp`DnOn^8-f%`5( zDi>knQg{#ZE4m?aw~=G4r#&nTKCO8ak%f#4e#`ZPp}3Ync>BJDZC(zFRlf1XOR^r= z(XXH{h#KC#bel%75<0TX6P&jpr|T1Ce*N>07(jDFpr|pdzGC+U*@Yy4l;VMc#~23w zW=}Q{-}kf0W;8t5%0x_jU(!KTJu1o-Vg|84Tp@E~fCBcr*;ao{+?8({YmkND!jBkx zj*HAM2%7SRx}Cr-;k`?)v3=$J4p0l8)OzaH8myW@yIlTeR%i)p+bIjyZh;L zci#FVg=yG-+BobKGc zwD33OXr(DMKKM29Y^Y*D!9jtU$12s}J%#r&hSyZH(j1=G0Ak{%AwThr2hyn)!Yofx zi*extHOR7XfT*#sQ8d8%Gk@5BNAn`yly@Dik6TR4!gjGo|)1m zq}u~6%t=wh13~t+ft=WP3{_B>UF?_6QKhA z7_IfAZp(y`kNiUSg{R@`MZkbA!hOs9{ULHWgSZe+qq6SbNBRrby(_k#Qc88d`*&N% zQRWwNW@~JSKuo)(4V@Al;VpCvK^j;h7>u#n&GfpEv;6{98ykk>WUXR)79D?zUXBr= zrhLxSsh&LJ_geV6K%656r;OY4Hw?yQYUQP-WEwG#)aw(7g4_O6C`de85wpfRs zP&|yVQ8~Ol=62;~C(@citE4(e1T!n0+toeKo|K)i_Q1UU&B62=VH{KmFbbuGYikOa zeLa^V1$UVCXJ?>M@N0l_JRhcR;rSrxxCW8p+J8-t4wt+kV#PaF0vkvyKndlZQ4Hk9 z=QY+h-dFymGgn-MRw?;*>p?Dd6&qnN#mwX=LZ6!w z*I5)Sc2nce8S)^!MMr@?JE51I=8y>pMY&6?W9U@v3Z~ z*GX>iusoCOHzpEH+2X~kB+-s}@uu&4L9f0tROR*NWt%v-6w!bH#6_2g|k4R$5+n zQGDD2N!mL-;Zir%%Ig-pwxbM`N&pJ@atf?dDi_ToKN=7#ttDr|VXLkzxeWcf?jYQ6 zqUk`%c`iZ%A=Cf=EIBKDY?fpV5BA1p5#hGBE}-B9$!GcL#P{zVe2ywJ*HnbcU`;_r zVLFPBz@Bis*jYjH(g+7u!n6^pP4bTs&p<7CPj@o&9^9YI;FrG}`U4WnB@i#M8S*f? z0+~xe^r8Ei3T5WR6ND=KE6h=3Q0Me_CjLaNyNMjdKIaCHHYW6wu_rn^MSt$7I18)+ zbS!Bc5C(sly7}<3z7841WhV6Q9D`lsDQ{0s^$D*FR97((uUkTR$yf z3QnNR8GVTTx7r4SSoANh^gX1@;OV`bAmM%Tcb@`@m^Y`qJ$R6T9xiAemkZtrD0eyd zyxL{&3wF@M|1G#!m-X{yUOOMW_w=_4%zo4wm6vw`NHXq1x&k;!4c4a2z3! z?)g>DPG#z*p5f6AsX{kq#1pcYX(XLEMb1Jpt>|Q@f5l>4@qgK zsxLgO!rg#5`*_XUaJD#MeE`&VC@;N}UZt1t8W~sR_}kGDa%s^<>7o$Ha$VJb564j9 zvpQU1)@6n6+@RL`|NRzElCa46_~Zbe?4~TFNiwrZs|=}I4BEDv62Q+|Tpezi=$fFx z%ElID@@rt1m%Ds%Y-Di(`7Ww{u6Q**^4oPvg^x~?CiMMq(?s9`|66G2>)N#$t{l8j zv<85j67*2%m;5Q8052GL0_7*L_NI6`t3GNfDuxIkN4U&SFyPkLG(`(2txk6{K%X59 zFJ}jtEd-!CEh0RT{^V1U3Td~IY`}ioI*jwKMgcai-%|saI*;J&=rfeQ;x25`cV%Jt z%JFAbZ+Y%l{8w4|*wf=$yx?u_#si81JByAPIO2D0C%yGRB$6?72uQ-gA8OM4GEQZ`E$| zX~t{hYb_5yodnI0Y@RLEsK_MvdkS4SG%7ROI`!7FwJM_}4?wmP-! z=cWZt3sE87Ldqg_r4=yn_`mO-K7DO@r_Sk4 z&Yy`C`4;@u-26GtG;w|_)E#-U|2R@0T=%qDHIyGAc{p2$SkJ=at*0?qM9rha1k_hg zQ5ZvJ9Ab8TzwfMzD$%GEm_4vFK^h#ec_nd*OP`W{Ng;6sZ*JLv?=5$KfsL(yfEso8-z>qxe!-4}$i2Rzjfv?BlnJ z((3o26+w&jsyG|WaO$h|D~6a3=KCRftd3WU7po& zqve22Iei7S#|0n(24M#QMQxnGoA9NG#kpWp5=rrYDzGY{a>$ty@mmv^g4S{riivgA z=SjI@h`FQ4kJtuVHENsh*-lNZT3>cBIp(?Achuq_TZH!hE5IR*)D8D#PS{z5QgU)= zLyV5O$KJq0$>Qv_J7KP9ZU@{vL2&q~0!F#uanRuCD)_{pKGd3+)gF;O}Em6|m3j5U*Z7egQ~K8?Y_vztNs(!tw?!%C&dhZ9^`}H08!hr zZX!aY8Xox>RIP~yO+%=(-`og$R@NXzcf*Wdv{e;$m~RH2T#`*osb#-;!v9)Nq{l4?c7uTI+hX4IP^;Oq7IE=-+A7=m)%nynv^$S7nx0>r2%+c2_KfDgr^|T0mFoxm250- z7ovf0%I7nAq`{>5pR*?1E}gJBX@~e6+!Vpk>s(M6llX;PzdX8^i}PS6$=4siyZ#T5 zQUBeBX;0WG^&QF1Mb)u7aHLQejzo=neH}Akn#J{%X zw6P8mxzbj`%j1hc?G)?TJb;NYp)vsiMVXK4UOvcU*N=6|Ga@Fl892Ub zn6D_1mkD3k7wQpQ*qp*dDEPjA&eKK$f-jVPWZ{S~J(>F%9`u+$&Osc~7^{*8#t*v< z;bA*T77v(f)G^4%Tn&iK%_RXv|VM;D0ghSZ4yivs=wbUR88d-O7Ho zTOZ^QtSv97Qu85e9*W6=jQMs^-2kT2->S_jG_rO8x%aKq;}{`yGh8lPjSk(0C)A z1C&UWc$A|~`8W}SWEG|DPuJ?M_ez{BMalBmk4dCh6_k$(T9%I#Pq3cb)^j-5+zPw* zaOSs!X85b&2dim#-q#}jz&tbGXA!!gdZemqYU&X z?9|dG4$?Q`v7Z*nZ-F{1f$?q6xr)UFn@4S7gP^ah2hjrQPE(UERGf$t^7_jlgXC&k zn-=PVIe)O}U2bpiZXe67p>o@=o(WshpK7KZDp-n>hVP!k^|Xm@cLutGLWs0TshER7 zo{u>$yZaj}jOA=Nl5ue1n|+*B*wKIIyByGyyv(XdGpPHArOZVAa4sVja7R z!c)u|Ov&JSwbKRkSs`oWV`+k)ZA^R3rMe|xaaH?|&oB_41(hL9aX&g;Igh&+yWAKu ztv2lRa`$8&{(5Yqad{WTb1Ea2bpM?)OA&dw)7@{c{qpGV-*ThH#lF;%v6aKAS#kw8 zzbizW9iUdO_x&OH9&uOcQOtFOkW&$zs%+j?VF_?mHB_3wi6c{W{8pZT29o-s2;jB{ zP%q1fUg}FaJbLtQ{1MHyvq*T^@MthwpCG%(uWucKX1_vur|cFk;8Z^C*Jaxh=?*&8 ziUYOe{@3aMTm*75lEBcR67^#+Us-6N+d(G2U&ZCgTA7Gmc8^R5>*$Ufl|D9FpOAKs zAyvIFYk8`3?ut^ct#Z&bD3A)As9H%dLgX)5S~9S&b){(3q-OV^g)dGN=irKdy$wMH z0Z$0E!ucXKcHk_&jHRzWfRHso;4<4TaJ}!()2xfrzRm8D&Jozc>KGkHgrKDx3Y!Ez zfYMMTtgyZNyE8}kjKnq!f>MyCNy%~w%2MhDHYyrIELwm%6e$( zE{7Z75WeTwRr|%4%)L9R%XBN#dbyyv)q|Tb{nw&I$fW`LNf@SS z_q%IGdcyDG#iwOsuJRGFHeOPJl(fUl`BIj+*fNOniI?{98HLL<6w-P1ua3O$1RK$t zah^Jr5C{x-$uT%b@AZJKPG3Pi!%;}&{wJMN>zAQHFJn-HL&ECM0pQ?^j8SPLrCDYjLoUj0y zsaG}nVx#b?1QImV2mqC-Ia8`sthxde^x#qPmROe}(U6EQ$Ax(tC<%=Bm0_4ZkFrqTJViqHT$gfB#vEhdXp-DAVbUd4QIDJh0*gZq#| zY3aL`cfJOCuzKRfJgGKMEgWL$98M6+W#UKp%IN2!VCi|3PNxG9i-)#z8o0LE^(4aj zd=>L44dKX}ME*FK7Xd?!#OaFa*E1{H|4QAI-Qt*g?mitI))pqPp{DySb=R!K0TfvtV6;sY z^J;&f^niSt?dE=%EBXK;`ErNU^E@!@klWbXBxyEQ4?E8lAP47)B@4JQH3b?jp)dz&MGh7$uz> z%5QqcW4!mY-OK}o*vz9Z@YJU1BWyyT(H{BrA=_Rw3<6DbntTEfk#wv}7OC|Y+~O;q zQhUd-PLbV2Hboc)$#@7?Y_E#}N;NC@P%WAi@DwzcK0Dy5DX_=8kwT@|Z1II1DKf{K zfCmQ2+BrmuN7!~p*-l`UeM;668U2+aKH<$1MdKTO1KQ*ookl|!tX+3|^?O+B%y6~! z#*IRSonAn5pIt_Q!)OQK$7R%=&LYm?^qJ-HTQ8j5mhB{G4vZ{{ThP%`L?;+X zA_7>GLzxyS$o?Lg$za-1U17pwG%|Q{Sn1#0X5}VXVP}1j5NK%&y(Z7tuq9etR?w3uRwh{RJZK^6hOSI zBNe~W^8|1oJCEccl!KJlXo?#Lugh$+yzwj?M`0Q}h$e?Z%5^(<#GQ2#eCK5l=%Czu z#w2UV0hUE+KvG1-9W`S@Ny=DMUWY=H$Hu5`>^^s*X5jtv)%yKh4XHX9^6bOV@&9$~ z53n6JrA?iIyrk~zJPgkX9r@ti>Co&g6SK;=q!~}e$psG&H;i^N$@LLKDR~^-0T6q- z6Mct%S`$DXVF5Nau`q5Pv)CdzT9-u|>#B98Fu$0YZU9)AZ`@#f-5DUkJgctZc1_V@ z9B>~g;5tA~mP`F~L_CM(cKPFTpQ56hCFHX}cTpMUl@2F{P&n z&!Wm~qoeKBg(I?e9O~xpA#(Fq?_Ja`bhP{f6+9M~88`4~u~k#3Qo$m^v%C8iZZ=i= zj@7YuDhEHMycoC{Ai)RhiaID#^d7)Ni#<{dGL=6!YXiIGD|jXR;N z?o?{n0I={=>n~SKrK+ACpR0{5ci()(=uAV?UfwRo`l8m9y@27S$MHYbJS5aclv@GO zs6C+UZ0Zy-K{#;Tc6j!&kASLn-J1U6@MmOF_Zmc9h>H2{sx931bO12oDu3^54YY&h(%>JYZ@=c@$&J>!_4C%*=;9D08ue5gGVdqF6?Z@rTSvZik%@8t5+e z!A21CotpVi`1#4ki6>`O4wOVIYS$>mE&!jV?&*mw*N@Swrp`$PQuB1j=lN+K{~ z=Y(Gc!p(u@b;&QS?!#>qEp>`S-GENXMp4UPPLboAIBwTwn26d~Z5x61k{}qx#nkhx z$DOQm!`t_*!;-;8z|0x-Vkc>8L;rss_6^F{l~+BF=YxKcFo37~pLsJINI_IvWjQY~8bM84d7OPjrFSp2{0Sc;yU;^kcEP62cTr=U zIVSFWHTGbY)wi*)FtCDlaf^BDNZd-nqtp?vs;#|Cp`yK3*^3yk1w`TkOtJwB_Cd>o z6L2@68-ai-J&*A*)R#)ATme;s=y5=IGuRNT*d>WGv(sb3AmCyfYd(9N{Up2PFM~Um zo`|T3d`d~~6K#+IY0p2jPb`efuvyUaj-lXm?kRUE_#) zYCkIkxiR5!-cn#C8d7(F)%z8g{u>9?*r%WwlQSg`bBwx$@lYZ^(7e7;YXqugRSr@T zS7M+4!^U&~ge5qPVUP)=YQqI{|95M2aMJDPY z07BpW>*4i>=Bv4W{R7(w*T|I{@Gf9u{xMVZ-ULQd0@9lY$A!M?29ragZKV467`q_` z@*$DSf2NU!$WJJ1O8xYlhsiBGNZY6-@=~4^om_i*D~;Oor_v&ASEa%iOzR6==b;JI zPyNpiH9Sml)Lc|O4j-Z?>HKDOO)3)+eX$zwS(1~@rQDa~_MqKLKBfo7S$!GRLe!rg z?i2vvg})x4D|A*!djpSJXFnXFBD@ z!w^%0Y_shy**Xrvie_N5iW-3c5v*PP>JgOYrREn7{&JF7f!)}<&*R5S8ey>Rt6j3T zMBv`jpZrFYY4g+f-#?UV>BU@T zpC>?mdMs9?9pF7v^Ah_zrDyO1@x8%yLbj8F3MG$2OqL9M+^5E145V~(7t|XD7eQp7id!%HeZjTLREyu!>er|1N04qFb*W_*FM621fTW0 z+-u7*R>dq87;yy6$Vu2!wS$fn14VlZ_76M_S?X9Otjv$ysjo8#5KS3B!D-^jc6N+35K zpY};$H%uxGtl~&a`pi@?c`;URIp+^($X{o1Ipzg-+w z{`rxl-(bW;GkJWj=8?!{n7r7!f1>y{BC+SDJ3NLtrR)>~8AE{4ms~l9h9n?8K{XhR z@UiWF!joow7bUphY;}ndH$C|yVh_lfQYmYd=h+_e^aeTf zXTNwDY1%9fJlUqs)2}+miszJvAAU$JIR?ePeD95w+leL)z95PQAS>_o;{k*pVKrhv zO#*Kqvj{mSnlDN|eXRRNAWFZ<&(L6i6|dI~;bstQbhzYwuTO)Y}C9lL?i@Zkr2*D>~H%>KE|Fuq4aqP>=Ag6~As=hT zuV(zgAZC)_mlFFuE|4XEU|T1+5-=my)ZsX3daC?A?5p#@W0$vWt5OzN38}|-3VbnW zUZQVN!*&eC%z31=j^?L^%e+E7=&X@oWyz|^9RKE+J?#mKkL+IMO8DVY$s0dg?8^$& ztu5X;qR!pcU-O6)po4?=eeSs}C)ZG_?+V=#4eDY#vrp(&L(hKH2_GRXO|&_<2n^^4 zGcE{MB1$t*hi2B-L(w?#d{SuHnR=+q&KxlW^ej}MNdKAQPDHu=1_M%F-X4TxY`HZK z;$_Q0f8`rI0R@tK8?1U8C*Wy*3uR~&ibP-5<31fc3?N>{Vb7j-J_=AN6d3c`vSNg> zf2Cgmmz&;DeXb<4t+%h|pbr*m7qkK&cGKYSz#w`LMLQ+7>%h-3g2)F=bbHw4XuSCc zYXyo4p`S`5GgsmcE)}a5XPo8rJ~||6YFmEG`{Q#+ybC<6_pP%0Jrswb>GA-0d^+v- z#gq%I5yA$=!zz87R+mSGnv111PS1ynoBO&mJC-y#ZIPiq{tDAU)9$e&<@*Z&Qoc9J zsBEi@Gr1=OC{zBr0iZ9sa@w?B4%2!(`3HC@Xwqyjh^*^aIliIfsYJ3y@YCE^!jcqs zab_>(L;5jghCXSJxf})9N`QOMr<<4l#F~FEI_+rW@V#eOL{1w50W5Z_cqVA4TrZZbI_l)mmiZ)i<-zLe$M}~0QrxE z$6VQQfX#2Y90)hpr`9+ZF{STt73#H2k_MAfhzlTY)+N!xGBNxpDMFMX3-xFG1N?I% zAbCvSZ9};+;IB_G>KVzm9|Ujsn(i6|y(q;9-TVpydz5I%!3`A{>NPEUY|$LuRA4Vn zj_;s)nyPDJx;y{qm1CXn?}Y$);l2x4U;&P3+PAUI1;TSs8W%L{Y)KYk`~owmdXJc` z+Nk2~K)x?#VO~$NnjVw^rc2ZA2a-Bl>m2OtGT_ZxU2tO*GfLeEhK2i}Bbp2=RShrs z6lP(f1-hV=W8lzq-r}V#{jD?!2Dyb!@i^%}9T^f<{0-D2r?bp;XP4slbntzq7?H50O1>zamV&FdTIR9$cOPhxLaFcbG7mbJ)=S;4FaQa=_{Wrow7eLbHzS zS?0#>JtD^mH)4J_1b4>SKFs1axQ9)n!wChz35%_AL`(?7P{hMwFGx#k`UXdPt1x%k zT%wK^zq4hd8zc`j08E{~CMdu2KYzUp3a^J`7{| z{j7XvVvjSJjIZGde1V{T3L1J!e0?T}$K6u}NQO%;mjG#iM(gOV%htf3@E6voEpBz_ zQsp>}rK$8Sg#`Htb`@)(>vK>v~y!$|=%WXXjM8dfTj9ld0OfYNhGy|8TBbCh;G4hNBGS#@Fieo;3= zQ!w*rLcR9qPJrw=VO#_U-tSZI7<&q5LKAEOCw@qOgx-Yw zpgf2c@tNF&5;VRLa9aOdE_xcX?IHyqoAhcvSM9datLe5D@ERaD$dpAl$F(`a< zaBy(+?j2r|@yCm!h4RUQDWKySCAI;!_fB9EA{}>Swh3m$YhiB)q=UeG{zN&GB_|>Q zfvRQYo7>d!K&K6zO!9E5_X?Ifsr6>4@Z{OJX%pGpCk&gNt`6RBg9yL z+;j01Eo$3yooqOzD$X0@l8xlqww%N@L*k}^e|>XfHQ+*4bK?atBm@{6L1s-av>J1v zB@)8Gd!t{Jj{rRPiOpA`qCe5>%X&))sr7=P)x zr#<3Y%nOJCV>5p^7+Zp;R$`0-5_0E9#9v|DE9r34r8ejD_T7Bn+zy#y-$ezm> z^@KL2UpTfC)IW6I*j{EX7vt z-G2P%S3i&4&i+|l_TSCfyS=uYIQhu_C`Z**yqn0K&I54^yroc=5Q1o4O8cAn20R*< zg9MYl-YpVt&$_}120A16tTV~GU} z_d7thyflO^DsxPYnXF?4q~d(w`lSeKr$6$9rY=MBhDrhj7S|0pcqq&)kq~W!@XIUA z*#p`Gj)y6VW+GJqm`rMD9Gvy-48ANgY{%|8^Q*B7;J*(}j)mUa6C$6p}4U?j0CHRb>p*x8fEjI)`fBc7vHR+68&T?!(f-wK9OgKtwa zYB#ucSOO%I`Sn|0xTxi>=|d9{P}mZ_Q-LJ+t||93M^k||Q_H>sKv3vqZ(ST4cIPq4 z80zGOY%t5bd9=m%D@55umx41S{~LDnY7c-E5UaWfT2%K$idsHK^tgbh+zzOpVPYv0klrXj$07?`^p*9o zPi|owm%6wU`Iq+T2Iqc$cc&mE1j55=@DnM+yPGY|gZ{j%V5RdtBzGcgvU#I#N4h~# zYVi|=HIN02w2hCCe`$X>dOh)Wjz9I>(+X+YD+f@f+{YSYTv!U|n*lSY{igs?}U*Jfdm_fweu11TUyMa8LgQ?O)l_%0ZsM?bCqn1He$DY(7$-M zade>-T0l*XEm@_(0Ffi0y(Wre8QPD1IOB@$=zxb6AC%OoTnf2a*WLtu_W3k@P$66~ zbJxzGJQ~nChu&fsviS#0K%Adiwhn^jV6x_=!oql2I1Ud>VahGTqC}q4n11tp-Dzu7 zFfXgt{sIG>^ZgWpqv7}kgSq-vAh^pW4d?uxOyX4^&oNKOI@6_5souulcMNrP!Bhkf zjIrpusCHj_3bn*|Q?>TZb1&I^&uFawcHwi}F4q-&9;y(iBxpZ>W=k=t!p2Dcu!+^B zxeFBWTW&JH)Wd}ZENA8FNJLE&DfQT%&CsiGg`WK?fQh(4se_v5gWXU)^puTvjlgI+ z1*`BLXGSXKsH;XzH#X572~y@0stS4Ex+^h^t_h4f<&wweOcRxc6vkJY_H}aI6v)C*F6KCg&f$wb(@U*UMAr6Z-=B1^U&Cq*Io09CO1BxJUEZDwMa+i=Qa zdwtz^H2%sw+8%g&ujwDc;7xR&fiB!D=?RU=iU(0iOCGiEZI6~Y7enc)7aP?hj6e3# zH?!)OSfcgZItM;SVKjUPMbh!08+ZUv+PY2OAPW8ZZ46QeK@fp-)ay8Lk3JCCH-$n% zm{m~HMxXtyg=4=phL&WFMzNFrQ~3*JZlk+x`kP=Hp_7Rrna>O0JOYk1=;{0T>uyg^ zI*jD{b8O?bmooIEk;beRh>_iAkrHi|%|#{02J9m6k0WEAsZe9L_(fhYJ!BonzsW&r zFNh6i#4%ORX~N*P4!~4V(`cTR@wLfrm@UQ{<(*djrLd_4S{&6t!fv2Gkr>b-55mqd zWzv6^w2hsL74w6=Mxj)(T4)BUxP%j|U=dmd7@rr>Gse4O4W^$|wF z+Pu*V3n>AN<*I9@eKMM>ghDh4tDDrF9057DNzD3Fzg`*!1#=t3@%uMfUdy&?t8!L$3m>i^7$#Dx1ex4N%sZ=$JG zghw>q%S^Ibb(E&DMPLb{eA<6_0t6 z3mnXabTSt0^t!Y?^ar;!GV0l%@ss={-R&?owS`5pZ@^i|PMzJkb;fmz0F$iSti1`X z#ef?mDUIkp-V}U%Z3zY-8o`+lotg(Mvl=$<%~oc!8+u_Eatl;4H`upZ=HAx8?n{zx z`wLFn7#QFC(Vw33_R&Qq7Ea!hcVWW-*eH=KUcY=?KlY~-m4_1Gm%Ke*5S`xU#!=#QKZh57*Vp8`$; z^tm@J04}64Id^BVByNetEyVze2S$huy*Lf-92gcly3#q=si@P=e<8zO7@tlvY78(vlW*pP(xF-$_%~NRkV7>c*X0<}o!4A&1kb~wTX|=F5;L@V9FM^I~CUmS= z(gAg;;OTz!@aZ}+;58b-8Wa{D$}Ry6bXi~!O{g{kVcXcPG;hyB{e{25s0fB=J05=2+^4osz#sik#PBthULWR#H;h zdb={WaPZm6sU13XZ{sijlph@Y>6GYvXXnU?lfOge za}OTOj~fnG0B9g9D+^(`U#JF5y3uqp7y~fpcz@F-(jMYUUGba}jzPoUGaGjkLw|9; z(&VY+-;bK2vi&2+%6G$#iw{7rRcOc- zG<-dPB7p+LG4VKjvdO8TO-^pOF~nDcKGudyoKuc@UeAONaTP(I~Dk!fiE#Ix&|jWVp4Oa(kLPwu|{YX>L{BOk}oS?}dTUMsugI@pvH=EKQ# zkc0rNBg>`Q7ulKObSIC939wfXY6kvxu4K@i_N9E($)4ddsDclVhAv`+0svI^q~14w z9|HkUh>uW#94Lf6oJbeeAIg{k&R?$L!+l49`Mw)YXb21_UVi&ZC8H| zKlxz2onhbcW8r_s@*7lhlaPRHVL>b#Bh|nQMi7H>ykNAZb*GygR5zsg_^PO1ZsQ~+ zb~L%bLCSpAD7$y-j(zMy!PlBa@r9!W3J@8Y=y=%QDh1r+2#)<^43wxE0n2Fx<(V26 zcX6AxD+yI-cx%DAywR^+FeeBGuNxVeN+x9kt{EsPoJ=QvjjJlE*va7O&AyCyF6$3I zoDNb3NMzg5@sxoOjB8clKli*l<2eOMIt73TevCZCSjsBO%2TIby@ie)!rs5-29>l2 z<55Yrk<9hM(6+o6IX(cMH=ZkXD=P*n-%xn9rQnup zqFQ{%PUbUzlz}ONn&ZaG-+9^zr@Q{KgBGO6o7iLyPy1evxecoLYDlhvt92w_>k3ou z`zMLNHb;K5{#uhU0i3&hjxBp%)7F2<-LRFFIf6_?ZS}}0V2>79xH>x*aQm+Ea=M?c z0|H-KTJ>eC_8h@EI*Bp{JY4ongF?YZd%JU<+Xekjj~~*;P4kz46dD@h9Q5G9gMr*c z&VWn!^~Z`sIX&*)(~X|K_aj!JLh6iMmei9`*Jz}ES2PU~x~BuYVJX zd2G}i-v@$j1GVeC-=76#p0r)wVu>~!RbP_NJhkelUg!eML|LlvsW2nOr&K*1&@Z~q zc>E|)lpQ^bJ1Xyb6;|#b-TbpKNl7G0`s}W<*N76JHL`)$>70GZ6omf;oI7I2vrCao zGR$f+q|`I`@~va56>!C2Oea4=yH13KB(MjZ#otir;=KK3m>r27zYBF2lIMvE`1s7u zp%con!AV2;EiM?u)w{oA|BVpoBB!CdE29W)QUF{ zDoRS1)m>cA6rx0x1@pm+dY8lfHIxDfFA zbh%3xhf@n!LO1?`a1jKqDslwVUmcTNJ%<#xaB8z9w=V}{YzudC5uW8WeI9UDjG(#l zHM8rDxF|`7y)K7%OpPlBVc<|Sf{Kx)AY-gIngeObc*r=&!VG67s0Q3C3g|^LkN0lx zJuF56f+L4t9k|JKkz>OUIqKs@mj5?P1BqJ>kxe%gi&^t@YCQ>22t^bQYI8Tl2AKUc zANUZa1tWCeLr`lm_K?IdTSr!ih4XB!p%FD^0@83?3cAjW4#KSv zUgRB=eDl-Cb5ArPz#=_+$lK;FYu+!rh({uAN@AT{kL%l@B=D}N;V>qjvHNvE2b1%Y z+d!&(54CHpcOR+6e0HovSN>E`_w^UiqZ{FBmv-Jr$wZ7EdbWu}VBZJaYww|snCMS{ zQa=*6y;#3fS7H&sm?|VnuTg$db&(bc#6jkK6l%3QqB^?(u~^#V7pN(u3e(I6Kc|Er zUYPtCI(=dzMc=t@BqIov+wYThslPmNkh`7mutq`n#@N+7V;xx<6|^%34eJ-Vy!9p8 z0b6QFysY-3Vd`+81s18rKZ@dkaC*1a0{AWQrC^TUc&m+omt;li2s*7SmUD`Rs9(cl zr1N?J^ZA8!<6?B1X=*o<@u^bmz);exzome=b1XLE_C~MQ)VJ=Q@;-r|CzJC&Pk-?W z-@O|Y47@QIJFd#3Ti8!f#4x`;UVjTq@4t?cBS7`m@cfi-N#uJjj@H(ZsKKa3`=-y1 z)Ak-;rro-z^1ir@MM4U90TP~6hWxfUT-_TEP`e^z5gEH`_II8?vSjo>Rnw zO2Xlq#{dWZ(LA{D8ggkxilWiXQqT)OuZQnt`Z9A;Gsi+Jy7yWjt`T$gnWDVp(`!5F z@<4{A3}gi#y-a?3%#--t^?sP9qb?d68d6ixBMZ-h{>LG_c$^#HB*}VGS|z10;^GYq zlPFpAa&0?+&*S>lTs)N>nw|FbB1MGVd%kSUpjgSD4>ncYVf1mm&X1m#`on-Lv)690 zzux8B@8b-}fm8gsS)(XyJs!yj_6qQsC{$yMQ}B4jKNl_PYaubmGuDGw%Z9k9X}MejokW7-o;_ zFY5JcUN@UBZ;I+cvg!&k(H@W4kI^@{`j86*|m!{C&Ju$_$IPR6AfU92K zceK{G>3R7x80|V79xv|*y&5Q!lzT0h$j)hL0^z$?*g5VBCNeS-L~E2ywOw}YjVguO z?y>o@@TlG!)It=%Z&lbKZev&{_=PfAqg%mXR_)=w3vZmGCphrN6sWQCgXu{oB?eU^ z>jQb;Njr=+!(5)rY!-+h?zp8;Iw-K*0$ectgUcg}X-Fb3sk>x6O*~!*F~u7oFFihO zafI?X9-_qkfN6MvmGvoM61Ip?{ql$&9`Znjl}o zSE^0}vimKjKI#dXJbMV_G3}u5C{A@`<@7s|-JU9LzaC7u4V6z|G654?79tTPPnEZ7 z|15{WCrohM)3Tph`sS42bnX5?PfNbbp({wH^3 zT--+Z;UoIHB5lxLU7`3r^xM;(6%{M!`@K5wavlQci0kn?7I9qHKiSM;1KY=BgDhD+SR+z6GgiOE`!_0e) z;%)A~!oMUpRWVt=YS>n6o|x6|E3UHuav;=DoZ1ZeJvEHw)OB$@m)3UL5RR5*Q}k{} zV{oEh!T-KIuS~nqAexeR5_fLrbr243l1?nzM&B+Xd9-mi;fii!y!$Su&TaIncZKD& zr;cUz`D?&3e*+Li+o+yp_~JXab{@rt^`Z+6ffkf+wQ7d;rq@DoW45m46zg>^9m?uw zUogCy@-0s4Q>24} ziy6aAnT{1kiV>a@A3^o@velQluIcXw=RU_TK$ZJZQ12RS@hxAQD-+yr+}!F*LQ5AO8mol|gF>8P z)?gQ^W7a6U2F2PkV7#$`6!e?)PRI7kViz9Kws?A8?iE}2;H!VHBe(7C2a%3#d}Ugv zeMu)M<~c^xMEFPLkl6C+;myNEG>w|-cEcSNO)9d@2`#a$T!TfG}d;8>HJH;|N(xD?s!)FLQstKB!S(fIpFk}Pa zmNBP<7R^8cbk!cNucOen&M7qxw`2g*Dtjw>aWX+Y)=ac`YQ@$$3#vlz(fN0a!$ng+ z*$IccehPZc08B}&d8=dIp8IsuyAhQF9TUo64GY|=+I4WJVz9#esvt6bOXs-YIE6ueE2yZ89_6d=?}^<>rV5AY)RR* z#XtRCF#2_O2}{6rV{%6@Up5e!TaWuc0zwfZ>~Dq*bS+)Z5grN9)OD8-BJ-H}>gDC{ z+Q)eTm~bQYf^O{f=6E=pLW++MCN|f(q#wet&3A81(oxskpLl3do0}9d41{|gb@|fq z>IC6dWZ_F;M8SEz1G$?E8iR!1YBiM1b&hE_=9~H=x8qk3?r2 z2i4ktb1KjOnQbm%6@ovaS?c^svf?!C0Xz`KNUKm*hY;^Xz=Kk-h_s-v&v-l1-BTGF zp_xHAd*N<(lR7nY*2EVm4uL;y_;D`l%N>mEw_BQr2S+C0sbuECvm^_dceOj+TkL@8 z9dBT`d6G!eCA=G`GYCq0FVa1yoS(`q*^FRxXe7qCZC>%xv1m?oW5aNJ(@=(R)Z5u?{Eulok|8*qE!c#Eg? zRu~wF_grXWhg?aIz%(S4(j5TpeuWy6bzf7CyCamKn_`_K;#sMG!1;D+0g6d`L7n8O z7+H(~xW}?44TH{Tnl7ayhPj=N)Zlfl419RO!*@`ai})yT{@-Fx>*?ujpUdR=&PPM| zaexSZrn-4XLG#oXa;u`>pU10I+%v|=UOn20&wJn+ai$}z7cLs`;Dko1le+jkaRL$6 z@C9x^uFU7(;}=FFo4&%B!c8Fit{C0ZHy97oCGH>x4G{Wmps}j^{FoA~{Ydft5I<(Z z;~3yib*Ck7*Kv-Pq0zHmz(x^#Q2p(V%es}_ttn;Fy4AUxX~yiv zcz13cF#EIN0b4~;KkKoFpzS)ac&RHLAmoCvp@QaLH3c#{%|*u2C1CY(b_NUB8-e?4 z5|r$j=JEp)q!+lREbYTOz+w442ig}$=bZrr4K|JC+wa(N!7Ck{xjOZamoxO#KWwFf zXF88~;+Dvf-1$Do;g-dX+n#*EY-F)l6$ge$8HA3l$hna$vnMVTTVq<+Xj*xj@FP?2 zQUHl|8P_~)2+C=XZ-7JkQc@~WZx#^NE+uw`uP#)J(qDpS<2+BttNC`)Iei!#GBeSe zcJ4Bt%sd(Gk?UBH%R@b34otoa;g&g+FgHtW+0TIyp0Y~z?({!_#AJ)L?fq|0Ut{%| zKn4@4C&r!4z!70Ga{~Xj1z6k3?v_~%C$oP=xlFjsU%KJv=a>HbvyK;tJ)ElpZ3X5Y zjXH<SCU{-lK|HvaCCtYJ zl`#(*+FcCdJ$E@@co-hK@a9(f;InYi`C`V^Z|IYUIQ_71s4g)cIEU?tDgj5T!0i}# zL;vcBLtlY3BcK-cn`jIwV{p1vyRF{QXi(Wc<)`r(WSeWL04**SMrA0&rN3j)dD$ixrqwEikn>=xo<#64=mDmd5xHBg3mZly% zL&G$T{Y(d$**kFD?=-}nn!D80gpXJWI_Z^RHp6WuI~HOF^qJcR&KX};8uc^03(TJ~ z%>&n4262B|sSYd2?sD;~KDgZ5>$t~Ocrq#tS_KYl+Of}2utt37uscJ^olQG4YE7K= z+n^gGNujvH3Chanr2WaK@{X2nlo`iIRk-qy3^+S3MknS|(S7y9M-$IsjuKykH@Or( zG!_?8I>6@e>CBVNOcA`?QDR_--NmR0g9%$8lPg1WM`x-ji)g7oy`*3*x%jo9|1d*Z zZkt)s@(HrcX?^C%n%2AEB&9CwUa@0>pP`v$b!{oK)NxOWvKO_9k8@ymI`n+~P>e(x zP@FrziTQ#W#O+Id5_`atNf0fP4j!@&;rnc|i+aEO$$yAvO4T;{k&kL-jXoM-DS^}d zy{TvBB$MU21y-L9X@d!Um5EpV`tw~^>lXXQ-jA*)c~mltC7-IEWS7NM4zo@qF}U4D z)8g1}c}!PEhQXU1I;XvVE^NU-@s2XJ`}ao*5m1AJ7bmk zLDXSdm-Joe7uflba}{D6Td~L#ual>Y+^Kpz4D>;mstQX-v~KM6)c8YTzGC4;jHav{ zYYto;LOK%9{kXbLn3!f^+vK~`%eI&&jAmsC+p5n2(^lv4&2r+EzDR+HPP|!+my&-6 zt*j4D9s54y^gGrOt(}{%6Q59!5z;ltMdw2M8@5oQQ0%q-$jH7RBASsQOye^QHZYMJ z4dC^H3;8)U@-HuU1)tG6EFXN2m~ZrH8OHgFX1KcESid98-vGvJ+@QTpJSr5)f`+1V zZF@%7d_X`du61#E5aXjvxJZ2}kW5$kqM;O~>MnK>yJ-olHnuz6_=$9?THned!oT1i zW8z1Ty1YxCI_Uk5Xbpbup_$(P1!f!{?YLOc;DIliYU5w-MVB7CuCjE~o3yH$$GU;I zzZGPZJw`@Bk-ZEOPK`oG(tSo>gFlEBV2Qr-;vwN|KnD*5z`JV9RIDhVOXrad_<}u* zs$9f#S!#wcuQiqh%d0;3iH~sl2w&Dn%UkhCJJergqsBSHFSD0mLYb5thppi58Lhtu zeZtGXKjVQvL_M-7RqMZD&EJ2Z;dNkaOYv^obj6ama{1e?fpWzgFWLF8y5Ayx8zm@( z8^?PlZw;DXK9RUuEXoZXA!Ka}l?6i67R2FVVPTON^0p^stMF2l;UIf+ooW9c;-ONa z6(5MX`39o4$BpV|cI{6p;^j<j=ro-tA)H0HTQZhClQ+Z(Dgr{88$bxT5;9 zv|ogkDxJj&NEOILmdpCwo+77aI0%>s=`xM&wgH6kv)eZ6ku9r+1xs=8SPU~0U&!eX zrV31iPg#f8rR2@xkuZQ*ftFoq~sI{W@1|uy_#xPO-~J75|1RSteY1x29-u zx-69>@mRyY#c*T3jmB|rHh(~Rtc`f_q|U%(0B(YR(-UkW{h99gF#Q)gqVCW^&vR)V!Fhxhd3|c+Z zc*pI}8QK)$)e5InN=Q4qz>x0hT0+@OMMFKZ1bN2if-%xDHavzw{lP<_zW#OX(Qe1g zWY)M-_AB_GAOs%d$Hz)MQ86i40k-IQ8`N(Krm|1(1Oae8L36hn4QEdN+@xv51{#1P zZImmA5dP&chw7-z;|4!b(j(<>zk7QM0_g9eOUZju>!X?i0~we9pfU#_flO(c3{H|g zU{|Hb+v$oHt0mIMm&}r)6H`t0#pxhG){NV`siATZT?SniIj{QG|D~YqELbBC7fp57W7WF?46K}4PqIHu@zty*g0b?Z|+4rciFgk?ol8sUhVV}*y91o(H#)_+V7KCMLg`4G4Ns{;=F1kn@hv4 zstPXf#+FxB#5>|kISify*0sFG`PU@qfgTmeks_@ao3Ov>x^=7@pj{gXjo*6R;n>BS3hogf5|wc|>U4savOJ&0u_trinmb$RXw)gQ!a z1G3RMG`wM_<5d&SwZ)1^lAcfQY`5q7Efkz5@5^O+zbVggb-m!FU$JcYaA{Z=u4L6Z zqc4B`F7YO!&oQQa*w7_#WrS#9EjfTPDOvWsKFTlY`SKga=wW*-rU1n;$Q}j6a?dc7 zQ~!3SOmlGA^{gh@E31hW6^N-Xz7SV@cmgEK(+(-52;06Q7BI3BN*`C3dkkMIn^@BjHV5p=B=!7+TC13{Z-vv^@gE z+~;T9E4CAT3BgY;z(=vYzCX1{<4gohd4o!!(UA$fn918Qpy;Q=R15nXKBtN9SDn4q z*aH$t^FRK(4($b&YL4T`t<_~B!=%uppK{^FmT3SgFqYL73CH;N5^M() z?J`>hnWC#NJRq9k<%39%4r0#mLuF#ff^DQ%g_*U@G9!bn_Y{}c_a_(XV7~>{x+y-n zUcch&jn$>aGf+Jksp~rGrbN7_%f{=2*q6h(e@rAM0OMmn3{Bu#%4e*Ik4J~S7>Gng zvO^&P&m9Ly4+cE^b+hRA#TA9jwh?0^JN|t}l>uD;(>!`SOFU_BUO%!y&7=~np9$?`K#q@{HN2^WeL3uL*R&lwX`BiDCGNRR?l z3L0KNT)tW&wz`7Rr1Uq@>&d}(OG{KA;#7*3k*)#Jfe-De#7(+E@%D1>(y!>HPtHb<=3#$^}T_0jT78YcMO>Nc&LI!Auf=f|&Fj5H@U` zso5HcC42$eJbHb|ecvomkkFA?PFM|($l?34nOMR zoU?oRIN}AMYS8-yR0_4tfH1K6Qu+PFzeP!qU38vOw+kdeb?k%>X-AbDR_B2yle=gh z5jL&z0di7@n1j|tS%%V>ro9lCY1MJctoSa?=u&_WkImaXMf)U~8oPYB@X3^i0WG@l z{sEuE6)n+XzcTVQR$}M2eUZ|~ZgOlVzDfzkI6Fbi5#EP%3p2P#@m@TqpZM-!Kn(w8 z$SZ@uOj-F)32gS(C2S4;FcoiBf|wc5*lj?b-O73MUEuo_OpryRa=I-)J@ZR zZAhLBZE-nT*mAX?EyTBE_rQR@{$+?hi)_!Ds?@0)Eq{IhIX=%~{zpZ_DK-|+tSz1u z>?ars(xT%egqREx&m9PPU_?4^*O7^`{&evP^3Q{Z*bflCqFxPOTU%Q&^}+aWkFtUM z{mV*Nm`#579}pL&1Hym=F(VYDBRWZ=Igao+xR}d`KClU`nBE-K$X^`+#3>GIB2)fo2+*cwhGDq--!p7;IIdbuw0}tH5ra5{ zICha9p}`uabw39x3BmQGUN_kOBo_&WwzZH7O=ST<@}E!1xfAVbDvH#)Y~CH61I+K^ z>iZ00fS0owRn>pAWm~wicu^Dg6)o_Ay%4lC-~&mxg9={Llno{;%LLb5`)nIMg-Ut7 zTBrR9n_+s~@WbU^*$HozTO&E`sev?6B%lht0!{(@K3&_z!O(UX_3=v zjPCZyrk@ilr&*hW#w07vJp#t|BpFDqiK{(v#^eB=4%f>O*&3Be@Se_`3H2-0?3h*z z$k3vaTdFx2@V{+Q`ro6OAX+#r<+gff=-Zm(dkE2bWkM<2(o99cTNTN{r}YgDXPoNR z-bQT3Ue(bbKQioH)lZ$$CoZrMIXE)^bg+xx4ooNWEI=)avnEnXZ0O2+;`+3BmO^0q z2HN?5L;-6eD*C$S}>k1fl|7mkP)S*HQq4TpV8cb#&eOfw#1-IH2z^SYOM(s@&@G1=r$Mvd|C#djc)NJDm#18|Y&d<7_)&{k z^j0EsSqUcmgxf8rV~8xLk}IS$TcJw+{O|9?$Q%A4>NiIa8^IU^Xdst=auoPC^1^u} z|7L~({kBH!>hfskABlJ1l4^MVxuf32IeJ8*(3v+U-5dV1D9c^ky=L)oL9x2SV6pQJ`}?fWB>&)TA}(@U;Y zf|R7R7OgJ+I|YC?61CbyCrkyYN>pukc*9D@!@e00@R%$>iCGM@MPqK(2puwORwg+Q z^a255grYv5_4R5JB_n_d550wAXv@X^eCKX}CgAVf=dTld_Z#Zue2aOQ0Db-%-8$kD zEZ+hh&_(&fD%(noekEwZzeVEVa3wTS3J@Z17=B!eihgLTpk8osf_x=XKvt6<`yQ%s zknO0~n-ggQi{q^WoZAtOhvGOG4mfEK*JM>4GB;BZ-gg^Cc*G`j{0 zhc<<|wSBbRPRK>M_|m^;Ou*D7#RIQ2*SrResW&eBy?)|3?Z&*5q`310Z42;QZd`Qv z87B>57JWDG$q~{mu01eU@_u%x?^0t}@dHg){Mx0h-%IwfRfjuGkGRV=7#KHi`gJzK z(d)zN?$^sgb}enC({j}Uz{CrHix1>aM*igzA*^PkA*y{Mm~=)tmro*t)2o4h6E4EF=5c-QbggBO<<08wTU%Mp^P`+CLwB+nt zPfA~gwxMWT90oNG$;?7!m=&lh>VI<%KY0PL`S~z6g0xckbUO~3ssfJmvup~@pj){M zkmdrqIyNw%YBZMnV(q~(IuXMh=9_kIuU6G5R??lyL0Ht!vN_1Qc~(Ee00X@so1l6C zJuWS25A}&@(ek20rI8TYtcm#?8FolHT1Yvial47c6>$&mA~@-x?GF!JKK<~Jxq7F_ z|HU==5Z7Fl@oXeI;-B36pjf%jb!Oa^J95Hedz*+1t`UJw_@h+G65+^GY=)*b!Kb&C zi3cCOLVXk*xDkm|XCh0$NV60w1{+O)msqud2o=%{gp~q`8{O{Y%-SCsio$C?0LT8f zkjPTlFnX%bYX)Ln1)1k}3G0N5Mv#VJPD|{lUUhl1Z63kuF8|M%&4k*vOIGe{xgQv! zag#!EVLCKAjYH86m88E3EhTdwh9N`A@my@n2UYbN9z?MC-ljp8yS)pu_9TvQtG<{Y zqqsLRawy$-g~z#k(uf;Jym07t3{t=-P8JQKkzVsZ{`#viO5`tYJ7%`F+uJ+%to^dT z{@U_=+s4T2G}gdcpy97_INkFfeqrtP!^N|l%@R7cXGm9J~7pG6_t1$NSv|FcTyx=tX}u0Gb^f1gS~^@Tkf`DjV%+B^SG ztBb#beW6g1lr3iT{Q|*{{L^nOzcOz+@I)*EOb~S0$Q!^5FuZ|6GA`V$NFr_0@kp?mPN) zE7$!MdTAto^ly*q5BAyZ)~{XvaaQONu>G(%wfSE@hqS)+ry#_Zd2{_Qh4Fv*n|pk! zLLsN0K#d}E+F6P8*Z+1wb|Lid$Ugu7SRvd?u%J^=iu$kB!BSXg#&k3_T^^j-EOq@a zdC)&RE5$kT)17mf?J=EO*Z;>d(G0}H(Q~2vw!$p@w?Cjkj|$TLe<}L^)0fk&i#`{a@G-nmf7?|IgQA z^>Zf?BH5*LeYH&gFMomTJN6%6bOXFh8y$cmZZ02n{^>o|E^v$|=3AbH zD?m(!%??CNcFiIB+tVBrQuRCG=#nM2rT@Pkm-iV&zdjP9|7n}t0CybYjA&lH2Wy{i z{Rq0?~a!NbatAy*8D%-TvZWomw1jUvicaHM{K@v z{V$NjKYYVIK~=%53a!8L8UFEoAgV)50)-0emMXe`_@uuqN6cQ;A6?O%8%ErB{N?8> ztF!tqIAJ(?T?)MZq|(#B{Q;gAJ?gjKzu=$$xb>xX$QQQ;$!9Y^EP6k`4*ropp?o~` IsNs$O0gK-7U;qFB diff --git a/documentation/modules/ROOT/assets/images/solution-odc.png b/documentation/modules/ROOT/assets/images/solution-odc.png new file mode 100644 index 0000000000000000000000000000000000000000..2dc3afebe8c9dc7301b3993f7a2e18c33ac3ceae GIT binary patch literal 115310 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%0DP#dQl zZ;KQTmsOM>ivT8n$naxdLww)3`uf?vJ&czVT0-OY#+ zR-~+3|7FnG6USk(ObS-r*B9>@7N=E6!aP5M6=Z_0V$%L*$3vsaQ#yT)3+-*|Rj-v? zQ#z4yeSj&_`E`T5w&k^|DSAIC|4Qoz$yJ<&BsfF^2Xwst9X)WPp7|cML4`1kMkI+) z1xzPz%1?28yP=G*It$P9kvi*;orf|Txu4B`SRoT3yvZf=G_gQA{t*XE(`{M9kFv*- z<6l_qU^$g5HVxQ{_NSd%RUVU}E+h4pZWMpx@j#i{G=)Xi6vZWNg}|M%EE|W*;Sc>r z3=5Em-(jYxpgVxDnkCCFDVlWivx24Ia`GhuTG)GQC}EzU3*{ds`H441sdhBTu7Js} zD0AD7QZgnPu*`?XdYmWexA}`V67$VThhyUNv}DxmOEHCZfNZt@7O#ul1T`)Oc)z`tK#G0&M#f^PSD26c0e=5yGL4^u05J@FVe=mp1Gi@ ziDEvj?3v)FMfPHB(e_O-l(`Xermgb=msRx_b~N_COi75$HEFyle5c{o2uqz<=C`bh znH*i{`<*%~vyt%l0QHlLRfpFn)z_KGYkFI}@_d#xK5{B(UxmG{Z}wB1dZ=eZtNkOL zOH0nqo>Vxzu=Q3mU=HEp>4j=j4*%(VfM!Q;#fs9}7iI%CZ;vmPvt!$E1xY!59j-53 zuV^gj4*|QJ0bHH`)`G1V6>nCTE5c8zxs#cLTY6IA*kHTt1&Voxz~YOrB$(A%U6tLm z?d_f*`c8^=Qr*gDL@$1Qseh}nk`WepoNKaE90!_Z{$UaZyVWqRfd~E{kV^dO4IK$# z(Bsop9`m(Y-*3Jq1PUh(f0rM(laFNKeVRd~mSc8b?zj*bp@eC3cTxZX+Sb;_$c01= zReq<4RGBf)ufMsn)|+EI{iZRDj=~-V7`u*lG}-e=(!SuL+uwE{FaUueN6LihI&`6D zRXn|eq07(kwXUN^*y^W3pT>m3nV=@lr5mU7T`W2pu+rV6N4HvIHb7Hcsf$Hxvy#t( zA#$kFU>#G~Md>+EH}cagwB0Df+KQz98~fjqJpaKDInODEy|tFE3_wjfq5Ybn==UX3 z3X&^hk)XgN@?g%%C5WKmN!F--Jhk~g++FKwL^QTdyKtnv#%o*(H(0&@NCrLAby{i$ zHpA9+9}fEZ6W7Vz0@MRW5Ro*qG?nf5Z`B~lWJv3H4qP$4 zTM+D;nXZb_^PpiSZeGek6V>%kTbuJ-KPOwzXvcDV&HHTxIcK|c^QF&17cBSv!sEpL zHPyIf50!CTYy_r2<-3JAvR1gN3aV{lnx!9SYMh6>Vp_EzrQo-gAaXJICef*YJo7lk zy{*&Ky<@19tQCu3hRV!sz=Nnf@RjAiTZ zkd$dnZ~q;|aQPoadwxAtr+>%rMpeo4y)&AUa+5Pw>akt4m}|dS{+}KPVs1Whd>Ohd z^0);%s!KG`2M&67(~r-}V;c}Zh))ZImrFENDdaP)76C7wDCyd721Bp)_s+W0ceZn% zAKHzk2So%|2PUbCH^}aC$2y1j`{GIdLf6ZG|DJrUA)`HRIIxFBVllc&eDi*;j zH)(GJvd+KL0LWvtviD+-Ml14HO5GQYO5KYW%*xn(;H-HL#Ox@mpE3JhXhf198=FAM zjcXc#d_x;)-Vt$G#M3vl^S54{o8c5ll^}vYaM0QnS0DY%(Ry<$Y_Dj)^?x~&75O{& z-v$Nk0_Jo-viQ*R8(fQ&V-R7^zkYCZ)B^u!&8w65&+gP7hmn#cKke)uf;>F>GZWeE ze>-Bt8ZoynS^Fhmg!^xp;|iBtkQfN&sPLOnJg}yYY1F5gAu`k?Soh!H<$o02{r~ap ZzRC_`Dn(8rO8LzPfB3`Y#fQn+X5_ literal 0 HcmV?d00001 diff --git a/documentation/modules/ROOT/nav.adoc b/documentation/modules/ROOT/nav.adoc index 103ce16..ecf986e 100644 --- a/documentation/modules/ROOT/nav.adoc +++ b/documentation/modules/ROOT/nav.adoc @@ -12,12 +12,6 @@ ** xref:03-demo.adoc#_initial_application[{module}.{counter:submodule3}. Initial application] ** xref:03-demo.adoc#_run_the_demonstration[{module}.{counter:submodule3}. Run this demonstration] -* xref:04-workshop.adoc[{counter:module}. Workshop] -** xref:04-workshop.adoc#_installing_the_workshop_environment[{module}.{counter:submodule4}. Installing the workshop environment] -*** xref:04-workshop.adoc#_before_getting_started[{module}.{counter:submodule4}. Pre-requisites] -*** xref:04-workshop.adoc#_installing_the_environment[{module}.{counter:submodule4}. Installing the environment] -** xref:04-workshop.adoc#deliver_wksp[{module}.{counter:submodule4}. Delivering the workshop] - * xref:developer-resources.adoc[{counter:module}. Developer Resources] * https://redhat-solution-patterns.github.io/solution-patterns/patterns.html[Explore Red Hat Solution Patterns^] \ No newline at end of file diff --git a/documentation/modules/ROOT/pages/03-demo.adoc b/documentation/modules/ROOT/pages/03-demo.adoc index 47f3389..a04a233 100644 --- a/documentation/modules/ROOT/pages/03-demo.adoc +++ b/documentation/modules/ROOT/pages/03-demo.adoc @@ -43,7 +43,7 @@ public void completeTransit(Long driverId, UUID requestUUID, Address destination invoiceGenerator.generate(finalPrice.toInt(), transitDetails.client.getName() + " " + transitDetails.client.getLastName()); // <2> - eventsPublisher.publish(new TransitCompleted( + eventsEventSender.publish(new TransitCompleted( transitDetails.client.getId(), transitDetails.transitId, transitDetails.from.getHash(), destinationAddress.getHash(), transitDetails.started, Instant.now(clock), Instant.now(clock)) @@ -171,6 +171,12 @@ async fn recv( } ---- +[NOTE] +==== +The example above uses a simple switch statement to determine the route for the given type of the event. +In a real application, you would probably use a more complex logic to determine which method should be called. +==== + Let's see also the _Cloud Event_ sender, that uses the _HTTP REST_ client to send events to the _Event Mesh_: [source,rust] @@ -202,17 +208,14 @@ impl Sender { } ---- -[NOTE] -==== <1> The client uses _POST_ method, to send the _JSON_ representation of the event to the sink. The _sink_ is the URL of the target, in this case the url of the _Event Mesh_. -==== ==== Event Mesh -In this section, we'll use the _Event Mesh_ setup to communication between the different parts of refactored code. +In this section, we'll use the _Event Mesh_ setup to communication between the extracted Drivers module and the different parts of the application. -Here's the _Event Mesh_ central component configuration, the _Broker_, which will be used in this example. +Here's the configuration of the _Event Mesh_'s central component, the _Broker_, which will be used in this example. The _Broker_ here is the _Knative_ component, and will be deployed in the _Kubernetes_ cluster. [source,yaml] @@ -229,22 +232,269 @@ spec: retry: 10 # <3> ---- -<1> The `backoffDelay` is the delay between retries, and us use `+200ms+` initially. -<2> The `backoffPolicy` is set to `exponential`, which means that the delay will be doubled each time. -<3> The `retry` is the number of times we retry before giving up. +<1> The `+backoffDelay+` is the delay between retries, and us use `+200ms+` initially. +<2> The `+backoffPolicy+` is set to `+exponential+`, which means that the delay will be doubled each time. +<3> The `+retry+` is the number of times we retry before giving up. [IMPORTANT] ==== -Because the policy is `exponential`, the maximum time the _Broker_ will be retrying is 6 min and 49 sec. -In the above configuration, after that time is reached, the event will be dropped. +The policy is `+exponential+`, and the `+retry+` is 10, which means that after approximately 6 min and 50 sec the event will be dropped. ==== [NOTE] ==== -A `+deadLetterSink+` could be configured for the _Broker_ to send the events that failed to be delivered in time to a back-up location. +A `+deadLetterSink+` option could be configured for the _Broker_ to send the events that failed to be delivered in time to a back-up location. Events captured in a back-up location can be re-transmitted into the _Event Mesh_ later. ==== +==== Legacy application changes + +The last part of the refactoring will be the changes needed in our legacy Java application. +We need to remove the _Drivers_ logic and send events to the _Event Mesh_ instead. +We also need to accept new events coming from the _Event Mesh_, as the calculated fee will be transmitted as such. + +Here's the refactored `+completeTransit+` method: +[source,java] +---- +public void completeTransit(UUID requestUUID, AddressDTO destinationAddress) { + // ... + Money finalPrice = completeTransitService.completeTransit(driverId, requestUUID, from, to); + // ... + driverFeeService.calculateDriverFee(requestUUID, finalPrice, driverId); // <1> + // ... +} + +@EventListener // <2> +public void driverFeeCalculated(DriverFee driverFee) { // <3> + Objects.requireNonNull(driverFee.ctx.getSubject()); + UUID id = UUID.fromString(driverFee.ctx.getSubject()); + transitDetailsFacade.driverFeeCalculated(id, driverFee.data.fee); +} +---- + +[NOTE] +==== +<1> Notice, we are just invoking the `+calculateDriverFee+`, that doesn't return anything. +It's asynchronous. +<2> We are using the `@EventListener` annotation to listen for the business events withing the applition. +Don't confuse this with _Cloud Events_ that are sent and received outside the application. +<3> The exact fee is calculated by the _Drivers_ module, and we'll be notified later, with the `+driverFeeCalculated+` method. +==== + +To make it work, we need to add a new _Cloud Event_ sender and listener. +That's being done similarly, as in the case of _Rust_ application. + +Below, you can see how you may implement the _Cloud Event_ sender: + +[source,java] +---- +@Service +public class DriverFeeService { + + private final CloudEventSender eventSender; + + @Autowired + public DriverFeeService(EventSender eventSender) { + this.eventSender = eventSender; + } + + public void calculateDriverFee(UUID rideId, Money transitPrice, Long driverId) { + eventSender.send(new CalculateFee( + rideId, + driverId, + transitPrice.toInt() + )); + } +} + +@Service +public class CloudEventSender { + + private static final Logger log = LoggerFactory.getLogger(EventSender.class); + + private final KnativeConfig knative; + private final List> converters; + + @Autowired + CloudEventSender(KnativeConfig knative, List> converters) { + this.knative = knative; + this.converters = converters; + } + + public void send(Object event) { + try { + unsafeSend(event); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + private void unsafeSend(T event) throws IOException { + Into convert = (Into) converters.stream() + .filter(c -> c.accepts(event)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException( + "Cannot find converter for " + event.getClass())); + CloudEvent ce = convert.into(event); + URL url = knative.getSink(); + log.info("Publishing event to {} : {}", url, ce); + HttpURLConnection http = (HttpURLConnection) url.openConnection(); + http.setRequestMethod("POST"); + http.setDoOutput(true); + http.setDoInput(true); + + HttpMessageWriter messageWriter = createMessageWriter(http); + messageWriter.writeBinary(ce); + + int code = http.getResponseCode(); + if (code < 200 || code >= 300) { + throw new IOException("Unexpected response code " + code); + } + } +} +---- + +Once again, notice this is just a simple _HTTP_ client doing the _POST_ request, with the body being the JSON representation of the _CloudEvent_. + +The last part to see is the _HTTP_ listener on the legacy application side. +This listener will be responsible for receiving events from _Knative's Event Mesh_ and converting them into our custom event type: + +[source,java] +---- +@RestController +public class CloudEventReceiver { + private static final Logger log = LoggerFactory.getLogger(Receiver.class); + + private final EventsPublisher eventsPublisher; + private final List> froms; + + @Autowired + Receiver(EventsPublisher eventsPublisher, List> froms) { + this.eventsPublisher = eventsPublisher; + this.froms = froms; + } + + @PostMapping("/") + public void receive(@RequestBody CloudEvent event) { + log.info("Received event: {}", event); + + for (From from : froms) { + if (from.matches(event)) { + Event ev = from.fromCloudEvent(event); // <1> + eventsPublisher.publish(ev); // <2> + return; + } + } + + throw new IllegalStateException("No matching event type consumer found"); + } +} +---- + +<1> We unwrap the _CloudEvent_ into our custom event type +<2> And publish it withing the application, using the framework's _EventsPublisher_ implementation. +The event will be transmitted to the methods annotated with `@EventListener`. + +[CAUTION] +==== +Don't confuse the the framework's _EventsPublisher_ with _Cloud Event_ sender and receiver. +==== + +==== The wiring of our _Event Mesh_ + +To complete the solution, we need to configure the _Event Mesh_. +The configuration describes the rules for receiving and sending events from and to the _Event Mesh_ and the application modules. + +Here are the sources in our case: + +[source,yaml] +---- +apiVersion: sources.knative.dev/v1 +kind: SinkBinding +metadata: + name: drivers-binding + namespace: demo +spec: + sink: + ref: + apiVersion: eventing.knative.dev/v1 + kind: Broker + name: default + namespace: demo + subject: + apiVersion: serving.knative.dev/v1 + kind: Service + name: drivers + namespace: demo +--- +apiVersion: sources.knative.dev/v1 +kind: SinkBinding +metadata: + name: legacy-binding + namespace: demo +spec: + sink: + ref: + apiVersion: eventing.knative.dev/v1 + kind: Broker + name: default + namespace: demo + subject: + apiVersion: serving.knative.dev/v1 + kind: Service + name: legacy + namespace: demo +---- + +We are using the _SinkBinding_ resource to bind an event source (the _Service_) with an event sink (_Broker_). +We have two applications that will feed their events into the _Event Mesh_, so we need two _SinkBinding_ resources. + +Lastly, we have to configure the _Broker_ to send events from the _Event Mesh_ to the expected application modules. We use the _Trigger_ resource for this purpose. + +[source,yaml] +---- +apiVersion: eventing.knative.dev/v1 +kind: Trigger +metadata: + name: trg-drivers + namespace: demo +spec: + broker: default + filter: + attributes: + type: cabs.drivers.calculate-fee # <1> + subscriber: + ref: + apiVersion: serving.knative.dev/v1 + kind: Service + name: drivers + namespace: demo +--- +apiVersion: eventing.knative.dev/v1 +kind: Trigger +metadata: + name: trg-legacy + namespace: demo +spec: + broker: default + filter: + attributes: + type: cabs.drivers.driver-fee # <1> + subscriber: + ref: + apiVersion: serving.knative.dev/v1 + kind: Service + name: legacy + namespace: demo +---- + +<1> Note, we specify the type of the event, as a filter. + + +=== Conclusion + +Let's step back and take a look at our refactored code. +The diagram below shows the sequence of operations that happen when we initiate our `+completeTransit()` method. image::https://www.plantuml.com/plantuml/svg/VP1DJiCm58JtFiMZ-rmWYwgqeHkeX2WNUBK7Ok4ubdyYzVQuZKbe5TZ5olTcFiqcHFOnTKOyn1OTIC8d0xPLdwBH5iBb_rfgnpRIwWMVBC_qwDoAED3ul4MUBKSzW9u6vES1eRsYMzz_mT-YZS-W3tJeLUwyOdlW23zeYJkK8vyuZ52p5O9bRk687uTYLgrB4zNqcav6XvPsR6GocTsZQ8d2L1aV3slQzVP3-uuKpCNgB1JkEwQpzI_FcjxoL5XgcUvdMioVL4soi-iuIOQcE5N259RYPgKYMNJ-3lfdkMPRqp7s7lJkjQFBvWihR61Lwimt[width=100%] @@ -278,22 +528,358 @@ deactivate Legacy The diagram illustrates the flow of events between the legacy application, the Knative _Event Mesh_, the fee calculator service, and the datastore. -In this video you can see the above example presented by Red Hat' employee https://github.com/cardil[Chris Suszynski]: - -video::Rc5IO6S6ZOk[youtube,width=800,height=480] - -Next, you can learn how to walkthrough this demo. +Next, you can learn how to walk through this demo. == Run the demonstration === Before getting started -// TODO: Add instructions how to run +We'll be using the Red Hat OpenShift Container Platform (OCP) 4.x cluster, so make sure you have it available in your environment. + +You could use the https://developers.redhat.com/products/openshift/overview[Red Hat's Developer Sandbox] to spin up an instance for you. + +Alternatively, you can use the https://developers.redhat.com/products/openshift-local/overview[OpenShift Local] installation. +Make sure to give it enough resources to fit the Serverless Operator and our demo application. === Installing the demo -// TODO: Installation guide and basic test of the demo installation if needed +==== Installing the Serverless Operator + +To install the Serverless Operator, follow https://docs.openshift.com/serverless/1.35/install/preparing-serverless-install.html[the documentation steps]. + +The *TL;DR* version would be to apply the following manifest, and wait until the operator is ready: + +[source,yaml] +---- +apiVersion: v1 +kind: Namespace +metadata: + name: openshift-serverless +--- +apiVersion: operators.coreos.com/v1 +kind: OperatorGroup +metadata: + name: openshift-serverless + namespace: openshift-serverless +spec: {} +--- +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: serverless-operator + namespace: openshift-serverless +spec: + channel: stable + name: serverless-operator + source: redhat-operators + sourceNamespace: openshift-marketplace +---- + +Here are commands to apply the above manifests. + +[.console-input] +[source,shell] +---- +git clone https://github.com/cardil/cabs-usvc +oc apply -f cabs-usvc/deploy/serverless/operator.yaml +oc wait csv/serverless-operator.v1.35.0 \ + --for 'jsonpath={.status.conditions[?(@.phase == "Succeeded")]}' +---- + +[CAUTION] +==== +Replace the `+v1.35.0+` with the actual version of the Serverless Operator. +==== + +Here's the expected output + +[source,shell] +---- +namespace/openshift-serverless created +operatorgroup.operators.coreos.com/openshift-serverless created +subscription.operators.coreos.com/serverless-operator created +clusterserviceversion.operators.coreos.com/serverless-operator.v1.35.0 condition met +---- + +==== Installing the Serving and Eventing components + +To install the Serving and Eventing components, follow https://docs.openshift.com/serverless/1.35/install/installing-knative-serving.html[the Serving documentation steps] and https://docs.openshift.com/serverless/1.35/install/installing-knative-eventing.html[the Eventing documentation steps]. + +Again for *TL;DR* version for small, development purposes, you could apply the following manifests, and wait until the components are ready for operation: + +[source,yaml] +---- +apiVersion: v1 +kind: Namespace +metadata: + name: knative-serving +--- +apiVersion: operator.knative.dev/v1beta1 +kind: KnativeServing +metadata: + name: knative-serving + namespace: knative-serving +spec: + high-availability: + replicas: 1 +--- +apiVersion: v1 +kind: Namespace +metadata: + name: knative-eventing +--- +apiVersion: operator.knative.dev/v1beta1 +kind: KnativeEventing +metadata: + name: knative-eventing + namespace: knative-eventing +spec: + high-availability: + replicas: 1 +---- + +Here are commands to apply the above manifests. + +[.console-input] +[source,shell] +---- +oc apply \ + -f cabs-usvc/deploy/serverless/serving.yaml \ + -f cabs-usvc/deploy/serverless/eventing.yaml + +oc wait knativeserving/knative-serving \ + --namespace knative-serving \ + --for 'condition=Ready=True' +oc wait knativeeventing/knative-eventing \ + --namespace knative-eventing \ + --for 'condition=Ready=True' +---- + +Here's the expected output + +[source,shell] +---- +Warning: resource namespaces/knative-serving is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by oc apply. oc apply should only be used on resources created declaratively by either oc create --save-config or oc apply. The missing annotation will be patched automatically. +namespace/knative-serving configured +knativeserving.operator.knative.dev/knative-serving created +Warning: resource namespaces/knative-eventing is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by oc apply. oc apply should only be used on resources created declaratively by either oc create --save-config or oc apply. The missing annotation will be patched automatically. +namespace/knative-eventing configured +knativeeventing.operator.knative.dev/knative-eventing created +knativeserving.operator.knative.dev/knative-serving condition met +knativeeventing.operator.knative.dev/knative-eventing condition met +---- + +==== Installing the demo applications + +To install the Demo application, apply the following manifests. + +* https://github.com/cardil/cabs-usvc/blob/main/deploy/apps/legacy.yaml[The legacy application] +* https://github.com/cardil/cabs-usvc/blob/main/deploy/db/redis.yaml[The Drivers database] +* https://github.com/cardil/cabs-usvc/blob/main/deploy/apps/drivers.yaml[The Drivers module] + +Here are commands to apply the above manifests. + +[.console-input] +[source,shell] +---- +oc create ns demo +oc apply \ + -f cabs-usvc/deploy/db/redis.yaml \ + -f cabs-usvc/deploy/apps/drivers.yaml \ + -f cabs-usvc/deploy/apps/legacy.yaml + +oc wait ksvc/drivers \ + --namespace demo \ + --for condition=Ready=True +oc wait ksvc/legacy \ + --namespace demo \ + --for condition=Ready=True +---- + +Here's the expected output + +[source,shell] +---- +namespace/demo created +pod/redis created +service/redis created +service.serving.knative.dev/drivers created +service.serving.knative.dev/legacy created +service.serving.knative.dev/drivers condition met +service.serving.knative.dev/legacy condition met +---- + +==== Configuring the Event Mesh + +To configure the Event Mesh, apply the following manifests. + +* https://github.com/cardil/cabs-usvc/blob/main/deploy/mesh/broker.yaml[_Broker_] +* https://github.com/cardil/cabs-usvc/blob/main/deploy/mesh/sources.yaml[Sources] +* https://github.com/cardil/cabs-usvc/blob/main/deploy/mesh/triggers.yaml[Triggers] + +Here are commands to apply the above manifests. + +[.console-input] +[source,shell] +---- +oc apply \ + -f cabs-usvc/deploy/mesh/broker.yaml \ + -f cabs-usvc/deploy/mesh/sources.yaml \ + -f cabs-usvc/deploy/mesh/triggers.yaml + +oc wait broker/default \ + --namespace demo \ + --for condition=Ready=True +oc wait sinkbinding/drivers-binding \ + --namespace demo \ + --for condition=Ready=True +oc wait sinkbinding/legacy-binding \ + --namespace demo \ + --for condition=Ready=True +oc wait trigger/trg-drivers \ + --namespace demo \ + --for condition=Ready=True +oc wait trigger/trg-drivers \ + --namespace demo \ + --for condition=Ready=True +---- + +Here's the expected output + +[source,shell] +---- +broker.eventing.knative.dev/default created +sinkbinding.sources.knative.dev/drivers-binding created +sinkbinding.sources.knative.dev/legacy-binding created +trigger.eventing.knative.dev/trg-drivers created +trigger.eventing.knative.dev/trg-legacy created +broker.eventing.knative.dev/default condition met +sinkbinding.sources.knative.dev/drivers-binding condition met +sinkbinding.sources.knative.dev/legacy-binding condition met +trigger.eventing.knative.dev/trg-drivers condition met +trigger.eventing.knative.dev/trg-drivers condition met +---- + +The OpenShift Container Platform provides can provide a clear visualization of our deployed solution. + +image::solution-odc.png[width=100%] + +The console shows two sink bindings on the left, and they are feeding the events from the applications to the _Broker_ (depicted in the center). +on the right, you could see the two applications deployed as _Knative_ services, and two triggers (as lines) that configure the _Event Mesh_ to feed appropriate events to the applications. === Walkthrough guide -// TODO: How to run through the demo +With the demo pieces deployed on the cluster, we could go ahead with testing the functionality. + +For the sake of brevity, the legacy application, at startup, prepares some development data in the in-memory database its running on. +We will leverage that data to complete transit without the hassle of simulating the whole ride. + +Because we use serverless deployments, the services could be scaled to zero. +This fact makes it a bit harder to listen to the application logs. +We recommend using https://github.com/stern/stern[`+stern+` tool] to easily listen to both apps, even across scale to zero periods. + +[.console-input] +[source,shell] +---- +stern \ + --namespace demo \ + --container user-container \ + '(legacy|drivers).*' +---- + +Alternatively, you can use a regular `+oc+` command and a bit of scripting: + +[.console-input] +[source,shell] +---- +oc logs \ + --selector app=legacy \ + --namespace demo \ + --follow & + +while [ $(oc get pod --namespace demo --selector app=drivers -o name | wc -l) -eq 0 ]; do \ + sleep 1; done && oc wait pod \ + --namespace demo \ + --selector app=drivers \ + --for condition=Ready=True && \ + oc logs \ + --selector app=drivers \ + --namespace demo \ + --follow +---- + +In the second terminal, call the legacy endpoint by sending a _POST_ message like the following: + +[.console-input] +[source,shell] +---- +curl -Lk -v -X POST -H 'Content-Type: application/json' \ + $(oc get ksvc legacy --namespace demo -o jsonpath='{.status.url}')/transits/8/complete \ + --data-binary @- << EOF +{ + "country": "Polska", + "city": "Warszawa", + "street": "Żytnia", + "buildingNumber": 32, + "hash": -580606919 +} +EOF +---- + +You should observe the cURL command succeeded, and return the ride data. +Moreover, the logs of both applications should be updated. + +On the _Legacy_ application you could see the log line, with shows the application is sending the _Cloud Event_ to the _Event Mesh_: + +---- +INFO 1 --- [nio-8080-exec-1] i.l.cabs.common.cloudevents.Publisher : +Publishing event to http://broker-ingress.knative-eventing.svc.cluster.local/demo/default : +CloudEvent{id='83720fe5-02ee-4a3e-9b22-5c287fb68d10',source=usvc://cabs/legacy, +type='cabs.drivers.calculate-fee', datacontenttype='application/json', +subject='4e630a96-4d5c-488c-a53b-9554c0bcb97e',time=2025-02-04T17:32:20.638351262Z, +data=BytesCloudEventData{value=[123, 34, 100, 114, 105, 118, 101, 114, 45, 105, +100, 34, 58, 49, 57, 57, 51, 52, 51, 50, 53, 53, 50, 44, 34, 116, 114, 97, 110, +115, 105, 116, 45, 112, 114, 105, 99, 101, 34, 58, 53, 49, 48, 48, 125]}, +extensions={}} +---- + +You can notice the `+cabs.drivers.calculate-fee+` event was later routed to the _Drivers_ service, which calculated the fee. +After the fee was calculated, the `+cabs.drivers.driver-fee+` event was published back into the _Event Mesh_. + +---- +[INFO drivers::app::events] Received event: + CloudEvent: + specversion: '1.0' + id: 'f94792bc-9c38-4db1-8da6-b6a28d1b4847' + type: 'cabs.drivers.calculate-fee' + source: 'usvc://cabs/legacy' + datacontenttype: 'application/json' + subject: '005be37e-8971-4a5b-b5e7-dd18de3c1184' + time: '2025-02-04T17:48:11.641317948+00:00' + knativearrivaltime: '2025-02-04T17:48:11.655926003Z' + Binary data: "{\"driver-id\":1993432552,\"transit-price\":5100}" + +[DEBUG drivers::drivers::service] fee event: Subject { + id: Some("005be37e-8971-4a5b-b5e7-dd18de3c1184"), + entity: CalculateFeeEvent { + driver_id: Identifier(1993432552), + transit_price: Money(5100) } } +[DEBUG drivers::drivers::service] fee: Money(4856) +[DEBUG drivers::support::cloudevents] sending cabs.drivers.driver-fee event to + http://broker-ingress.knative-eventing.svc.cluster.local/demo/default: + Event { attributes: V10(Attributes { id: "939babd7-6a85-4859-b45b-66087aba9418", + ty: "cabs.drivers.driver-fee", source: "usvc://cabs/drivers", + datacontenttype: Some("application/json"), dataschema: None, + subject: Some("005be37e-8971-4a5b-b5e7-dd18de3c1184"), + time: Some(2025-02-04T17:48:12.897943139Z) }), + data: Some(Json(Object {"driver-id": Number(1993432552), "fee": Number(4856)})), + extensions: {} } +---- + +In the end, the `+cabs.drivers.driver-fee+` event was routed to the _Legacy_ application, by _Event Mesh_. +You could see the evidence of it in the logs. + +---- +INFO 1 --- [nio-8080-exec-2] i.l.c.ride.details.TransitDetailsFacade : + Driver fee calculated for transit 005be37e-8971-4a5b-b5e7-dd18de3c1184: 48.56 +---- diff --git a/documentation/modules/ROOT/pages/04-workshop.adoc b/documentation/modules/ROOT/pages/04-workshop.adoc deleted file mode 100644 index 86ce843..0000000 --- a/documentation/modules/ROOT/pages/04-workshop.adoc +++ /dev/null @@ -1,13 +0,0 @@ -= Solution Pattern: Name Template -:sectnums: -:sectlinks: -:doctype: book - -= Workshop - -what is this workshop and what will be learned - -== Installing the workshop environment -=== Before getting started -=== Installing the environment -== Delivering the workshop diff --git a/documentation/modules/ROOT/pages/developer-resources.adoc b/documentation/modules/ROOT/pages/developer-resources.adoc index 3ca4c1f..9851495 100644 --- a/documentation/modules/ROOT/pages/developer-resources.adoc +++ b/documentation/modules/ROOT/pages/developer-resources.adoc @@ -1,4 +1,4 @@ -= Solution Patterns: Template Name += Building Apps around the Event Mesh :sectnums: :sectlinks: :doctype: book @@ -6,6 +6,10 @@ == Developer Resources -* Add link to the git repo of the code -* Add links to whitepapers, ebooks, learning paths, product pages - +* https://github.com/cardil/cabs-usvc[cardil / cabs-usvc] _(The example code used in this solution)_ +* https://youtu.be/Rc5IO6S6ZOk[youtu.be / Rc5IO6S6ZOk] _(The talk that served a base for this solution)_ +* https://www.redhat.com/en/technologies/cloud-computing/openshift/serverless[Red Hat OpenShift Serverless] +* https://knative.dev/docs/eventing/event-mesh/[Knative Event Mesh] +* https://bit.ly/knative-tutorial[Knative Tutorial] +* https://developers.redhat.com/[Red Hat Developer] +* https://docs.openshift.com/serverless/[Red Hat OpenShift Serverless Documentation] From 47a6152a9b4cf91f4a9565de15859d897c285535 Mon Sep 17 00:00:00 2001 From: Chris Suszynski Date: Wed, 26 Mar 2025 19:19:30 +0100 Subject: [PATCH 14/22] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Roland Huß --- .../modules/ROOT/pages/02-architecture.adoc | 14 +++++++------- documentation/modules/ROOT/pages/03-demo.adoc | 2 +- .../modules/ROOT/pages/developer-resources.adoc | 2 +- documentation/modules/ROOT/pages/index.adoc | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/documentation/modules/ROOT/pages/02-architecture.adoc b/documentation/modules/ROOT/pages/02-architecture.adoc index b35590b..373c34b 100644 --- a/documentation/modules/ROOT/pages/02-architecture.adoc +++ b/documentation/modules/ROOT/pages/02-architecture.adoc @@ -18,7 +18,7 @@ Here's the list of technologies used in this solution and its examples: * Red Hat supported products ** https://www.redhat.com/en/technologies/cloud-computing/openshift[Red Hat OpenShift] — Orchestrate containerized applications. -Based on https://kubernetes.io/[Kuberentes]. +Based on https://kubernetes.io/[Kubernetes]. ** https://www.redhat.com/en/technologies/cloud-computing/openshift/serverless[Red Hat OpenShift Serverless] — Provides the _Event Mesh_ and _Serverless_ capabilities. Based on https://knative.dev[Knative] project. @@ -72,7 +72,7 @@ By embracing an eventual consistency model, the _Event Mesh_ aligns closely with Unlike traditional transactional systems that strive for immediate, irreversible consistency, the _Event Mesh_ allows for a more flexible and adaptive approach to data consistency. This results in better alignment with business requirements, as it supports scenarios where multiple services collaborate and synchronize their operations, making the whole state eventually consistent, without the constraint of strict, synchronous consistency. -* **Avoidance of systemic issues**: +* **Improved Resilience**: The _Event Mesh_'s error-handling mechanism, through retries and event persistence, aids in minimizing the impact of failures on the end user. This is crucial as it prevents bugs and outages from becoming visible to the user, thereby preserving the system's perceived responsiveness. @@ -86,16 +86,16 @@ The event-driven flow enables eventual consistent collaboration and state synchr A usual flow may look like: -1. An end-user application sends a request, which forms a _Command_ type event, which is transferred to the _Event Mesh_. +1. An end-user application sends an _HTTP_ request to the _Event Mesh_. Such message can be understood as a _Command_ type event. 2. The _Event Mesh_ (Broker) persists the event in a queue (e.g. Kafka). -After successful persistence _Event Mesh_ returns the success information. +After _Event Mesh_ persists safely the data, it returns a successful _HTTP_ response with the `202 Accepted` return code. At this point, the operation could already be considered successful, from the end-user point of view. It will eventually settle correctly in all downstream systems. 3. The _Event Mesh_ routes the event to the appropriate endpoint based on the event's metadata and configured triggering rules. 4. The endpoints receive the events and process them, updating their internal states and potentially emitting new events for downstream consumers. The potential events are transmitted to the _Event Mesh_. 5. The dispatch loop continues until the event queue is empty and all the events are processed successfully. -The failures are being automatically retried by the _Event Mesh_ using exponential backoff algorithm by default. +The failures are automatically retried by the _Event Mesh_, with an increasing pauses between retries to avoid overloading the system. image::https://img.plantuml.biz/plantuml/svg/TPFDReGW483lFCNKkpw0XytMRDCqxJQRDdq05iULB885j35Dtxs8k2xxSuEPRpvm1jV6KcsxHf07MsE3m51t0gbCLMS5bqZCaSkMQjh0kBL3Yz0gCVWSOK9r9IHFFKeBMpHr0hy4WAccLNAC9Q-IMjuZ55eTKIT0JLWwxBl33Xr2goFr6RyYVuHKIfIe8TbofXKOr3rdQAxa6-tKsi3d17X7Y8MGuqjgwPuQNF1DSKvkYbZw8dl56PU7I3j5yPPsAGZYm5wAtvNb5MUk7qf6xlF4V81hmbdf6nue6y0Cnc9prOQGVMnRhvksqHK3CNzuCUf3B2tLZqnNOIevxBgzuAO676TgPYhJ_53RRELg8OUlrgdH-ybKjm1-XexPkTPoOsTFF1R815OZVUVK84tTlUB273xSmyGRN3oW-zoDPb_0brVDLijJoU4PhG4kAmLqxwgWd58aFjzNdTx1gMCX0XgPqgKXQvIb-_d-0G00[width=100%] @@ -159,9 +159,9 @@ A dead letter sink can also be configured to send events in case they exceed the === _Work Ledger_ analogy A good way of thinking about the _Event Mesh_ and its persistent queue backend is the _Work Ledger_ analogy. -Like in olden days, the clerk was keeping his to-do work in the _Work Ledger_ (e.g. a tray for paper forms). +Like in the olden days, the clerk kept his to-do work in the _Work Ledger_ (e.g. a tray for paper forms). Then he was picking the next form, and processing it, making changes within the physical file cabinets. -In case of rare and unexpected issues (e.g. Invoicing dept being unavailable), the clerk would just put the data back onto the _Work Ledger_ to be processed later. +In case of rare and unexpected issues (e.g. invoicing dept being unavailable), the clerk would just put the data back onto the _Work Ledger_ to be processed later. The _Event Mesh_ is processing the data in very similar fashion. The data is held in the _Event Mesh_ only until the system successfully consumes it. diff --git a/documentation/modules/ROOT/pages/03-demo.adoc b/documentation/modules/ROOT/pages/03-demo.adoc index a04a233..e706269 100644 --- a/documentation/modules/ROOT/pages/03-demo.adoc +++ b/documentation/modules/ROOT/pages/03-demo.adoc @@ -253,7 +253,7 @@ The last part of the refactoring will be the changes needed in our legacy Java a We need to remove the _Drivers_ logic and send events to the _Event Mesh_ instead. We also need to accept new events coming from the _Event Mesh_, as the calculated fee will be transmitted as such. -Here's the refactored `+completeTransit+` method: +Here's the refactored code: [source,java] ---- public void completeTransit(UUID requestUUID, AddressDTO destinationAddress) { diff --git a/documentation/modules/ROOT/pages/developer-resources.adoc b/documentation/modules/ROOT/pages/developer-resources.adoc index 9851495..6df84c1 100644 --- a/documentation/modules/ROOT/pages/developer-resources.adoc +++ b/documentation/modules/ROOT/pages/developer-resources.adoc @@ -6,7 +6,7 @@ == Developer Resources -* https://github.com/cardil/cabs-usvc[cardil / cabs-usvc] _(The example code used in this solution)_ +* https://github.com/cardil/cabs-usvc[Demo Source] _(The example code used in this solution)_ * https://youtu.be/Rc5IO6S6ZOk[youtu.be / Rc5IO6S6ZOk] _(The talk that served a base for this solution)_ * https://www.redhat.com/en/technologies/cloud-computing/openshift/serverless[Red Hat OpenShift Serverless] * https://knative.dev/docs/eventing/event-mesh/[Knative Event Mesh] diff --git a/documentation/modules/ROOT/pages/index.adoc b/documentation/modules/ROOT/pages/index.adoc index 65e5930..e367748 100644 --- a/documentation/modules/ROOT/pages/index.adoc +++ b/documentation/modules/ROOT/pages/index.adoc @@ -11,7 +11,7 @@ that are often at least as complex as the business they operate in. This solution pattern is written to make it obvious and to show simple, yet elegant, correct, and comprehensive way of building software, either in greenfield or even in legacy projects. This solution leverages the -https://www.redhat.com/en/technologies/cloud-computing/openshift/serverless[Red Hat Serverless] +https://www.redhat.com/en/technologies/cloud-computing/openshift/serverless[Red Hat OpenShift Serverless] Eventing component, which implements the https://www.redhat.com/en/topics/integration/what-is-an-event-mesh[Event Mesh] pattern. *Contributors:* https://github.com/cardil[Chris Suszynski] From 9521ee3945e1b1a50c881506d61e64da5a78a034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Wed, 26 Mar 2025 19:19:45 +0100 Subject: [PATCH 15/22] Review changes --- .../modules/ROOT/pages/01-pattern.adoc | 4 ++-- .../modules/ROOT/pages/02-architecture.adoc | 20 ++++++++++--------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/documentation/modules/ROOT/pages/01-pattern.adoc b/documentation/modules/ROOT/pages/01-pattern.adoc index bfb24a0..e8428e6 100644 --- a/documentation/modules/ROOT/pages/01-pattern.adoc +++ b/documentation/modules/ROOT/pages/01-pattern.adoc @@ -8,12 +8,12 @@ The team saw a https://www.youtube.com/watch?v=Rc5IO6S6ZOk[talk on _Event Mesh_] The talk presented the advantages of moving beyond transactional architectures in favor of eventual consistency. By leveraging event meshes with technologies like Knative, developers can achieve decoupled, reliable microservices without extensive re-engineering. This solution addresses inefficiencies and aligns distributed systems with real-world business processes. -The team had figured out they could leverage the _CQRS_ pattern together with _Knative's Event Mesh_ +The team had figured out they could leverage the https://martinfowler.com/bliki/CQRS.html[_CQRS_] pattern together with _Knative's Event Mesh_ to modernize their application in a non-extrusive way. == The Solution -The core of this solution is an event mesh—a dynamic, flexible layer that routes, retries, and processes asynchronous events across distributed components. +The core of this solution is an event mesh -- a dynamic, flexible infrastructure layer that routes, retries, and processes asynchronous events across distributed components. Using _Knative Eventing_ and _CloudEvents_, this pattern enables: - *Reliable delivery* of events with retry mechanisms. diff --git a/documentation/modules/ROOT/pages/02-architecture.adoc b/documentation/modules/ROOT/pages/02-architecture.adoc index 373c34b..eb45abe 100644 --- a/documentation/modules/ROOT/pages/02-architecture.adoc +++ b/documentation/modules/ROOT/pages/02-architecture.adoc @@ -22,13 +22,15 @@ Based on https://kubernetes.io/[Kubernetes]. ** https://www.redhat.com/en/technologies/cloud-computing/openshift/serverless[Red Hat OpenShift Serverless] — Provides the _Event Mesh_ and _Serverless_ capabilities. Based on https://knative.dev[Knative] project. -** https://swc.saas.ibm.com/en-us/redhat-marketplace/products/red-hat-amq[Red Hat AMQ Streams] +** https://developers.redhat.com/products/streams-for-apache-kafka[Streams for Apache Kafka] — (Optional) Provides a persistence for _Event Mesh_, likely needed in production. Based on https://strimzi.io/[Strimzi] project. * Other open source technologies: ** https://cloudevents.io/[CloudEvents] — Provides a standard for event metadata -** Rust and https://access.redhat.com/products/quarkus[Quarkus] — Implementation examples. ** https://opentelemetry.io/[OpenTelemetry] — (Optional) Facilitates tracing for observability. +** Rust and Java — Implementation examples. + +_Kubernetes_, _Knative_, _Strimzi_, _CloudEvents_, and _OpenTelemetry_ are https://landscape.cncf.io/[CNCF projects]. [#in_depth] == An in-depth look at the solution's architecture @@ -44,8 +46,8 @@ Traditional systems often enforce strict transactional consistency, which can im For instance, upon the completion of a ride-sharing service at the end-user's destination, the system should reliably capture this real-world event. The capture should be performed regardless of any potential operational disruptions affecting dependent services (e.g., invoicing). -In such scenarios, transactional applications typically return an error, which prevents any data from being changed, and causes the loss of real-world intent of end-users. -This results in an adverse user experience and a deviation from the genuine business process, potentially leading to customer dissatisfaction. +In such scenarios, transactional applications, which typically encompass a number of steps in a user workflow, make all the steps undone when an error is returned. +This prevents any data from being changed, and causes the loss of real-world intent of end-users, and results in an adverse user experience and a deviation from the genuine business process, potentially leading to customer dissatisfaction. === Solution Breakdown @@ -58,13 +60,13 @@ The primary responsibility of the _Event Mesh_ is twofold. Firstly, it persists the incoming events, thereby maintaining a record of changes in the system's state. Secondly, it routes these events to their respective endpoints, ensuring that the appropriate microservices are notified and can subsequently update their internal states based on the event data. -The mesh's inherent resilience is further bolstered by its exponential backoff strategy, which it employs when encountering operational failures. +The mesh's inherent resilience is further bolstered by its built-in retry strategies (linear or exponential backoff), which it employs when encountering operational failures. This mechanism ensures that the system retries the operation until it succeeds, thus mitigating the risk of data loss or system disruption due to transient issues. By integrating the _Event Mesh_ into the system architecture, several architectural benefits are achieved: * **Decomposition of the application into independently functioning services**: -This approach facilitates a division of labor, with each service handling specific responsibilities. +This approach facilitates a division of labor, with each service handling specific responsibilities -- the https://en.wikipedia.org/wiki/Domain-driven_design[Domain-driven design] approach fits here quite well. This not only enhances maintainability but also fosters scalability, as services can be independently scaled based on their demands. * **Improved business alignment**: @@ -87,11 +89,11 @@ The event-driven flow enables eventual consistent collaboration and state synchr A usual flow may look like: 1. An end-user application sends an _HTTP_ request to the _Event Mesh_. Such message can be understood as a _Command_ type event. -2. The _Event Mesh_ (Broker) persists the event in a queue (e.g. Kafka). +2. The _Event Mesh_ (Broker) persists the event in a queue (like an Apache Kafka topic, but the implementation is hidden from the user). After _Event Mesh_ persists safely the data, it returns a successful _HTTP_ response with the `202 Accepted` return code. At this point, the operation could already be considered successful, from the end-user point of view. It will eventually settle correctly in all downstream systems. -3. The _Event Mesh_ routes the event to the appropriate endpoint based on the event's metadata and configured triggering rules. +3. The _Event Mesh_ routes the event to the appropriate endpoint based on the CloudEvent's metadata and configured triggering rules. 4. The endpoints receive the events and process them, updating their internal states and potentially emitting new events for downstream consumers. The potential events are transmitted to the _Event Mesh_. 5. The dispatch loop continues until the event queue is empty and all the events are processed successfully. @@ -232,7 +234,7 @@ For instance: === Improving Resilience in Applications Traditional systems often rely on synchronous calls and transactions, which can cascade failures across components. -Replacing these with asynchronous event-driven communication reduces dependencies and makes the system _Eventually Consistent_. +Replacing these with asynchronous event-driven communication reduces dependencies and makes the system https://en.wikipedia.org/wiki/Eventual_consistency[_Eventually Consistent_]. For example, invoicing and notification services in a ride-sharing platform can process events independently, ensuring that downtime in one service does not block the entire workflow. From 5280cd089cc41dac15313f9a1fe105d4fb4780c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Thu, 27 Mar 2025 20:52:56 +0100 Subject: [PATCH 16/22] Review changes for demo (without reorder) --- .../modules/ROOT/pages/02-architecture.adoc | 5 +- documentation/modules/ROOT/pages/03-demo.adoc | 57 ++++++++++--------- .../ROOT/pages/developer-resources.adoc | 4 +- 3 files changed, 36 insertions(+), 30 deletions(-) diff --git a/documentation/modules/ROOT/pages/02-architecture.adoc b/documentation/modules/ROOT/pages/02-architecture.adoc index eb45abe..7c53e73 100644 --- a/documentation/modules/ROOT/pages/02-architecture.adoc +++ b/documentation/modules/ROOT/pages/02-architecture.adoc @@ -88,7 +88,8 @@ The event-driven flow enables eventual consistent collaboration and state synchr A usual flow may look like: -1. An end-user application sends an _HTTP_ request to the _Event Mesh_. Such message can be understood as a _Command_ type event. +1. An end-user application sends an _HTTP_ request to the _Event Mesh_. +Such message can be understood as a _Command_ type event. 2. The _Event Mesh_ (Broker) persists the event in a queue (like an Apache Kafka topic, but the implementation is hidden from the user). After _Event Mesh_ persists safely the data, it returns a successful _HTTP_ response with the `202 Accepted` return code. At this point, the operation could already be considered successful, from the end-user point of view. @@ -155,7 +156,7 @@ The _Event Mesh_ pushes the events as _CloudEvents_ encoded as _REST_ messages. The exponential backoff algorithm used by _Event Mesh_ is configurable. It uses the following formula to calculate the backoff period: `+backoffDelay * 2^+`, where the backoff delay is a base number of seconds, and number of retries is automatically tracked by the _Event Mesh_. -A dead letter sink can also be configured to send events in case they exceed the maximum retry number, which is also configurable. +A dead letter sink can also be configured to send events in case they exceed the maximum retry number, which is also configurable. ==== === _Work Ledger_ analogy diff --git a/documentation/modules/ROOT/pages/03-demo.adoc b/documentation/modules/ROOT/pages/03-demo.adoc index e706269..af597c5 100644 --- a/documentation/modules/ROOT/pages/03-demo.adoc +++ b/documentation/modules/ROOT/pages/03-demo.adoc @@ -8,7 +8,7 @@ == Demonstration Let's take a look at the following example. -We'll be looking at a Cabs ride-sharing application, that mimics real-world solutions of similar kind. +We'll be looking at a Cabs ride-sharing application, that resembles real-world solutions of similar kind. The application is written in a popular Java framework. === Initial application @@ -31,18 +31,19 @@ public void completeTransit(Long driverId, UUID requestUUID, Address destination } Address from = addressRepository.getByHash(transitDetails.from.getHash()); Address to = addressRepository.getByHash(destinationAddress.getHash()); + Money finalPrice = completeTransitService.completeTransit( driverId, requestUUID, from, to); // <2> - Money driverFee = driverFeeService.calculateDriverFee( - finalPrice, driverId); + Money driverFee = driverFeeService.calculateDriverFee(finalPrice, driverId); driverService.markNotOccupied(driverId); // <2> - transitDetailsFacade.transitCompleted(requestUUID, - Instant.now(clock), finalPrice, driverFee); // <2> - awardsService.registerMiles(transitDetails.client.getId(), - transitDetails.transitId); // <2> + + transitDetailsFacade.transitCompleted(requestUUID, Instant.now(clock), + finalPrice, driverFee); // <2> + awardsService.registerMiles(transitDetails.client.getId(), transitDetails.transitId); // <2> invoiceGenerator.generate(finalPrice.toInt(), transitDetails.client.getName() + " " + transitDetails.client.getLastName()); // <2> + eventsEventSender.publish(new TransitCompleted( transitDetails.client.getId(), transitDetails.transitId, transitDetails.from.getHash(), destinationAddress.getHash(), @@ -112,19 +113,22 @@ The entrypoint is the _Cloud Event_ of type `cabs.drivers.calculate-fee` we are ---- impl Service { pub async fn calculate_fee(&mut self, ce: Event) -> Result<()> { - let fee_event = Self::parse_fee_event(ce)?; // <1> - let subject = fee_event.id.clone(); + let calc_fee_intent = Self::unwrap_calculatefee(ce)?; // <1> + let subject = calc_fee_intent.id.clone(); + + log::debug!("calculate fee for: {:?}", calc_fee_intent); + let drv = self.repo.get(&calc_fee_intent.entity.driver_id).await?; - let drv = self.repo.get(&fee_event.entity.driver_id).await?; + let fee = drv.calculate_fee(&calc_fee_intent.entity.transit_price); // <2> - let fee = drv.calculate_fee(&fee_event.entity.transit_price); // <2> + log::debug!("fee value: {:?}", fee); - let fee_event = DriverFeeEvent { - driver_id: fee_event.entity.driver_id, + let driverfee_event = DriverFeeEvent { + driver_id: calc_fee_intent.entity.driver_id, fee, }; // <3> - let mut builder = fee_event.to_builder(); // <3> + let mut builder = driverfee_event.to_builder(); // <3> if let Some(id) = subject { builder = builder.subject(id); } // <3> @@ -140,10 +144,10 @@ impl Service { In the above code, we are doing the following: -<1> We are parsing the internal, business logic, fee event from the _Cloud Events_ envelope. -<2> We are calculating the fee for this event, using some business logic. -<3> We are wrapping the calculated fee into the _Cloud Events_ envelope. -<4> We are sending the fee back to the _Event Mesh_ using _HTTP REST_ client. +<1> We are unwrapping _Cloud Event_ envelope into an internal, domain, fee value object. +<2> We are calculating the fee value using some domain logic. +<3> We are wrapping the calculated fee value into a new _Cloud Event_. +<4> We are sending the fee, as _Cloud Event_, back to the _Event Mesh_ using _HTTP REST_ client. Of course, in order for this method to be called, we need to route the event from the HTTP listener: @@ -238,13 +242,13 @@ spec: [IMPORTANT] ==== -The policy is `+exponential+`, and the `+retry+` is 10, which means that after approximately 6 min and 50 sec the event will be dropped. +In our example, the policy is `+exponential+`, and the `+retry+` is 10, which means that after approximately 6 min and 50 sec the event will be dropped (or routed to the `+deadLetterSink+` if configured). ==== [NOTE] ==== A `+deadLetterSink+` option could be configured for the _Broker_ to send the events that failed to be delivered in time to a back-up location. -Events captured in a back-up location can be re-transmitted into the _Event Mesh_ later. +Events captured in a back-up location can be re-transmitted into the _Event Mesh_ later by reconfiguring the _Mesh_ (after resolving the outage or deploying a bug fix). ==== ==== Legacy application changes @@ -276,12 +280,12 @@ public void driverFeeCalculated(DriverFee driverFee) { // <3> ==== <1> Notice, we are just invoking the `+calculateDriverFee+`, that doesn't return anything. It's asynchronous. -<2> We are using the `@EventListener` annotation to listen for the business events withing the applition. +<2> We are using the `@EventListener` annotation to listen for the domain events within the application. Don't confuse this with _Cloud Events_ that are sent and received outside the application. <3> The exact fee is calculated by the _Drivers_ module, and we'll be notified later, with the `+driverFeeCalculated+` method. ==== -To make it work, we need to add a new _Cloud Event_ sender and listener. +To communicate with the _Event Mesh_, we need to add a new _Cloud Event_ sender and listener. That's being done similarly, as in the case of _Rust_ application. Below, you can see how you may implement the _Cloud Event_ sender: @@ -391,13 +395,13 @@ public class CloudEventReceiver { } ---- -<1> We unwrap the _CloudEvent_ into our custom event type +<1> We unwrap the _CloudEvent_ into our domain event type (in the example that's the `+DriverFeeCalculated+` type) <2> And publish it withing the application, using the framework's _EventsPublisher_ implementation. -The event will be transmitted to the methods annotated with `@EventListener`. +The domain events will be transmitted to the methods annotated with `@EventListener`. [CAUTION] ==== -Don't confuse the the framework's _EventsPublisher_ with _Cloud Event_ sender and receiver. +Don't confuse the framework's _EventsPublisher_ with _Cloud Event_ sender and receiver. ==== ==== The wiring of our _Event Mesh_ @@ -765,7 +769,8 @@ The OpenShift Container Platform provides can provide a clear visualization of o image::solution-odc.png[width=100%] The console shows two sink bindings on the left, and they are feeding the events from the applications to the _Broker_ (depicted in the center). -on the right, you could see the two applications deployed as _Knative_ services, and two triggers (as lines) that configure the _Event Mesh_ to feed appropriate events to the applications. +The _Broker_ is the centralized infrastructure piece that ensures a proper decoupling of the services. +On the right, you could see the two applications deployed as _Knative_ services, and two triggers (as lines) that configure the _Event Mesh_ to feed appropriate events to the applications. === Walkthrough guide diff --git a/documentation/modules/ROOT/pages/developer-resources.adoc b/documentation/modules/ROOT/pages/developer-resources.adoc index 6df84c1..219e26e 100644 --- a/documentation/modules/ROOT/pages/developer-resources.adoc +++ b/documentation/modules/ROOT/pages/developer-resources.adoc @@ -6,8 +6,8 @@ == Developer Resources -* https://github.com/cardil/cabs-usvc[Demo Source] _(The example code used in this solution)_ -* https://youtu.be/Rc5IO6S6ZOk[youtu.be / Rc5IO6S6ZOk] _(The talk that served a base for this solution)_ +* https://github.com/cardil/cabs-usvc[Demo source code] — _The example code used in this solution, based on the https://github.com/legacyfighter/cabs-java[LegacyFighter Java app]_ +* https://youtu.be/Rc5IO6S6ZOk[Let's get meshy! Microservices are easy with Event Mesh] — _The talk that served a base for this solution_ * https://www.redhat.com/en/technologies/cloud-computing/openshift/serverless[Red Hat OpenShift Serverless] * https://knative.dev/docs/eventing/event-mesh/[Knative Event Mesh] * https://bit.ly/knative-tutorial[Knative Tutorial] From 896b3d7cedb317424eec610b00a747b7381f935d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Fri, 28 Mar 2025 14:30:56 +0100 Subject: [PATCH 17/22] Reorder the demo --- documentation/modules/ROOT/nav.adoc | 7 +- .../modules/ROOT/pages/01-pattern.adoc | 2 + documentation/modules/ROOT/pages/03-demo.adoc | 1288 +++++++++-------- 3 files changed, 665 insertions(+), 632 deletions(-) diff --git a/documentation/modules/ROOT/nav.adoc b/documentation/modules/ROOT/nav.adoc index ecf986e..577f841 100644 --- a/documentation/modules/ROOT/nav.adoc +++ b/documentation/modules/ROOT/nav.adoc @@ -1,6 +1,6 @@ * xref:index.adoc[{counter:module}. Home page] ** xref:index.adoc#use-cases[{module}.{counter:submodule1} Use cases] -** xref:index.adoc#_the_story_behind_this_solution_pattern[{module}.{counter:submodule1} The story behind this solution pattern] +** xref:index.adoc#_the_story[{module}.{counter:submodule1} The story behind this solution pattern] ** xref:index#_the_solution[{module}.{counter:submodule1} The solution] * xref:02-architecture.adoc[{counter:module}. Architecture] @@ -10,7 +10,10 @@ * xref:03-demo.adoc[{counter:module}. See the Solution in Action] ** xref:03-demo.adoc#_initial_application[{module}.{counter:submodule3}. Initial application] -** xref:03-demo.adoc#_run_the_demonstration[{module}.{counter:submodule3}. Run this demonstration] +** xref:03-demo.adoc#_refactoring_plan[{module}.{counter:submodule3}. Refactoring plan] +** xref:03-demo.adoc#_run_this_demonstration[{module}.{counter:submodule3}. Run this demonstration] +** xref:03-demo.adoc#_in_depth_refactoring[{module}.{counter:submodule3}. In-depth look at the refactoring] +** xref:03-demo.adoc#_conclusion[{module}.{counter:submodule3}. Conclusion] * xref:developer-resources.adoc[{counter:module}. Developer Resources] diff --git a/documentation/modules/ROOT/pages/01-pattern.adoc b/documentation/modules/ROOT/pages/01-pattern.adoc index e8428e6..be42ca4 100644 --- a/documentation/modules/ROOT/pages/01-pattern.adoc +++ b/documentation/modules/ROOT/pages/01-pattern.adoc @@ -1,3 +1,4 @@ +[#_the_story] == The story behind this solution pattern Cabs is a fictional transportation company. @@ -11,6 +12,7 @@ This solution addresses inefficiencies and aligns distributed systems with real- The team had figured out they could leverage the https://martinfowler.com/bliki/CQRS.html[_CQRS_] pattern together with _Knative's Event Mesh_ to modernize their application in a non-extrusive way. +[#_the_solution] == The Solution The core of this solution is an event mesh -- a dynamic, flexible infrastructure layer that routes, retries, and processes asynchronous events across distributed components. diff --git a/documentation/modules/ROOT/pages/03-demo.adoc b/documentation/modules/ROOT/pages/03-demo.adoc index af597c5..610b983 100644 --- a/documentation/modules/ROOT/pages/03-demo.adoc +++ b/documentation/modules/ROOT/pages/03-demo.adoc @@ -5,13 +5,12 @@ = See the Solution in Action -== Demonstration - Let's take a look at the following example. We'll be looking at a Cabs ride-sharing application, that resembles real-world solutions of similar kind. The application is written in a popular Java framework. -=== Initial application +[#_initial_application] +== Initial application [IMPORTANT] ==== @@ -64,7 +63,7 @@ Similar methods are, unfortunately, quite common in business applications. At first glance, many developers don't see any problems with similar code. Let's break down the problems in detail. -==== Overuse of transactional processing +=== Overuse of transactional processing The transactional processing has been the cornerstone of many business applications. However, in most cases, the transactional processing isn't the best fit for real-world processes. @@ -80,7 +79,7 @@ Outages from the dependant services must not invalidate the main intent. In fact, all the operations in this example could happen independently, and at different, yet reasonable times. ==== -==== Bundling of different logical domains +=== Bundling of different logical domains Our example is also very chatty, and hard to understand at first glance. In fact, this is quite common in similar applications. @@ -90,9 +89,10 @@ When new features are added, it keeps growing as developers cramp new instructio Of course, the developers could re-architect the code, to extract instructions to a separate blocks, but that is just a half-measure. Still, the application will do all the operations, starting from `+completeTransit+` method in the same time, and withing the same _"script"_. -=== Refactoring +[#_refactoring_plan] +== Refactoring plan -In this section, we'll refactor the Cabs application. +In this section, we'll plan the refactoring of the Cabs application. The refactoring will be limited to make the process easy to understand. The scope of the refactoring will be the extraction of drivers module, which is already a separate domain in the codebase. Within the scope of the `+completeTransit+` method, we'll need to shift the way we calculate the fee for the driver. @@ -100,791 +100,819 @@ The calculation will be done asynchronously, and when the driver module publishe The base for the refactoring is the _Event Mesh_ pattern, and the asynchronous communication will be done with _Cloud Events_. -==== Drivers module +After the refactoring, the `+completeTransit+` code will use two event types: -The functionality around drivers is already quite separated in the codebase, so it is a good staring point to extract into a separate module. -The drivers module will become a standalone web service, deployed on the _Kubernetes_ cluster. -The implementation of the drivers module will be done with _Rust_ for this example. +* `+CalculateFee+` -- a command event, to calculate fee for the driver for given ride +* `+DriverFeeCalculated+` -- an information event, fired when the calculator does the logic to calculate the requested fee. -Here's the _Rust_ code for calculate fee functionality. -The entrypoint is the _Cloud Event_ of type `cabs.drivers.calculate-fee` we are expecting the _Event Mesh_ will route. +The diagram below shows the sequence of operations that happen when we initiate refactored `+completeTransit+` code. -[source,rust] ----- -impl Service { - pub async fn calculate_fee(&mut self, ce: Event) -> Result<()> { - let calc_fee_intent = Self::unwrap_calculatefee(ce)?; // <1> - let subject = calc_fee_intent.id.clone(); +image::https://www.plantuml.com/plantuml/svg/VP1DJiCm58JtFiMZ-rmWYwgqeHkeX2WNUBK7Ok4ubdyYzVQuZKbe5TZ5olTcFiqcHFOnTKOyn1OTIC8d0xPLdwBH5iBb_rfgnpRIwWMVBC_qwDoAED3ul4MUBKSzW9u6vES1eRsYMzz_mT-YZS-W3tJeLUwyOdlW23zeYJkK8vyuZ52p5O9bRk687uTYLgrB4zNqcav6XvPsR6GocTsZQ8d2L1aV3slQzVP3-uuKpCNgB1JkEwQpzI_FcjxoL5XgcUvdMioVL4soi-iuIOQcE5N259RYPgKYMNJ-3lfdkMPRqp7s7lJkjQFBvWihR61Lwimt[width=100%] - log::debug!("calculate fee for: {:?}", calc_fee_intent); - let drv = self.repo.get(&calc_fee_intent.entity.driver_id).await?; +//// +Online editor: +https://www.plantuml.com/plantuml/uml/VP1DJiCm58JtFiMZ-rmWYwgqeHkeX2WNUBK7Ok4ubdyYzVQuZKbe5TZ5olTcFiqcHFOnTKOyn1OTIC8d0xPLdwBH5iBb_rfgnpRIwWMVBC_qwDoAED3ul4MUBKSzW9u6vES1eRsYMzz_mT-YZS-W3tJeLUwyOdlW23zeYJkK8vyuZ52p5O9bRk687uTYLgrB4zNqcav6XvPsR6GocTsZQ8d2L1aV3slQzVP3-uuKpCNgB1JkEwQpzI_FcjxoL5XgcUvdMioVL4soi-iuIOQcE5N259RYPgKYMNJ-3lfdkMPRqp7s7lJkjQFBvWihR61Lwimt - let fee = drv.calculate_fee(&calc_fee_intent.entity.transit_price); // <2> +@startuml +!theme materia-outline +participant "Legacy App" as Legacy +participant "Knative _Event Mesh_" as Broker +participant "Drivers Module" as FeeService +participant "Database" as DB - log::debug!("fee value: {:?}", fee); +activate Legacy +Legacy -> Broker : Publish CalculateFee Event +Broker --> Legacy: Confirm delivery +deactivate Legacy - let driverfee_event = DriverFeeEvent { - driver_id: calc_fee_intent.entity.driver_id, - fee, - }; // <3> +Broker -> FeeService: Route CalculateFee Event +activate FeeService +FeeService --> Broker: Publish DriverFeeCalculated Event +deactivate FeeService - let mut builder = driverfee_event.to_builder(); // <3> - if let Some(id) = subject { - builder = builder.subject(id); - } // <3> - let ce = builder.build().map_err(error::ErrorInternalServerError)?; // <3> +Broker -> Legacy: Route DriverFeeCalculated Event +activate Legacy +Legacy -> DB: Store Trip Data +deactivate Legacy +@enduml +//// - Sender::new(&self.config).send(ce).await?; // <4> +The diagram illustrates the flow of events between the legacy application, the _Knative Event Mesh_, the fee calculator service, and the datastore. - Ok(()) - } - // [..] -} ----- +[#_run_this_demonstration] +== Run this demonstration -In the above code, we are doing the following: +Next, you can learn how to walk through this demo. -<1> We are unwrapping _Cloud Event_ envelope into an internal, domain, fee value object. -<2> We are calculating the fee value using some domain logic. -<3> We are wrapping the calculated fee value into a new _Cloud Event_. -<4> We are sending the fee, as _Cloud Event_, back to the _Event Mesh_ using _HTTP REST_ client. +=== Before getting started -Of course, in order for this method to be called, we need to route the event from the HTTP listener: +We'll be using the Red Hat OpenShift Container Platform (OCP) 4.x cluster, so make sure you have it available in your environment. -[source,rust] ----- -pub fn routes() -> impl HttpServiceFactory + 'static { - web::resource("/").route(web::post().to(recv)) -} +You could use the https://developers.redhat.com/products/openshift/overview[Red Hat's Developer Sandbox] to spin up an instance for you. -async fn recv( - ce: Event, - state: web::Data, - binding: web::Data, -) -> Result { - log::info!("Received event:\n{}", ce); +Alternatively, you can use the https://developers.redhat.com/products/openshift-local/overview[OpenShift Local] installation. +Make sure to give it enough resources to fit the Serverless Operator and our demo application. - let mut svc = service::new(state, binding).await?; +=== Installing the demo - match ce.ty() { - "cabs.drivers.calculate-fee" => svc.calculate_fee(ce).await, - _ => Err(error::ErrorBadRequest("unsupported event type")), - }?; +==== Installing the Serverless Operator - Ok(HttpResponse::Ok().finish()) -} +To install the Serverless Operator, follow https://docs.openshift.com/serverless/1.35/install/preparing-serverless-install.html[the documentation steps]. + +The *TL;DR* version would be to apply the following manifest, and wait until the operator is ready: + +[source,yaml] +---- +apiVersion: v1 +kind: Namespace +metadata: + name: openshift-serverless +--- +apiVersion: operators.coreos.com/v1 +kind: OperatorGroup +metadata: + name: openshift-serverless + namespace: openshift-serverless +spec: {} +--- +apiVersion: operators.coreos.com/v1alpha1 +kind: Subscription +metadata: + name: serverless-operator + namespace: openshift-serverless +spec: + channel: stable + name: serverless-operator + source: redhat-operators + sourceNamespace: openshift-marketplace ---- -[NOTE] +Here are commands to apply the above manifests. + +[.console-input] +[source,shell] +---- +git clone https://github.com/cardil/cabs-usvc +oc apply -f cabs-usvc/deploy/serverless/operator.yaml +oc wait csv/serverless-operator.v1.35.0 \ + --for 'jsonpath={.status.conditions[?(@.phase == "Succeeded")]}' +---- + +[CAUTION] ==== -The example above uses a simple switch statement to determine the route for the given type of the event. -In a real application, you would probably use a more complex logic to determine which method should be called. +Replace the `+v1.35.0+` with the actual version of the Serverless Operator. ==== -Let's see also the _Cloud Event_ sender, that uses the _HTTP REST_ client to send events to the _Event Mesh_: +Here's the expected output -[source,rust] +[source,shell] ---- -impl Sender { - pub async fn send(&self, ce: Event) -> Result<()> { - log::debug!("sending {} event to {}:\n{:?}", ce.ty(), &self.sink, ce,); - - let response = self - .client - .post(&self.sink) // <1> - .event(ce) - .map_err(error::ErrorInternalServerError)? - .send() - .await - .map_err(error::ErrorInternalServerError)?; - - match response.status().is_success() { - true => Ok(()), - false => { - log::error!("failed to send event: {:#?}", response); - Err(error::ErrorInternalServerError(format!( - "failed to send event: {}", - response.status() - ))) - } - } - } -} +namespace/openshift-serverless created +operatorgroup.operators.coreos.com/openshift-serverless created +subscription.operators.coreos.com/serverless-operator created +clusterserviceversion.operators.coreos.com/serverless-operator.v1.35.0 condition met ---- -<1> The client uses _POST_ method, to send the _JSON_ representation of the event to the sink. -The _sink_ is the URL of the target, in this case the url of the _Event Mesh_. - -==== Event Mesh +==== Installing the Serving and Eventing components -In this section, we'll use the _Event Mesh_ setup to communication between the extracted Drivers module and the different parts of the application. +To install the Serving and Eventing components, follow https://docs.openshift.com/serverless/1.35/install/installing-knative-serving.html[the Serving documentation steps] and https://docs.openshift.com/serverless/1.35/install/installing-knative-eventing.html[the Eventing documentation steps]. -Here's the configuration of the _Event Mesh_'s central component, the _Broker_, which will be used in this example. -The _Broker_ here is the _Knative_ component, and will be deployed in the _Kubernetes_ cluster. +Again for *TL;DR* version for small, development purposes, you could apply the following manifests, and wait until the components are ready for operation: [source,yaml] ---- -apiVersion: eventing.knative.dev/v1 -kind: Broker +apiVersion: v1 +kind: Namespace metadata: - name: default - namespace: demo + name: knative-serving +--- +apiVersion: operator.knative.dev/v1beta1 +kind: KnativeServing +metadata: + name: knative-serving + namespace: knative-serving spec: - delivery: - backoffDelay: PT0.2S # <1> - backoffPolicy: exponential # <2> - retry: 10 # <3> + high-availability: + replicas: 1 +--- +apiVersion: v1 +kind: Namespace +metadata: + name: knative-eventing +--- +apiVersion: operator.knative.dev/v1beta1 +kind: KnativeEventing +metadata: + name: knative-eventing + namespace: knative-eventing +spec: + high-availability: + replicas: 1 ---- -<1> The `+backoffDelay+` is the delay between retries, and us use `+200ms+` initially. -<2> The `+backoffPolicy+` is set to `+exponential+`, which means that the delay will be doubled each time. -<3> The `+retry+` is the number of times we retry before giving up. - -[IMPORTANT] -==== -In our example, the policy is `+exponential+`, and the `+retry+` is 10, which means that after approximately 6 min and 50 sec the event will be dropped (or routed to the `+deadLetterSink+` if configured). -==== - -[NOTE] -==== -A `+deadLetterSink+` option could be configured for the _Broker_ to send the events that failed to be delivered in time to a back-up location. -Events captured in a back-up location can be re-transmitted into the _Event Mesh_ later by reconfiguring the _Mesh_ (after resolving the outage or deploying a bug fix). -==== - -==== Legacy application changes - -The last part of the refactoring will be the changes needed in our legacy Java application. -We need to remove the _Drivers_ logic and send events to the _Event Mesh_ instead. -We also need to accept new events coming from the _Event Mesh_, as the calculated fee will be transmitted as such. +Here are commands to apply the above manifests. -Here's the refactored code: -[source,java] +[.console-input] +[source,shell] ---- -public void completeTransit(UUID requestUUID, AddressDTO destinationAddress) { - // ... - Money finalPrice = completeTransitService.completeTransit(driverId, requestUUID, from, to); - // ... - driverFeeService.calculateDriverFee(requestUUID, finalPrice, driverId); // <1> - // ... -} +oc apply \ + -f cabs-usvc/deploy/serverless/serving.yaml \ + -f cabs-usvc/deploy/serverless/eventing.yaml -@EventListener // <2> -public void driverFeeCalculated(DriverFee driverFee) { // <3> - Objects.requireNonNull(driverFee.ctx.getSubject()); - UUID id = UUID.fromString(driverFee.ctx.getSubject()); - transitDetailsFacade.driverFeeCalculated(id, driverFee.data.fee); -} +oc wait knativeserving/knative-serving \ + --namespace knative-serving \ + --for 'condition=Ready=True' +oc wait knativeeventing/knative-eventing \ + --namespace knative-eventing \ + --for 'condition=Ready=True' ---- -[NOTE] -==== -<1> Notice, we are just invoking the `+calculateDriverFee+`, that doesn't return anything. -It's asynchronous. -<2> We are using the `@EventListener` annotation to listen for the domain events within the application. -Don't confuse this with _Cloud Events_ that are sent and received outside the application. -<3> The exact fee is calculated by the _Drivers_ module, and we'll be notified later, with the `+driverFeeCalculated+` method. -==== - -To communicate with the _Event Mesh_, we need to add a new _Cloud Event_ sender and listener. -That's being done similarly, as in the case of _Rust_ application. - -Below, you can see how you may implement the _Cloud Event_ sender: +Here's the expected output -[source,java] +[source,shell] +---- +Warning: resource namespaces/knative-serving is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by oc apply. oc apply should only be used on resources created declaratively by either oc create --save-config or oc apply. The missing annotation will be patched automatically. +namespace/knative-serving configured +knativeserving.operator.knative.dev/knative-serving created +Warning: resource namespaces/knative-eventing is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by oc apply. oc apply should only be used on resources created declaratively by either oc create --save-config or oc apply. The missing annotation will be patched automatically. +namespace/knative-eventing configured +knativeeventing.operator.knative.dev/knative-eventing created +knativeserving.operator.knative.dev/knative-serving condition met +knativeeventing.operator.knative.dev/knative-eventing condition met ---- -@Service -public class DriverFeeService { - - private final CloudEventSender eventSender; - @Autowired - public DriverFeeService(EventSender eventSender) { - this.eventSender = eventSender; - } +==== Installing the demo applications - public void calculateDriverFee(UUID rideId, Money transitPrice, Long driverId) { - eventSender.send(new CalculateFee( - rideId, - driverId, - transitPrice.toInt() - )); - } -} +To install the Demo application, apply the following manifests. -@Service -public class CloudEventSender { +* https://github.com/cardil/cabs-usvc/blob/main/deploy/apps/legacy.yaml[The legacy application] +* https://github.com/cardil/cabs-usvc/blob/main/deploy/db/redis.yaml[The Drivers database] +* https://github.com/cardil/cabs-usvc/blob/main/deploy/apps/drivers.yaml[The Drivers module] - private static final Logger log = LoggerFactory.getLogger(EventSender.class); +Here are commands to apply the above manifests. - private final KnativeConfig knative; - private final List> converters; +[.console-input] +[source,shell] +---- +oc create ns demo +oc apply \ + -f cabs-usvc/deploy/db/redis.yaml \ + -f cabs-usvc/deploy/apps/drivers.yaml \ + -f cabs-usvc/deploy/apps/legacy.yaml - @Autowired - CloudEventSender(KnativeConfig knative, List> converters) { - this.knative = knative; - this.converters = converters; - } +oc wait ksvc/drivers \ + --namespace demo \ + --for condition=Ready=True +oc wait ksvc/legacy \ + --namespace demo \ + --for condition=Ready=True +---- - public void send(Object event) { - try { - unsafeSend(event); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } +Here's the expected output - private void unsafeSend(T event) throws IOException { - Into convert = (Into) converters.stream() - .filter(c -> c.accepts(event)) - .findFirst() - .orElseThrow(() -> new IllegalArgumentException( - "Cannot find converter for " + event.getClass())); - CloudEvent ce = convert.into(event); - URL url = knative.getSink(); - log.info("Publishing event to {} : {}", url, ce); - HttpURLConnection http = (HttpURLConnection) url.openConnection(); - http.setRequestMethod("POST"); - http.setDoOutput(true); - http.setDoInput(true); +[source,shell] +---- +namespace/demo created +pod/redis created +service/redis created +service.serving.knative.dev/drivers created +service.serving.knative.dev/legacy created +service.serving.knative.dev/drivers condition met +service.serving.knative.dev/legacy condition met +---- - HttpMessageWriter messageWriter = createMessageWriter(http); - messageWriter.writeBinary(ce); +==== Configuring the Event Mesh - int code = http.getResponseCode(); - if (code < 200 || code >= 300) { - throw new IOException("Unexpected response code " + code); - } - } -} ----- +To configure the Event Mesh, apply the following manifests. -Once again, notice this is just a simple _HTTP_ client doing the _POST_ request, with the body being the JSON representation of the _CloudEvent_. +* https://github.com/cardil/cabs-usvc/blob/main/deploy/mesh/broker.yaml[_Broker_] +* https://github.com/cardil/cabs-usvc/blob/main/deploy/mesh/sources.yaml[Sources] +* https://github.com/cardil/cabs-usvc/blob/main/deploy/mesh/triggers.yaml[Triggers] -The last part to see is the _HTTP_ listener on the legacy application side. -This listener will be responsible for receiving events from _Knative's Event Mesh_ and converting them into our custom event type: +Here are commands to apply the above manifests. -[source,java] +[.console-input] +[source,shell] ---- -@RestController -public class CloudEventReceiver { - private static final Logger log = LoggerFactory.getLogger(Receiver.class); +oc apply \ + -f cabs-usvc/deploy/mesh/broker.yaml \ + -f cabs-usvc/deploy/mesh/sources.yaml \ + -f cabs-usvc/deploy/mesh/triggers.yaml - private final EventsPublisher eventsPublisher; - private final List> froms; +oc wait broker/default \ + --namespace demo \ + --for condition=Ready=True +oc wait sinkbinding/drivers-binding \ + --namespace demo \ + --for condition=Ready=True +oc wait sinkbinding/legacy-binding \ + --namespace demo \ + --for condition=Ready=True +oc wait trigger/trg-drivers \ + --namespace demo \ + --for condition=Ready=True +oc wait trigger/trg-drivers \ + --namespace demo \ + --for condition=Ready=True +---- - @Autowired - Receiver(EventsPublisher eventsPublisher, List> froms) { - this.eventsPublisher = eventsPublisher; - this.froms = froms; - } +Here's the expected output - @PostMapping("/") - public void receive(@RequestBody CloudEvent event) { - log.info("Received event: {}", event); +[source,shell] +---- +broker.eventing.knative.dev/default created +sinkbinding.sources.knative.dev/drivers-binding created +sinkbinding.sources.knative.dev/legacy-binding created +trigger.eventing.knative.dev/trg-drivers created +trigger.eventing.knative.dev/trg-legacy created +broker.eventing.knative.dev/default condition met +sinkbinding.sources.knative.dev/drivers-binding condition met +sinkbinding.sources.knative.dev/legacy-binding condition met +trigger.eventing.knative.dev/trg-drivers condition met +trigger.eventing.knative.dev/trg-drivers condition met +---- - for (From from : froms) { - if (from.matches(event)) { - Event ev = from.fromCloudEvent(event); // <1> - eventsPublisher.publish(ev); // <2> - return; - } - } +The OpenShift Container Platform provides can provide a clear visualization of our deployed solution. - throw new IllegalStateException("No matching event type consumer found"); - } -} ----- +image::solution-odc.png[width=100%] -<1> We unwrap the _CloudEvent_ into our domain event type (in the example that's the `+DriverFeeCalculated+` type) -<2> And publish it withing the application, using the framework's _EventsPublisher_ implementation. -The domain events will be transmitted to the methods annotated with `@EventListener`. +The console shows two sink bindings on the left, and they are feeding the events from the applications to the _Broker_ (depicted in the center). +The _Broker_ is the centralized infrastructure piece that ensures a proper decoupling of the services. +On the right, you could see the two applications deployed as _Knative_ services, and two triggers (as lines) that configure the _Event Mesh_ to feed appropriate events to the applications. -[CAUTION] -==== -Don't confuse the framework's _EventsPublisher_ with _Cloud Event_ sender and receiver. -==== +=== Walkthrough guide -==== The wiring of our _Event Mesh_ +With the demo pieces deployed on the cluster, we could go ahead with testing the functionality. -To complete the solution, we need to configure the _Event Mesh_. -The configuration describes the rules for receiving and sending events from and to the _Event Mesh_ and the application modules. +For the sake of brevity, the legacy application, at startup, prepares some development data in the in-memory database its running on. +We will leverage that data to complete transit without the hassle of simulating the whole ride. -Here are the sources in our case: +Because we use serverless deployments, the services could be scaled to zero. +This fact makes it a bit harder to listen to the application logs. +We recommend using https://github.com/stern/stern[`+stern+` tool] to easily listen to both apps, even across scale to zero periods. -[source,yaml] +[.console-input] +[source,shell] ---- -apiVersion: sources.knative.dev/v1 -kind: SinkBinding -metadata: - name: drivers-binding - namespace: demo -spec: - sink: - ref: - apiVersion: eventing.knative.dev/v1 - kind: Broker - name: default - namespace: demo - subject: - apiVersion: serving.knative.dev/v1 - kind: Service - name: drivers - namespace: demo ---- -apiVersion: sources.knative.dev/v1 -kind: SinkBinding -metadata: - name: legacy-binding - namespace: demo -spec: - sink: - ref: - apiVersion: eventing.knative.dev/v1 - kind: Broker - name: default - namespace: demo - subject: - apiVersion: serving.knative.dev/v1 - kind: Service - name: legacy - namespace: demo +stern \ + --namespace demo \ + --container user-container \ + '(legacy|drivers).*' ---- -We are using the _SinkBinding_ resource to bind an event source (the _Service_) with an event sink (_Broker_). -We have two applications that will feed their events into the _Event Mesh_, so we need two _SinkBinding_ resources. - -Lastly, we have to configure the _Broker_ to send events from the _Event Mesh_ to the expected application modules. We use the _Trigger_ resource for this purpose. +Alternatively, you can use a regular `+oc+` command and a bit of scripting: -[source,yaml] +[.console-input] +[source,shell] ---- -apiVersion: eventing.knative.dev/v1 -kind: Trigger -metadata: - name: trg-drivers - namespace: demo -spec: - broker: default - filter: - attributes: - type: cabs.drivers.calculate-fee # <1> - subscriber: - ref: - apiVersion: serving.knative.dev/v1 - kind: Service - name: drivers - namespace: demo ---- -apiVersion: eventing.knative.dev/v1 -kind: Trigger -metadata: - name: trg-legacy - namespace: demo -spec: - broker: default - filter: - attributes: - type: cabs.drivers.driver-fee # <1> - subscriber: - ref: - apiVersion: serving.knative.dev/v1 - kind: Service - name: legacy - namespace: demo +oc logs \ + --selector app=legacy \ + --namespace demo \ + --follow & + +while [ $(oc get pod --namespace demo --selector app=drivers -o name | wc -l) -eq 0 ]; do \ + sleep 1; done && oc wait pod \ + --namespace demo \ + --selector app=drivers \ + --for condition=Ready=True && \ + oc logs \ + --selector app=drivers \ + --namespace demo \ + --follow ---- -<1> Note, we specify the type of the event, as a filter. +In the second terminal, call the legacy endpoint by sending a _POST_ message like the following: +[.console-input] +[source,shell] +---- +curl -Lk -v -X POST -H 'Content-Type: application/json' \ + $(oc get ksvc legacy --namespace demo -o jsonpath='{.status.url}')/transits/8/complete \ + --data-binary @- << EOF +{ + "country": "Polska", + "city": "Warszawa", + "street": "Żytnia", + "buildingNumber": 32, + "hash": -580606919 +} +EOF +---- -=== Conclusion +You should observe the cURL command succeeded, and return the ride data. +Moreover, the logs of both applications should be updated. -Let's step back and take a look at our refactored code. -The diagram below shows the sequence of operations that happen when we initiate our `+completeTransit()` method. +On the _Legacy_ application you could see the log line, with shows the application is sending the _Cloud Event_ to the _Event Mesh_: -image::https://www.plantuml.com/plantuml/svg/VP1DJiCm58JtFiMZ-rmWYwgqeHkeX2WNUBK7Ok4ubdyYzVQuZKbe5TZ5olTcFiqcHFOnTKOyn1OTIC8d0xPLdwBH5iBb_rfgnpRIwWMVBC_qwDoAED3ul4MUBKSzW9u6vES1eRsYMzz_mT-YZS-W3tJeLUwyOdlW23zeYJkK8vyuZ52p5O9bRk687uTYLgrB4zNqcav6XvPsR6GocTsZQ8d2L1aV3slQzVP3-uuKpCNgB1JkEwQpzI_FcjxoL5XgcUvdMioVL4soi-iuIOQcE5N259RYPgKYMNJ-3lfdkMPRqp7s7lJkjQFBvWihR61Lwimt[width=100%] +---- +INFO 1 --- [nio-8080-exec-1] i.l.cabs.common.cloudevents.Publisher : +Publishing event to http://broker-ingress.knative-eventing.svc.cluster.local/demo/default : +CloudEvent{id='83720fe5-02ee-4a3e-9b22-5c287fb68d10',source=usvc://cabs/legacy, +type='cabs.drivers.calculate-fee', datacontenttype='application/json', +subject='4e630a96-4d5c-488c-a53b-9554c0bcb97e',time=2025-02-04T17:32:20.638351262Z, +data=BytesCloudEventData{value=[123, 34, 100, 114, 105, 118, 101, 114, 45, 105, +100, 34, 58, 49, 57, 57, 51, 52, 51, 50, 53, 53, 50, 44, 34, 116, 114, 97, 110, +115, 105, 116, 45, 112, 114, 105, 99, 101, 34, 58, 53, 49, 48, 48, 125]}, +extensions={}} +---- -//// -Online editor: -https://www.plantuml.com/plantuml/uml/VP1DJiCm58JtFiMZ-rmWYwgqeHkeX2WNUBK7Ok4ubdyYzVQuZKbe5TZ5olTcFiqcHFOnTKOyn1OTIC8d0xPLdwBH5iBb_rfgnpRIwWMVBC_qwDoAED3ul4MUBKSzW9u6vES1eRsYMzz_mT-YZS-W3tJeLUwyOdlW23zeYJkK8vyuZ52p5O9bRk687uTYLgrB4zNqcav6XvPsR6GocTsZQ8d2L1aV3slQzVP3-uuKpCNgB1JkEwQpzI_FcjxoL5XgcUvdMioVL4soi-iuIOQcE5N259RYPgKYMNJ-3lfdkMPRqp7s7lJkjQFBvWihR61Lwimt +You can notice the `+cabs.drivers.calculate-fee+` event was later routed to the _Drivers_ service, which calculated the fee. +After the fee was calculated, the `+cabs.drivers.driver-fee+` event was published back into the _Event Mesh_. -@startuml -!theme materia-outline -participant "Legacy App" as Legacy -participant "Knative _Event Mesh_" as Broker -participant "Drivers Module" as FeeService -participant "Database" as DB +---- +[INFO drivers::app::events] Received event: + CloudEvent: + specversion: '1.0' + id: 'f94792bc-9c38-4db1-8da6-b6a28d1b4847' + type: 'cabs.drivers.calculate-fee' + source: 'usvc://cabs/legacy' + datacontenttype: 'application/json' + subject: '005be37e-8971-4a5b-b5e7-dd18de3c1184' + time: '2025-02-04T17:48:11.641317948+00:00' + knativearrivaltime: '2025-02-04T17:48:11.655926003Z' + Binary data: "{\"driver-id\":1993432552,\"transit-price\":5100}" + +[DEBUG drivers::drivers::service] fee event: Subject { + id: Some("005be37e-8971-4a5b-b5e7-dd18de3c1184"), + entity: CalculateFeeEvent { + driver_id: Identifier(1993432552), + transit_price: Money(5100) } } +[DEBUG drivers::drivers::service] fee: Money(4856) +[DEBUG drivers::support::cloudevents] sending cabs.drivers.driver-fee event to + http://broker-ingress.knative-eventing.svc.cluster.local/demo/default: + Event { attributes: V10(Attributes { id: "939babd7-6a85-4859-b45b-66087aba9418", + ty: "cabs.drivers.driver-fee", source: "usvc://cabs/drivers", + datacontenttype: Some("application/json"), dataschema: None, + subject: Some("005be37e-8971-4a5b-b5e7-dd18de3c1184"), + time: Some(2025-02-04T17:48:12.897943139Z) }), + data: Some(Json(Object {"driver-id": Number(1993432552), "fee": Number(4856)})), + extensions: {} } +---- -activate Legacy -Legacy -> Broker : Publish CalculateFee Event -Broker --> Legacy: Confirm delivery -deactivate Legacy +In the end, the `+cabs.drivers.driver-fee+` event was routed to the _Legacy_ application, by _Event Mesh_. +You could see the evidence of it in the logs. -Broker -> FeeService: Route CalculateFee Event -activate FeeService -FeeService --> Broker: Publish DriverFeeCalculated Event -deactivate FeeService +---- +INFO 1 --- [nio-8080-exec-2] i.l.c.ride.details.TransitDetailsFacade : + Driver fee calculated for transit 005be37e-8971-4a5b-b5e7-dd18de3c1184: 48.56 +---- -Broker -> Legacy: Route DriverFeeCalculated Event -activate Legacy -Legacy -> DB: Store Trip Data -deactivate Legacy -@enduml -//// +[#_in_depth_refactoring] +== In-depth look at the refactoring -The diagram illustrates the flow of events between the legacy application, the Knative _Event Mesh_, the fee calculator service, and the datastore. +In this section, we'll refactor the Cabs application. +The refactoring will be limited to make the process easy to understand. +The scope of the refactoring will be the extraction of drivers module, which is already a separate domain in the codebase. +Within the scope of the `+completeTransit+` method, we'll need to shift the way we calculate the fee for the driver. +The calculation will be done asynchronously, and when the driver module publishes the calculation result, it will be saved back into the database. -Next, you can learn how to walk through this demo. +The base for the refactoring is the _Event Mesh_ pattern, and the asynchronous communication will be done with _Cloud Events_. -== Run the demonstration +=== Drivers module -=== Before getting started +The functionality around drivers is already quite separated in the codebase, so it is a good staring point to extract into a separate module. +The drivers module will become a standalone web service, deployed on the _Kubernetes_ cluster. +The implementation of the drivers module will be done with _Rust_ for this example. -We'll be using the Red Hat OpenShift Container Platform (OCP) 4.x cluster, so make sure you have it available in your environment. +Here's the _Rust_ code for calculate fee functionality. +The entrypoint is the _Cloud Event_ of type `cabs.drivers.calculate-fee` we are expecting the _Event Mesh_ will route. -You could use the https://developers.redhat.com/products/openshift/overview[Red Hat's Developer Sandbox] to spin up an instance for you. +[source,rust] +---- +impl Service { + pub async fn calculate_fee(&mut self, ce: Event) -> Result<()> { + let calc_fee_intent = Self::unwrap_calculatefee(ce)?; // <1> + let subject = calc_fee_intent.id.clone(); -Alternatively, you can use the https://developers.redhat.com/products/openshift-local/overview[OpenShift Local] installation. -Make sure to give it enough resources to fit the Serverless Operator and our demo application. + log::debug!("calculate fee for: {:?}", calc_fee_intent); + let drv = self.repo.get(&calc_fee_intent.entity.driver_id).await?; -=== Installing the demo + let fee = drv.calculate_fee(&calc_fee_intent.entity.transit_price); // <2> -==== Installing the Serverless Operator + log::debug!("fee value: {:?}", fee); -To install the Serverless Operator, follow https://docs.openshift.com/serverless/1.35/install/preparing-serverless-install.html[the documentation steps]. + let driverfee_event = DriverFeeEvent { + driver_id: calc_fee_intent.entity.driver_id, + fee, + }; // <3> -The *TL;DR* version would be to apply the following manifest, and wait until the operator is ready: + let mut builder = driverfee_event.to_builder(); // <3> + if let Some(id) = subject { + builder = builder.subject(id); + } // <3> + let ce = builder.build().map_err(error::ErrorInternalServerError)?; // <3> -[source,yaml] ----- -apiVersion: v1 -kind: Namespace -metadata: - name: openshift-serverless ---- -apiVersion: operators.coreos.com/v1 -kind: OperatorGroup -metadata: - name: openshift-serverless - namespace: openshift-serverless -spec: {} ---- -apiVersion: operators.coreos.com/v1alpha1 -kind: Subscription -metadata: - name: serverless-operator - namespace: openshift-serverless -spec: - channel: stable - name: serverless-operator - source: redhat-operators - sourceNamespace: openshift-marketplace + Sender::new(&self.config).send(ce).await?; // <4> + + Ok(()) + } + // [..] +} ---- -Here are commands to apply the above manifests. +In the above code, we are doing the following: -[.console-input] -[source,shell] +<1> We are unwrapping _Cloud Event_ envelope into an internal, domain, fee value object. +<2> We are calculating the fee value using some domain logic. +<3> We are wrapping the calculated fee value into a new _Cloud Event_. +<4> We are sending the fee, as _Cloud Event_, back to the _Event Mesh_ using _HTTP REST_ client. + +Of course, in order for this method to be called, we need to route the event from the HTTP listener: + +[source,rust] ---- -git clone https://github.com/cardil/cabs-usvc -oc apply -f cabs-usvc/deploy/serverless/operator.yaml -oc wait csv/serverless-operator.v1.35.0 \ - --for 'jsonpath={.status.conditions[?(@.phase == "Succeeded")]}' +pub fn routes() -> impl HttpServiceFactory + 'static { + web::resource("/").route(web::post().to(recv)) +} + +async fn recv( + ce: Event, + state: web::Data, + binding: web::Data, +) -> Result { + log::info!("Received event:\n{}", ce); + + let mut svc = service::new(state, binding).await?; + + match ce.ty() { + "cabs.drivers.calculate-fee" => svc.calculate_fee(ce).await, + _ => Err(error::ErrorBadRequest("unsupported event type")), + }?; + + Ok(HttpResponse::Ok().finish()) +} ---- -[CAUTION] +[NOTE] ==== -Replace the `+v1.35.0+` with the actual version of the Serverless Operator. +The example above uses a simple switch statement to determine the route for the given type of the event. +In a real application, you would probably use a more complex logic to determine which method should be called. ==== -Here's the expected output +Let's see also the _Cloud Event_ sender, that uses the _HTTP REST_ client to send events to the _Event Mesh_: -[source,shell] ----- -namespace/openshift-serverless created -operatorgroup.operators.coreos.com/openshift-serverless created -subscription.operators.coreos.com/serverless-operator created -clusterserviceversion.operators.coreos.com/serverless-operator.v1.35.0 condition met +[source,rust] ---- +impl Sender { + pub async fn send(&self, ce: Event) -> Result<()> { + log::debug!("sending {} event to {}:\n{:?}", ce.ty(), &self.sink, ce,); -==== Installing the Serving and Eventing components + let response = self + .client + .post(&self.sink) // <1> + .event(ce) + .map_err(error::ErrorInternalServerError)? + .send() + .await + .map_err(error::ErrorInternalServerError)?; -To install the Serving and Eventing components, follow https://docs.openshift.com/serverless/1.35/install/installing-knative-serving.html[the Serving documentation steps] and https://docs.openshift.com/serverless/1.35/install/installing-knative-eventing.html[the Eventing documentation steps]. + match response.status().is_success() { + true => Ok(()), + false => { + log::error!("failed to send event: {:#?}", response); + Err(error::ErrorInternalServerError(format!( + "failed to send event: {}", + response.status() + ))) + } + } + } +} +---- -Again for *TL;DR* version for small, development purposes, you could apply the following manifests, and wait until the components are ready for operation: +<1> The client uses _POST_ method, to send the _JSON_ representation of the event to the sink. +The _sink_ is the URL of the target, in this case the url of the _Event Mesh_. + +=== Event Mesh + +In this section, we'll use the _Event Mesh_ setup to communication between the extracted Drivers module and the different parts of the application. + +Here's the configuration of the _Event Mesh_'s central component, the _Broker_, which will be used in this example. +The _Broker_ here is the _Knative_ component, and will be deployed in the _Kubernetes_ cluster. [source,yaml] ---- -apiVersion: v1 -kind: Namespace -metadata: - name: knative-serving ---- -apiVersion: operator.knative.dev/v1beta1 -kind: KnativeServing -metadata: - name: knative-serving - namespace: knative-serving -spec: - high-availability: - replicas: 1 ---- -apiVersion: v1 -kind: Namespace -metadata: - name: knative-eventing ---- -apiVersion: operator.knative.dev/v1beta1 -kind: KnativeEventing +apiVersion: eventing.knative.dev/v1 +kind: Broker metadata: - name: knative-eventing - namespace: knative-eventing + name: default + namespace: demo spec: - high-availability: - replicas: 1 + delivery: + backoffDelay: PT0.2S # <1> + backoffPolicy: exponential # <2> + retry: 10 # <3> ---- -Here are commands to apply the above manifests. +<1> The `+backoffDelay+` is the delay between retries, and us use `+200ms+` initially. +<2> The `+backoffPolicy+` is set to `+exponential+`, which means that the delay will be doubled each time. +<3> The `+retry+` is the number of times we retry before giving up. -[.console-input] -[source,shell] ----- -oc apply \ - -f cabs-usvc/deploy/serverless/serving.yaml \ - -f cabs-usvc/deploy/serverless/eventing.yaml +[IMPORTANT] +==== +In our example, the policy is `+exponential+`, and the `+retry+` is 10, which means that after approximately 6 min and 50 sec the event will be dropped (or routed to the `+deadLetterSink+` if configured). +==== -oc wait knativeserving/knative-serving \ - --namespace knative-serving \ - --for 'condition=Ready=True' -oc wait knativeeventing/knative-eventing \ - --namespace knative-eventing \ - --for 'condition=Ready=True' ----- +[NOTE] +==== +A `+deadLetterSink+` option could be configured for the _Broker_ to send the events that failed to be delivered in time to a back-up location. +Events captured in a back-up location can be re-transmitted into the _Event Mesh_ later by reconfiguring the _Mesh_ (after resolving the outage or deploying a bug fix). +==== -Here's the expected output +=== Legacy application changes -[source,shell] ----- -Warning: resource namespaces/knative-serving is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by oc apply. oc apply should only be used on resources created declaratively by either oc create --save-config or oc apply. The missing annotation will be patched automatically. -namespace/knative-serving configured -knativeserving.operator.knative.dev/knative-serving created -Warning: resource namespaces/knative-eventing is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by oc apply. oc apply should only be used on resources created declaratively by either oc create --save-config or oc apply. The missing annotation will be patched automatically. -namespace/knative-eventing configured -knativeeventing.operator.knative.dev/knative-eventing created -knativeserving.operator.knative.dev/knative-serving condition met -knativeeventing.operator.knative.dev/knative-eventing condition met +The last part of the refactoring will be the changes needed in our legacy Java application. +We need to remove the _Drivers_ logic and send events to the _Event Mesh_ instead. +We also need to accept new events coming from the _Event Mesh_, as the calculated fee will be transmitted as such. + +Here's the refactored code: + +[source,java] ---- +public void completeTransit(UUID requestUUID, AddressDTO destinationAddress) { + // ... + Money finalPrice = completeTransitService.completeTransit(driverId, requestUUID, from, to); + // ... + driverFeeService.calculateDriverFee(requestUUID, finalPrice, driverId); // <1> + // ... +} -==== Installing the demo applications +@EventListener // <2> +public void driverFeeCalculated(DriverFee driverFee) { // <3> + Objects.requireNonNull(driverFee.ctx.getSubject()); + UUID id = UUID.fromString(driverFee.ctx.getSubject()); + transitDetailsFacade.driverFeeCalculated(id, driverFee.data.fee); +} +---- -To install the Demo application, apply the following manifests. +[NOTE] +==== +<1> Notice, we are just invoking the `+calculateDriverFee+`, that doesn't return anything. +It's asynchronous. +<2> We are using the `@EventListener` annotation to listen for the domain events within the application. +Don't confuse this with _Cloud Events_ that are sent and received outside the application. +<3> The exact fee is calculated by the _Drivers_ module, and we'll be notified later, with the `+driverFeeCalculated+` method. +==== -* https://github.com/cardil/cabs-usvc/blob/main/deploy/apps/legacy.yaml[The legacy application] -* https://github.com/cardil/cabs-usvc/blob/main/deploy/db/redis.yaml[The Drivers database] -* https://github.com/cardil/cabs-usvc/blob/main/deploy/apps/drivers.yaml[The Drivers module] +To communicate with the _Event Mesh_, we need to add a new _Cloud Event_ sender and listener. +That's being done similarly, as in the case of _Rust_ application. -Here are commands to apply the above manifests. +Below, you can see how you may implement the _Cloud Event_ sender: -[.console-input] -[source,shell] +[source,java] ---- -oc create ns demo -oc apply \ - -f cabs-usvc/deploy/db/redis.yaml \ - -f cabs-usvc/deploy/apps/drivers.yaml \ - -f cabs-usvc/deploy/apps/legacy.yaml +@Service +public class DriverFeeService { -oc wait ksvc/drivers \ - --namespace demo \ - --for condition=Ready=True -oc wait ksvc/legacy \ - --namespace demo \ - --for condition=Ready=True ----- + private final CloudEventSender eventSender; -Here's the expected output + @Autowired + public DriverFeeService(EventSender eventSender) { + this.eventSender = eventSender; + } -[source,shell] ----- -namespace/demo created -pod/redis created -service/redis created -service.serving.knative.dev/drivers created -service.serving.knative.dev/legacy created -service.serving.knative.dev/drivers condition met -service.serving.knative.dev/legacy condition met ----- + public void calculateDriverFee(UUID rideId, Money transitPrice, Long driverId) { + eventSender.send(new CalculateFee( + rideId, + driverId, + transitPrice.toInt() + )); + } +} -==== Configuring the Event Mesh +@Service +public class CloudEventSender { -To configure the Event Mesh, apply the following manifests. + private static final Logger log = LoggerFactory.getLogger(EventSender.class); -* https://github.com/cardil/cabs-usvc/blob/main/deploy/mesh/broker.yaml[_Broker_] -* https://github.com/cardil/cabs-usvc/blob/main/deploy/mesh/sources.yaml[Sources] -* https://github.com/cardil/cabs-usvc/blob/main/deploy/mesh/triggers.yaml[Triggers] + private final KnativeConfig knative; + private final List> converters; -Here are commands to apply the above manifests. + @Autowired + CloudEventSender(KnativeConfig knative, List> converters) { + this.knative = knative; + this.converters = converters; + } -[.console-input] -[source,shell] ----- -oc apply \ - -f cabs-usvc/deploy/mesh/broker.yaml \ - -f cabs-usvc/deploy/mesh/sources.yaml \ - -f cabs-usvc/deploy/mesh/triggers.yaml + public void send(Object event) { + try { + unsafeSend(event); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } -oc wait broker/default \ - --namespace demo \ - --for condition=Ready=True -oc wait sinkbinding/drivers-binding \ - --namespace demo \ - --for condition=Ready=True -oc wait sinkbinding/legacy-binding \ - --namespace demo \ - --for condition=Ready=True -oc wait trigger/trg-drivers \ - --namespace demo \ - --for condition=Ready=True -oc wait trigger/trg-drivers \ - --namespace demo \ - --for condition=Ready=True ----- + private void unsafeSend(T event) throws IOException { + Into convert = (Into) converters.stream() + .filter(c -> c.accepts(event)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException( + "Cannot find converter for " + event.getClass())); + CloudEvent ce = convert.into(event); + URL url = knative.getSink(); + log.info("Publishing event to {} : {}", url, ce); + HttpURLConnection http = (HttpURLConnection) url.openConnection(); + http.setRequestMethod("POST"); + http.setDoOutput(true); + http.setDoInput(true); -Here's the expected output + HttpMessageWriter messageWriter = createMessageWriter(http); + messageWriter.writeBinary(ce); -[source,shell] ----- -broker.eventing.knative.dev/default created -sinkbinding.sources.knative.dev/drivers-binding created -sinkbinding.sources.knative.dev/legacy-binding created -trigger.eventing.knative.dev/trg-drivers created -trigger.eventing.knative.dev/trg-legacy created -broker.eventing.knative.dev/default condition met -sinkbinding.sources.knative.dev/drivers-binding condition met -sinkbinding.sources.knative.dev/legacy-binding condition met -trigger.eventing.knative.dev/trg-drivers condition met -trigger.eventing.knative.dev/trg-drivers condition met + int code = http.getResponseCode(); + if (code < 200 || code >= 300) { + throw new IOException("Unexpected response code " + code); + } + } +} ---- -The OpenShift Container Platform provides can provide a clear visualization of our deployed solution. +Once again, notice this is just a simple _HTTP_ client doing the _POST_ request, with the body being the JSON representation of the _CloudEvent_. -image::solution-odc.png[width=100%] +The last part to see is the _HTTP_ listener on the legacy application side. +This listener will be responsible for receiving events from _Knative's Event Mesh_ and converting them into our custom event type: -The console shows two sink bindings on the left, and they are feeding the events from the applications to the _Broker_ (depicted in the center). -The _Broker_ is the centralized infrastructure piece that ensures a proper decoupling of the services. -On the right, you could see the two applications deployed as _Knative_ services, and two triggers (as lines) that configure the _Event Mesh_ to feed appropriate events to the applications. +[source,java] +---- +@RestController +public class CloudEventReceiver { + private static final Logger log = LoggerFactory.getLogger(Receiver.class); -=== Walkthrough guide + private final EventsPublisher eventsPublisher; + private final List> froms; -With the demo pieces deployed on the cluster, we could go ahead with testing the functionality. + @Autowired + Receiver(EventsPublisher eventsPublisher, List> froms) { + this.eventsPublisher = eventsPublisher; + this.froms = froms; + } -For the sake of brevity, the legacy application, at startup, prepares some development data in the in-memory database its running on. -We will leverage that data to complete transit without the hassle of simulating the whole ride. + @PostMapping("/") + public void receive(@RequestBody CloudEvent event) { + log.info("Received event: {}", event); -Because we use serverless deployments, the services could be scaled to zero. -This fact makes it a bit harder to listen to the application logs. -We recommend using https://github.com/stern/stern[`+stern+` tool] to easily listen to both apps, even across scale to zero periods. + for (From from : froms) { + if (from.matches(event)) { + Event ev = from.fromCloudEvent(event); // <1> + eventsPublisher.publish(ev); // <2> + return; + } + } -[.console-input] -[source,shell] ----- -stern \ - --namespace demo \ - --container user-container \ - '(legacy|drivers).*' + throw new IllegalStateException("No matching event type consumer found"); + } +} ---- -Alternatively, you can use a regular `+oc+` command and a bit of scripting: +<1> We unwrap the _CloudEvent_ into our domain event type (in the example that's the `+DriverFeeCalculated+` type) +<2> And publish it withing the application, using the framework's _EventsPublisher_ implementation. +The domain events will be transmitted to the methods annotated with `@EventListener`. -[.console-input] -[source,shell] ----- -oc logs \ - --selector app=legacy \ - --namespace demo \ - --follow & +[CAUTION] +==== +Don't confuse the framework's _EventsPublisher_ with _Cloud Event_ sender and receiver. +==== -while [ $(oc get pod --namespace demo --selector app=drivers -o name | wc -l) -eq 0 ]; do \ - sleep 1; done && oc wait pod \ - --namespace demo \ - --selector app=drivers \ - --for condition=Ready=True && \ - oc logs \ - --selector app=drivers \ - --namespace demo \ - --follow ----- +=== The wiring of our _Event Mesh_ -In the second terminal, call the legacy endpoint by sending a _POST_ message like the following: +To complete the solution, we need to configure the _Event Mesh_. +The configuration describes the rules for receiving and sending events from and to the _Event Mesh_ and the application modules. -[.console-input] -[source,shell] +Here are the sources in our case: + +[source,yaml] ---- -curl -Lk -v -X POST -H 'Content-Type: application/json' \ - $(oc get ksvc legacy --namespace demo -o jsonpath='{.status.url}')/transits/8/complete \ - --data-binary @- << EOF -{ - "country": "Polska", - "city": "Warszawa", - "street": "Żytnia", - "buildingNumber": 32, - "hash": -580606919 -} -EOF +apiVersion: sources.knative.dev/v1 +kind: SinkBinding +metadata: + name: drivers-binding + namespace: demo +spec: + sink: + ref: + apiVersion: eventing.knative.dev/v1 + kind: Broker + name: default + namespace: demo + subject: + apiVersion: serving.knative.dev/v1 + kind: Service + name: drivers + namespace: demo +--- +apiVersion: sources.knative.dev/v1 +kind: SinkBinding +metadata: + name: legacy-binding + namespace: demo +spec: + sink: + ref: + apiVersion: eventing.knative.dev/v1 + kind: Broker + name: default + namespace: demo + subject: + apiVersion: serving.knative.dev/v1 + kind: Service + name: legacy + namespace: demo ---- -You should observe the cURL command succeeded, and return the ride data. -Moreover, the logs of both applications should be updated. +We are using the _SinkBinding_ resource to bind an event source (the _Service_) with an event sink (_Broker_). +We have two applications that will feed their events into the _Event Mesh_, so we need two _SinkBinding_ resources. -On the _Legacy_ application you could see the log line, with shows the application is sending the _Cloud Event_ to the _Event Mesh_: +Lastly, we have to configure the _Broker_ to send events from the _Event Mesh_ to the expected application modules. +We use the _Trigger_ resource for this purpose. +[source,yaml] ---- -INFO 1 --- [nio-8080-exec-1] i.l.cabs.common.cloudevents.Publisher : -Publishing event to http://broker-ingress.knative-eventing.svc.cluster.local/demo/default : -CloudEvent{id='83720fe5-02ee-4a3e-9b22-5c287fb68d10',source=usvc://cabs/legacy, -type='cabs.drivers.calculate-fee', datacontenttype='application/json', -subject='4e630a96-4d5c-488c-a53b-9554c0bcb97e',time=2025-02-04T17:32:20.638351262Z, -data=BytesCloudEventData{value=[123, 34, 100, 114, 105, 118, 101, 114, 45, 105, -100, 34, 58, 49, 57, 57, 51, 52, 51, 50, 53, 53, 50, 44, 34, 116, 114, 97, 110, -115, 105, 116, 45, 112, 114, 105, 99, 101, 34, 58, 53, 49, 48, 48, 125]}, -extensions={}} +apiVersion: eventing.knative.dev/v1 +kind: Trigger +metadata: + name: trg-drivers + namespace: demo +spec: + broker: default + filter: + attributes: + type: cabs.drivers.calculate-fee # <1> + subscriber: + ref: + apiVersion: serving.knative.dev/v1 + kind: Service + name: drivers + namespace: demo +--- +apiVersion: eventing.knative.dev/v1 +kind: Trigger +metadata: + name: trg-legacy + namespace: demo +spec: + broker: default + filter: + attributes: + type: cabs.drivers.driver-fee # <1> + subscriber: + ref: + apiVersion: serving.knative.dev/v1 + kind: Service + name: legacy + namespace: demo ---- -You can notice the `+cabs.drivers.calculate-fee+` event was later routed to the _Drivers_ service, which calculated the fee. -After the fee was calculated, the `+cabs.drivers.driver-fee+` event was published back into the _Event Mesh_. +<1> Note, we specify the type of the event, as a filter. ----- -[INFO drivers::app::events] Received event: - CloudEvent: - specversion: '1.0' - id: 'f94792bc-9c38-4db1-8da6-b6a28d1b4847' - type: 'cabs.drivers.calculate-fee' - source: 'usvc://cabs/legacy' - datacontenttype: 'application/json' - subject: '005be37e-8971-4a5b-b5e7-dd18de3c1184' - time: '2025-02-04T17:48:11.641317948+00:00' - knativearrivaltime: '2025-02-04T17:48:11.655926003Z' - Binary data: "{\"driver-id\":1993432552,\"transit-price\":5100}" - -[DEBUG drivers::drivers::service] fee event: Subject { - id: Some("005be37e-8971-4a5b-b5e7-dd18de3c1184"), - entity: CalculateFeeEvent { - driver_id: Identifier(1993432552), - transit_price: Money(5100) } } -[DEBUG drivers::drivers::service] fee: Money(4856) -[DEBUG drivers::support::cloudevents] sending cabs.drivers.driver-fee event to - http://broker-ingress.knative-eventing.svc.cluster.local/demo/default: - Event { attributes: V10(Attributes { id: "939babd7-6a85-4859-b45b-66087aba9418", - ty: "cabs.drivers.driver-fee", source: "usvc://cabs/drivers", - datacontenttype: Some("application/json"), dataschema: None, - subject: Some("005be37e-8971-4a5b-b5e7-dd18de3c1184"), - time: Some(2025-02-04T17:48:12.897943139Z) }), - data: Some(Json(Object {"driver-id": Number(1993432552), "fee": Number(4856)})), - extensions: {} } ----- +[#_conclusion] +== Conclusion + +Let's step back and take a look at what we have accomplished. + +The refactored application code fragment is now distributed, resilient, and eventually consistent. +It will gracefully handle the failures that may happen while calculating the driver's fee. +The _Event Mesh_ will make sure to retry the event delivery, in case of failures on either side. + +We could extend the refactoring, even further, with the same principle, making the whole application modern, responsible, and without incorrect, unnecessary, transactional behavior. -In the end, the `+cabs.drivers.driver-fee+` event was routed to the _Legacy_ application, by _Event Mesh_. -You could see the evidence of it in the logs. ----- -INFO 1 --- [nio-8080-exec-2] i.l.c.ride.details.TransitDetailsFacade : - Driver fee calculated for transit 005be37e-8971-4a5b-b5e7-dd18de3c1184: 48.56 ----- From 9f1b45b8b1895a2f3f9f4fcfdad20c77f4e78a66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Fri, 28 Mar 2025 15:32:01 +0100 Subject: [PATCH 18/22] CodeRabbit nitpicks --- documentation/modules/ROOT/pages/02-architecture.adoc | 1 + documentation/modules/ROOT/pages/03-demo.adoc | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/documentation/modules/ROOT/pages/02-architecture.adoc b/documentation/modules/ROOT/pages/02-architecture.adoc index 7c53e73..f6eb7f4 100644 --- a/documentation/modules/ROOT/pages/02-architecture.adoc +++ b/documentation/modules/ROOT/pages/02-architecture.adoc @@ -100,6 +100,7 @@ The potential events are transmitted to the _Event Mesh_. 5. The dispatch loop continues until the event queue is empty and all the events are processed successfully. The failures are automatically retried by the _Event Mesh_, with an increasing pauses between retries to avoid overloading the system. +// TODO: Replace with custom graphics image::https://img.plantuml.biz/plantuml/svg/TPFDReGW483lFCNKkpw0XytMRDCqxJQRDdq05iULB885j35Dtxs8k2xxSuEPRpvm1jV6KcsxHf07MsE3m51t0gbCLMS5bqZCaSkMQjh0kBL3Yz0gCVWSOK9r9IHFFKeBMpHr0hy4WAccLNAC9Q-IMjuZ55eTKIT0JLWwxBl33Xr2goFr6RyYVuHKIfIe8TbofXKOr3rdQAxa6-tKsi3d17X7Y8MGuqjgwPuQNF1DSKvkYbZw8dl56PU7I3j5yPPsAGZYm5wAtvNb5MUk7qf6xlF4V81hmbdf6nue6y0Cnc9prOQGVMnRhvksqHK3CNzuCUf3B2tLZqnNOIevxBgzuAO676TgPYhJ_53RRELg8OUlrgdH-ybKjm1-XexPkTPoOsTFF1R815OZVUVK84tTlUB273xSmyGRN3oW-zoDPb_0brVDLijJoU4PhG4kAmLqxwgWd58aFjzNdTx1gMCX0XgPqgKXQvIb-_d-0G00[width=100%] //// diff --git a/documentation/modules/ROOT/pages/03-demo.adoc b/documentation/modules/ROOT/pages/03-demo.adoc index 610b983..bcb9dd7 100644 --- a/documentation/modules/ROOT/pages/03-demo.adoc +++ b/documentation/modules/ROOT/pages/03-demo.adoc @@ -55,7 +55,7 @@ public void completeTransit(Long driverId, UUID requestUUID, Address destination ==== There are issues with the above method. -<1> It uses the `+@Transational+` annotation, and modify number of unrelated data stores. +<1> It uses the `+@Transactional+` annotation, and modifies multiple unrelated data stores. <2> It merges different, business domains. ==== @@ -75,7 +75,7 @@ In effect, the end-user will receive a nasty error message. [NOTE] ==== -Outages from the dependant services must not invalidate the main intent. +Outages from the dependent services must not invalidate the main intent. In fact, all the operations in this example could happen independently, and at different, yet reasonable times. ==== @@ -87,7 +87,7 @@ The code starts small, easy to understand. When new features are added, it keeps growing as developers cramp new instructions into methods like `+completeTransit+`. Of course, the developers could re-architect the code, to extract instructions to a separate blocks, but that is just a half-measure. -Still, the application will do all the operations, starting from `+completeTransit+` method in the same time, and withing the same _"script"_. +Still, the application will do all the operations, starting from `+completeTransit+` method in the same time, and within the same _"script"_. [#_refactoring_plan] == Refactoring plan @@ -107,6 +107,7 @@ After the refactoring, the `+completeTransit+` code will use two event types: The diagram below shows the sequence of operations that happen when we initiate refactored `+completeTransit+` code. +// TODO: Replace with custom graphics image::https://www.plantuml.com/plantuml/svg/VP1DJiCm58JtFiMZ-rmWYwgqeHkeX2WNUBK7Ok4ubdyYzVQuZKbe5TZ5olTcFiqcHFOnTKOyn1OTIC8d0xPLdwBH5iBb_rfgnpRIwWMVBC_qwDoAED3ul4MUBKSzW9u6vES1eRsYMzz_mT-YZS-W3tJeLUwyOdlW23zeYJkK8vyuZ52p5O9bRk687uTYLgrB4zNqcav6XvPsR6GocTsZQ8d2L1aV3slQzVP3-uuKpCNgB1JkEwQpzI_FcjxoL5XgcUvdMioVL4soi-iuIOQcE5N259RYPgKYMNJ-3lfdkMPRqp7s7lJkjQFBvWihR61Lwimt[width=100%] //// From 25b6ab011ed55e2a6326552006f01a86d35c3b17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Fri, 28 Mar 2025 17:06:39 +0100 Subject: [PATCH 19/22] ui-bundle: cardil/redhat-solution-patterns-course-ui v0.1.17 --- dev-site.yml | 2 +- site.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dev-site.yml b/dev-site.yml index 1818b85..7eb142f 100644 --- a/dev-site.yml +++ b/dev-site.yml @@ -17,7 +17,7 @@ asciidoc: - ./lib/tab-block.js ui: bundle: - url: https://github.com/redhat-solution-patterns/course-ui/releases/download/v0.1.16/ui-bundle.zip + url: https://github.com/cardil/redhat-solution-patterns-course-ui/releases/download/v0.1.17/ui-bundle.zip snapshot: true supplemental_files: ./supplemental-ui output: diff --git a/site.yml b/site.yml index 39a0fc4..3c260a5 100644 --- a/site.yml +++ b/site.yml @@ -21,7 +21,7 @@ asciidoc: ui: bundle: - url: https://github.com/redhat-solution-patterns/course-ui/releases/download/v0.1.16/ui-bundle.zip + url: https://github.com/cardil/redhat-solution-patterns-course-ui/releases/download/v0.1.17/ui-bundle.zip snapshot: true supplemental_files: - path: ./supplemental-ui From e40919af69cc3c2384ed4cdca912deee95deb1df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Mon, 31 Mar 2025 13:38:14 +0200 Subject: [PATCH 20/22] Use redhat-solution-patterns/course-ui latest bundle --- dev-site.yml | 2 +- documentation/modules/ROOT/pages/03-demo.adoc | 4 ++-- site.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dev-site.yml b/dev-site.yml index 7eb142f..22adedc 100644 --- a/dev-site.yml +++ b/dev-site.yml @@ -17,7 +17,7 @@ asciidoc: - ./lib/tab-block.js ui: bundle: - url: https://github.com/cardil/redhat-solution-patterns-course-ui/releases/download/v0.1.17/ui-bundle.zip + url: https://github.com/redhat-solution-patterns/course-ui/releases/download/v0.1.17/ui-bundle.zip snapshot: true supplemental_files: ./supplemental-ui output: diff --git a/documentation/modules/ROOT/pages/03-demo.adoc b/documentation/modules/ROOT/pages/03-demo.adoc index bcb9dd7..ba0d606 100644 --- a/documentation/modules/ROOT/pages/03-demo.adoc +++ b/documentation/modules/ROOT/pages/03-demo.adoc @@ -473,12 +473,12 @@ After the fee was calculated, the `+cabs.drivers.driver-fee+` event was publishe knativearrivaltime: '2025-02-04T17:48:11.655926003Z' Binary data: "{\"driver-id\":1993432552,\"transit-price\":5100}" -[DEBUG drivers::drivers::service] fee event: Subject { +[DEBUG drivers::drivers::service] calculate fee for: Subject { id: Some("005be37e-8971-4a5b-b5e7-dd18de3c1184"), entity: CalculateFeeEvent { driver_id: Identifier(1993432552), transit_price: Money(5100) } } -[DEBUG drivers::drivers::service] fee: Money(4856) +[DEBUG drivers::drivers::service] fee value: Money(4856) [DEBUG drivers::support::cloudevents] sending cabs.drivers.driver-fee event to http://broker-ingress.knative-eventing.svc.cluster.local/demo/default: Event { attributes: V10(Attributes { id: "939babd7-6a85-4859-b45b-66087aba9418", diff --git a/site.yml b/site.yml index 3c260a5..965ac1f 100644 --- a/site.yml +++ b/site.yml @@ -21,7 +21,7 @@ asciidoc: ui: bundle: - url: https://github.com/cardil/redhat-solution-patterns-course-ui/releases/download/v0.1.17/ui-bundle.zip + url: https://github.com/redhat-solution-patterns/course-ui/releases/download/v0.1.17/ui-bundle.zip snapshot: true supplemental_files: - path: ./supplemental-ui From 357b7bd65f56794cbda93415edc7861a05e46e9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Mon, 31 Mar 2025 15:45:57 +0200 Subject: [PATCH 21/22] Use openshift-knative/cabs-usvc for demo --- documentation/modules/ROOT/pages/03-demo.adoc | 14 +++++++------- .../modules/ROOT/pages/developer-resources.adoc | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/documentation/modules/ROOT/pages/03-demo.adoc b/documentation/modules/ROOT/pages/03-demo.adoc index ba0d606..96b785a 100644 --- a/documentation/modules/ROOT/pages/03-demo.adoc +++ b/documentation/modules/ROOT/pages/03-demo.adoc @@ -193,7 +193,7 @@ Here are commands to apply the above manifests. [.console-input] [source,shell] ---- -git clone https://github.com/cardil/cabs-usvc +git clone https://github.com/openshift-knative/cabs-usvc oc apply -f cabs-usvc/deploy/serverless/operator.yaml oc wait csv/serverless-operator.v1.35.0 \ --for 'jsonpath={.status.conditions[?(@.phase == "Succeeded")]}' @@ -286,9 +286,9 @@ knativeeventing.operator.knative.dev/knative-eventing condition met To install the Demo application, apply the following manifests. -* https://github.com/cardil/cabs-usvc/blob/main/deploy/apps/legacy.yaml[The legacy application] -* https://github.com/cardil/cabs-usvc/blob/main/deploy/db/redis.yaml[The Drivers database] -* https://github.com/cardil/cabs-usvc/blob/main/deploy/apps/drivers.yaml[The Drivers module] +* https://github.com/openshift-knative/cabs-usvc/blob/main/deploy/apps/legacy.yaml[The legacy application] +* https://github.com/openshift-knative/cabs-usvc/blob/main/deploy/db/redis.yaml[The Drivers database] +* https://github.com/openshift-knative/cabs-usvc/blob/main/deploy/apps/drivers.yaml[The Drivers module] Here are commands to apply the above manifests. @@ -326,9 +326,9 @@ service.serving.knative.dev/legacy condition met To configure the Event Mesh, apply the following manifests. -* https://github.com/cardil/cabs-usvc/blob/main/deploy/mesh/broker.yaml[_Broker_] -* https://github.com/cardil/cabs-usvc/blob/main/deploy/mesh/sources.yaml[Sources] -* https://github.com/cardil/cabs-usvc/blob/main/deploy/mesh/triggers.yaml[Triggers] +* https://github.com/openshift-knative/cabs-usvc/blob/main/deploy/mesh/broker.yaml[_Broker_] +* https://github.com/openshift-knative/cabs-usvc/blob/main/deploy/mesh/sources.yaml[Sources] +* https://github.com/openshift-knative/cabs-usvc/blob/main/deploy/mesh/triggers.yaml[Triggers] Here are commands to apply the above manifests. diff --git a/documentation/modules/ROOT/pages/developer-resources.adoc b/documentation/modules/ROOT/pages/developer-resources.adoc index 219e26e..4783fa3 100644 --- a/documentation/modules/ROOT/pages/developer-resources.adoc +++ b/documentation/modules/ROOT/pages/developer-resources.adoc @@ -6,7 +6,7 @@ == Developer Resources -* https://github.com/cardil/cabs-usvc[Demo source code] — _The example code used in this solution, based on the https://github.com/legacyfighter/cabs-java[LegacyFighter Java app]_ +* https://github.com/openshift-knative/cabs-usvc[Demo source code] — _The example code used in this solution, based on the https://github.com/legacyfighter/cabs-java[LegacyFighter Java app]_ * https://youtu.be/Rc5IO6S6ZOk[Let's get meshy! Microservices are easy with Event Mesh] — _The talk that served a base for this solution_ * https://www.redhat.com/en/technologies/cloud-computing/openshift/serverless[Red Hat OpenShift Serverless] * https://knative.dev/docs/eventing/event-mesh/[Knative Event Mesh] From f1240b1845c6aa2e08c84c79111e8d209aec44e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Mon, 31 Mar 2025 18:02:01 +0200 Subject: [PATCH 22/22] Typo --- documentation/modules/ROOT/pages/03-demo.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/modules/ROOT/pages/03-demo.adoc b/documentation/modules/ROOT/pages/03-demo.adoc index 96b785a..7cc670e 100644 --- a/documentation/modules/ROOT/pages/03-demo.adoc +++ b/documentation/modules/ROOT/pages/03-demo.adoc @@ -69,7 +69,7 @@ The transactional processing has been the cornerstone of many business applicati However, in most cases, the transactional processing isn't the best fit for real-world processes. In our example, when the ride finishes, that's a real-world situation. -However, the example uses the `+@Transational+` annotation, and operate on number of unrelated data. +However, the example uses the `+@Transactional+` annotation, and operate on number of unrelated data. This means that when one of those operations fails, the whole processing will be rolled back. In effect, the end-user will receive a nasty error message. @@ -645,7 +645,7 @@ spec: retry: 10 # <3> ---- -<1> The `+backoffDelay+` is the delay between retries, and us use `+200ms+` initially. +<1> The `+backoffDelay+` is the delay between retries, and we use `+200ms+` in this example. <2> The `+backoffPolicy+` is set to `+exponential+`, which means that the delay will be doubled each time. <3> The `+retry+` is the number of times we retry before giving up.