From 6245c413ffb39395583721fe36fc86a99a1e3c2e Mon Sep 17 00:00:00 2001 From: 9pace Date: Mon, 20 Oct 2025 15:57:57 -0400 Subject: [PATCH 1/5] docs: first cdk deploy flowchart --- packages/aws-cdk/README.md | 181 +++++++++++++++++++++++++++++++++++++ 1 file changed, 181 insertions(+) diff --git a/packages/aws-cdk/README.md b/packages/aws-cdk/README.md index a3e3a2a57..404a3da19 100644 --- a/packages/aws-cdk/README.md +++ b/packages/aws-cdk/README.md @@ -567,6 +567,187 @@ and might have breaking changes in the future. > *: `Fn::GetAtt` is only partially supported. Refer to [this implementation](https://github.com/aws/aws-cdk-cli/blob/main/packages/aws-cdk/lib/api/cloudformation/evaluate-cloudformation-template.ts#L256-L266) for supported resources and attributes. +#### Understanding the Deploy Process + +The `cdk deploy` command follows a multi-phase process to deploy your infrastructure. This flowchart provides a high-level overview of the deployment process: + +```mermaid +graph TD + %% Initialization Phase + c1["Start: cdk deploy command"] + c2["Parse CLI Arguments & Load Configuration"] + c3["Initialize CDK Toolkit"] + + %% Stack Selection Phase + c4["Select Target Stacks"] + c5["Validate Stack Selection"] + + %% Synthesis Phase + c6["Synthesis Phase"] + c7{"Missing AWS Context?"} + c8["Fetch Context from AWS"] + c9["Execute CDK Application"] + c10["Generate Cloud Assembly"] + + %% Asset Processing Phase + c11["Asset Processing Phase"] + c12["Analyze Asset Dependencies"] + c13["Build Assets in Parallel"] + c14["Publish Assets in Parallel"] + + %% Deployment Preparation Phase + c15["Deployment Preparation"] + c16["Check Security Approval Requirements"] + c17{"Approval Required?"} + c18["Request User Approval"] + + %% Deployment Method Selection + c19{"Deployment Method Selection"} + c20["Hotswap Deployment"] + c21["CloudFormation Deployment"] + + %% Hotswap Path + c22["Identify Hotswappable Resources"] + c23["Update Resources Directly via AWS APIs"] + + %% CloudFormation Path + c24["Create/Update CloudFormation Stack"] + c25["Monitor Stack Progress"] + c26["Wait for Stack Completion"] + + %% Completion Phase + c27["Collect Stack Outputs"] + c28["Report Deployment Status"] + c29["End: Deployment Complete"] + + %% Main Flow + c1 --> c2 + c2 --> c3 + c3 --> c4 + c4 --> c5 + c5 --> c6 + + %% Synthesis Phase with Context Loop + c6 --> c7 + c7 -->|"Yes"| c8 + c8 --> c9 + c9 --> c10 + c10 -->|"Loop if more context needed"| c7 + c7 -->|"No"| c11 + + %% Asset Processing Phase + c11 --> c12 + c12 --> c13 + c13 --> c14 + c14 --> c15 + + %% Deployment Preparation + c15 --> c16 + c16 --> c17 + c17 -->|"Yes"| c18 + c17 -->|"No"| c19 + c18 --> c19 + + %% Deployment Method Selection + c19 -->|"Hotswap Available"| c20 + c19 -->|"Standard Deployment"| c21 + + %% Hotswap Path + c20 --> c22 + c22 --> c23 + c23 --> c27 + + %% CloudFormation Path + c21 --> c24 + c24 --> c25 + c25 --> c26 + c26 --> c27 + + %% Completion + c27 --> c28 + c28 --> c29 + + %% Phase-based Color Coding + %% Initialization Phase (Light Gray) + style c1 fill:#f5f5f5,stroke:#757575,stroke-width:2px + style c2 fill:#f5f5f5,stroke:#757575,stroke-width:2px + style c3 fill:#f5f5f5,stroke:#757575,stroke-width:2px + + %% Stack Selection Phase (Light Cyan) + style c4 fill:#e0f7fa,stroke:#00838f,stroke-width:2px + style c5 fill:#e0f7fa,stroke:#00838f,stroke-width:2px + + %% Synthesis Phase (Light Blue) + style c6 fill:#e1f5fe,stroke:#0277bd,stroke-width:3px + style c7 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style c8 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style c9 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style c10 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + + %% Asset Processing Phase (Light Purple) + style c11 fill:#f3e5f5,stroke:#6a1b9a,stroke-width:3px + style c12 fill:#f3e5f5,stroke:#6a1b9a,stroke-width:2px + style c13 fill:#f3e5f5,stroke:#6a1b9a,stroke-width:2px + style c14 fill:#f3e5f5,stroke:#6a1b9a,stroke-width:2px + + %% Deployment Preparation (Light Yellow) + style c15 fill:#fffde7,stroke:#f57f17,stroke-width:2px + style c16 fill:#fffde7,stroke:#f57f17,stroke-width:2px + style c17 fill:#fffde7,stroke:#f57f17,stroke-width:2px + style c18 fill:#fffde7,stroke:#f57f17,stroke-width:2px + + %% Deployment Method Selection (Light Amber) + style c19 fill:#fff8e1,stroke:#ff6f00,stroke-width:2px + + %% Hotswap Deployment (Light Green) + style c20 fill:#e8f5e9,stroke:#2e7d32,stroke-width:3px + style c22 fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px + style c23 fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px + + %% CloudFormation Deployment (Light Red) + style c21 fill:#ffebee,stroke:#c62828,stroke-width:3px + style c24 fill:#ffebee,stroke:#c62828,stroke-width:2px + style c25 fill:#ffebee,stroke:#c62828,stroke-width:2px + style c26 fill:#ffebee,stroke:#c62828,stroke-width:2px + + %% Completion Phase (Light Teal) + style c27 fill:#e0f2f1,stroke:#00695c,stroke-width:2px + style c28 fill:#e0f2f1,stroke:#00695c,stroke-width:2px + style c29 fill:#e0f2f1,stroke:#00695c,stroke-width:2px + + %% Legend at Bottom + subgraph Legend[" "] + direction LR + L1["Initialization"] + L2["Stack Selection"] + L3["Synthesis"] + L4["Asset Processing"] + L5["Deployment Prep"] + L6["Hotswap"] + L7["CloudFormation"] + L8["Completion"] + + style L1 fill:#f5f5f5,stroke:#757575,stroke-width:2px + style L2 fill:#e0f7fa,stroke:#00838f,stroke-width:2px + style L3 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style L4 fill:#f3e5f5,stroke:#6a1b9a,stroke-width:2px + style L5 fill:#fffde7,stroke:#f57f17,stroke-width:2px + style L6 fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px + style L7 fill:#ffebee,stroke:#c62828,stroke-width:2px + style L8 fill:#e0f2f1,stroke:#00695c,stroke-width:2px + end +``` + +**Key Phases:** + +- **Synthesis Phase** (light blue): Converts your CDK code into CloudFormation templates. May iterate multiple times if AWS context information (like VPC IDs or availability zones) needs to be fetched. + +- **Asset Processing Phase** (light purple): Builds and publishes assets (Docker images, Lambda code, files) in parallel to improve performance. + +- **Hotswap Deployment** (light green): Fast deployment path that updates resources directly via AWS APIs, skipping CloudFormation. Only available for certain resource types when using `--hotswap` flag. + +- **CloudFormation Deployment** (light red): Standard deployment path that uses CloudFormation change sets for full change tracking and rollback capabilities. + ### `cdk rollback` If a deployment performed using `cdk deploy --no-rollback` fails, your From 73e4fd393b9544c7a03ebc915d48d4a1fca5c664 Mon Sep 17 00:00:00 2001 From: 9pace Date: Tue, 28 Oct 2025 12:25:21 -0400 Subject: [PATCH 2/5] docs(aws-cdk): technical and conceptual flowcharts for deploy --- packages/aws-cdk/README.md | 342 ++++++++++++++++++++++++++----------- 1 file changed, 243 insertions(+), 99 deletions(-) diff --git a/packages/aws-cdk/README.md b/packages/aws-cdk/README.md index 404a3da19..c4ea70483 100644 --- a/packages/aws-cdk/README.md +++ b/packages/aws-cdk/README.md @@ -567,63 +567,53 @@ and might have breaking changes in the future. > *: `Fn::GetAtt` is only partially supported. Refer to [this implementation](https://github.com/aws/aws-cdk-cli/blob/main/packages/aws-cdk/lib/api/cloudformation/evaluate-cloudformation-template.ts#L256-L266) for supported resources and attributes. -#### Understanding the Deploy Process -The `cdk deploy` command follows a multi-phase process to deploy your infrastructure. This flowchart provides a high-level overview of the deployment process: +##### Deploy flowchart + +The following diagrams illustrate the CDK deployment process at two levels of detail. The first diagram provides a conceptual overview suitable for understanding the high-level flow, while the second diagram shows the technical implementation details for contributors working on the CDK codebase. + +This flowchart provides a high-level overview of the deployment architecture and key decision points: ```mermaid graph TD %% Initialization Phase - c1["Start: cdk deploy command"] - c2["Parse CLI Arguments & Load Configuration"] - c3["Initialize CDK Toolkit"] + c1["Initialize Deployment"] %% Stack Selection Phase - c4["Select Target Stacks"] - c5["Validate Stack Selection"] + c4["Determine Which Stacks to Deploy"] + c5["Order Stacks by Dependencies"] %% Synthesis Phase c6["Synthesis Phase"] - c7{"Missing AWS Context?"} - c8["Fetch Context from AWS"] - c9["Execute CDK Application"] - c10["Generate Cloud Assembly"] + c7{"Need AWS Account Info?
(VPCs, Zones, AMIs)"} + c8["Query AWS & Cache to
cdk.context.json"] + c9["Run Your CDK Code"] + c10["Generate CloudFormation Templates"] %% Asset Processing Phase c11["Asset Processing Phase"] - c12["Analyze Asset Dependencies"] - c13["Build Assets in Parallel"] - c14["Publish Assets in Parallel"] - - %% Deployment Preparation Phase - c15["Deployment Preparation"] - c16["Check Security Approval Requirements"] - c17{"Approval Required?"} - c18["Request User Approval"] + c13["Package Assets
(Lambda code, Docker images)"] + c14["Upload to S3 & ECR"] %% Deployment Method Selection - c19{"Deployment Method Selection"} - c20["Hotswap Deployment"] - c21["CloudFormation Deployment"] + c19{"Fast Deploy Available?
(--hotswap flag set?)"} + c20["Fast Deployment Path"] + c21["Standard Deployment Path"] %% Hotswap Path - c22["Identify Hotswappable Resources"] - c23["Update Resources Directly via AWS APIs"] + c22["Identify Resources to Update"] + c23["Update Resources Directly
(Skip CloudFormation)"] %% CloudFormation Path - c24["Create/Update CloudFormation Stack"] - c25["Monitor Stack Progress"] - c26["Wait for Stack Completion"] + c25["Deploy via CloudFormation"] + c27["Monitor Progress & Wait for Completion"] %% Completion Phase - c27["Collect Stack Outputs"] - c28["Report Deployment Status"] - c29["End: Deployment Complete"] + c29["Collect Outputs & Report Status"] + c30["End: Deployment Complete"] %% Main Flow - c1 --> c2 - c2 --> c3 - c3 --> c4 + c1 --> c4 c4 --> c5 c5 --> c6 @@ -632,46 +622,34 @@ graph TD c7 -->|"Yes"| c8 c8 --> c9 c9 --> c10 - c10 -->|"Loop if more context needed"| c7 + c10 -->|"Loop if context missing
(can repeat multiple times)"| c7 c7 -->|"No"| c11 %% Asset Processing Phase - c11 --> c12 - c12 --> c13 + c11 --> c13 c13 --> c14 - c14 --> c15 - - %% Deployment Preparation - c15 --> c16 - c16 --> c17 - c17 -->|"Yes"| c18 - c17 -->|"No"| c19 - c18 --> c19 + c14 --> c19 %% Deployment Method Selection - c19 -->|"Hotswap Available"| c20 - c19 -->|"Standard Deployment"| c21 + c19 -->|"Yes: Fast Deploy"| c20 + c19 -->|"No: Standard Deploy"| c21 %% Hotswap Path c20 --> c22 c22 --> c23 - c23 --> c27 + c23 --> c29 %% CloudFormation Path - c21 --> c24 - c24 --> c25 - c25 --> c26 - c26 --> c27 + c21 --> c25 + c25 --> c27 + c27 --> c29 %% Completion - c27 --> c28 - c28 --> c29 + c29 --> c30 %% Phase-based Color Coding %% Initialization Phase (Light Gray) style c1 fill:#f5f5f5,stroke:#757575,stroke-width:2px - style c2 fill:#f5f5f5,stroke:#757575,stroke-width:2px - style c3 fill:#f5f5f5,stroke:#757575,stroke-width:2px %% Stack Selection Phase (Light Cyan) style c4 fill:#e0f7fa,stroke:#00838f,stroke-width:2px @@ -686,16 +664,9 @@ graph TD %% Asset Processing Phase (Light Purple) style c11 fill:#f3e5f5,stroke:#6a1b9a,stroke-width:3px - style c12 fill:#f3e5f5,stroke:#6a1b9a,stroke-width:2px style c13 fill:#f3e5f5,stroke:#6a1b9a,stroke-width:2px style c14 fill:#f3e5f5,stroke:#6a1b9a,stroke-width:2px - %% Deployment Preparation (Light Yellow) - style c15 fill:#fffde7,stroke:#f57f17,stroke-width:2px - style c16 fill:#fffde7,stroke:#f57f17,stroke-width:2px - style c17 fill:#fffde7,stroke:#f57f17,stroke-width:2px - style c18 fill:#fffde7,stroke:#f57f17,stroke-width:2px - %% Deployment Method Selection (Light Amber) style c19 fill:#fff8e1,stroke:#ff6f00,stroke-width:2px @@ -706,47 +677,220 @@ graph TD %% CloudFormation Deployment (Light Red) style c21 fill:#ffebee,stroke:#c62828,stroke-width:3px - style c24 fill:#ffebee,stroke:#c62828,stroke-width:2px style c25 fill:#ffebee,stroke:#c62828,stroke-width:2px - style c26 fill:#ffebee,stroke:#c62828,stroke-width:2px + style c27 fill:#ffebee,stroke:#c62828,stroke-width:2px %% Completion Phase (Light Teal) - style c27 fill:#e0f2f1,stroke:#00695c,stroke-width:2px - style c28 fill:#e0f2f1,stroke:#00695c,stroke-width:2px style c29 fill:#e0f2f1,stroke:#00695c,stroke-width:2px + style c30 fill:#e0f2f1,stroke:#00695c,stroke-width:2px +``` + +**Legend:** +```mermaid +graph LR + L1["Initialization"] --> L2["Stack Selection"] --> L3["Synthesis"] --> L4["Asset Processing"] --> L5["Fast Deploy"] + L4 --> L6["Standard Deploy"] + L5 --> L7["Completion"] + L6 --> L7 + + style L1 fill:#f5f5f5,stroke:#757575,stroke-width:2px + style L2 fill:#e0f7fa,stroke:#00838f,stroke-width:2px + style L3 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style L4 fill:#f3e5f5,stroke:#6a1b9a,stroke-width:2px + style L5 fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px + style L6 fill:#ffebee,stroke:#c62828,stroke-width:2px + style L7 fill:#e0f2f1,stroke:#00695c,stroke-width:2px +``` + +##### Technical Implementation Details + +For contributors debugging or modifying the deploy command, this technical flowchart shows the exact function calls and file locations in the execution path. + +```mermaid +graph TD + %% CLI Entry Point + n1["cdk deploy
(User Command)"] + n2["cli.ts: exec()"] + n3["cli.ts: main()"] + + %% Deploy Method + n4["cdk-toolkit.ts: CdkToolkit.deploy()"] + n5["cdk-toolkit.ts: selectStacksForDeploy()"] + n6["Check if synthesis needed"] + + %% Synthesis Process + n7["cloud-executable.ts: doSynthesize()"] + n29{"Context missing?"} + n34["cloud-executable.ts: synthesizer()"] + n9["cli.ts: execProgram()"] + n10["childProcess.spawn()
(Run CDK App)"] + n11["CDK App Process Started"] + n35["CDK App: app.synth()"] + n36["@aws-cdk/core: synthesize()
Generate CloudFormation JSON"] + n12["Write templates to cdk.out/"] + n13["Return CloudAssembly object"] + + %% Stack Selection + n14["cloud-assembly.ts:
assembly.selectStacks()"] + n15["cloud-assembly.ts:
validateStacks()"] + n16["Return StackCollection"] + + %% Asset Processing + n17["cdk-toolkit.ts:
ResourceMigrator.tryMigrateResources()"] + n18["work-graph.ts:
WorkGraphBuilder.build()"] + n37["work-graph.ts:
analyzeDeploymentOrder()"] + n19["work-graph.ts:
workGraph.doParallel()"] + + %% Parallel Execution Nodes + n20["asset-build.ts: buildAsset()
(Sequential: concurrency=1)"] + n21["asset-publishing.ts: publishAsset()
(Parallel: concurrency=8)"] + n44["deploy-stack.ts: deployStack()
(Parallel: configurable)"] + n45["await Promise.all()
Wait for dependencies"] + + %% Deployment Process + n22["cdk-toolkit.ts: deployStack()"] + n23["deploy-stack.ts:
CloudFormationStack.lookup()"] + n24["deploy-stack.ts:
makeBodyParameter()"] + n25["deploy-stack.ts:
publishAssets()"] + n38["deploy-stack.ts:
requireApproval()"] - %% Legend at Bottom - subgraph Legend[" "] - direction LR - L1["Initialization"] - L2["Stack Selection"] - L3["Synthesis"] - L4["Asset Processing"] - L5["Deployment Prep"] - L6["Hotswap"] - L7["CloudFormation"] - L8["Completion"] - - style L1 fill:#f5f5f5,stroke:#757575,stroke-width:2px - style L2 fill:#e0f7fa,stroke:#00838f,stroke-width:2px - style L3 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style L4 fill:#f3e5f5,stroke:#6a1b9a,stroke-width:2px - style L5 fill:#fffde7,stroke:#f57f17,stroke-width:2px - style L6 fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px - style L7 fill:#ffebee,stroke:#c62828,stroke-width:2px - style L8 fill:#e0f2f1,stroke:#00695c,stroke-width:2px - end -``` - -**Key Phases:** - -- **Synthesis Phase** (light blue): Converts your CDK code into CloudFormation templates. May iterate multiple times if AWS context information (like VPC IDs or availability zones) needs to be fetched. - -- **Asset Processing Phase** (light purple): Builds and publishes assets (Docker images, Lambda code, files) in parallel to improve performance. - -- **Hotswap Deployment** (light green): Fast deployment path that updates resources directly via AWS APIs, skipping CloudFormation. Only available for certain resource types when using `--hotswap` flag. - -- **CloudFormation Deployment** (light red): Standard deployment path that uses CloudFormation change sets for full change tracking and rollback capabilities. + %% Hotswap Decision + n30{"--hotswap flag set?"} + n31["hotswap-deployments.ts:
tryHotswapDeployment()"] + + %% Standard CloudFormation Deployment + n26["deploy-stack.ts:
FullCloudFormationDeployment.performDeployment()"] + n27["AWS SDK: CloudFormation
createChangeSet() OR
updateStack()"] + n28["CloudFormation Service"] + n32["deploy-stack.ts:
StackActivityMonitor.start()"] + n33["deploy-stack.ts:
waitForStackDeploy()"] + + %% Completion + n39["deploy-stack.ts:
getStackOutputs()"] + n40["cdk-toolkit.ts:
printStackOutputs()"] + + %% Main Flow Connections + n1 --> n2 + n2 --> n3 + n3 --> n4 + n4 --> n5 + n5 --> n6 + n6 --> n7 + n7 --> n29 + n29 -->|"Yes"| n34 + n34 --> n9 + n9 --> n10 + n10 --> n11 + n11 --> n35 + n35 --> n36 + n36 --> n12 + n12 --> n13 + n13 -->|"Loop if context missing"| n29 + n29 -->|"No"| n14 + n14 --> n15 + n15 --> n16 + n16 --> n17 + n17 --> n18 + n18 --> n37 + n37 --> n19 + + %% Parallel execution from workGraph.doParallel() + n19 -.->|"Parallel"| n20 + n19 -.->|"Parallel"| n21 + n19 -.->|"Parallel"| n44 + + %% Dependency relationships + n20 --> n45 + n21 --> n45 + n44 --> n45 + n45 --> n22 + n22 --> n23 + n23 --> n24 + n24 --> n25 + n25 --> n38 + n38 --> n30 + n30 -->|"Yes"| n31 + n30 -->|"No"| n26 + n31 --> n39 + n26 --> n27 + n27 --> n28 + n28 --> n32 + n32 --> n33 + n33 --> n39 + n39 --> n40 + + %% Simplified Color Scheme - Only 3 colors + %% External Systems (Light Red) + style n1 fill:#ffebee,stroke:#c62828,stroke-width:2px + style n28 fill:#ffebee,stroke:#c62828,stroke-width:2px + + %% CDK App Process (Light Green) + style n10 fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px + style n11 fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px + style n35 fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px + style n36 fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px + style n12 fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px + + %% Decision Points (Light Yellow) + style n29 fill:#fff9c4,stroke:#f57f17,stroke-width:2px + style n30 fill:#fff9c4,stroke:#f57f17,stroke-width:2px + style n38 fill:#fff9c4,stroke:#f57f17,stroke-width:2px + style n45 fill:#fff9c4,stroke:#f57f17,stroke-width:2px + + %% Everything else - CDK CLI Code (Light Blue) + style n2 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n3 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n4 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n5 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n6 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n7 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n9 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n13 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n14 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n15 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n16 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n17 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n18 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n19 fill:#e1f5fe,stroke:#0277bd,stroke-width:3px + style n20 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n21 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n22 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n23 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n24 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n25 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n26 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n27 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n31 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n32 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n33 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n34 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n37 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n39 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n40 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n44 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + +``` + +**Legend (Node Categories):** +```mermaid +graph LR + L1["External Systems"]~~~L2["CDK App Process"]~~~L3["CDK CLI Code"]~~~L4["Decision Points"] + + style L1 fill:#ffebee,stroke:#c62828,stroke-width:2px + style L2 fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px + style L3 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style L4 fill:#fff9c4,stroke:#f57f17,stroke-width:2px +``` + +**Parallel Execution Model:** + +The deploy process uses a sophisticated work graph (`workGraph.doParallel()` in `work-graph.ts`) to manage parallel execution: + +- **Asset Building** (concurrency: 1): Compiles Docker images, Lambda code, etc. sequentially to avoid overwhelming system resources +- **Asset Publishing** (concurrency: 8): Uploads assets to S3/ECR in parallel for faster deployment +- **Stack Deployment** (configurable): Deploys multiple stacks in parallel while respecting dependencies + +The dotted lines indicate parallel execution paths from the work graph orchestrator. All operations respect dependency relationships before proceeding (node n45 represents the synchronization point). ### `cdk rollback` From e73de14781dcbbd1e7e3034dfcb617dd4d249122 Mon Sep 17 00:00:00 2001 From: 9pace Date: Sun, 28 Dec 2025 22:44:21 +0000 Subject: [PATCH 3/5] docs(aws-cdk): move detailed deploy architecture to new file --- packages/aws-cdk/README.md | 195 +------------------ packages/aws-cdk/docs/deploy-architecture.md | 194 ++++++++++++++++++ 2 files changed, 196 insertions(+), 193 deletions(-) create mode 100644 packages/aws-cdk/docs/deploy-architecture.md diff --git a/packages/aws-cdk/README.md b/packages/aws-cdk/README.md index c4ea70483..749ec31e2 100644 --- a/packages/aws-cdk/README.md +++ b/packages/aws-cdk/README.md @@ -570,9 +570,8 @@ and might have breaking changes in the future. ##### Deploy flowchart -The following diagrams illustrate the CDK deployment process at two levels of detail. The first diagram provides a conceptual overview suitable for understanding the high-level flow, while the second diagram shows the technical implementation details for contributors working on the CDK codebase. - -This flowchart provides a high-level overview of the deployment architecture and key decision points: +This flowchart provides a high-level overview of the deployment architecture and key decision points. +For technical implementation details (function calls, file locations), see [docs/deploy-architecture.md](./docs/deploy-architecture.md). ```mermaid graph TD @@ -702,196 +701,6 @@ graph LR style L7 fill:#e0f2f1,stroke:#00695c,stroke-width:2px ``` -##### Technical Implementation Details - -For contributors debugging or modifying the deploy command, this technical flowchart shows the exact function calls and file locations in the execution path. - -```mermaid -graph TD - %% CLI Entry Point - n1["cdk deploy
(User Command)"] - n2["cli.ts: exec()"] - n3["cli.ts: main()"] - - %% Deploy Method - n4["cdk-toolkit.ts: CdkToolkit.deploy()"] - n5["cdk-toolkit.ts: selectStacksForDeploy()"] - n6["Check if synthesis needed"] - - %% Synthesis Process - n7["cloud-executable.ts: doSynthesize()"] - n29{"Context missing?"} - n34["cloud-executable.ts: synthesizer()"] - n9["cli.ts: execProgram()"] - n10["childProcess.spawn()
(Run CDK App)"] - n11["CDK App Process Started"] - n35["CDK App: app.synth()"] - n36["@aws-cdk/core: synthesize()
Generate CloudFormation JSON"] - n12["Write templates to cdk.out/"] - n13["Return CloudAssembly object"] - - %% Stack Selection - n14["cloud-assembly.ts:
assembly.selectStacks()"] - n15["cloud-assembly.ts:
validateStacks()"] - n16["Return StackCollection"] - - %% Asset Processing - n17["cdk-toolkit.ts:
ResourceMigrator.tryMigrateResources()"] - n18["work-graph.ts:
WorkGraphBuilder.build()"] - n37["work-graph.ts:
analyzeDeploymentOrder()"] - n19["work-graph.ts:
workGraph.doParallel()"] - - %% Parallel Execution Nodes - n20["asset-build.ts: buildAsset()
(Sequential: concurrency=1)"] - n21["asset-publishing.ts: publishAsset()
(Parallel: concurrency=8)"] - n44["deploy-stack.ts: deployStack()
(Parallel: configurable)"] - n45["await Promise.all()
Wait for dependencies"] - - %% Deployment Process - n22["cdk-toolkit.ts: deployStack()"] - n23["deploy-stack.ts:
CloudFormationStack.lookup()"] - n24["deploy-stack.ts:
makeBodyParameter()"] - n25["deploy-stack.ts:
publishAssets()"] - n38["deploy-stack.ts:
requireApproval()"] - - %% Hotswap Decision - n30{"--hotswap flag set?"} - n31["hotswap-deployments.ts:
tryHotswapDeployment()"] - - %% Standard CloudFormation Deployment - n26["deploy-stack.ts:
FullCloudFormationDeployment.performDeployment()"] - n27["AWS SDK: CloudFormation
createChangeSet() OR
updateStack()"] - n28["CloudFormation Service"] - n32["deploy-stack.ts:
StackActivityMonitor.start()"] - n33["deploy-stack.ts:
waitForStackDeploy()"] - - %% Completion - n39["deploy-stack.ts:
getStackOutputs()"] - n40["cdk-toolkit.ts:
printStackOutputs()"] - - %% Main Flow Connections - n1 --> n2 - n2 --> n3 - n3 --> n4 - n4 --> n5 - n5 --> n6 - n6 --> n7 - n7 --> n29 - n29 -->|"Yes"| n34 - n34 --> n9 - n9 --> n10 - n10 --> n11 - n11 --> n35 - n35 --> n36 - n36 --> n12 - n12 --> n13 - n13 -->|"Loop if context missing"| n29 - n29 -->|"No"| n14 - n14 --> n15 - n15 --> n16 - n16 --> n17 - n17 --> n18 - n18 --> n37 - n37 --> n19 - - %% Parallel execution from workGraph.doParallel() - n19 -.->|"Parallel"| n20 - n19 -.->|"Parallel"| n21 - n19 -.->|"Parallel"| n44 - - %% Dependency relationships - n20 --> n45 - n21 --> n45 - n44 --> n45 - n45 --> n22 - n22 --> n23 - n23 --> n24 - n24 --> n25 - n25 --> n38 - n38 --> n30 - n30 -->|"Yes"| n31 - n30 -->|"No"| n26 - n31 --> n39 - n26 --> n27 - n27 --> n28 - n28 --> n32 - n32 --> n33 - n33 --> n39 - n39 --> n40 - - %% Simplified Color Scheme - Only 3 colors - %% External Systems (Light Red) - style n1 fill:#ffebee,stroke:#c62828,stroke-width:2px - style n28 fill:#ffebee,stroke:#c62828,stroke-width:2px - - %% CDK App Process (Light Green) - style n10 fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px - style n11 fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px - style n35 fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px - style n36 fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px - style n12 fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px - - %% Decision Points (Light Yellow) - style n29 fill:#fff9c4,stroke:#f57f17,stroke-width:2px - style n30 fill:#fff9c4,stroke:#f57f17,stroke-width:2px - style n38 fill:#fff9c4,stroke:#f57f17,stroke-width:2px - style n45 fill:#fff9c4,stroke:#f57f17,stroke-width:2px - - %% Everything else - CDK CLI Code (Light Blue) - style n2 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style n3 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style n4 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style n5 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style n6 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style n7 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style n9 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style n13 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style n14 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style n15 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style n16 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style n17 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style n18 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style n19 fill:#e1f5fe,stroke:#0277bd,stroke-width:3px - style n20 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style n21 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style n22 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style n23 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style n24 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style n25 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style n26 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style n27 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style n31 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style n32 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style n33 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style n34 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style n37 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style n39 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style n40 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style n44 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - -``` - -**Legend (Node Categories):** -```mermaid -graph LR - L1["External Systems"]~~~L2["CDK App Process"]~~~L3["CDK CLI Code"]~~~L4["Decision Points"] - - style L1 fill:#ffebee,stroke:#c62828,stroke-width:2px - style L2 fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px - style L3 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style L4 fill:#fff9c4,stroke:#f57f17,stroke-width:2px -``` - -**Parallel Execution Model:** - -The deploy process uses a sophisticated work graph (`workGraph.doParallel()` in `work-graph.ts`) to manage parallel execution: - -- **Asset Building** (concurrency: 1): Compiles Docker images, Lambda code, etc. sequentially to avoid overwhelming system resources -- **Asset Publishing** (concurrency: 8): Uploads assets to S3/ECR in parallel for faster deployment -- **Stack Deployment** (configurable): Deploys multiple stacks in parallel while respecting dependencies - -The dotted lines indicate parallel execution paths from the work graph orchestrator. All operations respect dependency relationships before proceeding (node n45 represents the synchronization point). - ### `cdk rollback` If a deployment performed using `cdk deploy --no-rollback` fails, your diff --git a/packages/aws-cdk/docs/deploy-architecture.md b/packages/aws-cdk/docs/deploy-architecture.md new file mode 100644 index 000000000..d74bd2693 --- /dev/null +++ b/packages/aws-cdk/docs/deploy-architecture.md @@ -0,0 +1,194 @@ +# Deploy Command Technical Architecture + +This document provides technical implementation details for contributors debugging or modifying the `cdk deploy` command. It shows the exact function calls and file locations in the execution path. + +For a high-level conceptual overview of the deploy process, see the [README](../README.md#deploy-flowchart). + +## Technical Flowchart + +```mermaid +graph TD + %% CLI Entry Point + n1["cdk deploy
(User Command)"] + n2["cli.ts: exec()"] + n3["cli.ts: main()"] + + %% Deploy Method + n4["cdk-toolkit.ts: CdkToolkit.deploy()"] + n5["cdk-toolkit.ts: selectStacksForDeploy()"] + n6["Check if synthesis needed"] + + %% Synthesis Process + n7["cloud-executable.ts: doSynthesize()"] + n29{"Context missing?"} + n34["cloud-executable.ts: synthesizer()"] + n9["cli.ts: execProgram()"] + n10["childProcess.spawn()
(Run CDK App)"] + n11["CDK App Process Started"] + n35["CDK App: app.synth()"] + n36["@aws-cdk/core: synthesize()
Generate CloudFormation JSON"] + n12["Write templates to cdk.out/"] + n13["Return CloudAssembly object"] + + %% Stack Selection + n14["cloud-assembly.ts:
assembly.selectStacks()"] + n15["cloud-assembly.ts:
validateStacks()"] + n16["Return StackCollection"] + + %% Asset Processing + n17["cdk-toolkit.ts:
ResourceMigrator.tryMigrateResources()"] + n18["work-graph.ts:
WorkGraphBuilder.build()"] + n37["work-graph.ts:
analyzeDeploymentOrder()"] + n19["work-graph.ts:
workGraph.doParallel()"] + + %% Parallel Execution Nodes + n20["asset-build.ts: buildAsset()
(Sequential: concurrency=1)"] + n21["asset-publishing.ts: publishAsset()
(Parallel: concurrency=8)"] + n44["deploy-stack.ts: deployStack()
(Parallel: configurable)"] + n45["await Promise.all()
Wait for dependencies"] + + %% Deployment Process + n22["cdk-toolkit.ts: deployStack()"] + n23["deploy-stack.ts:
CloudFormationStack.lookup()"] + n24["deploy-stack.ts:
makeBodyParameter()"] + n25["deploy-stack.ts:
publishAssets()"] + n38["deploy-stack.ts:
requireApproval()"] + + %% Hotswap Decision + n30{"--hotswap flag set?"} + n31["hotswap-deployments.ts:
tryHotswapDeployment()"] + + %% Standard CloudFormation Deployment + n26["deploy-stack.ts:
FullCloudFormationDeployment.performDeployment()"] + n27["AWS SDK: CloudFormation
createChangeSet() OR
updateStack()"] + n28["CloudFormation Service"] + n32["deploy-stack.ts:
StackActivityMonitor.start()"] + n33["deploy-stack.ts:
waitForStackDeploy()"] + + %% Completion + n39["deploy-stack.ts:
getStackOutputs()"] + n40["cdk-toolkit.ts:
printStackOutputs()"] + + %% Main Flow Connections + n1 --> n2 + n2 --> n3 + n3 --> n4 + n4 --> n5 + n5 --> n6 + n6 --> n7 + n7 --> n29 + n29 -->|"Yes"| n34 + n34 --> n9 + n9 --> n10 + n10 --> n11 + n11 --> n35 + n35 --> n36 + n36 --> n12 + n12 --> n13 + n13 -->|"Loop if context missing"| n29 + n29 -->|"No"| n14 + n14 --> n15 + n15 --> n16 + n16 --> n17 + n17 --> n18 + n18 --> n37 + n37 --> n19 + + %% Parallel execution from workGraph.doParallel() + n19 -.->|"Parallel"| n20 + n19 -.->|"Parallel"| n21 + n19 -.->|"Parallel"| n44 + + %% Dependency relationships + n20 --> n45 + n21 --> n45 + n44 --> n45 + n45 --> n22 + n22 --> n23 + n23 --> n24 + n24 --> n25 + n25 --> n38 + n38 --> n30 + n30 -->|"Yes"| n31 + n30 -->|"No"| n26 + n31 --> n39 + n26 --> n27 + n27 --> n28 + n28 --> n32 + n32 --> n33 + n33 --> n39 + n39 --> n40 + + %% Simplified Color Scheme - Only 3 colors + %% External Systems (Light Red) + style n1 fill:#ffebee,stroke:#c62828,stroke-width:2px + style n28 fill:#ffebee,stroke:#c62828,stroke-width:2px + + %% CDK App Process (Light Green) + style n10 fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px + style n11 fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px + style n35 fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px + style n36 fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px + style n12 fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px + + %% Decision Points (Light Yellow) + style n29 fill:#fff9c4,stroke:#f57f17,stroke-width:2px + style n30 fill:#fff9c4,stroke:#f57f17,stroke-width:2px + style n38 fill:#fff9c4,stroke:#f57f17,stroke-width:2px + style n45 fill:#fff9c4,stroke:#f57f17,stroke-width:2px + + %% Everything else - CDK CLI Code (Light Blue) + style n2 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n3 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n4 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n5 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n6 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n7 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n9 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n13 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n14 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n15 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n16 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n17 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n18 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n19 fill:#e1f5fe,stroke:#0277bd,stroke-width:3px + style n20 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n21 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n22 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n23 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n24 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n25 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n26 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n27 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n31 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n32 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n33 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n34 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n37 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n39 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n40 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style n44 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + +``` + +## Legend (Node Categories) + +```mermaid +graph LR + L1["External Systems"]~~~L2["CDK App Process"]~~~L3["CDK CLI Code"]~~~L4["Decision Points"] + + style L1 fill:#ffebee,stroke:#c62828,stroke-width:2px + style L2 fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px + style L3 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style L4 fill:#fff9c4,stroke:#f57f17,stroke-width:2px +``` + +## Parallel Execution Model + +The deploy process uses a sophisticated work graph (`workGraph.doParallel()` in `work-graph.ts`) to manage parallel execution: + +- **Asset Building** (concurrency: 1): Compiles Docker images, Lambda code, etc. sequentially to avoid overwhelming system resources +- **Asset Publishing** (concurrency: 8): Uploads assets to S3/ECR in parallel for faster deployment +- **Stack Deployment** (configurable): Deploys multiple stacks in parallel while respecting dependencies + +The dotted lines indicate parallel execution paths from the work graph orchestrator. All operations respect dependency relationships before proceeding (node n45 represents the synchronization point). From 06a36f89fe88691c0f6b2615184a35d60eabdada Mon Sep 17 00:00:00 2001 From: 9pace Date: Mon, 5 Jan 2026 14:48:53 -0500 Subject: [PATCH 4/5] docs(aws-cdk): simplify deploy flowchart in README --- packages/aws-cdk/README.md | 147 ++++++++++--------------------------- 1 file changed, 39 insertions(+), 108 deletions(-) diff --git a/packages/aws-cdk/README.md b/packages/aws-cdk/README.md index 05c8203cb..dc48a9b51 100644 --- a/packages/aws-cdk/README.md +++ b/packages/aws-cdk/README.md @@ -570,135 +570,66 @@ and might have breaking changes in the future. ##### Deploy flowchart -This flowchart provides a high-level overview of the deployment architecture and key decision points. +This flowchart provides a high-level overview of the deployment process. For technical implementation details (function calls, file locations), see [docs/deploy-architecture.md](./docs/deploy-architecture.md). ```mermaid graph TD - %% Initialization Phase - c1["Initialize Deployment"] + %% Stack Selection + c1["Select and Order Stacks
that need update"] - %% Stack Selection Phase - c4["Determine Which Stacks to Deploy"] - c5["Order Stacks by Dependencies"] + %% Synthesis + c2{"Need AWS Context?"} + c3["Query AWS and Cache
to cdk.context.json"] + c4["Run CDK App and
Generate CloudFormation Templates"] - %% Synthesis Phase - c6["Synthesis Phase"] - c7{"Need AWS Account Info?
(VPCs, Zones, AMIs)"} - c8["Query AWS & Cache to
cdk.context.json"] - c9["Run Your CDK Code"] - c10["Generate CloudFormation Templates"] + %% Asset Processing + c5["Package and Upload Assets
(Lambda code, Docker images)"] - %% Asset Processing Phase - c11["Asset Processing Phase"] - c13["Package Assets
(Lambda code, Docker images)"] - c14["Upload to S3 & ECR"] + %% Deployment + c6["Deploy via CloudFormation"] + c7["Monitor Progress and
Collect Outputs"] - %% Deployment Method Selection - c19{"Fast Deploy Available?
(--hotswap flag set?)"} - c20["Fast Deployment Path"] - c21["Standard Deployment Path"] - - %% Hotswap Path - c22["Identify Resources to Update"] - c23["Update Resources Directly
(Skip CloudFormation)"] - - %% CloudFormation Path - c25["Deploy via CloudFormation"] - c27["Monitor Progress & Wait for Completion"] + %% Completion + c8["Done"] - %% Completion Phase - c29["Collect Outputs & Report Status"] - c30["End: Deployment Complete"] + %% Flow + c1 --> c2 + c2 -->|"Yes"| c3 + c3 --> c4 + c4 -->|"Re-check context"| c2 + c2 -->|"No"| c5 - %% Main Flow - c1 --> c4 - c4 --> c5 c5 --> c6 - - %% Synthesis Phase with Context Loop c6 --> c7 - c7 -->|"Yes"| c8 - c8 --> c9 - c9 --> c10 - c10 -->|"Loop if context missing
(can repeat multiple times)"| c7 - c7 -->|"No"| c11 - - %% Asset Processing Phase - c11 --> c13 - c13 --> c14 - c14 --> c19 - - %% Deployment Method Selection - c19 -->|"Yes: Fast Deploy"| c20 - c19 -->|"No: Standard Deploy"| c21 - - %% Hotswap Path - c20 --> c22 - c22 --> c23 - c23 --> c29 - - %% CloudFormation Path - c21 --> c25 - c25 --> c27 - c27 --> c29 + c7 --> c8 - %% Completion - c29 --> c30 - - %% Phase-based Color Coding - %% Initialization Phase (Light Gray) - style c1 fill:#f5f5f5,stroke:#757575,stroke-width:2px - - %% Stack Selection Phase (Light Cyan) - style c4 fill:#e0f7fa,stroke:#00838f,stroke-width:2px - style c5 fill:#e0f7fa,stroke:#00838f,stroke-width:2px - - %% Synthesis Phase (Light Blue) - style c6 fill:#e1f5fe,stroke:#0277bd,stroke-width:3px - style c7 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style c8 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style c9 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style c10 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + %% Styling + style c1 fill:#e0f7fa,stroke:#00838f,stroke-width:2px - %% Asset Processing Phase (Light Purple) - style c11 fill:#f3e5f5,stroke:#6a1b9a,stroke-width:3px - style c13 fill:#f3e5f5,stroke:#6a1b9a,stroke-width:2px - style c14 fill:#f3e5f5,stroke:#6a1b9a,stroke-width:2px + style c2 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style c3 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style c4 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - %% Deployment Method Selection (Light Amber) - style c19 fill:#fff8e1,stroke:#ff6f00,stroke-width:2px + style c5 fill:#f3e5f5,stroke:#6a1b9a,stroke-width:2px - %% Hotswap Deployment (Light Green) - style c20 fill:#e8f5e9,stroke:#2e7d32,stroke-width:3px - style c22 fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px - style c23 fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px + style c6 fill:#fff3e0,stroke:#e65100,stroke-width:2px + style c7 fill:#fff3e0,stroke:#e65100,stroke-width:2px - %% CloudFormation Deployment (Light Red) - style c21 fill:#ffebee,stroke:#c62828,stroke-width:3px - style c25 fill:#ffebee,stroke:#c62828,stroke-width:2px - style c27 fill:#ffebee,stroke:#c62828,stroke-width:2px - - %% Completion Phase (Light Teal) - style c29 fill:#e0f2f1,stroke:#00695c,stroke-width:2px - style c30 fill:#e0f2f1,stroke:#00695c,stroke-width:2px + style c8 fill:#e0f2f1,stroke:#00695c,stroke-width:2px ``` -**Legend:** ```mermaid +--- +title: Legend +--- graph LR - L1["Initialization"] --> L2["Stack Selection"] --> L3["Synthesis"] --> L4["Asset Processing"] --> L5["Fast Deploy"] - L4 --> L6["Standard Deploy"] - L5 --> L7["Completion"] - L6 --> L7 - - style L1 fill:#f5f5f5,stroke:#757575,stroke-width:2px - style L2 fill:#e0f7fa,stroke:#00838f,stroke-width:2px - style L3 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style L4 fill:#f3e5f5,stroke:#6a1b9a,stroke-width:2px - style L5 fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px - style L6 fill:#ffebee,stroke:#c62828,stroke-width:2px - style L7 fill:#e0f2f1,stroke:#00695c,stroke-width:2px + L1["Stack Selection"] --> L2["Synthesis"] --> L3["Assets"] --> L4["Deploy"] --> L5["Done"] + style L1 fill:#e0f7fa,stroke:#00838f,stroke-width:2px + style L2 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style L3 fill:#f3e5f5,stroke:#6a1b9a,stroke-width:2px + style L4 fill:#fff3e0,stroke:#e65100,stroke-width:2px + style L5 fill:#e0f2f1,stroke:#00695c,stroke-width:2px ``` ### `cdk rollback` From cf0671220308f304e20539361d93c4820ab6d9f7 Mon Sep 17 00:00:00 2001 From: 9pace Date: Tue, 6 Jan 2026 09:34:47 -0500 Subject: [PATCH 5/5] docs(aws-cdk): convert flowchart to image, add mmd source --- packages/aws-cdk/README.md | 59 +------------------ packages/aws-cdk/images/deploy-flowchart.mmd | 43 ++++++++++++++ packages/aws-cdk/images/deploy-flowchart.png | Bin 0 -> 60576 bytes 3 files changed, 44 insertions(+), 58 deletions(-) create mode 100644 packages/aws-cdk/images/deploy-flowchart.mmd create mode 100644 packages/aws-cdk/images/deploy-flowchart.png diff --git a/packages/aws-cdk/README.md b/packages/aws-cdk/README.md index dc48a9b51..5f32a584c 100644 --- a/packages/aws-cdk/README.md +++ b/packages/aws-cdk/README.md @@ -573,64 +573,7 @@ and might have breaking changes in the future. This flowchart provides a high-level overview of the deployment process. For technical implementation details (function calls, file locations), see [docs/deploy-architecture.md](./docs/deploy-architecture.md). -```mermaid -graph TD - %% Stack Selection - c1["Select and Order Stacks
that need update"] - - %% Synthesis - c2{"Need AWS Context?"} - c3["Query AWS and Cache
to cdk.context.json"] - c4["Run CDK App and
Generate CloudFormation Templates"] - - %% Asset Processing - c5["Package and Upload Assets
(Lambda code, Docker images)"] - - %% Deployment - c6["Deploy via CloudFormation"] - c7["Monitor Progress and
Collect Outputs"] - - %% Completion - c8["Done"] - - %% Flow - c1 --> c2 - c2 -->|"Yes"| c3 - c3 --> c4 - c4 -->|"Re-check context"| c2 - c2 -->|"No"| c5 - - c5 --> c6 - c6 --> c7 - c7 --> c8 - - %% Styling - style c1 fill:#e0f7fa,stroke:#00838f,stroke-width:2px - - style c2 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style c3 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style c4 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - - style c5 fill:#f3e5f5,stroke:#6a1b9a,stroke-width:2px - - style c6 fill:#fff3e0,stroke:#e65100,stroke-width:2px - style c7 fill:#fff3e0,stroke:#e65100,stroke-width:2px - - style c8 fill:#e0f2f1,stroke:#00695c,stroke-width:2px -``` - -```mermaid ---- -title: Legend ---- -graph LR - L1["Stack Selection"] --> L2["Synthesis"] --> L3["Assets"] --> L4["Deploy"] --> L5["Done"] - style L1 fill:#e0f7fa,stroke:#00838f,stroke-width:2px - style L2 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px - style L3 fill:#f3e5f5,stroke:#6a1b9a,stroke-width:2px - style L4 fill:#fff3e0,stroke:#e65100,stroke-width:2px - style L5 fill:#e0f2f1,stroke:#00695c,stroke-width:2px -``` +![Deploy flowchart](./images/deploy-flowchart.png) ### `cdk rollback` diff --git a/packages/aws-cdk/images/deploy-flowchart.mmd b/packages/aws-cdk/images/deploy-flowchart.mmd new file mode 100644 index 000000000..5c40081ff --- /dev/null +++ b/packages/aws-cdk/images/deploy-flowchart.mmd @@ -0,0 +1,43 @@ +graph TD + %% Stack Selection + c1["Select and Order Stacks
that need update"] + + %% Synthesis + c2{"Need AWS Context?"} + c3["Query AWS and Cache
to cdk.context.json"] + c4["Run CDK App and
Generate CloudFormation Templates"] + + %% Asset Processing + c5["Package and Upload Assets
(Lambda code, Docker images)"] + + %% Deployment + c6["Deploy via CloudFormation"] + c7["Monitor Progress and
Collect Outputs"] + + %% Completion + c8["Done"] + + %% Flow + c1 --> c2 + c2 -->|"Yes"| c3 + c3 --> c4 + c4 -->|"Re-check context"| c2 + c2 -->|"No"| c5 + + c5 --> c6 + c6 --> c7 + c7 --> c8 + + %% Styling + style c1 fill:#e0f7fa,stroke:#00838f,stroke-width:2px + + style c2 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style c3 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + style c4 fill:#e1f5fe,stroke:#0277bd,stroke-width:2px + + style c5 fill:#f3e5f5,stroke:#6a1b9a,stroke-width:2px + + style c6 fill:#fff3e0,stroke:#e65100,stroke-width:2px + style c7 fill:#fff3e0,stroke:#e65100,stroke-width:2px + + style c8 fill:#e0f2f1,stroke:#00695c,stroke-width:2px \ No newline at end of file diff --git a/packages/aws-cdk/images/deploy-flowchart.png b/packages/aws-cdk/images/deploy-flowchart.png new file mode 100644 index 0000000000000000000000000000000000000000..9695617c8954f30503cacbb6207386700bd1bc8b GIT binary patch literal 60576 zcmce;cR1Dm|37|2Igyc~%;Qu@R*}7Ogk&W}c2+`2$R2Tu$QIc%D~cYx;prY_d`M+={W;hlHXzmx`{@OoRpYbkJCf%J0)IAPyUlqp>m8XcHNC& z{v6g-(zfA>vl3s3UeucHvI@|t?6b|TP0Pt)Ieo0w4b1N8Z$_IA6#S|-pCf}`V|-hL z@ar}00Y3aH_LJR3Fn+)FEOUc~YFGtP5LR$i#ph!c1zs`1Nv?#kAo-57T_aCvD&l39 zIEVa_OjM`nS@-Yv-0sZ=Q(md9Vtv=}^!u}~J-jwbc#K+WzIZ}?P2-ZPQ8ZnmXYa|i zi8xu^yy3CJiog=LiJyh%SxCCU|A?XlarobT@c)A_l4Cp=GV}p=I{yE1+MRg@MEr5= zS;Bg0(HwRzHPuD^J9_$L+QU?Qt_K2Rk@;OSE{BDVI};P1%me9Ac8;SuizKv!q_iVb z=PW5G^pmdT^Kh4%nQZgYbqu{w5PDISpIGiZSW_h=V5srt&9mwxk0TKWsd|Z8g%4l+ z=Eg`_#TfWe_Kr)!i#Jl^tApszAOc|HRU4JAJnfKXv zgYllWQ+dUY<3zLeN5;$=8a)jSw|)JS|KrEOFwIMt(hM`_rZyiUVqpV55AxuU&+~SR zy)Ey3rzj~0i)Mop6XBWcRNp)=ok3LHb3^E6WM@~pOy`w`?clLop%yF&h(IkYE(&i` zo0*v@3H()xzLURskaSiy_s*;mL*HWG>aOVF)3Uc5E$!lmeKqlfVxl&-sjZsTg?B8p zOYS2D9oK!{=IDH7V(O=+?p{Wd9arS&#&A3F^)cfiT)l9J$|qmq)U=)ny!m;bT2K)4 zz)m6S!){8YBjpuJbsdeAgd`sQmcKKq$PKY+5wi2Yn}5&$sW|)|M3tdkmbcnuf5>;| zz-Xl*VEFFca}i%`p7yO(x%iTAthCai0-_%O`D2jcJo?ho*4B2ND{gO_yl$Z+*aBsRe>f03DROz-UFse1Um)m|_xBl0y^b8;GyG~+Z4evLx zfunDiQ$9R-{Pfto&th?2W%$G@=B|ONg6;MtH}PXUX-djztM)kGkG{tRdsi?I^juvH z8$-&Yqw#+I>UsKk)cNB`>Q^S|s=M^&5p<~V;Lz^D>gRQTtw>OmsBJA38JRLQE{u0( zxid;q64N-?mlHBMfkeL(+clb=^84h+YwM``R8@?OL{>?`==RkYVFr%d%ZG8t<=zh! zT%T%aC1!mydnNW*TJ^_x#b-)Nn8$R3sliqJbG<%OLp^i3b9!=OqUGK1(~_?c)iNEZ z>hSJT+wkBpSLfB0zpN^@TU#_E)3(2tn@aMREOP{72Ho1!zsiM6J9&R}-r4nErktMc z9={Nt)5;mQdagMJL|2-kCpdJ#XT7IqDQL2 z4-R4vZ7B;mWw^A1f<9*%{LugM8qnJ_Ss&U4e7H;Gc)Py>nmdr#w@E#$fg&6 z|Na{lRH8Fa#b&O~s5*i^0~vOsv*mx9Wo=3Jnem z3ky1S<_&kb@-;hqWvfzD2_I$I?-oct;ke{|vaGozskl;;keHarfz!oD?BO5a?*)5% zd$;}?1;w${%6mD~je2pC_aw`Vf8lZ)+iaWvRi2&j!o}&!l#-}}xPhYCCc%cnx5Bhy z_O~pvR=FoC z+SVHbBt6-~l{x_tC2O;FU*?j^aL#is4NY&)7UJ$$ERdbucj(iOCM!LXJZ2@wq_h?- zbd7cxcE9}jJbGY}{Nm*=v5^@`sdlTs3ccg2O*X06wMrg7d9qboRuuf_4@un5&58G^ z?*iO(Dqa-V-=y-Lb~_9M1GdiA=R-{NI7AmMh9EdM;zoRAx|RH!Fy^Ea_5AYd)fG$M zObVS!My$yC?se?dfP%)8t@+`_KAHj1vJ|7O&yF2H1Kt#lnlV59V znaNA;tDnZHl91>URQ`GNu4U;Z%nWCK3aQ)NHV-5A_SH|)PA_`8$uSvhY_!9i%*=|& z^z4j-QI$`3xfy;vzkTBdQ^=(LXzEvW`7gj=a@+D0IXl~n%0a#5_d{N^Jn8#Gb>&K` zKZ>{eo8@Tj6;8j{yMp7>zUFMNR!T-+uJm+tcG2=o9~N2a$Pk=;*xX2td6S=yL|5wQ zU;`tFuPAc`skZAZ8KSZG3C`-+S@EIxT@ReuFvyVK-QAtPae)^%I&^hpP5wUc?LCq} zAatt_2-ogZxE}8a#X2$2ym8*mjxp;SLJ~Q|MLt9djz1rL&0}@`qcmB|LnRjMkX@D4 zNmZ4^;=%%VSJ!#;2gwgVY`<*e zH7mUVUS2Wth2SxgTBA*R#kOK#?Vsfd%&93YcdtZr96r!&2b?qIWe!- zVs`5+alq1$6|U|MSY^lK1DA^aC@dC#knhSBs#`Z%m5ZLh&r?;`w&or%FhhfeV3U}! zhACABxzC;)zZ$C8t?q4Qp<5E=jMm+q&1Q}xM(kY#RUQGSGkPpAxEQP{tr3|VdKq2U zS^I6gDx*qAnLIp{5t}(`GP)*m&Q#8nO!uKrIu}iP&NnlQPm7$2tg;`$#nbazQK-nj zYMTqv6<_Tm5})ns?S1Tv*J{pnolP!=e&fz2{-OLJc>Y;EG&YcPxGelKB?adGeHv8M z-eaw!?UBlTio%(zGJsfgd$aBSe#hBjj`|d;^>g1^K2uW$*tf0~hx?FoX~Hg3qvrYT z`w{Y(2jjEtt;=uckeeWUbYv^L>#tKs`jUpf^?m%-7q_>Mvp$-miuxLU#Gw3*6;ZwV z`snQ5)2E)37rUt`02Qd|x?mpIj~Phgck^{ur4ny!BGIBwyJ#%I;XXIc*G28g%bQNK z-RG&hD^Md9W)`sxyQ?M(bMjyKv@wr^h4dfyIcGj{oLc}$l3L-|v-UCauI-8l=0SCZ z(~_pgu`^Fsm&_;X!6^-o(jR>28{AXB`|JwWC|tVSbT_pyNZ+TmI%4~Kx?B%KHA8(!@#;l&50PfJ$t(p(72dL$Ea6EE@>BCtOnpdX1sct7= zEy+YIbwpfl3162Sefj*=RQ{(T6GH7a-;W>XX{j$_I0a+FLc{pD8D0n&zO=c&SJ@iX z!rqXan({$pYjDv%yDX&_DBT;`un~0Jd#bhc{8HE7*&uc5RkD)kE0mPHD1I^av7kOC zekr5Rl^;IPh}zKj-_>6#c6YM#Ja(R*nil0MRj!)MavS{nQ|XQi&SPq?c$l_V-If1q z&N!kWEj(Bz;+W@My@Q@7cU||=#JtMN zNih}W8QB-LOOBWf;hiSY00@u+vf2iH+T0zQw-f@NCY@&XSOXU%hhP4sfC@ zYkI+9>Mrzr2=zn^&hS{>630OGe9^mO(F#YJx3 z2Jwoj!@5f26O!@=sXYOQ&LE^eHOQX>Y?AsQqUUpmkcO;p(U_5wb3{R9QM)OMag?xK zQqsn8*ThD_cSS=ZVt(GvQj6GOPW<)WnnbPqgl^?+ZibY^-ulf%O_XG94RcC&m|c$U zVs^Tq{*r(ngOJa|CM)H3-TL|$4vh_9%e6Zd&Eo?vU_tC1cJbb;&X>|7@L~&EdK2aZ>N!zkRB< zY992y*~^5{8t1lj6PZ^w%A<0qH*ZwRctQ*zNh?iRH6Yn6F( zbRvfhoK;8Fa&ybKO^EP-dMv%vpUP3_9mbjI7|o$V-< z$S2A=ZDQ$PgJyIREt^iZWaYKWfA{^!OT_3X2MNVX9&7nDHFX!g-`^+6pMmv?vG>h5 z8Fb-C>seY_=1{Mo=4wm+6)(&+T*2*JlzFd1`xyku_#W}v9cAUt58+d$4>Y7d+_go=L2Dy&E>RP}v*Zf0Tb{%5V|4V(BwznbR-++s-d#Kc7FaifCiO6tpT zrh}9ZSA5LVI?V>>W=*$B3vt#nS1(AX{vt$loSBU~%_#g|1kSjp+E2F^k4kjHhvpcP zN&Nd)hpMLST!#b^NS-Z1WTBc>Zg{&;UR733PCG78`N^Y>l$a?)qtX~5^~X=T&*T4? z>CbD-tihT*_Tw@Tyb)87dRd-9H^ zP4!)=a8&aQ1c<%!Vs50^zRixnBc-^9K141e78Dq1C7l0pLf)OAc8a8=uSUtO4N7x= zvV?6798FENo*3d%mB6app*ELwnOpfk#YTM2R8+p(Yi;ITonaBHU6+!Qq#_bik~kom z*S8EjSa=GHIG99y@Ne_JW6+NpSJl-$nK1dgh$XmVm8;`&KuWKt=n}}jt)3TzR@!*; z=G;|UHU2J9SZXp>oS&Lk?U^cylw(>-~!gx18h*?l(gO3o3I&;%=m5&hkhHYFt5b+JhvSfOoYYibO;Z zhy#4=0PsSoUmY9hw8D=>*Rr!uQC|KBB92zgb24#gE99k=ddY+jwPR1oMvTZ%1TV>O%pd&XNOSD#nRzLN~+3X`O1Vd0B~Cl zbBuQ%QxU`+dHj_#HWnv>#-BO0pRxDqy1nuxA~qW3{oDO&@tveR^QQJgpV|+$_3z)` zGS&VkjPLC3+&@T_QfYbX8UDZkqwd=}w(g4Gjlit3KGG zlNU<yxG86>$fa4O*QAsW06P6_a$_LN@AdWTzdq3mys{^*wLWMk zN9NzK-;i{Ct2xq#AD7u*Iccr4^4Z!SOTN0Omh=-dJNQ>;hwSy{ zdelbO(wz6&^HD-}s>LaWLx?xMy8IQ3R*Huzzr`m%QPb?}jnjUpG4Ok_?JP?C@KP!u z9{|&B&T%6@+obN_ha^p<)ov^s846Y9{8U1AKBKE2&t2$L+q0vkn^q2NOk#95(Mv?zpb!-9f>!#LSEzE;`-3VN4H zSV)CIrr%_TSg?Jtty$GoS(XwuTTiSO z(-w3tzvpE2(&LPqA%qls$RbU0ub98u1<+L@Ug!(t5gi{rT6_jKXDvtwk z*(DshA|%(bFSnO^ezqlDzlKEfWKr4nbtftsqp{sRy%d&V1=)wMHjcR}NDky=<-kQS zHyNs`s%pIz=~^3sMC3?c4g{wVSvyc(`Ier<^SArcsTCn4MJXcB@9c&Ig~&O@IB)(G z#|DOvkE^&w0?oRh2>_fw_jH?Pd}~lRPAC~4#LeO(&JZu67`vrEQJaZb9D&^iS9i2a zLUVH5P>S@FK;EG@7n~_$<>xxew_c81`t<3u=8ub*#Mlpy*$DH)* z4{I9n@?yNx(&m0hy3vwSN7A8YZT52PSXqf4`n6Zb-;QW06vjb5(F(LbY{qBpZWPoKiSyp4@++n%OMXTA0o{oKmSl)qVT z@s&5qSl4bw^0e#F5q;e2`dQ~%Ks}s~KoZlr;W54;BFY-d8_)S8T@?$^wm+QHoXv!q z`r7rbDedlgW?ciWL}wLiCvr+ka|`vvk{DmP2aj0F9yK$Ncz*nC2$|X+8|iomP(6T0 z#UzU;1jcwe%v@lN2(g86Lm*=qN=t155Qv|o4Z1Mm|JRxW!BEL;XSe~yT6CJ+js zW*4IBR zuCRZ{;l)TvUvP`EBg)Na%I5w9e?@el1x_yiv+-lRYGWH)+j#~&M0^s|Rh*gG*nC$m zA`n7Eryt#7WBboX|EF4zd;5i}x846ceqwU+KjWRHrKH~f_aiYkoct~lfuMi?pW4h? z#5;V#KcZ(4_hg{5vnT)R75ngY1j6R>zeOgf=L*!OZ-h760eloTcUD{ zw{OQg5g^?CK`hoHl9O+g${-MPH~&)(b8nwpTZ^{x3CKi+utAWr0qGqtt(& z%+1aHpNEO5sH#f;_ajI*An@FAh%ui3UKQhn5J&_(Hm+v75APo0HdI;WWAPA`t$+W1 zA%Co<#&Yc%#s$(iI_35fyIKgu^1E#^1TH=`RR)eiG$*H+`9Q%#+a$3|v%Df#fQPH` zF#h9FwN=gqsuh>(CpQb-SJeOK;r!0JZnzqb*aOFb_r>nrm{OKAh?gu{ZWr9e_bPEm z$NSGP-owcwSaQOu%T~(2JdHfrome|XX%P3K^p5e}$zYJkq&^)bN>1T!c;w3gg#~SG z&660jmfFj7-gpR{CvZbYrd~$DT$B>EGc2MvaMLQl@b3*b+{6g6irstw1gQf-12(4rt{nwyZ;kyAb)Il@cTD5oPt4$E=-2dK zJfj4{Jr$T=>=X9yjos;u*ROwXWKM6eJOAEXIlXx&GvVn$fQJ}>0~VrJs{dzur-spn zli?E?5d{I_B^HO6yDvif4{;r5kMTOx?M40}F8=HRe!R+>)W0OS0Htk{N&l|h4D`_b zvip|{{IIsbN2SSs9+WNNhIoBJw}H?o{o~AxRVi$8?$zm3a`(OX%)5Qk9*BF!k}$@- zx{mOxp2v_9SQ7yRqdTlf&-8pfQ$G_L2k2&`Czno`; z)oGFD|89j-C0$uNTG z`>l6?;_1$*;>GW!!CXq9HPRD@7=OPvb_N9a?)hUp4AFWGFEDkF2I9_(6Q0ed4@1H= z>4Ya0{QV{D?dREbiR&=_dxH2qZ$`0~ULZF_Fy!onrwqs)0!Ex!uTi04Zp^9^DQ&<* z(EN|-inm6K*@qZB`<38+_u@G#U4iE>+;~q1WdA%ML>7Cop7kahxu50H-4h}hKAB5& zhVfMgim{O)<+8jeN>fF%%H$PS9U+;9Np^+FtDI8Djjpfu0ef1fE3DM4Um<_?#QFQe z_l=sx*No@xA%VKvxswKi1frTe9HkBKECnbxaIeQSF^wc_wQ=Wc5}fD|b2h-2d){QO zSkU?ek4^D=9gJdomlb8slHY<)ZtjMNUl-fELP2oP9+>tTgivHtpKii42Y8AlIKU?$ zphOjVli`2`jHAwZCCH(yZTtA0v1Ni&t_$P3!=1qov z2iK4s8Ivob*d#~N$A(f;+Z?U*>+&uIDQd}Hw@OYk5rz(-PKx*_5uoRJ)v9tb4G z7U9~ZI6CJ)9uop5%RUn>-ux3{7C z{?U7_Nu0;j)HGN>2{l}CEVA^mxET8|JbO9H{L2py0+qX4<_R*+EAA_K$EA%nKffb7 zO1{{TA=b?4)c0?4-V!NvgN#PzeA=CpmHh=Nqo;+PAt|p7+a~^LNhmBVR2Yfc7aKnI zu(tHXNh-8{H8kXm6CO?qA9aD_;JD2@KyxtOp#?TjOvw6XVPS{*&3dz7(wLQv!^LJd zOs5KWOh{tVP#ZNQYa+Yew$0|W-3evQ;#Dh`VbspD>$F;=*(D6=+2qy|x_~ZayuFJ# zN43a!!D!K?H*ZF>%asJ_XtK=DtTn_gR)OCerVI*yh9P^;Ni+o`) zIQE&N%CHiT{5lR6bcpFGhncgDRfvFRPwl*(#$X{V*{7bLAitnq?K zDU~rCnsjd8Cym`yR@QN~+4Uc8Xy=YlIEoYJ6=daGP=~}=ihmojd3~w&=JxhB*H1}Z zmO5x;*j`8y?|yZ|vnC$W|JnXX*XY>DKlyfXe}X4wVv92J{)`TWkW@ysaxi9#rBaT$n5wZshZiN*@PNYK6lw$HGT%Y(+m*$#;Qu2?^=h| zs1g|&(E}v~FA{vXh|;V8+Xw#)o<~w{2*QG za;PkB;vP^`?x7ELXE zKZ<7J^IO>f?)r35?-Z%U(33@r<|OvMuh*v^$c?DrmOxSiHebZm$}{H|BpZ(YAo;zX z3wvG_;hvgvcXh{R23Tj?`tP zrlst!q7BDxtFW4wKph8|^2>Esl6W?~PFnOjRGRbSfAie>qf>QYJ?sO0KMTmVY3tM< zE5ahry{+E1E>_3Egi!oOtrCMUZ+&0Zim1vO1*G`aB4H%HZa%&irq zx3o(~%IBa?Yg;cTt-3SOA3|0>bRuAr`8(zjS-JB{H)Jm2)UwUD<1|kljWbb$uDgt_ zv@<#8!x#TACC}Hl-J(J1X-8t|P)_ypE#7w~LH;ZVM6~ml+o7W=ygh~)Yd=~{w|&>J za@&WkvgXR_S^0gdm1bil&!d$~nCv*ahyDTDd5*`FqtA<+@FeA>@9qXTjSezEzA>d$ zJ1stWYi@)d}D5{!|d(P?VUZSXNv zK=tN5x(Ijg+O5qQ%n)L{-*Q#ttY&0o*&dncg2Lw#_r-{=u8O&ak-u44bEWc?GLO$r zcd6&!iyL$`U{-3y1qNL`#>nLCG9Th&11Y0^25La7J$=rv)F%pv^pNlLgsQFT`T?Uk=#X^0U?l>JMFdS(PXP5%#ci=iCpL8Sgbw7 zll*iZoijO^af{7G#Pa4%R+p15k<+UDQcn>IjdgkXVOjE^OwHSSimJ>`CqOQAhy0qM z!UmQPrCdra>3c^G2`1;J07w*-paybF0^W@~FH&-p<2V~|f4b*QjLI@7-Bhy*|7bZ4 z-;DXkx$n{D#t9S~Bj#=h;Len%{fH&U)J0sQkZ)tjD=ywEr7!C{7MX2H5M83}>UxYs zH|(w)wTDqqJpKF`3cEbdC{JO@q5Gr1Xp5JQoSG&&E~=LCME0u%O(d3F zRiU*{97CLgzg>?R?0HAF0*UaP{vY|jtkPr#+;+jx%rInSWj$e%j)&qw#Rt#jK&Dsb(BJ6x}-gc|4pp}n<%)AV;d@#X;96T&YGV4>IAm*CJiaq2 zEs~Y>z^?6RNb9sr`$|e(y_SP^`a!LMY@+-N>(hPav%Kq`=faKX$hi%7Oev;4O+?MG z&zZg4+9vL~*ez3g`)ZxJ|GS>CUpcghHAcwsFc|R`M-9^9pYx<6dSHE_d2A2IqHtoB z*8gCqsN0GECqC*9O}wk_!aOZBEIw3FG__Gvvn9bac2&zfefqRpF;Zl6QvJarP~>|C zmy8NIn@qJ!ZPfZux4##EzkO$h30>Fnh8=xhTTT+M=od2Dq5Dmpo;^aXKFz?WhH^o_&Xld27l za?8X~tEt(3P_;cQiY?!@a30+q)ZfxYUicT9QMFO!*h1Yqt{r~uy$)?lmp?!Kr4Z4Z6dqeuWc%#+ees;GPS5?gH*ZnmW_MiwJW|Q$r zd<*@%;;lTiqB|;YRlipS?EgIvl6@X6b@r^QorqVYUw0QjWK?%{cO2uwt}$^O3!xRu z!ehe}bC`7rseEn60u=U3;@;AW8r*Sx{N$PUsySJH=OpwSR*lG7>D6TH^SD?#eL8e4 z1@V-@-DCA8Lx{bfoj z$th~+6BEzb`&{#U&wj*ye~A@sxUjUZ%6Afr>z~rQ&KzQr@4C6KB13;NAcLg7ZTQSO z$8*=O8Q_PnT2@lnYrcV1-LjWE=(1KX?VJY>9`X%*49=k0)-hUeS0jXuxVFK*vCR-sK%&3r$|XWLhrzDPq>a(-3P6yC?Q@6_f!aep7V|Ml@9BY>r6iQC>NTJPKdGic}#U$%^ zjJIJSutiWQ2IRFdPNs4Xh3{2Q2M9GaZUqu|mYFoJOAPyeqDz(z=+& z9jD(G?fG*sY7#~bt}l3~?S4C2;3=_cW&31h@8G-K%a>`szP?~k zA*4)5Ko8@eIqjdgXOEUBPI_-G_VedYEiJ97>FKPjEW!&{?~Q)?=N$=h(+7cVy^)s` z;F1Ic6^Ob~|&;fK4ctNr;6H8pxid+Q1o?gaDRZDr*L&EZ_yT3XO7kZ05^ zFE4+J+fEaMSSc&3+?bdca4Gyb`@RGwC{E`ea`N(@e0}ANjK0G9>FFlMB4-h=31P5D zSy@>~NEd8ZV_%N={2$e!qvs`m|2|Vw>&wgIh8GNYc=8opH~|sDMqjI|tGnU$Q!6WR zt5qi>DTLP~Gy=ku3jKV2t*xwBIXJX`yox9(5wwfFj1Yi?rN>g78*Y7PXQaZZC@4r- zn8BaGghXS)lLL*esjvTFYhh4mXe^%Q7ac>a>2N5G+b&Z?*PfbmNaeFNNC@n>@ zpa=!(m8`5R9N7N;KJY({9Kirm{%&KUo>*A8Y=3i>OQXQsvrNjvxpmp0H=EGXo<;0$ za7YN3PWj$=t(Q@An7W3>A5l`oU8s_H7>riBP*YQrl9EDtg>F=kA{ia)NA_cC$`ClU zwDgLWmi7q}K?b_Uh$JP&ZMKWUR>ZAmTH2hbZXn<9PI@l4M)3nR5fKq=YT0!csS&Xr zI0Q~rO|8hF!GB?4VYtjrPEO8lrwc8ycT?=|6sDLp1>FP3n_39BCQ2>ct-CL}zx%v4jPo5MM70u%E ziH$whY@NS<{ra_}v^3@G*Z#kM@9t9HLsXxIT$nh&<%o#WPNt`4t@p+2bCD8%Dem8% z@LXOVENW|OGchsw@#6=uP$OR4J#K1hicZw=iIkMl=1i+i`?dS$uRUL{35$(&9sl_r z$~V9Z3x=QgP)S+4#Lv&Kq|{#Fv`czg#Zt$`-M--+|BF!5(XlinM8(wf)-3{e$gWot zp2~qtuXGk1Nhj`* zg>{nr>4mB2=_~A3brckEd$ybp&R=U;ui04{7B)7XEwUV)a6}_wpmZSOb#OtD?Vq1g zV-wn%2jq1!lE4w*3rGZrmcg%2r>V`FcR0kzn~A!Q@O&UHEhFQPsGQT9lLw<%WN2jM z!qimg=g)oJ$Nt7-ow*VQb%V5cr`sWH5dCHfA5Y2IVvkOI(lhoDLO9B(!hY{&C~;s zl`*wBvUv5EFXwia2l>qh>Q{MOW9@d1#E-~Ih1pnPCwT3SAxu1$7;KUd&(;%eG2 z`S797in>66E(O7Qrv+4_6crVXjEvy)nVFfvxmGK6pzZ~Xjg5g|fTk+MibSla3te1g zK~5xruueorM}v5{9<9q57#N(=K?ZcZi;2;elB%zCIfO0E$A0Zve*=^V+~nkJ>+B4w zdH#1`fRyI0H&9|ve}G?n>-O!}hdax_fy+xq0n+w7u*Vqmty@jMf6G38{0GSH=mb9hRM6v+99_;^Op zSSepBg=m4G74?_3!sk8q#{4@v92-MC>`<8hYw3a3`d8zu-5 zo#+nyx>U0Dd)|M&A}-4o7=D>HleK*sj~q3Wnv}$&_mcqA2;8B#bm?$=k%f&-Zub#l ztM-7Vf_wD*u60YFoO<9d$}GSKfl~DXp0e+ z0dAeXK-ebmcIoeYS89%S8J}4%J3N(E3$%+cAd1&a_1UwlA-@4g*jigBfp)D(xZRWa znv&A?<&LC+LTi6N_@amvt3CNtW~jdCvTOceXJ?1z2QGLeXk}&PR8&dqPl#=x2cj7q zs9NT;goJmxmdkzAtKPtlBVuaJ+cQ+)0LtC&u~}7;@sahwYClyn1qy+>~Bmr z&&NuUzvct^bLJ2iAMNbCBP8V5lks%20W$J1{vFPJXKigwzzufbXj$ybp{J*B zZf;h~(%^mB!FVdJSGNcYYC>3)ewYvL?2fucMMQLp`c^MIIGym+#%3#m#~4&iHA~|w z6rh2lbnZC!-n^os@Xw!zi>m`3lh827UXf-Fw0;@2}R5prSd2~JcA9sb{vu8Cpa{rIs18um<6v&?$74MY*d zbYf$uvuDrxUg3gw#y~k9J${_%M3>OjBo~4f!*+$TsxXMVvR}V$ps)XCf5Qlv z@DdQy-Q^lj!p+(C(L5txKR*(9PL3sbYZ ziHL-(ChETH)%Ip-vT$%Hz=`-Jh`SSZOzM?Hee=7%g}d%kO6_-cNGT*iqF=Nl`P8o%q^*xC{SxAXMrXDqhvmmjThYoyff{c2+| z(5|Jwxq#=l7yD?hUhNPiMe=TW-3B4e$;uk8aN-~Kyhq#J(*w|G6&y-;5dekCH`6}e z$gtZ9thbS*EO-dHkio6b5cQIDlPpB zu1#W)dp+?IoUDb7r-Rw-GL6Q zLn+st(U#oQ6{@DPa)o8koh>yr(&wYA5`#}`o^H~9I(S1#Ur9uXN?T2{6= zKd=7m8F-`jD^~Xc6T}I6!MHtr^5lob@WWl`xG)Bf-2j&C=;#QL2;hQDax9hrxSU$OpIU7M;S(V#-Bn)G?t^XUt2s+R2uuxy#_L}V4Z0PMlmw=ha=CRih^RHUVt->A1sjEAjVo|a)TBrFi6$%Q9 zouz&r=e;!&TD}fZ;;2gYc7b9CdPqmLR;ZlCA`-?TCGAfqyUSQD`EQ?Hd@C3bb`Fly=*YA?ZMr!eB(j5S5mml8 z8|U@|5^Bx}_valQ9mQa^ps_UL={GT#gZsMz5bDb~**iInmRP5DrkB~lQMw%RrN-(* zh%{Jax!RY5N_~q&R1;@rWr3~~zv}0$I;h`0=UxV=8&(DubyVUUc^V@*WL1eQui)N;#9>~gq*?Y9=5(nN@R`xfj z$9XjD1|VbA(MB_fdF9CLK%v=edz|Hq7t#%61c-b1KrBCh5gdypK<5+Oah7vvP*5ju z8lnRbP^h{F2j>BqK0ZX?M!<#wBstlijg$OvVLrM)K@tSn6}%}nu;-ha+LI@l&vHF# zo<{>5VPP?bkl_?V+1f6TR#ins4T3!d!+#zPKFZ3@ZWJU3EI`#rR7}h;;3KGPFk%5I zoQezp=PQ>l7rZzGFF=6-j{qHt4V92>+L`(t0(i%`ExN>heF8!kBsx_w#0*IWIdEDQ$W1l)^ekwva$3&d;+3cP%L zy`7y2y${Zj(tY{-`MrvY!=-~H$uu_Q$1y<>5wb|xhYttV#DNz{!9(5MHf_;@(1&{J zcieE!wLC@V(Xipb&!1!XEg4+I;cHTk0W=&R9bqt-Y^{=wRzD7Q_Fn<0)rEy7F_+Im zgS8MKR*=}9_k^=(i>4VkKkN4T!nOk^P>tK})1@70dwv^A5n=2R0#=ET{sR0_1!Co} z`C?%Nlo`Gu0KCGVySxa5<^J*RXaK$N+p+3*AVELMr(tJ+Pr-Cby09@ZNg-J|IbT@b z`|MRvV8aq{;j|^xzq7mh29|)3P)$vZhlUZ`4d15F+Y7J?e25BwBq4gN=q6qfwYK-3oq$Mn@vqX?Mj>EPf1x85?K;8Zz^}1M-dj;P$i& zUMfRGZCQ2vcD9Y)&d!dOHmbV%9_E3T*3d%FH-G>x&dzYMPCHAoqK05|PD3IxQs;8dKwxU0Ck9w$d`Kgg4Q#S7U{5ox~}{0Yo3F}l#!BB?(<2` zc0q`Ecg{)5$Mb4brYLA@YwPJHL`Q2S{kX}+bp>8G_PN2!yA2A}9LBMDq$kmF0VO5^ zAuW8TO)(^33?WsTkdOe61u&yf8Sx`CQ~t@5(1XFxr(ZGRxna>9ply!UtaFqou+)+|6Pr`df^xJ@p5o*7}*JUUO@7_4>+64ueyMDz)#5gD`vl3%*S!_5tengl2EF=#d01qlid3u|g>`Xh>5 zD}r<*bV$b&hWv(CK27c4-x<@LBU=Gn>l+ng z&GPy-VWW!*q~F8C`+}~^2pL~PAZk*9H7?_0W4B+ARsWNQx>$hf6)!dfLpOTF4qry} zl0;Zo7-X5wcgk#z%;FS!mpg0@L+!Cf&C-<$;T;&C`}Un-77C-~B(ngqzn zB*~CL{;!nq-CK;CjSvLHlx(UUqR=EAub%%x!N$f$LIMvW0H=6yAvJJC`uY=KV&IKL z0-4%Hd3rX%(4_C{o8(0Pl6FhR7+52N3S! z?`~5_|8?RDst9j<^yu=CQ$brsR)Hzy;t$fH#Nzt%KD3u9jeb)Ek$7APVwL2(agTzr z`f&Upg_YpG@42-jw_|sHmRYggl-F_5CI$u}K|wY1Hv_pmHv%k~goFlKTm8C}8Ik`F zU4I!>RoJzE!wUfc0YMOuMnX`e6%eJAE@^2*N~Bb}L8U=TI;Fc)8l+1?KvKF}x}M2( z-S<2G?-L9^IQE9M_d0W)bN-HFeF|_+5eo$3Ytj04d!+DjTLol_^xwVfTw%gT6BZM| z!t#YEMNZtqne>~RGqbF$ESy6Z;CC@oK{L97k8ki6Mwp42+5G?fJrBg<9&IVLo*|ak zT>4%FQ~8J_L*h0gMW_y^Q?Sk#!W{^R-}Bu-6Aq@nMnXb@hllt7dlRx6DTXg^p$XTK zm!h>7em=ph^SyeFUl+biT^8iA1s!(3`1@lcKYsjxBNQAz;0GdNUP`iEhs^W2*uOI~ z3aYAbGnk)f=>9;rhJX83m{{}>&AT}evYmq;?xKF$4QhM^S_|0HdU|?Rgs$$B6XFS2 z=QcMj7HvB!9tibQPi4*gT;`|3uT?Uh%e{77~Apf^b>LTDA831baL` zZu^@e&jb~vxUbiQ@eSsok1L9b8eJC`7ZadrLrqPc@%j06v<2$VL2?;k67m<1%=}do{ z;|>mIbobRTIL@d4_9Y_z{aQ6Yp%Pfs6J?tnyroVOSJ2F(lXcb9h_F{|d%gh=pGe67M2wzI2+0e-3QU)GWME$n`F3V}Edg>rF)?J~bkD_T zAR7#AM1#4j`~6IxU0qX?D^}<>5s|_i#x6^0Murt18eIAE23*+;b}KbPA2=~XQX-@I zKi~elPtRE-x7f)3P*5DEkx0Y+@<3aQ$lNt<>)I%_#+A2T%$h{Ev`tW;)2?oj*=#px z_#l6ps%}n%oesU=R(oUbD4#o@oHwUdd|bBYE*^Z?t=ztS!6S#tMY2xU>DTyZik%%# zR9OBqI?#^GPr3!s9Cn=UnYvuP_pBLP;Q}trIs1JlGEn&;?Fz1IL5fTcbaMP zPCxXE_0JBe+3BmpsF!C=XBTTV?>8p0ahdC1 ze2Iz}j?hG@xV~oHtev=L3DYt7d%Ew0^~SKuFrC;*YpmO)w4B(c|LTg@W^re+SGrf@ z&293gHx~3f2d?)|RIEj0j=JxcY#+VED+^Ky7jPv(M?)(eI@Od&&i{T<@}x6K#K+fx zXk*T)@%Nu_dKt3Zu=3LKXShzB8djy>6Z&8OK6XhuxN1l}qsCm%mzIK0i!M{Ucq0RH z|8?=Oe&C}u5c-rLc+GwEC`vfDq_FaDQ`w#kZnI^T`OtrwvU~fl0~$J7Ag;`#-(_!f z+r;Xei_DvCIXx*7|E)rsa&YYI=(m9x4M$f+MMWE9?Sl(>9Aqper6;h*NjWMZTJ`Mv z=+6cbQOUBp?{x)^#UD!)2g0fOKShcVQa6jJmT+mhLTn~XVA#dFntE2it4LXleM+L zVM2o2?@Y`k`((O0`V?L%jEryuM|?9H4vq;Kcy6wsD*vI-=I_#+<=fmKS0Y@*Hw(+) zhPtFM)~U!1e{6!m&>z)5{@LJ`J}!k*Oa11si_(7vDrtUU22F_2{Oqhok%hzHrRD{j zj^Jfmwhh;$5sHwZ%EGXVrc{@dh(z+nhPg7C&E)ESSlm4><_@RC3cWVR+WwRLUJD4q zTz(U7&o{0}XA}*UTH@5cWl?$@Aj97Lo2J{zB(_M;N2=F!wagV z;l5n$Tu_9*(EDk}R23aJ#(S$CIrKN8ay=gG%a zeAUH^Ij7Ls(2?Gw8#gdr6~6Q}eMb4avdE&~%rlKf+9pUtRX4hi2o_{i3U-hmd z=84i$?&KNyfy3hvau`}cn@?^c7l)QQKW3V9H#&Qym%i#GJqm*{gwU|w-8A3SJmt7) zB(`{;v?JEm+#urT=HAHU4@+3NU;j z$p!LAqsm@1q`;~TTKm9que6K|8!@p|+_%ButL7_`T3uZ$Uq6>t)cQC*3?aNT(ojxC z7H@kpaQ_Ku)m|Ix?#|A}_C!QzNHP8)`X4#hf2`Hjj^|>q&1B3b^bB zc!-Y4SJX}XcBLG)tfaf7(q&`n zW<~_D{jrzL&DFXF)5ry2j!nM0kR!M!`csVJK)`;bwZ)v=cKz72?}xdYnO3z)O+2A( zzIY!MO2cPUk58XI6%fpoJ}#@@{OV%*_6*kScJ?{D5xbL@gT(nUZcqObhX|dSdp<=* z|BSA!-JwsXPc=yO@%2+QQRYm``ccluKqo3IiYqOEH2nPa&D$H}G+HcUgSRlxcf#KO z@Rq_Yj&+)GFvrM2X&C`-P?*0Ivzn6mHb`DL1@#*~(abd4NU z$imfPt8hssmiYlK+3~KZxeE*O`ds*qsTH|{x&y^cV^c$HMCCCx3e9|r6%xgxFEEVq zJu4p_;icGIvxtc)CPOl_GB1l9DG~Ux|CoZ~LU54Yn}nWdp7!?k6Zd5968MA^u@$!Z zCN5q~42%)nqU`Ny!9|F|iF9x4S!>-!0?41rsVj&o$nAV+pX=?F%l(aJN|t4s$;HJP z32sW^5vcA*sjvPx{8`N=QyUZ&vF1fa)kc*^RF_B=nLC(oVf{=kH7I}efSCas!K0c6 zX9+UPrJp@L=QeihnlCo~Ga~|$L zwtEG+kL`+MiPl|q=9~WtJ#76fdo|8 z{ct_iXdSm!dQrj=QI2iQ_G2FqX1^!cMl4$8udBXP{!FMppc1foyRoQi-fhmEzmHEs z$oB9)8nSMsH@mQ)@08Dg9TD*=V$#8W2^xCelw0O~+!6KWFwYl=L`aR`AjC^~tx4~z zew$w2p$v77AQkUSR$f-E{v0d%6VKQ~3#~c_Ebr!>ogGx67y5~NW_X*=oHsj33-)yG zd8L24_Q~Zpp;mF1-*1HBVG!N-+eiZPpcBDKQ7ufeqLTDnl^CEQQ+wE@%4d;QVlhf0$qFb1Bx??}RL-ATP z$WjoR6BXsHSm+Ob+%3a|o2R*f{{n;7pLpTQZd?jj-FSBuxso1q2lRk?olizyXj@xP zfP0dTdG;PdnOdL!cReu!K6$K~#+7)HaKhZt@tzQQ3K}LVi$5^mWcXplqyZ9Gw zV($KeWUA|ekA`_}24S^P?Hzj_t6gu7$SH~4ieG~;bPs#a{Gr*DLH$ZjYHi@T$|duN zg*Jpxd0bLF_XK`qrb;NtDcF6ZDhb%4)J4_){K~hW@NOd4gb|AS_qq=f2JN@DUO+Ba zPtWXoZsteEZSFv^685qhLVI$AxbGMXp)jLN^u+KM^}K-{Vlh?kkw;%{@%zL>`n2ty0Q_|q|% z15+;6OOvP17%`S6?5etJ-eErf?}B;#09l)CpkZUKUtRhQk-_Ce)!prm&*tRi{=p(e z(a~MR4|R*)8WL7@v~A7yIJv^wZ2t_;)Ep^%*YS?l!+!psp1R4Oy4C1e&NAPL`OCjX zt~1p>QJ6uKEQ4kZLm) z<*&_0=OBr~#)MHk#Zbizy!eo?5Pw%9o82ZXv%ictM<3-gF=tauT4~9Nv2r}#8OzHN zWf0|F~V9Wqzt4!IMJ{ zEB(EsrJ(YyX$>{4zcY1zdRwW;_1@)Le*F7oDWWzu{Ps8EZVibv1*<))>jZi-&Nzq+ z#Zr@FV0lD2f=^63Hax{j&tyG6^qr8TCbuW|@@&8F-p8=?n8lX0CH~q2Y-}t`^$Iw@ z5Zv`mc;c*TS?c!-l>4v4x&K{P*Kr z%2qCK12?xk78boARHKJl*AUOGkJG92G3r4oil>jra*FB%1R1+N=AxFI?Rg(QCB>&Gip0<)Dwrjl8lV}i|3b9-PP>0GW4Lfy}cd%5=*|PPo09Amjh)? z2xxBHobMxxer{o50-oJZBFTgz6yWzyCQi>n{!EiT2F`!&yMx(z(#GL%g6MkUl# zW#`3&QSLs(;q;XG%gD}V`}bDyZz=PI#YLmQs+5$^Vi|hW!a<>wlpEba;l7QpgYO%J zvip)YyWy-zZ&+cyHA$j&IptFLa-KOl#XESp%gw+4cUaIw`N3ZM;AsW_0VM=9GZN1V zQs^wSc<1K%w0%TY*Vk(tb{?i>nXHWMkLE~z=(o$)c|@)6ofkQxrfawI^A=ZZk%bj8 z#dsORz72(k1R6pX{($wq`O>o^H}`f~*>FSZLe^0#@M_7xJBvT!BttMoXal8O?7Kz| zC4at}#~)R{leiWlif_;k<;3RU?S?wy5`nb$ym6JILiLnIdB)Q_wcm_7zxgU19UT?v z(UQH3>8=2tMo*vpwC!ZwcwDB5SW?ZPfkE=zEN|cyKR?wTR5WsN8D(-0OWM@0Q{B}Z zRV>Vf^<~tRk%R`ERiHvB!!Iy>d1t_`!Q(6?t?C$B0p)MQpRSaDIAhEI#49W(s$DzU z*0v9t8SC7hA^5vY2%^(g6UA7O{oqVxWRRwxquL$A>2%ygglf=R)}^I5OpX9w8+`w>XX3cu;evaa!89@Y}L++}Nhvxq10gU;VSP@WyR4^U=4{otT(xocHI^i6qee3>l8rp#IZR{(CO&JSmBsDBXFEYh)0HF3#j z&k!GbvPXKWGEk!?7hhWPI24G8?0CRbF3)7CNPt2Ey&mC~TJse(pf8K}e^~%TAA7Cz z%PZuyg{ik;RtoND!P&G}24hRhH)7(y?|GTMKdfpbMkG5$#{V9Y7u1+$65vbDE`Bbl z($nieP?DEhTg!j@H_^RcgN*x@Z_#CMK6f8KB&CMw!a=UV8|-F~mX5gpz8u8vuIx}6AebxS_NpFXla%UW z-wPV)XM0Y?|NdiaZ%Z9ZeS-Xc4fGR+1rJf=VIVIzC&}_GMF=+jkhfXSj5bCU8jtp& z@D!;32^z22VnMTVU%A)NA7$5DQPY@ddLyO zXLolz@Y@NWB^0qcT%HoXp~VuRRS?=%Fvs0vK(^J632iM=Uhk}yagnf~yVqHqA_C@+ zV7~c`O0b3#FQ7E_(ONNSJAR|bG222~3%!Cuo!eo)ue2npkd2|CprzS&`I^Hm0;0(6 zAC7B_d&{WCY=k~P!%pouF~qE`OA~kSDhYQw^^$YK*8ZKvRTwfP4j%^MI>`|bZA^;v zj|~uz-DaP%iP<>9Lbf?+ZzI+?vIxy%ftyI^?3fUz8YJ$F4ub*TYnUZ8(Z+q*>yqBC!~sKIJ?pL_lM9}-S_ilN$luE zzkM=-mLHKJ6IF|0k^4rl#$DXysC%g!r8ZU=uYOTfgM)kFI8JR!3y8PSbHW=luyGQ*p zM&!?nI0ctBzGRg+RuKLa_e6Ey;58N{Qh6epR@jCDr@oq+8vS@}7^oeAfjbJf^y9U1 zDdP%RqXJUV5caa-mR8O4;wk;+{BseM#_>otGrP;Q^z5Zibr5TRe_}E4E%~fwgoDlJ z)2FMC`gFWnDXCOdRVA66>}3>z$iGsW6w46Au9PMqvWe%XK5hEW{qE5?som|5ga{@k zR#C0COFYl~3@Q>;^&V?DF)cH@m2aKIUtC5DbemYP_JaiYq-Nu{%DJ;zdj*$)oz+!X z&3p4-eLHg&_!=uaGpWd57%O~hJ>f%^-7cgZOt83>7FW*4bK9yf>iZGyB(#*IT+XqE z<(879V`f$8gg266TYQP=6Lk2#KU&if_Fiptg%7kaqdQ&+W`k13o{;qYg1;nMLxb)-oLV6_IT{XtBE#|lq^t|K3yrx zW%9tn_Vg(Z8vl0nfTHED-0 zLc_usbRM>$i$RQVW@iL#M1B;FB`R~$FB9-5c z%0~h`)uoy4LiAMAwM67^un-QtKDcw7?uS5czsHwUR#p@3)mJ{?9Q|Pn_*HPTVCwVy}?{i3IDL7uA4OLXQ`%+U=1I_bGKzAPU z8b+6zMl%JwsgZtHuE&$b&yBB#RNdC&pQxyO8_ZN5`LkEHj|++JvGFlAae+SXF=u0RS{!X zo#O4~uVJ3j57vG`en(EtmJ#}tF=S*-R2WEu;vw#+H6F858_#{;r6Bv&*eHgdVhct_ zuPq<3m;K`6kd_WOJTv`V)?5iqF}l5k(W}$w$m%#Zw^WhH{$#!%6)F69XL|1Ua74s5 zBVO9V{A9)E8v$8{w6ycyL^)^D#})&(;pzeNXp6-eik!tT>e4*7$}XlyN=2Cqs1s@Aj3&y0%WAUP!!W%QvmQVjvHzPJ47Syh{O8oN8`Y6nM)S4jI zrtyzC-$6;>XC)IoVVTjA%-{^-@&ouM`GEuKW&ob+_kGXFsD0CvkXH8<6``|Y&aFj} zrg3!h=P9Ei++Fs_D$7$V@H~d_3qiz5UJV!Q5|`g}U3w|*EkMp=;^+JO&b5$sKEu}D zKMS=rv?WfS&n;ks{5LIy%EgeY){`-dIY;5UZUe?72EG-Lo~AEmdb7 zT>59FLuZxKa~hPZ~W#S3v*j;;i39T)qh8g4R84+_AsTq(tc5(*wY_t1)ars zst0rb0%U&DrKTgc0|spZyLGzAqb;!2izF z64Icdp}~r(%G^VbPgb2qhlk5QPVPcP{_Bz1fmP z_>Z5TAC!DizMZ?O;A#QW_wnN{a2HQ>uy%h#a>{kG^kl34;F{3CoMoS=?Pw({!?5O`#9&8mHNNM$FZ0(%@Io_)w3AcjiO+( z7_tj#3A*bTt%(PqG1xgRpM)5MqR!ssG$gFkfNxUEn3-gx4BImf+ZL~%S z2?+q;!Arp8{AB+T8OR7soO+`J`d+C^b%q*G_e!i zn%X!0oi&FJP?|~Yuh*r0toWh$JO$$!)wGjUM1j#8lQ|NK`=f1RT9{2=+U6YW?LlP< zKTw?pJ^}a|C`qHx2nq`F^T$i20oVga^WsSYcviq@RA{K8jt(n5JyfeR^3MA#o`M7n z#C#&O{eY%woD9_C2o?IR=Xj%euX-4tH8~ za#lL&E%K>}foD=KLu#hgxpCb?JXwkainiPb&p%zB*|1!yeOQ_?m*NtAq0-ztmQd!) zz(Dte>#5RnnNMY=l{q=gEL@M5wB@XRh)B!!$ZorEA+H=YBN*W?=pDwcd!qfj(i${HZD-oFm=LLi%Af%H`jP>j7x&#mj8QJaXHRk68=9ZQz1DQxtZlT`PhtVgT;T;kXA1r02YHs_pBp58?GH2B01Cv27)heyCPfQL%M6MnX>gf*v2;=bGKBY0>r+QO$Uv3uU-i`0dEt zyn_9m+U2Tq_aYB0-Li`!0EYd z>y4_#Jw!g{eyr_zv~Cm|Bi$=?6)dEl_0oLm-!T##mr!&1OYT8nr}K*6p^8Jqq}A@! zlKE(nj%8_GP6@f~9^2%$UY+B@Vw#mWn}n3aVolc*xR*!kk_wWy5Ht0P4QW)WVlgv7 zB2Y!{h0)Q`0VF+L;{ekdG-8q2# z*vpqMfzSsH6x03t&?g4Q#yQ#9Z=}BfLT>NqC?zc|=yLL}$rF2JWd-nUEF2seDX9|x zJTriedd+@zehv%B*%b&)cn?sXMHplty(}#+zwRCofCDxEMY9xm1P*XrU`h&Or}j`j z6*Ma#Sp!KA$a`MM%LmKc8yOk`*6toX{TDAUxhVD-08HPSo7aNe_3hiYU^~m*4NvH@ z0HzRhq+pF|I+Blj^QNt}wN{12WLprm>AQFNI<=iO-2mSD!N-i3%ZiFJfP@UNbn&kg zRe&P{{tQ4PsMKB?7{IbEN`udBITg@0=cGLF^!0qKpCc(2l1%Gj5$GGu<5JhlG+Cr- z%S%D=%z=hmAic0sNPAz2@u-FrVCE=Y%~wzDTGj`OLkGQkp&IB$Oy&HqJLJo^k$ggd zyqwaHJ8b?-7s?tsj;9`OP*Mo2c7+~i;TBlbd!N*Nr;TN;9N^mN$~C)|OHS^&#{bVc zH&xLj-VYd)T$U$iD$=S}R#uVDO!x48;Bed4N0l~^IU=X~N=3D+U23}AEoY=^4#0(B zo?$1)jaT24o|X4WYbf$@o%T>`y0!J%Z}m?e%^wl@tMl zD1G;zC%p_U)Hu1{?@a{)EL1;i9{fPkpI>}Bf{P%X3@>_W^V z`e&np;?^w`1e6~5w{N2%1iqLwhdmA>>4JM=v3HqwVxSDtjPwAY3IJDrynw5!s#Zkk_e}W@fJyRn=7$RBr9g zK8fJco8*XD)#&CDz;(KYh@FVFq_se~2f!#~o115C&4MjljDY|hfw~|L61N_Q2r20F z|IxdK7#O56rr(n{QI7mTSfrN?G8L#icUKH9mr`Ps1381YB|!Ut_BwK_e+GH2ucxG~ z8Lt~vKwlt2j~_M=8f_WPXA+ZKLt9?`XQbsBT3{TraBu_2{d)$&2fSH9>p6ScY**26+uP)Ox0HO?fHwjK^_gzL?D?46(gk(%87}IZOwIe z7H!fG&yBvR12wR8Br7~U?MF&V3XIk13Y23x4Gm312pGB&hLXMF3MUJo75st)7|PUm zqy*7?uDNW4-o5w0BG)oBAzUnF5a_Gh3%CFD5}KryJFbsKg(adQejojiUs9$U3SLuU z1$hO($@AD~&k9W3f0wBsuQN|yMik`a9X{a5PcKieEWLx|cIP_1^4xbnt80nhw>M@? zxnwrX@f|=zpcem++mW!Uzq>u)m_b<6>Jg&+TUk#s$P?>y+S7QZaTM>r*aRZ4rih7P z$k`VY&n=v1bjWX6oxg3q)hQTEO-U6554wuyHrFtNG4VR-^XJcAUe^x-uY&7b-G!q1 z`_KZ~mGAFzd&K?8W8dy58XX}aC5;9JPsvTU=9%{pwvNgV*G-**7+Lp+bq7Q^y}dWd z@jGw$L(E&%#?7qOF+8klcEnh27mr{4{SSYPZ4o~{`>3I#y*)24Z(&3utA|_$$R6LI zzJeX6o#NkE3c-B!-EF+L1Js`zw?}J3q*4+DoK@|q_11HQk>gi2Dz}lMGDtdxNfiB0@3>16u(Aw3CowH$H8!f1SVlw0c4BVI4v2_g9HZvM&w?8|QXF@BlA?5eff;SMu@=KU|~w%!aeIKrHd_ zA*gx8zstj7;y98E!59J|7(ZHSR$)So6e#t=;31Vj}6N&-ny`|=9eGzS<3$w!L_nEVS5ozk{n{Hfw?WFjOsvs?2MO{T*O{?MAD4axS z81WEzzC<(zp%Nj?301&`ND%@>f+){u6%*5UuT)hQYy0%8eN|LsRZP@7gjm^^w0py2 zBT-&^t>M7c(vww{6-7)gN~z(gseA|%bLQ(jGL9XN+z>9eg#Q!DP&5A@fZ;Yc=svh2 zMH3-@=#F{JOhfY*6i=YZcH5or2xoo;DnV!zIJQYiN!8SXa^@p!2iYkpd#k^h;S>$0 ze%KglKmY{>?6u>JQ4wsqbztfO&Kxoc&(yWFo^f-l%E@g)oPtkGoB$EemAp4k11x(! zHP3)#8Giq3k8cZ^9B8E0H#QQVIm|9ExAS$8Ai$JgS&u*!kK&N0RrhxIZmGJCD7*whRmMz>4*- z!(61L)*DJ8cDpexfCN*AevXJ0XlAh(vnHarM`E!temyPr)Uuqa?{8dQUVc4+{R0&N zhyd07m}_yXy=Ql{_QNbMiMIJ<($eL>i6^6c0@!#r{cphOXtKr)6?vm0TA*20*LM3* z*Hveu$Z2j%b3z-$Xhh+3Z|EMWJRZrnPMqP}(|i9{*XbEhXOeO+^K-M~VCeZ20vz&x zr#kdh%ZyeE)+!3d%iY$LBeMwJ5GZ_5*!{R0JM8$H`Dvf-6B5Kir!tME&6T60@@FJV z9t(A+v=XNx@_O8BW3)0baf$W#w0#p+hrYzBq^f9we`g^velecD=r_Fw$@8emsrOEa z53z0%b~1OpNO{hdSo0~cr%B-2{|T=w$;9t%oBZ`OUFv$!`A?iY)qtKPoLJ|XYgVFR znK%LoU%^LEryjOg2ZbdVe?WCMfb!|VXpufhfS?cIhXEfGQYUb_uf3#zln!Wu2iw}f z^76scr_gP0Ab$)eb+bLZ+|SJo4X;7j2EAAf5>RgWZ%^Lp@65Kqj0e?3z3VxjhY&lL zehF(6$cn>4LqV<%!rUjrRD>KHMKC5{T(yDT`R7lV2Owot%2EaaFGN{-dv=8=88B{t zo`eHRq&{w=ZVJ9gJ>A_`!gFkFD{JdV92|ej&0~XtUK$wCb6bu6{Fz!(QUcBvzrMeq zCs>KpbwxoiFuXyd5gd#UCMm|o#=}w(57j|@vDMM)Ec52w8$%WJ18s`EzdJ6&oEC)X zXBS;RV0|>3JR}Jb(kgy!@=-%ktEuaPC$owD(h?B6rsqwkUpHEeYB#4BeFMt?Z>`qr zNhEP$dxmpUM)IYqih}+ymu2f&kP3Ct%+0WP?R}enmKYPAJ$;Rfzc{1GW4FeCTz(5W zJa0Qh8q}smRKk!_K#!bnZ^61wqomMy{)H>gL#`ln!QAts2pm!`keC*Q#b$2X4 z!>h}cnRFR=x=&rsyJt#tmTEsWCtUaDXCUwahOexw0_*?+{(9ldZC>ui$B$No4UhfU z2!5qA9Lwc>a8c}9^8L7-f(ddNlxKgxo@Dmt#xCKKOgmgg_HjQ}${IR2unj?Z_@(bP zdrWNXpI(_2>}Z+Rxt&_Ba7f;P?t;MgXZhe^$!Yzsw~wxW?sxhk4(AG8I>D3Y-{r4H z0^R!Za*{j~*aV<%1-Cx9MMy}VwHAcibFNDkOGcchQ~746Q(ejEP`4O>vZ5?u<@rG| zg?-%pZclyz|Nrn9Z<1$W-a$m$^qikWr|AI+p`nrcs5N20l$8AoJM0ebs%|MyE zdpkRN`chHwFg(I4$uIN+PsJIPVj$u*%kYDI=)}Yk)!-)`#`>urTLnH1?F9+i1HaT> z(qsP9Ne*s&Eg#ci#+I0;`p#5b{HfK$ZT4NF(|Vln9coDOaD4BhO%OP-&B)AWD#(7= zW*d<6@Kh-6fWqQj7Pk|>C2b#H5KNd<2SDT|n`d@>Ar zLFHzP$$rzDkdVmOwU5ev*CWuel`0<~%i1tJqXn~RX3T9A`u}ACo)Z`fY)Lky)`jA& z|EB7|I3Q=d%i74TPlHt=DHX-GFChR;&Z_kv(*Dx$T~1Uc@A!Vmj{R9f7@pbfjrTGF zb-nT(g22wy^4pQrbN$xtSrpNMqH|j8rP9`IXQ~D zZGm?22Ye@@l8sKcI5@;fc+6t|)Ug)Qur0|-(UzsD2#dC~Hu?r7)_Xqp#dTx7%c8Gm z3RDj+o{33%)SrOBAXu18uy&ww;J`pselFgEeq3cafa3n#A~YhrSwpsXAar`kfH}uB zfSbMP`NrB*tGK8{R|k{=GJdv|b5|_KMg*fki)@e|7q*}&vkg3-C-^_g?FPoE`{lcAQ46c&~pj@nh)HCu{( zZ0e79>(5j+d2+nkc>{sMzqII!l1dsks5E}mPpM2DYSx6hbJBoS?+k!lZ1KFDP-!af z5dVJ=2!Y|}mGD$N=Zj ztOXAbcC;@~#$ry!$R1t@U9PR!t(V2Jn*<9O8{ijeA7TlQ!hBgRawYkMbL&Og0$%Ygk(#=+J-9_~%S4XgV!N4w2S^a}m?ZkIE?GO~5nvp&&1qlv23 zs89djF$I`9eboFyDT*(3>fz7r3l7ndO8YaKk}wrH;SNFi#nlvfagqwCQT(%QIiEw)qew-xMR($l65?fTg!Y=M-Wd18UYaWRwyAtl5a4MhZIyO@| zt)__SUn;8(BJSC{#Z)a1I>F?m$gmInvP;?@rD6B-1(Rd7&B`<6SLRTJ(T$MFzh_Vk ztScAOoR&YD9;AMkBXG_AYY4|)I}`sojP@Tf56qIEgay=GL)iKFMz6~&9#J7R{B|W& z^XHdT--mC`;r2WP?2^@Hx`Co-hv+9gJ^uj}pVix~Vcp2sKLOfvMNn^h<9Gh3}C<7Cc#R5uz=eq=%po`SrMTOi+zPpXLVUHKc4|@Dn?%NeKS><9h!q ztf4&+x8bJe#8N&56!EKrAl{Z{{94G;5ZI<~rS3$r#7KbR-c&p-t}Tnp^;(sGAcTsf zz3(OBj(tdl@spn8vYPm|SFMJQ#_m0aTSybNpqZ(ueqQS3LakGY?H#wBi@|9Bi1eTJ z6Lq$RV9$hXu^@lNe(Chly#Nb4i7|I_Q0ETIAHVRDtz%-o|AtCIbp*}*u*$N?ZPCbx z9k00QYt2_*1FA-!gs&7&>hgzx29}UfG*aKN}Q?6x#2P)snkSZ`KWTnE&`x+}Y(LuhOFc4I~ru zTsmL>Fg0 zhNy3%+BS#no@h>T~7A%&)1+LPN6+9R9Xt$5v-0s85o|9jki_H0V%O{%L)%r zVc-?4;`v|7XziLi-tdsPO%!?OZ>^{o&DH6*y`BBbMR1Q=sfe_AAAmi7UYzb0bEX;? z;KkKGe8Bo)Z&tm4e;ggn6BghJCwepzk`dxQeOtnNfNE&*+HU{$XJ@Yd03QNnvGJRU z0B&@30i+D&i(V?2k;R>A+|Lh)CRadz=b)-YJZ+C zQZdN}X2+zQ^(G2bxkU!Ecet!s+$G3Lbn0s9>G|E}Mbj=1wbnp^+kou3->tZm)_0*) z5DE@5ygN>O106y0{1YJex&@-=4g-aq1m?+sOl69jZ7*qX*xiY5q#ahl>pB7g0v8F@ zc=9o1o}wc4Z$C!75sJ{6)8z?&Y;G$Ve8WzInj+nQ~=$ z`E5$SqwWZ@wQ=~5|Im%}D`?M&AFAP#k#(*J1-s!unC(?}Pik;5n6dXOVJbt~6Ur{e z=s%WXrYiyK+Q#)E1*4aSng8n9efIUU zoKHCSNuyUHEp?jq{x0>YvAfSsznD6GR$pD`ZA&SfgX4ygdDl)v($D`%%_QA@R-=B*FT_^YFIIW<5AIlCA)0zHkrSE;x`=DKTLfMXol4eim7x+0W zq$)h>3q5sp{GE_n?v1aLEREVRgLR`Wxp}aW7|j@TbTmks-tW0B`?$wvbQ_dD3acrt z8smlw2I+N@;i19BB}F6zXQeh)dLM*4W530Wk>Ng;eQNp?Wj3RA4t$V7HeB=R85ReY zp=dZW58K9{V!X9KS^0Uc;dfqXE3weAaJ4q6N-5qrRq5>Pkm-{mAt4;0&MU~y^=h7x zXrhIaC7YI@V225()W3T0oHG-->+5&ZnF5QG;`;%ffkC@Nq)TTTIWliBZr;C!`8gb2WQ&=L-)TOT>HE-mTf%*=_Na za&pKIQ$+DYAL6V)7cJvr=VEU=)~O}R|Zw5NiM5} z1=a^FDXx}5)B4KHBciPwxJ;sebA$xVreIw?c>8^j2u_Zh9USk2^6S5e55ZfPrZ4?{ z{ZJa#<`bM;Xg=QrZ7XLSh`kNaVwZVQyqhH@rJ_lrCHy0F3tTiAS2l!VL{8I5u@HeKK5~H z;r+~&Xd5J1Hn=t*o`y2YEshxwA#f0121F1N-a>Wn%)Ze(=|zoxLhDJ>j0FNF*GHq6 zLA{q-I-CDh|K)n4Bbh_0$S?UpH23ZbOEVU8QXDbcDNR5a^zP0K6e~hS<>=yb+oAdz zC~{An_NK@AD?m!-Fqc1l5cst0vET+N>jT;w$YYzbxXNK_?2{K>@KK)|g*K?$@tFTp z`unRKY0^bf0Aj*Fg)S}*hNMWqz#T&)16#Ib3prOg8(9@|myH4RF2o(oLJ(WCi6>LN zzGYNq;S%*$Jk80?y;^)_Msp7?{VNs>7f_ONa>$XWX6+D5jQx5z*L@m;EWP@Cmjt3# z{yy5L5EHS6;N}jFnF>AQDHbA>R`zvZNT9B-%jOd~@;2M#nvlKqoz3Z}da1DZdj+~B zD2O7LVxiKn@nwYOF83LC8-oE{-v#=env$g5oiONv(U+>nF))|hOQJkr> zCTA>;9Z>h zi4r`V62%@rXzy*EGK}+|)}F?FIvlC;O;1T*hp`O?T(#W$uFej}J7?Q3j=e$2m_Jrn zJgbimTiUeSM)Y6a8Jo_v<|&LV!McpB^!`7;J6^NH@=E)L_ClbzIyc$uPtyVvrAB=_ zA9NxOO+&j+r+lf0g2yk>j~lz;sF)|CM>m`uxId^!VzjotXN((=DM_O1dT9ql)P z(X?x^FDraI_9YNSV73U*I4^ z%0tmDAlsmK+^F?zo^hn7{$2JPgmJx8Pl7^&wvhkMIIxg#1dR^Y5SJq{Re z4&MI0Q|T}W&u16C{*>Eavkepdu- zF*?{}{LgpU0X1&`4tNO!&p<*{L;^DpCy=JSaAfHy=xcs{z>UsB-0Q+g>1lz3cX3Q0 zqyVd}{~Ekpsw5s`M7KtLVAwys{+XuT7(9JL{^PH5L&sNsFz#0>TW9F z_8s+@_-Y0I?@M6qVr**4d}ZyD1kZv8KI=cWBAl34Ml<(TwknGb|SMLCGpIgh2)PO1h@$qL$qSD~QUEcza3D#3!fEagkUfg?W z?&4F^G-oLFx1=PR7&rg_i?O!=t8(kshEX>bQX(KCARr(hjUcVE0BHdMDUk*#1?dt4 z7cJeOi*5v@Q;=MAw{&;cTHj#rbKduS=R5y@oqch+bhDo4nR7lf#u)cK?s2UQIu+`1 zOg)!g5CS)Uje30X z@~@X>%+apA=x--bt@GvjQ#xs-+#yV*F^cefYVM0$y+mf<|W-ytp(!2Zdqv-SJ z!D7qXAC%S4WsXLW_ye2qrb`_`_+>JX1ACMNrRuMK@IgK$PD0{cmes8iYp|}vL%w<^ zwS&=F-+ej6Y!XkUy*C%j!=nhX^TC|+e|n6}%$n`5baFS*(0umvJa>_P@`Cfp0oT^0 zMtEwt@Ny&>Nsx|Y8B_%gK#?RHv|8+Q>$jQeS9u%Zke)T{uG$I14pF@AYg6yC+mnRj%&B0F!cz-qt-hfuJ@a0HogNTgVqCwSN;x!bH_o36;+O;E z(cUWM_3OXvNju99k3qF{B4L#UN7N1sV~YqJwvQ*9#JiwE&&wOS%JPjAlq;vV4*@%Y zTWzG*(TizO!4sNBN42G;uc%M{aw!MQ4m1y;YdC-E;PxeOd(f|KhTCfbKCK7PiiP^Q z&Z~bGJF^L(=?{P#1t7J$np(cjR>kQ-JI>|T3&d(b?b4J8<{ciQX@fY*TZqd_^5 zsXUM<&jhB5GI2~F0EK0c{ha2-L-E^;^3m@=t$AnX9lV}?T5fJ-kZA_VY`9J5Yfz+o z|IcfzH~j5G3S7Ihc3cn?!}(M2<%E_I9_QoZ1B9>Mh{?NJX zYNG~9QNX%|hv5)injs|fyUB%;kKqF#0y>uP6-N35bG%+MB8cNk`&Df42aF^ryut{c zU40!YSbTo+9i+hE_JwLts#>r7FH?#c!u~V4b`cRO;=imWs;DR^K&Mi_2=AQfZ;-eB zr#~O%LDw%cEv+VdsM-*;pfc66hszx}&YFoN-MZ9Tg*h_U(HR4FBs?f@`gpy1e{avY z9F*tYiep|))O(XW;N=B4_qRRm9V-y8951zHTH8CfF##mFAOFmGCcUNJbReijgQ(=l z=l2ItXkiJ^R$%U)%}jwNG}`d2wd^CfHIz_A2F!rB_V#;QTLA3pm)|}p0SeIU;-Ysv zAO)6G3EdvAH{71q$^N*4Gah{4wnNK9qrBV zu!?eWh+?uDsjWY?7yjd-cTnU+5`oYzxA$+p4Pyg^RXjaCVFp@6Tx0`%c5bLiPEVf* zczeDM9#rN&e>kmD45U8TjM#O`dV70`laet|tZ&()yLaybxCijp5Ig=Y z@|!mw>is&CbBDzqwW^6zbptT}zh9#F@UUi)`70Gu7LUClDGT*Y0$_djVRJ!~8|>82 zPe5-Lj_e}Yk4L~J09kKPF&$)2GBPX)CiGZqfQ@23Jt@f$O4ZcX*23&y+eq%f5j{PmhP3Q6RUO^UY_Z#UCTBF16yxq626v@JSZ;gl-yIJYi$LG&$0uz+% zvbnj-TG`p|gAGegX831i5)n7cNEfLD!x;eIs9ret;=ond_2BE-uEB}DfrEonkADbS zjQ{bWDFVur|GYvRocC&Hijx0qbm!nJQ(hYApLOK6D0|)0(=KexgD&{VJ+NJ;N zX8)Q*f8Pw$cK?T)%}<<%>kAE=gDLr~kS~WvMtHEql$5P6l{&Q-uxA&Vb)h7HxEXe! z3k-FO0o=9^XYI%i1{NKF-(bitv)|@?h2ui{81Ie;G{*b^OfFyrcF6)w3%2S4O=4d1 zIS*H_6OQ=Sj^^~Ntgj$xZJO9;(#a`dG)w4$ocZGIy|3S`lF-u1`eJ0r!Db=jTbd*5 z{fBI`(srt0p@oG3Ri5d|c3PHHUF_-|apCIER(Kq5Zgcaj4#majU2I_78*|}vM&_AU zt+uh*;frSH^!jXVC739#3K<>@n(++53QU9APQdZo-rEcR`W4(;$PNB`PdMw(CPkUe z-gA3nuZ7t~`b+cJ!ixPGTAHM{-=8^-PcJYRUqIY#oDRG47lyned$gjbN-HpJ<16LB z>9UouC8ju$(XDOr4RRrA#9c((fYIZ*nwk}Mx_GBIR0r$$z&R8iV{mN0M=Sc5zdyStS3z!WX23N3=V11cGyxME!(rMoLEuLh zr>(0Wr2;btno2zal2TL9m`M{6@kGhM>kh|i#0fMrE@s^;huZ9zuqT;HT3a$N)Znbw z4d2VicN2_y=@KM}k}@IHGn02`9wBwpxI3$Q*HLEu2fcfNM|=rTI+c}&osZy$|6@+$ zn74C$yd+}Z09C%XmYFl;g=}eU`QYXzcRve#KbuDE={;A~S6y9v+`ODjLb4N0CHwDb z@v9G5Sy+S#RvA!zBT!ezoG1tuBa=&G*~rt@rlzJA%^`b?L1We7^p}K(d8u%Pu#;2Q z#Xy?7vB!;LWd(I#bH|S&WZrk+(y>f!ldS(96tpKXsZo}Rp0xzH4S>w8eTMnrr& zC|DzIP+W(agULx5(L|K=xoNMA%qMCy3=-K=lZCwlz1^cC%ne`nXFG@~=>^exY7Pr_ zbLVpfO(y5c3fkM}yYjo|E~nM3%L?*jGb%GD$31*263P2>cs$^;?Z{8niNR0JG#|RJ7wc#- zwMCm4o4N6`Y^}WIw-j-6uWjY_e2)yizQ%Esj1fzpH%rGobYicQ;+ae|yXxa}LDGHJ zc6i$9h=)hk+*l7Pbhe9mL`-j1>HhHYCcvMapQ}fVM{*kE4E(60#i&aheq;_thN`MY z5ff=OT2)&P*Us9wwL3D3$=$%eLfkbowB4wfpprYgg7!-=mM5-!H&$XbjiHxQ-V~VD z_?n>pHKDQa&#IF}bB3KaTiT2&hsF%qqYnQYRNZxYC4g|-^!(@Vb6*thX>FbPe*v>;Ac=XQnq<10e@ORyXlnkPbUkYlSH-T#F77F1!S z)f95pE^@@1Tn~cR#nbv~E}^OkO*Bi`QFm-pP*4>uD6W#ZI40_$2mzS$x!I090RlldjD56rq{zZ9^hSt}FV&@TR7%07(8~Fdp1u$b) zbdP@U8{2(2e&Nf^{M?FmwWgM$N84Uyw5BCZ!-UrEX@&E^@wwhaUcFN7^`p7~oP?-g zJRx1(!Nc+L>7$Vjm8eH~=5^69Xe8?mesO%Z?ZHNELzxp_gKiT@X{h!!d}k%DM7L%a zKW<*ur&E4rvGy$C*}c1TQCLE*Wz`{WVt;R6Q@VNUf!QsRNWV6;_tPg&P*Emu^4$7- zvgxEeU|~Bm^>fjej6_M*E(~wM`kLU80p%IRuQsj zp<%Q}MWNiChqfzk63aPx6kP~!${~t$%1D&*)@LP)pDQZ`O>ahu_a^o!d_iv6+T6+! ztgvmJS|o9>d@=2Uxkelo#wV&O-_co;kNSY*j!(YcHNt-VBF_7La6X)-WTey6((!4; zhU!PV=L@A?+XS2Tc~A&-cK0)ΜcdhDuNs!uM+;ki)N+eaJ9*HmfyC2J&dO+<2kW zLIqX20d^;nF8>;jVAZmWLh-kDZJ)#0par+0{o(EQlVnz;>BJmCG1YjLH^n#N=2j{b zJ>mInMKRmeHnf!d(NXsziTn6V@v7)Mjnjv*n=@}pNoS3i2uiA?KK77f@+{W)b0`NG z>Kh^>wPt23N>=Q;VGk~gJC4F1wYMbg?-j1_;NTZ(tw?NJV4mPrR=wo=-GJ#RUW~+f zm4(M8lo&E{nlDvqU*wVnIvt((`3t$)*LBb~dnGXvOd~@4b+CAmrVE4o;^0^^s;i_?S%PnE_A%HjFG;wiP+&4NUw}K92w7T-B5bj zNZ@jNG$#6Fuq%Dw zjQy}uMLc_-^Sx{0Qb2!YK*RFjq+1NXa2busMCJT2)$v2D3pFw=#6MU(g z?U(0kB}d5n_Y>pz&7;CBxBb) z{2X}qJWe5d6HVu9)7L-UMs!B-hhvbHw{dVBJ#KoO*~H)+!k_=EkGfN_7ta`p;Fx^s z5v}|+AvHOBda%HOq(j$|EtrOpaoks0(T#;8_m!o|MDzE|4=8=Zr+=i2Ppfk#P$q^a zj{|~3iPn$y%SvV4f4p6}PFkDGU)!4B(8=~}Si!ZjZ#wLh(IJr>J{)#?hacj00p zT#uNN@sB?F`H5v;rB7cxqd6v9bZGjgNQrcN+^`lGWrG^g#ec|k=C;XwBdq^y&g@y~ ztiCb^{(%`^L zhvHengsb!@iRv613O*kV{mya2BNWY&RY*dNEfd{+4*pd65qlkHLG!{ceX@pep9L|C z-t5kAg`rF=uV1@eA|w~Nl8mZ2F>cyLn{>eD23D}e#H9SXHrQ-nTWAiK71KYF)s47D zBNmmm*WR{~<@Zk2Za4n)5|=-TQcdzUVrQk*T#~a@C78OQ5rHQoV~39) zcT~dJk(HYX8DG<#FX=QZEdw*kE)qkr5c_-w*AWUw)r~C$#Gr51yyj{lRje}?{f&;E zp0!4V!|Is2P60kK6lKRfK8k$tB1)s`@T76V+uc!2L0(*3IUnQ4;Dr0zOI1}(P4Y8t zs+hdeGv&e}Th5<(&LdZx-eKdz1K5ejs)!rHrtI_AyQ@C_UZwo5NW-KtJUIN&-oSnR zd1%B$z-3vFXgVmBovkR=

_;wDN#AtH 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

    =mcz-}5_cuIFm)P1YB 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