Obs/bin/ObsDep/content/Powershell/Roles/Common/JustEnoughAdministrationDSC.psm1
<###################################################
# # # Copyright (c) Microsoft. All rights reserved. # # # ##################################################> Import-Module -Name "$PSScriptRoot\..\..\Common\Helpers.psm1" Import-Module -Name "$PSScriptRoot\..\..\Common\StorageHelpers.psm1" -Force Import-Module -Name "$PSScriptRoot\DscHelper.psm1" Import-Module -Name "$PSScriptRoot\JeaHelper.psm1" <# .Synopsis Generates DSC configuration document(s) for the target node(s), as specified by the Role configuration. Returns the list of the JEA endpoints captured in the configuration. #> function New-JustEnoughAdministrationConfiguration { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [CloudEngine.Configurations.EceInterfaceParameters] $Parameters, [Parameter(Mandatory=$true)] [IO.DirectoryInfo] $ModulesRootPath, [Parameter(Mandatory=$false)] [IO.DirectoryInfo] $MofOutputPath=$null, [Parameter(Mandatory=$false)] [string] $TargetComputerName = 'localhost', [string[]] $TargetImageRole = $Parameters.Configuration.Role.Id, [string[]] $SourceImageRole ) $ErrorActionPreference = 'Stop' if ($MofOutputPath -eq $null) { $MofOutputPath = Join-Path $ModulesRootPath "DSCConfigs\ConfigureJustEnoughAdministration" } Trace-Execution "$($MyInvocation.InvocationName) : BEGIN on $($env:COMPUTERNAME) as $($env:USERDOMAIN)\$($env:USERNAME)" $cloudRole = $Parameters.Roles["Cloud"].PublicConfiguration $securityInfo = $cloudRole.PublicInfo.SecurityInfo $domainRole = $Parameters.Roles["Domain"].PublicConfiguration $domainName = $domainRole.PublicInfo.DomainConfiguration.DomainName # Get all the roles that have JEA information $RolesToConfigure = $Parameters.Roles.GetEnumerator() | Where-Object { $Parameters.Roles[$_.Name].PublicConfiguration.PublicInfo.JEA } | Foreach-Object { $_.Name } if ($SourceImageRole) { Trace-Execution "Getting list of JEA endpoints defined under the following roles: $($SourceImageRole -join ', ')." $RolesToConfigure = $RolesToConfigure | where { $_ -in $SourceImageRole } } $endpoints = @() foreach($role in $RolesToConfigure) { $configuration = $Parameters.Roles[$role].PublicConfiguration.PublicInfo.JEA.Endpoints.Endpoint # Loop through all the endpoints defined foreach($endpoint in $configuration) { if (!$endpoint.TargetRoles) { if (-not ($TargetImageRole -contains $role)) { continue } } else { $applicable = $endpoint.TargetRoles.TargetRole | Where-Object { $TargetImageRole -contains $_.Id } if (!$applicable) { continue } } $runAsGmsa = $endpoint.RunAsGmsa -and ($endpoint.RunAsGmsa -eq "True") $runAsVirtualAccount = $endpoint.RunAsVirtualAccount -and ($endpoint.RunAsVirtualAccount -eq "True") if ( -not ($runAsGmsa -or $runAsVirtualAccount) ) { Trace-Execution "Create JEA endpoint '$($endpoint.Name)' as non-GMSA and non-virtual account (will use pass-through credential)." } Trace-Execution "Creating JEA Endpoint $($endpoint.Name) for Role $($TargetImageRole -join ', ')" # Define transportation options $transportOption = $null if ($endpoint.TransportOptions) { $transportOption = @{} $endpoint.TransportOptions.GetEnumerator() | foreach { if ([Microsoft.PowerShell.Commands.WSManConfigurationOption].GetProperties().Name.Contains($_.Name)) { $transportOption[$_.Name] = $_.Value } else { throw "Transport Option '$($_.Name)' for JEA endpoint not valid for WSManConfigurationOption" } } $endpoint | Add-Member -MemberType NoteProperty -Name "TransportOption" -Value $transportOption -Force } # Path to the Powershell Modules folder $modulePath = Join-Path $ModulesRootPath "Program Files\WindowsPowerShell\Modules\" # Path where the psrc file will be stored $rcPath = Join-Path $modulePath "JEA\RoleCapabilities" # Create the folder where the RC files will be stored New-Item -Path $rcPath -ItemType Directory -Force | Out-Null $deployLatestVersion = -not($endpoint.AllVersions -and $endpoint.AllVersions -eq "True") # This flag checks if the endpoint gathers its rolecapability configuration from a nuget. # If there is no rc nuget dependency, then conduct the custom configuration $psrcFromNuget = $false $endpointVersion = "" $sourceVersionExtensionList = @() # If the endpoint has nuget defined, copy the contents inside the nuget to the right location. if($endpoint.Nugets) { $clusterName = Get-ManagementClusterName $Parameters $nugets = $endpoint.Nugets.Nuget foreach($nuget in $nugets) { $nugetName = $nuget.Name Trace-Execution "EndpointName: $($endpoint.Name) , NugetName: $nugetName" # Get nuget store location on the library share $virtualMachinesRole = $Parameters.Roles["VirtualMachines"].PublicConfiguration $libraryShareNugetStorePath = Get-SharePath $Parameters $virtualMachinesRole.PublicInfo.LibraryShareNugetStoreFolder.Path $clusterName $buildLocally = $Parameters.Context.ExecutionContext.BuildVhdLocally -and [bool]::Parse($Parameters.Context.ExecutionContext.BuildVhdLocally) # Use the NuGet store on the file share, unless explicitly told not to (BuildVhdLocally) or the file share is not reachable. $useLibrarySharePath = -not $buildLocally -and (Test-Path $libraryShareNugetStorePath) Trace-Execution "useLibrarySharePath: $useLibrarySharePath" # Collect all versions of the JEA endpoint nugets to support upgrading from an unknown stamp version $getNugetVersionsParams = @{ NugetName = $NugetName MostRecent = $deployLatestVersion } if($useLibrarySharePath) { $getNugetVersionsParams.NugetStorePath = $libraryShareNugetStorePath } $versionList = Get-NugetVersions @getNugetVersionsParams # If version is required, but none are found, throw if ($endpoint.RequiresVersion -and ($versionList.Count -eq 0)) { Trace-Error "Requires version was specified, but no versions were found for endpoint '$($endpoint.Name)'" } # Loop through the list of versions and copy the content and PSRC(if applicable) to the right location foreach($nugetVersion in $versionList) { if ($nuget.PackagedModules -and $nuget.PackagedModules.Path) { # Temporary location where the JEA module source code will be extracted $tempPath = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath ([System.IO.Path]::GetRandomFileName()) New-Item -Path $tempPath -ItemType Directory -Force | Out-Null try { # Unpack the scripts for the JEA endpoint at a temporary location Trace-Execution "Expand nuget: $nugetName with content from: $($nuget.PackagedModules.Path) to : $tempPath " $expandNugetContentParams = @{ NugetName = $NugetName SourcePath = $nuget.PackagedModules.Path DestinationPath = $tempPath Version = $nugetVersion } if($useLibrarySharePath) { $expandNugetContentParams.NugetStorePath = $libraryShareNugetStorePath } Expand-NugetContent @expandNugetContentParams # Define what the module path will look like and if the path does not exist, create it $targetModulePath = $modulePath if($nuget.PackagedModules.Destination) { $targetModulePath = Join-Path $modulePath $nuget.PackagedModules.Destination if ((Test-Path -Path $targetModulePath) -eq $false) { $null = New-Item -Path $targetModulePath -ItemType Directory -Force } } # Copy content from the temporary path to the target path $copy = @{ Path = "$tempPath\*"; Destination = "$targetModulePath\"; Recurse = $true; Force = $true} if ($nuget.PackagedModules.Filter) { $copy["Filter"] = $nuget.PackagedModules.Filter } Trace-Execution "Copying content from $tempPath to $targetModulePath" try { Copy-Item @copy } catch [System.IO.IOException] { Trace-Execution "I/O exception ignored during copying of existing JEA modules, potentially due to module already being loaded" } } catch { # Printing error message here as Remove-Item occasionally throws errors that mask the original issue. Trace-Execution ($_ | Format-List *) throw } finally { Remove-Item -Recurse $tempPath -Force -ErrorAction SilentlyContinue if (Test-Path $tempPath) { Remove-Item -Recurse $tempPath -Force -ErrorAction Stop } } } # If the RoleCapability is present and has a path value, psrc files will be picked up from the nuget if ($nuget.RoleCapability -and $nuget.RoleCapability.Path) { Trace-Execution "Role Capability for the endpoint is defined in the nuget with path: $($nuget.RoleCapability.Path)" # Recurse over all available versions of the target package # There may be multiple RC files within the nuget, each representing a versioned endpoint. # The customer config will only define one broad endpoint, so need to expand the endpoints # to register by the versioned names. $tempPath = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath ([System.IO.Path]::GetRandomFileName()) New-Item -Path $tempPath -ItemType Directory -Force | Out-Null $psrcFromNuget = $true try { $expandNugetContentParams = @{ NugetName = $NugetName SourcePath = $nuget.RoleCapability.Path DestinationPath = $tempPath Version = $nugetVersion } if($useLibrarySharePath) { $expandNugetContentParams.NugetStorePath = $libraryShareNugetStorePath } Expand-NugetContent @expandNugetContentParams # Copy each RC file for each whitelist foreach($whiteList in $endpoint.WhiteList) { $copy = @{ Path = "$tempPath\*"; Filter = "$($whiteList.Name)*"; Destination = $rcPath; Recurse = $true; Force = $true } Trace-Execution "Copying content from: $tempPath to: $rcPath with whitelist name: $($whiteList.Name)" Copy-Item @copy Trace-Execution "Get version for the endpoint:$($endpoint.Name)" # If the version is not set yet, pick up the RC file with the name as (endpointName + Version) if ($whiteList.Name -like "$($endpoint.Name)*") { $rcFile = Get-ChildItem -Path $rcPath -Filter "$($whiteList.Name)*" foreach ($whitelistFile in $rcFile) { $roleCapabilityName = [System.IO.Path]::GetFileNameWithoutExtension($whitelistFile.FullName) $endpointVersion = $roleCapabilityName.Substring($whitelist.Name.Length, $roleCapabilityName.Length - $whitelist.Name.Length) if (-not($sourceVersionExtensionList -contains $endpointVersion)) { $sourceVersionExtensionList += $endpointVersion } } } } } catch { # Printing error message here as Remove-Item occasionally throws errors that mask the original issue. Trace-Execution ($_ | Format-List *) throw } finally { Remove-Item -Recurse $tempPath -Force -ErrorAction SilentlyContinue if (Test-Path $tempPath) { Remove-Item -Recurse $tempPath -Force -ErrorAction Stop } } } } } } # Nuget expansion completed # No versions were found, so ensure that at least the non-versioned endpoint is created if([string]::IsNullOrEmpty($endpointVersion)) { $sourceVersionExtensionList = @("") } # As we are done with Nuget expansion, if the PSRC file was not picked up from the nuget, create it. if(-not $psrcFromNuget) { # Simple endpoint from configuration definition, with no versions # Loop through all the whitelists and generate the PSRC files at the desired location. foreach($whiteList in $endpoint.Whitelist) { $RCParams = Get-RoleCapabilityParams($whitelist) Trace-Execution "Role Capabilities for endpoint '$($endpoint.Name)': " Trace-Execution ($RCParams | ConvertTo-Json -depth 3) New-Item -Path $rcPath -ItemType Directory -Force | Out-Null New-PSRoleCapabilityFile -Path "$rcPath\$($whitelist.Name).psrc" @RCParams } } foreach ($endpointVersion in $sourceVersionExtensionList) { # Gather information needed to create the PSSC file and also for registration of JEA endpoint. # Clone the endpoint $e = $endpoint.Clone() # Session configuration $sessionConfigurationArgs = @{ SessionConfig = $endpoint.SessionConfiguration; Endpointname = $endpoint.Name; } # If version was found add it to the name of the endpoint as it will be a versioned endpoint if([string]::IsNullOrEmpty($endpointVersion) -eq $false) { $e.Name = $endpoint.Name + $endpointVersion $sessionConfigurationArgs["Endpointname"] = $e.Name $sessionConfigurationArgs["VersionExtension"] = $endpointVersion } # RunAs accounts if ($runAsGmsa) { $RunAsAccountUser = "$domainName\$($endpoint.RunAsAccountID)" $sessionConfigurationArgs["RunAsAccountUser"] = $RunAsAccountUser $sessionConfigurationArgs["RunAsGmsa"] = $true $e | Add-Member -MemberType NoteProperty -Name "RunAsAccountUser" -Value $RunAsAccountUser -Force } elseif($runAsVirtualAccount) { Trace-Execution "[$($endpoint.Name)] will run under virtual admin account" $e | Add-Member -MemberType NoteProperty -Name "RunAsVirtualAccount" -Value $true -Force $sessionConfigurationArgs["RunAsVirtualAccount"] = $true } else { Trace-Execution "Endpoint $($endpoint.Name) will use user pass-through credential" $sessionConfigurationArgs["RunAsPassThroughCredential"] = $true } $scParams = Get-SessionConfigurationParams @sessionConfigurationArgs $e | Add-Member -MemberType NoteProperty -Name "RoleDefinitions" -Value $scParams.RoleDefinitions -Force if($scParams.TranscriptDirectory) { $e | Add-Member -MemberType NoteProperty -Name "TranscriptDirectory" -Value $scParams.TranscriptDirectory -Force } if($scParams.SessionType) { $e | Add-Member -MemberType NoteProperty -Name "SessionType" -Value $scParams.SessionType -Force } if($scParams.LanguageMode) { $e | Add-Member -MemberType NoteProperty -Name "LanguageMode" -Value $scParams.LanguageMode -Force } $endpoints += $e } } } # If no endpoints are defined, move on. if ($endpoints.Count -eq 0) { Trace-Execution "No endpoints to deploy for role [$TargetImageRole]" return; } # DSC is slow to import at module parse time. Defer import of all DSC configurations until runtime. Import-Module "$PSScriptRoot\JustEnoughAdministrationDSCconfig.psm1" -DisableNameChecking $dscEncryptionCert = GetDscEncryptionCert $ConfigData= @{ AllNodes = @( @{ NodeName = $TargetComputerName CertificateFile = "$env:temp\DscEncryptionPublicKey.cer" ThumbPrint = $dscEncryptionCert.ThumbPrint }; ); } Remove-Item "$MofOutputPath\$TargetComputerName.mof" -Force -ErrorAction SilentlyContinue Trace-Execution "Generating JustEnoughAdministration endpoint MOFs" ConfigureJustEnoughAdministration -ConfigurationData $ConfigData -Endpoints $endpoints -OutputPath $MofOutputPath | Out-Null Trace-Execution "$($MyInvocation.InvocationName) : END on $($env:COMPUTERNAME) as $($env:USERDOMAIN)\$($env:USERNAME)" Trace-Execution "Created configuration for the following endpoints:$([System.Environment]::NewLine)$($endpoints.Name -join [System.Environment]::NewLine)" return $endpoints.Name } function Get-NugetVersions { <# .SYNOPSIS Gets all versions of Nuget packages that exist in a specified source location. .EXAMPLE Get-NugetVersions -NugetName "MyNuget" -SourcePath "content" .PARAMETER NugetName The name of the nuget to filter by. .PARAMETER MostRecent Whether to report the most recent version only .PARAMETER NugetStorePath The path from which the nuget packages should be derived. #> [CmdletBinding()] PARAM ( [Parameter(Mandatory=$true, Position=0)] [ValidateNotNullOrEmpty()] [string[]] $NugetName, [Parameter(Mandatory=$false)] [switch] $MostRecent, [Parameter()] [ValidateNotNullOrEmpty()] [string] $NugetStorePath = "$env:SystemDrive\CloudDeployment\NuGetStore" ) PROCESS { $ErrorActionPreference = "stop" Trace-Execution "Finding nuget package $NugetName from store $NugetStorePath" $nugetPackageList = Find-Package -Source $NugetStorePath -Name $NugetName -ProviderName "nuget" -AllVersions:$(-not $MostRecent) -Verbose -Force if ($nugetPackageList) { $versionArray = $nugetPackageList.Version } else { $versionArray = @() } return $versionArray } } Export-ModuleMember New-JustEnoughAdministrationConfiguration # SIG # Begin signature block # MIIoRgYJKoZIhvcNAQcCoIIoNzCCKDMCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCqAiA/u5EXKJ25 # cdRpgvdnQk4G9Wp9nEHgRODHkpP+D6CCDXYwggX0MIID3KADAgECAhMzAAADrzBA # DkyjTQVBAAAAAAOvMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMjMxMTE2MTkwOTAwWhcNMjQxMTE0MTkwOTAwWjB0MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQDOS8s1ra6f0YGtg0OhEaQa/t3Q+q1MEHhWJhqQVuO5amYXQpy8MDPNoJYk+FWA # hePP5LxwcSge5aen+f5Q6WNPd6EDxGzotvVpNi5ve0H97S3F7C/axDfKxyNh21MG # 0W8Sb0vxi/vorcLHOL9i+t2D6yvvDzLlEefUCbQV/zGCBjXGlYJcUj6RAzXyeNAN # xSpKXAGd7Fh+ocGHPPphcD9LQTOJgG7Y7aYztHqBLJiQQ4eAgZNU4ac6+8LnEGAL # go1ydC5BJEuJQjYKbNTy959HrKSu7LO3Ws0w8jw6pYdC1IMpdTkk2puTgY2PDNzB # tLM4evG7FYer3WX+8t1UMYNTAgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE # AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQURxxxNPIEPGSO8kqz+bgCAQWGXsEw # RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW # MBQGA1UEBRMNMjMwMDEyKzUwMTgyNjAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci # tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j # b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG # CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu # Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0 # MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAISxFt/zR2frTFPB45Yd # mhZpB2nNJoOoi+qlgcTlnO4QwlYN1w/vYwbDy/oFJolD5r6FMJd0RGcgEM8q9TgQ # 2OC7gQEmhweVJ7yuKJlQBH7P7Pg5RiqgV3cSonJ+OM4kFHbP3gPLiyzssSQdRuPY # 1mIWoGg9i7Y4ZC8ST7WhpSyc0pns2XsUe1XsIjaUcGu7zd7gg97eCUiLRdVklPmp # XobH9CEAWakRUGNICYN2AgjhRTC4j3KJfqMkU04R6Toyh4/Toswm1uoDcGr5laYn # TfcX3u5WnJqJLhuPe8Uj9kGAOcyo0O1mNwDa+LhFEzB6CB32+wfJMumfr6degvLT # e8x55urQLeTjimBQgS49BSUkhFN7ois3cZyNpnrMca5AZaC7pLI72vuqSsSlLalG # OcZmPHZGYJqZ0BacN274OZ80Q8B11iNokns9Od348bMb5Z4fihxaBWebl8kWEi2O # PvQImOAeq3nt7UWJBzJYLAGEpfasaA3ZQgIcEXdD+uwo6ymMzDY6UamFOfYqYWXk # ntxDGu7ngD2ugKUuccYKJJRiiz+LAUcj90BVcSHRLQop9N8zoALr/1sJuwPrVAtx # HNEgSW+AKBqIxYWM4Ev32l6agSUAezLMbq5f3d8x9qzT031jMDT+sUAoCw0M5wVt # CUQcqINPuYjbS1WgJyZIiEkBMIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq # 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 # /Xmfwb1tbWrJUnMTDXpQzTGCGiYwghoiAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw # EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN # aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp # Z25pbmcgUENBIDIwMTECEzMAAAOvMEAOTKNNBUEAAAAAA68wDQYJYIZIAWUDBAIB # BQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO # MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIPdQ11oAHrmktdAw/ha3CecL # ykCnX9UV4e7bw19fGD/rMEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A # cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB # BQAEggEAQvIXFzuX0CurwB281EipM5iNC/8lK8U9oZ2eh62zHGw54JQ2GI3htXti # N3pzwypGfKLXMdZzMelmp2nxC5PzVyEAWqfaFJlxOViJpIH4QHO+8cRHBq/sCsKa # suDVa3n7yJuyCKHo5jBbDYwfqTSCsQfFaTA+YuPM2BpqNgup9pejp9tZ9Y5nayEQ # 2Sm0lKVB9xEEVFHBl3MMwflfn3nMjZxvQuO1aketFYcj8UarEOId8BRmIOI/OMTJ # qZxSWd+bJRxdGrkIVmslEB4d3pfH6iuLRoQEEm6ZOrYqVcGJ5IwdKvd22py0+YwA # LbTv5NYizGHG/CjciVQuI/mGN9eaWqGCF7AwghesBgorBgEEAYI3AwMBMYIXnDCC # F5gGCSqGSIb3DQEHAqCCF4kwgheFAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFaBgsq # hkiG9w0BCRABBKCCAUkEggFFMIIBQQIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl # AwQCAQUABCBDOfxf5fhL5wP6CyqdsiRjHjQZJIcMldeYIK7DOSCcDQIGZus5Bapj # GBMyMDI0MTAwOTAxMTIzNi4wNDZaMASAAgH0oIHZpIHWMIHTMQswCQYDVQQGEwJV # UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE # ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJl # bGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVT # TjoyQTFBLTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAg # U2VydmljZaCCEf4wggcoMIIFEKADAgECAhMzAAAB+R9njXWrpPGxAAEAAAH5MA0G # CSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9u # MRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp # b24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMB4XDTI0 # MDcyNTE4MzEwOVoXDTI1MTAyMjE4MzEwOVowgdMxCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9w # ZXJhdGlvbnMgTGltaXRlZDEnMCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjJBMUEt # MDVFMC1EOTQ3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNl # MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtD1MH3yAHWHNVslC+CBT # j/Mpd55LDPtQrhN7WeqFhReC9xKXSjobW1ZHzHU8V2BOJUiYg7fDJ2AxGVGyovUt # gGZg2+GauFKk3ZjjsLSsqehYIsUQrgX+r/VATaW8/ONWy6lOyGZwZpxfV2EX4qAh # 6mb2hadAuvdbRl1QK1tfBlR3fdeCBQG+ybz9JFZ45LN2ps8Nc1xr41N8Qi3KVJLY # X0ibEbAkksR4bbszCzvY+vdSrjWyKAjR6YgYhaBaDxE2KDJ2sQRFFF/egCxKgogd # F3VIJoCE/Wuy9MuEgypea1Hei7lFGvdLQZH5Jo2QR5uN8hiMc8Z47RRJuIWCOeyI # J1YnRiiibpUZ72+wpv8LTov0yH6C5HR/D8+AT4vqtP57ITXsD9DPOob8tjtsefPc # QJebUNiqyfyTL5j5/J+2d+GPCcXEYoeWZ+nrsZSfrd5DHM4ovCmD3lifgYnzjOry # 4ghQT/cvmdHwFr6yJGphW/HG8GQd+cB4w7wGpOhHVJby44kGVK8MzY9s32Dy1THn # Jg8p7y1sEGz/A1y84Zt6gIsITYaccHhBKp4cOVNrfoRVUx2G/0Tr7Dk3fpCU8u+5 # olqPPwKgZs57jl+lOrRVsX1AYEmAnyCyGrqRAzpGXyk1HvNIBpSNNuTBQk7FBvu+ # Ypi6A7S2V2Tj6lzYWVBvuGECAwEAAaOCAUkwggFFMB0GA1UdDgQWBBSJ7aO6nJXJ # I9eijzS5QkR2RlngADAfBgNVHSMEGDAWgBSfpxVdAF5iXYP05dJlpxtTNRnpcjBf # BgNVHR8EWDBWMFSgUqBQhk5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3Bz # L2NybC9NaWNyb3NvZnQlMjBUaW1lLVN0YW1wJTIwUENBJTIwMjAxMCgxKS5jcmww # bAYIKwYBBQUHAQEEYDBeMFwGCCsGAQUFBzAChlBodHRwOi8vd3d3Lm1pY3Jvc29m # dC5jb20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0El # MjAyMDEwKDEpLmNydDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUF # BwMIMA4GA1UdDwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAgEAZiAJgFbkf7jf # hx/mmZlnGZrpae+HGpxWxs8I79vUb8GQou50M1ns7iwG2CcdoXaq7VgpVkNf1uvI # hrGYpKCBXQ+SaJ2O0BvwuJR7UsgTaKN0j/yf3fpHD0ktH+EkEuGXs9DBLyt71iut # Vkwow9iQmSk4oIK8S8ArNGpSOzeuu9TdJjBjsasmuJ+2q5TjmrgEKyPe3TApAio8 # cdw/b1cBAmjtI7tpNYV5PyRI3K1NhuDgfEj5kynGF/uizP1NuHSxF/V1ks/2tCEo # riicM4k1PJTTA0TCjNbkpmBcsAMlxTzBnWsqnBCt9d+Ud9Va3Iw9Bs4ccrkgBjLt # g3vYGYar615ofYtU+dup+LuU0d2wBDEG1nhSWHaO+u2y6Si3AaNINt/pOMKU6l4A # W0uDWUH39OHH3EqFHtTssZXaDOjtyRgbqMGmkf8KI3qIVBZJ2XQpnhEuRbh+Agpm # Rn/a410Dk7VtPg2uC422WLC8H8IVk/FeoiSS4vFodhncFetJ0ZK36wxAa3FiPgBe # bRWyVtZ763qDDzxDb0mB6HL9HEfTbN+4oHCkZa1HKl8B0s8RiFBMf/W7+O7EPZ+w # MH8wdkjZ7SbsddtdRgRARqR8IFPWurQ+sn7ftEifaojzuCEahSAcq86yjwQeTPN9 # YG9b34RTurnkpD+wPGTB1WccMpsLlM0wggdxMIIFWaADAgECAhMzAAAAFcXna54C # m0mZAAAAAAAVMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UE # CBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9z # b2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZp # Y2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0yMTA5MzAxODIyMjVaFw0zMDA5MzAxODMy # MjVaMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQH # EwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNV # BAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMIICIjANBgkqhkiG9w0B # AQEFAAOCAg8AMIICCgKCAgEA5OGmTOe0ciELeaLL1yR5vQ7VgtP97pwHB9KpbE51 # yMo1V/YBf2xK4OK9uT4XYDP/XE/HZveVU3Fa4n5KWv64NmeFRiMMtY0Tz3cywBAY # 6GB9alKDRLemjkZrBxTzxXb1hlDcwUTIcVxRMTegCjhuje3XD9gmU3w5YQJ6xKr9 # cmmvHaus9ja+NSZk2pg7uhp7M62AW36MEBydUv626GIl3GoPz130/o5Tz9bshVZN # 7928jaTjkY+yOSxRnOlwaQ3KNi1wjjHINSi947SHJMPgyY9+tVSP3PoFVZhtaDua # Rr3tpK56KTesy+uDRedGbsoy1cCGMFxPLOJiss254o2I5JasAUq7vnGpF1tnYN74 # kpEeHT39IM9zfUGaRnXNxF803RKJ1v2lIH1+/NmeRd+2ci/bfV+AutuqfjbsNkz2 # K26oElHovwUDo9Fzpk03dJQcNIIP8BDyt0cY7afomXw/TNuvXsLz1dhzPUNOwTM5 # TI4CvEJoLhDqhFFG4tG9ahhaYQFzymeiXtcodgLiMxhy16cg8ML6EgrXY28MyTZk # i1ugpoMhXV8wdJGUlNi5UPkLiWHzNgY1GIRH29wb0f2y1BzFa/ZcUlFdEtsluq9Q # BXpsxREdcu+N+VLEhReTwDwV2xo3xwgVGD94q0W29R6HXtqPnhZyacaue7e3Pmri # Lq0CAwEAAaOCAd0wggHZMBIGCSsGAQQBgjcVAQQFAgMBAAEwIwYJKwYBBAGCNxUC # BBYEFCqnUv5kxJq+gpE8RjUpzxD/LwTuMB0GA1UdDgQWBBSfpxVdAF5iXYP05dJl # pxtTNRnpcjBcBgNVHSAEVTBTMFEGDCsGAQQBgjdMg30BATBBMD8GCCsGAQUFBwIB # FjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9y # eS5odG0wEwYDVR0lBAwwCgYIKwYBBQUHAwgwGQYJKwYBBAGCNxQCBAweCgBTAHUA # YgBDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU # 1fZWy4/oolxiaNE9lJBb186aGMQwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDovL2Ny # bC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0XzIw # MTAtMDYtMjMuY3JsMFoGCCsGAQUFBwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0cDov # L3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXRfMjAxMC0w # Ni0yMy5jcnQwDQYJKoZIhvcNAQELBQADggIBAJ1VffwqreEsH2cBMSRb4Z5yS/yp # b+pcFLY+TkdkeLEGk5c9MTO1OdfCcTY/2mRsfNB1OW27DzHkwo/7bNGhlBgi7ulm # ZzpTTd2YurYeeNg2LpypglYAA7AFvonoaeC6Ce5732pvvinLbtg/SHUB2RjebYIM # 9W0jVOR4U3UkV7ndn/OOPcbzaN9l9qRWqveVtihVJ9AkvUCgvxm2EhIRXT0n4ECW # OKz3+SmJw7wXsFSFQrP8DJ6LGYnn8AtqgcKBGUIZUnWKNsIdw2FzLixre24/LAl4 # FOmRsqlb30mjdAy87JGA0j3mSj5mO0+7hvoyGtmW9I/2kQH2zsZ0/fZMcm8Qq3Uw # xTSwethQ/gpY3UA8x1RtnWN0SCyxTkctwRQEcb9k+SS+c23Kjgm9swFXSVRk2XPX # fx5bRAGOWhmRaw2fpCjcZxkoJLo4S5pu+yFUa2pFEUep8beuyOiJXk+d0tBMdrVX # VAmxaQFEfnyhYWxz/gq77EFmPWn9y8FBSX5+k77L+DvktxW/tM4+pTFRhLy/AsGC # onsXHRWJjXD+57XQKBqJC4822rpM+Zv/Cuk0+CQ1ZyvgDbjmjJnW4SLq8CdCPSWU # 5nR0W2rRnj7tfqAxM328y+l7vzhwRNGQ8cirOoo6CGJ/2XBjU02N7oJtpQUQwXEG # ahC0HVUzWLOhcGbyoYIDWTCCAkECAQEwggEBoYHZpIHWMIHTMQswCQYDVQQGEwJV # UzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UE # ChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJl # bGFuZCBPcGVyYXRpb25zIExpbWl0ZWQxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVT # TjoyQTFBLTA1RTAtRDk0NzElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAg # U2VydmljZaIjCgEBMAcGBSsOAwIaAxUAqs5WjWO7zVAKmIcdwhqgZvyp6UaggYMw # gYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE # BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYD # VQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQsF # AAIFAOqwFFcwIhgPMjAyNDEwMDgyMDI4MDdaGA8yMDI0MTAwOTIwMjgwN1owdzA9 # BgorBgEEAYRZCgQBMS8wLTAKAgUA6rAUVwIBADAKAgEAAgIb9QIB/zAHAgEAAgIT # QTAKAgUA6rFl1wIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAow # CAIBAAIDB6EgoQowCAIBAAIDAYagMA0GCSqGSIb3DQEBCwUAA4IBAQAJeaTWdVz6 # TRrmR+ZQDUeMReQrxTtW8flgm3jlZ0wEMZ9rqSJAbKP6mK69Cg/DuCO0iZk78GlB # uIkfxhfKHNvjrW5OuaIj7DpKp4BBwcg0Q0+T6sMdNihCrmtQLEvYxfIXhRBwwFJk # fOD74yy+rxei5AS54DSRjPCBprV1NNmk/bRb1eMnon7znUO1v8a26p3ePgo3tcqG # 58oCGJUBs5GT2SvZQDSSqqmot7xmz73YtOcmF8M79fItT/BxhrAJnUzXAQgt/BZb # 6LkbzhaN4piAgQbw7WohBYOsrrYDgrasEa29ymd0OdqWBM54HnmI+26bDZ4L2HR2 # sW4Behv5Vh3dMYIEDTCCBAkCAQEwgZMwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgT # Cldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29m # dCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENB # IDIwMTACEzMAAAH5H2eNdauk8bEAAQAAAfkwDQYJYIZIAWUDBAIBBQCgggFKMBoG # CSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0BCQQxIgQgGFhMLwCW # /HIeAX4LyZJGYb21SCospkoO6FQ6Nc88SO4wgfoGCyqGSIb3DQEJEAIvMYHqMIHn # MIHkMIG9BCA5I4zIHvCN+2T66RUOLCZrUEVdoKlKl8VeCO5SbGLYEDCBmDCBgKR+ # MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS # ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMT # HU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAAB+R9njXWrpPGxAAEA # AAH5MCIEICg0FSgJqDpgrp0nEOO0m/kEOEJqgKL/FOZ6aw8VZnl1MA0GCSqGSIb3 # DQEBCwUABIICAK/O8DTLthvmbMks102gUlQeoDHmw3KTGauH0aD88XpWqGKdHasH # I2oRFYaugzGamJ/6AmQQAE/yUSap/lTjjKJOMySkyj691h5rfzWV2nTNm0nPrsPN # uCaa+6T5Wd9V5SUxlHsft3w0D9p6IvxZ7wxui8gHnaWr96aKEqLcVmJuPdmb+ku3 # kDblROeMkx/febxt5WeI1uEDc413MkCapOqh6BVvlFc73ppKLHZoiWYCZLoBLDh3 # wOTtZaHDzRGBeCXBJ+yEwxZYeXTcDcqSo6pDOa2gtHNNOqP6i+YR5zLnXkJduWNN # qA4iNmQXaV8CgIpaQvJ1T/X6ITQIt0XAws8SFaxkBaNl0FwuFN0UJlzI36HDYAZB # pdGDnNqPiFbSL7ka0OUO92rbbdSepWQvNIa1Vzd6fyHV+R1Pc+2OMoqq4qf99Zzl # 4Ap17GRVOvxD+z8TvMNPYzt43skL//Fbn1UC2+HF79AZP7xY6ptVbx5aR35l4cF8 # Fx8E4qW1EblLLr891pWZv0bY7/VA9OIRTgJmcKeLfEZR5orlQLYcxCBAQ/Cxj1ir # eMb4JY4dsakPer0/g0v0Wn5UzYxqLVz2mPQ7fRj3JGsaihN3Jaig11AWa9pPOAdj # eWR675VgIyzZjowdOrkKYXeIWGKrERdafS1WBHq882KZZvwYy2OwjdYw # SIG # End signature block |