Private/Discovery.ps1

function Get-DotNetProductType {
    param(
        [Parameter(Mandatory = $true)]
        [AllowEmptyString()]
        [string] $DisplayName
    )

    if ([string]::IsNullOrWhiteSpace($DisplayName)) {
        return $null
    }

    if ($DisplayName.IndexOf('.NET Core SDK', [StringComparison]::OrdinalIgnoreCase) -ge 0 -or
        $DisplayName.IndexOf('Microsoft .NET SDK', [StringComparison]::OrdinalIgnoreCase) -ge 0) {
        return 'Sdk'
    }

    if ($DisplayName.IndexOf('ASP.NET', [StringComparison]::OrdinalIgnoreCase) -ge 0 -and
        ($DisplayName.IndexOf('Runtime', [StringComparison]::OrdinalIgnoreCase) -ge 0 -or
        $DisplayName.IndexOf('Shared Framework', [StringComparison]::OrdinalIgnoreCase) -ge 0)) {
        return 'AspNetCoreRuntime'
    }

    if ($DisplayName.IndexOf('Windows Desktop Runtime', [StringComparison]::OrdinalIgnoreCase) -ge 0 -or
        $DisplayName.IndexOf(
            'Dotnet Shared Framework for Windows Desktop',
            [StringComparison]::OrdinalIgnoreCase
        ) -ge 0) {
        return 'WindowsDesktopRuntime'
    }

    if ($DisplayName.IndexOf('.NET Core Runtime', [StringComparison]::OrdinalIgnoreCase) -ge 0 -or
        $DisplayName.IndexOf('Microsoft .NET Runtime', [StringComparison]::OrdinalIgnoreCase) -ge 0) {
        return 'Runtime'
    }

    return $null
}

function Get-DotNetVersionFromDisplayName {
    param(
        [Parameter(Mandatory = $true)]
        [AllowEmptyString()]
        [string] $DisplayName
    )

    if ([string]::IsNullOrWhiteSpace($DisplayName)) {
        return $null
    }

    if ($DisplayName -match '(?i)(?<core>\d+\.\d+\.\d+)\s+(?<label>preview|alpha|rc)\s*(?<number>\d+(?:\.\d+)*)') {
        return '{0}-{1}.{2}' -f
            $Matches.core,
            $Matches.label.ToLowerInvariant(),
            $Matches.number
    }

    if ($DisplayName -match '(?<version>\d+\.\d+\.\d+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?)') {
        return $Matches.version
    }

    return $null
}

function Get-DotNetBundleIdentity {
    param(
        [Parameter(Mandatory = $true)]
        [string] $DisplayName,

        [AllowEmptyString()]
        [string] $BundleCachePath,

        [AllowEmptyString()]
        [string] $UninstallString
    )

    $productType = Get-DotNetProductType -DisplayName $DisplayName
    if ($null -eq $productType) {
        return $null
    }

    $version = $null
    $architecture = $null
    $identityText = "$BundleCachePath`n$UninstallString"
    if ($identityText -match '(?i)(?:dotnet-sdk|dotnet-runtime|aspnetcore-runtime|windowsdesktop-runtime)-(?<version>\d+\.\d+\.\d+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?)-win-(?<architecture>x64|x86|arm64)\.exe') {
        $version = $Matches.version
        $architecture = $Matches.architecture.ToLowerInvariant()
    }
    elseif ($identityText -match '(?i)dotnet-(?:dev-)?win-(?<architecture>x64|x86)\.(?<version>\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)\.exe') {
        $version = $Matches.version
        $architecture = $Matches.architecture.ToLowerInvariant()
    }

    if ([string]::IsNullOrWhiteSpace($version)) {
        $version = Get-DotNetVersionFromDisplayName -DisplayName $DisplayName
    }
    if ([string]::IsNullOrWhiteSpace($architecture) -and
        $DisplayName -match '(?i)\((?<architecture>x64|x86|arm64)\)') {
        $architecture = $Matches.architecture.ToLowerInvariant()
    }

    if ([string]::IsNullOrWhiteSpace($version) -or
        [string]::IsNullOrWhiteSpace($architecture)) {
        return $null
    }

    [pscustomobject] @{
        ProductType = $productType
        Version = $version
        Architecture = $architecture
        Rid = "win-$architecture"
    }
}

function Get-DotNetBundleInventory {
    $registryHive = [Microsoft.Win32.RegistryHive]::LocalMachine
    # Official .NET Burn bundles register in the 32-bit Add/Remove Programs view.
    $registryView = [Microsoft.Win32.RegistryView]::Registry32
    $uninstallPath = 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall'
    $bundles = New-Object System.Collections.Generic.List[object]
    $baseKey = $null
    $uninstallKey = $null

    try {
        $baseKey = [Microsoft.Win32.RegistryKey]::OpenBaseKey($registryHive, $registryView)
        $uninstallKey = $baseKey.OpenSubKey($uninstallPath)
        if ($null -eq $uninstallKey) {
            return @()
        }

        foreach ($subkeyName in $uninstallKey.GetSubKeyNames()) {
            $bundleKey = $uninstallKey.OpenSubKey($subkeyName)
            if ($null -eq $bundleKey) {
                continue
            }

            try {
                $displayName = [string] $bundleKey.GetValue('DisplayName')
                $displayVersion = [string] $bundleKey.GetValue('DisplayVersion')
                $bundleVersion = [string] $bundleKey.GetValue('BundleVersion')
                $publisher = [string] $bundleKey.GetValue('Publisher')
                $uninstallString = [string] $bundleKey.GetValue('UninstallString')
                $quietUninstallString = [string] $bundleKey.GetValue('QuietUninstallString')
                $bundleCachePath = [string] $bundleKey.GetValue('BundleCachePath')

                $productType = Get-DotNetProductType -DisplayName $displayName
                $isVisualStudioOwned =
                    $displayName.IndexOf('Visual Studio', [StringComparison]::OrdinalIgnoreCase) -ge 0 -or
                    $displayName.IndexOf('VS 2015', [StringComparison]::OrdinalIgnoreCase) -ge 0 -or
                    $displayName.IndexOf('Local Feed', [StringComparison]::OrdinalIgnoreCase) -ge 0
                $isExeBundle =
                    $uninstallString.IndexOf('.exe', [StringComparison]::OrdinalIgnoreCase) -ge 0 -and
                    $uninstallString.IndexOf('msiexec', [StringComparison]::OrdinalIgnoreCase) -lt 0

                if ($null -eq $productType -or -not $isExeBundle -or
                    $publisher -cne 'Microsoft Corporation' -or
                    [string]::IsNullOrWhiteSpace($displayVersion) -or
                    [string]::IsNullOrWhiteSpace($bundleVersion)) {
                    continue
                }

                $identity = Get-DotNetBundleIdentity -DisplayName $displayName `
                    -BundleCachePath $bundleCachePath -UninstallString $uninstallString
                if ($null -eq $identity) {
                    Write-Warning "Ignoring .NET bundle '$displayName' because its version or architecture could not be determined."
                    continue
                }

                try {
                    $versionInfo = New-SdkVersionInfo -Text $identity.Version
                }
                catch {
                    Write-Warning "Ignoring .NET bundle '$displayName' because version '$($identity.Version)' is invalid."
                    continue
                }

                $bundleProviderKey = [string] $bundleKey.GetValue('BundleProviderKey')
                if ([string]::IsNullOrWhiteSpace($bundleProviderKey)) {
                    $bundleProviderKey = $subkeyName
                }

                $bundles.Add([pscustomobject] @{
                    PSTypeName = 'DotNetSteward.Installation'
                    ProductType = $identity.ProductType
                    Version = $versionInfo.Text
                    VersionInfo = $versionInfo
                    Architecture = $identity.Architecture
                    Rid = $identity.Rid
                    InstallerKind = 'Bundle'
                    ManagementSource = if ($isVisualStudioOwned) { 'VisualStudio' } else { 'Standalone' }
                    ManagedByVisualStudio = $isVisualStudioOwned
                    Owners = @($displayName)
                    IsUpdateable = -not $isVisualStudioOwned
                    IsUninstallable = -not $isVisualStudioOwned
                    DisplayName = $displayName
                    DisplayVersion = $displayVersion
                    BundleVersion = $bundleVersion
                    BundleId = $bundleProviderKey
                    BundleUpgradeCode = @($bundleKey.GetValue('BundleUpgradeCode'))
                    BundleCachePath = $bundleCachePath
                    UninstallString = $uninstallString
                    QuietUninstallString = $quietUninstallString
                    RegistryView = [string] $registryView
                    RegistrySubkey = "$uninstallPath\$subkeyName"
                })
            }
            finally {
                $bundleKey.Dispose()
            }
        }
    }
    finally {
        if ($null -ne $uninstallKey) {
            $uninstallKey.Dispose()
        }
        if ($null -ne $baseKey) {
            $baseKey.Dispose()
        }
    }

    return $bundles.ToArray()
}

function Get-DotNetSdkBundleInventory {
    return @(
        Get-DotNetInstallationInventory |
            Where-Object {
                $_.ProductType -eq 'Sdk' -and
                    $_.InstallerKind -eq 'Bundle' -and
                    $_.IsUpdateable
            }
    )
}

function Get-DotNetDependencyMap {
    $dependencyPath = 'SOFTWARE\Classes\Installer\Dependencies'
    $byProductCode = @{}

    foreach ($registryView in @(
        [Microsoft.Win32.RegistryView]::Registry32,
        [Microsoft.Win32.RegistryView]::Registry64
    )) {
        $baseKey = [Microsoft.Win32.RegistryKey]::OpenBaseKey(
            [Microsoft.Win32.RegistryHive]::LocalMachine,
            $registryView
        )
        $dependenciesKey = $baseKey.OpenSubKey($dependencyPath)
        try {
            if ($null -eq $dependenciesKey) {
                continue
            }

            foreach ($providerName in $dependenciesKey.GetSubKeyNames()) {
                $providerKey = $dependenciesKey.OpenSubKey($providerName)
                if ($null -eq $providerKey) {
                    continue
                }
                try {
                    $productCode = [string] $providerKey.GetValue($null)
                    if ($productCode -notmatch '^\{[0-9A-Fa-f-]{36}\}$') {
                        continue
                    }

                    $dependentsKey = $providerKey.OpenSubKey('Dependents')
                    try {
                        $dependents = if ($null -ne $dependentsKey) {
                            @($dependentsKey.GetSubKeyNames())
                        }
                        else {
                            @()
                        }
                    }
                    finally {
                        if ($null -ne $dependentsKey) {
                            $dependentsKey.Dispose()
                        }
                    }

                    $mapKey = $productCode.ToUpperInvariant()
                    if (-not $byProductCode.ContainsKey($mapKey)) {
                        $byProductCode[$mapKey] = [pscustomobject] @{
                            ProviderKeys = New-Object System.Collections.Generic.List[string]
                            Dependents = New-Object System.Collections.Generic.List[string]
                        }
                    }

                    if (-not $byProductCode[$mapKey].ProviderKeys.Contains($providerName)) {
                        $byProductCode[$mapKey].ProviderKeys.Add($providerName)
                    }
                    foreach ($dependent in $dependents) {
                        if (-not $byProductCode[$mapKey].Dependents.Contains($dependent)) {
                            $byProductCode[$mapKey].Dependents.Add($dependent)
                        }
                    }
                }
                finally {
                    $providerKey.Dispose()
                }
            }
        }
        finally {
            if ($null -ne $dependenciesKey) {
                $dependenciesKey.Dispose()
            }
            $baseKey.Dispose()
        }
    }

    return $byProductCode
}

function Get-DotNetInstallRoot {
    param(
        [Parameter(Mandatory = $true)]
        [ValidateSet('x64', 'x86', 'arm64')]
        [string] $Architecture
    )

    $setupPath = "SOFTWARE\dotnet\Setup\InstalledVersions\$Architecture"
    foreach ($registryView in @(
        [Microsoft.Win32.RegistryView]::Registry64,
        [Microsoft.Win32.RegistryView]::Registry32
    )) {
        $baseKey = [Microsoft.Win32.RegistryKey]::OpenBaseKey(
            [Microsoft.Win32.RegistryHive]::LocalMachine,
            $registryView
        )
        $setupKey = $baseKey.OpenSubKey($setupPath)
        try {
            if ($null -ne $setupKey) {
                $installLocation = [string] $setupKey.GetValue('InstallLocation')
                if (-not [string]::IsNullOrWhiteSpace($installLocation)) {
                    return $installLocation
                }
            }
        }
        finally {
            if ($null -ne $setupKey) {
                $setupKey.Dispose()
            }
            $baseKey.Dispose()
        }
    }

    return $null
}

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

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

        [Parameter(Mandatory = $true)]
        [ValidateSet('x64', 'x86', 'arm64')]
        [string] $Architecture,

        [AllowEmptyCollection()]
        [object[]] $OwnerBundles = @()
    )

    if ($VersionInfo.IsStable) {
        return $VersionInfo
    }

    $installRoot = Get-DotNetInstallRoot -Architecture $Architecture
    if ([string]::IsNullOrWhiteSpace($installRoot)) {
        return $VersionInfo
    }

    if ($ProductType -eq 'Sdk') {
        $frameworkPath = Join-Path $installRoot 'sdk'
    }
    else {
        $frameworkName = switch ($ProductType) {
            'Runtime' { 'Microsoft.NETCore.App' }
            'AspNetCoreRuntime' { 'Microsoft.AspNetCore.App' }
            'WindowsDesktopRuntime' { 'Microsoft.WindowsDesktop.App' }
        }
        $frameworkPath = Join-Path (Join-Path $installRoot 'shared') $frameworkName
    }

    if (-not (Test-Path -LiteralPath $frameworkPath -PathType Container)) {
        return $VersionInfo
    }

    $matches = New-Object System.Collections.Generic.List[object]
    foreach ($directory in Get-ChildItem -LiteralPath $frameworkPath -Directory -ErrorAction Stop) {
        if ($directory.Name -ne $VersionInfo.Text -and
            -not $directory.Name.StartsWith("$($VersionInfo.Text).", [StringComparison]::OrdinalIgnoreCase)) {
            continue
        }

        try {
            $matches.Add([pscustomobject] @{
                VersionInfo = New-SdkVersionInfo -Text $directory.Name
            })
        }
        catch {
            continue
        }
    }

    if ($matches.Count -eq 0) {
        return $VersionInfo
    }

    foreach ($ownerBundle in $OwnerBundles) {
        if ($ownerBundle.ProductType -eq $ProductType -and
            ($ownerBundle.VersionInfo.Text -eq $VersionInfo.Text -or
            $ownerBundle.VersionInfo.Text.StartsWith(
                "$($VersionInfo.Text).",
                [StringComparison]::OrdinalIgnoreCase
            ))) {
            return $ownerBundle.VersionInfo
        }

        if ($ownerBundle.VersionInfo.Major -eq $VersionInfo.Major -and
            $ownerBundle.VersionInfo.Minor -eq $VersionInfo.Minor -and
            -not [string]::IsNullOrWhiteSpace($ownerBundle.VersionInfo.Prerelease)) {
            $ownerMatch = @($matches | Where-Object {
                $_.VersionInfo.Prerelease -ceq $ownerBundle.VersionInfo.Prerelease
            })
            if ($ownerMatch.Count -eq 1) {
                return $ownerMatch[0].VersionInfo
            }
        }
    }

    if ($matches.Count -eq 1) {
        return $matches[0].VersionInfo
    }

    return $VersionInfo
}

function Get-DotNetPayloadInventory {
    param(
        [Parameter(Mandatory = $true)]
        [AllowEmptyCollection()]
        [object[]] $Bundles
    )

    $uninstallPath = 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall'
    $visualStudioDependent = 'VS.{AEF703B8-D2CC-4343-915C-F54A30B90937}'
    $dependencyMap = Get-DotNetDependencyMap
    $bundleById = @{}
    foreach ($bundle in $Bundles) {
        $bundleById[$bundle.BundleId.ToUpperInvariant()] = $bundle
    }
    $payloads = New-Object System.Collections.Generic.List[object]

    foreach ($registryView in @(
        [Microsoft.Win32.RegistryView]::Registry32,
        [Microsoft.Win32.RegistryView]::Registry64
    )) {
        $baseKey = [Microsoft.Win32.RegistryKey]::OpenBaseKey(
            [Microsoft.Win32.RegistryHive]::LocalMachine,
            $registryView
        )
        $uninstallKey = $baseKey.OpenSubKey($uninstallPath)
        try {
            if ($null -eq $uninstallKey) {
                continue
            }

            foreach ($subkeyName in $uninstallKey.GetSubKeyNames()) {
                $productKey = $uninstallKey.OpenSubKey($subkeyName)
                if ($null -eq $productKey) {
                    continue
                }
                try {
                    $displayName = [string] $productKey.GetValue('DisplayName')
                    $publisher = [string] $productKey.GetValue('Publisher')
                    $uninstallString = [string] $productKey.GetValue('UninstallString')
                    $productType = Get-DotNetProductType -DisplayName $displayName
                    if ($null -eq $productType -or $publisher -cne 'Microsoft Corporation' -or
                        $uninstallString.IndexOf('msiexec', [StringComparison]::OrdinalIgnoreCase) -lt 0) {
                        continue
                    }

                    $version = Get-DotNetVersionFromDisplayName -DisplayName $displayName
                    if ([string]::IsNullOrWhiteSpace($version) -or
                        $displayName -notmatch '(?i)\((?<architecture>x64|x86|arm64)\)') {
                        continue
                    }
                    $architecture = $Matches.architecture.ToLowerInvariant()

                    $productCode = $subkeyName.ToUpperInvariant()
                    $providerKeys = @()
                    $dependentIds = @()
                    if ($dependencyMap.ContainsKey($productCode)) {
                        $providerKeys = $dependencyMap[$productCode].ProviderKeys.ToArray()
                        $dependentIds = $dependencyMap[$productCode].Dependents.ToArray()
                    }

                    $managedByVisualStudio = $false
                    $owners = New-Object System.Collections.Generic.List[string]
                    $ownerBundles = New-Object System.Collections.Generic.List[object]
                    foreach ($dependentId in $dependentIds) {
                        if ($dependentId -eq $visualStudioDependent) {
                            $managedByVisualStudio = $true
                            if (-not $owners.Contains('Visual Studio')) {
                                $owners.Add('Visual Studio')
                            }
                            continue
                        }

                        $dependentKey = $dependentId.ToUpperInvariant()
                        if ($bundleById.ContainsKey($dependentKey)) {
                            $ownerBundle = $bundleById[$dependentKey]
                            $ownerName = $ownerBundle.DisplayName
                            if (-not $ownerBundles.Contains($ownerBundle)) {
                                $ownerBundles.Add($ownerBundle)
                            }
                        }
                        else {
                            $ownerName = $dependentId
                        }
                        if (-not $owners.Contains($ownerName)) {
                            $owners.Add($ownerName)
                        }
                    }

                    try {
                        $versionInfo = New-SdkVersionInfo -Text $version
                    }
                    catch {
                        Write-Warning "Ignoring .NET payload '$displayName' because version '$version' is invalid."
                        continue
                    }

                    try {
                        $versionInfo = Resolve-DotNetPayloadVersion -ProductType $productType `
                            -VersionInfo $versionInfo -Architecture $architecture `
                            -OwnerBundles $ownerBundles.ToArray()
                    }
                    catch {
                        Write-Warning "Could not refine the prerelease version for .NET payload '$displayName'; using '$version'. $($_.Exception.Message)"
                    }

                    $managementSource = if ($managedByVisualStudio) {
                        'VisualStudio'
                    }
                    elseif ($owners.Count -gt 0) {
                        'SharedInstaller'
                    }
                    else {
                        'WindowsInstaller'
                    }

                    $payloads.Add([pscustomobject] @{
                        PSTypeName = 'DotNetSteward.Installation'
                        ProductType = $productType
                        Version = $versionInfo.Text
                        VersionInfo = $versionInfo
                        Architecture = $architecture
                        Rid = "win-$architecture"
                        InstallerKind = 'Payload'
                        ManagementSource = $managementSource
                        ManagedByVisualStudio = $managedByVisualStudio
                        Owners = $owners.ToArray()
                        IsUpdateable = $false
                        IsUninstallable = $false
                        DisplayName = $displayName
                        DisplayVersion = [string] $productKey.GetValue('DisplayVersion')
                        ProductCode = $subkeyName
                        DependencyProviderKeys = $providerKeys
                        RegistryView = [string] $registryView
                        RegistrySubkey = "$uninstallPath\$subkeyName"
                    })
                }
                finally {
                    $productKey.Dispose()
                }
            }
        }
        finally {
            if ($null -ne $uninstallKey) {
                $uninstallKey.Dispose()
            }
            $baseKey.Dispose()
        }
    }

    return $payloads.ToArray()
}

function Get-DotNetInstallationInventory {
    $bundles = @(Get-DotNetBundleInventory)
    $payloads = @(Get-DotNetPayloadInventory -Bundles $bundles)
    $payloadsByIdentity = @{}

    foreach ($payload in $payloads) {
        $identity = "$($payload.ProductType)|$($payload.Version)|$($payload.Architecture)"
        if (-not $payloadsByIdentity.ContainsKey($identity)) {
            $payloadsByIdentity[$identity] = New-Object System.Collections.Generic.List[object]
        }
        $payloadsByIdentity[$identity].Add($payload)
    }

    $installations = New-Object System.Collections.Generic.List[object]
    foreach ($bundle in $bundles) {
        $identity = "$($bundle.ProductType)|$($bundle.Version)|$($bundle.Architecture)"
        if ($payloadsByIdentity.ContainsKey($identity)) {
            foreach ($payload in $payloadsByIdentity[$identity]) {
                if ($payload.ManagedByVisualStudio) {
                    $bundle.ManagedByVisualStudio = $true
                    $bundle.ManagementSource = 'StandaloneAndVisualStudio'
                    $bundle.IsUpdateable = $false
                    $bundle.IsUninstallable = $false
                }
                $bundle.Owners = @($bundle.Owners + $payload.Owners | Sort-Object -Unique)
            }
            $payloadsByIdentity.Remove($identity)
        }
        $installations.Add($bundle)
    }

    foreach ($remainingPayloads in $payloadsByIdentity.Values) {
        foreach ($payload in $remainingPayloads) {
            $installations.Add($payload)
        }
    }

    return $installations.ToArray()
}

function Sort-DotNetInstallations {
    param(
        [Parameter(Mandatory = $true)]
        [AllowEmptyCollection()]
        [object[]] $Installations
    )

    $sorted = New-Object System.Collections.Generic.List[object]
    foreach ($installation in $Installations) {
        $insertAt = $sorted.Count
        for ($index = 0; $index -lt $sorted.Count; $index++) {
            $comparison = [string]::CompareOrdinal(
                [string] $installation.ProductType,
                [string] $sorted[$index].ProductType
            )
            if ($comparison -eq 0) {
                $comparison = [string]::CompareOrdinal(
                    [string] $installation.Architecture,
                    [string] $sorted[$index].Architecture
                )
            }
            if ($comparison -eq 0) {
                $comparison = Compare-SdkVersion -Left $installation.VersionInfo `
                    -Right $sorted[$index].VersionInfo
            }
            if ($comparison -lt 0) {
                $insertAt = $index
                break
            }
        }
        $sorted.Insert($insertAt, $installation)
    }

    return $sorted.ToArray()
}

# SIG # Begin signature block
# MII9JwYJKoZIhvcNAQcCoII9GDCCPRQCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDSyyPg9T3BVSZz
# U8gEDlplm4kK4VC2ruyO+bxIb9JoWqCCIewwggXMMIIDtKADAgECAhBUmNLR1FsZ
# 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
# DQEJAzEMBgorBgEEAYI3AgEEMC8GCSqGSIb3DQEJBDEiBCD2W1SahzW4jHjwxubd
# SrxkJLM/H4ulHsXAJM01vS5lfjANBgkqhkiG9w0BAQEFAASCAYBvCD62Solz1314
# CejM7rKt0b8DFYKAuPMtdaWUwEi7C6ZO88zXDLCOi5kuHQ/eDtejXiR9w03GhJDr
# HPjMrPfVTeRS1p3TRj0V5mP/gI/3CXsLuhwIz+tC5ZHPRvffXyUrP6P4sLk35xI2
# PHL1RkmdBqTy3Ite57zmh56TsGgarkW2KW33dqc05HICjEdb5onEvR3HpthKN/GS
# nCl2uGORoVwnrW5SdbEe3sY5oJZyFyWXmcddzPN5U567TLcYIJBltV/V5embTj2k
# amdTdQh9Z6mF/b2EfT6orNBNb/p5EAbotq484I7vEOj060BiM3BI4klVSCClQmO5
# murPclcz/PjZZo2zy2cO9Js7vAKRv7FAsOD34XF5YP06kCZBE4wcTjWkHlbhmVY+
# 3+jng77MPpJa6I2+wFICTg6Lfh/NONL/xTjZDhCg6zg5ZHAAv6QF9GchQPcmF+mc
# czv9ljcUm9xTb+FMtnGpprCdWByO6LSl2cL+NRBo2BuVyp8744GhghgRMIIYDQYK
# KwYBBAGCNwMDATGCF/0wghf5BgkqhkiG9w0BBwKgghfqMIIX5gIBAzEPMA0GCWCG
# SAFlAwQCAQUAMIIBYgYLKoZIhvcNAQkQAQSgggFRBIIBTTCCAUkCAQEGCisGAQQB
# hFkKAwEwMTANBglghkgBZQMEAgEFAAQgs+Z6tFmAIAMblYimHdiFfxQ4Z4YqCmVR
# 08I98Mniui0CBmqpSyRpxxgTMjAyNjA5MjUxNjQ3NTkuMDcyWjAEgAIB9KCB4aSB
# 3jCB2zELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT
# B1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjElMCMGA1UE
# CxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEnMCUGA1UECxMeblNoaWVs
# ZCBUU1MgRVNOOjdBMDAtMDVFMC1EOTQ3MTUwMwYDVQQDEyxNaWNyb3NvZnQgUHVi
# 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
# f6ADAgECAhMzAAAAWGXN6z+h1/zSAAAAAABYMA0GCSqGSIb3DQEBDAUAMGExCzAJ
# BgNVBAYTAlVTMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNV
# BAMTKU1pY3Jvc29mdCBQdWJsaWMgUlNBIFRpbWVzdGFtcGluZyBDQSAyMDIwMB4X
# DTI1MTAyMzIwNDY1NVoXDTI2MTAyMjIwNDY1NVowgdsxCzAJBgNVBAYTAlVTMRMw
# EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
# aWNyb3NvZnQgQ29ycG9yYXRpb24xJTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVyaWNh
# IE9wZXJhdGlvbnMxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVTTjo3QTAwLTA1RTAt
# RDk0NzE1MDMGA1UEAxMsTWljcm9zb2Z0IFB1YmxpYyBSU0EgVGltZSBTdGFtcGlu
# ZyBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCdeDSk
# dpDs9UCWWf4dlmskVwugpt6SFbXIv5A0FSAUVSyNkgpqqo3iggmwkzemzSsk1I7u
# d0I1G5kNfZaC6vcCTvt5euWgFepmY7plVd4M1EIuV1bgDT81+PMntdeR0SGOvzWC
# FcSlHvML7Bto036w9LHMsBkF6JsMU/tfCznBfRm0iw3Vrb5erlu9aneREzK3CyRO
# O6dGB4tkv+0GnbfslV1E8UBD2NhEqkKpQGj+/XGMEtEJXc9qUqOcZ9vcw3hTuNXK
# qJ8UdKFydbkIRFGgGZRrqzKAPMVKvx7eD3dM80sVSK9QTQaYt9tflx4PUa3UVxnr
# H8ktUBPOTn4FYdszHAkhWRU9OpJIyNDopMp1yerekfRzgAUmn+CW9ymrRT1/NkiM
# kYa92mKyGVGXvtFC1SFKPEe8KfcsL/GpBDA4dJAOwaHo1fYPRF+xLIS1MAHIBp77
# bDUcHJMNNyaVM0sS5At4KPWA0F0haPRY5jIO2OND/yJNZjp7LW9v2oeWMiPkeAid
# 1Pk/0xiTZWDZ7uEpRk0E1sD+GyAGy6hn4hfz1a+MQ31psX3VLg4lW6KeYqws78wt
# ueXuKS4PR03qgDRh7DINCdyzXawz0c627vZAD9NmV5+9byv3G0xcBihCVwaOyTxb
# hRztx+pWpsg+N2hzxnEHMtxdxXI/inlzIvC+QwIDAQABo4IByzCCAccwHQYDVR0O
# BBYEFHKNTcV6vhXFcn6GM9xEmfGdEgmwMB8GA1UdIwQYMBaAFGtpKDo1L0hjQM97
# 2K9J6T7ZPdshMGwGA1UdHwRlMGMwYaBfoF2GW2h0dHA6Ly93d3cubWljcm9zb2Z0
# LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUyMFB1YmxpYyUyMFJTQSUyMFRpbWVz
# dGFtcGluZyUyMENBJTIwMjAyMC5jcmwweQYIKwYBBQUHAQEEbTBrMGkGCCsGAQUF
# BzAChl1odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY3Jv
# c29mdCUyMFB1YmxpYyUyMFJTQSUyMFRpbWVzdGFtcGluZyUyMENBJTIwMjAyMC5j
# cnQwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAOBgNVHQ8B
# Af8EBAMCB4AwZgYDVR0gBF8wXTBRBgwrBgEEAYI3TIN9AQEwQTA/BggrBgEFBQcC
# ARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9Eb2NzL1JlcG9zaXRv
# cnkuaHRtMAgGBmeBDAEEAjANBgkqhkiG9w0BAQwFAAOCAgEAe+vEiJUXWIdxe/Gs
# lMIPx461s9Rsr3H4vPvSJh6GH4bRSg4xwx/ThAPq1A9N5nkeEYRORyfStoMnk2l9
# tEG4oQffWvFtkr3ujXYpEM0nc27h49pQikf9NxbPw8tU4IQLLBLFsSAQbbSTLJ0Z
# zjpzn3W1fOl+QkNySOhivKlp6t15AtFAf0tqhNhl90DMyj4PLQ7UPMUmQXlieyYA
# zyW32vU21d0WN1sUwJtXl1q7riZXbazXzoDxSaL6Xbf35R7RxslAjKRaEiWGFaHF
# CCiSyofPuSnYYVkAB7JJOYg5A5bJc4DwkDxMhInKfckM6BK2/nzc/dXRBIAtPolc
# MJbboVXbTxUYkzOS/RLbaI5Nkn+hqZOmTxHMPyhZPyl9t7Wr+T9vE+JdhFvOmz3p
# rlg6SjufRV2jrUM4mEv+aGTTVjfjyCrq+Eb9VNx0YeHWsKTA4zTkHfkBlmr0C0+l
# 9HMmKesfPMZHH6vp8Pdxxgw8wxf83B3aKvOumHXvZ9BxJ/V8zC/AiGZ8fgZYkn6Z
# /UcDq5egA5UHJySC5e+WPyA+LtPYRLpFTz5Cyx+pM1MkqOwGF5Ypa/ZbgRJV6fYv
# uULPuLv0WED7SSnTJcmdjB3NZLSi9Mg1Qsg2bNXIxxJSbla5V/xhnfdwC53Y6mvo
# 3X5G4tkNq8O+OJ6GUjl0f4YTLnoxggdDMIIHPwIBATB4MGExCzAJBgNVBAYTAlVT
# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jv
# c29mdCBQdWJsaWMgUlNBIFRpbWVzdGFtcGluZyBDQSAyMDIwAhMzAAAAWGXN6z+h
# 1/zSAAAAAABYMA0GCWCGSAFlAwQCAQUAoIIEnDARBgsqhkiG9w0BCRACDzECBQAw
# GgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yNjA5
# MjUxNjQ3NTlaMC8GCSqGSIb3DQEJBDEiBCDAYMNLcxU+gB5OlG1MvLRfGkNI3wfY
# KB7Rn8f1vV5GjzCBuQYLKoZIhvcNAQkQAi8xgakwgaYwgaMwgaAEIMUiVLuyB9D7
# ACjVxZtbP5Y3r1UF2znyFutqf3X1ouhxMHwwZaRjMGExCzAJBgNVBAYTAlVTMR4w
# HAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29m
# dCBQdWJsaWMgUlNBIFRpbWVzdGFtcGluZyBDQSAyMDIwAhMzAAAAWGXN6z+h1/zS
# AAAAAABYMIIDXgYLKoZIhvcNAQkQAhIxggNNMIIDSaGCA0UwggNBMIICKQIBATCC
# AQmhgeGkgd4wgdsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw
# DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
# JTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVyaWNhIE9wZXJhdGlvbnMxJzAlBgNVBAsT
# Hm5TaGllbGQgVFNTIEVTTjo3QTAwLTA1RTAtRDk0NzE1MDMGA1UEAxMsTWljcm9z
# b2Z0IFB1YmxpYyBSU0EgVGltZSBTdGFtcGluZyBBdXRob3JpdHmiIwoBATAHBgUr
# DgMCGgMVAJ1keRvbp6twXY7ra8J1lR9RK8RcoGcwZaRjMGExCzAJBgNVBAYTAlVT
# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jv
# c29mdCBQdWJsaWMgUlNBIFRpbWVzdGFtcGluZyBDQSAyMDIwMA0GCSqGSIb3DQEB
# CwUAAgUA7mD4kDAiGA8yMDI2MDkyNTEzNDEzNloYDzIwMjYwOTI2MTM0MTM2WjB0
# MDoGCisGAQQBhFkKBAExLDAqMAoCBQDuYPiQAgEAMAcCAQACAhXJMAcCAQACAhKP
# MAoCBQDuYkoQAgEAMDYGCisGAQQBhFkKBAIxKDAmMAwGCisGAQQBhFkKAwKgCjAI
# AgEAAgMHoSChCjAIAgEAAgMBhqAwDQYJKoZIhvcNAQELBQADggEBAEl1GKC+sSTG
# lSc+Lp+Hvg3cz2LCZMFBVz6cILptVNt10p4Ar6T57m0A8IXkntaHF7SfTfpOggfk
# yzGOI8XGarDqVXTSePevGe+TJx34MOz1HvH9RrPPkXWYA3vppzvna3Rp0IIpdhal
# //fuvcBZYK+OUAeCoT7ndXMLOKqsEhgPBAsI3BH4jr2007VqsARhukL/QwsoUq6v
# g42acMdT37u/K1Pg+krXt9sFR36fxFPe1aAvWRlmZHkSNQB5mpFc9INdTRpMk17y
# CYMjHTQKWGhiLzu5GuE2MVDZEgSSGfbGOIVfPSx64/Dz6Y6ilARNlh1F/B7ewApw
# /0cH09DqoIswDQYJKoZIhvcNAQEBBQAEggIAeHOTbk6o/2I28JNMGiiVJFuRhelM
# oNPtsPFgHN7NOrkKT5Y0CXag+PPvb/J18FBFNMyvPIoOzap7kkEPVPwB5OrLpXM3
# ZYKZCx1mVRAAxGz5ceEUwN3rlK2rmY/BOmcnxvqqfE4071I6j482vSDdQBp6+IIK
# qRRoRHJcx9JNYYldSB/lTjW1sDPbr/qW4lqp3Ilc+fVjxIJEtR5ZfDCHpOfsJEFm
# fzRfNxadnuH+zRqij9c1aO2vX/3evdMt2Gl2lyUUJfNTd7lBk47oob+Yh6AY8BdG
# Ul+RNGVpfKMSSllK+qC2CFhZnRUbnWxh6gQfZ/bDJoONFTNIDLqf+0LVD5qez7Wq
# VE8RuHK/21DQioZ3MfccKw9xXrB0zHA3OBOneY5jQZ9KnX45gV1R3NLGKgDpqp6z
# x+ejEk7sxexM7K3JUqFt08MhA+DdYzYl+JoNj6eLeuRnMmNx1n5tc/DJ/Hfy6Wx+
# yeH5QPt2e/wkOh7qq97ggMBxYPGVSthg04Ohux0aupqnT2OmL4xnQEInq/Y1BseW
# 6rS7PEFgGUH1tJM0ZA7/Ij9ggKeQ2am6o3x0k9y6bulpmzqOfYXZDNFrkZkTm8oA
# Qsr9OZpzmYQ3oe6LV/L5/R+VGjhYpP2hnHvjAefBupoZgEafQFsGMhFc6eRU4crQ
# ZED53HZq+ZhFKOA=
# SIG # End signature block