AzStackHciAddNode/AzStackHci.AddNode.Helpers.psm1

Import-LocalizedData -BindingVariable lanTxt -FileName AzStackHci.AddNode.Strings.psd1

function Test-ADCredential {
    [CmdletBinding()]
    param (
        [pscredential]
        $ActiveDirectoryCredential
    )
    try
    {
        $severity = 'CRITICAL'
        $adModuleExists = [bool](Get-Module ActiveDirectory -ListAvailable -ErrorAction SilentlyContinue)
        if ($adModuleExists)
        {
            [bool]$adTest = QueryAD -ActiveDirectoryCredential $ActiveDirectoryCredential
            $detail = $lanTxt.TestAD -f $AdTest, $true
            if ($adTest)
            {
                $status = 'SUCCESS'
                Log-Info $detail
            }
            else
            {
                $status = 'FAILURE'
                Log-Info $detail -Type $severity
            }
        }
        else
        {
            $status = 'FAILURE'
            $detail = $lanTxt.NoADModule
            Log-info $detail -Type $severity
        }

        $params = @{
            Name               = 'AzStackHci_AddNode_AD_Credential_Check'
            Title              = 'Test AD Credential'
            DisplayName        = 'Test AD Credential'
            Severity           = $severity
            Description        = 'Checking AD Credential is valid'
            Tags               = @{}
            Remediation        = 'https://learn.microsoft.com/en-us/azure-stack/hci/manage/add-server'
            TargetResourceID   = 'AD Credential'
            TargetResourceName = 'AD Credential'
            TargetResourceType = 'Credential'
            Timestamp          = [datetime]::UtcNow
            Status             = $Status
            AdditionalData     = @{
                Source    = $ENV:COMPUTERNAME
                Resource  = 'AD Credential'
                Detail    = $detail
                Status    = $status
                TimeStamp = [datetime]::UtcNow
            }
            HealthCheckSource  = $ENV:EnvChkrId
        }
        New-AzStackHciResultObject @params
    }
    catch
    {
        throw ("Error testing AD credential: {0}" -f $_.Exception)
    }
}

function QueryAD {
    [CmdletBinding()]
    param (
        [pscredential]
        $ActiveDirectoryCredential
    )
    try
    {
        $domain = $ActiveDirectoryCredential.GetNetworkCredential().domain
        if ([string]::IsNullOrEmpty($domain)) {
            if (($ActiveDirectoryCredential.UserName -split '@').count -le 1)
            {
                throw "Credential should contain domain"
            }
            else
            {
                $domain = ($ActiveDirectoryCredential.UserName -split '@')[1]
            }
        }
        return [bool](Get-ADDomain -Credential $ActiveDirectoryCredential -Server $domain -ErrorAction SilentlyContinue)
    }
    catch
    {
        throw ("Error retrieving AD Object: {0}" -f $_.Exception)
    }
}

function Test-LocalCredential {
    [CmdletBinding()]
    param (
        [pscredential]
        $LocalCredential,

        [string[]]
        $Ipv4OrHostName
    )
    try
    {
        $severity = 'CRITICAL'
        $PsSession = Microsoft.PowerShell.Core\New-PsSession -ComputerName $Ipv4OrHostName -Credential $LocalCredential
        Copy-RemoteItem -PsSession $PsSession -SourcePath (Join-Path (Split-Path -Parent $PSScriptRoot) "AzStackHci.EnvironmentChecker.PortableUtilities.psm1") -CmdletName "Test-Elevation"
        $IsAdmin = {
            if (Get-Command -Name Test-Elevation -ErrorAction SilentlyContinue)
            {
                Test-Elevation
            }
            else
            {
                throw "Cannot find Test-Elevation function"
            }
        }
        $results = @()
        $results += [bool](Microsoft.PowerShell.Core\Invoke-Command -Session $PsSession -ScriptBlock $IsAdmin -ErrorAction SilentlyContinue)
        $instanceResults = @()
        $instanceResults += foreach ($result in $results)
        {
            $detail = $lanTxt.TestLocalCredential -f $LocalCredential.UserName, $Ipv4OrHostName, $result, $true
            if ($result)
            {
                $status = 'SUCCESS'
                Log-Info $detail
            }
            else
            {
                $status = 'FAILURE'
                Log-Info $detail -Type $severity
            }

            $params = @{
                Name               = 'AzStackHci_AddNode_Local_Credential_Check'
                Title              = 'Test Local Credential'
                DisplayName        = 'Test Local Credential'
                Severity           = $severity
                Description        = 'Checking Local Credential is valid'
                Tags               = @{}
                Remediation        = 'https://learn.microsoft.com/en-us/azure-stack/hci/manage/add-server'
                TargetResourceID   = 'Local Credential'
                TargetResourceName = 'Local Credential'
                TargetResourceType = 'Credential'
                Timestamp          = [datetime]::UtcNow
                Status             = $Status
                AdditionalData     = @{
                    Source    = $Ipv4OrHostName
                    Resource  = 'Local Credential'
                    Detail    = $detail
                    Status    = $status
                    TimeStamp = [datetime]::UtcNow
                }
                HealthCheckSource  = $ENV:EnvChkrId
            }
            New-AzStackHciResultObject @params
        }
    }
    catch
    {
        throw ("Error testing local credential {0} on {1}. Error: {2}" -f $LocalCredential.UserName, $Ipv4OrHostName, $_.Exception)
    }
    finally
    {
        Remove-UtilityModule -PsSession $PsSession
        $PsSession | Remove-PSSession -ErrorAction SilentlyContinue
    }
}

function Test-ClusterNodeName {
    [CmdletBinding()]
    param (
        [string[]]
        $ComputerName
    )
    try
    {
        $severity = 'CRITICAL'
        [string[]]$clusterNodes = Get-ClusterNodeNames
        [string[]]$nodeNamesInUse = $ComputerName | Where-Object { $_ -in $clusterNodes }
        $detail = $lanTxt.TestClusterNodeName -f ($computerName -join ','), [bool]$nodeNamesInUse, $false
        if ($nodeNamesInUse.Count -eq 0)
        {
            Log-Info $detail
            $status = 'SUCCESS'
        }
        else
        {
            $detail = $detail + "`r`n" + $lanTxt.RemoveClusterNodeName -f ($nodeNamesInUse -join ',')
            $status = 'FAILURE'
            Log-Info $detail -Type $severity
        }

        $clusterName = Get-LocalClusterName
        $params = @{
            Name               = 'AzStackHci_AddNode_ComputerName_Check'
            Title              = 'Test ComputerName'
            DisplayName        = 'Test ComputerName'
            Severity           = $severity
            Description        = 'Checking ComputerName(s) is not in use in existing cluster'
            Tags               = @{}
            Remediation        = 'https://learn.microsoft.com/en-us/azure-stack/hci/manage/add-server'
            TargetResourceID   = $clusterName
            TargetResourceName = $clusterName
            TargetResourceType = 'Computer Name'
            Timestamp          = [datetime]::UtcNow
            Status             = $Status
            AdditionalData     = @{
                Source    = $ENV:COMPUTERNAME
                Resource  = $ComputerName -join ','
                Detail    = $detail
                Status    = $status
                TimeStamp = [datetime]::UtcNow
            }
            HealthCheckSource  = $ENV:EnvChkrId
        }
        New-AzStackHciResultObject @params
    }
    catch
    {
        throw ($lanTxt.NodeNameCheckError -f ($ComputerName -join ','), $_.Exception)
    }
}

function Get-ClusterNodeNames {
    <#
    .SYNOPSIS
        Get the cluster node names from the local cluster
    .OUTPUTS
        Returns the cluster node names.
    #>

    [CmdletBinding()]
    param ()

    try
    {
        $ClusterNodeNames = Get-ClusterNode | Select-Object -ExpandProperty Name
        Log-Info "Local Cluster Name: $($ClusterNodeNames -join ', ')"
        return $ClusterNodeNames
    }
    catch
    {
        throw ("Error retrieving cluster node names: {0}" -f $_.Exception)
    }
}

function Get-LocalClusterName {
    <#
    .SYNOPSIS
        Get the cluster name from the local cluster
    .OUTPUTS
        Returns the cluster name.
    #>

    [CmdletBinding()]
    param ()

    try
    {
        $ClusterName = Get-Cluster | Select-Object -ExpandProperty Name
        Log-Info "Local Cluster Name: $ClusterName"
        return $ClusterName
    }
    catch
    {
        throw ("Error retrieving cluster name: {0}" -f $_.Exception)
    }
}

function Test-ComputerName {
    [CmdletBinding()]
    param (
        [string[]]
        $ComputerName,

        [pscredential]
        $LocalCredential,

        [string[]]
        $Ipv4OrHostName
    )
    try
    {
        # if no IP is provided, we assume this is repair and return
        $severity = 'CRITICAL'
        if ($Ipv4OrHostName.Count -eq 0 -or -not $Ipv4OrHostName)
        {
            return
        }

        # Build a hashtable of IPs and computer names
        [array]$nodeIpMap += GetCsNameFromIps -LocalCredential $LocalCredential -Ipv4OrHostName $Ipv4OrHostName

        # verify all computername names
        if ($null -in $nodeIpMap.ComputerName)
        {
            throw "Failed to resolve ComputerName from all IP(s): $($Ipv4OrHostName -join ', ')"
        }

        $dtl = ""
        [string[]]$NodeMapComputerNames = $nodeIpMap | Select-Object -ExpandProperty ComputerName
        $compareResult = Compare-Object -ReferenceObject $ComputerName -DifferenceObject $NodeMapComputerNames
        if (-not $compareResult)
        {
            $status = 'SUCCESS'
            $dtl = "All ComputerName(s) match the IP(s): {0}" -f (($nodeIpMap | ForEach-Object { "'$($_.Ipv4OrHostName)' -> '$($_.ComputerName)'" }) -join ', ')
        }
        else
        {
            $status = 'FAILURE'
            $dtl += "Inconsistency found between ComputerName(s) and IP(s):"
            foreach ($cr in $compareResult)
            {
                if ($cr.SideIndicator -eq '=>')
                {
                    $foundOn = $nodeIpMap | Where-Object { $_.ComputerName -eq $cr.InputObject } | Select-Object -ExpandProperty Ipv4OrHostName
                    $dtl += "`r`n - ComputerName '$($cr.InputObject)' was found on $($foundOn -join ',')"
                }
                else
                {
                    $dtl += "`r`n - ComputerName '$($cr.InputObject)' was not found on the provided IPs.`r`nPlease check the IP(s) and ComputerName(s) provided are correct."
                }
            }

            Log-Info -Message $dtl -Type $severity
        }

        $params = @{
            Name               = 'AzStackHci_AddNode_ComputerNameIPs_Match'
            Title              = 'Test ComputerName IP'
            DisplayName        = 'Test ComputerName IP'
            Severity           = $severity
            Description        = 'Checking Computer(s) have correct IP(s) configured'
            Tags               = @{}
            Remediation        = 'https://learn.microsoft.com/en-us/azure-stack/hci/manage/add-server'
            TargetResourceID   = "$($Ipv4OrHostName -join ',')"
            TargetResourceName = "$($ComputerName -join ',')"
            TargetResourceType = 'Ip Configuration'
            Timestamp          = [datetime]::UtcNow
            Status             = $Status
            AdditionalData     = @{
                Source    = ($ComputerName -join ',')
                Resource  = ($Ipv4OrHostName -join ',')
                Detail    = $dtl
                Status    = $status
                TimeStamp = [datetime]::UtcNow
            }
            HealthCheckSource  = $ENV:EnvChkrId
        }
        New-AzStackHciResultObject @params
    }
    catch
    {
        throw ("Error testing IP {0} is set locally on {1}. Error: {2}" -f ($Ipv4OrHostName -join ','), ($ComputerName -join ','), $_)
    }
}

function GetCsNameFromIps {
    <#
    .SYNOPSIS
        Get the computer name from the IP address
    .PARAMETER Ipv4OrHostName
        The IP address or host name to resolve
    .OUTPUTS
        Returns the computer name associated with the provided IP address or host name.
    #>

    [CmdletBinding()]
    param (
        [pscredential]
        $LocalCredential,

        [string[]]
        $Ipv4OrHostName
    )
    $sb = {
        (Get-WmiObject -ClassName Win32_OperatingSystem | Select-Object -expand CSName)
    }
    $ipNodeMap = @()
    foreach ($ip in $Ipv4OrHostName)
    {
        $csName = (Microsoft.PowerShell.Core\Invoke-Command -ComputerName $ip -Credential $LocalCredential -ScriptBlock $sb -ErrorAction SilentlyContinue)
        $ipNodeMap += New-Object -TypeName PSObject -Property @{
            ComputerName = $csName
            Ipv4OrHostName = $ip
        }
    }
    return $ipNodeMap
}

function Test-Quorum {
    <#
    .SYNOPSIS
        Check if single node cluster has correct quorum configuration
    #>

    [CmdletBinding()]
    param()
    try {
        # Get the current number of nodes in the cluster
        $severity = 'CRITICAL'
        $CurrentNumberOfNodes = (Get-ClusterNode).Count

        # if the cluster has only one node, check if the quorum is set to NodeandFileShareMajority or CloudWitness
        if ($CurrentNumberOfNodes -eq 1)
        {
            $Quorum = Get-ClusterQuorum
            $detail = $lanTxt.QuorumCheck -f $Quorum.Cluster.Name, $CurrentNumberOfNodes, $Quorum.QuorumResource.ResourceType.Name,'File Share Witness or Cloud Witness'
            if ($Quorum.QuorumResource.ResourceType.Name -eq 'File Share Witness' -or $Quorum.QuorumResource.ResourceType.Name -eq 'Cloud Witness')
            {
                Log-Info $detail
                $Status = 'SUCCESS'
            }
            else
            {
                Log-Info $detail -Type $severity
                $Status = 'FAILURE'
            }

            $params = @{
                Name               = 'AzStackHci_AddNode_Quorum_Resource_Check'
                Title              = 'Test Quorum Resource'
                DisplayName        = 'Test Quorum Resource'
                Severity           = $severity
                Description        = 'Checking Quorum Resource is set to File Share Witness or CloudWitness'
                Tags               = @{}
                Remediation        = 'https://learn.microsoft.com/en-us/azure-stack/hci/manage/add-server'
                TargetResourceID   = "$($Quorum.Cluster.Name)/$($Quorum.QuorumResource.Name)"
                TargetResourceName = $Quorum.QuorumResource.Name
                TargetResourceType = 'Quorum Resource'
                Timestamp          = [datetime]::UtcNow
                Status             = $Status
                AdditionalData     = @{
                    Source    = $Quorum.Cluster.Name
                    Resource  = $Quorum.QuorumResource.Name
                    Detail    = $detail
                    Status    = $status
                    TimeStamp = [datetime]::UtcNow
                }
                HealthCheckSource  = $ENV:EnvChkrId
            }
            New-AzStackHciResultObject @params
        }
    }
    catch {
        throw ("Error cluster quorum on {0}. Error: {1}" -f (Get-Cluster).Name, $_.Exception)
    }
}

function Test-DriveLetterConsistency
{
    <#
    .SYNOPSIS
        Check if the DriveLetters are consistent across the cluster nodes.
    #>

    [CmdletBinding()]
    param (
        [pscredential]
        $LocalCredential,

        [string[]]
        $Ipv4OrHostName,

        [string[]]
        $DriveLetter = @('C','D')
    )
    try
    {
        $severity = 'CRITICAL'

        # get DriveLetters from the remote node
        $addNodeDriveLetters = @()
        $addNodeDriveLetters = Get-RemoteDriveLetter -LocalCredential $LocalCredential -Ipv4OrHostName $Ipv4OrHostName -DriveLetter $DriveLetter
        $localNodeDriveLetters = Get-LocalDriveLetter -DriveLetter $DriveLetter
        $instanceResults = @()
        foreach ($addNode in $addNodeDriveLetters)
        {
            if ($null -eq $addNode.DriveLetters)
            {
                $status = 'FAILURE'
                $detail = $lanTxt.DriveLetterConsistencyCheckError -f $addNode.ComputerName, ($addNode.DriveLetters -join ','), $DriveLetter -join ','
                Log-Info $detail -Type $severity
            }
            else
            {
                if (Compare-Object -ReferenceObject $addNode.DriveLetters -DifferenceObject $localNodeDriveLetters)
                {
                    $status = 'FAILURE'
                    $detail = $lanTxt.DriveLetterInconsistent -f $addNode.computername, ($addNode.DriveLetters -join ','), $env:computername, ($localNodeDriveLetters -join ','), ($DriveLetter -join ',')
                    Log-Info $detail -Type $severity
                }
                else
                {
                    $status = 'SUCCESS'
                    $detail = $lanTxt.DriveLetterConsistent -f  $addNode.computername, ($addNode.DriveLetters -join ','), $env:computername, ($localNodeDriveLetters -join ',')
                    Log-Info $detail
                }
            }
            $params = @{
                Name               = 'AzStackHci_AddNode_DriveLetter_Consistency_Check'
                Title              = 'Test DriveLetter Consistency'
                DisplayName        = 'Test DriveLetter Consistency'
                Severity           = $severity
                Description        = 'Checking DriveLetters are consistent across the cluster nodes'
                Tags               = @{}
                Remediation        = 'https://learn.microsoft.com/en-us/azure-stack/hci/manage/add-server'
                TargetResourceID   = $addNode.ComputerName
                TargetResourceName = $addNode.ComputerName
                TargetResourceType = 'DriveLetter'
                Timestamp          = [datetime]::UtcNow
                Status             = $Status
                AdditionalData     = @{
                    Source    = $addNode.ComputerName
                    Resource  = $addNode.DriveLetters -join ','
                    Detail    = $detail
                    Status    = $status
                    TimeStamp = [datetime]::UtcNow
                }
                HealthCheckSource  = $ENV:EnvChkrId
            }
            $instanceResults += New-AzStackHciResultObject @params
        }
        return $instanceResults
    }
    catch
    {
        throw ("Error checking DriveLetter consistency to node(s): $($Ipv4OrHostName -join ','). $($_.exception.StackTrace)")
    }
}

function Get-RemoteDriveLetter {
    [CmdletBinding()]
    param (
        [pscredential]
        $LocalCredential,

        [string[]]
        $Ipv4OrHostName,

        [string[]]
        $DriveLetter = @('C', 'D')
    )
    try
    {
        $addNodeDriveLetters = @()
        $addNodeDriveLetters = Microsoft.PowerShell.Core\Invoke-Command -ComputerName $Ipv4OrHostName -Credential $LocalCredential -ScriptBlock {
            $remoteDriveLetters = Get-Volume | Where-Object { $_.DriveLetter -in $USING:DriveLetter } | Select-Object -ExpandProperty DriveLetter | Sort-Object
            return (New-Object -TypeName PSObject -Property @{
                ComputerName = $env:COMPUTERNAME
                DriveLetters = $remoteDriveLetters
            })
        }
        return $addNodeDriveLetters
    }
    catch
    {
        throw ("Error retrieving DriveLetters from remote node {0}. Error: {1}" -f ($Ipv4OrHostName -join ','), $_.Exception)
    }
}

function Get-LocalDriveLetter {
    [CmdletBinding()]
    param (
        [string[]]
        $DriveLetter = @('C', 'D')
    )
    try
    {
        $driveLetters = @()
        $driveLetters = Get-Volume | Where-Object { $_.DriveLetter -in $DriveLetter } | Select-Object -ExpandProperty DriveLetter | Sort-Object
        return $driveLetters
    }
    catch
    {
        throw ("Error retrieving local DriveLetters. Error: {0}" -f $_.Exception)
    }
}

Export-ModuleMember -Function Test-*
# SIG # Begin signature block
# MIIoLQYJKoZIhvcNAQcCoIIoHjCCKBoCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCApwxw3kJgGw4ds
# iqKuc99NSZXYgnZRIQJW+m0vwhj7SKCCDXYwggX0MIID3KADAgECAhMzAAAEhV6Z
# 7A5ZL83XAAAAAASFMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
# bmcgUENBIDIwMTEwHhcNMjUwNjE5MTgyMTM3WhcNMjYwNjE3MTgyMTM3WjB0MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQDASkh1cpvuUqfbqxele7LCSHEamVNBfFE4uY1FkGsAdUF/vnjpE1dnAD9vMOqy
# 5ZO49ILhP4jiP/P2Pn9ao+5TDtKmcQ+pZdzbG7t43yRXJC3nXvTGQroodPi9USQi
# 9rI+0gwuXRKBII7L+k3kMkKLmFrsWUjzgXVCLYa6ZH7BCALAcJWZTwWPoiT4HpqQ
# hJcYLB7pfetAVCeBEVZD8itKQ6QA5/LQR+9X6dlSj4Vxta4JnpxvgSrkjXCz+tlJ
# 67ABZ551lw23RWU1uyfgCfEFhBfiyPR2WSjskPl9ap6qrf8fNQ1sGYun2p4JdXxe
# UAKf1hVa/3TQXjvPTiRXCnJPAgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUuCZyGiCuLYE0aU7j5TFqY05kko0w
# RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW
# MBQGA1UEBRMNMjMwMDEyKzUwNTM1OTAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci
# tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG
# CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu
# Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0
# MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBACjmqAp2Ci4sTHZci+qk
# tEAKsFk5HNVGKyWR2rFGXsd7cggZ04H5U4SV0fAL6fOE9dLvt4I7HBHLhpGdE5Uj
# Ly4NxLTG2bDAkeAVmxmd2uKWVGKym1aarDxXfv3GCN4mRX+Pn4c+py3S/6Kkt5eS
# DAIIsrzKw3Kh2SW1hCwXX/k1v4b+NH1Fjl+i/xPJspXCFuZB4aC5FLT5fgbRKqns
# WeAdn8DsrYQhT3QXLt6Nv3/dMzv7G/Cdpbdcoul8FYl+t3dmXM+SIClC3l2ae0wO
# lNrQ42yQEycuPU5OoqLT85jsZ7+4CaScfFINlO7l7Y7r/xauqHbSPQ1r3oIC+e71
# 5s2G3ClZa3y99aYx2lnXYe1srcrIx8NAXTViiypXVn9ZGmEkfNcfDiqGQwkml5z9
# nm3pWiBZ69adaBBbAFEjyJG4y0a76bel/4sDCVvaZzLM3TFbxVO9BQrjZRtbJZbk
# C3XArpLqZSfx53SuYdddxPX8pvcqFuEu8wcUeD05t9xNbJ4TtdAECJlEi0vvBxlm
# M5tzFXy2qZeqPMXHSQYqPgZ9jvScZ6NwznFD0+33kbzyhOSz/WuGbAu4cHZG8gKn
# lQVT4uA2Diex9DMs2WHiokNknYlLoUeWXW1QrJLpqO82TLyKTbBM/oZHAdIc0kzo
# STro9b3+vjn2809D0+SOOCVZMIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq
# hkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x
# EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv
# bjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
# IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEwOTA5WjB+MQswCQYDVQQG
# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQg
# Q29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
# CgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+laUKq4BjgaBEm6f8MMHt03
# a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc6Whe0t+bU7IKLMOv2akr
# rnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4Ddato88tt8zpcoRb0Rrrg
# OGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+lD3v++MrWhAfTVYoonpy
# 4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDstrjNYxbc+/jLTswM9
# sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6A4aN91/w0FK/jJSHvMAh
# dCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmdX4jiJV3TIUs+UsS1Vz8k
# A/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL5zmhD+kjSbwYuER8ReTB
# w3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zdsGbiwZeBe+3W7UvnSSmn
# Eyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3T8HhhUSJxAlMxdSlQy90
# lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS4NaIjAsCAwEAAaOCAe0w
# ggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTlUAXTgqoXNzcitW2o
# ynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYD
# VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQFTuHqp8cx0SOJNDBa
# BgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2Ny
# bC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3JsMF4GCCsG
# AQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3dy5taWNyb3NvZnQuY29t
# L3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3J0MIGfBgNV
# HSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEFBQcCARYzaHR0cDovL3d3
# dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1hcnljcHMuaHRtMEAGCCsG
# AQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5AF8AcwB0AGEAdABl
# AG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn8oalmOBUeRou09h0ZyKb
# C5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7v0epo/Np22O/IjWll11l
# hJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0bpdS1HXeUOeLpZMlEPXh6
# I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtYSWMfCWluWpiW5IP0
# wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvyCInWH8MyGOLwxS3OW560
# STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZiWhub6e3dMNABQam
# ASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJihsMdYzaXht/a8/jyFqGa
# J+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYbBL7fQccOKO7eZS/sl/ah
# XJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKfenoi+kiVH6v7RyOA
# 9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOppO6/8MO0ETI7f33Vt
# Y5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZOSEXAQsmbdlsKgEhr
# /Xmfwb1tbWrJUnMTDXpQzTGCGg0wghoJAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw
# EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
# aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp
# Z25pbmcgUENBIDIwMTECEzMAAASFXpnsDlkvzdcAAAAABIUwDQYJYIZIAWUDBAIB
# BQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO
# MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIPp10wfNwdQWnyTBMP1WOWec
# vLbhMKFkGaoQR+M9tc27MEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A
# cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB
# BQAEggEAs5T9TdKbEqUOXIkJd6YN0tp+bfbO+OwLtezoy4L+zZzsXodCZMtfS9gg
# CQDdiZUouKbeCrAPRSf4+yfaQR3npI2pK1cglJkjpu5uzOa+AF8oZc6PCJ9GHbug
# AduNbKOVjY+N7AxwFuoKZLgugy4fiwa7mx+/Cv7J/VSHg4ieSh4Dke5YLg1TNB7t
# EIjDP0Sk+KtqG3170r2QV/JUgVP5YAzkPnw/3PxFyIFPiRJ1M+uaI+y8k+Yhkygm
# 29yJ4Gw9cJSmdyIVNrpD7b3c8H9J0sOuSZlqJM7e3r4S8LsKXsQKX8CX62jLN9qi
# 5x5Dpu2SeRz6jvxxPopwzvdQKd2WeaGCF5cwgheTBgorBgEEAYI3AwMBMYIXgzCC
# F38GCSqGSIb3DQEHAqCCF3AwghdsAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFSBgsq
# hkiG9w0BCRABBKCCAUEEggE9MIIBOQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl
# AwQCAQUABCC0tJ314N5JQ+YDXxBPmEkip43SGdbrBkCaYbhcdJe7LAIGaKOkTfBN
# GBMyMDI1MDkwOTE5MjIwNC4yMjZaMASAAgH0oIHRpIHOMIHLMQswCQYDVQQGEwJV
# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1l
# cmljYSBPcGVyYXRpb25zMScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046OTYwMC0w
# NUUwLUQ5NDcxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2Wg
# ghHtMIIHIDCCBQigAwIBAgITMwAAAgTY4A4HlzJYmAABAAACBDANBgkqhkiG9w0B
# AQsFADB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYD
# VQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDAeFw0yNTAxMzAxOTQy
# NDdaFw0yNjA0MjIxOTQyNDdaMIHLMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2Fz
# aGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENv
# cnBvcmF0aW9uMSUwIwYDVQQLExxNaWNyb3NvZnQgQW1lcmljYSBPcGVyYXRpb25z
# MScwJQYDVQQLEx5uU2hpZWxkIFRTUyBFU046OTYwMC0wNUUwLUQ5NDcxJTAjBgNV
# BAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2UwggIiMA0GCSqGSIb3DQEB
# AQUAA4ICDwAwggIKAoICAQDw3Sbcee2d66vkWGTIXhfGqqgQGxQXTnq44XlUvNzF
# St7ELtO4B939jwZFX7DrRt/4fpzGNkFdGpc7EL5S86qKYv360eXjW+fIv1lAqDD3
# 1d/p8Ai9/AZz8M95zo0rDpK2csz9WAyR9FtUDx52VOs9qP3/pgpHvgUvD8s6/3KN
# ITzms8QC1tJ3TMw1cRn9CZgVIYzw2iD/ZvOW0sbF/DRdgM8UdtxjFIKTXTaI/bJh
# sQge3TwayKQ2j85RafFFVCR5/ChapkrBQWGwNFaPzpmYN46mPiOvUxriISC9nQ/G
# rDXUJWzLDmchrmr2baABJevvw31UYlTlLZY6zUmjkgaRfpozd+Glq9TY2E3Dglr6
# PtTEKgPu2hM6v8NiU5nTvxhDnxdmcf8UN7goeVlELXbOm7j8yw1xM9IyyQuUMWko
# rBaN/5r9g4lvYkMohRXEYB0tMaOPt0FmZmQMLBFpNRVnXBTa4haXvn1adKrvTz8V
# lfnHxkH6riA/h2AlqYWhv0YULsEcHnaDWgqA29ry+jH097MpJ/FHGHxk+d9kH2L5
# aJPpAYuNmMNPB7FDTPWAx7Apjr/J5MhUx0i07gV2brAZ9J9RHi+fMPbS+Qm4AonC
# 5iOTj+dKCttVRs+jKKuO63CLwqlljvnUCmuSavOX54IXOtKcFZkfDdOZ7cE4DioP
# 1QIDAQABo4IBSTCCAUUwHQYDVR0OBBYEFBp1dktAcGpW/Km6qm+vu4M1GaJfMB8G
# A1UdIwQYMBaAFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMF8GA1UdHwRYMFYwVKBSoFCG
# Tmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY3Jvc29mdCUy
# MFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNybDBsBggrBgEFBQcBAQRgMF4w
# XAYIKwYBBQUHMAKGUGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2Vy
# dHMvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBDQSUyMDIwMTAoMSkuY3J0MAwG
# A1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwDgYDVR0PAQH/BAQD
# AgeAMA0GCSqGSIb3DQEBCwUAA4ICAQBecv6sRw2HTLMyUC1WJJ+FR+DgA9Jkv0lG
# sIt4y69CmOj8R63oFbhSmcdpakxqNbr8v9dyTb4RDyNqtohiiXbtrXmQK5X7y/Q+
# +F0zMotTtTpTPvG3eltyV/LvO15mrLoNQ7W4VH58aLt030tORxs8VnAQQF5BmQQM
# Oua+EQgH4f1F4uF6rl3EC17JBSJ0wjHSea/n0WYiHPR0qkz/NRAf8lSUUV0gbIMa
# wGIjn7+RKyCr+8l1xdNkK/F0UYuX3hG0nE+9Wc0L4A/enluUN7Pa9vOV6Vi3BOJS
# T0RY/ax7iZ45leM8kqCw7BFPcTIkWzxpjr2nCtirnkw7OBQ6FNgwIuAvYNTU7r60
# W421YFOL5pTsMZcNDOOsA01xv7ymCF6zknMGpRHuw0Rb2BAJC9quU7CXWbMbAJLd
# Z6XINKariSmCX3/MLdzcW5XOycK0QhoRNRf4WqXRshEBaY2ymJvHO48oSSY/kpuY
# vBS3ljAAuLN7Rp8jWS7t916paGeE7prmrP9FJsoy1LFKmFnW+vg43ANhByuAEXq9
# Cay5o7K2H5NFnR5wj/SLRKwK1iyUX926i1TEviEiAh/PVyJbAD4koipig28p/6HD
# uiYOZ0wUkm/a5W8orIjoOdU3XsJ4i08CfNp5I73CsvB5QPYMcLpF9NO/1LvoQAw3
# UPdL55M5HTCCB3EwggVZoAMCAQICEzMAAAAVxedrngKbSZkAAAAAABUwDQYJKoZI
# hvcNAQELBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw
# DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
# MjAwBgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAy
# MDEwMB4XDTIxMDkzMDE4MjIyNVoXDTMwMDkzMDE4MzIyNVowfDELMAkGA1UEBhMC
# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRp
# bWUtU3RhbXAgUENBIDIwMTAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
# AQDk4aZM57RyIQt5osvXJHm9DtWC0/3unAcH0qlsTnXIyjVX9gF/bErg4r25Phdg
# M/9cT8dm95VTcVrifkpa/rg2Z4VGIwy1jRPPdzLAEBjoYH1qUoNEt6aORmsHFPPF
# dvWGUNzBRMhxXFExN6AKOG6N7dcP2CZTfDlhAnrEqv1yaa8dq6z2Nr41JmTamDu6
# GnszrYBbfowQHJ1S/rboYiXcag/PXfT+jlPP1uyFVk3v3byNpOORj7I5LFGc6XBp
# Dco2LXCOMcg1KL3jtIckw+DJj361VI/c+gVVmG1oO5pGve2krnopN6zL64NF50Zu
# yjLVwIYwXE8s4mKyzbnijYjklqwBSru+cakXW2dg3viSkR4dPf0gz3N9QZpGdc3E
# XzTdEonW/aUgfX782Z5F37ZyL9t9X4C626p+Nuw2TPYrbqgSUei/BQOj0XOmTTd0
# lBw0gg/wEPK3Rxjtp+iZfD9M269ewvPV2HM9Q07BMzlMjgK8QmguEOqEUUbi0b1q
# GFphAXPKZ6Je1yh2AuIzGHLXpyDwwvoSCtdjbwzJNmSLW6CmgyFdXzB0kZSU2LlQ
# +QuJYfM2BjUYhEfb3BvR/bLUHMVr9lxSUV0S2yW6r1AFemzFER1y7435UsSFF5PA
# PBXbGjfHCBUYP3irRbb1Hode2o+eFnJpxq57t7c+auIurQIDAQABo4IB3TCCAdkw
# EgYJKwYBBAGCNxUBBAUCAwEAATAjBgkrBgEEAYI3FQIEFgQUKqdS/mTEmr6CkTxG
# NSnPEP8vBO4wHQYDVR0OBBYEFJ+nFV0AXmJdg/Tl0mWnG1M1GelyMFwGA1UdIARV
# MFMwUQYMKwYBBAGCN0yDfQEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWlj
# cm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTATBgNVHSUEDDAK
# BggrBgEFBQcDCDAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMC
# AYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvX
# zpoYxDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20v
# cGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYI
# KwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDANBgkqhkiG
# 9w0BAQsFAAOCAgEAnVV9/Cqt4SwfZwExJFvhnnJL/Klv6lwUtj5OR2R4sQaTlz0x
# M7U518JxNj/aZGx80HU5bbsPMeTCj/ts0aGUGCLu6WZnOlNN3Zi6th542DYunKmC
# VgADsAW+iehp4LoJ7nvfam++Kctu2D9IdQHZGN5tggz1bSNU5HhTdSRXud2f8449
# xvNo32X2pFaq95W2KFUn0CS9QKC/GbYSEhFdPSfgQJY4rPf5KYnDvBewVIVCs/wM
# nosZiefwC2qBwoEZQhlSdYo2wh3DYXMuLGt7bj8sCXgU6ZGyqVvfSaN0DLzskYDS
# PeZKPmY7T7uG+jIa2Zb0j/aRAfbOxnT99kxybxCrdTDFNLB62FD+CljdQDzHVG2d
# Y3RILLFORy3BFARxv2T5JL5zbcqOCb2zAVdJVGTZc9d/HltEAY5aGZFrDZ+kKNxn
# GSgkujhLmm77IVRrakURR6nxt67I6IleT53S0Ex2tVdUCbFpAUR+fKFhbHP+Crvs
# QWY9af3LwUFJfn6Tvsv4O+S3Fb+0zj6lMVGEvL8CwYKiexcdFYmNcP7ntdAoGokL
# jzbaukz5m/8K6TT4JDVnK+ANuOaMmdbhIurwJ0I9JZTmdHRbatGePu1+oDEzfbzL
# 6Xu/OHBE0ZDxyKs6ijoIYn/ZcGNTTY3ugm2lBRDBcQZqELQdVTNYs6FwZvKhggNQ
# MIICOAIBATCB+aGB0aSBzjCByzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp
# bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw
# b3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEn
# MCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjk2MDAtMDVFMC1EOTQ3MSUwIwYDVQQD
# ExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNloiMKAQEwBwYFKw4DAhoDFQC6
# PYHRw9+9SH+1pwy6qzVG3k9lbqCBgzCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1w
# IFBDQSAyMDEwMA0GCSqGSIb3DQEBCwUAAgUA7Gp45zAiGA8yMDI1MDkwOTA5NTkw
# M1oYDzIwMjUwOTEwMDk1OTAzWjB3MD0GCisGAQQBhFkKBAExLzAtMAoCBQDsanjn
# AgEAMAoCAQACAhdFAgH/MAcCAQACAhQYMAoCBQDsa8pnAgEAMDYGCisGAQQBhFkK
# BAIxKDAmMAwGCisGAQQBhFkKAwKgCjAIAgEAAgMHoSChCjAIAgEAAgMBhqAwDQYJ
# KoZIhvcNAQELBQADggEBAEy/zxZn/eJP7mNC+ik3qOl787yHEwwJMjAvcZ5cPoQu
# LPWn4r08ywGO3jfRi9UX3O0lFhgWGzENyLffejZa4wRPVizOv5lWt+XNxhDk9Xun
# WisBXVR8QTufZfS8uuGZZCIfSRmiKufQ0ID22uJXAMHqkH0J3c//zjYfQqPD8BJ/
# Q0r9th3hNSpZn8rsr5V4wOynJaUvbT7RNeS1K7DGi6I3mIZHsYhYHIp+WWIg0Vvv
# nl6XzdUY6SrrpLKQ1931iecC/Gf8uIuNj1knI3ymtNwSkhOp3IPfoCJ4tqQSQZZm
# 12eiqYVCMSlIBTddCaYAiSAklsjM+Brw3hSMOzT6YvwxggQNMIIECQIBATCBkzB8
# MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVk
# bW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1N
# aWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAgTY4A4HlzJYmAABAAAC
# BDANBglghkgBZQMEAgEFAKCCAUowGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEE
# MC8GCSqGSIb3DQEJBDEiBCDuZeEbZPjkcJp8L941TjlWbzDZprwvm6AkVIibA2LB
# PDCB+gYLKoZIhvcNAQkQAi8xgeowgecwgeQwgb0EIPnteGX9Wwq8VdJM6mjfx1GE
# Jsu7/6kU6l0SS5rcebn+MIGYMIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgT
# Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m
# dCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENB
# IDIwMTACEzMAAAIE2OAOB5cyWJgAAQAAAgQwIgQgUer8geqTMk40hdkMD03WMHK2
# PBn5sabVYAb9uyCD8KkwDQYJKoZIhvcNAQELBQAEggIAxOE2jKXutuMUUkypYt3W
# dCQBxaS+/6AXF3MpbTEcrSsWQnFUy4vHm50tUKxUqBE0VkaLulXrqf8yQhgxeg2M
# VUzx1X6hvg7sQ9KK84m9Ll1MU4X010CL4/lvoI2njkhBxVjPMzQYiEYRloeUh3pS
# 7jY+D51wJoSvHIgw+c+6/xLvCDzE6oFxPF1W8wxQd7H4pUt6uaUkhe1LDfAsk7fT
# b1auOGGQAKn/Kw+WSAD2A4kOmoPkK181y/Qq7CXJ7p8BnLZNnErA6tKHSlmKMvPB
# o+a7XvA77bwrQJ/2Kz0EWB9yF0gEGROu/V1m0Q8lZFr23dV/ZPSIWl2sHURAbnpR
# bWiqheRWj4pJaqTxKvSuS2PAw3nNnBAXjguP22B2SZswvvvRILZOGb/rFVBo9x72
# CKUEtmpEL/KJM9Hc9ANnS33pObqgxXtdJYsNimNsFyPbH1XasvlxNj9zhJG3y8MG
# IhRsdk9x9wvtdGmsJL6D0IeSDShn0eDzg9Y2VfLM1WqnY+0yoVm2Ngsfd1SAu5cq
# vvjTEFPPqWDeXXWBLCfpgqbTgvaLZiNatkKeFmy2k9fSWUnUI01qnToouwhfugxm
# mCrbBc6djojq1i6CHJvK2aELF8OYeKQ+UJH2x7343kkbjUssd41sXXbZDcETl7cJ
# IGBj70cuI/ZWflzTQoY/c1E=
# SIG # End signature block