From 0525c298e5621562bb4b1ee5b3ff897074fb3aef Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Mon, 25 Jul 2022 13:09:20 -0600 Subject: [PATCH 01/76] network bicep wip --- 035-HubAndSpoke/README.md | 2 +- 035-HubAndSpoke/Student/00-Prereqs.md | 6 +- .../Resources/bicep/00-resourceGroups.bicep | 23 ++ .../Student/Resources/bicep/01-hub.bicep | 215 ++++++++++++++++++ .../Student/Resources/bicep/01-spoke1.bicep | 142 ++++++++++++ .../Student/Resources/bicep/01-spoke2.bicep | 140 ++++++++++++ .../Resources/bicep/01-vnetpeeringhub.bicep | 40 ++++ .../bicep/01-vnetpeeringspoke1.bicep | 27 +++ .../bicep/01-vnetpeeringspoke2.bicep | 27 +++ 035-HubAndSpoke/Student/Resources/csr.md | 35 ++- 10 files changed, 651 insertions(+), 6 deletions(-) create mode 100644 035-HubAndSpoke/Student/Resources/bicep/00-resourceGroups.bicep create mode 100644 035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep create mode 100644 035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep create mode 100644 035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep create mode 100644 035-HubAndSpoke/Student/Resources/bicep/01-vnetpeeringhub.bicep create mode 100644 035-HubAndSpoke/Student/Resources/bicep/01-vnetpeeringspoke1.bicep create mode 100644 035-HubAndSpoke/Student/Resources/bicep/01-vnetpeeringspoke2.bicep diff --git a/035-HubAndSpoke/README.md b/035-HubAndSpoke/README.md index 71e0ab4f7e..8dc5cb24ee 100644 --- a/035-HubAndSpoke/README.md +++ b/035-HubAndSpoke/README.md @@ -40,7 +40,7 @@ These are your challenges, it is recommended to start with the first one and pro - Fine tune your routing to send additional traffic flows through the firewall - Challenge 3: **[Routing Troubleshooting](Student/03-Asymmetric.md)** - Troubleshoot a routing problem introduced by a different admin -- Challenge 4: **[Application Gateway](Student/04-AppGW.MD)** +- Challenge 4: **[Application Gateway](Student/04-AppGW.md)** - Add an Application Gateway to the mix - Challenge 5: **[PaaS Networking](Student/05-Paas.md)** - Integrate Azure Web Apps and Azure SQL Databases with your hub and spoke design diff --git a/035-HubAndSpoke/Student/00-Prereqs.md b/035-HubAndSpoke/Student/00-Prereqs.md index f2cc1ed94f..3b9d2fb283 100644 --- a/035-HubAndSpoke/Student/00-Prereqs.md +++ b/035-HubAndSpoke/Student/00-Prereqs.md @@ -14,12 +14,12 @@ In this challenge we'll be setting up all the tools we will need to complete our - Ask your coach about the subscription you are going to use to fulfill the challenges - Install the recommended toolset, being one of this: - The Powershell way (same tooling for Windows, Linux or Mac): - - [Powershell core (7.x)](https://docs.microsoft.com/en-us/powershell/scripting/overview) + - [Powershell core (7.x)](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell) - [Azure Powershell modules](https://docs.microsoft.com/en-us/powershell/azure/new-azureps-module-az) - [Visual Studio Code](https://code.visualstudio.com/): the Windows Powershell ISE might be an option here for Windows users, but VS Code is far, far better - [vscode Powershell extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode.PowerShell) - The Azure CLI way: - - [Windows Subsystem for Linux](https://docs.microsoft.com/windows/wsl/install-win10), if you are running Windows and want to install the Azure CLI under a Linux shell like bash or zsh + - [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/install), if you are running Windows and want to install the Azure CLI under a Linux shell like bash or zsh - [Azure CLI](https://docs.microsoft.com/cli/azure/install-azure-cli) - [Visual Studio Code](https://code.visualstudio.com/): the Windows Powershell ISE might be an option here for Windows users, but VS Code is far, far better - [VScode Azure CLI extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode.azurecli) @@ -48,7 +48,7 @@ We recommend to review the below LinkedIn training and Azure docs(< 4 hours) in - Looking up IP addresses with DNS (DNS Hierarchical structure, DNS Record Types) - [Learning Subnetting](https://www.linkedin.com/learning/learning-subnetting-2019?u=3322) - - The structure of ipv4 addressess + - The structure of ipv4 addresses - Address classes - Public vs. private ipv4 communication - Types of IPv4 Communication diff --git a/035-HubAndSpoke/Student/Resources/bicep/00-resourceGroups.bicep b/035-HubAndSpoke/Student/Resources/bicep/00-resourceGroups.bicep new file mode 100644 index 0000000000..9ecc70b24a --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/00-resourceGroups.bicep @@ -0,0 +1,23 @@ +param location string = 'eastus2' + +targetScope = 'subscription' +//hub resources +resource wthrghub 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: 'wth-rg-hub' + location: location +} + +resource wthrgspoke01 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: 'wth-rg-spoke01' + location: location +} + +resource wthrgspoke02 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: 'wth-rg-spoke02' + location: location +} + +resource wthrgonprem 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: 'wth-rg-onprem01' + location: location +} diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep new file mode 100644 index 0000000000..8f49a8415e --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep @@ -0,0 +1,215 @@ +param location string = 'eastus2' +param hubVMUsername string = 'admin-wth' +@secure() +param hubVMPassword string + +targetScope = 'resourceGroup' +//hub resources + +resource wthhubvnet 'Microsoft.Network/virtualNetworks@2021-08-01' = { + name: 'wth-vnet-hub01' + location: location + properties: { + addressSpace: { + addressPrefixes: [ + '10.0.0.0/16' + ] + } + subnets: [ + { + name: 'GatewaySubnet' + properties: { + addressPrefix: '10.0.0.0/24' + routeTable: { + id: rtvnetgw.id + } + } + } + { + name: 'subnet-hubvms' + properties: { + addressPrefix: '10.0.10.0/24' + routeTable: { + id: rthubvms.id + } + networkSecurityGroup: { + id: nsghubvms.id + } + } + } + ] + } +} + +resource wthhubgwpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { + name: 'wth-pip-gw01' + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } +} + +resource wthhubgwpip02 'Microsoft.Network/publicIPAddresses@2022-01-01' = { + name: 'wth-pip-gw02' + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } +} + +resource wthhubvnetgw 'Microsoft.Network/virtualNetworkGateways@2022-01-01' = { + name: 'wth-vngw-hub01' + location: location + properties: { + activeActive: true + bgpSettings: { + asn: 65515 + } + enableBgp: true + gatewayType: 'Vpn' + vpnType: 'RouteBased' + vpnGatewayGeneration: 'Generation2' + sku: { + name: 'VpnGw1' + tier: 'VpnGw1' + } + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + publicIPAddress: { + id: wthhubgwpip01.id + } + subnet: { + id: '${wthhubvnet.id}/subnets/GatewaySubnet' + } + } + } + { + name: 'ipconfig2' + properties: { + publicIPAddress: { + id: wthhubgwpip02.id + } + subnet: { + id: '${wthhubvnet.id}/subnets/GatewaySubnet' + } + } + } + ] + } +} + +resource wthhubvmnic 'Microsoft.Network/networkInterfaces@2022-01-01' = { + name: 'wth-nic-hubvm01' + location: location + properties: { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + subnet: { + id: '${wthhubvnet.id}/subnets/subnet-hubvms' + } + privateIPAddress: '10.0.10.4' + } + } + ] + } +} + +resource wthhubvm01 'Microsoft.Compute/virtualMachines@2022-03-01' = { + name: 'wth-vm-hub01' + location: location + properties: { + hardwareProfile: { + vmSize: 'Standard_B2s' + } + storageProfile: { + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + osDisk: { + osType: 'Windows' + name: 'wth-disk-vmhubos01' + createOption: 'FromImage' + caching: 'ReadWrite' + } + } + osProfile: { + computerName: 'vm-hub01' + adminUsername: hubVMUsername + adminPassword: hubVMPassword + windowsConfiguration: { + provisionVMAgent: true + enableAutomaticUpdates: true + } + } + networkProfile: { + networkInterfaces: [ + { + id: wthhubvmnic.id + } + ] + } + diagnosticsProfile: { + bootDiagnostics: { + enabled: true + } + } + licenseType: 'Windows_Server' + } +} + +resource rtvnetgw 'Microsoft.Network/routeTables@2022-01-01' = { + name: 'wth-rt-hubgwsubnet' + properties: { + routes: [] + disableBgpRoutePropagation: false + } +} + +resource rthubvms 'Microsoft.Network/routeTables@2022-01-01' = { + name: 'wth-rt-hubvmssubnet' + properties: { + routes: [] + disableBgpRoutePropagation: false + } +} + +resource nsghubvms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { + name: 'wth-nsg-hubvmssubnet' + properties: { + securityRules: [ + { + name: 'allow-altrdp-to-vmssubnet-from-any' + properties: { + access: 'Allow' + direction: 'Inbound' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '33899-33899' + sourceAddressPrefix: '*' + destinationAddressPrefix: '10.0.10.0/24' + } + } + { + name: 'allow-altssh-to-vmssubnet-from-any' + properties: { + access: 'Allow' + direction: 'Inbound' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '22222-22222' + sourceAddressPrefix: '*' + destinationAddressPrefix: '10.0.10.0/24' + } + } + ] + } +} diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep new file mode 100644 index 0000000000..fc210dc07e --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep @@ -0,0 +1,142 @@ +param location string = 'eastus2' +param spoke1VMUsername string = 'admin-wth' +@secure() +param spoke1VMPassword string + +targetScope = 'resourceGroup' +//spoke1 resources + +resource wthspoke1vnet 'Microsoft.Network/virtualNetworks@2021-08-01' = { + name: 'wth-vnet-spoke101' + location: location + properties: { + addressSpace: { + addressPrefixes: [ + '10.1.0.0/16' + ] + } + subnets: [ + { + name: 'subnet-spoke1vms' + properties: { + addressPrefix: '10.1.10.0/24' + networkSecurityGroup: {id: nsgspoke1vms.id} + routeTable: { id: rtspoke1vms.id } + } + } + ] + } +} + +resource wthspoke1vmpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { + name: 'wth-pip-spoke1vm01' + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } +} + +resource wthspoke1vmnic 'Microsoft.Network/networkInterfaces@2022-01-01' = { + name: 'wth-nic-spoke1vm01' + location: location + properties: { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + subnet: { + id: '${wthspoke1vnet.id}/subnets/subnet-spoke1vms' + } + privateIPAddress: '10.1.10.4' + } + } + ] + } +} + +resource wthspoke1vm01 'Microsoft.Compute/virtualMachines@2022-03-01' = { + name: 'wth-vm-spoke101' + location: location + properties: { + hardwareProfile: { + vmSize: 'Standard_B2s' + } + storageProfile: { + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + osDisk: { + osType: 'Windows' + name: 'wth-disk-vmspoke1os01' + createOption: 'FromImage' + caching: 'ReadWrite' + } + } + osProfile: { + computerName: 'vm-spoke101' + adminUsername: spoke1VMUsername + adminPassword: spoke1VMPassword + windowsConfiguration: { + provisionVMAgent: true + enableAutomaticUpdates: true + } + } + networkProfile: { + networkInterfaces: [ + { + id: wthspoke1vmnic.id + } + ] + } + diagnosticsProfile: { + bootDiagnostics: { + enabled: true + } + } + licenseType: 'Windows_Server' + } +} + +resource rtspoke1vms 'Microsoft.Network/routeTables@2022-01-01' = { + name: 'wth-rt-spoke1vmssubnet' + properties: { + routes: [] + disableBgpRoutePropagation: false + } +} + +resource nsgspoke1vms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { + name: 'wth-nsg-spoke1vmssubnet' + properties: { + securityRules: [ + { + name: 'allow-altrdp-to-vmssubnet-from-any' + properties: { + access: 'Allow' + direction: 'Inbound' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '33899-33899' + sourceAddressPrefix: '*' + destinationAddressPrefix: '10.1.10.0/24' + } + } + { + name: 'allow-altssh-to-vmssubnet-from-any' + properties: { + access: 'Allow' + direction: 'Inbound' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '22222-22222' + sourceAddressPrefix: '*' + destinationAddressPrefix: '10.1.10.0/24' + } + } + ] + } +} diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep new file mode 100644 index 0000000000..63eb9eae3c --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep @@ -0,0 +1,140 @@ +param location string = 'eastus2' +param spoke2VMUsername string = 'admin-wth' +@secure() +param spoke2VMPassword string + +targetScope = 'resourceGroup' +//spoke2 resources + +resource wthspoke2vnet 'Microsoft.Network/virtualNetworks@2021-08-01' = { + name: 'wth-vnet-spoke201' + location: location + properties: { + addressSpace: { + addressPrefixes: [ + '10.2.0.0/16' + ] + } + subnets: [ + { + name: 'subnet-spoke2vms' + properties: { + addressPrefix: '10.2.10.0/24' + } + } + ] + } +} + +resource wthspoke2vmpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { + name: 'wth-pip-spoke2vm01' + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } +} + +resource wthspoke2vmnic 'Microsoft.Network/networkInterfaces@2022-01-01' = { + name: 'wth-nic-spoke2vm01' + location: location + properties: { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + subnet: { + id: '${wthspoke2vnet.id}/subnets/subnet-spoke2vms' + } + privateIPAddress: '10.2.10.4' + } + } + ] + } +} + +resource wthspoke2vm01 'Microsoft.Compute/virtualMachines@2022-03-01' = { + name: 'wth-vm-spoke201' + location: location + properties: { + hardwareProfile: { + vmSize: 'Standard_B2s' + } + storageProfile: { + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + osDisk: { + osType: 'Windows' + name: 'wth-disk-vmspoke2os01' + createOption: 'FromImage' + caching: 'ReadWrite' + } + } + osProfile: { + computerName: 'vm-spoke201' + adminUsername: spoke2VMUsername + adminPassword: spoke2VMPassword + windowsConfiguration: { + provisionVMAgent: true + enableAutomaticUpdates: true + } + } + networkProfile: { + networkInterfaces: [ + { + id: wthspoke2vmnic.id + } + ] + } + diagnosticsProfile: { + bootDiagnostics: { + enabled: true + } + } + licenseType: 'Windows_Server' + } +} + +resource rtspoke2vms 'Microsoft.Network/routeTables@2022-01-01' = { + name: 'wth-rt-spoke2vmssubnet' + properties: { + routes: [] + disableBgpRoutePropagation: false + } +} + +resource nsgspoke1vms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { + name: 'wth-nsg-spoke2vmssubnet' + properties: { + securityRules: [ + { + name: 'allow-altrdp-to-vmssubnet-from-any' + properties: { + access: 'Allow' + direction: 'Inbound' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '33899-33899' + sourceAddressPrefix: '*' + destinationAddressPrefix: '10.2.10.0/24' + } + } + { + name: 'allow-altssh-to-vmssubnet-from-any' + properties: { + access: 'Allow' + direction: 'Inbound' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '22222-22222' + sourceAddressPrefix: '*' + destinationAddressPrefix: '10.2.10.0/24' + } + } + ] + } +} diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-vnetpeeringhub.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-vnetpeeringhub.bicep new file mode 100644 index 0000000000..2a5c4b4453 --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/01-vnetpeeringhub.bicep @@ -0,0 +1,40 @@ +resource hubvnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { + name: 'wth-vnet-hub01' + scope: resourceGroup('wth-rg-hub') +} + +resource spoke1vnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { + name: 'wth-vnet-spoke101' + scope: resourceGroup('wth-rg-spoke1') +} + +resource spoke2vnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { + name: 'wth-vnet-spoke201' + scope: resourceGroup('wth-rg-spoke2') +} + +resource hubtospoke1 'Microsoft.Network/virtualNetworks/virtualNetworkPeerings@2022-01-01' = { + name: '${hubvnet.name}/wth-peering-hubtospoke1' + properties: { + allowGatewayTransit: true + allowForwardedTraffic: true + allowVirtualNetworkAccess: true + useRemoteGateways: false + remoteVirtualNetwork: { + id: spoke1vnet.id + } + } +} + +resource hubtospoke2 'Microsoft.Network/virtualNetworks/virtualNetworkPeerings@2022-01-01' = { + name: '${hubvnet.name}/wth-peering-hubtospoke1' + properties: { + allowGatewayTransit: true + allowForwardedTraffic: true + allowVirtualNetworkAccess: true + useRemoteGateways: false + remoteVirtualNetwork: { + id: spoke2vnet.id + } + } +} diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-vnetpeeringspoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-vnetpeeringspoke1.bicep new file mode 100644 index 0000000000..6531902b6a --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/01-vnetpeeringspoke1.bicep @@ -0,0 +1,27 @@ +resource hubvnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { + name: 'wth-vnet-hub01' + scope: resourceGroup('wth-rg-hub') +} + +resource spoke1vnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { + name: 'wth-vnet-spoke101' + scope: resourceGroup('wth-rg-spoke1') +} + +resource spoke2vnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { + name: 'wth-vnet-spoke201' + scope: resourceGroup('wth-rg-spoke2') +} + +resource spoke1tohub 'Microsoft.Network/virtualNetworks/virtualNetworkPeerings@2022-01-01' = { + name: '${spoke1vnet.name}/wth-peering-spoke1tohub' + properties: { + allowGatewayTransit: false + allowForwardedTraffic: false + allowVirtualNetworkAccess: true + useRemoteGateways: true + remoteVirtualNetwork: { + id: hubvnet.id + } + } +} diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-vnetpeeringspoke2.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-vnetpeeringspoke2.bicep new file mode 100644 index 0000000000..d837f6e6b5 --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/01-vnetpeeringspoke2.bicep @@ -0,0 +1,27 @@ +resource hubvnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { + name: 'wth-vnet-hub01' + scope: resourceGroup('wth-rg-hub') +} + +resource spoke1vnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { + name: 'wth-vnet-spoke101' + scope: resourceGroup('wth-rg-spoke1') +} + +resource spoke2vnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { + name: 'wth-vnet-spoke201' + scope: resourceGroup('wth-rg-spoke2') +} + +resource spoke2tohub 'Microsoft.Network/virtualNetworks/virtualNetworkPeerings@2022-01-01' = { + name: '${spoke2vnet.name}/wth-peering-spoke1tohub' + properties: { + allowGatewayTransit: false + allowForwardedTraffic: false + allowVirtualNetworkAccess: true + useRemoteGateways: true + remoteVirtualNetwork: { + id: hubvnet.id + } + } +} diff --git a/035-HubAndSpoke/Student/Resources/csr.md b/035-HubAndSpoke/Student/Resources/csr.md index 0b595e5e12..ac9cbf806c 100644 --- a/035-HubAndSpoke/Student/Resources/csr.md +++ b/035-HubAndSpoke/Student/Resources/csr.md @@ -2,7 +2,13 @@ ## Sample deployment script -You can use this script to deploy a Cisco CSR router to a new Vnet: +You can use this script to deploy a Cisco CSR router to a new VNet by following these steps: + +1. Depending on your shell, copy the appropriate variables declaration script below into your code editor, then copy the following Create CSR code block int your editor +1. Update the variable values to match your deployment +1. Run the updated script in your terminal to deploy your Cisco CSR + +### Bash variable declaration script ```bash # Variables @@ -19,9 +25,32 @@ branch_bgp_ip=172.16.1.10 branch_asn=65501 branch_username=labuser branch_password=BlahBlah123! +``` +### PowerShell variable declaration script + +```powershell +# Variables +$rg='myrg' +$location='westeurope' +$publisher='cisco' +$offer='cisco-csr-1000v' +$sku='16_12-byol' +$branch_name='branch1' +$branch_prefix='172.16.1.0/24' +$branch_subnet='172.16.1.0/26' +$branch_gateway='172.16.1.1' +$branch_bgp_ip='172.16.1.10' +$branch_asn='65501' +$branch_username='labuser' +$branch_password='BlahBlah123!' +``` + +### CSR Deployment Script (works in PowerShell and Bash shells) + +``` # Create CSR -az group create -n $rg -l westeurope +az group create -n $rg -l $location version=$(az vm image list -p $publisher -f $offer -s $sku --all --query '[0].version' -o tsv) # You only need to accept the image terms once per subscription az vm image terms accept --urn ${publisher}:${offer}:${sku}:${version} @@ -46,6 +75,8 @@ ssh -o BatchMode=yes -o StrictHostKeyChecking=no ${branch_username}@${branch_ip} EOF ``` + + ## Useful Cisco IOS commands This list is by no means comprehensive, but it is conceived to give some of the most useful commands for admins new to the Cisco CLI From c0562f939ce13ab0862d76c9762e9a5cbd2e78e5 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Mon, 25 Jul 2022 13:21:41 -0600 Subject: [PATCH 02/76] location param --- 035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep | 3 +++ 035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep | 2 ++ 035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep | 2 ++ .../Student/Resources/bicep/01-vnetpeeringhub.bicep | 2 ++ 4 files changed, 9 insertions(+) diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep index 8f49a8415e..966aa3c0d1 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep @@ -168,6 +168,7 @@ resource wthhubvm01 'Microsoft.Compute/virtualMachines@2022-03-01' = { resource rtvnetgw 'Microsoft.Network/routeTables@2022-01-01' = { name: 'wth-rt-hubgwsubnet' + location: location properties: { routes: [] disableBgpRoutePropagation: false @@ -176,6 +177,7 @@ resource rtvnetgw 'Microsoft.Network/routeTables@2022-01-01' = { resource rthubvms 'Microsoft.Network/routeTables@2022-01-01' = { name: 'wth-rt-hubvmssubnet' + location: location properties: { routes: [] disableBgpRoutePropagation: false @@ -184,6 +186,7 @@ resource rthubvms 'Microsoft.Network/routeTables@2022-01-01' = { resource nsghubvms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { name: 'wth-nsg-hubvmssubnet' + location: location properties: { securityRules: [ { diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep index fc210dc07e..880db5d9c6 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep @@ -103,6 +103,7 @@ resource wthspoke1vm01 'Microsoft.Compute/virtualMachines@2022-03-01' = { resource rtspoke1vms 'Microsoft.Network/routeTables@2022-01-01' = { name: 'wth-rt-spoke1vmssubnet' + location: location properties: { routes: [] disableBgpRoutePropagation: false @@ -111,6 +112,7 @@ resource rtspoke1vms 'Microsoft.Network/routeTables@2022-01-01' = { resource nsgspoke1vms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { name: 'wth-nsg-spoke1vmssubnet' + location: location properties: { securityRules: [ { diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep index 63eb9eae3c..4a15b7159c 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep @@ -101,6 +101,7 @@ resource wthspoke2vm01 'Microsoft.Compute/virtualMachines@2022-03-01' = { resource rtspoke2vms 'Microsoft.Network/routeTables@2022-01-01' = { name: 'wth-rt-spoke2vmssubnet' + location: location properties: { routes: [] disableBgpRoutePropagation: false @@ -109,6 +110,7 @@ resource rtspoke2vms 'Microsoft.Network/routeTables@2022-01-01' = { resource nsgspoke1vms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { name: 'wth-nsg-spoke2vmssubnet' + location: location properties: { securityRules: [ { diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-vnetpeeringhub.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-vnetpeeringhub.bicep index 2a5c4b4453..0f1e40932c 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-vnetpeeringhub.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-vnetpeeringhub.bicep @@ -1,3 +1,5 @@ +param location string = 'eastus2' + resource hubvnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { name: 'wth-vnet-hub01' scope: resourceGroup('wth-rg-hub') From 416e80d6ad93a258fe395a8616ab6d9e4ab98e08 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Mon, 25 Jul 2022 13:23:44 -0600 Subject: [PATCH 03/76] nsg sr priority --- 035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep | 2 ++ 035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep | 2 ++ 035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep | 2 ++ 3 files changed, 6 insertions(+) diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep index 966aa3c0d1..48912c1615 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep @@ -192,6 +192,7 @@ resource nsghubvms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { { name: 'allow-altrdp-to-vmssubnet-from-any' properties: { + priority: 1000 access: 'Allow' direction: 'Inbound' protocol: 'Tcp' @@ -204,6 +205,7 @@ resource nsghubvms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { { name: 'allow-altssh-to-vmssubnet-from-any' properties: { + priority: 1000 access: 'Allow' direction: 'Inbound' protocol: 'Tcp' diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep index 880db5d9c6..43ffe6febe 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep @@ -118,6 +118,7 @@ resource nsgspoke1vms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { { name: 'allow-altrdp-to-vmssubnet-from-any' properties: { + priority: 1000 access: 'Allow' direction: 'Inbound' protocol: 'Tcp' @@ -130,6 +131,7 @@ resource nsgspoke1vms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { { name: 'allow-altssh-to-vmssubnet-from-any' properties: { + priority: 1000 access: 'Allow' direction: 'Inbound' protocol: 'Tcp' diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep index 4a15b7159c..1f016bb6f7 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep @@ -116,6 +116,7 @@ resource nsgspoke1vms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { { name: 'allow-altrdp-to-vmssubnet-from-any' properties: { + priority: 1000 access: 'Allow' direction: 'Inbound' protocol: 'Tcp' @@ -128,6 +129,7 @@ resource nsgspoke1vms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { { name: 'allow-altssh-to-vmssubnet-from-any' properties: { + priority: 1000 access: 'Allow' direction: 'Inbound' protocol: 'Tcp' From 90668e3e25be66e0a23a1560c20bb681a38e1eb6 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Mon, 25 Jul 2022 13:23:44 -0600 Subject: [PATCH 04/76] nsg sr priority --- 035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep | 2 ++ 035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep | 2 ++ 035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep | 2 ++ 3 files changed, 6 insertions(+) diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep index 966aa3c0d1..48912c1615 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep @@ -192,6 +192,7 @@ resource nsghubvms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { { name: 'allow-altrdp-to-vmssubnet-from-any' properties: { + priority: 1000 access: 'Allow' direction: 'Inbound' protocol: 'Tcp' @@ -204,6 +205,7 @@ resource nsghubvms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { { name: 'allow-altssh-to-vmssubnet-from-any' properties: { + priority: 1000 access: 'Allow' direction: 'Inbound' protocol: 'Tcp' diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep index 880db5d9c6..43ffe6febe 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep @@ -118,6 +118,7 @@ resource nsgspoke1vms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { { name: 'allow-altrdp-to-vmssubnet-from-any' properties: { + priority: 1000 access: 'Allow' direction: 'Inbound' protocol: 'Tcp' @@ -130,6 +131,7 @@ resource nsgspoke1vms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { { name: 'allow-altssh-to-vmssubnet-from-any' properties: { + priority: 1000 access: 'Allow' direction: 'Inbound' protocol: 'Tcp' diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep index 4a15b7159c..1f016bb6f7 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep @@ -116,6 +116,7 @@ resource nsgspoke1vms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { { name: 'allow-altrdp-to-vmssubnet-from-any' properties: { + priority: 1000 access: 'Allow' direction: 'Inbound' protocol: 'Tcp' @@ -128,6 +129,7 @@ resource nsgspoke1vms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { { name: 'allow-altssh-to-vmssubnet-from-any' properties: { + priority: 1000 access: 'Allow' direction: 'Inbound' protocol: 'Tcp' From ee372904b39d1147e3b3ccfbfe94f3ea709d0451 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Mon, 25 Jul 2022 13:25:47 -0600 Subject: [PATCH 05/76] nsg rule priority --- 035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep | 2 +- 035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep | 2 +- 035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep index 48912c1615..e81bbf1df6 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep @@ -205,7 +205,7 @@ resource nsghubvms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { { name: 'allow-altssh-to-vmssubnet-from-any' properties: { - priority: 1000 + priority: 1001 access: 'Allow' direction: 'Inbound' protocol: 'Tcp' diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep index 43ffe6febe..25c07941d0 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep @@ -131,7 +131,7 @@ resource nsgspoke1vms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { { name: 'allow-altssh-to-vmssubnet-from-any' properties: { - priority: 1000 + priority: 1001 access: 'Allow' direction: 'Inbound' protocol: 'Tcp' diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep index 1f016bb6f7..b6d7fca60c 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep @@ -129,7 +129,7 @@ resource nsgspoke1vms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { { name: 'allow-altssh-to-vmssubnet-from-any' properties: { - priority: 1000 + priority: 1001 access: 'Allow' direction: 'Inbound' protocol: 'Tcp' From 5057d400224039db1e2123a4e0d624252b0e2d0f Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Mon, 25 Jul 2022 13:42:05 -0600 Subject: [PATCH 06/76] vm extension --- .../Student/Resources/bicep/01-hub.bicep | 17 +++++++++++++++++ .../Student/Resources/bicep/01-spoke1.bicep | 17 +++++++++++++++++ .../Student/Resources/bicep/01-spoke2.bicep | 17 +++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep index e81bbf1df6..1b1854ed7b 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep @@ -48,6 +48,9 @@ resource wthhubgwpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { name: 'Standard' tier: 'Regional' } + properties: { + publicIPAllocationMethod: 'Static' + } } resource wthhubgwpip02 'Microsoft.Network/publicIPAddresses@2022-01-01' = { @@ -57,6 +60,9 @@ resource wthhubgwpip02 'Microsoft.Network/publicIPAddresses@2022-01-01' = { name: 'Standard' tier: 'Regional' } + properties: { + publicIPAllocationMethod: 'Static' + } } resource wthhubvnetgw 'Microsoft.Network/virtualNetworkGateways@2022-01-01' = { @@ -102,6 +108,17 @@ resource wthhubvnetgw 'Microsoft.Network/virtualNetworkGateways@2022-01-01' = { } } +resource changerdpport 'Microsoft.Compute/virtualMachines/runCommands@2022-03-01' = { + name: '${wthhubvm01.name}/wth-vmextn-changerdpport' + location: location + properties: { + source: { + commandId: 'RunPowershellScript' + script: 'U2V0LUl0ZW1Qcm9wZXJ0eSAtUGF0aCAiSEtMTTpcU3lzdGVtXEN1cnJlbnRDb250cm9sU2V0XENvbnRyb2xcVGVybWluYWwgU2VydmVyXFdpblN0YXRpb25zXFJEUC1UY3BcIiAtTmFtZSBQb3J0TnVtYmVyIC1WYWx1ZSAzMzg5OQpOZXctTmV0RmlyZXdhbGxSdWxlIC1EaXNwbGF5TmFtZSAiUkRQIDMzODk5IFRDUCIgLURpcmVjdGlvbiBJbmJvdW5kIC1Mb2NhbFBvcnQgNTAxMDIgLVByb3RvY29sIFRDUCAtQWN0aW9uIEFsbG93Ck5ldy1OZXRGaXJld2FsbFJ1bGUgLURpc3BsYXlOYW1lICJSRFAgMzM4OTkgVURQIiAtRGlyZWN0aW9uIEluYm91bmQgLUxvY2FsUG9ydCA1MDEwMiAtUHJvdG9jb2wgVURQIC1BY3Rpb24gQWxsb3cKUmVzdGFydC1TZXJ2aWNlIC1OYW1lIFRlcm1TZXJ2aWNlIC1Gb3JjZQ==' + } + } +} + resource wthhubvmnic 'Microsoft.Network/networkInterfaces@2022-01-01' = { name: 'wth-nic-hubvm01' location: location diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep index 25c07941d0..9cbed6da0d 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep @@ -35,6 +35,9 @@ resource wthspoke1vmpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { name: 'Standard' tier: 'Regional' } + properties: { + publicIPAllocationMethod: 'Static' + } } resource wthspoke1vmnic 'Microsoft.Network/networkInterfaces@2022-01-01' = { @@ -49,6 +52,9 @@ resource wthspoke1vmnic 'Microsoft.Network/networkInterfaces@2022-01-01' = { id: '${wthspoke1vnet.id}/subnets/subnet-spoke1vms' } privateIPAddress: '10.1.10.4' + publicIPAddress: { + id: wthspoke1vmpip01.id + } } } ] @@ -101,6 +107,17 @@ resource wthspoke1vm01 'Microsoft.Compute/virtualMachines@2022-03-01' = { } } +resource changerdpport 'Microsoft.Compute/virtualMachines/runCommands@2022-03-01' = { + name: '${wthspoke1vm01.name}/wth-vmextn-changerdpport' + location: location + properties: { + source: { + commandId: 'RunPowershellScript' + script: 'U2V0LUl0ZW1Qcm9wZXJ0eSAtUGF0aCAiSEtMTTpcU3lzdGVtXEN1cnJlbnRDb250cm9sU2V0XENvbnRyb2xcVGVybWluYWwgU2VydmVyXFdpblN0YXRpb25zXFJEUC1UY3BcIiAtTmFtZSBQb3J0TnVtYmVyIC1WYWx1ZSAzMzg5OQpOZXctTmV0RmlyZXdhbGxSdWxlIC1EaXNwbGF5TmFtZSAiUkRQIDMzODk5IFRDUCIgLURpcmVjdGlvbiBJbmJvdW5kIC1Mb2NhbFBvcnQgNTAxMDIgLVByb3RvY29sIFRDUCAtQWN0aW9uIEFsbG93Ck5ldy1OZXRGaXJld2FsbFJ1bGUgLURpc3BsYXlOYW1lICJSRFAgMzM4OTkgVURQIiAtRGlyZWN0aW9uIEluYm91bmQgLUxvY2FsUG9ydCA1MDEwMiAtUHJvdG9jb2wgVURQIC1BY3Rpb24gQWxsb3cKUmVzdGFydC1TZXJ2aWNlIC1OYW1lIFRlcm1TZXJ2aWNlIC1Gb3JjZQ==' + } + } +} + resource rtspoke1vms 'Microsoft.Network/routeTables@2022-01-01' = { name: 'wth-rt-spoke1vmssubnet' location: location diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep index b6d7fca60c..e14e2f919a 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep @@ -33,6 +33,9 @@ resource wthspoke2vmpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { name: 'Standard' tier: 'Regional' } + properties: { + publicIPAllocationMethod: 'Static' + } } resource wthspoke2vmnic 'Microsoft.Network/networkInterfaces@2022-01-01' = { @@ -47,6 +50,9 @@ resource wthspoke2vmnic 'Microsoft.Network/networkInterfaces@2022-01-01' = { id: '${wthspoke2vnet.id}/subnets/subnet-spoke2vms' } privateIPAddress: '10.2.10.4' + publicIPAddress: { + id: wthspoke2vmpip01.id + } } } ] @@ -99,6 +105,17 @@ resource wthspoke2vm01 'Microsoft.Compute/virtualMachines@2022-03-01' = { } } +resource changerdpport 'Microsoft.Compute/virtualMachines/runCommands@2022-03-01' = { + name: '${wthspoke2vm01.name}/wth-vmextn-changerdpport' + location: location + properties: { + source: { + commandId: 'RunPowershellScript' + script: 'U2V0LUl0ZW1Qcm9wZXJ0eSAtUGF0aCAiSEtMTTpcU3lzdGVtXEN1cnJlbnRDb250cm9sU2V0XENvbnRyb2xcVGVybWluYWwgU2VydmVyXFdpblN0YXRpb25zXFJEUC1UY3BcIiAtTmFtZSBQb3J0TnVtYmVyIC1WYWx1ZSAzMzg5OQpOZXctTmV0RmlyZXdhbGxSdWxlIC1EaXNwbGF5TmFtZSAiUkRQIDMzODk5IFRDUCIgLURpcmVjdGlvbiBJbmJvdW5kIC1Mb2NhbFBvcnQgNTAxMDIgLVByb3RvY29sIFRDUCAtQWN0aW9uIEFsbG93Ck5ldy1OZXRGaXJld2FsbFJ1bGUgLURpc3BsYXlOYW1lICJSRFAgMzM4OTkgVURQIiAtRGlyZWN0aW9uIEluYm91bmQgLUxvY2FsUG9ydCA1MDEwMiAtUHJvdG9jb2wgVURQIC1BY3Rpb24gQWxsb3cKUmVzdGFydC1TZXJ2aWNlIC1OYW1lIFRlcm1TZXJ2aWNlIC1Gb3JjZQ==' + } + } +} + resource rtspoke2vms 'Microsoft.Network/routeTables@2022-01-01' = { name: 'wth-rt-spoke2vmssubnet' location: location From f0e95e72b2d838e4dc76085c7c18055a6c627f91 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Mon, 25 Jul 2022 13:46:38 -0600 Subject: [PATCH 07/76] extn, gw sku --- 035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep | 3 +-- 035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep | 1 - 035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep index 1b1854ed7b..45ca30d28e 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep @@ -76,7 +76,7 @@ resource wthhubvnetgw 'Microsoft.Network/virtualNetworkGateways@2022-01-01' = { enableBgp: true gatewayType: 'Vpn' vpnType: 'RouteBased' - vpnGatewayGeneration: 'Generation2' + vpnGatewayGeneration: 'Generation1' sku: { name: 'VpnGw1' tier: 'VpnGw1' @@ -113,7 +113,6 @@ resource changerdpport 'Microsoft.Compute/virtualMachines/runCommands@2022-03-01 location: location properties: { source: { - commandId: 'RunPowershellScript' script: 'U2V0LUl0ZW1Qcm9wZXJ0eSAtUGF0aCAiSEtMTTpcU3lzdGVtXEN1cnJlbnRDb250cm9sU2V0XENvbnRyb2xcVGVybWluYWwgU2VydmVyXFdpblN0YXRpb25zXFJEUC1UY3BcIiAtTmFtZSBQb3J0TnVtYmVyIC1WYWx1ZSAzMzg5OQpOZXctTmV0RmlyZXdhbGxSdWxlIC1EaXNwbGF5TmFtZSAiUkRQIDMzODk5IFRDUCIgLURpcmVjdGlvbiBJbmJvdW5kIC1Mb2NhbFBvcnQgNTAxMDIgLVByb3RvY29sIFRDUCAtQWN0aW9uIEFsbG93Ck5ldy1OZXRGaXJld2FsbFJ1bGUgLURpc3BsYXlOYW1lICJSRFAgMzM4OTkgVURQIiAtRGlyZWN0aW9uIEluYm91bmQgLUxvY2FsUG9ydCA1MDEwMiAtUHJvdG9jb2wgVURQIC1BY3Rpb24gQWxsb3cKUmVzdGFydC1TZXJ2aWNlIC1OYW1lIFRlcm1TZXJ2aWNlIC1Gb3JjZQ==' } } diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep index 9cbed6da0d..ec26f74ce5 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep @@ -112,7 +112,6 @@ resource changerdpport 'Microsoft.Compute/virtualMachines/runCommands@2022-03-01 location: location properties: { source: { - commandId: 'RunPowershellScript' script: 'U2V0LUl0ZW1Qcm9wZXJ0eSAtUGF0aCAiSEtMTTpcU3lzdGVtXEN1cnJlbnRDb250cm9sU2V0XENvbnRyb2xcVGVybWluYWwgU2VydmVyXFdpblN0YXRpb25zXFJEUC1UY3BcIiAtTmFtZSBQb3J0TnVtYmVyIC1WYWx1ZSAzMzg5OQpOZXctTmV0RmlyZXdhbGxSdWxlIC1EaXNwbGF5TmFtZSAiUkRQIDMzODk5IFRDUCIgLURpcmVjdGlvbiBJbmJvdW5kIC1Mb2NhbFBvcnQgNTAxMDIgLVByb3RvY29sIFRDUCAtQWN0aW9uIEFsbG93Ck5ldy1OZXRGaXJld2FsbFJ1bGUgLURpc3BsYXlOYW1lICJSRFAgMzM4OTkgVURQIiAtRGlyZWN0aW9uIEluYm91bmQgLUxvY2FsUG9ydCA1MDEwMiAtUHJvdG9jb2wgVURQIC1BY3Rpb24gQWxsb3cKUmVzdGFydC1TZXJ2aWNlIC1OYW1lIFRlcm1TZXJ2aWNlIC1Gb3JjZQ==' } } diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep index e14e2f919a..ac5930d6e0 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep @@ -110,7 +110,6 @@ resource changerdpport 'Microsoft.Compute/virtualMachines/runCommands@2022-03-01 location: location properties: { source: { - commandId: 'RunPowershellScript' script: 'U2V0LUl0ZW1Qcm9wZXJ0eSAtUGF0aCAiSEtMTTpcU3lzdGVtXEN1cnJlbnRDb250cm9sU2V0XENvbnRyb2xcVGVybWluYWwgU2VydmVyXFdpblN0YXRpb25zXFJEUC1UY3BcIiAtTmFtZSBQb3J0TnVtYmVyIC1WYWx1ZSAzMzg5OQpOZXctTmV0RmlyZXdhbGxSdWxlIC1EaXNwbGF5TmFtZSAiUkRQIDMzODk5IFRDUCIgLURpcmVjdGlvbiBJbmJvdW5kIC1Mb2NhbFBvcnQgNTAxMDIgLVByb3RvY29sIFRDUCAtQWN0aW9uIEFsbG93Ck5ldy1OZXRGaXJld2FsbFJ1bGUgLURpc3BsYXlOYW1lICJSRFAgMzM4OTkgVURQIiAtRGlyZWN0aW9uIEluYm91bmQgLUxvY2FsUG9ydCA1MDEwMiAtUHJvdG9jb2wgVURQIC1BY3Rpb24gQWxsb3cKUmVzdGFydC1TZXJ2aWNlIC1OYW1lIFRlcm1TZXJ2aWNlIC1Gb3JjZQ==' } } From 20f3549c67aa7a39ef3e6fd71d52dfbb80c0a8f6 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Mon, 25 Jul 2022 14:22:59 -0600 Subject: [PATCH 08/76] rg names --- .../Student/Resources/bicep/00-resourceGroups.bicep | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/00-resourceGroups.bicep b/035-HubAndSpoke/Student/Resources/bicep/00-resourceGroups.bicep index 9ecc70b24a..dba60c6b27 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/00-resourceGroups.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/00-resourceGroups.bicep @@ -8,16 +8,16 @@ resource wthrghub 'Microsoft.Resources/resourceGroups@2021-04-01' = { } resource wthrgspoke01 'Microsoft.Resources/resourceGroups@2021-04-01' = { - name: 'wth-rg-spoke01' + name: 'wth-rg-spoke1' location: location } resource wthrgspoke02 'Microsoft.Resources/resourceGroups@2021-04-01' = { - name: 'wth-rg-spoke02' + name: 'wth-rg-spoke2' location: location } resource wthrgonprem 'Microsoft.Resources/resourceGroups@2021-04-01' = { - name: 'wth-rg-onprem01' + name: 'wth-rg-onprem' location: location } From 895a5773743d646631ec9c8fb9dbaa35a91422ee Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Mon, 25 Jul 2022 15:09:35 -0600 Subject: [PATCH 09/76] change rdp port cse --- 035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep | 9 ++++++--- 035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep | 9 ++++++--- 035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep | 9 ++++++--- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep index 45ca30d28e..2ae3b0024a 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep @@ -108,12 +108,15 @@ resource wthhubvnetgw 'Microsoft.Network/virtualNetworkGateways@2022-01-01' = { } } -resource changerdpport 'Microsoft.Compute/virtualMachines/runCommands@2022-03-01' = { +resource changerdpport 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' = { name: '${wthhubvm01.name}/wth-vmextn-changerdpport' location: location properties: { - source: { - script: 'U2V0LUl0ZW1Qcm9wZXJ0eSAtUGF0aCAiSEtMTTpcU3lzdGVtXEN1cnJlbnRDb250cm9sU2V0XENvbnRyb2xcVGVybWluYWwgU2VydmVyXFdpblN0YXRpb25zXFJEUC1UY3BcIiAtTmFtZSBQb3J0TnVtYmVyIC1WYWx1ZSAzMzg5OQpOZXctTmV0RmlyZXdhbGxSdWxlIC1EaXNwbGF5TmFtZSAiUkRQIDMzODk5IFRDUCIgLURpcmVjdGlvbiBJbmJvdW5kIC1Mb2NhbFBvcnQgNTAxMDIgLVByb3RvY29sIFRDUCAtQWN0aW9uIEFsbG93Ck5ldy1OZXRGaXJld2FsbFJ1bGUgLURpc3BsYXlOYW1lICJSRFAgMzM4OTkgVURQIiAtRGlyZWN0aW9uIEluYm91bmQgLUxvY2FsUG9ydCA1MDEwMiAtUHJvdG9jb2wgVURQIC1BY3Rpb24gQWxsb3cKUmVzdGFydC1TZXJ2aWNlIC1OYW1lIFRlcm1TZXJ2aWNlIC1Gb3JjZQ==' + publisher: 'Microsoft.Compute' + type: 'CustomScriptExtension' + typeHandlerVersion: '1.10' + settings: { + commandToExecute: 'powershell.exe -ep bypass -encodedcommand U2V0LUl0ZW1Qcm9wZXJ0eSAtUGF0aCAiSEtMTTpcU3lzdGVtXEN1cnJlbnRDb250cm9sU2V0XENvbnRyb2xcVGVybWluYWwgU2VydmVyXFdpblN0YXRpb25zXFJEUC1UY3BcIiAtTmFtZSBQb3J0TnVtYmVyIC1WYWx1ZSAzMzg5OQpOZXctTmV0RmlyZXdhbGxSdWxlIC1EaXNwbGF5TmFtZSAiUkRQIDMzODk5IFRDUCIgLURpcmVjdGlvbiBJbmJvdW5kIC1Mb2NhbFBvcnQgNTAxMDIgLVByb3RvY29sIFRDUCAtQWN0aW9uIEFsbG93Ck5ldy1OZXRGaXJld2FsbFJ1bGUgLURpc3BsYXlOYW1lICJSRFAgMzM4OTkgVURQIiAtRGlyZWN0aW9uIEluYm91bmQgLUxvY2FsUG9ydCA1MDEwMiAtUHJvdG9jb2wgVURQIC1BY3Rpb24gQWxsb3cKUmVzdGFydC1TZXJ2aWNlIC1OYW1lIFRlcm1TZXJ2aWNlIC1Gb3JjZQ==' } } } diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep index ec26f74ce5..5bf3a8b9f8 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep @@ -107,12 +107,15 @@ resource wthspoke1vm01 'Microsoft.Compute/virtualMachines@2022-03-01' = { } } -resource changerdpport 'Microsoft.Compute/virtualMachines/runCommands@2022-03-01' = { +resource changerdpport 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' = { name: '${wthspoke1vm01.name}/wth-vmextn-changerdpport' location: location properties: { - source: { - script: 'U2V0LUl0ZW1Qcm9wZXJ0eSAtUGF0aCAiSEtMTTpcU3lzdGVtXEN1cnJlbnRDb250cm9sU2V0XENvbnRyb2xcVGVybWluYWwgU2VydmVyXFdpblN0YXRpb25zXFJEUC1UY3BcIiAtTmFtZSBQb3J0TnVtYmVyIC1WYWx1ZSAzMzg5OQpOZXctTmV0RmlyZXdhbGxSdWxlIC1EaXNwbGF5TmFtZSAiUkRQIDMzODk5IFRDUCIgLURpcmVjdGlvbiBJbmJvdW5kIC1Mb2NhbFBvcnQgNTAxMDIgLVByb3RvY29sIFRDUCAtQWN0aW9uIEFsbG93Ck5ldy1OZXRGaXJld2FsbFJ1bGUgLURpc3BsYXlOYW1lICJSRFAgMzM4OTkgVURQIiAtRGlyZWN0aW9uIEluYm91bmQgLUxvY2FsUG9ydCA1MDEwMiAtUHJvdG9jb2wgVURQIC1BY3Rpb24gQWxsb3cKUmVzdGFydC1TZXJ2aWNlIC1OYW1lIFRlcm1TZXJ2aWNlIC1Gb3JjZQ==' + publisher: 'Microsoft.Compute' + type: 'CustomScriptExtension' + typeHandlerVersion: '1.10' + settings: { + commandToExecute: 'powershell.exe -ep bypass -encodedcommand U2V0LUl0ZW1Qcm9wZXJ0eSAtUGF0aCAiSEtMTTpcU3lzdGVtXEN1cnJlbnRDb250cm9sU2V0XENvbnRyb2xcVGVybWluYWwgU2VydmVyXFdpblN0YXRpb25zXFJEUC1UY3BcIiAtTmFtZSBQb3J0TnVtYmVyIC1WYWx1ZSAzMzg5OQpOZXctTmV0RmlyZXdhbGxSdWxlIC1EaXNwbGF5TmFtZSAiUkRQIDMzODk5IFRDUCIgLURpcmVjdGlvbiBJbmJvdW5kIC1Mb2NhbFBvcnQgNTAxMDIgLVByb3RvY29sIFRDUCAtQWN0aW9uIEFsbG93Ck5ldy1OZXRGaXJld2FsbFJ1bGUgLURpc3BsYXlOYW1lICJSRFAgMzM4OTkgVURQIiAtRGlyZWN0aW9uIEluYm91bmQgLUxvY2FsUG9ydCA1MDEwMiAtUHJvdG9jb2wgVURQIC1BY3Rpb24gQWxsb3cKUmVzdGFydC1TZXJ2aWNlIC1OYW1lIFRlcm1TZXJ2aWNlIC1Gb3JjZQ==' } } } diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep index ac5930d6e0..0ba3ff82db 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep @@ -105,12 +105,15 @@ resource wthspoke2vm01 'Microsoft.Compute/virtualMachines@2022-03-01' = { } } -resource changerdpport 'Microsoft.Compute/virtualMachines/runCommands@2022-03-01' = { +resource changerdpport 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' = { name: '${wthspoke2vm01.name}/wth-vmextn-changerdpport' location: location properties: { - source: { - script: 'U2V0LUl0ZW1Qcm9wZXJ0eSAtUGF0aCAiSEtMTTpcU3lzdGVtXEN1cnJlbnRDb250cm9sU2V0XENvbnRyb2xcVGVybWluYWwgU2VydmVyXFdpblN0YXRpb25zXFJEUC1UY3BcIiAtTmFtZSBQb3J0TnVtYmVyIC1WYWx1ZSAzMzg5OQpOZXctTmV0RmlyZXdhbGxSdWxlIC1EaXNwbGF5TmFtZSAiUkRQIDMzODk5IFRDUCIgLURpcmVjdGlvbiBJbmJvdW5kIC1Mb2NhbFBvcnQgNTAxMDIgLVByb3RvY29sIFRDUCAtQWN0aW9uIEFsbG93Ck5ldy1OZXRGaXJld2FsbFJ1bGUgLURpc3BsYXlOYW1lICJSRFAgMzM4OTkgVURQIiAtRGlyZWN0aW9uIEluYm91bmQgLUxvY2FsUG9ydCA1MDEwMiAtUHJvdG9jb2wgVURQIC1BY3Rpb24gQWxsb3cKUmVzdGFydC1TZXJ2aWNlIC1OYW1lIFRlcm1TZXJ2aWNlIC1Gb3JjZQ==' + publisher: 'Microsoft.Compute' + type: 'CustomScriptExtension' + typeHandlerVersion: '1.10' + settings: { + commandToExecute: 'powershell.exe -ep bypass -encodedcommand U2V0LUl0ZW1Qcm9wZXJ0eSAtUGF0aCAiSEtMTTpcU3lzdGVtXEN1cnJlbnRDb250cm9sU2V0XENvbnRyb2xcVGVybWluYWwgU2VydmVyXFdpblN0YXRpb25zXFJEUC1UY3BcIiAtTmFtZSBQb3J0TnVtYmVyIC1WYWx1ZSAzMzg5OQpOZXctTmV0RmlyZXdhbGxSdWxlIC1EaXNwbGF5TmFtZSAiUkRQIDMzODk5IFRDUCIgLURpcmVjdGlvbiBJbmJvdW5kIC1Mb2NhbFBvcnQgNTAxMDIgLVByb3RvY29sIFRDUCAtQWN0aW9uIEFsbG93Ck5ldy1OZXRGaXJld2FsbFJ1bGUgLURpc3BsYXlOYW1lICJSRFAgMzM4OTkgVURQIiAtRGlyZWN0aW9uIEluYm91bmQgLUxvY2FsUG9ydCA1MDEwMiAtUHJvdG9jb2wgVURQIC1BY3Rpb24gQWxsb3cKUmVzdGFydC1TZXJ2aWNlIC1OYW1lIFRlcm1TZXJ2aWNlIC1Gb3JjZQ==' } } } From 2b9f401d07f8bce1410c720bf2dddbb088525695 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Mon, 25 Jul 2022 15:13:23 -0600 Subject: [PATCH 10/76] extn name --- 035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep | 2 +- 035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep | 2 +- 035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep index 2ae3b0024a..740b21d39d 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep @@ -109,7 +109,7 @@ resource wthhubvnetgw 'Microsoft.Network/virtualNetworkGateways@2022-01-01' = { } resource changerdpport 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' = { - name: '${wthhubvm01.name}/wth-vmextn-changerdpport' + name: '${wthhubvm01.name}/wth-vmextn-changerdpport33899' location: location properties: { publisher: 'Microsoft.Compute' diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep index 5bf3a8b9f8..a44fc079bb 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep @@ -108,7 +108,7 @@ resource wthspoke1vm01 'Microsoft.Compute/virtualMachines@2022-03-01' = { } resource changerdpport 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' = { - name: '${wthspoke1vm01.name}/wth-vmextn-changerdpport' + name: '${wthspoke1vm01.name}/wth-vmextn-changerdpport33899' location: location properties: { publisher: 'Microsoft.Compute' diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep index 0ba3ff82db..41baae858c 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep @@ -106,7 +106,7 @@ resource wthspoke2vm01 'Microsoft.Compute/virtualMachines@2022-03-01' = { } resource changerdpport 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' = { - name: '${wthspoke2vm01.name}/wth-vmextn-changerdpport' + name: '${wthspoke2vm01.name}/wth-vmextn-changerdpport33899' location: location properties: { publisher: 'Microsoft.Compute' From f0ddede13a9a24fd58ad23ce3ed3312117f945df Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Mon, 25 Jul 2022 15:20:00 -0600 Subject: [PATCH 11/76] enccmd --- 035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep | 2 +- 035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep | 2 +- 035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep index 740b21d39d..5bd02a154d 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep @@ -116,7 +116,7 @@ resource changerdpport 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' type: 'CustomScriptExtension' typeHandlerVersion: '1.10' settings: { - commandToExecute: 'powershell.exe -ep bypass -encodedcommand U2V0LUl0ZW1Qcm9wZXJ0eSAtUGF0aCAiSEtMTTpcU3lzdGVtXEN1cnJlbnRDb250cm9sU2V0XENvbnRyb2xcVGVybWluYWwgU2VydmVyXFdpblN0YXRpb25zXFJEUC1UY3BcIiAtTmFtZSBQb3J0TnVtYmVyIC1WYWx1ZSAzMzg5OQpOZXctTmV0RmlyZXdhbGxSdWxlIC1EaXNwbGF5TmFtZSAiUkRQIDMzODk5IFRDUCIgLURpcmVjdGlvbiBJbmJvdW5kIC1Mb2NhbFBvcnQgNTAxMDIgLVByb3RvY29sIFRDUCAtQWN0aW9uIEFsbG93Ck5ldy1OZXRGaXJld2FsbFJ1bGUgLURpc3BsYXlOYW1lICJSRFAgMzM4OTkgVURQIiAtRGlyZWN0aW9uIEluYm91bmQgLUxvY2FsUG9ydCA1MDEwMiAtUHJvdG9jb2wgVURQIC1BY3Rpb24gQWxsb3cKUmVzdGFydC1TZXJ2aWNlIC1OYW1lIFRlcm1TZXJ2aWNlIC1Gb3JjZQ==' + commandToExecute: 'powershell.exe -ep bypass -encodedcommand UwBlAHQALQBJAHQAZQBtAFAAcgBvAHAAZQByAHQAeQAgAC0AUABhAHQAaAAgACIASABLAEwATQA6AFwAUwB5AHMAdABlAG0AXABDAHUAcgByAGUAbgB0AEMAbwBuAHQAcgBvAGwAUwBlAHQAXABDAG8AbgB0AHIAbwBsAFwAVABlAHIAbQBpAG4AYQBsACAAUwBlAHIAdgBlAHIAXABXAGkAbgBTAHQAYQB0AGkAbwBuAHMAXABSAEQAUAAtAFQAYwBwAFwAIgAgAC0ATgBhAG0AZQAgAFAAbwByAHQATgB1AG0AYgBlAHIAIAAtAFYAYQBsAHUAZQAgADMAMwA4ADkAOQAKAE4AZQB3AC0ATgBlAHQARgBpAHIAZQB3AGEAbABsAFIAdQBsAGUAIAAtAEQAaQBzAHAAbABhAHkATgBhAG0AZQAgACIAUgBEAFAAIAAzADMAOAA5ADkAIABUAEMAUAAiACAALQBEAGkAcgBlAGMAdABpAG8AbgAgAEkAbgBiAG8AdQBuAGQAIAAtAEwAbwBjAGEAbABQAG8AcgB0ACAANQAwADEAMAAyACAALQBQAHIAbwB0AG8AYwBvAGwAIABUAEMAUAAgAC0AQQBjAHQAaQBvAG4AIABBAGwAbABvAHcACgBOAGUAdwAtAE4AZQB0AEYAaQByAGUAdwBhAGwAbABSAHUAbABlACAALQBEAGkAcwBwAGwAYQB5AE4AYQBtAGUAIAAiAFIARABQACAAMwAzADgAOQA5ACAAVQBEAFAAIgAgAC0ARABpAHIAZQBjAHQAaQBvAG4AIABJAG4AYgBvAHUAbgBkACAALQBMAG8AYwBhAGwAUABvAHIAdAAgADUAMAAxADAAMgAgAC0AUAByAG8AdABvAGMAbwBsACAAVQBEAFAAIAAtAEEAYwB0AGkAbwBuACAAQQBsAGwAbwB3AAoAUgBlAHMAdABhAHIAdAAtAFMAZQByAHYAaQBjAGUAIAAtAE4AYQBtAGUAIABUAGUAcgBtAFMAZQByAHYAaQBjAGUAIAAtAEYAbwByAGMAZQA=' } } } diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep index a44fc079bb..301216b75d 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep @@ -115,7 +115,7 @@ resource changerdpport 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' type: 'CustomScriptExtension' typeHandlerVersion: '1.10' settings: { - commandToExecute: 'powershell.exe -ep bypass -encodedcommand U2V0LUl0ZW1Qcm9wZXJ0eSAtUGF0aCAiSEtMTTpcU3lzdGVtXEN1cnJlbnRDb250cm9sU2V0XENvbnRyb2xcVGVybWluYWwgU2VydmVyXFdpblN0YXRpb25zXFJEUC1UY3BcIiAtTmFtZSBQb3J0TnVtYmVyIC1WYWx1ZSAzMzg5OQpOZXctTmV0RmlyZXdhbGxSdWxlIC1EaXNwbGF5TmFtZSAiUkRQIDMzODk5IFRDUCIgLURpcmVjdGlvbiBJbmJvdW5kIC1Mb2NhbFBvcnQgNTAxMDIgLVByb3RvY29sIFRDUCAtQWN0aW9uIEFsbG93Ck5ldy1OZXRGaXJld2FsbFJ1bGUgLURpc3BsYXlOYW1lICJSRFAgMzM4OTkgVURQIiAtRGlyZWN0aW9uIEluYm91bmQgLUxvY2FsUG9ydCA1MDEwMiAtUHJvdG9jb2wgVURQIC1BY3Rpb24gQWxsb3cKUmVzdGFydC1TZXJ2aWNlIC1OYW1lIFRlcm1TZXJ2aWNlIC1Gb3JjZQ==' + commandToExecute: 'powershell.exe -ep bypass -encodedcommand UwBlAHQALQBJAHQAZQBtAFAAcgBvAHAAZQByAHQAeQAgAC0AUABhAHQAaAAgACIASABLAEwATQA6AFwAUwB5AHMAdABlAG0AXABDAHUAcgByAGUAbgB0AEMAbwBuAHQAcgBvAGwAUwBlAHQAXABDAG8AbgB0AHIAbwBsAFwAVABlAHIAbQBpAG4AYQBsACAAUwBlAHIAdgBlAHIAXABXAGkAbgBTAHQAYQB0AGkAbwBuAHMAXABSAEQAUAAtAFQAYwBwAFwAIgAgAC0ATgBhAG0AZQAgAFAAbwByAHQATgB1AG0AYgBlAHIAIAAtAFYAYQBsAHUAZQAgADMAMwA4ADkAOQAKAE4AZQB3AC0ATgBlAHQARgBpAHIAZQB3AGEAbABsAFIAdQBsAGUAIAAtAEQAaQBzAHAAbABhAHkATgBhAG0AZQAgACIAUgBEAFAAIAAzADMAOAA5ADkAIABUAEMAUAAiACAALQBEAGkAcgBlAGMAdABpAG8AbgAgAEkAbgBiAG8AdQBuAGQAIAAtAEwAbwBjAGEAbABQAG8AcgB0ACAANQAwADEAMAAyACAALQBQAHIAbwB0AG8AYwBvAGwAIABUAEMAUAAgAC0AQQBjAHQAaQBvAG4AIABBAGwAbABvAHcACgBOAGUAdwAtAE4AZQB0AEYAaQByAGUAdwBhAGwAbABSAHUAbABlACAALQBEAGkAcwBwAGwAYQB5AE4AYQBtAGUAIAAiAFIARABQACAAMwAzADgAOQA5ACAAVQBEAFAAIgAgAC0ARABpAHIAZQBjAHQAaQBvAG4AIABJAG4AYgBvAHUAbgBkACAALQBMAG8AYwBhAGwAUABvAHIAdAAgADUAMAAxADAAMgAgAC0AUAByAG8AdABvAGMAbwBsACAAVQBEAFAAIAAtAEEAYwB0AGkAbwBuACAAQQBsAGwAbwB3AAoAUgBlAHMAdABhAHIAdAAtAFMAZQByAHYAaQBjAGUAIAAtAE4AYQBtAGUAIABUAGUAcgBtAFMAZQByAHYAaQBjAGUAIAAtAEYAbwByAGMAZQA=' } } } diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep index 41baae858c..ba827f5120 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep @@ -113,7 +113,7 @@ resource changerdpport 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' type: 'CustomScriptExtension' typeHandlerVersion: '1.10' settings: { - commandToExecute: 'powershell.exe -ep bypass -encodedcommand U2V0LUl0ZW1Qcm9wZXJ0eSAtUGF0aCAiSEtMTTpcU3lzdGVtXEN1cnJlbnRDb250cm9sU2V0XENvbnRyb2xcVGVybWluYWwgU2VydmVyXFdpblN0YXRpb25zXFJEUC1UY3BcIiAtTmFtZSBQb3J0TnVtYmVyIC1WYWx1ZSAzMzg5OQpOZXctTmV0RmlyZXdhbGxSdWxlIC1EaXNwbGF5TmFtZSAiUkRQIDMzODk5IFRDUCIgLURpcmVjdGlvbiBJbmJvdW5kIC1Mb2NhbFBvcnQgNTAxMDIgLVByb3RvY29sIFRDUCAtQWN0aW9uIEFsbG93Ck5ldy1OZXRGaXJld2FsbFJ1bGUgLURpc3BsYXlOYW1lICJSRFAgMzM4OTkgVURQIiAtRGlyZWN0aW9uIEluYm91bmQgLUxvY2FsUG9ydCA1MDEwMiAtUHJvdG9jb2wgVURQIC1BY3Rpb24gQWxsb3cKUmVzdGFydC1TZXJ2aWNlIC1OYW1lIFRlcm1TZXJ2aWNlIC1Gb3JjZQ==' + commandToExecute: 'powershell.exe -ep bypass -encodedcommand UwBlAHQALQBJAHQAZQBtAFAAcgBvAHAAZQByAHQAeQAgAC0AUABhAHQAaAAgACIASABLAEwATQA6AFwAUwB5AHMAdABlAG0AXABDAHUAcgByAGUAbgB0AEMAbwBuAHQAcgBvAGwAUwBlAHQAXABDAG8AbgB0AHIAbwBsAFwAVABlAHIAbQBpAG4AYQBsACAAUwBlAHIAdgBlAHIAXABXAGkAbgBTAHQAYQB0AGkAbwBuAHMAXABSAEQAUAAtAFQAYwBwAFwAIgAgAC0ATgBhAG0AZQAgAFAAbwByAHQATgB1AG0AYgBlAHIAIAAtAFYAYQBsAHUAZQAgADMAMwA4ADkAOQAKAE4AZQB3AC0ATgBlAHQARgBpAHIAZQB3AGEAbABsAFIAdQBsAGUAIAAtAEQAaQBzAHAAbABhAHkATgBhAG0AZQAgACIAUgBEAFAAIAAzADMAOAA5ADkAIABUAEMAUAAiACAALQBEAGkAcgBlAGMAdABpAG8AbgAgAEkAbgBiAG8AdQBuAGQAIAAtAEwAbwBjAGEAbABQAG8AcgB0ACAANQAwADEAMAAyACAALQBQAHIAbwB0AG8AYwBvAGwAIABUAEMAUAAgAC0AQQBjAHQAaQBvAG4AIABBAGwAbABvAHcACgBOAGUAdwAtAE4AZQB0AEYAaQByAGUAdwBhAGwAbABSAHUAbABlACAALQBEAGkAcwBwAGwAYQB5AE4AYQBtAGUAIAAiAFIARABQACAAMwAzADgAOQA5ACAAVQBEAFAAIgAgAC0ARABpAHIAZQBjAHQAaQBvAG4AIABJAG4AYgBvAHUAbgBkACAALQBMAG8AYwBhAGwAUABvAHIAdAAgADUAMAAxADAAMgAgAC0AUAByAG8AdABvAGMAbwBsACAAVQBEAFAAIAAtAEEAYwB0AGkAbwBuACAAQQBsAGwAbwB3AAoAUgBlAHMAdABhAHIAdAAtAFMAZQByAHYAaQBjAGUAIAAtAE4AYQBtAGUAIABUAGUAcgBtAFMAZQByAHYAaQBjAGUAIAAtAEYAbwByAGMAZQA=' } } } From 0909fe890e8d38700d1a04f58808583a6c9d2641 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Mon, 25 Jul 2022 15:30:55 -0600 Subject: [PATCH 12/76] cmd fix --- .../Student/Resources/bicep/01-hub.bicep | 13 ++++++++++++- .../Student/Resources/bicep/01-spoke1.bicep | 2 +- .../Student/Resources/bicep/01-spoke2.bicep | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep index 5bd02a154d..c08b36d08f 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep @@ -116,7 +116,18 @@ resource changerdpport 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' type: 'CustomScriptExtension' typeHandlerVersion: '1.10' settings: { - commandToExecute: 'powershell.exe -ep bypass -encodedcommand UwBlAHQALQBJAHQAZQBtAFAAcgBvAHAAZQByAHQAeQAgAC0AUABhAHQAaAAgACIASABLAEwATQA6AFwAUwB5AHMAdABlAG0AXABDAHUAcgByAGUAbgB0AEMAbwBuAHQAcgBvAGwAUwBlAHQAXABDAG8AbgB0AHIAbwBsAFwAVABlAHIAbQBpAG4AYQBsACAAUwBlAHIAdgBlAHIAXABXAGkAbgBTAHQAYQB0AGkAbwBuAHMAXABSAEQAUAAtAFQAYwBwAFwAIgAgAC0ATgBhAG0AZQAgAFAAbwByAHQATgB1AG0AYgBlAHIAIAAtAFYAYQBsAHUAZQAgADMAMwA4ADkAOQAKAE4AZQB3AC0ATgBlAHQARgBpAHIAZQB3AGEAbABsAFIAdQBsAGUAIAAtAEQAaQBzAHAAbABhAHkATgBhAG0AZQAgACIAUgBEAFAAIAAzADMAOAA5ADkAIABUAEMAUAAiACAALQBEAGkAcgBlAGMAdABpAG8AbgAgAEkAbgBiAG8AdQBuAGQAIAAtAEwAbwBjAGEAbABQAG8AcgB0ACAANQAwADEAMAAyACAALQBQAHIAbwB0AG8AYwBvAGwAIABUAEMAUAAgAC0AQQBjAHQAaQBvAG4AIABBAGwAbABvAHcACgBOAGUAdwAtAE4AZQB0AEYAaQByAGUAdwBhAGwAbABSAHUAbABlACAALQBEAGkAcwBwAGwAYQB5AE4AYQBtAGUAIAAiAFIARABQACAAMwAzADgAOQA5ACAAVQBEAFAAIgAgAC0ARABpAHIAZQBjAHQAaQBvAG4AIABJAG4AYgBvAHUAbgBkACAALQBMAG8AYwBhAGwAUABvAHIAdAAgADUAMAAxADAAMgAgAC0AUAByAG8AdABvAGMAbwBsACAAVQBEAFAAIAAtAEEAYwB0AGkAbwBuACAAQQBsAGwAbwB3AAoAUgBlAHMAdABhAHIAdAAtAFMAZQByAHYAaQBjAGUAIAAtAE4AYQBtAGUAIABUAGUAcgBtAFMAZQByAHYAaQBjAGUAIAAtAEYAbwByAGMAZQA=' + /* + To generate encoded command in PowerShell: + + $s = @' + Set-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp\" -Name PortNumber -Value 33899 + New-NetFirewallRule -DisplayName "RDP 33899 TCP" -Direction Inbound -LocalPort 33899 -Protocol TCP -Action Allow + New-NetFirewallRule -DisplayName "RDP 33899 UDP" -Direction Inbound -LocalPort 33899 -Protocol UDP -Action Allow + Restart-Service -Name TermService -Force + '@ + $bytes = [System.Text.Encoding]::Unicode.GetBytes($s) + [convert]::ToBase64String($bytes) */ + commandToExecute: 'powershell.exe -ep bypass -encodedcommand UwBlAHQALQBJAHQAZQBtAFAAcgBvAHAAZQByAHQAeQAgAC0AUABhAHQAaAAgACIASABLAEwATQA6AFwAUwB5AHMAdABlAG0AXABDAHUAcgByAGUAbgB0AEMAbwBuAHQAcgBvAGwAUwBlAHQAXABDAG8AbgB0AHIAbwBsAFwAVABlAHIAbQBpAG4AYQBsACAAUwBlAHIAdgBlAHIAXABXAGkAbgBTAHQAYQB0AGkAbwBuAHMAXABSAEQAUAAtAFQAYwBwAFwAIgAgAC0ATgBhAG0AZQAgAFAAbwByAHQATgB1AG0AYgBlAHIAIAAtAFYAYQBsAHUAZQAgADMAMwA4ADkAOQAKAE4AZQB3AC0ATgBlAHQARgBpAHIAZQB3AGEAbABsAFIAdQBsAGUAIAAtAEQAaQBzAHAAbABhAHkATgBhAG0AZQAgACIAUgBEAFAAIAAzADMAOAA5ADkAIABUAEMAUAAiACAALQBEAGkAcgBlAGMAdABpAG8AbgAgAEkAbgBiAG8AdQBuAGQAIAAtAEwAbwBjAGEAbABQAG8AcgB0ACAAMwAzADgAOQA5ACAALQBQAHIAbwB0AG8AYwBvAGwAIABUAEMAUAAgAC0AQQBjAHQAaQBvAG4AIABBAGwAbABvAHcACgBOAGUAdwAtAE4AZQB0AEYAaQByAGUAdwBhAGwAbABSAHUAbABlACAALQBEAGkAcwBwAGwAYQB5AE4AYQBtAGUAIAAiAFIARABQACAAMwAzADgAOQA5ACAAVQBEAFAAIgAgAC0ARABpAHIAZQBjAHQAaQBvAG4AIABJAG4AYgBvAHUAbgBkACAALQBMAG8AYwBhAGwAUABvAHIAdAAgADMAMwA4ADkAOQAgAC0AUAByAG8AdABvAGMAbwBsACAAVQBEAFAAIAAtAEEAYwB0AGkAbwBuACAAQQBsAGwAbwB3AAoAUgBlAHMAdABhAHIAdAAtAFMAZQByAHYAaQBjAGUAIAAtAE4AYQBtAGUAIABUAGUAcgBtAFMAZQByAHYAaQBjAGUAIAAtAEYAbwByAGMAZQA=' } } } diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep index 301216b75d..2a6e1508db 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep @@ -115,7 +115,7 @@ resource changerdpport 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' type: 'CustomScriptExtension' typeHandlerVersion: '1.10' settings: { - commandToExecute: 'powershell.exe -ep bypass -encodedcommand UwBlAHQALQBJAHQAZQBtAFAAcgBvAHAAZQByAHQAeQAgAC0AUABhAHQAaAAgACIASABLAEwATQA6AFwAUwB5AHMAdABlAG0AXABDAHUAcgByAGUAbgB0AEMAbwBuAHQAcgBvAGwAUwBlAHQAXABDAG8AbgB0AHIAbwBsAFwAVABlAHIAbQBpAG4AYQBsACAAUwBlAHIAdgBlAHIAXABXAGkAbgBTAHQAYQB0AGkAbwBuAHMAXABSAEQAUAAtAFQAYwBwAFwAIgAgAC0ATgBhAG0AZQAgAFAAbwByAHQATgB1AG0AYgBlAHIAIAAtAFYAYQBsAHUAZQAgADMAMwA4ADkAOQAKAE4AZQB3AC0ATgBlAHQARgBpAHIAZQB3AGEAbABsAFIAdQBsAGUAIAAtAEQAaQBzAHAAbABhAHkATgBhAG0AZQAgACIAUgBEAFAAIAAzADMAOAA5ADkAIABUAEMAUAAiACAALQBEAGkAcgBlAGMAdABpAG8AbgAgAEkAbgBiAG8AdQBuAGQAIAAtAEwAbwBjAGEAbABQAG8AcgB0ACAANQAwADEAMAAyACAALQBQAHIAbwB0AG8AYwBvAGwAIABUAEMAUAAgAC0AQQBjAHQAaQBvAG4AIABBAGwAbABvAHcACgBOAGUAdwAtAE4AZQB0AEYAaQByAGUAdwBhAGwAbABSAHUAbABlACAALQBEAGkAcwBwAGwAYQB5AE4AYQBtAGUAIAAiAFIARABQACAAMwAzADgAOQA5ACAAVQBEAFAAIgAgAC0ARABpAHIAZQBjAHQAaQBvAG4AIABJAG4AYgBvAHUAbgBkACAALQBMAG8AYwBhAGwAUABvAHIAdAAgADUAMAAxADAAMgAgAC0AUAByAG8AdABvAGMAbwBsACAAVQBEAFAAIAAtAEEAYwB0AGkAbwBuACAAQQBsAGwAbwB3AAoAUgBlAHMAdABhAHIAdAAtAFMAZQByAHYAaQBjAGUAIAAtAE4AYQBtAGUAIABUAGUAcgBtAFMAZQByAHYAaQBjAGUAIAAtAEYAbwByAGMAZQA=' + commandToExecute: 'powershell.exe -ep bypass -encodedcommand UwBlAHQALQBJAHQAZQBtAFAAcgBvAHAAZQByAHQAeQAgAC0AUABhAHQAaAAgACIASABLAEwATQA6AFwAUwB5AHMAdABlAG0AXABDAHUAcgByAGUAbgB0AEMAbwBuAHQAcgBvAGwAUwBlAHQAXABDAG8AbgB0AHIAbwBsAFwAVABlAHIAbQBpAG4AYQBsACAAUwBlAHIAdgBlAHIAXABXAGkAbgBTAHQAYQB0AGkAbwBuAHMAXABSAEQAUAAtAFQAYwBwAFwAIgAgAC0ATgBhAG0AZQAgAFAAbwByAHQATgB1AG0AYgBlAHIAIAAtAFYAYQBsAHUAZQAgADMAMwA4ADkAOQAKAE4AZQB3AC0ATgBlAHQARgBpAHIAZQB3AGEAbABsAFIAdQBsAGUAIAAtAEQAaQBzAHAAbABhAHkATgBhAG0AZQAgACIAUgBEAFAAIAAzADMAOAA5ADkAIABUAEMAUAAiACAALQBEAGkAcgBlAGMAdABpAG8AbgAgAEkAbgBiAG8AdQBuAGQAIAAtAEwAbwBjAGEAbABQAG8AcgB0ACAAMwAzADgAOQA5ACAALQBQAHIAbwB0AG8AYwBvAGwAIABUAEMAUAAgAC0AQQBjAHQAaQBvAG4AIABBAGwAbABvAHcACgBOAGUAdwAtAE4AZQB0AEYAaQByAGUAdwBhAGwAbABSAHUAbABlACAALQBEAGkAcwBwAGwAYQB5AE4AYQBtAGUAIAAiAFIARABQACAAMwAzADgAOQA5ACAAVQBEAFAAIgAgAC0ARABpAHIAZQBjAHQAaQBvAG4AIABJAG4AYgBvAHUAbgBkACAALQBMAG8AYwBhAGwAUABvAHIAdAAgADMAMwA4ADkAOQAgAC0AUAByAG8AdABvAGMAbwBsACAAVQBEAFAAIAAtAEEAYwB0AGkAbwBuACAAQQBsAGwAbwB3AAoAUgBlAHMAdABhAHIAdAAtAFMAZQByAHYAaQBjAGUAIAAtAE4AYQBtAGUAIABUAGUAcgBtAFMAZQByAHYAaQBjAGUAIAAtAEYAbwByAGMAZQA=' } } } diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep index ba827f5120..2368bab173 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep @@ -113,7 +113,7 @@ resource changerdpport 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' type: 'CustomScriptExtension' typeHandlerVersion: '1.10' settings: { - commandToExecute: 'powershell.exe -ep bypass -encodedcommand UwBlAHQALQBJAHQAZQBtAFAAcgBvAHAAZQByAHQAeQAgAC0AUABhAHQAaAAgACIASABLAEwATQA6AFwAUwB5AHMAdABlAG0AXABDAHUAcgByAGUAbgB0AEMAbwBuAHQAcgBvAGwAUwBlAHQAXABDAG8AbgB0AHIAbwBsAFwAVABlAHIAbQBpAG4AYQBsACAAUwBlAHIAdgBlAHIAXABXAGkAbgBTAHQAYQB0AGkAbwBuAHMAXABSAEQAUAAtAFQAYwBwAFwAIgAgAC0ATgBhAG0AZQAgAFAAbwByAHQATgB1AG0AYgBlAHIAIAAtAFYAYQBsAHUAZQAgADMAMwA4ADkAOQAKAE4AZQB3AC0ATgBlAHQARgBpAHIAZQB3AGEAbABsAFIAdQBsAGUAIAAtAEQAaQBzAHAAbABhAHkATgBhAG0AZQAgACIAUgBEAFAAIAAzADMAOAA5ADkAIABUAEMAUAAiACAALQBEAGkAcgBlAGMAdABpAG8AbgAgAEkAbgBiAG8AdQBuAGQAIAAtAEwAbwBjAGEAbABQAG8AcgB0ACAANQAwADEAMAAyACAALQBQAHIAbwB0AG8AYwBvAGwAIABUAEMAUAAgAC0AQQBjAHQAaQBvAG4AIABBAGwAbABvAHcACgBOAGUAdwAtAE4AZQB0AEYAaQByAGUAdwBhAGwAbABSAHUAbABlACAALQBEAGkAcwBwAGwAYQB5AE4AYQBtAGUAIAAiAFIARABQACAAMwAzADgAOQA5ACAAVQBEAFAAIgAgAC0ARABpAHIAZQBjAHQAaQBvAG4AIABJAG4AYgBvAHUAbgBkACAALQBMAG8AYwBhAGwAUABvAHIAdAAgADUAMAAxADAAMgAgAC0AUAByAG8AdABvAGMAbwBsACAAVQBEAFAAIAAtAEEAYwB0AGkAbwBuACAAQQBsAGwAbwB3AAoAUgBlAHMAdABhAHIAdAAtAFMAZQByAHYAaQBjAGUAIAAtAE4AYQBtAGUAIABUAGUAcgBtAFMAZQByAHYAaQBjAGUAIAAtAEYAbwByAGMAZQA=' + commandToExecute: 'powershell.exe -ep bypass -encodedcommand UwBlAHQALQBJAHQAZQBtAFAAcgBvAHAAZQByAHQAeQAgAC0AUABhAHQAaAAgACIASABLAEwATQA6AFwAUwB5AHMAdABlAG0AXABDAHUAcgByAGUAbgB0AEMAbwBuAHQAcgBvAGwAUwBlAHQAXABDAG8AbgB0AHIAbwBsAFwAVABlAHIAbQBpAG4AYQBsACAAUwBlAHIAdgBlAHIAXABXAGkAbgBTAHQAYQB0AGkAbwBuAHMAXABSAEQAUAAtAFQAYwBwAFwAIgAgAC0ATgBhAG0AZQAgAFAAbwByAHQATgB1AG0AYgBlAHIAIAAtAFYAYQBsAHUAZQAgADMAMwA4ADkAOQAKAE4AZQB3AC0ATgBlAHQARgBpAHIAZQB3AGEAbABsAFIAdQBsAGUAIAAtAEQAaQBzAHAAbABhAHkATgBhAG0AZQAgACIAUgBEAFAAIAAzADMAOAA5ADkAIABUAEMAUAAiACAALQBEAGkAcgBlAGMAdABpAG8AbgAgAEkAbgBiAG8AdQBuAGQAIAAtAEwAbwBjAGEAbABQAG8AcgB0ACAAMwAzADgAOQA5ACAALQBQAHIAbwB0AG8AYwBvAGwAIABUAEMAUAAgAC0AQQBjAHQAaQBvAG4AIABBAGwAbABvAHcACgBOAGUAdwAtAE4AZQB0AEYAaQByAGUAdwBhAGwAbABSAHUAbABlACAALQBEAGkAcwBwAGwAYQB5AE4AYQBtAGUAIAAiAFIARABQACAAMwAzADgAOQA5ACAAVQBEAFAAIgAgAC0ARABpAHIAZQBjAHQAaQBvAG4AIABJAG4AYgBvAHUAbgBkACAALQBMAG8AYwBhAGwAUABvAHIAdAAgADMAMwA4ADkAOQAgAC0AUAByAG8AdABvAGMAbwBsACAAVQBEAFAAIAAtAEEAYwB0AGkAbwBuACAAQQBsAGwAbwB3AAoAUgBlAHMAdABhAHIAdAAtAFMAZQByAHYAaQBjAGUAIAAtAE4AYQBtAGUAIABUAGUAcgBtAFMAZQByAHYAaQBjAGUAIAAtAEYAbwByAGMAZQA=' } } } From 6fe59dd1d96cda083a44963bc7b638a47a4d671a Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Mon, 25 Jul 2022 16:04:21 -0600 Subject: [PATCH 13/76] csr --- .../Student/Resources/bicep/01-onprem.bicep | 234 ++++++++++++++++++ 1 file changed, 234 insertions(+) create mode 100644 035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep new file mode 100644 index 0000000000..aff4ef9b82 --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep @@ -0,0 +1,234 @@ +param location string = 'eastus2' +param onpremVMUsername string = 'admin-wth' +@secure() +param onpremVMPassword string + +targetScope = 'resourceGroup' +//onprem resources + +resource wthonpremvnet 'Microsoft.Network/virtualNetworks@2021-08-01' = { + name: 'wth-vnet-onprem01' + location: location + properties: { + addressSpace: { + addressPrefixes: [ + '172.16.0.0/16' + ] + } + subnets: [ + { + name: 'subnet-vpn' + properties: { + addressPrefix: '172.16.0.0/24' + } + } + { + name: 'subnet-onpremvms' + properties: { + addressPrefix: '172.16.10.0/24' + networkSecurityGroup: {id: nsgonpremvms.id} + routeTable: { id: rtonpremvms.id } + } + } + ] + } +} + +resource wthonpremvmpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { + name: 'wth-pip-onpremvm01' + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } +} + +resource wthonpremvmnic 'Microsoft.Network/networkInterfaces@2022-01-01' = { + name: 'wth-nic-onpremvm01' + location: location + properties: { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + subnet: { + id: '${wthonpremvnet.id}/subnets/subnet-onpremvms' + } + privateIPAddress: '172.16.10.4' + publicIPAddress: { + id: wthonpremvmpip01.id + } + } + } + ] + } +} + +resource wthonpremvm01 'Microsoft.Compute/virtualMachines@2022-03-01' = { + name: 'wth-vm-onprem01' + location: location + properties: { + hardwareProfile: { + vmSize: 'Standard_B2s' + } + storageProfile: { + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + osDisk: { + osType: 'Windows' + name: 'wth-disk-vmonpremos01' + createOption: 'FromImage' + caching: 'ReadWrite' + } + } + osProfile: { + computerName: 'vm-onprem01' + adminUsername: onpremVMUsername + adminPassword: onpremVMPassword + windowsConfiguration: { + provisionVMAgent: true + enableAutomaticUpdates: true + } + } + networkProfile: { + networkInterfaces: [ + { + id: wthonpremvmnic.id + } + ] + } + diagnosticsProfile: { + bootDiagnostics: { + enabled: true + } + } + licenseType: 'Windows_Server' + } +} + +resource changerdpport 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' = { + name: '${wthonpremvm01.name}/wth-vmextn-changerdpport33899' + location: location + properties: { + publisher: 'Microsoft.Compute' + type: 'CustomScriptExtension' + typeHandlerVersion: '1.10' + settings: { + commandToExecute: 'powershell.exe -ep bypass -encodedcommand UwBlAHQALQBJAHQAZQBtAFAAcgBvAHAAZQByAHQAeQAgAC0AUABhAHQAaAAgACIASABLAEwATQA6AFwAUwB5AHMAdABlAG0AXABDAHUAcgByAGUAbgB0AEMAbwBuAHQAcgBvAGwAUwBlAHQAXABDAG8AbgB0AHIAbwBsAFwAVABlAHIAbQBpAG4AYQBsACAAUwBlAHIAdgBlAHIAXABXAGkAbgBTAHQAYQB0AGkAbwBuAHMAXABSAEQAUAAtAFQAYwBwAFwAIgAgAC0ATgBhAG0AZQAgAFAAbwByAHQATgB1AG0AYgBlAHIAIAAtAFYAYQBsAHUAZQAgADMAMwA4ADkAOQAKAE4AZQB3AC0ATgBlAHQARgBpAHIAZQB3AGEAbABsAFIAdQBsAGUAIAAtAEQAaQBzAHAAbABhAHkATgBhAG0AZQAgACIAUgBEAFAAIAAzADMAOAA5ADkAIABUAEMAUAAiACAALQBEAGkAcgBlAGMAdABpAG8AbgAgAEkAbgBiAG8AdQBuAGQAIAAtAEwAbwBjAGEAbABQAG8AcgB0ACAAMwAzADgAOQA5ACAALQBQAHIAbwB0AG8AYwBvAGwAIABUAEMAUAAgAC0AQQBjAHQAaQBvAG4AIABBAGwAbABvAHcACgBOAGUAdwAtAE4AZQB0AEYAaQByAGUAdwBhAGwAbABSAHUAbABlACAALQBEAGkAcwBwAGwAYQB5AE4AYQBtAGUAIAAiAFIARABQACAAMwAzADgAOQA5ACAAVQBEAFAAIgAgAC0ARABpAHIAZQBjAHQAaQBvAG4AIABJAG4AYgBvAHUAbgBkACAALQBMAG8AYwBhAGwAUABvAHIAdAAgADMAMwA4ADkAOQAgAC0AUAByAG8AdABvAGMAbwBsACAAVQBEAFAAIAAtAEEAYwB0AGkAbwBuACAAQQBsAGwAbwB3AAoAUgBlAHMAdABhAHIAdAAtAFMAZQByAHYAaQBjAGUAIAAtAE4AYQBtAGUAIABUAGUAcgBtAFMAZQByAHYAaQBjAGUAIAAtAEYAbwByAGMAZQA=' + } + } +} + +resource rtonpremvms 'Microsoft.Network/routeTables@2022-01-01' = { + name: 'wth-rt-onpremvmssubnet' + location: location + properties: { + routes: [] + disableBgpRoutePropagation: false + } +} + +resource nsgonpremvms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { + name: 'wth-nsg-onpremvmssubnet' + location: location + properties: { + securityRules: [ + { + name: 'allow-altrdp-to-vmssubnet-from-any' + properties: { + priority: 1000 + access: 'Allow' + direction: 'Inbound' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '33899-33899' + sourceAddressPrefix: '*' + destinationAddressPrefix: '10.1.10.0/24' + } + } + { + name: 'allow-altssh-to-vmssubnet-from-any' + properties: { + priority: 1001 + access: 'Allow' + direction: 'Inbound' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '22222-22222' + sourceAddressPrefix: '*' + destinationAddressPrefix: '10.1.10.0/24' + } + } + ] + } +} + +resource wthonpremcsrpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { + name: 'wth-pip-csr01' + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } +} + +resource wthonpremcsrnic 'Microsoft.Network/networkInterfaces@2022-01-01' = { + name: 'wth-nic-csr01' + location: location + properties: { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + subnet: { + id: '${wthonpremvnet.id}/subnets/subnet-vpn' + } + privateIPAddress: '172.16.0.4' + publicIPAddress: { + id: wthonpremvmpip01.id + } + } + } + ] + } +} + +resource ciscocsr 'Microsoft.Compute/virtualMachines@2022-03-01' = { + name: 'wth-vm-ciscocsr01' + location: location + properties: { + storageProfile: { + imageReference: { + publisher: 'cisco' + offer: 'cisco-csr-1000v' + sku: '16_12-byol' + version: 'latest' + } + osDisk: { + osType: 'Linux' + createOption: 'FromImage' + } + } + networkProfile: { + networkInterfaces: [ + { + id: wthonpremcsrnic.id + } + ] + } + osProfile: { + adminUsername: onpremVMUsername + adminPassword: onpremVMPassword + } + } +} From a7c635d5b4b20f010290973e076856a9281652b8 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Mon, 25 Jul 2022 16:06:26 -0600 Subject: [PATCH 14/76] csr pip --- 035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep index aff4ef9b82..13f29b95bd 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep @@ -195,7 +195,7 @@ resource wthonpremcsrnic 'Microsoft.Network/networkInterfaces@2022-01-01' = { } privateIPAddress: '172.16.0.4' publicIPAddress: { - id: wthonpremvmpip01.id + id: wthonpremcsrpip01.id } } } From 2f99d27a65ec3c308c92e5abceccc809fb957625 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Mon, 25 Jul 2022 16:07:20 -0600 Subject: [PATCH 15/76] csr --- 035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep | 3 +++ 1 file changed, 3 insertions(+) diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep index 13f29b95bd..5a2cbdb9a3 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep @@ -207,6 +207,9 @@ resource ciscocsr 'Microsoft.Compute/virtualMachines@2022-03-01' = { name: 'wth-vm-ciscocsr01' location: location properties: { + hardwareProfile: { + vmSize: 'Standard_B1s' + } storageProfile: { imageReference: { publisher: 'cisco' From 8b2ea69c2d88f596ee55eec6210f8670ca917066 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Mon, 25 Jul 2022 16:13:01 -0600 Subject: [PATCH 16/76] csr --- 035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep | 1 + 1 file changed, 1 insertion(+) diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep index 5a2cbdb9a3..8ba545700c 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep @@ -232,6 +232,7 @@ resource ciscocsr 'Microsoft.Compute/virtualMachines@2022-03-01' = { osProfile: { adminUsername: onpremVMUsername adminPassword: onpremVMPassword + computerName: 'csr' } } } From f89928b486277ee17491c07dbc0c3bd197d38893 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Mon, 25 Jul 2022 16:16:54 -0600 Subject: [PATCH 17/76] csr --- 035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep index 8ba545700c..8a8a0e1196 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep @@ -206,6 +206,11 @@ resource wthonpremcsrnic 'Microsoft.Network/networkInterfaces@2022-01-01' = { resource ciscocsr 'Microsoft.Compute/virtualMachines@2022-03-01' = { name: 'wth-vm-ciscocsr01' location: location + plan: { + publisher: 'cisco' + product: 'cisco-csr-1000v' + name: '16_12-byol' + } properties: { hardwareProfile: { vmSize: 'Standard_B1s' From 20d5db87e564bcd89a34c6b0a3d1d9ccb4d235c8 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Tue, 26 Jul 2022 10:23:24 -0600 Subject: [PATCH 18/76] deploy script --- .../Student/Resources/bicep/01-hub.bicep | 4 +- .../Student/Resources/bicep/01-onprem.bicep | 14 +-- ...ceGroups.bicep => 01-resourceGroups.bicep} | 0 .../Student/Resources/bicep/01-spoke1.bicep | 12 ++- .../Student/Resources/bicep/01-spoke2.bicep | 4 +- .../Resources/bicep/01-vnetpeeringhub.bicep | 2 +- .../Student/Resources/bicep/deployBicep.ps1 | 87 +++++++++++++++++++ 7 files changed, 109 insertions(+), 14 deletions(-) rename 035-HubAndSpoke/Student/Resources/bicep/{00-resourceGroups.bicep => 01-resourceGroups.bicep} (100%) create mode 100644 035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep index c08b36d08f..0be059d616 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep @@ -1,7 +1,7 @@ param location string = 'eastus2' param hubVMUsername string = 'admin-wth' @secure() -param hubVMPassword string +param vmPassword string targetScope = 'resourceGroup' //hub resources @@ -174,7 +174,7 @@ resource wthhubvm01 'Microsoft.Compute/virtualMachines@2022-03-01' = { osProfile: { computerName: 'vm-hub01' adminUsername: hubVMUsername - adminPassword: hubVMPassword + adminPassword: vmPassword windowsConfiguration: { provisionVMAgent: true enableAutomaticUpdates: true diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep index 8a8a0e1196..0a73d7f08e 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep @@ -1,7 +1,7 @@ param location string = 'eastus2' param onpremVMUsername string = 'admin-wth' @secure() -param onpremVMPassword string +param vmPassword string targetScope = 'resourceGroup' //onprem resources @@ -26,8 +26,12 @@ resource wthonpremvnet 'Microsoft.Network/virtualNetworks@2021-08-01' = { name: 'subnet-onpremvms' properties: { addressPrefix: '172.16.10.0/24' - networkSecurityGroup: {id: nsgonpremvms.id} - routeTable: { id: rtonpremvms.id } + networkSecurityGroup: { + id: nsgonpremvms.id + } + routeTable: { + id: rtonpremvms.id + } } } ] @@ -91,7 +95,7 @@ resource wthonpremvm01 'Microsoft.Compute/virtualMachines@2022-03-01' = { osProfile: { computerName: 'vm-onprem01' adminUsername: onpremVMUsername - adminPassword: onpremVMPassword + adminPassword: vmPassword windowsConfiguration: { provisionVMAgent: true enableAutomaticUpdates: true @@ -236,7 +240,7 @@ resource ciscocsr 'Microsoft.Compute/virtualMachines@2022-03-01' = { } osProfile: { adminUsername: onpremVMUsername - adminPassword: onpremVMPassword + adminPassword: vmPassword computerName: 'csr' } } diff --git a/035-HubAndSpoke/Student/Resources/bicep/00-resourceGroups.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-resourceGroups.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/00-resourceGroups.bicep rename to 035-HubAndSpoke/Student/Resources/bicep/01-resourceGroups.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep index 2a6e1508db..5b50254e97 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep @@ -1,7 +1,7 @@ param location string = 'eastus2' param spoke1VMUsername string = 'admin-wth' @secure() -param spoke1VMPassword string +param vmPassword string targetScope = 'resourceGroup' //spoke1 resources @@ -20,8 +20,12 @@ resource wthspoke1vnet 'Microsoft.Network/virtualNetworks@2021-08-01' = { name: 'subnet-spoke1vms' properties: { addressPrefix: '10.1.10.0/24' - networkSecurityGroup: {id: nsgspoke1vms.id} - routeTable: { id: rtspoke1vms.id } + networkSecurityGroup: { + id: nsgspoke1vms.id + } + routeTable: { + id: rtspoke1vms.id + } } } ] @@ -85,7 +89,7 @@ resource wthspoke1vm01 'Microsoft.Compute/virtualMachines@2022-03-01' = { osProfile: { computerName: 'vm-spoke101' adminUsername: spoke1VMUsername - adminPassword: spoke1VMPassword + adminPassword: vmPassword windowsConfiguration: { provisionVMAgent: true enableAutomaticUpdates: true diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep index 2368bab173..693cb98424 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep @@ -1,7 +1,7 @@ param location string = 'eastus2' param spoke2VMUsername string = 'admin-wth' @secure() -param spoke2VMPassword string +param vmPassword string targetScope = 'resourceGroup' //spoke2 resources @@ -83,7 +83,7 @@ resource wthspoke2vm01 'Microsoft.Compute/virtualMachines@2022-03-01' = { osProfile: { computerName: 'vm-spoke201' adminUsername: spoke2VMUsername - adminPassword: spoke2VMPassword + adminPassword: vmPassword windowsConfiguration: { provisionVMAgent: true enableAutomaticUpdates: true diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-vnetpeeringhub.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-vnetpeeringhub.bicep index 0f1e40932c..3593c540c7 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-vnetpeeringhub.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-vnetpeeringhub.bicep @@ -29,7 +29,7 @@ resource hubtospoke1 'Microsoft.Network/virtualNetworks/virtualNetworkPeerings@2 } resource hubtospoke2 'Microsoft.Network/virtualNetworks/virtualNetworkPeerings@2022-01-01' = { - name: '${hubvnet.name}/wth-peering-hubtospoke1' + name: '${hubvnet.name}/wth-peering-hubtospoke2' properties: { allowGatewayTransit: true allowForwardedTraffic: true diff --git a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 new file mode 100644 index 0000000000..ee12644384 --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 @@ -0,0 +1,87 @@ +<# +.SYNOPSIS +.DESCRIPTION + A longer description of the function, its purpose, common use cases, etc. +.NOTES + Information or caveats about the function e.g. 'This function is not supported in Linux' +.LINK + Specify a URI to a help page, this will show when Get-Help -Online is used. +.EXAMPLE + Test-MyTestFunction -Verbose + Explanation of the function or its result. You can include multiple examples with additional .EXAMPLE lines +#> +[CmdletBinding()] +param ( + # challenge number to deploy + [Parameter(Mandatory=$true, HelpMessage='Enter the WTH hub and spoke challenge number (1-6)')] + [ValidateRange(1,6)] + [int] + $challengeNumber, + + # deploy fully configured lab or leave some configuration to be done + [Parameter(Mandatory=$false, HelpMessage='Deploy all challenge resources fully configured or partially configured (for learning!)')] + [ValidateSet('FullyConfigured','PartiallyConfigured')] + [string] + $deploymentType = 'FullyConfigured', + + # resource deployment Azure region, defaults to 'eastus2' + [Parameter(Mandatory = $false)] + [string] + $location = 'EastUS2', + + # Parameter help description + [Parameter(Mandatory = $true)] + [SecureString] + $vmPassword +) + +If (-NOT (Test-Path ./01-resourceGroups.bicep)) { + $scriptPath = ($MyInvocation.MyCommand.Path | Split-Path -Parent) + Write-Warning "This script need to be executed from the directory containing the bicep files. Attempting to set location to '$scriptPath'" + + Push-Location -Path $scriptPath -ErrorAction Stop +} + +If ( -NOT ($azContext = Get-AzContext)) { + Write-Error "Run 'Connect-AzAccount' before executing this script!" +} +Else { + do { $response = (Read-Host "Resources will be created in subscription '$($azContext.Subscription.Name)'. Proceed? (y/n)") } + until ($response -match '[nNYy]') + + If ($response -match 'nN') { exit } +} + +switch ($challengeNumber) { + 1 { + Write-Host "Deploying resources for Challenge 1: Hub-and-spoke Basics" + + Write-Host "`tDeploying resource groups..." + New-AzDeployment -Location $location -TemplateFile ./01-resourceGroups.bicep + + Write-Host "`tDeploying base resources (this will take up to 60 minutes for the VNET Gateway)..." + $baseInfraJobs = @() + $baseInfraJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./01-spoke1.bicep -TemplateParameterObject @{vmPassword = $vmPassword} -AsJob + $baseInfraJobs +=New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./01-spoke2.bicep -TemplateParameterObject @{vmPassword = $vmPassword} -AsJob + $baseInfraJobs +=New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./01-hub.bicep -TemplateParameterObject @{vmPassword = $vmPassword} -AsJob + $baseInfraJobs +=New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-onprem' -TemplateFile ./01-onprem.bicep -TemplateParameterObject @{vmPassword = $vmPassword} -AsJob + + Write-Host "`tWaiting up to 60 minutes for resources to deploy..." + $baseInfraJobs | Wait-Job -Timeout 3600 + + Write-Host "`tDeploying VNET Peering..." + $peeringJobs = @() + $peeringJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./01-vnetpeeringhub.bicep -AsJob + $peeringJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./01-vnetpeeringspoke1.bicep -AsJob + $peeringJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./01-vnetpeeringspoke2.bicep -AsJob + + $peeringJobs | Wait-Job -Timeout 300 + } + 2 {} + 3 {} + 4 {} + 5 {} + 6 {} +} + +Pop-Location \ No newline at end of file From 5b02eeb01c375eda764081ce8c7719b87a0638e3 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Tue, 26 Jul 2022 11:07:40 -0600 Subject: [PATCH 19/76] deployment tested --- .../Student/Resources/bicep/01-onprem.bicep | 6 +++--- .../Student/Resources/bicep/01-vnetpeeringhub.bicep | 2 -- .../Student/Resources/bicep/deployBicep.ps1 | 10 ++++++++-- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep index 0a73d7f08e..6acf0346b8 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep @@ -154,7 +154,7 @@ resource nsgonpremvms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { sourcePortRange: '*' destinationPortRange: '33899-33899' sourceAddressPrefix: '*' - destinationAddressPrefix: '10.1.10.0/24' + destinationAddressPrefix: '172.16.10.0/24' } } { @@ -167,7 +167,7 @@ resource nsgonpremvms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { sourcePortRange: '*' destinationPortRange: '22222-22222' sourceAddressPrefix: '*' - destinationAddressPrefix: '10.1.10.0/24' + destinationAddressPrefix: '172.16.10.0/24' } } ] @@ -217,7 +217,7 @@ resource ciscocsr 'Microsoft.Compute/virtualMachines@2022-03-01' = { } properties: { hardwareProfile: { - vmSize: 'Standard_B1s' + vmSize: 'Standard_B2ms' } storageProfile: { imageReference: { diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-vnetpeeringhub.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-vnetpeeringhub.bicep index 3593c540c7..cc274cc671 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-vnetpeeringhub.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-vnetpeeringhub.bicep @@ -1,5 +1,3 @@ -param location string = 'eastus2' - resource hubvnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { name: 'wth-vnet-hub01' scope: resourceGroup('wth-rg-hub') diff --git a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 index ee12644384..724a6933ee 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 +++ b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 @@ -36,10 +36,16 @@ param ( ) If (-NOT (Test-Path ./01-resourceGroups.bicep)) { - $scriptPath = ($MyInvocation.MyCommand.Path | Split-Path -Parent) - Write-Warning "This script need to be executed from the directory containing the bicep files. Attempting to set location to '$scriptPath'" + Write-Warning "This script need to be executed from the directory containing the bicep files. Attempting to set location to script location." + + try { + $scriptPath = ($MyInvocation.MyCommand.Path | Split-Path -Parent -ErrorAction Stop) Push-Location -Path $scriptPath -ErrorAction Stop + } + catch { + Write-Error "Failed to set path to bicep file location. Use the 'cd' command to change the current directory to the same location as the WTH bicep files before executing this script." + } } If ( -NOT ($azContext = Get-AzContext)) { From 90b5b10fc63fedd24096e69a6714dca69ec80a2d Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Thu, 28 Jul 2022 09:08:39 -0600 Subject: [PATCH 20/76] wip: csr config --- .../Resources/bicep/01-csrconfig.bicep | 117 ++++++++++++++++++ .../Student/Resources/bicep/01-hub.bicep | 8 ++ .../Resources/bicep/01-hubvpnconfig.bicep | 50 ++++++++ .../Student/Resources/bicep/01-onprem.bicep | 3 +- .../Student/Resources/bicep/csrScript.txt | 79 ++++++++++++ .../Student/Resources/bicep/csrScript.txt.tpm | 79 ++++++++++++ .../Student/Resources/bicep/deployBicep.ps1 | 57 +++++++-- 7 files changed, 380 insertions(+), 13 deletions(-) create mode 100644 035-HubAndSpoke/Student/Resources/bicep/01-csrconfig.bicep create mode 100644 035-HubAndSpoke/Student/Resources/bicep/01-hubvpnconfig.bicep create mode 100644 035-HubAndSpoke/Student/Resources/bicep/csrScript.txt create mode 100644 035-HubAndSpoke/Student/Resources/bicep/csrScript.txt.tpm diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-csrconfig.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-csrconfig.bicep new file mode 100644 index 0000000000..03ed9bc95f --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/01-csrconfig.bicep @@ -0,0 +1,117 @@ +param location string = 'eastus2' + +resource wthcsrvm 'Microsoft.Compute/virtualMachines@2022-03-01' existing = { + name: 'wth-vm-ciscocsr01' + scope: resourceGroup('wth-rg-onprem') +} + +resource wthcsrnic 'Microsoft.Network/networkInterfaces@2022-01-01' existing = { + name: 'wth-nic-csr01' + scope: resourceGroup('wth-rg-onprem') +} + +resource wthhubgwpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' existing = { + name: 'wth-pip-gw01' + scope: resourceGroup('wth-rg-hub') +} + +resource wthhubgwpip02 'Microsoft.Network/publicIPAddresses@2022-01-01' existing = { + name: 'wth-pip-gw02' + scope: resourceGroup('wth-rg-hub') +} + +var csrScript = ''' +config t + +crypto ikev2 proposal azure-proposal + encryption aes-cbc-256 aes-cbc-128 3des + integrity sha1 + group 2 + exit +! +crypto ikev2 policy azure-policy + proposal azure-proposal + exit +! +crypto ikev2 keyring azure-keyring + peer **GW0_Public_IP** + address **GW0_Public_IP** + pre-shared-key **PSK** + exit + peer **GW1_Public_IP** + address **GW1_Public_IP** + pre-shared-key **PSK** + exit + exit +! +crypto ikev2 profile azure-profile + match address local interface GigabitEthernet1 + match identity remote address **GW0_Public_IP** 255.255.255.255 + match identity remote address **GW1_Public_IP** 255.255.255.255 + authentication remote pre-share + authentication local pre-share + keyring local azure-keyring + exit +! +crypto ipsec transform-set azure-ipsec-proposal-set esp-aes 256 esp-sha-hmac + mode tunnel + exit + +crypto ipsec profile azure-vti + set transform-set azure-ipsec-proposal-set + set ikev2-profile azure-profile + set security-association lifetime kilobytes 102400000 + set security-association lifetime seconds 3600 + exit +! +interface Tunnel0 + ip unnumbered GigabitEthernet1 + ip tcp adjust-mss 1350 + tunnel source GigabitEthernet1 + tunnel mode ipsec ipv4 + tunnel destination **GW0_Public_IP** + tunnel protection ipsec profile azure-vti +exit +! +interface Tunnel1 + ip unnumbered GigabitEthernet1 + ip tcp adjust-mss 1350 + tunnel source GigabitEthernet1 + tunnel mode ipsec ipv4 + tunnel destination **GW1_Public_IP** + tunnel protection ipsec profile azure-vti +exit + +! +router bgp **BGP_ID** + bgp router-id interface GigabitEthernet1 + bgp log-neighbor-changes + redistribute connected + neighbor **GW0_Private_IP** remote-as 65515 + neighbor **GW0_Private_IP** ebgp-multihop 5 + neighbor **GW0_Private_IP** update-source GigabitEthernet1 + neighbor **GW1_Private_IP** remote-as 65515 + neighbor **GW1_Private_IP** ebgp-multihop 5 + neighbor **GW1_Private_IP** update-source GigabitEthernet1 + maximum-paths eibgp 4 +! +ip route **GW0_Private_IP** 255.255.255.255 Tunnel0 +ip route **GW1_Private_IP** 255.255.255.255 Tunnel1 +! +end +! +wr mem +''' + +resource configcsr 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' = { + name: '${wthcsrvm.name}/wth-vmextn-changerdpport33899' + location: location + properties: { + publisher: 'Microsoft.Compute' + type: 'CustomScriptExtension' + typeHandlerVersion: '1.10' + settings: { + commandToExecute: 'ssh -o BatchMode=yes -o StrictHostKeyChecking=no admin-wth@' + } + } +} diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep index 0be059d616..63891c2946 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep @@ -53,6 +53,8 @@ resource wthhubgwpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { } } +output pipgw1 string = wthhubgwpip01.properties.ipAddress + resource wthhubgwpip02 'Microsoft.Network/publicIPAddresses@2022-01-01' = { name: 'wth-pip-gw02' location: location @@ -65,6 +67,8 @@ resource wthhubgwpip02 'Microsoft.Network/publicIPAddresses@2022-01-01' = { } } +output pipgw2 string = wthhubgwpip02.properties.ipAddress + resource wthhubvnetgw 'Microsoft.Network/virtualNetworkGateways@2022-01-01' = { name: 'wth-vngw-hub01' location: location @@ -108,6 +112,10 @@ resource wthhubvnetgw 'Microsoft.Network/virtualNetworkGateways@2022-01-01' = { } } +output wthhubvnetgwasn int = wthhubvnetgw.properties.bgpSettings.asn +output wthhubvnetgwprivateip1 string = wthhubvnetgw.properties.bgpSettings.bgpPeeringAddresses[0].defaultBgpIpAddresses[0] +output wthhubvnetgwprivateip2 string = wthhubvnetgw.properties.bgpSettings.bgpPeeringAddresses[1].defaultBgpIpAddresses[0] + resource changerdpport 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' = { name: '${wthhubvm01.name}/wth-vmextn-changerdpport33899' location: location diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-hubvpnconfig.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-hubvpnconfig.bicep new file mode 100644 index 0000000000..0a73045c3e --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/01-hubvpnconfig.bicep @@ -0,0 +1,50 @@ +param location string = 'eastus2' + +resource onpremcsrpip 'Microsoft.Network/publicIPAddresses@2022-01-01' existing = { + name: 'wth-pip-csr01' + scope: resourceGroup('wth-rg-onprem') +} + +resource onpremcsrnic 'Microsoft.Network/networkInterfaces@2022-01-01' existing = { + name: 'wth-nic-csr01' + scope: resourceGroup('wth-rg-onprem') +} + +resource wthhubvnetgw 'Microsoft.Network/virtualNetworkGateways@2022-01-01' existing = { + name: 'wth-vngw-hub01' + scope: resourceGroup('wth-rg-hub') +} + +resource wthhublocalgw 'Microsoft.Network/localNetworkGateways@2022-01-01' = { + name: 'wth-lgw-onprem01' + location: location + properties: { + gatewayIpAddress: onpremcsrpip.properties.ipAddress + localNetworkAddressSpace: { + addressPrefixes: [ + '172.16.0.0/16' + ] + } + bgpSettings: { + bgpPeeringAddress: onpremcsrnic.properties.ipConfigurations[0].properties.privateIPAddress + asn: 65510 + } + } +} + +resource wthhubconnection 'Microsoft.Network/connections@2022-01-01' = { + name: 'wth-cxn-vpn01' + location: location + properties: { + authorizationKey: '123mysecretkey' + connectionType: 'IPsec' + connectionMode: 'Default' + enableBgp: true + localNetworkGateway2: { + id: wthhublocalgw.id + } + virtualNetworkGateway1: { + id: wthhubvnetgw.id + } + } +} diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep index 6acf0346b8..6871a3b638 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep @@ -241,7 +241,8 @@ resource ciscocsr 'Microsoft.Compute/virtualMachines@2022-03-01' = { osProfile: { adminUsername: onpremVMUsername adminPassword: vmPassword - computerName: 'csr' + computerName: 'wthcsr01' + customData: loadFileAsBase64('./csrScript.txt.tmp') } } } diff --git a/035-HubAndSpoke/Student/Resources/bicep/csrScript.txt b/035-HubAndSpoke/Student/Resources/bicep/csrScript.txt new file mode 100644 index 0000000000..79ac06751d --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/csrScript.txt @@ -0,0 +1,79 @@ +Section: IOS configuration +crypto ikev2 proposal azure-proposal + encryption aes-cbc-256 aes-cbc-128 3des + integrity sha1 + group 2 + exit +! +crypto ikev2 policy azure-policy + proposal azure-proposal + exit +! +crypto ikev2 keyring azure-keyring + peer **GW0_Public_IP** + address **GW0_Public_IP** + pre-shared-key 123mysecretkey + exit + peer **GW1_Public_IP** + address **GW1_Public_IP** + pre-shared-key 123mysecretkey + exit + exit +! +crypto ikev2 profile azure-profile + match address local interface GigabitEthernet1 + match identity remote address **GW0_Public_IP** 255.255.255.255 + match identity remote address **GW1_Public_IP** 255.255.255.255 + authentication remote pre-share + authentication local pre-share + keyring local azure-keyring + exit +! +crypto ipsec transform-set azure-ipsec-proposal-set esp-aes 256 esp-sha-hmac + mode tunnel + exit + +crypto ipsec profile azure-vti + set transform-set azure-ipsec-proposal-set + set ikev2-profile azure-profile + set security-association lifetime kilobytes 102400000 + set security-association lifetime seconds 3600 + exit +! +interface Tunnel0 + ip unnumbered GigabitEthernet1 + ip tcp adjust-mss 1350 + tunnel source GigabitEthernet1 + tunnel mode ipsec ipv4 + tunnel destination **GW0_Public_IP** + tunnel protection ipsec profile azure-vti +exit +! +interface Tunnel1 + ip unnumbered GigabitEthernet1 + ip tcp adjust-mss 1350 + tunnel source GigabitEthernet1 + tunnel mode ipsec ipv4 + tunnel destination **GW1_Public_IP** + tunnel protection ipsec profile azure-vti +exit + +! +router bgp **BGP_ID** + bgp router-id interface GigabitEthernet1 + bgp log-neighbor-changes + redistribute connected + neighbor **GW0_Private_IP** remote-as 65515 + neighbor **GW0_Private_IP** ebgp-multihop 5 + neighbor **GW0_Private_IP** update-source GigabitEthernet1 + neighbor **GW1_Private_IP** remote-as 65515 + neighbor **GW1_Private_IP** ebgp-multihop 5 + neighbor **GW1_Private_IP** update-source GigabitEthernet1 + maximum-paths eibgp 4 +! +ip route **GW0_Private_IP** 255.255.255.255 Tunnel0 +ip route **GW1_Private_IP** 255.255.255.255 Tunnel1 +! +end +! +wr mem diff --git a/035-HubAndSpoke/Student/Resources/bicep/csrScript.txt.tpm b/035-HubAndSpoke/Student/Resources/bicep/csrScript.txt.tpm new file mode 100644 index 0000000000..b530d4c00a --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/csrScript.txt.tpm @@ -0,0 +1,79 @@ +Section: IOS configuration +crypto ikev2 proposal azure-proposal + encryption aes-cbc-256 aes-cbc-128 3des + integrity sha1 + group 2 + exit +! +crypto ikev2 policy azure-policy + proposal azure-proposal + exit +! +crypto ikev2 keyring azure-keyring + peer 20.230.112.137 + address 20.230.112.137 + pre-shared-key 123mysecretkey + exit + peer 20.230.118.170 + address 20.230.118.170 + pre-shared-key 123mysecretkey + exit + exit +! +crypto ikev2 profile azure-profile + match address local interface GigabitEthernet1 + match identity remote address 20.230.112.137 255.255.255.255 + match identity remote address 20.230.118.170 255.255.255.255 + authentication remote pre-share + authentication local pre-share + keyring local azure-keyring + exit +! +crypto ipsec transform-set azure-ipsec-proposal-set esp-aes 256 esp-sha-hmac + mode tunnel + exit + +crypto ipsec profile azure-vti + set transform-set azure-ipsec-proposal-set + set ikev2-profile azure-profile + set security-association lifetime kilobytes 102400000 + set security-association lifetime seconds 3600 + exit +! +interface Tunnel0 + ip unnumbered GigabitEthernet1 + ip tcp adjust-mss 1350 + tunnel source GigabitEthernet1 + tunnel mode ipsec ipv4 + tunnel destination 20.230.112.137 + tunnel protection ipsec profile azure-vti +exit +! +interface Tunnel1 + ip unnumbered GigabitEthernet1 + ip tcp adjust-mss 1350 + tunnel source GigabitEthernet1 + tunnel mode ipsec ipv4 + tunnel destination 20.230.118.170 + tunnel protection ipsec profile azure-vti +exit + +! +router bgp **BGP_ID** + bgp router-id interface GigabitEthernet1 + bgp log-neighbor-changes + redistribute connected + neighbor 10.0.0.5 remote-as 65515 + neighbor 10.0.0.5 ebgp-multihop 5 + neighbor 10.0.0.5 update-source GigabitEthernet1 + neighbor 10.0.0.4 remote-as 65515 + neighbor 10.0.0.4 ebgp-multihop 5 + neighbor 10.0.0.4 update-source GigabitEthernet1 + maximum-paths eibgp 4 +! +ip route 10.0.0.5 255.255.255.255 Tunnel0 +ip route 10.0.0.4 255.255.255.255 Tunnel1 +! +end +! +wr mem diff --git a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 index 724a6933ee..1567960342 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 +++ b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 @@ -13,14 +13,14 @@ [CmdletBinding()] param ( # challenge number to deploy - [Parameter(Mandatory=$true, HelpMessage='Enter the WTH hub and spoke challenge number (1-6)')] - [ValidateRange(1,6)] + [Parameter(Mandatory = $true, HelpMessage = 'Enter the WTH hub and spoke challenge number (1-6)')] + [ValidateRange(1, 6)] [int] $challengeNumber, # deploy fully configured lab or leave some configuration to be done - [Parameter(Mandatory=$false, HelpMessage='Deploy all challenge resources fully configured or partially configured (for learning!)')] - [ValidateSet('FullyConfigured','PartiallyConfigured')] + [Parameter(Mandatory = $false, HelpMessage = 'Deploy all challenge resources fully configured or partially configured (for learning!)')] + [ValidateSet('FullyConfigured', 'PartiallyConfigured')] [string] $deploymentType = 'FullyConfigured', @@ -35,13 +35,15 @@ param ( $vmPassword ) +$ErrorActionPreference = 'Stop' + If (-NOT (Test-Path ./01-resourceGroups.bicep)) { Write-Warning "This script need to be executed from the directory containing the bicep files. Attempting to set location to script location." try { - $scriptPath = ($MyInvocation.MyCommand.Path | Split-Path -Parent -ErrorAction Stop) - Push-Location -Path $scriptPath -ErrorAction Stop + $scriptPath = ($MyInvocation.MyCommand.Path | Split-Path -Parent -ErrorAction Stop) + Push-Location -Path $scriptPath -ErrorAction Stop } catch { Write-Error "Failed to set path to bicep file location. Use the 'cd' command to change the current directory to the same location as the WTH bicep files before executing this script." @@ -66,14 +68,19 @@ switch ($challengeNumber) { New-AzDeployment -Location $location -TemplateFile ./01-resourceGroups.bicep Write-Host "`tDeploying base resources (this will take up to 60 minutes for the VNET Gateway)..." - $baseInfraJobs = @() - $baseInfraJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./01-spoke1.bicep -TemplateParameterObject @{vmPassword = $vmPassword} -AsJob - $baseInfraJobs +=New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./01-spoke2.bicep -TemplateParameterObject @{vmPassword = $vmPassword} -AsJob - $baseInfraJobs +=New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./01-hub.bicep -TemplateParameterObject @{vmPassword = $vmPassword} -AsJob - $baseInfraJobs +=New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-onprem' -TemplateFile ./01-onprem.bicep -TemplateParameterObject @{vmPassword = $vmPassword} -AsJob + $baseInfraJobs = @{} + $baseInfraJobs += @{'wth-rg-spoke1' = (New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./01-spoke1.bicep -TemplateParameterObject @{vmPassword = $vmPassword } -AsJob)} + $baseInfraJobs += @{'wth-rg-spoke2' = (New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./01-spoke2.bicep -TemplateParameterObject @{vmPassword = $vmPassword } -AsJob)} + $baseInfraJobs += @{'wth-rg-hub' = (New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./01-hub.bicep -TemplateParameterObject @{vmPassword = $vmPassword } -AsJob)} Write-Host "`tWaiting up to 60 minutes for resources to deploy..." - $baseInfraJobs | Wait-Job -Timeout 3600 + $baseInfraJobs.GetEnumerator().ForEach({$_.Value}) | Wait-Job -Timeout 3600 + + $gw1pip = $baseInfraJobs.'wth-rg-hub'.Output.Outputs.pipgw1.Value + $gw2pip = $baseInfraJobs.'wth-rg-hub'.Output.Outputs.pipgw2.Value + $gwasn = $baseInfraJobs.'wth-rg-hub'.Output.Outputs.wthhubvnetgwasn.Value + $gw1privateip = $baseInfraJobs.'wth-rg-hub'.Output.Outputs.wthhubvnetgwprivateip1.Value + $gw2privateip = $baseInfraJobs.'wth-rg-hub'.Output.Outputs.wthhubvnetgwprivateip2.Value Write-Host "`tDeploying VNET Peering..." $peeringJobs = @() @@ -82,6 +89,32 @@ switch ($challengeNumber) { $peeringJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./01-vnetpeeringspoke2.bicep -AsJob $peeringJobs | Wait-Job -Timeout 300 + + Write-Host "Deploying 'onprem' infra" + + #update csr bootstrap file + $csrConfigContent = Get-Content -Path .\csrScript.txt + $updatedCsrConfigContent = $csrConfigContent + $updatedCsrConfigContent = $updatedCsrConfigContent.Replace('**GW0_Public_IP**',$gw1pip) + $updatedCsrConfigContent = $updatedCsrConfigContent.Replace('**GW1_Public_IP**',$gw2pip) + $updatedCsrConfigContent = $updatedCsrConfigContent.Replace('**BGP_ID**',$gwasn) + $updatedCsrConfigContent = $updatedCsrConfigContent.Replace('**GW0_Private_IP**',$gw1privateip) + $updatedCsrConfigContent = $updatedCsrConfigContent.Replace('**GW1_Private_IP**',$gw2privateip) + + Set-Content -Path .\csrScript.txt.tmp -Value $updatedCsrConfigContent -Force + + #deploy resources + $onPremJob = New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-onprem' -TemplateFile ./01-onprem.bicep -TemplateParameterObject @{vmPassword = $vmPassword } -AsJob + + $onPremJob | Wait-Job + + Write-Host "`tConfiguring VPN resources..." + + $vpnJobs = @() + $vpnJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./01-hubvpnconfig.bicep -AsJob + #$vpnJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-onprem' -TemplateFile ./01-csrconfig.bicep -AsJob + + $vpnJobs | Wait-Job -Timeout 600 } 2 {} 3 {} From c2ec3fbcfc4d18562f4e51c9df9846b3e53c4b32 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Thu, 28 Jul 2022 09:55:40 -0600 Subject: [PATCH 21/76] cxn sharedkey property --- .../Student/Resources/bicep/01-hubvpnconfig.bicep | 2 +- 035-HubAndSpoke/Student/Resources/bicep/csrScript.txt | 6 +++--- 035-HubAndSpoke/Student/Resources/bicep/csrScript.txt.tpm | 2 +- 035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-hubvpnconfig.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-hubvpnconfig.bicep index 0a73045c3e..dbc432e901 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-hubvpnconfig.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-hubvpnconfig.bicep @@ -36,7 +36,7 @@ resource wthhubconnection 'Microsoft.Network/connections@2022-01-01' = { name: 'wth-cxn-vpn01' location: location properties: { - authorizationKey: '123mysecretkey' + sharedKey: '123mysecretkey' connectionType: 'IPsec' connectionMode: 'Default' enableBgp: true diff --git a/035-HubAndSpoke/Student/Resources/bicep/csrScript.txt b/035-HubAndSpoke/Student/Resources/bicep/csrScript.txt index 79ac06751d..be46f27552 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/csrScript.txt +++ b/035-HubAndSpoke/Student/Resources/bicep/csrScript.txt @@ -59,14 +59,14 @@ interface Tunnel1 exit ! -router bgp **BGP_ID** +router bgp 65510 bgp router-id interface GigabitEthernet1 bgp log-neighbor-changes redistribute connected - neighbor **GW0_Private_IP** remote-as 65515 + neighbor **GW0_Private_IP** remote-as **VNETGWASN** neighbor **GW0_Private_IP** ebgp-multihop 5 neighbor **GW0_Private_IP** update-source GigabitEthernet1 - neighbor **GW1_Private_IP** remote-as 65515 + neighbor **GW1_Private_IP** remote-as **VNETGWASN** neighbor **GW1_Private_IP** ebgp-multihop 5 neighbor **GW1_Private_IP** update-source GigabitEthernet1 maximum-paths eibgp 4 diff --git a/035-HubAndSpoke/Student/Resources/bicep/csrScript.txt.tpm b/035-HubAndSpoke/Student/Resources/bicep/csrScript.txt.tpm index b530d4c00a..c993025e25 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/csrScript.txt.tpm +++ b/035-HubAndSpoke/Student/Resources/bicep/csrScript.txt.tpm @@ -59,7 +59,7 @@ interface Tunnel1 exit ! -router bgp **BGP_ID** +router bgp 65510 bgp router-id interface GigabitEthernet1 bgp log-neighbor-changes redistribute connected diff --git a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 index 1567960342..b2c5f1a2dc 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 +++ b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 @@ -97,7 +97,7 @@ switch ($challengeNumber) { $updatedCsrConfigContent = $csrConfigContent $updatedCsrConfigContent = $updatedCsrConfigContent.Replace('**GW0_Public_IP**',$gw1pip) $updatedCsrConfigContent = $updatedCsrConfigContent.Replace('**GW1_Public_IP**',$gw2pip) - $updatedCsrConfigContent = $updatedCsrConfigContent.Replace('**BGP_ID**',$gwasn) + $updatedCsrConfigContent = $updatedCsrConfigContent.Replace('**VNETGWASN**',$gwasn) $updatedCsrConfigContent = $updatedCsrConfigContent.Replace('**GW0_Private_IP**',$gw1privateip) $updatedCsrConfigContent = $updatedCsrConfigContent.Replace('**GW1_Private_IP**',$gw2privateip) From ea641e63c2a2e6229196778c5e4fabe0d5be368d Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Thu, 28 Jul 2022 10:03:11 -0600 Subject: [PATCH 22/76] allow ping --- 035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep | 4 +++- 035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep | 2 +- 035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep | 2 +- .../Student/Resources/bicep/windowsRDPFirewallScript.txt | 8 ++++++++ 4 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 035-HubAndSpoke/Student/Resources/bicep/windowsRDPFirewallScript.txt diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep index 63891c2946..212b9cd0ef 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep @@ -132,10 +132,12 @@ resource changerdpport 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' New-NetFirewallRule -DisplayName "RDP 33899 TCP" -Direction Inbound -LocalPort 33899 -Protocol TCP -Action Allow New-NetFirewallRule -DisplayName "RDP 33899 UDP" -Direction Inbound -LocalPort 33899 -Protocol UDP -Action Allow Restart-Service -Name TermService -Force + + New-NetFirewallRule -DisplayName 'ICMPv4' -Direction Inbound -Action Allow -Protocol icmpv4 -Enabled True '@ $bytes = [System.Text.Encoding]::Unicode.GetBytes($s) [convert]::ToBase64String($bytes) */ - commandToExecute: 'powershell.exe -ep bypass -encodedcommand UwBlAHQALQBJAHQAZQBtAFAAcgBvAHAAZQByAHQAeQAgAC0AUABhAHQAaAAgACIASABLAEwATQA6AFwAUwB5AHMAdABlAG0AXABDAHUAcgByAGUAbgB0AEMAbwBuAHQAcgBvAGwAUwBlAHQAXABDAG8AbgB0AHIAbwBsAFwAVABlAHIAbQBpAG4AYQBsACAAUwBlAHIAdgBlAHIAXABXAGkAbgBTAHQAYQB0AGkAbwBuAHMAXABSAEQAUAAtAFQAYwBwAFwAIgAgAC0ATgBhAG0AZQAgAFAAbwByAHQATgB1AG0AYgBlAHIAIAAtAFYAYQBsAHUAZQAgADMAMwA4ADkAOQAKAE4AZQB3AC0ATgBlAHQARgBpAHIAZQB3AGEAbABsAFIAdQBsAGUAIAAtAEQAaQBzAHAAbABhAHkATgBhAG0AZQAgACIAUgBEAFAAIAAzADMAOAA5ADkAIABUAEMAUAAiACAALQBEAGkAcgBlAGMAdABpAG8AbgAgAEkAbgBiAG8AdQBuAGQAIAAtAEwAbwBjAGEAbABQAG8AcgB0ACAAMwAzADgAOQA5ACAALQBQAHIAbwB0AG8AYwBvAGwAIABUAEMAUAAgAC0AQQBjAHQAaQBvAG4AIABBAGwAbABvAHcACgBOAGUAdwAtAE4AZQB0AEYAaQByAGUAdwBhAGwAbABSAHUAbABlACAALQBEAGkAcwBwAGwAYQB5AE4AYQBtAGUAIAAiAFIARABQACAAMwAzADgAOQA5ACAAVQBEAFAAIgAgAC0ARABpAHIAZQBjAHQAaQBvAG4AIABJAG4AYgBvAHUAbgBkACAALQBMAG8AYwBhAGwAUABvAHIAdAAgADMAMwA4ADkAOQAgAC0AUAByAG8AdABvAGMAbwBsACAAVQBEAFAAIAAtAEEAYwB0AGkAbwBuACAAQQBsAGwAbwB3AAoAUgBlAHMAdABhAHIAdAAtAFMAZQByAHYAaQBjAGUAIAAtAE4AYQBtAGUAIABUAGUAcgBtAFMAZQByAHYAaQBjAGUAIAAtAEYAbwByAGMAZQA=' + commandToExecute: 'powershell.exe -ep bypass -encodedcommand UwBlAHQALQBJAHQAZQBtAFAAcgBvAHAAZQByAHQAeQAgAC0AUABhAHQAaAAgACIASABLAEwATQA6AFwAUwB5AHMAdABlAG0AXABDAHUAcgByAGUAbgB0AEMAbwBuAHQAcgBvAGwAUwBlAHQAXABDAG8AbgB0AHIAbwBsAFwAVABlAHIAbQBpAG4AYQBsACAAUwBlAHIAdgBlAHIAXABXAGkAbgBTAHQAYQB0AGkAbwBuAHMAXABSAEQAUAAtAFQAYwBwAFwAIgAgAC0ATgBhAG0AZQAgAFAAbwByAHQATgB1AG0AYgBlAHIAIAAtAFYAYQBsAHUAZQAgADMAMwA4ADkAOQANAAoATgBlAHcALQBOAGUAdABGAGkAcgBlAHcAYQBsAGwAUgB1AGwAZQAgAC0ARABpAHMAcABsAGEAeQBOAGEAbQBlACAAIgBSAEQAUAAgADMAMwA4ADkAOQAgAFQAQwBQACIAIAAtAEQAaQByAGUAYwB0AGkAbwBuACAASQBuAGIAbwB1AG4AZAAgAC0ATABvAGMAYQBsAFAAbwByAHQAIAAzADMAOAA5ADkAIAAtAFAAcgBvAHQAbwBjAG8AbAAgAFQAQwBQACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwANAAoATgBlAHcALQBOAGUAdABGAGkAcgBlAHcAYQBsAGwAUgB1AGwAZQAgAC0ARABpAHMAcABsAGEAeQBOAGEAbQBlACAAIgBSAEQAUAAgADMAMwA4ADkAOQAgAFUARABQACIAIAAtAEQAaQByAGUAYwB0AGkAbwBuACAASQBuAGIAbwB1AG4AZAAgAC0ATABvAGMAYQBsAFAAbwByAHQAIAAzADMAOAA5ADkAIAAtAFAAcgBvAHQAbwBjAG8AbAAgAFUARABQACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwANAAoAUgBlAHMAdABhAHIAdAAtAFMAZQByAHYAaQBjAGUAIAAtAE4AYQBtAGUAIABUAGUAcgBtAFMAZQByAHYAaQBjAGUAIAAtAEYAbwByAGMAZQANAAoADQAKAE4AZQB3AC0ATgBlAHQARgBpAHIAZQB3AGEAbABsAFIAdQBsAGUAIAAtAEQAaQBzAHAAbABhAHkATgBhAG0AZQAgACcASQBDAE0AUAB2ADQAJwAgAC0ARABpAHIAZQBjAHQAaQBvAG4AIABJAG4AYgBvAHUAbgBkACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwAgAC0AUAByAG8AdABvAGMAbwBsACAAaQBjAG0AcAB2ADQAIAAtAEUAbgBhAGIAbABlAGQAIABUAHIAdQBlAA==' } } } diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep index 6871a3b638..80e45b7878 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep @@ -125,7 +125,7 @@ resource changerdpport 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' type: 'CustomScriptExtension' typeHandlerVersion: '1.10' settings: { - commandToExecute: 'powershell.exe -ep bypass -encodedcommand UwBlAHQALQBJAHQAZQBtAFAAcgBvAHAAZQByAHQAeQAgAC0AUABhAHQAaAAgACIASABLAEwATQA6AFwAUwB5AHMAdABlAG0AXABDAHUAcgByAGUAbgB0AEMAbwBuAHQAcgBvAGwAUwBlAHQAXABDAG8AbgB0AHIAbwBsAFwAVABlAHIAbQBpAG4AYQBsACAAUwBlAHIAdgBlAHIAXABXAGkAbgBTAHQAYQB0AGkAbwBuAHMAXABSAEQAUAAtAFQAYwBwAFwAIgAgAC0ATgBhAG0AZQAgAFAAbwByAHQATgB1AG0AYgBlAHIAIAAtAFYAYQBsAHUAZQAgADMAMwA4ADkAOQAKAE4AZQB3AC0ATgBlAHQARgBpAHIAZQB3AGEAbABsAFIAdQBsAGUAIAAtAEQAaQBzAHAAbABhAHkATgBhAG0AZQAgACIAUgBEAFAAIAAzADMAOAA5ADkAIABUAEMAUAAiACAALQBEAGkAcgBlAGMAdABpAG8AbgAgAEkAbgBiAG8AdQBuAGQAIAAtAEwAbwBjAGEAbABQAG8AcgB0ACAAMwAzADgAOQA5ACAALQBQAHIAbwB0AG8AYwBvAGwAIABUAEMAUAAgAC0AQQBjAHQAaQBvAG4AIABBAGwAbABvAHcACgBOAGUAdwAtAE4AZQB0AEYAaQByAGUAdwBhAGwAbABSAHUAbABlACAALQBEAGkAcwBwAGwAYQB5AE4AYQBtAGUAIAAiAFIARABQACAAMwAzADgAOQA5ACAAVQBEAFAAIgAgAC0ARABpAHIAZQBjAHQAaQBvAG4AIABJAG4AYgBvAHUAbgBkACAALQBMAG8AYwBhAGwAUABvAHIAdAAgADMAMwA4ADkAOQAgAC0AUAByAG8AdABvAGMAbwBsACAAVQBEAFAAIAAtAEEAYwB0AGkAbwBuACAAQQBsAGwAbwB3AAoAUgBlAHMAdABhAHIAdAAtAFMAZQByAHYAaQBjAGUAIAAtAE4AYQBtAGUAIABUAGUAcgBtAFMAZQByAHYAaQBjAGUAIAAtAEYAbwByAGMAZQA=' + commandToExecute: 'powershell.exe -ep bypass -encodedcommand UwBlAHQALQBJAHQAZQBtAFAAcgBvAHAAZQByAHQAeQAgAC0AUABhAHQAaAAgACIASABLAEwATQA6AFwAUwB5AHMAdABlAG0AXABDAHUAcgByAGUAbgB0AEMAbwBuAHQAcgBvAGwAUwBlAHQAXABDAG8AbgB0AHIAbwBsAFwAVABlAHIAbQBpAG4AYQBsACAAUwBlAHIAdgBlAHIAXABXAGkAbgBTAHQAYQB0AGkAbwBuAHMAXABSAEQAUAAtAFQAYwBwAFwAIgAgAC0ATgBhAG0AZQAgAFAAbwByAHQATgB1AG0AYgBlAHIAIAAtAFYAYQBsAHUAZQAgADMAMwA4ADkAOQANAAoATgBlAHcALQBOAGUAdABGAGkAcgBlAHcAYQBsAGwAUgB1AGwAZQAgAC0ARABpAHMAcABsAGEAeQBOAGEAbQBlACAAIgBSAEQAUAAgADMAMwA4ADkAOQAgAFQAQwBQACIAIAAtAEQAaQByAGUAYwB0AGkAbwBuACAASQBuAGIAbwB1AG4AZAAgAC0ATABvAGMAYQBsAFAAbwByAHQAIAAzADMAOAA5ADkAIAAtAFAAcgBvAHQAbwBjAG8AbAAgAFQAQwBQACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwANAAoATgBlAHcALQBOAGUAdABGAGkAcgBlAHcAYQBsAGwAUgB1AGwAZQAgAC0ARABpAHMAcABsAGEAeQBOAGEAbQBlACAAIgBSAEQAUAAgADMAMwA4ADkAOQAgAFUARABQACIAIAAtAEQAaQByAGUAYwB0AGkAbwBuACAASQBuAGIAbwB1AG4AZAAgAC0ATABvAGMAYQBsAFAAbwByAHQAIAAzADMAOAA5ADkAIAAtAFAAcgBvAHQAbwBjAG8AbAAgAFUARABQACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwANAAoAUgBlAHMAdABhAHIAdAAtAFMAZQByAHYAaQBjAGUAIAAtAE4AYQBtAGUAIABUAGUAcgBtAFMAZQByAHYAaQBjAGUAIAAtAEYAbwByAGMAZQANAAoADQAKAE4AZQB3AC0ATgBlAHQARgBpAHIAZQB3AGEAbABsAFIAdQBsAGUAIAAtAEQAaQBzAHAAbABhAHkATgBhAG0AZQAgACcASQBDAE0AUAB2ADQAJwAgAC0ARABpAHIAZQBjAHQAaQBvAG4AIABJAG4AYgBvAHUAbgBkACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwAgAC0AUAByAG8AdABvAGMAbwBsACAAaQBjAG0AcAB2ADQAIAAtAEUAbgBhAGIAbABlAGQAIABUAHIAdQBlAA==' } } } diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep index 5b50254e97..a29c457abe 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep @@ -119,7 +119,7 @@ resource changerdpport 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' type: 'CustomScriptExtension' typeHandlerVersion: '1.10' settings: { - commandToExecute: 'powershell.exe -ep bypass -encodedcommand UwBlAHQALQBJAHQAZQBtAFAAcgBvAHAAZQByAHQAeQAgAC0AUABhAHQAaAAgACIASABLAEwATQA6AFwAUwB5AHMAdABlAG0AXABDAHUAcgByAGUAbgB0AEMAbwBuAHQAcgBvAGwAUwBlAHQAXABDAG8AbgB0AHIAbwBsAFwAVABlAHIAbQBpAG4AYQBsACAAUwBlAHIAdgBlAHIAXABXAGkAbgBTAHQAYQB0AGkAbwBuAHMAXABSAEQAUAAtAFQAYwBwAFwAIgAgAC0ATgBhAG0AZQAgAFAAbwByAHQATgB1AG0AYgBlAHIAIAAtAFYAYQBsAHUAZQAgADMAMwA4ADkAOQAKAE4AZQB3AC0ATgBlAHQARgBpAHIAZQB3AGEAbABsAFIAdQBsAGUAIAAtAEQAaQBzAHAAbABhAHkATgBhAG0AZQAgACIAUgBEAFAAIAAzADMAOAA5ADkAIABUAEMAUAAiACAALQBEAGkAcgBlAGMAdABpAG8AbgAgAEkAbgBiAG8AdQBuAGQAIAAtAEwAbwBjAGEAbABQAG8AcgB0ACAAMwAzADgAOQA5ACAALQBQAHIAbwB0AG8AYwBvAGwAIABUAEMAUAAgAC0AQQBjAHQAaQBvAG4AIABBAGwAbABvAHcACgBOAGUAdwAtAE4AZQB0AEYAaQByAGUAdwBhAGwAbABSAHUAbABlACAALQBEAGkAcwBwAGwAYQB5AE4AYQBtAGUAIAAiAFIARABQACAAMwAzADgAOQA5ACAAVQBEAFAAIgAgAC0ARABpAHIAZQBjAHQAaQBvAG4AIABJAG4AYgBvAHUAbgBkACAALQBMAG8AYwBhAGwAUABvAHIAdAAgADMAMwA4ADkAOQAgAC0AUAByAG8AdABvAGMAbwBsACAAVQBEAFAAIAAtAEEAYwB0AGkAbwBuACAAQQBsAGwAbwB3AAoAUgBlAHMAdABhAHIAdAAtAFMAZQByAHYAaQBjAGUAIAAtAE4AYQBtAGUAIABUAGUAcgBtAFMAZQByAHYAaQBjAGUAIAAtAEYAbwByAGMAZQA=' + commandToExecute: 'powershell.exe -ep bypass -encodedcommand UwBlAHQALQBJAHQAZQBtAFAAcgBvAHAAZQByAHQAeQAgAC0AUABhAHQAaAAgACIASABLAEwATQA6AFwAUwB5AHMAdABlAG0AXABDAHUAcgByAGUAbgB0AEMAbwBuAHQAcgBvAGwAUwBlAHQAXABDAG8AbgB0AHIAbwBsAFwAVABlAHIAbQBpAG4AYQBsACAAUwBlAHIAdgBlAHIAXABXAGkAbgBTAHQAYQB0AGkAbwBuAHMAXABSAEQAUAAtAFQAYwBwAFwAIgAgAC0ATgBhAG0AZQAgAFAAbwByAHQATgB1AG0AYgBlAHIAIAAtAFYAYQBsAHUAZQAgADMAMwA4ADkAOQANAAoATgBlAHcALQBOAGUAdABGAGkAcgBlAHcAYQBsAGwAUgB1AGwAZQAgAC0ARABpAHMAcABsAGEAeQBOAGEAbQBlACAAIgBSAEQAUAAgADMAMwA4ADkAOQAgAFQAQwBQACIAIAAtAEQAaQByAGUAYwB0AGkAbwBuACAASQBuAGIAbwB1AG4AZAAgAC0ATABvAGMAYQBsAFAAbwByAHQAIAAzADMAOAA5ADkAIAAtAFAAcgBvAHQAbwBjAG8AbAAgAFQAQwBQACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwANAAoATgBlAHcALQBOAGUAdABGAGkAcgBlAHcAYQBsAGwAUgB1AGwAZQAgAC0ARABpAHMAcABsAGEAeQBOAGEAbQBlACAAIgBSAEQAUAAgADMAMwA4ADkAOQAgAFUARABQACIAIAAtAEQAaQByAGUAYwB0AGkAbwBuACAASQBuAGIAbwB1AG4AZAAgAC0ATABvAGMAYQBsAFAAbwByAHQAIAAzADMAOAA5ADkAIAAtAFAAcgBvAHQAbwBjAG8AbAAgAFUARABQACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwANAAoAUgBlAHMAdABhAHIAdAAtAFMAZQByAHYAaQBjAGUAIAAtAE4AYQBtAGUAIABUAGUAcgBtAFMAZQByAHYAaQBjAGUAIAAtAEYAbwByAGMAZQANAAoADQAKAE4AZQB3AC0ATgBlAHQARgBpAHIAZQB3AGEAbABsAFIAdQBsAGUAIAAtAEQAaQBzAHAAbABhAHkATgBhAG0AZQAgACcASQBDAE0AUAB2ADQAJwAgAC0ARABpAHIAZQBjAHQAaQBvAG4AIABJAG4AYgBvAHUAbgBkACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwAgAC0AUAByAG8AdABvAGMAbwBsACAAaQBjAG0AcAB2ADQAIAAtAEUAbgBhAGIAbABlAGQAIABUAHIAdQBlAA==' } } } diff --git a/035-HubAndSpoke/Student/Resources/bicep/windowsRDPFirewallScript.txt b/035-HubAndSpoke/Student/Resources/bicep/windowsRDPFirewallScript.txt new file mode 100644 index 0000000000..620e55085b --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/windowsRDPFirewallScript.txt @@ -0,0 +1,8 @@ +#change RDP port to 33899, allow through FW +Set-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp\" -Name PortNumber -Value 33899 +New-NetFirewallRule -DisplayName "RDP 33899 TCP" -Direction Inbound -LocalPort 33899 -Protocol TCP -Action Allow -Enabled True +New-NetFirewallRule -DisplayName "RDP 33899 UDP" -Direction Inbound -LocalPort 33899 -Protocol UDP -Action Allow -Enabled True +Restart-Service -Name TermService -Force + +#allow ping +New-NetFirewallRule -DisplayName 'ICMPv4' -Direction Inbound -Action Allow -Protocol icmpv4 -Enabled True \ No newline at end of file From de0cfa9ab0b24460629ed17f5171f2bc93dced84 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Thu, 28 Jul 2022 10:07:22 -0600 Subject: [PATCH 23/76] cleanup --- ...roups.bicep => 01-00-resourceGroups.bicep} | 0 .../bicep/{01-hub.bicep => 01-01-hub.bicep} | 0 .../{01-spoke1.bicep => 01-01-spoke1.bicep} | 0 .../{01-spoke2.bicep => 01-01-spoke2.bicep} | 0 ...nghub.bicep => 01-02-vnetpeeringhub.bicep} | 0 ...e1.bicep => 01-02-vnetpeeringspoke1.bicep} | 0 ...e2.bicep => 01-02-vnetpeeringspoke2.bicep} | 0 .../{01-onprem.bicep => 01-03-onprem.bicep} | 0 ...nconfig.bicep => 01-04-hubvpnconfig.bicep} | 0 .../Resources/bicep/01-csrconfig.bicep | 117 ------------------ .../Student/Resources/bicep/csrScript.txt.tpm | 79 ------------ .../Student/Resources/bicep/deployBicep.ps1 | 19 ++- .../bicep/windowsRDPFirewallScript.txt | 8 -- 13 files changed, 9 insertions(+), 214 deletions(-) rename 035-HubAndSpoke/Student/Resources/bicep/{01-resourceGroups.bicep => 01-00-resourceGroups.bicep} (100%) rename 035-HubAndSpoke/Student/Resources/bicep/{01-hub.bicep => 01-01-hub.bicep} (100%) rename 035-HubAndSpoke/Student/Resources/bicep/{01-spoke1.bicep => 01-01-spoke1.bicep} (100%) rename 035-HubAndSpoke/Student/Resources/bicep/{01-spoke2.bicep => 01-01-spoke2.bicep} (100%) rename 035-HubAndSpoke/Student/Resources/bicep/{01-vnetpeeringhub.bicep => 01-02-vnetpeeringhub.bicep} (100%) rename 035-HubAndSpoke/Student/Resources/bicep/{01-vnetpeeringspoke1.bicep => 01-02-vnetpeeringspoke1.bicep} (100%) rename 035-HubAndSpoke/Student/Resources/bicep/{01-vnetpeeringspoke2.bicep => 01-02-vnetpeeringspoke2.bicep} (100%) rename 035-HubAndSpoke/Student/Resources/bicep/{01-onprem.bicep => 01-03-onprem.bicep} (100%) rename 035-HubAndSpoke/Student/Resources/bicep/{01-hubvpnconfig.bicep => 01-04-hubvpnconfig.bicep} (100%) delete mode 100644 035-HubAndSpoke/Student/Resources/bicep/01-csrconfig.bicep delete mode 100644 035-HubAndSpoke/Student/Resources/bicep/csrScript.txt.tpm delete mode 100644 035-HubAndSpoke/Student/Resources/bicep/windowsRDPFirewallScript.txt diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-resourceGroups.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-00-resourceGroups.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/01-resourceGroups.bicep rename to 035-HubAndSpoke/Student/Resources/bicep/01-00-resourceGroups.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-01-hub.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/01-hub.bicep rename to 035-HubAndSpoke/Student/Resources/bicep/01-01-hub.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-01-spoke1.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/01-spoke1.bicep rename to 035-HubAndSpoke/Student/Resources/bicep/01-01-spoke1.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-01-spoke2.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/01-spoke2.bicep rename to 035-HubAndSpoke/Student/Resources/bicep/01-01-spoke2.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-vnetpeeringhub.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-02-vnetpeeringhub.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/01-vnetpeeringhub.bicep rename to 035-HubAndSpoke/Student/Resources/bicep/01-02-vnetpeeringhub.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-vnetpeeringspoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-02-vnetpeeringspoke1.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/01-vnetpeeringspoke1.bicep rename to 035-HubAndSpoke/Student/Resources/bicep/01-02-vnetpeeringspoke1.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-vnetpeeringspoke2.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-02-vnetpeeringspoke2.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/01-vnetpeeringspoke2.bicep rename to 035-HubAndSpoke/Student/Resources/bicep/01-02-vnetpeeringspoke2.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-03-onprem.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/01-onprem.bicep rename to 035-HubAndSpoke/Student/Resources/bicep/01-03-onprem.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-hubvpnconfig.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-04-hubvpnconfig.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/01-hubvpnconfig.bicep rename to 035-HubAndSpoke/Student/Resources/bicep/01-04-hubvpnconfig.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-csrconfig.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-csrconfig.bicep deleted file mode 100644 index 03ed9bc95f..0000000000 --- a/035-HubAndSpoke/Student/Resources/bicep/01-csrconfig.bicep +++ /dev/null @@ -1,117 +0,0 @@ -param location string = 'eastus2' - -resource wthcsrvm 'Microsoft.Compute/virtualMachines@2022-03-01' existing = { - name: 'wth-vm-ciscocsr01' - scope: resourceGroup('wth-rg-onprem') -} - -resource wthcsrnic 'Microsoft.Network/networkInterfaces@2022-01-01' existing = { - name: 'wth-nic-csr01' - scope: resourceGroup('wth-rg-onprem') -} - -resource wthhubgwpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' existing = { - name: 'wth-pip-gw01' - scope: resourceGroup('wth-rg-hub') -} - -resource wthhubgwpip02 'Microsoft.Network/publicIPAddresses@2022-01-01' existing = { - name: 'wth-pip-gw02' - scope: resourceGroup('wth-rg-hub') -} - -var csrScript = ''' -config t - -crypto ikev2 proposal azure-proposal - encryption aes-cbc-256 aes-cbc-128 3des - integrity sha1 - group 2 - exit -! -crypto ikev2 policy azure-policy - proposal azure-proposal - exit -! -crypto ikev2 keyring azure-keyring - peer **GW0_Public_IP** - address **GW0_Public_IP** - pre-shared-key **PSK** - exit - peer **GW1_Public_IP** - address **GW1_Public_IP** - pre-shared-key **PSK** - exit - exit -! -crypto ikev2 profile azure-profile - match address local interface GigabitEthernet1 - match identity remote address **GW0_Public_IP** 255.255.255.255 - match identity remote address **GW1_Public_IP** 255.255.255.255 - authentication remote pre-share - authentication local pre-share - keyring local azure-keyring - exit -! -crypto ipsec transform-set azure-ipsec-proposal-set esp-aes 256 esp-sha-hmac - mode tunnel - exit - -crypto ipsec profile azure-vti - set transform-set azure-ipsec-proposal-set - set ikev2-profile azure-profile - set security-association lifetime kilobytes 102400000 - set security-association lifetime seconds 3600 - exit -! -interface Tunnel0 - ip unnumbered GigabitEthernet1 - ip tcp adjust-mss 1350 - tunnel source GigabitEthernet1 - tunnel mode ipsec ipv4 - tunnel destination **GW0_Public_IP** - tunnel protection ipsec profile azure-vti -exit -! -interface Tunnel1 - ip unnumbered GigabitEthernet1 - ip tcp adjust-mss 1350 - tunnel source GigabitEthernet1 - tunnel mode ipsec ipv4 - tunnel destination **GW1_Public_IP** - tunnel protection ipsec profile azure-vti -exit - -! -router bgp **BGP_ID** - bgp router-id interface GigabitEthernet1 - bgp log-neighbor-changes - redistribute connected - neighbor **GW0_Private_IP** remote-as 65515 - neighbor **GW0_Private_IP** ebgp-multihop 5 - neighbor **GW0_Private_IP** update-source GigabitEthernet1 - neighbor **GW1_Private_IP** remote-as 65515 - neighbor **GW1_Private_IP** ebgp-multihop 5 - neighbor **GW1_Private_IP** update-source GigabitEthernet1 - maximum-paths eibgp 4 -! -ip route **GW0_Private_IP** 255.255.255.255 Tunnel0 -ip route **GW1_Private_IP** 255.255.255.255 Tunnel1 -! -end -! -wr mem -''' - -resource configcsr 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' = { - name: '${wthcsrvm.name}/wth-vmextn-changerdpport33899' - location: location - properties: { - publisher: 'Microsoft.Compute' - type: 'CustomScriptExtension' - typeHandlerVersion: '1.10' - settings: { - commandToExecute: 'ssh -o BatchMode=yes -o StrictHostKeyChecking=no admin-wth@' - } - } -} diff --git a/035-HubAndSpoke/Student/Resources/bicep/csrScript.txt.tpm b/035-HubAndSpoke/Student/Resources/bicep/csrScript.txt.tpm deleted file mode 100644 index c993025e25..0000000000 --- a/035-HubAndSpoke/Student/Resources/bicep/csrScript.txt.tpm +++ /dev/null @@ -1,79 +0,0 @@ -Section: IOS configuration -crypto ikev2 proposal azure-proposal - encryption aes-cbc-256 aes-cbc-128 3des - integrity sha1 - group 2 - exit -! -crypto ikev2 policy azure-policy - proposal azure-proposal - exit -! -crypto ikev2 keyring azure-keyring - peer 20.230.112.137 - address 20.230.112.137 - pre-shared-key 123mysecretkey - exit - peer 20.230.118.170 - address 20.230.118.170 - pre-shared-key 123mysecretkey - exit - exit -! -crypto ikev2 profile azure-profile - match address local interface GigabitEthernet1 - match identity remote address 20.230.112.137 255.255.255.255 - match identity remote address 20.230.118.170 255.255.255.255 - authentication remote pre-share - authentication local pre-share - keyring local azure-keyring - exit -! -crypto ipsec transform-set azure-ipsec-proposal-set esp-aes 256 esp-sha-hmac - mode tunnel - exit - -crypto ipsec profile azure-vti - set transform-set azure-ipsec-proposal-set - set ikev2-profile azure-profile - set security-association lifetime kilobytes 102400000 - set security-association lifetime seconds 3600 - exit -! -interface Tunnel0 - ip unnumbered GigabitEthernet1 - ip tcp adjust-mss 1350 - tunnel source GigabitEthernet1 - tunnel mode ipsec ipv4 - tunnel destination 20.230.112.137 - tunnel protection ipsec profile azure-vti -exit -! -interface Tunnel1 - ip unnumbered GigabitEthernet1 - ip tcp adjust-mss 1350 - tunnel source GigabitEthernet1 - tunnel mode ipsec ipv4 - tunnel destination 20.230.118.170 - tunnel protection ipsec profile azure-vti -exit - -! -router bgp 65510 - bgp router-id interface GigabitEthernet1 - bgp log-neighbor-changes - redistribute connected - neighbor 10.0.0.5 remote-as 65515 - neighbor 10.0.0.5 ebgp-multihop 5 - neighbor 10.0.0.5 update-source GigabitEthernet1 - neighbor 10.0.0.4 remote-as 65515 - neighbor 10.0.0.4 ebgp-multihop 5 - neighbor 10.0.0.4 update-source GigabitEthernet1 - maximum-paths eibgp 4 -! -ip route 10.0.0.5 255.255.255.255 Tunnel0 -ip route 10.0.0.4 255.255.255.255 Tunnel1 -! -end -! -wr mem diff --git a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 index b2c5f1a2dc..12bfd50a4f 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 +++ b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 @@ -65,13 +65,13 @@ switch ($challengeNumber) { Write-Host "Deploying resources for Challenge 1: Hub-and-spoke Basics" Write-Host "`tDeploying resource groups..." - New-AzDeployment -Location $location -TemplateFile ./01-resourceGroups.bicep + New-AzDeployment -Location $location -TemplateFile ./01-00-resourceGroups.bicep Write-Host "`tDeploying base resources (this will take up to 60 minutes for the VNET Gateway)..." $baseInfraJobs = @{} - $baseInfraJobs += @{'wth-rg-spoke1' = (New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./01-spoke1.bicep -TemplateParameterObject @{vmPassword = $vmPassword } -AsJob)} - $baseInfraJobs += @{'wth-rg-spoke2' = (New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./01-spoke2.bicep -TemplateParameterObject @{vmPassword = $vmPassword } -AsJob)} - $baseInfraJobs += @{'wth-rg-hub' = (New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./01-hub.bicep -TemplateParameterObject @{vmPassword = $vmPassword } -AsJob)} + $baseInfraJobs += @{'wth-rg-spoke1' = (New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./01-01-spoke1.bicep -TemplateParameterObject @{vmPassword = $vmPassword } -AsJob)} + $baseInfraJobs += @{'wth-rg-spoke2' = (New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./01-01-spoke2.bicep -TemplateParameterObject @{vmPassword = $vmPassword } -AsJob)} + $baseInfraJobs += @{'wth-rg-hub' = (New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./01-01-hub.bicep -TemplateParameterObject @{vmPassword = $vmPassword } -AsJob)} Write-Host "`tWaiting up to 60 minutes for resources to deploy..." $baseInfraJobs.GetEnumerator().ForEach({$_.Value}) | Wait-Job -Timeout 3600 @@ -84,9 +84,9 @@ switch ($challengeNumber) { Write-Host "`tDeploying VNET Peering..." $peeringJobs = @() - $peeringJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./01-vnetpeeringhub.bicep -AsJob - $peeringJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./01-vnetpeeringspoke1.bicep -AsJob - $peeringJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./01-vnetpeeringspoke2.bicep -AsJob + $peeringJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./01-02-vnetpeeringhub.bicep -AsJob + $peeringJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./01-02-vnetpeeringspoke1.bicep -AsJob + $peeringJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./01-02-vnetpeeringspoke2.bicep -AsJob $peeringJobs | Wait-Job -Timeout 300 @@ -104,15 +104,14 @@ switch ($challengeNumber) { Set-Content -Path .\csrScript.txt.tmp -Value $updatedCsrConfigContent -Force #deploy resources - $onPremJob = New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-onprem' -TemplateFile ./01-onprem.bicep -TemplateParameterObject @{vmPassword = $vmPassword } -AsJob + $onPremJob = New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-onprem' -TemplateFile ./01-03-onprem.bicep -TemplateParameterObject @{vmPassword = $vmPassword } -AsJob $onPremJob | Wait-Job Write-Host "`tConfiguring VPN resources..." $vpnJobs = @() - $vpnJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./01-hubvpnconfig.bicep -AsJob - #$vpnJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-onprem' -TemplateFile ./01-csrconfig.bicep -AsJob + $vpnJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./01-04-hubvpnconfig.bicep -AsJob $vpnJobs | Wait-Job -Timeout 600 } diff --git a/035-HubAndSpoke/Student/Resources/bicep/windowsRDPFirewallScript.txt b/035-HubAndSpoke/Student/Resources/bicep/windowsRDPFirewallScript.txt deleted file mode 100644 index 620e55085b..0000000000 --- a/035-HubAndSpoke/Student/Resources/bicep/windowsRDPFirewallScript.txt +++ /dev/null @@ -1,8 +0,0 @@ -#change RDP port to 33899, allow through FW -Set-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp\" -Name PortNumber -Value 33899 -New-NetFirewallRule -DisplayName "RDP 33899 TCP" -Direction Inbound -LocalPort 33899 -Protocol TCP -Action Allow -Enabled True -New-NetFirewallRule -DisplayName "RDP 33899 UDP" -Direction Inbound -LocalPort 33899 -Protocol UDP -Action Allow -Enabled True -Restart-Service -Name TermService -Force - -#allow ping -New-NetFirewallRule -DisplayName 'ICMPv4' -Direction Inbound -Action Allow -Protocol icmpv4 -Enabled True \ No newline at end of file From 8ff8dd8fb1dddbe9b10e64eb2f3c94ea2ed52fdc Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Thu, 28 Jul 2022 10:13:45 -0600 Subject: [PATCH 24/76] csr terms --- 035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 index 12bfd50a4f..36f947a842 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 +++ b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 @@ -90,7 +90,13 @@ switch ($challengeNumber) { $peeringJobs | Wait-Job -Timeout 300 - Write-Host "Deploying 'onprem' infra" + Write-Host "`tDeploying 'onprem' infra" + + #accept csr marketplace terms + If (-Not (Get-AzMarketplaceTerms -Publisher 'cicso' -Product 'cisco-csr-1000v' -Name '16_12-byol').Accepted) { + Write-Host "`t`tAccepting Cisco CSR marketplace terms for this subscription..." + Set-AzMarketplaceTerms -Publisher 'cicso' -Product 'cisco-csr-1000v' -Name '16_12-byol' -Accept + } #update csr bootstrap file $csrConfigContent = Get-Content -Path .\csrScript.txt From 44bc47b6ab62bdc8abf32b5749b77775da8bb760 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Thu, 28 Jul 2022 11:01:17 -0600 Subject: [PATCH 25/76] csr terms - cisco misspell --- 035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 index 36f947a842..0cbe414734 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 +++ b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 @@ -93,9 +93,9 @@ switch ($challengeNumber) { Write-Host "`tDeploying 'onprem' infra" #accept csr marketplace terms - If (-Not (Get-AzMarketplaceTerms -Publisher 'cicso' -Product 'cisco-csr-1000v' -Name '16_12-byol').Accepted) { + If (-Not (Get-AzMarketplaceTerms -Publisher 'cisco' -Product 'cisco-csr-1000v' -Name '16_12-byol').Accepted) { Write-Host "`t`tAccepting Cisco CSR marketplace terms for this subscription..." - Set-AzMarketplaceTerms -Publisher 'cicso' -Product 'cisco-csr-1000v' -Name '16_12-byol' -Accept + Set-AzMarketplaceTerms -Publisher 'cisco' -Product 'cisco-csr-1000v' -Name '16_12-byol' -Accept } #update csr bootstrap file From 55646ceee976862cefee5c5d4446117768c9d6d7 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Thu, 28 Jul 2022 12:49:38 -0600 Subject: [PATCH 26/76] on-prem routing --- .../Resources/bicep/01-03-onprem.bicep | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-03-onprem.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-03-onprem.bicep index 80e45b7878..c8d02b25f2 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-03-onprem.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-03-onprem.bicep @@ -134,7 +134,32 @@ resource rtonpremvms 'Microsoft.Network/routeTables@2022-01-01' = { name: 'wth-rt-onpremvmssubnet' location: location properties: { - routes: [] + routes: [ + { + name: 'route-hub' + properties: { + addressPrefix: '10.0.0.0/16' + nextHopIpAddress: '172.16.0.4' + nextHopType: 'VirtualAppliance' + } + } + { + name: 'route-spoke1' + properties: { + addressPrefix: '10.1.0.0/16' + nextHopIpAddress: '172.16.0.4' + nextHopType: 'VirtualAppliance' + } + } + { + name: 'route-spoke2' + properties: { + addressPrefix: '10.2.0.0/16' + nextHopIpAddress: '172.16.0.4' + nextHopType: 'VirtualAppliance' + } + } + ] disableBgpRoutePropagation: false } } @@ -190,6 +215,7 @@ resource wthonpremcsrnic 'Microsoft.Network/networkInterfaces@2022-01-01' = { name: 'wth-nic-csr01' location: location properties: { + enableIPForwarding: true ipConfigurations: [ { name: 'ipconfig1' From 9906139433a461ca429290f072a86eeb57c5fc59 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Fri, 29 Jul 2022 12:18:02 -0600 Subject: [PATCH 27/76] throw on error --- .../Student/Resources/bicep/deployBicep.ps1 | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 index 0cbe414734..f6ea43db49 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 +++ b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 @@ -1,14 +1,10 @@ <# .SYNOPSIS .DESCRIPTION - A longer description of the function, its purpose, common use cases, etc. -.NOTES - Information or caveats about the function e.g. 'This function is not supported in Linux' -.LINK - Specify a URI to a help page, this will show when Get-Help -Online is used. + Deploys or configures WTH Networking challenge resources. .EXAMPLE - Test-MyTestFunction -Verbose - Explanation of the function or its result. You can include multiple examples with additional .EXAMPLE lines + ./deployBicep.ps1 -challengeNumber 1 + Deploy all resource groups and resources for Challenge 1. Script will prompt for a password, which will be used across all VMs. #> [CmdletBinding()] param ( @@ -18,7 +14,7 @@ param ( [int] $challengeNumber, - # deploy fully configured lab or leave some configuration to be done + # TODO: deploy fully configured lab or leave some configuration to be done [Parameter(Mandatory = $false, HelpMessage = 'Deploy all challenge resources fully configured or partially configured (for learning!)')] [ValidateSet('FullyConfigured', 'PartiallyConfigured')] [string] @@ -46,15 +42,15 @@ If (-NOT (Test-Path ./01-resourceGroups.bicep)) { Push-Location -Path $scriptPath -ErrorAction Stop } catch { - Write-Error "Failed to set path to bicep file location. Use the 'cd' command to change the current directory to the same location as the WTH bicep files before executing this script." + throw "Failed to set path to bicep file location. Use the 'cd' command to change the current directory to the same location as the WTH bicep files before executing this script." } } If ( -NOT ($azContext = Get-AzContext)) { - Write-Error "Run 'Connect-AzAccount' before executing this script!" + throw "Run 'Connect-AzAccount' before executing this script!" } Else { - do { $response = (Read-Host "Resources will be created in subscription '$($azContext.Subscription.Name)'. Proceed? (y/n)") } + do { $response = (Read-Host "Resources will be created in subscription '$($azContext.Subscription.Name)'. If this is not the correct subscription, use 'Select-AzSubscription' before running this script. Proceed? (y/n)") } until ($response -match '[nNYy]') If ($response -match 'nN') { exit } @@ -121,7 +117,21 @@ switch ($challengeNumber) { $vpnJobs | Wait-Job -Timeout 600 } - 2 {} + 2 { + Write-Host "Deploying resources for Challenge 2: Azure Firewall" + + Write-Host "`tDeploying Azure Firewall and related hub resources..." + $afwJob = New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./02-00-afw.bicep -AsJob + + $afwJob | Wait-Job + + Write-Host "`tDeploying updated Spoke resources..." + $spokeRTJobs = @() + $spokeRTJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./02-01-spoke1.bicep -AsJob + $spokeRTJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./02-01-spoke2.bicep -AsJob + + $spokeRTJobs | Wait-Job + } 3 {} 4 {} 5 {} From b4005ec85cd8428916f0c3cfc57505559896b21c Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Fri, 29 Jul 2022 15:30:09 -0600 Subject: [PATCH 28/76] challenge 2 --- .../Student/Resources/bicep/01-01-hub.bicep | 21 ++ .../Student/Resources/bicep/02-00-afw.bicep | 143 +++++++++++ .../Resources/bicep/02-01-fwpolicyrules.bicep | 233 ++++++++++++++++++ .../Student/Resources/bicep/02-01-hub.bicep | 60 +++++ .../Resources/bicep/02-01-onprem.bicep | 29 +++ .../Resources/bicep/02-01-spoke1.bicep | 52 ++++ .../Resources/bicep/02-01-spoke2.bicep | 52 ++++ .../Student/Resources/bicep/deployBicep.ps1 | 23 +- 8 files changed, 607 insertions(+), 6 deletions(-) create mode 100644 035-HubAndSpoke/Student/Resources/bicep/02-00-afw.bicep create mode 100644 035-HubAndSpoke/Student/Resources/bicep/02-01-fwpolicyrules.bicep create mode 100644 035-HubAndSpoke/Student/Resources/bicep/02-01-hub.bicep create mode 100644 035-HubAndSpoke/Student/Resources/bicep/02-01-onprem.bicep create mode 100644 035-HubAndSpoke/Student/Resources/bicep/02-01-spoke1.bicep create mode 100644 035-HubAndSpoke/Student/Resources/bicep/02-01-spoke2.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-01-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-01-hub.bicep index 212b9cd0ef..3bf55cffa0 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-01-hub.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-01-hub.bicep @@ -37,6 +37,12 @@ resource wthhubvnet 'Microsoft.Network/virtualNetworks@2021-08-01' = { } } } + { + name: 'AzureFirewallSubnet' + properties: { + addressPrefix: '10.0.1.0/24' + } + } ] } } @@ -142,6 +148,18 @@ resource changerdpport 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' } } +resource wthhubvmpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { + name: 'wth-pip-hubvm01' + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } +} + resource wthhubvmnic 'Microsoft.Network/networkInterfaces@2022-01-01' = { name: 'wth-nic-hubvm01' location: location @@ -154,6 +172,9 @@ resource wthhubvmnic 'Microsoft.Network/networkInterfaces@2022-01-01' = { id: '${wthhubvnet.id}/subnets/subnet-hubvms' } privateIPAddress: '10.0.10.4' + publicIPAddress: { + id: wthhubvmpip01.id + } } } ] diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-00-afw.bicep b/035-HubAndSpoke/Student/Resources/bicep/02-00-afw.bicep new file mode 100644 index 0000000000..47f5e42156 --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/02-00-afw.bicep @@ -0,0 +1,143 @@ +param location string = 'eastus2' + +resource hubvnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { + name: 'wth-vnet-hub01' + scope: resourceGroup('wth-rg-hub') +} + +resource wthrthubvmssubnet 'Microsoft.Network/routeTables@2022-01-01' existing = { + name: 'wth-rt-hubvmssubnet' + scope: resourceGroup('wth-rg-hub') +} + +resource afwsubnet 'Microsoft.Network/virtualNetworks/subnets@2022-01-01' = { + name: '${hubvnet.name}/AzureFirewallSubnet' + properties: { + addressPrefix: '10.0.1.0/24' + } +} + +resource wthafwpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { + name: 'wth-pip-afw01' + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } +} + +resource wthafwpolicy 'Microsoft.Network/firewallPolicies@2022-01-01' = { + name: 'wth-fwp-default01' + location: location + properties: {} +} + +resource wthafw 'Microsoft.Network/azureFirewalls@2022-01-01' = { + name: 'wth-afw-hub01' + location: location + properties: { + sku: { + name: 'AZFW_VNet' + tier: 'Standard' + } + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + subnet: { + id: afwsubnet.id + } + publicIPAddress: { + id: wthafwpip01.id + } + } + } + ] + firewallPolicy: { + id: wthafwpolicy.id + } + } +} + +resource wthlaw 'Microsoft.OperationalInsights/workspaces@2021-12-01-preview' = { + name: 'wth-law-default01' + location: location + properties: { + sku: { + name: 'PerGB2018' + } + } +} + +resource wthafwdiagsettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = { + name: 'diagSettingsAFW' + scope: wthafw + properties: { + workspaceId: wthlaw.id + logs: [ + { + enabled: true + categoryGroup: 'allLogs' + retentionPolicy: { + enabled: true + days: 14 + } + } + ] + } +} + +resource rthubvms 'Microsoft.Network/routeTables@2022-01-01' = { + name: 'wth-rt-hubvmssubnet' + location: location + properties: { + routes: [ + { + name: 'route-all-to-afw' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress + } + } + ] + disableBgpRoutePropagation: false + } +} + +resource rtvnetgw 'Microsoft.Network/routeTables@2022-01-01' = { + name: 'wth-rt-hubgwsubnet' + location: location + properties: { + routes: [ + { + name: 'route-spoke1-to-afw' + properties: { + addressPrefix: '10.1.0.0/16' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress + } + } + { + name: 'route-spoke2-to-afw' + properties: { + addressPrefix: '10.2.0.0/16' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress + } + } + { + name: 'route-hubvm-to-afw' + properties: { + addressPrefix: '10.0.10.0/24' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress + } + } + ] + disableBgpRoutePropagation: false + } +} diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-01-fwpolicyrules.bicep b/035-HubAndSpoke/Student/Resources/bicep/02-01-fwpolicyrules.bicep new file mode 100644 index 0000000000..d0e148d384 --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/02-01-fwpolicyrules.bicep @@ -0,0 +1,233 @@ +resource wthafwpolicy 'Microsoft.Network/firewallPolicies@2022-01-01' existing = { + name: 'wth-fwp-default01' + scope: resourceGroup('wth-rg-hub') +} + +resource wthafw 'Microsoft.Network/azureFirewalls@2022-01-01' existing = { + name: 'wth-afw-hub01' + scope: resourceGroup('wth-rg-hub') +} + +resource wthafwpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' existing = { + name: 'wth-pip-afw01' + scope: resourceGroup('wth-rg-hub') +} + +resource wthhubvmnic 'Microsoft.Network/networkInterfaces@2022-01-01' existing = { + name: 'wth-nic-hubvm01' + scope: resourceGroup('wth-rg-hub') +} + +resource wthspoke1vmnic 'Microsoft.Network/networkInterfaces@2022-01-01' existing = { + name: 'wth-nic-spoke1vm01' + scope: resourceGroup('wth-rg-spoke1') +} + +resource wthspoke2vmnic 'Microsoft.Network/networkInterfaces@2022-01-01' existing = { + name: 'wth-nic-spoke2vm01' + scope: resourceGroup('wth-rg-spoke2') +} + +resource wthafwrcgdnat 'Microsoft.Network/firewallPolicies/ruleCollectionGroups@2022-01-01' = { + name: '${wthafwpolicy.name}/WTH_DNATRulesCollectionGroup' + properties: { + priority: 100 + ruleCollections: [ + { + ruleCollectionType: 'FirewallPolicyNatRuleCollection' + action: { + type: 'DNAT' + } + name: 'dnat-webservers-http' + priority: 100 + rules: [ + { + name: 'dnat-tcp8080-to-hub-80' + ruleType: 'NatRule' + description: 'DNAT port 8080 to hub' + destinationAddresses: [ + wthafwpip01.properties.ipAddress + ] + destinationPorts: [ + '8080' + ] + ipProtocols: [ + 'tcp' + ] + sourceAddresses: [ + '*' + ] + translatedAddress: wthhubvmnic.properties.ipConfigurations[0].properties.privateIPAddress + translatedPort: '80' + } + { + name: 'dnat-tcp8081-to-spoke1-80' + ruleType: 'NatRule' + description: 'DNAT port 8081 to Spoke1' + destinationAddresses: [ + wthafwpip01.properties.ipAddress + ] + destinationPorts: [ + '8081' + ] + ipProtocols: [ + 'tcp' + ] + sourceAddresses: [ + '*' + ] + translatedAddress: wthspoke1vmnic.properties.ipConfigurations[0].properties.privateIPAddress + translatedPort: '80' + } + { + name: 'dnat-tcp8082-to-spoke1-80' + ruleType: 'NatRule' + description: 'DNAT port 8082 to Spoke2' + destinationAddresses: [ + wthafwpip01.properties.ipAddress + ] + destinationPorts: [ + '8082' + ] + ipProtocols: [ + 'tcp' + ] + sourceAddresses: [ + '*' + ] + translatedAddress: wthspoke2vmnic.properties.ipConfigurations[0].properties.privateIPAddress + translatedPort: '80' + } + ] + } + { + ruleCollectionType: 'FirewallPolicyNatRuleCollection' + action: { + type: 'DNAT' + } + name: 'dnat-rdp' + priority: 101 + rules: [ + { + name: 'dnat-tcp33890-to-hub-33899' + ruleType: 'NatRule' + description: 'DNAT port 33891 to hub' + destinationAddresses: [ + wthafwpip01.properties.ipAddress + ] + destinationPorts: [ + '33890' + ] + ipProtocols: [ + 'tcp' + ] + sourceAddresses: [ + '*' + ] + translatedAddress: wthhubvmnic.properties.ipConfigurations[0].properties.privateIPAddress + translatedPort: '33899' + } + { + name: 'dnat-tcp33891-to-spoke1-33899' + ruleType: 'NatRule' + description: 'DNAT port 33891 to Spoke1' + destinationAddresses: [ + wthafwpip01.properties.ipAddress + ] + destinationPorts: [ + '33891' + ] + ipProtocols: [ + 'tcp' + ] + sourceAddresses: [ + '*' + ] + translatedAddress: wthspoke1vmnic.properties.ipConfigurations[0].properties.privateIPAddress + translatedPort: '33899' + } + { + name: 'dnat-tcp33892-to-spoke1-33899' + ruleType: 'NatRule' + description: 'DNAT port 33892 to Spoke2' + destinationAddresses: [ + wthafwpip01.properties.ipAddress + ] + destinationPorts: [ + '33892' + ] + ipProtocols: [ + 'tcp' + ] + sourceAddresses: [ + '*' + ] + translatedAddress: wthspoke2vmnic.properties.ipConfigurations[0].properties.privateIPAddress + translatedPort: '33899' + } + ] + } + ] + } +} + +resource wthafwrcgnet 'Microsoft.Network/firewallPolicies/ruleCollectionGroups@2022-01-01' = { + name: '${wthafwpolicy.name}/WTH_NetworkRulesCollectionGroup' + properties: { + priority: 200 + ruleCollections: [ + { + ruleCollectionType: 'FirewallPolicyFilterRuleCollection' + action: { + type: 'Allow' + } + name: 'allow-network-rules' + priority:200 + rules: [ + { + ruleType: 'NetworkRule' + name: 'allow-any-to-any' + description: 'Allow any traffic to any destination' + destinationAddresses: [ + '*' + ] + destinationPorts: [ + '*' + ] + sourceAddresses: [ + '*' + ] + ipProtocols: [ + 'Any' + ] + } + ] + } + ] + } + dependsOn: [ + wthafwrcgdnat + ] +} + +resource wthafwrcgapp 'Microsoft.Network/firewallPolicies/ruleCollectionGroups@2022-01-01' = { + name: '${wthafwpolicy.name}/WTH_AppRulesCollectionGroup' + properties: { + priority: 300 + ruleCollections: [ + { + ruleCollectionType: 'FirewallPolicyFilterRuleCollection' + action: { + type: 'Allow' + } + priority: 300 + name: 'allow-apprules' + rules: [] + } + ] + } + dependsOn: [ + wthafwrcgnet + ] +} + diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-01-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/02-01-hub.bicep new file mode 100644 index 0000000000..7b2f50d6da --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/02-01-hub.bicep @@ -0,0 +1,60 @@ +param location string = 'eastus2' + +resource wthafw 'Microsoft.Network/azureFirewalls@2022-01-01' existing = { + name: 'wth-afw-hub01' + scope: resourceGroup('wth-rg-hub') +} + +resource wthhubvm01 'Microsoft.Compute/virtualMachines@2022-03-01' existing = { + name: 'wth-vm-hub01' + scope: resourceGroup('wth-rg-hub') +} + +resource rthubvms 'Microsoft.Network/routeTables@2022-01-01' = { + name: 'wth-rt-hubvmssubnet' + location: location + properties: { + routes: [ + { + name: 'route-all-to-afw' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress + + } + } + { + name: 'route-onprem-to-afw' + properties: { + addressPrefix: '172.16.0.0/16' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress + } + } + ] + disableBgpRoutePropagation: true + } +} + +resource installinspectorgadget 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' = { + name: '${wthhubvm01.name}/wth-vmextn-installinspectorgadget' + location: location + properties: { + publisher: 'Microsoft.Compute' + type: 'CustomScriptExtension' + typeHandlerVersion: '1.10' + settings: { + /* + To generate encoded command in PowerShell: + + $s = @' + Install-WindowsFeature Web-Server,Web-Asp-Net45 -IncludeManagementTools + [System.Net.WebClient]::new().DownloadFile('https://raw.githubusercontent.com/jelledruyts/InspectorGadget/main/Page/default.aspx','c:\inetpub\wwwroot\default.aspx') + '@ + $bytes = [System.Text.Encoding]::Unicode.GetBytes($s) + [convert]::ToBase64String($bytes) */ + commandToExecute: 'powershell.exe -ep bypass -encodedcommand IAAgACAAIAAgACAAIAAgAEkAbgBzAHQAYQBsAGwALQBXAGkAbgBkAG8AdwBzAEYAZQBhAHQAdQByAGUAIABXAGUAYgAtAFMAZQByAHYAZQByACwAVwBlAGIALQBBAHMAcAAtAE4AZQB0ADQANQAgAC0ASQBuAGMAbAB1AGQAZQBNAGEAbgBhAGcAZQBtAGUAbgB0AFQAbwBvAGwAcwAKACAAIAAgACAAIAAgACAAIABbAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdABdADoAOgBuAGUAdwAoACkALgBEAG8AdwBuAGwAbwBhAGQARgBpAGwAZQAoACcAaAB0AHQAcABzADoALwAvAHIAYQB3AC4AZwBpAHQAaAB1AGIAdQBzAGUAcgBjAG8AbgB0AGUAbgB0AC4AYwBvAG0ALwBqAGUAbABsAGUAZAByAHUAeQB0AHMALwBJAG4AcwBwAGUAYwB0AG8AcgBHAGEAZABnAGUAdAAvAG0AYQBpAG4ALwBQAGEAZwBlAC8AZABlAGYAYQB1AGwAdAAuAGEAcwBwAHgAJwAsACcAYwA6AFwAaQBuAGUAdABwAHUAYgBcAHcAdwB3AHIAbwBvAHQAXABkAGUAZgBhAHUAbAB0AC4AYQBzAHAAeAAnACkA' + } + } +} diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-01-onprem.bicep b/035-HubAndSpoke/Student/Resources/bicep/02-01-onprem.bicep new file mode 100644 index 0000000000..30339547c7 --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/02-01-onprem.bicep @@ -0,0 +1,29 @@ +param location string = 'eastus2' + + +resource wthonpremvm01 'Microsoft.Compute/virtualMachines@2022-03-01' existing = { + name: 'wth-vm-onprem01' + scope: resourceGroup('wth-rg-onprem') +} + +resource installinspectorgadget 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' = { + name: '${wthonpremvm01.name}/wth-vmextn-installinspectorgadget' + location: location + properties: { + publisher: 'Microsoft.Compute' + type: 'CustomScriptExtension' + typeHandlerVersion: '1.10' + settings: { + /* + To generate encoded command in PowerShell: + + $s = @' + Install-WindowsFeature Web-Server,Web-Asp-Net45 -IncludeManagementTools + [System.Net.WebClient]::new().DownloadFile('https://raw.githubusercontent.com/jelledruyts/InspectorGadget/main/Page/default.aspx','c:\inetpub\wwwroot\default.aspx') + '@ + $bytes = [System.Text.Encoding]::Unicode.GetBytes($s) + [convert]::ToBase64String($bytes) */ + commandToExecute: 'powershell.exe -ep bypass -encodedcommand IAAgACAAIAAgACAAIAAgAEkAbgBzAHQAYQBsAGwALQBXAGkAbgBkAG8AdwBzAEYAZQBhAHQAdQByAGUAIABXAGUAYgAtAFMAZQByAHYAZQByACwAVwBlAGIALQBBAHMAcAAtAE4AZQB0ADQANQAgAC0ASQBuAGMAbAB1AGQAZQBNAGEAbgBhAGcAZQBtAGUAbgB0AFQAbwBvAGwAcwAKACAAIAAgACAAIAAgACAAIABbAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdABdADoAOgBuAGUAdwAoACkALgBEAG8AdwBuAGwAbwBhAGQARgBpAGwAZQAoACcAaAB0AHQAcABzADoALwAvAHIAYQB3AC4AZwBpAHQAaAB1AGIAdQBzAGUAcgBjAG8AbgB0AGUAbgB0AC4AYwBvAG0ALwBqAGUAbABsAGUAZAByAHUAeQB0AHMALwBJAG4AcwBwAGUAYwB0AG8AcgBHAGEAZABnAGUAdAAvAG0AYQBpAG4ALwBQAGEAZwBlAC8AZABlAGYAYQB1AGwAdAAuAGEAcwBwAHgAJwAsACcAYwA6AFwAaQBuAGUAdABwAHUAYgBcAHcAdwB3AHIAbwBvAHQAXABkAGUAZgBhAHUAbAB0AC4AYQBzAHAAeAAnACkA' + } + } +} diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke1.bicep new file mode 100644 index 0000000000..bb54f54154 --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke1.bicep @@ -0,0 +1,52 @@ +param location string = 'eastus2' + +resource wthafw 'Microsoft.Network/azureFirewalls@2022-01-01' existing = { + name: 'wth-afw-hub01' + scope: resourceGroup('wth-rg-hub') +} + +resource wthspoke1vm01 'Microsoft.Compute/virtualMachines@2022-03-01' existing = { + name: 'wth-vm-spoke101' + scope: resourceGroup('wth-rg-spoke1') +} + +resource rtspoke1vms 'Microsoft.Network/routeTables@2022-01-01' = { + name: 'wth-rt-spoke1vmssubnet' + location: location + properties: { + routes: [ + { + name: 'route-all-to-afw' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress + + } + } + ] + disableBgpRoutePropagation: true + } +} + +resource installinspectorgadget 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' = { + name: '${wthspoke1vm01.name}/wth-vmextn-installinspectorgadget' + location: location + properties: { + publisher: 'Microsoft.Compute' + type: 'CustomScriptExtension' + typeHandlerVersion: '1.10' + settings: { + /* + To generate encoded command in PowerShell: + + $s = @' + Install-WindowsFeature Web-Server,Web-Asp-Net45 -IncludeManagementTools + [System.Net.WebClient]::new().DownloadFile('https://raw.githubusercontent.com/jelledruyts/InspectorGadget/main/Page/default.aspx','c:\inetpub\wwwroot\default.aspx') + '@ + $bytes = [System.Text.Encoding]::Unicode.GetBytes($s) + [convert]::ToBase64String($bytes) */ + commandToExecute: 'powershell.exe -ep bypass -encodedcommand IAAgACAAIAAgACAAIAAgAEkAbgBzAHQAYQBsAGwALQBXAGkAbgBkAG8AdwBzAEYAZQBhAHQAdQByAGUAIABXAGUAYgAtAFMAZQByAHYAZQByACwAVwBlAGIALQBBAHMAcAAtAE4AZQB0ADQANQAgAC0ASQBuAGMAbAB1AGQAZQBNAGEAbgBhAGcAZQBtAGUAbgB0AFQAbwBvAGwAcwAKACAAIAAgACAAIAAgACAAIABbAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdABdADoAOgBuAGUAdwAoACkALgBEAG8AdwBuAGwAbwBhAGQARgBpAGwAZQAoACcAaAB0AHQAcABzADoALwAvAHIAYQB3AC4AZwBpAHQAaAB1AGIAdQBzAGUAcgBjAG8AbgB0AGUAbgB0AC4AYwBvAG0ALwBqAGUAbABsAGUAZAByAHUAeQB0AHMALwBJAG4AcwBwAGUAYwB0AG8AcgBHAGEAZABnAGUAdAAvAG0AYQBpAG4ALwBQAGEAZwBlAC8AZABlAGYAYQB1AGwAdAAuAGEAcwBwAHgAJwAsACcAYwA6AFwAaQBuAGUAdABwAHUAYgBcAHcAdwB3AHIAbwBvAHQAXABkAGUAZgBhAHUAbAB0AC4AYQBzAHAAeAAnACkA' + } + } +} diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke2.bicep b/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke2.bicep new file mode 100644 index 0000000000..58d1019ef7 --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke2.bicep @@ -0,0 +1,52 @@ +param location string = 'eastus2' + +resource wthafw 'Microsoft.Network/azureFirewalls@2022-01-01' existing = { + name: 'wth-afw-hub01' + scope: resourceGroup('wth-rg-hub') +} + +resource wthspoke2vm01 'Microsoft.Compute/virtualMachines@2022-03-01' existing = { + name: 'wth-vm-spoke201' + scope: resourceGroup('wth-rg-spoke2') +} + +resource rtspoke2vms 'Microsoft.Network/routeTables@2022-01-01' = { + name: 'wth-rt-spoke2vmssubnet' + location: location + properties: { + routes: [ + { + name: 'route-all-to-afw' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress + + } + } + ] + disableBgpRoutePropagation: true + } +} + +resource installinspectorgadget 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' = { + name: '${wthspoke2vm01.name}/wth-vmextn-installinspectorgadget' + location: location + properties: { + publisher: 'Microsoft.Compute' + type: 'CustomScriptExtension' + typeHandlerVersion: '1.10' + settings: { + /* + To generate encoded command in PowerShell: + + $s = @' + Install-WindowsFeature Web-Server,Web-Asp-Net45 -IncludeManagementTools + [System.Net.WebClient]::new().DownloadFile('https://raw.githubusercontent.com/jelledruyts/InspectorGadget/main/Page/default.aspx','c:\inetpub\wwwroot\default.aspx') + '@ + $bytes = [System.Text.Encoding]::Unicode.GetBytes($s) + [convert]::ToBase64String($bytes) */ + commandToExecute: 'powershell.exe -ep bypass -encodedcommand IAAgACAAIAAgACAAIAAgAEkAbgBzAHQAYQBsAGwALQBXAGkAbgBkAG8AdwBzAEYAZQBhAHQAdQByAGUAIABXAGUAYgAtAFMAZQByAHYAZQByACwAVwBlAGIALQBBAHMAcAAtAE4AZQB0ADQANQAgAC0ASQBuAGMAbAB1AGQAZQBNAGEAbgBhAGcAZQBtAGUAbgB0AFQAbwBvAGwAcwAKACAAIAAgACAAIAAgACAAIABbAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdABdADoAOgBuAGUAdwAoACkALgBEAG8AdwBuAGwAbwBhAGQARgBpAGwAZQAoACcAaAB0AHQAcABzADoALwAvAHIAYQB3AC4AZwBpAHQAaAB1AGIAdQBzAGUAcgBjAG8AbgB0AGUAbgB0AC4AYwBvAG0ALwBqAGUAbABsAGUAZAByAHUAeQB0AHMALwBJAG4AcwBwAGUAYwB0AG8AcgBHAGEAZABnAGUAdAAvAG0AYQBpAG4ALwBQAGEAZwBlAC8AZABlAGYAYQB1AGwAdAAuAGEAcwBwAHgAJwAsACcAYwA6AFwAaQBuAGUAdABwAHUAYgBcAHcAdwB3AHIAbwBvAHQAXABkAGUAZgBhAHUAbAB0AC4AYQBzAHAAeAAnACkA' + } + } +} diff --git a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 index f6ea43db49..c057985887 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 +++ b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 @@ -26,7 +26,7 @@ param ( $location = 'EastUS2', # Parameter help description - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $false)] [SecureString] $vmPassword ) @@ -60,6 +60,10 @@ switch ($challengeNumber) { 1 { Write-Host "Deploying resources for Challenge 1: Hub-and-spoke Basics" + If (-NOT ($vmPassword)) { + $vmPassword = Read-Host "Enter (and make note of) a complex password which will be used for all deployed VMs" -AsSecureString + } + Write-Host "`tDeploying resource groups..." New-AzDeployment -Location $location -TemplateFile ./01-00-resourceGroups.bicep @@ -125,12 +129,19 @@ switch ($challengeNumber) { $afwJob | Wait-Job - Write-Host "`tDeploying updated Spoke resources..." - $spokeRTJobs = @() - $spokeRTJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./02-01-spoke1.bicep -AsJob - $spokeRTJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./02-01-spoke2.bicep -AsJob + Write-Host "`tDeploying firewall policies..." + $fwpolJob = New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./02-01-fwpolicyrules.bicep -AsJob + + $fwpolJob | Wait-Job + + Write-Host "`tDeploying updated hub, spoke, and on-prem configs..." + $jobs = @() + $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./02-01-spoke1.bicep -AsJob + $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./02-01-spoke2.bicep -AsJob + $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./02-01-hub.bicep -AsJob + $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-onprem' -TemplateFile ./02-01-onprem.bicep -AsJob - $spokeRTJobs | Wait-Job + $jobs | Wait-Job } 3 {} 4 {} From 8f2f67c8fa51f37b53aa1df45b29aa114bcf2b0f Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Fri, 29 Jul 2022 16:11:46 -0600 Subject: [PATCH 29/76] readme --- .../Student/Resources/bicep/README.md | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 035-HubAndSpoke/Student/Resources/bicep/README.md diff --git a/035-HubAndSpoke/Student/Resources/bicep/README.md b/035-HubAndSpoke/Student/Resources/bicep/README.md new file mode 100644 index 0000000000..3060c1fadf --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/README.md @@ -0,0 +1,26 @@ +# What the Hack Networking Bicep Deployment + +This directory contains Bicep templates to deploy and configure resources as described in each WTH Networking challenge. These deployments represent one way to meet the challenge requirements--there are many others. + +## Who should use these templates? + +The WTH philosophy intends to have students learn by doing, and recognizes that one of the best ways to learn is to troubleshoot problems. As such, using these templates instead of building your own lab will detract from your learning experience, and only recommended for the scenarios below: + +- Students who will not be completing a challenge which is a prerequisite to a later challenge +- Students who are falling behind in the WTH due to issues unrelated to the core learning goals of this WTH +- Students looking for a reference implementation to compare against their own approach + +## Using these templates + +Using Cloud Shell is recommended, as it already has the necessary tools installed. + +### Prerequisites + +- Azure PowerShell module +- git + +1. Clone this repo to your local system or Cloud Shell + `git clone https://github.com/microsoft/WhatTheHack.git` +1. Navigate to the `035-HubAndSpoke\Student\Resources\bicep` directory in your clone of the repo +1. Run the deployBicep.ps1 script. For example: + `./deployBicep.ps1 -challengeNumber 1` \ No newline at end of file From 97bd22ef89cd7cc909bf262c43735e3d3bfb4fc9 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Mon, 1 Aug 2022 10:00:58 -0600 Subject: [PATCH 30/76] error handling --- .../Student/Resources/bicep/deployBicep.ps1 | 70 ++++++++++++++++--- 1 file changed, 59 insertions(+), 11 deletions(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 index c057985887..c352cd504b 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 +++ b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 @@ -74,7 +74,15 @@ switch ($challengeNumber) { $baseInfraJobs += @{'wth-rg-hub' = (New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./01-01-hub.bicep -TemplateParameterObject @{vmPassword = $vmPassword } -AsJob)} Write-Host "`tWaiting up to 60 minutes for resources to deploy..." - $baseInfraJobs.GetEnumerator().ForEach({$_.Value}) | Wait-Job -Timeout 3600 + $baseInfraJobs.GetEnumerator().ForEach({$_.Value}) | Wait-Job -Timeout 3600 | Out-Null + + # check for deployment errors + $baseInfraJobs.GetEnumerator().ForEach({$_.Value}) | Foreach-Object { + $job = $_ | Get-Job + If ($job.Error) { + Write-Error "A deployment experienced an error: $($job.error)" + } + } $gw1pip = $baseInfraJobs.'wth-rg-hub'.Output.Outputs.pipgw1.Value $gw2pip = $baseInfraJobs.'wth-rg-hub'.Output.Outputs.pipgw2.Value @@ -88,16 +96,28 @@ switch ($challengeNumber) { $peeringJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./01-02-vnetpeeringspoke1.bicep -AsJob $peeringJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./01-02-vnetpeeringspoke2.bicep -AsJob - $peeringJobs | Wait-Job -Timeout 300 + $peeringJobs | Wait-Job -Timeout 300 | Out-Null + + # check for deployment errors + $peeringJobs | Foreach-Object { + $job = $_ + If ($job.Error) { + Write-Error "A VNET peering deployment experienced an error: $($job.error)" + } + } Write-Host "`tDeploying 'onprem' infra" #accept csr marketplace terms - If (-Not (Get-AzMarketplaceTerms -Publisher 'cisco' -Product 'cisco-csr-1000v' -Name '16_12-byol').Accepted) { - Write-Host "`t`tAccepting Cisco CSR marketplace terms for this subscription..." - Set-AzMarketplaceTerms -Publisher 'cisco' -Product 'cisco-csr-1000v' -Name '16_12-byol' -Accept + try { + If (-Not (Get-AzMarketplaceTerms -Publisher 'cisco' -Product 'cisco-csr-1000v' -Name '16_12-byol').Accepted) { + Write-Host "`t`tAccepting Cisco CSR marketplace terms for this subscription..." + Set-AzMarketplaceTerms -Publisher 'cisco' -Product 'cisco-csr-1000v' -Name '16_12-byol' -Accept + } + } + catch { + throw "An error occured while attempting to accept the markeplace terms for the Cisco CSR deployment. Try running `Set-AzMarketplaceTerms -Publisher 'cisco' -Product 'cisco-csr-1000v' -Name '16_12-byol' -Accept` in Cloud Shell for the target subscription. Error: $_" } - #update csr bootstrap file $csrConfigContent = Get-Content -Path .\csrScript.txt $updatedCsrConfigContent = $csrConfigContent @@ -112,14 +132,24 @@ switch ($challengeNumber) { #deploy resources $onPremJob = New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-onprem' -TemplateFile ./01-03-onprem.bicep -TemplateParameterObject @{vmPassword = $vmPassword } -AsJob - $onPremJob | Wait-Job + $onPremJob | Wait-Job | Out-Null + + # check for deployment errors + If ($onPremJob.Error) { + Write-Error "A on-prem infrastructure deployment experienced an error: $($job.error)" + } Write-Host "`tConfiguring VPN resources..." $vpnJobs = @() $vpnJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./01-04-hubvpnconfig.bicep -AsJob - $vpnJobs | Wait-Job -Timeout 600 + $vpnJobs | Wait-Job -Timeout 600 | Out-Null + + # check for deployment errors + If ($vpnJobs.Error) { + Write-Error "A VPN resource/configuration deployment experienced an error: $($job.error)" + } } 2 { Write-Host "Deploying resources for Challenge 2: Azure Firewall" @@ -127,12 +157,22 @@ switch ($challengeNumber) { Write-Host "`tDeploying Azure Firewall and related hub resources..." $afwJob = New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./02-00-afw.bicep -AsJob - $afwJob | Wait-Job + $afwJob | Wait-Job | Out-Null + + # check for deployment errors + If ($afwJob.Error) { + Write-Error "The Azure Firewall deployment experienced an error: $($job.error)" + } Write-Host "`tDeploying firewall policies..." $fwpolJob = New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./02-01-fwpolicyrules.bicep -AsJob - $fwpolJob | Wait-Job + $fwpolJob | Wait-Job | Out-Null + + # check for deployment errors + If ($fwpolJob.Error) { + Write-Error "The Firewall Policy deployment experienced an error: $($job.error)" + } Write-Host "`tDeploying updated hub, spoke, and on-prem configs..." $jobs = @() @@ -141,7 +181,15 @@ switch ($challengeNumber) { $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./02-01-hub.bicep -AsJob $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-onprem' -TemplateFile ./02-01-onprem.bicep -AsJob - $jobs | Wait-Job + $jobs | Wait-Job | Out-Null + + # check for deployment errors + $jobs | Foreach-Object { + $job = $_ + If ($job.Error) { + Write-Error "A hub or spoke configuration deployment (to enable AFW) experienced an error: $($job.error)" + } + } } 3 {} 4 {} From 1d8a8cfb034f75858758228050ff4678a08242a5 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Mon, 1 Aug 2022 15:01:14 -0600 Subject: [PATCH 31/76] location param --- .../Student/Resources/bicep/README.md | 14 +++++++++- .../Student/Resources/bicep/deployBicep.ps1 | 28 +++++++++---------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/README.md b/035-HubAndSpoke/Student/Resources/bicep/README.md index 3060c1fadf..22af4702b6 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/README.md +++ b/035-HubAndSpoke/Student/Resources/bicep/README.md @@ -12,15 +12,27 @@ The WTH philosophy intends to have students learn by doing, and recognizes that ## Using these templates -Using Cloud Shell is recommended, as it already has the necessary tools installed. +Using Cloud Shell is recommended, as it already has the necessary tools installed. However, Cloud Shell has a timeout of about 20 minutes ### Prerequisites - Azure PowerShell module - git +### Download Options + +#### Clone the Git repo (slow) + 1. Clone this repo to your local system or Cloud Shell `git clone https://github.com/microsoft/WhatTheHack.git` 1. Navigate to the `035-HubAndSpoke\Student\Resources\bicep` directory in your clone of the repo +1. Run the deployBicep.ps1 script. For example: + `./deployBicep.ps1 -challengeNumber 1` + +#### Download a zip of the bicep directory + +1. Browse to https://download-directory.github.io/?url=https%3A%2F%2Fgithub.com%2Fmicrosoft%2FWhatTheHack%2Ftree%2Fnetwork-bicep%2F035-HubAndSpoke%2FStudent%2FResources%2Fbicep +1. A zip of the directory will download to your system +1. Expand the downloaded zip file and navigate to it in a PowerShell window 1. Run the deployBicep.ps1 script. For example: `./deployBicep.ps1 -challengeNumber 1` \ No newline at end of file diff --git a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 index c352cd504b..5bd4fb9627 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 +++ b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 @@ -69,9 +69,9 @@ switch ($challengeNumber) { Write-Host "`tDeploying base resources (this will take up to 60 minutes for the VNET Gateway)..." $baseInfraJobs = @{} - $baseInfraJobs += @{'wth-rg-spoke1' = (New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./01-01-spoke1.bicep -TemplateParameterObject @{vmPassword = $vmPassword } -AsJob)} - $baseInfraJobs += @{'wth-rg-spoke2' = (New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./01-01-spoke2.bicep -TemplateParameterObject @{vmPassword = $vmPassword } -AsJob)} - $baseInfraJobs += @{'wth-rg-hub' = (New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./01-01-hub.bicep -TemplateParameterObject @{vmPassword = $vmPassword } -AsJob)} + $baseInfraJobs += @{'wth-rg-spoke1' = (New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./01-01-spoke1.bicep -TemplateParameterObject @{vmPassword = $vmPassword; location = $location } -AsJob)} + $baseInfraJobs += @{'wth-rg-spoke2' = (New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./01-01-spoke2.bicep -TemplateParameterObject @{vmPassword = $vmPassword; location = $location } -AsJob)} + $baseInfraJobs += @{'wth-rg-hub' = (New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./01-01-hub.bicep -TemplateParameterObject @{vmPassword = $vmPassword; location = $location } -AsJob)} Write-Host "`tWaiting up to 60 minutes for resources to deploy..." $baseInfraJobs.GetEnumerator().ForEach({$_.Value}) | Wait-Job -Timeout 3600 | Out-Null @@ -92,9 +92,9 @@ switch ($challengeNumber) { Write-Host "`tDeploying VNET Peering..." $peeringJobs = @() - $peeringJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./01-02-vnetpeeringhub.bicep -AsJob - $peeringJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./01-02-vnetpeeringspoke1.bicep -AsJob - $peeringJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./01-02-vnetpeeringspoke2.bicep -AsJob + $peeringJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./01-02-vnetpeeringhub.bicep -TemplateParameterObject @{location = $location } -AsJob + $peeringJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./01-02-vnetpeeringspoke1.bicep -TemplateParameterObject @{location = $location } -AsJob + $peeringJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./01-02-vnetpeeringspoke2.bicep -TemplateParameterObject @{location = $location } -AsJob $peeringJobs | Wait-Job -Timeout 300 | Out-Null @@ -130,7 +130,7 @@ switch ($challengeNumber) { Set-Content -Path .\csrScript.txt.tmp -Value $updatedCsrConfigContent -Force #deploy resources - $onPremJob = New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-onprem' -TemplateFile ./01-03-onprem.bicep -TemplateParameterObject @{vmPassword = $vmPassword } -AsJob + $onPremJob = New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-onprem' -TemplateFile ./01-03-onprem.bicep -TemplateParameterObject @{vmPassword = $vmPassword; location = $location } -AsJob $onPremJob | Wait-Job | Out-Null @@ -142,7 +142,7 @@ switch ($challengeNumber) { Write-Host "`tConfiguring VPN resources..." $vpnJobs = @() - $vpnJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./01-04-hubvpnconfig.bicep -AsJob + $vpnJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./01-04-hubvpnconfig.bicep -TemplateParameterObject @{location = $location } -AsJob $vpnJobs | Wait-Job -Timeout 600 | Out-Null @@ -155,7 +155,7 @@ switch ($challengeNumber) { Write-Host "Deploying resources for Challenge 2: Azure Firewall" Write-Host "`tDeploying Azure Firewall and related hub resources..." - $afwJob = New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./02-00-afw.bicep -AsJob + $afwJob = New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./02-00-afw.bicep -TemplateParameterObject @{location = $location } -AsJob $afwJob | Wait-Job | Out-Null @@ -165,7 +165,7 @@ switch ($challengeNumber) { } Write-Host "`tDeploying firewall policies..." - $fwpolJob = New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./02-01-fwpolicyrules.bicep -AsJob + $fwpolJob = New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./02-01-fwpolicyrules.bicep -TemplateParameterObject @{location = $location } -AsJob $fwpolJob | Wait-Job | Out-Null @@ -176,10 +176,10 @@ switch ($challengeNumber) { Write-Host "`tDeploying updated hub, spoke, and on-prem configs..." $jobs = @() - $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./02-01-spoke1.bicep -AsJob - $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./02-01-spoke2.bicep -AsJob - $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./02-01-hub.bicep -AsJob - $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-onprem' -TemplateFile ./02-01-onprem.bicep -AsJob + $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./02-01-spoke1.bicep -TemplateParameterObject @{location = $location } -AsJob + $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./02-01-spoke2.bicep -TemplateParameterObject @{location = $location } -AsJob + $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./02-01-hub.bicep -TemplateParameterObject @{location = $location } -AsJob + $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-onprem' -TemplateFile ./02-01-onprem.bicep -TemplateParameterObject @{location = $location } -AsJob $jobs | Wait-Job | Out-Null From 05b4f732bf1f8f896a9d5ebc38a904dbcae7cc69 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Mon, 1 Aug 2022 16:02:05 -0600 Subject: [PATCH 32/76] location param --- 035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 index 5bd4fb9627..3837cd6094 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 +++ b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 @@ -92,9 +92,9 @@ switch ($challengeNumber) { Write-Host "`tDeploying VNET Peering..." $peeringJobs = @() - $peeringJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./01-02-vnetpeeringhub.bicep -TemplateParameterObject @{location = $location } -AsJob - $peeringJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./01-02-vnetpeeringspoke1.bicep -TemplateParameterObject @{location = $location } -AsJob - $peeringJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./01-02-vnetpeeringspoke2.bicep -TemplateParameterObject @{location = $location } -AsJob + $peeringJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./01-02-vnetpeeringhub.bicep -TemplateParameterObject @{} -AsJob + $peeringJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./01-02-vnetpeeringspoke1.bicep -TemplateParameterObject @{} -AsJob + $peeringJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./01-02-vnetpeeringspoke2.bicep -TemplateParameterObject @{} -AsJob $peeringJobs | Wait-Job -Timeout 300 | Out-Null From 9e3548e0472408934fe8947b31cb7c86bbd44f99 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Tue, 2 Aug 2022 13:55:16 -0600 Subject: [PATCH 33/76] error messages --- 035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 index 3837cd6094..cffcaf1888 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 +++ b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 @@ -136,7 +136,7 @@ switch ($challengeNumber) { # check for deployment errors If ($onPremJob.Error) { - Write-Error "A on-prem infrastructure deployment experienced an error: $($job.error)" + Write-Error "A on-prem infrastructure deployment experienced an error: $($onPremJob.error)" } Write-Host "`tConfiguring VPN resources..." @@ -148,7 +148,7 @@ switch ($challengeNumber) { # check for deployment errors If ($vpnJobs.Error) { - Write-Error "A VPN resource/configuration deployment experienced an error: $($job.error)" + Write-Error "A VPN resource/configuration deployment experienced an error: $($vpnJobs.error)" } } 2 { @@ -161,7 +161,7 @@ switch ($challengeNumber) { # check for deployment errors If ($afwJob.Error) { - Write-Error "The Azure Firewall deployment experienced an error: $($job.error)" + Write-Error "The Azure Firewall deployment experienced an error: $($afwJob.error)" } Write-Host "`tDeploying firewall policies..." @@ -171,7 +171,7 @@ switch ($challengeNumber) { # check for deployment errors If ($fwpolJob.Error) { - Write-Error "The Firewall Policy deployment experienced an error: $($job.error)" + Write-Error "The Firewall Policy deployment experienced an error: $($fwpolJob.error)" } Write-Host "`tDeploying updated hub, spoke, and on-prem configs..." From 368ba7a46875c48ae306c9f9c2cbc18c2e6f4c42 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Thu, 4 Aug 2022 12:33:13 -0600 Subject: [PATCH 34/76] removed location param from fwpol --- 035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 index cffcaf1888..e984f5079f 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 +++ b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 @@ -165,7 +165,7 @@ switch ($challengeNumber) { } Write-Host "`tDeploying firewall policies..." - $fwpolJob = New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./02-01-fwpolicyrules.bicep -TemplateParameterObject @{location = $location } -AsJob + $fwpolJob = New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./02-01-fwpolicyrules.bicep -TemplateParameterObject @{} -AsJob $fwpolJob | Wait-Job | Out-Null From 945a96765515da9f983b098c818af6e773d8f52b Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Fri, 5 Aug 2022 08:13:34 -0600 Subject: [PATCH 35/76] switch to run-command for inspector gaget --- .../Student/Resources/bicep/02-01-hub.bicep | 16 ++++++++-------- .../Student/Resources/bicep/02-01-onprem.bicep | 16 ++++++++-------- .../Student/Resources/bicep/02-01-spoke1.bicep | 16 ++++++++-------- .../Student/Resources/bicep/02-01-spoke2.bicep | 16 ++++++++-------- .../Student/Resources/bicep/README.md | 2 +- 5 files changed, 33 insertions(+), 33 deletions(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-01-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/02-01-hub.bicep index 7b2f50d6da..ea59870ba3 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/02-01-hub.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/02-01-hub.bicep @@ -37,15 +37,14 @@ resource rthubvms 'Microsoft.Network/routeTables@2022-01-01' = { } } -resource installinspectorgadget 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' = { - name: '${wthhubvm01.name}/wth-vmextn-installinspectorgadget' +resource installinspectorgadget 'Microsoft.Compute/virtualMachines/runCommands@2022-03-01' = { + name: '${wthhubvm01.name}/wth-runcmd-installinspectorgadget' location: location properties: { - publisher: 'Microsoft.Compute' - type: 'CustomScriptExtension' - typeHandlerVersion: '1.10' - settings: { - /* + asyncExecution: true + source: { + commandId: 'RunPowerShellScript' + /* To generate encoded command in PowerShell: $s = @' @@ -54,7 +53,8 @@ resource installinspectorgadget 'Microsoft.Compute/virtualMachines/extensions@20 '@ $bytes = [System.Text.Encoding]::Unicode.GetBytes($s) [convert]::ToBase64String($bytes) */ - commandToExecute: 'powershell.exe -ep bypass -encodedcommand IAAgACAAIAAgACAAIAAgAEkAbgBzAHQAYQBsAGwALQBXAGkAbgBkAG8AdwBzAEYAZQBhAHQAdQByAGUAIABXAGUAYgAtAFMAZQByAHYAZQByACwAVwBlAGIALQBBAHMAcAAtAE4AZQB0ADQANQAgAC0ASQBuAGMAbAB1AGQAZQBNAGEAbgBhAGcAZQBtAGUAbgB0AFQAbwBvAGwAcwAKACAAIAAgACAAIAAgACAAIABbAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdABdADoAOgBuAGUAdwAoACkALgBEAG8AdwBuAGwAbwBhAGQARgBpAGwAZQAoACcAaAB0AHQAcABzADoALwAvAHIAYQB3AC4AZwBpAHQAaAB1AGIAdQBzAGUAcgBjAG8AbgB0AGUAbgB0AC4AYwBvAG0ALwBqAGUAbABsAGUAZAByAHUAeQB0AHMALwBJAG4AcwBwAGUAYwB0AG8AcgBHAGEAZABnAGUAdAAvAG0AYQBpAG4ALwBQAGEAZwBlAC8AZABlAGYAYQB1AGwAdAAuAGEAcwBwAHgAJwAsACcAYwA6AFwAaQBuAGUAdABwAHUAYgBcAHcAdwB3AHIAbwBvAHQAXABkAGUAZgBhAHUAbAB0AC4AYQBzAHAAeAAnACkA' + script: 'powershell.exe -ep bypass -encodedcommand IAAgACAAIAAgACAAIAAgAEkAbgBzAHQAYQBsAGwALQBXAGkAbgBkAG8AdwBzAEYAZQBhAHQAdQByAGUAIABXAGUAYgAtAFMAZQByAHYAZQByACwAVwBlAGIALQBBAHMAcAAtAE4AZQB0ADQANQAgAC0ASQBuAGMAbAB1AGQAZQBNAGEAbgBhAGcAZQBtAGUAbgB0AFQAbwBvAGwAcwAKACAAIAAgACAAIAAgACAAIABbAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdABdADoAOgBuAGUAdwAoACkALgBEAG8AdwBuAGwAbwBhAGQARgBpAGwAZQAoACcAaAB0AHQAcABzADoALwAvAHIAYQB3AC4AZwBpAHQAaAB1AGIAdQBzAGUAcgBjAG8AbgB0AGUAbgB0AC4AYwBvAG0ALwBqAGUAbABsAGUAZAByAHUAeQB0AHMALwBJAG4AcwBwAGUAYwB0AG8AcgBHAGEAZABnAGUAdAAvAG0AYQBpAG4ALwBQAGEAZwBlAC8AZABlAGYAYQB1AGwAdAAuAGEAcwBwAHgAJwAsACcAYwA6AFwAaQBuAGUAdABwAHUAYgBcAHcAdwB3AHIAbwBvAHQAXABkAGUAZgBhAHUAbAB0AC4AYQBzAHAAeAAnACkA' } + timeoutInSeconds: 600 } } diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-01-onprem.bicep b/035-HubAndSpoke/Student/Resources/bicep/02-01-onprem.bicep index 30339547c7..7977c2cf64 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/02-01-onprem.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/02-01-onprem.bicep @@ -6,15 +6,14 @@ resource wthonpremvm01 'Microsoft.Compute/virtualMachines@2022-03-01' existing = scope: resourceGroup('wth-rg-onprem') } -resource installinspectorgadget 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' = { - name: '${wthonpremvm01.name}/wth-vmextn-installinspectorgadget' +resource installinspectorgadget 'Microsoft.Compute/virtualMachines/runCommands@2022-03-01' = { + name: '${wthonpremvm01.name}/wth-runcmd-installinspectorgadget' location: location properties: { - publisher: 'Microsoft.Compute' - type: 'CustomScriptExtension' - typeHandlerVersion: '1.10' - settings: { - /* + asyncExecution: true + source: { + commandId: 'RunPowerShellScript' + /* To generate encoded command in PowerShell: $s = @' @@ -23,7 +22,8 @@ resource installinspectorgadget 'Microsoft.Compute/virtualMachines/extensions@20 '@ $bytes = [System.Text.Encoding]::Unicode.GetBytes($s) [convert]::ToBase64String($bytes) */ - commandToExecute: 'powershell.exe -ep bypass -encodedcommand IAAgACAAIAAgACAAIAAgAEkAbgBzAHQAYQBsAGwALQBXAGkAbgBkAG8AdwBzAEYAZQBhAHQAdQByAGUAIABXAGUAYgAtAFMAZQByAHYAZQByACwAVwBlAGIALQBBAHMAcAAtAE4AZQB0ADQANQAgAC0ASQBuAGMAbAB1AGQAZQBNAGEAbgBhAGcAZQBtAGUAbgB0AFQAbwBvAGwAcwAKACAAIAAgACAAIAAgACAAIABbAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdABdADoAOgBuAGUAdwAoACkALgBEAG8AdwBuAGwAbwBhAGQARgBpAGwAZQAoACcAaAB0AHQAcABzADoALwAvAHIAYQB3AC4AZwBpAHQAaAB1AGIAdQBzAGUAcgBjAG8AbgB0AGUAbgB0AC4AYwBvAG0ALwBqAGUAbABsAGUAZAByAHUAeQB0AHMALwBJAG4AcwBwAGUAYwB0AG8AcgBHAGEAZABnAGUAdAAvAG0AYQBpAG4ALwBQAGEAZwBlAC8AZABlAGYAYQB1AGwAdAAuAGEAcwBwAHgAJwAsACcAYwA6AFwAaQBuAGUAdABwAHUAYgBcAHcAdwB3AHIAbwBvAHQAXABkAGUAZgBhAHUAbAB0AC4AYQBzAHAAeAAnACkA' + script: 'powershell.exe -ep bypass -encodedcommand IAAgACAAIAAgACAAIAAgAEkAbgBzAHQAYQBsAGwALQBXAGkAbgBkAG8AdwBzAEYAZQBhAHQAdQByAGUAIABXAGUAYgAtAFMAZQByAHYAZQByACwAVwBlAGIALQBBAHMAcAAtAE4AZQB0ADQANQAgAC0ASQBuAGMAbAB1AGQAZQBNAGEAbgBhAGcAZQBtAGUAbgB0AFQAbwBvAGwAcwAKACAAIAAgACAAIAAgACAAIABbAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdABdADoAOgBuAGUAdwAoACkALgBEAG8AdwBuAGwAbwBhAGQARgBpAGwAZQAoACcAaAB0AHQAcABzADoALwAvAHIAYQB3AC4AZwBpAHQAaAB1AGIAdQBzAGUAcgBjAG8AbgB0AGUAbgB0AC4AYwBvAG0ALwBqAGUAbABsAGUAZAByAHUAeQB0AHMALwBJAG4AcwBwAGUAYwB0AG8AcgBHAGEAZABnAGUAdAAvAG0AYQBpAG4ALwBQAGEAZwBlAC8AZABlAGYAYQB1AGwAdAAuAGEAcwBwAHgAJwAsACcAYwA6AFwAaQBuAGUAdABwAHUAYgBcAHcAdwB3AHIAbwBvAHQAXABkAGUAZgBhAHUAbAB0AC4AYQBzAHAAeAAnACkA' } + timeoutInSeconds: 600 } } diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke1.bicep index bb54f54154..536f36201c 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke1.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke1.bicep @@ -29,15 +29,14 @@ resource rtspoke1vms 'Microsoft.Network/routeTables@2022-01-01' = { } } -resource installinspectorgadget 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' = { - name: '${wthspoke1vm01.name}/wth-vmextn-installinspectorgadget' +resource installinspectorgadget 'Microsoft.Compute/virtualMachines/runCommands@2022-03-01' = { + name: '${wthspoke1vm01.name}/wth-runcmd-installinspectorgadget' location: location properties: { - publisher: 'Microsoft.Compute' - type: 'CustomScriptExtension' - typeHandlerVersion: '1.10' - settings: { - /* + asyncExecution: true + source: { + commandId: 'RunPowerShellScript' + /* To generate encoded command in PowerShell: $s = @' @@ -46,7 +45,8 @@ resource installinspectorgadget 'Microsoft.Compute/virtualMachines/extensions@20 '@ $bytes = [System.Text.Encoding]::Unicode.GetBytes($s) [convert]::ToBase64String($bytes) */ - commandToExecute: 'powershell.exe -ep bypass -encodedcommand IAAgACAAIAAgACAAIAAgAEkAbgBzAHQAYQBsAGwALQBXAGkAbgBkAG8AdwBzAEYAZQBhAHQAdQByAGUAIABXAGUAYgAtAFMAZQByAHYAZQByACwAVwBlAGIALQBBAHMAcAAtAE4AZQB0ADQANQAgAC0ASQBuAGMAbAB1AGQAZQBNAGEAbgBhAGcAZQBtAGUAbgB0AFQAbwBvAGwAcwAKACAAIAAgACAAIAAgACAAIABbAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdABdADoAOgBuAGUAdwAoACkALgBEAG8AdwBuAGwAbwBhAGQARgBpAGwAZQAoACcAaAB0AHQAcABzADoALwAvAHIAYQB3AC4AZwBpAHQAaAB1AGIAdQBzAGUAcgBjAG8AbgB0AGUAbgB0AC4AYwBvAG0ALwBqAGUAbABsAGUAZAByAHUAeQB0AHMALwBJAG4AcwBwAGUAYwB0AG8AcgBHAGEAZABnAGUAdAAvAG0AYQBpAG4ALwBQAGEAZwBlAC8AZABlAGYAYQB1AGwAdAAuAGEAcwBwAHgAJwAsACcAYwA6AFwAaQBuAGUAdABwAHUAYgBcAHcAdwB3AHIAbwBvAHQAXABkAGUAZgBhAHUAbAB0AC4AYQBzAHAAeAAnACkA' + script: 'powershell.exe -ep bypass -encodedcommand IAAgACAAIAAgACAAIAAgAEkAbgBzAHQAYQBsAGwALQBXAGkAbgBkAG8AdwBzAEYAZQBhAHQAdQByAGUAIABXAGUAYgAtAFMAZQByAHYAZQByACwAVwBlAGIALQBBAHMAcAAtAE4AZQB0ADQANQAgAC0ASQBuAGMAbAB1AGQAZQBNAGEAbgBhAGcAZQBtAGUAbgB0AFQAbwBvAGwAcwAKACAAIAAgACAAIAAgACAAIABbAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdABdADoAOgBuAGUAdwAoACkALgBEAG8AdwBuAGwAbwBhAGQARgBpAGwAZQAoACcAaAB0AHQAcABzADoALwAvAHIAYQB3AC4AZwBpAHQAaAB1AGIAdQBzAGUAcgBjAG8AbgB0AGUAbgB0AC4AYwBvAG0ALwBqAGUAbABsAGUAZAByAHUAeQB0AHMALwBJAG4AcwBwAGUAYwB0AG8AcgBHAGEAZABnAGUAdAAvAG0AYQBpAG4ALwBQAGEAZwBlAC8AZABlAGYAYQB1AGwAdAAuAGEAcwBwAHgAJwAsACcAYwA6AFwAaQBuAGUAdABwAHUAYgBcAHcAdwB3AHIAbwBvAHQAXABkAGUAZgBhAHUAbAB0AC4AYQBzAHAAeAAnACkA' } + timeoutInSeconds: 600 } } diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke2.bicep b/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke2.bicep index 58d1019ef7..25ee751ac9 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke2.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke2.bicep @@ -29,15 +29,14 @@ resource rtspoke2vms 'Microsoft.Network/routeTables@2022-01-01' = { } } -resource installinspectorgadget 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' = { - name: '${wthspoke2vm01.name}/wth-vmextn-installinspectorgadget' +resource installinspectorgadget 'Microsoft.Compute/virtualMachines/runCommands@2022-03-01' = { + name: '${wthspoke2vm01.name}/wth-runcmd-installinspectorgadget' location: location properties: { - publisher: 'Microsoft.Compute' - type: 'CustomScriptExtension' - typeHandlerVersion: '1.10' - settings: { - /* + asyncExecution: true + source: { + commandId: 'RunPowerShellScript' + /* To generate encoded command in PowerShell: $s = @' @@ -46,7 +45,8 @@ resource installinspectorgadget 'Microsoft.Compute/virtualMachines/extensions@20 '@ $bytes = [System.Text.Encoding]::Unicode.GetBytes($s) [convert]::ToBase64String($bytes) */ - commandToExecute: 'powershell.exe -ep bypass -encodedcommand IAAgACAAIAAgACAAIAAgAEkAbgBzAHQAYQBsAGwALQBXAGkAbgBkAG8AdwBzAEYAZQBhAHQAdQByAGUAIABXAGUAYgAtAFMAZQByAHYAZQByACwAVwBlAGIALQBBAHMAcAAtAE4AZQB0ADQANQAgAC0ASQBuAGMAbAB1AGQAZQBNAGEAbgBhAGcAZQBtAGUAbgB0AFQAbwBvAGwAcwAKACAAIAAgACAAIAAgACAAIABbAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdABdADoAOgBuAGUAdwAoACkALgBEAG8AdwBuAGwAbwBhAGQARgBpAGwAZQAoACcAaAB0AHQAcABzADoALwAvAHIAYQB3AC4AZwBpAHQAaAB1AGIAdQBzAGUAcgBjAG8AbgB0AGUAbgB0AC4AYwBvAG0ALwBqAGUAbABsAGUAZAByAHUAeQB0AHMALwBJAG4AcwBwAGUAYwB0AG8AcgBHAGEAZABnAGUAdAAvAG0AYQBpAG4ALwBQAGEAZwBlAC8AZABlAGYAYQB1AGwAdAAuAGEAcwBwAHgAJwAsACcAYwA6AFwAaQBuAGUAdABwAHUAYgBcAHcAdwB3AHIAbwBvAHQAXABkAGUAZgBhAHUAbAB0AC4AYQBzAHAAeAAnACkA' + script: 'powershell.exe -ep bypass -encodedcommand IAAgACAAIAAgACAAIAAgAEkAbgBzAHQAYQBsAGwALQBXAGkAbgBkAG8AdwBzAEYAZQBhAHQAdQByAGUAIABXAGUAYgAtAFMAZQByAHYAZQByACwAVwBlAGIALQBBAHMAcAAtAE4AZQB0ADQANQAgAC0ASQBuAGMAbAB1AGQAZQBNAGEAbgBhAGcAZQBtAGUAbgB0AFQAbwBvAGwAcwAKACAAIAAgACAAIAAgACAAIABbAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdABdADoAOgBuAGUAdwAoACkALgBEAG8AdwBuAGwAbwBhAGQARgBpAGwAZQAoACcAaAB0AHQAcABzADoALwAvAHIAYQB3AC4AZwBpAHQAaAB1AGIAdQBzAGUAcgBjAG8AbgB0AGUAbgB0AC4AYwBvAG0ALwBqAGUAbABsAGUAZAByAHUAeQB0AHMALwBJAG4AcwBwAGUAYwB0AG8AcgBHAGEAZABnAGUAdAAvAG0AYQBpAG4ALwBQAGEAZwBlAC8AZABlAGYAYQB1AGwAdAAuAGEAcwBwAHgAJwAsACcAYwA6AFwAaQBuAGUAdABwAHUAYgBcAHcAdwB3AHIAbwBvAHQAXABkAGUAZgBhAHUAbAB0AC4AYQBzAHAAeAAnACkA' } + timeoutInSeconds: 600 } } diff --git a/035-HubAndSpoke/Student/Resources/bicep/README.md b/035-HubAndSpoke/Student/Resources/bicep/README.md index 22af4702b6..80533315dc 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/README.md +++ b/035-HubAndSpoke/Student/Resources/bicep/README.md @@ -12,7 +12,7 @@ The WTH philosophy intends to have students learn by doing, and recognizes that ## Using these templates -Using Cloud Shell is recommended, as it already has the necessary tools installed. However, Cloud Shell has a timeout of about 20 minutes +Using Cloud Shell is recommended, as it already has the necessary tools installed. However, Cloud Shell has a timeout of about 20 minutes and may experience timeouts (in which case, run the same command again to pick up the deployments where they stopped). ### Prerequisites From 0ea4b55fd28b3c13427d3deb65e6ce5d5156b28c Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Fri, 5 Aug 2022 08:26:53 -0600 Subject: [PATCH 36/76] run-command remove commandid --- 035-HubAndSpoke/Student/Resources/bicep/02-01-hub.bicep | 2 +- 035-HubAndSpoke/Student/Resources/bicep/02-01-onprem.bicep | 2 +- 035-HubAndSpoke/Student/Resources/bicep/02-01-spoke1.bicep | 2 +- 035-HubAndSpoke/Student/Resources/bicep/02-01-spoke2.bicep | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-01-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/02-01-hub.bicep index ea59870ba3..9d3e98d02a 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/02-01-hub.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/02-01-hub.bicep @@ -43,7 +43,7 @@ resource installinspectorgadget 'Microsoft.Compute/virtualMachines/runCommands@2 properties: { asyncExecution: true source: { - commandId: 'RunPowerShellScript' + /* To generate encoded command in PowerShell: diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-01-onprem.bicep b/035-HubAndSpoke/Student/Resources/bicep/02-01-onprem.bicep index 7977c2cf64..397a33cff2 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/02-01-onprem.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/02-01-onprem.bicep @@ -12,7 +12,7 @@ resource installinspectorgadget 'Microsoft.Compute/virtualMachines/runCommands@2 properties: { asyncExecution: true source: { - commandId: 'RunPowerShellScript' + /* To generate encoded command in PowerShell: diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke1.bicep index 536f36201c..21b772d965 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke1.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke1.bicep @@ -35,7 +35,7 @@ resource installinspectorgadget 'Microsoft.Compute/virtualMachines/runCommands@2 properties: { asyncExecution: true source: { - commandId: 'RunPowerShellScript' + /* To generate encoded command in PowerShell: diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke2.bicep b/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke2.bicep index 25ee751ac9..ea70c7dc35 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke2.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke2.bicep @@ -35,7 +35,7 @@ resource installinspectorgadget 'Microsoft.Compute/virtualMachines/runCommands@2 properties: { asyncExecution: true source: { - commandId: 'RunPowerShellScript' + /* To generate encoded command in PowerShell: From 90de98b550769619584dbfc4b31f532ae2fa07bd Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Fri, 5 Aug 2022 08:35:15 -0600 Subject: [PATCH 37/76] clarify username --- 035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 index e984f5079f..104c4b9ffb 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 +++ b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 @@ -61,7 +61,7 @@ switch ($challengeNumber) { Write-Host "Deploying resources for Challenge 1: Hub-and-spoke Basics" If (-NOT ($vmPassword)) { - $vmPassword = Read-Host "Enter (and make note of) a complex password which will be used for all deployed VMs" -AsSecureString + $vmPassword = Read-Host "Enter (and make note of) a complex password which will be used for all deployed VMs (username will be 'admin-wth')" -AsSecureString } Write-Host "`tDeploying resource groups..." From 34094910f2df28eb7b89bd1f289cafbdedb4a94f Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Fri, 5 Aug 2022 08:52:43 -0600 Subject: [PATCH 38/76] deployed resources documentation --- .../Student/Resources/bicep/README.md | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/README.md b/035-HubAndSpoke/Student/Resources/bicep/README.md index 80533315dc..77c4e98465 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/README.md +++ b/035-HubAndSpoke/Student/Resources/bicep/README.md @@ -35,4 +35,27 @@ Using Cloud Shell is recommended, as it already has the necessary tools installe 1. A zip of the directory will download to your system 1. Expand the downloaded zip file and navigate to it in a PowerShell window 1. Run the deployBicep.ps1 script. For example: - `./deployBicep.ps1 -challengeNumber 1` \ No newline at end of file + `./deployBicep.ps1 -challengeNumber 1` + +## Deployed Configuration + +### Challenge 1 + +- Windows VMs are deployed in the hub, both spokes, and on-prem Resource Groups +- VM usernames are 'admin-wth' and passwords are the one supplied when executing the script +- All Windows VMs have associated Public IP Addresses and are accessible via RDP using alternate port 33899 (ex: `mstsc /v:4.32.1.5:33899`) +- The Cisco CSR deployed in the 'wth-rg-onprem' Resource Group uses the same username and password, but is not accessible from the internet. To access it, RDP to the Windows VM in the onprem Resource Group, then connect to the CSR using ssh and its private IP address + +### Challenge 2 + +- With Azure Firewall deployed and traffic routing through it following the Challenge, the Windows VMs are no longer directly accessible via Public IP. Use the Azure Firewall public IP with the following DNAT port mapping: + - Hub: 33980 + - Spoke 1: 33891 + - Spoke 2: 33892 + - On-prem (still accessible by Public IP and custom 33899 RDP port) + +- All Windows VMs have a diagnostic website configured in IIS called Inspector Gadget. To access it locally, browse to `http://localhost/default.aspx`. Web server DNAT through the Azure Firewall uses the following port mapping: + + - Hub: 8080 + - Spoke 1: 8081 + - Spoke 2: 8082 From 9499d8efc80e4805eaee64f9fdb56bef32127db9 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Tue, 13 Sep 2022 10:48:01 -0600 Subject: [PATCH 39/76] challenge 3 --- .../Student/Resources/bicep/03-01-hub.bicep | 41 +++++++++++++++++++ .../Resources/bicep/03-01-spoke1.bicep | 34 +++++++++++++++ .../Resources/bicep/03-01-spoke2.bicep | 25 +++++++++++ .../Student/Resources/bicep/README.md | 4 ++ .../Student/Resources/bicep/deployBicep.ps1 | 20 ++++++++- 5 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 035-HubAndSpoke/Student/Resources/bicep/03-01-hub.bicep create mode 100644 035-HubAndSpoke/Student/Resources/bicep/03-01-spoke1.bicep create mode 100644 035-HubAndSpoke/Student/Resources/bicep/03-01-spoke2.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/03-01-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/03-01-hub.bicep new file mode 100644 index 0000000000..45659731e3 --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/03-01-hub.bicep @@ -0,0 +1,41 @@ +param location string = 'eastus2' + +resource wthafw 'Microsoft.Network/azureFirewalls@2022-01-01' existing = { + name: 'wth-afw-hub01' + scope: resourceGroup('wth-rg-hub') +} + +resource rthubvms 'Microsoft.Network/routeTables@2022-01-01' = { + name: 'wth-rt-hubvmssubnet' + location: location + properties: { + routes: [ + { + name: 'route-all-to-afw' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress + + } + } + { + name: 'route-spoke1-to-afw' + properties: { + addressPrefix: '10.1.0.0/16' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress + } + } + { + name: 'route-spoke2-to-afw' + properties: { + addressPrefix: '10.2.0.0/16' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress + } + } + ] + disableBgpRoutePropagation: true + } +} diff --git a/035-HubAndSpoke/Student/Resources/bicep/03-01-spoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/03-01-spoke1.bicep new file mode 100644 index 0000000000..906a45c8ae --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/03-01-spoke1.bicep @@ -0,0 +1,34 @@ +param location string = 'eastus2' + +resource wthafw 'Microsoft.Network/azureFirewalls@2022-01-01' existing = { + name: 'wth-afw-hub01' + scope: resourceGroup('wth-rg-hub') +} + +resource rtspoke1vms 'Microsoft.Network/routeTables@2022-01-01' = { + name: 'wth-rt-spoke1vmssubnet' + location: location + properties: { + routes: [ + { + name: 'route-all-to-afw' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress + + } + } + { + name: 'route-hubvnet-to-afw' + properties: { + addressPrefix: '10.0.0.0/16' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress + + } + } + ] + disableBgpRoutePropagation: true + } +} diff --git a/035-HubAndSpoke/Student/Resources/bicep/03-01-spoke2.bicep b/035-HubAndSpoke/Student/Resources/bicep/03-01-spoke2.bicep new file mode 100644 index 0000000000..228555e99c --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/03-01-spoke2.bicep @@ -0,0 +1,25 @@ +param location string = 'eastus2' + +resource wthafw 'Microsoft.Network/azureFirewalls@2022-01-01' existing = { + name: 'wth-afw-hub01' + scope: resourceGroup('wth-rg-hub') +} + +resource rtspoke2vms 'Microsoft.Network/routeTables@2022-01-01' = { + name: 'wth-rt-spoke2vmssubnet' + location: location + properties: { + routes: [ + { + name: 'route-all-to-afw' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress + + } + } + ] + disableBgpRoutePropagation: true + } +} diff --git a/035-HubAndSpoke/Student/Resources/bicep/README.md b/035-HubAndSpoke/Student/Resources/bicep/README.md index 77c4e98465..355432166e 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/README.md +++ b/035-HubAndSpoke/Student/Resources/bicep/README.md @@ -43,6 +43,7 @@ Using Cloud Shell is recommended, as it already has the necessary tools installe - Windows VMs are deployed in the hub, both spokes, and on-prem Resource Groups - VM usernames are 'admin-wth' and passwords are the one supplied when executing the script +- Windows VM firewalls have been modified to allow Ping traffic - All Windows VMs have associated Public IP Addresses and are accessible via RDP using alternate port 33899 (ex: `mstsc /v:4.32.1.5:33899`) - The Cisco CSR deployed in the 'wth-rg-onprem' Resource Group uses the same username and password, but is not accessible from the internet. To access it, RDP to the Windows VM in the onprem Resource Group, then connect to the CSR using ssh and its private IP address @@ -59,3 +60,6 @@ Using Cloud Shell is recommended, as it already has the necessary tools installe - Hub: 8080 - Spoke 1: 8081 - Spoke 2: 8082 + +## Resource Cleanup + diff --git a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 index 104c4b9ffb..62f24a7912 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 +++ b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 @@ -191,7 +191,25 @@ switch ($challengeNumber) { } } } - 3 {} + 3 { + Write-Host "Deploying resources for Challenge 3: Asymmetric Routes" + + Write-Host "`tDeploying updated hub and spoke route configs..." + $jobs = @() + $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./03-01-spoke1.bicep -TemplateParameterObject @{location = $location } -AsJob + $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./03-01-spoke2.bicep -TemplateParameterObject @{location = $location } -AsJob + $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./03-01-hub.bicep -TemplateParameterObject @{location = $location } -AsJob + + $jobs | Wait-Job | Out-Null + + # check for deployment errors + $jobs | Foreach-Object { + $job = $_ + If ($job.Error) { + Write-Error "A hub or spoke configuration deployment experienced an error: $($job.error)" + } + } + } 4 {} 5 {} 6 {} From cbea0af2e7b790ff36e287294501ea70ceb6d31f Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Tue, 13 Sep 2022 10:51:35 -0600 Subject: [PATCH 40/76] unused resource refs cleanup --- 035-HubAndSpoke/Student/Resources/bicep/02-00-afw.bicep | 5 ----- .../Student/Resources/bicep/02-01-fwpolicyrules.bicep | 5 ----- 2 files changed, 10 deletions(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-00-afw.bicep b/035-HubAndSpoke/Student/Resources/bicep/02-00-afw.bicep index 47f5e42156..be0304bf94 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/02-00-afw.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/02-00-afw.bicep @@ -5,11 +5,6 @@ resource hubvnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { scope: resourceGroup('wth-rg-hub') } -resource wthrthubvmssubnet 'Microsoft.Network/routeTables@2022-01-01' existing = { - name: 'wth-rt-hubvmssubnet' - scope: resourceGroup('wth-rg-hub') -} - resource afwsubnet 'Microsoft.Network/virtualNetworks/subnets@2022-01-01' = { name: '${hubvnet.name}/AzureFirewallSubnet' properties: { diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-01-fwpolicyrules.bicep b/035-HubAndSpoke/Student/Resources/bicep/02-01-fwpolicyrules.bicep index d0e148d384..55a2c87fdd 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/02-01-fwpolicyrules.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/02-01-fwpolicyrules.bicep @@ -3,11 +3,6 @@ resource wthafwpolicy 'Microsoft.Network/firewallPolicies@2022-01-01' existing = scope: resourceGroup('wth-rg-hub') } -resource wthafw 'Microsoft.Network/azureFirewalls@2022-01-01' existing = { - name: 'wth-afw-hub01' - scope: resourceGroup('wth-rg-hub') -} - resource wthafwpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' existing = { name: 'wth-pip-afw01' scope: resourceGroup('wth-rg-hub') From 2df463865577e61ffce7a4fccaab273854001549 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Wed, 14 Sep 2022 09:32:15 -0600 Subject: [PATCH 41/76] wip: challenge 4 --- .../Student/Resources/bicep/04-01-hub.bicep | 307 ++++++++++++++++++ .../Student/Resources/bicep/deployBicep.ps1 | 20 +- 2 files changed, 326 insertions(+), 1 deletion(-) create mode 100644 035-HubAndSpoke/Student/Resources/bicep/04-01-hub.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/04-01-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/04-01-hub.bicep new file mode 100644 index 0000000000..bba506bb6a --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/04-01-hub.bicep @@ -0,0 +1,307 @@ +@description('Name of the subnet') +param subnetName string = 'ApplicationGatewaySubnet' + +@description('Application Gateway name') +param applicationGatewayName string = 'wth-appgw-hub01' + +@description('Minimum instance count for Application Gateway') +param minCapacity int = 1 + +@description('Maximum instance count for Application Gateway') +param maxCapacity int = 2 + +@description('Application Gateway Frontend port') +param frontendPort int = 80 + +@description('Application gateway Backend port') +param backendPort int = 80 + +resource wthspoke1vmnic 'Microsoft.Network/networkInterfaces@2022-01-01' existing = { + name: 'wth-nic-spoke1vm01' + scope: resourceGroup('wth-rg-spoke1') +} + +resource wthspoke2vmnic 'Microsoft.Network/networkInterfaces@2022-01-01' existing = { + name: 'wth-nic-spoke2vm01' + scope: resourceGroup('wth-rg-spoke2') +} + +@description('Back end pool ip addresses') +var backendIPAddresses = [ + { + ipAddress: wthspoke1vmnic.properties.ipConfigurations[0].properties.privateIPAddress + } + { + ipAddress: wthspoke2vmnic.properties.ipConfigurations[0].properties.privateIPAddress + } +] + +@description('Cookie based affinity') +@allowed([ + 'Enabled' + 'Disabled' +]) +param cookieBasedAffinity string = 'Disabled' + +@description('Location for all resources.') +param location string = resourceGroup().location + +var appGwPublicIpName = 'wth-pip-appgw01' +var appGwSize = 'Standard_v2' + +resource hubvnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { + name: 'wth-vnet-hub01' + scope: resourceGroup('wth-rg-hub') +} + +resource hubappgwsubnet 'Microsoft.Network/virtualNetworks/subnets@2022-01-01' = { + name: '${hubvnet.name}/ApplicationGatewaySubnet' + properties: { + addressPrefix: '10.0.2.0/24' + } +} + +resource keyvault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: 'wth${uniqueString(subscription().id)}' + location: location + properties: { + enableSoftDelete: true + enablePurgeProtection: true + sku: { + name: 'standard' + family: 'A' + } + tenantId: tenant().tenantId + accessPolicies: [ + { + objectId: userAssignedIdentity.properties.principalId + permissions: { + secrets: [ + 'all' + ] + } + tenantId: tenant().tenantId + } + ] + } +} + +resource publicIP 'Microsoft.Network/publicIPAddresses@2020-06-01' = { + name: appGwPublicIpName + location: location + sku: { + name: 'Standard' + } + properties: { + publicIPAllocationMethod: 'Static' + } +} + +resource userAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: 'wth-umsi-appgw01' + location: location +} + +resource applicationGateway 'Microsoft.Network/applicationGateways@2020-06-01' = { + name: applicationGatewayName + location: location + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${userAssignedIdentity.id}': {} + } + } + properties: { + sku: { + name: appGwSize + tier: 'Standard_v2' + } + autoscaleConfiguration: { + minCapacity: minCapacity + maxCapacity: maxCapacity + } + sslCertificates: [ + { + name: 'wildcard_fcride_com' + properties: { + keyVaultSecretId: 'https://wthotlxegowqsmac.vault.azure.net/secrets/wildcard/0de83a6671604affabc155af5bea1d7f' + } + } + ] + gatewayIPConfigurations: [ + { + name: 'appGatewayIpConfig' + properties: { + subnet: { + id: resourceId('Microsoft.Network/virtualNetworks/subnets', hubvnet.name, subnetName) + } + } + } + ] + frontendIPConfigurations: [ + { + name: 'appGatewayFrontendIP' + properties: { + publicIPAddress: { + id: publicIP.id + } + } + } + ] + frontendPorts: [ + { + name: 'appGatewayFrontendPort' + properties: { + port: frontendPort + } + } + { + name: 'appGatewayFrontendPortHttps' + properties: { + port: 443 + } + } + ] + backendAddressPools: [ + { + name: 'appGatewayBackendPool' + properties: { + backendAddresses: backendIPAddresses + } + } + { + name: 'appGatewayBackendPoolSpoke1' + properties: { + backendAddresses: [ + { ipAddress: wthspoke1vmnic.properties.ipConfigurations[0].properties.privateIPAddress } + ] + } + } + { + name: 'appGatewayBackendPoolSpoke2' + properties: { + backendAddresses: [ + { ipAddress: wthspoke2vmnic.properties.ipConfigurations[0].properties.privateIPAddress } + ] + } + } + ] + backendHttpSettingsCollection: [ + { + name: 'appGatewayBackendHttpSettings' + properties: { + port: backendPort + protocol: 'Http' + cookieBasedAffinity: cookieBasedAffinity + } + } + ] + httpListeners: [ + { + name: 'appGatewayHttpListener' + properties: { + frontendIPConfiguration: { + id: resourceId('Microsoft.Network/applicationGateways/frontendIPConfigurations', applicationGatewayName, 'appGatewayFrontendIP') + } + frontendPort: { + id: resourceId('Microsoft.Network/applicationGateways/frontendPorts', applicationGatewayName, 'appGatewayFrontendPort') + } + protocol: 'Http' + } + } + { + name: 'appGatewayHttpsListener' + properties: { + frontendIPConfiguration: { + id: resourceId('Microsoft.Network/applicationGateways/frontendIPConfigurations', applicationGatewayName, 'appGatewayFrontendIP') + } + frontendPort: { + id: resourceId('Microsoft.Network/applicationGateways/frontendPorts', applicationGatewayName, 'appGatewayFrontendPortHttps') + } + protocol: 'Https' + sslCertificate: { + id: resourceId('Microsoft.Network/applicationGateways/sslCertificates', applicationGatewayName, 'wildcard_fcride_com') + } + } + } + ] + requestRoutingRules: [ + { + name: 'rule1' + properties: { + ruleType: 'Basic' + httpListener: { + id: resourceId('Microsoft.Network/applicationGateways/httpListeners', applicationGatewayName, 'appGatewayHttpListener') + } + backendAddressPool: { + id: resourceId('Microsoft.Network/applicationGateways/backendAddressPools', applicationGatewayName, 'appGatewayBackendPool') + } + backendHttpSettings: { + id: resourceId('Microsoft.Network/applicationGateways/backendHttpSettingsCollection', applicationGatewayName, 'appGatewayBackendHttpSettings') + } + } + } + { + name: 'spokes' + properties: { + ruleType: 'Basic' + urlPathMap: { + id: resourceId('Microsoft.Network/applicationGateways/urlPathMaps', applicationGatewayName, 'spokes') + } + httpListener: { + id: resourceId('Microsoft.Network/applicationGateways/httpListeners', applicationGatewayName, 'appGatewayHttpsListener') + } + backendAddressPool: { + id: resourceId('Microsoft.Network/applicationGateways/backendAddressPools', applicationGatewayName, 'appGatewayBackendPoolSpoke1') + } + backendHttpSettings: { + id: resourceId('Microsoft.Network/applicationGateways/backendHttpSettingsCollection', applicationGatewayName, 'appGatewayBackendHttpSettings') + } + } + } + ] + urlPathMaps: [ + { + name: 'spokes' + properties: { + defaultBackendAddressPool: { + id: resourceId('Microsoft.Network/applicationGateways/backendAddressPools', applicationGatewayName, 'appGatewayBackendPoolSpoke1') + } + defaultBackendHttpSettings: { + id: resourceId('Microsoft.Network/applicationGateways/backendHttpSettingsCollection', applicationGatewayName, 'appGatewayBackendHttpSettings') + } + pathRules: [ + { + name: 'spoke1' + properties: { + paths: [ + '/spoke1/*' + ] + backendAddressPool: { + id: resourceId('Microsoft.Network/applicationGateways/backendAddressPools', applicationGatewayName, 'appGatewayBackendPoolSpoke1') + } + backendHttpSettings: { + id: resourceId('Microsoft.Network/applicationGateways/backendHttpSettingsCollection', applicationGatewayName, 'appGatewayBackendHttpSettings') + } + } + } + { + name: 'spoke2' + properties: { + paths: [ + '/spoke2/*' + ] + backendAddressPool: { + id: resourceId('Microsoft.Network/applicationGateways/backendAddressPools', applicationGatewayName, 'appGatewayBackendPoolSpoke2') + } + backendHttpSettings: { + id: resourceId('Microsoft.Network/applicationGateways/backendHttpSettingsCollection', applicationGatewayName, 'appGatewayBackendHttpSettings') + } + } + } + ] + } + } + ] + } +} diff --git a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 index 62f24a7912..56ef5d3cc2 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 +++ b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 @@ -210,7 +210,25 @@ switch ($challengeNumber) { } } } - 4 {} + 4 { + Write-Host "Deploying resources for Challenge 4: Application Gatway" + + Write-Host "`tDeploying App GW configs..." + $jobs = @() + #$jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./03-01-spoke1.bicep -TemplateParameterObject @{location = $location } -AsJob + #$jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./03-01-spoke2.bicep -TemplateParameterObject @{location = $location } -AsJob + $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./04-01-hub.bicep -TemplateParameterObject @{location = $location } -AsJob + + $jobs | Wait-Job | Out-Null + + # check for deployment errors + $jobs | Foreach-Object { + $job = $_ + If ($job.Error) { + Write-Error "A hub or spoke configuration deployment experienced an error: $($job.error)" + } + } + } 5 {} 6 {} } From 9901e58967bf40dcd306ba4882e6d0ef52240b13 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Thu, 15 Sep 2022 08:58:52 -0600 Subject: [PATCH 42/76] challenge 4 --- .../Resources/bicep/03-01-spoke2.bicep | 9 ++++ .../Resources/bicep/03-02-spoke1.bicep | 34 ++++++++++++ .../Resources/bicep/03-02-spoke2.bicep | 34 ++++++++++++ .../Student/Resources/bicep/04-01-hub.bicep | 37 ++++++++----- .../Student/Resources/bicep/04-02-hub.bicep | 41 +++++++++++++++ .../Student/Resources/bicep/deployBicep.ps1 | 52 ++++++++++++++----- 6 files changed, 181 insertions(+), 26 deletions(-) create mode 100644 035-HubAndSpoke/Student/Resources/bicep/03-02-spoke1.bicep create mode 100644 035-HubAndSpoke/Student/Resources/bicep/03-02-spoke2.bicep create mode 100644 035-HubAndSpoke/Student/Resources/bicep/04-02-hub.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/03-01-spoke2.bicep b/035-HubAndSpoke/Student/Resources/bicep/03-01-spoke2.bicep index 228555e99c..e3b5041f71 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/03-01-spoke2.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/03-01-spoke2.bicep @@ -19,6 +19,15 @@ resource rtspoke2vms 'Microsoft.Network/routeTables@2022-01-01' = { } } + { + name: 'route-hubvnet-to-afw' + properties: { + addressPrefix: '10.0.0.0/16' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress + + } + } ] disableBgpRoutePropagation: true } diff --git a/035-HubAndSpoke/Student/Resources/bicep/03-02-spoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/03-02-spoke1.bicep new file mode 100644 index 0000000000..e69c9117e4 --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/03-02-spoke1.bicep @@ -0,0 +1,34 @@ +param location string = 'eastus2' + +resource wthafw 'Microsoft.Network/azureFirewalls@2022-01-01' existing = { + name: 'wth-afw-hub01' + scope: resourceGroup('wth-rg-hub') +} + +resource rtspoke1vms 'Microsoft.Network/routeTables@2022-01-01' = { + name: 'wth-rt-spoke1vmssubnet' + location: location + properties: { + routes: [ + { + name: 'route-all-to-afw' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress + + } + } + { + name: 'route-hubvnet_vms-to-afw' + properties: { + addressPrefix: '10.0.10.0/24' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress + + } + } + ] + disableBgpRoutePropagation: true + } +} diff --git a/035-HubAndSpoke/Student/Resources/bicep/03-02-spoke2.bicep b/035-HubAndSpoke/Student/Resources/bicep/03-02-spoke2.bicep new file mode 100644 index 0000000000..6ba4ebabfa --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/03-02-spoke2.bicep @@ -0,0 +1,34 @@ +param location string = 'eastus2' + +resource wthafw 'Microsoft.Network/azureFirewalls@2022-01-01' existing = { + name: 'wth-afw-hub01' + scope: resourceGroup('wth-rg-hub') +} + +resource rtspoke2vms 'Microsoft.Network/routeTables@2022-01-01' = { + name: 'wth-rt-spoke2vmssubnet' + location: location + properties: { + routes: [ + { + name: 'route-all-to-afw' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress + + } + } + { + name: 'route-hubvnet_vms-to-afw' + properties: { + addressPrefix: '10.0.10.0/24' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress + + } + } + ] + disableBgpRoutePropagation: true + } +} diff --git a/035-HubAndSpoke/Student/Resources/bicep/04-01-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/04-01-hub.bicep index bba506bb6a..5fb85c527b 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/04-01-hub.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/04-01-hub.bicep @@ -16,6 +16,9 @@ param frontendPort int = 80 @description('Application gateway Backend port') param backendPort int = 80 +@description('Secret identifier for AppGW TLS private key - ex: https://.vault.azure.net/secrets//') +param appGWTLSSecretID string = 'https://wthotlxegowqsmac.vault.azure.net/secrets/wildcard/0de83a6671604affabc155af5bea1d7f' + resource wthspoke1vmnic 'Microsoft.Network/networkInterfaces@2022-01-01' existing = { name: 'wth-nic-spoke1vm01' scope: resourceGroup('wth-rg-spoke1') @@ -122,9 +125,9 @@ resource applicationGateway 'Microsoft.Network/applicationGateways@2020-06-01' = } sslCertificates: [ { - name: 'wildcard_fcride_com' + name: 'wth_certificate' properties: { - keyVaultSecretId: 'https://wthotlxegowqsmac.vault.azure.net/secrets/wildcard/0de83a6671604affabc155af5bea1d7f' + keyVaultSecretId: appGWTLSSecretID } } ] @@ -195,6 +198,15 @@ resource applicationGateway 'Microsoft.Network/applicationGateways@2020-06-01' = cookieBasedAffinity: cookieBasedAffinity } } + { + name: 'appGatewayBackendHttpSettingsSpokes' + properties: { + port: backendPort + protocol: 'Http' + cookieBasedAffinity: cookieBasedAffinity + path: '/' + } + } ] httpListeners: [ { @@ -220,14 +232,14 @@ resource applicationGateway 'Microsoft.Network/applicationGateways@2020-06-01' = } protocol: 'Https' sslCertificate: { - id: resourceId('Microsoft.Network/applicationGateways/sslCertificates', applicationGatewayName, 'wildcard_fcride_com') + id: resourceId('Microsoft.Network/applicationGateways/sslCertificates', applicationGatewayName, 'wth_certificate') } } } ] requestRoutingRules: [ { - name: 'rule1' + name: 'requestRoutingRuleDefault' properties: { ruleType: 'Basic' httpListener: { @@ -242,17 +254,17 @@ resource applicationGateway 'Microsoft.Network/applicationGateways@2020-06-01' = } } { - name: 'spokes' + name: 'requestRoutingRuleSpokes' properties: { - ruleType: 'Basic' + ruleType: 'PathBasedRouting' urlPathMap: { - id: resourceId('Microsoft.Network/applicationGateways/urlPathMaps', applicationGatewayName, 'spokes') + id: resourceId('Microsoft.Network/applicationGateways/urlPathMaps', applicationGatewayName, 'urlPathMapSpokes') } httpListener: { id: resourceId('Microsoft.Network/applicationGateways/httpListeners', applicationGatewayName, 'appGatewayHttpsListener') } backendAddressPool: { - id: resourceId('Microsoft.Network/applicationGateways/backendAddressPools', applicationGatewayName, 'appGatewayBackendPoolSpoke1') + id: resourceId('Microsoft.Network/applicationGateways/backendAddressPools', applicationGatewayName, 'appGatewayBackendPool') } backendHttpSettings: { id: resourceId('Microsoft.Network/applicationGateways/backendHttpSettingsCollection', applicationGatewayName, 'appGatewayBackendHttpSettings') @@ -262,10 +274,10 @@ resource applicationGateway 'Microsoft.Network/applicationGateways@2020-06-01' = ] urlPathMaps: [ { - name: 'spokes' + name: 'urlPathMapSpokes' properties: { defaultBackendAddressPool: { - id: resourceId('Microsoft.Network/applicationGateways/backendAddressPools', applicationGatewayName, 'appGatewayBackendPoolSpoke1') + id: resourceId('Microsoft.Network/applicationGateways/backendAddressPools', applicationGatewayName, 'appGatewayBackendPool') } defaultBackendHttpSettings: { id: resourceId('Microsoft.Network/applicationGateways/backendHttpSettingsCollection', applicationGatewayName, 'appGatewayBackendHttpSettings') @@ -281,7 +293,7 @@ resource applicationGateway 'Microsoft.Network/applicationGateways@2020-06-01' = id: resourceId('Microsoft.Network/applicationGateways/backendAddressPools', applicationGatewayName, 'appGatewayBackendPoolSpoke1') } backendHttpSettings: { - id: resourceId('Microsoft.Network/applicationGateways/backendHttpSettingsCollection', applicationGatewayName, 'appGatewayBackendHttpSettings') + id: resourceId('Microsoft.Network/applicationGateways/backendHttpSettingsCollection', applicationGatewayName, 'appGatewayBackendHttpSettingsSpokes') } } } @@ -295,7 +307,7 @@ resource applicationGateway 'Microsoft.Network/applicationGateways@2020-06-01' = id: resourceId('Microsoft.Network/applicationGateways/backendAddressPools', applicationGatewayName, 'appGatewayBackendPoolSpoke2') } backendHttpSettings: { - id: resourceId('Microsoft.Network/applicationGateways/backendHttpSettingsCollection', applicationGatewayName, 'appGatewayBackendHttpSettings') + id: resourceId('Microsoft.Network/applicationGateways/backendHttpSettingsCollection', applicationGatewayName, 'appGatewayBackendHttpSettingsSpokes') } } } @@ -303,5 +315,6 @@ resource applicationGateway 'Microsoft.Network/applicationGateways@2020-06-01' = } } ] + enableHttp2: true } } diff --git a/035-HubAndSpoke/Student/Resources/bicep/04-02-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/04-02-hub.bicep new file mode 100644 index 0000000000..45659731e3 --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/04-02-hub.bicep @@ -0,0 +1,41 @@ +param location string = 'eastus2' + +resource wthafw 'Microsoft.Network/azureFirewalls@2022-01-01' existing = { + name: 'wth-afw-hub01' + scope: resourceGroup('wth-rg-hub') +} + +resource rthubvms 'Microsoft.Network/routeTables@2022-01-01' = { + name: 'wth-rt-hubvmssubnet' + location: location + properties: { + routes: [ + { + name: 'route-all-to-afw' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress + + } + } + { + name: 'route-spoke1-to-afw' + properties: { + addressPrefix: '10.1.0.0/16' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress + } + } + { + name: 'route-spoke2-to-afw' + properties: { + addressPrefix: '10.2.0.0/16' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress + } + } + ] + disableBgpRoutePropagation: true + } +} diff --git a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 index 56ef5d3cc2..6aa49446d6 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 +++ b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 @@ -28,7 +28,12 @@ param ( # Parameter help description [Parameter(Mandatory = $false)] [SecureString] - $vmPassword + $vmPassword, + + # include to correct intentionally misconfigured resources (deployed as part of the challenge) + [Parameter(Mandatory = $false)] + [switch] + $correctedConfiguration ) $ErrorActionPreference = 'Stop' @@ -194,19 +199,38 @@ switch ($challengeNumber) { 3 { Write-Host "Deploying resources for Challenge 3: Asymmetric Routes" - Write-Host "`tDeploying updated hub and spoke route configs..." - $jobs = @() - $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./03-01-spoke1.bicep -TemplateParameterObject @{location = $location } -AsJob - $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./03-01-spoke2.bicep -TemplateParameterObject @{location = $location } -AsJob - $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./03-01-hub.bicep -TemplateParameterObject @{location = $location } -AsJob - - $jobs | Wait-Job | Out-Null - - # check for deployment errors - $jobs | Foreach-Object { - $job = $_ - If ($job.Error) { - Write-Error "A hub or spoke configuration deployment experienced an error: $($job.error)" + If (!$correctedConfiguration.IsPresent) { + Write-Host "`tDeploying updated hub and spoke route configs (intentionally misconfigured!)..." + $jobs = @() + $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./03-01-spoke1.bicep -TemplateParameterObject @{location = $location } -AsJob + $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./03-01-spoke2.bicep -TemplateParameterObject @{location = $location } -AsJob + $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./03-01-hub.bicep -TemplateParameterObject @{location = $location } -AsJob + + $jobs | Wait-Job | Out-Null + + # check for deployment errors + $jobs | Foreach-Object { + $job = $_ + If ($job.Error) { + Write-Error "A hub or spoke configuration deployment experienced an error: $($job.error)" + } + } + } + Else { + Write-Host "`tDeploying updated hub and spoke route configs (corrected configuration from original Challenge 3 design)..." + $jobs = @() + $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./03-02-spoke1.bicep -TemplateParameterObject @{location = $location } -AsJob + $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./03-02-spoke2.bicep -TemplateParameterObject @{location = $location } -AsJob + $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./03-01-hub.bicep -TemplateParameterObject @{location = $location } -AsJob + + $jobs | Wait-Job | Out-Null + + # check for deployment errors + $jobs | Foreach-Object { + $job = $_ + If ($job.Error) { + Write-Error "A hub or spoke configuration deployment experienced an error: $($job.error)" + } } } } From bd963513222ba780f3bde696824e75ce22a298c6 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Fri, 16 Sep 2022 14:14:34 -0600 Subject: [PATCH 43/76] wip: challenge 5 --- .../Student/Resources/bicep/04-02-hub.bicep | 41 ------ .../Student/Resources/bicep/05-01-hub.bicep | 23 +++ .../Resources/bicep/05-01-spoke1.bicep | 136 ++++++++++++++++++ .../Resources/bicep/05-01-spoke2.bicep | 86 +++++++++++ .../Student/Resources/bicep/deployBicep.ps1 | 28 +++- 5 files changed, 271 insertions(+), 43 deletions(-) delete mode 100644 035-HubAndSpoke/Student/Resources/bicep/04-02-hub.bicep create mode 100644 035-HubAndSpoke/Student/Resources/bicep/05-01-hub.bicep create mode 100644 035-HubAndSpoke/Student/Resources/bicep/05-01-spoke1.bicep create mode 100644 035-HubAndSpoke/Student/Resources/bicep/05-01-spoke2.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/04-02-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/04-02-hub.bicep deleted file mode 100644 index 45659731e3..0000000000 --- a/035-HubAndSpoke/Student/Resources/bicep/04-02-hub.bicep +++ /dev/null @@ -1,41 +0,0 @@ -param location string = 'eastus2' - -resource wthafw 'Microsoft.Network/azureFirewalls@2022-01-01' existing = { - name: 'wth-afw-hub01' - scope: resourceGroup('wth-rg-hub') -} - -resource rthubvms 'Microsoft.Network/routeTables@2022-01-01' = { - name: 'wth-rt-hubvmssubnet' - location: location - properties: { - routes: [ - { - name: 'route-all-to-afw' - properties: { - addressPrefix: '0.0.0.0/0' - nextHopType: 'VirtualAppliance' - nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress - - } - } - { - name: 'route-spoke1-to-afw' - properties: { - addressPrefix: '10.1.0.0/16' - nextHopType: 'VirtualAppliance' - nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress - } - } - { - name: 'route-spoke2-to-afw' - properties: { - addressPrefix: '10.2.0.0/16' - nextHopType: 'VirtualAppliance' - nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress - } - } - ] - disableBgpRoutePropagation: true - } -} diff --git a/035-HubAndSpoke/Student/Resources/bicep/05-01-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/05-01-hub.bicep new file mode 100644 index 0000000000..04e90d6e2e --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/05-01-hub.bicep @@ -0,0 +1,23 @@ +param location string = 'eastus2' + +resource hubvnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { + name: 'wth-vnet-hub01' + scope: resourceGroup('wth-rg-hub') +} + +resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { + name: 'privatelink.database.windows.net' + location: 'global' +} + +resource dnsvnetlink 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2020-06-01' = { + name: 'wth-dnsvnetlink-hub' + parent: privateDNSZone + location: 'global' + properties: { + registrationEnabled: true + virtualNetwork: { + id: hubvnet.id + } + } +} diff --git a/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke1.bicep new file mode 100644 index 0000000000..99acf6270d --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke1.bicep @@ -0,0 +1,136 @@ +param location string = 'eastus2' +param adminUserLogin string +param adminUserSid string + +resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' existing = { + name: 'privatelink.database.windows.net' + scope: resourceGroup('wth-rg-hub') +} + +resource sqlServer 'Microsoft.Sql/servers@2021-11-01' = { + name: 'wthspoke1${uniqueString(subscription().id)}' + location: location + properties: { + administratorLogin: 'admin-wth' + administratorLoginPassword: guid(subscription().id, 'this_is_a_b0gus_and_disabled_password!') + version: '12.0' + publicNetworkAccess: 'Disabled' + administrators: { + administratorType: 'ActiveDirectory' + principalType: 'User' + login: adminUserLogin + sid: adminUserSid + tenantId: tenant().tenantId + azureADOnlyAuthentication: true + } + } +} + +resource sqlDB 'Microsoft.Sql/servers/databases@2021-11-01' = { + parent: sqlServer + name: 'sampleDB' + location: location + sku: { + name: 'Standard' + tier: 'Standard' + } + properties: { + autoPauseDelay: 240 + maxSizeBytes: 1073741824 + sampleName: 'AdventureWorksLT' + zoneRedundant: false + } +} + +resource wthspoke1vnet 'Microsoft.Network/virtualNetworks@2021-08-01' existing = { + name: 'wth-vnet-spoke101' +} + +resource wthonpremvnet 'Microsoft.Network/virtualNetworks@2021-08-01' existing = { + name: 'wth-vnet-onprem01' + scope: resourceGroup('wth-rg-onprem') +} + +resource wthspoke1vnetpepsubnet 'Microsoft.Network/virtualNetworks/subnets@2022-01-01' = { + name: 'subnet-sqlpeps' + parent: wthspoke1vnet + properties: { + addressPrefix: '10.1.11.0/24' + networkSecurityGroup: { + id: nsg.id + } + privateEndpointNetworkPolicies: 'Enabled' + } +} + +resource nsg 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { + name: 'wth-nsg-sqlpepsubnet' + location: location + properties: {} +} + +resource nsgSecRuleAllow 'Microsoft.Network/networkSecurityGroups/securityRules@2022-01-01' = { + name: 'allow-sql-from-onprem' + parent: nsg + properties: { + access: 'Allow' + direction: 'Inbound' + protocol: '*' + sourceAddressPrefixes: wthonpremvnet.properties.addressSpace.addressPrefixes + destinationAddressPrefix: wthspoke1vnetpepsubnet.properties.addressPrefix + priority: 100 + sourcePortRange: '*' + destinationPortRange: '*' + } +} + +resource nsgSecRuleDeny 'Microsoft.Network/networkSecurityGroups/securityRules@2022-01-01' = { + name: 'deny-sql-from-any' + parent: nsg + properties: { + access: 'Deny' + direction: 'Inbound' + protocol: '*' + sourceAddressPrefix: '*' + destinationAddressPrefix: wthspoke1vnetpepsubnet.properties.addressPrefix + priority: 101 + sourcePortRange: '*' + destinationPortRange: '*' + } +} + +resource privateEndpoint 'Microsoft.Network/privateEndpoints@2022-01-01' = { + name: 'wth-pep-sqlspoke1' + location: location + properties: { + subnet: { + id: wthspoke1vnetpepsubnet.id + } + privateLinkServiceConnections: [ + { + name: 'sql' + properties: { + privateLinkServiceId: sqlServer.id + groupIds: [ + 'sqlServer' + ] + } + } + ] + } +} + +resource privdns 'Microsoft.Network/privateEndpoints/privateDnsZoneGroups@2022-01-01' = { + name: 'link' + parent: privateEndpoint + properties: { + privateDnsZoneConfigs: [ + { + name: 'zoneconfig' + properties: { + privateDnsZoneId: privateDNSZone.id + } + } + ] + } +} diff --git a/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke2.bicep b/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke2.bicep new file mode 100644 index 0000000000..1a7f4c490b --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke2.bicep @@ -0,0 +1,86 @@ +param location string = 'eastus2' +param adminUserLogin string +param adminUserSid string + +resource rtspoke2vms 'Microsoft.Network/routeTables@2022-01-01' existing = { + name: 'wth-rt-spoke2vmssubnet' +} + +resource nsgspoke2vms 'Microsoft.Network/networkSecurityGroups@2022-01-01' existing = { + name: 'wth-nsg-spoke2vmssubnet' +} + +resource sqlServer 'Microsoft.Sql/servers@2021-11-01' = { + name: 'wthspoke2${uniqueString(subscription().id)}' + location: location + properties: { + administratorLogin: 'admin-wth' + administratorLoginPassword: guid(subscription().id,'this_is_a_b0gus_and_disabled_password!') + version: '12.0' + publicNetworkAccess: 'Disabled' + administrators: { + administratorType: 'ActiveDirectory' + principalType: 'User' + login: adminUserLogin + sid: adminUserSid + tenantId: tenant().tenantId + azureADOnlyAuthentication: true + } + } +} + +resource sqlServerFirewall 'Microsoft.Sql/servers/virtualNetworkRules@2021-11-01' = { + name: 'rule' + parent: sqlServer + properties: { + virtualNetworkSubnetId: wthspoke1vnet.properties.subnets[0].id + } +} + +resource sqlDB 'Microsoft.Sql/servers/databases@2021-11-01' = { + parent: sqlServer + name: 'sampleDB' + location: location + sku: { + name: 'Standard' + tier: 'Standard' + } + properties: { + autoPauseDelay: 240 + maxSizeBytes: 1073741824 + sampleName: 'AdventureWorksLT' + zoneRedundant: false + } +} + +resource wthspoke1vnet 'Microsoft.Network/virtualNetworks@2021-08-01' = { + name: 'wth-vnet-spoke201' + location: location + properties: { + addressSpace: { + addressPrefixes: [ + '10.2.0.0/16' + ] + } + subnets: [ + { + name: 'subnet-spoke1vms' + properties: { + addressPrefix: '10.2.10.0/24' + networkSecurityGroup: { + id: nsgspoke2vms.id + } + routeTable: { + id: rtspoke2vms.id + } + serviceEndpoints: [ + { + service: 'Microsoft.SQL' + } + ] + } + } + ] + } +} + diff --git a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 index 6aa49446d6..19336a4ba1 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 +++ b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 @@ -235,7 +235,7 @@ switch ($challengeNumber) { } } 4 { - Write-Host "Deploying resources for Challenge 4: Application Gatway" + Write-Host "Deploying resources for Challenge 4: Application Gateway" Write-Host "`tDeploying App GW configs..." $jobs = @() @@ -253,7 +253,31 @@ switch ($challengeNumber) { } } } - 5 {} + 5 { + Write-Host "Deploying resources for Challenge 5: PaaS Networking" + + Write-Host "`tDeploying PaaS resources..." + + $adminUser = Get-AzAdUser -SignedIn + $adminUserLogin = $adminUser.UserPrincipalName + $adminUserSid = $adminUser.Id + + $jobs = @() + $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./05-01-hub.bicep -TemplateParameterObject @{location = $location } -AsJob + $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./05-01-spoke1.bicep -TemplateParameterObject @{location = $location; adminUserLogin = $adminUserLogin; adminUserSid = $adminUserSid } -AsJob + $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./05-01-spoke2.bicep -TemplateParameterObject @{location = $location; adminUserLogin = $adminUserLogin; adminUserSid = $adminUserSid } -AsJob + + + $jobs | Wait-Job | Out-Null + + # check for deployment errors + $jobs | Foreach-Object { + $job = $_ + If ($job.Error) { + Write-Error "A hub or spoke configuration deployment experienced an error: $($job.error)" + } + } + } 6 {} } From 7cc3f7f04aa67c8e210364f737d0ddf796bebf59 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Tue, 20 Sep 2022 16:07:47 -0600 Subject: [PATCH 44/76] challenge 5 sql --- 035-HubAndSpoke/Student/Resources/bicep/02-00-afw.bicep | 8 ++++++-- .../Student/Resources/bicep/05-01-spoke1.bicep | 1 - .../Student/Resources/bicep/05-01-spoke2.bicep | 1 - 035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-00-afw.bicep b/035-HubAndSpoke/Student/Resources/bicep/02-00-afw.bicep index be0304bf94..27c757c0db 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/02-00-afw.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/02-00-afw.bicep @@ -25,9 +25,13 @@ resource wthafwpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { } resource wthafwpolicy 'Microsoft.Network/firewallPolicies@2022-01-01' = { - name: 'wth-fwp-default01' + name: 'wth-fwp-premium01' location: location - properties: {} + properties: { + sku: { + tier: 'Premium' + } + } } resource wthafw 'Microsoft.Network/azureFirewalls@2022-01-01' = { diff --git a/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke1.bicep index 99acf6270d..13c1523e16 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke1.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke1.bicep @@ -21,7 +21,6 @@ resource sqlServer 'Microsoft.Sql/servers@2021-11-01' = { login: adminUserLogin sid: adminUserSid tenantId: tenant().tenantId - azureADOnlyAuthentication: true } } } diff --git a/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke2.bicep b/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke2.bicep index 1a7f4c490b..ae73843c9f 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke2.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke2.bicep @@ -24,7 +24,6 @@ resource sqlServer 'Microsoft.Sql/servers@2021-11-01' = { login: adminUserLogin sid: adminUserSid tenantId: tenant().tenantId - azureADOnlyAuthentication: true } } } diff --git a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 index 19336a4ba1..2a4560769b 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 +++ b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 @@ -55,7 +55,7 @@ If ( -NOT ($azContext = Get-AzContext)) { throw "Run 'Connect-AzAccount' before executing this script!" } Else { - do { $response = (Read-Host "Resources will be created in subscription '$($azContext.Subscription.Name)'. If this is not the correct subscription, use 'Select-AzSubscription' before running this script. Proceed? (y/n)") } + do { $response = (Read-Host "Resources will be created in subscription '$($azContext.Subscription.Name)' in region '$location'. If this is not the correct subscription, use 'Select-AzSubscription' before running this script and specify an alternate location with the -Location parameter. Proceed? (y/n)") } until ($response -match '[nNYy]') If ($response -match 'nN') { exit } From 7a25b9a053f6fc19b864f6e927fba6ecb24926d3 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Thu, 29 Sep 2022 10:39:09 -0600 Subject: [PATCH 45/76] afw logging --- .../Student/Resources/bicep/02-00-afw.bicep | 5 +++-- .../Resources/bicep/02-01-fwpolicyrules.bicep | 2 +- 035-HubAndSpoke/Student/Resources/bicep/README.md | 13 +++++++++++++ .../Student/Resources/bicep/deployBicep.ps1 | 11 +++++++++-- 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-00-afw.bicep b/035-HubAndSpoke/Student/Resources/bicep/02-00-afw.bicep index 27c757c0db..80be057477 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/02-00-afw.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/02-00-afw.bicep @@ -25,11 +25,11 @@ resource wthafwpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { } resource wthafwpolicy 'Microsoft.Network/firewallPolicies@2022-01-01' = { - name: 'wth-fwp-premium01' + name: 'wth-fwp-standard01' location: location properties: { sku: { - tier: 'Premium' + tier: 'Standard' } } } @@ -86,6 +86,7 @@ resource wthafwdiagsettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-pr } } ] + logAnalyticsDestinationType: 'Dedicated' } } diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-01-fwpolicyrules.bicep b/035-HubAndSpoke/Student/Resources/bicep/02-01-fwpolicyrules.bicep index 55a2c87fdd..fbff822e1c 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/02-01-fwpolicyrules.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/02-01-fwpolicyrules.bicep @@ -1,5 +1,5 @@ resource wthafwpolicy 'Microsoft.Network/firewallPolicies@2022-01-01' existing = { - name: 'wth-fwp-default01' + name: 'wth-fwp-premium01' scope: resourceGroup('wth-rg-hub') } diff --git a/035-HubAndSpoke/Student/Resources/bicep/README.md b/035-HubAndSpoke/Student/Resources/bicep/README.md index 355432166e..76d1de67d8 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/README.md +++ b/035-HubAndSpoke/Student/Resources/bicep/README.md @@ -14,6 +14,8 @@ The WTH philosophy intends to have students learn by doing, and recognizes that Using Cloud Shell is recommended, as it already has the necessary tools installed. However, Cloud Shell has a timeout of about 20 minutes and may experience timeouts (in which case, run the same command again to pick up the deployments where they stopped). +Challenges are meant to be deployed sequentially, as the infrastructure builds on itself. For example, to work with the Challenge 5 infrastructure, deploy Challenges 1-4 first. + ### Prerequisites - Azure PowerShell module @@ -61,5 +63,16 @@ Using Cloud Shell is recommended, as it already has the necessary tools installe - Spoke 1: 8081 - Spoke 2: 8082 +### Challenge 3 + +- The routing tables are adjusted to match the Challenge documentation. To correct the inital deployment, run `deployBicep.ps1 -challengeNumber 3 -correctedConfiguration` + +### Challenge 4 + +### Challenge 5 + +An Application Gateway is deployed matching the Challenge requirements. For the App GW to deploy, a TLS secret identifier from a Key Vault must be provided. The App GW's managed identity needs permissions to read the secret from the Key Vault. For convenience, +a Key Vault is deployed and the App GW is granted necessary permissions; however, the TLS certificate needs to be uploaded to the Key Vault for the App GW to deploy successfully. + ## Resource Cleanup diff --git a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 index 2a4560769b..1f2a9a6f9e 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 +++ b/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 @@ -14,11 +14,13 @@ param ( [int] $challengeNumber, + <# # TODO: deploy fully configured lab or leave some configuration to be done [Parameter(Mandatory = $false, HelpMessage = 'Deploy all challenge resources fully configured or partially configured (for learning!)')] [ValidateSet('FullyConfigured', 'PartiallyConfigured')] [string] $deploymentType = 'FullyConfigured', + #> # resource deployment Azure region, defaults to 'eastus2' [Parameter(Mandatory = $false)] @@ -33,7 +35,12 @@ param ( # include to correct intentionally misconfigured resources (deployed as part of the challenge) [Parameter(Mandatory = $false)] [switch] - $correctedConfiguration + $correctedConfiguration, + + # confirm subscription and resource types + [Parameter(Mandatory=$false)] + [System.Boolean] + $confirm = $true ) $ErrorActionPreference = 'Stop' @@ -54,7 +61,7 @@ If (-NOT (Test-Path ./01-resourceGroups.bicep)) { If ( -NOT ($azContext = Get-AzContext)) { throw "Run 'Connect-AzAccount' before executing this script!" } -Else { +ElseIf ($confirm) { do { $response = (Read-Host "Resources will be created in subscription '$($azContext.Subscription.Name)' in region '$location'. If this is not the correct subscription, use 'Select-AzSubscription' before running this script and specify an alternate location with the -Location parameter. Proceed? (y/n)") } until ($response -match '[nNYy]') From 972ad8ab8ce7de13e92853640371c7c5c313cab2 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun <25390936+mbrat2005@users.noreply.github.com> Date: Fri, 30 Sep 2022 14:50:48 -0600 Subject: [PATCH 46/76] Update 01-01-spoke2.bicep --- 035-HubAndSpoke/Student/Resources/bicep/01-01-spoke2.bicep | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-01-spoke2.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-01-spoke2.bicep index 693cb98424..cadec724fd 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-01-spoke2.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-01-spoke2.bicep @@ -20,6 +20,12 @@ resource wthspoke2vnet 'Microsoft.Network/virtualNetworks@2021-08-01' = { name: 'subnet-spoke2vms' properties: { addressPrefix: '10.2.10.0/24' + networkSecurityGroup: { + id: nsgspoke2vms.id + } + routeTable: { + id: rtspoke2vms.id + } } } ] From e35ddd837e9e78cc9c9b1a1c5ff8ceb172e2ec80 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Fri, 16 Dec 2022 14:43:14 -0700 Subject: [PATCH 47/76] correct spoke routes --- 035-HubAndSpoke/Student/Resources/bicep/02-01-spoke1.bicep | 2 +- 035-HubAndSpoke/Student/Resources/bicep/02-01-spoke2.bicep | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke1.bicep index 21b772d965..68e746b8a1 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke1.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke1.bicep @@ -20,7 +20,7 @@ resource rtspoke1vms 'Microsoft.Network/routeTables@2022-01-01' = { properties: { addressPrefix: '0.0.0.0/0' nextHopType: 'VirtualAppliance' - nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress + nextHopIpAddress: wthafw.properties.hubIPAddresses.publicIPs.addresses[0].address } } diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke2.bicep b/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke2.bicep index ea70c7dc35..5dd1d7cf2c 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke2.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke2.bicep @@ -20,7 +20,7 @@ resource rtspoke2vms 'Microsoft.Network/routeTables@2022-01-01' = { properties: { addressPrefix: '0.0.0.0/0' nextHopType: 'VirtualAppliance' - nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress + nextHopIpAddress: wthafw.properties.hubIPAddresses.publicIPs.addresses[0].address } } From 231c25443dea827ecd8a4fe1de5a764821a416bf Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Fri, 16 Dec 2022 14:55:19 -0700 Subject: [PATCH 48/76] cleanup doc --- .../Student/Resources/bicep/README.md | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/035-HubAndSpoke/Student/Resources/bicep/README.md b/035-HubAndSpoke/Student/Resources/bicep/README.md index 76d1de67d8..15b2b25f5c 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/README.md +++ b/035-HubAndSpoke/Student/Resources/bicep/README.md @@ -76,3 +76,24 @@ a Key Vault is deployed and the App GW is granted necessary permissions; however ## Resource Cleanup +To cleanup this deployment, delete each create resource group. To do this programmatically with PowerShell, run: + +```powershell + $jobs = @() + $jobs += Remove-AzResourceGroup -Name 'wth-rg-hub' -AsJob + $jobs += Remove-AzResourceGroup -Name 'wth-rg-spoke1' -AsJob + $jobs += Remove-AzResourceGroup -Name 'wth-rg-spoke2' -AsJob + $jobs += Remove-AzResourceGroup -Name 'wth-rg-onprem' -AsJob + + Write-Host "Waiting for all resource group cleanup jobs to complete..." + $jobs | Wait-Job + + $jobs | Foreach-Object { + $job = $_ + If ($job.Error) { + Write-Error "A cleanup task experienced an error: $($job.error)" + } + } + + Write-Host "Cleanup task completed." +``` From ee536b0d6ebd7ae2877f0f5933848e0be4c26d18 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Fri, 16 Dec 2022 15:40:28 -0700 Subject: [PATCH 49/76] wip:webapp --- .../Resources/bicep/05-01-spoke1.bicep | 94 +++++++++++++++++++ .../Student/Resources/bicep/README.md | 15 ++- .../bicep/{deployBicep.ps1 => deploy.ps1} | 2 +- 3 files changed, 102 insertions(+), 9 deletions(-) rename 035-HubAndSpoke/Student/Resources/bicep/{deployBicep.ps1 => deploy.ps1} (99%) diff --git a/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke1.bicep index 13c1523e16..737195649d 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke1.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke1.bicep @@ -133,3 +133,97 @@ resource privdns 'Microsoft.Network/privateEndpoints/privateDnsZoneGroups@2022-0 ] } } + +var webAppPortalName = 'wth-webapp-${uniqueString(subscription().id)}' +var appServicePlanName = 'wth-asp-${uniqueString(subscription().id)}' + +resource appServicePlan 'Microsoft.Web/serverfarms@2022-03-01' = { + name: appServicePlanName + location: location + sku: { + name: 'S1' + } + kind: 'linux' + properties: { + reserved: true + } +} + +resource webapp 'Microsoft.Web/sites@2022-03-01' = { + name: webAppPortalName + location: location + kind: 'app' + properties: { + serverFarmId: appServicePlan.id + siteConfig: { + linuxFxVersion: 'DOCKER|jelledruyts/inspectorgadget' + ftpsState: 'FtpsOnly' + appSettings: [ + { + name: 'WEBSITES_ENABLE_APP_SERVICE_STORAGE' + value: 'false' + } + ] + } + httpsOnly: true + } + identity: { + type: 'SystemAssigned' + } +} + +resource privateEndpoint_webapp 'Microsoft.Network/privateEndpoints@2020-06-01' = { + name: 'wth-pep-webapp' + location: location + properties: { + subnet: { + id: resourceId('Microsoft.Network/virtualNetworks/subnets',wthspoke1vnet.name, wthspoke1vnetpepsubnet.name) + } + privateLinkServiceConnections: [ + { + name: 'wth-peplink-webapp' + properties: { + privateLinkServiceId: webapp.id + groupIds: [ + 'sites' + ] + } + } + ] + } +} + +resource privateDnsZones 'Microsoft.Network/privateDnsZones@2018-09-01' = { + name: 'privatelink.azurewebsites.net' + location: 'global' + dependsOn: [ + wthspoke1vnet + ] +} + +resource privateDnsZoneLink 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2018-09-01' = { + parent: privateDnsZones + name: '${privateDnsZones.name}-link' + location: 'global' + properties: { + registrationEnabled: false + virtualNetwork: { + id: wthspoke1vnet.id + } + } +} + +resource privateDnsZoneGroup 'Microsoft.Network/privateEndpoints/privateDnsZoneGroups@2020-03-01' = { + parent: privateEndpoint + name: 'dnsgroupname' + properties: { + privateDnsZoneConfigs: [ + { + name: 'config1' + properties: { + privateDnsZoneId: privateDnsZones.id + } + } + ] + } +} diff --git a/035-HubAndSpoke/Student/Resources/bicep/README.md b/035-HubAndSpoke/Student/Resources/bicep/README.md index 15b2b25f5c..562c970a68 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/README.md +++ b/035-HubAndSpoke/Student/Resources/bicep/README.md @@ -28,16 +28,16 @@ Challenges are meant to be deployed sequentially, as the infrastructure builds o 1. Clone this repo to your local system or Cloud Shell `git clone https://github.com/microsoft/WhatTheHack.git` 1. Navigate to the `035-HubAndSpoke\Student\Resources\bicep` directory in your clone of the repo -1. Run the deployBicep.ps1 script. For example: - `./deployBicep.ps1 -challengeNumber 1` +1. Run the deploy.ps1 script. For example: + `./deploy.ps1 -challengeNumber 1` #### Download a zip of the bicep directory 1. Browse to https://download-directory.github.io/?url=https%3A%2F%2Fgithub.com%2Fmicrosoft%2FWhatTheHack%2Ftree%2Fnetwork-bicep%2F035-HubAndSpoke%2FStudent%2FResources%2Fbicep 1. A zip of the directory will download to your system 1. Expand the downloaded zip file and navigate to it in a PowerShell window -1. Run the deployBicep.ps1 script. For example: - `./deployBicep.ps1 -challengeNumber 1` +1. Run the deploy.ps1 script. For example: + `./deploy.ps1 -challengeNumber 1` ## Deployed Configuration @@ -65,14 +65,13 @@ Challenges are meant to be deployed sequentially, as the infrastructure builds o ### Challenge 3 -- The routing tables are adjusted to match the Challenge documentation. To correct the inital deployment, run `deployBicep.ps1 -challengeNumber 3 -correctedConfiguration` +- The routing tables are adjusted to match the Challenge documentation. To correct the inital deployment, run `deploy.ps1 -challengeNumber 3 -correctedConfiguration` ### Challenge 4 -### Challenge 5 +An Application Gateway is deployed matching the Challenge requirements. For the App GW to deploy, a TLS secret identifier from a Key Vault must be provided. The App GW's managed identity needs permissions to read the secret from the Key Vault. For convenience, a Key Vault is deployed and the App GW is granted necessary permissions; however, the TLS certificate needs to be uploaded to the Key Vault for the App GW to deploy successfully. -An Application Gateway is deployed matching the Challenge requirements. For the App GW to deploy, a TLS secret identifier from a Key Vault must be provided. The App GW's managed identity needs permissions to read the secret from the Key Vault. For convenience, -a Key Vault is deployed and the App GW is granted necessary permissions; however, the TLS certificate needs to be uploaded to the Key Vault for the App GW to deploy successfully. +### Challenge 5 ## Resource Cleanup diff --git a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 b/035-HubAndSpoke/Student/Resources/bicep/deploy.ps1 similarity index 99% rename from 035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 rename to 035-HubAndSpoke/Student/Resources/bicep/deploy.ps1 index 1f2a9a6f9e..7f74c09492 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/deployBicep.ps1 +++ b/035-HubAndSpoke/Student/Resources/bicep/deploy.ps1 @@ -3,7 +3,7 @@ .DESCRIPTION Deploys or configures WTH Networking challenge resources. .EXAMPLE - ./deployBicep.ps1 -challengeNumber 1 + ./deploy.ps1 -challengeNumber 1 Deploy all resource groups and resources for Challenge 1. Script will prompt for a password, which will be used across all VMs. #> [CmdletBinding()] From 30209f517187c13507996353b91be7a75c6dc5ea Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Mon, 19 Dec 2022 08:07:51 -0700 Subject: [PATCH 50/76] rg deployment name --- 035-HubAndSpoke/Student/Resources/bicep/deploy.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/deploy.ps1 b/035-HubAndSpoke/Student/Resources/bicep/deploy.ps1 index 7f74c09492..973f17775d 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/deploy.ps1 +++ b/035-HubAndSpoke/Student/Resources/bicep/deploy.ps1 @@ -77,7 +77,7 @@ switch ($challengeNumber) { } Write-Host "`tDeploying resource groups..." - New-AzDeployment -Location $location -TemplateFile ./01-00-resourceGroups.bicep + New-AzDeployment -Location $location -Name "01-00-resourceGroups_$location" -TemplateFile ./01-00-resourceGroups.bicep Write-Host "`tDeploying base resources (this will take up to 60 minutes for the VNET Gateway)..." $baseInfraJobs = @{} From a1f755c9483f33effee25fcd84a57bd4f2b72788 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Mon, 19 Dec 2022 08:20:45 -0700 Subject: [PATCH 51/76] fix spoke 2 nsg ref --- 035-HubAndSpoke/Student/Resources/bicep/01-01-spoke2.bicep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-01-spoke2.bicep b/035-HubAndSpoke/Student/Resources/bicep/01-01-spoke2.bicep index cadec724fd..3e95f45c0c 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/01-01-spoke2.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/01-01-spoke2.bicep @@ -133,7 +133,7 @@ resource rtspoke2vms 'Microsoft.Network/routeTables@2022-01-01' = { } } -resource nsgspoke1vms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { +resource nsgspoke2vms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { name: 'wth-nsg-spoke2vmssubnet' location: location properties: { From 4b0cadb5c35c3662998da9ffe5962e1d3581c10e Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Mon, 19 Dec 2022 09:55:15 -0700 Subject: [PATCH 52/76] fix premium afw ref --- .../Student/Resources/bicep/02-01-fwpolicyrules.bicep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-01-fwpolicyrules.bicep b/035-HubAndSpoke/Student/Resources/bicep/02-01-fwpolicyrules.bicep index fbff822e1c..e5c38d0672 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/02-01-fwpolicyrules.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/02-01-fwpolicyrules.bicep @@ -1,5 +1,5 @@ resource wthafwpolicy 'Microsoft.Network/firewallPolicies@2022-01-01' existing = { - name: 'wth-fwp-premium01' + name: 'wth-fwp-standard01' scope: resourceGroup('wth-rg-hub') } From aebc6e181f1597008798fcfc1ff84de876a36591 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Mon, 19 Dec 2022 10:16:26 -0700 Subject: [PATCH 53/76] fix afw int ip ref --- .../Student/Resources/bicep/02-01-spoke1.bicep | 8 ++++++-- .../Student/Resources/bicep/02-01-spoke2.bicep | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke1.bicep index 68e746b8a1..b1bc353e3f 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke1.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke1.bicep @@ -10,6 +10,11 @@ resource wthspoke1vm01 'Microsoft.Compute/virtualMachines@2022-03-01' existing = scope: resourceGroup('wth-rg-spoke1') } +resource wthafwpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' existing = { + name: 'wth-pip-afw01' + scope: resourceGroup('wth-rg-hub') +} + resource rtspoke1vms 'Microsoft.Network/routeTables@2022-01-01' = { name: 'wth-rt-spoke1vmssubnet' location: location @@ -20,8 +25,7 @@ resource rtspoke1vms 'Microsoft.Network/routeTables@2022-01-01' = { properties: { addressPrefix: '0.0.0.0/0' nextHopType: 'VirtualAppliance' - nextHopIpAddress: wthafw.properties.hubIPAddresses.publicIPs.addresses[0].address - + nextHopIpAddress: wthafw.properties.hubIPAddresses.privateIPAddress } } ] diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke2.bicep b/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke2.bicep index 5dd1d7cf2c..18494bb140 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke2.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke2.bicep @@ -20,7 +20,7 @@ resource rtspoke2vms 'Microsoft.Network/routeTables@2022-01-01' = { properties: { addressPrefix: '0.0.0.0/0' nextHopType: 'VirtualAppliance' - nextHopIpAddress: wthafw.properties.hubIPAddresses.publicIPs.addresses[0].address + nextHopIpAddress: wthafw.properties.hubIPAddresses.privateIPAddress } } From c51d1fde8d1dac7ac84db96ffcee5ce2b22c6b80 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Mon, 19 Dec 2022 15:28:49 -0700 Subject: [PATCH 54/76] fix afw ip refs --- 035-HubAndSpoke/Student/Resources/bicep/02-01-spoke1.bicep | 7 +------ 035-HubAndSpoke/Student/Resources/bicep/02-01-spoke2.bicep | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke1.bicep index b1bc353e3f..fab54341b9 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke1.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke1.bicep @@ -10,11 +10,6 @@ resource wthspoke1vm01 'Microsoft.Compute/virtualMachines@2022-03-01' existing = scope: resourceGroup('wth-rg-spoke1') } -resource wthafwpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' existing = { - name: 'wth-pip-afw01' - scope: resourceGroup('wth-rg-hub') -} - resource rtspoke1vms 'Microsoft.Network/routeTables@2022-01-01' = { name: 'wth-rt-spoke1vmssubnet' location: location @@ -25,7 +20,7 @@ resource rtspoke1vms 'Microsoft.Network/routeTables@2022-01-01' = { properties: { addressPrefix: '0.0.0.0/0' nextHopType: 'VirtualAppliance' - nextHopIpAddress: wthafw.properties.hubIPAddresses.privateIPAddress + nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress } } ] diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke2.bicep b/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke2.bicep index 18494bb140..ea70c7dc35 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke2.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke2.bicep @@ -20,7 +20,7 @@ resource rtspoke2vms 'Microsoft.Network/routeTables@2022-01-01' = { properties: { addressPrefix: '0.0.0.0/0' nextHopType: 'VirtualAppliance' - nextHopIpAddress: wthafw.properties.hubIPAddresses.privateIPAddress + nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress } } From 6da4ad47c06f439f7f8008726eabd86af229702f Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Thu, 22 Dec 2022 14:49:25 -0700 Subject: [PATCH 55/76] automated certificate issuance --- .gitattributes | 3 +- .../Student/Resources/bicep/04-01-hub.bicep | 492 +++++++++--------- .../Student/Resources/bicep/04-02-hub.bicep | 320 ++++++++++++ .../bicep/appGWCertificateProcess.md | 50 ++ .../Student/Resources/bicep/deploy.ps1 | 43 +- .../Student/Resources/bicep/docker/DOCKERFILE | 30 ++ .../Resources/bicep/media/dynv6signup.png | Bin 0 -> 150347 bytes 7 files changed, 690 insertions(+), 248 deletions(-) create mode 100644 035-HubAndSpoke/Student/Resources/bicep/04-02-hub.bicep create mode 100644 035-HubAndSpoke/Student/Resources/bicep/appGWCertificateProcess.md create mode 100644 035-HubAndSpoke/Student/Resources/bicep/docker/DOCKERFILE create mode 100644 035-HubAndSpoke/Student/Resources/bicep/media/dynv6signup.png diff --git a/.gitattributes b/.gitattributes index 6df265fc72..4aa1522deb 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ -.github/workflows/create-wth-template.sh eol=lf \ No newline at end of file +.github/workflows/create-wth-template.sh eol=lf +035-HubAndSpoke/Student/Resources/bicep/docker/DOCKERFILE eol=lf \ No newline at end of file diff --git a/035-HubAndSpoke/Student/Resources/bicep/04-01-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/04-01-hub.bicep index 5fb85c527b..aeacac1835 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/04-01-hub.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/04-01-hub.bicep @@ -1,71 +1,24 @@ -@description('Name of the subnet') -param subnetName string = 'ApplicationGatewaySubnet' - -@description('Application Gateway name') -param applicationGatewayName string = 'wth-appgw-hub01' - -@description('Minimum instance count for Application Gateway') -param minCapacity int = 1 - -@description('Maximum instance count for Application Gateway') -param maxCapacity int = 2 - -@description('Application Gateway Frontend port') -param frontendPort int = 80 - -@description('Application gateway Backend port') -param backendPort int = 80 - -@description('Secret identifier for AppGW TLS private key - ex: https://.vault.azure.net/secrets//') -param appGWTLSSecretID string = 'https://wthotlxegowqsmac.vault.azure.net/secrets/wildcard/0de83a6671604affabc155af5bea1d7f' - -resource wthspoke1vmnic 'Microsoft.Network/networkInterfaces@2022-01-01' existing = { - name: 'wth-nic-spoke1vm01' - scope: resourceGroup('wth-rg-spoke1') -} - -resource wthspoke2vmnic 'Microsoft.Network/networkInterfaces@2022-01-01' existing = { - name: 'wth-nic-spoke2vm01' - scope: resourceGroup('wth-rg-spoke2') -} - -@description('Back end pool ip addresses') -var backendIPAddresses = [ - { - ipAddress: wthspoke1vmnic.properties.ipConfigurations[0].properties.privateIPAddress - } - { - ipAddress: wthspoke2vmnic.properties.ipConfigurations[0].properties.privateIPAddress - } -] - -@description('Cookie based affinity') -@allowed([ - 'Enabled' - 'Disabled' -]) -param cookieBasedAffinity string = 'Disabled' - -@description('Location for all resources.') param location string = resourceGroup().location +@description('This is the domain name you registered for--for example: wthlab.dynv6.com') +param rfc2136ZoneName string +@description('This is the name of the TSIG key you created for your domain; it should start with \'tsig-\'') +param rfc2136TSIGKeyName string +@description('This is the name of the DNS server which accepts RFC2136 updates; for example: \'ns1.dynv6.com\'') +param rfc2136DNSNameserver string = 'ns1.dynv6.com' +param rfc2136KeyAlgorithm string = 'hmac-sha256' +@secure() +param rfc2136TSIGSecret string +@description('Email address where Let\'s Encrypt will send alerts if there are issues with the certificate or it expires. This must be a valid email address and will receive alerts from Let\'s Encrypt, which can be ignored if you\'re no longer running the lab environment.') +param letsEncryptCertAlertEmail string -var appGwPublicIpName = 'wth-pip-appgw01' -var appGwSize = 'Standard_v2' +var dnsUpdaterContainerImage = 'mbrat2005/whatthehackdnsupdate:latest' -resource hubvnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { - name: 'wth-vnet-hub01' - scope: resourceGroup('wth-rg-hub') -} - -resource hubappgwsubnet 'Microsoft.Network/virtualNetworks/subnets@2022-01-01' = { - name: '${hubvnet.name}/ApplicationGatewaySubnet' - properties: { - addressPrefix: '10.0.2.0/24' - } +resource wthlaw 'Microsoft.OperationalInsights/workspaces@2021-12-01-preview' existing = { + name: 'wth-law-default01' } resource keyvault 'Microsoft.KeyVault/vaults@2022-07-01' = { - name: 'wth${uniqueString(subscription().id)}' + name: 'wth${uniqueString(resourceGroup().id)}' location: location properties: { enableSoftDelete: true @@ -90,7 +43,7 @@ resource keyvault 'Microsoft.KeyVault/vaults@2022-07-01' = { } resource publicIP 'Microsoft.Network/publicIPAddresses@2020-06-01' = { - name: appGwPublicIpName + name: 'wth-pip-appgw01' location: location sku: { name: 'Standard' @@ -101,220 +54,273 @@ resource publicIP 'Microsoft.Network/publicIPAddresses@2020-06-01' = { } resource userAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { - name: 'wth-umsi-appgw01' + name: 'wth-umsi-certrequester01' location: location } -resource applicationGateway 'Microsoft.Network/applicationGateways@2020-06-01' = { - name: applicationGatewayName +resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = { + name: 'wthcertreq${uniqueString(resourceGroup().id)}' location: location - identity: { - type: 'UserAssigned' - userAssignedIdentities: { - '${userAssignedIdentity.id}': {} - } + sku: { + name: 'Standard_LRS' } + kind: 'StorageV2' properties: { - sku: { - name: appGwSize - tier: 'Standard_v2' - } - autoscaleConfiguration: { - minCapacity: minCapacity - maxCapacity: maxCapacity - } - sslCertificates: [ - { - name: 'wth_certificate' - properties: { - keyVaultSecretId: appGWTLSSecretID - } + accessTier: 'Hot' + supportsHttpsTrafficOnly: true + } + resource fileSvc 'fileServices@2022-09-01' = { + name: 'default' + + resource fileshare 'shares@2022-09-01' = { + name: 'lego' + properties: { } - ] - gatewayIPConfigurations: [ + } + } +} + +resource roleAssignmentUMIStorageData 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(resourceGroup().id, userAssignedIdentity.id, storageAccount.id, 'data') + properties: { + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0c867c2a-1d8c-454a-a3db-ab2ea1bdc8bb') // Storage File Data SMB Share Contributor + principalId: userAssignedIdentity.properties.principalId + principalType: 'ServicePrincipal' + } +} + +// grant user identity permissions to key vault +resource roleAssignmentUMIKeyVault 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(resourceGroup().id, userAssignedIdentity.id, keyvault.id) + properties: { + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483') // Key Vault Admin + principalId: userAssignedIdentity.properties.principalId + principalType: 'ServicePrincipal' + } +} + +// grant user identity to key vault via access policy +resource accessPolicy 'Microsoft.KeyVault/vaults/accessPolicies@2022-07-01' = { + name: '${keyvault.name}/add' + properties: { + accessPolicies: [ { - name: 'appGatewayIpConfig' - properties: { - subnet: { - id: resourceId('Microsoft.Network/virtualNetworks/subnets', hubvnet.name, subnetName) - } + tenantId: tenant().tenantId + objectId: userAssignedIdentity.properties.principalId + permissions: { + secrets: [ + 'all' + ] + keys: [ + 'all' + ] + certificates: [ + 'all' + ] } } ] - frontendIPConfigurations: [ + } +} + +// using the work of the lego project (https://go-acme.github.io/lego/), requests a publicly trusted certificate from letsencrypt +// the letsencrypt certificate challenge is performed via DNS, so we need to update the DNS record for the domain. +// this was tested with dynv6.com, but should work with any DNS provider that supports RFC2136 +// stores the certificate in the mounted storage account file share +resource containerCertRequester 'Microsoft.ContainerInstance/containerGroups@2022-09-01' = { + name: 'wth-container-certrequester01' + location: location + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${userAssignedIdentity.id}': {} + } + } + properties: { + containers: [ { - name: 'appGatewayFrontendIP' + name: 'wth-container-certrequester01' properties: { - publicIPAddress: { - id: publicIP.id + image: 'goacme/lego:latest' + resources: { + requests: { + cpu: 1 + memoryInGB: 1 + } } - } - } - ] - frontendPorts: [ - { - name: 'appGatewayFrontendPort' - properties: { - port: frontendPort - } - } - { - name: 'appGatewayFrontendPortHttps' - properties: { - port: 443 - } - } - ] - backendAddressPools: [ - { - name: 'appGatewayBackendPool' - properties: { - backendAddresses: backendIPAddresses - } - } - { - name: 'appGatewayBackendPoolSpoke1' - properties: { - backendAddresses: [ - { ipAddress: wthspoke1vmnic.properties.ipConfigurations[0].properties.privateIPAddress } + command: [ + 'lego' + '--domains' + rfc2136ZoneName + '-m' + letsEncryptCertAlertEmail + '--dns' + 'rfc2136' + '-a' + '--pfx' + '--path' + '/lego' + //'--server=https://acme-staging-v02.api.letsencrypt.org/directory' // ust staging environment for testing to avoid rate limits + 'run' ] - } - } - { - name: 'appGatewayBackendPoolSpoke2' - properties: { - backendAddresses: [ - { ipAddress: wthspoke2vmnic.properties.ipConfigurations[0].properties.privateIPAddress } + environmentVariables: [ + { + name: 'RFC2136_NAMESERVER' + value: rfc2136DNSNameserver + } + { + name: 'RFC2136_TSIG_KEY' + value: rfc2136TSIGKeyName + } + { + name: 'RFC2136_TSIG_ALGORITHM' + value: rfc2136KeyAlgorithm + } + { + name: 'RFC2136_TSIG_SECRET' + secureValue: rfc2136TSIGSecret + } + ] + volumeMounts: [ + { + name: 'lego' + mountPath: '/lego' + } ] } } ] - backendHttpSettingsCollection: [ - { - name: 'appGatewayBackendHttpSettings' - properties: { - port: backendPort - protocol: 'Http' - cookieBasedAffinity: cookieBasedAffinity - } - } - { - name: 'appGatewayBackendHttpSettingsSpokes' - properties: { - port: backendPort - protocol: 'Http' - cookieBasedAffinity: cookieBasedAffinity - path: '/' - } - } - ] - httpListeners: [ + osType: 'Linux' + volumes: [ { - name: 'appGatewayHttpListener' - properties: { - frontendIPConfiguration: { - id: resourceId('Microsoft.Network/applicationGateways/frontendIPConfigurations', applicationGatewayName, 'appGatewayFrontendIP') - } - frontendPort: { - id: resourceId('Microsoft.Network/applicationGateways/frontendPorts', applicationGatewayName, 'appGatewayFrontendPort') - } - protocol: 'Http' - } - } - { - name: 'appGatewayHttpsListener' - properties: { - frontendIPConfiguration: { - id: resourceId('Microsoft.Network/applicationGateways/frontendIPConfigurations', applicationGatewayName, 'appGatewayFrontendIP') - } - frontendPort: { - id: resourceId('Microsoft.Network/applicationGateways/frontendPorts', applicationGatewayName, 'appGatewayFrontendPortHttps') - } - protocol: 'Https' - sslCertificate: { - id: resourceId('Microsoft.Network/applicationGateways/sslCertificates', applicationGatewayName, 'wth_certificate') - } + name: 'lego' + azureFile: { + shareName: storageAccount::fileSvc::fileshare.name + storageAccountName: storageAccount.name + storageAccountKey: storageAccount.listKeys().keys[0].value } } ] - requestRoutingRules: [ - { - name: 'requestRoutingRuleDefault' - properties: { - ruleType: 'Basic' - httpListener: { - id: resourceId('Microsoft.Network/applicationGateways/httpListeners', applicationGatewayName, 'appGatewayHttpListener') - } - backendAddressPool: { - id: resourceId('Microsoft.Network/applicationGateways/backendAddressPools', applicationGatewayName, 'appGatewayBackendPool') - } - backendHttpSettings: { - id: resourceId('Microsoft.Network/applicationGateways/backendHttpSettingsCollection', applicationGatewayName, 'appGatewayBackendHttpSettings') - } - } - } - { - name: 'requestRoutingRuleSpokes' - properties: { - ruleType: 'PathBasedRouting' - urlPathMap: { - id: resourceId('Microsoft.Network/applicationGateways/urlPathMaps', applicationGatewayName, 'urlPathMapSpokes') - } - httpListener: { - id: resourceId('Microsoft.Network/applicationGateways/httpListeners', applicationGatewayName, 'appGatewayHttpsListener') - } - backendAddressPool: { - id: resourceId('Microsoft.Network/applicationGateways/backendAddressPools', applicationGatewayName, 'appGatewayBackendPool') - } - backendHttpSettings: { - id: resourceId('Microsoft.Network/applicationGateways/backendHttpSettingsCollection', applicationGatewayName, 'appGatewayBackendHttpSettings') - } - } + restartPolicy: 'Never' + sku: 'Standard' + diagnostics: { + logAnalytics: { + workspaceId: wthlaw.properties.customerId + workspaceKey: listKeys(wthlaw.id, wthlaw.apiVersion).primarySharedKey } - ] - urlPathMaps: [ + } + } +} + +// updates the DNS zone with an A record for the Application Gateway's public IP address +// uses 'nsupdate' in a custom container image referenced in this variable: dnsUpdaterContainerImage +// the container image is built from the Dockerfile in the 'docker' folder of this repo +// this was tested with dynv6.com, but should work with any DNS provider that supports RFC2136 +resource containerDNSUpdater 'Microsoft.ContainerInstance/containerGroups@2022-09-01' = { + name: 'wth-container-dnsupdater01' + location: location + dependsOn: [ + containerCertRequester + ] + properties: { + containers: [ { - name: 'urlPathMapSpokes' + name: 'wth-container-dnsupdater01' properties: { - defaultBackendAddressPool: { - id: resourceId('Microsoft.Network/applicationGateways/backendAddressPools', applicationGatewayName, 'appGatewayBackendPool') - } - defaultBackendHttpSettings: { - id: resourceId('Microsoft.Network/applicationGateways/backendHttpSettingsCollection', applicationGatewayName, 'appGatewayBackendHttpSettings') + image: dnsUpdaterContainerImage + resources: { + requests: { + cpu: 1 + memoryInGB: 1 + } } - pathRules: [ + command: [] + environmentVariables: [ + { + name: 'ZONENAME' + value: rfc2136ZoneName + } + { + name: 'KEYNAME' + value: rfc2136TSIGKeyName + } + { + name: 'KEYALGORITHM' + value: rfc2136KeyAlgorithm + } + { + name: 'KEYVALUE' + secureValue: rfc2136TSIGSecret + } { - name: 'spoke1' - properties: { - paths: [ - '/spoke1/*' - ] - backendAddressPool: { - id: resourceId('Microsoft.Network/applicationGateways/backendAddressPools', applicationGatewayName, 'appGatewayBackendPoolSpoke1') - } - backendHttpSettings: { - id: resourceId('Microsoft.Network/applicationGateways/backendHttpSettingsCollection', applicationGatewayName, 'appGatewayBackendHttpSettingsSpokes') - } - } + name: 'APPGWPUBLICIP' + value: publicIP.properties.ipAddress } { - name: 'spoke2' - properties: { - paths: [ - '/spoke2/*' - ] - backendAddressPool: { - id: resourceId('Microsoft.Network/applicationGateways/backendAddressPools', applicationGatewayName, 'appGatewayBackendPoolSpoke2') - } - backendHttpSettings: { - id: resourceId('Microsoft.Network/applicationGateways/backendHttpSettingsCollection', applicationGatewayName, 'appGatewayBackendHttpSettingsSpokes') - } - } + name: 'NAMESERVER' + value: rfc2136DNSNameserver } ] } } ] - enableHttp2: true + osType: 'Linux' + restartPolicy: 'Never' + sku: 'Standard' + diagnostics: { + logAnalytics: { + workspaceId: wthlaw.properties.customerId + workspaceKey: listKeys(wthlaw.id, wthlaw.apiVersion).primarySharedKey + } + } + } +} + +// uploads the certificate previously exported to the storage account file share to the key vault +// from the key vault, the certificate will be available to the Application Gateway +resource deploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { + name: 'wth-dscript-uploadcert01' + location: location + dependsOn: [ + containerCertRequester + ] + kind: 'AzurePowerShell' + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${userAssignedIdentity.id}': {} + } + } + properties: { + azPowerShellVersion: '8.3' + cleanupPreference: 'OnSuccess' + retentionInterval: 'PT1H' + arguments: '-resourceGroup "${resourceGroup().name}" -storageAccountName "${storageAccount.name}" -keyVaultName "${keyvault.name}" -shareName "${storageAccount::fileSvc::fileshare.name}"' + scriptContent: ''' + param($resourceGroup, $storageAccountName, $keyVaultName, $shareName) + + $DeploymentScriptOutputs = @{} + $DeploymentScriptOutputs['text'] = '' + + $context = (Get-AzStorageAccount -Name $storageAccountName -ResourceGroupName $resourceGroup).context + $directory = Get-AzStorageFile -ShareName $shareName -Path 'certificates' -Context $context + $pfxFile = $directory.CloudFileDirectory.ListFilesAndDirectories() | Where-Object { $_.Name -like '*.pfx' } + + If ($pfxFile) { + $pfxFile.DownloadToFile('/cert.pfx','CreateNew') + } + Else { + throw 'No certificate file found in the storage account file share--check the certificate requester "wth-container-certrequester01" container logs for errors.' + } + + $cert = Import-AzKeyVaultCertificate -Name appGWCert -VaultName $keyVaultName -FilePath '/cert.pfx' -Password (ConvertTo-SecureString -Force -AsPlainText 'changeit') + + $DeploymentScriptOutputs['text'] = $cert.SecretId + ''' + containerSettings: { + containerGroupName: 'wth-container-certuploader01' + } } } + +output TLSCertKeyVaultSecretID string = reference(deploymentScript.id).outputs.text diff --git a/035-HubAndSpoke/Student/Resources/bicep/04-02-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/04-02-hub.bicep new file mode 100644 index 0000000000..79ee5ce76b --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/04-02-hub.bicep @@ -0,0 +1,320 @@ +@description('Name of the subnet') +param subnetName string = 'ApplicationGatewaySubnet' + +@description('Application Gateway name') +param applicationGatewayName string = 'wth-appgw-hub01' + +@description('Minimum instance count for Application Gateway') +param minCapacity int = 1 + +@description('Maximum instance count for Application Gateway') +param maxCapacity int = 2 + +@description('Application Gateway Frontend port') +param frontendPort int = 80 + +@description('Application gateway Backend port') +param backendPort int = 80 + +@description('Secret identifier for AppGW TLS private key - ex: https://.vault.azure.net/secrets//') +param TLSCertKeyVaultSecretID string // = 'https://wthotlxegowqsmac.vault.azure.net/secrets/wildcard/0de83a6671604affabc155af5bea1d7f' + +resource wthspoke1vmnic 'Microsoft.Network/networkInterfaces@2022-01-01' existing = { + name: 'wth-nic-spoke1vm01' + scope: resourceGroup('wth-rg-spoke1') +} + +resource wthspoke2vmnic 'Microsoft.Network/networkInterfaces@2022-01-01' existing = { + name: 'wth-nic-spoke2vm01' + scope: resourceGroup('wth-rg-spoke2') +} + +@description('Back end pool ip addresses') +var backendIPAddresses = [ + { + ipAddress: wthspoke1vmnic.properties.ipConfigurations[0].properties.privateIPAddress + } + { + ipAddress: wthspoke2vmnic.properties.ipConfigurations[0].properties.privateIPAddress + } +] + +@description('Cookie based affinity') +@allowed([ + 'Enabled' + 'Disabled' +]) +param cookieBasedAffinity string = 'Disabled' + +@description('Location for all resources.') +param location string = resourceGroup().location + +var appGwPublicIpName = 'wth-pip-appgw01' +var appGwSize = 'Standard_v2' + +resource hubvnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { + name: 'wth-vnet-hub01' + scope: resourceGroup('wth-rg-hub') +} + +resource hubappgwsubnet 'Microsoft.Network/virtualNetworks/subnets@2022-01-01' = { + name: '${hubvnet.name}/ApplicationGatewaySubnet' + properties: { + addressPrefix: '10.0.2.0/24' + } +} + +resource keyvault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: 'wth${uniqueString(resourceGroup().id)}' + location: location + properties: { + enableSoftDelete: true + enablePurgeProtection: true + sku: { + name: 'standard' + family: 'A' + } + tenantId: tenant().tenantId + accessPolicies: [ + { + objectId: userAssignedIdentity.properties.principalId + permissions: { + secrets: [ + 'all' + ] + } + tenantId: tenant().tenantId + } + ] + } +} + +resource publicIP 'Microsoft.Network/publicIPAddresses@2020-06-01' = { + name: 'wth-pip-appgw01' + location: location + sku: { + name: 'Standard' + } + properties: { + publicIPAllocationMethod: 'Static' + } +} + +resource userAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: 'wth-umsi-appgw01' + location: location +} + +resource applicationGateway 'Microsoft.Network/applicationGateways@2020-06-01' = { + name: applicationGatewayName + location: location + identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${userAssignedIdentity.id}': {} + } + } + properties: { + sku: { + name: appGwSize + tier: 'Standard_v2' + } + autoscaleConfiguration: { + minCapacity: minCapacity + maxCapacity: maxCapacity + } + sslCertificates: [ + { + name: 'wth_certificate' + properties: { + keyVaultSecretId: TLSCertKeyVaultSecretID + } + } + ] + gatewayIPConfigurations: [ + { + name: 'appGatewayIpConfig' + properties: { + subnet: { + id: resourceId('Microsoft.Network/virtualNetworks/subnets', hubvnet.name, subnetName) + } + } + } + ] + frontendIPConfigurations: [ + { + name: 'appGatewayFrontendIP' + properties: { + publicIPAddress: { + id: publicIP.id + } + } + } + ] + frontendPorts: [ + { + name: 'appGatewayFrontendPort' + properties: { + port: frontendPort + } + } + { + name: 'appGatewayFrontendPortHttps' + properties: { + port: 443 + } + } + ] + backendAddressPools: [ + { + name: 'appGatewayBackendPool' + properties: { + backendAddresses: backendIPAddresses + } + } + { + name: 'appGatewayBackendPoolSpoke1' + properties: { + backendAddresses: [ + { ipAddress: wthspoke1vmnic.properties.ipConfigurations[0].properties.privateIPAddress } + ] + } + } + { + name: 'appGatewayBackendPoolSpoke2' + properties: { + backendAddresses: [ + { ipAddress: wthspoke2vmnic.properties.ipConfigurations[0].properties.privateIPAddress } + ] + } + } + ] + backendHttpSettingsCollection: [ + { + name: 'appGatewayBackendHttpSettings' + properties: { + port: backendPort + protocol: 'Http' + cookieBasedAffinity: cookieBasedAffinity + } + } + { + name: 'appGatewayBackendHttpSettingsSpokes' + properties: { + port: backendPort + protocol: 'Http' + cookieBasedAffinity: cookieBasedAffinity + path: '/' + } + } + ] + httpListeners: [ + { + name: 'appGatewayHttpListener' + properties: { + frontendIPConfiguration: { + id: resourceId('Microsoft.Network/applicationGateways/frontendIPConfigurations', applicationGatewayName, 'appGatewayFrontendIP') + } + frontendPort: { + id: resourceId('Microsoft.Network/applicationGateways/frontendPorts', applicationGatewayName, 'appGatewayFrontendPort') + } + protocol: 'Http' + } + } + { + name: 'appGatewayHttpsListener' + properties: { + frontendIPConfiguration: { + id: resourceId('Microsoft.Network/applicationGateways/frontendIPConfigurations', applicationGatewayName, 'appGatewayFrontendIP') + } + frontendPort: { + id: resourceId('Microsoft.Network/applicationGateways/frontendPorts', applicationGatewayName, 'appGatewayFrontendPortHttps') + } + protocol: 'Https' + sslCertificate: { + id: resourceId('Microsoft.Network/applicationGateways/sslCertificates', applicationGatewayName, 'wth_certificate') + } + } + } + ] + requestRoutingRules: [ + { + name: 'requestRoutingRuleDefault' + properties: { + ruleType: 'Basic' + httpListener: { + id: resourceId('Microsoft.Network/applicationGateways/httpListeners', applicationGatewayName, 'appGatewayHttpListener') + } + backendAddressPool: { + id: resourceId('Microsoft.Network/applicationGateways/backendAddressPools', applicationGatewayName, 'appGatewayBackendPool') + } + backendHttpSettings: { + id: resourceId('Microsoft.Network/applicationGateways/backendHttpSettingsCollection', applicationGatewayName, 'appGatewayBackendHttpSettings') + } + } + } + { + name: 'requestRoutingRuleSpokes' + properties: { + ruleType: 'PathBasedRouting' + urlPathMap: { + id: resourceId('Microsoft.Network/applicationGateways/urlPathMaps', applicationGatewayName, 'urlPathMapSpokes') + } + httpListener: { + id: resourceId('Microsoft.Network/applicationGateways/httpListeners', applicationGatewayName, 'appGatewayHttpsListener') + } + backendAddressPool: { + id: resourceId('Microsoft.Network/applicationGateways/backendAddressPools', applicationGatewayName, 'appGatewayBackendPool') + } + backendHttpSettings: { + id: resourceId('Microsoft.Network/applicationGateways/backendHttpSettingsCollection', applicationGatewayName, 'appGatewayBackendHttpSettings') + } + } + } + ] + urlPathMaps: [ + { + name: 'urlPathMapSpokes' + properties: { + defaultBackendAddressPool: { + id: resourceId('Microsoft.Network/applicationGateways/backendAddressPools', applicationGatewayName, 'appGatewayBackendPool') + } + defaultBackendHttpSettings: { + id: resourceId('Microsoft.Network/applicationGateways/backendHttpSettingsCollection', applicationGatewayName, 'appGatewayBackendHttpSettings') + } + pathRules: [ + { + name: 'spoke1' + properties: { + paths: [ + '/spoke1/*' + ] + backendAddressPool: { + id: resourceId('Microsoft.Network/applicationGateways/backendAddressPools', applicationGatewayName, 'appGatewayBackendPoolSpoke1') + } + backendHttpSettings: { + id: resourceId('Microsoft.Network/applicationGateways/backendHttpSettingsCollection', applicationGatewayName, 'appGatewayBackendHttpSettingsSpokes') + } + } + } + { + name: 'spoke2' + properties: { + paths: [ + '/spoke2/*' + ] + backendAddressPool: { + id: resourceId('Microsoft.Network/applicationGateways/backendAddressPools', applicationGatewayName, 'appGatewayBackendPoolSpoke2') + } + backendHttpSettings: { + id: resourceId('Microsoft.Network/applicationGateways/backendHttpSettingsCollection', applicationGatewayName, 'appGatewayBackendHttpSettingsSpokes') + } + } + } + ] + } + } + ] + enableHttp2: true + } +} diff --git a/035-HubAndSpoke/Student/Resources/bicep/appGWCertificateProcess.md b/035-HubAndSpoke/Student/Resources/bicep/appGWCertificateProcess.md new file mode 100644 index 0000000000..113e02f5af --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/appGWCertificateProcess.md @@ -0,0 +1,50 @@ +# Process for generating and assigning a publicly trusted certificate to the Application Gateway + +The process below describes the steps necessary to utilize automation to generate and publish a new publicly trusted certificate for the Application Gateway used in this lab. + +If you already have a certificate and domain you would like to use, see 'Use my own domain and certificate below' +## Register for a Domain Name and Create an API Key + +These instructions will use https://dynv6.com to register a free domain name you can use for this lab. Other free DNS providers are likely also compatible, as long as they support updates following the RFC2136 standard (which the lab automation has been written to use); however, you will need to pass a different value for the rfc2136DNSNameserver parameter on the '04-01-hub.bicep' template. + +1. Navigate to https://dynv6.com and register a new unique domain name--for example: `wthdom.dynv6.net` +1. Complete your registration by confirming your email address +1. After logging in, create a new TSIG Key: + 1. Click your email address at the top right corner of the screen and select the **Keys** link + 1. Click the **Add TSIG Key** button + 1. In the "Add a new TSIG Key" screen, select Algorithm: **hmac-sha256** + 1. Click **Generate TSIG Key** + 1. Click the **Details** button on the new key, then copy the following values to your notes: + TSIG Key Name (starts with 'tsig-') + TSIG Algorithm (should be 'hmac-sha256') + TSIG Secret (long string, usually ending in '==') + +## Provide DNS Details During Deployment + +When running the deploy.ps1 script to deploy Challenge 4, you will be prompted for the above parameter values, which you can paste into the terminal. + +## Troubleshooting + +Automating generating a certificate for Application Gateway has three main components to consider: + +- Certificate issuance: This step requests a certificate from Let's Encrypt using the 'acme-go/lego' container image. The Bicep deployment creates a Container Group/Instance with this image, and requests a certificate. In order to validate that you own the domain name you are requesting a certificate for, Let's Encrypt will complete a 'dns' challenge, where it authenticates to your DNS provider (DynV6, for example). After confirming you have valid credentials for the domain name, a certificate is issued and stored in an Azure Storage Account. +- Certificate upload to Key Vault: This step uses a Deployment Script resource to execute an Azure PowerShell script that uploads the above certificate from the Storage Account to an Azure Key Vault. This is necessary because the Application Gateway will access the certificate from the Key Vault. +- DNS record update: Lastly, the domain name used for the certificate needs to point to the Application Gateway's Public IP Address, so that when you nagivate to that domain, App Gateway responds to the request and forwards it to your backend pool servers. + +Each of the above steps use Azure Container Instances to perform the required automation. The container will typically output logs, viewable in the Portal by navigating to the Container Group resource or Deployment Script resource. In addition to logs, the Container Groups are set to output diagnostic information to the lab Log Analytics Workspace, which may be helpful. + +## Use my own domain and certificate + +You can skip this step by passing a Key Vault secret ID in the -challengeParameters parameter of the deploy script. The Application Gateway's identity will need access to this Key Vault to retrieve the certificate secret. For example: + +```powershell +./deploy.ps1 -ChallengeNumber 4 -ChallengeParameters @{existingTLSCertKeyVaultSecretID='https://wthotlxegowqsmac.vault.azure.net/secrets/wildcard/0de83a6671604affabc155af5bea1d7f'} +``` + +If you do this, you will need to perform the following steps yourself: + +- Create a certificate for your domain name (wildcard certificates can work) +- Upload a certificate PFX to the KeyVault created in the 'wth-rg-hub' resource group +- Create or update a DNS 'A' record with your DNS provider (ie: GoDaddy, Azure DNS, etc.) that points to the Application Gateway's Public IP Address +- Ensure that the Application Gateway identity has permission to access the uploaded certificate's secret +- Pass the certificate secret ID (and version number) as a -challengeParameters, as shown above \ No newline at end of file diff --git a/035-HubAndSpoke/Student/Resources/bicep/deploy.ps1 b/035-HubAndSpoke/Student/Resources/bicep/deploy.ps1 index 973f17775d..0a4540da9b 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/deploy.ps1 +++ b/035-HubAndSpoke/Student/Resources/bicep/deploy.ps1 @@ -40,7 +40,12 @@ param ( # confirm subscription and resource types [Parameter(Mandatory=$false)] [System.Boolean] - $confirm = $true + $confirm = $true, + + # challenge parameters + [parameter(Mandatory = $false)] + [hashtable] + $challengeParameters = @{} ) $ErrorActionPreference = 'Stop' @@ -244,11 +249,41 @@ switch ($challengeNumber) { 4 { Write-Host "Deploying resources for Challenge 4: Application Gateway" + If ($challengeParameters.ContainsKey('existingtlsCertKeyVaultSecretID')) { + $tlsCertKeyVaultSecretID = $challengeParameters['existingtlsCertKeyVaultSecretID'] + } + Else { + + Write-Host "`tDeploying ceriticate and DNS update solution...`n" + Write-Host "This deployment step requires a manual action to complete. Please follow the instructions in the 035-HubAndSpoke\Student\Resources\bicep\appGWCertificateProcess.md file to complete these steps. This solution assumes you are using Dynv6 for a DNS provider; to use another povider or an existing certificate, see the above document for more information.`n" + + Read-Host "Once you have completed the required steps and noted the required information, hit ENTER to proceed (ctrl + c to cancel)..." + + If ($response -match 'nN') { exit } + + $jobs = @() + $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./04-01-hub.bicep -TemplateParameterObject @{ location = $location } -AsJob + + $jobs | Wait-Job | Out-Null + + # check for deployment errors + $jobs | Foreach-Object { + $job = $_ + If ($job.Error) { + Write-Error "A hub or spoke configuration deployment experienced an error: $($job.error)" + } + } + + $tlsCertKeyVaultSecretID = $jobs[0].Output.Outputs.tlsCertKeyVaultSecretID.value + + If ($null -eq $tlsCertKeyVaultSecretID) { + Write-Error "An error occured during the deployment of the certificate and DNS update solution--the certificate ID was not returned. Please see the troubleshooting section of the 035-HubAndSpoke\Student\Resources\bicep\appGWCertificateProcess.md file for more information." -ErrorAction Stop + } + } + Write-Host "`tDeploying App GW configs..." $jobs = @() - #$jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./03-01-spoke1.bicep -TemplateParameterObject @{location = $location } -AsJob - #$jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./03-01-spoke2.bicep -TemplateParameterObject @{location = $location } -AsJob - $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./04-01-hub.bicep -TemplateParameterObject @{location = $location } -AsJob + $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./04-02-hub.bicep -TemplateParameterObject @{location = $location; tlsCertKeyVaultSecretID = $tlsCertKeyVaultSecretID } -AsJob $jobs | Wait-Job | Out-Null diff --git a/035-HubAndSpoke/Student/Resources/bicep/docker/DOCKERFILE b/035-HubAndSpoke/Student/Resources/bicep/docker/DOCKERFILE new file mode 100644 index 0000000000..3d5ddadc03 --- /dev/null +++ b/035-HubAndSpoke/Student/Resources/bicep/docker/DOCKERFILE @@ -0,0 +1,30 @@ +# syntax=docker/dockerfile:1.3-labs +FROM alpine:latest + +RUN apk add bind-tools + +# create input file for the nsupdate command, using placeholders for the values that will be passed in as environment variables +COPY <> +zone <> +update delete <> A +update add <> 60 A <> +key <>:<> <> +send +EOF + +# create the script that will replace the placeholders with the values passed in as environment variables, then call nsupdate +COPY <<'EOF' /home/updateDNS.sh +#!/bin/sh +sed -i /home/nsupdate.temp -e "s~<>~$ZONENAME~g" +sed -i /home/nsupdate.temp -e "s~<>~$KEYNAME~g" +sed -i /home/nsupdate.temp -e "s~<>~$APPGWPUBLICIP~g" +sed -i /home/nsupdate.temp -e "s~<>~$KEYVALUE~g" +sed -i /home/nsupdate.temp -e "s~<>~$KEYALGORITHM~g" +sed -i /home/nsupdate.temp -e "s~<>~$NAMESERVER~g" +nsupdate /home/nsupdate.temp +EOF + +RUN chmod 700 /home/updateDNS.sh + +CMD ["/bin/sh", "/home/updateDNS.sh"] \ No newline at end of file diff --git a/035-HubAndSpoke/Student/Resources/bicep/media/dynv6signup.png b/035-HubAndSpoke/Student/Resources/bicep/media/dynv6signup.png new file mode 100644 index 0000000000000000000000000000000000000000..25815215f892ce0541c32649be0e0db9fbcb6682 GIT binary patch literal 150347 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

AP-_kPYFziho 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 z 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 Date: Tue, 27 Dec 2022 09:28:55 -0700 Subject: [PATCH 56/76] add self-signed cert option --- .../Student/Resources/bicep/04-01-hub.bicep | 98 ++++++++++++++++++- .../bicep/appGWCertificateProcess.md | 17 +++- .../Student/Resources/bicep/deploy.ps1 | 6 +- 3 files changed, 111 insertions(+), 10 deletions(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/04-01-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/04-01-hub.bicep index aeacac1835..4aca636f70 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/04-01-hub.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/04-01-hub.bicep @@ -10,6 +10,8 @@ param rfc2136KeyAlgorithm string = 'hmac-sha256' param rfc2136TSIGSecret string @description('Email address where Let\'s Encrypt will send alerts if there are issues with the certificate or it expires. This must be a valid email address and will receive alerts from Let\'s Encrypt, which can be ignored if you\'re no longer running the lab environment.') param letsEncryptCertAlertEmail string +@description('Alternative to using Let\'s Encrypt, you can use a self-signed certificate. This is useful if you are having issues with the Let\'s Encrypt certificate request process. NOTE: You will still need a domain domain name registered for the lab environment.') +param useSelfSignedCertificate bool = false var dnsUpdaterContainerImage = 'mbrat2005/whatthehackdnsupdate:latest' @@ -127,7 +129,7 @@ resource accessPolicy 'Microsoft.KeyVault/vaults/accessPolicies@2022-07-01' = { // the letsencrypt certificate challenge is performed via DNS, so we need to update the DNS record for the domain. // this was tested with dynv6.com, but should work with any DNS provider that supports RFC2136 // stores the certificate in the mounted storage account file share -resource containerCertRequester 'Microsoft.ContainerInstance/containerGroups@2022-09-01' = { +resource containerCertRequester 'Microsoft.ContainerInstance/containerGroups@2022-09-01' = if (useSelfSignedCertificate == false) { name: 'wth-container-certrequester01' location: location identity: { @@ -278,7 +280,7 @@ resource containerDNSUpdater 'Microsoft.ContainerInstance/containerGroups@2022-0 // uploads the certificate previously exported to the storage account file share to the key vault // from the key vault, the certificate will be available to the Application Gateway -resource deploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { +resource deploymentScriptCertUploader 'Microsoft.Resources/deploymentScripts@2020-10-01' = if (useSelfSignedCertificate == false) { name: 'wth-dscript-uploadcert01' location: location dependsOn: [ @@ -323,4 +325,94 @@ resource deploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { } } -output TLSCertKeyVaultSecretID string = reference(deploymentScript.id).outputs.text +resource deploymentScriptSelfSignedCert 'Microsoft.Resources/deploymentScripts@2020-10-01' = if (useSelfSignedCertificate) { +name: 'wth-dscript-genselfsignedcert01' +location: location +kind: 'AzurePowerShell' +identity: { + type: 'UserAssigned' + userAssignedIdentities: { + '${userAssignedIdentity.id}': {} + } +} +properties: { + azPowerShellVersion: '8.3' + cleanupPreference: 'OnSuccess' + retentionInterval: 'PT1H' + arguments: '-keyVaultName "${keyvault.name}" -domainName "${rfc2136ZoneName}"' + scriptContent: ''' + param($keyVaultName, $domainName) + + $DeploymentScriptOutputs = @{} + $DeploymentScriptOutputs['text'] = '' + + $body = @" + { + "policy": { + "key_props": { + "exportable": true, + "kty": "RSA", + "key_size": 2048, + "reuse_key": false + }, + "secret_props": { + "contentType": "application/x-pkcs12" + }, + "x509_props": { + "subject": "CN=$domainName", + "sans": { + "dns_names": [ + "$domainName" + ] + } + }, + "issuer": { + "name": "Self" + } + } + } +"@ + + # create a certificate request in the key vault + $certName = 'appGWSelfSignedCert' + (get-date -f 'yyyyMMddHHmmss') + $response = Invoke-AzRestMethod -Method POST -URI "https://$keyVaultName.vault.azure.net//certificates/$certName/create?api-version=7.3" -Payload $body + + $responseBody = $response.Content | ConvertFrom-Json -Depth 10 + If ($response.StatusCode -ne 202) { + throw "Error creating self-signed certificate in key vault. $($response.StatusCode, $responseBody.Error, $responseBody.status, $responseBody.status_details)" + } + + # wait for the certificate request to complete + $timeout = 600 + $secondsElapsed = 0 + do { + $secondsElapsed = $secondsElapsed + 1 + $response = Invoke-AzRestMethod -Method GET -URI "https://$keyVaultName.vault.azure.net//certificates/$certName/pending?api-version=7.3" + + If ($response.StatusCode -ne 200) { + $responseBody = $response.Content | ConvertFrom-Json -Depth 10 + throw "Error getting self-signed certificate status in key vault. $($response.StatusCode, $responseBody.Error,$responseBody.status, $responseBody.status_details)" + } + + Start-Sleep -Seconds 1 + } + until (($responseBody = $response.Content | ConvertFrom-Json -Depth 10).status -eq 'completed' -or ($secondsElapsed -ge $timeout)) + + If ($secondsElapsed -ge $timeout) { + throw "Timeout waiting for self-signed certificate to complete in key vault." + } + + # get the completed certificate ID + $response = Invoke-AzRestMethod -Method GET -URI "https://$keyVaultName.vault.azure.net//certificates/$certName`?api-version=7.3" + $responseBody = $response.Content | ConvertFrom-Json -Depth 10 + + # return the completed certificate ID to the deployment script output + $DeploymentScriptOutputs['text'] = $responseBody.sid + ''' +containerSettings: { + containerGroupName: 'wth-container-genselfsignedcert01' + } +} +} + +output TLSCertKeyVaultSecretID string = useSelfSignedCertificate ? reference(deploymentScriptSelfSignedCert.id, '2020-10-01').outputs.text : reference(deploymentScriptCertUploader.id, '2020-10-01').outputs.text diff --git a/035-HubAndSpoke/Student/Resources/bicep/appGWCertificateProcess.md b/035-HubAndSpoke/Student/Resources/bicep/appGWCertificateProcess.md index 113e02f5af..5f1dda06a6 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/appGWCertificateProcess.md +++ b/035-HubAndSpoke/Student/Resources/bicep/appGWCertificateProcess.md @@ -1,8 +1,9 @@ -# Process for generating and assigning a publicly trusted certificate to the Application Gateway +# Process for generating and assigning a certificate to the Application Gateway -The process below describes the steps necessary to utilize automation to generate and publish a new publicly trusted certificate for the Application Gateway used in this lab. +The process below describes the steps necessary to utilize automation to generate and publish a new publicly trusted certificate for the Application Gateway used in this lab. + +The default process uses Let's Encrypt to generate a publicly trusted certificate. If you already have a certificate and domain you would like to use, see 'Use my own domain and certificate below'. If there are issues with the Let's Encrypt certificate request process, a self-signed certificate can be used -If you already have a certificate and domain you would like to use, see 'Use my own domain and certificate below' ## Register for a Domain Name and Create an API Key These instructions will use https://dynv6.com to register a free domain name you can use for this lab. Other free DNS providers are likely also compatible, as long as they support updates following the RFC2136 standard (which the lab automation has been written to use); however, you will need to pass a different value for the rfc2136DNSNameserver parameter on the '04-01-hub.bicep' template. @@ -47,4 +48,12 @@ If you do this, you will need to perform the following steps yourself: - Upload a certificate PFX to the KeyVault created in the 'wth-rg-hub' resource group - Create or update a DNS 'A' record with your DNS provider (ie: GoDaddy, Azure DNS, etc.) that points to the Application Gateway's Public IP Address - Ensure that the Application Gateway identity has permission to access the uploaded certificate's secret -- Pass the certificate secret ID (and version number) as a -challengeParameters, as shown above \ No newline at end of file +- Pass the certificate secret ID (and version number) as a -challengeParameters, as shown above + +## Use a self-signed certificate + +If there are issues with the certificate request process from Let's Encrypt, you can alternatively have the Key Vault generate a self-signed certificate for you. Use this option by passing the `@{useSelfSignedCertificate=$true}` challenge parameter when running deploy.ps1. For example: + +```powershell +./deploy.ps1 -ChallengeNumber 4 -ChallengeParameters @{useSelfSignedCertificate=$true} +``` diff --git a/035-HubAndSpoke/Student/Resources/bicep/deploy.ps1 b/035-HubAndSpoke/Student/Resources/bicep/deploy.ps1 index 0a4540da9b..1a136eb930 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/deploy.ps1 +++ b/035-HubAndSpoke/Student/Resources/bicep/deploy.ps1 @@ -254,15 +254,15 @@ switch ($challengeNumber) { } Else { - Write-Host "`tDeploying ceriticate and DNS update solution...`n" + Write-Host "`tDeploying certificate and DNS update solution...`n" Write-Host "This deployment step requires a manual action to complete. Please follow the instructions in the 035-HubAndSpoke\Student\Resources\bicep\appGWCertificateProcess.md file to complete these steps. This solution assumes you are using Dynv6 for a DNS provider; to use another povider or an existing certificate, see the above document for more information.`n" - Read-Host "Once you have completed the required steps and noted the required information, hit ENTER to proceed (ctrl + c to cancel)..." + Read-Host "Once you have completed the required steps and noted the DNS API details, hit ENTER to proceed (ctrl + c to cancel)..." If ($response -match 'nN') { exit } $jobs = @() - $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./04-01-hub.bicep -TemplateParameterObject @{ location = $location } -AsJob + $jobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./04-01-hub.bicep -TemplateParameterObject @{ location = $location; useSelfSignedCertificate = $challengeParameters.ContainsKey('useSelfSignedCertificate') } -AsJob $jobs | Wait-Job | Out-Null From 01620285faf5694d4e4bb8070abf79673d426561 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Tue, 27 Dec 2022 09:30:52 -0700 Subject: [PATCH 57/76] fix paas link casing --- 035-HubAndSpoke/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/035-HubAndSpoke/README.md b/035-HubAndSpoke/README.md index 8dc5cb24ee..098e82f193 100644 --- a/035-HubAndSpoke/README.md +++ b/035-HubAndSpoke/README.md @@ -42,7 +42,7 @@ These are your challenges, it is recommended to start with the first one and pro - Troubleshoot a routing problem introduced by a different admin - Challenge 4: **[Application Gateway](Student/04-AppGW.md)** - Add an Application Gateway to the mix -- Challenge 5: **[PaaS Networking](Student/05-Paas.md)** +- Challenge 5: **[PaaS Networking](Student/05-PaaS.md)** - Integrate Azure Web Apps and Azure SQL Databases with your hub and spoke design ## Prerequisites From f5903e3539a35371052840020f7bed3e579da034 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Tue, 27 Dec 2022 14:58:57 -0700 Subject: [PATCH 58/76] wip: challenge 5 --- .../Student/Resources/bicep/05-01-hub.bicep | 169 +++++++++++++++++- .../Resources/bicep/05-01-spoke1.bicep | 51 +++--- .../Resources/bicep/05-01-spoke2.bicep | 50 ++---- .../Student/Resources/bicep/README.md | 12 +- 4 files changed, 219 insertions(+), 63 deletions(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/05-01-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/05-01-hub.bicep index 04e90d6e2e..71d94a92f4 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/05-01-hub.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/05-01-hub.bicep @@ -2,22 +2,179 @@ param location string = 'eastus2' resource hubvnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { name: 'wth-vnet-hub01' - scope: resourceGroup('wth-rg-hub') +} + +resource spoke1vnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { + name: 'wth-vnet-spoke101' + scope: resourceGroup('wth-rg-spoke1') +} + +resource spoke2vnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { + name: 'wth-vnet-spoke201' + scope: resourceGroup('wth-rg-spoke2') } resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { name: 'privatelink.database.windows.net' location: 'global' + properties: { + } } -resource dnsvnetlink 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2020-06-01' = { +resource privateDnsZoneWeb 'Microsoft.Network/privateDnsZones@2018-09-01' = { + name: 'privatelink.azurewebsites.net' + location: 'global' +} + +resource dnsvnetlinkhub 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2020-06-01' = { name: 'wth-dnsvnetlink-hub' parent: privateDNSZone - location: 'global' + location: 'global' + properties: { + registrationEnabled: false + virtualNetwork: { + id: hubvnet.id + } + } +} + +resource dnsvnetlinkspoke1 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2020-06-01' = { + name: 'wth-dnsvnetlink-spoke1' + parent: privateDNSZone + location: 'global' + properties: { + registrationEnabled: false + virtualNetwork: { + id: spoke1vnet.id + } + } +} + +resource dnsvnetlinkspoke2 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2020-06-01' = { + name: 'wth-dnsvnetlink-spoke2' + parent: privateDNSZone + location: 'global' + properties: { + registrationEnabled: false + virtualNetwork: { + id: spoke2vnet.id + } + } +} + +resource dnsvnetlinkhubweb 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2020-06-01' = { + name: 'wth-dnsvnetlink-webhub' + parent: privateDnsZoneWeb + location: 'global' + properties: { + registrationEnabled: false + virtualNetwork: { + id: hubvnet.id + } + } +} + +resource dnsvnetlinkwebspoke1 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2020-06-01' = { + name: 'wth-dnsvnetlink-webspoke1' + parent: privateDnsZoneWeb + location: 'global' properties: { - registrationEnabled: true - virtualNetwork: { + registrationEnabled: false + virtualNetwork: { + id: spoke1vnet.id + } + } +} + +resource dnsvnetlinkwebspoke2 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2020-06-01' = { + name: 'wth-dnsvnetlink-webspoke2' + parent: privateDnsZoneWeb + location: 'global' + properties: { + registrationEnabled: false + virtualNetwork: { + id: spoke2vnet.id + } + } +} + +resource inboundDNSSubnet 'Microsoft.Network/virtualNetworks/subnets@2022-07-01' = { + name: 'wth-subnet-inbounddns' + parent: hubvnet + properties: { + addressPrefix: '10.0.17.0/27' + delegations: [ + { + name: 'Microsoft.Network/dnsResolvers' + properties: { + serviceName: 'Microsoft.Network/dnsResolvers' + } + } + ] + } +} + +resource outboundDNSSubnet 'Microsoft.Network/virtualNetworks/subnets@2022-07-01' = { + name: 'wth-subnet-outbounddns' + dependsOn: [ + inboundDNSSubnet + ] + parent: hubvnet + properties: { + addressPrefix: '10.0.17.32/27' + delegations: [ + { + name: 'Microsoft.Network/dnsResolvers' + properties: { + serviceName: 'Microsoft.Network/dnsResolvers' + } + } + ] + } +} + +resource publicIP 'Microsoft.Network/publicIPAddresses@2022-07-01' = { + name: 'wth-pip-dnsresolver01' + location: location + sku: { + name: 'Standard' + } + properties: { + publicIPAllocationMethod: 'Static' + publicIPAddressVersion: 'IPv4' + } +} + +resource privateDNSResplver 'Microsoft.Network/dnsResolvers@2022-07-01' = { + name: 'wth-dnsresolver-hub01' + location: location + properties: { + virtualNetwork: { id: hubvnet.id - } + } + } + resource inboundEndpoint 'inboundEndpoints@2022-07-01' = { + name: 'wth-dnsresolver-inboundendpoint01' + location: location + properties: { + ipConfigurations: [ + { + //privateIpAddress: '10.0.17.4' + //privateIpAllocationMethod: 'Static' + subnet: { + id: inboundDNSSubnet.id + } + } + ] + } + } + resource outboundEndpoint 'outboundEndpoints@2022-07-01' = { + name: 'wth-dnsresolver-outboundendpoint01' + location: location + properties: { + subnet: { + id: outboundDNSSubnet.id + } + } } } diff --git a/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke1.bicep index 737195649d..79183ab4fb 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke1.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke1.bicep @@ -62,6 +62,26 @@ resource wthspoke1vnetpepsubnet 'Microsoft.Network/virtualNetworks/subnets@2022- } } +resource wthspoke1vnetappsvcsubnet 'Microsoft.Network/virtualNetworks/subnets@2022-01-01' = { + name: 'subnet-appsvc' + parent: wthspoke1vnet + dependsOn: [ + wthspoke1vnetpepsubnet + ] + properties: { + addressPrefix: '10.1.12.0/24' + privateEndpointNetworkPolicies: 'Enabled' + delegations: [ + { + name: 'delegation' + properties: { + serviceName: 'Microsoft.Web/serverFarms' + } + } + ] + } +} + resource nsg 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { name: 'wth-nsg-sqlpepsubnet' location: location @@ -160,12 +180,14 @@ resource webapp 'Microsoft.Web/sites@2022-03-01' = { ftpsState: 'FtpsOnly' appSettings: [ { - name: 'WEBSITES_ENABLE_APP_SERVICE_STORAGE' - value: 'false' + name: 'WEBSITES_ENABLE_APP_SERVICE_STORAGE' + value: 'false' } - ] + ] } httpsOnly: true + virtualNetworkSubnetId: wthspoke1vnetappsvcsubnet.id + publicNetworkAccess: 'Enabled' } identity: { type: 'SystemAssigned' @@ -177,7 +199,7 @@ resource privateEndpoint_webapp 'Microsoft.Network/privateEndpoints@2020-06-01' location: location properties: { subnet: { - id: resourceId('Microsoft.Network/virtualNetworks/subnets',wthspoke1vnet.name, wthspoke1vnetpepsubnet.name) + id: resourceId('Microsoft.Network/virtualNetworks/subnets', wthspoke1vnet.name, wthspoke1vnetpepsubnet.name) } privateLinkServiceConnections: [ { @@ -193,28 +215,13 @@ resource privateEndpoint_webapp 'Microsoft.Network/privateEndpoints@2020-06-01' } } -resource privateDnsZones 'Microsoft.Network/privateDnsZones@2018-09-01' = { +resource privateDnsZones 'Microsoft.Network/privateDnsZones@2018-09-01' existing = { name: 'privatelink.azurewebsites.net' - location: 'global' - dependsOn: [ - wthspoke1vnet - ] -} - -resource privateDnsZoneLink 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2018-09-01' = { - parent: privateDnsZones - name: '${privateDnsZones.name}-link' - location: 'global' - properties: { - registrationEnabled: false - virtualNetwork: { - id: wthspoke1vnet.id - } - } + scope: resourceGroup('wth-rg-hub') } resource privateDnsZoneGroup 'Microsoft.Network/privateEndpoints/privateDnsZoneGroups@2020-03-01' = { - parent: privateEndpoint + parent: privateEndpoint_webapp name: 'dnsgroupname' properties: { privateDnsZoneConfigs: [ diff --git a/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke2.bicep b/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke2.bicep index ae73843c9f..a66f8dbb45 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke2.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke2.bicep @@ -2,14 +2,6 @@ param location string = 'eastus2' param adminUserLogin string param adminUserSid string -resource rtspoke2vms 'Microsoft.Network/routeTables@2022-01-01' existing = { - name: 'wth-rt-spoke2vmssubnet' -} - -resource nsgspoke2vms 'Microsoft.Network/networkSecurityGroups@2022-01-01' existing = { - name: 'wth-nsg-spoke2vmssubnet' -} - resource sqlServer 'Microsoft.Sql/servers@2021-11-01' = { name: 'wthspoke2${uniqueString(subscription().id)}' location: location @@ -17,7 +9,7 @@ resource sqlServer 'Microsoft.Sql/servers@2021-11-01' = { administratorLogin: 'admin-wth' administratorLoginPassword: guid(subscription().id,'this_is_a_b0gus_and_disabled_password!') version: '12.0' - publicNetworkAccess: 'Disabled' + publicNetworkAccess: 'Enabled' administrators: { administratorType: 'ActiveDirectory' principalType: 'User' @@ -30,9 +22,12 @@ resource sqlServer 'Microsoft.Sql/servers@2021-11-01' = { resource sqlServerFirewall 'Microsoft.Sql/servers/virtualNetworkRules@2021-11-01' = { name: 'rule' + dependsOn: [ + withspoke2vnetvmsubnet + ] parent: sqlServer properties: { - virtualNetworkSubnetId: wthspoke1vnet.properties.subnets[0].id + virtualNetworkSubnetId: wthspoke2vnet.properties.subnets[0].id } } @@ -52,34 +47,21 @@ resource sqlDB 'Microsoft.Sql/servers/databases@2021-11-01' = { } } -resource wthspoke1vnet 'Microsoft.Network/virtualNetworks@2021-08-01' = { +resource wthspoke2vnet 'Microsoft.Network/virtualNetworks@2021-08-01' existing = { name: 'wth-vnet-spoke201' - location: location +} + +resource withspoke2vnetvmsubnet 'Microsoft.Network/virtualNetworks/subnets@2021-08-01' = { + name: 'subnet-spoke2vms' + parent: wthspoke2vnet properties: { - addressSpace: { - addressPrefixes: [ - '10.2.0.0/16' - ] - } - subnets: [ + addressPrefix: wthspoke2vnet.properties.subnets[0].properties.addressPrefix + networkSecurityGroup: wthspoke2vnet.properties.subnets[0].properties.networkSecurityGroup + routeTable: wthspoke2vnet.properties.subnets[0].properties.routeTable + serviceEndpoints: [ { - name: 'subnet-spoke1vms' - properties: { - addressPrefix: '10.2.10.0/24' - networkSecurityGroup: { - id: nsgspoke2vms.id - } - routeTable: { - id: rtspoke2vms.id - } - serviceEndpoints: [ - { - service: 'Microsoft.SQL' - } - ] - } + service: 'Microsoft.SQL' } ] } } - diff --git a/035-HubAndSpoke/Student/Resources/bicep/README.md b/035-HubAndSpoke/Student/Resources/bicep/README.md index 562c970a68..ae08697ffe 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/README.md +++ b/035-HubAndSpoke/Student/Resources/bicep/README.md @@ -69,10 +69,20 @@ Challenges are meant to be deployed sequentially, as the infrastructure builds o ### Challenge 4 -An Application Gateway is deployed matching the Challenge requirements. For the App GW to deploy, a TLS secret identifier from a Key Vault must be provided. The App GW's managed identity needs permissions to read the secret from the Key Vault. For convenience, a Key Vault is deployed and the App GW is granted necessary permissions; however, the TLS certificate needs to be uploaded to the Key Vault for the App GW to deploy successfully. +An Application Gateway is deployed matching the Challenge requirements. The deployment automates the configuration of a TLS certificate and DNS records when appropriate RFC 2136 credentials are supplied (the default configuration). The deployment options are: + +1. Automated: Have automation handle DNS records and TLS certificates for you -- this requires registering for a DNS name, for example, from https://dynv6.com. +1. Manually configured: If you have an existing domain name and TLS certificates, you can manually upload the PFX certificate file to the Key Vault prior to deploying the App GW. +1. Automated, with self-signed certificate: If there are issues generating the publicly trusted TLS certificate from Let's Encrypt, a self-signed certificate can be used. + +For details on these options and troubleshooting, see: [Application Gateway DNS and Certificates](./appGWCertificateProcess.md) + +The application gateway is configured with backend pools for the Spoke 1 and Spoke 2 VMs. ### Challenge 5 +The required Azure SQL and App Service resources are deployed, along with their supporting Private Link infrastructure. An Azure Private DNS Resolver is deployed to enable Private Endpoint name resolution for the 'on-prem' resources. + ## Resource Cleanup To cleanup this deployment, delete each create resource group. To do this programmatically with PowerShell, run: From 687ce559c00da86ebb12bf43edc61951f8d1d4dc Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Wed, 28 Dec 2022 12:53:27 -0700 Subject: [PATCH 59/76] wip: challenge 5 appsvc sql conn --- .../Student/Resources/bicep/04-02-hub.bicep | 1 - .../Student/Resources/bicep/05-01-spoke1.bicep | 16 ++++++++++++++++ .../Student/Resources/bicep/README.md | 2 ++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/04-02-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/04-02-hub.bicep index 79ee5ce76b..c93776b316 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/04-02-hub.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/04-02-hub.bicep @@ -49,7 +49,6 @@ param cookieBasedAffinity string = 'Disabled' @description('Location for all resources.') param location string = resourceGroup().location -var appGwPublicIpName = 'wth-pip-appgw01' var appGwSize = 'Standard_v2' resource hubvnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { diff --git a/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke1.bicep index 79183ab4fb..fa2c96e9a6 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke1.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke1.bicep @@ -103,6 +103,21 @@ resource nsgSecRuleAllow 'Microsoft.Network/networkSecurityGroups/securityRules@ } } +resource nsgSecRuleAllowAppSvc 'Microsoft.Network/networkSecurityGroups/securityRules@2022-01-01' = { + name: 'allow-sql-from-appsvcsubnet' + parent: nsg + properties: { + access: 'Deny' + direction: 'Inbound' + protocol: '*' + sourceAddressPrefix: '*' + destinationAddressPrefix: wthspoke1vnetappsvcsubnet.properties.addressPrefix + priority: 102 + sourcePortRange: '*' + destinationPortRange: '*' + } +} + resource nsgSecRuleDeny 'Microsoft.Network/networkSecurityGroups/securityRules@2022-01-01' = { name: 'deny-sql-from-any' parent: nsg @@ -234,3 +249,4 @@ resource privateDnsZoneGroup 'Microsoft.Network/privateEndpoints/privateDnsZoneG ] } } + diff --git a/035-HubAndSpoke/Student/Resources/bicep/README.md b/035-HubAndSpoke/Student/Resources/bicep/README.md index ae08697ffe..fda9086191 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/README.md +++ b/035-HubAndSpoke/Student/Resources/bicep/README.md @@ -83,6 +83,8 @@ The application gateway is configured with backend pools for the Spoke 1 and Spo The required Azure SQL and App Service resources are deployed, along with their supporting Private Link infrastructure. An Azure Private DNS Resolver is deployed to enable Private Endpoint name resolution for the 'on-prem' resources. +The 'Inspector Gadget' utility is installed on the Web App. It includes functions to verify DNS name resolution and test SQL connectivity, though you may want to take the additional step of [granting your App Service MSI access to the SQL database](https://learn.microsoft.com/azure/active-directory/managed-identities-azure-resources/tutorial-windows-vm-access-sql). + ## Resource Cleanup To cleanup this deployment, delete each create resource group. To do this programmatically with PowerShell, run: From ae4e35e18ead77873b868166046975ddc9bf04eb Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Wed, 28 Dec 2022 13:09:00 -0700 Subject: [PATCH 60/76] challenge 5 completed --- .../Student/Resources/bicep/README.md | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/README.md b/035-HubAndSpoke/Student/Resources/bicep/README.md index fda9086191..4061474a68 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/README.md +++ b/035-HubAndSpoke/Student/Resources/bicep/README.md @@ -14,7 +14,7 @@ The WTH philosophy intends to have students learn by doing, and recognizes that Using Cloud Shell is recommended, as it already has the necessary tools installed. However, Cloud Shell has a timeout of about 20 minutes and may experience timeouts (in which case, run the same command again to pick up the deployments where they stopped). -Challenges are meant to be deployed sequentially, as the infrastructure builds on itself. For example, to work with the Challenge 5 infrastructure, deploy Challenges 1-4 first. +**Challenges are meant to be deployed sequentially, as the infrastructure builds on itself.** For example, to work with the Challenge 5 infrastructure, deploy Challenges 1-4 first. ### Prerequisites @@ -81,9 +81,19 @@ The application gateway is configured with backend pools for the Spoke 1 and Spo ### Challenge 5 -The required Azure SQL and App Service resources are deployed, along with their supporting Private Link infrastructure. An Azure Private DNS Resolver is deployed to enable Private Endpoint name resolution for the 'on-prem' resources. +The required Azure SQL and App Service resources are deployed, along with their supporting Private Link infrastructure. An Azure Private DNS Resolver is deployed to enable Private Endpoint name resolution for the 'on-prem' resources. -The 'Inspector Gadget' utility is installed on the Web App. It includes functions to verify DNS name resolution and test SQL connectivity, though you may want to take the additional step of [granting your App Service MSI access to the SQL database](https://learn.microsoft.com/azure/active-directory/managed-identities-azure-resources/tutorial-windows-vm-access-sql). +The 'Inspector Gadget' utility is installed on the Web App, which is publicly accessible. It includes functions to verify DNS name resolution and test SQL connectivity, though you may want to take the additional step of [granting your App Service MSI access to the SQL database](https://learn.microsoft.com/azure/active-directory/managed-identities-azure-resources/tutorial-windows-vm-access-sql). + +Resources deployed: + +- Azure SQL Servers and DBs in Spoke 1 and Spoke 1 +- Web App in Spoke 1 +- Private DNS Resolver in Hub +- Private Endpoints for SQL servers and App Service +- Private DNS Zones for Private Endpoint records +- Subnets for new services (App Service, DNS Resolver, SQL Private Endpoints) +- NSGs for new subnets ## Resource Cleanup From 3cb6c729890959a174f801f2216b160f936375de Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Thu, 29 Dec 2022 09:14:23 -0700 Subject: [PATCH 61/76] challenge 5 bonus --- .../Resources/bicep/02-01-fwpolicyrules.bicep | 25 ++++++++-- .../Student/Resources/bicep/05-01-hub.bicep | 2 +- .../Resources/bicep/05-01-spoke1.bicep | 50 +++++++++++++++++-- 3 files changed, 68 insertions(+), 9 deletions(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-01-fwpolicyrules.bicep b/035-HubAndSpoke/Student/Resources/bicep/02-01-fwpolicyrules.bicep index e5c38d0672..d1e311e646 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/02-01-fwpolicyrules.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/02-01-fwpolicyrules.bicep @@ -177,7 +177,7 @@ resource wthafwrcgnet 'Microsoft.Network/firewallPolicies/ruleCollectionGroups@2 type: 'Allow' } name: 'allow-network-rules' - priority:200 + priority: 200 rules: [ { ruleType: 'NetworkRule' @@ -203,7 +203,7 @@ resource wthafwrcgnet 'Microsoft.Network/firewallPolicies/ruleCollectionGroups@2 dependsOn: [ wthafwrcgdnat ] -} +} resource wthafwrcgapp 'Microsoft.Network/firewallPolicies/ruleCollectionGroups@2022-01-01' = { name: '${wthafwpolicy.name}/WTH_AppRulesCollectionGroup' @@ -217,7 +217,25 @@ resource wthafwrcgapp 'Microsoft.Network/firewallPolicies/ruleCollectionGroups@2 } priority: 300 name: 'allow-apprules' - rules: [] + rules: [ + { + ruleType: 'ApplicationRule' + name: 'allow-appsvcsubnet-to-azsql' + description: 'Allow App Service subnet (created in Challenge 5) to Azure SQL' + sourceAddresses: [ + '10.1.11.0/24' + ] + protocols: [ + { + protocolType: 'mssql' + port: 1433 + } + ] + targetFqdns: [ + '*.${environment().suffixes.sqlServerHostname}' + ] + } + ] } ] } @@ -225,4 +243,3 @@ resource wthafwrcgapp 'Microsoft.Network/firewallPolicies/ruleCollectionGroups@2 wthafwrcgnet ] } - diff --git a/035-HubAndSpoke/Student/Resources/bicep/05-01-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/05-01-hub.bicep index 71d94a92f4..1d216cffe1 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/05-01-hub.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/05-01-hub.bicep @@ -15,7 +15,7 @@ resource spoke2vnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { } resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { - name: 'privatelink.database.windows.net' + name: 'privatelink.${environment().suffixes.sqlServerHostname}' location: 'global' properties: { } diff --git a/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke1.bicep index fa2c96e9a6..5ebe6ec5b1 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke1.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke1.bicep @@ -3,7 +3,12 @@ param adminUserLogin string param adminUserSid string resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' existing = { - name: 'privatelink.database.windows.net' + name: 'privatelink.${environment().suffixes.sqlServerHostname}' + scope: resourceGroup('wth-rg-hub') +} + +resource afw 'Microsoft.Network/azureFirewalls@2022-07-01' existing = { + name: 'wth-afw-hub01' scope: resourceGroup('wth-rg-hub') } @@ -15,6 +20,7 @@ resource sqlServer 'Microsoft.Sql/servers@2021-11-01' = { administratorLoginPassword: guid(subscription().id, 'this_is_a_b0gus_and_disabled_password!') version: '12.0' publicNetworkAccess: 'Disabled' + minimalTlsVersion: '1.2' administrators: { administratorType: 'ActiveDirectory' principalType: 'User' @@ -23,6 +29,12 @@ resource sqlServer 'Microsoft.Sql/servers@2021-11-01' = { tenantId: tenant().tenantId } } + resource connectionPolicy 'connectionPolicies@2021-11-01' = { + name: 'default' + properties: { + connectionType: 'Proxy' + } + } } resource sqlDB 'Microsoft.Sql/servers/databases@2021-11-01' = { @@ -71,6 +83,9 @@ resource wthspoke1vnetappsvcsubnet 'Microsoft.Network/virtualNetworks/subnets@20 properties: { addressPrefix: '10.1.12.0/24' privateEndpointNetworkPolicies: 'Enabled' + routeTable: { + id: routeTable.id + } delegations: [ { name: 'delegation' @@ -107,14 +122,14 @@ resource nsgSecRuleAllowAppSvc 'Microsoft.Network/networkSecurityGroups/security name: 'allow-sql-from-appsvcsubnet' parent: nsg properties: { - access: 'Deny' + access: 'Allow' direction: 'Inbound' protocol: '*' - sourceAddressPrefix: '*' + sourceAddressPrefix: 'VirtualNetwork' destinationAddressPrefix: wthspoke1vnetappsvcsubnet.properties.addressPrefix priority: 102 sourcePortRange: '*' - destinationPortRange: '*' + destinationPortRange: '1433' } } @@ -202,6 +217,7 @@ resource webapp 'Microsoft.Web/sites@2022-03-01' = { } httpsOnly: true virtualNetworkSubnetId: wthspoke1vnetappsvcsubnet.id + vnetRouteAllEnabled: true publicNetworkAccess: 'Enabled' } identity: { @@ -250,3 +266,29 @@ resource privateDnsZoneGroup 'Microsoft.Network/privateEndpoints/privateDnsZoneG } } +resource routeTable 'Microsoft.Network/routeTables@2022-07-01' = { + name: 'wth-rt-sqlthroughafw' + location: location + properties: { + disableBgpRoutePropagation: false + routes: [ + { + name: 'route-sqlthroughafw' + properties: { + addressPrefix: wthspoke1vnetpepsubnet.properties.addressPrefix + nextHopType: 'VirtualAppliance' + nextHopIpAddress: reference(afw.id, '2022-01-01').ipConfigurations[0].properties.privateIPAddress + } + } + ] + } +} + +resource route 'Microsoft.Network/routeTables/routes@2022-07-01' = { + name: 'wth-rt-spoke1vmssubnet/route-sqlthroughafw' + properties: { + addressPrefix: wthspoke1vnetpepsubnet.properties.addressPrefix + nextHopType: 'VirtualAppliance' + nextHopIpAddress: reference(afw.id, '2022-01-01').ipConfigurations[0].properties.privateIPAddress + } +} From e0d2b51b5ca466864e99b83b2975b632fdf2ff11 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Thu, 29 Dec 2022 12:49:17 -0700 Subject: [PATCH 62/76] challenge 5 fix nsg --- .../Resources/bicep/02-01-fwpolicyrules.bicep | 20 +------------- .../Student/Resources/bicep/05-01-hub.bicep | 2 +- .../Resources/bicep/05-01-spoke1.bicep | 26 ++++++++++++++----- 3 files changed, 21 insertions(+), 27 deletions(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-01-fwpolicyrules.bicep b/035-HubAndSpoke/Student/Resources/bicep/02-01-fwpolicyrules.bicep index d1e311e646..b4b1a7cb6f 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/02-01-fwpolicyrules.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/02-01-fwpolicyrules.bicep @@ -217,25 +217,7 @@ resource wthafwrcgapp 'Microsoft.Network/firewallPolicies/ruleCollectionGroups@2 } priority: 300 name: 'allow-apprules' - rules: [ - { - ruleType: 'ApplicationRule' - name: 'allow-appsvcsubnet-to-azsql' - description: 'Allow App Service subnet (created in Challenge 5) to Azure SQL' - sourceAddresses: [ - '10.1.11.0/24' - ] - protocols: [ - { - protocolType: 'mssql' - port: 1433 - } - ] - targetFqdns: [ - '*.${environment().suffixes.sqlServerHostname}' - ] - } - ] + rules: [] } ] } diff --git a/035-HubAndSpoke/Student/Resources/bicep/05-01-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/05-01-hub.bicep index 1d216cffe1..7fa6ea4d74 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/05-01-hub.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/05-01-hub.bicep @@ -15,7 +15,7 @@ resource spoke2vnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { } resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' = { - name: 'privatelink.${environment().suffixes.sqlServerHostname}' + name: 'privatelink${environment().suffixes.sqlServerHostname}' location: 'global' properties: { } diff --git a/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke1.bicep b/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke1.bicep index 5ebe6ec5b1..4488187e68 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke1.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke1.bicep @@ -3,7 +3,7 @@ param adminUserLogin string param adminUserSid string resource privateDNSZone 'Microsoft.Network/privateDnsZones@2020-06-01' existing = { - name: 'privatelink.${environment().suffixes.sqlServerHostname}' + name: 'privatelink${environment().suffixes.sqlServerHostname}' scope: resourceGroup('wth-rg-hub') } @@ -104,17 +104,20 @@ resource nsg 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { } resource nsgSecRuleAllow 'Microsoft.Network/networkSecurityGroups/securityRules@2022-01-01' = { - name: 'allow-sql-from-onprem' + name: 'allow-sql-from-onpremandspoke1' parent: nsg properties: { access: 'Allow' direction: 'Inbound' protocol: '*' - sourceAddressPrefixes: wthonpremvnet.properties.addressSpace.addressPrefixes + sourceAddressPrefixes: [ + wthonpremvnet.properties.addressSpace.addressPrefixes[0] + wthspoke1vnet.properties.addressSpace.addressPrefixes[0] + ] destinationAddressPrefix: wthspoke1vnetpepsubnet.properties.addressPrefix priority: 100 sourcePortRange: '*' - destinationPortRange: '*' + destinationPortRange: '1433' } } @@ -125,8 +128,8 @@ resource nsgSecRuleAllowAppSvc 'Microsoft.Network/networkSecurityGroups/security access: 'Allow' direction: 'Inbound' protocol: '*' - sourceAddressPrefix: 'VirtualNetwork' - destinationAddressPrefix: wthspoke1vnetappsvcsubnet.properties.addressPrefix + sourceAddressPrefix: wthspoke1vnetappsvcsubnet.properties.addressPrefix + destinationAddressPrefix: wthspoke1vnetpepsubnet.properties.addressPrefix priority: 102 sourcePortRange: '*' destinationPortRange: '1433' @@ -142,7 +145,7 @@ resource nsgSecRuleDeny 'Microsoft.Network/networkSecurityGroups/securityRules@2 protocol: '*' sourceAddressPrefix: '*' destinationAddressPrefix: wthspoke1vnetpepsubnet.properties.addressPrefix - priority: 101 + priority: 1000 sourcePortRange: '*' destinationPortRange: '*' } @@ -213,6 +216,15 @@ resource webapp 'Microsoft.Web/sites@2022-03-01' = { name: 'WEBSITES_ENABLE_APP_SERVICE_STORAGE' value: 'false' } + // Inspector Gadget settings for SQL connection - App Svc MSI must still be manually granted SQL access + { + name: 'DefaultSqlConnectionSqlConnectionString' + value: replace('Server=${environment().suffixes.sqlServerHostname},1433;Initial Catalog=sampleDB;Persist Security Info=False;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;', '', sqlServer.name) + } + { + name: 'DefaultSqlConnectionUseAzureManagedIdentity' + value: 'true' + } ] } httpsOnly: true From 75d554632947893bf55a94dbf639652daa7dd894 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Thu, 29 Dec 2022 12:57:16 -0700 Subject: [PATCH 63/76] readme updates --- 035-HubAndSpoke/Student/Resources/bicep/README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/035-HubAndSpoke/Student/Resources/bicep/README.md b/035-HubAndSpoke/Student/Resources/bicep/README.md index 4061474a68..5bf338663e 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/README.md +++ b/035-HubAndSpoke/Student/Resources/bicep/README.md @@ -4,7 +4,7 @@ This directory contains Bicep templates to deploy and configure resources as des ## Who should use these templates? -The WTH philosophy intends to have students learn by doing, and recognizes that one of the best ways to learn is to troubleshoot problems. As such, using these templates instead of building your own lab will detract from your learning experience, and only recommended for the scenarios below: +The WTH philosophy intends to have students learn by doing, and recognizes that one of the best ways to learn is to troubleshoot problems. As such, using these templates instead of building your own lab will detract from your learning experience, and primarily recommended for the scenarios below: - Students who will not be completing a challenge which is a prerequisite to a later challenge - Students who are falling behind in the WTH due to issues unrelated to the core learning goals of this WTH @@ -14,7 +14,7 @@ The WTH philosophy intends to have students learn by doing, and recognizes that Using Cloud Shell is recommended, as it already has the necessary tools installed. However, Cloud Shell has a timeout of about 20 minutes and may experience timeouts (in which case, run the same command again to pick up the deployments where they stopped). -**Challenges are meant to be deployed sequentially, as the infrastructure builds on itself.** For example, to work with the Challenge 5 infrastructure, deploy Challenges 1-4 first. +**Challenges are meant to be deployed sequentially, as the infrastructure builds on itself.** For example, to work with the Challenge 5 infrastructure, deploy Challenges 1-4 first. Also, keep in mind that changes made for testing need to be manually reverted, unless the relevant Challenge and subsequent Challenges are redeployed. ### Prerequisites @@ -94,6 +94,7 @@ Resources deployed: - Private DNS Zones for Private Endpoint records - Subnets for new services (App Service, DNS Resolver, SQL Private Endpoints) - NSGs for new subnets +- Route table and routes to force Spoke 1 SQL traffic through the Azure Firewall (advanced scenario) ## Resource Cleanup @@ -101,10 +102,10 @@ To cleanup this deployment, delete each create resource group. To do this progra ```powershell $jobs = @() - $jobs += Remove-AzResourceGroup -Name 'wth-rg-hub' -AsJob - $jobs += Remove-AzResourceGroup -Name 'wth-rg-spoke1' -AsJob - $jobs += Remove-AzResourceGroup -Name 'wth-rg-spoke2' -AsJob - $jobs += Remove-AzResourceGroup -Name 'wth-rg-onprem' -AsJob + $jobs += Remove-AzResourceGroup -Name 'wth-rg-hub' -Force -AsJob + $jobs += Remove-AzResourceGroup -Name 'wth-rg-spoke1' -Force -AsJob + $jobs += Remove-AzResourceGroup -Name 'wth-rg-spoke2' -Force -AsJob + $jobs += Remove-AzResourceGroup -Name 'wth-rg-onprem' -Force -AsJob Write-Host "Waiting for all resource group cleanup jobs to complete..." $jobs | Wait-Job From 44c68651a04180766ec6c729dd5c1ea743b429ce Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Fri, 30 Dec 2022 08:28:19 -0700 Subject: [PATCH 64/76] challenge 5 docs and images --- .../Resources/bicep/appGWCertificateProcess.md | 14 ++++++++++---- .../bicep/media/challenge-4-dynv6apikey.png | Bin 0 -> 42926 bytes ...6signup.png => challenge-4-dynv6signup.png} | Bin .../bicep/media/challenge-4-dynv6tsig.png | Bin 0 -> 166397 bytes .../bicep/media/challenge-4-dynv6tsigkey.png | Bin 0 -> 103588 bytes .../bicep/media/challenge-4-example.png | Bin 0 -> 77904 bytes 6 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 035-HubAndSpoke/Student/Resources/bicep/media/challenge-4-dynv6apikey.png rename 035-HubAndSpoke/Student/Resources/bicep/media/{dynv6signup.png => challenge-4-dynv6signup.png} (100%) create mode 100644 035-HubAndSpoke/Student/Resources/bicep/media/challenge-4-dynv6tsig.png create mode 100644 035-HubAndSpoke/Student/Resources/bicep/media/challenge-4-dynv6tsigkey.png create mode 100644 035-HubAndSpoke/Student/Resources/bicep/media/challenge-4-example.png diff --git a/035-HubAndSpoke/Student/Resources/bicep/appGWCertificateProcess.md b/035-HubAndSpoke/Student/Resources/bicep/appGWCertificateProcess.md index 5f1dda06a6..644b6c1c2f 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/appGWCertificateProcess.md +++ b/035-HubAndSpoke/Student/Resources/bicep/appGWCertificateProcess.md @@ -9,28 +9,34 @@ The default process uses Let's Encrypt to generate a publicly trusted certificat These instructions will use https://dynv6.com to register a free domain name you can use for this lab. Other free DNS providers are likely also compatible, as long as they support updates following the RFC2136 standard (which the lab automation has been written to use); however, you will need to pass a different value for the rfc2136DNSNameserver parameter on the '04-01-hub.bicep' template. 1. Navigate to https://dynv6.com and register a new unique domain name--for example: `wthdom.dynv6.net` + ![DynV6 Name Registration](./media/challenge-4-dynv6signup.png) 1. Complete your registration by confirming your email address 1. After logging in, create a new TSIG Key: 1. Click your email address at the top right corner of the screen and select the **Keys** link + ![DynV6 API Keys Menu](./media/challenge-4-dynv6apikey.png) 1. Click the **Add TSIG Key** button + ![DynV6 New TSIG Key](./media/challenge-4-dynv6tsig.png) 1. In the "Add a new TSIG Key" screen, select Algorithm: **hmac-sha256** 1. Click **Generate TSIG Key** 1. Click the **Details** button on the new key, then copy the following values to your notes: TSIG Key Name (starts with 'tsig-') TSIG Algorithm (should be 'hmac-sha256') TSIG Secret (long string, usually ending in '==') + ![DynV6 TSIG Key Values](./media/challenge-4-dynv6tsigkey.png) ## Provide DNS Details During Deployment When running the deploy.ps1 script to deploy Challenge 4, you will be prompted for the above parameter values, which you can paste into the terminal. +![Providing DNS RFC 2136 Details During Deployment](./media/challenge-4-example.png) + ## Troubleshooting Automating generating a certificate for Application Gateway has three main components to consider: -- Certificate issuance: This step requests a certificate from Let's Encrypt using the 'acme-go/lego' container image. The Bicep deployment creates a Container Group/Instance with this image, and requests a certificate. In order to validate that you own the domain name you are requesting a certificate for, Let's Encrypt will complete a 'dns' challenge, where it authenticates to your DNS provider (DynV6, for example). After confirming you have valid credentials for the domain name, a certificate is issued and stored in an Azure Storage Account. -- Certificate upload to Key Vault: This step uses a Deployment Script resource to execute an Azure PowerShell script that uploads the above certificate from the Storage Account to an Azure Key Vault. This is necessary because the Application Gateway will access the certificate from the Key Vault. -- DNS record update: Lastly, the domain name used for the certificate needs to point to the Application Gateway's Public IP Address, so that when you nagivate to that domain, App Gateway responds to the request and forwards it to your backend pool servers. +- **Certificate issuance:** This step requests a certificate from Let's Encrypt using the 'acme-go/lego' container image. The Bicep deployment creates a Container Group/Instance with this image, and requests a certificate. In order to validate that you own the domain name you are requesting a certificate for, Let's Encrypt will complete a 'dns' challenge, where it authenticates to your DNS provider (DynV6, for example). After confirming you have valid credentials for the domain name, a certificate is issued and stored in an Azure Storage Account. +- **Certificate upload to Key Vault:** This step uses a Deployment Script resource to execute an Azure PowerShell script that uploads the above certificate from the Storage Account to an Azure Key Vault. This is necessary because the Application Gateway will access the certificate from the Key Vault. +- **DNS record update:** Lastly, the domain name used for the certificate needs to point to the Application Gateway's Public IP Address, so that when you nagivate to that domain, App Gateway responds to the request and forwards it to your backend pool servers. Each of the above steps use Azure Container Instances to perform the required automation. The container will typically output logs, viewable in the Portal by navigating to the Container Group resource or Deployment Script resource. In addition to logs, the Container Groups are set to output diagnostic information to the lab Log Analytics Workspace, which may be helpful. @@ -46,7 +52,7 @@ If you do this, you will need to perform the following steps yourself: - Create a certificate for your domain name (wildcard certificates can work) - Upload a certificate PFX to the KeyVault created in the 'wth-rg-hub' resource group -- Create or update a DNS 'A' record with your DNS provider (ie: GoDaddy, Azure DNS, etc.) that points to the Application Gateway's Public IP Address +- Create or update a DNS 'A' record with your DNS provider (ie: GoDaddy, Azure DNS, etc.) that points to the Application Gateway's Public IP Address or a 'CNAME' record pointing to the Application Gateway's DNS name - Ensure that the Application Gateway identity has permission to access the uploaded certificate's secret - Pass the certificate secret ID (and version number) as a -challengeParameters, as shown above diff --git a/035-HubAndSpoke/Student/Resources/bicep/media/challenge-4-dynv6apikey.png b/035-HubAndSpoke/Student/Resources/bicep/media/challenge-4-dynv6apikey.png new file mode 100644 index 0000000000000000000000000000000000000000..90d5ac5eef9139fc7507eb29ffa9be1700e32d7c GIT binary patch literal 42926 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

1+g{&nG`bqyM+N68{6DeU1Zyy3zWK(U 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ℑ|uFsM%K zy_thT#T~{;kI12CjWx%XqdR1b%>mY$Wcf~{u3^hIQQSzUULW09irzBjYrcl2U^dCt zAh=Lrj*Qwgv#7(`cjh3VsyoQ&u%u*wbUX1^s(Rvj40nmT_R{K~z?D;X!lV!@p|D4d zdoe*;@G_>+-IGU=aw0lbbaEN)u{XKlx>U@1P1g%EeE4_KLB^6@M>fiy(E|S9by+MW zE|b=zjGLX}QFD|;^rUXF@LigT?*FS}WuDKgm6r=f4lD*4(FclhQtfx?T);-D?H&Gi zp83}Lwctl5sV5Dmr<_e(re>CDC*1RI_v|OzgF~L{Bs`vsHhL}c-Lgu`L^$!d3?~rI zlZM?XwL|1kTf+yL^aXv&)6{oeo=d`OdwbLV`0!CJM-q>YL%A80Hdf9H5ARu?uiyxe%5TxWgPz-0AfvkB}rSNtXQq+F@$g?`^5eyQ}Y^4c6$7 zTpTk_y#eW)d=duH9t)z*KF&@r?3m@7-97f6_!#yD3?$rjmmKb}n4c^^PvWX63>j5G zg{+0mj11`9CBY*Z(0Y`CIm_RW}~Cy={SmB7GW)fp5SjE-sc98VdsFB84S8_|N)j&WzSs#p7Kd+KIfvH?q8+jRljDikyB ze}IpT-Ez5>mplCUlMG?GyFFkqrz6Gw;yBgWHQgqEJ3X$(Pr0<-Nf?XQ3~vDYSuK5^ zi$?{J+bX74?y5;EE4MyBU1oZ>_~VlVFXfoAaKLNW|65bzWWD;Mx7{MefoNMo$8#TF z({@%hCs6>7*0BzSwmIz-4ljduGmcDp8mkR#ufIXwYVFL^Ae{f&b&iGKX<`IBS( z&$?e957S9?>EMwybsj#QW@@c5 zOf|uT1t;T|46|DScpy+(vP*K(+$4GR^0xJpDn@Yo2|>XOF?KY1i%o zDP86Y@!iadFAS{h5b<2gkhA!3C;DX^wq>lodJC;VW02TdSbz=jF z3}Q)D%>>hQ16`$I)-K!o#9p|MkHA1uUoCTdjAdch;gbWZ$N|*>BuRr6c5{aJ|#F=IC88@3|0K{*=8^N4?d zV2@peS3sG*ds3|SDl=pcte1vPvy)QySUnC<6ok$qSXW}f-=>w}sX7VtQ1Xz~V8L>P z7oTyBT~Gvu^lU%59jpTR1ogWekr7BMLk4Gu-=y0qrkJD+%`y4*9_1BU`s+P3@QD=PfYZa)8%PG(5@z0c{l%4rk2FB*%xj9A74EvD-{u!!e zps@pq#SShGn74HGE%d~xFzcE7ms?y^BDQdroZ6%^Nen_jydYD2H$fUmn1 z;0AYr`(J{C!h+!?VuHG1mZbjG@^qx~sTq1GA}MT_hf^Ggc4$h5@9ERC#`o^gW#F@E zrOY^#NI26AP=~ycL^y{#^k`T6ar3EVWErjGE-7;BJh7pp#8r&&{WT?zK7VI`itOJa zFglA=xP+aT;0h-tnGLx3&Qq27{sZP@Mo0F5J>JGQ3oKpRjj<4RdFE){sfHa80giC} zD2lIg`J&Y2TIb90UhZAj zsB2`?Q#HKKNszh)Sq77E#b?1e$Y6#<@QJ6U90=vVAC`eB8sv$<7sh%~f9$2~%z=Wq zJt^q+*B!)2xI8LkcAVM0IZl~U+yG5CCw@uxZ_W-Z1K(t~B90egPx<-RyO}|A{^+BL zE~uN)M?C%ZHb-boQa+^FnqJ8XvaFZCElyhWw>54>1lh~)wlR@B3cb-)4;CxZJifcM zd~1`DTHaeGfl!3-dwq8IB+|oLH$a5oES;r=W3}Ycim$k<3+;{Mko8e+l407QTmIet zUq)Lb;orGx_ull|RT-?$TKRtTaOjRs-7p&4=rjjN0kcWz{o!w^-@|v*06Ur4U7gC} zROYF^=tx+{?zx5qK|*rKdcocJ#mr3-2UH_PKikHN%aqv7DiZxCrv;_d2%NA5u8Sr5 znv*`XUPbZsYkDhmoe06}hfPC;OFj zes>J6OUNj4@tZ=DOOl;evhjEQB)$2W$(nahHc;!}B>(kET%xyl$9;uj@Sh zM98`fGCVL|VS_in3N&dTFiecnBFhbU3AbZ*WVLms9WULWAE0QZS}|*>WrSTEl|CRW zHD3B{PdD+FoccjhN3cPNStDLscCa|}RnpMNlkic?B9)f(s z{cN$vkn~(4Fw1tEh^~o8a*yv-Q^QA!h^=iwFuihPQV%MLbiFE2QQOCt9&EHet7ho4 zats>sda1ay}4<8{L{>8f>bV#Q+aH2SrN_Y1VcUPsP%(>s<%P4mqi z!p%QmM=R4PeEm@Q7xy(kx9cqZuu~Bj{q?(J*1!ux0UI78vR*(fL>K80OlWbRCxI3R zX3df_t#1VP_^yI|Yi%+i34vrE{{hzcj}V@J*_5Z||CEPoT)%>T780+D#HAX5EYjSa z`g@gNM>Ks5g#o_B-JA4Lem-Nd3U_3A&pD(@sEqN*CNFH}jjk0sse7@P9DG24qIb%p z&jnX#T~j&lYC(`;74eb_T&n1x5mLAX9Zhn7N9v;0^nE{Jg$vPYuq1V~(IAQTkawv@ z{<}k`%bzjvVy9nwqjpx_gTJV%c={SvsU;n%syW-)4?&MAWQ0~wGfn)r%|r|1Et~tF zA*Jtt9#i9sq^t?K@wSBE8yjUuSTnyriTF(IU^3*J+-s?wVfe5~SmBZHGrJDVCh!28 z8a0ZQ_$**)tngqyuGjBL}J-J+*i2&g23UIxHntv`dHe}}&K5*?d zleSk*9LL_B4ZD}Bu1}{E2-oS+vN)rq3&dFOV6=%^iwMnj`0!)!bn6ALNQx}kv~tY|<`c|*4yLMZ`oB66->65=6!uQtX$`$>*ultY zld;{s*~e;uTQ`jy=3T$pmmwA$Vo}!3=UMA6un>x`{l@&uAJ*IHHfb7QCm{_(lqAwK!fl;4uQj*oWU5Ew2pK}uKMX%3SrdqQZbY=qO)jB(N* zA%R(+5KKRqR*yWne0X5nq+{~3P4{)t(6EXBSPq4MvK*hh1nyldj<*Q28xW}CwN|Jz z=v(Y9Evk7PHlH;vdn{z*0YKcfKu3oW){CK5(O{X>Zv1unxc4AeNu%Po!ZX2;Eus_$ z%PZzJD>N4F&t@eQspj;zmC4VNZ{5*dkp{2|eLdR^!(=y=nPi@!^BDon3JuE*Ifi4^ zrsx(vE6?ke98v0F;sF=z~Fu2Ri+KR3`ra2oEBA}~fS0Zys`gdUM|>1y^H zMRvPZ!T{#R0be>3Io?RS0QeqZKKY7D z$T<GKxE;2jAFE=hDRO4Wu@6EzccN$PeVF3kV1nGK*A78}TF;pJK`PJ3Cc<}2( zv{6~sAMyDhtjHMoxZbhv?7G#0vHfAtGO$L|E`1w0U$>k(5?G~Qg|V^l`got(BrT% zLknSX4IAi;fJ!@U1xX2FQDxUz{@p9p74gc4Jk%36?o3p3}D593u7+C zdpIp@Cv364mg3F{g2jih!9PaLW5*!s*xKKg5ej#cqBVo`nDsz(Jx(Xl7 zp!(>tI0&hqLfDO>^7ObV55JsjKyoVk=7QnOQ-JU(x7GoxFUPYK2GH%#;$uLv8|6tM z)2{f@yQy14l&F6o0HpHOnJ;KAm| zvw8%fh8Ygw$jxxVH?AbBWh+DQTGl!BS<-`u*E+f_@SuL6;Fb%tT@Vb#>yP_k)Yf&E^S*vW3!p6}B5AMQb6^?w9uFOLKp z#XWrUGLT-!;ohDW_z#j-IzMb2}%dn@u3ux1Dx@nz)0fEA7Z6~iOs)bRWm5*)_v9mJyYW9<`iYC29X2YAiE9*Mq6ZwH=k$Nc@8*p{8 z<*hAz?oJG=VBxIG*jkCJX3*FcK4NH?`weSF>$hS#e{Susf7{w80yg);B24ez$}4=+4mv-8TSHc|hbRL6jWOvSsi>9gfc|i}H%}TSMbypfb$lY;*HVshG z(n2}dYcAv6`AR1Tc$K<~QrxQxJ%r%HeCY{e2V5pw56tjl5Y(`3YUjUl=>AK9jCWg8a&gcspS89Z4cK@~kQsRFj z2ynP1QBxbK=g$erDVIQQN~^WDpAa3D=--^MO_$LrPFBA?k2?Izb)^aO{NID(ZC!=i zubDZfPjBcThl2}DU5Y63$W}4|N zUJ$y=o{Ch8Da(NFbmMs}8cE|aGpDhGX~-^1Q-g5t0%K*K2%XC~pj3HbW;RnY zQ%GsrKK*TtU;5Ey$Ml!^XlF1?{aiK7rWJ_c+wy-gv&=PKUPw3TiJ({>aVh5|P9X97a9;eCL;{J4N{!Cj#XA zD=lP8(|PHBt+m;*l*J`l$LrX(Pu+>;r(OOMI$U_>0&UW zoktDSoLxAMn$hQk3`W0{(rzv^QrMJf=3Uz|;&3jgxb+V*)XBWSyT+KXKf-{b*HGhZ z4%bt8i;h6@h<|TvQ$!`S=`CMobP%Tn@GY;Kw`-`1IUzUbk&!s$6ea|S(`l6=I&9eh z^O$T24&O^07!!*P_*Km^D&PF=L!u^9ym=i-eL00SY6-ozXWv`_yO13cPes&m(rxkX z8*L09%?W!vd;OszkP4sfA?;cwdK)s&d zy|ql@UOD=mdm(()Rce_vcNAESvOyjy3ecr2oh(io+WKxGl>@(>UCHqG!;ET=?w`0&PRp2>g3!W?1!_mJ*|*&S*?W=em-v zcH6;PR_CXW3rZ2bK?2t@ zi?xVIf`F0kgXdnWYojRK>)E^#QW!0r$L4exEj*F6VbFe^T(qCtG2D@~l#t8lxO z8y6I^EFP3j&6V|Mg>R(#f`XxQ0&W`*D7Q{g7R!p5%J2ORIT)_p*a*QhYWkeEMVs8n zsow^LD#SmHE$VuvxX8T|dC&n19kq`)7xWI~d4(ITXr5z|2LEuM?@4mC`h znz>4rtNHhxNwV@bnkl6Km@%HG@C9)|v;PZVTf*r#llo!uq;W-b1xAw56uYB&2 zZzy)>ZEUPSh${OW8c@}W2)m&`;24R$oM@p-fPdf+vZn17SyMfZXVt$f4P8?67t;2gPjL68MCXJX z&{qSQO_g8Dge4?aV!IzWd-k>+-Rj`Cx+Zl z7qggZu?Kc0f^>e@o|FJy70zWXI&ryMPCUJ~P3!Xy_hG>-$B#KAY}d^_-s+{`#mk@c zgRzJF*sjCUbqv8d7OiELypkr$KI~Vq4)*s$b1BJ=ML$*W9CSZFrXRfyF7xxhZd?U^ zn&K{M()W=fA6XMmvWEpq=*= zye5LUfo^vUVT%IRV6j9kzZ%=BOT`^Di~i{H@&mBx^Fjq?wxEMGdF2IH(CtV1YkJS0 zC{5KutRzw^*%<~2)^1>rNt=t3kgE6Cu`2bsoenA2vEuoOtz+&;?dp8h{rj9YJXpM$3YJsls+p6`zfwjB;uls_4=4cJ^9p%|kAu%o9rD*i z%;DS@hKxePViMdA4)?MfL3N9y=wc5nrsrlMSkGC|-O?U-I)RkzCKZ;>3eG%!G^`ie z6w+v`$>Cf%kn~(s-57V6OB_B)@TMA45j7XqKyXBVuvaG^MIk1vL4<&048gN|VA1Mr zOe^FG4uJP)ZXvAqRu2KzwR2(N_2$A`bILe`LfPJBK!`RQrtV_M53~$#ZMrkbe^}R! zgV&qu%&OLM6+H0h0ens>f$jw4u&<(l zv5^w95J%RgAg+3?d$nieq5&PkArUmUd%R?=b_5!Vu-#IrNXUH9&i$P1gx9KbkExZ! zTYKm6k(rvemrscI+6jLNg3fFOsCnj7dbP<%>q3(;#4b(P!M709#lRImpoFoerRCa^ zEu=8e^{{W!AtI}y%S`k!*iEmd@zUF@yK;k>g3QBZ7{{@+hhvU|KH3CytwNZ!YJ*>p zfDzJ3Q>v)C<&umI`jPEifwU4veAL7`OU+520}lP4s-^!AtgUWCVVp;xTk>G^0C|T& zun0fXKmywjY~#+J|Gh@2s>^yky5nxc8mqzlok3q#VV84+jsU2rXF&QL#}|Us1K;fK zRnAkTtI`gTe+}?KkA2<#*iT5_S)@24xyx`#ot`A84;W&iL&V2=QhtkC-(qcgnq)c! zUQSJ%CI70rS7-w25zmc>gYX)7Q~}-#Xt=w6(S<&b;i=(5$`nVm6Abf(kDg zn_$NuvIHp#_nRp7T_m}5;hUykWMg+3<2fk%21j8M-;FV}C(4tG!c}^G%#@YV^@MxD zWg$3ly=b`EM)KZPvUg6MF)pcGqiS~{LO}hsEhHYFsSw;$uZ6#k=)>7~(^3B0V~^fp zi0aoRDFpP3#*#_Lu3L}6iT*bI20Z-p{+~ufaT-^(f97V^@{f2{!OAs(EKdF{!9iVI zgCh@8&KmjOJ~(*(CzNYW{^^4RGurVboZ{l?vJ()6KWm5&*GKvOV;27P`1FpRz_5_} zq+aeV;jq)CxV+gX!&d<|2UPGLueJ1{h_TsylP8f@IP&|cI$pb?Audp$V-nQ6Cj!Zi z@vt0JPcAa-7SX-q^X(~z(DAC~QrS7>u?z1MIE+dbXlKk8*z$46P7Vl7TjUVmJUd)~ zcsrbpdykRBvW#a2NEof#Y;s=PfMnvB5Qc2#p2=!$C7LIS=z71Pu3Qb3+CDK8wA_1r z&(RwXdq4N1?vAvHfX%sY=Y)y}+nP~fOj%&6j7fs08f2{WO*yqCmVsRDvD-a@-VIlL zo{gGWoNS7!8CLvOuzl5;lO;#mjU|uJ^TKum>t=S}SDWU9`$vlDc7<&p9<8nH5!2P? zc6SZp~kcta|ZBXW1AI#3&1XS zdmGOxbQxsHcQgBjDQAa;eFBEr^>?s2)58@RXy$yW<=~g0Cw+HSlKd0RJrsUy^)`Rg z8?3yH^$2+LUrO*7I{!~4xN^kgwRDv}OiBassE*n=zhQiLxDE65#{@DoIzDNq%s0p= zK!Z|z@`#GzV4AzYw@N2+vHt=zl^Sac+jV#A(-l7&78IE#t8AboX)T<3B-lgpCSgA( zcxXz1ef|1vNvctU{6S&)mIIc13}NRJ+zdXZ`b&_>DgHsG*7R+Mp2(?5Vn)I7HcUdU z0;$BMDj%E#7j@O5S<=}7T{ zROmc3m;MwwfC&VV7JBvH2T?wx4OrJ%jQhG6nfH%=8G2Un%S#oSyVFoFzds^iQAer) zJF%vKy&ny>Vv1h6=Ci{h=N1u!XB)Rv@D9x~YmDs6rDkE=ugPtM)0AB2obWSl{QFSe zSF8)~zMncZOkCDA^mz~KoV7YAOA|M6K7{reHB|k4NbQb#>tPv`qvIV6S2z$#Ga%h4&lsra^`e({EP6}8#TNkHnjj21+HVBE;iWx z_Ay9=+5YY1o8D=Lh2VUtCL2XzSh;ZdA=T z!c9j*NBQ_uJ;nyyPwEs=oYA+^+!^m|Jos0NdCzB+Q&gv=JO#{6INI?73jaMWnp16@ zXd)lUX#a%++zgEN{NFr-^U;69V}V`{Z-4a0P2nG=Y;dfg_<%lI&~aFfmDa0C8s%v@ zkJuaOMOq&nXjAm7QfTZaR116lfSF%5kt!X|tWr~juY`P!PPxHN_S zSetspr}TI8es9woZpw`Oo_s+b`rv${=z@=Y_B&;dZ1ei_MU6F6`>x!cX!_ZT{&T=S z{$peGi&%>`yTIEn6i;~jf=<}A!t!E*=_Bf$bd#9EjxSO3-spFJT6B6av0iCW{jhSn>7H&S%<71I@4~rNo$;x&U3arxzWzrW z5yf{Hm`9O=LRwlTj3qbNx!OY&eibe$7QyRPxKIotqgN_KQ)+hg^re1<@#FxOhL>)v zucn?RT;F+~`f2g%gIgVuWKKi!PlP$S_8=)?2{gSpU`0y3yg~U%m4LZ!OVS2TA(>jJ zA01!*EG5MKO?7{^y?>f}4SY{+0abepTu47Do7N#0yriBb=!ir(TO@a`)_hdDt{;zT zSZF${)ZEt(GEEw8gAE7Z&gSzI8D$*1Z1dhqT`^ZR$Nfq<@k1Lw@OY(6}kN z+!yQLsNhi8U%G<#cbV15a&uAmepoHn&(_XV>4 z)r0CA&t;}I1pLlp#0{l0tsjFY|5H>m|NM`N_AAdI@ZH)AWy9F9R0`iD=mJ{RTcPQ7 z2`cTIqe4nTlM1Nx%j|3Ehn)JHtNP-O;$Nj}jAxb!lz}D&m0TY(hqSUD3E3E&K*k4V zUw`rthr7dFgeDluWcZu-f13I&=k9Nnp6TZGI~Sr4$oVdFewYJJbXt@4bVVxD;e)tV zp+H$orjv@6ufg0t(TI6&JgB>DCi>5V8vD=p8u;Yn>s)2L)ovq+tR%9(D+?=- zT2X6TYf|*i*~I_tk!8*9q0z&GBk;NB9U9&DhLUm@FEY+%y(aUmg5TaqqhXRXt{D8- zidcHVxPX`ZpSb5AZ-4OgeP)=_p?uelk+lI$sP|rDqx0@AMiaVZy9P?9c-P;XuJYyj zdQ_n^W%Y8-1uer%m(-+hXccnIiuv2P(^!GBe+kem=k^~dc(0SG^1r_Fm{rQMTsY!@ zH-wg@mD)|bQ)@CJg09tgBfP$on-q~S}^?T^8 z$5W@QUhRc4M^z3Ssm_c%r-gA-HX-if_!wrccF{5!X}rf8(`JVTga>vSG&cQ63g2T3 zyC@&UE|N5ekDegExVhSVI_Ss6(bz+o)=5YI-!}iLo)7}neO=lAp(?!6yfKQRnrSnm z74YPt|3;*SL*X6bDS17$t3;hqJ^^1#y;spMe(r5LXW{kF<0PsE{Wk;d75DdU_uq9L z{v=SA)$RMMg|*FUdACi6_oHBqSnq1{C&_-(E;d>gMXkfkkIaLkhiO)RCjTKdB{n_z zTc+~UE?#*%%H$y5_Gb#8MG*Z?VZXU!8@7_J&RvqK&J|=oyxSuF*i)kom=K1Z0H8$rS&R^Yb;OaKTrl;1se%iej z4O8Xe*kv~kdet^^tsmGn8tLE=3VVcWM?DA6brly?`~oA?=L8xos;#pWTW&BaFZWQ6 z#cG86vJJf**i5rKkF&9^It2~j?z@KFWw-o#5vmu`=2iZbuiih9#)S6$v5+dqNj%k# zN|io7JEk9XN}}tG1=%Gr04vz2#jjh82+Zsffx#}g*9BmRY4`<1Cg`CKCV!@!E8zuL zjXcb_TB0p3HMdjK0Y0R?d9bS%47uS)Y0CtIM?fBXv0gED3zKylJIMF!jClhN5@Pz; zG5&2?cUkXy`=UQ>DD~>!w*DvF=87$FpL26+z49r;n@s-R`$>W#cX7|QtKrt&I|WHj z!_^t9V4=)DE3*soJ|pH}ESEGRfcfA*%+uDstdiKrNAC^H--%*(0Xs2IMy8~I4!h4QL5 z;l)n_XFd`7F+EDz{|9cxHVdOfSIC;`Hb0RKRqnSbTuD(N8J$d8r2k)hy$3v-d;34G z`*feysa6%O+0xR+s;#B=s4A*P+S(;{gpj0Dt5!u(BT}POjnpPYI*}T&LlCV^kP@L1 zNq)DU=XuWae9!s+@7GIsMe@1t`?{~swXgT}yu#{nK@moS4^-FQb<%y_b`dw``|;me z+xaPA*!|0X`SnY0PcUTQ-6`epWjBtQfIx>tjB|Q|cV$O)$BWXw`5zfG_Fe#&H{DHy z;BFlD`)qp8IaJ-RthLNCxAl>u#>XtDoU~&1o$|i&!wqjV`)5<0C<|7uU!#>iQ85}R z5w`UdpT2OH&U@j7y-55Vo^^L^-8;3Z*gD;sY_uAAsC+ucAR;VfY6JtlQ^}cLmQ|TH z4DIZo9k>AaQ&s3yddAaD8>AZIz2Ka_@Fl#@w46D2=B&Nbzn|nQ!M_vsUr#bagF5VG z`!@V-q0A+_0gnQ4;OBt9hF3|r?4Y#IL&LX#4J3u1mFbeOkOV3)m}Lia1da}}mMrRZ zbOL{Ny_D2oH@plP%8mofW`*>YJDKb~EnbI(xAj~}4+5;GMw zpO;YUw+B6_Q(KiT{VG<5hK~Jl8=NF~l?`*HS$V;J)D^dfG9#ZGYobAm-mB{Ru zSO|VQIOEXXzWV4GeLdhiAsvQUnBE3x1j9`m=0EYr&)NUCB zj`mNEY-@8qIh&Y(^@xgGfjE_@U;a<2zJLJwz~8dP)INj$fq~N|n>*WBSdoh{pjlWM zSKnn@NgcOC>4Q#-|HVHi*Z;PWik*M0c*e8L3_xM9+l-=6j4l4+IOA)7bBH&4a(;KV zO`fts=F}kxQ?bJ7quf#tyA+uKRqCG}mt&Q&WTk=NU(29R{O!Uw#bl-5q-ndOf8Sa8 z9$#->WV>fp*Y*y>KUw;2S5Uiju*!d3{V!MRuQde(&ioPsV1x7~iFVgSnerQtFR$v} zt7v)lC7qdL`}{wU694%QTJ#?;;~0|;_Th0yee7(#o8*E-2j5*1yeRT{SkGfqmAIA4 z{AYpx?f2h&TW`-MJ+5`FE~MAc-U9USXn6Kac@%CIJb%ODl_T|a*-xSN=6-KO6`S0U zk}2c;f2}p6@QP4eB!tDgnagQvW(S!YeEb}ht^;AjC z-IQeSCZG8m?Xp>&nHTf{B3IT#`{qMVMxb~87ovbC5TN^OP2jK1a(=+ewg#APluww# zp-O~t#Xxa5qkm%&rXoo^m}wEJT^!yDs1v%fqoB7~Jy5e1TqyPzh*v;p&i~ze#{gdF z#26fJ20YP3!}759m)Yw8g@&$>~dSa@`HnV(kD* z%71aZK%Uk=-UMle$5CO_TlLWUVkw#G=~i0V4%c#a3kW=aD^#y6-s3f59@kx!E~z5$ ziaFo?QpGeFV@Ut=VFd)7*xktcwIM$Ly)bOkd_sR%UC=n{@`h=}&lB`J8B_51?69&> zRsi!xm|bya^oGuVQB`m6-wduz*t2`3zk45xQI3xjDX2gaEE^h^k6<7}Ari#@jyODh z@He$IzDdnA2@BV0OaYK!)mS>NaozLF9t`lL&&YNEwTlG=o*w#JDti-M?Ukgh?d&kT zsN?a`Ip5JzK^#C&&mmQedT_{}SN+^cs6NE0%Oj;jVVd!1*XEn|6yE=%S2**Vy!~9P zNCB{~>7RX;-7qz@?)9YvXnFa+*7|crYV<$e#`E9Y-8F)zvvd+i6KwNtpY6U_efwcY ztgyzP-+J0*jHx<>xmxLv^NYXq_Kf{as%+ZWmCXR3D*0u0d`;F^!q0;+#>{~lV#!}T zDIn1K;UA6hZ}UL_1yjMLOcstFM$lNOLey`P1)z?lZL($Yvu7b$VV9@-?4eEZeg93` z8L7WL)BiT2_0*2|iSOkUpt^m%J5ID8kyjo+vc9o4QZU$WSFz4iL9Ls$qYrON|B(1E z3hm9xH`V?vv}UyGl|ACRoeH|}SB_^(rwia+$|FZUP;@tGa_`vRX8BX3qwW?k{xxc)|7`#i9@hUQj>R8SkP?Ku*^Zl&aZ zZYAzT4UqRP_f$#s>vyWLtgsD5P|phr-9<8QwkHt%%)7~V(}hpOdt=vXbsg8HZJId;mBnLV zh>*_kcO|XRYAkm1p=NI4%l!AT2?QVzV&(3h{wd1aF#Yq*;6e9vT;p5evOk5Zp^kq8 zzz~sRyW548lz}ClJE2RWeZSmk54S!#6QTqe?@X!=JpH|ulH)M3crjJcFBG90f}3)# zUO#ht3=&c@B2fvzB_*U)N- z7^)akS&*PEFdLpLhef}>cN)?gy}%&vkH=&ONrQ8bjmkw4uRwEL*=ksjLuOcIM60^#XS8NF5~~T zK;+DTmX7nsUaYJ~qAe^e&`2T}Tfvlnj7WYA%iuWJfKiaD)EQ!*k z7Zym3ANkt$VugmRcbi}u{$e)L8KyYgY>J=oS=c-&VZXo6LyJ!V(Vrc-2M-f;jzTY4 zsx7o0u4+Ze6^P&^s*uV&7ZRq9lRnus{HXT0dr(-*Rwp?_%XK=ji`!rljW<%@H+G@@86G71s zEf@xg~>aV#rk(<`I%~7Y4R{thhJHZ5A71fPUN$8XmnKW3c~CB#AEmGA*V-%ha+!RM~-e0c;y;k z``;pK69uXiKsMawkQZJ&sd-;gcs;m5>6l(b9Z*F&ujv|<*P4aO@orc$B(>RtlS3%I z#!W@xU;iMz#d6KNb%XK%J68bzq&Q-y@#@bwfbhu)RX*6B6LMWh+^}R9-^}{xw-6iR zY3rq7D=EVAg~0ClAXYT2P9vHh;Uk@ZDj|rB9a$f6eV-~-F)^MN(uw@N2*H=`^6X!e zVl}QQm2pVl;|HxY5=Jc51{PKt4G#BkKXZt9>~*J8i2|GnSKj^#<=oOI@l+oEgu~iQ zkby2L^j#sok;|a(iH18xE}^93H>7ThOeuTwp%2}#4C(3k^jhY0fe#Z3wGzQSDY+Q* z^BotLqOp4M8FyXQu3@OEWTW=x|Z=r0LerM=IMAE!BC$ z6e(80Wr0p^os$A7#llT2AvDPFI7z}p(qYJeru%!i?j?Qwhi(&Ky%^=BC7o>oGbfzd z|9krbR!~(@^x1AbJ1|&L*juc%y*=4?J>G|QYTqjYXt7Jvwg<@zCdCWMoqe&w|Dc2RABQlMMt znvh$np)*EM_)?GAia#DZz2r7X6x@J1h^)oDhd4^t!wHqcJW`O(+*@3#z^hz?^cD#T z3x`B(jL~t@^768jWSrYmt5(!{ae4VQQ1^zA1JS{ODs4F~A`o)6qx^p;2SD`o8Q9s{ zN(*}*^I7-5v`sIkHeNKTO-$FNJB*MnDiy%$L${ly7)P;JlL5Fny)_}2t7(LYVyLcM zqRN?$rsM;FHKm+8Ip9(Gb1)yhtMbf%nvwn000VjXyEUrFFgqQoG+w1nX?@&d;rpH| z9gO^Hp}EhT4NZ7NY19~bm-5$jh^(>};G=uvI| z9I?w|Ed2(x|3%UpneuA?gW9^={d<`D%n?r=-P#28a^8NcX8G4q)oY2o#-18HT=U4s+@p@NpxXPGe1nrcFbX03h63v+%n(s?2prfWH{ zbb^6ARFpEU>)i28R@KH0F%yV6TeP9>)a@XWK* za&lBw$_bc@ftNwc@!v8t zPmngjd!x~T3A8h*t4yq!%*{OSwlyxpj7|J`WfK56(^;b=`mBRUOPk#K%d~nu5KV09 z+qRqGU6D^9@17?>rmN$0meiapgE^l^^tx%yF*Xexs{*yx(l~XDLlIj|A zuMtz6jadncCKSq8Tbx}gP2H~Tmq7+ckBBYW;!i;Q&OS4~5o}$asS73k(83#oD&i~x zqcyNq#P44f$Vv&`RGFgBvpM4}bCo#F9AhUzhdVW?)0Pmew#xQ|E}%J()%Kuf7FxTW zsOs`$2u_P@LLxd>UMkoRPfw~U*u(q{cii&=Ea14fICP>+35^h8*8TE`IF6h8M1rAt zT0tSDt)n9a*x=jlb$qe?Kaj(lk$|sXze@G=^hgH>v*Kj{T`%>FK5&6Fzcel#N07|U z-BDnby3YxkoX7X)+kvj%I1P9W_ZAC3iCm%%f9p}VxVC6iwInG&HFezi;C;^!?T{O} z296X*O_8WEXYmiaR88Rw;}DyUSv0gx!+dy1x6I;F*Owu^);xjG z@I9*jUxshENxz9MF0rr#*!icgY1pR}cM;KG-(1%=d>A2<>aR-W=6|vT1MMhP2u%mk zRjBFE@ekC|kmQ#DL?9S7&evGzfwF?29GscJ$!CDVMi2;MDk>(cbcz+wSM}52_{b(v z&YVeX`}!3fTkJ2OH~mfSznu)gzu$~b7$t}$o12*>wY9b;ZNFzgs+|@iRbu&0?E{FwT}0z#Z4M2iSpMIJ{zw7ydf-q>%CA&hn!2=!0NluJQO7dDvmS&jLh zesoHbUH4i02k8g4oE*FY#BDM%q`f74GJt!VK@qQav@0=U7@XK^GKw3Z%C`Z+0i5_u60hpKJXEg{^nZG-AbC*!v`X zP6%Xli>kb7h3d__NGGY!I)c9Ym%6fdY7V!3Gp|iMrS;t-Djwqbn;K+ZHLHNq`dKc3 zED91OMq(8L*0zDlbQ(Fc$r|7J{iDyUYvHkfBu^G8^oOMbQvwK!$B+DZs~ufxF8GSCG^>JY3|il~|;TZ%mwygKJM zZKaJ}U#zo`@o+SAAJauO$w$UxZa?U_6Sa$ET9d>m({$5-=!#u1mDylmXNdO?Uny9q zIrQCiPPJ#H#WyWJw>hwLaNqZ61(Q@CZm4i76Z?JB?CwN_bgbR@AF|xb+e|)6Nt2o6 z){v@ic_yI7U1HCH59>YC?9;2(YZ~9M3(J{X*$MJlGZiMoJ=I<1y1NYb@_i+H+zs0j zcekAfS(l)0HdPFTXF*OQ_s{|p%-^pwei-zuPF3`O9tz7FBEgz}6Mp54r-$d{LMbc| z2cC9=?75(g`W1}0SF!6Koo1=moi8tdqJ`#$>}3L$zJPedbrIoFU4DgmPX+mF7#LwY zT~gyF5$6WnkFjl$+nC?U`UT-MOaGHG0|aN8sixwg($wg>5BZ-S4OJPw{1)bkP#1Kr zmGL43GD5RFGtxsoR$Z!ySC|atJs& zgf0+v{#WP(cI0)%~QWxs%sf9?%^1i^efOB-Y%Z~s+UcjH|w1I)W31L$AS zhuI!?;5*Ofe789)ZcTd$sDpjNqazjW8if08L8*Sp(Y68ezooeys^zJs-KaB#wN~2B zCls`6XC>FWQ(Fnk-k2XKxA*I9n6GAL} zt{3Qzmi8~QME$aY`|TIElHQaAD~Ub-QQD{v;#I3dxF*DFL#aKVc6fT`o%6O}B^d9V zkh~eh=wFzjI?JW4ZiJdt*gC#;TJ9=yu@8GPa(i%*TNb>U5Jncf?>Q%(fiK>t*fCxi zHsui^V#Ybwey zOIq*(^Zw*Ikb0elLy}O7o5If&z`$#U0$px_MosJ28_q{n^aH#4dsP0*o9R>p4-nzN zF(Qillb8N|QF?ne<4T)H$a(SuP3T8{39;|P$Eq9kaS=t#IHJ;1tAGxRUjpXtm0BHN z!cy_@IYGs>uLXa8^jUyBb>Db>M78cL=}Eb+7lIiw!paIR+h40$J1ur_G3^k{W`O_o0WMs)Oze8_FDC>yiI; z)+3KqMZ>dP6b1WYGu*aHW=@(!=S$Wj7aOk0cy@2yln)5?f4NjAm;O!jUnd4$^3MMc z6aInLg0H-ByLmI+&BZ0lt-GR?5yUGH&L)cQ2BeP$^mZrzsguxURNXBpwfgr3v@^&# zeAA8tPc!H%+jPB{u3){bGag#7DN~QAm=DyG$NWwPhl!`1^Ny{4=02tHe5Iv%W-GbZ zO!bP6#mC1PnXx9sAhgHZ7i$0V3P?873#vi7@YinrH8~}ECGt!lB_UjL&UY>MutQR# zwD7_K;SY_8V^D`#qeKg-it z*;P;f+yvukpE>K}!(>f!BmXChc$b?`nOZ&lOwV~rU+GONytZ~KeYGvpXl$R3ta!o# z`@S0{(zm`L!pL+LVLG-izoq$WpP96Ll(Cd~`B@`+e@k%2G`E7C5a_u6@rwMHqETs=nWqDa|CbwL8MkShl7T$PK!lT z)amkl2CE4zWXjD&aX(n3=712)wd*Y2l3s6xa@C6PIsaS?q}ctgM^Lg3|jVM1u!o8*GOAZo_i67D@&U z*Jz1%8t)9zg+L@YZrdF87A?MLarm7s8((wb4P*?_C_4JQzdhut>y0NWnb2T}j*jQd z(nLg?n3ZUCR!6lAsE^wrh^Y|8bJvq(K;PFGFU;$gwMZw<&8R;lw>FPQAWs)MRxJea z-D};j{G^N9AWnsFRsuSCx1WGn%B0tb&vF?#Ks#a91-jFQXFK*o+&|gZN6=vj?5yDM zN0o#81{b?Y#)0PeYP9iuF!Cy1OO5JW^8_}fyA2X(~%RtE6 zqm2JO`j7IfZCeGN>gR=@4tRV2w29nP35t4#SbFol14jesOQ^Sr`}ArK`B#|t?kpD? z^SgEzX494Sg&XPW+ij|H0oVM-LMKo)wz5q4%}{hb$!bSd7q`kg)N=s`Jd-Yi)me0D z^jX^Y+fNi5igIFK9|UcVElL2NsJi5xXy_H~5pk}1^t@Jn7e4Jc&~;;U_ZP1g*=;6i z4V9Ru+N)sRO%@^r#97?2(dehn9F#tFM%=4(ghyE}Tu?N9DE+80H!G z2tU6*PajCcYSwRsJGsSn?ra~H$8|S2DGhcSq#Og{YkEQ7|HhHhGy|bVqJ-Asb2G!^ zj;Fo12z)*hq`h=e{FC51)P66x?UP{RXl3rA`i=m6Km`N{>E25edcW8LoquW0wnE7z zse8tovtf;rt{-7-L-kYldjdKY708Yvz|Af>#6iih-Gx10u1KP@W18uQm$FJDF~v0kebEE z)ZaawPEEtnu{Gy|eN;Nb=a+=mH7e?(l@r`Cuq^Yu@HS?X2&f>P# zZNfTk2C7!12_I}x9=&jRr?aH(@x9~PD48L6AOx%^Sk(FE5Xdv**7?(dJj*mjN|&vK z#cg3>VbH1R2+|LORdV&Xe09a8yu`ERD1+6Q8*2&A$+CiPijvg7sA_E)c`yP7;xU)} zb1iL>0MB+tEAq*vG5yzZ=Ij-kfd@lnJVi-BPa@EHOQ%Jc3*02%o%yl|e=}cY5wK1L zDnHEEyGJU;nujE`y3y)PWo{eBChvwF``jB`#`6{?`%MoAt{&b0<&wzM2B3nyhOKbD zfX}dD8RowD%l|Nd4zWO88DxCTK*r$pANlIPOoPi?w@(k}{aO2JmfZ9)jEqgtRZN;O zB>jAhJ5^+!9_+B&D&%`i?>@m3-?hjU@4hK^|NLCTFy5IMg=s7lG;jd$XAicN?P5Zpg4I=HlkqkDS_Bp!;v-guz!Z zmPuwZkxY{lYQ+L0`sYsy0-*j&6qT>r(;tHL3ND(J%4f5W3!|I~@oJ|ZN*xL6Kz(0Q zY5Cbo4>=wQ@{F+AJvL4yf@Okv8$C^g-~#jF%dSl=0$woznAYFMBj&fH{WzkUUo=0y z*9~MZoE9o_!AR!(r#j2ey-$VwNH_hpPN_n_ag^e z3`VlfiHvOSwTne+T3y=#H|t@~W5c-Tmmb6&lNMyws5_6`sI9-=G`Zm!1_ThMtspPV zgF8mP&w`4w04L%Qq{#xbWx8|E!LdJrN_Tc_-=>r1fwRvi4M~l|c#IzcdNoNYr^dg2 zO{I%7p5><0{ z_@$o`lwYe6LwobbYm$3m!fS9(hdW-2Add#~&T#zq+4C3F1TnOkDVO!icxJt4c+8v?kzfH8_OBJZ7zX_OXZh25>G#^`G6 zhF{MgPsK^sBazFs=EeVZi-pF1U$JfN6<16iTwSdPF>olb2a$O$G)&;tknlx28P_J? zG%*S-fV$EE&o}=*a37SG{e0gq$8W@Ox-sQ{8Pr(ruVk8V#?{kO;VU!Nq{>QVQbU6l z$!+|=+%jI}&hP6F;Tbo^HAST82i45rvQF}Yp3iC6)Wjo9S<8K>Bm?#?VzSnc`h(J~ za!*Y15etrJNm-6`1ydt@{cv&kI2{cYF;%fzNnRNaOLOab6-gSltI18nw(_YYZGvvo6az_g>S=vgdsT}#@FyzPU6 z#=$V&k6onLh{ePZ(H@*2_3W_Tlox#N4C#HJz1dbzK{BQeon~!zvl7}=V@-5ft*Rd} z9fEh`dU51#*K=U}f^c+{5!KPG%2dZ=YL2BdCG`4{HZt;GS%YKt*JTww+ggwM2?hU* zMPkJu^}ECePR|l@CF#9rqjLXgn_uB{lN#4Hm|Jy3__(&eSKJL7t|Xe>XMW;O$F^Un z$N($r*we)HG>E9t7pXycijxDyt#(t9&M@aVi|}<0dQfeSZb(>hrzrv0kvDU~pCJg+ zHx$a&swh%G$G;jfB=2%LzPr)#Xt%aI+mU}Jyr{9^*hmnEJM0wqW{$;b8n4$uJMl6X zVa=1d!8-5Mzt;hXGM)Z49ePBf@@qExb(en<^%7C{%xJ-ALJ8_lMjl57fk5=WL82vt z?Tn98wA#HqfD+JEh4v}a=&O(Yz8xV0(3s;ZtiD6jv+~us^J_i)sw?E@sr;WY=v-(O z=8_NRO5}q}TqJbb5+SOpW}kq~(w4+gzC<*dwFO=2Te)v=tN*%5f|#A>@ARNqdV~9r zs!1dBh0b@3m^LzpFDZ|Aj(I|-Q^u!e!UOP#`#SuU)H>bSr#gux87r*VX*D`oI3E?B zGNGrTo7lH9eXA+rvcw7xEA6v7yEV+G zqm(yr{m`2(?59a`y=8fG&X9DH1p+~E3$8$7I&oMR%CMh?(^%KQ8_Gfp=YRzLf@b}s zmG2e-%>ANcf0+`%U%xQ%Z6^-SiOTd@Y0Ep5nT%SyXc~z;2QZJ+*Ds*PKL0i&dL|3u zZ<0c+0+-`2Ww;Kf&SIPpyI|HfHzNk8k7_kImoHlolJb{r39co9skHSmHcw58gDq;m zp}j|ftc2dbTo%4Igs#HPm4r@`2W4;)kjrN_-qIX;=^#jud?jpSd&10kgxaiV5Hy3e zR8%uNiW^nG0pdEseQqV}fbY6S6xx5j^zKMPLk26Q`WdB4y|ljw)*UvFiS~<#2{><) z@wv@5)oew$pxr0jyE@T*tsZTZMbX@^@4{Jo2=}yjVwRS18y%1h-J-%5r zeURnYXh^Z*DiD&oA6YW4`GnF%jc0RL4&;rQ0WS}D)azrG^x?T=qH?15!)p#5`_YBn z213ho;Vm_0Yq@wB%aVZq1l=4(!FQvMoWJO_#(co6GAX418MedGGN6!rHvp8fZ-(-4 ze+H{#ZCr7VBAfkOd-Tyf=4W+c8@-S2i6wT?J-bd5^i}IEaWzwz0_o}vJ2H$HNlgrVztE$R6RTsnUM^6owAFW=X4(bUdzS>zo zfDp_b$n~tSx}7sxR-hlJG!WWz6EYAn_^bl}ZdYLgP8byFM%{je ziuOn}BZB3_?I}!RBW}Nr^=4V1RFho!9t83=J;j8E!g7y_%6QoX2ZFgs`qxyR#j?k_ z7a9-uPUiY^G)N)bU4qn0BF|QdMeQC$?pr?;`5^zwa!yRMX@}fhf59{)|EL^A_UA_> zHvXM3&gxdL0XGWLt4VyZ@lnoM5mx*&YvKzVGA^9wC76Z~Eib&b24na_w#&s*i(y5P z#gJ}6ePq$7y?=6orb`!>x5lr%zWiy4tziUAp1{kMDW;;(jV_(8k9cOM#&JE&!N+B) zi4bnm=hjvhYl%U8gL{JTBiT!Ndd|@q`!!csFLlL^oeXEjvDptJ+7C)mApOiw&kpIP zYz#Vawe+9moO?g3Q6Jsb2dj01gSqSa9>}~UqlDJ^*2-t+i-_Fy_qP$+S5mtNu@U=U znD3=h91hF`UH9#$xNn5=cZ*W^qhR>e@-y9TGUEJ?&c6IB$vFPia<6yD$;rZ=DR$E~ zs&YTN$e3K8mBnVJw3YBB9oEaUPHu{E) zn;J|;+YYfXovhS3QKUY(D?+1Ud8K2weH7uf4484!v_cJDdzpP;<+*)E&PLTLWqHYU zc(vn&Il>bPFQt9|zC457r$Qe+*guE4eksDtyG7NZiv9Ck#)bLS;Pn;ePmz%Dtrpgc zM=UB@lOVdN6ok{z`!2szLnp3zX6R>e{YjrD@eR-j)>5!;uS`k4c%*arXdT>>TqpzL zgkN@noG9GTB_x%sN)md$P<)=cEo2`iJs|csl>%9%OAkkQxH-%`X`9$>D2ES($_k01zV%7>! zoA0hMdQC-etxCS}NFCP@;v2-=QS{_%Jk7@lc`2xOKh-xSt%w78u=>D8GxS~K%?cBW zryJ^^9aW}oRQGgv&JBuwM>yPw{*4);xsHHq)dsOBi~F=s4j060aV|m=$4Rs;$=S`| zn<-p=(E{%ehkGF$PTXo(bfiW-s&*c8Xx3p>z_(x1daK1M<8esc@Q%>B`7Q9f+#U1S z3bO9Ee)4ojC+mbZHXQ;B} zNXdD4kSCqh-n_sHsJv|MIr%hpXwbGdEwsx1|iWcU-`+pT?lXfD2W zvL~w4RkyFXWFWg4`a=nud?GN7Hj5Ev^-n0#0mwP~s;q-OM5ZXI63jI{Y%HC9ip`1$ zz#|FN4MD;u9XH0y1p9L3{LiDm_0yuVpN6V(2AZ<-n=1oPcP_GWTF1k$i(Kg@z80D4 z!OdZFJ{^CaV{%phnn9{|fZ_ zU)^fXl_`l4MXd$x#>2g}eN*|W@;~n>7%@eGY60C2$!QD7$*-|6P3fQP(0%}Cx3Z4d za6O~aWgQ0Tyb0F>D;Cd};96s|^7%RMCo5Js*%uTb=a+SI`8i)!#J|*G#LDB`U{&45 z)n?!|W$hIXFc3&_Q(35L?r*Tqh{53vQm4oKhx~7d^>|_Y3ckj%BV%Oe($r@tjEW5w zTT!}KmCoQuj{X)tPv1F+cX=ks2N@eO-0adm#w@UcjjwHlsFQ2%Q@h?s)ZW5vtj?#3-Cl*pn&TR?Qa01tilpW_5Em|e{mtmn=>ZBI zbf@8-G)gdS#1DyZE?9b{K>q#^kBE#}nU)yODa8Sy;E_pU(uwRV*4VKXnR49?CKK(B z;(!6P^1h}Y@{)@7&8@sv(RP;+#kspI%4(l*Qngh=h8nmJHT!+ko=yx4dK>Ng+z)%- zg01#8gVhFpUW)akFm=&Rge%}06m&+{4C$Z6%e?I?jzFBz)UH0dZ&Sf&(>+KVF;(9Q zlp7;g6*x?tRA)c?iD&NM_puFU1(#>&22H98b^3`EFqHd}O*q_08GT;N2XoaOA9I=K zh?eUHf)0sdHSLT!rab4Ns#Nua&h#BpF}?A$!yOc|XXB9z%!k&^yc*|7F*>bZ<1@ih zh25MGh}Tl8cZ067%4In48t28UDUE*gG91kCc){gU^)$I8&p!nA=O}%c*5wC2RSgp(qyzOU{s_y>z zl7lZDi4NsR3{4~Chc1hv!x3t1x$_uKKc|w-WW|3@#CAC@mq!dum7IeYIZdMIqJQ)~ zS&83$fL&4^Vfedi2g~yZX zIgHw+RGP^JFJLgwLYOnZoi|S&hyswa?YtPj?NynOu4oPKb6N_=gJVyAt%1+vLDh6$@@;`Nb8LqE!dZa0l^k$GasA zQr~wLSu=cpWb}yK)e;*T4l!qZ)8Ks?HMX9!|o*$OJKuc1p`r)e8y$cn1nM9E^f-%Q50|1&t39FPcmkhkc%FS zKgum^vu`^4H=40Js>d$iPaqzM8;cEGZ~^f>5H44e0AL-(Jn|<8{pB*Y8rjq?WmeR< zeR_^5f{a$3zRopYON~mx>qa$UpBJO7Mebd88DU&@U05xr2M>H%?I=0OlXBqQSMU$- z*-px;p<~`&QHM*E6$lDmENs3+K=5RjR}QqzM{kpgn4DXF!Cf#y(=i9@`z$6s`vZKK_4BRsL08tr4vl=+%RcTB z-y|y%Ou^M?Eyu1LkaIO8HMcPa#{J)l6@+W9EG2N0Xn`IIedF)yOv(NBZX(b+$pEsaolP^ zb53F&#&pW4lK+7Cwr$XC(cA@!X0!&e zP9Dk+g*eI7(P66_*F5~&W8T@`{-Dm@U_0m20l=S;1V`1xb;B7bSw#;uvhj?k@e$f* zfnKM~U|v5o#5U@PP-dWS*{>;5t!h7YZ(s-`fvz1y1OfU^{(_$!x?89)xgW(mdz^IMntS3E^ zFuUps>nZ?E0wkoEV$O+kp=`NG0Y-9LGV_z+vJnmFf(z2L{N3`_aT*Z6dm7F^R3Tz} zoN%Kx+db&dx*2bENRW&yEqNAapH)MtB7KRK#$NlWr)ginAa)!0oH(R#nx3kTW1o7STGRnJl0lEaVCU zZUY`&@5p5%dhRDu10wqXU?E~;a-$zr-jOK&RhiAT_NpK8oA!R_Fy?|wD_o+Xj9-XZ zTo+8^#q8MC@8vr1&1?nAz&{i>T|}C$@xlK66xb@2BB+H};q(_5RSD12S}PO3FtbW) z`mDTlsvO8|rDANv;AgUzV7Cgki!okG&*hKlU60HiOSLDgU5?;M>z;! zO75=u5TZ_>flx2A`8y06!6ojeK8kF<2+;w=HdmdTUb4z6iX0K&NqYmfKihaYmH+lo zB1MT@Tme{a+!bg_+blKjhL)oUc6nj(*!q)TOLdl&g@J*~Z_#cO(|f2lj)kqelh~9H zg8gDA3Rr$|E^WEZ0kMhH~!30GLHuaBv zJ)>&_%xb3b@`YO&ZFfieut_hD&OGzRPY98=jI#hnz{ap6*~|=I$CnF1bn>B%*X&?J zz8#`zaS%`I@s&)gznrjb)I%F3inx?ebB}xU?8YYm87Ce3aH8`J^<}Ei`cdIXHvH}_ zBCp{U?*cb9(9*KO1r+g2!5(XlaIQv1^Y~T!*>E>kUG32@89F_RTiVY=Pn&S@#f$og z5n?s5bov2qmOfRd&4Qk6V|vUTD%tG;Wh~CUhCDg(@J6;NZRm4 zy#Mxu`o^03A(WJBOa0bM?;TA&pY0pbdM%nJd{y}xOAFv(Y=t1RF+1b)tW*>iDEZuV%6-P@5|L6Gd(F@atpQM?O~VTp{&y+nrz2XIscC zmO$&$h`3gb3ox|(o(_N6pDt=?tLeLKSeY9GbY4ItW>IZ+v~OoVdJFu-r2BwJ6?gUL#Kl>V;lBN_ZPWRB+Cr%OX-} z*@;;`j0vqs_R_KRJXpR^W)bWn>zL3G#=oqGHC$H^-mO*HiLG`~RfJqi&nM2aTwD|`;BQgkCB zwS}@jF~6$wDnSwid*$*ZSgF#1Ot8nvzaH&#d`*AGI`FxT$!h4WNI>e4kpy@3aw5lQ zmQ~7chZ9=M4j$ETBbE-}!1iHQS-jX0D7@f~>+3AfuNfhA9E6Fk|0VGeT}LABYHEET z#)V<2RSbLHA9-nwi3Va0oLUy!kJhCrS_1@3{kKFkLp)G~18xJ3xAh4Np$!J)`tU@< zPliJ+tJA1dt?Q+fntYjd7Zo_7>PoJR*V^{A(-AJUO-PL08?xHDuLnATspW&8SQ`r( z`Se5Y!O8=g$noTmxHAyn%H3MIWMU!Vi^l3w#r!yy*XOounl+`s<*6va?z?S()ui64 zzs)eas^ro=TW#THSMHZ83`ZWIHkH3=O$L1PR_+_sG*5*5T$ITkQ7BCd7Ri+kW2*!^eik>v{$-IT7wYY=@SmBiUK2Thkq{c?&I zg1h`pllqi9)5^xT&g^Aze)1ev!OIu(a3aNQW6Jx-;EkM#7g=ohYr4L3^hp1}N_dn(SfKPFk^p)9m}_=%P5!Ir8q(j69s; zgg98TjwOl6DmnnXUy$C?z~-kmX5%P4I){z_utqE%D&irubsGo{;G;vmV3A2;SV?1J zy-rLzW4MOx;8?bEa%eSqLw=$+ukudKk>y_V$`z-TOJfp0>i z%S1W9+t8*o%Rguj6cNQU5*hPx>6@xv-pQ?t7TbaC?Uw;jytKvhz$MekyrczsS^|Bw z(79-+AV1Y_G!r*R*>+`+tvL25er~*1yoZtuQtZhung0a;@S~)MdHah8ciriWlQ#b# zUa!VK(TM*zcWMDnC>+ei6?t@&4?2P=R+_i?(pd*rpetX$I-sqAGxrNA) zYu2xDd((ySh&@0AS^tX)8}HDriWt!v&|hmUUIHrl{Cz(83|exTSr^!NN1XR6SRw2h zn52e z;K;b8*GHv`bUVrRFs`I(MKQ5USJ2mKAJiUWj`{*72zq|$E~^GCoF@-Nh28eDcjPd%ImC*rHdolrV2QVMm6b>CXq z%%0ucl{LtH*WvWgStuMBi<&^ZT1sD1qRg_qYPofJ$nC!${9E1azbBZkSZ0Rx^$i+| zbK>V>WBWBv4Ba^5-5H>UQ7(N&u8l|Da-x|APpmbY_mp{zi>kG6 zFMnpS7?+w}nfS?^Xu>t`czH@DcTqBFL~%%2dF_Jt<2spMR72qOWCksDe}I_cNM3|f z(?YCz+33rtyFCrT^}An)f>gxkRpMUn(ovTcu^9i5lz*loVX42~9PZKbXtZ)cZgh5o zD`!I_^!_Zm+eYeE?wM&wdBV`XZ?>Q*?UB?S%SS7_*OXn;}(qnbFqJP zM=BonxxBwBe`#SYj?uC^I43gC+m!AOQaItMr5*7y=X;Zzkb8QYBwUspt-XpNkMA^{ z+SjKU;d^0NwsvkMKDqM}XKl1*O~|sxQMRIaR#bSsfVaT^A!?~(!@ricdwsacan|># z$MkM&hQAYUPg3=)WKTm)Td!}4Ds9=LC)3_{t8kr6@SI+f&Z{SZ#5(d|=q15pnqSwM zmy#|7-K$WlGr#0FfuSAxzB5}!aG<_tyH6(T=U0!O23+@bRdZ$DFi*y(-`JDbu5@Kv zhPffU(@m7>>eP<3;oa?gl&Lb8_0oIzzQ%N!W%||0z;Q6$mq_Rs#kHtev^&T!Gb6_r zG5*~nVxIM$8XU*>wFIOf9@(%vRcvz7y(NM?#Ma@oEJx^4Z*8?bk`G_!-pt5tVtNBk+zn``w|YbtyXj&xrrus$(CfFC59W7z!ge347~em=o|3Wb+yRG8r+@oa*5o`h zFPpjsU9Aa8qRS~M)U+x${Lz@y;(z@39*fi3t&j4Z{mi>g_C)ZmPyZCZ3kS;8o6VvF zMbE0G?GUr!+r17fb`~#^6Zt4@p)*6tS~FTn!nu>Sx|BaycLS=i6<=2UK&4S|n`*+~ zcIW*~$s)=h42glEM+BFnVq4e!1^sUC(ct*J>rfW^?KuDY`0|O2uXlm+GIJGP*=)RzB{#aa4Pe`w4Lu$Lqhb{k)ulI^-s*SpZUlj#JKzawI z3(}>Rs31*>NS6|&_bRzT%B*6n|-_Y zc*fYznrp7P<_y<{SMcUMLMWI9$U|v7<^b=aToUjJ#-+2N}vdc5A5j*1?PJc0U*<;_~MQGn9 zRF~=&1tx(|;5gyyDdp2uAC}9e(93=#6v-(lx*s?zPZ~1UM0(iU=(W-jWPrL7aGymw z@B>l)WC>umo?j5}sDF94tV0pksc$VOE5cYsZHk_^_odn*@?m4!{a z=%1%0^Lo38Y=s6ydApsk053n<+Yd`spA>49<|qAwd6x_y<=F`!qvT*!UxxSLuxsoq zeVL(aiHXP=8V6DE*rOQ(y6^40$`d7&gs#!Uj7Jb@bDbBRUMnr-Rx=|(cw)cC~lfDDSnjl%C4KvIu9Yyw~ffiTG>$4>b(q1Jvx}W zpmUr!l}8?>{G2d_T?Th2HG>tsS_}X z3zp6SR-dlo7Mo~qr4xDByh|$#Edso+>f7gW4>I`zbv;ESpqtr7iI&G|SCt8~I0a|n zwAT(aPW{e^x3e3bBbc{*=k>GecX2v$SPgIewt9D3rlfjGo9$wGge*kj4kG)*)`1`S zK>Jzr35Tpr_TTyhw0f(j?4ZBCPyO&P1>~`E@ux$tE%)Q>rNRjqOCx!4>(dz`mh4>T z3~x6N;g7x7fJ0PXc{4SnR1D>Ef5GZ#Mr3!cE!x|x#$xD+)3&%D^9 z*VGrJz;uFIrS`g8O8E(a|K)DE4n0P2TG-t9t$YIUDIL)PQncchR0`mHM9|PUJD2-3 zCoE#Rye5}iG#*`Pab4ykIIOt6QRX^yYzB4jqIt`n15S{&&kMylZC&rYJ#CfSYnXT2 z;LV$w17`5D5zZ5D-QP(-fW7#7T$rZ|RNoDoD27N78$ZjfAvyaz5u;gAz#xcLW;f$g(PsaD0;_h460}+IVz+ zk^jZplEfLUG-uWBpL_WC7b1#@Qf7I>Y0Dxc`~>cm>`B-|pDwdO*_13CFhb&A3yk9l z`(Jqvf0eS7zWsb2An~udLg> z%I-rEq37kBJgFUMt11xsyhVkj>l@`XOfae=7*aG{kSjsrp7~uC4@ z#$+zm;T82gZz8Tc5fZ!VyZmP`NNdkIoA`jaqE9W8gk3z-dYL#E@#Tx13XnA>$S<2M zq(+>tyt9~)Nj>x3)M4V;WmZ9o(rz~-DZAiZ`oELN$?VM(yxqu;-y=JLF1skU>gLy<+sozkYGATIWOf}9>pchFFuu@fAAi6x z56W8qw~Bdqd~UJSEv7iZC$NUkqW1mem@mn5_$(io7a@LHw zArslz!F)-Elx%N1gulB%;AYUUmVmsSW9jVjdu9pEn277Waq02o5aO{m*QoL7kq_Pt z)f2P+IojIeq==w%UWwpQ_JBptg03;o2OF?MMP96$bml?4goWg1kPy5=TgS|DWiyvG zY*+o2?#$=SFQoGvl4|I*>~iH_#SQ1F^|+4-i*@K|*~M)!V%_Ac=kud4@bXZDB$FVf0kkqjbPHmWkREA^9)n5JfCS(RJ@cLT-}dwEU+ zrxuWWqm8yLz#MIXTct-=U`O8~N?~`OMMUCg^OfB@TvV}|UbUm!Wsc>WMLWV?O?JGc z^4KO*=lFNb!T7)ofWS!;R81XEe34Basp(MN2}Bi zvl=?wjqK;;dS|WBnd?1~uI%Mj&L*kcMK8ekfg7vryF)7)+Q9$PENiZYdf$h7}HE z@q!YEIkMbV!m+XlY+&lYTT_yX!9aycoQFkUn z@@lc2TBqZZ-_VPo2eOkT)7yE{b40)MT=k)Uis*JSyJLDM>>g!*qp6al4Qc!CJwZCk z`YRz~QNPhsd{Kp&=-viIR`&F)@z3zw8b?PFBNPa#W)6VAvQaE9fm|av^K>Vz8iVGe zMD};rPncVqGUnQOZiOl4yH`duiqWr*~7b?wIoNI&D<;zO~wTkh{BB6eYVfij6FLOM3$15j94bTnp$n zHe7SRSxL+3q@gB>pu0`(bSGk>@JO0pESP`eT+!4>a58gkY>fP1=85`xk0Jj{*l#M5 zpeQ!#-+o@+Faj8U#{T`~Q0MoEmtYj)Z2ReUqW9Wa7s?cc&2?(VYr_37YY3loN6Thq z?~JR-udU&D=JkOZZM=$&4CGxgW;mk&$W+{apg< z_8tha@+OgUHo#wB_Mx-G0ty_ zQ+cS}nyf0}C!R>vzjVb{J2)KiN!Ths2#s=QaL_qUfmt`P>HY3;_Nc+xmum7iiYG>6E(z}|Tt5JeJFaqUH`UTh?JHnKf_AEl zZY}y9u6_zzOC1jGZpkL8q8PQD zKPBGsO3Cg=8ZgdYY0$5`7i?Ye{mJg)Rl-&EFMqq>W1?9?CY3+Ew+*9ei9g-!4 z)b0VVOsyg%fps#mrsct8a8hnq7JZeKSm7%OdC`{efJE(EXip%b%THw`0H(Ytgx%O! ztb6M3+Y}^k$8CGVE>SwxtEa2*wA4LqIa!PG^o5;xlh;phYge~cSNPe9+%lPde=3cb zGRZGr-hB4-;IN&^0IG}blMG;V$>%?OYLV7KEoXJ1ziRNW6y(nzo_ts0>RbM-hV>BX zkr<}j{wGlyd{{=a?^cb zP2qE4fqFN0n#?Aa?{Ch5TGcvy)W*0UO{!q|feH4X?F}rSt=XBIotV%l4c4(Q+aoO- zMtzMx7HbES*lo*psRb=xK3u9tf5Z0C3>30AyTk?B%|Z*Ie-Lz$>)y`+y}r&FVLQ#a zJMXNVr7(>hXmm7(Y51XS0Mn$7J6&uRXCsQOmg8AY^J@jrv-yexDekxi$Am*Fs`916 zdlDxuS!DeZ;J*5$(ZB+**??7X-cI7&=3LUsQ+B!}BFOi{1&ScAfjGZ5Qi;e8cww+N z^fgv;AGkcvpMU&#Zey<7Rh4+d{cdtAk-qw24x9>fVBJtb9#sn#JDk>~Xra8Yf6v*~ z{0lb=cmH?*kH_Uff0X+EFpCczo+G~~Jo}}tB2jvC8FCUfx0mtz!Mal=2J+ct&{hD$%W3b;R;1Y0!gOe<|DNc%aTPXS$=UauBmG^+ z#O~`LF_d!H$`PQT(^$J7^9FBl;q7+7;i5LBlQ{OeeMG1?bW+Otw?7NR$Z`X%L?;%GPn`QTb&w&`ucwv!VNf-t#K7;BiT28V zg}D#Y3pj>MqAnj37WhwEY-S~Hw-U7#$~lg&7Ac8h0~iv42l~a)ITRmxUpyVBawp3b zF`UfiIbx66I(}KVl7t__moGRnas%>mJn-w4@c(l3YhQ*g_0|HUcBAHp*}VG%z`dat zmBZa$3&o#gT`Kw}*aGkVphUzifTV7GWt8dHulPSZ<TexK0=mZ46T>fX;tjnsqII!v8dUP3mxyi2u>Fvk=mr3 zKdJ}E*$8Dad~6LXmU6q!eRK&tl9jRajdx#2tp9gp{3=vQ$K!Q%pHJbH9L-GepAMO| zA+=z?@@MiV}g9-8t)@f%aT{nG9T4KvEWZD!~+~5EZt> zdbL4o{TK1l@9krO;stao;m8csO3a~qz$tpO_gmr3H`S15)mb>LStp<51rTcRqOg3U zB~(uFNaCaf(tW|{8V`Q5D_B+5vL@?7PTl2Z`Q@xH2mugQV$HDExmPX0U|ZNBRM+yC z&ZQUJ4bP?Ja&*d&nT`c2Rv9qK}>*1)x73*4_w9R`wO)X5-yAnwEeW+)DnfgK{e)lDZ}&88zJBCpX1d_weW0rolV}8sar)^p z+`Jh;=sq!^q)|CvebUknAQj0i`XD_(@?pJfjx+{kWEk>XHE`9PNNA|(R zF9p?Agt`%m05`MZftO?HG5W4L;j$0VYCWic_X=(Iz}z%8${`m9>w&2#(00kQM`-&o zDIY}zGFUI0ZU-kA7>$g5llLIbdCQF&`GV+h>PG4an^yg*Q<&sUt8DvLn{SWFY;QEK z|6n_6}m$>07nkfMp zASAchmHkhQRhRWB3gg5QhQtg%EoHFP-D-2xdsdyA<}(mNbhhB!Cr_cQc%1Ml{YPJmcQw+FndD#t6+DQ75hC&CbT>U`!}4Cb~)wN zg)Esz@Kwp=bWP4c0gzph4&tq>`SGyW<@)U=Q0UJIK9$%5N6=`5u+OR~^Z@`9JE8I9%GYhHi4*jHyCYS%WX z1~6M#Ew@U)fUdU0;>3y*H#l|{-F~ou8Yss)eR_pwqnztA{EB&Bl|s$NJ4@pp$*i{3 zkIo9O%l$(oqw}ynf2I8G98SB@%CLOpQT)XtqYDvERu)WAp;~h}hoK27%`)Z76qfU!V+qP#+x~R2>yp^UbN_sj1!zHj{E-xwEqKg|33Oe zz4%PbGCH~4K1Zck_E^b!;9EN_*8?G@%+~K`lF>Z!3j@ zM6qJ=T5j?2II4m*>M;`;40p=FL%&abHjOm!kA_^^ooShRR$ceKy*Z0Zi@3O+YKLM3 zlIucuOaR6^bz(Jq)Dh^cS#_-(HVOZS_Q5=0^fSBlG}AivS5L1Vq%t9qWh$+$akC_I zj6dR96{$V6*gGcL?{k$ZQeCyb87HYP-Db89GB7S!%kFu1l-`xuN*gR>$NbB;SA9DF zqao-+)XvSz~E~leSauEsLot9Z?GWq)KhNtYiWl z4dwP_^QXG_-C!8&e>~3bjs=KHlzwKkqmLx-^L0#%fWiEzO&jjjRIG);4s*i;Spo!? z0y2XNTd+Yc8I><8fjRhvM9(=!4U|dbc8$=P7|oMYM5&r5E;*OR)=;@oa;#w#bZK!C z<}}uFrqyEDVNKb<@b)9krcRiK4P)z}J9Snu=2_}JuBo#T(bKh!K4O#E=;L+9u?8~z zd)rk$!T4*4$~ROTnR4fN0FlJIx5WkQedlUW8o1{8itkTFwh&s0`=i*80~SNN(}_s= z7%hDX!wx4^1D~=wj_R*;7Z&<4>93wHeBqUx`HNJ+p8qIVYh$|tWt3;^R7?X{Ey5@L z&~G?xMu!#q%s%&EC#7PZ??EzRo8{XKI`$05h(;9SL*d>mOYWL?N1ipXk~-}Olp&|E z4h-`d(;Q7Q=_5BWI6rMo zz2cS&l+R~%;!S3&>eEv9);*}v=gVh}KbrJ4;Q1CBiJR`CJkH1`d?Nhiq{ESY*cpED znR-#Id51}PF30YxyzgYm#o$b@-54XM-4I2-3C3Z$rjq1J zYsX`o-!wFzbDcu&t^`5uWt&*dMusKFOWzx2ZZc+Rx*K@pueu`3Hu&=>HCtaoms9>h z`luHm#qQvu)8au{=z8*pl!j~v>P1h3YXyMv%B6=g-+tL?;DcfPiJ&@g!koM1ZT+-G z+Q-#k9}P=EaSzRYkBZ=*hmM35IZ{8IDn*N&@ zVc#gO!t>oxee*9qVaIik`?nA3V}Lya7b%w%t>VY;a`1~%qWkuw;Evilk(9uroLD3| zfVAJI|3m6fm?ut?td+@p{-9c}zRv(qmTBxkoHSe=9K?r1kB};vK^7Ej)q=wF(dNJn3 zBKL2Z^PFm-7Pnk^%8ULzLQhSvPuKB_b3l{Dtsm$qF9x?yeFNnp$8xx`f?Z}DNtSZ7 zc`E!3UPmuSoSrUu@+?!w5~N*wPk?h)+}HLE{U>S_aUN_^!7S-Dw{n7v$bI~WV^iMb zog|gJ1wNvf9mbl#o>vLnzhkBRe}4@SRjL`^Szw<>9Jf7W7->8eH%Dkb8aQRQjN1|C zDd^($eI1ZV__mdi8+;B~^8evIc4(6LUBDcIUf=0*do$-<(I(815NNfO!2N5}eJat5 zzA*2KEOjWGL5owrrH+ID8bf-5$gqMo$v#2@LUDWCCllpCloD-*BA3850agO*&0`d# z@jf?YVD0S$0`*B36E5~N&A7?YqU{(O>U|u0# zLGa+4@z2|Ty|4ZgFVS+GkL4l!p$Wr)O0x-4Lz2{T;x$*bqz!R;Mg0D z<$U1{nE#H**ep-muD0ZlW0NyJwF)C6$=R~MZsAM`0~nWyKbOzmUv$%k$umCPswG@6 zIjwn=uirWDCZ1I@- z8ixHDedEp04a3#=t%Givs~t$6G`mXBqJ!FR$Hmv&cw3`&e8}v(2IQyaO}XhEQkl@j z3n`tBF2jp6>|GziJH52%t(reu@7z%>I;-$hNZ0L7!e~#(VsC{f`}KlLZVPR>inzUv z{mBq*E?{MqeCJ$~XeN}{w2vK@F_-u-DlR`xa8hlh4_Z&%k35&4m_&7 z^q_Dm>?=Z##Fs63tBCCrqDPX}{N3E*`eoU7QtAv`CKb{gsKSY|YK;b@8Li30tY(6# zivKPeZZhnO<&v8STN63Yss5<22B@mT7+d!5Ni49MUB)qhVyK|i6{6x2zXerQqRQ?| zq?IT4NQ%-Gb_JrXi=20jDwC=xQ(8E`S#f)qFe`}Dk2-Qo-WC$ON)Edx1{3}9NjJ6v zqyv%3kSdOW=(!=H=PkA(s<)x7;r5yw3tzJ0r=_j9{aypo-hCz-mRAGx`-+sQ+>QGs zvE+F`GPWKUuYYl1a-q`Na&{SuAkc9QoQ2gYyy_Jr7PO@v$Xt?iNh;SpiNEQnDiw+J zWc;&wX&3*FJnr3OqEU?>!vT#*Ao-3tQ^aKb`9L%xdV|rrChS*mBe}%tNY}ulmX+q? zu9PzMFsH)e>^C{bZRL`grfC;8$BsQDCN&pju1Ak{tDs#AuD|`)lIW`t3D`#UV%(O zjA>bMEP=@(QHb$X2SG#f6n7-pXQgJv`!0-)t8M&^33v=zs1UcMC*tCl57dy{Z+3DA zYjNL^liCOgK(hE+@krTBUv2ad6VG zA@92etI+$2?FYm&;coEoryBhiL1UTftlus(9!KE&8}H!${y|Jt3lLiufv$8#t&}9$ zFKX9o82>@sUlXjE!%%No!kJRF@4E}znafBR{9fWc7gW2KtPqqgzc5-BZQ9xjkyTz|;+}FhC)Gr{8Kob&BL*aEZ%b%Uc9fbM^Bu)ALCE z&)8VH^iRMe{qg>W`x0QX3~PeF12KMWpQ;g})ALC4;83S{I%UY|quiH3nsXBB2hV}) zSKBV1IGLUnxy47Yu|iG#o@DhEh20se*pD82N2<(Du0gR@AX-5rYA-Yz*KgVF>r zD>D6i{Zkc(Rha`AqV}_&{nNXcTqYl`0FR3G&Z&2B**|QG3%Ju1cj(w?@uJbf2}vK1 zf9Xou3|%f9=1b0FuGgHeAM5tavCY|+K~_S`b3YF5*Eq|KjIMsYK!4swY+ro$VG{c;*$OeOf5aqwch@J72h;1oNrN=q`5_Byx)r-OE)udY>yT@*zTn0Ho#8 z+sF&@RBY*2H8(bsrG$l~e^%|8y)vl$_+E%1Hjbt(7C1`}TePC&`gFL>Egr0!M4hX4 z68B-;$qG)VAC{NZ z?k!DZBJb`vawmse$)6`JqMw@D?5n5ce;qaQ*?Qgn*Y_zC?ib7h@G+J25T9~Obo?Kz z;b4v~#os|@;GSZDz{w|oaV}4GDlx`oX(AY?iw$aDtw0%tnx7Vxr!Cj zB8GPP;8NlTHza8X`q7g8zxWy2kV5E2R0b`o)(QM0BP}p?%4(y>GMb2e8 zUj)x)C_b9S<3?^O#%6310u<d0oWL{+e@u?~6+xxnN1XU4W}Ac-?I?OgumUx^ zlTO^DFO67gy^z`A8l}#;G-?}Hs5}7R%iM|pmazqx}-v-c9xbE#Qnw^1l0SwbtNfStFRGL ziw`$UIqTDD%x#%{JwQwuEArvnq}g`gwJJnU=E$8U_S8Kq{*oH@aA(6Ln(vOVY%H!= z;?c!k!MqH+s7wJh{xb6!ac30*ugB{b_6ju&6`kQ($&M7(zqm4=q+hu1AV4;f5`VV|h;FTkQy0LuJS;z5Z z!8@O(Y^FLYuJ^s6;Z(I^PAcV!EU22BSL4B=pHv)&gSqQ}*jqvzr23M$->O(YlesQXTww7T6PIgMh}hk~j5SOjDVCYOB&XVviF%1+ zHO4%AN{dRit>8`pOvkWIpUw8iTc-@nrU9%@MI3I9kn<#9^0{aBpN zbq^YZ{%B{uYxSeX?}goYB>6!6_e{ng`W}>qmQl4UJO3EPvg_5f;{L@Sy3|=mGzoG@ zhzn3|1t~aYwx)_cmgwwpRp0Y`uIx32H@)gCm#_ z&cLogt^AJ8g)TQTyc@TYBlCQFFkkv;nQHkm@uzB|lyZVmyBIwk?(5m(l%mAa^J>>ft(&sB`cT{F?1oNggEsE_pp)Czv z*N^`W*nA~xWUzS_9xl2mho|>9A!*9cPPp-9Q&kkWmIuGegMHxf{FTq9LVU~l{CZ3$ zMEFltCMambM^Arl?D+YGX5`w1kKN*Q|Y#QTb9Kc`cEB{vG+=)|L1Ztwc0GvQzHz6I;Zw0=QK ziPXowfH%esshM{cj`Y|YAY6V{?P4(p=P&ZO#a&P>kH#f?7y% zDQ6^hmOq4h;~ygU732X2`(m4}G<6n&388M`ng`|YCU;RWzMia&khk4|W)BJ!;w?80 z(B4;}FuenmAnc=J!nSrHOiF(0Nb5~$joNK(=67LS(hp{+ge~$V|Lj;gQUkm{rmz#= zWqa=&$fLxkW5_qD_rtHBw-K`R<+QFV9xp1U$`clxkVT_rX9Y5wGzwC_>S49;^ltZZ9P$yFGQcJ!YX-^yM51U$Rb3 z$)-5y5nDm7odzkzH|NPQP~)~*V9mi7oYV5Basnv;r&aEqreZ`h`hLvix8m`a7SnNa zCH+iwRg$M)!?M0!in8j?h2DH&%Ae4dS@RTs8U4N6^vhZDRGH5k{GCY&8E{ow26?rt zSCfX#2fB%pQ@^KlLxdEm;?@63THwxqL%6{PloYY(~QX%BjRk_^wj zm)5tcTO_f0c3us!xYL8yt;`9fT(t-p`)rl;DCAq`-K}6kJ%@*d%_|@`#|`?ud5z}E z7nN+={lLkCrk2Fxy&ah(?pVrv9@!Sdt+cua9(AGB~&uC=y-ckGfni)%wFvG z>#m;xSgtCsBI?w|TYd>r-*mPvP}JaYwkK6FEnOL20~$69p)iU+7thcF=FJip|DLXK z-XWzS<>41WFmwBAS$sQGG_gqP2)e6;IuEew!tb&2BpY({qj#zTjc=+BWhQ-Zk?)AP z3v>>!9^A1KarsH7@7f!wBm?CLU`q6^?j%8+#cX`#am~|G0gr%NCbB=1jSOce`F<1{2%*uXn6RgShGP)bD(^uTpc6Xn zM!^M`FGLr2ECmza-jc7%5O7O%9^+SEH}f=f=X=>D)W9uDU|oPzo5o`yx}9+%9d-{A zfl+=v_;qs&$?7bX%ZyH$qo7Tx6T}E@v+~1kH{a@6TGOv9XNZiUM5r;#QR1pO_w0jQhijPe9ZV zF?#Gj1NkHSqZ^9R>zz@VBYr3Y_AG|Mx;?5&_4nc+XaJXcfc0Pv#*uLQCOF)3C7PZc zZJTr}_Tz3zIP1|abxoF--rSjwD`oFBY~t#GW=)ib-XY?b(n%C*Ao%N5X;1c^knY~M z9-(-U`?`|zK|%{a9{-S4m%{H8Zmo-EN1>UE+NvG+6}KvpvF^Xxot1EE@tXv@*xaQm zOVMV=v*9y%;yvi_98yR^>a`5VWn4w6c>v`b_(nG7k+ndHu3y!iDYvk2!z%d5o_PX> zM`>_>C6Cr0JfUlWWHhs&A-5ZSOYRy3mOkQmmCg=8p1tm7sn! zKYE2w%ES-Fm-)Yzeh&P6^-sE1mQrFvfkmvq4<;VpN6|&QEMzCDI-x2j%DMP^NB^W3 z@^Ra3?SW)?6@5qYm4dhQ*z=@zVlJsd!?2WqcFpaq@Z^@(fBf#oJW~05OkAEqw>47Y zkokt4HWFs&u8b4JolBmqTosq&1+)?F`b` z6+OcPqpX7l1c2;&!U!~{xR14N!1Xk(y?YWFqZpQ2<=rH173DyzQg?jmrh0rd1voYt=Gy*=H}%)RI|qH)TWAIXsJ>*0 zQS3^2mw4&kNd{q%XC1bSnJ#hT16%MzPTj@oH>O|$C-x&2nemJ@Ih{*f!+&OJbE!^;taTpD}Ocj@SLWfWlGqKTCA`jf#I;Cl4$vtIP+oW zmciHy(I#b6;zkf_B1&Tk)7DbQR)F~#+RyVdPSdo~m+q|Cec zBh;|6rFi0jg^mMO1Q_S>T;$$68Z~W!SCV>sY=~(W;ZkG;I&^e*#dqnQczv~cD-E-*! z2xp?2ezO2@gx~TNL)6cW4;k55Fu(HK>lDPo>pE#>rYR2th$UnMyr+eesLE5eLNRYo zw(pqKWYU)$K?I-yY8?)D?83I)6~#=)aw0Gc3Lg$jLc?(Jb&zuBH8*_?&We}|K<0^E z(Ec+|eK9-X`?1&$tS~uCwRWC}$M4DTyjyY;}##AB`njlDA9oc)gqK^UnY^j zGp{vXbH8gF(usEZj19T%1t3=zE|&X;?t$>w7s7^ot}y^}&r;fzImHpvtcERLh(&60 zD1AF?&2>(8@LeP_2Qr#OA|p}Sz3__A$g|e3TppcO&ZHyWTlFAXLOxf@>;uZa0L&~c zcdD_wTFN9GK6s6reqoMgl3_=bQ1Vy>;BG6_#h14qeufrRAhX_}pVXC4_GiYymlKfb z6AAvW`|<+zqJ&wZk!+L{rCI)=P7{XIrqjMIkSce@r(GWZrKk%3^;JdA5cD$6>G&G$cn|dTo$%We7=(6_K4?**e-nPLt7(D0@Dxc(VON9 z_rTd;iTz*q_cXS+bvAG<^}DN;VcA%cyMMbpU7EhZEmZ5@Hu5|^+{uk5QAj7GRB1$P zky<}NhIDkb@%|B6#KKMc$EnXLLmr*#`mod$fu}=0Li=WmQnN`UEEpDV+G>!o%7!;5 z4GUk)Sog|(G;tW;lcz;*7@jwu-J2~*N%KEd58zH0+12Y%Qs5XoOl&mi>Uean)+9JZ zInbm`pl_guos0l_kQ7>~;u@Ow_>$Q)dc2$pr{KKj#utucDK1_aKLNhKo;>5TqOPuw zWFMe;lo%S1{A?>f8xo(6>n{wA^kpjpGd^zMKr^wz%ZVCLp3oVKghRSnN>aNGniG|< zJ(6>lYsiM2nPW`gZ)Nutm?nDy@^kt{X%Y{-5Htz*x4Qe*LNul_;Lk0cuAiK!vLFf1 z&r`y##=!h6(yltS6mPGx`vdnBZvMkW-f?U}<eOkqHtQAql5T>llKi<#73J+ ze}HqL9_sR}P}cUGqN5Uj0Z&$=4>1=trAilRlr?V-q2YSeddXL-EkW;KYcuMcSd1Af z13o}Lg&QJ7Svdky;;zP7J4kn2q zjNg6YV>vwF8}(KEQ0VP0fN0fzw`qGLdc zb8E&t3PPbZ)cx-{>%fB^p8(}$MD=K3|FyCXnM=~Aq^%$i>5*orfhCJ7^`bM22mCZ# z<)-UOC)iSx`?7E?T!vzynf35uzGk|orsF|O{}!fztw0LT$V%ywle86wQtG*+z>cE& z)D8v%M!zNOF~Ggo@rQuWxUD%iJqMAEeNrV`r{IC#CC7L^*9CVpV*-vpb?ARbG!a+i zsY5rf6yL%tRA0--9b-?P);c}6e5}fvU7$x{L}th7FDN?mNB9XPeH_ltHyW_)+_ zC$q=&3pN9fXx-B^ZAJzW0SWg@eV&wMJ5nds{V*c76EJQ5ShRmBB6hDwoN<_ETKV{3 zMLq3hahXk7ifpE%Q41xPrl9Joz?!4X0DY9oT(oAnUo9T2SqW`d=OOMd-J$FWoR_Ty z^3*#}`~dp!q%X66JG7%Pf>zk;hrv`xw#2qmuBSG3jT%LOX-DS>F-;i?yP8u17moMqK&2*~GRAZ$DI()DM}k-|7#v zLlT|rrQ)*h*!Cc@U9LbCxV|0vTQvhw*FB_Y*czTgfvm-ltP)t%zxU*kF;ee8G$Sc6 z*$K;9aakVvqj%M|oYhLyda&Fsn~ml8uph21a57<9zUHoao!z5XlW+-ok2T`z)ShG1 zJA7_<*z5Sb`K!PN|D4Y2+MDzxDTp3apw7J7%Md>INa=0#l3O{Wj_QS)iG1R<@EP`Z(6ix_y4E1)sYnWYwV3nl_I#i-$jdV=a6VM0GP&lUHH!-2AGj0ORlB~r)8}iBm;=-S+A^e z1I0Ksg5%|SP{YHP>BRj9kcu*<3VKPJ5wA*+!Dz|ly+P5kow&Yu^S8AE9F2jJCq|`s z6(NY)c+m@)06g!j_Yw@zX6WZz{zP}eG-|h>>jQMer8YAi>u?Ak+ zhzMb*u2^HbZZ!PpSUfrwhBt-1Tezl!xO zr}AAG9NayI9plf{4V=AR(a1Psy$bqE!hM9!31ixa`S$qyBk_6dq6bqu^Wz$JnnSA3 zU!RMn*!>nf?)m%J+I`0KpBF4B@8&_8;83oE4dcO+>ubt4IA|${J)o#YO|c& zA8taQraZgc*-}`m{@F3+)=>lBQdh_>O&P(IBS(BZk5Y!-=}JR=ldc3?)s;}6Wt)`I zMBEOnp?8KKj|yYbt|F$D`)WEEcNi?T0;dRg~!oU69pyN&^_sms_shnZw zrooGHkUk}>#3N~|s)J2#j_UT@h5vm)ir#)!>QHgqAoqq`is>qYShamn;X5VpLm#&O z%4%XJ*qi73m_%|?X)xi14s{lN#G#dIcYzvDW>LD8{2j^#nMlswjM)D zbsL=PV|B|*g=QLU#faL%w{Wf4TE!9G0*Kp8w}y@EKE`bL&E8<8b#ngSYL=1d?STuy z8a1Ap?ZQyw8%o_L0&=m)3d8+m&0?Z+<4Xu$RiTST32;UHLw^qG4>XdThqtiWKODI8 zqe?NIE0B5rZ7mxv>&+^|OveJjw0;WgJ)8Pzq-jg3aJgjy$*0BXY$+OZFze6e05_yN z?iry$>2sKd;jI>7kZ5Ql3+{u~3nf{v{}SsTB=n!m^!6s;Go6yZR zA_mueAv!ld zTlewlbc1hy`nuGlR#0K0_8$f($`TzqAJeEmM7G}{9T!CBgU4eALys#U*5<}EA*hBAf z1#Jy};&x~-9m%A9v|UcFTBEl|ZcXFBSioDgqb zvxs@uifSfwbdqt^bInHE-f;Kn8Z;w}V$>1N)J#ve4;=S3Y$V0pU*AnU{4};*_uN9j zlI3V4({cZ5U(oY*y+?AWdknq~-ZOTFl=(&7eEwl=SKvAST3x?~5FxS-4rgkj&{AzBEE0rt(%xj&14;kEqM=%V+cd@D$0V#ACU#{|9ry5rZrVnRyplHodTR zK}o$8TmQ}-U9~6(t`f+S-Re+th=b!astxte(bD#or>=oj!m z>1S{M{|5NfCv{p4kHWQd)_$*IhJ5g4E2DaO4rTSwg@`W{<4dYM9gV8;4qJ#+ z^V_Z}tCfuUI!pxH>L2G;YHZZ5hc8za3pLc`mboTOA8GwE>l=l?d~G!>z+L-ezD`lw zw?V?$o?GI<{hw<=r?smB=!&~aqzy0iNm4k%gScJ|en_xk%V4Rot0B2o-Zse++5DS~wAy#(o1nsgD64ngTj=tyr;r1#z< z5~|XBjRcSmhTalh+~?kN_j&K^d(ZnxNV2ll9CMWK`^K0PWVh>{G-c~$hGHvg0Ba}> zX*Wf0uDRO!yWiFpf=>*~r^d(VPZ^vXE{z93B;QVRC7ZiOU1sAa$pV=s1DcOF@Jmb3 zejb8b#Zxuy20Ba^0xJYUX^Il)Pe9Fu`bWn#bD>YNt$L-l2%i7+R6-Fzx-X2}bVPP# zBq{_eyuNADl{K=HV`Q~Rc6gmQ($;78CPMKZmp_*+bCbFN*%Ay$X#IooolOOSA5Qzk z(0&11DQ3+fcjWoU8ZSo!Ki1JRVqxZ8twq2Z2^>=^^7g9gHJSv4LvF#VbC0GWB- z9P5AF?Ig^AJeL%R4$dppgI#|Dz|6t7F6*(HuS8mG8LJP!+}Kf+v_m_hA6cQXI`!9Y zaUg5K6=}oiT-S#Fx6|dr>D?Zz&51NEQbVola)pPUbt#W3T9s#i2kDw8y=MeubuXzO&mBQI%1A=ohHKE?}{4vNmJlsm^ylWRDYrETnJynngUxRB7z z@F*G+(56yWPUn=IGBty2*bQB^qFuZ=K@K=}A%Qg|II6rlV2KO8$vF=>r3<3i$_zWv zxg4d9u653N{$71+^5ufWX)=nzxflF%92hyw*CC}Wk=pmgG{n>N=uvzRI0>>kvP%EF z!WQSR{v8?{LJGHMQML{%4Wwm|L6-gcxsuv4baaji|5=<$RX%w?O7PjCg2am1_|wBr z@8}dF^^9?3=}{OvihJ%=LFnL;8sSGl_647Z?B?wxPkK4sK`yG(R(K7Z_n$-tE23uM z%2XC%smu{p_Wh4OvG_JmMpn8n67oYLW8HhtlYSFV;SA9EEMJv{ve)8%6W>p^3{#|6 z9=%Ux!~Iwd#6E6L!p{g@@oBp_^$9WE1vzD*6i= z0A^>kLszRYj&YCcEN=ihepd9l^(_7pLo0W=E`nt^D$PyrW|RVJ255n|Y|0f5ddJif z<$k|rAqd$DT59A{6U6jc3=hKYWh@|fet_D^~)xH5B{ zZkgWnrtVj0+_qwb)ISP-{=|v3POPLcvlN}saz}gf?f8s~2Dt-Jc@fxPKIrgs@={OJ zdz&@y>zTrR@@(=TMDF*~EhVPfeR5>8Q|g(qz*x64Tv}%AbAT)TbG9D1t%Of$+`LEz!^hMSDQ)>z20)xQp~B3eR{i*<@obkkp7{)JSR&i%}nw!UgM@Q@)0Z|Erb zn!7`e8CntDo3LwC@X4RmEJ&^lTOM1rISY03zaVH^ay!;UglFMY|8cxp^!sHB0Ra*l zdT5fpt^lY;wVgCkV)8alChkr$wBpI@Z+t}sL!WX6@+n_ILC@ci9F_Dhi^N30n~9H4 z^Qy9;G}}m_n@E>BN!uF@*Kw!&6mVgeT<`QHGDPa%vkYnSfYg2^JJ1_`Kz|zD!{zN_ zM8x3NbtD<@T!igseacK69C?N-uML$4^nr*>KLR^ymlmlbOHD zkTb5BZsQo~1A0c=5Ebf!Gz~R+(P_WL6-fG9WV8_`m~`w_5%`5V`N1*aTU^8+#DkN? zJ$*UeOdz0{8AU!L*O&SVOfT>yn8A$Mj5RpxLFvUE0n@n3@jtA&NNZ0sIQDESpg*&M zt?%Lo_oY2k7s5ecIRMfV7Yg%Vqpw|Yhs7aUz2s%IhR5+A#2tp<$XbOVk|9IfZdND# z2cZ^reA@K(8oV~H^y;GQCPZN}ppxpk3uvMhp*^ZPl{Wc3SWaO54Unn*a?ca3d+x3M z60R7?2$pB+Snt~rjqgLLcE`LiV(LHz3LvCZ0+g=e<8E~q9;uMW5EOr2YOM}D{K%N< zhNSf$KBTeicAxuXG9(DuDP`V9WQ)JQ?9`MDBm0si;@&Mh+=W?5RRvWlh`WcM*(_Gw z1~j~qYH^ynMo4YE&o3zLS?M_VnDtzPP@=(DUPM1RC%dGq2lG6f?h-xXq>O&XYPa`Zknw$6IBJ%Cd7hG*p|7+>m!ver1eR)xJBo~Y%-@# z^ygOE6$v*z58?R~e@WCNxpA5(4JEA&Jf| zn&06Qn%Lhm$>^mu3_i%>BO~zcoL*#-yt{rUFkqayie zx*Yi^hT?8@`kZc4a19FIYYcVSIG$@1?ii=snKnDeMHnOK`h66V#@vxex!_ntITlz) z8L+9u?K!5z4feL>1}oun*96p2E|+$_rs*Au7wA=@9!m(fe)BPoECDy5kQ9D>sA)8n(IG zq%~UU4<5in-ONC?7|Av*>%qNB!*yG`J!QI8i3`8&TZcjG&tCSBqyp^DG^vtMq`iPe_*nSCTH!n)#taWlg)(|8D8*=SenmDQ>$y}1|$ z+dk>VL$OsV7H5>}2cN3(h;OjERN(&Vp<`T&iA~C`mKIA9S1?X2x6iclw^=LoRbWc} z(7XH5DyrQaE6XWbrKSYgE$`IjxeQUDq4dIMEV*xn#>dD&x;)qG8yyNPgXE3O8uQ(a+1qPVwu! z!*(t0+=$SOOQxJfSb;8ueWFxbK{Nlfy(YL#**FvQsk{#|Nle*X*VLeNk6z?qzoEkU z3PE))2jRrzQ(Bj=O&CW>DY7r}iCg~{TP0pL%HL1)ZQfG#bmI;6+$gO+a6k3(m8cjw`I#ZZVS+wWV|-<_40VUB)~j=>Je3! zwgf&xI3SD1EEZ~AM`_v;ajNjg5?>hs{a{i?neO`e0Jo6bw`+&uqzw2=;|Fub^EHif zjtQj2Ye_A2o}+fkSqC=D?DOme>afVB`HRP?++))`A*ANA_hD0Q7JA%l%~7xCenF;0_*K)* z$v@lJ(2qjPl;x8oPr_5A=r{mKnM_nk&z;t7x1^0n&x|MDvoI5_^i{}>gQW*PywkDFHCd2i4 zPgj_tEG#x$qO7auo^H9kW{GDMEtb2nf?56gMM;oJ+dt3K5Fh|x(a*PnSGiH0TteuA(J-9sh6ivUd5bse~`{MiNUBX>3bK@&Qh5~5Tzgy!HJ z3|%4hVvo-ka+%@kun5kQ`)rS23+-;VsE;HA%}>9KoTl((;8>ER=v@n#+denGa6|R` z^o**T`c>Dg@j?RYtuxOO@D;ikx*$IuCq`2GKkV1{qk?l{CuE!oKgLZ%G-*d)`bQ9K z9}kA_Ljse-kB4h>zRZU_w5{_!NG_mAk5!@=zq8^L7X8JSNU0hYj$aJ^yFfmwlF#C->0q(++5E^JU-8bebyDuesHde4w+% zav@E7kvVzGN=8)sogbIs9xCL*Tl%K$?|#dQ;SD)2uKpz1hUii3aSA@USDA?$@ET!% zHtZCuo$aN2wRrj5xCZ-K}8+V-q;uK~d(D)ujr0kkB;%otJ56%lN<` z_^AhYnM*F9-;0mZEv} zwF&te7`MCBZoGi2G#d44` z(_sl`uV385qhn$qkxfdhgpdayHz~3m9D88IE^B$XysI>J;jpLYO5v2BGey^H-HCSA zase7gbvz_cy!A4uI|j)h^L0EYaVF5I|3%Q~$%!{oUE&EM;j81GqK5xy zXDz6?=t?vu=`k?MBbDE<&DN0Qp{;Y^n7ezrM2{5m_p{z|4{dl>QrC}%!(Q3Y+c{Na>(4(ua zRmpizF9IIWONGJ>SEkzc9h5^m8bdPG_@*kIPES!T{xNFg}!K*Dc_-GMmaWh5uNDJ>2{Mv>J zmPdKHmF!jyP)2m)S7Y5LFKqQtP1Q28Vl}>_c?dlzR&2>5Worz+#)IqqHC8iLk(L8> z^wFSFnsKJh5!rh`zJHsw-?i@%90v0L^MA3vnoO;-V9^1-LlU1SAsL0%MRGM+>SA%< z^Wv{dQmzy=q(KkjDI$S|Q{~1m{M!}<4WY^s`44`1$Eu;;KF;|u!UzOBRJK$=={W1? z=tR(*T1EOgEyP&VES*QiY3b{R;*sZp<>VPf5WnV%3_5hgucZXKp9x$%ONa|W7!7mnu+I-Ygtgi`9Pu zxhF*+BEaDu_pS{S>WE+{ZZQ;h9??bNnoqWZ{{GJ2lKu}m)n}N)8oQVyA|$~&wmv8j z8kuqW?jf(+M;CwyzI|>%(0Zymlf;KecI$khqmTjyPAMt#d{*qn7+G%QM>d%)nmq8M z7OA#Gu8ODmfiA%f42T8g)dcoHgywrUz3d22rBN8DvxZR>7ynbvK#fo&bs_!0*ef;tGe-`gwyp?@V%GmgLd%N$kHvA%-&#}{6s9Mrdq1XG4)IT9P zr3BkfjAhPCa|)6aY2TZv1tMnt8Vifkk+Fo-xWcB}SyPJZjUn^Y5AQ$QyfJ334ZGBCzC+ipLWjMFM}1S4WI@+aHDN+k)l=8jMIJMK z%&(8+F#Y{mZnFlvoF=PN4Oe~XoTkdJUkL0~Qq-$Rk6(xgqC8dbxjO+M4V9Luy4AKHO(|VQ#?V&h2OrhDV zaJ7}Sv9Exr%}S^(JE78o)Bm?UT(^r?5wiV#1skSp{m)#>KFj(sh~0aR74=iM zFh=K~XqE5u$#{3>%A-)Zh)TwO&2NY15M!@T5~&T4$=Qng;=y;885Ub0&Af_Y?xmhR zSLAL&50y0(EF-#>Nrkb2%3Ivg|Uz5YpmtOc-ryI<~wLDeYW|- z~1U2bb9q36x9w7jU6jas`ds-UO^EgqCa;&woiJ1}9R{Ry` zzCYmH`qv)_V9hO6Du|0oGJD5h)ZxO1#`_feS)`0hb$%jl9Y44RA4t`#!chz&t^v%| z0SxHulY3FUe%d1vH{SL4{YTFu{(TzZX10R%ew=K) zTHy&b(Ip-ras7)s`WMNMpw-`hha1<2@0;Y02(0NFjpeR_|NcRBN&k;+|I33vB&?)z zYnC@_RD8E{t^DGzPVxW#6=RPL_DIM=!zMphGZ}}mF#TTJVnPW=wdCGiO1=*}JO817 z(vO<^HZTBaG~h!0PHX;RBC!SG$DK;(*lC1D*B|GbO6EYbMd_Wk-lhsevV{J8to(1| zxhUwT3*_?F;zFf~Qf{2YAXIFle=p?k5Y%eIgI-;=cCAf)#PdPR(2)I2q}bB|J|Ix8 z?OdB%DpR+})~4A8RZ%2|t{QoaCLLtl{h|kPs#f>50kPx(*eoZNOrjNBRuwMG^&&d*IlscI)OlB0=`~f3}q(@Q?$`%thed} zT3%@k-T(Ur`j@=Q*2MSWlD{<50t$s@>m3QceQ9l@ix>~3TLli5cO&(2Qk-$5dO z+1{;}0T#%bL@ofLQ#QQAR8S&JGd5L9utcfi(ib%GUL9j8Y_5RdQFg*Oxlt zrzdb&4Bec(f02Ey_nxpo_x|^6CUAFb2kP|x3(Px_DQMuqh##s|o0rVx**P_Oz7_K9 z51)hD7R&atjPNAL`Z3LuCF}qQMYhsCL_-{ai9EC2oYCM_T;P_x^mR(sKt~w|X4Rt5XYkI&YM#rr*05fJ6E*pUSVO~)bH~S z#z7q_SD9iX@b&wtz@^PF0+c@E*;bpybs?N8(B)VI9Vm}c@JG{0AX-_&pu&_xW3*`J z+6s!mHd2DLoc1^5fsXfbC175GydA}&$_v!6{E<%Ajb5mvqV{@%qcJr3-9t|7FWy+C z*LWdJ$coJ`xQG$@_c_soD!|Z=O+i~h(F(!&7t6{ga7!k@GL?CTeevWC_X_zlIN+(h z6vL(jQu%As5ehof`%lR|XOzmt9dh5+)@FjMHf$BfHJRM|H7gs{#2pun(7{HzP3*-9 zXJ07DlkjqmDa`5}T%jfyIl+9J6L)Ch6~hsF0!qibtr# z#c&v_@gbsK0tw~L3SUL6e~aCiS+_hY6pnUcUaBRF|1PPkZ2gEpNs#c7xOSUu#6_Fc zs|7_l*c6KHju&aKksWo?-n&;4(Aoy*zDe7QtMNw9h;^?QmipW1%rjyCcE7MQfHmLN<>Xon43lw*#{C z#ZACH9(znn1>6I?^$H$k0uZiT1M$rWD%jE}76C#AV6P=;uAGnFe~1K>ps2NfbWGr^UT;gm2vrYsYVu+WkOzf3*c3^b8#X^m?T<0A;v$7yXGG zs7OS+Xnd8G9bu1L!p5ITQ}uYPHhgijwPD))UXp|~OnXc}?p$>?(i_MD_OOoi&aJQT zjUJwdQ!Cq>Uv1t(yBvbDLK!Vkt^o>=(~e~jTC8<>A2dmWXyh?u!uChnpf2;AP`Z@B zIv-RV9@RU(r2U+JdlXgu*Y$9kN=|u^b*_MySBc$9Jr{3C06)KSIRupa>PR9hfReP3 zL(G!Bbo!kr`F2Naag_s@yW@=5Kd?1E5micMagIz0KEO>VpK~suJO#d^AlZ!~I_gVQ zda<1mAy-3MYLGdRD0edV*#NuSgM`ICrJTCFgBE6Gx>+#=tZ9uSPu7XFZZ|dmPHNsp z+yACCv&cmjHxJL>l4DDG00cbUHM=N26F}x=CMQ|68nnNK(XB+~@?e6`h@QOt<7qzK zJubCGKj+^|wfy&Km)c)*tNdo%aFpN9PEZK1i?)o(+>L%$AHnl&SjF0rqv?%klMwO(R$Xt3rMj%^Fx%DlKUFZ7< zP^XKtn&R@@fjzxA^s1SXz^vA9ffw5yWiSjges%7E4|&bgYk@{_0U_r17p?ZhI6`LJ9hb}_{OEi|fRHs4B}eYz&4AHmQ>O<*A$1y}O7 z{C)#HR?h}kTtZxU)P2a4gf}eJn8yH5X}$I(wy4D{7A$ zIAx9{hqz3-Sc$bY6MfU4d@#R%lKqKxUhy#jFaHW5`ZHm*M7DX@HN$yeQMN4ElWyZ= z#+-6HVZi+BL78Sn(}4D~D#)$w$=8(>EOC>(|5;grTTiMKIZw}>RFdpVcK;K~vwPqD zE9rEz2I^oH!Pl?(+nx}n;C-c^`QH4?xpvuDN207$l={Ai9;3xH6uTrth zmn^=`EEBd1Z>UK>tCPw@?v^+MkOwGBw2PF{lMZ2uO3fxL11iC9IUwL$EYS1qP#5Yt zB0$^UDG=yR#3iRa>Gv$Yk0quPJ^zpl&=Wm`ft@A#2t$xheXGv8x^_@Q96Opzddk+N zd2x7CD3vyB4nf4sz40muH>x%ub`3>@(o8gG#*S5n!$_QhT^ajC#ORc;ZXYWFf$PyO z2=_2G!2Y{i@goI2x)A-cK(nhv-q^DG{!q6TYw8o16=TZ)%iYf?=GI@$Vz2Z3u^nEq zXYaS;HiX2PjoVPW*O2RB7_b7A91VcGJq65a2gN=vSbM^_a~We!aqX`edUnwP2L#&7 zIJ$oG3Is@rK<;BYmy@fcuEDk+y(jAmy8{=E)l`W&DS3wm$ffEY9m8wL;v2QeKsAtu zVJ}&UaGlSj#PD*L4`*$&t=)^VRf`vqH0)p>>fEni1>4?S_u__3&YG}v)G)^{fL$d3 zM`O7`h^|a#l_SFFjj2c$Y)>!G3V>S}8q)^QH&IZ^G$ z`MWl98!V(p06VJCzapYtQ8{n?E1OAsUCs}+G?>K*yCt@s_I(*Yu|!97WOkGJ=4G9! zXn-lN2_M_P5ORTOQ7L3(+69 zS#o3d#3L?ti4+13-+ev(`y}jN3(7H*=jI779QduNuc8cp`I<{U+1%X!wRwZb{7cb6 z7W&~;=Y@tiXj?##$V|T~s`LK$PgC^by~;uY;a>|cn}5i@{*wIU!H>3HCAJm{0x}O) zvPr5EGmV$WHT^)eiQR5(ht?Xud7|nk%vP!;&eIiq0PJiz!s`{8V-`i}=_8T}j(*C*I?fRDDhK5IN%GQMV)Y@*r%eWNqSwcr3|8;GYP8k=!A z^W}rccaaB)N+_eIhsySWeJ|Xm%^7HTCG+V3DX~%>qF1U+>3}Fi$&-B~EB5;dIXa^u z88+NTLtxr-I{VS__I&ri6r2~k9cUFefhwR!WopL)b+3-LQJlPf8dqV}Z18?MkmR#| z>{caezfyW^CZWL(L52JF$_tVCQr*5soW31rhBwhyk|#$#hNc zN$1eEJm6LAAWfDId*dcxi${#*q_qfKjweIGjrmTG{Kep;&QUK zyNJQw*VI{N&GOZb%UFS|gS(Ju863yVS&$|Gp^y`3uDGH+K8dJ2g|R2h(?~rRBhd=$ zX>j7@r%Hkh5PCuHsS?VklbA56s6zquk>hfMw=v4zEl_BUyvXaAz6X!k9hUu~cqF7Y z4eq6C#F|<|HA$I`%5vYjK>C*7-*XF=16jo7#=dGT68hR@B_H& za>fKYC4K{%gigz6!zE>p)`fpYU~69mZ~VyV%9Rb(&8=~W*)Xx-T;d!Mi)S>7cP3k7 z?T%pbx2fQ4Fe0;0>nLkElB@79uWK^;SiAjx<4dCpRMMBk_i&Kx_+&>@K6^(HLR;_@ z1pDAO zO(xB8+|d3nx^zej#Hb)e4pQC#o628@){wl0SPrHYxjTq~j=BTntHTB4D@^_5!WZ9+ zW_7m9FMjQkbM{B(!ZNZ$j@o1dQ5ClGwOQFW7KOFnnf`h`8h4sazKHoEo4Z-t2+^Z0 z17wPcM$8dsu(fPL`g6sI2OrR#S(Msg!AOf}&H4waLP`^-Si@XfEYV<^hi|}1pGU5u zVtxcQwTr=XLDyWi4#j)q6iobv0C{Nwv$&sZq&})pc@~&Fc|0jAKW{oGhxaBos3)VH zNk3F|!aF2F4OA}QupI_rnq!HOsrQZ($H z!a6z8eI&S1MrNfWmwa!hgeK8IVEQz(g*v^tmN76@=(eai-&UR(MfzJ0@g89N?peNm zR9F%HU`4=1|G72~uSO7csmXoM;gBJZ^C~Prrth{&EL*jWBgko64s@|Rn5#ZdoBP;3 zq)4@ql1X)&9HjjwuE_0DWAsB1ZCtw-2}sGHsBi0%(sb~4LO*Uxs#Dg#O_x7GS%Q-G zpS5JD^uB#Ax3rL#>(r>K;{XNR#+P;FE|HhF>CT0!gck{^d^?cuW^T@X!FM|p67*z6 zjzF1xM%j-ruML)?vRZ5V)*wDmzTNw?(4@WUW# zk2Z5XRHvb1&uWWQR7vF(=H*Y6Vu}zHKqwSK#tZ~z=qZmb=We_zE$ZY;|1?4x$J}@C z9IKi9x+dbIecJSs1K-Cl?LPL2?%V;vvN1XndnLrVz{7i^ae-}YbEm_Va*7>DUXJ5{ zP@YQcXw8e`(0$ne{?u|U@2Wnh`UrnV*0JwGaqKhP|M?EGm=PemCkR%=i@~nG~f~;m2+P=YM z9``3ZSr{gq1#(9HqeoKl_WH{*uRH0sv9^$IOQEI(k(F4f{3T4bGTy3gS>s!dKYuQ9=1 zkXYmw^Bm;Sa|hJZsWysLQP1}=(K=BWJ&E)m?Hp4AWk*ADwOV!G@xNiVE}+ve=eV%w zcNi_9EiGayNG~$JzL9GYAO@Yo7nAoaHMHhuKbKV3w^|`?fPL>A&29Rj14^#$lBbh# zmkXUwhDgrnJm&BKMi@0ZvO7FjBVBVcV4gG5V&{14!1Tm;NY_K>-P`lzT$^n#sF1ao zoH~8FskO!~`#lCxC33OcaJB;DvOa1Mhnv$9E5~96H^*T>2v7U#?J>cC%m6o;rF%$= zY)u87RQG+0xRoCd;>LF_rLrfoF+Dn_Tx0iQB1(u^BK{7_#-V#}5S<(qA%U3&0S*taBJW6pl;l}0Fzd>SX+ zvS+ep&FBdVz*RX^R?W$_06#kjqcQj z@fY*G%0;_;`$T7mu&pl!ftspTbhySm_}WY4Zn%jSIRynI8Am7lg-TG7xU+TEbSsZm zRz?Pq&LzLy?a77FzCvn(c{)ag^!)owUv^hs_IINKOjA*u*b_fAiT-T}gK|0-_#6BU zDFchtGj4@>_71OeeboNqb%pl{rZPg4-aYQjVEYbwAvBN*?mBFT9u2sFXwpzJ(gT|1 zuM&PkkE6@fXrXCT(>|E%C*Od62S>+Sv;$hoIudZbZMD)JUI!zKNz5*MVh+|z&TErw zIVD2}Wa7gbn|8F(kYW&uz`|gtzA^y!G5O-NBr~Z8*^&Tc3ZUKG|GMQF${haQ?YZx< z3!;)?UftjSh!I_LT-$xUzuSe1mYmTDP`FPH2Lg_@<|C)u+v^Pc_2pd9u3pQRtgI3C z-R{+NNaLv8qe?bfD(;S3BHFk2EzaS+TXv~ru2=5(l&Y$C*-53^d_JE+MF_jSNUnb) zBQ4Mv`+ak6ca|>DB)jE*cq8eylF^L592o-V+pi|-w4@UHc%tT6 z_hvA0XW7@$n2{u|k5*$(fwbxu5@4j?r7B91nj3N-qPABegO0lHJRLMk=j;%2iu6`Z ze0zaNd5cbJ*hS4JKW5*`E2NBYA*_Y!8^reIGkZ`G(gcAq)ymG@tt>fMymV94k{d9P zqVmN##s$lQu58Sq!%x>~^{|YZQ*Sr(M_6+qDT@9%l3uD^&$aI`BSQ6k>h1Xhq7i$*I%54b>pKJyDqs_YdE$?NSU6^;02D(%6;`nVhmio&t-PZ5O>4m0of58?bcjvn7f3h8#B( zJ_eO(@+XOXHDfXJCEs>`B@v(K_I)P%ab^GX($~08HZGIuZJMfW*ZHd)Bpv3s5gcBZ z(!dAy66e+D7N>$4BKC~2l%}r zT*QMsUv3JyV+2;#lED@T+OWb*r$RA*N*Z1WyD(Pklba-{aqk^TEvMZN$;s& zDY|*6J-xe>OUa=Y@#-=ZcT5o7{746_e31)%UhY)Bvn`*W>I8Bmf-HGDJr8h40Hn$3 zu7lC_)|Ila&dr*qRg!dXc=?SX`k>+pkHA{d{Dogd3pm5u2{5N@S5;!06KDC8{yE9| zf9%(^kT}04`9bZ0owkM*ueth7^(B!NxpbDKtI5^)QR^U;*0kfgs^v(_W{mQ+E zXnau7tbvSK@nL9FkVPR6>;JMt{)LE-{W2rKFqU9@Q<-s`%;4Q70asM~*IZWTb3wn` ztGqGiN$S(hDB%wNu{GY>b(tG^ifw1_7DWqs!U#A-EnXd^$fbQ=@u$l8ohj)ee_D6qGG1%ce(SM6yQEueVGVW8TwxY8IgZE z5zxEcTc`l-gc{Kj7Z4B?HOlyl)@Tf`S#@wA;DMePN20^2TNAy(=e)w0&3yHsOW5yR zjBV3O%5qq(32ARX{%XnamwQ;&+ZC%K=y)38Gs|$kbU|h8f=hE=VTd9N8tB%Mx3hJ6Zi^-mW`*+_${Y-dVtxR4XT9saLrMByd zuSbcy_9nndHI=*0DvGLJCX<|6{zZH6*PD!7{uih~iEg9+x#T8+^@se}O#=FsBScA$ z2IKf_JJCV1{mW18(e&-8ae2vcT~^-rl+Rnpr@nb*1$cS|6V=&poPz`ksWs(-xdr84~r@mgQD6y*3)WvTqJyk!r{g4 zztLo=yCe@29RzefA8vFS70Q49>22G|`|u{$X{}9!ibU(4=-F!juV`O>qbFZ+JM1-a zsAgrY^!rDx%OpYvCyrcK6|5y@`)0&08>oLZ(9G?XhhzEd92@{%US29q4Gl`+^wed* z-NeL1RL_4G0R)Udtv32d+XG+mx5>r}D`5%$xu9t5Y1?yxvEU?~8G!wZhMl0HhZ6SP zg^y%EwHWZxjNR(iDKdD0GqTMOs@M=7_4J#jZ;RZJ61N=e^v>=XPakb+8BtsFOM4B5 zoSX@j@Mue&%}X|(H$?FSZcaR4%4ZbW#t{CwS}U*k)8$^5%3D{@%T0~E`u`zU8mm%k zA#@Pb5uBpT-emf~cP@%^UvJf{0s+b6Yz>xnGKg!@t;`*@Hj882=-GcEfD!J$2 zpq5^ke@%1k;cFJMmqrp-px)abd+(3Zgjsh+I7nHtR{wPU)-afL0$9n=gWJJ8X zM3h--&Hu#p%>}Sei6wo1KCI=xjm(7fU%|qEnjX&4TB&VrZZ4U%`xcvHy0(v@wl+49 zaGW$$QBm<93bl+7QScW{hAl7LhF)i9Nw~m&I(e3f+aE+iPVeF9J6D*~<=NR^b4|;4 z&iwW}hm&yPpmO}+OakAFl%X=nTlLS-RF+PRO_nIbQ^|rQ(58~?_z!T1sVV9G)Enm5 z$5&3NBIJ_o6*qM@4O)}Cwp9q{1<105=**}DJi8chbhkCORIT{*RaSP%S;POcMpZV9*DW%CG^DHoNE}Ee5zR;RGxN3!TgryJr=X6dfh=>zgDOR4=D|$DYzdl<+z(F@ZaPch z{Ak#k8rq$(rBW;cshXvm%S{U@~S(F;dt7AP*{JCDp4o=Uow#Y5(eB=I7sO& zHers(iFulz@&Wpznd1!0P(9aVxSN5gJba$?{G^BG7qjXQBKi4-U*{ZrMXFS1vtvJ$ zA3OM{C;Y(jYs!;PdyOc5f=H^-iaf)zG)(BaoO}-{R1cq)mz^YZa~KlM;rap&-aVYC zGSSE{W{GnZyNy$G_uanxThe_f1u0Vj`${O4EY&}M*(TnQ=xuEaRQ0;67kKU2dX^K! zkIogXOn)>zor^F&+2>s9kk9vqJ?0zRAnzOgDvOU006%9l8?~zQ?oFDJI=JJg_#!at!4(>Fq3nA;?_3?1e@QKnYiV7xi!&A0$mc*7?%7hw;;{zQ9}_hnL1 zV?Cv;PqcwNCBQh@Nij5f|HHoXypWkV2sgFgzYTo-0fTZprG#bQmmH=J8n&N=$9RXQ zyh0n8^bluUnOZ(lROuE@&V7I9#F?AkRqvJw=nZ?^ zSw>IT-;1yQVS!|3iFj*>zKtM%Zy#obBEO)K>~LlTL~-uv)bov*SSu@_m_kajwN-(- z;q4Pb9)!b@Tf1NyS$oKT ztK&-gIS4Q1sqig^uY3i0;H3u8IMC~^vUO_p15{l7ZTV)`@WGw? zR4$l=Y=}93QR`W(-r2P~xxqx_>=UWe3f!o@&On@~aPf*2t$N8AR}x5At?-8?-oYf> zdGm=pt=IQ!hs3koEpqg851-Cl&u_h;-u)p!^$1uPcFF+3AnOC-Zoh6rI!JPKTwe}% zQ(dhyqo>=FVVWHj)6XiXgMH_?>yqw)SMjUM_K{@pZHl^Z7()sN_*su9HoGot)6sebl_scgS=-KMlwm}uo6G@WzEIN&39kfj?Y`x!WDyN z4lj8Cfd|!Sl!WD5IGvAW;m!V#M=)Fq%MtMa`tZguRO%gjl8f4<`#6c)-wGN3JCueq!Or`Jl#pPw*ib%a_VtpYdu$bx%vhl%4Y9l+^OyUW!88MhgjHxWUT)%q@QK zJPdxko{z}> zIO_}`ep6YKtdgD;?Bl%8N`$uuYbiy`(JO}f@@w9WuiFtaA<-rAcfixglxyI+b!>B; z(%T*Q;gvXd&g(-r{V$W4m06cOvqF6jfXjIT5=yflL-Knp>8KhlReLfWdqq@>zSDtC zLU-V^rlf5;T(6Zb1=Mld{K4hrrJcSXD)ybw$qnFpBHUqFSlQ;JM4qJf3t2Q0?E6C8 zZGpF&)f{@_-Y%+sO!IHG^uLpYX01QNpdc%)&#$f&i|Yk}hoFvE+zR6BJ#`c@4_(vG zf`yq(44N6$u|8PtsD?Iwy#_x84AwZC1pK zI-gcFE`E;Zi9}TAyJt);%qTy;!CKGuvzTqAmKgiIOHME_;UjhAi{#e0c;l<3tY=Az zgjMtt^CvDPcufJCDxQwkSL!=_zgjWBYw5#s6I_J*vz(rm#|`4M!VulZRnUaE=@FA8 z>&^f}_KU;FD93Ij*fGI-Zg`(^AIYsN&P{&0wlMjeH{f!}1ySo8{b2vs__yxL@?F8v z53G32hn`U0OiaPq71P47yB7_+BxZ{eHCv0MKw9pxyxE4rk^X#utmt4w$<8hfLca}% z_J1WXz=Dg5ra^`V!<8L~edmi6@rzeN@i`|9TBje>ny~8;3_wW-H5c@9`%8ptGWvP* zHcsPVKX{5FBng2`=ZpV8jJ~H4mbIwd=G9moOkM*o)t^2;O(pdiwTk2gb zETO1*rL`v8SylnU=fX;;a1_$CrCV2^e*fszF-sJ2N}KvjZa(%Y|56F(0f6&oFW%}v zc43?MXUFw>(~orVJ4ATTd?5P=ev!RM|IMEB)iT*GFPf4Q#)${>1wjG>{knDX!P|si zIPnde=FRjf$Vam(S>>@`$VML?gkP{Sq!*R-8tQU&qs)KvJ2G1C%Wqh1+fmM%|0IV0 zmn9}GSODQcOVx`gebY0&AHNJWxJ9MQ!e>A=>qo#{xEEE9!mons;s!^JR7H8-%TK0srxribN1PXBco@fF{wc zkMv^}=xtkEQ6a$@?!g5}#cQu*7N&bW-neK>b zuL6YswBKrTDqB9}z;Xiee`!oUXia=m2zPknF!#Kp`So4)25!_9^)Y|M8tb&Ysg=@O zVj3Uk<15SbM)lzSx?s;V<=+CbcP%SFJU(8uewXoo33t?ozrZqS~S zY?T16)U7_Zp%*jh(G0hGrytt>?p%#MJY-uM_`-1aB?%V5L!_W?ehTpF9-wEx`jf#V z?6w~+c{?^6Z8ux}zUAW$d%it?#(j=;yO#xug2q3w(kyLaM=u}j7x6KlBfaG6()cS< z{8d;cFv}hjK|{up42PrSp1t5;E#7a<_B)?1sHdpR1UNKm?+NdOHZoNTqe2+yX-Ueu zWqfN}mHi%3#CDOh+UATLr-o$+#WAP9HLIl;vnd^nk>pA*u|J4oV7$0UAE15eWrMWk zljb>)_;g2j$&d>i<1wTGF9tvRE>$OP+IWZ?SiDNl*KhSM@Fzac5xpgr37^2f$7sdm zV5?Qk0=2X*t)bvKGeZH(Mz>slA5r_;CP{{vQe9d4Crf-2nLGPs-Td)+=2=dV{4krI z%x$&_R3u$7;exEi{0Zs5rSC~LbNXx$vELxxWH2IP)$M;n)`Ir0cUS6Hf>oTOaV|+~ z=A560x?)URn~=JKH@JxF{YE_g(}!hXt{7L_ZANxabCz40 zY-BG~$3zonlmftNV2`)_B@i$7y~|}cC@Yrk$R$R62gxKAXo;fRH5yt z@0Gu9p<80zm$>nOY3*(^<+a!D5jqQgd?g*nAKHx;ws^H$-%E2aOyl$iJONd6F+(rh zSr0PpQ`WqF71*JBqd^J&lT!B~a&W5(v~s+yB>XT)6+4%JUI5c^Ozd0W!q9tRM1*m# z&-gtb+mg9Z->*5LC%aO&`<>GswqKq*`(PjTmq-qBz`p^l-==|~fhS|i4Y{L`p4Qbh zsa4r{5GPelD&h-A!+xvhf=VE72kB_k_g0a06Ce zm+|S!C{!ISN=)F!KGK`UXkx?A@8`e>F@&rb)xS83SBiZjvlBLNVY=}&_~1Il5v4vp zir_cPGjIH#MPC1&eBUK?m8ncp)p|sKQS`>Nl~s0;M|~jXc1M(Oz~gt+*vLBW5&B%y zO{xx@V~X)O?#H8mjTcl2_2<2`JV1?5-qGoh7*(Ga8085He; z$1dm1)z42LszUa!m@3}geDls>h&<~k&ABVWT~V|hekXnQVv{rmD1Ps07(?>3WjF(C z{e#Y-&pati>pao|h%K`ibHaspj5NfVu_u*Grb5hHWfAIX$(Je&Y-@K%SZJ3 zv>7DKIncZiX>qK~c{lW;FX#hju!wz=#Oq~-^ZW5IL{DAMH|E^*kP~sqgc-xy+c=dK zV^p+*d*=}QejRt0UUZ#O# zfmp?Y;>^>qTzxKN1@?wxheEQ>}Ui@hK`q zvA&3RudT9Zrq45bCk0eg2IKvezW@P4m7%h^FTk>nVL3WsnaGUyZX~k3^FJ~hKA?Sw zyVYW^*q*G1>Y>{EZGnxaUzyS{#zQW=46jY3KQ=f4?!Uxrklk|U+(|oqZa+Z-I*#+- zet4!G_wKCihs2PC=;9{^L%|>zLZRoC8`3-fU#+}Ks5LQiGV1h+EAiQQp4j(w++S^HYa zYc@2Nmi1%Y{f|;4-;N9c=tXy)o0eL{3zBzEvbublvc5L4A3Be}d#Ls~bwhLjI1^Mi-lcmNf9-5ecuG^J8B7pw zKwa!rH^l!6l#bhlNYY+X9vnnd{H%B*85}GeM?gk(`CNU0ibu(b-Mu7;%3@Q{$_x!C zqXjzL?qdD&^@}>hkJ(EY!2*BIbS#GmJ^f%q zR9BHD6r~)#dY?H6)rA{Oqt8c_*RZ#j;$kVFgbxyRfK2J&gUi#ZMf}D6owe^<3140! zlIAL+omAO~Y=L}U%rODb@@1EPJ583C*lsKcr;j|vH1FswP?+J6kZ1@?90$AspB9B$ zL{>=YoM$QgSW(rQ-()XwIv|&ZmRw&p9Exq*>`mLgT9xhet7KPo!O^OOv*?iv&wb{W z1ZBlvADsf&tz8_=lD!9|Co+k+pX(BgTA}*aPg1+y$acTW25=F3xy%3F9Wtf%A6*ao4oDfp5`u!XE4k@US1J3*^&<9+=VdfF zU~kzdWX4wK=|*&Y)D|L<|KPfFe^qr+sv9q0G`S>sz8PahoOQ1M?C%*GvW42RSaB8B-NprmTAQPqh%?>u=}zSp ziPe@ZbMB_S_91IQO-}tQbr5Ib?Qd;1Bkxr?wwi*m8yacVMt=-LMkISs99gy+p#g?B zZRM$td}RkW{$pWoD)b}mN{qMByrNFBJ;1|Zw0H$rjN@H-&i=g zaUE~x{4lCWJJ5ufnN)?7ddm1pS6dbMt;ucot=#qRn8MXE@ike+zia;R5uX&6D9Gj0 z#DY}20_kSia6G}(2QqlIkLpVMxyXSxIstSOeD2VFFS|eeTO4#+jvmTr0F19zp`ZZS zdzZ7}%O|ayzR$LuPa$6;FD|7QM#}b}+^4}_w{qUBR&@C6@QDxf+Y+;C!j}_WQ0}6&Qgqk z$K@%1zdTpv_z_FdLDl82BQ#GZKutJO<){wB(&ow`=%=O;@Kg>shqP*U^Zj{T<*6sc z>jatb^;JImD+LFi*@?2m%`DpYf1IcXx?S`)Z1sEPYxPj7z=o&Qgdh%-V8ESzAI8d# zq>KuNPa96P7-H6u@nr|5bJ`XIlAwm#Hdhdm(2HrS`2L1R3*sgGP?t~i=R`RZMrB?O z+lp>cjP90`iR6x%F}x$HR`!hHd_?;8`N?=@!ar$LP+#w!f2&AprB21Ad)x7Wrr&DA zdK9Z;M2XT-KI3I?eQWFme$ICyI?VO!i@GDDWYmBhk{3~`!2BF_6gkrws^t>#-}Vjv zYw7jx&gL5{aSZq6>!yOBD)6+L!ZDlza!U3cGMVdgO*LSJMJv1<^Mhd+FLMmT-i zp|W9`)Hmd>RD1Qv60-a(@yGKxJi6sUITO@MvYCiS8mBlWzxZ7;9SHz0avVnpL20yg zRDt6}3d@PbcdL+V+m={&SCp1RgIiv*YK3j>)eC zt3_5picc*aSi;U3Kw_2IcoZ@*p6G%waqb|{mUtkuzmQRRs<4p z%XYYTAv)niKjQom%Mbfc<~-<31*295G5Z0d_GsVyaD#F~G5J+p%hZeXF)G;RBmbu5 z3`|w%b3NHQ{<^eHB^lu>V1oaw))3E>I&g@RE0FCgx z$umnsDj_#`EoJ>;?4@$qcOmRKP&#NTGObb`^xGmL!;rf`7G=41YL>q=eQ|}i;d?7J z;al+Z07EXu+`{Xm_4YX;--R}AOG}Hbll-nbt!&ZWqF?tZ>9NMS6UD&G7E&>8(jePS zJw5lKGu6o6A*S-9$oI!Y8sk^j_y%_7{nMktbX_kZMsVqnw`bS;X*+pwB5Qg8rRaTC zQ&-sY>W-#;+v8i6`;UgpwWuiqABlnH>J@RK4g~@(pVaA}Ppe4t&gin` zWCqvzZ{1ICU%S3`J`R!R8+CntT^`q}lf$ZYCeP_DLVZ0#_>~ivyC}F6__5UA-1*Gb zA-ewNpvl!fX0>~Mpo{-BCgZhJtFIMKMx6bF2%NsoyF+&&n}v@pGYZMrb2HJ>S0hCMLo0WoPlk=izecnA=i^Ttn}@%QpYI#h-qS1gGCfo?sM< zjRWE7-{+pF45gDb(c$c}UbBdtlxGDUUq{6{x_9rp(P>9^YrMIn+na_PTLlP;Td?M& zM_oUqn|iNm;;4+EaL^48B82Mz!srvQ5!`-WGGCiGf!>I%+ZG1yP zcKX!y`!RhY39^Lyj$qE`F9(K<9(I55X!%ufCDwL+dCmag`M6zpm|Q!48R52r?_H?x zns({*>1IyD>0*~ER2-cw8ufzL#ED|OOATo#$N6wW<;yCTid&bx8-U;YZ9aeZtB*Kx zir}7$^(|6~eX{!ZbzXXIJd>>T5Io>-seP(yr>yR|hr^b zO2BnoKvpj;UYTM)zZL9$S=3ZfdLS%IWOSeUDV)(lj&v6YFH%JfI?vac$%sV3e(ITn zRPKbXR|xS6F_OyHK2)RRK+RVQCk`mpQk~{1X|c`! zy0-xtXH6c=b?d;5ItLc4=@{3?C15z`PR+_j3Bh}BgZwuh)`WJ8jm86SuOI?&Uxt z%tBAZUTG#fc|&WkHoCeWQu?+h6)sBo5{xVa$9k1_$F_nVd&_?0V@pz8`V*=^-4jC_ z%ZM_b;1*O(UayG?8L&}QZ6%2mLVV0}oLC0K@Pf=Rm7t8i?K8n7?G(EdHuq6CUHc0C zWWXwI0FxbT6&tMkIX}@$*F-U_&!|bcX4mR7Pj#N@ggMdU5GjyA6n2Rgrhi$VnTL)+V^Dl? z1E2Z#fZ)OPBm~gGukFWhB=3~DNsuC^w_haRYEWc|R2{YAb*iGVtH1iGVg<8Y@x)kkA z4}is)>Ua_zsPxZ8lsWAvEU)HyLLt#}<+A-&cl*FAp`=WCy`=a{sX45=+bq~%eWA`Y z8QH2}un&)po5Z9)Pmt{67#l(?8Kiado&=IA8bm zXic&v*$!9AVJCL;3f)qqinPa+Z0hDIeYLJ>#UJ;#y#}H#RF6V)9m9lKR#z zUQ%QT{NTPr=lCZyLZMI{u3%?b-?v}J-(+6M2_x06;c-Mg(Y@+Wge}YtDg>Mo9cQ3< zg=y7&OiVj>z(9Ny9|B`(kY&PJ3h#=HyVO_9H%jQYyl%lDvm8UOu(bLHExu#up{w>>D;wWDRmuTPl@ zI&8J#W!Dypnm6SgVq^=Zi^T2Ue1_Y+PTrJC9rKyiAlmneg)Y#k7Slt`&-9;s=kB_l zOjSUtrTtSx&-n?hVO+ds=%3VGF8SXNWoCPd7!a-{g8(D+PLxo=(}(AioEAzl6G;Iv zA9Kd7TeP%O$6kKq`Od9zCt0*``bO^A_nd0AU2CGSwKQkwG^MKIO@JpA@Wj>3LaA}W zP+O~%CD7uOclkQsf5@1wN$CB*E&@|=9-SYUoeE+Sn1)tijTvieB$kJZXb^KAI8or_ z6w*x)Gye_{O&#o^E5_^k^$ZLsraY|fqom=AihKbTpmbH>Ew@p)FOmYQZH|u|@bZJk zrG`hU31lnYnj?ws*tgehUGs!8F{mp#BQw~);f|+a+Q=pT*FaKAlU11FC}lg$3RSv$ za*pL*@RQJAXn)J*{mbI}mi_jaxCO{X*0@%FeS`>@Huf*(S=i$TOQ9*U$Ahf@YRf*(b3U=Gl;(NJe0<~mx?jL4a zFzy~l)079pS^&Z-+wqxTI#*rwlVOeF!O!${UDeCnD31)ZOwtj~bwX?qa%I|t?iG^m zlCl#>b^bT`Mc!q%%NTK8h3*xbjuftaK#kmKH0$DiIORae(W$++w9(=)e61745edHhiCK(jgd)(9X49@63pv4wwvKEVPD4EVESIw|RSA!<0=b z&4}0wk`9u?AbA|d55a6X6IA=7aMv{dp0vP+X@|C8shdkwu(Q|n?0ia zS9<+7gFSD|75Q~&ch7%(3(>`r50p3145RC@bU59yZgT z)d(aNanW(@ZPi?gateftv7G-l$(z&u$cVPp@7A09EA}H8BZ4vcBX_zU-T1Kd1SfS} za$;Q{t^Dw9BQX^6)$slOsepTj!yv51@v4XlYa~kXIPpV z1ML;YX8XH|%msKbP9W3$lgIJmznCt9el5C2OnQMLa7~!WvTn1m0?3<^oS2u7PxCaU zuG5jq_auc);0i-8Ftw zZjsn4g%F|cgD)h%CeyHZdopdwWR9?Bi{bFzzmXo;HPEB2>aDn|lW|}U$5RQ3oZ~=y zs5rnQ*y+hPu8NiCSJ-^SoUP`JtoH9KBOwQ~r<$(F4dI{2mlE?hMc1qq-%CG?M&~); zknDW1JwcyxdE?w$E8%q|uW;{q`Z{pISmeLto()T`|Cu|cU{UETTD)sJ3y1<;>^L2B zHhWk|Y#b|hxwox4mwQ~zksJ&*mKj5lpe^xL6PeyfKQ!+_s73TVNo@glz?H{gyHES& zQadipr?BBb{32I^z|2QZJF{3#Ed#PbAu7MLf0BGz*U<7fVR|eiv9w0DAU;z-s$2h$;*t~{V%yQQ6s+Mc> z>7Pzzp#&sOs!8+K#iP6AEO}*X%9|eI1g}?Sk=^HeL;7;+MRgjto&TlbOWf&Xw z;BxVxnS2-1_RME-7P@=-tqF-Pa`$W%WxqMC4v_T>@ySm2 z9DPDm6ZW42GN9IVGg`g@lwaGnS;^dMT6HF@OCgIrWIdiiuHXm0xJlqC01^8qi@S%= zO62N;V`q|O#K`jkw7MsNW34l&3t%37y-eDUs~v1!zP_qHEO>XG8@GF!28i1o2W9_t zh!*qAZh1}4=@1|DC|+`ENh`MKtk{2BdLq8pIB&_&*XVqmzCqiW377Q>sOi91;SPd7 z-ro*m&hBCX-Mlml?1g=DM(##q!kg)rW!po&){$LB@twGDZ)qDUQt=N4E}H~u zDvK(6ap}84ZmgE44DxpXI7RFtt)p^vnFq@jlE|eBK9xS8e@af=|Ly1GLQx^Vi8sH0 zrQrYnqwU|1AO8G@D)lQ%K6e5!s8sXXsetQ@@|<~0%|O>&V6MUHv!lCZMRA`CRkp$s z-{=knf%kf?6+(qO({6wYwF019DeF<2F z{lFdh(Iri~go3f#xmay8~Y&$PSl);TdNP@rvK7^WGbLqvV4>*yDiLL{U!0 zA|BYjtd`NFnR2gJDdVGQd}sibo(zB`x*oF$a;nlyu)i~)b|+}TMi3uhz)BO~vS zoo~X+QT|d@|IAd_*XPZBji9u?-H%WKjHu$lj+(9^;UR4OS#+O~IiJ`5YXMQal7Y*iColcymfN19U&A}I$Rf>g;7&*h;Ae@CI)^}r36GohRke%8Ox9Kq9|{*C9w3k@QH z$sl<~M2Uueo03@`wSf_ndf%#*tE!^i&We^;*^uICYuruvIYLX^2 zg2dn1pC=Kt6cAnX7N?^SrDvP#IK`uWpbXcTCG5(5~jmPNDof?o1DuK8FTor zo_uHMh`C_<+mi0b0Usv=O`1C`IPxEwl-bwSnMr4^+w(+R`rAOA&!p2I#vY&RQWzX< zPwe{A*^sll8$ywo&Kx;S+e+=iU7hWV7$pV9ApD zWG*>4*!Aio+xkMDu~9D7nnJ?L3d}#A%gOPKyL+2&zDlzOr7QG$$BfP*&@Dk|ZO6)^ zYzkKAsS2wqn}XK;kT(nY$>z}ekWJ>3N?J~vfdi@jo4?vWOU9%RI$_LGqKZp3sxW9g zUh^zBLmXP+#LPeDUHa9~2TVo9z!^nON;xZ5t(c*erh;4zzA(;a{0hP-N@Cy&&inna zBZV>^j*0rX8w+ilpeY%ja45#Jrtq` z`MjZ?44bu~RpjD;vhgv&c0$+^a;kr*6YP;W?>eHwu-fN-QUPE4TG;)9K_J8 zT6kKdi`^Bh0AVw=aeQvq^nbI3tSc91&^T4R)tSBzlf?x_S2!hclS(xhC!6WA@*TA* z8f)@h96Yi+nCG0^^&(!Ig<#*&9J+8~h@^2!Bs@5`knEKD+oM;E$yv{$PH|?&9`BWP zU6725m$>~8qq#W&N@p5^fjEZ(g=q^K;nx84@y|+@!Msg!cu$9OJZ+;{JY}u_@+;lu z4~vRWN-2eIB)b&KRHZg_|E}xmcUzM09>jwFu2OhfOS$JIS170 zBh6j!M(Q;;DPBCP?4!=%gP${UJ6%QOLQM%zoleuo_R}IweLhBo>;);r#hB}EBzCe5 zhfpY(Xv+!@pa-@kFpuu_}8<6LnCNn|GPYxH3NtmUO! z!fB|uqU52_BfIiGs%+jR;$MQ9UI=dIPMN|&PSyA>2&yN1$U*u+m-EC(Qt^PQy7-kj zNqw}MTn^{J?4%y>U{0Mz@@H(H&C6(wACD6_D^%8fx1!XhxgtA+4!NVYv)M>Rf)xH> z-z7{>)9<_vI_oJKes}uDElGt8{w`2$y(E!M`<*ajwf)2Uw2BW7c}cx6JBivqEanwA zVV$rOU;1daRnthDpIoD=Gr@z)NvhlaHyIJb>t?SkcBYe#YWCSkqtt1_91iI=0?lD9 zp>}K$;wnJKZ(Q&h5NabyP}%_aVQt=5HbZ!aSIv!{lT`a2_3S)HabzR zw*D#m4#Jh)OaAF^uCZVr)wF(No+c-f`70uq{UW7Is1_8D1fcFV1w&5z*TpQpRUT}M z(siOGY%z{Ts7#RP)wPg?>DNPvHtuS7lz?cEqC?cN4~?S5KXXXHcNx6IL@obBv-k_! zyU9eW2)*n4yLef?6E_qX_Cq@&xRUZ}>D^@c8_7wBi8A}&)K|mNBNnHMMcAP?6UT2I z>)j=TokUf22c!Hb z8YsL#3VJtYo7ZVAs6>ceb%_@tnTh4=j3+& zX-NWvVfZcR)hNxz?pfMV2!*kQDz>NI9BuDbSKvo{nlk+jBLz6*m6g~!c_;7`Iy;Zf zM5e&bYLyj8M9UQJ9+XmzejX<9Tw|J9BJs6s`V-3ypg|b_WzguVBERAwg_%N$F@W_6 z4Xu#ciR(=Zuq{0LCo4`dG{TajsaUzek&rKtFjzR9z=9GV&4p7H%VI;S{EGZ@I1(axQJbLk;)+x?!$-#|i+Ud3POO1D?#+fe(l!OiE?NyfMz~~~ZT+rbSmTAvL z%p)!+6FL%$qF5f)~qJlygeAwL|t!~3zwZ>#fZG*8KV3f63!q8XlmA+nNECJ9|BUl5tk;vLOnuE&NLuvjw<=w7g0u&96~C z%Av(Dl^$(F*M3F0B$1fi5&DOT=Vf3x` zlBupN?S60&sO<}x6MMoRI{4?1=)O66AN5h0bm8KiEIjU z@njBsWd;fj?wD8g#j=1EeMNVv;C1K5U(1^XLVtRapMuUTXLwmwl}}D{+0FFBaqqe2 z`>*|M@!Bl`UtGRh-2i~X9j;nuvL z%n9ji$skgx?xW}ZSthB{6t;5z#iL=0ga?*EVzV*)MqdSoAAEfoFv23QU9xtG?z0zw zCNM+uAW@qIfNJ%Lz?II|)IkSw{TFw14P8nBignkkAK_kuXXEFm^wy#2^i}h+N_9UT zpZ3}GfIFoq>7^^J@me67-B8>E?2@ChIjy**=8qTDINL)obg#>720*Yr^Xo^k#Bvec_i@!E@qMiN7)FC#b@1;QsxX2+yYYpYFm~*~gzz3_Cmhn+B47PJEV6!ga)F z9i_0xf00(;CvtJ8eU=edskt&{!JX2v7gjkj!PLDB=)G*9*mNgKZ7e^{{_HY|nXu6b zw19nc`N+Ge-u?s0DJ6L*+-JX8P{)I+&)EA+S1Y?1b^Pk!DW?>k<7qF%n|~Jm0$na! zT9VG>3s=(IjHbDHF9M}@m+!w5sehMX_AFV(tY}ry6>3C0ZbHA}$(oZ$7loDGm z$XWiL%5mAEx7@$dsucZUD@EnXOG~V6c~8B`acg*dHPVl{UuxI?JxX{;YWzx?q0<4M z@l$7--hpK!UhbMiv>(}!x+i&Sc$nrnMfWL+`?O;1@Ae7j0zd;_dlE0UD7baq&-Mc*0da^ZDd`j8yRBNeVDoJ0aT>rQDM*{vzl8*34MC%Gs1vWbYRvK51 z11h}XxE9o^f}8k3(KQYoocI0qGZ0T%?H7V5?I(3$`hq+>7>u5!J;1iRbQ$M~xT$koh#19Iv3`4qA@J}>v~ zPy92^-V4IyI3G2xrB(K9g&1=zu{C2X7q+lsg9J9rP*$1wYDc(#3Cw%2B^6VZ}Id9~`D7uXx9o+AQS8l?~syzI6Xm z-n~_RYSan#xnCzP)!@#5Tb5+zJenl|qzMwLsl1z8?^67XUDQL0@c8~YSp2}&udFgx zE!m1`tCDbUc5o6iF4zEAINj6-isLVCz=PZray&6=Egt1NcHQv zrsue^(+)!Lgo`hH!U&7(v`K`Z~(kFgw12VnB<(+||7N*&K<&zOhH{;SqJ z!*?!Wt9Dq7&ZY`Bm%ra$yhFHpd|7zY+(35bVLtpjgzOKB{>x3h4P~8t@0<383MqG$ ze{JNAwK>W*Lr&eleY%y=wE>4#3UT={|r6x=FwaDQU9@1|PYB|Y??^$Sqdk6;%@ErS} z?teBS<-!b`#Jan3LiwaXqd8@{}*k0-IwI{($r>r_vkw0;2 zKc_Ra3vAqM4nFWDES4wtjiF4SLypRvDW6mN9@`tmOurp%JG#k7rmqSn_Y^q}>bew* zE6o!B8)bV5vza*RVFV68*}?1T88bEC+SNUI!V@Su)EKL$aV2s>WjikqyhEBFX1%ML ztS|HqoNO?_yZUe_wCh}L<#t-cmN1|v47Lr7daE|ei5D~Sm6Z9|&5O=oQ8o8_Y?>Sr zpZG%bnP4zUvK;J5n1yA@ZhT_D~Gel0QBuwf8p|pdZirRQBLWgT1;&t+w0&jmfrvirdAL;bLc5--s^@Qf|}IH`;_>f^5!3aPN4V*E~__jy+RK7l6(AvY7N(TiYuO!FE}kBxsQJTc|35`+l{Np~N|6*oY8 z4G4Vgq6y*XB$pmfAOIR*7R0`)DH=oi?U*IMqxXDB7j7M0nh?ob_$xmD=}mSV?9lhp%(Mp>hX zuqDd&08U2TDq93I>6e%MM=k6Yu7F(Qq7nuBGpn2~Go8lqD;a~-h=p`*=-p%{##GkB z;khu<&7<04bMK1I;}rV8r-t1)@kjOC^?5{I+r3W#sCQu+mQSTS^H~TcdTe5W%ehrJ zbOrv;VZN8}uSchxTd((uyabcSCRX~!+pyw1cYgI{7PrZrJilPc?Ex#$@omMBjZicK zB2XKftXfhA3lbns(X%4f7m8Ce=Tx&xx%uB0YFSdu25|PzgZGB}HZ7nM#zv%J61L*k z<(EZ~#ud03x3TZNy6AwD0sw1f5GUVulvn<}9l~$9ugqm~&1%5AnWZ(NRa6X}-)*it zw)&qOzUAEiS&R`Fy+3q1uC!s-!=17^qhI{ug)Eu`?vUA)9eLQ#n1JMT>$nz3wqfmj z&T{vwL&i|wuzjVu66Z(k^OLySWDFwY#4m0S%a`uV~37!`as4u8&p&AUgz)%?MBF`$N7}MrC3{bD3f$zKUOlV8xk^5_6Zm zOKX2Opd|cytUUpOd%X{i9LX=qsJYLzad#SYoisafucEKB)`5PDA35PwTOLS!E_nls z|CQ4MH-3g~L0PWdIcZ1Misq6*o|UOmH#S-k6gp5fTmY-D{lCQo4~vSVp}m* zo*c*0bzny*o1V2kH)c$R8%sxlBX3(j(DK1wgJ#lSQ`EM9XTD4-4bG(MDPekj;WI}E8p#ZY?X;E^dIH_>XzT(!jSjgeJ(5mec6iy@bYae&!=t; zhlZ#%l>$cy9a0QRikctSpUu`;W9?21bZ~Z%yNHD*oBK2=q#8TI?GgEJUQFGZXX)@w zDh=sK1*pE_rvS)W?1gmb#52xuL8YYu26s90qW+o+@HwxLC6J{XZe zFoJ^rQF~+IhPA5)gI{xT(`1i1=dJ7K#%_rjT;}p;{j}jfznVzf4S2Uo1l{vaV3G>{ zPLKRbbD1fm37z=NajMh5#uFNn@VkUhMrnlw&ng`kp%c)6hIh3wxv{8gK zi^#!bv7Gpy4%WsgufvY`&B_B?FkrZCP?a3yAKDvXWXCOWqY-NlYUQmRfsC8FQ^=L( z!_&>SLkIoqfXc^g#Gwf9kUQa?8kN8U36?Uw^>2kb*5O|$NO`N?`pC|n_Rqn;a?c6Q zAdc3gizrH_%Sdw!8!Bps6>&!2@sOiH;q)Im49%(Xc`6n z_`XWc_8zHsyAYGIBYBEiHFLzm&6o!_+G=hej~#q*cwCgnLAxC?rr%YG)$q%5;Q=y~ z<=;!q36o*amwNROsTtEo2<`M|s_q!pJdgC&Y7RucwjlmXWS*7cT{{E1JJZGcW60rb zEWOq~@*)DdUj}6LpVl4zVn*F+cgU}im<+qx(Q*oYwV~?x2LJ?k!>YC_&}hW?txoZd*5@W*Nrq= zCB`S&I`@C5n2u7Y5>Nefh9SZhq!SOANlI|}Bp8v_?9lql^v4|d$6g9bl zDAjxx{D0W zK9jAWnTXrtF5@2y>q$85JnGP#3dAqA%ViuUb z=R;Q^+rzqLE(F>P6IEuYM9WUWcxPo-30iX2i8?Z^eWz{gj zEs71;?qt};f3El>TEO%}E|-ln_2g`5*95wUU2QRB)Bnc(vET>c}28sLN3 zN#~_vck`wLFop)^2^=E2rlBff5f+C2QGU6|6-rNGFn3N3fQk(}b&)C{of4LW7O|3KYy8B)2X)ec~X=3!z9@-Yu zr`2+!uxRE!tvkcn_{aoN@}$TUkW8EB)faw~HC(bx;o;#kDcr&>Aos)f{XKL5`Bye~Es9s{$7&8WG=JO5lOY&&!T1_&+z+712%mS~K78s&%dig8rAHvYikaKbk zlM~Cui$ww4gcNLH;jWjb$RS%&K{P5Yw!3+muzz6pTjQ+N9womf-P`F=*N5;n**d&V zN8??~sN9z0y0uw0L~v199Ug13QTN4vHi9}o={OYa|Jw`y=a)AbiP8N1k$0Gkm7v+~ z!D&pRXsSq6SAbot@Y|7Fo+jVfjN~rtg~HJK(Vm33ZQY44g-`ytMmMRoYDriqs6~-f z{PFUDkBO0k_udaF%HSqnhK1Z2L#2(P?wa<-bKL%}dKJvL^{n4I)MDxPGg)M2O6sG? z+jjbp?RZmQ5;vWtG1eaHoZv5*(Z?_MM_u;hNIyME+*&=;p3OS*G8(Bc-sJXgds^*lxq_)K}F-?X_fZ~UgGH7M| zdBxd0^5rQ4`9<`@&UW3Lhdwd|Ay%#K>m*Nv44x#?oSO@PPXj`qFX}g`9*tnYtr|4v zJU{4t6mO#DUpA%tSRBs3kKQEfk#tT0a*_rve5Qwn$*;znf}+y;5-)>Gdq%L#wf~y{ z_qPXn-~K0dk&(N=|&PDEq}Vg@itr z?+V3|FHNHy)UyZg>6Mc?Wz$JyX5xX=wXpE&$%x?-?TyGw9qc4?nJC2W^@OymNUnt=bfSHy~QYV;jJER95q zgTF1Cl61xY&9^tNk{IwmzkF4&=~!EkX6XBHr0e6uXfa6CeL!2qHyl+Cf#=cu}^hmODzE!F+ zMZ&8OpPY@CQ}h-Rynh5rqZQ>#*(eo?B}>8fdWPIGA|g!bflK8XV|oU{#oM zi;*|r=ea{w?z{>Y&1WCSTX*>zv8daO8FVLwZpoVoL;IcAu#26vve}s$B#hX!X~fnI;{{Lc~p3wMJ6GutVVoDW4XqtNUc?X|q z*!@b|d09#dC?B2cL#n>yt76r*eD}@^@Bd>?qn9eb{D}FkeF89npyr&vx<0xhi3C3Q z%QufLNl*HGbQ31%eQHkPIGt!uOl!yi>;qR(!Dy>a<;n1ZT>*0VK}9`Op0q-7(h3(b zR?-rL9!DU+bz57XG+q;k@HpA%t7f@V#@vix6v}l9W6?HEj;hu$=QTddmS$(UTin)N zvtU9YjX%mU`UCvGShAE=2_%{DmGA_#I473qqake*aKBWH)J(@e+%-?n>k_LLP%SH< z*(}Wk0S0c&x7Qs0?d>F_D-`M4=7*LNz|aFZf<7p|dP@Ppm-`hyNCLDD7h9ri4pe_p z|Lo-Q8b0s$i3c!Z=3kKZXWe8DrvFFF=@6lurwznxwddsI0QH&GMs;Qt9zXYW)m36) z2YQdh4{bWyV|VUJmyNE)yt9M93TGLv^ir^F#Jr{c$Ff7#qTGG>B#UcRN;w>zv9D;% z_^~fv{>@vmy{Z45nn}Yvq3#!<#m_esM{sNZx zqw7&FZ?*BHBXHAZ3NIs_V+YQwezTa+DNAtGSY}Qp~9}0v0iGiR5&dv1CIxrB#w<}mi&&^#_c^Z zfA!CvpzTSf&uZDTEo|xSB4+8JbsaU&W{EC+0i0lp8`g&AgRpE<SvPViY~n^Mzx3CZNAN?& zA_rK4C!-{h@xZsoa!1w4biBO zA2FaenX1n~K~<$ynK6&T6GrFc!$Z10X{*?v+rakiI1GtC^#yY4FdaE{{@#(@wK{6u3Gu8-@f5<;p8C& zSh?(2OmgFsBTOKaV26))?P$%p|6e;KIZ6_b1*O&QKb2kou|>TY)SR}6xK06`+!3}6 zrt9O0z%FLyc|k9m4EU`YfwXW{p?$^$=T`Aru{6t!uk*}4-%{L->sq#{fEWkC$C;Jt zrHJU+15J(@2_p~vvLy+C>EF!g`#&sti=`v}Uv~XJI*j%Af4NmmEbzXn>^?hx``S72 z=~=~`UplBnBFR;>Ri{?4{i0tY6`$S&0glKVw)E4=uy5KhoWK0U`I{gQAHyyT5~L42 z2Ehk+o^^?fHKl=I&uXfT=n$H5G!oCs2imS$x@v~e$bQxyf&{4iqlP}+AozR@h(3?#&*Jxh(a0+B)c?G-lfGw~K zlH@v;c0~=6`D6^fr;tv-bXww<9u~_-V`ngnuZwF9Gyy4TfiRrOe{yDq{LQP-eEj=d zrJJA?qEV2mH&0U%x!&8xmA3&=ziY8wI(q{O5z|kU!tZzoUbHN|*lTsp|8fSf>X>GT zyW8Z=U2{!G))DxNAd!2<^oV?Vcv`|Ki0l7-^#A20-e7vVsPd>k?r)9hRm49$RbY?y zkNt~(y;OFC)-XYxaas?OgB{x?c<&}{<=BmN(2Ae>{PWd3PJ+PyPY6p&l=Lih2Bjyk zN|@2<-@+i>;s}eqdP37~(8k8UIl1J4+{HM4Ckzif$88@B5&~hLs;k^@!3E9hgxVj( zB*yLs#iFbf=u$zx9ii1*+8spJmT|!#M>k6NH^0d0kbzDh&-~-(XM_G3)wj(Ysdt=z z)ySpWG}ULi%E)?OUD>YzrtJHtp_JN#fdZbLy29yTr;LZGZe2)Us0;NdFu_f}w!)TF zjz+v>fX}KcSz0w@x%&Fb!INo&vj{I29|7w~*8nXGRSE#{3i|><2t7G??Q=ZNb$AuW z@+W{AZi=oN98Wk)pFxD2H!cjhD?Zfr<&DIDjNeMDarxo@$MaMhDraM@cIH}~>1i+d zy_CgaX9D^5jpu1XwkU0a7>DT^V^TW3{i!@t1gM^3Z9XGH&b9mpqL$-?>+iVvzrT2H zn2GIgE$m%z@hcmhbx==)U*y8fM}mLrLR0=n8y`l|N_%DqLec~s4jim( zY-FT5TYixJSTMYs*Ajm~djfthFS$?pGox7Qf9J$Q7hQqe=^}uDEyU%C!KDQ%in_Gl zE<+DGFKMB6?F_?~>{@n0LE8q`;Yq~?zwgvp>zp-;4G)dW(4=v_=|b=A~h_ZeVTE-V1tXfcVwU*xilcCFe2(-gE-)sFDBAJD>F&Jg2$0mW!XkQ7_LIJ z$8k@f-nG$J=e25WHGECQMbi_xB+~JVTOlue9XJPgMzjPC0x8Ff>*%)FJ2wx8z+R>z za0S<(p{_3l2o+bq@9BZy)|1Bl;gs~w<9?k%_wsJAbUwxk8gh=3hj&KULn|)C-f`Pu zE_{Hn0BpNeihh<~ow}xzlj3_pX&Vte^ScS4mxOuM6BqU2B1@h73;BDgH!;fZAqyHxSBbf0!~L!_1HtlKfwgCFuMpZvp{yH0qI|b)|;_n8d5%Bd^)Ly6m)VA zI`>C91+{@CJ&9k( zp|S-9R1Fou<&gjHGtkf@sZStHbAA~Sjk;Uf|3J1Y=`^TkDS753yV`(xM5+)F`cEhx z38Htn?&i*81fZn*#lcVy&a>1<*@co$jUpvd7!e+cZ^^D}J_SP9I`fUR7mbN&d;a_9 zKsyXG(-0U?pNX0w;-sMFHrD#hmV0(60!0oC4-$hb?PPth2}W}PVIih+@Gau59I#*^ z5`QvVeK%+b0ZKrLGaFnH+YgRMb!`5{S)fyfG_qKgQ-gaF7 zL@ItM`aRTmf*=FO79dp5x{IWt$w(qAJf!PRJWx!mKKZZH4;780LFW7sNtJey#u#(hX9q|r%RHEp~}1r?CQAYYE{lGB;-E5QB}#<y zdlk?w04#%Y(HcxH|8Pf8STHe116cEDWYEdZiy9u%adn~5H82dt2#7YC8<|vvUXoDB zEIU_I*4v3_a7SUDj^beeQi)=RvyxThP9wsP^ZPL!2Dp$QL>yBMxlD zTX-l6fPf4A{6Gydrk}$J9YAq>UAhv9NpbM?qM|DV- zq!?u|I(qVkOT+eg%+P3jt-6y@ye-GuqsuT;P+H7b;w_68{`n*{@%WF>L~>0@w-iKF zfhzc_47nIVrXvHJ)0C#75C^_|$tmWlH&F#Jh)(n2GA-1Da2Q}=D#cV>AT(eTCAeLYbrkcUZ*6`sG!(2T8!w z6fd6JyWfMqD%;&=`n+~{;3uh6xz7ixVgiLCdeZ2O-A;Kk&IP~|k0=Feo{1g+nSm_n7l0>5i(zk*(dqQ2ZI zEq@}Tr7Sv6wWTUjKO9DQr>;4qM_Y`b_0vne^>f0(lh=NN&tIP(HtSZ(7?jWmQ2A5&351qBxgYpbWB^ncd=V)7?X(&ZzbH?JB!85w< zloY*A{IKh2cmXhTI?cu?dQFC7BFi7wy}a{VquKcmcvpvXCsKu4*B5i?fzsO&LNPC` zv?O_SvSw4q;*-)|=zdRLuf1ngkZ|ry-TP_hW?~4EPx#Z5%`qV>>l-&`RGA0#c@_c7 z^~E)Z1>HACCx*6<2rosu2`<`FA#c4-@oWA;zN(kLy-BfgH8?2?9`q(JQKU+v%RIyD z&g76Slrchk$A`&NT_`iz=TX@Ws)j0;iDS_9CfZ%k&27oeolvblcJkH43MRaK<}Z%(s-e|4RA;EC@1JI*1+i#?5|!>q!5;z^~yPe(3}-l8DU z3HbE#1@)lW`YPDamJ_M|>S}!NLi@^A*X^_PhYl1nr4AsMyp(T{0~5~>Cgl4A!n6Cu5%T2zmrZ&X6YezM zQgmz%gd8jfhd=jyeLG-IWvU&i|Mb|$AaWKx+H#KZQ%&)XH6|DTHqLeA@W-KK zU~4j2cy)i97l+)w-9Ks3{=wBv8B@j^7Qo1~>lnPT z?C-Qxhmotcvk;*%bJa?Lp>?DRsD7P_#h*Xp*VUXrr*L-5C+YI>k8bug<3ynW5cHsI zxuUu`MjljecW}G^%{OXf_fs|w(k-J5qY6Q#OR(&@zP967YVej3a+^=!7*8SSZq3>=91fIiaqlIGrqAzTl_Ry)9m zrvrJ(@)dO+Xs>B3!kggb&iLtj2RBbRkz04j!RUbXVL6t9T~rSnc-zmp9g#YW3b=Nb zn^>i&K7lsjUY$ZKLI$=yJ3g~CLzym}0*CRTOYWmpOZL4f_3U7yqKO`wUUSaAR(&HI z4`hJt)(u?1eATRiPbb$%&bRuwsJF()Q52A?z(xiXF6`i)Tx$zl~Rc+Q1=R z96&xw-sk=86mrp&=R+*|y`ce)%`2laBlLh_XanLsa$%q|T{Nu%D{eNUPtu9N|H`ZV zyNbY76H>Ob{B=G`Lj(8zD&$V4b?+96f0}X^vPh^QYMjLh6@EWOnj1*TxLK&36$5%P z1`p>+99U~274#^Ks`9IsiHTFia1UIxnLnr8;z52w{I18JSnb~fL{qmq@`FT)_Dqx= zA;d4$CNoL9Q_=J}`^gFj#8|F-^NC@%X=;+TwAw)~P~RqwhS^SGKOh^m1_+b>2nJg+ z@8YH)AL#LlY0u0U;Zsrb#|0r|R02ENaVUE;eu1DR;j|s9yZdI)>n%^?Hot>SSm^Gh z)bXa26@}M+wWo(y)kPGrRwPf`?IATvUe9?GU-)8!F9xP4P0s3sjkt1uoRE#CliQS= zg#4iF>#DP(A>N-bg4C**nDxiVrsMk>v$L2_*-{f}I4AmB4AMe2wxlMuSoru0#|=L` zb*yzn`9LRJHT#a9GEfPbBf278?T0TrLtet#rql-`Ja>P`$TwYTl&BZpb0yVAH)a)H zZFx6FihDmsurgtaX#9XeqIjM_O2~S{Rg-5QN4HZ_Z$eIsT=R%q9#1#?Z1`5Q);g)w z%j0L(AFk$jux2n9yct+)7U7I}@dg%^WMGmL!oE5-6;*EW3F#k_!IB)NjT#^00=6iT zm!#uht@)^_yBU&NXD_X76>sRbAA1|DR*fk(4WFuCLmI!PLDvWU`UOOAYQk<&crKlN zAzi4mHp5Zq+WL-6bSQU5QQp|U1)=Xda=W=*2>BL@!ReZ7hYkEZPdTE|>n75=M-bf? zZj{`xqvRB29|+(`Fc`{jzd{JY8=VyUAPxrI7q4r4&B8Y1GksaXYm#q1SETm5*LVjU zgnxUYWy#`HuO{+NdO+r6Q(~}dHV%yPec1)taq11TR#;toKcWeZnGQT!7oH7E08j|d zQpsi5m02~=qF!UPpeN?Le~G6l;a#^S%RtgSYI)RIHEvZCPg@MoZFpXRYA9 zAJ{(g)gW^U{`fn^nP>&1+mAe+9dXDWFe@=wYY?W$t1JNmNZniQoF!jgDyi+~CaT`N zw;5riGpDyc5Y&DdmdqIwdOD6HG7c1E`qM^Yqzmq(O3RIa|*+3a_-ftVi8|1MBN0Rn=ce zg@vS3kfnExwYk{Hc3YKP(^Vpq44^a1s~ob!&}%+Nn>Rt=vfydgf3|km_WJh1&5PRw zBwfoGI5)d?#3{kl5Zs>Xfmp2Vmn)xz$49KHwytX-Q7BnE=|9 zwAsmW=^Ne)TW(aM8^^j8U9E2rTN|Fk7y^T63^}v*ZfC@Y%*Ofek85@j$8?H#9h5Ml zaA#jt6{i@Z(kIcwJc?{(I}a}!-W+KS5>6@CO*Pn^<*3xNR z8+X{S6X>co80LUDSZH;Kla$A;xfP-3 zT|Hjj87S5?EQPbR#BvPFE^%I1^@y&Q$k~(}KY}=SVNbN@rhc?xHa(^<=~e^fzg^wJ z&-i?!9r3cy-$z8t<8jJ~Sx1#H{-7S~YuRmYdbhfi1{)6)K6C1El?ldsK7_CEK>Vzq z`}(kNy18As966!yU2KWYj@^U#`UgywBZtWP2G<;@Y*N42@Yx^*CUULGy5q<{9E1<3XpL_Vtn-R$1+-F9 z7crcxGn3CD9_-VB#j9=H1LoGBj~g#70Mz7%0}bHb&d&A*!oEW68W%0UN2|qH5A$x9 zC3D*bC*_eWcewP-GMXe}7PGF+bB7lEez9HlbfX05VG*TRDjSMi{1if(f2qf~=`xjw zm6C<%@5Fy#fe6{Q-u4VWVvk>olblW1Q5rP1Rfs(`G5;=8?kO30$TJ}Q=enD9bg(B# zFj;LvdHkr|`yeNlHDD-h?;<*BuAnDyF25lW#oQvWWc&3t`WY<6uZ_(F?9L5}KtipDQGtCsaVhYXe$K2?IZ#-OO% zr$KTh7FF)l6Up&_S>5&LB~_{V)wMr@MV^OXsh^nfx7Ytip}ZQIsO^A4VdT+r0YdGp zhBrep{@^LapBLJ3NCu2ZrwHm_QwZ%0|zEjl<%&FarbT@@Z9nD#;eTI+^iqPxT;-=7t0rqMN9M-RlllJ?ZD3S z3sZN5bO5x0MYh#yAS+3peR$l3Wst(=#&Jn@*)17JPppilDZ9ILx5KISv`k;SIe!ms z>g&sgfAIuFqLK|qM;b85LGYVL89LIS!}d^l@NX+13BW6WsvIKBbQJOa5>=a<-t0qhFF_L zdgcUk5nBDOi#j{_si^s<uPdTLg_JIxlK&L_mH;^N$oT3&fxWneh2EYA}u;tIr zXC?%#e7Ts!Gs|(^zHCRAt#0LC5zGUMHs_CoPwqc|2~etA>r(ZTz`fhIiFI}q1%Cy^ z5a2N}{O^0@hL%caTc*y-f0i<`M;Ogco2^FyJncVOw_O>2G56qU$DCBQq_PvUU3i52 z_hJcLB+47kHc*1*7_6=8!=-4Y4Rm1;Y{XtF;Lj#=)e0w-Yw-`-7~tGu7y(N+x}Nf@rG5K=JlKWPGuf?Nb8y-4!gm72XlrQlZE@5r>w_dFc}s4wuhi zfXhA5Qoc)mEhl?7EBhGBc%0$v$@O!i8y9a&5%tBTAu&$(+a$XHy-C22O}jMwr@smU zF=+?lC*SF)U`a=o8K2cR-}Ly*A$(SY>+Ir?9XgxaIiGg{CBWjX&U-ePyA@0#pNH+H z+p5p?rel06wsLqrEE?Yk8S_vNZf$0%Q^YHx{RN>(bPimLzbJ@tA|;)GPVOy7gRP*8 z8>_#^B{>m@8-TWorsUP2X^Fb7hFdc*2O+ZfS zkGM$EB|4o< z?kMQI7$6*Q?*Jzczohnry)tCkEYld%iTIAR%2&a;xpkxA2z8vz=Th(SM5B9@v#$-2 zxyp+W7^wit0>)P;8Q=+e=ub*W;ZsPByQHQfOOq6IWe)osnzO{(U4e$8NJ#dT5`w)O zpKof{4=NLU8-Cqy*{9uVWn$tBC67Fst<|0J3c!iJvq{#B4_ zW0E3oqIfl`+lEeA<*e29gy>l1S+MspLs2tj?Ve2a%ylBOo52@cNV}x_Op`opW57?`{5xZ3iR$mgSUc0 z{@a}`fL7M(3?w-*Fh6#n^!(%CL@55QLo8h&f!=)fw&}SI9YEu3iREHIoqP7w$~_v8 zAwpE_c{BKUU>P|Wz=aQ6+cNqB#k0CM)he=9=M97*?2KC^>2Q)&nK8)Pwp{^ zMONtB(P-G(SR!=;#)e2{o5L5{u^<=Pu|3vO-*uud;7*Zj$D+skrXRC4IB>d*^D)3! zrKSXADvU^vX_GR$|518h_-S893lDR}0%31rXvyyeWK(UY{Jm&}8pXri^{=qInk9)r zSC}=FdM*}LGXo5MUQEsvDmKVQ#&0)k?cc*ncoeCMxI7STqCy*VE9Vkk%!ZE)%GN~u z7}i1>49x}cWaM*$$siN@C&gDqYN+CA9>ImhhZBolEy|HaC6nXJpH|?0$PF%eGLOIB zd&rcnM+#IS>*-e9ciT4%h4q8a#WS8VKdeBHgsG0YYCnckH!MDZ$*S+euv;x2F_RcII?Q72myq?SoxUcps^-gz{e_Kbp7 z;r2tR5%(7xgAtV+hGBtYoF+?LAe`M`7rmy&%dfOlYHdFzs_z=aIq$^)x@N-H;Iov1 z_lRuV?K1U?)$cF7Gnv6oP_qwiT@=F#tCG`b@^KlPgs9r3Ql z>=}aEGx7z6>dic8FCZ0{zk{G?2IAO(7-l%S^^Rr@DXOV)N+l=CNa~pN{>+@M?=7MB zxX+uz z_WP!-h`I3iA#sV%M6Q;_=e}>Ah^CgMET8M6dXH?2n6B)i-z}x7#TsAF*ATqSjIR68 z`Bp?!!yHmYb$lD+2VCd@o}awpKEY%VtU9DhRp?8X8tlZbt4iP1l(jbV@ohis*{z4qsVk*{? z{rqLeqB3WW00*RkTA7MikeiIxI`65ovQtxBw2dA<@TqEmX)tGN$zvGf5ChDuu~UVv#$M#JBVvtG;4?N{R|p;M)wwSxF^s~1`tO<*zT5wUSkH3WMa%u#6?CUL%6ph#ZyPm@aU22y@G4;+Dl>M^~3t zheeE5vnp9l@eO34%43$Us7re2aqRZi&mDL$B1?eTcgRG*DAj)^KIpxfxdiA4f$NXSn)4 z?svvR4vDJ8f0<{f8Vx8X&XJQYuZ4^VYbiET_fCW*85q4*O2pE+ zjSvCQ0^gS))Zr?K+^IK0Axprv^wmi*A`x$})aiWfsMPGz6vU~`udp8#zOnv7yTa|k zYVYS!c!uk;kntyr6k5edF!HaMfHolaY+T9ZARU9@Xi6sbKybk_^m5ZW-e+Yuc>R>b zU~Cm;1snuccWbM-?Ar4?i6_WAxCj{w$!g(+-K zLNnOHJVNn#?bqQ|%*LV2VG8+tCz}o02kJK#1=~PsyF3w{kgAf0dB+$%Lz>KSXxsO1 zN5GoO?7PgxzxzzeJs9vGkLHV}=$=Z!ZR`jf);(9ik*1>;qD)@)c?SGtN2<5&KcY2% zYQHlj&8gK!pmDV-B@RbtRDR6utS8(ziVStiv|1=Ft{Ih@nV$tG3qcYKs%>J(x-#z9v$bO zxs-38ClEfnfo|Z6uH@nnUHA1{`W>P8_jKPq;zf_zKIYcb-t* z)ZleH=<&G6a}gZhdbFKyN1~6&m*b?BE4bP^I&if^KKZTVP0fqNKGVZ2lW?2uI)Qd6 z0^pdJ8xLo;$TFK9^@Xtp3|nxFw}TWmJ*#+-cqt933;RH_P4rctPsVjjjZSluecw0( z+2?Lyn~QjkVM@6Sa4X<}jKH`!yV}e8YYq7{3h%hPrG;q`&78xAJ`~%mYB#nV_S8ZY zyRMV6GuMvO8CCML5MOGAAg`?Ux(YtvBaS*n(o97+_{+WrB>EH;*x|U3+t!6r=_ITZ zeS#Z?Lz0VTOPmXF;6q-F)d9c<&g+F(64z%(-ylu=AzOb;JbR*ff|1~xu=@#pQ$DuZ+C`?tPLKtCJW*k#x&V7O?M5b)pe0Udk78EnQ<5P^Kt z8GbOrAQ6X$%t?7L_-w-}nGYu(V{XwyCTREij(q8OX%ol$0{^_<1`O^W@*ZT1Mu+bR zL4H_dcIA+9Zmo2(r64@|eBc{)-JdEpwbwm08WSS|I7yA}H&%!1&IArR@RTJMpQ0`R z7007OJSu>N{kAmJZor_!N159aPHN_>x|sS-TDju^8uE-QHa7M8ibZ$P@N3XaAGd^s;zTsJ8|G*X?6?b%gBhh=(%hm5wd{6+lunxCUI3egQ@yJte zAUol_Ol}$6efqX*LsY{kBK{YB31ESaewCjBa8pvGy1Ke|MY`p)6vtL(m!mz75~>n*C7KuNxZz{tzRc-!=9I#*?lw6 zq{H@%UidQj4Ko-ZmpnWkW@DfjfXZPV>Y5CrYO$}Yz41>l#3iEgv%JVp zgx$r}DiMR;Dqvv8-OG6j_FBJX;(w-Z̭yrXt)V$rw@TQB4 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%0Df7GunYJY|H{s_^%LlDhwI%qjr?d|CeMK!#wzW zPPwjM#T#&6YCL^}-a-U?+2p}*j=*I3Mpd@ESOFCi-xpj*=|*n<7+UU<^A&5{wN;eM`q=>l*e{I zsf!~(gX?~62Qn1Dyx8E2oh2bHwwIvDnX&6;kow_zV&3qa2IjN^^gJ}Ye?Lf(^Oge& zXt=B971LJ5o;(&X+Qx9Cf>7(I%7`~uKlK{BbC-rT(S-Bz%qEuKL>b$)pS067uM7w- z=6W7+3z;(j%^Bnkw9%4m@UIrVpaiXcWRHSe0}VB{vY2FwuQHp1Zx+s z4!7LE-zyB297D1cM@;=BjZSubCmGzj_|5CgN%%|SpYu~BcCxy8HIF;I^-8QADgTC8 zWfd|$f`sbECX%~kf7 z#;4M%-85n~li_?S)?rRj7i|m+*;2>9;YD^w9G#!NW0 zjWbQ%$d@`B_+vhKQDXuvc`Yx*vy5>rCh|k$d210*2lxP=vc>LUQbNb~Bexg<;KUTlvYZG`_`->|T?D)7kp(-dHOmKD<9P*7? zk4I8PF)^Lc{-L(Oys2sLp;|D?7t2|cshbJ&*XY;iUanLt_`XoSbOMKhU243m|4M}F z3uE9_V~ZOG1=Od@KHY$xIPmkeBcfSZNPwfD+`*Dg*bq)Fk)o%I;rGwiNMYXBWE>wS zTAtbdoDEg>(StY7m%)cCPUZu ziW|1FHgbMoAp`X(4x_4+%k`xYFc0TBH8=Xf3&yyNYD`t^GJ{Dan_)2=|~ z)T@qCZiQmkz?B#Gb=_2|T;Ml4e55C)UnB)#XG)Z)a6c<{b|=EiL|n>o=lbQu6Aujz zMhmZM_I{#k{>q;YIyoNMa@@R8O=A zNBetEFIx4hw(xYwKEO}>eoXztpx^$TNY$1$dmN$XBtCqGM<_Ms828$yBlGFb?JkN16$hR_Ay^4x233?;osIoU?SySF$7yA4QKBT=3V zCf>p%*w+e~w0|Ry6;3o3+fI zbK@h{5_hf`E)f-gdQl1^_ES9O@NHnT;TH5tq-2Zr^7W@xRRM4+NlT@6_^NwEuJltN z0&47^;d&H%UtBXKWhKXcGv-hYWVmXK@$7BR!Zg;e_HDt{@mqDS;!2YBNkSS?*nmNZ z&qM**gK{R9d^Oqp>`I8IX%N-ZNKHw>8Vpv_;K}SKk<;Jh(LTyV+;m7jVM_1;llIQ=fY@ z0xhX~CnT2;daTW9{tyBIYmbx}tU_hBf4_+(&*in@V><3LWJF5PL!C|pY;05=~KE*@bU8W!r@rXz&v zubpFAsI+V3*YD2Fa~TK}endD>sbS)^nI2oi5SiJ^AmC!6(+MXTYr$JPR|RKGG%R8` zs9^Zl?bZ-@qh>yD*ovn5qAdGkn&1r}tr~Ld^CY*G5)41rV(i5}DKf|&F4gg1+@S{V zTn~9*ei>eGZevqo?(bqJh4?(kFVHi%8t#__cggA3RMyHV7t_f;O;LY(`nzKUtU1~L zo4|+9zXU#bLq2=NG9Dw3!55^EELvkS?&;|Btokhtd_e5-Mf?M6btId=7S{S_wYkO{Vj_Q_+!zYjbxs0do-pN$5CZ@!zmr7@MKZPBwco8C0McBcW}9x z(~69Z2uSvvO~nznK8)}|;P8l&l7~}-A@1feBreAH3e1b0juiPi-31=?-MK?9#6{RK zG^t>5Mq9tnbX$cf3?6X>rgZ0S5Ps{t9XgVP1##!Q1i|zt6Jj;ZUoRn(V}tTNOSp}r z&=>SNPup5~E+RC_sbTJDVk|DKmVAg!ffAZ$3z1=yR<-l|L7 zL8oC%Aid$I+L)>U@z^ACRo3Nj@d5*dK1C`Q>yAJDj|{5v(&nh8oyR1 zw1$o!?ZbVIh3v37)t?}X-EPPz^B~^w%lC*@jjNf&`^+@WD)oxSSI9BqFa=^m!9|8x zsm%yX3Y;2`w9|Rxf;t!mxG=Ia(Z-CG4twM~sQ-tp9+aJ!W5jhk*!B48_$jJ9_VC2^ zyNxy0{pCJUh-2yM#}YB5pK{HhQ#7psx=%&4}Q zAw+=#wB7qNAuvBqO^%179GYQ|ch&L?yQ0+3oRg5P8n3#h_}zMh!~TQA+QxfSx4NDl z2<_gSOvZRKll4I}RRc@FRF1`gZ^V#gpuaIDp=Rz_ZHzPHK}@KmDdqE9eMRWeUWLZa z2I>3iTE6|>aL0?Mh@*0Zs@Eqi1lHAP>70IG;g1_b9GE@-C{;s z-Xd^7webGEND-}4J9GgFIRsxHafM8`R-RXGcq>r1vx%x1$PuYiey}gE)s@k#N&nDB zUATnwI|J9*!zMZ>CSvp*ri29l^05f|AG~t~+i+@l;4&R}DCsJSxiySUFYOFNT(4+FG!v|Py2)O}Al+YcVJj`E+9=5Qy@cL-3EN_ z-FJDMtu<1|=AD9jlcYv_zI-UtS{-{9%vyNQgk&13#Xg$6^-fC~-<#4|-hA!vCwh!( zT9hxYz0ypx&$s+LH7&IudUeAWvG(Ll1T!mS5C<(>p7cfM+ZRD%ap)N1Vh=e3g&cM9 zkcA77bb+4tUyMT@piyeF!N#73vkCWK(8G;7Ute7;capzz{X9^L`mM+p6Z-<&+12}p z=>e(T;dV?#i4yaGn9uvydK7%5kyU^YzCo>>db#_Ru@tBDApqkD^rTQQ#KcY;rLVB+y z*!b}wkSuIU+4nV&;6eIchpoiE?10N%@3nVut+7w35`+Exjxcs0`KWg&oi=>husW}M zfH!P%p&y8{En?apL=f+1i3OUmc1Zr5N95X-nM(GDuS$3m+$IG{uYBQI0pZ6)57fKg zb7)Xosq9wBdWdFB2FDFoNKN0*aJJ_h$nrrs$=4Ykd|Fj`Qr zlhC|!ZTr=8ByMM%B`Iup%3NB91mBGVkDvS*AmiQ)CENHXZRa5WhMy2xA}+6vMdAq!r2hW-v4}r<_od?~Ae5%Aq*P#U?LoJVYHvGsWS3gZpH7nB zBsE_0L)#YjBg3XwpO9;@_HK5oc;XdiX>Zj9zY7WA>$$%9nYh9Tl2AW%=VmFmzNf3| z0IiZ@?VV@sX=eX@G(Qd-07S=+rf>hG*z+x2l~b?e!?$FbYg1xLg$|52ucnx@K0Y%a zV^7Stg{%%gSqi32)xzp#3VExuY8k8PU=7QIN+I9x4ZMb{{@E}3{l?A4HcNdu$|hbT z>n^znA;;i}`1p{0If`ZkM@lHNk$PG!T+b`)`Xlq@su2x(?fPe{pD*wK=Z$ZN@%~9Z zkO2aNB?JToEp07KMG+r-11wak9|Cf7f5h%@$s9Nq>V1?M3dQKX2bbEAs5TccBX{<$ zuT?)RRT|ePPr90*J-x>Kb#oj`)N3bQRJ9|&N3D06OKop&BgMqTkk;1LK%PoS0azLT zgDl5ih5>%32>kQ6eAm?b;Y!iD|7o)DhYt<@@~1BOH-d;ieCRJSAb&k#KYZp7-NzrU z{E@l*;mTh;%%8?5V6=}wAj*AH?YkXj=Gzx^J-hRe1$}rDE`CWFpaqaUpk5Fg&wU^o z+N;2(-PgYXHM$>T06sL0GlfOQxhlIV2Cf}hT0m4&!C}=i#m$g97uct$3?D+dG_h*f zY$!%qmF~U{~u@%(8+2DX;Tg42NU(5sXsI3JP5Z?)RNS?Zx6A>hN zlbY|=m4@t}?y!Yz6Mw?*)!n*JMz)#aecIplc$wWI(E+iwJ-YDo3|kr>Wcmv&8RAkO z9Y_AD{re$(SEnxZyRP#v7EOt=^R}(>y+(DV41Nd=a1v zLDGe5k3CUmW#v3Xf9c73+6s3&E)*6egw5*$9%JBs653lMEigb)KzNkB?J<;~MxEei z1(wv#yM75>mj{oMrenBB|}>O^tJ2QxaYN3)ZKn040^V04eZQ z3Nt5=#VW*RZtjH3mGFk<0Ym^=QW{LyBxsfpBPq2s85$%x4SyZ+q$feW|IYkroNtdu zXov2p(Lfyi7mlGQ`3e>O#UVW(z9q(X+ZMBhk!-ZDebVFh1eYDd#G6 z?pm@B+&wAIoh@JNR;b?_={OzR9EBp^I$N>$Xg`gzZ1?T~QiS_O1`iXsw&5D@`XT(I zNNhg4dqoA`{zibOr@_F%$+lwr77gX&(&3Xpeg_svI~Xz^B-BK$1qIBIhn92U)#L&b z-7@y4;kiSbq2B)OtU$cM%2+Xb>uDo!@6X2gbl7|Fp-m(>K5sLL%*q3JwA1{=oU-Om zk$9F%of9LrDyJYK=R)fYvDyN%Gaug%Q2}VD&5k3EN@mK8EnxQ;P?tb5-rq&?9?@lJ z<2k5$T3G*4R)#4#!WL?-+hC;p_3jk6c0zHm?Gx!+@{oNPzc(^Ma_K{F9{CND3Wt&! z!~IG;W8<9zNW@}*{7bni7lt8k6$9dX@?}IhV(-ilq`!+il?|p(PgX`e0ZPIx1mls1 z{I*fKk+Xd3z9U+<#_|+#G)!$PBwhPV#X%Y;*;pl0VnY?;>lDDDOrDRUcJft%UU`G%B0SG=FD-T05TqnAX~JJry8XAhDiyc2*Y z1)wDh_*iy~f#dW_RfLDFquW>?L#K$H)vq{|!-w66uJIBkMt?DPoOboA_sp;Nu2?-Q z@d>?p1^T}+Zl7L+DW8G#;29a*ZJG4jHx0yTY>QoWI200SO zGP*#qtH4PGHRg82ly>hNK4DXa5311qQUIqDo<21VhAoHm=(btHD2FV(b&x)Ktz30d zQhWKRGM3Vp<|br&$DRV|pqCtjx?sddPGsczH2Gj8(T)M_W{e#^mbX7G+`|nSThiWP z^UfF7M_U@2RQJWk&V>yYCHPJfEvV+ugRPWI%ntA4YIb!~A3XN#(XpKs3p?2OO368V z)i{tIv9Gs+MI`uPSMO25tQC#2=F)y-Q)H=~SnfuKI_DDrh5T6OhlIH9yyaZ=v-%2B(ttk_a*SEj1t z8;5|mdGVGqH1?9fa@|bnJ~!er1)^rlXi#T{NQ^TX&)oopMaoJ8W#D``e>kN;5SKIm68YXZy)l3^}Qd2*k<2 zs*Su0n32$FhgP2ovYDj=ScDq~j?f-PD4ahIu2kry+YWQ)@pJBJ(dmqkTw&Rg1V4S>&jThglH4+JESD`>4R=4r>YnS3NS$ z#4FYg8A>2?(G=uWByojovW5RRXwVNcJ^^*|B!DE z)Y*0KInJg5&MPq>ehtXM1U~>bIos-%jjz3=Ar((!lB&f{5>3NaHoPE&VG~4-0`xNp z=aELPPM%<(SH$Q8P7aVGf&B5y?CsY5)#rQ{4g56m$ZJLR0@%*Bug~OThv@LiX4zik zZnW3aN#EjxUBBg(cE%M610*Jpx ziP@|8@L)S-9yBVspG)D6w9yB)k%A4?XOd>_3FJ%=%a>HczL!h9&*~7Y z3areZ0G9vXqjowAF(~b|7(lxs2j_$iE(Skw*2D`m3!BI6T*;dM0C0oT)B>9Eoy^nrj2A~*| zWmZ|-WhTsX#fH<&xaU=MM&9iKI4(ED{2p1feM`H1109uCjdJw|qKTW$y>hUs8^5)T z2(to28aAu~?`bC!YOwnn#+lUb@}?jC$SR1$#PJ!yCNp>8{sCOw?p+^WT>7R@_e1+# z{xrvax>&MdS{^Wr&Dv6$ipNFj z_Pwx1)$OZ-+1k%JF(|ldw%u6EoA&{cII=aW<0518^)T}wo#@*#M?vB^3E+aMp_n`5 zBalHoVk`Rw-jC!Lqm>ibNbVwFx5FY6Xt<8LYF2nHczr6O68v^!WP;%tS?Gs-949ik zwR$NYbnJ+unA5MS7U&N#8mCVZdkwwyU}dA2u$2dZbgu5muQsZ_z1S5Dpe|jD-VTQ6 z%6s8&gVVvf3=_P;EQYHhhb(M9JCoNx1qjJZwR33fb0_LN>zB1S&9|Ix*o`r{AIfOS zF`oqRg=X$I&0@rWrMr@`hsjQM^1$KnXR)OI`Qh(F6mGE2BFz{iCMEd{{+_x0GMf1P zf4{$`bbi;8sJ=0mC?Jd>KRN#rsiLG@J+N=rG`K!x;e&Z%NWUZOLybRF=8+B9y9NNK zqP2$La3Nc#;GB7yz69vjm4dnU25O$G;V3h69wCM8$p{hjaPu<6U=w@7M?m~Cc@mbT zHb%5{fu1FLO2u7Me!;())aafOv$sjN4$B8S;T7>PI1k0x!{yGrHPK}Jsc}}LdwE}0 zraT2?V;IcZEzP)J6hYa2Kxi>_PkZ~|$bjUOw)S9isZmR$SVJIZcfwa?k1!6v(jdgB zW3#2JBRQJFV`a^hE2glfK4I2tXw@t4$T+ZPt~alv``M8fFQx^CT>Kk7>kvwn!j;ZV z*IHK-cRyT;-5{riJuk;Qn|F)bZ{BILSfK!qbB!4Do*NtG3PcqS$}qL8mur7e*X0l zSqZF~!Kw895}#Q{@DFYVjq&^5jbBOiCMhThq-HY1#h0UF+FFQgk2i{zCGKj+GgJ3a zC6u%z6+`%p-e$|HTT;bKo2&%LW|87_LZU4X3KtwQzqSnk3X$?QhJ+}4~Y-i$G)?N zufl@K27dp;A!tt+Q+T*(8(T!~Qy#Z>ko>bq9IwBb`8CZsz$Jq+<8 zWwd_4iZ`!);9B3)=ce)~QTxl5MLsLhUIHGU3WB`IMuhVh$wZ6HzUxVSWw|n0?=F-p z^rn66;469_o9wH70+G?qaR=2pF)LBrHa;;|nOqOKBor23e$z8=a zSCkSuZwBpHahgs?n$KRk)BxG`Jdl{!W69}sADcr=-;HRArnH*5TlXBTF_nH_lk!}7 zEr$zB4w;5UTr4HF#0T@mOs$0QpHdfn_X8M*A(@zo`3yA9=q92JlxUjPq-apV zr(*1HR9vM|dbPwfTauBR#Y9?GS~@?=PZM0HzBSnQma<{e;(0(*LbnV(%K5t$E-85!FI#!FctOGTa@ z>9lu=kBgcb^a;=$^&9Gv1gq=`rQFo(=cOiEETad?f`gA4$(_n%zLrQuWJ!2gdueb` zwn55jQs2$`w9(w$+=NC(Ur}3|mf5#ZOsVn?5x^b((0i_V5fuKDo7I-~^BzJ9zwDKT)rH3Q=jTFTI*Ps!%K5gt!(w~O2J zKq5VAz`AeK8>8B`$)&(+Me=Hv+$rv|G}`@bgrA)yb#z0uZN;CTwusMBg0@Ph&E@KpIZQLivwXOm|C2@feA`a(N>PxoQkX3M5>=UqW#f)X`<%x~J z^+^)|S(j~_!^wuCcB1_4G1o#DL?JL?3u}txsyoGml&{d!-JRiFU(VC5kg_PUtt#zw zD?j>EiOIq;WAy$0ns3v86*f=|NCTP>5F>|t+~2iDmM1W~``Y9dXSSZ5IPqxtm&N0; z&mE6O7#Cx)Ca<%U7j7{gGQRHF{OXns7ek1}FMRS+=|~zv3t9 zWh`fzbe^Gzip#fha<@&3(252HtB0inF;O-d-6yuM)X@>O(~kFffNM0 zDkN5p8Qc3Mx_{lH)H)_MPS}|XAd#aB4OCcsno<52*D5O36-sUROkVf26}HyP8)%(^ z=?G^&OY0#ei)-<~Lch+hXi>StBOHAIdZhu&?58j z(PR_YwggY*Gf}>g1*5=U&st|4?+MIsuTmTzrXUEpQR@){d6WIQdn;;!GJ4sjW`Q48 z6eC=XdXUN#v7QBEwce93__TPY;))hFwcnt&D+5RWcywERcv^FL%k)vNAzr4Z?|llp z*u_t@x8C*5_Z2|@J3tI!hlv?AH}}LwNV4-(|4r2UzvY97(Q5yV;_=a$cLnR)ZZg;E zinCx$XKH|w=g0cXmnwe3%b`MkG7Hu7D_cH|A2F$tUV4p;LF#S+A`qmD#Qdjc8%ULB zdj=1`f9M%&f+fFv9;0;y$Ug6l<=P@uJM%thZLPro-bKr0MtD!BC`HK^t2s=p7|)1B zke66ah3qT~JM>7~%g0FE_G~hk9utHkGfz7bW+BB$4@%56#u6+OI$igY@HESG{vo(E zWNOt5$z6Z0-H{mu1ECMT2SE>};sXeg{0*ZC(>rJIglAK9Lp%qB+v3agaY=E*l344x zNG`kYHaUFQB_OGO7D1*8}a5cppl{aM!4(48?FT-cIpNedm(#8FX$j`wK>^UzZDd@xeuIt zxP=QN80T@`BrS%R%I8AqsKEX`EqfqMVFizHWn2am*C zmXCZ7@WjM}-#EsWvMW~(;$NN8EUfx<6b?Vp!BWCAg8aIq*Ce92IVe6_D_9fNX2u|7 z*drGx6Wh7%K_z5gzh7bNKzPp1D>=$5EYI`SqBRlYkUB&DQDlm@h8O1+*!H-W=_?@&^(Q+g_bqL zZR;{n^UdK0q5FC|M50X?Ofw>=5v^Lm-%}@jrO%EE`S8M z0F~r8qrv>m4K-h(_+w7(HjG2ERpq`)tLLCQ0y9y`7UTAd{D z>|lHxcn%=HVut~-l@LIe&#w_|`c9QJ7yBiQXc$UYfqwB>!ER_?ZMxp!IVAv%YgunG z0U)y<1ZsaO#7rIYt=r(t?+NALBHT+oZ6{s&CmVT=%|qi3@%iL!12LJFz(i+UfzrsW z5&t9CSd*cT7hsy8Q8PQ-6qqQlGUSH$8RE#R9?h$bn9G{h3;l8-F&;b4B#EH+H63$- zCJ%2?^`dzOPkUoFnrN!H;Ym<0a!r6T3avr%446IvL02L>G1R!4+n$*-d9LV3fFv-W zo$yP&XOrDa9an8&b*5@Se*xSMdL}|8@$(sy1)TkaRx5u7Dp#4~!Fe?yOZIlK$THNI znJZ*6ysA91$!Lp!Vc#PTdvZ(PuHdu~kuJ#_-iN=^SW>a&;B-9F4-Z8@_T^5oo`9#p zVdL8APBHo9yTi%%PMd#E&fN|h28x?hRLGdsW~%z`-c_pjr<@7^So_$=)2OUdM2Se` z&>c#f{Y$}jH#%NPHmuGTBNHn#pe~Jr$j3o0TjgXw#V{X#`ir=tTO~0aA%qd6YlUVR ze*md4Vl?TQXXkq$s2`pc!Y}`2j6%X{m9VShk3y2-Xw>8$<6`j1>a8L$Pj36Iijoa` zA?21&qeu&!d!pg7<%Uj0+gs(}yScdNda^Zo%D=2Acb(NiyId@|0}?0i9AHlYF?hfUD- z6I0|mF;+9HB9;c)Yn^b_=&CdR^;s`mLojPEudXMOb8_wuR?7*=R@f=J?j#&bTRgWVYkA ze(r(jlSDgPXI%?MK@XGhkXBj`C*}2PL9wK)8yxF#)2L}@HEJVDD&ZNpHl(W67G{73 zCkY9MCQpU2Oj~nj+03o%f!|DE7ivi7y><69{W1C-J2#-9Y|KPPm$Oi9H1RtQX4?PX z2VcMMY`Xxw^*4Rrf0y?D=lgd3Kg@OhAC-9h{~zY}0sV`V^#9VHF@Jx-Jwb2w$FdqP zv+m=L?cbHt^QWzrnQ>H<5!tS>a(uMj&h$qNhH?Uj^=V}$nG>x8lnNyL{B7a=(9R1) zne0dG{b_e@xK<7C!3V*UVzocKK`pmAmaDC!Q!}TM%HD?m`#X5JyMJyna5#44$l{Zv zq$Rz=t3t@0AHJt_4~veS!qG#yJEU#SEf&2?Sy>qXp{VhGi^2ccAbmr_!%w|^eNCOU z&-qu{i36LOa7gacEfy-R%|%lMKey`r-4_8qcS|FP3)d1(1}MahHAUZ&!smZ|-ZPU7 zs3Lg%`L|k{xht>?skhX&Di&4Jn+-f$zi&{$tzMRQ`<;Ld`3W4_cdr(?f*anu>*eAT zTjd|04k%X{P@dp>^NpR{si?~>W*(rFAG*t2%AYrj1R^uoE(l)1Uf}2D{t1S?EDuJQ zf$FoK?E8WH{c_Rw=G-rMw_UfDkN*kEW$yDYq3Vz87ysqT|0l61|4SGCpU@BgheL+` z-!@GDv@idZb~Ja6;xN5emZ!?cH6|lLK;;AFjCyXGx$97H zMH5>N_=WUdu&qt?a1PS8aB+1EsK$Crqu^UTq958nYAXJ5LCxbq!5KU$Y})}{UTK7e zRhd|75w*z0yZ`pmh|Cn|x3AYT_41;d=Zd*GYfPLcn>O5ea!P4eK>WN##{AbD)VZF(*p=X<(52;-sbXG> zx8F>6?tcWKy_A*(bTJMa=m(1e;-_761G{gBJ>tNmmbVTY6AXi`y4cdi+}*%0{*UwL zwq*wC3$Mj?=JKYIdBeRY!b-d7MTNRyJOqm~Ub6=%rKx~<&N=YEZq0m&^H}=YZW*#< zl0lWLbjnA!1!tIF3XL<58!h~%_>uGIPhIj);{3tylVDelM%?R5$XG_7D>O7I#K-gN zJtRF(sl9Jqao9;S3PE14y6t&u>p2-RfX{vl00A1y@@BxM&wfb@vnwM$5fT7)YW5UDmNNRKKR#)|Mr}ppH$rJ zHJqV*I@ZH6d&aBxs=YV0SuQ0%E9SK||Eg8e;=*;5UnZem2S2SE&iV8q6i>KH%8S1Q z9Dj-dA*;w9TQ=1jXc@hi1auRrPaFM5-TV?l2axZTjLpFgYe87W5B|_E6Mq*_sLh5`~0T_ zlb=9|MZ_6h6w4Za7)8?s`ZMWIKG*LB&i-rtlmbO^g4_EJxD>Dx0BKgipeiF7%@>a7 zN=_J(8$dsbPYQ&lMpn+MGr%y}nNoHsm}qFDwWW;T@BZYVL{F1ZBB|a=RqOjXS{$X*-#ju_s9 zO}uTrfbCSRl^QvH>c#e}%sS5(xB8F;oj3g%qsQAPvD;WAwUq@~!B-BoT_;e$e4Z1u zlM!M_gq4)RYp-5DDmMUsB)1|G*NZCWx{57{e>)>N&+>*n7^TAR# zCbq-Teyxea(RPg36OL~tQ=fx#5^)VprqS>yr#&=`Q0Q_!38#9KGm>J*J4OYk;;UY4 zhvL^+J~fX>bL{E7F0kuLW1KP&=A7dOP|V%tJLsIGST1Y^jn+i7)+QEWstt`B+>M^f zzccskf>3`x@@UspqqS(qm{Y=d!|eG0KV95&cAwOA71@17hY;VmTW-zKd0Ql?>C4w zU_1{1ZWVEX(Kl;^=W4HF$lTVb!UW&K1F|RTj<}ym-i|`K3BFCu@ArYzUh3ejRuw`0 z{Uj=PWl&%FDUDoVON%rP(|)erF{09}Enq*;rg1}Xa@qwm8uHF7`_;iISK`*jjtgE$ zK1xK=lY5O(>-h%B(dV|4X=d(%{jrVy+1)LzBEys5HAOJ)gC9Mu^~)%da*77ivZ+gi z3hKwjnlWzKI>4%KqUbDzXj=v?&ac~nIC_kEBfER{({6mfFIO9HFbBp@tV!c}Rb7Un zTMhhc7bLhY7_cY zY!aS)rmpPf#E@Dy!ODcl(#s<%un?9%(KOsQZ6p`jtuq!HWA*?=oNVGQZmEJT%t(wa zLYv>;IOj-Jjc9Hed5DA>p0tcIVz8mQgVAmg4$9PeYL)Or3A^|zX>!B6Dt{3_PT?d% zM?ql$+b!Svai+-!#dUZi>^1sv4v7+(Dpa@GNh0f7F2Ijl$R9Z|7V`qTN5= zCZ|C-?54mT7uMs-&=_ajo0v9B-tpoVXFj)>WC*-Czz+Re0KNag12nR9lnlyTw=R;n zhkOGFDRVZvK>LXnUFeRj3J=nAl}vR1V*1G_lqxIsD$KDPUWnTQu%LXNU}|-Sr|1nj z$uKhpwWp>%pjKhL|CLp9Q3Uqe*{Mk+W{i9Czn`I+jzyqinB%%jbS&56p9A&LGriMW<{l%=ElZyiP$NtIs7wCveJ&rJ`Lo7soE zZZ@=*Iu-~gi^u3dP+2q8kLL~;n;^+{{L&iI{0|ci1A@DEqN`@+Qw|#xDDlt`=Oq-S zVP+v%X_~oY)Ck@7h)8M)&Salu;p}SH{3mZ4(G`H*9&V7)%Se69e1EY};!~L`a{Ad} z)!LrxXXWT8vdMW7MUz1rYOk(4M0Y$~4--Myx!WcAM_!DZyVo#8Mcg@WC7NV7NzJ_2 zWB?@VrmtlFjPEyCQr*}jA5`5?qo1glUH$4_$1yU}i2aMTskvVBlIR3q#8APNnC-XRy=Lzd~=6{;Q4l-=mNY%S{z#d{H!Sm1%gXHVd;thx~ z>RSC-+!mREWOK5vnG{|W+w_>1o*jP{qzKnj_X%kp;eHnvY1M!eDIhS?&*^f zmf^1{DP5^27uT#jLe^@Fu06|elih1yW9443lpf94W);}L`s5x{Z9IxWQb)Y3OYjl% z2Q$U#n0cFO30l&N*Fr09VSOqSenvFn>A+Hu;^-E+Em9mgCa>*TEo>f;_R27GoihFO ze1wBJJ|}hIbxuxCe{Xc-uQZpJOsR(Uiix4@XuASHe~cxR+VT1M>6MlASGNWyYa8I6 zP{dV8)*MUUjYqjlWP{=%PLyq4Ygk7MDGJI+Whhn_TEo*$dGUg5yJO7j%+q%_K zqRIfSM8$zceA)`wy0v*DIn_2G%c)~f;nUk@c-I6HCz3il1L??-hvcnnr;=l*L(jvS zf=n61eNbeqW2$8|@xh*o;a zw%j_QUq~C^lW+${R=n>XI}NTG-g1bkg;N$GwmF9_JtVJ~;Q%|OXRJKcQWD`apn}v^ zjnHRk*U%nTf+~^kIxRvwV?4X)q~!)`u`Ks4P|V3?IOj8(&RYMdgZJ74*qmf;7MTTQ z!p#ADnbjpYX!_N+aH4aGWG7TJre9?Z43j6KK%uw`;UY-8#iDO_@BBlCC3{LT=@L;s0 z&nRbjgImFtpQ(lV(*=gMMyIJrT{Xb>2xy7|#TzVdYHR#`C^%p%3{OGR;Oa1LMHsfc z&H>vWD~>T@B#Ur)@y|zf06lV@#2@zAZ-agNC>gM7UfePqE_OTl+m+wj%l1Oz3o{Ev zi;g0D-?0)&K%z$F$Ys$>vw^4iKSz9M%QRp<_-Xc;>y7??|M1NZIdS~SFC6yr?(QM9 z$zNc=RjD3+*$z9mB^&N##k+stOA$kq91gGGk=shNTH+1TvgI4C?tSW|XG1-CAU;Z* z6zrjO>V(B}gGUUyaqV1sqrUZo(AE6Uo~zlcnOvQ-S7B!N7Hr>D6MAH2Z9Op7scCF` zd*7NzwK`HAgC`fwg;UcV%vu~^*B}Y=kM_cz);Y->c|7Mn|MG**fynmMs%Q)3hIDgB zkf{w6JD(0VI5kxg{#fS#nc}WSluGw8n%&8ncShI@sHEmPq0JoAiSg|??M(qDNguPC ze*tfZS9yphOMw+n(E9cL64-wu{+bdk3!h35`!$ow}QH70g6j+koU)P?AP6CYxXc< zgVBD zPU&NSF>XfIKgI|baAQIx-5E?7&4>z!k?ea>y8-jW^xV4?CBBsSzK+}QRYIzHnc*2T z{S<5CIBRU8Rebxtaqpm4O|><_L_;{!dQ@t4!i48HN=!((tLQ?3o|g8k6;=!=OXDOx@sPH{-^^eX^Z&jY<^LKjcG%h~@|n5=AcICfCj&vLdftoGuH0!+A$}>k&XNW240u zC+uN_BkF0{=SBxosl{!cFDJdas^6FN%?$=SFNTpfHfD*9?{G#71lDd2h$r;> z5sbrVPyhE0v=Y-A7ZB{Sf&wZt49y#)9yMY*(s%dk>piJ{?~0^&5bi~;k+~k@CoQ_& zo6o{w+uKtH>tE?mQOEj37dja6j)Q*}weYZ3E@>{aI1A0A6n1m4ip3mq@xz8@!C(U9 zuymvHrvdL1Cr>u#$#GiC(A(em6V#B~HR2rbo*Fafn^=tV{Y(BWjx+UYk(G zxlJ~Few|QyX1rX)5FCr2#GULRQ^fhEWz?ml_Z&B9iNqM!H^^jNw>sFEs=fztmpRdh z8W&dHJ+7;EQ)iFx_z8=Ie$+W=aGLndW8Jq#?*;t^vpZVMdVd_fk69e&4$1&gU&@|K zcD=Zf&9h#-;Hx03(__@$?um!>yxm_Ueq#~RAv$1ZY167BHif7=eE%XD_R%DS>ttZ%H5uop`Y~6N6rBe}u7B!Gt~i&#&Oi9Q^A zQ9?XiVQ_sjYJ}OH1%4ZJjxl7@FP(>`EM~{qhkLZGVO^NvB@a#dwXTh-rH1u;6yO~? zM=^~7oLEseAT{N6V^&g6deC2`r(EeY`ssE8!P!GUHy!2-woOH7r@<@cLZbEyr@EMN z71P3_?8s|ocDqFFZZ$|SqZp=LDbTcsjCa};8pkkdomCG=jJn?RgQ21Ue*Oz$R{~+z zMuO3$_~Th;&a|t;TxzLF;S0>eQ`T}$gs_|ea>5DN*^$w{#Y|5c#IOWczJhRIA3J`P z-bL=#4K4)p1)181?ClH4X~r$6)kV@$H8*tl)T((CPX!w9XuF>&v!uu-^lF|NO_5WW3@>yjlGPL2;XZhE8S_%C`<9 zleYOCPiZ=$r#$?3q<0KriO$JbyXi<5^k87gLggCiBB5>0A->~n<{@#+g>T~0)#EdC zey(!B$)Gq_*l5$(rY#+yCeNAVrq=__)j?K{ltwhIGkZD|MY8);N!LjH>=iF1GT-&e1q=+M~9VuUC^U3k( z;AhSKqr_@m`iQ4C!@3j9x(0NCE9*5*6zK3AYygCH;EHC&M)VH7lgA6+1X~2cxV9I{DQ7Sd=BDZUMm9rGhOT|Frt3h^{0#Oa3T;4186 z^^GqNXl3`OMgZ&POnevmp&gH=C_=v9(5*QjwgJg+_LY8CgzWJ)W*)s|i7|k?Pe}8V zzp~JW86McJXd&lu1J+eA4M+l#$aZIF5RdoOokQ-p@gj?!9yBqAJu)T2IF{*X)!hSw zl}D)LsuvH$$*>SquBac z@n}d4%E=dM0GT{Krj{)5x)$=}LN>i=!C^O!_5C%kPrbEAlkCfh_8$en(!HqAeHPaFRLIGrc!tmT+@^wP5C0=Rd6 zaIzkYU=?57t2Ckht{wkPT@43G-UBDKeVJ$dy=xxp2>=(ocg8dAZomzw<99tmCoA{B z2hRAxfu5)EoEu4#)AKv=3)XMpG#gv*9z(ch3j_Ycv)i2OercS<8N1NOsq1j0GK$Kb zn7)hc7w#*Yx}?_q4ch}@*6WGQ?=+`Ib?}Mntgx- zE8-lfh?&Hsq^ix|N^Bd#NBjr?(n6|8k&F_6`zH5gFN6=OdRs42xEAk|!C9Y6rf7DN zdCRgq&3WSu1tiv$5%fr{PQbU5Dv;RN4g`ST(1db1@=$2d3MC06wHgCK1J005{_Hsl zEh7^$jFyu$Dgg*!Sbe<)Bu6&6pDp6)`*Q9?LRKxMtGvYl2=~~_H3@Ae;IW_rZFz)A z0_k^WYD!f=NXbvT0eow|UHD>=SIoqDXbV&ju)6Ps0Etz6_G?;*2o^l0{F)fjx|`JH)6ua9KiH+bX5b&o#uv2Y4?G@noO2WvsuS{YbSEibIg zrZ;#wZ|npD(X7(O{!+g?R??U-9VH*>qD84p*hBFOVL1oTq-jf9%9=f&WM)Dfa8-U9 zCRASY6<>_kT##nR%FJW<<3%?Nf>+Za>lbMHu)u-FlGL*2Ry=V8;2*~#_(0gblxUT~(H z#88piJ1B@@l>Pn{hv7s80PkjwDZhG0*9w*QA8HqKjN$x|g z;@UpEzm^c)YZiHWAU1~SBY7F(c+tbgZRwMjVCf+Pac#zYg@ss@CdtR3>e(u! zbI!-L)3uiv?OC{^OLeCH9J=tY;@1ZZsDiauH?Jv;7W<1tJqse+sxyOT1<`EpuW@55 zgyz@`G1odkXqGc{CD1BLT)hNHbB9oFyjS&k2gR?=Kz6z8mU-0RRQmxyyy%4}X)NzD zOC!m!JFXsH$_4#UO#zmFjarM2E~MO=TEZ3nT!hN$L!%j_0C|&$z@vUbU1*AN^h})a z?b^bV;hsVCBOs>4%YTPRvWICt_x3+}Ss#bzJXaw0xoC)6m8HU6tjah$NNi|qi`Pa! z6{F!6cs7dlj*$b-DsR2VOMeVbs<-2e@8S&gH2FfymD72{FQG;J%*_H$jv*?KuS1oW zb}o-U+CEvXC-BeZi~lyL4W}kjIelw;w!s=4RpT_q7unN zVYZkQ>n)cQCwmKLr6h1{t&b=uP`$7pbk*4l<|3j+hcq?aHnskBwn1~H&~l2&tB4Dd zN?AQ55DfHnx(Yp~q;pCEab4}$kFzU*R{8fqa+@;nOeIK%zzz6Y95;ym!V55OH>A;gJTZ*L~W@p6%Y2?j-v0E;L09`QVEc%pht@%AVxv z`0U2T=_QanexeR#ED%XK{jQE7T%@{ta-g~9sHjq32a;-Ne&k^jCC|{Y^Q&L+r99 zaepwocdse1lOOPIn>7%aqgH+$f1qj2U>S|*asI%qIXvJWU$_h7Z)N>s5w>{}z7bO8 zoBbk#kayV=Tt5%nufLNpv|e(N4d~WUC?7+lUNVSR-+ON5$C&X1TfuvP#j{?^8^ajT z%KLD2_nMjX?q1ofpne`MXNxbbK}lTFZ~C2{KLUi`-M|(a;`U@^x2?5TNx|VuYian0 zUYvJ}wNhftR2#bbX84;1$_6#&Lc?NG<-ZT?KzfVdRhC$OZ@^|CXZ1z3#y?4tO0eo) zZgU9spSi_xV1=6m=HwW910*XjEsqw9f-=d1DYv2F4(R@irt2Y#qtSFu^y|G*WXIq- z+jZLf0j)~_;FBX=;KDGgu!I6?xwc3EQEv~<1+aeDepsb%a`{Fjl^ML|g=*(9{&~Z1GFJR5eRh0V(8Nx$ms($osm;dvs6Qo(6Fx z{aCqAXJYTD4OHa%DqNaG zB=L%q`|4oqgyh&WX{-Bl!!a4*_lqOIG)~&jquzGCFP+mh&RkVh)o3_DIyqrcQ|^2+ zN3_9i^E-of79S`IjhbAtPr5+@ZBK6^t^B=azD*N0|L$>D3I?RuNRSj`LYNpiW|O5p=L0jt}E9-ttF!`VWh zLuPn=9Ul}FbcjVNl?Apx0vGwbaL4*^rLp>|0-#C9)pKHa-=md%C>=`ZnZKjS?pt%i z!1P!W{xxQCvd94sP|);rO`?T=QJcg_`}&oK;$|8JV48xnz^Park;GWG6XUzFlJEC7 z5E*pMW{_dn-N7`^D#vX+7;9+KkddiT`HQTQg@%@Y@V7Eu?ca?I#GI0|vE3k1_ThYo z@S9w-OihyYmb2~hhgxW`&q{M#N-5Ci7od^FSf6%;H^!y|trja?B+0jmk~8tKP=+MifsqK4p| zKQW*!Vsy>?d7}FWDw15)&PZOUy18WhXLB4O9Zwq{o|}NoV>w0mmlN53OBKCXocYwU z%mNZi9m=Fl*_s(P!ESlE_yfj3CesyrnD_kD87&q4wJI4>vwWBir_DPbJQ&#d5)`te616nPFxbr!aTL!}AGr*7G`>@o z72vQj)kzWVyCNjfRVPW-JP2I1i&?X0-gqZUMTmfXlaVfp1@74P)PTX9CR=b zv|(%)5U_}lW*)5s)ArDm5?Bg^~4n0eV{d_9MqQ*noTjKx_FBgC_~FQ9@`@1l%{|nQoO}GoT9-upa97~iRwYf5u@E0)qXW|{L`^6$JKo_3s0Tb_N0oVjby2P=BUr?qw6Jvd*W*Gj5OeSD^Y zGLF~TW#Qc3pO=YZc#aWTDaW`&zCT$Ye`_@w*3eAAHo8y1DTag$Bs3V)LajWQFmmrY z%37PslYGlWDrAtSJ6}@(4pF0Or|gmzhvu(3HUZQXPe}m7 zxVGmo0P2k8Mv4<(Fc3f&pWoQW<%JiyF<@#yD=#>YV?cFk%xLJeEcz4+A@!$PS#y%l z0GGR-K}`pNLwMAMc~qTgZ2zK!1M9#&`}t*X7^PSdPrA279MbjY<%^qJ{iO92CGSbm zsK_jq0qwql?$1Du5THP1>t-{ zte<1G$tVLR4rA{WSwr8{+eh(Dv?&yO)_k5My7B66JMdvYGaP~x7IJZdVfLeIXfRoW zX4uSBEVEcXJdb9qXx-=}N3W*LTLRCnkD|ufYYPsCf|oU|0&4O6R-OZP&e7|U(8Z#{ zmgLSvrrzk)KLg+rX)ES)85~AYNf&Me1$gc9F56Yq?H%un{5#@x6jv?4CwR^<*z#7vY-c3#e~my<#Nhj#u5N4IXdg4f^W> zLyMt^2uksqxy-KH`OG+i?@5lX4ElmhZfk2fXSohM?xQC=wA)O=?Or5TQ?e=oxTd~L zrpn-rE=JW^i9JseRF&3RH~t*X7_y$){wiTG#Ngnl9p2YjoRz^PP+FB=yo6}vJUFU5 zirJ`=_{@4`ipenNn^}}!pD;5u%}`26Q4v_xkyV7{_iITwcCF)-b@JnV$8B!yXU|3x zS^F9-&0(E>O{rEJ@l+f$U2$K2ALPPi%ey+o!4UpNV{`6{uT{2+&48GfWRw{!a>Oy)2PP;Rj zkN=f2=F8%SOm=gF(>Q<8>`%}1I7_f%i5yAm0{{D1%dXuG1x#Nr4Zd?wd2jlgPQL4A zJ0H>=VCKX})wfQ>mR{|TS`ya$F1WSY?#nU1&F`qYmj3D@{ShDqHF}mWtTyXv*k;l@ z$+*S9qZILadqo z^%-#H9A5lZ2Z|_D6KI>hC|bxBO55K0*+G-)IjI(X$!7sdwLz%uq;w};5YYL^e~12OU0k$}PQ?o%>UFmh=E^fBTotnLIt@I<-e3 z{6@A_-`X?OvST_2T~=7q(-D|fKg3&T(JLpcRf$@nxu@I%QbFG9ShssTFc^Q;tdsha zo0XYW(E#y03(}3!95@ldP{U?SbQ5!oGe;>NeFL4GiW2cur1>L;R0s|F-4K902DF*j z)F+Kc?*xc*Dau$@#$xt%;yonXrgGgc_am#O4L4loPft53YbG=XJ7iOQC(eEm-$yTO z9(F`Kyia%dL_=vlsTX@PX6tHFoAZgDl@L_Pe(SlPby@}asT0mhYUYGM7$|u2s#1}o z2uvkfm63$?g^jlzOR0F3wbhLgfk7ae8CXgyKo+~rCM+~(pR^Hja~DJH3) zD0^;uJ1?li(koLt&263u^u}gwZLQ+?+0-P}WDjiNi)kahi3~jh#9nu}jPN)RZ6*~z zU8arMORV@FwK29=Yq+zwJ{PJ!$pCF)aW%H)@dnj zTc=>*k=m#=)LFl9oB&?}B>KUZ#opP&RB(fybElgP8${|tqJ=7XmNo;GTPUr8#EGxG z&dM9)jL%abQRrLZB;*0DGi@;Gl=i6ZAlk#&V>gh^a#rd#$C-o78SuF44*;ZUCyL0O-Hhtc-;X@xMMd(y}7q4MB*GG(( zvR`lMFwx@5zzO35nJffm?yD@*ZZ}wZ)Gv-tdSh zrEo=zO~$u@XYSZ@plQrP8n9aBoQ(tVu+6=zKZ%Cxg^U=z+d{=AY5b}_c{9hxtmlO4 zmmX6B>Y{QeS|NvPOAK5ns*xs#BwMLBd+iJR#=7$q+O!B$et87{^T<1D6JEgK)v=25 z?#uqh)^~`9UMUXJ^H%}Fg4p%fY?0k@PX@L58x^R5wpe-v`=f|>z)~Bc@sughqrVu^ z`+-O7HE^9%Z6~f@h>zoRX8iT&5sKVH`)EfR3v4n0w*5G+cFAGkZa2XGPR=HF1EF13 zO5LL5nKu>U)@oGA*JUZ?dqC}74Gk_q_golr=c*w>&$3yrxQ#^4TiB_BzCkbKdts84 ze5NCz#{r<=-s%<&S9Igq_;G#(ab(n%NRL_3HhR2NNf>H~=l5cTqj@h9MY_$@ z>;bsZea9%jj_58eiOwabO#!a5TjA;1Dey0L;bNa22j9|cJc3n>En6$o(nc=mF1q7t zexk!Dh~JA|SW|^lh<2e&ZBM)MoFFf~ag(C8_F;pc@-8}!V@mTtKdDRwgixDFhDWEG zy21X`kl8J*djvx;R(Bd+FgO#3|9zgH*jIKR(rTJwwjc$C#*=|@!@J4aW8 zP>|I`EVtNHnFOV#1i5KCN?xTDZ+zlau+oZ41*XP0U5k3uqxBNpU*va{7=QiyMs=+Gt_F81QzqFHHDYTGQFi$hmO|($JJ)AF8oBGYjhJ4={=?75&5SaO! z0S%*iLyhu5;+}EFS!w~I)sT3fS9P~~c6?@4XS<*4vUz5F_LXKgT=ncp;zu;EBGq|# z@DyR=_yF~)WiSKNA$w8A`I6&AWofN`Bfo8ci!%9#lw9I&tQ>wC9A>{>tw*?{xBbkG zkhL-1@gW3~3CW~q_P`g^nR%owK`N!Go7bg4;!$80mix0D-#SQ*E~p2RBb0hG5TnkKri(Y$qh^L13)HjTqye#*v5 z6v(wW>(EOtDdm*X(SBv88>vA-QxL-@oCK__GC#)!e-*{3Gj8Vkx_fD@#Nf*YPq8+l z6{l5Hv*kV6K`+L-DDQ40Dm;ymz^X{f9-vOtE$KuXXv>W&NwX>DYz;-=R@?Bwvx}Ls z=>REpH1PEzBby*2+P1sA17|e_7l_c0;_& zOp;9IstkB$?HiExcJ!T69BDO?a73+jQEK~;9DThe2;2*iIHhr(I(RbYFTyn|g(`90 ziAXF+q^$UOP4l$d>sGLEWp`K0@(y4Sf3wGN2eWGni-B~|A2ALVjcudOSt4+sO(6{4SCXaU*oB|=d*<`6Y zBcQF(5EsHV|z-(ao9{S6zME7Q#R2PNA6eYtHQGu!BB>U20IJVMHFySi8EI=C)- z9B!xC{eXM&wBxOm=?DjDs1u?z3rpD=6)o==?q26hH#WnB+cLtN1rH5mdJ{Y!E7Wgb zc1TN_RyDf1A6S0%H8@k2gY1Zcbe#BXG041-UtBvsbJO#UVa8&lZy)(7Qr@<%#KbOf zZQP);6bGiM5QYtbM%7WJjT&pWeS$?%tVzaUzx#>+>S~=FZXl}+smy0>^v>e;xaS;o zw(OQi_qDp#&xYcd@Jq3e3)i0m&P%HkqlSemPwPE$f-DAwU}=44%cd!IdBG}zJHPKo zEk8qwJPbT^;6v^*Eq=k|`K;`-RJwQiu-!W4F#&v9Hus)*WX_rEa3*jO+?|Q@L5&1x z(`pzi^&(efj*Qom>Q?%1oL&d?>mj5SV&3IJnVLutG4DwCPz z8l#1euD&CZR;?HG;(T=Ux+c|N9>3x&j)kQ%@;|;P5Y109qD~C&?E^!=Jc5xpKcQ8a zJ46ZA-=(ZX@;Ms|X*y%pZcqAmBww|a$n57}Pi%gp9-}&!Jg4-tNJBao&Joc(e$tD3 z;);Uo!=P*vJv*3r=1X2mQ&`h+-_hxo3E%Db$u(8Hzo>asST+kCB(HHRTB|(ZT}eT_ z7IHfQd(kQ$$3v=h6H!*@sJ_}pzO$Vj;Z{PMgYPD-xx~+2vkr9Ky)v^Mb0Zf&*oR+b zy5{&z_Al5tn>AUP`PQgA09Ns_j*$d%V+YG~iLB{L4{hD|wUxm-jGcMSD8Eg1cy$$* z_x1S=k6J4!E+U7#z$%@@4_7HKBZs_q8ZFU8NT=FIbli&ub1=1-7dn~MBofxG3*e!+ zyH+yp(K6gJG_b3ZcH~-Wk<2BDNnK4?tfpIqjp7%w7;TefoT)2c7y0*al=R*}@ZKYt ze5qS)a>z@b-y2|g?l$*lt8aj~I#J$|$KKqYXM8cL_~V2%#zZVL{nV?D#LidEB4NoM zEd__lGp$&V9vV#&1*AdqeJ^h*h?_Ot_GnPR~Ard?ji>0H&MnONDuG!B+&363kB@(_81FLbj0t0%-mv01w)KS+3$4;GZsseMaC z2PQ|1J5GwkS8X=1+Kxe#+e?YVl=-FGZ(yrJwG7+ zw5rQz64E8gT1S*eDvZhJFJeW9%Ir>mF;E2LI3CUahjq)C1v5T~NnJi$Yt?i&7j2IR z^KpRXfQN@Sez`kc9vY6i^LE6*b`pf6pw()SdrSQ`XjW_zww>R>;}Z!rOYf7L$1g6_ zTi!N|S}`<$F(+Nui{ME9t((Uci9rrN!5Kf3K~8qmV4nY#&mG5_TfLUMku^%;$iG(u z5i!pn%s7{h1?s4k3YWvF;|;*?NgJ9etbON2j5uMA^5}{ze4eNVYj0rQ;_hbUCgGjT zq4<*fl$Eg}<+9xup2T9EA}0QZGg{|Jo4iwTL2E{bzaFe#Ux4<1U}e*#ox#{IN6QiK z3QD{8>JLL#ncA62B8!K=zLRE%t>GsOh5JWGA#L7IA?)uQOLl#zHu&wYH>4-bh0}75 z<`2z~`%Y*fwrWoqXL`JOlPbi(1S#a@pJV0Tdq)S#2ALj*l1=|%OywWDvUDB|>cNcP zc|63{vi}#@)qi`+o2UOTlDLM-a&&BL7@RIA9o44e|KTe0&>coZB31_gI3A4b1FzF! zaqNuRjSj+tCJq6;6tI)(aOz__%GbFiSmCK=r!6u zK5(M=zeq{HkLrKZXm8B-|KH8K1^ye?1>Qye=W7$@_sknEl+4)uBlE+=OJ=hHoLl{{ z?x#adkrDO2i)snjb-y3{$vrEnyImD8X1uQ%Nni}#O(32g@u-d_OB47y-7cY+*G8kd z80ydo{;sEJW{>*XN*<~$`bunQwV%6kL)GINyTg40Or&s)m$0IJnFP1h>*Ed&rgZgg z*Kzgl(E8K6x+1JEx*JQ0K;0A`K0hfVReB3Vn|g_ZHng*VSamdZ&m<)X>R_7*KL}$H+~- z;+Pg}hk`#cPsTWU&*@2_N^^blDg>C(Yp{hbvQAWKA7AnX>v9km=C#L=E&sA0r42P7 zX70|Kkn_*K;HcCG^*Pl-?ZrVZ0p}>k4~*tSw$#kWwlAoxb3G>kZS6(=Apafo{o+aX zN0mScnAA<4N9#{yI!KIzP?-Un)ixoR1Z|gcQa8$$RjttmXa>Dh&a9ScN7>JOwlyK4 zihI}i+7aLdaf3|TarHD7w@4b#78KDRnTCU!qaL1Vn`HMVmAA*nE7EdK3j&m@Jm5Z zh@1E95+kNP(BnzcSBI3|BMyy=6WUoKb&re=9G44YOAs8{72J*%oM5o0@n@Z2E>)`+ zl>!SdE&-K-&+Hp0f(w($IaTqvLR7P^77s)H@tr3nf`oWY()rpvv#6K z_t#_OEpnUi;`%o(54N5KMnFyTBf7dU06Ekah<(7Mg}EE~X8GT30ZD+pUU!_wCsD7( zJSeOux31w~Nq1%VPXYxM`FdxUoMJvn!FDtjs>Vm=SbczmOMuq_ml! zM#^R8Y(rhZXKH=(z)TvNej0Rvkk2DNG+7=|g0{lb8_g?5gY1~yV}B1+N1O-^?OE*Q zRg2eUlH?IrTdRJgpaD=1Scv$rH$#0EaTa~*@PHb2cb^sM-dmmU9^zea5w;GH{##)f z70s~PI9&;^%aTGQ9YD-|X&m{${fhzXCK~@nCW}W)^nUi(96l3$gAroJNd`9BN zUzd*%kiG=UNMm=_?vEGS&mx>)RU&Grj@f@+RPb^*C8q)5Qmlp0GomoH-_B`G z7GtJ~1IxP}HSr53d&*x25i>}|8-{tC-s%ll-#I#COhY&^y}qmsU_V5q`zg!BU`1FI zCL-KAm@M{g)1t-Yo78~DAU6M~-^A29a-IWuMA+llqAxu|A*T-;9nw^6gSA@Yb6t|X zNQKEak4~!jIcqs)nQ;HM5Ku;=eu4WCO81Ef2a0nl6P?-yv6ILARvkV%*+g{}@S6+> zc)n1bSAv^l7Haan#H>ALc~V`2CmZ&5m{&cD7?_!p70@q!NW_+(1z`N9#1A2?nE4el zqzA?U3%pHV0<2`i@JvR}zgh5KJ%0Qd?+U&%n(|X{;IDrfOnF{h}qqa z8)4fg)88fiRAo36crjE8A(EDX)BD`ET}4zSS$Cs9Pgd&tJAwf-wFDDuR-OzQ)#h7% z#*)hrI=%NTKOmiDiv_NOwPf}-I=xU86*e3~WjYCI!txtkJ;_{v=Y$i3%KdF+%iw9U z_yM;S`kC3a%IPxq|VWMOzr$o()D{fBpsYUcemG?Fa5 zxP5c5OK?!ylleZFfG_MkV2X2v``>WbV4uCIT_DE0Y`b@FF(ZD)?i+L`geTq0BN}6> z=f^7oc2Pe%|1F6RM)j++GV~c&N)umta`Wcxf%lmJR;-~kIQCh`IVjFu%JOv>cW zJA!(#A_iC#l@6pP%N+C%JGA9^+JWtXHGbo)gixJy>$IO=piR@>8B?ix=2j$l*LK8HQ&4E)wG|0*ai9)Ul)4+Q+i38t+Eyt|mR}sD2zv zdVu}~I5J%(NX-$?hgeqK8B7u)c-F_6qJka%_Vhv^Uhig zaZ<5^s$@9FtRyZ`DkbKhTT`?GxHO!E%n`+Y-G0TyA~)TkQbNK5O`mWaYF}vg2KBK> z(rtNa+VOk3cu-rbBZ2l}gGIJjML$$9(c=A(Y3uWL-^X?D*&YCn(%b;2C=%J36sI$N zzfl}pN483-1+cn0p2HcXG8Zl84jI*i$@cj*T5@?#T+4D4?BVPr!lc5^WLq|0zw@yE zm=#}-epGYn$FKO(IW{ftR<1He@^_xUQcnFmkP0By3V{p&2l>)+x-eG0S?K<7yV^(w z^);@=UL}buVqIEm5by@aaWRBFWzIk8gWToB#Yf6|TiUR;LKdBDhOOGFBg_N?1uJC2 zNGA~9s(WuX6mZ-;KG~X&%|Hq#_ncA)+PcX9(9^<*6_yg#aZ+W#15prg+tDLwFqdn$ z(o)RQ8gJa_0aBt;!LaT8#$VJtaX`q+_85K7He1ZCOM-Y=Zk)~9GlF5U)gaA}jW8>< zyAmFU!Y8@8FT6dO0<}uLM{YY>K&Z8NASygpd#-vxDKCuIc#l(>7&3ltORnnTI|ZJd zQNwKOZA%BM-4E#m>AO=#9brzL^jYLP&|N{Dx5ySQL%?Hc{6>PogPMvEKVM>|U{yxL zmz?8DHP(*8Y1QmW#PA=k#ju^3#{~v<-7y23x%exw>^;33eJ`j<%q@%>v*zE*9V1d! zPmVpbsbUo|*;`qHH+ zwzR%$W=rHp2_~NGs)!cmNt0&-tJP-sW7CK(^iirDB^ze~3~f03dHbvSGqa1FMrNjW z<4j4*jl=#}MSALP_8ec4*E2-8CIHAO)R^f5jA4Of9di?CeU|;oE)xz9#oAgy?TI073ghw>buS&CRpcrbo38U zQZ1~m*Jo~nDtb^JpTt{*&r_a4M;KM| z+m(zg70V{^uN?>YnxKwQ>99%jzoC*NLGp{ug%h)RQ0F93e$NK)$z?V$K=@hJwpfaz zx6P ztLI}XM)MZ2VkT;)s94eT)q`9<>YCPEm6PR$!>8Ywfn@W zj(}jEmkXbFQo}%$$Th0mN*79-x**&Puz9J~@?f#pM)YNdbz8)irFl;_IP(L%L6_lH zzM9O-_y;|2&QeVD1oZ`0S?tK&SkA+M-f|k`ZXPrRP<f?_A1(ju6%^LF zsaY9<*K@!5W+EJdmV=981!C~IHb$6WQoI#MKo#Fi7w|XSU3tj>0K?p z&K%v<-+jJT5k4bB$}>kQ5`54kiGY(gR=mLG&=a}RYX6PsElCC^sd=!W=9KOzKXQ0s z6A&3{k-E{R*Y8R!J#&PdYuIuT2+mgE9#ojhYX6|mvm+gbPqw+#;4bi`=~&b6avYJ_ z*DMX|r+8M84^Ajy_busy>m}M54_Ek)VZ{S-x;?HjQ8UXFjvSH087BO{`766#{LOhf z2hnx!E>Re#Ldx*Jl6mhNsv4*|LgAf0L1j9phR0?%o`kkYUn&n+a7H3SovbTn*^aSFmNiVf;j&(%)TgEO1)Q>f8~A!X7W0IO#1n zN%#|&7Vm{+O00}k*6C!K=4WHMR*9`zKVg#n>;V0c>;2|BkN3Y0?}YfzPcA}V-fkXi zIx>~qh$WBM-|3EU<<50+O;I3ZTJVwudwsH+5|aX3M2qALWEZvXUl41flhJ?3f>OH_ zJ4L>#lC-QTESGvm5A(#JxXnq1(ndcTYUSBha^-O3mT_?$-pP&>{Xp?EG~~=$4*3M2 z8}=`aFaF6Nykh6&gG&yN+yC%XwZ%<9D{1V-WJ(5+fCSaFC8K`^X?^>_#ePwHQ@xoe z#MCP!Xq#}sRk#e53=#tJ@g-0fz2x?xSc(b2Q4Am?p3HjH;F7z`XME1L>Aq)@ zVEoXmC*sfH-({GXk<^;&X>egK=<5bMUB_r0!2gqYLS|%9>kDQIz&Xy` zQs`w8CfsyYAwNgb_uH(mtABF0B!Pj7;>VY0Hiw?jmNJ0FB0>$*r$X)2SvcI6hEJ<& z2fz02`5sbwFEipwa%j&wzP)DOu8psGR>k2&zq=j^NZV5bVu~sw4{`-^{hiA@| zf*TPLaobDNYI0bRpV5Vhw_e&2!lNuVB9CqA712*FP-$^XRl4A&MwfN}>uob{91`M_ zC7XYIJSBIMG0UeUdfgYml7u)BYiu!xBE5xd`7+pFCl~@4%Qj>1CKXW`C*I5By5FI-Ie}N1 z6K$4RdJ~GX0Y0_=1L#BxPpQkvCO`={k9AzFhF(ZUk`=07aqkSrs72FTzQh!w%)oc= z+jL&Gw+ltNSV1dZL1e8@5vwt@L8d4Ve8Z7BGBr<2i>{4f)re5{H~c*M8%OaEFjCyJ zdN4CV_h6DvIdM8HUEcWnDP?2l3C+t8RXA3By;C+8qck?v$hVHle1lna+diq;n)wB9 z29yUCn!xt1r#;$oa5px>u|$V=YaEvvaK0U*0LK{XNN_YGx$?yR!E2PWPG)z~X-UNY zg&R(nsU$4shXeTzr@Gc%3x!q=X;XM|AS|befmyt3FXuZquqU3gS1)Ay9mDEn3Rlo& zu=b2;aaY<1c&Dy1G!H^VpT*A@u8myBvZ3%%%|g zl5|JKKZ_^N@rDsck1WFGQSS=Dkuz5&F6MDy`PP5v^eZMTh!OZZ@i?E#hrcS{2$Z0= z8KTeq&tGM|BZB{rVOF@SSEe`08b)4T{=dBY;V;)}?1{VmzktmDJO;bD)0d<3*1y*L zn{tW%^&srO-SvN1l>g4Vv;VJlQ$aICNDNYO|X^$g9yPSRGEb@zPr?Is*zgE}Rh$pE&flNTZ|rBErjZPa@$;GD1cdNrEPx|N&`?7UF067pGQ&%EG_ zG47r&axjbC^(P+eVjmlcioIj}P~Km%{e3EdmiyprXmm&v(&{d!;>(sfl;U%fO6mx; z=&v`npzTK%>YAlbL}>}J^YFssBFu42bQMd#pJ&ksi>|l0T*7~^ZUJ!_3(6MO&XT+| zNwA2^d-HW>!MoU#%X5#A$@ka)&UgQ`xX1N zN>a1ye|aT*zk4_Ny=Huwr9CpN|FZpiyeD0xyl9nhE*5g5iDJwX^J?OG!|6fe4Z~P} zFz*D?y>FfmN4O)=VD7wArWH%hxX-w~VXG>?(AJ;h z$7C~@hm|K;f|sNfW|#-iL|?SVPt1**i_1IS7d@S;@Y(V}?|{rKZKnvs>JxWP?qO(8 za;4@}`>tF!b#sbQq)z8$P%bR!-Uo1X`NFFv{jO2unh+?md+|@O>^yj_fm=Bxyj!8*MNq$|mk$;y zS}&&0jvF+GAo&&4pY*#!C_D|x0^nAICJw$+;7$lgoCiS|_u%JxZmKQhVYX?Z6Yht#s>?wMnc)#<NNpk$9c!-De~-Y*3n$F;j(ObB7L0%Z1F3K)$$l z?asX!pWv!^M8E4GoC|@x*eswANP*bb=Ze zqY0F`ZB)c2Mk`>~7|dE=G)7+cmrvpyWOCwRX0G-}E-RR!8dQXFg=#v76BCu>if4M9 zL%0YoBgsY+9#M4Z$j2&9$!DQiw7kM3+op9^H4{l65BOO5#(^pidxM-q-{%>_>D6xn zmOOEq8QF+_xhT&diO1oX?o`%8hc6fCUrpkeA^5_7u#}^S3-LbR z8I6lp&Wb?43T=maKh8x75cBy+uqlA9TfkD&kbT#0e8R^J0UQ3lEU;3X1R1e)H5Few`hz1lN&fWYvAt5x0*etvY7`hA&fo-La z?pL8CWes9!X`Ese@M%q%Vf1T|x-rJBa;%lu5HxHdoK3Y^(zlx~&dfe%vkX7sGqBP{ z^&a)7+pEoJ%O*A39DsKR&)sNg(bS)E`3@D0lRQj;7xe@=$J-e9Ag`kb!SF}QlTXjX zA{I^sCfYk1Hag5ZN6=4pC;lnfsP1<7_h!W;pt@h=fIipd`0JsNaC}j! z%+cAuywWp{Z(WTRSuhR_g>d%qmcNo~wu`pUS+x6R%z7iv+>6r8F0NAI!8>06Jm}7T zNi$@-wNy1;-t{5ogngEJXy(z}^>Ei$TTvO!ylOJ%Ub-h2alVvX(7p0V89Sb@GVPm( zI?h?mH&%^(@ycv!Aq?%@V-B@rb+xRqi4o5&iaExnIP^RM#5_r`Uo*gz1Ug9^XjXcB z^~k^~c|ff730teOWVRxN6E;OS$D(g;5z|T({24phUcNFO+H#_FLca}pl61c=SOSB^ z^{Lss2Fhlq?bC_#NCa8@%{-&WHdh@6ncnCaR|so{Oz8=ZE6CaHI~cWV*7U&b&=p?J zj*m|HR!Y@UVAVb1FEi7wU&;Zt0?X@>hSs@mx}wjg)o)icptiTXVsvm(9LyYiQ<#cMgsAd@?f zrknLlf^lu0@$PQze*Ky=8>zf!l~O_2h1D!%H;d>-qhBZ80|XGF$osd?S8?=eF-J>! zdG$cF1DY>}YJJCd%tkKklo8vesl-+0c7n#(yT;9QvL~rSEvNNaTuOCSew{4IlbI?j zELN+u=_!p^T?HH)o6AV-%z)qC(o`0U?3~@~IF)7#Q z3ly%qwl_m<9|HmP!r*R9I2F?sXO1f?H;fQ<7yKp1D- zuy&ZXjYKyab-T5EO!G_%xl`7EDwC00#7*io{4eVYuug>z?9%d82Ow!j@*>UjUm;JZTXX6s?16?B|hpxWxrUiKSeg9-K)ZmP<1gG%> zS)nb8xBkvE($4U;{df7WSSbSkccaKa;Rm_+FK#p(K-?eSVKuYef6!2DXox zo^Dd{S&6SR*IF+3@Wx#vvfUVi{%AY=W1G3fdMYu)PzwXi)jAOIDKn>1R1RE8Xat4Mc3KD%Ec$MZz`}WS&Qt5nYYQou@Ml|hQ0PfH)gP8_m7`V*KG4? zQuE}*-I8XT8tAc<9r*V8qeW6S*1E?Ss~UhhpdWXp+Ls69YeAlKbFcg9NMRv(Vr_Ei z*oj(%^lQdRr$$g6;gI)NI`t2^D3uC0$W+HD)+Ri{CK^*Gz0^Ol^ssFJk=!TBwOo|K zJi|tpBeEaq3hWsM+3%17_fLf?y6K{-gRjJV z$+(7B2%uzaLte+(JH^99W$5c=S&9T}mw|U0Cqbn?3B&qAm@~vTNq5d&Js=pQ>c`(C z(-VVTmN|7an%)|I0?xa?M(}4DGv&t4AGt?yZiLp>tv&U-_UMHg3%$2yM?F4Z2YfW> zaFI7liJBdi)o9}x+K$Yi;KO_zwev({M@BYWqO2e zFHkil9Oooizg~JZv53m-2UB14ohhDc^vL-4{Um3@?1b!>=GN5B?d@~+PQbL!oyCOTT`r&{rP6pk+6aY>Cf=nzY$Dc5*m z?ZYH5xn{PwZ22L4-WsbPr2WuCruA2}Aut7V62`5WH&ID7rS+)QI(wmapanAK>D$``SXnK@192Ly@Ih5O+YakpF+HOlQZ^S`_q^m zNM1$SfR#R-!?(>*0SYB{k8z&TA8mr*YGBt0azspKr8n?X{I9cBuEkBlsZ#xyJM~|g ziVq{{{vI!niORMejt2J=VC!Xd`v>_QdseFBK>|A(=+4r;sW{&sIF&=xDu;!@nLxR>Hk+#QO$J4uQ= z6n7`MyQjDnDDF7bjWA8aL@Bf+1B-!7cz1O-v*W#J+^!BDXF9loiL5pc* znX23#r9jXJ!YzzFhzBTUCkAsw_QY-47o=REpOLq((h^Ps(}Z0lN1@Mr!-P+BT5>DY z9hOMzJ_W&BF3k<`-tKauE)8en zoT}XtY3~~fVrZ(vi*_E2$z>X8!>C}niz3CE;fs)BCf$I`Gn2{H|b>=rWI{+X)F zG~aWIEff=K+P74T~2v?V7BW$dl+Yw{xYh4AhE?Cv1%5!q1%WPSd}S!r#{N#lu*LOiQQPyiRa&RYZFo&1xpUV~ zdgc%BTF#1Kht=-YrA@3M%bgs} z-lv{Q#Bl0@lAEmZ3#V`c93U>T9M-1Q{eW#G`BN9J{Xf}o3x^3`4};9P@Rb%ZRhMmC z`E+#2#xDsHGQ%Dm1S3VepbL#?P@=VpFk!7kfo#F~nN7z@_^j>mE(No$;gosTYijDQ zM2WNw;IT?4Nv?KfTXy6GeT=X+0Xeo=|8UDTyy!}(XFN6|qhNniU1G7YGi|NmHN3Hk z3pm-5^@MmyA^IMw@YRc)9Wa*WWhW@8ah~fsmSo4LP$yc&6ft{$t@^XJ-S{>w;eH{p zul5dsSR`BYd7J6>0UBtp{j+(MA4bEW(XZ>(QL1tzH)*5xP<)44j>mD?B2$qVUft(dx}TOmrY z;!v;C^nv9394~Sv%!zy zMLr#Ff<}_BCJFwRiu?K81#Z+Nuq%?RNhL zlw-872Zaj&zJ{6!ubh8vC&#)@s1ymd8Vje2XIc@KyQ-reUoONS3Rv{?TRl^}^w9Pk zWplTe-gPZwaBlguJ5HW<`*x1==wTx{uYEeJX~$r0jpgj@Y)OJHY|>9{W;%l7^PS!5 zA$(kY+{w+J%=O_RMWG%*G+WggG_O~|ZtKVee&_73*YKwYmoF^o&#adB;cnjFLG_9Dp01v*e}2U9Lm!fusu=hFF zvaS8Nf0*Tm>%V-VZ!sLj7sQf@)#agUINLt|;sDux_lpPMD$tj#?UAvq!zwJSfdSHP zeNWhtUjO#^nNxe?HW+qi&>ueXyI5D@QR1FjgLJ~K4L4|%Hk+K=1gXBlt!}L6rPW=c8-AJBy93PZhP=isRI4-rl z&c|nPbYywq$n9}Tx$2wlHc4SA72{9AZV4lM0Id&9K=jJBH_Wviy*}wp2b`(#!`FZL z*@?Fw5AITrX{WkvwrVa>6CaldefeHJdYh$k41-o*R%~v*Z?QImn|UqU+pZME4*#jd zM}$2-vP`NnjD)8cGENfDCdFHT?`jF<2LmhnsLI=T+cOC8JQ2cB}s14fqG;|o>qB0c-z06tT1$CsLyrOLedT~$TZ z9Gk;0=9!SB9pi{&q;GXYw5>ca+k(su(j zb>r(9V0v#4uI5>pag}5649-H=dKq&ve6PvNm5^we&k6V1*)-75BEVT?Q%8Y0gcxUb z=-$Va`Bso*rAML)xwvM_dh%>Zi$y3PIMEYR9%oj7!?$b%!1~e#GkB|1n#iJp6@eB53^RE9=a{NU{VWW^6IBTl=Qedr)9s(%Ya(hS>&m4z{KU3v zqL;pco?U^>gSAoQbd$SGrjFkjMG(NAe`#pqv8#PmiU%!iQ-Ls+jB6>AMlBw2g2@SKr+ zKkOg%l zT*2`4Gq%4N+Wr$%39K@C{wr653rz3%f-xrk{?-h8aZ9W8%|SAkt-lWuqI>hqP-Z1v z0HDwio*N&J920HWV;&ovp8Q-5!NMHD6@M9Pit*sb&X9hy)Yi-dXjFTV-#FF-@c&J% zRAwniyhXN^XE3EHmGD^`d7qaosA6)!0)QPB1S0Dd518{WvwmCw>OVMM54R{uVO!hWPwym>nsy-Di!C+91{zRNYG z8s`vSHK61Il<9o3rwkp4vb}aU_7m-lGptiA_GnoeAHL->tK@=Fq34CcA_cXk={wq< z3T{r#8Mxa!7?@*ALb z0O0%4Rk|jr&OvuAcvu?pnh53KWS|?#a*t)V!Az@h%<~gJi`*oc5$Z?ymxdgLJw7wO z=&^5if0ETmZW@0x0mf;*S!)piN$!mPB!H^VFK}=Gd8zyN5`l6{W~BmeP(&P{daQ0| zD)3RC3e(wJ8!OVrZPH&nN$>8#xsM+MIf4P+9} zhtl1qz)8HxvaZ6gXrtrG3WoL3-!ELtmHR5a$=b5md;OD{RZJbro_d|SP`+-$srs~~ zm)mO)y`t!-w^5&R;>rx|SSq9c(T%A3G+FtkHiE2E?Jlq}C_xHBQWanH&NYKxi1D}w zZEe?+*a;Kw>XpgJn#lL%A1s!FEaFVmT8=U0ZV*Ru{6IFGg!VKQJ~-Ml+cY3#b$wN; zqW2^<6aIRFDggQRSa0Avj&jF*IT{A|tb zS?0Q_@gmqB{}A<;47tB1-h?Ar*D)A3oyb~+7}x02NFAzJ!OJKwJypRCdqD`N4yRQDoeI@vqD z)SF~e{a)PuRD6Uk{OB8aoBDHTP-0b&CCf`m)Z@dl++6i-4W%%%LwSG3`ksHQ8Ry_B z1@@9ciH!A8r^lbNejjUpJ{4koF&O(XwJs3{M+OJYO7bs(!3uXi^CTurGGnLt2dXNN zeQD54pTzlEgFGI^GP@;}Xiw7xf^ziFQo#U1Aod^wNFV2yfmoo6gdmV43j>eSB zh|b=Mz#2H+8GpVZDuvZ!yU+N%B?W)&?vJ{z4OhEmy%wy@TIG9eW^1Qs4u4>M&I~ZC zPh{d~b}mbauoh5|5Rf@3Qc5!H^s5^Z{DC{Bs`qUn2@EyeL8HmL!gYY~L36yBfq9kH~U&A9M7Uf9$#_nc!&!8^FAPRFTLwRdyCS|Dy$9^G; z;_m)`*w(!OLSg1VZqbP(!BXOMNCffN$Z%<*=RbRmZR5HVB$b5Wb488j*Uus%Y0QSM z8_gE-nAj|RO?r_RoNuS2i2*1cRq6QEvKx_yCuy2AG$Y+U^g+u-I?3EA?%b%g*IB^? z-dro?jACX@@a?*Fl+9@p6q{j#^zGc@j+-Kgi1i#?BL7$Pp1^l}pjI`qk9}K?=>+GS z`4nnN0?ul%hx|19g%pCdvu}Oq>HE;e5}jV}djCMU&-Qk7nTc#V)7{skASSM2C!Twz zoq-|PIX1`D!Ba-Ldbtid6Vc?ClZH)@8(XQJ7pHp-#R<{h!bx?u>e+9*7BygU-yE8S zr)Dxpc0TN-Y*hOSFIL=3%+lt3+pvRT?bFwl!~%uA4ACS>Qt;w1W2!l_9JZa>!2 zk?GLckGuzO9Z{y1ecCG{V|Q6Fx1F!W{7X;QZd@v><-61j%pJ2b zJ~;mEaIYY{5Iq0VR$HOa8DVFPz-H=)5=0p;)Rgi_{9XM8`wi2599}ia(owd%TxrW{Cf$M`YVqem>VNXgeYF zCEPal2~J)ewrtj=Y`aQ9lAmI9xEhNiMfmyv&0O;zuLvrFndA^VPDG|@Jp#s*L zHhmlXLbb{AMk0H7RsWC)g?#I3zf3RKZC4^*X+WyuZwUv#ia3c?rS;ymdnE@QZS!)b z4*(K$E+!90ew}166L2E{Eq&_GOk!Fb|IC=(QW2MSQoETJTVkLOZmj+6xgBdVzqJ?o zsmgj%Aj`1|Kj<1G`%9=fin~Kx8&z?@7v$4H46wEmCSG^q!A6XWsjAc&!~P4N{oE$k zLHm3F&`RS%Ie4KGaV}~me3xzi243ZdA$z{^ZBT8MsG<$CUlH|dbw!geH1Y%2pGZ%L zKekePwS&i`Va3*0r~AN1RSlWs;mM~elL1nbWHh(Ir&d41@2z1~b<|6h5&Q=+%MLTo ziP`4OpD&SQ7V8P(!FLjDLZo}WVt;{&1?vVVc2gs6#s|3$o_l#}n0uio z3iB)u+svQVK7@45Zz%VD;vZri3vs$H0E;yrFscsg-+@x7u-+arA(2%tagiZh41qNzV%zV(U4-b=&3$=5oJjA8kjth=4E?eteJ@xjb&iY9%JC zdocdd%l+q6a!9%B^d$$n!0*`*?MgEXl{TFJrsFn?^4#;_*wy~ zx$n)=su(FTQ7dD|+gs6f=Vq)0+4%6?g)0!EBf82NQ5j`Vw?T2O+=}DVNMvP1Q1_m) zboxs`qbm9xI_J6uDHQCo004!?3a?eltXY|QZmU(Va7{}tWm_*QNBI$E-v@52Ver7y z{6*!VKYqXdW@rcdto()`=F0DKT}b_?v?n(OrCsFiT|N-CKT8HZAx(@?0sqR$I#`8z zgGR`fV4O@v8^R^Nk8|GcD$llyl2NW`5|m0mb?580zS5i=r!k>(%*h>!)c3hGsMS<{JFxHr5E=I+$~=b%gDMdypdoi*eiI{eh*uqBXdBG0oumW`6S z9Ue5vrS;(VppH6lB@Z7gNSrVk_H=d7$AO+hC572<9JZl>or-F>%alc{cID`alx`=V zisjwV?uvEd=AK$x^V?jXp!iS!jEEU{)#0ORHD;?`{g(Z1mxKjZFF6HJDsf1B12#It#3d+Zr0oZt2xj@~Ezts{$IgSveq zTcvCq?Lhwb11)_+5ZkCZjKWi`6s5&5C8#W#X4aJbXNivdzBwf!V%9$ST`RnJ0}OI8 zKH~SP%=Yg@xOrDaMf6rWsU~zc+O{RlUY31-YckN&?Q7YAzZ}KZjMU!7u+c8P9nmj( zLXWw-1>wT)fB4OLU(5Y6EAJhHX1)F@ownK$ezz9->!X)vmHKy>784ObP3!Q2VE2dT z4~K)h2Xvb@_?F$E<7Fv-IvlO4LM=2+(~L5g*;QDCv1h2POUcaldSaR}fAW>bS$_!c zZURn4d*6y`?Y19#v~f2;YI$6fm_vYO>Nk(5`HiQ!6zM*>%f!ys-Kg#snaMZ=uLc|A zk2GvWoJzOgC#ueNj96009J{%G0uZD<7rlEa7s3cSaoX)e0k%pETlPv1MTWmzEciiBpF)7w5+k$uJk~Z7&kmNCzM6GOxB)3yRCEo^L)O96qsAvFOiX5pk=%+sSR~_Il8|`{T%%& z$W;>;t0ZBq;T;rWU{^Nz~`2l!?& z9NM~NCNq~zFW1nKLu>YY(N!nqz9#*WXbO?GO?%1^$T3rDcRhCK3LHfgIG??A{j&rf zD_)~|<4iUJGgs(SSQ!rCM{GO6`Yp>6IKsMEI*@n^+)&dSrCY}3Dw?BS{&DGN7Ee6! z=Y!Bpo#ZE)6}Q+r6EiXSsN-(unr4Y)P};Bi>rGSr%*rnW2Fc)!wn)h^#y00((fyR> z*9b5tqDceAWLW35CDJaS=41_N;I_QiQm=@0y!#`OFXCIsx^uLvCgegZ*3mD+cWeAz zSmC+k?l$Teph>d-cz5{un-)l-ijl!>J=L;2wMpC?ndSA`!E7Rqc$Ka*iDkiFm%rkK zFBtd{H)I}vIrL}t=QU-ZcKW69X4wA3iO0oT1pd@4DC)`-vZLG%5F_b$@TO2_s9`fG+Edo+3KLXf2U;*aAdqd4R0xo$_#}YkTlO zc@=3DNjTCm(aVKO5o6oG3iJ9&t0;K9f)g?P&Z9fj0b@P?1jFcZVD(MO21@q*DqXt>&>zUeU!5@-unvIzu?Blq00y|cD8zS zpq9u#z@k#hU-_SEB{REcJ2pJmwLSm?yh|`)+`~i|!fqQvSNP^x2{v>eW)VA(##f5_V=bC!-W&0{TedZgSWC>1_wl(e<8A5s z#V>@1-TB$%9w=as5xbqPbXn9zpEU1deU{71}k}hg0+9-Cnuc@^7@Y!k~@Y zB|Ebmw38LSKjlAgG78K*q(@f$aqb`16ekHdmVkfuczKv!=31)JVQnIFc~pW#$06r=;%mVh(6b z!shc<$Lh<|)Di_7G}HJ>S}9}#)?ITq_T8O7=tol5U03#XSPc4A2lwhEZj89%$jat| zQos*nmZpG&kc%^|rk(P7Ryp#)fei0&xCTTWklw1yn7oJkh7|m2R5`Fqqe?XG_gl|> z?+HR2VL86);|Yfs{2^C8?JXg9rgSQi0y z$l9A_Cgr!lwMGT(SJB$7-`*B3TTOf|Dk;D^7PU06#uzhL4s`1hJGIhXLY9Nx&lX)9 zYF!V|SQ#GTAt*?d@jTXlfhIg-o9Kf92`Z$nV!5^BKW~?_Q%?I{dL~>+o~#NN3wsjt z-}Agd1>bK#W?yDCMC1YxF z<|G1KP#m?GN=KH@=i&ry_l16xJgEHXza8&sqIRw{VALO2lQ>p{Q4QHBJm#OStR_tY zuJtY)8gW0CdG|0690da4&$*-fymNqTwati51{tN@^Vj~QzXo`NlI@jSDAl|?Q*wzB zDYmrH<~TskQMw(~UuoEHlB%VPL>WqY zAS55ioAr8Kg@TbqAGdp!^allWOW#EaY5{JiHz?l*zvJM_ZG!10Kd zTws1&%Ef@2?FlrZanV^kLyk{hmZGR$UpG-ye)@z5LCUAT>Ex?O_2}X#zEDaXPx7U& zL_@S5volm;QfR4l>f^fE82CD|&QYZ3Aa$w!o|-}W2@+MkhFDME>Qj~#HdKAkAJfq1 zNI-JgVeUz^A@~W7P|#GfH%na1p(PWL-mQ&U-Ghr?QK^f7`Gndd(s>*XIx5#(#G_Sa zHlF&v9X?F0Cv)vG?D2zW9}i&>rIS7PUFv1k-?xm#am&N{*D8Kp8Mms#GL=oHCEXUv zm3bRQk8|89F@%9+Zaxp8Zgnd76{8iDz}ssNGwdNCFL8AqDxjmR@-}c9-G!+HIv1Y1Fgj@nVRz8go;j504HN_4mRVV|uSwRXXQ| zS2AL+Y=2FkRX-OZ#!9+8?=SV=TjP3soqjYjGqj6x70o9ZW&> z2=X({Gp%rH1TE$F%+oPLY#mi{p7$FP`I&a8_6``SMIrPEsb@ z@PqdF;O;0!#-K78V263YGG^N2lSpTk&{=iJyDV!xo7Ew_+3bvjcN&s|PYn4$>$Ij_<|qe9N%TD7XW)01u@MFgv z+L@Qj#<{{}O|PK^?46g<-EQTc&K}8jJ6Q!<;o0>i-k{!%knciA<-{WrG`9Itz^W;l z-fIE1cauW&#B6U1_s(?LX5G2D8ue7T z>35&44`hr*^mApl9@q4+x;u#HcEuS|Fq2^f)Gn$jCPdN13_;1z^i|5mL7cgjo4@Ds zTz#HhLdfFe#GsOi4Ex9*PC{d}KS^$Btboe0d$-qQ39f~#L8|Q6vIZxIfp;|xN9jKn zj{n`la{G%QpNi+(Jj=_sFevjaf*Iw@pqDqrKv~h3Je(Lx9HM)LM){-fRT)7|4fBFD zZyE}0()EC42rgDxH+=tvr$|l{!{%JKr{m&GxjTdqW3_jmaYLb8kY$~c{)2w!$MneCW^65N2Z65V1n@e{kg^I&xremPnf#C zm`2u+dHyFao}K{-s7_eoL?O6FI?#8Ggy|^e(=Pp1E3B&>oHigi z(B)q{w<&0P0h~i8DIC@4tTNI|iDOxF=_o&cEy=7KLA{ALqG}Q4rfw9r8~WK3_uE}- zgvBNvF=1rN=Ffp_jABpaIE)5mSGcC4|lqUU)wJo)ykSS#G zR)^0uk5y|qf^i80C?O5s7MWi>i~LgmZ(+JRO=ZLI(8=^W09%eT=hsL5ds)d3K8zW{ zez(b)KdWTlB45N|-HxwmArwf^VAk)SXG+MXFLPY}k}2kG8sk-Xz^ zh6V7|dHHl`Z@qaI7NCQB=JU;HZ50i7!`OUz65t5vYcQD>Uj%~m}3G-ZsQA|EV*}ZZU zHkKXJ4Xx?QjCzdxYOR8wSo`#>;3nV9Xl++u2XBl%C2&pzlWBR*%1Ib< z@R>s5H%PoB8RHn`uTNp`C;=nDyX&UJ*ddbdQSEn;)V>i(6PjcPu&$bNQIzU^ECVrW z8)r{4jG|W%OIfET#0U3p)Y4lOJd)-;zS%3zZ*EIc1_F`f=AN?;N>CMm=PkZ}O(t4o z#fYCZ{u^eJ-F*Q}iq@oS1gU6I{bc6tEfk*5#N9n-WTp(=ORWCy8*~AZT zG5d(%;sJZ&LB`Nt`?oOV1=@ee&~-!gulo>hv$kdz+4tru zb8mod+C6R>ofh-B;N^OP>*I4Z{N6VK9<9BdKKKST6 z#q#oby!WQr=D1Ax%}WOg#WFv!Nrie1E#I^3hHolUZ;}` z*v1$ah$>RDlw@aA4FvXZf2)8!hL6nr8_@wD#*PnYsK&^w6;A5u1Z4X(e5=v>Ok=K~ z`y8kkC#m?GvX=0E?!v6$%3!;UbeSRuza0yi*y=rwOzQL5+20nQXVM$k;G{qdKOjRx z^p1h_iDYv{JgPg;TIraU+l3UYdPy!f4l<-g2oiX~RhbP#;@rN9Dr)_M9kxh-u5D-LrK66y{cGa7j>^Wo!V(*;MOvy)-=hj8TO{l?tH%@0b)8MD7Z0*DZYCBB6bQwkN!V5(AT8heC>>3P5Pk4C0mnNUev$I(4Zh1d6uH`EkV5^>9oSnWE=Ul$XHKmVI zflo{}`woz_)+>-zk!Yez!L6sg3hK2F_~d7Ga!eeE+W{1-R#k@z*g&q|G`T;9)0h+* zc^66IS8u#twVB42FR&Z(z5GW5G(%#d5GIn;_g6ake}+N0tg`>#VUQ2MSLYaP;BhUt zE9@+25p9h2?~uEMn!xwyx&)b>mUuCAYtQi+9u|?>xxd zk0yeLOk;U*+~rak-0qpCPa%$`B8?)$KknVyl{Bb^CTsOZaRqTRAEUo^1v5{yf5mOr z%wzg2v+qQNl4F&wd;?Q@MV#nN|K>7cSq<)$&b<|tAa|FM&KcxkD`;PZ*>4b=^yyz2 zSa+&7^F%{VnyD9`P!K|*=st8%S8QRe;XJdCrR4s`^;WFr zCk7+DF6+YyN~OtMGSZ%)0CCMEd)&C)b@BmwDcj(ub(X}k?1q~UCK{Pt`Rxa-oR_~N z+lIa7KM1+bN$6a~yHm2COsjsVoRVGG9cAQY7>Tx7QU{S0x)c4?!O%TSY3<#!Msa3k zWuy(}sH?Wqrnf6FkCm1&J?wBxtNAFz2^P+%dW%CJ zerZUzw!cr1v)@9mLp7Yo)z%p|CB(&yH$YWj_Y4<wj6-g5k=C z2{jp3K?UFA8ksaqup8ZiRp*XnMq0sNP~J>CyJb!yT>LP`yUuMg@<_49?&Cv<=OR;3y0lKuEb_JPs|U}TVF`i3xW0E)mAOuVG>3!*sPRtIVq<u3%`BA0q; zl;Up?KSBrOwY7WnD4Lj9PqmxN8+=+@UMycSXiY)}vpVYvOJI+e4) zJNh|5|NG!hHa+~G;Gob~G8d4vsuk$gCkIu5(KmL$*o>zMU0KvgG$9sjrbXJ>q_QJy zh@#x~$A5u;*I7l}{{sI2tMrR28SKUOc?FI;kyt801dP&brL7W++Aj!dGE}~f0-dlhu8j~ zg&*EAyL!0%hf6+-=%=LoNE#V?Z83-8)tAv*!d_OHPQ;01cR7VvO;Eto|KD}<`uugl8&>1OjH+2JgNTwSg57d4`eU;$N z0PXn84)+gcR$BarD|Pz6xY8tSnXd;|b>Oc~SCNbcNssSe`f@~Yl52ica{|yDp+20; zy4UGoM$YQ44t7Q_MOCD8J}1~2`w6o`grpd}W^jKC97~3F@vOGFz0`C~{~&vtGcc@V zYasNh0?l0}Tm_M8&!tqij@o=864*fTc3}MZ%15hneeitLlY zugRl4VkNzv*3poJ+I%;h2CC{t;%|wXN{^67=fzg|#Ij9=1cKU}T%+7sZ5XrXAv6Es z%|)eUwOIM@@g#;hn>ULv4JeO$WHeLPChCbSZ1Qza06a`QxBCkkEJbrM1W`?=wQ_A~5wb?KK03XghB0gN}M6wZxIP#MCcU6j4#dO)#@-6@IUR1DM;=;Bw>|Y1=S{)iT zA)$f@f>_&bHbyG)DpU!F(nP9&Kcoht)ARUtCi345t%v^Q5WDu+@l8(C0AB&`=7Cqu z@G6Z!-M5}$R_VN6I@&QD$7V`$RMd{}zF!q>)i&l*YDwm(t{GwIOV`H1CoY1~%^|2h z{x#4OGIskfc$}nod5=+j-yQeiZu@J_#hSXixy*jF?Eq)Fr{InD)t+*W<#2PnsaYQ_ zI##{D`cCI!qtj2AMNETqG#~%+uExk#6lhERR6@beu&(259#RPa zXFN<6lAh>wi4+khy1Rx)wF|RkHNCKI=^E2FB0;Jc(Y)$ILi_9q@KPyt#&AZ;zbool zgak^Z9dvT%7cSX~Xw63Z)x41IwC!E4_3K^9<2S_{u0d*Oa^}3pSNRr4OCnO<=`RzC z!+Gw$f*QmhM{|34jC*c9u(aE(;~vtV*Hj5yW_-wm)}8LDb6G@aXg89ef0$_xkFe?*zPBZ?_`sS&WH9|PI9+pwel+O3d2{`rximMWukw>yIz^R} zy&eP9Tmjx(hoLXh@b7tkYwovIFI5||yBPB3p@V#UssCp&#k(mEDf^r$fv*$$^;)aGTB#7cRlyL{ zqR^<&R;&8i#kwsi!?VZXo%jDmYZd&|>R0h_JaLDshh)@kzgKMy{}e;8k__Jd&W_gs zY%70ODR8iv4T?`RPPd<9krlR)U0xf|3nKz1bzOwIy6@a6Y6m9aO4&@R^s zNnG5%oaa8F^_`hO;qukVfe{DzaZ@$UkK?wq65>D=E&(t8}IyN)hKp-Niv(|$olW1cVPla5Un(Chw73(YixsUWMxu#q5{PDVC!+&#NDg*Cxy z2VRLnN}Lc%2G@6;&1oY+T=}D5@4mWE$Hx-HOKfCQ2*5uOoraAfl5KIRMSIG>b%hQE zjaQf5HPz!qH&)j|+m<(cohfiu?$-{zSub;WtBrB*Ivv>1wrnnHpM~@2=v=pxk;>`G z;8e7O0MptAP~iWH5>*2=>7tJpe`se$&gDyMBW=^C_{R68(9%f8%F~Wb6GbsgMrU4q zWSPT{$E!Co)ZO9Q_9*f#{$s-bxZ?CGBx$^R8;OiAbK1honS>Sui&ji(?{{G`7Xt3_ z6Gx1jhRB6fvDsgJwgMggBHhlBc1l=vQo>+V>zy0qL5`p2`ulkM z5dLHxy6=8SpJ9=xQhmsffibd8(T}<@f#+rBRlB3h^v*_Yl$^L_+BPtGl2XqAif~P?yovEuin^8iS_@7_+T+8Ai5t(b``jp z_!tlp{6N`9+&|$mG?!ByUY0(|GaiviE+Zw8pm#GvmIy;x&#%XbR%0rQ9Md|ufKpK= z4L=AopQsSJy_DJA|+DC_#yV9-czLPT1eeS)iBIt?jU%$?{+Q?4!#lL7H6=XgBNDt7^)LzOymaBmO( zd1gtbg}JIaBiv0K?)3|iU&VINWOSH1{l&{t-|1`9Q?;h;i6m1b5T!{sraR7$EGO2- z$qHnuil_=l9SCxqYN%D&{)_gQ9CwPmg2nY-Rc_pb34Fi141Fvj^1rvq>0xLgccn3X z9$7ZKg0fZgntXm%SJ;ojiS2jo4}W>#sUbYK(zW=pM6vn0>-UYOgJIUt=|$Pw(iw55 zQF`KqPHghr1*i7lCd)YM*F;HW)cV_!MRQn^B_}G~Xk`b@Mp1CKm*HI9lEk5!CQ(Lu9(WGEgRz!wqld&YK$h4J!y8a21 zgwj|O$6a)~-$wzUQd&M9zvqkLM0OIpf1h43dYM3pb9A#GsyF89xD((&Q}S-wS?n!d z3&(EeeEA%K3tD#}a~$cH_{y*5`+lFM^6?wA!CcE}`SOYQrX8FlYh%p?Yj_K(RyX!t z`n7EH}^p;TwDOUv;^#vFWwDe_N+$F6H^wV|tu=ah;CDFhZu{ z3HU2#Avg?M8MSv_tcYdK{3tQ~4hDJ%eC>@n2tOkXDw*ThGH*z-OkVZ({;Ob)$HH(* zXS3_pSe~$(A!tA{DLM+C!aGPo8I37WcGwZEdX#Q4c2?dx`7Vj(6Ji)kgk}+Cm^KhkPu8Hf zPHu$VBtX<4vNbp~M8We=<&85wLVX$a?^ZqmGxJh<_J3yG_KV=}En#&eilW`+%5|h! zvR_l{$(knOPM$cndr#TZeOfuqCfkY#20+x4P8N!>gms?llY(gJ5-qt(3l_ssw}Gtv zn@el%B`?Xf3h2_F+vvYCYCPHUnXMZR0vw*@(9K9B>vLWh3fBMAP@f^$OKpoDvt&Eq zsUN(>#st}f5N4v#Wva&Pk-W)v`0B`EW9EBnCYSJqe%gWRy3Lhj$>%ojNYf+{+IhH# zUd4jyR3R<{4o+%}w+*tvg64Ac_+t&Tr}qtrQMr2JxoHn- za&5PN9`8YjUr{c0xAm7Zp?`Q44TDJj$WEK<2TtKIr(^aFqnvy)iO9uQ5o5Bw>TLY^ z@m5Iv8OKpP>Hdi_oPwVdkJozBAf-ary-oSy*Lsc4AkT~RA7c{P8>`FqZ?jpmQP61)rEFJizn3I5 z=LV(|V=sr@K1fO<98xEA7;s(wGA^GP0(4x@Z2atdI#tKOzzU+gsoFQGZII4CB-sUBhC$uw2?Q3H1GO@ zjh{i6&DI=J7%qncIZK4uZkbDb;b~IilhPhvMzJPJ1$0U!8T@xKZYy5k?mmRBR;lFf<%vV)zTeqAwVYbn-yc){X9; z69bYyBl0ANt>1-423X^}!`a+@aH3r1v0&Acd@*_0g_X z{b~);-yk9j`D~#;i%hG>Z)}t-JD9!S?u-WHb<}8&RhzJnsBw}d<79>XkP4ZV$?m{H z$x8fki-A+^IjZJbXPq#s`K#q!>)2Y!VRC6|6~j`?|D&hBdPnJ=_FU01kpL=!?^kBO zpQn79W?+G`QnQwKUom{b)g@GvC}-C6Pg7vYu^n>NJx#=w$+NHeg;s{4*xH zwjOgC!8Qshu2;ez%a|;~`7ZpQKCbg>CkT`czxAPz>p?`M-qbYQ5*chw8NOFL)E5*c z-@PW`HIJV)8!KkF&QBw&liZjOP8@D=Jv~DdFTteB(`T?qag&R=@4i`xc>0tyxR)il z%<-|pbJH{l%nrT@K?=H9jKpr^`m z#jF2=z4wf2vU~bQQABP5!G>5sMCk}fuK@uO=}3!|(2Mk5LqMe}3etP;p-Hbv1f^H$ zJs>@lAP@q9Bq!+of6w#boORx{p67gfuMezER@T1uHJLrv?3v%pPs;wJ_P~uznCNyL zUh-t}EzkRa=7bT)*eoZ{A?-ps!fOe21FWOZc(vvrkDo)pTb8~_3qPX_FSo5=*`%Iz zjaMtpwW>Y9z9SRGP8H_dq1GUQ@4zCXIAPeIUfQ{n>Lo)tF`ORH54~d@wjjsXKGR)& zArTdS(6C`GAZBI(%-(LLO=UEz18*OMncVkNw7Z=(5}5-e;TeygW;Y zfNEt5y$B{^V_=_A?7bLE;|sgvh+B_Z-1n6F=VR_07*RaU#!k$Hm3Wo5Rem4KC*L{4 zlCN#|hj;NU?Abi~!x*;ku&jiXf{ZkX{s8d)1!LyO&NCptd98qQ={3PXwjXvk8Z3rh zHeZ;yQ|I`PVPX9TfoWbp;mM-|Gz(t~kF*2u`R`Bnek?46^HM(E>+hkz8kiD}cF1pw zI6coax?GV#Ia`g*b}Y01JcyRLXskw*i+|+_pTFn+Uv(p_mDy&`nX3f4xbD~ zFY(rJ*YrfRb!4=-?N` zFiw-I`XEmvKMsHJRg;ngVFXrb32i}}rd5xRr*H{{=a1z)ln~4`4 zEu#Kf1T?UoG5m1)1f%X4_kSyD$~i4$`&vVNVwH3=E$&jm^0@fsJZVX~DSu4E`Jd{m zmoX#n!SrMO4@%W+WP@%l_1-#nUC*x=r>Dh9>{JhpOhk&YD1g$+PsDGJ%EW()O({%F zOnOV5&BQ#js%gS^BRk5jwOHPgDMOV6m=wH)vtPdG7nPP~V>pDfbX-ndd zN3g`{y346_8Se@xDBk)pCyF$+jWWd8;gVL3w{gNk|F4#jDE`}YQV=qWo zccwtGt%rd4Q*WwzD=i-}X%@ zU=(qUXo*_3G|cXBr@jcbEzD8MDiBXGex?~ftc}y?Ejz3GRl-&zv>+iLp^d`rf`_(8$`dYFfwOD*d3 ze&P^1dZuY*#$m{9=k(|Ca(%V${-Bz|WRyoN-G=ffNRSIcyE{WRdLO?N#@i8vG|bBl zzD(l5=;+D|R-Z_0@j++CIK7F8X0K?^r90s66aV4VzQ#Kv832XdCv-AVHhHgvA8%H& z9M_sqth#ut^M4Rjm+8u<$h*#olawZLBWdvH{KrHbg^OUG?47qceW$Xj*T+!a9Q_S_ zS|{>tzs=)}HQph6tw2VG%k`|AaxlXr}PhShCm{YqQ4e-`VjrAf-I$nfhB61*V$tKL)x#O;5{ay%f}iUHfXd zQ;QP_vD`WjRxQVWiXNGc;=y9^uCHbf*JLHH0N}G9<9?#NQTxYhWZsu6+i?;A6ZM)m z|L)aXVY9ewlU=RP##i`l+bC_>I4BUOAMO)P`2(J4(va(VtmhRrM1SmoF2oA5VX_%F+CiD zuKXg#zpFGSbn>wmc+1(%UcCjh{uww)+&M9=LEp#x?^5FIiu>3{&ZVsRjXG~Ep>%dLtS`l z{^JiAIBGbe(JHK1{f>xvX^+evqs7hAH6|t?^XH3rb@;vdGdA;UG1y(j_H<`_zrHo6 zjRuu`XurL>jKSQzrFg3=_luyJdx3TKdFDvw-|Jja5Y>P6@aVG~K#=>KjAIY0{b^r| zJj_50|5k1`lWVj-Rs*3(LFaJo}Dq8Jw+NXF=j2nwZl8D2rGa zR$pTO8k-1Cn57o_>S8(|Jeex^!|ifOi@iNNmGLWmEN=$YXrAa@RDW?bTx=!PC1y(2 zO;De8mMxbjm5)a8O|jp3xpZ#Xv1(fH22D~J;OTM0>Xg43zkFhU`;Sa@ts39kRb+eT zwxLNs=+O8-QUteUFWi5qQ>9Jf{mBnC6_q)D{=QL*Q8osY@`>B@27LmTLIr0L)2%#L z4w{p)FM=t*cLf8aB1Qhf}mQag(aKk8i1(!e!bjRMzp!1cAtNT9q2M|@6SA|05 zj3jc;tEo%+2hZY;#jV}ZGYO4lYAM$QZ@e21`1#e(L-=fdY^p`SvE~8-YyaUP@m{fP zm#5jmyp8(OsWu2Gt!a~N@*jov{3Hhxdl$!VSgYL?IpB+Rp&@$n?6OAD$87XpJj`-? zo-#(Np{f+Mj^F%43)99N8Dssp%IOS^d#A8Y`)1nEX(Wxf!FrhP-|rjb_3HlKd@+4Q zM6}%4fX~vh<@e483c*Kw+mD>*B0FFmLL~d0e?NlGB+?08{P=Bc*-FLPf0V__<<1yb zq4DVC3ON!e)#_nP6uIZc_)c~rtNkS6)Yo14C1+O&hh*NzHf)SIa_Y-yIb4x(`N@EtV}idwj>jwyn&vbBV& z@8SIqv=U?AK=mE6ztV2@=5qtd!gx<8GK|N$1HzE9X6{c3;6j@Q#vOLcJ}s9O-8I6{ zLdLggV{{NBv7aW-YA9aou39erL3Fd>WjoIJkD{ThKXaX9-V{Abxb1#Dp*dHN`lCR; z^H{dFilq(bb8lq>n>FGo0ggmUAdu5G0?9%qL#N^m2S$S~vfo=FaHLC5iU0ha6yFZF zqtnKD*`9P;0xyY*ysCD~^+PRu)7j4-H*_R2WmHozcQRtu^y>~-kL>(uO?9bL2j z=f5@OhgZZTm#QKv^Vxc*HKu=Om&2gO2U>ph4Gm>6-@l(`!S0q!FY)iazr}=WReI)} z@cz%-|Nn1yW6zKrJNNdS3VTD;)9NS=1r^1*$Q`5Iy3r!i#`};~N|2ic%1aYiYtsHRD>EaZ;yC zxku#}VWc^(ZCvpr>2}CD{lB^&cm!g&p z6#ZTFKcoZy(ZOu}zMh^K!#evEi4H3#j=>qPPcu$AM*$J9fsbX`U$~FU84xK*PdyrT z^}f~mU`A|On!{Q=$j!}7yFex3YY_2cp~I`;CP&C`gA*ZM_5Gt=5sxV8s^7o0o7C@@ zxOD++G=3MaKN1l5iR0PH!Aq4NoXX>Im;pwzXLesQGC+@l_+HDduXlBJ7A7k*+JwuD z)zrVz*eMqd^?O%VT5Srt`<^5Y6()N9V%K7g3`y+@V+o;#?HNQ6qRgmakap)Hk@mLJ zc;%((Xs_WohD-5U-A`ZM_KZk-cW^$XKdl#2)Czky=_hoh#Us;m*?1n0 z{xu=bxad2GjH!GEwpZhs-GB89lXRj!=#{3{%Td$LBE=q7oR$Lg+hpfd4`hvexBTVt*;hHIi*%( zfR`mnwS9mK{*b>?PqqZ?)QXphx7Q4MSk!v+IFIdYln)hu8$M~h`2dCgBslBx_)29mW_+u2;7F1rw2oI$1pxgw-WC+N zCrA^BF0qHBh87rZwU<2O7jpgz8=Pj?saebK(*)J4G`SSvWPm3XwpP}k2-K!?KIm@T z)ai~juTmzL(&HBfa8&B(+@_US8RI0b%hQXyjJ-ik!mwG^FD`#U zM$tsQ+)SUlEM@;k!cA+;4)aXctQ)b^25!14BV?tPc2&CxNu!L`>+0vtY%~puHO2s? zdg1{-kVir2WBCclVQKfIW)HLXag&mja{YGPd*UPDYWj;C2uSdDHSq{s%6g=kcuZ$B ztrrlq!m4}%q{NjTL+fI>Ws9x(d+V8$wSPxJZ+Q4|7?8^6&>j`F0l}Z9<3p9gWPusIA^eC_f9+&Q3rMrGSM*R2ab3q66Ta)P=yC@>*CGugo=|0QOS*i8@_)Eq!sq4nljTiPN=el2^Vwe8-QU6F>lsIF$+h_EYxpufTb6 zq3=2!MS;o_eIr&`{$=pMN!r!k$`gg7RD{s3)QR{9Bq7uhtXG*-vj=p@vQ_yNxK$$s zRW**RpEwiMUXAa4Br9VJL+Eis+53;cF)EdVU!0`uU(WRqr$+ZY!Z&3MQuY;>JGH^P z(nDwJr8QPcc{um56uyM*LaYvzb9>-xuP>BvQ}$(}w4OH>rltpUkMHWN!f`DC&_7eM zI^|jAgSEJ>+ju$wg4Y?5%&ocM{$)(+jLy;g?AhX_%z_t%YH5cl`6jX4K~WiZ1e1+M z79dwKTc4YQ3r5Xp^I<`27nL$cm{9Z^&p!kenRcUKkc`X8+<2WN)hr11)s6 zhzvbqrYO5;w0?K=ss&qv2~&x+4Sg6D&75wWHphmxy4w1B2W6hQyTfyop@JRC0u>(v(QUX_>W!?(2JOqL&v6pg~x#SV3 ztW5}}+xdp3(W~PSVI?&|z3qGYLgy#LLRA+~3@seAC=)I^$8IZ20HaEpdl??g zNJ7ltcS_~^>p3(}So_PI-D6cQ&60_WHa4y7*hIhV9ne%M!V7^8gka_^C9mD#dDlzx zx6zxA1zmO#kgb+dUtMeM-uxbTFE7)EZv)yCsVB0Q%N=}{V6|({=c73FdH>Aio$TXQ zdP@pDh7!E^*6mt&!>``?Ii%6u!f3q5-#nsBQeh1i!XI=W%M0q~7D0O{%+Ky!ouvOXagwB<xyD z!0gM);bnrAEBQS$VuDs^2`u=OR1M?}l1y3Dg!wB^Tm&+|qnN68OYf+a9YmgHS&kOW(ctG9k%lfv zWbFbhFt*lt{@FxfQ|UkB0!7J|9y)Su*HVNQEnyiYyjJs1un{8uC#aumw(qAk&CE8m zE`(JYkzwvlsH6_vyCzwd40tx9sh0Q-?lo@qY>CJsr{`FHx2oL)h~bySqpX?`KP`}f zt@I$-?tHne0$52hwP~AP?E#NbyQ~ZMiaRn*5zNsC{=Md7bl`ZJ1*1tBKfSbtqf3mD zfKo@?g`=K>++H7|+Y4)__fZ8-1*Nq~qB~+eA%`!KY2-=6?Bh2tL-G94c&;BlCYmBy zb)8s{?mFDlY-3#?q=dzq>!WFgvPwedqu^m!9HMA z+%w=na7x^A7RNDN9}=ex*JeWPIJpK3GwIDcTa>2$j7909P#S{)f+fXJ7yOc{lJ z0;JC6>8DSb=$|g6qm;El#(nFtJ?hmT>RCMp8ALV)9~5hbWL=zS5^c<6pj5A+dHIvU z?uo72VHj#xV(o-rZW7h*A^*;1rFf9tB=NoJB7bg8*Db9QvA&t821&W_2uhpZE0e5* zpDxzNcGGMO8(iK~f*=#ob(rt3xL2>5fGm*YGr~aDBL-<}Y+BJN%z7Q0Svetf~lPH2QRh|GVv3*8zUt z{!s&s#|uY|SZCOb0phUeB(MkhbHieDLpY@l(Km0ET51PrSi%={armD~=DX@K3=-7X zvwjW|{lZ0vu;V_6`jj61RJTkW2HaQZ#^3j4kiR*#4TT>A+sSwD$%z0CKS^fHXf$v0 zT5YkmD5JicE3KG}z@saBzBcbZV#0Shp=}e&yg{=zkMXl3^u`PJss+XCMY^DqR!^+n zbBW6L&}`K&Cp8bnvw5MeLq>@pH^U}V7b2!66GVj6PGrE_529b9{HRaqo+uLd`s1%y zPWJM0`JbW|B!;}KQb@1V&8J@@`m@+H6ti)Z!sCaN*o+1^hl1p3!&cyJOcOW@pq@nv zf)daQ^2lguWOTbzmjxURU!R{Nml75kfXxqm#rds{|2UhM+ccvrVBtA^cSGx=JnWX; z-hB7sw~EgX$iDk+zI%ELjT`ju5!+m2eV3)0Ij0!a5V%|N4P8s>3X>OrS9t1rkBsbj zWut0lTr|?}b%o3h=QJ!3R%S{}+LqlB+!V7&p7Z=gJH2P&)3jaZ+O|N|a-##Qx;$JC zZ{xp(>3awD9!40;SP?CtrH^zGeyaT&4LAmoq7>);B;a)Lix8Lkagzsk{K|q53Z*Ub z!Q{Vd0)#wk114>2=Vrwly5E_YW%;8Dc!JVRze!CW?7AE_Vj^w#kU6?K8?krr6a31( zuzCHciWzzPqDzFf0chwp=%SR@a+VMQ2bx2(BbO=BS>z~@LuxzG5u&Z! z?@;i9JL}duRjlq1)4j0WXj0vsaJvZ4zE2x%Haeyy;|uqqf%m2Ph82gMJy*plLcdCN zMTf?LZC*vM6nah49h68IEJa7(6uh0vv`;A=-f?UH^uZ6LbOZheazJ`yHw>uhfM4{`zEEtkOJJ+>^$y5lJ82=_m~NQFp-r|BLCS_c9;26ELQtn1k=Re(JZD1#^dn};>NUo#YxOJnd}T|8P5YZ`6!0zHj~N&oqWCT zR5mu#V}}IKlfCbBJCn8KPVV63Rn3zIs|8<3_ar}^T8!+8l+oRS?=2mb0em$;k$qk9 z5|!cp@i;(R3e>x_S+FI7>B!cvbbtGu***W#l22b|8+d~I!I7hvu%#cU<;7riAu~}> zD)(X!>U$?*PXJmGyIVDHa*_#@RPzk4%@p;2U(#I-ElK5`IZ-4Bl`y@IDLy{6@(KYj z+}MFiyC^oG_(x7WRIo$E?Var*ZxnHSQ{+~{bP~VNcm0@e`+xgnAWy`ea`s$+#l3LqR>4?~gimZ6;}ZHOso5`QsO2hq3k98kpc0R96@2f<4y> z=4r^wCUiG97=2CMQV~P1=8=W#Gj}>95F_fqHReT8J@csYLy;xj zf#(X?I{o;ANLp_n^6&L0m8Jfmme=aKhSdK(Ww|sjxa02%{6sa2z1`6|e zBYYR&F5`ZsaJR_OTB${_JuG0z^Bb1aPQ~M7?*nx{s#ije{5x6r`wZh%qwSK5#pCYo z?)m!VhBmZhWZ!Zyef)^-&7v&6)!wEVSc2Or7M;W#cr2$Ov3g5LDYDby`mXVWabU?0 zedrT`ione%-4j2**oG}liIZT>{`B10ujaw5?CdK2EQE0Tb!;dOqv}_KK957rKC(M= z?g=$i;v4Upx@G|IpEgH>E5;<{vl=>rAAAvcoXPp3I4qb&N~+~K!T4+7;867E&*}nk z;{C@)H%Z|{Qm|b&#%pV0dTBW3Sw@khsn^20+#SQ`l1aTzGcVPgGnw8n_53Gp`@Fng zKrlA|d=aqtFi)G5-g(ZX7h3DFuF*4aRjk)?`Z@!HZMfMIfk3Z5nVan~jr&!zZ)=#k zvNP|n#^`6Uyu9rK0bbI{&cXdXOz8S@t#$skpJp z-THv^Ly)56KakTG$T&~8o6iD7jsjSAkO))nof$R~MkEmcKAQSIaUNV2Z`F-6(#ru> zStyq1mc+*M00*B)c#fejOGrp)BLX2pMdCKSH*INS#`BVTjwfvNVpgH@Qw{SDhHeRw!uH749v z;So}hz}pklnvkLs5Q`gMo^Mm(wndG#Mmd#FFfrAyZOn^!Qgg~D{rV%&>O z<~wl(LQ_1qyOj-UsnjU zg|Rdks!B(Q?G;RKA?fC{?b4)MW*f zm0v&kr?RL))9Z9Lx3FGRw4g(Q{=0isGO|PPgecMh4<2nK_VV@)tP_|~a3p)iK&*2$ z^{A^ny^jat26r8zIv{)(CZ*a1!f!2!lUF+AuRk;{US}L49Y|vX36yOKz>2p#9dJHi zpAk>iJ`)1#_d7G~muW?m7gQI#d+}rq?sjxgI0P$f4O%0I+jjfRzlVOK0$2FU%H?Es zoPvhCnx#u3F@V$YQ{$GwCWm3XM@Sl)fzXl{T{V&6WwqVdbfk@j)cL}bn99);x9&bT zg+d0GGBvSozSy1ldZ~wFL%YjxbV_c+DlAE^t>{;iQmA;*_fJ}tG&+A%sf-b=t*vKe zWlx0kjI&ngWS6(k)&`h+vTW9#+Pq}o-= zn!x)p1|9g5Z%%$i!7@@?e3NdQUXW8f2@L)~J&j_!Po25Q#q_AYc|E$D7Epe)WAK3W zxOLnsHivp3-lxgdU=cphB;JRCr-3ViQ;#4EGL!cMvVgPRmFRi+Y3gmy{tJ&D*e=$; zZ`d(+;+ccJT4(T2!yTt@e%ty5kii>Zn|#qZGDqLmryzlu4ogj)iW0y&5E1tKYs1M` zzd(%WSW_`RENBqpzm&B#Jk}JBv{|hCr_p<@Wd$}!SRZPlgCEenHs!|>&;CjGHnqhp zK?P?T+1udq>6byFs*wx91>>4o zJxUVLi|f{RM@|%hdK$5w_ZLi2Fk!jEG>MK$xd+D!CDN%}H#_y?jKZ3@TeOw>l0|Q> ztSWCkw+UiLcbM`uNQ_G< zU#6yO3ZFx2Fh*B*N5CX(=s5aQZABaeQp0Gfac3K}OEO!zg} zA$nRTb?K+)*Y0uDDkli--|LGoSvyePVXa%bVPK6`(n+v{gJWk*cT2NaYDUVpR`eGI zC^>();SAQLAd0RcdMvDC4iB%^c&uuJiM?8E^& z;uD*cLnA?eqRO;}P@~>~!GruEYvofJ_<=)=dxAt1*@PEZvL%gZz_Z)L&ZaU#cw)fh zT0RcgXgV|4EXv$^Xm6Ugy*eKk$2Q%H>lcbt;9hL8Jgy9d?+!M(sHE|l3O`tE9z@mL z?++>54Ms~;!@&^#1;;Yf;0l|}6p2^^ z=TJ4oOda#qsxWr8R#Mel7|L%urISh(PQ{^99a!;D8Pl4hhW}Bx25K84lvV^R+^l8g zkYz=8v{VFNq0;ks=F`2Dmr5t^ zzHjj8EPtyg{-tlOe1^WPb&tD%B1h5xXoSmP}Q&7d7u#jefOcH~C}! zTJps&OHe}sUa+UT`^%>iz)rSyknMx3O!*9Z^IQ?Qs7h$o2HhpzcgW9LeR^*bRo}zj$|=U^fKHoJm&V-l{I^J+QX?YGS!w1 zO(?v?nAT7|!0%C4s?u|%ry}FYsuFLNEW_(7USDsmCR0mmw8ReK&c-rFP(?qzUvFHo zp;ivHfq&_)kWc6HST{Hrwdupvmjjkwv1%k2U0(P)^z)KgK^Rkg=oMRaGHLUTTL#Sc zS=j$%5usoK5etlw9dVb;n&R&=wO;^NPo~U6D&TJ1?kcUyX;&g_Ffwvt2sJ3Wl$J(O zZ&eSJQqI#%Lr+Vu5i2b26)pCrrkJXrovM!bu!eGKz*$LVwY**1e7rPC#wE+8QI7Uw zuTer0SE&c|l3oryDj7rtN!J**qO7q~bPUVjI#{!AiqaEHOaDS>7D2=oZ8}*smsC(y z3qHPj_KHRk=Df6FQ+~Bw|4d@Q6%F>vOR;)xp~0KL4HAL3_{VY6cn zm!fcmFAqs<%^q1%aflulA;>gU5}a$a!tZEg`P-XL3g1IJJSt9IgAU@A zQt`zEq<*yb<&k0Xe~hJZg0StG0rx;e-1ZRtM<@-W{&ysLYPfs^v-5O7OJU@cS!S8m z!_of!xOMhCjRA!Tws%En_xDxN#RoKUR~er=BIDrjohT!*?h36Z{t0Qw*dvZU!k{{6 z{RULRGvAW-_KA48(=>VhaTfXb_Bb*967}v7zky*Vg5KD`R;&#_8`2U=fBXdY=MX`c ze_hz@WekP1!vxQM6XDueRt9`9)EB;uj%?wopTSc3uNHwN2*03^Cl~34Y@;~ z03@uLxg(!zV0AaLA=!E+>P3>u{O_VP%U1(6_^#X|K&eld3v!2pJsi^cXjCr^m3h0! zK+KhMis+af##Uc+{^rU~9;>APk2gxGbWu;Fuw4M#UHMZzG?%U?^}0^vwd!A5ujtdR z2M2`2XJqhx`0(MzO%Jp2yosTcld7sJE}I+ScN6~Nvcv^to$4G82$gnYQ5gR z?pO(WVtciSissp-(t*+WUD@8RHIQjZ{yeL9%sqGi&#(Uux~t%2q1x8W^VqmJh1LfN zn>OXoA}Plck|_~ikuLWpe`4Ve?dMlk?ps?$rI=I8gt^Y@oO)FzdE#%K^gM}t4&k#N zkrdL4J$J=L6J!qhtztF~jv%5QpAH=-0E;t>+`9+jUp%Pt>%G1XDl-=yFa`kN9ywXx zgOvfxla$*hn&J3n8ns%R;)kWP ztbUl0bwC!7#h6%YWM$U*ePmpu()!GZqJqKdi0s43K2)B`^k<2gT}0UfSlOLP{>7Qu zNsAcaK%b9r(eSZ%=}N5jEjk5rpMqUACLrpmBgQfTH7&yR?2-G74~$W88CHiEY5*GS z^#Vn2@A~sIqS_}Wa{4rkM_{0%qvOYvALcL4aeA(owB9WM@84E7QG@?rS~T5w<-cke zR31GL9pm9pC;g;tA%_a1`+7tK9!c6|6n^|N8mXWAzof~IUzla~B2~qHK+JCKyzxvT zop99si2an?n7PC1UG34Es7*+;YR2PD7%Eu=-^yarI9!tbl>7NNi}ycPs|I~)l%I7s zDi5Nu8K0Q2X|OQ~Z+b>9$>g#1)_e%~uFUdsgn2R;5);M#c5I#C>8%KMUJVpt#h=k_ zYgKBT!URu8pMV1w;d);Zq{mD@7w(4EAhobu$H|8n_uZk`qdWy;zsR6*?Sm05d6Xu0q`dpUZkAlmr-tY!(W%~7|$|A1D-?sZ@i-AY1 zXPV6S8LYF^_I`LOkCpE>6AQMSyaEMxDsgB*o4AZlxMG!cmd0U%w%@vJPIXqx6ChNM z+^9-;^n-ZD-g1>KuB z>-~2H!|JLPMC*_YnE`zm#sxND(OA-n#9(Moyx&1JDLUe4;JntoJ!JKAy&nDyo%&*V zK%f}x`QD3(vZZ2+26>R3<;Jv8GAy*>##6FW2F9iYcxt6Gk&7Gu@%f_2pgp|r7GmV) z*QSMwV$Ix34?Qs@`u=3Sylbn zt{nNVue`g*=e^P?FsJo)UWuf1=my=bI9%UKfvRy=94pBkeu`#Nw|dTBgn|awl6>t; z&m|e5bCnI1B`%TImkat9jD_gm6sp~6(NFz+D0Wq2T*})GUq`Qb;anc68b1k&O&*^FNr#$i)IH(rKGc~a(f^1=$ zJ_#APGOFD9!{(WPQ&0YxInLitRbff&jqf$+<@sX_He<+j$bN?Y0pUI?$%A&JtFYnS zQ-QaUB$q(2_RQ?=eF0%^Do}zgb5;r2n7P&Q1wge&Vvpj79F6CCMw@cC=LWnv$e zC_~p}m_c%Pv~8lS5~V=*{JpbSF*kftv5GlZraSQ4gek9YO?j^%65rJrK0;`DtZ?HC z_#@3yYkl!+$|L1KsS^)JTX5QfoTfa;AqMwBeW2xHBe}Uwg3siK&ukubRMR#pGi3`S zq7UEb55RT~TD+@E?Yy62)I_pGzIg!N%jThL5Qf*D89e&~IL_|ZQ5PL2yZ!w!hHK)X z@?f`-HTQ4%ujB=nb9heFIxb*I?hT96Z<;In^ED%~NzePF>pR+sW2~ zOjDr6+(S)S3Zf=v(`IxG@xn6|?N3s!JL)A^HiNi|+STZ{p;WCi9_z{)6ZSnDW1Ya? z8zFw@SSK+S(RXgF&=i+NO!q%`$_j=ru)Zyp`@1g3KE}u7U6oi-dJ0hxxe~}K1aYKz=w50lWl})HLXlHep-kN24+(NdSdnhNA z>K^suF?b|t_<9gNPcB|8_aOC__;6@+Q`j!_ zg;&O7U?)XZu+GkFt)MUpYMH?C$@$nL=*J4Vy%R$$G{|u4D^~JlFze>;o`VUD%(yNX zYUbJeiOI+N*{G4vo02T#%K?|0xP>*QZ$EOmb;#4`O7}!PM_tH%e*CNBDY=wvjeQmQ zX<}jnv`y)OBWL_fR3&@gh5iW#5N?;%^rUVOzCoN?~7;XEyZgZqKB1;<<0O zL)6qO@`FPAAJRP@SdS|dPNK_dd0ldVKzGzyWZ$8? zP4oSR%~w=%@OP!4;`{r)x}(P6A4WB%VAi=k2%tGjLF#QSj~r2yB?s^wzOWETA$5L8 z^u*{LC&s7!CUuZcQo6I!j_YrM0lLaxP!fi9HjB8$Gh#9#@4zo|)@?V+A}usYalLFc z)M21fiGCF{g}XJ+9>g`NU-_sC3{)|kAX?R>M2|R~?lSE!(KDx%C@A3#W8&f-W40#6 zJg%uxaA&ZUqd&@rX+66_0!UcETT#~zNyN(BQc^}YZr)^DBU5T`_%Ctfe=T&!RZObb zeGVTs-Rgz%#L$`tU#?We-1qkcpszMPAvpK}@O~-x*BHW0??-<*;n<;W0)T_`^e;gI z9p=HSpGR-3HlV@1qX?j|2Zo^Sjd(aOYHG$SYXnU>aSn1ye=Mtucy0J2?XEL;tZFx2 zzr=}+Gi-)XHP?8|E0i<64xCo=4ME5pojgGB{Sx7_BZ18sFHqBR(X-0_agY|T=U<2Y zub^`F^Ww#w_s1gDl54tlhNmt<*x}+T@A$cs&8zNt82`XgKBkEQ_(CRpXLiy`t=YtT zIvUyQJpy-tX*eeBm{aoBw-?`=G;T=#mAsRyyf5* z>9Ea3Y%;2h+>NjICcg(8{OXal$1k*%xBW)I!b#vo3&lqbj9hok<#_c!&b@1s@vejI zd)BRjv;}U=%GnVSGZ0k&`-%;GS>Db-M6+6KFo{i-LD{=*6qKV+=eJZ_Q*hSFunnz8 zTWSa%cwIYcQ}$BpnDsot7jxV6EKMk+>fWBN0#~H)MPM0a38T#><&?=^2Hj!~HJcPQ zjBPWvel_$r0R{DfNy6%vaJTGp7-)XPp*Lj)yl-+yqT;k)?}Kn`i>i|3@<*E%U#UlN zJ@=7P0*e1^9j%|h%i5(AYn~Vd)rw%CWydv{q~Ji3fxeD?x4l8LXAA(a3mm_sKdUDp z2i-X_T&vJ!8t45YcmI)yQW>{x`bj4LYu(CW{4BlZ&JQ}!tTRuSOMu)ivA~tZvfHC< zxO9=1)_vY-`tZu^R@uM=~$^P`ypIypEapZ(LNX$GXQdt&nC59nE_g()~LcHy> zFo1IzReP6Jn{Huu#SVzE<+GU9GA16YO=jx;0CfsoJ?`|!VukQc>REdr+LFH}Sn3q? zl_!d?cafyX6)m%BmD$imno~rMBrl{>_nW+ zfZ>cPF4MEV5<1{)Xt=~^H~TVS4#fG`UeVTew^@*XkrATqfY+^=gLL^+pWaVD=;EH< zMe$T_`MD&w32rNsqOcKve)MblpKd-~-Jvpa@^QgPKAH_88IWCsA>S88DeoQu@3#qj z(YDa1TN*7XcD=haKxVf}l}gje6vDQ1jO47KRgu9BkV%46&|%iHbpo)j-7jxP=J%X^ z853Kj6O?N`3!H%`?3?sdvOx7vZA7*9csUx{z-(L3>r`RVbGs!jwhfvwY<5h$6`)2n1; zz4d>~fT&0du%4K*=2ym5ZdP-+RHg)1ztGz#c~)sUIy;cAp!&zoTNaXXW6Bm5xj%kP z320Rr{H+(+=T|DY^fyj-V=2VH&VF3bgY>;NQlSdTY(D(|$i@9{7cBixSBgEmTX!-V z>fW|DWIepUZxdyi*6(WvhdtRF=XGi@P+HlrHZ?kcCrwug*l1X-ik)%#Ts2}PPT#U! zi>Htf#Qkp1ifgv9g{89@2;fqAAs(5!sYfmN2b{|PhC$+$CH6ZfR|_D)?t-V0SrC@E z*`|z{?sWw|SC~e;2NC<3W9s`mJ8y`?^!UytA&Pj$)B72uYP54*_+K%aQhi<_%5O{g z+?^T*o@D`ZtIT&rmNf0$w-756A;vYjdMF47v1QNVu3M*!kfzQ!1XC|o8_ZevnV9Am zFTJ;D5Sz*%DXEq4hFm|X1}WzFT9Mn9usoBrFeD`9ss3{$OgZzds@@SMtx+*CrS*46 zVvk_Cx}p#g+;1<-5bxj^v>?$rge9)bHc)Y*jbt^Otu~fv=8|xqYSdUs0MuniBfVcv z@rLW2eN!DRhZZF^gA%ibN2RT{-1OrzW0;Z2Rc3Hz;UvPM$6_)7fNtcngD>m1W_dA( z%XD3@L-jThPXTYTC@sE+U5!mn<`iIgKcD+wGtI?+3-7XNaPA#^5}5d#D?gSURJZJj z-K}V%u&PQFRgV9zv;jLEOiPB@J1!g$Wgf#S;66Ap`#x zd+#02_W%F;>uymUs=81`6-80hruJ4uYIhj5H#H)(Rh{;zP3<67i4~#C7DWU>s`iW` zi6j!gm-hYne9v|L&bhAdxz0J)_xy2Q|0P$%^Ywf^^Bj-I{eFA+nmZR;nSf6mmE~Zo z7=sz41Rjh@?+{M zeqO!3QA@qkx_x_%4*6jr*W~3E+NfM95ar2u$H($F`^Mz>4(1;!TKw^oa&3(?$QDik zYf>OTU0p~D(|ucbldxKP`jwSM$F$Afm`j`e zb#+A6+KCf58EBKmb!@o^q<_LIrHpCq^IdRZ>Caxu>Ir8|73s1#`V-vEm{3;uym$4a zFlnGKj%FM1M$V}E3*rY+re{_TIyUr%rpQP>CwQ`coo&p)5<=SI6}1J$zV=mvEI{~i zvlZe&Jtsub+Yk$$4o?cXrH=He=F@an>m0QuuqXZfSJ~s=&Gr+-OsW^RXhGI<$^6he z+d)Hzo6~R76(-Fwc`)3>bB9b?_xUkzPv5*}b(@z1^^FXUl-i4+d+$B8($u}3H{}Ig zjpve%iRYK9Xh_{_3eIuBlq|B0v)O3MQJ(Hq-`VzAPnPW{4(-Rd)LYwxn8bZ_cWa(? ze;Xgt0g@gX*Og`gryW0h?VkZ;a4*>EQT1>@p>=*V@5T3c?Id7*urUT%l*`Z%(Kv9Ztn#`cqTMLlMK$~maUUM zT!*K_-wY9q72(h7P$>Q(%rgwq22>K|_RA{aF4scj04PqEBrQ75bRNTB9nxCPcpRNJ zV*c%#$(4W26TGew?+Q<{KRfEO)9jM4+w7{#_96a;Y$p2(jDfpOXsPXzHF-IeBlYve z$5e&BXKr?;;1Ewckr`A_Ivf@$J+F`WG}(H!U(RAu`+-kJ&+^PR+nqeE7F&}=HMxV0 zUv#98Yfq=+QV2S$aM+EU;*79^BVoJn=54Lw)$ z_U~!)^}e5Wc5W_Bh^cM5DExX^PT!5tKl>P_qz~Q6B0VD&)@%0HN?8v?e9@+}TBy9m zpdE;{7ae2i#qO=&viGGe5r+WBXZTp1Tk5_g7qIZ=hhuL6o8agKAQT&A_w5ZwAz%yL z_h{A@?3Cv${Y%Cn^*75Rphb6$2Mnaqq06XU*a4>KXlCNCU%ysw8PgH`u;LR$J6!E;WNNgYIcSdLZP)Mg= z?R*yw%^Dwxtxp_gD;+7zn7HHpu0?)Ngp#Z65sLgU!Lix>Q(_ZT^1W36iTnb8lR2>b z$Zxg1@@?h1XpjmyC5*Bx?W^@pIg**DgS2z>(pv?bT?~+d|mTZI~f{yoTFfU&8yRobE)*P@AaM+ z#{N$iECz9JFBRiO)SI!l*)1ivdai77ALG9|V5auF;WfEa;PBrRXfEpwr;=15xA4I= zPVyDJM*j_On^(fVi~!qN2Py83Sua%m-U=A_F0qs8*&-N&y6KPjktNw1${dRUsBVtM zNnwIvi>+9>tMOmWq6YF2czG^W%1}!do-7R=^Wt+0tiO#+$l-~12&X}z*nHSvS^h?448&RL+hfQ#K?re(cOf0otUQ|OuPLgJq&?1 zcv(oZw^j^&S)k+>H7w;5Y~aH=p)# zQxJWfmHJK*aS^JOcYAm@@q7NMwJek*0*z|9glj6BkY=!l&N>SEzQrNOxC4U2P%^yQ zLPm?Dx(sow`TKBrsb7s@3M-u_{*B_ zcUEnRw_Zxb?Vqlhm&GN_RrGr`ICKq_F)iZ3my28Zy*%EfLf*rZtnD*}bNY78ig}bIM;6Y zYmgE{;xf$^TKzzh#DlG)dEnM=~Wdm`7ZKuc(y=&jmdvEbWSPBEgbrEQ_& zg1&&#=lc^s$;r1&KBdh0)+(EKWhvaJwq|-nzgnJ}kXZ%=yUjbRVOtg~TmWu>xG=$ssQZNHz8$=llX%37EycRu zFyT@Mm&i#5M*V23oPM@PS=o12sFDpgi~D)2D+>4oiN^sZ2*kXj@7_D1&E7sv{h`D% zYg&bPv0X^9qLSka8@s;4plP1nlEj?_z1_i_a`m+9g?n_(Oc z0y?$vE}K(T8T@rV(tFY&ZrLq?5ZlnTQOh8G{Ka**q^n$F9?qz@U37z1gHwKVPf zpE?%1CTP?3kI{3eTDyc$D=rbn%NJJb^X`;D(n{bB?0gHf>l;FakHAQGOL+;*Sqd!{ zo!e#V$D)@pH6F5!)6-Z1$aA)B^9^ZI>2ut>oyxD-lJnJDh3RRe*ZOfRM<<0mHUkQ0 zSJR{%pVQ$xfvsEcu(Ow)QO2#1D*vIG+@~PpH!Yt?H)v}=l(G|lR}e!hg?-1fPU+<|?Two07a5aZ zxJh{Qr|NHQZ{2}}TXj0symdzL;vNq}8Z6{#pK%73du{@>$^MyTokO;r3m{~zzl*h6 zOm&KE`3AyWs`j73v=VVw$-2*PuIWckcWMrRHc|{Jvw<>}5=U7h_U3>8;7Xf znrlv&izhQ#DR}Ie$SrYXn`&D+Aqf6!G0?U&Gv~ttbf85gjgb`J6Lvb_~c@L9vOv&((<`!|Owytv9K= zhl1Cp>U~`wYC9`2=@OSe1m$IoZ`|DStk@+r2V37vOF-&@``6s>+Z&zY-gI z<}FyGzq|PMsUvzW7F{Hhev^CR2y2Lk4&7)Kd0wkSa`17BF=|IjRb_gek;Do-t{gO9 z;X^vIR+x^&9og(MAowNa)DM`8$t0J-pOiaa5^W+TY6VlDBEoO!gw)G{tqMpf*4jv6 zo^V7_XJ6mnD8m@oH_tAjA^rVaW?5(t{V_iA)3(s&Y9XU_IgsJ}vBmVOURA=>R6AJH z=t+Q2=T8%)SRL(C*}37~ou4k(PO|smZn<)=yi?5-SeXPp(X78GQz`0W>r=W#rn(}IlP!N;TRWKYl2>&AR(B31PK2k1H z6RfYwl<8aNuVhCqM%;kF%T8<=r8RpO(br>(Jm%iCd0x&?y2_rtezTZo&Pyb-nPP3Z zIikNg+6ShlXBac$tG)i*Sw!H#U8UGJhO^JK_e9XP1%j9d2YaNpX^(`K)_8R^C%Np- zE#8pDhX|0IJ<$ z1r9|*O^-S$<9>CY`sQ*AWs{T$IS9MQF*y;|Yv?i8@=yS}pJ@V)cGPns!`3A8H~#D1 z@%(~#-p2v5?olS1{a(247EX$oe(XCKuxg#|X0`;Wl6^A}?vjLbowY|quZ25$Fmo)( z8ITRLp`TP7=<|N;ti*e0VM$HwGo^OALXwwHU6PriN8p&qY*eEe`M#V?3QX%wE9040 z;(^@s>-nY^ZllmR`cCqSX&8rYOG7MN%XU}Aa)+dGF?glWcfE_FkNH}tN`v*f(CZ(s z{|*Fm5sMOV@w`OMdaUh8bLH%o_}kOBW~tZ!G69$wMc&RYXz0w!xF_HrF|Rj>l{A)g z7*RaG#gdwL8;&MCRsFJ&&HGxnc`XQJ;n;I({bQ}FoVaeRMXFA*k?malSY)!-vBhDA z?^@$eg$zD`*{zLDy`nX7~sOB*ZwwoGoXgkGRxW$@ENYeUw0(G^ZTq=oZQm1$ZTMdcpML7?Ai*}D@7Qi7ruj^2~k;a zds!CaxJV})vweQvIY@$VzO$L2Eyh6)e9GdIo*ga`GWl4A@JY5824WW^4t{HUj7Ot2vc^aS7sS|m?}ZC%@hb;=7PciyIe;tK+FpQ z^T}B4q!_SX@W7D1+_)%H=#=a%IlIm%gMyNoK{qBTkNHZ!# z+lBMmP~yytK#*pAIj+XO-XQ0+%s_tzrMg$7QbE4umw|KAqd)iWT_8NKdJ$AG7a=%T z#2#>D+6>x0vC3Uk}Vo=L^EB6@(7u;tJl zhnV>6Nx)1rI#hs@vYkbD@WiL#)V<1FvDKUFZGO)V4jRtL>j4T!Yl3|DAD>mWN1Bjv zrkuvq+t@^bHEn&yOnc!Il+l_P;ytzN#l!Z^ndR=WQwDKhdBG2IQStj$t$MWV&WF!k zNeKALEQ|P_-l|Yy5joY*wxbTp$R7+{WTi~!Y*-?ey*3i!*=Jv~usjh~1UO-*=${SF zZQoo?@`|?SL*n)kbB*~QHz}^>_Gg*djz!N!pv}672;M$-S z<|mEGmpfgstSLUVcBvg19P8I+bNm|>NhIi8dw($%?&kR|-L!bFZg8)zG2#5R0Rc+*3Pc6+{?tkIA{vBgZ{*B+9C_nY)!Xig1;^Ml5Tw>wE(9{9JZrkmu7J08G zMf`%P93niR^wNUE6kUJu7QzZ<`w!Jws-c`6A320z}OYcG+x5=O{GznW&g!7WM z3vZk#Z~pxkD0f5RHtL988-XV_)p*7zMZP&av2uz_kY_x9C1v1&(4W6gI(Qo;YI~d* zadxBQYfr(KhLcWuWfNXa1!R~PkXHq+SDt|Ogr(0b@~pSba|isZ&py)V6qabDcMw(g@4y&CT5L7yQP1>`d)`4L~Gc2XKfM=p_rE<>B#~=jL7}zgWW|de$eKDUbt9Z0y8^yZeE6fZ<5W zIVI3eO;i3?k{>XV79T_!X2|GLHs=83B5)OcYlYDGd3mR+j)d;*ZpH30XawKY>JB}C z=J=I5hrW4$>55)(aBz(qR&1=s@olE}=M#UancuWaz)k1mhH)*ywe$yHzkM5P&!(zd z6{7aPmhBV~8%zxH=U4=2o8wUJO3T_J%aA7?qgCy2)_WY!nIgUz*L^Zi9{Q7}e-jJD z@c}n1!gEr-+1*T_Ww-1y@FgZ8B@c{2-KF!D0n5V@ey6yIZr_$MWplHM#`8f(m~IFR z=bUsKDUS~!E^~R`JD+E_WIC(jg5eo9`iHNnPUo_v+aiwxW$1qmw^D2Yy5^~Ux+Vjl zYZl*!j>C!&`;FD(VZhk{SxVmhJZ{Kes3$uVe2nR5r>gC~+Y`9{_l@lT{4n?@FZSPa z59`Gnq>a?Q-cEDAKIwESZgy7Nu_^7Hdy%4#)6f7;?!hrXoWRvTE`o_Bi>_AiM)mT_ zs-56`yLhi;VFNkuw$0@L*2#TWg5qaK1M2;R=w1@?k}@rE_fZNZjNa&+HOsrS`Ae(T zpgJXbH`6^nC_7sy%Zct-bSgD@bDLf}yYA?8_RihEO;okaJBa*a1lH&0<5Nc!k&+-} znbaiRmCR%ZD{Q}{SU?Ok>s{&QNVjsrAMZnX)FLnt_e6qH99WHs$SGKg0QMxsN?B%Q zG;-=){_Gj7{Kc%9**Z=q?Rz>SI_se@q#}0M;Gp(#ARnY%ke_Ol(!qTh2sWH?o`0g? zq{26Y689=%cB^iob>@$dxTPvxHi1aFWs!zetI_$Ejk^Ori|7`PDlW~6y(%|rYQWy` zoKx`AW#G{&R!-AfI)Titt%>Xw~^AbQT!1y?S!jXF^_NY1caN-yc!J#y=`B#t3}uHY8Un}kW2g_Auq>tgmB*@a1Nzxg&F*qQuHeHOWs1E`ka z%$jIAQsNOu&Uoy?`1r!l%H6FgRGUYX0?K<^PJX2st+LU0B0z~j?{?VQjg~J?PGIO~ zvfi1|kg5n7I3Xzq~C@X3IFtF*0OHthZ! zpTa8Kr$RFM53knl5;7bheTPd^bG+v73{&6FebnYAc@XlV#p3s@8*|$R^t1fvL+NQk zDuh-m9jwB5r*35P$^1;>SU?B2^9VL_1{zeL6B|wIN$!{%U%7HTp!fFzskXn`p`Npg z+J`H!>SOOc$8=SG_iEzNid2$*0BHPjz%l*eINmpKgXW?iPmMw8;tlsA(fejCk7Cy~ ziKQCyp(Ur3GVenASBHyFVB_c4vThQ-MN|A_>$2!$jja#F%;x)g5|T2S^&h(ldt2{Y z8#=2FfU0(Kw0pi5h_9mORi?UoiTWj2K&l&Nm+g1txgNkW;@>iauqGtk(4|4+)DjQg zZ7*O*1}~kvxX5<+)C*hbJG$MmR*zyp_+vp)xlPW7t1FrN4uFkgvE6_}Ve=xnbFzXM z&G)p`6L%w@uqLtXowR_Vh6{8q&rc}@N_8IyZirngmGg7>2D3`=ANd`^%XHQC_GL z0cKqSslICZcl$S84d6ndPeOSGhnRm4l9J` z?07-QI{w#oP=RO0i2N(opC^R)x|0CINbNd4kwJ5_%?IeTN21feJycPc4?pi69x3xa zbc{`uzG6*woQ>LC7=0bZ7M%LYYbG@18J7rn607P-e_Us?P^QS@X__%mo%PObBXx3O z#8R;2W520K&n0x=_R8g8*U*QLj|3=k&3++u+$SJ96<7khDB!G_%G2eO2HYw^ITMsp zC_bC{vtJC^{6aTXS~AGm(1m??Hn6aT>InBYaJgChL2mg9crw2TQ?u!dB{CeFgnys9 z$OE%ib+i2Ljg>f92&}~sd;{{7$15%gPrH_Ut%w|(TZp;U#`OrpBUaB<;EQFin&GZZ z@9177MQNf1x?gx47<}T5!gE%g$*~ij!adi-$reqN(t+ylzuQ5N8K?WaI#v-5o)a#c z(2j+pQIU+b5^tZ3UYu_VL^&vHD>f{VRDq0XeulPG8K$5aVpWzkY|M%MR(u3yN$Xa_ zCmiP%l~lq@lbV0|)S~MoxB3Vb0s*rPml*ahhC}=i#hn3buIX}mTrQ!+Jze6Zy#(%4 zD*TXs8&MX!3*z?DtzV`_W)Qa%=>!#L_|hZG>Scd>@8#CmWvVBRS{QaVG=D*HySgG} z#w&C<9a@`78{*u2?0(ne8$VO-r+s5gdfGDcC(wZd-9;G7n!k=1+-g8yXtawk>{%Ib zj?GLnuW%JOI(C<()??cB_gywDcbwd;|9ET!)Q{L1 z6^?$8xxCtqTpy7O7H(UGDGm{)ZgB*{t1`-t9*yYJT3&lhy{P|VJ3oV0Gb`;_Pfj{_tg40~-t|UFZy75yR<5?;&nvI3_sWPC z_NS=awJ4KrefU8!*iw_?lL^1ZvYIG9xLGJtQ}Ae>MhYXZtgW)&l{sXQmjSc!t5gtP zaku|4fASFMX>cZzi_5<*AsoA8@9dh5>C8ljfD<1()9ch0D*N-$X|z>xxcrS>p9#T{ zdbiHjOHWa5fT`wN%NYvrOJEyg#?N3E~Vj zLEeR*s~+il2r8wnypaNV1nTRx^NzL;KKg29f10!YU@u(8EOPR3p!fMvf5aVOat3d0 zh*#nXbtLa}j8+gOeSm6jlw9EX%ndB(6n>p2W##AcWfSQ#Tc-+zeV5_GV{y|ojKYV6 z0^BwS$*0U&11w2Z|K7O}^a0~}eP*?&T=*64N|PkuXDMy-wCEW4ga9h@ zJHHy#b5I%5zonx<2jWn$KAeLEWIlFauhW&*Y-tQWGWJ}p-EMJCUPGax5_aB?+A#!~ z&9b7KH*faqgA0ObL$&o|_|ljyi}KQ~(F^$^JG+sEcE4130^m(u)ocnFs#|&Ri6bP@ zlFy&sOGucmYq3Jyc_=wsZDCPH0ABL@%^{|Oz0!{%=^9y=FAq7s`#*{|+202&nZ?>u+ zyH34367*ijx5e{Qc3>3fxjujh*a~EtaT8w7FWYSC$S*^EHZ$}daX z>C$dv>1EsSbH2`~q==@pO}4#YwCHCF@;#<^tVrG=Gr1LRvanDDI|AXziYYg+ zcWt-Z>8>NxTZUeub+PeBgZFeuAyRAST`ZYwktGKQP>%hB*SH0}UjYXi;9-8bHmMl+ z+#wus``6Wru#f$hg_oT2AM+4n{L6$p;a)!P9QGPMwau-o_8Ag05TBg9+s@sOKYzo! zF;s!kW@>cA)^{-DBaBE-ehM3}sHxPg40Jbnuyi<%W~@_HMpDi~ z+;K?GJ_|ol^YLIO4??>7P;c9^#vWwb&YtTo?0S7WaJ<09w-*0<1t$xB5p>sUDbXeEyUfI8TITPKNda)hFua#J%EK`&b)hUDyn zMwggn4m~$%#<%9r{c?i6Idua9$R4lw9Q^Xp$?#IAJt|C0#ZzJGu&V3N*EwO3wNl2M zx!-7RH=I3v9I{C#m=*JRI9B)Ce(Hgr6L}Kc5Z8ZMo=Q=dmEwyCZDc-|Ls^uq<>K&P zyRG)ojx_&^c@yfnEi?J|X!bRF2W!khd?XiM)?9oqvTJclYP z*?2L|uAwo8c>GS)fon`ZZ<+L|71zh*z=!ELIY?p!H_~A6(7|F)q6L+D%Pc=1eq7>O zIoGN|&coQJWr%ppHj}#D#i5t;~HcQJvT9t zTZDk26v*}4Iiz7bcho0U!bU%zwG)MGS-DXXtt?^h;C2hR)vEAw=QLwaQ)_M~+ zHTia7qrq=3{S(zO+9&n$GNxg)TY4|i4PQ|BJdEu^FbPNcr z2fN-Bi22xbophsa9sSbl>cwXWF zMKF=4M*A~SX=Z+0u458_a;!82t~f@0%t&YjiS{V8efvQ79b*^rji!`UT++B3ySZ%T z+$p>1XzgtB_E!xF3K1?_7}rF@iJXL7Yk$eO};HS3GgD_eq=604u&m0^0cltbi51D{#~M!zhY- zUmke(esf@jd8M80qelnBn-4{l! zvU1p+=AmuW`A%eZQF=a=mcxRwiP8=X3uTh>)Ar_)q9()5qYI< zB)EI)yeB%~UQQ@!GQV((%N0UsJZ7Kjr9qwKm~NWa`TQ75T~CyUN?(H4C@eAK1N_il zqg8ofJbo_$r%Fh0F}AYOkKn$)v$f1k*fl^}3Ty0f2Ewdrd)5PcjDNfDiR;l=vCO&uwj2y; zk{=M#U(uUBXvowS$u}$_07Sn&h*$c8I`X{DrH9pPoW2fMCHphIiTQ_j@bk1Ohi`26 z&sY(?=oR$sEx@;^@6WD;S@pdXY4>B4jv|`xA6$l4`A93$~Hn^DfxWKt~K0(qYEA3$~_tmbh*lvF*OPh@E0jyKS z#($6{0NE<>hDm4WqLf+oo!U}Dh?bpf%dc?w6FurwD4PEBM@Lp>rn}t%{FyC?ZweTeoBwM{+4P36~emeO7U9-nce(e0SR#CkV!M-tU0~Z5g;6j^*Nu6;}_i7xR5_R1=i1^bTBHFeuVdy?3?`i9ChD>TG| z_&WqOq}IW)X*2wrHJ^u2Ce)eM&2!dv!QgDIqxrj(gB^VY_N~058bj9*RjHLgixw1fPg?dNqk6n;{!mNw;T-rB)+o&ggJ+tJ0Zj%{o448 z2~$1esV73=F1K3;l8uC08UTbnk};fJLztS+j+lR0XH12`hO0}7#LYkGSX&S%whI8V zihQkM5{^4w(%)1W{?g#WC1DevFn)xQGVTiaM_FS!I$fYlTYQLi*+RX@-q!nR-skh= zx()LWQFE<4r}V*YG2{KgEX_^u(s2~qfVn`4U|aXDfm7wOFk*~6B07x3^7dsO;8|Hq zcjFct9hwFK$dZm~09mq+nGrYea8}9pgOK&3hlONmIqfPPMf!~wsh42R{!4AQ79J>v z>g$QHkJlx}ymq?B6x6n0vB^<6orCVg%XP3e2KS-X(8~eabz~*8`Lyk$Q4iq($JgBy zTI<4J0)Bi6Tz{PGGF!^^)&-@BMt`6v2ao4u$9EDs`*&;Z@R>)!Khdze;j$6lZ>}tZ zN=?5p-hNiu+vNi)-Z_Z@PcY((E`8GGPa?#Yo~0Bbpt~}1(&26sB})D;Y@X{*$*sp8 z=`PRQ`p`GAs>`Jt*8)BfSvFTB2RI%4;{e`&8W|uw1yRZpS5+MwMef{uHuiXSY1LD* z51S;e+jNp3uB1#c9<}eqw06kn-7|$Qh5pvUQ%ap8vmbm>uD6joqZ4(w=kAMRdM_MD zlm*3Ye_0h(`ZyTcVC*z2=S?HudqGR-Yo~wkbiR}{yZ+90{tLf(%B=-#C&|n{5T1yMX+|O>T1S!nB|KstcMRNH^ag|4qsWQv|_P6 z={(9i#F@Pk?yV6LsBXqvsBTN+&9dKC{IVPhCKR3+sY46@v^s_ZAp6h_7f3NiY8F*V z-TLCZNciN3r(@o0s&I;$6&X@{<@*KcDrKwAe%Y+)<~wayylYoBD^N`5gtBnWL6xf$ zjYABUL+$%HRPUYA>j>Cg<0B!zfB$w`&npa<{kLED+if7dZs;P$(>gZECfM{n)(@ly z5j}~5YM7Q&0A$nbnqZH4foLqIFBVi)kfM-m?HVfIumPr*0MBAG*MqVs%nh1bC|{XO z`B*Ot>hAmSi}`$=368Dqq_nZLu7An$EoW$d*h1Kq_>`z3G_Lf4>BD@oA}dYaGl8Vf z^E=v>)S@}KGbuEs1*lg%bQ0v+;yDuig3)Esv4IaEM z`vp}Q;oR0|iH3wN(?wFt>tY2ykf&&9-igKvah>+9075}sgcJIhxFH4R6T2DX~&lVoY@_M%|@Ns!p{k>%6+rL70ZD6 zLuV=jeiD6o5VSkU^gnV6mX4?fg7WfxbtqYyylH~gP{V$lb#QjpfAr|rfgtn)dgedH z6z^Rs`Qw6OV$%Q$eTQ3Eq@>B8{(~Hy-gTjrZQ`4#>APpfoa!Baw8>Kt1xtH&+uc@5 zTdAp=p|?F!@GZf9p=lpedIq9MG=M#N^IvSzb9MAu$O>$(zo|XEIwr5$*_Kd$t`2!w zv193Yod;QFI5c3QFGJ-~R^=}xnHr)!U}m8iPhlIUtAE#1UfaZf9&ip3Ttqtay#xs z@EU}LM$c?V?Zi#>kKiBU$$87AZDwa`u=t; z%a_~j82lONkTo&vDA!{hATzqG8NzMuXh}XqAXMZo)SkX;7n<|gW@Y1Uc(Ls@Li3Hg zT*ZuFrgNNsbO;fq+VpEkUJp+bs58u~Iz$}FpNQUIJNlDRXf5r`GHG6Uc$EId(C_4D zKymZ(U3JXXNL8N}!0WWj-XcPav<10-^x%j4_w-v`C7)K7J%@6@8nlxGVs|dPSl%*z zA`zzD9{_G!t6q2M62*H~maLE!19Z$J#;B0no^(=8=a-AjP6^XY?3?px_QQ zR)7D&=JdiH;#DOXHx>GjRcJUjljc7_qTzefw!3JRW6@%y#Rh1Go~&pdp*Aq?$0RFj zF16Scq!z_Bs2BbU?qGa zyP=J}^RU}B^-Vigq{mR>-gX(0)bt(i%u{PU7cNwT@-qt!roF}#uHcTCU$Yu+yWl!} zZ$Wwa-dz?(rl05p-=$`>tQ;jTH@w&ULlO1yTN^IUrv%VxnF(&n@EH8k30Zeyen8gn z@z#Ey3H;*kpY4}>+iqx{;N+rS;lFxg2%+uWf57I8gLV&ht*R z^DM#U#t3O@ZH)@&52bC1^wzQI+t%Kb4ExU2>LGZlLhKL(QyYSJ9d<=d(3H#%R5u;X zQ*Vu!8}V5_JY{nG+oc^l}?mJ2TDl039{({AGwZhf21 z|17PvqyIyg81eC8?z@`Tdixbg0g{}f4^`nCEJnnqRz*Z>$eL;3uYHtB`zR=Cw7l`t zJLpR8DcISx^;ARYt<1pDvLgpHME-&pZkz$6N)dyv=Mj$V|3Dm>{s+Z%7tQuTjjFG2 zlqwT9efPDo6DcQ^fIq9IcmN zcg0m?(FQ>AMel#T6_^MxAx*CSb9^~w=m~Ju&;9f2ev?BM@mV?RP$O+hH%RBZn_FL! z^(>l;^|z&0Cs}DK@jY)~BQZ~87Dt)uOTx7)8`aU>99_0n%CT>ww?hv5+UMwCmme_i zwVbolb)R|gD$KCfVe-B0+QQXszvEXg{b7?Zsh$|!7;jF%=4V{tF>x>XoKlAhOl3DE zrO8FVVcvG?!t)rUI_Wdqkn3?;(bZ=qCx~+XgL8<5!~)+~_P*`-g2>@uTcu+Now;WC zwb4V}`|=3jDzw|3RWPU}Tr^cMr+hz2)@wYwN9nS_9BGQ4eLcz$9yasPquX z^(_zG%BzDqfrxEgDYM$NsBA17hqJ)Go8tNwFE*VOHudJb;zTJc+V)vK31hysaEAjD zL){s!;js_JDLa!Xhr_?yQV>Cdp*3sSfNb&WN21w<98v+{l17uV(X9e_Pq%h)yo$%3#m7wD){e$ovF$ zlF<_2-cK4{_^jeLT^hP_#rj_M5b{*OiQgBs-`ox-8I0Bb)R#JWHT`dI-k57mP#Kwc z0M5vof+BW_RB#QV{iN@>q%@>_c2aK8{NwwoL*+?||a)o@3bvbeB$Fx(M^RJ=v zUGrk1Yv@%gq(w|U-1fog3$K}TQzosuf+lw{5MicJOGX%j3-1GNUGZdp@_M&%-ofSe zvcYQzuR4Q~i!!%wvZ#NnV!{lCYzJZjg4W}kl>6yEgyIoHuwEDy+gj!QsX3=ME{dK{DO5b%h2im)4y6fxYa1uxB(8WHhQ*AsVJ3J|(ngFXfAaVlX3eu9_Iew?kHA;5 zEHF<{^$dX0w&-jbG}BSz*3A^!8l-Ujc<8pAg2^V-$-ZsjSP#Jm+xfZ@<_F5T=zdJ! z73uxPS1AjUb(P*RL9{g*1|%@c;i{wuK*< zw_C@nbbg6k5x@vr%zYF2rLQEo9DEOblG%mmRfFA)X-4!tX#TvkYvB?FcQ<>M5g`9& zDmnwEm3YKnFKh%{gX~M@t-shyc{h$vkv3w-9`*G{LR$4?q_ez#{H}o-#-!gV_-vaq zQ43Fa(Zh(Jz(giLUT6{?p1^pYGEAMOBC$ zHlhCceI`8u=3w#b_P^LR>_>bYOwg}G?1ugP_)oA!U2$`?51h3RHfJ|#?8MzPkKz$6 z4vNe78wsIC)zbV~md(T)EQ`NPo*NN@JUFoRpw%2G517k5k>GJ*WP1k2Nq&y&=3Cp#8Jm-ayjo_ly;w?NM#bpRS zWw0usLSapPs4oG^-kAmF}T}vApL^ z){1>lkZO|vNl~|iN4}GJ_uY8(P>WpV06KH4rLf1C99HQZb$U6C#W*^YC`Q*LRsL4) zna&>a9;UN}hab@RLqLcyHIQx;7*M}gvM{IP3ag+c4L!g8^bqWv+;2F_5h!l@43=h& zdc2ap6h1FGbCi}Y2pcf+T9CIK4sgoTa>dYV0#4qeoNJOd0B1-iw?OSZ2n*N|GKD%k zWUe_WJXUj6!u>dh0o3UW(i#c*P7L|M*1IjI^n^UaSqf~5pIyT&WJtBWf>s?_Y2aDs zpCgQPRKU@#3;tVpozM0>s7tZ$6PhgZ!y?VzcdRD?b$OjhJof`quXSWAYL0X;de~Ez zBTOqRkMj6{kG{MdAiL{4{NOAGf{qCZKDv0E(%YDW7&{vpRAV=GoZK6gf7fhJl?$s& z@?xlIz1hk}^e&R` z7*G^kV;_fU^5)EP-kpztz;%zz-G$?s0AGqo&@Ks@y$WnL{@Ih1p1Evq^yt@)^bw|r zXB))=z}g#O$|oac^h@}wzI&tZwPW}19b{6q)Y_*{N0^pB?en^^Pf1FY*X>}xoDn?jQ4w0%;@x$5b67~B zFVjRUi6P|G+2b62sjD_x@$B@LEjm=)4w0fz*+#r3ib$<%_-^1reHz^*8XW8tWB;>$ zTV%V*GrpeUHgjf^su`q*3xk}zW-nN2(oq@f^KK&Ov!@hr&$)|#BHlN?y#bdN->t9z z=vv4a-+4AcTEm6}0wO(msXefq5FxbD=eMt!G}!Linnj7}7}EQhDV-+UXU#?6S#NlN2wE1CWJioIWxV|otB3r%1&!dd zI^|*-Tvtx5W*_vnA8K?$ejs12u+1BKshTl8`b?WzdYVs<3!PR(S2S5!Mt}Hgf z^NGIo74YW&kGc1bYN8L@{ILs&4H2cPNEc9g2Sti>fq;|{8z8-d)L22OqS8y~C6pkL z0D*vr7^#sOT7rlWAP}U42!Uh=eV#qT>Ei=+H7B_%fPQ~FOg^SvuDHU z>vk7ngO&!c-`$?6?n0H)x{%LOQsctP@u#-vC(`Zj`rgoRJ=?17wX<jG5ey9aQj zJiXQ2&bs&AQv5nKn&pDwPtx2iB5~K5P5ag#=Qgne3F0e;lb^&PCJA!h{1U(HS^>g) zWS?O9Wjy!g*Ye8nw>!vHohB8y<@J&Uwk9e$dTihDEv?@79bvusEJi7t$-G+Gl4HZt z>(Q}QEQs7$MVc&`y6Wm;q);nX_=LK=*r03K`^g~a>l#FKY$fFi`0^MR&#l36C_qsE zW1)Da)eeANJT#jiosxc4mq4mIh{;KXzpbk(Xk=`wS|>k{T&X8AA1*VMZ`Dy=j@!)a zz?{am3zn%Y7c$P=DN9w+3srQN?(FQm2-))lF^GfYrHDgfw{U4hqu>&dI z+oqA@Ny4^j*0zY=9~*`#O)lB#^@e_m;X*KM19Q7Xr)d1O;P$5)i55U!7n~<-c;lk% z%~qS)Bs1^o@_w(KfM-{#9@}bL4(w0y#wUC9k!u87lb4-u8|)+Rxo?^UIy|0uNJkg+ z(7y(OOkeR`37vPtCNe8TN%aCJt#(NcOgvy3V0QNHECT=shw^{$^^osLWLmTO#W?Q4OR(++s!2MU7#ujd2DvH=24hmo#tNF&x6wBg_ zs4Co}_$*gH`|Ap$QjfOUkVr3+vU^1L;Uc?i=u&W7ceBK9qqtx7yt9&bLh=GL^Fr){ zz9h*^)K&KP{53mt>70`T=U?4aXsZP8wh2`)c>am4s1*XN7w7Uc@R)a$H$}aOTF7}s zrGh{5cb%wC-w9z&GRIa6Hmv5ui{tj5E7;<>hR~GBAm2x&B=}XFN#}2?y{Z)=27yzT zn@9oLmlRi}jL?xWI}cONJlbTT%Za}mNk1>AL0<(Oje`HG)uNXgE4}-e_h)JcB&54_ zptWNbd85w_t<(s|$Cn}r2`dj&fiP#uvSj2?-?6O&ty#MLE`eN`^fpf%!|{T8R})@|JjC*z!g4ov};?Oz9; znx+-+$NW*-BR;L{fwphm%OJzez2>bKwu7R82A>DLfQ3GQShHKv2c2j^)+8R^`CHbJ zl_an-Z|*@ilIhfxDrX+$_kV)quB?c;){&+NQym8xg6L#IF56W#1B(NC^6st}!NSZq z6cZ61Zl}=6Xvdf3TmizVD%GZIRFib*j_THz^CuOb@NE2;Q4SUi_MH74FY_DT&t~UX z6HtmGY&7E4R$Ryq1ncguw4BWv^XGPtF%rRy-<4MKCNAub5X%V87L;o$;ivV>;2^4_ zZiG5~%RhuXxxy@pv9*60N$h``sBT+B`BIg$SXp@je9FqRcz=0E;x_C&c#C@fGh4&= zz>SucYzQ%D%?f#FY04IB?^-fNY7Q+~0hGO$Vqr^5?r(P96daHWre;JOt1=WTflL3A zGb|++BrNYm*yBPJiQBD}ComT#D22n$vc= zKc(%&1C+rM`vHya<0-<+^sgUp?rP?lz_XI-4Xw-JjbjfU0z*`G6EwK))KYcmi@sr%L?8QT?IkvEqALm_Jq6^66elY;939Bq2bP64Kz&2A6XSJ{I zJ&?#9(Clc1d^fLYZQME=wpR@-GAyB~86smqy=M}xz(dxUoscQo`w}SP(HvLbCPD3I zyQHS9Wpu(e^3tDbzf9!%0tOm+#nweCb$4n?nDvCCbh_{JqK|_Ob(kP5cYXNi60PyEMb`vAAcjM*bx$KY@hCz8Lrvic=XrT z{;>Bbt2oCW7UWLS}oh-xw@-rFL7Af{P|;)z?0R z(%SaI{0JC8aIF2gav~?mIRp_>rT;5*#!0_%{byQH@HoxIiFkBr|dwDaY~ zcVJ^8vn|6|a!Z0})fzF37IAxJcvXe8fH|J`GE90uNe#EKrL=RuDpQpP?H)f&GaTeB z8O8cIQ(j$y2=4B#X_fRv-hj&J#3I7uLTpZgeN#t*U;frnFyVOL51{s-f?;rRkNSU$ zI)BWgLR<7X7q(Ga)$1R$)NZ9<;Rb~T$9f)*+PIc%4r)nR4a045j3p7*){Rs2UFr#& zq&()bbbPN}5$GRWM;xn9Z1;a>B`f9>VCeut{s7zD@POH?ow54v+!R%*^9232Q zlxy63Lz80rRu73KOM6_@Csjz@)E#bQ>?$@~?>lz%-VOhVViTjXmVio+dUqMCCxzvW z8;z>NW*k4~Lv3qlaIbyIPfk_g7N;IE*Mc7!b?I+z)$`e!FhZ6*$>DPoyd^m9M6;^?o`M+7)#OV$_(qQM+)K zqO#krdXU)&yNsQDT;-WYqvEvUdWOv_ZJaL0*K5VS2N%wM zGY$s4!1hhtmf_qPGw~_uo(#E^Iq(OBWfYMc{f{4@n3I(pK@I%enJ=U-c`*KdhGyCMte*ZXl3F(Elc-WSD8b(d_@b)i~k-t4`tXlZ1HLEy3Y$6~TJ+dwNpyuIB zMr`F}QIei!|f6aL;WIson0% zo<4!iVvz_Y-XFW|Rmp!6zO39U#y)u2>d+0=)Lo&*a(t#rg8ytvPO6V$Z%M4WJ{6{NGptAqhJBf*a;0^YyJa^(JMW8@VMeXH}@@D z$RbQxcSK>3e+x_Fxe!>Z*C+ws;oni)M@TvJ`mK5ERgis#Ta8#jD=XW6Y9uwX21=Hu z3S2V@@Uh_FJZ|FgwOs_F2D|r zuqa#&b1^jL1}D`&x+`3^vzYvnjlyOz^Wiq2&+S6-Bof4jVHjNSF(SP6jLPOu@fspm z!XZa;PXq7La^n$AR^c5gtIXOuXAXGm_fpszO_wR_UlGFL^`=lQa+RP)*GzMVr(}Qg z&B1uw#(P?gEY+c& zn0A8doZl70&)GMef}@hR$E-JH2R0~zzq$qxk|>*M}z?RPe-%7Bzi0h zeyA2?2~<>nQ9<2>uc$B$5Je`P0`&s7Kpf2{>2U&`iag2%E0ot74YaOSLAmxKF;@+IjD#S2ON^)+C6&$E(w$cjqvqC zi52$aCl`}V{^pEgK(FFc9T>Y@y16;r)Jed_^eiX0l$Kr=z-*H=~AC!GFN zX0^pr{48QV&tXq4<(Uup=l}h}JxzqSDL^4O``?hXF35xO zfNs@D6K^H|7D=5!me66VT*nFg>r%)?ujEa4Phb9HEHVDlRknmLE-7LmF}GQ)%QKCD#w@XlI0`3 zfDm?5a>sYU{g1>?`W^%--Kpa|fiSIQ$jTY%eJM;7o}*6nSUuFWRr0u%OGc4llj3cgq}Kg*Nbp`UB+ z&K3BjD|2mljS2ROIt$Y56{F+I&eScR?q)jXb`BGOQm{fDV!|eX_}yvlFgx6h-QU}a zE4!Amjia#o3tD$h;Ik+b-t%y|z+JV8eIo-;iGc}5yo+>T=X)x=rL7tJqjLX-=7Ggo z&EqQ(Do;o*o9D>tO`UaE`}Fgdr1UD1!|`>!=(z)$-XhsNj0esy?%BYBn(+6SCaJZ) zLAi+Too?z*i|y>gU2gWuEl4+Zb6awDf$p+3B31g#1T@-M&+ipc!qbOg5W0JAzyfn3 z!cvZ8Jy?75y{p-?b}+pAc|toVsnoF#HSCLoycg}YVTf_Sc5g-Y*FJ3*{bMe2-27in zibR#!S~SczD6*aGh=WXLcoCb!7_U6S^ceY11J|79Z)mJ`8*OQ15Wm|O|4wDTWsVHT zugiowRXUzj)&Ll|kwqyy#__IaSjx(}TVt&^X3Cb~S!w?kO1`^-rpyeGW%`%~CI>6X ze5u}3&W+4F`}-y|rE8@+9H*LOXbLfh|67bMK<(Zeu7=s~Gqa1+`3p_xCN+f-g6Gp7 z;oki1Ys=aX|8e6MAW*b12t}wmqwgAxC#I}c_TF@ZHUdJ!9z%$WjVXte)}1eC)G(kp z19)&+`-boAQLQFS05!b@R<^lyD9rU4BF00%py{XARLl6SR7|&1GN$rR-zHwcR|zr< z*p-LhL2svMxbu_bLu^5Dy$oYwY^#Hpe}Y_DYuu8heQW(q&8jQuN-{;$oH|Q0g-gZb*`upMTG0n z)OOC2oE%$u(j?6)ETpO|6k6dB2szT(x_UG0_1kaF#h0U1icAD6lb)KGD#1V%I0(eZ zO=hRxYBfZdhBme)4Bj!lHt5&4Iv}Og^F?YRQNvbG#U$Ka=^c@S);&MVh(Qa-^K|iJ z$+T@{=372cyi27T<+T;g7yQ^wWu18YIt5KsIZJMkskjUb7%zUBb%;xwvL!!J>(<&0wcrX3e(A-di>(LqT+W_*gDT8mK@%vo-y~ni7J?vN4P8Q!-oocuI z`M?ZoI35sogvZ(9jSe{gQedA-cML$4?S7zxSV>A3N}n}Njmne0{?%z)nJX|$jb}Jj zZb@7Uz*?v4P`w)MxuX|;P9**q=IhzE=}aaW^}&V!Ck=iyE1ZiQ5SIBU71mVR-^ zONdIjvoMt9k&4PiM;;F%=!FP^QQQXatiWG;`)L1ldxD|JnMn~9`}^T|Y{(&~fbz~i zYZ*8w&?@So@v?YjB#&pb*dbb;wKDvfd(8Q|kIYbl&FymrpxqEWNCx_nFnyZQ@X5yf zWdU3aU)=jHt73RPwIag36IWyX1^44^h9l9TW+0(rK&vRn#@A`X;g$y{ zXU$D?ghV#u@+Yp4l}{T#Ds{w_uKqlHir?%z1PuW(*YD*W~WQOuV z{{oU;B4;Am)TqO$knfe26!1^?t>o^0Jv}Lhci;aNnYn|fS~h9`j2fLIFe``|8WR}t zhYD`(?osbv zo&{W&8{xZFj~gbcme_gt@x|q%J3<|c)s?qq-u*n&q`EHHxv6n!1TEunY$8iBZ>H0a zELcA4h@WqS^T-U8Rx_%N3lDMVC9gq%4Dd=|MG#RHO z4L|0QnYE4Am4+OF?gT|H$m3&S| zr20_rqODV(-plm0!)|$b<3427SC@z1(SDh#!x6WtM`&Ycjz)P=`D5)A0q8Db1+~ff z4vfu9Tn7vs7I5Gu+rE|Hx0suf-y1CS!%z{>0&M$<_xA=5SiTC_P(Thp*Oxy|5Y4rC zML(HCguyK&9cmZzr=o?ISKcemWXw~eBQN&qshR-3|0KklFr%*C$KwJ+?Z?wA-Iajc z!W7bScR5*5p(7l14u_+)7ZF)@ufW}!-Ff0qaE@~oCQagJ&)L9yr@jtjVfQ4)_or5- z7Em;G(X$L8|CA`Ux(e!wx}%$n!=n+H6v;V9OissoOXc|^Wpbnt1f>C?AW}%@cRqR2 zKMc<{)TM{+{^_bJ`F;4ytNASUhYruRexC9-=4dr|a{{5P2lpJi0NZ|s=8-L$!_D3C zTiT};4vH8dxgaM+5tv*pL;{sMD6=7D^W1N8yB6rMLTX$vm_87i`*19&fhT43FVW!s ze*oq3v4{zPR=G7V+`R4dM??$|hh8A!t{fwicK&ssiu)^u`yb;6-b=9ZPjI;%bo_3x z$y_EJ3AX|fzpRR~9@ItO)Q)*^(p51gMzZ6{p_8B4F4Z7POP^FVNK|3+pK*Y%A3Dgz zRW1F@;=S8}qSDe=`=0H$c=keM;BB)%MZ;3=mdNEd#=j%9U`b(=>_$)LXCc2~{(t9i zpwRrE+WhK%541)j>+IgXi|_KfyRMyGh9_Xm^cIlBbbMC6_U-!mP8N)pmpAi15W)W) zMlmmxhROj4DewUnF;+#dNrO@ww*K8er}%#eShaUG|FfVC`1k)VLcp+0N>0Ee1I zzNRK9-X=<vFtMz&7_~<>I6Ks#GyEjp?B(gYz2Eo!LOMipU|_(i*4d=#u(q!( z*8@>$Wot_rLP3fCiq#-5ZX}*HJ*d2Fi0%kMYMJSn5xwz^#(|JsPmb&hT}v|?W(flt zG#K2}cDmqza?GTb+ZQ#Nsnz~M+lj96Qq@$e1L5#>WY&L<1 zSU2lQPtJN-bA|PmYfMDqkDx62`PwICXe~>=BaM?JNX_GWA47u)zB4XceG^9`J->%E z;Far~`Ln6RQGD1daq+xL64$QXzIN{!;n}bM@J?CnVc`IM2V2C}y0n7khm^$;Wk-Ja zQvZ@*(72Q?_Jw&wa8|A_4T;|gGqa{`c(y$0&aI5t%>~7^Fdn7wZiI|OAi)(?M!UUur;&r9{5FE#xZ3QN z<~eDb;u#s2-6D<#VsD@L`lStKT5 z=NPUfabVL8sX^~L|01eoL?cn=IeOFUPBln>YN&0D;)wt8s!40+>y1AoR~BvY2NDEF zGfBkp6040m_+nRWw|o1u8l2MWPMVrf z&0V~9dzt5P>iXNf*AR+zuijQqz*G^oJvmo7{C@lcauTnd zrdNh4j0qm!C8)QRiDa&0CP2g8R`rKW-};V}L)~U;uawiXpMP;)MYQV?DbCeq zyMf>m`@;@%FNakd1CEZy)2w;-N1yn!>jElhU;B*)snh+mxG22Sk; zPUkZweCE5)P&_sZO4JCCoN*4@;*|`(l}xdAJ_NnDL{*N620uwvk(;J0+ID-H4Q21b z-Ej|B8X_q{^+q1~6iR3v$$?vCA|vwgd(IyIEB-mo_v5gF3Z#V~eWK55<0|G!YI|G%~npGi+kJ4XU!>gRtqI)whCdX}B-O11<#n1EF@CUYy@BT}(o<8P|b z{Go((MQNpdy=v=Ci}U+gI>*c!6&c&RR zbgeDW0hX9();)|<)>Yh&?U~`h7ooy`33E>_VG-w8%w^BanjihI9|AM+nr^90&DGn7 z_h#k)bXJRi81Mc6iHYa`#J%zVpHsf`E=@%~hz9?~yRev_{+z~q7^W=cj$g;QGZVGk zrt)>W49#rPInAuXW6w(9TQCWWBfXmJe;5+qGc+-PEZ>CE zvTJ2eb9uGcaxvEhC*E%MWtQ+Ks^=e&v>sL1JAu!y1jHQj3wtRzI2F5K3LL14;>c zz$>Y|>q3)pT#{#VW5#fq1`0miYuJ3EBfMTeRTuW@pr;q!v`N&o&V3(?a*awJvBkSJ zkmpd~cM=Tw9B4fO8f2z{L4}&~jSgzvDhA9)KPE{!doGW6`VJsa;0sPXibGG6B|ZP# z-{Xldw$?$#*AGnWXW=^@&?;qnqZlETwxkiZbb9Y1`83sF;RDk9SbQEzSe2Gw!j}I$ zMn26WYA;R#%Zl#w4NQ&GzaQEzEOa^4_n}x=l-JHk48^J}iZ%TqAVuS!*2x2ZeoQL) zmgnd(+lAUQl?9IPK4K2EiL`Sd9@)=|e?J1Q<0U&)J)!0I{p6M5Zs25p4nDV+$Ek5$ zW*S8?!ISp@S?izUc+n+RY8>11!waLdsbKhKm%Q6U{6BA+nA7p)lzC|VO|~{9xa z?)FLclOYW?f}RiT_ia`V#xPBWCj46mKFzwIF<{Fb6AzgN@R{mP)Rb`OKJQ#H1yIN3?gD|MPUz>^}=Mu9+ z7y10_*)HzRdM&CuKd+suc&a7nZ%954!U={@u6Yg4!KQWV24}RTIQGy;`5`|($(ItVuS6r zw`|?CobdSEi^HLnIcYa@_xv+}QTRgAs)#rhNM6L#1?!~BjJNqP8=qXZ zr9|{HGa&`HQ|0UIpDiQ$9SC+K)l%aAUp&$CIXI;F7td7J5o_)`Rj`XN$bTGK$ux!Z zG4HIWGMDS(V-67ev)p+{t#kKVE$%8?C=ulKVmBX4?kCT`j}3)m$120IL}X-HO9u04 zach&d);MXooCr#6UVkH9^;4d`@IrFv)2EI>4*bZl`}sL!pZ86tfNK>y1PGp=%wI18 z-l0;U5LxRC*L)D=8B&;FK9%zTc|}o#CXLFIbs=}GA6`K6uXZK4!`UG_2muvL4dL7m zY{_u_%0a1a#RbS)>2qqgbWDAfwsg-e?*350Yv%X|Zh}k$5xjY+-s&a_e&ygEWBfBw zM1QZKmtV&DUa#RHJiYYwV2ndyo}*80YT-I81Z-A!@f$FOYA@_<35d2@t1XNdMu`;zjRf%_W$AuFGfP zQYwaXV^YPdcF_z+E-TX=VO2Kp$;DfN9Yf>)Oi;iL(CiRcEJEybN(+~|4lV|%1b+Zm zStjy$r3H0O3d#@KN~A5Fh$b&U5`9ykDx^~p=TN-f%E?2UDBi%(;&&2@*^RZwWvzM$ zXdCpxTL5H5CnFa6&xZ6J`#bob2pNBf4jprvd}3^fMM}u=7tUkV+k!jn~7>c1r2|VIk zu&=X$_V5*n9&v#8E!)9C<<>davBk%;+61-8GDWAcl0zAqUo{cQ7GLK4g@TQTpr-EA z>a?ZQl!@f33hMespU&=3ZMRCxu7cS@Aw}s#|5sc0>?eOFS{4@Fl2IMZjNOio=)LrmYR^yP-N6AkF$}GD#c;~gg|FYy6Vhld zm$Oomkh)|4zTGM`RWK+B5~`%&xRVqqnNa^~B3*Dl=YS${4M> z%n0eWF5P4uGtsC^<_<6Y5Dd`eWYZ=>Zn zb278Zq+R67w?z9B%H-Ign%V71){;X05=Dt$H@Ty4_`Gxs;|Qnff(2c3Q@7rU9B(!i zO6gGP-Hn$XLh6XR&56p%)2Sr+-#@k`NVd?S?XA%1x#$fonsw6;)zX;|uiQ}MahHtQ zW!CI=yNI2I`o4j=xm0+f(oqxsJn~9r*;MWQx{@F@a0D$jG-BMCH2N;5)mCFk;XP!# zxhi~{xBedw_ZyN7bF;v}Y0CmCG>|rm3iw`vqxQ)uku%oq%R|%#%_Jx!%r%lIC4&5=nlgGFl<`feuKGatGu#Vy!_5 zGxOJXEPnT(hO5;HUKM%yv0u_4nqe7VV_aQtI7m7YTu!ys0>dI9ZMGhPk=&5LAL#S% zmLCc&2M+#rQJAk8aZ54pRS6mx!$10Ek08$-ZptPJtTW^>V3kHJN|1EHQ3#SXHR! zFdSC2q_zAPBgk^bu=6N2uHj&IK)d9&4`sgz?`}0?c*Yo6Vg1ExBX%nyubANS#g(@x zWMa8X=Mv~$s65qV=gq`S)Y#_2k!d{4Mj1*ei%1vXWhOZ`P#%}?zuT&H4DktI%zTTW z#yext1h4Weysk?~^Z>iiLRL`F(kB>ob?2ku#}xF&rFzb_+hna_td?@@zO&?+1uwSW z?JAxD>Go&lAH5l!+^RMHLJ!?ZQIdBD7Y`n{s-k7uDM!>4n}*)eSc6TT`*YV>PKl}H z<=8khpU!}kLXQjN**Hso%ikJQSlEJ+N4$EI9ok@i$q-dTJfqx)^J>K%`|oA`v6GP3 zHVf&i!Q>x?7TILj5Wgs6wgS=ogNq=$#_gh_lxcHiK#})nwiO1A@?yy0_4RImgVEW1^+My}st945F5h zsGmd+kzZw+*C&AAqLwFJQ$LmE4Ia^~#0rF5!Om!rK(#pWtT<=<{OmR6$f4w=msv(Fp^N#M2SY>YLW>Vj5OHL_mLL05Q2 z)!rcw$|wxm`c-Do%B(+snb#g(4`>?;DzX{Q;o08SE*jcM3_MrwpWKqkh;nQ!N>#0Q zFB)Oea`pNoGAILopMp>Fj=7AvL-S%Vf4NHPf4Vf zT~wDSyH1y094fL*(5G`6&)Q7~?zCnOx72t(RuCxFM+7%b8!lw*ety>`H*)sr1Jue} z-supK1@?VkpGA6{c*fSt+W8N6YKxiESDb=dZ*oVGiD3hQp>AvS8H(GA;0aXv>8=T- zFRH%=u{>d^3)0{QxZ&SR{LSTEszka74(Q)neC%ul-u7|?`M2F~3IIj#Qhs}Kq#`Cajd#c9#wYwZ~7%f)drKA>ZPVD#B&t&$@PXVm11U_7Oi5@=4tO z{V&n-gOh{&+u!|p-$!cdu6W4qbABsr=DJkHj$M!?*dNFV0}sy0jC@*{p$>RrhA4$y zYhPfqshWtVh%@uqe-}?}=@=mI4FO}T=#~?559IytMYe&S^kBxhXHw!TJ>H}V<#ySF z!2`PvO*^$;;&ZsRd{1x>a?tKUl_p1B>lcbURn)3QZY-4Q-Rk3J?rIY~> zOv6Yp3`n8voXEOHM=34ByD`x*+746^RSa!8bQ5X2y@r$w^h*ij=jFa4afjt^4EUrP zxE>>Qqh)gAJ*$~U=J5Bi#zaAGG5T}y47(8xs*$P6@K)`G`_kusmcLMQo&%#FF1fih z-n=DHnx`~U!y!&xRon3Uru|sJC99adb~2^|QOq!N&nj{VXS_jY^*r+8!`v931gX8LUguIL8~xM12Ye_dZkq+J_$9!nR>+9V!CQpkvgxV5`%C*s zdm$HaoUyo;ScbQV@S+s+mIjCE@rp7kOd1m~C>!2lVmYzBCD@J*hZJjqB~-f) zy{nKEY|(eI3A8NE77Cl+!8$K+Gs90zI~BWksL{xMN+)m?jaV=^Q4XP5wS4ayO=Dq<64mU%Tg>K&S5YQuWeYH4nmX|tRIo)?DQC)&Adry#*_FLDKdH z;aVsKB{{q*m^~CWD!cdyd)C75!|j&yGz`(^8rn}9uOGm08P68 zUPqFLTWHTiL&nYQ8biuaMG+;qsZecvK$AXm!g?g6j~MGcBGnjF=j_$3cy>IcZa1kx&F#OGTcr$No+~Zp#21g{+v}$IIoDoqp4yu)8zwqCOW9w;Ei$BO=nT70MOb6ardJKL|E9dq?gS{)d z=sS|M$EMy>{niR==#G6Wc}Y_$49&d6Z7qyL=9+Rqki*+P=v<&i|D0IUUgpckX=4SU zVOczC-DZ_}_4@2M3Ms|%F)t-MTjSqsTMWhm2Qo#XkN3ORY7Jzbm?|ZDnprH*NQ`<` zH7p`QO;llY(ELp)#`iIY{g~$`r_7fHA46(2VM~1UHMzyI%@0mXdiZPDVe7$7o5gK? z2>uA9XXHpCze8?t_5P;mj9b@=k45&SfBjUlsIrYOL~QiWC@GTweMW0yRik&jDj{EA z^vY00+t$HQy*1s%pe|{bRqf&KAq^P94dXbYK*eAK-RtMve8Lr`JnH8(DnoZ%-KLo5 z<1^J>{}XWJ9_8{Z5-@y<-2R^7PyL<9g+yTuJb8>$_aKsdsz7Z9YO=#{73@{H)-K6pjn3HLik zME*&1h?N}${C;oUS~OSav+b!!D|~k(Zlo@H0v=QQPoh%zR30%&`U5N~0&O09R%&2C z<()ibd=B1L@^|{qy(!f4Pg3H4w|4lyX4t>BwQmaY%i1XSp0{ZE`5`3AagFIlIp$7GDlImLK# z86#Oat*Sij_i|8fdkNZqlPdpb1?AWAiSfNP-GA>nOTPBB1huC2Z;A@I-u9Q2f3`jU z-{n{DD-Ks?zE4j^4xrdYRBY2{uoHXF^2v|WoSX%Ivt4BtMTRkniS_QWSRy72={cde zOvKoajg19)K3+YcQP?n6>sfwxQT%?ug{O|uEHO|Jh z*pc-(|2~i)l-j!m9iB|auAzZ}80xM!;I24ceeZdK#^xPRsrmIB2xBSbm+UqT55O@! z%J0HW(sKPgC&tgRTrdan`g>`4z|qeVKqU>_*5`Ms=TpCdd0S)-B=8FKRGrrzitg@Z z@yykY6|w*`nuDR~>FK6#tTCa1P1IlG4Za1I=kH4#7TT*1MUN!#t7Ua9WGJ|gD;xo+ zOAp1ZO1be3A0)yzlKy1k#7sp-<&yo1>F&$p$mQ{N?2A|cvDD8hn)Sx}WzL?Kn$K=- zC2A^?ZbBvFWdioFOP!x?o(C>KTm0U$x*Df$)oDB5YuE&NAdkTpI_Ki&%fLL*iEiCH z{S%AJ($alE8uQ5j(4r4~M@;wJ3J=Q@p#%Ta$NsZ{mhuNIcaM|;35FIdNA2=qeYgnq z5&ZoJvgbrMSnxO6x>8_7Ey!JYK_=MJZ)MfaYeK9!zojIE;=P@Fn#z!BE>E~mVSYlb zIaf&zkW#Kpx42M*CTa3Z^qG(;zi_4Oz^8P2NmS98r*5A{{r7c_FSx^Jl>T-=+%6+N z7eYSjzeKy1huECzmo@sfv3rPK}jcdJ}cvXtK}XnWC0qeG?Df zBFor&jFt5D>Z!qRxfN?MB!vrzm8yIDF?6__&v%AEd2w*nQ4Y2ff|^({0QAP2(}q#_XAa&L}VZvBKZL_>GpN6QEG2=|3TXW!UPP11InC0cqE2#iJLFioO6 zyQXtOOyLu<;zSGIFd;Y&Fs!9CK3*~T9#oqp8-G+UnU7FYER{Pd_+m_Vq9kJxz6S4uMhYBKAoD%3~HZ-*=#GMjqcpWID&M;{P zt<9JEsEFByvkGj`AhXHCDDz=AIZPGm1xCHId)*8e-&}X zu5V>bDF+wcfNKnfw9&K>o*&zQs??L`=0Q4W#g5PO2uSM*wjoq_>kT>_UsGw2Rn{#K zYJNif*Aszd{0*+RGQKIjGo6m2YI&oB<)(uQC(vYp$KUr0Lsf1RM2eA{(Qzd85y7ym zMJF{A(NQ+q&g7@6_)LJ0z7lToQCV;Bv^1@`s$|@0Ec@)UG3bu%0d+cWX?H?*o%@NG z)bVBo(_yzWKZyre@(J{*u|twLc=}L!MoUffcJ#qeN0;N^RG}qy>l`lAM`z46ep+1`yIMH7g$|fvZlufHG#FkQD}V2ot)h>U`JEbnd#r?e0$!jWK>StJ z_(I6*qmNU;?H0BoS3I7L^|}ZdJ>?aQYNUNUc$DVW`>SYEfm7bMgJa)QQ`2?FZE$vK z+WIy8oPb<4e6?3KxV%j1)zv(l28=H8!GeBeq_SX*O?VyU|C28{eJO`rdfe;LMj|fk zF{QQ%T7RjV_h2J_b0N2kf?{=X+pSCPOW{-Hpf#i7QA+6HTEr28_SX;`3XW}hO7Bw} z?Vd>F3BwC+5*uj?m%P6{pjhHQFlbvJj+wx2cZ4KQGu1)H7)zzNG0E zTp*DqJen?^8n&s>-6}P&c5*x2PfPF+YsQVK+E*%5vB`FvKCMc@;XSM)`cvGeUmf1d zf%t0__%)l&HD&HT;+ZFr~Y4jM2B#>?u1Sx5RnIskY&O=@;w= zO~itFUYBg&P~+U6Gl70)&8++EdML_o?y7Fmg%8|>khPYM7B>K4YfH%OgE6d*D%A+iB7f9 zb@WI0r;q+&yMwR|OFc^k&E+QqHWua6g$ZkkWvKi07poXp|_m(a+C`g=*!R>!;s!4FK72Xy(>O6cXUJWBn%Mp+7DDO>kkrKex9o{K!r zCVg5pXrS{VlLar+(W_!qzPLYlzQ~dBH3}swz;D~(WpdZOVg4REVXk<+fBL<4b`hx=hy8@VKzC1mhL-dxJ0}B zDYNFw`nkchA%a`bV0(-EuTK<4oO^#5`H+5~)Cm zmi;)%R{TLjNNrcJ*)ILDw&3R`gc2PxcA;NTTHKaj_43&44MP)4w{+O^PrU2rl)IO` zJ^MVv3Jzc2=Xqn-AaS|HrIY%+{fyFi6^yR0LqNqk0azJ2(TRk&zgD$Y{!HIH8%u~pBXeR!QUYt z^iYs#8Rxdj9{7NCV>YTJx@kZ!oO=YVtm65V%UVnHml${^$>?#<7+b6h9IrvXMp#HS zNJuw)>g`^>u~Y8cTyrNKYt1nq<=$}d-j1zC1i{%}-edqJMPVM~hhX3+FTYf18d7_9 zeD)aUfu_Tmq@~~3%#(LXySvz>@s-5F392^Y4rs2RTkDf-xY%49Z?_hbWsvNmG!oLd8a@tt?)sS7{T zj(uGJ1sV=ig+!z_g6y4*t3OHzPOW;T8m)IndgT==^{fXDXMI!BFLD$c^px9ZJ{!`M ztM_rahG#o;V)^$Q_r(1g~=D@|PSGeWGS*!s}(VNXyK6;{gujyi&=*HhPTH$Fpxn@JqMX9k}3q zlMCl4&>wE)yRAFJeg(^)&r#eH*zL3DqMlM3LhEyUjScRSWJz_xb9YKkucTz+%-2$3 zhXP(J;Lni*vZ;rk2b+Q2>u)I}md_mwCrV&UOAbeQNki|D4ySaMjQA)$evG}mak!A- z`Sf~`{jK>E5~+(NaXdM6hJ6Cv{Y8@=;O!|Qu0pHw?&COg+~4H?6{lB;Z$Ns+(<(Nu@>jVebU!lpOsu5>7F? zqiDql?NKL85bT9By6NPsda&mEEXp7UNGsK6bb^D{hgTd^h*Imk*$~q_sa2j7t`%$g zc}hjj_SJc4KkNE|FX{)6?+3z)GjCW68KpVj*$0geWuC9~>O9dpr+VwZbob@aY_0G9 zXmy~fJ*orM@f4+{rkaYP8NQv?yw zB0)$H5ybG@IN$p_cir#0Yu&Z(U)P@zvG>k?-~BwF>1q6cvWtBC?#KoII^nZJPtay) zW_C|^JcDfZ#{(yf;iTj>c;U+^V7`<;+wNDQXE|rZ(+G>}>iR(n?dQz~5_Bx(zvW#) zD#0G~%julG2Yslh5;nq;xom^GAQm3HqkAMxc|kXs5rFI0YUiU#K*xeF0HiMG-jD0Y zgqyCUlN73y;!TuUOSVVG3!{>CWq&CI?N!$)(3Uj4W06zWh_T4I1-cK_S2-0nvM&={ z+S?Ix_PGH9c{);Zws*4sbbP16rM9`M#ji?1fmvo1dGP4DW>Xvc@04|<(tH)kLlg4~ z`z#x}K?ovHF&95e=1P`?Oj*lHxK(|*heOatW|EF;@L#W8`%0$?KejS{Je#XGG#(Ne zL_k7VY3Zb>;$h_nX7`sK>bj?MbwA&^FbhebhAOY7f7DJiU~9#ZtaQ{HaGXcN?94;Uv(z6ck>fJj?%MN~#rIqjGT^Y6v%nCJEStsKP zydp*Vstj;x64DojxSYc9DNPUFg5mOtK-a+h|AC#t0ptc z$1z8^Ow;jrnPe8Xdf`<~&#@gB?=U~@$y95DP1}lUU|wTC9;l$Zxd{iBaRxKWc1&p& z3%BOk!fZnw2Cn|FHqyd04u)#8;7rPEygr(H&k29Oiaxx1L*9k3A|Em;nxxRJ$J2fJ zje9;Q1q-jp4A|59pe_Xv*Qr&bes^jzg|AOR<9;BGo}}(o28!)89@sgo=Dw z=^kXNaj==IV#m~op-G%!NGFq^=m$SwQY)JL`_0?3u>l{IF<<=>H?)2Jcqdse#*RLRf4Ed&w=g?fgxXaCVjbB9VQ|s_ra4WOV(Qba+*Op?uC6LWGZ-z`Kj) zH;x920A6a79pLtHtO3`@tzHVCK8Gwj^~{|{R*XFRXJuxzCil8KPH+Uvb`UPE7h+;p z$59<$w9u#wcdDKP#b+I};^ z{qhg()49aF>=h#s_|sf#yYYlSHXNEPt~?q=AWUg^ygK!Mk-gc;PYH^OdUeA`A{_9+ zr2v2>KDzH2WcJEGRI0${msTrKuLmRx8sypuNS#g>N>2sZ)Fp7oiNbw|q0WOZ1%aX2 z*SSFUAb)~T)yn{G@BCCZ?+|W3A72DLn(B(pHqS5-dYOEz25opt=JC1C9VRkz900co zzY_uYUarc@asGZ`^R@qKJJB$B+E!@!?!5G~?->Oy z&#vXiWiP0ZJkg2wMX!2nMRf7;8HZ1Y@@BeY=r^hZ`Lee2)%lL|M}HE+TN=-o?vTa* z6VCe`{fCRq(!|*1 z6N_y>Ldiy-%i^Kkkaq90@99$1>>}N%=^CF&E4O^M0Njq|-ISVUu}--zGg$WJ@w7Fi zB>%0qP0zJ!9hP?Fd7c$Zr_|CpmD~V75iK4(rB|SKUZK%LFeT^gQ&`35*(zdzo&2WL zL5YdiwogT|AucX1R!_tl{`Mx_&Lic&c=w^jqP3$PVciDsPiC0-I z-Z!i1re1in7pWk$^Gsm8R#Wdx;ax+J}3 z0!MyqYW4uBr<_^EPie{}a#1$}P`EjmOMV&~9xc5GzTrPq$m`9wk>@?NXK8p{tF#F{ z`CXBuZCB#ANLOYg^PEu1fq0OQ*~vqnS#VGLB+yB@O;GG{A}`GEL4L&+-1a=tTfb?a zR(!3OtQqYwG4BP(#R2JkQi6sVtBL=HItHQozypw>dJq@^vOJW)ov2o{4r*XeiIq@~ z=@UdlSvR#8#BZHX z0#aE|;Dt%Um1pk#7#$$Ex>zqxHt6%tn@+er&nh74{H#Q)525QiDy@n4-8WL3BB}@B z#;BodMq@1^FCCYe<0XtE9`-jrtFyAG#GpTe^k&vXKQz&^dwdD>Pg{Tpdsrv;#G?4c zoV9G_kMV<}#O@E@)<=VIAROuep?(=Dm`ZpA;*w`NE^{I9+||6Gn&Xx|(wsVfh>mSM zb)dm^L9IK*B5*%bf!E~hARepL+kNet)_ESv##_7gShj&;S^@K9%_Qb+W`L8h`k3Rw z=>CgfYk5;Ur;#7qu8cHmlgbWB|KAI)z5E^M=?>pkvs!6Y^cZU1==AWZt|TYn^ASBaiNKf|neyi%;a8PJi{a0!0n z)7UeK!1}U19SxWAB%+y56Ck@S z3$7`-KTaSCvLO2JElSi!)bBtPhDixcP)O^p!jnZau6-WVah;h!csZq$y-*i&^n!x^=#5m`Fuf!;SrPmV3sB6)YLDhGYGPSs zN8NDlyRHZ+HyicUfV*z~nV6dOyA%jsvwxMgNGYZ5B` zt|!-;pzBiVHEb}0UGjq!A{XD`8|=K@^OyEta4hx?4Ea9vo#2o*<9c|a_%MFj%gm4( zJmU`X6yYnWS_22+L16C`A4Z% z-UkPC|48zy`nE;}YZz9j;NyJyv9|B0ZT~|!U-p!Ou^q)G&*89_K(-j7_i6DR($3wG zY!i74H`7u>W`zgCtvx#A&JHgC_RzYU;ysRn-YXsZOuu9Ot9Y&0YOSvf0GcidPbWF{ znueDMU4%2iS&ja;&8{?kNvHq&<3JHv#0H4ntJ-}?Oe&>_oy z_W431EZbSle^gO#@{Ie#H#ejT7T>i_(8p_DwmoDh^QYE0bflakrSO;Ef0mkfJ@Y|y zqTibNjaQ`Dg`zUS+HKo^INx4%jvWAb_Mvd8yG_0q8HR#6?f?&Urahy z?A%gQ6(dVt@|~O|w;B0?2>Ef9?vUc!1X0-PhG0eUPRs?5)9)V?cCWw}X9HfUQ5>MU zaGX?=f?ZGcXX_(BjN=|5$TO7mO=@0(~Hvpa~F(|v-#@9U(;V<_T_ zBtKlE`^qT-`(&SX*`#luAd`g(qN)?v^-S^!b=T=&vH~!3Z;G5@5y47?6+WldBfFiM zfwT0GghU8um{&Vqr_6g@xgkuJb8w@s6DE%n-1WM-N3TBEHtW4IIm@%{)wUZGvlM@$ zfTh38k|2J&ES%f$c~e0+@;B3KTx$cAqY{5P+q?dM-j-JBldk_@5}kYqu+zl8g+(kZ|&M` zHxhtN`xqEqrA_$k`4h=4sel-BK6@MI{FLbWBh!d*{@!?8`HKAPiHKd1&&Ud)p_w2C z0;Al8f9V#w<$s|kL5A&EkQXc$C-Mg(dr)E#@&Px()mw7fZJR0RqtY~!8G|u`={jFb znPJjB9cq`CUeIqa6XS!xBkrn8tIvzOC@e{RZV!ywR@UKiId{BdNbb_LVntP1(J<6% zlNxEbo~wI~8)gYb1*3FdIWr>~p&~U+?A1<~_`PqQ(F_;Sa@tJh=G%<_1mXo|q6sTwc1C|BY_!UCdfdzXdAq519?e@?|+%_5{E> zmWzA6&t-je4@H2bFI5Ip#3Wb+ZeF7ir=IbD?}%|(Aa|ltX3lDL1U`SWq3SRJs~$LU zbZ4dMtnW)*DOKVL=yPdw#pzSIuPt-f0h84L&v&5g33Dj{av~_wM&!3-7}~`;dW6-M z&WPP)`Lv$WPAoI^Zx}w9)k#T9t*I_{{W8oYi!jkoR9lAQ4U+;xFG}8#E}(0F3~+xz zF&FGddU?T8eFV~BrEW`ic&oL%qu+EEhia-@-8@Yc_;dHZ6QFK*kQBS|mw)%W_Qkf^ z(-`AzZ)wlTOqGPi?ozxvJ-`e@uaqREDSxCu)L300mo@%-PTULXF(JB+<}iH>*iR3| zq<4vgm^Gj(%im~=iaIZ=hgx=WDiO$GhHxlq2*%h2%Ra-AqVi%_`s#y!@tUrndZef3 zm}f+!dZm|C7|Xh02TtbnssY5g^|Fm6{Sbl2u#N=>IMGkg4+5UVoK*gA;~g=O5U#)V zZf+Iu+{g=EKZCzZ2djxZ)%E>-`+0sK0f zQ3ag@lX{{@^@ti5kS^ZPMY+{f^N|OtFEr85ok@xE>N*3%FS50pxw@6ywWRmX%?A(B zA2Az_Q*|tyF(w?XfWA4@z=%#jwys={A*C(UFM2tOl^VoyNt=1s0YP~^?O;@Yh4NUL zFP9beB_3}M;?LT>y*j#2FNXwpPKZ?BDU~iNaufu*0PrhO4I9Itf#KX|=4GvwO8Q2> z6SSXh^;y;Vg}$bz#)`fw+t_5+wcc|HBR+_+-z3XagA!V(pemdQ(3{50n) zV2?XqODZZMRfL;V-v=UcS31btSslHbI>kCvh$vQ@Q4g&*wO#uzReeDHhNnXZgd>D& zr`S1l+}u~LVh844DEDl=D!3eCRM>M>=F@REme&aV%rsp+o~v{m;?2~77R)<1lbqVa zR1u}Ap@bx~UWdp&iVhMy4_2o=!*~uNfXBbGi^<{_`gDy+{|Y^ zl5I9WaxZ7<{AVFqf#J{JsUlte8^Y)aIj1}a&aKwjZy!~RQUO-teScM014O>xwALN# z(h*epwCNN(DySNqCALCy$a7C%W)7p{)?XIMLges6p(S^9hxWn@YD$LjDxj{;KR)#2(h;u~u>6 zA!&-^L4(hA`YgSTx?N+gMW$zTG)YGEl_U%_m zp6pM|*BDuu)xX_FyMahp|TyjM63jL^dr*&~9$Q#lTf`s%rtG^PaUc9_;PY0Q3-~Q;}Fzl#? z7^CJ|1^;ZfumATPHSKXnxeL5RH1(x>I->5E!%P4+R!v6s3})_TrI* z_QzC?AnN1t1=B#cD$WUVTSPLit(iG?l*Xos+@;)fO(&1TpMB$|7tGpXU|_@7D&uik2z%t#Y!tBPxYC#w6!>RkOl9Qd05$?G<&vG zz{i_6apeEN>B*Pxhp(>#7_(f0r%z3h-^}1Z94c>q^5Dk2e%qxt&o6NYP8I_7+3xeS z)>ihO%>D0kvF@@qw#80GTj55Bz{&>+gynyk=#4ff{QyY%_Y_x58p!8%QX;c4`OMTW zA-=ANEpg=4$&t5t#9NBcV6D2jYTw^4xs1#u@>xo3M;~2{kv+dD(ETQ-Bn3%SE*Q2ihej{D&0xGN?;zg1vopaT5_uek0YRQ_ewK+emKtZiwWfX`_AXQp zS6scTH1Jw}Oi@5%K^cP)PnOCA^0E}-?!O0)%S74$-~H#7c=rb)uk&o@n-jE9WmbF; zb%ws?|X`fxNZ%byp4yEZ(hTpY#b&9kd(64ND%dzUwGuwEtPqd~DZ&HN2fWAy;GP{cPRG%~w z^tApur2U!rb6V+7`9qt@1h2R5IKzy&X2qqtJaq*PJCW%X7tht!n(BI~sT18c9Imuk z?|nezCdI>Me`?Cpe+QX9EE!>QFO!f1%0kPlSf3jP&rZy}57Sa17k$-sH$Fz4JELwP zT*mSvD5kwBw4#*zW_T}a((}}SC#E2-k)fue>T*970i|hy&H6J4?xLc57N*svQ>Uy~ zQ`o#|gs`mid3TNG{DA=2cckjx3D_{%M~@my;(px%WJwY@DyLvx_iMu zTUjhcF?Rz>T}ow?z3;1y4a>(3ho(5r9q!-n+Bl?bXPgyDW`fy~&&k;<2Kd_1n;5C%Z*T0^n8HVrqZId<`0lpW9K%BoP+B+A0+>|Rcx;+ z@!xyj6qB9HN$9+%iBn(Y^6yq+qvtNTGC{>^upxBb7hn)NnQGQ2L}eX1{Vd4^7q`}F zXW>0D9dS>_HA0w^L_7FOT(wttjM)ThJD%=@U(+;bu8N+C3I->XZh$7Tzy>(spp-O79e^(;^=!_vvZLJDZJ(wDR@RnpgItmA- zT8>8rn^|@1G?k1F2bDhQlCN_i^kn8yJ>c))1ACR)=H$tIRvjGtflGIz#Ln1ig52FU zGP2;uX9@vWVs`65YEOTru20?_+=vGWm6di(dLF9LF&0lMKZ7=W)0aAqQzh>7Nul=j zy4jQjv(0%IR2b7cbLMAIDZ_q^SYBUyozQpF*Gg(=ug;w()d16^?_tHtn;^J}6~#(- z7T=i2=Q3!s?9T{D90+iRKL7R}IopvpEYCUt_XKXwKFE`eFw==6SF{y@jroYnX874D zJHcaCqK57MqPifs=BO}D7X#LK3!p-Kz9$4{ZO`Mqx_30NLCxkx@ez&9Kmy}k+XzvF z62*T*{E`Q-IbN0BEEYI=BjdLM2d z@O!?lpT#u`+-ss9+}dX?4){UzPQH;J2OWJV*didSrNnIWJ+Dsi^wzAkwFBWf_(0d&Gs{y!aRc6$zP|C)M$V7sbh0;58o>zV+y>cg)`~m$Y@Yp3aY4a)5#r#SZRxP3Dy{Ph;(4raxgV zC*R7pEY#@Izfb<_J>+q-ek?7#)p}9nC_5)^up_7Uuu3o6`+{>elMq)fkm9| zXT)pTQCe6f*Y!Q7V_bLRLxb>+J{%)jQm+*{Y&7e&gHVreOjlz}6c%3|({OumDcfms zETo{N)TbE8^!Zh|c>%&7$5#61fduY{{2xsH`(-qKLY!4)WgNh8+rmc=fRt-Ch86fP zA;85s2)mb7a={KZ0pkPXr4PQfgw&sAV~uOt`)ac}(@9mIJOJB7fM<{W%>n7E{QOo$ z3rk3{ixghfhVY~~n;R^}LVqUXACTjYF;vmPQWW17ejH`zBAO<+ zDs|Gb$%9oqxht_iJ*mHbChE$_yx2@o%U)^}iJI{TYJI%qT`faHThsieBlP9W*C$Te z8^eA4Ht+xRB-P@O@%zkH{mMN{bsM-2+$({M#Q_Gg?8~R0d#h)d0W*C*$suzhBcmJE z-y8F%ZYk!?ccuet82GvVzOd8_krMO3u{OrLp6kf*{Hk|+1sC+(%Iq>7R$h=Fp9dC3 z{yti0x6#{(aWFhoh@ezBdMJ(ern$v|T zbz0GE3nM~e9Wv)ffS`sY)MO?c@RUH&IPLQ{^cPFbJb-Xz_&ry0AhF=YUDq=QIees7A(%{(LMw47#eps(;I|4f4Y3lJBX4G%5KweA%0V)}q&tc*Y644oFo^tVHJv zHD6qwWoywJuiHY<)X1N<`qJ9mlKW!z*0&!LpA-#LQOZEs4-aY_4GPO}X^A6t9RY1K z6qbGn%{71A&f^1ZJCEIxkRD6;^pizv#^U{MneC^N?3HPITh2a{8hh6I z{!tI&8;!~gLJi{dV_OV zr8mE^g3pq8ScWiEU=OtJZAP9$L72YdyMl$}72V4gGf@|Mpk~orv)BjGq&1pV$}t~` zLTxKD(HF`obS;;e>Ieg59ABaL^q@HMxy!eqP@O>t`VG?COz%p|UfTXRO$!yJ#?kjl zY=7KYpNgfSJ@PYc*N@^-l$K3L?AM-uT)07VfVHzzjzQZmlma=R+Ue=XYC0njp(lA- zk8K_6Q=~`$>lDqRcSOJfYd=X|9Yfk{lIuOjA95r14u;WFwo|yy8Ji;H@@Ln1uZtW> zXnww(o8GBtrumPWWUD?W=%JTHVXDPpv7}!cavt0dETwx%tw;TcZY<<7~ znR|yIBYz7=4YA_ES8np)OZvO}3cpBh-aWOeEq~cenEbUGtI4r$Q1i;JXnbc==4FRF z%=echpy$eY9=R0-@|W;-IIm}4p$7>ls|A3zFYmEY<5rLu;8*VdUrx9)l$Mrm3ZLovoWitp;2lHQAU z!b7&o!0HpD$^dMVsXFi&gb(v@6Y>v&f`mt zc50ioHY+J9shvOfmy?o`YOIpde@uQ-QIzBb&iTCkGRwvdg#O}txr5lTw(-1C2(yc*#-Emf0vIAbTUq6c;rhkxD_ zaOt0ezia-0JahDRu65>rTyhLT2ORAycR%`b2HO^z3O->|GoBXqPMPLAp0-}(^yp9X zOp?nJ738VR-q$(thy3GvwSGRil!6xsB zi;^6bG9@qY?Gvljd})yQ-~EYKR|do3;vs^D3xBOWeD@)hBbL_J&dekX=vACf1OvAR zO*VaR=)d;D`dYP<1e=E*EBU%i9Y_C@=quQHVEug0?sLa^3QoM+@zEw{xSg$pHtts zJ$kJ?s&TjuNz#)zh06KZpgC2g)`NpQXV}c96IpjdkA816x?2$YBo$Ip4YbeTT?g^p z6oHKf$QiGsRCW$FHT47pD%-6DT%@;fJbt-N{a!~YsdTz^5f?H%tP}1MshPqy6DU7l z&l`ohUKtD*NyWBGFLy#g;;Z5|6s`<2@>pLbSSg!HoR33XRSZ>N=)b?kY#mops(Q=4 z1X=1lO<;a&wrpgf#gxjEEz@Cky6CT7?ROF(vIsF_rIuPHAX8L=^BS5UviYxf+%Yxd z7Suhh=z-D~(BppI9lthRZ3&H^udkO;U3!rnr{@rKOc_T%iw`o!Hj=Vr{*l;mHbvYTSQ zd>xO{IpXPGi78%v#*yBr2xAj5pX!Mqc6~ih@UoU)G+QH16rz=m7@E6EDyUfG+%Bah zZmDkzc^6~up~6rnD|Q;XT-5-t4h>PK>b<`8d~4nemkxu$v7utVjEmQ9-7`zV2}tA? zlj;KNnR1rmb(@@&>kO2e#b&Xop!u8PLH!j6sBMYJne~Fr1Mv%YDPG{i&B+8)Tg3={ zJ5I!@L|gn)u*q9(Ym5`s*0abR3K4FX%LVr}7}Wz}geYIP590v>0dzebqyK!bv+;j2 zy)XK%;6#a$&Dz&g6Hn?JLzv)NEUYBsjwDUMSfABvHSlRX%6A9JS9iheASm%j9CnlI zR(qX{G|!ceGR~)U8yUv|*rJqT-i&-_ik*lg?`I&+NIj7qyjs9cE-KVquBGY`YDCH) zjcZx#jx$B6+?5q#ExUvt86`%^AqWm%HTr6mn%Fx=$8t5mZ;7fDr%ivo5&fd4=6Nd& z`i48J;*DqKoAjtSNfSP5jI4;cO%;L(CShU3t92whc3e+kn$C85!PhIMJa%dH z{-iW>Z=;#9WcCz79#Vni>WKNV$ZjHbriTgs@HiU^u2j; zH3nO1Eq{)8mXg9{*QHn`*68YJB9#HKsp>KERx%STr=b}UggnJBn_Lv6RbwL{YC6;%CL zP1Dq!QG;0vz`e5;{HX7&C;zxC2&GzAV#du93ub|44p|2dT)^i2O-#S8!RS#wLa0lv z%Z|<4wO2kOh~Z1Fu(RYGzE;7`59SfF#VjTjTZx+E+{tf2e^u9Hu4PH|*!x>tTujk* zN7?vQCjK=56IC%V{9YzmQ*iP|x(bplvlMb*_+Dv>$QA}r&ItF1#q&^mt5tmiSqZ>D_?>sa48#J z$Xg_?Y-NnGuG{Sr{_yDXn)UcgAF>r=KAvz~b$u=day>kQzmP)TIv&zw=6X@S`6c|t zG(0|_cvZfJmt_ITia9`Wd~kYSdQ93pGDhH(M1C?OIvX276qCef5c}5{Jr`*w0CRz? zK>1G6o<~;B`dRPu7&oX4Hz+Hd=|1DPx9@re@yp7}D8T}lJVDs}!~rjc;Va}rr?cKg z<0en*4d}INL=7p6ZFA7We9tFky?#rK#Hr~1H!AiBdU@9bb6%TybTweX^Io$dg^Cpm z*&JpG1@o1g=*$#Tb~&Tgn-H@Bgpknr?840h1&z!8b5+z@H*w7RrvZxZgU>EI*ZKom+!A^W4wmJ}W84OrbeYPnt82<*=;S;t9>1@3&zJB;M9KA9<* z)TgNGM!my~8R)xA)ZE32Yn%3Z7_)*;5b87?s(>>rMZcAxtZRT}0)KBomq@lQqIMka zd`nq2f8Rw?M)T!TK0NF5oet2-v<89$+obfu3r5&#lkK-?%6JcJN^7y#-6z(?qw=^e#IHyKW`;oIs5vgp#wFd(U4p% zVpO|T-t!fk${LxwqXslcSvZW2rN_hkVuAR~aB0asXPm@Q+qf4ZNVeI*1T}(GE zsbMSGZyN5ff6!v=T~30QWGAVkV(+&;8U00l2RHd6#zE%@vCnHh*rkB1nWEz~!;^Z6 zKW>M*WC7C&0)ifJJCrZ2Cc~H`zHA#FkVt0pBSS(b8NYzBksljj4jmEWWn=}+=w~bQ zSJ&&bq{N7k$G}3cgZ2A2Ev4|~(o{8YW=)o~KdVsVy&yW_A&aNXYM)K!+h+UWNj!V} z-URouB4E57W$gKkjsmJ}m`>6G8@>lVOuSQ$5T~*5UPmSu22a}f(nGO;bTPsG3U*X) zmds=&o8snU3E{Ct??;~aHznw>_b1vqLG{-An#g+VC3+MHi!%NYRyEaIm9}ETT(lt^ zcNVYUzXdCW$uSR%vIyo zEiV}@QB%&!He$X|j)hP)iC4u^F_@)lL_#=KLP=+K_RpA--v5ytTd9~^qosB9v_iXs)$ z0(jlNWvXr{5547-v`~Ee_#iN6hx=-$l4XmHJXLrli;J+^d-t!}Sxd~>msqF}b!*jB zQg1q)7~`30O;FmMI=-omq5E&t=g-uFtl*mBa8yP3oh=-QbO`Rk1kz(+%^s0#Q&>|W zP9~!~5iVb#5|%F@Il+l;&Y<@ct|7-0=uYjW@+IR|!uwY}3|8V0wmA&(B9cDnQoGt{ zTEvsihQov$Dpj@wm6r#NdM-Rq?cx8r&QL*~>Coy;ZVvx)*G@_wH~>;zO>qy(&-$?d z@vFe9oY4uDe1!H8PU7cx;V;VzDNhn@X5V9!T!ptyP&}ZQ-aAF+vqYZ3Z59M*H(qr4%R6yHNz`gC?&M`Nk^DqHo4qnO$)uSBuDqvc`vjUE9 zIK+pqwzAbx_VI~~D-i#{{PQh-YkoPSmm5@`I5bDk|D_U}YV7W!vsN(S5=lAz4RX76 znn6}@^a1J6tRP2E9wKH!mOlgg#t+Dwpc``lMRVDh9udkLN-0{;Lts0~C?fRoWp+cg zNUtC?M5~~f`&RH_Y!4#ivQ#FLhzk|y>z5qm zJz48tCIl-0v54G-DQB2Q4R2wiWaB8^JK0Y3WM}W5nP23R4tWjG0Fg8Rf*SceL}r(H zzd_xfF{&ear@#;^Y+ zK!*APH=Yh4ndjHKNo$hX^7-wt9r_+LNwHv06VXY7X5{H$dz-TSt`8Q{%4+po8bsV1N({w zOdJ5l_>^;x%RlNt{+C?n3GD2$UMX>CD>D?7qI}l9a?(|9Z_2+ktb)>Yz6ahc`w3UH317 zM2jzzI|^}=tuSYZwMf`vG-~5MmMcPIFw$}oYJ}A*1M)fs)ixX^E^-_*{XKdnQfddJ1s8V4!=J09)S@1 zFqdN3gYeZQ7Hp@6N<30&JQ7CDpIskFRSD3JFQT#E8uHA~tq*V*G$OTbHz?RF%A{D0 zr-1dQ1@M`aO0A*Jw{>sRgR1=G`w9ns^w{*S4xxtoM+F(GecM6n=HssHpmW}xN^_s} zv#x7o-_CSP41(!&pQtFgBMb*I)#B3G`#~}8(;{#-{)__293Y3cO|`&f_dtzc?TNCc zbmdPFDGSne;#rBC>S`OR5x(}hc8!uYHQE?W_bTFsxCy;1X4Ha=31XVSm z)-DeKwd!{SO8F|O<{!L;k(_FtGoRdf@Mp8Lum1cCDgj)2N=&5S3o-3wS}z~Zxf}{2+j)?a>$P*F)FwJ znn^gQ6Ig++!axbl!%9Vyo4p5BtTUWY;&-(3%Dt(c7(eNX0V%_YnWr^IzrQW5;}DI* z*t(nb&6gM})LSQyc}WbJ3x->Fe4`NZdKIBC5iQ$7vD1?}iu>q#`7U~qA>wg-$Sv^; zl>C`M)$^`@h45J|JBEgR4SXbl-4$IuEBH7Hb4Ex$7_eU-;mPqz_jl2N=QQNuc-a)(Y-5AxU0IVV`*9%iXTbk%NeRe`m%Jk=Q@UM>@Ifx$JlDj6ah zvLi#*JCV-fkFx?}NQj%*3?dsBAmmdvq!uUFlaJyH;1-7{lsF5xkhOTiVzmHqz)F>H+Rbrhs0qAWA{}0} zl8^IyvU1gTkI5`AJ!yVzuKFatEfJI+nK20;%fUaqcGOr(x%Ot$NTjGX_5Sy4sV7Yl z^MeyTJwURLFW6ljSQl|~YL=@`t-rH)IFWy?c7iEGSFEMDlh>J&&w}?ki3RNuVhWj) zS;+wEILsoTPA}@T7_h1-!8E=?6?#faSwh0A#3*4p!6M8a_G)tTi}0FJ9r29%8Q9>| zT1XnTqmlS}EzhbpA6#sp2Xw{=lrz!-_uc9PcnapNR}|AVl&C&Ax$hl=G$x*A^v&#u zDVb36#I22q`Be*-gk6S548kZKZNFO7YHE#0rd3VH&9b z$~uF8SH%ad6i~jH54}cc1^jZF{;GHJSOaBFrr?F%;@IquVaY`U`du}5`soUkB3}Hb z!ensVdF_qiOZeR1ySAnrd#REm&SXiDZLJ zZHdL6C8{D@V>n#-Z??A7q~Nu1QzKWVmZbqu5-V8Xcns$d%Ezu~jE4xDa56esL*4S9;#3)U!bSDnz-STd7ak~1I{o4WAP5eVlQ^fv;OoCCk(UlF*r;4k7S_$tPEL;!yM znH`x^Gu|qAjKWp`&3q(xS8pw$0+{rAQsn4Y?U9|*W&CrZwcs7F7EwhmM7y8X2~X$95ofbN+bgmBlyhr8ZRGa6~Uc`lW+J+%2gUh4SzD!|qVDmw~wF_W+B;NOzK)-2xu&!zf@ zce49ks4 z;5rXJR5Zvs82Ue7H!kII7U~Q)z9KG&vTLvmin>>DuiTJ-H1DiXT1nf+W}eb^I^AV+Ndfx zWVz$9;U84u{`(j^N+iA-_&1o9YB`=AStM-{*td9Imv*A5d!l|&Dm$(J@iyk`Gdl(O z>}CCK#?5tzX8Pa9t)feU<>DLy-G(fu&FGO)RO?(!OYEMDn~rFkf4HG+tO1eS5i7_$ z4e+Musq7cmryp#vtsBQ=cd3ObX1Jc!aTtdc_h#8tT92?`SF^>7`4R zcJOg5w=%$I#W`7+6cHsb1@UHIC>mbCp=QTkRBr@0xi> zq)Oq=f@`Wq6QJxZ|F^r9Zf!};`~CnM|3B=#@twf_UNnBmr+BqbaLvx-sv_X}5Saf@ z#j@LL29e9^JQubV^!jC;iaU65JX6L~7|j13AB@~&1QdFHXy!Z{T8KXxy2{6s0e+0m zpD$Ja_a>#6XIf08nS9SxUTq|$RzZKl*Sy5*blw%`EzT8TGgX2F8?ePU3iH2pj@YLZ zqPw>2B0t2+g;Xh3L4^NrYafi@+eAMfBpX%*FWFA;d||ur?+ZqWGK`n_C|K? z5z2NZ9B26sG-Qod35zJB*Z(eDfBV8wtF`V>UVhZ!xXqOMFNh?$E$b<>98%Vn&di}@ zvAXlbY&+Qk9HtQ^U7@h>Lyd&vYrK^vrYlt_!2>{D#{4Q%&i(|1H{{2zdM!AD*S-oS z@UjVtp0rC(r*(?Ak+sUt9@A0e?F6XCxQFiG9y|0)tHtX?=Y$>bQ*#f2UTKPFl@k=1qqeXBFP^q5T1r_p|${a*7AcX_&o z|Lyal=*^x_Ma4gpHjnea;^b(FUj z^p*J7RfGzAfxvrEttP=q_o|O6dST+1&HlmtceKuAEm{?5j2;#>B;BS0hv7NUFY zcu@YlI1gW-^Rs@@rPsN%&MvtUZn86XgJm8oTN?zSFHPoTtRX|UJ~|Vx%|g7 zRv!~K?Ac3ZgkOCfLy6JDy~W(*FU>XZc`H>Yg@+5~o3eHrjpQh2TOZovs85Wzu@qe~ zK24cPB@_M}s8MZIQD?4p(0lJW^~#L|MuX?Q4Jc>&G#S=oRdn#jCNhHEOy?B6 z@FB_-r;yKFVp+ebUX0O|*4O=>Q)YO;w05Z*aGpMqt5j@LO`oh!ZqM*IY zwMVc6^}i21>sIP>Li`W_8u;8@*j!K0!cftGk;J%`v(Y7LvH)H&fA7j?wFXykW4EjC zwXDW^xk5YDO=_~AdFf{Drxh0ZsPGC?XPlZxTj1Ahv(&sbPlI_!q|J+a?NHoK7g?6d==S%17wzW{&r9jeLj9GcLRO zzUd5X7oLB<=>Xg#u)~_>moI808Wx}(+!Ddnvn#TG*@`80*o+Bs^$#hTo3uK;y#7RZ zBt<=csy9iSpEMT>vU7W}u)0f?u9Ib6eb^!+1*2X_%+WI8)AW2hepe%%2gf)|t8Ycz zz=G{}skLH8))N$Ry=!PZ|s*tKRWLoX@dM);i=d&ITck$Cu!}Md1 z)^=@S*84DhU-TZ0(`RTp8k%mtvRdmJanA!U6|CL0bFi-S{S1DD0nuMKjSu76@ z`FtRC8t$p=R`rC^-_?uM7b~XAH{yYC^M^Ximm}(_9chS^f#l+n%pIms;GZ!6q>15V z8c@{RW%)tV>3u~`PUzQ^tV;qmT-(wJ+;YhV;b4i90%9?xZ=r2L-v!rD_LLjuN_s4) z?e1RSEClpL$ISE@W*X^m!P$?S~u*cogdkfd#1=rJJl(JBB6}z>C$qOKPX5|(y z#U`?Mvu! zv#e{r{77u-4OOl9 z&QOTh>$bfQ=Yl z@Z>FZq5Mc^TVh}Xg6e^~?oA1_lc&1cpVt?THH5}puzC5U#fgw~Pa%-?P=8A&h3?L+ z?B1v8=+2=bxdP5pwLhSSV~HM9hrHL~W}XJ1FI)EyCAP(OA$UN5aOXqgR(*vD8`yHL z2e%DTNiD%<3=GvbeGD$LfMzvz>-V_G?D9nhW6Yb8#D;Wc z^dHCP+4n<@_3}u~WyX4fH@2pYv_b2qQB6AGd*^H%p2Q;7ovg8^h!Qr&b_PMd`!?}5 z?n314rAnREa%G}*1ch;3@bgU%R&>4!#0MtP@{p2!Wh-{!dykv|04wP&5c9k;8KYaO za~4>Lnq7nP85v8wXXjd(BaaH`s&$esBrB4;BX(@sX z&M^fXh0U%5X1iEs3Zq30i_AQbBp|0wkFB3`Qjh)ETlqPe)Z3(~*5{{_rssM0UELpT zEQA|rEuFcR4v5c~VlGRqO*W^iFw9r?s9!gj-JAp7(ttAOYxD2?qF}x{W*uNY|%J1u z2ju2H;ui(R8&jixbw3zmg`K9?Z^Gte)_U7mp7m`~4~wyhIl7t9OZr^TI?JRG4wZ1< zYsDt^k}@wDvM?fp?biE>bZm4^Xf$Y!XR1Hv0u~k>TC-+`?!Tq)B7XVpf(`e+m16QA zPQV?ikZ@5I5A~C{o>Mk$e`?yiYUBmfI#^O)fnVn~%MXb`xsuetj^KzzD=Vy13-^#y zH#5E{D&@{o6Gb9y*;?eK7Vk#9(noVw)lBtYG&U)j`$#j*W$AzY%%?5bUce+6VwbL6 zh}`Xi-Rv*`c6_38ky)u=EA?@b3dIV5$U&fSyAyb^pGk$E*7^`wy2)8PM6KWYhH{Bp zs>+GedV{o=GR;SOmj_n{7d`_PHy7*0?rFE9X;Z%XIxxJYz`1cGUPR8(U_9X#{XSck z%2>)33t^0fWWeHWovp{iU6e?z+kT~nC%#c2&gO>{YN(*@shVx0imrX>>Zf`t?Q-C& zOa4(=D>V~rD$OKk)pFu|P{d#SJ(e#an`2XdmiMl^5*tTuEgCueq0iteR5}4n8Z_P9 zV^SlRil}h@GL6orvg*4nUGPXxBk2|4cVjwOA;X~8^(&i#?*Wkq;V%KY>kL&1AP z6si0N$u-6XkJG>4>s%3dCKRww%vZOW?i4(osCkQ-Hy~}*+!L>YC{*T6|0CSIC-epq zah2ZLRd>N5XREon&8qcJ`TS1DzjdCL-~T#(-<~@DAv4dUae(h7$8}|(VOK(0Zy)61kjdeEkM&D3OH}J%;=v`{pO+rgU zH@hXB=~;p>ao-b|Lhn<0RGX;wS44TT+`HppyB~FccvR;Tr+qvjSw8;R)IkxRj2TGr z;M*j*(+pZ2B}+&H=jPHNB>?3`d6MZc%|xG3g@Jh&i`8wsPoFjD@C=)y#!FoU%ef(d zdG0usBwgBV2b}Yd+?^BF-c4&kIwi>Gd5LT~L^mw7Bq-GgUWu4@nR@L}tqpqeb?1sL@ zDf52k=Yn$oUyM`L_i?>S)UOMpE7h+GTtII+oYeo+$VqrVLTX2^#--CDmLKQFFX*?L zI#jid9;texA4kdSa|ZL49%ufV-mLO($k{*xB86#w$mg!Z@jZ1#U%KD^nI96syJ1#C zK75@tF0{xUwKJSyU{^6&tK!_dMocBQ!XsdZAH{_Y$;7S7j*Xi96#VWCdu1M z*>5lgp)<6hYo=Yqi3<+G%PdlP&yt3anzGAK?{&s1In&8KXgcge+P%2$@t6UXeeo;w zPnlpMz)s>4AAEWSZYY1q2YyW}*z1n}y+*qJKKHtZQAu6z?#P6BCY}Qo>3u1m>UEEr zxg|g)kk_VttJ{{ie1Hr%SJnI|KGHBk;i83m8qZGM_Omv?Xd;5|=r2dLcPkrKHBxZy z%Q_hke3e^LOx$CDd~v^SachMe7YYS_f>c&vyZ^0fhbWAVrXm?x)o--bL^s zn6f~AWNq)_lHH>|uNR@GuJmQUjQexnTjhTRs{#5a2#2&Dux>7vn?1Yt6umpM%aAot zLVIr&9#{YQ1w&vL@YKX57amMc-Danzb;tzJiDfxW zU-YX^Lk)Zk;!w&ml2y_IV>k!XslI0|1ciSG4^aA0c}el!EpL$8W%wS^K5mUAT0 z&;nn5E~~p{imF_=Ex_*HD1~Nw{gdN+f8D2Axwff8(!%bk?Juq{-^Ow?6AiI9ZVb~6 zqozL;H5V7sO{InS6)wF8R^+)7DOWHEUSSVsou;2$QwtJkel9srhdMq3(vbs2Ll$km zH#(Gik@*%>v~bd-q7lZ_&U-!hpQz``pA0UjeR#DIamB)o1z$RIt*rAUtCp&a`h0ZD z;PbO;i5?zbn(9XSX0YoivMOmg?dUF#kS?$Gkn{P>;Xe&pVgNThH)8bIW|aJom5BC3 z(%NnJ>T_gy9+wM55A+cVO2i9itXGqeJm^@AJaQ4%Kl#DWBr@o2=FY;C#~ey=QUEhZ zyQppxT!D7JxJ%h}v{M{xkzO-pb|E6{UCHrfy9 zmxA2!1-273{rsAF<4o{TgSGSlVnnPK64~rvub(;U5K;=kW_ZmgMtE!kskEO=ZIzTY6c%#~7!kImC&Oo;w;K#4nd=m_SN!=XVWvExK0B zPMjgK2g0g{O{gE@3R}AO?X5A)lzDCp)y}H;JIDMOw~rhTi}j}V0F&$#q9rP6DJu`q zjz#(LWRJ!6PKmIsqf?@aDKezyYD9TQo-7Z@%$bI64BYa?o5ilGGV_RRLSISUpIwf$ zl+P8x6C-8(kcwRE`cLY_SYuXhymk{_>2OT@zSKVTzrzljubMTtw;yTfCK=mmNt_~5 zw0`K#e$^ZohI^E3*oAP*%A<|l2vVqNK*gRE+8lT0{>;rEyOLG6RX3*33_XHH`jH%m z<7a9HtOGM&(1Hf5>Z%EiLCJxOG!);H`9$ze;6H7IYTF{btG;d=`KaV z7|5}v@%}#>6!Tq?AhJM`m;*v>H$)L7$wl3ya_^arBMP|gARVYV)uati=Y-7}*+y{B zpe>Oz=gGA1xCikvcfqOxG=De~e9%Ht)mT1IcDJ)EaAx@4C1(9>o;i0kR`#tU)Lr2hST*Z;Ex3?&Ag+aFgl}>q=HZ(t#Raj*~jn|i6 z84d8$1VbtfmZK&at0TLZu1v<{8B;R+^akxDbng^Y1ia7+^pB+iJD-RYuCy*%y8@l^U1Xwbx!J#UYn<#18VNK%olF)uz`|Spb;kLei$PzoUJ?k9=&*k!5975=&_-e=y}n2zr@pN=>Klh*Dnk==2O=*ha0*?X5@;ErDC|8A`H!V z_fqDZ%jYN6y|334jA$;LJ4DB7=2gU~-LYiJyX{TmWkEra$=l$UF@o^)F*`*r=4;<# zaLDRe?sVtXtZ|(IBj287yepvLGvB>wn9WrDJ#<&TsQ;HA@WR??hcK27iL5e4LKnS(wzD0`o@lj;=s1F zT}DP*Wv<2H>z0-9PI7*w6Y@jaC#b4}fY=B#r! zgcc>hHbWoJ<72=Zqb?drxdLh* z?MQAd(on-?{8YmLVm=8m|CO41nk%wu9N{iY6_fk+7WkGJTx9<8l_ZzplU(mK-=eEP z-#xcf5@@fg+5!*LGP21RWY)JH<)K)hXcU@0+PMq7$Q2j9Y%`S!@cC5B-hHJ!D^(+l z)&9LhJs+kUnRBWHre^;=txh(Q*dY2?|9VqzpL6AJYT1nGoyhGSiINjMrQaZ zbAIz+8)6*ioSeG(+VJhM^xm#0S((bD4}Cl8!eeNvx$DX!s~Yb)&hKi?=2?0HEsbE- zP}aZ>5Z`?7zVfxRSYx$w`GcKGucH7~R*|qkWp6rHd{E7)|9m`e%)yAES#-%U>I~uJ z@QJjd6H!z4aO;q@o;laF#@^SIQ;pq!_H0dL$fpsI_3ThT9q;SNOD)|{<%e2HEM!t+ zePOYG^pQ9M;L{LPk)Z|eI*~W)zoUiV6teC&_{0sS$#woT`qZ7+P<8Xh*oTkZ3SY(u zP=_=RmXz*yA*O7@**T4-yW?wZrSy!^oyVoM&)048htE&xne5b1SZFJ)eM9Dot*`qv z?ER)zvw?=7hXhjF{SI)a*WFab+Nr3cwSjjoC^wDP0KY2kSBeIw^&#JFs2{B=)kv`o zzhd>vxonLPiz1IP?NY-P#r~vkw|&>g_IK|5P=yTTn#JEg--*PWq4!x-?WCy0&X{f7 zq%^KWXx#Yx5@Mm)T~z3Prioax^p|P@jrfj}7`qun6A1Y7sZt*+)TJ0?N z?EWxK=VKNf?>48RO8Klme{;w6?P$Knd~mm7s*1mkAV8b;Yd-R36-(wY>yWjTP|__H zUiz<>`l;M*5=GMRd-wL&*A8h|Uy_E~Fg!(3?N#VPCaX%CTbo&MHy1y(aDFYzWU-w2 zv`m^wTAFvtJU@sRe|y5pVUjdMeNhu`+6=jIVa#-jAH);vSGt(vs1h3vnmZRdeY9hb zM4@hUl{%pCLW+t=JxXtJL&>Xs_LKh1Z9b;Ox2x{jd7U^ljsgG6+T6*-8%`YRm`qxY zs{(In?Olsy0&wyMIBmkTK#^Vz5q{5aMOl;_B?g(g1-B0ARGq;5Zay{%YC&-I1o%9vrA-H9*LDs&WF3&%9FqTsCf{|SFDjN=@te2y@e5z<{50%oC{Nlf4 zFU+ZoDrgVA#(ZR)t_9x`Tmbqr#S}S}{<{VCqJI>!7BI@Solq#Xt=9lcbTi3H;)IcI zqa>#2H{cA<1Oc)75*{ENo63qF8>#nw{r`ihux*~cVJ&Tt1`W75&OTIKN` zgOX=V-sO&tYltU3V#T&p{5za9Rzr@IYE`Z7l4awtjrsaLR4mP(T}E-h&zUa6(FKM% zJLP?w_EkIob5QLc(=*!sp}OUc>%0xgMfWC3nEiI42;M^3z8!3Tu|=r#SAp`pI8v_w z-T_+QDV~sz*6MNPAcr+V5MK!mi z8&YEv-R-h?V@l-V$;^LYQvd#N;niDq$uEeSvSP_37B+S*ZS3T*lUB$xnI};!{6Vjx zA252GP?dR=6?H4iYGbU9UO=By!+%}~L?(8huCMm!>xm=Kv1O}|rl>0o%}mEC0BR+n zN|9+PmzgK{+qsX%|3zwmxHc#SyVybqUw@v?RA~1-O?S)b`SWbb!2Vomv9g{*G%{!X z+rafij~eE4g&9j6>m4o+`%|t|zu8pMcQW&f44N+^MfB=X5}C_}s6v?{%h+S|45c|> zIKKp~Sxa_@+s-2&@o5evbCF*I@xjey3Klv^1{fKoKY^x7-KjmJKl1>K=H){cpkM%! zKW3&cS?tBR;U3OB=7l>GYsHQAFPw1q=(`S}Su8G*B6+)P_35&#c77)mJOA?Gg2-57 zF+$R&&^CISX1|%n*cO7-mMw}`@?=zui`k#;^r}|F|4t05F2i95f$c(AN!h))!JrYt zmFWU_{LJo2v;*zv%B<0(SEg2oPCb+0M8J zt--D*+gU$5(b5;597IXb#XkLF@8|IbyQpP{p8Kj0Cou3*@OY9HG-~D#X5XgBbds{P zvS#XqJJX!`m)zJWYjYWTqS}%}wI5Wsbk3hk?-9q$s|j;xerXT`U(%D}c!2hGDl&rZwAZ)EDcF)Pq$__23&WhVLAimaAN-Sy zOn!Jrm1-{tv}!pqeKY>9B7&z7OALiGLCVATBSZ_D;p;|k&9$wzKno;&H6{y&npXCN zJ5t`#l45>tE@@x78cC&HL6nkbCj;9Lih!9~k}Tz`8lK-=7BN82SYQh8E9+f;t(dWu7kmDJ$=A0C zM>z>K7VO4_Zb=M}6pVpnm#VNPjp;(cnEm1Fu9jHDE8oM{5n;gJbg?eht^iqKr%+23kQ6d? zjPI`dU=*dA0|pyw!j(SUsq>nDBCs$8RpICpuY}|ZQl<+NnyXfxX_5EHP5J#m@j&u! zt#d&^AH~-epKPt=)b#D#`^MetwwLRRlo#Xu7ms3aXBJPuQ}6XsxgLjfF`tw*J6yN0 zPIXjGmNpD4%p6f4ABo^_U#I_I4+SYVc7HiIcKSs)+Dy&Q`>cTv@`m5jbYlM5Ys^9N zx%!pYUlbl#Ii*-%^Tm0+mu{=ocxa68vv=&b19(yiSbfWBe>9DIF@}D%?BqX}gH9SB z=tgAt6)EGJBgOX{5Gj6XR$&KDWub+r)T-MJHNMp?tBzOn%$yy8Bp!UR`8e@Xb2*24 zUJ$T8g$z!+mjJo=MiOWLlE^F1{3QGIZVb_V@UkrUj>K3)fw_O#zEucKhCL-~Hw0winy;^6|Jo?)Uox;bLHogC6&2^l9dzQ`hWS2F-RMqG7Qa>H^!* zE=G`JsK$PP>wU1S6#w+xI`c0>vo?P!PMBoaj?}GPiXm<3Jx$^b=MreE<>vo-yDfvLzAl3)Q;Sh?j$Bmz(0?21#bs?N+$cA5TRrxc%gD z)18oy@G!setKS}MB7Fw_ zw^s$DBe%e_nKkmjeB9us%31EkMef39aFVr=aQTW8UF;OF&vd2y-e9{%W}3P}#{sXZ z3dZP=r-z~;OwJ9QzOz?{ges9*Ff)I`to0#GT_d44B0NuAZ~D5wJgdKaX6g?F$-P!| zTp4aQFKfvN+nJT7V07fmL{|rZlCn?KFet>~Y+i#FA;|N=Y94lacLj)((_nPIJZ+8F zTT1L-#w{<+U0&yq#`2m%e%tP0Ou&71(D9EO@vGfV^WU%!Z{C3xcJ-Yho67&_ z*@Fg&$NY%bMiy=u6C5tTPYrHUiRDuLjQZ`c?y)z?8*ZhKo_`)0ZoY3uP|1oE)Vtfu z0ZxlY{plKV_=z)=Z8TLdhc#i1mKP3){2&Fxa(mQ}-MD!7v8q zjN@Emsi?)PF~+r=vWOmj<7L!Yod!84Xv}eZ7zXV_e$n3IdiVX_n)ueVff~hQwydd_Ao;_`X1x0#Dty&%6#~48a$_4&9=X;Kz$P>j8OU4 z@-fV-K+mwEt5|En5GUf)@r5OgVD6^C$CS~rR~VW#>$r~|ni-FAWEUI8xA9$+@XJ!!kc#v& z7`x^LtkS$@I57Q;Y?dLiTLu7UIAQc?_K?Tn!7b=0_h63ORjz}-Vu<$Y!Ng;%=|(KH zo9bnk<>Ynyv%C5xa@tNA9N3NCQu(Lh~m}=F2!X{6hyOZLe`l! z!f1-_L)fd$I-V(x;GmAgFDqudscxw;e6Ex=wQ>Kus8RWKGe7N&Zm7FRScoavI#AgZ z=;esyJc4NT*_7%Ap2O{Hk}5YS8$LatRs3aV;W|5d;1VubZrD4pB%Gy{JtUtaic{w= zc;@fW=hWN(CBRBtA39#o=&XA>^Rjzp_qD0)JZ|pHqN_r3edA-So_r#4aKALkGWbqz zf6vFhhsJw+F25)#O5->Z^bbm-Js#;D;R7qAbyGD`@JYcHnk-2~VR{8cOLD$m9 zU%STauPu32Mq7G|f>jmPb4sYTQh}^4Cnfxpwnu?kFv`y@#!Mb@OY@SNb!W|peaK{X1kuBc)WB%AL#PXlW(RIw)1i|Tp2Jdps z>jimbqktS~`egy*mWNIixK$+-O#f0m$m@+lLF^!~Ex%08vtNaXKnuH|v17au+XHWv zQ2~W*45RZQF`w=FU1O8c>E(ofTU!-QupI(o!&o-b5X90<_JOzbg8epImj>Uyx{*`X z9hu1=g~v;X@yjRxwDWC*-vB^cl-};I;@#56LO%gI~Y5G=FZX zb2p~k|6II0(m;bj`TXyBj%<*%9TSjt+Mn1KCE#1suZ6`7kP?#_EM|JB0 z`m+ckywg5yFev&VI<@LSc`7H>-BI+F#dOTRf29F;IuOuHF6w9<{Io4e@Q&8mmKqe{ zq=BlW!^C#yWQv^V2{GH`1fb6}TL~UY!iBuBH{lL;D0qiMJ>br8YB0{(uMo-e?&~;) zUm`|7yJgHQ&5$Tm`p}9`CRT9OCZ2|<`Sw@6G2Xa7+!Igd1dfx^iM78>JKc_f%CW87 zD71oizS$nw>#{zdLR(Y`C@pu9S&hph=l!OuigxG^X9Vj0>z^=X!yz>%tkp3Qk5TYW7#DKx!bwh0v`=LP>!!@q;WibPx;;rROg%LekCQ$e{+#b%FIKgBaHf<5jG3BD@0b8G%z`R_uQ z0Z(t3Pli+M5+FV|AuaHa=MM~FQr_x-C0e6m^!fhb`P0+D#Nvc8P>8kzX{umyem3sw z?DIlMz{^`qect-3GBUFS|52+`tN$uR$3>#rw)D?2rL?Q#ET})Fz#L72s3BQfZyt%G zCyo^DX3}>>hRIzJ?*g2CKV)4~;B*fikT?+jFq>KJ4a-6?WCs%408gG-z_#ekBaEgglnD%I$ zZ~oQ_@b-QnIPS^Mp8HNPBDMO_^Ho8-pH0`SN!e{W8!=1Y{N@z>2Zu&b4duoUWQ!$pB zwVlJVsKVY{L*+f+Tuq*8G_}W2amPqob@;3&3?oBA&T<+9YLDREdmFU^EzHt{bxRA; zv;f#Bj~>-&@rd`viFTV};d0aw>%(iy^mTH*a?Rf-bSKLm&^P# z)5fu570l^LPuJ+O5KNk(X?-w)%C~#KH%UQ{7r3??bdlADRM%ss(+rOeWxFbjbN+NB zoqc4UsDcxyImfqkJH!Fl7t0$U5oP3t3lD&MBn0xdUSO97V{)!JQgk&fdh5E!x9Z~R zEuwA-dft0Mq8=K?bH`5duh}evilCMSjh`D>Ax!U5<57eC|CW!_un9&wFV|W$nLnyR z?&Wg#NjT(Po4#U`Xi043%w*$CsT^xb$c9nMyR5E+)6)XXE7bs3H;7PMEHuai)x!agF2==2s>W1 z)2~lyXPH-g1twyAXPFxZ!Sga*L&V~fwk0BMCNTJzP~MF$kuGzcRsx?R8@Cxn0uZ&e zIJIb$6RCvPHXcYUp6%;`J#}lb?&)bKpWO$u zIh=dpeZs`%P&a?lQ|gv+sbu zHK=88R_?Jbtb2^ISKdv%U+dOT7ME6^f8IU9MRk(cpqGiYhB&{g+x+q+I~lim9~T=< z#JtjwT6G)!bH4hLL#KX<192}Zo{>KTNg>J>zz?7bbvBKxhrT@?&TtfV?N#b(yN>8X z-`Y00ArweMG~16bar;m=`1cqV`;~gNooQ#(_a5o<)R2ioLRq}Vej|pK{-#fi^K-$f zW6OQxf+K3kn~)fk^PWZfUrpB!`B3KZ>Ff7yNMvhl}$g0$) zTrm&xH>(gJw5s|6I!iA_DZ^ss(2LRh6(i;%dnpOrl0F43ceRyp{*9OA(L1Rd6C; z*?a5{+pr$@?j%7%;?NwF@_V(yiYaJGDLu&GNx-J>U=^Zmsvdungt5AxNSFQ#n;-jk zZq zuBcU09DILioqXx}ihazPm|tJUm7pKEwZ|gNe9XTqh#?Ipe0;CVWman+*;sM;mdkD! zuXW934~_6tvJB0_aEs`T70;3+OXSa7weVBD(%r>*WUlXU&#WUjGI2;&?%-N9^{nE(_Ncc;G?kWxk9}A)n{RTl7%6(17RAN5;XkX41BUcAzW|9JeJ3oGm$m!A4M*($kMa0BscS-gE5Vl>i;1bOFV-ZnMDK3t6- z8~h0tHI7PWOlhh*)6Z5gyiBL+7g6f{&Eq}Ry6s2O!Z!4GkB=v#$7i1~YA$U&JL{)f zSy;wynTt5HzpU1{rBMYU?J5)y3X0IRJfbLC3}(5X|~7_D4}D zQP{=lx&D}ka!MX!MdtVBcED|MZW@IiIXFSn1WzXmX^1K~UQ$ZHZF$|^$d#jq9<&r( zjbHNbT|?=mzs+ z4+&knYY<3oLwQZLG-9E4-p1ss{0FYXXSKV;bL408b`eR*<_$kK`i~}*!X^It8XD4= zhg7j#(9BR!GojGv^Jn?@GPCy|_2Ad;71OIA-ZyX9EP&TbXsZxR@eGwOq7^-opM%>fuF=X4llR2)?+!NlWRFU30`b^8Of^~xk#-IMkuVB!0{Wi=igqu1g z_beqlGhLpWpIZq~w=Hy2FU%O2<@HvP*fzEg8s)I|ur0zH9xmPYnj<$=&=EIx?U}-P z`*pRU_O#y_-$%@%_GM`mGIvUrx9K^Fx^m5B${Pdl5_9&ER ztm7JciJP-Gy_U{K%(Misff3W9WwGR&)FT()$z6B$w0SpE`qyY_{-ay6COiL3{5_NW zDLt%Yn*}_LUUE$w5vw1rdjEB?7BOwxZN-`RjMk8p0DV*VrwELR7QOHn=3oAwQjLBJ6{7sYN&|sBjeZ}bZQ|QjA7)4 z`2%5WZr;+|p{LSG588DDBjt1b8ZMgKJmrC{N>z$RP%2@}MZ3b#q~2@4iUyFwck$}( za*yMaCIW0u@HDvlyegZBXpA6KcU933xWs?4Ky zPdFlZVTFnx`u)DKhwog~ooa3AZ#xl0DYN5lERnwgfDym+kcs`ccI?m`zJjOwPcjIzb#bmG*L|&8**M>=qV-Yve~)WII~p_2q~C!-?feF zu3#VQNNprcs!kR%oz~wQnL8P8(zxjwW?6+(cbbm&2EJ_f52|xtd4u|8%(*8Raop}L z#Z)@_M(9Xw^Gpt(`#kknrB|8+`UvW`%0}yjI?gyAn_sgeWCpWv2Cga%M zF^|%Xv6qkj#C}h?2^n`Q{D`HtR32=wQ4ufws^a?WX_p{{jHj9erslAnp@P|VtOWq9 zjXu<|TO(se(4#zK71Qzd%H5$GY@Frp0eDx)a*e-h{7;iP*Vi91-J{CdkSp_*W(sA& zf_h;rolMU)r>&ueeYelWie;_fJnnh_nu_41Y8#JLKRg##nm4VB?p*YUr*bl0q#Ha! zYxL#<4Wj?E$HelMabDh4=Jayov3<&#E<}yctdl-Ib?epxx7yVkLVQZ^HEKZ5FY0SY zF!5T-H;RTa`TJ`uG#f?wZFXJJy`TR0;GJ((DQx3*AO{(bkk&*~&t|b08$xjWr6B4rFVjOS7 zQ!!%~LthDX%#yjYVHCnX7(Z${(3*k4#i?x;uv4ujEqZ=|*hiyKa$Zg^g^xefcWo7zH|o(uws+1d-Ih zv99*LJ0mmX_L*s3!INU#@R`E_b;MPt^9m6&joVpuc@@VOE^jGjyq`=pp#&+H2Dde;NIo}PZa7g|H{WwL z5 zdXi?O)nTjGVrBA{*F*^D!+bM>C3JtPgpB^p zO*8t6nXRsln)YshlN!UaulgQ}E!*1z+{tYO0Zi?d`9kqH@XVjZ?IpJJs9v#_&hKDt zJ*6Q^?+|+SUx^9MPqlkuvVO=)oLT9&Iyl+n%t4M{jh5aKVu?J?y1y& zjmSkGV`dNZe;U60{~T-nPxh!e?*k4BLz3L9oV?=Zz59Y*0n_(NYDjC1@y0@fWY|%V zDLc68!Ot&~`TP1q>sEJ_gMd0@NsV6yV-NyMP+M-0LWjT2nSWL#ASiE8yH&8-<_A2Z zrcV1uk*!pu%+J$5gvIr`=Z?W+o0MuGEOtVBqNMqXi}DYe^EQ)&g_or6mr@SOHUvtS zFcFleGg<>(Lr9MA0MP-Q2bceD#1ifa4SfTrs&q$uXZM<9G^`E~mKBcH2Ju zkmYz`NU!x4zHtx$3$cAp$d6e!DCTt+kmqiC&chatDH?<(=fn;lO>%lrbyK@#?m6F? zebK6N_c(pD1s>RR?d_wEiI1*NwM5kWil`gQ_gyfaW>Lvjb=2R#(%M?%ezJbv-fzG; z@EcY;Lm$Tdn^*2$>WAZ_3cf6c|3=u8gX0vPK9#?^XWOvF?A`mrMzNVUtXp-o;0F$Q zoToCx@DhAz&1L6V4}XyltQYW6pXWDe>}dU5^a}jT(#sJH<}Xk9)vdrCr{b%aEPP+5 zZaSOyck#@LZenp=2)$i!hdv^Mo6V1;eZridAN7i1Hzg3H_op_fm>$(P>s*2XCC8n* zE+YMUKC3pQW(-x(VjVcT_y#Bs;|(zLDQI6O&3sb^#hvzt{-zPgzE;zRj<`dD)(1Hm zPPD6t{WfRcYxS$Y9lxu0nIQeADkMqZ0`&Fv)j9Bwj=qR^wL5C~!=vvBmK-G124v($)Qj_;u9{lqE~XF5x+;OGXe z&NqxzQoi{m2-3!U24?>LqAIFK81;2!^^kgqz$Hxm>Nu4d*5D1+Rpnv0{LtA%^E(ax|n!6@H}MLLO% zG-5iXB(~OQ8f>H+fnpxrjHyjyIDPX9YIYrKqAyhDW5boPNJUh9aVFLzNY}a%T1inO zCBb!3?VcWJz=}Ue=+a0HE{ZA?EEW`G+2*^$$<+zvR{2u!D1D3-AYK;Rd%VIMC(Re> zvnQGx;yeg(NWnTNz3}28P7N8waH`+@b+l{!)$_=RLL_9$!O|iB*<<62Q_-C#15@CA zZBrkOYbb$q%7zb9ZO0aHC~1yIXdT$O^-7Q8H04mPvtKC{L+(aFV{2>^HMO!Vo+~PB zJhJOGt>c!LmE-UTVqvFzfdY*)?Pd;mueDw)LCKw{k(%rrNz2<`1|!{oDS7?sG8X6A zI15SkbrnX>8D{O@kx&C=qar>uomJEgScgtHOSC?AqB&B$8l@o{Of6Ue=Nc&hNyZ`_ zjE3&+LAOaa>iHL#Q%;mLengYfq4rUZj6qA-`uj0ZQN9+ye|WeZ?G{Dkzxd`6tZiLh z9=Y*34U_pIJ(7-$6vzd}JVf3grKq$|&uv9LJZ#FZhHyzFV&P@;iuB14b(x+!i(Xd2(>;^-P{M+=GPW?zNs% zM}o5EnpB$<_qVrgK}*N-BaY?B$HHd@tsErvN~QlYuIFo-Za_#?VHNgieS3DfsVq%| z_1AoTHT}rGPcF#uBnG4k9bS-R%lv1f(#~pptwi)Q^Jo}Tc4zubvY)iNcH?HLHYGMrD7q_8@TVS5}{) zjzh16o;QnkT&1GPZz;5yBC|z%S92MOlB&FOCc@(-sQ9L~9C~6N2bCjCNk!QOTZHwv zTkS{=8m%jilNvKsjOul6*^FW&mG6VC|DDHE(KoXxhuFv3IL2~w`D`7<&LuroYq^kD zgGWpU>JeD{n+ZF<`{d|-I)q(#rRs_1TNpWZmVE1}Y9G|ro}Yg1v#g)v^)faXWVOYU)^w*fw} zxn`ky*o{$PY7eV!+POSG;<8}83)_dyow9N{z61A#x0N+)9VS(Vb7)~;p`aOww;&)? zuH1nF3aYjj!T|wrZ(lV466-p=%7x7yD%g69vsnSQYp05VI1XR8n(>FvI>8){2#ceXh ziDsSbC1Ue3%EJ*h9t4I*1HR(e+n!IaGVOst&fowWVc6(|(YrXFs2Nlrj&dLo!rj2T zwe$sTY(IO1h7|!VUMY7GMy^rdx<&2zP!+zu+#>~1qj3%!fv7JUWnY-LhPna763*W*ATzv+vOFm|+Yq&>Tv2L3!_>A+&*vp#jW#Q|#?5!^% z+&-&82n^?U)3h9wyXSNTwQ3$-w}&kr2~v-Z9{LI#=bZ_1kTsi;NEkmR8&@~xS3HXM z$pl){>|^{b>|~>{$%hw$`20OZzNj55s_d*Tp9+oIp`)r>`ufz`DP4fjW9@Q8Z<&5`*Q`nc@7{5^}=qrJSNvd7X-(05jd1IK?CFC8d7W2n|Ky#rGVGnsG9r#vY;ziOEgi;bU6ba?#~> z9tSPg`vJzvr0*BHZul>Pb*zRm@6|XNK1?uYovGktRB2Bw1Ba#eJilMLZ7kshpsDTw zbr6_Wk9#41HsbM690V%O{8V+cHRYZ8^qn9%8_f3=OX>DdK1&n&fnA36D&WTO)AnaO za(y$o-w^R`$n)~AVbWi6GncY!7ip`Dx7P=6-^2~=pR{k?>2omq33Ursl>*OQesXk7 zy5}S>T}mACbtj-e^C_i0Qv zHdO01>EiU^71t+P)L|ZtTP2w|M+0DhL`XseKp~@k&E3v%j$AF%lAw5-Mhi5>FHewG zdk;SB9>3v2b9~s4Mt)r+G|Eq}qg88ss%j|6LUxjgq$5lQB-4d2Y7&J*u29x-cSn z;tYCv_&kF3T(Ecz;WR$?x=Thgl%o!HqK~;w&!9DI(z2#(VR*sCh6fKy3KKn!V z&p2Qh$ok7r5VoS>w{;#`8DLV*o~)Zan67^0N+pygB-AFMwgG^AUn3^SjgD#@)D*fj zO`l!F7|?Iqz)6zk7m>UMfW9fG8N+f7f-C8)2#p(0`fCFAnoQs3&JS@}Cova;Kw-g9 z3Tj(c2Gl1Pjm>P5=~ZmoQLD+M7k}8q0~?#x^CPAQhiMUsJk#{V5;yHm_uFaDf%%Ny zT#us&38#;6ZY0cD?_|`}eqnxolST%J5^Rd;jyMQKF51LWfsQ^%b~!0Nr^j8h9nJiN zAD0VEfM-4NsJOneUEY+jSwZz*8ILoNbkKucqH&mM+T7!5XeZU-Ew%gtO1qhQo6vt& zYm2t3Fv2-rZ@lm2tRg*jrI#C+Jx-LFW^Yl42BxD-&s8ftbgvK`78ASJeY#(>51mFZ z;0K#1Pp$lU75B$+W2!ytWy9C*_aW5%FA-E64CD2-ScDPkO|%@*H=}+I^d(70GgR{n z(4BNNFm;ro^-62l^m59mn692rjVmBdp>c6p@#8B~1|btCqYULzQx#7h_sH6s5M6gP zUIT_dFJi7+mPPp|z-+>TG)s`bgwLHghO*n7Uv3gUZM#eIXiO!C26o!!i&z}GWFOz2c z8eIqa_xS2W>VaTx-!YW_>tE=O)o|>9ybMcECI<6Xlj%V|I z>G@eVGK?kp)mHfq@YO*?qp!%yznB!`DoH*H|8P#SwR7FBB|o=swV}TW|5c^Pg+`+rIwAl}VAS_D~ZTAWvVSGVrx8wE>wDGT2)EQFS zna(-GvjFP?(iyfd(VqpT`3<<|jldDM>ORSm#3K{-ZcE z%_igr=M$z!SR<-Ai0e)#RY6!`g0PTot(3*Y20#}?fC(lB z_|Uf!WOr`RNaF`ERp#sOAtQ^kcl)d_0nabrwtqd9GH!4)sm{J~`~929OdX}h*$n+f z;MC%gX$BCLodSrr!Q78Kq+SF*HZhn}qTqxCMe&ah#E}P!e7AlEt=Xf^88VAL!$uj37Wd5a64xSaGF!?MD#;fz%&g0-=caZvLyb%JOGDT!A zt$W(9HvqIG5oSf$9$o)%0`x&tLBDAG7(8T(s{%_;Y``KKi{*2Tv3uloz6Ng5A0?~W zrgWCpfzACo{QpI1{J(ir8|hIJx&X@KBVzX{>g0!$tr8$Atjem|%FZw#6Wl!`Ch%eC z=GC@-ZRsedK)Cjyj;1!tSPNtbW+1*Kv(TTeRB!elE9O{9sr?o(0ksm>&d?eHj^xHq zb=yJ!1#iB(p|7%>3L_wO4xEyg!smr{%MO*<bR-Isvm0WkY0Z)yX`dN$C*5lq0?!|a}?Z!_plS==mI z>oZxbmMknwt1S(}o<4$6>i%*MVfJ35j;#*2qZq4>WV0PY_;xIwo~DU`N5q(K0>tv| zq3sqSV21Ze?%Gc$u#rQBv^e@FjHx>=WHKI}QMMOi8d|ygx%kQ(iOGmXng_vtuhh#c z0N&s_XAKKSoymrPnCGqbAw>g&zr7Ul@=~Aeno=BSGp2;kMFwE>-c1H!0K+h^&;Dg@ z`6@V(MX$%0HQiLW*d?gie9_GX;5{Jo9yrKAKh22+t_0*All<%Il)oqQ8i5{h3JMAr zw;oRvR2{VMl=#@WW`IEjrD6oNzYcFlTlVnhETT0lDE+}+h?AyLaKFdR z+*%Rprh9D)Viyk-58DZFnv@b4=++2!<#4Ts$m_PCE!Z)wUssEN`E`*hpjG6vcSdvvt|xmTEm|$y;y6pHI;Hfg04h zNu_ye`K5+J?)tz59~YW`K#0kO;tpMTG2Ljo!Q&T=H*4?6eUD(9wKV>c209-7_nSKaXk%*cFq9s-TAV=W8DJ}R zNgqvG2#|L_+6e0ABBv)5#23mRz2ow3Mt=lTby$B%#`Ev%;y?3)^2W&xTD`a5NTlZ6 z=8TXV5TA^Wst|4?KFjZf*fLkuf-_ekR{iZ{c7zttTi?s$On<}*U1J=LO|L?eJ%MR+ zf>DNy{HdmIof6$`RE#6lM0=wKXbM)*?GM9Z{;qoFQt$4OZ4F6{u@*F)zP#ZM{deG! zONNKT#FgPFBE4KF^Zl6BVTtTD=I-fM#q&8bLoZbhz?4UiDB9{p9C=Wy=dWZssJmc_ zm#hoZ$Ha}{5n+N#jT;Z8ejW8gdPC2^kN7Sbsl>w*a|--!inuXvUqIbuA+b)}-;mbw zsH1AkF+;i1i^hRVzsJtpaQ*gHt$Z{5$Z!Dw5-;OI5EI!NJK#gtR(4o!ixvOw1VG~S zI4uzmNN)2sJ75Z}WmFFhB+-BdRv}E_EQ?#5`|%ODZmSCP9&7M57Zw@!;xF@|-@nOg z&67ZD`v1|R(kDG81zoURGmq>gcfcR(DE#sATd#QXRH=Bj+J$DtQY+cl0mn+*Rp+s3 z#;yT+e-uV7~~?IVyjt;r&c9^c;2>HRkAxPs1Ji*3{m(+#R})=U#zu zGd64ELP@|_QR04+BKbP9{wqzi(c8jR{RZ$1MN+RB+b|ShGxybHFs=&%m)A< zH!#ZCbzy(P1xX3`DIJ3~U!2jdF+6BwJc2RWcACSP4+dMZQ{=Qp@LJ4Qt`oV;lB$+# z{w_I&!0D9QF};LH0i@i95Rt=LZ17YwD7wwRVh#ZeklbRsbmiU$2 zod#_2yGibGcs$#RxpcFw-U=$4A~oJUs&z}Bi9Aqk+EsgN5Wl2Ox~Rzx@(dCk5}DY| zv?f^RYJK}CzP%Bu1Vni_;br&nASjpCGuxMMW6^WHV(Az<@bv4YLk$w0eHL4r{GuX{ieJfhJGZNiBcC}DuWx52+@I3g-I)MdDfDv*V~kH#GO$5oC!U&krnHi6eSVfaSBvNL2*lN=zw~;EwoXkz@VZWX+dBGN#DI~l za@G;Ez|c!Rv7JkEI8j_>ygBv$S8!+O!T9M3wRJA;d$GH(_D>8tk2Y6JkFhVE56-DA za2kJGE2j1SKSQ$mAnO}8V#s_aD+%mMG&a)HM_ASfUpXat2NUx$X`{5$S!seIq1G6dvr=g0M zg2;DYuk@LK{=gmKIxmgH$`Vjhcm3)a;h!!-oA1#--d&kF^;r7#xXiK6H$-4?B0Yah zf1p_BeO$Qwkp>a&r6Hl`%iTXix{XO}OTG>71KNyBu{lrzsSR5kz8%o&*ht|XS z)o-R{sVxs?U#zzKTSv2b3KERD&9ZrPBSxlb*71ayU4TH*rJT5EI8rDd=T`Zj_2R7u z^pe@b5lh(J;W`Z%pN51+k6oE!PhpKJaUigv<04<5t?j4LjXY&mfu1i#$P zhdYLMxv!`n*=7&-yq3OmsZmAjXpQ!N_aExGtLg6^Ka_#<4waIjWLiJF&g4D4AbA-c z}R`l&roPj!@MfCenk zp(&&78of>mnQ0Zrl|&qOD~(seT7Lf@Vtd|tA5Uri--S$9KD7EP@AJ7R*>K&nXXO>v zvJt@J+pn_T(+OQ~+au0$QOd|L5rZvON0M?VVkomrv<2&aJd^DehcLT&i&cY@p7GvS z!F*R^LkQy0Eng7IScBjzV{|U*TLO_P395X|$ z()|{P=f9TRs^(A3nj1b%^?xbqf>P9AC+Z<$c8XXe#`gwictRw_f4q}!Xv7`@>Mw(+ z5qs80K8PH*bv|xhA*W5PGG~E#)PFwzN09Q-H(5aDzOiNq#3TD}-ufa+=`dGPq#nJg zT}t&R_Jc0^7j@I9gN&@``XxQd5#-}Q8E(+y@s-4L{@EPXB~GGU9s z^Ctx5ZKiLBEi^Shdzfb##)px0QBWHOEFe~ElmEeq{?BNBC}#{2iJx1M+T7Oit&WGU zL@nz^WMbN(=~YW)?xODAov zR{UVy<+Pm#=$GEEe)XdIVJ`5aE+dqiuGX7Y3CCN41SvKR0>k|Ub?q!c9m7V>as##3 z3xWhCHqlFm0BDfMZ=_3czNafvF9N(zi&swFT>!0Lij}+v{Oa$z_7VVmByyhlW8`j# zRDdSj`I0=4H4MWvb{*XXc@@{20hm&v1_FKw_9X+01wh*dvKxvcp$0ermDGVM@=i(T zfAkBh?sEHXmZhWP!^E^y;)A`}qVz?QL8LQHfK}!?+V?}6AG|Wu-;P)0^K)RaN@!6=DiVJxCVf0R=w1VN-DVv}}E`^B+|9<|1f{{p) zFrvWom^=!iu|(F$X^s!B6cAW~1#Tzj9&4b?w`-IwH+pmU&YD4}hztHhdD)$u-%;jr z_>bNfPu_o=LHMp@xc#g2&vxQ4{)?cSo-6Z?8q^X`v)l}!QuCB@lc~)C212cur(Swe zPjV|ab7V)kMAxOGdRlOO&Pi2UHFmk7Xrbr2o@DQsc#MWrw^Q*tX5}6su}&H;_45cx0!QqzIDHBVG!E*^id6zNc4>7$aO35VC$5{C|zpkyYA zBjlTo;%_V1ej$8F7y`?iAWlXw0{eJZb9&ul|Ji#Fp`zSodgPznMn@xP;M~HFV;)U1 z(waBPy2s4$;^ECX(EMN;zBx_`W86?hU1%_`(`ddh)pp`m=4Sq?x3@HmfAf&Fe{n~} zk}RfI<6szY61!@hOn+Dv^7bCvIisL_($wMl!O5f%a(4l{@-FC9iQ7F+KB+GnwbZX- zMRoEuBXNh5aduB5fTi5`5fhsIQj_uSKhA29Sk}*?93+9y5!2OJ)7rhf}~(-8nblIg9Ru z9SyA-ca0gk4m}W4XcdGDM2%`Ks1$3ZIZ@)rNevF8o$zrF=^WrP&7GtkT^+-B{nNSa zb(EscceP9$e^6%VxBq4ySI0$a)3|Mj0s0;p0z@5X(6n&`Q*!0BsMvA9ognr59QI{P z&&34WX6W-YBJqa*zhAoFe?-g$sd;(6VY|ztTxdwym5LmY?51mM9!F!mA2vacw*=RR z7|~;0s>r8;?|7V7D7ky1Nv3(cb}hJ7@m9bF({9UOyT5bJ<@0t~D;XyZ117$KHl64% zGcYyu^tKBlutaVLQ8}mpnu{uc1%9=lwSdBsB0>)$0{uPIUR3pm!|PF$Lyu?Da=Y4|nYUPI5Qner9H| zkyF;ML(_0hes+l;DHEsB-+OnowkIstHAd!Ip&@3EivVg;WN>;a?c=FXYH+P({dNSO zfW{Vjptl+`{oF07pCZ=qU$9G~rtW2dKx5Z)66h()@B@0)!h6=*|J?0Gcv12gsi>z)MVZ*#Na2mMo`Y1-kI3pqAs+aBiPvqb85x*p=;3&2`B(BSp zrN^N#*0JnBF$s#Mu5AAXC zPULo7ryyB&*i))R?~%uEu>$VM2&R6PIdAv|^}cwsDdQ56UyEG^*s|Ovyl#+3$rVyO z3)tAt_3my|e&?z~)V|ppNXVFH>APO~6Sn*NwSQ3Ir!W%eWcVuar#9-he&S~fE~}+U zyJEWE}BK+7QcO}LKY0!*oBhUjk1OKX^64<3j)1M4eCP z0Hf{dy3EcJt6r~mrmcXkwq(IlI1n#uSwc2JVzqTl)1?GB_7z) zk>&zM!0k|{r!ed}#;K<_wkVUTZmjuM7<@d8GH` z^seKPF_}4p;>^{-$S{DcuFVWb*0b;2+-Mp+6wYM)bC6|%0P#tqV(eFOsn@IeK@qnK z#HU}!&c|$s+V_ZFPrW*VU)*JuR@Hpj#>`aCLyO0p9~A>;^)Tk2&dj3s6+sSac3+~% z#I$IYhx{+%-aMS`ZGZo6chBZ@Vt3S1?5Q;mEvg7Q><%bu9#T?N)exz9YLfOSc1!6l zqNSoOk(%eE#T8^uTI5e+?MmoNx z@bB-STM~Wa&klj)AOGht&zp1CmVPL)m2Z;tZT`I8XM=xi>#V3~S(rN~{Rg(;kN>(M z*{{pyR<;Pb9Go3{u;T_2jq_jE69cf@HVdjY>VO!^8PwwfY;s` z3;h6MVE_6mFeGXJ9US@Z8~g7F&HoZ4|1aj%I;e7OzNWuCxRFBulI3#w_e%q-E66fD z;@AO#OUb*bYu{{NpMG^6~%h7{qEH`jSR7W0F zvZgeFb+w(iz>|~CF5Jk*G&~pIZFT!sS=>S5CWx}Ec_v<*U3kTrt*!M>p!EpT6xd@7z-|!%ZNH=?uT-ajpFa7Q}D^D}|krPy9DlIsrWTW2- zHGsCtR~*ypJC#qZ^&b?kki(bS=y#XnV(pa*cdmbXnPM<<)q&(GDXj%s zEIZR3KAZHdbgunI;#|sOIyIQ;)R7?CD+u9>^tax=1t;`-sP=N>x*|@Br>3<@i-gl)>Y6+N=((d=oPk>WY!gp9 z)NZ0-56vcELbr+$p{p-(i5TAm!ITLJQ`J4%3h!gGLDnN7I-}r(SID#Q^-7J2R*Ur$ zff5)2{9{Ai7hv%o&oLYHq&M47v8^{?I>Hz5F`w6|cn8aHK+fuKQEi zb{uWlpAOT`H9L}LK}1(Zd(p$^4})Ou#@T(td7`mAr##U(T^pq<)xF<0)w)f+Ts`vj zvqD@S5?nIF|DLbvClSyTrGteh(kQ5w% z$rWTMLob-*ynJZCmRsKai)E~3aC9iS6C977)(0Bu%mN+jCKjVEbiwwO!1#@m0qhO zvq+%>6Z@^rD7brZFEN~4uzI|nF-WjJ+1{$@EY`22U-$oR;)KC2TfG(>yRlsjV>rRB zi0^Of_6Fo5%*7(!M=}T~uwNbl;ZF${NxAkDO-mqzlim^BAN!?#mQwKpBIZ{ubItk3 z4YzH?)Z4f+)sGxQZwce$R6A-g!$ujPWvRC98dq(=G1NgF8PsfmEAl{(zh(=V=`cXlP8Ic}b0&~Bx zY{?_S-TK8`051W7j26mE(<8bE#WPEXZN=HH(TNEjO<;g-J1E}rT{1L}wBm_vZ~H8c zM3-KzuWsOWYpkZRG`t)`e0DeNNYTPeU03Vgf8b=?qI=~vO_~)UNk^_ZcDIKvFaqmCtd_k z7hX}(Vc0Mo*Nw-U`d6alx0#E?AdE-Vhg~0N`z~2VWi( z-AZU$>gAXR=1vM4si+vC0#+RFx@Lt-i(V#o9@-I6{&xu6MQo#9#@mD zHf+R!`4mJi2OjFd&qV61uA!fp#hRBQ6)wh|cwmEdgX}Qa@`rV#J;i=2dBe_R!`QXB z>f&gLm>DAN3C2Wgf#lY%T3@W!KW}jqhcKWUQz;p_(i)#Fk9uDn-TI zyD>gy2Ap)O{yqA2b$Xci7TDPw1?af-;N{+E<$&!-@;C zKA%8{?vmFt+W@F<&Pp_V=6XHAiGb|OUWX@uA_sRYO&x9cDq%~Uf5WY{H>PE#0-7+O zF<7dUNK3lmxD06#2CSseid`lXxX_=};t&1+0LzxR<1)5i5ii(JeScRQy@_}~UIM}e6&Q+c?zvdyKd|4)xvso&pM7?e&|5&pO3u7sl3S+$C2@%VBhmD-Q>@6NI`^KWi;L<7 z0LftC!JLYSn;tJ(K(YY9#cxmJWKii;=HQ9!AnC;?KB+}8_*jSqTr%UA1JE`1iP!lH1uN!Zw0-%Nqi@GtX(pEI zL?2({R}jgleD0-#g;)!be+f)?1J|wfO!@d)VQ|_7t$wx8R2blDu+2fc@sSFe25hZN zqwQQ9qs&q4$YcpRcqVx#O!h7<0PBT&T6O>Ye>H;lh(R#}gW|Q3M62^9U zUpb|R-KeY1rDEd-YkJlS!Mui8$ctP$)VJyHX6w#YCaOnP7REesrecUS9w06<$m1B{ zwz|n+hx+MPV}}&1`ezRBVJ)(13JH~lj6&PI%f(IBFE{R$h6GIQ27YgBsMFc|61%ET zwzQ3Y#8DNPWui)FZDMD)eW_{Qy=NS&ybKwVWX{qZl&#=8^Nl#d0&awUfR`JTR8&7T z{hI>JRyZ@J#M2T9DdOnXe8s>jQpABO8S%|(jR!eB{D%n@3%sgcK%RL_&ReOjeV9qK zICK$t#0AwGZ#Dw+*b@+=Y5eHq{HI*0e|)VbAGSXEI*6{ANkMp3Su8i~Wv97e^#{!( z-waHo#eS+RgY07Ku`IQ4^#tfk+E4ECyA=*ubI_?|>?_&A%2yv1Dbj(-2=K|&QXf88 zw|mQM0q|~YC>kIwtt`;@hhe+-s=~lrJzI+a$d3?C)1*IPc<`Eh+Y$Mr8%IBTs+%_6jMobKIz@RUF}jwMgJaM02^te?z#EU{ z*ue%#)TrmXeUC^{oUT;M|Qj(lL(1}Wdj zmYyml89xuCz08Pj?Dm6tN`KjZO!3~Xu}sb0h=7*hK{fgCVDeVxjoV44X?Ee~YecEm z*)HTt@slrtLipL}Z+@Ey^qfzZrzKIly&KLH+` zSym^AaI`A&H|^v9a4|rT#2XPfIGdd{TH?gU>6b#{Vp3r^`6xj&%f%r}SOc6seorzM z0rJZO?Dz`(SX_#BqVKz#jR^nZyG9&^qN}t>o4ki7Zkkx4GUxhN9}+jR%v!Q@U`CyO z4c&Cz-OWrR%k}pM6oJ@fZNymz8Z-B)f_d=EuQ#iuez{Lg7=q$mw+1?A+_LY$gW|E4 z+P5wBDP;Qt7Sa_d@_xNmV_kuRzJkm4MO+FIcp(+U7We9Q0{pNON?QUeaWcuzrwnU< zhmD+A)Tgm5thU?ITaTzKq86f5o?<=thL&);RfW0B{IyWINwDE3A_uD{jg#PM0^pI0 z_`&ySIY^vZC7gQ|PqmD)rmRw$LK5jctrVhQF4J8sEJXPJbQI!oFUEbj1YtP>gOX%^ zJUP~s!F?Y8nOeyFzQEIAG*d2;*I9d?*BO33g?u`_JNDGr#$xKN`U{+$)bCpgWUh6h z!ZP^3AWvv$wAuV)?&SsysE8sO;-rvaWH1lwwDW?D8Edr1L$#{NpAB0k#9=uZz73!M z4sGlajXBnX{6={(VTH+!&H@}@Y8c>)y)LTw?u+smgkzErlTm|Wh6ztvcu@;gk+%&D zNtVia{`<72toz5;Qa^(;Zc-WyCYn~$C}!C5R!ezya}=G(8%$MVY}IVgyLWwie@ALx z4D#SF@(H?{I7ywEfTI1X!3mN+>f6?mF}}iVEboEBy1|ZhgV2;HWuJPPyOM% z3!}b->*G(kjMtX=ep*#g2@&&zzrrkTijaJtehf1o(932RutR|k zI2~TJeDLgnMh9WF^kgO$Z~9$923q;-esFW|pMVwQ5Rv;Kvs~Z<;_fd4x&~C-c%o<{ zI}$JOZ@i&p@#q-((0FvrU= z?`+KQ$>@rbiCSc!P{2cCB=b8DZjv zk$V98g93Jl0f%*%K_4JTz68mCQ7+niP8h5~)wNHaN<>BtaUms=+=dC@P9jNUHmzLd z?#-V+#{qNtIhAK_qM;ra=N@HYXvC@<>G%_q+}am*41`8Xl@N)S=U<638N^941AV+6 z!jJf{t7AYqGJLWsrV46Ble(m+u7$TLn|Y{ih!ngGk6}aCm$-@aR?4o;O2P1rj|~y= zQBz>2*Q?=#N*sF~GWE&B90U?=Wbt2xi(~76C~EA))TiBPg3*^KLbF^mQSdr! zwog!(CV@6LG0=~_MNbJUdF|pi`iv2MRlq@^0IZ$j#(|H`m%aNZ>bBjO96lVmXy~jI zq)6zq2&5@naMH#ie~cVXof$ixbCnNO>ud~%Tz`TY@z3l@dCt^MjI$@D79_cYU+%qXE7v5NofVK&dGm9_=TJzpq#I}#en#@I0m)3V^ty)%RMgH5Ud1gT-}Ik5;8k-6?25{%+G zcGl+tMw_B;yGMV`Aw$INupV1=E4@a=U+3;T=zBfb;N!Oi<7f<-;OcUi`!K{xQ3HlyWd?2H>&;?&NNP{9Sn=g2Vy~E-Ve#o;ly#$j8L6!s zkFr{xXPxj_r$Huu#LOB_L<9OZzr{^y1?rx}BA=ouw~siWtu4{-$vWdU`eS}x?s0QO zZ>ITtbXM?P^{Uy~v1J_m=@rY{xDx)fB*YpParFmKWpa6PAQA_CvQW>QV#>0CZZ(5D z(@QTW`>Ev<5N%}iq2w$nc3U)X^KvrroAYY@u?tmlGYj`KZ4pf64buW z8tGS;ZDIewIQ}5xs?Ur~ zDh{K3mSofhb4@Rdhy}DL>D`DuBw$q3G#|}H+=fynfqiiM6 zi5o#Ea}{KEPiMES>Onu|%eQ@M2<#%LXc!GW@;}$;xN){<(y&*6g9iA==U4CRp}Qi7 z$}VQKOmdyYn7uP^Pkn|~H&@4cX&&)fw<;1IH{yNVhaDGS-Id;fzxkA(R7lf``ZFID^Of72FE+FlfPOH4IpjZ*Ppahar1t{p~eo3r=AHT!*ghy4+TiMX4lbWo zvf8=RXFkfFU4csmg_^=Y!yDO+u23IZ!8rH3ooL!pIaok=KKqsWmmUo9e<_6@q8xij zCCPV?%?_pwt!&2)MWwq>0A{PhpbD|+zDmpSsue^D>E#L4-s)*B*$K{Xcu2AeI!vJO zC-LXqJMIW54R{ud_Je{cy6~^O#+1Vpu|5%ZFtu`*``B`#U&bQzqh1^J98_C#)=MB0 zsGQAS_>uH89%W%E#6Zm)+VoSo3u*|^jyqno?#n)c$vSSduCOx>8u!J*b}6IZ?tp@3 z$Ia63q7|?qcJZ{4$`_jqzx@QSohIA2+=0|IHG}5L>CF$D|G0A=30C*X7pBrTdbWZN znf+YQ_U#DapSBS2s%s5^&@GpH{Cd_xR7m56e>Y{)--2G>T!42R|8!B@%YQdy4k=^Z zcK!QhVZZ*bglQ`OMT@!M$NrNK!+dMsdTTO4PN}vp-Nx8|QLRvM-Q*c7fqahl4^{XO z*V#LVYzW*yGe3y7PQO4tfn!LMLxjz5QwCKzvT(T@x!r{B*WJbq7lrX5Ea=l0yKFIr zBKZ0(`3T6jy6P(GI_ieY58i&>e&w#o{|gP~w^<1ShE)F5IuymdnbCN>d;_fgcBqE) zvED~!>YBgVvf@xA(%Hfopy$A+b?%gZz+QG{uH^B>5JnhC#M9q((Dsfz;VaPP36>=> z3n{z-x$qIXe#Td};~J8ik8t5=q+{6=?>V)pLK=jZ&%197~P0N!y&s= z#z0H<%<@>woLslw7ENkH1bZv31bC0Clpf_^a=jBGfT&8?hL%)erQ;jqSFl8pPQ^2B z*qCqD?uoj=*xHs`qHJfteL;8p6j8Zf5C%f-iFPr0ww{1#lbz&afxaHwBY3I)1gHG6;3!uA8SDhw~`Qa z_+W%M@+mA`)f|KE?omKAE!|ll-~i)zg6pOZ68fSoXF-Yqzi{^TD>Gt(3BD--es??V z9tgyp@<0biV*)B#fnhau?%E2_2#1|^XJpJiW-4Pg0sdNrXzp2csusQtpvyohK_HemU;y6|LTu^e z>(sUt>&ghr_JgRQ@p(fnWf0z`(n1J=8oRpfm?~Yh+`JJp|8j%YKzm2-b3lc%l3g^F z+E^7y_>Et+Dj*nFaT0HWTv)bnsDxJ3%6&@RoG(TO7LL7QnAbW!yW+$+AJS#E{%3P5F=nLWx8R|&}HH|egg&%#B;_PnZa zK_>v{H=)VrrwS{_Z+`uCc4nDdKrrv^_M@(PRLU^3|)cr?KuWn~vDJaX^ zi#W69=1+2L9^T)3VNYdE;(=QRy4fSs9uw@9LE8#RhJiP#mP1SEBqPwZyo_dSXM%W1@+65m~-iKrqL(R^(bFI3Uk)uK&TInM}nekYsu1 zn;3pTHP2%Ucx<-#H~!A~xa@3`v4fy~`toN)%DjT z$!4g8g9`RgOi}!gaL3^3iMWL_*f~qN_VY3N>b9GJ;R`K>%*9P`btd>K6s+o(wp16_ zH3!-(nK9;*A<7yOK;47Uz$B!PH(d%^(A-dC(mO>W5C&r#=Q{~gH}yx8LA(reivQ6; zxf!yKJ97<)r)wT{=aC(J%VNA=0@x3=Kjerq@ELcqtg=LCT-xXFFn+i+N(Gl%aI0XZ zBDx!xj)=Yo%q^Jxvmjb8HkJi4)1MA)sF#JKI~toVDhm}nv0O?5Ky{JUt7IK>%$FX% zg`tcOjn3aub=ZH`HGa;+EQwMU5pb?Bg8FL<%5Z*2HDve^o7lE^a~poWrbDJrRk8KK zixmKliqN;R6R-_=v`IHPujmU!TPXhiFeit+7Ab5>*Ib}7En3>KJRPU8}cJtc#>}~Bv9Rqo*me!kIJY0#Ggz5>q zZK8t4*PDN0fNF>!2Q*?WHOBIoKDW=uTm?}|b`4GK;UE=a^v;vqfjv_m6ZtX9af;9N z1(y#@JOio6ypj_{wUY>{n~HrxS=VO;_Dzg8vx4Syats1JmehWffO5K#NxYT+XrGd8 zjGiUCvN~Dj%_X@dtxSNdF+X+?`;|uSQFFsur2f^C(2;3|qxO$4vh{3Zw8zA0Ah4|m z953ug@&=V`YR1awg1b=wTXA4&qNZUY>Vn%e|~);Z3{JFX2IUWu-YA1Z(bg609f zNaCE^00Ll%Vejbp@a%LC1)IT*V8#=*E^6 z(!LU(inrMt`*=jWD;#yB;TS_e)V$OU-)tmnn*Wfw9Z89dsN%Xau1cTMgk?3z8zrHB zs@r6C=^$bjF=*gGbI_!;L!*Gg^0_hVWWvrxIuFR$du-$ zl7N%J@6N$4kBbWy3-K!tRDhBL#c9f7oR)H8B%a>?9frnt!^KpiH4VqP}V*tN9Adg#%sfBCxy zOpiAf|333@uaYo0NOat2vP(?` zPG|nug5wfb1XexUN%&^@i-L?G^RTuBwSF9J)87R!yV*J)%~q{pQzbNIH`JJZ3Lp_^ zBRqJW4L9?`Mg?seGAjzkr(X7-t+|3q;f&XU-U8V&OFE6P0@585@Q~RLsi9$_lc!Gw zi5j%>ZeDav53cgvmNKPpDY7oosSjl#{EcrGzLoX}AzyHjQ?soror?@Qm{cy68pg-l zb2adg>5NUs34Q^5{VV0WKEo^+ZA#0xIM5i%kvIO6# zM^Op1%%}3BbN|AN=5q)u^Dj3M?6l0;C*vEL{`0cYAd)qsn3O;5qIOiMhfJyHeBEl^ z$2pIWZ#SMgYqEM_wJ$jNPSkqH;z^mo?mozer`s_zC)Jb%H#2IET0Zl)^UfuoKdhNc z8gxaS{g3r1Yf{-6D;yQCS}<3bu_EUiGwnb(n);f1J~xc~_a z2)xs6`ox-Z9KE!bEami2-TWTTc^82rmNxpd3pe(CF0%n*=w_V69&xfh5hMb#DwkYD zN4fJJk0P>48w(*Py_tQXh~(jq$$Nx_;VToi?Q5Gm8GJCZk#$Kr%ZjmJFLdx=xYU3V zL{|(U+wG{cdl~hz9rdCEpkKJcua)I=of-rP81$E=yc@CV!Dof(ey;1!hBnxGuwRG9ig2JQ zTh}b_BFG3ZZ`_53#(aSa>4vz$PAHaEpsA-NI7r{A{rWj-_-zEkO&tN^$dK>hXv;(x zoAMO6*Q~>H%zFc8x=J(h9P8Je++p3zKl^vun`HKKXVm(Q!q4BAIs_N(NGjj!tfW6e zl9c3zxhmKFylKOyr*siKVs9mPUv)`xbN|l-T9L&(rpRM16kTi`cGz~kKU3atCzMW| zwGRb*t&9b)Y+0I8W?w}JPnw#dC$hr(WqC&!tAHnQVvj}t<74&6w8KY9^G5A^TNcg+ z2#pX;zI6y*6{3mRCFXq|azfvr_V_UuZN206{2x7mfjNpp&>AX~FFn zun6VxECPUpT7j`k6VzLiI^T6uz9P3nIz~#sCzh?g(MBz?z}dP;o`e^*`qKg6<2-Yv zORfK;&QWxdzsWh|USf`#B21^mr8nHN{;>vl2)1E#a$#`h!axMFD);*`EB}f!8KZZ1 zfTcDU>yeq~)zDqx)nJ)N=FIAXlCIXSOr?K(WfaDK<$k{y;y&vMjw<3oPw5}}c%8_u z_LJ+3mi?5{3c`FfKuxnYGw%`CJ$_HGpQ(C^x`T1$@f0ZoNB#wa`=TNO_Yqk9sGs** z#S<3$Uyg5BI>p908k3HVDbM{VYPQ7tl@IaN4Z(1J2GsftGH*b`kW~9{B=TxSz{pC= zw4&Fs;k?!A70uzz)ftyyaophJ3+O zPTcJBjm%VUg?2mH?<(VmOt>(c))_Jn8?CwCMl;Egj5^98q*miu_f!9yz(s$}0o%36(Xe@*i%vmGo5 zRy6Mt(AxPo$Jc#329#BE#mCbv`*8&XmwKjA1*hLWbTDkZqY9bU)umGhSND-f*NN-= z4R6!N*JU5AyhvkN;7P?4qoJsnG=%L-GyX$E(vlq4(B4#1{`d+{G1ta!|RQJg|RoNurbUU=WpOmW%spiq zkmse<1+%U)4%Ns*7lnD|i7)-X5$m z_Gtpxzu4Fw&=CTxcBWn*_t9ArjvkZZ&nf_Pdj$uB<4)Lz=|` zHoG!WB#m>DV|4a_PfJa>h7&poh^&6VC1Viw6PEKa9)jIfz87Ac{87`qO_1lApOFMG z?_L}W*3yoIvg^Vl)hh$WS;lYQl-PFevkXqNoXyJo?Xl?Yvz3J&vH11ZDO3|oKHQyBH~zqp3(XNLT^6h?V~>@vnG5^rK;IAa$|d^mg7#LxFWUK=Jp`FBqC{HY<2c* z#Hd%23wkXHt?#OtYi!2KxVOK`>)YYRrdO?08~m5;`tM5NbRCld#kcl=dlAnCX?(Y;fd!GntE~}28818t*ds( zL!F5Rb1%Iffy7bnkD!jqy)pSAYUShNYF++wn$f+ErzGqK%W8f5V9jAA0}43OgSrI2 zI9xDYn|G9JczH8}8)OLrzU_~A^SZ#P+~6#w`DjiYY@$6;O15%a`|hQN_%(VFv{r;Vh50|5&$y* z5-S~q0OYA^pslJl`pOo17XyWLKuh);Ey)XhjdoJA)-gs2huqooOE;g|>fKOEnmEBJ zA{p`8f5MAw8CvFq+nW7ao8Dgj7_@~}KD?D%M3)@|`dvMc@4}KHeNJ+R_7E z%^R-5XHcw`cD-+iT3dHODMxaEu&4br)up3j8@HEIaU+^a-F&uU+eIH=Ov&HC|FbQR z>S=N38zQ1Bv6@Y!CrvIzA%e8xe+X5xo zuukt`96l`+nYm>SX z-l(2`mum6lg9CPJ_<7>c5WKyyfu{%{P~~YN^m}cS?XTZ)@W;`AeDRO9Q@EPeh@R7& z(VA^iI=i2b*3>v+^!=YZ_aBgtig^jyHkVD^6KuYF%bP*L&}QenL(CL^aBj!{XUoM4 zfMoAC6V40na$@fYn;ZZpHRITvN>Bc+hA$0lsl1ndVQ}X90maMb`#>0by}h;|1s0mlqoHR{L58v$E)&C^NG|mn!9&R#LVUn?=~FQ zeG=c&xWVmVZyo~*fcH%HK0+@n$UA8*n-%h)fGFdgiHtH-9pwSgP>I~;GxRtdY}?q;Bai>K6~% znm0E{EX)z=qWx017pRN-vmPbT)3NHZz);2zGwPn9O5Bw6U*r1gf(JtRiq=(cPk{tG zO8)ByQp0V$PE_0HoNU*OXvy2{sAoZe{?43@WAtG$_wB*{r=~x z=%7zVnXQGV{5>Y0r+qG8x1Ly250by`uU&CQdH49u)8}259$I>h7)Kc7wO%9P!goqH zhYdO`x0U>(jjL-Z$eQWZ`9riTDg87|rJBgBdAitxNQAYpo^$?!k9!&LtBkklB#QWE zOc)3`q*PFjrCQktex0%P5&rd&cvC9b>Esa6&l?!~R%ONA`DY#;%ZZ};>x0Dlyy0#|%LbvH9Akcpm$!veyhm3;t2~AZtb9W?n(oos2hdY?pF-2K%1jF<9mOzpsl>mo|s8>lBX#yYrPY)}a)3oTBuBVc~VF8)$U}imk{jPR27mSsf ztS!4363rc%<5T2QcH=D$9Yy{EhFNFWRVK z8~N|`=yIQ{RI(3opY`F>{(!DiL9KzD-*zmPfGZ#0nMYIOf1EjOdCCAWnf(*bxoBdo zP}AII%Cf&@amEECiJLPfuT5#nel7FH0{DaC5a0SN{omib;IOgl?cbMS#?iC;8e@Yb z5S$XzWP2*s${!5b!;iu4#5_+4#2vM_zd0qL_Z|6-0t~T6E5G&SGrs~iSc7N+5ec|9 z+n8wT&)xBL$9rRyCtjkT2{2}VjnDVi!1(-Ps{fTIfeV7~%o@nVt{FJJr5Sag5nfw< z8t|ukp;kSh>*GNR$c;=`0?Rb0TT&?%cW-=b9mYmIYx^Af^{v)X9vRH-Ai~#sv>Quh zNS+R*VEewP4P&m%0~8O>nz`tpgr(rQmB3x|wsA?`PcW+W+JO1DIqmnT4?u*|Nh18) z{5F*jJqwdqxz>RK=zrZu4|bcJJJBI?tl_#y#u2C&F?&!FSZ^N?#}7ZBHreoXD()G%DPvS zIi#b`)rxP4Pw|Q%H^28}9--{3GuhDzR#g_?4%`FOq6}ulq~llqdO~mU$0(v(Lv{-1 zj^p=k`JQUd8*9?V zP_vNDPdfkp>NlnTMeO{a{E{zT#J49wHgWNPfg!;6x#PAE6m-@S{2W!vAmNLDZ-FFk z&?EZ5r@vHDhWeZ#VVyN94S#x{ufH0iKLeBZjh@^m(T(T8AXw&!K@ zw}Nxhs{N;?QUU-CMks`4YqzX@e!I6OL15xmuzCGA@lE@fQ(zy+63zGM01^*T0oP4? zohp0TgeAN_onbp{s#Vf(3A+{iyj2tkuW03c~Arh$Q%dXvL`3|Ecre{Ti;cYe2uT_vfK4g?V#~IB|Nre>}#g@v!e%pRb zL|^}M+D}(E!OHvOnHZDx!b-cofLi6#`Kbaw@{xf3ns2j#E9if= z7fYLa{n39N2I@I*H6u=@3Nn4^DK#0C!x!|hXk{sYbnPM$QbnjxeO17odX$P9ke zP}Aee4LqOT5YSI+MNIB!C)gb$hzX%n9xdT$Pff+T30y&;txZf%7c9R&<5(4ew6j~9 zDHzx_!Nn9KcppIs+`9Y&M#w03Woa$IX8lNAZ(c^_d}eXlmMt0NvCMW#6-BDKYo^_p zuHjtzN`iM2=vlLVd37!*ci@q6KdbhY9@vgfmDnU1ldavej8Cw1$GC!WU{AivdLH=P z)kKT+&p+DhUVam;`x0RboYS9v29CuOMk0fL<7h&Y@nhCMi_-lyk+oP?!A&>hNlj!! zpH4ayWxxC%@`DF?7`r1pQy|Cn5y{)HkANO;8=2mdj%B@Jg=uLB##{2$2w~H1BvqSY zxygnDQJHV;824Zh23-MG@s-lf9;vA4nF0?{{$^_7%-yYs=tR(%gUdM*gPJk2@M8z) z+TA&?OsnVwUWvGaniMjmvs9~sU7Y=ZC=Aj$ixr<{ZXB?UUU^D(hym1BQ9<{)u9X+f z9>(BC^7tpy3|k(%qv0O|N`B#FAUg|h03EMg_UH-Vm6Pz2h~`D7a0H?eZv+I)tn9Ik zGm*jayVK3;Iez|8;~^In&3AvZ@>FW~{=TaqjKP#K)-#Cif%iMK!301(OPdgNUXA#; zilv|WE!4qZ{@f4#RUu1^<8M#x4R8qRUW>f?G3U@FXsjBiS>9ju>_6P{*YVCjm;Ro8 zS;NuGfD6lf@Xxcm;1x3$_74vpx;0K)i?sjcTvc+$sa*-j(fZ+gRaN_P!!!DLdbcSx zq-ayNTU=fpKW%wgRBb4HhNQRwWbz1g79xzJOw==-q>*U);QEeXVrotN^pI^jAJd3d z@d%FVIi4yqjfx91qg(gQ`qM?tTJVx?B@_HV0foKlXV)fHQU87#_M^58-J7G07D7R-b%UkeGsm`~8{5PBS&pQQ=3r99!WlXE*Ev0i-_co==$r=bG zbCvW@R&)2cin?|33&?e#)Cm4k<7+(Nv*K&R-qo{^g=g)A^YN6NP+pu{Ya zGxlUCapYzUYpI~0E96y39%~5$v0>(E0xIdTgA#5y5M{z&b#dJ^3Z=DGvQ)Aty-S!W zPUWj-Y8)+>bTQUp^8#adDeS|l1xXy1N<{kGo4;fr=PL?pCqmS1>H5V^a4UHD)uM@r zT~0w5P)O%kpij;MmOGR0I;$qN=L_aL7^1>h-+AU()-NEeyaf z_8Scr$_TEYi!(dId8>}WF&Sp~%}7bea&Rzm|CTK)2)oMYVF!|9P|O12L0CnuMhmYD zk!dwJ*K=3r`aTUa`Q~GmI7voPme-&KjdCC2v89#Upqc{ zWpl8yxk~xY+@Uf4^zAQv`DRQQgjuptpC@;$&RiyNa|VO2=wA(iZ`RwhYy5@%ZAFH&X(q74j!8Hc6dHB^djyq=N1z0JmRkWo&Uy=v@S zh(h-mVW%ucH+#Ps?udpqS5WYR-yzG zF#ZG}@?1wJsI1x#HRF>xoJKQ;mXOvil4qFkeV`)kqWhn3#K`0zSWMvm}IOlT2So=+K!GyqgVkR3yiaM5i zAvuBbworY?j=7}m$Q129En7_ycsnGbJ|kT@_2vD}TQk1C%#l64I2HgDfvl<1bHmdHbzMa2olaq4vtj9J}gdXGCiwjRbBjPSG+immh z+V@gy>B5q<22LQFA>O)2uT=29my`@wNN8aXW`zQmAq#C!bRoT_RDF1L#JP~r5QK1w z_~5smbK6t@xJBna8s7S{1KM`LSEzh%ieq0xnGjqVrZ?^ie&VHwXmoTkpG(#Lfkpfl zU7Rn>FV?E79}2h}9J8@54+hD{{aI(&%s^P@ z%2Ld4R#_+b!s2g6vp0OjjMT8*HD-00)vw-{ryz0j1r6F2r7$mc7P@L5CxTJs zi@Cr;jTt}asT|eW-WIxBz^L~KcIVYZu$@;=@yygcSk4l*Sa`W-GqsmCZC=hh zoGvV(*v&PXg&CBg1EDRhqBPo)pFNd!cboKsbQRl%PWYGgk=o`uQ*5{sO5@^}+4IGA z9J+dhum^)1LT7@A_h4SS26&TFYQ;tqHW%W0oLtNarR6pal+~q^Bd>>LxlDwi=ryso z*{HE#3jy`MP+3{F(L=Vxv@|*2v8k{W9>SV04li1YnwOWLz*f z5&ndiPk80O|0f&#QxT`I#P?w`pqY;K{y&s`XIN8P*DZQZ)B`FOih_b3RC-Y5zz8!Ww&nqwqA`Ex}ryZ_)Xd%^)-sS5+0e+Z}pYIwj z^+X#<3)ySFr1eTG*<+j(6w?{DyhSQ&vWf5}R?1-uc{%#Z{8)#zOj$}vM_usIT^-F& z0kEvD%HsqT4&k=H$dw_=cC+}5ITHl*C7;LZ+k4#%YOMBowWS&meO z@;%JavM?gHW#V=7_tW=lS^g?C)qI#GC|k(n8fpk#Bn17 zBM2<-+79MOMfuq`Qyy^UuqaK|N!iD-@5)&Z2HFTljo@!i)6D{#8!)HGeOE);e0K=w z5}ur+a+l`(YW)VawF)0QKraq(!WEpZpRuq>?)5CVGET3g_#oaC60!n_BUvWnKOe^r z0MVapXx%nh&wWd1WRZO3BS&V@BFk?5D0x0 z=m_LeyLdtsYsoG2iES9N8F++enGhu6_2DPnnQ6pGYhi7G{BfMK7dG4b@OutuSmi1g)VERYQUkj5ppy z-5vk)Z7SS!Qm87wO+BZrPtzz5@%@{$PaC`Ok`>DT?+k7v?+&$1mmk=p$Gp@3NXF2c z;topMaL@^1)AH87g-j{bylv>luk;&czJ)FQ9^o-eqCTa|aG625+A{l2T^^PDtWAi( z{Zci_2L4GEUZG&yi`eCVbV%Ys#g$45rL2b9Yi5jUYd*%}q>t|MN6PcGD)_*HS$z<` zU~kj(XS~CUOs0%H6N^)5dzjzQ*)-9|$LDi)StR!jOJ{n8<}Uc0dkR`+qLdKg9y7pR zi&b%;X>Neg^k6w?GA5&NGNp3-&MfkM@1xG;fJsAhio+*9A}rEn0Nk(RNISsj3*RDY z9cqi;Oz4?hodkZJy{PI-*c*E8u}sOGfwgAul>y~Da>1-ZqL$epQN#SKgubK(_9}=MbU52ICW1e+EZgX=GK* zy4F`zrD{ZdDHgbfxgG|nnkUzGPM}4wjun^X<5_y#OS5C!O{e_o}Zp6f2s*CSnRE+ zwNf$M&HKAA@>UBK5JJEmPkKSd$zXZSSSKI~1{`gc1=O^A*XNsnt@X=nbmNDY+eL%@ z_o~?Z;J|pDaxyB=O{qRrx;H;f_R;*x;O5h z{=Ig`;@+d*P4aGR_`MPI#=n23HV@zZ(QkU?>cH`FPxOEJM{tvK^yTWAEk8fJ@>4Bi z$L}Zp@86d6XN-+*Wm+Ge*6%j*K90KW-|wj_vlCHrW_GKJLZPUfBiE+OzXIDd70hpB zXlCmwKqbJreoMcVDyika_Wa#j@4wze?nW`xXIT;ka0(vSAnjJKjvd(?IO!WNmXj`%dy5|DAr(r{J)=Z zA&1m|T_0mo;P6GNhUJbH^U?APME~N-LEheTb$xo1GMJ*uJ*>sDy)xeE;J5R)FR4*2Y=_Z z|9`%`3`E)9a}U1udt#MAt2Y;`Z zgT(mrn7Bq8{Q`W95gp#mi{87DC9GCNPehtq2_-)ZL|nft71Sm zjNb5necIx4jWx@IP}cXWSJ9#vl^Ux9zh6cCe%5b~SKvJKzrB>n_g!YO{Bf+9mj95_ z!t|hnirox_z@zw8LUor$Zf1sE zm=&*`x#b2@g?{Y!TD4{>G%49ZfsK@+2mbMX0}t9FoLzQZ(Rq4)m&wn^&<;^KIcN@- z9p{?q?aj9!CSKfT8(OWCvr`g6HHj_SwHY-`4xH*MX7r4k^$hVDs>>zkuLH-t*~*+N zio)+33i%U-ReNY)ZEe{f@6kzw`hi$@eD*>o3xkyMxvBp1ELC5?g2Up^DM#McM(eRJ zEoDRFr6RiSogINrzkPbxbKtBAsw$Y4eC*y4`TF^@8No}{1WvV|NOBMFI}|L8ptX^O zp!MtQDQv|`D=?zx&$Er4`z{mXF0;v1k^>+wqdynQim&RKQCNI&)73#tP>*GdDQl^&H zo45D}9l6^XxOLvbNj^0@$NODjkLO^5w*8`b6hE5g3tf==8K31X0qpCSP z+`UX{TR$9`NFcH;rK|!vzju4akDN8;A1LR-SpEuxDR$&b>5QK*SE|GFbumG&&dBE1 z&S$6&N{410e{3w(XuLyyLl}4Q3g%+tebMQg?NlOWkaJYa;{CGbI?^9Mqwd21JTlw z&-3=Ui->`0_h6^eQz0o9@*kw|G0%94-fdy6!xi2*!N>1A9r%$P(n#)nW$oN^`s*c6 zy}6wvEPvF5KgthNzlBNoNJAfGUj1CRMr)Z&s{Qs&&xZpXp#!eQJMe2KEvyS1#~Tf@*D&2G=ftn8u3Uz(-c4<+^H zpPgiy806^KXVvKW!k5`3r>Aad7m!D(6{&-u`^%t?!5ZD-G8pfxD*sgqZWn&o*G>=u z?bZw|QA@;IAPj?C116f}`d-dQhFjPh(JeULhiWb&Y`I+ATB#h6T-mK< zUwtzXjn~a0e8;bk2XC4;I}>ECEyy>pgw7`gwa^{;rD(nnkOykRDtS16d(Rer2?Go? z^^rL?EUzqVkX*D#{fp)QiFM~n*M;!Y#HKHcKe0ws#B)fDa?}>dE2;5FL8&F#=ci;J zBKcQ!7fcR7dGlR<1&_||eg4n~=a-(Ie^~6u&UK0MI{nfu@&pJi&p2pXo64-G?7URi z*j}xQGMJp|^L^dTC*rSuZ8u1Zn2mu4&RL4RW0HyEwR3t;CIEgDRs%AJ zeg%h?WZT_+9n3lIe!O=R9uJ=}gwym+H*F>$??kp>V;l;Y5{$(vc_+z7xEgBj>zLtO4OD! z&7&pp1>O9<^vDxc-T4IRTov7?=6qMM&=#k`_^`>+LWX*diO({B!y(R^yUs#AiMrio zk?&!B-!$T)d#t=s{+&_*3x%VZnA(Zbf*K8Z&%|1G;n`M#U%2c`)FvDkET`WVy=X_M z>jOsIo(%u9J*Y{oz*oeOnQ!<)SAUv7t^q$#Ihc_vWF6_W&kCAY)Gm(@ zl?ld=$>D)^mmo9h{m6?<`>9j8YolEGR{HvJ=Pacni)_&4N}6sRmn231v<_Vtcic+N z?z$_?dZ=%|QOXoNpVDSDKBWt@-ATSr!f=T5jHrF6r(TX{S$D5Hp!JW pnqLD(Td_K13^gK(qo^H1~sYH$jvy_CAPDt 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

mG~;y}0UR zQ3mwm=LhwZ`WuV1EPr5uTv?x4=xGWMsM$Sr-~>y)Y&%%w<1$4h%Hw0$+*w9~WR}9_ z`XhEuw=Pnq5V~#aCStSj=SS>9L^SfSe+v!L7K3Q%Wx#@2?Wcam=rC9PoLK+Xf{(S3}Qz6~%q6xgsTsRk%eMg$wAdOZiX`p@mhv*xnwQ<%Fph9;Y^}{s68-X%#Pb_ zSs|oBUhh00JRO~+z9ELjbptt9SMhaOGVgYZj5wDp@L9etTlJ4TF4USkdf%_$-#d^LbmwDAY)?qV3Nk5OC+(lIW+q6&J8m4Yb9Er$z4;5|zveFd ze?XA`GePoSPt+2VspfttPQxNqy9ITY^yO1Zq`UGq6ErAsKo`uz|BK>5vQ^EC%_1pj>Gn5DNf p? Date: Fri, 30 Dec 2022 08:58:01 -0700 Subject: [PATCH 65/76] challenge 4: fix permissions and dependancies --- .../Student/Resources/bicep/04-01-hub.bicep | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/035-HubAndSpoke/Student/Resources/bicep/04-01-hub.bicep b/035-HubAndSpoke/Student/Resources/bicep/04-01-hub.bicep index 4aca636f70..b0c0406424 100644 --- a/035-HubAndSpoke/Student/Resources/bicep/04-01-hub.bicep +++ b/035-HubAndSpoke/Student/Resources/bicep/04-01-hub.bicep @@ -82,6 +82,17 @@ resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = { } } +//grant user identity permissions to read storage account resource +resource roleAssignmentUMIReader 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(resourceGroup().id, userAssignedIdentity.id, storageAccount.id, 'Reader and Data Access') + properties: { + roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c12c1c16-33a1-487b-954d-41c89c60f349') // Reader and Data Access + principalId: userAssignedIdentity.properties.principalId + principalType: 'ServicePrincipal' + } +} + +// grant user identity permissions to read storage account data resource roleAssignmentUMIStorageData 'Microsoft.Authorization/roleAssignments@2022-04-01' = { name: guid(resourceGroup().id, userAssignedIdentity.id, storageAccount.id, 'data') properties: { @@ -132,6 +143,11 @@ resource accessPolicy 'Microsoft.KeyVault/vaults/accessPolicies@2022-07-01' = { resource containerCertRequester 'Microsoft.ContainerInstance/containerGroups@2022-09-01' = if (useSelfSignedCertificate == false) { name: 'wth-container-certrequester01' location: location + dependsOn: [ + roleAssignmentUMIReader + roleAssignmentUMIStorageData + roleAssignmentUMIKeyVault + ] identity: { type: 'UserAssigned' userAssignedIdentities: { @@ -328,6 +344,11 @@ resource deploymentScriptCertUploader 'Microsoft.Resources/deploymentScripts@202 resource deploymentScriptSelfSignedCert 'Microsoft.Resources/deploymentScripts@2020-10-01' = if (useSelfSignedCertificate) { name: 'wth-dscript-genselfsignedcert01' location: location +dependsOn: [ + roleAssignmentUMIReader + roleAssignmentUMIStorageData + roleAssignmentUMIKeyVault +] kind: 'AzurePowerShell' identity: { type: 'UserAssigned' From 17b701e1fd0df934b44bf3d992db3f1bfd5eb731 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Tue, 10 Jan 2023 13:17:28 -0700 Subject: [PATCH 66/76] move to Coaches, remove .gitattribute --- .gitattributes | 3 +-- .../Solutions}/bicep/01-00-resourceGroups.bicep | 0 .../Solutions}/bicep/01-01-hub.bicep | 0 .../Solutions}/bicep/01-01-spoke1.bicep | 0 .../Solutions}/bicep/01-01-spoke2.bicep | 0 .../Solutions}/bicep/01-02-vnetpeeringhub.bicep | 0 .../Solutions}/bicep/01-02-vnetpeeringspoke1.bicep | 0 .../Solutions}/bicep/01-02-vnetpeeringspoke2.bicep | 0 .../Solutions}/bicep/01-03-onprem.bicep | 0 .../Solutions}/bicep/01-04-hubvpnconfig.bicep | 0 .../Solutions}/bicep/02-00-afw.bicep | 0 .../Solutions}/bicep/02-01-fwpolicyrules.bicep | 0 .../Solutions}/bicep/02-01-hub.bicep | 0 .../Solutions}/bicep/02-01-onprem.bicep | 0 .../Solutions}/bicep/02-01-spoke1.bicep | 0 .../Solutions}/bicep/02-01-spoke2.bicep | 0 .../Solutions}/bicep/03-01-hub.bicep | 0 .../Solutions}/bicep/03-01-spoke1.bicep | 0 .../Solutions}/bicep/03-01-spoke2.bicep | 0 .../Solutions}/bicep/03-02-spoke1.bicep | 0 .../Solutions}/bicep/03-02-spoke2.bicep | 0 .../Solutions}/bicep/04-01-hub.bicep | 0 .../Solutions}/bicep/04-02-hub.bicep | 0 .../Solutions}/bicep/05-01-hub.bicep | 0 .../Solutions}/bicep/05-01-spoke1.bicep | 0 .../Solutions}/bicep/05-01-spoke2.bicep | 0 .../Resources => Coach/Solutions}/bicep/README.md | 0 .../Solutions}/bicep/appGWCertificateProcess.md | 0 .../Solutions}/bicep/csrScript.txt | 0 .../Resources => Coach/Solutions}/bicep/deploy.ps1 | 0 .../Solutions}/bicep/docker/DOCKERFILE | 0 .../bicep/media/challenge-4-dynv6apikey.png | Bin .../bicep/media/challenge-4-dynv6signup.png | Bin .../bicep/media/challenge-4-dynv6tsig.png | Bin .../bicep/media/challenge-4-dynv6tsigkey.png | Bin .../Solutions}/bicep/media/challenge-4-example.png | Bin 36 files changed, 1 insertion(+), 2 deletions(-) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/01-00-resourceGroups.bicep (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/01-01-hub.bicep (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/01-01-spoke1.bicep (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/01-01-spoke2.bicep (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/01-02-vnetpeeringhub.bicep (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/01-02-vnetpeeringspoke1.bicep (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/01-02-vnetpeeringspoke2.bicep (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/01-03-onprem.bicep (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/01-04-hubvpnconfig.bicep (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/02-00-afw.bicep (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/02-01-fwpolicyrules.bicep (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/02-01-hub.bicep (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/02-01-onprem.bicep (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/02-01-spoke1.bicep (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/02-01-spoke2.bicep (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/03-01-hub.bicep (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/03-01-spoke1.bicep (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/03-01-spoke2.bicep (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/03-02-spoke1.bicep (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/03-02-spoke2.bicep (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/04-01-hub.bicep (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/04-02-hub.bicep (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/05-01-hub.bicep (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/05-01-spoke1.bicep (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/05-01-spoke2.bicep (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/README.md (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/appGWCertificateProcess.md (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/csrScript.txt (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/deploy.ps1 (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/docker/DOCKERFILE (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/media/challenge-4-dynv6apikey.png (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/media/challenge-4-dynv6signup.png (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/media/challenge-4-dynv6tsig.png (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/media/challenge-4-dynv6tsigkey.png (100%) rename 035-HubAndSpoke/{Student/Resources => Coach/Solutions}/bicep/media/challenge-4-example.png (100%) diff --git a/.gitattributes b/.gitattributes index 4aa1522deb..6df265fc72 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1 @@ -.github/workflows/create-wth-template.sh eol=lf -035-HubAndSpoke/Student/Resources/bicep/docker/DOCKERFILE eol=lf \ No newline at end of file +.github/workflows/create-wth-template.sh eol=lf \ No newline at end of file diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-00-resourceGroups.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/01-00-resourceGroups.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/01-00-resourceGroups.bicep rename to 035-HubAndSpoke/Coach/Solutions/bicep/01-00-resourceGroups.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-01-hub.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/01-01-hub.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/01-01-hub.bicep rename to 035-HubAndSpoke/Coach/Solutions/bicep/01-01-hub.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-01-spoke1.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/01-01-spoke1.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/01-01-spoke1.bicep rename to 035-HubAndSpoke/Coach/Solutions/bicep/01-01-spoke1.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-01-spoke2.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/01-01-spoke2.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/01-01-spoke2.bicep rename to 035-HubAndSpoke/Coach/Solutions/bicep/01-01-spoke2.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-02-vnetpeeringhub.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/01-02-vnetpeeringhub.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/01-02-vnetpeeringhub.bicep rename to 035-HubAndSpoke/Coach/Solutions/bicep/01-02-vnetpeeringhub.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-02-vnetpeeringspoke1.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/01-02-vnetpeeringspoke1.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/01-02-vnetpeeringspoke1.bicep rename to 035-HubAndSpoke/Coach/Solutions/bicep/01-02-vnetpeeringspoke1.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-02-vnetpeeringspoke2.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/01-02-vnetpeeringspoke2.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/01-02-vnetpeeringspoke2.bicep rename to 035-HubAndSpoke/Coach/Solutions/bicep/01-02-vnetpeeringspoke2.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-03-onprem.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/01-03-onprem.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/01-03-onprem.bicep rename to 035-HubAndSpoke/Coach/Solutions/bicep/01-03-onprem.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/01-04-hubvpnconfig.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/01-04-hubvpnconfig.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/01-04-hubvpnconfig.bicep rename to 035-HubAndSpoke/Coach/Solutions/bicep/01-04-hubvpnconfig.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-00-afw.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/02-00-afw.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/02-00-afw.bicep rename to 035-HubAndSpoke/Coach/Solutions/bicep/02-00-afw.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-01-fwpolicyrules.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/02-01-fwpolicyrules.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/02-01-fwpolicyrules.bicep rename to 035-HubAndSpoke/Coach/Solutions/bicep/02-01-fwpolicyrules.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-01-hub.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/02-01-hub.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/02-01-hub.bicep rename to 035-HubAndSpoke/Coach/Solutions/bicep/02-01-hub.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-01-onprem.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/02-01-onprem.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/02-01-onprem.bicep rename to 035-HubAndSpoke/Coach/Solutions/bicep/02-01-onprem.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke1.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/02-01-spoke1.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/02-01-spoke1.bicep rename to 035-HubAndSpoke/Coach/Solutions/bicep/02-01-spoke1.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/02-01-spoke2.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/02-01-spoke2.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/02-01-spoke2.bicep rename to 035-HubAndSpoke/Coach/Solutions/bicep/02-01-spoke2.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/03-01-hub.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/03-01-hub.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/03-01-hub.bicep rename to 035-HubAndSpoke/Coach/Solutions/bicep/03-01-hub.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/03-01-spoke1.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/03-01-spoke1.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/03-01-spoke1.bicep rename to 035-HubAndSpoke/Coach/Solutions/bicep/03-01-spoke1.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/03-01-spoke2.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/03-01-spoke2.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/03-01-spoke2.bicep rename to 035-HubAndSpoke/Coach/Solutions/bicep/03-01-spoke2.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/03-02-spoke1.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/03-02-spoke1.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/03-02-spoke1.bicep rename to 035-HubAndSpoke/Coach/Solutions/bicep/03-02-spoke1.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/03-02-spoke2.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/03-02-spoke2.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/03-02-spoke2.bicep rename to 035-HubAndSpoke/Coach/Solutions/bicep/03-02-spoke2.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/04-01-hub.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/04-01-hub.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/04-01-hub.bicep rename to 035-HubAndSpoke/Coach/Solutions/bicep/04-01-hub.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/04-02-hub.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/04-02-hub.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/04-02-hub.bicep rename to 035-HubAndSpoke/Coach/Solutions/bicep/04-02-hub.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/05-01-hub.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/05-01-hub.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/05-01-hub.bicep rename to 035-HubAndSpoke/Coach/Solutions/bicep/05-01-hub.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke1.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/05-01-spoke1.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/05-01-spoke1.bicep rename to 035-HubAndSpoke/Coach/Solutions/bicep/05-01-spoke1.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/05-01-spoke2.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/05-01-spoke2.bicep similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/05-01-spoke2.bicep rename to 035-HubAndSpoke/Coach/Solutions/bicep/05-01-spoke2.bicep diff --git a/035-HubAndSpoke/Student/Resources/bicep/README.md b/035-HubAndSpoke/Coach/Solutions/bicep/README.md similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/README.md rename to 035-HubAndSpoke/Coach/Solutions/bicep/README.md diff --git a/035-HubAndSpoke/Student/Resources/bicep/appGWCertificateProcess.md b/035-HubAndSpoke/Coach/Solutions/bicep/appGWCertificateProcess.md similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/appGWCertificateProcess.md rename to 035-HubAndSpoke/Coach/Solutions/bicep/appGWCertificateProcess.md diff --git a/035-HubAndSpoke/Student/Resources/bicep/csrScript.txt b/035-HubAndSpoke/Coach/Solutions/bicep/csrScript.txt similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/csrScript.txt rename to 035-HubAndSpoke/Coach/Solutions/bicep/csrScript.txt diff --git a/035-HubAndSpoke/Student/Resources/bicep/deploy.ps1 b/035-HubAndSpoke/Coach/Solutions/bicep/deploy.ps1 similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/deploy.ps1 rename to 035-HubAndSpoke/Coach/Solutions/bicep/deploy.ps1 diff --git a/035-HubAndSpoke/Student/Resources/bicep/docker/DOCKERFILE b/035-HubAndSpoke/Coach/Solutions/bicep/docker/DOCKERFILE similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/docker/DOCKERFILE rename to 035-HubAndSpoke/Coach/Solutions/bicep/docker/DOCKERFILE diff --git a/035-HubAndSpoke/Student/Resources/bicep/media/challenge-4-dynv6apikey.png b/035-HubAndSpoke/Coach/Solutions/bicep/media/challenge-4-dynv6apikey.png similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/media/challenge-4-dynv6apikey.png rename to 035-HubAndSpoke/Coach/Solutions/bicep/media/challenge-4-dynv6apikey.png diff --git a/035-HubAndSpoke/Student/Resources/bicep/media/challenge-4-dynv6signup.png b/035-HubAndSpoke/Coach/Solutions/bicep/media/challenge-4-dynv6signup.png similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/media/challenge-4-dynv6signup.png rename to 035-HubAndSpoke/Coach/Solutions/bicep/media/challenge-4-dynv6signup.png diff --git a/035-HubAndSpoke/Student/Resources/bicep/media/challenge-4-dynv6tsig.png b/035-HubAndSpoke/Coach/Solutions/bicep/media/challenge-4-dynv6tsig.png similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/media/challenge-4-dynv6tsig.png rename to 035-HubAndSpoke/Coach/Solutions/bicep/media/challenge-4-dynv6tsig.png diff --git a/035-HubAndSpoke/Student/Resources/bicep/media/challenge-4-dynv6tsigkey.png b/035-HubAndSpoke/Coach/Solutions/bicep/media/challenge-4-dynv6tsigkey.png similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/media/challenge-4-dynv6tsigkey.png rename to 035-HubAndSpoke/Coach/Solutions/bicep/media/challenge-4-dynv6tsigkey.png diff --git a/035-HubAndSpoke/Student/Resources/bicep/media/challenge-4-example.png b/035-HubAndSpoke/Coach/Solutions/bicep/media/challenge-4-example.png similarity index 100% rename from 035-HubAndSpoke/Student/Resources/bicep/media/challenge-4-example.png rename to 035-HubAndSpoke/Coach/Solutions/bicep/media/challenge-4-example.png From 59091a729ab497891bfa462c53fc9ff6a27a44e3 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Tue, 10 Jan 2023 13:22:15 -0700 Subject: [PATCH 67/76] DOCKERFILE line ending --- 035-HubAndSpoke/Coach/Solutions/bicep/docker/.gitattributes | 1 + 1 file changed, 1 insertion(+) create mode 100644 035-HubAndSpoke/Coach/Solutions/bicep/docker/.gitattributes diff --git a/035-HubAndSpoke/Coach/Solutions/bicep/docker/.gitattributes b/035-HubAndSpoke/Coach/Solutions/bicep/docker/.gitattributes new file mode 100644 index 0000000000..e50633e122 --- /dev/null +++ b/035-HubAndSpoke/Coach/Solutions/bicep/docker/.gitattributes @@ -0,0 +1 @@ +DOCKERFILE eol=lf \ No newline at end of file From fca706e6f718ca407e0c2368a0712c0082dbb867 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Tue, 10 Jan 2023 13:38:36 -0700 Subject: [PATCH 68/76] coaches bicep solution documentation --- 035-HubAndSpoke/Coach/README.md | 14 ++++++++++++++ 035-HubAndSpoke/Coach/Solutions/bicep/README.md | 1 + 2 files changed, 15 insertions(+) diff --git a/035-HubAndSpoke/Coach/README.md b/035-HubAndSpoke/Coach/README.md index 7ab9ebfbed..ad42ff9e59 100644 --- a/035-HubAndSpoke/Coach/README.md +++ b/035-HubAndSpoke/Coach/README.md @@ -26,3 +26,17 @@ These topics are not covered, and you might want to introduce them along the way - Add an Application Gateway to the mix - Challenge 5: **[PaaS Networking](05-Paas.md)** - Integrate Azure Web Apps and Azure SQL Databases with your hub and spoke design + +## Deployment using Infrastructure-as-Code +The coaches solutions for this hack includes a deployment of the challenges written in Bicep. + +For coaches, the infrastructure deployed in the solution can provide a quick reference architecture/lab for an approach to implementing the challenges. + +For students, the automation presents a solution, which the students are generally expected to figure out on their own. However, there are a number of scenarios where providing a student with the Bicep files could be helpful: + +* Bringing a student up to speed with the rest of the cohort +* Enabling students to focus on the network aspects of the hack, versus manual infrastructure deployment (especially when they are struggling with a less-relevant aspect) +* Quickly bringing a cohort of students up to a specific challenge (for example, enabling data-focused students to work with PaaS services and Private Endpoints, without having had to manually deploy the underlying infrastructure) +* Providing examples to students looking to implement the hack with IaC + +**See [Bicep Solution Readme](./Solutions/bicep/README.md) for detail deployment process.** \ No newline at end of file diff --git a/035-HubAndSpoke/Coach/Solutions/bicep/README.md b/035-HubAndSpoke/Coach/Solutions/bicep/README.md index 5bf338663e..18564f7892 100644 --- a/035-HubAndSpoke/Coach/Solutions/bicep/README.md +++ b/035-HubAndSpoke/Coach/Solutions/bicep/README.md @@ -9,6 +9,7 @@ The WTH philosophy intends to have students learn by doing, and recognizes that - Students who will not be completing a challenge which is a prerequisite to a later challenge - Students who are falling behind in the WTH due to issues unrelated to the core learning goals of this WTH - Students looking for a reference implementation to compare against their own approach +- Coaches looking to deploy a reference architecture to the lab ## Using these templates From 4e97eadb76bf82713e874e04cec2faad5c06cea5 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Thu, 19 Jan 2023 10:41:17 -0700 Subject: [PATCH 69/76] added nsg for on prem vpn subnet --- .../Coach/Solutions/bicep/01-03-onprem.bicep | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/035-HubAndSpoke/Coach/Solutions/bicep/01-03-onprem.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/01-03-onprem.bicep index c8d02b25f2..64464639fe 100644 --- a/035-HubAndSpoke/Coach/Solutions/bicep/01-03-onprem.bicep +++ b/035-HubAndSpoke/Coach/Solutions/bicep/01-03-onprem.bicep @@ -6,6 +6,15 @@ param vmPassword string targetScope = 'resourceGroup' //onprem resources +resource hubvnet 'Microsoft.Network/virtualNetworks@2022-07-01' existing = { + name: 'wth-vnet-hub01' + scope: resourceGroup('wth-rg-hub') + + resource gwsubnet 'subnets' existing = { + name: 'GatewaySubnet' + } +} + resource wthonpremvnet 'Microsoft.Network/virtualNetworks@2021-08-01' = { name: 'wth-vnet-onprem01' location: location @@ -20,6 +29,9 @@ resource wthonpremvnet 'Microsoft.Network/virtualNetworks@2021-08-01' = { name: 'subnet-vpn' properties: { addressPrefix: '172.16.0.0/24' + networkSecurityGroup: { + id: nsgonpremvpn.id + } } } { @@ -199,6 +211,41 @@ resource nsgonpremvms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { } } +resource nsgonpremvpn 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { + name: 'wth-nsg-onpremvpnsubnet' + location: location + properties: { + securityRules: [ + { + name: 'allow-any-to-vpnsubnet-from-onprem' + properties: { + priority: 1000 + access: 'Allow' + direction: 'Inbound' + protocol: '*' + sourcePortRange: '*' + destinationPortRange: '*' + sourceAddressPrefix: '172.16.10.0/24' + destinationAddressPrefix: '*' + } + } + { + name: 'allow-any-to-any-from-azurevpngw' + properties: { + priority: 1001 + access: 'Allow' + direction: 'Inbound' + protocol: '*' + sourcePortRange: '*' + destinationPortRange: '*' + sourceAddressPrefix: hubvnet::gwsubnet.properties.addressPrefix + destinationAddressPrefix: '*' + } + } + ] + } +} + resource wthonpremcsrpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { name: 'wth-pip-csr01' location: location From cca1c394d2dff6a53bef41556d4a8ecaeade1c67 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Thu, 19 Jan 2023 10:48:23 -0700 Subject: [PATCH 70/76] removed local prefix from lng - should come from bgp --- .../Coach/Solutions/bicep/01-04-hubvpnconfig.bicep | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/035-HubAndSpoke/Coach/Solutions/bicep/01-04-hubvpnconfig.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/01-04-hubvpnconfig.bicep index dbc432e901..11883fa563 100644 --- a/035-HubAndSpoke/Coach/Solutions/bicep/01-04-hubvpnconfig.bicep +++ b/035-HubAndSpoke/Coach/Solutions/bicep/01-04-hubvpnconfig.bicep @@ -21,9 +21,7 @@ resource wthhublocalgw 'Microsoft.Network/localNetworkGateways@2022-01-01' = { properties: { gatewayIpAddress: onpremcsrpip.properties.ipAddress localNetworkAddressSpace: { - addressPrefixes: [ - '172.16.0.0/16' - ] + addressPrefixes: [] } bgpSettings: { bgpPeeringAddress: onpremcsrnic.properties.ipConfigurations[0].properties.privateIPAddress From dd691ab0f8efcbac637cfd9e8cae3e7553f43e02 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Thu, 23 Feb 2023 15:00:20 -0700 Subject: [PATCH 71/76] enable ping spoke 2 --- 035-HubAndSpoke/Coach/Solutions/bicep/01-01-spoke2.bicep | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/035-HubAndSpoke/Coach/Solutions/bicep/01-01-spoke2.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/01-01-spoke2.bicep index 3e95f45c0c..bc959ce86e 100644 --- a/035-HubAndSpoke/Coach/Solutions/bicep/01-01-spoke2.bicep +++ b/035-HubAndSpoke/Coach/Solutions/bicep/01-01-spoke2.bicep @@ -119,7 +119,7 @@ resource changerdpport 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' type: 'CustomScriptExtension' typeHandlerVersion: '1.10' settings: { - commandToExecute: 'powershell.exe -ep bypass -encodedcommand UwBlAHQALQBJAHQAZQBtAFAAcgBvAHAAZQByAHQAeQAgAC0AUABhAHQAaAAgACIASABLAEwATQA6AFwAUwB5AHMAdABlAG0AXABDAHUAcgByAGUAbgB0AEMAbwBuAHQAcgBvAGwAUwBlAHQAXABDAG8AbgB0AHIAbwBsAFwAVABlAHIAbQBpAG4AYQBsACAAUwBlAHIAdgBlAHIAXABXAGkAbgBTAHQAYQB0AGkAbwBuAHMAXABSAEQAUAAtAFQAYwBwAFwAIgAgAC0ATgBhAG0AZQAgAFAAbwByAHQATgB1AG0AYgBlAHIAIAAtAFYAYQBsAHUAZQAgADMAMwA4ADkAOQAKAE4AZQB3AC0ATgBlAHQARgBpAHIAZQB3AGEAbABsAFIAdQBsAGUAIAAtAEQAaQBzAHAAbABhAHkATgBhAG0AZQAgACIAUgBEAFAAIAAzADMAOAA5ADkAIABUAEMAUAAiACAALQBEAGkAcgBlAGMAdABpAG8AbgAgAEkAbgBiAG8AdQBuAGQAIAAtAEwAbwBjAGEAbABQAG8AcgB0ACAAMwAzADgAOQA5ACAALQBQAHIAbwB0AG8AYwBvAGwAIABUAEMAUAAgAC0AQQBjAHQAaQBvAG4AIABBAGwAbABvAHcACgBOAGUAdwAtAE4AZQB0AEYAaQByAGUAdwBhAGwAbABSAHUAbABlACAALQBEAGkAcwBwAGwAYQB5AE4AYQBtAGUAIAAiAFIARABQACAAMwAzADgAOQA5ACAAVQBEAFAAIgAgAC0ARABpAHIAZQBjAHQAaQBvAG4AIABJAG4AYgBvAHUAbgBkACAALQBMAG8AYwBhAGwAUABvAHIAdAAgADMAMwA4ADkAOQAgAC0AUAByAG8AdABvAGMAbwBsACAAVQBEAFAAIAAtAEEAYwB0AGkAbwBuACAAQQBsAGwAbwB3AAoAUgBlAHMAdABhAHIAdAAtAFMAZQByAHYAaQBjAGUAIAAtAE4AYQBtAGUAIABUAGUAcgBtAFMAZQByAHYAaQBjAGUAIAAtAEYAbwByAGMAZQA=' + commandToExecute: 'powershell.exe -ep bypass -encodedcommand UwBlAHQALQBJAHQAZQBtAFAAcgBvAHAAZQByAHQAeQAgAC0AUABhAHQAaAAgACIASABLAEwATQA6AFwAUwB5AHMAdABlAG0AXABDAHUAcgByAGUAbgB0AEMAbwBuAHQAcgBvAGwAUwBlAHQAXABDAG8AbgB0AHIAbwBsAFwAVABlAHIAbQBpAG4AYQBsACAAUwBlAHIAdgBlAHIAXABXAGkAbgBTAHQAYQB0AGkAbwBuAHMAXABSAEQAUAAtAFQAYwBwAFwAIgAgAC0ATgBhAG0AZQAgAFAAbwByAHQATgB1AG0AYgBlAHIAIAAtAFYAYQBsAHUAZQAgADMAMwA4ADkAOQANAAoATgBlAHcALQBOAGUAdABGAGkAcgBlAHcAYQBsAGwAUgB1AGwAZQAgAC0ARABpAHMAcABsAGEAeQBOAGEAbQBlACAAIgBSAEQAUAAgADMAMwA4ADkAOQAgAFQAQwBQACIAIAAtAEQAaQByAGUAYwB0AGkAbwBuACAASQBuAGIAbwB1AG4AZAAgAC0ATABvAGMAYQBsAFAAbwByAHQAIAAzADMAOAA5ADkAIAAtAFAAcgBvAHQAbwBjAG8AbAAgAFQAQwBQACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwANAAoATgBlAHcALQBOAGUAdABGAGkAcgBlAHcAYQBsAGwAUgB1AGwAZQAgAC0ARABpAHMAcABsAGEAeQBOAGEAbQBlACAAIgBSAEQAUAAgADMAMwA4ADkAOQAgAFUARABQACIAIAAtAEQAaQByAGUAYwB0AGkAbwBuACAASQBuAGIAbwB1AG4AZAAgAC0ATABvAGMAYQBsAFAAbwByAHQAIAAzADMAOAA5ADkAIAAtAFAAcgBvAHQAbwBjAG8AbAAgAFUARABQACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwANAAoAUgBlAHMAdABhAHIAdAAtAFMAZQByAHYAaQBjAGUAIAAtAE4AYQBtAGUAIABUAGUAcgBtAFMAZQByAHYAaQBjAGUAIAAtAEYAbwByAGMAZQANAAoADQAKAE4AZQB3AC0ATgBlAHQARgBpAHIAZQB3AGEAbABsAFIAdQBsAGUAIAAtAEQAaQBzAHAAbABhAHkATgBhAG0AZQAgACcASQBDAE0AUAB2ADQAJwAgAC0ARABpAHIAZQBjAHQAaQBvAG4AIABJAG4AYgBvAHUAbgBkACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwAgAC0AUAByAG8AdABvAGMAbwBsACAAaQBjAG0AcAB2ADQAIAAtAEUAbgBhAGIAbABlAGQAIABUAHIAdQBlAA==' } } } From cfdf1328298af49a34282f9b3c196429b7e9912c Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Thu, 1 Jun 2023 15:18:25 -0600 Subject: [PATCH 72/76] afw hub route --- .../Coach/Solutions/bicep/02-00-afw.bicep | 38 ++- .../Solutions/bicep/02-01-fwpolicyrules.bicep | 2 +- .../Coach/Solutions/bicep/02-01-hub.bicep | 8 + .../Coach/Solutions/bicep/csrScript.txt | 6 + .../Coach/Solutions/bicep/deploy.ps1 | 2 +- .../bicep/01-00-resourceGroups.bicep | 23 ++ .../Coach/Solutions/bicep/01-01-hub.bicep | 290 ++++++++++++++++ .../Coach/Solutions/bicep/01-01-spoke1.bicep | 178 ++++++++++ .../Coach/Solutions/bicep/01-01-spoke2.bicep | 178 ++++++++++ .../bicep/01-02-vnetpeeringhub.bicep | 40 +++ .../bicep/01-02-vnetpeeringspoke1.bicep | 22 ++ .../bicep/01-02-vnetpeeringspoke2.bicep | 22 ++ .../Coach/Solutions/bicep/01-03-onprem.bicep | 321 ++++++++++++++++++ .../Solutions/bicep/01-04-hubvpnconfig.bicep | 48 +++ .../Coach/Solutions/bicep/01-05-csrnva.bicep | 180 ++++++++++ .../Coach/Solutions/bicep/README.md | 122 +++++++ .../Coach/Solutions/bicep/csrScript.txt | 85 +++++ .../Coach/Solutions/bicep/csrScriptNVA.txt | 12 + .../Coach/Solutions/bicep/deploy.ps1 | 188 ++++++++++ 19 files changed, 1760 insertions(+), 5 deletions(-) create mode 100644 057-AzureRouteServer/Coach/Solutions/bicep/01-00-resourceGroups.bicep create mode 100644 057-AzureRouteServer/Coach/Solutions/bicep/01-01-hub.bicep create mode 100644 057-AzureRouteServer/Coach/Solutions/bicep/01-01-spoke1.bicep create mode 100644 057-AzureRouteServer/Coach/Solutions/bicep/01-01-spoke2.bicep create mode 100644 057-AzureRouteServer/Coach/Solutions/bicep/01-02-vnetpeeringhub.bicep create mode 100644 057-AzureRouteServer/Coach/Solutions/bicep/01-02-vnetpeeringspoke1.bicep create mode 100644 057-AzureRouteServer/Coach/Solutions/bicep/01-02-vnetpeeringspoke2.bicep create mode 100644 057-AzureRouteServer/Coach/Solutions/bicep/01-03-onprem.bicep create mode 100644 057-AzureRouteServer/Coach/Solutions/bicep/01-04-hubvpnconfig.bicep create mode 100644 057-AzureRouteServer/Coach/Solutions/bicep/01-05-csrnva.bicep create mode 100644 057-AzureRouteServer/Coach/Solutions/bicep/README.md create mode 100644 057-AzureRouteServer/Coach/Solutions/bicep/csrScript.txt create mode 100644 057-AzureRouteServer/Coach/Solutions/bicep/csrScriptNVA.txt create mode 100644 057-AzureRouteServer/Coach/Solutions/bicep/deploy.ps1 diff --git a/035-HubAndSpoke/Coach/Solutions/bicep/02-00-afw.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/02-00-afw.bicep index 80be057477..f0e517a2f1 100644 --- a/035-HubAndSpoke/Coach/Solutions/bicep/02-00-afw.bicep +++ b/035-HubAndSpoke/Coach/Solutions/bicep/02-00-afw.bicep @@ -1,4 +1,5 @@ param location string = 'eastus2' +param afwSku string = 'basic' resource hubvnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { name: 'wth-vnet-hub01' @@ -12,6 +13,13 @@ resource afwsubnet 'Microsoft.Network/virtualNetworks/subnets@2022-01-01' = { } } +resource afwmgmtsubnet 'Microsoft.Network/virtualNetworks/subnets@2022-01-01' = { + name: '${hubvnet.name}/AzureFirewallManagementSubnet' + properties: { + addressPrefix: '10.0.2.0/24' + } +} + resource wthafwpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { name: 'wth-pip-afw01' location: location @@ -24,12 +32,24 @@ resource wthafwpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { } } +resource wthafwmgmtpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { + name: 'wth-pip-afwmgmt01' + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } +} + resource wthafwpolicy 'Microsoft.Network/firewallPolicies@2022-01-01' = { - name: 'wth-fwp-standard01' + name: 'wth-fwp-policy01' location: location properties: { sku: { - tier: 'Standard' + tier: afwSku } } } @@ -40,7 +60,7 @@ resource wthafw 'Microsoft.Network/azureFirewalls@2022-01-01' = { properties: { sku: { name: 'AZFW_VNet' - tier: 'Standard' + tier: afwSku } ipConfigurations: [ { @@ -55,6 +75,18 @@ resource wthafw 'Microsoft.Network/azureFirewalls@2022-01-01' = { } } ] + managementIpConfiguration: { + name: 'ipconfigMgmt1' + properties: { + publicIPAddress: { + id: wthafwmgmtpip01.id + } + subnet: { + id: afwmgmtsubnet.id + } + } + } + firewallPolicy: { id: wthafwpolicy.id } diff --git a/035-HubAndSpoke/Coach/Solutions/bicep/02-01-fwpolicyrules.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/02-01-fwpolicyrules.bicep index b4b1a7cb6f..2d3e52ad59 100644 --- a/035-HubAndSpoke/Coach/Solutions/bicep/02-01-fwpolicyrules.bicep +++ b/035-HubAndSpoke/Coach/Solutions/bicep/02-01-fwpolicyrules.bicep @@ -1,5 +1,5 @@ resource wthafwpolicy 'Microsoft.Network/firewallPolicies@2022-01-01' existing = { - name: 'wth-fwp-standard01' + name: 'wth-fwp-policy01' scope: resourceGroup('wth-rg-hub') } diff --git a/035-HubAndSpoke/Coach/Solutions/bicep/02-01-hub.bicep b/035-HubAndSpoke/Coach/Solutions/bicep/02-01-hub.bicep index 9d3e98d02a..c68616e14b 100644 --- a/035-HubAndSpoke/Coach/Solutions/bicep/02-01-hub.bicep +++ b/035-HubAndSpoke/Coach/Solutions/bicep/02-01-hub.bicep @@ -32,6 +32,14 @@ resource rthubvms 'Microsoft.Network/routeTables@2022-01-01' = { nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress } } + { + name: 'route-afw-to-vnet' + properties: { + addressPrefix: '10.0.1.0/24' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: wthafw.properties.ipConfigurations[0].properties.privateIPAddress + } + } ] disableBgpRoutePropagation: true } diff --git a/035-HubAndSpoke/Coach/Solutions/bicep/csrScript.txt b/035-HubAndSpoke/Coach/Solutions/bicep/csrScript.txt index be46f27552..553bcaa0d3 100644 --- a/035-HubAndSpoke/Coach/Solutions/bicep/csrScript.txt +++ b/035-HubAndSpoke/Coach/Solutions/bicep/csrScript.txt @@ -1,4 +1,10 @@ Section: IOS configuration +ip ssh port 2222 rotary 1 +! +line vty 0 15 + rotary 1 + exit +! crypto ikev2 proposal azure-proposal encryption aes-cbc-256 aes-cbc-128 3des integrity sha1 diff --git a/035-HubAndSpoke/Coach/Solutions/bicep/deploy.ps1 b/035-HubAndSpoke/Coach/Solutions/bicep/deploy.ps1 index 1a136eb930..2a58414e92 100644 --- a/035-HubAndSpoke/Coach/Solutions/bicep/deploy.ps1 +++ b/035-HubAndSpoke/Coach/Solutions/bicep/deploy.ps1 @@ -172,7 +172,7 @@ switch ($challengeNumber) { Write-Host "Deploying resources for Challenge 2: Azure Firewall" Write-Host "`tDeploying Azure Firewall and related hub resources..." - $afwJob = New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./02-00-afw.bicep -TemplateParameterObject @{location = $location } -AsJob + $afwJob = New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./02-00-afw.bicep -TemplateParameterObject @{location = $location; afwSku = 'Premium' } -AsJob $afwJob | Wait-Job | Out-Null diff --git a/057-AzureRouteServer/Coach/Solutions/bicep/01-00-resourceGroups.bicep b/057-AzureRouteServer/Coach/Solutions/bicep/01-00-resourceGroups.bicep new file mode 100644 index 0000000000..dba60c6b27 --- /dev/null +++ b/057-AzureRouteServer/Coach/Solutions/bicep/01-00-resourceGroups.bicep @@ -0,0 +1,23 @@ +param location string = 'eastus2' + +targetScope = 'subscription' +//hub resources +resource wthrghub 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: 'wth-rg-hub' + location: location +} + +resource wthrgspoke01 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: 'wth-rg-spoke1' + location: location +} + +resource wthrgspoke02 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: 'wth-rg-spoke2' + location: location +} + +resource wthrgonprem 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: 'wth-rg-onprem' + location: location +} diff --git a/057-AzureRouteServer/Coach/Solutions/bicep/01-01-hub.bicep b/057-AzureRouteServer/Coach/Solutions/bicep/01-01-hub.bicep new file mode 100644 index 0000000000..6bac55c2d5 --- /dev/null +++ b/057-AzureRouteServer/Coach/Solutions/bicep/01-01-hub.bicep @@ -0,0 +1,290 @@ +param location string = 'eastus2' +param hubVMUsername string = 'admin-wth' +@secure() +param vmPassword string + +targetScope = 'resourceGroup' +//hub resources + +resource wthhubvnet 'Microsoft.Network/virtualNetworks@2021-08-01' = { + name: 'wth-vnet-hub01' + location: location + properties: { + addressSpace: { + addressPrefixes: [ + '10.0.0.0/16' + ] + } + subnets: [ + { + name: 'GatewaySubnet' + properties: { + addressPrefix: '10.0.0.0/24' + routeTable: { + id: rtvnetgw.id + } + } + } + { + name: 'subnet-hubvms' + properties: { + addressPrefix: '10.0.10.0/24' + routeTable: { + id: rthubvms.id + } + networkSecurityGroup: { + id: nsghubvms.id + } + } + } + { + name: 'RouteServerSubnet' + properties: { + addressPrefix: '10.0.3.0/24' + } + } + ] + } +} + +resource wthhubgwpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { + name: 'wth-pip-gw01' + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } +} + +output pipgw1 string = wthhubgwpip01.properties.ipAddress + +resource wthhubgwpip02 'Microsoft.Network/publicIPAddresses@2022-01-01' = { + name: 'wth-pip-gw02' + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } +} + +output pipgw2 string = wthhubgwpip02.properties.ipAddress + +resource wthhubvnetgw 'Microsoft.Network/virtualNetworkGateways@2022-01-01' = { + name: 'wth-vngw-hub01' + location: location + properties: { + activeActive: true + bgpSettings: { + asn: 65515 + } + enableBgp: true + gatewayType: 'Vpn' + vpnType: 'RouteBased' + vpnGatewayGeneration: 'Generation1' + sku: { + name: 'VpnGw1' + tier: 'VpnGw1' + } + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + publicIPAddress: { + id: wthhubgwpip01.id + } + subnet: { + id: '${wthhubvnet.id}/subnets/GatewaySubnet' + } + } + } + { + name: 'ipconfig2' + properties: { + publicIPAddress: { + id: wthhubgwpip02.id + } + subnet: { + id: '${wthhubvnet.id}/subnets/GatewaySubnet' + } + } + } + ] + } +} + +output wthhubvnetgwasn int = wthhubvnetgw.properties.bgpSettings.asn +output wthhubvnetgwprivateip1 string = wthhubvnetgw.properties.bgpSettings.bgpPeeringAddresses[0].defaultBgpIpAddresses[0] +output wthhubvnetgwprivateip2 string = wthhubvnetgw.properties.bgpSettings.bgpPeeringAddresses[1].defaultBgpIpAddresses[0] + +resource changerdpport 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' = { + name: '${wthhubvm01.name}/wth-vmextn-changerdpport33899' + location: location + properties: { + publisher: 'Microsoft.Compute' + type: 'CustomScriptExtension' + typeHandlerVersion: '1.10' + settings: { + /* + To generate encoded command in PowerShell: + + $s = @' + Set-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp\" -Name PortNumber -Value 33899 + New-NetFirewallRule -DisplayName "RDP 33899 TCP" -Direction Inbound -LocalPort 33899 -Protocol TCP -Action Allow + New-NetFirewallRule -DisplayName "RDP 33899 UDP" -Direction Inbound -LocalPort 33899 -Protocol UDP -Action Allow + Restart-Service -Name TermService -Force + + New-NetFirewallRule -DisplayName 'ICMPv4' -Direction Inbound -Action Allow -Protocol icmpv4 -Enabled True + '@ + $bytes = [System.Text.Encoding]::Unicode.GetBytes($s) + [convert]::ToBase64String($bytes) */ + commandToExecute: 'powershell.exe -ep bypass -encodedcommand UwBlAHQALQBJAHQAZQBtAFAAcgBvAHAAZQByAHQAeQAgAC0AUABhAHQAaAAgACIASABLAEwATQA6AFwAUwB5AHMAdABlAG0AXABDAHUAcgByAGUAbgB0AEMAbwBuAHQAcgBvAGwAUwBlAHQAXABDAG8AbgB0AHIAbwBsAFwAVABlAHIAbQBpAG4AYQBsACAAUwBlAHIAdgBlAHIAXABXAGkAbgBTAHQAYQB0AGkAbwBuAHMAXABSAEQAUAAtAFQAYwBwAFwAIgAgAC0ATgBhAG0AZQAgAFAAbwByAHQATgB1AG0AYgBlAHIAIAAtAFYAYQBsAHUAZQAgADMAMwA4ADkAOQANAAoATgBlAHcALQBOAGUAdABGAGkAcgBlAHcAYQBsAGwAUgB1AGwAZQAgAC0ARABpAHMAcABsAGEAeQBOAGEAbQBlACAAIgBSAEQAUAAgADMAMwA4ADkAOQAgAFQAQwBQACIAIAAtAEQAaQByAGUAYwB0AGkAbwBuACAASQBuAGIAbwB1AG4AZAAgAC0ATABvAGMAYQBsAFAAbwByAHQAIAAzADMAOAA5ADkAIAAtAFAAcgBvAHQAbwBjAG8AbAAgAFQAQwBQACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwANAAoATgBlAHcALQBOAGUAdABGAGkAcgBlAHcAYQBsAGwAUgB1AGwAZQAgAC0ARABpAHMAcABsAGEAeQBOAGEAbQBlACAAIgBSAEQAUAAgADMAMwA4ADkAOQAgAFUARABQACIAIAAtAEQAaQByAGUAYwB0AGkAbwBuACAASQBuAGIAbwB1AG4AZAAgAC0ATABvAGMAYQBsAFAAbwByAHQAIAAzADMAOAA5ADkAIAAtAFAAcgBvAHQAbwBjAG8AbAAgAFUARABQACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwANAAoAUgBlAHMAdABhAHIAdAAtAFMAZQByAHYAaQBjAGUAIAAtAE4AYQBtAGUAIABUAGUAcgBtAFMAZQByAHYAaQBjAGUAIAAtAEYAbwByAGMAZQANAAoADQAKAE4AZQB3AC0ATgBlAHQARgBpAHIAZQB3AGEAbABsAFIAdQBsAGUAIAAtAEQAaQBzAHAAbABhAHkATgBhAG0AZQAgACcASQBDAE0AUAB2ADQAJwAgAC0ARABpAHIAZQBjAHQAaQBvAG4AIABJAG4AYgBvAHUAbgBkACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwAgAC0AUAByAG8AdABvAGMAbwBsACAAaQBjAG0AcAB2ADQAIAAtAEUAbgBhAGIAbABlAGQAIABUAHIAdQBlAA==' + } + } +} + +resource wthhubvmpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { + name: 'wth-pip-hubvm01' + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } +} + +resource wthhubvmnic 'Microsoft.Network/networkInterfaces@2022-01-01' = { + name: 'wth-nic-hubvm01' + location: location + properties: { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + subnet: { + id: '${wthhubvnet.id}/subnets/subnet-hubvms' + } + privateIPAddress: '10.0.10.4' + publicIPAddress: { + id: wthhubvmpip01.id + } + } + } + ] + } +} + +resource wthhubvm01 'Microsoft.Compute/virtualMachines@2022-03-01' = { + name: 'wth-vm-hub01' + location: location + properties: { + hardwareProfile: { + vmSize: 'Standard_B2s' + } + storageProfile: { + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + osDisk: { + osType: 'Windows' + name: 'wth-disk-vmhubos01' + createOption: 'FromImage' + caching: 'ReadWrite' + } + } + osProfile: { + computerName: 'vm-hub01' + adminUsername: hubVMUsername + adminPassword: vmPassword + windowsConfiguration: { + provisionVMAgent: true + enableAutomaticUpdates: true + } + } + networkProfile: { + networkInterfaces: [ + { + id: wthhubvmnic.id + } + ] + } + diagnosticsProfile: { + bootDiagnostics: { + enabled: true + } + } + licenseType: 'Windows_Server' + } +} + +resource rtvnetgw 'Microsoft.Network/routeTables@2022-01-01' = { + name: 'wth-rt-hubgwsubnet' + location: location + properties: { + routes: [] + disableBgpRoutePropagation: false + } +} + +resource rthubvms 'Microsoft.Network/routeTables@2022-01-01' = { + name: 'wth-rt-hubvmssubnet' + location: location + properties: { + routes: [ + { + name: 'route-all-to-csr' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: '10.0.1.4' + } + } + ] + disableBgpRoutePropagation: false + } +} + +resource nsghubvms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { + name: 'wth-nsg-hubvmssubnet' + location: location + properties: { + securityRules: [ + { + name: 'allow-altrdp-to-vmssubnet-from-any' + properties: { + priority: 1000 + access: 'Allow' + direction: 'Inbound' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '33899-33899' + sourceAddressPrefix: '*' + destinationAddressPrefix: '10.0.10.0/24' + } + } + { + name: 'allow-altssh-to-vmssubnet-from-any' + properties: { + priority: 1001 + access: 'Allow' + direction: 'Inbound' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '22222-22222' + sourceAddressPrefix: '*' + destinationAddressPrefix: '10.0.10.0/24' + } + } + ] + } +} diff --git a/057-AzureRouteServer/Coach/Solutions/bicep/01-01-spoke1.bicep b/057-AzureRouteServer/Coach/Solutions/bicep/01-01-spoke1.bicep new file mode 100644 index 0000000000..6f429602b0 --- /dev/null +++ b/057-AzureRouteServer/Coach/Solutions/bicep/01-01-spoke1.bicep @@ -0,0 +1,178 @@ +param location string = 'eastus2' +param spoke1VMUsername string = 'admin-wth' +@secure() +param vmPassword string + +targetScope = 'resourceGroup' +//spoke1 resources + +resource wthspoke1vnet 'Microsoft.Network/virtualNetworks@2021-08-01' = { + name: 'wth-vnet-spoke101' + location: location + properties: { + addressSpace: { + addressPrefixes: [ + '10.1.0.0/16' + ] + } + subnets: [ + { + name: 'subnet-spoke1vms' + properties: { + addressPrefix: '10.1.10.0/24' + networkSecurityGroup: { + id: nsgspoke1vms.id + } + routeTable: { + id: rtspoke1vms.id + } + } + } + ] + } +} + +resource wthspoke1vmpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { + name: 'wth-pip-spoke1vm01' + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } +} + +resource wthspoke1vmnic 'Microsoft.Network/networkInterfaces@2022-01-01' = { + name: 'wth-nic-spoke1vm01' + location: location + properties: { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + subnet: { + id: '${wthspoke1vnet.id}/subnets/subnet-spoke1vms' + } + privateIPAddress: '10.1.10.4' + publicIPAddress: { + id: wthspoke1vmpip01.id + } + } + } + ] + } +} + +resource wthspoke1vm01 'Microsoft.Compute/virtualMachines@2022-03-01' = { + name: 'wth-vm-spoke101' + location: location + properties: { + hardwareProfile: { + vmSize: 'Standard_B2s' + } + storageProfile: { + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + osDisk: { + osType: 'Windows' + name: 'wth-disk-vmspoke1os01' + createOption: 'FromImage' + caching: 'ReadWrite' + } + } + osProfile: { + computerName: 'vm-spoke101' + adminUsername: spoke1VMUsername + adminPassword: vmPassword + windowsConfiguration: { + provisionVMAgent: true + enableAutomaticUpdates: true + } + } + networkProfile: { + networkInterfaces: [ + { + id: wthspoke1vmnic.id + } + ] + } + diagnosticsProfile: { + bootDiagnostics: { + enabled: true + } + } + licenseType: 'Windows_Server' + } +} + +resource changerdpport 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' = { + name: '${wthspoke1vm01.name}/wth-vmextn-changerdpport33899' + location: location + properties: { + publisher: 'Microsoft.Compute' + type: 'CustomScriptExtension' + typeHandlerVersion: '1.10' + settings: { + commandToExecute: 'powershell.exe -ep bypass -encodedcommand UwBlAHQALQBJAHQAZQBtAFAAcgBvAHAAZQByAHQAeQAgAC0AUABhAHQAaAAgACIASABLAEwATQA6AFwAUwB5AHMAdABlAG0AXABDAHUAcgByAGUAbgB0AEMAbwBuAHQAcgBvAGwAUwBlAHQAXABDAG8AbgB0AHIAbwBsAFwAVABlAHIAbQBpAG4AYQBsACAAUwBlAHIAdgBlAHIAXABXAGkAbgBTAHQAYQB0AGkAbwBuAHMAXABSAEQAUAAtAFQAYwBwAFwAIgAgAC0ATgBhAG0AZQAgAFAAbwByAHQATgB1AG0AYgBlAHIAIAAtAFYAYQBsAHUAZQAgADMAMwA4ADkAOQANAAoATgBlAHcALQBOAGUAdABGAGkAcgBlAHcAYQBsAGwAUgB1AGwAZQAgAC0ARABpAHMAcABsAGEAeQBOAGEAbQBlACAAIgBSAEQAUAAgADMAMwA4ADkAOQAgAFQAQwBQACIAIAAtAEQAaQByAGUAYwB0AGkAbwBuACAASQBuAGIAbwB1AG4AZAAgAC0ATABvAGMAYQBsAFAAbwByAHQAIAAzADMAOAA5ADkAIAAtAFAAcgBvAHQAbwBjAG8AbAAgAFQAQwBQACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwANAAoATgBlAHcALQBOAGUAdABGAGkAcgBlAHcAYQBsAGwAUgB1AGwAZQAgAC0ARABpAHMAcABsAGEAeQBOAGEAbQBlACAAIgBSAEQAUAAgADMAMwA4ADkAOQAgAFUARABQACIAIAAtAEQAaQByAGUAYwB0AGkAbwBuACAASQBuAGIAbwB1AG4AZAAgAC0ATABvAGMAYQBsAFAAbwByAHQAIAAzADMAOAA5ADkAIAAtAFAAcgBvAHQAbwBjAG8AbAAgAFUARABQACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwANAAoAUgBlAHMAdABhAHIAdAAtAFMAZQByAHYAaQBjAGUAIAAtAE4AYQBtAGUAIABUAGUAcgBtAFMAZQByAHYAaQBjAGUAIAAtAEYAbwByAGMAZQANAAoADQAKAE4AZQB3AC0ATgBlAHQARgBpAHIAZQB3AGEAbABsAFIAdQBsAGUAIAAtAEQAaQBzAHAAbABhAHkATgBhAG0AZQAgACcASQBDAE0AUAB2ADQAJwAgAC0ARABpAHIAZQBjAHQAaQBvAG4AIABJAG4AYgBvAHUAbgBkACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwAgAC0AUAByAG8AdABvAGMAbwBsACAAaQBjAG0AcAB2ADQAIAAtAEUAbgBhAGIAbABlAGQAIABUAHIAdQBlAA==' + } + } +} + +resource rtspoke1vms 'Microsoft.Network/routeTables@2022-01-01' = { + name: 'wth-rt-spoke1vmssubnet' + location: location + properties: { + routes: [ + { + name: 'route-all-to-csr' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: '10.0.1.4' + } + } + ] + disableBgpRoutePropagation: false + } +} + +resource nsgspoke1vms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { + name: 'wth-nsg-spoke1vmssubnet' + location: location + properties: { + securityRules: [ + { + name: 'allow-altrdp-to-vmssubnet-from-any' + properties: { + priority: 1000 + access: 'Allow' + direction: 'Inbound' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '33899-33899' + sourceAddressPrefix: '*' + destinationAddressPrefix: '10.1.10.0/24' + } + } + { + name: 'allow-altssh-to-vmssubnet-from-any' + properties: { + priority: 1001 + access: 'Allow' + direction: 'Inbound' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '22222-22222' + sourceAddressPrefix: '*' + destinationAddressPrefix: '10.1.10.0/24' + } + } + ] + } +} diff --git a/057-AzureRouteServer/Coach/Solutions/bicep/01-01-spoke2.bicep b/057-AzureRouteServer/Coach/Solutions/bicep/01-01-spoke2.bicep new file mode 100644 index 0000000000..703c65f899 --- /dev/null +++ b/057-AzureRouteServer/Coach/Solutions/bicep/01-01-spoke2.bicep @@ -0,0 +1,178 @@ +param location string = 'eastus2' +param spoke2VMUsername string = 'admin-wth' +@secure() +param vmPassword string + +targetScope = 'resourceGroup' +//spoke2 resources + +resource wthspoke2vnet 'Microsoft.Network/virtualNetworks@2021-08-01' = { + name: 'wth-vnet-spoke201' + location: location + properties: { + addressSpace: { + addressPrefixes: [ + '10.2.0.0/16' + ] + } + subnets: [ + { + name: 'subnet-spoke2vms' + properties: { + addressPrefix: '10.2.10.0/24' + networkSecurityGroup: { + id: nsgspoke2vms.id + } + routeTable: { + id: rtspoke2vms.id + } + } + } + ] + } +} + +resource wthspoke2vmpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { + name: 'wth-pip-spoke2vm01' + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } +} + +resource wthspoke2vmnic 'Microsoft.Network/networkInterfaces@2022-01-01' = { + name: 'wth-nic-spoke2vm01' + location: location + properties: { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + subnet: { + id: '${wthspoke2vnet.id}/subnets/subnet-spoke2vms' + } + privateIPAddress: '10.2.10.4' + publicIPAddress: { + id: wthspoke2vmpip01.id + } + } + } + ] + } +} + +resource wthspoke2vm01 'Microsoft.Compute/virtualMachines@2022-03-01' = { + name: 'wth-vm-spoke201' + location: location + properties: { + hardwareProfile: { + vmSize: 'Standard_B2s' + } + storageProfile: { + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + osDisk: { + osType: 'Windows' + name: 'wth-disk-vmspoke2os01' + createOption: 'FromImage' + caching: 'ReadWrite' + } + } + osProfile: { + computerName: 'vm-spoke201' + adminUsername: spoke2VMUsername + adminPassword: vmPassword + windowsConfiguration: { + provisionVMAgent: true + enableAutomaticUpdates: true + } + } + networkProfile: { + networkInterfaces: [ + { + id: wthspoke2vmnic.id + } + ] + } + diagnosticsProfile: { + bootDiagnostics: { + enabled: true + } + } + licenseType: 'Windows_Server' + } +} + +resource changerdpport 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' = { + name: '${wthspoke2vm01.name}/wth-vmextn-changerdpport33899' + location: location + properties: { + publisher: 'Microsoft.Compute' + type: 'CustomScriptExtension' + typeHandlerVersion: '1.10' + settings: { + commandToExecute: 'powershell.exe -ep bypass -encodedcommand UwBlAHQALQBJAHQAZQBtAFAAcgBvAHAAZQByAHQAeQAgAC0AUABhAHQAaAAgACIASABLAEwATQA6AFwAUwB5AHMAdABlAG0AXABDAHUAcgByAGUAbgB0AEMAbwBuAHQAcgBvAGwAUwBlAHQAXABDAG8AbgB0AHIAbwBsAFwAVABlAHIAbQBpAG4AYQBsACAAUwBlAHIAdgBlAHIAXABXAGkAbgBTAHQAYQB0AGkAbwBuAHMAXABSAEQAUAAtAFQAYwBwAFwAIgAgAC0ATgBhAG0AZQAgAFAAbwByAHQATgB1AG0AYgBlAHIAIAAtAFYAYQBsAHUAZQAgADMAMwA4ADkAOQANAAoATgBlAHcALQBOAGUAdABGAGkAcgBlAHcAYQBsAGwAUgB1AGwAZQAgAC0ARABpAHMAcABsAGEAeQBOAGEAbQBlACAAIgBSAEQAUAAgADMAMwA4ADkAOQAgAFQAQwBQACIAIAAtAEQAaQByAGUAYwB0AGkAbwBuACAASQBuAGIAbwB1AG4AZAAgAC0ATABvAGMAYQBsAFAAbwByAHQAIAAzADMAOAA5ADkAIAAtAFAAcgBvAHQAbwBjAG8AbAAgAFQAQwBQACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwANAAoATgBlAHcALQBOAGUAdABGAGkAcgBlAHcAYQBsAGwAUgB1AGwAZQAgAC0ARABpAHMAcABsAGEAeQBOAGEAbQBlACAAIgBSAEQAUAAgADMAMwA4ADkAOQAgAFUARABQACIAIAAtAEQAaQByAGUAYwB0AGkAbwBuACAASQBuAGIAbwB1AG4AZAAgAC0ATABvAGMAYQBsAFAAbwByAHQAIAAzADMAOAA5ADkAIAAtAFAAcgBvAHQAbwBjAG8AbAAgAFUARABQACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwANAAoAUgBlAHMAdABhAHIAdAAtAFMAZQByAHYAaQBjAGUAIAAtAE4AYQBtAGUAIABUAGUAcgBtAFMAZQByAHYAaQBjAGUAIAAtAEYAbwByAGMAZQANAAoADQAKAE4AZQB3AC0ATgBlAHQARgBpAHIAZQB3AGEAbABsAFIAdQBsAGUAIAAtAEQAaQBzAHAAbABhAHkATgBhAG0AZQAgACcASQBDAE0AUAB2ADQAJwAgAC0ARABpAHIAZQBjAHQAaQBvAG4AIABJAG4AYgBvAHUAbgBkACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwAgAC0AUAByAG8AdABvAGMAbwBsACAAaQBjAG0AcAB2ADQAIAAtAEUAbgBhAGIAbABlAGQAIABUAHIAdQBlAA==' + } + } +} + +resource rtspoke2vms 'Microsoft.Network/routeTables@2022-01-01' = { + name: 'wth-rt-spoke2vmssubnet' + location: location + properties: { + routes: [ + { + name: 'route-all-to-csr' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: '10.0.1.4' + } + } + ] + disableBgpRoutePropagation: false + } +} + +resource nsgspoke2vms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { + name: 'wth-nsg-spoke2vmssubnet' + location: location + properties: { + securityRules: [ + { + name: 'allow-altrdp-to-vmssubnet-from-any' + properties: { + priority: 1000 + access: 'Allow' + direction: 'Inbound' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '33899-33899' + sourceAddressPrefix: '*' + destinationAddressPrefix: '10.2.10.0/24' + } + } + { + name: 'allow-altssh-to-vmssubnet-from-any' + properties: { + priority: 1001 + access: 'Allow' + direction: 'Inbound' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '22222-22222' + sourceAddressPrefix: '*' + destinationAddressPrefix: '10.2.10.0/24' + } + } + ] + } +} diff --git a/057-AzureRouteServer/Coach/Solutions/bicep/01-02-vnetpeeringhub.bicep b/057-AzureRouteServer/Coach/Solutions/bicep/01-02-vnetpeeringhub.bicep new file mode 100644 index 0000000000..cc274cc671 --- /dev/null +++ b/057-AzureRouteServer/Coach/Solutions/bicep/01-02-vnetpeeringhub.bicep @@ -0,0 +1,40 @@ +resource hubvnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { + name: 'wth-vnet-hub01' + scope: resourceGroup('wth-rg-hub') +} + +resource spoke1vnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { + name: 'wth-vnet-spoke101' + scope: resourceGroup('wth-rg-spoke1') +} + +resource spoke2vnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { + name: 'wth-vnet-spoke201' + scope: resourceGroup('wth-rg-spoke2') +} + +resource hubtospoke1 'Microsoft.Network/virtualNetworks/virtualNetworkPeerings@2022-01-01' = { + name: '${hubvnet.name}/wth-peering-hubtospoke1' + properties: { + allowGatewayTransit: true + allowForwardedTraffic: true + allowVirtualNetworkAccess: true + useRemoteGateways: false + remoteVirtualNetwork: { + id: spoke1vnet.id + } + } +} + +resource hubtospoke2 'Microsoft.Network/virtualNetworks/virtualNetworkPeerings@2022-01-01' = { + name: '${hubvnet.name}/wth-peering-hubtospoke2' + properties: { + allowGatewayTransit: true + allowForwardedTraffic: true + allowVirtualNetworkAccess: true + useRemoteGateways: false + remoteVirtualNetwork: { + id: spoke2vnet.id + } + } +} diff --git a/057-AzureRouteServer/Coach/Solutions/bicep/01-02-vnetpeeringspoke1.bicep b/057-AzureRouteServer/Coach/Solutions/bicep/01-02-vnetpeeringspoke1.bicep new file mode 100644 index 0000000000..3742abe6d8 --- /dev/null +++ b/057-AzureRouteServer/Coach/Solutions/bicep/01-02-vnetpeeringspoke1.bicep @@ -0,0 +1,22 @@ +resource hubvnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { + name: 'wth-vnet-hub01' + scope: resourceGroup('wth-rg-hub') +} + +resource spoke1vnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { + name: 'wth-vnet-spoke101' + scope: resourceGroup('wth-rg-spoke1') +} + +resource spoke1tohub 'Microsoft.Network/virtualNetworks/virtualNetworkPeerings@2022-01-01' = { + name: '${spoke1vnet.name}/wth-peering-spoke1tohub' + properties: { + allowGatewayTransit: false + allowForwardedTraffic: false + allowVirtualNetworkAccess: true + useRemoteGateways: true + remoteVirtualNetwork: { + id: hubvnet.id + } + } +} diff --git a/057-AzureRouteServer/Coach/Solutions/bicep/01-02-vnetpeeringspoke2.bicep b/057-AzureRouteServer/Coach/Solutions/bicep/01-02-vnetpeeringspoke2.bicep new file mode 100644 index 0000000000..41216b73a6 --- /dev/null +++ b/057-AzureRouteServer/Coach/Solutions/bicep/01-02-vnetpeeringspoke2.bicep @@ -0,0 +1,22 @@ +resource hubvnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { + name: 'wth-vnet-hub01' + scope: resourceGroup('wth-rg-hub') +} + +resource spoke2vnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { + name: 'wth-vnet-spoke201' + scope: resourceGroup('wth-rg-spoke2') +} + +resource spoke2tohub 'Microsoft.Network/virtualNetworks/virtualNetworkPeerings@2022-01-01' = { + name: '${spoke2vnet.name}/wth-peering-spoke1tohub' + properties: { + allowGatewayTransit: false + allowForwardedTraffic: false + allowVirtualNetworkAccess: true + useRemoteGateways: true + remoteVirtualNetwork: { + id: hubvnet.id + } + } +} diff --git a/057-AzureRouteServer/Coach/Solutions/bicep/01-03-onprem.bicep b/057-AzureRouteServer/Coach/Solutions/bicep/01-03-onprem.bicep new file mode 100644 index 0000000000..64464639fe --- /dev/null +++ b/057-AzureRouteServer/Coach/Solutions/bicep/01-03-onprem.bicep @@ -0,0 +1,321 @@ +param location string = 'eastus2' +param onpremVMUsername string = 'admin-wth' +@secure() +param vmPassword string + +targetScope = 'resourceGroup' +//onprem resources + +resource hubvnet 'Microsoft.Network/virtualNetworks@2022-07-01' existing = { + name: 'wth-vnet-hub01' + scope: resourceGroup('wth-rg-hub') + + resource gwsubnet 'subnets' existing = { + name: 'GatewaySubnet' + } +} + +resource wthonpremvnet 'Microsoft.Network/virtualNetworks@2021-08-01' = { + name: 'wth-vnet-onprem01' + location: location + properties: { + addressSpace: { + addressPrefixes: [ + '172.16.0.0/16' + ] + } + subnets: [ + { + name: 'subnet-vpn' + properties: { + addressPrefix: '172.16.0.0/24' + networkSecurityGroup: { + id: nsgonpremvpn.id + } + } + } + { + name: 'subnet-onpremvms' + properties: { + addressPrefix: '172.16.10.0/24' + networkSecurityGroup: { + id: nsgonpremvms.id + } + routeTable: { + id: rtonpremvms.id + } + } + } + ] + } +} + +resource wthonpremvmpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { + name: 'wth-pip-onpremvm01' + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } +} + +resource wthonpremvmnic 'Microsoft.Network/networkInterfaces@2022-01-01' = { + name: 'wth-nic-onpremvm01' + location: location + properties: { + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + subnet: { + id: '${wthonpremvnet.id}/subnets/subnet-onpremvms' + } + privateIPAddress: '172.16.10.4' + publicIPAddress: { + id: wthonpremvmpip01.id + } + } + } + ] + } +} + +resource wthonpremvm01 'Microsoft.Compute/virtualMachines@2022-03-01' = { + name: 'wth-vm-onprem01' + location: location + properties: { + hardwareProfile: { + vmSize: 'Standard_B2s' + } + storageProfile: { + imageReference: { + publisher: 'MicrosoftWindowsServer' + offer: 'WindowsServer' + sku: '2022-datacenter-azure-edition' + version: 'latest' + } + osDisk: { + osType: 'Windows' + name: 'wth-disk-vmonpremos01' + createOption: 'FromImage' + caching: 'ReadWrite' + } + } + osProfile: { + computerName: 'vm-onprem01' + adminUsername: onpremVMUsername + adminPassword: vmPassword + windowsConfiguration: { + provisionVMAgent: true + enableAutomaticUpdates: true + } + } + networkProfile: { + networkInterfaces: [ + { + id: wthonpremvmnic.id + } + ] + } + diagnosticsProfile: { + bootDiagnostics: { + enabled: true + } + } + licenseType: 'Windows_Server' + } +} + +resource changerdpport 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' = { + name: '${wthonpremvm01.name}/wth-vmextn-changerdpport33899' + location: location + properties: { + publisher: 'Microsoft.Compute' + type: 'CustomScriptExtension' + typeHandlerVersion: '1.10' + settings: { + commandToExecute: 'powershell.exe -ep bypass -encodedcommand UwBlAHQALQBJAHQAZQBtAFAAcgBvAHAAZQByAHQAeQAgAC0AUABhAHQAaAAgACIASABLAEwATQA6AFwAUwB5AHMAdABlAG0AXABDAHUAcgByAGUAbgB0AEMAbwBuAHQAcgBvAGwAUwBlAHQAXABDAG8AbgB0AHIAbwBsAFwAVABlAHIAbQBpAG4AYQBsACAAUwBlAHIAdgBlAHIAXABXAGkAbgBTAHQAYQB0AGkAbwBuAHMAXABSAEQAUAAtAFQAYwBwAFwAIgAgAC0ATgBhAG0AZQAgAFAAbwByAHQATgB1AG0AYgBlAHIAIAAtAFYAYQBsAHUAZQAgADMAMwA4ADkAOQANAAoATgBlAHcALQBOAGUAdABGAGkAcgBlAHcAYQBsAGwAUgB1AGwAZQAgAC0ARABpAHMAcABsAGEAeQBOAGEAbQBlACAAIgBSAEQAUAAgADMAMwA4ADkAOQAgAFQAQwBQACIAIAAtAEQAaQByAGUAYwB0AGkAbwBuACAASQBuAGIAbwB1AG4AZAAgAC0ATABvAGMAYQBsAFAAbwByAHQAIAAzADMAOAA5ADkAIAAtAFAAcgBvAHQAbwBjAG8AbAAgAFQAQwBQACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwANAAoATgBlAHcALQBOAGUAdABGAGkAcgBlAHcAYQBsAGwAUgB1AGwAZQAgAC0ARABpAHMAcABsAGEAeQBOAGEAbQBlACAAIgBSAEQAUAAgADMAMwA4ADkAOQAgAFUARABQACIAIAAtAEQAaQByAGUAYwB0AGkAbwBuACAASQBuAGIAbwB1AG4AZAAgAC0ATABvAGMAYQBsAFAAbwByAHQAIAAzADMAOAA5ADkAIAAtAFAAcgBvAHQAbwBjAG8AbAAgAFUARABQACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwANAAoAUgBlAHMAdABhAHIAdAAtAFMAZQByAHYAaQBjAGUAIAAtAE4AYQBtAGUAIABUAGUAcgBtAFMAZQByAHYAaQBjAGUAIAAtAEYAbwByAGMAZQANAAoADQAKAE4AZQB3AC0ATgBlAHQARgBpAHIAZQB3AGEAbABsAFIAdQBsAGUAIAAtAEQAaQBzAHAAbABhAHkATgBhAG0AZQAgACcASQBDAE0AUAB2ADQAJwAgAC0ARABpAHIAZQBjAHQAaQBvAG4AIABJAG4AYgBvAHUAbgBkACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwAgAC0AUAByAG8AdABvAGMAbwBsACAAaQBjAG0AcAB2ADQAIAAtAEUAbgBhAGIAbABlAGQAIABUAHIAdQBlAA==' + } + } +} + +resource rtonpremvms 'Microsoft.Network/routeTables@2022-01-01' = { + name: 'wth-rt-onpremvmssubnet' + location: location + properties: { + routes: [ + { + name: 'route-hub' + properties: { + addressPrefix: '10.0.0.0/16' + nextHopIpAddress: '172.16.0.4' + nextHopType: 'VirtualAppliance' + } + } + { + name: 'route-spoke1' + properties: { + addressPrefix: '10.1.0.0/16' + nextHopIpAddress: '172.16.0.4' + nextHopType: 'VirtualAppliance' + } + } + { + name: 'route-spoke2' + properties: { + addressPrefix: '10.2.0.0/16' + nextHopIpAddress: '172.16.0.4' + nextHopType: 'VirtualAppliance' + } + } + ] + disableBgpRoutePropagation: false + } +} + +resource nsgonpremvms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { + name: 'wth-nsg-onpremvmssubnet' + location: location + properties: { + securityRules: [ + { + name: 'allow-altrdp-to-vmssubnet-from-any' + properties: { + priority: 1000 + access: 'Allow' + direction: 'Inbound' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '33899-33899' + sourceAddressPrefix: '*' + destinationAddressPrefix: '172.16.10.0/24' + } + } + { + name: 'allow-altssh-to-vmssubnet-from-any' + properties: { + priority: 1001 + access: 'Allow' + direction: 'Inbound' + protocol: 'Tcp' + sourcePortRange: '*' + destinationPortRange: '22222-22222' + sourceAddressPrefix: '*' + destinationAddressPrefix: '172.16.10.0/24' + } + } + ] + } +} + +resource nsgonpremvpn 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { + name: 'wth-nsg-onpremvpnsubnet' + location: location + properties: { + securityRules: [ + { + name: 'allow-any-to-vpnsubnet-from-onprem' + properties: { + priority: 1000 + access: 'Allow' + direction: 'Inbound' + protocol: '*' + sourcePortRange: '*' + destinationPortRange: '*' + sourceAddressPrefix: '172.16.10.0/24' + destinationAddressPrefix: '*' + } + } + { + name: 'allow-any-to-any-from-azurevpngw' + properties: { + priority: 1001 + access: 'Allow' + direction: 'Inbound' + protocol: '*' + sourcePortRange: '*' + destinationPortRange: '*' + sourceAddressPrefix: hubvnet::gwsubnet.properties.addressPrefix + destinationAddressPrefix: '*' + } + } + ] + } +} + +resource wthonpremcsrpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { + name: 'wth-pip-csr01' + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } +} + +resource wthonpremcsrnic 'Microsoft.Network/networkInterfaces@2022-01-01' = { + name: 'wth-nic-csr01' + location: location + properties: { + enableIPForwarding: true + ipConfigurations: [ + { + name: 'ipconfig1' + properties: { + subnet: { + id: '${wthonpremvnet.id}/subnets/subnet-vpn' + } + privateIPAddress: '172.16.0.4' + publicIPAddress: { + id: wthonpremcsrpip01.id + } + } + } + ] + } +} + +resource ciscocsr 'Microsoft.Compute/virtualMachines@2022-03-01' = { + name: 'wth-vm-ciscocsr01' + location: location + plan: { + publisher: 'cisco' + product: 'cisco-csr-1000v' + name: '16_12-byol' + } + properties: { + hardwareProfile: { + vmSize: 'Standard_B2ms' + } + storageProfile: { + imageReference: { + publisher: 'cisco' + offer: 'cisco-csr-1000v' + sku: '16_12-byol' + version: 'latest' + } + osDisk: { + osType: 'Linux' + createOption: 'FromImage' + } + } + networkProfile: { + networkInterfaces: [ + { + id: wthonpremcsrnic.id + } + ] + } + osProfile: { + adminUsername: onpremVMUsername + adminPassword: vmPassword + computerName: 'wthcsr01' + customData: loadFileAsBase64('./csrScript.txt.tmp') + } + } +} diff --git a/057-AzureRouteServer/Coach/Solutions/bicep/01-04-hubvpnconfig.bicep b/057-AzureRouteServer/Coach/Solutions/bicep/01-04-hubvpnconfig.bicep new file mode 100644 index 0000000000..11883fa563 --- /dev/null +++ b/057-AzureRouteServer/Coach/Solutions/bicep/01-04-hubvpnconfig.bicep @@ -0,0 +1,48 @@ +param location string = 'eastus2' + +resource onpremcsrpip 'Microsoft.Network/publicIPAddresses@2022-01-01' existing = { + name: 'wth-pip-csr01' + scope: resourceGroup('wth-rg-onprem') +} + +resource onpremcsrnic 'Microsoft.Network/networkInterfaces@2022-01-01' existing = { + name: 'wth-nic-csr01' + scope: resourceGroup('wth-rg-onprem') +} + +resource wthhubvnetgw 'Microsoft.Network/virtualNetworkGateways@2022-01-01' existing = { + name: 'wth-vngw-hub01' + scope: resourceGroup('wth-rg-hub') +} + +resource wthhublocalgw 'Microsoft.Network/localNetworkGateways@2022-01-01' = { + name: 'wth-lgw-onprem01' + location: location + properties: { + gatewayIpAddress: onpremcsrpip.properties.ipAddress + localNetworkAddressSpace: { + addressPrefixes: [] + } + bgpSettings: { + bgpPeeringAddress: onpremcsrnic.properties.ipConfigurations[0].properties.privateIPAddress + asn: 65510 + } + } +} + +resource wthhubconnection 'Microsoft.Network/connections@2022-01-01' = { + name: 'wth-cxn-vpn01' + location: location + properties: { + sharedKey: '123mysecretkey' + connectionType: 'IPsec' + connectionMode: 'Default' + enableBgp: true + localNetworkGateway2: { + id: wthhublocalgw.id + } + virtualNetworkGateway1: { + id: wthhubvnetgw.id + } + } +} diff --git a/057-AzureRouteServer/Coach/Solutions/bicep/01-05-csrnva.bicep b/057-AzureRouteServer/Coach/Solutions/bicep/01-05-csrnva.bicep new file mode 100644 index 0000000000..a0e600b6c2 --- /dev/null +++ b/057-AzureRouteServer/Coach/Solutions/bicep/01-05-csrnva.bicep @@ -0,0 +1,180 @@ +param location string = 'eastus2' +param vmusername string = 'admin-wth' +@secure() +param vmPassword string + +resource hubvnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { + name: 'wth-vnet-hub01' + scope: resourceGroup('wth-rg-hub') +} + +resource nvaoutsidesubnet 'Microsoft.Network/virtualNetworks/subnets@2022-01-01' = { + name: '${hubvnet.name}/nvaoutsidesubnet' + properties: { + addressPrefix: '10.0.2.0/24' + } +} + +resource nvainsidesidesubnet 'Microsoft.Network/virtualNetworks/subnets@2022-01-01' = { + dependsOn: [ + nvaoutsidesubnet + ] + name: '${hubvnet.name}/nvainsidesidesubnet' + properties: { + addressPrefix: '10.0.1.0/24' + } +} + +resource wthcsrpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { + name: 'wth-pip-afw01' + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } +} + +resource wthcsroutsidenic 'Microsoft.Network/networkInterfaces@2022-07-01' = { + name: 'wth-nic-nvaoutside' + location: location + properties: { + ipConfigurations: [ + { + name: 'ipconfigOutside' + properties: { + subnet: { + id: nvaoutsidesubnet.id + } + privateIPAllocationMethod: 'Static' + privateIPAddress: '10.0.2.4' + publicIPAddress: { + id: wthcsrpip01.id + } + } + } + ] + } +} + +resource wthcsrinsidenic 'Microsoft.Network/networkInterfaces@2022-07-01' = { + name: 'wth-nic-nvainside' + location: location + properties: { + ipConfigurations: [ + { + name: 'ipconfigInside' + properties: { + subnet: { + id: nvainsidesidesubnet.id + } + privateIPAllocationMethod: 'Static' + privateIPAddress: '10.0.1.4' + } + } + ] + } +} + +resource ciscocsr 'Microsoft.Compute/virtualMachines@2022-03-01' = { + name: 'wth-vm-ciscocsr01' + location: location + plan: { + publisher: 'cisco' + product: 'cisco-csr-1000v' + name: '16_12-byol' + } + properties: { + hardwareProfile: { + vmSize: 'Standard_B2ms' + } + storageProfile: { + imageReference: { + publisher: 'cisco' + offer: 'cisco-csr-1000v' + sku: '16_12-byol' + version: 'latest' + } + osDisk: { + osType: 'Linux' + createOption: 'FromImage' + } + } + networkProfile: { + networkInterfaces: [ + { + id: wthcsroutsidenic.id + properties: { + primary: true + } + } + { + id: wthcsrinsidenic.id + properties: { + primary: false + } + } + ] + } + osProfile: { + adminUsername: vmusername + adminPassword: vmPassword + computerName: 'wthcsrnva01' + customData: loadFileAsBase64('./csrScriptNVA.txt') + } + } +} + +resource rthubvms 'Microsoft.Network/routeTables@2022-01-01' = { + name: 'wth-rt-hubvmssubnet' + location: location + properties: { + routes: [ + { + name: 'route-all-to-nva' + properties: { + addressPrefix: '0.0.0.0/0' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: wthcsrinsidenic.properties.ipConfigurations[0].properties.privateIPAddress + } + } + ] + disableBgpRoutePropagation: false + } +} + +resource rtvnetgw 'Microsoft.Network/routeTables@2022-01-01' = { + name: 'wth-rt-hubgwsubnet' + location: location + properties: { + routes: [ + { + name: 'route-spoke1-to-nva' + properties: { + addressPrefix: '10.1.0.0/16' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: wthcsrinsidenic.properties.ipConfigurations[0].properties.privateIPAddress + } + } + { + name: 'route-spoke2-to-nva' + properties: { + addressPrefix: '10.2.0.0/16' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: wthcsrinsidenic.properties.ipConfigurations[0].properties.privateIPAddress + } + } + { + name: 'route-hubvm-to-nva' + properties: { + addressPrefix: '10.0.10.0/24' + nextHopType: 'VirtualAppliance' + nextHopIpAddress: wthcsrinsidenic.properties.ipConfigurations[0].properties.privateIPAddress + } + } + ] + disableBgpRoutePropagation: false + } +} diff --git a/057-AzureRouteServer/Coach/Solutions/bicep/README.md b/057-AzureRouteServer/Coach/Solutions/bicep/README.md new file mode 100644 index 0000000000..18564f7892 --- /dev/null +++ b/057-AzureRouteServer/Coach/Solutions/bicep/README.md @@ -0,0 +1,122 @@ +# What the Hack Networking Bicep Deployment + +This directory contains Bicep templates to deploy and configure resources as described in each WTH Networking challenge. These deployments represent one way to meet the challenge requirements--there are many others. + +## Who should use these templates? + +The WTH philosophy intends to have students learn by doing, and recognizes that one of the best ways to learn is to troubleshoot problems. As such, using these templates instead of building your own lab will detract from your learning experience, and primarily recommended for the scenarios below: + +- Students who will not be completing a challenge which is a prerequisite to a later challenge +- Students who are falling behind in the WTH due to issues unrelated to the core learning goals of this WTH +- Students looking for a reference implementation to compare against their own approach +- Coaches looking to deploy a reference architecture to the lab + +## Using these templates + +Using Cloud Shell is recommended, as it already has the necessary tools installed. However, Cloud Shell has a timeout of about 20 minutes and may experience timeouts (in which case, run the same command again to pick up the deployments where they stopped). + +**Challenges are meant to be deployed sequentially, as the infrastructure builds on itself.** For example, to work with the Challenge 5 infrastructure, deploy Challenges 1-4 first. Also, keep in mind that changes made for testing need to be manually reverted, unless the relevant Challenge and subsequent Challenges are redeployed. + +### Prerequisites + +- Azure PowerShell module +- git + +### Download Options + +#### Clone the Git repo (slow) + +1. Clone this repo to your local system or Cloud Shell + `git clone https://github.com/microsoft/WhatTheHack.git` +1. Navigate to the `035-HubAndSpoke\Student\Resources\bicep` directory in your clone of the repo +1. Run the deploy.ps1 script. For example: + `./deploy.ps1 -challengeNumber 1` + +#### Download a zip of the bicep directory + +1. Browse to https://download-directory.github.io/?url=https%3A%2F%2Fgithub.com%2Fmicrosoft%2FWhatTheHack%2Ftree%2Fnetwork-bicep%2F035-HubAndSpoke%2FStudent%2FResources%2Fbicep +1. A zip of the directory will download to your system +1. Expand the downloaded zip file and navigate to it in a PowerShell window +1. Run the deploy.ps1 script. For example: + `./deploy.ps1 -challengeNumber 1` + +## Deployed Configuration + +### Challenge 1 + +- Windows VMs are deployed in the hub, both spokes, and on-prem Resource Groups +- VM usernames are 'admin-wth' and passwords are the one supplied when executing the script +- Windows VM firewalls have been modified to allow Ping traffic +- All Windows VMs have associated Public IP Addresses and are accessible via RDP using alternate port 33899 (ex: `mstsc /v:4.32.1.5:33899`) +- The Cisco CSR deployed in the 'wth-rg-onprem' Resource Group uses the same username and password, but is not accessible from the internet. To access it, RDP to the Windows VM in the onprem Resource Group, then connect to the CSR using ssh and its private IP address + +### Challenge 2 + +- With Azure Firewall deployed and traffic routing through it following the Challenge, the Windows VMs are no longer directly accessible via Public IP. Use the Azure Firewall public IP with the following DNAT port mapping: + - Hub: 33980 + - Spoke 1: 33891 + - Spoke 2: 33892 + - On-prem (still accessible by Public IP and custom 33899 RDP port) + +- All Windows VMs have a diagnostic website configured in IIS called Inspector Gadget. To access it locally, browse to `http://localhost/default.aspx`. Web server DNAT through the Azure Firewall uses the following port mapping: + + - Hub: 8080 + - Spoke 1: 8081 + - Spoke 2: 8082 + +### Challenge 3 + +- The routing tables are adjusted to match the Challenge documentation. To correct the inital deployment, run `deploy.ps1 -challengeNumber 3 -correctedConfiguration` + +### Challenge 4 + +An Application Gateway is deployed matching the Challenge requirements. The deployment automates the configuration of a TLS certificate and DNS records when appropriate RFC 2136 credentials are supplied (the default configuration). The deployment options are: + +1. Automated: Have automation handle DNS records and TLS certificates for you -- this requires registering for a DNS name, for example, from https://dynv6.com. +1. Manually configured: If you have an existing domain name and TLS certificates, you can manually upload the PFX certificate file to the Key Vault prior to deploying the App GW. +1. Automated, with self-signed certificate: If there are issues generating the publicly trusted TLS certificate from Let's Encrypt, a self-signed certificate can be used. + +For details on these options and troubleshooting, see: [Application Gateway DNS and Certificates](./appGWCertificateProcess.md) + +The application gateway is configured with backend pools for the Spoke 1 and Spoke 2 VMs. + +### Challenge 5 + +The required Azure SQL and App Service resources are deployed, along with their supporting Private Link infrastructure. An Azure Private DNS Resolver is deployed to enable Private Endpoint name resolution for the 'on-prem' resources. + +The 'Inspector Gadget' utility is installed on the Web App, which is publicly accessible. It includes functions to verify DNS name resolution and test SQL connectivity, though you may want to take the additional step of [granting your App Service MSI access to the SQL database](https://learn.microsoft.com/azure/active-directory/managed-identities-azure-resources/tutorial-windows-vm-access-sql). + +Resources deployed: + +- Azure SQL Servers and DBs in Spoke 1 and Spoke 1 +- Web App in Spoke 1 +- Private DNS Resolver in Hub +- Private Endpoints for SQL servers and App Service +- Private DNS Zones for Private Endpoint records +- Subnets for new services (App Service, DNS Resolver, SQL Private Endpoints) +- NSGs for new subnets +- Route table and routes to force Spoke 1 SQL traffic through the Azure Firewall (advanced scenario) + +## Resource Cleanup + +To cleanup this deployment, delete each create resource group. To do this programmatically with PowerShell, run: + +```powershell + $jobs = @() + $jobs += Remove-AzResourceGroup -Name 'wth-rg-hub' -Force -AsJob + $jobs += Remove-AzResourceGroup -Name 'wth-rg-spoke1' -Force -AsJob + $jobs += Remove-AzResourceGroup -Name 'wth-rg-spoke2' -Force -AsJob + $jobs += Remove-AzResourceGroup -Name 'wth-rg-onprem' -Force -AsJob + + Write-Host "Waiting for all resource group cleanup jobs to complete..." + $jobs | Wait-Job + + $jobs | Foreach-Object { + $job = $_ + If ($job.Error) { + Write-Error "A cleanup task experienced an error: $($job.error)" + } + } + + Write-Host "Cleanup task completed." +``` diff --git a/057-AzureRouteServer/Coach/Solutions/bicep/csrScript.txt b/057-AzureRouteServer/Coach/Solutions/bicep/csrScript.txt new file mode 100644 index 0000000000..553bcaa0d3 --- /dev/null +++ b/057-AzureRouteServer/Coach/Solutions/bicep/csrScript.txt @@ -0,0 +1,85 @@ +Section: IOS configuration +ip ssh port 2222 rotary 1 +! +line vty 0 15 + rotary 1 + exit +! +crypto ikev2 proposal azure-proposal + encryption aes-cbc-256 aes-cbc-128 3des + integrity sha1 + group 2 + exit +! +crypto ikev2 policy azure-policy + proposal azure-proposal + exit +! +crypto ikev2 keyring azure-keyring + peer **GW0_Public_IP** + address **GW0_Public_IP** + pre-shared-key 123mysecretkey + exit + peer **GW1_Public_IP** + address **GW1_Public_IP** + pre-shared-key 123mysecretkey + exit + exit +! +crypto ikev2 profile azure-profile + match address local interface GigabitEthernet1 + match identity remote address **GW0_Public_IP** 255.255.255.255 + match identity remote address **GW1_Public_IP** 255.255.255.255 + authentication remote pre-share + authentication local pre-share + keyring local azure-keyring + exit +! +crypto ipsec transform-set azure-ipsec-proposal-set esp-aes 256 esp-sha-hmac + mode tunnel + exit + +crypto ipsec profile azure-vti + set transform-set azure-ipsec-proposal-set + set ikev2-profile azure-profile + set security-association lifetime kilobytes 102400000 + set security-association lifetime seconds 3600 + exit +! +interface Tunnel0 + ip unnumbered GigabitEthernet1 + ip tcp adjust-mss 1350 + tunnel source GigabitEthernet1 + tunnel mode ipsec ipv4 + tunnel destination **GW0_Public_IP** + tunnel protection ipsec profile azure-vti +exit +! +interface Tunnel1 + ip unnumbered GigabitEthernet1 + ip tcp adjust-mss 1350 + tunnel source GigabitEthernet1 + tunnel mode ipsec ipv4 + tunnel destination **GW1_Public_IP** + tunnel protection ipsec profile azure-vti +exit + +! +router bgp 65510 + bgp router-id interface GigabitEthernet1 + bgp log-neighbor-changes + redistribute connected + neighbor **GW0_Private_IP** remote-as **VNETGWASN** + neighbor **GW0_Private_IP** ebgp-multihop 5 + neighbor **GW0_Private_IP** update-source GigabitEthernet1 + neighbor **GW1_Private_IP** remote-as **VNETGWASN** + neighbor **GW1_Private_IP** ebgp-multihop 5 + neighbor **GW1_Private_IP** update-source GigabitEthernet1 + maximum-paths eibgp 4 +! +ip route **GW0_Private_IP** 255.255.255.255 Tunnel0 +ip route **GW1_Private_IP** 255.255.255.255 Tunnel1 +! +end +! +wr mem diff --git a/057-AzureRouteServer/Coach/Solutions/bicep/csrScriptNVA.txt b/057-AzureRouteServer/Coach/Solutions/bicep/csrScriptNVA.txt new file mode 100644 index 0000000000..84172effa3 --- /dev/null +++ b/057-AzureRouteServer/Coach/Solutions/bicep/csrScriptNVA.txt @@ -0,0 +1,12 @@ +Section: IOS configuration +ip ssh port 2222 rotary 1 +! +line vty 0 15 + rotary 1 + exit +! +ip route 172.16.0.0 255.255.0.0 10.0.2.1 +ip route 10.1.0.0 255.255.0.0 10.0.1.1 +ip route 10.2.0.0 255.255.0.0 10.0.1.1 +! +wr mem \ No newline at end of file diff --git a/057-AzureRouteServer/Coach/Solutions/bicep/deploy.ps1 b/057-AzureRouteServer/Coach/Solutions/bicep/deploy.ps1 new file mode 100644 index 0000000000..a50eaa2758 --- /dev/null +++ b/057-AzureRouteServer/Coach/Solutions/bicep/deploy.ps1 @@ -0,0 +1,188 @@ +<# +.SYNOPSIS +.DESCRIPTION + Deploys or configures WTH Networking challenge resources. +.EXAMPLE + ./deploy.ps1 -challengeNumber 1 + Deploy all resource groups and resources for Challenge 1. Script will prompt for a password, which will be used across all VMs. +#> +[CmdletBinding()] +param ( + # challenge number to deploy + [Parameter(Mandatory = $true, HelpMessage = 'Enter the WTH hub and spoke challenge number (1-6)')] + [ValidateRange(1, 6)] + [int] + $challengeNumber, + + <# + # TODO: deploy fully configured lab or leave some configuration to be done + [Parameter(Mandatory = $false, HelpMessage = 'Deploy all challenge resources fully configured or partially configured (for learning!)')] + [ValidateSet('FullyConfigured', 'PartiallyConfigured')] + [string] + $deploymentType = 'FullyConfigured', + #> + + # resource deployment Azure region, defaults to 'eastus2' + [Parameter(Mandatory = $false)] + [string] + $location = 'EastUS2', + + # Parameter help description + [Parameter(Mandatory = $false)] + [SecureString] + $vmPassword, + + # include to correct intentionally misconfigured resources (deployed as part of the challenge) + [Parameter(Mandatory = $false)] + [switch] + $correctedConfiguration, + + # confirm subscription and resource types + [Parameter(Mandatory=$false)] + [System.Boolean] + $confirm = $true, + + # challenge parameters + [parameter(Mandatory = $false)] + [hashtable] + $challengeParameters = @{} +) + +$ErrorActionPreference = 'Stop' + +If (-NOT (Test-Path ./01-resourceGroups.bicep)) { + + Write-Warning "This script need to be executed from the directory containing the bicep files. Attempting to set location to script location." + + try { + $scriptPath = ($MyInvocation.MyCommand.Path | Split-Path -Parent -ErrorAction Stop) + Push-Location -Path $scriptPath -ErrorAction Stop + } + catch { + throw "Failed to set path to bicep file location. Use the 'cd' command to change the current directory to the same location as the WTH bicep files before executing this script." + } +} + +If ( -NOT ($azContext = Get-AzContext)) { + throw "Run 'Connect-AzAccount' before executing this script!" +} +ElseIf ($confirm) { + do { $response = (Read-Host "Resources will be created in subscription '$($azContext.Subscription.Name)' in region '$location'. If this is not the correct subscription, use 'Select-AzSubscription' before running this script and specify an alternate location with the -Location parameter. Proceed? (y/n)") } + until ($response -match '[nNYy]') + + If ($response -match 'nN') { exit } +} + +switch ($challengeNumber) { + 1 { + Write-Host "Deploying resources for Challenge 1: Hub-and-spoke Basics" + + If (-NOT ($vmPassword)) { + $vmPassword = Read-Host "Enter (and make note of) a complex password which will be used for all deployed VMs (username will be 'admin-wth')" -AsSecureString + } + + Write-Host "`tDeploying resource groups..." + New-AzDeployment -Location $location -Name "01-00-resourceGroups_$location" -TemplateFile ./01-00-resourceGroups.bicep | Out-Null + + Write-Host "`tDeploying base resources (this will take up to 60 minutes for the VNET Gateway)..." + $baseInfraJobs = @{} + $baseInfraJobs += @{'wth-rg-spoke1' = (New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./01-01-spoke1.bicep -TemplateParameterObject @{vmPassword = $vmPassword; location = $location } -AsJob)} + $baseInfraJobs += @{'wth-rg-spoke2' = (New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./01-01-spoke2.bicep -TemplateParameterObject @{vmPassword = $vmPassword; location = $location } -AsJob)} + $baseInfraJobs += @{'wth-rg-hub' = (New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./01-01-hub.bicep -TemplateParameterObject @{vmPassword = $vmPassword; location = $location } -AsJob)} + + Write-Host "`tWaiting up to 60 minutes for resources to deploy..." + $baseInfraJobs.GetEnumerator().ForEach({$_.Value}) | Wait-Job -Timeout 3600 | Out-Null + + # check for deployment errors + $baseInfraJobs.GetEnumerator().ForEach({$_.Value}) | Foreach-Object { + $job = $_ | Get-Job + If ($job.Error) { + Write-Error "A deployment experienced an error: $($job.error)" + } + } + + $gw1pip = $baseInfraJobs.'wth-rg-hub'.Output.Outputs.pipgw1.Value + $gw2pip = $baseInfraJobs.'wth-rg-hub'.Output.Outputs.pipgw2.Value + $gwasn = $baseInfraJobs.'wth-rg-hub'.Output.Outputs.wthhubvnetgwasn.Value + $gw1privateip = $baseInfraJobs.'wth-rg-hub'.Output.Outputs.wthhubvnetgwprivateip1.Value + $gw2privateip = $baseInfraJobs.'wth-rg-hub'.Output.Outputs.wthhubvnetgwprivateip2.Value + + Write-Host "`tDeploying VNET Peering..." + $peeringJobs = @() + $peeringJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./01-02-vnetpeeringhub.bicep -TemplateParameterObject @{} -AsJob + $peeringJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./01-02-vnetpeeringspoke1.bicep -TemplateParameterObject @{} -AsJob + $peeringJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./01-02-vnetpeeringspoke2.bicep -TemplateParameterObject @{} -AsJob + + $peeringJobs | Wait-Job -Timeout 300 | Out-Null + + # check for deployment errors + $peeringJobs | Foreach-Object { + $job = $_ + If ($job.Error) { + Write-Error "A VNET peering deployment experienced an error: $($job.error)" + } + } + + Write-Host "`tDeploying 'onprem' infra" + + #accept csr marketplace terms + try { + If (-Not (Get-AzMarketplaceTerms -Publisher 'cisco' -Product 'cisco-csr-1000v' -Name '16_12-byol').Accepted) { + Write-Host "`t`tAccepting Cisco CSR marketplace terms for this subscription..." + Set-AzMarketplaceTerms -Publisher 'cisco' -Product 'cisco-csr-1000v' -Name '16_12-byol' -Accept | Out-Null + } + } + catch { + throw "An error occured while attempting to accept the markeplace terms for the Cisco CSR deployment. Try running `Set-AzMarketplaceTerms -Publisher 'cisco' -Product 'cisco-csr-1000v' -Name '16_12-byol' -Accept` in Cloud Shell for the target subscription. Error: $_" + } + #update csr bootstrap file + $csrConfigContent = Get-Content -Path .\csrScript.txt + $updatedCsrConfigContent = $csrConfigContent + $updatedCsrConfigContent = $updatedCsrConfigContent.Replace('**GW0_Public_IP**',$gw1pip) + $updatedCsrConfigContent = $updatedCsrConfigContent.Replace('**GW1_Public_IP**',$gw2pip) + $updatedCsrConfigContent = $updatedCsrConfigContent.Replace('**VNETGWASN**',$gwasn) + $updatedCsrConfigContent = $updatedCsrConfigContent.Replace('**GW0_Private_IP**',$gw1privateip) + $updatedCsrConfigContent = $updatedCsrConfigContent.Replace('**GW1_Private_IP**',$gw2privateip) + + Set-Content -Path .\csrScript.txt.tmp -Value $updatedCsrConfigContent -Force + + #deploy resources + $onPremJob = New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-onprem' -TemplateFile ./01-03-onprem.bicep -TemplateParameterObject @{vmPassword = $vmPassword; location = $location } -AsJob + + $onPremJob | Wait-Job | Out-Null + + # check for deployment errors + If ($onPremJob.Error) { + Write-Error "A on-prem infrastructure deployment experienced an error: $($onPremJob.error)" + } + + Write-Host "`tConfiguring VPN resources..." + + $vpnJobs = @() + $vpnJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./01-04-hubvpnconfig.bicep -TemplateParameterObject @{location = $location } -AsJob + + $vpnJobs | Wait-Job -Timeout 600 | Out-Null + + # check for deployment errors + If ($vpnJobs.Error) { + Write-Error "A VPN resource/configuration deployment experienced an error: $($vpnJobs.error)" + } + + Write-Host "`tConfiguring Cisco Hub CSR NVA resources..." + + $csrJobs = @() + $csrJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./01-05-csrnva.bicep -TemplateParameterObject @{vmPassword = $vmPassword;location = $location } -AsJob + + $csrJobs | Wait-Job -Timeout 600 | Out-Null + + # check for deployment errors + If ($csrJobs.Error) { + Write-Error "The Cisco CSR NVA resource/configuration deployment experienced an error: $($csrJobs.error)" + } + } + default { + Write-Error "Deployment of this challenge is not implemented" + } +} + +Pop-Location \ No newline at end of file From 98fbd6047d2c4e2da57f873726c557b1a4c8f820 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Fri, 2 Jun 2023 09:48:09 -0600 Subject: [PATCH 73/76] add 172.16.10.0/24 to adv routes --- 035-HubAndSpoke/Coach/Solutions/bicep/csrScript.txt | 2 ++ 035-HubAndSpoke/Coach/Solutions/bicep/deploy.ps1 | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/035-HubAndSpoke/Coach/Solutions/bicep/csrScript.txt b/035-HubAndSpoke/Coach/Solutions/bicep/csrScript.txt index 553bcaa0d3..8baedd0812 100644 --- a/035-HubAndSpoke/Coach/Solutions/bicep/csrScript.txt +++ b/035-HubAndSpoke/Coach/Solutions/bicep/csrScript.txt @@ -68,6 +68,7 @@ exit router bgp 65510 bgp router-id interface GigabitEthernet1 bgp log-neighbor-changes + network 172.16.10.0 mask 255.255.255.0 redistribute connected neighbor **GW0_Private_IP** remote-as **VNETGWASN** neighbor **GW0_Private_IP** ebgp-multihop 5 @@ -79,6 +80,7 @@ router bgp 65510 ! ip route **GW0_Private_IP** 255.255.255.255 Tunnel0 ip route **GW1_Private_IP** 255.255.255.255 Tunnel1 +ip route 172.16.10.0 255.255.255.0 null0 200 ! end ! diff --git a/035-HubAndSpoke/Coach/Solutions/bicep/deploy.ps1 b/035-HubAndSpoke/Coach/Solutions/bicep/deploy.ps1 index 2a58414e92..bf8e7eace8 100644 --- a/035-HubAndSpoke/Coach/Solutions/bicep/deploy.ps1 +++ b/035-HubAndSpoke/Coach/Solutions/bicep/deploy.ps1 @@ -172,7 +172,7 @@ switch ($challengeNumber) { Write-Host "Deploying resources for Challenge 2: Azure Firewall" Write-Host "`tDeploying Azure Firewall and related hub resources..." - $afwJob = New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./02-00-afw.bicep -TemplateParameterObject @{location = $location; afwSku = 'Premium' } -AsJob + $afwJob = New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./02-00-afw.bicep -TemplateParameterObject @{location = $location; afwSku = 'Basic' } -AsJob $afwJob | Wait-Job | Out-Null From baeefbc06a60444c8ee451f4bf321ee52849d013 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Mon, 5 Jun 2023 10:26:51 -0600 Subject: [PATCH 74/76] correct 172.16.10.0/24 route on csr --- 035-HubAndSpoke/Coach/Solutions/bicep/csrScript.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/035-HubAndSpoke/Coach/Solutions/bicep/csrScript.txt b/035-HubAndSpoke/Coach/Solutions/bicep/csrScript.txt index 8baedd0812..69a95424da 100644 --- a/035-HubAndSpoke/Coach/Solutions/bicep/csrScript.txt +++ b/035-HubAndSpoke/Coach/Solutions/bicep/csrScript.txt @@ -80,7 +80,7 @@ router bgp 65510 ! ip route **GW0_Private_IP** 255.255.255.255 Tunnel0 ip route **GW1_Private_IP** 255.255.255.255 Tunnel1 -ip route 172.16.10.0 255.255.255.0 null0 200 +ip route 172.16.10.0 255.255.255.0 GigabitEthernet1 172.16.0.1 200 ! end ! From af616a816e82b739fed55ea0c24a2b208277bb80 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Mon, 5 Jun 2023 15:47:45 -0600 Subject: [PATCH 75/76] removed route server bicep --- .../bicep/01-00-resourceGroups.bicep | 23 -- .../Coach/Solutions/bicep/01-01-hub.bicep | 290 ---------------- .../Coach/Solutions/bicep/01-01-spoke1.bicep | 178 ---------- .../Coach/Solutions/bicep/01-01-spoke2.bicep | 178 ---------- .../bicep/01-02-vnetpeeringhub.bicep | 40 --- .../bicep/01-02-vnetpeeringspoke1.bicep | 22 -- .../bicep/01-02-vnetpeeringspoke2.bicep | 22 -- .../Coach/Solutions/bicep/01-03-onprem.bicep | 321 ------------------ .../Solutions/bicep/01-04-hubvpnconfig.bicep | 48 --- .../Coach/Solutions/bicep/01-05-csrnva.bicep | 180 ---------- .../Coach/Solutions/bicep/README.md | 122 ------- .../Coach/Solutions/bicep/csrScript.txt | 85 ----- .../Coach/Solutions/bicep/csrScriptNVA.txt | 12 - .../Coach/Solutions/bicep/deploy.ps1 | 188 ---------- 14 files changed, 1709 deletions(-) delete mode 100644 057-AzureRouteServer/Coach/Solutions/bicep/01-00-resourceGroups.bicep delete mode 100644 057-AzureRouteServer/Coach/Solutions/bicep/01-01-hub.bicep delete mode 100644 057-AzureRouteServer/Coach/Solutions/bicep/01-01-spoke1.bicep delete mode 100644 057-AzureRouteServer/Coach/Solutions/bicep/01-01-spoke2.bicep delete mode 100644 057-AzureRouteServer/Coach/Solutions/bicep/01-02-vnetpeeringhub.bicep delete mode 100644 057-AzureRouteServer/Coach/Solutions/bicep/01-02-vnetpeeringspoke1.bicep delete mode 100644 057-AzureRouteServer/Coach/Solutions/bicep/01-02-vnetpeeringspoke2.bicep delete mode 100644 057-AzureRouteServer/Coach/Solutions/bicep/01-03-onprem.bicep delete mode 100644 057-AzureRouteServer/Coach/Solutions/bicep/01-04-hubvpnconfig.bicep delete mode 100644 057-AzureRouteServer/Coach/Solutions/bicep/01-05-csrnva.bicep delete mode 100644 057-AzureRouteServer/Coach/Solutions/bicep/README.md delete mode 100644 057-AzureRouteServer/Coach/Solutions/bicep/csrScript.txt delete mode 100644 057-AzureRouteServer/Coach/Solutions/bicep/csrScriptNVA.txt delete mode 100644 057-AzureRouteServer/Coach/Solutions/bicep/deploy.ps1 diff --git a/057-AzureRouteServer/Coach/Solutions/bicep/01-00-resourceGroups.bicep b/057-AzureRouteServer/Coach/Solutions/bicep/01-00-resourceGroups.bicep deleted file mode 100644 index dba60c6b27..0000000000 --- a/057-AzureRouteServer/Coach/Solutions/bicep/01-00-resourceGroups.bicep +++ /dev/null @@ -1,23 +0,0 @@ -param location string = 'eastus2' - -targetScope = 'subscription' -//hub resources -resource wthrghub 'Microsoft.Resources/resourceGroups@2021-04-01' = { - name: 'wth-rg-hub' - location: location -} - -resource wthrgspoke01 'Microsoft.Resources/resourceGroups@2021-04-01' = { - name: 'wth-rg-spoke1' - location: location -} - -resource wthrgspoke02 'Microsoft.Resources/resourceGroups@2021-04-01' = { - name: 'wth-rg-spoke2' - location: location -} - -resource wthrgonprem 'Microsoft.Resources/resourceGroups@2021-04-01' = { - name: 'wth-rg-onprem' - location: location -} diff --git a/057-AzureRouteServer/Coach/Solutions/bicep/01-01-hub.bicep b/057-AzureRouteServer/Coach/Solutions/bicep/01-01-hub.bicep deleted file mode 100644 index 6bac55c2d5..0000000000 --- a/057-AzureRouteServer/Coach/Solutions/bicep/01-01-hub.bicep +++ /dev/null @@ -1,290 +0,0 @@ -param location string = 'eastus2' -param hubVMUsername string = 'admin-wth' -@secure() -param vmPassword string - -targetScope = 'resourceGroup' -//hub resources - -resource wthhubvnet 'Microsoft.Network/virtualNetworks@2021-08-01' = { - name: 'wth-vnet-hub01' - location: location - properties: { - addressSpace: { - addressPrefixes: [ - '10.0.0.0/16' - ] - } - subnets: [ - { - name: 'GatewaySubnet' - properties: { - addressPrefix: '10.0.0.0/24' - routeTable: { - id: rtvnetgw.id - } - } - } - { - name: 'subnet-hubvms' - properties: { - addressPrefix: '10.0.10.0/24' - routeTable: { - id: rthubvms.id - } - networkSecurityGroup: { - id: nsghubvms.id - } - } - } - { - name: 'RouteServerSubnet' - properties: { - addressPrefix: '10.0.3.0/24' - } - } - ] - } -} - -resource wthhubgwpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { - name: 'wth-pip-gw01' - location: location - sku: { - name: 'Standard' - tier: 'Regional' - } - properties: { - publicIPAllocationMethod: 'Static' - } -} - -output pipgw1 string = wthhubgwpip01.properties.ipAddress - -resource wthhubgwpip02 'Microsoft.Network/publicIPAddresses@2022-01-01' = { - name: 'wth-pip-gw02' - location: location - sku: { - name: 'Standard' - tier: 'Regional' - } - properties: { - publicIPAllocationMethod: 'Static' - } -} - -output pipgw2 string = wthhubgwpip02.properties.ipAddress - -resource wthhubvnetgw 'Microsoft.Network/virtualNetworkGateways@2022-01-01' = { - name: 'wth-vngw-hub01' - location: location - properties: { - activeActive: true - bgpSettings: { - asn: 65515 - } - enableBgp: true - gatewayType: 'Vpn' - vpnType: 'RouteBased' - vpnGatewayGeneration: 'Generation1' - sku: { - name: 'VpnGw1' - tier: 'VpnGw1' - } - ipConfigurations: [ - { - name: 'ipconfig1' - properties: { - publicIPAddress: { - id: wthhubgwpip01.id - } - subnet: { - id: '${wthhubvnet.id}/subnets/GatewaySubnet' - } - } - } - { - name: 'ipconfig2' - properties: { - publicIPAddress: { - id: wthhubgwpip02.id - } - subnet: { - id: '${wthhubvnet.id}/subnets/GatewaySubnet' - } - } - } - ] - } -} - -output wthhubvnetgwasn int = wthhubvnetgw.properties.bgpSettings.asn -output wthhubvnetgwprivateip1 string = wthhubvnetgw.properties.bgpSettings.bgpPeeringAddresses[0].defaultBgpIpAddresses[0] -output wthhubvnetgwprivateip2 string = wthhubvnetgw.properties.bgpSettings.bgpPeeringAddresses[1].defaultBgpIpAddresses[0] - -resource changerdpport 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' = { - name: '${wthhubvm01.name}/wth-vmextn-changerdpport33899' - location: location - properties: { - publisher: 'Microsoft.Compute' - type: 'CustomScriptExtension' - typeHandlerVersion: '1.10' - settings: { - /* - To generate encoded command in PowerShell: - - $s = @' - Set-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp\" -Name PortNumber -Value 33899 - New-NetFirewallRule -DisplayName "RDP 33899 TCP" -Direction Inbound -LocalPort 33899 -Protocol TCP -Action Allow - New-NetFirewallRule -DisplayName "RDP 33899 UDP" -Direction Inbound -LocalPort 33899 -Protocol UDP -Action Allow - Restart-Service -Name TermService -Force - - New-NetFirewallRule -DisplayName 'ICMPv4' -Direction Inbound -Action Allow -Protocol icmpv4 -Enabled True - '@ - $bytes = [System.Text.Encoding]::Unicode.GetBytes($s) - [convert]::ToBase64String($bytes) */ - commandToExecute: 'powershell.exe -ep bypass -encodedcommand UwBlAHQALQBJAHQAZQBtAFAAcgBvAHAAZQByAHQAeQAgAC0AUABhAHQAaAAgACIASABLAEwATQA6AFwAUwB5AHMAdABlAG0AXABDAHUAcgByAGUAbgB0AEMAbwBuAHQAcgBvAGwAUwBlAHQAXABDAG8AbgB0AHIAbwBsAFwAVABlAHIAbQBpAG4AYQBsACAAUwBlAHIAdgBlAHIAXABXAGkAbgBTAHQAYQB0AGkAbwBuAHMAXABSAEQAUAAtAFQAYwBwAFwAIgAgAC0ATgBhAG0AZQAgAFAAbwByAHQATgB1AG0AYgBlAHIAIAAtAFYAYQBsAHUAZQAgADMAMwA4ADkAOQANAAoATgBlAHcALQBOAGUAdABGAGkAcgBlAHcAYQBsAGwAUgB1AGwAZQAgAC0ARABpAHMAcABsAGEAeQBOAGEAbQBlACAAIgBSAEQAUAAgADMAMwA4ADkAOQAgAFQAQwBQACIAIAAtAEQAaQByAGUAYwB0AGkAbwBuACAASQBuAGIAbwB1AG4AZAAgAC0ATABvAGMAYQBsAFAAbwByAHQAIAAzADMAOAA5ADkAIAAtAFAAcgBvAHQAbwBjAG8AbAAgAFQAQwBQACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwANAAoATgBlAHcALQBOAGUAdABGAGkAcgBlAHcAYQBsAGwAUgB1AGwAZQAgAC0ARABpAHMAcABsAGEAeQBOAGEAbQBlACAAIgBSAEQAUAAgADMAMwA4ADkAOQAgAFUARABQACIAIAAtAEQAaQByAGUAYwB0AGkAbwBuACAASQBuAGIAbwB1AG4AZAAgAC0ATABvAGMAYQBsAFAAbwByAHQAIAAzADMAOAA5ADkAIAAtAFAAcgBvAHQAbwBjAG8AbAAgAFUARABQACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwANAAoAUgBlAHMAdABhAHIAdAAtAFMAZQByAHYAaQBjAGUAIAAtAE4AYQBtAGUAIABUAGUAcgBtAFMAZQByAHYAaQBjAGUAIAAtAEYAbwByAGMAZQANAAoADQAKAE4AZQB3AC0ATgBlAHQARgBpAHIAZQB3AGEAbABsAFIAdQBsAGUAIAAtAEQAaQBzAHAAbABhAHkATgBhAG0AZQAgACcASQBDAE0AUAB2ADQAJwAgAC0ARABpAHIAZQBjAHQAaQBvAG4AIABJAG4AYgBvAHUAbgBkACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwAgAC0AUAByAG8AdABvAGMAbwBsACAAaQBjAG0AcAB2ADQAIAAtAEUAbgBhAGIAbABlAGQAIABUAHIAdQBlAA==' - } - } -} - -resource wthhubvmpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { - name: 'wth-pip-hubvm01' - location: location - sku: { - name: 'Standard' - tier: 'Regional' - } - properties: { - publicIPAllocationMethod: 'Static' - } -} - -resource wthhubvmnic 'Microsoft.Network/networkInterfaces@2022-01-01' = { - name: 'wth-nic-hubvm01' - location: location - properties: { - ipConfigurations: [ - { - name: 'ipconfig1' - properties: { - subnet: { - id: '${wthhubvnet.id}/subnets/subnet-hubvms' - } - privateIPAddress: '10.0.10.4' - publicIPAddress: { - id: wthhubvmpip01.id - } - } - } - ] - } -} - -resource wthhubvm01 'Microsoft.Compute/virtualMachines@2022-03-01' = { - name: 'wth-vm-hub01' - location: location - properties: { - hardwareProfile: { - vmSize: 'Standard_B2s' - } - storageProfile: { - imageReference: { - publisher: 'MicrosoftWindowsServer' - offer: 'WindowsServer' - sku: '2022-datacenter-azure-edition' - version: 'latest' - } - osDisk: { - osType: 'Windows' - name: 'wth-disk-vmhubos01' - createOption: 'FromImage' - caching: 'ReadWrite' - } - } - osProfile: { - computerName: 'vm-hub01' - adminUsername: hubVMUsername - adminPassword: vmPassword - windowsConfiguration: { - provisionVMAgent: true - enableAutomaticUpdates: true - } - } - networkProfile: { - networkInterfaces: [ - { - id: wthhubvmnic.id - } - ] - } - diagnosticsProfile: { - bootDiagnostics: { - enabled: true - } - } - licenseType: 'Windows_Server' - } -} - -resource rtvnetgw 'Microsoft.Network/routeTables@2022-01-01' = { - name: 'wth-rt-hubgwsubnet' - location: location - properties: { - routes: [] - disableBgpRoutePropagation: false - } -} - -resource rthubvms 'Microsoft.Network/routeTables@2022-01-01' = { - name: 'wth-rt-hubvmssubnet' - location: location - properties: { - routes: [ - { - name: 'route-all-to-csr' - properties: { - addressPrefix: '0.0.0.0/0' - nextHopType: 'VirtualAppliance' - nextHopIpAddress: '10.0.1.4' - } - } - ] - disableBgpRoutePropagation: false - } -} - -resource nsghubvms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { - name: 'wth-nsg-hubvmssubnet' - location: location - properties: { - securityRules: [ - { - name: 'allow-altrdp-to-vmssubnet-from-any' - properties: { - priority: 1000 - access: 'Allow' - direction: 'Inbound' - protocol: 'Tcp' - sourcePortRange: '*' - destinationPortRange: '33899-33899' - sourceAddressPrefix: '*' - destinationAddressPrefix: '10.0.10.0/24' - } - } - { - name: 'allow-altssh-to-vmssubnet-from-any' - properties: { - priority: 1001 - access: 'Allow' - direction: 'Inbound' - protocol: 'Tcp' - sourcePortRange: '*' - destinationPortRange: '22222-22222' - sourceAddressPrefix: '*' - destinationAddressPrefix: '10.0.10.0/24' - } - } - ] - } -} diff --git a/057-AzureRouteServer/Coach/Solutions/bicep/01-01-spoke1.bicep b/057-AzureRouteServer/Coach/Solutions/bicep/01-01-spoke1.bicep deleted file mode 100644 index 6f429602b0..0000000000 --- a/057-AzureRouteServer/Coach/Solutions/bicep/01-01-spoke1.bicep +++ /dev/null @@ -1,178 +0,0 @@ -param location string = 'eastus2' -param spoke1VMUsername string = 'admin-wth' -@secure() -param vmPassword string - -targetScope = 'resourceGroup' -//spoke1 resources - -resource wthspoke1vnet 'Microsoft.Network/virtualNetworks@2021-08-01' = { - name: 'wth-vnet-spoke101' - location: location - properties: { - addressSpace: { - addressPrefixes: [ - '10.1.0.0/16' - ] - } - subnets: [ - { - name: 'subnet-spoke1vms' - properties: { - addressPrefix: '10.1.10.0/24' - networkSecurityGroup: { - id: nsgspoke1vms.id - } - routeTable: { - id: rtspoke1vms.id - } - } - } - ] - } -} - -resource wthspoke1vmpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { - name: 'wth-pip-spoke1vm01' - location: location - sku: { - name: 'Standard' - tier: 'Regional' - } - properties: { - publicIPAllocationMethod: 'Static' - } -} - -resource wthspoke1vmnic 'Microsoft.Network/networkInterfaces@2022-01-01' = { - name: 'wth-nic-spoke1vm01' - location: location - properties: { - ipConfigurations: [ - { - name: 'ipconfig1' - properties: { - subnet: { - id: '${wthspoke1vnet.id}/subnets/subnet-spoke1vms' - } - privateIPAddress: '10.1.10.4' - publicIPAddress: { - id: wthspoke1vmpip01.id - } - } - } - ] - } -} - -resource wthspoke1vm01 'Microsoft.Compute/virtualMachines@2022-03-01' = { - name: 'wth-vm-spoke101' - location: location - properties: { - hardwareProfile: { - vmSize: 'Standard_B2s' - } - storageProfile: { - imageReference: { - publisher: 'MicrosoftWindowsServer' - offer: 'WindowsServer' - sku: '2022-datacenter-azure-edition' - version: 'latest' - } - osDisk: { - osType: 'Windows' - name: 'wth-disk-vmspoke1os01' - createOption: 'FromImage' - caching: 'ReadWrite' - } - } - osProfile: { - computerName: 'vm-spoke101' - adminUsername: spoke1VMUsername - adminPassword: vmPassword - windowsConfiguration: { - provisionVMAgent: true - enableAutomaticUpdates: true - } - } - networkProfile: { - networkInterfaces: [ - { - id: wthspoke1vmnic.id - } - ] - } - diagnosticsProfile: { - bootDiagnostics: { - enabled: true - } - } - licenseType: 'Windows_Server' - } -} - -resource changerdpport 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' = { - name: '${wthspoke1vm01.name}/wth-vmextn-changerdpport33899' - location: location - properties: { - publisher: 'Microsoft.Compute' - type: 'CustomScriptExtension' - typeHandlerVersion: '1.10' - settings: { - commandToExecute: 'powershell.exe -ep bypass -encodedcommand UwBlAHQALQBJAHQAZQBtAFAAcgBvAHAAZQByAHQAeQAgAC0AUABhAHQAaAAgACIASABLAEwATQA6AFwAUwB5AHMAdABlAG0AXABDAHUAcgByAGUAbgB0AEMAbwBuAHQAcgBvAGwAUwBlAHQAXABDAG8AbgB0AHIAbwBsAFwAVABlAHIAbQBpAG4AYQBsACAAUwBlAHIAdgBlAHIAXABXAGkAbgBTAHQAYQB0AGkAbwBuAHMAXABSAEQAUAAtAFQAYwBwAFwAIgAgAC0ATgBhAG0AZQAgAFAAbwByAHQATgB1AG0AYgBlAHIAIAAtAFYAYQBsAHUAZQAgADMAMwA4ADkAOQANAAoATgBlAHcALQBOAGUAdABGAGkAcgBlAHcAYQBsAGwAUgB1AGwAZQAgAC0ARABpAHMAcABsAGEAeQBOAGEAbQBlACAAIgBSAEQAUAAgADMAMwA4ADkAOQAgAFQAQwBQACIAIAAtAEQAaQByAGUAYwB0AGkAbwBuACAASQBuAGIAbwB1AG4AZAAgAC0ATABvAGMAYQBsAFAAbwByAHQAIAAzADMAOAA5ADkAIAAtAFAAcgBvAHQAbwBjAG8AbAAgAFQAQwBQACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwANAAoATgBlAHcALQBOAGUAdABGAGkAcgBlAHcAYQBsAGwAUgB1AGwAZQAgAC0ARABpAHMAcABsAGEAeQBOAGEAbQBlACAAIgBSAEQAUAAgADMAMwA4ADkAOQAgAFUARABQACIAIAAtAEQAaQByAGUAYwB0AGkAbwBuACAASQBuAGIAbwB1AG4AZAAgAC0ATABvAGMAYQBsAFAAbwByAHQAIAAzADMAOAA5ADkAIAAtAFAAcgBvAHQAbwBjAG8AbAAgAFUARABQACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwANAAoAUgBlAHMAdABhAHIAdAAtAFMAZQByAHYAaQBjAGUAIAAtAE4AYQBtAGUAIABUAGUAcgBtAFMAZQByAHYAaQBjAGUAIAAtAEYAbwByAGMAZQANAAoADQAKAE4AZQB3AC0ATgBlAHQARgBpAHIAZQB3AGEAbABsAFIAdQBsAGUAIAAtAEQAaQBzAHAAbABhAHkATgBhAG0AZQAgACcASQBDAE0AUAB2ADQAJwAgAC0ARABpAHIAZQBjAHQAaQBvAG4AIABJAG4AYgBvAHUAbgBkACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwAgAC0AUAByAG8AdABvAGMAbwBsACAAaQBjAG0AcAB2ADQAIAAtAEUAbgBhAGIAbABlAGQAIABUAHIAdQBlAA==' - } - } -} - -resource rtspoke1vms 'Microsoft.Network/routeTables@2022-01-01' = { - name: 'wth-rt-spoke1vmssubnet' - location: location - properties: { - routes: [ - { - name: 'route-all-to-csr' - properties: { - addressPrefix: '0.0.0.0/0' - nextHopType: 'VirtualAppliance' - nextHopIpAddress: '10.0.1.4' - } - } - ] - disableBgpRoutePropagation: false - } -} - -resource nsgspoke1vms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { - name: 'wth-nsg-spoke1vmssubnet' - location: location - properties: { - securityRules: [ - { - name: 'allow-altrdp-to-vmssubnet-from-any' - properties: { - priority: 1000 - access: 'Allow' - direction: 'Inbound' - protocol: 'Tcp' - sourcePortRange: '*' - destinationPortRange: '33899-33899' - sourceAddressPrefix: '*' - destinationAddressPrefix: '10.1.10.0/24' - } - } - { - name: 'allow-altssh-to-vmssubnet-from-any' - properties: { - priority: 1001 - access: 'Allow' - direction: 'Inbound' - protocol: 'Tcp' - sourcePortRange: '*' - destinationPortRange: '22222-22222' - sourceAddressPrefix: '*' - destinationAddressPrefix: '10.1.10.0/24' - } - } - ] - } -} diff --git a/057-AzureRouteServer/Coach/Solutions/bicep/01-01-spoke2.bicep b/057-AzureRouteServer/Coach/Solutions/bicep/01-01-spoke2.bicep deleted file mode 100644 index 703c65f899..0000000000 --- a/057-AzureRouteServer/Coach/Solutions/bicep/01-01-spoke2.bicep +++ /dev/null @@ -1,178 +0,0 @@ -param location string = 'eastus2' -param spoke2VMUsername string = 'admin-wth' -@secure() -param vmPassword string - -targetScope = 'resourceGroup' -//spoke2 resources - -resource wthspoke2vnet 'Microsoft.Network/virtualNetworks@2021-08-01' = { - name: 'wth-vnet-spoke201' - location: location - properties: { - addressSpace: { - addressPrefixes: [ - '10.2.0.0/16' - ] - } - subnets: [ - { - name: 'subnet-spoke2vms' - properties: { - addressPrefix: '10.2.10.0/24' - networkSecurityGroup: { - id: nsgspoke2vms.id - } - routeTable: { - id: rtspoke2vms.id - } - } - } - ] - } -} - -resource wthspoke2vmpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { - name: 'wth-pip-spoke2vm01' - location: location - sku: { - name: 'Standard' - tier: 'Regional' - } - properties: { - publicIPAllocationMethod: 'Static' - } -} - -resource wthspoke2vmnic 'Microsoft.Network/networkInterfaces@2022-01-01' = { - name: 'wth-nic-spoke2vm01' - location: location - properties: { - ipConfigurations: [ - { - name: 'ipconfig1' - properties: { - subnet: { - id: '${wthspoke2vnet.id}/subnets/subnet-spoke2vms' - } - privateIPAddress: '10.2.10.4' - publicIPAddress: { - id: wthspoke2vmpip01.id - } - } - } - ] - } -} - -resource wthspoke2vm01 'Microsoft.Compute/virtualMachines@2022-03-01' = { - name: 'wth-vm-spoke201' - location: location - properties: { - hardwareProfile: { - vmSize: 'Standard_B2s' - } - storageProfile: { - imageReference: { - publisher: 'MicrosoftWindowsServer' - offer: 'WindowsServer' - sku: '2022-datacenter-azure-edition' - version: 'latest' - } - osDisk: { - osType: 'Windows' - name: 'wth-disk-vmspoke2os01' - createOption: 'FromImage' - caching: 'ReadWrite' - } - } - osProfile: { - computerName: 'vm-spoke201' - adminUsername: spoke2VMUsername - adminPassword: vmPassword - windowsConfiguration: { - provisionVMAgent: true - enableAutomaticUpdates: true - } - } - networkProfile: { - networkInterfaces: [ - { - id: wthspoke2vmnic.id - } - ] - } - diagnosticsProfile: { - bootDiagnostics: { - enabled: true - } - } - licenseType: 'Windows_Server' - } -} - -resource changerdpport 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' = { - name: '${wthspoke2vm01.name}/wth-vmextn-changerdpport33899' - location: location - properties: { - publisher: 'Microsoft.Compute' - type: 'CustomScriptExtension' - typeHandlerVersion: '1.10' - settings: { - commandToExecute: 'powershell.exe -ep bypass -encodedcommand UwBlAHQALQBJAHQAZQBtAFAAcgBvAHAAZQByAHQAeQAgAC0AUABhAHQAaAAgACIASABLAEwATQA6AFwAUwB5AHMAdABlAG0AXABDAHUAcgByAGUAbgB0AEMAbwBuAHQAcgBvAGwAUwBlAHQAXABDAG8AbgB0AHIAbwBsAFwAVABlAHIAbQBpAG4AYQBsACAAUwBlAHIAdgBlAHIAXABXAGkAbgBTAHQAYQB0AGkAbwBuAHMAXABSAEQAUAAtAFQAYwBwAFwAIgAgAC0ATgBhAG0AZQAgAFAAbwByAHQATgB1AG0AYgBlAHIAIAAtAFYAYQBsAHUAZQAgADMAMwA4ADkAOQANAAoATgBlAHcALQBOAGUAdABGAGkAcgBlAHcAYQBsAGwAUgB1AGwAZQAgAC0ARABpAHMAcABsAGEAeQBOAGEAbQBlACAAIgBSAEQAUAAgADMAMwA4ADkAOQAgAFQAQwBQACIAIAAtAEQAaQByAGUAYwB0AGkAbwBuACAASQBuAGIAbwB1AG4AZAAgAC0ATABvAGMAYQBsAFAAbwByAHQAIAAzADMAOAA5ADkAIAAtAFAAcgBvAHQAbwBjAG8AbAAgAFQAQwBQACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwANAAoATgBlAHcALQBOAGUAdABGAGkAcgBlAHcAYQBsAGwAUgB1AGwAZQAgAC0ARABpAHMAcABsAGEAeQBOAGEAbQBlACAAIgBSAEQAUAAgADMAMwA4ADkAOQAgAFUARABQACIAIAAtAEQAaQByAGUAYwB0AGkAbwBuACAASQBuAGIAbwB1AG4AZAAgAC0ATABvAGMAYQBsAFAAbwByAHQAIAAzADMAOAA5ADkAIAAtAFAAcgBvAHQAbwBjAG8AbAAgAFUARABQACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwANAAoAUgBlAHMAdABhAHIAdAAtAFMAZQByAHYAaQBjAGUAIAAtAE4AYQBtAGUAIABUAGUAcgBtAFMAZQByAHYAaQBjAGUAIAAtAEYAbwByAGMAZQANAAoADQAKAE4AZQB3AC0ATgBlAHQARgBpAHIAZQB3AGEAbABsAFIAdQBsAGUAIAAtAEQAaQBzAHAAbABhAHkATgBhAG0AZQAgACcASQBDAE0AUAB2ADQAJwAgAC0ARABpAHIAZQBjAHQAaQBvAG4AIABJAG4AYgBvAHUAbgBkACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwAgAC0AUAByAG8AdABvAGMAbwBsACAAaQBjAG0AcAB2ADQAIAAtAEUAbgBhAGIAbABlAGQAIABUAHIAdQBlAA==' - } - } -} - -resource rtspoke2vms 'Microsoft.Network/routeTables@2022-01-01' = { - name: 'wth-rt-spoke2vmssubnet' - location: location - properties: { - routes: [ - { - name: 'route-all-to-csr' - properties: { - addressPrefix: '0.0.0.0/0' - nextHopType: 'VirtualAppliance' - nextHopIpAddress: '10.0.1.4' - } - } - ] - disableBgpRoutePropagation: false - } -} - -resource nsgspoke2vms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { - name: 'wth-nsg-spoke2vmssubnet' - location: location - properties: { - securityRules: [ - { - name: 'allow-altrdp-to-vmssubnet-from-any' - properties: { - priority: 1000 - access: 'Allow' - direction: 'Inbound' - protocol: 'Tcp' - sourcePortRange: '*' - destinationPortRange: '33899-33899' - sourceAddressPrefix: '*' - destinationAddressPrefix: '10.2.10.0/24' - } - } - { - name: 'allow-altssh-to-vmssubnet-from-any' - properties: { - priority: 1001 - access: 'Allow' - direction: 'Inbound' - protocol: 'Tcp' - sourcePortRange: '*' - destinationPortRange: '22222-22222' - sourceAddressPrefix: '*' - destinationAddressPrefix: '10.2.10.0/24' - } - } - ] - } -} diff --git a/057-AzureRouteServer/Coach/Solutions/bicep/01-02-vnetpeeringhub.bicep b/057-AzureRouteServer/Coach/Solutions/bicep/01-02-vnetpeeringhub.bicep deleted file mode 100644 index cc274cc671..0000000000 --- a/057-AzureRouteServer/Coach/Solutions/bicep/01-02-vnetpeeringhub.bicep +++ /dev/null @@ -1,40 +0,0 @@ -resource hubvnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { - name: 'wth-vnet-hub01' - scope: resourceGroup('wth-rg-hub') -} - -resource spoke1vnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { - name: 'wth-vnet-spoke101' - scope: resourceGroup('wth-rg-spoke1') -} - -resource spoke2vnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { - name: 'wth-vnet-spoke201' - scope: resourceGroup('wth-rg-spoke2') -} - -resource hubtospoke1 'Microsoft.Network/virtualNetworks/virtualNetworkPeerings@2022-01-01' = { - name: '${hubvnet.name}/wth-peering-hubtospoke1' - properties: { - allowGatewayTransit: true - allowForwardedTraffic: true - allowVirtualNetworkAccess: true - useRemoteGateways: false - remoteVirtualNetwork: { - id: spoke1vnet.id - } - } -} - -resource hubtospoke2 'Microsoft.Network/virtualNetworks/virtualNetworkPeerings@2022-01-01' = { - name: '${hubvnet.name}/wth-peering-hubtospoke2' - properties: { - allowGatewayTransit: true - allowForwardedTraffic: true - allowVirtualNetworkAccess: true - useRemoteGateways: false - remoteVirtualNetwork: { - id: spoke2vnet.id - } - } -} diff --git a/057-AzureRouteServer/Coach/Solutions/bicep/01-02-vnetpeeringspoke1.bicep b/057-AzureRouteServer/Coach/Solutions/bicep/01-02-vnetpeeringspoke1.bicep deleted file mode 100644 index 3742abe6d8..0000000000 --- a/057-AzureRouteServer/Coach/Solutions/bicep/01-02-vnetpeeringspoke1.bicep +++ /dev/null @@ -1,22 +0,0 @@ -resource hubvnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { - name: 'wth-vnet-hub01' - scope: resourceGroup('wth-rg-hub') -} - -resource spoke1vnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { - name: 'wth-vnet-spoke101' - scope: resourceGroup('wth-rg-spoke1') -} - -resource spoke1tohub 'Microsoft.Network/virtualNetworks/virtualNetworkPeerings@2022-01-01' = { - name: '${spoke1vnet.name}/wth-peering-spoke1tohub' - properties: { - allowGatewayTransit: false - allowForwardedTraffic: false - allowVirtualNetworkAccess: true - useRemoteGateways: true - remoteVirtualNetwork: { - id: hubvnet.id - } - } -} diff --git a/057-AzureRouteServer/Coach/Solutions/bicep/01-02-vnetpeeringspoke2.bicep b/057-AzureRouteServer/Coach/Solutions/bicep/01-02-vnetpeeringspoke2.bicep deleted file mode 100644 index 41216b73a6..0000000000 --- a/057-AzureRouteServer/Coach/Solutions/bicep/01-02-vnetpeeringspoke2.bicep +++ /dev/null @@ -1,22 +0,0 @@ -resource hubvnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { - name: 'wth-vnet-hub01' - scope: resourceGroup('wth-rg-hub') -} - -resource spoke2vnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { - name: 'wth-vnet-spoke201' - scope: resourceGroup('wth-rg-spoke2') -} - -resource spoke2tohub 'Microsoft.Network/virtualNetworks/virtualNetworkPeerings@2022-01-01' = { - name: '${spoke2vnet.name}/wth-peering-spoke1tohub' - properties: { - allowGatewayTransit: false - allowForwardedTraffic: false - allowVirtualNetworkAccess: true - useRemoteGateways: true - remoteVirtualNetwork: { - id: hubvnet.id - } - } -} diff --git a/057-AzureRouteServer/Coach/Solutions/bicep/01-03-onprem.bicep b/057-AzureRouteServer/Coach/Solutions/bicep/01-03-onprem.bicep deleted file mode 100644 index 64464639fe..0000000000 --- a/057-AzureRouteServer/Coach/Solutions/bicep/01-03-onprem.bicep +++ /dev/null @@ -1,321 +0,0 @@ -param location string = 'eastus2' -param onpremVMUsername string = 'admin-wth' -@secure() -param vmPassword string - -targetScope = 'resourceGroup' -//onprem resources - -resource hubvnet 'Microsoft.Network/virtualNetworks@2022-07-01' existing = { - name: 'wth-vnet-hub01' - scope: resourceGroup('wth-rg-hub') - - resource gwsubnet 'subnets' existing = { - name: 'GatewaySubnet' - } -} - -resource wthonpremvnet 'Microsoft.Network/virtualNetworks@2021-08-01' = { - name: 'wth-vnet-onprem01' - location: location - properties: { - addressSpace: { - addressPrefixes: [ - '172.16.0.0/16' - ] - } - subnets: [ - { - name: 'subnet-vpn' - properties: { - addressPrefix: '172.16.0.0/24' - networkSecurityGroup: { - id: nsgonpremvpn.id - } - } - } - { - name: 'subnet-onpremvms' - properties: { - addressPrefix: '172.16.10.0/24' - networkSecurityGroup: { - id: nsgonpremvms.id - } - routeTable: { - id: rtonpremvms.id - } - } - } - ] - } -} - -resource wthonpremvmpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { - name: 'wth-pip-onpremvm01' - location: location - sku: { - name: 'Standard' - tier: 'Regional' - } - properties: { - publicIPAllocationMethod: 'Static' - } -} - -resource wthonpremvmnic 'Microsoft.Network/networkInterfaces@2022-01-01' = { - name: 'wth-nic-onpremvm01' - location: location - properties: { - ipConfigurations: [ - { - name: 'ipconfig1' - properties: { - subnet: { - id: '${wthonpremvnet.id}/subnets/subnet-onpremvms' - } - privateIPAddress: '172.16.10.4' - publicIPAddress: { - id: wthonpremvmpip01.id - } - } - } - ] - } -} - -resource wthonpremvm01 'Microsoft.Compute/virtualMachines@2022-03-01' = { - name: 'wth-vm-onprem01' - location: location - properties: { - hardwareProfile: { - vmSize: 'Standard_B2s' - } - storageProfile: { - imageReference: { - publisher: 'MicrosoftWindowsServer' - offer: 'WindowsServer' - sku: '2022-datacenter-azure-edition' - version: 'latest' - } - osDisk: { - osType: 'Windows' - name: 'wth-disk-vmonpremos01' - createOption: 'FromImage' - caching: 'ReadWrite' - } - } - osProfile: { - computerName: 'vm-onprem01' - adminUsername: onpremVMUsername - adminPassword: vmPassword - windowsConfiguration: { - provisionVMAgent: true - enableAutomaticUpdates: true - } - } - networkProfile: { - networkInterfaces: [ - { - id: wthonpremvmnic.id - } - ] - } - diagnosticsProfile: { - bootDiagnostics: { - enabled: true - } - } - licenseType: 'Windows_Server' - } -} - -resource changerdpport 'Microsoft.Compute/virtualMachines/extensions@2022-03-01' = { - name: '${wthonpremvm01.name}/wth-vmextn-changerdpport33899' - location: location - properties: { - publisher: 'Microsoft.Compute' - type: 'CustomScriptExtension' - typeHandlerVersion: '1.10' - settings: { - commandToExecute: 'powershell.exe -ep bypass -encodedcommand UwBlAHQALQBJAHQAZQBtAFAAcgBvAHAAZQByAHQAeQAgAC0AUABhAHQAaAAgACIASABLAEwATQA6AFwAUwB5AHMAdABlAG0AXABDAHUAcgByAGUAbgB0AEMAbwBuAHQAcgBvAGwAUwBlAHQAXABDAG8AbgB0AHIAbwBsAFwAVABlAHIAbQBpAG4AYQBsACAAUwBlAHIAdgBlAHIAXABXAGkAbgBTAHQAYQB0AGkAbwBuAHMAXABSAEQAUAAtAFQAYwBwAFwAIgAgAC0ATgBhAG0AZQAgAFAAbwByAHQATgB1AG0AYgBlAHIAIAAtAFYAYQBsAHUAZQAgADMAMwA4ADkAOQANAAoATgBlAHcALQBOAGUAdABGAGkAcgBlAHcAYQBsAGwAUgB1AGwAZQAgAC0ARABpAHMAcABsAGEAeQBOAGEAbQBlACAAIgBSAEQAUAAgADMAMwA4ADkAOQAgAFQAQwBQACIAIAAtAEQAaQByAGUAYwB0AGkAbwBuACAASQBuAGIAbwB1AG4AZAAgAC0ATABvAGMAYQBsAFAAbwByAHQAIAAzADMAOAA5ADkAIAAtAFAAcgBvAHQAbwBjAG8AbAAgAFQAQwBQACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwANAAoATgBlAHcALQBOAGUAdABGAGkAcgBlAHcAYQBsAGwAUgB1AGwAZQAgAC0ARABpAHMAcABsAGEAeQBOAGEAbQBlACAAIgBSAEQAUAAgADMAMwA4ADkAOQAgAFUARABQACIAIAAtAEQAaQByAGUAYwB0AGkAbwBuACAASQBuAGIAbwB1AG4AZAAgAC0ATABvAGMAYQBsAFAAbwByAHQAIAAzADMAOAA5ADkAIAAtAFAAcgBvAHQAbwBjAG8AbAAgAFUARABQACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwANAAoAUgBlAHMAdABhAHIAdAAtAFMAZQByAHYAaQBjAGUAIAAtAE4AYQBtAGUAIABUAGUAcgBtAFMAZQByAHYAaQBjAGUAIAAtAEYAbwByAGMAZQANAAoADQAKAE4AZQB3AC0ATgBlAHQARgBpAHIAZQB3AGEAbABsAFIAdQBsAGUAIAAtAEQAaQBzAHAAbABhAHkATgBhAG0AZQAgACcASQBDAE0AUAB2ADQAJwAgAC0ARABpAHIAZQBjAHQAaQBvAG4AIABJAG4AYgBvAHUAbgBkACAALQBBAGMAdABpAG8AbgAgAEEAbABsAG8AdwAgAC0AUAByAG8AdABvAGMAbwBsACAAaQBjAG0AcAB2ADQAIAAtAEUAbgBhAGIAbABlAGQAIABUAHIAdQBlAA==' - } - } -} - -resource rtonpremvms 'Microsoft.Network/routeTables@2022-01-01' = { - name: 'wth-rt-onpremvmssubnet' - location: location - properties: { - routes: [ - { - name: 'route-hub' - properties: { - addressPrefix: '10.0.0.0/16' - nextHopIpAddress: '172.16.0.4' - nextHopType: 'VirtualAppliance' - } - } - { - name: 'route-spoke1' - properties: { - addressPrefix: '10.1.0.0/16' - nextHopIpAddress: '172.16.0.4' - nextHopType: 'VirtualAppliance' - } - } - { - name: 'route-spoke2' - properties: { - addressPrefix: '10.2.0.0/16' - nextHopIpAddress: '172.16.0.4' - nextHopType: 'VirtualAppliance' - } - } - ] - disableBgpRoutePropagation: false - } -} - -resource nsgonpremvms 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { - name: 'wth-nsg-onpremvmssubnet' - location: location - properties: { - securityRules: [ - { - name: 'allow-altrdp-to-vmssubnet-from-any' - properties: { - priority: 1000 - access: 'Allow' - direction: 'Inbound' - protocol: 'Tcp' - sourcePortRange: '*' - destinationPortRange: '33899-33899' - sourceAddressPrefix: '*' - destinationAddressPrefix: '172.16.10.0/24' - } - } - { - name: 'allow-altssh-to-vmssubnet-from-any' - properties: { - priority: 1001 - access: 'Allow' - direction: 'Inbound' - protocol: 'Tcp' - sourcePortRange: '*' - destinationPortRange: '22222-22222' - sourceAddressPrefix: '*' - destinationAddressPrefix: '172.16.10.0/24' - } - } - ] - } -} - -resource nsgonpremvpn 'Microsoft.Network/networkSecurityGroups@2022-01-01' = { - name: 'wth-nsg-onpremvpnsubnet' - location: location - properties: { - securityRules: [ - { - name: 'allow-any-to-vpnsubnet-from-onprem' - properties: { - priority: 1000 - access: 'Allow' - direction: 'Inbound' - protocol: '*' - sourcePortRange: '*' - destinationPortRange: '*' - sourceAddressPrefix: '172.16.10.0/24' - destinationAddressPrefix: '*' - } - } - { - name: 'allow-any-to-any-from-azurevpngw' - properties: { - priority: 1001 - access: 'Allow' - direction: 'Inbound' - protocol: '*' - sourcePortRange: '*' - destinationPortRange: '*' - sourceAddressPrefix: hubvnet::gwsubnet.properties.addressPrefix - destinationAddressPrefix: '*' - } - } - ] - } -} - -resource wthonpremcsrpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { - name: 'wth-pip-csr01' - location: location - sku: { - name: 'Standard' - tier: 'Regional' - } - properties: { - publicIPAllocationMethod: 'Static' - } -} - -resource wthonpremcsrnic 'Microsoft.Network/networkInterfaces@2022-01-01' = { - name: 'wth-nic-csr01' - location: location - properties: { - enableIPForwarding: true - ipConfigurations: [ - { - name: 'ipconfig1' - properties: { - subnet: { - id: '${wthonpremvnet.id}/subnets/subnet-vpn' - } - privateIPAddress: '172.16.0.4' - publicIPAddress: { - id: wthonpremcsrpip01.id - } - } - } - ] - } -} - -resource ciscocsr 'Microsoft.Compute/virtualMachines@2022-03-01' = { - name: 'wth-vm-ciscocsr01' - location: location - plan: { - publisher: 'cisco' - product: 'cisco-csr-1000v' - name: '16_12-byol' - } - properties: { - hardwareProfile: { - vmSize: 'Standard_B2ms' - } - storageProfile: { - imageReference: { - publisher: 'cisco' - offer: 'cisco-csr-1000v' - sku: '16_12-byol' - version: 'latest' - } - osDisk: { - osType: 'Linux' - createOption: 'FromImage' - } - } - networkProfile: { - networkInterfaces: [ - { - id: wthonpremcsrnic.id - } - ] - } - osProfile: { - adminUsername: onpremVMUsername - adminPassword: vmPassword - computerName: 'wthcsr01' - customData: loadFileAsBase64('./csrScript.txt.tmp') - } - } -} diff --git a/057-AzureRouteServer/Coach/Solutions/bicep/01-04-hubvpnconfig.bicep b/057-AzureRouteServer/Coach/Solutions/bicep/01-04-hubvpnconfig.bicep deleted file mode 100644 index 11883fa563..0000000000 --- a/057-AzureRouteServer/Coach/Solutions/bicep/01-04-hubvpnconfig.bicep +++ /dev/null @@ -1,48 +0,0 @@ -param location string = 'eastus2' - -resource onpremcsrpip 'Microsoft.Network/publicIPAddresses@2022-01-01' existing = { - name: 'wth-pip-csr01' - scope: resourceGroup('wth-rg-onprem') -} - -resource onpremcsrnic 'Microsoft.Network/networkInterfaces@2022-01-01' existing = { - name: 'wth-nic-csr01' - scope: resourceGroup('wth-rg-onprem') -} - -resource wthhubvnetgw 'Microsoft.Network/virtualNetworkGateways@2022-01-01' existing = { - name: 'wth-vngw-hub01' - scope: resourceGroup('wth-rg-hub') -} - -resource wthhublocalgw 'Microsoft.Network/localNetworkGateways@2022-01-01' = { - name: 'wth-lgw-onprem01' - location: location - properties: { - gatewayIpAddress: onpremcsrpip.properties.ipAddress - localNetworkAddressSpace: { - addressPrefixes: [] - } - bgpSettings: { - bgpPeeringAddress: onpremcsrnic.properties.ipConfigurations[0].properties.privateIPAddress - asn: 65510 - } - } -} - -resource wthhubconnection 'Microsoft.Network/connections@2022-01-01' = { - name: 'wth-cxn-vpn01' - location: location - properties: { - sharedKey: '123mysecretkey' - connectionType: 'IPsec' - connectionMode: 'Default' - enableBgp: true - localNetworkGateway2: { - id: wthhublocalgw.id - } - virtualNetworkGateway1: { - id: wthhubvnetgw.id - } - } -} diff --git a/057-AzureRouteServer/Coach/Solutions/bicep/01-05-csrnva.bicep b/057-AzureRouteServer/Coach/Solutions/bicep/01-05-csrnva.bicep deleted file mode 100644 index a0e600b6c2..0000000000 --- a/057-AzureRouteServer/Coach/Solutions/bicep/01-05-csrnva.bicep +++ /dev/null @@ -1,180 +0,0 @@ -param location string = 'eastus2' -param vmusername string = 'admin-wth' -@secure() -param vmPassword string - -resource hubvnet 'Microsoft.Network/virtualNetworks@2022-01-01' existing = { - name: 'wth-vnet-hub01' - scope: resourceGroup('wth-rg-hub') -} - -resource nvaoutsidesubnet 'Microsoft.Network/virtualNetworks/subnets@2022-01-01' = { - name: '${hubvnet.name}/nvaoutsidesubnet' - properties: { - addressPrefix: '10.0.2.0/24' - } -} - -resource nvainsidesidesubnet 'Microsoft.Network/virtualNetworks/subnets@2022-01-01' = { - dependsOn: [ - nvaoutsidesubnet - ] - name: '${hubvnet.name}/nvainsidesidesubnet' - properties: { - addressPrefix: '10.0.1.0/24' - } -} - -resource wthcsrpip01 'Microsoft.Network/publicIPAddresses@2022-01-01' = { - name: 'wth-pip-afw01' - location: location - sku: { - name: 'Standard' - tier: 'Regional' - } - properties: { - publicIPAllocationMethod: 'Static' - } -} - -resource wthcsroutsidenic 'Microsoft.Network/networkInterfaces@2022-07-01' = { - name: 'wth-nic-nvaoutside' - location: location - properties: { - ipConfigurations: [ - { - name: 'ipconfigOutside' - properties: { - subnet: { - id: nvaoutsidesubnet.id - } - privateIPAllocationMethod: 'Static' - privateIPAddress: '10.0.2.4' - publicIPAddress: { - id: wthcsrpip01.id - } - } - } - ] - } -} - -resource wthcsrinsidenic 'Microsoft.Network/networkInterfaces@2022-07-01' = { - name: 'wth-nic-nvainside' - location: location - properties: { - ipConfigurations: [ - { - name: 'ipconfigInside' - properties: { - subnet: { - id: nvainsidesidesubnet.id - } - privateIPAllocationMethod: 'Static' - privateIPAddress: '10.0.1.4' - } - } - ] - } -} - -resource ciscocsr 'Microsoft.Compute/virtualMachines@2022-03-01' = { - name: 'wth-vm-ciscocsr01' - location: location - plan: { - publisher: 'cisco' - product: 'cisco-csr-1000v' - name: '16_12-byol' - } - properties: { - hardwareProfile: { - vmSize: 'Standard_B2ms' - } - storageProfile: { - imageReference: { - publisher: 'cisco' - offer: 'cisco-csr-1000v' - sku: '16_12-byol' - version: 'latest' - } - osDisk: { - osType: 'Linux' - createOption: 'FromImage' - } - } - networkProfile: { - networkInterfaces: [ - { - id: wthcsroutsidenic.id - properties: { - primary: true - } - } - { - id: wthcsrinsidenic.id - properties: { - primary: false - } - } - ] - } - osProfile: { - adminUsername: vmusername - adminPassword: vmPassword - computerName: 'wthcsrnva01' - customData: loadFileAsBase64('./csrScriptNVA.txt') - } - } -} - -resource rthubvms 'Microsoft.Network/routeTables@2022-01-01' = { - name: 'wth-rt-hubvmssubnet' - location: location - properties: { - routes: [ - { - name: 'route-all-to-nva' - properties: { - addressPrefix: '0.0.0.0/0' - nextHopType: 'VirtualAppliance' - nextHopIpAddress: wthcsrinsidenic.properties.ipConfigurations[0].properties.privateIPAddress - } - } - ] - disableBgpRoutePropagation: false - } -} - -resource rtvnetgw 'Microsoft.Network/routeTables@2022-01-01' = { - name: 'wth-rt-hubgwsubnet' - location: location - properties: { - routes: [ - { - name: 'route-spoke1-to-nva' - properties: { - addressPrefix: '10.1.0.0/16' - nextHopType: 'VirtualAppliance' - nextHopIpAddress: wthcsrinsidenic.properties.ipConfigurations[0].properties.privateIPAddress - } - } - { - name: 'route-spoke2-to-nva' - properties: { - addressPrefix: '10.2.0.0/16' - nextHopType: 'VirtualAppliance' - nextHopIpAddress: wthcsrinsidenic.properties.ipConfigurations[0].properties.privateIPAddress - } - } - { - name: 'route-hubvm-to-nva' - properties: { - addressPrefix: '10.0.10.0/24' - nextHopType: 'VirtualAppliance' - nextHopIpAddress: wthcsrinsidenic.properties.ipConfigurations[0].properties.privateIPAddress - } - } - ] - disableBgpRoutePropagation: false - } -} diff --git a/057-AzureRouteServer/Coach/Solutions/bicep/README.md b/057-AzureRouteServer/Coach/Solutions/bicep/README.md deleted file mode 100644 index 18564f7892..0000000000 --- a/057-AzureRouteServer/Coach/Solutions/bicep/README.md +++ /dev/null @@ -1,122 +0,0 @@ -# What the Hack Networking Bicep Deployment - -This directory contains Bicep templates to deploy and configure resources as described in each WTH Networking challenge. These deployments represent one way to meet the challenge requirements--there are many others. - -## Who should use these templates? - -The WTH philosophy intends to have students learn by doing, and recognizes that one of the best ways to learn is to troubleshoot problems. As such, using these templates instead of building your own lab will detract from your learning experience, and primarily recommended for the scenarios below: - -- Students who will not be completing a challenge which is a prerequisite to a later challenge -- Students who are falling behind in the WTH due to issues unrelated to the core learning goals of this WTH -- Students looking for a reference implementation to compare against their own approach -- Coaches looking to deploy a reference architecture to the lab - -## Using these templates - -Using Cloud Shell is recommended, as it already has the necessary tools installed. However, Cloud Shell has a timeout of about 20 minutes and may experience timeouts (in which case, run the same command again to pick up the deployments where they stopped). - -**Challenges are meant to be deployed sequentially, as the infrastructure builds on itself.** For example, to work with the Challenge 5 infrastructure, deploy Challenges 1-4 first. Also, keep in mind that changes made for testing need to be manually reverted, unless the relevant Challenge and subsequent Challenges are redeployed. - -### Prerequisites - -- Azure PowerShell module -- git - -### Download Options - -#### Clone the Git repo (slow) - -1. Clone this repo to your local system or Cloud Shell - `git clone https://github.com/microsoft/WhatTheHack.git` -1. Navigate to the `035-HubAndSpoke\Student\Resources\bicep` directory in your clone of the repo -1. Run the deploy.ps1 script. For example: - `./deploy.ps1 -challengeNumber 1` - -#### Download a zip of the bicep directory - -1. Browse to https://download-directory.github.io/?url=https%3A%2F%2Fgithub.com%2Fmicrosoft%2FWhatTheHack%2Ftree%2Fnetwork-bicep%2F035-HubAndSpoke%2FStudent%2FResources%2Fbicep -1. A zip of the directory will download to your system -1. Expand the downloaded zip file and navigate to it in a PowerShell window -1. Run the deploy.ps1 script. For example: - `./deploy.ps1 -challengeNumber 1` - -## Deployed Configuration - -### Challenge 1 - -- Windows VMs are deployed in the hub, both spokes, and on-prem Resource Groups -- VM usernames are 'admin-wth' and passwords are the one supplied when executing the script -- Windows VM firewalls have been modified to allow Ping traffic -- All Windows VMs have associated Public IP Addresses and are accessible via RDP using alternate port 33899 (ex: `mstsc /v:4.32.1.5:33899`) -- The Cisco CSR deployed in the 'wth-rg-onprem' Resource Group uses the same username and password, but is not accessible from the internet. To access it, RDP to the Windows VM in the onprem Resource Group, then connect to the CSR using ssh and its private IP address - -### Challenge 2 - -- With Azure Firewall deployed and traffic routing through it following the Challenge, the Windows VMs are no longer directly accessible via Public IP. Use the Azure Firewall public IP with the following DNAT port mapping: - - Hub: 33980 - - Spoke 1: 33891 - - Spoke 2: 33892 - - On-prem (still accessible by Public IP and custom 33899 RDP port) - -- All Windows VMs have a diagnostic website configured in IIS called Inspector Gadget. To access it locally, browse to `http://localhost/default.aspx`. Web server DNAT through the Azure Firewall uses the following port mapping: - - - Hub: 8080 - - Spoke 1: 8081 - - Spoke 2: 8082 - -### Challenge 3 - -- The routing tables are adjusted to match the Challenge documentation. To correct the inital deployment, run `deploy.ps1 -challengeNumber 3 -correctedConfiguration` - -### Challenge 4 - -An Application Gateway is deployed matching the Challenge requirements. The deployment automates the configuration of a TLS certificate and DNS records when appropriate RFC 2136 credentials are supplied (the default configuration). The deployment options are: - -1. Automated: Have automation handle DNS records and TLS certificates for you -- this requires registering for a DNS name, for example, from https://dynv6.com. -1. Manually configured: If you have an existing domain name and TLS certificates, you can manually upload the PFX certificate file to the Key Vault prior to deploying the App GW. -1. Automated, with self-signed certificate: If there are issues generating the publicly trusted TLS certificate from Let's Encrypt, a self-signed certificate can be used. - -For details on these options and troubleshooting, see: [Application Gateway DNS and Certificates](./appGWCertificateProcess.md) - -The application gateway is configured with backend pools for the Spoke 1 and Spoke 2 VMs. - -### Challenge 5 - -The required Azure SQL and App Service resources are deployed, along with their supporting Private Link infrastructure. An Azure Private DNS Resolver is deployed to enable Private Endpoint name resolution for the 'on-prem' resources. - -The 'Inspector Gadget' utility is installed on the Web App, which is publicly accessible. It includes functions to verify DNS name resolution and test SQL connectivity, though you may want to take the additional step of [granting your App Service MSI access to the SQL database](https://learn.microsoft.com/azure/active-directory/managed-identities-azure-resources/tutorial-windows-vm-access-sql). - -Resources deployed: - -- Azure SQL Servers and DBs in Spoke 1 and Spoke 1 -- Web App in Spoke 1 -- Private DNS Resolver in Hub -- Private Endpoints for SQL servers and App Service -- Private DNS Zones for Private Endpoint records -- Subnets for new services (App Service, DNS Resolver, SQL Private Endpoints) -- NSGs for new subnets -- Route table and routes to force Spoke 1 SQL traffic through the Azure Firewall (advanced scenario) - -## Resource Cleanup - -To cleanup this deployment, delete each create resource group. To do this programmatically with PowerShell, run: - -```powershell - $jobs = @() - $jobs += Remove-AzResourceGroup -Name 'wth-rg-hub' -Force -AsJob - $jobs += Remove-AzResourceGroup -Name 'wth-rg-spoke1' -Force -AsJob - $jobs += Remove-AzResourceGroup -Name 'wth-rg-spoke2' -Force -AsJob - $jobs += Remove-AzResourceGroup -Name 'wth-rg-onprem' -Force -AsJob - - Write-Host "Waiting for all resource group cleanup jobs to complete..." - $jobs | Wait-Job - - $jobs | Foreach-Object { - $job = $_ - If ($job.Error) { - Write-Error "A cleanup task experienced an error: $($job.error)" - } - } - - Write-Host "Cleanup task completed." -``` diff --git a/057-AzureRouteServer/Coach/Solutions/bicep/csrScript.txt b/057-AzureRouteServer/Coach/Solutions/bicep/csrScript.txt deleted file mode 100644 index 553bcaa0d3..0000000000 --- a/057-AzureRouteServer/Coach/Solutions/bicep/csrScript.txt +++ /dev/null @@ -1,85 +0,0 @@ -Section: IOS configuration -ip ssh port 2222 rotary 1 -! -line vty 0 15 - rotary 1 - exit -! -crypto ikev2 proposal azure-proposal - encryption aes-cbc-256 aes-cbc-128 3des - integrity sha1 - group 2 - exit -! -crypto ikev2 policy azure-policy - proposal azure-proposal - exit -! -crypto ikev2 keyring azure-keyring - peer **GW0_Public_IP** - address **GW0_Public_IP** - pre-shared-key 123mysecretkey - exit - peer **GW1_Public_IP** - address **GW1_Public_IP** - pre-shared-key 123mysecretkey - exit - exit -! -crypto ikev2 profile azure-profile - match address local interface GigabitEthernet1 - match identity remote address **GW0_Public_IP** 255.255.255.255 - match identity remote address **GW1_Public_IP** 255.255.255.255 - authentication remote pre-share - authentication local pre-share - keyring local azure-keyring - exit -! -crypto ipsec transform-set azure-ipsec-proposal-set esp-aes 256 esp-sha-hmac - mode tunnel - exit - -crypto ipsec profile azure-vti - set transform-set azure-ipsec-proposal-set - set ikev2-profile azure-profile - set security-association lifetime kilobytes 102400000 - set security-association lifetime seconds 3600 - exit -! -interface Tunnel0 - ip unnumbered GigabitEthernet1 - ip tcp adjust-mss 1350 - tunnel source GigabitEthernet1 - tunnel mode ipsec ipv4 - tunnel destination **GW0_Public_IP** - tunnel protection ipsec profile azure-vti -exit -! -interface Tunnel1 - ip unnumbered GigabitEthernet1 - ip tcp adjust-mss 1350 - tunnel source GigabitEthernet1 - tunnel mode ipsec ipv4 - tunnel destination **GW1_Public_IP** - tunnel protection ipsec profile azure-vti -exit - -! -router bgp 65510 - bgp router-id interface GigabitEthernet1 - bgp log-neighbor-changes - redistribute connected - neighbor **GW0_Private_IP** remote-as **VNETGWASN** - neighbor **GW0_Private_IP** ebgp-multihop 5 - neighbor **GW0_Private_IP** update-source GigabitEthernet1 - neighbor **GW1_Private_IP** remote-as **VNETGWASN** - neighbor **GW1_Private_IP** ebgp-multihop 5 - neighbor **GW1_Private_IP** update-source GigabitEthernet1 - maximum-paths eibgp 4 -! -ip route **GW0_Private_IP** 255.255.255.255 Tunnel0 -ip route **GW1_Private_IP** 255.255.255.255 Tunnel1 -! -end -! -wr mem diff --git a/057-AzureRouteServer/Coach/Solutions/bicep/csrScriptNVA.txt b/057-AzureRouteServer/Coach/Solutions/bicep/csrScriptNVA.txt deleted file mode 100644 index 84172effa3..0000000000 --- a/057-AzureRouteServer/Coach/Solutions/bicep/csrScriptNVA.txt +++ /dev/null @@ -1,12 +0,0 @@ -Section: IOS configuration -ip ssh port 2222 rotary 1 -! -line vty 0 15 - rotary 1 - exit -! -ip route 172.16.0.0 255.255.0.0 10.0.2.1 -ip route 10.1.0.0 255.255.0.0 10.0.1.1 -ip route 10.2.0.0 255.255.0.0 10.0.1.1 -! -wr mem \ No newline at end of file diff --git a/057-AzureRouteServer/Coach/Solutions/bicep/deploy.ps1 b/057-AzureRouteServer/Coach/Solutions/bicep/deploy.ps1 deleted file mode 100644 index a50eaa2758..0000000000 --- a/057-AzureRouteServer/Coach/Solutions/bicep/deploy.ps1 +++ /dev/null @@ -1,188 +0,0 @@ -<# -.SYNOPSIS -.DESCRIPTION - Deploys or configures WTH Networking challenge resources. -.EXAMPLE - ./deploy.ps1 -challengeNumber 1 - Deploy all resource groups and resources for Challenge 1. Script will prompt for a password, which will be used across all VMs. -#> -[CmdletBinding()] -param ( - # challenge number to deploy - [Parameter(Mandatory = $true, HelpMessage = 'Enter the WTH hub and spoke challenge number (1-6)')] - [ValidateRange(1, 6)] - [int] - $challengeNumber, - - <# - # TODO: deploy fully configured lab or leave some configuration to be done - [Parameter(Mandatory = $false, HelpMessage = 'Deploy all challenge resources fully configured or partially configured (for learning!)')] - [ValidateSet('FullyConfigured', 'PartiallyConfigured')] - [string] - $deploymentType = 'FullyConfigured', - #> - - # resource deployment Azure region, defaults to 'eastus2' - [Parameter(Mandatory = $false)] - [string] - $location = 'EastUS2', - - # Parameter help description - [Parameter(Mandatory = $false)] - [SecureString] - $vmPassword, - - # include to correct intentionally misconfigured resources (deployed as part of the challenge) - [Parameter(Mandatory = $false)] - [switch] - $correctedConfiguration, - - # confirm subscription and resource types - [Parameter(Mandatory=$false)] - [System.Boolean] - $confirm = $true, - - # challenge parameters - [parameter(Mandatory = $false)] - [hashtable] - $challengeParameters = @{} -) - -$ErrorActionPreference = 'Stop' - -If (-NOT (Test-Path ./01-resourceGroups.bicep)) { - - Write-Warning "This script need to be executed from the directory containing the bicep files. Attempting to set location to script location." - - try { - $scriptPath = ($MyInvocation.MyCommand.Path | Split-Path -Parent -ErrorAction Stop) - Push-Location -Path $scriptPath -ErrorAction Stop - } - catch { - throw "Failed to set path to bicep file location. Use the 'cd' command to change the current directory to the same location as the WTH bicep files before executing this script." - } -} - -If ( -NOT ($azContext = Get-AzContext)) { - throw "Run 'Connect-AzAccount' before executing this script!" -} -ElseIf ($confirm) { - do { $response = (Read-Host "Resources will be created in subscription '$($azContext.Subscription.Name)' in region '$location'. If this is not the correct subscription, use 'Select-AzSubscription' before running this script and specify an alternate location with the -Location parameter. Proceed? (y/n)") } - until ($response -match '[nNYy]') - - If ($response -match 'nN') { exit } -} - -switch ($challengeNumber) { - 1 { - Write-Host "Deploying resources for Challenge 1: Hub-and-spoke Basics" - - If (-NOT ($vmPassword)) { - $vmPassword = Read-Host "Enter (and make note of) a complex password which will be used for all deployed VMs (username will be 'admin-wth')" -AsSecureString - } - - Write-Host "`tDeploying resource groups..." - New-AzDeployment -Location $location -Name "01-00-resourceGroups_$location" -TemplateFile ./01-00-resourceGroups.bicep | Out-Null - - Write-Host "`tDeploying base resources (this will take up to 60 minutes for the VNET Gateway)..." - $baseInfraJobs = @{} - $baseInfraJobs += @{'wth-rg-spoke1' = (New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./01-01-spoke1.bicep -TemplateParameterObject @{vmPassword = $vmPassword; location = $location } -AsJob)} - $baseInfraJobs += @{'wth-rg-spoke2' = (New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./01-01-spoke2.bicep -TemplateParameterObject @{vmPassword = $vmPassword; location = $location } -AsJob)} - $baseInfraJobs += @{'wth-rg-hub' = (New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./01-01-hub.bicep -TemplateParameterObject @{vmPassword = $vmPassword; location = $location } -AsJob)} - - Write-Host "`tWaiting up to 60 minutes for resources to deploy..." - $baseInfraJobs.GetEnumerator().ForEach({$_.Value}) | Wait-Job -Timeout 3600 | Out-Null - - # check for deployment errors - $baseInfraJobs.GetEnumerator().ForEach({$_.Value}) | Foreach-Object { - $job = $_ | Get-Job - If ($job.Error) { - Write-Error "A deployment experienced an error: $($job.error)" - } - } - - $gw1pip = $baseInfraJobs.'wth-rg-hub'.Output.Outputs.pipgw1.Value - $gw2pip = $baseInfraJobs.'wth-rg-hub'.Output.Outputs.pipgw2.Value - $gwasn = $baseInfraJobs.'wth-rg-hub'.Output.Outputs.wthhubvnetgwasn.Value - $gw1privateip = $baseInfraJobs.'wth-rg-hub'.Output.Outputs.wthhubvnetgwprivateip1.Value - $gw2privateip = $baseInfraJobs.'wth-rg-hub'.Output.Outputs.wthhubvnetgwprivateip2.Value - - Write-Host "`tDeploying VNET Peering..." - $peeringJobs = @() - $peeringJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./01-02-vnetpeeringhub.bicep -TemplateParameterObject @{} -AsJob - $peeringJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke1' -TemplateFile ./01-02-vnetpeeringspoke1.bicep -TemplateParameterObject @{} -AsJob - $peeringJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-spoke2' -TemplateFile ./01-02-vnetpeeringspoke2.bicep -TemplateParameterObject @{} -AsJob - - $peeringJobs | Wait-Job -Timeout 300 | Out-Null - - # check for deployment errors - $peeringJobs | Foreach-Object { - $job = $_ - If ($job.Error) { - Write-Error "A VNET peering deployment experienced an error: $($job.error)" - } - } - - Write-Host "`tDeploying 'onprem' infra" - - #accept csr marketplace terms - try { - If (-Not (Get-AzMarketplaceTerms -Publisher 'cisco' -Product 'cisco-csr-1000v' -Name '16_12-byol').Accepted) { - Write-Host "`t`tAccepting Cisco CSR marketplace terms for this subscription..." - Set-AzMarketplaceTerms -Publisher 'cisco' -Product 'cisco-csr-1000v' -Name '16_12-byol' -Accept | Out-Null - } - } - catch { - throw "An error occured while attempting to accept the markeplace terms for the Cisco CSR deployment. Try running `Set-AzMarketplaceTerms -Publisher 'cisco' -Product 'cisco-csr-1000v' -Name '16_12-byol' -Accept` in Cloud Shell for the target subscription. Error: $_" - } - #update csr bootstrap file - $csrConfigContent = Get-Content -Path .\csrScript.txt - $updatedCsrConfigContent = $csrConfigContent - $updatedCsrConfigContent = $updatedCsrConfigContent.Replace('**GW0_Public_IP**',$gw1pip) - $updatedCsrConfigContent = $updatedCsrConfigContent.Replace('**GW1_Public_IP**',$gw2pip) - $updatedCsrConfigContent = $updatedCsrConfigContent.Replace('**VNETGWASN**',$gwasn) - $updatedCsrConfigContent = $updatedCsrConfigContent.Replace('**GW0_Private_IP**',$gw1privateip) - $updatedCsrConfigContent = $updatedCsrConfigContent.Replace('**GW1_Private_IP**',$gw2privateip) - - Set-Content -Path .\csrScript.txt.tmp -Value $updatedCsrConfigContent -Force - - #deploy resources - $onPremJob = New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-onprem' -TemplateFile ./01-03-onprem.bicep -TemplateParameterObject @{vmPassword = $vmPassword; location = $location } -AsJob - - $onPremJob | Wait-Job | Out-Null - - # check for deployment errors - If ($onPremJob.Error) { - Write-Error "A on-prem infrastructure deployment experienced an error: $($onPremJob.error)" - } - - Write-Host "`tConfiguring VPN resources..." - - $vpnJobs = @() - $vpnJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./01-04-hubvpnconfig.bicep -TemplateParameterObject @{location = $location } -AsJob - - $vpnJobs | Wait-Job -Timeout 600 | Out-Null - - # check for deployment errors - If ($vpnJobs.Error) { - Write-Error "A VPN resource/configuration deployment experienced an error: $($vpnJobs.error)" - } - - Write-Host "`tConfiguring Cisco Hub CSR NVA resources..." - - $csrJobs = @() - $csrJobs += New-AzResourceGroupDeployment -ResourceGroupName 'wth-rg-hub' -TemplateFile ./01-05-csrnva.bicep -TemplateParameterObject @{vmPassword = $vmPassword;location = $location } -AsJob - - $csrJobs | Wait-Job -Timeout 600 | Out-Null - - # check for deployment errors - If ($csrJobs.Error) { - Write-Error "The Cisco CSR NVA resource/configuration deployment experienced an error: $($csrJobs.error)" - } - } - default { - Write-Error "Deployment of this challenge is not implemented" - } -} - -Pop-Location \ No newline at end of file From 4f5a504a59080ec7e41d07ed69a86e3956a92193 Mon Sep 17 00:00:00 2001 From: Matthew Bratschun Date: Wed, 12 Jul 2023 15:38:14 -0600 Subject: [PATCH 76/76] new-deployment --> new-subscriptiondeployment --- 035-HubAndSpoke/Coach/Solutions/bicep/deploy.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/035-HubAndSpoke/Coach/Solutions/bicep/deploy.ps1 b/035-HubAndSpoke/Coach/Solutions/bicep/deploy.ps1 index bf8e7eace8..61a374e136 100644 --- a/035-HubAndSpoke/Coach/Solutions/bicep/deploy.ps1 +++ b/035-HubAndSpoke/Coach/Solutions/bicep/deploy.ps1 @@ -82,7 +82,7 @@ switch ($challengeNumber) { } Write-Host "`tDeploying resource groups..." - New-AzDeployment -Location $location -Name "01-00-resourceGroups_$location" -TemplateFile ./01-00-resourceGroups.bicep + New-AzSubscriptionDeployment -Location $location -Name "01-00-resourceGroups_$location" -TemplateFile ./01-00-resourceGroups.bicep Write-Host "`tDeploying base resources (this will take up to 60 minutes for the VNET Gateway)..." $baseInfraJobs = @{}