PS/ConvertFrom-JWTToken.ps1

Function ConvertFrom-JWTToken
{
<#
    .SYNOPSIS
        Get JWT token information.

    .PARAMETER JWTToken
        AccessToken string.

    .PARAMETER ValidateSignature
        Use additional signature validation.

    .PARAMETER AsJSON
        Return data as json.

    .EXAMPLE
        $AccessToken | ConvertFrom-JWTToken -AsJSON

    .EXAMPLE
        $AccessToken | ConvertFrom-JWTToken -ValidateSignature

    .NOTES
        Author: Michal Gajda

    .LINK
        https://learn.microsoft.com/en-us/azure/active-directory/develop/access-tokens
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)]
        [string]$JWTToken,
        [Switch]$ValidateSignature,
        [Switch]$AsJSON
    )

    #Check if token is ok
    if (!$JWTToken.Contains(".") -or !$JWTToken.StartsWith("eyJ"))
    {
        Write-Error "Invalid Access Token" -ErrorAction Stop
    }

    $DecodedToken = @{}
    $Header, $Payload, $Signature = $JWTToken.Split(".")

    #Decode Header
    $HeaderData = $Header.Replace('-', '+').Replace('_', '/')
    while($HeaderData.Length % 4 -ne 0) { $HeaderData += "=" }
    $DecodedHeader = [System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($HeaderData)) | ConvertFrom-Json
    $DecodedToken['Header'] = [PSCustomObject]$DecodedHeader

    #Decode Payload
    $PayloadData = $Payload.Replace('-', '+').Replace('_', '/')
    while($PayloadData.Length % 4 -ne 0) { $PayloadData += "=" }
    $DecodedPayload = [System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($PayloadData)) | ConvertFrom-Json
    $DecodedToken['Payload'] = [PSCustomObject]$DecodedPayload

    #Get expiration time
    $UnixTime = (Get-Date -Year 1970 -Month 1 -Day 1 -hour 0 -Minute 0 -Second 0 -Millisecond 0)
    $UtcTime = $UnixTime.AddSeconds($DecodedToken['Payload'].exp)
    $ExpiryDateTime = $UtcTime.AddMinutes($(Get-TimeZone).GetUtcOffset($(Get-Date)).TotalMinutes)
    $DecodedToken['ExpiryDateTime'] = $ExpiryDateTime

    #Validation
    if($ValidateSignature)
    {
        $Issuer = $DecodedToken['Payload'].iss
        $Kid = $DecodedToken['Header'].kid

        #Get keys pool for tenant
        $Url = $Issuer + ".well-known/openid-configuration"
        #if($null -ne $AppId) { $Url += "?appid=" + $AppId }
        $Configuration = (ConvertFrom-Json (Invoke-WebRequest $Url).Content)
        $Keys = (ConvertFrom-Json (Invoke-WebRequest $Configuration.jwks_uri).Content).Keys
        $KeysHT = $Keys | Group-Object -Property Kid -AsHashTable

        #Get right key
        $Key = $KeysHT[$Kid]

        if($null -ne $Key)
        {
            #Get key info
            $KeyInfo = @{}
            $KeyInfo['e'] = $Key.e
            $KeyInfo['kty'] = $Key.kty
            $KeyInfo['n'] = $Key.n
            $KeyInfo['kid'] = $Key.kid

            #Decode public cert
            if($Key.x5c)
            {
                $X5C = $Key.x5c | Select-Object -First 1
                $X509Certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]([System.Convert]::FromBase64String($X5C))
                $KeyInfo['X509Certificate'] = $X509Certificate
            }
            $DecodedToken['KeyInfo'] = [PSCustomObject]$KeyInfo

            #Validate Signature
            $RSA = New-Object System.Security.Cryptography.RSACryptoServiceProvider
            $RSAParameters = [System.Security.Cryptography.RSAParameters]::New()

            $KaynData = $Key.n.Replace('-', '+').Replace('_', '/')
            while($KaynData.Length % 4 -ne 0) { $KaynData += "=" }
            $RSAParameters.Modulus = [Convert]::FromBase64String($KaynData)

            $KayeData = $Key.e.Replace('-', '+').Replace('_', '/')
            while($KayeData.Length % 4 -ne 0) { $KayeData += "=" }
            $RSAParameters.Exponent = [System.Convert]::FromBase64String($KayeData)

            $RSA.ImportParameters($RSAParameters)

            $SignatureDeformatter = [System.Security.Cryptography.RSAPKCS1SignatureDeformatter]::new($RSA)
            $SignatureDeformatter.SetHashAlgorithm("SHA256")

            #Get hash of header and payload
            $SHA256 = [System.Security.Cryptography.SHA256]::Create()
            $Hash = $SHA256.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($Header + '.' + $Payload))

            #Decode signature
            $SignatureData = $Signature.Replace('-', '+').Replace('_', '/')
            while($SignatureData.Length % 4 -ne 0) { $SignatureData += "=" }
            $SignatureBytes = [System.Convert]::FromBase64String($SignatureData)

            #Verify signature
            if($SignatureDeformatter.VerifySignature($Hash, $SignatureBytes))
            {
                $DecodedToken['SignatureStatus'] = "Signature Verified"
            } else
            {
                if($TokenClaims.aud -eq "https://graph.microsoft.com")
                {
                    $DecodedToken['SignatureStatus'] = "Cant validate MSGraph token signature"
                } else
                {
                    $DecodedToken['SignatureStatus'] = "Invalid Signature"
                }
            }
        }
    }

    if($AsJSON)
    {
        $Result = [PSCustomObject]$DecodedToken | ConvertTo-Json -Depth 5
    } else {
        $Result = [PSCustomObject]$DecodedToken
    }

    Return $Result
}

# SIG # Begin signature block
# MIIixQYJKoZIhvcNAQcCoIIitjCCIrICAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCxsVkrh2KDqf2G
# 1P2mIiVkji7dp3lEJA5wDjb1EDRVkaCCHDUwggQuMIICFqADAgECAhBTXA6VE4ZJ
# kkZJJNYxZDR4MA0GCSqGSIb3DQEBCwUAMBoxGDAWBgNVBAMMD01pY2hhbCBHYWpk
# YSBDQTAeFw0yNjExMDkxMDI2MTZaFw0yNzExMDkxMDM2MTZaMCMxITAfBgNVBAMM
# GE1pY2hhbCBHYWpkYSBDb2RlU2lnbmluZzCCASIwDQYJKoZIhvcNAQEBBQADggEP
# ADCCAQoCggEBAMbcpWN3ctQ7jeDfNLFP+cxh3Wd9vA1r6jN9iQYAS15j1wEI6V53
# yWjJoYJKmeIQtXxQYWhsfPE5cJ2CHTTxhsovsKp2zm/30MRL50maZrbwdkZ/KZyc
# LLPk+dyNvfWfH5UBQV0pRCLN1ILXPQd1F3LqsBPH7cko5L5Om+b3oBl2w9CxF4G/
# UbTFh/9qgcAYXvOPNDzUFFryFepSiwAAfC6D5RHaFMWljb+gegRUkl+/B4g8Xf3R
# mbFcl2lTqhRENPFhOdrtngy9ldkz/tyUO3Reaixhy+EA8/bTOtK5Mq7RtyAA2dhZ
# IH5AQrN5U9jIY8SL+rizT4JvF/L6TQgqRC0CAwEAAaNnMGUwDgYDVR0PAQH/BAQD
# AgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMB8GA1UdIwQYMBaAFGfJIhIP6r4+OzlU
# V5fnBSoEZF3BMB0GA1UdDgQWBBRuO6w3QLbfSM2OJPzXgPrB6kf7zTANBgkqhkiG
# 9w0BAQsFAAOCAgEAT752PsmY9UcAejy9a4CgH74wvHt5otpbyMGtM0qUqlyc+8q/
# E69LBVDjPt6CEXiJFMTRNXoVTKkEjZA0wO4GsyBg+T9ODbGxl/Vn+39qsqLh0HYZ
# aTQyPGfsVtm/ZuvcwJYnm2gdHUjb3T9joP+vGe+2bFfzRnCIAjdM66Bgq6pxSPlt
# KQLmLsWyygMqTHaam4VLe5Kaqf8DgibsJ6NWHhS4/b7XdZaajp6YpFaoIARAoGZe
# hOVgZaDIIi9yEFfhxhAhX5G9+yJEVjJH/ZnRCY3vRHvFYQHtvJcxQrUmG16IeA3L
# 6t2+UzT6mWKIrFUprO3XceGZeT/sKn7vUqSnKU0fJR/C9+CLjNaD2P4U5QXgIa0+
# bN+RGuB+0u4NUj0fOTFQRKAxIhgzlzUJbMUceDOhmg8aMgG9vrI6Ukhp0q4iNjvg
# 7HLDM+mDzbthNy+duIAKli3DTfGMKvpy1PLfY9NlTQLi2suhppUlzMMxtBuQCajq
# dZBYLEQIBZyrsnfG7dleDRzXHy6E137/EXx3MeYj2ZT0vGRwDH0qQWZkL3WLILN9
# t1hwlueP2imnQ8IyxxGRRgR61LpEoeVxpkMP/LlsXngLvxDuAZVFadHkcH4YvoZx
# bu8t/sbwZWIiVhZarLyochr1eXwecXNbjXucI7tGAxanRq0SFl7mQyJ6YEMwggTv
# MIIC16ADAgECAhASiMPAZpZmrkW5VhWUwZQNMA0GCSqGSIb3DQEBCwUAMBoxGDAW
# BgNVBAMMD01pY2hhbCBHYWpkYSBDQTAeFw0yNjExMDkxMDI1MjNaFw0zNjExMDkx
# MDM1MjFaMBoxGDAWBgNVBAMMD01pY2hhbCBHYWpkYSBDQTCCAiIwDQYJKoZIhvcN
# AQEBBQADggIPADCCAgoCggIBAKoTH4NpYpZwRaNHiIVPS/34t3cwY7fAjDjtY08F
# Vs0af5/C6EY7OwwmrIf6f8bMHOPI25lfZ57mOaTdFpZKK1/6y56KKc8vhYMmUYeB
# 3KGZ+NYGdDsyLt+PFG32nGwpDVu8r/iKJMk5tWwAbTpyIa+DD/W+skB3jNf93aCh
# A8htMXwHooHMkNZ7p5E5fx8NQjY/mlTtGB7IZ61DBwg4Zm74avD+56RgbkvTz222
# V6vKQxU30F4wu6fmrRVzLDbZw1tCMND389QRx01MuD9lCzsZcty4dj4oWh4PoJKf
# HtoHuoUFtJW9UOLsNxryat6JFlbkggPb6CbWvwJfCsCXgjEFP1DEtO5KFjup3ME9
# a+Duvsk3XkbXfNWeVdDZ12LqHu89QV1z6pAi/qAf21zYO/bNfwKoaN9sqlDEVEEM
# bytam3Iw1WxDgweWshAXTABOKOWHVryU9VFPhRTlazEXZZjGXup6kxk4+zpU9DAx
# BqGfZvRevGlVqmr6/1qt8FtQi73+L+WQu51lVAMezQNhTukCvA3odiCOg2/LHLXb
# 7Du3SVeQgM52OUAN6CP7dPHJUf5EBiWidiNqx2B1a9l+pxIeLPdn+7t64uQdY6j9
# NpOY7CNyZDcx/KwZ4IG++VQlOcMbHnDuooD2/lCFEPf8wX974KvQk5to90b1TYB1
# TVU1AgMBAAGjMTAvMA4GA1UdDwEB/wQEAwICBDAdBgNVHQ4EFgQUZ8kiEg/qvj47
# OVRXl+cFKgRkXcEwDQYJKoZIhvcNAQELBQADggIBACbBQxFIE77wc05vEf2IjBLC
# plLr7Yo71AIg1JwggEze1ZWQcRrZqDqpH4i/hbihW4LlSDxJVQXCacnknJg0p2Ur
# maP/0fyI8KhYkmj+VQh1VFkovErPQp+aYSMD9sDsr7BqqmSLNMoL3HV7YZM9qlX+
# sR0is+Cg+cT0bq+SHxTBmb4EUy3lD6+gzH3qvv79fqMHA6JXBbNDVDYyaOFB2y51
# U+F1yzbf1NzVGkTdFv9JzO57WneJ3qLxFAfKckVBsn0f+nUsNkTP6c42hHlc1dna
# H4zgt0Ie8CIPg3mwy28hnG7C80C3T0B8bUBC2NntGMjxYm8mML2v7xZRhAwkBUx/
# GtklhGUGiHfBCKyy2YgSGWI7/OmOK4dv3+1Vi+3FKyFXwZ2FibmA12WaIXsaoz9N
# vIVIu+vqm01f6C3kFj/VxVjVa3Q6vSeq/Lk7y/HKCGFoQzbwUT70VKBC/X/oSI0k
# BRiMQMoHUwJhwehWszvwh6/Oul7We3618pGfjgSeaDjRhb1t7aOLs9WIt+n4HOUj
# Aiq5MJ/bLbVBxVSCzoMblRwX1XU5bpJedyN2rbXhLfDuywISBT0N6nd+cQ78RjbX
# QO99Vegf01cCG8vicJKWAHOK78a3sCUdgC1ZSIqpu2FhdYa5QdNn3eCAey1X8nnE
# veaEYam2B60G1P0WV02OMIIFyTCCBLGgAwIBAgIQG7WPJSrfIwBJKMmuPX7tJzAN
# BgkqhkiG9w0BAQwFADB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBU
# ZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24g
# QXV0aG9yaXR5MSIwIAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMB4X
# DTIxMDUzMTA2NDMwNloXDTI5MDkxNzA2NDMwNlowgYAxCzAJBgNVBAYTAlBMMSIw
# IAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0
# dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJDAiBgNVBAMTG0NlcnR1bSBUcnVz
# dGVkIE5ldHdvcmsgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
# AL35ePjm1YAMZJ2GG5ZkZz8iOh51AX3v+1xnjMnMXGupkea5QuUgS5vam3u5mV3Z
# m4BL14RAKyfT6Lowuz4JGqdJle8rQCTCl8en7psl76gKAJeFWqqd3CnJ4jUH63BN
# StbBs1a4oUE4m9H7MX+P4F/hsT8PjhZJYNcGjRj5qiYQqyrT0NFnjRtGvkcw1S5y
# 0cVj2udjeUR+S2MkiYYuND8pTFKLKqfA4pEoibnAW/kd2ecnrf+aApfBxlCSmwIs
# vam5NFkKv4RK/9/+s5/r2Z7gmCPspmt3FirbzK07HKSH3EZzXhliaEVX5JCCQrtC
# 1vBh4MGjPWajXfQY7ojJjRdFKZkydQIx7ikmyGsC5rViRX83FVojaInUPt5OJ7Dw
# QAy8TRfLTaKzHtAGWt32k89XdZn1+oYaZ3izv5b+NNy951JW5bPldXvXQZEF3F1p
# 45UNQ7n8g5Y5lXtsgFpPE3LG130pekS6UqQq1UFGCSD+IqC2WzCNvIkM1ddw+IdS
# /drvrFEuB7NO/tAJ2nDvmPpW5m3btVdL3OUsJRXIni54TvjanJ6GLMpX8xrlyJKL
# GoKWesO8UBJp2A5aRos66yb6I8m2sIG+QgCk+Nb+MC7H0kb25Y51/fLMudCHW8wG
# EGC7gzW3XmfeR+yZSPGkoRX+rYxijjlVTzkWubFjnf+3AgMBAAGjggE+MIIBOjAP
# BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAf
# BgNVHSMEGDAWgBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYw
# LwYDVR0fBCgwJjAkoCKgIIYeaHR0cDovL2NybC5jZXJ0dW0ucGwvY3RuY2EuY3Js
# MGsGCCsGAQUFBwEBBF8wXTAoBggrBgEFBQcwAYYcaHR0cDovL3N1YmNhLm9jc3At
# Y2VydHVtLmNvbTAxBggrBgEFBQcwAoYlaHR0cDovL3JlcG9zaXRvcnkuY2VydHVt
# LnBsL2N0bmNhLmNlcjA5BgNVHSAEMjAwMC4GBFUdIAAwJjAkBggrBgEFBQcCARYY
# aHR0cDovL3d3dy5jZXJ0dW0ucGwvQ1BTMA0GCSqGSIb3DQEBDAUAA4IBAQBRwqFY
# FiIQi/yGMdTCMtNc+EuiL2o+TfirCB7t1ej65wgN7LfGHg6ydQV6sQv613RqAAYf
# pM6q8mt92BHAEQjUDk1hxTqo+rHh45jq4mP9QfWTfQ28XZI7kZplutBfTL5MjWgD
# EBbV8dAEioUz+TfnWy4maUI8us281HrpTZ3a50P7Y1KAhQTEJZVV8H6nnwHFWyj4
# 4M6GcKYnOzn7OC6YU2UidS3X9t0iIpGW691o7T+jGZfTOyWI7DYSPal+zgKNBZqS
# pyduRbKcYoY3DaQzjteoTtBKF0NMxfGnbNIeWGwUUX6KVKH27595el2BmhaQD+G7
# 8UoA+fndvu2q7M4KMIIGgjCCBGqgAwIBAgIQKPB3wRw2vf5fdDJHcCcuAzANBgkq
# hkiG9w0BAQwFADBWMQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEg
# U3lzdGVtcyBTLkEuMSQwIgYDVQQDExtDZXJ0dW0gVGltZXN0YW1waW5nIDIwMjEg
# Q0EwHhcNMjYwMzExMDczNDU0WhcNMzYwMjI3MDczNDU0WjBQMQswCQYDVQQGEwJQ
# TDEhMB8GA1UECgwYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMR4wHAYDVQQDDBVD
# ZXJ0dW0gVGltZXN0YW1wIDIwMjYwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
# AoICAQC4vc3wcPsSNdoYthfbjUATTkk5EyItd37odw4lsmyOd/dmwXycOrTu8w7O
# 1Kj/63o1X+MRU1N1zTj7LjhZD+UjxbJ1sJ91SS/jYTYbLro72LELWkJ7zaNcJOOq
# 3k4MLNS/DhRHSmsYMqk+MzkMfNZi8DWUqlzVPUa2/aACViReDMnc/gtXm7tA9Pr4
# DN7agEPE1NtN36oCgj6iHR5aGhah/XskfvLZ6ZstoZ5zefWTrZrLh3kcH+YkzoZY
# X9Hf6qqrizkiBj4BlS9R4+VwVKMdjhO7UEa/pf8cTWy+jrsATuAGthG7sWIN+3KV
# 7+Ytv5Uy+DQEgf3bn/VuH4wN0aPhj/mwueJ9jmIjNwqvM/dno8fBeR1jtnuP++Xg
# veQfbTMP3qu9dPRg8ltvtrreQZ9KPDFyUxEZMsrLVm6nJ1JKJgPe6n4gwsL6Vrjj
# HX0zpLF3vUvsQ8TiWgm4sk4r4D7pcXE/rX0E0Vwa+VMLT73PiDZ2nzhIpc1RwNdb
# b/qR3Mpa8sQXNPHFIoX/7bapGUtG5sd1cUGsvLqIWk6dP/xAgPb2BludUinSTCYV
# 7ysiHQS8vFmDXIU7fMkSE7/QHcYPSahro4fk5z9W1t2kIxbZRJe0s4DXiPDlQPwi
# QFllLkU9wLvU6DqR8v35a65J4TeIXhMO/+iCzL+B0rI9GGeKLQIDAQABo4IBUDCC
# AUwwdQYIKwYBBQUHAQEEaTBnMDsGCCsGAQUFBzAChi9odHRwOi8vc3ViY2EucmVw
# b3NpdG9yeS5jZXJ0dW0ucGwvY3RzY2EyMDIxLmNlcjAoBggrBgEFBQcwAYYcaHR0
# cDovL3N1YmNhLm9jc3AtY2VydHVtLmNvbTAfBgNVHSMEGDAWgBS+VAIvv0Bsc0PO
# rAklTp5DRBru4DAMBgNVHRMBAf8EAjAAMDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6
# Ly9zdWJjYS5jcmwuY2VydHVtLnBsL2N0c2NhMjAyMS5jcmwwFgYDVR0lAQH/BAww
# CgYIKwYBBQUHAwgwDgYDVR0PAQH/BAQDAgeAMCIGA1UdIAQbMBkwCAYGZ4EMAQQC
# MA0GCyqEaAGG9ncCBQELMB0GA1UdDgQWBBQjOWooq5oSp6Sn8h/5RZq/jf6CAzAN
# BgkqhkiG9w0BAQwFAAOCAgEAZv6Tm6wL3k6mBTwkrYcTVcAR01uE37gUGNihgnTJ
# R+gC41T2H9lwETRjE10nEdCUNv3Ni8S6aBx4UcMRX93fd9w4RUteua2I+oj0kCpu
# Na3PQDKUwozHZmotWivaPO9KTs08y0YVhVSMZvuUH/reFec9eLT6FLAFnX0Sg9Wc
# 7833uQB5RPa8TmXBkTolC8bNxHX+2SfEWSNI8w/Y7o9qBF9l0uwVSrjQitVtIdZo
# 2qb9NvMqqPFLWYef9SG+PGMqfPAQ2EoYeT0hlFLkubWF1X3HbiDwXtz3TU2EWHU+
# VTcZMC4IzMyHK/+kh9n3oxSQ45wsY71y7mqxKyYPyHSPoV3RiAQ1Thr9c65BeJLa
# ELxWSKeQyAGIdBsMlIXPO6qp+VGmE49vosogQ0jYe2hgq5LgJ6oO0Ie364V/kITB
# nifUqS6Zxu+qjfOYS8o72EeoEWIi04/BuH8Y6leNNP27j8NKwaPciWcqv/HBnQji
# zzmH/aqXn03K2SnjvaYPlCR8fFAAW2k6os0cZvLFEhMnHHAghYSIrdwCP98Brkjg
# A3ogOu+jXEO/nbD9OGL873Te6U2TcoOu9lqQQyXYNHiLR5eMqJrzXiDlodarOEKj
# lukyPDnLIuLkg0y6K8S1A5wU8CkM86cXdWFHLRIEYd9kdCfRZBZHhK7iVPeEZYxa
# 9bgwgga5MIIEoaADAgECAhEA5/9pxzs1zkuRJth0fGilhzANBgkqhkiG9w0BAQwF
# ADCBgDELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVz
# IFMuQS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEk
# MCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAyMB4XDTIxMDUxOTA1
# MzIwN1oXDTM2MDUxODA1MzIwN1owVjELMAkGA1UEBhMCUEwxITAfBgNVBAoTGEFz
# c2VjbyBEYXRhIFN5c3RlbXMgUy5BLjEkMCIGA1UEAxMbQ2VydHVtIFRpbWVzdGFt
# cGluZyAyMDIxIENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6RIf
# BDXtuV16xaaVQb6KZX9Od9FtJXXTZo7b+GEof3+3g0ChWiKnO7R4+6MfrvLyLCWZ
# a6GpFHjEt4t0/GiUQvnkLOBRdBqr5DOvlmTvJJs2X8ZmWgWJjC7PBZLYBWAs8sJl
# 3kNXxBMX5XntjqWx1ZOuuXl0R4x+zGGSMzZ45dpvB8vLpQfZkfMC/1tL9KYyjU+h
# tLH68dZJPtzhqLBVG+8ljZ1ZFilOKksS79epCeqFSeAUm2eMTGpOiS3gfLM6yvb8
# Bg6bxg5yglDGC9zbr4sB9ceIGRtCQF1N8dqTgM/dSViiUgJkcv5dLNJeWxGCqJYP
# gzKlYZTgDXfGIeZpEFmjBLwURP5ABsyKoFocMzdjrCiFbTvJn+bD1kq78qZUgAQG
# Gtd6zGJ88H4NPJ5Y2R4IargiWAmv8RyvWnHr/VA+2PrrK9eXe5q7M88YRdSTq9TK
# bqdnITUgZcjjm4ZUjteq8K331a4P0s2in0p3UubMEYa/G5w6jSWPUzchGLwWKYBf
# eSu6dIOC4LkeAPvmdZxSB1lWOb9HzVWZoM8Q/blaP4LWt6JxjkI9yQsYGMdCqwl7
# uMnPUIlcExS1mzXRxUowQref/EPaS7kYVaHHQrp4XB7nTEtQhkP0Z9Puz/n8zIFn
# USnxDof4Yy650PAXSYmK2TcbyDoTNmmt8xAxzcMCAwEAAaOCAVUwggFRMA8GA1Ud
# EwEB/wQFMAMBAf8wHQYDVR0OBBYEFL5UAi+/QGxzQ86sCSVOnkNEGu7gMB8GA1Ud
# IwQYMBaAFLahVDkCw6A/joq8+tT4HKbROg79MA4GA1UdDwEB/wQEAwIBBjATBgNV
# HSUEDDAKBggrBgEFBQcDCDAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vY3JsLmNl
# cnR1bS5wbC9jdG5jYTIuY3JsMGwGCCsGAQUFBwEBBGAwXjAoBggrBgEFBQcwAYYc
# aHR0cDovL3N1YmNhLm9jc3AtY2VydHVtLmNvbTAyBggrBgEFBQcwAoYmaHR0cDov
# L3JlcG9zaXRvcnkuY2VydHVtLnBsL2N0bmNhMi5jZXIwOQYDVR0gBDIwMDAuBgRV
# HSAAMCYwJAYIKwYBBQUHAgEWGGh0dHA6Ly93d3cuY2VydHVtLnBsL0NQUzANBgkq
# hkiG9w0BAQwFAAOCAgEAuJNZd8lMFf2UBwigp3qgLPBBk58BFCS3Q6aJDf3TISoy
# tK0eal/JyCB88aUEd0wMNiEcNVMbK9j5Yht2whaknUE1G32k6uld7wcxHmw67vUB
# Y6pSp8QhdodY4SzRRaZWzyYlviUpyU4dXyhKhHSncYJfa1U75cXxCe3sTp9uTBm3
# f8Bj8LkpjMUSVTtMJ6oEu5JqCYzRfc6nnoRUgwz/GVZFoOBGdrSEtDN7mZgcka/t
# S5MI47fALVvN5lZ2U8k7Dm/hTX8CWOw0uBZloZEW4HB0Xra3qE4qzzq/6M8gyoU/
# DE0k3+i7bYOrOk/7tPJg1sOhytOGUQ30PbG++0FfJioDuOFhj99b151SqFlSaRQY
# z74y/P2XJP+cF19oqozmi0rRTkfyEJIvhIZ+M5XIFZttmVQgTxfpfJwMFFEoQrSr
# klOxpmSygppsUDJEoliC05vBLVQ+gMZyYaKvBJ4YxBMlKH5ZHkRdloRYlUDplk8G
# Ua+OCMVhpDSQurU6K1ua5dmZftnvSSz2H96UrQDzA6DyiI1V3ejVtvn2azVAXg6N
# njmuRZ+wa7Pxy0H3+V4K4rOTHlG3VYA6xfLsTunCz72T6Ot4+tkrDYOeaU1pPX1C
# BfYj6EW2+ELq46GP8KCNUQDirWLU4nOmgCat7vN0SD6RlwUiSsMeCiQDmZwgwrUx
# ggXmMIIF4gIBATAuMBoxGDAWBgNVBAMMD01pY2hhbCBHYWpkYSBDQQIQU1wOlROG
# SZJGSSTWMWQ0eDANBglghkgBZQMEAgEFAKCBhDAYBgorBgEEAYI3AgEMMQowCKAC
# gAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsx
# DjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCCwBcWH7XE8reQYzof95tYL
# HANSbam0+y1afE1wm+mVEjANBgkqhkiG9w0BAQEFAASCAQA/1alB/micQmQdPg8M
# m5no9cBmfSjBlM22iiR8/kNugf5gRkCARlCK/Lu/hgsfRcrEn84u18Zguz2MsS9/
# h6Sf8PuGRPUTc1wXe6mVhoe9fnm9NfyL06oS5hlbx5atuuNwY1epnSepAlsdp1wo
# ceZ0G7i2g82B+t5Ih+oS4exQqVFyRfSzR3x4V/1j83A60M60Lrut0NtQs332A3lr
# d6ydepzpSJRwtCHsckU2s6xrGf1IN3lOdB6wS1yhW8Gn1D2FtDzwIpF2IKu7s8xa
# yLuIsGhUyc+guIKcwBjfBENj07uylagkiBDmiVXB10GQ4ayDrQN2IHS4dMftO+l6
# kkC6oYIEAjCCA/4GCSqGSIb3DQEJBjGCA+8wggPrAgEBMGowVjELMAkGA1UEBhMC
# UEwxITAfBgNVBAoTGEFzc2VjbyBEYXRhIFN5c3RlbXMgUy5BLjEkMCIGA1UEAxMb
# Q2VydHVtIFRpbWVzdGFtcGluZyAyMDIxIENBAhAo8HfBHDa9/l90MkdwJy4DMA0G
# CWCGSAFlAwQCAgUAoIIBVjAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwHAYJ
# KoZIhvcNAQkFMQ8XDTI2MTEwOTEwNTIwNlowNwYLKoZIhvcNAQkQAi8xKDAmMCQw
# IgQghb6Q4QrSQ418ySi2r0iwmrIIF3zs+LASbFjTkQUlxDwwPwYJKoZIhvcNAQkE
# MTIEMHKa/4T2ENqeLFBPllhgtXvHS+/xEXMgSndm/T9W3kA65Y3Y29NTXsXZGK8K
# 0RHm1DCBnwYLKoZIhvcNAQkQAgwxgY8wgYwwgYkwgYYEFFcUaEEMqFrzQk75FkpR
# NhD0042YMG4wWqRYMFYxCzAJBgNVBAYTAlBMMSEwHwYDVQQKExhBc3NlY28gRGF0
# YSBTeXN0ZW1zIFMuQS4xJDAiBgNVBAMTG0NlcnR1bSBUaW1lc3RhbXBpbmcgMjAy
# MSBDQQIQKPB3wRw2vf5fdDJHcCcuAzANBgkqhkiG9w0BAQEFAASCAgCC+WUYyqsw
# CrsNMbu4gTqTDzKs28To/k6GmQ9li7qjtoECLl3sj1chd31+2QQLJ/g24fZgMbUP
# crmfXAjnTOHJcY9Y1waHobjMGuirFMlVNaRdT9toBkGt1RoOo7ecF0THzoWY0Ax+
# nInaBBC/XOwonwe99VC1gAtu8SnsO1Ixv8UtrIoumtlH7RW03doNC7BAeVf2CN2I
# 6WJEBxjfMIIiyJ5msfV4y98POXMO3plVf9kvaWQH7AyQN4v1HuDtdnowDHoFkXSk
# hpDjITzYiX5rCWm7WTo/vOiLx0boAqpx3/cmJZAp+SJX1OE3Em+98JFhtxjuIAdh
# snoBfkvWrZuIeQVPNhQ6sIZhGqk6YpOJFhJeoaACdjCxx0Gv/KSBy2C+3ZSW2cJP
# abKXcwddXcSIQoSFA2X1MXd1xybTx43xBMgRmgyXyWYquqCHctwNwIvvBt0lwpbT
# +YcDXivx/H9ZUHrUgZ9Kjzf4CO+16SHxkfsXaoYhVxoR7IEaes1BzlBBRox5c4L0
# pbPGASvQkuwWhaMy4gTeKyf2DwEBpwxYDVkPRCRhHUaccAZd1l5Qc9ZaR0jsdLyO
# SXY9pLGe5ZJ3omKBQdsg8bLUujL8xshnICR0tZ+vkAGTvCtYcuDQKHxeUYbVjnQq
# b5x7wMSyhsqf9c8VOtKOmruJvbfISjxoXg==
# SIG # End signature block