Functions/Assertions/Be.ps1
#Be function Should-Be ($ActualValue, $ExpectedValue, [switch] $Negate, [string] $Because) { <# .SYNOPSIS Compares one object with another for equality and throws if the two objects are not the same. .EXAMPLE $actual = "Actual value" PS C:\>$actual | Should -Be "actual value" This test will pass. -Be is not case sensitive. For a case sensitive assertion, see -BeExactly. .EXAMPLE $actual = "Actual value" PS C:\>$actual | Should -Be "not actual value" This test will fail, as the two strings are not identical. #> [bool] $succeeded = ArraysAreEqual $ActualValue $ExpectedValue if ($Negate) { $succeeded = -not $succeeded } $failureMessage = '' if (-not $succeeded) { if ($Negate) { $failureMessage = NotShouldBeFailureMessage -ActualValue $ActualValue -Expected $ExpectedValue -Because $Because } else { $failureMessage = ShouldBeFailureMessage -ActualValue $ActualValue -Expected $ExpectedValue -Because $Because } } return & $SafeCommands['New-Object'] psobject -Property @{ Succeeded = $succeeded FailureMessage = $failureMessage } } function ShouldBeFailureMessage($ActualValue, $ExpectedValue, $Because) { # This looks odd; it's to unroll single-element arrays so the "-is [string]" expression works properly. $ActualValue = $($ActualValue) $ExpectedValue = $($ExpectedValue) if (-not (($ExpectedValue -is [string]) -and ($ActualValue -is [string]))) { return "Expected $(Format-Nicely $ExpectedValue),$(Format-Because $Because) but got $(Format-Nicely $ActualValue)." } <#joining the output strings to a single string here, otherwise I get Cannot find an overload for "Exception" and the argument count: "4". at line: 63 in C:\Users\nohwnd\github\pester\Functions\Assertions\Should.ps1 This is a quickwin solution, doing the join in the Should directly might be better way of doing this. But I don't want to mix two problems. #> (Get-CompareStringMessage -Expected $ExpectedValue -Actual $ActualValue -Because $Because) -join "`n" } function NotShouldBeFailureMessage($ActualValue, $ExpectedValue, $Because) { return "Expected $(Format-Nicely $ExpectedValue) to be different from the actual value,$(Format-Because $Because) but got the same value." } Add-AssertionOperator -Name Be ` -InternalName Should-Be ` -Test ${function:Should-Be} ` -Alias 'EQ' ` -SupportsArrayInput #BeExactly function Should-BeExactly($ActualValue, $ExpectedValue, $Because) { <# .SYNOPSIS Compares one object with another for equality and throws if the two objects are not the same. This comparison is case sensitive. .EXAMPLE $actual = "Actual value" PS C:\>$actual | Should -Be "Actual value" This test will pass. The two strings are identical. .EXAMPLE $actual = "Actual value" PS C:\>$actual | Should -Be "actual value" This test will fail, as the two strings do not match case sensitivity. #> [bool] $succeeded = ArraysAreEqual $ActualValue $ExpectedValue -CaseSensitive if ($Negate) { $succeeded = -not $succeeded } $failureMessage = '' if (-not $succeeded) { if ($Negate) { $failureMessage = NotShouldBeExactlyFailureMessage -ActualValue $ActualValue -ExpectedValue $ExpectedValue -Because $Because } else { $failureMessage = ShouldBeExactlyFailureMessage -ActualValue $ActualValue -ExpectedValue $ExpectedValue -Because $Because } } return New-Object psobject -Property @{ Succeeded = $succeeded FailureMessage = $failureMessage } } function ShouldBeExactlyFailureMessage($ActualValue, $ExpectedValue, $Because) { # This looks odd; it's to unroll single-element arrays so the "-is [string]" expression works properly. $ActualValue = $($ActualValue) $ExpectedValue = $($ExpectedValue) if (-not (($ExpectedValue -is [string]) -and ($ActualValue -is [string]))) { return "Expected exactly $(Format-Nicely $ExpectedValue),$(Format-Because $Because) but got $(Format-Nicely $ActualValue)." } <#joining the output strings to a single string here, otherwise I get Cannot find an overload for "Exception" and the argument count: "4". at line: 63 in C:\Users\nohwnd\github\pester\Functions\Assertions\Should.ps1 This is a quickwin solution, doing the join in the Should directly might be better way of doing this. But I don't want to mix two problems. #> (Get-CompareStringMessage -Expected $ExpectedValue -Actual $ActualValue -CaseSensitive -Because $Because) -join "`n" } function NotShouldBeExactlyFailureMessage($ActualValue, $ExpectedValue, $Because) { return "Expected $(Format-Nicely $ExpectedValue) to be different from the actual value,$(Format-Because $Because) but got exactly the same value." } Add-AssertionOperator -Name BeExactly ` -InternalName Should-BeExactly ` -Test ${function:Should-BeExactly} ` -Alias 'CEQ' ` -SupportsArrayInput #common functions function Get-CompareStringMessage { param( [Parameter(Mandatory = $true)] [AllowEmptyString()] [String]$ExpectedValue, [Parameter(Mandatory = $true)] [AllowEmptyString()] [String]$Actual, [switch]$CaseSensitive, $Because ) $ExpectedValueLength = $ExpectedValue.Length $actualLength = $actual.Length $maxLength = $ExpectedValueLength, $actualLength | & $SafeCommands['Sort-Object'] -Descending | & $SafeCommands['Select-Object'] -First 1 $differenceIndex = $null for ($i = 0; $i -lt $maxLength -and ($null -eq $differenceIndex); ++$i) { $differenceIndex = if ($CaseSensitive -and ($ExpectedValue[$i] -cne $actual[$i])) { $i } elseif ($ExpectedValue[$i] -ne $actual[$i]) { $i } } if ($null -ne $differenceIndex) { "Expected strings to be the same,$(Format-Because $Because) but they were different." if ($ExpectedValue.Length -ne $actual.Length) { "Expected length: $ExpectedValueLength" "Actual length: $actualLength" "Strings differ at index $differenceIndex." } else { "String lengths are both $ExpectedValueLength." "Strings differ at index $differenceIndex." } $ellipsis = "..." $excerptSize = 5; "Expected: '{0}'" -f ( $ExpectedValue | Format-AsExcerpt -startIndex $differenceIndex -excerptSize $excerptSize -excerptMarker $ellipsis | Expand-SpecialCharacters ) "But was: '{0}'" -f ( $actual | Format-AsExcerpt -startIndex $differenceIndex -excerptSize $excerptSize -excerptMarker $ellipsis | Expand-SpecialCharacters ) } } function Format-AsExcerpt { param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [AllowEmptyString()] [string]$InputObject, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [int]$startIndex, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [int]$excerptSize, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string]$excerptMarker ) $InputObjectDisplay="" $displayDifferenceIndex = $startIndex - $excerptSize $maximumStringLength = 40 $maximumSubstringLength = $excerptSize * 2 $substringLength = $InputObject.Length - $displayDifferenceIndex if ($substringLength -gt $maximumSubstringLength) { $substringLength = $maximumSubstringLength } if ($displayDifferenceIndex + $substringLength -lt $InputObject.Length) { $endExcerptMarker = $excerptMarker } if ($displayDifferenceIndex -lt 0) { $displayDifferenceIndex = 0 } if ($InputObject.length -ge $maximumStringLength) { if ($displayDifferenceIndex -ne 0) { $InputObjectDisplay = $excerptMarker } $InputObjectDisplay += $InputObject.Substring($displayDifferenceIndex, $substringLength) + $endExcerptMarker } else { $InputObjectDisplay = $InputObject } $InputObjectDisplay } function Expand-SpecialCharacters { param ( [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)] [AllowEmptyString()] [string[]]$InputObject) process { $InputObject -replace "`n", "\n" -replace "`r", "\r" -replace "`t", "\t" -replace "`0", "\0" -replace "`b", "\b" } } function ArraysAreEqual { param ( [object[]] $First, [object[]] $Second, [switch] $CaseSensitive, [int] $RecursionDepth = 0, [int] $RecursionLimit = 100 ) $RecursionDepth++ if ($RecursionDepth -gt $RecursionLimit) { throw "Reached the recursion depth limit of $RecursionLimit when comparing arrays $First and $Second. Is one of your arrays cyclic?" } # Do not remove the subexpression @() operators in the following two lines; doing so can cause a # silly error in PowerShell v3. (Null Reference exception from the PowerShell engine in a # method called CheckAutomationNullInCommandArgumentArray(System.Object[]) ). $firstNullOrEmpty = ArrayOrSingleElementIsNullOrEmpty -Array @($First) $secondNullOrEmpty = ArrayOrSingleElementIsNullOrEmpty -Array @($Second) if ($firstNullOrEmpty -or $secondNullOrEmpty) { return $firstNullOrEmpty -and $secondNullOrEmpty } if ($First.Count -ne $Second.Count) { return $false } for ($i = 0; $i -lt $First.Count; $i++) { if ((IsArray $First[$i]) -or (IsArray $Second[$i])) { if (-not (ArraysAreEqual -First $First[$i] -Second $Second[$i] -CaseSensitive:$CaseSensitive -RecursionDepth $RecursionDepth -RecursionLimit $RecursionLimit)) { return $false } } else { if ($CaseSensitive) { $comparer = { param($Actual, $Expected) $Expected -ceq $Actual } } else { $comparer = { param($Actual, $Expected) $Expected -eq $Actual } } if (-not (& $comparer $First[$i] $Second[$i])) { return $false } } } return $true } function ArrayOrSingleElementIsNullOrEmpty { param ([object[]] $Array) return $null -eq $Array -or $Array.Count -eq 0 -or ($Array.Count -eq 1 -and $null -eq $Array[0]) } function IsArray { param ([object] $InputObject) # Changing this could cause infinite recursion in ArraysAreEqual. # see https://github.com/pester/Pester/issues/785#issuecomment-322794011 return $InputObject -is [Array] } function ReplaceValueInArray { param ( [object[]] $Array, [object] $Value, [object] $NewValue ) foreach ($object in $Array) { if ($Value -eq $object) { $NewValue } elseif (@($object).Count -gt 1) { ReplaceValueInArray -Array @($object) -Value $Value -NewValue $NewValue } else { $object } } } # SIG # Begin signature block # MIIZbgYJKoZIhvcNAQcCoIIZXzCCGVsCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUA9c23VB2YZe72DevXxLvvut/ # vfKgghR8MIIE/jCCA+agAwIBAgIQDUJK4L46iP9gQCHOFADw3TANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgVGltZXN0YW1waW5nIENBMB4XDTIxMDEwMTAwMDAwMFoXDTMxMDEw # NjAwMDAwMFowSDELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMu # MSAwHgYDVQQDExdEaWdpQ2VydCBUaW1lc3RhbXAgMjAyMTCCASIwDQYJKoZIhvcN # AQEBBQADggEPADCCAQoCggEBAMLmYYRnxYr1DQikRcpja1HXOhFCvQp1dU2UtAxQ # tSYQ/h3Ib5FrDJbnGlxI70Tlv5thzRWRYlq4/2cLnGP9NmqB+in43Stwhd4CGPN4 # bbx9+cdtCT2+anaH6Yq9+IRdHnbJ5MZ2djpT0dHTWjaPxqPhLxs6t2HWc+xObTOK # fF1FLUuxUOZBOjdWhtyTI433UCXoZObd048vV7WHIOsOjizVI9r0TXhG4wODMSlK # XAwxikqMiMX3MFr5FK8VX2xDSQn9JiNT9o1j6BqrW7EdMMKbaYK02/xWVLwfoYer # vnpbCiAvSwnJlaeNsvrWY4tOpXIc7p96AXP4Gdb+DUmEvQECAwEAAaOCAbgwggG0 # MA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsG # AQUFBwMIMEEGA1UdIAQ6MDgwNgYJYIZIAYb9bAcBMCkwJwYIKwYBBQUHAgEWG2h0 # dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAfBgNVHSMEGDAWgBT0tuEgHf4prtLk # YaWyoiWyyBc1bjAdBgNVHQ4EFgQUNkSGjqS6sGa+vCgtHUQ23eNqerwwcQYDVR0f # BGowaDAyoDCgLoYsaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJl # ZC10cy5jcmwwMqAwoC6GLGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFz # c3VyZWQtdHMuY3JsMIGFBggrBgEFBQcBAQR5MHcwJAYIKwYBBQUHMAGGGGh0dHA6 # Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBPBggrBgEFBQcwAoZDaHR0cDovL2NhY2VydHMu # ZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJRFRpbWVzdGFtcGluZ0NB # LmNydDANBgkqhkiG9w0BAQsFAAOCAQEASBzctemaI7znGucgDo5nRv1CclF0CiNH # o6uS0iXEcFm+FKDlJ4GlTRQVGQd58NEEw4bZO73+RAJmTe1ppA/2uHDPYuj1UUp4 # eTZ6J7fz51Kfk6ftQ55757TdQSKJ+4eiRgNO/PT+t2R3Y18jUmmDgvoaU+2QzI2h # F3MN9PNlOXBL85zWenvaDLw9MtAby/Vh/HUIAHa8gQ74wOFcz8QRcucbZEnYIpp1 # FUL1LTI4gdr0YKK6tFL7XOBhJCVPst/JKahzQ1HavWPWH1ub9y4bTxMd90oNcX6X # t/Q/hOvB46NJofrOp79Wz7pZdmGJX36ntI5nePk2mOHLKNpbh6aKLzCCBQ0wggP1 # oAMCAQICEAPBBFtdmcD9x4iXgGyKU+cwDQYJKoZIhvcNAQELBQAwcjELMAkGA1UE # BhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2lj # ZXJ0LmNvbTExMC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIENvZGUg # U2lnbmluZyBDQTAeFw0yMTAxMjgwMDAwMDBaFw0yNDAxMzEyMzU5NTlaMEsxCzAJ # BgNVBAYTAkNaMQ4wDAYDVQQHEwVQcmFoYTEVMBMGA1UECgwMSmFrdWIgSmFyZcWh # MRUwEwYDVQQDDAxKYWt1YiBKYXJlxaEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw # ggEKAoIBAQC154nkzSQ95K1yCflVL3iFQhzw/25ht4o506hK7ATFgvP71ZI+YHce # gvVoMtaMhJp2/EzXsgxDF7EZBR4Hl9vNbIpLAFSVCK4GBD0DxNCDFrJTPtNohgsA # STNMcK6t0iunh7MEkaYt1yPgiISA1vcQUMKi51WSUxeWnsUNTkJDZkyM61fETbhy # CI66xLItaf3OWdyjiOFPq2n8yx+eg1w7GCC/eNYVAjzqtSmiE/xv6Qoj7z9qFyS1 # pAO4cxDRLAD9IcCiYmHOJVgsho3/u4QNNm72ghz7iiRAO5lDoBcZIiLS5RKxJwMG # nnYbIiAuISZmv4PtrkcSu81Lzmtu81idAgMBAAGjggHEMIIBwDAfBgNVHSMEGDAW # gBRaxLl7KgqjpepxA8Bg+S32ZXUOWDAdBgNVHQ4EFgQUF2nEZEX1uTrPSD3h5VSJ # 8g9ef20wDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMHcGA1Ud # HwRwMG4wNaAzoDGGL2h0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3Vy # ZWQtY3MtZzEuY3JsMDWgM6Axhi9odHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hh # Mi1hc3N1cmVkLWNzLWcxLmNybDBLBgNVHSAERDBCMDYGCWCGSAGG/WwDATApMCcG # CCsGAQUFBwIBFhtodHRwOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQB # MIGEBggrBgEFBQcBAQR4MHYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2lj # ZXJ0LmNvbTBOBggrBgEFBQcwAoZCaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29t # L0RpZ2lDZXJ0U0hBMkFzc3VyZWRJRENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB # /wQCMAAwDQYJKoZIhvcNAQELBQADggEBANuuPZ7LhU/v1GDprUhYch3/fov3sIxp # wshFvufWbGxUYzxEVQSsZLdFVUzAdsCz3fKInY2ihCwqIoU5vbwKFvV1zvizat/r # aNn5aa8H34NjEXPHQiyNykOk9CdFgk+zZn+YpeyzBMAEvQR4uB4eDv1USWkwdXPB # VVZcjM0xEsx9H/ZZRSEGS0x3ue+shvZdPRzoWcuiK8hNcbFZr15hMGi4s0F9IxTZ # QzoSpNJsBA/vMmkbp2SWeENn49BNx8q760e+ELMfuSBltKs8S2hB9TLrpko3nIvp # l1323zyR6ZpWK1/FHbGkHRsSJKvOOBdlSL08+KM2kNzXez88eUae+1YwggUwMIIE # GKADAgECAhAECRgbX9W7ZnVTQ7VvlVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNV # BAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdp # Y2VydC5jb20xJDAiBgNVBAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAe # Fw0xMzEwMjIxMjAwMDBaFw0yODEwMjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUw # EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x # MTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcg # Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9ML # MUkZz9D7RZmxOttE9X/lqJ3bMtdx6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWs # DnkoOn7p0WfTxvspJ8fTeyOU5JEjlpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeK # iUXULaGj6YgsIJWuHEqHCN8M9eJNYBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5Tsx # HM/q8grkV7tKtel05iv+bMt+dDk2DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sI # ZD5SlsHyDxL0xY4PwaLoLFH3c7y9hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/Rnf # JZPRAgMBAAGjggHNMIIByTASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQE # AwIBhjATBgNVHSUEDDAKBggrBgEFBQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYB # BQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0 # cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENB # LmNydDCBgQYDVR0fBHoweDA6oDigNoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29t # L0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDA6oDigNoY0aHR0cDovL2NybDMu # ZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAE # SDBGMDgGCmCGSAGG/WwAAgQwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGln # aWNlcnQuY29tL0NQUzAKBghghkgBhv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPA # YPkt9mV1DlgwHwYDVR0jBBgwFoAUReuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZI # hvcNAQELBQADggEBAD7sDVoks/Mi0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0P # xK+L/e8q3yBVN7Dh9tGSdQ9RtG6ljlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK # 95xGTlz/kLEbBw6RFfu6r7VRwo0kriTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6 # aGivm6dcIFzZcbEMj7uo+MUSaJ/PQMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lF # luhZHen6dGRrsutmQ9qzsIzV6Q3d9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmC # SfdibqFT+hKUGIUukpHqaGxEMrJmoecYpJpkUe8wggUxMIIEGaADAgECAhAKoSXW # 1jIbfkHkBdo2l8IVMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYD # VQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAi # BgNVBAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xNjAxMDcxMjAw # MDBaFw0zMTAxMDcxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERp # Z2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBUaW1lc3RhbXBpbmcgQ0EwggEiMA0GCSqG # SIb3DQEBAQUAA4IBDwAwggEKAoIBAQC90DLuS82Pf92puoKZxTlUKFe2I0rEDgdF # M1EQfdD5fU1ofue2oPSNs4jkl79jIZCYvxO8V9PD4X4I1moUADj3Lh477sym9jJZ # /l9lP+Cb6+NGRwYaVX4LJ37AovWg4N4iPw7/fpX786O6Ij4YrBHk8JkDbTuFfAnT # 7l3ImgtU46gJcWvgzyIQD3XPcXJOCq3fQDpct1HhoXkUxk0kIzBdvOw8YGqsLwfM # /fDqR9mIUF79Zm5WYScpiYRR5oLnRlD9lCosp+R1PrqYD4R/nzEU1q3V8mTLex4F # 0IQZchfxFwbvPc3WTe8GQv2iUypPhR3EHTyvz9qsEPXdrKzpVv+TAgMBAAGjggHO # MIIByjAdBgNVHQ4EFgQU9LbhIB3+Ka7S5GGlsqIlssgXNW4wHwYDVR0jBBgwFoAU # Reuir/SSy4IxLVGLp6chnfNtyA8wEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8B # Af8EBAMCAYYwEwYDVR0lBAwwCgYIKwYBBQUHAwgweQYIKwYBBQUHAQEEbTBrMCQG # CCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQwYIKwYBBQUHMAKG # N2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJv # b3RDQS5jcnQwgYEGA1UdHwR6MHgwOqA4oDaGNGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0 # LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwOqA4oDaGNGh0dHA6Ly9j # cmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwUAYD # VR0gBEkwRzA4BgpghkgBhv1sAAIEMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3 # LmRpZ2ljZXJ0LmNvbS9DUFMwCwYJYIZIAYb9bAcBMA0GCSqGSIb3DQEBCwUAA4IB # AQBxlRLpUYdWac3v3dp8qmN6s3jPBjdAhO9LhL/KzwMC/cWnww4gQiyvd/MrHwwh # Wiq3BTQdaq6Z+CeiZr8JqmDfdqQ6kw/4stHYfBli6F6CJR7Euhx7LCHi1lssFDVD # BGiy23UC4HLHmNY8ZOUfSBAYX4k4YU1iRiSHY4yRUiyvKYnleB/WCxSlgNcSR3Cz # ddWThZN+tpJn+1Nhiaj1a5bA9FhpDXzIAbG5KHW3mWOFIoxhynmUfln8jA/jb7UB # JrZspe6HUSHkWGCbugwtK22ixH67xCUrRwIIfEmuE7bhfEJCKMYYVs9BNLZmXbZ0 # e/VWMyIvIjayS6JKldj1po5SMYIEXDCCBFgCAQEwgYYwcjELMAkGA1UEBhMCVVMx # FTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNv # bTExMC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIENvZGUgU2lnbmlu # ZyBDQQIQA8EEW12ZwP3HiJeAbIpT5zAJBgUrDgMCGgUAoHgwGAYKKwYBBAGCNwIB # DDEKMAigAoAAoQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEE # AYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAjBgkqhkiG9w0BCQQxFgQUGNBypn2qKM7Q # dzWa7Ted0IYneikwDQYJKoZIhvcNAQEBBQAEggEApu6OlZrzWx2vRJkldWnBwVSb # NB04NW+DLOwOB/gpV4nW7CZtbwjJKTUup8AqcQw7ROpgrDd7PAZgPjXvt1BpOeAs # /hdoW+sZgc+Vy9+6Hq8wl3UgfbB2h+n4IhhDXcSbw137NK6PDOLnIzFGZZ9XgRN8 # JG+xGN2+GAIW5d9O7Y2kxFUZkG3nblxBgEe54xDmo0N6R/ShmF4Utn+dpxWq0YxF # bhdTFcfE+QAp2Xpwu60toDHzdUBWbyP6WyDfHNsB9IodbSSNgDJXOuq5MocvMUMj # 1/TU/uZNDcNWl7cl2Kdxru5blk4RCA4ULNEkLbpG1PHUh4CtGR6mOEWF6fs7d6GC # AjAwggIsBgkqhkiG9w0BCQYxggIdMIICGQIBATCBhjByMQswCQYDVQQGEwJVUzEV # MBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29t # MTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgVGltZXN0YW1waW5n # IENBAhANQkrgvjqI/2BAIc4UAPDdMA0GCWCGSAFlAwQCAQUAoGkwGAYJKoZIhvcN # AQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMjEwNTI5MTIyODA3WjAv # BgkqhkiG9w0BCQQxIgQgFaAE6DIGRG9jwJ7khTiFuxNcz7LCMrz54zWN/3SH9EQw # DQYJKoZIhvcNAQEBBQAEggEAi8fDebCU1UPZDNogV51eFD07C9W13Ve9YafGQEaL # UZQVjL9KKhg7lV32P7Z15QPZ1b9CTg/6RLBZNXPt01YP2UtwjhOSyCcPQ6GKgLiF # R2xfq88AoJIHbT/JrydNvFZkyd9YvrBZk2jmMWYjMOFdQl72BtubLOeS7FgNnH3R # 7heYhvxY0q3a066bX6RgaHfsxRlErZLMKx+xMadSKwceixNlL4pWR/fb5tZosWpx # dI9ML8aB6LgokqzNnrJatydMzdY4af8B+Tz028U479mEcmTSooU0L0242RXddpZp # Kg7uFYsHR5GTDaQyonahC2cSZSrDc7TIHq2prK4rmCS5Xw== # SIG # End signature block |