Private/Deploy-Accelerator-Helpers/Invoke-Terraform.ps1

function Invoke-Terraform {
    [CmdletBinding(SupportsShouldProcess = $true)]
    param (
        [Parameter(Mandatory = $false)]
        [string] $moduleFolderPath,

        [Parameter(Mandatory = $false)]
        [string] $tfvarsFileName = "",

        [Parameter(Mandatory = $false)]
        [switch] $autoApprove,

        [Parameter(Mandatory = $false)]
        [switch] $destroy,

        [Parameter(Mandatory = $false)]
        [string] $output = "",

        [Parameter(Mandatory = $false)]
        [string] $outputFilePath = "",

        [Parameter(Mandatory = $false)]
        [switch] $silent,

        [Parameter(Mandatory = $false)]
        [string] $bootstrapSubscriptionId = ""
    )

    # Resolve to absolute path for `terraform -chdir` switch
    $moduleFolderPath = (Resolve-Path $moduleFolderPath).Path

    if ($PSCmdlet.ShouldProcess("Apply Terraform", "modify")) {
        # Check and Set Subscription ID
        $removeSubscriptionId = $false
        if ($null -eq $env:ARM_SUBSCRIPTION_ID -or $env:ARM_SUBSCRIPTION_ID -eq "") {
            Write-Verbose "Setting environment variable ARM_SUBSCRIPTION_ID"

            $subscriptionId = ""
            if ($bootstrapSubscriptionId -ne "") {
                # Use the provided bootstrap subscription ID
                Write-Verbose "Using provided bootstrap_subscription_id: $bootstrapSubscriptionId"
                $subscriptionId = $bootstrapSubscriptionId
            } else {
                # Fall back to az cli
                $subscriptionId = $(az account show --query id -o tsv)
            }

            if ($null -eq $subscriptionId -or $subscriptionId -eq "") {
                Write-Error "Subscription ID not found. Please ensure you are logged in to Azure and have selected a subscription, or provide bootstrap_subscription_id. Use 'az account show' to check."
                return
            }
            $env:ARM_SUBSCRIPTION_ID = $subscriptionId
            $removeSubscriptionId = $true
            Write-Verbose "Environment variable ARM_SUBSCRIPTION_ID set to $subscriptionId"
        }

        terraform -chdir="$moduleFolderPath" init
        $action = "apply"
        if ($destroy) {
            $action = "destroy"
        }

        if (!$silent) {
            Write-ToConsoleLog "Terraform init has completed, now running the $action..." -IsSuccess
        }

        $planFileName = "tfplan"

        # Start timer
        $StopWatch = New-Object -TypeName System.Diagnostics.Stopwatch
        $StopWatch.Start()

        $command = "terraform"
        $arguments = @()
        $arguments += "-chdir=$moduleFolderPath"
        $arguments += "plan"
        $arguments += "-out=$planFileName"
        $arguments += "-input=false"
        if ($tfvarsFileName -ne "") {
            $arguments += "-var-file=$tfvarsFileName"
        }

        if ($destroy) {
            $arguments += "-destroy"
        }

        if (!$silent) {
            Write-ToConsoleLog "Running Plan Command for $action : $command $arguments" -IsSuccess
            & $command $arguments
        } else {
            & $command $arguments | Write-Verbose
        }

        $exitCode = $LASTEXITCODE

        # Stop and display timer
        $StopWatch.Stop()
        if (!$silent) {
            Write-ToConsoleLog "Time taken to complete Terraform plan:" -IsSuccess
        }
        $StopWatch.Elapsed | Format-Table

        if ($exitCode -ne 0) {
            Write-ToConsoleLog "Terraform plan for $action failed with exit code $exitCode. Please review the error and try again or raise an issue." -IsError
            throw "Terraform plan failed with exit code $exitCode. Please review the error and try again or raise an issue."
        }

        if (!$autoApprove) {
            Write-ToConsoleLog "Terraform plan has completed, please review the plan and confirm you wish to continue." -IsWarning
            $choices = [System.Management.Automation.Host.ChoiceDescription[]] @("&Yes", "&No")
            $message = "Please confirm you wish to apply the plan."
            $title = "Confirm Terraform plan"
            $resultIndex = $host.ui.PromptForChoice($title, $message, $choices, 0)
            if ($resultIndex -eq 1) {
                Write-ToConsoleLog "You have chosen not to apply the plan. Exiting..." -IsError
                return
            }
        }

        # Start timer
        $StopWatch = New-Object -TypeName System.Diagnostics.Stopwatch
        $StopWatch.Start()

        $command = "terraform"
        $arguments = @()
        $arguments += "-chdir=$moduleFolderPath"
        $arguments += "apply"
        $arguments += "-auto-approve"
        $arguments += "-input=false"
        $arguments += "$planFileName"

        if (!$silent) {
            Write-ToConsoleLog "Running Apply Command for $action : $command $arguments"
            & $command $arguments
        } else {
            & $command $arguments | Write-Verbose
        }

        $exitCode = $LASTEXITCODE

        $currentAttempt = 0
        $maxAttempts = 5

        while ($exitCode -ne 0 -and $currentAttempt -lt $maxAttempts) {
            Write-ToConsoleLog "Terraform $action failed with exit code $exitCode. This is likely a transient issue, so we are retrying..." -IsWarning
            $currentAttempt++
            $command = "terraform"
            $arguments = @()
            $arguments += "-chdir=$moduleFolderPath"
            $arguments += "apply"
            $arguments += "-auto-approve"
            $arguments += "-input=false"
            if ($tfvarsFileName -ne "") {
                $arguments += "-var-file=$tfvarsFileName"
            }
            if ($destroy) {
                $arguments += "-destroy"
            }

            Write-ToConsoleLog "Retry Attempt $($currentAttempt) of $($maxAttempts): Running Apply Command for $action : $command $arguments"
            & $command $arguments
            $exitCode = $LASTEXITCODE
        }

        if ($removeSubscriptionId) {
            Write-Verbose "Removing environment variable ARM_SUBSCRIPTION_ID that was set prior to this run"
            $env:ARM_SUBSCRIPTION_ID = $null
        }

        # Stop and display timer
        $StopWatch.Stop()
        if (!$silent) {
            Write-ToConsoleLog "Time taken to complete Terraform apply:"
        }
        $StopWatch.Elapsed | Format-Table

        if ($exitCode -ne 0) {
            Write-ToConsoleLog "Terraform $action failed with exit code $exitCode after $maxAttempts attempts. Please review the error and try again or raise an issue." -IsError
            throw "Terraform $action failed with exit code $exitCode after $maxAttempts attempts. Please review the error and try again or raise an issue."
        } else {
            if ($output -ne "") {
                if ($outputFilePath -eq "") {
                    $outputFilePath = Join-Path $moduleFolderPath "output.json"
                }
                $command = "terraform"
                $arguments = @()
                $arguments += "-chdir=$moduleFolderPath"
                $arguments += "output"
                $arguments += "-json"
                $arguments += "$output"

                Write-Verbose "Outputting $output to $outputFilePath"
                Write-Verbose "Running Output Command: $command $arguments"
                & $command $arguments > $outputFilePath
            }
        }
    }
}

# SIG # Begin signature block
# MIIoVAYJKoZIhvcNAQcCoIIoRTCCKEECAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCA5Mo9QJCMfe/8q
# TFX1/3BNYeX/35vieMsaBG7P6/DEfaCCDYUwggYDMIID66ADAgECAhMzAAAEhJji
# 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/Xmfwb1tbWrJUnMTDXpQzTGCGiUwghohAgEBMIGVMH4x
# CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt
# b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01p
# Y3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTECEzMAAASEmOIS4HijMV0AAAAA
# BIQwDQYJYIZIAWUDBAIBBQCggbAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw
# HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIF84
# eoJQcVjSIF4QQnInUB0+zR4OZTtiW8YLaRezmYUwMEQGCisGAQQBgjcCAQwxNjA0
# oBSAEgBNAGkAYwByAG8AcwBvAGYAdKEcgBpodHRwczovL3d3dy5taWNyb3NvZnQu
# Y29tIDANBgkqhkiG9w0BAQEFAASCAQCZH+tE/GOUo9wJCREa4RagfZq5Ce+NaCV6
# ecdeDcLGavhLW8YCAtnFUkbNdcdEUtyzgkNXLWsovG5rv/Brx03bZvMjRFRWMV78
# iVnipRjwhCXtlcXd6Ejbko8zQu5Gm7LWXLX8tUpx4M9RNdWBMHCNQAznU0cLshGj
# BUhPGC1uOB+MPP7vbiOhL82hLPIPoqEcl4/8iT6mrDmyfbVg6zvz/lMIPKIR52ew
# tFKmzJxFOcYd3deSiSElkBj9H4PiZymM6uXov41WAAljJ1LhHqrxN/bGyF7peh4I
# vrVzzXsYb2o7oyK/NtqOpr3VBXjJm+UbEnNG2Irebtcv+ZivZjhkoYIXrTCCF6kG
# CisGAQQBgjcDAwExgheZMIIXlQYJKoZIhvcNAQcCoIIXhjCCF4ICAQMxDzANBglg
# hkgBZQMEAgEFADCCAVoGCyqGSIb3DQEJEAEEoIIBSQSCAUUwggFBAgEBBgorBgEE
# AYRZCgMBMDEwDQYJYIZIAWUDBAIBBQAEIECOhC1+udtm/r6d50N/2ggk1qiRXZJb
# A8qWJRzxi3khAgZpvC7Me7gYEzIwMjYwMzI1MTA1ODMxLjc4NVowBIACAfSggdmk
# gdYwgdMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQH
# EwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xLTArBgNV
# BAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJhdGlvbnMgTGltaXRlZDEnMCUGA1UE
# CxMeblNoaWVsZCBUU1MgRVNOOjQzMUEtMDVFMC1EOTQ3MSUwIwYDVQQDExxNaWNy
# b3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNloIIR+zCCBygwggUQoAMCAQICEzMAAAId
# S8CShziFfjkAAQAAAh0wDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxEzAR
# BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p
# Y3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3Rh
# bXAgUENBIDIwMTAwHhcNMjUwODE0MTg0ODMzWhcNMjYxMTEzMTg0ODMzWjCB0zEL
# MAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1v
# bmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEtMCsGA1UECxMkTWlj
# cm9zb2Z0IElyZWxhbmQgT3BlcmF0aW9ucyBMaW1pdGVkMScwJQYDVQQLEx5uU2hp
# ZWxkIFRTUyBFU046NDMxQS0wNUUwLUQ5NDcxJTAjBgNVBAMTHE1pY3Jvc29mdCBU
# aW1lLVN0YW1wIFNlcnZpY2UwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
# AQCitKBoADyg6XimHnvjPDb16BQ3wMN6lEctfwUzXMc0mZcboqtKpQrDNwpp+im5
# h09MRNMK9v1ol8RK4BTSIY1QUj8PpHSS91+l7ag9f4TextNC8aLgk8fmp0hhRonj
# lX/hup7x429tbOkL5kqMfX3cN6IjVcAj3XwmhCYGGURej9OifXvbWW5kmCKdyx/k
# uMxjeNfzhbJdRJfd2xLuH/vFUj7DXKODulr7TLej+Z7ZOy/pQlR1JNBqnk5EZJ8K
# dyWc/XPciKJYhavdWjtog9ayAnOrebkbGnFQcJCTyrNSGTnTL+4H4sYTdYgrYLvu
# LL2IWxJ9ItSfIwTMZENb2ZcdPg8fs7PPoIepASI2/BweqW+UKHWkdCHU1dBICo6h
# UGzmaLp5qx/rLFZN97kOtHv3nTevylTpWoLZj1cxFTjAf1BthdiwhRnfcmad3LbZ
# bUsEMBvEE9AcIGWdwYNTcGB2FVRUt7zSaCAU73wV2RaGjrvDiQ90JNGS92+Rjw+t
# BgT+dCMdcJrSDstwy21lvp6Mwd9D61RZe/r6dnhieSvY6RrFyUULDhEhg0xYPboB
# ZtCP9YR3OBrXx8q3DrovmDNc/NrqMUF88l4oTcfxAC7CmKuYfiaz7mdSM01A6Y2C
# omfRTX7difsKWzAPv1g3Svd91tgEwMCkFkmk2UrursddGwIDAQABo4IBSTCCAUUw
# HQYDVR0OBBYEFIRZ8HE0RqZm1ebyCX3ZirzSN/FdMB8GA1UdIwQYMBaAFJ+nFV0A
# XmJdg/Tl0mWnG1M1GelyMF8GA1UdHwRYMFYwVKBSoFCGTmh0dHA6Ly93d3cubWlj
# cm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQ
# Q0ElMjAyMDEwKDEpLmNybDBsBggrBgEFBQcBAQRgMF4wXAYIKwYBBQUHMAKGUGh0
# dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIw
# VGltZS1TdGFtcCUyMFBDQSUyMDIwMTAoMSkuY3J0MAwGA1UdEwEB/wQCMAAwFgYD
# VR0lAQH/BAwwCgYIKwYBBQUHAwgwDgYDVR0PAQH/BAQDAgeAMA0GCSqGSIb3DQEB
# CwUAA4ICAQCR3B4HjLG8uyksqrQP6aLIPhDQRzFUWk1m4nGJHniBZGR5MMO7KY14
# HTcmGWwGlvBJgnm5lKAMEK/AcQPZUvyUmkWU6msnPGxdYLY1N8D47487kWTmPDos
# eHqN4EAMMR1ADHceqLtmbQnC9D3fPl/p23GSbb1ao5wdhdFd8BDDLWFKstfJ95uW
# pHrqOk//2fR8KRZTiCCxSNClDY2CPUNXT0nhjfLun013zX5ezqpij77tEqbyqIH/
# k0N6KA4uOUB4WCIRchFQlb6YnKqlDD445GVqpwWNHwe7Qb7/tsx16Trxhf6Q+kMG
# TtR74j/GCJgnXFwNEGf+9zMu03vb5EiUPhSBdgu4FIKT/+kMQ9fnPf0Kv6uRzoTh
# jbwU+TgGGWgDK+nrbw/jF8SVBjxNzGtpRtlKHKmhwTqfL3kPUrUGSW1masdUoLGa
# CWe46UzXk0oitcWVcLN2qkK0jBDjXvA0BUX9AM+/PNu6Y91OLp9vS0ttJxihtXrO
# 9sGwywoQwThOPVv2ghcLx3JsmridtugRdilHCLVABulI2uf4/EZb25/WrrcWcwm7
# iCbc6HreeNb+JV/vbeq7PIetKKNYyBjQeJGIdCLQnK7SHwx2FFSnubFuYtByQ+I4
# XACUhpQ3+TvbnL9otamRFTp+qYuUQ7IflanIt3bcBjL2vy/5ChtrqzCCB3EwggVZ
# oAMCAQICEzMAAAAVxedrngKbSZkAAAAAABUwDQYJKoZIhvcNAQELBQAwgYgxCzAJ
# BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k
# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jv
# c29mdCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDEwMB4XDTIxMDkzMDE4
# MjIyNVoXDTMwMDkzMDE4MzIyNVowfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh
# c2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD
# b3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIw
# MTAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDk4aZM57RyIQt5osvX
# JHm9DtWC0/3unAcH0qlsTnXIyjVX9gF/bErg4r25PhdgM/9cT8dm95VTcVrifkpa
# /rg2Z4VGIwy1jRPPdzLAEBjoYH1qUoNEt6aORmsHFPPFdvWGUNzBRMhxXFExN6AK
# OG6N7dcP2CZTfDlhAnrEqv1yaa8dq6z2Nr41JmTamDu6GnszrYBbfowQHJ1S/rbo
# YiXcag/PXfT+jlPP1uyFVk3v3byNpOORj7I5LFGc6XBpDco2LXCOMcg1KL3jtIck
# w+DJj361VI/c+gVVmG1oO5pGve2krnopN6zL64NF50ZuyjLVwIYwXE8s4mKyzbni
# jYjklqwBSru+cakXW2dg3viSkR4dPf0gz3N9QZpGdc3EXzTdEonW/aUgfX782Z5F
# 37ZyL9t9X4C626p+Nuw2TPYrbqgSUei/BQOj0XOmTTd0lBw0gg/wEPK3Rxjtp+iZ
# fD9M269ewvPV2HM9Q07BMzlMjgK8QmguEOqEUUbi0b1qGFphAXPKZ6Je1yh2AuIz
# GHLXpyDwwvoSCtdjbwzJNmSLW6CmgyFdXzB0kZSU2LlQ+QuJYfM2BjUYhEfb3BvR
# /bLUHMVr9lxSUV0S2yW6r1AFemzFER1y7435UsSFF5PAPBXbGjfHCBUYP3irRbb1
# Hode2o+eFnJpxq57t7c+auIurQIDAQABo4IB3TCCAdkwEgYJKwYBBAGCNxUBBAUC
# AwEAATAjBgkrBgEEAYI3FQIEFgQUKqdS/mTEmr6CkTxGNSnPEP8vBO4wHQYDVR0O
# BBYEFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMFwGA1UdIARVMFMwUQYMKwYBBAGCN0yD
# fQEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lv
# cHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTATBgNVHSUEDDAKBggrBgEFBQcDCDAZBgkr
# BgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw
# AwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvXzpoYxDBWBgNVHR8ETzBN
# MEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0
# cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYIKwYBBQUHAQEETjBMMEoG
# CCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01p
# Y1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDANBgkqhkiG9w0BAQsFAAOCAgEAnVV9
# /Cqt4SwfZwExJFvhnnJL/Klv6lwUtj5OR2R4sQaTlz0xM7U518JxNj/aZGx80HU5
# bbsPMeTCj/ts0aGUGCLu6WZnOlNN3Zi6th542DYunKmCVgADsAW+iehp4LoJ7nvf
# am++Kctu2D9IdQHZGN5tggz1bSNU5HhTdSRXud2f8449xvNo32X2pFaq95W2KFUn
# 0CS9QKC/GbYSEhFdPSfgQJY4rPf5KYnDvBewVIVCs/wMnosZiefwC2qBwoEZQhlS
# dYo2wh3DYXMuLGt7bj8sCXgU6ZGyqVvfSaN0DLzskYDSPeZKPmY7T7uG+jIa2Zb0
# j/aRAfbOxnT99kxybxCrdTDFNLB62FD+CljdQDzHVG2dY3RILLFORy3BFARxv2T5
# JL5zbcqOCb2zAVdJVGTZc9d/HltEAY5aGZFrDZ+kKNxnGSgkujhLmm77IVRrakUR
# R6nxt67I6IleT53S0Ex2tVdUCbFpAUR+fKFhbHP+CrvsQWY9af3LwUFJfn6Tvsv4
# O+S3Fb+0zj6lMVGEvL8CwYKiexcdFYmNcP7ntdAoGokLjzbaukz5m/8K6TT4JDVn
# K+ANuOaMmdbhIurwJ0I9JZTmdHRbatGePu1+oDEzfbzL6Xu/OHBE0ZDxyKs6ijoI
# Yn/ZcGNTTY3ugm2lBRDBcQZqELQdVTNYs6FwZvKhggNWMIICPgIBATCCAQGhgdmk
# gdYwgdMxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQH
# EwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xLTArBgNV
# BAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJhdGlvbnMgTGltaXRlZDEnMCUGA1UE
# CxMeblNoaWVsZCBUU1MgRVNOOjQzMUEtMDVFMC1EOTQ3MSUwIwYDVQQDExxNaWNy
# b3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNloiMKAQEwBwYFKw4DAhoDFQC6g74Ept9f
# OrJ+L0YsR1YeQIt5P6CBgzCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpX
# YXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQg
# Q29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAy
# MDEwMA0GCSqGSIb3DQEBCwUAAgUA7W3s9jAiGA8yMDI2MDMyNTA1MTExOFoYDzIw
# MjYwMzI2MDUxMTE4WjB0MDoGCisGAQQBhFkKBAExLDAqMAoCBQDtbez2AgEAMAcC
# AQACAgrKMAcCAQACAhP7MAoCBQDtbz52AgEAMDYGCisGAQQBhFkKBAIxKDAmMAwG
# CisGAQQBhFkKAwKgCjAIAgEAAgMHoSChCjAIAgEAAgMBhqAwDQYJKoZIhvcNAQEL
# BQADggEBAAQV2zDgQwe7n7xUatUeOWLuVnTddUnuLHU0Fa5NjGH+VNYuf92q+f0O
# Cpf1rnf8p4al2YrhczRIuhR5ldlGbCLZlhNRPDr0WP9ioiOt4xIlz6KlbUIi+tkJ
# bv/pzDsBAkBijEshY+wEWyh43Dny+SdVeiD62kgC3mKuK7JGZoVkxx5AFZrY68/H
# xfTPO8FgKNVbucR1vCqJs0EwcF1kIfYyPX2yd8aYxyr85fYOjZLgWquS+EdY+PY+
# hUG8/tzezZsw3Xq6g4KXjQGEORCQTW1nEvzOfV2IP2up23izF1CB6cFBUaA+QVsA
# pusABrif+o1/2qWl3w5KMkOFdE9NCi8xggQNMIIECQIBATCBkzB8MQswCQYDVQQG
# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQg
# VGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAh1LwJKHOIV+OQABAAACHTANBglghkgB
# ZQMEAgEFAKCCAUowGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMC8GCSqGSIb3
# DQEJBDEiBCDJNRHKh8bfZvfB9efaJgAskKD0B30CDz+/Nb6P0pOeoTCB+gYLKoZI
# hvcNAQkQAi8xgeowgecwgeQwgb0EILG2lcxcSIsnOuozvt6nitM3Csw6PqClY32F
# m+mPlAVRMIGYMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0
# b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3Jh
# dGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTACEzMA
# AAIdS8CShziFfjkAAQAAAh0wIgQgb0D2oS09wyjEM9mc59U1BLw9jg3uG1uHNJVf
# FC6Hq6owDQYJKoZIhvcNAQELBQAEggIAe86AD1bX/2WQqRSqng63o3+LGfX9MKdQ
# 9v+8Igu2Vp/n1fANWbR7wzlW2PWIidiRZUChpuVySKLI3WKQhFJ8tHVGTzDkSIbi
# Qz2BF0VfBcsMNtZWc13KWJqbEKiiZuKdCdeLLLFSVGchWJLyMzYBq2QN8zmUFWPn
# ji0rsiOGVBrKPAoEdIUvxnEucXtJ4U0RySNpSudXBbyNA9p/ZAz+rAWf4OXbIPCY
# 1wCezw86tGm4eiUTWMIf8dH0xr0sq+gAaiTx7BLjA1tGZL/T6P1O9LaTzuM8pq7F
# KXF+q/A1ky+e+MtwentJruCyVi/7SIrXrpM8htG2vNtZAWWY8VKYypcKqyhMMHRW
# urH/M9wgUltYZ8DF1i0jniNXPv5RT1ijozNPWDTWNPgaJOBfHFroTxyxHqK6o/Ek
# 7IiHr4li+bxI7gAWO84IrE0tVgriCaYoTNBpxbDmwONwE4oRd+vFUwkmYToDTnfD
# 5lr35+Pdi+3hxcyTmis5wjP4ibqK3uKis+oRT4tJzbbxdFvYlmEFrfXJZYh7fg+W
# vMlhJDjkYEVCtvxhxs8AyNq8XhF7bOTg7pwS3/Iy5JneFxM/Ng5Ws3uPqU94L1KI
# gmbvey5Thd5+LfRbkwlITHbuj1/o+NFBezpvoZyQfapIIWZcyLRkFY9EIyR8kCwR
# Unxzw+YYYLY=
# SIG # End signature block