modules/AzStack.Utilities/AzStack.Utilities.psm1

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


Using module .\AzStack.Utilities.Helper.psm1
Import-Module $PSScriptRoot\AzStack.Utilities.Helper.psm1

Import-LocalizedData -BindingVariable 'msg' -BaseDirectory "$PSScriptRoot\locale" -UICulture "en-US"

# due to issue with how snap-ins work with JEA endpoints
# need to remove it, then re-import the Microsoft.PowerShell.Utility module so we can expose the functions such as Import-PowerShellDataFile
if (Get-PSSnapin | Where-Object { $_.Name -eq 'Microsoft.PowerShell.Utility' }) {
    Remove-PSSnapin -Name Microsoft.PowerShell.Utility
}

Import-Module Microsoft.PowerShell.Utility


<#
  ┌──────────────────────────────────────────────────────────────────────────┐
  │ Here our HCI helper functions start. │
  └──────────────────────────────────────────────────────────────────────────┘
 #>


function Trace-CheckResult() {
    param (
        [string] $checkName,
        [CheckStatus] $checkState,
        [string] $desc,
        [string] $details,
        [string] $url
    )

    $color = [ConsoleColor]::DarkBlue

    # we now support different states (besides pass / fail)
    switch ($checkState) {
        ([CheckStatus]::Pass) { $color = [ConsoleColor]::Green; $details = "Validation successfull" }
        ([CheckStatus]::Fail) { $color = [ConsoleColor]::Red }
        ([CheckStatus]::Info) { $color = [ConsoleColor]::Gray }
        Default {}
    }


    Write-Host -NoNewline   ("[" + $checkState + "] ")  -ForegroundColor $color
    Write-Host              ("[" + $checkName + "]")    -ForegroundColor Gray
    Write-Host              $desc                       -ForegroundColor White
    Write-Host -NoNewline   "Details: "                 -ForegroundColor Gray
    Write-Host              $details                    -ForegroundColor White
    # we only post the URL when it is specified. Some error messages dont have public docs.
    if(($null -ne $url) -and ($url -ne "")) {
        Write-Host -NoNewline "Documentation: "             -ForegroundColor Gray
        Write-Host              $url                        -ForegroundColor Yellow
    }
    Write-Host # Blank line for spacing.
}

<#
  ┌──────────────────────────────────────────────────────────────────────────┐
  │ THIS HAS BEEN PORTED OVER FROM HUB. WE DONT KNOW WHAT WE TRULY NEED. TO │
  │ BE CLEANED UP IN THE │
  │ FUTURE │
  └──────────────────────────────────────────────────────────────────────────┘
 #>

# create a script variable that is accessible to all the functions within the AzStack.Utilities.psm1 module
# this can be used to store configuration type data, only available within the script scope
$configurationData = Import-PowerShellDataFile -Path "$PSScriptRoot\AzStack.Utilities.Config.psd1"
New-Variable -Name 'AzsSupport_Utilities' -Scope Local -Force -Value @{
    Cache  = @{
        FilesExcludedFromCleanup = @()
        TraceFilePath            = $null
        WorkingDirectory         = $null
    }
    Config = $configurationData
}
function New-WorkingDirectory {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $false)]
        [System.String]$Path = $script:AzsSupport_Utilities.Config.WorkingDirectory
    )

    try {
        # create the working directory and set the global cache
        if (-NOT (Test-Path -Path $Path -PathType Container)) {
            $null = New-Item -Path $Path -ItemType Directory -Force
        }

        # create the trace file
        New-TraceOutputFile
    }
    catch {
        "{0}`n{1}" -f $_.Exception, $_.ScriptStackTrace | Trace-Output -Level:Error
    }
}

function Get-FormattedDateTimeUTC {
    param (
        [Switch]$NoSpace
    )

    if ($NoSpace) {
        return ([DateTime]::UtcNow.ToString('yyyyMMddHHmmss'))
    }

    return ([DateTime]::UtcNow.ToString('yyyyMMdd-HHmmss'))
}

# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
function Get-TraceOutputFile {
    return [System.String]$script:AzsSupport_Utilities.Config.TraceFilePath
}

function Get-AzsSupportTraceEvent {
    <#
    .SYNOPSIS
        Gets the trace events from Get-AzsSupportTraceFilePath.
    .PARAMETER FunctionName
        The function name that you want to filter on
    .PARAMETER Level
        The log level you want to filter on
    .PARAMETER IncludeDebugEvents
        Return debug level events from trace file
    .EXAMPLE
        Get-AzsSupportTraceEvent -FunctionName 'New-AzsSupportTraceFilePath' -Level Verbose
    #>


    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $false)]
        [ArgumentCompleter({
                param($commandName, $parameterName, $wordToComplete, $commandAst, $FakeboundParameter)
                $possibleValues = (Import-Csv -Path (Get-TraceOutputFile)).FunctionName | Select-Object -Unique | Sort-Object
                $possibleValues | Where-Object { $_ -like "$wordToComplete*" }
            })]
        [string]$FunctionName,

        [Parameter(Mandatory = $false)]
        [ArgumentCompleter({
                param($commandName, $parameterName, $wordToComplete, $commandAst, $FakeboundParameter)
                $possibleValues = (Import-Csv -Path (Get-TraceOutputFile)).Level | Select-Object -Unique | Sort-Object
                $possibleValues | Where-Object { $_ -like "$wordToComplete*" }
            })]
        [string]$Level,

        [Parameter(Mandatory = $false)]
        [switch]$IncludeDebugEvents
    )

    try {

        $traceEvents = Import-Csv -Path (Get-TraceOutputFile)


        if ($PSBoundParameters['FunctionName']) {
            $traceEvents = $traceEvents | Where-Object { $_.FunctionName -eq $FunctionName }
        }

        if ($PSBoundParameters['Level']) {
            $traceEvents = $traceEvents  | Where-Object { $_.Level -eq $Level }
        }

        if (!$IncludeDebugEvents) {
            $traceEvents = $traceEvents | Where-Object { $_.Level -ne 'Debug' }
        }


        return $traceEvents
    }
    catch {
        "{0}`n{1}" -f $_.Exception, $_.ScriptStackTrace | Trace-Output -Level:Error
    }
}

function Get-FormattedException {
    <#
    .SYNOPSIS
        Extracts details from an exception that is used to format the error message in a consistent manner.
        Does not capture the exception message as this might contain PII
 
    .PARAMETER Exception
        An exception thrown by the CLR or with the throw keyword
 
    .EXAMPLE
        PS> try {
                10 / 0
            }
            catch {
                Get-FormattedException -Exception $_.Exception | Write-Host -ForegroundColor Red
            }
    .NOTES
        We return compressed json as this information sent to the telemetry endpoint if customer has it enabled
    #>

    param(
        [System.Exception]$Exception
    )
    $outerTypeName = $null
    $innerTypeName = $null

    if ($null -ne $Exception) {
        $outerTypeName = ($Exception | Get-Member)[0].TypeName
    }

    if ($null -ne $Exception.InnerException) {
        $innerTypeName = ($Exception.InnerException | Get-Member)[0].TypeName
    }

    return (@{
            ErrorRecord    = @{
                ScriptStackTrace = $Exception.ErrorRecord.ScriptStackTrace
                InvocationInfo   = $Exception.ErrorRecord.InvocationInfo
            }
            OuterException = @{
                TypeName   = $outerTypeName
                Source     = $Exception.Source
                StackTrace = $Exception.StackTrace
            }
            InnerException = @{
                TypeName   = $innerTypeName
                Source     = $Exception.InnerException.Source
                StackTrace = $Exception.InnerException.StackTrace
            }
        }) | ConvertTo-Json -Depth 3 -Compress
}

function Trace-Output {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [System.String]$Message,

        [Parameter(Mandatory = $false)]
        [TraceLevel]$Level
    )

    begin {
        if (!$PSBoundParameters.ContainsKey('Level')) {
            $Level = [TraceLevel]::Information
        }

        $traceFile = (Get-TraceOutputFile)
        if ([string]::IsNullOrEmpty($traceFile)) {
            New-WorkingDirectory

            $traceFile = (Get-TraceOutputFile)
        }
    }
    process {
        # create custom object for formatting purposes
        $traceEvent = [PSCustomObject]@{
            Computer     = $env:COMPUTERNAME.ToUpper().ToString()
            TimestampUtc = [DateTime]::UtcNow.ToString('yyyy-MM-dd HH-mm-ss')
            FunctionName = (Get-PSCallStack)[1].Command
            Level        = $Level.ToString()
            Message      = $Message
        }

        # write the message to the console
        switch ($Level) {
            'Error' {
                "{0}" -f $traceEvent.Message | Write-Error
            }

            'Exception' {
                "{0}" -f $traceEvent.Message | Write-Host -ForegroundColor:Red
            }

            'Success' {
                "{0}" -f $traceEvent.Message | Write-Host -ForegroundColor:Green
            }

            'Verbose' {
                if ($VerbosePreference -ne [System.Management.Automation.ActionPreference]::SilentlyContinue) {
                    "{0}" -f $traceEvent.Message | Write-Verbose
                }
            }

            'Warning' {
                "{0}" -f $traceEvent.Message | Write-Warning
            }

            'Important' {
                "====[ {0} ]====" -f $traceEvent.Message | Write-Host -ForegroundColor:White -BackgroundColor:DarkGray
            }

            'Detail' {
                "{0}" -f $traceEvent.Message | Write-Host -ForegroundColor:White
            }

            'Unknown' {
                "{0}" -f $traceEvent.Message | Write-Host -ForegroundColor:DarkGray
            }

            default {
                "{0}" -f $traceEvent.Message | Write-Host -ForegroundColor:DarkCyan
            }
        }

        # write the event to trace file to be used for debugging purposes
        $mutexInstance = Wait-OnMutex -MutexId 'AzsSupport_TraceLogging' -ErrorAction Continue
        if ($mutexInstance) {
            $traceEvent | Export-Csv -Append -NoTypeInformation -Path $traceFile
        }
    }
    end {
        if ($mutexInstance) {
            $mutexInstance.ReleaseMutex()
        }
    }
}

function Wait-OnMutex {
    param (
        [Parameter(Mandatory = $true)]
        [System.String]$MutexId
    )

    try {
        $MutexInstance = New-Object System.Threading.Mutex($false, $MutexId)
        if ($MutexInstance.WaitOne(3000)) {
            return $MutexInstance
        }
        else {
            throw New-Object -TypeName System.TimeoutException($msg.TimeoutException)
        }
    }

    catch [System.Threading.AbandonedMutexException] {
        $MutexInstance = New-Object System.Threading.Mutex($false, $MutexId)
        return (Wait-OnMutex -MutexId $MutexId)
    }
    catch {
        $MutexInstance.ReleaseMutex()
        $_ | Write-Error
    }
}

function Get-WorkingDirectory {
    # check to see if the working directory has been configured into cache
    # otherwise set the cache based on what we have defined within our configuration file
    if ([String]::IsNullOrEmpty($script:AzsSupport_Utilities.Cache.WorkingDirectory)) {
        $script:AzsSupport_Utilities.Cache.WorkingDirectory = ($script:AzsSupport_Utilities.Config.WorkingDirectory -f (Get-FormattedDateTimeUTC -NoSpace))
    }

    return [System.String]$script:AzsSupport_Utilities.Cache.WorkingDirectory
}

function Get-AzsSupportWorkingDirectory {
    return (Get-WorkingDirectory)
}

function New-TraceOutputFile {
    try {
        # make sure that directory path exists, else create the folder structure required
        $workingDir = Get-WorkingDirectory
        if (-NOT (Test-Path -Path $workingDir -PathType Container)) {
            $null = New-Item -Path $workingDir -ItemType Directory -Force
        }

        # build the trace file path and set global variable
        [System.String]$fileName = "AzsSupport_TraceOutput_{0}.csv" -f (Get-Date).ToString('yyyyMMdd')
        [System.IO.FileInfo]$filePath = Join-Path -Path $workingDir -ChildPath $fileName
        Set-TraceOutputFile -Path $filePath.FullName

        # configure the cache to not cleanup the trace file
        $script:AzsSupport_Utilities.Cache.FilesExcludedFromCleanup += $filePath.Name

        "TraceFile: {0}" -f $filePath.FullName | Trace-Output -Level:Verbose
    }
    catch {
        $_.Exception | Write-Error
    }
}

function Get-TraceOutputFile {
    return [System.String]$script:AzsSupport_Utilities.Cache.TraceFilePath
}

function Set-TraceOutputFile {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [System.String]$Path
    )

    $script:AzsSupport_Utilities.Cache.TraceFilePath = $Path
}

function Convert-FileSystemPathToUNC {
    <#
    .SYNOPSIS
        Converts a local file path to a computer specific admin UNC path, such as C:\temp\myfile.txt to \\$COMPUTERNAME\c$\temp\myfile.txt
    .PARAMETER ComputerName
        The computer name to inject into the unc path
    .PARAMETER Path
        The local file system path, such as C:\temp\myfile.txt
    #>

    param(
        [String]$ComputerName,
        [String]$Path
    )

    $newPath = $path.Replace((Split-Path $Path), (Split-Path $Path).Replace(':', '$'))
    return ("\\{0}\{1}" -f $ComputerName, $newPath)
}

function Get-UserInputValues {
    <#
    .SYNOPSIS
        Used to capture information from user and generate a psobject
    .PARAMETER Properties
        The psobject properties you want to prompt user to provide
    .EXAMPLE
        PS> $results = Get-UserInputValues -Properties "Destination,Port,RetryAttempts"
 
        Destination: microsoft.com
        Port: 80
        RetryAttempts: 3
 
        PS> $results
 
        Destination Port RetryAttempts
        ----------- ---- -------------
        microsoft.com 80 3
    #>


    param (
        [Parameter(Mandatory = $true)]
        [string]$Properties
    )

    $object = foreach ($property in ($Properties.Split(','))) {
        $property = $property.Trim()
        New-Object -TypeName PSCustomObject -Property @{
            $($property) = (Get-UserInput -Message "$($property): ").Trim()
        }
    }

    return $object
}

function Clear-AzsSupportDirectory {
    <#
    .SYNOPSIS
        Clears the contents of the directory
    .PARAMETER ComputerName
        Type the NetBIOS name, an IP address, or a fully qualified domain name of one or more remote computers.
    .PARAMETER Credential
        Specifies a user account that has permission to perform this action. The default is the current user.
        Type a user name, such as User01 or Domain01\User01, or enter a PSCredential object generated by the Get-Credential cmdlet. If you type a user name, you're prompted to enter the password.
    .PARAMETER Path
        Specifies a path of the items being removed. Wildcard characters are permitted. If ommitted, defaults to (Get-WorkingDirectory).
    .PARAMETER Recurse
        Indicates that this cmdlet deletes the items in the specified locations and in all child items of the locations.
    .PARAMETER Force
        Forces the cmdlet to remove items that cannot otherwise be changed, such as hidden or read-only files or read-only aliases or variables.
    .EXAMPLE
        PS> Clear-AzsSupportDirectory
    .EXAMPLE
        PS> Clear-AzsSupportDirectory -ComputerName PREFIX-NC01 -Path 'C:\Temp\SDN2'
    .EXAMPLE
        PS> Clear-AzsSupportDirectory -ComputerName PREFIX-NC01,PREFIX-SLB01 -Credential (Get-Credential)
    .EXAMPLE
        PS> Clear-AzsSupportDirectory -Force -Recurse
    .EXAMPLE
        PS> Clear-AzsSupportDirectory -Path 'C:\Temp\Azs.Support\Path1','C:\Temp\Azs.Support\Path2' -Force -Recurse
    #>


    [CmdletBinding(DefaultParameterSetName = 'Local')]
    param (
        [Parameter(Mandatory = $false, ParameterSetName = 'Remote')]
        [System.String[]]$ComputerName,

        [Parameter(Mandatory = $false, ParameterSetName = 'Remote')]
        [System.Management.Automation.PSCredential]
        [System.Management.Automation.Credential()]
        $Credential = [System.Management.Automation.PSCredential]::Empty,

        [Parameter(Mandatory = $false, ParameterSetName = 'Remote')]
        [Parameter(Mandatory = $false, ParameterSetName = 'Local')]
        [System.String[]]$Path = (Get-WorkingDirectory),

        [Parameter(Mandatory = $false, ParameterSetName = 'Remote')]
        [Parameter(Mandatory = $false, ParameterSetName = 'Local')]
        [Switch]$Recurse,

        [Parameter(Mandatory = $false, ParameterSetName = 'Remote')]
        [Parameter(Mandatory = $false, ParameterSetName = 'Local')]
        [Switch]$Force
    )

    function Clear-WorkingDirectory {
        [CmdletBinding()]
        param (
            [System.String[]]$Path,
            [bool]$Recurse,
            [bool]$Force
        )

        $filteredPaths = @()
        foreach ($obj in $Path) {

            # if the path does not exist, lets skip
            if (-NOT (Test-Path -Path $obj)) {
                continue
            }

            # enumerate through the allowed folder paths for cleanup to make sure the paths specified can be cleaned up
            foreach ($allowedFolderPath in $Script:AzsSupport_Utilities.Config.FolderPathsAllowedForCleanup) {
                if ($obj -ilike $allowedFolderPath) {
                    $filteredPaths += $obj
                }
            }
        }

        if ($filteredPaths) {
            $msg.FileSystemRemove -f ($filteredPaths -join ', ') | Trace-Output -Level:Verbose
            Remove-Item -Path $filteredPaths -Exclude $Script:AzsSupport_Utilities.Cache.FilesExcludedFromCleanup -Force:$Force -Recurse:$Recurse -ErrorAction Continue
        }
    }

    $params = @{
        Path    = $Path
        Recurse = $Recurse.IsPresent
        Force   = $Force.IsPresent
    }

    try {
        if ($PSCmdlet.ParameterSetName -eq 'Remote') {
            Invoke-PSRemoteCommand -ComputerName $ComputerName -Credential $Credential -ScriptBlock {
                param([Parameter(Position = 1)]$Path, [Parameter(Position = 2)]$Recurse, [Parameter(Position = 3)]$Force)
                Clear-SdnWorkingDirectory -Path $Path -Recurse:$Recurse -Force:$Force
            } -ArgumentList @($params.Path, $params.Recurse, $params.Force)
        }
        else {
            Clear-WorkingDirectory @params
        }
    }
    catch {
        "{0}`n{1}" -f $_.Exception, $_.ScriptStackTrace | Trace-Output -Level:Error
    }
}

function Test-Is23H2Version() {
    if(($null -ne $Global:AzsSupport.EnvironmentInfo) -AND ($Global:AzsSupport.EnvironmentInfo.WindowsProductName -eq "Azure Stack HCI") -AND ($Global:AzsSupport.EnvironmentInfo.OSDisplayVersion -eq "23H2")) {
        return $true
    } else {
        return $false
    }
}
# SIG # Begin signature block
# MIIoRgYJKoZIhvcNAQcCoIIoNzCCKDMCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCyU9xXixEV4XAh
# spYnWhwvG7nkRK44iivFJVJPMYDgKKCCDXYwggX0MIID3KADAgECAhMzAAAEBGx0
# 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
# MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIIAyQuSiUyuWhP+z1ykwDBRv
# xp74c2RUhvKQ3tutm19jMEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A
# cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB
# BQAEggEAQxddt8WXvnRSe6JurHXOjQoRLmxSpDPlzscCX9ZUz10WxyK1pR5TBaqf
# Qt7wQRUIJqXFLx/uxlSCNboCoyyROiCA6c+PC48KMNMsGNU94MXDGx0Fd5sh8LAc
# YeCpbqj5iw2Gq48DX7entsxOytC0if2Faum+HZa37yPkWa/q7cdmMXCirXqJgQNl
# yOOtA9P+mNIqu56SoCF2E8Z6S0GdXpzLaBtO8sdtYh4zfthrDuSfVDyzbYsHDe9V
# wzbFl5nqZ34q6SojoafJydwGlmaCN58fkv3fBqEOwSXuyCSEKN4FI2+lxAVrk+HA
# ZQTi8NbCpxKb4JGysydjbWGmjJxHnaGCF7AwghesBgorBgEEAYI3AwMBMYIXnDCC
# F5gGCSqGSIb3DQEHAqCCF4kwgheFAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFaBgsq
# hkiG9w0BCRABBKCCAUkEggFFMIIBQQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl
# AwQCAQUABCCu1XTPfUoZaHGF22S+Tx/dMgLPopNWWZMoMaWs6cS1fAIGZusqy3G+
# GBMyMDI0MTExNTEwMTQ0OC4xMjdaMASAAgH0oIHZpIHWMIHTMQswCQYDVQQGEwJV
# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJl
# bGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVT
# TjozMjFBLTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAg
# U2VydmljZaCCEf4wggcoMIIFEKADAgECAhMzAAAB+KOhJgwMQEj+AAEAAAH4MA0G
# CSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9u
# MRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp
# b24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMB4XDTI0
# MDcyNTE4MzEwOFoXDTI1MTAyMjE4MzEwOFowgdMxCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9w
# ZXJhdGlvbnMgTGltaXRlZDEnMCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjMyMUEt
# MDVFMC1EOTQ3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNl
# MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxR23pXYnD2BuODdeXs2C
# u/T5kKI+bAw8cbtN50Cm/FArjXyL4RTqMe6laQ/CqeMTxgckvZr1JrW0Mi4F15rx
# /VveGhKBmob45DmOcV5xyx7h9Tk59NAl5PNMAWKAIWf270SWAAWxQbpVIhhPWCnV
# V3otVvahEad8pMmoSXrT5Z7Nk1RnB70A2bq9Hk8wIeC3vBuxEX2E8X50IgAHsyaR
# 9roFq3ErzUEHlS8YnSq33ui5uBcrFOcFOCZILuVFVTgEqSrX4UiX0etqi7jUtKyp
# gIflaZcV5cI5XI/eCxY8wDNmBprhYMNlYxdmQ9aLRDcTKWtddWpnJtyl5e3gHuYo
# j8xuDQ0XZNy7ESRwJIK03+rTZqfaYyM4XSK1s0aa+mO69vo/NmJ4R/f1+KucBPJ4
# yUdbqJWM3xMvBwLYycvigI/WK4kgPog0UBNczaQwDVXpcU+TMcOvWP8HBWmWJQIm
# TZInAFivXqUaBbo3wAfPNbsQpvNNGu/12pg0F8O/CdRfgPHfOhIWQ0D8ALCY+Lsi
# wbzcejbrVl4N9fn2wOg2sDa8RfNoD614I0pFjy/lq1NsBo9V4GZBikzX7ZjWCRgd
# 1FCBXGpfpDikHjQ05YOkAakdWDT2bGSaUZJGVYtepIpPTAs1gd/vUogcdiL51o7s
# huHIlB6QSUiQ24XYhRbbQCECAwEAAaOCAUkwggFFMB0GA1UdDgQWBBS9zsZzz57Q
# lT5nrt/oitLv1OQ7tjAfBgNVHSMEGDAWgBSfpxVdAF5iXYP05dJlpxtTNRnpcjBf
# BgNVHR8EWDBWMFSgUqBQhk5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3Bz
# L2NybC9NaWNyb3NvZnQlMjBUaW1lLVN0YW1wJTIwUENBJTIwMjAxMCgxKS5jcmww
# bAYIKwYBBQUHAQEEYDBeMFwGCCsGAQUFBzAChlBodHRwOi8vd3d3Lm1pY3Jvc29m
# dC5jb20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0El
# MjAyMDEwKDEpLmNydDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUF
# BwMIMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAgEAYfk8GzzpEVnG
# l7y6oXoytCb42Hx6TOA0+dkaBI36ftDE9tLubUa/xMbHB5rcNiRhFHZ93RefdPpc
# 4+FF0DAl5lP8xKAO+293RWPKDFOFIxgtZY08t8D9cSQpgGUzyw3lETZebNLEA17A
# /CTpA2F9uh8j84KygeEbj+bidWDiEfayoH2A5/5ywJJxIuLzFVHacvWxSCKoF9hl
# SrZSG5fXWS3namf4tt690UT6AGyWLFWe895coFPxm/m0UIMjjp9VRFH7nb3Ng2Q4
# gPS9E5ZTMZ6nAlmUicDj0NXAs2wQuQrnYnbRAJ/DQW35qLo7Daw9AsItqjFhbMcG
# 68gDc4j74L2KYe/2goBHLwzSn5UDftS1HZI0ZRsqmNHI0TZvvUWX9ajm6SfLBTEt
# oTo6gLOX0UD/9rrhGjdkiCw4SwU5osClgqgiNMK5ndk2gxFlDXHCyLp5qB6BoPpc
# 82RhO0yCzoP9gv7zv2EocAWEsqE5+0Wmu5uarmfvcziLfU1SY240OZW8ld4sS8fn
# ybn/jDMmFAhazV1zH0QERWEsfLSpwkOXaImWNFJ5lmcnf1VTm6cmfasScYtElpjq
# Z9GooCmk1XFApORPs/PO43IcFmPRwagt00iQSw+rBeIH00KQq+FJT/62SB70g9g/
# R8TS6k6b/wt2UWhqrW+Q8lw6Xzgex/YwggdxMIIFWaADAgECAhMzAAAAFcXna54C
# 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
# TjozMjFBLTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAg
# U2VydmljZaIjCgEBMAcGBSsOAwIaAxUAtkQt/ebWSQ5DnG+aKRzPELCFE9GggYMw
# gYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE
# BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYD
# VQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQsF
# AAIFAOrhc6wwIhgPMjAyNDExMTUwNzE1NTZaGA8yMDI0MTExNjA3MTU1NlowdzA9
# BgorBgEEAYRZCgQBMS8wLTAKAgUA6uFzrAIBADAKAgEAAgIHbQIB/zAHAgEAAgIS
# MDAKAgUA6uLFLAIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAow
# CAIBAAIDB6EgoQowCAIBAAIDAYagMA0GCSqGSIb3DQEBCwUAA4IBAQAf4rryHc1p
# OdFV/DCyYq537v1dgQpIdA/4eUsPdJR18EfBDebbGuG9523bhdCgmk7J939f30tM
# RJsFh+7+34PFI37n4gfbvH6YN5qdvLKTxceRohyqi8PsyN6a4O357emnsF7roIHM
# h1GyiYGIoNS6b66k8OcPumtydqBdIXxKb8UZkmDDaqG7Q+CL2/u87q8U1u2yvuSt
# afD0TxlOiNoBvGB89Dds+5Nww6klaS30bJdYXFswvaXfO5Xi3oV7r0Q6keLPKtz6
# R8BT4XxI3dHfAQ7nuHX5D44ms5IcTCMSWTxeIpR7eN0eC9SHyM4KavyGFiNMcGKz
# Q6RnkXJ687zwMYIEDTCCBAkCAQEwgZMwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgT
# Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m
# dCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENB
# IDIwMTACEzMAAAH4o6EmDAxASP4AAQAAAfgwDQYJYIZIAWUDBAIBBQCgggFKMBoG
# CSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0BCQQxIgQgjcM7X/MW
# teUufkdJgHj/kzYc7DUDkrdUMu2kb4PnyYkwgfoGCyqGSIb3DQEJEAIvMYHqMIHn
# MIHkMIG9BCDvzDPyXw1UkAUFYt8bR4UdjM90Qv5xnVaiKD3I0Zz3WjCBmDCBgKR+
# MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS
# ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMT
# HU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAAB+KOhJgwMQEj+AAEA
# AAH4MCIEIMGTHrtFSZ2QXMpCWpOpI+oRB6INUp8HzdASoDGrB/cWMA0GCSqGSIb3
# DQEBCwUABIICAEXT7+oEYZThVZB+89N1E10OKHjAftMSGRTbTAxdkg2UuQztE3fF
# dbUl+6HlP8PDSdzE+Y73KU6mKgxtaqLNMVW6oZirC/zYdM/R4ydOG9WnTFzslHdA
# TQiwR10lWzBKQSp3yg2PFU2zFGbGgCybyYC759PKn6YLX93q1HF+pD91pmB7dSHC
# lEIC6SK1MfLMEWNGfQYRR0g2cDCUSMnYhOeExbQfY/IijrRfTvz6suQPxJcwZe6/
# 1jM/Kh4avMM7CjXHJpNfMQU0rXQEE70iEdZ68BWoAZpAZqWQgsuH/IVnvviu6g0P
# P7QgfILQSKS6AJcqYpjrffDfm2UcRp1ChzUXHVxWwQD81sxq3HqUbbRTTS9ixwpk
# TxOXU/HAGcvnPXVyjnayI/LiD+7rGwbnwTKbNpMy1nOB+8ITDNbGFuQpyJ4ocP8w
# xVdLSUBfWM6uBPmm6QbdWrFnVX84wwP7FeWTnIyKAGHosrpyLYOhPCwrWXdwUJog
# FlgChvOKX5nmB25q6ccY3eMYTR0vhZwnpqswbq/scI+Btf3b+EYbR4MCCfpGih3X
# Ciill6QTNix9awR77i5bUVhONKQvQFneXTzJ9EaKgOpHnvvNoAALL6f0N94+CwFW
# JjxzrqjYaxFjJAFr2s9qfHU/hAJTrcuOKBwYsZ4r2+XFwZmBzdE7KSI2
# SIG # End signature block