Private/Get-Utils.ps1

#
# © Copyright 2018-2021, 2026 Hewlett Packard Enterprise Development LP
# All Rights Reserved
#

$JSON_HEADER = 'application/vnd.simplivity.v1.10+json'
$JSON_API15_HEADER = 'application/vnd.simplivity.v1.15+json'
$JSON_API16_HEADER = 'application/vnd.simplivity.v1.16+json'
$JSON_API17_HEADER = 'application/vnd.simplivity.v1.17+json'
$BEGIN_CERTIFICATE = '-----BEGIN CERTIFICATE-----'
$END_CERTIFICATE = '-----END CERTIFICATE-----'
$CRED_XML_PATH = Join-Path $HOME HPESvtCertificate.ps1.credential
$VALID_RBAC_ROLES = 'Administrator', 'BackupUser'

# Module-level flag to track certificate bypass initialization
$script:SvtCertBypassReady = $false

function SetCredXml {
    param(
        $configObject
    )
    if (!(Get-IsPowerShellCore)) { #Export/Import-Clixml with encrypted content not supported on PowerShell Core
        $configObject.AccessToken = ConvertTo-SecureString $configObject.AccessToken -AsPlainText -Force
    }
    $configObject | Export-Clixml $CRED_XML_PATH -Force
    return $CRED_XML_PATH
}

function GetCredXml {
    if (![System.IO.File]::Exists($CRED_XML_PATH)) {
        throw "Could not authenticate. Run Get-HPESvtAuthToken to authenticate."
    }
    
    $configObject = Import-Clixml $CRED_XML_PATH
    if (!(Get-IsPowerShellCore)) { #Export/Import-Clixml with encrypted content not supported on PowerShell Core
        $configObject.AccessToken = (New-Object PSCredential "user",$configObject.AccessToken).GetNetworkCredential().Password
    }
    return $configObject
}

function Get-IsPowerShellCore {
    $PSVersionTable.PSEdition -and $PsVersionTable.PSEdition -eq 'Core'
}

function Get-BaseUrl {
    param(
        [string] $hostname
    )

    'https://' + $hostname + '/api'
}

function Get-CertificateUrl {
    param(
        [string] $hostname
    )

    $baseUrl = Get-BaseUrl $hostname
    return $baseUrl + '/certificates'
}

function Get-RbacUrl {
    param(
        [string] $hostname
    )

    $baseUrl = Get-BaseUrl $hostname
    return $baseUrl + '/security/rbac'
}

function Get-RbacRoleAssignmentUrl {
    param(
        [string] $hostname
    )

    $baseUrl = Get-RbacUrl $hostname
    return $baseUrl + '/policies/role_assignments'
}

function Get-RbacRoleRemovalUrl {
    param(
        [string] $hostname
    )

    $baseUrl = Get-RbacUrl $hostname
    return $baseUrl + '/policies/role_assignments/remove'
}

function Get-Header {
    param(
        [string] $accessToken
    )

    @{
        'Authorization' = ("Bearer {0}" -f $accessToken);
        'Accept'=$JSON_HEADER
    }
}

# Add -SkipCertificateCheck flag if on PowerShell Core. This flag only exists in PowerShell 6.0 or later.
# There is an alternate way to do this on earlier versions of PowerShell, so just set this for PowerShell Core.
function Get-SkipCertificateFlag {
    $skipCertificateFlag = @{}
    if (Get-IsPowerShellCore) {
        $skipCertificateFlag.add("SkipCertificateCheck", $true)  
    }
    $skipCertificateFlag
}

# Skip certificate checking for 5.1. For some reason the standard way of disabling certificate checking does not
# work when connecting to the VmWare HMS, but this snippet of C# does.
# Force Tls version to 1.2. This fixes a defect when connecting to a system with Tls 1.0 disabled.
# Version-aware certificate validation bypass
# PS 7.x+: No-op (uses -SkipCertificateCheck cmdlet parameter)
# PS 5.1: Uses legacy callback mechanism
function Skip-CertificateCheck {
    # PowerShell Core handles this via -SkipCertificateCheck parameter
    if (Get-IsPowerShellCore) {
        Write-Verbose "HPESvtCmdlets: Certificate validation handled via cmdlet parameter"
        return
    }

    # Already configured for this session
    if ($script:SvtCertBypassReady) {
        Write-Verbose "HPESvtCmdlets: Certificate bypass already configured"
        return
    }

    Write-Warning "Bypassing certificate validation. Use only in trusted environments."

    # PowerShell 5.1 - configure legacy bypass
    try {
        # Search for existing type in loaded assemblies
        $typeFound = $false
        foreach ($asm in [System.AppDomain]::CurrentDomain.GetAssemblies()) {
            try {
                $testType = $asm.GetType('SvtTlsValidationBypass', $false, $false)
                if ($null -ne $testType) {
                    $typeFound = $true
                    Write-Verbose "Found SvtTlsValidationBypass in assembly: $($asm.FullName)"
                    break
                }
            }
            catch {
                # Some assemblies don't support type lookup
            }
        }

        if (-not $typeFound) {
            $tlsBypassDefinition = @'
            using System;
            using System.Net;
            using System.Net.Security;
            using System.Security.Cryptography.X509Certificates;
 
            public sealed class SvtTlsValidationBypass {
                private static readonly object SyncRoot = new object();
                private static bool Configured = false;
 
                public static void Configure() {
                    lock (SyncRoot) {
                        if (Configured) return;
                        ServicePointManager.ServerCertificateValidationCallback = TrustAllCallback;
                        Configured = true;
                    }
                }
 
                private static bool TrustAllCallback(
                    object requestSender,
                    X509Certificate serverCert,
                    X509Chain certChain,
                    SslPolicyErrors policyErrors) {
                    return true;
                }
            }
'@

            Add-Type -TypeDefinition $tlsBypassDefinition -Language CSharp -ErrorAction Stop
        }

        [SvtTlsValidationBypass]::Configure()
        $script:SvtCertBypassReady = $true
    }
    catch {
        Write-Warning "HPESvtCmdlets: TLS bypass setup failed - $($_.Exception.Message)"
    }

    # Ensure TLS 1.2 is enabled for PS 5.1
    try {
        $currentProtocols = [System.Net.ServicePointManager]::SecurityProtocol
        $tls12 = [System.Net.SecurityProtocolType]::Tls12
        if (-not ($currentProtocols -band $tls12)) {
            [System.Net.ServicePointManager]::SecurityProtocol = $currentProtocols -bor $tls12
        }
    }
    catch {
        Write-Verbose "HPESvtCmdlets: Protocol configuration skipped"
    }
}

# Get X509Certificate2 from base64 encoded string from the server.
# This will include Begin/End Certificate strings and newlines that need to be trimmed.
function Get-CertificateFromBase64String {
    param(
        [string] $base64String
    )
    $base64String = $base64String.Trim()
    $base64String = $base64String.Trim($BEGIN_CERTIFICATE)
    $base64String = $base64String.Trim($END_CERTIFICATE)
    $byteArray = [System.Convert]::FromBase64String($base64String)
    $cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::New($byteArray)
    Write-Output $cert
}

# see table at https://docs.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed
function Get-IsRunningNet47 {

    # Core has everything we need for 4.7 interop
    if (Get-IsPowerShellCore) {
        return;
    }

    $running = Get-CheckDotNetVersion -version 460805
    if ($running -eq $false)
    {
        throw "This cmdlet requires .net 4.7"
    }

}

function Get-CheckDotNetVersion {
    param(
        [int] $version
    )

    try {

        $installed = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full')
        if ($version -gt $installed.Release)
        {
            return $false
        }

        return $true
    }
    catch {
        Write-Error "Error while determining .NET version"       
    }

    return $false        
}

function Copy-Hashtable {
    param(
        [Parameter(Mandatory=$true)]
        [ValidateNotNull()]
        [hashtable]$DeepCopyObject
    )

    # JSON-based deep copy - works on both PS 5.1 and PS 7.x
    # Replaces BinaryFormatter which was removed in .NET 9
    try {
        $json = $DeepCopyObject | ConvertTo-Json -Depth 10 -Compress

        if (Get-IsPowerShellCore) {
            # PS 6.0+ supports -AsHashtable parameter
            return ($json | ConvertFrom-Json -AsHashtable)
        }
        else {
            # PS 5.1: ConvertFrom-Json returns PSCustomObject, convert to hashtable
            $obj = $json | ConvertFrom-Json
            $hashtable = @{}
            $obj.PSObject.Properties | ForEach-Object {

                $hashtable[$_.Name] = $_.Value
            }
            return $hashtable
        }
    }
    catch {
        throw "Failed to clone hashtable: $($_.Exception.Message)"
    }
}

function Approve-HostOAuthToken {
    param(
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [HashTable] $HostOAuthToken
    )

    # Validate the 'Hostname' portion of the Host OAuth Token composite.
    $hostname = $HostOAuthToken['Hostname']
    if (-not $hostname) {
        throw "HostOAuthToken hash table missing 'Hostname' key"
    }
    if ([string]::IsNullOrWhiteSpace($hostname)) {
        throw "HostOAuthToken hash table 'Hostname' value contains only white space"
    }

    # Validate the 'OAuthHeader' portion of the Host OAuth Token composite.
    if (-not $HostOAuthToken['OAuthHeader']) {
        throw "HostOAuthToken hash table missing 'OAuthHeader' key"
    }
    if ($HostOAuthToken['OAuthHeader'].GetType().FullName -ne 'System.Collections.Hashtable') {
        throw "HostOAuthToken hash table 'OAuthHeader' value is not a hash table"
    }
    if ($HostOAuthToken['OAuthHeader'].Count -lt 1) {
        throw "HostOAuthToken hash table 'OAuthHeader' value is expected to have at least one entry"
    }
    if (-not ($HostOAuthToken['OAuthHeader']['Authorization'])) {
        throw "HostOAuthToken hash table 'OAuthHeader' value is missing the 'Authorization' key"
    }
    if ([string]::IsNullOrWhiteSpace($HostOAuthToken['OAuthHeader']['Authorization'])) {
        throw "HostOAuthToken hash table 'OAuthHeader' value hash table 'Authorization' value contains only white space"
    }
    if (-not ($HostOAuthToken['OAuthHeader']['Authorization']).StartsWith("Bearer ")) {
        throw "HostOAuthToken hash table 'OAuthHeader' value hash table 'Authorization' value is invalid"
    }
}

function Get-PkiUrl {
    param(
        [string] $hostname
    )

    $baseUrl = Get-BaseUrl $hostname
    return $baseUrl + '/security/pki/ca'
}

function Get-HostsUrl {
    param(
        [string] $hostname
    )

    $baseUrl = Get-BaseUrl $hostname
    return $baseUrl + '/hosts'
}

function Get-VersionUrl {
    param(
        [string] $hostname
    )
    $baseUrl = Get-BaseUrl $hostname
    return $baseUrl + '/version'
}

function Get-TokenUrl {
    param(
        [string] $hostname
    )
    $baseUrl = Get-BaseUrl $hostname
    return $baseUrl + '/oauth/token'
}

function Get-TokenRevokeUrl {
    param(
        [string] $hostname
    )
    $baseUrl = Get-BaseUrl $hostname
    return $baseUrl + '/oauth/revoke'
}

function Get-MvaNodeUrl {
    param(
        [string] $hostname
    )
    $baseUrl = Get-BaseUrl $hostname
    return $baseUrl + '/configuration/mva/nodes'
}

# Helper function to return the embedded error message in the body of the response from the API, rather
# than a generic runtime (404) error.
function Get-SvtError {
    [CmdletBinding()]
    Param (
        [Parameter(Mandatory = $true, Position = 0)]
        [System.Object]$Err
    )

    #$VerbosePreference = 'Continue'
    if (-not (Get-IsPowerShellCore)) {
        if ($Err.Exception.Response) {
            $Result = $Err.Exception.Response.GetResponseStream()
            $Reader = New-Object System.IO.StreamReader($Result)
            $Reader.BaseStream.Position = 0
            $Reader.DiscardBufferedData()
            $ResponseBody = $Reader.ReadToEnd()
            Write-Verbose $ResponseBody
            if ($ResponseBody.StartsWith('{')) {
                $ResponseBody = $ResponseBody | ConvertFrom-Json
            }
            return $ResponseBody.Message
        } else {
            return $Err.Exception.Message #This return incase there is no response or host is not not reachable
        }
    }
    else {
        # PowerShell V6 doesn't support GetResponseStream(), so return the generic runtime error
        return $Err.Exception.Message
    }
}

# Helper function for Invoke-RestMethod to handle REST errors in one place. The calling function
# then re-throws the error, generated here. This cmdlet either outputs a custom task object if the
# REST API response is a task object, or otherwise the raw JSON.
function Invoke-SvtRestMethod {
    [CmdletBinding()]
    param (

        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory=$true, Position = 0, HelpMessage='Input a valid host OAuth token composite')]
        [HashTable] $HostOAuthToken,

        [Parameter(Mandatory = $true, Position = 1)]
        [System.Object]$Uri,

        [Parameter(Mandatory = $false, Position = 2)]
        [System.Collections.IDictionary]$Header,

        [Parameter(Mandatory = $true, Position = 3)]
        [ValidateSet('get', 'post', 'delete', 'put')]
        [System.String]$Method,

        [Parameter(Mandatory = $false, Position = 4)]
        [System.Object]$Body
    )
    [System.int32]$Retrycount = 0
    [bool]$Stoploop = $false
    do {
        try {
            $skipCertParam = Get-SkipCertificateFlag
            if ($PSBoundParameters.ContainsKey('Body')) {
                $Response = Invoke-RestMethod -Uri $Uri -Headers $Header -Body $Body -Method $Method @skipCertParam
            }
            else {
                $Response = Invoke-RestMethod -Uri $Uri -Headers $Header -Method $Method @skipCertParam
            }
            $Stoploop = $true
        }
        catch [System.Management.Automation.RuntimeException] {
            if ($_.Exception.Message -match "Unauthorized") {
                if ($Retrycount -ge 3) {
                    # Exit after 3 retries
                    throw "Runtime error: Session expired and could not reconnect"
                }
                else {
                    $Retrycount += 1
                    Write-Verbose "Session expired, reconnecting..."
                    Renew-SvtSession -HostOAuthToken $HostOAuthToken
                    $Header.Authorization = "Bearer " + $HostOAuthToken.AccessToken
                }
            }
            else {
                throw "Runtime error: $(Get-SvtError($_))"
            }
        }
        catch {
            throw "An unexpected error occurred: $($_.Exception.Message)"
        }
    }
    until ($Stoploop -eq $true)

    # If the JSON output is a task, convert it to a custom object of type 'HPE.SimpliVity.Task' and pass this
    # back to the calling cmdlet. A lot of cmdlets produce task object types, so this cuts out repetition
    # in the module.
    # Note: $Response.task is incorrectly true with /api/omnistack_clusters/throughput, so added a check for this.
    if ($Response.task -and $URI -notmatch '/api/omnistack_clusters/throughput') {

        $LocalFormat = Get-SvtLocalDateFormat

        $Response.task | ForEach-Object {
            if ($_.start_time -as [datetime]) {
                $StartTime = Get-Date -Date $_.start_time -Format $LocalFormat
            }
            else {
                $StartTime = $null
            }
            if ($_.end_time -as [datetime]) {
                $EndTime = Get-Date -Date $_.end_time -Format $LocalFormat
            }
            else {
                $EndTime = $null
            }
            [PSCustomObject]@{
                StartTime       = $StartTime
                TaskResult      = $_.task_results
                AffectedObjects = $_.affected_objects
                OwnerId         = $_.owner_id
                DestinationId   = $_.destination_id
                Name            = $_.name
                EndTime         = $EndTime
                ErrorCode       = $_.error_code
                ErrorMessage    = $_.error_message
                State           = $_.state
                TaskId          = $_.id
                Type            = $_.type
                PercentComplete = $_.percent_complete
                SubTasks        = $_.sub_tasks
            }
        }
    }
    else {
        # For all other object types, return the raw JSON output for the calling cmdlet to deal with
        $Response
    }
}

# Helper function that returns the local date format. Used by cmdlets that return date properties
function Get-SvtLocalDateFormat {
    $Culture = (Get-Culture).DateTimeFormat
    $LocalDate = "$($Culture.ShortDatePattern)" -creplace '^d/', 'dd/' -creplace '^M/', 'MM/' -creplace '/d/', '/dd/'
    $LocalTime = "$($Culture.LongTimePattern)" -creplace '^h:mm', 'hh:mm' -creplace '^H:mm', 'HH:mm'
    return "$LocalDate $LocalTime"
}

#Helper function to identify the IP/Hostname provided is an MVA or SVA
function Identify-Host {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [string] $Hostname
    )

    $response = Get-SvtVersion -Hostname $Hostname
    $response | ForEach-Object {
        if ($_.Aggregator_Version) {
            return "MVA"
        }
        elseif ($_.SVTFS_Version)
        {
            return "SVA"
        }
        else {
            throw "The provided IP/hostname is not an SVA/MVA"
        }
    }
}

#Helper function to get the version information from the SVA/MVA IP/hostname provided.
function Get-SvtVersion {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, HelpMessage = "Input the MVA/SVA Hostname/IP")]
        [Alias("mva", "ovc")]
        [string] $Hostname
    )

    $url = Get-VersionUrl -hostname "$Hostname"
    $skipCertParam = Get-SkipCertificateFlag
    try
    {
        $response = Invoke-RestMethod -Uri $url -Method Get @skipCertParam
    }
    catch
    {
        throw "The host $Hostname is not reachable or not a MVA or SVA" + $_.Exception.Message
    }

    return $response
}

function Get-SvtVersionUrl {
    param(
        [string] $hostname
    )

    $baseUrl = Get-BaseUrl $hostname
    return $baseUrl + '/version'
}

function Get-SvtPolicyUrl {
    param(
        [string] $hostname
    )

    $baseUrl = Get-BaseUrl $hostname
    return $baseUrl + '/policies'
}

function Check-ClusterTopology {
    param(
        [ValidateNotNullOrEmpty()]
        [Parameter(Mandatory=$true, HelpMessage='Input a valid host OAuth token composite')]
        [HashTable] $HostOAuthToken
    
    )

    $Url = Get-MvaNodeUrl -Hostname $HostOAuthToken.Hostname
    $Header = @{
        'Authorization' = "Bearer " + $HostOAuthToken.AccessToken
        'Accept'        = 'application/json'
    }
    #Multifed check
    try {
        $Response = Invoke-SvtRestMethod -HostOAuthToken $HostOAuthToken -Uri $Url -Header $Header -Method Get -ErrorAction Stop
    } catch {
        throw ($_)
    }

    if ($Response.cluster_topology -eq "MULTI_FED") {
        return $true
    }
    return $false
}

#Function to pick a single cluster from a list of Cluster objects.
#This will be used to select a cluster where there are more than one cluster with same name
function Select-Cluster {
    param (
        [Parameter(Mandatory = $true)]
        $ClusterList #List of HPE Simplivity cluster object from Get-Omnistack cluster list
    )
    $ClusterCount = ($ClusterList | Measure-Object).count
    Write-Warning ("There are multiple HPE SimpliVity clusters with the Name $ClusterName") -WarningAction "Continue"

    foreach ($Count in 0..($ClusterCount - 1)) {
        Write-host (($Count + 1).ToString() + ". " + $ClusterList[$Count].HypervisorManagementName + "/" + $ClusterList[$Count].DataCenterName + "/" + $ClusterList[$Count].ClusterName)
    }
    if ($ClusterCount -gt 9) {
        throw("There are more than nine HPE SimpliVity clusters with the name $ClusterName. Use HPE SimpliVity cluster id instead of cluster name in the command line")
    }
    Write-host ("Select a HPE SimpliVity cluster from the above list to apply configuration changes (Select between 1 to $ClusterCount)")

    do {
        [Int]$Selection = Get-KeyStroke
        if (($Selection -lt 1) -or ($Selection -gt $ClusterCount)) {
            Write-Warning ("Input a valid number from 1 to $ClusterCount")
        }
    } while (($Selection -lt 1) -or ($Selection -gt $ClusterCount))

    Write-Host ("Selected Cluster is : " + $ClusterList[($Selection - 1)].HypervisorManagementName + "/" + $ClusterList[($Selection - 1)].DataCenterName + "/" + $ClusterList[($Selection - 1)].ClusterName)
    return $ClusterList[($Selection - 1)]
}

#Helper function to take the key stroke from the command line with default timeout of 60 seconds.
function Get-KeyStroke {
    param (
        [Int]$Timeout = 60,
        [Int]$SleepTime = 1
    )

    [int]$KeyOut = 0
    $Timer = [Diagnostics.Stopwatch]::StartNew()
    do {
        $TotalSecs = [Math]::Round($Timer.Elapsed.TotalSeconds, 0)
        if ([Console]::KeyAvailable){
            $Key = $Host.UI.RawUI.ReadKey("IncludeKeyDown")
            Write-host("`n")
            if ([int]::TryParse($Key.Character, [ref]$KeyOut)) {
                break
            } else {
                Write-Warning ("Invalid input")
            }
        }
        Start-Sleep $SleepTime
    } while($Timer.Elapsed.TotalSeconds -lt $Timeout)

    $Timer.Stop()
    if($Timer.Elapsed.TotalSeconds -gt $Timeout) {
        throw ("Timed out for the user input")
    }
    return $KeyOut
}

function Invoke-SvtRestMethodWithRetry {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, Position = 1)]
        [ValidateSet('get', 'post', 'delete', 'put')]
        [String]$Method,

        [Parameter(Mandatory = $true, Position = 2)]
        [String]$Uri,

        [Parameter(Mandatory = $false, Position = 3)]
        [Hashtable]$Headers,

        [Parameter(Mandatory = $false, Position = 4)]
        [Object]$Body,

        [Parameter(Mandatory = $false, Position = 5)]
        [Int32]$MaximumRetries = 12,

        [Parameter(Mandatory = $false, Position = 6)]
        [Int32]$SleepIntervalInSecs = 10,

        [Parameter(Mandatory = $false, Position = 7)]
        [Int32[]]$ErrorCodesOnRetry = @(503)
    )

    [Int32]$Retrycount = 0
    [bool]$Stoploop = $false

    do {
        try {
            $skipCertParam = Get-SkipCertificateFlag
            $Response = Invoke-RestMethod -Uri $Uri -Headers $Headers -Body $Body -Method $Method @skipCertParam

            $Stoploop = $true
            Write-Output $Response
        }
        catch {
            $Stoploop = $true
            if ($Retrycount -lt $MaximumRetries) {
                if ($_.Exception.Response) {
                    $errorCode = $_.Exception.Response.StatusCode.value__;
                    if ($ErrorCodesOnRetry.contains($errorCode)) {
                        $Retrycount = $Retrycount + 1
                        Write-Host "Server ($Method $Uri) unavailable! will reconnect after $SleepIntervalInSecs seconds, attempt #$Retrycount/$MaximumRetries"
                        Start-Sleep -Seconds $SleepIntervalInSecs
                        $Stoploop = $false
                    }
                    else {
                        throw $_.Exception
                    }
                }
                else {
                    throw $_.Exception
                }
            }
            else {
                throw $_.Exception
            }
        }
    } While ($Stoploop -eq $false)
}

function Get-GenerateCSRUrl {
    param(
        [string] $hostname
    )

    $baseUrl = Get-BaseUrl $hostname
    return $baseUrl + '/security/pki/generate_csr'
}

function Get-TLSCertChainUrl {
    param(
        [string] $hostname
    )

    $baseUrl = Get-BaseUrl $hostname
    return $baseUrl + '/security/pki/import_tls_cert_chain'
}

function Get-VerifyCRLUrl {
    param(
        [string] $hostname
    )

    $baseUrl = Get-BaseUrl $hostname
    return $baseUrl + '/security/pki/verify_crl'
}

# SIG # Begin signature block
# MIIungYJKoZIhvcNAQcCoIIujzCCLosCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDCqJMAAn/HzMD5
# uhqwGWPeNWyF5ciOxbU6iqMIjDAv3KCCEfYwggVvMIIEV6ADAgECAhBI/JO0YFWU
# jTanyYqJ1pQWMA0GCSqGSIb3DQEBDAUAMHsxCzAJBgNVBAYTAkdCMRswGQYDVQQI
# DBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoM
# EUNvbW9kbyBDQSBMaW1pdGVkMSEwHwYDVQQDDBhBQUEgQ2VydGlmaWNhdGUgU2Vy
# dmljZXMwHhcNMjEwNTI1MDAwMDAwWhcNMjgxMjMxMjM1OTU5WjBWMQswCQYDVQQG
# EwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMS0wKwYDVQQDEyRTZWN0aWdv
# IFB1YmxpYyBDb2RlIFNpZ25pbmcgUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEBAQUA
# A4ICDwAwggIKAoICAQCN55QSIgQkdC7/FiMCkoq2rjaFrEfUI5ErPtx94jGgUW+s
# hJHjUoq14pbe0IdjJImK/+8Skzt9u7aKvb0Ffyeba2XTpQxpsbxJOZrxbW6q5KCD
# J9qaDStQ6Utbs7hkNqR+Sj2pcaths3OzPAsM79szV+W+NDfjlxtd/R8SPYIDdub7
# P2bSlDFp+m2zNKzBenjcklDyZMeqLQSrw2rq4C+np9xu1+j/2iGrQL+57g2extme
# me/G3h+pDHazJyCh1rr9gOcB0u/rgimVcI3/uxXP/tEPNqIuTzKQdEZrRzUTdwUz
# T2MuuC3hv2WnBGsY2HH6zAjybYmZELGt2z4s5KoYsMYHAXVn3m3pY2MeNn9pib6q
# RT5uWl+PoVvLnTCGMOgDs0DGDQ84zWeoU4j6uDBl+m/H5x2xg3RpPqzEaDux5mcz
# mrYI4IAFSEDu9oJkRqj1c7AGlfJsZZ+/VVscnFcax3hGfHCqlBuCF6yH6bbJDoEc
# QNYWFyn8XJwYK+pF9e+91WdPKF4F7pBMeufG9ND8+s0+MkYTIDaKBOq3qgdGnA2T
# OglmmVhcKaO5DKYwODzQRjY1fJy67sPV+Qp2+n4FG0DKkjXp1XrRtX8ArqmQqsV/
# AZwQsRb8zG4Y3G9i/qZQp7h7uJ0VP/4gDHXIIloTlRmQAOka1cKG8eOO7F/05QID
# AQABo4IBEjCCAQ4wHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Klf9AwpLQwHQYD
# VR0OBBYEFDLrkpr/NZZILyhAQnAgNpFcF4XmMA4GA1UdDwEB/wQEAwIBhjAPBgNV
# HRMBAf8EBTADAQH/MBMGA1UdJQQMMAoGCCsGAQUFBwMDMBsGA1UdIAQUMBIwBgYE
# VR0gADAIBgZngQwBBAEwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5jb21v
# ZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYIKwYBBQUHAQEE
# KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZI
# hvcNAQEMBQADggEBABK/oe+LdJqYRLhpRrWrJAoMpIpnuDqBv0WKfVIHqI0fTiGF
# OaNrXi0ghr8QuK55O1PNtPvYRL4G2VxjZ9RAFodEhnIq1jIV9RKDwvnhXRFAZ/ZC
# J3LFI+ICOBpMIOLbAffNRk8monxmwFE2tokCVMf8WPtsAO7+mKYulaEMUykfb9gZ
# pk+e96wJ6l2CxouvgKe9gUhShDHaMuwV5KZMPWw5c9QLhTkg4IUaaOGnSDip0TYl
# d8GNGRbFiExmfS9jzpjoad+sPKhdnckcW67Y8y90z7h+9teDnRGWYpquRRPaf9xH
# +9/DUp/mBlXpnYzyOmJRvOwkDynUWICE5EV7WtgwggYaMIIEAqADAgECAhBiHW0M
# UgGeO5B5FSCJIRwKMA0GCSqGSIb3DQEBDAUAMFYxCzAJBgNVBAYTAkdCMRgwFgYD
# VQQKEw9TZWN0aWdvIExpbWl0ZWQxLTArBgNVBAMTJFNlY3RpZ28gUHVibGljIENv
# ZGUgU2lnbmluZyBSb290IFI0NjAeFw0yMTAzMjIwMDAwMDBaFw0zNjAzMjEyMzU5
# NTlaMFQxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxKzAp
# BgNVBAMTIlNlY3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBDQSBSMzYwggGiMA0G
# CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCbK51T+jU/jmAGQ2rAz/V/9shTUxjI
# ztNsfvxYB5UXeWUzCxEeAEZGbEN4QMgCsJLZUKhWThj/yPqy0iSZhXkZ6Pg2A2NV
# DgFigOMYzB2OKhdqfWGVoYW3haT29PSTahYkwmMv0b/83nbeECbiMXhSOtbam+/3
# 6F09fy1tsB8je/RV0mIk8XL/tfCK6cPuYHE215wzrK0h1SWHTxPbPuYkRdkP05Zw
# mRmTnAO5/arnY83jeNzhP06ShdnRqtZlV59+8yv+KIhE5ILMqgOZYAENHNX9SJDm
# +qxp4VqpB3MV/h53yl41aHU5pledi9lCBbH9JeIkNFICiVHNkRmq4TpxtwfvjsUe
# dyz8rNyfQJy/aOs5b4s+ac7IH60B+Ja7TVM+EKv1WuTGwcLmoU3FpOFMbmPj8pz4
# 4MPZ1f9+YEQIQty/NQd/2yGgW+ufflcZ/ZE9o1M7a5Jnqf2i2/uMSWymR8r2oQBM
# dlyh2n5HirY4jKnFH/9gRvd+QOfdRrJZb1sCAwEAAaOCAWQwggFgMB8GA1UdIwQY
# MBaAFDLrkpr/NZZILyhAQnAgNpFcF4XmMB0GA1UdDgQWBBQPKssghyi47G9IritU
# pimqF6TNDDAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADATBgNV
# HSUEDDAKBggrBgEFBQcDAzAbBgNVHSAEFDASMAYGBFUdIAAwCAYGZ4EMAQQBMEsG
# A1UdHwREMEIwQKA+oDyGOmh0dHA6Ly9jcmwuc2VjdGlnby5jb20vU2VjdGlnb1B1
# YmxpY0NvZGVTaWduaW5nUm9vdFI0Ni5jcmwwewYIKwYBBQUHAQEEbzBtMEYGCCsG
# AQUFBzAChjpodHRwOi8vY3J0LnNlY3RpZ28uY29tL1NlY3RpZ29QdWJsaWNDb2Rl
# U2lnbmluZ1Jvb3RSNDYucDdjMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5zZWN0
# aWdvLmNvbTANBgkqhkiG9w0BAQwFAAOCAgEABv+C4XdjNm57oRUgmxP/BP6YdURh
# w1aVcdGRP4Wh60BAscjW4HL9hcpkOTz5jUug2oeunbYAowbFC2AKK+cMcXIBD0Zd
# OaWTsyNyBBsMLHqafvIhrCymlaS98+QpoBCyKppP0OcxYEdU0hpsaqBBIZOtBajj
# cw5+w/KeFvPYfLF/ldYpmlG+vd0xqlqd099iChnyIMvY5HexjO2AmtsbpVn0OhNc
# WbWDRF/3sBp6fWXhz7DcML4iTAWS+MVXeNLj1lJziVKEoroGs9Mlizg0bUMbOalO
# hOfCipnx8CaLZeVme5yELg09Jlo8BMe80jO37PU8ejfkP9/uPak7VLwELKxAMcJs
# zkyeiaerlphwoKx1uHRzNyE6bxuSKcutisqmKL5OTunAvtONEoteSiabkPVSZ2z7
# 6mKnzAfZxCl/3dq3dUNw4rg3sTCggkHSRqTqlLMS7gjrhTqBmzu1L90Y1KWN/Y5J
# KdGvspbOrTfOXyXvmPL6E52z1NZJ6ctuMFBQZH3pwWvqURR8AgQdULUvrxjUYbHH
# j95Ejza63zdrEcxWLDX6xWls/GDnVNueKjWUH3fTv1Y8Wdho698YADR7TNx8X8z2
# Bev6SivBBOHY+uqiirZtg0y9ShQoPzmCcn63Syatatvx157YK9hlcPmVoa1oDE5/
# L9Uo2bC5a4CH2RwwggZhMIIEyaADAgECAhEAyDHh+zCQwUNyJV9S6gqqvTANBgkq
# hkiG9w0BAQwFADBUMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1p
# dGVkMSswKQYDVQQDEyJTZWN0aWdvIFB1YmxpYyBDb2RlIFNpZ25pbmcgQ0EgUjM2
# MB4XDTI1MDUyMDAwMDAwMFoXDTI4MDUxOTIzNTk1OVowdzELMAkGA1UEBhMCVVMx
# DjAMBgNVBAgMBVRleGFzMSswKQYDVQQKDCJIZXdsZXR0IFBhY2thcmQgRW50ZXJw
# cmlzZSBDb21wYW55MSswKQYDVQQDDCJIZXdsZXR0IFBhY2thcmQgRW50ZXJwcmlz
# ZSBDb21wYW55MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA37AD03qw
# cmuCQyxRB2VBM7SfUf0SmpQb8iaPvGmxw5uoDBY3gdC/3Xq/rfM3ndCn03hNdGyu
# cpC7tD4zmel6yYqxyXDVr45Jd2cz9jFXoYTOMcuDV6I6CvU/EnbFxWhv0VCp+2Ip
# z4+uJGI6aVlMpFpLbgPjhp9ogd/89HEyi1FkSFoarnvxxaXm93S81k7FD/4Edtvu
# muGI4V8p39GfbCiMuHku8BzSQ2g86gWFnOaVhY6h4XWvEmE8LPYkU/STrej28Flg
# kSt9f/Jg6+dvRKm92uN2Z760Eql9+DTWkGmGe4YrIyD25XDa07sS9tIpVWzLrGOy
# ecaVpJwVVBqCadXDgkgTYKw/UlS+cEqsviT6wREGl4aX/GbeNO6Y4oDTTYkabW3p
# eg1ku0v90oDqzoTaWEE5ly2UajvXIgzpFLLXqpR6GYkv/y3ZJV0chBqRtAObebH7
# XOBa5a2kqMBw0gkIZBJHd8+PCPH/U7eJkeKXtGGj2uTudcGjZgOjVcFYdCRnufJd
# isrV7bj0Hzghcv3QyRXL3rRjcNb4ccKNnSgF/8cmiTVpvFHTfUKsYdkbM6wsbjXR
# dJNADjGOYRms7tKsii3/oXO+2S1Um7yomBZQ2+wVRCY6MrRX1onDKid5t5AyWFtR
# u0aQcdBmHG6JeDiQ3Hrb2g9kZhuFkgABVBkCAwEAAaOCAYkwggGFMB8GA1UdIwQY
# MBaAFA8qyyCHKLjsb0iuK1SmKaoXpM0MMB0GA1UdDgQWBBQH4rUE0gsy8LW2G3vm
# oYtOnZ8zEjAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADATBgNVHSUEDDAK
# BggrBgEFBQcDAzBKBgNVHSAEQzBBMDUGDCsGAQQBsjEBAgEDAjAlMCMGCCsGAQUF
# BwIBFhdodHRwczovL3NlY3RpZ28uY29tL0NQUzAIBgZngQwBBAEwSQYDVR0fBEIw
# QDA+oDygOoY4aHR0cDovL2NybC5zZWN0aWdvLmNvbS9TZWN0aWdvUHVibGljQ29k
# ZVNpZ25pbmdDQVIzNi5jcmwweQYIKwYBBQUHAQEEbTBrMEQGCCsGAQUFBzAChjho
# dHRwOi8vY3J0LnNlY3RpZ28uY29tL1NlY3RpZ29QdWJsaWNDb2RlU2lnbmluZ0NB
# UjM2LmNydDAjBggrBgEFBQcwAYYXaHR0cDovL29jc3Auc2VjdGlnby5jb20wDQYJ
# KoZIhvcNAQEMBQADggGBAIax+Yaj5EciDlztft4iAfD2CtIWEF0cxR+UbbvJEs86
# 5wyoO3ZQoujr0FJ+P5fjDKLbamHrEWmyoD2YC4lzecmnFOnY0y4uJ9zBY8B6X6TU
# 9e6+TfZtlXd44YffXYAfoLX+uYjVJcZOaMuXF61+CFpjLJjepsD8m1gdj5QUz2sH
# 6GOfU6mEm8SHvKpgPMV/yhEKqgjlenY6Ao49RkxnDuvRlMP8SFPB+8bxiLegEdGa
# ei8nSr/j5YeDZFevUJ696T4W45QGrwAhBBpbKDz6CzlImC1b2C8Bp02XBAsOQs/u
# CIaQv5XxUmVxmb85tDJkd7QfqHo2z1T2NYMkvXUcSClYRuVxxC/frpqcrxS9O9xE
# v65BoUztAJSXsTdfpUjWeNOnhq8lrwa2XAD3fbagNF6ElsBiNDSbwHCG/iY4kAya
# VpbAYtaa6TfzdI/I0EaCX5xYRW56ccI2AnbaEVKz9gVjzi8hBLALlRhrs1uMFtPj
# nZ+oA+rbZZyGZkz3xbUYKTGCG/4wghv6AgEBMGkwVDELMAkGA1UEBhMCR0IxGDAW
# BgNVBAoTD1NlY3RpZ28gTGltaXRlZDErMCkGA1UEAxMiU2VjdGlnbyBQdWJsaWMg
# Q29kZSBTaWduaW5nIENBIFIzNgIRAMgx4fswkMFDciVfUuoKqr0wDQYJYIZIAWUD
# BAIBBQCgfDAQBgorBgEEAYI3AgEMMQIwADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGC
# NwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQx
# IgQgE6HgGhBKHBeUiQ3lJ3kOEkNnR3Oa4OstJws845HSv+YwDQYJKoZIhvcNAQEB
# BQAEggIAcuPQmhCMc8U+nsxYY8Yd63h5C3OMO3nS2Kg87m3h20w/p8ieDWPWGoYL
# zo5uyCvDnp3RSlwO5x3+nJzUN86L3Fxbh43QFXH1G6Ohfrm+169dhxa8JMEPgaeh
# I3+jJ6GGCeA5cj2Ewrg74K/N+cxpNZgDqibvf5fgchujC66P3zU7/VQ5QxBtNnnm
# OWlWbhm5bF1ArR/c6rXqcqraZcFKDdAMN3Ibbym/da/8BOxyzgyJF9aqhoSOdLNM
# o5/dB3WhJcRCgM+yw46nh49D5zK/y0bXnrlZh4z0gTkOXPTX5amzVsPeGl5m7IJr
# t1FKp9kcMUB4wWNCKwTNj5gkTdtT7trXO4T6jWhcfqgsJ8yG/H90n3mTb1es1i7j
# pkFQFVHbIk49FWClXvebJfKivkkTHD/zI6pVjOu69CXjuI6yK9Q8HynKnF4w56s8
# CXyhLXJO04wulLFbplbf7sQpRP40FMx5R1wSFOXNK3RJdkW3wR+T32KmOeWOqTtm
# TS1WrL+4CjCNYR2gT9LSf5szB1W56hs275fC6qOylgD07jqyBNw+aBP2b4A+fPPI
# gK7pAH+Jv7WRmSx+J4iuQb3w8x7bjQjx/kI/qpdMZbeEDCV8JVWN4fouDpUUlDCt
# Vb2rPDXw764sqyhyOv8/um5F4DfYn52JR/dGRuUsJuo6itLFAQGhghjoMIIY5AYK
# KwYBBAGCNwMDATGCGNQwghjQBgkqhkiG9w0BBwKgghjBMIIYvQIBAzEPMA0GCWCG
# SAFlAwQCAgUAMIIBBwYLKoZIhvcNAQkQAQSggfcEgfQwgfECAQEGCisGAQQBsjEC
# AQEwQTANBglghkgBZQMEAgIFAAQwMhewWztSyCbwWccRnEHAzTu7+qMDZBosqfzw
# SO4wk5Vx8yIk5UznnLOVvwLNtZS1AhQT4e5HGUwZtSmncKrR+9E+7Ue2hhgPMjAy
# NjAzMTYwODExMjhaoHakdDByMQswCQYDVQQGEwJHQjEXMBUGA1UECBMOV2VzdCBZ
# b3Jrc2hpcmUxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDEwMC4GA1UEAxMnU2Vj
# dGlnbyBQdWJsaWMgVGltZSBTdGFtcGluZyBTaWduZXIgUjM2oIITBDCCBmIwggTK
# oAMCAQICEQCkKTtuHt3XpzQIh616TrckMA0GCSqGSIb3DQEBDAUAMFUxCzAJBgNV
# BAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxLDAqBgNVBAMTI1NlY3Rp
# Z28gUHVibGljIFRpbWUgU3RhbXBpbmcgQ0EgUjM2MB4XDTI1MDMyNzAwMDAwMFoX
# DTM2MDMyMTIzNTk1OVowcjELMAkGA1UEBhMCR0IxFzAVBgNVBAgTDldlc3QgWW9y
# a3NoaXJlMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxMDAuBgNVBAMTJ1NlY3Rp
# Z28gUHVibGljIFRpbWUgU3RhbXBpbmcgU2lnbmVyIFIzNjCCAiIwDQYJKoZIhvcN
# AQEBBQADggIPADCCAgoCggIBANOElfRupFN48j0QS3gSBzzclIFTZ2Gsn7BjsmBF
# 659/kpA2Ey7NXK3MP6JdrMBNU8wdmkf+SSIyjX++UAYWtg3Y/uDRDyg8RxHeHRJ+
# 0U1jHEyH5uPdk1ttiPC3x/gOxIc9P7Gn3OgW7DQc4x07exZ4DX4XyaGDq5LoEmk/
# BdCM1IelVMKB3WA6YpZ/XYdJ9JueOXeQObSQ/dohQCGyh0FhmwkDWKZaqQBWrBwZ
# ++zqlt+z/QYTgEnZo6dyIo2IhXXANFkCHutL8765NBxvolXMFWY8/reTnFxk3Maj
# gM5NX6wzWdWsPJxYRhLxtJLSUJJ5yWRNw+NBqH1ezvFs4GgJ2ZqFJ+Dwqbx9+rw+
# F2gBdgo4j7CVomP49sS7CbqsdybbiOGpB9DJhs5QVMpYV73TVV3IwLiBHBECrTgU
# fZVOMF0KSEq2zk/LsfvehswavE3W4aBXJmGjgWSpcDz+6TqeTM8f1DIcgQPdz0IY
# gnT3yFTgiDbFGOFNt6eCidxdR6j9x+kpcN5RwApy4pRhE10YOV/xafBvKpRuWPjO
# PWRBlKdm53kS2aMh08spx7xSEqXn4QQldCnUWRz3Lki+TgBlpwYwJUbR77DAayNw
# AANE7taBrz2v+MnnogMrvvct0iwvfIA1W8kp155Lo44SIfqGmrbJP6Mn+Udr3MR2
# oWozAgMBAAGjggGOMIIBijAfBgNVHSMEGDAWgBRfWO1MMXqiYUKNUoC6s2GXGaIy
# mzAdBgNVHQ4EFgQUiGGMoSo3ZIEoYKGbMdCM/SwCzk8wDgYDVR0PAQH/BAQDAgbA
# MAwGA1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwSgYDVR0gBEMw
# QTA1BgwrBgEEAbIxAQIBAwgwJTAjBggrBgEFBQcCARYXaHR0cHM6Ly9zZWN0aWdv
# LmNvbS9DUFMwCAYGZ4EMAQQCMEoGA1UdHwRDMEEwP6A9oDuGOWh0dHA6Ly9jcmwu
# c2VjdGlnby5jb20vU2VjdGlnb1B1YmxpY1RpbWVTdGFtcGluZ0NBUjM2LmNybDB6
# BggrBgEFBQcBAQRuMGwwRQYIKwYBBQUHMAKGOWh0dHA6Ly9jcnQuc2VjdGlnby5j
# b20vU2VjdGlnb1B1YmxpY1RpbWVTdGFtcGluZ0NBUjM2LmNydDAjBggrBgEFBQcw
# AYYXaHR0cDovL29jc3Auc2VjdGlnby5jb20wDQYJKoZIhvcNAQEMBQADggGBAAKB
# PqSGclEh+WWpLj1SiuHlm8xLE0SThI2yLuq+75s11y6SceBchpnKpxWaGtXc8dya
# 1Aq3RuW//y3wMThsvT4fSba2AoSWlR67rA4fTYGMIhgzocsids0ct/pHaocLVJSw
# nTYxY2pE0hPoZAvRebctbsTqENmZHyOVjOFlwN2R3DRweFeNs4uyZN5LRJ5EnVYl
# cTOq3bl1tI5poru9WaQRWQ4eynXp7Pj0Fz4DKr86HYECRJMWiDjeV0QqAcQMFsIj
# JtrYTw7mU81qf4FBc4u4swphLeKRNyn9DDrd3HIMJ+CpdhSHEGleeZ5I79YDg3B3
# A/fmVY2GaMik1Vm+FajEMv4/EN2mmHf4zkOuhYZNzVm4NrWJeY4UAriLBOeVYODd
# A1GxFr1ycbcUEGlUecc4RCPgYySs4d00NNuicR4a9n7idJlevAJbha/arIYMEuUq
# TeRRbWkhJwMKmb9yEvppRudKyu1t6l21sIuIZqcpVH8oLWCxHS0LpDRF9Y4jijCC
# BhQwggP8oAMCAQICEHojrtpTaZYPkcg+XPTH4z8wDQYJKoZIhvcNAQEMBQAwVzEL
# MAkGA1UEBhMCR0IxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDEuMCwGA1UEAxMl
# U2VjdGlnbyBQdWJsaWMgVGltZSBTdGFtcGluZyBSb290IFI0NjAeFw0yMTAzMjIw
# MDAwMDBaFw0zNjAzMjEyMzU5NTlaMFUxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9T
# ZWN0aWdvIExpbWl0ZWQxLDAqBgNVBAMTI1NlY3RpZ28gUHVibGljIFRpbWUgU3Rh
# bXBpbmcgQ0EgUjM2MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAzZjY
# Q0GrboIr7PYzfiY05ImM0+8iEoBUPu8mr4wOgYPjoiIz5vzf7d5wu8GFK1JWN5hc
# iN9rdqOhbdxLcSVwnOTJmUGfAMQm4eXOls3iQwfapEFWuOsYmBKXPNSpwZAFoLGl
# 5y1EaGGc5LByM8wjcbSF52/Z42YaJRsPXY545E3QAPN2mxDh0OLozhiGgYT1xtjX
# VfEzYBVmfQaI5QL35cTTAjsJAp85R+KAsOfuL9Z7LFnjdcuPkZWjssMETFIueH69
# rxbFOUD64G+rUo7xFIdRAuDNvWBsv0iGDPGaR2nZlY24tz5fISYk1sPY4gir99aX
# AGnoo0vX3Okew4MsiyBn5ZnUDMKzUcQrpVavGacrIkmDYu/bcOUR1mVBIZ0X7P4b
# Kf38JF7Mp7tY3LFF/h7hvBS2tgTYXlD7TnIMPrxyXCfB5yQq3FFoXRXM3/DvqQ4s
# hoVWF/mwwz9xoRku05iphp22fTfjKRIVpm4gFT24JKspEpM8mFa9eTgKWWCvAgMB
# AAGjggFcMIIBWDAfBgNVHSMEGDAWgBT2d2rdP/0BE/8WoWyCAi/QCj0UJTAdBgNV
# HQ4EFgQUX1jtTDF6omFCjVKAurNhlxmiMpswDgYDVR0PAQH/BAQDAgGGMBIGA1Ud
# EwEB/wQIMAYBAf8CAQAwEwYDVR0lBAwwCgYIKwYBBQUHAwgwEQYDVR0gBAowCDAG
# BgRVHSAAMEwGA1UdHwRFMEMwQaA/oD2GO2h0dHA6Ly9jcmwuc2VjdGlnby5jb20v
# U2VjdGlnb1B1YmxpY1RpbWVTdGFtcGluZ1Jvb3RSNDYuY3JsMHwGCCsGAQUFBwEB
# BHAwbjBHBggrBgEFBQcwAoY7aHR0cDovL2NydC5zZWN0aWdvLmNvbS9TZWN0aWdv
# UHVibGljVGltZVN0YW1waW5nUm9vdFI0Ni5wN2MwIwYIKwYBBQUHMAGGF2h0dHA6
# Ly9vY3NwLnNlY3RpZ28uY29tMA0GCSqGSIb3DQEBDAUAA4ICAQAS13sgrQ41WAye
# gR0lWP1MLWd0r8diJiH2VVRpxqFGhnZbaF+IQ7JATGceTWOS+kgnMAzGYRzpm8jI
# cjlSQ8JtcqymKhgx1s6cFZBSfvfeoyigF8iCGlH+SVSo3HHr98NepjSFJTU5KSRK
# K+3nVSWYkSVQgJlgGh3MPcz9IWN4I/n1qfDGzqHCPWZ+/Mb5vVyhgaeqxLPbBIqv
# 6cM74Nvyo1xNsllECJJrOvsrJQkajVz4xJwZ8blAdX5umzwFfk7K/0K3fpjgiXpq
# NOpXaJ+KSRW0HdE0FSDC7+ZKJJSJx78mn+rwEyT+A3z7Ss0gT5CpTrcmhUwIw9jb
# vnYuYRKxFVWjKklW3z83epDVzoWJttxFpujdrNmRwh1YZVIB2guAAjEQoF42H0BA
# 7WBCueHVMDyV1e4nM9K4As7PVSNvQ8LI1WRaTuGSFUd9y8F8jw22BZC6mJoB40d7
# SlZIYfaildlgpgbgtu6SDsek2L8qomG57Yp5qTqof0DwJ4Q4HsShvRl/59T4IJBo
# vRwmqWafH0cIPEX7cEttS5+tXrgRtMjjTOp6A9l0D6xcKZtxnLqiTH9KPCy6xZEi
# 0UDcMTww5Fl4VvoGbMG2oonuX3f1tsoHLaO/Fwkj3xVr3lDkmeUqivebQTvGkx5h
# GuJaSVQ+x60xJ/Y29RBr8Tm9XJ59AjCCBoIwggRqoAMCAQICEDbCsL18Gzrno7Pd
# NsvJdWgwDQYJKoZIhvcNAQEMBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpO
# ZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVT
# RVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmlj
# YXRpb24gQXV0aG9yaXR5MB4XDTIxMDMyMjAwMDAwMFoXDTM4MDExODIzNTk1OVow
# VzELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDEuMCwGA1UE
# AxMlU2VjdGlnbyBQdWJsaWMgVGltZSBTdGFtcGluZyBSb290IFI0NjCCAiIwDQYJ
# KoZIhvcNAQEBBQADggIPADCCAgoCggIBAIid2LlFZ50d3ei5JoGaVFTAfEkFm8xa
# FQ/ZlBBEtEFAgXcUmanU5HYsyAhTXiDQkiUvpVdYqZ1uYoZEMgtHES1l1Cc6HaqZ
# zEbOOp6YiTx63ywTon434aXVydmhx7Dx4IBrAou7hNGsKioIBPy5GMN7KmgYmuu4
# f92sKKjbxqohUSfjk1mJlAjthgF7Hjx4vvyVDQGsd5KarLW5d73E3ThobSkob2SL
# 48LpUR/O627pDchxll+bTSv1gASn/hp6IuHJorEu6EopoB1CNFp/+HpTXeNARXUm
# dRMKbnXWflq+/g36NJXB35ZvxQw6zid61qmrlD/IbKJA6COw/8lFSPQwBP1ityZd
# wuCysCKZ9ZjczMqbUcLFyq6KdOpuzVDR3ZUwxDKL1wCAxgL2Mpz7eZbrb/JWXiOc
# NzDpQsmwGQ6Stw8tTCqPumhLRPb7YkzM8/6NnWH3T9ClmcGSF22LEyJYNWCHrQqY
# ubNeKolzqUbCqhSqmr/UdUeb49zYHr7ALL8bAJyPDmubNqMtuaobKASBqP84uhqc
# RY/pjnYd+V5/dcu9ieERjiRKKsxCG1t6tG9oj7liwPddXEcYGOUiWLm742st50jG
# wTzxbMpepmOP1mLnJskvZaN5e45NuzAHteORlsSuDt5t4BBRCJL+5EZnnw0ezntk
# 9R8QJyAkL6/bAgMBAAGjggEWMIIBEjAfBgNVHSMEGDAWgBRTeb9aqitKz1SA4dib
# wJ3ysgNmyzAdBgNVHQ4EFgQU9ndq3T/9ARP/FqFsggIv0Ao9FCUwDgYDVR0PAQH/
# BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wEwYDVR0lBAwwCgYIKwYBBQUHAwgwEQYD
# VR0gBAowCDAGBgRVHSAAMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNl
# cnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNy
# bDA1BggrBgEFBQcBAQQpMCcwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0
# cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggIBAA6+ZUHtaES45aHF1BGH5Lc7JYzr
# ftrIF5Ht2PFDxKKFOct/awAEWgHQMVHol9ZLSyd/pYMbaC0IZ+XBW9xhdkkmUV/K
# bUOiL7g98M/yzRyqUOZ1/IY7Ay0YbMniIibJrPcgFp73WDnRDKtVutShPSZQZAdt
# FwXnuiWl8eFARK3PmLqEm9UsVX+55DbVIz33Mbhba0HUTEYv3yJ1fwKGxPBsP/Mg
# TECimh7eXomvMm0/GPxX2uhwCcs/YLxDnBdVVlxvDjHjO1cuwbOpkiJGHmLXXVNb
# sdXUC2xBrq9fLrfe8IBsA4hopwsCj8hTuwKXJlSTrZcPRVSccP5i9U28gZ7OMzoJ
# GlxZ5384OKm0r568Mo9TYrqzKeKZgFo0fj2/0iHbj55hc20jfxvK3mQi+H7xpbzx
# ZOFGm/yVQkpo+ffv5gdhp+hv1GDsvJOtJinJmgGbBFZIThbqI+MHvAmMmkfb3fTx
# mSkop2mSJL1Y2x/955S29Gu0gSJIkc3z30vU/iXrMpWx2tS7UVfVP+5tKuzGtgkP
# 7d/doqDrLF1u6Ci3TpjAZdeLLlRQZm867eVeXED58LXd1Dk6UvaAhvmWYXoiLz4J
# A5gPBcz7J311uahxCweNxE+xxxR3kT0WKzASo5G/PyDez6NHdIUKBeE3jDPs2ACc
# 6CkJ1Sji4PKWVT0/MYIEkjCCBI4CAQEwajBVMQswCQYDVQQGEwJHQjEYMBYGA1UE
# ChMPU2VjdGlnbyBMaW1pdGVkMSwwKgYDVQQDEyNTZWN0aWdvIFB1YmxpYyBUaW1l
# IFN0YW1waW5nIENBIFIzNgIRAKQpO24e3denNAiHrXpOtyQwDQYJYIZIAWUDBAIC
# BQCgggH5MBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUx
# DxcNMjYwMzE2MDgxMTI4WjA/BgkqhkiG9w0BCQQxMgQwVIwfRZkx4Ea4Tc+Qaq1s
# SBo57YSMZjK/HhZBi6w0mr0yaD7G4VxBgv2Pv8JxG3qsMIIBegYLKoZIhvcNAQkQ
# AgwxggFpMIIBZTCCAWEwFgQUOMkUgRBEtNxmPpPUdEuBQYaptbEwgYcEFMauVOR4
# hvF8PVUSSIxpw0p6+cLdMG8wW6RZMFcxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9T
# ZWN0aWdvIExpbWl0ZWQxLjAsBgNVBAMTJVNlY3RpZ28gUHVibGljIFRpbWUgU3Rh
# bXBpbmcgUm9vdCBSNDYCEHojrtpTaZYPkcg+XPTH4z8wgbwEFIU9Yy2TgoJhfNCQ
# NcSR3pLBQtrHMIGjMIGOpIGLMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKTmV3
# IEplcnNleTEUMBIGA1UEBxMLSmVyc2V5IENpdHkxHjAcBgNVBAoTFVRoZSBVU0VS
# VFJVU1QgTmV0d29yazEuMCwGA1UEAxMlVVNFUlRydXN0IFJTQSBDZXJ0aWZpY2F0
# aW9uIEF1dGhvcml0eQIQNsKwvXwbOuejs902y8l1aDANBgkqhkiG9w0BAQEFAASC
# AgCgF6Qa7p6Cpr41ZUOgPGciV/HioGdqMApwNN4EmKY+t1zA5dtQQ7+GxkBwuFW0
# RBzNfEunhI5A6QNOBLmWuC8Azl2wdvDdr6THaQS6zCLp8V2lCWzaa1qS8oJt73WF
# ++BuNsVZMGK3kFQHpl5EhDoGFVFuYHHmyHSIINfwHLKQymhqUACNGW5+uXYjfVLz
# a3PXPM1J10GTpXYqelCXhYv7XVy+hsdwQJC71OySVmHetucoMIajaXxiF0hY15jp
# Euxp0QSWZzwXnJtUqUibH5WrgzaMvJqSERIphcpthXVHNzSEtzFpO7aUgnwhubFt
# 6wNtGfgd6t4cGVRV/I+qHHNogAC5WMElUkitxGeaDX4mGX2W3UKI7D/z4xZkrC/v
# wNNX1fEcPUNt1LX41iujtfBA19BVAHh2JTy7xQ2E/SUUns6Efzbcn+l3D4TfJcdi
# /6D4tKBn3qHFdZLKIj3V91mkQIx9Zyy2uusa/cNEWcZF1FBi+ZrNLKD5mRv54jI6
# b7QIYMhjZHKi8SnoB21vMRagy5VTS6Vx0ST2/xaL4Wa7bcKF5V7mXKUmM6NwNLBc
# CG8xHVRdFn6Pb8Cgbjnj7/CIjvpeNk1qiCmExEEJZkUldl4Th+wvsFM+6l10VGv3
# G2z2facRUHoceqQcd+KB26g+ORtcXIg4xG1211WnR1rAcw==
# SIG # End signature block