GoogleAuthenticationFactory.psm1
|
#region Public commands <# .SYNOPSIS Gets an OAuth access token from a Google authentication factory. .DESCRIPTION Retrieves an access token from the supplied factory instance, the named factory, or the most recently created factory stored in the module scope. Use -AsHashTable to return an Authorization header that can be passed directly to Invoke-RestMethod or Invoke-WebRequest. .PARAMETER AsHashTable Returns a hashtable containing the Authorization header instead of the raw token object. .PARAMETER Factory The authentication factory instance to use. You can pass a factory object or the name of a registered factory. If omitted, the current module-level default factory is used. .PARAMETER ForceRefresh Forces acquisition of a new token instead of reusing a cached valid token. .EXAMPLE PS> Get-GoogleAccessToken Gets the access token from the most recently created factory. .EXAMPLE PS> Get-GoogleAccessToken -Factory 'googleAdminApi' -AsHashTable Gets the access token from the named factory and returns it as an Authorization header hashtable. .EXAMPLE PS> Get-GoogleAccessToken -Factory 'googleAdminApi' -ForceRefresh Forces a fresh token retrieval from the named factory. .OUTPUTS System.Collections.Hashtable Google access token object #> function Get-GoogleAccessToken { param ( [switch]$AsHashTable, [Parameter()] $Factory = $script:GoogleTokenProvider, [switch]$ForceRefresh ) process { if($Factory -is [string]) { #name of factory has been passed $Factory = Get-GoogleAuthenticationFactory -Name $Factory } $token = $Factory.GetAccessToken($ForceRefresh) if($AsHashTable) { @{ Authorization = "$($token.token_type) $($token.access_token)" } } else { $token } } } <# .SYNOPSIS Gets one or more registered Google authentication factories. .DESCRIPTION Returns a registered factory by name, all registered factories, or the current default factory when no parameters are specified. .PARAMETER Name The name of a registered factory to retrieve. .PARAMETER All Returns all registered factories instead of only the current default factory. .EXAMPLE PS> Get-GoogleAuthenticationFactory Returns the current default Google authentication factory. .EXAMPLE PS> Get-GoogleAuthenticationFactory -Name 'chatAdminApi' Returns the registered factory with the specified name. .EXAMPLE PS> Get-GoogleAuthenticationFactory -All Returns all registered Google authentication factories. .OUTPUTS GoogleTokenProvider System.Object[] #> function Get-GoogleAuthenticationFactory { param ( [Parameter()] [string]$Name, [switch]$All ) process { if(-not [string]::IsNullOrEmpty($Name)) { if($script:GoogleAuthenticationProviders.ContainsKey($Name)) { return $script:GoogleAuthenticationProviders[$Name] } else { Write-Warning "No Google authentication provider registered with name '$Name'" return $null } } else { if($all) { return $script:GoogleAuthenticationProviders.Values } else { return $script:GoogleTokenProvider } } } } <# .SYNOPSIS Creates a Google authentication factory for acquiring access tokens. .DESCRIPTION Creates a new GoogleTokenProvider instance using either service account JSON credentials or Azure AD federated credentials, then stores it as the current module-level default provider. Optionally registers the provider by name and enables Application Insights logging. In the federated flow, you can optionally exchange the federated token for a service-account access token by supplying `-ServiceAccountEmail`. .PARAMETER GoogleAccessJson The raw JSON content of the Google service account credentials. Used by parameter set: ClientSecret. .PARAMETER AadAuthenticationFactory An Azure AD authentication factory configured for workload identity federation. Used by parameter set: AadFederated. .PARAMETER WorkloadIdentityProviderResourceId The full Google workload identity provider resource identifier configured for federated identity. Used by parameter set: AadFederated. .PARAMETER ServiceAccountEmail The Google service account email used to exchange the federated token for a native Google service-account access token. If omitted, the factory uses the federated token directly. Used by parameter set: AadFederated. .PARAMETER Scopes One or more Google API scopes to request when acquiring access tokens. .PARAMETER TargetUserEmail The email address of the user to impersonate. If omitted, no impersonation is used. Used by parameter set: ClientSecret. .PARAMETER Name An optional name used to register the factory in the module-level factory dictionary. .PARAMETER AiLogger Optional logger instance used for Application Insights logging. .EXAMPLE PS> $jsonData = Get-Content -Path 'C:\service-account.json' -Raw PS> New-GoogleAuthenticationFactory -GoogleAccessJson $jsonData -Scopes 'https://www.googleapis.com/auth/admin.directory.user.readonly' Creates a new factory and makes it the current default factory. .EXAMPLE PS> New-GoogleAuthenticationFactory -GoogleAccessJson $jsonData -Scopes 'https://www.googleapis.com/auth/chat.admin.spaces.readonly' -TargetUserEmail 'user@contoso.com' -Name 'chatAdminApi' Creates a named factory that uses user impersonation. .EXAMPLE PS> New-GoogleAuthenticationFactory -AadAuthenticationFactory $aadFactory -WorkloadIdentityProviderResourceId '//iam.googleapis.com/projects/132546827814/locations/global/workloadIdentityPools/my-pool/providers/entra-id-mytenant-com' -ServiceAccountEmail 'service-account@project-id.iam.gserviceaccount.com' -Scopes 'https://www.googleapis.com/auth/cloud-platform' -Name 'federatedApi' Creates a named factory using Azure AD federated credentials. .EXAMPLE PS> New-GoogleAuthenticationFactory -AadAuthenticationFactory $aadFactory -WorkloadIdentityProviderResourceId '//iam.googleapis.com/projects/132546827814/locations/global/workloadIdentityPools/my-pool/providers/entra-id-mytenant-com' -Scopes 'https://www.googleapis.com/auth/cloud-platform' -Name 'federatedApi' Creates a named factory that uses the federated token directly without service-account exchange. .OUTPUTS GoogleTokenProvider #> function New-GoogleAuthenticationFactory { param ( [Parameter(Mandatory, ParameterSetName='ClientSecret')] [string] #Google access JSON file content $GoogleAccessJson, [Parameter(ParameterSetName='ClientSecret')] [string] #Impersonated user email address # If not specified, impoersonation will not be used $TargetUserEmail, [Parameter(Mandatory, ParameterSetName='AadFederated')] [object] #instance of AAD Authentication Factory configured for federated credentials $AadAuthenticationFactory, [Parameter(Mandatory, ParameterSetName='AadFederated')] [string] #Resource ID of the Google workload identity provider configured in Azure AD #Example: //iam.googleapis.com/projects/132546827814/locations/global/workloadIdentityPools/my-pool/providers/entra-id-mytenant-com $WorkloadIdentityProviderResourceId, [Parameter(ParameterSetName='AadFederated')] [string] #email address of the service account to impersonate. If not specified, the factory will use the federated token directly without exchanging for a service account token. #Important: to be able to impersonate, the federated identity must have "Service Account Token Creator" role on the target service account $ServiceAccountEmail, [Parameter(Mandatory)] [string[]] #Scopes requested to be granted $Scopes, [Parameter()] [string] #Name of the factory instance # If specified, the factory will be registered in the global dictionary of Google authentication providers $Name, [Parameter()] #AI logger to use for logging to Application insights #Instance of this logger can be obtained via module AiLogging $AiLogger ) process { switch($PSCmdlet.ParameterSetName) { 'AadFederated' { Write-Verbose "Creating Google authentication factory using Azure AD federated credentials" $script:GoogleTokenProvider = [GoogleTokenProvider]::new($AadAuthenticationFactory, $WorkloadIdentityProviderResourceId, $ServiceAccountEmail, $Scopes, $Name, $AiLogger) break; } 'ClientSecret' { if(-not [string]::IsNullOrEmpty($TargetUserEmail)) { Write-Verbose "Using impersonation for user $TargetUserEmail" } Write-Verbose "Creating Google authentication factory using JSON credentials" $script:GoogleTokenProvider = [GoogleTokenProvider]::new($GoogleAccessJson, $Scopes, $TargetUserEmail, $Name, $AiLogger) break; } default { throw "Invalid parameter set: $($PSCmdlet.ParameterSetName)" } } if(-not [string]::IsNullOrEmpty($Name)) { $script:GoogleAuthenticationProviders[$Name] = $script:GoogleTokenProvider Write-Verbose "Registered Google authentication provider with name '$Name'" } $script:GoogleTokenProvider } } <# .SYNOPSIS Displays diagnostic information about a Google access token. .DESCRIPTION Calls the factory's token test routine to inspect the current access token. The factory can be provided directly, looked up by name, or taken from the current module-level default factory. Direct federated tokens are not supported by the Google token inspection endpoint used by this command; in that case the command returns `$null` and writes a warning. .PARAMETER Factory The authentication factory instance to test. You can pass a factory object or the name of a registered factory. If omitted, the current module-level default factory is used. .EXAMPLE PS> Test-GoogleAccessToken Tests the access token for the current default factory. .EXAMPLE PS> Test-GoogleAccessToken -Factory 'googleAdminApi' Tests the access token for the named factory. .EXAMPLE PS> Test-GoogleAccessToken -Factory 'federatedApi' Tests the token for the named factory when the factory is configured to exchange the federated token for a service-account token. .OUTPUTS System.Object System.Management.Automation.WarningRecord #> function Test-GoogleAccessToken { [CmdletBinding()] param ( [Parameter()] $Factory = $script:GoogleTokenProvider ) process { if($Factory -is [string]) { #name of factory has been passed $Factory = Get-GoogleAuthenticationFactory -Name $GoogleTokenProvider } $Factory.TestAccessToken() } } #endregion Public commands #region Internal commands <# .SYNOPSIS Internal token provider used by the module public commands. .DESCRIPTION `GoogleTokenProvider` encapsulates token acquisition, caching, refresh logic, and token diagnostics for Google APIs. It supports two authentication flows: - `ClientSecret`: Service account JSON private key flow (optionally with user impersonation). - `AadFederated`: Azure AD token exchange with Google STS (optionally followed by service account access token generation). The class is internal to the module and is created by `New-GoogleAuthenticationFactory`. #> class GoogleTokenProvider { [string] $Name [string[]] $Scopes [string] $FlowType hidden $token hidden [PSCustomObject]$Configuration # Initializes provider configuration for service-account JSON authentication. # The JSON must contain `client_email` and `private_key` fields. GoogleTokenProvider([string]$googleAccessJson , [string[]]$scopes, $TargetUserEmail, $Name, $AiLogger = $null) { $this.FlowType = 'ClientSecret' $this.Name = $Name $this.Scopes = $scopes $Credential = ConvertFrom-Json -InputObject $GoogleAccessJson -Depth 10 $this.Configuration = [PSCustomObject]@{ AiLogger = $AiLogger ServiceAccountEmail = $Credential.client_email TargetUserEmail = $TargetUserEmail PrivateKey = $Credential.private_key -replace '-----BEGIN PRIVATE KEY-----\n' -replace '\n-----END PRIVATE KEY-----\n' -replace '\n' } } # Initializes provider configuration for Azure AD federated authentication. # The provider can optionally exchange the federated token for a native # service-account token when ServiceAccountEmail is supplied. GoogleTokenProvider([object]$aadFactory , [string]$workloadIdentityProviderResourceId, [string]$saEmail, [string[]]$scopes, $Name, $AiLogger = $null) { $this.FlowType = 'AadFederated' $this.Name = $Name $this.Scopes = $scopes $this.Configuration = [PSCustomObject]@{ AiLogger = $AiLogger ServiceAccountEmail = $saEmail AadFactory = $aadFactory WorkloadIdentityProviderResourceId = $workloadIdentityProviderResourceId } } # Returns a cached token when valid, otherwise acquires a new one. # Set ForceRefresh to bypass cache and always request a new token. [PSCustomObject]GetAccessToken([bool]$ForceRefresh) { if($null -eq $this.token -or $this.token.expiration_time -lt ([DateTime]::UtcNow) -or $ForceRefresh) { switch($this.FlowType) { 'AadFederated' { $tokenUri = "https://sts.googleapis.com/v1/token" Write-Verbose "Getting Google access token using Azure AD federated credentials" $aadToken = Get-AadToken -factory $this.Configuration.AadFactory $payload = @{ grant_type = "urn:ietf:params:oauth:grant-type:token-exchange" audience = $this.Configuration.WorkloadIdentityProviderResourceId subject_token_type = "urn:ietf:params:oauth:token-type:jwt" subject_token = $aadToken.AccessToken scope = ($this.Scopes -join " ") requested_token_type = 'urn:ietf:params:oauth:token-type:access_token' } Write-Verbose "Calling Google API to get access token: $tokenUri" $this.token = $this.CallGoogleTokenApi($tokenUri, 'POST', $null, ($payload | ConvertTo-Json), "application/json") if(-not [string]::IsNullOrEmpty($this.Configuration.ServiceAccountEmail)) { #try to exchange federated token for native google token Write-Verbose "Exchanging federated token for native Google access token with service account email $($this.Configuration.ServiceAccountEmail)" $tokenUri = "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/$($this.Configuration.ServiceAccountEmail)`:generateAccessToken" $payload = @{ "scope"= $this.Scopes "lifetime"= "3600s" } $headers = @{ Authorization = "$($this.token.token_type) $($this.token.access_token)" } $finaltoken = $this.CallGoogleTokenApi($tokenUri, 'POST', $headers, ($payload | ConvertTo-Json) , "application/json") #token comes in different shape from this endpoint, we need to map it back to the same shape as the original token for caching and later use $this.token.access_token = $finaltoken.accessToken $this.token.expiration_time = $finaltoken.expireTime } break; } 'ClientSecret' { Write-Verbose "Getting Google access token using client secret flow" Write-Verbose "Fetching new access token for Google API" $tokenUri = "https://oauth2.googleapis.com/token" $header = @{ alg = "RS256" typ = "JWT" } $headerBase64 = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(($header | ConvertTo-Json))) $timestamp = [Math]::Round((Get-Date -UFormat %s)) $claimSet = @{ iss = $this.Configuration.ServiceAccountEmail scope = ($this.Scopes -join " ") aud = "https://oauth2.googleapis.com/token" exp = $timestamp + 3600 iat = $timestamp } if(-not [string]::IsNullOrEmpty($this.Configuration.TargetUserEmail)) { $claimSet.sub =$this.Configuration.TargetUserEmail } $claimSetBase64 = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(($claimSet | ConvertTo-Json))) $signatureInput = $headerBase64 + "." + $claimSetBase64 $signatureBytes = [System.Text.Encoding]::UTF8.GetBytes($signatureInput) $privateKeyBytes = [System.Convert]::FromBase64String($this.Configuration.PrivateKey) $rsaProvider = [System.Security.Cryptography.RSA]::Create() $bytesRead = $null $rsaProvider.ImportPkcs8PrivateKey($privateKeyBytes, [ref]$bytesRead) $signature = $rsaProvider.SignData($signatureBytes, [System.Security.Cryptography.HashAlgorithmName]::SHA256, [System.Security.Cryptography.RSASignaturePadding]::Pkcs1) $signatureBase64 = [System.Convert]::ToBase64String($signature) $jwt = $headerBase64 + "." + $claimSetBase64 + "." + $signatureBase64 $body = @{ grant_type = "urn:ietf:params:oauth:grant-type:jwt-bearer" assertion = $jwt } Write-Verbose "Calling Google API to get access token: $tokenUri" $this.token = $this.CallGoogleTokenApi($tokenUri, 'POST', $null, $body, "application/x-www-form-urlencoded") break; } default { throw "Unsupported flow type: $($this.FlowType)" } } } return $this.Token } # Validates the current token by calling Google's tokeninfo endpoint. # Returns token metadata when validation succeeds. [PSCustomObject]TestAccessToken() { if($this.FlowType -eq 'AadFederated' -and [string]::IsNullOrEmpty($this.Configuration.ServiceAccountEmail)) { Write-Warning "Test-GoogleAccessToken is not supported for Federated access tokens" return $null } $t = $this.GetAccessToken($false) $headers = @{ Authorization = "$($t.token_type) $($t.access_token)" } $tokenUri = 'https://www.googleapis.com/oauth2/v3/tokeninfo' Write-Verbose "Calling Google API to test access token: $tokenUri" $requestStart = Get-Date -AsUTC $response = Invoke-WebRequest -Uri $tokenUri -Headers $headers -SkipHttpErrorCheck if($this.AiLogger) { Write-AiDependency -Target 'GoogleAuth' -DependencyType 'HTTP' -Name 'TestAccessToken' ` -Data $tokenUri -Start $requestStart ` -ResultCode $response.StatusCode.ToString() ` -Success ($response.StatusCode -eq [System.Net.HttpStatusCode]::OK) ` -Connection $this.AiLogger } if($response.StatusCode -ne [System.Net.HttpStatusCode]::OK) { $ex = new-object System.Net.Http.HttpRequestException( $response.Content, $null, $response.StatusCode ) throw $ex } return ($response.Content | ConvertFrom-Json) } # Executes token-related HTTP calls and normalizes successful responses # into the module's `Google.AccessToken` shape. hidden [PSCustomObject] CallGoogleTokenApi($uri, $method, $headers, $body, $contentType) { Write-Verbose "Calling Google API: $uri" $requestStart = Get-Date -AsUTC $response = Invoke-WebRequest ` -Uri $uri ` -Method $method ` -Body $body ` -Headers $headers ` -ContentType $contentType ` -SkipHttpErrorCheck if($response.StatusCode -eq [System.Net.HttpStatusCode]::OK) { if($this.AiLogger) { Write-AiDependency -Target 'GoogleAuth' -DependencyType 'HTTP' -Name 'GetAccessToken' -Data $uri -Start $requestStart -ResultCode 'Ok' -Success $true -Connection $this.AiLogger } #when succeeded, response is the token object, we add the expiration_time property to it for easier caching and check later $responseToken = $response.Content | ConvertFrom-Json $responseToken | Add-Member -MemberType NoteProperty -Name expiration_time -Value ([DateTime]::UtcNow.AddSeconds($responseToken.expires_in)) $responseToken.psobject.TypeNames.Insert(0,"Google.AccessToken") return $responseToken } else { if($this.AiLogger) { Write-AiDependency -Target 'GoogleAuth' -DependencyType 'HTTP' -Name 'GetAccessToken' -Data $uri -Start $requestStart -ResultCode $response.StatusCode.ToString() -Success $false -Connection $this.AiLogger } $ex = new-object System.Net.Http.HttpRequestException( $response.Content, $null, $response.StatusCode ) throw $ex } } } #endregion Internal commands #region Module initialization $script:GoogleAuthenticationProviders = @{} #endregion Module initialization # SIG # Begin signature block # MIIuNAYJKoZIhvcNAQcCoIIuJTCCLiECAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAqVQPav0kfGxfj # cB1lPEgbNhTasvl0QXzclKJQzWy+I6CCE2AwggWQMIIDeKADAgECAhAFmxtXno4h # MuI5B72nd3VcMA0GCSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNV # BAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0xMzA4MDExMjAwMDBaFw0z # ODAxMTUxMjAwMDBaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ # bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0 # IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB # AL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsbhA3EMB/z # G6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKyunWZ # anMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGbNOsFxl7s # Wxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclPXuU15zHL # 2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJBMtfb # BHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFPObURWBf3 # JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTvkpI6nj3c # AORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWMcCxBYKqx # YxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5SUUd0 # viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+xq4aL # T8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjQjBAMA8GA1Ud # EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTs1+OC0nFdZEzf # Lmc/57qYrhwPTzANBgkqhkiG9w0BAQwFAAOCAgEAu2HZfalsvhfEkRvDoaIAjeNk # aA9Wz3eucPn9mkqZucl4XAwMX+TmFClWCzZJXURj4K2clhhmGyMNPXnpbWvWVPjS # PMFDQK4dUPVS/JA7u5iZaWvHwaeoaKQn3J35J64whbn2Z006Po9ZOSJTROvIXQPK # 7VB6fWIhCoDIc2bRoAVgX+iltKevqPdtNZx8WorWojiZ83iL9E3SIAveBO6Mm0eB # cg3AFDLvMFkuruBx8lbkapdvklBtlo1oepqyNhR6BvIkuQkRUNcIsbiJeoQjYUIp # 5aPNoiBB19GcZNnqJqGLFNdMGbJQQXE9P01wI4YMStyB0swylIQNCAmXHE/A7msg # dDDS4Dk0EIUhFQEI6FUy3nFJ2SgXUE3mvk3RdazQyvtBuEOlqtPDBURPLDab4vri # RbgjU2wGb2dVf0a1TD9uKFp5JtKkqGKX0h7i7UqLvBv9R0oN32dmfrJbQdA75PQ7 # 9ARj6e/CVABRoIoqyc54zNXqhwQYs86vSYiv85KZtrPmYQ/ShQDnUBrkG5WdGaG5 # nLGbsQAe79APT0JsyQq87kP6OnGlyE0mpTX9iV28hWIdMtKgK1TtmlfB2/oQzxm3 # i0objwG2J5VT6LaJbVu8aNQj6ItRolb58KaAoNYes7wPD1N1KarqE3fk3oyBIa0H # EEcRrYc9B9F1vM/zZn4wggawMIIEmKADAgECAhAIrUCyYNKcTJ9ezam9k67ZMA0G # CSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ # bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0 # IFRydXN0ZWQgUm9vdCBHNDAeFw0yMTA0MjkwMDAwMDBaFw0zNjA0MjgyMzU5NTla # MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE # AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEz # ODQgMjAyMSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDVtC9C # 0CiteLdd1TlZG7GIQvUzjOs9gZdwxbvEhSYwn6SOaNhc9es0JAfhS0/TeEP0F9ce # 2vnS1WcaUk8OoVf8iJnBkcyBAz5NcCRks43iCH00fUyAVxJrQ5qZ8sU7H/Lvy0da # E6ZMswEgJfMQ04uy+wjwiuCdCcBlp/qYgEk1hz1RGeiQIXhFLqGfLOEYwhrMxe6T # SXBCMo/7xuoc82VokaJNTIIRSFJo3hC9FFdd6BgTZcV/sk+FLEikVoQ11vkunKoA # FdE3/hoGlMJ8yOobMubKwvSnowMOdKWvObarYBLj6Na59zHh3K3kGKDYwSNHR7Oh # D26jq22YBoMbt2pnLdK9RBqSEIGPsDsJ18ebMlrC/2pgVItJwZPt4bRc4G/rJvmM # 1bL5OBDm6s6R9b7T+2+TYTRcvJNFKIM2KmYoX7BzzosmJQayg9Rc9hUZTO1i4F4z # 8ujo7AqnsAMrkbI2eb73rQgedaZlzLvjSFDzd5Ea/ttQokbIYViY9XwCFjyDKK05 # huzUtw1T0PhH5nUwjewwk3YUpltLXXRhTT8SkXbev1jLchApQfDVxW0mdmgRQRNY # mtwmKwH0iU1Z23jPgUo+QEdfyYFQc4UQIyFZYIpkVMHMIRroOBl8ZhzNeDhFMJlP # /2NPTLuqDQhTQXxYPUez+rbsjDIJAsxsPAxWEQIDAQABo4IBWTCCAVUwEgYDVR0T # AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUaDfg67Y7+F8Rhvv+YXsIiGX0TkIwHwYD # VR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMG # A1UdJQQMMAoGCCsGAQUFBwMDMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYY # aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2Fj # ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNV # HR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRU # cnVzdGVkUm9vdEc0LmNybDAcBgNVHSAEFTATMAcGBWeBDAEDMAgGBmeBDAEEATAN # BgkqhkiG9w0BAQwFAAOCAgEAOiNEPY0Idu6PvDqZ01bgAhql+Eg08yy25nRm95Ry # sQDKr2wwJxMSnpBEn0v9nqN8JtU3vDpdSG2V1T9J9Ce7FoFFUP2cvbaF4HZ+N3HL # IvdaqpDP9ZNq4+sg0dVQeYiaiorBtr2hSBh+3NiAGhEZGM1hmYFW9snjdufE5Btf # Q/g+lP92OT2e1JnPSt0o618moZVYSNUa/tcnP/2Q0XaG3RywYFzzDaju4ImhvTnh # OE7abrs2nfvlIVNaw8rpavGiPttDuDPITzgUkpn13c5UbdldAhQfQDN8A+KVssIh # dXNSy0bYxDQcoqVLjc1vdjcshT8azibpGL6QB7BDf5WIIIJw8MzK7/0pNVwfiThV # 9zeKiwmhywvpMRr/LhlcOXHhvpynCgbWJme3kuZOX956rEnPLqR0kq3bPKSchh/j # wVYbKyP/j7XqiHtwa+aguv06P0WmxOgWkVKLQcBIhEuWTatEQOON8BUozu3xGFYH # Ki8QxAwIZDwzj64ojDzLj4gLDb879M4ee47vtevLt/B3E+bnKD+sEq6lLyJsQfmC # XBVmzGwOysWGw/YmMwwHS6DTBwJqakAwSEs0qFEgu60bhQjiWQ1tygVQK+pKHJ6l # /aCnHwZ05/LWUpD9r4VIIflXO7ScA+2GRfS0YW6/aOImYIbqyK+p/pQd52MbOoZW # eE4wggcUMIIE/KADAgECAhAP9xCe9qf4ax3LBs7uih/sMA0GCSqGSIb3DQEBCwUA # MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE # AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEz # ODQgMjAyMSBDQTEwHhcNMjMxMTA4MDAwMDAwWhcNMjYxMDAxMjM1OTU5WjCBnDET # MBEGCysGAQQBgjc8AgEDEwJDWjEdMBsGA1UEDwwUUHJpdmF0ZSBPcmdhbml6YXRp # b24xETAPBgNVBAUTCDA0OTIzNjkzMQswCQYDVQQGEwJDWjEOMAwGA1UEBxMFUHJh # aGExGjAYBgNVBAoTEUdyZXlDb3JiZWwgcy5yLm8uMRowGAYDVQQDExFHcmV5Q29y # YmVsIHMuci5vLjCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAJ8t/Qga # dJKtGC7EqH4pmIU73fInH+j1scmVnrJtXL8tGlKzWZ7qlWDWOJBR3owF9CVqL4IX # BGImH8Miowj6RKKqhEe9UtxiH5ipV6msnzAjTFkwqR9vjfEm9vrU1JuXWvAWAfYx # qYg92oyCEBDQxpURpZmqAVSBy9U/ScDwE4NykZGzb0oYSPtzStd8RJvtUkc4126w # YKMbVe/kdY1mDbKO9DLfpbSIj3vghrH6XeHwEb7/jAVYI7Vl+jUyyqfmYHD7FldQ # X2fZfwvoGSibY1uWvvP0/vm0yd6uDbDjCDOTQW8Lxl5wvlXEf5ewn2oaPSoa6ov3 # 1XmnxL5iT8c1LM06JFCwfHS9e0NSyNr86IiKaxQO9/MANrYciTicObtD3cBcSRDO # pEUfhc4TvA5DQZaakSduVJWPdMhxQs9iWeYMOzh5NDTB3xAx8eLBn7Uj++hjI3FQ # WGEPw4Ew6WoDsJShU0HemlDJGTPW9EZSWHGdNFr1BxXEPb4F7DbjJZn33QIDAQAB # o4ICAjCCAf4wHwYDVR0jBBgwFoAUaDfg67Y7+F8Rhvv+YXsIiGX0TkIwHQYDVR0O # BBYEFP2yViJvcgO05qXIH6aJSXB/QcEhMD0GA1UdIAQ2MDQwMgYFZ4EMAQMwKTAn # BggrBgEFBQcCARYbaHR0cDovL3d3dy5kaWdpY2VydC5jb20vQ1BTMA4GA1UdDwEB # /wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzCBtQYDVR0fBIGtMIGqMFOgUaBP # hk1odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2Rl # U2lnbmluZ1JTQTQwOTZTSEEzODQyMDIxQ0ExLmNybDBToFGgT4ZNaHR0cDovL2Ny # bDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0Q29kZVNpZ25pbmdSU0E0 # MDk2U0hBMzg0MjAyMUNBMS5jcmwwgZQGCCsGAQUFBwEBBIGHMIGEMCQGCCsGAQUF # BzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wXAYIKwYBBQUHMAKGUGh0dHA6 # Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNENvZGVTaWdu # aW5nUlNBNDA5NlNIQTM4NDIwMjFDQTEuY3J0MAkGA1UdEwQCMAAwDQYJKoZIhvcN # AQELBQADggIBADCe9Fh40HN9RneCehz5MrBy4O9WYsYCMJ7qJ9DsBT+Hed98UOKB # k/XjgSLfsj5eZRHRmz3HzhGDK1PaRI+yIUVQx96a4qL7adktmrHex3fW39Iq+tPB # rHtiEIp9rwunATeZpk+876u0AXYD1VDRWCtkL8zwZU0oqL6U/mWEIXzkryCB5N3x # xtE54jMmW7MKi1+To4yQcrK3zQ394e2dr50L+aF2fgJ5mo1/YJvzyLLhigbqpoYG # U/gjZonhNJXUaYogpHSTgUaBRlIKZ5xCnrFfJlOsbkhex4QAcdkU6XC+XyYfEQka # 7ERwgxmEoRT3NlZ8/EbrQxJP4S1H8Z29M4D3L6rXNXXmv0IbfA9FQcqEco3Y3tRW # dgdcFEwJmYTo0mCZrYTJHgkKW8xDvQ5BJISAp/ydOX5tSa71ojx1/Kp7qizqjBN/ # W77jdqJ89N1y+N/SOiHOCH9NO5pDLsHpTWW/arvjZT0I8dVYkqK0V39rh95XELI+ # NwBZvV4AsKLirjrkZU3pwCz6O99VmPkBqp9TA5wl13NdTpDHuQ6QyVT7hbC8LF5p # z6x/xO/+tEGxG+1A31UTJPmkxhhUlR+NE3ZXiXhcG72CFHYUUvqwlThPkFYe4Ygf # j9ADmss08k0JhVU5rkbrC2h+549HPlFu/XOSIrps4SXzInjHPEYuBETzMYIaKjCC # GiYCAQEwfTBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4x # QTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgQ29kZSBTaWduaW5nIFJTQTQw # OTYgU0hBMzg0IDIwMjEgQ0ExAhAP9xCe9qf4ax3LBs7uih/sMA0GCWCGSAFlAwQC # AQUAoIGEMBgGCisGAQQBgjcCAQwxCjAIoAKAAKECgAAwGQYJKoZIhvcNAQkDMQwG # CisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZI # hvcNAQkEMSIEIAwDeV/QMOZdpgZmX0TtYKuIbUAujhj0L9kc73dGtHdvMA0GCSqG # SIb3DQEBAQUABIIBgAqgVlWEI9PsHfD2d+k7f9ibNUvG4vWe02N431NMiFqn503T # iQ5DxP8oE7KoGNqTdX6XjP9yQt1t/fNksB46zGYqmME+wOMyUWXs1kt1xHvguWjx # PHlaTPG05QtbYfOa/KxsRVrCzERmXaoGH2iKI5Xc6DiJDLkWqPpdlHQdyXIvGpQ3 # PeeeRxgahmHUnHd6F8xghz9FVVCHzEjoo+RUo/CqJ6iEPKyAKutoEUujkanFUhwc # P5YOZS3QCKb59aJQ79viTOc7ygwAjFXyt7699OhCT0KSeTnSWcufyFjQeaFB/xXW # +ARI8wfbV1GNvgkW3AijdbCE/EcRRr9OafW8ZU/Dl9Bm0xJdb35dnejvzMJWOiiN # gU5nrLP6MVdD3rF8Bz8p+BQMDQBSQtjqEwltol8S65FnzUVQOL2T82srCmThfiJ4 # 7eM9US9GHqaYd2c7X8alVCUQUfkgPJnGzz4DOrW1PvjcUIKa7VYnHsUeHtbVR98I # 712SgXaujcR8nm8iLaGCF3cwghdzBgorBgEEAYI3AwMBMYIXYzCCF18GCSqGSIb3 # DQEHAqCCF1AwghdMAgEDMQ8wDQYJYIZIAWUDBAIBBQAweAYLKoZIhvcNAQkQAQSg # aQRnMGUCAQEGCWCGSAGG/WwHATAxMA0GCWCGSAFlAwQCAQUABCD2fZXoKeAwfCse # 1Igs+AFzfDK54MXf57Iq3XewtZE+gwIRAKDmFR/O6ilosHVRmOVGYvAYDzIwMjYw # NDA1MjMwMDI3WqCCEzowggbtMIIE1aADAgECAhAKgO8YS43xBYLRxHanlXRoMA0G # CSqGSIb3DQEBCwUAMGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwg # SW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBUaW1lU3RhbXBpbmcg # UlNBNDA5NiBTSEEyNTYgMjAyNSBDQTEwHhcNMjUwNjA0MDAwMDAwWhcNMzYwOTAz # MjM1OTU5WjBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4x # OzA5BgNVBAMTMkRpZ2lDZXJ0IFNIQTI1NiBSU0E0MDk2IFRpbWVzdGFtcCBSZXNw # b25kZXIgMjAyNSAxMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0Eas # LRLGntDqrmBWsytXum9R/4ZwCgHfyjfMGUIwYzKomd8U1nH7C8Dr0cVMF3BsfAFI # 54um8+dnxk36+jx0Tb+k+87H9WPxNyFPJIDZHhAqlUPt281mHrBbZHqRK71Em3/h # CGC5KyyneqiZ7syvFXJ9A72wzHpkBaMUNg7MOLxI6E9RaUueHTQKWXymOtRwJXcr # cTTPPT2V1D/+cFllESviH8YjoPFvZSjKs3SKO1QNUdFd2adw44wDcKgH+JRJE5Qg # 0NP3yiSyi5MxgU6cehGHr7zou1znOM8odbkqoK+lJ25LCHBSai25CFyD23DZgPfD # rJJJK77epTwMP6eKA0kWa3osAe8fcpK40uhktzUd/Yk0xUvhDU6lvJukx7jphx40 # DQt82yepyekl4i0r8OEps/FNO4ahfvAk12hE5FVs9HVVWcO5J4dVmVzix4A77p3a # wLbr89A90/nWGjXMGn7FQhmSlIUDy9Z2hSgctaepZTd0ILIUbWuhKuAeNIeWrzHK # YueMJtItnj2Q+aTyLLKLM0MheP/9w6CtjuuVHJOVoIJ/DtpJRE7Ce7vMRHoRon4C # WIvuiNN1Lk9Y+xZ66lazs2kKFSTnnkrT3pXWETTJkhd76CIDBbTRofOsNyEhzZtC # GmnQigpFHti58CSmvEyJcAlDVcKacJ+A9/z7eacCAwEAAaOCAZUwggGRMAwGA1Ud # EwEB/wQCMAAwHQYDVR0OBBYEFOQ7/PIx7f391/ORcWMZUEPPYYzoMB8GA1UdIwQY # MBaAFO9vU0rp5AZ8esrikFb2L9RJ7MtOMA4GA1UdDwEB/wQEAwIHgDAWBgNVHSUB # Af8EDDAKBggrBgEFBQcDCDCBlQYIKwYBBQUHAQEEgYgwgYUwJAYIKwYBBQUHMAGG # GGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBdBggrBgEFBQcwAoZRaHR0cDovL2Nh # Y2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0VGltZVN0YW1waW5n # UlNBNDA5NlNIQTI1NjIwMjVDQTEuY3J0MF8GA1UdHwRYMFYwVKBSoFCGTmh0dHA6 # Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFRpbWVTdGFtcGlu # Z1JTQTQwOTZTSEEyNTYyMDI1Q0ExLmNybDAgBgNVHSAEGTAXMAgGBmeBDAEEAjAL # BglghkgBhv1sBwEwDQYJKoZIhvcNAQELBQADggIBAGUqrfEcJwS5rmBB7NEIRJ5j # QHIh+OT2Ik/bNYulCrVvhREafBYF0RkP2AGr181o2YWPoSHz9iZEN/FPsLSTwVQW # o2H62yGBvg7ouCODwrx6ULj6hYKqdT8wv2UV+Kbz/3ImZlJ7YXwBD9R0oU62Ptgx # Oao872bOySCILdBghQ/ZLcdC8cbUUO75ZSpbh1oipOhcUT8lD8QAGB9lctZTTOJM # 3pHfKBAEcxQFoHlt2s9sXoxFizTeHihsQyfFg5fxUFEp7W42fNBVN4ueLaceRf9C # q9ec1v5iQMWTFQa0xNqItH3CPFTG7aEQJmmrJTV3Qhtfparz+BW60OiMEgV5GWoB # y4RVPRwqxv7Mk0Sy4QHs7v9y69NBqycz0BZwhB9WOfOu/CIJnzkQTwtSSpGGhLdj # nQ4eBpjtP+XB3pQCtv4E5UCSDag6+iX8MmB10nfldPF9SVD7weCC3yXZi/uuhqdw # kgVxuiMFzGVFwYbQsiGnoa9F5AaAyBjFBtXVLcKtapnMG3VH3EmAp/jsJ3FVF3+d # 1SVDTmjFjLbNFZUWMXuZyvgLfgyPehwJVxwC+UpX2MSey2ueIu9THFVkT+um1vsh # ETaWyQo8gmBto/m3acaP9QsuLj3FNwFlTxq25+T4QwX9xa6ILs84ZPvmpovq90K8 # eWyG2N01c4IhSOxqt81nMIIGtDCCBJygAwIBAgIQDcesVwX/IZkuQEMiDDpJhjAN # BgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQg # SW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2Vy # dCBUcnVzdGVkIFJvb3QgRzQwHhcNMjUwNTA3MDAwMDAwWhcNMzgwMTE0MjM1OTU5 # WjBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNV # BAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgVGltZVN0YW1waW5nIFJTQTQwOTYgU0hB # MjU2IDIwMjUgQ0ExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtHgx # 0wqYQXK+PEbAHKx126NGaHS0URedTa2NDZS1mZaDLFTtQ2oRjzUXMmxCqvkbsDpz # 4aH+qbxeLho8I6jY3xL1IusLopuW2qftJYJaDNs1+JH7Z+QdSKWM06qchUP+AbdJ # gMQB3h2DZ0Mal5kYp77jYMVQXSZH++0trj6Ao+xh/AS7sQRuQL37QXbDhAktVJMQ # bzIBHYJBYgzWIjk8eDrYhXDEpKk7RdoX0M980EpLtlrNyHw0Xm+nt5pnYJU3Gmq6 # bNMI1I7Gb5IBZK4ivbVCiZv7PNBYqHEpNVWC2ZQ8BbfnFRQVESYOszFI2Wv82wnJ # RfN20VRS3hpLgIR4hjzL0hpoYGk81coWJ+KdPvMvaB0WkE/2qHxJ0ucS638ZxqU1 # 4lDnki7CcoKCz6eum5A19WZQHkqUJfdkDjHkccpL6uoG8pbF0LJAQQZxst7VvwDD # jAmSFTUms+wV/FbWBqi7fTJnjq3hj0XbQcd8hjj/q8d6ylgxCZSKi17yVp2NL+cn # T6Toy+rN+nM8M7LnLqCrO2JP3oW//1sfuZDKiDEb1AQ8es9Xr/u6bDTnYCTKIsDq # 1BtmXUqEG1NqzJKS4kOmxkYp2WyODi7vQTCBZtVFJfVZ3j7OgWmnhFr4yUozZtqg # PrHRVHhGNKlYzyjlroPxul+bgIspzOwbtmsgY1MCAwEAAaOCAV0wggFZMBIGA1Ud # EwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFO9vU0rp5AZ8esrikFb2L9RJ7MtOMB8G # A1UdIwQYMBaAFOzX44LScV1kTN8uZz/nupiuHA9PMA4GA1UdDwEB/wQEAwIBhjAT # BgNVHSUEDDAKBggrBgEFBQcDCDB3BggrBgEFBQcBAQRrMGkwJAYIKwYBBQUHMAGG # GGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggrBgEFBQcwAoY1aHR0cDovL2Nh # Y2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcnQwQwYD # VR0fBDwwOjA4oDagNIYyaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # VHJ1c3RlZFJvb3RHNC5jcmwwIAYDVR0gBBkwFzAIBgZngQwBBAIwCwYJYIZIAYb9 # bAcBMA0GCSqGSIb3DQEBCwUAA4ICAQAXzvsWgBz+Bz0RdnEwvb4LyLU0pn/N0IfF # iBowf0/Dm1wGc/Do7oVMY2mhXZXjDNJQa8j00DNqhCT3t+s8G0iP5kvN2n7Jd2E4 # /iEIUBO41P5F448rSYJ59Ib61eoalhnd6ywFLerycvZTAz40y8S4F3/a+Z1jEMK/ # DMm/axFSgoR8n6c3nuZB9BfBwAQYK9FHaoq2e26MHvVY9gCDA/JYsq7pGdogP8HR # trYfctSLANEBfHU16r3J05qX3kId+ZOczgj5kjatVB+NdADVZKON/gnZruMvNYY2 # o1f4MXRJDMdTSlOLh0HCn2cQLwQCqjFbqrXuvTPSegOOzr4EWj7PtspIHBldNE2K # 9i697cvaiIo2p61Ed2p8xMJb82Yosn0z4y25xUbI7GIN/TpVfHIqQ6Ku/qjTY6hc # 3hsXMrS+U0yy+GWqAXam4ToWd2UQ1KYT70kZjE4YtL8Pbzg0c1ugMZyZZd/BdHLi # Ru7hAWE6bTEm4XYRkA6Tl4KSFLFk43esaUeqGkH/wyW4N7OigizwJWeukcyIPbAv # jSabnf7+Pu0VrFgoiovRDiyx3zEdmcif/sYQsfch28bZeUz2rtY/9TCA6TD8dC3J # E3rYkrhLULy7Dc90G6e8BlqmyIjlgp2+VqsS9/wQD7yFylIz0scmbKvFoW2jNrbM # 1pD2T7m3XDCCBY0wggR1oAMCAQICEA6bGI750C3n79tQ4ghAGFowDQYJKoZIhvcN # AQEMBQAwZTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcG # A1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEkMCIGA1UEAxMbRGlnaUNlcnQgQXNzdXJl # ZCBJRCBSb290IENBMB4XDTIyMDgwMTAwMDAwMFoXDTMxMTEwOTIzNTk1OVowYjEL # MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 # LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgVHJ1c3RlZCBSb290IEc0 # MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAv+aQc2jeu+RdSjwwIjBp # M+zCpyUuySE98orYWcLhKac9WKt2ms2uexuEDcQwH/MbpDgW61bGl20dq7J58soR # 0uRf1gU8Ug9SH8aeFaV+vp+pVxZZVXKvaJNwwrK6dZlqczKU0RBEEC7fgvMHhOZ0 # O21x4i0MG+4g1ckgHWMpLc7sXk7Ik/ghYZs06wXGXuxbGrzryc/NrDRAX7F6Zu53 # yEioZldXn1RYjgwrt0+nMNlW7sp7XeOtyU9e5TXnMcvak17cjo+A2raRmECQecN4 # x7axxLVqGDgDEI3Y1DekLgV9iPWCPhCRcKtVgkEy19sEcypukQF8IUzUvK4bA3Vd # eGbZOjFEmjNAvwjXWkmkwuapoGfdpCe8oU85tRFYF/ckXEaPZPfBaYh2mHY9WV1C # doeJl2l6SPDgohIbZpp0yt5LHucOY67m1O+SkjqePdwA5EUlibaaRBkrfsCUtNJh # besz2cXfSwQAzH0clcOP9yGyshG3u3/y1YxwLEFgqrFjGESVGnZifvaAsPvoZKYz # 0YkH4b235kOkGLimdwHhD5QMIR2yVCkliWzlDlJRR3S+Jqy2QXXeeqxfjT/JvNNB # ERJb5RBQ6zHFynIWIgnffEx1P2PsIV/EIFFrb7GrhotPwtZFX50g/KEexcCPorF+ # CiaZ9eRpL5gdLfXZqbId5RsCAwEAAaOCATowggE2MA8GA1UdEwEB/wQFMAMBAf8w # HQYDVR0OBBYEFOzX44LScV1kTN8uZz/nupiuHA9PMB8GA1UdIwQYMBaAFEXroq/0 # ksuCMS1Ri6enIZ3zbcgPMA4GA1UdDwEB/wQEAwIBhjB5BggrBgEFBQcBAQRtMGsw # JAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcw # AoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElE # Um9vdENBLmNydDBFBgNVHR8EPjA8MDqgOKA2hjRodHRwOi8vY3JsMy5kaWdpY2Vy # dC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMBEGA1UdIAQKMAgwBgYE # VR0gADANBgkqhkiG9w0BAQwFAAOCAQEAcKC/Q1xV5zhfoKN0Gz22Ftf3v1cHvZqs # oYcs7IVeqRq7IviHGmlUIu2kiHdtvRoU9BNKei8ttzjv9P+Aufih9/Jy3iS8UgPI # TtAq3votVs/59PesMHqai7Je1M/RQ0SbQyHrlnKhSLSZy51PpwYDE3cnRNTnf+hZ # qPC/Lwum6fI0POz3A8eHqNJMQBk1RmppVLC4oVaO7KTVPeix3P0c2PR3WlxUjG/v # oVA9/HYJaISfb8rbII01YBwCA8sgsKxYoA5AY8WYIsGyWfVVa88nq2x2zm8jLfR+ # cWojayL/ErhULSd+2DrZ8LaHlv1b0VysGMNNn3O3AamfV6peKOK5lDGCA3wwggN4 # AgEBMH0waTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMUEw # PwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IFRpbWVTdGFtcGluZyBSU0E0MDk2 # IFNIQTI1NiAyMDI1IENBMQIQCoDvGEuN8QWC0cR2p5V0aDANBglghkgBZQMEAgEF # AKCB0TAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwHAYJKoZIhvcNAQkFMQ8X # DTI2MDQwNTIzMDAyN1owKwYLKoZIhvcNAQkQAgwxHDAaMBgwFgQU3WIwrIYKLTBr # 2jixaHlSMAf7QX4wLwYJKoZIhvcNAQkEMSIEIPFXwYjoRLxfDoc3wX9nh+uy+8Cp # urjqVPND31InTLNJMDcGCyqGSIb3DQEJEAIvMSgwJjAkMCIEIEqgP6Is11yExVyT # j4KOZ2ucrsqzP+NtJpqjNPFGEQozMA0GCSqGSIb3DQEBAQUABIICAEaQfSXv1H1F # XwOqPF5CI5uPI4rCniaaLj/Ax/ViIpOXBgLJOsdruqQ78EfzdjN/oXxc46bL1gSs # HEvEuLeXK9Fdjg/iTPY7Mkwkhg22MXH1Y8VZK8ohpJHWnCCgUJ9igh+tcEY603p9 # bX+1K3DI0/sOh1wjftZlnb4gbiytPOdeA+5VzzyuQ9jPQcgOPwLEYnlka4/SUpLt # LuZlssSGp91jsPZ5VggR0Tm25gV0oj6QrGtAn+uYF9zcTT34iWfuEPUO4bu5GtyQ # DxvTQxqvLTvONxzSiD5AH7rvr0ZaVHxGuZZlZ7JUHZzk4A7XAcEQdXZZFy/gwmLy # virhmpA/J30LlvTC4fSDXZPXywLS7u3QOyz+V35QGISoqc/AJeSF9XuxrPtArHoE # c6u0f05Q2ymxPw0Ou+NViNe+daLqOfrbJM6rNEIWlOryaOMtUFST84lnJwIRzsy/ # cuYac/T9BlmxsUVYK/Xx+622uIAZrX7ZME4HcCbm3DcpHI3INinJF6A/nVOwQjmi # wBJXC9AfV1KXr4/yZxIRUaS5gP/DYBnJp3BfazIqA+Aqm3tSbq/H3ouzo2iW5zM9 # rsYtbWH6hdzBOaCklAGgyJo4twGBeJnl0Yumg1rkgy19xh6wa6lT/PSRnRiusCrV # Z4vP2hFkMBf7O8CS7lSDf0GW2LoAbAR5 # SIG # End signature block |