Private/Deploy-Accelerator-Helpers/New-Bootstrap.ps1
|
function New-Bootstrap { [CmdletBinding(SupportsShouldProcess = $true)] param ( [Parameter(Mandatory = $false)] [string] $iac, [Parameter(Mandatory = $false)] [PSCustomObject] $bootstrapDetails, [Parameter(Mandatory = $false)] [PSCustomObject] $inputConfig, [Parameter(Mandatory = $false)] [string] $bootstrapTargetPath, [Parameter(Mandatory = $false)] [switch] $hasStarter, [Parameter(Mandatory = $false)] [string] $starterTargetPath, [Parameter(Mandatory = $false)] [PSCustomObject] $starterConfig = $null, [Parameter(Mandatory = $false)] [string] $bootstrapRelease, [Parameter(Mandatory = $false)] [string] $starterRelease, [Parameter(Mandatory = $false)] [switch] $autoApprove, [Parameter(Mandatory = $false)] [switch] $destroy, [Parameter(Mandatory = $false, HelpMessage = "An extra level of logging that is turned off by default for easier debugging.")] [switch] $writeVerboseLogs, [Parameter(Mandatory = $false)] [string] $hclParserToolPath, [Parameter(Mandatory = $false)] [switch] $convertTfvarsToJson, [Parameter(Mandatory = $false)] [string[]] $inputConfigFilePaths = @(), [Parameter(Mandatory = $false)] [string[]] $starterAdditionalFiles = @(), [Parameter(Mandatory = $false)] [switch] $cleanBootstrapFolder ) if ($PSCmdlet.ShouldProcess("ALZ-Terraform module configuration", "modify")) { $bootstrapPath = Join-Path $bootstrapTargetPath $bootstrapRelease $starterPath = Join-Path $starterTargetPath $starterRelease $bootstrapModulePath = Join-Path -Path $bootstrapPath -ChildPath $bootstrapDetails.Value.location if($cleanBootstrapFolder.IsPresent) { Write-Verbose "Cleaning bootstrap folder of Terraform meta files as requested..." Remove-TerraformMetaFileSet -path $bootstrapModulePath -writeVerboseLogs:$writeVerboseLogs.IsPresent -terraformFilesOrFoldersToRemove @( "terraform.tfstate.backup", ".terraform", "terraform.tfvars", ".terraform.lock.hcl" ) } Write-Verbose "Bootstrap Module Path: $bootstrapModulePath" # Run upgrade Invoke-FullUpgrade ` -bootstrapModuleFolder $bootstrapDetails.Value.location ` -bootstrapRelease $bootstrapRelease ` -bootstrapPath $bootstrapTargetPath ` -autoApprove:$autoApprove.IsPresent # Get starter module $starterModulePath = "" $starterRootModuleFolder = "" $starterRootModuleFolderPath = "" $starterFoldersToRetain = @() if ($hasStarter) { if (!$inputConfig.starter_module_name.Value) { Write-InformationColored "No starter module has been specified. Please supply the starter module you wish to deploy..." -ForegroundColor Red -InformationAction Continue throw "No starter module has been specified. Please supply the starter module you wish to deploy..." } $starter_module_name = $inputConfig.starter_module_name.Value.Trim() $chosenStarterConfig = $starterConfig.starter_modules.Value.$($starter_module_name) if($null -eq $chosenStarterConfig ) { Write-InformationColored "The starter module name '$($starter_module_name)' does not exist in the starter configuration. Please check your input and try again." -ForegroundColor Red -InformationAction Continue throw "The starter module name '$($starter_module_name)' does not exist in the starter configuration. Please check your input and try again." } Write-Verbose "Selected Starter: $starter_module_name" $starterModulePath = (Resolve-Path (Join-Path -Path $starterPath -ChildPath $chosenStarterConfig.location)).Path $starterRootModuleFolderPath = $starterModulePath Write-Verbose "Starter Module Path: $starterModulePath" if ($chosenStarterConfig.PSObject.Properties.Name -contains "additional_retained_folders") { $starterFoldersToRetain = $chosenStarterConfig.additional_retained_folders Write-Verbose "Starter Additional folders to retain: $($starterFoldersToRetain -join ",")" } if ($chosenStarterConfig.PSObject.Properties.Name -contains "root_module_folder") { $starterRootModuleFolder = $chosenStarterConfig.root_module_folder # Retain the root module folder $starterFoldersToRetain += $starterRootModuleFolder # Add the root module folder to bootstrap input config $inputConfig | Add-Member -NotePropertyName "root_module_folder_relative_path" -NotePropertyValue @{ Value = $starterRootModuleFolder Source = "calculated" Sensitive = $false } # Set the starter root module folder full path $starterRootModuleFolderPath = Join-Path -Path $starterModulePath -ChildPath $starterRootModuleFolder Write-Verbose "Starter root module folder: $starterRootModuleFolder" Write-Verbose "Starter final folders to retain: $($starterFoldersToRetain -join ",")" } } # Getting configuration for the bootstrap module user input $bootstrapParameters = [PSCustomObject]@{} Write-Verbose "Getting the bootstrap configuration..." $terraformFiles = Get-ChildItem -Path $bootstrapModulePath -Filter "*.tf" -File foreach ($terraformFile in $terraformFiles) { $bootstrapParameters = Convert-HCLVariablesToInputConfig -targetVariableFile $terraformFile.FullName -hclParserToolPath $hclParserToolPath -appendToObject $bootstrapParameters } Write-Verbose "Bootstrap Parameters before setting config: $(ConvertTo-Json $bootstrapParameters -Depth 100)" # Getting the configuration for the starter module user input $starterParameters = [PSCustomObject]@{} if ($hasStarter) { Write-Verbose "Getting the starter configuration..." if ($iac -eq "terraform") { $terraformFiles = Get-ChildItem -Path $starterRootModuleFolderPath -Filter "*.tf" -File foreach ($terraformFile in $terraformFiles) { $starterParameters = Convert-HCLVariablesToInputConfig -targetVariableFile $terraformFile.FullName -hclParserToolPath $hclParserToolPath -appendToObject $starterParameters } } if ($iac -like "bicep*") { $starterParameters = Convert-BicepConfigToInputConfig -bicepConfig $starterConfig.starter_modules.Value.$($inputConfig.starter_module_name.Value) } } # Set computed inputs $inputConfig | Add-Member -NotePropertyName "module_folder_path" -NotePropertyValue @{ Value = $starterModulePath Source = "calculated" Sensitive = $false } if ($iac -eq "bicep-classic" -and $inputConfig.PSObject.Properties.Name -contains "starter_locations") { # Get the supported regions and availability zones Write-Verbose "Getting Supported Regions and Availability Zones with Terraform" $regionsAndZones = Get-AzureRegionData -toolsPath $toolsPath Write-Verbose "Supported Regions: $($regionsAndZones.supportedRegions)" $zonesSupport = $regionsAndZones.zonesSupport $availabilityZonesStarter = @() foreach ($region in $inputConfig.starter_locations.Value) { $availabilityZonesStarter += , @(Get-AvailabilityZonesSupport -region $region -zonesSupport $zonesSupport) } $inputConfig | Add-Member -NotePropertyName "availability_zones_starter" -NotePropertyValue @{ Value = $availabilityZonesStarter Source = "calculated" Sensitive = $false } } Write-Verbose "Final Input config: $(ConvertTo-Json $inputConfig -Depth 100)" # Getting the input for the bootstrap module Write-Verbose "Setting the configuration for the bootstrap module..." $bootstrapConfiguration = Set-Config ` -configurationParameters $bootstrapParameters ` -inputConfig $inputConfig Write-Verbose "Final Bootstrap Parameters: $(ConvertTo-Json $bootstrapConfiguration -Depth 100)" # Getting the input for the starter module Write-Verbose "Setting the configuration for the starter module..." $starterConfiguration = Set-Config ` -configurationParameters $starterParameters ` -inputConfig $inputConfig ` -copyEnvVarToConfig Write-Verbose "Final Starter Parameters: $(ConvertTo-Json $starterConfiguration -Depth 100)" # Creating the tfvars files for the bootstrap and starter module $tfVarsFileName = "terraform.tfvars.json" $bootstrapTfvarsPath = Join-Path -Path $bootstrapModulePath -ChildPath $tfVarsFileName $starterTfvarsPath = Join-Path -Path $starterRootModuleFolderPath -ChildPath "terraform.tfvars.json" $starterBicepVarsFileName = "parameters.json" $starterBicepAllVarsFileName = "template-parameters.json" $starterBicepVarsPath = Join-Path -Path $starterModulePath -ChildPath $starterBicepVarsFileName $starterBicepAllVarsPath = Join-Path -Path $starterModulePath -ChildPath $starterBicepAllVarsFileName # Write the tfvars file for the bootstrap and starter module Write-TfvarsJsonFile -tfvarsFilePath $bootstrapTfvarsPath -configuration $bootstrapConfiguration if ($iac -eq "terraform") { if ($starterFoldersToRetain.Length -gt 0) { Write-Verbose "Removing unwanted folders from the starter module..." $folders = Get-ChildItem -Path $starterModulePath -Directory foreach ($folder in $folders) { if ($starterFoldersToRetain -notcontains $folder.Name) { Write-Verbose "Removing folder: $($folder.FullName)" Remove-Item -Path $folder.FullName -Recurse -Force } else { Write-Verbose "Retaining folder: $($folder.FullName)" Remove-TerraformMetaFileSet -path $folder.FullName -writeVerboseLogs:$writeVerboseLogs.IsPresent } } } Remove-TerraformMetaFileSet -path $starterModulePath -writeVerboseLogs:$writeVerboseLogs.IsPresent if ($convertTfvarsToJson) { Write-TfvarsJsonFile -tfvarsFilePath $starterTfvarsPath -configuration $starterConfiguration } else { $inputsFromTfvars = $inputConfig.PSObject.Properties | Where-Object { $_.Value.Source -eq ".tfvars" } | Select-Object -ExpandProperty Name Write-TfvarsJsonFile -tfvarsFilePath $starterTfvarsPath -configuration $starterConfiguration -skipItems $inputsFromTfvars foreach ($inputConfigFilePath in $inputConfigFilePaths | Where-Object { $_ -like "*.tfvars" }) { $fileName = [System.IO.Path]::GetFileName($inputConfigFilePath) $fileName = $fileName.Replace(".tfvars", ".auto.tfvars") $destination = Join-Path -Path $starterRootModuleFolderPath -ChildPath $fileName Write-Verbose "Copying tfvars file $inputConfigFilePath to $destination" Copy-Item -Path $inputConfigFilePath -Destination $destination -Force } } # Copy additional files foreach ($additionalFile in $starterAdditionalFiles) { if (Test-Path $additionalFile -PathType Container) { $folderName = ([System.IO.DirectoryInfo]::new($additionalFile)).Name $destination = Join-Path -Path $starterRootModuleFolderPath -ChildPath $folderName Write-Verbose "Copying folder $additionalFile to $destination" Copy-Item -Path "$additionalFile/*" -Destination $destination -Recurse -Force } else { $fileName = [System.IO.Path]::GetFileName($additionalFile) $destination = Join-Path -Path $starterRootModuleFolderPath -ChildPath $fileName Write-Verbose "Copying file $additionalFile to $destination" Copy-Item -Path $additionalFile -Destination $destination -Force } } } if ($iac -like "bicep*") { if($iac -ne "bicep") { Copy-ParametersFileCollection -starterPath $starterModulePath -configFiles $starterConfig.starter_modules.Value.$($inputConfig.starter_module_name.Value).deployment_files } Set-ComputedConfiguration -configuration $starterConfiguration Edit-ALZConfigurationFilesInPlace -alzEnvironmentDestination $starterModulePath -configuration $starterConfiguration Write-JsonFile -jsonFilePath $starterBicepVarsPath -configuration $starterConfiguration Write-JsonFile -jsonFilePath $starterBicepAllVarsPath -configuration @($inputConfig, $starterConfiguration, $bootstrapConfiguration) -all # Remove unrequired files $foldersOrFilesToRetain = $starterConfig.starter_modules.Value.$($inputConfig.starter_module_name.Value).folders_or_files_to_retain $foldersOrFilesToRetain += $starterBicepVarsFileName $foldersOrFilesToRetain += $starterBicepAllVarsFileName $foldersOrFilesToRetain += "config" $foldersOrFilesToRetain += ".config" foreach ($deployment_file in $starterConfig.starter_modules.Value.$($inputConfig.starter_module_name.Value).deployment_files) { $foldersOrFilesToRetain += $deployment_file.templateParametersSourceFilePath } $subFoldersOrFilesToRemove = $starterConfig.starter_modules.Value.$($inputConfig.starter_module_name.Value).subfolders_or_files_to_remove Remove-UnrequiredFileSet -path $starterModulePath -foldersOrFilesToRetain $foldersOrFilesToRetain -subFoldersOrFilesToRemove $subFoldersOrFilesToRemove -writeVerboseLogs:$writeVerboseLogs.IsPresent } # Running terraform init and apply Write-InformationColored "Thank you for providing those inputs, we are now initializing and applying Terraform to bootstrap your environment..." -ForegroundColor Green -NewLineBefore -InformationAction Continue # Get bootstrap_subscription_id from inputConfig if available $bootstrapSubscriptionId = "" if ($null -ne $inputConfig.bootstrap_subscription_id -and $null -ne $inputConfig.bootstrap_subscription_id.Value) { $bootstrapSubscriptionId = $inputConfig.bootstrap_subscription_id.Value } if ($autoApprove) { Invoke-Terraform -moduleFolderPath $bootstrapModulePath -autoApprove -destroy:$destroy.IsPresent -bootstrapSubscriptionId $bootstrapSubscriptionId } else { Write-InformationColored "Once the plan is complete you will be prompted to confirm the apply." -ForegroundColor Green -NewLineBefore -InformationAction Continue Invoke-Terraform -moduleFolderPath $bootstrapModulePath -destroy:$destroy.IsPresent -bootstrapSubscriptionId $bootstrapSubscriptionId } Write-InformationColored "Bootstrap has completed successfully! Thanks for using our tool. Head over to Phase 3 in the documentation to continue..." -ForegroundColor Green -NewLineBefore -InformationAction Continue } } # SIG # Begin signature block # MIIoUwYJKoZIhvcNAQcCoIIoRDCCKEACAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCD3cUM5Xx3QQPh/ # wiPihx8PZyTdAV7hN01Bxk1+MNja+6CCDYUwggYDMIID66ADAgECAhMzAAAEhJji # EuB4ozFdAAAAAASEMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMjUwNjE5MTgyMTM1WhcNMjYwNjE3MTgyMTM1WjB0MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQDtekqMKDnzfsyc1T1QpHfFtr+rkir8ldzLPKmMXbRDouVXAsvBfd6E82tPj4Yz # aSluGDQoX3NpMKooKeVFjjNRq37yyT/h1QTLMB8dpmsZ/70UM+U/sYxvt1PWWxLj # MNIXqzB8PjG6i7H2YFgk4YOhfGSekvnzW13dLAtfjD0wiwREPvCNlilRz7XoFde5 # KO01eFiWeteh48qUOqUaAkIznC4XB3sFd1LWUmupXHK05QfJSmnei9qZJBYTt8Zh # ArGDh7nQn+Y1jOA3oBiCUJ4n1CMaWdDhrgdMuu026oWAbfC3prqkUn8LWp28H+2S # LetNG5KQZZwvy3Zcn7+PQGl5AgMBAAGjggGCMIIBfjAfBgNVHSUEGDAWBgorBgEE # AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUBN/0b6Fh6nMdE4FAxYG9kWCpbYUw # VAYDVR0RBE0wS6RJMEcxLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJh # dGlvbnMgTGltaXRlZDEWMBQGA1UEBRMNMjMwMDEyKzUwNTM2MjAfBgNVHSMEGDAW # gBRIbmTlUAXTgqoXNzcitW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8v # d3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIw # MTEtMDctMDguY3JsMGEGCCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDov # L3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDEx # XzIwMTEtMDctMDguY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIB # AGLQps1XU4RTcoDIDLP6QG3NnRE3p/WSMp61Cs8Z+JUv3xJWGtBzYmCINmHVFv6i # 8pYF/e79FNK6P1oKjduxqHSicBdg8Mj0k8kDFA/0eU26bPBRQUIaiWrhsDOrXWdL # m7Zmu516oQoUWcINs4jBfjDEVV4bmgQYfe+4/MUJwQJ9h6mfE+kcCP4HlP4ChIQB # UHoSymakcTBvZw+Qst7sbdt5KnQKkSEN01CzPG1awClCI6zLKf/vKIwnqHw/+Wvc # Ar7gwKlWNmLwTNi807r9rWsXQep1Q8YMkIuGmZ0a1qCd3GuOkSRznz2/0ojeZVYh # ZyohCQi1Bs+xfRkv/fy0HfV3mNyO22dFUvHzBZgqE5FbGjmUnrSr1x8lCrK+s4A+ # bOGp2IejOphWoZEPGOco/HEznZ5Lk6w6W+E2Jy3PHoFE0Y8TtkSE4/80Y2lBJhLj # 27d8ueJ8IdQhSpL/WzTjjnuYH7Dx5o9pWdIGSaFNYuSqOYxrVW7N4AEQVRDZeqDc # fqPG3O6r5SNsxXbd71DCIQURtUKss53ON+vrlV0rjiKBIdwvMNLQ9zK0jy77owDy # XXoYkQxakN2uFIBO1UNAvCYXjs4rw3SRmBX9qiZ5ENxcn/pLMkiyb68QdwHUXz+1 # fI6ea3/jjpNPz6Dlc/RMcXIWeMMkhup/XEbwu73U+uz/MIIHejCCBWKgAwIBAgIK # YQ6Q0gAAAAAAAzANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNV # BAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv # c29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlm # aWNhdGUgQXV0aG9yaXR5IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEw # OTA5WjB+MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE # BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYD # VQQDEx9NaWNyb3NvZnQgQ29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG # 9w0BAQEFAAOCAg8AMIICCgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+la # UKq4BjgaBEm6f8MMHt03a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc # 6Whe0t+bU7IKLMOv2akrrnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4D # dato88tt8zpcoRb0RrrgOGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+ # lD3v++MrWhAfTVYoonpy4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nk # kDstrjNYxbc+/jLTswM9sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6 # A4aN91/w0FK/jJSHvMAhdCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmd # X4jiJV3TIUs+UsS1Vz8kA/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL # 5zmhD+kjSbwYuER8ReTBw3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zd # sGbiwZeBe+3W7UvnSSmnEyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3 # T8HhhUSJxAlMxdSlQy90lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS # 4NaIjAsCAwEAAaOCAe0wggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRI # bmTlUAXTgqoXNzcitW2oynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTAL # BgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBD # uRQFTuHqp8cx0SOJNDBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jv # c29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFf # MDNfMjIuY3JsMF4GCCsGAQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3 # dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFf # MDNfMjIuY3J0MIGfBgNVHSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEF # BQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1h # cnljcHMuaHRtMEAGCCsGAQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkA # YwB5AF8AcwB0AGEAdABlAG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn # 8oalmOBUeRou09h0ZyKbC5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7 # v0epo/Np22O/IjWll11lhJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0b # pdS1HXeUOeLpZMlEPXh6I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/ # KmtYSWMfCWluWpiW5IP0wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvy # CInWH8MyGOLwxS3OW560STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBp # mLJZiWhub6e3dMNABQamASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJi # hsMdYzaXht/a8/jyFqGaJ+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYb # BL7fQccOKO7eZS/sl/ahXJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbS # oqKfenoi+kiVH6v7RyOA9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sL # gOppO6/8MO0ETI7f33VtY5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtX # cVZOSEXAQsmbdlsKgEhr/Xmfwb1tbWrJUnMTDXpQzTGCGiQwghogAgEBMIGVMH4x # CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt # b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01p # Y3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTECEzMAAASEmOIS4HijMV0AAAAA # BIQwDQYJYIZIAWUDBAIBBQCggbAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw # HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIO5t # doDaHucKr1y/zng3d9KX86YbOIS0sopC40eouNglMEQGCisGAQQBgjcCAQwxNjA0 # oBSAEgBNAGkAYwByAG8AcwBvAGYAdKEcgBpodHRwczovL3d3dy5taWNyb3NvZnQu # Y29tIDANBgkqhkiG9w0BAQEFAASCAQA8PhxXjLq3m6BvrDUHCy+8BYjBV/Z6psyl # lhURpfFeJA4DH5FmgVsfd2MT0nCAHUhELJLPQgo/Jc4ARgdof6ggSCYrB/G3U66q # Mk2qYS0vErqJzZxzqXFG6QtFK/TALElNVrtcLsJv7hBmjvsUdth3ilLt1e+nf30L # ndulU6PgK09EUMUfksoeT/wozMhwBct7Nf7A1k6rnEOs89e1sMtJRQO2qaBHOj9B # BB7hJuM7pany4r0esriSgfJcUsByb+Sz2blJ+ZeYHczrW2eMIvihEn/QN39I/ndb # NAHV4R20cpL61SKANfdO6Pxa11DPtj2H4qprsOi6CQpvjJ/L/RBZoYIXrDCCF6gG # CisGAQQBgjcDAwExgheYMIIXlAYJKoZIhvcNAQcCoIIXhTCCF4ECAQMxDzANBglg # hkgBZQMEAgEFADCCAVkGCyqGSIb3DQEJEAEEoIIBSASCAUQwggFAAgEBBgorBgEE # AYRZCgMBMDEwDQYJYIZIAWUDBAIBBQAEIDmBtIbkV78ac5CUEaYgK9cB9/4HyLkd # FiOcsspHKMKbAgZpQxanhHIYEjIwMjYwMTA5MTMwNjE1LjU0WjAEgAIB9KCB2aSB # 1jCB0zELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT # B1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEtMCsGA1UE # CxMkTWljcm9zb2Z0IElyZWxhbmQgT3BlcmF0aW9ucyBMaW1pdGVkMScwJQYDVQQL # Ex5uU2hpZWxkIFRTUyBFU046NDAxQS0wNUUwLUQ5NDcxJTAjBgNVBAMTHE1pY3Jv # c29mdCBUaW1lLVN0YW1wIFNlcnZpY2WgghH7MIIHKDCCBRCgAwIBAgITMwAAAhle # sthUdfSxjQABAAACGTANBgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJVUzETMBEG # A1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWlj # cm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFt # cCBQQ0EgMjAxMDAeFw0yNTA4MTQxODQ4MjZaFw0yNjExMTMxODQ4MjZaMIHTMQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNy # b3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJzAlBgNVBAsTHm5TaGll # bGQgVFNTIEVTTjo0MDFBLTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9zb2Z0IFRp # bWUtU3RhbXAgU2VydmljZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB # AKahSMlJMyMsaS90NN1pi7suBvWCFEnM54Sq/nBzk/v7uz2q8SPeoMcW9Vq1rgMQ # fKoxi37GyJsfFd6LitZ1HH/kf57J12rOf4k4Ff05d0E0Rk9A3rlwTW6R6nPsAtTY # k8gO+oC54q70gRKAc5a6TUBRJ7sHWzywi6U0tylkgruSdNm/kRVkf5HBc1cZ4aBN # 4CGnlEbaxihgWRiiwV76oIJAxDbSpL7b0U99sS7wLy/0aUXruc9fGaIwrO9mUqGu # +A8vGG2lrA5tzmTqSUWcWbDygh2esTaoBSn9MTR49Lfb9EN1vts+YAFWmrCSQr0e # dkpdFydgDn95dC0nrV4FAOYA+SENUbxLJU5jZ0qLk6xiA9w9Z42O5gbtKboiHTyt # oyv9Vnnn9vmEeHEKVkJHgWZl4nYfQLlnZcMSkC9eSyeitncPMv7fzwYZi8rekAH9 # AnqVkXYGZzMrVQFLlh8JWUVfSS2O2l/A+eXi/fnDi6V92xjTpjduFKSFvKrWWql2 # nrBbyDlttyTS4WmkFbzm69XruxhP+TJ+N3vvw27XWJf2yz9iENcWBCXUm3FJAxX1 # typWRIfpwSg7WkZzUZG4CIMSGynU9/DikMGf2gOLkrIgIOpxD4lgRxrsrSKOcFO+ # TOVXY4RKqkx312LvASYuhk871k/vXpHzF3s6gpJLMWhvAgMBAAGjggFJMIIBRTAd # BgNVHQ4EFgQUgGjqOR1mrTc6mZ9SBdX3A+p69yEwHwYDVR0jBBgwFoAUn6cVXQBe # Yl2D9OXSZacbUzUZ6XIwXwYDVR0fBFgwVjBUoFKgUIZOaHR0cDovL3d3dy5taWNy # b3NvZnQuY29tL3BraW9wcy9jcmwvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBD # QSUyMDIwMTAoMSkuY3JsMGwGCCsGAQUFBwEBBGAwXjBcBggrBgEFBQcwAoZQaHR0 # cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNyb3NvZnQlMjBU # aW1lLVN0YW1wJTIwUENBJTIwMjAxMCgxKS5jcnQwDAYDVR0TAQH/BAIwADAWBgNV # HSUBAf8EDDAKBggrBgEFBQcDCDAOBgNVHQ8BAf8EBAMCB4AwDQYJKoZIhvcNAQEL # BQADggIBAF8c1WSy1wRX6Aggk4mOzB13W+3IryUk36x2CQuTpNjTe+Tac0zE/Vdk # 3CEI30NwBVG4dTQQGLTFLsMQug+HHhFxuZVwJ275AvWI3i1Q0ciJl2GJn7e8/kKZ # fbdwv/GtLYqpzs/FHvPw2C7TE4L1jJ7KizYyCw2iJjn5xyN+kywoxhXvEWC1xnQl # HTi5XwHTBnj8UkwN0wADnPhkG5j1o64Li1m8b55dzVY0b6wWVZMRTKFWR9H+6hsA # zkoY6Z7+Z2J0OPLny9Lgc+dkWzxnV+Bb/flBjqwaa5nB85iLrRbSXnNmOJLozbUy # tsARoFrHBDlYRYmlXY3vFSyezFTShOU5rLhjN40y69Z7keQBRrN1CpD+4N3EA+HB # yu13S4k5u3utOkCflqnkLAA2BPXb1PcCFGyPQ5eFHCBKxcPhR2lkk65HyeEry5oS # p5eZIYaSdbBd8+ntQcXqVJYlx6s0S4h1ooViFhEhfCBxJRdzzsWz+FSahwYmL2lz # FdEskYMKA+s13XW1J1/VkeiS9gZagI4x8SDcHpbKf1YcQFk4c7jAOfC8bxP1QM43 # xReFpu2tWQC5iVcN6C/7P7saNTqeLXE/oX2fbjdYbQtSTeA7kahXy7bY7qAJlEKG # zuc1BUc7wp/ApP4Yjvm80debKpI5cSzMjI6ZHP3n+ElFIpA+OvL1MIIHcTCCBVmg # AwIBAgITMwAAABXF52ueAptJmQAAAAAAFTANBgkqhkiG9w0BAQsFADCBiDELMAkG # A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx # HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9z # b2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTAwHhcNMjEwOTMwMTgy # MjI1WhcNMzAwOTMwMTgzMjI1WjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2Fz # aGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENv # cnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAx # MDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAOThpkzntHIhC3miy9ck # eb0O1YLT/e6cBwfSqWxOdcjKNVf2AX9sSuDivbk+F2Az/1xPx2b3lVNxWuJ+Slr+ # uDZnhUYjDLWNE893MsAQGOhgfWpSg0S3po5GawcU88V29YZQ3MFEyHFcUTE3oAo4 # bo3t1w/YJlN8OWECesSq/XJprx2rrPY2vjUmZNqYO7oaezOtgFt+jBAcnVL+tuhi # JdxqD89d9P6OU8/W7IVWTe/dvI2k45GPsjksUZzpcGkNyjYtcI4xyDUoveO0hyTD # 4MmPfrVUj9z6BVWYbWg7mka97aSueik3rMvrg0XnRm7KMtXAhjBcTyziYrLNueKN # iOSWrAFKu75xqRdbZ2De+JKRHh09/SDPc31BmkZ1zcRfNN0Sidb9pSB9fvzZnkXf # tnIv231fgLrbqn427DZM9ituqBJR6L8FA6PRc6ZNN3SUHDSCD/AQ8rdHGO2n6Jl8 # P0zbr17C89XYcz1DTsEzOUyOArxCaC4Q6oRRRuLRvWoYWmEBc8pnol7XKHYC4jMY # ctenIPDC+hIK12NvDMk2ZItboKaDIV1fMHSRlJTYuVD5C4lh8zYGNRiER9vcG9H9 # stQcxWv2XFJRXRLbJbqvUAV6bMURHXLvjflSxIUXk8A8FdsaN8cIFRg/eKtFtvUe # h17aj54WcmnGrnu3tz5q4i6tAgMBAAGjggHdMIIB2TASBgkrBgEEAYI3FQEEBQID # AQABMCMGCSsGAQQBgjcVAgQWBBQqp1L+ZMSavoKRPEY1Kc8Q/y8E7jAdBgNVHQ4E # FgQUn6cVXQBeYl2D9OXSZacbUzUZ6XIwXAYDVR0gBFUwUzBRBgwrBgEEAYI3TIN9 # AQEwQTA/BggrBgEFBQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9w # cy9Eb2NzL1JlcG9zaXRvcnkuaHRtMBMGA1UdJQQMMAoGCCsGAQUFBwMIMBkGCSsG # AQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTAD # AQH/MB8GA1UdIwQYMBaAFNX2VsuP6KJcYmjRPZSQW9fOmhjEMFYGA1UdHwRPME0w # S6BJoEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3Rz # L01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNybDBaBggrBgEFBQcBAQROMEwwSgYI # KwYBBQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWlj # Um9vQ2VyQXV0XzIwMTAtMDYtMjMuY3J0MA0GCSqGSIb3DQEBCwUAA4ICAQCdVX38 # Kq3hLB9nATEkW+Geckv8qW/qXBS2Pk5HZHixBpOXPTEztTnXwnE2P9pkbHzQdTlt # uw8x5MKP+2zRoZQYIu7pZmc6U03dmLq2HnjYNi6cqYJWAAOwBb6J6Gngugnue99q # b74py27YP0h1AdkY3m2CDPVtI1TkeFN1JFe53Z/zjj3G82jfZfakVqr3lbYoVSfQ # JL1AoL8ZthISEV09J+BAljis9/kpicO8F7BUhUKz/AyeixmJ5/ALaoHCgRlCGVJ1 # ijbCHcNhcy4sa3tuPywJeBTpkbKpW99Jo3QMvOyRgNI95ko+ZjtPu4b6MhrZlvSP # 9pEB9s7GdP32THJvEKt1MMU0sHrYUP4KWN1APMdUbZ1jdEgssU5HLcEUBHG/ZPkk # vnNtyo4JvbMBV0lUZNlz138eW0QBjloZkWsNn6Qo3GcZKCS6OEuabvshVGtqRRFH # qfG3rsjoiV5PndLQTHa1V1QJsWkBRH58oWFsc/4Ku+xBZj1p/cvBQUl+fpO+y/g7 # 5LcVv7TOPqUxUYS8vwLBgqJ7Fx0ViY1w/ue10CgaiQuPNtq6TPmb/wrpNPgkNWcr # 4A245oyZ1uEi6vAnQj0llOZ0dFtq0Z4+7X6gMTN9vMvpe784cETRkPHIqzqKOghi # f9lwY1NNje6CbaUFEMFxBmoQtB1VM1izoXBm8qGCA1YwggI+AgEBMIIBAaGB2aSB # 1jCB0zELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT # B1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEtMCsGA1UE # CxMkTWljcm9zb2Z0IElyZWxhbmQgT3BlcmF0aW9ucyBMaW1pdGVkMScwJQYDVQQL # Ex5uU2hpZWxkIFRTUyBFU046NDAxQS0wNUUwLUQ5NDcxJTAjBgNVBAMTHE1pY3Jv # c29mdCBUaW1lLVN0YW1wIFNlcnZpY2WiIwoBATAHBgUrDgMCGgMVADF2Kf1qqncm # 9Hp4oKy38ZdCJwM+oIGDMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh # c2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD # b3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIw # MTAwDQYJKoZIhvcNAQELBQACBQDtCz3MMCIYDzIwMjYwMTA5MDg0MTQ4WhgPMjAy # NjAxMTAwODQxNDhaMHQwOgYKKwYBBAGEWQoEATEsMCowCgIFAO0LPcwCAQAwBwIB # AAICE5cwBwIBAAICEu8wCgIFAO0Mj0wCAQAwNgYKKwYBBAGEWQoEAjEoMCYwDAYK # KwYBBAGEWQoDAqAKMAgCAQACAwehIKEKMAgCAQACAwGGoDANBgkqhkiG9w0BAQsF # AAOCAQEAVCyMKQbtVe4ODO9GQn3EfSRDmk+NXxq7hDZGX/3UMWI8BLVK06nxe94i # YrMA9HydGiGw45OfY9mYcCpBsEXMXE52GRUd3a9VHjSvzTmPnKdkmCthcPsxvmE3 # HNNk6Oh1vZdQkrC7lKgIfz2VRUIGNeI4XiyeN5gdtGOnXHDwPCdA2EF1sQ6RaZoo # 4rO/O2lPui4zFXMkX0D0er8/dFVhbkhHvyuUjs7odfvicBq+oNwWBWYl5SmKXhDn # ronmUqeBwGn8SCqSTzdW3ULO8KxrNXmmbfb6drxfQa/fipZlzLs7zywjZ9THY0+w # ypmnqMeyrW8zeNKdevFtBe71CjTfPTGCBA0wggQJAgEBMIGTMHwxCzAJBgNVBAYT # AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD # VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBU # aW1lLVN0YW1wIFBDQSAyMDEwAhMzAAACGV6y2FR19LGNAAEAAAIZMA0GCWCGSAFl # AwQCAQUAoIIBSjAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwLwYJKoZIhvcN # AQkEMSIEIJ42aMidbCNpKVMcDr6vOaKJo0lpGd5wyBup3R63MOpbMIH6BgsqhkiG # 9w0BCRACLzGB6jCB5zCB5DCBvQQg3JF+t9xNctRBd9ldfM0HK7II8yPfty3u5pb5 # Njnm7YYwgZgwgYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv # bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0 # aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAA # AhlesthUdfSxjQABAAACGTAiBCAgkNc5v9JxrD+YEQ+qe38k1GfnBbKBAMOtxUcc # ua8D5jANBgkqhkiG9w0BAQsFAASCAgBdv7VOegg7iRxfiC6VPCLAZxOKzPwU7LVn # AJPW30DO+vzpuHBSy2Rj1EXE//3l9FFgunp9SXvGeV9ppHsuunsKD9Tgu/UKX68i # SKt0ffIcQQe9qZHsUUD/5BPB4PsMlmvj1IND0S9Lls2dzKts/yrOfxJXFBIbYFMT # RRfSxQ8riI8UjIjPbkuX3MgUVqXraj7zGbQsfOjPRL0GT4WnMukvyqZrVAUL8+Mm # RwpywtW0gb7juIG5tRHhZJ7pjVbPU6xpGQDq7ZviIZJUUtaF48H3ElE7M6poM1lq # ZjbSgRQW/gBeCJMTtcoxO/HS9IQOVfX3nkOlosy9mUQIoczhJ2jM4MUUVO3pz7Kd # r9MAVsu7Sv4sMFqDeJb1WihroHfl8uGkEGZ602Y5XJ7LZ8ltNdn0kPlswYyYTB/I # KdEAt9I+8nvMhofxW5oDaY42WfXQYpmSM8Z8r0C9iw8Z8LFPsyEtWwFkRKRH80wz # JnhihlH14auVR4TXLLA65vNKTAv9C96eeAJmLpLL20mHYR2B895cND9Mqzm1uVEf # Px1HPU6On53arYYqGmAhxbVL1qI7Jc0BuCsHMgOlU/lDpBa+7tB3cWyMFFB27ClL # 7cfcrsYj8LS47LlZ+tQHcTulyXV+yIZwofRFvW3scCGjCUJR52i4rM9gku3QWHyH # hctSWzZgWw== # SIG # End signature block |