2atWeb.psm1

#Requires -Version 4.0 -Modules 2atGeneral

$PSDefaultParameterValues.Clear()
Set-StrictMode -Version 2.0

$ErrorActionPreference = 'Stop'

Add-Type -Assembly System.Net.Http
Import-Module 2atGeneral

Function HashTableToDictionary {
    Param(
        [Parameter(Mandatory=$true)]
        [HashTable]$HashTable
    )
    
    $Dictionary = New-Object 'System.Collections.Generic.Dictionary[string,string]'
    $HashTable.Keys | %{ $Dictionary.Add($_, $HashTable[$_]) }
    $Dictionary
}

Function ReadCookiesFromResponseHeader{
    Param(
            [Parameter(Mandatory=$true)]
            $CookieHeaders,
            [string]$Url
    )
    
    $CookieCollection = New-Object System.Net.CookieCollection

    foreach($c in $CookieHeaders) {
        $Cookie = New-Object System.Net.Cookie 
        
        $cookieName = $c.Substring(0,$c.Indexof('='))
        if (-Not ($CookieName -match "[,; ]")) { 
            $Cookie.Name = $c.Substring(0,$c.Indexof('='))
        } else {
            return $CookieCollection
        }

        $cValue = ($c.Substring($c.Indexof('=')+1, $c.Length - $c.Indexof('=')-1)).Split(';')
        Foreach ($var in $cValue) {
            if ($var.Contains('path='))    { 
                $path = ($var.Split('='))[1].Trim() 
                if ($path.LastIndexOf('/') -eq $path.Length -1 ) { $path = $path.Substring(0, $path.Length-1) } 
                $Cookie.Path = $path
            }
            if ($var.Contains('HttpOnly')) { $Cookie.HttpOnly = $true }
            if ($var.Contains('expires'))  { 
                if ($var.Split('=')[1] -as [DateTime]) {
                    $Cookie.Expires = Get-Date $var.Split('=')[1] 
                }
            }
        }
        $Cookie.Value = $cValue[0]
        $Cookie.Domain = ([System.Uri]$url).DnsSafeHost

        $CookieCollection.Add($Cookie)
        Write-Verbose "ReadCookiesFromResponseHeader: Added cookie to collection: $($cookie.Name)"
    }

    $CookieCollection

}

Function Get-WebResponseString {
    Param(
        [Parameter(Mandatory=$true)]
        [PSCustomObject]$WebResponse
    )
    Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState

    $headers = ($WebResponse.ResponseHeaders | %{ "$($_): $($WebResponse.ResponseHeaders[$_])" }) -join [Environment]::NewLine
    
    "HTTP/$($WebResponse.ProtocolVersion) $([int]$WebResponse.HTTPStatus) $($WebResponse.HTTPStatusDescription)
$headers
 
$($WebResponse.ResponseBody)"

}

Function Get-WebResponse {
    Param(
        [Parameter(Mandatory=$true)]
        [ValidateScript({(New-Object System.Uri $_)})]
        [string]$Url,

        [hashtable]$HostIPs = @{},

        [System.Net.CookieContainer]$CookieContainer,
        
        [string]$Method = 'GET',
        
        [object]$FormData,
        
        [System.Net.WebProxy]$Proxy,
        
        [System.Net.ICredentials]$Credentials,
        
        [string]$UserAgent
    )

    Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState
    
    if ($FormData -And -Not ($FormData -is [HashTable] -or $FormData -is [System.Collections.Generic.Dictionary[string,string]])) { throw 'FormData must be either a HashTable or a Dictionary[string,string]' }

    $o = [ordered]@{
        DateTime=Get-Date
        Url=$Url
        Method=$Method
        HostHeader=$null
        FormData=$null
        WebRequestStatus=[System.Net.WebExceptionStatus]::Success
        WebRequestStatusDescription=$null
        ProtocolVersion=$null
        HTTPStatus=$null
        HTTPStatusDescription=$null
        ResponseHeaders=$null
        ResponseBody=$null
    }

    if ($HostIPs.Keys | ?{ $url -match "(https?://)($_)(/.*)" }) { 
        $req = [System.Net.WebRequest]::Create("$($Matches[1])$($HostIPs[$Matches[2]])$($Matches[3])")
        $o.HostHeader = $req.Host = $Matches[2]
    } else {
        $req = [System.Net.WebRequest]::Create($Url)
    }

    $req.AllowAutoRedirect = $false
    if (!$UserAgent) { 
        $req.UserAgent = 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0; 2AT Monitoring; +http://2at.nl)'
    } else {
        $req.UserAgent = $UserAgent
    }
    $req.CookieContainer = $CookieContainer
    $req.Method = $Method
    $req.Proxy = $Proxy
    $req.Credentials = $Credentials

    $c = $null
    if ($FormData) {
        if ($FormData['SOAP'] -OR $FormData['API']) {
            if ($FormData['SOAP']) {
                $o.FormData = $FormData
                   $c = New-Object System.Net.Http.StringContent $FormData['SOAP'].InnerXml
                $req.ContentType = 'text/xml'
                $req.Headers['SOAPAction'] = $FormData['SOAPAction']
            }
            if ($FormData['API']) {
                $o.FormData = $FormData
                $FormData['API'].Keys | % { $req.Headers[$_] = $FormData['API'][$_] }
                $req.Accept = 'application/json'
            }
        } else {
            if ($FormData -is [HashTable]) { $FormData = HashTableToDictionary $FormData }
            $o.FormData = $FormData
            $c = New-Object System.Net.Http.FormUrlEncodedContent $FormData
            $req.ContentType = $c.Headers.ContentType.MediaType
        }
    }
    
    $reader = $null
    $resp = $null
    try {
        $o.TotalTime = Measure-Command {
            $o.TimeToFirstByte = Measure-Command {
                try {
                    if ($c) {
                        Wait-Job $c.CopyToAsync($req.GetRequestStream())
                    }
                    $resp = $req.GetResponse()
                } catch [System.Net.WebException] {
                    $e = $_.Exception
                    
                    Write-Warning "$Method $Url : $($e.Status) - $($e.Message)"

                    $resp = $e.Response
                    $o.WebRequestStatus = $e.Status
                    $o.WebRequestStatusDescription = $e.Message
                }
            }
            if ($resp) {
                $encoding = if ($resp.CharacterSet) {
                    try {
                        [System.Text.Encoding]::GetEncoding($resp.CharacterSet)
                    } catch {
                        Write-Warning "$Method $Url : Invalid encoding $($resp.CharacterSet)"
                    }
                }
                if ($encoding) {
                    $reader = New-Object System.IO.StreamReader $resp.GetResponseStream(), $encoding
                } else {
                    $reader = New-Object System.IO.StreamReader $resp.GetResponseStream()
                }

                $o.ResponseBody = $reader.ReadToEnd()
            }
        }

        if ($resp) {
            $o.ProtocolVersion = $resp.ProtocolVersion
            $o.ResponseHeaders = $resp.Headers
            $o.HTTPStatus = $resp.StatusCode
            $o.HTTPStatusDescription = $resp.StatusDescription
        }

        # With some ASP.net applications the response cookies are not added to the cookiecontainer
        if ($resp.Cookies.Count -eq 0 -AND $resp.Headers['Set-Cookie'] -ne $null) {
            $Cookies = ReadCookiesFromResponseHeader -CookieHeaders $resp.Headers.GetValues('Set-Cookie') -Url $Url
            ForEach ($cookie in $Cookies) {
                $uri = [System.Uri] $url
                $CookieContainer.Add("$($uri.scheme)://$($cookie.Domain)$($cookie.Path)", $cookie)                
            }
        }

        [PSCustomObject]$o

    } finally {
        if ($reader) { $reader.Dispose() }
        if ($resp) { $resp.Dispose() }
    }
}

Export-ModuleMember -Function Get-*

# SIG # Begin signature block
# MIIhcgYJKoZIhvcNAQcCoIIhYzCCIV8CAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCB4L1maUMLfpgqm
# WJUbXK978Yas+Pv87KcZG597mpIZw6CCCxswggUzMIIEG6ADAgECAhEAgNHe/U3D
# BzyckFGAgIDcJDANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJHQjEbMBkGA1UE
# CBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQK
# ExFDT01PRE8gQ0EgTGltaXRlZDEjMCEGA1UEAxMaQ09NT0RPIFJTQSBDb2RlIFNp
# Z25pbmcgQ0EwHhcNMTcwMTEzMDAwMDAwWhcNMjAwMTEzMjM1OTU5WjCBgDELMAkG
# A1UEBhMCTkwxEDAOBgNVBBEMBzM1NDIgRFoxEDAOBgNVBAgMB1V0cmVjaHQxEDAO
# BgNVBAcMB1V0cmVjaHQxFTATBgNVBAkMDEVuZXJnaWV3ZWcgMTERMA8GA1UECgwI
# MkFUIEIuVi4xETAPBgNVBAMMCDJBVCBCLlYuMIIBIjANBgkqhkiG9w0BAQEFAAOC
# AQ8AMIIBCgKCAQEAzB3KZ2CBenaD2WDwOsy0cHE6mLIeIYqWP718FuWeUZ5eejvw
# 8BozajbtBWgISZ2IMsTYZ1I7KFBzHgXXkNglmyboa6++x7j2Ws+T0hmHCUZ64AFb
# OkXjqYsOBCPhi3yuKIRLwc4snA3F3DCH24mBpDYymrU22+0vMIlDqpzRXBNEeIhG
# ss3jehu86l85fWVS54F5KGeDYQ2BT0Tc0UO6hMlcpCEVKIbthLm36q1/oSchRYjH
# B4JCT1KqACRhD0hJcQmTcJZvhpgOrglUVlj1ClS5xfWgHq3ySShOOZMecl0VNMtY
# xNi5TF1Ae+sie4044ioyGB6dGItGXwhObIk/9wIDAQABo4IBqDCCAaQwHwYDVR0j
# BBgwFoAUKZFg/4pN+uv5pmq4z/nmS71JzhIwHQYDVR0OBBYEFDHc2o80OMg8zNfF
# WMH8QB57E7rnMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQM
# MAoGCCsGAQUFBwMDMBEGCWCGSAGG+EIBAQQEAwIEEDBGBgNVHSAEPzA9MDsGDCsG
# AQQBsjEBAgEDAjArMCkGCCsGAQUFBwIBFh1odHRwczovL3NlY3VyZS5jb21vZG8u
# bmV0L0NQUzBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsLmNvbW9kb2NhLmNv
# bS9DT01PRE9SU0FDb2RlU2lnbmluZ0NBLmNybDB0BggrBgEFBQcBAQRoMGYwPgYI
# KwYBBQUHMAKGMmh0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NPTU9ET1JTQUNvZGVT
# aWduaW5nQ0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5j
# b20wGQYDVR0RBBIwEIEOc3VwcG9ydEAyYXQubmwwDQYJKoZIhvcNAQELBQADggEB
# AHGDJyOKLJwzdt4Y8ow7H4ZKZXs9Hopf0GhizzhcPWyWL7GI6QHhKHzFWYGsFhh2
# vesuY7p89jthK5YqSn1u2KUQuLWzQZQj3cZCK2BwSz6FpgmmjqIo49qCfKIB5IrE
# DcZAQPC9wxaXPI+R3B32JmTllBpkFQNTIJVcB7jR/Ft991iV17tMMq0GssMAHnVd
# /yvTWlUaE7XNtgtNYQ5v/8HxxNtdBXsIbdjiv/A8GjUmyPN8Dum9CW82hUqOE7U9
# AXHZIBWy9yrooSieo26GA1OzrBvnDc+L42JZnjvwdhBqSnbQrSS7L6VjVHU+Ct84
# Fnb5u23Jypdmj9123Hw9qJwwggXgMIIDyKADAgECAhAufIfMDpNKUv6U/Ry3zTSv
# MA0GCSqGSIb3DQEBDAUAMIGFMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRl
# ciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8g
# Q0EgTGltaXRlZDErMCkGA1UEAxMiQ09NT0RPIFJTQSBDZXJ0aWZpY2F0aW9uIEF1
# dGhvcml0eTAeFw0xMzA1MDkwMDAwMDBaFw0yODA1MDgyMzU5NTlaMH0xCzAJBgNV
# BAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcTB1Nh
# bGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMSMwIQYDVQQDExpDT01P
# RE8gUlNBIENvZGUgU2lnbmluZyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
# AQoCggEBAKaYkGN3kTR/itHd6WcxEevMHv0xHbO5Ylc/k7xb458eJDIRJ2u8UZGn
# z56eJbNfgagYDx0eIDAO+2F7hgmz4/2iaJ0cLJ2/cuPkdaDlNSOOyYruGgxkx9hC
# oXu1UgNLOrCOI0tLY+AilDd71XmQChQYUSzm/sES8Bw/YWEKjKLc9sMwqs0oGHVI
# wXlaCM27jFWM99R2kDozRlBzmFz0hUprD4DdXta9/akvwCX1+XjXjV8QwkRVPJA8
# MUbLcK4HqQrjr8EBb5AaI+JfONvGCF1Hs4NB8C4ANxS5Eqp5klLNhw972GIppH4w
# vRu1jHK0SPLj6CH5XkxieYsCBp9/1QsCAwEAAaOCAVEwggFNMB8GA1UdIwQYMBaA
# FLuvfgI9+qbxPISOre44mOzZMjLUMB0GA1UdDgQWBBQpkWD/ik366/mmarjP+eZL
# vUnOEjAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADATBgNVHSUE
# DDAKBggrBgEFBQcDAzARBgNVHSAECjAIMAYGBFUdIAAwTAYDVR0fBEUwQzBBoD+g
# PYY7aHR0cDovL2NybC5jb21vZG9jYS5jb20vQ09NT0RPUlNBQ2VydGlmaWNhdGlv
# bkF1dGhvcml0eS5jcmwwcQYIKwYBBQUHAQEEZTBjMDsGCCsGAQUFBzAChi9odHRw
# Oi8vY3J0LmNvbW9kb2NhLmNvbS9DT01PRE9SU0FBZGRUcnVzdENBLmNydDAkBggr
# BgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMA0GCSqGSIb3DQEBDAUA
# A4ICAQACPwI5w+74yjuJ3gxtTbHxTpJPr8I4LATMxWMRqwljr6ui1wI/zG8Zwz3W
# GgiU/yXYqYinKxAa4JuxByIaURw61OHpCb/mJHSvHnsWMW4j71RRLVIC4nUIBUzx
# t1HhUQDGh/Zs7hBEdldq8d9YayGqSdR8N069/7Z1VEAYNldnEc1PAuT+89r8dRfb
# 7Lf3ZQkjSR9DV4PqfiB3YchN8rtlTaj3hUUHr3ppJ2WQKUCL33s6UTmMqB9wea1t
# QiCizwxsA4xMzXMHlOdajjoEuqKhfB/LYzoVp9QVG6dSRzKp9L9kR9GqH1NOMjBz
# wm+3eIKdXP9Gu2siHYgL+BuqNKb8jPXdf2WMjDFXMdA27Eehz8uLqO8cGFjFBnfK
# S5tRr0wISnqP4qNS4o6OzCbkstjlOMKo7caBnDVrqVhhSgqXtEtCtlWdvpnncG1Z
# +G0qDH8ZYF8MmohsMKxSCZAWG/8rndvQIMqJ6ih+Mo4Z33tIMx7XZfiuyfiDFJN2
# fWTQjs6+NX3/cjFNn569HmwvqI8MBlD7jCezdsn05tfDNOKMhyGGYf6/VXThIXcD
# Cmhsu+TJqebPWSXrfOxFDnlmaOgizbjvmIVNlhE8CYrQf7woKBP7aspUjZJczcJl
# mAaezkhb1LU3k0ZBfAfdz/pD77pnYf99SeC7MH1cgOPmFjlLpzGCFa0wghWpAgEB
# MIGSMH0xCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIx
# EDAOBgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMSMw
# IQYDVQQDExpDT01PRE8gUlNBIENvZGUgU2lnbmluZyBDQQIRAIDR3v1Nwwc8nJBR
# gICA3CQwDQYJYIZIAWUDBAIBBQCgfDAQBgorBgEEAYI3AgEMMQIwADAZBgkqhkiG
# 9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIB
# FTAvBgkqhkiG9w0BCQQxIgQgjfrx84XeiC2ERorawBL91pjC+s1T6o/3PiTme81N
# /pIwDQYJKoZIhvcNAQEBBQAEggEAF7tcOkuyLraWM6IcjDYYG+6gfh9oAttj8h6e
# pwPzkfM4jyEaSL7QP1kKVOfSzIKnvSDOb9Ip7uvebMJUwMeGLGa0qtV01p+z1uG+
# lVuy6KoY26ZbN9kbX103DLA70M3nmKF4vbDGWrj90CdQLw8aKIedHxvlXvJ9UrPE
# EzLZuk9/Vlgwzw6gwE9XtNLnpQFyIH2FRODjbDT7zszJKxzeFtWEIr7cJQkHup/g
# HVYmK2EFa5T1ThcNzhj66TiqNJHxH6DYQ9vy8AFmZfbKR6PvmpqhMj1ALuzYa7bG
# 86cuPrVcU/BULru5xfXF+m2ufk/hDWv8K0jgc2xi+48vjBKs1qGCE20wghNpBgor
# BgEEAYI3AwMBMYITWTCCE1UGCSqGSIb3DQEHAqCCE0YwghNCAgEDMQ8wDQYJYIZI
# AWUDBAIBBQAwggEMBgsqhkiG9w0BCRABBKCB/ASB+TCB9gIBAQYKKwYBBAGyMQIB
# ATAxMA0GCWCGSAFlAwQCAQUABCAurFcBEyJESI0KIxtQ5JXFPJxYK+1UYUuWKgnA
# pX+4wQIUG9Kc+62fLtkXDNUVCMpPwVWBzw8YDzIwMTkwNzExMDkzMTM2WqCBiqSB
# hzCBhDELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQ
# MA4GA1UEBwwHU2FsZm9yZDEYMBYGA1UECgwPU2VjdGlnbyBMaW1pdGVkMSwwKgYD
# VQQDDCNTZWN0aWdvIFJTQSBUaW1lIFN0YW1waW5nIFNpZ25lciAjMaCCDfowggcG
# MIIE7qADAgECAhA9GjVyMBWCYzDQE3F+gkEIMA0GCSqGSIb3DQEBDAUAMH0xCzAJ
# BgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcT
# B1NhbGZvcmQxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDElMCMGA1UEAxMcU2Vj
# dGlnbyBSU0EgVGltZSBTdGFtcGluZyBDQTAeFw0xOTA1MDIwMDAwMDBaFw0zMDA4
# MDEyMzU5NTlaMIGEMQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5j
# aGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRgwFgYDVQQKDA9TZWN0aWdvIExpbWl0
# ZWQxLDAqBgNVBAMMI1NlY3RpZ28gUlNBIFRpbWUgU3RhbXBpbmcgU2lnbmVyICMx
# MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAy1FQ/1b+/HhjcAGTWp4Y
# 9DtT9gevIWz1og99HXAthHRIi5yKlQU9WYT5kYB5USzZirfBC5q6CorNZk8DiwG7
# MMqrvdvATxJe/ArM4kWwATiKu03n1BxUmO05WM9bwi9FmDEK+TU4uDEubbQeOXLh
# uCq+n4yMGqVGrgsrTJn+LEv8KLkiOmYX0KpWiiHA85YktNCFJmu68G9kmHmmrb1c
# 2FNrKwrWcoqFRuMNGAbaxntBVjabFT7xahGg92b1GNCAVWOHaGbrDnlVglyj7Um4
# cYaekzewa6PqYmyjrpbouf2Lq8b2WVsAPFcgGC1wA6ec75LreaHHXex8tI9L3+td
# /KMg3ZI45WpROmuFnEygmAhpWwbnKhnQlZOLO2uKBQkp2Nba2+Ny+lxKL3sVVoYy
# v38FCZ0tKs9Q4eZhINvHBoBcThRGvq5XcaKqbDCTHH53ywbpV82R9dUzchzh2spu
# 6/MP7Hlbuyee6B7+L/K7f+nl0GfruA18pCtZA4uV7SIozfosO8cWEa/j1rFQZ2nF
# jvV50K3/h8z4f6r5ou1h+MiNadqx9FGR62dX0WQR62TLA71JVTpFQxgsJWzRLwwt
# b/VBNSSg8mNZFl/ZpOksTtu7MRLGbfhbbgPcyxWPG41y7NsPFZDWEk7u4gAxJZM1
# b2pbpRJjQAGKuWmIOoi4DxkCAwEAAaOCAXgwggF0MB8GA1UdIwQYMBaAFBqh+GEZ
# IA/DQXdFKI7RNV8GEgRVMB0GA1UdDgQWBBRvTYYH2DInniwp0tATA4CB3QWDKTAO
# BgNVHQ8BAf8EBAMCBsAwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAKBggrBgEF
# BQcDCDBABgNVHSAEOTA3MDUGDCsGAQQBsjEBAgEDCDAlMCMGCCsGAQUFBwIBFhdo
# dHRwczovL3NlY3RpZ28uY29tL0NQUzBEBgNVHR8EPTA7MDmgN6A1hjNodHRwOi8v
# Y3JsLnNlY3RpZ28uY29tL1NlY3RpZ29SU0FUaW1lU3RhbXBpbmdDQS5jcmwwdAYI
# KwYBBQUHAQEEaDBmMD8GCCsGAQUFBzAChjNodHRwOi8vY3J0LnNlY3RpZ28uY29t
# L1NlY3RpZ29SU0FUaW1lU3RhbXBpbmdDQS5jcnQwIwYIKwYBBQUHMAGGF2h0dHA6
# Ly9vY3NwLnNlY3RpZ28uY29tMA0GCSqGSIb3DQEBDAUAA4ICAQDAaO2z2NRQm+/T
# dcsPO/ck03o3RY0s7xb7UaksH7UltYqfXQvCGyB0jWYPNsuq9jYND36PS0p0Q2Ws
# DSr2Cu1rbcUJOO0AG/jl3KYKQAVH74TKCbxDZoO/n+3bjj3RQWSxcAItA1dbGG8c
# LMsesgDougkvW4EENbmpY22OCMUY0eEhrPkSChTAEtt+JZ2sHRDAWqWD0h8aZlX8
# myri7DdXjuXfljD4wJMLQxj5Am+pUa+4VwrzHAdpOY83nG3Xka6lLknpSt6z0Iy/
# OZANwIHO8CoHOgymLVHScvNTxvm97+8MaUl3nyxWxOmhCD0HrsUe1oQix7x9QxtY
# OGJO0QUlhMVC+B8v9tv6q4xU7EWKbBJNMFpS5aQXCSLm72/1X4ZD36EtvUpGkqCB
# lixhl39Ab9g/jDVaq9HGoDuFZlSA7x8a9fGbsKEnfbLnC8/2LZxYE5SphvxFUqIo
# bX90D1KRSXrpEvipO7CS/X2RFOlbbUiU8siW7gU4s8XsMD/hByAEsdiLvP2zPm/y
# AlMG9KDtyZpyo5dfAPvLY9DozXT9dcnUNkW6exJZcu3n8npQAHj4Q5pG2N+/VNRe
# scfRvBuD9CvnC+hHyFOezBqs9vqKdVNsIIWp1bhquiSOiisIkZ83BBz2b6LdNKqR
# /8YVLh5CGgkpT/TGzeKRotNADI544zCCBuwwggTUoAMCAQICEDAPb6zdZph0fKlG
# Nqd4LbkwDQYJKoZIhvcNAQEMBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpO
# ZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVT
# RVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmlj
# YXRpb24gQXV0aG9yaXR5MB4XDTE5MDUwMjAwMDAwMFoXDTM4MDExODIzNTk1OVow
# fTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
# A1UEBxMHU2FsZm9yZDEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSUwIwYDVQQD
# ExxTZWN0aWdvIFJTQSBUaW1lIFN0YW1waW5nIENBMIICIjANBgkqhkiG9w0BAQEF
# AAOCAg8AMIICCgKCAgEAyBsBr9ksfoiZfQGYPyCQvZyAIVSTuc+gPlPvs1rAdtYa
# BKXOR4O168TMSTTL80VlufmnZBYmCfvVMlJ5LsljwhObtoY/AQWSZm8hq9VxEHmH
# 9EYqzcRaydvXXUlNclYP3MnjU5g6Kh78zlhJ07/zObu5pCNCrNAVw3+eolzXOPEW
# snDTo8Tfs8VyrC4Kd/wNlFK3/B+VcyQ9ASi8Dw1Ps5EBjm6dJ3VV0Rc7NCF7lwGU
# r3+Az9ERCleEyX9W4L1GnIK+lJ2/tCCwYH64TfUNP9vQ6oWMilZx0S2UTMiMPNMU
# opy9Jv/TUyDHYGmbWApU9AXn/TGs+ciFF8e4KRmkKS9G493bkV+fPzY+DjBnK0a3
# Na+WvtpMYMyou58NFNQYxDCYdIIhz2JWtSFzEh79qsoIWId3pBXrGVX/0DlULSbu
# RRo6b83XhPDX8CjFT2SDAtT74t7xvAIo9G3aJ4oG0paH3uhrDvBbfel2aZMgHEqX
# LHcZK5OVmJyXnuuOwXhWxkQl3wYSmgYtnwNe/YOiU2fKsfqNoWTJiJJZy6hGwMny
# pv99V9sSdvqKQSTUG/xypRSi1K1DHKRJi0E5FAMeKfobpSKupcNNgtCN2mu32/cY
# QFdz8HGj+0p9RTbB942C+rnJDVOAffq2OVgy728YUInXT50zvRq1naHelUF6p4MC
# AwEAAaOCAVowggFWMB8GA1UdIwQYMBaAFFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0G
# A1UdDgQWBBQaofhhGSAPw0F3RSiO0TVfBhIEVTAOBgNVHQ8BAf8EBAMCAYYwEgYD
# VR0TAQH/BAgwBgEB/wIBADATBgNVHSUEDDAKBggrBgEFBQcDCDARBgNVHSAECjAI
# MAYGBFUdIAAwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3Qu
# Y29tL1VTRVJUcnVzdFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYGCCsG
# AQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3QuY29t
# L1VTRVJUcnVzdFJTQUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRwOi8v
# b2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQBtVIGlM10W4bVT
# gZF13wN6MgstJYQRsrDbKn0qBfW8Oyf0WqC5SVmQKWxhy7VQ2+J9+Z8A70DDrdPi
# 5Fb5WEHP8ULlEH3/sHQfj8ZcCfkzXuqgHCZYXPO0EQ/V1cPivNVYeL9IduFEZ22P
# sEMQD43k+ThivxMBxYWjTMXMslMwlaTW9JZWCLjNXH8Blr5yUmo7Qjd8Fng5k5OU
# m7Hcsm1BbWfNyW+QPX9FcsEbI9bCVYRm5LPFZgb289ZLXq2jK0KKIZL+qG9aJXBi
# gXNjXqC72NzXStM9r4MGOBIdJIct5PwC1j53BLwENrXnd8ucLo0jGLmjwkcd8F3W
# oXNXBWiap8k3ZR2+6rzYQoNDBaWLpgn/0aGUpk6qPQn1BWy30mRa2Coiwkud8Tle
# TN5IPZs0lpoJX47997FSkc4/ifYcobWpdR9xv1tDXWU9UIFuq/DQ0/yysx+2mZYm
# 9Dx5i1xkzM3uJ5rloMAMcofBbk1a0x7q8ETmMm8c6xdOlMN4ZSA7D0GqH+mhQZ3+
# sbigZSo04N6o+TzmwTC7wKBjLPxcFgCo0MR/6hGdHgbGpm0yXbQ4CStJB6r97DDa
# 8acvz7f9+tCjhNknnvsBZne5VhDhIG7GrrH5trrINV0zdo7xfCAMKneutaIChrop
# 7rRaALGMq+P5CslUXdS5anSevUiumDGCBBwwggQYAgEBMIGRMH0xCzAJBgNVBAYT
# AkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZv
# cmQxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDElMCMGA1UEAxMcU2VjdGlnbyBS
# U0EgVGltZSBTdGFtcGluZyBDQQIQPRo1cjAVgmMw0BNxfoJBCDANBglghkgBZQME
# AgEFAKCCAVswGgYJKoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJ
# BTEPFw0xOTA3MTEwOTMxMzZaMC8GCSqGSIb3DQEJBDEiBCB2yx19fpqsOPGDGkcA
# FZi8mtT7HsRObJ5Tb29ZfDp4uDCB7QYLKoZIhvcNAQkQAgwxgd0wgdowgdcwFgQU
# Jcisc05IULf42RORqBuSSTZln2EwgbwEFALWW5Xig3DBVwCV+oj5I92Tf62PMIGj
# MIGOpIGLMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKTmV3IEplcnNleTEUMBIG
# A1UEBxMLSmVyc2V5IENpdHkxHjAcBgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29y
# azEuMCwGA1UEAxMlVVNFUlRydXN0IFJTQSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
# eQIQMA9vrN1mmHR8qUY2p3gtuTANBgkqhkiG9w0BAQEFAASCAgCcEr7hkfnts8+Z
# FXmtwnPjViKyZh+S7+1ebGs5jJ5WH5e/hHktbXIB/GINei5nq8Y84HOwBHI8Qbh/
# 7V7qw8ebF39IOIWkB6IiHIbBJpjo1fXBUzOpu1XA9Ap+ut7psbXHF+khfNrwP1Du
# 2rOXdWL2gWqnlfO6J5pXJL6R712MspUTeoQZMFM86VD9go5vgbAVCqvrFzJhd7ht
# v1eYVHdvtx2eebdpv1K0U41uYi9BoZP9G1hDoqto/gycvqhYF8brGm5rTNU1TkeF
# 07Ug3amnQo1vIkxR0iaohH5xmc+wE5y3rSEVc8IcmE4AlnG3BHzOKnEjeXmEaWjE
# VtrePQqGDe2WWbqhcoVacDMbEKhiOcy/QO+YptAPLxNRjgTjgARC+jhRspd4QtfM
# U2jGHkChMjki56YfYsLM4lxbxDDKSJtc5PtmBjs0B7b2wH/R7ryHEKFE30t5s5Yc
# +nGeIrHgiUZGKbYzHR3GVmRySnEKUQyd61mPWqQ9XZH7DtzV8GweiFrGJtZ6+33E
# JCJfguCu1PapHJ7aeE3pI+GoR0x2Glz4V0hfKA00AYhGRU0B7TTR4crJTJ2vMGli
# /dRTZUUTovYprUs1Czy+nehjvTpAjGAwwGmWO3NA47IU1BpzPhROPwhqSD/IGr4J
# sFjDFyEOwLVxkwbiJukOpw0dF3ejCA==
# SIG # End signature block