AzureValidation/AzureADConfiguration.psm1

<#############################################################
# #
# Copyright (C) Microsoft Corporation. All rights reserved. #
# #
#############################################################>


$ErrorActionPreference = 'Stop'

Import-LocalizedData LocalizedData -BaseDirectory $PSScriptRoot -Filename AzureADConfiguration.Strings.psd1

$AzurePowerShellClientID = "1950a258-227b-4e31-a9cf-717495945fc2"
$AzurePowerShellReturnUri = "urn:ietf:wg:oauth:2.0:oob"

function Get-AzureURIs
{
    <#
    .SYNOPSIS
        Resolve Azure URIs for a given Azure Service
    .DESCRIPTION
        Resolve Azure URIs for a given Azure Service
    .EXAMPLE
        Get-AzureURIs -AzureEnvironment AzureCloud
    .INPUTS
        AzureEnvironment - string - should be AzureCloud, AzureChinaCloud, AzureGermanCloud
    .OUTPUTS
        Hashtable of URIs
    .NOTES
        General notes
    #>

    [OutputType([Hashtable])]
    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [ValidateSet("AzureCloud", "AzureChinaCloud", "AzureGermanCloud", "AzureUSGovernment", "CustomCloud")]
        [string] $AzureEnvironment,

        [Parameter(Mandatory=$false)]
        [string] $CustomCloudARMEndpoint
    )

    if($CustomCloudARMEndpoint){
        $CustomCloudARMEndpointProperties = Get-Endpoints -CloudARMEndpoint $CustomCloudARMEndpoint
    }

    $data = switch ($AzureEnvironment)
    {
        'AzureCloud'
        {
            @{
                GraphUri             = "https://graph.windows.net/"
                LoginUri             = "https://login.microsoftonline.com/"
                ManagementServiceUri = "https://management.core.windows.net/"
                ARMUri               = "https://management.azure.com/"
            }
        }

        'AzureChinaCloud'
        {
            @{
                GraphUri             = "https://graph.chinacloudapi.cn/"
                LoginUri             = "https://login.chinacloudapi.cn/"
                ManagementServiceUri = "https://management.core.chinacloudapi.cn/"
                ARMUri               = "https://management.chinacloudapi.cn/"
            }
        }

        'AzureUSGovernment'
        {
            @{
                GraphUri             = "https://graph.windows.net/"
                LoginUri             = "https://login.microsoftonline.us/"
                ManagementServiceUri = "https://management.core.usgovcloudapi.net/"
                ARMUri               = "https://management.usgovcloudapi.net/"
            }
        }

        'AzureGermanCloud'
        {
            @{
                GraphUri             = "https://graph.cloudapi.de/"
                LoginUri             = "https://login.microsoftonline.de/"
                ManagementServiceUri = "https://management.core.cloudapi.de/"
                ARMUri               = "https://management.microsoftazure.de/"
            }
        }

        'CustomCloud'
        {
            @{
                GraphUri             = $CustomCloudARMEndpointProperties.GraphUri
                LoginUri             = $CustomCloudARMEndpointProperties.LoginUri
                ManagementServiceUri = $CustomCloudARMEndpointProperties.ManagementServiceUri
                ARMUri               = $CustomCloudARMEndpointProperties.ARMUri
            }
        }

        default
        {
            throw New-Object NotImplementedException("Unknown environment type '$AzureEnvironment'")
        }
    }

    return $data
}

<#
.Synopsis
Builds graph and login endpoints for a given CloudARMEndpoint
#>

function Get-Endpoints([string] $CloudARMEndpoint)
{

    $fullUri = $CloudARMEndpoint.TrimEnd('/')+"/metadata/endpoints?api-version=2015-01-01"
    $response = Invoke-RestMethod -Uri $fullUri -ErrorAction Stop -UseBasicParsing -TimeoutSec 30

    $EndpointProperties = @{
        GraphUri = $response.graphEndpoint
        LoginUri = $response.authentication.loginEndpoint
        ManagementServiceUri = $response.authentication.audiences[0]
        ARMUri = $CloudARMEndpoint
    }

    return $EndpointProperties
}

function Get-AADToken
{
    [CmdletBinding()]
    param(
        [string]
        $ResourceUri,

        [string]
        $TenantId,

        [PSCredential]
        $Credential,

        [string]
        $UserId,

        [Hashtable]
        $AzureURIs,

        [Microsoft.IdentityModel.Clients.ActiveDirectory.PromptBehavior]
        $PromptBehavior
    )

    # new TokenCache instance provided to ensure returned access token is for the target user
    $context = New-Object Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext "$($AzureURIs.LoginUri.TrimEnd('/'))/$TenantId", $true, ([Microsoft.IdentityModel.Clients.ActiveDirectory.TokenCache]::new())

    Write-Verbose -Message "Date: $([System.DateTime]::UtcNow)"
    Write-Verbose -Message "AAD context : $($context | ConvertTo-Json)"
    Write-Verbose -Message "User: $($Credential.UserName) `nResourceUri: $ResourceUri `nAzPSClientID: $AzurePowerShellClientID"

    if ($Credential -ne $null)
    {
        $aadCredential = New-Object Microsoft.IdentityModel.Clients.ActiveDirectory.UserCredential $Credential.UserName,$Credential.Password
        return $context.AcquireToken($ResourceUri, $AzurePowerShellClientID, $aadCredential)
    }
    else
    {
        if ([string]::IsNullOrEmpty($UserId))
        {
            $userIdentifier = [Microsoft.IdentityModel.Clients.ActiveDirectory.UserIdentifier]::AnyUser
        }
        else
        {
            $userIdentifier = New-Object Microsoft.IdentityModel.Clients.ActiveDirectory.UserIdentifier $UserId, OptionalDisplayableId
        }

        return $context.AcquireToken(
                    $ResourceUri, $AzurePowerShellClientID, $AzurePowerShellReturnUri,
                    $PromptBehavior, $userIdentifier, "site_id=501358&display=popup")
    }
}

function Set-CookiesOptions
{
    [CmdletBinding(SupportsShouldProcess=$True,ConfirmImpact="Medium")]
    $signature = @'
    [DllImport("wininet.dll", SetLastError = true)]
    public static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int lpdwBufferLength);
 
    [DllImport("wininet.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern int PrivacySetZonePreference(int dwZone, int dwType, int dwTemplate, string pszPreference);
'@


    $type = Add-Type -MemberDefinition $signature -Name 'NativeMethods' -Namespace 'AzureStack.SetCookies' -PassThru -ErrorAction Ignore

    $INTERNET_OPTION_END_BROWSER_SESSION = 42
    $URLZONE_INTERNET = 3
    $PRIVACY_TYPE_FIRST_PARTY = 0
    $PRIVACY_TEMPLATE_ADVANCED = 101
    $preference = "IE6-P3PV1/settings: always=a session=a"

    $type::InternetSetOption([IntPtr]::Zero, $INTERNET_OPTION_END_BROWSER_SESSION, [IntPtr]::Zero, 0)
    $type::PrivacySetZonePreference($URLZONE_INTERNET, $PRIVACY_TYPE_FIRST_PARTY, $PRIVACY_TEMPLATE_ADVANCED, $preference)
}

function Get-AADTenantIds
{
    [OutputType([Hashtable])]
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [Hashtable] $AzureURIs,

        [Parameter(Mandatory=$false)]
        [PSCredential] $Credential
    )

    Set-CookiesOptions

    $token = Get-AADToken -ResourceUri $AzureURIs.ManagementServiceUri -TenantId "Common" -Credential $Credential -PromptBehavior Always -AzureURIs $AzureURIs

    $UserInfo = @{
        FirstName = $token.UserInfo.GivenName
        LastName = $token.UserInfo.FamilyName
        Account = $token.UserInfo.DisplayableId
    }

    $tenantsResponse = Invoke-RestMethod -Method Get -Uri "$($AzureURIs.ARMUri.TrimEnd('/'))/tenants?api-version=2016-02-01" -Headers @{Authorization = "Bearer $($token.AccessToken)"} -UseBasicParsing -TimeoutSec 30
    $tenantIds = [Array]$tenantsResponse.Value.tenantId

    return @{
                UserInfo = $UserInfo
                TenantIds = $tenantIds
            }
}

function Invoke-Graph($method, $uri, $authorization, $body)
{

    $params = @{
        Method  = $method
        Uri     = "$($uri)?api-version=1.6"
        Headers = @{ Authorization = $authorization }
        UseBasicParsing = $true
        TimeoutSec = 30
        ContentType = 'application/json'
    }
    if ($body) { $params += @{ Body = $body } }

    try
    {
        return (Invoke-WebRequest @params -ErrorAction Stop).Content | ConvertFrom-Json
    } 
    catch
    {
        if ($_.Exception.Response.StatusCode -eq 'Internal Server Error')
        {
            throw ($LocalizedData.GraphEndpointError -f $graphUri)
        }
        if ($_.Exception.Response.StatusCode -eq 'Forbidden')
        {
            return $null
        }
        else
        {
            throw $_
        }  
    }

}

function Get-AADTenantDetail
{
    [OutputType([Hashtable])]
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [string]
        $TenantId,

        [Parameter(Mandatory=$true)]
        [string]
        $UserId,

        [Parameter(Mandatory=$true)]
        [Hashtable]
        $AzureURIs,

        [Parameter(Mandatory=$false)]
        [PSCredential]
        $Credential
    )

    try
    {
        $token = Get-AADToken -ResourceUri $AzureURIs.GraphUri -TenantId $TenantId -Credential $Credential -PromptBehavior never -UserId $UserId -AzureURIs $AzureURIs
    }
    catch [Microsoft.IdentityModel.Clients.ActiveDirectory.AdalException]
    {
        if ($_.Exception.ErrorCode -eq "user_interaction_required")
        {
            $token = Get-AADToken -ResourceUri $AzureURIs.GraphUri -TenantId $TenantId -Credential $Credential -PromptBehavior auto -UserId $UserId -AzureURIs $AzureURIs
        }
        else
        {
            throw
        }
    }

    # Validating if the user has required permission
    $authorization = "Bearer $($token.AccessToken)"
    
    $accessTokenObj = ConvertFrom-JwtToken -JwtToken $token.AccessToken
    $postUri = $azureURIs.GraphUri.TrimEnd('/')+"/$($TenantId)/directoryObjects/$($accessTokenObj.Claims.oid)/getMemberObjects"
    $roles = Invoke-Graph -method Post -uri $postUri -authorization $authorization -body ( ConvertTo-Json -Depth 1 @{ securityEnabledOnly = $false } ) | Select-Object -ExpandProperty value
    if( $roles -eq $null ){ return $null }

    $getUri = $azureURIs.GraphUri.TrimEnd('/')+"/$($TenantId)/directoryRoles"
    $roleOid = Invoke-Graph -method Get -uri $getUri -authorization $authorization | Select-Object -ExpandProperty Value | Where displayName -EQ 'Company Administrator' | Select-Object -ExpandProperty objectId
    
    if ($roleOid -notin $roles){ return $null }

    $tenantResponse = Invoke-RestMethod -Method Get -Uri "$($AzureURIs.GraphUri.TrimEnd('/'))/myOrganization/tenantDetails?api-version=1.5" -Headers @{Authorization = "Bearer $($token.AccessToken)"} -UseBasicParsing -TimeoutSec 30

    return @{
                Id = $tenantResponse.Value.objectId
                DisplayName = $tenantResponse.Value.DisplayName
                DomainName = ($tenantResponse.Value.VerifiedDomains | Where {$_.default}).name
                Token = $token.AccessToken
                RefreshToken = $token.RefreshToken
            }
}

# Dlls packaged with AzureRM
$AzureRMBase = (Get-Module AzureRM.Profile -ListAvailable | Sort-Object version -Descending | Select-Object -first 1).ModuleBase
[System.Reflection.Assembly]::LoadFile("$AzureRMBase\Microsoft.IdentityModel.Clients.ActiveDirectory.dll") | Out-Null
[System.Reflection.Assembly]::LoadFile("$AzureRMBase\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll") | Out-Null
function Get-AADTenantDetails
{
    <#
    .SYNOPSIS
        Resolve Azure Tenant Details
    .DESCRIPTION
        Resolve Azure Tenant Details
    .EXAMPLE
        Get-AADTenantDetails -AzureEnvironment AzureCloud -Credential $tenantCredential
    .INPUTS
        AzureEnvironment - string - should be AzureCloud, AzureChinaCloud, AzureGermanCloud or CustomCloud
        Credetential - PSCredential
    .OUTPUTS
        Hashtable of tenant details
    .NOTES
        General notes
    #>

    [OutputType([Hashtable])]
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string] $AzureEnvironment,

        [Parameter(Mandatory=$false)]
        [PSCredential] $Credential,

        [Parameter(Mandatory=$false)]
        [string] $AADDirectoryTenantName,

        [Parameter(Mandatory=$false)]
        [string] $CustomCloudARMEndpoint
    )

    Write-Progress -Activity $LocalizedData.InfoSigningIn

    $azureURIs = Get-AzureURIs -AzureEnvironment $AzureEnvironment -CustomCloudARMEndpoint $CustomCloudARMEndpoint

    $TenantsInfo = Get-AADTenantIds -Credential $Credential -AzureURIs $azureURIs
    $TenantIds = [Array] $TenantsInfo.TenantIds

    # Workaround to add the target tenant Id if specified to the list of "resolved" tenant memberships
    if ($AADDirectoryTenantName)
    {
        $targetTenantId = Get-TenantIdFromName -azureEnvironment $AzureEnvironment -CustomCloudARMEndpoint $CustomCloudARMEndpoint -tenantName $AADDirectoryTenantName
        if ($TenantIds -inotcontains $targetTenantId)
        {
            $TenantIds = ([Array] $TenantsInfo.TenantIds) + $targetTenantId
        }
    }

    $tenantDetails = @()
    for ($i = 1; $i -le $TenantIds.Count; $i++)
    {
        Write-Progress -Activity $LocalizedData.InfoSigningIn -PercentComplete ($i * 100 / ($TenantIds.Count + 1))
        $tenantDetail =  Get-AADTenantDetail -Credential $Credential -TenantId $TenantIds[$i-1] -UserId $TenantsInfo.UserInfo.Account -AzureURIs $azureURIs
        if ($tenantDetail -ne $null)
        {
            $tenantDetails += $tenantDetail
        }
    }

    Write-Progress -Activity $LocalizedData.InfoSigningIn -Completed

    return @{
                UserInfo = $TenantsInfo.UserInfo
                TenantDetails = $tenantDetails
            }
}

function Get-AADUserObjectId
{
[CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string] $AzureEnvironment,

        [string] $TenantId,
        [PSCredential] $Credential,

        [Parameter(Mandatory=$false)]
        [string] $CustomCloudARMEndpoint
    )

    $azureURIs = Get-AzureURIs -AzureEnvironment $AzureEnvironment -CustomCloudARMEndpoint $CustomCloudARMEndpoint

    return (Get-AADToken -ResourceUri $azureURIs.GraphUri -TenantId $TenantId -Credential $Credential -AzureURIs $azureURIs).UserInfo.UniqueId
}

<#
.Synopsis
Decodes a base64-encoded string.
#>

function ConvertFrom-Base64String
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [ValidateNotNull()]
        [string] $Base64String
    )
    process
    {
        $data = $Base64String.Replace('-','+').Replace('_','/')
        switch ($data.Length % 4)
        {
            0 { break }
            2 { $data += '==' }
            3 { $data += '=' }
            default { Write-Error "Invalid data: '$data'" }
    }
        $bytes = [System.Convert]::FromBase64String($data)
        Write-Output $bytes
    }
}

<#
.Synopsis
Converts a Jwt Token into an object.
#>

function ConvertFrom-JwtToken
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [string] $JwtToken
    )

    function ConvertFrom-RawData([String]$Data)
    {
        [System.Text.Encoding]::UTF8.GetString((ConvertFrom-Base64String $Data)) | ConvertFrom-Json | Write-Output
    }

    $parts = $JwtToken.Split('.')
    [pscustomobject]@{
        Headers = ConvertFrom-RawData $parts[0]
        Claims = ConvertFrom-RawData $parts[1]
        Signature = $parts[2]
    } | Write-Output
}

function Get-AzureADTenantDetails
{
    <#
    .SYNOPSIS
        Resolve Azure AD Tenant Details
    .DESCRIPTION
        Resolve Azure AD Tenant Details
    .EXAMPLE
        Get-AzureADTenantDetails -AzureEnvironment AzureCloud -AADAdminCredential $AADAdminCredential $AADDirectoryTenantName $AADDirectoryTenantName
    .INPUTS
        AzureEnvironment - string - should be AzureCloud, AzureChinaCloud, AzureGermanCloud or CustomCloud
        AADAdminCredential - PSCredential - AAD Admin Credential
        AADDirectoryTenantName - string - AAD tenant Name
    .OUTPUTS
        Hashtable of Azure AD tenant details
    .NOTES
        General notes
    #>

    [OutputType([Hashtable])]
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [string] $AzureEnvironment,

        [Parameter(Mandatory=$false)]
        [PSCredential] $AADAdminCredential,

        [Parameter(Mandatory=$false)]
        [string] $AADDirectoryTenantName,

        [Parameter(Mandatory=$false)]
        [string] $CustomCloudARMEndpoint
    )

    $claimsProvider = $AzureEnvironment

    $azureResult = Get-AADTenantDetails -AzureEnvironment $AzureEnvironment -CustomCloudARMEndpoint $CustomCloudARMEndpoint -Credential $AADAdminCredential -AADDirectoryTenantName $AADDirectoryTenantName
    $azureToken = $null
    $azureRefreshToken = $null
    $tenantId = $null
    $tenantName = $null

    if ($azureResult.TenantDetails -eq $null -or @($azureResult.TenantDetails).Count -eq 0)
    {
        Write-Error ($LocalizedData.AADAccountNotAdmin -f $($azureResult.UserInfo.Account))
    }
    elseif (@($azureResult.TenantDetails).Count -gt 1 -and -not $AADDirectoryTenantName)
    {
        Write-Error ($LocalizedData.MoreThanOneTenant -f @($($azureResult.UserInfo.Account), $($azureResult.TenantDetails.DomainName -join ', ')))
    }
    elseif (@($azureResult.TenantDetails).Count -ige 1 -and $AADDirectoryTenantName)
    {
        $tenantDetail = $azureResult.TenantDetails | Where-Object DomainName -eq $AADDirectoryTenantName
        if ($tenantDetail)
        {
            $azureToken = $tenantDetail.Token
            $azureRefreshToken = $tenantDetail.RefreshToken
            $tenantName = $tenantDetail.DomainName
            $tenantID = $tenantDetail.ID
        }
        else
        {
            Write-Error ($LocalizedData.NotAdminOfTenant -f @($($azureResult.UserInfo.Account), $AADDirectoryTenantName, $($azureResult.TenantDetails.DomainName -join ', ')))
        }
    }
    else
    {
        $azureToken = $azureResult.TenantDetails.Token
        $azureRefreshToken = $azureResult.TenantDetails.RefreshToken
        $tenantName = $azureResult.TenantDetails.DomainName
        $tenantID = $azureResult.TenantDetails.ID
    }

    $adminSubscriptionOwner = (ConvertFrom-JwtToken $azureToken).Claims.unique_name

    return @{
                UserName = $azureResult.UserInfo.Account
                Token = $azureToken
                RefreshToken = $azureRefreshToken
                AdminSubscriptionOwner = $adminSubscriptionOwner
                TenantDirectoryName = $tenantName
                TenantDirectoryID = $tenantID
                ClaimsProvider = $claimsProvider
            }
}

<#
.SYNOPSIS
    Returns Azure AD directory tenant ID given the login endpoint and the directory tenant name
.DESCRIPTION
    Makes an unauthenticated REST call to the given Azure environment's login endpoint to retrieve directory tenant id
.EXAMPLE
$tenantId = Get-TenantIdFromName -azureEnvironment "Public Azure" -tenantName "msazurestack.onmicrosoft.com"
#>

function Get-TenantIdFromName
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory=$true)]
        [ValidateNotNull()]
        [string] $azureEnvironment,

        [Parameter(Mandatory=$true)]
        [ValidateNotNull()]
        [string] $tenantName,

        [Parameter(Mandatory=$false)]
        [string] $CustomCloudARMEndpoint
    )

    $azureURIs = Get-AzureURIs -AzureEnvironment $AzureEnvironment -CustomCloudARMEndpoint $CustomCloudARMEndpoint

    $uri = "{0}/{1}/.well-known/openid-configuration" -f ($azureURIs.LoginUri).TrimEnd('/'), $tenantName

    $response = Invoke-RestMethod -Uri $uri -Method Get -UseBasicParsing -TimeoutSec 30

    Write-Verbose -Message "using token_endpoint $($response.token_endpoint) to parse tenant id"
    $tenantId = $response.token_endpoint.Split('/')[3]

    $tenantIdGuid = [guid]::NewGuid()
    $result = [guid]::TryParse($tenantId, [ref] $tenantIdGuid)

    if(-not $result)
    {
        Write-Error "Error obtaining tenant id from tenant name"
    }
    else
    {
        Write-Verbose -Message "Tenant Name: $tenantName Tenant id: $tenantId"
        return $tenantId
    }
}

Export-ModuleMember -Function Get-AzureADTenantDetails
Export-ModuleMember -Function Get-AzureURIs
Export-ModuleMember -Function Get-TenantIdFromName
Export-ModuleMember -Function Get-AADToken
# SIG # Begin signature block
# MIIjkgYJKoZIhvcNAQcCoIIjgzCCI38CAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCyUwhF6o4YCUNC
# vQD1yXzKYccE3vi97vRV/tik93sSz6CCDYEwggX/MIID56ADAgECAhMzAAABh3IX
# chVZQMcJAAAAAAGHMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
# bmcgUENBIDIwMTEwHhcNMjAwMzA0MTgzOTQ3WhcNMjEwMzAzMTgzOTQ3WjB0MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQDOt8kLc7P3T7MKIhouYHewMFmnq8Ayu7FOhZCQabVwBp2VS4WyB2Qe4TQBT8aB
# znANDEPjHKNdPT8Xz5cNali6XHefS8i/WXtF0vSsP8NEv6mBHuA2p1fw2wB/F0dH
# sJ3GfZ5c0sPJjklsiYqPw59xJ54kM91IOgiO2OUzjNAljPibjCWfH7UzQ1TPHc4d
# weils8GEIrbBRb7IWwiObL12jWT4Yh71NQgvJ9Fn6+UhD9x2uk3dLj84vwt1NuFQ
# itKJxIV0fVsRNR3abQVOLqpDugbr0SzNL6o8xzOHL5OXiGGwg6ekiXA1/2XXY7yV
# Fc39tledDtZjSjNbex1zzwSXAgMBAAGjggF+MIIBejAfBgNVHSUEGDAWBgorBgEE
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUhov4ZyO96axkJdMjpzu2zVXOJcsw
# UAYDVR0RBEkwR6RFMEMxKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVyYXRpb25zIFB1
# ZXJ0byBSaWNvMRYwFAYDVQQFEw0yMzAwMTIrNDU4Mzg1MB8GA1UdIwQYMBaAFEhu
# ZOVQBdOCqhc3NyK1bajKdQKVMFQGA1UdHwRNMEswSaBHoEWGQ2h0dHA6Ly93d3cu
# bWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY0NvZFNpZ1BDQTIwMTFfMjAxMS0w
# Ny0wOC5jcmwwYQYIKwYBBQUHAQEEVTBTMFEGCCsGAQUFBzAChkVodHRwOi8vd3d3
# Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY0NvZFNpZ1BDQTIwMTFfMjAx
# MS0wNy0wOC5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAgEAixmy
# S6E6vprWD9KFNIB9G5zyMuIjZAOuUJ1EK/Vlg6Fb3ZHXjjUwATKIcXbFuFC6Wr4K
# NrU4DY/sBVqmab5AC/je3bpUpjtxpEyqUqtPc30wEg/rO9vmKmqKoLPT37svc2NV
# BmGNl+85qO4fV/w7Cx7J0Bbqk19KcRNdjt6eKoTnTPHBHlVHQIHZpMxacbFOAkJr
# qAVkYZdz7ikNXTxV+GRb36tC4ByMNxE2DF7vFdvaiZP0CVZ5ByJ2gAhXMdK9+usx
# zVk913qKde1OAuWdv+rndqkAIm8fUlRnr4saSCg7cIbUwCCf116wUJ7EuJDg0vHe
# yhnCeHnBbyH3RZkHEi2ofmfgnFISJZDdMAeVZGVOh20Jp50XBzqokpPzeZ6zc1/g
# yILNyiVgE+RPkjnUQshd1f1PMgn3tns2Cz7bJiVUaqEO3n9qRFgy5JuLae6UweGf
# AeOo3dgLZxikKzYs3hDMaEtJq8IP71cX7QXe6lnMmXU/Hdfz2p897Zd+kU+vZvKI
# 3cwLfuVQgK2RZ2z+Kc3K3dRPz2rXycK5XCuRZmvGab/WbrZiC7wJQapgBodltMI5
# GMdFrBg9IeF7/rP4EqVQXeKtevTlZXjpuNhhjuR+2DMt/dWufjXpiW91bo3aH6Ea
# jOALXmoxgltCp1K7hrS6gmsvj94cLRf50QQ4U8Qwggd6MIIFYqADAgECAgphDpDS
# AAAAAAADMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMK
# V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0
# IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0
# ZSBBdXRob3JpdHkgMjAxMTAeFw0xMTA3MDgyMDU5MDlaFw0yNjA3MDgyMTA5MDla
# MH4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS
# ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMT
# H01pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTEwggIiMA0GCSqGSIb3DQEB
# AQUAA4ICDwAwggIKAoICAQCr8PpyEBwurdhuqoIQTTS68rZYIZ9CGypr6VpQqrgG
# OBoESbp/wwwe3TdrxhLYC/A4wpkGsMg51QEUMULTiQ15ZId+lGAkbK+eSZzpaF7S
# 35tTsgosw6/ZqSuuegmv15ZZymAaBelmdugyUiYSL+erCFDPs0S3XdjELgN1q2jz
# y23zOlyhFvRGuuA4ZKxuZDV4pqBjDy3TQJP4494HDdVceaVJKecNvqATd76UPe/7
# 4ytaEB9NViiienLgEjq3SV7Y7e1DkYPZe7J7hhvZPrGMXeiJT4Qa8qEvWeSQOy2u
# M1jFtz7+MtOzAz2xsq+SOH7SnYAs9U5WkSE1JcM5bmR/U7qcD60ZI4TL9LoDho33
# X/DQUr+MlIe8wCF0JV8YKLbMJyg4JZg5SjbPfLGSrhwjp6lm7GEfauEoSZ1fiOIl
# XdMhSz5SxLVXPyQD8NF6Wy/VI+NwXQ9RRnez+ADhvKwCgl/bwBWzvRvUVUvnOaEP
# 6SNJvBi4RHxF5MHDcnrgcuck379GmcXvwhxX24ON7E1JMKerjt/sW5+v/N2wZuLB
# l4F77dbtS+dJKacTKKanfWeA5opieF+yL4TXV5xcv3coKPHtbcMojyyPQDdPweGF
# RInECUzF1KVDL3SV9274eCBYLBNdYJWaPk8zhNqwiBfenk70lrC8RqBsmNLg1oiM
# CwIDAQABo4IB7TCCAekwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFEhuZOVQ
# BdOCqhc3NyK1bajKdQKVMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1Ud
# DwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFHItOgIxkEO5FAVO
# 4eqnxzHRI4k0MFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9jcmwubWljcm9zb2Z0
# LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y
# Mi5jcmwwXgYIKwYBBQUHAQEEUjBQME4GCCsGAQUFBzAChkJodHRwOi8vd3d3Lm1p
# Y3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y
# Mi5jcnQwgZ8GA1UdIASBlzCBlDCBkQYJKwYBBAGCNy4DMIGDMD8GCCsGAQUFBwIB
# FjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2RvY3MvcHJpbWFyeWNw
# cy5odG0wQAYIKwYBBQUHAgIwNB4yIB0ATABlAGcAYQBsAF8AcABvAGwAaQBjAHkA
# XwBzAHQAYQB0AGUAbQBlAG4AdAAuIB0wDQYJKoZIhvcNAQELBQADggIBAGfyhqWY
# 4FR5Gi7T2HRnIpsLlhHhY5KZQpZ90nkMkMFlXy4sPvjDctFtg/6+P+gKyju/R6mj
# 82nbY78iNaWXXWWEkH2LRlBV2AySfNIaSxzzPEKLUtCw/WvjPgcuKZvmPRul1LUd
# d5Q54ulkyUQ9eHoj8xN9ppB0g430yyYCRirCihC7pKkFDJvtaPpoLpWgKj8qa1hJ
# Yx8JaW5amJbkg/TAj/NGK978O9C9Ne9uJa7lryft0N3zDq+ZKJeYTQ49C/IIidYf
# wzIY4vDFLc5bnrRJOQrGCsLGra7lstnbFYhRRVg4MnEnGn+x9Cf43iw6IGmYslmJ
# aG5vp7d0w0AFBqYBKig+gj8TTWYLwLNN9eGPfxxvFX1Fp3blQCplo8NdUmKGwx1j
# NpeG39rz+PIWoZon4c2ll9DuXWNB41sHnIc+BncG0QaxdR8UvmFhtfDcxhsEvt9B
# xw4o7t5lL+yX9qFcltgA1qFGvVnzl6UJS0gQmYAf0AApxbGbpT9Fdx41xtKiop96
# eiL6SJUfq/tHI4D1nvi/a7dLl+LrdXga7Oo3mXkYS//WsyNodeav+vyL6wuA6mk7
# r/ww7QRMjt/fdW1jkT3RnVZOT7+AVyKheBEyIXrvQQqxP/uozKRdwaGIm1dxVk5I
# RcBCyZt2WwqASGv9eZ/BvW1taslScxMNelDNMYIVZzCCFWMCAQEwgZUwfjELMAkG
# A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx
# HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9z
# b2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMQITMwAAAYdyF3IVWUDHCQAAAAABhzAN
# BglghkgBZQMEAgEFAKCBrjAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgor
# BgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgIPkS/r42
# R42JJmhowdCFItVE6CfRqVHJKKAf78sk/JEwQgYKKwYBBAGCNwIBDDE0MDKgFIAS
# AE0AaQBjAHIAbwBzAG8AZgB0oRqAGGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbTAN
# BgkqhkiG9w0BAQEFAASCAQCKIBRiKJcfM4eCFxzawk2ME8lVz/Z3L62KFHg45wT3
# cLIRIfyX+ExXdzD1pzEq1tvEobtz0gj7i7k2CrTOZEO/sXewfuZvRDbFE5YX+MBC
# zWXgvG+022wt+srRtqmAkpqKcDzrKSqcZwMk9af1QyXWUCeesO95jcROVy0HK9Es
# N9ozqBxyhD4TOz5USWnvi2/sPynUcRSZVegmy/8u/2eU63ZzOJabP4NYHS8Ni9Ci
# uS//pPWAMu4P+SwP1Fla8N4hk3Vwmlg4Rw1RiEvzBeNBXS+fzLImcM/zmrEcQHJt
# NsFPGjygbwclN0UVGS0gIAHp6RIbXqrFHGpQD3BYlkd6oYIS8TCCEu0GCisGAQQB
# gjcDAwExghLdMIIS2QYJKoZIhvcNAQcCoIISyjCCEsYCAQMxDzANBglghkgBZQME
# AgEFADCCAVUGCyqGSIb3DQEJEAEEoIIBRASCAUAwggE8AgEBBgorBgEEAYRZCgMB
# MDEwDQYJYIZIAWUDBAIBBQAEIC+/SyH/WEAo5FLD1fqzxNzEdaPtSa4ltMs8Pj9X
# z6teAgZfiEOoHfwYEzIwMjAxMDI4MTAxNDM2LjE4OVowBIACAfSggdSkgdEwgc4x
# CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt
# b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1p
# Y3Jvc29mdCBPcGVyYXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMg
# VFNTIEVTTjo3ODgwLUUzOTAtODAxNDElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUt
# U3RhbXAgU2VydmljZaCCDkQwggT1MIID3aADAgECAhMzAAABKKAOgeE21U/CAAAA
# AAEoMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo
# aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y
# cG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEw
# MB4XDTE5MTIxOTAxMTUwMFoXDTIxMDMxNzAxMTUwMFowgc4xCzAJBgNVBAYTAlVT
# MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQK
# ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVy
# YXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjo3ODgw
# LUUzOTAtODAxNDElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2Vydmlj
# ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ2Rsdb3VNuGPs2/Dgpc
# 9gt77LG0JPkD4VWTlEJLkqznTJl+RoZfiOwN6iWfPu4k/kj8nwY7pvLs1OsBy494
# yusg4rHLwHNUJPtw1Tc54MOLgdcosA4Nxki73fDyqWwDtjOdk6H7kNczBPqADD6B
# 98ot77/wSACBJIxm9qAUudquS5fczCF0++aWUavDu46U3cv6HEjIdV2ZdJTUKg4W
# UIdTYMQXI082+qSs45WBZjcK98/tIfx8uq8q8ksWF9+zUjGTFiMaKHhn7cSCoEj7
# E1tVmW08ISpS678WFP2+A0OQwaWcJKNACK+J+La7Lz2bGupCidOGz5XDewc1lD9n
# LPcCAwEAAaOCARswggEXMB0GA1UdDgQWBBSE4vKD8X61N5vUAcNOdH9QBMum8jAf
# BgNVHSMEGDAWgBTVYzpcijGQ80N7fEYbxTNoWoVtVTBWBgNVHR8ETzBNMEugSaBH
# hkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNU
# aW1TdGFQQ0FfMjAxMC0wNy0wMS5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUF
# BzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1RpbVN0
# YVBDQV8yMDEwLTA3LTAxLmNydDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsG
# AQUFBwMIMA0GCSqGSIb3DQEBCwUAA4IBAQCLX2ZHGIULgDk/iccHWUywjDyAsBHl
# hkmtmBp4lldwL3dNo0bXZZHiSZB+c2KzvPqY64BlECjS/Pqur2m9UaT1N0BeUowR
# HQT88wdzd94gYqKXmLDbVR8yeVgBkcP/JiVWbXdQzcz1ETHgWrh+uzA8BwUgAaHJ
# w+nXYccIuDgPJM1UTeNl9R5Ovf+6zR2E5ZI4DrIqvS4jH4QsoMPTn27AjN7VZt4a
# moRxMLEcQAS7vPT1JUUaRFpFHmkUYVln1YMsw///6968aRvy3cmClS44uxkkaILb
# hh1h09ejZjHhrEn+k9McVkWiuY724jJ/57tylM7A/jzIWNj1F8VlhkyyMIIGcTCC
# BFmgAwIBAgIKYQmBKgAAAAAAAjANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMC
# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJv
# b3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTAwHhcNMTAwNzAxMjEzNjU1WhcN
# MjUwNzAxMjE0NjU1WjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv
# bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0
# aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDCCASIw
# DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKkdDbx3EYo6IOz8E5f1+n9plGt0
# VBDVpQoAgoX77XxoSyxfxcPlYcJ2tz5mK1vwFVMnBDEfQRsalR3OCROOfGEwWbEw
# RA/xYIiEVEMM1024OAizQt2TrNZzMFcmgqNFDdDq9UeBzb8kYDJYYEbyWEeGMoQe
# dGFnkV+BVLHPk0ySwcSmXdFhE24oxhr5hoC732H8RsEnHSRnEnIaIYqvS2SJUGKx
# Xf13Hz3wV3WsvYpCTUBR0Q+cBj5nf/VmwAOWRH7v0Ev9buWayrGo8noqCjHw2k4G
# kbaICDXoeByw6ZnNPOcvRLqn9NxkvaQBwSAJk3jN/LzAyURdXhacAQVPIk0CAwEA
# AaOCAeYwggHiMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBTVYzpcijGQ80N7
# fEYbxTNoWoVtVTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMC
# AYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvX
# zpoYxDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20v
# cGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYI
# KwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDCBoAYDVR0g
# AQH/BIGVMIGSMIGPBgkrBgEEAYI3LgMwgYEwPQYIKwYBBQUHAgEWMWh0dHA6Ly93
# d3cubWljcm9zb2Z0LmNvbS9QS0kvZG9jcy9DUFMvZGVmYXVsdC5odG0wQAYIKwYB
# BQUHAgIwNB4yIB0ATABlAGcAYQBsAF8AUABvAGwAaQBjAHkAXwBTAHQAYQB0AGUA
# bQBlAG4AdAAuIB0wDQYJKoZIhvcNAQELBQADggIBAAfmiFEN4sbgmD+BcQM9naOh
# IW+z66bM9TG+zwXiqf76V20ZMLPCxWbJat/15/B4vceoniXj+bzta1RXCCtRgkQS
# +7lTjMz0YBKKdsxAQEGb3FwX/1z5Xhc1mCRWS3TvQhDIr79/xn/yN31aPxzymXlK
# kVIArzgPF/UveYFl2am1a+THzvbKegBvSzBEJCI8z+0DpZaPWSm8tv0E4XCfMkon
# /VWvL/625Y4zu2JfmttXQOnxzplmkIz/amJ/3cVKC5Em4jnsGUpxY517IW3DnKOi
# PPp/fZZqkHimbdLhnPkd/DjYlPTGpQqWhqS9nhquBEKDuLWAmyI4ILUl5WTs9/S/
# fmNZJQ96LjlXdqJxqgaKD4kWumGnEcua2A5HmoDF0M2n0O99g/DhO3EJ3110mCII
# YdqwUB5vvfHhAN/nMQekkzr3ZUd46PioSKv33nJ+YWtvd6mBy6cJrDm77MbL2IK0
# cs0d9LiFAR6A+xuJKlQ5slvayA1VmXqHczsI5pgt6o3gMy4SKfXAL1QnIffIrE7a
# KLixqduWsqdCosnPGUFN4Ib5KpqjEWYw07t0MkvfY3v1mYovG8chr1m1rtxEPJdQ
# cdeh0sVV42neV8HR3jDA/czmTfsNv11P6Z0eGTgvvM9YBS7vDaBQNdrvCScc1bN+
# NR4Iuto229Nfj950iEkSoYIC0jCCAjsCAQEwgfyhgdSkgdEwgc4xCzAJBgNVBAYT
# AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD
# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1pY3Jvc29mdCBP
# cGVyYXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjo3
# ODgwLUUzOTAtODAxNDElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2Vy
# dmljZaIjCgEBMAcGBSsOAwIaAxUAMT1LG/KAEj0XsiL9n7mxmX1afZuggYMwgYCk
# fjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
# UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQD
# Ex1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQUFAAIF
# AONDPCkwIhgPMjAyMDEwMjgwNDM5MDVaGA8yMDIwMTAyOTA0MzkwNVowdzA9Bgor
# BgEEAYRZCgQBMS8wLTAKAgUA40M8KQIBADAKAgEAAgIhwwIB/zAHAgEAAgIRljAK
# AgUA40SNqQIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIB
# AAIDB6EgoQowCAIBAAIDAYagMA0GCSqGSIb3DQEBBQUAA4GBACtR3pwf4e0dpARD
# TtFNvaozErP/pjYkLCt7BsEIoSH3EhFrLpMZyi+wfsGTxhXMqxXXXacmSfMT7Fhk
# 68phW7DTeBGGG+8xw2rklK0qYbrHoNiIHab/Mq5v1J2sQJYr/lyEHmIMRO+t3saW
# HTUr7+VIzozJMby+PUpg/ewsq5PYMYIDDTCCAwkCAQEwgZMwfDELMAkGA1UEBhMC
# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRp
# bWUtU3RhbXAgUENBIDIwMTACEzMAAAEooA6B4TbVT8IAAAAAASgwDQYJYIZIAWUD
# BAIBBQCgggFKMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0B
# CQQxIgQgSi9sccewtY9acKRtGYGHOkNBnlHnOcBlaeLOfEL357AwgfoGCyqGSIb3
# DQEJEAIvMYHqMIHnMIHkMIG9BCC8RWqLrwVSd+/cGxDfBqS4b1tPXhoPFrC615vV
# 1ugU2jCBmDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9u
# MRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp
# b24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAAB
# KKAOgeE21U/CAAAAAAEoMCIEID5rIhPu+Gcx+HRpoVGNavMLMgV2eS1DHJRNq4Fk
# r4saMA0GCSqGSIb3DQEBCwUABIIBAH/G5J9uG4H5iqQJaOHNVEVI4uVwSyb7xANL
# EhpVa/HqOPnynH4CO+is4tjI3tD1rd3gTEhtoovNwwxW097jb9p7+DeCkeT8WC/b
# VQ9Lr1KmeKSikvsA/3sOLO1jK+GZJp2titDYUpBLJUHJBUIiO3v0REqvDBYp43U3
# ZkuAXNMkm253C5pFzdMBpv0Evp0rpPPMhW+O//qPuGY+sqsUNDgomXpJ5lhsyQRq
# 98ABJGnv6CnX63FFYirAHgARoIh1Uo5Oj+gd5kbf5ARSjsOOGQ6t25smWn6tiitd
# /ZPC8O3X5mNgGHWU8mHg3grcFw5JIGaJzYCVYvgFC9ta2sKReyU=
# SIG # End signature block