eventsModule/Test.AdfsEventsModule.ps1

function Initialize()
{
    ipmo .\AdfsEventsModule.psm1
    Set-AdfsProperties -AuditLevel Verbose

    # Try installing an RP. If it already exists, use the existing one
    try
    {
        $authzRules = "=>issue(Type = `"http://schemas.microsoft.com/authorization/claims/permit`", Value = `"true`"); "
        $issuanceRules = "x:[]=>issue(claim = x); "
        $redirectUrl = "https://adfshelp.microsoft.com/ClaimsXray/TokenResponse"
        $samlEndpoint = New-AdfsSamlEndpoint -Binding POST -Protocol SAMLAssertionConsumer -Uri $redirectUrl

        Add-ADFSRelyingPartyTrust -Name "ClaimsXray" -Identifier "urn:microsoft:adfs:claimsxray" -IssuanceAuthorizationRules $authzRules -IssuanceTransformRules $issuanceRules -WSFedEndpoint $redirectUrl -SamlEndpoint $samlEndpoint
    }
    catch
    {

    }

    # Clear any existing logs

}

function Make-Request([string]$Guid){
    $farmhost = (Get-AdfsProperties).HostName
    $url = "https://" + $farmhost + "/adfs/ls?wa=wsignin1.0&wtrealm=urn:microsoft:adfs:claimsxray"

    if ( $Guid )
    {
        $url = $url + "&client-request-id=" + $Guid
    }

    Invoke-WebRequest -URI $url
}

function Validate-LogEventCount([object]$logs){
    if($logs.Count -gt 0 -and $logs[0].Events.Count -gt 0)
    {
        return $true    
    }

    return $false
} 

Describe 'Basic functionality of Get-AdfsEvents'{
    BeforeAll {
        Initialize

        # Make a few requests for the ByTime tests
        $global:startTime = Get-Date
        for($i=0; $i -le 5; $i++)
        {
            Make-Request
        }

        $global:currentGuid = [guid]::NewGuid()
        Make-Request($global:currentGuid.Guid)

        # Give the auditing system time to flush the audits to the system
        Start-Sleep -Seconds 3

        $global:endTime = Get-Date

        $securityLogs = "Security"
        $global:exportFileName = (pwd).Path + "\SecurityLogs.evtx"
        wevtutil.exe export-log $securityLogs $exportFileName /overwrite:true
    }

    AfterAll {
        rm $global:exportFileName
    }

    It "[00000]: 'All' Flag Returns CorrIDs that are valid guids"{
        $logs = Get-AdfsEvents -Logs Security -All
        
        Validate-LogEventCount($logs) | Should -Be $true

        $hasInvalidGuid = $false

        foreach ( $aggObj in $logs )
        {
            $guidRef = [ref] [System.Guid]::NewGuid()
            $valid = [System.Guid]::TryParse( $aggObj.CorrelationID, $guidRef )

            if ( !$valid -or ( $guidRef.Value -ne $aggObj.CorrelationID ) )
            {
                $hasInvalidGuid = $true
                break
            }
        }

        $hasInvalidGuid | Should -Be $false
    }

    It "[00000]: 'All' Flag Returns Multiple Aggregate Objects, with Multiple Events"{
        $logs = Get-AdfsEvents -Logs Security, Admin -All
        Validate-LogEventCount($logs) | Should -Be $true
    }

    It "[00000]: 'All' Flag Returns Aggregate Objects, with Events by correlation ID"{
        $logs = Get-AdfsEvents -Logs Security, Admin -All
        
        $hasInvalidId = $false
        foreach ( $aggObj in $logs )
        {
            foreach ( $event in $aggObj.Events )
            {
                if ( $event.CorrelationID -ne $aggObj.CorrelationID )
                {
                    $hasInvalidId = $true
                }
            }
        }

        $hasInvalidId | Should -Be $false
    }

    It "[00100]: 'All' Flag with FromFile Returns Non-Empty Events List"{
        $logs = Get-AdfsEvents -Logs Security -All -FilePath $global:exportFileName
        Validate-LogEventCount($logs) | Should -Be $true
    }

    It "[01000]: 'All' Flag with AnalysisData Returns Analysis Objects"{
        $logs = Get-AdfsEvents -Logs Security -All -CreateAnalysisData

        $hasInvalidBlob = $false

        foreach ( $aggObj in $logs )
        {
            if ( -not $aggObj.AnalysisData.requests.Count )
            {
                $hasInvalidBlob = $true
                break
            }
        }

        $hasInvalidBlob | Should -Be $false
    }

    It "[01001]: ByTime with AnalysisData Returns Analysis Objects"{
        $logs = Get-AdfsEvents -Logs Security -CreateAnalysisData -StartTime $global:startTime -EndTime $global:endTime 

        $hasInvalidBlob = $false

        foreach ( $aggObj in $logs )
        {
            if ( -not $aggObj.AnalysisData.requests.Count )
            {
                $hasInvalidBlob = $true
                break
            }
        }

        $hasInvalidBlob | Should -Be $false
    }

    It "[01001]: ByTime returns Multiple Aggregate Objects, with Multiple Events"{
        $logs = Get-AdfsEvents -Logs Security -StartTime $global:startTime -EndTime $global:endTime 
        Validate-LogEventCount($logs) | Should -Be $true
    }

    It "[01100]: 'All' Flag with AnalysisData with FromFile Returns Non-Empty Events List"{
        $logs = Get-AdfsEvents -Logs Security -All -FilePath $global:exportFileName -CreateAnalysisData
        Validate-LogEventCount($logs) | Should -Be $true
    }

    It "[01101]: ByTime with AnalysisData with FromFile returns Non-Empty Events List"{
        $logs = Get-AdfsEvents -Logs Security -FilePath $global:exportFileName -CreateAnalysisData -StartTime $global:startTime -EndTime $global:endTime 
        Validate-LogEventCount($logs) | Should -Be $true
    }

    It "[10000]: CorrelationID Call Returns Exactly 1 Aggregate Object"{
        $logs = Get-AdfsEvents -Logs Security, Admin, Debug -CorrelationID $global:currentGuid.Guid

        # Note: despite the fact that PowerShell should always be giving us a list object out of Get-AdfsEvents, the
        # Count and Length calls do not work when there is only 1 entry in the list

        $hasAtLeastOne = $false
        $hasExactlyOne = $false

        if ( $logs[0].CorrelationID )
        {
            $hasAtLeastOne = $true            
        }

        if ( $hasAtLeastOne -and ( -not $logs[1] ) )
        {
            $hasExactlyOne = $true            
        }

        $hasExactlyOne | Should -Be $true
    }

    It "[10000]: CorrelationID Call Returns Non-Empty Events list"{
        $logs = Get-AdfsEvents -Logs Security, Admin, Debug -CorrelationID $global:currentGuid.Guid
        $logs[0].Events.Count | Should -BeGreaterThan 0 
    }

    It "[10000]: CorrelationID Call Returns Events list with 403 and 404"{

        $logs = Get-AdfsEvents -Logs Security, Admin, Debug -CorrelationID $global:currentGuid.Guid

        $has403 = $false
        $has404 = $false 

        foreach( $event in $logs.Events )
        {
            if ( $event.Id -eq 403 )
            {
                $has403 = $true
            }

            if ( $event.Id -eq 404 )
            {
                $has404 = $true
            }
        }

        $hasBoth = $has403 -and $has404
        $hasBoth | Should -Be $true
    }

    It "[10000]: CorrelationID Call Returns Analysis Data With Single Request"{
        $logs = Get-AdfsEvents -Logs Security, Admin, Debug -CorrelationID $global:currentGuid.Guid -CreateAnalysisData
        $logs.AnalysisData.requests.Count | Should -Be 1
    }

    It "[10000]: CorrelationID Call Returns Analysis Data With Single Timeline Event"{
        $logs = Get-AdfsEvents -Logs Security, Admin, Debug -CorrelationID $global:currentGuid.Guid -CreateAnalysisData
        $logs.AnalysisData.timeline.Count | Should -Be 1
        $logs.AnalysisData.timeline[0].type | Should -Be "incoming"
    }

    It "[10100]: CorrelationID Call with FromFile returns Non-Empty Events List"{
        $logs = Get-AdfsEvents -Logs Security -CorrelationID $global:currentGuid.Guid -FilePath $global:exportFileName
        $logs[0].Events.Count | Should -BeGreaterThan 0 
    }

    It "[10101]: ByTime with CorrelationID is not a valid scenario"{
        
        $invalidScenarioError = $false;

        try
        {
            $logs = Get-AdfsEvents -Logs Security -StartTime $global:startTime -EndTime $global:endTime -CorrelationID $global:currentGuid.Guid
        }catch [System.Management.Automation.ParameterBindingException]
        {
            $invalidScenarioError = $true;
        }
        
        $invalidScenarioError | Should -Be $true
    }

    It "[11100]: CorrelationID Call with AnalysisData with FromFile returns Non-Empty Events List"{
        $logs = Get-AdfsEvents -Logs Security -CorrelationID $global:currentGuid.Guid -FilePath $global:exportFileName -CreateAnalysisData 
        $logs[0].Events.Count | Should -BeGreaterThan 0 
    }
}

# SIG # Begin signature block
# MIIjgwYJKoZIhvcNAQcCoIIjdDCCI3ACAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAxcUHPl6q9IOYV
# mELWSDCXFTk32+pzbsfTEtHdDUmsBKCCDYIwggYAMIID6KADAgECAhMzAAABXFSi
# Z7ZIC9ybAAAAAAFcMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
# bmcgUENBIDIwMTEwHhcNMTkwNjA1MTczNDU2WhcNMjAwNjAzMTczNDU2WjB0MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQC1Bfsypco2wGSeVhv1kfGPga1DJXLSLKz6oDb870Zcez2WOFhcKlcIozpXNwjY
# tKAnHUlDjbkJ+Ejwe/sfKf8B0gEltYzCNHgoRG1JLCCnPm+3jzTItIVDewLi0zGZ
# 4WmeR6k05qBNg9eBfgdc+6PwHNkEy+hmu7ewXTsrUxwjMX2xSC56wawzIYyqr78w
# YhZRL2MfFmH0rBViobUMU3/5MwPCbVGJY05mZMGM1x6QL9WlhA+d0JIT1q3u4jbh
# iK8wScxiDyeIykDxzluGHaa76hgIdFDRidNhTmYBEXn2r1MaLRviiLZyjEt7avi7
# qqkhXefzIZ5c2iV1tb9Kc31zAgMBAAGjggF/MIIBezArBgNVHSUEJDAiBgorBgEE
# AYI3TBMBBgorBgEEAYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUtJuPF6DKaOYX
# HqR+uQJbTOBzmX8wRQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBD
# b3Jwb3JhdGlvbjEWMBQGA1UEBRMNMjMzMTEwKzQ1NTUwMjAfBgNVHSMEGDAWgBRI
# bmTlUAXTgqoXNzcitW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3
# Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEt
# MDctMDguY3JsMGEGCCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3
# dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIw
# MTEtMDctMDguY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAEoN
# 39sJSBkqbUsRcN8UdOReYS/hQ0qCkZged24kxOvI1oeHznc8uNljCCyaeeA5bra3
# 55bZbzYBjTxHC+aQI0OUqkYhSXjf1irM08RCjt/NehtYfcnJq7QUDX0ge+qEfOK2
# bW9XMrcomzA69ZMMNRRNh0G81xV1UlTCbBlOsjFG1+mADQwZGWtOWtlScj3OU4HR
# oiXTaF3i064ANwZdebIIdMhzaGfCdWotnSmRiBIOqYhzE+vA4FGNuS20WyUsvCKK
# sXHCtOLI6+eWRX6VHqxQ4lrmCt7e6AjMeQ7dalQMtK7ttJ05lQhjV+eo1ibnqwyh
# UbMOFJBYy5DlSXng+iBLh4VEMiVVOf+hzHJyRDyZ0oladgmYtO2hrRc237HfojsB
# tFZuKF3D2udA9JlkoK9CE1rXjw0ShCoJnvLVaht4XEnQMhvu6BVx8nAtN1o6/BO5
# N3dKqX90ZnJxBKGDVjXMQXLjP8PeWU0zhS8eKiFkCyv/zVuydqH+1wfdBFjMX0EY
# asudfJXcRNlfTASIxeuCCDSNRm/SZiD4wDsRv8bkhTYJ3eFwKHhf+4XTjVJbStOH
# sVIyRaqX7m1EU2W/AdeY9/5wjaCgW4LU72JMsdXtQRpyyJYzB07ofeYcJtDdSa08
# LGIdTlOX8pIXQtsO7WIQvlWuK+RbyKJnEaROThFGMIIHejCCBWKgAwIBAgIKYQ6Q
# 0gAAAAAAAzANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT
# Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m
# dCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNh
# dGUgQXV0aG9yaXR5IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEwOTA5
# WjB+MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
# UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQD
# Ex9NaWNyb3NvZnQgQ29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG9w0B
# AQEFAAOCAg8AMIICCgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+laUKq4
# BjgaBEm6f8MMHt03a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc6Whe
# 0t+bU7IKLMOv2akrrnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4Ddato
# 88tt8zpcoRb0RrrgOGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+lD3v
# ++MrWhAfTVYoonpy4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDst
# rjNYxbc+/jLTswM9sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6A4aN
# 91/w0FK/jJSHvMAhdCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmdX4ji
# JV3TIUs+UsS1Vz8kA/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL5zmh
# D+kjSbwYuER8ReTBw3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zdsGbi
# wZeBe+3W7UvnSSmnEyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3T8Hh
# hUSJxAlMxdSlQy90lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS4NaI
# jAsCAwEAAaOCAe0wggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTl
# UAXTgqoXNzcitW2oynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNV
# HQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQF
# TuHqp8cx0SOJNDBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jvc29m
# dC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNf
# MjIuY3JsMF4GCCsGAQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3dy5t
# aWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNf
# MjIuY3J0MIGfBgNVHSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEFBQcC
# ARYzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1hcnlj
# cHMuaHRtMEAGCCsGAQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5
# AF8AcwB0AGEAdABlAG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn8oal
# mOBUeRou09h0ZyKbC5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7v0ep
# o/Np22O/IjWll11lhJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0bpdS1
# HXeUOeLpZMlEPXh6I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtY
# SWMfCWluWpiW5IP0wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvyCInW
# H8MyGOLwxS3OW560STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZ
# iWhub6e3dMNABQamASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJihsMd
# YzaXht/a8/jyFqGaJ+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYbBL7f
# QccOKO7eZS/sl/ahXJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKf
# enoi+kiVH6v7RyOA9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOpp
# O6/8MO0ETI7f33VtY5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZO
# SEXAQsmbdlsKgEhr/Xmfwb1tbWrJUnMTDXpQzTGCFVcwghVTAgEBMIGVMH4xCzAJ
# BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k
# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jv
# c29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTECEzMAAAFcVKJntkgL3JsAAAAAAVww
# DQYJYIZIAWUDBAIBBQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYK
# KwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIOcjLZ31
# k7jZ1P/1ffm2pXe0iBWzQz/DO0xNnP6D+KJIMEIGCisGAQQBgjcCAQwxNDAyoBSA
# EgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20w
# DQYJKoZIhvcNAQEBBQAEggEAgtXlB9ltor028roHMt9sHOogsY8DQmwbaIajPxy3
# BdGy1dw0a1yu3pMOm3kLlyyrZtkjb+339d3/qNL6diNS+aB1Hpr1x9OKV9HuI3Pb
# JU5fhaYPTKylw3u4wMCkNwkZVe7wQF9wKXUOCxwwV45c6GlKmPJ9gfkTmhENENUC
# 5LuGqW6R1xjS7ih0Y6XOeWST0lmaysQT1pIr/jlOoIO2p+VOB9aPZ4bA6fcsmdwQ
# 3ReBRorWqohBWZntx8I9pg4+zj1uC5HMKy4OzIQenQhThT3lwDbEmLtKiS03NV+L
# Ylddw9RwV9O10gswU3W40oQ6QDQpgGk+S/Jw11yLlNqStqGCEuEwghLdBgorBgEE
# AYI3AwMBMYISzTCCEskGCSqGSIb3DQEHAqCCErowghK2AgEDMQ8wDQYJYIZIAWUD
# BAIBBQAwggFQBgsqhkiG9w0BCRABBKCCAT8EggE7MIIBNwIBAQYKKwYBBAGEWQoD
# ATAxMA0GCWCGSAFlAwQCAQUABCCursuHUQiUY2oIoKNgh5HNaN7ItYJcI3e0upmf
# OFdvjQIGXMtItN5vGBIyMDE5MDczMTE3MjM0MC4wMVowBIACAfSggdCkgc0wgcox
# CzAJBgNVBAYTAlVTMQswCQYDVQQIEwJXQTEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQg
# SXJlbGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJjAkBgNVBAsTHVRoYWxlcyBUU1Mg
# RVNOOkEyNDAtNEI4Mi0xMzBFMSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFt
# cCBzZXJ2aWNloIIOOTCCBPEwggPZoAMCAQICEzMAAADgship1NHCtPcAAAAAAOAw
# DQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0
# b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3Jh
# dGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwHhcN
# MTgwODIzMjAyNzAxWhcNMTkxMTIzMjAyNzAxWjCByjELMAkGA1UEBhMCVVMxCzAJ
# BgNVBAgTAldBMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQg
# Q29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJhdGlv
# bnMgTGltaXRlZDEmMCQGA1UECxMdVGhhbGVzIFRTUyBFU046QTI0MC00QjgyLTEz
# MEUxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIHNlcnZpY2UwggEiMA0G
# CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCl/hnDsembJx7FMS5RuaJsiQJDP0t
# iqyeCettiNlGcNoa428oVtblH6yZatCXZygyhzbnDJofTHIGtdiEzQc5fPhddfTd
# 4hEQgd5ch/BlGITXFEwJ4d/GhHZQ1hbLdiBT/j67Qx15VeuXy5n/jM9PvIbBksSW
# wX8vrkhRT/rqa1xWrmF+SfcYKw+pC+d3tUHrgACo0YaVHuS3jlpXg33A+pul8wib
# ZBcGxMF1CqwlP0AfMW60Dp4qm/JLbWxdx/pOiiOrM/tykFDtEnN07HXRjXDhDhfI
# eBCz4GPiCEFk94AaFxysFeFn9vyz7TyKJxUksXJhtWGq2i4WmPcphyDzAgMBAAGj
# ggEbMIIBFzAdBgNVHQ4EFgQUa0HTCrY5zqzv/p44rWuSbXaAh+gwHwYDVR0jBBgw
# FoAU1WM6XIoxkPNDe3xGG8UzaFqFbVUwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDov
# L2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljVGltU3RhUENB
# XzIwMTAtMDctMDEuY3JsMFoGCCsGAQUFBwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0
# cDovL3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNUaW1TdGFQQ0FfMjAx
# MC0wNy0wMS5jcnQwDAYDVR0TAQH/BAIwADATBgNVHSUEDDAKBggrBgEFBQcDCDAN
# BgkqhkiG9w0BAQsFAAOCAQEACx/endmS5DW6xgb8fIdEqI963fUB7IoYlYNQU/YZ
# wq155uK1lwhcH5R1CaVMr+lyNIfD8l+lqy8mdou+Zwcrnzo3m2UEGO0uNFd4c8Ie
# w5Z49V+6AojT6z5IGJh3y56uDACQzRZrR+26uCx1nLsYjK/WtxQDq1IHHWeAxfrG
# xsAZO1BdQo25Mx34ZseViVj+usfmy0nUmfvZ0hFcMeNd4i4Kds03kY/CwWVZBw62
# tAjOHK/c81wO7hiutu9JX4MNjaEuFdheiNwmHyAmbpqYmz6K+9IPM75iXELbzjDc
# 6yLJpVOq17gfVDCaweryzgVnC2CIxq7gDGyTM9afwMtESTCCBnEwggRZoAMCAQIC
# CmEJgSoAAAAAAAIwDQYJKoZIhvcNAQELBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRp
# ZmljYXRlIEF1dGhvcml0eSAyMDEwMB4XDTEwMDcwMTIxMzY1NVoXDTI1MDcwMTIx
# NDY1NVowfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNV
# BAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQG
# A1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwggEiMA0GCSqGSIb3
# DQEBAQUAA4IBDwAwggEKAoIBAQCpHQ28dxGKOiDs/BOX9fp/aZRrdFQQ1aUKAIKF
# ++18aEssX8XD5WHCdrc+Zitb8BVTJwQxH0EbGpUdzgkTjnxhMFmxMEQP8WCIhFRD
# DNdNuDgIs0Ldk6zWczBXJoKjRQ3Q6vVHgc2/JGAyWGBG8lhHhjKEHnRhZ5FfgVSx
# z5NMksHEpl3RYRNuKMYa+YaAu99h/EbBJx0kZxJyGiGKr0tkiVBisV39dx898Fd1
# rL2KQk1AUdEPnAY+Z3/1ZsADlkR+79BL/W7lmsqxqPJ6Kgox8NpOBpG2iAg16Hgc
# sOmZzTznL0S6p/TcZL2kAcEgCZN4zfy8wMlEXV4WnAEFTyJNAgMBAAGjggHmMIIB
# 4jAQBgkrBgEEAYI3FQEEAwIBADAdBgNVHQ4EFgQU1WM6XIoxkPNDe3xGG8UzaFqF
# bVUwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud
# EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU1fZWy4/oolxiaNE9lJBb186aGMQwVgYD
# VR0fBE8wTTBLoEmgR4ZFaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwv
# cHJvZHVjdHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3JsMFoGCCsGAQUFBwEB
# BE4wTDBKBggrBgEFBQcwAoY+aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraS9j
# ZXJ0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcnQwgaAGA1UdIAEB/wSBlTCB
# kjCBjwYJKwYBBAGCNy4DMIGBMD0GCCsGAQUFBwIBFjFodHRwOi8vd3d3Lm1pY3Jv
# c29mdC5jb20vUEtJL2RvY3MvQ1BTL2RlZmF1bHQuaHRtMEAGCCsGAQUFBwICMDQe
# MiAdAEwAZQBnAGEAbABfAFAAbwBsAGkAYwB5AF8AUwB0AGEAdABlAG0AZQBuAHQA
# LiAdMA0GCSqGSIb3DQEBCwUAA4ICAQAH5ohRDeLG4Jg/gXEDPZ2joSFvs+umzPUx
# vs8F4qn++ldtGTCzwsVmyWrf9efweL3HqJ4l4/m87WtUVwgrUYJEEvu5U4zM9GAS
# inbMQEBBm9xcF/9c+V4XNZgkVkt070IQyK+/f8Z/8jd9Wj8c8pl5SpFSAK84Dxf1
# L3mBZdmptWvkx872ynoAb0swRCQiPM/tA6WWj1kpvLb9BOFwnzJKJ/1Vry/+tuWO
# M7tiX5rbV0Dp8c6ZZpCM/2pif93FSguRJuI57BlKcWOdeyFtw5yjojz6f32WapB4
# pm3S4Zz5Hfw42JT0xqUKloakvZ4argRCg7i1gJsiOCC1JeVk7Pf0v35jWSUPei45
# V3aicaoGig+JFrphpxHLmtgOR5qAxdDNp9DvfYPw4TtxCd9ddJgiCGHasFAeb73x
# 4QDf5zEHpJM692VHeOj4qEir995yfmFrb3epgcunCaw5u+zGy9iCtHLNHfS4hQEe
# gPsbiSpUObJb2sgNVZl6h3M7COaYLeqN4DMuEin1wC9UJyH3yKxO2ii4sanblrKn
# QqLJzxlBTeCG+SqaoxFmMNO7dDJL32N79ZmKLxvHIa9Zta7cRDyXUHHXodLFVeNp
# 3lfB0d4wwP3M5k37Db9dT+mdHhk4L7zPWAUu7w2gUDXa7wknHNWzfjUeCLraNtvT
# X4/edIhJEqGCAsswggI0AgEBMIH4oYHQpIHNMIHKMQswCQYDVQQGEwJVUzELMAkG
# A1UECBMCV0ExEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD
# b3Jwb3JhdGlvbjEtMCsGA1UECxMkTWljcm9zb2Z0IElyZWxhbmQgT3BlcmF0aW9u
# cyBMaW1pdGVkMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjpBMjQwLTRCODItMTMw
# RTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgc2VydmljZaIjCgEBMAcG
# BSsOAwIaAxUAxnmkjOXedpqyHQqkJGn7ewhSC9GggYMwgYCkfjB8MQswCQYDVQQG
# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQg
# VGltZS1TdGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQUFAAIFAODrxDcwIhgPMjAx
# OTA3MzExNTM5MzVaGA8yMDE5MDgwMTE1MzkzNVowdDA6BgorBgEEAYRZCgQBMSww
# KjAKAgUA4OvENwIBADAHAgEAAgIfAzAHAgEAAgIRtzAKAgUA4O0VtwIBADA2Bgor
# BgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIBAAIDB6EgoQowCAIBAAID
# AYagMA0GCSqGSIb3DQEBBQUAA4GBAKh6Fg1ATz+6FlO9B8IN6hv6yYnww3FwapzT
# xai5m+xUA9TsUDGDFDDkDQ2XrXc4yBDFNE6qNI+6acOUS7UvLNvfO3vkJmkko5ui
# L8E8jrAnrOnOkhVrEB8/1HxT0uHgV3zR6bjE4fUNxWYZICkuBLh0qPoN6EH9+zEv
# il5C7j8fMYIDDTCCAwkCAQEwgZMwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh
# c2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD
# b3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIw
# MTACEzMAAADgship1NHCtPcAAAAAAOAwDQYJYIZIAWUDBAIBBQCgggFKMBoGCSqG
# SIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0BCQQxIgQgJHYykQ9q0rCy
# O4euw2PGz4xmXG9a1gYCgmz25vJKZPwwgfoGCyqGSIb3DQEJEAIvMYHqMIHnMIHk
# MIG9BCClgS9VpDMosldyg1GQPVVk5wwNOD+Pcl2aoLvRrEJfkDCBmDCBgKR+MHwx
# CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt
# b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1p
# Y3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAAA4LIYqdTRwrT3AAAAAADg
# MCIEIPBqt6pctCaN7WKlMVZ9bOCJ9nXQGXRMRSoph+FpHf0hMA0GCSqGSIb3DQEB
# CwUABIIBAHd1m4uUSLm4faGBBOTf+98zrkF5jmIfY9ZYrLNO/I0dYBquSeHMMkR9
# XV1iAP25xZlAMsnJm9RN68EPuSuJfq6fdc8Lr4aYn8l5SytYwgkSI1+AeUQvmHXN
# 51RXSepiKsZhULaGKtd2EgsRZxquzPfaMogatmwPKwU0KCnh0EzB4SU/3Zu0kWfy
# 10kPUgltF1OP+0DztlW5Zr/dK2ADcgZS5hY6V14zVwmA93oaT8knIV9QABQZDV8Z
# SnF+3aBY5SPwZ1gm55KBfGT+K8uw60lg6jJypKcaBwpPxGVt/P131Qhdk5i99+KS
# umZkJPHMm2asXJn+BR+K9F4+OZhHEak=
# SIG # End signature block