Private/Get-Utils.ps1

#
# (c) Copyright 2018-2021 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'

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.
function Skip-CertificateCheck {
Add-Type @"
    using System;
    using System.Net;
    using System.Net.Security;
    using System.Security.Cryptography.X509Certificates;
    public class ServerCertificateValidationCallback {
        public static void Ignore() {
            ServicePointManager.ServerCertificateValidationCallback +=
                delegate
                (
                    Object obj,
                    X509Certificate certificate,
                    X509Chain chain,
                    SslPolicyErrors errors
                )
                {
                    return true;
                };
        }
    }
"@

    [ServerCertificateValidationCallback]::Ignore();
    [System.Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
}

# 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($DeepCopyObject)
    $memStream = new-object IO.MemoryStream
    $formatter = new-object Runtime.Serialization.Formatters.Binary.BinaryFormatter
    $formatter.Serialize($memStream,$DeepCopyObject)
    $memStream.Position=0
    $formatter.Deserialize($memStream)
}

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 {
            if ($PSBoundParameters.ContainsKey('Body')) {
                $Response = Invoke-RestMethod -Uri $Uri -Headers $Header -Body $Body -Method $Method -ErrorAction Stop
            }
            else {
                $Response = Invoke-RestMethod -Uri $Uri -Headers $Header -Method $Method -ErrorAction Stop
            }
            $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"
    try
    {
        $response = Invoke-RestMethod -Uri $url -Method Get -ErrorAction Stop
    }
    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
# MIIlSAYJKoZIhvcNAQcCoIIlOTCCJTUCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDKKm64NMb58ETX
# OD+D3a1lJgwOhOPYwvBRwftqrFrFxKCCEKwwggUqMIIEEqADAgECAhEAh0L0QnA4
# GzyXlRYB5/Z3IjANBgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJHQjEbMBkGA1UE
# CBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRgwFgYDVQQK
# Ew9TZWN0aWdvIExpbWl0ZWQxJDAiBgNVBAMTG1NlY3RpZ28gUlNBIENvZGUgU2ln
# bmluZyBDQTAeFw0yMTA1MjgwMDAwMDBaFw0yMjA1MjgyMzU5NTlaMIGQMQswCQYD
# VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJUGFsbyBBbHRv
# MSswKQYDVQQKDCJIZXdsZXR0IFBhY2thcmQgRW50ZXJwcmlzZSBDb21wYW55MSsw
# KQYDVQQDDCJIZXdsZXR0IFBhY2thcmQgRW50ZXJwcmlzZSBDb21wYW55MIIBIjAN
# BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuy98a4/YGCzF1KvXZeoHxDtk6qL4
# PSuU32Ob9Fzpxq36JZIs6oezkvBnNVlf4iuaWSk3UyqK/JpKpbdz1dB/cuB2s+PV
# aVR9goUC494Qi7HVDeFmomdvH2Xt0r+R6VUDtpxnR/XmZrZjXKP5T2Yk+XDMl78R
# XT9ayu3ZZncwTdYauSBk1sJq1Vid3gHnNrrA5DmidVwxmu5Y9XvIjcrEtECPm4hx
# sV2ISbMnnuzM0bvisxwAAho74TfswOyBSy182sFGZPbmwkyJvW1RhPV+2POqSaOR
# CXvSad2KJUWtxgqfOGOU+hAP+sHvg5MbXDj6I+RSx9dJAu5WKcffyp506QIDAQAB
# o4IBkDCCAYwwHwYDVR0jBBgwFoAUDuE6qFM6MdWKvsG7rWcaA4WtNA4wHQYDVR0O
# BBYEFE32P36Oqh0//kySCDZQvL8TnjDgMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMB
# Af8EAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMBEGCWCGSAGG+EIBAQQEAwIEEDBK
# BgNVHSAEQzBBMDUGDCsGAQQBsjEBAgEDAjAlMCMGCCsGAQUFBwIBFhdodHRwczov
# L3NlY3RpZ28uY29tL0NQUzAIBgZngQwBBAEwQwYDVR0fBDwwOjA4oDagNIYyaHR0
# cDovL2NybC5zZWN0aWdvLmNvbS9TZWN0aWdvUlNBQ29kZVNpZ25pbmdDQS5jcmww
# cwYIKwYBBQUHAQEEZzBlMD4GCCsGAQUFBzAChjJodHRwOi8vY3J0LnNlY3RpZ28u
# Y29tL1NlY3RpZ29SU0FDb2RlU2lnbmluZ0NBLmNydDAjBggrBgEFBQcwAYYXaHR0
# cDovL29jc3Auc2VjdGlnby5jb20wDQYJKoZIhvcNAQELBQADggEBABmxgISN4Ehp
# rP/zvy+4wqQItJDH30z1qv02yZXsA988VQ8uq3Iof7x1tvTsNo06hcNhqXWx547s
# p3DU/FmteG8LTT4iATHZNc6OHdZ+A4IYOAmUNhIPCMT/DLgunRjnLJPHPVYkRiKu
# a0Ggzwa2a4CsV2z9DB1erpbX9jsOLS21ENqRIYcgipSVNo1cJYVdtWi7INWwuqcy
# juJcy0ZOfKlPMr7Mn4i3L1HPzcoWAkZPBqefO/KrDAhM5qW07+YYZAH7pcBdQcLu
# m4+LlAT51Ha9gi1mcr2WcJEOnUtazO/TVcr7T/0RlUMuLRfSkCdQymUDx0TGwSME
# elGewxW1JUYwggWBMIIEaaADAgECAhA5ckQ6+SK3UdfTbBDdMTWVMA0GCSqGSIb3
# DQEBDAUAMHsxCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0
# ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVk
# MSEwHwYDVQQDDBhBQUEgQ2VydGlmaWNhdGUgU2VydmljZXMwHhcNMTkwMzEyMDAw
# MDAwWhcNMjgxMjMxMjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5l
# dyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNF
# UlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNh
# dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCA
# EmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B3PHTsdZ7
# NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkYtJHUYmTb
# f6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/Fp0YvVGO
# NaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2VN3I5xI6
# Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT79uq/nRO
# acdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6c0Plfg6l
# ZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmTYo61Zs8l
# iM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97lc6wjOy0A
# vzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4eeUB9XVKg+
# /XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeEHg9j1uli
# utZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo4HyMIHvMB8GA1Ud
# IwQYMBaAFKARCiM+lvEH7OKvKe+CpX/QMKS0MB0GA1UdDgQWBBRTeb9aqitKz1SA
# 4dibwJ3ysgNmyzAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zARBgNV
# HSAECjAIMAYGBFUdIAAwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5jb21v
# ZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYIKwYBBQUHAQEE
# KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZI
# hvcNAQEMBQADggEBABiHUdx0IT2ciuAntzPQLszs8ObLXhHeIm+bdY6ecv7k1v6q
# H5yWLe8DSn6u9I1vcjxDO8A/67jfXKqpxq7y/Njuo3tD9oY2fBTgzfT3P/7euLSK
# 8JGW/v1DZH79zNIBoX19+BkZyUIrE79Yi7qkomYEdoiRTgyJFM6iTckys7roFBq8
# cfFb8EELmAAKIgMQ5Qyx+c2SNxntO/HkOrb5RRMmda+7qu8/e3c70sQCkT0ZANMX
# XDnbP3sYDUXNk4WWL13fWRZPP1G91UUYP+1KjugGYXQjFrUNUHMnREd/EF2JKmuF
# MRTE6KlqTIC8anjPuH+OdnKZDJ3+15EIFqGjX5UwggX1MIID3aADAgECAhAdokgw
# b5smGNCC4JZ9M9NqMA0GCSqGSIb3DQEBDAUAMIGIMQswCQYDVQQGEwJVUzETMBEG
# A1UECBMKTmV3IEplcnNleTEUMBIGA1UEBxMLSmVyc2V5IENpdHkxHjAcBgNVBAoT
# FVRoZSBVU0VSVFJVU1QgTmV0d29yazEuMCwGA1UEAxMlVVNFUlRydXN0IFJTQSBD
# ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xODExMDIwMDAwMDBaFw0zMDEyMzEy
# MzU5NTlaMHwxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0
# ZXIxEDAOBgNVBAcTB1NhbGZvcmQxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDEk
# MCIGA1UEAxMbU2VjdGlnbyBSU0EgQ29kZSBTaWduaW5nIENBMIIBIjANBgkqhkiG
# 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhiKNMoV6GJ9J8JYvYwgeLdx8nxTP4ya2JWYp
# QIZURnQxYsUQ7bKHJ6aZy5UwwFb1pHXGqQ5QYqVRkRBq4Etirv3w+Bisp//uLjMg
# +gwZiahse60Aw2Gh3GllbR9uJ5bXl1GGpvQn5Xxqi5UeW2DVftcWkpwAL2j3l+1q
# cr44O2Pej79uTEFdEiAIWeg5zY/S1s8GtFcFtk6hPldrH5i8xGLWGwuNx2YbSp+d
# gcRyQLXiX+8LRf+jzhemLVWwt7C8VGqdvI1WU8bwunlQSSz3A7n+L2U18iLqLAev
# Rtn5RhzcjHxxKPP+p8YU3VWRbooRDd8GJJV9D6ehfDrahjVh0wIDAQABo4IBZDCC
# AWAwHwYDVR0jBBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFA7h
# OqhTOjHVir7Bu61nGgOFrTQOMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAG
# AQH/AgEAMB0GA1UdJQQWMBQGCCsGAQUFBwMDBggrBgEFBQcDCDARBgNVHSAECjAI
# MAYGBFUdIAAwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3Qu
# Y29tL1VTRVJUcnVzdFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsG
# AQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29t
# L1VTRVJUcnVzdFJTQUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8v
# b2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQBNY1DtRzRKYaTb
# 3moqjJvxAAAeHWJ7Otcywvaz4GOz+2EAiJobbRAHBE++uOqJeCLrD0bs80ZeQEaJ
# EvQLd1qcKkE6/Nb06+f3FZUzw6GDKLfeL+SU94Uzgy1KQEi/msJPSrGPJPSzgTfT
# t2SwpiNqWWhSQl//BOvhdGV5CPWpk95rcUCZlrp48bnI4sMIFrGrY1rIFYBtdF5K
# dX6luMNstc/fSnmHXMdATWM19jDTz7UKDgsEf6BLrrujpdCEAJM+U100pQA1aWy+
# nyAlEA0Z+1CQYb45j3qOTfafDh7+B1ESZoMmGUiVzkrJwX/zOgWb+W/fiH/AI57S
# HkN6RTHBnE2p8FmyWRnoao0pBAJ3fEtLzXC+OrJVWng+vLtvAxAldxU0ivk2zEOS
# 5LpP8WKTKCVXKftRGcehJUBqhFfGsp2xvBwK2nxnfn0u6ShMGH7EezFBcZpLKewL
# PVdQ0srd/Z4FUeVEeN0B3rF1mA1UJP3wTuPi+IO9crrLPTru8F4XkmhtyGH5pvEq
# CgulufSe7pgyBYWe6/mDKdPGLH29OncuizdCoGqC7TtKqpQQpOEN+BfFtlp5MxiS
# 47V1+KHpjgolHuQe8Z9ahyP/n6RRnvs5gBHN27XEp6iAb+VT1ODjosLSWxr6MiYt
# aldwHDykWC6j81tLB9wyWfOHpxptWDGCE/IwghPuAgEBMIGRMHwxCzAJBgNVBAYT
# AkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZv
# cmQxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDEkMCIGA1UEAxMbU2VjdGlnbyBS
# U0EgQ29kZSBTaWduaW5nIENBAhEAh0L0QnA4GzyXlRYB5/Z3IjANBglghkgBZQME
# AgEFAKB8MBAGCisGAQQBgjcCAQwxAjAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3
# AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEi
# BCBNnxB7ZXCUCoepOdqkiSBOWC4IDDayt7sTpifaJOHpEDANBgkqhkiG9w0BAQEF
# AASCAQAZpSr/Xvdu9SwxnI4iQZ5yVGIQSu6oMpkh06Bfe8DpvLcoI4OJZUaHIHiY
# Io5aSrHpj1L7Np/FKvP9/9cM3fNAmOuQ58xO4Xse4JW2I78/NptqymCca+YlXG6h
# Ug6lbvOW/yMIt7zDcnmLE3vQGySaegGZTOl26Wu5YbCqhYUojusnP5EHp3H+oMg4
# 9qsiL+z5jHsaaYnGjSxQOFkDuhdFAvZ8el36nAcUM8VYhISGT9InZzlZ0uttU1tA
# eoJExIfSwJFZpqxTcTJWXkUpIfNwL5Pg5e80CtEU2oEj4MKdxs72lQ64jWYHqhWV
# RXtyonv4CIkwFeDJmWNP/Fv5JbWSoYIRszCCEa8GCisGAQQBgjcDAwExghGfMIIR
# mwYJKoZIhvcNAQcCoIIRjDCCEYgCAQMxDzANBglghkgBZQMEAgEFADB4BgsqhkiG
# 9w0BCRABBKBpBGcwZQIBAQYJYIZIAYb9bAcBMDEwDQYJYIZIAWUDBAIBBQAEIAri
# iVSESrRBbwRfJri73TF5BhUSXisE4BRGNueNbjd/AhEA7wm9ggCoNaps4Qrook7e
# pRgPMjAyMjA0MDcwNjE0NTlaoIINfDCCBsYwggSuoAMCAQICEAp6SoieyZlCkAZj
# OE2Gl50wDQYJKoZIhvcNAQELBQAwYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRp
# Z2lDZXJ0LCBJbmMuMTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQw
# OTYgU0hBMjU2IFRpbWVTdGFtcGluZyBDQTAeFw0yMjAzMjkwMDAwMDBaFw0zMzAz
# MTQyMzU5NTlaMEwxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5j
# LjEkMCIGA1UEAxMbRGlnaUNlcnQgVGltZXN0YW1wIDIwMjIgLSAyMIICIjANBgkq
# hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuSqWI6ZcvF/WSfAVghj0M+7MXGzj4CUu
# 0jHkPECu+6vE43hdflw26vUljUOjges4Y/k8iGnePNIwUQ0xB7pGbumjS0joiUF/
# DbLW+YTxmD4LvwqEEnFsoWImAdPOw2z9rDt+3Cocqb0wxhbY2rzrsvGD0Z/NCcW5
# QWpFQiNBWvhg02UsPn5evZan8Pyx9PQoz0J5HzvHkwdoaOVENFJfD1De1FksRHTA
# MkcZW+KYLo/Qyj//xmfPPJOVToTpdhiYmREUxSsMoDPbTSSF6IKU4S8D7n+FAsmG
# 4dUYFLcERfPgOL2ivXpxmOwV5/0u7NKbAIqsHY07gGj+0FmYJs7g7a5/KC7CnuAL
# S8gI0TK7g/ojPNn/0oy790Mj3+fDWgVifnAs5SuyPWPqyK6BIGtDich+X7Aa3Rm9
# n3RBCq+5jgnTdKEvsFR2wZBPlOyGYf/bES+SAzDOMLeLD11Es0MdI1DNkdcvnfv8
# zbHBp8QOxO9APhk6AtQxqWmgSfl14ZvoaORqDI/r5LEhe4ZnWH5/H+gr5BSyFtaB
# ocraMJBr7m91wLA2JrIIO/+9vn9sExjfxm2keUmti39hhwVo99Rw40KV6J67m0uy
# 4rZBPeevpxooya1hsKBBGBlO7UebYZXtPgthWuo+epiSUc0/yUTngIspQnL3ebLd
# hOon7v59emsCAwEAAaOCAYswggGHMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8E
# AjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMCAGA1UdIAQZMBcwCAYGZ4EMAQQC
# MAsGCWCGSAGG/WwHATAfBgNVHSMEGDAWgBS6FtltTYUvcyl2mi91jGogj57IbzAd
# BgNVHQ4EFgQUjWS3iSH+VlhEhGGn6m8cNo/drw0wWgYDVR0fBFMwUTBPoE2gS4ZJ
# aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0UlNBNDA5
# NlNIQTI1NlRpbWVTdGFtcGluZ0NBLmNybDCBkAYIKwYBBQUHAQEEgYMwgYAwJAYI
# KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBYBggrBgEFBQcwAoZM
# aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0UlNB
# NDA5NlNIQTI1NlRpbWVTdGFtcGluZ0NBLmNydDANBgkqhkiG9w0BAQsFAAOCAgEA
# DS0jdKbR9fjqS5k/AeT2DOSvFp3Zs4yXgimcQ28BLas4tXARv4QZiz9d5YZPvpM6
# 3io5WjlO2IRZpbwbmKrobO/RSGkZOFvPiTkdcHDZTt8jImzV3/ZZy6HC6kx2yqHc
# oSuWuJtVqRprfdH1AglPgtalc4jEmIDf7kmVt7PMxafuDuHvHjiKn+8RyTFKWLbf
# OHzL+lz35FO/bgp8ftfemNUpZYkPopzAZfQBImXH6l50pls1klB89Bemh2RPPkaJ
# FmMga8vye9A140pwSKm25x1gvQQiFSVwBnKpRDtpRxHT7unHoD5PELkwNuTzqmkJ
# qIt+ZKJllBH7bjLx9bs4rc3AkxHVMnhKSzcqTPNc3LaFwLtwMFV41pj+VG1/calI
# GnjdRncuG3rAM4r4SiiMEqhzzy350yPynhngDZQooOvbGlGglYKOKGukzp123qlz
# qkhqWUOuX+r4DwZCnd8GaJb+KqB0W2Nm3mssuHiqTXBt8CzxBxV+NbTmtQyimaXX
# FWs1DoXW4CzM4AwkuHxSCx6ZfO/IyMWMWGmvqz3hz8x9Fa4Uv4px38qXsdhH6hyF
# 4EVOEhwUKVjMb9N/y77BDkpvIJyu2XMyWQjnLZKhGhH+MpimXSuX4IvTnMxttQ2u
# R2M4RxdbbxPaahBuH0m3RFu0CAqHWlkEdhGhp3cCExwwggauMIIElqADAgECAhAH
# Nje3JFR82Ees/ShmKl5bMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAlVTMRUw
# EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x
# ITAfBgNVBAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0yMjAzMjMwMDAw
# MDBaFw0zNzAzMjIyMzU5NTlaMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdp
# Q2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2
# IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
# ggIKAoICAQDGhjUGSbPBPXJJUVXHJQPE8pE3qZdRodbSg9GeTKJtoLDMg/la9hGh
# RBVCX6SI82j6ffOciQt/nR+eDzMfUBMLJnOWbfhXqAJ9/UO0hNoR8XOxs+4rgISK
# Ihjf69o9xBd/qxkrPkLcZ47qUT3w1lbU5ygt69OxtXXnHwZljZQp09nsad/ZkIdG
# AHvbREGJ3HxqV3rwN3mfXazL6IRktFLydkf3YYMZ3V+0VAshaG43IbtArF+y3kp9
# zvU5EmfvDqVjbOSmxR3NNg1c1eYbqMFkdECnwHLFuk4fsbVYTXn+149zk6wsOeKl
# SNbwsDETqVcplicu9Yemj052FVUmcJgmf6AaRyBD40NjgHt1biclkJg6OBGz9vae
# 5jtb7IHeIhTZgirHkr+g3uM+onP65x9abJTyUpURK1h0QCirc0PO30qhHGs4xSnz
# yqqWc0Jon7ZGs506o9UD4L/wojzKQtwYSH8UNM/STKvvmz3+DrhkKvp1KCRB7UK/
# BZxmSVJQ9FHzNklNiyDSLFc1eSuo80VgvCONWPfcYd6T/jnA+bIwpUzX6ZhKWD7T
# A4j+s4/TXkt2ElGTyYwMO1uKIqjBJgj5FBASA31fI7tk42PgpuE+9sJ0sj8eCXbs
# q11GdeJgo1gJASgADoRU7s7pXcheMBK9Rp6103a50g5rmQzSM7TNsQIDAQABo4IB
# XTCCAVkwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUuhbZbU2FL3Mpdpov
# dYxqII+eyG8wHwYDVR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0P
# AQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMIMHcGCCsGAQUFBwEBBGswaTAk
# BggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAC
# hjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9v
# dEc0LmNydDBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5j
# b20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNybDAgBgNVHSAEGTAXMAgGBmeBDAEE
# AjALBglghkgBhv1sBwEwDQYJKoZIhvcNAQELBQADggIBAH1ZjsCTtm+YqUQiAX5m
# 1tghQuGwGC4QTRPPMFPOvxj7x1Bd4ksp+3CKDaopafxpwc8dB+k+YMjYC+VcW9dt
# h/qEICU0MWfNthKWb8RQTGIdDAiCqBa9qVbPFXONASIlzpVpP0d3+3J0FNf/q0+K
# LHqrhc1DX+1gtqpPkWaeLJ7giqzl/Yy8ZCaHbJK9nXzQcAp876i8dU+6WvepELJd
# 6f8oVInw1YpxdmXazPByoyP6wCeCRK6ZJxurJB4mwbfeKuv2nrF5mYGjVoarCkXJ
# 38SNoOeY+/umnXKvxMfBwWpx2cYTgAnEtp/Nh4cku0+jSbl3ZpHxcpzpSwJSpzd+
# k1OsOx0ISQ+UzTl63f8lY5knLD0/a6fxZsNBzU+2QJshIUDQtxMkzdwdeDrknq3l
# NHGS1yZr5Dhzq6YBT70/O3itTK37xJV77QpfMzmHQXh6OOmc4d0j/R0o08f56PGY
# X/sr2H7yRp11LB4nLCbbbxV7HhmLNriT1ObyF5lZynDwN7+YAN8gFk8n+2BnFqFm
# ut1VwDophrCYoCvtlUG3OtUVmDG0YgkPCr2B2RP+v6TR81fZvAT6gt4y3wSJ8ADN
# XcL50CN/AAvkdgIm2fBldkKmKYcJRyvmfxqkhQ/8mJb2VVQrH4D6wPIOK+XW+6kv
# RBVK5xMOHds3OBqhK/bt1nz8MYIDdjCCA3ICAQEwdzBjMQswCQYDVQQGEwJVUzEX
# MBUGA1UEChMORGlnaUNlcnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0
# ZWQgRzQgUlNBNDA5NiBTSEEyNTYgVGltZVN0YW1waW5nIENBAhAKekqInsmZQpAG
# YzhNhpedMA0GCWCGSAFlAwQCAQUAoIHRMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0B
# CRABBDAcBgkqhkiG9w0BCQUxDxcNMjIwNDA3MDYxNDU5WjArBgsqhkiG9w0BCRAC
# DDEcMBowGDAWBBSFCPOGUVyz0wd9trS3wH8bSl5B3jAvBgkqhkiG9w0BCQQxIgQg
# VIIsdkg+u8l/LpdtKutgUahsxLQctv5eZhzB0C1KJv8wNwYLKoZIhvcNAQkQAi8x
# KDAmMCQwIgQgnaaQFcNJxsGJeEW6NYKtcMiPpCk722q+nCvSU5J55jswDQYJKoZI
# hvcNAQEBBQAEggIATvmscJ1QxoCY0oc/q8tTKGt+y767djteEuJOK+89cIArEEHb
# T3KYGPccW5vP7r5jpG6tj14gEuBCnqy0q3K7ohVyWM3mGSUQDDYABc/TWqulqvk2
# EtKSrGphK3SXNilD3ifpZF63k9HHE+2C7B1iMjr2GwjTU2yQ9yFc7ylBkNOsu95Y
# af9MYB1Xc22lFaiN6rO3GZ+7T6hA/yeUBPU6l9w6doYf4XOMk3y1nct3UDk4ZHjn
# 2xAIzUlCKWYGb7jb9D3nKtxd9ZT1XSf4Xp6JFp9LdJ7FEekzAAYXC6jJEo5Ex0Vu
# 664GAw3HlArYgdp93Y2+9F66qXfq2ayGM77kpcKgKJw0SV+oPLmBg/bWE28LGy8Q
# S2aeFQl4jXIPjQ398/qByXlEBTyNYoteWun47H+kwhDtYL4trr30CDchrLtHQOTv
# b5UCEi9jdncrKn4sO3j9M69cke5+7QuUcNCg0x4p3LeOY4rUXSy9LtHXMSl10LFY
# zTPSyP6mcaT0wPn5+N8YKnz/7X2Cek3o34vDDSRmx/Oq24kI1gPfQGlURvXJzpEd
# wcUA3dCQzAXPQOEcS9zTDO+1i/ZnLpu1XFAEHqFOSVg8aCvEAkdAf7OCsUlkn2rc
# YukXlI9cqV/jB9gN9+qCq1dhg/3NxO0g4XOu27t4Z5uG1XH4P3ZysvREiog=
# SIG # End signature block