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] $validationConfig,

        [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)]
        [PSCustomObject] $zonesSupport = $null,

        [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 = @()
    )

    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

        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 -eq "") {
                $inputConfig.starter_module_name = @{
                    Value  = Request-SpecialInput -type "starter" -starterConfig $starterConfig
                    Source = "user"
                }
            }

            $chosenStarterConfig = $starterConfig.starter_modules.Value.$($inputConfig.starter_module_name.Value)

            Write-Verbose "Selected Starter: $($inputConfig.starter_module_name.Value))"
            $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 = "caluated"
                }

                # 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 -validators $validationConfig -appendToObject $bootstrapParameters
        }

        # 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 -validators $validationConfig -appendToObject $starterParameters
                }
            }

            if($iac -eq "bicep") {
                $starterParameters = Convert-BicepConfigToInputConfig -bicepConfig $starterConfig.starter_modules.Value.$($inputConfig.starter_module_name.Value) -validators $validationConfig
            }
        }

        # Set computed inputs
        $inputConfig | Add-Member -NotePropertyName "module_folder_path" -NotePropertyValue @{
            Value  = $starterModulePath
            Source = "calculated"
        }
        $inputConfig | Add-Member -NotePropertyName "availability_zones_bootstrap" -NotePropertyValue @{
            Value  = @(Get-AvailabilityZonesSupport -region $inputConfig.bootstrap_location.Value -zonesSupport $zonesSupport)
            Source = "calculated"
        }

        if($inputConfig.PSObject.Properties.Name -contains "starter_location" -and $inputConfig.PSObject.Properties.Name -notcontains "starter_locations") {
            Write-Verbose "Converting starter_location $($inputConfig.starter_location.Value) to starter_locations..."
            $inputConfig | Add-Member -NotePropertyName "starter_locations" -NotePropertyValue @{
                Value  = @($inputConfig.starter_location.Value)
                Source = "calculated"
            }
        }

        if($inputConfig.PSObject.Properties.Name -contains "starter_locations") {
            $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"
            }
        }

        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

        # 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 $starterParameters -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"
        $starterBicepVarsPath = Join-Path -Path $starterModulePath -ChildPath "parameters.json"

        # 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 -eq "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

            # Remove unrequired files
            $foldersOrFilesToRetain = $starterConfig.starter_modules.Value.$($inputConfig.starter_module_name.Value).folders_or_files_to_retain
            $foldersOrFilesToRetain += "parameters.json"
            $foldersOrFilesToRetain += "config"
            $foldersOrFilesToRetain += "starter-cache.json"

            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

        if($autoApprove) {
            Invoke-Terraform -moduleFolderPath $bootstrapModulePath -autoApprove -destroy:$destroy.IsPresent
        } 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
        }

        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
# MIIoSAYJKoZIhvcNAQcCoIIoOTCCKDUCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCD1fc+JByEEmL7O
# 3FWAz7MkFDraL56kxvdgmRe5lGsbgKCCDXYwggX0MIID3KADAgECAhMzAAAEhV6Z
# 7A5ZL83XAAAAAASFMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
# bmcgUENBIDIwMTEwHhcNMjUwNjE5MTgyMTM3WhcNMjYwNjE3MTgyMTM3WjB0MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQDASkh1cpvuUqfbqxele7LCSHEamVNBfFE4uY1FkGsAdUF/vnjpE1dnAD9vMOqy
# 5ZO49ILhP4jiP/P2Pn9ao+5TDtKmcQ+pZdzbG7t43yRXJC3nXvTGQroodPi9USQi
# 9rI+0gwuXRKBII7L+k3kMkKLmFrsWUjzgXVCLYa6ZH7BCALAcJWZTwWPoiT4HpqQ
# hJcYLB7pfetAVCeBEVZD8itKQ6QA5/LQR+9X6dlSj4Vxta4JnpxvgSrkjXCz+tlJ
# 67ABZ551lw23RWU1uyfgCfEFhBfiyPR2WSjskPl9ap6qrf8fNQ1sGYun2p4JdXxe
# UAKf1hVa/3TQXjvPTiRXCnJPAgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUuCZyGiCuLYE0aU7j5TFqY05kko0w
# RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW
# MBQGA1UEBRMNMjMwMDEyKzUwNTM1OTAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci
# tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG
# CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu
# Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0
# MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBACjmqAp2Ci4sTHZci+qk
# tEAKsFk5HNVGKyWR2rFGXsd7cggZ04H5U4SV0fAL6fOE9dLvt4I7HBHLhpGdE5Uj
# Ly4NxLTG2bDAkeAVmxmd2uKWVGKym1aarDxXfv3GCN4mRX+Pn4c+py3S/6Kkt5eS
# DAIIsrzKw3Kh2SW1hCwXX/k1v4b+NH1Fjl+i/xPJspXCFuZB4aC5FLT5fgbRKqns
# WeAdn8DsrYQhT3QXLt6Nv3/dMzv7G/Cdpbdcoul8FYl+t3dmXM+SIClC3l2ae0wO
# lNrQ42yQEycuPU5OoqLT85jsZ7+4CaScfFINlO7l7Y7r/xauqHbSPQ1r3oIC+e71
# 5s2G3ClZa3y99aYx2lnXYe1srcrIx8NAXTViiypXVn9ZGmEkfNcfDiqGQwkml5z9
# nm3pWiBZ69adaBBbAFEjyJG4y0a76bel/4sDCVvaZzLM3TFbxVO9BQrjZRtbJZbk
# C3XArpLqZSfx53SuYdddxPX8pvcqFuEu8wcUeD05t9xNbJ4TtdAECJlEi0vvBxlm
# M5tzFXy2qZeqPMXHSQYqPgZ9jvScZ6NwznFD0+33kbzyhOSz/WuGbAu4cHZG8gKn
# lQVT4uA2Diex9DMs2WHiokNknYlLoUeWXW1QrJLpqO82TLyKTbBM/oZHAdIc0kzo
# STro9b3+vjn2809D0+SOOCVZMIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq
# hkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x
# EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv
# bjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
# IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEwOTA5WjB+MQswCQYDVQQG
# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQg
# Q29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
# CgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+laUKq4BjgaBEm6f8MMHt03
# a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc6Whe0t+bU7IKLMOv2akr
# rnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4Ddato88tt8zpcoRb0Rrrg
# OGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+lD3v++MrWhAfTVYoonpy
# 4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDstrjNYxbc+/jLTswM9
# sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6A4aN91/w0FK/jJSHvMAh
# dCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmdX4jiJV3TIUs+UsS1Vz8k
# A/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL5zmhD+kjSbwYuER8ReTB
# w3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zdsGbiwZeBe+3W7UvnSSmn
# Eyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3T8HhhUSJxAlMxdSlQy90
# lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS4NaIjAsCAwEAAaOCAe0w
# ggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTlUAXTgqoXNzcitW2o
# ynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYD
# VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQFTuHqp8cx0SOJNDBa
# BgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2Ny
# bC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3JsMF4GCCsG
# AQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3dy5taWNyb3NvZnQuY29t
# L3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3J0MIGfBgNV
# HSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEFBQcCARYzaHR0cDovL3d3
# dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1hcnljcHMuaHRtMEAGCCsG
# AQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5AF8AcwB0AGEAdABl
# AG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn8oalmOBUeRou09h0ZyKb
# C5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7v0epo/Np22O/IjWll11l
# hJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0bpdS1HXeUOeLpZMlEPXh6
# I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtYSWMfCWluWpiW5IP0
# wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvyCInWH8MyGOLwxS3OW560
# STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZiWhub6e3dMNABQam
# ASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJihsMdYzaXht/a8/jyFqGa
# J+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYbBL7fQccOKO7eZS/sl/ah
# XJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKfenoi+kiVH6v7RyOA
# 9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOppO6/8MO0ETI7f33Vt
# Y5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZOSEXAQsmbdlsKgEhr
# /Xmfwb1tbWrJUnMTDXpQzTGCGigwghokAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw
# EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
# aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp
# Z25pbmcgUENBIDIwMTECEzMAAASFXpnsDlkvzdcAAAAABIUwDQYJYIZIAWUDBAIB
# BQCggbAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO
# MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIFE7NcsF57ghH5V/Q8+Jx3yY
# V0rWgtdhx0rnrHVtdb6MMEQGCisGAQQBgjcCAQwxNjA0oBSAEgBNAGkAYwByAG8A
# cwBvAGYAdKEcgBpodHRwczovL3d3dy5taWNyb3NvZnQuY29tIDANBgkqhkiG9w0B
# AQEFAASCAQCtQIGA4bfOieBQYppPWj8Y1hdcOee1uoDebwjAxg1t2blR118bEejC
# M1FJnBBYF7gcUhoC8UB5xz3V4x4aVoP7BRJVfMkAaOj6/nNhf5rsVUzqyoXcQ2YV
# 3OdtC61LkFzyhu6ct56rOPhGX3QVE9Zz/33+kBUwGoo6c7mEy5qLHxXupEIwyWSu
# KH411rS77DW5NWAazKC235lcrWHHKZTgWScYjsQNgrF3G+ZmYNPrODdMJIZ/GB39
# +eyQKYp6mLwtexXmvKnhvRe1UVcol+4NJaYUPRvo/XiuXW4JX8+n6aRIrHb6+Jkn
# WyW9sKBGY3hihLRfC73sCeuIPyTH6o5ToYIXsDCCF6wGCisGAQQBgjcDAwExghec
# MIIXmAYJKoZIhvcNAQcCoIIXiTCCF4UCAQMxDzANBglghkgBZQMEAgEFADCCAVoG
# CyqGSIb3DQEJEAEEoIIBSQSCAUUwggFBAgEBBgorBgEEAYRZCgMBMDEwDQYJYIZI
# AWUDBAIBBQAEIKd2I88KOXp9TcW0DDFTGbi6tCdl5FZhvVb6rxGoJwTjAgZoo62Z
# 4wkYEzIwMjUwOTE2MTMzMTU1Ljc4NFowBIACAfSggdmkgdYwgdMxCzAJBgNVBAYT
# AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD
# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29mdCBJ
# cmVsYW5kIE9wZXJhdGlvbnMgTGltaXRlZDEnMCUGA1UECxMeblNoaWVsZCBUU1Mg
# RVNOOjJEMUEtMDVFMC1EOTQ3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFt
# cCBTZXJ2aWNloIIR/jCCBygwggUQoAMCAQICEzMAAAH9c/loWs0MYe0AAQAAAf0w
# DQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0
# b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3Jh
# dGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwHhcN
# MjQwNzI1MTgzMTE2WhcNMjUxMDIyMTgzMTE2WjCB0zELMAkGA1UEBhMCVVMxEzAR
# BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p
# Y3Jvc29mdCBDb3Jwb3JhdGlvbjEtMCsGA1UECxMkTWljcm9zb2Z0IElyZWxhbmQg
# T3BlcmF0aW9ucyBMaW1pdGVkMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046MkQx
# QS0wNUUwLUQ5NDcxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZp
# Y2UwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQChZaz4P467gmNidEdF
# 527QxMVjM0kRU+cgvNzTZHepue6O+FmCSGn6n+XKZgvORDIbbOnFhx5OMgXseJBZ
# u3oVbcBGQGu2ElTPTlmcqlwXfWWlQRvyBReIPbEimjxgz5IPRL6FM/VMID/B7fzJ
# ncES2Zm1xWdotGn8C+yqD7kojQrDpMMmkrBMuXRVbT/bewqKR5YNKcdB5Oms7TMi
# b9u1qBJibdX/zNeV/HLuz8RUV1KCUcaxSrwRm6lQ7xdsfPPu1RHKIPeQ7E2fDmjH
# V5lf9z9eZbgfpvjI2ZkXTBNm7DfvIDU8ko7JJKtetYSH4fr75Zvr7WW0wI+gwkdS
# 08/cKfQI1w2+s/Im0NpyqOchOsvOuwd04uqOwfbb1mS+d2TQirEENmAyhj4R/t98
# VE/ak+SsXUX0hwGRjPyEv5CNf67jLhSqrhS1PtVGeyq9H/H/5AsTSlxISH9cTXDV
# 9ynomarxGccReKTJwws39r8pjGlI/cV8Vstm5/6oivIUvSAQPK1qkafU42NWSIql
# U/a6pUhiPhWIKPLmktRx4x6qIqBiqGmZQcITZaywsuF1AEd2mXbz6T5ljqbh08Wc
# SgZwke4xwhmfDhw7CLGiNE6v42rvVwmPtDgvRfA++5MdC3SgftEoxCCazLsJUPu/
# nl06F0dd1izI7r10B0r6daXJhwIDAQABo4IBSTCCAUUwHQYDVR0OBBYEFOkMxcDh
# lbz7Ivb7e8DpGZTugQqkMB8GA1UdIwQYMBaAFJ+nFV0AXmJdg/Tl0mWnG1M1Gely
# MF8GA1UdHwRYMFYwVKBSoFCGTmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lv
# cHMvY3JsL01pY3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNy
# bDBsBggrBgEFBQcBAQRgMF4wXAYIKwYBBQUHMAKGUGh0dHA6Ly93d3cubWljcm9z
# b2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBD
# QSUyMDIwMTAoMSkuY3J0MAwGA1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYB
# BQUHAwgwDgYDVR0PAQH/BAQDAgeAMA0GCSqGSIb3DQEBCwUAA4ICAQBj2Fhf5PkC
# YKtgZof3pN1HlPnb8804bvJJh6im/h+WcNZAuEGWtq8CD6mOU2/ldJdmsoa/x7iz
# l0nlZ2F8L3LAVCrhOZedR689e2W5tmT7TYFcrr/beEzRNIqzYqWFiKrNtF7xBsx8
# pcQO28ygdJlPuv7AjYiCNhDCRr7c/1VeARHC7jr9zPPwhH9mr687nnbcmV3qyxW7
# Oz27AismF9xgGPnSZdZEFwyHNqMuNYOByKHQO7KQ9wGmhMuU4vwuleiiqev5AtgT
# gGlR6ncnJIxh8/PaF84veDTZYR+w7GnwA1tx2KozfV2be9KF4SSaMcDbO4z5OCfi
# Pmf4CfLsg4NhCQis1WEt0wvT167V0g+GnbiUW2dZNg1oVM58yoVrcBvwoMqJyanQ
# C2FE1lWDQE8Avnz4HRRygEYrNL2OxzA5O7UmY2WKw4qRVRWRInkWj9y18NI90JNV
# ohdcXuXjSTVwz9fY7Ql0BL3tPvyViO3D8/Ju7NfmyHEGH9GpM+8LICEjEFUp83+F
# +zgIigVqpYnSv/xIHUIazLIhw98SAyjxx6rXDlmjQl+fIWLoa6j7Pcs8WX97FBpG
# 5sSuwBRN/IFjn/mWLK+MCDINicQHy8c7tzsWDa0Z3mEaBiz4A6hbHbj5dzLGlSQB
# qMOGTL0OX7wllOO2zoFxP2xhOY6h2T9KAjCCB3EwggVZoAMCAQICEzMAAAAVxedr
# ngKbSZkAAAAAABUwDQYJKoZIhvcNAQELBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRp
# ZmljYXRlIEF1dGhvcml0eSAyMDEwMB4XDTIxMDkzMDE4MjIyNVoXDTMwMDkzMDE4
# MzIyNVowfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNV
# BAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQG
# A1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwggIiMA0GCSqGSIb3
# DQEBAQUAA4ICDwAwggIKAoICAQDk4aZM57RyIQt5osvXJHm9DtWC0/3unAcH0qls
# TnXIyjVX9gF/bErg4r25PhdgM/9cT8dm95VTcVrifkpa/rg2Z4VGIwy1jRPPdzLA
# EBjoYH1qUoNEt6aORmsHFPPFdvWGUNzBRMhxXFExN6AKOG6N7dcP2CZTfDlhAnrE
# qv1yaa8dq6z2Nr41JmTamDu6GnszrYBbfowQHJ1S/rboYiXcag/PXfT+jlPP1uyF
# Vk3v3byNpOORj7I5LFGc6XBpDco2LXCOMcg1KL3jtIckw+DJj361VI/c+gVVmG1o
# O5pGve2krnopN6zL64NF50ZuyjLVwIYwXE8s4mKyzbnijYjklqwBSru+cakXW2dg
# 3viSkR4dPf0gz3N9QZpGdc3EXzTdEonW/aUgfX782Z5F37ZyL9t9X4C626p+Nuw2
# TPYrbqgSUei/BQOj0XOmTTd0lBw0gg/wEPK3Rxjtp+iZfD9M269ewvPV2HM9Q07B
# MzlMjgK8QmguEOqEUUbi0b1qGFphAXPKZ6Je1yh2AuIzGHLXpyDwwvoSCtdjbwzJ
# NmSLW6CmgyFdXzB0kZSU2LlQ+QuJYfM2BjUYhEfb3BvR/bLUHMVr9lxSUV0S2yW6
# r1AFemzFER1y7435UsSFF5PAPBXbGjfHCBUYP3irRbb1Hode2o+eFnJpxq57t7c+
# auIurQIDAQABo4IB3TCCAdkwEgYJKwYBBAGCNxUBBAUCAwEAATAjBgkrBgEEAYI3
# FQIEFgQUKqdS/mTEmr6CkTxGNSnPEP8vBO4wHQYDVR0OBBYEFJ+nFV0AXmJdg/Tl
# 0mWnG1M1GelyMFwGA1UdIARVMFMwUQYMKwYBBAGCN0yDfQEBMEEwPwYIKwYBBQUH
# AgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0
# b3J5Lmh0bTATBgNVHSUEDDAKBggrBgEFBQcDCDAZBgkrBgEEAYI3FAIEDB4KAFMA
# dQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAW
# gBTV9lbLj+iiXGJo0T2UkFvXzpoYxDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8v
# Y3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRf
# MjAxMC0wNi0yMy5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRw
# Oi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEw
# LTA2LTIzLmNydDANBgkqhkiG9w0BAQsFAAOCAgEAnVV9/Cqt4SwfZwExJFvhnnJL
# /Klv6lwUtj5OR2R4sQaTlz0xM7U518JxNj/aZGx80HU5bbsPMeTCj/ts0aGUGCLu
# 6WZnOlNN3Zi6th542DYunKmCVgADsAW+iehp4LoJ7nvfam++Kctu2D9IdQHZGN5t
# ggz1bSNU5HhTdSRXud2f8449xvNo32X2pFaq95W2KFUn0CS9QKC/GbYSEhFdPSfg
# QJY4rPf5KYnDvBewVIVCs/wMnosZiefwC2qBwoEZQhlSdYo2wh3DYXMuLGt7bj8s
# CXgU6ZGyqVvfSaN0DLzskYDSPeZKPmY7T7uG+jIa2Zb0j/aRAfbOxnT99kxybxCr
# dTDFNLB62FD+CljdQDzHVG2dY3RILLFORy3BFARxv2T5JL5zbcqOCb2zAVdJVGTZ
# c9d/HltEAY5aGZFrDZ+kKNxnGSgkujhLmm77IVRrakURR6nxt67I6IleT53S0Ex2
# tVdUCbFpAUR+fKFhbHP+CrvsQWY9af3LwUFJfn6Tvsv4O+S3Fb+0zj6lMVGEvL8C
# wYKiexcdFYmNcP7ntdAoGokLjzbaukz5m/8K6TT4JDVnK+ANuOaMmdbhIurwJ0I9
# JZTmdHRbatGePu1+oDEzfbzL6Xu/OHBE0ZDxyKs6ijoIYn/ZcGNTTY3ugm2lBRDB
# cQZqELQdVTNYs6FwZvKhggNZMIICQQIBATCCAQGhgdmkgdYwgdMxCzAJBgNVBAYT
# AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD
# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29mdCBJ
# cmVsYW5kIE9wZXJhdGlvbnMgTGltaXRlZDEnMCUGA1UECxMeblNoaWVsZCBUU1Mg
# RVNOOjJEMUEtMDVFMC1EOTQ3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFt
# cCBTZXJ2aWNloiMKAQEwBwYFKw4DAhoDFQCiPRa1VVBQ1Iqiq2uOKdECwFR2g6CB
# gzCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD
# VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAk
# BgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMA0GCSqGSIb3DQEB
# CwUAAgUA7HO8JTAiGA8yMDI1MDkxNjEwMzYyMVoYDzIwMjUwOTE3MTAzNjIxWjB3
# MD0GCisGAQQBhFkKBAExLzAtMAoCBQDsc7wlAgEAMAoCAQACAgfIAgH/MAcCAQAC
# AhKUMAoCBQDsdQ2lAgEAMDYGCisGAQQBhFkKBAIxKDAmMAwGCisGAQQBhFkKAwKg
# CjAIAgEAAgMHoSChCjAIAgEAAgMBhqAwDQYJKoZIhvcNAQELBQADggEBAHnYi6/I
# W9nERnDkoZZi3QFm+fn2k0KILOdOMA1Rc+p3m2p7+Oyg9vPEGZLeyd0BKTDTL4g9
# tDit4T7RUXz9tU8du8Mg9MqhKx2s+n2TYIqhYwPkDzDZZ/T2akY/icT9gHgZH035
# A39b6W59XgcZmo3Fujb0yq6TgMaWa1DwzF35tMIiUA033w2wWVzXde+JPnjJEg1X
# 6lyYEG3epDBW/YdFlhxrhnYxv5LhrvkdoBXYW9kBiL6TVyimy/ue3pO2VU3ZaKFT
# 527algyCa/i4nyqG3WlPRHQsls9w4TSor0VrNGuXHPxDTYKxQwBqF4cXY0WA79OE
# tjgauEV8x202SbYxggQNMIIECQIBATCBkzB8MQswCQYDVQQGEwJVUzETMBEGA1UE
# CBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9z
# b2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQ
# Q0EgMjAxMAITMwAAAf1z+WhazQxh7QABAAAB/TANBglghkgBZQMEAgEFAKCCAUow
# GgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMC8GCSqGSIb3DQEJBDEiBCBzvQKd
# 5DbPCQr1DlSixkP0FINbTnhwnGwbdBIeDjgvPTCB+gYLKoZIhvcNAQkQAi8xgeow
# gecwgeQwgb0EIIAoSA3JSjC8h/H94N9hK6keR4XWnoYXCMoGzyVEHg1HMIGYMIGA
# pH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT
# B1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UE
# AxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTACEzMAAAH9c/loWs0MYe0A
# AQAAAf0wIgQgkyTwOz5XDFdNYORYDLW3wuA+ij9FPpkJzDczVH8axSIwDQYJKoZI
# hvcNAQELBQAEggIAlyV9/lv2OYprSX8YPM5UOCrSrOcl9EGCONJfGZ1CPXUQ6Qk/
# 0EnaVqWtCYucKGpf09VY1jFyf0Qx0VeX/zCFO1+Cuj0cCbUdrUV/xC9n3MlY4Dks
# YcPGoY+KHTW41enGvM2t4dNuUwniuTA6siMyQApG+lvoGWH3YiX6XjDB98PWhLPq
# SVhVJQvcMgYBAYK4plw5TolpE66SNcdbZcWyzZ9i8e3mYoZa8FyiTRGbR+gCdwOq
# pNt8P0N+HsiuuosyR9vWYPI5YKCVtFjJPCdzc3XCPzvjvlDDQNdtcGZa/BNbHkNC
# qaAX2Oq07lwy8d69+aIsG0zPlCT6NnZynz8y34kFlEHRj134J9cnFKbd+66x5dh/
# nDpo548R5pslVx5Y7COsOR4gLo/PaDRIy3s32YR/Xsi/hpRVk2h7s94SbIP9sRLY
# rO2TRtkkHEQDYgm4KJ+zODLV3YVrVWP+vC3LLtktDCalHfTqKec4XxtLKAIISxHO
# sD2JXwMAOKmn5O01l5p4PPqk3RJGFZE4XhkIIDwQAY2Qt4IcoeP3Aalvcs5JdRCl
# hnEQ+Dx0al+zFbsyRiMGOCw4F3OubcEzbmevvljnu3wE844Q9gpakLdvGZ9rd14B
# /6WFSKmmuE9qF21lvBewiHtokNrcb5l6skNWZSCcuU1eZPm8a9JKdNrmnJ8=
# SIG # End signature block