Obs/bin/ObsDep/content/Powershell/Roles/Common/DscHelper.psm1
<###################################################
# # # Copyright (c) Microsoft. All rights reserved. # # # ##################################################> Import-Module -ErrorAction Stop -Name "$PSScriptRoot\..\..\Common\Helpers.psm1" -DisableNameChecking -Verbose:$false | Out-Null Import-Module -ErrorAction Stop -Name "$PSScriptRoot\RoleHelpers.psm1" -DisableNameChecking -Verbose:$false | Out-Null # This certificate is used for encyrpting credentials passed in a DSC MOF. function GetDscEncryptionCert { $ErrorActionPreference = 'Stop' # If the cert exists, return it. If not, create it and then return it. $cert = Get-ChildItem Cert:\LocalMachine\My | % {if ($_.Subject -like '*DscEncryptionCert*') {$_}} if (!$cert) { $cert = New-SelfSignedCertificate -Type DocumentEncryptionCertLegacyCsp -DnsName 'DscEncryptionCert' -HashAlgorithm SHA256 -CertStoreLocation "Cert:\LocalMachine\My" -KeyLength '4096' } return $cert } # This certificate is used for signing DSC MOFs. Security best practices (and, indeed, the # certificate management infrastructure) insist that you use different certificates for # encryption and signing. function GetDscSigningCert { $ErrorActionPreference = 'Stop' # If the cert exists, return it. If not, create it and then return it. $cert = Get-ChildItem Cert:\LocalMachine\My | % {if ($_.Subject -like '*DscSigningCert*') {$_}} if (!$cert) { $cert = New-SelfSignedCertificate -Type CodeSigningCert -DnsName 'DscSigningCert' -HashAlgorithm SHA256 -KeyLength '4096' } return $cert } <# This function exports the DSC Encryption and signing certificates, as PFX files with the private keys. This is necessary because the DSC engine insists that the private key be on the target node, with the public key used for encryption or signing. The assumption is that this will be generated on the target node and then the cert will be sent back to the machine generating the target state MOFs. This would be fine, except that we need to use the MOFs we're generating before the machines running DSC connect to a network. So we're generating the cert in the DVM or the Seed Ring, and then writing it into the image that will then boot later. To do this, we need to encrypt the PFX file using a password. We can't use AD to deliver the secret, again because the target node won't have connected to a network before this is used. This function writes the relatively random string used as the password. We delete both the PFX files and the password used before the images attach to a network, but just to be sure that there is no attack path, we use a different password for every deployment, P&U cycle, scale-out, etc. #> function ExportDscDecryptionCert { param ( [Parameter(Mandatory)] [string] $DestinationPath ) $ErrorActionPreference = 'Stop' $certPassword = [String]::Empty 1..16 | % {$certPassword += ([char](get-random -Minimum 33 -Maximum 126))} $certSecurePassword = ConvertTo-SecureString -String $certPassword -AsPlainText -Force $destinationFile = Join-Path -Path $DestinationPath -ChildPath DscCertPassword.txt $certPassword | Set-Content -Path $destinationFile -Force $cert = GetDscEncryptionCert Write-Verbose -Verbose "Exporting DSC Encryption Certificate with Private key to $DestinationPath" $destinationFile = Join-Path -Path $DestinationPath -ChildPath DscEncryption.pfx Export-PfxCertificate -Cert $cert -FilePath $destinationFile -Password $certSecurePassword -Force $cert = GetDscSigningCert Write-Verbose -Verbose "Exporting DSC Signing Certificate with Private key to $DestinationPath" $destinationFile = Join-Path -Path $DestinationPath -ChildPath DscSigning.pfx Export-PfxCertificate -Cert $cert -FilePath $destinationFile -Password $certSecurePassword -Force } function RemoveExportedDscDecryptionCert { param ( [Parameter(Mandatory)] [string] $Path ) $ErrorActionPreference = "Stop" Remove-Item -Path "$Path\DscCertPassword.txt" -Force -ErrorAction SilentlyContinue Remove-Item -Path "$Path\DscEncryption.pfx" -Force -ErrorAction SilentlyContinue Remove-Item -Path "$Path\DscSigning.pfx" -Force -ErrorAction SilentlyContinue } # This function signs a Configuration which is expressed as a MOF. function SignDscConfiguration { param ( [Parameter(Mandatory)] [string] $MofPath ) $ErrorActionPreference = 'Stop' Write-Verbose -Verbose "Signing $MofPath" $dscSigningCert = GetDscSigningCert $null = Set-AuthenticodeSignature -Certificate $dscSigningCert ` -HashAlgorithm SHA256 ` -FilePath $MofPath ` -Force } # This function returns a password, encrypted with the DSC Encryption key function GetEncryptedPassword { param ( [Parameter(Mandatory)] [pscredential] $Credential ) $ErrorActionPreference = 'Stop' $cleartext = $Credential.GetNetworkCredential().Password $cleartext | Protect-CmsMessage -To "CN=DscEncryptionCert" } # This function builds the right files in an image to finish a DSC configuration # when the machine boots for the first time. function PrepareDSCFirstBoot { param ( [Parameter(Mandatory)] [System.String] $MountPath, [Parameter(Mandatory = $false)] [psobject[]] $PartialConfigList, [switch] $WaitForTimeSyncBeforeDSC ) $ErrorActionPreference = "Stop" # Install a SetupComplete.cmd which will force DSC to resolve secondary partial configurations. $setupDir = Join-Path -Path $MountPath -ChildPath "Windows\Setup" New-Item -Path $setupDir -ItemType Directory -Force $scriptsDir = Join-Path -Path $setupDir -ChildPath Scripts New-Item -Path $scriptsDir -ItemType Directory -Force Write-Verbose -Verbose "Placing SetupComplete.cmd in $scriptsDir" Copy-Item -Path (Join-Path -Path "$PSScriptRoot\..\Common" -ChildPath SetupComplete.cmd) ` -Destination (Join-Path -Path $scriptsDir -ChildPath SetupComplete.cmd) ` -Force # Make a directory full of stuff necessary for applying all the DSC partial configs. $dscDirectory = Join-Path -Path $MountPath -ChildPath DSCConfigs New-Item -Path $dscDirectory -ItemType Directory -Force Write-Verbose -Verbose "Placing DSC collateral in $dscDirectory" Copy-Item -Path $PSScriptRoot\..\Common\CompleteBootDSC.ps1 -Destination $dscDirectory -Force Copy-Item -Path $PSScriptRoot\..\Common\DscMetaconfig.psm1 -Destination $dscDirectory -Force if ($WaitForTimeSyncBeforeDSC) { Copy-Item -Path $PSScriptRoot\..\Common\WaitForTimeSyncBeforeDSC.ps1 -Destination $dscDirectory -Force } # Get the DSC Encryption Cert and place it in the image. ExportDscDecryptionCert -DestinationPath $dscDirectory if ($PSBoundParameters.ContainsKey('PartialConfigList')) { # Write the partial config list where the machine will find it. $partialConfigListFile = Join-Path -Path $dscDirectory -ChildPath DscPartialConfigList.xml Write-Verbose -Verbose "Writing list of $($partialConfigList.Count) partial configs into $partialConfigListFile" $xmlString = "<PartialConfigurations>" foreach($partialConfig in $PartialConfigList) { $xmlString += "<PartialConfiguration Name=`"$($partialConfig.Name)`" Phase=`"$($partialConfig.Phase)`" />" } $xmlString += "</PartialConfigurations>" $xmlString | Set-Content -Path $partialConfigListFile -Force } } # Helper function to write a DSC status configuration file. This file will be used to find out where the # status file will be written. The status file and its contents help deployment/update determine if DSC configuration is complete # on a remote machine. function Add-DSCStatusConfigFile { param( [Parameter(Mandatory=$True)] [string] $Version, [Parameter(Mandatory=$True)] [string] $DSCStatusConfigFolder ) $ErrorActionPreference = "Stop" Write-Verbose "Injecting DSC status configuration file in $DSCStatusConfigFolder" $configString = @" <Configuration> <TargetShares> <TargetShare PrimaryPath="C:\CompleteBootDSCStatus" /> </TargetShares> <Version>$Version</Version> </Configuration> "@ if((Test-Path -Path $DSCStatusConfigFolder) -eq $false) { $null = New-Item -Path $DSCStatusConfigFolder -ItemType Directory -Force } $configFilePath = Join-Path -Path $DSCStatusConfigFolder -ChildPath "CompleteBootDscStatusConfig.xml" $configString | Out-File $configFilePath -Force } <# .Synopsis Function to wait for ping, CIM, recent OS installation (with a deployment artifact) and WinRM to be available on a machine .Parameter StartTime The start time of the operation, used to check that OS boot time was strictly after the wait period. .Parameter StopTime The stop time for the wait operation after which the operation is considered failed. .Parameter NodeArray A list of physical/Virtual machine nodes to wait. .Parameter Version Current version being deployed or the version to which the stamp is being updated .Parameter DSCStatusFolder Folder where the DSC completion status will be written .Parameter TargetNodeNotInDomain Indicates that the target node is not domain-joined, so we cannot check its DSC status file using the default mechanism of admin SMB share path (\\node\C$\CompleteBootDSCStatus\node.version.xml). #> function Wait-ForDSCComplete { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [DateTime] $StartTime, [Parameter(Mandatory=$true)] [DateTime] $StopTime, [Parameter(Mandatory=$true)] [string[]] $NodeArray, [Parameter(Mandatory=$true)] [string] $Version, [Parameter(Mandatory=$false)] [string] $DSCStatusFolder = "C:\CompleteBootDSCStatus", [Parameter(Mandatory=$false)] [bool] $TargetNodeNotInDomain = $false, [Parameter(Mandatory=$false)] [pscredential] $Credential ) $ErrorActionPreference = "Stop" $remainingNodes = $NodeArray $failedNodes = [System.Collections.Generic.Dictionary[string, string[]]]::new() do { foreach ($node in $NodeArray) { $dscStatusFileName = $node + "." + $Version + ".xml" $dscStatusFilePath = Join-Path -Path $DSCStatusFolder -ChildPath $dscStatusFileName $remoteDscStatusFilePath = Join-Path -Path "\\$node" -ChildPath ($dscStatusFilePath.Replace(":","$")) # Check if the SetupComplete is still processing. # If the DSC status file exists for this specific version, then skip and move on to the next node $statusFilePresent = $false $statusFilePresentOnHost = $false # In case of VMs where AD is not set up, the status file is accessed via remote session with explicit credentials. # For example this will be applicable to DC VM on one node. if($TargetNodeNotInDomain) { Trace-Execution "Testing for presence of $dscStatusFilePath on $env:COMPUTERNAME" $statusFilePresentOnHost = Test-Path -Path $dscStatusFilePath $statusFilePresent = $statusFilePresentOnHost if(-not $statusFilePresent) { Trace-Execution "Testing for presence of $dscStatusFilePath on $node" try { $currentVM = Get-VM -Name $node -ComputerName $env:COMPUTERNAME if($currentVM.State -eq "Running") { $statusFilePresent = Invoke-Command -VMName $node -Credential $Credential -ScriptBlock { Test-Path -Path $using:dscStatusFilePath } -ErrorAction Stop } } catch { Trace-Warning "Failed to get the DSC Status file from: $node. Reporting this as a warning as the node might not be up. Failure details: $_" } } } else { try { $remoteDscStatusFilePathParent = Split-Path $remoteDscStatusFilePath -Parent Trace-Execution "Creating PS drive 'DscStatusFileTempPSDrive' with root $remoteDscStatusFilePathParent and user $($Credential.UserName)." New-PSDrive -Name DscStatusFileTempPSDrive -PSProvider FileSystem -Root $remoteDscStatusFilePathParent -Credential $Credential -ErrorAction Stop } catch { Trace-Warning "Could not create PS drive 'DscStatusFileTempPSDrive' with root '$remoteDscStatusFilePathParent'. Failure details: $_" } $StatusFile = Get-ChildItem -Path $remoteDscStatusFilePathParent -ErrorAction Ignore if($StatusFile) { $statusFilePresent = $true } else { $statusFilePresent = $false } } # If status file is not present, keep loopin, else read the contents of the file if (!$statusFilePresent) { Trace-Execution "$node is still being deployed. It will be reachable once OS deployment is complete and execution of SetupComplete script has ended." } else { $statusXml = $null # If the file exists, check the status in the file # If the completed file was previously copied on to the host, read the status from there. # Avoid going over PSDirect as the local admin account might have been disabled. if($TargetNodeNotInDomain) { $statusXml = [xml] ( Invoke-Command -VMName $node -ScriptBlock { Get-Content -Path $using:dscStatusFilePath } -Credential $Credential) } else { $statusfileName = Get-ChildItem -Path $remoteDscStatusFilePathParent $statusXml = [xml] ( Get-Content -Path $statusfileName.FullName ) } $status = $statusXml.DeploymentDSC.Status if($status -eq "Started") { Trace-Execution "$node has finished OS deployment, but is still processing SetupComplete." } elseif(($status -eq "Completed") -or ($status -eq 'Failed')) { Trace-Execution "$node has finished SetupComplete with status: $status" # Create copy of the file locally. This is to avoid reaching out to the VM again in case of consistency check if($TargetNodeNotInDomain) { Trace-Execution "Creating copy of the file locally" New-Item -Type Directory -Path (Split-Path $dscStatusFilePath) -Force | Out-Null $statusXml.InnerXml | Out-File $dscStatusFilePath -Force } $remainingNodes = $remainingNodes -ne $node if ($status -eq 'Failed') { if ($null -eq $statusXml.DeploymentDSC.ResourcesNotInDesiredState.ResourceId) { Trace-Error "DSC failed to converge on $node, but no additional details were found in the status XML. Check C:\Windows\SetupComplete.log on $node to determine whether DSC was configured and started properly." } $failedNodes[$node] = $statusXml.DeploymentDSC.ResourcesNotInDesiredState.ResourceId } } else { Trace-Execution "Unknown status reported for $node . The expected values are Started, Completed and Failed. Value reported was: $status" } } Trace-Execution "Removing PS drive 'DscStatusFileTempPSDrive'." Get-PSDrive -Name DscStatusFileTempPSDrive -ErrorAction SilentlyContinue | Remove-PSDrive } if (-not $remainingNodes) { break } $NodeArray = $remainingNodes Start-Sleep -Seconds 30 } until ([DateTime]::Now -gt $StopTime) if ($failedNodes.Count -ne 0) { $stringBuilder = [System.Text.StringBuilder]::new("DSC failed to converge on one or more nodes.") foreach ($node in $failedNodes.Keys) { $stringBuilder.AppendLine("Resources not in desired state on ${node}: " + [string]::Join((", ", $failedNodes[$node]))) } Trace-Error $stringBuilder.ToString() } $totalBmdWaitTimeMinutes = [int]($StopTime - $StartTime).TotalMinutes if ($remainingNodes) { Trace-Error "Deployment failed to complete in $totalBmdWaitTimeMinutes minutes - $(($remainingNodes) -join ',') ." } else { $nodesString = $NodeArray -join "," Trace-Execution "Deployment has completed on all nodes: $nodesString" } } # Tests if DSC has completed and completed status has been written on at least one of the orchestrators. function Test-ForDSCComplete { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [pscredential] $Credential, [Parameter(Mandatory=$true)] [string] $NodeName, [Parameter(Mandatory=$true)] [string] $Version, [Parameter(Mandatory=$false)] [string] $DSCStatusFolder = "C:\CompleteBootDSCStatus" ) $statusFilePresent = $false $dscStatusFileName = $NodeName + "." + $Version + ".xml" $dscStatusFilePath = Join-Path -Path $DSCStatusFolder -ChildPath $dscStatusFileName $remoteDscStatusFilePath = Join-Path -Path "\\$NodeName" -ChildPath ($dscStatusFilePath.Replace(":","$")) Trace-Execution "DSC status file path on node: $remoteDscStatusFilePath" $statusFilePresent = Test-Path -Path $remoteDscStatusFilePath -ErrorAction Ignore try { if ($statusFilePresent) { $statusXml = [xml] ( Get-Content -Path $remoteDscStatusFilePath ) $status = $statusXml.DeploymentDSC.Status if ($status -eq "Completed") { Trace-Execution "Status for the node was set to Completed. The node was already created with expected version hence returning True." return $true } } } catch { Trace-Execution "Encountered an exception reading status file from path: $remoteDscStatusFilePath. Exception: $_" } return $false } <# .Synopsis Revoke access to the CompleteBootDSCShare .Parameter ComputerName The computer that is to be granted access. .Parameter DomainAdminCredentials Credentials for the domain admin #> function Revoke-CompleteBootDSCShareAccess { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string[]] $ComputerName, [Parameter(Mandatory = $true)] [CloudEngine.Configurations.EceInterfaceParameters] $Parameters ) $cloudRole = $Parameters.Roles["Cloud"].PublicConfiguration $securityInfo = $cloudRole.PublicInfo.SecurityInfo $domainAdminUser = $securityInfo.DomainUsers.User | Where-Object Role -EQ "DomainAdmin" $domainAdminCredential = $Parameters.GetCredential($domainAdminUser.Credential) Start-ParallelWorkAndWait -ComputerName $ComputerName -Credential $domainAdminCredential -ScriptBlock { $DSCStatusFileShareAccessRules = Get-SmbShareAccess -Name "CompleteBootDSCStatus" foreach($DSCStatusFileShareAccessRule in $DSCStatusFileShareAccessRules) { $accessPermission = $DSCStatusFileShareAccessRule.AccessRight if ($accessPermission -eq "Change" -or $accessPermission -eq "Read" -or $accessPermission -eq "Full") { Revoke-SmbShareAccess -Name $DSCStatusFileShareAccessRule.Name -AccountName $DSCStatusFileShareAccessRule.AccountName -Force } } } } <# .Synopsis Remove the DSC status file for a specific computer with a specific build installed .Parameter ComputerName The computer that is to be removed the DSC status file. .Parameter Version The build version #> function Remove-DSCStatusFile { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string] $ComputerName, [Parameter(Mandatory=$true)] [string] $Version ) $ErrorActionPreference = "Stop" $dscStatusFileName = $ComputerName + "." + $Version + ".xml" $remoteDscStatusFilePath = "\\$ComputerName\C$\CompleteBootDSCStatus\$dscStatusFileName" try { if(Test-Path $remoteDscStatusFilePath -ErrorAction Ignore) { Remove-Item -Path $remoteDscStatusFilePath -Force -Confirm:$false } } catch { Trace-Warning "Could not remove $remoteDscStatusFilePath. Error: $_" } } <# .SYNOPSIS Reset partial configurations on all nodes to clean up any stale references to Script resources in existing configurations. #> function Reset-PartialConfigurationsOnNode { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [CloudEngine.Configurations.EceInterfaceParameters] $Parameters ) $ErrorActionPreference = "Stop" $nodeName = @( Get-ExecutionContextNodeName -Parameters $Parameters ) if (-not $nodeName -or $nodeName.Count -gt 1) { throw "Invalid node information specified in the execution context: [$nodeName]" } Trace-Execution "Checking for presence of DscMetaconfig.psm1 on $nodeName." $modulePath = "\\$nodeName\C$\DSCConfigs\DscMetaconfig.psm1" if (-not (Test-Path $modulePath)) { Trace-Execution "Copying DscMetaconfig.psm1 to $nodeName." Copy-Item $PSScriptRoot\DscMetaConfig.psm1 $modulePath -Force } Trace-Execution "Cleaning up configuration on $nodeName." Invoke-Command -ComputerName $nodeName -ScriptBlock ${function:Reset-PartialConfigurations} } <# .SYNOPSIS Clean up of partial configurations is done by updating the meta configuration. We set the meta config to point to a single known resource that works, and start the DSC configuration, which removes all other partial configs from the store. Then we reset the partial configuration list in the meta configuration to ensure new configs pushed to the node are valid. This function is intended to be invoked in a remote session to a target node. #> function Reset-PartialConfigurations { $ErrorActionPreference = "Stop" $VerbosePreference = "Continue" # Helper function to update meta configuration. function Set-MetaConfig ($CertThumbprint, $PartialList) { Import-Module C:\DSCConfigs\DscMetaconfig.psm1 $metaMofPath = Join-Path ([IO.Path]::GetTempPath()) ([IO.Path]::GetRandomFileName()) Trace-Execution "Creating new temp path for meta configuration: $metaMofPath" New-Item -Path $metaMofPath -Type Directory -Force Trace-Execution "Generating meta configuration to only reference $PartialList configuration." MetaMof -OutputPath $metaMofPath -CredentialEncryptionThumbprint $CertThumbprint -PartialConfigList $PartialList $lcmConfig = $false $timeout = (Get-Date).AddMinutes(10) do { try { Trace-Execution "Setting LCM configuration from $metaMofPath" Set-DscLocalConfigurationManager -Path $metaMofPath -Force -ErrorAction Stop $lcmConfig = $true } catch { $errorMessage = $_.Exception.Message Trace-Execution "Error setting LCM configuration : '$errorMessage'" Start-Sleep 30 } } until ($lcmConfig -or (Get-Date) -gt $timeout) if (-not $lcmConfig) { throw "Failed to set LCM configuration. Last error: $errorMessage" } } # Collect current LCM settings, which will be used to set/reset the meta configuration. $lcm = Get-DscLocalConfigurationManager $encryptionThumbprint = $lcm.CertificateID if (-not $encryptionThumbprint) { Write-Warning "CertificateID on the LCM was not set. Retrieving Thumbprint of certificate in the local store." $encryptionThumbprint = Get-ChildItem Cert:\LocalMachine\My | ? Subject -match "DscEncryptionCertificate" | select -First 1 | % Thumbprint if (-not $encryptionThumbprint) { throw "Failed to get thumpbrint of DSC encryption certificate from LCM or the local store." } } Trace-Execution "Got encryption certificate thumbprint: $encryptionThumbprint." Trace-Execution "Resetting configuration." Set-MetaConfig -CertThumbprint $encryptionThumbprint -PartialList $null } Export-ModuleMember -Function Add-DSCStatusConfigFile Export-ModuleMember -Function ExportDscDecryptionCert Export-ModuleMember -Function GetDscEncryptionCert Export-ModuleMember -Function GetEncryptedPassword Export-ModuleMember -Function PrepareDSCFirstBoot Export-ModuleMember -Function Remove-DSCStatusFile Export-ModuleMember -Function RemoveExportedDscDecryptionCert Export-ModuleMember -Function Reset-PartialConfigurationsOnNode Export-ModuleMember -Function Revoke-CompleteBootDSCShareAccess Export-ModuleMember -Function SignDscConfiguration Export-ModuleMember -Function Test-ForDSCComplete Export-ModuleMember -Function Wait-ForDSCComplete # SIG # Begin signature block # MIInvwYJKoZIhvcNAQcCoIInsDCCJ6wCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAjT9aU79m1/4Vd # IQXGledp9MrczQA5n0sjMF4LAscao6CCDXYwggX0MIID3KADAgECAhMzAAADTrU8 # esGEb+srAAAAAANOMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMjMwMzE2MTg0MzI5WhcNMjQwMzE0MTg0MzI5WjB0MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQDdCKiNI6IBFWuvJUmf6WdOJqZmIwYs5G7AJD5UbcL6tsC+EBPDbr36pFGo1bsU # p53nRyFYnncoMg8FK0d8jLlw0lgexDDr7gicf2zOBFWqfv/nSLwzJFNP5W03DF/1 # 1oZ12rSFqGlm+O46cRjTDFBpMRCZZGddZlRBjivby0eI1VgTD1TvAdfBYQe82fhm # WQkYR/lWmAK+vW/1+bO7jHaxXTNCxLIBW07F8PBjUcwFxxyfbe2mHB4h1L4U0Ofa # +HX/aREQ7SqYZz59sXM2ySOfvYyIjnqSO80NGBaz5DvzIG88J0+BNhOu2jl6Dfcq # jYQs1H/PMSQIK6E7lXDXSpXzAgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE # AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUnMc7Zn/ukKBsBiWkwdNfsN5pdwAw # RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW # MBQGA1UEBRMNMjMwMDEyKzUwMDUxNjAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci # tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j # b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG # CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu # Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0 # MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAD21v9pHoLdBSNlFAjmk # mx4XxOZAPsVxxXbDyQv1+kGDe9XpgBnT1lXnx7JDpFMKBwAyIwdInmvhK9pGBa31 # TyeL3p7R2s0L8SABPPRJHAEk4NHpBXxHjm4TKjezAbSqqbgsy10Y7KApy+9UrKa2 # kGmsuASsk95PVm5vem7OmTs42vm0BJUU+JPQLg8Y/sdj3TtSfLYYZAaJwTAIgi7d # hzn5hatLo7Dhz+4T+MrFd+6LUa2U3zr97QwzDthx+RP9/RZnur4inzSQsG5DCVIM # pA1l2NWEA3KAca0tI2l6hQNYsaKL1kefdfHCrPxEry8onJjyGGv9YKoLv6AOO7Oh # JEmbQlz/xksYG2N/JSOJ+QqYpGTEuYFYVWain7He6jgb41JbpOGKDdE/b+V2q/gX # UgFe2gdwTpCDsvh8SMRoq1/BNXcr7iTAU38Vgr83iVtPYmFhZOVM0ULp/kKTVoir # IpP2KCxT4OekOctt8grYnhJ16QMjmMv5o53hjNFXOxigkQWYzUO+6w50g0FAeFa8 # 5ugCCB6lXEk21FFB1FdIHpjSQf+LP/W2OV/HfhC3uTPgKbRtXo83TZYEudooyZ/A # Vu08sibZ3MkGOJORLERNwKm2G7oqdOv4Qj8Z0JrGgMzj46NFKAxkLSpE5oHQYP1H # tPx1lPfD7iNSbJsP6LiUHXH1MIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq # hkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x # EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv # bjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 # IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEwOTA5WjB+MQswCQYDVQQG # EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG # A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQg # Q29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC # CgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+laUKq4BjgaBEm6f8MMHt03 # a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc6Whe0t+bU7IKLMOv2akr # rnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4Ddato88tt8zpcoRb0Rrrg # OGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+lD3v++MrWhAfTVYoonpy # 4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDstrjNYxbc+/jLTswM9 # sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6A4aN91/w0FK/jJSHvMAh # dCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmdX4jiJV3TIUs+UsS1Vz8k # A/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL5zmhD+kjSbwYuER8ReTB # w3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zdsGbiwZeBe+3W7UvnSSmn # Eyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3T8HhhUSJxAlMxdSlQy90 # lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS4NaIjAsCAwEAAaOCAe0w # ggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTlUAXTgqoXNzcitW2o # ynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYD # VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQFTuHqp8cx0SOJNDBa # BgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2Ny # bC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3JsMF4GCCsG # AQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3dy5taWNyb3NvZnQuY29t # L3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3J0MIGfBgNV # HSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEFBQcCARYzaHR0cDovL3d3 # dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1hcnljcHMuaHRtMEAGCCsG # AQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5AF8AcwB0AGEAdABl # AG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn8oalmOBUeRou09h0ZyKb # C5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7v0epo/Np22O/IjWll11l # hJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0bpdS1HXeUOeLpZMlEPXh6 # I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtYSWMfCWluWpiW5IP0 # wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvyCInWH8MyGOLwxS3OW560 # STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZiWhub6e3dMNABQam # ASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJihsMdYzaXht/a8/jyFqGa # J+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYbBL7fQccOKO7eZS/sl/ah # XJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKfenoi+kiVH6v7RyOA # 9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOppO6/8MO0ETI7f33Vt # Y5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZOSEXAQsmbdlsKgEhr # /Xmfwb1tbWrJUnMTDXpQzTGCGZ8wghmbAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw # EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN # aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp # Z25pbmcgUENBIDIwMTECEzMAAANOtTx6wYRv6ysAAAAAA04wDQYJYIZIAWUDBAIB # BQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO # MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIFDoxhKDxo/W5V7mdhrz5EJH # Ut04He52Gs8HQ5dHa5U1MEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A # cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB # BQAEggEABVGf6clDB7+9AtxjrRXNkk9Qz0qulQA7OrJA9kJ1D0cUEsepF79DMBp5 # aK0MbboikTTNa3NximZr+hWF4c95SErhaXpm0/HNdAZ/yo2omwuViLESM9XAIqsU # Bv3DX3McpcS7F9H5ZG42BlLSO2tkg5x3z106TB+szCOBs+EGIULYSpaLMsh08KH/ # xZXOlwlv02wORQgnsnB0B60Y6i4NpaPS49A5fwYjnVg9qbxrJjS2sU86Cdz1gNp0 # oCdcswsCVVfz59T5KzCIPVMKR8iJf+bfqHMI5fCJx2m7vL1/gtzolhPRzD0w3ys/ # A3gKeKXDMejy+XXAe/9lzmHeNNZCPqGCFykwghclBgorBgEEAYI3AwMBMYIXFTCC # FxEGCSqGSIb3DQEHAqCCFwIwghb+AgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFZBgsq # hkiG9w0BCRABBKCCAUgEggFEMIIBQAIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl # AwQCAQUABCAPFYvN1biI5oN+V/oz264MCdWmymxRLopPy9RX5sa/DQIGZMmKewgm # GBMyMDIzMDgwMzA4MjA1OS41NjJaMASAAgH0oIHYpIHVMIHSMQswCQYDVQQGEwJV # UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE # ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJl # bGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNO # OjhENDEtNEJGNy1CM0I3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBT # ZXJ2aWNloIIReDCCBycwggUPoAMCAQICEzMAAAGz/iXOKRsbihwAAQAAAbMwDQYJ # KoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x # EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv # bjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwHhcNMjIw # OTIwMjAyMjAzWhcNMjMxMjE0MjAyMjAzWjCB0jELMAkGA1UEBhMCVVMxEzARBgNV # BAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv # c29mdCBDb3Jwb3JhdGlvbjEtMCsGA1UECxMkTWljcm9zb2Z0IElyZWxhbmQgT3Bl # cmF0aW9ucyBMaW1pdGVkMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjo4RDQxLTRC # RjctQjNCNzElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZTCC # AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALR8D7rmGICuLLBggrK9je3h # JSpc9CTwbra/4Kb2eu5DZR6oCgFtCbigMuMcY31QlHr/3kuWhHJ05n4+t377PHon # dDDbz/dU+q/NfXSKr1pwU2OLylY0sw531VZ1sWAdyD2EQCEzTdLD4KJbC6wmACon # iJBAqvhDyXxJ0Nuvlk74rdVEvribsDZxzClWEa4v62ENj/HyiCUX3MZGnY/AhDya # zfpchDWoP6cJgNCSXmHV9XsJgXJ4l+AYAgaqAvN8N+EpN+0TErCgFOfwZV21cg7v # genOV48gmG/EMf0LvRAeirxPUu+jNB3JSFbW1WU8Z5xsLEoNle35icdET+G3wDNm # cSXlQYs4t94IWR541+PsUTkq0kmdP4/1O4GD54ZsJ5eUnLaawXOxxT1fgbWb9VRg # 1Z4aspWpuL5gFwHa8UNMRxsKffor6qrXVVQ1OdJOS1JlevhpZlssSCVDodMc30I3 # fWezny6tNOofpfaPrtwJ0ukXcLD1yT+89u4uQB/rqUK6J7HpkNu0fR5M5xGtOch9 # nyncO9alorxDfiEdb6zeqtCfcbo46u+/rfsslcGSuJFzlwENnU+vQ+JJ6jJRUrB+ # mr51zWUMiWTLDVmhLd66//Da/YBjA0Bi0hcYuO/WctfWk/3x87ALbtqHAbk6i1cJ # 8a2coieuj+9BASSjuXkBAgMBAAGjggFJMIIBRTAdBgNVHQ4EFgQU0BpdwlFnUgwY # izhIIf9eBdyfw40wHwYDVR0jBBgwFoAUn6cVXQBeYl2D9OXSZacbUzUZ6XIwXwYD # VR0fBFgwVjBUoFKgUIZOaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9j # cmwvTWljcm9zb2Z0JTIwVGltZS1TdGFtcCUyMFBDQSUyMDIwMTAoMSkuY3JsMGwG # CCsGAQUFBwEBBGAwXjBcBggrBgEFBQcwAoZQaHR0cDovL3d3dy5taWNyb3NvZnQu # Y29tL3BraW9wcy9jZXJ0cy9NaWNyb3NvZnQlMjBUaW1lLVN0YW1wJTIwUENBJTIw # MjAxMCgxKS5jcnQwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcD # CDAOBgNVHQ8BAf8EBAMCB4AwDQYJKoZIhvcNAQELBQADggIBAFqGuzfOsAm4wAJf # ERmJgWW0tNLLPk6VYj53+hBmUICsqGgj9oXNNatgCq+jHt03EiTzVhxteKWOLoTM # x39cCcUJgDOQIH+GjuyjYVVdOCa9Fx6lI690/OBZFlz2DDuLpUBuo//v3e4Kns41 # 2mO3A6mDQkndxeJSsdBSbkKqccB7TC/muFOhzg39mfijGICc1kZziJE/6HdKCF8p # 9+vs1yGUR5uzkIo+68q/n5kNt33hdaQ234VEh0wPSE+dCgpKRqfxgYsBT/5tXa3e # 8TXyJlVoG9jwXBrKnSQb4+k19jHVB3wVUflnuANJRI9azWwqYFKDbZWkfQ8tpNoF # fKKFRHbWomcodP1bVn7kKWUCTA8YG2RlTBtvrs3CqY3mADTJUig4ckN/MG6AIr8Q # +ACmKBEm4OFpOcZMX0cxasopdgxM9aSdBusaJfZ3Itl3vC5C3RE97uURsVB2pvC+ # CnjFtt/PkY71l9UTHzUCO++M4hSGSzkfu+yBhXMGeBZqLXl9cffgYPcnRFjQT97G # b/bg4ssLIFuNJNNAJub+IvxhomRrtWuB4SN935oMfvG5cEeZ7eyYpBZ4DbkvN44Z # vER0EHRakL2xb1rrsj7c8I+auEqYztUpDnuq6BxpBIUAlF3UDJ0SMG5xqW/9hLMW # naJCvIerEWTFm64jthAi0BDMwnCwMIIHcTCCBVmgAwIBAgITMwAAABXF52ueAptJ # mQAAAAAAFTANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT # Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m # dCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNh # dGUgQXV0aG9yaXR5IDIwMTAwHhcNMjEwOTMwMTgyMjI1WhcNMzAwOTMwMTgzMjI1 # WjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH # UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQD # Ex1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDCCAiIwDQYJKoZIhvcNAQEB # BQADggIPADCCAgoCggIBAOThpkzntHIhC3miy9ckeb0O1YLT/e6cBwfSqWxOdcjK # NVf2AX9sSuDivbk+F2Az/1xPx2b3lVNxWuJ+Slr+uDZnhUYjDLWNE893MsAQGOhg # fWpSg0S3po5GawcU88V29YZQ3MFEyHFcUTE3oAo4bo3t1w/YJlN8OWECesSq/XJp # rx2rrPY2vjUmZNqYO7oaezOtgFt+jBAcnVL+tuhiJdxqD89d9P6OU8/W7IVWTe/d # vI2k45GPsjksUZzpcGkNyjYtcI4xyDUoveO0hyTD4MmPfrVUj9z6BVWYbWg7mka9 # 7aSueik3rMvrg0XnRm7KMtXAhjBcTyziYrLNueKNiOSWrAFKu75xqRdbZ2De+JKR # Hh09/SDPc31BmkZ1zcRfNN0Sidb9pSB9fvzZnkXftnIv231fgLrbqn427DZM9itu # qBJR6L8FA6PRc6ZNN3SUHDSCD/AQ8rdHGO2n6Jl8P0zbr17C89XYcz1DTsEzOUyO # ArxCaC4Q6oRRRuLRvWoYWmEBc8pnol7XKHYC4jMYctenIPDC+hIK12NvDMk2ZItb # oKaDIV1fMHSRlJTYuVD5C4lh8zYGNRiER9vcG9H9stQcxWv2XFJRXRLbJbqvUAV6 # bMURHXLvjflSxIUXk8A8FdsaN8cIFRg/eKtFtvUeh17aj54WcmnGrnu3tz5q4i6t # AgMBAAGjggHdMIIB2TASBgkrBgEEAYI3FQEEBQIDAQABMCMGCSsGAQQBgjcVAgQW # BBQqp1L+ZMSavoKRPEY1Kc8Q/y8E7jAdBgNVHQ4EFgQUn6cVXQBeYl2D9OXSZacb # UzUZ6XIwXAYDVR0gBFUwUzBRBgwrBgEEAYI3TIN9AQEwQTA/BggrBgEFBQcCARYz # aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9Eb2NzL1JlcG9zaXRvcnku # aHRtMBMGA1UdJQQMMAoGCCsGAQUFBwMIMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIA # QwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNX2 # VsuP6KJcYmjRPZSQW9fOmhjEMFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwu # bWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dF8yMDEw # LTA2LTIzLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93 # d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYt # MjMuY3J0MA0GCSqGSIb3DQEBCwUAA4ICAQCdVX38Kq3hLB9nATEkW+Geckv8qW/q # XBS2Pk5HZHixBpOXPTEztTnXwnE2P9pkbHzQdTltuw8x5MKP+2zRoZQYIu7pZmc6 # U03dmLq2HnjYNi6cqYJWAAOwBb6J6Gngugnue99qb74py27YP0h1AdkY3m2CDPVt # I1TkeFN1JFe53Z/zjj3G82jfZfakVqr3lbYoVSfQJL1AoL8ZthISEV09J+BAljis # 9/kpicO8F7BUhUKz/AyeixmJ5/ALaoHCgRlCGVJ1ijbCHcNhcy4sa3tuPywJeBTp # kbKpW99Jo3QMvOyRgNI95ko+ZjtPu4b6MhrZlvSP9pEB9s7GdP32THJvEKt1MMU0 # sHrYUP4KWN1APMdUbZ1jdEgssU5HLcEUBHG/ZPkkvnNtyo4JvbMBV0lUZNlz138e # W0QBjloZkWsNn6Qo3GcZKCS6OEuabvshVGtqRRFHqfG3rsjoiV5PndLQTHa1V1QJ # sWkBRH58oWFsc/4Ku+xBZj1p/cvBQUl+fpO+y/g75LcVv7TOPqUxUYS8vwLBgqJ7 # Fx0ViY1w/ue10CgaiQuPNtq6TPmb/wrpNPgkNWcr4A245oyZ1uEi6vAnQj0llOZ0 # dFtq0Z4+7X6gMTN9vMvpe784cETRkPHIqzqKOghif9lwY1NNje6CbaUFEMFxBmoQ # tB1VM1izoXBm8qGCAtQwggI9AgEBMIIBAKGB2KSB1TCB0jELMAkGA1UEBhMCVVMx # EzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoT # FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEtMCsGA1UECxMkTWljcm9zb2Z0IElyZWxh # bmQgT3BlcmF0aW9ucyBMaW1pdGVkMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjo4 # RDQxLTRCRjctQjNCNzElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2Vy # dmljZaIjCgEBMAcGBSsOAwIaAxUAcYtE6JbdHhKlwkJeKoCV1JIkDmGggYMwgYCk # fjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH # UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQD # Ex1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQUFAAIF # AOh1WlYwIhgPMjAyMzA4MDMwNjQyMzBaGA8yMDIzMDgwNDA2NDIzMFowdDA6Bgor # BgEEAYRZCgQBMSwwKjAKAgUA6HVaVgIBADAHAgEAAgIhfDAHAgEAAgIVwzAKAgUA # 6Har1gIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIBAAID # B6EgoQowCAIBAAIDAYagMA0GCSqGSIb3DQEBBQUAA4GBAFNPJasblHYtMWpbDWh3 # Ti7S/zUXN3xSGMoyf/tPnY91WzbTWChClrIZMjdCtD960bg3IPdvemfpuGLYFmh3 # ji3o0625aH5vnk28E0Iz2ERW2U70Rf+ZIbgNxIelAVXXghfMw+UN4O2FEdq4szY5 # 5xwJaJ7nDGl2Q4KDrSVr5aAZMYIEDTCCBAkCAQEwgZMwfDELMAkGA1UEBhMCVVMx # EzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoT # FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUt # U3RhbXAgUENBIDIwMTACEzMAAAGz/iXOKRsbihwAAQAAAbMwDQYJYIZIAWUDBAIB # BQCgggFKMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0BCQQx # IgQg/aTkyIu7xzwVZ2WjWcGJzIcNiGARVK4kuKdVZ0fQLUkwgfoGCyqGSIb3DQEJ # EAIvMYHqMIHnMIHkMIG9BCCGoTPVKhDSB7ZG0zJQZUM2jk/ll1zJGh6KOhn76k+/ # QjCBmDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw # DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x # JjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAABs/4l # zikbG4ocAAEAAAGzMCIEIETylqyW4GfyewUmEWdFqjUbqnCfTLToMzXLeQn2MHLg # MA0GCSqGSIb3DQEBCwUABIICABe1YVvD7tw/IAHskPc+6tsJp6ShbcCZSmOIwdaC # BRcAG/3qM+RyiFu4sEncA5pnzXUb/SebwAKzOZfHku2SIxjycabBjv6+0757HVZy # 7eG5HTa1gnopIbS23IFSYv4t+WP437+DJANQq+stJLJ7VSvYbCXDS7j2dF2+hBQ/ # vJplcCYlAMNgwfO/vUUcLSvZ5MQKHsAY655kMd2yMN0CiOIyAmgvzA1Yapas3a8t # WgiaiHDgxqI7TlhDBC9BCNQJ/TmQnbQP9YCW2AdNxUtD9hv8uk6FXcZDHGHQSzwq # m6EgWiTpyVXdsJK1tSR8mKmd9R6QvbFsU0zBNzu2MAxaS92fRm4RUnMnRdWjbsJD # rXw6Sp+zlhgGQulejfHZN7RC3bkVFVOJBh2mSfEmEPK1Fg3GVhJRrjQPsDAlmuJW # 9f5AjxDWiYHR4/YMln5+srXmS6k45J1upZ/kVpWAwfERaVr+xiYikizVY2VJrrRD # J1YMND1zCU7US33dc4oaVqfdQ4Bjcs07fvoClBNid6iQRnq+SNymhZfzf+P1LaKg # SBrVGq7bsimIToXYaW5BZBq3Il1LkPQouPxXpBxi7Kbq+Lpx2DNZ50aWJ7n2gfny # TWC1pjTkrYKxTK/ZsN82mstdf6CLhAAkxeq1K6FuHB64gQUDSkWdF32gZG6vmhO7 # Qu14 # SIG # End signature block |