Code/SymbolsSource.ps1

#requires -version 2.0
###############################################################################
# WintellectPowerShell Module
# Copyright (c) 2010-2014 - John Robbins/Wintellect
#
# Do whatever you want with this module, but please do give credit.
###############################################################################

# Always make sure all variables are defined and all best practices are
# followed.
Set-StrictMode -version Latest

###############################################################################
# Script Global Variables
###############################################################################
$script:devTenDebuggerRegKey = "HKCU:\Software\Microsoft\VisualStudio\10.0\Debugger"
$script:devElevenDebuggerRegKey = "HKCU:\Software\Microsoft\VisualStudio\11.0\Debugger"
$script:devTwelveDebuggerRegKey = "HKCU:\Software\Microsoft\VisualStudio\12.0\Debugger"
$script:devFourteenDebuggerRegKey = "HKCU:\Software\Microsoft\VisualStudio\14.0\Debugger"

###############################################################################
# Module Only Functions
###############################################################################
function CreateDirectoryIfNeeded ([string] $directory="")
{
    if ( ! (Test-Path -Path $directory -type "Container"))
    {
        New-Item -type directory -Path $directory > $null
    }
}

# Just to hide PS errors when reading registry keys that don't exist.
function SmartGetRegProperty($regKey="",$regValue="")
{
    $key = Get-ItemProperty -Path $regKey -Name $regValue -ErrorAction SilentlyContinue
    if ($null -ne $key)
    {
        return $key.$regValue
    }
    return $null
}

# Reads the values from VS 2010+, and the environment.
function GetCommonSettings($regValue="", $envVariable="")
{
    $returnHash = @{}
    if (Test-Path -Path $devTenDebuggerRegKey)
    {
        $returnHash["VS 2010"] = SmartGetRegProperty -regKey $devTenDebuggerRegKey -regValue $regValue
    }
    if (Test-Path -Path $devElevenDebuggerRegKey)
    {
        $returnHash["VS 2012"] = SmartGetRegProperty -regKey $devElevenDebuggerRegKey -regValue $regValue
    }
    if (Test-Path -Path $devTwelveDebuggerRegKey)
    {
        $returnHash["VS 2013"] = SmartGetRegProperty -regKey $devTwelveDebuggerRegKey -regValue $regValue
    }
    if (Test-Path -Path $devFourteenDebuggerRegKey)
    {
        $returnHash["VS 2015"] = SmartGetRegProperty -regKey $devFourteenDebuggerRegKey -regValue $regValue
    }
    $envVal = Get-ItemProperty -Path HKCU:\Environment -Name $envVariable -ErrorAction SilentlyContinue
    if ($null -ne $envVal)
    {
        $returnHash[$envVariable] = $envVal.$envVariable
    }
    $returnHash
}

# Makes doing ShouldProcess easier.
function Set-ItemPropertyScript 
{
    [CmdletBinding(SupportsShouldProcess=$true)]
    param
    (
        [Parameter(Mandatory=$true)]
        $path,
        [Parameter(Mandatory=$true)] 
        $name, 
        [Parameter(Mandatory=$true)] 
        $value,
        $type=$null 
    )

    $propString = "Item: " + $path.ToString() + " Property: " + $name
    if ($PSCmdLet.ShouldProcess($propString ,"Set Property"))
    {
        if ($null -eq $type)
        {
          Set-ItemProperty -Path $path -Name $name -Value $value
        }
        else
        {
          Set-ItemProperty -Path $path -Name $name -Value $value -Type $type
        }
    }
}

function SetInternalSymbolServer([string] $DbgRegKey="", 
                                 [string] $CacheDirectory="",
                                 [string] $SymPath="")
{

    CreateDirectoryIfNeeded -directory $CacheDirectory
    
    # Turn off Just My Code.
    Set-ItemPropertyScript -Path $dbgRegKey -Name JustMyCode -Value 0 -Type DWORD

    # Turn off .NET Framework Source stepping.
    Set-ItemPropertyScript -Path $DbgRegKey -Name FrameworkSourceStepping -Value 0 DWORD

    # Turn off using the Microsoft symbol servers.
    Set-ItemPropertyScript -Path $DbgRegKey -Name SymbolUseMSSymbolServers -Value 0 DWORD

    # Set the symbol cache dir to the same value as used in the environment
    # variable.
    Set-ItemPropertyScript -Path $DbgRegKey -Name SymbolCacheDir -Value $CacheDirectory
} 

function SetPublicSymbolServer([string] $DbgRegKey="", 
                               [string] $CacheDirectory="")
{
    CreateDirectoryIfNeeded -directory $CacheDirectory
        
    # Turn off Just My Code.
    Set-ItemPropertyScript $dbgRegKey JustMyCode 0 DWORD
    
    # Turn on .NET Framework Source stepping.
    Set-ItemPropertyScript $dbgRegKey FrameworkSourceStepping 1 DWORD
    
    # Turn on Source Server Support.
    Set-ItemPropertyScript $dbgRegKey UseSourceServer 1 DWORD
    
    # Turn on Source Server Diagnostics as that's a good thing. :)
    Set-ItemPropertyScript $dbgRegKey ShowSourceServerDiagnostics 1 DWORD
    
    # It's very important to turn off requiring the source to match exactly.
    # With this flag on, .NET Reference Source Stepping doesn't work.
    Set-ItemPropertyScript $dbgRegKey UseDocumentChecksum 0 DWORD
    
    # Turn off using the Microsoft symbol servers.
    Set-ItemPropertyScript $dbgRegKey SymbolUseMSSymbolServers 0 DWORD
    
    # Set the VS SymbolPath setting.
    Set-ItemPropertyScript $dbgRegKey SymbolPath ""
    
    # Tell VS that all paths are empty.
    Set-ItemPropertyScript $dbgRegKey SymbolPathState ""
    
    # Set the symbol cache dir to the same value as used in the environment
    # variable.
    Set-ItemPropertyScript $dbgRegKey SymbolCacheDir $CacheDirectory
}

###############################################################################
# Public Cmdlets
###############################################################################
function Get-SourceServer
{
<#
.SYNOPSIS
Returns a hashtable of the current source server settings.
 
.DESCRIPTION
Returns a hashtable with the current source server directories settings
for VS 2010-2015, and the _NT_SOURCE_PATH enviroment variable
used by WinDBG.
 
.OUTPUTS
HashTable
The keys are, if all present, VS 2010, VS 2012, VS 2013, VS 2015, and WinDBG.
The values are those set for each debugger.
 
.LINK
http://www.wintellect.com/blogs/jrobbins
https://github.com/Wintellect/WintellectPowerShell
 
#>

    GetCommonSettings SourceServerExtractToDirectory _NT_SOURCE_PATH
}

###############################################################################

function Set-SourceServer
{
<#
.SYNOPSIS
Sets the source server directory.
 
.DESCRIPTION
Sets the source server cache directory for VS 2010, VS 2012, VS 2013, VS 2015,
and WinDBG through the _NT_SOURCE_PATH environment variable to all reference
the same location. This ensures you only download the file once no matter
which debugger you use. Because this cmdlet sets an environment variable
you need to log off to ensure it's properly set.
 
.PARAMETER Directory
The directory to use. If the directory does not exist, it will be created.
 
.PARAMETER CurrentEnvironmentOnly
If specified will only set the current PowerShell window _NT_SOURCE_PATH
environment variable and not overwrite the global settings. This is primarily
for use with WinDBG as Visual Studio does not use this environment variable.
 
.LINK
http://www.wintellect.com/blogs/jrobbins
https://github.com/Wintellect/WintellectPowerShell
#>

    param ( 
        [Parameter(Mandatory=$true,
                   HelpMessage="Please specify the source server cache directory")]
        [string] $Directory,
        [switch] $CurrentEnvironmentOnly
    ) 
    
    $sourceServExtractTo = "SourceServerExtractToDirectory"
    
    CreateDirectoryIfNeeded $Directory

    if ($CurrentEnvironmentOnly)
    {
        $env:_NT_SOURCE_PATH = "SRV*" + $Directory
    }
    else
    {
        if (Test-Path -Path $devTenDebuggerRegKey)
        {
            Set-ItemProperty -Path $devTenDebuggerRegKey -Name $sourceServExtractTo -Value $Directory 
        }
    
        if (Test-Path -Path $devElevenDebuggerRegKey)
        {
            Set-ItemProperty -Path $devElevenDebuggerRegKey -Name $sourceServExtractTo -Value $Directory 
        }
    
        if (Test-Path -Path $devTwelveDebuggerRegKey)
        {
            Set-ItemProperty -Path $devTwelveDebuggerRegKey -Name $sourceServExtractTo -Value $Directory 
        }

        if (Test-Path -Path $devFourteenDebuggerRegKey)
        {
            Set-ItemProperty -Path $devFourteenDebuggerRegKey -Name $sourceServExtractTo -Value $Directory 
        }

        # Always set the _NT_SOURCE_PATH value for WinDBG.
        Set-ItemProperty -Path HKCU:\Environment -Name _NT_SOURCE_PATH -Value "SRV*$Directory"
    }
        
}

###############################################################################

function Get-SymbolServer
{
<#
.SYNOPSIS
Returns a hashtable of the current symbol server settings.
 
.DESCRIPTION
Returns a hashtable with the current source server directories settings
for VS 2010, VS 2012, VS 2013, VS 2015, and the _NT_SYMBOL_PATH enviroment
variable.
 
.LINK
http://www.wintellect.com/blogs/jrobbins
https://github.com/Wintellect/WintellectPowerShell
#>

    GetCommonSettings SymbolCacheDir _NT_SYMBOL_PATH
}

###############################################################################

function Get-SourceServerFiles
{
<#
.SYNOPSIS
Prepopulate your symbol cache with all your Source Server extracted source
code.
 
.DESCRIPTION
Recurses the specified symbol cache directory for PDB files with Source Server
sections and extracts the source code. This script is a simple wrapper around
SRCTOOl.EXE from the Debugging Tools for Windows (AKA WinDBG). If WinDBG is in
the PATH this script will find SRCTOOL.EXE. If WinDBG is not in your path, use
the SrcTool parameter to specify the complete path to the tool.
 
.PARAMETER CacheDirectory
The required cache directory for the local machine.
 
.PARAMETER SrcTool
The optional parameter to specify where SRCTOOL.EXE resides.
 
.OUTPUTS
HashTable
The keys are, if all present, VS 2010, VS 2012, VS 2013, VS 2015, and WinDBG.
The values are those set for each debugger.
 
.LINK
http://www.wintellect.com/blogs/jrobbins
https://github.com/Wintellect/WintellectPowerShell
#>

    param ( 
        [Parameter(Mandatory=$true,
                   HelpMessage="Please specify the source server directory")]
        [string] $CacheDirectory ,
        [Parameter(HelpMessage="The optional full path to SCRTOOL.EXE")]
        [string] $SrcTool = ""
    ) 
    
    if ($SrcTool -eq "")
    {
        # Go with the default of looking up WinDBG in the path.
        $windbg = Get-Command -Name windbg.exe -ErrorAction SilentlyContinue
        if ($null -eq $windbg)
        {
            throw "Please use the -SrcTool parameter or have WinDBG in the path"
        }
        
        $windbgPath = Split-Path -Path ($windbg.Definition)
        $SrcTool = $windbgPath + "\SRCSRV\SRCTOOL.EXE"
    }
    
    if ($null -eq (Get-Command -Name $SrcTool -ErrorAction SilentlyContinue))
    {
        throw "SRCTOOL.EXE does not exist."
    }
    
    if ((Test-Path -Path $CacheDirectory) -eq $false)
    {
        throw "The specified cache directory does not exist."
    }
    
    # Get all the PDB files, execute SRCTOOL.EXE on each one.
    Get-ChildItem -Recurse -Include *.pdb -Path $cacheDirectory | `
        ForEach-Object { &$SrcTool -d:$CacheDirectory -x $_.FullName }

}

###############################################################################

function Set-SymbolServer
{
<#
.SYNOPSIS
Sets up a computer to use a symbol server.
 
DESCRIPTION
Sets up both the _NT_SYMBOL_PATH environment variable as well as VS 2010, VS 2012,
VS 2013, and VS 2015 (if installed) to use a common symbol cache directory as well
as common symbol servers. Optionally can be used to only set _NT_SYMBOL_PATH for
an individual PowerShell window.
 
.PARAMETER Internal
Sets the symbol server to use to http://SymWeb. Visual Studio will not use the
public symbol servers. This will turn off the .NET Framework Source Stepping.
This switch is intended for internal Microsoft use only. You must specify either
-Internal or -Public to the script.
 
.PARAMETER Public
Sets the symbol server to use as the two public symbol servers from Microsoft.
All the appropriate settings are configured to properly have .NET Reference
Source stepping working.
 
.PARAMETER CacheDirectory
Defaults to C:\SYMBOLS\PUBLIC for -Public and C:\SYMBOLS\INTERNAL for -Internal.
 
.PARAMETER SymbolServers
A string array of additional symbol servers to use. If -Internal is set, these
additional symbol servers will appear before HTTP://SYMWEB. If -Public is set,
these symbol servers will appear before the public symbol servers so both the
environment variable and Visual Studio have the same search order.
 
.PARAMETER CurrentEnvironmentOnly
If specified will only set the current PowerShell window _NT_SYMBOL_PATH
environment variable and not overwrite the global settings. This is primarily
for use with WinDBG as Visual Studio requires registry settings for the
cache directory.
 
.LINK
http://www.wintellect.com/blogs/jrobbins
https://github.com/Wintellect/WintellectPowerShell
#>

    [CmdLetBinding(SupportsShouldProcess=$true)]
    param ( [switch]   $Internal,
            [switch]   $Public,
            [string]   $CacheDirectory="",
            [string[]] $SymbolServers=@(),
            [switch]   $CurrentEnvironmentOnly)
            
    # Do the parameter checking.
    if ($Internal -eq $Public)
    {
        throw "You must specify either -Internal or -Public"
    }

    # Check if VS is running if we are going to be setting the global stuff.
    if (($CurrentEnvironmentOnly -eq $false) -and (Get-Process -Name 'devenv' -ErrorAction SilentlyContinue))
    {
        throw "Visual Studio is running. Please close all instances before running this script"
    }
    
    if ($Internal)
    {
        if ($CacheDirectory.Length -eq 0)
        {
            $CacheDirectory = "C:\SYMBOLS\INTERNAL" 
        }
        
        $symPath = ""

        for ($i = 0 ; $i -lt $SymbolServers.Length ; $i++)
        {
            $symPath += "SRV*$CacheDirectory*"
            $symPath += $SymbolServers[$i]
            $symPath += ";"
        }
        
        $symPath += "SRV*$CacheDirectory*http://SYMWEB"

        if ($CurrentEnvironmentOnly)
        {
            CreateDirectoryIfNeeded -directory $CacheDirectory
            $env:_NT_SYMBOL_PATH = $symPath
        }
        else
        {
            Set-ItemPropertyScript HKCU:\Environment _NT_SYMBOL_PATH $symPath

            if (Test-Path -Path $devTenDebuggerRegKey)
            {
        
                SetInternalSymbolServer $devTenDebuggerRegKey $CacheDirectory $symPath
            }

            if (Test-Path -Path $devElevenDebuggerRegKey)
            {
        
                SetInternalSymbolServer $devElevenDebuggerRegKey $CacheDirectory $symPath
            }

            if (Test-Path -Path $devTwelveDebuggerRegKey)
            {
        
                SetInternalSymbolServer $devTwelveDebuggerRegKey $CacheDirectory $symPath
            }

            if (Test-Path -Path $devFourteenDebuggerRegKey)
            {
        
                SetInternalSymbolServer $devFourteenDebuggerRegKey $CacheDirectory $symPath
            }
        }
    }
    else
    {
    
        if ($CacheDirectory.Length -eq 0)
        {
            $CacheDirectory = "C:\SYMBOLS\PUBLIC" 
        }

        # It's public so we have a little different processing to do as there are
        # two public symbol servers where MSFT provides symbols.
        $refSrcPath = "$CacheDirectory*http://referencesource.microsoft.com/symbols"
        $msdlPath = "$CacheDirectory*https://msdl.microsoft.com/download/symbols"
        $extraPaths = ""
        
        # Poke on any additional symbol servers. I've keeping everything the
        # same between VS as WinDBG.
        for ($i = 0 ; $i -lt $SymbolServers.Length ; $i++)
        {
            $extraPaths += "SRV*$CacheDirectory*"
            $extraPaths += $SymbolServers[$i]
            $extraPaths += ";"
        }

        $envPath = "$extraPaths" + "SRV*$refSrcPath;SRV*$msdlPath"
    
        if ($CurrentEnvironmentOnly)
        {
            CreateDirectoryIfNeeded -directory $CacheDirectory
            $env:_NT_SYMBOL_PATH = $envPath
        }
        else
        {
            Set-ItemPropertyScript HKCU:\Environment _NT_SYMBOL_PATH $envPath
    
            if (Test-Path -Path $devTenDebuggerRegKey)
            {
                SetPublicSymbolServer $devTenDebuggerRegKey $CacheDirectory
            }
        
            if (Test-Path -Path $devElevenDebuggerRegKey)
            {
                SetPublicSymbolServer $devElevenDebuggerRegKey $CacheDirectory
            }

            if (Test-Path -Path $devTwelveDebuggerRegKey)
            {
                SetPublicSymbolServer $devTwelveDebuggerRegKey $CacheDirectory
            }

            if (Test-Path -Path $devFourteenDebuggerRegKey)
            {
                SetPublicSymbolServer $devFourteenDebuggerRegKey $CacheDirectory
            }
        }
    }

    if ($CurrentEnvironmentOnly)
    {
        Write-Verbose -Message "`nThe _NT_SYMBOL_PATH environment variable was updated for this window only`n"
    }
    else
    {
        Write-Verbose -Message "`nPlease log out to activate the new symbol server settings`n"
    }
}

###############################################################################
# SIG # Begin signature block
# MIIYTQYJKoZIhvcNAQcCoIIYPjCCGDoCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUZqGKKzf0UDEaWZmhs6DeENtK
# At+gghM9MIIEhDCCA2ygAwIBAgIQQhrylAmEGR9SCkvGJCanSzANBgkqhkiG9w0B
# AQUFADBvMQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNV
# BAsTHUFkZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRU
# cnVzdCBFeHRlcm5hbCBDQSBSb290MB4XDTA1MDYwNzA4MDkxMFoXDTIwMDUzMDEw
# NDgzOFowgZUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMOU2Fs
# dCBMYWtlIENpdHkxHjAcBgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEhMB8G
# A1UECxMYaHR0cDovL3d3dy51c2VydHJ1c3QuY29tMR0wGwYDVQQDExRVVE4tVVNF
# UkZpcnN0LU9iamVjdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6q
# gT+jo2F4qjEAVZURnicPHxzfOpuCaDDASmEd8S8O+r5596Uj71VRloTN2+O5bj4x
# 2AogZ8f02b+U60cEPgLOKqJdhwQJ9jCdGIqXsqoc/EHSoTbL+z2RuufZcDX65OeQ
# w5ujm9M89RKZd7G3CeBo5hy485RjiGpq/gt2yb70IuRnuasaXnfBhQfdDWy/7gbH
# d2pBnqcP1/vulBe3/IW+pKvEHDHd17bR5PDv3xaPslKT16HUiaEHLr/hARJCHhrh
# 2JU022R5KP+6LhHC5ehbkkj7RwvCbNqtMoNB86XlQXD9ZZBt+vpRxPm9lisZBCzT
# bafc8H9vg2XiaquHhnUCAwEAAaOB9DCB8TAfBgNVHSMEGDAWgBStvZh6NLQm9/rE
# JlTvA73gJMtUGjAdBgNVHQ4EFgQU2u1kdBScFDyr3ZmpvVsoTYs8ydgwDgYDVR0P
# AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0gBAowCDAGBgRVHSAAMEQG
# A1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9BZGRUcnVz
# dEV4dGVybmFsQ0FSb290LmNybDA1BggrBgEFBQcBAQQpMCcwJQYIKwYBBQUHMAGG
# GWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEFBQADggEBAE1C
# L6bBiusHgJBYRoz4GTlmKjxaLG3P1NmHVY15CxKIe0CP1cf4S41VFmOtt1fcOyu9
# 08FPHgOHS0Sb4+JARSbzJkkraoTxVHrUQtr802q7Zn7Knurpu9wHx8OSToM8gUmf
# ktUyCepJLqERcZo20sVOaLbLDhslFq9s3l122B9ysZMmhhfbGN6vRenf+5ivFBjt
# pF72iZRF8FUESt3/J90GSkD2tLzx5A+ZArv9XQ4uKMG+O18aP5cQhLwWPtijnGMd
# ZstcX9o+8w8KCTUi29vAPwD55g1dZ9H9oB4DK9lA977Mh2ZUgKajuPUZYtXSJrGY
# Ju6ay0SnRVqBlRUa9VEwggSUMIIDfKADAgECAhEAn+rIEbDxYkel/CDYBSOs5jAN
# BgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYD
# VQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3
# b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHTAbBgNVBAMT
# FFVUTi1VU0VSRmlyc3QtT2JqZWN0MB4XDTE1MDUwNTAwMDAwMFoXDTE1MTIzMTIz
# NTk1OVowfjELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3Rl
# cjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQx
# JDAiBgNVBAMTG0NPTU9ETyBUaW1lIFN0YW1waW5nIFNpZ25lcjCCASIwDQYJKoZI
# hvcNAQEBBQADggEPADCCAQoCggEBALw1oDZwIoERw7KDudMoxjbNJWupe7Ic9ptR
# nO819O0Ijl44CPh3PApC4PNw3KPXyvVMC8//IpwKfmjWCaIqhHumnbSpwTPi7x8X
# SMo6zUbmxap3veN3mvpHU0AoWUOT8aSB6u+AtU+nCM66brzKdgyXZFmGJLs9gpCo
# VbGS06CnBayfUyUIEEeZzZjeaOW0UHijrwHMWUNY5HZufqzH4p4fT7BHLcgMo0kn
# gHWMuwaRZQ+Qm/S60YHIXGrsFOklCb8jFvSVRkBAIbuDlv2GH3rIDRCOovgZB1h/
# n703AmDypOmdRD8wBeSncJlRmugX8VXKsmGJZUanavJYRn6qoAcCAwEAAaOB9DCB
# 8TAfBgNVHSMEGDAWgBTa7WR0FJwUPKvdmam9WyhNizzJ2DAdBgNVHQ4EFgQULi2w
# CkRK04fAAgfOl31QYiD9D4MwDgYDVR0PAQH/BAQDAgbAMAwGA1UdEwEB/wQCMAAw
# FgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDov
# L2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmlyc3QtT2JqZWN0LmNybDA1Bggr
# BgEFBQcBAQQpMCcwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5j
# b20wDQYJKoZIhvcNAQEFBQADggEBAA27rWARG7XwDczmSDp6Pg4z3By56tYg/qNN
# 0Mx2TugY2Hnf00+aQmQjiilyijpsZqY8OheocEVlxnPD0M6JVPusaQ9YsBnLhp9+
# uX7rUZK/m93r0WXwJXuIfN69pci1FFG8wIEwioU4e+Z5/mdVk4f+T+iNDu3zcpK1
# womAbdFZ4x0N6rE47gOdABmlqyGbecPMwj5ofr3JTWlNtGRR+7IodOJTic6d+q3i
# 286re34GRHT9CqPJt6cwzUnSkmTxIqa4KEV0eemnzjsz+YNQlH1owB1Jx2B4ejxk
# JtW++gpt5B7hCVOPqcUjrMedYUIh8CwWcUk7EK8sbxrmMfEU/WwwggTnMIIDz6AD
# AgECAhAQcJ1P9VQI1zBgAdjqkXW7MA0GCSqGSIb3DQEBBQUAMIGVMQswCQYDVQQG
# EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD
# VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu
# dXNlcnRydXN0LmNvbTEdMBsGA1UEAxMUVVROLVVTRVJGaXJzdC1PYmplY3QwHhcN
# MTEwODI0MDAwMDAwWhcNMjAwNTMwMTA0ODM4WjB7MQswCQYDVQQGEwJHQjEbMBkG
# A1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYD
# VQQKExFDT01PRE8gQ0EgTGltaXRlZDEhMB8GA1UEAxMYQ09NT0RPIENvZGUgU2ln
# bmluZyBDQSAyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy/jnp+jx
# lyhAaIA30sg/jpKKkjeHR4DqTJnPbvkVR73udfRErNDD1E33GcDTPE3BR7lZZRaT
# jNkKhJuf6PZqY1j+X9zRf0tRnwAcAIdUIAdXoILJL5ivM4q7e4AiJWpsr8IsbHkT
# vaMqSNa1jmFV6WvoPYC/FAOFGI5+TOnCGYhzknLN+v9QTcsspnsac7EAkCzZMuL7
# /ayVQjbsNMUTU2iywZ9An9p7yJ1ibJOiQtd5n5dPMVtQIaGrr9kcss51vlssVgAk
# jRHBdR/w/tKV/vDhMSMYZ8BbE/1amJSU//9ZAh8ArObx8vo6c7MdQvxUdc9RMS/j
# 24HZdyMqT1nOIwIDAQABo4IBSjCCAUYwHwYDVR0jBBgwFoAU2u1kdBScFDyr3Zmp
# vVsoTYs8ydgwHQYDVR0OBBYEFB7FsSx9h9oCaHwlvAwHhD+2z97xMA4GA1UdDwEB
# /wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMBMGA1UdJQQMMAoGCCsGAQUFBwMD
# MBEGA1UdIAQKMAgwBgYEVR0gADBCBgNVHR8EOzA5MDegNaAzhjFodHRwOi8vY3Js
# LnVzZXJ0cnVzdC5jb20vVVROLVVTRVJGaXJzdC1PYmplY3QuY3JsMHQGCCsGAQUF
# BwEBBGgwZjA9BggrBgEFBQcwAoYxaHR0cDovL2NydC51c2VydHJ1c3QuY29tL1VU
# TkFkZFRydXN0T2JqZWN0X0NBLmNydDAlBggrBgEFBQcwAYYZaHR0cDovL29jc3Au
# dXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQUFAAOCAQEAlYl3k2gBXnzZLTcHkF1a
# Ql4MZLQ2tQ/2q9U5J94iRqRJHGZLRhlZLnlJA/ackt9tUDVcDJEuYANZ0PFk92kJ
# 9n7+6zSzbbG/ZpyjujF4uYc1YT2SMRvv9Oie1qxF+gw2PIBnu73vLsKQ4T1xLzvB
# sFh+RcNScQMH9vM5TYs2IRsB39naXivrDpeAHkQcUIj1xhIzSqhNpY0vlAx7xr+a
# LMMyzb2MJybw4TADUAaCvPQ7s4N1Bsbvuu7TgPhSxqzLefI4nnuwklhCkQXIliGt
# uUsWgRRp8Tew/jT33LDfl/VDEJt2j7Rl9eifE7cerG/EaYpfujxhfl5JhiMTLq8V
# SDCCBS4wggQWoAMCAQICEHF/qKkhW4DS4HFGfg8Z8PIwDQYJKoZIhvcNAQEFBQAw
# ezELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
# A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxITAfBgNV
# BAMTGENPTU9ETyBDb2RlIFNpZ25pbmcgQ0EgMjAeFw0xMzEwMjgwMDAwMDBaFw0x
# ODEwMjgyMzU5NTlaMIGdMQswCQYDVQQGEwJVUzEOMAwGA1UEEQwFMzc5MzIxCzAJ
# BgNVBAgMAlROMRIwEAYDVQQHDAlLbm94dmlsbGUxEjAQBgNVBAkMCVN1aXRlIDMw
# MjEfMB0GA1UECQwWMTAyMDcgVGVjaG5vbG9neSBEcml2ZTETMBEGA1UECgwKV2lu
# dGVsbGVjdDETMBEGA1UEAwwKV2ludGVsbGVjdDCCASIwDQYJKoZIhvcNAQEBBQAD
# ggEPADCCAQoCggEBAMFQoSYu2olPhQGXgsuq0HBwHsQBoFbuAoYfX3WVp2w8dvji
# kqS+486CmTx2EMH/eKbgarVP0nGIA266BNQ5GXxziGKGk5Y+g74dB269i8G2B24X
# WXZQcw0NTch6oUcXuq2kOkcp1srh4Pp+HQB/qR33qQWzEW7yMlpoI+SwNoa9p1WQ
# aOPzoAfJdiSgInWGgrlAxVwcET0AmVQQKQ2lgJyzQkXIAiRxyJPSgKbZrhTa7/BM
# m33SWmG9K5GlFaw76HFV1e49v8hrTDFJJ7CAQz65IcazjqHTaKOfYhsPhiFrm/Ap
# kPUuJb45MeEPms8DzD8lTSQfo7eLkG2hNtxkRmcCAwEAAaOCAYkwggGFMB8GA1Ud
# IwQYMBaAFB7FsSx9h9oCaHwlvAwHhD+2z97xMB0GA1UdDgQWBBQEi+PkyNipSO6M
# 0oxTXEhobEPaWzAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADATBgNVHSUE
# DDAKBggrBgEFBQcDAzARBglghkgBhvhCAQEEBAMCBBAwRgYDVR0gBD8wPTA7Bgwr
# BgEEAbIxAQIBAwIwKzApBggrBgEFBQcCARYdaHR0cHM6Ly9zZWN1cmUuY29tb2Rv
# Lm5ldC9DUFMwQQYDVR0fBDowODA2oDSgMoYwaHR0cDovL2NybC5jb21vZG9jYS5j
# b20vQ09NT0RPQ29kZVNpZ25pbmdDQTIuY3JsMHIGCCsGAQUFBwEBBGYwZDA8Bggr
# BgEFBQcwAoYwaHR0cDovL2NydC5jb21vZG9jYS5jb20vQ09NT0RPQ29kZVNpZ25p
# bmdDQTIuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20w
# DQYJKoZIhvcNAQEFBQADggEBAB4m8FXuYk3D2mVYZ3vvghqRSRVgEqJmG7YBBv2e
# QCk9CYML37ubpYigH3JDzWMIDS8sfv6hzJzY4tgRuY29rJBMyaWRw228IEOLkLZq
# Si/JOxOT4NOyLYacOSD1DHH63YFnlDFpt+ZRAOKbPavG7muW97FZT3ebCvLCJYrL
# lYSym4E8H/y7ICSijbaIBt/zHtFX8RJvV7bijvxZI1xqqKyx9hyF/4gNWMq9uQiE
# wIG13VT/UmNCc3KcCsy9fqnWreFh76EuI9arj1VROG2FaYQdaxD2O+9nl+uxFmOM
# eOHqhQWlv57eO9do7PI6PiVGMTkiC2eFTeBEHWylCUFDkDIxggR6MIIEdgIBATCB
# jzB7MQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAw
# DgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDEhMB8G
# A1UEAxMYQ09NT0RPIENvZGUgU2lnbmluZyBDQSAyAhBxf6ipIVuA0uBxRn4PGfDy
# MAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3
# DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEV
# MCMGCSqGSIb3DQEJBDEWBBTOLgKrJ9/Em4CuSUwV+a9h5LzqAjANBgkqhkiG9w0B
# AQEFAASCAQC6D+fGPeeJHmguB0NEde2qEqpvSHcc0X4sza1RuSxKw4M6nyYvTueh
# capsp3CEy6P1DShOY2yNBE/DdCOK9mBtk8qAyvyLfzrA58cv6hJLk89PCSQkPh6R
# hP/nbbrt3fQE1PHylDy+74Ex1oTJXxe/IolfJLqFUBZiYqtDA6r1tmCXtc0jgX7G
# QG6f6FPm9MOd9S3u6VO8puJwa1PgzkPrTg8oiVzjlZ7ky/5tHGlVGTQqeUIyisa8
# xUWyFOYtzPuPGh0JLOq7cRp65X62miGZ0oBxcAPq8Ou4DvhdHpDW2XHDl4jI2J0u
# Mr5oXs9p/oHcNfyuyxiGzMNMN4Rnx33KoYICRTCCAkEGCSqGSIb3DQEJBjGCAjIw
# ggIuAgEAMIGrMIGVMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcT
# DlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsx
# ITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTEdMBsGA1UEAxMUVVRO
# LVVTRVJGaXJzdC1PYmplY3QCEQCf6sgRsPFiR6X8INgFI6zmMAkGBSsOAwIaBQCg
# XTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0xNTA3
# MDkxNzIwMThaMCMGCSqGSIb3DQEJBDEWBBShkiMY80DjPRARBmzNPUxLMLf7RzAN
# BgkqhkiG9w0BAQEFAASCAQAoH5imjbfVA+XUoCpNavDZFABBhgIJH/HfxcJIsipS
# nWJCqoXrH4GESJGykuBjKocldbumpS2yEDmi1MkOLPTp19VpwGYssYuzOlFRRZzk
# MsFVS+Nd6ZT6eFaqMD7cpIW3djXx+3z9h7xqmcPB2Lb480hCAUP5Xyh9f4wjMffj
# 5MdnoEXD995t1zzTFDSvYsHPlYsO3bN6ra/6ZzXK2hkSm+ldERHLBPY0oxN4CXWV
# 5fykFzX23yw1l7J9itFO+M+qOihRbeykPBdGeUaC+ZS2PmOKD16dWq/arxrhr46i
# RAeigyGfzkswRz67p6Ij6KgcG0+5LYPrPLflyLBz0MZv
# SIG # End signature block