function New-PesterState { param ( [String[]]$TagFilter, [String[]]$ExcludeTagFilter, [String[]]$TestNameFilter, [System.Management.Automation.SessionState]$SessionState, [Switch]$Strict, [Switch]$Quiet, [object]$PesterOption ) if ($null -eq $SessionState) { $SessionState = $ExecutionContext.SessionState } if ($null -eq $PesterOption) { $PesterOption = New-PesterOption } elseif ($PesterOption -is [System.Collections.IDictionary]) { try { $PesterOption = New-PesterOption @PesterOption } catch { throw } } & $SafeCommands['New-Module'] -Name Pester -AsCustomObject -ScriptBlock { param ( [String[]]$_tagFilter, [String[]]$_excludeTagFilter, [String[]]$_testNameFilter, [System.Management.Automation.SessionState]$_sessionState, [Switch]$Strict, [Switch]$Quiet, [object]$PesterOption ) #public read-only $TagFilter = $_tagFilter $ExcludeTagFilter = $_excludeTagFilter $TestNameFilter = $_testNameFilter $script:SessionState = $_sessionState $script:CurrentContext = "" $script:CurrentDescribe = "" $script:CurrentTest = "" $script:Stopwatch = [System.Diagnostics.Stopwatch]::StartNew() $script:MostRecentTimestamp = 0 $script:CommandCoverage = @() $script:BeforeEach = @() $script:AfterEach = @() $script:BeforeAll = @() $script:AfterAll = @() $script:Strict = $Strict $script:Quiet = $Quiet $script:TestResult = @() $script:TotalCount = 0 $script:Time = [timespan]0 $script:PassedCount = 0 $script:FailedCount = 0 $script:SkippedCount = 0 $script:PendingCount = 0 $script:InconclusiveCount = 0 $script:IncludeVSCodeMarker = $PesterOption.IncludeVSCodeMarker $script:SafeCommands = @{} $script:SafeCommands['New-Object'] = & (Pester\SafeGetCommand) -Name New-Object -Module Microsoft.PowerShell.Utility -CommandType Cmdlet $script:SafeCommands['Select-Object'] = & (Pester\SafeGetCommand) -Name Select-Object -Module Microsoft.PowerShell.Utility -CommandType Cmdlet $script:SafeCommands['Export-ModuleMember'] = & (Pester\SafeGetCommand) -Name Export-ModuleMember -Module Microsoft.PowerShell.Core -CommandType Cmdlet $script:SafeCommands['Add-Member'] = & (Pester\SafeGetCommand) -Name Add-Member -Module Microsoft.PowerShell.Utility -CommandType Cmdlet function EnterDescribe([string]$Name) { if ($CurrentDescribe) { throw & $SafeCommands['New-Object'] InvalidOperationException "You already are in Describe, you cannot enter Describe twice" } $script:CurrentDescribe = $Name } function LeaveDescribe { if ( $CurrentContext ) { throw & $SafeCommands['New-Object'] InvalidOperationException "Cannot leave Describe before leaving Context" } $script:CurrentDescribe = $null } function EnterContext([string]$Name) { if ( -not $CurrentDescribe ) { throw & $SafeCommands['New-Object'] InvalidOperationException "Cannot enter Context before entering Describe" } if ( $CurrentContext ) { throw & $SafeCommands['New-Object'] InvalidOperationException "You already are in Context, you cannot enter Context twice" } if ($CurrentTest) { throw & $SafeCommands['New-Object'] InvalidOperationException "You already are in It, you cannot enter Context inside It" } $script:CurrentContext = $Name } function LeaveContext { if ($CurrentTest) { throw & $SafeCommands['New-Object'] InvalidOperationException "Cannot leave Context before leaving It" } $script:CurrentContext = $null } function EnterTest([string]$Name) { if (-not $script:CurrentDescribe) { throw & $SafeCommands['New-Object'] InvalidOperationException "Cannot enter It before entering Describe" } if ( $CurrentTest ) { throw & $SafeCommands['New-Object'] InvalidOperationException "You already are in It, you cannot enter It twice" } $script:CurrentTest = $Name } function LeaveTest { $script:CurrentTest = $null } function AddTestResult { param ( [string]$Name, [ValidateSet("Failed","Passed","Skipped","Pending","Inconclusive")] [string]$Result, [Nullable[TimeSpan]]$Time, [string]$FailureMessage, [string]$StackTrace, [string] $ParameterizedSuiteName, [System.Collections.IDictionary] $Parameters, [System.Management.Automation.ErrorRecord] $ErrorRecord ) $previousTime = $script:MostRecentTimestamp $script:MostRecentTimestamp = $script:Stopwatch.Elapsed if ($null -eq $Time) { $Time = $script:MostRecentTimestamp - $previousTime } if (-not $script:Strict) { $Passed = "Passed","Skipped","Pending" -contains $Result } else { $Passed = $Result -eq "Passed" if (($Result -eq "Skipped") -or ($Result -eq "Pending")) { $FailureMessage = "The test failed because the test was executed in Strict mode and the result '$result' was translated to Failed." $Result = "Failed" } } $script:TotalCount++ $script:Time += $Time switch ($Result) { Passed { $script:PassedCount++; break; } Failed { $script:FailedCount++; break; } Skipped { $script:SkippedCount++; break; } Pending { $script:PendingCount++; break; } Inconclusive { $script:InconclusiveCount++; break; } } $Script:TestResult += & $SafeCommands['New-Object'] -TypeName PsObject -Property @{ Describe = $CurrentDescribe Context = $CurrentContext Name = $Name Passed = $Passed Result = $Result Time = $Time FailureMessage = $FailureMessage StackTrace = $StackTrace ErrorRecord = $ErrorRecord ParameterizedSuiteName = $ParameterizedSuiteName Parameters = $Parameters } | & $SafeCommands['Select-Object'] Describe, Context, Name, Result, Passed, Time, FailureMessage, StackTrace, ErrorRecord, ParameterizedSuiteName, Parameters } $ExportedVariables = "TagFilter", "ExcludeTagFilter", "TestNameFilter", "TestResult", "CurrentContext", "CurrentDescribe", "CurrentTest", "SessionState", "CommandCoverage", "BeforeEach", "AfterEach", "BeforeAll", "AfterAll", "Strict", "Quiet", "Time", "TotalCount", "PassedCount", "FailedCount", "SkippedCount", "PendingCount", "InconclusiveCount", "IncludeVSCodeMarker" $ExportedFunctions = "EnterContext", "LeaveContext", "EnterDescribe", "LeaveDescribe", "EnterTest", "LeaveTest", "AddTestResult" & $SafeCommands['Export-ModuleMember'] -Variable $ExportedVariables -function $ExportedFunctions } -ArgumentList $TagFilter, $ExcludeTagFilter, $TestNameFilter, $SessionState, $Strict, $Quiet, $PesterOption | & $SafeCommands['Add-Member'] -MemberType ScriptProperty -Name Scope -Value { if ($this.CurrentTest) { 'It' } elseif ($this.CurrentContext) { 'Context' } elseif ($this.CurrentDescribe) { 'Describe' } else { $null } } -Passthru | & $SafeCommands['Add-Member'] -MemberType ScriptProperty -Name ParentScope -Value { $parentScope = $null $scope = $this.Scope if ($scope -eq 'It' -and $this.CurrentContext) { $parentScope = 'Context' } if ($null -eq $parentScope -and $scope -ne 'Describe' -and $this.CurrentDescribe) { $parentScope = 'Describe' } return $parentScope } -PassThru } function Write-Describe { param ( [Parameter(mandatory=$true, valueFromPipeline=$true)]$Name ) process { Write-Screen Describing $Name -OutputType Header } } function Write-Context { param ( [Parameter(mandatory=$true, valueFromPipeline=$true)]$Name ) process { $margin = " " * 3 Write-Screen ${margin}Context $Name -OutputType Header } } function Write-PesterResult { param ( [Parameter(mandatory=$true, valueFromPipeline=$true)] $TestResult ) process { $testDepth = if ( $TestResult.Context ) { 4 } elseif ( $TestResult.Describe ) { 1 } else { 0 } $margin = " " * $TestDepth $error_margin = $margin + " " $output = $TestResult.name $humanTime = Get-HumanTime $TestResult.Time.TotalSeconds switch ($TestResult.Result) { Passed { "$margin[+] $output $humanTime" | Write-Screen -OutputType Passed break } Failed { "$margin[-] $output $humanTime" | Write-Screen -OutputType Failed $failureLines = $TestResult.ErrorRecord | ConvertTo-FailureLines if ($Pester.IncludeVSCodeMarker) { $marker = $failureLines | & $script:SafeCommands['Select-Object'] -First 1 -ExpandProperty Trace | & $script:SafeCommands['Select-Object'] -First 1 Write-Screen -OutputType Failed $($marker -replace '(?m)^',$error_margin) } $failureLines | & $SafeCommands['ForEach-Object'] {$_.Message + $_.Trace} | & $SafeCommands['ForEach-Object'] { Write-Screen -OutputType Failed $($_ -replace '(?m)^',$error_margin) } } Skipped { "$margin[!] $output $humanTime" | Write-Screen -OutputType Skipped break } Pending { "$margin[?] $output $humanTime" | Write-Screen -OutputType Pending break } Inconclusive { "$margin[?] $output $humanTime" | Write-Screen -OutputType Inconclusive if ($testresult.FailureMessage) { Write-Screen -OutputType Inconclusive $($TestResult.failureMessage -replace '(?m)^',$error_margin) } Write-Screen -OutputType Inconclusive $($TestResult.stackTrace -replace '(?m)^',$error_margin) break } } } } function ConvertTo-FailureLines { param ( [Parameter(mandatory=$true, valueFromPipeline=$true)] $ErrorRecord ) process { $lines = & $script:SafeCommands['New-Object'] psobject -Property @{ Message = @() Trace = @() } ## convert the exception messages $exception = $ErrorRecord.Exception $exceptionLines = @() while ($exception) { $exceptionName = $exception.GetType().Name $thisLines = $exception.Message.Split([Environment]::NewLine, [System.StringSplitOptions]::RemoveEmptyEntries) if ($ErrorRecord.FullyQualifiedErrorId -ne 'PesterAssertionFailed') { $thisLines[0] = "$exceptionName`: $($thisLines[0])" } [array]::Reverse($thisLines) $exceptionLines += $thisLines $exception = $exception.InnerException } [array]::Reverse($exceptionLines) $lines.Message += $exceptionLines if ($ErrorRecord.FullyQualifiedErrorId -eq 'PesterAssertionFailed') { $lines.Message += "$($ErrorRecord.TargetObject.Line)`: $($ErrorRecord.TargetObject.LineText)".Split([Environment]::NewLine, [System.StringSplitOptions]::RemoveEmptyEntries) } if ( -not ($ErrorRecord | & $SafeCommands['Get-Member'] -Name ScriptStackTrace) ) { if ($ErrorRecord.FullyQualifiedErrorID -eq 'PesterAssertionFailed') { $lines.Trace += "at line: $($ErrorRecord.TargetObject.Line) in $($ErrorRecord.TargetObject.File)" } else { $lines.Trace += "at line: $($ErrorRecord.InvocationInfo.ScriptLineNumber) in $($ErrorRecord.InvocationInfo.ScriptName)" } return $lines } ## convert the stack trace $traceLines = $ErrorRecord.ScriptStackTrace.Split([Environment]::NewLine, [System.StringSplitOptions]::RemoveEmptyEntries) # omit the lines internal to Pester foreach ( $line in $traceLines ) { if ( $line -match '^at (Invoke-Test|Context|Describe|InModuleScope|Invoke-Pester), .*\\Functions\\.*.ps1: line [0-9]*$' ) { break } $count ++ } $lines.Trace += $traceLines | & $SafeCommands['Select-Object'] -First $count | & $SafeCommands['Where-Object'] { $_ -notmatch '^at Should, .*\\Functions\\Assertions\\Should.ps1: line [0-9]*$' -and $_ -notmatch '^at Assert-MockCalled, .*\\Functions\\Mock.ps1: line [0-9]*$' } return $lines } } function Write-PesterReport { param ( [Parameter(mandatory=$true, valueFromPipeline=$true)] $PesterState ) Write-Screen "Tests completed in $(Get-HumanTime $PesterState.Time.TotalSeconds)" Write-Screen ("Passed: {0} Failed: {1} Skipped: {2} Pending: {3} Inconclusive: {4}" -f $PesterState.PassedCount, $PesterState.FailedCount, $PesterState.SkippedCount, $PesterState.PendingCount, $PesterState.InconclusiveCount) } function Write-Screen { #wraps the Write-Host cmdlet to control if the output is written to screen from one place param( #Write-Host parameters [Parameter(Position=0, ValueFromPipeline=$true, ValueFromRemainingArguments=$true)] [Object] $Object, [Switch] $NoNewline, [Object] $Separator, #custom parameters [Switch] $Quiet = $pester.Quiet, [ValidateSet("Failed","Passed","Skipped","Pending","Inconclusive","Header","Standard")] [String] $OutputType = "Standard" ) begin { if ($Quiet) { return } #make the bound parameters compatible with Write-Host if ($PSBoundParameters.ContainsKey('Quiet')) { $PSBoundParameters.Remove('Quiet') | & $SafeCommands['Out-Null'] } if ($PSBoundParameters.ContainsKey('OutputType')) { $PSBoundParameters.Remove('OutputType') | & $SafeCommands['Out-Null'] } if ($OutputType -ne "Standard") { #create the key first to make it work in strict mode if (-not $PSBoundParameters.ContainsKey('ForegroundColor')) { $PSBoundParameters.Add('ForegroundColor', $null) } switch ($Host.Name) { #light background "PowerGUIScriptEditorHost" { $ColorSet = @{ Failed = [ConsoleColor]::Red Passed = [ConsoleColor]::DarkGreen Skipped = [ConsoleColor]::DarkGray Pending = [ConsoleColor]::DarkCyan Inconclusive = [ConsoleColor]::DarkCyan Header = [ConsoleColor]::Magenta } } #dark background { "Windows PowerShell ISE Host", "ConsoleHost" -contains $_ } { $ColorSet = @{ Failed = [ConsoleColor]::Red Passed = [ConsoleColor]::Green Skipped = [ConsoleColor]::Gray Pending = [ConsoleColor]::Cyan Inconclusive = [ConsoleColor]::Cyan Header = [ConsoleColor]::Magenta } } default { $ColorSet = @{ Failed = [ConsoleColor]::Red Passed = [ConsoleColor]::DarkGreen Skipped = [ConsoleColor]::Gray Pending = [ConsoleColor]::Gray Inconclusive = [ConsoleColor]::Gray Header = [ConsoleColor]::Magenta } } } $PSBoundParameters.ForegroundColor = $ColorSet.$OutputType } try { $outBuffer = $null if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer)) { $PSBoundParameters['OutBuffer'] = 1 } $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Write-Host', [System.Management.Automation.CommandTypes]::Cmdlet) $scriptCmd = {& $wrappedCmd @PSBoundParameters } $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin) $steppablePipeline.Begin($PSCmdlet) } catch { throw } } process { if ($Quiet) { return } try { $steppablePipeline.Process($_) } catch { throw } } end { if ($Quiet) { return } try { $steppablePipeline.End() } catch { throw } } } # SIG # Begin signature block # MIInjAYJKoZIhvcNAQcCoIInfTCCJ3kCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDPZLreddgR0Geh # u1WfGwwONHXVHGKZRDPrAFEgyifb1qCCC8MwggXaMIIEwqADAgECAhMzAAABP8rF # 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 # 8f7BcdpMoEFagt3xHzGCGx8wghsbAgEBMIGmMIGOMQswCQYDVQQGEwJVUzETMBEG # A1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWlj # cm9zb2Z0IENvcnBvcmF0aW9uMTgwNgYDVQQDEy9NaWNyb3NvZnQgV2luZG93cyBU # aGlyZCBQYXJ0eSBDb21wb25lbnQgQ0EgMjAxMgITMwAAAT/KxSgZC4k1WAAAAAAB # PzANBglghkgBZQMEAgEFAKCCARgwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw # HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIA/w # 3k5wxvizbJLJ+v8N84BVujn5+u8BLjoOmqEoMdp5MFAGCisGAQQBgjcKAxwxQgxA # ODNFNzM0RkUzQzY5QjBDNDRFNzBBREJGQUU5RjdDODY0RTkzMjJDMTdBQTY5Qjgz # NUUxQkQ5MEM2NEFERTlCQzBaBgorBgEEAYI3AgEMMUwwSqAkgCIATQBpAGMAcgBv # AHMAbwBmAHQAIABXAGkAbgBkAG8AdwBzoSKAIGh0dHA6Ly93d3cubWljcm9zb2Z0 # LmNvbS93aW5kb3dzMA0GCSqGSIb3DQEBAQUABIIBgMshW42shwIh4XUAUs8UegJN # +BNwCu9yGnRY5BT4vauIKLpdGxKRVC4oVt8us31bKzX1ui329prVESRggoriVnig # 0xv+2cmge4KzVvo/hrjczHTHKI2UZWlzb0P82yY9nDws9eqI9agYOYKHt95uTMx9 # aQuFRgbfpixffzEt9NSFgtqtEPrlNO97qJaKDYuuqMSx0Hj/5BoUF/cPR3NhdP2v # /UwzNWdRl03TdITFB7OaU7xbrSP4qNuZB4C39/Q600FDHZzmh0gkJH2Cr6i41g/m # kRvwCUPmUszQq9jg1mHT02VZY8JA7sBmdv0wMa/KJzj46MAeY8uWLqyZEKLdo5BE # HPjRouWm+gRUIIBULb6tvVP8fIwyEmpOg+Hb444aBDhdyp3kJENcinqinkuQn5io # 3DXOk03LQ2yLwej1V+K9BpxzpLawtbJ9EMN98iSaySaK25Duk5c0b/0pNU+aRaog # eAe1aUbdosP4f38eS9SNUcISpYhRFcM+9rVJsi8pGaGCF60wghepBgorBgEEAYI3 # AwMBMYIXmTCCF5UGCSqGSIb3DQEHAqCCF4YwgheCAgEDMQ8wDQYJYIZIAWUDBAIB # BQAwggFaBgsqhkiG9w0BCRABBKCCAUkEggFFMIIBQQIBAQYKKwYBBAGEWQoDATAx # MA0GCWCGSAFlAwQCAQUABCCj8jXtW7KvN+UaDB2ywUtQChbwmPkTHuYj9dkQmJN1 # MwIGaonm18ocGBMyMDI2MDkwNTEzNDkzNy41NzdaMASAAgH0oIHZpIHWMIHTMQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNy # b3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJzAlBgNVBAsTHm5TaGll # bGQgVFNTIEVTTjo2NTFBLTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9zb2Z0IFRp # bWUtU3RhbXAgU2VydmljZaCCEfswggcoMIIFEKADAgECAhMzAAACFRgD04EHJnxT # AAEAAAIVMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpX # YXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQg # Q29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAy # MDEwMB4XDTI1MDgxNDE4NDgyMFoXDTI2MTExMzE4NDgyMFowgdMxCzAJBgNVBAYT # AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD # VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29mdCBJ # cmVsYW5kIE9wZXJhdGlvbnMgTGltaXRlZDEnMCUGA1UECxMeblNoaWVsZCBUU1Mg # RVNOOjY1MUEtMDVFMC1EOTQ3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFt # cCBTZXJ2aWNlMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAw3HV3hVx # L0lEYPV03XeNKZ517VIbgexhlDPdpXwDS0BYtxPwi4XYpZR1ld0u6cr2Xjuugdg5 # 0DUx5WHL0QhY2d9vkJSk02rE/75hcKt91m2Ih287QRxRMmFu3BF6466k8qp5uXtf # e6uciq49YaS8p+dzv3uTarD4hQ8UT7La95pOJiRqxxd0qOGLECvHLEXPXioNSx9p # yhzhm6lt7ezLxJeFVYtxShkavPoZN0dOCiYeh4KgoKoyagzMuSiLCiMUW4Ue4Qsm # 658FJNGTNh7V5qXYVA6k5xjw5WeWdKOz0i9A5jBcbY9fVOo/cA8i1bytzcDTxb3n # ctcly8/OYeNstkab/Isq3Cxe1vq96fIHE1+ZGmJjka1sodwqPycVp/2tb+BjulPL # 5D6rgUXTPF84U82RLKHV57bB8fHRpgnjcWBQuXPgVeSXpERWimt0NF2lCOLzqgrv # S/vYqde5Ln9YlKKhAZ/xDE0TLIIr6+I/2JTtXP34nfjTENVqMBISWcakIxAwGb3R # B5yHCxynIFNVLcfKAsEdC5U2em0fAvmVv0sonqnv17cuaYi2eCLWhoK1Ic85Dw7s # /lhcXrBpY4n/Rl5l3wHzs4vOIhu87DIy5QUaEupEsyY0NWqgI4BWl6v1wgse+l8D # WFeUXofhUuCgVTuTHN3K8idoMbn8Q3edUIECAwEAAaOCAUkwggFFMB0GA1UdDgQW # BBSJIXfxcqAwFqGj9jdwQtdSqadj1zAfBgNVHSMEGDAWgBSfpxVdAF5iXYP05dJl # pxtTNRnpcjBfBgNVHR8EWDBWMFSgUqBQhk5odHRwOi8vd3d3Lm1pY3Jvc29mdC5j # b20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBUaW1lLVN0YW1wJTIwUENBJTIwMjAx # MCgxKS5jcmwwbAYIKwYBBQUHAQEEYDBeMFwGCCsGAQUFBzAChlBodHRwOi8vd3d3 # Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMFRpbWUtU3Rh # bXAlMjBQQ0ElMjAyMDEwKDEpLmNydDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQM # MAoGCCsGAQUFBwMIMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAgEA # d42HtV+kGbvxzLBTC5O7vkCIBPy/BwpjCzeL53hAiEOebp+VdNnwm9GVCfYq3KMf # rj4UvKQTUAaS5Zkwe1gvZ3ljSSnCOyS5OwNu9dpg3ww+QW2eOcSLkyVAWFrLn6Ii # g3TC/zWMvVhqXtdFhG2KJ1lSbN222csY3E3/BrGluAlvET9gmxVyyxNy59/7JF5z # IGcJibydxs94JL1BtPgXJOfZzQ+/3iTc6eDtmaWT6DKdnJocp8wkXKWPIsBEfkD6 # k1Qitwvt0mHrORah75SjecOKt4oWayVLkPTho12e0ongEg1cje5fxSZGthrMrWKv # I4R7HEC7k8maH9ePA3ViH0CVSSOefaPTGMzIhHCo5p3jG5SMcyO3eA9uEaYQJITJ # lLG3BwwGmypY7C/8/nj1SOhgx1HgJ0ywOJL9xfP4AOcWmCfbsqgGbCaC7WH5sINd # zfMar8V7YNFqkbCGUKhc8GpIyE+MKnyVn33jsuaGAlNRg7dVRUSoYLJxvUsw9GOw # yBpBwbE9sqOLm+HsO00oF23PMio7WFXcFTZAjp3ujihBAfLrXICgGOHPdkZ042u1 # LZqOcnlr3XzvgMe+mPPyasW8f0rtzJj3V5E/EKiyQlPxj9Mfq2x9himnlXWGZCVP # eEBROrNbDYBfazTyLNCOTsRtksOSV3FBtPnpQtLN754wggdxMIIFWaADAgECAhMz # 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 # 7oJtpQUQwXEGahC0HVUzWLOhcGbyoYIDVjCCAj4CAQEwggEBoYHZpIHWMIHTMQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNy # b3NvZnQgSXJlbGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJzAlBgNVBAsTHm5TaGll # bGQgVFNTIEVTTjo2NTFBLTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9zb2Z0IFRp # bWUtU3RhbXAgU2VydmljZaIjCgEBMAcGBSsOAwIaAxUAj6eTejbuYE1Ifjbfrt6t # XevCUSCggYMwgYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv # bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0 # aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDANBgkq # hkiG9w0BAQsFAAIFAO5GMBUwIhgPMjAyNjA5MDUwNjA3MTdaGA8yMDI2MDkwNjA2 # MDcxN1owdDA6BgorBgEEAYRZCgQBMSwwKjAKAgUA7kYwFQIBADAHAgEAAgI5ezAH # AgEAAgISoTAKAgUA7keBlQIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZ # CgMCoAowCAIBAAIDB6EgoQowCAIBAAIDAYagMA0GCSqGSIb3DQEBCwUAA4IBAQCA # dVXLSX27hVlibsLhtHulRBg2dCh57pweOLROI2XrsOvJSj4yLC0uhTpMvnTxb5kS # GkYF1vdd1xxOsE3JiVBpc1PcocvMMCifSPPM97XugqGr4ao9kfnHFvKtNi2Q2Q3F # XZ3Lmx1rRJgPgwz7RBq+CXHsLIMMMoMseSeeUp0DWfXQktMt18nCS2qRO3nAfSq1 # n3r2VM5vvGICSQ1piy45np3byyRUTJUoMDZI78UVMABxbP5VuaSrDeK4KorX3sk2 # XanMzo8F7yI1EoaLBAUH+bUU8NxyjEh6Trh+AQoITIU1hrLEh9E9YUkBf0AVij/e # 72dW4uTa61J7VInkS6mZMYIEDTCCBAkCAQEwgZMwfDELMAkGA1UEBhMCVVMxEzAR # BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p # Y3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3Rh # bXAgUENBIDIwMTACEzMAAAIVGAPTgQcmfFMAAQAAAhUwDQYJYIZIAWUDBAIBBQCg # ggFKMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0BCQQxIgQg # Yz9nWMfe6gF3F7arXGKRQGl9qZpNfIwG4DhijLEkhB4wgfoGCyqGSIb3DQEJEAIv # MYHqMIHnMIHkMIG9BCBwEPR2PDrTFLcrtQsKrUi7oz5JNRCF/KRHMihSNe7sijCB # mDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYD # VQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAk # BgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAACFRgD04EH # JnxTAAEAAAIVMCIEIAwrKl4+SQQznVmLkPNf3C/fGPZI0LmAhVatnQWUTX7QMA0G # CSqGSIb3DQEBCwUABIICAIGD7zy5yO4q6iYEPb8/l6y0W8zDnszH7MfR8r1ZdfMx # wSWLAHLovtHoNOaX2zvipeQ1DyS3T/G0zCK2Byqcsjc1EGK8iqPK5XvrlLm9ZmHz # t+SHBDnlAfLpHlcj1/Duqs9lNaLgYktAWO0DJaGNWDdCX09aHVkXeyRQcDK3Gl2Q # Mu5oIC5ZoKuQf2ETqPtq+3sVeRjUan3dScpzlPtZvpfBJfq6Ef5axe73VUoAb2Kk # ucVYXAp6hnuY1wXMmfMGHoU3Oor1ZAFTN3uN/WgmyxWnVyLIUKfB3HsjsM4DhptI # RBqjLF/OPACddKhP3Ly2vn06RbVXFhlx5qAc6ymKZ5YcvOpLLDCSi4Hu0QlAhV48 # qZfixGKM3Nrd7XMPYOpEnaQMkoixjchqfFi2vCk7Oon6xR3UfBJXkkIkaslw1NW1 # SAF1TWJCzERvi5ocSoMyztzsxvGwODbIBUpLgMRLup3SaKDndZK6Mj0NKDpg9wSx # Q64RG8YPLbDZ6ziZlo2JUlpeT97CQHH1mSmMv03eWT6tjO/JPbQeVhCRO88kAei4 # C/S2WUSR0euy2WXH6livgUQGIYwEsO2w/2W0FpqglHfSqMRzNMDvHEu4qHJg+iMV # UZsWfunUbSLmXXF80o8qGnqkk5dgKRp+VuG69cHtcAbR/wSjpJlhURoVVbTmCvjU # SIG # End signature block