Private/ReleaseMetadata.ps1

function Get-ReleaseIndex {
    Write-Host 'Checking Microsoft .NET release metadata...'
    $index = Invoke-RestMethod -Uri $script:ReleaseIndexUri -Method Get -Headers @{
        Accept = 'application/json'
        'User-Agent' = 'DotNetSteward'
    }

    $indexProperty = $index.PSObject.Properties['releases-index']
    if ($null -eq $indexProperty -or @($indexProperty.Value).Count -eq 0) {
        throw "Microsoft's release index did not contain any release channels."
    }

    return @($indexProperty.Value)
}

function Get-ChannelIndexEntry {
    param(
        [Parameter(Mandatory = $true)]
        [object[]] $ReleaseIndex,

        [Parameter(Mandatory = $true)]
        [string] $Channel
    )

    foreach ($entry in $ReleaseIndex) {
        $channelProperty = $entry.PSObject.Properties['channel-version']
        if ($null -ne $channelProperty -and [string] $channelProperty.Value -eq $Channel) {
            return $entry
        }
    }

    return $null
}

function Get-ReleasesUri {
    param(
        [Parameter(Mandatory = $true)]
        [object] $ChannelEntry
    )

    foreach ($propertyName in @('releases.json', 'patch-releases-info-uri')) {
        $property = $ChannelEntry.PSObject.Properties[$propertyName]
        if ($null -ne $property -and -not [string]::IsNullOrWhiteSpace([string] $property.Value)) {
            $uri = [uri] $property.Value
            if (-not $uri.IsAbsoluteUri -or $uri.Scheme -ne 'https') {
                throw "Release metadata URI '$uri' is not an absolute HTTPS URI."
            }

            return $uri.AbsoluteUri
        }
    }

    $channel = [string] $ChannelEntry.PSObject.Properties['channel-version'].Value
    throw "The release-index entry for .NET $channel did not provide a releases metadata URI."
}

function Get-ChannelReleaseMetadata {
    param(
        [Parameter(Mandatory = $true)]
        [object] $ChannelEntry,

        [AllowNull()]
        [hashtable] $Cache
    )

    $channel = [string] $ChannelEntry.PSObject.Properties['channel-version'].Value
    $releasesUri = Get-ReleasesUri -ChannelEntry $ChannelEntry
    if ($null -ne $Cache -and $Cache.ContainsKey($releasesUri)) {
        return $Cache[$releasesUri]
    }

    Write-Host " Reading .NET $channel releases..."
    $metadata = Invoke-RestMethod -Uri $releasesUri -Method Get -Headers @{
        Accept = 'application/json'
        'User-Agent' = 'DotNetSteward'
    }

    $releasesProperty = $metadata.PSObject.Properties['releases']
    if ($null -eq $releasesProperty) {
        throw "Release metadata for .NET $channel did not contain a releases collection."
    }

    if ($null -ne $Cache) {
        $Cache[$releasesUri] = $metadata
    }

    return $metadata
}

function Get-ChannelSdkInstallers {
    param(
        [Parameter(Mandatory = $true)]
        [object] $ChannelEntry,

        [Parameter(Mandatory = $true)]
        [string] $Rid,

        [AllowNull()]
        [hashtable] $MetadataCache
    )

    $metadata = Get-ChannelReleaseMetadata -ChannelEntry $ChannelEntry `
        -Cache $MetadataCache
    $releasesProperty = $metadata.PSObject.Properties['releases']

    $installerNames = @(
        "dotnet-sdk-$Rid.exe"
        "dotnet-dev-$Rid.exe"
    )
    $byVersion = @{}

    foreach ($release in @($releasesProperty.Value)) {
        $sdkObjects = New-Object System.Collections.Generic.List[object]
        $sdksProperty = $release.PSObject.Properties['sdks']
        if ($null -ne $sdksProperty) {
            foreach ($sdkValue in @($sdksProperty.Value)) {
                if ($null -ne $sdkValue) {
                    $sdkObjects.Add($sdkValue)
                }
            }
        }

        $sdkProperty = $release.PSObject.Properties['sdk']
        if ($null -ne $sdkProperty -and $null -ne $sdkProperty.Value) {
            $sdkObjects.Add($sdkProperty.Value)
        }

        foreach ($sdk in $sdkObjects) {
            $versionProperty = $sdk.PSObject.Properties['version']
            $filesProperty = $sdk.PSObject.Properties['files']
            if ($null -eq $versionProperty -or $null -eq $filesProperty) {
                continue
            }

            try {
                $versionInfo = New-SdkVersionInfo -Text ([string] $versionProperty.Value)
            }
            catch {
                continue
            }

            $matchingFiles = @($filesProperty.Value | Where-Object {
                $ridProperty = $_.PSObject.Properties['rid']
                $nameProperty = $_.PSObject.Properties['name']
                $null -ne $ridProperty -and $null -ne $nameProperty -and
                    [string] $ridProperty.Value -eq $Rid -and
                    $installerNames -contains [string] $nameProperty.Value
            })

            if ($matchingFiles.Count -eq 0) {
                continue
            }

            if ($matchingFiles.Count -gt 1) {
                throw "Release metadata contains multiple $Rid EXE installers for SDK $($versionInfo.Text)."
            }

            $file = $matchingFiles[0]
            $urlProperty = $file.PSObject.Properties['url']
            $hashProperty = $file.PSObject.Properties['hash']
            if ($null -eq $urlProperty -or $null -eq $hashProperty -or
                [string]::IsNullOrWhiteSpace([string] $hashProperty.Value)) {
                Write-Verbose "Skipping SDK $($versionInfo.Text) because its Windows installer metadata does not include a hash."
                continue
            }

            $url = [uri] ([string] $urlProperty.Value)
            $hash = ([string] $hashProperty.Value).ToUpperInvariant()
            if (-not $url.IsAbsoluteUri -or $url.Scheme -ne 'https') {
                throw "Installer URI '$url' for SDK $($versionInfo.Text) is not an absolute HTTPS URI."
            }

            if ($hash -notmatch '^(?:[0-9A-F]{64}|[0-9A-F]{128})$') {
                throw "Release metadata for SDK $($versionInfo.Text) has an invalid SHA-256 or SHA-512 hash."
            }

            $installer = [pscustomobject] @{
                Version = $versionInfo.Text
                VersionInfo = $versionInfo
                Rid = $Rid
                Url = $url.AbsoluteUri
                Hash = $hash
                HashAlgorithm = if ($hash.Length -eq 128) {
                    'SHA512'
                }
                else {
                    'SHA256'
                }
            }

            if ($byVersion.ContainsKey($versionInfo.Text)) {
                $existing = $byVersion[$versionInfo.Text]
                if ($existing.Url -ne $installer.Url -or $existing.Hash -ne $installer.Hash) {
                    throw "Release metadata contains conflicting installers for SDK $($versionInfo.Text)."
                }
            }
            else {
                $byVersion[$versionInfo.Text] = $installer
            }
        }
    }

    return @($byVersion.Values)
}

function Get-DotNetProductLabel {
    param(
        [Parameter(Mandatory = $true)]
        [ValidateSet('Sdk', 'Runtime', 'AspNetCoreRuntime', 'WindowsDesktopRuntime')]
        [string] $ProductType
    )

    switch ($ProductType) {
        'Sdk' { return '.NET SDK' }
        'Runtime' { return '.NET Runtime' }
        'AspNetCoreRuntime' { return 'ASP.NET Core Runtime' }
        'WindowsDesktopRuntime' { return '.NET Windows Desktop Runtime' }
    }
}

function Get-ChannelRuntimeInstallers {
    param(
        [Parameter(Mandatory = $true)]
        [object] $ChannelEntry,

        [Parameter(Mandatory = $true)]
        [string] $Rid,

        [Parameter(Mandatory = $true)]
        [ValidateSet('Runtime', 'AspNetCoreRuntime', 'WindowsDesktopRuntime')]
        [string] $ProductType,

        [AllowNull()]
        [hashtable] $MetadataCache
    )

    $componentPropertyName = switch ($ProductType) {
        'Runtime' { 'runtime' }
        'AspNetCoreRuntime' { 'aspnetcore-runtime' }
        'WindowsDesktopRuntime' { 'windowsdesktop' }
    }
    $installerNames = switch ($ProductType) {
        'Runtime' {
            @(
                "dotnet-runtime-$Rid.exe"
                "dotnet-$Rid.exe"
            )
        }
        'AspNetCoreRuntime' { @("aspnetcore-runtime-$Rid.exe") }
        'WindowsDesktopRuntime' { @("windowsdesktop-runtime-$Rid.exe") }
    }
    $productLabel = Get-DotNetProductLabel -ProductType $ProductType
    $channel = [string] $ChannelEntry.PSObject.Properties['channel-version'].Value
    $metadata = Get-ChannelReleaseMetadata -ChannelEntry $ChannelEntry `
        -Cache $MetadataCache
    $releasesProperty = $metadata.PSObject.Properties['releases']

    $byVersion = @{}
    foreach ($release in @($releasesProperty.Value)) {
        $componentProperty = $release.PSObject.Properties[$componentPropertyName]
        if ($null -eq $componentProperty -or $null -eq $componentProperty.Value) {
            continue
        }

        $component = $componentProperty.Value
        $versionProperty = $component.PSObject.Properties['version']
        $filesProperty = $component.PSObject.Properties['files']
        if ($null -eq $versionProperty -or $null -eq $filesProperty) {
            continue
        }

        try {
            $versionInfo = New-SdkVersionInfo -Text ([string] $versionProperty.Value)
        }
        catch {
            continue
        }

        $matchingFiles = @($filesProperty.Value | Where-Object {
            $ridProperty = $_.PSObject.Properties['rid']
            $nameProperty = $_.PSObject.Properties['name']
            $null -ne $ridProperty -and $null -ne $nameProperty -and
                [string] $ridProperty.Value -eq $Rid -and
                $installerNames -contains [string] $nameProperty.Value
        })
        if ($matchingFiles.Count -eq 0) {
            continue
        }
        if ($matchingFiles.Count -gt 1) {
            throw "Release metadata contains multiple $Rid EXE installers for $productLabel $($versionInfo.Text)."
        }

        $file = $matchingFiles[0]
        $urlProperty = $file.PSObject.Properties['url']
        $hashProperty = $file.PSObject.Properties['hash']
        if ($null -eq $urlProperty -or $null -eq $hashProperty -or
            [string]::IsNullOrWhiteSpace([string] $hashProperty.Value)) {
            Write-Verbose "Skipping $productLabel $($versionInfo.Text) because its Windows installer metadata does not include a hash."
            continue
        }

        $url = [uri] ([string] $urlProperty.Value)
        $hash = ([string] $hashProperty.Value).ToUpperInvariant()
        if (-not $url.IsAbsoluteUri -or $url.Scheme -ne 'https') {
            throw "Installer URI '$url' for $productLabel $($versionInfo.Text) is not an absolute HTTPS URI."
        }
        if ($hash -notmatch '^(?:[0-9A-F]{64}|[0-9A-F]{128})$') {
            throw "Release metadata for $productLabel $($versionInfo.Text) has an invalid SHA-256 or SHA-512 hash."
        }

        $installer = [pscustomobject] @{
            ProductType = $ProductType
            ProductLabel = $productLabel
            Version = $versionInfo.Text
            VersionInfo = $versionInfo
            Rid = $Rid
            Url = $url.AbsoluteUri
            Hash = $hash
            HashAlgorithm = if ($hash.Length -eq 128) {
                'SHA512'
            }
            else {
                'SHA256'
            }
        }
        if ($byVersion.ContainsKey($versionInfo.Text)) {
            $existing = $byVersion[$versionInfo.Text]
            if ($existing.Url -ne $installer.Url -or $existing.Hash -ne $installer.Hash) {
                throw "Release metadata contains conflicting installers for $productLabel $($versionInfo.Text)."
            }
        }
        else {
            $byVersion[$versionInfo.Text] = $installer
        }
    }

    return @($byVersion.Values)
}

function Get-SupportPhase {
    param(
        [Parameter(Mandatory = $true)]
        [object] $ChannelEntry
    )

    $property = $ChannelEntry.PSObject.Properties['support-phase']
    if ($null -eq $property) {
        return 'unknown'
    }

    return [string] $property.Value
}

function Get-ReleaseType {
    param(
        [Parameter(Mandatory = $true)]
        [object] $ChannelEntry
    )

    $property = $ChannelEntry.PSObject.Properties['release-type']
    if ($null -eq $property -or
        [string]::IsNullOrWhiteSpace([string] $property.Value)) {
        return 'unknown'
    }

    return [string] $property.Value
}

function Get-ChannelSdkVersions {
    param(
        [Parameter(Mandatory = $true)]
        [object] $ChannelEntry,

        [Parameter(Mandatory = $true)]
        [hashtable] $MetadataCache
    )

    $metadata = Get-ChannelReleaseMetadata -ChannelEntry $ChannelEntry -Cache $MetadataCache
    foreach ($release in @($metadata.releases)) {
        foreach ($propertyName in @('sdk', 'sdks')) {
            $property = $release.PSObject.Properties[$propertyName]
            if ($null -eq $property) {
                continue
            }
            foreach ($sdk in @($property.Value)) {
                if ($null -ne $sdk) {
                    New-SdkVersionInfo -Text ([string] $sdk.version)
                }
            }
        }
    }
}

function Get-InstallationSupportInfo {
    param(
        [Parameter(Mandatory = $true)]
        [object] $Installation,

        [Parameter(Mandatory = $true)]
        [object[]] $ReleaseIndex,

        [Parameter(Mandatory = $true)]
        [hashtable] $MetadataCache
    )

    $version = $Installation.VersionInfo
    $channelEntry = Get-ChannelIndexEntry -ReleaseIndex $ReleaseIndex -Channel $version.Channel
    if ($Installation.ProductType -eq 'Sdk') {
        $possibleChannels = @(
            if ($null -ne $channelEntry) {
                $channelEntry
            }
            foreach ($entry in $ReleaseIndex) {
                $latestSdkProperty = $entry.PSObject.Properties['latest-sdk']
                if ($null -ne $latestSdkProperty -and $entry -ne $channelEntry) {
                    $latestSdk = New-SdkVersionInfo -Text ([string] $latestSdkProperty.Value)
                    if ($latestSdk.Channel -eq $version.Channel) {
                        $entry
                    }
                }
            }
        )

        # Early SDK versions can belong to a different runtime/catalog channel.
        if ($possibleChannels.Count -gt 1 -or $null -eq $channelEntry) {
            $channelEntry = $null
            foreach ($entry in $possibleChannels) {
                $versions = @(Get-ChannelSdkVersions -ChannelEntry $entry -MetadataCache $MetadataCache)
                if (@($versions | Where-Object Text -eq $version.Text).Count -gt 0) {
                    $channelEntry = $entry
                    break
                }
            }
        }
    }

    if ($null -eq $channelEntry) {
        throw "No official release channel was found for $($Installation.ProductType) $($version.Text)."
    }

    $channel = [string] $channelEntry.'channel-version'
    $phase = Get-SupportPhase -ChannelEntry $channelEntry
    if ($phase -notin @('active', 'maintenance', 'eol', 'preview', 'go-live')) {
        throw "Release metadata for .NET $channel has an unknown support phase '$phase'."
    }

    $endOfSupportDate = $null
    $endOfSupportProperty = $channelEntry.PSObject.Properties['eol-date']
    if ($null -ne $endOfSupportProperty -and
        -not [string]::IsNullOrWhiteSpace([string] $endOfSupportProperty.Value)) {
        $endOfSupportDate = [datetime]::ParseExact(
            [string] $endOfSupportProperty.Value,
            'yyyy-MM-dd',
            [Globalization.CultureInfo]::InvariantCulture
        )
    }

    $latestPatch = $null
    if ($phase -eq 'eol' -or
        ($null -ne $endOfSupportDate -and $endOfSupportDate -lt [datetime]::Today)) {
        $status = ".NET $channel is out of support."
    }
    elseif ($phase -eq 'maintenance') {
        $status = ".NET $channel is going out of support soon."
    }
    else {
        if ($Installation.ProductType -eq 'Sdk') {
            $latestSdk = New-SdkVersionInfo -Text ([string] $channelEntry.'latest-sdk')
            if ($latestSdk.FeatureBandKey -eq $version.FeatureBandKey) {
                $latestPatch = $latestSdk
            }
            else {
                $versions = @(Get-ChannelSdkVersions -ChannelEntry $channelEntry -MetadataCache $MetadataCache)
                foreach ($candidate in $versions) {
                    if ($candidate.FeatureBandKey -eq $version.FeatureBandKey -and
                        ($null -eq $latestPatch -or
                            (Compare-SdkVersion -Left $candidate -Right $latestPatch) -gt 0)) {
                        $latestPatch = $candidate
                    }
                }
            }
        }
        else {
            $latestPatch = New-SdkVersionInfo -Text ([string] $channelEntry.'latest-runtime')
        }

        if ($null -eq $latestPatch) {
            throw "No official patch release was found for $($Installation.ProductType) $($version.Text)."
        }
        if ((Compare-SdkVersion -Left $latestPatch -Right $version) -gt 0) {
            $status = "Patch $($latestPatch.Text) is available."
        }
        else {
            $status = 'Up to date.'
        }
    }

    return @{
        SupportStatus = $status
        SupportPhase = $phase
        Channel = $channel
        EndOfSupportDate = $endOfSupportDate
        LatestPatchVersion = if ($null -ne $latestPatch) { $latestPatch.Text } else { $null }
    }
}

function Add-InstallationSupportStatus {
    param(
        [Parameter(Mandatory = $true)]
        [AllowEmptyCollection()]
        [object[]] $Installations,

        [switch] $SkipSupportCheck
    )

    foreach ($installation in $Installations) {
        $installation | Add-Member -NotePropertyMembers @{
            SupportStatus = if ($SkipSupportCheck) { 'Not checked' } else { 'Unknown' }
            SupportPhase = 'unknown'
            Channel = $null
            EndOfSupportDate = $null
            LatestPatchVersion = $null
        } -Force
    }
    if ($SkipSupportCheck -or $Installations.Count -eq 0) {
        return
    }

    $originalSecurityProtocol = [Net.ServicePointManager]::SecurityProtocol
    try {
        [Net.ServicePointManager]::SecurityProtocol =
            $originalSecurityProtocol -bor [Net.SecurityProtocolType]::Tls12

        try {
            $releaseIndex = @(Get-ReleaseIndex)
        }
        catch {
            Write-Warning "Could not check .NET support status: $($_.Exception.Message) Local inventory is still available; support status is Unknown."
            return
        }

        $metadataCache = @{}
        $statusCache = @{}
        foreach ($installation in $Installations) {
            $key = "$($installation.ProductType)|$($installation.Version)"
            if (-not $statusCache.ContainsKey($key)) {
                try {
                    $statusCache[$key] = Get-InstallationSupportInfo -Installation $installation `
                        -ReleaseIndex $releaseIndex -MetadataCache $metadataCache
                }
                catch {
                    $statusCache[$key] = $null
                    Write-Warning "Could not check support status for $($installation.ProductType) $($installation.Version): $($_.Exception.Message) Support status is Unknown."
                }
            }
            if ($null -ne $statusCache[$key]) {
                $installation | Add-Member -NotePropertyMembers $statusCache[$key] -Force
            }
        }
    }
    finally {
        [Net.ServicePointManager]::SecurityProtocol = $originalSecurityProtocol
    }
}

# SIG # Begin signature block
# MII9JwYJKoZIhvcNAQcCoII9GDCCPRQCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCB0Isin6P926MYv
# hmHgbmBCIOtxDwgfMkCzvajQw4UkaKCCIewwggXMMIIDtKADAgECAhBUmNLR1FsZ
# lUgTecgRwIeZMA0GCSqGSIb3DQEBDAUAMHcxCzAJBgNVBAYTAlVTMR4wHAYDVQQK
# ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xSDBGBgNVBAMTP01pY3Jvc29mdCBJZGVu
# dGl0eSBWZXJpZmljYXRpb24gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAy
# MDAeFw0yMDA0MTYxODM2MTZaFw00NTA0MTYxODQ0NDBaMHcxCzAJBgNVBAYTAlVT
# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xSDBGBgNVBAMTP01pY3Jv
# c29mdCBJZGVudGl0eSBWZXJpZmljYXRpb24gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRo
# b3JpdHkgMjAyMDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALORKgeD
# Bmf9np3gx8C3pOZCBH8Ppttf+9Va10Wg+3cL8IDzpm1aTXlT2KCGhFdFIMeiVPvH
# or+Kx24186IVxC9O40qFlkkN/76Z2BT2vCcH7kKbK/ULkgbk/WkTZaiRcvKYhOuD
# PQ7k13ESSCHLDe32R0m3m/nJxxe2hE//uKya13NnSYXjhr03QNAlhtTetcJtYmrV
# qXi8LW9J+eVsFBT9FMfTZRY33stuvF4pjf1imxUs1gXmuYkyM6Nix9fWUmcIxC70
# ViueC4fM7Ke0pqrrBc0ZV6U6CwQnHJFnni1iLS8evtrAIMsEGcoz+4m+mOJyoHI1
# vnnhnINv5G0Xb5DzPQCGdTiO0OBJmrvb0/gwytVXiGhNctO/bX9x2P29Da6SZEi3
# W295JrXNm5UhhNHvDzI9e1eM80UHTHzgXhgONXaLbZ7LNnSrBfjgc10yVpRnlyUK
# xjU9lJfnwUSLgP3B+PR0GeUw9gb7IVc+BhyLaxWGJ0l7gpPKWeh1R+g/OPTHU3mg
# trTiXFHvvV84wRPmeAyVWi7FQFkozA8kwOy6CXcjmTimthzax7ogttc32H83rwjj
# O3HbbnMbfZlysOSGM1l0tRYAe1BtxoYT2v3EOYI9JACaYNq6lMAFUSw0rFCZE4e7
# swWAsk0wAly4JoNdtGNz764jlU9gKL431VulAgMBAAGjVDBSMA4GA1UdDwEB/wQE
# AwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTIftJqhSobyhmYBAcnz1AQ
# T2ioojAQBgkrBgEEAYI3FQEEAwIBADANBgkqhkiG9w0BAQwFAAOCAgEAr2rd5hnn
# LZRDGU7L6VCVZKUDkQKL4jaAOxWiUsIWGbZqWl10QzD0m/9gdAmxIR6QFm3FJI9c
# Zohj9E/MffISTEAQiwGf2qnIrvKVG8+dBetJPnSgaFvlVixlHIJ+U9pW2UYXeZJF
# xBA2CFIpF8svpvJ+1Gkkih6PsHMNzBxKq7Kq7aeRYwFkIqgyuH4yKLNncy2RtNwx
# AQv3Rwqm8ddK7VZgxCwIo3tAsLx0J1KH1r6I3TeKiW5niB31yV2g/rarOoDXGpc8
# FzYiQR6sTdWD5jw4vU8w6VSp07YEwzJ2YbuwGMUrGLPAgNW3lbBeUU0i/OxYqujY
# lLSlLu2S3ucYfCFX3VVj979tzR/SpncocMfiWzpbCNJbTsgAlrPhgzavhgplXHT2
# 6ux6anSg8Evu75SjrFDyh+3XOjCDyft9V77l4/hByuVkrrOj7FjshZrM77nq81YY
# uVxzmq/FdxeDWds3GhhyVKVB0rYjdaNDmuV3fJZ5t0GNv+zcgKCf0Xd1WF81E+Al
# GmcLfc4l+gcK5GEh2NQc5QfGNpn0ltDGFf5Ozdeui53bFv0ExpK91IjmqaOqu/dk
# ODtfzAzQNb50GQOmxapMomE2gj4d8yu8l13bS3g7LfU772Aj6PXsCyM2la+YZr9T
# 03u4aUoqlmZpxJTG9F9urJh4iIAGXKKy7aIwggajMIIEi6ADAgECAhMzAAcIrb9X
# cwQsftqMAAAABwitMA0GCSqGSIb3DQEBDAUAMFoxCzAJBgNVBAYTAlVTMR4wHAYD
# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKzApBgNVBAMTIk1pY3Jvc29mdCBJ
# RCBWZXJpZmllZCBDUyBBT0MgQ0EgMDQwHhcNMjYwOTI0MDcxMzM4WhcNMjYwOTI3
# MDcxMzM4WjBnMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjERMA8G
# A1UEBxMISXNzYXF1YWgxFzAVBgNVBAoTDkRhbWlhbiBFZHdhcmRzMRcwFQYDVQQD
# Ew5EYW1pYW4gRWR3YXJkczCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGB
# AJ5jtVar1idK8RtfKZWzNR7tPEbbeEBinO8X3Ci+OJ0kYOQNbqcliD+jgBaL+++J
# zFZGZczZwMYt6ILXBlDG6vCrBOOvJLuK6ciwjiI/P9smpUyMEiNRW0g8tFzCWsyH
# 5irGeisZUHW2FC6LJosXb6qX/FpkD1owXyyJTA81dH0sRkP67N8VKMqN57ZFkxxD
# ToUTT/RYgHjrLQeIxalHTuYNRvFINkSjtH572pKyxuB1FqZnDAwlt/JCXCeY0VCj
# fQ8HiJJSMqfggCPjTGnfHer9bIRcVIh+IMNa+x7N9xHYlVFWFCXfOZT5Ktb3ECBV
# FpN+o+mNCSapmBsWYa1Fn6GpaYX9kTrKDwgs1rCblSdKVSlR6/X+sHXhmM76hPWr
# Z2x1W+xRJoMhbbCAu8IYIi7DwpivnSnOZMVOHKIUUO7FbxA9hFrWv4SoR0036s1x
# W3lQmcFta35AffU/0esPDpSu5lh0EJx+RJD9a/rOWagO6qAZdBu8xfhRbgmNoPUI
# VQIDAQABo4IB0zCCAc8wDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCB4AwOgYD
# VR0lBDMwMQYKKwYBBAGCN2EBAAYIKwYBBQUHAwMGGSsGAQQBgjdh8PiHLKGwwBPl
# htEVg5ShoiEwHQYDVR0OBBYEFGFhyVkBGIFcI6YAofP8NOdiItSuMB8GA1UdIwQY
# MBaAFGslQd77a3z9GIAKLX+Pdl2qcz24MGcGA1UdHwRgMF4wXKBaoFiGVmh0dHA6
# Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUyMElEJTIw
# VmVyaWZpZWQlMjBDUyUyMEFPQyUyMENBJTIwMDQuY3JsMHQGCCsGAQUFBwEBBGgw
# ZjBkBggrBgEFBQcwAoZYaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9j
# ZXJ0cy9NaWNyb3NvZnQlMjBJRCUyMFZlcmlmaWVkJTIwQ1MlMjBBT0MlMjBDQSUy
# MDA0LmNydDBUBgNVHSAETTBLMEkGBFUdIAAwQTA/BggrBgEFBQcCARYzaHR0cDov
# L3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9Eb2NzL1JlcG9zaXRvcnkuaHRtMA0G
# CSqGSIb3DQEBDAUAA4ICAQCBsw+V1oTQ4Z+OZndkz/wZ+iNGdm/dz2QERNpkfOQ1
# Z5M3nWy+ITMExDONjG5NQowSE8eZe67NafUwrben9wUR/frCEzWNZ2/AryU4JIrj
# HnHcG+LfdbPskSB/4V2KR9lFac+/eows2FvLc+ga6LxEKKSrP7BCHy0kkdpaNu7+
# AsR03aNIm7hNe0iN+k81yeUWKygGLO90ooivclqjhGfbV4rjXTpkaoJOxMZfhfop
# ++9SbJlR+dCV6GGYEvdC33wT54d7bTNEK801u9DiTdTYQx1r9Vqnd950ZymDap/a
# vdrVz6u/MCbZ10ENP62VV7OxY5FdM9Y40GUWnWQUicELHSDe0Pnz8zWfsR4+Hkvc
# GCzc1oFqBlePHClH0RDMpHA97RPiMZxJAxdI0lTQfb3xvkhCVSpOGopCpKX+LTsI
# ZccKWm43NxiHMtbMoHr70wtgeomtia09fZBxB2i9mD6NAr0JVmjKRXQqTJ5BLPHC
# IrjSgtb3L+AWlfswNbOiKy89DZLRMci1LZnY0EzOZyeQm09okPXMoGyENAoigyBv
# xxcMLqO/8Q4zzvySTLzRfa6fxJ81vubUPrkejL4SLXsXejq5YKCwzE66mqVtqZC/
# MSqPEyKs5M63VnwOVBxpClMCBKPHqMgFZZnupT/JoLKKXhjhklZ66TnVRDldtNps
# EDCCBqMwggSLoAMCAQICEzMABwitv1dzBCx+2owAAAAHCK0wDQYJKoZIhvcNAQEM
# BQAwWjELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv
# bjErMCkGA1UEAxMiTWljcm9zb2Z0IElEIFZlcmlmaWVkIENTIEFPQyBDQSAwNDAe
# Fw0yNjA5MjQwNzEzMzhaFw0yNjA5MjcwNzEzMzhaMGcxCzAJBgNVBAYTAlVTMRMw
# EQYDVQQIEwpXYXNoaW5ndG9uMREwDwYDVQQHEwhJc3NhcXVhaDEXMBUGA1UEChMO
# RGFtaWFuIEVkd2FyZHMxFzAVBgNVBAMTDkRhbWlhbiBFZHdhcmRzMIIBojANBgkq
# hkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAnmO1VqvWJ0rxG18plbM1Hu08Rtt4QGKc
# 7xfcKL44nSRg5A1upyWIP6OAFov774nMVkZlzNnAxi3ogtcGUMbq8KsE468ku4rp
# yLCOIj8/2yalTIwSI1FbSDy0XMJazIfmKsZ6KxlQdbYULosmixdvqpf8WmQPWjBf
# LIlMDzV0fSxGQ/rs3xUoyo3ntkWTHENOhRNP9FiAeOstB4jFqUdO5g1G8Ug2RKO0
# fnvakrLG4HUWpmcMDCW38kJcJ5jRUKN9DweIklIyp+CAI+NMad8d6v1shFxUiH4g
# w1r7Hs33EdiVUVYUJd85lPkq1vcQIFUWk36j6Y0JJqmYGxZhrUWfoalphf2ROsoP
# CCzWsJuVJ0pVKVHr9f6wdeGYzvqE9atnbHVb7FEmgyFtsIC7whgiLsPCmK+dKc5k
# xU4cohRQ7sVvED2EWta/hKhHTTfqzXFbeVCZwW1rfkB99T/R6w8OlK7mWHQQnH5E
# kP1r+s5ZqA7qoBl0G7zF+FFuCY2g9QhVAgMBAAGjggHTMIIBzzAMBgNVHRMBAf8E
# AjAAMA4GA1UdDwEB/wQEAwIHgDA6BgNVHSUEMzAxBgorBgEEAYI3YQEABggrBgEF
# BQcDAwYZKwYBBAGCN2Hw+IcsobDAE+WG0RWDlKGiITAdBgNVHQ4EFgQUYWHJWQEY
# gVwjpgCh8/w052Ii1K4wHwYDVR0jBBgwFoAUayVB3vtrfP0YgAotf492XapzPbgw
# ZwYDVR0fBGAwXjBcoFqgWIZWaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9w
# cy9jcmwvTWljcm9zb2Z0JTIwSUQlMjBWZXJpZmllZCUyMENTJTIwQU9DJTIwQ0El
# MjAwNC5jcmwwdAYIKwYBBQUHAQEEaDBmMGQGCCsGAQUFBzAChlhodHRwOi8vd3d3
# Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMElEJTIwVmVy
# aWZpZWQlMjBDUyUyMEFPQyUyMENBJTIwMDQuY3J0MFQGA1UdIARNMEswSQYEVR0g
# ADBBMD8GCCsGAQUFBwIBFjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3Bz
# L0RvY3MvUmVwb3NpdG9yeS5odG0wDQYJKoZIhvcNAQEMBQADggIBAIGzD5XWhNDh
# n45md2TP/Bn6I0Z2b93PZARE2mR85DVnkzedbL4hMwTEM42Mbk1CjBITx5l7rs1p
# 9TCtt6f3BRH9+sITNY1nb8CvJTgkiuMecdwb4t91s+yRIH/hXYpH2UVpz796jCzY
# W8tz6BrovEQopKs/sEIfLSSR2lo27v4CxHTdo0ibuE17SI36TzXJ5RYrKAYs73Si
# iK9yWqOEZ9tXiuNdOmRqgk7Exl+F+in771JsmVH50JXoYZgS90LffBPnh3ttM0Qr
# zTW70OJN1NhDHWv1Wqd33nRnKYNqn9q92tXPq78wJtnXQQ0/rZVXs7FjkV0z1jjQ
# ZRadZBSJwQsdIN7Q+fPzNZ+xHj4eS9wYLNzWgWoGV48cKUfREMykcD3tE+IxnEkD
# F0jSVNB9vfG+SEJVKk4aikKkpf4tOwhlxwpabjc3GIcy1sygevvTC2B6ia2JrT19
# kHEHaL2YPo0CvQlWaMpFdCpMnkEs8cIiuNKC1vcv4BaV+zA1s6IrLz0NktExyLUt
# mdjQTM5nJ5CbT2iQ9cygbIQ0CiKDIG/HFwwuo7/xDjPO/JJMvNF9rp/EnzW+5tQ+
# uR6MvhItexd6OrlgoLDMTrqapW2pkL8xKo8TIqzkzrdWfA5UHGkKUwIEo8eoyAVl
# me6lP8mgsopeGOGSVnrpOdVEOV202mwQMIIHKDCCBRCgAwIBAgITMwAAABYxko2S
# AmV7mgAAAAAAFjANBgkqhkiG9w0BAQwFADBjMQswCQYDVQQGEwJVUzEeMBwGA1UE
# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTQwMgYDVQQDEytNaWNyb3NvZnQgSUQg
# VmVyaWZpZWQgQ29kZSBTaWduaW5nIFBDQSAyMDIxMB4XDTI2MDMyNjE4MTEyOVoX
# DTMxMDMyNjE4MTEyOVowWjELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jvc29m
# dCBDb3Jwb3JhdGlvbjErMCkGA1UEAxMiTWljcm9zb2Z0IElEIFZlcmlmaWVkIENT
# IEFPQyBDQSAwNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMpV+sjb
# 6Akwz/RtDk5Uo1284BLMttRQy9e5/5WXtga6h89pkdWjeAwcXmKdP4YxKkhx8hn2
# q1dTVQbryvLy81tC04vg2bfSJ9emojX4HKIBYs7VhPRafMbtc866hN55aw1m/kWa
# PEKxF4Fm/LPLMLJdlu7URB8nFZMfh5tTC0CJb2uox/14OP/BiGIR8214lXdkV6Js
# PbO0Iev0mEV133tducIeBChMipzTZfnGVEq1QYFr7460cEGOIn+7AGfNOSq7gWOl
# mNB4m2uZ1r66vUJPaN+VYgH/Kmfu7tX229b3Alsli38fYS0nQY41bElntMS7yNY+
# Kd047eXM8/tS3NL+ZUNX3ge5xZqW2aytrrNIbwGgQnzsgzxBJvu9+b87jUWFiRS/
# z1YiPkRLY7iTHKIxJ973kIyK8K5itE/aEq/Ht6A8ytaAMMGTEwuCspk72FE1Qyby
# +TfDlv1KiAc7IlWHHIWbxoVd8jGCoMXhLSDhuFuGfOWOZKUIuW6YxlxcUYOOkXa0
# 2gC7dUYUZi0e1NI1Uq9mmAHdvjKdqgORs9/5aDjnbeO3hWd5qwGBmELWytkjY0Kc
# IEF+CMurTimoQoBYSiHJbYrb0pKSQe+3lVoTVpzdi36jKI7MxLnu1fBAMksa8uD8
# 5cU7RU29zMOd18h9dgTEH9pvY+4xLB3lUgE7AgMBAAGjggHcMIIB2DAOBgNVHQ8B
# Af8EBAMCAYYwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFGslQd77a3z9GIAK
# LX+Pdl2qcz24MFQGA1UdIARNMEswSQYEVR0gADBBMD8GCCsGAQUFBwIBFjNodHRw
# Oi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9yeS5odG0w
# GQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwEgYDVR0TAQH/BAgwBgEB/wIBADAf
# BgNVHSMEGDAWgBTZQSmwDw9jbO9p1/XNKZ6kSGow5jBwBgNVHR8EaTBnMGWgY6Bh
# hl9odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNyb3NvZnQl
# MjBJRCUyMFZlcmlmaWVkJTIwQ29kZSUyMFNpZ25pbmclMjBQQ0ElMjAyMDIxLmNy
# bDB9BggrBgEFBQcBAQRxMG8wbQYIKwYBBQUHMAKGYWh0dHA6Ly93d3cubWljcm9z
# b2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIwSUQlMjBWZXJpZmllZCUy
# MENvZGUlMjBTaWduaW5nJTIwUENBJTIwMjAyMS5jcnQwDQYJKoZIhvcNAQEMBQAD
# ggIBAAbVUF5UdNVEGWOVxkPciIzHA/IyNDIs1oSdW7mY4ObaFEEl8fwawEsBOasc
# BzwXjuOaTkKelQ+IiC4JvDpn8pWPgOyiKrbbw1Iswt7AV8YyuLu7A0YshILlxyny
# 9R0AMMQixLZ0T5Aj07CQOm/de5QPt36ECBwtVww6XUCx8Rm2xl6eEa9JhSub8W4u
# rQGoQYv0Zczlz4ej2ryj5Wf9L4ZZA3bL6CRE7XmzSQjTmdSmr904PiuL2uBWzq2K
# kR3RhmoaAP4Jk2JplasNM5Bs0+dx3YX2o6xRrbSaJiu6hPk/AkBoj5BCJMTZkl4w
# k6Q6nOFNSCpUxnBmJ0RRkoKq51p5ADTxbCeRAx8rIfNpTyPjxQtxTiFTC8yy/t9K
# 6s570YB1FAI+8XxZxIrmgMd7xVUkzi2/oooKb3UeovH0lqYGBEjpHZJ9jee7boQb
# Oe7SsKD/vr3PzFabg9VwLZlovpWUpWoWnU2w3xiozJ/m35tsZVvT2egUpwkb9TDI
# aXFGZAGV94FRDHn/K2XNnOwSeGskX19MB+N7yPc51fmUSd49MVAtGW/NkUGpRech
# 5Aq/d8dCML2bZ+j9nTUMgj+qnd3wuEZVRbQEIbTh9HAck0fyKqoIb+qh8y/6TKbY
# DEEOcfM2BGMvrQk4WIGCK6u8uFhA2EH3kpaiMUDqyFCeCCQxMIIHnjCCBYagAwIB
# AgITMwAAAAeHozSje6WOHAAAAAAABzANBgkqhkiG9w0BAQwFADB3MQswCQYDVQQG
# EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMUgwRgYDVQQDEz9N
# aWNyb3NvZnQgSWRlbnRpdHkgVmVyaWZpY2F0aW9uIFJvb3QgQ2VydGlmaWNhdGUg
# QXV0aG9yaXR5IDIwMjAwHhcNMjEwNDAxMjAwNTIwWhcNMzYwNDAxMjAxNTIwWjBj
# MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTQw
# MgYDVQQDEytNaWNyb3NvZnQgSUQgVmVyaWZpZWQgQ29kZSBTaWduaW5nIFBDQSAy
# MDIxMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAsvDArxmIKOLdVHpM
# SWxpCFUJtFL/ekr4weslKPdnF3cpTeuV8veqtmKVgok2rO0D05BpyvUDCg1wdsoE
# tuxACEGcgHfjPF/nZsOkg7c0mV8hpMT/GvB4uhDvWXMIeQPsDgCzUGzTvoi76YDp
# xDOxhgf8JuXWJzBDoLrmtThX01CE1TCCvH2sZD/+Hz3RDwl2MsvDSdX5rJDYVuR3
# bjaj2QfzZFmwfccTKqMAHlrz4B7ac8g9zyxlTpkTuJGtFnLBGasoOnn5NyYlf0xF
# 9/bjVRo4Gzg2Yc7KR7yhTVNiuTGH5h4eB9ajm1OCShIyhrKqgOkc4smz6obxO+Hx
# KeJ9bYmPf6KLXVNLz8UaeARo0BatvJ82sLr2gqlFBdj1sYfqOf00Qm/3B4XGFPDK
# /H04kteZEZsBRc3VT2d/iVd7OTLpSH9yCORV3oIZQB/Qr4nD4YT/lWkhVtw2v2s0
# TnRJubL/hFMIQa86rcaGMhNsJrhysLNNMeBhiMezU1s5zpusf54qlYu2v5sZ5zL0
# KvBDLHtL8F9gn6jOy3v7Jm0bbBHjrW5yQW7S36ALAt03QDpwW1JG1Hxu/FUXJbBO
# 2AwwVG4Fre+ZQ5Od8ouwt59FpBxVOBGfN4vN2m3fZx1gqn52GvaiBz6ozorgIEjn
# +PhUXILhAV5Q/ZgCJ0u2+ldFGjcCAwEAAaOCAjUwggIxMA4GA1UdDwEB/wQEAwIB
# hjAQBgkrBgEEAYI3FQEEAwIBADAdBgNVHQ4EFgQU2UEpsA8PY2zvadf1zSmepEhq
# MOYwVAYDVR0gBE0wSzBJBgRVHSAAMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cu
# bWljcm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTAZBgkrBgEE
# AYI3FAIEDB4KAFMAdQBiAEMAQTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaA
# FMh+0mqFKhvKGZgEByfPUBBPaKiiMIGEBgNVHR8EfTB7MHmgd6B1hnNodHRwOi8v
# d3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBJZGVudGl0
# eSUyMFZlcmlmaWNhdGlvbiUyMFJvb3QlMjBDZXJ0aWZpY2F0ZSUyMEF1dGhvcml0
# eSUyMDIwMjAuY3JsMIHDBggrBgEFBQcBAQSBtjCBszCBgQYIKwYBBQUHMAKGdWh0
# dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIw
# SWRlbnRpdHklMjBWZXJpZmljYXRpb24lMjBSb290JTIwQ2VydGlmaWNhdGUlMjBB
# dXRob3JpdHklMjAyMDIwLmNydDAtBggrBgEFBQcwAYYhaHR0cDovL29uZW9jc3Au
# bWljcm9zb2Z0LmNvbS9vY3NwMA0GCSqGSIb3DQEBDAUAA4ICAQB/JSqe/tSr6t1m
# CttXI0y6XmyQ41uGWzl9xw+WYhvOL47BV09Dgfnm/tU4ieeZ7NAR5bguorTCNr58
# HOcA1tcsHQqt0wJsdClsu8bpQD9e/al+lUgTUJEV80Xhco7xdgRrehbyhUf4pkeA
# hBEjABvIUpD2LKPho5Z4DPCT5/0TlK02nlPwUbv9URREhVYCtsDM+31OFU3fDV8B
# mQXv5hT2RurVsJHZgP4y26dJDVF+3pcbtvh7R6NEDuYHYihfmE2HdQRq5jRvLE1E
# b59PYwISFCX2DaLZ+zpU4bX0I16ntKq4poGOFaaKtjIA1vRElItaOKcwtc04CBrX
# SfyL2Op6mvNIxTk4OaswIkTXbFL81ZKGD+24uMCwo/pLNhn7VHLfnxlMVzHQVL+b
# Ha9KhTyzwdG/L6uderJQn0cGpLQMStUuNDArxW2wF16QGZ1NtBWgKA8Kqv48M8Hf
# FqNifN6+zt6J0GwzvU8g0rYGgTZR8zDEIJfeZxwWDHpSxB5FJ1VVU1LIAtB7o9PX
# bjXzGifaIMYTzU4YKt4vMNwwBmetQDHhdAtTPplOXrnI9SI6HeTtjDD3iUN/7ygb
# ahmYOHk7VB7fwT4ze+ErCbMh6gHV1UuXPiLciloNxH6K4aMfZN1oLVk6YFeIJEok
# uPgNPa6EnTiOL60cPqfny+Fq8UiuZzGCGpEwghqNAgEBMHEwWjELMAkGA1UEBhMC
# VVMxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjErMCkGA1UEAxMiTWlj
# cm9zb2Z0IElEIFZlcmlmaWVkIENTIEFPQyBDQSAwNAITMwAHCK2/V3MELH7ajAAA
# AAcIrTANBglghkgBZQMEAgEFAKBeMBAGCisGAQQBgjcCAQwxAjAAMBkGCSqGSIb3
# DQEJAzEMBgorBgEEAYI3AgEEMC8GCSqGSIb3DQEJBDEiBCBHJjbpgh0Zao6+HJWX
# oKLnqsGzhLEk1v4dBDG7lYFnczANBgkqhkiG9w0BAQEFAASCAYAc7brSs4qTSZA7
# iBfxU9JOFiaIN7XmJiNByVf+cWh/xJpkFc+zbeQsmkdqt2reqMRQup59GGZUvmzm
# aRm9IMLz85SajNoj4Q3+CvhnumZpWkWJBjELwsuUHdQpiT7+c/XEtqSCXSID3UQZ
# E2n/TXFtlK2qF8AiTSG1+mH+TFx1KSAc3LJpbqvH2UKo6svbejvgALP6iosg/PxL
# V7ZAp7KEMaPomAhRZ9wk8ilMpleM4D0WS6+8aduM17otYZCFKo+9NuFnk8XRQpyc
# N0Yf/fhmcRXlnmqfhTfQXfHbxisafRwG3PnYj9C3vVujqhAQaAlNfDulpia1bCHx
# IWrUS6nVILLVtIUDE8QiWxcCH2e92OALKL1K8Loxb0oc6vX3v03LDyyH2grdNRxj
# vhwtrAtO7Bxsq2+HZdTqZRd/QrQ4JGCeDsY0xK8N6lDh9FM0hlTl7Tirqlh//dTO
# JoGpnIDWan0Sy+lGIU9d4vJDQ5PRZqtqMelzn3opV7fYhxr+r+mhghgRMIIYDQYK
# KwYBBAGCNwMDATGCF/0wghf5BgkqhkiG9w0BBwKgghfqMIIX5gIBAzEPMA0GCWCG
# SAFlAwQCAQUAMIIBYgYLKoZIhvcNAQkQAQSgggFRBIIBTTCCAUkCAQEGCisGAQQB
# hFkKAwEwMTANBglghkgBZQMEAgEFAAQgJmj3yvGUWFpgaaLMI3B/o3ftTzVyZns0
# PrNBSh1ZWoECBmqpM5i5qhgTMjAyNjA5MjUxNjQ4MDkuMTc4WjAEgAIB9KCB4aSB
# 3jCB2zELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT
# B1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjElMCMGA1UE
# CxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEnMCUGA1UECxMeblNoaWVs
# ZCBUU1MgRVNOOkE1MDAtMDVFMC1EOTQ3MTUwMwYDVQQDEyxNaWNyb3NvZnQgUHVi
# bGljIFJTQSBUaW1lIFN0YW1waW5nIEF1dGhvcml0eaCCDyEwggeCMIIFaqADAgEC
# AhMzAAAABeXPD/9mLsmHAAAAAAAFMA0GCSqGSIb3DQEBDAUAMHcxCzAJBgNVBAYT
# AlVTMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xSDBGBgNVBAMTP01p
# Y3Jvc29mdCBJZGVudGl0eSBWZXJpZmljYXRpb24gUm9vdCBDZXJ0aWZpY2F0ZSBB
# dXRob3JpdHkgMjAyMDAeFw0yMDExMTkyMDMyMzFaFw0zNTExMTkyMDQyMzFaMGEx
# CzAJBgNVBAYTAlVTMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAw
# BgNVBAMTKU1pY3Jvc29mdCBQdWJsaWMgUlNBIFRpbWVzdGFtcGluZyBDQSAyMDIw
# MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnnznUmP94MWfBX1jtQYi
# oxwe1+eXM9ETBb1lRkd3kcFdcG9/sqtDlwxKoVIcaqDb+omFio5DHC4RBcbyQHjX
# CwMk/l3TOYtgoBjxnG/eViS4sOx8y4gSq8Zg49REAf5huXhIkQRKe3Qxs8Sgp02K
# HAznEa/Ssah8nWo5hJM1xznkRsFPu6rfDHeZeG1Wa1wISvlkpOQooTULFm809Z0Z
# YlQ8Lp7i5F9YciFlyAKwn6yjN/kR4fkquUWfGmMopNq/B8U/pdoZkZZQbxNlqJOi
# BGgCWpx69uKqKhTPVi3gVErnc/qi+dR8A2MiAz0kN0nh7SqINGbmw5OIRC0EsZ31
# WF3Uxp3GgZwetEKxLms73KG/Z+MkeuaVDQQheangOEMGJ4pQZH55ngI0Tdy1bi69
# INBV5Kn2HVJo9XxRYR/JPGAaM6xGl57Ei95HUw9NV/uC3yFjrhc087qLJQawSC3x
# zY/EXzsT4I7sDbxOmM2rl4uKK6eEpurRduOQ2hTkmG1hSuWYBunFGNv21Kt4N20A
# KmbeuSnGnsBCd2cjRKG79+TX+sTehawOoxfeOO/jR7wo3liwkGdzPJYHgnJ54Uxb
# ckF914AqHOiEV7xTnD1a69w/UTxwjEugpIPMIIE67SFZ2PMo27xjlLAHWW3l1CEA
# FjLNHd3EQ79PUr8FUXetXr0CAwEAAaOCAhswggIXMA4GA1UdDwEB/wQEAwIBhjAQ
# BgkrBgEEAYI3FQEEAwIBADAdBgNVHQ4EFgQUa2koOjUvSGNAz3vYr0npPtk92yEw
# VAYDVR0gBE0wSzBJBgRVHSAAMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWlj
# cm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTATBgNVHSUEDDAK
# BggrBgEFBQcDCDAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTAPBgNVHRMBAf8E
# BTADAQH/MB8GA1UdIwQYMBaAFMh+0mqFKhvKGZgEByfPUBBPaKiiMIGEBgNVHR8E
# fTB7MHmgd6B1hnNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9N
# aWNyb3NvZnQlMjBJZGVudGl0eSUyMFZlcmlmaWNhdGlvbiUyMFJvb3QlMjBDZXJ0
# aWZpY2F0ZSUyMEF1dGhvcml0eSUyMDIwMjAuY3JsMIGUBggrBgEFBQcBAQSBhzCB
# hDCBgQYIKwYBBQUHMAKGdWh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMv
# Y2VydHMvTWljcm9zb2Z0JTIwSWRlbnRpdHklMjBWZXJpZmljYXRpb24lMjBSb290
# JTIwQ2VydGlmaWNhdGUlMjBBdXRob3JpdHklMjAyMDIwLmNydDANBgkqhkiG9w0B
# AQwFAAOCAgEAX4h2x35ttVoVdedMeGj6TuHYRJklFaW4sTQ5r+k77iB79cSLNe+G
# zRjv4pVjJviceW6AF6ycWoEYR0LYhaa0ozJLU5Yi+LCmcrdovkl53DNt4EXs87KD
# ogYb9eGEndSpZ5ZM74LNvVzY0/nPISHz0Xva71QjD4h+8z2XMOZzY7YQ0Psw+ety
# NZ1CesufU211rLslLKsO8F2aBs2cIo1k+aHOhrw9xw6JCWONNboZ497mwYW5EfN0
# W3zL5s3ad4Xtm7yFM7Ujrhc0aqy3xL7D5FR2J7x9cLWMq7eb0oYioXhqV2tgFqbK
# HeDick+P8tHYIFovIP7YG4ZkJWag1H91KlELGWi3SLv10o4KGag42pswjybTi4to
# QcC/irAodDW8HNtX+cbz0sMptFJK+KObAnDFHEsukxD+7jFfEV9Hh/+CSxKRsmnu
# iovCWIOb+H7DRon9TlxydiFhvu88o0w35JkNbJxTk4MhF/KgaXn0GxdH8elEa2Im
# q45gaa8D+mTm8LWVydt4ytxYP/bqjN49D9NZ81coE6aQWm88TwIf4R4YZbOpMKN0
# CyejaPNN41LGXHeCUMYmBx3PkP8ADHD1J2Cr/6tjuOOCztfp+o9Nc+ZoIAkpUcA/
# X2gSMkgHAPUvIdtoSAHEUKiBhI6JQivRepyvWcl+JYbYbBh7pmgAXVswggeXMIIF
# f6ADAgECAhMzAAAAVn6PnVgIjulgAAAAAABWMA0GCSqGSIb3DQEBDAUAMGExCzAJ
# BgNVBAYTAlVTMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNV
# BAMTKU1pY3Jvc29mdCBQdWJsaWMgUlNBIFRpbWVzdGFtcGluZyBDQSAyMDIwMB4X
# DTI1MTAyMzIwNDY1MVoXDTI2MTAyMjIwNDY1MVowgdsxCzAJBgNVBAYTAlVTMRMw
# EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
# aWNyb3NvZnQgQ29ycG9yYXRpb24xJTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVyaWNh
# IE9wZXJhdGlvbnMxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVTTjpBNTAwLTA1RTAt
# RDk0NzE1MDMGA1UEAxMsTWljcm9zb2Z0IFB1YmxpYyBSU0EgVGltZSBTdGFtcGlu
# ZyBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC0pZ+b
# +6XTbv93xGVvwyf+DRBS+8upjZWzLe0jxTa0VKylNmiZk4PcEdPwuRH5GuEwmBvV
# WMAoU3Kxor1wtJeJ88ZIgGs8KCz0/jLbiWskSatXpDnPgGaoyEg+tmES9mdakJLg
# c7uNhJ6L+fGYLv/USv6XkuDc+ZLFvx3YhVwBHFLDUHibEHpcjSeR6X3BrV1hvbB8
# amh+toWbFk7FP142G3gsfREFJW55trpk2mNL/SC1+buqIiLI/qno9HNNNsydWqwe
# dX93+tbTMfH5D5A1nnBSoqZNkkH2FTznf7alfmsN8rfa41j39YE4CbNuqCkR1CRu
# Ixq9QzJQNKGbJwi+Ad1CdLbTuxOPwz6Qkve051qE+4+ozCxoIKB1/DBDHQ71Mp7s
# VK9sARizUCeV0KX8ocZkI5W9Q2qPIvXQkt7T/4YP3/KepcZYWlc6Nq6e9n9wpE6G
# M3gzl7rHHRvaaKpw+KLj+KLZmF4pqWUkRPsIqWkVKGzfDKDoX9+iNDFC8+dtYPg3
# LHqWGNaPCagtzHrDUVIK1q8sKXLfcEtFKVNTiopTFprx3tg3sSqmf1c7RJjS6Y68
# oVetYfuvGX72JqJyK12dNOSwCdGO96R0pPeWDuVEx+Z9lTy9c2I3RRgnNP0SOqNG
# bS43+HShfE+E189ip4VvI9cYbHNphTPrPHepNwIDAQABo4IByzCCAccwHQYDVR0O
# BBYEFL62M/K7q1n+HkazIu/LPUf4U0haMB8GA1UdIwQYMBaAFGtpKDo1L0hjQM97
# 2K9J6T7ZPdshMGwGA1UdHwRlMGMwYaBfoF2GW2h0dHA6Ly93d3cubWljcm9zb2Z0
# LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUyMFB1YmxpYyUyMFJTQSUyMFRpbWVz
# dGFtcGluZyUyMENBJTIwMjAyMC5jcmwweQYIKwYBBQUHAQEEbTBrMGkGCCsGAQUF
# BzAChl1odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY3Jv
# c29mdCUyMFB1YmxpYyUyMFJTQSUyMFRpbWVzdGFtcGluZyUyMENBJTIwMjAyMC5j
# cnQwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAOBgNVHQ8B
# Af8EBAMCB4AwZgYDVR0gBF8wXTBRBgwrBgEEAYI3TIN9AQEwQTA/BggrBgEFBQcC
# ARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9Eb2NzL1JlcG9zaXRv
# cnkuaHRtMAgGBmeBDAEEAjANBgkqhkiG9w0BAQwFAAOCAgEADgOoBcSw7bqP8trs
# WCf9CJ+K3zG5l6Spnnv5h76wf+FFNsQSMZitmCyrBH+VRR8oIWltkXyaxpk9Ak5H
# hhhQRTxfKMuufxjWMJKajGH2Xu1aJKhz8kUHDfnokCbMYbF4EDYRZLFG5OvUC5l7
# qdho3z/C0WSIdyzyAxp3FcGzoPFWHK7lieEs9CR+6YqbeUV+3ATumJ5Xt/WWySaW
# CwLoB5IYLMY9lSAK9wflO/9B73PtsgiZIPdK7OE4jBo/54pBNh/rtOJ/IkqRZBJ0
# Z9MDopy7jWTwsHqg8r4wuTWNvHErnA+otIvrbGMrThIFccQlISewW3TPFaTE/+WB
# 6PUPGpSeatgR2TG/MpIcgCoVZJm6X/mEj68nG8U+Gw1AESThxK6UOQlClx1WL+CZ
# /+YcU5iEMGOxrXmzgv7awGKXddX9PxGJHrpDzFi9MtFbF3Z1Wys6gLCexThYh6IL
# QmKcK/VYscSHtDLOv1FKviQoktZ2k1guGCOSiNOYSQCMU7vvi3fEHt6du8gXQY6x
# XX3GcJTOr0QYrK3SAy5qmEqU2Mn5pOmNYxkMaj4Y4qyen3ceZ+2aXRLKncX34zfL
# 7LpYkZRmghkmrbbuMOOMSd22lSuH0F091Uh9UkP8C7zVHOHTlQcCK+itDc6zw8Qs
# ciCI531NbNt2CYbNwgu3911VARExggdDMIIHPwIBATB4MGExCzAJBgNVBAYTAlVT
# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jv
# c29mdCBQdWJsaWMgUlNBIFRpbWVzdGFtcGluZyBDQSAyMDIwAhMzAAAAVn6PnVgI
# julgAAAAAABWMA0GCWCGSAFlAwQCAQUAoIIEnDARBgsqhkiG9w0BCRACDzECBQAw
# GgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yNjA5
# MjUxNjQ4MDlaMC8GCSqGSIb3DQEJBDEiBCAvuPd24GOvEBS1oDeRnBb0A8pMp1Jz
# WKZ0Cs7tWSvL3jCBuQYLKoZIhvcNAQkQAi8xgakwgaYwgaMwgaAEILYMMyVNpOPw
# lXeJODleel7gJIfrTXjdn5f2jk0GAwyoMHwwZaRjMGExCzAJBgNVBAYTAlVTMR4w
# HAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29m
# dCBQdWJsaWMgUlNBIFRpbWVzdGFtcGluZyBDQSAyMDIwAhMzAAAAVn6PnVgIjulg
# AAAAAABWMIIDXgYLKoZIhvcNAQkQAhIxggNNMIIDSaGCA0UwggNBMIICKQIBATCC
# AQmhgeGkgd4wgdsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw
# DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
# JTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVyaWNhIE9wZXJhdGlvbnMxJzAlBgNVBAsT
# Hm5TaGllbGQgVFNTIEVTTjpBNTAwLTA1RTAtRDk0NzE1MDMGA1UEAxMsTWljcm9z
# b2Z0IFB1YmxpYyBSU0EgVGltZSBTdGFtcGluZyBBdXRob3JpdHmiIwoBATAHBgUr
# DgMCGgMVAP9z9ykVKpBZgF5eCDJEnZlu9gQRoGcwZaRjMGExCzAJBgNVBAYTAlVT
# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jv
# c29mdCBQdWJsaWMgUlNBIFRpbWVzdGFtcGluZyBDQSAyMDIwMA0GCSqGSIb3DQEB
# CwUAAgUA7mDhBDAiGA8yMDI2MDkyNTEyMDEwOFoYDzIwMjYwOTI2MTIwMTA4WjB0
# MDoGCisGAQQBhFkKBAExLDAqMAoCBQDuYOEEAgEAMAcCAQACAgx8MAcCAQACAhIN
# MAoCBQDuYjKEAgEAMDYGCisGAQQBhFkKBAIxKDAmMAwGCisGAQQBhFkKAwKgCjAI
# AgEAAgMHoSChCjAIAgEAAgMBhqAwDQYJKoZIhvcNAQELBQADggEBACph9fFH2f56
# 7d4FyehOvtGptU3UpANOmX7SlDBA9AESkpaCkr8Iy1eXyEr92uRPs9CLv+THkfVs
# OqgWwDVEQwBjm1TfZ9lsOUcYFUPpodnLCAVoUVS35aDthxcVPCMkKiRGrEAARoPk
# o68BWe81hvztVePIZZoEQ8KQeU1ACV7Cls7oypTeYfjssn9pTzhsDYQAaaKsrxyf
# MrGpbkW0IE99yQpPI8YtyPjljQ13l1XYe9lDlp/j7nS4tUK1y+KktW79h6Q5y5kM
# cF5hK5ZMACpY25XHGoavX+ieb6LaoKm3p61ckp6zSdNrC/LDW6eDFxzeqFuj4Tk6
# eRJXUYlP7L8wDQYJKoZIhvcNAQEBBQAEggIASVaBQC/37Tg5N5t4iDDSBVbqO7qM
# cYSbV1fphIs2D3shnS5GZ61hh0/vhSuDFWS5wXqDRocE+ntHqwe2reD9d/uTUpJt
# R3jNnHGFxKW3GxTp5IDPHKF2dBsn57ZQHo91zU4GA0gpoDcFYzp6SGMpZ7avc7L7
# lCwPBnmWAt1CZ+lLRRuKM1AUL8jEJDGxxTDbMTi3WkyhsUwXxDLL3K8goqYHgQMf
# 08SDMnt69ba9Q3N6dgzw5zMkdZwP+YIHjL2VKJO1FPOsQ0pUnpG6pHWQCR8NrSbz
# caq9kPb97W9q0OBiBXDFuKkDn5RT/m6lKOowV/QUnFtcekn/C/cjAq+oPxzNPNX/
# E5VwpSWoJKTHR3kv/7HFi9OOb/y8E7uYeh/E2L9HeoGBwCf8pEKZ/XB1IEVWgf9q
# ulqcriDHjg2J9adUIe5iVk7GoKxl1SqGyCxl5z0solWZoLYkMw4y0kj8jEQrQNF/
# Dy1JGa8VxtqvgTIxCXyxUhNttTp7MPLNyLSpMZmEyqIoIBj9xPMKdDbd78L2RISk
# Abh9Wo8Rg8wQ1NtqDzjig48a1i+SAOPo/2QXOhe11jXTsnOeQUs71OsqwJc58gjl
# k+ptsauOWgnreowdmSNaF2I715Ey5ECEUW4rSBQAgFDiei8hg22P1qacrrgWC5qB
# 2P0PKjGDr3lhrsA=
# SIG # End signature block