| Server IP : 121.121.20.254 / Your IP : 216.73.216.202 Web Server : Microsoft-IIS/10.0 System : Windows NT WEB-SERVER 10.0 build 20348 (Windows Server 2022) AMD64 User : IUSR ( 0) PHP Version : 8.3.28 Disable Function : NONE MySQL : ON | cURL : ON | WGET : OFF | Perl : OFF | Python : OFF | Sudo : OFF | Pkexec : OFF Directory : /Program Files/WindowsPowerShell/Modules/Pester/3.4.0/Functions/ |
Upload File : |
if ($PSVersionTable.PSVersion.Major -le 2)
{
function Exit-CoverageAnalysis { }
function Get-CoverageReport { }
function Show-CoverageReport { }
function Enter-CoverageAnalysis {
param ( $CodeCoverage )
if ($CodeCoverage) { & $SafeCommands['Write-Error'] 'Code coverage analysis requires PowerShell 3.0 or later.' }
}
return
}
function Enter-CoverageAnalysis
{
[CmdletBinding()]
param (
[object[]] $CodeCoverage,
[object] $PesterState
)
$coverageInfo =
foreach ($object in $CodeCoverage)
{
Get-CoverageInfoFromUserInput -InputObject $object
}
$PesterState.CommandCoverage = @(Get-CoverageBreakpoints -CoverageInfo $coverageInfo)
}
function Exit-CoverageAnalysis
{
param ([object] $PesterState)
& $SafeCommands['Set-StrictMode'] -Off
$breakpoints = @($PesterState.CommandCoverage.Breakpoint) -ne $null
if ($breakpoints.Count -gt 0)
{
& $SafeCommands['Remove-PSBreakpoint'] -Breakpoint $breakpoints
}
}
function Get-CoverageInfoFromUserInput
{
param (
[Parameter(Mandatory = $true)]
[object]
$InputObject
)
if ($InputObject -is [System.Collections.IDictionary])
{
$unresolvedCoverageInfo = Get-CoverageInfoFromDictionary -Dictionary $InputObject
}
else
{
$unresolvedCoverageInfo = New-CoverageInfo -Path ([string]$InputObject)
}
Resolve-CoverageInfo -UnresolvedCoverageInfo $unresolvedCoverageInfo
}
function New-CoverageInfo
{
param ([string] $Path, [string] $Function = $null, [int] $StartLine = 0, [int] $EndLine = 0)
return [pscustomobject]@{
Path = $Path
Function = $Function
StartLine = $StartLine
EndLine = $EndLine
}
}
function Get-CoverageInfoFromDictionary
{
param ([System.Collections.IDictionary] $Dictionary)
[string] $path = Get-DictionaryValueFromFirstKeyFound -Dictionary $Dictionary -Key 'Path', 'p'
if ([string]::IsNullOrEmpty($path))
{
throw "Coverage value '$Dictionary' is missing required Path key."
}
$startLine = Get-DictionaryValueFromFirstKeyFound -Dictionary $Dictionary -Key 'StartLine', 'Start', 's'
$endLine = Get-DictionaryValueFromFirstKeyFound -Dictionary $Dictionary -Key 'EndLine', 'End', 'e'
[string] $function = Get-DictionaryValueFromFirstKeyFound -Dictionary $Dictionary -Key 'Function', 'f'
$startLine = Convert-UnknownValueToInt -Value $startLine -DefaultValue 0
$endLine = Convert-UnknownValueToInt -Value $endLine -DefaultValue 0
return New-CoverageInfo -Path $path -StartLine $startLine -EndLine $endLine -Function $function
}
function Convert-UnknownValueToInt
{
param ([object] $Value, [int] $DefaultValue = 0)
try
{
return [int] $Value
}
catch
{
return $DefaultValue
}
}
function Resolve-CoverageInfo
{
param ([psobject] $UnresolvedCoverageInfo)
$path = $UnresolvedCoverageInfo.Path
try
{
$resolvedPaths = & $SafeCommands['Resolve-Path'] -Path $path -ErrorAction Stop
}
catch
{
& $SafeCommands['Write-Error'] "Could not resolve coverage path '$path': $($_.Exception.Message)"
return
}
$filePaths =
foreach ($resolvedPath in $resolvedPaths)
{
$item = & $SafeCommands['Get-Item'] -LiteralPath $resolvedPath
if ($item -is [System.IO.FileInfo] -and ('.ps1','.psm1') -contains $item.Extension)
{
$item.FullName
}
elseif (-not $item.PsIsContainer)
{
& $SafeCommands['Write-Warning'] "CodeCoverage path '$path' resolved to a non-PowerShell file '$($item.FullName)'; this path will not be part of the coverage report."
}
}
$params = @{
StartLine = $UnresolvedCoverageInfo.StartLine
EndLine = $UnresolvedCoverageInfo.EndLine
Function = $UnresolvedCoverageInfo.Function
}
foreach ($filePath in $filePaths)
{
$params['Path'] = $filePath
New-CoverageInfo @params
}
}
function Get-CoverageBreakpoints
{
[CmdletBinding()]
param (
[object[]] $CoverageInfo
)
$fileGroups = @($CoverageInfo | & $SafeCommands['Group-Object'] -Property Path)
foreach ($fileGroup in $fileGroups)
{
& $SafeCommands['Write-Verbose'] "Initializing code coverage analysis for file '$($fileGroup.Name)'"
$totalCommands = 0
$analyzedCommands = 0
:commandLoop
foreach ($command in Get-CommandsInFile -Path $fileGroup.Name)
{
$totalCommands++
foreach ($coverageInfoObject in $fileGroup.Group)
{
if (Test-CoverageOverlapsCommand -CoverageInfo $coverageInfoObject -Command $command)
{
$analyzedCommands++
New-CoverageBreakpoint -Command $command
continue commandLoop
}
}
}
& $SafeCommands['Write-Verbose'] "Analyzing $analyzedCommands of $totalCommands commands in file '$($fileGroup.Name)' for code coverage"
}
}
function Get-CommandsInFile
{
param ([string] $Path)
$errors = $null
$tokens = $null
$ast = [System.Management.Automation.Language.Parser]::ParseFile($Path, [ref] $tokens, [ref] $errors)
if ($PSVersionTable.PSVersion.Major -ge 5)
{
# In PowerShell 5.0, dynamic keywords for DSC configurations are represented by the DynamicKeywordStatementAst
# class. They still trigger breakpoints, but are not a child class of CommandBaseAst anymore.
$predicate = {
$args[0] -is [System.Management.Automation.Language.DynamicKeywordStatementAst] -or
$args[0] -is [System.Management.Automation.Language.CommandBaseAst]
}
}
else
{
$predicate = { $args[0] -is [System.Management.Automation.Language.CommandBaseAst] }
}
$searchNestedScriptBlocks = $true
$ast.FindAll($predicate, $searchNestedScriptBlocks)
}
function Test-CoverageOverlapsCommand
{
param ([object] $CoverageInfo, [System.Management.Automation.Language.Ast] $Command)
if ($CoverageInfo.Function)
{
Test-CommandInsideFunction -Command $Command -Function $CoverageInfo.Function
}
else
{
Test-CoverageOverlapsCommandByLineNumber @PSBoundParameters
}
}
function Test-CommandInsideFunction
{
param ([System.Management.Automation.Language.Ast] $Command, [string] $Function)
for ($ast = $Command; $null -ne $ast; $ast = $ast.Parent)
{
$functionAst = $ast -as [System.Management.Automation.Language.FunctionDefinitionAst]
if ($null -ne $functionAst -and $functionAst.Name -like $Function)
{
return $true
}
}
return $false
}
function Test-CoverageOverlapsCommandByLineNumber
{
param ([object] $CoverageInfo, [System.Management.Automation.Language.Ast] $Command)
$commandStart = $Command.Extent.StartLineNumber
$commandEnd = $Command.Extent.EndLineNumber
$coverStart = $CoverageInfo.StartLine
$coverEnd = $CoverageInfo.EndLine
# An EndLine value of 0 means to cover the entire rest of the file from StartLine
# (which may also be 0)
if ($coverEnd -le 0) { $coverEnd = [int]::MaxValue }
return (Test-RangeContainsValue -Value $commandStart -Min $coverStart -Max $coverEnd) -or
(Test-RangeContainsValue -Value $commandEnd -Min $coverStart -Max $coverEnd)
}
function Test-RangeContainsValue
{
param ([int] $Value, [int] $Min, [int] $Max)
return $Value -ge $Min -and $Value -le $Max
}
function New-CoverageBreakpoint
{
param ([System.Management.Automation.Language.Ast] $Command)
if (IsIgnoredCommand -Command $Command) { return }
$params = @{
Script = $Command.Extent.File
Line = $Command.Extent.StartLineNumber
Column = $Command.Extent.StartColumnNumber
Action = { }
}
$breakpoint = & $SafeCommands['Set-PSBreakpoint'] @params
[pscustomobject] @{
File = $Command.Extent.File
Function = Get-ParentFunctionName -Ast $Command
Line = $Command.Extent.StartLineNumber
Command = Get-CoverageCommandText -Ast $Command
Breakpoint = $breakpoint
}
}
function IsIgnoredCommand
{
param ([System.Management.Automation.Language.Ast] $Command)
if (-not $Command.Extent.File)
{
# This can happen if the script contains "configuration" or any similarly implemented
# dynamic keyword. PowerShell modifies the script code and reparses it in memory, leading
# to AST elements with no File in their Extent.
return $true
}
if ($PSVersionTable.PSVersion.Major -ge 4)
{
if ($Command.Extent.Text -eq 'Configuration')
{
# More DSC voodoo. Calls to "configuration" generate breakpoints, but their HitCount
# stays zero (even though they are executed.) For now, ignore them, unless we can come
# up with a better solution.
return $true
}
if (IsChildOfHashtableDynamicKeyword -Command $Command)
{
# The lines inside DSC resource declarations don't trigger their breakpoints when executed,
# just like the "configuration" keyword itself. I don't know why, at this point, but just like
# configuration, we'll ignore it so it doesn't clutter up the coverage analysis with useless junk.
return $true
}
}
if (IsClosingLoopCondition -Command $Command)
{
# For some reason, the closing expressions of do/while and do/until loops don't trigger their breakpoints.
# To avoid useless clutter, we'll ignore those lines as well.
return $true
}
return $false
}
function IsChildOfHashtableDynamicKeyword
{
param ([System.Management.Automation.Language.Ast] $Command)
for ($ast = $Command.Parent; $null -ne $ast; $ast = $ast.Parent)
{
if ($PSVersionTable.PSVersion.Major -ge 5)
{
# The ast behaves differently for DSC resources with version 5+. There's a new DynamicKeywordStatementAst class,
# and they no longer are represented by CommandAst objects.
if ($ast -is [System.Management.Automation.Language.DynamicKeywordStatementAst] -and
$ast.CommandElements[-1] -is [System.Management.Automation.Language.HashtableAst])
{
return $true
}
}
else
{
if ($ast -is [System.Management.Automation.Language.CommandAst] -and
$null -ne $ast.DefiningKeyword -and
$ast.DefiningKeyword.BodyMode -eq [System.Management.Automation.Language.DynamicKeywordBodyMode]::Hashtable)
{
return $true
}
}
}
return $false
}
function IsClosingLoopCondition
{
param ([System.Management.Automation.Language.Ast] $Command)
$ast = $Command
while ($null -ne $ast.Parent)
{
if (($ast.Parent -is [System.Management.Automation.Language.DoWhileStatementAst] -or
$ast.Parent -is [System.Management.Automation.Language.DoUntilStatementAst]) -and
$ast.Parent.Condition -eq $ast)
{
return $true
}
$ast = $ast.Parent
}
return $false
}
function Get-ParentFunctionName
{
param ([System.Management.Automation.Language.Ast] $Ast)
$parent = $Ast.Parent
while ($null -ne $parent -and $parent -isnot [System.Management.Automation.Language.FunctionDefinitionAst])
{
$parent = $parent.Parent
}
if ($null -eq $parent)
{
return ''
}
else
{
return $parent.Name
}
}
function Get-CoverageCommandText
{
param ([System.Management.Automation.Language.Ast] $Ast)
$reportParentExtentTypes = @(
[System.Management.Automation.Language.ReturnStatementAst]
[System.Management.Automation.Language.ThrowStatementAst]
[System.Management.Automation.Language.AssignmentStatementAst]
[System.Management.Automation.Language.IfStatementAst]
)
$parent = Get-ParentNonPipelineAst -Ast $Ast
if ($null -ne $parent)
{
if ($parent -is [System.Management.Automation.Language.HashtableAst])
{
return Get-KeyValuePairText -HashtableAst $parent -ChildAst $Ast
}
elseif ($reportParentExtentTypes -contains $parent.GetType())
{
return $parent.Extent.Text
}
}
return $Ast.Extent.Text
}
function Get-ParentNonPipelineAst
{
param ([System.Management.Automation.Language.Ast] $Ast)
$parent = $null
if ($null -ne $Ast) { $parent = $Ast.Parent }
while ($parent -is [System.Management.Automation.Language.PipelineAst])
{
$parent = $parent.Parent
}
return $parent
}
function Get-KeyValuePairText
{
param (
[System.Management.Automation.Language.HashtableAst] $HashtableAst,
[System.Management.Automation.Language.Ast] $ChildAst
)
& $SafeCommands['Set-StrictMode'] -Off
foreach ($keyValuePair in $HashtableAst.KeyValuePairs)
{
if ($keyValuePair.Item2.PipelineElements -contains $ChildAst)
{
return '{0} = {1}' -f $keyValuePair.Item1.Extent.Text, $keyValuePair.Item2.Extent.Text
}
}
# This shouldn't happen, but just in case, default to the old output of just the expression.
return $ChildAst.Extent.Text
}
function Get-CoverageMissedCommands
{
param ([object[]] $CommandCoverage)
$CommandCoverage | & $SafeCommands['Where-Object'] { $_.Breakpoint.HitCount -eq 0 }
}
function Get-CoverageHitCommands
{
param ([object[]] $CommandCoverage)
$CommandCoverage | & $SafeCommands['Where-Object'] { $_.Breakpoint.HitCount -gt 0 }
}
function Get-CoverageReport
{
param ([object] $PesterState)
$totalCommandCount = $PesterState.CommandCoverage.Count
$missedCommands = @(Get-CoverageMissedCommands -CommandCoverage $PesterState.CommandCoverage | & $SafeCommands['Select-Object'] File, Line, Function, Command)
$hitCommands = @(Get-CoverageHitCommands -CommandCoverage $PesterState.CommandCoverage | & $SafeCommands['Select-Object'] File, Line, Function, Command)
$analyzedFiles = @($PesterState.CommandCoverage | & $SafeCommands['Select-Object'] -ExpandProperty File -Unique)
$fileCount = $analyzedFiles.Count
$executedCommandCount = $totalCommandCount - $missedCommands.Count
[pscustomobject] @{
NumberOfCommandsAnalyzed = $totalCommandCount
NumberOfFilesAnalyzed = $fileCount
NumberOfCommandsExecuted = $executedCommandCount
NumberOfCommandsMissed = $missedCommands.Count
MissedCommands = $missedCommands
HitCommands = $hitCommands
AnalyzedFiles = $analyzedFiles
}
}
function Show-CoverageReport
{
param ([object] $CoverageReport)
if ($null -eq $CoverageReport -or $CoverageReport.NumberOfCommandsAnalyzed -eq 0)
{
return
}
$totalCommandCount = $CoverageReport.NumberOfCommandsAnalyzed
$fileCount = $CoverageReport.NumberOfFilesAnalyzed
$executedPercent = ($CoverageReport.NumberOfCommandsExecuted / $CoverageReport.NumberOfCommandsAnalyzed).ToString("P2")
$commandPlural = $filePlural = ''
if ($totalCommandCount -gt 1) { $commandPlural = 's' }
if ($fileCount -gt 1) { $filePlural = 's' }
$commonParent = Get-CommonParentPath -Path $CoverageReport.AnalyzedFiles
$report = $CoverageReport.MissedCommands | & $SafeCommands['Select-Object'] -Property @(
@{ Name = 'File'; Expression = { Get-RelativePath -Path $_.File -RelativeTo $commonParent } }
'Function'
'Line'
'Command'
)
Write-Screen ''
Write-Screen 'Code coverage report:'
Write-Screen "Covered $executedPercent of $totalCommandCount analyzed command$commandPlural in $fileCount file$filePlural."
if ($CoverageReport.MissedCommands.Count -gt 0)
{
Write-Screen ''
Write-Screen 'Missed commands:'
$report | & $SafeCommands['Format-Table'] -AutoSize | & $SafeCommands['Out-String'] | Write-Screen
}
}
function Get-CommonParentPath
{
param ([string[]] $Path)
$pathsToTest = @( $Path | & $SafeCommands['Select-Object'] -Unique )
if ($pathsToTest.Count -gt 0)
{
$parentPath = & $SafeCommands['Split-Path'] -Path $pathsToTest[0] -Parent
while ($parentPath.Length -gt 0)
{
$nonMatches = $pathsToTest -notmatch "^$([regex]::Escape($parentPath))"
if ($nonMatches.Count -eq 0)
{
return $parentPath
}
else
{
$parentPath = & $SafeCommands['Split-Path'] -Path $parentPath -Parent
}
}
}
return [string]::Empty
}
function Get-RelativePath
{
param ( [string] $Path, [string] $RelativeTo )
return $Path -replace "^$([regex]::Escape($RelativeTo))\\?"
}
# SIG # Begin signature block
# MIInjwYJKoZIhvcNAQcCoIIngDCCJ3wCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCqG+zazlxP++cv
# 0EUGZRX6zP2XM6BmoNh/fiywwj2BLqCCC8MwggXaMIIEwqADAgECAhMzAAABP8rF
# KBkLiTVYAAAAAAE/MA0GCSqGSIb3DQEBCwUAMIGOMQswCQYDVQQGEwJVUzETMBEG
# A1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWlj
# cm9zb2Z0IENvcnBvcmF0aW9uMTgwNgYDVQQDEy9NaWNyb3NvZnQgV2luZG93cyBU
# aGlyZCBQYXJ0eSBDb21wb25lbnQgQ0EgMjAxMjAeFw0yNTExMTMxOTU5NDJaFw0y
# NjExMTAxOTU5NDJaMIGEMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv
# bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0
# aW9uMS4wLAYDVQQDEyVNaWNyb3NvZnQgV2luZG93cyAzcmQgcGFydHkgQ29tcG9u
# ZW50MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA2Zy0BnZmL5lF9IDS
# IFBJ81NqCWCPLo2bRGJObUnrlezQw+FWEDU9+poMEyRjgbgafifNKY4TJ3e9Od4p
# q56xMXBcGYVIe546gz4p68MQG4iXqqSBB4kk5jwk5U7igTCfZIga6PFElV6Wm7kv
# Bdw14NVgdJZZDdmIc9TdaWbxrxAda9IMjZNQYfJZ/WVinf0mPnYM2hQwj4Gl4DGC
# 0/KO6U+ayXHAtcS9qj2UJYB7rCyteNydGWHaMa5B8fzOpSNS3ioJfYcBwSjfcBRD
# pemnEb5BcIF10FVuNA4foeMz5emIZaGGl8XxVC9K79Xwkc571Sv899qEdYP8ZFW9
# yVXY8l1ptvk4nD52nq9ld4HjWA+FHmhbhKggbjEVymQee7fOgEWKE3Uc73YnTMGf
# TXzDwH9jYip5fwls08LWs0HCINu/iA/OG/vm1jrJdK5wcBgX2B0fZPdwgLTEgs0R
# rSIyv9WucI0S6XffXJuUH+lziAX7RmCPhy5kZR1R3LB0GnBlAgMBAAGjggG3MIIB
# szATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUt3RSDxhJIhKufhwaOyWL
# 3nMDoeUwVAYDVR0RBE0wS6RJMEcxLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5k
# IE9wZXJhdGlvbnMgTGltaXRlZDEWMBQGA1UEBRMNMjMwODA5KzUwNjIzOTAfBgNV
# HSMEGDAWgBRhcaeHr/9p1SF2T1KTKAC+eRKrhDB0BgNVHR8EbTBrMGmgZ6BlhmNo
# dHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBX
# aW5kb3dzJTIwVGhpcmQlMjBQYXJ0eSUyMENvbXBvbmVudCUyMENBJTIwMjAxMi5j
# cmwwgYEGCCsGAQUFBwEBBHUwczBxBggrBgEFBQcwAoZlaHR0cDovL3d3dy5taWNy
# b3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNyb3NvZnQlMjBXaW5kb3dzJTIwVGhp
# cmQlMjBQYXJ0eSUyMENvbXBvbmVudCUyMENBJTIwMjAxMi5jcnQwDAYDVR0TAQH/
# BAIwADANBgkqhkiG9w0BAQsFAAOCAQEAk+iGdVNjQ2VMiNXhflILGybQmTUMM+qd
# BZ3KErdJ9wkVTN/fMukvmp9y1iF8Sz1NUqDNqiKLofcL0XukOu5W3zAofFlAs2tR
# vf0ArWKgRP5gjpqXeo3xWRM/1LBYTDhwDmylfh36AnfErB+aHyoIr9an+2KqeIqj
# 5VvFPgwJ1n6ZTXZMhjvYnIol/P+vwVroo2XKwbOL1/c79xRj7X8Lqw+7sVoIA9/P
# ytqdSDV1ClBjltkRpdgwvbSDPzycfvN8V5pPFfkrqrcIHjaL2pe76nqRsEIPqiVQ
# SmqiaJV6iprCSDGJYC4/4EMLIDZ4uf+m0XHW3Qzlr7RLlMdsJKny7jCCBeEwggPJ
# oAMCAQICCmELqsEAAAAAAAkwDQYJKoZIhvcNAQELBQAwgYgxCzAJBgNVBAYTAlVT
# MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQK
# ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBSb290
# IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDEwMB4XDTEyMDQxODIzNDgzOFoXDTI3
# MDQxODIzNTgzOFowgY4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9u
# MRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp
# b24xODA2BgNVBAMTL01pY3Jvc29mdCBXaW5kb3dzIFRoaXJkIFBhcnR5IENvbXBv
# bmVudCBDQSAyMDEyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo5ww
# hAmnYy7PCkfw6iT5ozAgD15XMSaBmjEHslDUzmcJCGUKWqVLrtXtEC7npZm1n2gv
# mItYAqwgtCnEcb0oHKX9PJtk5MXr32ElvPDuaL/Rp8t+KgKBTmRcDFOGeVcZN2G3
# mPkMoE4iWZv5Gy1nPCc8VpBm4/1/ZX0Phr01R+iKzPTajulqTqunVeyiiR7VM0VT
# y/med73NLPkFuH90AR3o+xjhQ9EN6arcN2+9/rgP7R1NAUZOCqz8gujsVoMTjjoB
# 7RRkdOpksmYQtmhtyHAAfVBILj1D7uAklcbNjsf9uOSVz91++5VeoQHNQ7EH16Qw
# 7puGGipuwQtZonRviwIDAQABo4IBQzCCAT8wEAYJKwYBBAGCNxUBBAMCAQAwHQYD
# VR0OBBYEFGFxp4ev/2nVIXZPUpMoAL55EquEMBkGCSsGAQQBgjcUAgQMHgoAUwB1
# AGIAQwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaA
# FNX2VsuP6KJcYmjRPZSQW9fOmhjEMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9j
# cmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dF8y
# MDEwLTA2LTIzLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6
# Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljUm9vQ2VyQXV0XzIwMTAt
# MDYtMjMuY3J0MA0GCSqGSIb3DQEBCwUAA4ICAQBaimfazNX9DSZBd78KRni0s94S
# aSt3I8JlLwFf0gP0YbpQnS6MOXLzbD5qsR52bey384LczLvFaXAoc2YXP1Tr7gEW
# SMRG2RuAroE6jQ95bWiwnuotPznTyjh+vV58CG4Z3MbC9DgzaGHiUkeD4QABVtK6
# y4eCBTEKQYtO539fX+1f0zktReuiE7/9HsKYQXFhFl/ICnAlfFlpMSTkcecKuwQX
# 959yHsnSuxq+PQL+CQyyQ7RZGplTk5YhX+DWtyYBQpU2rCf9vvSFd2g9GL30vpiI
# IhGGUhbzRewDlxBwh6NwQ3E828mGAxcM9XNbxn3hXGTt18VI1+0y4tGq08+n9ldO
# Yfl362fyiLPeANoDj9CKNDc+HdhiuNKx8+Evi3I7gZZ8b/zsZnZyYBsk8qCJbVtt
# AC7vKN2GhwXCtLnlvmTCKvJKFVyY4sQnhf9S42J+D7ICC9dmxwqy0z0gBBRQMlmD
# Cn2b7Vo4EgFSui9eIHKOSvH953ECjDvhB77Jc/TdR9i077SkszC5iT52yrkAmFZ+
# q+qKuKXQOKtpdxMLFC/pqkEf97q9Ois0iu4Kq2PmY/eIJI4gDSs7nePCSVKsnx8O
# OTtd1G5QauZ9UjqqfDMVKQ0mXgFYp06pPXqEb3Q/YJ/kMk82AK9tcdM+pkZlX4F0
# 8f7BcdpMoEFagt3xHzGCGyIwghseAgEBMIGmMIGOMQswCQYDVQQGEwJVUzETMBEG
# A1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWlj
# cm9zb2Z0IENvcnBvcmF0aW9uMTgwNgYDVQQDEy9NaWNyb3NvZnQgV2luZG93cyBU
# aGlyZCBQYXJ0eSBDb21wb25lbnQgQ0EgMjAxMgITMwAAAT/KxSgZC4k1WAAAAAAB
# PzANBglghkgBZQMEAgEFAKCCARgwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw
# HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEICON
# wWKXH7dsutIwpVdzGbC2Jltl5fqVrNgeaNFAr39gMFAGCisGAQQBgjcKAxwxQgxA
# QjVGNDdGRDM1MjdFQTI3MUEyQUNCRjRGMjYxQUNGMDZBRkEwQjE0OUNBOTZCMjZC
# MDBENTY0NDY5MzlGMTFCMTBaBgorBgEEAYI3AgEMMUwwSqAkgCIATQBpAGMAcgBv
# AHMAbwBmAHQAIABXAGkAbgBkAG8AdwBzoSKAIGh0dHA6Ly93d3cubWljcm9zb2Z0
# LmNvbS93aW5kb3dzMA0GCSqGSIb3DQEBAQUABIIBgDMT3nQLrkaYczZgJ3iLtB1O
# zyhz5Gw4NgHsKdOPpuAVTg13WIND02sPmk+7x3mAH/KrohI090w+0b+7CI6O8cRp
# U9aJIODUWeBLsIT9X8PdCSKIW89jmjQ+qWI/hQ2jDqqOXyr86jVn3ptzjq94I3Nh
# qpnXtCN7mYJcW/Uv1W7VyH5OLi/FrzTDcj9tuyxwBeXIJ0JqdONt/k1JrVxGQ9Fz
# 6YILqGHs9CRMhBNblFSYr3g6bjTTX0SaFcCWeuOLd50H9mubWPN4OgJgFSY36KGJ
# mjjDN9NQY3UbCZPnHuIWLojlpHv/kfxRNbOZzNq+l29PS0HqHM1aSNBCJKaJHy3j
# LgBnnqW9hGQGhzheA5BUx/Eh8EwvIZCka3Z3ZTmpGqx1s4Dz6rNfER86ICmKbKGy
# 8abQ2Bwe9EFkswHiYQ+J2lzroMxQdwQ2BWhx/5hpl4HSpow07F1hDPo7KOASI8ey
# 1oevKcCc4rsNW00Q8XjTeTlHpbkQmzGkLVne0DRfHqGCF7AwghesBgorBgEEAYI3
# AwMBMYIXnDCCF5gGCSqGSIb3DQEHAqCCF4kwgheFAgEDMQ8wDQYJYIZIAWUDBAIB
# BQAwggFaBgsqhkiG9w0BCRABBKCCAUkEggFFMIIBQQIBAQYKKwYBBAGEWQoDATAx
# MA0GCWCGSAFlAwQCAQUABCBCNkYObWEqTkWdFRaECQbwE8rwzqLQJEashzup4rwD
# sQIGamNJIB+tGBMyMDI2MDgwODE4MzQ0My41OTRaMASAAgH0oIHZpIHWMIHTMQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNy
# b3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJzAlBgNVBAsTHm5TaGll
# bGQgVFNTIEVTTjo2QjA1LTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9zb2Z0IFRp
# bWUtU3RhbXAgU2VydmljZaCCEf4wggcoMIIFEKADAgECAhMzAAACEUUYOZtDz/xs
# AAEAAAIRMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpX
# YXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQg
# Q29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAy
# MDEwMB4XDTI1MDgxNDE4NDgxM1oXDTI2MTExMzE4NDgxM1owgdMxCzAJBgNVBAYT
# AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD
# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29mdCBJ
# cmVsYW5kIE9wZXJhdGlvbnMgTGltaXRlZDEnMCUGA1UECxMeblNoaWVsZCBUU1Mg
# RVNOOjZCMDUtMDVFMC1EOTQ3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFt
# cCBTZXJ2aWNlMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAz7m7MxAd
# L5Vayrk7jsMo3GnhN85ktHCZEvEcj4BIccHKd/NKC7uPvpX5dhO63W6VM5iCxklG
# 8qQeVVrPaKvj8dYYJC7DNt4NN3XlVdC/voveJuPPhTJ/u7X+pYmV2qehTVPOOB1/
# hpmt51SzgxZczMdnFl+X2e1PgutSA5CAh9/Xz5NW0CxnYVz8g0Vpxg+Bq32amktR
# Xr8m3BSEgUs8jgWRPVzPHEczpbhloGGEfHaROmHhVKIqN+JhMweEjU2NXM2W6hm3
# 2j/QH/I/KWqNNfYchHaG0xJljVTYoUKPpcQDuhH9dQKEgvGxj2U5/3Fq1em4dO6I
# h04m6R+ttxr6Y8oRJH9ZhZ3sciFBIvZh7E2YFXOjP4MGybSylQTPDEFAtHHgpksk
# eEUhsPDR9VvWWhekhQx3qXaAKh+AkLmz/hpE3e0y+RIKO2AREjULJAKgf+R9QnNv
# qMeMkz9PGrjsijqWGzB2k2JNyaUYKlbmQweOabsCioiY2fJbimjVyFAGk5AeYddU
# FxvJGgRVCH7BeBPKAq7MMOmSCTOMZ0Sw6zyNx4Uhh5Y0uJ0ZOoTKnB3KfdN/ba/e
# KHFeEhi3WqAfzTxiy0rMvhsfsXZK7zoclqaRvVl8Q48J174+eyriypY9HhU+ohgi
# Yi4uQGDDVdTDeKDtoC/hD2Cn+ARzwE1rFfECAwEAAaOCAUkwggFFMB0GA1UdDgQW
# BBRifUUDwOnqIcvfb53+yV0EZn7OcDAfBgNVHSMEGDAWgBSfpxVdAF5iXYP05dJl
# pxtTNRnpcjBfBgNVHR8EWDBWMFSgUqBQhk5odHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBUaW1lLVN0YW1wJTIwUENBJTIwMjAx
# MCgxKS5jcmwwbAYIKwYBBQUHAQEEYDBeMFwGCCsGAQUFBzAChlBodHRwOi8vd3d3
# Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMFRpbWUtU3Rh
# bXAlMjBQQ0ElMjAyMDEwKDEpLmNydDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQM
# MAoGCCsGAQUFBwMIMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAgEA
# pEKdnMeIIUiU6PatZ/qbrwiDzYUMKRczC4Bp/XY1S9NmHI+2c3dcpwH2SOmDfdvI
# Iqt7mRrgvBPYOvJ9CtZS5eeIrsObC0b0ggKTv2wrTgWG+qktqNFEhQeipdURNLN6
# 8uHAm5edwBytd1kwy5r6B93klxDsldOmVWtw/ngj7knN09muCmwr17JnsMFcoIN/
# H59s+1RYN7Vid4+7nj8FcvYy9rbZOMndBzsTiosF1M+aMIJX2k3EVFVsuDL7/R5p
# pI9Tg7eWQOWKMZHPdsA3ZqWzDuhJqTzoFSQShnZenC+xq/z9BhHPFFbUtfjAoG6E
# DPjSQJYXmogja8OEa19xwnh3wVufeP+ck+/0gxNi7g+kO6WaOm052F4siD8xi6Uv
# 75L7798lHvPThcxHHsgXqMY592d1wUof3tL/eDaQ0UhnYCU8yGkU2XJnctONnBKA
# vURAvf2qiIWDj4Lpcm0zA7VuofuJR1Tpuyc5p1ja52bNZBBVqAOwyDhAmqWsJXAj
# YXnssC/fJkee314Fh+GIyMgvAPRScgqRZqV16dTBYvoe+w1n/wWs/ySTUsxDw4T/
# AITcu5PAsLnCVpArDrFLRTFyut+eHUoG6UYZfj8/RsuQ42INse1pb/cPm7G2lcLJ
# tkIKT80xvB1LiaNvPTBVEcmNSvFUM0xrXZXcYcxVXiYwggdxMIIFWaADAgECAhMz
# AAAAFcXna54Cm0mZAAAAAAAVMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJV
# UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE
# ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9v
# dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0yMTA5MzAxODIyMjVaFw0z
# MDA5MzAxODMyMjVaMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9u
# MRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp
# b24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMIICIjAN
# BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA5OGmTOe0ciELeaLL1yR5vQ7VgtP9
# 7pwHB9KpbE51yMo1V/YBf2xK4OK9uT4XYDP/XE/HZveVU3Fa4n5KWv64NmeFRiMM
# tY0Tz3cywBAY6GB9alKDRLemjkZrBxTzxXb1hlDcwUTIcVxRMTegCjhuje3XD9gm
# U3w5YQJ6xKr9cmmvHaus9ja+NSZk2pg7uhp7M62AW36MEBydUv626GIl3GoPz130
# /o5Tz9bshVZN7928jaTjkY+yOSxRnOlwaQ3KNi1wjjHINSi947SHJMPgyY9+tVSP
# 3PoFVZhtaDuaRr3tpK56KTesy+uDRedGbsoy1cCGMFxPLOJiss254o2I5JasAUq7
# vnGpF1tnYN74kpEeHT39IM9zfUGaRnXNxF803RKJ1v2lIH1+/NmeRd+2ci/bfV+A
# utuqfjbsNkz2K26oElHovwUDo9Fzpk03dJQcNIIP8BDyt0cY7afomXw/TNuvXsLz
# 1dhzPUNOwTM5TI4CvEJoLhDqhFFG4tG9ahhaYQFzymeiXtcodgLiMxhy16cg8ML6
# EgrXY28MyTZki1ugpoMhXV8wdJGUlNi5UPkLiWHzNgY1GIRH29wb0f2y1BzFa/Zc
# UlFdEtsluq9QBXpsxREdcu+N+VLEhReTwDwV2xo3xwgVGD94q0W29R6HXtqPnhZy
# acaue7e3PmriLq0CAwEAAaOCAd0wggHZMBIGCSsGAQQBgjcVAQQFAgMBAAEwIwYJ
# KwYBBAGCNxUCBBYEFCqnUv5kxJq+gpE8RjUpzxD/LwTuMB0GA1UdDgQWBBSfpxVd
# AF5iXYP05dJlpxtTNRnpcjBcBgNVHSAEVTBTMFEGDCsGAQQBgjdMg30BATBBMD8G
# CCsGAQUFBwIBFjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL0RvY3Mv
# UmVwb3NpdG9yeS5odG0wEwYDVR0lBAwwCgYIKwYBBQUHAwgwGQYJKwYBBAGCNxQC
# BAweCgBTAHUAYgBDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYD
# VR0jBBgwFoAU1fZWy4/oolxiaNE9lJBb186aGMQwVgYDVR0fBE8wTTBLoEmgR4ZF
# aHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljUm9v
# Q2VyQXV0XzIwMTAtMDYtMjMuY3JsMFoGCCsGAQUFBwEBBE4wTDBKBggrBgEFBQcw
# AoY+aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJB
# dXRfMjAxMC0wNi0yMy5jcnQwDQYJKoZIhvcNAQELBQADggIBAJ1VffwqreEsH2cB
# MSRb4Z5yS/ypb+pcFLY+TkdkeLEGk5c9MTO1OdfCcTY/2mRsfNB1OW27DzHkwo/7
# bNGhlBgi7ulmZzpTTd2YurYeeNg2LpypglYAA7AFvonoaeC6Ce5732pvvinLbtg/
# SHUB2RjebYIM9W0jVOR4U3UkV7ndn/OOPcbzaN9l9qRWqveVtihVJ9AkvUCgvxm2
# EhIRXT0n4ECWOKz3+SmJw7wXsFSFQrP8DJ6LGYnn8AtqgcKBGUIZUnWKNsIdw2Fz
# Lixre24/LAl4FOmRsqlb30mjdAy87JGA0j3mSj5mO0+7hvoyGtmW9I/2kQH2zsZ0
# /fZMcm8Qq3UwxTSwethQ/gpY3UA8x1RtnWN0SCyxTkctwRQEcb9k+SS+c23Kjgm9
# swFXSVRk2XPXfx5bRAGOWhmRaw2fpCjcZxkoJLo4S5pu+yFUa2pFEUep8beuyOiJ
# Xk+d0tBMdrVXVAmxaQFEfnyhYWxz/gq77EFmPWn9y8FBSX5+k77L+DvktxW/tM4+
# pTFRhLy/AsGConsXHRWJjXD+57XQKBqJC4822rpM+Zv/Cuk0+CQ1ZyvgDbjmjJnW
# 4SLq8CdCPSWU5nR0W2rRnj7tfqAxM328y+l7vzhwRNGQ8cirOoo6CGJ/2XBjU02N
# 7oJtpQUQwXEGahC0HVUzWLOhcGbyoYIDWTCCAkECAQEwggEBoYHZpIHWMIHTMQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNy
# b3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJzAlBgNVBAsTHm5TaGll
# bGQgVFNTIEVTTjo2QjA1LTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9zb2Z0IFRp
# bWUtU3RhbXAgU2VydmljZaIjCgEBMAcGBSsOAwIaAxUAKyp8q2VdgAq1VGkzd7PZ
# wV6zNc2ggYMwgYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv
# bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0
# aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDANBgkq
# hkiG9w0BAQsFAAIFAO4hjKQwIhgPMjAyNjA4MDgxMTA4MjBaGA8yMDI2MDgwOTEx
# MDgyMFowdzA9BgorBgEEAYRZCgQBMS8wLTAKAgUA7iGMpAIBADAKAgEAAgISWAIB
# /zAHAgEAAgISbTAKAgUA7iLeJAIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEE
# AYRZCgMCoAowCAIBAAIDB6EgoQowCAIBAAIDAYagMA0GCSqGSIb3DQEBCwUAA4IB
# AQBkNSlv58dwYIU6sXgCll+ub/YaNmbz8RBEwJGWEs+2uGyR5qbmu790YlBNQM4m
# 0yH7JWZyFktlX51NcAsBpaHhmbKaGGNOeyx8OfmUMEre1kvnVgmZ7WwiHYU+i8Wj
# xCwuKHiJxdwWSoWh1z4XhXnKxCElXQJ0rxU49jd9Zm/bWsiCHvNnvQQ1YdRn+5pi
# GJ2MsfjXGtvD9SluFzrTUz5ph5BW3CgfM41ElsB23byDqwl7m8LAKqtOUqLh3+dX
# A6HB4qxJNXeAuZubvUS4y+nIvCAoJyFnJ2c/gBz2zQzO1NBsJFjLMI0D8dsba1d/
# qFy2b0SLYXPZCyqLJmZAylLsMYIEDTCCBAkCAQEwgZMwfDELMAkGA1UEBhMCVVMx
# EzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoT
# FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUt
# U3RhbXAgUENBIDIwMTACEzMAAAIRRRg5m0PP/GwAAQAAAhEwDQYJYIZIAWUDBAIB
# BQCgggFKMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0BCQQx
# IgQgqNQD6rVcyLQCeNmMu+k2eo+w6TvFp+m1WtlHplpn5ukwgfoGCyqGSIb3DQEJ
# EAIvMYHqMIHnMIHkMIG9BCAsrTOpmu+HTq1aXFwvlhjF8p2nUCNNCEX/OWLHNDMm
# tzCBmDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw
# DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
# JjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAACEUUY
# OZtDz/xsAAEAAAIRMCIEIEj+X8hc4D4LMhQobr/U9zAfx4P6I5LalDYGlO/FCCLl
# MA0GCSqGSIb3DQEBCwUABIICALgDPzEoFQoTe+8sBcd1XYegkwpaDLPPfNG8Jfcq
# 07jz3ReTfFZY+OE3xZ4CD47BrbkqcUwb/IMvGxLm/1SJkhkZAYkyhptcQ2CxHlxY
# yYyOpqYlB7cnk/xn4+S+73b323JE/E5YV8Weq5bgXgqK58aBcP8PHsqSDol290VX
# TgOfxThrlNdDCu9xaYrj2w431xtWnbDr7F8jULyT2DDbLtoq5dmis/q4z1kk6cem
# nZrEVeLarsyJ0u2N07ab8yG/NRqH2ORqE6xDJ8Ir9EClG0jQbayfRUgNEAElgEAm
# vFaEXADSijcwFbrKymKMMIbvOoTq8CLycmp8vuZTwV+f7txGUqzwjgPYuYxRAqFh
# 7uQEkwH6xyp+zzX8oofNBhLA2N/ACB2MLzFtCIDJDSRgqnIYgOLyIAytgMV/tZuP
# itt3NEhllrOj7qmNTuC/YMqAbMIsNKHRfeQ/hENwXziiQULDo9gSsMCc2ar3whTa
# plF5ayPZTr0AGnV1f3ItSur53Kwyfon2a5BzWAXrzyV1MPPm6y+jZ0VPU9Lj0c7s
# YGb8WhcRG8P+kH7NVW4decPq5KWmzhq7yrE+EU48iCzkQEqWfbeTbrDcV2odcvLV
# b/1o2eZTAhKEUGhWO0vIfuXUe/QpuaKQVIft/Boa7L3xJaemaPkOcwBZU8MXKvMs
# cbhk
# SIG # End signature block