modules/AzStack.Common/AzStack.Common.psm1

<################################################################
# #
# Copyright (C) Microsoft Corporation. All rights reserved. #
# #
################################################################>


Import-LocalizedData -BindingVariable 'msg' -BaseDirectory "$PSScriptRoot\locale" -UICulture "en-US" -WarningAction SilentlyContinue
Import-Module $PSScriptRoot\..\AzStack.Utilities\AzStack.Utilities.psm1 -WarningAction SilentlyContinue
Import-Module $PSScriptRoot\AzStack.Common.Helper.psm1

function Get-AzsSupportInfrastructureHost {
    <#
    .SYNOPSIS
        Gets physical host node information from FailoverClustering.
     
    .DESCRIPTION
        Gets physical host node information from FailoverClustering. If no Cluster is provided, it will attempt to find Nodes.
 
    .PARAMETER Name
        A node name, such as contoso-n01 to filter the results.
 
    .PARAMETER Cluster
        Cluster to connect to, such as contoso-cl
 
    .PARAMETER State
        A node state, such as Up, Down, Paused, or Unknown to filter the results.
 
    .EXAMPLE
        PS> Get-AzsSupportInfrastructureHost
 
    .EXAMPLE
        PS> Get-AzsSupportInfrastructureHost -Cluster "contoso-cl"
 
    .EXAMPLE
        PS> Get-AzsSupportInfrastructureHost -Node "contoso-n01" -Cluster "contoso-cl"
 
    .EXAMPLE
        PS> Get-AzsSupportInfrastructureHost -Cluster $Cluster -State:Up
 
    .OUTPUTS
            Get-AzsSupportInfrastructureHost -cluster contoso-cl
 
            Name State Type
            ---- ----- ----
            contoso-n01 Up Node
            contoso-n02 Up Node
         
    #>


    [CmdletBinding()]
    param(
        [parameter(mandatory = $false)]
        [String]$Name,
        [parameter(mandatory = $false)]
        [string]$Cluster,    
        [String]$State
    
    )

    try {
        #Trace-AzsSupportCommand -Event OnEntry

        $clusterNodes = $null

        # If no cluster name is provided, attempt to get the cluster name
        if (!$PSBoundParameters['Cluster']) {
            $ClusterName = Get-AzsSupportClusterName 
        } else {
            #Ensure the cluster name is correct
            $ClusterName = Get-AzsSupportClusterName -Name $Cluster
        }

        # If no cluster name is found, return
        if ($null -eq $ClusterName) {
            Trace-Output -Level:Exception -Message ($msg.CommonClusterName)
            Return
        }

        if ($PSBoundParameters["Name"]) {
            $clusterNodes = (Get-ClusterNode -Name $Name -Cluster $ClusterName)
        }
        else {
            $clusterNodes = (Get-ClusterNode -Cluster $ClusterName)
        }

        if ($PSBoundParameters["State"]) {
            $clusterNodes = $clusterNodes | Where-Object { $_.State -eq $State.ToString() }
        }

        #Trace-AzsSupportCommand -Event OnExit
        return $clusterNodes
    }
    catch {
        #$formattedException = Get-FormattedException -Exception $_.Exception
        $_.Exception.Message | Trace-Output -Level:Exception
        #Trace-AzsSupportCommand -Event OnExit -Status Exception -StatusMessage $formattedException
    }
}

function Get-AzsSupportClusterName {
    <#
        .SYNOPSIS
            Gets the failover cluster name.
 
        .DESCRIPTION
            Gets the failover cluster name. If no cluster name is provided, it will attempt to get the cluster name.
 
        .PARAMETER Name
           Filter the results by the provided cluster name.
 
        .EXAMPLE
            PS> Get-AzsSupportClusterName -Name "contoso-cl"
 
        .OUTPUTS
            Output the Cluster name
             
            contoso-cl
        #>


    param(
        [parameter(mandatory = $false, HelpMessage = "Please provide Name of Cluster")]
        [string]$Name
    )

    try {
        #Trace-AzsSupportCommand -Event OnEntry


        # If no cluster name is provided, attempt to get the cluster name
        if (!$PSBoundParameters['Name']) {
            $Clustername = (Get-Cluster).Name
        }
        else {
            #Ensure the cluster name is correct
            $ClusterName = (Get-Cluster -Name $Name).Name
        }
        
        # If no cluster name is found, return
        if ($null -eq $ClusterName) {
            Trace-Output -Level:Exception -Message ($msg.StorageClusterName)
            Return
        }
        
        #Trace-AzsSupportCommand -Event OnExit
        return $clustername
    }
    catch {
        #$formattedException = Get-FormattedException -Exception $_.Exception
        $_.Exception.Message | Trace-Output -Level:Exception
        #Trace-AzsSupportCommand -Event OnExit -Status Exception -StatusMessage $formattedException
    }
}

function Test-AzsSupportClusterNode {
    <#
        .SYNOPSIS
            Checks if Node provided is a cluster node, returns true if it is, false if it is not.
 
        .PARAMETER NodeName
            Provide NodeName to test if it's cluster node.
 
        .EXAMPLE
            PS> Test-AzsSupportClusterNode -NodeName "contoso-n01"
 
        .OUTPUTS
            True if the node is a cluster node, false if it is not.
    #>


    param (
        [Parameter(Mandatory = $false)]
        [string]$NodeName = $env:COMPUTERNAME
    )

    try {
        #Trace-AzsSupportCommand -Event OnEntry

        $cluster = Get-Cluster -ErrorAction Stop
        $node = Get-ClusterNode -Cluster $cluster.Name -Name $NodeName -ErrorAction Stop
        if ($node) {
            Trace-Output -Level:Verbose -Message ("$($msg.CommonTestClusterNodeSucccess)" -f $NodeName)
            return $true
        }
        else {
            Trace-Output -Level:Verbose -Message ("$($msg.CommonTestClusterNodeFail)" -f $NodeName)
            return $false
        }

        #Trace-AzsSupportCommand -Event OnExit
    }
    catch {
        Trace-Output -Level:Verbose -Message ("$($msg.CommonTestClusterNodeError)" -f $NodeName)
        return $false
    }
}

function Get-AzsSupportService {
    <#
    .SYNOPSIS
        Gets services on a specified ComputerName, and sorts them by State, Name. Supports WMI, and WinRM.
 
    .PARAMETER ComputerName
        The remote computer you want to list services on.
 
    .PARAMETER Name
        Wildcard search for the provided name.
 
    .PARAMETER UseWinRM
        If specified, uses WinRM to get the services.
 
    .EXAMPLE
        PS> Get-AzsSupportService -ComputerName "contoso-n01" -Name "smphost" -UseWinRM
 
    .OUTPUTS
        Status ComputerName Name DisplayName
        ------ ------------ ---- -----------
        Running contoso-n01 smphost Microsoft Storage Spaces SMP
    #>


    [CmdletBinding(DefaultParameterSetName = "Default")]
    param(
        [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = "Default")]
        [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = "Named")]
        [Array]$ComputerName,

        [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = "Named")]
        [String]$Name,

        [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = "Default")]
        [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = "Named")]
        [Switch]$UseWinRM
    )

    try {
        #Trace-AzsSupportCommand -Event OnEntry

        if ([string]::IsNullOrEmpty($ComputerName)) {
            $ComputerName = $env:COMPUTERNAME
        }



        if ($UseWinRM) {
            $session = New-AzsSupportPSSession -ComputerName $ComputerName
            switch ($PSCmdlet.ParameterSetName) {
                "Named" {
                    $Services = Invoke-Command -Session $session -ScriptBlock {
                        return (Get-Service -Name "*$using:Name*" `
                            | Sort-Object -Property @{Expression = "Status"; Descending = $true }, @{Expression = "Name"; Descending = $false })
                    }

                    $results = foreach ($Service in $Services) {

                        New-Object -TypeName PSCustomObject -Property @{

                            Status       = $service.Status
                            Name         = $service.Name
                            DisplayName  = $service.DisplayName
                            ComputerName = $(Hostname)
                        }
                        break
                    }
                }
                default {
                    $Services = Invoke-Command -Session $session -ScriptBlock {
                        return (Get-Service `
                            | Sort-Object -Property @{Expression = "Status"; Descending = $true }, @{Expression = "Name"; Descending = $false })
                    }
                    $results = foreach ($Service in $Services) {

                        New-Object -TypeName PSCustomObject -Property @{

                            Status       = $service.Status
                            Name         = $service.Name
                            DisplayName  = $service.DisplayName
                            ComputerName = $(Hostname)
                        }
                        break
                    }
                }
            } #end UseWinRM
        }
        else {
            switch ($PSCmdlet.ParameterSetName) {
                "Named" {
                    $wmiServiceQuery = "SELECT * FROM Win32_Service WHERE Name LIKE '%{0}%' OR DisplayName LIKE '%{0}%' OR Description LIKE '%{0}%'" -f $Name
                    break
                }
                default {
                    $wmiServiceQuery = "SELECT * FROM Win32_Service"
                    break
                }
            }

            $wmiServiceQuery | Trace-Output -Level:Verbose

            # Get-Process does not return the command line
            $wmiW32_Services = Get-WmiObject -ComputerName $ComputerName -Query $wmiServiceQuery `
            | Sort-Object State, Name

            $results = foreach ($service in $wmiW32_Services) {

                New-Object -TypeName PSCustomObject -Property @{
                    State        = $service.State
                    Status       = $service.Status
                    Name         = $service.Name
                    ProcessId    = $service.ProcessId
                    DisplayName  = $service.DisplayName
                    ComputerName = $service.SystemName
                }

            }
        }

        #Trace-AzsSupportCommand -Event OnExit
        return $results
    }
    catch {
        #$formattedException = Get-FormattedException -Exception $_.Exception
        $_.Exception.Message | Trace-Output -Level:Exception
        #Trace-AzsSupportCommand -Event OnExit -Status Exception -StatusMessage $formattedException
    }
}

function Get-AzsSupportProcess {
    <#
    .SYNOPSIS
        Gets processes on a remote computer
 
    .DESCRIPTION
        Gets processes on a remote computer. Supports WMI, WinRM, and Tasklist /SVC
         
    .PARAMETER ComputerName
        The remote computer you want to list processes on.
 
    .PARAMETER Name.
        Wildcard search for the given name against both the Process Name and Process CommandLine args
 
    .PARAMETER ProcessId
        Process ID (PID) for a known process on the remote computer.
 
    .PARAMETER UseWinRM
        If specified, uses WinRM to get the processes.
 
    .PARAMETER UseTasklist
        If specified, uses Tasklist /SVC to get the processes.
 
    .EXAMPLE
        PS> Get-AzsSupportProcess -ComputerName "contoso-n01"
 
    .EXAMPLE
        PS> Get-AzsSupportProcess -ComputerName "contoso-n01" -Name "svchost"
 
    .EXAMPLE
        PS> Get-AzsSupportProcess -ComputerName "contoso-n01" -Name "svchost" -UseWinRM
 
    .EXAMPLE
        PS> Get-AzsSupportProcess -ComputerName "contoso-n01" -ProcessId 1234
 
    .EXAMPLE
        PS> Get-AzsSupportProcess -ComputerName "contoso-n01" -ProcessId 1234 -UseWinRM
 
    .EXAMPLE
        PS> Get-AzsSupportProcess -ComputerName "contoso-n01" -UseTasklist
 
    .OUTPUTS
        Get-AzsSupportProcess -ComputerName "contoso-n01" -Name "healthpih.exe" | Select-Object Name, ProcessId, StartTime, WorkingSetMB, HandleCount | Format-Table -AutoSize
 
        Name ProcessId StartTime WorkingSetMB HandleCount
        ---- --------- --------- ------------ -----------
        healthpih.exe 11692 2/21/2025 10:34:14 AM 49 MB 2319
 
    #>


    [CmdletBinding(DefaultParameterSetName = "Default")]
    param(
        [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = "Default")]
        [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = "Named")]
        [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = "PID")]
        [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = "Tasklist_SVC")]
        [String]$ComputerName,

        [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = "Named")]
        [String]$Name,

        [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = "PID")]
        [Int]$ProcessId,

        [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = "Default")]
        [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = "Named")]
        [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = "PID")]
        [Switch]$UseWinRM,

        [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = "Tasklist_SVC")]
        [Switch]$UseTasklist,

        [Parameter(Mandatory = $false, ValueFromPipeline = $false, ParameterSetName = "Default")]
        [Int]$Top
    )

    try {
        #Trace-AzsSupportCommand -Event OnEntry

        if ([string]::IsNullOrEmpty($ComputerName)) {
            $ComputerName = $env:COMPUTERNAME
        }



        if ($UseWinRM) {
            $session = New-AzsSupportPSSession -ComputerName $ComputerName
            $results = switch ($PSCmdlet.ParameterSetName) {

                "Named" {

                    $Processes = Invoke-Command -Session $session -ScriptBlock {
                        return (Get-Process -Name "*$using:Name*" -IncludeUserName)
                    }
                    foreach ($Proc in $Processes) {
                        New-Object -TypeName PSCustomObject -Property @{

                            StartTime    = $proc.StartTime
                            Name         = $proc.ProcessName
                            ProcessId    = $proc.Id
                            WorkingSet   = $proc.WorkingSet64
                            WorkingSetMB = ("{0} MB" -f [int]($proc.WorkingSet / 1MB))
                            HandleCount  = $proc.HandleCount
                            ThreadCount  = $proc.Threads.Count
                            ComputerName = $ComputerName
                        }
                    }


                    break

                }
                "PID" {
                    $Process = Invoke-Command -Session $session -ScriptBlock {
                        return (Get-Process -Name "*$using:ProcessId*" -IncludeUserName)
                    }

                    New-Object -TypeName PSCustomObject  @{

                        StartTime    = $proc.StartTime
                        Name         = $proc.ProcessName
                        ProcessId    = $proc.Id
                        WorkingSet   = $proc.WorkingSet64
                        WorkingSetMB = ("{0} MB" -f [int]($proc.WorkingSet / 1MB))
                        HandleCount  = $proc.HandleCount
                        ThreadCount  = $proc.Threads.Count
                        ComputerName = $ComputerName
                    }


                    break
                }
                default {
                    if ($PSBoundParameters['Top']) {


                        $Process = Invoke-Command -Session $session -ScriptBlock {
                            return (Get-Process -IncludeUserName | Sort-Object WorkingSet -Descending | Select-Object -First $using:Top)
                        }

                        New-Object -TypeName PSCustomObject @{

                            StartTime    = $proc.StartTime
                            Name         = $proc.ProcessName
                            ProcessId    = $proc.Id
                            WorkingSet   = $proc.WorkingSet64
                            WorkingSetMB = ("{0} MB" -f [int]($proc.WorkingSet / 1MB))
                            HandleCount  = $proc.HandleCount
                            ThreadCount  = $proc.Threads.Count
                            ComputerName = $ComputerName
                        }



                    }
                    else {


                        $process = Invoke-Command -Session $session -ScriptBlock {
                            return (Get-Process -IncludeUserName)
                        }


                        New-Object -TypeName PSCustomObject  @{

                            StartTime       = $process.CreationDate
                            Name            = $processName
                            ProcessId       = $process.ProcessId
                            ParentProcessId = $process.ParentProcessId
                            WorkingSet      = $process.WorkingSetSize
                            WorkingSetMB    = ("{0} MB" -f [int]($process.WorkingSet / 1MB))
                            HandleCount     = $process.HandleCount
                            ThreadCount     = $process.ThreadCount
                            CommandLine     = $commandLine
                            ComputerName    = $process.CSName
                        }


                    }

                    break
                }
            }


        } #end UseWinRM
        elseif ($UseTasklist) {
            $session = New-AzsSupportPSSession -ComputerName $ComputerName
            $results = New-Object -TypeName PSCustomObject @{
                Output = (
                    Invoke-Command -Session $session -ScriptBlock {
                        return (& tasklist /svc /FO CSV | ConvertFrom-Csv)
                    }
                )
            }
        }#end tasklist
        else {
            # We're using WMI
            switch ($PSCmdlet.ParameterSetName) {
                "Named" {
                    $wmiProcessQuery = "SELECT * FROM Win32_Process WHERE Name LIKE '%{0}%' OR CommandLine LIKE '%{0}%'" -f $Name
                    break
                }
                "PID" {
                    $wmiProcessQuery = "SELECT * FROM Win32_Process WHERE ProcessId = '{0}'" -f $ProcessId
                    break
                }
                default {
                    $wmiProcessQuery = "SELECT * FROM Win32_Process"
                    break
                }
            }
            Trace-Output -Level:Verbose -Message ($msg.CommonProcessRunning -f $ComputerName, $wmiProcessQuery)

            if ($PSBoundParameters['Top']) {
                $wmiW32_Processes = Get-WmiObject -ComputerName $ComputerName -Query $wmiProcessQuery `
                | Sort-Object WorkingSetSize -Descending | Select-Object -First $Top
            }
            else {
                # Get-Process does not return the command line
                $wmiW32_Processes = Get-WmiObject -ComputerName $ComputerName -Query $wmiProcessQuery
            }


            $Results = foreach ($process in $wmiW32_Processes) {

                $commandLine = [string]::Empty

                # Some process command line args are several thousand characters long
                if ($process.CommandLine.Length -gt 95) {
                    $commandLine = "Truncated due to length. Try: Get-WmiObject -Class Win32_Process -ComputerName '{0}' | Where-Object {{ `$_.ProcessId -eq {1} }} | Select-Object CommandLine" -f $ComputerName, $process.ProcessId
                }
                elseif (![string]::IsNullOrEmpty($process.CommandLine)) {
                    # Some of the command lines come back with \??\, so just removing that
                    $commandLine = $process.CommandLine.Replace("\??\", "")
                }

                $processName = $process.Name

                # Extracting the service name from svchost command line so we can do this all in powershell and not use tasklist /svc
                if ($process.Name -eq 'svchost.exe') {
                    if (![string]::IsNullOrEmpty($process.CommandLine)) {
                        if (!$process.CommandLine.EndsWith("-p")) {
                            $processName = "svchost.exe ({0})" -f $process.CommandLine.Split(" ")[-1]
                        }
                    }
                }

                # Creating custom return object as we are translating processname and command line properties
                New-Object -TypeName PSCustomObject -Property @{

                    StartTime       = $process.ConvertToDateTime($process.CreationDate)
                    Name            = $processName
                    ProcessId       = $process.ProcessId
                    ParentProcessId = $process.ParentProcessId
                    WorkingSet      = $process.WorkingSetSize
                    WorkingSetMB    = ("{0} MB" -f [int]($process.WorkingSetSize / 1MB))
                    HandleCount     = $process.HandleCount
                    ThreadCount     = $process.ThreadCount
                    CommandLine     = $commandLine
                    ComputerName    = $process.CSName
                }
            }
        }#end Wmi

        #Trace-AzsSupportCommand -Event OnExit
        if ($results.Count -eq 0) {
            Trace-Output -Level:Information -Message ($msg.CommonProcessNoneFound)
            return $null
        }


        return $results | Sort-Object Name, Id

    }
    catch {
        #$formattedException = Get-FormattedException -Exception $_.Exception
        $_.Exception.Message | Trace-Output -Level:Exception
        #Trace-AzsSupportCommand -Event OnExit -Status Exception -StatusMessage $formattedException
    }
}

function Get-AzsSupportStampInformation {
    <#
    .SYNOPSIS
        Gets common stamp information
 
    .DESCRIPTION
        Queries for common stamp information properties such as DeplymentID, OEMVersion and CloudID
     
    .EXAMPLE
        PS> Get-AzsSupportStampInformation
     
    .OUTPUTS
        Outputs the Stamp Information
 
    #>


    try {


        $StampInformationOutput = Get-StampInformation

        #Default information added for now and we can augment this as needed
        $StampInformation = [Ordered]@{
            #CompanyName =
            DeploymentID           = $StampInformationOutput.DeploymentID
            OemVersion             = $StampInformationOutput.OemVersion
            StampVersion           = $StampInformationOutput.StampVersion
            ServicesVersion        = $StampInformationOutput.ServicesVersion
            PlatformVersion        = $StampInformationOutput.PlatformVersion
            InitialDeployedVersion = $StampInformationOutput.InitialDeployedVersion
            NetworkSchemaVersion   = $StampInformationOutput.NetworkSchemaVersion
            Prefix                 = $StampInformationOutput.Prefix
            CompanyName            = $StampInformationOutput.CompanyName
            ServerSku              = $StampInformationOutput.ServerSku
            Topology               = $StampInformationOutput.Topology
            TimeZone               = $StampInformationOutput.TimeZone
            HardwareOEM            = $StampInformationOutput.HardwareOEM
            RegionName             = $StampInformationOutput.RegionName
            DomainNetBIOSName      = $StampInformationOutput.DomainNetBIOSName
            DomainFQDN             = $StampInformationOutput.DomainFQDN
            TimeServer             = $StampInformationOutput.TimeServer
            NumberOfNodes          = $StampInformationOutput.NumberOfNodes
            CloudID                = $StampInformationOutput.CloudID
            RingName               = $StampInformationOutput.RingName
            InstallationMethod     = $StampInformationOutput.InstallationMethod
            HardwareClass          = $StampInformationOutput.HardwareClass
        }
        
        Return $StampInformation
    }
    catch {

        #$formattedException = Get-FormattedException -Exception $_.Exception | Trace-Output -Level:Exception
        $_.Exception.Message | Trace-Output -Level:Exception
        #Trace-AzsSupportCommand -Event OnExit -Status Exception -StatusMessage $formattedException
    }
}

#region command aliases

Set-Alias -Name "Get-AzsSupportClusterNode" -Value "Get-AzsSupportInfrastructureHost" -Force
#endregion command aliases
# SIG # Begin signature block
# MIIoRgYJKoZIhvcNAQcCoIIoNzCCKDMCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCzDuwu/MulNXNK
# XjYTQSLGyMQSCwhD2Vy5HiGlxjcFD6CCDXYwggX0MIID3KADAgECAhMzAAAEBGx0
# Bv9XKydyAAAAAAQEMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
# bmcgUENBIDIwMTEwHhcNMjQwOTEyMjAxMTE0WhcNMjUwOTExMjAxMTE0WjB0MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQC0KDfaY50MDqsEGdlIzDHBd6CqIMRQWW9Af1LHDDTuFjfDsvna0nEuDSYJmNyz
# NB10jpbg0lhvkT1AzfX2TLITSXwS8D+mBzGCWMM/wTpciWBV/pbjSazbzoKvRrNo
# DV/u9omOM2Eawyo5JJJdNkM2d8qzkQ0bRuRd4HarmGunSouyb9NY7egWN5E5lUc3
# a2AROzAdHdYpObpCOdeAY2P5XqtJkk79aROpzw16wCjdSn8qMzCBzR7rvH2WVkvF
# HLIxZQET1yhPb6lRmpgBQNnzidHV2Ocxjc8wNiIDzgbDkmlx54QPfw7RwQi8p1fy
# 4byhBrTjv568x8NGv3gwb0RbAgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQU8huhNbETDU+ZWllL4DNMPCijEU4w
# RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW
# MBQGA1UEBRMNMjMwMDEyKzUwMjkyMzAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci
# tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG
# CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu
# Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0
# MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAIjmD9IpQVvfB1QehvpC
# Ge7QeTQkKQ7j3bmDMjwSqFL4ri6ae9IFTdpywn5smmtSIyKYDn3/nHtaEn0X1NBj
# L5oP0BjAy1sqxD+uy35B+V8wv5GrxhMDJP8l2QjLtH/UglSTIhLqyt8bUAqVfyfp
# h4COMRvwwjTvChtCnUXXACuCXYHWalOoc0OU2oGN+mPJIJJxaNQc1sjBsMbGIWv3
# cmgSHkCEmrMv7yaidpePt6V+yPMik+eXw3IfZ5eNOiNgL1rZzgSJfTnvUqiaEQ0X
# dG1HbkDv9fv6CTq6m4Ty3IzLiwGSXYxRIXTxT4TYs5VxHy2uFjFXWVSL0J2ARTYL
# E4Oyl1wXDF1PX4bxg1yDMfKPHcE1Ijic5lx1KdK1SkaEJdto4hd++05J9Bf9TAmi
# u6EK6C9Oe5vRadroJCK26uCUI4zIjL/qG7mswW+qT0CW0gnR9JHkXCWNbo8ccMk1
# sJatmRoSAifbgzaYbUz8+lv+IXy5GFuAmLnNbGjacB3IMGpa+lbFgih57/fIhamq
# 5VhxgaEmn/UjWyr+cPiAFWuTVIpfsOjbEAww75wURNM1Imp9NJKye1O24EspEHmb
# DmqCUcq7NqkOKIG4PVm3hDDED/WQpzJDkvu4FrIbvyTGVU01vKsg4UfcdiZ0fQ+/
# V0hf8yrtq9CkB8iIuk5bBxuPMIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq
# 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
# /Xmfwb1tbWrJUnMTDXpQzTGCGiYwghoiAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw
# EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
# aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp
# Z25pbmcgUENBIDIwMTECEzMAAAQEbHQG/1crJ3IAAAAABAQwDQYJYIZIAWUDBAIB
# BQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO
# MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIOc97gHnE/+cBoxoZv9UK4jC
# z5ld2zcHAQzF2VRWbk0aMEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A
# cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB
# BQAEggEAHwuJuu6D33sgnjcxxOC2+lFhc/a4zWTWwhGu8514vzdRENASJKCHiw9T
# SEr8yFlKomVCIvtN4zhMeC7d5UCmmmWFJSI2hNdaJhmcVPBSOPX9bwgNGHS8NBR+
# 7DzTrFfl9yz6U3CwrbSYRwAmdRNBY/aOyBpxK2bqK4HLGG2NBl3DIpBvhaxU0ZDR
# ApE6HGjF+AYLwoGcHNneIhtExlEtlEoxWfQMOGFwt1k7WS/J2iuvW6hWflnmeu0/
# wQ7zou0mTYTfWm77Dodkghlm3Gm8KIa63hknsh10l0njSA6eNFbxK9U4pysiXdyN
# 8qJ4dQQ/hUOLmO6rIenxtjJ0YKCQhaGCF7AwghesBgorBgEEAYI3AwMBMYIXnDCC
# F5gGCSqGSIb3DQEHAqCCF4kwgheFAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFaBgsq
# hkiG9w0BCRABBKCCAUkEggFFMIIBQQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl
# AwQCAQUABCDr0kUs7WBJn9G2S4fnq4yvQ/HiD/BYglBSbSsvK5EjuQIGZ7Y0ohbp
# GBMyMDI1MDIyNzEzNDQ1NC43OTZaMASAAgH0oIHZpIHWMIHTMQswCQYDVQQGEwJV
# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJl
# bGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVT
# TjoyQTFBLTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAg
# U2VydmljZaCCEf4wggcoMIIFEKADAgECAhMzAAAB+R9njXWrpPGxAAEAAAH5MA0G
# CSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9u
# MRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp
# b24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMB4XDTI0
# MDcyNTE4MzEwOVoXDTI1MTAyMjE4MzEwOVowgdMxCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9w
# ZXJhdGlvbnMgTGltaXRlZDEnMCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjJBMUEt
# MDVFMC1EOTQ3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNl
# MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtD1MH3yAHWHNVslC+CBT
# j/Mpd55LDPtQrhN7WeqFhReC9xKXSjobW1ZHzHU8V2BOJUiYg7fDJ2AxGVGyovUt
# gGZg2+GauFKk3ZjjsLSsqehYIsUQrgX+r/VATaW8/ONWy6lOyGZwZpxfV2EX4qAh
# 6mb2hadAuvdbRl1QK1tfBlR3fdeCBQG+ybz9JFZ45LN2ps8Nc1xr41N8Qi3KVJLY
# X0ibEbAkksR4bbszCzvY+vdSrjWyKAjR6YgYhaBaDxE2KDJ2sQRFFF/egCxKgogd
# F3VIJoCE/Wuy9MuEgypea1Hei7lFGvdLQZH5Jo2QR5uN8hiMc8Z47RRJuIWCOeyI
# J1YnRiiibpUZ72+wpv8LTov0yH6C5HR/D8+AT4vqtP57ITXsD9DPOob8tjtsefPc
# QJebUNiqyfyTL5j5/J+2d+GPCcXEYoeWZ+nrsZSfrd5DHM4ovCmD3lifgYnzjOry
# 4ghQT/cvmdHwFr6yJGphW/HG8GQd+cB4w7wGpOhHVJby44kGVK8MzY9s32Dy1THn
# Jg8p7y1sEGz/A1y84Zt6gIsITYaccHhBKp4cOVNrfoRVUx2G/0Tr7Dk3fpCU8u+5
# olqPPwKgZs57jl+lOrRVsX1AYEmAnyCyGrqRAzpGXyk1HvNIBpSNNuTBQk7FBvu+
# Ypi6A7S2V2Tj6lzYWVBvuGECAwEAAaOCAUkwggFFMB0GA1UdDgQWBBSJ7aO6nJXJ
# I9eijzS5QkR2RlngADAfBgNVHSMEGDAWgBSfpxVdAF5iXYP05dJlpxtTNRnpcjBf
# BgNVHR8EWDBWMFSgUqBQhk5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3Bz
# L2NybC9NaWNyb3NvZnQlMjBUaW1lLVN0YW1wJTIwUENBJTIwMjAxMCgxKS5jcmww
# bAYIKwYBBQUHAQEEYDBeMFwGCCsGAQUFBzAChlBodHRwOi8vd3d3Lm1pY3Jvc29m
# dC5jb20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0El
# MjAyMDEwKDEpLmNydDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUF
# BwMIMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAgEAZiAJgFbkf7jf
# hx/mmZlnGZrpae+HGpxWxs8I79vUb8GQou50M1ns7iwG2CcdoXaq7VgpVkNf1uvI
# hrGYpKCBXQ+SaJ2O0BvwuJR7UsgTaKN0j/yf3fpHD0ktH+EkEuGXs9DBLyt71iut
# Vkwow9iQmSk4oIK8S8ArNGpSOzeuu9TdJjBjsasmuJ+2q5TjmrgEKyPe3TApAio8
# cdw/b1cBAmjtI7tpNYV5PyRI3K1NhuDgfEj5kynGF/uizP1NuHSxF/V1ks/2tCEo
# riicM4k1PJTTA0TCjNbkpmBcsAMlxTzBnWsqnBCt9d+Ud9Va3Iw9Bs4ccrkgBjLt
# g3vYGYar615ofYtU+dup+LuU0d2wBDEG1nhSWHaO+u2y6Si3AaNINt/pOMKU6l4A
# W0uDWUH39OHH3EqFHtTssZXaDOjtyRgbqMGmkf8KI3qIVBZJ2XQpnhEuRbh+Agpm
# Rn/a410Dk7VtPg2uC422WLC8H8IVk/FeoiSS4vFodhncFetJ0ZK36wxAa3FiPgBe
# bRWyVtZ763qDDzxDb0mB6HL9HEfTbN+4oHCkZa1HKl8B0s8RiFBMf/W7+O7EPZ+w
# MH8wdkjZ7SbsddtdRgRARqR8IFPWurQ+sn7ftEifaojzuCEahSAcq86yjwQeTPN9
# YG9b34RTurnkpD+wPGTB1WccMpsLlM0wggdxMIIFWaADAgECAhMzAAAAFcXna54C
# m0mZAAAAAAAVMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UE
# CBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9z
# b2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZp
# Y2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0yMTA5MzAxODIyMjVaFw0zMDA5MzAxODMy
# MjVaMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQH
# EwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNV
# BAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMIICIjANBgkqhkiG9w0B
# AQEFAAOCAg8AMIICCgKCAgEA5OGmTOe0ciELeaLL1yR5vQ7VgtP97pwHB9KpbE51
# yMo1V/YBf2xK4OK9uT4XYDP/XE/HZveVU3Fa4n5KWv64NmeFRiMMtY0Tz3cywBAY
# 6GB9alKDRLemjkZrBxTzxXb1hlDcwUTIcVxRMTegCjhuje3XD9gmU3w5YQJ6xKr9
# cmmvHaus9ja+NSZk2pg7uhp7M62AW36MEBydUv626GIl3GoPz130/o5Tz9bshVZN
# 7928jaTjkY+yOSxRnOlwaQ3KNi1wjjHINSi947SHJMPgyY9+tVSP3PoFVZhtaDua
# Rr3tpK56KTesy+uDRedGbsoy1cCGMFxPLOJiss254o2I5JasAUq7vnGpF1tnYN74
# kpEeHT39IM9zfUGaRnXNxF803RKJ1v2lIH1+/NmeRd+2ci/bfV+AutuqfjbsNkz2
# K26oElHovwUDo9Fzpk03dJQcNIIP8BDyt0cY7afomXw/TNuvXsLz1dhzPUNOwTM5
# TI4CvEJoLhDqhFFG4tG9ahhaYQFzymeiXtcodgLiMxhy16cg8ML6EgrXY28MyTZk
# i1ugpoMhXV8wdJGUlNi5UPkLiWHzNgY1GIRH29wb0f2y1BzFa/ZcUlFdEtsluq9Q
# BXpsxREdcu+N+VLEhReTwDwV2xo3xwgVGD94q0W29R6HXtqPnhZyacaue7e3Pmri
# Lq0CAwEAAaOCAd0wggHZMBIGCSsGAQQBgjcVAQQFAgMBAAEwIwYJKwYBBAGCNxUC
# BBYEFCqnUv5kxJq+gpE8RjUpzxD/LwTuMB0GA1UdDgQWBBSfpxVdAF5iXYP05dJl
# pxtTNRnpcjBcBgNVHSAEVTBTMFEGDCsGAQQBgjdMg30BATBBMD8GCCsGAQUFBwIB
# FjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9y
# eS5odG0wEwYDVR0lBAwwCgYIKwYBBQUHAwgwGQYJKwYBBAGCNxQCBAweCgBTAHUA
# YgBDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU
# 1fZWy4/oolxiaNE9lJBb186aGMQwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDovL2Ny
# bC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0XzIw
# MTAtMDYtMjMuY3JsMFoGCCsGAQUFBwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0cDov
# L3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXRfMjAxMC0w
# Ni0yMy5jcnQwDQYJKoZIhvcNAQELBQADggIBAJ1VffwqreEsH2cBMSRb4Z5yS/yp
# b+pcFLY+TkdkeLEGk5c9MTO1OdfCcTY/2mRsfNB1OW27DzHkwo/7bNGhlBgi7ulm
# ZzpTTd2YurYeeNg2LpypglYAA7AFvonoaeC6Ce5732pvvinLbtg/SHUB2RjebYIM
# 9W0jVOR4U3UkV7ndn/OOPcbzaN9l9qRWqveVtihVJ9AkvUCgvxm2EhIRXT0n4ECW
# OKz3+SmJw7wXsFSFQrP8DJ6LGYnn8AtqgcKBGUIZUnWKNsIdw2FzLixre24/LAl4
# FOmRsqlb30mjdAy87JGA0j3mSj5mO0+7hvoyGtmW9I/2kQH2zsZ0/fZMcm8Qq3Uw
# xTSwethQ/gpY3UA8x1RtnWN0SCyxTkctwRQEcb9k+SS+c23Kjgm9swFXSVRk2XPX
# fx5bRAGOWhmRaw2fpCjcZxkoJLo4S5pu+yFUa2pFEUep8beuyOiJXk+d0tBMdrVX
# VAmxaQFEfnyhYWxz/gq77EFmPWn9y8FBSX5+k77L+DvktxW/tM4+pTFRhLy/AsGC
# onsXHRWJjXD+57XQKBqJC4822rpM+Zv/Cuk0+CQ1ZyvgDbjmjJnW4SLq8CdCPSWU
# 5nR0W2rRnj7tfqAxM328y+l7vzhwRNGQ8cirOoo6CGJ/2XBjU02N7oJtpQUQwXEG
# ahC0HVUzWLOhcGbyoYIDWTCCAkECAQEwggEBoYHZpIHWMIHTMQswCQYDVQQGEwJV
# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJl
# bGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVT
# TjoyQTFBLTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAg
# U2VydmljZaIjCgEBMAcGBSsOAwIaAxUAqs5WjWO7zVAKmIcdwhqgZvyp6UaggYMw
# gYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYD
# VQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQsF
# AAIFAOtqlbswIhgPMjAyNTAyMjcwNzQxNDdaGA8yMDI1MDIyODA3NDE0N1owdzA9
# BgorBgEEAYRZCgQBMS8wLTAKAgUA62qVuwIBADAKAgEAAgIEHgIB/zAHAgEAAgIa
# GDAKAgUA62vnOwIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAow
# CAIBAAIDB6EgoQowCAIBAAIDAYagMA0GCSqGSIb3DQEBCwUAA4IBAQBX1bOXCkIk
# Lk71DI3gLVaZuEhXlyaipx8hS1GiDEUZcmu4tgo443hqor6alVz/PO8Qh293W7uN
# 6+Izt8soAurgCEGFut+dRSqvo1RYuKeoUTf/9TZzRocL8lHrWqcw7op575WDLB/t
# GjFSS9L4ZnjyC6Rbi+krE9KgxJ4Axox5Sa7PBK3UnXpym31KhDnSbJ/gnV7G8/rC
# GKn3MlUb7DJ/SoJg7srCFGDNIGlwhzMrutizgvmU4/9qJd5BANwi0H3aogk/EMs/
# U4KJYalW/YumLSPJWTRkRuI53B0++wNtCgIxmAlKPqsmcPpBkbOMRW1dFmPcgiS9
# /fZSvWuNdebxMYIEDTCCBAkCAQEwgZMwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgT
# Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m
# dCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENB
# IDIwMTACEzMAAAH5H2eNdauk8bEAAQAAAfkwDQYJYIZIAWUDBAIBBQCgggFKMBoG
# CSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0BCQQxIgQgUiVCuJi4
# 2PTUC9T1h4I/6jAY4aiIjhr6NWTWYTdk8gswgfoGCyqGSIb3DQEJEAIvMYHqMIHn
# MIHkMIG9BCA5I4zIHvCN+2T66RUOLCZrUEVdoKlKl8VeCO5SbGLYEDCBmDCBgKR+
# MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS
# ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMT
# HU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAAB+R9njXWrpPGxAAEA
# AAH5MCIEIFfece0BVPMrtrtZYM+GRvwAQ+35A+kg0kIeD9ykfP5VMA0GCSqGSIb3
# DQEBCwUABIICABxjyqoFqbyA14jRO//oUwnuVmYmnhoF9rhOkvHVy6Kz4NW6WB6q
# feC+H+4NrhO5klDlsrQvcQZDiUq9htfAcCi4pBDMgq7LvLIUTjPJzdCPz4o/poL/
# JJRgiY86IUY5uyH3z0vXXlbex6TmhGGhEDwzBeGrbFsdfaMjcManVDIcu1TFRjrB
# FNhyY+ZM8Q3cuslAQWz6Bl9K3ntTrNGHMtCexkayi9i6L2P83F1zrLtY0gOkhRen
# xNfENefsaL6dO9U49n18y0gLxGH2lm6kfYx6E/n6Z0+QGbu3zZX6HBlHmUOSWUBX
# YaRa0gFRyZA5fpvj4NkyK5CJ/q/3YMy5HLLTerNhnsxLBRx7Y5c9jB7wletWKWBr
# mdR5GvyU30D0hU7EMzx158QtoPu2TjkKdrJmaphsc2eFK5cZ40q5HNsd3a/AjDD4
# eOmS1xKfBDfg+0uZnp8FerfWVDW10XwNXMsOGXZtmDZgiBhjHJjrjSGE/OKtwDcV
# H3ulg+79gUSnQLwuVgVXBRtVaJ62/kuAsc+5ECdKsKmgTf4kQLguNyxe9MkmomkA
# Jx6JYa8EQkhfObX24VqYf2SjjKdrxJ0O6GF7sA1TeVWOWRvouWXxPd/yIri58KS8
# 2nO8JJK25ECnl39Ss8svIciigvggYJqQ3/HsNpk/Vq+00kq2Zr4zKrG4
# SIG # End signature block