DevUtils.psm1
function Stop-Processes { [CmdletBinding()] param( [Parameter()] [string[]] $ProcessesToStop = @('msbuild', 'dotnet', 'vbcscompiler'), [Parameter()] [switch] $WhatIf ) Log info 'Killing running build processes...' $getProcesses = { Get-Process -ErrorAction SilentlyContinue | Select-Object Id, ProcessName, Path | Where-Object { $ProcessesToStop -contains $_.ProcessName } } # $sb = [System.Text.StringBuilder]::new() $retries = 255 $milliseconds = 75 do { try { $processes = & $getProcesses foreach ($process in $processes) { # Original version # Write-Host 'Try to stop process: ' -NoNewline # Write-Host $($process.ProcessName) -NoNewline -ForegroundColor White # Write-Host ' -> ' -NoNewline -ForegroundColor DarkGray # Write-Host "'$($process.Path)'" -ForegroundColor DarkGray # PoshGit's ANSI console version (should adapted) # $sb.Clear() > $null # $sb | Write-Prompt 'Try to stop process ' > $null # $sb | Write-Prompt $($process.ProcessName) -ForegroundColor ([ConsoleColor]::White) > $null # $sb | Write-Prompt ' -> ' -ForegroundColor ([ConsoleColor]::DarkGray) > $null # $sb | Write-Prompt "'$($process.Path)'" -ForegroundColor ([ConsoleColor]::DarkGray) > $null # Log info ($sb.ToString()) Log info "Try to stop process: '$($process.ProcessName)' -> '$($process.Path)'" if (-not $WhatIf.IsPresent) { Stop-Process -Id $process.Id } } } catch { } Start-Sleep -Milliseconds $milliseconds --$retries $processes = & $getProcesses } while ($processes -and ($retries -gt 0)) } function Get-VisualStudioVersions() { $installations = [VisualStudio.Setup.Core.VisualStudio]::GetInstalled() return $installations } function Get-ProductSemanticVersionShortList() { return Get-VisualStudioVersions | Select-Object -ExpandProperty ProductSemanticVersionShort } function Export-DefaultVisualStudioVersion([string] $Version) { $filePath = Join-Path (Join-Path $env:LOCALAPPDATA 'Microsoft/VisualStudio') 'Common.json' $content = @{ DefaultVersion = $Version } $content | ConvertTo-Json -Compress | Out-File -FilePath $filePath -Force -NoNewline -Encoding utf8NoBOM } function Import-DefaultVisualStudioVersion() { $filePath = Join-Path (Join-Path $env:LOCALAPPDATA 'Microsoft/VisualStudio') 'Common.json' if (Test-Path $filePath) { $content = Get-Content $filePath -Raw | ConvertFrom-Json return $content.DefaultVersion } return $null } function Get-DefaultVisualStudioVersion() { $defaultVisualStudioVersion = Import-DefaultVisualStudioVersion return Get-VisualStudioVersions | Where-Object ProductSemanticVersionShort -eq $defaultVisualStudioVersion | Select-Object -First 1 } function Set-DefaultVisualStudioVersion { [CmdletBinding()] param() DynamicParam { New-DynamicParameter -Name 'Version' -ValidateSet (Get-ProductSemanticVersionShortList) } Begin { $Version = $PSBoundParameters['Version'] } Process { Export-DefaultVisualStudioVersion $Version } } function EnumerateFiles([string] $path, [string[]] $searchPattern) { $files = [System.Collections.ArrayList]@() foreach ($pattern in $searchPattern) { foreach ($item in [System.IO.Directory]::EnumerateFiles($path, $pattern, [System.IO.SearchOption]::AllDirectories)) { $files.Add($item) > $null } } return $files } function Get-VisualStudioSolutions { [CmdletBinding()] param( [Parameter()] [string] $RootPath = (Get-Location) ) $RootPath = Resolve-Path $RootPath # $solutionFiles = EnumerateFiles -path $RootPath -searchPattern @('*.sln', '*.slnf') $solutionFiles = [VisualStudio.Setup.Core.FindFiles]::GetFilesWithExtension($RootPath, @('.sln', '.slnf')) $solutions = [ordered]@{ } for ($i = 0; $i -lt $solutionFiles.Count; ++$i) { $item = Get-Item $solutionFiles[$i] $solution = [pscustomobject]@{ BaseName = $item.BaseName RelativePath = Resolve-Path -Path $item.FullName -Relative FullName = $item.FullName } $solutions.Add($i, $solution) } return $solutions } function Write-VisualStudioSolutions { [CmdletBinding()] param( [Parameter()] [string] $RootPath = (Get-Location), [Parameter()] [pscustomobject] $VisualStudioSolutions = $null ) if ($VisualStudioSolutions -eq $null) { $VisualStudioSolutions = Get-VisualStudioSolutions $RootPath } if ($VisualStudioSolutions.Count -lt 1) { Write-Host 'Could not found any solution' -ForegroundColor DarkRed return } $maxLengthPosition = 0 $maxLengthBasename = 0 foreach ($solution in $VisualStudioSolutions.GetEnumerator()) { $maxLengthPosition = ([string]($solution.Key + 1)).Length if ($solution.Value.BaseName.Length -gt $maxLengthBasename) { $maxLengthBasename = $solution.Value.BaseName.Length } } Write-Host 'Please select a solution:' -ForegroundColor Cyan foreach ($solution in $VisualStudioSolutions.GetEnumerator()) { Write-Host "[$(($solution.Key + 1).ToString().PadLeft($maxLengthPosition, '0'))] " -ForegroundColor Yellow -NoNewline Write-Host "$($solution.Value.BaseName.PadRight($maxLengthBasename, ' ')) " -ForegroundColor Green -NoNewline Write-Host "($(Resolve-Path -Path $solution.Value.FullName -Relative))" } } filter IsNumeric() { return $_ -is [byte] -or $_ -is [int16] -or $_ -is [int32] -or $_ -is [int64] -or $_ -is [sbyte] -or $_ -is [uint16] -or $_ -is [uint32] -or $_ -is [uint64] -or $_ -is [float] -or $_ -is [double] -or $_ -is [decimal] -or $_ -match "^\d+$" } function Start-VisualStudio { [CmdletBinding()] param( [Parameter()] [switch] $WhatIf ) DynamicParam { $dict = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary $solutionValidateSet = @() $solutionValidateSet += (Get-VisualStudioSolutions).Values.RelativePath $solutionValidateSet += (Get-VisualStudioSolutions).Keys | ForEach-Object { $_ + 1 } New-DynamicParameter -Name 'Solution' -Position 0 -ValidateSet $solutionValidateSet -DPDictionary $dict New-DynamicParameter -Name 'Version' -Position 1 -ValidateSet (Get-ProductSemanticVersionShortList) -DPDictionary $dict return $dict } Begin { $Solution = $PSBoundParameters['Solution'] if (-not $Solution) { $Solution = (Get-VisualStudioSolutions).GetEnumerator() | Select-Object -First 1 | Select-Object -ExpandProperty Value | Select-Object -ExpandProperty RelativePath } if ($Solution | IsNumeric) { $solutionIndex = [int]::Parse($Solution) - 1 $Solution = (Get-VisualStudioSolutions)[$solutionIndex] | Select-Object -ExpandProperty RelativePath } $Version = $PSBoundParameters['Version'] if (-not $Version) { $visualStudioVersion = Get-DefaultVisualStudioVersion } else { $visualStudioVersion = Get-VisualStudioVersions | Where-Object ProductSemanticVersionShort -eq $Version | Select-Object -First 1 } } Process { $solutionPath = Resolve-Path $Solution $solutionItem = Get-Item $solutionPath if (-not (Test-Path $solutionPath)) { Log error "File '$solutionPath' does not exists" return } if (-not $visualStudioVersion) { Log error "Visual Studio version '$Version' does not exists" return } $maxLengthProductVersion = "Visual Studio $($visualStudioVersion.ProductLineVersion)".Length Write-Host '-> ' -ForegroundColor Yellow -NoNewline Write-Host "$($solutionItem.BaseName.PadRight($maxLengthProductVersion, ' ')) " -ForegroundColor Green -NoNewline Write-Host "($(Resolve-Path -Path $solutionItem.FullName -Relative))" Write-Host '-> ' -ForegroundColor Yellow -NoNewline Write-Host "Visual Studio $($visualStudioVersion.ProductLineVersion) " -ForegroundColor Green -NoNewline Write-Host "(v$($visualStudioVersion.ProductSemanticVersionShort))" $instances = [VisualStudio.Setup.Core.VisualStudioController]::GetRunningVisualStudioDTEs($visualStudioVersion.InstallationVersion) $otherSolutionIsOpened = $false foreach ($dte in $instances) { if (-not $dte.Solution.IsOpen) { Write-Host '-> ' -ForegroundColor Yellow -NoNewline Write-Host 'Open solution in existing Visual Studio instance' -ForegroundColor Green if (-not $WhatIf.IsPresent) { $dte.Solution.Open($solutionItem.FullName) } return } else { $otherSolutionIsOpened = $true } } if ($otherSolutionIsOpened) { Write-Host '-> ' -ForegroundColor Yellow -NoNewline Write-Host 'Another solution or folder is already open in Visual Studio' -ForegroundColor Green } Write-Host '-> ' -ForegroundColor Yellow -NoNewline Write-Host 'Create new Visual Studio instance' -ForegroundColor Green if (-not $WhatIf.IsPresent) { & $visualStudioVersion.DevEnvPath $solutionItem.FullName } } } function Clear-NuGetCache { Start-NativeExecution dotnet nuget locals all --clear } New-Alias kp Stop-Processes New-Alias vs Start-VisualStudio New-Alias vss Write-VisualStudioSolutions # SIG # Begin signature block # MIIcjgYJKoZIhvcNAQcCoIIcfzCCHHsCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCC1gRM7Sox6ywrE # +hwm+xJ9lV3wsFaJNX1XAPJI9UDVg6CCF5gwggUhMIIECaADAgECAhAIWwDz5iwy # UtohxU7HR7bMMA0GCSqGSIb3DQEBCwUAMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNV # BAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwHhcN # MTkwMzEyMDAwMDAwWhcNMjAwMzE2MTIwMDAwWjBeMQswCQYDVQQGEwJERTEfMB0G # A1UEBxMWR2FybWlzY2gtUGFydGVua2lyY2hlbjEWMBQGA1UEChMNTWFudWVsIFRh # bnplcjEWMBQGA1UEAxMNTWFudWVsIFRhbnplcjCCASIwDQYJKoZIhvcNAQEBBQAD # ggEPADCCAQoCggEBAPIHE2FyXkrHpGfPf80N/4sJPgORb+Br0+wCuJSD8BMRNB40 # 1Rmn2dcq7IEfvud6qCdnxo/jLmTWNiEb7dr+NcRvIggi5yUM48DjpUnYpsDAIVTQ # 1j1+X7DgaCy7KrR9qsJciYvsZqjFOG7vHdOfU8LUaGD+eKHlL8uKOAdgHT7KnNJi # QQtK1fK2D0MUK+CqBuFg4m+XDfQbugzi5w9YkbdlIaQoxjVWogDqG9fs60501ly6 # yDrS4oOQFnHWcx1HlWFrGPU6kMMdDLeVC211qbIMFH+z8Rc+aSWzXBlxn9TUygJW # ghkNTGS/2C34RjtQDK/4rl2Koh7NHqCUMJf1bIECAwEAAaOCAcUwggHBMB8GA1Ud # IwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5YMB0GA1UdDgQWBBSjqX8VbvlnZ2WB # n2oo/qfn1g674TAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMw # dwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NoYTIt # YXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNv # bS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwGA1UdIARFMEMwNwYJYIZIAYb9bAMB # MCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCAYG # Z4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3Nw # LmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZCaHR0cDovL2NhY2VydHMuZGlnaWNl # cnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJRENvZGVTaWduaW5nQ0EuY3J0MAwG # A1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggEBAOIRTvC2IfJXdRz46zRs+4+z # YKsufAnKNlAkgMc4cX2NKD/u5kvB1aS1EFAE9vRLPURtDgiLia6I8nLOUag4iWpO # mH9nd8utH+obJhR3l35jB8WP/RVdcRU9GicRT9ARWLZEby6CYpq081WNCtxoPCEs # +bAiCBcR6KkWP5YUGoC0tBn5aeoTmpJgtLjGGjtsHQH9Xoak7T39gjbJZLoztVfE # A78MSmjvTvVyn4SfgVT31y9puQxMwusrZf+axm51SJp0YTYVAuHtNVqfxve4QBXq # 6OXtGnceVuEmcH9cSRYo5GOhuNyq4yIq1/yLIWeLiBxlqaKauSPPG8yCaXFs1LEw # ggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7VvlVAIMA0GCSqGSIb3DQEBCwUAMGUx # CzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 # dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9v # dCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEwMjIxMjAwMDBaMHIxCzAJBgNVBAYT # AlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2Vy # dC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBDb2RlIFNp # Z25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD407Mcfw4R # r2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx6nadBS63j/qSQ8Cl+YnUNxnXtqrw # nIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEjlpB3gvmhhCNmElQzUHSxKCa7JGnC # wlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJNYBi+qsSyrnAxZjNxPqxwoqvOf+l8 # y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2DZDv5LVOpKnqagqrhPOsZ061xPeM # 0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9hbFig3NBggfkOItqcyDQD2RzPJ6f # pjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1Ud # DwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcDAzB5BggrBgEFBQcBAQRtMGsw # JAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcw # AoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElE # Um9vdENBLmNydDCBgQYDVR0fBHoweDA6oDigNoY0aHR0cDovL2NybDQuZGlnaWNl # cnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDA6oDigNoY0aHR0cDov # L2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDBP # BgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93 # d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgBhv1sAzAdBgNVHQ4EFgQUWsS5eyoK # o6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAUReuir/SSy4IxLVGLp6chnfNtyA8w # DQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi0RXILHwlKXaoHV0cLToaxO8wYdd+ # C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6ljlriXiSBThCk7j9xjmMOE0ut119E # efM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0kriTGxycqoSkoGjpxKAI8LpGjwCUR # 4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/PQMtARKUT8OZkDCUIQjKyNookAv4v # cn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d9gEgzpkxYz0IGhizgZtPxpMQBvwH # gfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJmoecYpJpkUe8wggZqMIIFUqADAgEC # AhADAZoCOv9YsWvW1ermF/BmMA0GCSqGSIb3DQEBBQUAMGIxCzAJBgNVBAYTAlVT # MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j # b20xITAfBgNVBAMTGERpZ2lDZXJ0IEFzc3VyZWQgSUQgQ0EtMTAeFw0xNDEwMjIw # MDAwMDBaFw0yNDEwMjIwMDAwMDBaMEcxCzAJBgNVBAYTAlVTMREwDwYDVQQKEwhE # aWdpQ2VydDElMCMGA1UEAxMcRGlnaUNlcnQgVGltZXN0YW1wIFJlc3BvbmRlcjCC # ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKNkXfx8s+CCNeDg9sYq5kl1 # O8xu4FOpnx9kWeZ8a39rjJ1V+JLjntVaY1sCSVDZg85vZu7dy4XpX6X51Id0iEQ7 # Gcnl9ZGfxhQ5rCTqqEsskYnMXij0ZLZQt/USs3OWCmejvmGfrvP9Enh1DqZbFP1F # I46GRFV9GIYFjFWHeUhG98oOjafeTl/iqLYtWQJhiGFyGGi5uHzu5uc0LzF3gTAf # uzYBje8n4/ea8EwxZI3j6/oZh6h+z+yMDDZbesF6uHjHyQYuRhDIjegEYNu8c3T6 # Ttj+qkDxss5wRoPp2kChWTrZFQlXmVYwk/PJYczQCMxr7GJCkawCwO+k8IkRj3cC # AwEAAaOCAzUwggMxMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMBYGA1Ud # JQEB/wQMMAoGCCsGAQUFBwMIMIIBvwYDVR0gBIIBtjCCAbIwggGhBglghkgBhv1s # BwEwggGSMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BT # MIIBZAYIKwYBBQUHAgIwggFWHoIBUgBBAG4AeQAgAHUAcwBlACAAbwBmACAAdABo # AGkAcwAgAEMAZQByAHQAaQBmAGkAYwBhAHQAZQAgAGMAbwBuAHMAdABpAHQAdQB0 # AGUAcwAgAGEAYwBjAGUAcAB0AGEAbgBjAGUAIABvAGYAIAB0AGgAZQAgAEQAaQBn # AGkAQwBlAHIAdAAgAEMAUAAvAEMAUABTACAAYQBuAGQAIAB0AGgAZQAgAFIAZQBs # AHkAaQBuAGcAIABQAGEAcgB0AHkAIABBAGcAcgBlAGUAbQBlAG4AdAAgAHcAaABp # AGMAaAAgAGwAaQBtAGkAdAAgAGwAaQBhAGIAaQBsAGkAdAB5ACAAYQBuAGQAIABh # AHIAZQAgAGkAbgBjAG8AcgBwAG8AcgBhAHQAZQBkACAAaABlAHIAZQBpAG4AIABi # AHkAIAByAGUAZgBlAHIAZQBuAGMAZQAuMAsGCWCGSAGG/WwDFTAfBgNVHSMEGDAW # gBQVABIrE5iymQftHt+ivlcNK2cCzTAdBgNVHQ4EFgQUYVpNJLZJMp1KKnkag0v0 # HonByn0wfQYDVR0fBHYwdDA4oDagNIYyaHR0cDovL2NybDMuZGlnaWNlcnQuY29t # L0RpZ2lDZXJ0QXNzdXJlZElEQ0EtMS5jcmwwOKA2oDSGMmh0dHA6Ly9jcmw0LmRp # Z2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRENBLTEuY3JsMHcGCCsGAQUFBwEB # BGswaTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsG # AQUFBzAChjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1 # cmVkSURDQS0xLmNydDANBgkqhkiG9w0BAQUFAAOCAQEAnSV+GzNNsiaBXJuGziMg # D4CH5Yj//7HUaiwx7ToXGXEXzakbvFoWOQCd42yE5FpA+94GAYw3+puxnSR+/iCk # V61bt5qwYCbqaVchXTQvH3Gwg5QZBWs1kBCge5fH9j/n4hFBpr1i2fAnPTgdKG86 # Ugnw7HBi02JLsOBzppLA044x2C/jbRcTBu7kA7YUq/OPQ6dxnSHdFMoVXZJB2vkP # gdGZdA0mxA5/G7X1oPHGdwYoFenYk+VVFvC7Cqsc21xIJ2bIo4sKHOWV2q7ELlmg # Yd3a822iYemKC23sEhi991VUQAOSK2vCUcIKSK+w1G7g9BQKOhvjjz3Kr2qNe9zY # RDCCBs0wggW1oAMCAQICEAb9+QOWA63qAArrPye7uhswDQYJKoZIhvcNAQEFBQAw # ZTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQ # d3d3LmRpZ2ljZXJ0LmNvbTEkMCIGA1UEAxMbRGlnaUNlcnQgQXNzdXJlZCBJRCBS # b290IENBMB4XDTA2MTExMDAwMDAwMFoXDTIxMTExMDAwMDAwMFowYjELMAkGA1UE # BhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2lj # ZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgQXNzdXJlZCBJRCBDQS0xMIIBIjAN # BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6IItmfnKwkKVpYBzQHDSnlZUXKnE # 0kEGj8kz/E1FkVyBn+0snPgWWd+etSQVwpi5tHdJ3InECtqvy15r7a2wcTHrzzpA # DEZNk+yLejYIA6sMNP4YSYL+x8cxSIB8HqIPkg5QycaH6zY/2DDD/6b3+6LNb3Mj # /qxWBZDwMiEWicZwiPkFl32jx0PdAug7Pe2xQaPtP77blUjE7h6z8rwMK5nQxl0S # QoHhg26Ccz8mSxSQrllmCsSNvtLOBq6thG9IhJtPQLnxTPKvmPv2zkBdXPao8S+v # 7Iki8msYZbHBc63X8djPHgp0XEK4aH631XcKJ1Z8D2KkPzIUYJX9BwSiCQIDAQAB # o4IDejCCA3YwDgYDVR0PAQH/BAQDAgGGMDsGA1UdJQQ0MDIGCCsGAQUFBwMBBggr # BgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCDCCAdIGA1UdIASC # AckwggHFMIIBtAYKYIZIAYb9bAABBDCCAaQwOgYIKwYBBQUHAgEWLmh0dHA6Ly93 # d3cuZGlnaWNlcnQuY29tL3NzbC1jcHMtcmVwb3NpdG9yeS5odG0wggFkBggrBgEF # BQcCAjCCAVYeggFSAEEAbgB5ACAAdQBzAGUAIABvAGYAIAB0AGgAaQBzACAAQwBl # AHIAdABpAGYAaQBjAGEAdABlACAAYwBvAG4AcwB0AGkAdAB1AHQAZQBzACAAYQBj # AGMAZQBwAHQAYQBuAGMAZQAgAG8AZgAgAHQAaABlACAARABpAGcAaQBDAGUAcgB0 # ACAAQwBQAC8AQwBQAFMAIABhAG4AZAAgAHQAaABlACAAUgBlAGwAeQBpAG4AZwAg # AFAAYQByAHQAeQAgAEEAZwByAGUAZQBtAGUAbgB0ACAAdwBoAGkAYwBoACAAbABp # AG0AaQB0ACAAbABpAGEAYgBpAGwAaQB0AHkAIABhAG4AZAAgAGEAcgBlACAAaQBu # AGMAbwByAHAAbwByAGEAdABlAGQAIABoAGUAcgBlAGkAbgAgAGIAeQAgAHIAZQBm # AGUAcgBlAG4AYwBlAC4wCwYJYIZIAYb9bAMVMBIGA1UdEwEB/wQIMAYBAf8CAQAw # eQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy # dC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9E # aWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwgYEGA1UdHwR6MHgwOqA4oDaGNGh0 # dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5j # cmwwOqA4oDaGNGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3Vy # ZWRJRFJvb3RDQS5jcmwwHQYDVR0OBBYEFBUAEisTmLKZB+0e36K+Vw0rZwLNMB8G # A1UdIwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgPMA0GCSqGSIb3DQEBBQUAA4IB # AQBGUD7Jtygkpzgdtlspr1LPUukxR6tWXHvVDQtBs+/sdR90OPKyXGGinJXDUOSC # uSPRujqGcq04eKx1XRcXNHJHhZRW0eu7NoR3zCSl8wQZVann4+erYs37iy2QwsDS # tZS9Xk+xBdIOPRqpFFumhjFiqKgz5Js5p8T1zh14dpQlc+Qqq8+cdkvtX8JLFuRL # cEwAiR78xXm8TBJX/l/hHrwCXaj++wc4Tw3GXZG5D2dFzdaD7eeSDY2xaYxP+1ng # Iw/Sqq4AfO6cQg7PkdcntxbuD8O9fAqg7iwIVYUiuOsYGk38KiGtSTGDR5V3cdyx # G0tLHBCcdxTBnU8vWpUIKRAmMYIETDCCBEgCAQEwgYYwcjELMAkGA1UEBhMCVVMx # FTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNv # bTExMC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIENvZGUgU2lnbmlu # ZyBDQQIQCFsA8+YsMlLaIcVOx0e2zDANBglghkgBZQMEAgEFAKCBhDAYBgorBgEE # AYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwG # CisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCCK7Y51 # KAhnvylzNyoFIc3uz5EB3DIi6b8JNQJYAzNQBTANBgkqhkiG9w0BAQEFAASCAQCQ # hWWU1cPDKrhImITBfGfOzm3EwTp3lZpNOEmiBtmxF+elOrBBYMuO1IX7cf+OC87w # JRrqUw84V6uGF6oixPvhmcBNh6jF2OOna3EeArPj3XbAkY0PHWDbp0AhTO8mMik/ # P8VfYzujCUt7o0PPeYA2kucwzsgINMDD4V8XxNqKz91qRkIV28rF8whtC4gw6rb1 # r0Pv776lwQZx6cuLzeeawWEAQiIidg3QEVrq3/2IQlzNywL4E/ptcQyl1tFLKc9z # okOmRjlI3cNtecPlVLo8z7HlhhUNFeYlL79KIsrU2MD4t1OPlnR8qxrxPbjPMI0Y # N/PQSAgf8E9OhnRJVxBOoYICDzCCAgsGCSqGSIb3DQEJBjGCAfwwggH4AgEBMHYw # YjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQ # d3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgQXNzdXJlZCBJRCBD # QS0xAhADAZoCOv9YsWvW1ermF/BmMAkGBSsOAwIaBQCgXTAYBgkqhkiG9w0BCQMx # CwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0yMDAzMTAxMzM4MTlaMCMGCSqG # SIb3DQEJBDEWBBQ6IZsYg+tqD1DWt7d8z02lkUrbmzANBgkqhkiG9w0BAQEFAASC # AQBnhUH/C87Qmmjhd9YFQNO6Q7SgRIT0dxKItdCaHK/iWIW9o+8iZq5DHpgE6YzD # Mu9e7JYRNJTVic3kGsEcnx4c2bD9uGRa11duL+/Ynoq6Ll+125NYj5lBcTPYBQhG # 6D4PoC2lDrj7G+M3OY7vSOnHuLhg1dRMF8+WqDHiJ8AP1AbdQNl0NwLYUj0nf7MI # X1id0WAdic3GasRlZuI4XnLZgfSondMQgVVLUZ0gVDe3e+i8B1YTX7wDWtk31hiM # aFEWKMI/yAtNRTZhP7xLeI5AB/fKll9wMTFK+OQk88ihb55njSqJBgGDXw8zzerY # KVsSK9Z2QgE4K5Zkg4IJZjTU # SIG # End signature block |