From 9dad1f87b3688ed5ac36b5d7fbf3aa2e52190614 Mon Sep 17 00:00:00 2001 From: Bryan Scarbrough Date: Wed, 15 Mar 2023 06:55:28 +0000 Subject: [PATCH] Resolve ENG-8 "Update terraform on github to reference latest kasm version (1.12)" --- .gitignore | 7 +- aws/multi_region/README.md | 69 ++- aws/multi_region/agents/agent.tf | 38 +- aws/multi_region/agents/availability_zones.tf | 3 + aws/multi_region/agents/main.tf | 8 - aws/multi_region/agents/provider.tf | 8 + aws/multi_region/agents/routes.tf | 21 + aws/multi_region/agents/security_group.tf | 14 +- aws/multi_region/agents/subnet.tf | 16 +- aws/multi_region/agents/variables.tf | 47 ++- aws/multi_region/agents/vpc.tf | 20 +- aws/multi_region/deployment.tf | 243 +++++++---- .../diagram/aws_multi_region.drawio | 203 +++++++++ aws/multi_region/diagram/aws_multi_region.png | Bin 0 -> 175040 bytes .../primary/availability_zones.tf | 3 + aws/multi_region/primary/cert.tf | 18 +- aws/multi_region/primary/db.tf | 42 +- aws/multi_region/primary/lb_s3_log_bucket.tf | 56 +++ aws/multi_region/primary/main.tf | 14 - aws/multi_region/primary/output.tf | 35 ++ aws/multi_region/primary/provider.tf | 8 + aws/multi_region/primary/routes.tf | 32 ++ aws/multi_region/primary/security_group.tf | 144 ++++++- aws/multi_region/primary/subnet.tf | 67 ++- aws/multi_region/primary/variables.tf | 91 ++-- aws/multi_region/primary/vpc.tf | 22 +- aws/multi_region/primary/webapps.tf | 27 -- aws/multi_region/provider.tf | 49 +++ aws/multi_region/settings.tfvars | 62 +++ aws/multi_region/userdata/agent_bootstrap.sh | 29 ++ aws/multi_region/userdata/db_bootstrap.sh | 20 + aws/multi_region/userdata/webapp_bootstrap.sh | 36 ++ aws/multi_region/variables.tf | 294 ++++++++++++- aws/multi_region/webapps/agent.tf | 38 +- .../webapps/availability_zones.tf | 3 + aws/multi_region/webapps/elb.tf | 145 +++---- aws/multi_region/webapps/main.tf | 9 - aws/multi_region/webapps/provider.tf | 8 + aws/multi_region/webapps/security_group.tf | 63 --- aws/multi_region/webapps/variables.tf | 171 +++++--- aws/multi_region/webapps/webapp.tf | 50 +-- aws/standard/README.md | 57 ++- aws/standard/deployment.tf | 52 +-- aws/standard/diagram/aws_multi_server.drawio | 166 ++++++++ aws/standard/diagram/aws_multi_server.png | Bin 0 -> 149914 bytes aws/standard/module/agent.tf | 38 +- aws/standard/module/alb_logs_s3_bucket.tf | 60 +++ aws/standard/module/availability_zones.tf | 3 + aws/standard/module/cert.tf | 13 +- aws/standard/module/db.tf | 44 +- aws/standard/module/elb.tf | 130 ------ aws/standard/module/guac_rdp.tf | 26 ++ aws/standard/module/main.tf | 8 - aws/standard/module/natgw.tf | 22 +- aws/standard/module/private_alb.tf | 93 ++++ aws/standard/module/provider.tf | 8 + aws/standard/module/public_alb.tf | 126 ++++++ aws/standard/module/routes.tf | 54 +++ aws/standard/module/security_group.tf | 112 +++-- aws/standard/module/subnet.tf | 74 ++-- .../module/userdata/agent_bootstrap.sh | 29 ++ aws/standard/module/userdata/db_bootstrap.sh | 20 + .../module/userdata/guac_bootstrap.sh | 29 ++ .../module/userdata/webapp_bootstrap.sh | 36 ++ aws/standard/module/variables.tf | 122 ++++-- aws/standard/module/vpc.tf | 19 +- aws/standard/module/webapp.tf | 51 +-- aws/standard/provider.tf | 18 + aws/standard/settings.tfvars | 43 ++ aws/standard/variables.tf | 284 +++++++++++++ digitalocean/single_server/README.md | 36 +- digitalocean/single_server/deployment.tf | 31 +- digitalocean/single_server/module/dns.tf | 31 +- digitalocean/single_server/module/firewall.tf | 34 +- .../single_server/module/load_balancer.tf | 24 ++ digitalocean/single_server/module/output.tf | 3 + digitalocean/single_server/module/project.tf | 16 +- digitalocean/single_server/module/provider.tf | 8 + digitalocean/single_server/module/server.tf | 56 +-- .../{files => userdata}/kasm_server_init.sh | 2 +- .../single_server/module/variables.tf | 64 ++- digitalocean/single_server/module/vpc.tf | 10 + digitalocean/single_server/provider.tf | 12 + digitalocean/single_server/settings.tfvars | 24 ++ digitalocean/single_server/variables.tf | 135 ++++++ oci/single_server/README.md | 67 ++- oci/single_server/authorized_keys | 1 - oci/single_server/deployment.tf | 56 +-- .../diagram/oci_single_server.drawio | 75 ++++ .../diagram/oci_single_server.png | Bin 0 -> 77494 bytes oci/single_server/module/dns.tf | 25 +- oci/single_server/module/instance.tf | 37 +- oci/single_server/module/letsencrypt.tf | 48 +++ oci/single_server/module/main.tf | 8 - oci/single_server/module/provider.tf | 16 + oci/single_server/module/security_list.tf | 67 +-- .../module/userdata/bootstrap.sh | 9 +- oci/single_server/module/variables.tf | 131 ++++-- oci/single_server/module/vcn.tf | 12 +- oci/single_server/oci-private-key.pem | 29 +- oci/single_server/provider.tf | 28 ++ oci/single_server/settings.tfvars | 43 ++ oci/single_server/variables.tf | 268 ++++++++++++ oci/standard/README.md | 74 +++- oci/standard/authorized_keys | 1 - oci/standard/deployment.tf | 63 +-- oci/standard/diagram/oci_multi_server.drawio | 191 +++++++++ oci/standard/diagram/oci_multi_server.png | Bin 0 -> 217262 bytes oci/standard/module/agent.tf | 39 +- oci/standard/module/db.tf | 43 +- oci/standard/module/dns.tf | 25 +- oci/standard/module/guac_rdp.tf | 39 ++ oci/standard/module/letsencrypt.tf | 48 +++ oci/standard/module/load_balancer.tf | 98 +++-- oci/standard/module/main.tf | 8 - oci/standard/module/provider.tf | 12 + oci/standard/module/security_lists.tf | 190 +++++---- oci/standard/module/subnet.tf | 114 +++-- .../module/userdata/agent_bootstrap.sh | 12 +- oci/standard/module/userdata/db_bootstrap.sh | 3 +- .../module/userdata/guac_bootstrap.sh | 29 ++ .../module/userdata/webapp_bootstrap.sh | 12 +- oci/standard/module/variables.tf | 201 +++++---- oci/standard/module/vcn.tf | 35 +- oci/standard/module/webapp.tf | 46 +- oci/standard/provider.tf | 28 ++ oci/standard/settings.tfvars | 69 +++ oci/standard/variables.tf | 399 ++++++++++++++++++ 128 files changed, 5495 insertions(+), 1660 deletions(-) create mode 100644 aws/multi_region/agents/availability_zones.tf delete mode 100644 aws/multi_region/agents/main.tf create mode 100644 aws/multi_region/agents/provider.tf create mode 100644 aws/multi_region/agents/routes.tf create mode 100644 aws/multi_region/diagram/aws_multi_region.drawio create mode 100644 aws/multi_region/diagram/aws_multi_region.png create mode 100644 aws/multi_region/primary/availability_zones.tf create mode 100644 aws/multi_region/primary/lb_s3_log_bucket.tf delete mode 100644 aws/multi_region/primary/main.tf create mode 100644 aws/multi_region/primary/output.tf create mode 100644 aws/multi_region/primary/provider.tf create mode 100644 aws/multi_region/primary/routes.tf delete mode 100644 aws/multi_region/primary/webapps.tf create mode 100644 aws/multi_region/provider.tf create mode 100644 aws/multi_region/settings.tfvars create mode 100644 aws/multi_region/userdata/agent_bootstrap.sh create mode 100644 aws/multi_region/userdata/db_bootstrap.sh create mode 100644 aws/multi_region/userdata/webapp_bootstrap.sh create mode 100644 aws/multi_region/webapps/availability_zones.tf delete mode 100644 aws/multi_region/webapps/main.tf create mode 100644 aws/multi_region/webapps/provider.tf delete mode 100644 aws/multi_region/webapps/security_group.tf create mode 100644 aws/standard/diagram/aws_multi_server.drawio create mode 100644 aws/standard/diagram/aws_multi_server.png create mode 100644 aws/standard/module/alb_logs_s3_bucket.tf create mode 100644 aws/standard/module/availability_zones.tf delete mode 100644 aws/standard/module/elb.tf create mode 100644 aws/standard/module/guac_rdp.tf delete mode 100644 aws/standard/module/main.tf create mode 100644 aws/standard/module/private_alb.tf create mode 100644 aws/standard/module/provider.tf create mode 100644 aws/standard/module/public_alb.tf create mode 100644 aws/standard/module/routes.tf create mode 100644 aws/standard/module/userdata/agent_bootstrap.sh create mode 100644 aws/standard/module/userdata/db_bootstrap.sh create mode 100644 aws/standard/module/userdata/guac_bootstrap.sh create mode 100644 aws/standard/module/userdata/webapp_bootstrap.sh create mode 100644 aws/standard/provider.tf create mode 100644 aws/standard/settings.tfvars create mode 100644 aws/standard/variables.tf create mode 100644 digitalocean/single_server/module/load_balancer.tf create mode 100644 digitalocean/single_server/module/output.tf create mode 100644 digitalocean/single_server/module/provider.tf rename digitalocean/single_server/module/{files => userdata}/kasm_server_init.sh (86%) create mode 100644 digitalocean/single_server/module/vpc.tf create mode 100644 digitalocean/single_server/provider.tf create mode 100644 digitalocean/single_server/settings.tfvars create mode 100644 digitalocean/single_server/variables.tf delete mode 100644 oci/single_server/authorized_keys create mode 100644 oci/single_server/diagram/oci_single_server.drawio create mode 100644 oci/single_server/diagram/oci_single_server.png create mode 100644 oci/single_server/module/letsencrypt.tf delete mode 100644 oci/single_server/module/main.tf create mode 100644 oci/single_server/module/provider.tf create mode 100644 oci/single_server/provider.tf create mode 100644 oci/single_server/settings.tfvars create mode 100644 oci/single_server/variables.tf delete mode 100644 oci/standard/authorized_keys create mode 100644 oci/standard/diagram/oci_multi_server.drawio create mode 100644 oci/standard/diagram/oci_multi_server.png create mode 100644 oci/standard/module/guac_rdp.tf create mode 100644 oci/standard/module/letsencrypt.tf delete mode 100644 oci/standard/module/main.tf create mode 100644 oci/standard/module/provider.tf create mode 100644 oci/standard/module/userdata/guac_bootstrap.sh create mode 100644 oci/standard/provider.tf create mode 100644 oci/standard/settings.tfvars create mode 100644 oci/standard/variables.tf diff --git a/.gitignore b/.gitignore index 97fe116..b555a12 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ - Local .terraform directories +# Local .terraform directories **/.terraform/* +.terraform # .tfstate files *.tfstate @@ -8,12 +9,12 @@ # Crash log files crash.log -# Exclude all .tfvars files, which are likely to contain sentitive data, such as +# Exclude secrets.tfvars files, which are likely to contain sentitive data, such as # password, private keys, and other secrets. These should not be part of version # control as they are data points which are potentially sensitive and subject # to change depending on the environment. # -*.tfvars +secrets.tfvars # Ignore override files as they are usually used to override resources locally and so # are not checked in diff --git a/aws/multi_region/README.md b/aws/multi_region/README.md index dab13d3..3ccc915 100644 --- a/aws/multi_region/README.md +++ b/aws/multi_region/README.md @@ -18,8 +18,6 @@ is deployed. [Image_Diagram]: https://f.hubspotusercontent30.net/hubfs/5856039/terraform/diagrams/aws-multi-region-int-gw.png "Diagram" - - # Pre-Configuration Consider creating a special sub account for the Kasm deployment. @@ -27,12 +25,10 @@ Consider creating a special sub account for the Kasm deployment. In your AWS account create a DNS Public zone that matches the desired domain name for the deployment. e.g `kasm.contoso.com` ### SSH Key Pair -In the desired AWS region create an aws Key pair. This will be configured as the SSH key for the deployed EC2 machines +In the each AWS region where you will deploy Kasm, create an aws Key pair with the same name. The key name will be value used in the `aws_key_pair` variable and it will be configured as the SSH key for the deployed EC2 machines. ### AWS API Keys -Create a user via the IAM console that will be used for the terraform deployment. Give the user **Programatic Access** -and attach the existing policy **AdministratorAccess**. Save the key and key secret - +Create a user via the IAM console that will be used for the terraform deployment. Give the user **Programatic Access** and attach the existing policy **AdministratorAccess**. Save the key and key secret. # Terraform Configuration @@ -41,22 +37,61 @@ and attach the existing policy **AdministratorAccess**. Save the key and key sec terraform init -2. Open `variables.tf` and update the global variables. The variable definitions and descriptions -can be found in `/variables.tf` - -3. Open `deployment.tf` and update the module level variables as desired. - +2. Open `settings.tfvars` and update the variable values. The variable definitions, descriptions, and validation expectations can be found in the `variables.tf` file. -4. Verify the configuration +> ***NOTE:*** This document assumes you are using a separate file named `secrets.tfvars` for the AWS credentials generated in the [AWS API Keys](#aws-api-keys) section above. The .gitignore file in this repository will ignore any files named `secrets.tfvars` since they are expected to have sensitive values in them. This will prevent you from accidentally committing them to source control. - terraform plan +3. If you are deploying more than 2 regions, you will need to modify the `provider.tf` and the `deployment.tf` files. There are commented sections in both files indicating how to deploy additional regions. -5. Deploy +3. Verify the configuration - terraform apply + terraform plan -var-file settings.tfvars -var-file secrets.tfvars + +4. Deploy + + terraform apply -var-file settings.tfvars -var-file secrets.tfvars + +5. Login to the Deployment as an Admin via the domain defined e.g `https://kasm.contoso.com` + +6. Navigate to the Agents tab, and enable each Agent after it checks in. (May take a few minutes) -6. Login to the Deployment as an Admin via the domain defined e.g `https://kasm.contoso.com` +# AWS Terraform Variable definitions -7. Navigate to the Agents tab, and enable each Agent after it checks in. (May take a few minutes) +| Variable | Description | Variable type | Example | +|:--------:|-------------|---------------|---------| +| `aws_access_key` | The AWS access key used for deployment. | String | `"AKIAJSIE27KKMHXI3BJQ"` | +| `aws_secret_key` | The AWS secret key used for deployment. | String | `"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"` | +| `aws_primary_region` | The AWS Region to deploy all Kasm Management resources. | String | `"us-east-1"` | +| `project_name` | The name of the deployment (e.g dev, staging). A short single word of up to 15 characters. | String | `"kasm"` | +| `aws_domain_name` | The Route53 Zone used for the dns entries. This must already exist in the AWS account. (e.g dev.kasm.contoso.com). The deployment will be accessed via this zone name via https. | String | `"kasm.contoso.com"` | +| `kasm_zone_name` | A name given to the kasm deployment Zone. | String | `"default"` | +| `primary_vpc_subnet_cidr` | The subnet CIDR to use for the Primary region's VPC. | String | `"10.0.0.0/16"` | +| `aws_key_pair` | The name of an aws keypair to use. | String | `"kasm_ssh_key"` | +| `primary_region_ec2_ami_id` | The AMI used for the EC2 nodes in the Primary (Management) region. Recommended Ubuntu 20.04 LTS. | String | `"ami-09cd747c78a9add63"` | +| `swap_size` | The amount of swap (in MB) to configure inside the Kasm servers. | Number | `2048` | +| `webapp_instance_type` | The instance type for the Kasm WebApps. | String | `"t3.small"` | +| `webapp_hdd_size_gb` | The HDD size for the WebApp EC2s in GB. | Number | `40` | +| `db_instance_type` | The instance type for the Kasm Database. | String | `"t3.medium"` | +| `db_hdd_size_gb` | The HDD size for the DB EC2 in GB. | Number | `40` | +| `agent_instance_type` | The instance type for the Kasm Agents in the Primary region. | String | `"t3.medium"` | +| `agent_hdd_size_gb` | The HDD size for the Agent EC2s in GB. | Number | `120` | +| `num_webapps` | The number of WebApp role servers to create in this deployment. Acceptable ranges from 1-3. | Number | `2` | +| `num_agents` | The number of static Kasm Agents to create in the primary region. Acceptable ranges from 0-100. | Number | `2` | +| `allow_ssh_cidrs` | A list of subnets in CIDR notation allowed to SSH into your kasm servers (use `["0.0.0.0/0]"` to allow SSH from any IP). | List(String) | `["1.1.1.1/32","172.217.22.14/32"]` | +| `web_access_cidrs` | A list of subnets in CIDR notation allowed Web access to your kasm servers (use `["0.0.0.0/0]"` to allow HTTP/HTTPS from any IP). | List(String) | `["0.0.0.0/0"]` | +| `secondary_regions_settings` | A map of AWS environment settings for secondary regions. The Primary region is considered "region1", thus all secondary regions should be labeled "region2", "region3", etc. Refer to the commented settings in the `secondary_regions_settings` variable in the `settings.tf` for an example. | Map(any) |
{
  region2 = {
    agent_region = "eu-central-1"
    agent_ec2_ami_id = "ami-0e067cc8a2b58de59"
    agent_instance_type = "t3.medium"
    num_agents = 2
    agent_vpc_cidr = "10.1.0.0/16"
  }
}
+| `database_password` | The Kasm PostgreSQL database password. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` | +| `redis_password` | The Kasm Redis password. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` | +| `admin_password` | The Kasm Administrative user login password. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` | +| `user_password` | A Kasm standard (non-administrator) user password. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` | +| `manager_token` | The manager token value used by Kasm agents to authenticate to the Kasm WebApps. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` | +| `kasm_build` | The download URL for the desired Kasm Workspaces version. | String | `"https://kasm-static-content.s3.amazonaws.com/kasm_release_1.12.0.d4fd8a.tar.gz"` | +| `aws_default_tags` | A Map of all tags you wish to apply to all TF created resources in this deployment. | Map(Any) |
{
  Service_name = "Kasm Workspaces"
  Kasm_version = "1.12"
}
| + +# Detailed Terraform Deployment Diagram + +![Detailed Diagram][Detailed_Diagram] + +[Detailed_Diagram]: ./diagram/aws_multi_region.png "Detailed Diagram" \ No newline at end of file diff --git a/aws/multi_region/agents/agent.tf b/aws/multi_region/agents/agent.tf index 98e4e8e..b32beb2 100644 --- a/aws/multi_region/agents/agent.tf +++ b/aws/multi_region/agents/agent.tf @@ -1,29 +1,25 @@ resource "aws_instance" "kasm-agent" { - count = "${var.num_agents}" - ami = "${var.ec2_ami}" - instance_type = "${var.agent_instance_type}" - vpc_security_group_ids = ["${aws_security_group.kasm-agent-sg.id}"] - subnet_id = "${aws_subnet.kasm-agent-subnet.id}" - key_name = "${var.aws_key_pair}" + count = var.num_agents + ami = var.ec2_ami + instance_type = var.agent_instance_type + vpc_security_group_ids = [data.aws_security_group.data-kasm_agent_sg.id] + subnet_id = data.aws_subnet.data-kasm_agent_subnet.id + key_name = var.aws_key_pair root_block_device { - volume_size = "50" + volume_size = var.agent_hdd_size_gb } - user_data = <<-EOF - #!/bin/bash - fallocate -l 4g /mnt/kasm.swap - chmod 600 /mnt/kasm.swap - mkswap /mnt/kasm.swap - swapon /mnt/kasm.swap - echo '/mnt/kasm.swap swap swap defaults 0 0' | tee -a /etc/fstab - cd /tmp - wget ${var.kasm_build} - tar xvf kasm_*.tar.gz - PUBLIC_DNS=(`curl -s http://169.254.169.254/latest/meta-data/public-ipv4`) - bash kasm_release/install.sh -S agent -e -p $PUBLIC_DNS -m ${var.zone_name}-lb.${var.aws_domain_name} -M ${var.manager_token} - EOF + user_data = templatefile("${path.module}/../userdata/agent_bootstrap.sh", + { + kasm_build_url = var.kasm_build + swap_size = var.swap_size + manager_address = var.aws_domain_name + manager_token = var.manager_token + } + ) + tags = { Name = "${var.project_name}-${var.zone_name}-kasm-agent" } -} \ No newline at end of file +} diff --git a/aws/multi_region/agents/availability_zones.tf b/aws/multi_region/agents/availability_zones.tf new file mode 100644 index 0000000..87d8f48 --- /dev/null +++ b/aws/multi_region/agents/availability_zones.tf @@ -0,0 +1,3 @@ +data "aws_availability_zones" "available" { + state = "available" +} diff --git a/aws/multi_region/agents/main.tf b/aws/multi_region/agents/main.tf deleted file mode 100644 index 83275fb..0000000 --- a/aws/multi_region/agents/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -provider "aws" { - region = "${var.aws_region}" - access_key = "${var.aws_access_key}" - secret_key = "${var.aws_secret_key}" -} -data "aws_availability_zones" "available" { - state = "available" -} \ No newline at end of file diff --git a/aws/multi_region/agents/provider.tf b/aws/multi_region/agents/provider.tf new file mode 100644 index 0000000..ea82995 --- /dev/null +++ b/aws/multi_region/agents/provider.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + #version = "4.56.0" + } + } +} \ No newline at end of file diff --git a/aws/multi_region/agents/routes.tf b/aws/multi_region/agents/routes.tf new file mode 100644 index 0000000..3d48abb --- /dev/null +++ b/aws/multi_region/agents/routes.tf @@ -0,0 +1,21 @@ +resource "aws_route_table" "internet_access" { + vpc_id = data.aws_vpc.data-kasm_agent_vpc.id + + route { + cidr_block = var.anywhere + gateway_id = data.aws_internet_gateway.data-kasm_agent_default_ig.id + } + + tags = { + Name = "${var.project_name}-kasm-agent-default-route" + } +} + +data "aws_route_table" "data-agent_internet_gateway_route_table" { + route_table_id = aws_route_table.internet_access.id +} + +resource "aws_route_table_association" "agent_table_association" { + subnet_id = data.aws_subnet.data-kasm_agent_subnet.id + route_table_id = data.aws_route_table.data-agent_internet_gateway_route_table.id +} diff --git a/aws/multi_region/agents/security_group.tf b/aws/multi_region/agents/security_group.tf index ec7d79c..4fe5d53 100644 --- a/aws/multi_region/agents/security_group.tf +++ b/aws/multi_region/agents/security_group.tf @@ -1,26 +1,30 @@ resource "aws_security_group" "kasm-agent-sg" { name = "${var.project_name}-${var.zone_name}-kasm-agent-access" description = "Allow access to agents" - vpc_id = "${aws_vpc.kasm-default-vpc.id}" + vpc_id = data.aws_vpc.data-kasm_agent_vpc.id ingress { from_port = 22 to_port = 22 protocol = "tcp" - cidr_blocks = ["${var.ssh_access_cidr}"] + cidr_blocks = var.ssh_access_cidrs } ingress { from_port = 443 to_port = 443 protocol = "tcp" - cidr_blocks = ["0.0.0.0/0"] + cidr_blocks = [var.anywhere] } egress { from_port = 0 to_port = 0 protocol = "-1" - cidr_blocks = ["0.0.0.0/0"] + cidr_blocks = [var.anywhere] } -} \ No newline at end of file +} + +data "aws_security_group" "data-kasm_agent_sg" { + id = aws_security_group.kasm-agent-sg.id +} diff --git a/aws/multi_region/agents/subnet.tf b/aws/multi_region/agents/subnet.tf index e8fce6d..598d6f8 100644 --- a/aws/multi_region/agents/subnet.tf +++ b/aws/multi_region/agents/subnet.tf @@ -1,9 +1,19 @@ +locals { + kasm_agent_vpc_subnet_cidr_mask = split("/", var.agent_vpc_cidr)[1] + kasm_agent_subnet_cidr_calculation = (8 - (local.kasm_agent_vpc_subnet_cidr_mask - 16)) + kasm_agent_subnet_cidr_size = local.kasm_agent_subnet_cidr_calculation < 0 ? 0 : local.kasm_agent_subnet_cidr_calculation +} + resource "aws_subnet" "kasm-agent-subnet" { - vpc_id = "${aws_vpc.kasm-default-vpc.id}" - cidr_block = "10.0.40.0/24" + vpc_id = data.aws_vpc.data-kasm_agent_vpc.id + cidr_block = cidrsubnet(var.agent_vpc_cidr, local.kasm_agent_subnet_cidr_size, 0) availability_zone = data.aws_availability_zones.available.names[0] map_public_ip_on_launch = true tags = { Name = "${var.project_name}-${var.zone_name}-kasm-agent-subnet" } -} \ No newline at end of file +} + +data "aws_subnet" "data-kasm_agent_subnet" { + id = aws_subnet.kasm-agent-subnet.id +} diff --git a/aws/multi_region/agents/variables.tf b/aws/multi_region/agents/variables.tf index b4075f6..5d59afa 100644 --- a/aws/multi_region/agents/variables.tf +++ b/aws/multi_region/agents/variables.tf @@ -1,51 +1,76 @@ -variable "aws_access_key" { - description = "The AWS access key used for deployment" -} - -variable "aws_secret_key" { - description = "The AWS secret key used for deployment" -} - variable "project_name" { description = "The name of the deployment (e.g dev, staging). A short single word" + type = string } variable "aws_domain_name" { description = "The Route53 Zone used for the dns entries. This must already exist in the AWS account. (e.g dev.kasm.contoso.com). The deployment will be accessed via this zone name via https" + type = string +} + +variable "agent_vpc_cidr" { + description = "Subnet CIDR range for Agent VPC" + type = string +} + +variable "swap_size" { + description = "The amount of swap (in MB) to configure inside the compute instances" + type = number } variable "num_agents" { description = "The number of Agent Role Servers to create in the deployment" + type = number } variable "agent_instance_type" { - description = "the instance type for the agents" + description = "The instance type for the agents" + type = string +} + +variable "agent_hdd_size_gb" { + description = "The HDD size for agents" + type = number } variable "aws_region" { description = "The AWS region for the deployment. (e.g us-east-1)" + type = string } variable "kasm_build" { description = "The URL for the Kasm Workspaces build" + type = string } variable "zone_name" { description = "A name given to the Kasm deployment Zone" + type = string } variable "aws_key_pair" { description = "The name of an aws keypair to use." + type = string } variable "ec2_ami" { - description = "The AMI used for the EC2 nodes. Recommended Ubuntu 18.04 LTS." + description = "The AMI used for the EC2 nodes. Recommended Ubuntu 20.04 LTS." + type = string } variable "manager_token" { description = "The password for the database. No special characters" + type = string + sensitive = true } -variable "ssh_access_cidr" { +variable "ssh_access_cidrs" { description = "CIDR notation of the bastion host allowed to SSH in to the machines" + type = list(string) +} + +variable "anywhere" { + description = "Anywhere subnet for routing and load ingress from all IPs" + type = string + default = "0.0.0.0/0" } diff --git a/aws/multi_region/agents/vpc.tf b/aws/multi_region/agents/vpc.tf index 383913c..4f5a78d 100644 --- a/aws/multi_region/agents/vpc.tf +++ b/aws/multi_region/agents/vpc.tf @@ -1,19 +1,23 @@ -resource "aws_vpc" "kasm-default-vpc" { - cidr_block = "10.0.0.0/16" +resource "aws_vpc" "kasm-agent-vpc" { + cidr_block = var.agent_vpc_cidr + enable_dns_hostnames = true + enable_dns_support = true tags = { Name = "${var.project_name}-${var.zone_name}-kasm-vpc" } } +data "aws_vpc" "data-kasm_agent_vpc" { + id = aws_vpc.kasm-agent-vpc.id +} + resource "aws_internet_gateway" "kasm-default-ig" { - vpc_id = "${aws_vpc.kasm-default-vpc.id}" + vpc_id = data.aws_vpc.data-kasm_agent_vpc.id tags = { Name = "${var.project_name}-${var.zone_name}-kasm-ig" } } -resource "aws_route" "internet_access" { - route_table_id = "${aws_vpc.kasm-default-vpc.main_route_table_id}" - destination_cidr_block = "0.0.0.0/0" - gateway_id = "${aws_internet_gateway.kasm-default-ig.id}" -} \ No newline at end of file +data "aws_internet_gateway" "data-kasm_agent_default_ig" { + internet_gateway_id = aws_internet_gateway.kasm-default-ig.id +} diff --git a/aws/multi_region/deployment.tf b/aws/multi_region/deployment.tf index d10789f..9d4b835 100644 --- a/aws/multi_region/deployment.tf +++ b/aws/multi_region/deployment.tf @@ -3,88 +3,175 @@ # This will house the Kasm Workspaces DB, and a set of # agents/webapps that map to this region. ########################################################### - module "primary_region" { - source = "./primary" - aws_region = "us-east-1" - zone_name = "us-east-1" - ec2_ami = "ami-013f17f36f8b1fefb" - db_instance_type = "t3.small" - num_agents = 2 - agent_instance_type = "t3.medium" - num_webapps = 2 - webapp_instance_type = "t3.small" - - - - aws_access_key = "${var.aws_access_key}" - aws_secret_key = "${var.aws_secret_key}" - project_name = "${var.project_name}" - kasm_build = "${var.kasm_build}" - database_password = "${var.database_password}" - redis_password = "${var.redis_password}" - user_password = "${var.user_password}" - admin_password = "${var.admin_password}" - manager_token = "${var.manager_token}" - aws_key_pair = "${var.aws_key_pair}" - aws_domain_name = "${var.aws_domain_name}" - ssh_access_cidr = "${var.ssh_access_cidr}" + source = "./primary" + aws_region = var.aws_primary_region + zone_name = var.aws_primary_region + vpc_subnet_cidr = var.primary_vpc_subnet_cidr + ec2_ami = var.primary_region_ec2_ami_id + db_instance_type = var.db_instance_type + num_webapps = var.num_webapps + project_name = var.project_name + kasm_build = var.kasm_build + db_hdd_size_gb = var.db_hdd_size_gb + swap_size = var.swap_size + database_password = var.database_password + redis_password = var.redis_password + user_password = var.user_password + admin_password = var.admin_password + manager_token = var.manager_token + service_registration_token = var.service_registration_token + aws_key_pair = var.aws_key_pair + aws_domain_name = var.aws_domain_name + ssh_access_cidrs = var.ssh_access_cidrs + web_access_cidrs = var.web_access_cidrs } - -########################################################### -# Add a pair of webapp and agent modules -# for each additional region desired. -########################################################### - -module "us-west-1-webapps" { - source = "./webapps" - faux_aws_region = "us-west-1" - zone_name = "us-west-1" - num_webapps = 2 - webapp_instance_type = "t3.small" - ec2_ami = "ami-013f17f36f8b1fefb" - - - - primary_aws_region = "${module.primary_region.primary_aws_region}" - webapp_subnet_id_1 = "${module.primary_region.webapp_subnet_1_id}" - webapp_subnet_id_2 = "${module.primary_region.webapp_subnet_2_id}" - agent_subnet_id = "${module.primary_region.agent_subnet_id}" - aws_access_key = "${var.aws_access_key}" - aws_secret_key = "${var.aws_secret_key}" - aws_domain_name = "${var.aws_domain_name}" - project_name = "${var.project_name}" - kasm_build = "${var.kasm_build}" - database_password = "${var.database_password}" - redis_password = "${var.redis_password}" - manager_token = "${var.manager_token}" - aws_key_pair = "${var.aws_key_pair}" - kasm_db_ip = "${module.primary_region.kasm_db_ip}" - primary_vpc_id = "${module.primary_region.primary_vpc_id}" - certificate_arn = "${module.primary_region.certificate_arn}" - ssh_access_cidr = "${var.ssh_access_cidr}" +module "primary_region-webapps-and-agents" { + source = "./webapps" + faux_aws_region = var.aws_primary_region + zone_name = var.aws_primary_region + primary_aws_region = var.aws_primary_region + num_webapps = var.num_webapps + num_agents = var.num_agents + ec2_ami = var.primary_region_ec2_ami_id + swap_size = var.swap_size + webapp_subnet_ids = module.primary_region.webapp_subnet_ids + webapp_security_group_id = module.primary_region.webapp_security_group_id + agent_subnet_id = module.primary_region.agent_subnet_id + agent_security_group_id = module.primary_region.agent_security_group_id + load_balancer_security_group_id = module.primary_region.lb_security_group_id + webapp_instance_type = var.webapp_instance_type + webapp_hdd_size_gb = var.webapp_hdd_size_gb + agent_instance_type = var.agent_instance_type + agent_hdd_size_gb = var.agent_hdd_size_gb + aws_domain_name = var.aws_domain_name + project_name = var.project_name + kasm_build = var.kasm_build + database_password = var.database_password + redis_password = var.redis_password + manager_token = var.manager_token + aws_key_pair = var.aws_key_pair + kasm_db_ip = module.primary_region.kasm_db_ip + primary_vpc_id = module.primary_region.primary_vpc_id + certificate_arn = module.primary_region.certificate_arn + ssh_access_cidrs = var.ssh_access_cidrs + load_balancer_log_bucket = module.primary_region.lb_log_bucket } - -module "us-west-1-agents" { - source = "./agents" - aws_region = "us-west-1" - zone_name = "us-west-1" - num_agents = 2 - agent_instance_type = "t3.medium" - ec2_ami = "ami-08d0eee5e00da8a9b" - - - - aws_access_key = "${var.aws_access_key}" - aws_secret_key = "${var.aws_secret_key}" - aws_domain_name = "${var.aws_domain_name}" - project_name = "${var.project_name}" - kasm_build = "${var.kasm_build}" - manager_token = "${var.manager_token}" - aws_key_pair = "${var.aws_key_pair}" - ssh_access_cidr = "${var.ssh_access_cidr}" - +##################################################################### +# +# Add a webapp and agent module for each additional region desired. +# +##################################################################### +module "region2-webapps" { + source = "./webapps" + faux_aws_region = var.secondary_regions_settings.region2.agent_region + zone_name = var.secondary_regions_settings.region2.agent_region + primary_aws_region = var.aws_primary_region + num_webapps = var.num_webapps + webapp_instance_type = var.webapp_instance_type + webapp_hdd_size_gb = var.webapp_hdd_size_gb + swap_size = var.swap_size + ec2_ami = var.primary_region_ec2_ami_id + webapp_subnet_ids = module.primary_region.webapp_subnet_ids + webapp_security_group_id = module.primary_region.webapp_security_group_id + load_balancer_security_group_id = module.primary_region.lb_security_group_id + aws_domain_name = var.aws_domain_name + project_name = var.project_name + kasm_build = var.kasm_build + database_password = var.database_password + redis_password = var.redis_password + manager_token = var.manager_token + aws_key_pair = var.aws_key_pair + kasm_db_ip = module.primary_region.kasm_db_ip + primary_vpc_id = module.primary_region.primary_vpc_id + certificate_arn = module.primary_region.certificate_arn + ssh_access_cidrs = var.ssh_access_cidrs + load_balancer_log_bucket = module.primary_region.lb_log_bucket } +module "region2-agents" { + source = "./agents" + aws_region = var.secondary_regions_settings.region2.agent_region + zone_name = var.secondary_regions_settings.region2.agent_region + num_agents = var.secondary_regions_settings.region2.num_agents + agent_instance_type = var.secondary_regions_settings.region2.agent_instance_type + ec2_ami = var.secondary_regions_settings.region2.agent_ec2_ami_id + agent_vpc_cidr = var.secondary_regions_settings.region2.agent_vpc_cidr + agent_hdd_size_gb = var.secondary_regions_settings.region2.agent_hdd_size_gb + swap_size = var.swap_size + aws_domain_name = var.aws_domain_name + project_name = var.project_name + kasm_build = var.kasm_build + manager_token = var.manager_token + aws_key_pair = var.aws_key_pair + ssh_access_cidrs = var.ssh_access_cidrs + + providers = { + aws = aws.region2 + } +} + +######################################################################### +# +# Uncomment the below section and update the provider and the settings +# in the secondary_regions_settings variable in the settings.tfvars +# file for your desired region. +# +######################################################################### +# module "region3-webapps" { +# source = "./webapps" +# ##### Update the values below to reference the appropriate region number +# faux_aws_region = var.secondary_regions_settings.region3.agent_region +# zone_name = var.secondary_regions_settings.region3.agent_region +# +# ##### The values below should not change +# primary_aws_region = var.aws_primary_region +# num_webapps = var.num_webapps +# webapp_instance_type = var.webapp_instance_type +# webapp_hdd_size_gb = var.webapp_hdd_size_gb +# swap_size = var.swap_size +# ec2_ami = var.primary_region_ec2_ami_id +# webapp_subnet_ids = module.primary_region.webapp_subnet_ids +# webapp_security_group_id = module.primary_region.webapp_security_group_id +# load_balancer_security_group_id = module.primary_region.lb_security_group_id +# aws_domain_name = var.aws_domain_name +# project_name = var.project_name +# kasm_build = var.kasm_build +# database_password = var.database_password +# redis_password = var.redis_password +# manager_token = var.manager_token +# aws_key_pair = var.aws_key_pair +# kasm_db_ip = module.primary_region.kasm_db_ip +# primary_vpc_id = module.primary_region.primary_vpc_id +# certificate_arn = module.primary_region.certificate_arn +# ssh_access_cidrs = var.ssh_access_cidrs +# load_balancer_log_bucket = module.primary_region.lb_log_bucket +# } + +# module "region3-agents" { +# source = "./agents" +# ##### Update the values below to reference the appropriate region number +# aws_region = var.secondary_regions_settings.region3.agent_region +# zone_name = var.secondary_regions_settings.region3.agent_region +# num_agents = var.secondary_regions_settings.region3.num_agents +# agent_instance_type = var.secondary_regions_settings.region3.agent_instance_type +# ec2_ami = var.secondary_regions_settings.region3.agent_ec2_ami_id +# agent_vpc_cidr = var.secondary_regions_settings.region3.agent_vpc_cidr +# agent_hdd_size_gb = var.secondary_regions_settings.region3.agent_hdd_size_gb +# swap_size = var.swap_size +# +# ##### The values below should not change +# aws_domain_name = var.aws_domain_name +# project_name = var.project_name +# kasm_build = var.kasm_build +# manager_token = var.manager_token +# aws_key_pair = var.aws_key_pair +# ssh_access_cidrs = var.ssh_access_cidrs +# +# ##### Update the provider to reference the settings in the provder.tf file +# providers = { +# aws = aws.region3 +# } +# } diff --git a/aws/multi_region/diagram/aws_multi_region.drawio b/aws/multi_region/diagram/aws_multi_region.drawio new file mode 100644 index 0000000..084fa9f --- /dev/null +++ b/aws/multi_region/diagram/aws_multi_region.drawio @@ -0,0 +1,203 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/aws/multi_region/diagram/aws_multi_region.png b/aws/multi_region/diagram/aws_multi_region.png new file mode 100644 index 0000000000000000000000000000000000000000..61de799c3fa5df9815a5fec71255e7cd995226c9 GIT binary patch literal 175040 zcmeEv2|QHo+yBf&wj@hPs0hh6W0$OvWGy|`EMu27YeGgPTT&ESq$F*!ugOxOvZR!K zYom>X?A!l7GjlYSo~NFk_j!N6_g^2MPjl`$bDwkW`?|i@_ge1zgz0Ll(NeQfBM=B$ z^&Kj^5r}0L2m~39aybHlIJ;l?I`|Liv0F_Uk@kfB0|F8E#Z%SL)A@j{gOd${M{FD6 z6OWiG_-yTfwR6Wh^N6Ayta-##ctk~Qyp?^0tUZPHDNB2c3c2Xn+F@KlGdRNq>uf_f zN6A1B9BX+wc{&K~wy|??b%D;ncj$aT%^mAzujOiO;{?vJK0x>dMnVEZ=*8NX*di(g zI)(bRbBC`@JOygdb2v!67zRx|&C9{s#)J4{LX)SfE4T%>`HfbtE-p4!p7Tz`y1Tpj z%scxh<~;up?X z_+(;(hdtKX)ratVd=q};++AJ4FIDjqw9Uo|8a;Si2*2C@op0yv-`&QAc-kFkU@kAyNfYa5zJ0*KT$=tx);Ty$Q;!egoV4dD7Dr{j;HKHv@s4GWJ! zAEYN>=8n+9`0hy?pv#dS<8P3pVgA?9-9UZ7-Qyomc;PYO2EjRE%C26XP7W?M+vcPZ z4H|*2Sv!DP+UDxy>J9|J#nlB&fU>=(vlBSNfR8@*4xTo8Zdfa5Vtjxqfi_!L7f+%- zV1Swtj)?;g^$H~36AP{d^$7KWp9vdxRc~-5XhI0*I5}b6JRB_X(*?D-+gN$IdpLO8 z?6&bBC>zuYWYZ10wDSRQuWt6jSRW5@VLNwMFE{X|ox3`?){@_vdqCYec>0=uJ6X@u z-PIB54Bs*S0Df>DQ87_*X=#i&=oR3S6G^+O%yuzVNzm?XDI^iRpj!4A5prz><1 zSmKeBjV&aT9$=^(T2K~j)>sdF8%XD&lVBD9rZYgIAT)xmY6GJd z)C9wtjjOYbr@JpWh4`(wBoG4VCorN(%MgxzNZf^~Bf0#8Z!20RPlo(MQX7?E$c zC+gv7<7ou}Dl{`o;s_}g%wfs=Mgn}yZzEy~X(JvuAZ?zf%7oTAHb zEp421T|FF#-CMePdb&D;v*8n#h5{>qa}fBE;^<#tCf37^KoV>n4nUx=H1N6Gc({7G zTiFm`4?w2JQUGXU1)(xQs@IxoWQmnMvLEYG9OMbQb3L%K>8Q(1Y8CWecxORg43vE zW##Gx+!Xw`Botstt3M~(3#}g-FmF*4?zl!ACP(o7!2fpLkjdO zHeHN(yWezB%g!0{?e%p5?_WsT@!mb~@BvxJND_WYqM!39`oHMg{%wEM+sz7Mbqfio zw3G}+2J$XRz0QADn&vL?7t#bnZZAYWb{LOy`WK@K1!!z5z#8|LxE?N6OE*wKPx82^WYMDB!O z@e+E85tmX`R{9^+%ehO;=_M2_BZw#|%KyAx!n#4!OQ|Jzme^7-F9!ecmlPAe-)}Il zWDK+pgI%P3|8*da^~O3lVJ#h;puplmLa=lZq)UiPDE|)=gt<%nmFU1A`NNpLfFR7- zeG*KcBN3#Sjt|>G;QC9VLj-6Nr(ekqN+NupB7pG!Z;J5CG3g(s2tO@PnE5Ur92z1K zCs9e_Df7e$j{p3MI7t!N?GoYyr~*Da03=HdpG;Ut4Dj(flAOk$GyA!SA2IyD2TBd7 z2ti@EC3qdUpo=v=^8dXI3rPZI5xi{Qjt2ig&xCIbh{1j6TJz9gVHO4i+ZSY9Yz~0H zJRGE0I{gB`&c;a@Yvl-KQCzGSPyo`PCUi#&!nn|V;_npeZbi%&L4MN`7Vf9TN@l)T zVc@g|iCkgej0CA%fxIu_^1mWiqKh3F7^dKKrL{5w_o-uKYI1$ov5 zuH%wHhdBg>;1ISM|6tsAiSUD%FsO6D-@CaT@mA+s9VlrgAuS;WMH#;1%Pj=*e*&W6 zi6YK0Oe{$zSWH@2Oq_5j(kX_g{a0pKj2M|9nc+nfNGJ@zPwPB)>wCsX6b(!&RLX-T z6fJ-b@uz+_AwOr8h(j>Pkx9k?<~gJTAVa)^UmAeL+-K1M%yYk%jD*aOX%iF1^BaLZ z1-a|_ZNJmpOPAX$;76e5&|6}5!>_%mGk zt(I_+9-bI}s~^Ev?#<=SNFj&NNPr@kRubC2{Tj4?rwZ=3TK*f=CqJ*23t|Uw;qAYn zri%knzpW>}ZWgbS^A!zm{RxFEcv_2G#>w zJ%EqLcr4Oc;GIHsr{4{)5mQ@B#O&ZQ-?>O1?A*brerE@3Yp9la$%^T35kELg2G>tR z$AsG?^+A4O5{RP?*Zz`>`cke1?3Dcqhk?tANjS{!1P@#~zfdgxW|8<0CwK_5^W%XR zQCLu5xmldE$H1qMl3z)we;{WM%Ion+u}E?(7isD|61-%n9D1 zga5kJ;Ll2qI2=#^Ny!lt`zIu4F(K1+cW_?1*24xY0{C6)L1b#MJ49e<|NBvP$l&2) zP5<_Sp#MK=J>XD02@jB13eTnBNW`x&0b-1iq@K#g8mv(yrcI%>7_N4%E?6hkZ>^-< z%jSTCry;EoB{O3LVnOqH;F z1KcS%gJ=vrvF>(Yg(JR+n3sS?kr^ z(ppN!@*kc`qEqzmPvv5cwHxp!8wp^A(V8GZKXeB-N1ciaIDB_9H9qEU_M- zia`{uqOJGm{Oxyc;aeE;KOl%HBQBw`9jX_BDfAC4p_5P&Ln}k-yr>@K=a$eB{Go+j z(p=1Bk(*6I=NBd^@y8@3I{#!46FBUiHs(NQ#FX(RFeHlr=OO^#1^J)w#)uXaGDx61 zQP?PxT5n=9kklE2nfR~RZVdYGSnqva&Tg=M2UR^_c57Hy16U)Eb+G~~V*hhXD8TY?C$P33TIXx-1n%10629l9Ybl^Q zHW)o&F@b}Jz1p0xJ4@gD29=`+r(I_xA=*3zt3o z=mt-7@cZLD5LQOmUtFxjb2X>)lo*Zx{~8e_UX4VH7cu&8iS8d*+VYc&OGvimB2w)| z4&HZ&+oH8G-xj1m-r!<0{_|4<$K7Fkg&8{uzRp1@>D0h8`YSU7Z(KNUVhC9JFK)f{ zr+ekhf&1^Rw?N(EqU}R|S5?8w(BR16Ke%Rs)Mdl3$b%g8|Dm|y_qN{pX_sFD_5)$4 zhk=3wQ2xjKg2l;pn4A5Jc=D%P`TfQd5HJ2l3yCW;=5s?3-&?S&;L_U?Ekq+Q`v9Wm z|C-SDEsOEHm>Rzw@RA!C{gZi!|1mt7Tg3k_;0Z?b?}QM4HIV@2_UEb#paUb2WP#)w zq@?jx0CVL9_#+5sq4I$R0e%~dwS>)*TSv-(k~r+r$piwSToAz%MgK)Tz+5VTG#*HR z{a>g6!2eXq-5pxNIJY?iF(C^g0K}ekq0N%P3DB5;yO)Gb3v7LerTBAOKL5q};!=dH z#<#s=33q_M8h$5PHF%5JZ%u!)x$NA~%%ix#2#{p2MgNz5kMAUxe%kl=X{s>iR}d!) z1IKzuRD156f7VTWG8n8mgsD-0z+D zpxEtS5#fb9M&M`S-!9Ypuiv-(=k-@o3SwIjnh`Zv97EJ95)Hu&K$AHikD*1;gljHJCVp?fi}{WWhOisb;&CRr5<-BHiAoZMk*Eh?V=Vk^ z{qR%}d)J-sr3gt7`yqBqJc8B6)z;PndUXtF{^o~(_W}Ks=K%{AiEV`E_FIblcS@Y# zJO4W=amb@0$j=fE^&%<$u3*mXJ4cir3CYEk7jxSZk-{?u7CTtb{?6-CWQfALlwAGQ zE04r}XT-mSK7YUR2!0{bfB!3wV4e73ezmZyMM9cb(nP|rFfg5(r^9fq%P;9L(W;T? zFaeiHT%qr5GBv0E3m^4+M)$ig277=o#avtx0EdG}pC8U9{nFzvUTL!E@qc@Q^YS#` z5-9%x%Rqj=N$GFDNl6CQ{DtcKT{R`fX-IHsDOiHren~Bfm-;hQ`mL6~)e?G@;s3EJ zi=S7^|Gh1yz)L^yKJaff{aw89|63gOr>!R>BEUI-^CNJ=;@_~Q#Gn9)n*QI|V(KTb zlIU8%MZ_edzLab6Pk2`Fe3Oj&?+u#&=|zQb*)VZ>VSyl-UQuabxDuMwdHg447GX$jlM?3V&EJ>i z&r@IclCr;1ZuXZcvmYoxBRuWTrp&-Q{RlrK&6)jYl$(i(60Gk3TDjR0Wl4Waf_^4> zIwwISHHt={91kyre^RiB|J}k(jQ&!r{>L)0@Jn|{rRv|y#1a$iBvu8^*8TsGiT%zv zlVoBg&_uWM7gMh=1BY??AIY_1;Fm>`Oy8n)=HC+NB>4WbI~Res{@QqW0286E-eXQW??A=@#KHAoCX3Ze0j~E zt%+G!3kadol6z%ZdRaL_+nEve&H3)Dqy7PwAp!4#0sALX#DoM1gB24MmLyhZ%ww>` zGhy-lI~iPYVjm>JN?Pc#{SOal$CGd3O4v7HPV)BrNxjEU7wODrD&TdG|GV3+E!Y8N zu`yaa`^5Sk(%o{v;tD*CTVzQ@(F?fFccbp0_yi*j=k8>=^O*JNq^MZLxt#$zRIN-xUg?iJfz5V4r%Sog~OIv5pDI_unr}!Voz!ngoA{ zk*TGTM-Ny$u)Wcr;m&_@of$z>zN_hgG{YO35yzhBN&ej#{YTXt0|&H72*&@8p8sv# zTdc+lR!aQ<6#VtBPy`KMpr#874hiS{m8BpQ?k$#=AC`xCy7^~olSCJ1a(+Y+0qy*6 z)kUH>FCJVX41xvjXxPjWwNdClOC1R^L;{^KQ-kc_ywK6lx)%1Ho^BpIVoDIUi*9!W zucHu#*44OrxPt$|t0@SC5PU_r5`h&GMfw{Fm|vu;j24E%5oq#_Q zhTi#2y8IU+2urVHkb-zL>8bcmp||o98u4p=;qu~z8DqkJp7Wd~k}75RS8!4Cw|zc6 z+`x5Pf!kn{^mn`!3}$g?1QtfG z9};*;H=x}hIt(iW_+$t9c}fO);P+ZyPM!`zyKU?M#ek5_2CO)>b#;f{#iC;4=H%*2 zTK*2CA6)Z0qW_=qj+QwG9HP>AnfR_NJKr)w)ybq}8d}o;9mC>Bx|t|J?MXxJe?z2* zQCwK27T5oY!6bB^2TVNgCu9oDn!Bqjm~vGfv2EZ0l+wFn-R!kot!k;ZIN_!5N^(Igi>{UHG)Ai9WW>xe_oW0vJvdU+rV!WGP zq9~=6ai?lcnOj~{Qf}N7{wSJ^jD>Xv0vWPNscaVoQZ^s?xhWyWk*NQ%Q26hBYeD%A?rxX3zxMZTC$?Kz>`5zq1%r+{b7W_GHuxQ;) zBd`I3lzZ^C* zO7mA}X`!;2=qkF?Mf>s%V&)pP#tn@s7QY#`vbHmR>2{+EsOHl4#^nB(@G}SNZtOO{ zV1+YMQcsR7dN{FZlU2Bidcf+s&YL3*qR;aM9>3cyzKh2pcg8&aKFf19t`*6hy5>42 zhl-w;QkPL7guhl^@NO%c*m21j8i-@(R-Xccrf9J0qV+wa^LefO0uwW;)DOa zcO|2$t$8+>H`ikN-<@VGl?zt1&qXlCM8|vO#GJo=0VTM`OlaWgW~>sj@hG>L0F~!C z1i9fgKiqH(^t|4bV~o84j7c2A6YHO`^WoZ6bdNUiVD`U_SslRv>75xrgM2))L+-{_w?csdgC#k za#|po@`~Uy_g#;Z^9rwCdLkLnGgBd=MWKXALBkuXpW0hNTW9+>jppV&9KSnd5-S-& z_vp-?L+3INJE&h00Auf^D)np!q+s?kL1TkO8(*EwQPJTIXgd=er#bl6{q?2~v!XY& zid-M1k3KnCEMj@2Xo|<(fh<1s!GX#8UgXed;dsL8C>)QF#_@jBi0o0m0xmO^smeB9 zn;kFe`%ZcI3U8v(FzDAeW6O7Xe#WToaWt9X-HT(!PWgjs+!pkQT)r(ZDi(kr> zx%vAK7}OeYB<`CQK~;|%-PJK&r$0&CFr;xv2W6@T5aH9E{?G<J54em6O0W5RoP)bpq>l=%fuzf@cm>Os#uL+bZVEYSFmOThFpG_@dsyL0c|{l5WBB4@ zpl^n5WTfkPk+M#Pr?U(a!+q`Ic^jqGA5E0n`3zoH;1x{IN|jEYjJAG)xX|jvf(`l9p7t$ z-aB#Q)z>Z*XVs}Yd8xhT>vJ76iZFECgOl0SyRNif=cWmNS^J@^jiu_`Wv~5@s_k`a z3Mc!+(T|Tj-ZkCo)rf3`uS{lVDB@PrELWMo5)Yk@|Et#H2uJ9~+&!0J_39ZfAvEfa z%Ru&Ey(`(igcmG{o5r~`Mh-phUKjf6VtvFWcfSW82X3<1>}XBoeI^mMDt<-c%K^$c4iu5eRwg#H-C^`p(tcaYW8={c`6 zEiTzlA9qk=)vfU~5y`0s`ctDXa=B5l)@r-S1fR&voXD3Bc}f|-F8IW(_jJheTFQ(A zIg-$wevAyCl5YaI?A}rA#17#i8U6L#qnjPpg=$_@FcdaAacMN_Xxvw>@V65;Mi0L+ z=1T9xvNZ6%5_&PMdY=y5QIIEz6h{YO^>{f-3eK`xqliMMMsv99rcpgtxp0x7TIIjjEYG z^!l)9^6a((GFmfD6;#I#pk8bJA|)a9!f^&AGd`ZGk69V*=DRUL)~l}j#)xUIjc;^% zr)*?2?}RX0w}{Dcnv8-2$J-kBA$gq{Wv8E0ZClxM-J3e8PF7g|_3$29IbA(mnB1^- zPKhqSAQ;x^u4M85Hhi)J;DJ)7BqN^Qil%~Ti0aI)`ZkrfgbHmtvR z*sy=JB@_{}$>z$m4l+gRSaz~7B!$5V+hZVYQaq(tzY$}0S2Nc7{<{$|9-(v(-+fd< z>Tk4%hCW>%y?AvaGL~tV#un_8be)wGtB_p7kJbIuHJ)Fvj~S)sFgj$XFV>IrNZs4U z!$9wj2n(bPZWa|7N&2*pe&gAKqG|V~gpF%#)U;Z<|@_ zXVlLPuYBcJt@4H<<>=SI3&rN!i}iM`4pCrMMI~$i&$Z@r>KP&hs$X@Tg-275`MK?R z#rh*;LJ_z6FfTSIc0+=*>JowmSH2NqRwu1cS>~VW+4Ixe&hcvWT0g$HH+N-!Mn@yM zb*+kGkIjB$qm%ihM{&VP*Sy|K+plVRZp8`c^BFPR`bZA6xBFn$ z?wHSNPp$?-Y4m}rRcS%HA80S^x0F0N@Ah}B7XUbrRnM4nWI_8Vgb!U6PU{y8^#Ab* zD3E0vYwJsC`1>GUD zF3~{hvoJE|M1V;x+L6sk`n5KY$WLTmjYel6H-mK8*VlnDA8ao&ZO$V@dhg7{shxA! zc{%h3LU^R=B}2I_PE>?sG87+xv)Q&kJbruqDi(_h)W~M0{RZK8^kbiEd-^g|0Xu{| ztxhVfUxDg;$h20cCOgM$QOVA67TedrWI@ewpNmv>_W(t@@!A?&%V577C#NU)a#QAI z-EtJ7?NR9(q+^~zd?JaUD1rx!XI78BqI`)T$*fx1yDNp#k*0@@h5QOa?*kjNGKmmg zQpBM&kz5f^xphr(XL-=x6`|(@M>Yk5pS2&#%z7W5WD!Z75t4WQ5IOF)+HIrRO#bRL z)1e|M4zY@J_q*2$$$$NP?VU)>L7qtDNV|RJwb`@&`Oo!+qGpHBr|59nWU!W*RC&vP zzNW=B+UBevM@#OPkXb=@_sxfX!Dm<6_Nvp<9eL<|(0zud_Dp&EH}!s61jg}Te!p1D z;67BUVA9Cx4$~)JERjAeg0|aK3}q%(Pp`#g8uo(QqeRo2sOm|ZS8Z;79j8iprs73p zC9}@SS&_5;F#LXf)YH$_L`lwmp`eRDKa#hK2E5) z0=k2pXYLDjZhj^>UMiwo#nmTnH9+C`WjV{hN2#$VxC+dbUF}up?$aF?I@GS3wV6IM z=`8 zX>|n3_A=eHh%oQM-KWvkea!G6%TUI!Ja*FO9&@_jx%&=R8dGP#mNjd6dsuFFYL#}W zp^KzkuOrxy)j*{{FMaCz=5yx-xHMF-Mk^+`ZkFPr_ztQT^KMrqhId$$<@Ygo_<2=Ep8o*vzR(xOKDQpEQ%MrbQ|8Wxu>Sqi)6qNULKKGhDskH5sK$o`pn0k2)aE|M@ zE4VXH6lzc$2@bX#_-u?4%$mJ1{_tUS3gV3jY$1UHodX7mQ=ZwCSJMQ)djy-?lGIC=ztL%C|Eun&&OZ52FRMt?lJdwbzxc%KMQPJ!>LvG`@T^I4VG0F~boNj8s>^L?Sd8ga;l- zaRup@lR18oWZ{WO+FSW~qu;#?n})azpM2g&FEC!>|Iv~u!2LslJzMU<>HI6*$5lPT zyvYQON9-}TvnYY}uDG#NY^PQ<4(KW5u-qN;k? z^bX@^Oi2%5&Ww*6ryKmK6T{hpPt0FF*{(XXA0>zp(NH_*~|{$ft* zbCe)I^=j2?ci+6>&SWrI$;#r8HpI}mEN|-}5 zK96*{tQvP2!5-ryqm8RAc$Nqy^{@51F$ zIu%>yZ*_cTx+~|_RTgqXje#sTcr1gUxQs+_)Y)8MZyXqF^?gk)7Q0DW*yc8Frp{;_ zwD~ZH(6vCL9glGi-2{|PPwm_dlp_s#@=cKPe%ruIGz*$S!bO_g@J(-g42+`dwQ(A& zJ}?&Y>M~nAyGM2VPB^(>=Xluo)d%Yi=z;aP>3^YI_^FEz-va>-bnEBeG`ug&t(B z*<0xUME>E!h=a98`8sRFgR3W(Q?ENXFhwW$Nu@uOR#k7T@UG65@*dr_<{l#)&%+xp zw&ynJg*TUtpJVWaWDit9%RN*mVwrQL%@s3;jOT(cDhcR&lby+WH zc#w^wM-FpLjYYisT%_XUp=KqHbBo*!@tRx9-FyLIvF|4ZL$B=Yc7uEBQEr^JS!SUR`=OaQ1|Q& z!(HyuJ`+m6LLW7@5%=)w1+HE%hJ-=BkI%@u;(cu{RMX^*A+sB|Zcwgcb;1VutTmB- zkW_FhLh%f@>9yfvONBnQ$e8rBf6DGgJBBMe8;{ zSLKO0pwW`Kb(ccfSLg1b&?W<{QCT*<==L(@J7*mry0*TF>;R=&T2Wl&6-0GD-O+XT zcZF=boYB0JiSO*;LI>+APgG45@4b~J>#L`!(IFAIfw=YCQ7cBg>7{zkybiFrmz6*n zH0a~;W|lc<71atvfMf5CT^CUo&!`9P4Gj%F={aDp0pbh|^k+;M_BN?nT4l_V8@cl< zXIf@AGcZ~lc~cYo;ONiI5j&-Yxk`7j(ggsj|! zT=%8642}*P394B6`npKjYrnF+UpEVTGmtfBgq1{`c+o1*!#k;sThkn@Z5?)Ulc9&l z#uGQgqBi@LZI+B1%`LosQRKkUn9{oHuF-DQvJ;%_j%nV?72PbdrYcW`0-db846h?@ z@w~4}%DOL4+n;>(DzIOicFkKLxq8YAl(ALC$cz|3ei6CL_^{!_v#CFt>WW#@HDw4)BYV7y5H?@YAj?5b!$J{v{vgK*At_Yv(qmDP-=jEy9vUrauT z^}fRseIh?X^k7KZo>-wu)y(R(UHui?q+f&}m;khF8U5*me=%=a@B5O0U1XIO`*)LR9=y%oHy+yC65b!MGaRRySP{#yvTd2Z zS=Oe>X0!#TgEw7#EW*RDtBO87JGq$ImX7Zz7m~SvB6V-&KvsV>%U${Y`<3^d%;VkZ z41JE%=R`vwpS1%3e0H-yj(Q~UKiH}?nP1RotRlZ#+FNVv-+@@yXW|&rm+Q{4$JP9g zT)kBR^bF=B??tW-X)En@vFI^&>^eWfq%z8xb1+Ze;|}&3J)8dn<6hot>+i&DxFv*S zXRcja!Xj*Zh&91e+MlZD4QGG7dempK9WuFD{<>Ssnv3lA2OVPYOoMne26D39^w z26kt)C)91~AY_%0(`Ie}8hj+|jD~qaYtOWuYwx@8cJfqKW6rUwM6_3&fp~MeP77BQ zFcKvlK`5u|fdc*KH?N~vcQDnDjV`R1LPPs)K?BF5Qz`5zJOr8-WClrPar>m)Q*Y`F ze;@a2aqD}|3!A9H9PBAA1PfAMchj}(K*shzN%N)*L8fJrXImhqqrO^MY+jC8U1`?N z8u{7yaI@jsvk|b(ykr9Gu$N<9_X`*5j0@gQg+^XFN_!mS$>XWFe{X``ato=)UsgbtiOk0`6Nhn!s-iir1LHU@<993Jbq!DGjXN=6 zCR*V1hNH43@^R~TN3t(djap27DyomqJk=^>}k+_ ztG6D!iYH;fKH&ci}tsGt8eRCEKZ*IV`?hey%gqn`B$G z=VMmmUU~b8lmxFqyNjOPs*+5#xtp4~rw&fl3DvwiUXk-kve{-?N}z#3V_}@X0cx`UvmsXD%AuDJeMg5EF2P zPLi4N_Pw2k9$xOPTL3GGy0?$j?=GVv57ssfS20$A-uFW9CRN6UOgrX8`8NmX&paD$ z@HMC*@4d*C)Hv)qcF}*NJ4UCuX||JXl6l-|hyUu5{;DrSve=gEeKoK$Zy@_h&Z?ud z;?)yz)16@IHDraK_I@@wZ2u0iJ(gp_uXv{h1C9O&?(yJ*tBAbFRjhvEsb^^|&Y#+` zj|LsKbF~F$UYSS90ZiGahzwaaE1gx?kp|y59SXNIr(J28*&=SMu;1=)`?3MScRxJz zK^o3mIeI=A?8}fB+L=6O&hhhq9Qi*YQZMi+30H5b^K*qe%gX983RsyjoY^m zxV3x`(~e*FezWFw;^5IT0!gG@yPJnQZvDP_I=0@IE`EA{W@t-5NqRy#Tnj+%kxQPU zA1-{Z*rK<#@%1LXvUaRx^*Qp4g5|-lHOtt=+b>L@RxmfMJ#s{)W=H36Fs(w+Jrs?< zI$1MfB2kd$y4b@NCrUDNw$gtgi>J)ip$o9fkM0hd_I48~JH#^~wLDM9_%JI~Mzd)7 zfgC|~Tw$H$8rA^&#}{AG=PWNe+CoH-OAvLWy<$}fiUg325yhS3l2J?+BM;F9EruSM zrK8ns7qYN!(}yw5Dr7D7T;Va)^iIJ;e9zB z?U7+Pb?EC^36moG7?t>{XBqBa)wwKqPVr1;s<5tc$Zmv92N_!||14*RAL4nI z^HGF=TA>Aczaht<@4e1H#sy~r6$V24KhmIOSg+6>=@Ms_Li8l6Osz=j&kpc*!>Z#} zkBr8RMKW1jy^7;{!bWdlS;A<#J3RvAkdLU-qnqCD^Lvyt5eh~3p+Ch<$N*%e-l}aa zVx}w%z~#QLt$}rKV!yvj%kYeRoSfOSKLlIPhS6uduZ}m|7LSOCr7>nFKQh3e#fA>> zp{2?=NROsP^7`HBHAt1{ahn-HOWFHU$C*^XQ7_>r8ne3F_s!u{n zOny5xXoB`7U1!S7Dyry`)7QbNpXKgaCOMc>vHmDXV-YL_Ed!((=XOb~9bI63)_-79 zp~oI+e8PVT{hGXH_$H>3(^~86VcY(jART?ipl@=O(hK{RIaug`u)xIcgtyO8U|Q8O zM*Xioe)!bU%E1hG#;iuLnz6gs?AhuB#YZgcj-#uqiBE2eYDH=Kk<)Qobo83ai`s6Kr*Kh#{ zz5K*Jh`+;~QjO-Eu-LfFwYo89Cg`ZWr$AfT*_0^QV@^&L{>d zuU)(PvK-Gmq@e3duD$b`Y)kiOtK4OgvIEpf-s>{&t^n4)TGuWI0Gm>(NLhQt$!;>0 zCi0n15yys6uBu z+@}2*FDUW9Qd^lQzm~a^>gG=J$qF>85p{ihQWRPiOsa~07-!U5ny7KEH0xj!7pZHL5-y7NN zKK&<};^H(yN>0k48QdZ>Z8L?Mui8FU(a3j7lt{79%dM;$tl)OML(Z2(JF{;v@wOi0 zGezX~(z;R_@8sZwLBGCA0?#Rg{O?bnYn|TgMAdAkK7y3W_swMmBZQWKQW(U7Y9R(-5EttRn>;oO$jCaS^unwK{b3N3E(%LvCx)3f>HWcvh*uXg3*q#|ng zkbRSPMmQlpJz?6E7miAGEE0a?)`t|lUXN30UFM~D=8qT<5qg$YzO($+9fYI#okJ#D z)!9~=FPBlqsaEqK>7yJcD5U!HmyIs#sj-b+ug`^Gc2|D=rTX>f_eV}C3ou|C&lPfW zVVNvy3j~JpaEj50D_!{r@rW7;{I#coQG!jMn*x9<|EWY?!zyzG5u5Va*ddqVqiyfU zW0Z#LmX|sRx`fi)*o;cedZ$ssBH6H#KFmYoI2mj2nN{NxnVGhE!E%q7YN(m^=S%3H zh*fwb;1Mh_Vs90xQhQ7oIE3vIO}?_ZOal9KW>`6bLrOE3OAG(*4ed?c>w*YU~)71dgEx zme2MMUgpI4`_o<5GBF#SV?TdVAK8ry{>t?{2RMR;ZMxZ9QHrt4KNcVy zM?V}}sgZjSIXO8tFeI$A*KK^VzHv0Yi;7taWovsyV^yStS{%1YTfvs%y0?gvN1X3z zAFeZ|Utlbgi92|R{C@+#k27d&+J0+OlJ|G8I}QS{ekZ0Gh^VkP$T zD6cHr-)Om<+%PZXvbL7W82kjg$Vz0N4gir-opoFKrAk4nd*_V?ght!<#xue zi7(7Bw6tJe5#fENgkAXcN0l<`q=G!@o|{T~Qxm*Lf?1YNd`Xy5VjoJJl?goCrLa!^ z>+|QwGdlU1w0rWUP1E`(t81HBOj*P2tOEs9p86B;B#j9KiYq)1E(oCzoC^5?~69Hu;}S#C~L~Cub)npk6SG&HiZ}Mhi;Ealx z83ngR%fN&-$M#jgI_FOYY(+7<aH>7u8Y|o52;D8mN<0-qiuUy)HCmgxb(oMt z3c-iv3L8%isVC@a;LdQn*kMqOzN39FRK(x1PPmNvjmk!QKkB#3<;Yz&iu3AxS8*6J z4WF_PnO{RZ|GYo8i3xbDDPJ%iN650|b)}k9)9PZ;^j>~NZ{x?qs8EjS@3Y6$!>%5! zGqkcx@ul|wp{mei<$H%3jfeOUv(bo&0ppPU$M+tV&Z&8ZvSVJ+Sv|__)foWc;Rn^4 zZn?<9fyuXet7=R9`3(CfioL6I`#-e`9030GQbwsU>sC{>I)jD#7-EHXP(|&2dS)S2 z6(;hSO>u#@kKVfnDv-*3kp0L{!-p&;+cYf7J0I>I{yI70z0C2GJF0cmt52>Mu$j*m zzG8_eL07pgcja1_#WM@_1sPYTnThc6Gw9l88IHK{gk_M~YWvrsGTw#u^Oqg$s12C;Mh!T|I+J-Hr)4xxA}*-V|96ggpJ_Wzx~N zkF%Z}Zv-gun+rM;GC9uWKvg?flIeTb-%%+%hCaUY=ve-|bDBj0Y)gYts^4 zTWPOX)wf}7pZ2$P2o&qBqkCnqW3GqG4H0vs0uC25W%y%4)xjQt)Jg`G+$|vKvh8es z^cD$vT6znu?4BbbDfB(LI3N|0b*WuV{G=08)4o0^mF@+tnHI=V^c>fM774nHq{R|A@O!ID>Z#v@F0g(Efw9ivo1X=;x<^{JM+5)u>8tdG-> z8-{QkZJ>iHiCm+ea+c-TJJ7vQ_nrH)IP2HT+uNOlTsQ-JmNnVu-fF7`4?M!z>oWNvu%ja|rv!uY9hlVb zXj*$^izo}RrUTS#kaN?ht6y5ZZ204lw|rIE-W3+RcY4G!M+9HtyD7 z)9Qv1`t$KF_6|jl_+U^#7o>QN6XAK&jNDp~ivoJQbE94#^zjcUGnV=G1{ITq@5kCx z&d=~8NBiPdU7PRCpu#)81Apv0E8#s*NxPP=#ealbAg8s;9f}fbtrwvWb<#`m^5wha zW$tq!XEZ|(*WIzKC^Y~mU?Y~lwt=&3x4yYVVWpz!34gg27A8VP7bw@xc2kVj3uc>C zRaM6{yS&np%~k>-%C*yq0(Z{iDg!$BF3AOg;d7a-N*D%3RiEmywDtIVS^?dYO(t?= zN7iFaf1!!aDfxIU-m)~4;Cr*h6yDuK4mF8lpN~`6UVD5pB*&O>7fo;2=741{*_H`L z4rSrkFJx(<)KcQ!JJEd^Sck~TE-r2D(ef*KclKHbr|yJF)Yy52M)CKq%vUp=!jNoc z5~t!Q%-KeVU!i(W7**G`nDh;=0%H_^_3d?9CJUL5HAhq4dQrU=F!ycJbWCM0!1OZQ zllZty?Ah!H-HA(>u~Hwa2Re0;WJZr{us-a8l}DnECf91PsUmq_d+Dzh_FH379>kaT z)hPOs?L_@i=}~|G*-ybEm1K&aC#Bx?nIbH->mOV_I7)GQf4-UA?HM!3@zFr0Xq|?c zJfxep%Rdg*Ke+bh8b|mTn@4l^Ce1@)lAW^amPO5ohaXfI*CaEV6;8yN4zQ$_&KzA& z&pUbVpfi6`V@$IaM{mh>t@4; zo7P3$vpXb}WJzy(p50FYwru!Zdha0Rij;EaHIw7!>y2#>RLlHP%bq)V?aGe$WC0*7)F!3e#<81}1wUkE z3{@r$SbSW2llhupoE0*^#?6d7=7eB=WZp1y&|Q`F2X8esx2DqD_mo@|EMsoze%EW2 z)2fb4QH}1t4szvs_u^ZW2fZmDwx*Z(wOM9vs-_Du4QRW&%xYy3>XYl3<;Jv|rdgWw zR+R=T-?9#!qS1|?0?Cz*frgbI4p_IZq3exrS*b56_*FesNT~1>RjHO9>C+n}1M>)9iVJLY|QD~l=+gF3)Yk=b!)wo^D(w=oXj-o zqX|G<>L}4}xYe;TwkZKZ144ZLn%eV^>j4{4ioYYdt21_en!M|~D^((9Cni)>;(9-2 ziIn0ZNB90AHu1-8M%A+6V&AA8p^rN;^!p!>nO**p0;kzeb4ME;d-(#gTk zYmLGm-SVUCHI~oqo5*?`f*eEPqLz)VL(EdXY#tOKYpgssycxlVC|IR9CA%8c9roS@ z@p*`PD?2XR;3_BLkV$fFJ*Pw9IgP4SMJZ>*gvi!!ojsSbDy5bWNmE0PURJgtCCBp8 zM^$7a=Q=Q5basslppsf}6;sR&hNlb`=QT@(w=`rl-dpRiLT7V&9GM}dfUIZlV0iMV zZ}91R;vC#BX#_F%i{E;x8)=3r`YGT%7zLdQ5pDftQ32C=iBq~KhUBjZT35z8PkApx z@iPtb_xsHrYU}WL=gb#uyNRZtT6armC6yG`hYY7@%%iK<{4kk=_a(>fjs44S6>7@9 zy=M?|o^emWmC@mS!FZZM^Km=xJ{Caoyia}BgxHY202{~kz}azr^T6lKRweIyDP_jd zk+oc987_Z#ZVD;-Y;>pR(sbIy1D*QQ4{|o1+=b$@*Cu!KZIKVN@8F`ifjG%>K9T(8 zlR+P0YA_|pUD~ZOWj8$ ztnm7++If|+vAmr}pXBaJ+Qo3jT_aT0T0N)V9CtAY74d8xd=C<@KI$JI9V%@5$aZqW@X1rzQNo`F2w=bK9%*7QPO? z;L$%q>7t$rspb=8K%B?DBkpqCA1IGYnQC+7JANw6+*4I!)$FSP!_hwOn+cYz?f0@y z?^-z&x=tf-Hc|g`Ufr45H#!VQs(bT}`uZ}oIk&etrHky?*vez6Szc*?V5faKiIDFP zqvMlwp?IklaKX?-?*!_xs62~OjA%@Km4>4#F6_~by!Krx@u5n5h8HOJ4?lK&)_un3 zY1qqX$_Lrq_Gd$rmR0wK)1X;8hOYQN)RKL9g+=IYcWK^Nl{m_4`%Wo-5blcIh%HD5 zwRVY)*^J)xGgdd7-zV9hZ=?@$_Fk(WcMSOCY{rir07(VOqb@!{B~TC(&sDR6`6?9P z$$Z9VlOHhQOi}VK^8Cz!J?0-Q?!PB1e~^wyt*G=%SKi+;D`9Opdww*ulTP1%U^c_- zM6!AQ=FN63HzS)rJJJm?l^?qp?PL|A2-(wDwlp1}7jihJa!+N? zIH(zrk*XxqyPdN;R^>{vwgMYV-}#$^2t}uuuj__X&Tfp`6t9xAk?mc-Mnv2v8f|(U z*VAKEXjiJF%yHepfTeBR-5nE1N$ip|hGk zmJgZ<(Ccy8TFWG<+=-6us)*|@-1JoV;tu=GD9JutRBLelR1FTMt(+n+eE zn!Mo!YgvNT)14pf4!baZUxT_u+J4}?!tIIAIk!0D3HgUL^ACfJlJ1G zNlzDtkS=6*9vJ;YT`OzFQ>tvAxGPpJuJM$~pQ?Hu4ZeJb@W1Ady3i)lbIr@I?CncB zp9#y;#Z~;FGo0eHFO>2rv@YH)AH6j$`FJKrqk4pg3f&Sh{3=U`>#p_qn_?uNNaGfA z4CnA*+@3oDt_@CKM{yOSk0hEt)g-8+e0{$()C3fBaDdrbS(VBi55yI{nRm~|r!|TJ zZO>fge6BfHCKP_SemF^$J7S`=`_q@#t;2HJvjR*h<-6LgCNWnMj2cP?`2_LZxc z#~(-3-=IL4757PdWyW%sn=?Mu(|&#{vJb?9hFpNLwvK=Z0=kdWj+lHl?-6qZkpo&6 z+e;WqhKg2)N>6@w?c$3>37RUW8-CWpoxM;d`sNlls%4+VDwhpxSh6RI;kr`gI zKf?{Y_7Ih3YbvXH%v2vb3YE%n+DJ`g)))3KHV$;2tml3jk_}X z%;b7B14ZI_A9T(5(rzCeEq>P#CqLm>>z-|<|0u=~tTq_s>eJ9zFQQRapLhO)x?&7a zT3)T#Gtdfx@z1aCQlmfQo|hl);qyNDW~?v2ImbMgF>$8tprC2yOcvdt$pLW@+dpzI z>jejEs_>U>X^vr|7O*v5NZ(A}}b5=42Oq# zaH-nfGiM(1gr3L}RApCuRqEs4G4|M)OLHVZuE=t_gTicD!Ou2b%EXnP-0;(y>|-Cv zl&7Mmpw(7`uSY?WqbL#hhw~EQmn3vWwtQaaV_KXycBL=2Ky=O+P~h_R1rIIwkJ18@!WnD%t~1EyiEhcvK^4 zI2AG;r*z8~k-y#KI-dRFw3(#I@I;ikx%=>uz?sNo=a$@|wVk3^xkU%$(?bnwa>YC?{n|teegw1=0E>3#`wzkEr~sWA++xl&+JA_0Y<3{W`Tmza2|AFU{#8JYc`H zKD!|=zgsGH{LK4$efOS9wk^ckvysf6yO%mf@mG$_xTewP`X+?}8kmutk!UrZlfc6) z@xl6@A{_uh-mv|6X$U|^%ms3KGW8tH*23$H9J^zf6)jYs_QbZueQ;M-YS*M-X99X5%F^EA#$&OJF+T9}BxB?k?46yp?{f^-q9SHih7DKim9f^9{I%T5-0yP( z;|vg6r*&EH-?L!5m2;mUXppeSH?*Me7QQxH1rVv@OPj{S6}|U9x`wkkgQQ43T(|TS zyjFm(@{9fSV#n_T78|P3KhW=QS~QCm#**dAbnHEd;cw9l8JpIfjl>zV?X;EzJOpe7 zNufI%x={9iBCF=_bqdp5$ZPD|Z$I_LKLN8y3%h!P(Q`LyF4ISZ9&-#<;oF5wgewx5 z@FYj$g!zQ7g)&#Ms3(RETfSaPW1$%`9CC+Fc&EvEXp`y^(rI@DO*hg&DvWlMJbhjv z5q9QgBWMKQy*%;e4{@U8m#{XW1Wch|nh_Zh)X5(OxevZeixMY>>J^zE5ssbq)9qGW ztjzz&jMWxcE`QY=BQz~dS0q{d*%%-uCBGVsg*?H46?xL}n=x1AAp3Stjxuiu+RVl$ zOQS##Rf(4qJi0`o&TK$E=PwfmkVdMSe(y%gqnC!bfe5DENLC~uKDBowvmit5>z?}H zA1{DuJoHOMQFx9YayeW05)vISa(1PT&S2{}MD5mU-^5~lRf7Y@t)S5E?;VDJh!7E! z8jS!R5vqrO1VGG@`Os>DM>b3c9$+fu%=3ZPOkF=I-Rg^4eYre<%*k&4YjpqNgXs~T zi69xje#YI8y*2IqGAxW9TP&$^QTlmJmqI}^kr zP|Ls=xa<1*nwwJM%KUMiTCc2lV{*1TL6xT_(1al-BLQ=U=f zOeL{+S2AUvVm%($_b4W!&^8Zm9_0Lbks{sGHv z>`3biyQlth^lL=WHr-c6T)=zSHjsAIDU^*PnJX9qXxcaZpDuo%Kl#owz(bCFjR~;X z`9m`^OeAWJGC-yXMi_dEIn-`#5O|b%LVY2o^;%h-+svGya`L4MAYG3R`%d6!@emJoJ=Qw%fhB=!TjQM6XF1V z#~ylkfBm|ooowJiftkhl=aoGnoUkBmh)Ac*Q33ayqlxx6LHO4@(l(Z-`p2|nsZObq zO{0Dgvy2~I9uwIW?_K5Pmm+xBmhZnaecC7xHN`nDcxE<^B*tBwClqeiG<({q&eck@ z1YqL}sUoWz9ru$SJXOCozm+QXCadz>iiw@-Sco`~3%TK$!-Py1QgG}hX1rq-768`~ z)v=!5QHHzy`_W$}8Z!r_K)yC#>iGgX2JbE~paSU;UZ4om`KgUmqH5K(zDN4&iJuJ% zxQnrgn~oB*rTdRD7|qgFOwBBbO!J-`{oXubTW5VXGuc%f@5L)Pn*Qh4iv#+g#UHUO zM)e1ss`1EuqAWywWwXz6>O+;);f3lbmDfYR*G;Q^jW`ZXjSrMIc`=s_c-^oBsfIsH z1{RSSpd#yM2P62JKAbbZ=?;sUN^)oS8AnS4W^qQK{g!)N`UBDw3BnAR5gJz@|Sz%+c?e$TM8{vbNV1ozlOG$bi~zqxXX{gGBu(!m6s|Gk&3=(XI+C7=BNj> z4_P%2-|{5d#KSxNx;XY1Qub?=@A|uNtxXTerj9NpUa-47q-TWb+Czrp+{rmC4^ z{kc9>Sv}#MPA3}JHiFj7@=TNR0&QiR8!={}h8j3cv7Ru%ryE}M221c@4EFkLnHt#O zB6Spn7eC!@JvW-h%lh?b{*o#wdRQtrjdIQiRPL}aX?6QH#FGIb(`}*7_Iy8O)(5nB zAPTyh>)|LBqbbzAzDT>r)lH>}R7ckwY7h#zvoWuS0~bSFx16IIe?V&zb4fVzdgNH# zg$|4V2J6El4Z`+O#=gkoSDjdH8rdqU;<%mj2MIV_j=U%P&C@}l@T|C17A#FHfB>9o zNugDZrcUs5m9_Ikk|HuG912A9W_Yud6Q!1I0bSqo4S)F{!&H{&PN(ErU%uR%y~gP2 z`M&Lw)AhYX{_sV{2dojSml~ju*0)PA8%lnm=WbXkfG;1Oh zGy=Ixgeu7fCDPGbUVX3fWr~xgG!f+g{;jUO0zGO8gf)H>*J=9kq&rGLC?`7DQ5`&z zRs@t)nC7Kho2O_mHE#A9%+Ry1M|-~~&zR|9PP4Dix1!U^X2nVDB}&`4KVGNFa%Y%b zVTG)uv^zzmaCFhCM82ubn=Ojux!=iX!{$C^%6}%`M4~01NIEPEhkstbiToPjR(*4K zM0t)4=JcM&6ON0w=Z~-FsJ9x=Wy#uQhdJRg$2ix{=@?BK2_FJ^|GBA&9OK2=#HzWP z(5c(Gq~sKT65gaZg#E;oav%IBcqaiR3lHzdL5^RjL=iX{&=bHl-yMsPs^EOTwEu(- z7D(9R?9{gj9t@<-v~J-;dBF!wX-@odn(RaB#raSlZqab=@jQ|J3_Mr=@`Y8%p8n}BM4`AvCVyPzJ+FaWT*!3eY|%)4<2<04>uMct$?xIhAB<&abH8K70o{ z^#U)wFY2z+gx1orE!-G>OenBG_Yi%++HZejf4gt*BIRd$c%a)65i|p1HNqkrQk@@! z@wMsaTjTj-X~s7s7;_luFheLQhFBq+B%r{@ZyajnVEs>NP_>{ppXk7tX9B*<$6=kc zKQLXGZeQ#zD)Q?@a}PkHOt5<;fx0s0(|aB=s;zS8so{?SE@XB{$Hb9EOLqOkGw13q z@=T;1P-a?PHWs?5MK|3>yA{^NXffhB$Y0rSDW^v5nLjoLheL|x0#U{gfM+ENULUZ; z2S;MO2zNV0KSwcRAz8|NDWq!gA<$yfbW+8oYC{-|)q-ym!<~A|J_LTkOGJ3R@dy*g zJAuDYAqFX%fr7u6m3iJ*emUV(d?M}b@Z7(abPe~!$KPsx{Clh~;YiBX{^ zfYOfFJc?$+wffb7d2tMx4*HC@L37#sV+e=`QGz|c7dU+{iS3*OwUk}V`reY?pT1DD zylcI(;IetUJ)H4J(v4e}CCn*(K))_6C~uT7fb$e;-W!%bwFb(X>RUrNrS6T#(*M-h zIzGf3+JHcq;@tj^TK30#utf`#X$o8k(^EK~dIcCa<2T$tBFXF{a31BH__SJ^*fV zmC6jzp!s7yPJZll1+t0^+%P8K@Uud}Rql%IlU!`p5k{H_YNIRi%mnWYClckieTwMZ z+rvhNZCfh&zzqk)8Bp?|ux6Dgxp!(Pi0jklb0a&D58QZ|pP$ZvhWCKw>-DCN{aFkE z5oZ%m2cWi48)-BD&M*7eJA3l)e3v4<{cy*axwU4wt5%7rDu#aQ6?CqXjdmDwpg}cn^cDHRD3Vx1GC`v8!QGZk7 zJbv_MbSK1E6J-fG9ay*Wo;1+konL3bHd<}r#E6&sA3ck z6BOEQ4WcUtauP3Y$AIjo+$xeqcbjfHRQ|Dd!49>?sDQn@^=_(G8ozf_2&snlw}omy zH~MKdHJ83sV|(77V%Bn=zAsbnbU3q7MTlw#JCMy?ES&^*l4q*^QkU8<6*@Z)2Q3Cz z=yxq`8(=4wXdZgsM2LbON4MCT+x>y7df!t@d;=L^s)}CcQ9}3Jg$zAgIM-TxEZl9R zn}e!SZjJEmwj>_GXH zA_&d;sc6I*;H5Y7%i*MJ{zi%1r&m| zwP|cz?;8%hwtWw=0}q@qJzf!m2mpr}KwWE)osDnHwsT`-&SHOvKrUfag@hTPb{d{JKNFJH?igDF%Dh_gdE6gCM0hWCwQ}gi#y^tN3QQz(R z-9J(o!JCwGlQRhq1Ub@q3IGAa#*$y`8PLl0WG274;noDMYUOy|I$v|3`%z~!b;J8| zf&Q(ccz4;5ya0tP0dl0C0;RTLH*TJqBoMhc(M1b2LmZXkv3Iz3jpS2>*~-2|6Mg-; zfJX6Tk|Yf<11M5`0)N$0K(W!_XOLG~MfaN#9)z%%cnhiNqrA-u%vb_KV%R6l1!cJ-wA zj`Paz)-xeC$r8J>-mS8|C{J(8$2s_X%4;s$Gy!Gvr?Q{r7yH?7s@q?=Z@5%}xc=FN z17S~re3!BZ40%K*=2z8UQ*AJlSv_{sOTM^WtTgu6}&#j;_V{`jF*uAQ$k{;dk8pbP7>56SpG_G z54Mi>Lq;<5NuiArfUSa-^k7AgTBx$#8)TRKxiO$4VW{~!fyS=+-@fXLWQ z3N7=!FS9UX|`TlA|=h9&)w~IDoaHQ~r--8O=eeK{k=k*F4AbLU<}zupX)t0I^LOdD&u|^TPSVuPmgUC^??Tt?Kl$ z_ZdH4(RqlUi5>F-(0|^abo(4BkmAwC5Anw@{91th^&sciH5*UN`KtY0B>oQ{6rsrn zJXS)sA1=)4M&d|7F+-+8x;Blk0a|pNe>NQ0-Z6SOa=|kFwSU}N(o0v1Qz6A90g6Df zP%6Z4s^N_#J;YHRN#$q!w_L{ACx@~w0Ty7r^-wW$U@F))0$Kids?+cP%L(yZJv5T^ zcgDVT;`lvT{6CQ#e>{J;Q}Q(5#go~)zyyg6K> zZwn79AutDjuJMkyX%l|BNKSaAz~1RrSFU|*pb^q z#w!xzkUXw!L`#|=ZN257V*)#%oklfDbn z&X`daD$G=VWPw+XWaf;VccEe6RE|u0BDU;z-!&YX2i?{TUYPZ_>B==TMA#~vYK${g zE#ilUcg@*7>kSqI3UXV$9;d6od>Cl{!<_1n38#0|Ej^|4I)|X!o0~@K*>GqL*NZ>+zXsFzyqb$-mWgZ zZS}nSVm*hf&qLk{C^Si zl-$KfKF4a8rpbyVDt?g?UKnNi*QBI6!nd#dQ9bY-68HoNoZ@>dcszF5?jPugo&7(c#eW~$ z6dSQ`b3zqox8R$U+43|J9cY3KH;D-8F9<~mD!VL>@e2A_X z0%_WRxfIFtA@daZqApSK9Z1FVyHkhNM4LLu)4#I19#$#s!()io# z4twf&!|`Co^B-mcNZwtat^qVAv6=!;;vhvBG3<-^ivBH{;O)8=HW)qyUJV_&Hs6=) z;VCk`8h*R2kfZ_=XTI=Ll$A}O-Vi8z*ik^)RWGZN^3M^lnttWmBabf!zy4P_I11Qd z2{_Q=U5v0cfT-JR&Qi2LIJu^Z*czHyRXk{pM$;L5Ql7+R)cARm)zZMIf2uYofHrUi z?0RWmwZ9i`)zLGZUU(ok3?FwfT?SXXr35tmQS$&9-W;c%7!MJk6#VEY1-xYnyEPFR zuwTm882-}o)>5#Q*^{d_uIp^D;dQr6YdiRCX5t_R*Af0Km7F*lzEWvMv!qQP&Xl#- ze}ql-Q^R)0{g{C}jkt8bg<*cShK1iQ852czYdyFEyfj`Q$~hvT&fV(xzirSw&~-Ar z@wBj&PX%EW<6-5>ton7T!S%t*WCpGg9Q?Pq{+;dBS=g@biEqL6uOn?lPxo=;Wj-*O)`MzS{b1QEv&x_5{Tl2pn&BHK z=7Y+Nzn97!AMxJO4(t@${v{*4yEzSo&l>U_tH?KLQj;O6&Ki%$ihxXox6k~yu7hrW zYkb=H_9sdR6vzjOY1-GhwD83TVP`wAY0JlmBj-jE2{{KEQ|xCgooh1IPE+R5z}L$` z;XAeTe#A54bhNCirJ9l!@1~CdxFCskqvhY*X_`$Ugo+yCBz9h%u67-S6GA8U+inDs z5a-lh+t?N)6Rstm6(^Wq8E?eLuKACD=g<+}K3HQUuz>qpO#fRF<)Dp&gC(c~nvV&g zulyR&HRA*eR3;J0W;Z5xZP;Y z6eED*`AYsB0H#=n{`USWalNl)gf+(l<}1>)gE%{ylH46t1f{l4k)YJ;RMCd>+|EzY z2yiQvmQE(_S;$}E*15ZbR%xSGldyPa)CxQTg;n<>oGhBia`?!QRcxrP zrfX?o&2=2ZEn~g%9x@{WXtpRJ*{FW~H;Om|=k|f<7aLE1{cqXxct{W8_HM7nf!l0e4W0} zd+2!7=WX?y@jV}xza6VVfEP2m+E+$mdIeI9-frs8Mrs#4LmUCB+Z;LW*$n%#0P|<( z3U)^Gg#kb0@pkUTo#V!>SSm4HpkK)+%$HMznkkT%q&~!~EaT{sX_NJA2aDwN0mY#+ zM!ul|X8ai8e=;hSX)#p2^WFOX%*_jv(%v`55mnKB(fg0JhIsK!*+#(<-?;O)q6(BC-+DAG@Fhsa_s?|y1@xeyDij0S{>HPSp=Qr$ z$&g(%*V|CWks-;34>-@^(G{bxVR4LwvY3<{-Noegn^jL|4}okaO7q8QF@?R7oY?>UXlF1G2b`+ODH~e zmgOe++EEGta-6#<)+6?5_&f!2uJnU~lroc!Xl))=o>R2(t&gb?Z%AUl2cF;I^Ei6hlzc$2{Y*w|QN z#n|1?d0E6`M?O2MOZ4i1C=qU`>Nr!#3y-4 zDSEKMnJM9z-=vI`W47-Fnf-x>n5mKtA={6fYc=l!r1DlrFH(o5yN4CdwuGN^TMYDb z#t(H2HxFMahHrAmLo4hJEnwq$-`BI;d$z_-4;!KEG{OZaPr0kKM8KhPy8ihODwdfX z@2bNiAiptQl<_!5Kt>$M8bcj*e6R4i(fgm=_@`$7llSS2-4@oS79Sr!t-YE%NxqDO z4;kpgB*rP|_!9?(zb%ssj^AJ4DuAAd5Sv12$pj5&f8;qwb2Zs-OAAdzGc*Pj6C@6{ z+19-U5>D@Ezc-m2Ud^9|+Y&*m*e%+2PACtXkGGhrww%1zHupRR>j?vW*pQ1sDlV-R zOy1as#Z6n$GbV?iv%v3zCv(a5KUvmM&vc{C8?p?6Xf=BB;u3P%PxpV|EsM#KRc2Xr zf}4eo#jTIYWj=|-gczAq+zc8&?HL*3^OIhE5^;F`O{Cdv9}PT1i}aY~UeosEzsCd-JsiIIDDVDJA87NT z`THVc!-;(2(Ao`2rv~eT@z{>A?9ztHoF8FY&_TfqTY?eHZPh(f1&D#8t$Alk$xo9Q z#-DMkin3W1RlZokkKOx4eqYdxw7;3t71l7pq)07YokVmYHY6EROxg6TROyG|-i+qP zHrQ{t!1?>C~AyE)M(K-z>NLn8u=^6iSVFC-r|0~GVdJ*@o7?I?(o!KAuf20*>`q! zYASX}fd&1m=CQJh0CgMlTiK>Gwwq-q`%_#n%q$)frN1>OMYoTnT4x~4!nAa7T#18G zm-z#P67?hFo-9sbbd-RMRRmy`h_?4Fn33(R-?}FVzPwk98=-FR5N-%{AI@@6I{X$JNWpZ%s~Ej!_JQxTEMS) zr$7G>Lz;iKB;wc&$bD7UUGDSaffn;%C%098q2X*Rf`;|ZCLhp2qZTmd_N{m7^dMUA z>2b6An)3|OWp35!P1uuHc#oB&4%Et3+WTbp;!d6^W9D0V50=G>7B0FxvSqWTMRFwU zFyb_Q(1oyi52D>JD} z;S>O^BzBRPZt!=zu2w~jk-;F4elyh4)*yJYt_?tvxt__X*Jp@ec8{`~9A_f$gg?7# ze0{_Wew{ey%(3b)_R1xKaQ8v;8?5n&2H<)d3g9aCyD3jaq_UEPr95VvOJ$`zaH+3H zQs$xkPZn?@XIFwa69+#Ws?RbW-zCG>fBchlBiVE?uW0-$koo1jxih&Fwq%I4Uo_ah z@>4JtbG6OE&^Y*XijmvksnhD?Ujz5qbsr|3EGNrO2tB{hKT-8KJzK&Y>CS{d$ySUe z9J{%7wC64q(g#q)b`Jlv1>-p@N&LN!O*ilo$NPLaz3{Ooy8h}{yC7OoPtDDbng29e zjg75|vC{QVkt6Gcz9SgHlL8rUx8J0ePQjrk4d|~XKD~DyT*fK7UeXjv3rDy7 z2s=hJE{EipU(lVH=aUwfKT6y`w?7O1jy$GTDDj_dUWvR+GxC#vdP5kX5r?qH$LiORU4#U8JF;!2J&(Jd&T5z~?W)zWAbFf|r zTHuXvTw7-adv>h60dFRLU7N2DANK#Xa(usE7GZ)7kUED;TFiiP)x7BToEWehE1JYC z#$uM0XN-|{!|}tp!HU#wQr52*qjMi?W2@>un+oR8AWgT$yi~aWHi=W=*Kz%6fT6CY*aPW3IU34EZ<*p8Josb1s`sJ(Z$-*yF zPfz1OnPOX-Ocmd^p~u=Q3;BA(3?y*MJkt~1F-u^%dsh6x23y0uKihJ5xZ%eyR%g#+ zm`*1v#!gdb7n~*Gye|FkYitlXWL>iuKzb^s8{aKKqjZxuM&srPaW#g>(ju zk7#t++L&vpPR~x}0;4jFHeBjL7hX>Vi_fGQd zAWy2HGJmUr^pUywIEG3MMDj*9(BT+v9X=MnB*qZu^`SE-pSbW$WIZn8ULAK|2{(Iu zP>_rqxOyiQ*?By(Sn1#Kdl`tmMsQc=KvFhK*NGKv9o+52LFqHhES!x)>DMzufbjoi z`;wLVW{6jWf|qhL#nh3uLxVmcRGmkA;-oSGRKNMk>OeCmc6KRob=KmV)>}{JY$+?Z zGFxnB)A=a(52CczMLIY`08jU2)sT|FIlpXBbgF)r!aDvyZ7i&{<^G}XJvw%(0`OLc z#$awP)UGwu%~+k0erYLZ@_U9e!Lgt4vFTU~eSh=ToR_)U4MM0M%awd<~w35a&^nGwlD1cA> zzu`ON zA5AnCrDP6kcal!Z8^=K2DV9NZ zxw;mjZ|0QJJ=-_pq~+3N`ErSYi>?f!oYQ_p%!#aFgC zXbOySJu|hr6yLm$HFFht|JIwSd6Cq&-sy?WUOB^FhRX~2yYr`*U5Ig}2ml)FR69b% zr+;u)F1HP;LN*y^_KWuy4?{KFVcz3Tt`iSpOtS8ZNm2GHpv@*&Zje@$_~KQ!PNL^Y|cZb`m3gX1A^YZZ45W(b~z&wyynXKV8aBs z$oYxXZcRJ;6_yJj?#gF~d_PwI0Qg6c{rSnND`4GENWB%s6L(?M`oxXDn`!~LN)M5_ zTc7X4)6gEhnDky^n|ALvVUkMPQ*7?4E^j$U@OQEzjiEwX?Q1vbqsUdv+*?!0(MK{t zOt_v%xyUgo%(++-=%DqT5G`jENdvheFN8~LYNoF6*&Xv$DDHGN+_ab$SIkC1WbKoa zjS+~FRSWhhRLD4~c#{kWn0F2xKS6=4Eh4RgknzcR~w2AT>iA3Le(DhupevZr3v+lbeZcx|yK;a&Fpu`RoItQpQdQUL4ZP@Qlr`?=R zJ_etToLtd$iSVcbo#WIOq4klA(*U74>))68cI2nRG6BF0gwzxocL4~c^V5GvC^{b# zNhmhpw;{z1qxQH#WaQ~-1GO4({rsIhHk7I40>kTR^U;nWZe3cifwbvNK#seB#W`lQ z_tZB3b(QW^?8?dwJxSau^;?k7uej-=KaCo>*wkk?IlGm%H*6=~H3k>BfEi*DwX4aM zA2WU_{?2(hsEP|!mOpv;?i7<-m>5t__-&IhQo>AD%0*PGCplEh<>JZewWGaNJ!+bW zBf>P6fP}(QsHFE zNjJdsjF+FnXGQsBqQDPxq9P*LqBrXi4rFBNA8~H>AGx#Cb?baTzNqti&D7tW){fRc zGGH=p=4-{(@wMrdu)i3UyenJeHzx<1@ufga%m3K?L|q|&LBvl0ljtLEU+6QJ_`tg^ z6nIa*lo5$VC>W;FP2QXcK=Z0TrZ+A>r2-tSu%EvWwcPkBHv4+Ew3 zUSxaC`(Vos)-Q#>l?NScn$Yj4Usir{tjb{54k8b2^FCJja`ECWNHTOu9k*hYDvS1E5*{gK9J@MB z@R0~L7AU$FNL|7CM6ijZcK-eac3fl|KoQrCxU=|3!r| z6nSY3v1TT+SmCbfNdh_V=l@3fus+AX1Pg7Sc zZo6?1PT(3DdH;1NHe}Ya@^0^$MXB>u7^|}5FPeK^ z6jf*QkL}+aG8RJ+p|dr~45a=`rRgL_DXi+Wd>&V$L&8d2UaEN=8`YL#r(rX^*WZp4 zNXazwa+$%m)i;@qukKMA=PpO|A>AHueq1T1$@x80&f78bh4r0j$#K_=6d_^Drpf7f zdJWDKzK4>b%EoOp)U~iOPD#NYUfE}$%Da^H%|tQe7O}I;Ls4(?UHQTqK@jJ>`K>OV z%iS46k9w5}Hyxg421VG5-a7r}Z9j1HOK^aK%bI!yGTu~Fro02RWu7Nj8O;I9^}XCI z)I2I_M);%asq5DA2lPp`TPxRH>tYH-3GWn({wMxBu#%TH*0G4^?}&J&n-!z=6@08* zG^B0rX^=nR>zYqmXX4%Sn#j6A3PuAFsxdxoXU{AQcMeo z?gaI)HA_x5HQ+{lCdFlf?}LO*yUA-Kpo$=5MA~?{T2CM%UHtM4NmWbmr^zL-#Y(pQ z_|GNCmpgT#ASNq?9wU(lh7xg#=LBV}I~$|5;Izq@uQrP#>b?wU2u{~|YM&s8eO5v;$W^ak9QN?J!U6ITE5R|Jy zAHjw9xu(*R)AMxrcFxTAn)V{$%l#EA{GZJEpWgjS?|N+X!=N-Y?T6*!_0!}|x?MJf z6xzgiy#qT-ngvx1hyAk{z$&g67hv4F>w9>%VF-V-Bh0jSLxUPr(Y4d-lzM`bcCNSH zF{h?N>>V3)kdZT0B0w-=%4K1f3Kp0(W{Zszc zSH3Ev<*!q(Ow#==@(em=u#`_DJ0r@*uZ;ij?o=E%){ghu2Td{lBpfOlHdVS0fxS{r zwTDm2igAEU%wIZE+9v7YJ5i?Ccouklg~7o`YRp; zwG5aV3)($Ceo@iP(tv(_Znn~IdyG~E3EwOtPmeId?}hY19(e=YNl<>QMZ9!BenJ(Un&SYC}pfr{J44QRe-^9 zAn%Efyrk(%2&P~rbo0h6@sph6VBRenP+rahhUcA#KL@!1+g{YiC&dnIWVDSZVJrwH zYrrT%Qvs|Fjc64oW#~Q#v!I>iRo~yrnHw}26P6G{{Ep>nwzhx-|N5^VVc{lkNZqli zNl$Nl>Aj>MRc~iTVyHp6=zKOM`Tkr`lQl<*_GQSG^3~7NEnW)MMqUhoJULRE^(iMu z!HA;@el9EQlbQ@cI+s=L4bB~G7$5M5t}$b-%vAgE2f<7Y|K;Z(2hOe7y(GRL2ywes zhSYB<{AM_EOhLW~m%vcM81Me3VqpOBDMPWW5J+i9bC>x&8N#Z}fB1y&cfw6Vl(G42 z_u@j(fM<$-<6dwx(wXnqszw=qZ)T5!dN!M+=@4HyZr$OHo9<1&$6+fpH$!fOCAup5O1_}oVc}9h zo8T=_noDMK81v*TYODM;qvaei$r~@T7`k2&i)pJc`=cxr-Hqbwq_=49)_--kh{V)h z8PVcj3rl)*X^W4$8}G(Sh+k}>8K#c)r|tdawmVuQXU4g`nCG!C>Ykc zT_z1#x<1D2&aNI~{JSr5E506X|7(_R$uDWlM|f3LnIpOdp-K)Ktjv1Nsr>O|^TzG^ zOCakMtDT$EBqEQ%DVL=439BmOWeIqo9H=y-w%E5fMM2OD`^n1W=|}M)5L#iYQK1cT zYT^~9M==|vnpy%pqaLHn9`5Hs)}Oq3OQcUj$aYFudfjxT3XBYy$clp&=p)y)ioDD@!NL|KviXm~?|uD%NsD7FsOO#udwXH> zYT9C9L-*0j{kY4&TWwd{mIz@CR<9N)!O;xF0)DMUo1Cv6@#Ly$6k%u*p{%Q)nqI>A ze>xh|xCeNs`gX>RNtNS*HHbh5Oj3;HQ+^$Xrr=SdZ#wVCK>|snH%sn}<$yJB3{qu( z*W5r;!dMi080phN3fD7Z8i)dJvqASSItZowsR(K=Z1P-o_S~V2;4F zE2!7xzM0(8zJ^u1-H{^oEma6&ODY-jXwbI#4f*gJ&*C!R_DirSVG|EU|JY3QZfqJu z!Ac_qQ`N_+yTk0K=Q|i7otTjtUl-=O;WH3)b&IedNb>NGF^H)V)?uvUhYEgkmqOxE ze39v+)Nk(?DdPp&vX#-;;u=GVsppxJ`_sM=_vAVXNghaoy&p_}6woXQ)4@r$MrRn{ z1Fr4RrrhQ+G3-;GHHdaAORtMfs6P2qr;`tg`HQ9dZLRW}M_hU@Yhd5Kr@DR9UlJhS zZ(g}oyXZMyy2 `pOsM(zFKUj#$4qsKC`##%mjB0fpJd#}KEapq=N>pH2T#T-`+HG`y5t4YbQ~gI?l*%X8%qm(2}y@H zuXolx-Osti17Stp;|ajs5^#LkmO#fxY&dl zJN3Gv(d8;c>OgE6vG~nE<*g6togaVE2D-jEv3o_g1K25#P_LGWfBR8cI8!Ub(5j?854jOaCV7wotc0h!mleBDL zDuzKlxJls`J@cM-TzjsAv>Q);Qm2np`0vhU%!|k1XLYm#9eO_}01REXkrr*Q=Y48S zvUsA}rX{qHFIqW7!>hPSs;G0Iu}$>Ui+y3KS5}QiWW)$109s}VE+po^{SNp=k4vQS z-4+e*G|I_wio_^jE)qCy7%~Zq54NV=sW~sa&fUnfWKj;W7!rBCWMLlR%0F{i<&t=h zOBUv0S69KRC@8Z9;e$#$xAD|EX5w0~nvHPOZ~HKmXo2j=iv4uQ<+k)Y2EuBKg$1tV zmBsvr@agSfE^NBsf;5ay%^|e@PlfJ&{JqYak)?JxX%yF?E za&yI%9J%D}xj|Ky5f}fhM;(l+zf3t)%z&XM_2!k{Bu15|G)K90n+{JE<5}b@IUvgmjd>L;;vnW!^@PfT6o4oq%F=CAIMqdhg^#y+0RA0Sks904@PRd0+HV z`1M@7n9%^;NWV=cM3p|FFZx&^t=bz0U>gbMZ+Qiy*&qQAvC!+Z(W;^%G*|TpkBHy< zD0ql{F?X+~{9>LN6nq>^M&6Y`Q)I~i(pLh}BR?P*h@R3Ye+c1XGcZQTPBD@qtlG13 zK3UgwFkNELw~l=vIjyh6vgTa!^1C8yMCiMi<2Upoc9%ejR<)lQkQ_#k*J50p4hc#O zRV~~`ES%Rp?rmF(aST#$&jlbH{RncDh`TEU3F=Fk5yaM&EDuO_UQNVa3=o;FA4^a< zvq_d_%+;&R@s{=?ES_}*j2^^h)4H89o?x|Ascdxo_wV|UDHCs4tvIYB09X2ZfHde)~)^^{Sjppl~H^SyfKvHkjc zW+SU$SlRgY_`+obz^ud!SNNK*6#f1bR}YQofHKwGlK_H~gXdHr(seXLoHoy8Uj z>QVa#MiImP2bNl+6qCOtpz900;FCVnGc8Lk`@Uy}q-s+TYXV_rM25BnP^*Ev6La)H zku3s57N{$Eh2L&G(?3q9zcOcy)>72s9}>C@(%(6nH%BD}7T&X>0WDi~4+Z2kPZRCC ztGC=FN>cMrkYYYxpgiZTfV!Xr^E4BKgkMN{AgX|C z*)G(t+(F-;3tRT;uCln%UK?)cjbjK*z+KonR3lIgP5-A zj+&7BvpUuAhziTU0Ga*^7 zpZ1Df{eyiKS>!$@3U1ZmWGe~={N6ud?THaYMOoHAyP9?dp~^ns%U!G9ll0i@QOS9q zZs#Z*yh$6yc^|EH_Ocvp!;BJS-)Xk>unzjY87lhjma~GBj=iZGCK()VSkMa^vq7(@ z;~w;Zh&;3@8MSUCl65$OH&xpzkwUB9+=?CaRfww~tuZkqQE)G*ZHl(fP1qy@LPE^( zusVI*8`SdC_yBmfz-zqUKtipa-7KHs>f<6`+MPc?d-JTE0EF?JJv;F6IXkLrXxtF0 zSiU>p3)yl!Jxd(ALgdXGKubRIpzqDINl~wFcE>zES4n^OS)0s!LT_&M`5I(N`l`P` zRZa2NICNBIPam%DPOY3Z|I916j3`Obm7V-n8E07!MmEcB8j@m~AV!0Utnsvdzuu(V zt13~kJ26Tbfl)0l>@S6LF!T{wGRx8R7Mt#I{2prpozw~FnsQ%vZ<2W2@(Y-$ z>3^YpJ7&kU#Q*IQXmc(-ddx=zFnTy|dk+<#iJMUOWkT6AyIX^YH?O*WmiH5a5`o-4 zo28FBUkd#xQ$g<1c_am}f;9>oMpoM$vFn@4CMv(@UOeXth%ahtnbH~MJddJwj5^Xj>Nq>AM8{F)5fOsO^IRO?Wvt)}BObp` z<+|LBdmt?euhHH>J(BgE3@jz{ixo|U>JmeF-rH@JjJ9FDiH5hHPj9;!xg=m*Wh%^M z$sdAI6uQlYpe7>zK61oMro@_OdrGX=M{2@#{=!>cmUz4sd*5kh^@QgtKR+;Bv89|m z{9xIw^ zfr=3bi(Cu@Qm#Dap%dM#%TQ10{ee5qX>X0*KggP$!B$#j&DlUf!c^>J@wWs}HL#_< z=3C5?B>+D7m_FbcB|rqD=?N}mnjr)AIBCJp~kT1hgD_6*! zoD{@RN10X1IssZ(P zAPPNysi-u?1&p_ci;lI9289o!?0xF|rn00U>m|c)sT}MSnC2vxPbWcETB4!zl>?Uj zW7YJa*N>X`SHeQOKdwLC)3}x-l3gwUp$%;sVf0=W|}ErqPv>iBYTS zUJU|JUdZ)Yq5-c|gNS;zgj=ssqx}^=@RXQ%=W4grT$-GOpt{}j&19bc#n^vG(-n5@ zqww0c-ic21-n-}}dJxgOt=H(iZbS=-7F|dPqSp|86P@Uy6GRZbch2%W@B90{GsZb% zoPYLT8L`%V-}9c=yykVyHK2tN8O_JraL6~IP3J^|<%U$9dp9W+a`3J?TIOaUat4n6`1KYG9T;hJ}3yyj_gCljML#&T_=Y5*@o2qE9x z1S(=Gnu+5R7T@vCBe2{y;WO;rs3dck8d2YAECFT(Vo_p8OYyYyMz{-pWH1OD$_jR$ z030|#yjtURl48Y(O^g2YSNwE&G{I=kmt=ca^oM8qdLepp@yn5q{0win}H(S50!jU zE8Lg(m4FFJH6~oPH@G&QyIYZs^TUd$(Mn%$bMrv$O|slym1QM6Pa74(8_ZFX6B7o6 z{BYK8+SX-6aPpgt#KX@Nv~1DLlbNP(B~zgpsV5!3ll3)Mw#KY2+pG^(2fc*Jmg>ZR zA77+Qx`mI7xu4b>dLW(1X<_NmL$&G?tFu`SW29Nmrt2G-WzrCJ1m{7yv z>TARPxgn%$EIp1J4j?1-SEJHGFYX&q6$L@a<>}|1#U<(OcEbyy{5H~9EBEEfa0!NA zq_sVqFmiw+5p|+-a6?mS{NrXWQ+kh|=!)*^i_y$o3HC?}E$}m8Ub%3JJ9RWl?NZ-T z8cG@wK4})7pTwIKA=I0-7@r903egZmnrTmcLzu%j4TSGE@5}RFsE;riiKH6NmZZVM*@}Cc zDzR|tyLbEKfGdE;iY30YGa{O|dX)C|eCJ?y`Fk;S-&c2q(cQb%Q0e@ekG{m@BN2EP zy`Cv7^ip)WP8m}P!{2tsN}QCq{dXe41B(uv3@X z_!nY&mDs($2GuFJO}-`sK)Kss_u7=&#k6^~mXqyGUM2&rX(0w&QaFIj_GKW762g~*~;+h{#90(Vy&9=Ly_H1?Ny>|&#ohtGZ%@yT1hA-`Rk5(!3+ zWhq}YDh0$x8T)CZU)>Op00&WY%uEbh87fjZ>M)21FLs9w*dAnlh2E zkMXXw5y_OZvUPIU8T{gJsVxyck5q+ILRu)gWsM}v3^o2A2ZlJK;dRukC>v=C@e-yR zmM?vhvcH*w72Z(GzNXc=zYyAD3tEE3ld9Pe(7oX$nk04P|^Grw#4-6OxB7R=b%fBrhyZikW zl>0&N1rqGx>ac@sB9yFb;{Lr)#=~Ee90~uyzEYv4YxZIPU||w&gEzj*M)Cfxt%QV$ zSWEP+6d(ntpH0j|or8cM%_r!O*aB)e$!gY}TA*l!FA(?w92fUzXhciJSw6=yKtWiG z^g^{*_+$ShFVrxS`Kw@AV@S>k!QLX(GyYaj*sec^*QiA~cVsM>j&;|e#Sc`1@NbtU zd@BznX`Y!JwO0p-7vv>T@7*I}H{`_1kH6Rw3sa!fDErKv>H`#!#gWx4O3X+fTVLQ{ zl5q?qA~&xw&ftln>_ZOmIOwZ9)3awgdS6 z6yn;Vac;+Dymj>~5}$BKXyYo~&>Ji)k+e($y)0Ja)w6{xyot}_XKRhT9f>W*^OGR! zXOhWa#4w1RS^xK%KkY4PcjW;TB{{4+g`p^5z?{@4K^z8)-ZTG=yH~+F=diYl(hnmB zI9nMA=ch@2`@=B+y+u1#L#6gVj_@E8^WVwA7;h{WCmg!hltepzix=-5@b6?>FxK}D zVCjL+J7lGdM*|4dDKIqqk)yNRcvb^yrU_(R?El<;B$M$X>HU+m&a1j2!lC%p_dDeI z(KKl$E$Z%>LKWY~aguQR?uYV3Z&V=e7iY|1d~xYTIGq>19&%7@o4H<4O?*8YkU`)i z`cjW^)onS)aLy`Mqy`D@Pe^phLWUnVnJl3X@N#s_Fnv=W*7?}%9rQ`{XnkSdIf0Z} zqc_E2Js3l*9-&7IoL`i59G!&&P_4uL!Ey#<7^!zP^Up3S%ig!JpUkdkm=@7 zkSppB;X<;gj7~f{wtcQ1*o7N=rPYP=b4B0w>+{I2TFxO^J>uzGPFj`ZXPOJLW^_PC z1oIH8>4pW8Di%<%jUT67my_(;Ie3DED5owtJ8YnQjZHQOhbMO_kK1{pJ`Y8G!O`+r zk3@d{K*(xeP%V!?Wp6KEZZ!`1^egL4*AzAxpUu+#KO@c|%V&R$UliA@^FC7B2mggy zBjf<5Q625|sOBqtABsdfq(bJ1rCrD-{{uj_*v7JDODVX&wgQokgvbrt7Y#c3DdKmr(e)Etg3EDf)gXOkoA-B((y|%*@-%-@;u)NIeeuMFZ z*I|M&4=3ISY%~;*)OEDZLTw*J-|FD`FL!7Cgp*_4#eQIt7yoM{1Mqt8vDIh3hSWha zk~Y8mH_kI9`_7SJ)TnXEw)FxIh(O3NGA4;TpFOh>g)$BwOu%*+F__A6G%PUsNw-Xo zb}Tt9Evn9LGzwX{YtftgY@yM$?|5T~&*RG`y!)l}9g)77KU0gX5+Hoh>FMAGW!>I2 zj$Wj>*6^Ri#rTu8%ZrWykf0VQ)~L=s*_M$GWP<0OL9p3@1Zldvxgbqp z(o`DO-uYGG{!?h?)AMND_$0^id=#i+Rogj5%l&FJO}@|Ge1@1eJML4l?n>#K-MX*( zRn*jezai$7b8~ZB(`BT36-JTopNjLRar5ydg(?2S;xqHQ`zf-5Tod@kZXlWIvQPTH z)1Ym+EpUBW-y8=Waeujv_e-DsZOHXPhkA3->~HV@(E*gl)YYPRIVvf1#V-g5vABt@o@TcPM44!5cQT zez$Xj?lBD!jqsYyL@+f%V4W9YmsukKY&-*{#-Iz^;c4PZdKh<`ocEd5bn*MISlwf} zykZKEnr zm3WlG*xTFN*n$L?+cQ-(R-^USsfSWXs>sdg$gfyGAvu4*mqCIfXKl43jm_6P{6M5k zpoaZeaA|p0G6=Rvwj0)O-PKj1eA3TXOi~}hYnFPuQJ7_)8ND7=% zQpjumx%wlzZbx-CpPViR8$RG6_Vj$C$N2p%mr61e$he1shsbhgmB|{-Sh0HF(SU>DxnS%y_1VD>c*z)1IC=7PCgn>*M|t7z3;bpg^+1EGz5>|81K> z7Z6)hYTU>T^&mR`N@Uqd!e#VkRO)7UrV^Cn73`;)Pb_|0L(- z281aQ1;efU)J_uko?Wm1k=p%C$s?0uv=$axyyJX*?N6HD>O%m;&uEQv7k9vzurltD z;4`JId&idouGw-U10-V?b|4!*^DtbWAwX7bKNxNxIBD@G+2+f86|_Hs2`BvmNqkFn zhHP>Q5Lh?r>&5R$k%t5_pLu05Q5abajbUN|6Aj((vp@D@U5bLjwqsRNV^NN$t_BdZPW zyw@lIROm1K(9RFQ@WU~=eWh*n6#RI`zPfv*mQ|NQ=7Jxg9)=E4=XGP4;q-4g?$ zyppvs7Jx~h&NcwXfQfpoJ0Zo?L4v8onOst=C7=kzolgZUI}&lV0h|z-58ovr83Wm! z|HYSbM`EvL#IUv=c^0gL-LXtF^U7<&h$tLu9JWp0;P$`Ti*A!=yAr$)5$UPaS2U$m zmAQXS`a37rCxh&w*@Ch313Py%PVCI?^jiJ!fp}jZxzrQJ$;<8nMMs*3#OG}x0bMj~ zi%BxGoYrcTpY?mN64bj(Vns|ZXT+qmaMkB~*BiY>4bJ}goBB`qPD;kwk267NBm+@d&Nu2R9KudH z_F8_wB>@x%Jd)|wgVw`XX)w$|&Xl40IVEogL}ruM3vyU0vOPw7K(_rZPFj;5_|_R{ z4pHrPOfpgG2ymR!UFOxmTwxR)bbJ1qL&2iAc5fJdG~9-r#+QD6!JWKiV}ucj20yAN zcOhrt)F7tRG+!}3mFm?Xi@1Dq>6YEgcozf~wQ@D~@YX%Cp1g0&KWSj&bnB|*LN1J| z$7RZp>W839^IwIJbxJIJjIkJ776;@Jg%LZUt=E2kazMf%Ip!!{Hz`&Es%Jf#jxwCy z;r$j~-G9nL2$n7?pMx+36a)KjpWnqlduwX*6M#+b-*LPH3=mXQ%VXV_j2LajI&wkD zST;|XZqqU&z8&QJ=y9HV(!7=aBjV43qye@1fq|deNJ(JnHohVImC>Y2Bd%6HTTz;LKiL z!a8qs`q4#7j0*R`@M(-V?JUa3Z+?fX%YH7$-CvH}wtK36Fv}i`xg7Y3 zJN|0LKCvC`Grd@heED#~79}A}HY8P`MDDimagXo&ie}K60`vUJIPS?x&QRrOrc}C( z%gE)WHtW68E8(}C1H*yq#9n*jk=s%pm#kK`L{G(ice@4)%MzP}pLE<^i>EMsBL0d` zsTe>_F-A(vp^M#DAN^_41R#-93a|W!4HR`mFU3IUu@Dk-xNNJ6o-$c6@g?WVL7M&j zA5l&Al8$OO6E}HN!42m1UeR*|H-={=kP}BC+0EY5=%P?pe!AJ+&u*7(%8@WyBZA}i zusO=5!xhSH12<)pA?8aazG`pNba|Z$%DB{%QA?-4D1xuk5&x)GvJ>*s?7&k`jr#7B z@f_nPl?7xymaAkky-kEG>Cx{OsqR6p)KWQ@jf4AP&qUbnjuJ}esNku$z{0uMh>RQx zML8DPFMB}Z;q?y_P9zv|tNrsob<3*+P({wnF26Hm-jRcToJbVynS$MC^$FjE;dpJw z-Eaa}%LHZk_gCI8f7Z`Yz>ivE-zfr$_ppl|HZEm>nabyPQD+5d5Udj`mQU9cNCm7a_5pGa@lWIq#5@I@AOEpU8Kl z?%X7`4ffPmC0Yuoi9~aKig-W1oRS_@g+8QgYZ_F5rP}Jl@8#jW@AUIkX$6RsPs*Jz zft$@FL6MJmq_k+%rtKB3D5&qHGW;-aLRfn}-)QL3L2Jv1sVrSj`Vx0}UI=Jbuyl9n- zDuo=T5_-G-?>!1EWP4NEK>`RfSIXLyQ%jk{b9}eYwo4p|>lj9jiJ?*1pMlec#AnT6wvbr@CvjD!t8g79O} zGatbQgg5e(Zpo_i_Xs_wZR|0jij?U##5+Wg8YA^V+9t>HgXLdUwZXKiPDIGv6pNbQ z&DVyHf>7Jh6R*i=q3i-*1g&5*PEUN$Qz1XYaBN&}y5*gdb> z-o0y0$538rkDB*ADPWNqq*17WC(CHNU8th%e)wB9{^Q{@tGfOJ^Q=?;N~gJSrY+4` zF3YM9`Na7zu*o3omJL(RhOF3RXB!)&MV80)r1aE2_H6${6+i1pTeKuVh83`FE0%75 zj;4lP)Ll^V?S~mN`cWkAr%C%~cJVgFB};0G9%i)U$A*94Z})bZ?=!D=25XPPF`g3E zyW;0X+nju2cIBTw0bIrn*5u&eGRx{7BH%pXxr2+!4OO+H_xj=3ROzLV0OgPw8#eUI zPT%=ocW|JDBX*@rdcRkW=)Oh6>D!L`${+0f!n=3%Paq3zyAy?(Ga{jk5_VhL-m{2c z4CSyl&57g!+WJMK3NHfIAu+5eq!7RsAt$F(1Ar}e94$N=sYyygP}@$q zsTd{Er|@xu*rV$XJSp427FMrB1o7T_zC4wxu>4s&x8*k?+udTCP)p}&kiN7#9?X@W z$i5zJF*vu!)DH?hLTi_V4TjWkb=(?(a#_8o=R(+fPqia2Jb3f!&WUGwX)R6uO{O}7)x!$dOEagOL#im@cAPBSDzR!Z0HnOMt z701-bBzZ&;ohN0hyXGi<7nvOfYuKvUl2=rsplSSd{G~&#*91W zH*92fb?eSm+AUnJ*yC#K`_47Vtd7oEbB?a}H)H|lA${a)4Zh%`Si%6wKn!*h!icNq z@98!rAWivaPI~5w!0>x)-UC6`x9?;RQ1RA%moaSzFhI=}6GN5K`5S|YQL}+39^}>k zt=+oB&BS>$UZ4O1S7gX$uB-k>GR=M<$??-Z73+h<^QR5=eKnL|6Cj$F0trTP+4cm; zFeBtE2q7Xz<@7#P1BmGDUDn=pRVzA8&Yc*TPS3pTy-@h~PTk*;FOyur7LNN|kLG*1 zl=e=RQ)MTJSo=o^v`6OHw<(@hmrMD+7)bo;{j($G9#B*9eYyKf@?!DF$ek8H54&A_ zl9^@u_38GHT9V+S9#T#QD-#nc@#pbxJ$f^)oq4IDnGgi?-MS3LpEYcQ4u^F5LL=P$R!H}vm6%X7@2uWBNmCuxH;46amr8y7sfN-rviExN^77CiJV=%zUOdsY zvD`%oK#rDHY44>R*~LTJ5HNqXG`POb#!|f=_;Qvm^4WQw8IF?g=IWB&ds2Z>8=*9t z<=LR>NnlnK5C?)5{Q%~ZVgF~=V5cuycdt0buG7(Z)vAM!VmnEjv{D{)U1#FJl8qzy_uA6bZZAZcd1Ob!gkf{hg=?Oi=gO}D0|z>Zmq!CbfYc!x+f zq8Rs-<85c2ogo&1UsqyDVp+3IP80h(@Y5S{x3kwb=X-u2@x$l7CjWJgL6xr~@WKVv zI)=`;#fJ+jZ8Sp!FMt=07bvYq;7PG|6_ps4zIlV#HK7HBLAGbi-)d^*@6XsoWT=1R zk`HBN>#^!^wn)Oa;%)x`)c@52#IGhPQFl(2Xp;j4fm6On7J}S`9TKSgDDXmR<&?rM zPs9hGgP`y9E?aukc^w{v#=ip2LkPA4e$SPH7Phw(ONj^s$&&V9dxhxig)#S5V<=sd znED_|3X5jLT{ITj87;q zWwi-lTifXbK#|l?T)<~uc@F(b`K4y>xZMtV!v`lvy|{lI!?V5bDC0g7^m@8H)}0_h zA%X-08917ds|`|H!Fh%vG{mz1=F{Fo0s*`F3VmnFi+IliWc0z0jq?D06@v@h z3DPGGY=3f`A^$4~Qi~IffOr~_$eUkUkl~8H_W+7`^}4y)ZYqePl-+|Y-w~yiyRY}M zY8PQ!CD&Iv1RJ7jzS4>hxx2ms5`PI5x~Kr0;^GT^UIb(UU2puf{0S1Zh>c4A<6ZNS`p|3ZWy z+k|G|XH=vF>Sx6J$EGJgz?|$h>wYYs_tsG6|HljtJNIEdQ1hB6W2gMU8z6jzi>OD$ zAPu5_Vht?wyMQMR#K>j~*x^zKpS~(LQphZY%tIAF!w01}H?m03LFVL@qzztHeuNyB zxc5IDOLY2ytZKCQ*Ijsju|Qn~H6FAm$94DOrl=)(yvE!{ZM%t7baM&&b78O%-j38I zW#+-%-cTgL*Y@$9y#PJ=g&PjbHPaThO*F029?Q${`Ae^J^V!>;Cior!G|ko%AQ`@u z&wu|8l0or@06`DGV}|ch_{2&9w#T+^)V+w0p^&*2X<5sU8g8i-L>L!OUdt~&Hb@}| zdMUR2&QDy3&C%9>6@Evw0NKIr;b6^4lcjy#AUP<`c`5X>jH%k>1GIV!hv<$%2YXg7 zEq|;|MhLl^`TSDgXN79l=ifX%0T?RW@qrH>M|LG1q=50>)g zBLtE20i_0?mP@WzFyMuQ3jr`}5-6sby+X}92z=FO??UM&0`w*hX>v_cmO`9bS&mS{ z^0NCj%xBB0I=PM4s)(&qa)B|xGutJkW^9t zwNDihA5wZ3%p=Jeeiy)VWC9Vl7ny88tW36a+4&btIDv8Dvb17gpM6JGKwc*J&5Tm1 zy0hBeWdWoRWM&#+_m%AZ)5ijp5fHx;db(-Qs^jvUrGkhDT!1Gxb9QOWz)kQ~8&QyE zxykfKK^NyxY0GM|K9G?c5(+Ti{;a(3eF#dlB-H#o$J?FOqIPj*zzPcb(`v#mJIwNb z{?wo+S(XHK#)`lM_T=b;mf9apfJ8Wu?6P@YSI51d_C|@bY||h-zfhj`Tqk|cfu9v4 zy33dN;qLH{(X(I)yobz?50QWmxdHL?PHGS3Iv&y7+Vn}u5We|{?w2#-Dw@94r6zlK zCH~5`0=b%zHlcesdnW2ws0SC-+{d_$s=(xs(|~LKw7<*dm42axr<>^_wW3gxvqw=P zL$y3M5hPy*JEO~ToYK#m5SI&3q-z+=RSJz#wLnnogs}@f`qrjoG?SR5brGM}>Ihb> zdh1B(l0mu6loRnhPm%7M);{+0x&&e9`9f`A?9=nqm5aV_ZKXcT&CI6K>>j2Bhw1v2 z(d<>Ne&C70L%ivjn_juh#k0}+_aoIS6J0jvm-b0y^tkuuD`0q$(b59+?@d5Nxt!t8 z!9LZ!ec%;7gzVjD9*TBv5CzZ{mG8!Ty`Z1FTPvwZ2aJC z_qUP2dA1sX86tcAoD>5iD8!KA_I88(Hdt`f_imGCbnT#k)ZM?1(Imt>{NS3aB-QQO zfZEL8%Qea8M!jTjT=E`h(eOaN%>CDFS{JI?VKb0=AHMhBoJ1uSgXaASJF=Vq>Htz; zpmp|b8jwP%R_PHO7qaZVg&2I|j6wcDq__tK&|2Focy&%`LStv72JdSdTd~t>N7XD4 zQ+JbK8gW#P&ayZetFz$tfx;}PD>Z5Ounzf9LFTH4+ewhfQMn>DnDlkF14JtH@9S~Q z4qrKR`l>s>4Y1$%O{dy}ViUf4TBFc!qP1pw1k0{-mlS~`0jJ_)FFQjW?@k&6af8&H zWmG)wFQx+6<^V2RXsV^m?tsR^g!PyxY@W&>PF(wN^p((|$BOCY&8$Mh=1yh;rR8Ln zfWbAz$4Om-gGl0cN4?*JXWJriU2um>zI_)U_myzNu*IAEN$B)dw9zGk8)YfvkMi68;Q>lvO%hq#1j5!P+;G@o6;XD>At zq6*#!o?4L#A(ECv4Q@I4v=F+DACwO494*ermYyBkX%I-9uDvZ2tSYm@uG&dNLNcsM zSTZh`8klZj#()-0S?t~2SFr5eBGUiS7dldz{i_2{LAsQ`%@YVB{LmQu;muMn?ay^n zBS~i4ww58r(#uxM+E@Y+gchm48Suu6wRI0O6gT?p<5%tfz=#pf99yG7PzATkXc-O> zn2f0R0=t$jSka}S<_DB3H(wNwr?Xmi4z^5*eI+!B>!NqNERc)=)b=1zb~7VX?Eq5g zw+_dpMc>`p0gMgHjN9}V@7Eh$N3X99*5CR`2voQ{;3$ zI_r~+eVQ6z&MEqyhlFN^st#NK`bF6u4gz$HMT%Xi27_cp?U%MQPPyAXiA3OceiOgI6lG4=BIfa|nYNd^c{$4jEJ*~XHc zdPv@`)JM#I&r%jtO?gE|sC>Z|1|E|ddk?Hga=jj>goDm~uFXu79!Gc1FNuI|iZT1A zfHpt1?K&vw$R_FdWbJdzd!c4#v%nw`AJ@-seE9dDYGdgynV4xWFC?6%>zTiHLLJ`a zl%qNsW}*kk(lhC~yN8euebhJ&{Qn0Qb3EFrQh)hcE?nPpg8q>c$484@_1NYYYaAm0 zdqUn?ZF;zrXn%j!v;#xs+1B@n#usG8cz$dH&w3Y+u$ZJ+bMSa_{~f}F7UxLM#Vz@4jF_ zeWfe&PX>u2bFX#M=b7*o`$7ra3Y?rsXgKm;PKR7i@l+B3oaij1;7@_VC(K7^&w&I# zGGd?K0J}@pkUDeV&?vRhbak|qKp6oWInHF1aVR1N!eNwaGC>x4??Fw|uC_}$R{NZ3@xqU*RqXFepO3|fxOhN; z^;3m7G`Nt>wMeCu?(RMD%!eNg+EuI`dGp0PJQCIF1^xpN@Nz~Y8>Kqz2gMFnh5e6Z znSXZrdy=!qCfM0Op3vKU%AzmbxY4FyBPd$;e?#OyJ@{eg(HMLH%Jp`;Z#Nm~lc;tn zhS#tQH+nGGG~+jl0aMW({cnZe?66-0uNv=iP)qF5*KG8=t)`sx*Y@g{X0LJfR+Hy8 zbIOs1DZjlq>8>uS&@zZwT{W%OSL>~~&{4SiyTSW<%qK@ID^BJj@8B%3249}3-o5|y zI_Blu&Qsa$?<)55rAX9S1_{AZ-RECQuri|V)^UG z_(+ass5(#$lQaZ>xa@)@$v=_u1OuGOs(#~glElF9^;NAB-v0`l#9dpu^8C3d_B?{_ zhn-N&9@eM(7&egsTOY!jLw?Y+iKn1Q)lK#G%-K)`87QhYUqrm%L&W$<`;%A8rFi|* zhCaQ~>FZwzu_WCQ;Ys*BNol$N_37-lE0b>L;_3bPZ!>(q8$8BW^Y0Q1Pct)T=CU9H zHxS!j@}O4tk&yy{I!%_1ra?>jT_S2U)ny8g~iXi>7BM6rIQpW94NnjnGaJEp5t8&-!4 zYi%TFxle1eH|DjZJ`LC_&?o6tw)v~ib+r7U?b2c+mj3mm?C?1n?5`AJn7 zNeNd=kPw^sTlhS??a}g{ipwMD`T_Lg=DK5ohnq|R-^7h76CIr^8#R+|Jn%g|d%%P`wzY@D)X-LC5boU{| z7WC4Lf+EdT=(+_3^1ld2y{KKMro?RdR2z;0hIDNy7yR2JW8+6j;Rajh{m z03J66P+Im_hJdPyzsv-26ZqYI*-(D2!3rL7?bytt4^!jPfyq%Zf~R53%*p`Cgals8 z*^QuzR^jIh$L!i&vD@pj6$5^Mkrp}5S*tpV^{%EMPIJGnWKd!)mRt6fu@cPY(>833 z4J*FDOJS;c1-mc^UVK$_*@8~@_sZNcW$z@LFCDe_irG+JPta#QXTtm6r2}8V>E&nj z8UXYX_dS%?mjEz5qZN(UCszWl2^EKdETEzN=4eoq3jPk%ee53Lp1WA94gG%V*S(=N z9h^G<9A}t*nfylBo)}<29bREKr7p#|&Rjgur&`SHanWzD=cM*K#uT(SgRmt0wH%r$ zu0GkUn{B$v5lOLdYbbo4M=8jYfI6cmQzx8iATBPF*ON?oZ@s5kGDnNCzS2rDv?A3X za*Gw#um5Ys*$E)Y@$NEz0aPC@Jj)>QTkgh0|bwf4Z(Z$ zIH$hr0Q3svhZembK>pK^i!bO;$EeS&iSPBy$Uu$u#U2owEI)-(jmK*LK0fpOpOpcs zi%AJF;H9X7Sr_83eWbnagzi8gUkeI>4Jm&W%PhHeB!eq-?84Oke zG6v1_p(t%4(XW|YubM*CcT~%z!nl!4bhxdFtFKoop1n7f&O4h<;319Mlxj}fgJxgN z9xUVc=U=B-&Dj1@4=7D^7jn5*o_Vh(2oOICl{cN~vq4IFk&0r-~?CepXzB4Diw|=o4vo&M_Zd+YSjA%Bb z;2<{IFkhkg*J_K;4f98c$=;(nuf=1%vDeDw_;KVv8rFVSmecQX+^KM%=>FYMdD&Pu zWa4oip{2SH93Fit%osN8^WuXb)I>_Sh~J`=aTWK3Yi#ovaBY34QZYl7yR1vCvo3A` zUlbjvv$TGUqkRisaJ~n;ng}sX3f9aA&-kBi<(PN`JD8$hi$GDf!>`!q!u24$_yCqB zI!yA|(h9Y=-8h8G>EWQ7hw)VzW>|H0i%yUF$Fkam7c27#58z%c-0MOcmy9D!3r4?y zTI5f10m^9G^kZlLo-9ZJTrw)|%z$=+Z3S_T&26i zQ~yUU^KAkN32x{R%+gTt9|lvZN;en823{PF4y@QV*yZNIvz~qdul{{Af*??rkG(0N zu;p19MduQYXL?dA6W=KIpPD7`>7)7BTJ#l7&bDu3H#k2lVKZ-1lyKQL!D(F4kC>*@ z+a1Egv)WUNPW0wp8S?Uv6?6@psjrMz1ed;A0n<@P+0t7o>l@_?w|EiTOYEG9j<+@f z0z0XJy}#&U%=HdFhTM$z2+-Yh^|E>mOIv7Me=3ZzzXbE*dC=)0x4eHK4?tE`m~W~P z+NnyydxHX0>H33yr(vgY`}E2GBmOBBAmjB+iBUj<+D4IrS8WvW^IsNE0gl`^3}Z0# z7@>}Dm{=l=Fog}o$O)&!QOic(?8-l_rU39ov~X6qrK3`mJl-yrO@E?t+1J7$vQ-Y% zrW;cjo^2d@Z+UW^ax0u_vRxIrz?_eW?C_*ksUZ6|(`xW*g`>uS__iW%qg3oyvac+J1kNo?;y^*;m#?1iP z9%%~WUYlhtIO;|r2t&cc>7XjfYBVO;^zZi~Vxas%eP;rWpo?L87cZk-K*ARPEq{gD zXIG;A@;5EiBn%T$E52VfAVUhN+%pq?7jgrA7BZx|?Rr~PQ2{YfvGT8=oB&4M0sg}Q zh8IV8_chVXY=D9NIhOwGx|MF!I@r%4skkQ#?LRWxjG?$EgMo@p%Qx%NlY&)P{t1TV zb)y-ljvHm9fqDUXvhAWb0__Ud#G=_q{Kxmlsy#B;?Q_TX_s$VM4@=oKx@Ms+k?*xU*;zW~G#DK|_;n(uydPG& z2#j4 zJ->f9(Ly%-_j_|E+vXtKK>urQQyJ7ib^h)d{8Y#((`EoJ*$W+~=GNmi*_Rz1(#Cc# zS08Mz1j4FtJwtfWyVOuY^?v?ePh)G@sXKi#88}NfufdY4WQ`K14ptW?aDIqmUI@9R zi;;+Mp30}+r*IRs>S=Jjrp)7>jcY-jLNR4Y+nGcOob~pMegw}=2&QuVo^=X@2 zwCnxeAl1ebd4jUsw4ce|NKla1MiyTvDHte-Ml&|;$gRgE*Z!D>WD;sXkXDTf56)!1 znHYlIP)l{nOd{dwD)l0ajj>BycKRDS!V2z>=zKkA(f?@P9xM=wz&`CVS>45r3N1<9*Ghs%ubo+h7|w z5P@U4&fXNdW|CSI&=n~0;|UPor>c==VG+YU*sN#ipjW^hSyx@VacH*jItasiu^4h8 zmt<)+T6=v_0lcefJ5ckcljM00Jw-)8rKOYbzK(43y0sP+~1t`~y#uJc#< z^f;?@6_^3%vxrf?=wdTge(*Id+YYBU{GU+bqH+c?5N7RJK-y8th_PNVod5qZDiSOp z8iOG6=cIAsLA^b+m)~#-Jn1rVx{qxe41VipXCl8<%?VKewU6&}Cnl8EG;P6bdQY#U z`4M~N^Ku{)%vD7_4#f$XrT3RQm{?10z(FZpd}_-+kfvY?FDKYH_UTBhCLJY2cB7=E3y@9$~;eW9){Bo{3MhS-&eNZO-(Eamkj zfMJ6zJlCPlp;T|gnxIHm+~n_ylBqvX*rV-aPsFuF;(mCcDAmIzG%Ji>`X_5V(JOjI z=i{3-Z-%5m(`^W>_1>;%^jQRC@+G}(H#0r*EASJnaB_D#Pn!Y)xcY67Oc8QP1-8Gb z(FIE3b@?-baQpoWrulD%pwFkxANK(pAK<7|1Veb{H?`jeE9&isFrtL{jkImNc&W#kv0d4R0O{K&@Yyq}*@B|Im^*v;R; zuJe>io);EC!Y+C7Gvvuo9qijv;Kl)UEu{Wv?ew}I99!^!>c$Tv;go+D{|+1oyH%%} zX2v_a)W_4{B@DH-cKI1{)HB)eI5mhJg+Clp=aO82183V!w|vzZzI_8);I4%U2_s1o z!`gvszm?`h#^&qU(zT z%?)uS#T%Z!Qcg0C~#X>ItxO0g>DKBO6u!i5_r5I z&vvJw&?3w**XBo34pO_RSncDJ~7q`}1#k zzIV#_=$?A3P?+Ak*z~a9M|NesurH>^N3#cQoK>&73zL0yTToT-?%?5fJ6PEwUlY7c z77wYo@3$mFw2+Qn$t*l+Km+s1WjJ_afdZ@C8g}qn0Jp2#yo;L>Bq8$dwBq%%40)5@ zFzlLt{^|(dRCjg&VAMV`D2Sj(~cFe8O5i;`lpYF9k!=VPngaCRp z8tC@n!Uhi}-%1%^kf`{s!jmI8prSXEbS+{EV3e#zMY;J!x9LO-w75SzcIA|Ol%0nQ z*D5O50lY~l<`{gY_|$-zmU*d}Jtl*sS2cnjzMhzX&aJ3(%4q3vzE-E=%fgmGqdAKG?xKIilR# zT?aXuoie>g6%N@W+b@rvA5{o0pEu3PMm_|d+8u&HqPAk!P0brjnM#5I8nkS|hHBmG z-HW>4*YA_vKH!IMb+8PFvT+Q>R4n{ze8%PTn@}m((cCbH5YSF*-_KT@4RWUdVM8sg z;-4Lv-$Q2~(;--Y{Y zr~%deeiU{b()h)+VEMps%QQHmcH!X9xhq$wR=YAda1(#=aH(z7-PC>3O-Tf%Nr(e3ZCq-T7 zd1xe>KAkI1O>0Wf#gd3Li92AsE8_>&_s9s&{`+lY)JH#1{|V@E0&mF67qd1WaS?vt zy9|dPNgzOp&&^Evl<@Cv6b>$pLf6=*zh8E}y6;TwHU-7J^nn7FULPJAM-ek#G zR_5J(k=Ew}c9Z^`?tjSaj42(ylC=UXSMq<1siAH5G1h!(@1{Ye@qjz~YfVs8uv|=CdbN6wm)PQufvIs| zCBwm7DC{B3V=<`+j}H=MF2o%a4n?39tz}EYTieXnZwG5+Ml$8#g{tn_pAS@-pUeEb z2yF)KLH*a?!4YMlQ1cw2mm!vy_}=IFi64&3&Eo}WLA2rYcm+ldr+V`Pldukr7DhF% zp^VQ4156fQj1?*1M9q5hBPi>j>k@T%@!&(swg{k)cExpIz(E~-E>~hZEY!eBSla3S77*Vt>dD>8$7No3T>g{f*SA7jc4k8l#A%(RE(txf|+Z*k*}tW;KJyv?UfQ{M#BRvg{x`3@BaL z*|i?9lcrHlaM#P-z84FmJh`0+V<4i{%QD~vA;FUGP%IbN;ELx8>T=b!aW5r>lleLb z&@Q+3u<;@LD>V{f1gV{K2i3J_{b|9)A}RiC{P77qmXYdncGh#KRY!Z~6S7cn@+p&d z2!{J~HeIEQ)9smB6C$wp7V4uL*v~H2n%tK7DgBARQUk41k3r;?&GpuOkK|6$-85EY zv`~Ejkw=*p7=iyG2yyj=8R^0O@&xy*KU$60haF%zFLTb!cxYl&dj(IoB;x{#7Eh3B z+?zX_QO$9dlYVUo{9gY=!^eM5584&130R4h_YWg$S+v zYv?>GPQl(I*ET!T-)%&y{2=C*w;bKd(6M%V+!wd?`Gz$1slkg?LuzH#Zy}s(ag$@F zAe}z;+CD!D=g+$5cVfN3dx`gwy6=t6xD0A&_)K=(L-w$;&c5xxsGvbH5(l#tU)mf` zyWc#?V}VmB19FHv%yT6`Ib&QZGNQb$KG>K97;g8p>dPIFF$W&0d3Yq#*?24v&j&Rh z)wB7`BY{`GMa}hcKfZLir=(V?%q<}!*_gpC`20NYygx{Ept0|TsrgArb{||XVSZdl zb?XTWP)AEi<(+lW15Je3 z;gC|6y*D=?`Csr9{>nZr@Q&&y0oZS4L5_UGp zC4G|Ow;|iVlse_=|1ZMcGOntvYad>lE(J+xl#(t1X%q#Ol5W_N(j_6e0Ywx6r5gkV zk=k^_R*(*n25IRA>3Zi@&$-XJpXd3%U-YLRV6D04yvB81W6Uw=w1Cd#iGl1+xul7& z`txYiQNKGNkUsAiD+yRT&tRd8!R2mz!!Ehsf7Z5BwT+rI71#Q+!Mz1H8@s^6kl`E{*o4FBfrt z)cd4!y_SAbh&9yty|(raMW1L|c+>ab%nPZ{K8&FCh3XA?BTe=qOzf5ZX+6>z8^bk& zWK!b$>DLP6g(_#FZW6XO&JIlL-6>)DSVH5a&sl3?F-5R3^BDho^wZhRSkrxLXRr0p z&zt%2^##1sjJtWR>$pE zu>>~BE$W<%IL(*r=Rz=C*)%2y@tLDiPdFOseBTU!G)?F#-mZabp+B|*2HZILc4!}Y z!`lA~Jx|REd4hvz0 z1_!%CHS%A~7$EhFNQ7s!K|kJ*)AsXrLKF+rVfR*NOGMAcvhSsI7dZZh-EC^R%d^<< z)jKzPk6C>S#LcN)Jbc51a@oC=)&{c6k6%2Ka(=iXIC(nk-YClr8WjW2^NET+x+Y@; z%xN7J0>+lj`qeOi*ePpk-(0LQ;1jPK3!&>n#r{euD-X(ta=&Xt9j`NA8{XGoI_%=r zIUDbd&6C4<)%_l6!!U0kDj{IxUEMEXC% zJduq20$T90fpWUP?}$g>;VAtruF?6yRQJAS&}|1u7Gj^??+HYxyK~mm>c=i*e&6jx zCqr)g)8V58O>U-sz6jl2KfszPd=zH3^D@|qV=q@~jc708BCllb=xdACD^U4ICx4={ z_vE8g?pt3A?__ZnoFYTO>+Dnfsb3C=3vdENSnt_zVQnD+O!t1v)-{8M3*lWn%d;`+ z?92u78cjovVZND~P$wcM_kvOI@XNB-{x&k(7ahOkyxOWRn;j*-V|R>h)i|PyPI_Qw z*}mq-yYZV2#vf&Hf~-86G@yl7dBp9GtN71b+9jvBK$o?Chx+)q$qD@F5Xmbc@+X5Y z2(?XdwukCx#-d`rTT6oXnuWnX{tTwrNPShgocd+SPd^#w`wqn;zRR)@x4d35!^q19 z8S27Z_Pz3ludX<0_kun{VyU1Z^88iDd;)~qRcMf=#dt~EoTh#JD_K#D4Rh7(ja6Db zfe#!XMeI0o<7#X%F&{4Yd#dWFeg}@t)s02Nv?-=<2$n4yA~Ymm(XLpS!p z!NSaX$OE`c#5vVO1?+Yj;)kA?)pwV zyXGkK1d1>E$~X}l6xVTX!^=ww?ZlE}z<0-{7P;<>z(5o5)lU;|J{4icUEEpqZX4MZ z-k&KYf+6wvRDvq9)T4+I3E)C=#pIt0&D!mtGtphBlh#JJsPD%7tit?P27Xq2rRj|h ztFtgEW=_gr2F@!l=^Aons$U)MPjY2D4e_~-Js`pRf04SszYo@>R=@f=JiX6E4BpQP z5l_ZaWqdjpG3nb_D!OPncI_iH9Jk}sZ}+7eeI8rsOi=_m z-v#4@pK)EG9$-AB^A6S_P@0Q%%5dFPh`W0JLpu3*+P8diW#(;uwO9Lh>35I+G+F3e z-6#aKf}0bHA8}|dRE7Bc4DRHbUl)Q;d~KAf&6#f`LaEdk9uAF)aXkOso2DESZo6=G zKeVde;?eu=*-Mk@!r`6k+U5y*d&Rj|ST$wCT0m$rqX>E-dwaJ>2#=}_(|3?eZMrv{s2K=6COg9^i2En= z?(w{EzCTMJL2kkj{c@t=f#vOX&qb4K*mcRS;W|=ZuJYdZT5d62+Bl@p<>SEYKmU{T z@cMBV+MAQaL6Nh(<5nT=SvNK()(x9ZJEn{+y)ke{g~q$dMpFC3pIHbs1q?VS2S(F6 z=F7`4P*R6(6lL_|PopUH^{a;miMMd_)Z>a)SuuBHE+`c2Hi?taQre0A9)(cQ;lp8q zEcPIULh~YMB}h_1SI4z4|G7nsZY%e(^?!#%?=o74I0WBi2vZQ3_s;M>=N5#l(0H@` z07nJaRwHv&=iVBN^dWPxNu~5~0eOyx0AE7}8L0~vja~YxvHlLahu7ZxNHoVaHGBa~ zG22>*NOq2Qc6cUw7`EZ@uC+*^EKQejd*=YPK&$1UVCO<|C$q2 z2}K^-nIv%GD|i^+|_uxhT~hw>;cb~7>RL^@vE zSp;u>b`J-|yLwO_?-TTd9n590$O?iXKgA>@CNj%3wps8^e|G1C%s9(-sTkg|Upedk zMD%o|Vi61o#|8FL9r;KE7UA4(DMJ6k# za$PEl?%EC09B212@aNYV2}aVCH$Mw%xYaEkI^14H5*7a{8MD+%?bfYEgUkF;q+CpI z=LcFxivo=JG;%q%RT*S&?kyp_%0@%~noWT2ly-^&?KaJCUU%&lb^}G9XtM>FN-K7Z zFJb|o%wa5aYdnV5_xF~vZz}c*CZB>BI^k!LL2{cK!&EOypR&0(nm@i$1oP66rEF{C zdnr@wW51biQP&@4@(9&E!vGs3w^?~y)I?%x&fWP1Mdhj~?%VIeJI)UWBpJ7JzWZ{M z(v~*EOmQ_A5IGg?EdQEfFn#|6;{RuiK?ji)Rsic`7D#0HVwT`n++Thr(RG{ZN534) z!+I$_t!kNWz>Jl41mW^@-;VDvk$CLY5XY<1x;zS#vcjjwM~sZLpd}{kKZQRpq~J8M zpwqyRZ)Y56Bjb}Kt~Q%H?hJZ1$_?zZAB#^XlZ^3M zFN+5tG?zAW5I6_d)a@s;+2Db<1E6oW`0g#T!rnbKjlPXn9-{v4X~e~46U~>`u3=n( zMUr?CaIhRVq(0fVvs_3Smnu2#>`X}TF5sf7t+7hoNj{czwe&kqc5OD1(;zW$n&y?O zdAwC@rA!RtA31euTT>9_F({NRY;74JJU3FUOf4HM)S4R|ooh7dU zt3H_Sz?bN-eg6$MNmM6l23N-dH7Nbg%=eXK^5Aq~R$9{YK8uYm8;inlnq%KR#jm_~-ba%kO8G3FaY)t|I7k<736N~Y3=MSXIAe`z0!-y@Sttp^YOqTNV?8pbWP zW|Vt4AGBo!ou#mu2Jss}WMK}{m(RH4DMIe(oyXuHV${ToC&hZMf4}*)?129)I^fgd zfoKUDr{ zHk{Uk_Uz)+#b|y)u1%XE3QvpvAkT(z5qTI=Tn`z{L}_t+cpV}_?C@DQltm=%#;q{1 zjRf4;pVS>EOYdvUaSV(hzOS=(g=G6wI|@7smkvyK^YD86q;GxXNuzac5pub9o;Yu9 zsJ9w>jOey8q%>u_bvmyQOgi{|A6NJIYai0Qyq2Y^EOUdhX0~k0`(az2zvf^pwM5Ef z!`H0|P@=Ve*e*bVr??$bPW@oVGdvQeSe%koUakWf%jS7zKrMU3;(+1AM$iG^bgG%wMdSC z1SCm9Laup(-!~rR`LtH`3c};VE+O|qnH08Ko;dA!!jPLD600z9Rxe^*yjOc1= z5170wL_V<0i^=D~5o63**wmn=e@JuR)Bfkv>4B~?JTPk1YK#QNU3bQec%SV{Dy)Fb zzjcp^h|5Vc$4n!9H*!;>DqOU_yu-a=Wvs5{#Y1=O)E{5kccFVzb|ZDOv;_--dL>9@ z(fhfDp$=&hmDAphc<@}Wtd?b4vqnBYik0|Hxdlj z%al>tf$8ixcD<+ckam~^nSc06#YR9&#)b|aeAGEy(1Fo+0Lk3sAOgLrVfxr2`;`gC z?fzm#TNYAOJ!Y{97sM9mOiQ}>c}UR+$=*KTCR4m;waelYVW>dO`1Xgrj(?Z**s9a0 zzHfEPI38-bPItso4)i7yGoKBcdI%Nvh9;RL9#2I1`=0JfF;@sEus_}yFA{5MpHtl0 zs3~lToxDL|;J4G?Z%}z~2EMWD?jm@Lr;I9NL!U`e!4aIQX(A(S^tbK=eTRm9*IO#h zKSfGz$HHvW$JL`d6w);#=Wr$jyk_`gYz zF_WmjYmodCuJQb{F22;Gst!@Tl7*!LjNz3HzB<#f7ydGhWtWj%Sl72}^!%weNe?2e zLwW~|n+k`oKDlvP*9f_P6__B;x1-16k2_MF8QZgG$ zS^UXp*5XTLwdO3@r5z|d&qEr<{jyk$OA%5ml>6&ZAl-2z5;;`Iqoc)MgOtiKdEY{3 z3e?%&UdG1ylSah~3jv&V)Ln=fQsRN7xVz-l5Sp^iTA(^grAC8PPhR39cq;ej%ZF@) z4LSyv_fLtX#T%g5&kjzcYUMJLKUgu#H}^$b{I8Vh$u$J&`}5r8(o*ogQY(mHCD|Ve ztFnJI=##%NHs5sG}LBwrs zoNYKdFNUw|Rpt8k6lleDHB-NbtvpF`ieCyUo(`t7G`n~nOjCU6`Jr+9VYXH~a0(|rOD*Dz3< zUez_I3z`;8)toPyeNDGMK;&0~WT?}$&QqN4sa zplhk);Ae%s`olTj($fA?vmGXVV$|oO71Y>#GG26x@V3BcKV#S6H*FV!VJYP32}JU| zr+ilslk)kIUa2)zPdQIXn2dpU7uc0CGAUN^B&Fp>?f$Phw%XEUl>Gs&#keskG; zCKT^^?#0;Sf(HsE&bzmpyt0dah$fRn9t+9roO(sKu`eb0E%#bZ!?Kkm$_+V{1<$Go z;N?dnv1T~jw>dE4?GF~?m=R01_d~lVkZp+ZBdxp%0?&le4GEW$GVi^`z3v6k2%mL!Z^P3$9gJ2;PMtq@J-jJdeoPPm)_cj}y{?T{ueyc)*e1##B-0N&?Y3l?$@ zvq6gxKuSzU^RFSXxn;P^mVT!WP4oV={SC+AWBFs*dTP5HCh;YgcPP32_i{B%M(&MQ z7T+AhRU5Ohhq%G!9!u2g=D}Wtl#X#Bg9~;mWiPD8#L@rt4U2#5pih&VmYRP(@WaT$ z+wy;r64%~rCYmq{xo|L0+TYNsY+Ww$DStp=6(gU2nbpuXRWbiA{{_(VZ7Qlst5N(X z1riH6o!Q=(t*qi$;1m^1hWg3eND)$ZE3~95`La$(S?J?bH&DGFLv_8SicM+I2j8d5;!Ryz;O>6k_E zZ3K)xy$Ba{vTXEB?MOLO^!b3=#<=F_yfHn7nWVa_=nX%6@!sOhy?DX6?omHWdwUlIV z7T*tj!b1Km<#Xw>hT<1_l3chAgT1}>7X{6eZq_}VxRf`YX97wm8{8^#k>H&LW;q36j|?kbrge23=vY)0P9;U{OUnqV&w zPOpI<5n(^uGnlGe#SO*p5ix*XJXeDtOV_FMvU< zq~tXccpL48x6$Y9{*1N@qTBD@nW>-Mpq@Ysa8l zf&;(fb0ds~Ii+LeuTa#Pq%3KBOc_@v50%gB+qz>E@XI*VpHZ%soJ$YGgLb7n#aC&c zPZvynf7UA_N!id)Gb^m&y-`CIF136^^2k5pVc|K$OIm*yOt1a*u$^wY(6rN^B88pr z+J?N(>7|xEefGT-rapHx>)hlk*sHJ_TJtQoHu%NIMt@ouSm43!+lB_)u#n|HT+hrM zKC3l^TKf3!ydjL6E~en>2*TN2xfmeu#6-8>Y$9;(wFejp=C-DuI8=z+{e7dQ@OmfF zoqXn;ZIOm1N_y0R)9C%{)u*WY(8{95Ir;52_$j=p_n>9+oLU@Pt(`Vx%rARQ3NA4n zJ?k{CB?=!7+3@Tm!|qPDDJCf_dW&8{2Fj*DN#1SgNtxd zq!R&Vtitx28Iz$BbA8VD%O&TcD7aLpNTR+8@;K*9kAJQ4j{DjfpSN-3xkOM~aiG!q zSWXP9*2`nf>x+)x(Y98X?c<84T|pm25OF@6X(h-leWuuDOoYu zY%5O`>UIq+>4#BexL#i@q(&V5p0H1(oEL~B_h($T@?A;dqpXcthh z{+`$0xY%?q`n+l_MqWAZ*5PzmV)M}V z;WCBp@u7XgUHc2Vr8j;(uyvC!fFo_0F&D#sE6w*`<_X?a;pA0$&?mY1=r0$GNq;He zs*ctXU3hGycSJJ2sdU&!;omuX#G7PdS|$V+Ieqh(S~}T=%V8gt*c|jII(8l(^=>>e zKhjNSo?qf}`{bDs$(-Z4hhJAybD_V$xWSl(tjeHIn>?MR= zXeUJSYT>#!$3%7JTJxx6Y9^#x%R^X^df|VIkMnGF_dX=2iQ5Um%6aB7bMw`o@C}^= z2rFab!L2`T$d7|)cYO00v`$)}vP8whY-QRhct}v>Umkyr-h;9RZm$LCcNAuf75S2s z4Yc8)GL%n?@)PF1tD`_a7JmpifGRgm@+{Af0{_LN3<1)n{G}MQU*`=;^kuLKrA7|3 zTH+!>k#UX5hQWIod<5A!==aF~j$OP}oHVe`fmG{Bkj_HOc0p`4@9$-5 z%!H6-U-&hPco?BtC`8Hn^l^tEW>zkH{s;$(C_Y8yUfj1c*1`DzVIVHPy+lgWV}n(? zFJ&zmB5$3hEU8e`QoMeRP$O|(4`1M;6<39S&X4klU2UsbWANL2xG~r2(%R8XJhG2m zKCV0AGmYJUa!7o*KFFy0X_1j3)VR*ux~jh|ymnY`0(-9{ZDQV6XJg!~NDOX2j0Rl! z{|f*dKEJt7wFXU*LFXSej-Nmbu+7Ju6T%<*0S%SJ(4}NhQLcDV=%I8frXpjdlt+lFH|;|I)=RKX`S%#n;7|+! zfd5&lnqi5dOUmi-an>B#e+KC~LfieW*AY_5Sp1>NB&9IGi_$!ggb0bVzqv$}9jxz% zqn^cu_0S_mfB;ay8XioVBZ^;i-`TBzr=9M9!lBKJxHmKr(pc|&dHtx%$k=ja-=pI- zxY4j-d}Hs!?B?RRRB+vy_ce!;whI#rLq=|x6J9GkCk{tO{9F5N>}i@E_Y>|#6}H@b z&agO=y0d4<7iD2ryS;Hf72wU-WELSA?0<5aW~>Lx_j+#L*wp=IlJNyxo;Un*h@}P< z%5Ih~F(ORS3KLaHm|>ar{J$g{c1qw4I#egYlpSmeMR0I;ekt(f`T}O<*CAY6SmkAu z7*vk6sfitFT;RiNG3OJIy#Vvc#n8Q(6gd*<%813}SG$ngXx@A_G(x0H0L3=B!8M+* z5NB`89t|@`n3eQ6#Eucg+q1Q2$;@7ha)ZbaX@FeWHT3Nn6Qww{J2U8BpxvT(^vXbu zjC)LkN!8clx*wku4CD>(D=^D#rW%t|QPR+3ZTjHPf zaYWJ3x0;>FU1<5QIA|2aYQYlZw)8Y~Yiy|@w*V$I^fH-`-~I58j@KTGkb8G!$!4E{ zL%wB!Qi{ZSaVD-m+X}0Ur(OM*`N~JDUxcXz+T_!oERSdnhw8l1&KJc+UK7Ip7UGSe zo9mlavIAh(?Hby#4K;KnfY>z7u{s?J7kR0XCa?om#2SolJt+Sf#ndRdY{UKX`%InY zJxx#B0@p~990`J$@a<^k5q_}~jf*MR{7LcLm>3_n9W8U1`*inP)ti~XcE9?#0A@G* zp{Q>oUUGu%qHxEs3amq2^7#^T!h0^>RD|fH4_S7aYhqkiq-XWa3|G+(uf!AD$MLJN z=7pV?MDFMa!Z9=>N4BjxM%xfC_;ic~VR6c}EL+ykK~O0qf^(pQ>K`D=#DFR7Xp?pU zrk`l6$CWRIur8Bu8rR%iFfbd^sHz zlXn;yb_45O=VURC(#1BLgwA1;w8PxEeDT@ueYM+`${Eqe%c8`MM=OQI2?Yl`W1t%p zrsZI0-R8-p?I7aWn$u!W)(hnlKkgU8@LqSb0c`#*-SV=SUooxxbi@TfcE`6e->a}Z zd;AoU2Va$Mn2*P`*>ypi5R?#jZL`$>ePf_4>W5j$z2K9EJnSgphmKlPT@3-jK76*d zDzD3yu83eG>!%IaDPLW(0`@i;oc5=lH{9)TIvTR1b?fb*z(-}|lC8b+O0qi0=8-Rn zSF*;?Jr=h;M}9m#`AnpHmyrxLN_?UXqNBbRFYSUg0Qmeth7V;YoYnL|_Zg(v{n35n z+;IcX`}PLxQUzX%ql4t`*zfouR5({mGiwd(gA?m!B@sdRcWkwi9y$9I;out_#2xR=w(?ay-y8NOZoq|mC|Y^Vo*8jRjmy9yGfb{)HX+HW67*|F z2w=`@YLcRom%~5bXe5eHGRps3t%U5#i+Oh=-58n0k$G!l^?|^8a(-(5gZH}_r zE#Xmsm=Pn*_pi=@+(m2WeGCE;R52~71)K!|TJXgpIKuRAfjB9%;svPI$5Tv%J?%dP zZAKl*1aGRn!6RD#@;$qDP$3664GH*dB17_~fd9X^mva9Oa0axQ@!kqQ*@NH5-xG9~I{d8e$H{`q-x^ zLAHw03##3{Y;?th)0d$rs5YCa)=rGkN5Iu7TP}yquHv>vUAZbjmrc*pF215sNMwPJ zcYG!2i9w!^ovA% zxSLi1F5Is*cfTHaf)W3PhRz-`s6Q|}Ikj3a>u^kcDUB(rG*b+xf58RcN7?LP%F-2# z4R#Re(k)x{W*JG2m3NAq*{zL4ci7|f-)@Rx-l*C>*TK9&gYaS7I7o!1qS`$^iT~JOhQ8yZt4>LoKF6%= zi;JOM^xlt;AHzg-#CW{$WkBu4h<_n&;CYfZym|jLi+;Z3OAM8KM^&NDDBLHEb@T+@9JZR|G@54fE`>y)I(=RPpY;(AsHAll=!iGAu0xX z!-yhEPmsTSne=N^PQ-RkzbiFjmb33FtJ_ZDOP-=SkGY){*egu_Tnvqwmh&SYkxLVMeeY{BJEIvkT}j>I}VT4z$F&6+PPHxw8?7jEgoHOo5> z((zuq?$8?95GHYC{Fsw#E^w}^>Rt>n#^u?r0nZXzM)M=reQ8Yn_@nQ1sEk)pSjb^V zdt+=Yehgi~H$#{1*>7K4rmillsKT=GRU?{#0tm zg65>tgRgb_Hp8D}fqsURqwk%#sRv4j60b<2Ox4 z@!+1==cUmh;2-E`;(=L8{0Z&s)Yo8F&&7HDaXQV5eo!5FX^>n%;G27*E=9f-q(*KW zrMIWS2r>C(@DhvF;{xQEUFSs)A5o#qpEn`p21B3Gb5Fi~>3!7Sg}CQl+2{PT&Ug^~ zwex8@t-@f!oGEc+BN}GrBTnP!KHG@OZ$Q9;D#9!XOrwe72YrQK0whFx+~2Z!V&=%3 zV$C(gUO-t_GfU)M%JCJPywckQv4;?Kw7OIxm?$IYY`#Oi%_@?b5JOj&o(hBHfgp96 z2^4RXu>43+6BnwiBgM1y9Z}_?<}T^(G)JABJRk~?s)1;Gb z1cjFB6 z2L@nIu@)G>(BvWNgP4K_N!07yO*ax00V9S0{@0U$0ZjhTA*QAu=`ng3@i9u+*ZR>S z@OR3!?;;Cug2-7B*3T2_q%h*^w7GM#AtAVzzKuRmHnGHciFHvH2EZJ}hwH6RW*j;I zYy9K8twu~(XSs)qaX3IMTr^_Uw+fS?ipP%s-;iw~ImVf|?*hED+(7%2k{g{0A0=?UU3q5^3;j`+ z!f1#S?xQwn4kP8i zgRk)F;&b38zaIkWs9#Pb7IJmZkNWbfi<@3~Se=~?ii=gY1jD~_9o7T13I>mae6cyr zeyl*!oUmNcooitS9T*7fo~eg8uc(ohL#7#%WGK=YiLLfhT>g9<5>#pQJ9`^VI zFrwQv(mOsL6r1@`F*J z!=+^vp}>{8riH=a+M|eo=1mLVO_9O4LBo12(!YY>ua!JtN=&QoG*$d|1Y^qgDj8Pz zSyhBF7j8X5i+R}uqj_X8M*hU&mr7DTDb)%_hqu3D^*s6Qg_>3lTmx*RON;4FBXrX0 zzQC7Fqhgi(AbsG#_45<)o7j+M^XI4xB`GE5b+o{Mp>v=wNl~SZof8bOPGhdvehq{z z>L*Af^)K@k)zdeakIgM`p8q(vxNti=OuU_bJnn;ay` z*rGhIIZ0MZOGhKNXlD6fN^)Q3K@9*Fa$YSGj*p=mXj<~|BL)`I2V2f!JV>@NM7HDB zkZiQX;2j^a+t{%io>N)U^q=0`mBjM*Og|go61sF6G%FkYbF!#^D@emYAy>wyOv9Q| z5I!p8iT<(f1=PE)`0(XOaf=7&EF?&kDc-AC)hsuOwO_WlpJCS^`Ti!3Qad(rtVzsP zx-|Y5RenshHd*!ar$0g2%b@^!$x)3k=X391`V3qe7n`A|jaF$2ZJyihbV(8S_jIZ)$kC5o?pcm2^@Xb7Pf5`F8S#|Mc_fYM@jp+5CU_YV-oBb|Wjf+TB4ojWgG{=F+9zcoRzfpu4#fC$H%2?n!`!@E?Id?q*oUP%lLhDv9KX zy@iF;HFs;imdyl~Il+nLDk2P%U*z4xSw(~o6&8Q&#)GFv{g{6eHN5ZLiduvC@5c=D zn0@~#!4^Sfav5&y5id;W)J;oJUruh>Kkp{at2x;6>@|e7v0~{RY(s5uo?SLr7J+Gbvj|fQFugw^ zqVE{P1WLtra>0*}r0-d>9wfhO#;HAcJ)=QWRxaSL@VBTPiyD2{xaM*ZK8q0G}F+h;X`8tFOXPv4lJ%QJ0rhfq6=H=*4fIGm{ z|NcZyWZ}O-*-0m7_Wa3%fO3j!9!eJUu&KM}rP?Yt?F{s3(lNAuZ;K2qt8$GHXfWJs z4SXnDRhgk4fJZ~#tvu(qKwC(|%hj%F1`~ZrdDkAS53_1yT^VfBiZ;4Y@=g2b9{N=X zp{#t`A;hz5_o2RvLf+n3{NDMx>Z-5;SYMxdpL#3#ZF^{p9;E?G+lMwE2f62A!`UI? z0S;yni_F*7iTYS}_OPiqsJzg}PZ~iOv$AplPK3BeQ4=;wm*;f@G3Lw2z)-?qFPwsg zOvwa-Qm{vXz}FfSOkg|@$FO`X* ziMkI%Gr>c?+ko~&pet)Y1;`)TgKro3^%^D{^y7Ill1SN!C)WJSkIh0@R9?4lOwZ{` z`McGQ`p)P!_fw)gG0(qh0Sbxpew2FY@%t;#GQG+1$7w%VxbLp$vuXA1M>0P|rknIY zz+n&!peIv)WvQ;?G-@UVzrJu6r+1j@hVVHblFeeTU^p)h7Pb2bC*-}dV3|NUa{wb` zx|0%|BO6Qpdu4~sUP6>LO>SIFzw=|R1g4~%3)$i1P-g>pq~d&d6ABs*2i*=k z+Ru}O%^v~-=@_}I@~Jbat^3}SHi9;Bj`J#<#S>f9$x4r<=G5Im1Yq;lC3-zU? zf@_?we-Vq9Mhp)B^*PDHf6;FI+7K}r(;`+LE?K0bo_OkAY)x_|L{4kGFEe1ZN3VZ# zY>+&;HFwf~$uOu9ckbk8z9P?bXuQ$#g(LOb*nfEFFbgPf5)gtf-AlIVN)C+wc#@D? zOO5b7ADVnZ{+_p}d?n+QU6Rrk`+Dj}3{a0GQO}FGz^IifZSTUNg{vnVE@p2}ekhkq9zR&m=xSJHq?QI_D#qJJ>k8CWYW+6=CWMQ$QfrU;am|r>X*C zLBu-^itX}qZCeTcOItH+L^k|F(1 z>AUFV>s^&n5`oyJ+-6d<&8EL$GkCU5o_g)IM5NY!CTPNgAHK*&#^NF7YM$BAQ#hFb z&^Y#u4tb7+yls9l|LMQK1Ym~4#g-5o(rsOuY9`}(Pi_Fu;Yl&3|5Kq2i6V}tpoWM{ zRSlLmLJS>h2j^#Ev~m323PlQ7=!%*In4;>8rtLg=ljdBH;oKU=@C)zcaCT#Fte*PQ zI2HRz=ToDt_sV;pBT}m~-tuB0JD(}DJg2olC4Mn^_fj{W;6Xq&fjO}LY9eg^qi8{o z=`z!MQrO^Nt12ohb_tSn3Brf`ciC^8c_<9H<&5mRT!kr>D2$iffm{n!7uB}FW}_(V zkuv~0jE@AZ2toZLK73^Hbjp1i3u*T=sl!+V3y`lxm!aMYI*!->(XT2-pV2~7Zk&1z zrqprs7hf55zJQwN^TAb^e1bL46R**?8A==<@>XtdSNeFNmda^+yv2077<)hvY{1Z@ z20z-t_5B2uKx}&v&J~%%A|1xhd}$3A$S$Tnt(Q6~8^1KO|32bXqt^59_ z5~L*o?Ytq(uvZX&8J5zEs{4uA7@AD!vcK|i%?y>D|0?tQi@$U6nNGMy)otdl5%1p~ zwp-)bN;~8mqG$rcR?`~jRqM|lWfzBKG12HAO|P4Y!-n*{BX*?8UW+Y!5~%b%#~=3k z>YjSKW0gFAx*vF2keAalEMcBoINfR#u~lEQ3vA&Y#fE%ByJp#MVCqw`V~?M*udCQq z+B)1$i-sjyiqF{_=^+|7lauL-X2UbU@0vzU5k z+~yNDYJYwGY{8MnvW<=~M`eBUPG`YB$thPL#xJ^k*_)g6Uz8H+AMhn_eolI(Y z>w_Vro3}qHw`2$LVlVtN=?B5zXxzJmV zGT|Sa{4d*P2(e_HW1SNNY+XV4_MytkMqrDHKURaEpMF@ZhHUV4 z@s$!9QMy7<&E69Jz!D;B_0F-$vknFc#v1#BJH(wVneOdUE#R7QeTfsp=k7OdCK%zs zwv37~eNrZ{StdJxs*1m`0S{;XvLTr!) zij5m{{#@FQ`J%t$K{jjqg5NcQq`*fa(|8!e73DIY4WcNq_+=Jfocc)}d5;vqjUHZ# zJVqN_o%1N!LZNKgzmiLx2r;*}=tRRsH!EOD@Zh4O51VZZCF;!Tc>18{#Q(|4XY;6V zH*JGLHo~k6@M35AOkubmo*=Djhzo{hM6GzHrRzl@9yN%w5~tH7LW$?6RSD4#Bj3#~ zW1Kt&#K4$XFHV77I}7clUfW!yn{>Yb6(*EvFij2OS83+&gH_(wqP-x9Y00X={R~vk zwJyI>bND>1q+|a1jka+UT`X*6GE=7eY=dyC9XwJWNl*0#3-_iyVIe-;QX^EphH0<^ zB%MA!5~=0a<4EYfR_-yrNtiO|eov%BNr$KaSffawwa&vs?<5AszX%ObQ4gTw0s`B4 zLEf4MR7LAoTj0a1y{aw4pn3g>$~9FWOVTUKsrg+e#EuOSp^VZE8ku9*$PXK!@BGQh z2;Z#crWE{BF&K$)F4>mE>Dek`(jqf2Z8C1y*g%+}XT|1jK^D#rMID{iFdeN3`n4YJ zPUywP5$V?DrUS@!Fp>HhPGGJO@aG;w#=lAig|eC0-n#fLf5qW%3x8%WJjsceQ&^fQ zzYXXrHo!{V?xZ!4jm+VYvIq_^c=wZx|RRn@HL3($}LR~SGShc*+%YYfT2I&;<^ zc*p}g#N{=V_1?VJ-413qJ}~$tIbuOq!mRzdvZ~KfB~{)U623?NVKwl^Uv+t_Wq}MD z0d`z}#VP9lJ&3l4#t$tuFbo>mpSE7@JUrk5G1)yEWOU!W@9f71F&P(RIJa13&(eO! zWKj0`z%DNLDlqCK{!z35sO%IQod`Am+Ta*Q{Hn^q5pLmNZDU76;dx#O?^rtS$u)Q1pq~V{1F$A< zQvOs;S88v+a;^%6N_=~iMnJ9u!_aj;uFskSYlabkCLebS5&(^wNUNAy8-{giCrpvw zPFQB=lNXt~>Th!V^Qj7-uuAdwlRK_keO3;i4^9gfqq|67N6&(Y_4CYjw4{wjZgXM8 z{~8-QKQ^{$CC2$R_7~-&mIOupPeHaUf8|4d6h5$(7f#yH3B;g3aAN@xT1GF!bR*~1 zeV0@Ug97`Qg6i8!TX(EpeZoFgMkH%Mf2bHtC@Rc!P#*ikUjaGiUv@o+lq~3z^Qas@ zumg%Ux3pdJOUrTh%JeEcZj6~YDg;y^pTmENdDaO;3GHmwL^o6Q0=y)r9}6!ZDuN$M z!31D;vcHZEk)vp1{~EI7(PAScMG21B=ZMjRXulW&e(aA?-t+m(yUS9pgb@6oS=drZo-)(!iOwP#Q zH}@%VouI?z5{fPEx>;g5FyI#RAlNIlX%29b{)?jl5dZ-50``){1DMK9bEO9XKPg)O z<7xjaluX0@pCs)H;!CdMrF_DF=oNA`-0}p1cR7E3Hs=4GN0m?s0M|0DUL}_m9CY@L z4>41aX#Kwc;zg%~x&@Eg%)>!baL8j_&I7c_Jiwpkx zbynzI@?V8(WGKNQiv-uoKa3zO$;rGxW65cr9Q}f!?fh2VSoMekBE3^B8^-)FI^ z-0atkD*p_atpM)_*(0>^xPi$o3F7w91vCJGnq|Oj_oRo=Tgh-cQG?`{lG4Qfrxm)A z@?Tb{pdLUk^WAPU`@dudOlW6VrThg!W!_(}A@_f*nlfP4hf6D^`rj6%;MRvtUOBS8 zXyTpUvQirNmpuKI1pnp#2PQdT8OTE&swUY3r1c?UJac+{6uR&K`Yk2@&&2}%a_25P zeRtL`sIvG6Q~`(gpVod8M@XX0H|=;dwZW#i3*?UOk?+(~T(Csd|G}HEiG|Skl3rE4 z?MMxhl754q!iE2iH$wk2-r&KvmJM#N#2Aq%U|fd5ZSdpOZ_^K3a=y;`i&?$`rSbpt zHvWiVpG&TON8biwuX_>4=SuhSalRG>o9f9*FXfmVWUF@LSsxyp;HtP?AT;l^aAQ&5 ziR_{!if;AYtC}V%0jpZfB|qN3+>@X%w0qKtc+c+qQ5bk9AGfUvTrhO!tGQh-ilPNg zeAU^z#*yEiBlkaobmzYT{iPsw(ZXcGV6^i1;I|YN?TV$BK=r%=MBz zckBJ2a$H}4wjB5^QP*b-yKq4Kzt4UFUGx&xk1l%2NNFbcfsHyEFD>dbs@shJjyVj6 zK-Cj|{L*8quVS39g|OLDyq>Sh+PE_s@q5i62d*c6@HH7SZd3uaCe}?=i5D>96QfmV zz5(-*CP(Ul?V;9Vi91g&xlYpJda$6{Wpl8il`%TsG*B@_nXp;^WZ+L)ar~SUCAzM$ z?%K7O8|>SaCE4)+#`z!@b-~Q{DqRaXn2N_ z!Dv4t%@qI9^&{M5zX(o*w$oW8;T32SJg;AU{_&xMS<@@w`z2Ed7JKj=m3n0iv5}7k zTD7HvHhF}MCq*5wxg+l+P^MtDf21Os3}mt}g=w?Q9!c1Yg-()ou7<>V8q{Gu%DCP! z?>O6Jrl9rHY1A}-#5TItiE;) zu4eLVI0)I+P)6PW=Xj1fT@f%m7q4JB;)R|?gE8`A=&*5yfcNJzC3uy*=zUu!wv-#e zK7qaPK+^qOA>Xm!LyTf@gao$M!e5~_7FJ-;nitR%d;0yF6#7k8`{vlEZ804THfTlP&OR=%Swv~1C#PLum<8chbq3TQaG?ZHGw<^&w z)P)SZ87dE}C{|7L$-w#8@m`|bk;Wn`@g}4y3;Ri-xjz7ArjTf4Uzy($e^AGVcuLWp z@I}2DyjH*BX}SWhhpn$*ZDE-xiMU{^NYS|~E&MxqmhtDw#XhIw4UfFr(PF+LM{B<5 z8eOL%(PHPkMfHhQ2OkGC5tU?L(w%ARnT~w-@74R>+o13j6Jo?|Arau8`tv#vvB@k-f7wU?9v1I*zuv{%gPwDWwkkt+Y!@ z1GGkhCGU@buaPZ1w`%tAJ+yvCd&1y#*VNZ;<$L@h=O_PUYM5z}xSyD0?=G+!)yDbJ zlAZ>>6{lphX-t~h#%OrIh%@;)x+;ElAs^0o%sMuKb{@9&gECaew2lsG$xS~v&;?kv%lC3#7|d0Yh1LQFJ0h#3-S?O(Lr7hC1sp<;7i=g&W} zC%F~E5D3%krM|i^rYp9M^-SBF9)Fxf)LuBc!7HMuQGIXz7(!1AubVp>^lEaHKZD@H zwSYO$Z8sioHhRB}P$MOjv@>H1+#PfBV<|6?sWf}=*JnomR3EJt z{)g`qP{zlQa>o=-<}d5k)$UNh3RkTI4MeEI*Au+3Sj9un#&aGQ4fWY1^?qyC#s9ei zzT1utZI>Pj4w}N)2p)>?0=C=s3O3E>pMHiEU*}T%q|E<~xqw-8xK3^(Y}JpfDkZ}0 zW2qpqj56de|6}{und%NAvIPp$nirr0X1qiOV^YK&4LVLBpi{uA79)S6cH+aiUyNs5 z5kv2ExKxDRV^{W={f9}{(pO8`X|zr~sRyplAEWOl1t=|^G+4HIo%gtVTlI?1y_*a$ z0!QBJgA_m#7P3XMx^ja~gOgt4eopL9Om7UFSnlxuYVc&`t{qV^NP2@M> z6`wAVD#LCHPA8v+4TshyC(2i0)2L>sMqU2%{C7r+Ls?V6r03&3DOjKIYOOn@e%*>0r|wEA>xYffN(Rc=12O zi(U4OQyz6v^~*YD`RV)=5B5??P>)!2;dnh^J-C8}|Hs5W6K#-bk*Ic3u|;FDlgoL$ z4N#Y;--WC7;b8l@R*l?Y@Ejv9tj_F*ihrLVo(u=Dbg}85>PMGf%ZDvi>oOjq<;g9zpUBd(jq$Ki{ zYI^xT6jAI|OulLfQ1QbBbIe8Faat+8i6rn}I<)Tk)pAkyrKh@k6KrRZ+NzY9x2EtK zJQ(5Q&&@5FJ?D6N5~Zeo?%lg3CgAHC($q0uEGm#|)zP&tDlkT9MSbd7@7-$IxRuva zwC`QzWY`1#ezf8zA6gZgjJFOZ`QPJxKoQcA_=TCkjOVnnMSrPva1mnr6bn$?(Th#z zSOJZv>lm6|p@#yrFEWZcY+q7i<-Siq1Xo0yHS908;p?xQ=Fymiryi#C%!mf&m)?-d zb5`p}*qFInfMP-HDcaNPijj{S3g!{`;B~H-Bh+B8VN4VG+ZzIq`PONL<-dMA7~oY5 zTI!#jMDtk{@>g%scQwfZYqy&Xhc+}Pis(`IHbd0`vv$KJArt(3@2(B*<8lb!p2oy} zmt{7)@3B-@gU3FFuSaOND+b$@J*lSkQ6HAqm>0g(%Zbcrsw3o=khijD%J5d+l8e8U z{Z>3gm&c_uzHr*&yR@5m|2?h85U%qW)V&R$ID%%!6wZd4G4fjUXIx)XTfQo$TJKWj z!o#J7g!Sq*M3eD66YY@J8ed~9l2=K~SYt!h^4QoGGb0thM8>!ENOtpX{pVqWf9?}t z?WDkR*xu&Orerd z2^~@>ykS%5Gi`MuSA+K%WS80?WH?YStk>uJR}&Nj9a(WHAENUV!dCa4K}gq?BNvLS z%!pdaM=)1DJ$sOnDi!BneNbOusUvo1^fHNmwrZmk4#;ANRt~_xvR4c0B%Ev`%iugJ51s4E$?07-}$!KLS6HQ*u%NTT?Al zxaNooHMdbM!>}H(nrTa1z51Ey+@Jy@f8QMa{rcYh@6V4p_s{qkn94+r=9?M>CQw(; zikkzdoC-yWl4YXVl{pSvo8->kOekCL&=gPd$Ab=vu8jP%PfzZH1&EL{`DGfr0@ISc z>6LBP7~>UpNO44OHb5pUX#Hh(W3GUfx|RiXVZyv|#s%|967A%$qXnDis#I6)j@;08 zhM0Rq*_i9}@r1el*}AVb_eFz^-4#VC9b_O}F5KgnGHjI7pPBd?JT3cOLn$)+qx=s4 zs#L&4WoDj0-8a#C=P+P&AoWJ^!aehp{e?PD(;q)$Vm5xbo$tpOpGK|kS${c~b3g1! zBxI=6s5|-0{Fzt1QUxPl`^2rucl(bPz%)1YSu{40Jmfd#SB<&#A8|Rslx`~$a{RO0 z1{}Sx@tN~<+g_0@Ihauz@v^zGLd( z$Bfe4lqctYN0IYSa<}bV$%JmfwVhKKD;89$0b|UT<+VDxUQ-bv2s9P-b&*`p2dv-ru~JI{yLPGN#tpfw#R`g*k-)0^)c`-@2UtnUmnC@D*HsMvPZ)-hS`R+qF zEG~L?kdzF^kz6v!vlXlUZLnifj`uS_LJKSDF&~l&k#kz)0GHup0KTai8)nUYpX^DmnNNeLtm5hw@2#!a00xwUM$mfNh0? z3bn|+kwLuF{_%&4=Fxrperc9#e@9BInE#HH2R&F5AJlZ-NK)Wzl0rre@MX={WS5cjx2;Vf4+%CmC z6=7PtRx;mCa^B_K%b@$jzk;s|DRD&e^jBAb=>P4ITvI`I0~C;a1qijcK9UtEyaYt~ zHw3F7)?e}d-y#@oQGTh^C40d(iW!oN-{7>6vsYMn_eaAxG zdjfyry?*ZCWZb_vHuG0Px@B0DR{8doO`iAAMEDnJ61 zj9?sFtumDs1mUn82Iwmn>T+o?uWwy)rglSOJj;K}>mZEL+woB>I|YGubf#f`0w_J$ zyL6risp_pUG%nM7)VxS_KcCVcD3V~$g{rX=^wmz>uqD6fHv3};>BW!zsyOwk6?4U| zU21Lq&Iy5l#?F31mp9=5iArf* zPIFbr!eYuuE}HGLY0Qj&^VJDVk@aHdn}|mru7fRdN#|i%^zRqw@b}QjIZKc-Dum5n zi<~VNJRsSWU-uG5EJF#$y^`d*zVzS*11?&!_j+>m&oo($YYzckV$Hu-+7e9_8O%$bPmV8&0C(Fq*3EVC`oIEd&Wwke z%6fz`j@P%*IR}W@m=?b*>e@93`D}K2-WcP*ZC7fhGV%1J&Sre-y||C=(^mHn`>>2< z($!29wG`2dPrrbzTAl=jUi=VwZRNHuB)Qo=@N1$k3G4;l6YcMSQM*oZO>!+SPVd}3 zza!RuzkQLg=q@!X#!eAR-y3P44`#y2Z;uCPleZ;gQs|e7ze48*JGMNPL?N7c<>u@;v*xSV6fiFT2mFXzhi)uF94mxwhfV)i3JE?!k zcQq(;p{V1pj0`^vK+fJptzR9MMjs@yKW#*^wmIl^0XI-$174LAsDtLal8tDWb0^KB z!-i42{}3pds!VY0_>Pu!Dl7iw?R^Mylz!yX0G@*0WCmVJBbhiCfQ_y5$4vHIz-sS) zrrgmz7HdiT+vcEr5GzoKQ_!YFTf}p3O@+6+uO+LGvD=LSmXRX{-q+?I3>?CFq+1N8 zu6uXh_gA8TRi=#q7ZXOm4}lZcHc_JE5++@{#84*`Jqz0s659?w+LzESIMfLve~ryb z+66l-)4Hx`CY-7uq9ptjt+2){H%f%X5!*-+1C#$bHrk~~kXUPh^`CWmxoRHF3SgYZ z+UfFKY*@h{#gLEY&|fI18+UIj;IbaQ!53EmDhBX??G1lHi?0%#b0+XdjUwv@IM=#h z=#VbM9w4^7FMoo^3U1)G`HlrPRyly5wU9VVQG4fmLn+Sp-z(Ep`+q)nehgtr`4!;t zM3DS7<))1eJ*?t(%3PKe(ng1VPo0i{QisaD4te%T=xMK;DqgS9K82ltWSp7cnh55% zV5aw*z(Pih;Vzxb)iCg$D=dt7tBuqAZXYUU9<@J_=v{*{TaC8Z&BZh&`thD~1Yykj z58SpHe+nI1^I!V3Be|K==Lvu1b6Rq$M%Q@}nv)H|DTn_HZ35EiG9qArJ^NyOe0X!= z?jFm;19ado=BF!X_3gh{ELw4zw8RO*?h3M}eRdU!r$)#4C+Tp%^szF-f)*^dmW`{z z!4ke<*mU1|B$LieQ`W;k36xVBKga%|`WMpG1cyZ~F%Us`3P)011XISFxXkd|LF7xf zYGu%ME{cF(ka9#8)h3Bgv~{c-ga6zFrvm!>!ds97DqyBJuH zEnm<%zj_!MzV8meCf?ry!QXHx98^Vw_tP#U>6P-P3H>MogB5Dwdp8pPX}4461sx7n z=lCSdus5^e!ThbKpgu(8){$YqwQ=)j9x$OTq&4jXV=F^M{ti*G`nQfQWC$41L=_0|;o8QzI*wOg}zKq4ezHGj2z=kT!OXD%V>f^2% z14Pu1tQOYMJZ$puwqLZP-I``_0Ry@lr`vmx{VB^DXx9r!Y<=%q?W$dy`(k)2400+u zv7iq;#L!}nrF zrVFCX8tH)2PZAxxQ#j9JKp#J3W3w@I|D)hT#Y*S`IVH*deYnLX?S1pC_k69K- zxyYM?Guzjr%_x!WjPCVSWjZ-dqrIYrNb7gBaR1ZWDGYJ>gyG^;KEQTN6x%!6(w0Ve zl1ZCCIs3Ugs4_k|Lo0J)9AMNg*0noTsJL44bY;gJegZ^)76b<-+4d;BGf}#Ukr440 zHi?&Z@Ml1Fvy<+tBf&r61^Bnf((ucNfP?nl?Wjc}>(!Xs)9yuPmdU>3$>se`+yS)l zx8^G5uIg%L(Zw(Oseq|S?jfr+bqp|?5i_kuUk;3aCQS;Wv^x<(hJTtLptO0Dy=x}F z#nzOx<b~-tP%p0ItEr1~NHqNeqoE6;P!L+c>%<5W*k9X;*8vGYWd{MZA z!H)J{{@5Q_aNL70&&1<2n60w92AiT3se*mawu!%ZR^TSK&p28r-rF(HMFTR#%9_*0 z(7CG(y5%|F_BNHb^=KIv3|aAi%U-n8FscH}_c4w{?Wgpo=_pcaf0Z`Qvi~S;zJ6s> zy2oajY+3;B>&f3GJIz3G`Qt2WH-%CkqZPk+VaCUYgrH@0pNQ?jt5_?uX8w8&9uP($ zavI(~SJrpk1H4C=;bjcL8vUOqD3rWJe!vR5b?rr@gFVrj09#;bDbQJbK zAj9f*@tkllKoV10J|Tm|=z9i%DB2zbyvJ;m*!I{){71nCkNvVQ5s)gz!oypj#(!R6 zsv6l+r2ErSgaNHVUo}!LCHL~x6jAUvA}?{Za%Z^~%Jl!joF3d<_>~z!{_4QW91m1K zwqziyzT?A}AjccRx~E$T&NRtZb|oU2em=dwv%>#NnZtwzS46RQHq9NCv6VF3x$?B> zlo&XshBX6T1)!qFQ@TuFaH1%Q1U%Xxxj*%cUdc?PK8luH>1I0rMO9el9w#blg8ls} za>Ps%>wpEqR;IriI+wiMG)(~*U=|C*sO8{JXk6yCf#J%2U@7?vSyoU@IwZ;fA(HCj z)?j^#>dbo{vg1uY`tj~9Linq}?alIC-qVo@9QX%-h7%%rT5-n{@BUqyK5%Cn3dNcWQGU+wC2!ZM@{OQw~6EFMZ(? z6fVeUlaz-J{L5{mnb37ekcBo7R2I0Alj)7Q+-2tObgj25P(C6$6*fN3k)XMV*S}h< ziu$hqQqq@9p`}ii_$)rZ)*!6F8pZQ2G*Dgyhlb5i!h1#ET*U`qKB@p^1dx$`U{SMw z>ls1dw~XmI2k>ZkDNW#7G$~?u96S>TtVhnspC|ouszS~eE(0zFnLCouj}5GU7q&4lFfft9gd(v(X#IEw?{>GF~{6NgS%A(_yRHpPQxv>4dDs_JGTAZ{^dQfdeiDW>0_hr>~C85{aVp+lYf-r0F}X zh(3Oa#kOK<9O`8NHFzs;?}6(7Jcr-xswBYbftEhu(`s0IROZ6+H5{dIW&|W1ie0|z zp6a3enq39$twM^>QTqjXke-W`8HE%8ih%nr26q19P}wgd%PahEu?5q?qp{ECUBV^~ z%Kn>-A>mG+V^;)1G-t{SkXRkjcOjPf|9LidIwjuvr2>sqX#;Z%vn8{OY=-JDj)3fz z=2qZAM4VL9G_w1`bO|G>j!^!K)y5Zmyp1{sgyQu*^~#y6i+?_!=ct@~72w_6z5$Dp zgA@6}?;Jx?{GXU^eRPgxXO#a%?UDOg*5S25W*u7n4n1W&Yz!q+Uhw0Zbh|`lR;%?1`*cO{U}HG zN91G|bkWCUqZ(^)UrP{*sYEH12_-u&zMU4h{wDdIvY*x^D>cG8(Fg-21pi#tla{1| z?q%h2e}qegljZ9xl+Zj4wK*X*xXnN447z_w`Dnb?yp%aS9u%K~p7Fm#=vMZ~WEf;J z(R(|neWiOm8L@j!nj zxMm9&O$(=eqJY4gwFIQw){@h@3gW&qQX#9QY#7cTc<>jkb?FiYQ*Q?~v+BO<&4CAM z#3bU*HUfHxt57?DRD*>;P&jw1k=L(6Fq})A;^T-7@P6-*3F>hdw*TFpgFOMQxcsd- zIHUU)Gl-C`Nkd18O^dx_T7dKYl&2A93K_TNa4gX%x8ofILM z3ZoVNagGk4*PF!8(u-w}mZO;aSP+c9mW0g(VXImH=(M0FjD$pOp)fY(n@pXkUORQB zP$o3&$u~*)p_k)pgl=Nu@#Gp@-lba{z3*VN5Wf~J?IcdH#Ack{`6%lq1+8mNxn^Tb zX`1Y{g{#@9(6ig`&s>BF(4P5&#HRH{Wc*cd3OP%GB7(n0FMjirZEtX2_=-k93pO$D z!LU!{q%`9Z;z{}ni&_?I_s7a6x5q(Eez@8p&-h5ANv)ML z(ueXAivsVKBYC{-OYnV6u#I>DLQf-OjW4ylQM+43kZn8V>uAN`Jkh3VsR?5pvyB`( zss=us>JSWE%>dZJ(78aDzf1bR;G69za-*(J#&2fqDxh^OAYBgk=Sg;C-_vq%2SdWH z!IN2ftIkG((#|Jbt7gMWha<3Hn=*}+RX;wc*{k%mbmjq6!$P>4D6oBeW0s+gN=(}? z9ZJSOj?NvsyR{K*F+Q7YAoQWsfE}D=$xo8|aXlLc+ARGpODRF`Q45yFeGqTw{?0gD zLomA$GDyBYy1NhS1y$Uic{g#+4dW*GvnI}^91Xs;DGSlZVb8D>-^!9$kS}J}ODfM3P_eHr?Q2EUwbhx@k}Zz%XBVz$^4I30KvnV17j*K*5Fi z&ctk$HQT3P+lw)9aN($SrtuasI~!jDOp5y8il@Ja=Kg}N2@G5}zbnHWhy!!WWzqZ9 zk@)?WxIk_n8*5PUzwtYDAd;6a{GHL`E+Kv)=X?KRw_xK6lb84+IBpzJw3vK`+We27 zhFnC7UaWie3{lWqe|T;Z^Kmp>U*Mo9F3@IMd@G!lMo1Z|eD0i3h;W3G_E0f*Gb;N% z`@>#lIGGOSyh9c|mwNS;s@Iy%S2yk+E#=|kg{fw3AUxQ@#}T7~c`1k%BIYo97y~0e zYZ^)pn1(JiC35qhvNdmCMgu{NcLwFr6|%4qm1;yby|9-?Vf9e|N@S>^C3f4vIl`Faf`t+FMkFQ+FCga3?E zpqh2m)*p%kJuf@8_i~SF$eU%L+dEi|m>ua=vSQ(bPu_pz%njX z*gS8eZa)O%9xj$!BHN?me?&u-33Q{t#T;lAY5fpZC0hQ`{#pdBsI!!04Hne>)kE-= zj#CJoQb#en8Xf09tjg*?tqQ!lK9pi`zHF`(wdmt!lL(7i|7z0_VWRtttX8%4J^l8J ze^Cyg6wAHqJ^thId!3$2WxupP=ME0zUc{I`S{?$6Y#WR;Z4CKLiuLNV!h>aAfq+N1 z?RUX}#XEY0pjcg%=sJ9BFu@v!_zK7!UP$#82H#y2o_|_~X|j@?f8MH4m3KfPqrVl8 z5{)FjKeTuBtHEzvN)CY>q~Or0nt99Yg;p%>SGRDGMcJ+lEe2GYkY_zP`{W*L|MS)k zqK`A0BeCfxb)sW0x1iOA19Dt5Y31Pez^O)-nk_g4sBo%XZhfP5QiNh={Ok%Yb!pM7 znJO_SLWA>Jb-m)5ch2DII2DJ?)*x!w@`zjr5{+M!f1VedaP(jWR2^J9tHEPhiQLb@ z@ZvYDE}suFas8tOIKH_chhL9z>bWD`^gb`uu-7N{cyl5(vaoF2L#z7P4HAx1GMs33 zxb}Y1U`}E;(E~{G>ihSzNuHn9jqiVx`JhAziS^_3<3)YUuN;d3zLTVIwtZ`@?C=cl zhJs|74&`KkfuX8SI*RQj{GM2A^ludlsB*K!kmn!CuG)MkYO|VTj0!~|TDW57L*u!7 zBXJv^Gd+Srb;cHVE)rD`=@|J&r*4Ms?n%e`oNBH1)bIV!ch;o+Z<(KS!$vhb4UuPi%%lW7{Rj>n8HcMAr}7k_`5&2W>w% z{3vX5TQofSB8YF4VIagI1~nr7`RT;hY>(DzoU+TGocZn1w6@@gEKsKZTx)0bEmGh1 zKQa(ZasVTFdI_&$+rEn^hSk14=3+0|bDX_|*?X@|^1~aqubkNLbB{VVbGiWxf%2+e zbI(U|?aMbQ5;Rgffj76ABgOqdwV?w9cp;J5pB7k_$zGhTOB zt|#ht*v#~|EBIed$SXX~aO}tAIm>T<@TDF#g~(t&$de++*{f_Kh0aTYfCmiPmO=WGlK;W3Y+3TNy8L9dm0E5cW8cb(@eg{yr$hi z*C5lP>}f(iH`;kcA88&Jqg9Xf32F7)O4BEJS`9eh{7v1Bmv}6%|D?k#4ryc%`%8$f zK%w(zm-YZrQ5BXnnS8r>X=|Qc@0p-O?|?|bz9ljI1a5r7W0mluj_V80>zk`7Cv7Qb ztKV0i+qIfTBpFT-(X+q~5rI_^&z z!vIAhUs40HO*AgkVId*^O^3N)KLDR2i*2?pRl)!IX*i5e2X!IY$b!G|C#ovAV*VQR zQ|W_`3f$I^u6)U;{5TpNu-3CN(4xBzqxLCil1W`FN@#AvhBUpYXXb z?RK5>_@F!uz4=8vs@D`Ac96hNC~afeSI`~T-IuGT$2r?fpRhJBd;DWH!X>hr7~s`TpH&2@-#7Z# zOht!pOn6bB#~yoi*K(Fgrpb#FDX$ECQ0n%qIRVW0SKSZ|nvw$JR~j+9M(@xx)AC)xe%ew|r`NPaf;%Y>bQkE_!-S<7W?739 z+pAo@J8+f5f44&&AQx#>_IPc=R|Qg>eX52(nl}FAP=mPGlc3Dzq+$iV7b)Tq`$O$- zO8MeMV?o)2T2;qE0@1G)fnhcXv%$D&iNW?196C(zs%yOE*+P#8jsZQ*?h($Bi2PG% zMb^{A4@&`7ECe_$DM$(nSD`1p{jXOhhz5ePf#K}U0{MGg>9H?e#;+qAAE_T+g!NWl z0tl*_NJ-(JdD#mUWr&LKIQCh2T)?ub?`P9?=gh*xJ(Ivs(gsN?Q>Q<{Anu+uteZ^Y6<3~F**;N<$~D0k z)PCGcfs9_6f72+#YypI);NJc0$zaV)B)ci`o82tMfTG+6XQ;7!zHBw6yN}>C&DyZr z8Mv%%7*051B${*{7n4d*CUmc1wID=I#Ou$_@}_U2IGnl09H#cbCNr(@a%_{55u@dQ zR52W;bp<=`v578q5gGr1?j$5_vgoF_vaIa9UHiPoQs^snF9&E{|;Gyg%Ms4*_jsnJhLfda#OF3mw>O(2wwQ*Dfoe{4-O_$*I+IwjKtK z&2bP>WTJ%sg>im7UbcV!4}=;O5dG&(z&oE8K@yXMIl}2)7C36#u64R~IALi}>xCE~ ztdC(&Af*qPshmHtv3?7&GO;^Lt3hI-Cnr9d&-`;{MLOg?(YDU+9^-#T0b}3NCk83n zYzetbn2jCXMUM%zlgGn&bx1qO`_*G=Q-s7o*kV<#b76y*<@k_*cdE~&JGyDw)3A1c zmrzfHWJdwmI3YK-|L8+Vw@8EsUrUR~0C~XQ?)i&V&G}dN1o34xF0?X^eZui$Y_>o~ z$(x4NGy9CHGpnW7-gyh@C&*Q$%#qP_LR+bP>t;<#`$$*>so7@HRM1 z`wQ`@4|i6ZvT7he3I8#wMCG`mU5*6zB~B@^_WFNG1Ei{=FhM;XW$Lmq_;>J`edN>a zUb87(xMp|kUM4Fe3M=a_H|2fEj?@pCm3c0MOKJYnr{BNO-u?sAegaqE-^rOiuJ#up z8;{;@!t6?ZQ(D3VFa>I#&sUlL!0&ViHi4n@693t!Q*pNwzz>XF~SGo5f zPytClEBui|plJ2c(-rRNUaTU>L$!#(Zuz4pTj$j6%(B>0)o8`-L_~O2h?}y{$bny8Qt>NRWDzKrg){ z@mLrf`V1~h_|Hicu%??8hV33r4E4CqM`LYVV;Ctr`t;+DSRO&G*j1OjdfdB$(HOooi%zhv?G+PF+d zq7XKf8f|SUWY;at<*g0Ir(ImFh$g+T^NKti! z`X2!pEU!`j?APJ`JcU_o^%c=e4VanHQOtZeoAREZSEeX-SiMp5Lz2yR)8%c9kJhgF zp)CrOslt}m$$Y#3f-F*nGo)3QDX474v zq|8?}SD}%oD|_cGm~@DcNhT`u%o87#`p+i+DJy1nAo$4WF^TPc-+izo?e z-5pV#OWp_?ResRjCZCyk4!{^5!hb$_fufw^M*JGH_?^c@BH`yo@SPQaD^E-x;EG!Z zVC_q>N~}Qfuw_igy)N}4wv<ba2v8Is(lVvSaXeFg})HW^X>OackSw zP}v^lD|bD`E176+lfN16|E~Atot^oC5sRlaEC9gz>3y=>#ERAqwC`PWi$&Fyj4ySa z02g_C1K@JHJ2DVR>m#$h*qe2gTKJ3FwTi7V^W?skV8Wcr%IK@2J6{DS^fm+q_7c~@?1aLmSj&6%p<)hFHIukW2{01=n#e6%=# z91*eHwK5vBY65H`J%~G?%V#x__^m91BH)VFbp{CZaWkuvNXAuYc&=deUU^0WuO?%e z2ri5p-WALJT-bG8-ncE?23oe zCP|+g2V&n1)|;{;^gSiJl7BkjLZcj$uD)9G@g?AD(iRNK{$@{%{Wc7xA7Ess0>G!w zMKc{sHCKSlw=_OePxtFzN6CoU@&m2F_V*CZ{>?Vpjk8|-BQJ7^T2Qs4S3Oo@EY0@n zvoe>{f_&AaB);g6PuC{2%Prm(*?#oi9)uz4Tv9<^>pUr?&~#+wUvUA0#GYcJR$j!)(sFWdt?B%XTYsd;aAVxO`bUT_t)M+!8Uo9>PA!^_$Lr-8 z69q)h`D*M_PxyxKd=>#P(XbaV>Tc5G5EXPI--`p#I^5yY(J90R;IE1o2_UR`S?`2l zZ_+x=-n;Bi-D9-|LQ|LCswz4_g6N+(E%rEnYy)tb&d05a`d(lW>M48d4rv<8eXsAt zsj`_MVKs)nf&}_1l0rnbyLj~h?mjNNDKpu0NJf;BSloNxGxrgt#!>TaisKGgvmEuI zSimPtTCcBRp`wRBqSkw@6TJDvoYzMCDxBaDOl2caviI`t0gMai=uAX1LTY zqfa;_cv2kd4h;&EHw+uSYH)l{js|m7jp?kSNw=&p;MJj3r&W`VA-YUAp=V+Q@!9xN z;8Nl=52qM}tl&++#ZwMVp3tG=-Kcw4-%MU^QY^S7HzKpuRrAgCA(r}@C)&%#QcgY_ zo%u$??hPBSAhj&-oTJ%q<*sv*>#OSCfvN{{0$;`sWgp!evvoTrv79dD(0EAe#c`7f=!q5Kw(o zufj$6X3mA;=jL!X!5zX=9>gN^=)vZkK47fOqry|>+6kMjc9>i8$KeQ)T0HOx_n&f| z@h)`1kZ72_0z@6&8odgoI(>ZZ?K$4c15>ZS@%+*iRVAiw!WK~^;A8hFm}+zlAKvdm zhAjbMh8Cb~0Re15ey;ogn|-jVhVlx~is$-;Ttj4Qx|UAe4A|z#*#7h)_zM}G47i^o zn3s%V3muA4f8dMpun~+W#j#%oK%p`*DMStfN`*IP>Qmnm@j;96iHt6|s;y%}oRM5c z7&sm(@*&2Iwx)Lwrvkdpzw9TVee?n9k_P42foPWHC+Z@BEP2fiC=6zCN@|?R8v@kb zfCjj(@+1j$!8bka77+}k@-_gJ6-av>paR=B9!p4dK;T4u2_s?k$088frFa_)i?3#f zRMOT5TmB@Re0SiH)o6We^K+i^gMq$1Byb*We~aj2ZstuDvoiBumlz@sNEeVMP-mQb zC3fGyPULV`P3~H^W0ygL$LE_bsXoh*LW~9H9xzQ}a9BlC#5Xtw!A!-zpEBMnriM>0 zk)mo@cR$(sqEWXlnv=Hqq3dPG0JWEf)?8mk6&km?BWaT_@FnUb8v|Ry50~gQCYQ;* zE{U_XS19n(0fp~{jzDpcqUFnhA9^aD3!-*%OVJi{1y$4i!JQ|#54hoE%pJF|q$5R_Tk3N0;`3b)Ck`;pq6?#%8tM{?7$e>|7Ofb${D_HJYL%Vok?F!2g z7%ufBc%1D^37TXD`ypf_2!-pBu`lS!VcddSk(T3C>9c*K-?OUC`VKGbU5j7$*-fZVo8j=yxrfXEI*O_U z1w5TvilpTh_$Q?Y#`${Aqe34NdS_{@;5k0?c6J^T8Bo+IZEw=aku!6=R_5xSD!`li zg7!0%UY+IC>p0vAuEV-6fbzr>Ep&KB(c_f*X&@2jz5MSCK~Ha*E>GioSBN{;FA-zg z=~D_73*mUCdLOIK9j)eU4v84;3()e$31VxUkOKJ!$Jf|lC^oFf1Wteg{ECS$-_p!l zRQLx8qvvcnXH5-d9=4o5q4MLFBYwWqNiwnE#XT1xOK&K1UU)ud`ZB+fd1d`PtLo{j zanXqDxka0`RC$-6jW}%To<|Zskav|(l59J&=K8+d;bBACZ)CBVx5s_fF=+4`R}5B* zIU0}|eluoN8Q?ZW17n94(Kbrr3zT-E*BHplZx%%TD~@zixmS4(53Gsn@hiP~Px7{Z z8DPuycp~754nUVHD7U^CTKu#-|L*gGNX4cEAZw0k2BI0S56xF6D-R@`zcUEB!@%N+ zpBcVbluo@pZf=t|x1>%qT^g{LUw6Zd-iwWPR8I_uu5bgPfrOtwD;+-gIb?2GC~%Y* zK~wa36et^f*SG!$8sh7X2f4H_vuU56#U06J;{#F3+)e!8H|%m)0=kq!UlKVNidRm< z>4qAe*7h^^hgFYhj$e--_X^%9ZFl?v3_sn$9v7>U%)6qM){(R3N9yOec8b*1#1Q!oX9K&9Mz25i9fpx;AJY zoF_ZJ1)(CHA@&zkvQj#XX;+{a&Y-9b0p!6IZLy)@hvlGIm;$;FzSWWdt9QL9)M@X& zuAFkW)ca6}D;N_$?Z!3rNQ!i@YpC$t!V-LfU^yvS`SVD4iZYl?o({0=BP@OF<|NaF z5pqMA_*o5FDP>QG5JUGg%1b>wr$5^4m4H@u`#jKnj%R7k&} z=?eHsM=O>@{wNwOU`pu^dvM8R0IqYL3iZd>@U9!57@b8%+Oh81HXfP@G@PUc(oncI zlAXVIbH}Gy|C%b9w=abAO=vMuGK7?qL=No}e^kadJ2~Dt%$S;mc&nxQ?Vb;Wih_Q7 zGrqpHKO*H?yyWIl0X8fc!>xPF!&k_po8mR4A@T&y)%#t#id zuo3|;#u%ZKSU+pHA~(H1h*f3f=IvMrGsi z*Gx?>*OrNOJ{I zK9e@t0-?U=Q1L2uf(Ffy{5Zy*EA<=``=Y`%JWlx$hNVmv0AuLObw9QhOql77_^<5XA>3eqbUnxs6#m>t7r-8lvHAFc-H%r@ zynUPl*x~*T&w^9if!D4%wC7zL2^pcdT1a$YCotQ*L7q~#H*Phx^mZ(20bO+Ctn2~6 zJ8QC+5_f7qh0aS*^9*QJkticl&5Ze80Kg-G(L>TzCYnY88}%`ML_8$#!qu8?NwMaU;`ib9nK>&MZ@oo$Rs@1_$wINb%-eTU#`CyhcKX zcZ0_+HZGhDV~lC8}2m5!WOp89MIZZ!0`mQNNHR?6ZVmVzKuvfSb{&&}{@653cF-pMp zAtvBCfz_KLad;62AKk<;x-JEQ_BVGmiGth33&vS)gKr72DT$vx(@VqMrjX7Syn%@t zroGbExcT`0G<~aPDMJv|;Um3P^Vv|paC&H>-`6$XZH{~LUZPXiAK0OFB|xA1p8agb zpUQXv=2Hi(G=W^EKC7S$i$nY50$8047+HEf!Ft-CE~8SVT9|tE6r(>7NBZF=>(SAy zlSS_;enyzJv(P%z;Ld{Y{N1$!_`$|quDtkJtJ zVa=a&gQm1)q(N4&I$zt!ZCKmbnlr&>@CtIp0 zE4{3s;1~m{R-hzCKjyY{ZIjhBWh>^bI?p$}Re=8nOD!GTqiG)CG#r zLhC!|TPMewJ`|ARDXTOBE~y_>0>K$q>cRX&2gp9Sr$+W^t>FX`+i=#*3nJ3~+ZWL< zR&hIV1`{^V_GB0XfNIN;f)^wIu+2*c0@{Iy1C~)A%4jY_d0QAvDk!Hd2N#OE^!zYO z`U;E3W5*vnE@E!iUpBg+Ip5tJ+4+phRI?`>S{+9rASTmI+wi8}XEC`j zCG)7F+#E5fb=u==prQsu_x1{{_=5mO9IWfNK9pI2AxlMwmj?srlqr1sGK3m#qQ=Yt zQeC&ei7B*HEr@mRqi`5|7y`2DFg~Q_^hILagK`6+S~9{q@sggPcq#rPM{`!q@`||r zr?KnCLU$*ZVgw#9n5XZ@4$b-#H$U$FO0G6$&gETV{lb&AX@6{uB6o#1mTd6AyiwS& z+TUfQ+j&FQ*&%M>sA5oAKtSVx?>V;PS()2SXwLY8D}Ea7sS2{HIbr#oZt#EON}%}D z)8vTwj1gtILpD(rxkL4Jm+NJ8B%Cnzj44*P+fQEPdxY0_==&d>74%)v+Hoe$zdMFk zm+1Bzk=!|hFUX{`t$E^W4LzaH*{+G`e~*X%rp!A8M~7J7v!-eLvqUREyfU6JPAepg zp^6BnQs~}YwOHKB3*K9k(J_p{iBVNO6($`t^6bXog6Tim{JHCTt!#!Zkwk!~@Sb0( zI(%=#+2o!)&m9Q#<#9a<96QTfXvF&XfqtR4DvR7T@#k?x_D^3K#_a``v=DvdKu@X`}&-( zBp&l?&W{`oOgD+oeTtuMcpfkAPG2}(D6XrhuudAgPMR7^}(Mr+m zB@?~Ts@YbYj+J&9nGw?|`n`tK=7BSIUUuw!`R_?RlQ8rYJtVLI5WhzMwD!+@SBug= zv)a$<23)YP&p|4-R&tVj8B4z7-g2-`2j}Q!77PKj{v7&Q58;xU3N(CloajT0a6j*^ z##levrXT#dLjNX_>Q(lt>`3cXYnLeN2ZlxYuMBfz6*Ii;MrD&vN>yu(WM?+`qv`dm zo-T%Ldo>kd7%1K;K7g>XezYe9DF6*-y3>YfCq^X9FVXTRt8Tf?3c!dJkG%%jMEzv{ zGP@J7N~eXdr|b7t09sNC<}1Rpdf(3*+<#Ec=t_I_#9#$GiyX$2!K6B*3im`kA6xWF zHwLyfIyI#$nR$J7b+`LyODev>!997HMFeiU_2vtLtZn75boMI9NG8)Jso)SXCte&! zFJ};pft(UFeQzj;I|jsP`Q((KkHzGa1|R#ptD|m`y=IMBtlujQbUi43e7dm?*=D=9 z=F`D9m^veIWdH4{gWR<`e6hg2dJ@@`zF{G#D98Wd?JdKq+}gI$dlI66G}0kRgQOxL zAt5c@H7RLOLZl}u5=tp0APv$D(jXw9bV-AXbV*BpV@_~A>wUjx?_>Yke>m2X$$gJ; zjVsUV9M|+o%EhN#ymn-*PtwG9m!-?@`H$aaUJt^4o9_JFrxGkm=QasKi)X;TT9asa zxomF>e5L0Z1b5*7K~BPIj+xOolBx3>YJ%X}K6hboZMVQG{sH2+sOJO36;UR0jvp+b z)oKx&1sC_MwVqZ{xHsJ8$QOMn8ArAarmH1j71NGQD~(*87mseX4|&mdG50|yw7(=};9H0{r0M2tEM zKL)c8zx$W3_59gx_B=h-v)vEvAZo=gTL0M@*eYpEC;cp*uHHbu=lAz<0GAyHSXRj?>)bafZ7nRvzkl9-%u;-`h|LMbmw= zU++~zv~jll$I50SYq#9oQUEP0Xf$bmymHlh{A8Yvk(({;YbtSYI(*Og6zVcQ`#}MW zY>6b|)Hrs!1rI_;WKy+w_|QQyI@R08?{+Ylhase`7dd~_V8`M;T9bXrEymwvQT-h~ z!Q;x$qmN1Jys6nCvGg@qw`B`&vKT9_;n9-7c=q{fTNoN?o_0R*^t06o5B;-mo={`P zq(6POTxB&SYAm9C%D(4V`y8tk@8!IYsWM#y;g|u9y<)b{?<=Eaa#oq})weU+7_y_#3zjD&Zl4@szN<(&h388ASm0z^ z`EXxjq>WVmiQjPX6-}Z1KQI74v^t+9rk$uZ-Txn!=ZI9W|805HuzXV?mX#pslt0Du z@lsfQF$uDtt?ntwHGjgo{c%MkLQJo9Y1yFgL3^TX^puxcEa6CB4BJ#G<%6RKuQ|DX zSq9;nikNuZD0rVcOVPxf!KG7$h6Lrx9$hP>$)*4ySrdEov>thEdb>-Q2)$t%%h}f; zgp9dLOGbwL>p|kh)t+ZgwF`(f_XE1c zdig0)uNE_wAQ{zONT*ZYv?OT4H})(tUVK8*q+!copSrjWpW@O)L*pUVtRi|-Pwmrh z#Nm@76HaHT)W9hAkdfzR{WB~m=2BBs+7EXnioIu|Qn}@#Y?x5(@weev8<|G>G+&3E zZz2kV1@6aYagE1AOap63=gWz5zL~aGTgSsjWJ(m3M!7zjXz*I{rX+*$5GNv!cIr{; zFEQEK6Ko@@fxsQN1bnD&Oc>cu*uh%vizR+Y;LuR#wd%IrkbJhEyd!H%S5e|MsJPSL z9BH$rnaq=v>!*55$dj{qMFjZTUna1n4YwuHRj611%8G8V-;A2wh@lpach{Y@)qu^d z-{CG?891=p&->QH$KaFZ*E{_6K55PGb++f?TYf5=F;T#hq9Txvh+Ru0cBb->tzdCi zAuYhcKW^s6WhQiZ@07eq^0o)O%nMKV2GM7%+b$TZ$Oy7V%D+K($KmQ@0nUk)+1mEL zLct_OntO`$txsAgn%b-kjA+-TC=c%jy=D)Q@J|)oTS|Aebb4|t-`biZmZqX!a_Q>v z;qp?#Hst`=6+n(~|}rC_htWht6XV(~V%KT`xvjam2w1xAzJ+ZMNn=TMaL$gXs*vE8m_ zkhSvEYj?vtWt(q+LpJ_|4uKBK$HK70XUGa&+<50z>Y0iy;s6v#weEvaY#N|zd(ZXs zV4+s4ac4kL;L&#p{YGEWtK#4h$mmFT!V#X1E4L_N6|o?Ss1FUo2ev23zlN z;I%WSP9ag@5LN8PM+>TY{)Rw1Ml`tS$fTtBMm@C<7U#NCL^4;6v#v@o zjF6&zDVClYponDXePD)ylBnnJSo30#tT#3gJLXUoN_twZ;?dx*et}+hKB%i$m(AFj zoflinCMHv%srl;H&B~Sua`y^N5r@**;Ab9FA?Un~ghA@TfXtgL$`MOIH*UZ8X!p*V zZLW|7y+gf&#Uw4y25nIo2<}sK$I-4WWSV2M5sRl&$xe58g|XX!}1P% zQeQvqQ-9dxq_J(ap;6^un`!B!S5t4kra~>drh)-pp%V2R?H(&nd8LZZRH2!e&0OKn zfehNqk=rDN%ap^GYxgPAgI7zIu}1fiWQYQTj{`_lno7_y{mmZau}^-0egjzEX6t|^vi@QII3?$_BLkNp76^zYhUpm*M9mFzQ*rtRRsg#?I8 zET7>@B?vlY0gSE|@wxLFMG$!*dB~rWxz5-@KtnKmYL4L3F@T;7$g_N2UK!4dt<`h} zl#cZRe6c?%cCWZMR*0FE9!)%6ObtAIlNSfs|8&UPU`i{Qz_8r0E-@tm5|Yw^F(|5<{rwTht@KJo@HY2DzBGL=}8M1$oM`faz^KQSv1ud zEB(!eH7$v;C<~-812G9IPC}Qu;89=rlIQoGrprPrC;392G@hv6;P835@73u}&YSda zpr)@9O=@AUR+Yo2QC%S4aXc##9m{uz_HNM(pUffJ@aQBL>*)4uAR8kx+6K}3gV4+l0JV(QHmR;2lZ1>-L3`1sW0C{rufoa{}^LTyx-{QZRv6P49Rtz8?q zcX6$8;r4;oyAbb!A5d6t;lS-*!5rqh-j#G1nC*0y2cC!lVe=b{c^n+qb&;9**y09I z`|PY~grB`KfogxokTov67|Qz@)%BJ?+;YW6+cG(yuOR_+;8=@D@ub2Rp=35RR>nj`?&(XGXukI%Z%w zt%hQwRT~E*r#r&K$4@2kyVNZ@O~C@OClAac+$t@pAZ^w;m+TQ7_^U$dEau6YLrQg5 zM*%w}ycouh57FSvSFohs3aZa3cRU_74gAcY&fIJfgSPcX>QX_8dHX{QxUn4n)dxz= zKQJYX+d9Z(C+mVm{#4lS6_IivHlNB<(>rk8`&D|SDS7+PGk}=qVh^pJI=A2YXgr>I z)F^&)&s6Uq4B$3=kDYf}-%j^*VgauL}M&88)91sd^m3FO#daY%ThCuM?*I64tr>KsYxJ@hR)3H!iUuIAfqO0n4SE-in$crvG4TDsm8a@~JZcyqNxsm#8ekNNN<9x}uT_bo! zHcOG9x?uVR<#DZ`USM$3<_a@R&OrVSU-x%iC9kG|&{wX6#jg9aC*MhnebVrZ{hNm( z9P#76_0YU!C=a#X`SUh?EH zYv;&*t4|(PZF6E4-+ir|mj@yArbL+*5`_?gKpw>*Y^$U4`csP;HN7LeM`i|A_NLPahM!rPjzU*FeOaIQfjUb`q@P zr<~ZxE6JL?mNVI+MQti{YlCvDq^nDd9;V)oqto+OgZuf({(w%2Lt`8o5`ftF^rrV2 zRP3GmzOe@Uv!DKiu|~+Ej{0wfkr-$6;`hDN^2fd3@&lBQ|&*%k}Z z&KDi2oIw@=3g<ukNzqB-x?!XPhBvPAby*>68bX&EOse`mjDXB&qBF7HVTT^nlu)M$k4pM>OOAnWrd zsQO&JVm8>ff?`v6!iwkx*pxaA*@0cGIJotTg*ZM4jZZ=NVJfj7DwPt&Z?`;EiBs>M z*-d!RK(G*&sUdmjW#oy84*?r-#3lRX1L@wgz^_wB0)3_z4|h3m$V(oGzkOqUQ^B4a z%GZ>YNS&A?Zt^~brSuitJ5i;7hX$BU+y|bj<{)9tnC{ZO$}ihG?sNGsm#BBB{3S3r-@kb(ZVZFS?@KRnziH-b@_cXbPS>@z&w3On;zPxHS4+=7qvN0 zKL;4YLg@CV#|N!TKgz0=#=Rc6B|j}NX`B|dn=G^)D(S(AxJMb{dryBw(>0! zcH{ItzViIp!6WmDLVN!({6~ca1(`ChuJv!tb=qvtceAB-PCSI-92h0q=)ftoaWI_Y zt-(6b0>V_fgY`Rplg08gQdZSFm^aj0_&e0J<}3;(#SxD+U-w!VUQ_SJ>E3F+zJ2IR zEBg7p#;ABEWdiqCfylse1!ThFH41}cqVb5u#T981();>>80kpi0y&#Wf0a(H!(vX5 ziZt#4n81IiAlxeWMy28$(gk-5Uj zF*p1@vC84cBhH0E%Ap7PQSCHIYLhgjgV$##rC7lyjfAak<1$ij9y zzeIASJ7&?VX5^HB+3LY)HEltLYv*&g^OzBSfX4HZckh+y7NEI>aQR^%2(P2Xd~k}V z&Momt>q)hd@!^P}zvi~Dw|W=q`q|@e_Y52N{fIjs_Z7|D1A6hLUu8Mt62=j37PGOa zq74nwm6CdX`>3dkmgiD21^>go$!eD=3sUCmShel+ZF9>jD@INS?!;f>`K|E4tkQyY zAL?K;0<)+5z^?)CjL|jJ*|6D5=ldtM_KcGT!F2Op-Omt?#k~oq4=s2i`4%zDu%^;? z!rNZqz&-g67k|91JQT=qwoIyKA$fxV8IgKdce+?WcQoz&6jqTp2Z5qYk+rUY%`YD+ zCG|&(p;+8~`pWD(Z(5{B{y8-Wu5b4~PL+}Os!!<+>foG}Za!&Z!r3f~_!m;xO?6_E zZX-tJsMc?wyGg7dPMUjif?#lv{GDe^LDfoud(#}qvRf0Gq~km}2877%55x)-n8z^k zoo8sD3!D0?Pr`;28ViH6hLmT@>4Wy9HTv9*_w}wrq`Gr@{cnQ;9yBH05ReWleD@P4Q-i<5X?+)M0IVQU=$q!QxlD zER1j6h8u1pJ)jr(%U*cC>Wm;SaP3=t)yoIMZZG1xk0~W75095a$FXw|2_eRVt0{XH zSKp27yD68Ouk9#H;f(dP)?|WCMY0L9o0K5N%?tiR`-x)D19=s=kO;{w`v2g#83XB~ z5I}N^%6f$O`)>Nq&4~}59jy_U&x|zQpDiMnT@xuM%W)bM*%(OHJ`TQ_@H8i={+MbL z)fb8IJ5ysM`CZfm677{+YCfun8;`%moqhYm&2|CjU4pj7IpU($m{X&@|{12$1}-;RVBpMyEty^D~jtzzn+ab2zGx+aI6~hS&KI@o`a8I5VIQ<#CGngEjy5e`MmJ~i!vFLdCDTuDBxbLk;3X;>4R08MpO`5Ta$b`51eILQyr;`uxA0s3=UuOd~NC#Oa~+&3)ms0 zG)i-ik|`oGhqQ0}C~g#VNX}l<;UULAxlbR$g!T>4>Ene8ZeP;NAFoZgt+Bs8HJKSq zt>^j6e`bJbwtc{f&RgK7?VQnrr_yH|Rf;&_N2evO%S#`sB3cP7p;v2^20FcQ3UuDT zO*zfxeBSSqnjF1aavk2u+39-Q+t+j*eJV2~tBbTTPR_;7={1+B1?w-qDKFRXG5&~! z0+G0WdK*%RIfvPPtf1+;$4Ly^02xN)4MsY7u~MxOBq%`+aZZ%bbofBU5*7jd0@$Ns zYHhp?>wmcb>FA8u)@eAwi)aj<5`SU3e8t+C?9^(-xbeoq_Uh9R+njdT^RgD z>J2RJW8hZBN3Q+efX2(Z>$^>8B&>CyefU~90rz-?;Rsdvp2K0dnnhQ>{3{Tr=9H2B)1v5iYX@u zGgfkQ4qhgoFm8P4WBBs3^rD>|KKW5|WEDll;G&@WOtJu4n_AJ}{rAg<4tu$zE40O+ zVUl{1Ss=klTCYtu-2IfL(pe&H7*rZ_$^|pPRcYv4@p^L`=`qi}!bX-6Y?Y+@;=6o3vL}tz9XeBNOnCad(@VC(F2)aJk{?#vb+Am!pkFa#z) zTAf#q(znlW+tT4&WJr`Y5Fzlj%x>x%7c+XloQs+Gn$bD0kVT!UJngEm5)~-0jPmBW z+y<9dLT$nl*)nT?Z^)d=XUz9km#>Ot#4N1(wqpO{KZ;=s~rlk2UIFGTez|=zrJGTOjA&vgP*zS zSy>-4-g;UrDkgkJ89f-O*Y4F*3BiRFFQbD7=#lh$nYRjC*ZzjFRql#PmLIHNdRUk5 zA7FqQi*wod<@OTk_YU%kJPQIwXKU*`k*H}21qT*chhDcaGfyWA#lQJ0tjR*wJM0^H zIJWfxvdN+8f{GvT_GD0H`3a{+sWs6d?r{TVPKeImegsm)$v6Lth&K~3V377YBh%m> z<5i!mkkq>*thZ4ewR0WF6Vv$Ld;`#fd<$6Z(X_~fitSzH41k>hs-9JmeiyWBK5_hQ z*Ia^dPBkL#U4@EqTiKh_kd+w5MY;*9vvo%L?7bu8=5ce;;bhntg%^El-S2eIl-MDJ zW!kl`3T!}jT*EzPWwU~4{+D%2cI{J7FcG9RSgPVAm-R208^tN&=oDjsb$Eje8wd3l zLtSZt>42%lAl5#QWNHaq29x)V5*9A~LB6odr7=aAmHq?bKYqfo97h)oaV5yQ?N^Nb zXX-h5K3TDG7`FF`*GyiH&H5dFO^TYiwZNpGqEEQ2 zST8>f*LF=RDGG8NFMqsN@n!k#9^1(6%vzIwSDOpFpxQK^>+!NgDir!(M??gzC`j*0 z4+R9>W=~@zzBM52lXlcfG&BBlO7P*d^g*0bAB$=0pYCS8^<<556JwaosQeW;ZHLPW z?#N`CAJq*2WH_=0`t3$CKi5&mg3bIr?L)p%N) z>~Xg%XZ8$+$CPZIjanF-uqI&vx0%iCKeEcmm1;gJGip)t#u54q)VREzq6d|i% z--RtnbfPz*MSuL>mdV1Cb4eaqMt#BqN)OtcQORg*u+^aJgIbxVqO$dqmI2B=&8k|~ zZ)RUKX3~7-K<|)lBlpJr^+)enhdZT&b83N`ro$T;kD&hCn0T94J9$&xQP<&ppW*K1 zz&5KwM$$hywuh0n8CTSgrjcvdFGi6?y6yjqK|Q~58I(tTzO1TA*cL>vbOks3Te)uq z>q{OQgWE(bUj=U6ydo=^hJUG8RjzU6&NBS8QR@XeCCnv$C-YKn9bs_>G!MI{@ojC` z8l!8cc!!oB8H6qjaqKFR9up+O2vU6^){8_KF#jfHB}^y6!M$efGv`84t(TJS2PVz5 zJeiVbTMbzxqOu{hc9(A*3sqvhUL;jN>c1btYoia_JKeQLnTnmvIy}>7rY`!9K3RqKq{Oo^WGoXBD zO7U9zACCOfY#QueX@4E(%~^wEV<@gFgJ%(?g>=fSUl@WUqAWgMQ%;BAGJ{%=NU+P* zkyJdC-wEeJ`W;p(D-iKIvl#nSS>cgrf6x&!?_oMA5-+j;6LI*c2R>cHLSW`Or4}Gr zR%@tM?lT(T%D^QBpcM2jsF-nna__>Ip$!Ou$y$h+h14Eql=c8lmNflWAB>a}ph6P< zt0=Aul1~DPJ*qL-6efftr>oed03P4{2GuEc7a4u7vCfFxD;2z7<|va)dF{)uaeP{s(k z*P2+H8QiwD;%l; zD&p}OMY6I9vk1Aco;Z5bSDPK;{?-X?yTMd_G~f-htvntD`sM{X0R1Bzz_5W_g2b#WxD|f z3qM*7>)e5mB%p0d5N#R|Oi>&wW9jJWh zw1E>bzhd@g8Uta;*J{~`)?~3;-W`v`X~iyhRL?I0!De3SU+9zSb&N z9{yvn_5yh<39w$YsC2toPTwfH>?^01BR3d5eY zH%~5VLnY6y1q*yA=B;;?kRmd5F0;Sp_#8L{EX?0n2b4QIL1Y^A7L^9Uu`X5yZetn#%{c%0C|Q;UJIGN(3&EZ*ws6b=M}l*>(7d0(Lh22O z6Q3bHL>np6^v-i{iTvQ%zl3reK7Tg~19?diP5U~CJ-1}eVWxjR?cYWEA7-GXST1@U zI&>|i>RKFb*}{5O>U|0{yu(pUBVv!?+y_;|*qLhh{#YI9Br zn;90w%#dDjA6SkZ6?Xf7KKn*Z!V_Nv$n@cGAo@Sr6D)H1`CqAn&&sJv93EgIlksIK z@Z*Bn*-G=`-al~)!Y)TE)+(#)rVukwAV(quww%GEFhp>Nbpavgz4A)C@8st`3Mm;D zaH9z-zI*kS-!Rm4y!1l-UoS(Tea?YU3+g}-{vH8lK1zX+@zAmeaSlLq<>Hh6liU-# z6I@C~g-evCM5G{gXrG`WF+Ror(}y6a^Nc(WOve~a%?CYc<|jc0rv~cYx6qnGihB7r z$)T8FeO8={C=6kbf@fmWN;eU}%1jO0y+QL2srpY@cuwERjofEft6;9@Fb>bC4#4Y! zCF6AA$6@i{!)c4HXd}E?(SX6-XxI2#xBid4UIVv$k**CzY{p9T|3}$@*a@^DAai0` z_3C%vqHPx4`pbX+wisMLMHV@P*vJ$4j{A>vfvqEoQGLPR5nsEhAx^=QM}q(3w^QI+ z21tNHRgrZo%<3O)K#KVVDFl}LB2d$D9)edd1=jvcun^`dYDs0bFVK*l_zwC%@&QLg zpN~8?=DQir{8&(@viRiHfBzQ#5w#>OMiQi!HBtOab0lDaXmUg2-0;t9P@P# z*W;cnDtAd;`JnEWk#lp4|0+{KU`WG*+$YG1AY%`E-{n0dTpAA&drBh=zx&$AUD_r#I z>7_-~gvF~BE${zP4T(O~5#0+fc@27sd~fm=vG)_J(_-Yh6_%^CRc`4BsN^`a+urKO z923NYV(On%5&vT)pnL~g;9TU5i3GLheP>dmAGcwz4T#lSI(WyheQs^YF)S0A5JB^b zLf{UsYKk&uF$N(z23T|oN^H+44fMt^5td8_{gY9*anf+$J*sJ{315WEXYFyday{4j zRtl)_A&z($Og0tq8Jqq};OF<~BPkM*7rOl7LKrr0A4xO7^9D8R(uGLGN(XY_f0nT! z;tghUaJjijRGh$Ok(U4{-(_$Y7c4j~GCETW(v4{*{o=p?UGpzLkZ$e7e{1L<+teU@ z65#V*ArK!S#_73jkUHPjr?T+=w|uI_@p6|IBlQ5zv){9MBU~FB*?l<2cPU21WZWGS ze12BhPpls1?~;<%?uLt3TecS3uaRu~92tK6iA|$Eqx8YNSC1o>UH0t6WF)+*K5oLm zu>mAE)w_4baWJ<&Ak{ghv41|D8H&S?45puyk}U&A?=dF-aQ{ilFK7~_=I1`DWAIb{3i81k*SUli3_r z4|ozmxQv(2Pfhn+KUC1p^`p&-D9lxnKu}dq`MNCs3#J?2;jtRBO$_}hm8LhYn~{*w zyz){RbYVUu#>}28g!hjev_Hbyy%S)~A&#is@JM^`xRPW_KK>=;<=2uwnysjm0c4DQYqpSVZ3wjuQIDo?x}+Y@Peb3m!S{A91+ph(BWe4@NN zO67%7(VE3chd%S`D<8$>w7k2o(=2V@=x>e7nmjYa0HboILYEFt1Bhb&& zI?(cA`61^LAn8^!wv;QmykDT0b%}@D`swwSQMuQ+)%g3D?&NX^2XMS+;V9=%Vw9i% zWE5%KqIfKsaX;^pRlR>>UR5kKK)M8J;JdW%=pmbvjI8-~YfL62as*>@wS=YrO~ z>{~{0`n8R>+8R7hOs!{~gVnBy_t`8zTDu=3)pqbDvQ&4XZY}ucJy+pAU1FJxkoh7C zQMo|z`Q+$tBV{JWqWpT5ao9~&^_S3$z89$NzbJQk8@%(*ch`2dnJb6zx^q^oDph@Z z1!;f_dM$46{rx)#jYHgTUsW(T37-sJb*OU+N7H>~tzyzd%&Ka8;fQT60K{IVpo)x~ zZq6Xy_NZEX&g+D-hnzu=Bk@#PS$Kub819gEr}7)|D3mU+J?4%oQTwr|(X7Cwo}t6z z{nY#gUn&ma&bRX_>Y z)2b{jxdJActm20VHqdJXYl!y0(;7X|Sz7GJg_m>$vzU<jrD7`wC?H z-v>vM`;KAaWcCIj9<0m-I=*{h8CyVK=BEBeE?QsZ=b45?u=|xX99Cl<0eG|TXa9#G ztu#w9gq0N-{k4XJ5|(N8sv6nfavu2-=U!HEas6BsF@P_uABt_W%dkTB>LHtDj1OQn z#-`NJkH4v6s^q*y7}m|#*?M9u*BrSgWoHS4;-aU}KBP#_x)W}`bQvs@;(YygORWrTzp*oBF^_I5`3o8lz3heb=Y72 z`(1|H{>qa)+>oTQ-s5ozAy(CV5Iki|_Nb3vqU~J-Pldng^`QCsG(A#QDHb3li?$z0 zGgVFbj&c~7bT5ptE)c97NQqE1Maou>U&}E&W1f*sN%qaac9{!(nZVB2uzxLb7j9sM zB}0Ja_#7=j1L<=)CKnae`Og>0yhbD)NeP29@HJolCrcyrIH0V=QDoi?+n~CXqOdm`W&#AruSZ9w zV({nOdY>;+vAcaiirC1?1OuRrd59MQNX-8-GKegjgGoxr!sHWrD8T8!=}Aan!>^c0 zG&ggCT|vbb=5W9ouJG^yqwq-DbabO4|qPpnx6GnkmS!}HSMh0yk#DWd1h=4GI>GFr(wXd42sh0 zRa5Su>YjYcYNV>Quv;O`3t5kSV*@j8s-;&8h_UeQf!SiwDA`1#53ql5c72GvQ^NH= zL1=5e)R^{dC;C;0v)w;vB2^+7IiiSTw^E2DW;fC3r_`nH=V+Mcwm14+QJa_H{5DHkI@g0$7Ag4;l1gsie=O-XnEasfb+gt$nOAo$NW&GcZ0YM8%Z_QUxO zE-!muHX-#6W`puROT5uTY7%{G4%Q~GLL{M6@a0H+U1f>kAVv0|4qA4HC$ez zd@Y9BARbMcKB+d9VLL~nSjKRGv_Pw$6u2wUsLgr>a}})Yp^je@75HQIb2qhnfU1DC zh2CCjy8R}dSt9^kr+Imwrf39DS?#*;^Pro*M?m9Q{JknR_UH$M0Ah}) zDxab?EtJIn`D>%^@il2#{glw`fc^O4EgbIktX9%|) zWnFuaAP`pZsECT}rjbMji^o?(K8JxnUeB%Z?IrzFz%Wi^r?jRQ4)DsnbG+1G_3k%#^57WmP`F;iZr&q)6MxnVd|JD@{ozGKAL)$K46D@)+DX|vbWFzCDrs1 z%v8PpvdDoZ1jVRSsF8uQtw!Yb-Mce34a7d|_S-ozxuXco^^agK+2R=Es zcs@&-n3{D>P&wdSOc#9Kgu!oCN#88kF`Z`B#CW}!)Zta$OvSX_AS+EJd2r!CNs zP3n^`5X!S(;Z!IVZo-mwD(y+eCOnAa`33$3$1-}z`w;_T>d8d?RQheQTX`YFm%h~% zlkPq?i-;7>yL2OwjSXlWpo%EkB2su&n;1|U_v$61>6J9C`s*97kBOvD%4by_WaOrb zg2P^WtY({L>}co@2Cz%xDsdHO4)YD{Kmmzgq-{05IVM1?H(z7_Js~Gfv!(cq;@?KqxDw()mN(Yjo5PNy1wvzPh$)HQQtYP=5?vmGcd6*HNvxA%RFjcj$F3q?iJzjOU10MUG@u_ z$vs|;XPU7<6PauNXzM1i5*FO}sFuBD zs;>B&9`ieUeDZ3qI)bHATk95z>p*mplFdli#{b+=igoY-;0wS`b6S<82$^)ljBLe3 zqGM0FqOeylJ^c2sJ>XQdf%4r3u-$X6b4$HuF1NyIvTXasBZz6(} zB&1&{17mzk()7k(3nTYwc&wLDSW=<@+I+)1$j$-ME%njaBxvnCWUcgL=S7RDGI^c1 zzux(kq^YYuWbu}=Yn1<;$^`o>Y3{li3RRKhKgyo6e!9ilrvOH|0)7cDa;C|%^Mv6c z_|_d#C?@lfjB|no5#9q)I`!N_EsWRuPuT>QUM|?eN~>b|LC{u9zlKnE>t=Til(+By zM$7Xc%XDD$Bj>%YyJ+*zv^g0*h;KfW24d#gXYPDP?m3i@+aUMy+T;r~45)=3M1d6D z3nVD-B7=~JG~$y6uAc}9g}l{n<(Ar+tJatMWzV8srXTXb_*vZYDwmV+z5)&HwJ*=I z-PzQ`T`bs5XJQksN5<0e@wnL+{+YC3R(g$iXF(%f<79SCdbVh6B{N!|E;f|6o2Yg4 zq##DKEtz;;@jk#-V$R1`S<8Ci5{nA_KAX3 z6*MH#b#D?L@kP-o1Bj6x9r^TP+?R^K!8D^!c7`34&K@a%-(9+(Do9dna(p3^3Fpkcn?{RdjubI3dtOszxWW$kdolk?+v zrw-%k@s4|180(H7CzM#t1!K%v95%>NZ#b$L(H45}zKHbwT6aWT{&bA%9*Kyqe%&@e z*D&%Ccaal(nv5=OtESjr1n%R%j|9~<{4r z^?QjEe(x(hcM}c%e1#8zEE|R#;RLI}9z;5d>T^dy2Wmf*q#{M(o=;L92&LB8 zXtWJy=C)9$bl)XuTy(BcRRARBqEUBMz*nEfNGDyO75kH%ejF&Xj*`%Sf>zG5uhNPTRM-HA< z3Wm?fgBki;|47B|UiBX3L)R-cwz0dCX5!@#otH8H{EHg@gwXH@FO45wD{lTgLw{bY z?^H6^1fA@Zd6&A%Qs`@UVaxRrg5>3up6nkykP`n!z2;MRDXuNx0nuv{UhAIozkm3H zo$Np#eRKd*TKL-L*3Fepyr$zZ#nVl2Z z8NN0#T=Qwf>j7v7ni8I29hSYeViTb?$b%L`>1W=3R3DtcojDeZaw#y+kWvSiuoxSg zTRYzDs8PvF0~%%65aYeMqC6S-O1p{-`xjvE2r zd@F6s7ehbKC;7H%ysN-9GFx-O zi)lJG-_XKIcjd(7Sii=lNjxf)l{&`iDcL`A0k(8?QBjwm^`-IFzF}08iz+`5kdRllP5!O#KXP@w@O-8Gk695y4C2D+*MJvu zM&+!XJ|tK4A;gssJ+rLekF?BaLgtaZgN%hBLx#O(<>x}+lM1M+u`Bob)$@Ar3u;>m zb&pXs;XTrbBu3}4GX4M8g<1|&O>Li=%Z;k}M5T$%i^+J_s+ap~evZK#G%oCIrTq%3 zTYAumqK@qJW||S!MHcB%7lEet!VMYHT4&G|j@wSIQ-!ajzyHmuye!EeJP=3#Zo>CG z9zr*%UY`@Dn^Ob0`~SBsu*rTs?)nFV8}!Q{+vCY}%3qFOR=q17cHWCHO@R z>qnKrZ%|(1%`BUh0aTpG#HojVPt_eE*?{Gx*Mt-I)$2hZt*wBrI5{*-kh%NL2U=64>aAIrq8A1phfZB7B`% z$2$)x*ue1Y7F_S8dXb#X;5@?)g*tXT3Q5BU6)V!+PREgyXHR`@3p+U3+upsbR&1Zq zBC1MXjYi}meHT$MG%=r;oq}pZN}&2vN}ft{=lq6mGlm^EsF%`A>Spq$4itlb*lkG7 zb{za#i}HNAC;DPM)OcBvJa%^GzzlBZY3iG>PnoWe$9Ajncn0&EJ0DYU{q&t@*eEE|~T?vcQ#WgE&uYtw#IvP7=4x zM$7Dp#OTW~e&Ykj8qeQiK+30J!u3T%d%|Rm6%%=$zl)Hbe%`PA*E#!utT;sS=Do>V z`*9-^U%hqtPyCE5Dd%Zc3{v;V#D6vGZ*zp#c(vxfRC&A~elSIM4LbmDnP+XzbA~hx z={4DqgI?uOUDC@6D9k3iBs$s%($y}F{;XVm*HA{I*Dpzd)mU=WclEhr$bl%n<$K+h zTQjE3gBdm6p_DpP_kVmGA+l0dar6_ELXNBel3JeHEW9@u+o>sHOSpc1!wA57!RKUvHqS$5ORPs(!JR~@YJ(y$4( z57G|hyQ9&C{fkfbhMhYIre@y=8-SG))FB_M`#YWUIVA+A2-12XW$s7rkC)~w zc9{z-3iDI#pMMYUd`&0u6?yYSY~oeA&2e}c(^e8+gSw^SkhGm}_ft#jN;ja05T-s! zhh>-?9vJK#vIhyw2w=03*gp3gsL*G>O72uH3ovbJ+KIW2z%|rj_d5*HvY` z#{J+tgHJRNr-qCgEp`S#PhR%Jz!OR?AbahLFmxNHJIA}AzI#POI)GS`xG!LyRG+zJf(X#rpUZqlQqslTRkF* zzO=f1Gf5`o5A`jEIy@ST_U9DlM9GbY^Ou7UP0^7?`&|dAK3yBSUlc(D-Pq#hR|RK} zD$i}Q6DQ$puiCu&tKl?t$IagR)I}*bhb_gId48~s{2#`?!Y``tYxm5+kOI;jN-5n6 zNGTx=(mkMnl$3Oh7=Wa7gOoHwHw-8s-6awtAuTO^58(IreeZqm=ic`Zm^u5bv-Vog zv(~fs^1hAmX%cNXM^K;heYKyqO!MQlbh;sA6_7Eh`rxHKI-i5oD}eO=$!YLDF~Mv> zR{rJZS$f1p=#?jQC3DICN2h^tt%kVdj^O*QDiV~4<+y#)o54u95$M?;S8@1bd%=6B z%H2!2MXr7~u11eA>Ef6}@Z40zkk+93-g*B$`VL!=*wY+z! z`y2pL>49wqCKKLY1oW3kNXD~6&e26cKzMI;ET#GW(LMX=rD~@%#hdhM`lBlm#X6>o zvOO=~YImvoR17tEZ~F_aJworXcS}z;zus#KpsBmFUR_GKbaSpTW(4}bre6Czdb~aB zyH|}>*s*=( z6ni&fjmA{ZdG1oH%>1|P{rl?6gH=FqE%Y69t{tVAu8HwAH%iq)Pt%G_d|$R2`CWLj z>{mnJ1Q8kLSu2OqBZ8s58(F^s7SuTJQVr#Uin=H+sYx0Vqz|?kzA~t4yX*`LU30qQ zK;W`7T#(#JiqbYZ-LQAHR=sfh;wuQVAIB7>vf6Dvm~q%S^9xrDP3tRt241T1fm=EG z7Vr5`MZ3>O!RNI%b1L-**oZIy#c@1$lgE&gD2F))i;u59eL_oX%)za zKe<(zLZhDcH8eu|L7)E`a23_X+Y`1# z0C-b2TbDnG-WTf72eGQ==k3KuGoLQz+WS^Mnh`v8d&GZs^qO13ihgLeQ{cF*kA+K0 zQ{RXr)OKGebh|-Tp@9G8V>f2y?!aHp*`p7O_RexRSeLL?25h%%7SK=>6>N6}!Z!q> z_|Far&Mcnt@pgnz4m*awIIQ_O@LtoQ?YE4y#CReL1hpg1q?rFOPq;M@ya&E1>y6A) zFdN^z;snI>nza<5#4jWD>~IN0dixG-cUKPYua?YytNz&(WVP~I^LKZnsi#M`inWfB z@alrs`GJy;G`$;p2n9O?$RM^Wn`YJ7PSqFiWpn%QA#rJo?1Df@J z-s?Kb%zDrN@akY@r+Le+aM1LMzsQPxb}bZfw!lihHARvka$AJM`mj&a z)F5X)anI2+WJ#o?d2{c4NXlR#Qd`JLW1$+!RVTJbnURouwH(Q%*bVm$szKb54g8t{ ztGei4Nl4sCNSRF8%umSM^f>Wwhg+^Xt%_CJojuU{^u0c5Bwc68E#c{&y;M&~B6GE% zc~Bq_&?O}u|!1T)&}}sYAPW|D&k`Q= zc~&gZPf%X%>xX;(^KejmAbe*stj0yI zcbGKyK2ovX;#Zjozkt=k^H8G@aMEdP?XO8GpuCH=J#?^)Qw1iUAuBX+kUIOM=2=Czrd)YQRu5oPi=+)RGyS{Q>%Eb5cd0w4rg`(!qQP{hIt=@6MUYrfluhU~&|m70SVe&I4LyKC_7LPoPC9=RN6hdviBw5+8i{ zV&0XNM!|#q*AE|^SEynY2~A3Q2ev(`##??UM9T{Hu?Q5q4^Nk``F%Fbr;+{6VQ^E6 zUvY6=TL`OrDBQm!2=E*|N(IQ;1q+EEUM5l=Tr;fdG92&$9w6&tL@e?uzt?#KXg?@Y z9E<|}Nb#e5g!meGp=rr!@mft3?fs6=Z@*u}q`sij#ls}1bzoL*MCn*)atu;II06-Q zwI6|SFGTOA;P>u)O$5$J=Jlevu^>HcZWQ<0$Czl^G4<0iz>A5|C2ITVZITluM8e9y z*}q$>3(%?|U9JuDGHzTVMByxm2_@wL7lZ4@9U%rxdZY^oP5mfiiWLE|eG*ElqLT3_I zFZ&8t?|%LUn(vFz)z-}yR{3}18XHp58xm3pG{QOkJJnrP8im zLaX`Kzwa#tP~S+$LA|FzvxTH{BP>I4feK6qC?c-4!p^gWO{gZQJ6^TltiJ$X&653g z_b0GgX3F9SS)=flbJt##UdO$!B%}rhO96R-0U|D?Qk+yT;C0e_X)x}CH*vc*mMN652o@a@3D`K7(Jnz63_FNPO` zTn7gw4)Bno@_;%>4FRebc!9}7gSrU>MI(F1)gW8K9g3=fG6}1dESO|5UA1jCRmGP*!-sbD9oq*2?{=Z zq~zK&x2`->*F2=9EruRtaf@(K4-L+Tz>IpWO^7rA8Y15?2Zb16%+UcmNA93Jeu=d^ zcZX;(Qtq}<*@hZIxr;uN7&5Gf#PNo>W1=W9-M_Le55<>hqV^JGUvFXc(~E#2l9zWd zFYQM#etPkb7GUPe89Y>D%}AIKq>mPd_CJ=V^VZbtpiMjmhJp2)JP;%b6Ta)M&cU20 zT~mzVU|N>yEl!4_0jQ%0`GR=%Av|rLD&G6M3_y`BpTB>i^Fd+%lp@#l|Kd^NMKkw} z#}0{4`kQ@@rK*^23%DSar36Qtl-8Rn%&Ilpo9@ABL0|5YyY{cizy4LqfgNBgRY-tZ zxDhV_&Do0xjLnb3MS(ZCHizk3qFT9hqXtXDA%!Yj@%Jd*xTrZqVTO`R>IT59E5hwH zPCD^m?^s;Rh5S#!lHDepd|0;z=#a*Lx32s3)(z?NZ=aiIOT(HV22xdItDaGROol|s z^#x7i%zeU>M$PmErskEKmcbl7cD(iGq-jja3%MNV5E73q&e5DgncLkPIR@>u4*-BI-)^ZI^e1_whvD6^0JMe~jk?_6`DB%mZSerj+thSsUG>Z16b zACt;AZE|Y&t9r-<`VHPBHbQKDb-0+!V!I_OmYd+psMS8L?xo-?;fH|`*(YFdA-E1M z7JS#iC1h#7%TI`f|JG~N*f}txjISFL<1FUXCrkF(H(kwOYN27EANY;|7XXAanS%G} znKL=3B3C+@>z2ZGN8Ge?je9?H>AIAUQl?@hSfa9yP;pPFt2(8f&o}&!va;_DS}w)P z6Wfs$;SF0-fva$7FCs4GP7GWR#8G?o`0r+N{MRi(OI8Jj_ys3Q-#@jCU|OBSMD~1r z|K15EzbJsi%IAIC9aj8oEdg@l07$EZA&j>`EgjI3Bt6b5cs^~%# zxG>u!9gG=5E8oGOiH_D58gvjb!!#}lAN#}t&M*&zBgA?zFB8n+jWui^tz{(GpG`fi zeeI=I7|$VKP|(*APU>?RgGk-Q`cW*p2LT(?Gv; zXTM6>f}j8O%l{JOr6B85m}$R4cT!ZDe?0Xi0PkyCAqjnA0qNO`S8ir}dHW!zqx}GU ztH8Kx;LD!~Sj32iP+xxvKJgkXp?Ge@8FC7q?CYLJ;*K5Ic)ZR2=d4SPnnn;(C>3;D zGra-eco_CE56slkO4o?!uHq%))~0*}@Nb2A1M7)&_vVH<*H%%nh*9z0gBG!FKfMxD zbe>&bcB5c$F)yX#wgQKGZyYFrw&1zk^hh{=4k{ZP4kNqY+Ux8{DvoPbZ0mvt(Ot_q znd>XxYR{E0j&)h;5!sRoF>v6l(zfpuF2{lso@W<4tuqCll6|?aj34$EG!Ss*FpwO@ zAHhT@oD#>oUUOv9V*8(2eqiCk%SL}srKq%)%qAy|I=m`y8*9|tN&r!HYX3&Q5i9OI zGr)!M8;SOSWMmAvE36}tbHN(gmoS>Hk9=@RDzC_l#c0SCsr=dgi{rTxcX0?oF&5rC zBP0>({akX{uMB*IGL(l9^$at@57QH5Lb)KgV?xKh1b41~@rLJrHrqQu`;;@VEd-&g z>n+waaV(sJ7ynvY*?>CDYiN$#;39M_wVCMNe!?4j8h67K@$=c`Ez=%n#wP}B;iA9( zU~EikHi~wxlXOxo6+^xx>Ww&0U`@zM<4w*&b-Ta6J*{HSkdm58b## zaom3ct-ya0*i%nOb8iQ-dlUjt*N#cIr)fDS=`Q6$&!-Co$L!Aq)_#dp2~!xj*|m)s zC6#7-;=a&#uuE||vXvtFUF+5+P_j8X-C^;Tk$7he6OPk_-beCy5$!EH@;4z5vG{&< zi`yG3nMpd(hHsx-MS+p;IHOz;j%ZtR^`PK_-!JfS;E{%mI`g51+6(zn1PJ*ra$*S| z(z59r-)sl_F8Q3DF`i`0be_)UJ&%cw3LH5vBKXpMQK&RpUpg+mwR%)n#>EGamaN8M{ zpH=9B6jken3j8|QqaFmt_%0@VyU@9d>bAH@vbnft*WfDC(j$ukza_=_y)eP6O5XnU zKHL|5_>b%3Hp6)17@f_fI9L$!=vMRd)W3(Liocu}iI}y{m&OmdC1Oeul~SGesD*5b zld;lzCSt1Xd=+XNH7QnT88khi{ov09lg>{DLM0=BxQa9z+>BM5sp2A+Ii+tzy7>es z@!8{AOnVbsgS0Zm)y~*<+;I9;NPeWU0r^v>a@Ca*0_hea9TET}EV6;p2{^ch2YujEFq(RXq=)QFBPs0u~C7z7kMC6@k zrSAFt@ilT(Sl-HkEA=HWK5a&2hj8AuMAZQi5?c6bqNxSUE8_cH6HH~gi| z+yA%FIK}|5Aeb#1^aZCd$M+gO_IZ>bfh9~j=8v|5njg|_BeEG}UPb1+&52{0wj)j) zmWQzOvM8j$2`{o2RbQI@n#yLd;w7*H=uu3^LOyd3xHICg;gjoecfR3XxU&!eIiibp zS37oS^xZ!Aodc`?hRNjrgvnco7+2g3rX@9bp|Tcj3J}}!Y6fwiqM|)E*@)p~GC_P% zW(&CRRhmTU-Vu#7PN?2aE@wC!H0L-jjTx#8#_~0uFR*`Byvpub;;oAxWZQpqKprP9G zOIdi_2rtVGMBbez7CFsIzdvvUI?>t8l`j9>TGPo%Ie9`!WPb7y@uWM4b9i%c2Q6M< ztkn9aoF1{=GjMq3H%&dlHsj91J85Z7zuZdg4#!9kN97FpN&#%RW>uVlPBXn}u)*25 zV?(<(fvqDXXO5-Rjj8wfmM3J=)7z!ups6$w02v%VB(dp>R-2{K_!PEUjEo?dQ>}0) zey)O1$Ka-N_Q$y3ghh|#;pz}TcVHzEcf!Bw^NuMg&kgwNfLc|tV?^mid*T%x{LI$l z31+kC0B8upe48Iq_%bRD&=%PU9xMmx_uhOy#ZSR$Igk;m!;n3J(RFKz8FJnVA0<<~ zP+SlPUPJ)x+{bjXw<-O#$Gm6%Ghc2&;%aLE+Os!5+e&fxKU;6jg)X`fmiL`><*wU? zfN5;v?scBe`!~-+b+@Y+#P_4#>i!O2h8|t4mk_l2T^tmOxcGVwVHvva1WMYKB8zb1 zVLZc`0^mY|CX(o=r!qm5_fJ*f`F|1*_*x**<#@sK9DN;3i8z9ZU^0{kaI+0H*<#2M zGHvV?QQ$Iu{auF5)iT(gV!?k*6Oy1>4>hYTnh24$ZYD?lh{Y&EH6z4&b9cABdeg?J zjtU=1)6U?$=D}w$E|0I>9zPPGjJx2oiuy*@%vlb!a|E^>GI(V{HBtCiekN*RHiUDH z?ekcX%g7+8s$5d(csX#1P#2HzF&7thP;P9e)7m$95wHlT-UfeACU5ZXcFL< zJ)mM^J=O!?TnHXFwQGARFP+1Wm*4}GB#_I=tzk4%rf&mS`U6fr2FzpP(^uiU?^$?adSy+WtK@Yh0Ux=n=a&FgQ&5Ys2i^$oiwjdiIBtJ>=gKV#(M zd7rGdltseQE-m){uQkdU9itQhwiDg&J@F*cGYun?8*NIIw z!PMQn3sqrYa%4cj;?Xj5xE-~&^~U#Ip_=CE%Ai9gLfdOZARMP;Ukt5&*!yYCli8><{%9Fx@(`4I-hYgmj-h;q%EE+!KAsYDWK4hc^H$rz0RR3dmFR z9+UvzI69;!Iaa7D>x%1?si(cO#i@sf-bMtG)o%Xmg6SuuS)M1`drfv>Kkm%z^UJF^ z^i4Alc50(U8A|d!H@-1vis_#F@hIuYXW}Tifc~-<#9ts)3HP|HNGksQgsT57yWapG z0$!OUCGPsM2=N09R8&ISc^!1|g?8FykjpRA#+A}ivCH56gNFZ)-}TL7V8h8oS)b%w#*r>TfmqNn9{-IarvD|5 zNCCJdv^K}2Jh<@73ZQqZ8@eSs7~Iv>uk&Cr(dG8kYInGz16*?7qG5yiow84z?!dum z(*(|Go_mm|3Gc3XP4Yv~SJYk|U!#X(yj%bMWt3Z`u3sit1Q>%MPV<})`RPO;_P^$4 zudQ2l!2gK;hZ&{*C*^}A6=X)Y1)h7hbYWd{v#zz<7Ac2Xh2Q&H)WDLE;njEelQm=& z0pw(+p1HV?383@5kgD)|*D?L@(srExBinKL&902VW}Ael;Rua~)srrW8UG_;`MYOh)4@fpK4@x6t3JL~^dU{70l5sUiiWentP zb$*otGLiHvik!pm7c$O_po|;I$EXFHE3~Fj4mVMIFD>n|CBc4k98g1n`i%cuO)aIh zZ`trH{ya?pvi2PZ7^O8*IZbGt=Kt z;{}rP@1QH?#NlPT0AO1X9f|BJHLim$!r*&XSRq~QigvwCH2C<983BvxC4g7Yc(RWb z83cg$ji-ZG^tVu1r|-3gQuA7m+)+vtzy`;^ztp!{ISgbBL(R3kre1gM2&1Lox42>K zcLt6G{z9BrmF1H+o2?kK||G+(P`G1fp5U`I~aHX*<~j6@Pn8=?u& zLfF$IY!ksn^Ib!{RUL*L;D8z7BlC+zCDZjDUOc-5wFe0T8x=w?L1*`^q6Hkxq>UN* zQuG9zqr~gE_q-=rn7_ylrU?#Zx`7T)60&PWy+YG)(Js_|MJMJ7|MUAtDLT(9O^=r# z)Ax_D`sL!s-&NFfMU0)2Bx$%o?~wnC=_u#1;ML-OZK7Nb4XhO!&hu{|1gE3Xzi?3C z#2Jr8(!G`8juQj2RTK>pTdHz{ybV8=BhMAe-=w*aAl;rBM}^Ex#dF zL4nupH$0DjfTN~~Zr__ISTpC3i*#D-5;)0fH1Cf6n4jOZ_OvVd?u_o)&uARq2#uc& zzguw|tC%9k8@=56g-VU+M#J9k?Qc#`**t0&^g6KZ7hh3bVUo;W*Z65WS(be-RV76v z`=wEnckOr+D*M5Xb2yz?YZ`>V0nUs_I9BF}b6o{=$$_0uU66eL{F_2~O2xiPawxF8 zmMf>13VteYa5I^!TaWB9=Y7E_FJ7bdER8N9)-Be4bsstry<7rbZMgd^y7)D{GL6H< zmhzDyBwliG(lTuW5+U81qmr`vDjZ67biPqN+peW!wD@Ysz`il&8`1KtagFKccbb$i z4e0%yt#`NK;N_}Km<()GOIrqZL7M3=!3pA~KU&|WrtAdvuJV^^0diF$3SzHXk9L>6 zK9pLfdbFQZS8!IbCFxgMFIGB#y%oUV`~a$&-yj(U#5~AXKB}G&d-+R^#<_==P7)`* zvnIQEk9(h-Q-7f)&0E}ceS+j`{>Iy#1SrqlpY#_MR>KYAm5gv+45Wp9KhM66I?~lO zCE^b~#^MP@6DHW4?sj8yT+mGK`5RnF0~ry@zUS}t@Eu~XHfs863^1k-aWyh<5!enr z3H%+ep%AiH7(s93qdN(teR(`~I$1T;smz0=-4<@dLdi%633)m(QOAc{X|5_t3<`ZA z^3uvOEhGr}BsMeFvjRW%JCTlHb(}4O8DP1|#8c&Sa!_%8s?J0DA;SCcb`P6a$FWo~ZM=xGKJy3nXN807vV5%5Z*Sk^#S*qV*{SswQ!t3XSJ8u6ELG zc<;Fgn(~FG+Ys%}1?u!-t6)z;$ItSHt4{#n3KB-WB+>zIbnu0h&#K>VfKff7_;1rw zng(LqwHs%Gecw6iq2IR(;U?bAo|9(2TMgjE7WNc+7ENhch}5MNCHdBX8V8^;$Lxp8 z)0GJ*A!KAy#X(tG1(vQ55cNFXb~lRCm#FOt_M=ra9+#X{r~sXj2&OmGSv=Mc6 z`Xe`80JjXLZg)tm7Fp24qMEvHcXtmh9xCnU+F=OxK#VT#FYX!|+#Gf7=}Qs)bo(t) zo6Q|4ivvrL%Cj3!wCw~nEf;YpA^g0Sg)n6Grfk%`t#{uem!@B^LU_o>P8$q>^)EKc z^$cbk2_PqtHwO!LNh$(yIMJoo8Esf13}At(dThRTbZ`hDnsVWR&m&GuMo2GS6No$T zS0CLCBtodGkuYJ)2>}|GnPu5QaXXjeN79*Spxn?9-x?x^CjiTZb`blQ17^iocS2Sd ze0FEt42h$T{c)4<-lTh8h^*s?XN*TIKb~Wuvh4jLBYK!B% zdxhNby@3}0gFiF}QurDDg%rouQQx4(tJbSeLi)n>?Q`K`Kxn1y11-Dt!6`PXR9uhl zwFbWtE4x`laQxX6?pXr%qnf*sT29$R+z0TNn-JV2K`u66><`|g|1UId7#wn5e1Fcp zqHd3SqTW@H69voVKGUIbpvjM$eYaX|k+VMOyiLH$z{0nmcD*$7(@QICaXH!nmY=wcPIPWHT#l z_9b-u;&?}^@xWx)ykzTavm}a^L2EXL9}YDMy>L=>`U82SeHR6#ayzHf$2Sh?brU$0 zrz~vLeog+gKXDvsGii6%>mb>Q6TP+Tgx8xu_iG>*q_DyAmYgbVKK*(JKA@VvZTOEC zAdDYz#GrJpx-HN0rr8|j!;)x9Eu%R%M*fbxwEA1Iir;z(k{Y!sl{vn6BmQR!uF`2y zA0jV}|DyQBC+f3`Tz5;%gtuI<+J3ePq^8lv_;cU*3&m6^=h8z>2+~GjUerrO5X2lE z=Hk$H&cGa>FPHW5$JbrT{ra13fQFf>@8(W9Tk`uBuJ0`(_zZ}ZT%E)^bmV&7y<}#o^AmjF+O3!gfl8T8{%89mapwjEMj>JaFw_g>6v&jv zJMrA%F2gtYQcaNlOG#{HEc&DmdZA2I*nCRNzg_ zJ|DX*3#?w(qkDfiq4UsUqRY2_941&x)R1Jy4*0>(FO&iy2At11EK#eft%F$!$;%4K zE7srauw4E2h`txC4gNyC$bIgUepv23TQQ}kS&~ff$wf|J#gippM||FACdik$!)AexzwS5C2xzS6)zWYCKyj&f@jx+JC<(+bxOozeW z4ZBXE!$~hhhtYU0D0y503l5axgL8Uq25RJ$ktWf%V`J-EyRcA9Qb2ccl+y3b_JR^b)|6qt62;NROrem%n%&?=^;bK8nNt-p%D?tA z69T)ZVW*3oE*{HP3`|1zcYFA^kJn1P(vF(R9X@o2E~@8EFM8E-=%s=)e`r1j5Cj;-f=|b> zxasvSYq9SEj9sP8A$`EYy~SDsT?x3sZXx83tGnxZl9_R=5p#|_u-DSyvMp9l)7{&0 z!$qV}jKACmJ4hp2(bgRg5RSMRR`geFl<3-(&$w>>ef5D$C=HH^YP%fJ`AX^H{7fSa zn_>SF+#1S6WcB5$XExX&sD*5Q&$Sb%fw+2)K_2m<#UDneDUYr|cZugtIgkh793e0D zyRRgUM0cI@)|#ci(L)R>o)a$hr)^boo6q=J?LV|72BNmH zzuxuAQiesgG(%uGgnrYGiznIRhRX=#K$S`X+2v8(ptyf{` zZNfcR!6N{dr3gIfug(^vA}{b5u9zWJMmk7e8@Z*qr>MuS&J)CiEpQjuvEPsK>prw* z&jiL6I-?p_al98qVK0BShwf%*tSTka@0~99^FfqeMTxx5>GP5&QIc7pg7O4G^NZqJ z8a|jBxDpk!w)`F~Os+uj z!oSfb?kLjn&eTqQP3=75r&{BwkY;l>ig3orv>qGoamEL#DvkL{Z-Rh^_bN%1TkHRI zVEKNi0yvwtz4a|_%;kRy5b&upk@_uJm! z(xb2?;qqJgw!yXMF9h9r4+=f->SLL=a9;QxZ|^^10jk_Ww^}V~ zCcN?iUBfNhf~a@rL;yLO`vimz=lF!sReX81V~2L^U$$HrOfH!r(tBA!y^9d# z-)T#Q(lo<;bt~rg?J3LJNQbY>P{T;nL%XAHGF}Zz(nZm{a;sq$?#Z_g&iS7uq=BLP zv0i1{Z%m0lQsBuBkrL*)T%s3&Vv4aG+mUa+>Xr6z1fKK5hXVY(%~UO#TNa4>#EHJ%nkN=!Y%Q;!Cy_yX0{O1dTb#pvrC;nrUPJx>spb zt5^xk*aT6uKhOrckElsOC}I=~k@7?c5W+@eDWf6Ci}(i0I(}+slZz*MUJ< z5vt4M7LS31H?GBL%iq^5!yh#(?%(&~@WIsw$oO#0NN&RgOL`xM0=j%_-rdBQPiN^_ z$~5zrhpDI1gWL!vjPE-%lpANC*6$A}5TINeTn)Oy5{HXhjG?;nzJon-s2W%)Q`oal zn(6;2KbOF^_9j?l9PWNMBm$6)oj(R93d)fk;H7!cCw9j(Z!CB(sLrn6_y3&F)UVPG7+Av7`W4 z^&VxX-@Xyyw{@LqRb=Kgy|7;+ET-R?ZRL#8y~*nk+taKGNREsv$Z#`tPT>sHCqy<# zC zirl$>dr<(L2|M7Kl;*@@Zefr$qv_6a&J!+}>5nRkF@5W%Cd07?b|-S7BpAFqQF#|P12w+Mj15G6vTIHnXs{vh7GF-T@Q4T4W8R6o z9Xtv`2wG)iz_pdl`zdPKl^8hm!%YF|2R%NkgP3o!Lmz-uC0Z5-+zi4FBq10RSN}pa zoByKU|3?O#0!qGtsq&XX2Mv7eE*OP&7mm+oDlMTX@8n9=YVnEk{2@{2>?SqKmQ#s) z_HF=MzC^D}nscW_TzzZ4YKVT_@qZ~DHbZlk%U9gc%Na2C?_7#EBT6pcP`AlB`_3X3 zT;@aVvy^LzfC7uZYzL^p(}qk$PUeyUisC0Y2%jR>v3`YcM5Xwt?uhsHi`Q&bA_pf9 z;~YEYT7|HxcbkV@r0muF#z#9S z2zGn^Uxj_}e84|C=t^vqYcn794l6Cn6Mj|*vFhp?d&rHO5mnQ~K0d3Qo%{+ni5>qw zT@lwA?m@8;*>UR<7|0*(?@Xzk#Tp8v08+JudKvIRPf%E}QhKRClwSY;$qEQ<2ZVsB z{ZEs5p>H?(r~;Pc4p5f-m|4?9qZyyi9bA19nai?iA^@7LLR}3P45bZIP4k_LTF2$B zkBf6{AX;}$3)n5;j#+435(5Eyv3WJ~ltbxZv`y*BGiZFL33U^rQhsL@2p#WaU44RE z%Q|ya*zi}(>`6F=h6!$!TEM{$4Hn`qbZTpzdT{si|-4dv{=EmDN`o*nCK%hVya%2%eINryx+JMd9;vg zG+`?QwGheZc6)Q=hHe1%wEj=wdhv~X$EyN1$tI-We3)i^PYy+bnC2fqqbKNDm?>T$ zlfHoqwMmw&y}7C!ZE|m_Cji8 z*Z#7J2_TL95?>o}_sV0BY|;cFTsrFNF|&h~nlY7{o_oy0*H1pzTA7bcPq382N)x`5 zFG-d$MH?@iWZcN$wE=aiLYscm$Uj1E)))o`ZS}oX-f3b zt{8;}bjUXmc74&fNmo(w)7^UeL;6h5MSC=Jsqf3I!APHNyoq{W=0ukhY$}&ivMQaK zIhm$|BYEbk(<*u@m-TnCK7K)*%^O=jGi9>^>-t9q>qZyV$?_uK3=M;(wMtAo3Y;)F z9A$gYUT^@mM2H}OMHF!=I`9;1G=s%`hFiMv;QGrzV_HBE8xy5y;J8t#{!}qu_uugT z3{rOObh&Uk-6n70I=3z3fgteam@-a`%M$RDv#*wNG>+0;sShc@a`2mc*Xq3T^jnBF zFWmX!xFs{W#pDr6-gfuJ<}vi?NR#Xcd?DWVeLkqX5F998jm+vUv#v0at`kO-jb5skkHWgNULtlBASX* zX-ggLb~-5UZwp3#vZk!!j^T%6d!eJORjBO_xov6JdW^r=dj7tw#}j%DKYi+T$v44f zQv6#`w8jkVf#vKBu!^uFkvafrt&m2bfdr%Q?5$c3Dc(7uiic=gz}VF*17Js=}A+!_zH>tp!$wh)GZA z-WhGN5cyWD3(lZ%9u*#KKWgyn9$x=*%lM_uR0j3j=4ltXW5Gtr26J!&Uyw-WISkdL z2=E_yeRX>yFE~jCqQ$o$TC|`SscXm~HczM_Htgg=ZW}@UmaGtt&U+^>*ItViuxVHpTbG!sBx7qx+*_Hz zdp?74V$2r7w)$w$^+D-TOH>=bjxQsvjg zsa_ zQL5qz-&pSOR9KI)h0q8Op>a%B-H~K+U{+(A<<_sj>W<~yol^!B#P%V&msIHtMADN} zY{Fn6xn%Y9Xt%LyVcXAlR7=O>=l$bfnQJLN=sZoS{$Q%Tl0EeaWq+K#1yu1s;E{Yk z5mMNIfzNnt9zT31#f`9>8(L)oCfb9_R9y*n2plI(pWc_ly2-t|g&$tj--N4-e;iA` zeSFASM8#n;^@ww5!)@{*Hy_J~^69iQJOgsWw6QR6le29;Td!;(=+YhqUbUBp9I7?d zsz)&Gy8S0LW5=Ng67nOk`c{sG%FoY#@I3PQ5Ll2N2HNRi8iU1n)I#pdUqNFy=Yo~o_;b)nDovCjDZja zP&1m&_6x4mZ~5Pvz407pfk_gM0p4T_r&M57%~*&}|LSO$7Rl&65PM;RI;cvQ9}Uvz-7u)@(sZt0(~c0*+ho9FJ7u0@eW{y~<_n+c?32An67%c&2A>fe;YX8^5eH^|@>s7Xc6sc0^+t zm4isPj-Z#rKr*#w$#@FJ{xn)_0!;nvd!ELpky>W@`_I?1Gi?#pK>qU5^X zK#)q$kHLmmW4XDLs}jQg^v`y@h)aIlP3cz&$yyq&xkW+Hh{-;apB zNeFKI6&6BE?3)LpX>SH*!O)JFJkNOZ_K3a`x?0!qeFOB6z!O!ceS1H6|0~M zM4@XX&2&lk><{`(v1#)9&%hbMFQlT+Pq76TEd9#xNnb_vYe6H9BOMl!T0Z>ewJv>9 zY`@3ARs-F3%HLz+*vuD*t$~9&zK#AS!rt)pSE^f-@xCVU$)vl?Yd7~3X}oEYm+YQA z)GpEA^wAz{;QVG%3Z#Wiu||KTE!GVbGbwHlYZiZ>m||jj_-QM9%=&L2<3|kL#aU)QOV&Z=? zw)3TB;xM36k1YH5r+ZcM`)YcZ#Sy5eAoRV zG}Mn+akc#~(l7?Ffsf?qGW0nd8hjDzrMgp)WMMRZqB4C~8Yn1W07cc>F*-g_ir>T3 zOQ#>rJ4(_p;dg12`pCazM7$GE`xSR6(Uw1hn#sTS#CyaP75dy!)6JVttlP)5H*#gw zC_NOUQL5g&Tk91j$!8^o2n#u;Dh6MtM|Lkciqz07QKxq6`jroC=c`P@^ALj|aEE;XEZ0CM0?MslI*`}vq-=WL4TJ(zI2lj%3$ zG3B{k;Ymp0Zb?&XV%l3YB$`}PUfv-#7w6{m%!{I8Bls37Il~-F3iL zeM656!c&X%=&f)bhREH9N4{Z9D9SAQPCjf> zcEdIv(9JxY}xFe>4@{A7>A37o`gL7X{;l&K0d{PNT6!~k3Okx z$XGjEq9nCxPndiYrAat`h850VP4K4V}w@Fr}G2|>oxAt zL#rv+aU5uT>bbx3$vI9$BS$IE`GcdlojH5vCVtf3o)fojQ}~7dVvoqV<{n<FLC|HYXM{=<^`4Zbs^j{&G5u%dK;5_U?VmKJGYzJ8@L9I8kxu!dqGS*bsI^ zT-0HU-UFTo9^Anzx;zY{0M?3jevkcHQ9K?8hMivPehyVS?yPPQtzXD^24T7oGuf%d z3pYePuo`0ONfhj^e<}Pmlk0h`Xt!)A71)d48e)TkHbN`|MByeeLvvDPIj1u04si!-%snwauZG8Yk(xW)kH3DchIZWYwC%2qw|o`u8rgor}`dST}ou!!NxzYX)AgOp80ZyOfb*0um7vD zD-EY|{rcNRId;WShRARXC37+>TV+l{<_z1Mq0IAK$P|&W44LOC&Nlwpln4hLryzAM!bN=VN=fnH@;@a2!4EM0sy4StdZ~Y$Hjrqr}_~L$9ucdT!SxE`svR`DuFFG%?uiwz@`_*-E{5pimkkFCt*15j7GGI?OE}y_gVB|woBC+}F=+2wA*-67nVyF4U&U3v%F&LFuDI(4r_u;>x;j1{eMzcaM z-NeGdX+1|DeTi>7zgKG@U)t>xWZ&t<6KZt!Zlt|ViAZ6O*bOegEdYi}K1Ikx8#nUA zx~De6FaT9RP#r&s%Fn@->~Evg-``vqtMsNVC zV^nVT$91-?%^=g=F#S_qL%Y54)-<>a>)nNAhyfma?7v`r9K6wPebAA3|13dFPL%tP zIc03g=0XxyD;#?!9J|s17=*dDBn1LBC60QxqIJ&~J_)&Hhf+rI4=O}?OOiI_A~m1I z7#@?2`tMTFKYZ@!Cz3gSi9YOvO9|4Y4Q7$&~2>!lG5&E#KsLD9j_CjpQLx)6#Rq}Jm)<6&8IP~gxLM-@#1u|PLu4# z4g+4?4>Jtk{VFoldgq_+SeUj%?%SE3lqUO~EH#a6JeArM_4vb6U%7*NW|6}ko{4%) zJws+#mZpG1SzOS1xSw^Y%~~ zzc0g~0twg0u7n~7nWV4`|M7~EovRUv_pLBSz*UQp8QdV~xegv~rZ3VF_e+w7S{#?k3L%aV_e(W>38XG*G z6?z9YtseoF(jaiR;dqKE(4QM@j%cWGKS$2sE2D_#gwZuDJz1e?6nw)TFX>(UuA7d) zH|vWk$UH(vCfg`GqAn|0do;FTA5*q9>|@HUzG*k^MDcJl+LHn*NL4cx{m00-MOo&m z*%656{Y!>O*s2-uS~G%4rWb(DM&0Q^N3O&J=eezw9RAKGz{N0233^JS$BvLyeGD+C z^O3=6q6vDF9=Gh3AJb^o*y#4|?tP*04;l8#xOAmcv z;Vn{-tcAJi1gy#ofQZXf0#5;nNR-%c*%FjQKNXDl-H`T6)N*Wk+jg8KSQn&Kn#(AH%(IOh1L7~#cvHW+-x$7crG|W(XBVvZ&7c# zxHGo8(f-P|Yu6UMq5vMFOvQi4lk`+P#yxSc8T^bLhk1GUpvTTRn%p<*-u~JhUYUlf z;(scsnecGlkk;*GssELl0E|V;G!9wbB6&@?^8&r))@?wi@)tG7-%3X@1Y#_NI)jKP ze*TFri%mzc&s*<~>qWKI$<3U$4jW8q{X4HbxlE2G9$( z4jRF@qTtkCHWpRW>I*{E;ddK?fmFCZZZj=U#`4DWA&zbJzZ_cz;UJ|zaIw3Zs@{>2 zqK8xE?t!_{ZWIDoN&~)B1fbhiYi>uJw>`x38ja$K2EpB=Q=}3nepT)sxW0sRm`^vOCp_fP=R*-UT#o*6yJ$8Yiejj6zKu0_ z?Z-#{3QZMhAbGES)m%3l@gfEy4#o#Yz%Lwh9czS6{U$Uhs!2Sn} zNA1n7pB=H8XA$+M8T*Uo>0S>^-fV!iy}ILFuyfv^Y0-sdT(W#<11po1ln*3}(0mAA zc7Gl~OysGAlylhn_q(@!KinIge6}34dF+TxJ(p4}TgWHDhb;5UX8XHT!ul;SA95>1 z1~XajA@x(1qW`L&nwshFiVH_E_%M#hqDVos=A=F+cRYHGUszD}PNnev8jq5(Cw=m+ zUGe5t`av5XoWu{tvtOepmR9AOR%S>2P&`_-{c=YD;Vb)=)* zOQV9^VDn`oJ46NpXp%oJSF(-|J6uI+e*Pwx%h=+wAn82NfmPbsSk(6HnssAOzXw6; z_bJy3KP)frvtBj}9OlPbZd8i=VD$2nh$z3y=E-{?)2CvzqNFg#f6J#kSsT<1U!)-m zdJzGvM^)dq#0I%IgB9NdP>MsTgQ+PCSsA#vsm?=r$E;oyVYf&5YGI-3#I-mt$DQAm zHI`cy-MzIpZKuV*@7X@x7|=6e-4&516Y=@;s;AAK)k`5D7yHj?(*-29Q~7ZK28j| zP|-k4rzxEIgxZ1NHUU0sA##-O$ze+n%ox?&eNvw!hmNWWM-dkkqxW%aGyVJ`-J3%qQTkq5h`o&1)ftH)-Pr)#4A|)uY-lB9z zb?_QfD{gy^juP$Xc)5<}7a;q|MdJV<@?`Pr#tW~hPm$9c*XbzjcjHe*8Wpb@p`GYH zY`2BY=B{?A(S!q_CTM3bk3Gk~?r5Wrmc%@lK83mu?^z!e3DlZjje+e1_1RXS5o@L( zbfDM}c8HDRB-jQ>{y!3HdZv5$Kp^eBEXSrK(KlIKFWLW>al znL~^}a1n*uKKlVeG9I5pvr~>dzhc>0*cXOW?~&sMH&*pi3at%#LtD1{f+Gd#B3ZEW zCwI5^CavxTtG;$1G|YN?me$z2$dD&Hn9l5cG5`1Gf9}Vv#iCzuBaP1^%s~ZVv#R4@ zPQ!&Wzc@!;!09reo^GyktnzpbTmv^>ZQS+ficG5lw3(rF9p>Z+gaE* zD1hvcL0*7Cuo;BE-QmPA8wk>}G@}$7K^B$i5xmx3_w1n#M|Ln~0rTFHdv6a<-pr!I z0)E3Y`1{PQ`UOFLz7BQ*nLaA{yH7c zrXF-Ng3F4j2XIc2&sj-6UIV9 znWulnKW(O|4CuWl`b0~s{2}OtZ+`OX)GOhjU#UqM|7a0o&kN97r>xg zITEW%3Q{@cud$ejT0H2Enk&`Sy-E=?L-zT>V9Q?t) zR9!6Umbe53{TM+LZobb%RtL`C48r39vZ3`lSfW#zjFiNfn&ycOg*ChguYs(tr(iY)01nE)YL*n1Pf_LFWJp>X#eDGf za*N1r#>SEGE1^Je@!dO;D;qM2w9r-RY`%#@NSdY=KIKtFOx8z*;*KjpDXNkd`I{5$ zlq6D%sJIjeqO&l;2}{u~}};nonfIVQ|j|re>1yPK6fQCZH={)jI5VK$(X#6B@9nB0gB=#&?URUS_=X>slFfYM{s7d{F zDtPe!vQvVhN%fB-V@hxE()0RJGF1!joR%jml5c|^(W@ItoKON;WE#%7b{F$-?t4@+ z3>-R)L^r}fW%Za$#_d($rN4z)ivQU_?EK%AXY2bzE^yp~smIDtTpJR8ckx;wH()-Z z@%t9G=g9;-g|4vBGK#Hi2!o-S%0u;+J%91&1ctr}fq9th@%lL+Lq@ZnY^kNFn7}xn zyqW6y$?ABy{PFi1YBA|q*ADg_+%q*;WpjSz@bu$Zzs{ZV-T@@}M-4s8*USj`1n7(B zFF=xzek0w3)w6{*myKH#ol2vV@q0H zkSs;y^w2-rq>ypdcyUQdpbaQ8lpYWRL8Mp0t_%ml&ZO;s$E&V?%ZPmXLIOoJ30$lXJW4RC1A63oy7Ht-Yu@CQFxbsu4 zh?hLpfx)QdpWAs^60EMG2AmoHy%VzBWdtw1^Y5ix*f=_&9Q^N1@S{pKWS^$yR9nig TvcCzS;7?UiL!sg#?)LuxY$87L literal 0 HcmV?d00001 diff --git a/aws/multi_region/primary/availability_zones.tf b/aws/multi_region/primary/availability_zones.tf new file mode 100644 index 0000000..87d8f48 --- /dev/null +++ b/aws/multi_region/primary/availability_zones.tf @@ -0,0 +1,3 @@ +data "aws_availability_zones" "available" { + state = "available" +} diff --git a/aws/multi_region/primary/cert.tf b/aws/multi_region/primary/cert.tf index eb2c3a1..9881f83 100644 --- a/aws/multi_region/primary/cert.tf +++ b/aws/multi_region/primary/cert.tf @@ -1,12 +1,12 @@ data "aws_route53_zone" "kasm-route53-zone" { - name = "${var.aws_domain_name}" + name = var.aws_domain_name private_zone = false } resource "aws_acm_certificate" "kasm-alb-cert" { - domain_name = "${var.aws_domain_name}" + domain_name = var.aws_domain_name subject_alternative_names = ["*.${var.aws_domain_name}"] - validation_method = "DNS" + validation_method = "DNS" lifecycle { @@ -15,8 +15,8 @@ resource "aws_acm_certificate" "kasm-alb-cert" { } resource "aws_route53_record" "kasm-route53-cert-validation-record" { - for_each = { - for dvo in aws_acm_certificate.kasm-alb-cert.domain_validation_options: dvo.domain_name => { + for_each = { + for dvo in aws_acm_certificate.kasm-alb-cert.domain_validation_options : dvo.domain_name => { name = dvo.resource_record_name record = dvo.resource_record_value type = dvo.resource_record_type @@ -27,16 +27,12 @@ resource "aws_route53_record" "kasm-route53-cert-validation-record" { records = [each.value.record] zone_id = data.aws_route53_zone.kasm-route53-zone.id - ttl = 30 + ttl = 30 allow_overwrite = true } resource "aws_acm_certificate_validation" "kasm-elb-certificate-validation" { certificate_arn = aws_acm_certificate.kasm-alb-cert.arn - validation_record_fqdns = [for record in aws_route53_record.kasm-route53-cert-validation-record: record.fqdn] + validation_record_fqdns = [for record in aws_route53_record.kasm-route53-cert-validation-record : record.fqdn] } - -output "certificate_arn" { - value = "${aws_acm_certificate_validation.kasm-elb-certificate-validation.certificate_arn}" -} \ No newline at end of file diff --git a/aws/multi_region/primary/db.tf b/aws/multi_region/primary/db.tf index d6e60f2..6f7b8e4 100644 --- a/aws/multi_region/primary/db.tf +++ b/aws/multi_region/primary/db.tf @@ -1,33 +1,31 @@ resource "aws_instance" "kasm-db" { - ami = "${var.ec2_ami}" - instance_type = "${var.db_instance_type}" - vpc_security_group_ids = ["${aws_security_group.kasm-default-sg.id}"] - subnet_id = "${aws_subnet.kasm-database-subnet.id}" - key_name = "${var.aws_key_pair}" + ami = var.ec2_ami + instance_type = var.db_instance_type + vpc_security_group_ids = [data.aws_security_group.data-kasm_db_sg.id] + subnet_id = data.aws_subnet.data-kasm_db_subnet.id + key_name = var.aws_key_pair root_block_device { - volume_size = "40" + volume_size = var.db_hdd_size_gb } - user_data = <<-EOF - #!/bin/bash - fallocate -l 4g /mnt/kasm.swap - chmod 600 /mnt/kasmswap - mkswap /mnt/kasm.swap - swapon /mnt/kasm.swap - echo '/mnt/kasm.swap swap swap defaults 0 0' | tee -a /etc/fstab - cd /tmp - wget ${var.kasm_build} - tar xvf kasm_*.tar.gz - bash kasm_release/install.sh -S db -e -Q ${var.database_password} -R ${var.redis_password} -U ${var.user_password} -P ${var.admin_password} -M ${var.manager_token} - EOF + user_data = templatefile("${path.module}/../userdata/db_bootstrap.sh", + { + kasm_build_url = var.kasm_build + user_password = var.user_password + admin_password = var.admin_password + redis_password = var.redis_password + database_password = var.database_password + manager_token = var.manager_token + swap_size = var.swap_size + } + ) + tags = { Name = "${var.project_name}-kasm-db" } } - -output "kasm_db_ip" { - value = "${aws_instance.kasm-db.private_ip}" +data "aws_instance" "data-kasm_db" { + instance_id = aws_instance.kasm-db.id } - diff --git a/aws/multi_region/primary/lb_s3_log_bucket.tf b/aws/multi_region/primary/lb_s3_log_bucket.tf new file mode 100644 index 0000000..b43677f --- /dev/null +++ b/aws/multi_region/primary/lb_s3_log_bucket.tf @@ -0,0 +1,56 @@ +data "aws_elb_service_account" "main" {} + +resource "aws_s3_bucket" "kasm_s3_logs" { + bucket_prefix = "${var.project_name}-${var.zone_name}-" + force_destroy = true +} + +data "aws_s3_bucket" "data-kasm_s3_logs_bucket" { + bucket = aws_s3_bucket.kasm_s3_logs.bucket +} + +resource "aws_s3_bucket_acl" "kasm_s3_acl" { + bucket = data.aws_s3_bucket.data-kasm_s3_logs_bucket.id + acl = "private" +} + +resource "aws_s3_bucket_policy" "kasm_s3_logs_policy" { + bucket = data.aws_s3_bucket.data-kasm_s3_logs_bucket.id + + policy = jsonencode({ + Id = "Policy" + Version = "2012-10-17" + Statement = [ + { + Action = [ + "s3:PutObject" + ] + Effect = "Allow" + Resource = "${aws_s3_bucket.kasm_s3_logs.arn}/AWSLogs/*" + Principal = { + AWS = [ + data.aws_elb_service_account.main.arn + ] + } + } + ] + }) +} + +resource "aws_s3_bucket_server_side_encryption_configuration" "encrypt_elb_bucket" { + bucket = data.aws_s3_bucket.data-kasm_s3_logs_bucket.id + + rule { + apply_server_side_encryption_by_default { + sse_algorithm = "AES256" + } + } +} + +resource "aws_s3_bucket_public_access_block" "s3_log_public_access" { + bucket = data.aws_s3_bucket.data-kasm_s3_logs_bucket.id + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true +} diff --git a/aws/multi_region/primary/main.tf b/aws/multi_region/primary/main.tf deleted file mode 100644 index 0c7c31a..0000000 --- a/aws/multi_region/primary/main.tf +++ /dev/null @@ -1,14 +0,0 @@ -provider "aws" { - region = "${var.aws_region}" - access_key = "${var.aws_access_key}" - secret_key = "${var.aws_secret_key}" -} - -data "aws_availability_zones" "available" { - state = "available" -} - -output "primary_aws_region" { - value = "${var.aws_region}" -} - diff --git a/aws/multi_region/primary/output.tf b/aws/multi_region/primary/output.tf new file mode 100644 index 0000000..f735419 --- /dev/null +++ b/aws/multi_region/primary/output.tf @@ -0,0 +1,35 @@ +output "certificate_arn" { + value = aws_acm_certificate_validation.kasm-elb-certificate-validation.certificate_arn +} + +output "webapp_subnet_ids" { + value = data.aws_subnet.data-kasm_webapp_subnets[*].id +} + +output "agent_subnet_id" { + value = data.aws_subnet.data-kasm_agent_subnet.id +} + +output "kasm_db_ip" { + value = data.aws_instance.data-kasm_db.private_ip +} + +output "primary_vpc_id" { + value = data.aws_vpc.data-kasm-default-vpc.id +} + +output "lb_log_bucket" { + value = data.aws_s3_bucket.data-kasm_s3_logs_bucket.bucket +} + +output "lb_security_group_id" { + value = data.aws_security_group.data-kasm_default_elb_sg.id +} + +output "webapp_security_group_id" { + value = data.aws_security_group.data-kasm_webapp_sg.id +} + +output "agent_security_group_id" { + value = data.aws_security_group.data-kasm_agent_sg.id +} diff --git a/aws/multi_region/primary/provider.tf b/aws/multi_region/primary/provider.tf new file mode 100644 index 0000000..ea82995 --- /dev/null +++ b/aws/multi_region/primary/provider.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + #version = "4.56.0" + } + } +} \ No newline at end of file diff --git a/aws/multi_region/primary/routes.tf b/aws/multi_region/primary/routes.tf new file mode 100644 index 0000000..50c62e8 --- /dev/null +++ b/aws/multi_region/primary/routes.tf @@ -0,0 +1,32 @@ +resource "aws_route_table" "internet_access" { + vpc_id = data.aws_vpc.data-kasm-default-vpc.id + + route { + cidr_block = var.anywhere + gateway_id = data.aws_internet_gateway.data-kasm_default_ig.id + } + + tags = { + Name = "${var.project_name}-kasm-default-route" + } +} + +data "aws_route_table" "data-internet_gateway_route_table" { + route_table_id = aws_route_table.internet_access.id +} + +resource "aws_route_table_association" "webapp_route_association" { + count = var.num_webapps + subnet_id = data.aws_subnet.data-kasm_webapp_subnets[count.index].id + route_table_id = data.aws_route_table.data-internet_gateway_route_table.id +} + +resource "aws_route_table_association" "db_route_association" { + subnet_id = data.aws_subnet.data-kasm_db_subnet.id + route_table_id = data.aws_route_table.data-internet_gateway_route_table.id +} + +resource "aws_route_table_association" "agent_table_association" { + subnet_id = data.aws_subnet.data-kasm_agent_subnet.id + route_table_id = data.aws_route_table.data-internet_gateway_route_table.id +} diff --git a/aws/multi_region/primary/security_group.tf b/aws/multi_region/primary/security_group.tf index 7447042..fe1cc95 100644 --- a/aws/multi_region/primary/security_group.tf +++ b/aws/multi_region/primary/security_group.tf @@ -1,37 +1,145 @@ -resource "aws_security_group" "kasm-default-sg" { - name = "${var.project_name}-kasm-allow-db-access" - description = "Allow access to db" - vpc_id = "${aws_vpc.kasm-default-vpc.id}" +resource "aws_security_group" "kasm-default-elb-sg" { + name = "${var.project_name}-${var.zone_name}-kasm-allow-elb-access" + description = "Security Group for ELB" + vpc_id = data.aws_vpc.data-kasm-default-vpc.id ingress { - from_port = 22 - to_port = 22 + from_port = 443 + to_port = 443 protocol = "tcp" - cidr_blocks = ["${var.ssh_access_cidr}"] + cidr_blocks = var.web_access_cidrs } ingress { - from_port = 5432 - to_port = 5432 + from_port = 80 + to_port = 80 protocol = "tcp" - cidr_blocks = [aws_subnet.kasm-webapp-subnet-1.cidr_block, aws_subnet.kasm-webapp-subnet-2.cidr_block] - } - - ingress { - from_port = 6379 - to_port = 6379 - protocol = "tcp" - cidr_blocks = [aws_subnet.kasm-webapp-subnet-1.cidr_block, aws_subnet.kasm-webapp-subnet-2.cidr_block] + cidr_blocks = var.web_access_cidrs } egress { from_port = 0 to_port = 0 protocol = "-1" - cidr_blocks = ["0.0.0.0/0"] + cidr_blocks = [var.anywhere] + } + + tags = { + Name = "${var.project_name}-${var.zone_name}-kasm-allow-access" + } +} + +data "aws_security_group" "data-kasm_default_elb_sg" { + id = aws_security_group.kasm-default-elb-sg.id +} + +resource "aws_security_group" "kasm-db-sg" { + name = "${var.project_name}-kasm-allow-db-access" + description = "Allow access to db" + vpc_id = data.aws_vpc.data-kasm-default-vpc.id + + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = var.ssh_access_cidrs + } + + ingress { + from_port = 5432 + to_port = 5432 + protocol = "tcp" + cidr_blocks = data.aws_subnet.data-kasm_webapp_subnets[*].id + } + + ingress { + from_port = 6379 + to_port = 6379 + protocol = "tcp" + cidr_blocks = data.aws_subnet.data-kasm_webapp_subnets[*].id + } + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = [var.anywhere] } tags = { Name = "${var.project_name}-kasm-allow-db-access" } } + +data "aws_security_group" "data-kasm_db_sg" { + id = aws_security_group.kasm-db-sg.id +} + +resource "aws_security_group" "kasm-webapp-sg" { + name = "${var.project_name}-${var.zone_name}-kasm-webapp-access" + description = "Allow access to webapps" + vpc_id = data.aws_vpc.data-kasm-default-vpc.id + + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = var.ssh_access_cidrs + } + + ingress { + from_port = 443 + to_port = 443 + protocol = "tcp" + security_groups = [data.aws_security_group.data-kasm_db_sg.id] + } + + ingress { + from_port = 443 + to_port = 443 + protocol = "tcp" + security_groups = [data.aws_security_group.data-kasm_agent_sg.id] + } + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = [var.anywhere] + } +} + +data "aws_security_group" "data-kasm_webapp_sg" { + id = aws_security_group.kasm-webapp-sg.id +} + +resource "aws_security_group" "kasm-agent-sg" { + name = "${var.project_name}-${var.zone_name}-kasm-agent-access" + description = "Allow access to agents" + vpc_id = data.aws_vpc.data-kasm-default-vpc.id + + ingress { + from_port = 22 + to_port = 22 + protocol = "tcp" + cidr_blocks = var.ssh_access_cidrs + } + + ingress { + from_port = 443 + to_port = 443 + protocol = "tcp" + cidr_blocks = [var.anywhere] + } + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = [var.anywhere] + } +} + +data "aws_security_group" "data-kasm_agent_sg" { + id = aws_security_group.kasm-agent-sg.id +} diff --git a/aws/multi_region/primary/subnet.tf b/aws/multi_region/primary/subnet.tf index 0f45679..a626318 100644 --- a/aws/multi_region/primary/subnet.tf +++ b/aws/multi_region/primary/subnet.tf @@ -1,54 +1,51 @@ -resource "aws_subnet" "kasm-database-subnet" { - vpc_id = "${aws_vpc.kasm-default-vpc.id}" - cidr_block = "10.0.0.0/24" +locals { + kasm_vpc_subnet_cidr_mask = split("/", var.vpc_subnet_cidr)[1] + kasm_server_subnet_cidr_calculation = (8 - (local.kasm_vpc_subnet_cidr_mask - 16)) + kasm_server_subnet_cidr_size = local.kasm_server_subnet_cidr_calculation < 2 ? 2 : local.kasm_server_subnet_cidr_calculation + kasm_agent_subnet_id = (var.num_webapps + 1) +} + +## Will create Agent subnet x.x.0.0/24 (assuming a VPC Subnet CIDR between x.x.0.0/16 and x.x.0.0/22) +resource "aws_subnet" "kasm-db-subnet" { + vpc_id = data.aws_vpc.data-kasm-default-vpc.id + cidr_block = cidrsubnet(var.vpc_subnet_cidr, local.kasm_server_subnet_cidr_size, 0) map_public_ip_on_launch = true tags = { - Name = "${var.project_name}-kasm-subnet" + Name = "${var.project_name}-kasm-db-subnet" } } -resource "aws_subnet" "kasm-webapp-subnet-1" { - vpc_id = "${aws_vpc.kasm-default-vpc.id}" - cidr_block = "10.0.20.0/24" - availability_zone = data.aws_availability_zones.available.names[2] +data "aws_subnet" "data-kasm_db_subnet" { + id = aws_subnet.kasm-db-subnet.id +} + +## Will create WebApp subnets x.x.1.0/24 and x.x.2.0/24 (assuming a VPC Subnet CIDR between x.x.0.0/16 and x.x.0.0/22 and 2 webapps) +resource "aws_subnet" "kasm-webapp-subnets" { + count = var.num_webapps + vpc_id = data.aws_vpc.data-kasm-default-vpc.id + cidr_block = cidrsubnet(var.vpc_subnet_cidr, local.kasm_server_subnet_cidr_size, (count.index + 1)) + availability_zone = data.aws_availability_zones.available.names[count.index] map_public_ip_on_launch = true tags = { - Name = "${var.project_name}-kasm-webapp-subnet-1" + Name = "${var.project_name}-kasm-webapp-subnet" } } - - -resource "aws_subnet" "kasm-webapp-subnet-2" { - vpc_id = "${aws_vpc.kasm-default-vpc.id}" - cidr_block = "10.0.30.0/24" - availability_zone = data.aws_availability_zones.available.names[1] - map_public_ip_on_launch = true - tags = { - Name = "${var.project_name}-kasm-webapp-subnet-2" - } +data "aws_subnet" "data-kasm_webapp_subnets" { + count = var.num_webapps + id = aws_subnet.kasm-webapp-subnets[count.index].id } +## Will create Agent subnet x.x.3.0/24 (assuming a VPC Subnet CIDR between x.x.0.0/16 and x.x.0.0/22) resource "aws_subnet" "kasm-agent-subnet" { - vpc_id = "${aws_vpc.kasm-default-vpc.id}" - cidr_block = "10.0.40.0/24" - availability_zone = data.aws_availability_zones.available.names[1] + vpc_id = data.aws_vpc.data-kasm-default-vpc.id + cidr_block = cidrsubnet(var.vpc_subnet_cidr, local.kasm_server_subnet_cidr_size, local.kasm_agent_subnet_id) map_public_ip_on_launch = true tags = { - Name = "${var.project_name}-kasm-webapp-subnet-2" + Name = "${var.project_name}-agent-natgw-subnet" } } - -output "webapp_subnet_1_id" { - value = "${aws_subnet.kasm-webapp-subnet-1.id}" +data "aws_subnet" "data-kasm_agent_subnet" { + id = aws_subnet.kasm-agent-subnet.id } - - -output "webapp_subnet_2_id" { - value = "${aws_subnet.kasm-webapp-subnet-2.id}" -} - -output "agent_subnet_id" { - value = "${aws_subnet.kasm-agent-subnet.id}" -} \ No newline at end of file diff --git a/aws/multi_region/primary/variables.tf b/aws/multi_region/primary/variables.tf index 2b162c4..dca6b3b 100644 --- a/aws/multi_region/primary/variables.tf +++ b/aws/multi_region/primary/variables.tf @@ -1,82 +1,113 @@ variable "aws_region" { description = "The AWS region for the deployment. (e.g us-east-1)" + type = string } -variable "aws_access_key" { - description = "The AWS access key used for deployment" -} - -variable "aws_secret_key" { - description = "The AWS secret key used for deployment" -} variable "project_name" { description = "The name of the deployment (e.g dev, staging). A short single word" + type = string +} + +variable "vpc_subnet_cidr" { + description = "The subnet CIDR to use for the Primary VPC" + type = string } variable "aws_domain_name" { description = "The Route53 Zone used for the dns entries. This must already exist in the AWS account. (e.g dev.kasm.contoso.com). The deployment will be accessed via this zone name via https" + type = string +} + +variable "db_hdd_size_gb" { + description = "The HDD size in GB to configure for the Kasm Database instances" + type = number +} + +variable "db_instance_type" { + description = "The instance type for the Database" + type = string + default = "t3.small" +} + +variable "swap_size" { + description = "The amount of swap (in MB) to configure inside the compute instances" + type = number } variable "kasm_build" { description = "The URL for the Kasm Workspaces build" + type = string } variable "database_password" { description = "The password for the database. No special characters" + type = string + sensitive = true } variable "redis_password" { - description = "The password for the database. No special characters" + description = "The password for the Redis server. No special characters" + type = string + sensitive = true } variable "user_password" { - description = "The password for the database. No special characters" + description = "The standard (non administrator) user password. No special characters" + type = string + sensitive = true } variable "admin_password" { - description = "The password for the database. No special characters" + description = "The administrative user password. No special characters" + type = string + sensitive = true } variable "manager_token" { - description = "The password for the database. No special characters" + description = "The manager token value for Agents to authenticate to webapps. No special characters" + type = string + sensitive = true +} + +variable "service_registration_token" { + description = "The guac token value for Guac RDP servers to authenticate to webapps. No special characters" + type = string + sensitive = true } variable "zone_name" { - default = "default" - description="A name given to the kasm deployment Zone" + description = "A name given to the kasm deployment Zone" + type = string + default = "default" } variable "aws_key_pair" { description = "The name of an aws keypair to use." -} - -variable "db_instance_type" { - default = "t3.small" - description = "The instance type for the Database" + type = string } variable "ec2_ami" { - description = "The AMI used for the EC2 nodes. Recommended Ubuntu 18.04 LTS." + description = "The AMI used for the EC2 nodes. Recommended Ubuntu 20.04 LTS." + type = string } -variable "ssh_access_cidr" { +variable "ssh_access_cidrs" { description = "CIDR notation of the bastion host allowed to SSH in to the machines" + type = list(string) } -variable "num_agents" { - default = "2" - description = "The number of Agent Role Servers to create in the deployment" +variable "web_access_cidrs" { + description = "List of Networks in CIDR notation for IPs allowed to access the Kasm Web interface" + type = list(string) } variable "num_webapps" { description = "The number of WebApp role servers to create in the deployment" + type = number } -variable "agent_instance_type" { - default = "t3.medium" -} - -variable "webapp_instance_type" { - default = "t3.small" - description = "The instance type for the webapps" +variable "anywhere" { + description = "Anywhere subnet for routing and load ingress from all IPs" + type = string + default = "0.0.0.0/0" } diff --git a/aws/multi_region/primary/vpc.tf b/aws/multi_region/primary/vpc.tf index 2baf711..133c952 100644 --- a/aws/multi_region/primary/vpc.tf +++ b/aws/multi_region/primary/vpc.tf @@ -1,25 +1,23 @@ resource "aws_vpc" "kasm-default-vpc" { - cidr_block = "10.0.0.0/16" + cidr_block = var.vpc_subnet_cidr + enable_dns_hostnames = true + enable_dns_support = true tags = { Name = "${var.project_name}-kasm-db-vpc" } } +data "aws_vpc" "data-kasm-default-vpc" { + id = aws_vpc.kasm-default-vpc.id +} + resource "aws_internet_gateway" "kasm-default-ig" { - vpc_id = "${aws_vpc.kasm-default-vpc.id}" + vpc_id = aws_vpc.kasm-default-vpc.id tags = { Name = "${var.project_name}-kasm-ig" } } -resource "aws_route" "internet_access" { - route_table_id = "${aws_vpc.kasm-default-vpc.main_route_table_id}" - destination_cidr_block = "0.0.0.0/0" - gateway_id = "${aws_internet_gateway.kasm-default-ig.id}" +data "aws_internet_gateway" "data-kasm_default_ig" { + internet_gateway_id = aws_internet_gateway.kasm-default-ig.id } - - -output "primary_vpc_id" { - value = "${aws_vpc.kasm-default-vpc.id}" -} - diff --git a/aws/multi_region/primary/webapps.tf b/aws/multi_region/primary/webapps.tf deleted file mode 100644 index 81e08d2..0000000 --- a/aws/multi_region/primary/webapps.tf +++ /dev/null @@ -1,27 +0,0 @@ -module "primary-webapps" { - source = "../webapps" - primary_aws_region = "${var.aws_region}" - faux_aws_region = "${var.aws_region}" - zone_name = "${var.zone_name}" - num_agents = "${var.num_agents}" - agent_instance_type = "${var.agent_instance_type}" - num_webapps = "${var.num_webapps}" - webapp_instance_type = "${var.webapp_instance_type}" - ec2_ami = "${var.ec2_ami}" - webapp_subnet_id_1 = "${aws_subnet.kasm-webapp-subnet-1.id}" - webapp_subnet_id_2 = "${aws_subnet.kasm-webapp-subnet-2.id}" - agent_subnet_id = "${aws_subnet.kasm-agent-subnet.id}" - aws_access_key = "${var.aws_access_key}" - aws_secret_key = "${var.aws_secret_key}" - aws_domain_name = "${var.aws_domain_name}" - project_name = "${var.project_name}" - kasm_build = "${var.kasm_build}" - database_password = "${var.database_password}" - redis_password = "${var.redis_password}" - manager_token = "${var.manager_token}" - aws_key_pair = "${var.aws_key_pair}" - kasm_db_ip = "${aws_instance.kasm-db.private_ip}" - primary_vpc_id = "${aws_vpc.kasm-default-vpc.id}" - certificate_arn = "${aws_acm_certificate_validation.kasm-elb-certificate-validation.certificate_arn}" - ssh_access_cidr = "${var.ssh_access_cidr}" -} \ No newline at end of file diff --git a/aws/multi_region/provider.tf b/aws/multi_region/provider.tf new file mode 100644 index 0000000..041dd35 --- /dev/null +++ b/aws/multi_region/provider.tf @@ -0,0 +1,49 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + #version = "4.56.0" + } + } +} + +provider "aws" { + access_key = var.aws_access_key + secret_key = var.aws_secret_key + region = var.aws_primary_region + + default_tags { + tags = var.aws_default_tags + } +} + +provider "aws" { + access_key = var.aws_access_key + secret_key = var.aws_secret_key + region = var.secondary_regions_settings.region2.agent_region + alias = "region2" + + default_tags { + tags = var.aws_default_tags + } +} + +############################################################################## +### +### Uncomment the below provider section if you want to deploy a 3rd region. +### +### Copy/paste the provider below to deploy additional regions, then refer +### to the README.md, the deployment.tf file, and the settings.tfvars file for +### code blocks to copy/paste/configure to deploy the new regions. +### +############################################################################## +# provider "aws" { +# access_key = var.aws_access_key +# secret_key = var.aws_secret_key +# region = var.secondary_regions_settings.region3.agent_region +# alias = "region3" + +# default_tags { +# tags = var.aws_default_tags +# } +# } diff --git a/aws/multi_region/settings.tfvars b/aws/multi_region/settings.tfvars new file mode 100644 index 0000000..1dd8776 --- /dev/null +++ b/aws/multi_region/settings.tfvars @@ -0,0 +1,62 @@ +aws_domain_name = "kasm.contoso.com" +project_name = "contoso" +aws_key_pair = "" +aws_primary_region = "us-east-1" +primary_vpc_subnet_cidr = "10.0.0.0/16" + +database_password = "changeme" +redis_password = "changeme" +user_password = "changeme" +admin_password = "changeme" +manager_token = "changeme" + +kasm_build = "https://kasm-static-content.s3.amazonaws.com/kasm_release_1.12.0.d4fd8a.tar.gz" +ssh_access_cidrs = ["0.0.0.0/0"] +web_access_cidrs = ["0.0.0.0/0"] + +swap_size = 2048 +primary_region_ec2_ami_id = "ami-09cd747c78a9add63" +webapp_instance_type = "t3.small" +db_instance_type = "t3.small" +agent_instance_type = "t3.medium" +webapp_hdd_size_gb = 40 +db_hdd_size_gb = 40 +agent_hdd_size_gb = 40 + +## Settings for all additional Agent regions +secondary_regions_settings = { + region2 = { + agent_region = "us-west-1" + agent_ec2_ami_id = "ami-0d221cb540e0015f4" + agent_instance_type = "t3.medium" + agent_hdd_size_gb = 120 + num_agents = 2 + agent_vpc_cidr = "10.1.0.0/16" + } + + ####################################################################### + ### + ### Uncomment and update the settings below for an third region. + ### Copy/paste the settings below (changing the region number) for any + ### additional regions. + ### + ### Make sure to add a provider section for each additional region in + ### the providers.tf file. + ### + ####################################################################### + # region3 = { + # agent_region = "eu-central-1" + # agent_ec2_ami_id = "ami-0e067cc8a2b58de59" + # agent_instance_type = "t3.medium" + # num_agents = 2 + # agent_vpc_cidr = "10.2.0.0/16" + # } +} + +## Default tags for all AWS resources +aws_default_tags = { + Deployed_by = "Terraform" + Deployment_type = "Multi-Region" + Service_name = "Kasm Workspaces" + Kasm_version = "1.12" +} diff --git a/aws/multi_region/userdata/agent_bootstrap.sh b/aws/multi_region/userdata/agent_bootstrap.sh new file mode 100644 index 0000000..ca26186 --- /dev/null +++ b/aws/multi_region/userdata/agent_bootstrap.sh @@ -0,0 +1,29 @@ +#!/bin/bash +set -ex +echo "Starting Kasm Workspaces Agent Install" + +/bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=${swap_size} +/sbin/mkswap /var/swap.1 +chmod 600 /var/swap.1 +/sbin/swapon /var/swap.1 + +echo '/var/swap.1 swap swap defaults 0 0' | tee -a /etc/fstab + +cd /tmp + +PRIVATE_IP=(`hostname -I | cut -d' ' -f1 | tr -d '\\n'`) + +wget ${kasm_build_url} -O kasm_workspaces.tar.gz +tar -xf kasm_workspaces.tar.gz + +echo "Waiting for Kasm WebApp availability..." +while ! (curl -k https://${manager_address}/api/__healthcheck 2>/dev/null | grep -q true) +do + echo "Waiting for API server..." + sleep 5 +done +echo "WebApp is alive" + +bash kasm_release/install.sh -S agent -e -p $PRIVATE_IP -m ${manager_address} -M ${manager_token} + +echo "Done" diff --git a/aws/multi_region/userdata/db_bootstrap.sh b/aws/multi_region/userdata/db_bootstrap.sh new file mode 100644 index 0000000..ac7b403 --- /dev/null +++ b/aws/multi_region/userdata/db_bootstrap.sh @@ -0,0 +1,20 @@ +#!/bin/bash +set -ex +echo "Starting Kasm Workspaces Install" + +/bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=${swap_size} +/sbin/mkswap /var/swap.1 +chmod 600 /var/swap.1 +/sbin/swapon /var/swap.1 + +echo '/var/swap.1 swap swap defaults 0 0' | tee -a /etc/fstab + +cd /tmp + +PRIVATE_IP=(`hostname -I | cut -d ' ' -f1 | tr -d '\\n'`) + +wget ${kasm_build_url} -O kasm_workspaces.tar.gz +tar -xf kasm_workspaces.tar.gz +bash kasm_release/install.sh -S db -e -Q ${database_password} -R ${redis_password} -U ${user_password} -P ${admin_password} -M ${manager_token} + +echo "Done" diff --git a/aws/multi_region/userdata/webapp_bootstrap.sh b/aws/multi_region/userdata/webapp_bootstrap.sh new file mode 100644 index 0000000..5f781f5 --- /dev/null +++ b/aws/multi_region/userdata/webapp_bootstrap.sh @@ -0,0 +1,36 @@ +#!/bin/bash +set -ex +echo "Starting Kasm Workspaces Install" + +/bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=${swap_size} +/sbin/mkswap /var/swap.1 +chmod 600 /var/swap.1 +/sbin/swapon /var/swap.1 + +echo '/var/swap.1 swap swap defaults 0 0' | tee -a /etc/fstab + +cd /tmp + +PRIVATE_IP=(`hostname -I | cut -d ' ' -f1 | tr -d '\\n'`) + +wget ${kasm_build_url} -O kasm_workspaces.tar.gz +tar -xf kasm_workspaces.tar.gz + +echo "Checking for Kasm DB and Redis..." +apt-get update && apt-get install -y netcat +while ! nc -w 1 -z ${db_ip} 5432; do + echo "Database not ready..." + sleep 5 +done +echo "DB is alive" + +while ! nc -w 1 -z ${db_ip} 6379; do + echo "Redis not ready..." + sleep 5 +done +echo "Redis is alive" + + +bash kasm_release/install.sh -S app -e -z ${zone_name} -q "${db_ip}" -Q ${database_password} -R ${redis_password} + +echo "Done" diff --git a/aws/multi_region/variables.tf b/aws/multi_region/variables.tf index faf5d67..0d3c352 100644 --- a/aws/multi_region/variables.tf +++ b/aws/multi_region/variables.tf @@ -1,47 +1,297 @@ -variable "aws_domain_name" { - default = "kasm.contoso.com" -} - -variable "project_name" { - default = "contoso" -} - -variable "aws_key_pair" { - default = "" -} - variable "aws_access_key" { - default = "" + description = "The AWS access key used for deployment" + type = string + sensitive = true + + validation { + condition = can(regex("^([A-Z0-9]{20})", var.aws_access_key)) + error_message = "The aws_access_key variable must be a valid AWS Access Key (e.g. AKIAJSIE27KKMHXI3BJQ)." + } } variable "aws_secret_key" { - default = "" + description = "The AWS secret key used for deployment" + type = string + sensitive = true + + validation { + condition = can(regex("^([a-zA-Z0-9+\\/-]{40})", var.aws_secret_key)) + error_message = "The aws_secret_key variable must be a valid AWS Secret Key value (e.g. wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY)" + } +} + +variable "aws_key_pair" { + description = "The name of an aws keypair to use." + type = string + + validation { + condition = can(regex("^[a-zA-Z0-9-_]{4,15}", var.aws_key_pair)) + error_message = "The aws_key_pair variable contains invalid characters. Allowed values are between 4-15 characters consisting of letters, numbers, and dashes (-)." + } +} + +variable "project_name" { + description = "The name of the deployment (e.g dev, staging). A short single word" + type = string + + validation { + condition = can(regex("^[a-z]{4,15}", var.project_name)) + error_message = "The project_name variable can only be one word between 4 and 15 lower-case letters since it is a seed value in multiple object names." + } +} + +variable "aws_domain_name" { + description = "The Route53 Zone used for the dns entries. This must already exist in the AWS account. (e.g dev.kasm.contoso.com). The deployment will be accessed via this zone name via https" + type = string + + validation { + condition = can(regex("(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]", var.aws_domain_name)) + error_message = "There are invalid characters in the aws_domain_name - it must be a valid domain name." + } +} + +variable "primary_vpc_subnet_cidr" { + description = "The subnet CIDR to use for the VPC" + type = string + default = "10.0.0.0/16" + + validation { + condition = can(cidrhost(var.primary_vpc_subnet_cidr, 0)) + error_message = "The VPC subnet must be valid IPv4 CIDR." + } +} + +variable "num_agents" { + description = "The number of Agent Role Servers to create in the deployment" + type = number + default = 2 + + validation { + condition = var.num_agents >= 0 && var.num_agents <= 100 && floor(var.num_agents) == var.num_agents + error_message = "Acceptable number of Kasm Agents range between 0-100." + } +} + +variable "num_webapps" { + description = "The number of WebApp role servers to create in the deployment" + type = number + default = 2 + + validation { + condition = var.num_webapps >= 1 && var.num_webapps <= 3 && floor(var.num_webapps) == var.num_webapps + error_message = "Acceptable number of webapps range between 1-3." + } +} + +variable "webapp_instance_type" { + description = "The instance type for the webapps" + type = string + default = "t3.small" + + validation { + condition = can(regex("^(([a-z-]{1,3})(\\d{1,2})?(\\w{1,4})?)\\.(nano|micro|small|medium|metal|large|(2|3|4|6|8|9|10|12|16|18|24|32|48|56|112)?xlarge)", var.webapp_instance_type)) + error_message = "Check the webapp_instance_type variable and ensure it is a valid AWS Instance type (https://aws.amazon.com/ec2/instance-types/)." + } +} + +variable "db_instance_type" { + description = "The instance type for the Database" + type = string + default = "t3.small" + + validation { + condition = can(regex("^(([a-z-]{1,3})(\\d{1,2})?(\\w{1,4})?)\\.(nano|micro|small|medium|metal|large|(2|3|4|6|8|9|10|12|16|18|24|32|48|56|112)?xlarge)", var.db_instance_type)) + error_message = "Check the db_instance_type variable and ensure it is a valid AWS Instance type (https://aws.amazon.com/ec2/instance-types/)." + } +} + +variable "agent_instance_type" { + description = "The instance type for the Agents" + type = string + default = "t3.medium" + + validation { + condition = can(regex("^(([a-z-]{1,3})(\\d{1,2})?(\\w{1,4})?)\\.(nano|micro|small|medium|metal|large|(2|3|4|6|8|9|10|12|16|18|24|32|48|56|112)?xlarge)", var.agent_instance_type)) + error_message = "Check the agent_instance_type variable and ensure it is a valid AWS Instance type (https://aws.amazon.com/ec2/instance-types/)." + } +} + +variable "webapp_hdd_size_gb" { + description = "The HDD size in GB to configure for the Kasm WebApp instances" + type = number + + validation { + condition = can(var.webapp_hdd_size_gb >= 40) + error_message = "Kasm Webapps should have at least a 40 GB HDD to ensure enough space for Kasm services." + } +} + +variable "db_hdd_size_gb" { + description = "The HDD size in GB to configure for the Kasm Database instances" + type = number + + validation { + condition = can(var.db_hdd_size_gb >= 40) + error_message = "Kasm Database should have at least a 40 GB HDD to ensure enough space for Kasm services." + } +} + +variable "agent_hdd_size_gb" { + description = "The HDD size in GB to configure for the Kasm Agent instances" + type = number + + validation { + condition = can(var.agent_hdd_size_gb >= 120) + error_message = "Kasm Agents should have at least a 120 GB HDD to ensure enough space for Kasm services." + } +} + +variable "primary_region_ec2_ami_id" { + description = "AMI Id of Kasm EC2 image in the primary region. Recommended AMI OS Version is Ubuntu 20.04 LTS." + type = string + default = "ami-09cd747c78a9add63" + + validation { + condition = can(regex("^(ami-[a-f0-9]{17})", var.primary_region_ec2_ami_id)) + error_message = "Please verify that your AMI is in the correct format for AWS (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/finding-an-ami.html)." + } +} + +variable "secondary_regions_settings" { + description = "Map of Kasm settings for secondary regions" + type = map(any) + + validation { + condition = can([for region in var.secondary_regions_settings : regex("^([a-z]{2}-[a-z]{4,}-[\\d]{1})$", region.agent_region)]) + error_message = "Verify the regions in the secondary_regions_settings variable and ensure they are valid AWS regions in a valid format (e.g. us-east-1)." + } + validation { + condition = can([for ami_id in var.secondary_regions_settings : regex("^(ami-[a-f0-9]{17})", ami_id.agent_ec2_ami_id)]) + error_message = "Please verify that all of your Region's AMI IDs are in the correct format for AWS (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/finding-an-ami.html)." + } + validation { + condition = can([for instance_type in var.secondary_regions_settings : regex("^(([a-z-]{1,3})(\\d{1,2})?(\\w{1,4})?)\\.(nano|micro|small|medium|metal|large|(2|3|4|6|8|9|10|12|16|18|24|32|48|56|112)?xlarge)", instance_type.agent_instance_type)]) + error_message = "Check the Instance types used in your secondary_regions_settings and ensure they are valid AWS Instance types (https://aws.amazon.com/ec2/instance-types/)." + } + validation { + condition = can([for number_of_agents in var.secondary_regions_settings : number_of_agents.num_agents >= 0 && number_of_agents.num_agents <= 100 && floor(number_of_agents.num_agents) == number_of_agents.num_agents]) + error_message = "Check the number of agents in the secondary_regions_settings variable. Acceptable number of Kasm Agents range between 0-100." + } + validation { + condition = can([for subnet in var.secondary_regions_settings : cidrhost(subnet.agent_vpc_cidr, 0)]) + error_message = "Verify the VPC subnet in your secondary_regions_settings. They must all be valid IPv4 CIDRs." + } +} + +variable "aws_primary_region" { + description = "The AWS Region used for deployment" + type = string + default = "us-east-1" + + validation { + condition = can(regex("^([a-z]{2}-[a-z]{4,}-[\\d]{1})$", var.aws_primary_region)) + error_message = "The aws_primary_region must be a valid Amazon Web Services (AWS) Region name, e.g. us-east-1" + } +} + +variable "swap_size" { + description = "The amount of swap (in MB) to configure inside the compute instances" + type = number + + validation { + condition = var.swap_size >= 1024 && var.swap_size <= 8192 && floor(var.swap_size) == var.swap_size + error_message = "Swap size is the amount of disk space to use for Kasm in MB and must be an integer between 1024 and 8192." + } } variable "database_password" { - default = "changeme" + description = "The password for the database. No special characters" + type = string + sensitive = true + + validation { + condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.database_password)) + error_message = "The Database Password should be a string between 12 and 30 letters and numbers with no special characters." + } } variable "redis_password" { - default = "changeme" + description = "The password for the Redis server. No special characters" + type = string + sensitive = true + + validation { + condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.redis_password)) + error_message = "The Redis Password should be a string between 12 and 30 letters and numbers with no special characters." + } } variable "user_password" { - default = "changeme" + description = "The standard (non administrator) user password. No special characters" + type = string + sensitive = true + + validation { + condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.user_password)) + error_message = "The User Password should be a string between 12 and 30 letters and numbers with no special characters." + } } variable "admin_password" { - default = "changeme" + description = "The administrative user password. No special characters" + type = string + sensitive = true + + validation { + condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.admin_password)) + error_message = "The Admin password should be a string between 12 and 30 letters and numbers with no special characters." + } } variable "manager_token" { - default = "changeme" + description = "The manager token value for Agents to authenticate to webapps. No special characters" + type = string + sensitive = true + + validation { + condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.manager_token)) + error_message = "The Manager Token should be a string between 12 and 30 letters and numbers with no special characters." + } } +variable "ssh_access_cidrs" { + description = "CIDR notation of the bastion host allowed to SSH in to the machines" + type = list(string) + default = ["0.0.0.0/0"] + + validation { + condition = can([for subnet in var.ssh_access_cidrs : cidrhost(subnet, 0)]) + error_message = "One of the subnets provided in the ssh_access_cidr variable is invalid." + } +} + +variable "web_access_cidrs" { + description = "CIDR notation of the bastion host allowed to SSH in to the machines" + type = list(string) + default = ["0.0.0.0/0"] + + validation { + condition = can([for subnet in var.web_access_cidrs : cidrhost(subnet, 0)]) + error_message = "One of the subnets provided in the web_access_cidrs variable is invalid." + } +} + +## Non-validated variables variable "kasm_build" { - default = "https://kasm-static-content.s3.amazonaws.com/kasm_release_1.9.0.077388.tar.gz" + description = "Download URL for Kasm Workspaces" + type = string } -variable "ssh_access_cidr" { - default = "0.0.0.0/0" +variable "aws_default_tags" { + description = "Default tags to apply to all AWS resources for this deployment" + type = map(any) + default = { + Service_name = "Kasm Workspaces" + Kasm_version = "1.12" + } } diff --git a/aws/multi_region/webapps/agent.tf b/aws/multi_region/webapps/agent.tf index d833ac9..299f515 100644 --- a/aws/multi_region/webapps/agent.tf +++ b/aws/multi_region/webapps/agent.tf @@ -1,29 +1,25 @@ resource "aws_instance" "kasm-agent" { - count = "${var.num_agents}" - ami = "${var.ec2_ami}" - instance_type = "${var.agent_instance_type}" - vpc_security_group_ids = ["${aws_security_group.kasm-agent-sg.id}"] - subnet_id = "${var.webapp_subnet_id_1}" - key_name = "${var.aws_key_pair}" + count = var.num_agents + ami = var.ec2_ami + instance_type = var.agent_instance_type + vpc_security_group_ids = [var.agent_security_group_id] + subnet_id = var.agent_subnet_id + key_name = var.aws_key_pair root_block_device { - volume_size = "50" + volume_size = var.agent_hdd_size_gb } - user_data = <<-EOF - #!/bin/bash - fallocate -l 4g /mnt/kasm.swap - chmod 600 /mnt/kasm.swap - mkswap /mnt/kasm.swap - swapon /mnt/kasm.swap - echo '/mnt/kasm.swap swap swap defaults 0 0' | tee -a /etc/fstab - cd /tmp - wget ${var.kasm_build} - tar xvf kasm_*.tar.gz - PUBLIC_DNS=(`curl -s http://169.254.169.254/latest/meta-data/public-ipv4`) - bash kasm_release/install.sh -S agent -e -p $PUBLIC_DNS -m ${var.zone_name}-lb.${var.aws_domain_name} -M ${var.manager_token} - EOF + user_data = templatefile("${path.module}/../userdata/agent_bootstrap.sh", + { + kasm_build_url = var.kasm_build + swap_size = var.swap_size + manager_address = var.aws_domain_name + manager_token = var.manager_token + } + ) + tags = { Name = "${var.project_name}-${var.zone_name}-kasm-agent" } -} \ No newline at end of file +} diff --git a/aws/multi_region/webapps/availability_zones.tf b/aws/multi_region/webapps/availability_zones.tf new file mode 100644 index 0000000..87d8f48 --- /dev/null +++ b/aws/multi_region/webapps/availability_zones.tf @@ -0,0 +1,3 @@ +data "aws_availability_zones" "available" { + state = "available" +} diff --git a/aws/multi_region/webapps/elb.tf b/aws/multi_region/webapps/elb.tf index 9471d40..994e22a 100644 --- a/aws/multi_region/webapps/elb.tf +++ b/aws/multi_region/webapps/elb.tf @@ -1,150 +1,103 @@ -resource "aws_security_group" "kasm-default-elb-sg" { - name = "${var.project_name}-${var.zone_name}-kasm-allow-elb-access" - description = "Security Group for ELB" - vpc_id = "${var.primary_vpc_id}" - - ingress { - from_port = 443 - to_port = 443 - protocol = "tcp" - cidr_blocks = ["0.0.0.0/0"] - } - - ingress { - from_port = 80 - to_port = 80 - protocol = "tcp" - cidr_blocks = ["0.0.0.0/0"] - } - - egress { - from_port = 0 - to_port = 0 - protocol = "-1" - cidr_blocks = ["0.0.0.0/0"] - } - - tags = { - Name = "${var.project_name}-${var.zone_name}-kasm-allow-access" - } +data "aws_route53_zone" "kasm-route53-zone" { + name = var.aws_domain_name + private_zone = false } -resource "aws_s3_bucket" "kasm-s3-logs" { - bucket_prefix = "${var.project_name}-${var.zone_name}-" - acl = "private" - force_destroy = true - -} - -resource "aws_s3_bucket_policy" "kasm-s3-logs-policy" { - bucket = aws_s3_bucket.kasm-s3-logs.id - - policy = < ***NOTE:*** This document assumes you are using a separate file named `secrets.tfvars` for the AWS credentials generated in the [AWS API Keys](#aws-api-keys) section above. The .gitignore file in this repository will ignore any files named `secrets.tfvars` since they are expected to have sensitive values in them. This will prevent you from accidentally committing them to source control. 3. Verify the configuration - terraform plan + terraform plan -var-file settings.tfvars -var-file secrets.tfvars 4. Deploy - terraform apply - + terraform apply -var-file settings.tfvars -var-file secrets.tfvars 5. Login to the Deployment as an Admin via the domain defined e.g `https://kasm.contoso.com` 6. Navigate to the Agents tab, and enable each Agent after it checks in. (May take a few minutes) +# AWS Terraform Variable definitions + +| Variable | Description | Variable type | Example | +|:--------:|-------------|---------------|---------| +| `aws_access_key` | The AWS access key used for deployment. | String | `"AKIAJSIE27KKMHXI3BJQ"` | +| `aws_secret_key` | The AWS secret key used for deployment. | String | `"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"` | +| `aws_region` | The AWS Region used for deployment. | String | `"us-east-1"` | +| `project_name` | The name of the deployment (e.g dev, staging). A short single word of up to 15 characters. | String | `"kasm"` | +| `aws_domain_name` | The Route53 Zone used for the dns entries. This must already exist in the AWS account. (e.g dev.kasm.contoso.com). The deployment will be accessed via this zone name via https. | String | `"kasm.contoso.com"` | +| `kasm_zone_name` | A name given to the kasm deployment Zone. | String | `"default"` | +| `vpc_subnet_cidr` | The subnet CIDR to use for the VPC | String | `"10.0.0.0/16"` | +| `aws_key_pair` | The name of an aws keypair to use. | String | `"kasm_ssh_key"` | +| `ec2_ami` | The AMI used for the EC2 nodes. Recommended Ubuntu 20.04 LTS. | String | `"ami-09cd747c78a9add63"` | +| `swap_size` | The amount of swap (in MB) to configure inside the Kasm servers. | Number | `2048` | +| `webapp_instance_type` | The instance type for the webapps. | String | `"t3.small"` | +| `db_instance_type` | The instance type for the webapps. | String | `"t3.medium"` | +| `agent_instance_type` | The instance type for the webapps. | String | `"t3.medium"` | +| `guac_instance_type` | The instance type for the webapps. | String | `"t3.medium"` | +| `num_webapps` | The number of WebApp role servers to create in this deployment. Acceptable ranges from 1-3. | Number | `2` | +| `num_agents` | The number of static Kasm Agents to create in this deploymenbt. Acceptable ranges from 0-100. | Number | `2` | +| `num_guac_rdp_nodes` | The number of Guacamole RDP access servers to create in this deployment. Acceptable ranges from 0-100. | Number | `1` | +| `allow_ssh_cidrs` | A list of subnets in CIDR notation allowed to SSH into your kasm servers | List(String) | `["10.0.0.0/16","172.217.22.14/32"]` | +| `web_access_cidrs` | A list of subnets in CIDR notation allowed Web access to your kasm servers | List(String) | `["0.0.0.0/0"]` | +| `database_password` | The Kasm PostgreSQL database password. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` | +| `redis_password` | The Kasm Redis password. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` | +| `admin_password` | The Kasm Administrative user login password. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` | +| `user_password` | A Kasm standard (non-administrator) user password. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` | +| `manager_token` | The manager token value used by Kasm agents to authenticate to the Kasm WebApps. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` | +| `service_registration_token` | The service registration token value used by Guac RDP servers to authenticate to the Kasm Webapps. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` | +| `kasm_build` | The download URL for the desired Kasm Workspaces version. | String | `"https://kasm-static-content.s3.amazonaws.com/kasm_release_1.12.0.d4fd8a.tar.gz"` | +| `aws_default_tags` | A Map of all tags you wish to apply to all TF created resources in this deployment. | Map(Any) |
{
  Service_name = "Kasm Workspaces"
  Kasm_version = "1.12"
}
| + + +# Detailed Terraform Deployment Diagram + +![Detailed Diagram][Detailed_Diagram] + +[Detailed_Diagram]: ./diagram/aws_multi_server.png "Detailed Diagram" \ No newline at end of file diff --git a/aws/standard/deployment.tf b/aws/standard/deployment.tf index 3d1000f..b3c978f 100644 --- a/aws/standard/deployment.tf +++ b/aws/standard/deployment.tf @@ -1,30 +1,30 @@ module "standard" { - source = "./module" - aws_access_key = "" - aws_secret_key = "" - aws_key_pair = "" - aws_region = "us-east-1" - aws_domain_name = "kasm.contoso.com" - project_name = "contoso" - num_agents = "2" - num_webapps = "2" + source = "./module" + aws_key_pair = var.aws_key_pair + aws_region = var.aws_region + aws_domain_name = var.aws_domain_name + project_name = var.project_name + num_agents = var.num_agents + num_webapps = var.num_webapps + num_guac_nodes = var.num_guac_nodes + vpc_subnet_cidr = var.vpc_subnet_cidr + ## Kasm Server settings + agent_instance_type = var.agent_instance_type + guac_instance_type = var.guac_instance_type + webapp_instance_type = var.webapp_instance_type + db_instance_type = var.db_instance_type + ec2_ami = var.ec2_ami + swap_size = var.swap_size - - agent_instance_type = "t3.medium" - webapp_instance_type = "t3.small" - db_instance_type = "t3.small" - ec2_ami = "ami-0747bdcabd34c712a" - - - ssh_access_cidr = "0.0.0.0/0" - database_password = "changeme" - redis_password = "changeme" - user_password = "changeme" - admin_password = "changeme" - manager_token = "changeme" - zone_name = "default" - kasm_build = "https://kasm-static-content.s3.amazonaws.com/kasm_release_1.9.0.077388.tar.gz" + ssh_access_cidrs = var.ssh_access_cidrs + web_access_cidrs = var.web_access_cidrs + database_password = var.database_password + redis_password = var.redis_password + user_password = var.user_password + admin_password = var.admin_password + manager_token = var.manager_token + service_registration_token = var.service_registration_token + kasm_zone_name = var.kasm_zone_name + kasm_build = var.kasm_build } - - diff --git a/aws/standard/diagram/aws_multi_server.drawio b/aws/standard/diagram/aws_multi_server.drawio new file mode 100644 index 0000000..1edf218 --- /dev/null +++ b/aws/standard/diagram/aws_multi_server.drawio @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/aws/standard/diagram/aws_multi_server.png b/aws/standard/diagram/aws_multi_server.png new file mode 100644 index 0000000000000000000000000000000000000000..6098881c8c3ce284c4e1fc5d7b0d81636813ad37 GIT binary patch literal 149914 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

N<%(0?j$_? z4^soQl!ySzhv|V`wvk*2f1{d7hMNEKDg=1mI<_7_PWe( zN@x|6uKhpLgF1}HF_KHyQ9b(5OGFTk0LrA1Ghv7}3(mBrc#BFJd0TLkMy>W;`Bp|z zQOQ#0ukXE%-LWV_29gWuWbMp10%cqF>$%mg8K?ebw(l6cyhQF=bd{Xlv?)f9?CzmQ zb^<(tHCWDTEqiKshCG>VVe4Gtt8Pb0g0UKdjxQAR1(IxvJ(C(D{nd*uk+HM49eA1 z&Xas4rvA1bd@XIN$u_qep+jELh29-5VH!pJ7A)oUMt0Ao3z=M8pV#~`m;weG+TS|Z z%1b*~<9u1bv?nBdFlnFAFM0QrsDL_1V3ndobIcFUdp@d5L-YuW&^0|BeNUH)7gTR7 z`D3geTVmv1lH=#_Pgfh79kJoXP6`ogYqkYx-xF-sO}olz1)2Y+7)`88inLH2pE+I8 zZj(51>I|w=9fp3R2nDku=#7FjZQ;q#=(VWALsq-_g!PJ^&VfEhsZNT zx6#(Fu9uWs0GqR;v)l3Rs!6nqw+r48%`S`Bk-tqCp6alEUwPeq6Nw*Zv5bWGV{%Gg z{Ig?8G!!}xF#t5(WLLqYNT9DSzkoohf~9(fsP$zmt{lO*&q;d^@Wyc9>;X!gU%5Uq zSppfHr6AHDZpXEOS|{%9rKS*$e^)6|YHRv(*{Pss!Oh;$?Ok0Hjd`gHmQ!tZ1arQX z=bj5`z)#s~rKVO(3;2JM!SKIHhQ((>t86VZ`;SAL8hI=4Yarf!dRve#T*rUR>uO(U zilg#gW7uJ@m!I?;yk`UPJnWLHBQ_e)O5d^IiDbJO>IAGm7P)#Y?BJQag?@Wrq_pKI z%XC2?emGSMVO~q6^$Lv+cwIQPxtAsxSlBi}Y_3-=#y3CbIqDRs-^VsCzWKNq?cuo) z3p%b zNfw#a+5ZagNKcZwp>q*$IxjB0?o|g9vDyQejb9?yuJxXRmxB$TF3it-g3%jyzzm6t z!L62KtUugP{3Q9?@cLhceVf){q)N%6Yof&JLX)y*#`tG$4=9O+%Q1(T>UPtPPm-SH zwg6RfZvo|B7;ujm`HPmXjB>V#c;F@&HOC!!4gi8K;i*a+fV=oi*PKt4h94JacXBh9 zz7(bgnL$1xUVs(PgGECdpOU5;buc18aMANln1`c@57qDTqe)4I`$JF8B7Y;WXF;EQ z3zjC|s9snL2B4C9K-d$Tb998EePo|pD$qqs?Z12~G=Xxn8q17hTVPy#s0RzmnRCVP zW@bSm4S@2<7MN-{A%LHHEc4NNe1dPj{-A!RM#-%hBHEz#&6HPh4FCH}v|dWtikYC0 zfCGn(t$S68cT?1*MWGD&jZ>a@B3)ugDRPc=|6Xt%E zxm?g-)8Ov!j{-|ic2mOJL{;!WHwhTF?Q!6&Gq)`f+{}b!V5(S|pM!~h8cU}5B%ZkS zpy$HC3nK;nZ&FzY{jst9U>vTl&1xw#WRj~ZvB?x%b#)G_riNDTVAs|itbd!VmFI;{ z*n?+a@|oH&3aa_3nE|a6mIlsW?IyCl2s18Re=`nJSc$~9rpTct5UaiV8x0^%W57M~ zxoKNrZ<9-C183*N?Ba8(6nvbh4AllyUbuoG8S9j|<$XAs%_L0emnZRbH3~Y#Mq}BP z4#>{UJ;YTla5}W$*)b)2{pp^*$W~DMJSik9no-pr@2{{5Q?h(I3ASy%k0;v>t%&Vh z48>t)h!!wx3~t;=o@4h77`+NvO=8Z^D#G|nZWEO?LLI@RSj)EhtKPrso2Hpqf(+IV zr{>@$vsnVj>Z-K^FPg9WJ#B#%XY)Sv0!EV}d3n(eV51vI3?2WkC4{3f5ZICaXIBOe zyyjW7tB*jL?L-6H4sgkhE*?)kqkid-pgfSvu9_$Fn0^k)+-3>{#e9ykoZN)s{2Gfc zg=1X!-8^2KOZPwWKJW7Ca0;qUC=6FO$z}ABi7Hi*gufESvXu@wRwQd>nqNY zL`?Ws@*KY&N^X(eqJt%2lpP87_oY2H2dJ;u`n-|Ryky^>={iw7mRgRN%92|p%&GPY zl;>EDDZHLxUWeRIVn%QrA3>hCqtgxT%wd-1v3m(>fc4$`g@mGLovr1s&IZ=B<{>P* z2J3c5Qj3n8I?uEJrQZNOe!{#(H5MX;;lXUqsGY$|_>@3H=ZZX^2^fYvlWcL_yBN`4 z_HLs5<6?jnpf0wqK_aO_&PJf{7|7=e8zf>i2GwAgc3F(j$W*vxe$ zv1*80R>L=}5{;q?o`Pzdq}Ax}`In+5xzMYqI{~J_-WK*>b#6!)QXAt4+wk=z+>*_D zjFug7W?{0H+ZZKKgFDQR-6gCgLXsl6(ixmW2G}snfWATIBN|M_`6Bv$3J}2+iiwxX zlr8e zvrlvfJaxtg1I*a4Ah`040bcYZ7F)u*4H&`Q^=zj!A+*CHj4ewtlkT?#ytU#O+Ax1$ z%^6_y?fPU~Lat{C4|#?1+pj;sIK#Jq1Q%n_6V1(3_P(7f%V~9_SxFum(YZ+kNy;+Y z-9fM0g)%K0Nd6$RMTfPn_7NMP_KJMOuYw)!kQx@V$Hrm>%4M9t^+Vvp9u-bS%V3NN z5bFfCFkjDzn49}0jIq1p6V=zbV3f6sb0tXCui|9#=ZPn89;>l{s-G9P;P839u*a9H z^(KZoW_;(OQZ^m#Ow3n)qE&|~d(z?6*_d2M`Z#C708Km91e2e%_b}imlk}$>FFvcd zn~uJGal=xDmC}`-tNh%G{cn9_J(J3sRS7|^9B7L}gh9+t_Wq6e7Tkxr0(jTRrMy?@ z&vxYX@O`8OuwCK(JvmbBl}L@-F$HlAP#k^2a@1`#LRh=`0ZM{V0@dH$$Nro?l2 z;*;2?o{JxJZb;(0H(|M655|jfyrSo%hu{n4SQ0_`#o-r~s3tFKE*wDecXX{wnbhRH z-#9Bxf0@UE)Y9L_<0Jh~@>=j|3< zTaB3~_H@in=WH2To(1Knq64-#9I@CL{9%>PoEu5?9?_ZIFw8>by=eF8Q{{1ioqvYO z{!$cxP@y34X^R0mW|H>C?NZRX1vQJvZ9!<%0FVGwp>Ng62_Vk~)!lD^cKQ*LM`?Q( z$beP@a6Q*okD2NO-*eEw)5NJwR*Z4Es&l0|oYKHvuKDZ8sAN`XDKAHQC9n7DEC-y} z!t)$GtCsWL2tn;rnH7h!`Q6V|!!%h8QIogh6uxeLe;dMS&{vf;zvP>6qP?R>cVc|m z_HDnx62eHww((khxvO^Ff_--)&!*_4V^|1wbzth&(xc0=0nlGq5it3fH z9eJO`I%F!~U>XtdY~tD{xaD5zk<9Z;ZyiC%vI9#H+R>SGtypK76R0I!8O*o<)lPL2 zLfrVebrBq8L-(v6_d~Srhf+>5ox{cZuCF?+!s?yMifG}4(CTR~Iugkr*LT-P1+gU_ zJc!I#jO0SJ^Q*_v7#(th@x5Io;JY z@uU)O3ijF2xlM{kO#2kPHsl+Z>>)v)*uv#Efk&&q#`^=qR|j*gzJE@6vR+($-KLxJ z1+56-sHwLp=lT0lvuM83hJoWB8DS)-j80OO=JV4nw;^q1pQXhS=uBZ@Y10Is-=tG@ zd*Ja#M4HzGfnd`w%eO_OGQTiLrG8?7J&}6jkLr4LBP^Up%D9sV`GZrFZ1{$+u=s7= z*@WUVE^0U&oUroSY8-XAwRF&yiGpmD_XwDYcQ6G>UAlZNIQ{%&8PTXFX^-vGn@6v| zRra9Gb*J~%LPft!8~8t4prCsplV=46q9<<09?hK7?BQa5Z9dx*obp*t`_*HN!&x=!kxo|=PA7DGP)aV{B}}t2QiEV4#}oos&c`2pyS*v z*HOj=ib_H7%9SD=3!cz4a;pT^OVAtlB#hJt84N0kW6c~_pTW&K3GS{m@A$yacGA!1 z;*}YbPTeY#|N6GxvySpvNEH7UGS1#Gaoxr(nm6J5I zQz!@H8H%T#@~KnR_(R6eUu2WcUpthvN*_!u_}EYsF7baJ{=gV)?nSuUl%H*QV*_(#PJ=P9w>&FM+LIZ7uqbg=t^QCb4?uTp2~ghinikkUeE&Ks|{w2$vH)_zW}0OEU1$Ix*uapWJ%6?Khm58?(mVPoDOYm6+0+ zoOyV7*r~kzYiV+5|5QKatN3M&)m6=f2oBjA9(;DcJkl<{Tq)>K#G3!L_tDJixBoxR z-ZCJ{cI_IbQ4kOmkX9N*5a|X15r)u_ZlnaHyGub@Y7l`ThmgFK;gTnEVCPHnQyd{oGpM&1yX&2`pwThXS=KY;2KZ5lfi{uOO^@wk0=LP6wQOT&5Y$cG=gPK(*t51we_+(H|9JeSc5iz3&NDcm@x1){j__ot&?{D; zHDg_aHbwa+$zm5&RGk)Y-)vUwMaBlZlSzAnCudtc140FA(2f+MFvK7I5156a=xaW+ zl54CFqOM+g1O?UFgHx}D5RAlNtb5lXZxMHo*;snSty11Rq#e5*EF^zUuVjEpPp;lwpJvqgizoV4Y;h6PF;wo*cNmp%gX zc0!3~%SSpkt+g{1IRTAOc`RHXaB4i1qhZQWU!z7amCjqd6J3o5M(Re-v_pbnmM$cY zsyE~vea8lGVBdKx7SaS=c1p4xFsNMEU{dOyIIDRg>H`7f3k!;25@i{E7A$n8sW*>{ zGAIPKS(*qF=|yu%tlGc~AkW(E@|_L>Mr?Y-2sm--Bd^^OhHE4*;@dT#02B z6C}%CL@52p=C_{hb5p+x7e|Zt2z&DbnaME4O+kv)>8pZsoCdG68`^HYJfr13&U`rw z7slJOepyOAukTM9cGd-tmlha2VD~s;`&oOnd#CmyLSw^g<48G8gJp@ms~cK^Bs?zt0>%L05$L-d zMIe0Cf`mHb&bw&*4puY7dIh>sYFiJgkG_qELD*0g7DZx zf-Kgt_5LlJ?Y;>8QpE)K(`za0$(IzNG)F=n=wBrPy%SE8Cv? zjve)eHuIvUE~nNWyXFLfIl68w1T{S9hNm0e7p2}t<$NPG87Sdv=jKz7d=azWSi_4q z)k`w-9+P$aX})tI47VyluQv(ik#Hmyb^R}l3;_G=4?oxmG*X^vFgHpH7z7D(VW2Q= z+h=0)t9}1`Z3I7Q78TdkPtp6QOQO&Y?MCU)CG|$Hq}CycXX#z^M_R|Dyy#DHbd?4D zA}I7~JN)Tb8+v(#RYt1AEO=2_SVI~!AE;|q96<=muKl>J|6Fu@*m(oqa4_4xox^G* z))d)IB9z44B=dAaKn{RPF-w ztuH{P)+U^^8-QDq+esoRsmn*M4d3D{>f4~qpMW1M2SKgq*#7%o4F+)Eas%BmaZWnoq(eX8N;tR>FaGC8Ii>suI-+->;u6bFKb4Z%wcK=5 z6Lf0@Z`s^qW;^ZNxBl+F-B~$tz;=o*d}0t(F*hYRPu=qZh6_2}VA>um-4?r7WVArT zPzsb!U4BnK@&AK6f(Og^NLLgy2=B4_1v>uG5UN?Jr=<|!yx;SEen)-Jy7Wcl;!m4s zcSUAW-aS`6J9PGyFHwSg($ma`WyZLugd*k>$$M-$XRFS8Y=G(VwpK<^Yr~=6<|?en zvYEmYyrP#mxowFVn^go()h_if)Dt`{jAwm()=&JX?Oa!vdfRM7 zuCSk`$t!F_TUrM_jYL6_?yz9d`xp=~Wc50aF2ajIKZxErM#>y@|Er?5pZFRYM0o;r z0)Lk^sYd^ZF*eYbVJWFS>;#6(avLwAn*eX-@KtT)#^xt`IaVmOWfNU?PF{Xz^>G^k zg!Sgvtox!J6kqQh!x>aEgTrNxpl?LZJR0)7d>q5p9~CV|1Z2@p1A5D8#a!Ph8yKc~ z>#XfpJoeYx)QIYx)AX)IgJ?d|NO<>0o;Yqm%+U;n&_l@vT1a`K1tituH^syTQ@b&p z5_>0`iJ5KlFdtPH0djCMCd{uQ<)${~1DXE77e2di#8`wvotX6W-fe)EvrPNb{klK3 zt#F?FTgZq&Wc><^0_dF;KfH25OoKPZ)jJLkvTI`6?$arq63_Y}_Oz@_!_Xj3M+pT( zzW^!+_vig&Dxki}u7&caBN17$1T&rI2Hl=9I1tOA+a?rn$26u%eP6^LJ_`76O=oKy zIZZ?Y^Bp4O8TGZ`;zJ?uhY}v*-yrS3$6Ep65e%1gdir%ekFPUqgN#b5j)O>~ ziXYXNMH7DI__;9(CO^!GR0|>J4H`n9=8Zo$LTk^sUR!{6*1(b_CgQIFByNEZI~yiP zl?}d5543*83LGv=>3{)+thBMn@~jOZtV^NTpATN;2?r}5&ogmxJ>QwuJqw5{?{&?c z3~>}Ff8eYElvyg;`Z=|3aW%YuZl_%YRt`rYxG|3&{`2?@stdMP|KXAy%J$>l$9+3~ zaoXf;gwH0g#_3Od+q?}nMYT4!-=eFLHk?_2Z@3%yC1$zihFYw~Ctn}$; zA2%*FP;?OJ<5X9ymm4xp3S?C*v4?Cz$De0C1_<=c_IdhW+sa0*Zu>|_pGC2b zY#TuDk0UDgEGyZObvV(s=iyPH+9$os`_Y14h1)1)<@rkBIg8`lp5<0#gGrDo=i9`4 zy(^iWmUKfkmJyr0yX@sE)Ugt$iqp&T*&!AxRaHlX;yKTj*C~J`FrLzg^MRH=OD0u< zmFh3X&%aQ|K18LqJJhT;Z~vUjy1d4`@}UMVLRiAvbv^PE?yGGVV?XEJPu29WjbR0~ zHVPh>a~e~ghWx$D8YePp7ta!GhpM?w`)wcS=DoY_o26=)u(XG5Y^4(V?IrlQuh{=U zUX9%`izc9@eUzSOi9psJJhQ)@1#AI}QVCB&UR1qbVfh%P4<K&IBc()SigS@vvyxVg8gJ%By!~R*}2`B;!E_3q0aIQr$ z)zZ__6^1NXwritiD5O_GK4+ceouBR+7IrKM>SwsuDB0T}jo(Y4nH9E*346W4l=sjp%L6u{0hC5b7nv43zn3e@ibGB? z9o${A*pZK4kW|~SUq%c_(daB%DN7vsjnw4l0f?8+SC!Wt!8^r49l*)+Q>~@@*6iCG zYN*UOO{!Lf^i8EP6jAk~ZHw0wp`XI}JwRCgw{rjA5`TL=^Yj~#!OFK=LLFg7Sqa_V zJyA0Q=`W}y2t?LuqZ-(FdfxOi|KS4Q@4H5TvD{BJP0a~RnA`xzT2=ZlDZl3d{Z~<6 z#2W{P8z0Gl_6ch*!0ItT>%cenK7QI#!qVu-VmWrBqL$W|p;M^n-RYmX-M`IXOh`uN zv&$pI7J%3@)&=mS23Dh#Sn4(bCEemq1_qe1 zn2*K5{-nA3-P@25pu!)^_oXlfY3{XDb=f zeQ1XIC;GR;<4Vdwy#;#D;p@nQ=?4Y|NQ(|(P!MKYH(Oj4PSDPLr)Y4NShQSx^d1jJ zPYzd&yT)eLZe&S|ysXHX-G5RQ62B8Du1XHsPeG*kI5cGsZ8IEhiKOjY3L1MrSWVOtTEx1eiOGKIcqaWnj&x=q#+783}D%M6V7=rnKqiKkN7 z3jJL~>T;S9%hrX+mf}yP8Hb^s>uO2cR-?S8fyn)So<0y%nCiOQnc5?&a=021;5w3O zaG6Brel6zX5fI-zQ=h-481<&X8))Q@AN}5C=-)LkC(%@2-U>1P$>ywtWp^=Jvvgomu^?@k;Y25%~|Da>m5Kg3D*hm}c7f0u5wP6UFJ{Hz zNJ^bsDS9(Wrl+xEmr7FR?zYEIdF}^pWE6UeuCNt_2D7Vu(DoBZg83p*8u@xDsB324 zTJrwI0{MFx|CE0Ct+=Lx203dqmFZ_Rm2n;>IY#4lzU&S1P5l9Jg*~GKwO6jM#`J_C zvX?^KV@|#d(QB&p8^0J-u{1Oc+MuXea9t;hT{gW?oJha@^n5eh?JztoZLq>Z!t(sbQe+cOk@ z?=V^zLd}NgAv)bQ?x12aNLxMaycV4-o@3y1aj&IH7($ssbKC%WdU%yi?8MI?^JSIh z?P#Anoa+w10~53hDX=!%hu8|fFDplRuyD@C4jKCGqo!p8C*xEHzhv92%TB>eqfjy_b*s^#*+5LHLD zw6I@9g7E9N@OmoTVGpYM<_DY2mJWPk@eDldFy!Kq%K#X&MO%?zfiOh5&Lm}cAK{TqsYIvB*fpnPGhNm*2{V zhs&a`{TT>ieylY|VRe?Ziw|AkOHJ8w6`y6|8)#fl3Qu^O`HdshKzH3!KJ1(bxbVMB z>@1C0Y|u)oh;aWA)1;EUSKEjN5ey!S5BPJ$x;cr3@<84iL8Ou!fg@)8lp_9*(27Vu z$9OBr<~l6+*|U)gZ{JMkEA_qi*<)wo4&*$y@~l>FR)11VH%)czgJdVWduE1aUaahC z?y|8+@cTu-*}9ASNcXtQZ2NQL78-=aLG?N#aIl?E;`AoCg>jZqjbZ9<-5?puRNxth7mY3;p}7({p+ zURfnu3}?f_;fWuLtsA% zRZ@E32?nJ@-reeIeEPTDemdB}${{UI(v~$QgB8{+Yrd>MQs+DmuHb018PUrr` zk(U(W-|?~2Pdh97N}M#BxD=GFI&-C8Y4Yf$1?yifpWJd>ThIIbzL;EQ;P(|&A>oJ+Aif-u~`Q8s^^?A7&DkkDI8 z@fNiMWmjOx+k%0;zM?DFGs6HzO${j|fQ1(Zlwu0@TaWh>Yq(6Dg%*j*W-d`YcutEB z%u)u`rg>|f9!Qe~2t&#@6X+&pFytJ3EtNqmDn9O#vDvw&xkEVXwWvJTd_UskVn+D^ z8f3#wCRZF8>X3d{Pw`?Gf%RF;Wc_jFAN4Es*Me0sDpz4`qqlr{cDdogi{5Y-!KVVY ziV4@$KYEgWG?_{AO|g>XkO-v0Z;W%Uv}#V@wADGfeYDg8S?Zrfzxxd#)Ohf_Og_s55WbtmQO9sNp$bHlZ`e?w$9_+j)Fb z#)edZW6igJOj@nxeAlMhQm3rj@A{fr+U^ufV@oWVJNc1-7+De0kgX-`e+5X4l&@E% zhmTiR=NhNVZKI7)o{dH?IP60NJuyK=$uS*<<;O6BNr^2I5OydGfox}RK@@-3UvNQ$ zpYQ)uXf;hr!g*|<;(3;CFzxv2!;D*m@`9*?Yktzi&VdY7;~X&_G&vt=AYN|@h}8Tc zS00=_gOY&`p}nXPcH0^$q7oc=Q(!StX80uB-Y1Wx4%c}tH9~|(ldmwtLJQ;(1r|#E zYZsw{Y&^9#eB^qGi(wcg)vc)*5dWeBMSv)NcET3~^3mKgj*t?$FdRec?DXO}{-v@Mt~Sk}Z;%vn39&%Kq! z_-=CzhEEX^E`kHlccp%R{oVH?Ej&@^T1| zp|O8O5nBH}W-pk$mT$;tP9ZT<^*4+sy&dud5TemT6Ru?CE<97b*L z)_?YNftj+{v*Z`bSX54;D+U(CE0L3QNuKK_q`EDTN&}?2n@z>q^R8e7+&6YXh@{p! zXJ|V%c}|cfxw_VAp>xD^!)*LY*q0&iiq$m?v;{+4<_Kh6gOnmkTb9ueQiJ~3$wRRe z*+n6hwAD@uVCB&GM+5ptJ`YV?o$R)X4Si3@a0v22Xhe%QE>^Qswo3Fgvp;D~!kXKk z2yk!6>#?xg(#WNFh$G@9C}6?Q1`Pj*U)Fj;o)ajybE||_Xs7%N@N-M+Tu0p7-qe~$ zVjLySA396Ff&p3yEhjl+(N|^@j1VL!_e-un>m!>ciw2S1I8>NGs`ijQ^hmkI87JMU z%78mPj;_HFFisl(p^?j^{!zL&IxRvsu<{F%$y04An=^Dc3+b~umr(aovUq2ERxm*j zF1;WWf$=i6pdm5bk&EL=XPkAq&eg*6(r?u2d<(Qa>4T?n1I0%X&CkleQLi|(Sr?y0 zG}rbB;V1b7R8mU}#95Ob2s>UZ-QZ?-BRk{>`&A-Wy*l+m)0a(~GgAos8^lGn5=NUv z!Eu1fw7b?*lnzH(?}x8`(Bn{V5a{K5h2;t;czOz77v_x^9?}G)+Rk-mQ+NoNR|wq9qoH17 zNZnS|ei1lsi7z#xr*M3k054$bY77uqs1trmEjLiMWBe(ZOEmiH#U=P&-$v+8BvlV3 z__PhRpo+>jIwMS7yULtk7`B>LNFExlK>6@>Zt18FNE!!xHxLmy4#VCZP&> zfl+ou>?;>d5yqknhUoI3j=BmgLOFewcbZYd9{`xzk`e0{Pt1J$hP^0b#Mc1Or(l$h z>a@?sANqH*A%vgQ1?q)XCt(}(y&=4`fIWLL5hWNB<5f+7=(HecEU6*r^vf-9zacT; z7cbqzHgqtCuGng|;x+HU&7PPya!(+~ykaFH?8<8#{l0TEEB6C;p}grWCIy)VzbbVZ zID-3uYYO+n%c9$Iy%;7$U|yRQ=WdCYme~lsSx%qN32Kv2+54DW_n&QD*U^_PL~q7$ zDZ+ydE2+T|F-r+yzzOi3^sVqNb2-Zzl3p=ss;R&*g{FR;MGf<*f|1{e1;iu8z)OS#1o*`F-*R~B21f74j%J;uY;Z8;m`EAtZFq4Z^_ zn@fJDjKnET{-oW1yW?;uxaVfk#a?G3WY^YQcg#j#f0fR@+L&UC9Im@$9`5nxUhrKL z-H7U1DqoC*!gD6GUBAU_*nOSiAj>F5ew)0^~qb6k_4IJ)1MoPHU`0*=z5pds~-X#113i^w#y6{B-9t`*~EXE zwtt03{v(>$`;NtQq6WC!E&2_f&oaa^VK?=UFSnNt9z_Ei8TLYjCNMJ7>|x7+m|gU3 zue>G_bU1|eN$S5SU82rj8^xDkMRZ-j{%>QuHTy80~mb?Tq-mUOlJvw=y7 z)B{*v{YE&1ilp&Mgt?(r(i9Ziw-mfEpBPd(4s zvFtO0p9U=N!eteK`eb|h-{#=z#wcCvfa^Q@KrYHm?5#;skLBEF0X#A5@YRZ9T1ywD zze7YETrF!hu?F6S%*suhC}7-`I%>G0(f6w=*U^rP;i?Anv1~x>3hO_7?s{o@+MHfAS7*vKGjfv+FI)^s%jlz`;LQT_z^dcmiS9qp zb?p_sG#LP;SpC~blns!D9xt-c1Bn0*MHWu`Y^yA&uRjQo9da=uqJ>sOe$rY~Oq(`P z%n6lZY_n$$E|s&at^Ok)lvLNM4t+TD0%HF8QrsHT{>t&_?HK40OD3?$rKS*z4^iQ= z?pU;L@a)i%KCFDL9@fG!-TqVYP=!Dgmq*qIiID?5vG>FfWpYdVs9BVp^lrt(olufrF!&Bf9Szdxfua|6LhNEzsTjwwI0dE>KraedHHv0 zHo~>u0Z-&+8Rd+>U&BNk$kB~S~c!-t)y4g?u;T!V+UWAaq0%s>$mNP?Xy>l zi9goshJtVVHln0E&tP`nd-HwiGcI~mID;=kzL@UcW_3vSqW_ls?R}e8Nsj~$xYhuD zRqL~tU=wtGsocTVa;h7>_|=!lgeT4WfIHl2VMZ}sQWM^mo4a4%nwn`U=0G7x62iWc zYVkz1TGUi*{X$V|_u7Zy`lDBUcINnkxES)!J@0I5eEc7ve)^<^#Z4YCCC+B}BXMB) zpy6w$v;vHAsqTQ0yj6R#FNpaPjTyYHhr%ZgHy;jpA6cnJk01m7cW-X{C)uqJt80%? z*y{Fo4&o6G{B>o4<`Y3P`c0=I9;UF8h8}H{SjFut&rW-|Hx@=f6Q6FUQ^@T(+^t~_Qza4 zJV?^$kaB60OWqzHf6(JfqHv$Y;JbzQ-j;^B`s3MQr^|8wmXs+lDmu7Cn@D2) zymxA>paeTKwX*n6E$Oc$sFBfqwTnpPtt7Kc-%c$Tgry7Vmit%JpaZ~+ zG9{VjngfRSaV#7AOP;NUQxiQFG6NRJ3!Ja67B~&^xZn{W2?CRrl?T2Ic#&+1U%*Nr z`A;P-`rq0ed=dPICMOj@Z2UzlT8!y;6exfqvO;j#@;$exdmCO4nhnXg`Y5m10M-LM zQ#bIGz3^~LLr(hpil@LtwuCxT+2c)46Slg#wC#R5 zpuRi#eROB8R-vQw!OWFAwjaVD%XIV0cRo3~&1Z`_n(8o2dM9qio>r>yw{UpV!sWGe=ZYW(g0I>lP49Pif!T ztyQNjR5pY-F3S4(J85l(XA&o;x?XhnE&a$VY`$lj)_m{C73TLP%F3HTBnjLvng4pf z0I3_q#Z@i{$Zp8yt#l^r+9K+n`@3tORU6JsxeHD{y(+7D2}guWUWauLQlJn&Raxl* zs>=9omsYf?jaqpJ-JT;& zw_27^=QenA?7qhQVy!D`YkTJO!j7$a>FMi}o!Dom7l)3Nf>_A-^;tg%th6%Ed>KSP z=*9PySR}~z%ObIEH|i3GWCBR*9Q}|}GE*HjO$jp6L3f-w9u4m5KjnL2VcY5pq^*hXIkp8bF z0kTO1dBSX_jq;2v?v+cm+^1w%eJ!u2Nltaa{b~YXk^`=%gMwFM>3GR?z%o3oCMHIP zO^8mmSL@_*^%Lk?PJ+KEkxzUC`d)(4b0T%qL5+JFy+7G6ks6RFQR_#0TP>=TpWkWax*wVtjUv+g}}CR zPe(b*_sL)QF$Sr#yHvJFuE9Rw$W>Zy?m@W-S!=Gqvp!()r%AADs3cZ~ ze*xvYAz>QfA1=T*cZWavz<+7_{a15=a|@57axnv7cjuFJZu6=S!51nO>Tg=AeaC_j z;VI=s{QXJ-67_EX*Q~6+8w0Z<l;{|1saEUTm? z8>>&vz(y-z!p!fb29$0}O)dhA?7OQL`0x=L53-ScMSAV^|@o(R~K<=4CEDl`p zFD0f5DsNBJ8~hP+)xS}fU(Wvjag#8WmeG)NRTok}Iquq7az+7c!xfvLfGp1U7%*=xuZ_5+Fi;4n;N*PR<1@p7M?7<)?VL+(UdJ&6k^#N!5U$^=K-JaLjR?Qv& zCp1=0tY7YDr)z)w-S)!JM;zTzRtWSX4jML54={S~UzB1sRv$DR)+Z;UoCx`Nqqz*& zCbsP16}k)pY%#)%t(=&Vu?lM0@x6y9^`9kcS7#H2El_{bNZj%vrEHCFd1kT^0*KF^q!v8D=`~Bm)<;VF zR<%_us1K3##uLCaXh@}w-ue)FOGyM(#I66T0$cbJyh!nCj`pY92BzENw@;-HbzR$s zPF6X>o9fR8pzZt5s_b<=t~cY;biB}yhZy)XT;E9cBv!z)$MegIZ$L!`0q5L z8sAZ&LBFg2k#Sa8-4bZnL#1$Yf4M{_AfZ2qzN}hK|G*d)1ViqC@?t+-&f0^5q4p?Z zWLM1F?S__@1#YOovAn~|s4t>ELhKBKqss*~E7_AA;=05x1#V?9n4+m|+l{pRD)^%A zfInS%-v@W#O7I5-20KdJB@NZ2{8a`GzUNkFidRN-Ug&+jaEA24LQ0*I~MeOYv}2gmwKTmMPqW#N_Hb z?na>O@ywE^^ZNJ7xgYCHF3Dka^Rxs`Z9?S-AsoA{*fhJM6K)CloIhepcRQoQTOIjy zO0VCTav$+L>FcF&)t3}=9*uO$&Z^anv2KgNHXNC9`exg3hUs>=7GLZyn*6hIYGt&T z&P(W$r1p5r{loqji0;|M)+LoyookvY`dIbQu$I9|lZ@L^u1AMENv&yTv_G&)L{@*` z5gcUo2Sr8;#M9- zw?EK$uzWX(c)1KXk#9}8lz;#FM$~<=ZHvNUrwCVG_@J2Sg>}tp)&upAPF-zH_%>eW zjEN5y+nLl_AglWMzbC+hytRr+f^)f$R%4%cF=vYlN`0lK1lI1LU`D!3Ls5nTj^K3-#IXR6>dpDAr-CJAJh%%nUro_KSm`~S&zW+tb#{MhS7QY31 z>#X44FV0hYEs9*rClhwyCDg-^A^g}X*yP5guFg_Qh2XYo-F>RoD$!|gEXzs|Z`ujny_ULh@$eJ+6viM#@V-#N9?dc~-6mx9(>6fVW>KW{v z^n(WNB|bFur2TD`R$G&@$B~fpp7!)I|Fck(oYbmA`KXs^@^Eghx7#Kci5T(+9Lp}Z zFn#a7O50foat9UV$dW6?pCLn!XG(CZ@l-G?!2H$(Af zF^Ar{ao6^1b!qusg~kNew`xh2K@4wDv4hH|T2o(El0GE*gRT}NGLyClOq@<9ufM+* zGrr90GaFFxohPe@v`>i?%%OZG#a6Ep2e->r#1)92DaKjZWn`VE- zUrRJFqAIXb8-#OGyui;9(_h8AM66ztQyFEMw|ZS?0Qpsk21pcS>nVx4+|i6v@34In zwAU^ABY-ofMXcQ{A4u1g{5on_He^0r_F;^7)AH@YzOy{VImn>vX0c(tDTP`_Wv%1C zJ)d!{_*Q&>xg@JOe0z1Bznj#ztcbg~F$zHyCtljgnM%6P9;9YA;7f{pVgZVFHSKs(K_%eq9U zq#xv-0df5XDn%qBA3R3Vx(x>4qj~w3e~sRF@gW84{nAAa*w-*^+Jp}k#69VHd!wF& zr$pA+r;QNfG>R8V%}SvXtG=KV!G%vJmC!DUEb@2Dl6=sK3Igw(w38-uA+1(yKQkV@ zbRymZKbNJ!j*=s>1g~&3J7)U=r>F^VOnS-H|G5${xD5{e6hR{m>PCiJ#Fl_&C1Lil zu2$a+vRR@_-bIn zIwn>DRez{vviz^v=pBC$ELY+5IKFjni99UPi<}He7-MQU9uH-O*d@xO2$rK)mtlFj z#1-VB?7$cJ9oAT#A{wC^)!fSdKtzyw!;J10z)TF)3Y=wY@mXqMg9>_%YzWl7ulDda!1zy|&FJ^Q+>n`WXez<`=cFw4^7%A9flDoI- zb(3-C?k7SV->9stkCDL$-CkXijEsGNkY|mFZi*m7LpEgp9!#1)P3nS~Da% ziSkln)m*`7DrLK$Fm`VEGzf<8e|kb3DGM5l_=4>0d&pu93-E)hoe*^p>k8{Ha7nmF z)Md+3dpgo~B*gB1BPN6rFpZ~<Zol0-wYV}FnB)SH^(V=weN6oR+v+1kxnTG%P><26#I_00TO z(kB)&SLRSLTwx4_<1sV^aMsA5_Z0x2pw_9E1=s5y)YKzii@@JBKj&*6Yq2f<{;_5ah$EnT!iS3nnjZc%}%P~I*w{e{Jz)O!*HqhH+=j+A>W5(^Q zv@+pXjcu+keT2}l{G8WZ{csrZrTiijqqB|BpYYFm!{>v7anhnVR&w55r+*;8&Q?_9 zdVb|DGEgc~$|W?!rNTAERp`B8y}GJasOzb+pWEQ6QYh6Pog<-2i%Bc95P<*XLr&?l znr@9d{gtFx!U9BbR~6|T&kmbvLO2%-kI7Y%y`Q^xxh`1J;T$$xSvBfZY8!fZZEjnC z33Uy550CT>qN8qoyUE^^#;4c9A?6i9R><~sOGoITVaJ_h?M*?)w=y2)3@HW*1eWOx zVKouwhH_t7>Pi9*I>etWrI_nTeEh(6ognB9iSpc{5jtaMD)xA+&}wi<>YSIth#Sf) zT774dl>C5j#L$z=V{}wklAt{V4Alrj>ZX1Py|x!w@F8i>Y2WQIPdw1 zLf$*cJ&Bcfcq~S~g>c9}gx#7x*Y^%}bwk0zqYBCVuC>t25Q1kngjlEHv^}|LC@}Lb zh-+s*)7p0Aftumj{Scc4OYg54k&-s2u_Gz1Ng|$|M9u767|$9632BuUj^IAUpZZ#V zbn&jk-`#2-$|mQYKMr>t$C(zTTYkjW|>4ulu==oAvei*W5d(*tCsC?Y;nMp$9uE744Cm@t$FO zuJr0&zBEH)_rkQt+>Zj9h5YHL-NstJ$HG6f8seeCPRBx(SHVpL7i0u@E;yv+4LAI0 z>M0E2o`i9i73l`nUJ|02p_G1=q$d>y2EAMheOK+zN2?r5?mIwIMJezr}+BQz}!gAO6Y*{r)QDUFppbTyTY@*IVEj@V@$q#3iSG3HHuRF5v*Del(sR9oAGy#eqe0#($ znJ$l$9b2yU_q%6Ty+mwf1H)JPH`!}XCe=f^X`eV2Z`6HzGPZ7gL6;d$?q}sZy-o*F z73f!pL`+=XcFRdlyr-s%`=FKXi*hSJZ=>l8)=|}6I#?R!;~!VjPvx0y z7r9>*Wokd%PTH9W-Hr4#BA6Oc9O+HToY@H$GI&|CsCvvevL&Sx;Oqv)wwo-|CW|H4 z3+@;pkZ6j^N=@d!OWN2w-l9UW8#~xery7v=Dex%~3T<(Wk)bFn}@CyWuRwlMb-BGlPjgp2bm+67;!)|=aGyA{nqtYvsixCQislu z=9rN?=v7Ei{ix$8S@NWI(c^d_c|q=FxG148FnvSF{Pwkn8c-D0JY_#0oj@2l;!NysYvQFGduie`+ReHhuSLjUhR7tvtAGk}KN#zOrKAG?V?;k+Mm) zxq?@1&@aACcy`2SiHTC5YCilrb1Xvk7Sfi=#m53K!5wp}Lg1E}u8zj74tqsLt@BOHBlJr|i+_}8#$c}Xgz}3BW{orvfuScJ zLxWDz?97cEiR>%%yqwHv@(16ru%a0_6DL`XO|2X;HE`(VVpwa-WlI?xT&3>3Ynb2(mX!t=}Kh zSr6CPgzWHMTBE}nDz8bl$jfLB9oWe#|x_qoOVlo;b10NW~n`tE|cF4 ziNi_S{bIzTS#~SkgEkWJ;#R>%OcYcu=gS3qG#jy(DEc?OIx3Y`;~Q6n&!@389;a>V z1miqo@4EIC6_pY4GKEWnsJT5Ky4MzkUNW~@J&oJ=xRlFo&!_ffikD*#Qvv}xQ>f&N zy7eEouXJ}WX*VY7ZV}v|H2X9#ad7BX%V~k837?@R5aYx*GgB#EP4J!@I3{_y^MS0T z&N?E3&+gX7<$2-A!hkpXmsw7SyOsgPOl|M?O=5A~tvlYHQbo7H#GSsVnxd97U$0$0 zdp1zE73nqij-EL4<$HYXe&cp%$Bo-ZFH3Hdq-ETEnqlmc#pLvX0Ph&viSj{tdh)zN zXWG`l(>5Xpwrt+L`yJ{nq;!qf_)&bHMo05E9(?%NXvC5U>}DQm7|Fh!tAK$YsF=XJ z%7JM4@jd#qkt5L2C=-=*c>gtX8a=^8>84B^t>xqvmDbK#sIAM(pOk~2bV#kg!+l7W zE1NqAu6zRnLM75o@{3>QEccEkxE)AIcu|{#c~e5Jtl_(3_aVcnQ%h75ZkZ8eMjlTx zRtiMXi>;Od?{K?S?~=s|oKNoC^w24t#nN!ur=~jJl1{s{ie8- zgp3z+cx(Y)AD|no-Y3o5z&jNk+Fr&KlN8`NZREjd@~C7}B}-IzghNP|OJU&E^~fFL zd$Rs4j=A^_^{!yGD2acq7A=X*HMBH*kx?SyF@<;U*ceuz!d`PRBGu|NbhB(2pwi3} zGt#0Htn4UIlS{!DrPfUrAko=&Lpdbp{<1#MnzlYgFdG7FXiD3U2Q*$?{E?0$Vyh2=VaaESG6a4j;6aeip|$ytYY zg#+i&=CrRUy3E|y-Pa3b?Hl9uWEWeXv83Qu8+`-Wf$UMGm&qNW6oa^R*x}r3#cOn5 zj#|KudHkgOX+H<4-;??(FBJ4Mr<$E#ru0c1mib3snT!JQs6_?`3oFf%7$To*I`XhL z`Y-Qc-@QBEyPv5&mQhwVI7~x9Yo^IuqP!Gvk6BxQE~6tRCMI*W`BE~zW(_T+fw8Yd zD`H?zTLhIG_ayYPT2k)VRg7=@94qJDB{>g zFY<<&qdGp~rW8gj%;uEzD7eVtJoN6C3WXP6<5?f%Ig+gtu%HYGO#+W2 ziW63GS-x`YLws0ZurrDvdn6bc9k%Q5o_cIZC*nl1h#7lJT}N%05RLwz_M>>IVEsye z*2l~#=yNd)I$78yNjU3s(5^W>@tE((wXrMdBeGpdJ-Q$Hpv*J}+PN<74oj3Aor_OL|i>yqyFKA~zFn$Kl07e%9ZNO+^Uf}M17 zf>g)P*GX|@k%m)q7Y$}IYA9kF@3bCHfG{xL_jPIEEeaD8p(OmTGU5MF_MYKzeqY-# zf`|msB6=MyqXtnUVbnnoC8H)Xdh|}zL?@VGgy@W3V)PynW%Mq3^iK3BiTCm=|NFV$ zaMnm^h-CNg)-_2~~FrA+iHJ-};9d^#=Cn^Tr1?_YdRFW;eA z+BPw*>*$+`uLxyIllHr_6ngYc-&X%ubfnh9dy9ncD#Q7|J&cUR=IM_+o;h3=_Ku3| zxc>N29LC{w&Rm_PsuO}mgxywtOAFLNF&nnO^hqYES&Z5ujoGP(@8pP7bmP#W@On_#l&Yj13^7dUauUaggt|W)r<{ z(f&>^b(#wsp2Z>byp?PnYDz)pw?M@x3SJWl$y?_CcNPHu<9g&Vz(205C`h;_qEfxx z=lxySuv?Q*05i^gYX&jq6G%*obExpfs6RVH=)n(Q8^) zkNOF(HEN<#Qe$^s1wxpcDIlPYNdH(uYWY*R1g$CZl1>qJmsSnHoT>hE*X8QK_ zn#Q3A2bG-7?BqTDiqg*KmFbNMG!|=Xi6aW(DHXSgMMf)oexWl^ac~o@C)|TC!qt-VExRare_)UIX9AB80ypCeSl*${Zg*PN<8Zz|JBY(! zdy_r$i7^P>EauJRb8-c9gGCOG$W^3aAe?^Ym$DiH$Qtgf8!KXes$Y*2T$!w?wAiHx z>bp}X#9JL5*DZc!_Z{I)Bvfy8P-iSn7Y_&m0ps1gRau8kJH`oRLVx^%v)szgs6}M+ z$apZ2_XW%PEoE>PnD@OercGF%u=n@~5M2inM-#FE#v#MYh(@gnOOa#XAxkAazwzkb zl!T^frBXJL7d^rmq;-VshOH-Q3HoG|i?II?1S(#*+rP0E18(P`Pb=LzO1mI+`%-}S z!{6t1;+Lm6BjNac>7w^6ou4hXa&cxU@(pZlAZje`;}?$bc>o2wY~X7hrQ^|{-#dJ} z-y4R#bW%9kmR`fB{2ygVZ*=wxbzl8br-ey2`q%7D-i$Pn`yJBf=zE$bo`j5kWO6?| zH0|d$jPBQ(t>6VSmGx#=OW$!L+05}E($ji)i3u~>lvmy;@NuT;hT^Ne4}2eG{O%Hd zNDJ0Yzwg*~`F19wLCAC4$jB4cNvuDgX9xZ%wcDQlT&5)Qs$|#Gy$bkhM4CSRNjXfL;zz zDEM<{K|Vx#f)w6{HGX`r5DzBcFE?DS3jMkc8SM8wRY;=M?~|0-$_Tt7V70Nqd0i6q zB0Oo%z=Zb3g|TGk*t} zX_--y#pKaO)NA7k>>>b?Y9+C zVZT25gyiRow#vWMCiK?mRQA-4j^Jy%O$}qqQh@gvSy)oA4?|VBxrfaWqAs*A>(;4S z9H*Eb8wHR%Qsb$ijK++sqt)>-%RND-ZBH3P87lDy+#MjmTaA0j$g>6#`M;WmK2tLA zt`Aj9PK=tFqyEgX=cLuV;=St2(K67DGnKxUz8uH~JuA3hj2llegZcS@`y<@i`iZ-X z>{F8DK+;s$N`tFTNXXYG(YfzeW2^!`Dy6Sw70M*SVy^O5AGR50tSwvW*RV>9^}pK^C6z+dxOO$tfX7+B>|4^pVR;T63E* z@rpdV!<3Az&E78Uja`RmkY_7}AU?CjiY!TkB^KHNCI`u@oFpw`qd9${(9K>M=qg6+ zp&W!Bj2)rmxphyJm_r;;JDNVIppE*ThVAJnlepC1xC{rJKHMHwVglwAK)LB8s-*-p z&hGXjts?U{5OsJKgdG}R5T;$T*kdOd0o~|@9S*{tZ92}gmaHz6G|L+`?fqmWb0gWG z@%UJT#dU=)hGE)X^=Sx_Me;Ep@FIzt&y@NP)0>TB1RlSLYHl+Tq>z5!fAfBq_wp#S z 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 MlD1-*{G%8D4-wZlQ~&?~ literal 0 HcmV?d00001 diff --git a/aws/standard/module/agent.tf b/aws/standard/module/agent.tf index b01e296..4914007 100644 --- a/aws/standard/module/agent.tf +++ b/aws/standard/module/agent.tf @@ -1,30 +1,26 @@ resource "aws_instance" "kasm-agent" { - count = "${var.num_agents}" - ami = "${var.ec2_ami}" - instance_type = "${var.agent_instance_type}" - vpc_security_group_ids = ["${aws_security_group.kasm-agent-sg.id}"] - subnet_id = "${aws_subnet.kasm-use-natgw-subnet.id}" - key_name = "${var.aws_key_pair}" + count = var.num_agents + ami = var.ec2_ami + instance_type = var.agent_instance_type + vpc_security_group_ids = [data.aws_security_group.data-kasm_agent_sg.id] + subnet_id = data.aws_subnet.data-kasm_agent_subnet.id + key_name = var.aws_key_pair associate_public_ip_address = false root_block_device { - volume_size = "50" + volume_size = 120 } - user_data = <<-EOF - #!/bin/bash - fallocate -l 5g /mnt/kasm.swap - chmod 600 /mnt/kasm.swap - mkswap /mnt/kasm.swap - swapon /mnt/kasm.swap - echo '/mnt/kasm.swap swap swap defaults 0 0' | tee -a /etc/fstab - cd /tmp - wget ${var.kasm_build} - tar xvf kasm_*.tar.gz - PRIVATE_IP=(`curl -s http://169.254.169.254/latest/meta-data/local-ipv4`) - bash kasm_release/install.sh -S agent -e -p $PRIVATE_IP -m ${var.zone_name}-lb.${var.aws_domain_name} -M ${var.manager_token} - EOF + user_data = templatefile("${path.module}/userdata/agent_bootstrap.sh", + { + kasm_build_url = var.kasm_build + swap_size = var.swap_size + manager_address = local.private_lb_hostname + manager_token = var.manager_token + } + ) + tags = { - Name = "${var.project_name}-${var.zone_name}-kasm-agent" + Name = "${var.project_name}-${var.kasm_zone_name}-kasm-agent" } } diff --git a/aws/standard/module/alb_logs_s3_bucket.tf b/aws/standard/module/alb_logs_s3_bucket.tf new file mode 100644 index 0000000..bbfa0e0 --- /dev/null +++ b/aws/standard/module/alb_logs_s3_bucket.tf @@ -0,0 +1,60 @@ +data "aws_route53_zone" "kasm-route53-zone" { + name = var.aws_domain_name +} + +data "aws_elb_service_account" "main" {} + +resource "aws_s3_bucket" "kasm_s3_logs" { + bucket_prefix = "${var.project_name}-${var.kasm_zone_name}-" + force_destroy = true +} + +resource "aws_s3_bucket_acl" "kasm_s3_acl" { + bucket = aws_s3_bucket.kasm_s3_logs.id + acl = "private" +} + +resource "aws_s3_bucket_policy" "kasm_s3_logs_policy" { + bucket = aws_s3_bucket.kasm_s3_logs.id + + policy = jsonencode({ + Id = "Policy" + Version = "2012-10-17" + Statement = [ + { + Action = [ + "s3:PutObject" + ] + Effect = "Allow" + Resource = "${aws_s3_bucket.kasm_s3_logs.arn}/AWSLogs/*" + Principal = { + AWS = [ + data.aws_elb_service_account.main.arn + ] + } + } + ] + }) +} + +resource "aws_s3_bucket_server_side_encryption_configuration" "encrypt_elb_bucket" { + bucket = aws_s3_bucket.kasm_s3_logs.id + + rule { + apply_server_side_encryption_by_default { + sse_algorithm = "AES256" + } + } +} + +data "aws_s3_bucket" "data-kasm_s3_logs_bucket" { + bucket = aws_s3_bucket.kasm_s3_logs.bucket +} + +resource "aws_s3_bucket_public_access_block" "s3_log_public_access" { + bucket = aws_s3_bucket.kasm_s3_logs.id + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true +} diff --git a/aws/standard/module/availability_zones.tf b/aws/standard/module/availability_zones.tf new file mode 100644 index 0000000..87d8f48 --- /dev/null +++ b/aws/standard/module/availability_zones.tf @@ -0,0 +1,3 @@ +data "aws_availability_zones" "available" { + state = "available" +} diff --git a/aws/standard/module/cert.tf b/aws/standard/module/cert.tf index 13dc8e9..2126e66 100644 --- a/aws/standard/module/cert.tf +++ b/aws/standard/module/cert.tf @@ -1,7 +1,7 @@ resource "aws_acm_certificate" "kasm-alb-cert" { - domain_name = "${var.aws_domain_name}" + domain_name = var.aws_domain_name subject_alternative_names = ["*.${var.aws_domain_name}"] - validation_method = "DNS" + validation_method = "DNS" lifecycle { create_before_destroy = true @@ -10,7 +10,7 @@ resource "aws_acm_certificate" "kasm-alb-cert" { resource "aws_route53_record" "kasm-route53-cert-validation-record" { for_each = { - for dvo in aws_acm_certificate.kasm-alb-cert.domain_validation_options: dvo.domain_name => { + for dvo in aws_acm_certificate.kasm-alb-cert.domain_validation_options : dvo.domain_name => { name = dvo.resource_record_name record = dvo.resource_record_value type = dvo.resource_record_type @@ -19,14 +19,13 @@ resource "aws_route53_record" "kasm-route53-cert-validation-record" { name = each.value.name type = each.value.type records = [each.value.record] - zone_id = "${data.aws_route53_zone.kasm-route53-zone.id}" + zone_id = data.aws_route53_zone.kasm-route53-zone.id - ttl = 30 + ttl = 30 allow_overwrite = true } - resource "aws_acm_certificate_validation" "kasm-elb-certificate-validation" { certificate_arn = aws_acm_certificate.kasm-alb-cert.arn - validation_record_fqdns = [for record in aws_route53_record.kasm-route53-cert-validation-record: record.fqdn] + validation_record_fqdns = [for record in aws_route53_record.kasm-route53-cert-validation-record : record.fqdn] } diff --git a/aws/standard/module/db.tf b/aws/standard/module/db.tf index 5b77d6c..e802b50 100644 --- a/aws/standard/module/db.tf +++ b/aws/standard/module/db.tf @@ -1,28 +1,32 @@ resource "aws_instance" "kasm-db" { - ami = "${var.ec2_ami}" - instance_type = "${var.db_instance_type}" - vpc_security_group_ids = ["${aws_security_group.kasm-db-sg.id}"] - subnet_id = "${aws_subnet.kasm-db-subnet.id}" - key_name = "${var.aws_key_pair}" + ami = var.ec2_ami + instance_type = var.db_instance_type + vpc_security_group_ids = [data.aws_security_group.data-kasm_db_sg.id] + subnet_id = data.aws_subnet.data-kasm_db_subnet.id + key_name = var.aws_key_pair root_block_device { - volume_size = "40" - volume_type = "gp2" + volume_size = 40 } - user_data = <<-EOF - #!/bin/bash - fallocate -l 4g /mnt/kasm.swap - chmod 600 /mnt/kasm.swap - mkswap /mnt/kasm.swap - swapon /mnt/kasm.swap - echo '/mnt/kasm.swap swap swap defaults 0 0' | tee -a /etc/fstab - cd /tmp - wget ${var.kasm_build} - tar xvf kasm_*.tar.gz - bash kasm_release/install.sh -S db -e -Q ${var.database_password} -R ${var.redis_password} -U ${var.user_password} -P ${var.admin_password} -M ${var.manager_token} - EOF + user_data = templatefile("${path.module}/userdata/db_bootstrap.sh", + { + kasm_build_url = var.kasm_build + user_password = var.user_password + admin_password = var.admin_password + redis_password = var.redis_password + database_password = var.database_password + service_registration_token = var.service_registration_token + manager_token = var.manager_token + swap_size = var.swap_size + } + ) + tags = { Name = "${var.project_name}-kasm-db" } -} \ No newline at end of file +} + +data "aws_instance" "data-kasm_db" { + instance_id = aws_instance.kasm-db.id +} diff --git a/aws/standard/module/elb.tf b/aws/standard/module/elb.tf deleted file mode 100644 index 87953f4..0000000 --- a/aws/standard/module/elb.tf +++ /dev/null @@ -1,130 +0,0 @@ -data "aws_route53_zone" "kasm-route53-zone" { - name = "${var.aws_domain_name}" -} - -resource "aws_s3_bucket" "kasm-s3-logs" { - bucket_prefix = "${var.project_name}-${var.zone_name}-" - acl = "private" - force_destroy = true -} - - -resource "aws_s3_bucket_policy" "kasm-s3-logs-policy" { - bucket = aws_s3_bucket.kasm-s3-logs.id - - policy = </dev/null | grep -q true) +do + echo "Waiting for API server..." + sleep 5 +done +echo "WebApp is alive" + +bash kasm_release/install.sh -S agent -e -p $PRIVATE_IP -m ${manager_address} -M ${manager_token} + +echo "Done" diff --git a/aws/standard/module/userdata/db_bootstrap.sh b/aws/standard/module/userdata/db_bootstrap.sh new file mode 100644 index 0000000..5317314 --- /dev/null +++ b/aws/standard/module/userdata/db_bootstrap.sh @@ -0,0 +1,20 @@ +#!/bin/bash +set -ex +echo "Starting Kasm Workspaces Install" + +/bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=${swap_size} +/sbin/mkswap /var/swap.1 +chmod 600 /var/swap.1 +/sbin/swapon /var/swap.1 + +echo '/var/swap.1 swap swap defaults 0 0' | tee -a /etc/fstab + +cd /tmp + +PRIVATE_IP=(`hostname -I | cut -d ' ' -f1 | tr -d '\\n'`) + +wget ${kasm_build_url} -O kasm_workspaces.tar.gz +tar -xf kasm_workspaces.tar.gz +bash kasm_release/install.sh -S db -e -Q ${database_password} -R ${redis_password} -U ${user_password} -P ${admin_password} -M ${manager_token} -k ${service_registration_token} + +echo "Done" diff --git a/aws/standard/module/userdata/guac_bootstrap.sh b/aws/standard/module/userdata/guac_bootstrap.sh new file mode 100644 index 0000000..484d063 --- /dev/null +++ b/aws/standard/module/userdata/guac_bootstrap.sh @@ -0,0 +1,29 @@ +#!/bin/bash +set -ex +echo "Starting Kasm Workspaces Agent Install" + +/bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=${swap_size} +/sbin/mkswap /var/swap.1 +chmod 600 /var/swap.1 +/sbin/swapon /var/swap.1 + +echo '/var/swap.1 swap swap defaults 0 0' | tee -a /etc/fstab + +cd /tmp + +PRIVATE_IP=(`hostname -I | cut -d ' ' -f1 | tr -d '\\n'`) + +wget ${kasm_build_url} -O kasm_workspaces.tar.gz +tar -xf kasm_workspaces.tar.gz + +echo "Waiting for Kasm WebApp availability..." +while ! (curl -k https://${manager_address}/api/__healthcheck 2>/dev/null | grep -q true) +do + echo "Waiting for API server..." + sleep 5 +done +echo "WebApp is alive" + +bash kasm_release/install.sh -S guac -e -p $PRIVATE_IP -n ${manager_address} -k ${service_registration_token} + +echo "Done" diff --git a/aws/standard/module/userdata/webapp_bootstrap.sh b/aws/standard/module/userdata/webapp_bootstrap.sh new file mode 100644 index 0000000..5f781f5 --- /dev/null +++ b/aws/standard/module/userdata/webapp_bootstrap.sh @@ -0,0 +1,36 @@ +#!/bin/bash +set -ex +echo "Starting Kasm Workspaces Install" + +/bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=${swap_size} +/sbin/mkswap /var/swap.1 +chmod 600 /var/swap.1 +/sbin/swapon /var/swap.1 + +echo '/var/swap.1 swap swap defaults 0 0' | tee -a /etc/fstab + +cd /tmp + +PRIVATE_IP=(`hostname -I | cut -d ' ' -f1 | tr -d '\\n'`) + +wget ${kasm_build_url} -O kasm_workspaces.tar.gz +tar -xf kasm_workspaces.tar.gz + +echo "Checking for Kasm DB and Redis..." +apt-get update && apt-get install -y netcat +while ! nc -w 1 -z ${db_ip} 5432; do + echo "Database not ready..." + sleep 5 +done +echo "DB is alive" + +while ! nc -w 1 -z ${db_ip} 6379; do + echo "Redis not ready..." + sleep 5 +done +echo "Redis is alive" + + +bash kasm_release/install.sh -S app -e -z ${zone_name} -q "${db_ip}" -Q ${database_password} -R ${redis_password} + +echo "Done" diff --git a/aws/standard/module/variables.tf b/aws/standard/module/variables.tf index 2af9eaa..b9e0e7d 100644 --- a/aws/standard/module/variables.tf +++ b/aws/standard/module/variables.tf @@ -1,89 +1,147 @@ variable "project_name" { description = "The name of the deployment (e.g dev, staging). A short single word" + type = string } variable "aws_domain_name" { description = "The Route53 Zone used for the dns entries. This must already exist in the AWS account. (e.g dev.kasm.contoso.com). The deployment will be accessed via this zone name via https" + type = string } variable "aws_key_pair" { description = "The name of an aws keypair to use." + type = string } -variable "aws_access_key" { - description = "The AWS access key used for deployment" +variable "vpc_subnet_cidr" { + description = "The subnet CIDR to use for the VPC" + type = string + default = "10.0.0.0/16" } -variable "aws_secret_key" { - description = "The AWS secret key used for deployment" +variable "num_webapps" { + description = "The number of WebApp role servers to create in the deployment" + type = number + default = 2 } variable "num_agents" { - default = "2" description = "The number of Agent Role Servers to create in the deployment" + type = number + default = 2 } -variable "agent_instance_type" { - default = "t3.medium" - description = "The instance type for the Agents" -} - - -variable "num_webapps" { - default = "2" - description = "The number of WebApp role servers to create in the deployment" +variable "num_guac_nodes" { + description = "The number of Agent Role Servers to create in the deployment" + type = number + default = 2 } variable "webapp_instance_type" { - default = "t3.small" description = "The instance type for the webapps" + type = string + default = "t3.small" } - variable "db_instance_type" { - default = "t3.small" description = "The instance type for the Database" + type = string + default = "t3.small" } -variable "ssh_access_cidr" { - default = "0.0.0.0/0" +variable "agent_instance_type" { + description = "The instance type for the Agents" + type = string + default = "t3.medium" +} + +variable "guac_instance_type" { + description = "The instance type for the Guacamole RDP nodes" + type = string + default = "t3.medium" +} + +variable "ssh_access_cidrs" { description = "CIDR notation of the bastion host allowed to SSH in to the machines" + type = list(string) + default = ["0.0.0.0/0"] +} + +variable "web_access_cidrs" { + description = "CIDR notation of the bastion host allowed to SSH in to the machines" + type = list(string) + default = ["0.0.0.0/0"] } variable "aws_region" { - default = "us-east-1" description = "The AWS region for the deployment. (e.g us-east-1)" + type = string } + variable "ec2_ami" { - default = "ami-0747bdcabd34c712a" - description = "The AMI used for the EC2 nodes. Recommended Ubuntu 18.04 LTS." + description = "The AMI used for the EC2 nodes. Recommended Ubuntu 20.04 LTS." + type = string } variable "kasm_build" { description = "The URL for the Kasm Workspaces build" + type = string } -variable "master_subnet_id" { - default = "0" - description = "The 2nd octect of VPC subnet" +variable "swap_size" { + description = "The amount of swap (in MB) to configure inside the compute instances" + type = number } variable "database_password" { description = "The password for the database. No special characters" + type = string + sensitive = true } + variable "redis_password" { - description = "The password for the database. No special characters" + description = "The password for the Redis server. No special characters" + type = string + sensitive = true } + variable "user_password" { - description = "The password for the database. No special characters" + description = "The standard (non administrator) user password. No special characters" + type = string + sensitive = true } + variable "admin_password" { - description = "The password for the database. No special characters" + description = "The administrative user password. No special characters" + type = string + sensitive = true } + variable "manager_token" { - description = "The password for the database. No special characters" + description = "The manager token value for Agents to authenticate to webapps. No special characters" + type = string + sensitive = true } -variable "zone_name" { - default = "default" - description="A name given to the kasm deployment Zone" + +variable "service_registration_token" { + description = "The service registration token value for Guac RDP servers to authenticate to webapps. No special characters" + type = string + sensitive = true +} + +variable "kasm_zone_name" { + description = "A name given to the kasm deployment Zone" + type = string + default = "default" +} + +variable "anywhere" { + description = "Anywhere route subnet" + type = string + default = "0.0.0.0/0" + + validation { + condition = can(cidrhost(var.anywhere, 0)) + error_message = "Anywhere variable must be valid IPv4 CIDR - usually 0.0.0.0/0 for all default routes and default Security Group access." + } } diff --git a/aws/standard/module/vpc.tf b/aws/standard/module/vpc.tf index 56a8047..27442b5 100644 --- a/aws/standard/module/vpc.tf +++ b/aws/standard/module/vpc.tf @@ -1,22 +1,23 @@ resource "aws_vpc" "kasm-default-vpc" { - cidr_block = "10.${var.master_subnet_id}.0.0/16" + cidr_block = var.vpc_subnet_cidr + enable_dns_hostnames = true + enable_dns_support = true tags = { Name = "${var.project_name}-kasm-db-vpc" } } +data "aws_vpc" "data-kasm-default-vpc" { + id = aws_vpc.kasm-default-vpc.id +} + resource "aws_internet_gateway" "kasm-default-ig" { - vpc_id = "${aws_vpc.kasm-default-vpc.id}" + vpc_id = data.aws_vpc.data-kasm-default-vpc.id tags = { Name = "${var.project_name}-kasm-ig" } } -resource "aws_route" "internet_access" { - route_table_id = "${aws_vpc.kasm-default-vpc.main_route_table_id}" - destination_cidr_block = "0.0.0.0/0" - gateway_id = "${aws_internet_gateway.kasm-default-ig.id}" +data "aws_internet_gateway" "data-kasm-default-ig" { + internet_gateway_id = aws_internet_gateway.kasm-default-ig.id } - - - diff --git a/aws/standard/module/webapp.tf b/aws/standard/module/webapp.tf index 2f2e96b..1361856 100644 --- a/aws/standard/module/webapp.tf +++ b/aws/standard/module/webapp.tf @@ -1,38 +1,33 @@ resource "aws_instance" "kasm-web-app" { - count = "${var.num_webapps}" - ami = "${var.ec2_ami}" - instance_type = "${var.webapp_instance_type}" - vpc_security_group_ids = ["${aws_security_group.kasm-webapp-sg.id}"] - subnet_id = "${aws_subnet.kasm-webapp-subnet.id}" - key_name = "${var.aws_key_pair}" + count = var.num_webapps + ami = var.ec2_ami + instance_type = var.webapp_instance_type + vpc_security_group_ids = [data.aws_security_group.data-kasm_webapp_sg.id] + subnet_id = data.aws_subnet.data-kasm_webapp_subnets[count.index].id + key_name = var.aws_key_pair associate_public_ip_address = true root_block_device { - volume_size = "40" + volume_size = 40 } - user_data = <<-EOF - #!/bin/bash - set -x - fallocate -l 4g /mnt/kasm.swap - chmod 600 /mnt/kasm.swap - mkswap /mnt/kasm.swap - swapon /mnt/kasm.swap - echo '/mnt/kasm.swap swap swap defaults 0 0' | tee -a /etc/fstab - cd /tmp - wget ${var.kasm_build} - tar xvf kasm_*.tar.gz + user_data = templatefile("${path.module}/userdata/webapp_bootstrap.sh", + { + kasm_build_url = var.kasm_build + db_ip = data.aws_instance.data-kasm_db.private_ip + database_password = var.database_password + redis_password = var.redis_password + swap_size = var.swap_size + zone_name = "default" + } + ) - echo "Checking for Kasm DB..." - while ! nc -w 1 -z ${aws_instance.kasm-db.private_ip} 5432; do - echo "Not Ready..." - sleep 5 - done - echo "DB is alive" - - bash kasm_release/install.sh -S app -e -z ${var.zone_name} -q "${aws_instance.kasm-db.private_ip}" -Q ${var.database_password} -R ${var.redis_password} - EOF tags = { - Name = "${var.project_name}-${var.zone_name}-kasm-webapp" + Name = "${var.project_name}-${var.kasm_zone_name}-kasm-webapp" } } + +data "aws_instance" "data-kasm_web_app" { + count = var.num_webapps + instance_id = aws_instance.kasm-web-app[count.index].id +} diff --git a/aws/standard/provider.tf b/aws/standard/provider.tf new file mode 100644 index 0000000..f85cc71 --- /dev/null +++ b/aws/standard/provider.tf @@ -0,0 +1,18 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + #version = "4.56.0" + } + } +} + +provider "aws" { + access_key = var.aws_access_key + secret_key = var.aws_secret_key + region = var.aws_region + + default_tags { + tags = var.aws_default_tags + } +} diff --git a/aws/standard/settings.tfvars b/aws/standard/settings.tfvars new file mode 100644 index 0000000..e46bbcb --- /dev/null +++ b/aws/standard/settings.tfvars @@ -0,0 +1,43 @@ +## AWS Environment settings +aws_key_pair = "troy-common-ssh" +aws_region = "us-east-1" +aws_domain_name = "bryan-test2.sandbox1.kasmweb.net" +vpc_subnet_cidr = "10.0.0.0/16" + +## Kasm deployment settings +kasm_zone_name = "default" +project_name = "contoso" +num_agents = 2 +num_webapps = 2 +num_guac_nodes = 1 + +## Kasm Server settings +agent_instance_type = "t3.medium" +guac_instance_type = "t3.medium" +webapp_instance_type = "t3.small" +db_instance_type = "t3.small" +ec2_ami = "ami-09cd747c78a9add63" +swap_size = 2048 + +## VM Access subnets +ssh_access_cidrs = ["0.0.0.0/0"] +web_access_cidrs = ["0.0.0.0/0"] + +## Kasm passwords +database_password = "changeme" +redis_password = "changeme" +user_password = "changeme" +admin_password = "changeme" +manager_token = "changeme" +service_registration_token = "changeme" + +## Kasm download URL +kasm_build = "https://kasm-static-content.s3.amazonaws.com/kasm_release_1.12.0.d4fd8a.tar.gz" + +## Default tags for all AWS resources +aws_default_tags = { + Deployed_by = "Terraform" + Deployment_type = "Multi-Server" + Service_name = "Kasm Workspaces" + Kasm_version = "1.12" +} diff --git a/aws/standard/variables.tf b/aws/standard/variables.tf new file mode 100644 index 0000000..8abb128 --- /dev/null +++ b/aws/standard/variables.tf @@ -0,0 +1,284 @@ +variable "aws_access_key" { + description = "The AWS access key used for deployment" + type = string + sensitive = true + + validation { + condition = can(regex("^([A-Z0-9]{20})", var.aws_access_key)) + error_message = "The aws_access_key variable must be a valid AWS Access Key (e.g. AKIAJSIE27KKMHXI3BJQ)." + } +} + +variable "aws_secret_key" { + description = "The AWS secret key used for deployment" + type = string + sensitive = true + + validation { + condition = can(regex("^([a-zA-Z0-9+\\/-]{40})", var.aws_secret_key)) + error_message = "The aws_secret_key variable must be a valid AWS Secret Key value (e.g. wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY)" + } +} + +variable "aws_region" { + description = "The AWS Region used for deployment" + type = string + default = "us-east-1" + + validation { + condition = can(regex("^([a-z]{2}-[a-z]{4,}-[\\d]{1})$", var.aws_region)) + error_message = "The aws_region must be a valid Amazon Web Services (AWS) Region name, e.g. us-east-1" + } +} + +variable "project_name" { + description = "The name of the deployment (e.g dev, staging). A short single word" + type = string + + validation { + condition = can(regex("^[a-z]{4,15}", var.project_name)) + error_message = "The project_name variable can only be one word between 4 and 15 lower-case letters since it is a seed value in multiple object names." + } +} + +variable "kasm_zone_name" { + description = "A name given to the kasm deployment Zone" + type = string + default = "default" + + validation { + condition = can(regex("^[a-z0-9A-Z-_]{4,15}", var.kasm_zone_name)) + error_message = "The kasm_zone_name variable can only be one word between 4 and 15 characters consisting of letters, numbers, dash (-), and underscore (_)." + } +} + +variable "aws_domain_name" { + description = "The Route53 Zone used for the dns entries. This must already exist in the AWS account. (e.g dev.kasm.contoso.com). The deployment will be accessed via this zone name via https" + type = string + + validation { + condition = can(regex("(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]", var.aws_domain_name)) + error_message = "There are invalid characters in the aws_domain_name - it must be a valid domain name." + } +} + +variable "aws_key_pair" { + description = "The name of an aws keypair to use." + type = string + + validation { + condition = can(regex("^[a-zA-Z0-9-_]{4,15}", var.aws_key_pair)) + error_message = "The aws_key_pair variable contains invalid characters. Allowed values are between 4-15 characters consisting of letters, numbers, and dashes (-)." + } +} + +variable "vpc_subnet_cidr" { + description = "The subnet CIDR to use for the VPC" + type = string + default = "10.0.0.0/16" + + validation { + condition = can(cidrhost(var.vpc_subnet_cidr, 0)) + error_message = "The VPC subnet must be valid IPv4 CIDR." + } +} + +variable "swap_size" { + description = "The amount of swap (in MB) to configure inside the compute instances" + type = number + + validation { + condition = var.swap_size >= 1024 && var.swap_size <= 8192 && floor(var.swap_size) == var.swap_size + error_message = "Swap size is the amount of disk space to use for Kasm in MB and must be an integer between 1024 and 8192." + } +} + +variable "webapp_instance_type" { + description = "The instance type for the webapps" + type = string + default = "t3.small" + + validation { + condition = can(regex("^(([a-z-]{1,3})(\\d{1,2})?(\\w{1,4})?)\\.(nano|micro|small|medium|metal|large|(2|3|4|6|8|9|10|12|16|18|24|32|48|56|112)?xlarge)", var.webapp_instance_type)) + error_message = "Check the webapp_instance_type variable and ensure it is a valid AWS Instance type (https://aws.amazon.com/ec2/instance-types/)." + } +} + +variable "db_instance_type" { + description = "The instance type for the Database" + type = string + default = "t3.small" + + validation { + condition = can(regex("^(([a-z-]{1,3})(\\d{1,2})?(\\w{1,4})?)\\.(nano|micro|small|medium|metal|large|(2|3|4|6|8|9|10|12|16|18|24|32|48|56|112)?xlarge)", var.db_instance_type)) + error_message = "Check the db_instance_type variable and ensure it is a valid AWS Instance type (https://aws.amazon.com/ec2/instance-types/)." + } +} + +variable "agent_instance_type" { + description = "The instance type for the Agents" + type = string + default = "t3.medium" + + validation { + condition = can(regex("^(([a-z-]{1,3})(\\d{1,2})?(\\w{1,4})?)\\.(nano|micro|small|medium|metal|large|(2|3|4|6|8|9|10|12|16|18|24|32|48|56|112)?xlarge)", var.agent_instance_type)) + error_message = "Check the agent_instance_type variable and ensure it is a valid AWS Instance type (https://aws.amazon.com/ec2/instance-types/)." + } +} + +variable "guac_instance_type" { + description = "The instance type for the Guacamole RDP nodes" + type = string + default = "t3.medium" + + validation { + condition = can(regex("^(([a-z-]{1,3})(\\d{1,2})?(\\w{1,4})?)\\.(nano|micro|small|medium|metal|large|(2|3|4|6|8|9|10|12|16|18|24|32|48|56|112)?xlarge)", var.guac_instance_type)) + error_message = "Check the guac_instance_type variable and ensure it is a valid AWS Instance type (https://aws.amazon.com/ec2/instance-types/)." + } +} + +variable "num_webapps" { + description = "The number of WebApp role servers to create in the deployment" + type = number + default = 2 + + validation { + condition = var.num_webapps >= 1 && var.num_webapps <= 3 && floor(var.num_webapps) == var.num_webapps + error_message = "Acceptable number of webapps range between 1-3." + } +} + +variable "num_agents" { + description = "The number of Agent Role Servers to create in the deployment" + type = number + default = 2 + + validation { + condition = var.num_agents >= 0 && var.num_agents <= 100 && floor(var.num_agents) == var.num_agents + error_message = "Acceptable number of Kasm Agents range between 0-100." + } +} + +variable "num_guac_nodes" { + description = "The number of Agent Role Servers to create in the deployment" + type = number + default = 1 + + validation { + condition = var.num_guac_nodes >= 0 && var.num_guac_nodes <= 100 && floor(var.num_guac_nodes) == var.num_guac_nodes + error_message = "Acceptable number of Kasm Agents range between 0-100." + } +} + +variable "ssh_access_cidrs" { + description = "CIDR notation of the bastion host allowed to SSH in to the machines" + type = list(string) + default = ["0.0.0.0/0"] + + validation { + condition = can([for subnet in var.ssh_access_cidrs : cidrhost(subnet, 0)]) + error_message = "One of the subnets provided in the ssh_access_cidr variable is invalid." + } +} + +variable "web_access_cidrs" { + description = "CIDR notation of the bastion host allowed to SSH in to the machines" + type = list(string) + default = ["0.0.0.0/0"] + + validation { + condition = can([for subnet in var.web_access_cidrs : cidrhost(subnet, 0)]) + error_message = "One of the subnets provided in the load_balancer_public_access variable is invalid." + } +} + +variable "ec2_ami" { + description = "The AMI used for the EC2 nodes. Recommended Ubuntu 20.04 LTS." + type = string + + validation { + condition = can(regex("^(ami-[a-f0-9]{17})", var.ec2_ami)) + error_message = "Please verify that your AMI is in the correct format for AWS (https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/finding-an-ami.html)." + } +} + +variable "database_password" { + description = "The password for the database. No special characters" + type = string + sensitive = true + + validation { + condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.database_password)) + error_message = "The Database Password should be a string between 12 and 30 letters or numbers with no special characters." + } +} + +variable "redis_password" { + description = "The password for the Redis server. No special characters" + type = string + sensitive = true + + validation { + condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.redis_password)) + error_message = "The Redis Password should be a string between 12 and 30 letters or numbers with no special characters." + } +} + +variable "user_password" { + description = "The standard (non administrator) user password. No special characters" + type = string + sensitive = true + + validation { + condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.user_password)) + error_message = "The User Password should be a string between 12 and 30 letters or numbers with no special characters." + } +} + +variable "admin_password" { + description = "The administrative user password. No special characters" + type = string + sensitive = true + + validation { + condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.admin_password)) + error_message = "The Admin password should be a string between 12 and 30 letters or numbers with no special characters." + } +} + +variable "manager_token" { + description = "The manager token value for Agents to authenticate to webapps. No special characters" + type = string + sensitive = true + + validation { + condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.manager_token)) + error_message = "The Manager Token should be a string between 12 and 30 letters or numbers with no special characters." + } +} + +variable "service_registration_token" { + description = "The service registration token value for Guac RDP servers to authenticate to webapps. No special characters" + type = string + sensitive = true + + validation { + condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.service_registration_token)) + error_message = "The Service Registration Token should be a string between 12 and 30 letters or numbers with no special characters." + } +} + +## Non-validated variables +variable "kasm_build" { + description = "The URL for the Kasm Workspaces build" + type = string +} + +variable "aws_default_tags" { + description = "Default tags to apply to all AWS resources for this deployment" + type = map(any) + default = { + Service_name = "Kasm Workspaces" + Kasm_version = "1.12" + } +} diff --git a/digitalocean/single_server/README.md b/digitalocean/single_server/README.md index 7e9a478..4004c34 100644 --- a/digitalocean/single_server/README.md +++ b/digitalocean/single_server/README.md @@ -23,18 +23,40 @@ This project will launch a droplet and allow connections using the ssh keys defi terraform init -2. Open `deployment.tf` and update the variables. The variable definitions and descriptions -can be found in `module/variables.tf` - +2. Open `settings.tf` and update the variables. The variable definitions and descriptions can be found in `variables.tf`. + +> ***NOTE:*** This document assumes you are using a separate file named `secrets.tfvars` for the DigitalOcean token credential. The .gitignore file in this repository will ignore any files named `secrets.tfvars` since they are expected to have sensitive values in them. This will prevent you from accidentally committing them to source control. Refer to the [Generating a DigitalOcean Access Token](https://docs.digitalocean.com/reference/api/create-personal-access-token/) document if you need help with this process. 3. Verify the configuration - terraform plan + terraform plan -var-file settings.tfvars -var-file secrets.tfvars 4. Deploy - terraform apply + terraform apply -var-file settings.tfvars -var-file secrets.tfvars -5. Login to the Deployment as an Admin via the domain defined e.g `https://kasm.contoso.com`. Single server installs -download all workspaces images during the install process so it may take ~15 minutes for the server to fully come online. +5. Login to the Deployment as an Admin via the domain defined e.g `https://kasm.contoso.com`. Single server installs download all workspaces images during the install process so it may take ~15 minutes for the server to fully come online. + + + +# OCI Terraform Variable definitions + +| Variable | Description | Variable type | Example | +|:--------:|-------------|---------------|---------| +| `digital_ocean_token` | The DigitalOcean authentication token. | String | `"dop_v1_EXAMPLEb8f85b081895f489921abbf26e64d7f3a0e581f8a1d8d532a5ba553"` | +| `digital_ocean_region` | The DigitalOcean region where you wish to deploy Kasm | String | `"nyc3"` | +| `do_domain_name` | The domain name that users will use to access kasm. | String | `"kasm.contoso.com"` | +| `ssh_key_fingerprints` | A list of DigitalOcean SSH fingerprints to use for SSH access to your Kasm server. | List(String) | `["66:e5:d1:85:cd:ba:ca:6a:d0:76:86:ef:1c:11:63:97"]` | +| `project_name` | The name of the deployment (e.g dev, staging). A short single word of up to 15 characters. | String | `"kasm"` | +| `oci_domain_name` | The public Zone used for the dns entries. This must already exist in the OCI account. (e.g kasm.contoso.com). The deployment will be accessed via this zone name using https. | String | `"kasm.contoso.com"` | +| `vpc_subnet_cidr` | The VPC Subnet CIDR where you wish to deploy Kasm | String | `"10.0.0.0/24"` | +| `digital_ocean_droplet_slug` | The Default Digital Ocean Droplet Slug: https://slugs.do-api.dev/ | String | `"s-2vcpu-4gb-intel"` | +| `digital_ocean_image` | Default Image for Ubuntu 20.04 LTS with Docker | String | `"docker-20-04"` | +| `kasm_build_url` | The download URL for the desired Kasm Workspaces version. | String | `"https://kasm-static-content.s3.amazonaws.com/kasm_release_1.12.0.d4fd8a.tar.gz"` | +| `admin_password` | The Kasm Administrative user login password. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` | +| `user_password` | A Kasm standard (non-administrator) user password. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` | +| `allow_ssh_cidrs` | A list of subnets in CIDR notation allowed to SSH into your kasm servers | List(String) | `["10.0.0.0/16","172.217.22.14/32"]` | +| `allow_web_cidrs` | A list of subnets in CIDR notation allowed Web access to your kasm servers | List(String) | `["0.0.0.0/0"]` | +| `swap_size` | The amount of swap (in MB) to configure inside the Kasm servers. | Number | `2048` | +| `instance_shape` | The OCI instance shape to use for Kasm deployment. Kasm recommends using a Flex instance type. | String | `"VM.Standard.E4.Flex"` | diff --git a/digitalocean/single_server/deployment.tf b/digitalocean/single_server/deployment.tf index 371ca49..a981c09 100644 --- a/digitalocean/single_server/deployment.tf +++ b/digitalocean/single_server/deployment.tf @@ -1,19 +1,16 @@ module "kasm" { - source = "./module" - - digital_ocean_token = "" - - do_domain_name = "kasm.contoso.com" - project_name = "contoso" - - digital_ocean_region = "nyc3" - digital_ocean_image = "docker-18-04" - digital_ocean_droplet_slug = "s-2vcpu-4gb-intel" - swap_size = 2048 - - kasm_build_url = "https://kasm-static-content.s3.amazonaws.com/kasm_release_1.9.0.077388.tar.gz" - user_password = "changeme" - admin_password = "changeme" - allow_ssh_cidrs = ["0.0.0.0/0"] - ssh_key_fingerprints = [] + source = "./module" + project_name = var.project_name + do_domain_name = var.do_domain_name + vpc_subnet_cidr = var.vpc_subnet_cidr + digital_ocean_region = var.digital_ocean_region + digital_ocean_image = var.digital_ocean_image + digital_ocean_droplet_slug = var.digital_ocean_droplet_slug + swap_size = var.swap_size + kasm_build_url = var.kasm_build_url + user_password = var.user_password + admin_password = var.admin_password + allow_ssh_cidrs = var.allow_ssh_cidrs + allow_kasm_web_cidrs = var.allow_kasm_web_cidrs + ssh_key_fingerprints = var.ssh_key_fingerprints } diff --git a/digitalocean/single_server/module/dns.tf b/digitalocean/single_server/module/dns.tf index 901061d..ec051c2 100644 --- a/digitalocean/single_server/module/dns.tf +++ b/digitalocean/single_server/module/dns.tf @@ -1,5 +1,9 @@ resource "digitalocean_domain" "default" { - name = "${var.do_domain_name}" + name = var.do_domain_name +} + +data "digitalocean_domain" "data-default" { + name = digitalocean_domain.default.name } resource "digitalocean_record" "static" { @@ -12,32 +16,13 @@ resource "digitalocean_record" "static" { resource "digitalocean_certificate" "cert" { name = "${var.project_name}-cert" type = "lets_encrypt" - domains = ["${digitalocean_domain.default.id}"] + domains = [digitalocean_domain.default.id] lifecycle { create_before_destroy = true } } -resource "digitalocean_loadbalancer" "www-lb" { - name = "${var.project_name}-lb" - region = "${var.digital_ocean_region}" - - forwarding_rule { - entry_port = 443 - entry_protocol = "https" - - target_port = 443 - target_protocol = "https" - - certificate_name = digitalocean_certificate.cert.name - } - - healthcheck { - port = 443 - protocol = "https" - path = "/" - } - - droplet_ids = digitalocean_droplet.kasm-server.*.id +data "digitalocean_certificate" "data-cert" { + name = digitalocean_certificate.cert.name } diff --git a/digitalocean/single_server/module/firewall.tf b/digitalocean/single_server/module/firewall.tf index 3559969..b8853dd 100644 --- a/digitalocean/single_server/module/firewall.tf +++ b/digitalocean/single_server/module/firewall.tf @@ -4,31 +4,37 @@ resource "digitalocean_firewall" "workspaces-fw" { tags = ["${digitalocean_tag.project.id}"] inbound_rule { - protocol = "tcp" - port_range = "22" - source_addresses = "${var.allow_ssh_cidrs}" + protocol = "tcp" + port_range = "22" + source_addresses = var.allow_ssh_cidrs } inbound_rule { - protocol = "tcp" - port_range = "443" - source_addresses = ["0.0.0.0/0", "::/0"] + protocol = "tcp" + port_range = "443" + source_addresses = var.allow_kasm_web_cidrs + } + + inbound_rule { + protocol = "tcp" + port_range = "80" + source_addresses = var.allow_kasm_web_cidrs } outbound_rule { - protocol = "tcp" - port_range = "1-65535" - destination_addresses = ["0.0.0.0/0", "::/0"] + protocol = "tcp" + port_range = "1-65535" + destination_addresses = var.anywhere } outbound_rule { - protocol = "udp" - port_range = "1-65535" - destination_addresses = ["0.0.0.0/0", "::/0"] + protocol = "udp" + port_range = "1-65535" + destination_addresses = var.anywhere } outbound_rule { - protocol = "icmp" - destination_addresses = ["0.0.0.0/0", "::/0"] + protocol = "icmp" + destination_addresses = var.anywhere } } diff --git a/digitalocean/single_server/module/load_balancer.tf b/digitalocean/single_server/module/load_balancer.tf new file mode 100644 index 0000000..a60c29f --- /dev/null +++ b/digitalocean/single_server/module/load_balancer.tf @@ -0,0 +1,24 @@ +resource "digitalocean_loadbalancer" "www-lb" { + name = "${var.project_name}-lb" + region = var.digital_ocean_region + vpc_uuid = data.digitalocean_vpc.data-kasm_vpc.id + redirect_http_to_https = true + + forwarding_rule { + entry_port = 443 + entry_protocol = "https" + + target_port = 443 + target_protocol = "https" + + certificate_name = data.digitalocean_certificate.data-cert.id + } + + healthcheck { + port = 443 + protocol = "https" + path = "/" + } + + droplet_ids = [data.digitalocean_droplet.data-kasm_server.id] +} diff --git a/digitalocean/single_server/module/output.tf b/digitalocean/single_server/module/output.tf new file mode 100644 index 0000000..6e70e92 --- /dev/null +++ b/digitalocean/single_server/module/output.tf @@ -0,0 +1,3 @@ +output "kasm_server_ip" { + value = digitalocean_droplet.kasm-server.ipv4_address +} diff --git a/digitalocean/single_server/module/project.tf b/digitalocean/single_server/module/project.tf index 7b47382..09b152a 100644 --- a/digitalocean/single_server/module/project.tf +++ b/digitalocean/single_server/module/project.tf @@ -1,10 +1,18 @@ resource "digitalocean_project" "project" { - name = "${var.project_name}" + name = var.project_name description = "Deployment for ${var.project_name}" - purpose = "Kasm Workspaces" + purpose = "Kasm Workspaces" environment = "Development" resources = [ - digitalocean_droplet.kasm-server.urn, - digitalocean_domain.default.urn + data.digitalocean_droplet.data-kasm_server.urn, + data.digitalocean_domain.data-default.urn ] } + +resource "digitalocean_tag" "project" { + name = var.project_name +} + +data "digitalocean_tag" "data-project" { + name = digitalocean_tag.project.name +} diff --git a/digitalocean/single_server/module/provider.tf b/digitalocean/single_server/module/provider.tf new file mode 100644 index 0000000..68aba8c --- /dev/null +++ b/digitalocean/single_server/module/provider.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + digitalocean = { + source = "digitalocean/digitalocean" + version = "~> 2.0" + } + } +} diff --git a/digitalocean/single_server/module/server.tf b/digitalocean/single_server/module/server.tf index 4b98f9f..a4a0652 100644 --- a/digitalocean/single_server/module/server.tf +++ b/digitalocean/single_server/module/server.tf @@ -1,43 +1,23 @@ -data "template_file" "user_data" { - template = "${file("${path.module}/files/kasm_server_init.sh")}" - vars = { - kasm_build_url = "${var.kasm_build_url}" - user_password = "${var.user_password}" - admin_password = "${var.admin_password}" - swap_size = "${var.swap_size}" - } -} - resource "digitalocean_droplet" "kasm-server" { - ssh_keys = "${var.ssh_key_fingerprints}" - image = "${var.digital_ocean_image}" - region = "${var.digital_ocean_region}" - size = "${var.digital_ocean_droplet_slug}" - private_networking = false - backups = false - ipv6 = false - name = "${var.project_name}-workspaces" - tags = ["${digitalocean_tag.project.id}"] - user_data = "${data.template_file.user_data.rendered}" -} - -output "kasm_server_ip" { - value = "${digitalocean_droplet.kasm-server.ipv4_address}" -} - -terraform { - required_providers { - digitalocean = { - source = "digitalocean/digitalocean" - version = "~> 2.0" + ssh_keys = var.ssh_key_fingerprints + image = var.digital_ocean_image + region = var.digital_ocean_region + size = var.digital_ocean_droplet_slug + vpc_uuid = data.digitalocean_vpc.data-kasm_vpc.id + backups = false + ipv6 = false + name = "${var.project_name}-workspaces" + tags = [data.digitalocean_tag.data-project.id] + user_data = templatefile("${path.module}/userdata/kasm_server_init.sh", + { + kasm_build_url = var.kasm_build_url + user_password = var.user_password + admin_password = var.admin_password + swap_size = var.swap_size } - } + ) } -provider "digitalocean" { - token = "${var.digital_ocean_token}" -} - -resource "digitalocean_tag" "project" { - name = "${var.project_name}" +data "digitalocean_droplet" "data-kasm_server" { + id = digitalocean_droplet.kasm-server.id } diff --git a/digitalocean/single_server/module/files/kasm_server_init.sh b/digitalocean/single_server/module/userdata/kasm_server_init.sh similarity index 86% rename from digitalocean/single_server/module/files/kasm_server_init.sh rename to digitalocean/single_server/module/userdata/kasm_server_init.sh index 7d79aea..45483a9 100644 --- a/digitalocean/single_server/module/files/kasm_server_init.sh +++ b/digitalocean/single_server/module/userdata/kasm_server_init.sh @@ -9,7 +9,7 @@ chmod 600 /var/swap.1 cd /tmp -PRIVATE_IP=(`hostname -I | cut -d ' ' -f1 | tr -d '\\n'`) +PRIVATE_IP=(`hostname -I | cut -d' ' -f1 | tr -d '\\n'`) wget ${kasm_build_url} -O kasm_workspaces.tar.gz tar -xf kasm_workspaces.tar.gz diff --git a/digitalocean/single_server/module/variables.tf b/digitalocean/single_server/module/variables.tf index 13fa31b..311fce7 100644 --- a/digitalocean/single_server/module/variables.tf +++ b/digitalocean/single_server/module/variables.tf @@ -1,45 +1,83 @@ variable "project_name" { description = "The name of the project/deployment/company eg (acme). Lower case all one word as this will be used in a domain name" + type = string } -variable "digital_ocean_token" { - description = "Authentication Token For Digital Ocean" -} + variable "digital_ocean_region" { description = "The Default Digital Ocean Region Slug: https://docs.digitalocean.com/products/platform/availability-matrix/" - default = "nyc3" + type = string } + variable "digital_ocean_droplet_slug" { description = "The Default Digital Ocean Droplet Slug: https://slugs.do-api.dev/" - default = "s-2vcpu-4gb-intel" + type = string } + variable "digital_ocean_image" { description = "Default Image for Ubuntu LTS" - default = "docker-18-04" + type = string } + +variable "vpc_subnet_cidr" { + description = "VPC Subnet CIDR to deploy Kasm" + type = string +} + variable "kasm_build_url" { - description = "The Build file to install" - default = "https://kasm-static-content.s3.amazonaws.com/kasm_release_1.9.0.077388.tar.gz" + description = "The Kasm build file to install" + type = string } + variable "user_password" { - default = "changeme" description = "The default password to be used for the default user@kasm.local account. Only use alphanumeric characters" + type = string + sensitive = true } + variable "admin_password" { - default = "changeme" description = "The default password to be used for the default admin@kasm.local account. Only use alphanumeric characters" + type = string + sensitive = true } + variable "allow_ssh_cidrs" { - description = "CIDR notation for hosts allowed to SSH" + description = "List of Subnets in CIDR notation for hosts allowed to SSH" + type = list(string) } + +variable "allow_kasm_web_cidrs" { + description = "CIDR notation of the bastion host allowed to SSH in to the machines" + type = list(string) +} + variable "do_domain_name" { description = "The domain name that users will use to access kasm" + type = string } + variable "ssh_key_fingerprints" { # The ssh key fingerprints from uploaded keys can be obtained at https://cloud.digitalocean.com/account/security description = "Keys used for sshing into kasm hosts" + type = list(string) } -variable swap_size { +variable "swap_size" { description = "The amount of swap (in MB) to configure inside the compute instances" - default = 2048 + type = number + + validation { + condition = var.swap_size >= 1024 && var.swap_size <= 8192 && floor(var.swap_size) == var.swap_size + error_message = "Swap size is the amount of disk space to use for Kasm in MB and must be an integer between 1024 and 8192." + } +} + +variable "anywhere" { + description = "Anywhere route subnet" + type = list(string) + default = ["0.0.0.0/0", "::/0"] + + validation { + condition = can([for subnet in var.anywhere : cidrhost(subnet, 0)]) + error_message = "Anywhere variable must be valid IPv4 CIDR - usually 0.0.0.0/0 for all default routes and default Security Group access." + } } diff --git a/digitalocean/single_server/module/vpc.tf b/digitalocean/single_server/module/vpc.tf new file mode 100644 index 0000000..8114c9b --- /dev/null +++ b/digitalocean/single_server/module/vpc.tf @@ -0,0 +1,10 @@ +resource "digitalocean_vpc" "kasm_vpc" { + name = "${var.project_name}-vpc" + description = "Kasm deployment VPC for ${var.project_name}" + region = var.digital_ocean_region + ip_range = var.vpc_subnet_cidr +} + +data "digitalocean_vpc" "data-kasm_vpc" { + name = digitalocean_vpc.kasm_vpc.name +} diff --git a/digitalocean/single_server/provider.tf b/digitalocean/single_server/provider.tf new file mode 100644 index 0000000..6225189 --- /dev/null +++ b/digitalocean/single_server/provider.tf @@ -0,0 +1,12 @@ +terraform { + required_providers { + digitalocean = { + source = "digitalocean/digitalocean" + version = "~> 2.0" + } + } +} + +provider "digitalocean" { + token = var.digital_ocean_token +} diff --git a/digitalocean/single_server/settings.tfvars b/digitalocean/single_server/settings.tfvars new file mode 100644 index 0000000..2e8a629 --- /dev/null +++ b/digitalocean/single_server/settings.tfvars @@ -0,0 +1,24 @@ +## Kasm deployment settings +project_name = "contoso" +do_domain_name = "kasm.contoso.com" +digital_ocean_region = "nyc3" +vpc_subnet_cidr = "10.0.0.0/24" + +## DO Authentication variables +ssh_key_fingerprints = ["c2:4c:f2:5d:0c:59:5a:3f:93:a2:9d:25:94:24:9a:b1"] + +## VM Settings +digital_ocean_image = "docker-20-04" +digital_ocean_droplet_slug = "s-2vcpu-4gb-intel" +swap_size = 2048 + +## Kasm passwords +user_password = "changeme" +admin_password = "changeme" + +## VM Access subnets +allow_ssh_cidrs = ["0.0.0.0/0"] +allow_kasm_web_cidrs = ["0.0.0.0/0"] + +## Kasm download URL +kasm_build_url = "https://kasm-static-content.s3.amazonaws.com/kasm_release_1.12.0.d4fd8a.tar.gz" \ No newline at end of file diff --git a/digitalocean/single_server/variables.tf b/digitalocean/single_server/variables.tf new file mode 100644 index 0000000..b8c95ad --- /dev/null +++ b/digitalocean/single_server/variables.tf @@ -0,0 +1,135 @@ +variable "digital_ocean_token" { + description = "Authentication Token For Digital Ocean" + type = string + sensitive = true + + validation { + condition = can(regex("^(dop_v1_[a-f0-9]{64})", var.digital_ocean_token)) + error_message = "The digital_ocean_token must be a valid API Token (https://docs.digitalocean.com/reference/api/create-personal-access-token/)." + } +} + +variable "digital_ocean_region" { + description = "The Digital Ocean region where you wish to deploy Kasm" + type = string + default = "nyc3" + + validation { + condition = can(regex("^[a-zA-Z]{3}\\d", var.digital_ocean_region)) + error_message = "The DigitalOcean region format is always 3 letters and a number (e.g. nyc3) - check out https://docs.digitalocean.com/products/platform/availability-matrix/ for available regions." + } +} + +variable "do_domain_name" { + description = "The domain name that users will use to access Kasm" + type = string + + validation { + condition = can(regex("^[a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,6}", var.do_domain_name)) + error_message = "There are invalid characters in the do_domain_name - it must be a valid domain name." + } +} + +variable "ssh_key_fingerprints" { + # The ssh key fingerprints from uploaded keys can be obtained at https://cloud.digitalocean.com/account/security + description = "Keys used for sshing into kasm hosts" + type = list(string) + + validation { + condition = can([for fingerprint in var.ssh_key_fingerprints : regex("^([a-f0-9]{2}:?){16}$", fingerprint)]) + error_message = "One of the SSH Key fingerprints is incorrectly formatted. It should be 16 colon-delimited hex bytes (e.g. 12:34:56:78:90:ab:cd:ef:12:34:56:78:90:ab:cd:ef)." + } +} + +variable "project_name" { + description = "The name of the project/deployment/company eg (acme)." + type = string + + validation { + condition = can(regex("^[a-z]{1,15}", var.project_name)) + error_message = "The project_name variable can only be one word between 1 and 15 lower-case letters since it is a seed value in multiple object names." + } +} + +variable "vpc_subnet_cidr" { + description = "VPC Subnet CIDR where you wish to deploy Kasm" + type = string + default = "10.0.0.0/24" + + validation { + condition = can(cidrhost(var.vpc_subnet_cidr, 0)) + error_message = "The vpc_subnet_cidr must be a valid IPv4 Subnet in CIDR notation (e.g. 10.0.0.0/24)" + } +} + +variable "digital_ocean_droplet_slug" { + description = "The Default Digital Ocean Droplet Slug: https://slugs.do-api.dev/" + type = string + default = "s-2vcpu-4gb-intel" +} + +variable "digital_ocean_image" { + description = "Default Image for Ubuntu 20.04 LTS with Docker" + type = string + default = "docker-20-04" +} + +variable "kasm_build_url" { + description = "The Kasm build file to install" + type = string + default = "https://kasm-static-content.s3.amazonaws.com/kasm_release_1.12.0.d4fd8a.tar.gz" +} + +variable "user_password" { + description = "The default password to be used for the default user@kasm.local account. Only use alphanumeric characters" + type = string + default = "changeme" + + validation { + condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.user_password)) + error_message = "The User Password should be a string between 12 and 30 letters or numbers with no special characters." + } +} + +variable "admin_password" { + description = "The default password to be used for the default admin@kasm.local account. Only use alphanumeric characters" + default = "changeme" + type = string + + validation { + condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.admin_password)) + error_message = "The Admin Password should be a string between 12 and 30 letters or numbers with no special characters." + } +} + +variable "allow_ssh_cidrs" { + description = "CIDR notation of the bastion host allowed to SSH in to the machines" + type = list(string) + default = ["0.0.0.0/0"] + + validation { + condition = can([for subnet in var.allow_ssh_cidrs : cidrhost(subnet, 0)]) + error_message = "One of the subnets provided in the allow_ssh_cidrs list is invalid." + } +} + +variable "allow_kasm_web_cidrs" { + description = "CIDR notation of the bastion host allowed to SSH in to the machines" + type = list(string) + default = ["0.0.0.0/0"] + + validation { + condition = can([for subnet in var.allow_kasm_web_cidrs : cidrhost(subnet, 0)]) + error_message = "One of the subnets provided in the allow_ssh_cidrs list is invalid." + } +} + +variable "swap_size" { + description = "The amount of swap (in MB) to configure inside the compute instances" + default = 2048 + + validation { + condition = var.swap_size >= 1024 && var.swap_size <= 8192 && floor(var.swap_size) == var.swap_size + error_message = "Swap size is the amount of disk space to use for Kasm in MB and must be an integer between 1024 and 8192." + } +} diff --git a/oci/single_server/README.md b/oci/single_server/README.md index db060db..f14cbb5 100644 --- a/oci/single_server/README.md +++ b/oci/single_server/README.md @@ -8,7 +8,6 @@ This project will deploy Kasm Workspaces in a single-server deployment in OCI. - # Pre-Configuration Consider creating a new Compartment for the Kasm Workspaces deployment. @@ -16,40 +15,70 @@ Consider creating a new Compartment for the Kasm Workspaces deployment. In OCI create a public DNS zone that matches the desired domain name for the deployment. e.g `kasm.contoso.com`. ### API Keys -Create an administative user in the OCI console that will be used for the terraform deployment. Add the user to the -**Administrators** Group. Generate an API Key for the user. The API Key Fingerprint will be used as a variable -in the deployment configuration. Save the private key to the local directory replacing `oci-private-key.pem`. +Create an administative user in the OCI console that will be used for the terraform deployment. Add the user to the **Administrators** Group. Generate an API Key for the user. The API Key Fingerprint will be used as a variable in the deployment configuration. Save the private key to the local directory replacing `oci-private-key.pem`. -### SSH Authorized Keys -The project will install an SSH key(s) inside the OCI compute instance(s). Update `authorized_keys` in this directory -with the desired SSH public keys. - -### SSL Certificate -Create an SSL certificate that matches the desired domain for the deployment. e.g (kasm.contoso.com). Place the pem encoded -cert and key in this directory overwriting `kasm_ssl.crt` and `kasm_ssl.key`. +### SSL Certificate Options +#### Terraform-generated Let's Encrypt Certificate +To use Terraform to generate a Let's Encrypt certificate automatically, set the `letsencrypt_cert_support_email` to a valid email address and set the `letsencrypt_server_type` to either "staging" or "prod" and leave the `kasm_ssl_crt_path` and `kasm_ssl_key_path` variables empty. +***NOTE:*** +- Staging generates certificates that a browser will not trust, but are formatted correctly and are designed for testing and validating the system configuraiton and deployment and has a limit of hundreds of certificates per domain per week. +- Prod generates valid Let's Encrypt certificates but is limited to 5 certificates per week per domain. +#### Bring Your Own Certificates +Create an SSL certificate that matches the desired domain for the deployment. e.g (kasm.contoso.com). Place the pem encoded cert and key in this directory overwriting `kasm_ssl.crt` and `kasm_ssl.key`. # Terraform Configuration - 1. Initialize the project terraform init -2. Open `deployment.tf` and update the variables. The variable definitions and descriptions -can be found in `module/variables.tf` +2. Open `settings.tfvars` and update the variables. The variable definitions, descriptions, and validation requirements can be found in `variables.tf`, or in the [table](#oci-terraform-variable-definitions) below. - 3. Verify the configuration - terraform plan + terraform plan -var-file settings.tfvars 4. Deploy - terraform apply + terraform apply -var-file settings.tfvars + +5. Login to the Deployment as an Admin via the domain defined e.g `https://kasm.contoso.com`. Single server installs download all workspaces images during the install process so it may take ~15 minutes for the server to fully come online. -5. Login to the Deployment as an Admin via the domain defined e.g `https://kasm.contoso.com` . Single server installs -download all workspaces images during the install process so it may take ~15 minutes for the server to fully come online. +# OCI Terraform Variable definitions + +| Variable | Description | Variable type | Example | +|:--------:|-------------|---------------|---------| +| `tenancy_ocid` | The OCI Tenancy OCID | String | `"ocid1.tenancy.oc1..aaaaaaaaai06vvcguozt39d4ilmwtpdovl998wsxpyn0hjkab2kuh7z16po7"` | +| `compartment_ocid` | The OCI Compartment OCID | String | `"ocid1.compartment.oc1..aaaaaaaauepg1z967huiazuiwjt80rtbszp64x9oxaidkoi7wz0pgr950bzb"` | +| `region` | The OCI Region name | String | `"us-ashburn-1"` | +| `user_ocid` | The OCI User OCID | String | `"ocid1.user.oc1..aaaaaaaau3me8nojmdjrbj2vzfxeouscc1i7cf9w0aoy0iyv9b38t2y0a1ba"` | +| `fingerprint` | The OCI User API Key fingerprint | String | `"66:e5:d1:85:cd:ba:ca:6a:d0:76:86:ef:1c:11:63:97"` | +| `private_key_path` | The path for the API Key PEM encoded Private Key for the OCI User. ***NOTE:*** *Ensure the API Key contents are a valid PEM encoded RSA key file. You can tell this by ensuring that the value `-----BEGIN RSA PRIVATE KEY-----` is the first line in the key file. Otherwise, you can validate the key file by running the `openssl rsa -in oci-private-key.pem -check` command.* | String | `"./oci-private-key.pem"` | +| `project_name` | The name of the deployment (e.g dev, staging). A short single word of up to 15 characters. | String | `"kasm"` | +| `oci_domain_name` | The public Zone used for the dns entries. This must already exist in the OCI account. (e.g kasm.contoso.com). The deployment will be accessed via this zone name using https. | String | `"kasm.contoso.com"` | +| `letsencrypt_cert_support_email` | Email address to use for Terraform-generated Let's Encrypt SSL certificates | String | `"support@contoso.com"` | +| `letsencrypt_server_type` | SSL Server type for certificate generation. Valid options are staging, prod, and empty string (""). Refer to [SSL Certificate Options](#ssl-certificate-options) section of this document for more information. | String | "prod" | +| `kasm_ssl_crt_path` | Bring Your own Certificate - The file path fo the PEM encoded SSL Certificate file generated outside of Terraform. Copy/paste the contents of your generated SSL Certificate to the file designated in this path variable. | String | `"./kasm_ssl.crt"` | +| `kasm_ssl_key_path` | Bring Your own Certificate - The file path to the PEM encoded SSL Private Key file generated outside of Terraform. Copy/paste the contents of your generated SSL Private Key to the file designated in this path variable. | String | `"./kasm_ssl.key"` | +| `vcn_subnet_cidr` | The OCI VCN Subnet CIDR of the VCN where you wish to deploy Kasm | String | `"10.0.0.0/16"` | +| `ssh_authorized_keys` | The SSH Public key to be installed on the Kasm servers for SSH access | String | `"ssh-rsa some_base64_encoded_ssh_public_key_data"` | +| `instance_image_ocid` | The OCI Image OCID value of the OS to use. Kasm recommends using lates Ubuntu 20.04 LTS-Minimal for speed and efficiency. | String | `"ocid1.image.oc1.iad.aaaaaaaahiz6xym3a76xhwkmwmhrz6luyiehho7dpxpkphxhsq5q6z4m3nlq"` | +| `allow_ssh_cidrs` | A list of subnets in CIDR notation allowed to SSH into your kasm servers | List(String) | `["10.0.0.0/16","172.217.22.14/32"]` | +| `allow_web_cidrs` | A list of subnets in CIDR notation allowed Web access to your kasm servers | List(String) | `["0.0.0.0/0"]` | +| `admin_password` | The Kasm Administrative user login password. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` | +| `user_password` | A Kasm standard (non-administrator) user password. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` | +| `kasm_build_url` | The download URL for the desired Kasm Workspaces version. | String | `"https://kasm-static-content.s3.amazonaws.com/kasm_release_1.12.0.d4fd8a.tar.gz"` | +| `swap_size` | The amount of swap (in MB) to configure inside the Kasm servers. | Number | `2048` | +| `instance_shape` | The OCI instance shape to use for Kasm deployment. Kasm recommends using a Flex instance type. | String | `"VM.Standard.E4.Flex"` | +| `kasm_server_cpus` | The number of CPUs, memory in GB, and HDD size to use for Kasm WebApps. | Number | `4` | +| `kasm_server_memory` | The number of CPUs, memory in GB, and HDD size to use for the Kasm Database server. | Number | `8` | +| `kasm_server_hdd_size` | The number of CPUs, memory in GB, and HDD size to use for the Kasm Agent server(s). | Number | `120` | +# Detailed Terraform Deployment Diagram + +![Detailed Diagram][Detailed_Diagram] + +[Detailed_Diagram]: ./diagram/oci_single_server.png "Detailed Diagram" diff --git a/oci/single_server/authorized_keys b/oci/single_server/authorized_keys deleted file mode 100644 index 5d6af95..0000000 --- a/oci/single_server/authorized_keys +++ /dev/null @@ -1 +0,0 @@ -replaceme \ No newline at end of file diff --git a/oci/single_server/deployment.tf b/oci/single_server/deployment.tf index c3440a4..b4bf79e 100644 --- a/oci/single_server/deployment.tf +++ b/oci/single_server/deployment.tf @@ -1,30 +1,36 @@ module "kasm" { - source = "./module" + source = "./module" + oci_domain_name = var.oci_domain_name + project_name = var.project_name + kasm_build_url = var.kasm_build_url + vcn_subnet_cidr = var.vcn_subnet_cidr - oci_domain_name = "kasm.contoso.com" - project_name = "contoso" + ## OCI Auth information + tenancy_ocid = var.tenancy_ocid + compartment_ocid = var.compartment_ocid + user_ocid = var.user_ocid + fingerprint = var.fingerprint + private_key_path = var.private_key_path + region = var.region - tenancy_ocid = "" - user_ocid = "" - compartment_ocid = "" + ## SSL Certificate values + # Let TF generate Let's Encrypt SSL Certificates automatically + letsencrypt_cert_support_email = var.letsencrypt_cert_support_email + letsencrypt_server_type = var.letsencrypt_server_type + # Bring your own SSL Certificates + kasm_ssl_crt_path = var.kasm_ssl_crt_path + kasm_ssl_key_path = var.kasm_ssl_key_path - fingerprint = "" - private_key_path = "./oci-private-key.pem" + instance_image_ocid = var.instance_image_ocid + instance_shape = var.instance_shape + swap_size = var.swap_size + kasm_server_cpus = var.kasm_server_cpus + kasm_server_memory = var.kasm_server_memory + kasm_server_hdd_size = var.kasm_server_hdd_size + allow_ssh_cidrs = var.allow_ssh_cidrs + allow_web_cidrs = var.allow_web_cidrs + ssh_authorized_keys = var.ssh_authorized_keys - ssh_authorized_keys = "./authorized_keys" - kasm_ssl_crt_path = "./kasm_ssl.crt" - kasm_ssl_key_path = "./kasm_ssl.key" - - region = "us-ashburn-1" - instance_image_ocid = "ocid1.image.oc1.iad.aaaaaaaafg6lg7dejwjebjqontwzyvutgf6qs5awyze6fgoiqepyj5qkvcuq" - instance_shape = "VM.Standard.E4.Flex" - instance_ocpus = 2 - shape_memory_in_gb = 4 - instance_boot_size_gb = 60 - - kasm_build_url = "https://kasm-static-content.s3.amazonaws.com/kasm_release_1.9.0.077388.tar.gz" - user_password = "changeme" - admin_password = "changeme" - allow_ssh_cidr = "0.0.0.0/0" - allow_web_cidr = "0.0.0.0/0" -} \ No newline at end of file + admin_password = var.admin_password + user_password = var.user_password +} diff --git a/oci/single_server/diagram/oci_single_server.drawio b/oci/single_server/diagram/oci_single_server.drawio new file mode 100644 index 0000000..49eb0a3 --- /dev/null +++ b/oci/single_server/diagram/oci_single_server.drawio @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/oci/single_server/diagram/oci_single_server.png b/oci/single_server/diagram/oci_single_server.png new file mode 100644 index 0000000000000000000000000000000000000000..d8fb34082c4205da918ad2b68099007579f64bc7 GIT binary patch literal 77494 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 StZXFUPyRJjrs9>!hyMWx3L^*r literal 0 HcmV?d00001 diff --git a/oci/single_server/module/dns.tf b/oci/single_server/module/dns.tf index f49066f..af075bf 100644 --- a/oci/single_server/module/dns.tf +++ b/oci/single_server/module/dns.tf @@ -1,12 +1,17 @@ +data "oci_dns_zones" "kasm_dns_zone" { + compartment_id = var.compartment_ocid + name = var.oci_domain_name +} + resource "oci_dns_rrset" "kasm_a_record" { + domain = var.oci_domain_name + rtype = "A" + zone_name_or_id = var.oci_domain_name + compartment_id = var.compartment_ocid + items { domain = var.oci_domain_name - rtype = "A" - zone_name_or_id = var.oci_domain_name - compartment_id = var.compartment_ocid - items { - domain = var.oci_domain_name - rdata = oci_core_instance.kasm_instance.public_ip - rtype = "A" - ttl = 300 - } -} \ No newline at end of file + rdata = oci_core_instance.kasm_instance.public_ip + rtype = "A" + ttl = 300 + } +} diff --git a/oci/single_server/module/instance.tf b/oci/single_server/module/instance.tf index 23c5d08..578feed 100644 --- a/oci/single_server/module/instance.tf +++ b/oci/single_server/module/instance.tf @@ -1,15 +1,3 @@ -data "template_file" "user_data" { - template = "${file("${path.module}/userdata/bootstrap.sh")}" - vars = { - kasm_build_url = "${var.kasm_build_url}" - user_password = "${var.user_password}" - admin_password = "${var.admin_password}" - swap_size = "${var.swap_size}" - nginx_cert_in = file("${var.kasm_ssl_crt_path}") - nginx_key_in = file("${var.kasm_ssl_key_path}") - } -} - resource "oci_core_instance" "kasm_instance" { availability_domain = data.oci_identity_availability_domain.ad.name compartment_id = var.compartment_ocid @@ -17,8 +5,8 @@ resource "oci_core_instance" "kasm_instance" { shape = var.instance_shape shape_config { - ocpus = var.instance_ocpus - memory_in_gbs = var.shape_memory_in_gb + ocpus = var.kasm_server_cpus + memory_in_gbs = var.kasm_server_memory } create_vnic_details { @@ -30,17 +18,24 @@ resource "oci_core_instance" "kasm_instance" { } source_details { - source_type = "image" - source_id = var.instance_image_ocid - boot_volume_size_in_gbs = var.instance_boot_size_gb + source_type = "image" + source_id = var.instance_image_ocid + boot_volume_size_in_gbs = var.kasm_server_hdd_size } - metadata = { - ssh_authorized_keys = file("${var.ssh_authorized_keys}") - user_data = base64encode("${data.template_file.user_data.rendered}") + ssh_authorized_keys = var.ssh_authorized_keys + user_data = base64encode(templatefile("${path.module}/userdata/bootstrap.sh", + { + kasm_build_url = var.kasm_build_url + user_password = var.user_password + admin_password = var.admin_password + swap_size = var.swap_size + nginx_cert_in = var.letsencrypt_server_type == "" ? file(var.kasm_ssl_crt_path) : acme_certificate.certificate.certificate_pem + nginx_key_in = var.letsencrypt_server_type == "" ? file(var.kasm_ssl_key_path) : tls_private_key.certificate_private_key.private_key_pem + } + )) } - } diff --git a/oci/single_server/module/letsencrypt.tf b/oci/single_server/module/letsencrypt.tf new file mode 100644 index 0000000..b9bf330 --- /dev/null +++ b/oci/single_server/module/letsencrypt.tf @@ -0,0 +1,48 @@ +resource "tls_private_key" "registration_private_key" { + algorithm = "RSA" +} + +resource "tls_private_key" "certificate_private_key" { + algorithm = "RSA" +} + +resource "acme_registration" "registration" { + account_key_pem = tls_private_key.registration_private_key.private_key_pem + email_address = var.letsencrypt_cert_support_email +} + +resource "tls_cert_request" "kasm_certificate_request" { + private_key_pem = tls_private_key.certificate_private_key.private_key_pem + dns_names = [data.oci_dns_zones.kasm_dns_zone.zones[0].name, "*.${data.oci_dns_zones.kasm_dns_zone.zones[0].name}"] + + subject { + common_name = data.oci_dns_zones.kasm_dns_zone.zones[0].name + } +} + +resource "acme_certificate" "certificate" { + account_key_pem = acme_registration.registration.account_key_pem + certificate_request_pem = tls_cert_request.kasm_certificate_request.cert_request_pem + recursive_nameservers = [ + "8.8.8.8:53", + "4.4.2.2:53" + ] + + dns_challenge { + provider = "oraclecloud" + + config = { + OCI_COMPARTMENT_OCID = var.compartment_ocid + OCI_PRIVKEY_FILE = var.private_key_path + OCI_TENANCY_OCID = var.tenancy_ocid + OCI_REGION = var.region + OCI_PUBKEY_FINGERPRINT = var.fingerprint + OCI_USER_OCID = var.user_ocid + OCI_PROPOGATION_TIMEOUT = 600 + OCI_POLLING_INTERVAL = 60 + OCI_TTL = 300 + } + } + + depends_on = [acme_registration.registration] +} diff --git a/oci/single_server/module/main.tf b/oci/single_server/module/main.tf deleted file mode 100644 index 586a8cb..0000000 --- a/oci/single_server/module/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -provider "oci" { - tenancy_ocid = var.tenancy_ocid - user_ocid = var.user_ocid - fingerprint = var.fingerprint - private_key_path = var.private_key_path - region = var.region -} - diff --git a/oci/single_server/module/provider.tf b/oci/single_server/module/provider.tf new file mode 100644 index 0000000..7539cab --- /dev/null +++ b/oci/single_server/module/provider.tf @@ -0,0 +1,16 @@ +terraform { + required_providers { + oci = { + source = "oracle/oci" + version = ">= 4.0.0" + } + acme = { + source = "vancluever/acme" + version = ">= 2.0" + } + tls = { + source = "hashicorp/tls" + version = ">= 4.0.0" + } + } +} diff --git a/oci/single_server/module/security_list.tf b/oci/single_server/module/security_list.tf index 3fae3cb..827d823 100644 --- a/oci/single_server/module/security_list.tf +++ b/oci/single_server/module/security_list.tf @@ -1,42 +1,47 @@ - resource "oci_core_security_list" "allow_web" { - compartment_id = var.compartment_ocid - vcn_id = oci_core_vcn.kasm_vcn.id - display_name = "allow_web" + compartment_id = var.compartment_ocid + vcn_id = oci_core_vcn.kasm_vcn.id + display_name = "allow_web" - egress_security_rules { - destination = "0.0.0.0/0" - protocol = "all" - stateless = "false" - } + egress_security_rules { + destination = var.anywhere + protocol = "all" + stateless = "false" + } - ingress_security_rules { - protocol = "6" - source = "${var.allow_web_cidr}" - tcp_options { - max = "443" - min = "443" - } + dynamic "ingress_security_rules" { + for_each = var.allow_web_cidrs + content { + protocol = "6" + source = ingress_security_rules.value + tcp_options { + max = "443" + min = "443" + } } + } } resource "oci_core_security_list" "allow_ssh" { - compartment_id = var.compartment_ocid - vcn_id = oci_core_vcn.kasm_vcn.id - display_name = "allow_ssh" + compartment_id = var.compartment_ocid + vcn_id = oci_core_vcn.kasm_vcn.id + display_name = "allow_ssh" - egress_security_rules { - destination = "0.0.0.0/0" - protocol = "all" - stateless = "false" - } + egress_security_rules { + destination = var.anywhere + protocol = "all" + stateless = "false" + } - ingress_security_rules { - protocol = "6" - source = "${var.allow_ssh_cidr}" - tcp_options { - max = "22" - min = "22" - } + dynamic "ingress_security_rules" { + for_each = var.allow_ssh_cidrs + content { + protocol = "6" + source = ingress_security_rules.value + tcp_options { + max = "22" + min = "22" + } } + } } diff --git a/oci/single_server/module/userdata/bootstrap.sh b/oci/single_server/module/userdata/bootstrap.sh index dfe4da9..0ff4b69 100644 --- a/oci/single_server/module/userdata/bootstrap.sh +++ b/oci/single_server/module/userdata/bootstrap.sh @@ -9,17 +9,18 @@ chmod 600 /var/swap.1 cd /tmp -PRIVATE_IP=(`hostname -I | cut -d ' ' -f1 | tr -d '\\n'`) +PRIVATE_IP=(`hostname -I | cut -d ' ' -f1 | tr -d '\\n'`) wget ${kasm_build_url} -O kasm_workspaces.tar.gz tar -xf kasm_workspaces.tar.gz bash kasm_release/install.sh -e -U ${user_password} -P ${admin_password} -p $PRIVATE_IP -m $PRIVATE_IP echo -e "${nginx_cert_in}" > /opt/kasm/current/certs/kasm_nginx.crt - echo -e "${nginx_key_in}" > /opt/kasm/current/certs/kasm_nginx.key -docker exec kasm_proxy nginx -s reload +echo "Stopping and restarting Kasm services to apply certificates..." +/opt/kasm/bin/stop +docker rm $(docker ps -aq) +/opt/kasm/bin/start echo "Done" - diff --git a/oci/single_server/module/variables.tf b/oci/single_server/module/variables.tf index 29fb5f5..847373c 100644 --- a/oci/single_server/module/variables.tf +++ b/oci/single_server/module/variables.tf @@ -1,94 +1,139 @@ variable "project_name" { description = "The name of the deployment (e.g dev, staging). A short single word" + type = string } variable "oci_domain_name" { description = "The public Zone used for the dns entries. This must already exist in the OCI account. (e.g kasm.contoso.com). The deployment will be accessed via this zone name via https" -} - -variable kasm_build_url { - description = "The URL for the Kasm Workspaces build" -} - -variable swap_size { - description = "The amount of swap (in MB) to configure inside the compute instances" - default = 2048 + type = string } variable "tenancy_ocid" { description = "The Tenancy OCID." -} - -variable "user_ocid" { - description = "The User OCID." + type = string } variable "compartment_ocid" { description = "The Compartment OCID" + type = string } variable "region" { description = "The OCI Region eg: (us-ashburn-1)" + type = string +} + +variable "user_ocid" { + description = "The User OCID." + type = string } variable "fingerprint" { description = "API Key Fingerprint" + type = string } variable "private_key_path" { description = "The path to the API Key PEM encoded Private Key" + type = string + sensitive = true +} + +variable "letsencrypt_cert_support_email" { + description = "Email address to use for Let's Encrypt SSL certificates for OCI Deployment" + type = string +} +variable "letsencrypt_server_type" { + description = "SSL Server type to generate. Valid options are staging, prod, and empty string. Prod certificates are limited to 5 per week per domain." + type = string +} + +variable "vcn_subnet_cidr" { + description = "VPC Subnet CIDR where you wish to deploy Kasm" + type = string } variable "ssh_authorized_keys" { - description = "The file path to the authorized_keys file that contains SSH public keys to be installed on the OCI compute instance" + description = "The SSH Public Keys to be installed on the OCI compute instance" + type = string } variable "instance_image_ocid" { - description = "The OCID for the instance image , such as ubuntu 18.04, to use." - default = "ocid1.image.oc1.iad.aaaaaaaafg6lg7dejwjebjqontwzyvutgf6qs5awyze6fgoiqepyj5qkvcuq" + description = "The OCID for the instance image , such as ubuntu 20.04, to use." + type = string } -variable "instance_boot_size_gb" { - description = "The size, in GB, of the instance drive" - default = 60 -} - -variable "instance_shape" { - description = "The instance shape to use. Should be a Flex type." - default = "VM.Standard.E3.Flex" -} - -variable "instance_ocpus" { - description = "The number of CPUs to configure for the instance" - default = 2 -} - -variable "shape_memory_in_gb" { - description = "The amount of memory, in GB, to configure for the instance" - default = 4 -} - -variable "allow_ssh_cidr" { +variable "allow_ssh_cidrs" { description = "The CIDR notation to allow SSH access to the systems." - default = "0.0.0.0/0" + type = list(string) } -variable "allow_web_cidr" { +variable "allow_web_cidrs" { description = "The CIDR notation to allow HTTPS access to the systems." - default = "0.0.0.0/0" + type = list(string) } variable "kasm_ssl_crt_path" { description = "The file path to the PEM encoded SSL Certificate" + type = string } variable "kasm_ssl_key_path" { description = "The file path to the PEM encoded SSL Certificate Key" + type = string + sensitive = true } variable "user_password" { - description = "The password for the database. No special characters" + description = "The standard (non administrator) user password. No special characters" + type = string + sensitive = true } + variable "admin_password" { - description = "The password for the database. No special characters" -} \ No newline at end of file + description = "The administrative user password. No special characters" + type = string + sensitive = true +} + +variable "kasm_build_url" { + description = "The URL for the Kasm Workspaces build" + type = string +} + +variable "swap_size" { + description = "The amount of swap (in MB) to configure inside the compute instances" + type = number +} + +variable "instance_shape" { + description = "The instance shape to use. Should be a Flex type." + type = string +} + +variable "kasm_server_cpus" { + description = "The number of CPUs to configure for the Kasm instance" + type = number +} + +variable "kasm_server_memory" { + description = "The amount of memory to configure for the Kasm instance" + type = number +} + +variable "kasm_server_hdd_size" { + description = "The size in GBs of the Kasm instance HDD" + type = number +} + +## Pre-set values +variable "anywhere" { + description = "Anywhere route subnet" + type = string + default = "0.0.0.0/0" + + validation { + condition = can(cidrhost(var.anywhere, 0)) + error_message = "Anywhere variable must be valid IPv4 CIDR - usually 0.0.0.0/0 for all default routes and default Security Group access." + } +} diff --git a/oci/single_server/module/vcn.tf b/oci/single_server/module/vcn.tf index a068830..23958c5 100644 --- a/oci/single_server/module/vcn.tf +++ b/oci/single_server/module/vcn.tf @@ -1,12 +1,16 @@ +locals { + kasm_vcn_subnet_cidr_mask = split("/", var.vcn_subnet_cidr)[1] + kasm_server_subnet_cidr_calculation = (8 - (local.kasm_vcn_subnet_cidr_mask - 16)) + kasm_server_subnet_cidr_size = local.kasm_server_subnet_cidr_calculation < 0 ? 0 : local.kasm_server_subnet_cidr_calculation +} resource "oci_core_vcn" "kasm_vcn" { - cidr_block = "10.0.0.0/16" + cidr_block = var.vcn_subnet_cidr compartment_id = var.compartment_ocid display_name = "${var.project_name}-VCN" dns_label = "${var.project_name}vcn" } - resource "oci_core_internet_gateway" "kasm_internet_gateway" { compartment_id = var.compartment_ocid display_name = "${var.project_name}-Gateway" @@ -18,7 +22,7 @@ resource "oci_core_default_route_table" "default_route_table" { display_name = "DefaultRouteTable" route_rules { - destination = "0.0.0.0/0" + destination = var.anywhere destination_type = "CIDR_BLOCK" network_entity_id = oci_core_internet_gateway.kasm_internet_gateway.id } @@ -26,7 +30,7 @@ resource "oci_core_default_route_table" "default_route_table" { resource "oci_core_subnet" "kasm_subnet" { availability_domain = data.oci_identity_availability_domain.ad.name - cidr_block = "10.0.10.0/24" + cidr_block = cidrsubnet(var.vcn_subnet_cidr, local.kasm_server_subnet_cidr_size, 0) display_name = "${var.project_name}-Subnet" dns_label = "${var.project_name}subnet" security_list_ids = [oci_core_security_list.allow_web.id, oci_core_security_list.allow_ssh.id] diff --git a/oci/single_server/oci-private-key.pem b/oci/single_server/oci-private-key.pem index 5d6af95..6593da0 100644 --- a/oci/single_server/oci-private-key.pem +++ b/oci/single_server/oci-private-key.pem @@ -1 +1,28 @@ -replaceme \ No newline at end of file +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC9ue4AlUo3K11g +loxg3CvAUwJdkthsPmxZzOarkel1NZw22vdFnIbZhVWeO7U/WErzBWW0gpublWrq +MVZvtwitAs+++QsUV9NkDecCfghxoOV4xO3WIGmBUx32iuNM0jzqFSodUq2JpBLB +41lBToUaUbVVvd8934GoXIaFIjgvFhZcfMnQCj+FMCc86Sm5MEOtIfdI2fv6Ih71 +Yqoeqwz85xM3O8AtXlVkTwea2MOrtaPe+FzvcyLMB+lemTlaVkZ/ZnasB1SC5nzS +eOCerdx7/E7QR8mpXCWovOUIWDvMAdJvGHZM9FzI/Ve0hcmOAHTTkVn3vplnFKdO +hXAyBbCXAgMBAAECggEAH2hFFwGfvIxIM/IYIPyxnW/gZ18kxp56z07VLLfF3upW +Btqurm5gAGhLKRuXQHo8RgixsnUgj1vnzAcI2QuCuylI/MM7a02yp9CJWmdEvJK3 +CgwHlzfcX1VEE4kgYZo4DUQdqacDJVLs6/3Xy7DU5et6ykvZRePXEejnN+jXRivn +yOXD4rAA5C7Zf+vQRqfah41CqF85el7Iwc5s7//GTOoobanpxHbrQxqftfmYJooY +jWx2SEj1IWWesOp3uRUuldgfLDu9i5jr3uY9NaCHp4Q41sf/ww2Qa9SimPJWPVyi +F/UxYmasnygere/dEwEBbF7Qt9WWAFmgWEePG5OTkQKBgQDpG11wtp/KN74S70YN +StbsCnYqWjnfjwiUF0v45uqxMlcaF/i7/M/REyQgZ4c4pimdqLQiz+M1CLoG6K6v +XetK8waskxbduXtogjTZq0IbemLyLb0aw8hxb/VLP2DTOa/y21zKVSznT5RmEHuF +mMfeYVUjg70QqbpTvSP6NcSQ+QKBgQDQW+pO0vV52i6fvcLR/wRXxHdpOKyq/7SL +ugdWPiEZBSRdRT6L4pPDA0cbASsf79sYLiwqV9WlpKh4VXePot7xwU7w59AqWWrn +M3Oed9PtLZYMyKd1Udqx8nvkgHqmDEUw8q3iG7EcwT6FYMbfiKCdfiVYcMooHOeJ +NI3EKGlCDwKBgQDfUmooi612DAU7GqSgI2zX4gXm+V2sgdmUFuWf5Yo+jJ3Jz+Fq +J//oq0/XA5gWe4ovEurQ1x0zN9MQv2Zrd6zttvpT5u7nKMXED8oWJu5EaPHWVl9u +/tZPZxU3K9bVRdT8849oAEXurNzdEzljekUxFUp9pb5B8nkhtHh9Q3m38QKBgQCQ +mVlwvsMRf7OftKgB6MNwza45XdWnDrKTzdTNq2x42rKz8BxKJEJ7skikmxj8nw8k +JtcLw81HmZA5gsbo7hVfHdLVKWu0GD4ymeiBb5OqJFrgIFjm+JmXqTsGB4wWtKlI +IQM/ygwOcqYbFmCuPTmKU0NDr3L8h6K/+7LvEUSLTQKBgB7mHVR3IS08w8rdJi3v +Ej72UYtPDbCSkEwf2/grdfwSqPFq/BGCOJjRn9D/cHIS9g/OOBkssJX/TI3PHA17 +mrtwF2F93H4wWptnmjyNnApIvndE5IoPNMZhTtsdk7+D/2QcSMaUtfv8dCi8E6K6 +OQsbnf32CLR2ef1inNhCFBuO +-----END PRIVATE KEY----- diff --git a/oci/single_server/provider.tf b/oci/single_server/provider.tf new file mode 100644 index 0000000..e65d81e --- /dev/null +++ b/oci/single_server/provider.tf @@ -0,0 +1,28 @@ +terraform { + required_providers { + oci = { + source = "oracle/oci" + version = ">= 4.0.0" + } + acme = { + source = "vancluever/acme" + version = ">= 2.0" + } + tls = { + source = "hashicorp/tls" + version = ">= 4.0.0" + } + } +} + +provider "oci" { + tenancy_ocid = var.tenancy_ocid + user_ocid = var.user_ocid + fingerprint = var.fingerprint + private_key_path = var.private_key_path + region = var.region +} + +provider "acme" { + server_url = local.letsencrypt_server_url +} diff --git a/oci/single_server/settings.tfvars b/oci/single_server/settings.tfvars new file mode 100644 index 0000000..4e9dbd5 --- /dev/null +++ b/oci/single_server/settings.tfvars @@ -0,0 +1,43 @@ +## Kasm deployment settings +oci_domain_name = "kasm.contoso.com" +project_name = "contoso" +vcn_subnet_cidr = "10.0.0.0/16" + +## OCI Authentication variables +tenancy_ocid = "changeme" +user_ocid = "changeme" +compartment_ocid = "changeme" +fingerprint = "changeme" +private_key_path = "./oci-private-key.pem" +region = "us-ashburn-1" + +## Load Balancer SSL Keys +# Terraform auto-generated Let's Encrypt keys +letsencrypt_cert_support_email = "" +letsencrypt_server_type = "" + +# Bring your own - Load Balancer SSL Keys +kasm_ssl_crt_path = "" +kasm_ssl_key_path = "" + +## VM Access subnets +allow_ssh_cidrs = ["0.0.0.0/0"] +allow_web_cidrs = ["0.0.0.0/0"] + +## Kasm passwords +admin_password = "changeme" +user_password = "changeme" + +## SSH Public Keys +ssh_authorized_keys = "changeme" + +## OCI VM Settings +instance_image_ocid = "ocid1.image.oc1.iad.aaaaaaaahiz6xym3a76xhwkmwmhrz6luyiehho7dpxpkphxhsq5q6z4m3nlq" +instance_shape = "VM.Standard.E4.Flex" +swap_size = 2048 +kasm_server_cpus = 2 +kasm_server_memory = 2 +kasm_server_hdd_size = 120 + +## Kasm download URL +kasm_build_url = "https://kasm-static-content.s3.amazonaws.com/kasm_release_1.12.0.d4fd8a.tar.gz" diff --git a/oci/single_server/variables.tf b/oci/single_server/variables.tf new file mode 100644 index 0000000..46e9fd3 --- /dev/null +++ b/oci/single_server/variables.tf @@ -0,0 +1,268 @@ +variable "project_name" { + description = "The name of the deployment (e.g dev, staging). A short single word" + type = string + + validation { + condition = can(regex("^[a-z]{1,15}", var.project_name)) + error_message = "The project_name variable can only be one word between 1 and 15 lower-case letters since it is a seed value in multiple object names." + } +} + +variable "oci_domain_name" { + description = "The public Zone used for the dns entries. This must already exist in the OCI account. (e.g kasm.contoso.com). The deployment will be accessed via this zone name via https" + type = string + + validation { + condition = can(regex("^[a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,6}", var.oci_domain_name)) + error_message = "There are invalid characters in the oci_domain_name - it must be a valid domain name." + } +} + +variable "tenancy_ocid" { + description = "The Tenancy OCID." + type = string + + validation { + condition = can(regex("^(ocid\\d)\\.(compartment|tenancy)\\.(oc\\d)[.]{1,}[a-z0-9]{60}", var.tenancy_ocid)) + error_message = "The tenancy_ocid must be a valid Oracle Cloud Tenancy OCID value (e.g. ocid1.tenancy.oc1..aaaaaaaaba3pv6wkcr4jqae5f44n2b2m2yt2j6rx32uzr4h25vqstifsfdsq)." + } +} + +variable "user_ocid" { + description = "The User OCID." + type = string + + validation { + condition = can(regex("^(ocid\\d)\\.(user)\\.(oc\\d)[.]{1,}[a-z0-9]+", var.user_ocid)) + error_message = "The variable user_ocid must be a valid Oracle Cloud User OCID." + } +} + +variable "compartment_ocid" { + description = "The Compartment OCID" + type = string + + validation { + condition = can(regex("^(ocid\\d)\\.(compartment|tenancy)\\.(oc\\d)[.]+[a-z0-9]{60}", var.compartment_ocid)) + error_message = "The compartment_ocid must be a valid Oracle Cloud Compartment OCID value (e.g. ocid1.compartment.oc1..aaaaaaaaba3pv6wkcr4jqae5f44n2b2m2yt2j6rx32uzr4h25vqstifsfdsq)." + } +} + +variable "region" { + description = "The OCI Region eg: (us-ashburn-1)" + type = string + + validation { + condition = can(regex("^([a-z]{2}-[a-z]{5,}-[\\d]{1})$", var.region)) + error_message = "The provider-oci_deployment_region must be a valid Oracle Cloud (OCI) Region name, e.g. us-ashburn-1" + } +} + +variable "fingerprint" { + description = "API Key Fingerprint" + type = string + + validation { + condition = can(regex("^([a-f0-9]{2}:?){16}$", var.fingerprint)) + error_message = "The API fingerprint is incorrectly formatted. It should be 16 colon-delimited hex bytes (e.g. 12:34:56:78:90:ab:cd:ef:12:34:56:78:90:ab:cd:ef)." + } +} + +variable "private_key_path" { + description = "The path to the OCI API Key PEM encoded Private Key" + type = string + sensitive = true + + validation { + condition = can(fileexists(var.private_key_path)) + error_message = "The variable private_key_path must point to a valid OCI API Key file." + } + + validation { + condition = !can(regex("replaceme", file(var.private_key_path))) + error_message = "You must enter a valid OCI API Private key in the file located at the private_key_path." + } +} + +variable "vcn_subnet_cidr" { + description = "VCN Subnet CIDR where you wish to deploy Kasm" + type = string + + validation { + condition = can(cidrhost(var.vcn_subnet_cidr, 0)) + error_message = "The vcn_subnet_cidr must be a valid IPv4 Subnet in CIDR notation (e.g. 10.0.0.0/24)." + } +} + +variable "ssh_authorized_keys" { + description = "The SSH Public Keys to be installed on the OCI compute instance" + type = string + + validation { + condition = can(regex("^ssh-rsa\\s+[A-Za-z0-9+/]+[=]{0,3}(\\s+.+)?\\s*$", var.ssh_authorized_keys)) + error_message = "The ssh_authorized_keys value is not in the correct format." + } +} + +variable "instance_image_ocid" { + description = "The OCID for the instance image , such as ubuntu 20.04, to use." + type = string + + validation { + condition = can(regex("^(ocid\\d)\\.(image)\\.(oc\\d)\\.[a-z]{3,}\\.[a-z0-9]{60}", var.instance_image_ocid)) + error_message = "The compartment_ocid must be a valid Oracle Cloud Compartment OCID value (e.g. ocid1.image.oc1.iad.aaaaaaaahiz6xym3a76xhwkmwmhrz6luyiehho7dpxpkphxhsq5q6z4m3nlq)." + } +} + +variable "allow_ssh_cidrs" { + description = "The CIDR notation to allow SSH access to the systems." + type = list(string) + + validation { + condition = can([for subnet in var.allow_ssh_cidrs : cidrhost(subnet, 0)]) + error_message = "One of the subnets provided in the allow_ssh_cidrs list is invalid." + } +} + +variable "allow_web_cidrs" { + description = "The CIDR notation to allow HTTPS access to the systems." + type = list(string) + + validation { + condition = can([for subnet in var.allow_web_cidrs : cidrhost(subnet, 0)]) + error_message = "One of the subnets provided in the allow_web_cidrs list is invalid." + } +} + +variable "letsencrypt_cert_support_email" { + description = "Email address to use for Let's Encrypt SSL certificates for OCI Deployment" + type = string + default = "" + + validation { + condition = can(var.letsencrypt_cert_support_email == "" ? true : can(regex("^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$", var.letsencrypt_cert_support_email))) + error_message = "The ssl_cert_support_email must be a valid email address format." + } +} + +variable "letsencrypt_server_type" { + description = "SSL Server type to generate. Valid options are staging and prod, and prod certificates are limited to 5 certificates per week." + type = string + default = "" + + validation { + condition = can(contains(["staging", "prod", ""], var.letsencrypt_server_type)) + error_message = "Allowed values for the letsencrypt_server_type variable are: staging, prod, and empty string. For reference: Staging generates certificates that a browser will not trust, but are formatted correctly to apply to resources; while Prod generates valid, useable, trusted certificates. NOTE: Prod certificate generation is limited to 5 times per week, so if you are testing Kasm or intend to possibly re-deploy multiple times, it is recommended to use Staging (which has a much higher generation limit since it is intended for testing) until you are ready to deploy your 'final' version. If you have your own CA and are bringing your own certificates, then copy/paste then set this value to an empty string." + } +} + +variable "kasm_ssl_crt_path" { + description = "The file path to the PEM encoded SSL Certificate. Leave this empty if you are using Lets Encrypt to automatically generate your certificates." + type = string + default = "" + + validation { + condition = can(var.kasm_ssl_crt_path == "" ? true : can(fileexists(var.kasm_ssl_crt_path))) + error_message = "The variable kasm_ssl_crt_path must point to a valid OCI API Key file or be left empty (using Terraform-generated Lets Encrypt certificates)." + } + + validation { + condition = can(var.kasm_ssl_crt_path == "" ? true : !can(regex("replaceme", file(var.kasm_ssl_crt_path)))) + error_message = "You must enter a valid SSL Cert in the file located at the kasm_ssl_crt_path or be left empty (using Terraform-generated Lets Encrypt certificates)." + } +} + +variable "kasm_ssl_key_path" { + description = "The file path to the PEM encoded SSL Certificate Key. Leave this empty if you are using Lets Encrypt to automatically generate your certificates." + type = string + sensitive = true + default = "" + + validation { + condition = can(var.kasm_ssl_key_path == "" ? true : can(fileexists(var.kasm_ssl_key_path))) + error_message = "The variable kasm_ssl_key_path must point to a valid OCI API Key file or be left empty (using Terraform-generated Lets Encrypt certificates)." + } + + validation { + condition = can(var.kasm_ssl_key_path == "" ? true : !can(regex("replaceme", file(var.kasm_ssl_key_path)))) + error_message = "You must enter a valid SSL Cert in the file located at the kasm_ssl_key_path or be left empty (using Terraform-generated Lets Encrypt certificates)." + } +} + +variable "user_password" { + description = "The standard (non administrator) user password. No special characters" + type = string + sensitive = true + + validation { + condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.user_password)) + error_message = "The User Password should be a string between 12 and 30 letters or numbers with no special characters." + } +} + +variable "admin_password" { + description = "The administrative user password. No special characters" + type = string + sensitive = true + + validation { + condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.admin_password)) + error_message = "The Admin password should be a string between 12 and 30 letters or numbers with no special characters." + } +} + +variable "swap_size" { + description = "The amount of swap (in MB) to configure inside the compute instances" + type = number + + validation { + condition = var.swap_size >= 1024 && var.swap_size <= 8192 && floor(var.swap_size) == var.swap_size + error_message = "Swap size is the amount of disk space to use for Kasm in MB and must be an integer between 1024 and 8192." + } +} + +variable "kasm_server_cpus" { + description = "The number of CPUs to configure for the Kasm instance" + type = number + + validation { + condition = can(var.kasm_server_cpus >= 2) + error_message = "Kasm Webapps should have at least 2 CPUs to ensure enough resources for Kasm services." + } +} + +variable "kasm_server_memory" { + description = "The amount of memory to configure for the Kasm instance" + type = number + + validation { + condition = can(var.kasm_server_memory >= 2) + error_message = "Kasm Webapps should have at least 2 GB Memory to ensure enough resources for Kasm services." + } +} + +variable "kasm_server_hdd_size" { + description = "The size in GBs of the Kasm instance HDD" + type = number + + validation { + condition = can(var.kasm_server_hdd_size >= 120) + error_message = "Kasm Webapps should have at least a 120 GB HDD to ensure enough space Kasm Workspaces images." + } +} + +## Non-validated variables +variable "kasm_build_url" { + description = "The URL for the Kasm Workspaces build" + type = string +} + +variable "instance_shape" { + description = "The instance shape to use. Should be a Flex type." + type = string +} + +## Local for Let's Encrypt staging/prod URL selection +locals { + letsencrypt_server_url = var.letsencrypt_server_type == "prod" ? "https://acme-v02.api.letsencrypt.org/directory" : "https://acme-staging-v02.api.letsencrypt.org/directory" +} diff --git a/oci/standard/README.md b/oci/standard/README.md index 5992457..9eceb10 100644 --- a/oci/standard/README.md +++ b/oci/standard/README.md @@ -8,7 +8,6 @@ This project will deploy Kasm Workspaces in a multi-server deployment in OCI. - # Pre-Configuration Consider creating a new Compartment for the Kasm Workspaces deployment. @@ -16,18 +15,17 @@ Consider creating a new Compartment for the Kasm Workspaces deployment. In OCI create a public DNS zone that matches the desired domain name for the deployment. e.g `kasm.contoso.com`. ### API Keys -Create an administative user the OCI console that will be used for the terraform deployment. Add the user to the -**Administrators** Group. Generate an API Key for the user. The API Key Fingerprint will be used as a variable -in the deployment configuration. Save the private key to the local directory replacing `oci-private-key.pem`. +Create an administative user in the OCI console that will be used for the terraform deployment. Add the user to the **Administrators** Group. Generate an API Key for the user. The API Key Fingerprint will be used as a variable in the deployment configuration. Save the private key to the local directory replacing `oci-private-key.pem`. -### SSH Authorized Keys -The project will install an SSH key(s) inside the OCI compute instance(s). Update `authorized_keys` in this directory -with the desired SSH public keys. - -### SSL Certificate -Create an SSL certificate that matches the desired domain for the deployment. e.g (kasm.contoso.com). Place the pem encoded -cert and key in this directory overwriting `kasm_ssl.crt` and `kasm_ssl.key`. +### SSL Certificate Options +#### Terraform-generated Let's Encrypt Certificate +To use Terraform to generate a Let's Encrypt certificate automatically, set the `letsencrypt_cert_support_email` to a valid email address and set the `letsencrypt_server_type` to either "staging" or "prod" and leave the `kasm_ssl_crt_path` and `kasm_ssl_key_path` variables empty. +***NOTE:*** +- Staging generates certificates that a browser will not trust, but are formatted correctly and are designed for testing and validating the system configuraiton and deployment and has a limit of hundreds of certificates per domain per week. +- Prod generates valid Let's Encrypt certificates but is limited to 5 certificates per week per domain. +#### Bring Your Own Certificates +Create an SSL certificate that matches the desired domain for the deployment. e.g (kasm.contoso.com). Place the pem encoded cert and key in this directory overwriting `kasm_ssl.crt` and `kasm_ssl.key`. # Terraform Configuration @@ -36,20 +34,60 @@ cert and key in this directory overwriting `kasm_ssl.crt` and `kasm_ssl.key`. terraform init -2. Open `deployment.tf` and update the variables. The variable definitions and descriptions -can be found in `module/variables.tf` +2. Open `settings.tfvars` and update the variables. The variable definitions, descriptions, and validation requirements can be found in `variables.tf`, or in the [table](#oci-terraform-variable-definitions) below. - 3. Verify the configuration - terraform plan + terraform plan -var-file settings.tfvars 4. Deploy - terraform apply + terraform apply -var-file settings.tfvars + +5. Login to the Deployment as an Admin via the domain defined e.g `https://kasm.contoso.com`. It may take several minutes for the deployment to fully come online. -5. Login to the Deployment as an Admin via the domain defined e.g `https://kasm.contoso.com`. It may take several minutes -for the deployment to fully come online. +# OCI Terraform Variable definitions + +| Variable | Description | Variable type | Example | +|:--------:|-------------|---------------|---------| +| `tenancy_ocid` | The OCI Tenancy OCID | String | `"ocid1.tenancy.oc1..aaaaaaaaai06vvcguozt39d4ilmwtpdovl998wsxpyn0hjkab2kuh7z16po7"` | +| `compartment_ocid` | The OCI Compartment OCID | String | `"ocid1.compartment.oc1..aaaaaaaauepg1z967huiazuiwjt80rtbszp64x9oxaidkoi7wz0pgr950bzb"` | +| `region` | The OCI Region name | String | `"us-ashburn-1"` | +| `user_ocid` | The OCI User OCID | String | `"ocid1.user.oc1..aaaaaaaau3me8nojmdjrbj2vzfxeouscc1i7cf9w0aoy0iyv9b38t2y0a1ba"` | +| `fingerprint` | The OCI User API Key fingerprint | String | `"66:e5:d1:85:cd:ba:ca:6a:d0:76:86:ef:1c:11:63:97"` | +| `private_key_path` | The path for the API Key PEM encoded Private Key for the OCI User. ***NOTE:*** *Ensure the API Key contents are a valid PEM encoded RSA key file. You can tell this by ensuring that the value `-----BEGIN RSA PRIVATE KEY-----` is the first line in the key file. Otherwise, you can validate the key file by running the `openssl rsa -in oci-private-key.pem -check` command.* | String | `"./oci-private-key.pem"` | +| `project_name` | The name of the deployment (e.g dev, staging). A short single word of up to 15 characters. | String | `"kasm"` | +| `oci_domain_name` | The public Zone used for the dns entries. This must already exist in the OCI account. (e.g kasm.contoso.com). The deployment will be accessed via this zone name using https. | String | `"kasm.contoso.com"` | +| `letsencrypt_cert_support_email` | Email address to use for Terraform-generated Let's Encrypt SSL certificates | String | `"support@contoso.com"` | +| `letsencrypt_server_type` | SSL Server type for certificate generation. Valid options are staging, prod, and empty string (""). Refer to [SSL Certificate Options](#ssl-certificate-options) section of this document for more information. | String | "prod" | +| `kasm_ssl_crt_path` | Bring Your own Certificate - The file path fo the PEM encoded SSL Certificate file generated outside of Terraform. Copy/paste the contents of your generated SSL Certificate to the file designated in this path variable. | String | `"./kasm_ssl.crt"` | +| `kasm_ssl_key_path` | Bring Your own Certificate - The file path to the PEM encoded SSL Private Key file generated outside of Terraform. Copy/paste the contents of your generated SSL Private Key to the file designated in this path variable. | String | `"./kasm_ssl.key"` | +| `vcn_subnet_cidr` | The OCI VCN Subnet CIDR of the VCN where you wish to deploy Kasm | String | `"10.0.0.0/16"` | +| `ssh_authorized_keys` | The SSH Public key to be installed on the Kasm servers for SSH access | String | `"ssh-rsa some_base64_encoded_ssh_public_key_data"` | +| `instance_image_ocid` | The OCI Image OCID value of the OS to use. Kasm recommends using lates Ubuntu 20.04 LTS-Minimal for speed and efficiency. | String | `"ocid1.image.oc1.iad.aaaaaaaahiz6xym3a76xhwkmwmhrz6luyiehho7dpxpkphxhsq5q6z4m3nlq"` | +| `allow_ssh_cidrs` | A list of subnets in CIDR notation allowed to SSH into your kasm servers | List(String) | `["10.0.0.0/16","172.217.22.14/32"]` | +| `allow_web_cidrs` | A list of subnets in CIDR notation allowed Web access to your kasm servers | List(String) | `["0.0.0.0/0"]` | +| `num_webapps` | The number of WebApp role servers to create in this deployment. Acceptable ranges from 1-3. | Number | `2` | +| `num_agents` | The number of static Kasm Agents to create in this deploymenbt. Acceptable ranges from 0-100. | Number | `2` | +| `num_guac_rdp_nodes` | The number of Guacamole RDP access servers to create in this deployment. Acceptable ranges from 0-100. | Number | `1` | +| `database_password` | The Kasm PostgreSQL database password. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` | +| `redis_password` | The Kasm Redis password. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` | +| `admin_password` | The Kasm Administrative user login password. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` | +| `user_password` | A Kasm standard (non-administrator) user password. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` | +| `manager_token` | The manager token value used by Kasm agents to authenticate to the Kasm WebApps. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` | +| `service_registration_token` | The service registration token value used by Guac RDP servers to authenticate to the Kasm Webapps. String from 12-30 characters in length with no special characters. | String | `"1qaz2wsx3EDC4RFV"` | +| `kasm_build_url` | The download URL for the desired Kasm Workspaces version. | String | `"https://kasm-static-content.s3.amazonaws.com/kasm_release_1.12.0.d4fd8a.tar.gz"` | +| `swap_size` | The amount of swap (in MB) to configure inside the Kasm servers. | Number | `2048` | +| `instance_shape` | The OCI instance shape to use for Kasm deployment. Kasm recommends using a Flex instance type. | String | `"VM.Standard.E4.Flex"` | +| `kasm_webapp_vm_settings` | The number of CPUs, memory in GB, and HDD size to use for Kasm WebApps. | Map(Any) |

{
  cpus = 2
  memory = 2
  hdd_size_gb = 50
}
| +| `kasm_database_vm_settings` | The number of CPUs, memory in GB, and HDD size to use for the Kasm Database server. | Map(Any) |
{
  cpus = 2
  memory = 2
  hdd_size_gb = 50
}
| +| `kasm_agent_vm_settings` | The number of CPUs, memory in GB, and HDD size to use for the Kasm Agent server(s). | Map(Any) |
{
  cpus = 4
  memory = 8
  hdd_size_gb = 120
}
| +| `kasm_guac_vm_settings` | The number of CPUs, memory in GB, and HDD size to use for the Kasm Guac RDP server(s). | Map(Any) |
{
  cpus = 4
  memory = 4
  hdd_size_gb = 50
}
| +# Detailed Terraform Deployment Diagram + +![Detailed Diagram][Detailed_Diagram] + +[Detailed_Diagram]: ./diagram/oci_multi_server.png "Detailed Diagram" diff --git a/oci/standard/authorized_keys b/oci/standard/authorized_keys deleted file mode 100644 index 5d6af95..0000000 --- a/oci/standard/authorized_keys +++ /dev/null @@ -1 +0,0 @@ -replaceme \ No newline at end of file diff --git a/oci/standard/deployment.tf b/oci/standard/deployment.tf index 6d770d8..842eeba 100644 --- a/oci/standard/deployment.tf +++ b/oci/standard/deployment.tf @@ -1,29 +1,44 @@ module "kasm" { - source = "./module" - oci_domain_name = "kasm.contoso.com" - project_name = "contoso" + source = "./module" + oci_domain_name = var.oci_domain_name + project_name = var.project_name + kasm_build_url = var.kasm_build_url + vcn_subnet_cidr = var.vcn_subnet_cidr - tenancy_ocid = "" - user_ocid = "" - compartment_ocid = "" + ## OCI Auth information + tenancy_ocid = var.tenancy_ocid + compartment_ocid = var.compartment_ocid + user_ocid = var.user_ocid + fingerprint = var.fingerprint + private_key_path = var.private_key_path + region = var.region + ssh_authorized_keys = var.ssh_authorized_keys - fingerprint = "" - private_key_path = "./oci-private-key.pem" - ssh_authorized_keys = "./authorized_keys" - kasm_ssl_crt_path = "./kasm_ssl.crt" - kasm_ssl_key_path = "./kasm_ssl.key" + ## SSL Certificate values + # Let TF generate Let's Encrypt SSL Certificates automatically + letsencrypt_cert_support_email = var.letsencrypt_cert_support_email + letsencrypt_server_type = var.letsencrypt_server_type + # Bring your own SSL Certificates + kasm_ssl_crt_path = var.kasm_ssl_crt_path + kasm_ssl_key_path = var.kasm_ssl_key_path - region = "us-ashburn-1" - instance_image_ocid = "ocid1.image.oc1.iad.aaaaaaaafg6lg7dejwjebjqontwzyvutgf6qs5awyze6fgoiqepyj5qkvcuq" - num_agents = "2" - num_webapps = "2" + instance_image_ocid = var.instance_image_ocid + instance_shape = var.instance_shape + num_agents = var.num_agents + num_webapps = var.num_webapps + num_guac_rdp_nodes = var.num_guac_rdp_nodes + kasm_agent_vm_settings = var.kasm_agent_vm_settings + kasm_database_vm_settings = var.kasm_database_vm_settings + kasm_webapp_vm_settings = var.kasm_webapp_vm_settings + kasm_guac_vm_settings = var.kasm_guac_vm_settings + allow_ssh_cidrs = var.allow_ssh_cidrs + allow_web_cidrs = var.allow_web_cidrs + swap_size = var.swap_size - kasm_build_url = "https://kasm-static-content.s3.amazonaws.com/kasm_release_1.9.0.077388.tar.gz" - allow_ssh_cidr = "0.0.0.0/0" - allow_web_cidr = "0.0.0.0/0" - manager_token = "changeme" - admin_password = "changeme" - user_password = "changeme" - redis_password = "changeme" - database_password = "changeme" -} \ No newline at end of file + manager_token = var.manager_token + admin_password = var.admin_password + user_password = var.user_password + redis_password = var.redis_password + database_password = var.database_password + service_registration_token = var.service_registration_token +} diff --git a/oci/standard/diagram/oci_multi_server.drawio b/oci/standard/diagram/oci_multi_server.drawio new file mode 100644 index 0000000..0542cc8 --- /dev/null +++ b/oci/standard/diagram/oci_multi_server.drawio @@ -0,0 +1,191 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/oci/standard/diagram/oci_multi_server.png b/oci/standard/diagram/oci_multi_server.png new file mode 100644 index 0000000000000000000000000000000000000000..5578b24a7cb9276e79ad2b75eb75d7c2a0707742 GIT binary patch literal 217262 zcmeFaTdw2CvM9DM3>d}*?gR|OfIk|zhS3Fz4~hEZQ=%l2qC`EYp98)`k)lXRq(q7{ zFyH|g9)#!M0od>~JPSvV)LL4r)~c@B-PPS^A60ji_(*0(Mn*(NL`FvbuTyRCU;gud z|DXTykAM6ZWhl=6@sI!Je}TXM$A9MrY#(=O>iIF0@yg~4is=zeE#9qp@+(br zndVV&zBk@^eJ~HJwzW?CWpD{SKWn~j3+8DGFdW}Lbkij9-TX~K`+QD|x5c(;+;+LG z>}Ut~78@||!Q8duub-|$FW^7aM(v!AqWfBS>YK3-XZqYy;KD8o|kEC06om1;VDwc|_M z;a|vZ4E6Ca{@nmCnsJ}`L6|1@m%otm%loE=EWh1RR_wyupC4@(Yb<~;ppspFh~cgS zmv$Tm30%ki7OUT;NiN%mFh&y5&$bKIki^_hVBmNlvOI*r;M#BU6e|Ooj)gQ%&+x@B zBqcL4EdwRiRXseXI;2Q)@I1@U>E3^M)0g^eAHO)Km&EgtB5KIaZcBjo+S=O=zRjRV zVG_*Rv1Z^A5M6GE32*`>60b!jbWKR@392kqNm z**h1tOw=Xr#8Jq+`VXKPQ5FS}ZL4~qjNd^sNDxTO^Oh43 z^7jPtN039eM}A>izI~yHyVQB0h)$RNLUfxJ-w*}$vxuUV><_}^Gok?M!^!1epD4P2 z5>ZfyPekcADFP^mXes9{MYK%%hl`1p{2nOcK7%|=AI*G&tOM}7FLJ$my5Q6ZB9w9* zrqglZ)0aoh)HJp;)MA!`2LJvFe>=pN`ah6q9ca6q$3v z`NOlb-RsoyyC*%6t$xhg?mnm|t-H)h(gdd2H&f#M5g_zl3UJ6tOqUd(=vTAh%bWMo zs-5xv=;@4Z<E4%Cad^iJ{kHZu%s`P}K%gQ1|8QpL z|4GcieUs3BIx~RE^vSfa@*VDYM8)cB2=6|iZ?N&dK8s{~KX=h7gyw$`+Zh_#c>U^G zz`H+3v-*mYI^@@y)u)rnPcsYeo{2Zw)jN3!&aor9i^4goLyg?r zc-mQ&7q=opdpILpF}+SGkMeE|rQVpUdvLF6#1*R0ue^gBD#Kmw446t!cA33m&eQoQ z^@g)T57{exMNJa7njHGK&5bQ}bI(kurkoP;{b6Voh#)el0sz=@8NsZTF0>) zvn7kp0;3L!!JjDDc)M(4h*iA(r6l%BAi~ZyEXgcI~-XI8EYQ_LmedVw@ zI)kFC5Szhl4}YT!FktkRJyEH1`Zf^_z{)b3n94;Lieh3eF6xcA;jca?h)J|dC#HK* zS8A>bG&vEKi*_R__zubwok_IMG=Ziqd={yhDi9>r1!dsZIw+M?=r=3U%?z&hy-}z# zI;lcC%0-MnA2KNYul|kRJEf{0Ki$D|YFN`6d)%ZtvBQFA6 z&=V2cF94^|pZXW*V6Rr%4Zm0ENfcyiWdLji0p$UQh*u@k;5%)dhLcx%{1FX-8QR93AIKh4aTqM9_)_s8Qjl8M1`TYb} zztJY(E^J|#Bb_%ewKUPvqKm)KE(iQkwB=od8E^ym5@@EyC%^>vH>C4r1hm+U(;UZt zfpp*W^>aFGzOVUB!giod#MLW*>J5JaE^69`@-dY4APt6UPajL*HQB;J&6={QZ=N8a~B7qFiWjS@+qkUhbRm zMtEx60goe&pne!<=o8QwiL`2r&V`c=#O z5BqIZbzh)Qb$x*MwofM9w=%n#H=sW3D?V?=_cK@#4xj^&qYW;wJoF7{3gNl)P z$D*FMP&VLL1I^*spiBb1!I*Zxc>Nj zKN2*PD~;-PzDL@JcFTqy5cfEbBacB}8XiM@Able3HZa#?S(iZ`!#*`UcBtn*>=WRx zmPIeJ>=Stla;26`u#?*55?VQr!9oob`0S}{W`-Hz7tW!WahEGixP2IB&7*7{q`2Y@G}twp@MO*WfkD~8#t-wqIQg-zldLuzaPW7r~;J9sMEpR-Cn~uA-)=!F999b@*Z_Y zsOJ^;Zaas7P71i0A-)iwpkKh8EUQ3UKr5gNH**H`4X@W}V4B!3)P?JLv!TZZPf!nh zJA`lRdw^a1gf^&p9)&pt=l_COR85`jy#7-Eo&I1R!#TeLav9(PogZ}lh6VzJ8O8w{xB}kR;@GFWg2=w9T??!ql4i5MtvgVY8?q+#P3=i33U#niH44V zhMTcR`hA=mN&H(Oqi(o2;W>c z?)>%w0r+#@F9g8i0TAhPncxFX`ZROtK1S)6k0Vc0u}|}xzs$5_Jl5iqaNrlp% z)d-yadEy@W9p_+lox_q+L=G1TDwv|HrY_~X7YS4_Db;F^Z9`DG1TY1q78&5)-^KRI zOTBs_0m=Z(P=?e^gH|Ks2KV91O??Y70>tC3@!ITcs?2%VsnpEK4 z0W%NX=`__`gDV@Zy-0#@K2fDmJwaDS*qUEx&Vj1gxZ)%*5j{{*;C-!{kJLwa-?&m`3&T2`r)LHzn8rZb9V)R~4u<;NolG1d|?A^#;xns+OR7*QzF{ zN@!Yv+KVbPsGOj_;8F*?M-!Va>!k=-iUHi!CK{M8@C~?O8Z#Hv94H64(>_t%K}`kq z3fx(>8V<`RXyTdmFTISwT;7Aa)v8(Q9L#iZd4Wn&bCA<+n~oeJ2K+CczD@!hBfqY|A$fPvar z0jL23z%}q5C<-wMJqKeP4e7?g2t9{ur0RN6rp7Q(6pU`iLc{4}#htkK6yPG7#TB3~ zvNkM`3P6#EdvHK_V9j!WQ>vFr(A5b{^E! z1jYs$(_httoS0xets#m=5s8LL%{ey*7XH*v94o+887`~XdLgTT732?~%GTBONR_ypCW1?1fV>Q@irPg4d?p|zBhR6G2QV_I`LmW;uly-} zOnD#|fFgjZ>U!`R+(l^OL;bZJtauz@3lg@(sBN`U-vfOa?V_6XY_Mt<6jV>O<2RVTEPy7&&Xxa9%Bc z;^sO;w`dGp0`LvrFMp0e5*Yyo4rnk}_@D!*2s2!Ny)6IWrXPC8&2W~&Vn6g90~KE9 zaiqGhslXviW<&NbAI#8?lu$TieDQ`Vgf`%U14w&Q2|yD-%z&)nkdM&`2NHV^&p}p! z^97_kXeT&xqT@w{S?i@7seps=zM%gVR5y^ogfa}EH4NOqfC{B}qYt(7sj*i&Dr^-& z$?1{t9>Nx&EJ&8Ofe*-m@0XXa&M;0KlKu^R@>d8J0k;_7Kf)f=ZoyI!71ZURS1_O6 zpjWl)2kBA@nrF@Y4CSD0kWzpVDA&59@LR+lJ_9ZVedVP-qy^!VCB;g?`5)?n83Ed? zd7*{_>%wO>#{f2*A=cG~OxzxpgK#D~EF({-16L@(Edw-jgBgVW>+xLkI>Lf@ z21$r|3od!wsYjvVIm~Q`SCEK8jaQI@3h*6LAIO;6bp+pkN@ed{IxllHJpY$=?~o(} z6B0Dhr&+c`^;vKWV5HZJK}wKc(62+%Bsy{0_{vA`4n#Khx_zqKXS?uE8xy^I*waRS z;{W;MojV_GUU`PC{gkk^8(NlcB*Sl8q!4b#fh7xz#~6Ai9xJelBD7}R;V5>=<;^=R z;N8oNh2d%cRJhvfTnTa*=D1pxfqcN)UxMsDvO6Dw<=)Pf5R&wMzWCmdIIv%f(u<5@ zE`kQU2;d%;#zc@+1JDr`K{*$BQe9hwIvtJFl|WXJ34>hCD2cF(4!jN z6T{-ZTlWNgN?SOvPU{!SPMZm+fU7p|^tr8!88MnVA<01Y-ATuTPv zez3RDcY^+(TB?A>iWUT58>J0u#xK&Q4hFkR8?-EHJL_X90g?v%HXz~A`heLI+i2=S z-_E^_AC?rz`F|}H*S;u#ANvISj26Nj=ZGKhI--Su78LX!r7!d!C=_hk2FGYwfz{vQ zxZ(FZo-mLT>Hvw}$e(ZHxNW<|aV^DL9M_iCy^Zg~aqudQ|9TwP0qPCz8cuIqifvD)pP#6 z97;ea*GdTp7eafvEf03|y&k~Y?K8hatFKf6>Le(G>pB`Kf#GyU@O>2gpijUkLE4(% z@V&fP20%GKNuL0o1n&aSsSe%+zzPP0G}vzV8)*wx=zz9fp4anyi(T|ifIMlii?RUp z4i&u|z)Y=*fsxEDQc$#8{)FAlKG9!G|+lqn{wnwt7olN2AYRh-B?=`%NF& zqh!GAAMlf*KkAKTi<0nB?|y6Fy}zSivs*<&NYOVUgg(z1@u$WPv3-aQ>Qe;4_8``w zN59L0(*f^N@0;GGPkcwazr?@vQPPR0f9dI8dis~z7>-BV^yyy`pZ=x0t^ULMAo%&7 z{v}+gt8JR6f9dI8`sX}&PyfO(O$kV^{GqL;h zFa1R9KK)BgyxV^m{}MzbePKGU{-t*7$~}0ArZBb%_N>u#pY8QN$k+I{axb-;-rnp@ zd%Bl?hIQI>H#+&EHo7as9&y6=Pn+2X5Z=M@(o*QqP ze4fvZH|_SW=f<1+NnSsmMV*1ue!A?Z8*hHwcK!Qoydm4Lj;H1N)AL0?Emuel@zK_u zXUd3Y$_Q8#flVJb4BCV+zGupaXUd4z)DzE?5w9DhpD81rDI?yU2 zhF}}bGi3zkfcX4)s$I9due$zrQ2*b^a{VYD=yT2WXRNtGx`=1W zi0?Z^>6tRZ#LfE8lo7D4>~;J7GiAgxWrUfHo+%@m?Vit+5%)weFR36Nx7t5bMl|Of z{gc}!U^6?UPJO0~z>_0?(zc0bNI#yV^_uSN8Pfk_DX9J?Ne$Yw*PbaO-Y1v+L$tML zNdJGhkbd?Ho)W__EWwa81F*TMPd?Am@cyiWw4d&!XGT&ugtyM5iRTPF zGm^d@);fI1TK>#PirMggp0bTcFXHy1dq%)#M$%_S()XEeA9B7vGm?Iq_Z9OSzGQ)X zW+Z)PB>l16#m|fpPxlh$fqiBqeP$%p9y8NDoL%&EFZ~B}FHyZu-AiP*^QH6eCSwHo zJn-hvaxXpi-8}c*Z0aLwUk~Mc9@Y9hsuhm0dLGr<9Qpb@suj|;J~Ku_Sye^86()vr~7Vx+jjl??7Lw;%5~U{^Y%m&K$V-u=^4*B zA-ktbiZ6a4DaT&^-(uyUNzr3@Tz_=zc`7XLp2gSsjGF)_jmUvzmW1v`G;rQ z6h^46=Ki>O_AyLUhxAArO1^;EfY5>5lV9jB1T;g!E~EEQjP2|I@C`0D_UCgD--7dQ zYf`ZbbANucT^}%2ob4l^X_p^jxa+`Wa|p~T^zvQ%#Iv)V@3l8}90mzo$Nu(?c-cOL zF~-{HXWNZ^0B~+68B}%k&w1$DG1q>Rr`XoxSu#nQ02DmJE4+*y#Ys$;6kcHY=#2|s z*kR)1XcJfx`V%I>q=rhQ;7Jn#^!u2nN5e=wMiO<2-j~*Y@_3vv{lN*w9g6(YZWQ~& z4=rZeBbA@IQ+|5xl;;jK{uv_l3=!%pht1I$6kUaQ-1Ywq5iHIG5b-njl{^nE zwpX*CiQ(s=GC%*oljor_KOe`>9cX{njQ2cL=4XZ+KM$4piP(LH2>pi(5$b+n=+{GK zTF=jY2O87=_jIUCxAl5G-Ag~+z4QzbdWHx+LxkWY`|NqB%=1v0{Y70`xaiyQLtc9x zD)T&4Mk@5%D;Daoi07d)&qHONhsrz;m5CM?bgbJk@h`zSy&S(kIs~JNlEim&+kx1Yy2{!-{yf!jw?loQ;RxCL zpBAROFQ7~IzjOd51nVJ)geAVPZGh9x4}%><*C6;E2nk}@dsPI{X>0q#V@kTueL;WL zzM#KDOo>a)Fq?k>Mn|zRiO?G?X;0`!E~SRk&}#A^&Y8*+`QD~Jv`Hxe@uAIlW&cM8W)*RDp3+ zshPS^38?o5Ne;>y7toegEiz54Gar-M8#u7P3c^9v~?H!XsG%>mXH4x@UgV_rPe zuQHI7q-yZ!e%xA!D&6lAB?-V0{$R1FsW3NYgEVw^UA2O-a9RD7d2V{OvMY#wNVb^sF~odsmD`; zHen1S3EL`Q9PpY!UTk<1cxlm$w{;`%9rEjI88N``fZv*D-=s6-E36lJGveqsZM5Ip zVx1TTD5xz5W7@*;3S0dwUbXOdmG@~@K9E2!qenubsC#k%h?P))J2=V<30O-Dn7IfN z#N0s5aE_EX>najH=Li_7`WMQ>_fqMB;;NgP0@-2xKW*TwS?>6k}6ow%h_j|Xk;L{I@&&{`{zL-EM1IK zfQ#0bR{gAT$EX0em8mBFZtn26eXIMlYTx}BRza50geDYqOSaHp^HV6IH&CP#vuU}; z;vne2NgN=rqzZn??~t!wVFH~_Fp5fzk;JM;))s4wK=0~zII<<27{=7eLhyGV)K~yY zsN1*UBrzD_m0H8P`RA}v)({+mydH=3r;yy zg?bF&A>22+AU~mw23N@=98G`kaD3m$Ooe`OpO4>NSKa|-{@1bU5Xmo++()tMeW}m( z;YgG>0q?LMK^A0Q#xLH-uzzinZ1(ZW5*&pfGDaDedSCgs)vqr$4n)`cWosqiw_jT% z59USpWAozS@gHwdv{CWTWyGJpjQF%Do)!gKN8d5yJuQl-Me(#KLY2{<76tfjo)$%; zrN7uUPmAJdQ7o;eMe(skakn?#?u+fTw|}v{@zMV9cZ)yS&OYKQPI#~b+=2 z24F{)u-%#zrbCU~+<4kql^68)+QS*)is^Mid6ai!DD}o%-Gh6DvziK3=%Wn^XTR)n zXTVf?(ww&lKJwHX&I&zbukh7>pv3vl6^!Q!#&ZP&R)d}^7?EyfusXHxJy$S3UPFDZ zU_4haU`^+_fe7Oq@1rI$3_Z$Bx00 z4dzYyD&f*S$Cx*2*8h z)YJ}C_Y2*74OSz_b_uABeXC>KUSHp1+1?Ce1KMK<9Mul~AHG1aQ^P0g1y$nd$7b>Q<@7f`E|Wn z>ffyu{r#ix@6w8H_p&{V-B;uFTy|acFU<+UsNcmHe6L#TICf(eLvUz#SGdCfmUr>+ z1HSMDCGZY$>=C1D9q=!3g#z1J>c1ghz2u5mF+1x}#*@`(XOVg09{L^UV04|sl2Sx2 zPz4Sah~RI8=Q_gDv3RW9fgItMFLyYKU2=Kz4hwka9XG=no^lN3mB1b>j~jAFwD+%D zw%F&g>vP%lx$OE}c74pt@mzL&F1s$sPq%E<8^&G&ET0?4o*Tzj&t=!YVA=JD?T~w1 zXS;lNzkOJWde}eqxMcV6_>W(;qZ;$#X>UBYl|2(xK*EA&qKbRchHoYicqXcNlX~Sh zG}h6pI4#&h-Qx%%{bSD*eSVV=X?LFWA1oSc*XW%O@> z>0WxjGI$avZXs|^g`n9QsgQhy< zvHZFU1p`0pBTAdrzw0p4cN^ed<3RDS&yONSA3{@O+!e>$?jEBc6YpI>YH+r_5LV~j zJ;ttldL$^moHy8l=ug--*B%Y}64d&5Iw&SfVPsmyBr46Zr1z%a%}aU}`|RFp>_fr( zj=p%eadH&YE z)W_WViN~GKX#s`OqYpbYd3Yj2kaYW1GicZwcmOwTPd^yNEWMoTqi>@k5I zu|l}y^;toT2SLigA8o$aNs9okWCQ-;3xQMNSD?c2)`Sa=TWj+fp>XGncDq=FnYpk1_|1=AzlG(qufMO< zXJ3EM^B-^F$G`X+k#G`%3++dVjoi zfFy#{#QgOUq)Dg0efJb=7CM_vHS;0JA#xY;(OY;If6r9g&XV5A5Jkj?gRvN`LS+xf zsPkG(+4E$0vrMdaw*V>Lq}2#= z?;&N5Txqv)0kd)`K?mF!=cWg?V&PTD&KEO&IoOH4WzsV`<#4d`2_Ow$!Bsp385Fc)SVlS z-&yyTsTNj~XITbeIM+m$-JoVOiuA~ZjLX-xH|00%bU7?96*;F*Mg@qIGZI;szpZ=2BCrioUsbnWUda>P;k(EEXx*>U z{f6!iA^N6ElVn%oPy1;l_AlLIWvbkj>W|ag+2MzI8CD`2W2FWT0ke*aRJg8o7c1Go z{RE*tHrLDc5kfm`1}bp&d+jz1AFM z&n4`*qbz#Gb|5%AGP;l_JD4-1fWYa4>IgMSU2|OtOZPg|_j_)A9^3mE^f9@lI+s2< zo5EBtZ#d7njx$xFM1QNww{d1!9B&aT%P^FAavg^(Pb+>#Ri1U(9gU%P4us&sq*BM$ zQm~77T`r4~NPAj`SxW`cDd%fCS*lbxkjWV%=_4pZj637&aFHLWVR1e0%F(TV4F~*+ zqqHL-2%YonX!3-3R*e2mJ_O@j?(bYFf(pxwWV)-#WPcfv!ECO@_LkLD9$ zpu>YRQRuy6%BPhu_PK?+$XAElVr(hQxgGGWbb~^GTbby_oqXjoQa+r~3#*`Z<#sa2 zY<>!c9xv=fNsf8sygvLLI6)$KJwu%hf)(VvR1fn>Z*eWVc}j4-;uK-Qc%vLQS+Q_p zvq-|tCESQ!R4HW|4Gv6vk~ae=#GVi2WHTH~)P503+=$ef9xu%{SMJE}4vsNaSXH4H z%k!ZcYV>V$2#V?PGAcWKaTq| zr)Lu6{Im}j=BCU}j49t-!C<+Ab6rSBg*ypHdJ(DdWjQ7clQ={Iz>yA3W7ZqW+$udg z+#!?XU9^R!(@|x`=hTX|c`Ws9+RZLk{zP=mLPp$O0*+jY8*wr{aVs@GA7d_|7Ms?jGK!WnP zjQP2Fi3<8^Dhng;iOb_j9~Hu4G2W&-W*{)5%(aa%LF>W!k|kXW(g(@LL7=-X%L)RS zOwwsyE=+AUCd2+l;mezhX_S136@hh@xD7Upp zP?tFy_4Q?95rzXGhU{e_3x{j64^DPpmEF^r>Cbg!GE=`9PQDrSWZz!TyCqDCtJ66+ zmZ97ANrlUCUK^B*Iiv=oa?GukX*~0S6V2O~QrnTiHCRW^EkDMQHI^U)a>VP^1tg(7 zCJ%-j213-V?9OmFb#8jsJDNH#TRmo%xVtl`2FmPWGusOr?PMj0E++_5=D=5z zZ-IM~QTn4O ztCHOS6=o&nESM`~Jz0_Nia4mrA=37Co>RSiJaH{)%}{`$t&pgczPU;VXJLCA%T{)$ z+}mWguHD&6+VE=LE|YmT*+S#;Zc-`N4V#V*@`b&?gR_-I9e?eR>jVUYOgn_XhPJ10 zEhj4~pl2&WK0DhIY2_$yZ{8|TkgP9U#aTwJO*g2uO+z8kzB-pE>4B??X2MzW# zqk(sLgT5w06ii0zZi4l>HxE8OAII}PH@@03SM0ajRlj!&kHWC;3*&ufBxjRhkLpiv zV~}8jlW{$dFGRo#p45{&gY96x76d!du=zP(IRLG$%;Vk;h1OwOQT>j)G@~fW&;;S6 zST^_b3kYTbyncU#bGAnV1)*E~#W{QT);X-%l2*>R^9J4h(|2oHP3+S5_ zBZT~6e1CXL%-_v1E1^S{CmP4Bc(kcLdR)KLF)M*;|4%t)K|H0IQ#xL*>P6y5Z-&e=yr9OZ2(!{%quVHvs;N|xF>V8|QzI*4w zg9+gqt~C7O@8{s7-QKxhyZ6NR?mb12QdP9*sl+P_d1rx3FLj3@7bw0KG5+@0?SlJm zOo2xZ9d^r3Kibmz@b0QZEulc0#6+cJOM!ntzM>6_zqHv?uDCqH32R1DszM>Slc+^38Oxb9gYU?--C^xnX$}_V%qI?^W-rQ>B&)JPs0C_ z+qtJ(&Y(nHE7hxQAPx^?w^yBwp3yVs;G~e1Y%tDy!VvY&#ST1irFfu~1uL@rAPRcZ za-FEBMMA8?+acY_og1?O7a?=8KsQYLs1F{GWHFfTP1Lb&M>ab2FY=TbO-{Xhm_lET zskEO*DR^)-lHCW&dc&wR98oq38CD%IW-LJ^%OhJB#i^_LQ(MZi=`ztIqwnMeR4Npw zDx900DN!6RQI)dHG?z#|DFqo!IXRnZm$29=aUd^ArZbcG`d~rMS7-hNww@VmXoFU7 z+rzce3}TjsdvL{y$MyEGTI~xhsQjVa^Q?rk;!^8^K06eSTwI-*9Y_Q3|os2!#T!mG4J`WAwjK^%QIF_FbN9uYK(sN@r;`?5;_w4DY zl6;M&O3j{VXo-6L-Z5j@@v`)+i8xt~fL!?r_#AXN!#TOG-K$%iMni`+#km=-O9~R+ z@{`=TScAhP?-|)J>`D535U(nkvS_o)^o?nqhKAic3+Oj120^?y!X8McrxD7g+QlPu zRYrt}%Dj0UGb2Z)HjB*L@XS!Xa88dth1R8`>*LjhKe0Bw(To0dzoy7x5pGW-hZ!8Y zx1peHO|d)MQreXo^*hP(uu*%-es}E3+7^73d^OvnhpF#gwzI`BbuYj#_b8dLyzizH5Ml-q*a86z`YovHOM zVHk6A99J6Dg-^F_R% zch{MkO5ObG?bK|3JM>QZd9tEoDav!>mi3oacRatkiIiOIlbV6AMkw{m2|6+o6Ghiy z)2BUPK%VgF_|`dGPAF>JQ8`$P$r7Hz_Eh-SjgR21cSZ}jKRGNW)N6JtLvJ) zdP+wp(}biu7C-|PNF7gKj;L7PW;6dlF|@j-1!@j&+_jOF^O?(c2!Ad{lk_xA_qyu= z-$digiP*j@$>DXFbB0&mPWi|q&Axn%)X{217L;8uAeZ^R+*t_g`E)?8jcaA7boYE^ z*P)cJb~`nZ1#h{E*>22n@uqa=7Nc#ux6UqC2;)Q?yiwp>_6nC~92|ERZb5#@rX}}O zD-SoN!&MXq9?|26ss-0-Oxkb_77P$Uw5XB6TJfDd) zZAQw0nQ_Oub}}z?ZXMlRD?gS4;li%LrDMRt0Za~YG1*1xtm_alzr$9l!bq-}z2*6t z=i)3=|IZg7j{<>TWoQf=+kraquf%n*ABftannrWMTEh!2p0WAt5cWcDh%@6)FdbQf z`qF(!aMyWfNRquTG>{*v`VY1wMSrb-*kl_t6ObF#NGw7yJ`!(2t=6 z@%~rPKs}r%R#Qr5{pcW8+84WZf@GtF!Q0lNSx$#2q)4@3()w2J) z!o!C0PxnF~FfaxGsa8B%%J)C7ZNC5k7jJFx$2UKEeQ)cvoj z42qiazZWpnw`hgWdc!ba-j~z(%p_Kj8QNM&s;*_7o-BZ zqAzKOQC{oDqjc&xB;nAJ>cRNSx<$ zYnmU!Sw5FfJ$c^AyW6XmPgf#G&$z*ar-f2Pb8JHOE5Cx}afaZsxd(lf&0c?+0bI8l zFbX49^eXGAy~DV_9vcIRIgKSNxfCXplDAt=-*&GDlh~ey3DI+Q;5rNX3hQ<%SbdVi zBLtH5b7|DcoKrV*X7*&W4#`~Ta5S0THZy%YTxyJ)aVy5?D$XjVhvr~7Tce9&Iny$A zIAQVf zE$-%{?zAk%BgfppIg!%DJPPaLYKhkICSPOCkFV$L0vtQ?q@1misub&DVXf zqHmg33a2713~R?$$B|SR6AwI8*F(}5T|?QX@&3lygnpV>X+)}nnZ5&`UvBKzGYkOh zk1}>)qy0uET{WKT)qF-C^6Oj(#QANoHFcVXV}yen*Uc?rO)ZV%bi5dmmkAslKhm#s zM=$);yrF9-r2+kmrKM<{nK!T}P${=`+^K)mqMh15O)hX+dp;r!bcLxKKJA(lZ5JNd zP1o5DPHIfv7=EE9<;@Kit9?`+CEDgMLtiG3=r3Jf+Z@ixkdMkmL z%t%Ja9g|Bt5Shc?u=_VR?2_u;(%jIM`Bcx+IunRD_ z`K7wz*m6fHS7LXtqja;isB_P79V%ciM0aw&0hZ)o*EvnNZmDp)RpwbsQ}brCB=*;* zptmg`WOb|w`o=k=q%xm5ry%H^`RY0l(&cfxxE{u9$O5(~CwtpS4ni;629ag*B`@G}BdiZ0YGv45YE-3)6_1IA?Ht4hWZ>tVr+~E*K*tdJ&nA#f9grckVG; zV#LGlA}svubc^_uORXb%usX-hvacyPKn8eYr#-tccN6eVQ1XzG)4iYU28BP>)QIBob zTF=Hkg)_~0I6i4vLiGk$Z=?7I(OHep{WHN#6kk#^_Sn@2hB>)SSmx4o;>l#Tunx{~ z)f*@&dhu3MwVVqbf$BPvaJDsTc&j9c81Bon`Jua_-H~#m*a4*}1gkINekCqur$7%z zUNF<;s}b1t>frjwvLouuazQUk*GsAJhM^m+R)KIG4GewO-LFAL^Fw3OW%*$>l~&_w zHCnJ%_d4^vk|##ia3*oK?N2?6Sl*ZtU>hEjFj0G%bPJ1tZWN)}A22b?IFwQ*WA(_K zmh5cC?lK72>v5W9CpRk5SHY$;?95E9isC0-CrOX|)~ux8q_9jz=D%Hu+tlE>@k*S&^jRGT^6|YMeXd^fs_B zCwuGdd%#3AIro|U96~=o5OCWEDQz5LvgB}g85KpvBPJLUzNn$LIxmhO* zH!M9K$}u$&tl_HH4~^B%nk;+d*zSYum?lB$ivf2rCgwm}T%lU{HXrV|k<$lR#|ok} zOZI6fO`Ww&#n<`SnhJw%>bZP(bvW!5eHaoBzZ;<+5L7FE5G#DKr&pD_TZ}hX?DuR= z77HV(R@zn3`Pp<)WpczFmk>Vd7IZbWLWum1u4b4*GQi~G4h1JmnQpo`41`s$+}V1u z-5{a$CTRwNv{qoJ`#x!P2Z3r;=TjNSRY~m1__l+o`&g2~Ah~par{(Jg_RF{s+&fpy zy&UP=)jYR2YBkocb|*V)3*b~(99h~-vFmdI9~@C%V1-$ z6@-QufgX*rv8r9tGGxsH>Js9>6QnG6sQ8W?(macFSSlHZq@US5IQ^}rs4b`NH@~$&vxuOF-ImuV;hOcERTef z6hqhynRNFnD@xCdkcs74LgUpl1qk&Ehy^z^c zF-Le8^vUuj#M36WHQn0fAO*LtOvpBMR8}@b$zJ){u)m?NXVK|Sajp$ujVQW|eRn?u zwwKf*+bp^cc{+v=(#$|7WqK~q*IgI=^{2%kbEdt%*{wj}k;60Pj-f@lr>ma5-nzkv z_U8SYFq<={WV0pvez3~jQ!H8(yV@gcz~6GbiOc>el?S^poR+2GNe2}L7BDieEW5l@ z@aO%gdzeC5b)q3It8=Umw&xYSP)gm%;R&oiL3NW+Pngj#>&lng3bg0)ES{#FwX+A! zm#;$C3(pKcyBM&`K{DyHIwfsmbl&z`XsI+9K7{Me+>8n~nc)u`NE;mzkc}NnT?yhH(a^VP>P0U!*h9sZjH98ZSE1ft4 zI^na|(n$nJQWjz`aMyCV%3^Z7{@@ebJes!M8Q&AJFoq~n|>p{>l zu8L^n(p2>>$bX9$tdqm#Tt`zgb(XYk^6ENoj z#WHn~n7+;*Pma9rvn+Q#ryJJ0?8)$Qyj`Zr%4X8BVXJPAq%s`^TmFbD?2frsY|;1g z;kAsEwK%I*5=gvl+2Jx*Jl|HZ2*iMzIdm*5az`j}on8lgoBXz0up=(xF9MtQy9BCD z{YpnyJE)th^CgMc)Zw~Q!bpf2JnVwNmM7wgaoAi%+lO_h(oZXdgl_ z7kYXQ&a^H@orvRx2Y4rs(?lt#LhXw%&&rgt-X2|9j9oq3-1eZF$&O(5t#FWflbjhq zWe6^{_7`-2b3sX#tj&|TzE(p!3p$m)@$$hLr_|j(HuP(-*{Sj*?y=SRs;%L1-$owj zD*jZfda7-l-R*V{gUQb(-9$AQO`F1i%6y-mCDmw;lpp~esvftazgtae73kKHc%;}{ZXluEmh2@|_ zGK=Ec!EisIgVZ<@Wg4HXi(|}q4gScIM08m1z=H`O7ka0Et%Ttag`86xxcq3gU?dPe zK@i}+VEi8j3H|K2E7r#q3%ISFz9jM0=HsvZ!0iXW(ku`yR)b-6aMkTFun!!#1D`#t zB(dz5E~uIK^l>Gr4;{j1fA~t$eTVw*SV{UIF0ljb|NUx*HMfAaeEo7JM<3Qw$;p{D*hJoxpYTJ;w62AMy)nf$|Ln05#s7mGeD*U-$@ z1oGWG$=gq-X^834i92C2y&llf!;xD}-|l2a-3RziISrs~EkIK8FLlLmaVQ6V3RpVB zx6&^ZDtU)e@Now|-nQ2y5yIieNWvd>6U8feH%`d#`?Jr=+WR0*)Pp|5{aa=M?G z_Sex94J+KBJK!L`5D`thJo^ngf*cMui18OebwqLnPaNRAA)@#6OMcZD)v#1cn1}NH z7YqiryaDg+7eKcS6t7hLM-X<4lW(oHJsc(X!EE8CNdm`-+s^%@z*eUJz$`-E=Yjjk zbeMLsc$h-&Wgh1bmU$~A+6nAFn8BU#5wDLD;T!D#@sfC3@wc$_!*S6c=c9O@(EdCs zK%*@)8%@6>?I8z;GBii(Ou#!n5sh*ZEu)DkT~u?QsRD7EL=rVIxr=VPxf;@?c59wB zDJQ)M%D^`gGZ7!lJdX-^9u@FBD&Tok0O&0IC~V}>ZzNtNC((k0gtnbYWDvHfFpwRD z@hkOa8?h4S#dRC>_@B$akgwSUtEy3mGc2CxtoqnFs z{x%05q&j@fR+yjDy?@V+_m~9necD7phHdO%%z{;s+hKy|g+I799&L(`?ex1j^WLk~ znrSZ<(~GB}1D+|e|M2H)%j4ltfJfuw;qmV=I6m&jM+QfeJTp7m$s13^Jr$>$#wnl+ zHhB=|!1=EN5JchUp=&?9f0xqp^~2T! zg5M?S`Cx+^<)u={%@Ep9IpoH)^UK-Kn)*L2=i0~5iWGj6*%I5K!S7l(68kwgyM6@> zxFICptAT&4JcT{=cG6afE)n<`oSXTtAsitO?xp$z0y31ozRAzKWiHb zlQ0kOD1Be{0rTH1_do}4%5CG+ZgG&L_ilP&c8tNbQKKeIVqiId_kRixN64xPV_75P zPGR?yu#iW>J|5w&PH_pQbwiW)e6jBwW!Mj><~LHdew9%5lWoHp4#yRC=(r&&4UL|5Xseeb)54dP(>Q%h9 z%LTs&Pak_|TC_YpG|$6T?)v?lfwb>@Z*zz<2U0)H_L~9z)hXg`OI*-y@X5{585CWm z8i^WgvDK=)-`YIvgwhCqRmOLl;jK^R?cK-r(bGdy+ftD0O08gJegR$ufrbMKin8`r ziPA-@7MUhW8F;5ijj}4RE=Y}3;eZ(QNGUm#r|RJv2`b z&C^5k>Z?-C+Ryg%&_MA0gZJ(bPh-5FyiQn`Vqp6r6@Zic%(B;` zFJ9mUWLg%{Nh}AwYuwf0qD!yMKBR4Ru4h1?JW>;?>upJIIxKaDnJ>DKRT#I;Y_F@# zgaTqoAHWsHv)i1FU3YtBf*Hi_^8Qsg9*eCmRFIJz!`BZI!xmd}IV;7TV+_cW3u2p; zcz$H97V>}{34U}XU{?+V@+aNnU@WsdhB#($Uc_LQRfmyjtJER0*HF7$6jDg8ELq;4 zR}rD)Yw@U+CwL=p2LiAluNP-+d7frj*VYCK$r*a(&BE(yR4KWlh~==iHiGRWI1h!z zt}DnHV~jSC6i#x=wGyU-A-!CiTxSj;_q(fm^JfLgEqC@H3xY7a&dm+6E%PNbn0ZPv zpLy1hl)9&C$xd0azX+YuF3&y9+--;nFTtq@w_qvKDtYF*s-`7nI9leB;KM%4L0}M< zlN2eCDBZpBkOiMRrWfV9Jj6$SE=^0DWvi7a3hK7#&cmITkQWzrr*z|SC%1gELzT+K z3oYEwLDHELZ^(<{9_}%pE9Y}Vnied`l zq9O*G7P6KuaK5^bgo~%UkhZR!n}d!y2twVGUr@;!&WnbZh{2Y#qxSOh4p!RQR$h*F z4jwA9?%J+)%4nCctOy*wOe9)3YLOkB6$!4o4jM9Wa=d}QnSz$QBFRA6+Q3R)j-V&z zOO(RWfI3gFU#Y#oqO;|uhQ^1ZWUEUodc3G3!4Zyjc5)>-in^$&E7%(-8OeCqilZ$svhIc|f=X_%)0FJ& z!B2GM7j!&n$FHF7by7#u%1zdlOtcX&P|{ZvJgRDm(@Hy=ZYJUCDI)K9RM0_Q+}e%cYNkvwvQ>7)yTPj&T-}u9BwWn3 zb=BQZ+DItl1%!^;SqSlq33w^F1KVW@Xd8fmxsjbUPJ%#m(-ksT#!J}gkR_b(`mRo{ z4zOw%_TN}4DjL|DD&QozbAqYUw&Ufk!+bgl?nEbICfoxjDl8)E{4}Tb@KQbn$%)?}Ed=qb^W| zC@UhnO9UU- zGQGtUjOd4j*WRHiI&{5gV))mT@xROmQRD1i(}q8{EBt-v!D95k0t)I{b3qYa{>3xE zV$_hn2vP`1@Jdhv0fNB_|NrDnFa^8+t6!i(Xknp0k+BeU?sAb|_&Y%T-yxc~-|2in6~0+cEG5 ztEtNx7KO^c4eNhNYks{K_Fv-LU$+C;+gMnjEfs&eaKaJphV>liwW8K=ANFF=zb=_t z99e(A1@oU_0F{wuF4%IJe=|iFTu{ZoM&p0em;@n$3Ifm)#r`iQAoQ<6_V0`dcI_-Y zLwS-y;D17iz(+08qd%qj&+=b*^X)&`+d>vfeMPA3-@i>1q-0^{2Ft5tDEC2n=7Dw| zlk5Rb${kh42^x9H3Y!~{+|gQAGi7alg1n=Lx{!sCg_nqshL?y3!JgouL6q^-kdq)= z*b{72l#QH>@D_4#_KJiGQN~I`PKKIe&I z>cI0vZEKjFhW2G(zXi-{>j(>Ipzn1pT;Xp)tPdjA2N|xtur}lspbb?bT!X~Wy{La! zJq^F3HZ|p-A9);l9=q1iwO(|uExK12J&Ut}d*u;5di>_tGw5#(L<2w8FJ$eo8XH}c zadMt8qb@5;S=DUi`s)+>UcpsU&J$<>+WD=7QCk{hL=)v%4d@5x(ZG4ZJ!tk`5aR)& z!3)s}R!@?T!h6<#+9?cfm4V8u70548b%T!22r zTlgKW;m{*_EqLA#?uX(LRlXPvx?1qNA>tcGgQl)38jmL?7Xw(CfWAlV$fI^ZpB8@8 z)kk}7fM#nI*oR{P77KmZ!RwVkj!M9P7_+7l^?B4EMjHXzL1WSrFo)Idi~2zFAYuF@ zs<@+1SQ(GrxrxR>hIZgN#7p1}MIQw;ynrXrza|_j4#z1V+Q{%5q7Q5U<1y$3MP@jn z7Tkl$0`~t<`D^b9^rGjq$cA39R|wHZgq0gaj6QxU--U333-@UV5Re=YFJOfS4(pQu z`a{ucoIL0_)*iA!6-*C-CL}w4oPsB^N7T14ys8x5s;EE$KJkMr7e3Jn5LoHq2|Edp z{X+X>J4X#APj^axXnqgr9U3E&7s#6ky9hAZfF2@ULUVv*%w9-{ChR#PT5*Eum^-xX zsSe*`vedN$S}@yzaWB{{*f7zMVz)Lx8{!A-3ed#*Re>>qPl5h)F~5Rz4pz9JT?4wX zq6Ov~H4H#6Vf^qnTJ3`RgKI?%4J1!k4FfA(yflE9;JHE1fDZTszJrfIz6Ol}$pHBo z_zsO5+t&p%yhM;M=s4vQ^ari3(X~ap9)Ks%4?KtI2N~N32G5~;43V#ZzqMgZTEH_H zE9DdRh@pLB8WbB+0y&`myg&|=&jmTaJ#aD?>caqD%8B?1Jb`Efc8laDjO5^j>4O(G z7Vv{WJJ1a}1^sIyU4Zc;z9F5}0=a^ZB@)Qc7U&SzhBBg85AKCeA_3VpJOlcUbcd)Q zjM}F>Z%Bq}71%b?GvE=D4H~nYumIvI&<#aH=ofTGgKUS|fM=0SAbW?lZG=TMkgmht z1)Kq*33hh?-!$dH7f}5nJOea>O@a11iH|DAa{s?pzoL;CR+XW#YjF#H|()^3UUX%Td?)N*D;89u-eN8;*22D zG4Q2G&wy_@;6LaE@E6lvFD!l|Kaa%&h&@Euc|@@l;0x9t(lxLrG3W`M#Ul1QqOhNXA#WbXMLcjWw$9xH8PvvjBgf@^K%TO@|)rX_KmdF<) z+tvd;@xoTIf#3H0?GN;w+>nh?VvZg13$DmcaYTK@SI_}ZPebHOke|YQA4)@5*n(68y`vTtyyR@*j z0Z&kD2I;me&?N)1wsOVk8wz6mc>zvBcBHF?^d4wJypj68N4Cz7ER^a1}M)*yS* z#PFCcKfIt6o&|d%+JZj9&NCvs1d&KUvV!NqFQa(rh535{BopA7FeV!V@B?HNgHe2e zPmnzh`3iyU<*}Fvp9{DKVF0u*R~2F)w2%BG z_&K@`VuhFn)sl5ri?@DacL zFX97cUl@%rZb8h~f<2@5F?>YfEwlmH0`up9HBgKos=#*yA>fxMjEf9-5%>#jBcBca z1LHgRXiZA|g_weTEa*Py65v6&7yL5(0}KOvgYhaWpg4_uyeH5h0(`>SM+aQ$$V1!$ zeI@8(ep(3AZOT2KhGeW=WZNj7g1w;ljkO6l7W%TG#DC1b(O8kMKr+=ub`E$Eb}nLA z7>gqoRE!8bMgA0v^T;1j#!A4R1%07lO$tAd4Wk%|{65kV3Kl}YA%6|+08cR=gxUZZ z0Ixu1XbhNaFuFj8D0mfc6XGp~<>1vt*jRu^6zqyH6NXg*s{sv&e&i?hAZ}4GKln2Y zn_!>R7zero{sxEii8@};IYa~Wk6~}nuZ27W$qq0D8ZYP(=orODF-%3(ZTJo86PDK? ze+RNgzG#7dkUtsp6JbAOLztgM_JuGsU~P&I=101L`Cy7IqBenF80MweE8-=xWAMLV z!z2y7p(g>053nj2`CDD2KWL{Z#3tkmAg6=-N#HNw`j_uOz6ALhh*`+rgT7&T3H5iR zo2V@em&2-KBx z@JU!7R9!=Mf^-OrF$7EpDEz~Ir^X=k9AE_GD-a*Byb;S&5I%(8sDFcg0^i{p4n{+5 zV)$5rg1fP6Mj~9mUm>T={#9m4sN6DoznNr4z>|(+Hpn8P7473CH zVxQPK4Tvrgj0Q|Uv0NI0)kAw&4Fbcn6uT6L{;^sHU|Fi3pqPgF00BerXOJ(r zB08~nh2cQpE0)8e{2JpS8VC4QL?>VlWaG%!Qeuji2J&5Up5R9fAumC39NmZVXUw+< z0&WAJZsnzpa3%7$5HBGgp~ORo+f;o7nyfH=#^g%DQs9H3EnP)8XAkp%DE@otBMe2! z4Z!ybi-3PXc_Z)%{3Y_O=w2)*hLgq-A5s2<;u?z0x{9#l1D#2th4N|vOedI9tc7!cuDEM^0i!}1XrFGa5q z#>8qfpfAuSvSk#rjNpD1umu%YioIgFC$ev_2f*c+ABFoc{E1;6h4XfRKEyYWnFbm9L0A`R#n|_@sE(<^PpLT|+m?a; zu^Jxesv*b9Db75InYaCjE+$;yi&choPkd6avATmd^HIRcMS zyC6S90hAj6uTd?B!gFfAf|G~(D2me%cin5;mUlo~ z3pxS)Bma%Y41B`k3Ce-MHn2Pb(Tr$9btz0Qk?#fitSC7UstsZO7HksB1u=Ob-otDM zx=#yeLeHTw0oK9Bi0Ub*T?MEYQ0xzM0(=J0hGt1@fVPD?5t0XHvxpuH<3fArJCF~` z$wB^@JTTqCcm{nKBAx(0uutd*)e=yDAUAng)DB!DUZZ>((S`XOl~QB zLa~SHzhF!d!+{sSa$m4<45uROiTwi}!#(KVf=wd~20oSuXLBITif}IxbPxOs*gLX& z)IRcI3(vqcR!irn#wKbmhT^CU7MHNths6LC524MiTMUHs^6i$^-w*L60@;f0P#cy=>WxFpxPJmquBk(Cm14ZMX3*9m>Agt)t7;e z08LcC33Uz(8(0Y-yg`Ls0Ak=s@)x z%AArF)IX?Lk3y>#;4@^i&_2>f&@<#;saO<8HUfSE?~yK3{VGdzBLsl8%4i|G@Jb(ENaWX_NKJ+B4+6w!pn3-W+AkxfzK z80rJ+Ux+727m+T34@A#n?PENp#z3SiNEa}B6{6HGG5JyI5g0$QS~G?*DD!OK4-s!s ze;7^y9YeHWe=7*-$|Jc!jv}w%Mfo1fcPRM}MTgN?D7h0hHmp5rJr~6}R5!z`E7UA8%tFaevGyp~8!!#3M}Vye0FR+POm9h$U!b;;o?|hV z634MQH}KzRTvU97#zmQz!S1ExRhSM_a#X})%)SYTE^2)q!;z>C12qp%ECvx*M}^H>qTJ=L{+59J8GLUGI0Wp8h&_j4 zQ25>xbO8JhJcF<=(if=Ds@S0A$w!rCtu2(Ste}EwO%T$MP=PbBAPdB1$FV)uShW%~ znyinqA}^dRn#n;Z88jA231)avG)5Fd)eL!K0eEc*d}6&(Ke79ucdQ}|pYYxQ8#puT z-D0GDLk^ z!B!6pneqSX6XVqaJxJSSfG#8jTdWTac?~OUW)povNJ8XhNy|gjLzTUJOSz*))&F$p6)XoE?_6F!l|p^gdHNYl_Y;7*Jp3`6|- z9sD~cEmX5b&!d_TH|E3Ez%hHM13R8!L$NCG1}l$2EIq!*Fd!X^?HH!h5ISj z3qI{X$O$B47%AetJn$T4GDMI8T*JwxaE+l`xCR7)$rygu1wDeQJD@^L2Qb+{B?dT! zbXEj7gE$10J&FzkjJ>WLdWlW!t%^5g zYk^+sJ&;-BCsX zFIu-LB+e@!4huT@MTCXKh4}@jOE#^kXK|tBfWiX2BK-U!BEk|v;u0dFV$>Cu|A_^8 z|FHwtg{Y@UFWN5lKl3W+U$1{QgjIY0e8m6XFR=XgPVT43_dk0`|358Jg+tEFT&yhr zX-_4#pWt5?Xa0vz>Hm+Op8dD`FNCPO8UCkbxgb3xNjM}QY|HZBf2}w5M)WdPDzV%c8B_+^7dR!mDu< zZDD%|FItT5=;{ccuvG*NYLVpsU#y&`?veYiEt>yxkJ~>lg#UYGpbX{TIdu>ViT~F8sc5PNb%s3OujjZs%rmK*!Pr_y(7I zbl~hxv;%`*+tLcoz}yRe>B1gZGwc*j*j8leWasE*k2WCu-c|&3{PXFO|CwzV{|(CY z$BxK<)-1{{5d#|wH*1JX3tJ!;wnSn(;s4wcN!gtL3mN{`v`-YhLkijBg7%3oe6dLT zgcnrwzo>oS3|t%?0hgdXG;jg0;&Cx^vet04u%y0y2fnnhF@r7su)p=!O|WGK_Pr?d zo$L9!WXbj=D)KVAq~rb9S6tFfg z)_r?T_HjlAxOwhhqh|kN{s(XC_@JdreAD$N-6m*!A2}buQ^; zfBe@GK(lte^+pZOrHtGE`0r?j6Jzuey2byAb1e;H4%x!8S>ew%q%)sM{I%I=nmzhk zT=3RRf3y(2qkYl`ocYbM>r1b}3(#x25t}Xw|SL;;*%*%I#1Sv}F2wb*A zf9an4nMKS2mM5nLX-a9UXIz(zE!mLar7^0!*(Nz*bjifhO~l<%#Fj~x{#w!VgL=np zCLb6$X45zgG?YXZIi{tjMK(`XH}!pe&LH6|cz5<2V{p&X`w_e#%c#>hi|CNnAN0#K#n`WL5N-WsZPg5GV zBHE83qxom7!%~N{2@k)e^u-WkE;eLk>Ygw!dC*+^iFuWd@7Zwa2(|XMn|J}y#}yTP zydJxC*=DEkM1yMomQ$sfx|%-i1~0UFV)IvR8L@v6H#+KjvEijveS$0J-m}a~myI7s zNPNHWTR=E@>4e}g{M*%Q8+-^y^n3hDBM$i78_7_fX<0hOW{3~)+qgnkjut6gta% z*)#Qwy3dhBCZ3U9FGsneY3Pn-a6Of=jAx7p5LvUe=#l`pL)ozBi38+@qx`nzmHbOg zBKKdp^;2buiLiP3#n89B(mujwrsnZyuH03T%{#f7Ze!i)T=%7^JrBmyIDPTg_FHhh z#>rnMg~@a2uDmfx`*p>cTjYlFfjWcZ+X5d-x3=h|Ktv;Rwf>29{N8 zU%D>vM9_w%C2ec3xqADNdrn%cS5hTSd*`@pWd~oMWhO+7n@Ly5wvB}=&q}@xXC@?_ zPpvpH@Fc(3aJu!*_cyIu-UajZ&fJOPN#Ce8Es^$y-H^#vAtxb8!0ZA2nueAeapy&| z+YZI%9OTF`SDwF;?`zjn7S?v$_Hap>Nl%6544c-MP+I96|LL00%#an$A8xKU^Vie~ zA%^HnZ@OyxKB7cYxHcR&YsHr-w>IXPo`K@k@Jqem*?6ym6WCk(JE~A(f?#<}y6XBF`=(WIfxQboa;)b#@{_J;PelxQ=go zWX|oH6lR`j=l9<9>emY`2Zi~4NfCRUZ;T&2Yc2ZN;6&ThJ)?AeK}{_Zi8+=@6I zAqEz%#Rj^jsB<)4rbfPLw<0jz*N6#S1PnL{P2r#N~CNI3=q-ew*P4A*nc-^+TtCaRsC~Ga=xQ%$p&(rxq^wX z4eP78!JfB|uA26|DtKIznqZXP$>zctFZrWBVlc~!p5{dEoGR!esr|p|H1n!Wqmw6)c_adB4_YYO$J= ziv?Y~pI9m2QZHwqeQl5*P5_7l_ydY8TdLS5x3e4c!8Wd z4Qpg(t?J{Xc+N7cOii48@8hR2U|73t*1j)+S>&}wWrOedc!`RufyS}2Fx`|R8)S~x zy>Zs*)~r!|Hor2f+(J6Qd>7kV!6(+9%PJD2`^1=R9dC(wjGo_gm!4hw1Y+F#ds4F% z^(u0s-RTZ(`ZG69dUns zg?tYNXZ}$m@>XVMRzp@YD_^r;+76RA+;W`(evkabgDgE0$JzQ4MXnA;9yqBW*{69* zn{}q5xt7ntek23W_=DK4Atm{+UdffStg-ehC4dxHc0{T)LdvMF^YRrD*PP|Fa3uPXVJOWe;sBDJz>ePH;K@b@H0JpU8atF zWud|Rhu|BVx-;5!_j^Tr95E#>FD54?=T}z|*()v?r+qNWG$#fU?e^b_s=!GC<2c>F z_OZz9zRh(v+=sA6fA(0mn_adIp|#;h^10lDVitp&2zNQSZ3jE}dkix_ zsR-`A6B*QdsW0V#xx$g)N4ZMp1XvFDo^S5KZ8uI6z#qEJD4TI-GRgY#oJ!F!%J(~nV^ z5%Hjm|ItRkY;^La*GyGuH`*D7a-WfU|JaP^Y-R6dJo;*x7Vi9`o|WFly_RiL3=hWx zRvQ}$?V7N=d)iASfM(0ZCFNnK*RQR1AuVI%D5~wecQerOLV(YSv~UNy59e=p)jB>} zs$udjF4KwK*ZNvfbChjvnZvlvqx{Gp6AusVc)@+&=Yp*S8~Z){c`1$&jpp(2_lNea zq8B$$TWWfH=VryL%B8gs#>A&-YYzjISK7HfX;*LNTVm*yBD?zFQf2m3S*QL6zhiw3 zAxFUtMr8AF%c|UAiy<&P46#yJ_x(ZwaWYL@zs6=AU9@x|z=X0j9BX3!#OjUVFo>d; zkBrp5-~#F^7-$_M@MX!*x0nVI5|1xbagLU6&juVi%0@3WJ)`_ z7<&hMCQ8d2#&xZ&UsgQ)8ajUc;CP;F0U>!_18MUg59QX)Os6((VuH~91a~4) zFzDq?ykRD3@Md&Jv}4;|ZQ(mdJCpaCd~6N9{HL@5PibryP{Iycv|Fw$(rUv!D<2KR<7TOvv(2a4u@ zHhs6{dzMf?*qHfcr+ot6T;WXE1Mf;-!>lhpeMOU1soc1~4(Op+U`oh($pZK8>C-oq zYAQYZe6+b={v-^H)iup`*UO~Y# zQ>UeC`EpLU=`tlJb24n*YVU2iU*->sdUY|N->hk>?~3yFf-~0`Q#0-x@Ln(BH5e?^ z3uoawFL>D{Grz^fE$hh>?qkPHoJZg39V_r!mDJg(DkULgDLwMjtE2l{VCb-uynLb0 z^|OBts#G#iXMT&X%RuF4sp=LtJB#Qw93N9mhJ+p3Ry#;0G^XWucYX_cJFKjJqG(&o z`Yj5jF}EMYes}VGF%z_=BYY)C%2Z1}1Iy-&Ykbx6i0rc}9f{p9MoR9Rn5$bi6^InL z&F&M>FmIvqW<$8NygZGcVLnr5@XP(dE3#63&+j#UED)Qf>mPpY^+x_pYlnx&DiTt- z1v)~0gmLfk4j$X1x93RPtJtlELWMy}nu(n~v#Z3NdardkpBIeW=N}+5V7z@F=a%#5 z8Okt!c~-TfImhBleKy;o~ZfX3|ncg(KeweK!@E?kaPA zch68R`{$k2TwJg5(_fxhMi^(Wwz}UYeZDaNAqnqzCM0B^x6vi!q9LDb+^2uC`sY#! zmroB>8_RBMa)v2JZV7x)JQr-f>+p8NI3$n@O9ImkcsuLQb{nr#`%+V^bx(hw-|wzA zcc4SlgEfQO62wV8oCW6+&k66BE?xW%!-gDgHHo zcCBSK;hBn?nO(UyAU>Y8UUcZ=laQsSS0>2@ zg?+7i!usag;d}K$gr5C{#>q4ozreh&zE=5a<#ZM;IJA);p>*Qz-}arHnAvQ(x+rq^;n8Fih63ex zn7+#q;U($4l{**f)n} zrYP~8l9!K&ipm{LDBR7dBq_9}r~3JsS31#qb#_N^9Adep8ZX<)sUUFj6Rpq3qE%cp zb`4>lRksBP?y9UeO+oDI;HR;8Fj>PBAH2DzCV}N+hMsYVz-xweBg4bbo>dULArj8JJUh0y8TUJEtq-WirnZn*~LkB5RX!FNaDO$0ko8H}*cqS{?b&PclLKD)*=*pBb?sOjSJsh+3 zkVi+|ZjFol{0-seDj7Fbt{XKaa;iv5yg0X2VNlX5X}p+!?f&~IRW69J(Qbe;@B(r7 z?>mTljBGv_c|B}ihHwHOZ}Q!L*D1fpJ^@iWdHY0aq-=Uf@(FY%1Vx1$1YKY0>+>%>X+ET>)i z4(;Lh6W>2)T}Kq4dA*zbdNHnzZbh(@zpKl{aH@s(W%;=ku9h#tw3c`DcA4v~tI8dC znx~K+y;EnU-4)?wGBP!RU#-(C1vmZy3%Qg4bBab3^qV+O4nMomv?kMXp1}ea&(iKW zv#fmdv#4QsYx?N(8um=$iy`H{c*c?lj#Es>w}nQ~<|bL5`~&a?eo_MDSs~!*?5sso zl~ObcKM&nxFmIhUHb=V zhvfeH3jNF1{|K`eH~>P6N92?6l0`mF6TR!!CO%oq>d-2ieKz|3*j=3@!|KYZW{o-BlEG=n&C=_;6TH zb&febjtgOpFwO^2xJ;lVpsnS%{ zHAqLtaQf+uLKbG`voAwwc9I>92M9IO0WK!mVtR& zLK`g|{fnf!FPWt8I7t#y=+(*D5f7*S964wyrcl9?)t={fO9Fkc@mf<2JwY^wH{35GgV$+z9x9$)YYZ5 z^!{v$6&OPKWj3#_gX*4V>llbxR+RcP^m<4X&(MTj)20KqdRk|KX=8WKDs?u0oKgPV z7cP}mqEn`Xw^mkv8GrG-8kdwLm+))m_5;UHTef&S|5(jzTd`j8Tm;(&=B+`8=Az!( zz1>6;bf&bWZliJPIoZ{ko(|762NP8%7DGzu9nzV}S7}`;KfF#9>%2W~d~wYdR{Eio z)~IBSPKNVSC!eYRbRW&;)E)iuI@oNhv5X`akvzdkt7CBQdCzRfh~%D4cXg)BtMi_| zydF3^_;F9^G0LR^Lp2bHJ zyZtqKje|xW`!6|n{Yj{I)VA*TzWz7WK8GB;EVMTvuAi-r=Ty1&YSJiELrHH`*sd^B z)hHY--TFtmXNLaBwxuuZhUVFhd(vyF*6J}o(?1k@ zl>bk~Rel3{E1WU}xR$ruzw~L{mxsjH(uFa7B~p9n1XQl9-xBHi!J+HZXw#;*B^(Ko zzN_Vxs+L;t>133|vZ@!}_BDx7yZdqijuA}0caO*8uOvpzx&bJC*xLxqR^Xf^i3o9qJRr-dQg*5OioIeR^}9 zz50rXMn_!JmfzmE41^+^d7&fmY=L`Uisw+m)bR5>FMURxjF+;-qam?c_n|Jdbq(tQ z#qTFI1f07p!eVI>RqUb{9NzZ38*ku~@R>7P+Ow?aQ#BF;b4uotv-NH}NR55_$j;%1 zXRC_idr{3U#;h5Xqr%KH6icR`ouQYmO;*UX7?HiH7QY?kRNb*cZ@-OBt@Ioq$ow1d!5wPRBfqg z*^{ujq3T`U2zREWl=g?~Pdo+uTJb+!yJ*r39mR;Pdqg6x}DUaJGMJ_s-6&K%_Heph^|I!i7k%M&U@9mrSS>`-YJLGzD z{*G>D&zD5Prfr8jwhSC{^QqpQL%;Q4w!!r0fq{EtCwxtebBi5`iII^H;-2gk?d_|m z@E!ehHu|8&>jvj6k8J`R3ycrw#@MD3ZP@%Zro#H|jinYzCvM|_XD!BbiTiXWmPc$6 z*dk&(mwO}EBD!G7P;JpwPSNbHj`#PB1)jRFH^`k*lzBR)r zXS4r6`-AK(v*(J(fCY+7>*hUZg6Y}AzO(Y~StiZ$l`|t-w95Nk>OOhh7G3AJ$qKFt zv?_?;FP%(NR*R!FWdjYFCtp}jM z#6u^j<2lrJ`mpaz=hyRccT8^cPLB_SU(IzeZ>Vf&%yTZ%5dEqU&>Ojd!Bi#V;(W(x zd>d2K)$=>8&TY!%nJ>+0@ZLciQyV-QSsl!uw@j>}YK7oDbw+$^F?qgpcOTYFpcNW?ag zWg^7-hp$%7a<;N$CX+dC$_ykQW9ge7<}T8zm`D$eSD?8dIpWwfDpW4FeH){DcZuk0 zmEO8wEw(j*@4}bcmW3VfxZ}}x;zMwbO_2(xEKDlg6H^|wX$n`?k$YY5cQ$W><2jOA zSyjrHjONtfdp6%+c~=}aU<<|9hKby(o{pBfx|``Ywc`7sstIO&_1Y89A;osT+4F~e z$rs5(QrETsu!$9qL{IXE&oBky*a_ikI&q2U5?e zy$?1zyFFT=uz9ZjZk_qWW9y*kezn>#THsC_dlFfWtNwnU!HLVQS>};2PhzFue@FV* zM22!Z*IjS@`jM&6@h3C}4U??Od!p80sUKuX0Xh_;d`nko`@vzC`W}P(*QUBBi=2rq z*YH};qi=Q@3i+4jjkI^ZO?obHJMdMH(|A3f8n>&BT)6yO>+dKYg!y!Lsp zfBLnlUECK`UN+VonNQy0ykAACNNrBvK2vn9`bX}RHW5N^J)i6Cz{`w0MCEG}X9Nki z18wBKWOv%9;+6|}6kM5*7q-=0t~2wR|Dm|A4?dLYaj%6@n5KzuVt@D0Y)?)5p!<>>IKI?j+`AEyx~=d%rL4Ch-rGD{Xy zs0gWqlTlfCz|)T8P$n@kPsz1DVb87jI=(iAi@Qy4x!>+>s`ruYU8>?p?)N?OvE(oI zpK21AYqidYhSKJy=a%p5zO=YNw!Ib_gAcB1&jVn7;=<`f#m+uD7PEN%ChJwo#G+QG#|W8d=lMP+Q2eMWhH z){}yQrysj-DPMkK#v?lKt~`>aTzOSQ$f)6dFsGNx4wJNt%JG%-zNyva6Q`AGlY2tK z0u0Am)>|mYY*tem3nHD|cEmS$jhI8{ha&&Z#(XtZDL{35u84^hTMrAg@m=FEGuu%) z$FdkN1%8r4=}@NVF8%izKiKHENlLdoPJI6118cg$1DVp4C2sw1mj(s~=DB=cjhpq} zy!B9aZl=PEO5V=ny!QtiUB_sOjUTO?F?WD zRvQKE|5j&K`|$9vlc(GhNA8Zw>)v}NJRDvRwy)b;SY&?C>wEDL7Ki4*k4kegP=5@w z{`M}9_loX4T1_$5UBVH6NX%;kWIE2*BG1N3xSlk7b>Y_6*8Gk4O`Zf-8$V8dJ#(w` z+qa+`+YiZRDZ!iG`fq>i@X?N7doK3l^E$PrtE1fo)t6?g9797Rbf4v?j`yBAC6V>K zK@T@O&1dq&o8v&pIi;gcv~iLBQL_22dmP)m$7t7)*C|=!#e?0f&sOO1lX|N}%GM2||W@78t54lm1_aty0nwpL@K|y9?Kbac~=lP*1 zF|6=Bsx}q3j^s_=Br?{L7}pgqHS;z@(Q+;E1E+q1P5OJY!RdR-i3gck)(tH;U}Y_r zi`i`%hW}CaT+pF*U+WrD1O)Tv7Za|Z7gJk##+4(yTYbHe?C%1D2b#OtiKiPH{r>&A z5=XX03Sws_PnT>*Y;5Hrh26(tUe(OD;uob9dWEZ+x!9fn|v_=JO|J zYM;_grYkqbhsOE|^_W%7J&z^?bGy%LH~r-8G_1IACS?4|Xv(7p3TKq6jPy=aJ^udI zdF>^M6Lc#!K2Ux0nr(zrT)t`fPR`HW^r{5>3;oJ%tSXN#`~OVVYs?$E(PhSvd2y$l zk-Xw4E>2wCjAh3HBH6z5_IAMYOwTWhD;B_fKtuKS&)Z^8`0L1K`)#h@`oq;i$Tr&U zf}@}*_>jh4fzuu7P11ZTPMkS&LuFnoZ?zv0dt`(A2M5gJM zMo&~TY-a2arL|dH&XJa++hcB78zppVv&hVACIR*EY_rSbgGL#J6{- ztnVaub64He;onk;4%o;*>+_S=+r!}r5uf?>_K7vj2aa=}m^)QbbHhCuS6e@|F}mej zB2CZ@=Mo0m_3NIGGR&Um^JYok7Z;s5u58G3e`ofk z612yPNr!vK?rvmX_uWdN zv&l?tz^~PwKcSG6L^|{+)nAH6y)vh2M){cCmfGxR13 zZ;q>-UAM7BZ{qPLwL|N->fpAjed~@~w=v{-OZB5KFD}gbEH0;%3efhqWr~!}&&>`7 z->OUfp+L%?`e0jM_Pna4MIa-E`K)Yd^~bGqnh7Z$lRGL?r*qoZDYV(W_tN{cK5k`E z$WGUS>_*`qpSSX)UZB13gFSbzS6EL~0H* z7P?G_*#&V7N8}D=%U^fdMH0j(zuqjW`rB_h#z`wX@r&L!+1SIv7<*iz)#mdBukc3} zRmX>l-dPejs>e>YSlX}0mA167_RUM)AnCVNC$ffzOlDe-eDBzBEYEM_)rqaoYM#u? zr$?nHIri;7StaGoa3-i^pft?hdqh%v!sfV3`mBLQZ;IJx`i?I1x&F**|E?<=}~#ivb}2X zayJ9x&u537@H~q&Ui#Dq664gS7BR=Q;Vwd-Y}@D3uL?xnkLSBq_o1%pNsW>_yUUR3 zskK1_5l$roZ?acP#r(=WVikPsP4qw1&jf5eA^5+gY%sPwY;l)+dadhc#Ggrwz-^uTJl>XwL=nwnEAJrDiBz9J=h|#`}Pp}IO z3wxBdU+DZosD^+ozAf+``-c_sXF@dW-lulsGkNu|RrlUnBYF!LldAipQcvh$!nf>~ z2{eEdod$chW^WNZp6}~dRj)NXN}3JG>+|HeQ9V2~{7GR$*r!)#leQXHjGlq~j5oM- zbkYn;hRL4knzgAO?%}CogJO&>J3f8dcKzr*H@fg24Qn^X&z@2!8IUegwG_yhwF-?` zt0cT4yy54i^9#ij5N%LtqPJ(e_vWdu%60k!eRoBR9`7|R@5=YTsS@*8x_n=Qka$>U z_VYO!NvWcd?`(%`(Aw$vDqwaAD8*oI=n5qtkcPdnukF7-5ZAAa;%!47TUgV-)POrdxwPIT_ud>-MY2LuYWTen*guv z<9@TCa2Cxk@%!94J%g%SVghob_+T#U-17MZJ=t6+k`5cW*6H8V!43D0sciKbw~6q4 zbJH-e=J*YlFKx=P&kXXtcLhbozbbV3KI`beRW_?Pwstn_Lyt{{%hMfZ2NiRsFOoeDYBlA!19K zb-@^0EqQ7ZW@6JAAARl{FL;U;@v7QU0qk~hcZs3bsFCEGYVO+NR+smdk)<;|zKTUP7YhS1MHvG%`OD`oC zr)wTu8yFeaHgU}U{2?Ui<1}ABa8*q9)Tz^J6A}{C5`$>`S~3YWN~u@G{Lcra*8eoD zv-Ki-*RMR*7Je?Ql7)foa&vk4hLbP+GJ9#b-e%~{xZNw6ZTsBca5e0xv*!ns-c9RX zUf;*bRHk;}h?0JKMtY0u9*4F`rPUmcc~|nq6hwPgg#_Idf z*2*Y}?% z=FTrEY-c>fd%`g*RVKYWOe9ty>N{iTxpT$s9%W@~U%WBV<#o?6PI_&7oh_FnV)5Xm zSoP)`gws(6JVf_!(QvqZU3!AU@$;!yZYL#o+j`8N{g(bA#jBdWHpkf{%e{n_PD^r+ zW$YQ%Bgogha(y`2sPftGlGgPjL$>^zigT^Ggnp$L$Y-H)Ovu(NXGHcN zJUBfSz|m8}Goz^fQI?O}$9?OOtrCJKOD{0^p5JY`Iz~}ZNr_NdnS+1m{KREd)jP+T zD@Be9qi@c=x#9C&&6T;yJrAW8oW5a&gW`86TqbT!et z^<+*zb=qaN_mRkN9o-%%23u1;YrJ#oDo9RA@i%$s?49z8$4}wxPp?dC5=TnW-5=vi zP%7dvPE0obuIMDNDN&Z2_xMxRl-ts{6*Gf<=k92w-ZVV;yk~z!bNghATTNyA?KjEu z^xuc4zPVZ+iJ*;T^DSQe>ik~0b*G;`tT`KUI`vlt4fybtFNo{>C$;Sd50bxTy2cmV zA2L7n=&2tpLl9v9kfVF;ZW;iaXRFs!L85I$s-Wk8I;WKw&;E%0Y-r1E#%OqSr%iJR7934oX z3lp<|X|9*&UriO=sLCCD+B$ALJp4+hFt!q*5a~9%%M8O~Z08b+0>Z_H_H2uvT*F#+ zhc}VuwyU9P^{UA7&&Hk)P4Rq8uVSjSJwE$3^|!l~S|2NLUu9dd_E`{NrgOfdSkLnE z;vBlPm`3{+&bRYh47ZnwiAf?<9X|5sbvRi&y)5v!UeaW3U&T_6txLN-p&=zK%r%w8 zw0HK|qc1PNT|G?L?Rca_cUah^@LtY3p+o|Mle2SRd^~-DWYm0MhHIRsUjO(odUI?vB3nQ}nQY?eD5CfOlonWl1}BkfuM;{p4u%_WNFu^Y%+kLcTYNw13UHwOecN ze>9kUeVL%2k%1qrd-%5F?NSNXFMboa^IeX&)W5}-nh;#+luDO4a&Tm{j;yNSJ$5$j zR$Dn_#MPo4%v-Sup=aa9jiZwcKYe>6T&@j6T#lX5&d~Vc*eV+{mvV79OCv_{Sxeo| z+Hzvi%$!8z1Mazi%|r2JjrZ*#$+5GKd9Cyt7;;4`(IKDy9DqVQ(1~SJQ0^2SV`Rk^sTIaVI#zHCWR~a80n_ z!3n_{cXtTZc!IkJcXx;2?tGi)x#!&X-0|IU|1f|ad+*v+tEy(rHRoyrw$|}}q)#m= zSwTL^!b}l{`oF$6+Asts1ogoCzoj1+c$#04p0S;4{b>Z9fn?b}dl}4(5>DQuD=TnOQK=QGZtVhZ4a~Vs4 zZe^mzmL8yyd!}L8(XD0~% zl>YwY`t+tsIo)5Fx#Xg}69)uJ7+6f;b{}%tQTf^kr$8TKlG7BJfO)H!5n_!L&Uhzg zQq{z5Ich7w_H~xkLiaa(fRmM}BDR%?E1u`i#~*SuP(!zjQg9r<{UtmAA_CAY)r>C^ z#q2&%Z)D5-j}2#=hMY7WfX1m`Mt^>g{7uMiB*`=G{_WO7qsqDId}v-$`;iv8cPVcE zF=F)djH{q0_7C1|LLgvw*NS}0TLjf4NHeSSj zHfEwzLnHCnqQ_0kNymvhl>PVR)4%KaQ${?v^%w!SblE4X;Q|$j!2=V-LI4ArjQPB z3K2Q|bWWq2K0@hmLbAIx!wzU7C18Hg@fsyp?GI*~j!MwAK=4F!EiLmblfNec|8(%cFK z01y&KuB>&ni+zRhxUccC^Cc5NN3de9_h1D|ORW7x5uqo(asOrU1K8`5N;FxD?wt=+ zt>#>0u(?4}7t-4Lw&^e85w?gL{#)TA3a<^1bamu@yt0(0pIoy$qk#;jKq2tw&g3Oe?$mE_Fd+&20RWq>;@y`6NNgMlz47eJK@<~P!Q#Z=-4RgCt;UM z7^U1fy!4XhtB~9D$K@#u!Y=6V+_iY+_O_KZD4?TQy}s$c&a|M|bSxjRO}Z@q5fGTu zUu!A%C@b_nr_a5ccTS#9bKEy)b@MR%_cA8uUk&VtzQ&7rw!aBs&k`Hlde30Wx+)4v zfJXRAtQG$s)2N4r{HomQ$+}~l=Uu~34yHt*61^fW%kAkRHIeS(Y-nJ7iB69EbXjbA zfgaw?-5m;Ug~tuY{#*r>)IjfFN_!rg86UTczw=CBsjzDv@Tc$))^A!{n+G|m7*pj} zc0VK~=xh2}NtTFr?-lg1iUM3@uV-vyq>1n;pLHJZ0>iVwbysYU-tSh8)?7`n89Tgm zLxEGX6mXy?z&Hq7v)x{M75V22QDx14qt!p5t<}p@NP^$)Ytsy8+xbN{Sw9w-W@UFZ zX&}0>LV;|iZGSm7Ai&teqiH}+P%qTSe9f`VJR11jQZj0y(9QaAu_52p47K?zeC_va zg{RH{8~2w{_y~AXhO$CZB5o_i*Rt|4?|PRFUggOcaR z!p~9XZ#lXlX&;R??}B5>J?E<-t7e~(wF}4c@Z7^mguh38nFe3B2GQ4f-VqQCq~yCA z!jp-Fqj1MePnYTB2jzR-J%(P?{3t85HtkKM=+@b|?$~%kQ1qRKgJ_5QM*80CKG$CT zIPeI+Bhxv9!gy}Ft7yRjfXWD_!+qVs%al%icyi_@N5T7+b@q2Gh&8rZ3)*GM6o!T~ zo*QJL$u;o9etuEx)`UgmS&y67g_%`S=AQ=wfED7?APv zbi&H21`m-35H$=W^K-`cj_7;|Gned?-s7?~I`Bk!jS>u;51pV1CIhu6kP44)q2`ho zofh-gcSjF=Ui*+xh{~(MU2kQEcGHcW(L^DKc%z>s#5V`;ag@~R;7CbHgM#3}R?8tt zEmjg1kXlOhJq^adYNw)(;j5PM#_a5DHse95fln>3{Oz|}7sP~CHg~gJ&8zoCLIt%r zjdz2*`d*)Zj^+UP7Gwa?b#@WgU;_Z;=Oidge!c$q>_prZQZPP}o%P?L3HGU<4H8BaleTND#tasO_h)#NM2oNt&g5_eF-hOEb z-H)=IZvFrpZ~tYTcm@N=bISdX1e?XS^GRa6opXKwjkN<*eHgI0&uz+s z?zG49PW@a>v@!3LP~P4B)cUZ|AOBV;{~lS{#f1r=V(O|)+Rri#78;KtT9ne;lGD6b z08*&7zLwl&O2I-WpLP%Is*lY8sJ3lOabf=hey*ax^s4E{j{Ez%wnd8O*;?4YFu(f* zThyW4ydcH=t#lAt0i!H}u z3uh|7RjpZLw@oyeV=5$Z@ps>4;|r^nD$G{$xvu!AF3g~qVu)yCm}CZF@iPo`b>UAR zF7=G?hv17*%1VTkB@n9Ky5>ddL9mzw%a5*GYM-tv zD4jdysTkb5&v&MOG63gDOczZ;$%12NHzXpDBa^JT0_y~)nRNVmI78J-7?-~3jYVggKHkcgqw?nPSZt_qK5Nl-qsYD^~ z*0FIdWDkfO#XBS#gQg{UdTmAQ(4XM|r)F7)$gwO;sWC-_RrTgJTV_eOK)Z-fHUC_L zB`YEnS=!b0jSxe)$i}b#mhJc;>?^fec0w0r%YAvpMSnosR^YK&DRrq86dtE&QFh&K z^zpKDva#O2Exdn+kN;Zq(fB_$1mKwXuiN%NSxT8!if6mlM)?T+e;gy9^CnRIAzx}m zgMq|~sf%HQa>fj&x)%_Yj0>k=%XkN!p_8HzIjR0S=53kx7g~$cZydMeA)oXWx_=Z8 zf1Wo|#2wGGDr5C>nk>;l`gXcev3J(@zluH#DFdm_o1T#@H!LhHpYrmAe4m@!+xFpM z<(s>%5W>g?_pv+T z!IJM(hm$W{Y>jIJKA+yZjSc;$ai2v?3WoRUjTAWbDM$B0EN6bbs-8FV62z%&cGw>3 z0FueY;F9vS@jj-1XSl2{;MP)oBZ;*4VZB>%q+StJTUTdzxbW@GdlO{2cqZT7adU%( z>!Wgq9-hXtApywm&)k=fj{;ta?C(5p&n5pv)5IxW5whrY9vgmGE-?5?F39B%7!ybl zz@@tW09$Ibw2-l;f)?_xON<)xj%h?JT^4~$h@9~y=8tj<@sJei)>lN;v*zQ zLE!s`2bH|fP9(yPF94+)xKpmqe)D6FnIaw&gpHP3p@f``4T~(cEa;O!4VA;z0QEl> zxaZ0NcH+;wkLW3&Y>2+^UMLj;cR};>>6#zwQ`W>RXUgHs2Getb;)*niSGvQ9>GiX4 zHju}}ULqL)`CW_YQs!_{p@8A}>W;RTcTtp*sQ-_a8jP$^)Y?6MKh+K)7(Dqy7Z%%6 zV>JtfX;lF^aHGDK9`7q5)t?H%rJvp#KYsTI)4_0D!Gih|4nJK z0dfKV@qc^^|20(m?9cb$qX8b3Pr^f__1H z8Vmp#{nhjTj3j>de^ew&&$Uh%0>h-9S)TvH7)Xr=D6W4{4mv;IqxCB=G<-vl5uAS) z5>DW0d_vEkkl#GNikI;a>GM5&)Se5i^cm)iK6kkipL}8zdTm#;rtRd5oUOqrVx!^hYCfPJSHu_-~u$ zpT!^DA$9-iws9h#<#-kLlZ;ji<-+lho5MSlS^xuY4W!5UOqDbIbB*s0Kx-L2(m6}| zPx{115uq=ZIWUS!YGpJ>dZxmG?s*BY-DV9c(ecXB?4phSS9d@3tZ%>R4kh@f+bSu` z9cS$U;T|fp$ejW<=oRWl&t|{oj)p9_$|nsFWXqI3$Hm{?s^x#;LIR<)LAA-vX`$JZ zxWW0LeTq3{SL18;NlxKEeWnTY%U7D7f2=J1zi=uq2Q*06Dmmj zyz={Y(g2OGy`O#mZ{y<-PzhO}cbKFGM@x(J?YOP5-0pvj1}h8Ck?4MJ;R%oPoC=*T z)$M+8cRAUgRWlii#;>u_RTf2?QMadvWR_N1XmTKCP`jlt{yESaN5=|8dx~zoZDj_h zS7LBSAg1wX`>Q|clJ+l;*KRm3or2zgDzCo>@kqU0K}?Rxebg0!&T4 zQJ|Vr&w*IJ=hzGs&~c)K9~~X#^V+~F)oTvg=eMW)bbEe3W}kiHV5XKK*VS6A2fn$i{}q- zJ{B^GfA^z@z)ZFWW&yIS$G7EC6v($wX&wsNIXF0M9gaBD(ULDWO_%EVK0Ub8t2IZj zotVk-0V9jjlgtbh7V>m=>6jeE|8~}N@MCIxBUftWG%qA5G)UARvzX?0Y0`cKqk6!= zKj~jlKewUXqUOFT_XsfVE&46Rz&E}LnAy^SwuWOKeZpz<4c&u0}XNO{o;W` zv6?LhYhnGAOM4HeW2#1Nklq^8Dym!WN=i2UC3ZvQ+qXM|%Q zQygb6Zr$16sOxJ_Ks*g4T(G>5hk=M(979SFxZDzlO$l(7zNG(j`7(DnkwKQq-pT0$ zM4ij#4k^=MXrKO8%Y1-r0T=MZbd(^$(MJlQ0iKO$F29W_e*O#jM#fD>^)=GC4W4VI z3H@2=>#Jswk0s!D*LiZA67d50g}~eL+x(gvLKw;r3JZM1Ja*Vg6Hb=8yi%}z;Zsc1t-kPk{>m(aA*&!{ z%nuS0d>b3WwA-|HTgx%X9(a*V?IdaLxfTzb07@ET#fRdtioJ0LRwpC#R@f3h3W?A; zZ+k~a6rHW`_Wp|!r7?t3-DU(A7njB>uR7{UWnLG|&D^RB@B6R|Z<5wkPQuv7I5)Z$ z9K@e)U}~oQ<5{#mQi79Ot^!?*3sAg&O(1c5hwD=Sr!sVLzJ^>L%%6SDY<`Gnt&E63 zD&qBnc)B#JyT>U;%oevM1P>J4pHU(}4>#LMLQ0gaix4-md%ioK$m2v5fd1~g)of)~ z;Z44BhS9(dyT#(q->P1{D-^vMA|i+wM93m7)2!91XChwrGZqcc%iW(Cy3tIrm!V|5 zkEUrK0?7e{mB{Zv3&jToe4ext$&%Z9Fzm)GyErL+^2E=-werm~RiEjbADQGJWYHDv zlEWVb#Ag!x4o}^`i|ww? z$}(9Tb}BuB8%#vM%D_CiKSscEwKdvZ?eT_${-~ZC6ni}1*(mM5+~$+xh19RE;mx~o zMJL=6bCPz6jg2iw4_V(TS<}Jq*8zk^?F{1ZQpnUlAzGCtC{vI1JbEGoxBj&g-)@)3 zX}h4eFU#E~KUWz^5^UdH9{42>Cqnq0&)=Ljr41L*bMVZX7?K-(-YAH|8qIvf;=awr z)~@klsNRoSqXc(i)bZ;eBvV7(=lbDN(dq4o(~PJUt6r$bxk^0stM_On0W*r^L;&*8^f3^` zPDT{`y5(po7;uxecXe^AY+I??rW(-{MzGxx(!m4XZ4@2otkosRZ5SC!RfCAprSW?E|6;z9yVNA@LM=`@`Oh$sBMZw|iJ_&ymsV+3@yzcFbq-}wHo$I6n0DRnCu5^-L|?9;W}j z`$kaI@zs^4c*Ndxal}#cozhKvd^ywe4{Dm_f~ejE){N7Qr(u!D(32sHuD-z(!0`}3 zZEcarD6X2X6c$3r+Wmw7Q@tYt_|5EUN1$BY!CgIrEzT+Tx3oPU~dIvX1$GAv~WPGm*L(o=E72g z#{5y~N#i3|2p3$RwgLtYxoH5x$mO{Ig8<2m03_|lX#?$_bW&G&+;pQZoGjim;jX@v z)n4uBH_x4OcXia`e$A@UjLw%X?V6q(M_nMoJ~`>zRW z$OI@odFZvs)=9UmSuaj*d?x|u9>ePsjBn1RTtVW7lz`Ri;QjCQ#+oxl1q*2$5Mas^ z6a<`D17dk!80?$V&77z)uj=b9HD4FZljHR!y&HFP zswm?A(gi*Jc4LYgZ!;T~(Sy;h z^f;GQI-&ayX!VZp=0C5*`xg9T4}~AEZ1Ha0aPFa+j<+wRfyu$`r&Xqg`}~fJi8fZt z0YpD9zReG-1DhKU--JK{@W3v4Yl({kbaM{%>YiPfhI8}A}vkN*Gkx3|KF;kE= zN=DEG8NC8T1ZO8Wpvo86zQ$-&Q2aYDkHtlya{Fmv$&XeUJaao{ZpH*Nl;B*ChNzfG zZqN5LBus!`-cz7!ZW-CP6YqJD7{DYC0+8l$np{XD<7o|h!~=0sC|G@s-l&V25hu{i zGj#3c7NzN7!uPY;$#FjRYAU&K$g5lhV@X>QUNqns6#kl7UIHG48T?DX`E$*rWTP8p z2%~~Y8I&le81)TGly;>n3Wr&rh0`0zrd%BR=ZS*EkDSJa2C8NEu3bP)BjGI0-xT_u z;y;C6D=gcVBu3o>1@lnEIJdP_gv6#eaE@@hpq?TgOTr9zWpaLfWQmI(%WB%e6_mt> z4T{NO4-Rx~i&zKe%7h03jNvNoM#1=ANKY=5K)xNRSkFGGBG}WTf+`6AL|x?Zj#se7 znczkMJ>o*Fna!3@*YhDV?=eBC$tA+5i@iC+(%%nTMy4WLxGVaB;FgW$BvK}tjgfo5 zP->8f-6gU>gt1aZ?+0{(-ErolDQCkybD8(pHEt-e0LxF(*$4`E&RphMWlC9sou|jU zvPw-!i3qD1&5n*=(vn_NfDr{m^~Ee>Br8aZScS?h;Nk!ICPjh$^L!~Yt#UFfHtO}AbOdSGZjSTW zPsTTsU)fz;!i4gFaV}R;ew~~q6%+@O6eV-&Wt$eokf=&kGxhCZmHY*FRVC<_srsHxvkiPgs6>2+gF~D>UKtJ&Z?@!gwvc2dXZ#0Juug1m2#Cn@s&%6b| zwe1FH@|!ro9f0Umy?cy+qYC2_40R=Y5$Lok_XlN&lBc{50hUjFC0pk+pUo-#uL!S};j#kAom%$))wd{+TXl`X>(vcTiS^<7WU0p^>_T?QPIzd6KwUv9Gv&nryE(SZeN(wq$C z_50VuTg6|u1x0HVH~KNRi4|skl#Uy@Wwp8R0CK)E55poN!bw3e0};J9kKDO1;uVSw%_m-T2~)&Mm>y;0pLqyQF9Uk0EK?5_KH%yLkK8g=n_phTt^ z(ZG>c1@lU^E*W)=_Y*&%f5{4pIXC^x;2hG*Hz{l6PmhE(}lWc-!>gD6>wL)fVLis)Z%v`H445`OOb#DWsZ^= zGkv2bQ2^-fdyDbWHpR#WElk%va`Z1h^C&8peu7yX@=rYfOccx!27Ely)?+j(6EZ%W=oqSGh@IpI7bdr`iMpI%! zq5}x5m6sA{M%d*w5R^K5R9@aecg5IV;W$t+ZO{7$c@|$m{!*&;3=!WHTgKXanLI0) zCTlQW2j*o#o~yAsYuH@U__!P8!yR{2w#BzV62pJX3dcQL?s41^X1rAKL6xgs{cXn2 zu+?5G=ZA?_%9{PKT!}4W_UA&E(PGIDOI1e9I}!uZ712S*v%dxr_L;$rjh+=P4&Q(x zd;!+MQEL=YF)hGsl?bRLqwq|Mh!tYEna9*@@1QOu{)^_4lI?0pO0s}>bUwQh$1VW9 z${-%sJZazmtB!G`JhN8Ly9mGqL2fN_{^x+h$k}i7bTk`={_vM<^}&39sUA*UjfeX4 z9gR*`-@B(56MH-|Co3C6iQ$I&N^F}9;8cT13nO$m_Yi#kWWJR$MJOSS^h3Da)rFdb zbnin7J?FO+oI{$Ycp*9ldqSyITRlDaLfY9J%4{0o#d9VP*o@bn89_my4uCWKB>~7N$~EVM&8POorZ30$dv7>Ej@6X-P&`p~|V1{q1V|ANU@16zz3?4kG1&h(br1dAr>s$td?SDRq40ua_wNIrw} z666$}(9e+`w)J)HYcfZ3^gIT7uyVH9GJ7K{Y4vONOY9RI7Fr6U&lZUjc|SZowFu(k zQ&pP@si>YBy!(C*(HU$>;DaKD-gT^>_2~b#NrtD1tTy;Ft!Mt2Ak(`|gXBJhgbfnY zRPNxt9{qCmQMZKQ6wmA6Vp~&b{bq7}Kv}qtq%m_ z#^8Yr>G*6$jDR%=@8@&s!-G{E5Vi7dT^@WtBPOIgje~q85Wc+ks=B%|_t<;7+7RhY zqq7~jqHnR)&o1A-Lizi2WIjK2#srjs<|7L7qp-LJT8nOMtqUZ;k-2vYaUiw7S_bv&s~41OAMfT1<}Tt@exuAqeENtCwz|0)Z1%#YBaEO&pfH(}Gz^yQ z7fX^nG=$&xUffS86}=|SEuqh0SsJt&t5HwaCB@a;p4FGYSTkM>XJ-jzM+l?i7( zuh+MbEso1S2a$HkukP-kSP*F7s@+|&y?v(;Z00ZO&#`EmDvY7g4j<)l(*kc?ZuT_U z+Y^5mS90~ieaicOxubw`90plGYrh+Qhwg2;y%ZCdILH z&cLq=y}yUIqvgR^*Yx^Pd=lIqm}jZ}+RupV6=)-e!?3F-C``FEd-dh9LCI$sW%=Jd zj&{W0Sl}KIl|%wz5V@Fb)m3PpPyz1Q*T~Ox8aogBfJ4yQD~HoYvb6_Kq!)~uWu=Y zKswal1no|_>P5y87t_76BgsN2AQVq{r|w$S--!F-&lP9PcZ{XaK1QjIDc}AM>IEIuGWs))-nUGMNbRWwz zP@b)>sykFd-CDi|9zSsObCQH)$&%wD*^=pBUth0n`1j8ocVNI#u@f49J+H!l57`xR z67G}ykz=+Ar7Sc_`T063EiM=aQ^;rkVplI|o{zx^n=yj3T=*|7fb7UZs0OuxG9>F| z+KjDcP-kQ=O_YA_r{MWIS-#2svUB1DNzynX&m~p__E^8X!|Mn>$BM!@a(^dI0;w^^ z;vkSAN+JVX06yodo|;)n_)=7m{i+Hj7wau68VX~Q?_`mx7~k6V))u({2#ueA7M;Oa z>sz($55ulYjx7Qh9h`eR>bouKgBwy8mQ*GLGSwffeG;rKy~_kJTEAO}~VAf_)Sm#9sty*GY9oI47+1Lqi46(5nTv~w`ZF$%_qiNxP)SGb(+R3I7@ zxXq&M!v?Z8y4)X%@x@+bxt9fi;%-@VZqgxW|B1{>!(ln4uri(s$Uee=U zjpt`C{sNhQweCr%uR|+RuM+jnZ7z809R*)02E+z2a$NDRWQ2uRU>O5@gSwbx+SJ{* z>aglql2Xb5{6GN6M4~)T+5%8}&G0<$vcy!!2LwEd3?Vhb8+bQ&cdBh0RKfd~gQrKv zkkNjyx6LB;!u#JXFJc!Ko^YYlt|MlVlo=){ki%2~Mg!T~cF!wS^g}&CU)2(Qtgc`87`-UAubp%gSZXLtZ8~&OYH?w`zNR~ko7V=N zFQy6-8|+e7gah#D5~&ZfmEg5oq2M)h2s<1|@6lI$9!I++PASDOA~>4sg*`KrBoSFx zW?n6OS55p2<)`zmhdoTPoP}{AyQ?vV+)oWYAsNH?wz$^_v85*5kSyVJE#Z2f%fee9 ztyjN5m-HV*&zA$&k6U%d5fq5N;~T#)j;Q0xe;t7DklTGVBM*Ow2*N49zP+KM6G(9= znE8@rIfBsvMHJtr9gGK7xY=wqryMh35S|7(`xaLF7anoflI~aUnJvMeBOu}ODTG-b zfxJ$0uM0DCCo@}UVkmDvaZtr5^x9<1vHl{%W}c&>qU37Btb!z%166^x^m%?Z*Vt9-U_v9Vff2K#pTIx+Qqyh3EyApoXiLC|p66^jmn! z=zIk0TLYtkM&)G*g+iu%m2kr@Qq?Vapa!%8A$ya>I=W<<20|!oFo<%zZp;DAic-1Jo_j+HP03qWB2l6V z3w7Km5-JL{_-AfO*BGAm31}uTGpL73GD5XK5U%cBUIbap!ZlN1w<}W%(4hRzP9S&g zmxE*C4rJ;KTW%pxd~^0L%PW#c@-*eopp2y5h141;4Xq*$4EWdg0y$Ppe_L0Egzxy# zuLk`#SaUEz(F9P@BG;0ih}^2xdOM&0nnP4T>@2p*D77FMM7|pxG!>nD@z)Si(X3D> zH80zmX3*uV%2aO_=#PJ@Rmg8aY7`%el}T~+E-HY=6NR?N{X71tB?Y}qM8xEcO>f&z zxoMZqJIAO1KZS%1(~B+|-dAU@K^m>*Qb0H)zb%sgjz31;o3=p{c$b~O?S&#e36l^! zSAfH1+pA!JFgyS{HvW%92BKl9FpYS_F74sNENM!YaeUN z{f}hs&zXS2<++Z>XtgylOs4@+z1lq@ozLyO;E;Q4V1KrOkkf3SGmQAeVhYBf=W+51 zrhgSx@MU~!ut2knRQSfVX(TZ>FVFBivEtR-=b233L+)={Is>@Vg?jMlpgq%W7YjOI zt+?x5$};rN25Rg%s#++W=SX8SnJk2UD3sQh7|1q!m0C^HOYVbGq^@HDmO;xQ08_VS z_Ud5|W=PKF>rD?rCjuyrGefgtCDk!NjyZ+y8*|hjoPg=!ew`!pl4mO3Cx%RfIWx@& zQZXEupz~E9g^v@4StXNv%yr~nHfl0-J3zCw*Ex+oYCxWXYiXC zWc=TEcCg=*Q@C2rUoyZ6;RMBkbifPp7vqvGYW%y+I5cwQZxj8zJl=pw9F1yq5NTS= zjWYaKkIO0ftzwpgy^syyBYjRMe<(vu5aY|;i5Xkoi>DrrOVT}UwWBWD_AT^}xT`kc z%|Xb(xwkv{3k>>y)Qf`=Y2ngIrp~DXw2Bqln-8+@RO!v(SlvcjH#`%#v@bCdGbOrD zIbd4Ur0!@xqmwx&KR96C)S@ewEQMesLpn0RCp>TJ)Seu(b(0tb8mt>c!SMG^Y&C1-_9$ zcez6LIz4jzzQnje1@>7;-NWkzi+6)=W9gBBvUh^@^veVuZ}K9F<)~UR5rR4$g(UkZ zskV0Me>jJ3n&@CxTn3JQ1RbyZJVjs{~25?XcU|d%_3p6AH=zdnkhn0 zT70N6%Vv4;{qbH!Kd&Ms#aJrX!%8KL6+x)QgLa1CFZ4Yxkn%X{pR%!e!&eIlq}5Ry%Gb@C11a z-scQN2VF*S)~uP}7(l*OqBv9?zQ={t&Q2WLF~oy zixQ8aRQ=!GU52GUgM+{OeBk|{aL46xpX5NYO)07c^c_&u-LL%S&oH@aaOUB0?C}kb zHvHRNOBp4(a@XaH%M;(SvX)P;q5kn)h?9Kv7R-c0w!B~T+?d0pi_1$f zNHB74n$Y+C1_t`2V{Gc~Wl?A6c*&PJffbtflGJ3&UsQzTY+25BLV}c;?^jG9DvV+* z+g8ulm%hz;nYBi-dOTDc7Lr0p<+U7v91imvi)aqQVb1uVY9z?P8S8zM5Rq;`Gtq+! zgxMU6I7-PP`rB3fH{ej2d1g;AeUYfq0L2dnF17{_H~-w$KKh2`$wi?_-_776_KWE!wTa*f?T z9tIDYO|rJ^?u9EBJY16G;(@dZSOV}vy87|?3IMzctPAJ$l1SpK*m-t$y+^f`4^+9I zT9_`I;#q@ua_1%bCvYyyew(8Agf(2}PjHa}J~ad=;0rt@kdO#P=y=GJoeWcH z(d2|4GyEu&F)fe-24RvdZB2SUj?7d^x*M?T>vulgFdMb#gD`&d36FM>E9@LK{K_!B zL!#QeWR}#nK>@Sa+_vtd-}a;7k6xzq6QG4%T5}MZK`J1zJcYp8LTj`sm-Yz=yKoUd zdo|Ygv-0ojbyD|6{Wvq#o24Y5`kLK!Qm;p!R*IZdvOHPwisw;lqHP&DG=M0$cWM)I zv;j7JzO8%z9|0Y7XBaFt+CQ#aym64k+1oan`^!~h zO%}I31MshszK|B80+$zH#Un~m$;Gvmc+P({97j6FU8k+m?f{<5nK-5mP{Jhp-Ppa%Pvf>I6`2-n5SNG}e}kE% zh!tCyEb2SmiRdJL2LeheD#=8{<^}oZ*X3VsE9Cv^xRtUd8uTddo;bH8cUS6Nh+44V zUHyWCUBCqHDTX;fd@T4MOLVe%XElCU9Sh zjswnfM_fw86+>P%=zV*EsWfXb;v%7Vv`gV^Cr&7My6Ii(cJp1s5a1k0W4Uh|S@&o@ z&Jr(T2#a;8c<&RXA?^$}Gq0#IA#l63g?cYQiSq2x1XM+7 zHYh*-`5AkClHrZ9s~5w?9*bOQJ)bX82NYQgajUU;zyQio60+rDil25y1xApJE`qjh z6Ea510o4jACqY@$Wf4XyawMte{wSrG+$zqdk(nG2rV4Gd*F5qD{uq{HHo8+up|kK{ znUGV>76SS^SM!Ot9LpO^j0c0SyJ1t7m2bgTjXq2;Jx)kg0lX}GAXfKiD^sd?^CAJT z#8mjJmuTkGl#456^{K%dH}p!o{y$2>+< z`mAPkkFD3K5FYIr@BCB|I80VniDoWjy7*8>IVAT#_kUO8nH7`2Vt>RU|5$x{d~A0j z@Ckv;e()dgY_vf?kRpJD&!~M&$5QXLq;J-o)d)-skGyA$qC1;p=KV)b+o%-E!NGpd1)@bhQ z@Bt58C&XdG#uYG&h?4}vQ(66Il}->5D{P3yD3+<6c-d~ zgN=K_vuu}Z*lZu+&pmRGkUwrD=&pU%vMxTO6_HZJp;K77{!H6ALXfYdqN zMz#%2k+P}zpu!;})%1z^+mye8^$Hk$Zkb#T%&SbO_UbKH{pbAzfNKuX7C>PDILtml zz#DA@t|z|BXlsCK7SrkRn#D^V75c{k4Dp<#XxP%z!mc=B${4KI5U?0(M{|Ff+B4xd zyss5c#;+?(R4=!l=Mkr>`aBuf?)bOW*U$AlYU+CVsd_yxLBD;iOWsi%2c8TicB5RP zMLCVaWmW^oHSY-&lsr>cBEwfa zJk-v0@@|#V`GSdgZIHwI0)~a9KN@6Srwsf#R~+0ph%pPCYs4nQ@i_nF0U0!^5)`ueqN z>zUvYtegGI;$YxE&>9`FExm$TGTvS)4BG1LO3Lw-U7zG_i{93X^4S6^b-qe+YP#4; zx!&E*a3cSp(vB|qGDe}b7h7+6BXq@h?$_Hy5${sF*o1AjEDK`ASy$o%mEox!cYgBSS+~q!^$W)iaR)X{mwwD_XCRONvvO)Q; z6Ffgr;scndCKm!+50%W575g9zYH;J_nMvs3O`T{`x=|1mBo{~MX9Z49;R8EVO1Qh~ zQQ3Z@l9-ma%9z$}K5FnX9Ev%(y{c4vl4`sfTbj2ANy)j9zXB1Zr?7)b|DtP=UqVom zJUmo>&8QWU;o*m}%%$vJ0XS#WpMPtlOOh3fxuxdImVy2+NG*cAr~t5uS#WL&l=_(unORvJFRu&JL_Hj;WOKH5hm-=B4rs%c)duUunVre2(?Rzf=p$#7|0lVDhArIw7H^El*cOybmi>tW=y-9gOAT z#~%WP&jl@x549KSTv4-rr$CSY{OXZ+FU~I`WASd$YmJ^sA^t^hKu3Dx_kl1)Aj`Qn z!mtZNe2X^qIl97y%)7pSurnRxi*?TqVR>1ROe#<3>4=&3I4Y~7LW`mfW`IS`5+)Hz zyw>u;4arv7+!T`$KH&w{Csu`~UW8CDvpi}FracO3k_C!xv4?DlFI+6A2_trU}dW-RPlnj(_EH9U%X!IZnO3<%1o8ruhEO28xC$3Cl&}2u^&pN1GML8nwJrA z?6w~!XKptiH0B>BBk!rQle0}`?T?vBS?+}_T7-Uo*3D9uNCKx}al59En59Be%XVe> zU39mr#OpL==0`m);B*_@W;YxzE-Mxbp7sn-uBZr1g6yWAv`45R5P*+`A;J#xLnqi}&t;D;sOHsrq}goQ3gi6pRGE&kt*>RFx9 zV__TasuytD%@qKz;pLUVj)&CCW1;tV&NN8W%3AfnFA zG_|hurJllS5~+nqc^^Lk+ve zlFAPr8jlEKSv#QC(to40}b&Zz@G1BR?-_O77(lak9yGOJ2>* zwJqUe&;YD|>06k^+p^g)$%CRRvP4b1b1Qx%SjpFG-jUp9;RkGSma&Z93N0M`WITWe<4PgxEN-Ro&qeNP#IQ;e&5;tSCT7B3`3 zTm{=_XX{M1LN}ohD_)0()TW|^nQA?gG z>lY!%;-_<=a-N@quTz75mgPYC!uCMCTAaP1`VzE(M)is%D?>FM|ATvRR@3ZMGSF%o zPMb#b4yftrdc&t@9%YELf<``}%R3}z6*xSo_?@L~h1BOFnJ=P{Q3*5D6|B`?O}3&+ zzU)_0gqt;&m!&`fBa6e!Y2rCg;ROd6nA$oDoM_MX2>i9GDtQI6|5iHPk>Hm{uL3liZE8zxF~@_89MN7$K(g?M45`yA|r-0$+U8U=Ne66!G;B zhQWCuBoC{rzJXg$neK{ms5dkDJx-oA1hDd9s6&aV%Mo)2)B)x*a*RxUbV~$K30Q&b zs`irKjx1a9gxKzen5!;zfRm*4!&C_dqtlKbkYt;7^0TkkovTJXZPJjNkvEfJ^}b``RL2yeD&GW+WQ-l&Z9e7iMugx*XX^c^Ep}Zacpk;x*}X* zOT5np{+U0>{WJ5-S}be7*#*joO3}Fj2a4>84+oL1j=YS5cZin}d*t@TBbEkJX*vZH zSv8ZV&zQ&db@F&LD77}3)5iD;c%E8vbx8;pQ;>jPjJy;@qaK<>b2M2I1c7t5S_*-S z;qJP>;ChXmnwkzYRUp#@ehG41S;ti;;k|qa3Rs_B?^Djmn)^caV=DPlyPkg4W_Rk{ z$q~$pQuKv?V7^fD8H`?s?tcK8N)4kxRdmpm|3JA>;45=KT5<7?sBgC~hF~c$&fotZ zUvC{3)wlKy3n*REpfZA#4&8`^AR(Q@5K_{Jba!`2Nec=R0}QEjNtbjAQqtZ1F8rNy zo^#*N`@Vnj@iWfev)5khy1sQ~n=sWGgN`A@gP!WXVx8aVhOJ3uF$rw-OYFNmtdE!< zUetU3CMCRE;-f#vDx}txIMq5#OfBrSdw9&Uo06pWxD|}GND=l#pY?P`XdbMD@a;8d z+rR)gW1B#=6Zh>KL5pAb{8V)2@BJzs%))V%P1k1iY^9tYc9+DGtO-V?Mp7Om?NkIJ zuCc_;70tDJH=2nJG{(bP<`@mOABif`;uMB1BFE@M*dAK*bKw}^+BL@aoB|ULcbj*xs4tug) zTTN*mqWLiL%adB{NUnb1F2IA#;x_`o%l(a3$;v{Vc4) z>JEqy4^xK~n*y_BshfU$@KqI?16Z6<`3tBAlR?+!9b9N)*TC`)!!G|fFHQ@*H+R`? zME5@JLzT(Y-Rn*5Hdn^vTfhL`B2;j`$emtb#QD71dNaL8Pg~m~6KH3BG&oMI|C&FIwu6CGz;cBv%Jeq&<;>8Uo%ANd-RBlcFXjg97?rYP{z5pt>G8ma)N%xKN4LbB7oIzQ4$} zGey(&Pfq}8s&jJ%Ra>1He-FT-2y=~os(Wc8f~CQvNd=4$uS9(si`o#HSKv~+4FWf>)(AKHt3TsHQ;I0wgFr~8KvE5M zv|*X{5!TkQ#35&772a)=QB$V!LFrGZ2KF6)oz$1?G~@523AlC)v!ufXOKLSZtwPKO zsRi<%wxo%^7k)fSsZ?w;;#>D`EkMDYF9Dv@fml>;0Nu-hN&D0kKlJ47H$=r0TAV>! zGZ~}vSD(LEDKL@5s)}!VBj|6~=BMMN&VSxuDP3+@_`X@@)aCm$kTmIG-6M=P zq@k37pqpy@NW4S0v*EF)eAr#`A+*Yt12m;Nn5qG`Xk#2@;-x{NBUE=r@#LO*LF6qz z?Ic4~K=6^if|sT;1sn52CWG#^TPUGM7wpmA+&WebXONLJZ`u963^FPR>I2Jx(bhUn~(cySovLyAg*ZOU{7 zIK@>I_)#PlKgYLBWjGBnd%=^fb%9@)MSHghHB$e3hzXI6DLfyZj~(?;AYd2C-nV4k z7nE*0mjIDG3wpJBtZ&Ib$%TO1JKDafO7u~I+uq}1zioohp<3;hRYwbsW9Q&uejXO8 z`NG8ZMP8uZh~EOYdw_)1TorK-daiIr6d^rD?m77(&UBB8AS~pq$`>lj2?Z_$|Hdz z`1aeur(3ZHkvni>HvDp+$4EgHAi^?(!6Q zH50DDg={YI`8AJ)L?<#EW~eip@%Pq`Me#0=#vx3q&qan(%k_d3bRN0R(Yy8-NQ4pP z?|7SS*RlWAASvR2l4e3`{g$REAFdK3=u10Pn>oF*oX1tHhAquMb;RE@eiG}+s2LGA ztN8pMM1kWWuu}5lq{Q2>-T+}w{K~WmTg2Wv0l5b-~{Uv%_TQrKh8|7)QF z?Z<_f;eV|+^PkB34c8W2z&oFtd|5QfzEgWI2YglEXq)4t7OIRv+kcAJ2{#nrt)?N*~mYY(Xv%;Y`Y7WRbv5?cYzL z0=8Pt%i~-4Ehs9%I3^La+>acpSQ9@zT|CNrQ(Gn5n+pmDEqhvcxuLwd9a!N2HY%b| z(-Ub8^IY0IEMnHHB1w3rE_Q)Gu-0xj-*PV^f|}tvqgFrb%|1~wLDlxkJIhN+7C)&$h3-rnAEAmVf3P}WO7bHG++!H3N7d7J9^iVX4e=O`VPW|4^ z694$zRfWbU8{;N&gOA;96COmGq*cAmN5O+!uo!Hj_WI5P#sc{Pll%9>AJcYo^v#q7 zdaOUQkFB*gYjL5h^Mk^?cJJP|b;|1?#`4LL|}4#UJe-kgj?L7O8h zA;zpQ8!YqTZKXDTPtUmcBa|5YnWIp57?aNP7X7)tT9E7IrVPNMK zR0VY#7g_{y#f31ZMFWVF{3)X;lm7aTQP@Q>9r@My@;+y!_q4?vXc&V?dpzU+a=jZb z{~Nd7LCK z#W^UUgWB3(pxiXud^nfi`T9kHq~!DKfaKLIvWsFOFdO7w-?*N$nV7DD4K3D3&s{!o z>eH9#S>k+u7OKK-raIUZhDuPRAGn!Y_)3zDQ{>|P2JFRn>1UVpUQ$f8Rl`iudpN$~ z{B^gdQ7b`i2>$!4Z9!(uGC4ZGFNN~cU)inJjkv96AAatL2rP*v$dyaptY~$RgqMy2 z`e&h{XTnMl)QdVaR3HCxtux0@a^L@s!h~8)2|wj#So%uaNY|k#L&eCap^xG2Xy2dn zNCS2IF7(W2pYHr*C%B)jG2-i#kpBrolvI%x$f5M50?|i$U}?R`}2V~-vc$nqu@=f!ZCQ`*OCyj1fqC|?_%7@n=5NU2E}B*dUvPAWK%)?&5zEz zE1BN&Q%4){!)7tCooR2?%ILRE%)a~k&BjS(J^y1rn+)8PL*pXD>-}k-{z3(}-nz4{ zd(0UB>VN>GFA)+^J^O(u5uiCJA!C7zC5M!nv?aryoQ%f*J^5duxzD#H4Q5@HpZ=L< zq2P63cRO*#5qWo`yNOclw$>U}d8|f{G(@myZ-eDsT=U_Lv(D|-17I!iz7lRse3Z}8 z5u_o|d&h(>QqSwzZB!>{klk5pSjcJI9sg7xRr0HkKRQ0sV<}fXyyl3fS>+~eG>LT1 zEg^Sj?!&InH`wY%zd^u=sVHDtTm-|JPR*{Kf7N@^uApO8ze82fn0GZjb^%JFVK&om z55UgjnXB`E@0}VpcU0NsBqS(cB%z@==5#2|0i;BZ0~z(UOLN|~7spl}=W88iUl_P{Y`?yBePtWZr0(CHw72OW7+}H+%NECiUjG@@$EljM`WJu^ANXW>q6ePT z2RaZ|!hmYQZ8=7AbK#XLiyLVW2wrruvQ&Jrr-77h869vqq}e{G4d#K4#WRc>Tiza@S}kWs zK-4MKKNA)QU}}2r7F7SREEhBW%PX|BcjyU@d|X^;`OYdaX%4EBc=#$ZcnE$sZg#(W z1d56-ZZ6nsf0mbN`S`|J?||7KSP(rCBV%J)KE{rhCgb(B^A^YjeD~G#>2Ed{un*d- zIyuOeV4_480-9#s~o{fO(M`fPkP1ro)`?8TV-WXNdY}TN2e#bo7rhmJutS5uh0TE!4m6RQ!zbD6BhBBjh&imfjneqNbS{NV zw_hl4A<3V?BZ79afZzh$Ihx(r8dK*|9cwSEx!&kkZX2->zf3F z54YOq+SV{{(Z}8Kg(14Ce{hPr7YTR?^=RL$$yBF?DSA)P1UUf3a0>}DV8x#Xt@a`p z=I60)eD2KD#Dyt`Yb@@rm3MabK6~s8v9_+r(|EvzarE+2CIRQrFv5gPl8RL1MpP%X zF_iBstLRMMs}Y0_O1KpMtF>MBLD>7^E4daO^SOjz@iA{|rYrqwY=pGCS#8#$4bOG1 z_GZ=>O+Cnamlw(Oj*(TLI-M%gkFoKU$K{26H2xh(89 zwbvcDcJ`4A(p;jSes8Qq8=)ph6yC!e#&R&49LiHI!XDz{wBhB&Un$llwi)_9hW7Ey z3Gym{MBGHOrcL}l73s~LG=6W&K^)k^RNt#N>FPa6Z4uwxvrKZZvsv6x!f7I_xVCHe zSMEF_kxzetWlzpbGJwaERM;F=(XmTiU_#2TsCj#riBNEtrf}PgfdCUB`aY>}GM2!x zR~e&lH_UWUK%~V}xiOL6gC2UhX;C?C&tzG)YN4?dSgCFyO>#b&1VSptv=YYhr6Nt* zp0j9uCEHitJKS&g(G1@^*`rWivs4rc;u93|C(3FI9Pf_&Vbpu>^2F=<0+#E%a_iG*C|(VLcZJ_w+iku$W$UDS_h-6(_f=d_3)XBJduv99?(V?}x$rab zKg_K~wa$Tha{lY;9G+L?E)}+(C^EJ9k0jcL=sBF>dTJ#~_{mGH*|Ed*<=eGGueuFn z`@V)6NJLgtu=ODKZ##ZyU0t1=LJ;($Z>dR+Dr8H7JaNu(5|DG&#JLxey=O1l?!y|M@WlDj4VF zCBB80+tLf85RB#r5=i2Tern8o8Jphdh9|_>C!x~)C?21n?VJ5^ia$MVln(Csl-m+*GE zR&G*F=BrVbfdLSP5$*1(tgvEYc47onR5+x=B-Y6U;3{V&yjCRo;sh+!Fv)!=jeNu< zb=PY>FHR}rBv##kJz@rI2zeK?{B_M;0TrM;`NKvSM0#Ls8ZDTP2V*)X55&6u-D6$q zv=O~~wAX%_b+s$K=*G}?G+33%adS`-$ZI@d$(C(;Q6;UYm^0B{@I%gv({;Bggg}_& zH&?C{xh>K2gGIKzNdmz=g>U^XSILYqDH&1umLgIuMbls_uns`KN6W?ai`gn_2tVby ztz)}qQoB_*_jjghb_5AMO@~|N?afj{RsKhfL4AP8!&61lzLa!v!OD`L(a%%MC;HMD z_aP2PG?YXClN-}>3KXp5XbD(R?t$YVpLX`ne^HM7}&*Ovb>t zZF~+|ps2e#`juMTLhE_e=G5o)S%ykWOh#|}sm<$m5ALp+&*s^hdj5R=00A5!v}+1f z&!apD^4BQM;Gdtt>IHGH8v^?pm%?eGf*96vDgJLw**-ZXgu#VPFvHHy^2UmrTG51O zg{6DCU;1Q1Uc}(Au~{D`*NF0;u|c>f2qZ=c6^@c8T|0aGC2d5#%A_mxzgQ@v*|d2& zkMA^QbvzIn4HJuZ=7V#Xifjy*KElrw{`&kTf!^KhhJ5-#nxg41@jk6I^!F<3(Xk_DLnWwL zN+IQ>j7yDMOT}7E^}CNCB#gDjec7KQn-tI(UOIk6-<(2vFdn1=Uwh&7Od(&+>A0i7 zmEV31+f6aOq`)6dciqRA&9UhKg!XPG@T;F}zp4FcWgwC8>7Cky2s>tB!(^0kY9sMr z}&1m1wetvl|e9SZW3Ck0l z#*&Zzcl6kdOpSfJV;DNA20P*%21yVN6MWOD|Mb`k#4`uPdBDx`Soy-2LKIInI#wCKUf=YmH8<3| z)09N(xBc9(n|!blK6Ey3rr(|I`x?0~*OMy|=5(=rl^yXA7IqK)6U=z{OuM+9@wbH- z?V*8$d@6XW6{7pFW6+;K2hjXinA@6FO<(aZR1!-zsTvirozt@Ccrfu<{~}XvMR#5^ zv#oLslW{t?dsw6J@#)xHJLTftJIjA2*c!vQ?Nk|y`zv;aP)0xbqG8MBd3dwA-iH+z%W(f68ADQxZNyiQ5hcgMf)nH2D;*|iu-Jgdtfq@Ib62mcZ z>7i+x?{d^ho=H{1glG0Y0~|?D($Rg=@D67!7rxWy#EW9V*6#g5|G|Qnk3JXr;=h~1 zbJeJ03nry^&x@bY&?_%q87nhdS9*h#jv_N}}1>`%2hDI4T$&|h;RW&@V&n;TFT^KHuip9M= zRlPuyqZXw>S=z@SklarJHR?<52;ZZ){X7cyUsJ=Kpg%L*;xXE)vJ5&v?E-u=)dI5Dys*pO>~SCa3mFH-}Fjg zJ|&}*8*1@Ki%m#2fO#g)E=e;MYwi5Kjzq7FP0w2#hz?MwN@~7eK8j;50@-!4`Mn~3 zA_UWFv3&Tg>}SHkR})@c-W2vVi5ze_duENX-%}H#5|2J34SNa8C2!ilRP&P@K&VFZ zf)aM{@7a|}9J2C|3!Ge>VT6U)9X47GOMVo{&b1F9sVp5YV=E1}1FxwZfHYfJRB~$S&VNj2LAlvOn8kUf5{n(PuMNxKK57|6;{W_F(qYes= zRG@IEYe>HbW3s%`XxwTasm#Q(eV=|JToBLlHqp%aA%Dbu91R+#CI}?zK@b&bPre_n zq9U8i#ks+G4I9$61LA^&IU=YmHi6dX>T)>xlaTXFKrmhm1MGGAm%WMiqGW{$3wzLhtLVZ4dQ%k-elW)U7OeuRpO zialc7XZx%uoCg|2--drIqY>lT1Ar^3*?)n!v;%}}LXQOjAcd*7*-hSx-5U0!#F__a z`nZukK976Pjfj~vu<75rEu+9RF=8_AGXjGg*xSLv}R2x*) zeklo1{o#l`lM~;TyaoX)n&Mw_KYG8pFRqcvzxqC3_d@2t>^yt7%Xx^4!{(3SLqX@4 zAG7h?kM1oQ8Cw*nbBtQLs<94LF~6z9WOLlk_9vC;-GC5&y3p25Qh{gbz~ar4Sf9q0 z=*X(Z>sajxTf%T<6L_FiaI3`ed=eP5_3I0&+Z9`(7by8qh(0a=s$m#-_EOr+%(p?t zjla$W4n40a0ZU24#x`!2 zewG!77Mqemvn}NLl3Oppt6|A}`6Hhk-W9j5k`CZFG80o88kz+s5fKrPVTs46m_cGCvm={p zx-nLK-~D^mieIT|=m?v0ASus9@{5764?>3{f$*%@k%98;TzNo`o)QC$t|(0Bci1|wamkCd#!3GX0|`*=mD2*x&N}NqJh5TEkK<4&%fMssT87okGfHZ9SvV z_iAnp=cVTAg~PkxtdfRLCR5n)eO+A=CnqL2ebOCLTKY1L)C@!dZcRPYI7`31|JXe= z@j9f(&v@=XrT)xde)pP*l8Sl1LaBmN4%;4E3}afVj~+XR2PYU?kw9;Q zJ&cSvbO6()QI(aIYpxQ`A16l*?tIYHFfuao71Es5z=C(4NT5D)tvz?_mLEK<~zSIF{1OjS~ks+h-K{p4(0*gPZHsY zDbw;?2qyo85~u5YH`^-nDa?HHwNs~YYV{M|qBr6b9;w3&$+-8+T?)Op0$gC9n`#&={JTY*@kN$0I0(Of4_RU zJmLBqlWN@K&c@sW-@`-hr9UJNQD1j|G&EfA?jHWI#)#JM9deZJ=@hNpUq%{k>c?Z_ zNVrYCQTBGqU~HH=BcC;!gEfVdH5opWiK%c73JRnVc=~!X)d-u6Fs3nacxdQed<;yY zM*4~Ta^qBmvQH!!0ee`-qGgUYRv?#a>c18VXfyPla>N8=RVV z;ToCzk=m!VXX6w+*xwhUeu2E0Bc3?yVZC%+;xDteyGs|jb%yOxR~M5Ui{5Rxv$7K1 zmRe=lHwGEZQs;`;9HV^MFx%PRUv|vNrJ0#etbxVZ(khF|g1uD@s3E^YXB9g;6sB0J zp>a1QA){>i6RF$V;bUwO%UG_od7@_&QDuuKt+c(x}v9S_ys_ZP7A4EN-UQNi#P+jj`n5eb{(F z@xnRTtlaqO`A5D(7Q*d`2k;22z~i~-u_AG!QE3O)W%U>nx7M$jze_tZMKAClIT(c9 z<*>Z`w-$iDTpLUDUyav-j8)f(-Rld(&iHYqbhQjtKfqOEV5oGovMXSIT!Ce}z8bL#xgBh*+QXZd)nZZTkmGDdcD3aI6Mf zM!~(e%PqK27+D^dhAA@@d}g!|m3PVZnqJDiy4(A@g#dZweS@})@i>m%HNyK0P0sD- z>oaX>6C*bHq?!4QPm+b87U|}O-i3Z;Z7)b+IM!6AXY~&pHG{p|(pS{N6DMzO$`98N zOyaEcB&~OgxOhyttSZLq(9d2K;qGxX`!fy zUSKFqeJDy2{ovCEs$a$dy_WB!8@9*$ z>fDh9p-->oL_-%|26k%;TdrHiT;5CNwxWHwL9eQVrI06C%~j_ymvF4{)F<@XOXfE* zxihIOIUAXY(Z2i92Hn9d*5WMbz#UIhPdD_R^e0?u=Q`|k_no=W;>5@cH6Lx3XG>~T zu@tJ68&2zf_u2wHi%3V9R3~r3i9{PR8z1%u-xWtWHbJhq()2T9$jLHNZ2p~;^N!(u z1553(&-I4j1RE8{9Rf9`uX*xL$ZwJUp4a4Fdj9sJg!W6lu7@txyr`E~NV6r;ta+yO zFj?szF|Iv?_8esNtzt;CQ_+!pnC8s!QGes^b#NvHg0{|u{kiba!$(>|beAfaDqo-? zb++?_9Y**J4ZC{v3}VcBA+CAo4AqJ0{-F%~{-Iz+xV9`u7)oiyer1fAc9crZ2jmd!@*{311IJGfGmJ3|DJ;D{v?&6_FJ z7wo>tzY+cNJy`6)${(tJJH`1ZYdZS3Khuo)?a#tG7rCrN*}xfJijzn36qk<~I38Sv zC}9r|T7hIhXI{yV2bzA)|L2)Qxh^FjzD#I;;wAn4#l{<`;H8e->~HO8^%A*CZC3@% zSLg$8T4{-hh>qPbSNL3LDY-DUBWceS}$(w(xPC$cSRB06MmWB%RxU!koLUjX0 zv$nHJxE!`C$M*9e7PxPDsjb;G;(q(ldKeK+^SvM6R(n|B^~QpLDA*lfl)dMnG{Vun zDCYWvbuOf1_A}$&k+t{yak|>P{VjPyanW8Ff{7(*Vp8+7%*E9`ocY9FvW-}xPArsvm zGj)#IAMG8@FG7@)VEP3@0O1wX*xiEQYauNe~a%Wdp z|A6k!7E1;FUACl>4je)Omvvkfm0_hFU+G@z5vkKELZnL*n%DJph++eahlQl$4kB4H z@Z^`DtRHyF66KMj5kU!{d;gc76VCBgewT$e@s1SQTX-y;zQXE4_QTYR{!>vkwt;e$ zLOY3w?ZL^V?(1XcMOWBm7#n_ewFna11iSLfQd*3bPI<*Fr zPBx4@MWRt8u4mU=ZQAxYg7q%9kG#StBQOKR|s_KL) z5*ozKt<6$K^A_NAuPanDgS?{Oz`o7Rt(EL`yC|dwo9bR199&b>ez}s%0CpMb=NpUi z{EmBeSudc4?f5Kq?lDtKFQ7pZIkzGo-6a(+O`z`KJlp%l`V3_ZkvELU(?m~e){U&d zO;Z1?Sz5<)VDT6(-PirHkrMKIB(TS9u7J`6chgGO*ryYw*niH*rX#i?=~!yCG|kY8 z4TexR4~#=J0c<4lHuh&(JT6{y3RbH!4Xut3zPS;IYKl!xrU93$1NH<9`ReLI6NyM% z0snd`^T{e^Akbfijsma*B47_yU;x7TW#or=JB`uJ_Zb4z|EKIy#CBz5c{5tC{ih-L zaq{OX2m5;WvzMzQ>;h{HABc(7Mhn#q{@Fxw+ZCyB2(0yR(<<*?DE`2li#;NiN@3x& z`?SO3O5G36tlqBnBRA4DuxPl5*21Z>g+U^f{}_{T!<^$P698fGx(8JlUfiA3Om2B6 zx9wu>gmETWDBbi3L=Hekb*9M`nuE2y2)pb?b@p+O%izRe1*gVcxcE#e=AZBGR1FZersrMG=fm^0Ny`6 zwsgPWBNzBT@Rcz3*952VO|>`!eWqpQO7Rgp;`>JL0}8%rHBN*ykyNT8L^?uZ_z)SZ>@uX zFm*Ljb2zw|(wil7+>COP4C)M8xjk`Zo&bT5iR78z$>JMoo5RWh1x)Gr-7CIlGi&U; z7lKL@GB)+RU)ON_;AO9QzY=QM@x4!a`{9kgjpM1Zy-5@*=~r> zKqj}s%f4r?VPh6K1STeQHqQ>0kiHFKM^JpE`(OO@A|M}NR{*aB9aoFYMR2NlKAW{~_AX>j)U7cd7zMo^`Qo~KPc-s&!|Inl8?oN)wzilz9vFMQ%cHoKI z_^{b+)BC7Bmy}UU{*dUK)FF4v#+u--`#TZv5Yfa`*4*AWChVaj0ez$i;A_F<%+mZ9 zaF{(x95(G}h6S7koSCGr%f%S~Z1uk2__i$OV%|#MbJ*0;Ipm3bA|3_&#xiT;9 z!?|8B0^e(|0{2nSgj^EaqZ5o3ueEL0GEh;042Ppi3ALo zN^i5R1c5#f?3oSQ-WOKni6uILYr_nmwMGk4yy-?x5oW-I6Ywgws#C*g^xJgly94J> zIxh-4BtF9u!U~LBwoHgtWgpQ;J)Av~ICQCsH1sCD3cAgyJDicYpTo@FL;z{z!=@Ma z2N-i!fuha?FOdxc+_m0a@zAr7fZFqmBha>cd4JHGnc8a|6f&vvToUMBQLo6fcFDgX0j1Yd(#fJg0SocHmUS=`=Vi#dMpQr)Z5)d zJ3neWNYAhj*#a^wGfHsz5-AbH178GP?7F?`)=a86tO`@nj4@TBpReX10D!-*vWvD~w5M692! zt!)diIu5JeNxfXjf$%=wpQPSBJoE_;Ua8Ndrj^1q&&9o}s1S+rXyj@Rqw5%GoL~Z` zmA>`W3lj+U`x)uG_Drh9v}rHP_qTRxISiIN4Ee26cz?94Uf0n7Q~fuw0Eiu%uKl4H zzZ9DN#})L}?yG!|5J3%}v_GUX@h-!xY;fSO_$mPjR zjEU}O3Mw1<2SvsvCYDrZoh9D%O277V*0)_+UJetezbUuTT+^jWGKh&qQ#4@bL>DuwcRcF$`7qxEt; z;o7SNUs-o;=gf1u-jvO2t`g^HW3;t5d3Z3}*z&7S!p`+XxN}koIV8#S$WI@jD;WO} zT7X13Lom6?*wWO>_rV|m zrIE@6J@05^Ju70RQWG6+nc(2ZT;i^shHsuwQ|}%fq3!$3)ID5sb;%mlZjFsi4$LG| zlyb586v8U`SUl=e24x07^$D`J74F^h}gU4r6Gyi<20iQH(UhO zuGI^s22Gqw!A#CK)N8tLMQ)}liIp8U)|yxvZ%(Fa#vAH{hZ|RVXd5Gj=5VU$&!0m0 zK(=n&UW!Y)M8LkM^86)v=%`evEf+*odXxw&87C_KkMFG0r^!b4>Zh)Q8b_O zqd=y8;2WE8LtN;4j=mStl|=e|VFzX~xxOMT_-h3@!qKbUMa9$AMa9_o_y|5XhgQoH zC*|6JcUrpO!}5Yz*>(VHc5yrV9jF{^Nz265lbH8hqwU3Kt#E!=ghA4IEnI~LVf;`qve#>K-2L@o7pl(2ZO zG8SmZe<>l|Tf-_4H?O9Z=g>LRH5gv zUG8}7ew9@s94-7Pv%MN>OHt{67fyH*Jo%ak(%{A@8=r1bc6 zwC!FCJqpvWTF24Q-eeDOKKJUa$ruC@(Dx>B`~s|X@}j7OqZ^LVGe=7CcBK!2R zV-C4lxU)M%T(moOFz{*aP~yA8)^n;+k2^TQCsNW%kB5d;1!O*I`D!c8YU(eaM?P@* zypoElqPwW|9qt zDADQ=_W43X1s4N5uj7N0j^zh@941{<4@I2s;}vK~ET$0X|EkI)B-Ny()YRnn=E1*} zGYR<5iIs|q)CO?b(8Ab>pz z-6S&^_7nRSFwlZe)>xMK0XJ9d9dA9rL)pA1c#2pZ9DqFr?EqaS>6ZJu8jSut&8+*% zNHEr31TlBamH2Mz*~5v#L^l5}Pxnt=N0&yab62GVvV7L00!phXyq_4SL}q#ogPr~8 z^+desa%S4{B*5I@5z5nxGg_f1s;|Pubg8K$3VbL1&mY&hAldnzti03KtJ|sJL-6-d zYtdHlQx`+jR~LUH-191h$N$@tacd~n3LhC=2OnSHqE{$PPT|7^j74;EYff1bZmmO*aZKb>zVL-nV$X?5fP}e`5s-E5w4$cwD=I= zX=(3_jLAIaJ~%S^w2eddzNxT#{vto!%6#I2u=SMlD1XorjzRMzU9Rt4iE?cFZ-4?M z_6A?qZ=0Z-$WNLpCzWq!jeQ{fFLhzEwk;=+I0M`B{)gLNf)KAahWT~tZU0;GaQgc4 zL2dLysr+3f?qc;v>C+Wt0;Xl;f-6PVQGmG5RUhcjW|8W#^p4-BvmBvk=V*&yuNLi?{4&SH7}{}X}Hxd&S+ z%R=lKc^NC}$H)zJ_V#9Mb$4w28y6Xi&)wQEgahF3>e(>+!0iH$5D2gV3p^T7t>~@T zmM}W3)nL|Q^=eu_e^ip9C#KI{RlitWFw^hnwk#gin03bK|617G-ShSeL`ra<+}*pFaW~eD{QQRSJKSh>*-5_z#?sN%~EzPk|F2h2D;&)hkG#EnNKOeckr+ z44P(iFLk`{UsC4Z7Mu6(J9bmD@}!WOQbY@$#2U2m7_BQd&$RC`N%#+@;LL~i+59#$L&dl|+=Ki!9yfl3J1KRGF@>9uF~fmM z`m0~R9dPya$dUe11P2O>TYR_d_b`({NgZbXyZ3Xtzqe7Z%efZBm$YZgaw14ro>;~M zM_&+0HGUF+3}vq4&(F_jxa;TuxB%+0EtLZ~tQ$@)E*q%8eZYY7k4^yR2+wEVUtmll z<@2pL3^0C;9SE&SpfFtjS?WA^(6{%$B!LHWmza{%fdW5u+);YTQwdcl`2 zx2L5>GBVg<}*gD^f zJmDhtYG@GKc)6qeJ^>(4d%8|eRXzzhvSd%VxMYn!B>9LJYi8LU3O`i<(KYC86bR`P zC8?`R4@XzRq2b}!)Kra6MVDTx!bvaQP3%(kr;Awg^cw8bPek3=k>g15n+MI!%@cKJAZ4`yS3czhCKikdqxfl88}HOj`}G^@`>rYe|@(_vtQ|LpDZ`sYfE}?|MyO`ko$>&%OQKk`(M~S z8i*etA`}cN3G=)-&I0Sf$)9xA86d>^vh%DU2K#>@25*<5f;WT~NDA+ICX6rAI<_9Ld$wD~dLAa#C&=FlA2Fw#- zWyQZbCusT#^pp$D&DoH1q}Wv&uP1tTw#8x_xh|n`c5pOdBk@OR^0O&AdU}I}fIYLh ztS4h7df{QD&-DAID*4@yAA-%8EUMcLUY@O@ucM>-*LKVw|MPDsMQ%^p1822c4B~S? z?nyY^CsM>mPBhCS8(9a>`Ue?1BUr%W0R~I9G@)GGj-%1g+X}N^888^wZUi%v-(bS% zFx-bMz-Uz}s0M2X(qIr31}o9@ekOGcP|1FUH8E}4b{ltb zmT&aG9F>{>Gw|~L*c*Ti7MbaPDP;$5+EeSJt?&U}k1!;X{a3{0^#v=)hC?TX!hXal z3WqjW*PD~Tgl`sb9!_}Q0RxW5%wbjUCTTt1pyRns|7PB>1lWzV{XyrGqI>*q-XczS(lg&+$lJ@Mjy{T`1OV1(O#!Jbp+Y z?#vMYH`RTrh*3y!%Q}yxqltdK+sS}3s6M07v{>Mk46?-y&^0=yN)`8Z=lHN z(P(Hn*JX872j0y>feK?&m<$gGtd8^!;)nM9hdq{Q^mg@o*avn`?~OJcx=aO-Hg#*p z-hs}e1?lmEL7WO2x~}w& zz!wE(WXMQZRz>9fZ!G{P8H?5{*+#8rRX=g5xTSI1GPfp5TTe`z!XjF-rn{TMsKP1e zb+PZj>QJDk7#S{}{)k88%!uFa)TxoU6{hQQeXnMDO#8>qnQ0IOI?k+EJH3?vTI&sp-u^NX%7dBUd841d zU&d!-uukn6n9tI-`xr(vFGfBPjH+?mVQBx2+aE1*&2$H3V{5+b;HoN=&`rM5?raJx zu+T3n=uPHIy1qUf&eoQZv2xoBT*(7d*%n zB;D-XygDk@yh)X?nyw^$yQd0=Gj%_)p00`9Zg9{0zII)hBfGXYs2EaUU|oNdn}?p5 zE~HwKdC@O;m_#FbDeg+@YNPz*1 zq5AB{zD>dgk}MQ_#4y`kIYQXj5Z6;Ej3-i+{2ezvZf`XfEZ@+^`a!0CPFeqQgHFY+ z!Pyr%dL;B7WDQKLA-7i#c@`RJ-t$k84$O>ol>sX4 z9RX9)kZpM{0St)5QpYbdCXvz!cckBqWfv$AdBL!8g_P;~ljYJGM)93t#~8lLv7$N- zLpdcXClHa2+OtyUv_!lpgR#%n)$c`7G%0tujCm`Md7p3{jh%cw_uZk1!CSRRnq?A% zF+32)7+DPHhDeMk;lrzvCF`FU&_=PZnxq#~!5KtRJF@6jKdEcH)vJ?LX)XQOX6hsx zAMl-bBwY@cb;s>PmW;J-=SyqwRt}|sB{rf%6wUX}w(wM@RII|Q?s=>3GADLKbXYtWcaX>KJA%2a zjN^L;XX(!n!b(Q@qwq;~1-Nu~nbXqy&MQtu?aiiyS~iD&Nqc)-|HfE4JrvS(FO=@M zK_e}}b`-x+e4OdAx@_>4F$BK3i-k^>0~3i+*gjBqiPo!n)^S>Ei8)l<(c!+(_u0OC zbqZcy*N>)NRs}h*PBtln;SB;c@Xh1db(mY{(GDpL52kyQQ}Pqu(ORf?>cYWRMw^~^ zz_SR|(3h!|o(G+os-bE#ZSfYP74-9iMZ_Z#;Cti?Rdzu`izmYCs>2-QQJ(BqFmkunA734ibK8)hs8shjMK51==M&;|QAaMX*2JADusU6xt| z?tI7E;T^RwjoxarcCT1gWmkn(o_7k+m}{<=oK{BTA8F>MGT&Z47cgCrZ<_&9wBv}A zr{!Y5z2KuCV-_G^I4;bgPMwGUgS2g;V~L5!ughQJHGwll8YD7z;p? zhdPzpD~TKizgMWjf~#k{I&)SlcsSyr>gB#wtNsT>K*SGYt;M}-orHyKz`v&=hGEF(*|QBj!3!=!<`C7C z4#R=LHE=ef6w$ge01I3o3^Xjfill_EhLY!%;-JZ6y>jPYSRui&aELta!ae;LkEGQB z3SD3|bZFs6Kf&1+c41A|RDe_yVb{uIunAkvmzNHBsQykEg;vn1fenl?w!xC;Omav#-#8geQ;e z>9H#29frY6z$;61@L_O$ZVH)eZpp+LptN{ymIPKX>K0FXv4Fgbfgf!|kZ45q4m=eW z+~~*){6~X#|Jcm1fpp9Pgi#2rv+1f^83GcgmDg5Er8oT4tZEBi$U&*phLEGvjEgyJc7CcZQLTD1a+?*(JcY6TOB zDYC()x4LUyBuO}Ds3RkhJBagww&*=bbx=ji?`xupj%PT>63;#fNT8B(pK}<+cebcgF7&Rc zsvmq%Y@s}-rTjecEXqJ;A;0PShUgscZiKRB8>%F;@g4Ro{iRWA_`MmsceSoOQO615 zM?A2$Y+aAFhC=IsN0_ufny^v4ThLtqJ3g6cmfEO%=+z}qkl7H;)uq25XP__`4oi;@ zHX~%1-=V)@DM|1=(S<9+*u2|a+Jcx!~eqS3M4$l$5Ma6Y* z(uY~v-*#@89#402>&Iv15#c{IE#ZRX<^)Y(k&k;f5H1K11^V!w`$P=bsU8VdD_rGy zObQP{5t*x!AYA9OzVx76#q}NqZWO@!Jcky|Y0#HeC{A|{ggbT`FZ${r#(2X9Ll8Jn z4v25IkzH{m5ZL&&?<@$dVh=IWDsNmagG%)~6K8>u-OT`_pPh7e6=r(XwfSn`*6WY3 z;Xj1#_u`I}T%B!CkMk2(#WtB3V>$ zy%DOkkEvTJ!CilhV4a#LPfZY}AToucDs*KvUK!Eva9|s9!MJk9|0aJxXP82;PeJvYKrlo zX=d83P4K*3kl)YyWfeej-WDvF_51RowZje&qmnHe<& z+JH;xpI#~;62yre=ax29Ceeiu9K4BlSV$Je>=?R&4H>HYZNnv5`k%_C#h+Pddb^DatYa@8xuEeNDzdVNRTYk9r;^W;5l}H zb^J1V;6E&e4H`fF2XyLP?e2dn3oG$uQO}VTqTsl1zieJ;*;k;Rr+rDN()l@7M0G#` zqt0}D5<{^0{a&{hS>qZdYDNLUmfrT~8N@t3_dJ2X(oKRMT&`BoohtHp2z-?o>@mnG z5QJ*l6_EO0qbE2pPG4GZ|68!-aYad%Ej1!5I_gTXn~nDgbZ~EOD11LaA6w;#sl=0< zXTGL06Iza`NIIdiedla=d%29%}d|SLiCp3h_!N_(L(c zM(q*1jWs@;T$w(Zsfp~uP{sTX^+o;t6j$miqC>Sax49o%(ky)$qj9FDL19;z<^Zi{trdN*v_lurbL#0~6PeIcp&BR4bU- zxmh*;$ebXKU(CVSqSW7?gAAbx&7*EQwE*)9L%;T1-lSCLc@|0<9)#i5tO3ra9Pke^ zPHj~oFPW~U&%fwufOxbOA1;SQW#C{n1O(O?4ZWUN>maafDu2i3>UY1yNrIr++0l3-?&Eg5*gln|4Q?FNvokj_ z0qrgW=Dr+%?koRyQ=effbIjOD_KDCln8uCYEPcuZP5eMT8hnp_P+8ta(XJ*4AO0~0 zaciW}bdll9n8F^6GP~4#D#P?M3U}=)vY~7xovZ~cV+6Rze=_bjhNd;;4(uA23XIH( zW#^1Wt)@<-abOjGoc#@`E3}f5ID;i;Te4 zC*Eb3@+l%s8A1I=IKUiZh13;}I$Oci|55g^DvSn#irNU)(*`(oB5=1A2lx%_cectF z3^t>$RuIg77rFrODq?0r%5hnic)F#A$gXN|yT<#;y|S+z8TB*6(*g3g>zUoTxmtH( zRw>RR#&NbKDBH;+Dv978SC^lTXCNDHDP#^kfBD0X;-tO0eq%z4ZiA2emGs=icfK=- zyyfz&I*h-X{?~lp?-yU*d9d;|rAK^P0Creg<$aW$^v3q_USh*coYsK2xBo}U%DT@q z_U)*LVn(^x@RR%nPc%76)GjBf!9}fH`cBtL1@5391Q^nHS;rzCbF1xB=fDJNa!~5Z zBmPRuU(o9{?i-o+s1cSusbXBEML2rX7qt-C}6`kuM)y?0TMBam*83SIPbZte-DAkitY2MtW2SBa(68~ zE1n$Bhl6K__aI8h*GmGeOo%ceiRIvSvyRwG#d<62P0PvccMYz4aoK&Gys1LS`dj2i z=C-S(1qiH{y6dotcvd9ldFP?S1?069J`om|M`(^P86NxJ89qEx@ylPB`vOW=En8!L zr94o|eQo0fU0-+LWYg6meaY!M1tpf z%Ho>EKAW(c68ec(ZDU08S&pA>e2h~aZw)$en6I~AYg&iG_O6p{)0}ke#@V4)#04U~ z^vcj7WO(H+_Zt)-jRsh0bbV@^T4 zl1FP(Y;!$dC^iqu8)HSRC*S%&=_KT8dcY1}I>o-HFDrqR(Woy&#`%@Fr0EMpmLXa4 zcpyX7M&Eb`&x`AKL|;Gpaa#efl@ik0Pa6w8KI8RR&dXKao*NgZ2J|e|BAs*5IO>y9{jyIG%e0Y~fJ|HEq$JH!4N642K?+N5y;Q z^Q$E^T@=Fk97~M*YzzuYDfct($j5`FHP*nbzq?gXffd+^vJt_m=`>T0==D)b@kdtU4ob%`jIDL@Oo*cBoGPK#wc4ucCYtJu--(he) z`1W>h!0|ZT#nQ#_$C5!lx^~85clpBg=j{=dAvil8y9ol~9*vEnsdn_uGge3s)l_@m z)NC7MSmDFL6$tF!M%1te1op_y{=uI}X?Y(*Uibm>;)xZ~?V3$(Gn>nHQp-tczqI0x z2n59K$&hV^x$+N@YQ5PSckd=Yir`T9YO&fk9lVWAw3{Y1T$fbav3kIFk~YTCn@VBM z;S|ls`bNu;j_z0_LR@mgFbl-M6yjd%^pynY^@2z1vxZh(8*T!Mg`RZPK}&iUx^aO& zt^eDf)bWTKRWq>2`V)IWbmh)9k+T{p#yMI&`lgnTV+j^o5cDunk>8WPb4Lbi|2Tl@pozWJ`NCDQ8B_*zv zI3>J>hIFzXfXKm z4NxSxL+kF4l6bzm088;TDXXD={PaP^>81yr{7=D9Kbz6&^X)7|9y!am+}i=)PHse4 zT~RF+f06m|p|Uz?Mv3vF=$rMF0*H%cB!sfOUL26Upn<27h$r#!!^j@0k=zGOrC@@8 z7P5|6P<&s~4t!LbV)z7io@^R zjt1^^=a1-`AVJsHdgi*))eulX?5&>Cf4_=qq^aIL;hgp_>6Fo0;R#yBk3zF=)QV0+ z&p20)dIv{@ed3k)9A$&@d}3&o()55_V?XW zR^qO+SkR+YJkx83{47N)to}lcsKKOCtW-(Z^>aEMyYkBq?b)yL<#Sjk+GKlR$lvt6 zyn6}P3Q3y z2SJ|)d#pU)eU8~Rw=ZtWl6BO1<=8lBWOy{F@4QESiNLbngd`m#=9bY;f#w za*)9wD3h*m_BWGBoc@K{7$%e8PvvT|3%CL|N9Sh|cY3QyM0xWWo3@wMAPT$)zBbfu z$@}g(Wo$UL3ax=l=nBw0UVd-%ydgS#x+ElBNclvF6NPK$q5k|uYY-81stJ7hnA%Bn z1$*CgD|9_xvgbA>T!pmtcFp)|8py~DXa0}nwmGjFTX#=bHxE+DskFE!oKK`1xB$ri z$5+QhBaKW94o!vmC4^#1cpS|94(xAYoj7pva|8I6nU=d0c3CcS5-(n6&gj}Z=qq1n z$=q`rr0s^q+!lr+`WM{;yu?4kz`#v994B`)RU<1$`D)MM><2jcdQx zhOXT3I5KmbC^1^2!BOaJZpXxbh`7f|pnY4zN!wfPrLwLBQ(}evYlrzCsr*{V3K)#v z(~NZ*^`9vkfvqaN2(mHsfl@#y0$8h#oL`kWmPf&J4!Oxv%FXZ4AZ`lr?(B{b1B3YN zj$sV|7T13Q#q={J3X(ZgcwdU+-C{s%n%9V3hQLv4y~j8NnFkG$vjM|)sA!+tsOH)r z&dB;#|&jK6(Nu1wNxbiuVK8T9z^U$vR^AkG}xdX(Ogj)Ouy~ z*1S`%(B@K5+Ryy~3_r6XzvNfA542lbERPwa%Lo4vJ3ScILYtq}^SsNn@8&B1#rkJ= z1xXjBQ$+{kKKtCwn-)k7~?rU-0U&W0w;l+ zqNJ_rcC3`51p}`iTQHjz+9-N^?=z{x*yXL_47`q`$+O{UplO^ePr>@UlINaxpx0QQ zahCmKZU?jW|%Ae995F_)H_AGS>R z<059m%c*{E5N5-N@Qb(_Ut+b2PO0mjRJjrHXbtYsO9CkW7_Hf;S{+^4k|1I-I`cj`Zy8Lkg|G%^cbIG3%Z*KAJB1TRXe z2Ai`HWBO8gb;!{|kj}c*_GtfRM;IbU&z6P!G4AnoT97lF8%Y-$;M^x{aW>aKbQNk9 z@DDXkR~>Nc4V9Pd4)w&a?#?Q?jan{E>}ym~`Wn zbG8_;PS)rhOHI~4Byh)JG+x>6$WHiZ=Y^&v_{xA|%hK)H0vV?Bn)nNYOKSU$owuxd z(C;MK>^e~uBrqn^y28TN9aa~R37@Tp_pB|CX}zI2EIv5e#3UJYqm+2qwvSecc9@5ntWKW<>%un?*X7V z_@{6D4u&RV{Rf)+6EwI(`ljhGAQui#JRVE+_`0U7M^)tvuT*7(gpiEwy{&GQN2cRP zL!I)H-BQIIW;!e4T;{&8$#xs8&?|hX+P9nUT2fPma)Q2xmBULWWzd9FCq?1H_dCMB zyrEx_<4i(fpiSm)Xd@G0))|6>2$U6y+zwPPi;7$_s1)sI;5Zzpw>O^a>FX9xT{4*|5H*o?^)uf0Wtb z0d#(J=~6Z#?~>$xNx+h%Ww03m5b+=`xY>(iy?7 zPh&h!#V+~L#?(m)ivef)kJKwaf9?ad#&Nh2B`YKYZfgB+6AM~@#7=W69>kcKlB0_T z=(fEdo-1nrk~4|-pmnWF)niVH3(6DD(^BBHfu-YY_78*^oyK9ydyjFEZ0S&jQ&>10hAlw0S~}2@$b?5KfHWPoHZtiUIdH zi+#E>|A=!q2(bm}YK28eyg@~x@G|E)-u3RroWgPosWo$sgy}8Cq%^&P#-3|j5iz~W zX=U<(9RAMr)ILxXIQ{udRV8vjJJ9~AVt&&OOLEV{&RcvZR2fy$LnU@8 zn5-gomR|7rGOe47ZXcz^(Ab&wr#zuQB(#9E1EO8v=9DFt8AXL;5ihar*SZm`nfq?) zL0>dJg@1@jQcaS>>}S>cZw!45AJ2`Xr7YCQ`~-XIXWoU8g6_{}3CKT5gE=)AzM#qW z+-0nq-3>e{{fpf8Au|*fu{Ja!T?aTVyTGoO-2(#M_0+$fMPHiHYKyui;=-IW_%TPR z$@wmw>c|i2?8xw|$YlLT7NUVB5r&ypjNkC^3-8Gsc2x z-0jDiy*i?k1fJ)*#nzTeT1?eJt}FaELSn>XcR7Q0&zfsD07uMn5dB$>!3*$@**6UJxzmzpqZpNA z(c~!FC(u!2vi8H6|&Q8V&v)5OhLh%F_456KNFJ8R!W1exQVV!Kf zO+xHG$r|a#p?Rh2aS+U%aQDugJFBD&MDSf!w@GJrZo6PmPt7#ueL3njVDrZtZEhGK zIl)=87o>Y+(YE~XZGZr8{9s{{s>oKc5v_d@J4P=-si}#4*nnyN;sJdESg~Ja)@koD z<(@B+VDV|Z&iE4Y_^jR6iGUJ649Ibs>niG5$xwDz#ZpqW=aUpY^eW?m1rHWK;PF~^ zZGbv<-^FP$k$dc;g06jNf<;uP@Vyl3pM)sMWG*nep6eExz(IR4vg_^Fdv6X^{l$SPW@rR6h-~LnkEcIKpvOgP+E$q&Ii#t0dFmCu4YLcM+iFK2MabmNyC++ z0Xpa(r2dP$u`!$>@nF1i4sj@T@cjr6v`S12L>FEQ*d_23BxA!Lx85;_hgjdsxoUTl z02Oss%NxPxw)Pg?Ml;t_X?a=Uu0jZ1#bKdktf)zQz|w7vi#RCGi|RN6OzjqyIUrHE z9-S7GzZ;L-MdY02H9DUtJrDDE>Wr+9jBc!r;WwJT6nkI$u*UrUuHi#IvPQW#T6{XB zB+*b$h-G#2i%2KR-fHTLPb5A16PVMrj>;y!`I_q-DpEW6|LExKVhMhsU>vq=Jw9)I zZQEN)k9+Yk1AJ5F38Nxl%H_=8gMR#v2*Bz8!>u|L&>I|$+qrt>&VkU4y>nh6<(j)Q zg@uB7y$c5`m1!>1ZP0+36?*Y-*-$t2;lNsNvsZjxxvD8;7UuMAGuC%9-Qka|jp?+( zzlTH83zR1CR+xD;k>;q;o$pVV-V58NO-X&AioBIwc80$vB%4M3yt7zv-2lBmBR*ZO z3O<5wMJ}Td7bV(ozw;{v*de+4v6O-DJ0c?aA43_O1O~fadkLhH(%ANL_|2Lz41C6uIM=~=D zV!_68FfMFbPVE~xT8$R|uv%Zw+Awt&NGZa;{R4dfZT_V`JfMJR6F-kOx}F4qO&6*4 zlBWgRv!`Yw@`pf+-8J;|-WYMmUroowGq9R$UooQz`=~3(hKfvZKkY0lc1+SqS8xrX zu*0|w(SPh2ww6<%jr3s}T&6%$b+1{^~FM6JIyY)0cxFHeZ55#|Ns zwk3c;!U%-@UMZ_Vng2 zR72cBORm$TnkbU0a-~e)l-oVTtQE2UkOe(6&AmCYGO?w|OamW=lY+r&Psd}|nNFOu zFOw1^-RjA?XCDY)-kR+6!9XbcJFNPtXd<-1frnI*a7ng5P>k0uxma1G-?Y)4ZZkpN z3{qW0=`;Qds0%AYa`Hu1b5RM8=<=hXA~i(8V(Xo9b1gho$-~3CW#j%3K>>IFM=$u2 zgfNlQ>2FSPs!s#OtO{ruliy9EMR(;|UN*8g<3X)I&%*ZlV?7^x*gPwnT0xF+b7`?7b#z{2PpS;cX;oHm9 zAD_`i)Ufap8xK3$IkS@7kd!b}nF(=(@THiwQR%iDJTX2L>!-}y{z@C25H5v6#UBvG$BsS`Kd!{-RZ!rdncTD#w+S&jFPdoF#TK=Pnh&!KC1EN^>WMa zU%@2Rr=B#2nOBu(gw5vKn+HR#h2HUOJpvzlZ>u+9m%QceESvvYlx%>lE9!XctZ^LT zK$>=Aab+xaN7!l3c`bS+<2=r>xPRb_*M^5iY}<)1KFny{Jt{i0;ef6(#y(zN^V~T) zVSIHwFeYbq;x8?sLG&+74zLA9qjNxnR?2enV)TcOkmwI8?TnFXeM=>(v3+f$+*b-n zTW!*Uaf}_O&PsL2P&s7)(WH8oTAIZzYESD_tYY7R&oogA(jXL_XHn|{DsyRB7ZOar zBf{d+z%ts19xdgzIZI=)C!*&(mnQgQTPN#oY+onm!1{GSa`jmu7oUTK+L_gzVX>E= z_Vxge;<+AB@-EUE;d+9AvuQyJYAf)uN+qD8O{6Lo`bpBm*C3%uj$(+nzqGU!b#eHx>lR{O zaU2qkL$8#~8Y9dK1hC}PxO!)bmv>x}?wsFtic7Mfi3k{~(^ zbFDTs$-gizcwuuHYz$W=aF+xz?yi=9>}VOyUkfr~_v^FY%)M7>?2GukZjB&6G{y*} ze6A)+)Dm;uL&`O;1`0GZH-ydzXe3W6}2*oyHQRKT@^&uf8_= z5(SCHd%3?1*AgE^?Mb8U=4`EK6D!Q&&}l3<89P^p%y;V+)($TpBw&}7s&2;S&@O*H zIC8x?B)r(J4*dx5C4#Q&SBBc56yZQWcj*I-8_=%U~C`rAFYG zT=2D|N6Zro*0u&UQ@}-ZQs7~Pa}u>g7!h?cq56pcZ0j|JIxXDM4lXy$91 zkQd3VuHlEb*=Vb@Zwz)VCm#t~OpPfk#2=#L3c&6DkoU57IrjZbffgsyrIfe z=wvpmUn5;W-a5@dIqxHBE-6ZJT3tStnxcv@ktV|%*0vi}lW(yi)R6X1w|#V}S5YC= z`73R((uYx$H3qyye!gx2Z1GAlUep5ngLvVMn|P zhZCOIW`|7vVP*0~9!&Oq>9%UgS%Dx1fBErQ)(0wA_H{EAsOr*g-KGOgxXwx37Np;M zq6o@l4+b%J!Jh zLGS|Tbz;P4G^l?@vU7XFDp&-IKxzJr8N*2%EnL-X%ferU#0d?w${t~$um^J#R1 z#;FNOAo0eoCjt`&8*D%T{*&F%hf&c4ay?lbqC*=Qj3Lc@pzmLk_&_}lJbn%lu*7`8 z`RmFUxJ4N|I-8>mc#i8ihV0IGue1X7ZVOz-g12Tq6Hd5~We#sGr~fZ_D=;*dTIf31 zxrvkq-vNaCC8dmV>3`*ILZP`cv0f88+B4+Xz`a5FLwjA%>)ZZ3Nan;#n|^ zMFxTaz+?o^EY(4?P@08KTq_l%#?aNbH5du-Z?zQ#KqQN(JD5&^LptH@ntGA3EvN6n zG!iB98DP^bai}W0O&i)5Ece zhrf`sS&u89&dfGj1j!mVg5)JfNg7ap8Hh_@7*abhdtsy(lyl(D2+v(me8YCPuqc$b zbQaJO(iwDaS}B+nS^k^DspE6pZfw+Ji9Xx*j9TkFRG3<6*E=rjd~|GKS?E|WOl z@eKV(gsG2@!a$44k_F@6!_)9FH!N7LQx1#@ADBJ-kJKCEvUjP_Pe3P&)U`TDM{=Rf z2{W72`}dIzOs5qDig+j?+UOFpqyFarOGIz=E3G`v?Fk!dG`XE0U!?-xUknyLY~fM9 zrRP22qR*|#o2{G?c~A3_)qnbgsy|toCHw|}k#JJf7?=nmC+mOkQe1NSG++q*Nrr)% znjzSLDExTol_dHMM!210NQSU~Z$47W4IaM=R0p%52Fb+7N7zdz8NI#&n85cKCeXbK z*9W?@-}eHBgPL9Az(`>*otcMb4TfYJ{f?M%i>^ZJ-k5zo7lvZr(yw{ueK-jFEMvVg zPH^2O%ymzN;1j$7uGT=00#@ZVBYFbfUgn?&_Ry>7KV+Ka5&UACAz`=iJ*rtSNvoD3 z%TiLlVLsXTGR1bJyff+MQzhv;i+4$4@$m2}Yt-)Fx7?ge@!W6&L&CH1r7Pk5n8~&K z?Fo{ei8=b8Vk*J>XxUqAYO@kCUIY|Yb65F)U>-*3B$ruzg zvcrehj56f#;lsdQqM;HE$@8T^&<_h*o5=bFwva3dHBa+W?t?A(gacSHl5#t0Fup8Y z<`bB#$!lSB=kamrjAu1C$1N11QnUXscB4%q)C#Cs@N2hM#+1RVZ|cpb1oAmwnc(CU zOP*_~oT!iQ!88*~(1!%$G7$GCIh4YmV|HI0M4GgH;Q~^`8a`?@_%S+iPbQeMvydu- z@cdx`!y&oUeqQIq2KXRvP%Dl(UAl52_wk`^TluAent@OT3Fqgi=bhZEX;RdWS3e&6 zke`9cg)%~mb1T*rAWVldCl%{VW%Kjz>*KHmWE&ro(h8m%piVi7H1J>_45gE5Bj7uZ zW^8Lj9a}m@w>E=$#b(r)RTKmTT4-O7H{Mx``#??Aj4qObfG7A|N&2@#mNLQd$M_M} zPGu9#ux9J`{KYrcf-w`X}0slo9%T4=7Qf;n^hNY+Ui$DIbf- zud%sZLxdBSw**GowTyI6T8Zii?F_-dB{gR9w>6NN{Tv({G8~3qm z8l)8KbUtGl7IILGfQPc^|5VFo5}5+{=>{ zM0SM4&l0O0*zi#(@HuLAT>jS7w6s049y*%X8;J3}hue*!^>(PS`P(}`N%Ve$tn>_G z1RocacJKyxZALc4zo&kG)>5VC;fE!Pc$GZ|b=XzU>7pa5ISdcj^ysc}qO_eA`!Sc(JhX+TZNVWS=s!$TtX-7L52Th5Q-Z~f8& zoOFX3;>YC|G}q_j2V&tU1am$G3BPOvFLbCHdqsxNp*<*%h3g#Ut$5#YXD07W`>bYD zAkshC5I@!##wVk{qf=~qUW@L;9sVR|On#_Zv|vIUG3UZ?H%7E`&3ncOVhSwcB1hcM zoL+LO+rVT?9+c=MEI#>eqR(b4SL}No0c~S`@{M#01)1M=&UZ{d>aIR-#~n zcaLx63=!yl4Aol`BJ5)o6>|u{C%SjaZ0&(3a^wBVYd?SA4}K4N?Lt2wFxxGZ#5X*U zwlq)C+VqqfNJf95HGdoA=@h2VulBR>^XlEZ5Hz`z4PU<7pOiFz8~<`+HjvBVz>Quo zZ+=Vh0YMA^Q>2XYD=iZ|v{Be9FI@z-{*#DIT(urTj0Ql21P7CVm|uQEEk}!ADOBhrZQ6i)~(~AP2kq&eC*?}kt{DK zj4Y=9O0Fd&|I*?%}=*laPgK7T5i-;GpfC!~DNeb0)sO6*BjT5(}=opsmRbP)$<~CiY^+b^zZNAl7Q! z9q|SA@h&assKv@DegI}+ds1fO1pbKe|C$95yY#&RThLputV;zJ)d0-K|9xr-L;g`0 z`$nIk5X|$%26L@eNa2Un=}3$a$ug^>1OLxDSf4YFy5)l{iad*`iL9j|`iy}&Vs#&) zSipp;>h~)@&1WAN$7xQ3p!zwl@Wr140R!{W24sH&OwiNTB@nz+2VKU7zL6H<1%9$r z0tB<#-^v~Vjf|x2?{^{VmuNL)jLijQu1yyP;$G8s17l4t2j6VoV^GW0U#R7;!Cqnv z#xC){20&1P(@Yt#kV7k)e+=CSV?qdcDCwxAK++2!x~t<9_}1~_b%SSBQuOl|R{34A z=Kn*6k$>~EA<@qTD5=IQK+sUO?^abM)7?1H8k)9R&NKjG?|kuVr2K6FM)pZVU#=q+xUorI7e+$fWNS_l` z#3Ti8089T9GK+?mxb?*^04`zez3IQY`(PF7gn20ppRfw6+yD>>fq_VLxQ21*;H;51 zXlh~ZKejMIE<`QJiubdmxR3R&Kp4-&umO~9ue3TTtz$?ba6w`+2R?S-27&UK)Dj?! zTHchV>;YOyrJr0+I63Qzy04D&;NRR z71CCGvbqaOV8i}OwSNs-)-;#JS!*Z0xy!|0a8**E1)n*9{X2+^cw^Y+S17a zz5RHBobNm5@5B_h_38P7HF*DskNDL1n(00>hG{2Tg7(<9XiZ8LVcIibrNwaW2WEnl zmMpD6iv65 zo5CsD+K>v+0}JarqeT)#py~|~z{-P~^+LO?KJn>Rjs0z_zz`5dppW6?pmMkztnxoa zNoQy?04rf1l)}S3Whh8rSI=%L(6I~@J2ix<+Pn%*)=&_@&Gvb~T9}(^W ze0C~(3L5q8QrGxi-D8jnYJd0Cbgde#ChBk@{_3_JpT!^^^Hb&|A8|lV&KK6-nFrYs3*I9aAt{TC>aRN+14EQ@Lo1 z0hg>flLWbltk>H@aiaQ<#InFFAr@@#smhz1)j_Q93}piW?0~X7kr6wCWKkIJ_&Nf9 z6t^-)EA&9MC|J$}{x3@mU&R$9u-#VrwK?#cX z7O4xw@=J$uRviy`H8S1Fmc}%t+3tn6seeYjHDs|8BB>mi zdzD+Hv-cVq!|11o7~NPIQa6%w!~=PcDQ%(??`kXvrMpGy$`zICD;@+9&wU=h-9;>f zOxsJ8Q+ZU*ZMtvwc!6e(=H&X@jM)s+dT@@4!uvCbK$h&qF)Fl?HrD7&Z8#rE>~PJ+N79A~HjNwSKZ!#@)E&$y`fEk^$(TTS^{IO1 z!NYChdaT!A{PxltwE``j`{1B5`=ZZ&HP z29dr84q%_RomHMT-kl4k>&n_At&?G8=^r>R0Q>I19A`POT9xIvcGB1RGAH(u^BdoY zsXF(-9P=%n1!YpVO)BGpPszP4bDx)U9FKPgjF$1E9yZQY*cUXoQUT{;G2$&lLy!%A z_ng*V|C+ehJ!GlvN(Rg|`6p*_H(Kb>52vhOE?_( zsqMD5ig$CrB)`>C-k+}e@seA;KnvfAI-2V`4hq-BX1_FN)*o_YS^I2F!6WqMA{c>h z&_AxWt_69klY;qA9_$}7%&QLioL&*hmCxS@#v-%EjIlg-5Z>8CS&>*!?%TRWUiZb( zUJ;pB-c}hg7nPrg4VJGvWXJS{J98(nT$kF}X3Mnb)eK)Rw-rS)T>(>T+sC$z;u6&g zD5B)5dte#edhq{LC8K1-&!Apk#&{P7z-XlF&}5|&ULxI|?Iu=sr{L2;GFaANgK`CO zs=mgva)X^MG+dqW{VSEPI|H4y9@&T-|CItTOVYiD)8IJYZ;0vDAz7}VNRkLC8V4lq z@Res`*up>j=|A4H2I<#ALEyftL@f0_k?AI$K_q?S4nc&4p&ySQi8Flqj@OsI!e?bK zjLB7p3)FI06{rX@5wEo%sQL@K!pkIxygUcqB7R`Io49`e#7MO8)Smz^?UQ}sP_;8> z!ji=7vecXfKTMZV46(&mToY=abY0v2qZPHLc%39H4GLIZI@PvW0))MPB5w=%pE!TU z@hZ|BESmE+nQ9@L+)AUfnuy!4kX06psL$rM04DB~*8pji=u-XPiwUk zMAvE&U8ks3PMZ%*<9-Q}!O+-o0jQ~(G&@@_pvhlY%^G74b&zbv`3(b&>;mv43f8*| z>Ym)&-$~IwpSVGDu5#yDV%vSHx8io>U{Ds!c*(Ms+L(*KuKG$KM{<|Yd|B19!`KH* zS{c7Qlo-|b?`o(qJ_pV~S}{X`+tp`Z++P5VrDQpqKLKQM35`Un9k!I*WYe2DWSnsD ze^#-`CIj~?dAJr$F&RjJLX&dqwNgo%4IhxOlq_6o<$Jbj=v}!R#^d)Rzz%(4ulDxy zp`*KN^oJ4ul7yP*2&@l4Mtd|8;^gcTfq+VT$78l8^LJaVI_MJvTqFm=^-1ih3Af)5 zFr8_vzHX$lJO4p%Hd(~$-H1eqjPAz)x#9jkgwB@vb`aP8T>)45< z7Y|s{I{dS4%lOxSMtoMf6^@siaJB4VqiM?_P5ANms!R*JoArhue6B0mRvA)6=PdiYsTqdL;Ne%N18UgwWZXIQH-v=tyOGrj=j_1o8vdCnbbviv zy54?w^cS)J&+24d*JsGSX6Sl5yHJj7q)8BFMm9%Br2ESx+tsvtHrWp2&|3kLV;;H+ zOdk4|0-)mRin+Hnh)TM@+$P90?RztEji_ptz}-r?mtUh!jN;=aK}Fv&UB zt)9ELGI!(HdF(Eu8Dy$*fQgR03%w`vO~VNbN%T&$Ohru=PlA$F#9m*(?XuT_?~5Gn^ivyjd51#>CsqODT8FL&0Vgt2 zJZ*eaW6mO@Y{&*FiOCaBk)*)()cSSmNfE|fk-^oegS3epizYJ;gUU-nckCF}+{>K% zf(y4cT(V{gLye+e+U#S)ttW#%D&eBZskHbk;y`q$m+$v6Jmone{u*i(H_Ba0xKixf zpfldzq?~m>((CAeA-&{@efpDvtC-^?Zuk{&>ddq!6&ss(CLHRevzj{7QQMsaO{r>- zF7_Ya+Mi#maU3XEY2arV+JvGX)nUc(dd1mHKMTwRXRsvSQw+J_4I;zZw)8W^U3 zOj6)U8`J;e>#gIW+`9K+1qDG6iIEZ!5d?>n2I-QP8W_485tR_6q$H&~q-&_5lnw_F zX%LVUkS^(lcMl%VdCv2Fe(xX0&-r7Rx$nLAy4G6Py4Kp8!L;)f8!{NMnZoC*v$3rD zDfw$tk`3~%BO0P|W@_C!2(rGQemg3KHp=pB;s>FL%j*(A*KT1H8IwI^z7L9kHLeVm zhnHbS0|a%uKn&HF!SheD-Tj=*T!UND<7pCAc$dkq>3!Nm?WJ*lz3gVe!)(%3PEGbY zHh)ea_xh}?tVnzjR+*u-S%OI5iou*hHr7}bz$(7aF_c6LkE3*AxQjGuxKDY_?t+;g z*SHq@rUt=a#$j;&atF#;b3f$11AA|pPtEfP^f@-BY$#6W8@v%}^<Y4Mfv&KFPF%aq)vcdUm6dX9Y^D54URI~(=2;_kX>8myH1STs6v`JEiir&@Lmd~2uk zm#>~5yX3@(iDGjjw%mr6?Y@IpxLXC+=6iYgLv@)CH>i5vFEa4lDLLQ9 z$Fz8SV?=tVju?PW(jwPJH#tbG0R??g2M2t{%sUZ$cA4&y%=<%`YukG1$zU)`%YlA^IY;J zkQ~kHL=E2#9MHy&lm9e}f^N|EzJc$#)7BzQendp}PZcmKE;3`(^(8jKxo1I9j~$%C z{fmU}Z!(cq9%*Jo1iGc)ard~3ieN-TA0R0eu*an#i6(K?SwcxTn6UgIYk3?8%2>;e zo6Q8`vP=Z2`h2yn&^*AM7NVPRN+n|Ij)AjTqwXw1_kRcyUIs_LETeGsWYJ;tU{oSs zjU!%*z$5&|#;Alt%|8C8Y;Wx?i>{wzc}86(R{M({xhjRD9m5{Wi-sMphP;v+$dP zde}mN(J0of4Zh_&!l&agI}4Q08oAjfnyr!8ntk^Q*HaS{2P;lH zrNZ@O*|`F>5LvZGSv6!@Bt3fI-)}03#4H9Bq%`jdfWiNNl^cK+UtVr~)^uZplJ&fe zfJ9mAJ*DhrOz-CZ-zL)H;?gXHVr;?E&ooRU;GAxKCM&b@p2rB=LmY_Mh|WIv)Pgd- zbpIwSc+IfERueMd2#85a+Hpba2;b=9JJj;Ag2yS)DiEHBQ0o-_L>cz~SHGx)$3?s7k>w2Ys~Hi(WY=Mm@QS=|M`D*n&)`XgFZD?hvK&_w zR?LF;DsV`MfQ9uo--m!ez9}ApqA^XJ29<65tMo?bVi!(03Fl=5!_7Wsafy5^GZV>R zL|dtw>l;rZJQx^ZdbYOw>L}6^f)&*|JTZG5Z-{EoCv$m0pLNKbVc9j{aTW2AuD#?2 z9h$#0y`IQtL!ku>)txV?>q;S4(inCizKS8A$ZgISiP9i@O6SyR#|Km2RSI-9M$2qOWm17Pe2!T- zURPwVOxUDi_QOBNJo{*V)oaxhoJ~Mc*4}39))p{8y%yTu3Pxv_N94a*Z>nX_x~}Xz zQ+_=JR*WVz-s=9)J?J`N-?UnN!OyDGV~g|pdsOo?Ru`?eOhxOBKX5?;&OkyejzWvZ z#_4Wh{e@~^hBnV@d{~6a@>7);wpu4^vK?c$&lA5F9*A*1DO89jbs{WL`S@TekddKm z$x>6sPR65t6AR2KO?o8A9_9uDk&!miI2jWV7KC%D^kI~wi%G@?6XsFG$;DV&k%P(& z=;2q+c$qM;!?)2V_j25xRGQ(z)JfZ&o%SD>%Zymm$G^tx;?fdi|vW(CASYjvBqFKb-l(mHPe@ZQX z=*jl@!(7QZ8IGyQHQgVw);I`E=Lz#^- zIok;-B(Qn)_xGn$EX1aIWc%c+Tka|qeC9o=-A* zfh*zB{X@jFh(Gw9WSG z=Gt086Ng(mX5(#D_zN!IWRti?ZUeNNpxM>Wvy4W0Ubgl{8zARTu!8G6$& zAG$g^H7o2t8f#q5d$Ci7fsiOpCU(JqCHgO**tBLFoC3&m}R-yA?tf?0T2b~NzeiZLPH1-0W+wXj9?0|v0ftQ@VOTN-* zuzo&Jhq^eopgP(Zh-xA=-$n-k!PC(Xfw3z;O!^5Jd6_04v!C~@^YCREx<9h_ki+(5 z7tf(lXpr|4m{(0sPLA%F#v_j7n_kn`t=9WFb`K24vx$#ROmz;_quyqFR$bMkj{&5# z^}mY>Y{6eaQQ@zouu(S22cPVMahKLaw_1`;dt~4LSF5F~#=VNo21?T(A4Kbyjlx@} z1>h$HKRFi1Id+Ov__0$w0I!1uRjNIq2=N}*9{HmM_+)$&{mWJ4=owt1WUZ#SpfuAS zC^`#@_jHQQppJWOMFI*Ik+Y!}=RtmoPvW|9027y+=|#!w64dJ6 z7x#=yu+;_PPKJxHvCpgX@A06QpaqjB41<4ALXlES>mioOBZi(ilE;)qtr) z>v!dg(WL>w%ZC3hQ~sU}h}KjMYDj4VTj9=QX1}6YD&a^LqVhL){%=HscCd-^M57xZ zv-?AdTQSge6$~K!n)hk2XOk8O(~6CnWc~`?uo1jV+JpO<%i;_jZU>Ra(n zzW6m4+VrgIeXMSy>`uws#PwN7w0T=JT5A~8pkyE#0+#1@#)OVa@X$fIaUoe_#P=M6 z(|Tj+M`v%Ed`Wx14eJz`>e{>-1n+aue>e zY7MHitTw>r9&}5bFY+1`>%UCCbs5V4&96`s_~Xy{A3mM^rzDeOfiXx6Oc-C`wzU|& z-lN)ZhBw25 zfO8M{;rHjUkdn8quo-I8Ax$8U&JaLI{Vnr1psOwsDRzE%6WwqK{m+I&0{8D8i%r-T zUCZA-uYsEvgg+M_mW3`POXuY|xZyYzs3{HTa$iN4;drl8EybQf_0mt*3FX#IK)f94WhU!DebBQq~24| z*-Y}iVhFjjn;YkU_iY(j%$a#?Q!rJM>uKIK;*)cOev-ArC*9mpD{wa+gIAK zTNSp$dMD%CfzZY5M67<$d3x37%Gk{A(v0LF=zKToZ0zjr7}wDPw=_&}?L3=FeL3Gn z+*`I7`QGj2%%Safq~r+urRB=8vNy)SZ_<=S=m;3Keg-q~%*MVmon+-0izGtSTY&qs z#a^|m-s}PQwQ5?Xrg@)&jUSnkj+=&qS8z%HE;TA? z6_eO_YzR#9e-j^`Asu>fDGjtLwy&9v~ za|728%-Io_sQ5=*g7!}-HwKoQ$nyV+2lh?GXbZ|&sF-I>nP{u)Bc}MBXv+f2NqP0- zvTL{A6^x*BbL!d#5ffPO>UDE2-Z4Y)f3`YihQ4j{ZDc*viowjr;GT+eTOBFCHsR|( zJ-Dxyyx_hcsRD-0z7b8nf>wNDX$H_6CHDcz2%fNE3?16-N?=^L`U)T)ti6flB}whE z`nBZ1+v}X0O^CV~4#B!5l-T^fRN*TaCIefVIXtktY8=PDdJwd#zZ@r=dcIyWm?n;W z)DU|v`98$`c05G56#Sr@U@``@udutm4#-}M?bJGfjzvr|IPF55ko8{_sqFwG1rR%)bc!7Yas5fN|5 zsp@A@=R%}@#6n?qBi!BfWZO8MMP%AdDX;hVj((i(qmtRZxIe`r6 zMpo8PSpAm-zU~$fj~1r z7(vD}k+`e;>BZb)8;@Q(nA)8YJ6~&FnP}kzyt9QxgY{yB0CjrvDYiVg-6Zdx+kPsk zccqi8nXepaO);9#$o3vF#J_wo?;dCd`-m_7K30JP2ELNJQ@2_@_NE@)3R?7pxRq?> z6p>23`i3pnkS3y;r(F23LMX?6q`tvsQnrDLUk3};ISPsyuR`{)+7TA9It8MQfv``8 zOj5vF*l{h8AREejs%LQvKo{u{l}(6e^r9hZRbgMsjPAH}ddEK)Mk8*!-97QD3sWh| zEBg9qd8WtvJA~X4c9i>gZpYiBk4m6<3~;$ z{~_o3NALx_h0#a;eg$x|%whuxnEsbuWz>_>ju;tW%{RM>9{u~fgVDc3;y(fX&zNl@ zK}4J&&@+YOeo+ZQYv?4X1^3p$!2c=_wwnHbIF6gY_EZ}K!0?N#duZw_+tvW2p~Vf1 zY(?mbOg;qVys3r;JS8gH5PZ#m%rJlVjn9~Sn=c5^AEyVCeM+296};@#K|rcp$j};; zgT9m?-__CPA~rPymO7*W>J24Exx`CMVA=`le1)Y9A1^Ctc7s6kDY}0yIfjh!3>fT8 zF+0H2iy1sSzbKGF#-Fe9q zMKFVakt{(Qo!-AcL7xP)rcA^Pt&KtAcN*%~y&Hg_(>y|l7gm^!fvSQFU9Uj_=>XWl zKQ|J%JVxhX063at+h9wCZjp&qMV*3Bt^)N8km~ua9e>TXef6U^?a@9Wu42j070fGK z`PaO{-f@+G%3%Ml$jW)+x5|M*_$6iG00gn2W(^)*JR^x~ZENexPWbq1PWZYn7R1#) zo_j78J@W+ZT zJCsDJOodQSIR|9-yne5ju$`hNd~RzXiS5oYQKf>y-I?&v!yBEHDVeE6i(Lk2RzLcA zLfSrc4iJOVsy%3E|0B=83N*7O6KI(}de+oe6hh|10bGO|c7U zesQdnJ$fme{E%$vA8R}wri~8c8SOC7yn$v!p~uD z?{5o8G3YYwM)wVUlsx*x`71l|xtV0*j0;eC?JVP4m;S@M1Ta7D6}SW1ZbsnhprxlJ zFwH3QEA4B_k@e<#Mw*A>QUzf&b*~rJKa{)>O^n&u=%a0RhdlcW06vuTmzoBJxp_=f zPjFqN1HeR1PVHjZFGC$Sugn`tp%If@aON9U2@$I)6)y`~o~r4kS>P34w**>SPW6ej zxotCL)roS&+qP+MfScxvz%oX^Q*?R`jzkeO{`nTi}w4`VGySU>_TgqOUPz(2@%-A^O$?MikRLA5m-X2=XX)T7u1-YZi+$Jh0QTp}mW8>SF=l#Nj4c8wY&Pp;D-8kyj_>?+& z|GvtGkel{9`np z$p^&ECceoJe?S?tIg_wj9}K)R3cO@Orv`iF85T`Xgse434K~Jpcz)(EJaF)`+Y9j| ztUxp28a%+4qKHsZgbq%4IL;yulMTYnL*#}bx3?G{u<8%;ijQBy;KfIfW0_n<&O~Pf z)j3j-nV`nbzrRH|3pD7hB+DZ2ZGECb&Qu7riFuSX-9a{AliXpuwwmp(;5_pIXIX z2bs5#&HiO1%6Fk*5JIHU&iuQepbR_xHxV)QCs=}qTa;3)10562OA-n0OA`Fsegb*O z?4e&3VUU*Gj}RZkb8+VTH%%n3IbI0~2dg0UoSxMi5qD*NZiW{h5812@>zq_N*V_uC zgB!NdC7zbVO$#Ac;fA0AQ5`b)$?j*Cn_2ujCIUF2%+%pX7-WH*_O08MyU@K-n?m|O zI~%=+DBtJ}uijl$AT~Qoa8y?#($@QyCted4JQqSKzDixgJtD__Un~I{glO;P`*<1# zDK;%P^|%Y2>@FU5!G=#qDjOo36(PAyjM=aL?3t%5GU5Z3*I26Fu`{IW^>Pm(U#Y2@ z4PUe_a_b;)Sbk1IZJPZ7etNjKq9@{=tjJTH_CPtJ>8Bibp*OrFD?)ERm4QhJRb7vS zNK4^AtdO{r`y-eP19>l^{;QF(cU?8I*(GJXNH8li zTXih+zSRId&CFuCwV7mW^mPxH{IBai+4FBo>wWeP^S@k2ZhfgOSX>C|q>}y7k$IEQ z3^txX?mBuEUg}S4H7yQ~uRjMc8gs^U5!hf%w1qb(m!P-GK($0Noc$=S8g1Y90-h-O-bkAb*2UN@OHg#hH^lqUO-jJI}zTDAn@1rG+2A+C>|ZOxCQp7|uU-f+ujmfF!yguNdIW0^ z%oFhSFl@*5n14(w26OJ0Vk)?z76A$GS!*`QD$fn;2*hO+U`>6owN)5Os$++FISFeB zj}V#ehp0V9X}lUsH!tr_vEO>Co&z{tqdzp!i%E-$j0#^$mEbVTnr? zu1$$QqMSRX4q(vHaesqwreL%>=SL5H{)NHmlqg6N)_n9-|KtX?3F??{PlbR6`UZ&u zpKgH%GK4|eWvwy4t@BJ6d%FRc?R*Bl>T@@R#unWr`1DuGJ_LAo%~|sutM));72GKB z>S57CexD}ns=?>Zh5ApW*suDcN6Kc>O?Z1r+5<74DrXr3!wOBaRc1$@ z0EzJ6OM3_(rMP6f>S0sU&yB=7d|+zU_mzNs#7CkcUnx--Q)A>0mG;0ZGGfH1;7{LR zd9%R{b8yvSNL2Y1F=rz!CDW6!( z>ZVt#VDY+GtufA_j0eP3dwk^AkTdsnHyy-bpBFAMvnhhFW>-X=MT9|)<7KsJxktod zt7NrOrl?TOdn;iwu#zUdpHD<>IKT^-S)?H>Fu>_02j>TUdfRbLP@!J9@KSH16^FQF zxEF#ql~|(0|B?ynPH3(#!DTc8fzKypy?Z;*co*u3r`8@wMY0x+-oiJEH=FK&Z*%2M zza@lT9$tW^&!tGdTr=pAUB&SR+t$4pZDs}w9%7W^TZM5<9bxXQJ(n=t*=1_KL;q-izgtdMdX{8yfZ12?cDc zf=^tX!3fSlH6rk%F%(yjPc9*i2=B5i$o@IQ)BK1DDm=n86WeAMKZ&9k|>hFXiwt;P)@VORwFGeThDz-jx5ilNzl2aGr@Vh@6_B zdB|-k%;VkZvrx#8emicAR{+JnVw*35SAlGI41^9w54zeNME?mMM);nF)GtkT$JH+L zyRVXc8y;4+Re(_OJ9}zqdfYBUg6;U2bM3M*_~`(`+bqOr$BZrT&$)gQ!-h(*mV(v# zVdZ$eX3k(f#)NM=y4MW}wBx1*<3>Up^F>T$*t2Fi*@WVyNL0c8Wj{}2GY9+0ggN{8 z=SN>};Mzh&xc@RoBw1_Wvi@`D#Q(uGtjFsX0gVx~m-54~0_eq+%H$A4{n;{VpXVf4yx%#!S zmVc23s@H|!Ilc-!od){Msz?Cb4TA_^TYW%eX65u1maX@isbWaZeM=v<99na-GQ`HG zcp`U4JGZMDakvGow&|D~-Jk6ylMA{fB(@e2Y1!mW(AP^NzUWIDJK%>;X*o@OCwpt_ zh0CixBactzgK7db(;d~|2qw^pR2E zszd3>EtV~fP9Gn)9tj^DtYeO2`9w#)35^oZXUTlx#H93`t1l;gHWLsfJ>#zC1EUTr zTxo{Q>E||s?cvNunj5|X)@-!U^;OZ;!e&c@(z3{D+4ev@xEQ4a+N_O5;}9jPSKrW~ zqWlIL4@@YO<-r5RHA5;(>Q{rhJWB{714ZCC_3vbG66tVaAay!!Zgup~>ada{Qf57| zebUa|uZpQcZg-(Wstd~$ccDd!@8?ZlnzrN;BR{j;3xUU=!w4v_EXyR z7uN9)Q+*qH)7=EFgm?EJJh1*+Hv(?!VKhA2AJ%tbHkoU?5)a2}HMyGO^_>r?92*IC zMzLRV!jTxbTm{ZIZolyi1ArYcvKA`c&b_SF$ueo;s48%=DJ#@rcXt%)4Y%=&>8lG> znv;-P^Q#)`2xj6as=h3K~~;;PU)49$5W#++Og)H`UcGRU+cQ zCqApU&r0&%+?katYh9FdlvhY+rCRL>je_i9)!E8!ZjGL};Mg1T1Ri(90ZX zM6r>4-*KD%65O7QEx#%n#D_*u-pFWCm^{Yz3wyLrcYgiGHP6n>6s+xQ#^cHL>mWcs z+|}9u;Qt8sZwDSof(Z%vY-zAyKpv-IhuI#e!Lici4#4dvEq7Q zfIt15?oUm;Dm5E3@;L2L8w~+~9=i7@-~=Y9-a1**u#TcQ=6bDgmt=N!5V<1LpKf)bqk^bSEeytm{V2M z6PoJtwJ^l_!C7L)1pMDKqCKPbSlC(e7E8(#CBeGjb=EjJ%e*|Txufg%zRS^k52CiV zCg?5XFt;dUU9Bds>P!ds$Xc-m>y-Z@T;u1K+djF@YBk(&)|$v^(JNxxIzP5C6mdrM z#n;1mM41ukA6%i;*@^hU$!3kP=h6rEQC~~gMR7UWMDpiL0Ta|H@9yBY5d#8vsjEnX z)=o8yPCEf*Ce#|t7a|qPD|sAxn(PKZHd*tNc?`sACOjr3yKXMUt)~O|qGo@!Z_=j0 zal!?SfaP0RbDXc*4YYp!5FgBNbt+^sgEgDKzX*CsLx2(dszeXe_A-dW{U|KyCkr!s$E~TqT_%L{l`)VTS;aH)m8a6R5sX~V zzf8G05lv8|4InO&VfkeQuritIE(ehN{4YQ1OESdMvvRDsgJDB&0&r@yvzoffbuy z%tSEulNT$N-Kwjrrwb5ak9DL#MN)mMIhMn3?ICm<}8W% z1VZDX)<;G2av(H_0iDEbbIm_G0=HTI7^-=$+V`LT*q%-wz)`*(~cIZu+lMhK1v z8>h)VV84;f|KWuhu^v)bT6qg9VzzjO2Y^5>+a|3Le7W&OHkSTG>XIw$zFeG97Z*p_ z3>POaey26L?RV<-z^d()ib=3hCTjoNulY77;fTOW@PfC)W^dj2S0?h`1jCdcjrT(Y z5gPQa&_H3*#6?aKp5$-<+lpowf1L{D!G-&O8`T$OCip~whp=}XpE;gjh}8IA?vM*T zn+@yr(rqf}zc#Sj83x8m6G>I-cKUwB^=kBPVmUdje zQZldO{O$;!NiagPlck*>jlh%zT;Gh56OcHbs zj^1_TJ$N&THH#UHt!(BS4FP=9%B=1?EARldVt*N@$nPcb1VP?n2eLhQc69!PczrES!1OD(Mfr#Q|8fcOTZ7?%fnM#9Tt$>R(?m#w>5kJRE zQh^Bf*8^~7d&UFaCG+Q~)NpTVeeB7~Ntj()vUFWfL&6NlkxF#&+fXWjTQ51{5N{mk3}h)^XpQhM@2wBk+YK{w z%#*D)w|a9$^`>#mO;+F`w`gVB1G8x6j)G{QMM{JeWPj)4O}5w=hG4sXQr@zSj9_4{ zgRY(bdxfpci1f?QiWh*RV1@|7#?HWF;+TXK z(YF2Qfg-1r;TRVODz_BwNW)i4>T5#|qw-(t)mKMx2G5b&xoNi8`9=A`qpvfN{o9By zgU%%hAg~s9aQ&J$;7Ox3!BlxhbBPW>A^%@+2GSvZu8obCd4%_$}!q5NGn7cZn$>z zX6VXt6qiqR3cr_2vO_$KM|)Jg##Zp#24ha&^{Kx40hG_0>fx7Fv36M>CJ|Wr4W+#6 zBL8GSpZ*u=V1yeR)?AH{809glR6eiIe7^?5X_q19`VjYn9@(Ss`a_4lfjD2V2mGF{ zSL|D+XL$&HG-AubrxI^5BdxqiwhFiGrZ+*Yw#O7aHjylPlQ*e#5l#TtqwMCHalVcY z1D)J8R}k&Ek-k)RBvxgQj@oeGhF=?DUHlrvH!H6&)!RODpkRy3m#gnrJQ}T8rlNQ} zOSn~d8a2ARSlm@q;-Oe=%&3ky=BPqB#%(H2d@Zfn5{SDbDo=(3V-cKR)91)Xejyxw{6eAQr28oSe%% zo)W#QG)~Ap_+|f0<~U{Tvf+lHVd}uG`hl4VCdGDK0sP?Pb(G?zf~lGTR%!W!5vNsi zG_q89pT@h5xayDej9|T~C3(aN;>8E+^!tN2aC;?|-iXD&d`wvMqA?*I37|6UJ^Eeu zsYIw1yXoB+ZwcTdvRB7S@O#MYWA+5c&YKj6ji~o-knGL7oX+|nO2}+fJ!aD=DBf&m zj1so4w%qptA~uom~4EeYG-IIK}j^|u?E zIrDMYh?hy#Vee&yN@;a+Bg$sIcHf^3x$X%P`>LkGC0(610=1(1ct$wjhPy{YZi>Qg zM;x-NQTgAxLZN3r&s(2P1sp~>9KJ6TZ40$56I!b_?Jsdn9q9NL9Mye(Z}XxO^?#(6vJF_RY5us8Tp>3S{55nqw$D>L z^+SS{{-9NG2d;Jp%Iw9F&Z}f@xqccB=|qL^dt1bxW8Rgfn(Es>pc<(U52d#39c}p> z(A78?z7e1j z?0>REuFGIN=o})BT6WU@)wHj`D`DS$J68JJxsKFY^*+rWm{NteT4HB6;u?a3alH7p zc`x|n*BLIwrpN$cOCs)d2BA-aTqZkN;`M>Kr~Rgq4MMyO1&MBPVVZ{)(xe_|+`Bb< z?)=YdLp*N7V5>RY0XTy>O2Us^QkUltkXpMwA zRiy3(7DcsERo%7*zw1&%At#D!SPZ5Ui7QP34&xQ*Lx*>NXO_I2&z=@u#n{ksivt(Zm@H5XKc; z)4Dopu#x3Ti8L~m_;juXQ1+$IEp9ZtO3YLJuA_K7A4BbwN$bCa7kuW#M&9$Q`JRh| z6EIkGggsjF^Ts)jmf5la2PyUW6d8rfg6gZ>mjr+ek4yV%8X4W94vC6NFwC`k#(D*A z@9KxBAV3<0Q2)*>{CWNcQppsb(vZDG>a%D^Jod2~qxqIlf@hC46)>}fjhtb=-&hk7 zafUN{$S_EidArszV3`i4t?EHc_Qv@Sa}0tNSvZ%9Yh1L*CQvhDu>?4i21U`C!th z?GfeHK3`uM+{ozZ{qqnjVgVK7SwdBO?uSr$#gWx6f^)cx@bOpvb0PA|lT~j^aR%!S zriR86tdfwk)e)mp$#BOt_+~$m5-7W*J=8U94}8U_THOT9ZV52gt7@0^0rNVIW?s2( zqT~{viHrVOt4xuM(uZJE$7S1;SZY9 z_4j?27aQ^a5*V#?I{6}hOjQwP4y!HyO#EMlgeH;z7J)KI=vGU^nV7czLCBtm4|cbf zm_tpKauo+lz(|g_fUL!-U2&F=q9y0fut)aiD3;3o^O0%(hp*qvJ;EgCADYaVw;486LTf9aVymFuS;pv9XN=rxu~vGy#O7LR zvY^^iRgM=dC(d`(3-KI-nE`~yH=TV#KsHTBZ<7t&dYn}D&{g@zl_!=$__e0&=r9OJ zOeHoY%Aw1x@a@Rf_^Dc*eFZbJ`E%w>P*n@A%JbVW$KkOa)#B}- zx3n8x-Oig-aus?L|A_Sr!UN(a0f(trU&wudEQS*CIQZt!$exy6XGdUcjI$W5mOJ6U zm`t=?cy)kcW*fSgX?s`pqr%6dh$7kwp=JA_s9VjA5{CQ7tbLwPkHRlLXA3C{inM!W zrv>MdI8>^6>;8pj*1L43xwe_cAD~;P2g_$5bDa1#b#fMAtR`n1Q|X z$%iAdYZ5LW49lP^9#fAa)4%$%Jc^Hemf4LdZF#IVl8R|+`b)5kY%96uDOnuWd5 zxd*x2-oeM|uuPKo!mpKr79{DdI9cNtWki|VzY$$p`(b)d;9}Vw{BICwGuapwQb1pP8@h{l5ef*;@AW(8Sc*v4+}* z&+}kEf@Nv|PG#xYoXdVRHE^M_Ref}?8w9XCh#TBstkss2@V3eTl88yO^d}yY=sK59 zOAw%`zBW3Ca826Zh1Lepra(Y=1>FhOzYb^b?%1ZIO~!I8KfAeh`ipwh?BItR%^Cit zAokN)uZJOoV>~m*N8$j2O6d7*Ue?$5(EUngW)xS-3GA7)sh%$~&waUm?Yu^HC(CS= zirFQ&5&x{P&Kwn52Sg%01WtJZ7BE;k^JWwdmKn^XBj&JD4A#lf0+|8X_Cd-2!1xDP z@PPzqhI2am!UdxFBDJXKpN?ycbX*~$^mM9;+&B@Yh~4=+0*=8H6gN~A z)agLoQRJvTJ{qzlaJ%<16Xv!GxA-x}e-sq|5H`8=P%43}r&3jS%I#hG3cr`cTM^ue zU^4DYJl+m(u`p;5Qkxr7Qjdo8u|BuQLBGZ)XJ;)d3KJBOkWObjx+?tqH*;udo7WyG zm-?aJ?YQ5Un00I4bga_$RU1OPqCpt>oN#wzN;orBs$-F~?yz-blp51`QP{dL1#}I7 z!8wlQ&(@rFdc6s(VwvDa_mdyj&bh)gsaT73M0qA2M@B?OYIg+y^-EaTle(jwoMB-- z$(JcdWhBO2LsF9tbEdE64$TL;*R*p>H=iKBU2Et@Ae=1&9+<&=2!y36LBLMJ`mhQ- zEXwQyVLtKyL9R^vJ^6caS32wW^%|ZG4i66yzh}*sV@;F?HG%Rshe5BpDh`?NH$EY+ zgMU+3f3-kWr8=1@LxUtLOgXPTzq7lZEHmZN5b5qd^nJ$x-1ozFesqRjT4@tW5G~6%U)yPev8j#hcMKQ+c~91E%j)P?Hm{ zK2&O@+_+LP2wr397hZc{dCSn#785Q>Hr4=SK;;KSBLncN-4=NDMKidRzA6kZ%jFTO^tA8 zBtu*BV<+#k5t_fMMR}mu$Z-v=iZU(L)_zFD1noQPt~SfWgSN$(e;fX$42S1Q-FGI} zwBB9)UZ!1>?Ye)5*#fJBI5M_J=+pR;sf6W){%P#-YY_vE+i>> zuXzKk!xDuvVS&>9)99}m0n#5&>HCTdSL2@4o{d_+>O+wZxSqQYmm^9}AD&|4U4y%4 z4}aOqE-^KdR~x~0g^5WsnMl^xj35y0!!7O1t&iAPO*zUzZuM_wcPT@H_`Rm7hyLL5!20c2J>% z<1KVO3`k=NnIZN@J%ROAKPNou2Hqu#bw6 za8RydDlHnR`)li&X386s-RnX~oq5dy;eNoKV1ml)cbqb4Spn zToa?!Oy5ktp;Yqxt+@qAE==Z<$jdC1vXlfESC_B14um1ei40)QMsn?wgRwSF8syz%RZ{ zw6=C;!YqU2tUUBad}N`scnU@Dvmf@~nG_IHuDi}(tv=V#m{HhgA^VChKhM84TzoeE*AA#8j>=#~BuJ(q=~2#@|$(Fy?Qq<>YtZ7PNfXTj>Ik+q!Lg;9AQU zbqL61qi=B1euJ~68!Icz z?<(5z2+Uwcsqlc^!foe)y3Ia3ba|;&I!K3(2Kr)7Zg&WH$>2-BcMPXWO(HhBN!+iu zW}|k^gTu|hKffSJeN@qS;ALyX z!Qmy>p_Q2Ih4{<@1<$u#RRc#qVE4im!d0N}{YM~K_MhdE%`fF%4Aa~r{$o`{wI_i% zmySzJ4V75jnj3N?2tMru&?Sf*N(E(;h(KwT$QooFhM0C zekkl?J>$JDiOv{q^fW$VyN)USR*nWrbRS1y=YrZmOHZTw)5RV_A7-xBzUlb#wXN6b zve%G_?;6}N6?=Y4={=JU2@;R#sa2drW_H#gN@8lPImWK8_JuD!otIH~RMKt7*YIEN z5Gv&lwc5C{0&d8kZJk6|K- z=Ohsl@|(q>LK2M~?EF-pjtRVCS7J^%?(IwWtETGgFq^w9{krIf=OytF4rH^0Pgi|s zyp#U*CboM}FxGyzO4W`y65@u%poM|9-E{*YVZ6RNBqJb|<#PHjDnUfzZi#CXdG?Zfduu-$YI$<7 zIm&3vJ-hRWPkf*7^iDuBdD{w+lDt2Qad<%$9 z`m}NvI`7P=&Oh!BaeF-sZtdl|WfS@McyU9|&||$X!@qKHrGRy~7kYl+U-|mXZ)w1C zy{=)1d%CQFBfRf?ywn)GFsYtTSo01B7&3c=$uo;xsazZz&{q=a-$&bUUMH-NP_Q{1 zt*)3l9P1dpvvgnzr1-9&9NB%I;E4cglkE(7`77;#Wb5xJD1pw_X1r7HDx6)evt_QX zTFzTNpplzwuyZF8m@Uko-#TzJ3cN4pk-?YivM8XXF#H`{+V6@)WKjzXXcW zF1Kv+o8%r~!6nhiCP69w=nEPOnJ|O6AI+WdnMkgm$N4Yc$aQuK#+@ z=mge4sQsS`@`=gZ&v8U<#_WoMHiIUNztT<`=oc+_M}eSzsWGkkCY+rDh&j2q#zC#> zBkcmkO=L5K=k0GTWbco;Fo^dDHHP`Dtb4HStKgCra1q>+UMie1i6cmn>W$IoDBE*G z0)^Vs`kQcaK8DzoL|5&Cyn3^yjB>MN-@*+C4V2F_B-%4oPyFi%9BmNc*bo?j_v@)3NBO@&ddyP3tZlBwP zZqJ^!1+;CDBYn7+|E_cYTLsO&r7O}XN5BcQ7lRqaLVyYs$cu$QA<3E1WHqC0LPPB0 z0Td_V(Hd${@_g-%p{MoGh^r7NP)$*bXmLg9dzCW4xYMP?!2{gJ+n>{!Ncu6Qg*@yA zRcW@ew*ph9zz>H(Sl2+1x@MZkhbC2YJlIW8yNqI(nAdX4@$i7tYwFr~gb^0~6wc>< z^0D%Z;HVx+CxTZvuB#itJ9W>U@GkU!7$ShF+pJ2ld+1{o@D}0I(cxz+VDa?4J}jCV zJ63++?f-D>2HtKQ_tBZ!YfJLDix9v|f1ZdGv~?ss zzM5F{CuzkEwH$W(j$ScC5Kw;U@DvZ@A3^q{bP#4D?*6s)}-8}#XMR9Q_%qkC%%&FG~AvM&;n@d?-6yRL6V^Aja& z@{s?S-Zc zME`oQJNlamOUm}!KZ7iHj}*#XTIf}WLn)%9{TM|MO+RwS~rvS&t_hY%SlM9K`=D_NoJ+4p)K?a%xD`TcI++qc{4 z)*m{r*Y&zy*Y%u_`z6|@BZNm^K#&CG?BUNR2CCf{eJ~`k{Z;L5@<2t|soa6nqS?6u zBB_OkJ${xYL7IJD*pmtLweH98Oh8*88V|ZJ$kvMI;I*p*0p)8S#b;aN$AoSa){*e_ zJw$hWk8FB77+uQHj-~ zgqRPTAh`qeQMy{QX+C^Zl!)WwipxJ(8-+STo%cz+m+NcSWT^^^yMStO;uI{<#ZplX z|D#Na&@{Y+YS*HBL{GzEeQ>O{#Q#FYGRX&HM|h5&*uX95vI@0^*#e-cf7ZKA)ChCg zV<_#VzK~%PL4NAeL?kf8fSo~X?z9t8-G%rGVT&Q30eLFNdO-!G(y_KjpJqn;u01YB zt#E^?0FMGPRj?{L=#!=Lb2pdm&FM#A^dQ4FZ<==$cfU#owVpexb;;?0k*-qD;#E@t1WPKKJ+iB3BEP_33i5!yBb79Y2L>Xh{ioy6vH zEu?{G{X8%}P6lj16852ViPO!us{1LpRS|;p1Pvri?bWcgzpQ7m;2161&B+FBJtbwnds-cy>8q}pdcjA-SJfS_ z-HWPl7Nlxpz4+~0RY7D?y#Nc^bUi*q`e|75WWiQ*cnw)JHb#_>pu2(m>_T3_tZOF!@wmh>J17W&bSfS5W@k#KJQ`I__rmVmyB$6`-V!2FU+XmmSJE zh{h6Pmu&J2!y}!PX~`D*?=IENqmjkCBdai*sg18C%Cx!e^K@SZgPN5znGE?pe7-xw z3yRU1PG30}&w_SN_b<1&XWlg1*}$-vqzbqR%NXG{KVJxX=%SbPI)osajA+o5l9C;U z_a3po<$=US1J)~T42z|&dR*#@q=!Ha!b)eMH5|lL*}DIc7~3`K>L3T*XH`Z#*K!C& zd=NFfymJLnr+ON0C$Mn@)xrX6MMsNBH(J7(M1**+(Anc|5R!{`@)m zn8d!o(W|SX_QQ1|iw&kCuq?Y|441XcT~S{FcB(*af$_cE{V8nG!yHJjcb){)h(!zn zY=Je#C>*qajZ95^$79obhBKCua;PGazs3^jilV=58V*x#c~`q@omQOq9BeDx`$~SY zbl?q;5GO$OQFG$&op)J9)V(-%?+wmG@OuP%Y6T#J)RiBgd7mbAx1*za&fztY`#eG3 zS#alh4%wmus89iY7r=TYm$J_wB4az*Y%d|#U|Fi9U_)Oewu}&HrtBC%O01=I$n%Ng5FM`X2p+nU1G%vH!(86tLWELEWW)(UpRzL`P!V4Q%kP%?I!Td z=9MgoPap`Ru{FMA0az7PATIo_MY+S({vD_ShLd!oRJk#hwILo{UeHmY4Ad`7!_vB* zu)&m6d9;qHDJDjfpa_{(-0J6;(UiM_)SxHAnOa)b9P0%|2w#=pwqVcqZPC|W{(W!! zoYZ?_uNS?bw@K9!9!`UN-Jw@FG@GzlFg{9i`VKi94;W>-^a)Cne+j$-N#VE-T)y}x zUWY{Oz9N{L_Sixpw-|iN-KY zBD}CtWv7-{5b;X}XHc_}18FShS&kSdh>S`z0Mmid5Q9dZCY?E_o10QGT(Zox+$aVI zs|!q0rikyBC0If2oguY+(9ctAD8c;d5P^6Qw7gBNtky1IW>={-Gx={Dh5X$qG^I)> z6~E#F1SXR_5!w{Lsc!*PlBz0GItbYZK$*gnOu4u5?oUm@3cXUWY0wd7PzJMXR?7w* zcS&wJWO8mWfdiznF++Cds9@$l3sP-Dm?dWN*ld6YcY8&ttNc0Rtmj1GX8Fn@yreCp z_L9!$sXoRs5t#mDE59g#Ik4eP?6L;$fCed$3~bXM0P;O)6Qwa%mRq=+24_A$FPmL@ z!qrohGL$#5V&Xt50)q{o2$E$r{^xH4o%0=fkDl761e3)}BTtC|*_!n>4`j}%EEvI4 zQ#82QDf?Gws52LvUb?^rYnI^ACIS=MLxL(jHx2Ppo+pJx;mkJaiSxWgZ|c`l6Jx3Q zz8n`(B7ZLhwuXmgl^i2@b1WNwQ2}_F#t^2|AatIB7HVBpRT@UZ;V;O+ci7aqrzwB3 z6BjREQn64Bj7f>tJmaw~K<{=<9ES`ZN&R&Bh=(T`D(aM;b^aM(b6lQlU4}M3Mxd{_ zDB-T_%17;2P<2f8MQk5#- zRm&$K2#?3=g&O6eD#!AVGQh1_`9171#E8pg-W1QGdE#xyA|%cD_%Ck}JXO=kIZAd; zLH;gD2Cb2S27{PgHb561w!L{X*QFS`|FQd`PNDedM`*-+UtB%px};>lTfhrY2YbW| z&H1}+-ZBTZX9zW+qvHw+okgEsok^Pg!l^d*K-B}zv&{Z&U0r2hQ(fVqafwV>N4ZUW z4$}!81O7LF@Bkqe@+Z7yg-zx?B6- z*{DXXwvtype;vZw$+HaPC2 z!5|h<`twA%faUH*x8)C6gl$91&llojt9Lx@an2C^a{ z=+-1S7eFTSHT3@N3v{5?KGRqLg&yl)?w{BKb{_Iz8{pr8m%^9%f8Vq;{K~_(!x2>g zZVDjviAE*vH~->a_{r!l8K+=OW1lj`wej;Hs|z@78VveEho!8; zRs_iQ&&o;PWQq%sMM_B&NPpnO80u6;ywt_x=1tKy>vp+d@m?hUo>u}^38T3O2B&Ey zy@nFh=P>y(NVK9|e{IU|%KawFA}x0|7!l_Xjv)xBRN0|d!INp6PY~y)Dy-F|(xXgk zcJCBk7$4XnXmg^^kfz_O+3!Cp_Ruj1-Gf4eo6XzMjsr-Pxv?t>);QYnbvCn!pO^k{ z+p<|$kh1Qpn7ff&AGi9b_U5U3WeJ(&1&?O_GV7N?Vf<|?^8upR{KaCDW&XE@G%KwbDN(RP57oP(x~fJ~UFR&O?PF^4ZEhXQnd) zBeX7GyB3;rCz_gzC6q=mW0!d5n#G4VTmelyB_lO%`?5z@S{* zpjX|*VZfo;obvAd2wLhP(XQH+BVeB0s7SA}{75=MA?cL5Pdba}b@L}`b?mKe>-~mm z#LQm7YYRA55}xbx`TOeefwC_M8BdqC7nCgE1UBo<5l6*3mGPe@(Je!>%cpfJksE`{ z(&7I_heAhYU|X?ZZ$=s%yx|$NYXhQm4geqJq`gJYsud4x?kuXT*nyHR?lOwry;;B8 z%7mR?l{hXIXfCifpT0h=&W2eVa46D@qiYL=k_vg2-veZ7GZC0y8Bbv=5zPHV%$xn# z`J^eB_c_x^Du+3}?1We+5$P!Nz^3;LWa4G)O=0voP*GG(%HnOgC%_x>;$0GML0(1r zFHjpt8(MdiHV+jB%eoT_X4NWl5H-)6Za>hsLh28#k#4+5`oz(CpIrJ|=5HAXnGU(kybb~jypFPmk zRLhpu!mUz0g1D5sM$0I@PUx2(RIh)+%+yGtYB}s7#7oKjmC>eBw^HWlyMVTt>CH~V zdtjZP)JXM5Ku9ylR}YULFjqw1;pqcGohhMSUJdZh4?g=9fhN&Oia%Z=Pf!6m3=XZ; z{6(#(qNzygxr;fj0idkaeRu}M_q+!3oiXq0)6Vk=s^-%}YR{e`W9*mAt^>+Xm#2o@ zb4*-P-|yVcZdSJSxmCOI>D4=+R7;hayyZlGmU&V#yK}2$?6hlI4jH3H){kZ~&qf`O00j&E# z$8pi>01yW=dC0=^6A(l}VSe;w!xM0|KM8#3L?Y<%F{Ii*`n&&=C;aR96ZHu>lXqY&$$lJ+ z;@}y^E31U&6xP0E=^=g;Ml`Ca|J1I=!>Uz}MWTu?mHhew+s(EXJ&T0pj19 zCAMB)td!ve;G z9q+R%O;@(|?|n0pIN0r+8>=jQ9|1;ESruKcspYd;tX($s*{M&Z+G(Sa9Oe9VTVZ;i zZf?7$2c5|hKr`H`(n6o*Ma8pXGdVtev(pMWcsBtx*W1>9-u__%b&O*h?XFC~xV(7_ z^t0|pK!I-ttk$z6AM9sc-(RTPPu#(8FBovHAK%nm)uFjLxI31`ue%=OK9zEuh2?Bn zqftjj+iGF1Mbq57jN9bFu?>lW=dzkPl(}J&r}}uEmylQOHY4sZVtn7HRTcZT{LAzCALGJToI_!VJ1D2r!k&Zyf2@GQdL#eWjeaE%#JPk{(ZU4 z6kav!vX4P8FZ?L(BAe5SEPw635=9ujWH_kBF6JM9>g)R!7Z92`{8*B=8UsNAv}tBg z+fc}lTJT`odU*9s91@Yd78;X1ZBCAjMZOg!YtyPUSp6s_h*ajNx@?0eZXM4-2%fo> zj>Zyee>ov37M3Jo0cxFI6wa8FOjR=eQllvE%{lBV7sPc8yckY+@96LHDk4k>8Hf6x5@?078Ah;zz;W}YqP2dio1F~Aey9Pu$ zC`W1FM{twbou*X+#A>>IWNB_JclG28<&JM<@vtJOtgWrnHDz`p+=9+tp`>A9S^mPDb<5$T z)83Y|{hZ!ZmlEO+Kz}A30k^!bG&fE0wtq#Oea<=W zU2Ua)hu%`1Qx-cB;UOGO=@oIjyc^ov8}@Kk$-6-jj0k6E=gAXyUb8kt9l0g6w-+6e zr>3N5A9wVYzC@#P9u00dv-E|b3WqKYLZ%BT?1q#n? z`iDxo&-W&nQIQkjPO~+H^9&=A;CJCH=HNUP?ak729DHV0BgG`E_J}R=LnX`S(e+xc zrjhE+>;u%9n7C8{#BP@sc}eJzE0h~=^{#er6k7C_(Mon#g}PlGm*#V$P?C-!D2b(B z^r6#5B0HB1Yw|Sf57we5ICyvnmyb+}Ub|-dcI@?c{R{Rng%5>M}} zm2L^L7xS@(m*WoD5g(9Mmd{0JPSBZM%q9$*R`5-stneN}A|`DgKbc*bc$v)3asM$c z(DmBn`hk2tbZ3J_b}MarPr30^npe5c*b+;eX6?>SLSli`{#s+Is`I@o9knZyCmG+j z$*=_zV6z_i?IU~1P*-ueZr#%xhiT4df4y?)i=glAFPa_gHe(r6?JgZ@1JvoVM{xi6 z_=@|vf7|v{^!6T^(kZTXI2Sr%S~)Xj#J!iTXE`=Zk)>p{;y^d)cZ9(Aw@;qh_!H5z z<$b`Ut@grJ_XW{5Y%ookeHEpaiWKB062|1yYuP3?^O=RH+@-{vh2R2LRaIE`%CI#gM> zum+ag-6*4vd-u89NY$Z#=~Y*5#ODyi=CxytYbXAA&Sdrmu^yiA5}#Sg(5j)|NjAU=LtXn literal 0 HcmV?d00001 diff --git a/oci/standard/module/agent.tf b/oci/standard/module/agent.tf index 90cd524..c149f0d 100644 --- a/oci/standard/module/agent.tf +++ b/oci/standard/module/agent.tf @@ -1,44 +1,39 @@ -data "template_file" "agent_user_data" { - template = "${file("${path.module}/userdata/agent_bootstrap.sh")}" - vars = { - kasm_build_url = var.kasm_build_url - swap_size = var.swap_size - manager_address = var.oci_domain_name - manager_token = var.manager_token - } -} - resource "oci_core_instance" "kasm_agent_instance" { count = var.num_agents - availability_domain = data.oci_identity_availability_domain.ad.name + availability_domain = data.oci_identity_availability_domains.kasm_ads.availability_domains[0].name compartment_id = var.compartment_ocid display_name = "${var.project_name}-Kasm-Agent-${count.index}" shape = var.instance_shape shape_config { - ocpus = var.agent_ocpus - memory_in_gbs = var.agent_memory_in_gb + ocpus = var.kasm_agent_vm_settings.cpus + memory_in_gbs = var.kasm_agent_vm_settings.memory } create_vnic_details { - subnet_id = oci_core_subnet.kasm-agent-subnet.id - display_name = "${var.project_name}-Primaryvnic" + subnet_id = data.oci_core_subnet.data-kasm_agent_subnet.id + display_name = "${var.project_name}-Primaryvnic-${count.index}" assign_public_ip = true assign_private_dns_record = true hostname_label = "${var.project_name}-Kasm-Agent-${count.index}" } source_details { - source_type = "image" - source_id = var.instance_image_ocid - boot_volume_size_in_gbs = var.agent_boot_size_gb + source_type = "image" + source_id = var.instance_image_ocid + boot_volume_size_in_gbs = var.kasm_agent_vm_settings.hdd_size_gb } metadata = { - ssh_authorized_keys = file("${var.ssh_authorized_keys}") - user_data = base64encode("${data.template_file.agent_user_data.rendered}") + ssh_authorized_keys = var.ssh_authorized_keys + user_data = base64encode(templatefile("${path.module}/userdata/agent_bootstrap.sh", + { + kasm_build_url = var.kasm_build_url + swap_size = var.swap_size + manager_address = var.oci_domain_name + manager_token = var.manager_token + } + )) } - } - diff --git a/oci/standard/module/db.tf b/oci/standard/module/db.tf index fb21f6f..fb150dc 100644 --- a/oci/standard/module/db.tf +++ b/oci/standard/module/db.tf @@ -1,26 +1,12 @@ -data "template_file" "db_user_data" { - template = "${file("${path.module}/userdata/db_bootstrap.sh")}" - vars = { - kasm_build_url = var.kasm_build_url - user_password = var.user_password - admin_password = var.admin_password - redis_password = var.redis_password - database_password = var.database_password - manager_token = var.manager_token - swap_size = var.swap_size - - } -} - resource "oci_core_instance" "kasm_db_instance" { - availability_domain = data.oci_identity_availability_domain.ad.name + availability_domain = data.oci_identity_availability_domains.kasm_ads.availability_domains[0].name compartment_id = var.compartment_ocid display_name = "${var.project_name}-Kasm-DB" shape = var.instance_shape shape_config { - ocpus = var.db_ocpus - memory_in_gbs = var.db_memory_in_gb + ocpus = var.kasm_database_vm_settings.cpus + memory_in_gbs = var.kasm_database_vm_settings.memory } create_vnic_details { @@ -34,15 +20,26 @@ resource "oci_core_instance" "kasm_db_instance" { source_details { source_type = "image" source_id = var.instance_image_ocid - boot_volume_size_in_gbs = var.db_boot_size_gb + boot_volume_size_in_gbs = var.kasm_database_vm_settings.hdd_size_gb } - metadata = { - ssh_authorized_keys = file("${var.ssh_authorized_keys}") - user_data = base64encode("${data.template_file.db_user_data.rendered}") + ssh_authorized_keys = var.ssh_authorized_keys + user_data = base64encode(templatefile("${path.module}/userdata/db_bootstrap.sh", + { + kasm_build_url = var.kasm_build_url + user_password = var.user_password + admin_password = var.admin_password + redis_password = var.redis_password + database_password = var.database_password + service_registration_token = var.service_registration_token + manager_token = var.manager_token + swap_size = var.swap_size + } + )) } - } - +data "oci_core_instance" "data-kasm_db_instance" { + instance_id = oci_core_instance.kasm_db_instance.id +} diff --git a/oci/standard/module/dns.tf b/oci/standard/module/dns.tf index daaa765..fbe4c4b 100644 --- a/oci/standard/module/dns.tf +++ b/oci/standard/module/dns.tf @@ -1,12 +1,17 @@ +data "oci_dns_zones" "kasm_dns_zone" { + compartment_id = var.compartment_ocid + name = var.oci_domain_name +} + resource "oci_dns_rrset" "kasm_a_record" { + compartment_id = var.compartment_ocid + domain = var.oci_domain_name + zone_name_or_id = data.oci_dns_zones.kasm_dns_zone.zones[0].name + rtype = "A" + items { domain = var.oci_domain_name - rtype = "A" - zone_name_or_id = var.oci_domain_name - compartment_id = var.compartment_ocid - items { - domain = var.oci_domain_name - rdata = oci_load_balancer_load_balancer.kasm_load_balancer.ip_addresses[0] - rtype = "A" - ttl = 300 - } -} \ No newline at end of file + rdata = oci_load_balancer.kasm_load_balancer.ip_address_details[0].ip_address + rtype = "A" + ttl = 300 + } +} diff --git a/oci/standard/module/guac_rdp.tf b/oci/standard/module/guac_rdp.tf new file mode 100644 index 0000000..dc3d129 --- /dev/null +++ b/oci/standard/module/guac_rdp.tf @@ -0,0 +1,39 @@ +resource "oci_core_instance" "kasm_guac_instance" { + count = var.num_guac_rdp_nodes + availability_domain = data.oci_identity_availability_domains.kasm_ads.availability_domains[0].name + compartment_id = var.compartment_ocid + display_name = "${var.project_name}-Kasm-Guac-${count.index}" + shape = var.instance_shape + + shape_config { + ocpus = var.kasm_guac_vm_settings.cpus + memory_in_gbs = var.kasm_guac_vm_settings.memory + } + + create_vnic_details { + subnet_id = data.oci_core_subnet.data-kasm_guac_subnet.id + display_name = "${var.project_name}-Primaryvnic-${count.index}" + assign_public_ip = true + assign_private_dns_record = true + hostname_label = "${var.project_name}-Kasm-Guac-${count.index}" + } + + source_details { + source_type = "image" + source_id = var.instance_image_ocid + boot_volume_size_in_gbs = var.kasm_guac_vm_settings.hdd_size_gb + } + + + metadata = { + ssh_authorized_keys = var.ssh_authorized_keys + user_data = base64encode(templatefile("${path.module}/userdata/guac_bootstrap.sh", + { + kasm_build_url = var.kasm_build_url + swap_size = var.swap_size + manager_address = var.oci_domain_name + service_registration_token = var.service_registration_token + } + )) + } +} diff --git a/oci/standard/module/letsencrypt.tf b/oci/standard/module/letsencrypt.tf new file mode 100644 index 0000000..b9bf330 --- /dev/null +++ b/oci/standard/module/letsencrypt.tf @@ -0,0 +1,48 @@ +resource "tls_private_key" "registration_private_key" { + algorithm = "RSA" +} + +resource "tls_private_key" "certificate_private_key" { + algorithm = "RSA" +} + +resource "acme_registration" "registration" { + account_key_pem = tls_private_key.registration_private_key.private_key_pem + email_address = var.letsencrypt_cert_support_email +} + +resource "tls_cert_request" "kasm_certificate_request" { + private_key_pem = tls_private_key.certificate_private_key.private_key_pem + dns_names = [data.oci_dns_zones.kasm_dns_zone.zones[0].name, "*.${data.oci_dns_zones.kasm_dns_zone.zones[0].name}"] + + subject { + common_name = data.oci_dns_zones.kasm_dns_zone.zones[0].name + } +} + +resource "acme_certificate" "certificate" { + account_key_pem = acme_registration.registration.account_key_pem + certificate_request_pem = tls_cert_request.kasm_certificate_request.cert_request_pem + recursive_nameservers = [ + "8.8.8.8:53", + "4.4.2.2:53" + ] + + dns_challenge { + provider = "oraclecloud" + + config = { + OCI_COMPARTMENT_OCID = var.compartment_ocid + OCI_PRIVKEY_FILE = var.private_key_path + OCI_TENANCY_OCID = var.tenancy_ocid + OCI_REGION = var.region + OCI_PUBKEY_FINGERPRINT = var.fingerprint + OCI_USER_OCID = var.user_ocid + OCI_PROPOGATION_TIMEOUT = 600 + OCI_POLLING_INTERVAL = 60 + OCI_TTL = 300 + } + } + + depends_on = [acme_registration.registration] +} diff --git a/oci/standard/module/load_balancer.tf b/oci/standard/module/load_balancer.tf index 1daa13d..7f791e1 100644 --- a/oci/standard/module/load_balancer.tf +++ b/oci/standard/module/load_balancer.tf @@ -1,66 +1,88 @@ -resource "oci_load_balancer_load_balancer" "kasm_load_balancer" { - compartment_id = var.compartment_ocid - display_name = "Kasm-${var.project_name}-lb" - shape = "100Mbps" - subnet_ids = [oci_core_subnet.kasm-webapp-subnet.id, oci_core_subnet.kasm-webapp-subnet-2.id] - is_private = false +resource "oci_load_balancer" "kasm_load_balancer" { + shape = "flexible" + compartment_id = var.compartment_ocid + subnet_ids = [for subnet_id in data.oci_core_subnets.data-kasm_webapp_subnets : subnet_id.subnets[0].id] + + shape_details { + minimum_bandwidth_in_mbps = 10 + maximum_bandwidth_in_mbps = 100 + } + + display_name = "${var.project_name}-kasm-load_balancer" } resource "oci_load_balancer_certificate" "kasm_lb_certificate" { - certificate_name = "${var.project_name}-kasm-cert-2" - load_balancer_id = oci_load_balancer_load_balancer.kasm_load_balancer.id + certificate_name = "${var.project_name}-kasm-cert" + load_balancer_id = oci_load_balancer.kasm_load_balancer.id - ca_certificate = file(var.kasm_ssl_crt_path) - public_certificate = file(var.kasm_ssl_crt_path) - private_key = file(var.kasm_ssl_key_path) + ca_certificate = var.letsencrypt_server_type == "" ? file(var.kasm_ssl_crt_path) : acme_certificate.certificate.certificate_pem + public_certificate = var.letsencrypt_server_type == "" ? file(var.kasm_ssl_crt_path) : acme_certificate.certificate.certificate_pem + private_key = var.letsencrypt_server_type == "" ? file(var.kasm_ssl_key_path) : tls_private_key.certificate_private_key.private_key_pem - lifecycle { - create_before_destroy = true - } + lifecycle { + create_before_destroy = true + } } -resource "oci_load_balancer_backend_set" "kasm-webapps-backend-set" { +resource "oci_load_balancer_backend_set" "kasm_load_balancer_backend_set" { + name = "${var.project_name}-kasm-backend_set" + load_balancer_id = oci_load_balancer.kasm_load_balancer.id + policy = "ROUND_ROBIN" + health_checker { - interval_ms = "10000" - port = "443" + port = 443 protocol = "HTTP" response_body_regex = "" - retries = "3" - return_code = "200" - timeout_in_millis = "3000" + retries = 3 + return_code = 200 + timeout_in_millis = 3000 + interval_ms = 10000 url_path = "/api/__healthcheck" } + ssl_configuration { - certificate_name = oci_load_balancer_certificate.kasm_lb_certificate.certificate_name + protocols = [ + "TLSv1.1", + "TLSv1.2" + ] + cipher_suite_name = data.oci_load_balancer_ssl_cipher_suite.data-kasm_load_balancer_cipher_suite.name + certificate_name = oci_load_balancer_certificate.kasm_lb_certificate.certificate_name verify_peer_certificate = false } - - load_balancer_id = oci_load_balancer_load_balancer.kasm_load_balancer.id - name = "kasm-webapps-lb-backend-set" - policy = "ROUND_ROBIN" } -resource "oci_load_balancer_backend" "webapp-ld-backed" { - count = var.num_webapps - backendset_name = oci_load_balancer_backend_set.kasm-webapps-backend-set.name - backup = "false" - drain = "false" - load_balancer_id = oci_load_balancer_load_balancer.kasm_load_balancer.id - ip_address = oci_core_instance.kasm_webapp_instance[count.index].private_ip - offline = "false" - port = "443" - weight = "1" +resource "oci_load_balancer_backend" "kasm_webapp_load_balancer_backend" { + count = var.num_webapps + backendset_name = oci_load_balancer_backend_set.kasm_load_balancer_backend_set.name + backup = false + drain = false + load_balancer_id = oci_load_balancer.kasm_load_balancer.id + ip_address = data.oci_core_instance.data-kasm_webapp_instances[count.index].private_ip + offline = false + port = 443 + weight = 1 } resource "oci_load_balancer_listener" "kasm_https_ssl_listener" { - load_balancer_id = oci_load_balancer_load_balancer.kasm_load_balancer.id name = "${var.project_name}-https-ssl-listener" - default_backend_set_name = oci_load_balancer_backend_set.kasm-webapps-backend-set.name + load_balancer_id = oci_load_balancer.kasm_load_balancer.id + default_backend_set_name = oci_load_balancer_backend_set.kasm_load_balancer_backend_set.name port = "443" protocol = "HTTP" ssl_configuration { - certificate_name = oci_load_balancer_certificate.kasm_lb_certificate.certificate_name + protocols = [ + "TLSv1.1", + "TLSv1.2" + ] + server_order_preference = "ENABLED" verify_peer_certificate = false + cipher_suite_name = data.oci_load_balancer_ssl_cipher_suite.data-kasm_load_balancer_cipher_suite.name + certificate_name = oci_load_balancer_certificate.kasm_lb_certificate.certificate_name } } + +data "oci_load_balancer_ssl_cipher_suite" "data-kasm_load_balancer_cipher_suite" { + name = "oci-default-ssl-cipher-suite-v1" + load_balancer_id = oci_load_balancer.kasm_load_balancer.id +} diff --git a/oci/standard/module/main.tf b/oci/standard/module/main.tf deleted file mode 100644 index 586a8cb..0000000 --- a/oci/standard/module/main.tf +++ /dev/null @@ -1,8 +0,0 @@ -provider "oci" { - tenancy_ocid = var.tenancy_ocid - user_ocid = var.user_ocid - fingerprint = var.fingerprint - private_key_path = var.private_key_path - region = var.region -} - diff --git a/oci/standard/module/provider.tf b/oci/standard/module/provider.tf new file mode 100644 index 0000000..9e55cc0 --- /dev/null +++ b/oci/standard/module/provider.tf @@ -0,0 +1,12 @@ +terraform { + required_providers { + oci = { + source = "oracle/oci" + version = ">= 4.0.0" + } + acme = { + source = "vancluever/acme" + version = ">= 2.0.0" + } + } +} diff --git a/oci/standard/module/security_lists.tf b/oci/standard/module/security_lists.tf index 5499bb3..946824f 100644 --- a/oci/standard/module/security_lists.tf +++ b/oci/standard/module/security_lists.tf @@ -1,101 +1,143 @@ resource "oci_core_security_list" "allow_web" { - compartment_id = var.compartment_ocid - vcn_id = oci_core_vcn.kasm_vcn.id - display_name = "allow_web" + compartment_id = var.compartment_ocid + vcn_id = oci_core_vcn.kasm_vcn.id + display_name = "allow_web" - egress_security_rules { - destination = "0.0.0.0/0" - protocol = "all" - stateless = "false" - } + dynamic "egress_security_rules" { + for_each = var.anywhere - ingress_security_rules { - protocol = "6" - source = var.allow_web_cidr - tcp_options { - max = "443" - min = "443" - } + content { + destination = egress_security_rules.value + protocol = "all" + stateless = "false" } + } + + dynamic "ingress_security_rules" { + for_each = var.allow_web_cidrs + content { + protocol = "6" + source = ingress_security_rules.value + tcp_options { + max = "443" + min = "443" + } + } + } +} + +data "oci_core_security_lists" "data-allow_web" { + compartment_id = var.compartment_ocid + display_name = oci_core_security_list.allow_web.display_name } resource "oci_core_security_list" "allow_ssh" { - compartment_id = var.compartment_ocid - vcn_id = oci_core_vcn.kasm_vcn.id - display_name = "allow_ssh" + compartment_id = var.compartment_ocid + vcn_id = oci_core_vcn.kasm_vcn.id + display_name = "allow_ssh" - egress_security_rules { - destination = "0.0.0.0/0" - protocol = "all" - stateless = "false" - } + dynamic "egress_security_rules" { + for_each = var.anywhere - ingress_security_rules { - protocol = "6" - source = var.allow_ssh_cidr - tcp_options { - max = "22" - min = "22" - } + content { + destination = egress_security_rules.value + protocol = "all" + stateless = "false" } + } + + dynamic "ingress_security_rules" { + for_each = var.allow_ssh_cidrs + content { + protocol = "6" + source = ingress_security_rules.value + tcp_options { + max = "22" + min = "22" + } + } + } } +data "oci_core_security_lists" "data-allow_ssh" { + compartment_id = var.compartment_ocid + display_name = oci_core_security_list.allow_ssh.display_name +} resource "oci_core_security_list" "allow_db_redis" { - compartment_id = var.compartment_ocid - vcn_id = oci_core_vcn.kasm_vcn.id - display_name = "allow_db_redis" + compartment_id = var.compartment_ocid + vcn_id = oci_core_vcn.kasm_vcn.id + display_name = "allow_db_redis" - egress_security_rules { - destination = "0.0.0.0/0" - protocol = "all" - stateless = "false" - } + dynamic "egress_security_rules" { + for_each = var.anywhere - ingress_security_rules { - protocol = "6" - source = oci_core_subnet.kasm-webapp-subnet.cidr_block - tcp_options { - max = "5432" - min = "5432" - } + content { + destination = egress_security_rules.value + protocol = "all" + stateless = "false" } - ingress_security_rules { - protocol = "6" - source = oci_core_subnet.kasm-webapp-subnet.cidr_block - tcp_options { - max = "6379" - min = "6379" - } + } + + dynamic "ingress_security_rules" { + for_each = [for cidr_block in data.oci_core_subnets.data-kasm_webapp_subnets : cidr_block.subnets[0].cidr_block] + content { + protocol = "6" + source = ingress_security_rules.value + tcp_options { + max = "5432" + min = "5432" + } } + } + + dynamic "ingress_security_rules" { + for_each = [for cidr_block in data.oci_core_subnets.data-kasm_webapp_subnets : cidr_block.subnets[0].cidr_block] + content { + protocol = "6" + source = ingress_security_rules.value + tcp_options { + max = "6379" + min = "6379" + } + } + } } +data "oci_core_security_lists" "data-allow_db_redis" { + compartment_id = var.compartment_ocid + display_name = oci_core_security_list.allow_db_redis.display_name +} resource "oci_core_security_list" "allow_web_from_webapp" { - compartment_id = var.compartment_ocid - vcn_id = oci_core_vcn.kasm_vcn.id - display_name = "allow_web_from_webapp" + compartment_id = var.compartment_ocid + vcn_id = oci_core_vcn.kasm_vcn.id + display_name = "allow_web_from_webapp" - egress_security_rules { - destination = "0.0.0.0/0" - protocol = "all" - stateless = "false" - } + dynamic "egress_security_rules" { + for_each = var.anywhere - ingress_security_rules { - protocol = "6" - source = var.webapp_cidr_1 - tcp_options { - max = "443" - min = "443" - } + content { + destination = egress_security_rules.value + protocol = "all" + stateless = "false" } - ingress_security_rules { - protocol = "6" - source = var.webapp_cidr_2 - tcp_options { - max = "443" - min = "443" - } + } + + dynamic "ingress_security_rules" { + for_each = [for cidr_block in data.oci_core_subnets.data-kasm_webapp_subnets : cidr_block.subnets[0].cidr_block] + content { + protocol = "6" + source = ingress_security_rules.value + tcp_options { + max = "443" + min = "443" + } } + } +} + +data "oci_core_security_lists" "data-allow_web_from_webapp" { + compartment_id = var.compartment_ocid + display_name = oci_core_security_list.allow_web_from_webapp.display_name } diff --git a/oci/standard/module/subnet.tf b/oci/standard/module/subnet.tf index 371cb4b..e6ffbee 100644 --- a/oci/standard/module/subnet.tf +++ b/oci/standard/module/subnet.tf @@ -1,48 +1,90 @@ +locals { + kasm_vcn_subnet_cidr_mask = split("/", var.vcn_subnet_cidr)[1] + kasm_server_subnet_cidr_calculation = (8 - (local.kasm_vcn_subnet_cidr_mask - 16)) + kasm_server_subnet_cidr_size = local.kasm_server_subnet_cidr_calculation < 3 ? 3 : local.kasm_server_subnet_cidr_calculation + kasm_agent_subnet_id = (var.num_webapps + 1) +} + +## Will create Agent subnet x.x.0.x/24 (assuming a VPC Subnet CIDR between x.x.0.0/16 and x.x.0.0/21) resource "oci_core_subnet" "kasm-db-subnet" { - availability_domain = data.oci_identity_availability_domain.ad.name - cidr_block = "10.0.10.0/24" - display_name = "${var.project_name}-kasm-db-subnet" + compartment_id = var.compartment_ocid + vcn_id = data.oci_core_vcn.data-kasm_vcn.id + route_table_id = oci_core_route_table.default_route_table.id + dhcp_options_id = data.oci_core_vcn.data-kasm_vcn.default_dhcp_options_id + availability_domain = data.oci_identity_availability_domains.kasm_ads.availability_domains[0].name + cidr_block = cidrsubnet(var.vcn_subnet_cidr, local.kasm_server_subnet_cidr_size, 0) + display_name = "${var.project_name}-db-subnet" dns_label = "${var.project_name}db" - security_list_ids = [oci_core_security_list.allow_db_redis.id, oci_core_security_list.allow_ssh.id] - compartment_id = var.compartment_ocid - vcn_id = oci_core_vcn.kasm_vcn.id - route_table_id = oci_core_vcn.kasm_vcn.default_route_table_id - dhcp_options_id = oci_core_vcn.kasm_vcn.default_dhcp_options_id + security_list_ids = [ + data.oci_core_security_lists.data-allow_db_redis.security_lists[0].id, + data.oci_core_security_lists.data-allow_ssh.security_lists[0].id + ] } -resource "oci_core_subnet" "kasm-webapp-subnet" { - availability_domain = data.oci_identity_availability_domain.ad.name - cidr_block = var.webapp_cidr_1 - display_name = "${var.project_name}-kasm-webapp-subnet" - dns_label = "${var.project_name}webapp" - security_list_ids = [oci_core_security_list.allow_web.id, oci_core_security_list.allow_ssh.id] - compartment_id = var.compartment_ocid - vcn_id = oci_core_vcn.kasm_vcn.id - route_table_id = oci_core_vcn.kasm_vcn.default_route_table_id - dhcp_options_id = oci_core_vcn.kasm_vcn.default_dhcp_options_id +data "oci_core_subnet" "data-kasm_db_subnet" { + subnet_id = oci_core_subnet.kasm-db-subnet.id } -resource "oci_core_subnet" "kasm-webapp-subnet-2" { - availability_domain = data.oci_identity_availability_domain.ad2.name - cidr_block = var.webapp_cidr_2 - display_name = "${var.project_name}-kasm-webapp-subnet-2" - dns_label = "${var.project_name}webapp2" - security_list_ids = [oci_core_security_list.allow_web.id, oci_core_security_list.allow_ssh.id] +## Will create WebApp subnets x.x.1.x/24 and x.x.2.x/24 (assuming a VPC Subnet CIDR between x.x.0.0/16 and x.x.0.0/21, and 2 WebApps) +resource "oci_core_subnet" "kasm-webapp-subnets" { + count = var.num_webapps compartment_id = var.compartment_ocid - vcn_id = oci_core_vcn.kasm_vcn.id - route_table_id = oci_core_vcn.kasm_vcn.default_route_table_id - dhcp_options_id = oci_core_vcn.kasm_vcn.default_dhcp_options_id + vcn_id = data.oci_core_vcn.data-kasm_vcn.id + route_table_id = oci_core_route_table.default_route_table.id + dhcp_options_id = data.oci_core_vcn.data-kasm_vcn.default_dhcp_options_id + availability_domain = data.oci_identity_availability_domains.kasm_ads.availability_domains[count.index].name + cidr_block = cidrsubnet(var.vcn_subnet_cidr, local.kasm_server_subnet_cidr_size, (count.index + 1)) + display_name = "${var.project_name}-webapp-subnet${count.index}" + dns_label = "${var.project_name}webapp${count.index}" + security_list_ids = [ + data.oci_core_security_lists.data-allow_web.security_lists[0].id, + data.oci_core_security_lists.data-allow_ssh.security_lists[0].id + ] } +data "oci_core_subnets" "data-kasm_webapp_subnets" { + count = var.num_webapps + compartment_id = var.compartment_ocid + vcn_id = data.oci_core_vcn.data-kasm_vcn.id + display_name = oci_core_subnet.kasm-webapp-subnets[count.index].display_name +} +## Will create Agent subnet x.x.3.x/24 (assuming a VPC Subnet CIDR between x.x.0.0/16 and x.x.0.0/21) resource "oci_core_subnet" "kasm-agent-subnet" { - availability_domain = data.oci_identity_availability_domain.ad.name - cidr_block = "10.0.30.0/24" - display_name = "${var.project_name}-kasm-agent-subnet" - dns_label = "${var.project_name}agent" - security_list_ids = [oci_core_security_list.allow_web_from_webapp.id, oci_core_security_list.allow_ssh.id] compartment_id = var.compartment_ocid - vcn_id = oci_core_vcn.kasm_vcn.id - route_table_id = oci_core_vcn.kasm_vcn.default_route_table_id - dhcp_options_id = oci_core_vcn.kasm_vcn.default_dhcp_options_id -} \ No newline at end of file + vcn_id = data.oci_core_vcn.data-kasm_vcn.id + route_table_id = oci_core_route_table.default_route_table.id + dhcp_options_id = data.oci_core_vcn.data-kasm_vcn.default_dhcp_options_id + availability_domain = data.oci_identity_availability_domains.kasm_ads.availability_domains[0].name + cidr_block = cidrsubnet(var.vcn_subnet_cidr, local.kasm_server_subnet_cidr_size, local.kasm_agent_subnet_id) + display_name = "${var.project_name}-agent-subnet" + dns_label = "${var.project_name}agent" + security_list_ids = [ + data.oci_core_security_lists.data-allow_web_from_webapp.security_lists[0].id, + data.oci_core_security_lists.data-allow_ssh.security_lists[0].id + ] +} + +data "oci_core_subnet" "data-kasm_agent_subnet" { + subnet_id = oci_core_subnet.kasm-agent-subnet.id +} + +## Will create Guac subnet x.x.4.x/24 (assuming a VPC Subnet CIDR between x.x.0.0/16 and x.x.0.0/21) +resource "oci_core_subnet" "kasm-guac-subnet" { + compartment_id = var.compartment_ocid + vcn_id = data.oci_core_vcn.data-kasm_vcn.id + route_table_id = oci_core_route_table.default_route_table.id + dhcp_options_id = data.oci_core_vcn.data-kasm_vcn.default_dhcp_options_id + availability_domain = data.oci_identity_availability_domains.kasm_ads.availability_domains[0].name + cidr_block = cidrsubnet(var.vcn_subnet_cidr, local.kasm_server_subnet_cidr_size, (local.kasm_agent_subnet_id + 1)) + display_name = "${var.project_name}-guac-subnet" + dns_label = "${var.project_name}guac" + security_list_ids = [ + data.oci_core_security_lists.data-allow_web_from_webapp.security_lists[0].id, + data.oci_core_security_lists.data-allow_ssh.security_lists[0].id + ] +} + +data "oci_core_subnet" "data-kasm_guac_subnet" { + subnet_id = oci_core_subnet.kasm-guac-subnet.id +} diff --git a/oci/standard/module/userdata/agent_bootstrap.sh b/oci/standard/module/userdata/agent_bootstrap.sh index 58ebf1b..ca26186 100644 --- a/oci/standard/module/userdata/agent_bootstrap.sh +++ b/oci/standard/module/userdata/agent_bootstrap.sh @@ -11,11 +11,19 @@ echo '/var/swap.1 swap swap defaults 0 0' | tee -a /etc/fstab cd /tmp -PRIVATE_IP=(`hostname -I | cut -d ' ' -f1 | tr -d '\\n'`) +PRIVATE_IP=(`hostname -I | cut -d' ' -f1 | tr -d '\\n'`) wget ${kasm_build_url} -O kasm_workspaces.tar.gz tar -xf kasm_workspaces.tar.gz + +echo "Waiting for Kasm WebApp availability..." +while ! (curl -k https://${manager_address}/api/__healthcheck 2>/dev/null | grep -q true) +do + echo "Waiting for API server..." + sleep 5 +done +echo "WebApp is alive" + bash kasm_release/install.sh -S agent -e -p $PRIVATE_IP -m ${manager_address} -M ${manager_token} echo "Done" - diff --git a/oci/standard/module/userdata/db_bootstrap.sh b/oci/standard/module/userdata/db_bootstrap.sh index 76b1efb..5317314 100644 --- a/oci/standard/module/userdata/db_bootstrap.sh +++ b/oci/standard/module/userdata/db_bootstrap.sh @@ -15,7 +15,6 @@ PRIVATE_IP=(`hostname -I | cut -d ' ' -f1 | tr -d '\\n'`) wget ${kasm_build_url} -O kasm_workspaces.tar.gz tar -xf kasm_workspaces.tar.gz -bash kasm_release/install.sh -S db -e -Q ${database_password} -R ${redis_password} -U ${user_password} -P ${admin_password} -M ${manager_token} +bash kasm_release/install.sh -S db -e -Q ${database_password} -R ${redis_password} -U ${user_password} -P ${admin_password} -M ${manager_token} -k ${service_registration_token} echo "Done" - diff --git a/oci/standard/module/userdata/guac_bootstrap.sh b/oci/standard/module/userdata/guac_bootstrap.sh new file mode 100644 index 0000000..484d063 --- /dev/null +++ b/oci/standard/module/userdata/guac_bootstrap.sh @@ -0,0 +1,29 @@ +#!/bin/bash +set -ex +echo "Starting Kasm Workspaces Agent Install" + +/bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=${swap_size} +/sbin/mkswap /var/swap.1 +chmod 600 /var/swap.1 +/sbin/swapon /var/swap.1 + +echo '/var/swap.1 swap swap defaults 0 0' | tee -a /etc/fstab + +cd /tmp + +PRIVATE_IP=(`hostname -I | cut -d ' ' -f1 | tr -d '\\n'`) + +wget ${kasm_build_url} -O kasm_workspaces.tar.gz +tar -xf kasm_workspaces.tar.gz + +echo "Waiting for Kasm WebApp availability..." +while ! (curl -k https://${manager_address}/api/__healthcheck 2>/dev/null | grep -q true) +do + echo "Waiting for API server..." + sleep 5 +done +echo "WebApp is alive" + +bash kasm_release/install.sh -S guac -e -p $PRIVATE_IP -n ${manager_address} -k ${service_registration_token} + +echo "Done" diff --git a/oci/standard/module/userdata/webapp_bootstrap.sh b/oci/standard/module/userdata/webapp_bootstrap.sh index dfd0b23..5f781f5 100644 --- a/oci/standard/module/userdata/webapp_bootstrap.sh +++ b/oci/standard/module/userdata/webapp_bootstrap.sh @@ -16,15 +16,21 @@ PRIVATE_IP=(`hostname -I | cut -d ' ' -f1 | tr -d '\\n'`) wget ${kasm_build_url} -O kasm_workspaces.tar.gz tar -xf kasm_workspaces.tar.gz -echo "Checking for Kasm DB..." +echo "Checking for Kasm DB and Redis..." apt-get update && apt-get install -y netcat while ! nc -w 1 -z ${db_ip} 5432; do - echo "Not Ready..." + echo "Database not ready..." sleep 5 done echo "DB is alive" +while ! nc -w 1 -z ${db_ip} 6379; do + echo "Redis not ready..." + sleep 5 +done +echo "Redis is alive" + + bash kasm_release/install.sh -S app -e -z ${zone_name} -q "${db_ip}" -Q ${database_password} -R ${redis_password} echo "Done" - diff --git a/oci/standard/module/variables.tf b/oci/standard/module/variables.tf index f621f6a..f0d19ad 100644 --- a/oci/standard/module/variables.tf +++ b/oci/standard/module/variables.tf @@ -1,156 +1,183 @@ -variable "project_name" { - description = "The name of the deployment (e.g dev, staging). A short single word" -} - -variable "oci_domain_name" { - description = "The public Zone used for the dns entries. This must already exist in the OCI account. (e.g kasm.contoso.com). The deployment will be accessed via this zone name via https" -} - -variable kasm_build_url { - description = "The URL for the Kasm Workspaces build" -} - - -variable swap_size { - description = "The amount of swap (in MB) to configure inside the compute instances" - default = 2048 -} - - variable "tenancy_ocid" { description = "The Tenancy OCID." -} - -variable "user_ocid" { - description = "The User OCID." + type = string } variable "compartment_ocid" { description = "The Compartment OCID" + type = string } variable "region" { description = "The OCI Region eg: (us-ashburn-1)" + type = string +} + +variable "user_ocid" { + description = "The User OCID." + type = string } variable "fingerprint" { description = "API Key Fingerprint" + type = string } variable "private_key_path" { description = "The path to the API Key PEM encoded Private Key" + type = string + sensitive = true } -variable "ssh_authorized_keys" { - description = "The file path to the authorized_keys file that contains SSH public keys to be installed on the OCI compute instance" +variable "project_name" { + description = "The name of the deployment (e.g dev, staging). A short single word" + type = string } -variable "instance_image_ocid" { - description = "The OCID for the instance image , such as ubuntu 18.04, to use." - default = "ocid1.image.oc1.iad.aaaaaaaafg6lg7dejwjebjqontwzyvutgf6qs5awyze6fgoiqepyj5qkvcuq" +variable "oci_domain_name" { + description = "The public Zone used for the dns entries. This must already exist in the OCI account. (e.g kasm.contoso.com). The deployment will be accessed via this zone name via https" + type = string } - -variable "allow_ssh_cidr" { - description = "The CIDR notation to allow SSH access to the systems." - default = "0.0.0.0/0" +variable "letsencrypt_cert_support_email" { + description = "Email address to use for Let's Encrypt SSL certificates for OCI Deployment" + type = string } - -variable "allow_web_cidr" { - description = "The CIDR notation to allow HTTPS access to the systems." - default = "0.0.0.0/0" +variable "letsencrypt_server_type" { + description = "SSL Server type to generate. Valid options are staging and prod, and prod certificates are limited to 5 certificates per week." + type = string } variable "kasm_ssl_crt_path" { description = "The file path to the PEM encoded SSL Certificate" + type = string } variable "kasm_ssl_key_path" { description = "The file path to the PEM encoded SSL Certificate Key" + type = string + sensitive = true } - -variable "instance_shape" { - description = "The instance shape to use. Should be a Flex type." - default = "VM.Standard.E3.Flex" +variable "vcn_subnet_cidr" { + description = "VCN Subnet CIDR where you wish to deploy Kasm" + type = string } -variable "db_boot_size_gb" { - description = "The size, in GB, of the DB instance drive" - default = 50 +variable "ssh_authorized_keys" { + description = "The SSH Public Keys to be installed on the OCI compute instance" + type = string } -variable "webapp_boot_size_gb" { - description = "The size, in GB, of the Webapp instance drives" - default = 50 +variable "instance_image_ocid" { + description = "The OCID for the instance image , such as ubuntu 20.04, to use." + type = string } -variable "agent_boot_size_gb" { - description = "The size, in GB, of the Agemt instance drives" - default = 60 +variable "allow_ssh_cidrs" { + description = "The CIDR notation to allow SSH access to the systems." + type = list(string) } +variable "allow_web_cidrs" { + description = "The CIDR notation to allow HTTPS access to the systems." + type = list(string) +} variable "num_agents" { - default = "2" description = "The number of Agent Role Servers to create in the deployment" + type = number } - variable "num_webapps" { - default = "2" description = "The number of WebApp role servers to create in the deployment" + type = number } - -variable "agent_ocpus" { - description = "The number of CPUs to configure for the Agent instances" - default = 2 +variable "num_guac_rdp_nodes" { + description = "The number of WebApp role servers to create in the deployment" + type = number } -variable "db_ocpus" { - description = "The number of CPUs to configure for the DB instance" - default = 1 +variable "database_password" { + description = "The password for the database. No special characters" + type = string + sensitive = true } -variable "webapp_ocpus" { - description = "The number of CPUs to configure for the Webapp instances" - default = 1 +variable "redis_password" { + description = "The password for the Redis server. No special characters" + type = string + sensitive = true } -variable "agent_memory_in_gb" { - description = "The amount of memory, in GB, to configure for the Agent instances" - default = 4 +variable "user_password" { + description = "The standard (non administrator) user password. No special characters" + type = string + sensitive = true } -variable "webapp_memory_in_gb" { - description = "The amount of memory, in GB, to configure for the Webapp instances" - default = 2 -} - -variable "db_memory_in_gb" { - description = "The amount of memory, in GB, to configure for the DB instance" - default = 2 +variable "admin_password" { + description = "The administrative user password. No special characters" + type = string + sensitive = true } variable "manager_token" { - description = "The password for the database. No special characters" + description = "The manager token value for Agents to authenticate to webapps. No special characters" + type = string + sensitive = true } -variable "database_password" { - description = "The password for the database. No special characters" + +variable "service_registration_token" { + description = "The service registration token value for Guac RDP servers to authenticate to webapps. No special characters" + type = string + sensitive = true } -variable "redis_password" { - description = "The password for the database. No special characters" + +variable "kasm_build_url" { + description = "The URL for the Kasm Workspaces build" + type = string } -variable "user_password" { - description = "The password for the database. No special characters" + +variable "swap_size" { + description = "The amount of swap (in MB) to configure inside the compute instances" + type = number } -variable "admin_password" { - description = "The password for the database. No special characters" + +variable "instance_shape" { + description = "The instance shape to use. Should be a Flex type." + type = string } -variable "webapp_cidr_1" { - default = "10.0.20.0/24" + +variable "kasm_webapp_vm_settings" { + description = "The amount of memory, in GB, to configure for the Kasm WebApp instance" + type = map(any) +} + +variable "kasm_database_vm_settings" { + description = "The amount of memory, in GB, to configure for the Kasm DB instance" + type = map(any) +} + +variable "kasm_agent_vm_settings" { + description = "The amount of memory, in GB, to configure for the Kasm Agent instance" + type = map(any) +} + +variable "kasm_guac_vm_settings" { + description = "The number of CPUs, amount of memory in GB, and HDD size in GB to configure for the Kasm Guac RDP instance" + type = map(any) +} + +## Pre-set values +variable "anywhere" { + description = "Anywhere route subnet" + type = list(string) + default = ["0.0.0.0/0"] + + validation { + condition = can([for subnet in var.anywhere : cidrhost(subnet, 0)]) + error_message = "Anywhere variable must be valid IPv4 CIDR - usually 0.0.0.0/0 for all default routes and default Security Group access." + } } -variable "webapp_cidr_2" { - default = "10.0.25.0/24" -} \ No newline at end of file diff --git a/oci/standard/module/vcn.tf b/oci/standard/module/vcn.tf index 23a7605..de2acb8 100644 --- a/oci/standard/module/vcn.tf +++ b/oci/standard/module/vcn.tf @@ -1,4 +1,3 @@ - resource "oci_core_vcn" "kasm_vcn" { cidr_block = "10.0.0.0/16" compartment_id = var.compartment_ocid @@ -6,7 +5,9 @@ resource "oci_core_vcn" "kasm_vcn" { dns_label = "${var.project_name}vcn" } - +data "oci_core_vcn" "data-kasm_vcn" { + vcn_id = oci_core_vcn.kasm_vcn.id +} resource "oci_core_internet_gateway" "kasm_internet_gateway" { compartment_id = var.compartment_ocid @@ -14,25 +15,29 @@ resource "oci_core_internet_gateway" "kasm_internet_gateway" { vcn_id = oci_core_vcn.kasm_vcn.id } -resource "oci_core_default_route_table" "default_route_table" { - manage_default_resource_id = oci_core_vcn.kasm_vcn.default_route_table_id - display_name = "DefaultRouteTable" +data "oci_core_internet_gateways" "data-kasm_internet_gateway" { + compartment_id = var.compartment_ocid + vcn_id = data.oci_core_vcn.data-kasm_vcn.id +} + +resource "oci_core_route_table" "default_route_table" { + compartment_id = var.compartment_ocid + vcn_id = data.oci_core_vcn.data-kasm_vcn.id + display_name = "KasmRouteTable" route_rules { - destination = "0.0.0.0/0" + destination = var.anywhere[0] destination_type = "CIDR_BLOCK" - network_entity_id = oci_core_internet_gateway.kasm_internet_gateway.id + network_entity_id = oci_core_internet_gateway.kasm_internet_gateway.id #data.oci_core_internet_gateways.data-kasm_internet_gateway.gateways[0].id } } +# data "oci_core_route_tables" "data-default_route_table" { +# compartment_id = var.compartment_ocid +# vcn_id = data.oci_core_vcn.data-kasm_vcn.id +# display_name = oci_core_route_table.default_route_table.display_name +# } - -data "oci_identity_availability_domain" "ad" { +data "oci_identity_availability_domains" "kasm_ads" { compartment_id = var.tenancy_ocid - ad_number = 1 -} - -data "oci_identity_availability_domain" "ad2" { - compartment_id = var.tenancy_ocid - ad_number = 2 } diff --git a/oci/standard/module/webapp.tf b/oci/standard/module/webapp.tf index e227c31..380a120 100644 --- a/oci/standard/module/webapp.tf +++ b/oci/standard/module/webapp.tf @@ -1,29 +1,17 @@ -data "template_file" "webapp_user_data" { - template = "${file("${path.module}/userdata/webapp_bootstrap.sh")}" - vars = { - kasm_build_url = var.kasm_build_url - db_ip = oci_core_instance.kasm_db_instance.private_ip - database_password = var.database_password - redis_password = var.redis_password - swap_size = var.swap_size - zone_name = "default" - } -} - resource "oci_core_instance" "kasm_webapp_instance" { count = var.num_webapps - availability_domain = data.oci_identity_availability_domain.ad.name + availability_domain = data.oci_identity_availability_domains.kasm_ads.availability_domains[count.index].name compartment_id = var.compartment_ocid display_name = "${var.project_name}-Kasm-Webapp-${count.index}" shape = var.instance_shape shape_config { - ocpus = var.webapp_ocpus - memory_in_gbs = var.webapp_memory_in_gb + ocpus = var.kasm_webapp_vm_settings.cpus + memory_in_gbs = var.kasm_webapp_vm_settings.memory } create_vnic_details { - subnet_id = oci_core_subnet.kasm-webapp-subnet.id + subnet_id = data.oci_core_subnets.data-kasm_webapp_subnets[count.index].subnets[0].id display_name = "${var.project_name}-Primaryvnic" assign_public_ip = true assign_private_dns_record = true @@ -31,18 +19,28 @@ resource "oci_core_instance" "kasm_webapp_instance" { } source_details { - source_type = "image" - source_id = var.instance_image_ocid - boot_volume_size_in_gbs = var.webapp_boot_size_gb + source_type = "image" + source_id = var.instance_image_ocid + boot_volume_size_in_gbs = var.kasm_webapp_vm_settings.hdd_size_gb } - metadata = { - ssh_authorized_keys = file("${var.ssh_authorized_keys}") - user_data = base64encode("${data.template_file.webapp_user_data.rendered}") + ssh_authorized_keys = var.ssh_authorized_keys + user_data = base64encode(templatefile("${path.module}/userdata/webapp_bootstrap.sh", + { + kasm_build_url = var.kasm_build_url + db_ip = data.oci_core_instance.data-kasm_db_instance.private_ip + database_password = var.database_password + redis_password = var.redis_password + swap_size = var.swap_size + zone_name = "default" + } + )) } } - - +data "oci_core_instance" "data-kasm_webapp_instances" { + count = var.num_webapps + instance_id = oci_core_instance.kasm_webapp_instance[count.index].id +} diff --git a/oci/standard/provider.tf b/oci/standard/provider.tf new file mode 100644 index 0000000..e65d81e --- /dev/null +++ b/oci/standard/provider.tf @@ -0,0 +1,28 @@ +terraform { + required_providers { + oci = { + source = "oracle/oci" + version = ">= 4.0.0" + } + acme = { + source = "vancluever/acme" + version = ">= 2.0" + } + tls = { + source = "hashicorp/tls" + version = ">= 4.0.0" + } + } +} + +provider "oci" { + tenancy_ocid = var.tenancy_ocid + user_ocid = var.user_ocid + fingerprint = var.fingerprint + private_key_path = var.private_key_path + region = var.region +} + +provider "acme" { + server_url = local.letsencrypt_server_url +} diff --git a/oci/standard/settings.tfvars b/oci/standard/settings.tfvars new file mode 100644 index 0000000..b8dc804 --- /dev/null +++ b/oci/standard/settings.tfvars @@ -0,0 +1,69 @@ +## Kasm deployment settings +oci_domain_name = "kasm.contoso.com" +project_name = "contoso" +kasm_build_url = "https://kasm-static-content.s3.amazonaws.com/kasm_release_1.12.0.d4fd8a.tar.gz" +vcn_subnet_cidr = "10.0.0.0/16" + +## OCI Authentication variables +tenancy_ocid = "" +user_ocid = "" +compartment_ocid = "" +fingerprint = "" +region = "us-ashburn-1" +private_key_path = "./oci-private-key.pem" + +## Load Balancer SSL Keys +# Terraform auto-generated Let's Encrypt keys +letsencrypt_cert_support_email = "" +letsencrypt_server_type = "" + +# Bring your own - Load Balancer SSL Keys +kasm_ssl_crt_path = "" +kasm_ssl_key_path = "" + +## VM Access subnets +allow_ssh_cidrs = ["0.0.0.0/0"] +allow_web_cidrs = ["0.0.0.0/0"] + +## Kasm passwords +manager_token = "changeme" +admin_password = "changeme" +user_password = "changeme" +redis_password = "changeme" +database_password = "changeme" +service_registration_token = "changeme" + +## SSH Public Keys +ssh_authorized_keys = "changeme" + +## OCI VM Settings +instance_image_ocid = "ocid1.image.oc1.iad.aaaaaaaahiz6xym3a76xhwkmwmhrz6luyiehho7dpxpkphxhsq5q6z4m3nlq" +instance_shape = "VM.Standard.E4.Flex" +swap_size = 2048 +num_webapps = 2 +num_agents = 2 +num_guac_rdp_nodes = 1 + +kasm_webapp_vm_settings = { + cpus = 2 + memory = 2 + hdd_size_gb = 50 +} + +kasm_database_vm_settings = { + cpus = 2 + memory = 2 + hdd_size_gb = 50 +} + +kasm_agent_vm_settings = { + cpus = 4 + memory = 8 + hdd_size_gb = 120 +} + +kasm_guac_vm_settings = { + cpus = 4 + memory = 4 + hdd_size_gb = 50 +} \ No newline at end of file diff --git a/oci/standard/variables.tf b/oci/standard/variables.tf new file mode 100644 index 0000000..59f7e2d --- /dev/null +++ b/oci/standard/variables.tf @@ -0,0 +1,399 @@ +variable "tenancy_ocid" { + description = "The Tenancy OCID." + type = string + + validation { + condition = can(regex("^(ocid\\d)\\.(compartment|tenancy)\\.(oc\\d)[.]{1,}[a-z0-9]{60}", var.tenancy_ocid)) + error_message = "The tenancy_ocid must be a valid Oracle Cloud Tenancy OCID value (e.g. ocid1.tenancy.oc1..aaaaaaaaba3pv6wkcr4jqae5f44n2b2m2yt2j6rx32uzr4h25vqstifsfdsq)." + } +} + +variable "user_ocid" { + description = "The User OCID." + type = string + + validation { + condition = can(regex("^(ocid\\d)\\.(user)\\.(oc\\d)[.]{1,}[a-z0-9]+", var.user_ocid)) + error_message = "The variable user_ocid must be a valid Oracle Cloud User OCID." + } +} + +variable "compartment_ocid" { + description = "The Compartment OCID" + type = string + + validation { + condition = can(regex("^(ocid\\d)\\.(compartment|tenancy)\\.(oc\\d)[.]+[a-z0-9]{60}", var.compartment_ocid)) + error_message = "The compartment_ocid must be a valid Oracle Cloud Compartment OCID value (e.g. ocid1.compartment.oc1..aaaaaaaaba3pv6wkcr4jqae5f44n2b2m2yt2j6rx32uzr4h25vqstifsfdsq)." + } +} + +variable "region" { + description = "The OCI Region eg: (us-ashburn-1)" + type = string + + validation { + condition = can(regex("^([a-z]{2}-[a-z]{5,}-[\\d]{1})$", var.region)) + error_message = "The provider-oci_deployment_region must be a valid Oracle Cloud (OCI) Region name, e.g. us-ashburn-1" + } +} + +variable "fingerprint" { + description = "API Key Fingerprint" + type = string + + validation { + condition = can(regex("^([a-f0-9]{2}:?){16}$", var.fingerprint)) + error_message = "The API fingerprint is incorrectly formatted. It should be 16 colon-delimited hex bytes (e.g. 12:34:56:78:90:ab:cd:ef:12:34:56:78:90:ab:cd:ef)." + } +} + +variable "private_key_path" { + description = "The path to the API Key PEM encoded Private Key" + type = string + sensitive = true + + validation { + condition = can(fileexists(var.private_key_path)) + error_message = "The variable private_key_path must point to a valid OCI API Key file." + } + + validation { + condition = !can(regex("replaceme", file(var.private_key_path))) + error_message = "You must enter a valid OCI API Private key in the file located at the private_key_path." + } +} +variable "project_name" { + description = "The name of the deployment (e.g dev, staging). A short single word" + type = string + + validation { + condition = can(regex("^[a-z]{1,15}", var.project_name)) + error_message = "The project_name variable can only be one word between 1 and 15 lower-case letters since it is a seed value in multiple object names." + } +} + +variable "oci_domain_name" { + description = "The public Zone used for the dns entries. This must already exist in the OCI account. (e.g kasm.contoso.com). The deployment will be accessed via this zone name via https" + type = string + + validation { + condition = can(regex("^[a-z0-9]+([\\-\\.]{1}[a-z0-9]+)*\\.[a-z]{2,6}", var.oci_domain_name)) + error_message = "There are invalid characters in the oci_domain_name - it must be a valid domain name." + } +} + +variable "vcn_subnet_cidr" { + description = "VCN Subnet CIDR where you wish to deploy Kasm" + type = string + + validation { + condition = can(cidrhost(var.vcn_subnet_cidr, 0)) + error_message = "The vcn_subnet_cidr must be a valid IPv4 Subnet in CIDR notation (e.g. 10.0.0.0/24)." + } +} + +variable "ssh_authorized_keys" { + description = "The SSH Public Keys to be installed on the OCI compute instance" + type = string + + validation { + condition = can(regex("^ssh-rsa\\s+[A-Za-z0-9+/]+[=]{0,3}(\\s+.+)?\\s*$", var.ssh_authorized_keys)) + error_message = "The ssh_authorized_keys value is not in the correct format." + } +} + +variable "instance_image_ocid" { + description = "The OCID for the instance image , such as ubuntu 20.04, to use." + default = "ocid1.image.oc1.iad.aaaaaaaafg6lg7dejwjebjqontwzyvutgf6qs5awyze6fgoiqepyj5qkvcuq" + + validation { + condition = can(regex("^(ocid\\d)\\.(image)\\.(oc\\d)\\.[a-z]{3,}\\.[a-z0-9]{60}", var.instance_image_ocid)) + error_message = "The compartment_ocid must be a valid Oracle Cloud Compartment OCID value (e.g. ocid1.image.oc1.iad.aaaaaaaafg6lg7dejwjebjqontwzyvutgf6qs5awyze6fgoiqepyj5qkvcuq)." + } +} + +variable "allow_ssh_cidrs" { + description = "The CIDR notation to allow SSH access to the systems." + type = list(string) + + validation { + condition = can([for subnet in var.allow_ssh_cidrs : cidrhost(subnet, 0)]) + error_message = "One of the subnets provided in the allow_ssh_cidrs list is invalid." + } +} + +variable "allow_web_cidrs" { + description = "The CIDR notation to allow HTTPS access to the systems." + type = list(string) + + validation { + condition = can([for subnet in var.allow_web_cidrs : cidrhost(subnet, 0)]) + error_message = "One of the subnets provided in the allow_web_cidrs list is invalid." + } +} + +variable "letsencrypt_cert_support_email" { + description = "Email address to use for Let's Encrypt SSL certificates for OCI Deployment" + type = string + default = "" + + validation { + condition = can(var.letsencrypt_cert_support_email == "" ? true : can(regex("^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$", var.letsencrypt_cert_support_email))) + error_message = "The ssl_cert_support_email must be a valid email address format." + } +} + +variable "letsencrypt_server_type" { + description = "SSL Server type to generate. Valid options are staging and prod, and prod certificates are limited to 5 certificates per week." + type = string + default = "" + + validation { + condition = can(contains(["staging", "prod", ""], var.letsencrypt_server_type)) + error_message = "Allowed values for the letsencrypt_server_type variable are: staging, prod. For reference: Staging generates certificates that a browser will not trust, but are formatted correctly to apply to resources; while Prod generates valid, useable, trusted certificates. NOTE: Prod certificate generation is limited to 5 times per week, so if you are testing Kasm or intend to possibly re-deploy multiple times, it is recommended to use Staging (which has a much higher generation limit since it is intended for testing) until you are ready to deploy your 'final' version." + } +} + +variable "kasm_ssl_crt_path" { + description = "The file path to the PEM encoded SSL Certificate" + type = string + default = "" + + validation { + condition = can(var.kasm_ssl_crt_path == "" ? true : can(fileexists(var.kasm_ssl_crt_path))) + error_message = "The variable kasm_ssl_crt_path must point to a valid OCI API Key file." + } + + validation { + condition = can(var.kasm_ssl_crt_path == "" ? true : !can(regex("replaceme", file(var.kasm_ssl_crt_path)))) + error_message = "You must enter a valid SSL Cert in the file located at the kasm_ssl_crt_path." + } +} + +variable "kasm_ssl_key_path" { + description = "The file path to the PEM encoded SSL Certificate Key" + type = string + sensitive = true + default = "" + + validation { + condition = can(var.kasm_ssl_key_path == "" ? true : can(fileexists(var.kasm_ssl_key_path))) + error_message = "The variable kasm_ssl_key_path must point to a valid OCI API Key file." + } + + validation { + condition = can(var.kasm_ssl_key_path == "" ? true : !can(regex("replaceme", file(var.kasm_ssl_key_path)))) + error_message = "You must enter a valid SSL Cert in the file located at the kasm_ssl_key_path." + } +} + +variable "database_password" { + description = "The password for the database. No special characters" + type = string + sensitive = true + + validation { + condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.database_password)) + error_message = "The Database Password should be a string between 12 and 30 letters or numbers with no special characters." + } +} + +variable "redis_password" { + description = "The password for the Redis server. No special characters" + type = string + sensitive = true + + validation { + condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.redis_password)) + error_message = "The Redis Password should be a string between 12 and 30 letters or numbers with no special characters." + } +} + +variable "user_password" { + description = "The standard (non administrator) user password. No special characters" + type = string + sensitive = true + + validation { + condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.user_password)) + error_message = "The User Password should be a string between 12 and 30 letters or numbers with no special characters." + } +} + +variable "admin_password" { + description = "The administrative user password. No special characters" + type = string + sensitive = true + + validation { + condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.admin_password)) + error_message = "The Admin password should be a string between 12 and 30 letters or numbers with no special characters." + } +} + +variable "manager_token" { + description = "The manager token value for Agents to authenticate to webapps. No special characters" + type = string + sensitive = true + + validation { + condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.manager_token)) + error_message = "The Manager Token should be a string between 12 and 30 letters or numbers with no special characters." + } +} + +variable "service_registration_token" { + description = "The service registration token value for Guac RDP servers to authenticate to webapps. No special characters" + type = string + sensitive = true + + validation { + condition = can(regex("^[a-zA-Z0-9]{12,30}$", var.service_registration_token)) + error_message = "The Service Registration Token should be a string between 12 and 30 letters or numbers with no special characters." + } +} + +variable "num_agents" { + description = "The number of Agent Role Servers to create in the deployment" + type = number + + validation { + condition = var.num_agents >= 0 && var.num_agents <= 100 && floor(var.num_agents) == var.num_agents + error_message = "Acceptable number of Kasm Agents range between 0-100." + } +} + +variable "num_guac_rdp_nodes" { + description = "The number of Guac RDP Role Servers to create in the deployment" + type = number + + validation { + condition = var.num_guac_rdp_nodes >= 0 && var.num_guac_rdp_nodes <= 100 && floor(var.num_guac_rdp_nodes) == var.num_guac_rdp_nodes + error_message = "Acceptable number of Kasm Guac RDP nodes range between 0-100." + } +} + +variable "num_webapps" { + description = "The number of WebApp role servers to create in the deployment" + type = number + + validation { + condition = var.num_webapps >= 1 && var.num_webapps <= 3 && floor(var.num_webapps) == var.num_webapps + error_message = "Acceptable number of Kasm Agents range between 1-3." + } +} + +variable "swap_size" { + description = "The amount of swap (in MB) to configure inside the compute instances" + type = number + + validation { + condition = var.swap_size >= 1024 && var.swap_size <= 8192 && floor(var.swap_size) == var.swap_size + error_message = "Swap size is the amount of disk space to use for Kasm in MB and must be an integer between 1024 and 8192." + } +} + +variable "kasm_webapp_vm_settings" { + description = "The number of CPUs, amount of memory in GB, and HDD size in GB to configure for the Kasm WebApp instances" + type = object({ + cpus = number + memory = number + hdd_size_gb = number + }) + + validation { + condition = can(var.kasm_webapp_vm_settings.cpus >= 2) + error_message = "Kasm Webapps should have at least 2 CPUs to ensure enough resources for Kasm services." + } + validation { + condition = can(var.kasm_webapp_vm_settings.memory >= 2) + error_message = "Kasm Webapps should have at least 2 GB Memory to ensure enough resources for Kasm services." + } + validation { + condition = can(var.kasm_webapp_vm_settings.hdd_size_gb >= 50) + error_message = "Kasm Webapps should have at least a 50 GB HDD to meet OCI minimum requirements, and ensure enough space Kasm services." + } +} + +variable "kasm_database_vm_settings" { + description = "The number of CPUs, amount of memory in GB, and HDD size in GB to configure for the Kasm Database instance" + type = object({ + cpus = number + memory = number + hdd_size_gb = number + }) + + validation { + condition = can(var.kasm_database_vm_settings.cpus >= 2) + error_message = "Kasm Webapps should have at least 2 CPUs to ensure enough resources for Kasm services." + } + validation { + condition = can(var.kasm_database_vm_settings.memory >= 2) + error_message = "Kasm Webapps should have at least 2 GB Memory to ensure enough resources for Kasm services." + } + validation { + condition = can(var.kasm_database_vm_settings.hdd_size_gb >= 50) + error_message = "Kasm Webapps should have at least a 50 GB HDD to meet OCI minimum requirements, and ensure enough space Kasm services." + } +} + +variable "kasm_agent_vm_settings" { + description = "The number of CPUs, amount of memory in GB, and HDD size in GB to configure for the Kasm Agent instances" + type = object({ + cpus = number + memory = number + hdd_size_gb = number + }) + + validation { + condition = can(var.kasm_agent_vm_settings.cpus >= 2) + error_message = "Kasm Agents should have at least 2 CPUs to ensure enough resources for Kasm services. More CPU is definitely better for the Kasm Agent as it is the VM that runs your Kasm workspaces." + } + validation { + condition = can(var.kasm_agent_vm_settings.memory >= 2) + error_message = "Kasm Agents should have at least 4 GB Memory to ensure enough resources for Kasm services. More Memory is definitely better for the Kasm Agent as it is the VM that runs your Kasm workspaces." + } + validation { + condition = can(var.kasm_agent_vm_settings.hdd_size_gb >= 120) + error_message = "Kasm Agents should have at least a 120 GB HDD to meet OCI minimum requirements, and ensure enough space to pull the default Kasm workspace images." + } +} + +variable "kasm_guac_vm_settings" { + description = "The number of CPUs, amount of memory in GB, and HDD size in GB to configure for the Kasm Guac RDP instances" + type = object({ + cpus = number + memory = number + hdd_size_gb = number + }) + + validation { + condition = can(var.kasm_guac_vm_settings.cpus >= 4) + error_message = "Kasm Guac RDP servers should have at least 4 CPUs to ensure enough resources for Kasm services." + } + validation { + condition = can(var.kasm_guac_vm_settings.memory >= 4) + error_message = "Kasm Guac RDP servers should have at least 4 GB Memory to ensure enough resources for Kasm services." + } + validation { + condition = can(var.kasm_guac_vm_settings.hdd_size_gb >= 50) + error_message = "Kasm Guac RDP servers should have at least a 50 GB HDD to meet OCI minimum requirements, and ensure enough space Kasm services." + } +} + +## Non-validated variables +variable "kasm_build_url" { + description = "The URL for the Kasm Workspaces build" + type = string +} + +variable "instance_shape" { + description = "The instance shape to use. Should be a Flex type." + type = string +} + +## Local for Let's Encrypt staging/prod URL selection +locals { + letsencrypt_server_url = var.letsencrypt_server_type == "prod" ? "https://acme-v02.api.letsencrypt.org/directory" : "https://acme-staging-v02.api.letsencrypt.org/directory" +}