123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437 |
- <#
- .Synopsis
- Activate a Python virtual environment for the current PowerShell session.
- .Description
- Pushes the python executable for a virtual environment to the front of the
- $Env:PATH environment variable and sets the prompt to signify that you are
- in a Python virtual environment. Makes use of the command line switches as
- well as the `pyvenv.cfg` file values present in the virtual environment.
- .Parameter VenvDir
- Path to the directory that contains the virtual environment to activate. The
- default value for this is the parent of the directory that the Activate.ps1
- script is located within.
- .Parameter Prompt
- The prompt prefix to display when this virtual environment is activated. By
- default, this prompt is the name of the virtual environment folder (VenvDir)
- surrounded by parentheses and followed by a single space (ie. '(.venv) ').
- .Example
- Activate.ps1
- Activates the Python virtual environment that contains the Activate.ps1 script.
- .Example
- Activate.ps1 -Verbose
- Activates the Python virtual environment that contains the Activate.ps1 script,
- and shows extra information about the activation as it executes.
- .Example
- Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv
- Activates the Python virtual environment located in the specified location.
- .Example
- Activate.ps1 -Prompt "MyPython"
- Activates the Python virtual environment that contains the Activate.ps1 script,
- and prefixes the current prompt with the specified string (surrounded in
- parentheses) while the virtual environment is active.
- .Notes
- On Windows, it may be required to enable this Activate.ps1 script by setting the
- execution policy for the user. You can do this by issuing the following PowerShell
- command:
- PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
- For more information on Execution Policies:
- https://go.microsoft.com/fwlink/?LinkID=135170
- #>
- Param(
- [Parameter(Mandatory = $false)]
- [String]
- $VenvDir,
- [Parameter(Mandatory = $false)]
- [String]
- $Prompt
- )
- <# Function declarations --------------------------------------------------- #>
- <#
- .Synopsis
- Remove all shell session elements added by the Activate script, including the
- addition of the virtual environment's Python executable from the beginning of
- the PATH variable.
- .Parameter NonDestructive
- If present, do not remove this function from the global namespace for the
- session.
- #>
- function global:deactivate ([switch]$NonDestructive) {
- # Revert to original values
- # The prior prompt:
- if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) {
- Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt
- Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT
- }
- # The prior PYTHONHOME:
- if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) {
- Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME
- Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME
- }
- # The prior PATH:
- if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) {
- Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH
- Remove-Item -Path Env:_OLD_VIRTUAL_PATH
- }
- # Just remove the VIRTUAL_ENV altogether:
- if (Test-Path -Path Env:VIRTUAL_ENV) {
- Remove-Item -Path env:VIRTUAL_ENV
- }
- # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether:
- if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) {
- Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force
- }
- # Leave deactivate function in the global namespace if requested:
- if (-not $NonDestructive) {
- Remove-Item -Path function:deactivate
- }
- }
- <#
- .Description
- Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the
- given folder, and returns them in a map.
- For each line in the pyvenv.cfg file, if that line can be parsed into exactly
- two strings separated by `=` (with any amount of whitespace surrounding the =)
- then it is considered a `key = value` line. The left hand string is the key,
- the right hand is the value.
- If the value starts with a `'` or a `"` then the first and last character is
- stripped from the value before being captured.
- .Parameter ConfigDir
- Path to the directory that contains the `pyvenv.cfg` file.
- #>
- function Get-PyVenvConfig(
- [String]
- $ConfigDir
- ) {
- Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg"
- # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue).
- $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue
- # An empty map will be returned if no config file is found.
- $pyvenvConfig = @{ }
- if ($pyvenvConfigPath) {
- Write-Verbose "File exists, parse `key = value` lines"
- $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath
- $pyvenvConfigContent | ForEach-Object {
- $keyval = $PSItem -split "\s*=\s*", 2
- if ($keyval[0] -and $keyval[1]) {
- $val = $keyval[1]
- # Remove extraneous quotations around a string value.
- if ("'""".Contains($val.Substring(0, 1))) {
- $val = $val.Substring(1, $val.Length - 2)
- }
- $pyvenvConfig[$keyval[0]] = $val
- Write-Verbose "Adding Key: '$($keyval[0])'='$val'"
- }
- }
- }
- return $pyvenvConfig
- }
- <# Begin Activate script --------------------------------------------------- #>
- # Determine the containing directory of this script
- $VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
- $VenvExecDir = Get-Item -Path $VenvExecPath
- Write-Verbose "Activation script is located in path: '$VenvExecPath'"
- Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)"
- Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)"
- # Set values required in priority: CmdLine, ConfigFile, Default
- # First, get the location of the virtual environment, it might not be
- # VenvExecDir if specified on the command line.
- if ($VenvDir) {
- Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values"
- }
- else {
- Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir."
- $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/")
- Write-Verbose "VenvDir=$VenvDir"
- }
- # Next, read the `pyvenv.cfg` file to determine any required value such
- # as `prompt`.
- $pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir
- # Next, set the prompt from the command line, or the config file, or
- # just use the name of the virtual environment folder.
- if ($Prompt) {
- Write-Verbose "Prompt specified as argument, using '$Prompt'"
- }
- else {
- Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value"
- if ($pyvenvCfg -and $pyvenvCfg['prompt']) {
- Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'"
- $Prompt = $pyvenvCfg['prompt'];
- }
- else {
- Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)"
- Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'"
- $Prompt = Split-Path -Path $venvDir -Leaf
- }
- }
- Write-Verbose "Prompt = '$Prompt'"
- Write-Verbose "VenvDir='$VenvDir'"
- # Deactivate any currently active virtual environment, but leave the
- # deactivate function in place.
- deactivate -nondestructive
- # Now set the environment variable VIRTUAL_ENV, used by many tools to determine
- # that there is an activated venv.
- $env:VIRTUAL_ENV = $VenvDir
- if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) {
- Write-Verbose "Setting prompt to '$Prompt'"
- # Set the prompt to include the env name
- # Make sure _OLD_VIRTUAL_PROMPT is global
- function global:_OLD_VIRTUAL_PROMPT { "" }
- Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT
- New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt
- function global:prompt {
- Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) "
- _OLD_VIRTUAL_PROMPT
- }
- }
- # Clear PYTHONHOME
- if (Test-Path -Path Env:PYTHONHOME) {
- Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME
- Remove-Item -Path Env:PYTHONHOME
- }
- # Add the venv to the PATH
- Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH
- $Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH"
- # SIG # Begin signature block
- # MIIkCQYJKoZIhvcNAQcCoIIj+jCCI/YCAQExDzANBglghkgBZQMEAgEFADB5Bgor
- # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
- # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCD50itNqbOCCDp6
- # 9ZnhKce5X7vV6KL67iKMbGTUZ4nf36CCDi8wggawMIIEmKADAgECAhAIrUCyYNKc
- # TJ9ezam9k67ZMA0GCSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
- # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNV
- # BAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0yMTA0MjkwMDAwMDBaFw0z
- # NjA0MjgyMzU5NTlaMGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwg
- # SW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcg
- # UlNBNDA5NiBTSEEzODQgMjAyMSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
- # ggIKAoICAQDVtC9C0CiteLdd1TlZG7GIQvUzjOs9gZdwxbvEhSYwn6SOaNhc9es0
- # JAfhS0/TeEP0F9ce2vnS1WcaUk8OoVf8iJnBkcyBAz5NcCRks43iCH00fUyAVxJr
- # Q5qZ8sU7H/Lvy0daE6ZMswEgJfMQ04uy+wjwiuCdCcBlp/qYgEk1hz1RGeiQIXhF
- # LqGfLOEYwhrMxe6TSXBCMo/7xuoc82VokaJNTIIRSFJo3hC9FFdd6BgTZcV/sk+F
- # LEikVoQ11vkunKoAFdE3/hoGlMJ8yOobMubKwvSnowMOdKWvObarYBLj6Na59zHh
- # 3K3kGKDYwSNHR7OhD26jq22YBoMbt2pnLdK9RBqSEIGPsDsJ18ebMlrC/2pgVItJ
- # wZPt4bRc4G/rJvmM1bL5OBDm6s6R9b7T+2+TYTRcvJNFKIM2KmYoX7BzzosmJQay
- # g9Rc9hUZTO1i4F4z8ujo7AqnsAMrkbI2eb73rQgedaZlzLvjSFDzd5Ea/ttQokbI
- # YViY9XwCFjyDKK05huzUtw1T0PhH5nUwjewwk3YUpltLXXRhTT8SkXbev1jLchAp
- # QfDVxW0mdmgRQRNYmtwmKwH0iU1Z23jPgUo+QEdfyYFQc4UQIyFZYIpkVMHMIRro
- # OBl8ZhzNeDhFMJlP/2NPTLuqDQhTQXxYPUez+rbsjDIJAsxsPAxWEQIDAQABo4IB
- # WTCCAVUwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUaDfg67Y7+F8Rhvv+
- # YXsIiGX0TkIwHwYDVR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0P
- # AQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMDMHcGCCsGAQUFBwEBBGswaTAk
- # BggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAC
- # hjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9v
- # dEc0LmNydDBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5j
- # b20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNybDAcBgNVHSAEFTATMAcGBWeBDAED
- # MAgGBmeBDAEEATANBgkqhkiG9w0BAQwFAAOCAgEAOiNEPY0Idu6PvDqZ01bgAhql
- # +Eg08yy25nRm95RysQDKr2wwJxMSnpBEn0v9nqN8JtU3vDpdSG2V1T9J9Ce7FoFF
- # UP2cvbaF4HZ+N3HLIvdaqpDP9ZNq4+sg0dVQeYiaiorBtr2hSBh+3NiAGhEZGM1h
- # mYFW9snjdufE5BtfQ/g+lP92OT2e1JnPSt0o618moZVYSNUa/tcnP/2Q0XaG3Ryw
- # YFzzDaju4ImhvTnhOE7abrs2nfvlIVNaw8rpavGiPttDuDPITzgUkpn13c5Ubdld
- # AhQfQDN8A+KVssIhdXNSy0bYxDQcoqVLjc1vdjcshT8azibpGL6QB7BDf5WIIIJw
- # 8MzK7/0pNVwfiThV9zeKiwmhywvpMRr/LhlcOXHhvpynCgbWJme3kuZOX956rEnP
- # LqR0kq3bPKSchh/jwVYbKyP/j7XqiHtwa+aguv06P0WmxOgWkVKLQcBIhEuWTatE
- # QOON8BUozu3xGFYHKi8QxAwIZDwzj64ojDzLj4gLDb879M4ee47vtevLt/B3E+bn
- # KD+sEq6lLyJsQfmCXBVmzGwOysWGw/YmMwwHS6DTBwJqakAwSEs0qFEgu60bhQji
- # WQ1tygVQK+pKHJ6l/aCnHwZ05/LWUpD9r4VIIflXO7ScA+2GRfS0YW6/aOImYIbq
- # yK+p/pQd52MbOoZWeE4wggd3MIIFX6ADAgECAhAHHxQbizANJfMU6yMM0NHdMA0G
- # CSqGSIb3DQEBCwUAMGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwg
- # SW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcg
- # UlNBNDA5NiBTSEEzODQgMjAyMSBDQTEwHhcNMjIwMTE3MDAwMDAwWhcNMjUwMTE1
- # MjM1OTU5WjB8MQswCQYDVQQGEwJVUzEPMA0GA1UECBMGT3JlZ29uMRIwEAYDVQQH
- # EwlCZWF2ZXJ0b24xIzAhBgNVBAoTGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9u
- # MSMwIQYDVQQDExpQeXRob24gU29mdHdhcmUgRm91bmRhdGlvbjCCAiIwDQYJKoZI
- # hvcNAQEBBQADggIPADCCAgoCggIBAKgc0BTT+iKbtK6f2mr9pNMUTcAJxKdsuOiS
- # YgDFfwhjQy89koM7uP+QV/gwx8MzEt3c9tLJvDccVWQ8H7mVsk/K+X+IufBLCgUi
- # 0GGAZUegEAeRlSXxxhYScr818ma8EvGIZdiSOhqjYc4KnfgfIS4RLtZSrDFG2tN1
- # 6yS8skFa3IHyvWdbD9PvZ4iYNAS4pjYDRjT/9uzPZ4Pan+53xZIcDgjiTwOh8VGu
- # ppxcia6a7xCyKoOAGjvCyQsj5223v1/Ig7Dp9mGI+nh1E3IwmyTIIuVHyK6Lqu35
- # 2diDY+iCMpk9ZanmSjmB+GMVs+H/gOiofjjtf6oz0ki3rb7sQ8fTnonIL9dyGTJ0
- # ZFYKeb6BLA66d2GALwxZhLe5WH4Np9HcyXHACkppsE6ynYjTOd7+jN1PRJahN1oE
- # RzTzEiV6nCO1M3U1HbPTGyq52IMFSBM2/07WTJSbOeXjvYR7aUxK9/ZkJiacl2iZ
- # I7IWe7JKhHohqKuceQNyOzxTakLcRkzynvIrk33R9YVqtB4L6wtFxhUjvDnQg16x
- # ot2KVPdfyPAWd81wtZADmrUtsZ9qG79x1hBdyOl4vUtVPECuyhCxaw+faVjumapP
- # Unwo8ygflJJ74J+BYxf6UuD7m8yzsfXWkdv52DjL74TxzuFTLHPyARWCSCAbzn3Z
- # Ily+qIqDAgMBAAGjggIGMIICAjAfBgNVHSMEGDAWgBRoN+Drtjv4XxGG+/5hewiI
- # ZfROQjAdBgNVHQ4EFgQUt/1Teh2XDuUj2WW3siYWJgkZHA8wDgYDVR0PAQH/BAQD
- # AgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMIG1BgNVHR8Ega0wgaowU6BRoE+GTWh0
- # dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNENvZGVTaWdu
- # aW5nUlNBNDA5NlNIQTM4NDIwMjFDQTEuY3JsMFOgUaBPhk1odHRwOi8vY3JsNC5k
- # aWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZT
- # SEEzODQyMDIxQ0ExLmNybDA+BgNVHSAENzA1MDMGBmeBDAEEATApMCcGCCsGAQUF
- # BwIBFhtodHRwOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwgZQGCCsGAQUFBwEBBIGH
- # MIGEMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wXAYIKwYB
- # BQUHMAKGUGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0
- # ZWRHNENvZGVTaWduaW5nUlNBNDA5NlNIQTM4NDIwMjFDQTEuY3J0MAwGA1UdEwEB
- # /wQCMAAwDQYJKoZIhvcNAQELBQADggIBABxv4AeV/5ltkELHSC63fXAFYS5tadcW
- # TiNc2rskrNLrfH1Ns0vgSZFoQxYBFKI159E8oQQ1SKbTEubZ/B9kmHPhprHya08+
- # VVzxC88pOEvz68nA82oEM09584aILqYmj8Pj7h/kmZNzuEL7WiwFa/U1hX+XiWfL
- # IJQsAHBla0i7QRF2de8/VSF0XXFa2kBQ6aiTsiLyKPNbaNtbcucaUdn6vVUS5izW
- # OXM95BSkFSKdE45Oq3FForNJXjBvSCpwcP36WklaHL+aHu1upIhCTUkzTHMh8b86
- # WmjRUqbrnvdyR2ydI5l1OqcMBjkpPpIV6wcc+KY/RH2xvVuuoHjlUjwq2bHiNoX+
- # W1scCpnA8YTs2d50jDHUgwUo+ciwpffH0Riq132NFmrH3r67VaN3TuBxjI8SIZM5
- # 8WEDkbeoriDk3hxU8ZWV7b8AW6oyVBGfM06UgkfMb58h+tJPrFx8VI/WLq1dTqMf
- # ZOm5cuclMnUHs2uqrRNtnV8UfidPBL4ZHkTcClQbCoz0UbLhkiDvIS00Dn+BBcxw
- # /TKqVL4Oaz3bkMSsM46LciTeucHY9ExRVt3zy7i149sd+F4QozPqn7FrSVHXmem3
- # r7bjyHTxOgqxRCVa18Vtx7P/8bYSBeS+WHCKcliFCecspusCDSlnRUjZwyPdP0VH
- # xaZg2unjHY3rMYIVMDCCFSwCAQEwfTBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMO
- # RGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgQ29k
- # ZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEgQ0ExAhAHHxQbizANJfMU6yMM
- # 0NHdMA0GCWCGSAFlAwQCAQUAoIHOMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEE
- # MBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCBW
- # STMEpY5oTqEtnhE8rXHTfUpY7MZMEfDbBKbS1J0cLTBiBgorBgEEAYI3AgEMMVQw
- # UqBQgE4AQgB1AGkAbAB0ADoAIABSAGUAbABlAGEAcwBlAF8AbQBhAGkAbgBfAHYA
- # MwAuADkALgAxADMAXwAyADAAMgAyADAANQAxADcALgAwADIwDQYJKoZIhvcNAQEB
- # BQAEggIAZ20aZkGkTuZACtVG89TVf+3Nw7cpJO4pkpM71AFEX7/TZ4NjeFMHCrEr
- # g8kNhN1UNcf0FGKplenCcykaIYUTlYgT3VCOeRGINOmySIotyEfYw4HapwNhj8/G
- # CK/XOKJvIZ96yHHkpaiCOx3JDVtX5UjkChX1IJNECy0RyzALQA9U/EQl7v8oNEs6
- # mCHRfPflHgkPYUPYUJXAGk3tD0ZgeeomUR0zm6Zmvqar2RJaZADtCF5OxOcFbdui
- # 9yrlbSlkxv6gSW60W372FRCIoy1BML7Okjv7QJnhJkPIAs4sb0ZCV3rB6ZjKBXx3
- # WzeQ5yjpJ3O1ZsZKPP4XVayPJCv2PSRd8dlDgmJtMbN2gvjsLtOkDKN03jnEsiiX
- # 9IeYu7AaDdDeMDW8U5A0HYStrVX7OYpLqojtWOdeIz3/thj9ncWDio4KqEZTud37
- # kfhDQPks9zWHoeI8MnjWMgBCEMskNFQnEhgGNlxWRW8bzypODhlrUGB271/6tFCE
- # UW24irgtfCvNVmQh5E7V+GNplFujgCa7O4wQvYBb1i2OnQ+igJkfWx2N+wmb8QYE
- # mN4RM/bk/SOc1b3MnU/ztqscOPPllmQsqMe/8LW77Ww2fy3i88RlcjweWiTs+3AK
- # akFenQ/OzGPTrG8+mMKEjRKuxKyL2uZRKUoZ2zVlmjEddgnIVCWhghGzMIIRrwYK
- # KwYBBAGCNwMDATGCEZ8wghGbBgkqhkiG9w0BBwKgghGMMIIRiAIBAzEPMA0GCWCG
- # SAFlAwQCAQUAMHgGCyqGSIb3DQEJEAEEoGkEZzBlAgEBBglghkgBhv1sBwEwMTAN
- # BglghkgBZQMEAgEFAAQgnT/1Hedipjs4jpirOCgW93RhvoYu0jJ5WKO7Y0LYfrYC
- # EQDwVmhL49/+ciLQ3plX3i8KGA8yMDIyMDUxNzE2NDQyNVqggg18MIIGxjCCBK6g
- # AwIBAgIQCnpKiJ7JmUKQBmM4TYaXnTANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQG
- # EwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0
- # IFRydXN0ZWQgRzQgUlNBNDA5NiBTSEEyNTYgVGltZVN0YW1waW5nIENBMB4XDTIy
- # MDMyOTAwMDAwMFoXDTMzMDMxNDIzNTk1OVowTDELMAkGA1UEBhMCVVMxFzAVBgNV
- # BAoTDkRpZ2lDZXJ0LCBJbmMuMSQwIgYDVQQDExtEaWdpQ2VydCBUaW1lc3RhbXAg
- # MjAyMiAtIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC5KpYjply8
- # X9ZJ8BWCGPQz7sxcbOPgJS7SMeQ8QK77q8TjeF1+XDbq9SWNQ6OB6zhj+TyIad48
- # 0jBRDTEHukZu6aNLSOiJQX8Nstb5hPGYPgu/CoQScWyhYiYB087DbP2sO37cKhyp
- # vTDGFtjavOuy8YPRn80JxblBakVCI0Fa+GDTZSw+fl69lqfw/LH09CjPQnkfO8eT
- # B2ho5UQ0Ul8PUN7UWSxEdMAyRxlb4pguj9DKP//GZ888k5VOhOl2GJiZERTFKwyg
- # M9tNJIXogpThLwPuf4UCyYbh1RgUtwRF8+A4vaK9enGY7BXn/S7s0psAiqwdjTuA
- # aP7QWZgmzuDtrn8oLsKe4AtLyAjRMruD+iM82f/SjLv3QyPf58NaBWJ+cCzlK7I9
- # Y+rIroEga0OJyH5fsBrdGb2fdEEKr7mOCdN0oS+wVHbBkE+U7IZh/9sRL5IDMM4w
- # t4sPXUSzQx0jUM2R1y+d+/zNscGnxA7E70A+GToC1DGpaaBJ+XXhm+ho5GoMj+vk
- # sSF7hmdYfn8f6CvkFLIW1oGhytowkGvub3XAsDYmsgg7/72+f2wTGN/GbaR5Sa2L
- # f2GHBWj31HDjQpXonrubS7LitkE956+nGijJrWGwoEEYGU7tR5thle0+C2Fa6j56
- # mJJRzT/JROeAiylCcvd5st2E6ifu/n16awIDAQABo4IBizCCAYcwDgYDVR0PAQH/
- # BAQDAgeAMAwGA1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwIAYD
- # VR0gBBkwFzAIBgZngQwBBAIwCwYJYIZIAYb9bAcBMB8GA1UdIwQYMBaAFLoW2W1N
- # hS9zKXaaL3WMaiCPnshvMB0GA1UdDgQWBBSNZLeJIf5WWESEYafqbxw2j92vDTBa
- # BgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNl
- # cnRUcnVzdGVkRzRSU0E0MDk2U0hBMjU2VGltZVN0YW1waW5nQ0EuY3JsMIGQBggr
- # BgEFBQcBAQSBgzCBgDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQu
- # Y29tMFgGCCsGAQUFBzAChkxodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGln
- # aUNlcnRUcnVzdGVkRzRSU0E0MDk2U0hBMjU2VGltZVN0YW1waW5nQ0EuY3J0MA0G
- # CSqGSIb3DQEBCwUAA4ICAQANLSN0ptH1+OpLmT8B5PYM5K8WndmzjJeCKZxDbwEt
- # qzi1cBG/hBmLP13lhk++kzreKjlaOU7YhFmlvBuYquhs79FIaRk4W8+JOR1wcNlO
- # 3yMibNXf9lnLocLqTHbKodyhK5a4m1WpGmt90fUCCU+C1qVziMSYgN/uSZW3s8zF
- # p+4O4e8eOIqf7xHJMUpYtt84fMv6XPfkU79uCnx+196Y1SlliQ+inMBl9AEiZcfq
- # XnSmWzWSUHz0F6aHZE8+RokWYyBry/J70DXjSnBIqbbnHWC9BCIVJXAGcqlEO2lH
- # EdPu6cegPk8QuTA25POqaQmoi35komWUEftuMvH1uzitzcCTEdUyeEpLNypM81zc
- # toXAu3AwVXjWmP5UbX9xqUgaeN1Gdy4besAzivhKKIwSqHPPLfnTI/KeGeANlCig
- # 69saUaCVgo4oa6TOnXbeqXOqSGpZQ65f6vgPBkKd3wZolv4qoHRbY2beayy4eKpN
- # cG3wLPEHFX41tOa1DKKZpdcVazUOhdbgLMzgDCS4fFILHpl878jIxYxYaa+rPeHP
- # zH0VrhS/inHfypex2EfqHIXgRU4SHBQpWMxv03/LvsEOSm8gnK7ZczJZCOctkqEa
- # Ef4ymKZdK5fgi9OczG21Da5HYzhHF1tvE9pqEG4fSbdEW7QICodaWQR2EaGndwIT
- # HDCCBq4wggSWoAMCAQICEAc2N7ckVHzYR6z9KGYqXlswDQYJKoZIhvcNAQELBQAw
- # YjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQ
- # d3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgVHJ1c3RlZCBSb290
- # IEc0MB4XDTIyMDMyMzAwMDAwMFoXDTM3MDMyMjIzNTk1OVowYzELMAkGA1UEBhMC
- # VVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMTswOQYDVQQDEzJEaWdpQ2VydCBU
- # cnVzdGVkIEc0IFJTQTQwOTYgU0hBMjU2IFRpbWVTdGFtcGluZyBDQTCCAiIwDQYJ
- # KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMaGNQZJs8E9cklRVcclA8TykTepl1Gh
- # 1tKD0Z5Mom2gsMyD+Vr2EaFEFUJfpIjzaPp985yJC3+dH54PMx9QEwsmc5Zt+Feo
- # An39Q7SE2hHxc7Gz7iuAhIoiGN/r2j3EF3+rGSs+QtxnjupRPfDWVtTnKC3r07G1
- # decfBmWNlCnT2exp39mQh0YAe9tEQYncfGpXevA3eZ9drMvohGS0UvJ2R/dhgxnd
- # X7RUCyFobjchu0CsX7LeSn3O9TkSZ+8OpWNs5KbFHc02DVzV5huowWR0QKfAcsW6
- # Th+xtVhNef7Xj3OTrCw54qVI1vCwMROpVymWJy71h6aPTnYVVSZwmCZ/oBpHIEPj
- # Q2OAe3VuJyWQmDo4EbP29p7mO1vsgd4iFNmCKseSv6De4z6ic/rnH1pslPJSlREr
- # WHRAKKtzQ87fSqEcazjFKfPKqpZzQmiftkaznTqj1QPgv/CiPMpC3BhIfxQ0z9JM
- # q++bPf4OuGQq+nUoJEHtQr8FnGZJUlD0UfM2SU2LINIsVzV5K6jzRWC8I41Y99xh
- # 3pP+OcD5sjClTNfpmEpYPtMDiP6zj9NeS3YSUZPJjAw7W4oiqMEmCPkUEBIDfV8j
- # u2TjY+Cm4T72wnSyPx4JduyrXUZ14mCjWAkBKAAOhFTuzuldyF4wEr1GnrXTdrnS
- # DmuZDNIztM2xAgMBAAGjggFdMIIBWTASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1Ud
- # DgQWBBS6FtltTYUvcyl2mi91jGogj57IbzAfBgNVHSMEGDAWgBTs1+OC0nFdZEzf
- # Lmc/57qYrhwPTzAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0lBAwwCgYIKwYBBQUHAwgw
- # dwYIKwYBBQUHAQEEazBpMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy
- # dC5jb20wQQYIKwYBBQUHMAKGNWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9E
- # aWdpQ2VydFRydXN0ZWRSb290RzQuY3J0MEMGA1UdHwQ8MDowOKA2oDSGMmh0dHA6
- # Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRSb290RzQuY3JsMCAG
- # A1UdIAQZMBcwCAYGZ4EMAQQCMAsGCWCGSAGG/WwHATANBgkqhkiG9w0BAQsFAAOC
- # AgEAfVmOwJO2b5ipRCIBfmbW2CFC4bAYLhBNE88wU86/GPvHUF3iSyn7cIoNqilp
- # /GnBzx0H6T5gyNgL5Vxb122H+oQgJTQxZ822EpZvxFBMYh0MCIKoFr2pVs8Vc40B
- # IiXOlWk/R3f7cnQU1/+rT4osequFzUNf7WC2qk+RZp4snuCKrOX9jLxkJodskr2d
- # fNBwCnzvqLx1T7pa96kQsl3p/yhUifDVinF2ZdrM8HKjI/rAJ4JErpknG6skHibB
- # t94q6/aesXmZgaNWhqsKRcnfxI2g55j7+6adcq/Ex8HBanHZxhOACcS2n82HhyS7
- # T6NJuXdmkfFynOlLAlKnN36TU6w7HQhJD5TNOXrd/yVjmScsPT9rp/Fmw0HNT7ZA
- # myEhQNC3EyTN3B14OuSereU0cZLXJmvkOHOrpgFPvT87eK1MrfvElXvtCl8zOYdB
- # eHo46Zzh3SP9HSjTx/no8Zhf+yvYfvJGnXUsHicsJttvFXseGYs2uJPU5vIXmVnK
- # cPA3v5gA3yAWTyf7YGcWoWa63VXAOimGsJigK+2VQbc61RWYMbRiCQ8KvYHZE/6/
- # pNHzV9m8BPqC3jLfBInwAM1dwvnQI38AC+R2AibZ8GV2QqYphwlHK+Z/GqSFD/yY
- # lvZVVCsfgPrA8g4r5db7qS9EFUrnEw4d2zc4GqEr9u3WfPwxggN2MIIDcgIBATB3
- # MGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UE
- # AxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBp
- # bmcgQ0ECEAp6SoieyZlCkAZjOE2Gl50wDQYJYIZIAWUDBAIBBQCggdEwGgYJKoZI
- # hvcNAQkDMQ0GCyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yMjA1MTcxNjQ0
- # MjVaMCsGCyqGSIb3DQEJEAIMMRwwGjAYMBYEFIUI84ZRXLPTB322tLfAfxtKXkHe
- # MC8GCSqGSIb3DQEJBDEiBCD6nFFQEG6P9dJgqwYWRs4qcIuEc8WzVzP/ANrLjNw9
- # 9DA3BgsqhkiG9w0BCRACLzEoMCYwJDAiBCCdppAVw0nGwYl4Rbo1gq1wyI+kKTvb
- # ar6cK9JTknnmOzANBgkqhkiG9w0BAQEFAASCAgAw6wjOhvvgNacByXWLXEcHuoRB
- # hCB6I/ZNStOapAzlidSg0ccPO4QsS5L78/ff+DCa4ZFu//T2wfORd9wCt9NpL0XT
- # 7/zVF3zw16aNIn1W9gbJkjPfHGLImV30M/PzMnzlj3m9ybK0W/vvu8SmNpMrsSKI
- # sR1/nSzaA+Y0FmOOy2jtf7MtZeVh8o4ZkgBVPgVLpRSr4SJXzadMjQjshWII2ujM
- # v2YPK7qczQmXaonfN+rAkPxLS+3MVDgoUKAGvQBpm686eDkImZ0qTG+Qi6+Z+2id
- # QXv8h4V4L7Ln37RNsm4j5carTNxTx6b0SZPreswMEFfUwtHeaSWvUIKRzyY0t3O/
- # NT5G8RSxtJLqTMVFWcmlbgaXo7/PDsA7hs1XQJE3UJnfRNrcznnHgYJPuW737A9Q
- # v4sFjmov5/F4qUbYIh5yE8ec4IhOuR0rTEgDJLcU67KdrLjcePMlIlbPaArw1vn3
- # On862t4jYz5aj3YaaHYzXB6VxiMp9JN5B3e4gmix/8TgN9kNmvbVwODfK5hfaPcY
- # QXkTBySKKoRz+eyz67IBXPCHDYXtiXdaqvhWPFn+YbFH9jlEqPP2ATzqEz/ibgDZ
- # 0YyvPy8vnItbUwPuGTVjwU0VmF0m5pSHm/pPALd1xKiMF+eZq580lbrIoUeyZ5mP
- # 0XyrSEj88tBJMxcKZA==
- # SIG # End signature block
|