Private/Shared/Get-GithubRelease.ps1

####################################
# Get-GithubRelease.ps1 #
####################################
# Version: 0.1.0
# Based on Invoke-GitHubReleaseFetcher by Jack Tracey:
# Source: https://github.com/jtracey93/PublicScripts/blob/master/GitHub/PowerShell/Invoke-GitHubReleaseFetcher.ps1

<#
.SYNOPSIS
Checks for the releases of a GitHub repository and downloads the latest release or all releases and pulls it into a specified directory, one for each version.
.DESCRIPTION
Checks for the releases of a GitHub repository and downloads the latest release or all releases and pulls it into a specified directory, one for each version.
 
.EXAMPLE
 
.NOTES
# Release notes 16/03/2023 - V0.1.0:
- Initial release.
#>



function Get-GithubRelease {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, Position = 1, HelpMessage = "Please the provide the full URL of the GitHub repository you wish to check for the latest release.")]
        [string]
        $githubRepoUrl,

        [Parameter(Mandatory = $false, Position = 2, HelpMessage = "The releases to download. Specify 'latest' to download the latest release. Defaults to the latest release.")]
        [array]
        $release = "latest",

        [Parameter(Mandatory = $true, Position = 3, HelpMessage = "The directory to download the releases to.")]
        [string]
        $targetDirectory,

        [Parameter(Mandatory = $false, Position = 4, HelpMessage = "Whether to just query the API and return the release versions.")]
        [switch]
        $queryOnly,

        [Parameter(Mandatory = $false, HelpMessage = "The source directory location of the modules. Defaults to root")]
        $moduleSourceFolder = ".",

        [Parameter(Mandatory = $true, HelpMessage = "The target directory location of the modules.")]
        $moduleTargetFolder,

        [Parameter(Mandatory = $false, HelpMessage = "The name of the release artifact in the target release. Defaults to standard release zip.")]
        $releaseArtifactName = ""
    )

    $parentDirectory = $targetDirectory
    $targetPath = Join-Path $targetDirectory $moduleTargetFolder

    # Split Repo URL into parts
    $repoOrgPlusRepo = $githubRepoUrl.Split("/")[-2..-1] -join "/"

    Write-Verbose "=====> Checking for release on GitHub Repo: $repoOrgPlusRepo"

    # Get releases on repo
    $repoReleaseUrl = "https://api.github.com/repos/$repoOrgPlusRepo/releases/$release"
    if($release -ne "latest") {
        $repoReleaseUrl = "https://api.github.com/repos/$repoOrgPlusRepo/releases/tags/$release"
    }

    $releaseData = Invoke-RestMethod $repoReleaseUrl -SkipHttpErrorCheck -StatusCodeVariable "statusCode"

    Write-Verbose "Status code: $statusCode"

    if($statusCode -eq 404) {
        Write-Error "The release $release does not exist in the GitHub repository $githubRepoUrl - $repoReleaseUrl"
        throw "The release $release does not exist in the GitHub repository $githubRepoUrl - $repoReleaseUrl"
    }

    # Handle transient errors like throttling
    if($statusCode -ge 400 -and $statusCode -le 599) {
        Write-InformationColored "Retrying as got the Status Code $statusCode, which may be a transient error." -ForegroundColor Yellow -InformationAction Continue
        $releaseData = Invoke-RestMethod $repoReleaseUrl -RetryIntervalSec 3 -MaximumRetryCount 100
    }

    if($statusCode -ne 200) {
        throw "Unable to query repository version, please check your internet connection and try again..."
    }

    $releaseTag = $releaseData.tag_name

    if($queryOnly) {
        return $releaseTag
    }

    # Check if directory exists
    Write-Verbose "=====> Checking if directory for releases exists: $targetPath"

    if (!(Test-Path $targetPath)) {
        Write-Verbose "Directory does not exist for releases, will now create: $targetPath"
        New-Item -ItemType Directory -Path $targetPath | Out-String | Write-Verbose
    }

    # Check the directory for this release
    $targetVersionPath = Join-Path $targetPath $releaseTag

    Write-Verbose "===> Checking if directory for release version exists: $targetVersionPath"

    if (!(Test-Path $targetVersionPath)) {
        Write-Verbose "Directory does not exist for release $releaseTag, will now create: $targetVersionPath"
        New-Item -ItemType Directory -Path $targetVersionPath | Out-String | Write-Verbose
    }

    Write-Verbose "===> Checking if any content exists inside of $targetVersionPath"

    $contentTargetVersionPath = Get-ChildItem -Path $targetVersionPath -Recurse -ErrorAction SilentlyContinue

    if ($null -eq $contentTargetVersionPath) {
        Write-Verbose "===> Pulling and extracting release $releaseTag into $targetVersionPath"
        New-Item -ItemType Directory -Path "$targetVersionPath/tmp" | Out-String | Write-Verbose
        $targetPathForZip = "$targetVersionPath/tmp/$releaseTag.zip"

        # Get the artifact url
        if($releaseArtifactName -ne "") {
            $releaseArtifactUrl = $releaseData.assets | Where-Object { $_.name -eq $releaseArtifactName } | Select-Object -ExpandProperty browser_download_url
        } else {
            $releaseArtifactUrl = $releaseData.zipball_url
        }

        Write-Verbose "===> Downloading the release artifact $releaseArtifactUrl from the GitHub repository $repoOrgPlusRepo"

        Invoke-WebRequest -Uri $releaseArtifactUrl -OutFile $targetPathForZip -RetryIntervalSec 3 -MaximumRetryCount 100 | Out-String | Write-Verbose

        if(!(Test-Path $targetPathForZip)) {
            Write-InformationColored "Failed to download the release $releaseTag from the GitHub repository $repoOrgPlusRepo" -ForegroundColor Red -InformationAction Continue
            throw
        }

        $targetPathForExtractedZip = "$targetVersionPath/tmp/extracted"

        Expand-Archive -Path $targetPathForZip -DestinationPath $targetPathForExtractedZip | Out-String | Write-Verbose

        $extractedSubFolder = $targetPathForExtractedZip
        if($releaseArtifactName -eq "") {
            $extractedSubFolder = (Get-ChildItem -Path $targetPathForExtractedZip -Directory).FullName
        }

        Write-Verbose "===> Copying all extracted contents into $targetVersionPath from $($extractedSubFolder)/$moduleSourceFolder/*."

        Copy-Item -Path "$($extractedSubFolder)/$moduleSourceFolder/*" -Destination "$targetVersionPath" -Recurse -Force | Out-String | Write-Verbose

        Remove-Item -Path "$targetVersionPath/tmp" -Force -Recurse
        Write-InformationColored "The directory for $targetVersionPath has been created and populated." -ForegroundColor Green -InformationAction Continue
    } else {
        Write-InformationColored "The directory for $targetVersionPath already exists and has content in it, so we are not overwriting it." -ForegroundColor Green -InformationAction Continue
        Write-Verbose "===> Content already exists in $releaseDirectory. Skipping"
    }

    # Check and replace the .env file release version if it is Bicep
    $envFilePath = Join-Path -Path $parentDirectory -ChildPath ".env"
    if (Test-Path $envFilePath) {
        Write-Verbose "===> Replacing the .env file release version with $releaseTag"
        (Get-Content $envFilePath) -replace "UPSTREAM_RELEASE_VERSION=.*", "UPSTREAM_RELEASE_VERSION=$releaseTag" | Set-Content $envFilePath
    }

    return $releaseTag
}

# SIG # Begin signature block
# MIIoPQYJKoZIhvcNAQcCoIIoLjCCKCoCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAAVmOiiSXWHNtI
# Byi8YZXtrk91+pCSq1NzoFZSQPq216CCDYUwggYDMIID66ADAgECAhMzAAAEhJji
# 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/Xmfwb1tbWrJUnMTDXpQzTGCGg4wghoKAgEBMIGVMH4x
# CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt
# b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01p
# Y3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTECEzMAAASEmOIS4HijMV0AAAAA
# BIQwDQYJYIZIAWUDBAIBBQCggbAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw
# HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIB/j
# e563Edd6Ldkx9P4suSYlZAMmipT0Ik9K7toNZX9MMEQGCisGAQQBgjcCAQwxNjA0
# oBSAEgBNAGkAYwByAG8AcwBvAGYAdKEcgBpodHRwczovL3d3dy5taWNyb3NvZnQu
# Y29tIDANBgkqhkiG9w0BAQEFAASCAQAN367aRfoY4EYTeajfIMrFBSDby3+SBFdp
# 2zYYY3/qDXfxrCCxktQaSkHju3UkcpAScA0qRFQ42aegrlTGzuS82Vr1ijKg6lpy
# Dlij6FEoFuDcS3RjnVQRM2vSIIsvPcK07Syc81v1uPb0DLHOc5JGy2ZcWIR6pvhb
# rBLo0OmIx3Q0mnGdqpb6joV5pd/4/NsNXo+C9U9EDfxIG6Wg69ofUMSxzzChoQgg
# EiTtE5zSFWyVDeRxqF1uDEvcB7NpFwMK58dtUBaRuVJliMQLLcKXYeHQQvlv6lLo
# MQVPvqxcyMr75UtoaYVqE1ZE5IQRf2BuO3rn04qzIJKlIHgkHhZboYIXljCCF5IG
# CisGAQQBgjcDAwExgheCMIIXfgYJKoZIhvcNAQcCoIIXbzCCF2sCAQMxDzANBglg
# hkgBZQMEAgEFADCCAVEGCyqGSIb3DQEJEAEEoIIBQASCATwwggE4AgEBBgorBgEE
# AYRZCgMBMDEwDQYJYIZIAWUDBAIBBQAEIF1tI/zvr9aj7YFPSrtjUnSVAqfgnb0q
# tniFFXUrwvfqAgZoo6N6Vy0YEjIwMjUwOTE2MTE0NzE0LjQ5WjAEgAIB9KCB0aSB
# zjCByzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT
# B1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjElMCMGA1UE
# CxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEnMCUGA1UECxMeblNoaWVs
# ZCBUU1MgRVNOOjg5MDAtMDVFMC1EOTQ3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGlt
# ZS1TdGFtcCBTZXJ2aWNloIIR7TCCByAwggUIoAMCAQICEzMAAAIOLMsofZUgdWMA
# AQAAAg4wDQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh
# c2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD
# b3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIw
# MTAwHhcNMjUwMTMwMTk0MzAzWhcNMjYwNDIyMTk0MzAzWjCByzELMAkGA1UEBhMC
# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFt
# ZXJpY2EgT3BlcmF0aW9uczEnMCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjg5MDAt
# MDVFMC1EOTQ3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNl
# MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEArObe4kbV7dIW3qPTBO/G
# WIyKN7GkLljARUO1+LPb6KGEQAUzn9qaEx2rcfhMJwVBgdVdrfxOjMLEDZmOV6TP
# ++Wgq2XcQJ61faOE7ubAXqW233obKzlkQSBqCROj7VqHdQqxXoZtXYs942Nx/Iha
# 4e56nn54mdUp23FjzMjSMbhhc6UIgwPhOWEt95njKml8IXW9NQpbspof9xCr5J4+
# HSKUGRFjjzN48W0VQGDeSdrTq2JCXHQ8dJdNlfzWHdapL1AYD8ayr4quZM+xOgGz
# onwg0jAYHJ/1+0UMOt9EJM6oadJA1Nqnov2qPSB5rrkXlxI546YE7K+AG99yAgCj
# GMTkHvp+cKhFXBPTk8oZlmSUuQJ1lE54qJOJoMDjQVkNQyzhhZGcF099+CDwqneP
# 9/y3fyLYs4rLclGWLJpfwuGYXQC2732MM799TsX/DU5leSBsVnR55Nh4YeG580yq
# LBGg6yb0DIkPpaKIzO3+W4HcgQZ2EAZufv4ibMcPJNtu8xdo2zSPjsLPBy3mRrfL
# eridnlYzQ9QdGLYLAT9HLAZZ5yPuPnby2EbdHAKsOj4mEs+RUmXG6YtMXQB/43d3
# c8hgK28i7qOvR7oHxhBG/7DNO63KD9aN3GfHljG+PjCAfHrjm+Q1Tw5xHBYuDQ7p
# GDPdYNQ7f6iHpPq7RPPFUvECAwEAAaOCAUkwggFFMB0GA1UdDgQWBBSFcURpUhGR
# PtREiulBiO2DXBCI2zAfBgNVHSMEGDAWgBSfpxVdAF5iXYP05dJlpxtTNRnpcjBf
# BgNVHR8EWDBWMFSgUqBQhk5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3Bz
# L2NybC9NaWNyb3NvZnQlMjBUaW1lLVN0YW1wJTIwUENBJTIwMjAxMCgxKS5jcmww
# bAYIKwYBBQUHAQEEYDBeMFwGCCsGAQUFBzAChlBodHRwOi8vd3d3Lm1pY3Jvc29m
# dC5jb20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0El
# MjAyMDEwKDEpLmNydDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUF
# BwMIMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAgEAdeC9ky/i/Dly
# 8Zxkmpdod9JmexbARaKImJFFTmNORfaZ8D01bnxAxlhKTTctjn2lB1iDqEP/f648
# DtIUtkqQdAczAJNoMs/djRljqVm6QXTL660Q6YlmYv7i0uGRnUZ9z9g3HGJpZDT/
# r2kQF757/pqduyoCO/ZifYRsgkG77TCI5G2KC6iu7Be1moZ/ay419cuUCS+JbxMt
# 0JgPSkQY+enBL/5QL8w6u3koqkav6QsqsnPLs5kPEnilslrug41APb4vOELJi46j
# xgpx+HD8oPrfeUaVvu97J4XsNYglfsF7tkcTJ1oOxLA+Xi5CRy7M1CD3flwpQ/hU
# 71dNxn6ww35PuOX5R/3ikWXNzFGbZ4SyYz8L9yqCg0nFuIlekmwkcnGD5KqFgax3
# +0rwwOxqx9lDrc9VmtZNu7HWYKRuv3PQqiiPAl+b4GmvgO6GB2+GQY+0vLvLIMcF
# iux4Fg0Qcjh9woibuCyfId04kZEQK5h0adJWzX9YgCri/POiChPddr9MquebfIzM
# YwVO7qC7K2FSKCpM4frAJIJKRjqGS9ePnZcVTPdQWr82uJDg01JcM2/kqV7Eqlcf
# J7geqoVMu6aqYMMNauEjYQMRZxcbMYk5WqC++RjcT0etOZSdll3obRIu//mHyarx
# /r56nKago8kPYTWlc7jhB1+DMrqnI8IwggdxMIIFWaADAgECAhMzAAAAFcXna54C
# m0mZAAAAAAAVMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UE
# CBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9z
# b2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZp
# Y2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0yMTA5MzAxODIyMjVaFw0zMDA5MzAxODMy
# MjVaMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQH
# EwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNV
# BAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMIICIjANBgkqhkiG9w0B
# AQEFAAOCAg8AMIICCgKCAgEA5OGmTOe0ciELeaLL1yR5vQ7VgtP97pwHB9KpbE51
# yMo1V/YBf2xK4OK9uT4XYDP/XE/HZveVU3Fa4n5KWv64NmeFRiMMtY0Tz3cywBAY
# 6GB9alKDRLemjkZrBxTzxXb1hlDcwUTIcVxRMTegCjhuje3XD9gmU3w5YQJ6xKr9
# cmmvHaus9ja+NSZk2pg7uhp7M62AW36MEBydUv626GIl3GoPz130/o5Tz9bshVZN
# 7928jaTjkY+yOSxRnOlwaQ3KNi1wjjHINSi947SHJMPgyY9+tVSP3PoFVZhtaDua
# Rr3tpK56KTesy+uDRedGbsoy1cCGMFxPLOJiss254o2I5JasAUq7vnGpF1tnYN74
# kpEeHT39IM9zfUGaRnXNxF803RKJ1v2lIH1+/NmeRd+2ci/bfV+AutuqfjbsNkz2
# K26oElHovwUDo9Fzpk03dJQcNIIP8BDyt0cY7afomXw/TNuvXsLz1dhzPUNOwTM5
# TI4CvEJoLhDqhFFG4tG9ahhaYQFzymeiXtcodgLiMxhy16cg8ML6EgrXY28MyTZk
# i1ugpoMhXV8wdJGUlNi5UPkLiWHzNgY1GIRH29wb0f2y1BzFa/ZcUlFdEtsluq9Q
# BXpsxREdcu+N+VLEhReTwDwV2xo3xwgVGD94q0W29R6HXtqPnhZyacaue7e3Pmri
# Lq0CAwEAAaOCAd0wggHZMBIGCSsGAQQBgjcVAQQFAgMBAAEwIwYJKwYBBAGCNxUC
# BBYEFCqnUv5kxJq+gpE8RjUpzxD/LwTuMB0GA1UdDgQWBBSfpxVdAF5iXYP05dJl
# pxtTNRnpcjBcBgNVHSAEVTBTMFEGDCsGAQQBgjdMg30BATBBMD8GCCsGAQUFBwIB
# FjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9y
# eS5odG0wEwYDVR0lBAwwCgYIKwYBBQUHAwgwGQYJKwYBBAGCNxQCBAweCgBTAHUA
# YgBDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU
# 1fZWy4/oolxiaNE9lJBb186aGMQwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDovL2Ny
# bC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0XzIw
# MTAtMDYtMjMuY3JsMFoGCCsGAQUFBwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0cDov
# L3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXRfMjAxMC0w
# Ni0yMy5jcnQwDQYJKoZIhvcNAQELBQADggIBAJ1VffwqreEsH2cBMSRb4Z5yS/yp
# b+pcFLY+TkdkeLEGk5c9MTO1OdfCcTY/2mRsfNB1OW27DzHkwo/7bNGhlBgi7ulm
# ZzpTTd2YurYeeNg2LpypglYAA7AFvonoaeC6Ce5732pvvinLbtg/SHUB2RjebYIM
# 9W0jVOR4U3UkV7ndn/OOPcbzaN9l9qRWqveVtihVJ9AkvUCgvxm2EhIRXT0n4ECW
# OKz3+SmJw7wXsFSFQrP8DJ6LGYnn8AtqgcKBGUIZUnWKNsIdw2FzLixre24/LAl4
# FOmRsqlb30mjdAy87JGA0j3mSj5mO0+7hvoyGtmW9I/2kQH2zsZ0/fZMcm8Qq3Uw
# xTSwethQ/gpY3UA8x1RtnWN0SCyxTkctwRQEcb9k+SS+c23Kjgm9swFXSVRk2XPX
# fx5bRAGOWhmRaw2fpCjcZxkoJLo4S5pu+yFUa2pFEUep8beuyOiJXk+d0tBMdrVX
# VAmxaQFEfnyhYWxz/gq77EFmPWn9y8FBSX5+k77L+DvktxW/tM4+pTFRhLy/AsGC
# onsXHRWJjXD+57XQKBqJC4822rpM+Zv/Cuk0+CQ1ZyvgDbjmjJnW4SLq8CdCPSWU
# 5nR0W2rRnj7tfqAxM328y+l7vzhwRNGQ8cirOoo6CGJ/2XBjU02N7oJtpQUQwXEG
# ahC0HVUzWLOhcGbyoYIDUDCCAjgCAQEwgfmhgdGkgc4wgcsxCzAJBgNVBAYTAlVT
# MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQK
# ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVy
# aWNhIE9wZXJhdGlvbnMxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVTTjo4OTAwLTA1
# RTAtRDk0NzElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZaIj
# CgEBMAcGBSsOAwIaAxUASuh2P2Vi5znDBELI5AwKAfyWVgiggYMwgYCkfjB8MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNy
# b3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQsFAAIFAOxzscYw
# IhgPMjAyNTA5MTYwOTUyMDZaGA8yMDI1MDkxNzA5NTIwNlowdzA9BgorBgEEAYRZ
# CgQBMS8wLTAKAgUA7HOxxgIBADAKAgEAAgImIwIB/zAHAgEAAgISKjAKAgUA7HUD
# RgIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIBAAIDB6Eg
# oQowCAIBAAIDAYagMA0GCSqGSIb3DQEBCwUAA4IBAQAsywdwrq+LtXxctC0jSbHh
# 2f6pmBPJlLUWrWoF6GF2oG3mYoswL/Db+W/4/GWqbaXCI/IvTprpw3BmqPgl8Hix
# e/yKtJyYSY9NNtFDTSRNgx4pQW4qMLVGLVw8be13eH4Pz3ideH5/UNuEsQaejM0E
# 9FK1Ia+80uvpnuFXB9MjIzizYHAxpdaQwqPaO4s7CRUpP3ztxFh18UTxjvxXRWxC
# rVMODv367FIa29ob0qbWSGwcUk3OXgGLHlNdMjVuE1EPtp9xHMTw5Afks1M8S2ly
# yt87SRshkYvlRgeJo1h5HszISyisI9xNlLR4sWPvRvQursPxRPZ2V4XiKiTjcdda
# MYIEDTCCBAkCAQEwgZMwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0
# b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3Jh
# dGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTACEzMA
# AAIOLMsofZUgdWMAAQAAAg4wDQYJYIZIAWUDBAIBBQCgggFKMBoGCSqGSIb3DQEJ
# AzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0BCQQxIgQgU7pwA1SA8Ns4/s9dmoZB
# I9PLO0cXU+WT3J7MQsrMhJswgfoGCyqGSIb3DQEJEAIvMYHqMIHnMIHkMIG9BCAB
# dB1zJfDpgZCtuu5saGykoocDnT9HlDV0DMqT808ShjCBmDCBgKR+MHwxCzAJBgNV
# BAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4w
# HAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29m
# dCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAACDizLKH2VIHVjAAEAAAIOMCIEIOEH
# Fqnjki4QJ1f8QmWeqq/73DtchmszMBYKRWFRy+KuMA0GCSqGSIb3DQEBCwUABIIC
# AHwSSzOSgypOwnHNNOURfUpIzF1q6sLKMUhigUgElywsxRaAW2YDRXXo+Uckc7W9
# tqI4kuDDRySTjMOZFfV0TDdW6V98+uT6F3m0thFbkiGarMdxnQyvT/mttwjAydR/
# vkONaoOISte344WqET1faIk2OrqS/PJSa5gYHJMxGUtmyRR81s9jTCodsiifBwz8
# VsoQ/gl1aA+2maiWEAgoTrtis8gSE+h8OJJ3POqXXEzC2TQwjJNoqOdGnQyrC0eh
# 2KM/th7GfTVCIA+OZfp4kchSl5GFrDnUjQsuIFcp9G7pX5ekTUXJ0EG8SPnq/p/A
# OQy5nzO7Y2VHY2CkTPXU7exrjwk+FUCcLok0rFckoeX37f1mpMe+E0aJaQ6d0xH2
# SBFAd0KdjOJuXoXB0UNGafBCQfr0Y34lGlMR6nw6/P5UPwEQmy2Fiw/aP+2ZHXnV
# e2q45x1Yz2j/oq5QJ2Y5U7CYHQTVQV+WYpAPYdVj1CrZVdHuQGSdQ6sXy79d7odt
# j3MohWtEB3jkWLZ0ow16eCoEhE7/20BvG5AOFK+xxZyHz3KFgGeV/w5A1caJOlkT
# +K73yaU1ZN8YU+6TdFbH6frEIlbjUgPp0d1J1zos1cFPXmNumboJBSnQgbTzuB2u
# UK0/79Bk4L2fBx5dIGxbkY6pLxEUFBS2IqEyFtzR8G0U
# SIG # End signature block