Execution.psm1
|
function Set-ScriptArgs { [CmdletBinding()] param( [Parameter()] [System.Collections.Generic.Dictionary`2[System.String, System.Object]] $BoundParameters, [Parameter()] [System.Collections.Generic.List`1[System.Object]] $UnboundArguments ) $global:PSCommandPath = $MyInvocation.PSCommandPath Log trace "global:PSCommandPath: '$global:PSCommandPath'" $argumentList = [System.Collections.ArrayList]@() $parameters = (Get-Command $global:PSCommandPath).Parameters Log trace 'Parse bound parameters...' foreach ($key in $BoundParameters.Keys) { $type = $parameters.Values | Where-Object { $_.Name -eq $key } | Select-Object -ExpandProperty ParameterType Log trace "Parametertype: '$($type.FullName)'" switch ($type) { ([System.Management.Automation.SwitchParameter]) { $value = '$true' } ([System.Boolean]) { try { $boolValue = [System.Convert]::ToBoolean($BoundParameters[$key]) } catch { $boolValue = $false } $value = if ($boolValue) { '$true' } else { '$false' } } default { $value = $BoundParameters[$key] } } Log trace "-$key`:$value" $argumentList.Add("-$key`:$value") > $null } Log trace 'Parse bound parameters... Done.' Log trace 'Parse unbound arguments...' foreach ($arg in $UnboundArguments) { Log trace "$arg" $argumentList.Add($arg) > $null } Log trace 'Parse unbound arguments... Done.' $global:ScriptArgs = $argumentList Log trace "global:ScriptArgs: '$global:ScriptArgs'" } function Invoke-SelfElevation() { # Self-elevate the script if required if ($PSVersionTable.Platform -eq 'unix') { if ((id -u) -ne 0) { Log trace 'Try self elevation on Unix platform...' $executionInfo = Get-ExecutionInfo & sudo $executionInfo.Executable @($executionInfo.ArgumentList) exit 0 } } else { if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'administrator')) { if ([int] (Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -ge 6000) { Log trace 'Try self elevation on Windows platform...' $executionInfo = Get-ExecutionInfo $hashAndFile = Get-HashAndFile -Executable $executionInfo.Executable -Arguments $executionInfo.Arguments Log trace "Write mutex file with hash to '$($hashAndFile.File)'" New-Item -Path $hashAndFile.File -ItemType File -Force > $null Log trace "Start-Process -FilePath $($executionInfo.Executable) -ArgumentList $($executionInfo.Arguments) -WorkingDirectory $PSScriptRoot -Verb runas" Start-Process -FilePath $executionInfo.Executable -ArgumentList $executionInfo.Arguments -WorkingDirectory $PSScriptRoot -Verb runas exit 0 } } } } function Exit-WithAndWaitOnExplorer([int] $ExitCode) { if ($PSVersionTable.Platform -ne 'unix') { $executionInfo = Get-ExecutionInfo $hashAndFile = Get-HashAndFile -Executable $executionInfo.Executable -Arguments $executionInfo.Arguments Log trace "Check if mutex file exists '$($hashAndFile.FileName)'..." $mutexFileExists = Test-Path -Path $hashAndFile.File if ($mutexFileExists) { Log trace "Mutex file exists '$($hashAndFile.File)'" Remove-Item -Path $hashAndFile.File -Force > $null } if ((Get-ScriptIsCalledFromUI) -or $mutexFileExists) { Log info 'Press any key to continue . . . ' $HOST.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown') > $null $HOST.UI.RawUI.FlushInputBuffer() } } exit $ExitCode } function Get-ScriptIsCalledFromUI() { # Check distance from current process to 'explorer.exe' to # determine if the user start the script in explorer or UI. # If the hierarchy is like this above, then we can determine # that the user executed the script from 'explorer.exe' UI. # # 1) pwsh.exe|powershell.exe # 2) -> cmd.exe # 3) -> explorer.exe $calledFromUI = $false $processNames = [System.Collections.ArrayList]@() $currentProcessId = $PID $indent = 2 Log trace 'ProcessHierarchy:' while ($true) { $currentProcess = Get-CimInstance Win32_Process -Filter "ProcessId = $currentProcessId" $currentProcessName = $currentProcess.Name if (-not $currentProcessId -or -not $currentProcessName) { # We are on the top -> break break } Log trace "$(''.PadLeft($indent))$currentProcessName -> $currentProcessId" $processNames.Add($currentProcessName) > $null $indent += 2 $currentProcessId = $currentProcess.ParentProcessId } $expectedProcessNames = @('(pwsh.exe)|(powershell.exe)', 'cmd.exe', 'explorer.exe') if ($processNames.Count -ge $expectedProcessNames.Count) { $indent = 2 Log trace 'Check ProcessHierarchy:' for ($i = 0; $i -lt $expectedProcessNames.Count; $i++) { if ($processNames[$i] -imatch $expectedProcessNames[$i]) { $calledFromUI = $true Log trace "$(''.PadLeft($indent))$($processNames[$i]) -> $($expectedProcessNames[$i]) -> OK" } else { $calledFromUI = $false Log trace "$(''.PadLeft($indent))$($processNames[$i]) -> $($expectedProcessNames[$i]) -> FAIL" break } $indent += 2 } } return $calledFromUI } function Get-ExecutionInfo() { $executable = Get-Process -Id $PID | Select-Object -ExpandProperty MainModule | Select-Object -ExpandProperty FileName $argumentList = @('-NoProfile', '-ExecutionPolicy', 'Unrestricted', '-Command', "`"& `"$global:PSCommandPath`" $global:ScriptArgs`"") $arguments = "$argumentList" Log trace "executable: $executable" Log trace "argumentList: $argumentList" Log trace "arguments: $arguments" $executionInfo = [pscustomobject][ordered]@{ Executable = $executable ArgumentList = $argumentList Arguments = $arguments } return $executionInfo } function Get-HashAndFile([string] $Executable, [string] $Arguments) { Log trace "Get-HashAndFile -> `$Executable: '$Executable' | `$Arguments: '$Arguments'" $value = "$Executable $Arguments".ToLowerInvariant() $fileName = "psec-$(Get-Checksum -Value $value)" $file = (Join-Path $env:TEMP $fileName) $object = [pscustomobject][ordered]@{ FileName = $fileName File = $file } return $object } function Set-PSScriptID() { Log trace 'Set-PSScriptID' $callStack = Get-PSCallStack $callerInvocation = $callStack[1].InvocationInfo $commandPath = $callStack[0].InvocationInfo.PSCommandPath Log trace " commandPath: '$commandPath'" $argumentList = [System.Collections.ArrayList]@() $parameters = (Get-Command $commandPath).Parameters Log trace ' Parse bound parameters...' foreach ($key in $callerInvocation.BoundParameters.Keys) { $type = $parameters.Values | Where-Object { $_.Name -eq $key } | Select-Object -ExpandProperty ParameterType Log trace " Parametertype: '$($type.FullName)'" switch ($type) { ([System.Management.Automation.SwitchParameter]) { $value = '$true' } ([System.Boolean]) { try { $boolValue = [System.Convert]::ToBoolean($callerInvocation.BoundParameters[$key]) } catch { $boolValue = $false } $value = if ($boolValue) { '$true' } else { '$false' } } default { $value = $callerInvocation.BoundParameters[$key] } } Log trace " -$key`:$value" $argumentList.Add("-$key`:$value") > $null } Log trace ' Parse unbound arguments...' foreach ($arg in $callerInvocation.UnboundArguments) { Log trace "$arg" $argumentList.Add($arg) > $null } # Construct command and arguments $executable = Get-Process -Id $PID | Select-Object -ExpandProperty MainModule | Select-Object -ExpandProperty FileName # Normalize executable $executable = "`"$(Get-CanonicalPath $executable)`"" Log trace " executable: '$executable'" $argumentList = @('-NoProfile', '-ExecutionPolicy', 'Unrestricted', '-Command', "`"& `"`"`"$commandPath`"`"`" $argumentList`"") Log trace " argumentList: '$argumentList'" $fileHash = Get-FileHashFromCommand $executable $argumentList $scriptID = [guid]::NewGuid().Guid.Replace('-', '') Log trace " Set PSScriptInfos for scriptID: '$scriptID'" $global:PSScriptInfos[$scriptID] = [pscustomobject][ordered]@{ Executable = $executable ScriptPath = $commandPath ArgumentList = $argumentList } $global:PSScriptInfos[$scriptID] | Add-Member -MemberType ScriptProperty -Name 'Arguments' -Value { "$($this.ArgumentList)" } $global:PSScriptInfos[$scriptID] | Add-Member -MemberType NoteProperty -Name 'FileHash' -Value $fileHash Log trace " Executable: '$($global:PSScriptInfos[$scriptID].Executable)'" Log trace " ScriptPath: '$($global:PSScriptInfos[$scriptID].ScriptPath)'" Log trace " ArgumentList: '$($global:PSScriptInfos[$scriptID].ArgumentList)'" Log trace " Arguments: '$($global:PSScriptInfos[$scriptID].Arguments)'" Log trace " FileHash: '$($global:PSScriptInfos[$scriptID].FileHash)'" Set-Variable -Name 'PSScriptID' -Value $scriptID -Scope 1 return $scriptID } function Get-CanonicalPath([string] $Path) { if (-not (Test-Path -Path $Path -PathType Any)) { return $Path } $dir = [System.IO.DirectoryInfo]::new($Path) if ($null -ne $dir.Parent) { return Join-Path (Get-CanonicalPath -Path $dir.Parent.FullName) ($dir.Parent.GetFileSystemInfos($dir.Name)[0].Name) } else { return $dir.Name.ToUpperInvariant() } } function Restart-SelfElevated([string] $PSScriptID) { Log trace 'Restart-SelfElevated' $scriptID = $PSScriptID Log trace " -> `$scriptID: '$scriptID'" # Self-elevate the script if required if ($PSVersionTable.Platform -eq 'unix') { if ((id -u) -ne 0) { Log trace ' Try self elevation on Unix platform...' Log trace " Get PSScriptInfos for scriptID: '$scriptID'" $scriptInfo = $global:PSScriptInfos[$scriptID] & sudo $scriptInfo.Executable @($scriptInfo.ArgumentList) exit 0 } } else { if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'administrator')) { if ([int] (Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -ge 6000) { Log trace ' Try self elevation on Windows platform...' Log trace " Get PSScriptInfos for scriptID: '$scriptID'" $scriptInfo = $global:PSScriptInfos[$scriptID] Log trace " Write mutex file -> '$($scriptInfo.FileHash.File)'" New-Item -Path $scriptInfo.FileHash.File -ItemType File -Force > $null Log trace " -> Start-Process -FilePath $($scriptInfo.Executable) -ArgumentList $($scriptInfo.Arguments) -WorkingDirectory $PSScriptRoot -Verb runas" Start-Process -FilePath $scriptInfo.Executable -ArgumentList $scriptInfo.Arguments -WorkingDirectory $PSScriptRoot -Verb runas exit 0 } } } } function Exit-AndWaitOnUI([int] $ExitCode, [string] $PSScriptID) { Log trace 'Exit-AndWaitOnUI' Log trace " -> `$ExitCode: '$ExitCode'" $scriptID = $PSScriptID Log trace " -> `$scriptID: '$scriptID'" if ($PSVersionTable.Platform -ne 'unix') { Log trace " Get PSScriptInfos for scriptID: '$scriptID'" $scriptInfo = $global:PSScriptInfos[$scriptID] Log trace " Check if mutex file exists '$($scriptInfo.FileHash.FileName)'..." $mutexFileExists = Test-Path -Path $scriptInfo.FileHash.File if ($mutexFileExists) { Log trace "Remove existing mutex file -> '$($scriptInfo.FileHash.File)'" Remove-Item -Path $scriptInfo.FileHash.File -Force > $null } if ((Get-ScriptIsCalledFromUI) -or $mutexFileExists) { Log info 'Press any key to continue . . . ' $HOST.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown') > $null $HOST.UI.RawUI.FlushInputBuffer() } } exit $ExitCode } function Get-FileHashFromCommand([string] $Executable, [string[]] $ArgumentList) { Log trace 'Get-FileHashFromCommand' Log trace " -> `$Executable: '$Command'" Log trace " -> `$ArgumentList: '$ArgumentList'" $combinedValue = "$Executable $ArgumentList" Log trace " combinedValue: '$combinedValue'" $checksum = Get-Checksum -Value $combinedValue $fileName = "psec-$checksum" $file = (Join-Path $env:TEMP $fileName) Log trace " checksum: '$checksum'" Log trace " checksum: '$fileName'" Log trace " checksum: '$file'" $object = [pscustomobject][ordered]@{ FileName = $fileName File = $file Checksum = $checksum } return $object } function Invoke-Process { [CmdletBinding()] param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $Command, [Parameter(ValueFromRemainingArguments = $true)] [string[]] $CommandArgs ) $commandString = $Command if ($commandArgs) { $commandString += " $commandArgs" } Write-Host "Execute: '$commandString'" -ForegroundColor DarkYellow $startInfo = New-Object System.Diagnostics.ProcessStartInfo $startInfo.FileName = $command $startInfo.Arguments = $commandArgs $startInfo.UseShellExecute = $false $startInfo.WorkingDirectory = Get-Location $process = New-Object System.Diagnostics.Process $process.StartInfo = $startInfo $process.Start() > $null $finished = $false try { while (-not $process.WaitForExit(100)) { # Non-blocking loop done to allow ctr-c interrupts } $finished = $true return $global:LASTEXITCODE = $process.ExitCode } finally { # If we didn't finish then an error occured or the user hit ctrl-c. Either way kill the process if (-not $finished) { $process.Kill() } } } function Start-NativeExecution() { $backupEap = $Script:ErrorActionPreference $Script:ErrorActionPreference = 'Continue' try { if ($args.Length -lt 1) { Log warning 'No arguments specified' return } Log trace "Execute: '$args'" $command = $args[0] | Get-QuotedPath $arguments = $args | Select-Object -Skip 1 | Get-QuotedPath Log trace "Command: '$command'" if ($arguments -and $arguments.Length -gt 0) { Log trace "Arguments: '$arguments'" } $wrapperScriptBlock = [ScriptBlock]::Create("& $command $arguments") $calledFromPrompt = Test-CalledFromPrompt if ($calledFromPrompt) { $wrapperScriptBlock = [ScriptBlock]::Create("& $command $arguments") } else { $wrapperScriptBlock = [ScriptBlock]::Create("& $command $arguments 2>&1") } Log trace "WrapperScriptBlock: '$wrapperScriptBlock'" $messages = & $wrapperScriptBlock # NOTE: If $wrapperScriptBlock's command doesn't have a native invocation, # $LASTEXITCODE will point to the obsolete value Log trace "LASTEXITCODE: $LASTEXITCODE" Log trace "`$?: $?" # Need to check both of these cases for errors as they represent different items # - $?: Did the powershell script block throw an error # - $LASTEXITCODE: Did a windows command executed by the script block end in error if ((-not $?) -or ($LASTEXITCODE -and $LASTEXITCODE -ne 0)) { if ($Error -ne $null) { Log error $Error[0] } Log error "Execution of '$args' failed with exit code $LASTEXITCODE." $logLevel = 'error' } else { $logLevel = 'info' } if ($calledFromPrompt -and (Test-Path Variable:\messages)) { if ($messages -is [System.Object[]]) { foreach ($message in $messages) { if ($message.GetType() -eq [System.Management.Automation.ErrorRecord]) { $lines = $message.Exception.Message.Split("`r`n", [System.StringSplitOptions]::RemoveEmptyEntries) } elseif ($message.GetType() -eq [string]) { $lines = $message.Split("`r`n", [System.StringSplitOptions]::RemoveEmptyEntries) } if (Test-Path Variable:\lines) { $lines | Log $logLevel } } } if ($messages -is [string]) { $messages.Split("`r`n", [System.StringSplitOptions]::RemoveEmptyEntries) | Log $logLevel } } } catch { if ($_.Exception -and $_.Exception.Message) { $_.Exception.Message.Split("`r`n", [System.StringSplitOptions]::RemoveEmptyEntries) | Log error } } finally { if (-not (Test-Path Variable:\messages)) { $messages = $null } $Script:ErrorActionPreference = $backupEap } return $messages } function Get-QuotedPath { [CmdletBinding()] param( [Parameter(Mandatory, ValueFromPipeline)] [string] $Path ) process { Log trace "Path: $Path" if ($Path -match '\s') { return "`"$Path`"" } else { return $Path } } } function Test-CalledFromPrompt() { $command = (Get-PSCallStack)[-2].Command Log trace "PromptCommand: $command" return ($command -eq 'prompt') } function Clear-TempDirectories { [CmdletBinding()] param( [Parameter()] [string[]] $AdditionalPaths, [Parameter()] [switch] $TryRun ) $tempDirName = 'temp' $dirs = [System.Collections.ArrayList]@() Add-ItemWhenExists -Item (Join-Path $env:ProgramFiles $tempDirName) -List $dirs Add-ItemWhenExists -Item (Join-Path ${env:ProgramFiles(x86)} $tempDirName) -List $dirs Add-ItemWhenExists -Item (Join-Path $env:windir $tempDirName) -List $dirs $userDirs = Get-ChildItem 'C:/Users' -Directory -Force foreach ($userDir in $userDirs) { Add-ItemWhenExists -Item (Join-Path $userDir.FullName "AppData/Local/$tempDirName") -List $dirs Add-ItemWhenExists -Item (Join-Path $userDir.FullName "AppData/LocalLow/$tempDirName") -List $dirs Add-ItemWhenExists -Item (Join-Path $userDir.FullName "AppData/Roaming/$tempDirName") -List $dirs } if ($AdditionalPaths) { $AdditionalPaths | Add-ItemWhenExists -List $dirs } for ($i = 0; $i -lt $dirs.Count; $i++) { $items = $dirs[$i] | Get-ChildItem -Recurse -Force -ErrorAction SilentlyContinue | Select-Object -ExpandProperty FullName | Sort-Object -Descending -Property Length $total = $items | Measure-Object | Select-Object -ExpandProperty Count Log trace "Found '$total' items in '$($dirs[$i])' to remove" Write-Progress -Id 1 -Activity 'Clear TEMP directories' -Status "Step $($($i + 1).ToString().PadLeft($dirs.Count.ToString().Length)) of $($dirs.Count)" -CurrentOperation "Remove all items in '$($dirs[$i])'" -PercentComplete (($i + 1) / $dirs.Count * 100) for ($ii = 0; $ii -lt $items.Count; $ii++) { Write-Progress -Id 2 -ParentId 1 -Activity 'Processing items' -Status "Item $($($ii + 1).ToString().PadLeft($items.Count.ToString().Length)) of $($items.Count)" -CurrentOperation "Remove item '$($items[$ii])'" -PercentComplete (($ii + 1) / $items.Count * 100) if (-not $TryRun) { Remove-ItemSafe -Path $items[$ii] -Retries 16 -Milliseconds 10 } else { Start-Sleep -Milliseconds 1 } } } } function Add-ItemWhenExists { [CmdletBinding()] param( [Parameter(ValueFromPipeline)] [string] $Item, [Parameter()] [System.Collections.ArrayList] $List ) process { if ($Item -and (Test-Path $Item)) { $List.Add($Item) > $null } } } function Remove-ItemSafe { [CmdletBinding()] param( [Parameter(Mandatory, ValueFromPipeline)] [string] $Path, [Parameter()] [int] $Retries = 255, [Parameter()] [int] $Milliseconds = 75 ) process { Log trace "Remove item safe '$Path'..." while ($path -and (Test-Path -Path $Path -ErrorAction SilentlyContinue) -and ($Retries -gt 0)) { try { if ((Test-Path -Path $Path -PathType Container) -and ((Get-ChildItem -Path $Path -Recurse -Force -ErrorAction SilentlyContinue | Measure-Object | Select-Object -ExpandProperty Count) -gt 0)) { Remove-Item -Path $Path -Recurse -Force -ErrorAction SilentlyContinue > $null } else { Remove-Item -Path $path -Force -ErrorAction SilentlyContinue > $null } } catch { Start-Sleep -Milliseconds $Milliseconds } finally { --$Retries } } } } function Invoke-WhenFileChanged { [CmdletBinding()] param ( [Parameter(Mandatory)] [string] $File, [Parameter(Mandatory )] [string] $Action, [Parameter()] [int] $PoolingIntervalInMS = 100 ) process { $global:FileChanged = $false $executeCounter = 0 $File = Resolve-Path $File $filePath = Split-Path $File -Parent $fileName = Split-Path $File -Leaf $scriptBlock = [scriptblock]::Create($Action) $watcher = New-Object IO.FileSystemWatcher $filePath, $fileName -Property @{ IncludeSubdirectories = $false EnableRaisingEvents = $true } Log info "::: [$(Get-Date -Format s)] Register event..." $onChange = Register-ObjectEvent $watcher Changed -Action { $global:FileChanged = $true } [System.Console]::TreatControlCAsInput = $true try { while ($true) { if ($global:FileChanged) { ++$executeCounter Log info "::: [$(Get-Date -Format s)] Execute (${executeCounter}): ${Action}" & $scriptBlock $global:FileChanged = $false } if ($Host.UI.RawUI.KeyAvailable -and (3 -eq [int]$Host.UI.RawUI.ReadKey('AllowCtrlC, IncludeKeyUp, NoEcho').Character)) { Log info "::: [$(Get-Date -Format s)] Unregister event..." Unregister-Event -SourceIdentifier $onChange.Name return } Start-Sleep -Milliseconds $PoolingIntervalInMS } } catch [Exception] { Log info "::: [$(Get-Date -Format s)] Unregister event..." Unregister-Event -SourceIdentifier $onChange.Name } } end { [System.Console]::TreatControlCAsInput = $false } } $global:PSScriptInfos = [hashtable]@{} # SIG # Begin signature block # MIIn8gYJKoZIhvcNAQcCoIIn4zCCJ98CAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCuJhMxOgomG0ek # 9dsLFRVYyx3BFu6i0LQrXDnbHGCi66CCIP4wggWNMIIEdaADAgECAhAOmxiO+dAt # 5+/bUOIIQBhaMA0GCSqGSIb3DQEBDAUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQK # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNV # BAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0yMjA4MDEwMDAwMDBa # Fw0zMTExMDkyMzU5NTlaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2Vy # dCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lD # ZXJ0IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC # ggIBAL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsbhA3E # MB/zG6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKy # unWZanMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGbNOsF # xl7sWxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclPXuU1 # 5zHL2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJB # MtfbBHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFPObUR # WBf3JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTvkpI6 # nj3cAORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWMcCxB # YKqxYxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5S # UUd0viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+x # q4aLT8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjggE6MIIB # NjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTs1+OC0nFdZEzfLmc/57qYrhwP # TzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzAOBgNVHQ8BAf8EBAMC # AYYweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp # Y2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNv # bS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwRQYDVR0fBD4wPDA6oDigNoY0 # aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENB # LmNybDARBgNVHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQEMBQADggEBAHCgv0Nc # Vec4X6CjdBs9thbX979XB72arKGHLOyFXqkauyL4hxppVCLtpIh3bb0aFPQTSnov # Lbc47/T/gLn4offyct4kvFIDyE7QKt76LVbP+fT3rDB6mouyXtTP0UNEm0Mh65Zy # oUi0mcudT6cGAxN3J0TU53/oWajwvy8LpunyNDzs9wPHh6jSTEAZNUZqaVSwuKFW # juyk1T3osdz9HNj0d1pcVIxv76FQPfx2CWiEn2/K2yCNNWAcAgPLILCsWKAOQGPF # mCLBsln1VWvPJ6tsds5vIy30fnFqI2si/xK4VC0nftg62fC2h5b9W9FcrBjDTZ9z # twGpn1eqXijiuZQwggahMIIEiaADAgECAhAHhD2tAcEVwnTuQacoIkZ5MA0GCSqG # SIb3DQEBCwUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRy # dXN0ZWQgUm9vdCBHNDAeFw0yMjA2MjMwMDAwMDBaFw0zMjA2MjIyMzU5NTlaMFox # CzAJBgNVBAYTAkxWMRkwFwYDVQQKExBFblZlcnMgR3JvdXAgU0lBMTAwLgYDVQQD # EydHb0dldFNTTCBHNCBDUyBSU0E0MDk2IFNIQTI1NiAyMDIyIENBLTEwggIiMA0G # CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCtHvQHskNmiqJndyWVCqX4FtYp5FfJ # LO9Sh0BuwXuvBeNYt21xf8h/pLJ/7YzeKcNq9z4zEhecqtD0xhbvSB8ksBAfWBMZ # O0NLfOT0j7WyNuD7rv+ZFza+mxIQ79s1dCiwUMwGonaoDK7mqZfDpKEExR6UyKBh # 3aatT73U2Imx/x+fYTmQFq+N8FrLs6Fh6YEGWJTgsxyw1fAChCfgtEcZkdtcgK7q # uqskHtW6PJ9l5VNJ7T3WXpznsOOxrz3qx0CzWjwK8+3Kv2X6piWvd8YRfAOycSrT # 4/PM0cHLFc5xs/4m/ek4FCnYSem43doFftBxZBQkHKoPW3Bt6VIrhVIwvO7hrUjh # chJJZYdSld3bANDviJ5/ToP7ENv97U9MtKFvmC5dzd1p4HxFR0p5wWmYQbW+y3RF # m0np6H9m57MUMNp0ysmdJjb0f7+dVLX3OEBUb6H+r1LRLZT/xEOTuwOxGg2S4w25 # KGL9SCBUW4nkBljPHeJToU+THt0P8ZQf4B9IFlGxtLK0g3uOAnwSFgKtmNjhkTl8 # caLAQwbgEINCqrhc0b6k2Z8+QwgVAL0nIuzM9ckKP8xtIcWg85L3/l0cTkHQde+j # KGDG2CdxBHtflLIUtwqD7JA2uCxWlIzRNgwT0kH2en0+QV8KziSGaqO2r06kwboq # 2/xy4e98CEfSYwIDAQABo4IBWTCCAVUwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNV # HQ4EFgQUyfwQ71DIy2t/vQhE7zpik+1bXpowHwYDVR0jBBgwFoAU7NfjgtJxXWRM # 3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMD # MHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNl # cnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20v # RGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNVHR8EPDA6MDigNqA0hjJodHRw # Oi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNybDAc # BgNVHSAEFTATMAcGBWeBDAEDMAgGBmeBDAEEATANBgkqhkiG9w0BAQsFAAOCAgEA # C9sK17IdmKTCUatEs7+yewhJnJ4tyrLwNEnfl6HrG8Pm7HZ0b+5Jc+GGqJT8kRc7 # mihuVrdsYNHdicueDL9imhtCusI/rUmjwhtflp+XgLkmgLGrmsEho1b+lGiRp7LC # /10di8SAOilDkHj5Zx142xRvBrrWj9eOdSGHwYubAsEd6CDojwcaVz9pfXMzYO3k # c0O6PXg1TkcgkYlCUAuDHuk/sZx68W0FVj1P2iMh+VUq9lL1puroAydoeWVUh/+c # MXeqfgpBqlAW+r8ma5F6yKL0stVQH8vYb1ES0mJSIPyIfkIjC1V0pbZS3p0QWsKa # afEor8fLfLNfSxntVI/ugut0+6ekluPWRpEXH+JAiNdRjbLbZchCREe3/Xl0Ylwk # A+eQVJfM0A7XiuFtY/mOpK2AN+E25t5mQYFhpdxZX5LTDKWgDnb+A6QnEt4iNyuk # cLaJuS8IPgPz0E2ALZLt3Rqs+lXifK/GwnNIWQNbf7FmLDB9ph8i8dvsR1hsjc2K # PEW4bAsbvLcz8hN1zE1/QbOV92vDGoFjwZOi2koQ+UyEh0e8jDFHAKJeTI+p8EPE # /mqvojLFAnt31yXIA2tjt0ERtsjkhBNmZY6SEOfnIoOwvyqavLPya1Ut3/2cOFLu # NQ8Ql6HaZsNQErnnzn+ZEAaUTkPZaeVyoHIkODECLzkwgga0MIIEnKADAgECAhAN # x6xXBf8hmS5AQyIMOkmGMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAlVTMRUw # EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x # ITAfBgNVBAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0yNTA1MDcwMDAw # MDBaFw0zODAxMTQyMzU5NTlaMGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdp # Q2VydCwgSW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBUaW1lU3Rh # bXBpbmcgUlNBNDA5NiBTSEEyNTYgMjAyNSBDQTEwggIiMA0GCSqGSIb3DQEBAQUA # A4ICDwAwggIKAoICAQC0eDHTCphBcr48RsAcrHXbo0ZodLRRF51NrY0NlLWZloMs # VO1DahGPNRcybEKq+RuwOnPhof6pvF4uGjwjqNjfEvUi6wuim5bap+0lgloM2zX4 # kftn5B1IpYzTqpyFQ/4Bt0mAxAHeHYNnQxqXmRinvuNgxVBdJkf77S2uPoCj7GH8 # BLuxBG5AvftBdsOECS1UkxBvMgEdgkFiDNYiOTx4OtiFcMSkqTtF2hfQz3zQSku2 # Ws3IfDReb6e3mmdglTcaarps0wjUjsZvkgFkriK9tUKJm/s80FiocSk1VYLZlDwF # t+cVFBURJg6zMUjZa/zbCclF83bRVFLeGkuAhHiGPMvSGmhgaTzVyhYn4p0+8y9o # HRaQT/aofEnS5xLrfxnGpTXiUOeSLsJygoLPp66bkDX1ZlAeSpQl92QOMeRxykvq # 6gbylsXQskBBBnGy3tW/AMOMCZIVNSaz7BX8VtYGqLt9MmeOreGPRdtBx3yGOP+r # x3rKWDEJlIqLXvJWnY0v5ydPpOjL6s36czwzsucuoKs7Yk/ehb//Wx+5kMqIMRvU # BDx6z1ev+7psNOdgJMoiwOrUG2ZdSoQbU2rMkpLiQ6bGRinZbI4OLu9BMIFm1UUl # 9VnePs6BaaeEWvjJSjNm2qA+sdFUeEY0qVjPKOWug/G6X5uAiynM7Bu2ayBjUwID # AQABo4IBXTCCAVkwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU729TSunk # Bnx6yuKQVvYv1Ensy04wHwYDVR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08w # DgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMIMHcGCCsGAQUFBwEB # BGswaTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsG # AQUFBzAChjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVz # dGVkUm9vdEc0LmNydDBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdp # Y2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNybDAgBgNVHSAEGTAXMAgG # BmeBDAEEAjALBglghkgBhv1sBwEwDQYJKoZIhvcNAQELBQADggIBABfO+xaAHP4H # PRF2cTC9vgvItTSmf83Qh8WIGjB/T8ObXAZz8OjuhUxjaaFdleMM0lBryPTQM2qE # JPe36zwbSI/mS83afsl3YTj+IQhQE7jU/kXjjytJgnn0hvrV6hqWGd3rLAUt6vJy # 9lMDPjTLxLgXf9r5nWMQwr8Myb9rEVKChHyfpzee5kH0F8HABBgr0UdqirZ7bowe # 9Vj2AIMD8liyrukZ2iA/wdG2th9y1IsA0QF8dTXqvcnTmpfeQh35k5zOCPmSNq1U # H410ANVko43+Cdmu4y81hjajV/gxdEkMx1NKU4uHQcKfZxAvBAKqMVuqte69M9J6 # A47OvgRaPs+2ykgcGV00TYr2Lr3ty9qIijanrUR3anzEwlvzZiiyfTPjLbnFRsjs # Yg39OlV8cipDoq7+qNNjqFzeGxcytL5TTLL4ZaoBdqbhOhZ3ZRDUphPvSRmMThi0 # vw9vODRzW6AxnJll38F0cuJG7uEBYTptMSbhdhGQDpOXgpIUsWTjd6xpR6oaQf/D # Jbg3s6KCLPAlZ66RzIg9sC+NJpud/v4+7RWsWCiKi9EOLLHfMR2ZyJ/+xhCx9yHb # xtl5TPau1j/1MIDpMPx0LckTetiSuEtQvLsNz3Qbp7wGWqbIiOWCnb5WqxL3/BAP # vIXKUjPSxyZsq8WhbaM2tszWkPZPubdcMIIG7TCCBNWgAwIBAgIQCoDvGEuN8QWC # 0cR2p5V0aDANBgkqhkiG9w0BAQsFADBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMO # RGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgVGlt # ZVN0YW1waW5nIFJTQTQwOTYgU0hBMjU2IDIwMjUgQ0ExMB4XDTI1MDYwNDAwMDAw # MFoXDTM2MDkwMzIzNTk1OVowYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lD # ZXJ0LCBJbmMuMTswOQYDVQQDEzJEaWdpQ2VydCBTSEEyNTYgUlNBNDA5NiBUaW1l # c3RhbXAgUmVzcG9uZGVyIDIwMjUgMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC # AgoCggIBANBGrC0Sxp7Q6q5gVrMrV7pvUf+GcAoB38o3zBlCMGMyqJnfFNZx+wvA # 69HFTBdwbHwBSOeLpvPnZ8ZN+vo8dE2/pPvOx/Vj8TchTySA2R4QKpVD7dvNZh6w # W2R6kSu9RJt/4QhguSssp3qome7MrxVyfQO9sMx6ZAWjFDYOzDi8SOhPUWlLnh00 # Cll8pjrUcCV3K3E0zz09ldQ//nBZZREr4h/GI6Dxb2UoyrN0ijtUDVHRXdmncOOM # A3CoB/iUSROUINDT98oksouTMYFOnHoRh6+86Ltc5zjPKHW5KqCvpSduSwhwUmot # uQhcg9tw2YD3w6ySSSu+3qU8DD+nigNJFmt6LAHvH3KSuNLoZLc1Hf2JNMVL4Q1O # pbybpMe46YceNA0LfNsnqcnpJeItK/DhKbPxTTuGoX7wJNdoRORVbPR1VVnDuSeH # VZlc4seAO+6d2sC26/PQPdP51ho1zBp+xUIZkpSFA8vWdoUoHLWnqWU3dCCyFG1r # oSrgHjSHlq8xymLnjCbSLZ49kPmk8iyyizNDIXj//cOgrY7rlRyTlaCCfw7aSURO # wnu7zER6EaJ+AliL7ojTdS5PWPsWeupWs7NpChUk555K096V1hE0yZIXe+giAwW0 # 0aHzrDchIc2bQhpp0IoKRR7YufAkprxMiXAJQ1XCmnCfgPf8+3mnAgMBAAGjggGV # MIIBkTAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTkO/zyMe39/dfzkXFjGVBDz2GM # 6DAfBgNVHSMEGDAWgBTvb1NK6eQGfHrK4pBW9i/USezLTjAOBgNVHQ8BAf8EBAMC # B4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwgZUGCCsGAQUFBwEBBIGIMIGFMCQG # CCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wXQYIKwYBBQUHMAKG # UWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFRp # bWVTdGFtcGluZ1JTQTQwOTZTSEEyNTYyMDI1Q0ExLmNydDBfBgNVHR8EWDBWMFSg # UqBQhk5odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRU # aW1lU3RhbXBpbmdSU0E0MDk2U0hBMjU2MjAyNUNBMS5jcmwwIAYDVR0gBBkwFzAI # BgZngQwBBAIwCwYJYIZIAYb9bAcBMA0GCSqGSIb3DQEBCwUAA4ICAQBlKq3xHCcE # ua5gQezRCESeY0ByIfjk9iJP2zWLpQq1b4URGnwWBdEZD9gBq9fNaNmFj6Eh8/Ym # RDfxT7C0k8FUFqNh+tshgb4O6Lgjg8K8elC4+oWCqnU/ML9lFfim8/9yJmZSe2F8 # AQ/UdKFOtj7YMTmqPO9mzskgiC3QYIUP2S3HQvHG1FDu+WUqW4daIqToXFE/JQ/E # ABgfZXLWU0ziTN6R3ygQBHMUBaB5bdrPbF6MRYs03h4obEMnxYOX8VBRKe1uNnzQ # VTeLni2nHkX/QqvXnNb+YkDFkxUGtMTaiLR9wjxUxu2hECZpqyU1d0IbX6Wq8/gV # utDojBIFeRlqAcuEVT0cKsb+zJNEsuEB7O7/cuvTQasnM9AWcIQfVjnzrvwiCZ85 # EE8LUkqRhoS3Y50OHgaY7T/lwd6UArb+BOVAkg2oOvol/DJgddJ35XTxfUlQ+8Hg # gt8l2Yv7roancJIFcbojBcxlRcGG0LIhp6GvReQGgMgYxQbV1S3CrWqZzBt1R9xJ # gKf47CdxVRd/ndUlQ05oxYy2zRWVFjF7mcr4C34Mj3ocCVccAvlKV9jEnstrniLv # UxxVZE/rptb7IRE2lskKPIJgbaP5t2nGj/ULLi49xTcBZU8atufk+EMF/cWuiC7P # OGT75qaL6vdCvHlshtjdNXOCIUjsarfNZzCCBxswggUDoAMCAQICEAYFIuuX3jJX # cLz8AeYyZmYwDQYJKoZIhvcNAQELBQAwWjELMAkGA1UEBhMCTFYxGTAXBgNVBAoT # EEVuVmVycyBHcm91cCBTSUExMDAuBgNVBAMTJ0dvR2V0U1NMIEc0IENTIFJTQTQw # OTYgU0hBMjU2IDIwMjIgQ0EtMTAeFw0yNTEyMjkwMDAwMDBaFw0yNjEyMjgyMzU5 # NTlaMGExCzAJBgNVBAYTAkRFMQ8wDQYDVQQIEwZCYXllcm4xETAPBgNVBAcTCEZh # cmNoYW50MRYwFAYDVQQKEw1NYW51ZWwgVGFuemVyMRYwFAYDVQQDEw1NYW51ZWwg # VGFuemVyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuxv/b0+nhaEE # 94ewtCEHJFhCdgrwn6iF1lZ41Y40alX0LnSGBniZxw480yw+F9o6qhhprIpKvEoW # WW1q+KNMxjdbLgKPlMcudU8DTfUVxKRxlVuqSMdizawGlQgwtwrj5RDsWEE2k0nq # guNejIRWrWDn6JblBaj/WIx8DZ9YuYl6egi/KtJF5lYC6StOgymjFdZQ6WKs5v9Q # IZMCvMw0BqpthVkFUXEQ07J49/h50bkl1dfNAnT2K8V2QeVGuJ5YOSs3GFMXiAxZ # g6LJTHT0poTL5I5XD62X9xQ56LMRa9IDmFx6x4sMDrkn5oNVSGw7Vmx7cnI/5u1C # 1pEymuN8vTa3DeMcVOngt7k9wRLyA+OTzdlobO+o+Hfr2S9zFVh+7PVDC0wUzrTd # W7u1c63IK89HPHnTc37lnGFQUGPXYKXIooN6UhIbHRDTUFVO/sH2LysKLRyFWEs8 # qdOsszmx2zL+WNKmjrBmQBvPzrV7IimT6rpmpCYxEnoY/bFvXsmK5avv/Osj+efn # GkCc9hm7oLxy494MFy3u5S1XqkB0jweBCJo750sGG3N8QapKAicVYobSXBdeLxsm # H82yzsczRNPRAdyAGbFIe5vVpl43OSwclH9gRpREbdE63Bb8Uvyn+8FqECSb1f7N # uLXsMwue6nHTf7Lc/u48srSd6yRnY70CAwEAAaOCAdQwggHQMB8GA1UdIwQYMBaA # FMn8EO9QyMtrf70IRO86YpPtW16aMB0GA1UdDgQWBBREAaQBaa2AQTUPKUUkMbf9 # S5f5sDA+BgNVHSAENzA1MDMGBmeBDAEEATApMCcGCCsGAQUFBwIBFhtodHRwOi8v # d3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoG # CCsGAQUFBwMDMIGXBgNVHR8EgY8wgYwwRKBCoECGPmh0dHA6Ly9jcmwzLmRpZ2lj # ZXJ0LmNvbS9Hb0dldFNTTEc0Q1NSU0E0MDk2U0hBMjU2MjAyMkNBLTEuY3JsMESg # QqBAhj5odHRwOi8vY3JsNC5kaWdpY2VydC5jb20vR29HZXRTU0xHNENTUlNBNDA5 # NlNIQTI1NjIwMjJDQS0xLmNybDCBgwYIKwYBBQUHAQEEdzB1MCQGCCsGAQUFBzAB # hhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wTQYIKwYBBQUHMAKGQWh0dHA6Ly9j # YWNlcnRzLmRpZ2ljZXJ0LmNvbS9Hb0dldFNTTEc0Q1NSU0E0MDk2U0hBMjU2MjAy # MkNBLTEuY3J0MAkGA1UdEwQCMAAwDQYJKoZIhvcNAQELBQADggIBABqpRiImY/Bk # WSYmqNEZsmjcqPNRBEp9bYFMylajgTFR7dOLqF9sCStkO+cs/X64RKHkZtlaCrQa # ecZp6j/Dpq1fnkp2NfwuAaX2Osp/h6tMKnjaun3gvTdmI/j2iyJv6YJRxZ7daee7 # q9bkPzCTINwNc7AqWHbZ3Whlg+MmhLXaFHpoasR5JO9Vh+A8z8Y593G1bc7/Wjp2 # JWBNrCLjSUuz83YcDtf7yaURHuoJ96NDrHpbggaYU1s75sMhfBwAMTuYN2HmQe6/ # ShmDwGPtNzja0OtUdL0siHUp3Gouuqiux+ii7sjK0BDqvW3cbIQhCY41HkrJt4YF # e+KAUzZXeger2mTb9StmWLTLuqTKvUnCpzsVlqEO1I6NwsXgV2u46/0EYqk42vBT # e1vwXXj2Eawp5g4sSHQqbcxTAr/H5wZDIMp32tSyDMqV7zXhT6UWvxy5xua9Zkvf # j7bn7CzUWgX/+GMyP8KlgXEDG5rCY1uSxleFBvn0ACZjWRp+kWl17WbdrIL22Kkl # 2s1px/g9dfRbhHwNVAX1Mx2S7uCreeRs5qAA1cEjct2ulpNIbuPAEDDKenUHDTfN # k0osUL9uaOjSx6HiVkcwPHgFzyMyu+SCVOUTpBhwBXIH+/r77s6XVnQWmjUHcZUY # Y6KuwZiQ+E7joeAaZ0JGyW+LWx8WPfg7MYIGSjCCBkYCAQEwbjBaMQswCQYDVQQG # EwJMVjEZMBcGA1UEChMQRW5WZXJzIEdyb3VwIFNJQTEwMC4GA1UEAxMnR29HZXRT # U0wgRzQgQ1MgUlNBNDA5NiBTSEEyNTYgMjAyMiBDQS0xAhAGBSLrl94yV3C8/AHm # MmZmMA0GCWCGSAFlAwQCAQUAoIGEMBgGCisGAQQBgjcCAQwxCjAIoAKAAKECgAAw # GQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisG # AQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIC1ZxGjILxocWicWhcYemB6dMl16L5fs # vJyUrdB6xKBeMA0GCSqGSIb3DQEBAQUABIICAFxpPdbiGQOkeizIlfSKqfBWNmSO # FrK2nlGnQb1VJ8a7F4Qc119tvMW6fcCY5OGAig6Nw5SueqwcVy60StVGm2YasW1l # B4ikW/STECRfdxD4hUwlamxj/+QwG/3zwTYfNJQvY9NJP/WyBZtBgjo53QTNaHeS # FB7bMUVBZx0tm9+9cPiyJB049IlXX9ysxmbPZ+PQtVXB64VQEg/UoIk3TZBHA2SY # dbZKO4TI5HLjWadwLBQosUDufXvfOM2AiLx76nicg1GjjOrrp3iJABjS+oeGIFSa # Qqxg8JmtcPw2YUFanVDgNLhr+zb35gYiDsP+1uT5uqbDTDH3dHKi9B8X/9JE2tFB # kxWp7QDtk4MlFPyXugEEAB6eS9YyZOKcIXWMl68u6sI4gCFCTBtv31SlAFVb7KCd # Aq4ZhYjuETVeFg5MG/tXl75I0XGxYBk8ulcrGejcJRUEnmtTRnbqqNKSSxWVkMou # bHy7Hy8BbO+xVGuB2bj0dUcsXFgNPjZqQRojjzm4yKfN6Yv6f8J1ppKN5tgjg9pV # 3PTIXUESm3dyHI2pxWd8BGVdZOI3TB34LAxyvebyDuTYY4PWfr9D3L8E1gBzCT7N # FQkiRCEsU+RiSq0HdCsEZXO8fkfC1TyqUXYUwzfxCYgn7908iQRm+is/yCIN+fZk # jqqMzvC+r/w7MMTtoYIDJjCCAyIGCSqGSIb3DQEJBjGCAxMwggMPAgEBMH0waTEL # MAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMUEwPwYDVQQDEzhE # aWdpQ2VydCBUcnVzdGVkIEc0IFRpbWVTdGFtcGluZyBSU0E0MDk2IFNIQTI1NiAy # MDI1IENBMQIQCoDvGEuN8QWC0cR2p5V0aDANBglghkgBZQMEAgEFAKBpMBgGCSqG # SIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTI1MTIyOTE4MTYy # MVowLwYJKoZIhvcNAQkEMSIEIAJbzjxpM53Wh5bS/YYJcJ7zmxi11ojyh/5TTk1w # 6++EMA0GCSqGSIb3DQEBAQUABIICALT7yW5NGGPmWywgS7g6GGdVBUjcMN7IMkYv # KLe/+/dhgA/pKayHLRUG1pWWg46tlPwfRjDZnehdA/lc7U1n/D2oScQtd5V3/u2T # RUhN7y56G2tKmVhd2cot7uXer6uWuOEgc8GTK7PooVov6JbTNMGePGnN3fPu145M # 1ppC3HGZ+mj5ZVeOf4vSUUW+G7upFDhbLY6lriMQ28btPtXtQzCdDv/AcWWcKRKI # MYjlJxaLLWeQc+Pj+b/kjqqITTzLDllxYDUH4V7NbB8gyx3oC+hkM2mjFE6RXVcs # 28YXtVb1U8C6UM95oNQ7NJcNkLP08VNP4VOZHiI6M56gxG584VEEr3V2XZSkqffn # szESNV2MI57Cgh7AhYgqd5oBXc0xG02yKvAd/W5pWY9XQedC4OwbexjdCSCbCpm3 # 8zJ2Q15WZnnI56P92Su5ObJJ38AWGKTBQTZiZCFu+7XB5TF8DzwwotYJiqE+mjNk # y2TwEXUTr9BmTK7nIoAu3kQJyoAqZbyA9ewaNfXNO1Rr/N0IPhEcE0aZZab/rmzt # HzQyidsmSmUGFYX0ISpOlnVnotWa6gNxOykAoiI4D0+9SJchTJV46Z8qPENEnOUl # IDrMW1jKZoj4X2GwFAcfUjiUMZfaUjbkxVaXii/uPC2Cy/H6nF1FBOJxMvx0ZKdy # Yx8+trTs # SIG # End signature block |