AzStackHciSBEHealth/AzStackHci.SBEHealth.Helpers.psm1
Import-LocalizedData -BindingVariable locSbeTxt -FileName AzStackHci.SBEHealth.Strings.psd1 function Get-ASArtifactPathLite { <# .SYNOPSIS Returns the nuget content path. Same as normal Get-ArtifactPath except it doesn't use Trace-Execution or try to locate on ProductVHD. .DESCRIPTION Calculates and returns the path to the nuget content folder for the specified nuget on the current infrastructure vm environment. All product artifacts are exposed to the infrastructure vms, however the location is not fixed, this method is used to find the desired content. .EXAMPLE $Path = Get-ASArtifactPathLite -NugetName "Microsoft.Diagnostics.Tracing.EventSource.Redist" .PARAMETER NugetName The full name of the nuget without version information. .PARAMETER Version The optional version number of the package. #> [CmdletBinding()] PARAM ( [Parameter(Position=0, Mandatory=$true)] [ValidateNotNullOrEmpty()] [System.String] $NugetName, [Parameter(Mandatory=$false)] [System.String] $Version = $null ) PROCESS { $VerbosePreference = [System.Management.Automation.ActionPreference]::Continue Import-Module PackageManagement -DisableNameChecking -Verbose:$false | Out-Null $nugetProvider = get-packageprovider | where { $_.Name -eq "Nuget" } if ($nugetProvider -eq $null) { Log-Info -Message "Attempting to install nuget package provider." install-packageprovider nuget -Force -ForceBootstrap } $drivePath = "$env:SystemDrive\NugetStore" if(Test-Path -Path $drivePath) { if ($Version) { $package = Get-Package -Name $NugetName -Destination $drivePath -ErrorAction Stop -RequiredVersion $Version -ProviderName Nuget } else { $package = Get-Package -Name $NugetName -Destination $drivePath -ErrorAction Stop -ProviderName Nuget } Log-Info -Message "Get-Package returned with Success:$($?)" } if ($package -eq $null) { throw "Could not find package $NugetName on source $drivePath." } Log-Info -Message "Found package $($package.Name) with version $($package.Version) at $($package.Source)." return [System.IO.Path]::GetDirectoryName($package.Source); } } function Copy-SBEContentLocalToNode { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [string]$PackagePath, [Parameter(Mandatory=$true)] [string]$TargetNodeName, [Parameter(Mandatory=$false)] [string[]]$ExcludeDirs, [Parameter(Mandatory=$false)] [string[]]$ExcludeFiles, [PSCredential]$Credential ) $copyItems = @() # Note - this function only works on the seed node as only it will have NugetStore bootstrapped. $sbeConfig = Get-ASArtifactPathLite -NugetName "Microsoft.AzureStack.SBEConfiguration" $sbeRoleNuget = Get-ASArtifactPathLite -NugetName "Microsoft.AzureStack.Role.SBE" if ($Credential) { Log-Info ("Username is '{0}'" -f $Credential.UserName) } else { # Credential is not needed if the target is the seed node (in this case it is copying to itself) Log-Info "Credential was not provided" } # Check if the copy destination is the seed node $targetIsSeedNode = $false if ($env:ComputerName -eq $TargetNodeName) { Log-Info "ComputerName matched TargetNodeName" $targetIsSeedNode = $true } else { $thisComputerName = $null $dnsName = ((Resolve-DnsName -Name $TargetNodeName -ErrorAction SilentlyContinue) | Select-Object -First 1) if ($dnsName.NameHost) { # Case when IP is resolved $thisComputerName = ($dnsName.NameHost).Split('.')[0] if ($env:ComputerName -eq $thisComputerName) { Log-Info "ComputerName matched Resolve-DnsName by IP address" $targetIsSeedNode = $true } } elseif ($dnsName.Name) { # Case when hostname is resolved $thisComputerName = ($dnsName.Name).Split('.')[0] if ($env:ComputerName -eq $thisComputerName) { Log-Info "ComputerName matched Resolve-DnsName by hostname" $targetIsSeedNode = $true } } else { # No DNS match so try IP address instead [array]$myIP = (Get-NetIPAddress).IPAddress if ($TargetNodeName -in $myIP) { Log-Info "TargetNodeName was matched in the myIP list" $targetIsSeedNode = $true } } } if ($true -eq $targetIsSeedNode) { Log-Info "Target node is the seed node, so use local path as destination" $dest = Join-Path -Path $env:SystemDrive -ChildPath "SBE\Extracted" } else { Log-Info "Target node is a remote node, so need to map a PSDrive" Get-PSDrive -Name SBE -ErrorAction SilentlyContinue | Remove-PSDrive -Force $root = '\\' + $TargetNodeName + '\' + ($env:SystemDrive ).Replace(':','$') $dest = $root + '\SBE\Extracted' $sbeConfigDest = Join-Path -Path $root -ChildPath ($sbeConfig.Replace($env:SystemDrive,'')) $sbeRoleDest = Join-Path -Path $root -ChildPath ($sbeRoleNuget.Replace($env:SystemDrive,'')) $retry = $true $maxRetry = 4 $attempt = 0 while ($true -eq $retry) { $attempt++ Log-Info "Map New-PSDrive to '$($root)', attempt '$($attempt)/$($maxRetry)'" try { $drv = New-PSDrive -Credential $Credential -Name SBE -PSProvider FileSystem -Root $root -ErrorAction SilentlyContinue } catch { $errMessage = $PSItem.Exception.Message Log-Info "New-PSDrive failed with exception: $($errMessage)" } $found = Get-PSDrive -Name SBE if ($found -and $found.Root -eq $root) { $errMessage = '' $retry = $false } else { if ($attempt -ge $maxRetry) { throw "Failed to map New-PSDrive after '$($attempt)' attempts. Exception: '$($errMessage)'" $retry = $false } Start-Sleep -Seconds 15 } } } $copyItems += @{Source=$PackagePath;Destination=$dest} if (-not([string]::IsNullOrWhitespace($sbeConfigDest))) { $copyItems += @{Source=$sbeConfig;Destination=$sbeConfigDest} } if (-not([string]::IsNullOrWhitespace($sbeRoleDest))) { $copyItems += @{Source=$sbeRoleNuget;Destination=$sbeRoleDest} } [string]$exclude = "" if ($ExcludeFiles.Count -ne 0) { $exclude += " /XF $ExcludeFiles" } if ($ExcludeDirs.Count -ne 0) { $exclude += " /XD $ExcludeDirs" } foreach ($item in $copyItems) { Log-Info -Message ($locSbeTxt.CopySBEToNode -f $item.Source, $item.Destination) -Type Info $copyCmd = "robocopy.exe $($item.Source) $($item.Destination) *.* /MIR /NP /R:2 /W:10$exclude" $output = Invoke-Command -ScriptBlock { cmd.exe /c $copyCmd } # Check for exit code. If exit code is greater than 7, an error occurred while peforming the copy operation. if ($LASTEXITCODE -ge 8) { Log-Info -Message ($locSbeTxt.RobocopyFailed -f $LASTEXITCODE) -ConsoleOut -Type Error Log-Info -Message ($output | Out-String).Trim() -ConsoleOut -Type Info if ($drv) { $drv | Remove-PSDrive -ErrorAction SilentlyContinue } return $false } } if ($drv) { $drv | Remove-PSDrive -ErrorAction SilentlyContinue } return $true } function Get-SBEHealthCheckParams { [CmdletBinding()] param ( [Parameter()] [CloudEngine.Configurations.EceInterfaceParameters] $ECEParameters ) $sbeRoleNuget = Get-ASArtifactPathLite -NugetName "Microsoft.AzureStack.Role.SBE" Import-Module "$($sbeRoleNuget)\content\Helpers\SBESolutionExtensionHelper.psm1" -Force -ErrorAction Stop -Verbose:$false -DisableNameChecking -Global | Out-Null $sbePartnerProps = Get-SBEPartnerProperties -SBERoleConfig $ECEParameters.Roles["SBE"].PublicConfiguration $sbeCredList = Get-SBECredentialList -Parameters $ECEParameters $sbeHostData = Get-AllNodesData -BareMetalConfig $ECEParameters.Roles["BareMetal"].PublicConfiguration $params = @{ CredentialList = $sbeCredList HostData = $sbeHostData PartnerProperties = $sbePartnerProps Tag = $Tag } return $params } function Test-SBEPropertiesValid { [CmdletBinding()] param ( [Parameter()] [CloudEngine.Configurations.EceInterfaceParameters] $ECEParameters ) $sbeRoleNuget = Get-ASArtifactPathLite -NugetName "Microsoft.AzureStack.Role.SBE" Import-Module "$($sbeRoleNuget)\content\Helpers\SBESolutionExtensionHelper.psm1" -Force -ErrorAction Stop -Verbose:$false -DisableNameChecking -Global | Out-Null $sbePartnerProps = Get-SBEPartnerProperties -SBERoleConfig $ECEParameters.Roles["SBE"].PublicConfiguration Log-Info -Message "Found '$($sbePartnerProps.Count)' PartnerProperties." -Type Info } function Test-SBECredentialsValid { [CmdletBinding()] param ( [Parameter()] [CloudEngine.Configurations.EceInterfaceParameters] $ECEParameters ) $sbeRoleNuget = Get-ASArtifactPathLite -NugetName "Microsoft.AzureStack.Role.SBE" Import-Module "$($sbeRoleNuget)\content\Helpers\SBESolutionExtensionHelper.psm1" -Force -ErrorAction Stop -Verbose:$false -DisableNameChecking -Global | Out-Null $sbeCredList = Get-SBECredentialList -Parameters $ECEParameters } function Test-SolutionExtensionModule { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [string] $PackagePath, [Parameter()] [System.Management.Automation.Runspaces.PSSession] $PsSession ) $ErrorActionPreference = [System.Management.Automation.ActionPreference]::Stop $solExtModule = $null Log-Info -Message ($locSbeTxt.SBEPackagePath -f $PackagePath) -Type Info if ($PSSession) { $computername = $PsSession.ComputerName } else { $computername = $env:ComputerName } # Validate the SolutionExtension module using a function from the SBE Role Helper module $sbValidate = { param( [String] [parameter(Mandatory=$true)] $PackagePath, [String] [parameter(Mandatory=$true)] $SbeRoleNuget ) try { Import-Module "$SbeRoleNuget\content\Helpers\SBESolutionExtensionHelper.psm1" -Force -ErrorAction Stop -Verbose:$false -DisableNameChecking -Global | Out-Null $solExtModulePath = Join-Path -Path $PackagePath -ChildPath "Configuration\SolutionExtension" $solExtModule = Initialize-SolutionExtensionModule -SolExtFilePath $solExtModulePath -RequireTag "HealthServiceIntegration" -AssertCertificate return $solExtModule } catch { Write-Output "An exception occurred while validating the SolutionExtension module: " + ($PSItem | Format-List * | Out-String).Trim() } } $sbeRoleNuget = Get-ASArtifactPathLite -NugetName "Microsoft.AzureStack.Role.SBE" $solExtModule = if ($PsSession) { Invoke-Command -Session $PsSession -ScriptBlock $sbValidate -ArgumentList @($PackagePath, $sbeRoleNuget) } else { Invoke-Command -ScriptBlock $sbValidate -ArgumentList @($PackagePath, $sbeRoleNuget) } if ($null -eq $solExtModule) { Log-Info -Message ($locSbeTxt.NoHeatlhChecks) -Type Info return $false } elseif ($solExtModule -match "An exception occurred") { throw $solExtModule } return $true } function Invoke-TestSBEContentIntegrity { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [string] $SBEMetadataPath, [Parameter(Mandatory=$true)] [string] $SBEContentPath, [Parameter()] [System.Management.Automation.Runspaces.PSSession] $PsSession ) $sbIntegrity = { param( [String] [parameter(Mandatory=$true)] $SBEMetadataPath, [String] [parameter(Mandatory=$true)] $SBEContentPath, [String] [parameter(Mandatory=$true)] $SbeRoleNuget ) try { if (-not(Get-Command -Name Test-SBEContentIntegrity -ErrorAction SilentlyContinue)) { Import-Module "$($SbeRoleNuget)\content\Helpers\SBESolutionExtensionHelper.psm1" -Force -ErrorAction Stop -Verbose:$false -DisableNameChecking -Global | Out-Null } $skipDir = @("IntegratedContent") Test-SBEContentIntegrity -SBEMetadataDirPath $SBEMetadataPath -SBEContentPath $SBEContentPath -IgnoreTopLevelFolder $skipDir } catch { throw $PSItem } } $sbeRoleNuget = Get-ASArtifactPathLite -NugetName "Microsoft.AzureStack.Role.SBE" $result = if ($PsSession) { Invoke-Command -Session $PsSession -ScriptBlock $sbIntegrity -ArgumentList @($SBEMetadataPath, $SBEContentPath, $sbeRoleNuget) } else { Invoke-Command -ScriptBlock $sbIntegrity -ArgumentList @($SBEMetadataPath, $SBEContentPath, $sbeRoleNuget) } return $result } function Import-SolutionExtensionModule { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [string] $PackagePath, [Parameter()] [System.Management.Automation.Runspaces.PSSession] $PsSession ) $ErrorActionPreference = [System.Management.Automation.ActionPreference]::Stop # Import the SolutionExtension module $solExtModule = (Join-Path -Path $PackagePath -ChildPath "Configuration\SolutionExtension\SolutionExtension.psd1") Log-Info -Message ($locSbeTxt.ModuleToImport -f $solExtModule) -Type Info $sbImport = { param( [String] [parameter(Mandatory=$true)] $SolExtModule ) try { Import-Module $SolExtModule -Force -ErrorAction Stop -Verbose:$false -DisableNameChecking -Global | Out-Null } catch { Write-Output "An error occurred while importing the SolutionExtension module: " + ($PSItem | Format-List * | Out-String).Trim() } } $result = if ($PsSession) { Invoke-Command -Session $PsSession -ScriptBlock $sbImport -ArgumentList @($solExtModule) } else { Invoke-Command -ScriptBlock $sbImport -ArgumentList @($solExtModule) } if ($result -match "An exception occurred") { throw $solExtModule } return $true } function New-SBEHealthResultObject { param ( [Parameter(Mandatory=$true)] [string]$TargetName, [Parameter()] [string]$TestName, [Parameter()] [ValidateSet('CRITICAL','WARNING','INFORMATIONAL')] [string]$Severity = 'INFORMATIONAL', [Parameter()] [ValidateSet('SUCCESS', 'FAILURE', 'ERROR')] [string]$Status, [Parameter()] [string]$Description, [Parameter()] [string]$Detail, [Parameter()] [bool]$PopulateAdditionalData = $true ) $name = 'AzStackHci_SBEHealth' $title = 'SBE' if (-not([string]::IsNullOrWhiteSpace($TestName))) { $name += "_$TestName" $title += " $TestName" } $name += "_$TargetName" if (-not($title.EndsWith(" Health Check"))) { $title += " Health Check" } $params = @{ Name = $name Title = $title DisplayName = $title Severity = $Severity Description = $Description Tags = @{} Remediation = '' TargetResourceID = $TargetName TargetResourceName = $TargetName TargetResourceType = 'SBEHealth' Timestamp = [datetime]::UtcNow Status = $Status AdditionalData = @{ Source = $TargetName Resource = 'SBEHealth' Detail = $Detail Status = $Status TimeStamp = $resultObj.Timestamp } HealthCheckSource = $ENV:EnvChkrId } $resultObj = New-AzStackHciResultObject @params return $resultObj } function Get-ResultObject { $resultObject = @{ "Name" = "" "DisplayName" = "" "Title"= "" "Description" = "" "Status" = "" "Severity" = "" "Timestamp" = "" "TargetResourceID" = "" "TargetResourceName" = "" "TargetResourceType" = "" "Tags" = @{} "AdditionalData" = @{} "HealthCheckSource" = "" "Remediation" = "" } return $resultObject } function Assert-ResponseSchemaValid { [CmdletBinding()] param ( [PSObject[]]$ResultObject ) $expectedSchema = Get-ResultObject foreach ($item in $ResultObject) { # Assert Name or Title must contain information if ([string]::IsNullOrWhiteSpace($item.Name) -and [string]::IsNullOrWhiteSpace($item.Title)) { $msg = "Both Name and Title properties of this result object are empty" Log-Info -Message $msg -Type Error $item.AdditionalData.NameTitleEmpty = $msg $item.Severity = 'CRITICAL' $item.Status = "Error" } elseif ([string]::IsNullOrWhiteSpace($item.Name)) { $item.Name = $item.Title } elseif ([string]::IsNullOrWhiteSpace($item.Title)) { $item.Title = $item.Name } # Assert response contains expected schema properties foreach ($expectedKey in $expectedSchema.Keys) { if (-not($item.ContainsKey($expectedKey))) { # TODO : Temporary special case to add DisplayName if missing due to this being added after partner communication if ($key -eq "DisplayName") { $item.DisplayName = $item.Title } else { Log-Info -Message "Expected result property '$($expectedKey)' was not found" -Type Warning $item.$expectedKey = "" # TODO : In the future, we should decide how to better handle these cases of missing properties } } } # Assert Status values if ($item.Status -notin @("Success", "Failure", "Error")) { $msg = "Unexpected Status: '$($item.Status)'" Log-Info -Message $msg $item.AdditionalData.StatusDiscrepancy = $msg $item.Status = "Error" } # Assert Severity values if ($item.Severity -notin @('CRITICAL', 'WARNING', 'INFORMATIONAL')) { $msg = "Unexpected Severity: '$($item.Severity)'" $item.AdditionalData.SeverityDiscrepancy = $msg if ($item.Status -eq "Success") { $item.Severity = 'WARNING' Log-Info -Message $msg -Type Warning } else { $item.Severity = 'CRITICAL' Log-Info -Message $msg -Type Error } } } return $ResultObject } Export-ModuleMember -Function Test-* Export-ModuleMember -Function New-SBEHealthResultObject Export-ModuleMember -Function Get-SBEHealthCheckParams Export-ModuleMember -Function Copy-SBEContentLocalToNode Export-ModuleMember -Function Import-SolutionExtensionModule Export-ModuleMember -Function Assert-ResponseSchemaValid Export-ModuleMember -Function Invoke-TestSBEContentIntegrity # SIG # Begin signature block # MIInwgYJKoZIhvcNAQcCoIInszCCJ68CAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDpw5cNMmiK93jz # SueH69Qynes8SRhYV+fVwvP9Ki16raCCDXYwggX0MIID3KADAgECAhMzAAADrzBA # DkyjTQVBAAAAAAOvMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMjMxMTE2MTkwOTAwWhcNMjQxMTE0MTkwOTAwWjB0MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQDOS8s1ra6f0YGtg0OhEaQa/t3Q+q1MEHhWJhqQVuO5amYXQpy8MDPNoJYk+FWA # hePP5LxwcSge5aen+f5Q6WNPd6EDxGzotvVpNi5ve0H97S3F7C/axDfKxyNh21MG # 0W8Sb0vxi/vorcLHOL9i+t2D6yvvDzLlEefUCbQV/zGCBjXGlYJcUj6RAzXyeNAN # xSpKXAGd7Fh+ocGHPPphcD9LQTOJgG7Y7aYztHqBLJiQQ4eAgZNU4ac6+8LnEGAL # go1ydC5BJEuJQjYKbNTy959HrKSu7LO3Ws0w8jw6pYdC1IMpdTkk2puTgY2PDNzB # tLM4evG7FYer3WX+8t1UMYNTAgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE # AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQURxxxNPIEPGSO8kqz+bgCAQWGXsEw # RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW # MBQGA1UEBRMNMjMwMDEyKzUwMTgyNjAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci # tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j # b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG # CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu # Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0 # MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAISxFt/zR2frTFPB45Yd # mhZpB2nNJoOoi+qlgcTlnO4QwlYN1w/vYwbDy/oFJolD5r6FMJd0RGcgEM8q9TgQ # 2OC7gQEmhweVJ7yuKJlQBH7P7Pg5RiqgV3cSonJ+OM4kFHbP3gPLiyzssSQdRuPY # 1mIWoGg9i7Y4ZC8ST7WhpSyc0pns2XsUe1XsIjaUcGu7zd7gg97eCUiLRdVklPmp # XobH9CEAWakRUGNICYN2AgjhRTC4j3KJfqMkU04R6Toyh4/Toswm1uoDcGr5laYn # TfcX3u5WnJqJLhuPe8Uj9kGAOcyo0O1mNwDa+LhFEzB6CB32+wfJMumfr6degvLT # e8x55urQLeTjimBQgS49BSUkhFN7ois3cZyNpnrMca5AZaC7pLI72vuqSsSlLalG # OcZmPHZGYJqZ0BacN274OZ80Q8B11iNokns9Od348bMb5Z4fihxaBWebl8kWEi2O # PvQImOAeq3nt7UWJBzJYLAGEpfasaA3ZQgIcEXdD+uwo6ymMzDY6UamFOfYqYWXk # ntxDGu7ngD2ugKUuccYKJJRiiz+LAUcj90BVcSHRLQop9N8zoALr/1sJuwPrVAtx # HNEgSW+AKBqIxYWM4Ev32l6agSUAezLMbq5f3d8x9qzT031jMDT+sUAoCw0M5wVt # CUQcqINPuYjbS1WgJyZIiEkBMIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq # 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 # /Xmfwb1tbWrJUnMTDXpQzTGCGaIwghmeAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw # EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN # aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp # Z25pbmcgUENBIDIwMTECEzMAAAOvMEAOTKNNBUEAAAAAA68wDQYJYIZIAWUDBAIB # BQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO # MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIMA7STfrJK4ZHmKV4LKHemuL # w0ZPLCyDiDcil2DVAO4bMEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A # cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB # BQAEggEAZsTyA/ibYHPki9RHfj+vQWhCO2O6Rg3d3DUKH0hFmhMwSp69I5AUKFbG # G9wqWJ1mgedKKp0zuHApLjRNqfPA9w+IR8PyNL0jtoM29OhYFeBMrAUOz0A79akT # WsAFgRjyEazGzx/tYxTVGSbema5bYy7LstZxVwAmyfazyNfcvTZ7jFrmGfDUsZo0 # JIp1WMrRjnxZY7MBJqjdp7AgcfFjuUJy0i3cKei39yW75YxD/UH/Q2+/e17bSKOF # j7Ja3Jwsx2naswqNrE8kGPoyTuF48y36cKFL1ny/7KvNyGrp24aWT4So0Z1b9CSt # HRdWNJUenRBjln7BKPOVVEgqNuax06GCFywwghcoBgorBgEEAYI3AwMBMYIXGDCC # FxQGCSqGSIb3DQEHAqCCFwUwghcBAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFZBgsq # hkiG9w0BCRABBKCCAUgEggFEMIIBQAIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl # AwQCAQUABCAMmpsJGmi+Cu+UoYCuxCs9glmoYwLF8P67WusLSiAnUwIGZnLCoNeD # GBMyMDI0MDcwOTA4NTQwMS40NjdaMASAAgH0oIHYpIHVMIHSMQswCQYDVQQGEwJV # UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE # ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJl # bGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNO # OjJBRDQtNEI5Mi1GQTAxMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBT # ZXJ2aWNloIIRezCCBycwggUPoAMCAQICEzMAAAHenkielp8oRD0AAQAAAd4wDQYJ # KoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x # EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv # bjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwHhcNMjMx # MDEyMTkwNzEyWhcNMjUwMTEwMTkwNzEyWjCB0jELMAkGA1UEBhMCVVMxEzARBgNV # BAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv # c29mdCBDb3Jwb3JhdGlvbjEtMCsGA1UECxMkTWljcm9zb2Z0IElyZWxhbmQgT3Bl # cmF0aW9ucyBMaW1pdGVkMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjoyQUQ0LTRC # OTItRkEwMTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZTCC # AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALSB9ByF9UIDhA6xFrOniw/x # sDl8sSi9rOCOXSSO4VMQjnNGAo5VHx0iijMEMH9LY2SUIBkVQS0Ml6kR+TagkUPb # aEpwjhQ1mprhRgJT/jlSnic42VDAo0en4JI6xnXoAoWoKySY8/ROIKdpphgI7OJb # 4XHk1P3sX2pNZ32LDY1ktchK1/hWyPlblaXAHRu0E3ynvwrS8/bcorANO6Djuysy # S9zUmr+w3H3AEvSgs2ReuLj2pkBcfW1UPCFudLd7IPZ2RC4odQcEPnY12jypYPnS # 6yZAs0pLpq0KRFUyB1x6x6OU73sudiHON16mE0l6LLT9OmGo0S94Bxg3N/3aE6fU # bnVoemVc7FkFLum8KkZcbQ7cOHSAWGJxdCvo5OtUtRdSqf85FklCXIIkg4sm7nM9 # TktUVfO0kp6kx7mysgD0Qrxx6/5oaqnwOTWLNzK+BCi1G7nUD1pteuXvQp8fE1Kp # TjnG/1OJeehwKNNPjGt98V0BmogZTe3SxBkOeOQyLA++5Hyg/L68pe+DrZoZPXJa # GU/iBiFmL+ul/Oi3d83zLAHlHQmH/VGNBfRwP+ixvqhyk/EebwuXVJY+rTyfbRfu # h9n0AaMhhNxxg6tGKyZS4EAEiDxrF9mAZEy8e8rf6dlKIX5d3aQLo9fDda1ZTOw+ # XAcAvj2/N3DLVGZlHnHlAgMBAAGjggFJMIIBRTAdBgNVHQ4EFgQUazAmbxseaapg # dxzK8Os+naPQEsgwHwYDVR0jBBgwFoAUn6cVXQBeYl2D9OXSZacbUzUZ6XIwXwYD # VR0fBFgwVjBUoFKgUIZOaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9j # cmwvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBDQSUyMDIwMTAoMSkuY3JsMGwG # CCsGAQUFBwEBBGAwXjBcBggrBgEFBQcwAoZQaHR0cDovL3d3dy5taWNyb3NvZnQu # Y29tL3BraW9wcy9jZXJ0cy9NaWNyb3NvZnQlMjBUaW1lLVN0YW1wJTIwUENBJTIw # MjAxMCgxKS5jcnQwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcD # CDAOBgNVHQ8BAf8EBAMCB4AwDQYJKoZIhvcNAQELBQADggIBAOKUwHsXDacGOvUI # gs5HDgPs0LZ1qyHS6C6wfKlLaD36tZfbWt1x+GMiazSuy+GsxiVHzkhMW+FqK8gr # uLQWN/sOCX+fGUgT9LT21cRIpcZj4/ZFIvwtkBcsCz1XEUsXYOSJUPitY7E8bbld # mmhYZ29p+XQpIcsG/q+YjkqBW9mw0ru1MfxMTQs9MTDiD28gAVGrPA3NykiSChvd # qS7VX+/LcEz9Ubzto/w28WA8HOCHqBTbDRHmiP7MIj+SQmI9VIayYsIGRjvelmNa # 0OvbU9CJSz/NfMEgf2NHMZUYW8KqWEjIjPfHIKxWlNMYhuWfWRSHZCKyIANA0aJL # 4soHQtzzZ2MnNfjYY851wHYjGgwUj/hlLRgQO5S30Zx78GqBKfylp25aOWJ/qPhC # +DXM2gXajIXbl+jpGcVANwtFFujCJRdZbeH1R+Q41FjgBg4m3OTFDGot5DSuVkQg # jku7pOVPtldE46QlDg/2WhPpTQxXH64sP1GfkAwUtt6rrZM/PCwRG6girYmnTRLL # sicBhoYLh+EEFjVviXAGTk6pnu8jx/4WPWu0jsz7yFzg82/FMqCk9wK3LvyLAyDH # N+FxbHAxtgwad7oLQPM0WGERdB1umPCIiYsSf/j79EqHdoNwQYROVm+ZX10RX3n6 # bRmAnskeNhi0wnVaeVogLMdGD+nqMIIHcTCCBVmgAwIBAgITMwAAABXF52ueAptJ # mQAAAAAAFTANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT # Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m # dCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNh # dGUgQXV0aG9yaXR5IDIwMTAwHhcNMjEwOTMwMTgyMjI1WhcNMzAwOTMwMTgzMjI1 # WjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH # UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQD # Ex1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDCCAiIwDQYJKoZIhvcNAQEB # BQADggIPADCCAgoCggIBAOThpkzntHIhC3miy9ckeb0O1YLT/e6cBwfSqWxOdcjK # NVf2AX9sSuDivbk+F2Az/1xPx2b3lVNxWuJ+Slr+uDZnhUYjDLWNE893MsAQGOhg # fWpSg0S3po5GawcU88V29YZQ3MFEyHFcUTE3oAo4bo3t1w/YJlN8OWECesSq/XJp # rx2rrPY2vjUmZNqYO7oaezOtgFt+jBAcnVL+tuhiJdxqD89d9P6OU8/W7IVWTe/d # vI2k45GPsjksUZzpcGkNyjYtcI4xyDUoveO0hyTD4MmPfrVUj9z6BVWYbWg7mka9 # 7aSueik3rMvrg0XnRm7KMtXAhjBcTyziYrLNueKNiOSWrAFKu75xqRdbZ2De+JKR # Hh09/SDPc31BmkZ1zcRfNN0Sidb9pSB9fvzZnkXftnIv231fgLrbqn427DZM9itu # qBJR6L8FA6PRc6ZNN3SUHDSCD/AQ8rdHGO2n6Jl8P0zbr17C89XYcz1DTsEzOUyO # ArxCaC4Q6oRRRuLRvWoYWmEBc8pnol7XKHYC4jMYctenIPDC+hIK12NvDMk2ZItb # oKaDIV1fMHSRlJTYuVD5C4lh8zYGNRiER9vcG9H9stQcxWv2XFJRXRLbJbqvUAV6 # bMURHXLvjflSxIUXk8A8FdsaN8cIFRg/eKtFtvUeh17aj54WcmnGrnu3tz5q4i6t # AgMBAAGjggHdMIIB2TASBgkrBgEEAYI3FQEEBQIDAQABMCMGCSsGAQQBgjcVAgQW # BBQqp1L+ZMSavoKRPEY1Kc8Q/y8E7jAdBgNVHQ4EFgQUn6cVXQBeYl2D9OXSZacb # UzUZ6XIwXAYDVR0gBFUwUzBRBgwrBgEEAYI3TIN9AQEwQTA/BggrBgEFBQcCARYz # aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9Eb2NzL1JlcG9zaXRvcnku # aHRtMBMGA1UdJQQMMAoGCCsGAQUFBwMIMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIA # QwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNX2 # VsuP6KJcYmjRPZSQW9fOmhjEMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwu # bWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dF8yMDEw # LTA2LTIzLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93 # d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYt # MjMuY3J0MA0GCSqGSIb3DQEBCwUAA4ICAQCdVX38Kq3hLB9nATEkW+Geckv8qW/q # XBS2Pk5HZHixBpOXPTEztTnXwnE2P9pkbHzQdTltuw8x5MKP+2zRoZQYIu7pZmc6 # U03dmLq2HnjYNi6cqYJWAAOwBb6J6Gngugnue99qb74py27YP0h1AdkY3m2CDPVt # I1TkeFN1JFe53Z/zjj3G82jfZfakVqr3lbYoVSfQJL1AoL8ZthISEV09J+BAljis # 9/kpicO8F7BUhUKz/AyeixmJ5/ALaoHCgRlCGVJ1ijbCHcNhcy4sa3tuPywJeBTp # kbKpW99Jo3QMvOyRgNI95ko+ZjtPu4b6MhrZlvSP9pEB9s7GdP32THJvEKt1MMU0 # sHrYUP4KWN1APMdUbZ1jdEgssU5HLcEUBHG/ZPkkvnNtyo4JvbMBV0lUZNlz138e # W0QBjloZkWsNn6Qo3GcZKCS6OEuabvshVGtqRRFHqfG3rsjoiV5PndLQTHa1V1QJ # sWkBRH58oWFsc/4Ku+xBZj1p/cvBQUl+fpO+y/g75LcVv7TOPqUxUYS8vwLBgqJ7 # Fx0ViY1w/ue10CgaiQuPNtq6TPmb/wrpNPgkNWcr4A245oyZ1uEi6vAnQj0llOZ0 # dFtq0Z4+7X6gMTN9vMvpe784cETRkPHIqzqKOghif9lwY1NNje6CbaUFEMFxBmoQ # tB1VM1izoXBm8qGCAtcwggJAAgEBMIIBAKGB2KSB1TCB0jELMAkGA1UEBhMCVVMx # EzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoT # FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEtMCsGA1UECxMkTWljcm9zb2Z0IElyZWxh # bmQgT3BlcmF0aW9ucyBMaW1pdGVkMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjoy # QUQ0LTRCOTItRkEwMTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2Vy # dmljZaIjCgEBMAcGBSsOAwIaAxUAaKBSisy4y86pl8Xy22CJZExE2vOggYMwgYCk # fjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH # UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQD # Ex1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQUFAAIF # AOo29GgwIhgPMjAyNDA3MDkwNzI3MzZaGA8yMDI0MDcxMDA3MjczNlowdzA9Bgor # BgEEAYRZCgQBMS8wLTAKAgUA6jb0aAIBADAKAgEAAgIa4QIB/zAHAgEAAgITJzAK # AgUA6jhF6AIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIB # AAIDB6EgoQowCAIBAAIDAYagMA0GCSqGSIb3DQEBBQUAA4GBAD2A7tJk9DAoC8Oc # +ielMNKvVut3EBLHaB8jthX0LVqgGlsGUnNwotqvXXAEdMvFLCdH3a5ffPJb8CWo # KmcfVOnJBneSdNNaWKxUC+QDOjPR+gkYRrCClXbG8q2ZxXkwxqIs8RtmyrP4yhIx # U2OlZ/+gUV3HJ39T5LzrbjfpcS+9MYIEDTCCBAkCAQEwgZMwfDELMAkGA1UEBhMC # VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV # BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRp # bWUtU3RhbXAgUENBIDIwMTACEzMAAAHenkielp8oRD0AAQAAAd4wDQYJYIZIAWUD # BAIBBQCgggFKMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0B # CQQxIgQgnqj0skaxhUeSf4bQRzSHK5v2hhCkMsYdn4DFrL0hSE0wgfoGCyqGSIb3 # DQEJEAIvMYHqMIHnMIHkMIG9BCCOPiOfDcFeEBBJAn/mC3MgrT5w/U2z81LYD44H # c34dezCBmDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9u # MRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp # b24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAAB # 3p5InpafKEQ9AAEAAAHeMCIEIHLphp75VJAw/Q+22JzJT4hvke1brS01dg5ald+d # CN20MA0GCSqGSIb3DQEBCwUABIICAI79nHFDSssl0EUEjYxkYfgkBRHVmPvkjMX8 # 50zFUJ/htPQWpl8cwbvgv5IzI4k38sHIWyQDsQmRPmWf2fuZkjY4LK0/9mTHVihe # tVo3P8CLkjkQvUwvz/LVXhG26IjZCR9uvrM2i7m2frV3bwlPcCTPGNccD/eBBn7u # ou6AhzoiricIlpLjeFmfKTMr4kLhbvSW5BUUCTkaq53p47/7iO5SIzz50iJ98QA6 # zRqdD9Emr//Ni1TpunsN7DY+FydX2IRhjZMGyvKvAAeL/R2Igi9QKHQBunGk2SAE # Iy3U29kBNWsJYmuDH2pW8rVI4+vGa8DqRU6hm5Wt83NXH7UxPJSGrR0O0Vn7eVVZ # VoRIJ90edXhW1Gl4AQ68DjaKQgzdOsbmRVFsjOq0oq8rnr25rCZlMGaE3sMbG/mf # s5VpmJ2hUa/Ln4mXnuSX9TUUxRYyS/HOsXxjFjXx5HokdqyugN1Q+p+n/CqetpvL # iPxKRwIn5+35FkfkySZAXhmYu/ZBxNWYvXbjjM9216h42EkL+H7BTwfMGZ6GWipC # qdzo6jzEKjuruzOlfy6/L3LCuKXPmqa+kVhKwoZljjqFewFHF0q6AvGdh6jB1Kpg # ilxV/LaCoWL/g16j0FJhErFaqYlvzUYAAabFxA0HHsukPDNPZTcpo37xX2ICutDf # FglW+HzP # SIG # End signature block |