diff --git a/lab_3/aimenv/Scripts/Activate.ps1 b/lab_3/aimenv/Scripts/Activate.ps1
new file mode 100644
index 0000000..3045241
--- /dev/null
+++ b/lab_3/aimenv/Scripts/Activate.ps1
@@ -0,0 +1,502 @@
+<#
+.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 VIRTUAL_ENV_PROMPT altogether.
+ if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) {
+ Remove-Item -Path env:VIRTUAL_ENV_PROMPT
+ }
+
+ # 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
+ }
+ $env:VIRTUAL_ENV_PROMPT = $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
+# MIIvIwYJKoZIhvcNAQcCoIIvFDCCLxACAQExDzANBglghkgBZQMEAgEFADB5Bgor
+# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
+# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBnL745ElCYk8vk
+# dBtMuQhLeWJ3ZGfzKW4DHCYzAn+QB6CCE8MwggWQMIIDeKADAgECAhAFmxtXno4h
+# MuI5B72nd3VcMA0GCSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
+# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNV
+# BAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0xMzA4MDExMjAwMDBaFw0z
+# ODAxMTUxMjAwMDBaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ
+# bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0
+# IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
+# AL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsbhA3EMB/z
+# G6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKyunWZ
+# anMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGbNOsFxl7s
+# Wxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclPXuU15zHL
+# 2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJBMtfb
+# BHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFPObURWBf3
+# JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTvkpI6nj3c
+# AORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWMcCxBYKqx
+# YxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5SUUd0
+# viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+xq4aL
+# T8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjQjBAMA8GA1Ud
+# EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTs1+OC0nFdZEzf
+# Lmc/57qYrhwPTzANBgkqhkiG9w0BAQwFAAOCAgEAu2HZfalsvhfEkRvDoaIAjeNk
+# aA9Wz3eucPn9mkqZucl4XAwMX+TmFClWCzZJXURj4K2clhhmGyMNPXnpbWvWVPjS
+# PMFDQK4dUPVS/JA7u5iZaWvHwaeoaKQn3J35J64whbn2Z006Po9ZOSJTROvIXQPK
+# 7VB6fWIhCoDIc2bRoAVgX+iltKevqPdtNZx8WorWojiZ83iL9E3SIAveBO6Mm0eB
+# cg3AFDLvMFkuruBx8lbkapdvklBtlo1oepqyNhR6BvIkuQkRUNcIsbiJeoQjYUIp
+# 5aPNoiBB19GcZNnqJqGLFNdMGbJQQXE9P01wI4YMStyB0swylIQNCAmXHE/A7msg
+# dDDS4Dk0EIUhFQEI6FUy3nFJ2SgXUE3mvk3RdazQyvtBuEOlqtPDBURPLDab4vri
+# RbgjU2wGb2dVf0a1TD9uKFp5JtKkqGKX0h7i7UqLvBv9R0oN32dmfrJbQdA75PQ7
+# 9ARj6e/CVABRoIoqyc54zNXqhwQYs86vSYiv85KZtrPmYQ/ShQDnUBrkG5WdGaG5
+# nLGbsQAe79APT0JsyQq87kP6OnGlyE0mpTX9iV28hWIdMtKgK1TtmlfB2/oQzxm3
+# i0objwG2J5VT6LaJbVu8aNQj6ItRolb58KaAoNYes7wPD1N1KarqE3fk3oyBIa0H
+# EEcRrYc9B9F1vM/zZn4wggawMIIEmKADAgECAhAIrUCyYNKcTJ9ezam9k67ZMA0G
+# CSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ
+# bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0
+# IFRydXN0ZWQgUm9vdCBHNDAeFw0yMTA0MjkwMDAwMDBaFw0zNjA0MjgyMzU5NTla
+# MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE
+# AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEz
+# ODQgMjAyMSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDVtC9C
+# 0CiteLdd1TlZG7GIQvUzjOs9gZdwxbvEhSYwn6SOaNhc9es0JAfhS0/TeEP0F9ce
+# 2vnS1WcaUk8OoVf8iJnBkcyBAz5NcCRks43iCH00fUyAVxJrQ5qZ8sU7H/Lvy0da
+# E6ZMswEgJfMQ04uy+wjwiuCdCcBlp/qYgEk1hz1RGeiQIXhFLqGfLOEYwhrMxe6T
+# SXBCMo/7xuoc82VokaJNTIIRSFJo3hC9FFdd6BgTZcV/sk+FLEikVoQ11vkunKoA
+# FdE3/hoGlMJ8yOobMubKwvSnowMOdKWvObarYBLj6Na59zHh3K3kGKDYwSNHR7Oh
+# D26jq22YBoMbt2pnLdK9RBqSEIGPsDsJ18ebMlrC/2pgVItJwZPt4bRc4G/rJvmM
+# 1bL5OBDm6s6R9b7T+2+TYTRcvJNFKIM2KmYoX7BzzosmJQayg9Rc9hUZTO1i4F4z
+# 8ujo7AqnsAMrkbI2eb73rQgedaZlzLvjSFDzd5Ea/ttQokbIYViY9XwCFjyDKK05
+# huzUtw1T0PhH5nUwjewwk3YUpltLXXRhTT8SkXbev1jLchApQfDVxW0mdmgRQRNY
+# mtwmKwH0iU1Z23jPgUo+QEdfyYFQc4UQIyFZYIpkVMHMIRroOBl8ZhzNeDhFMJlP
+# /2NPTLuqDQhTQXxYPUez+rbsjDIJAsxsPAxWEQIDAQABo4IBWTCCAVUwEgYDVR0T
+# AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUaDfg67Y7+F8Rhvv+YXsIiGX0TkIwHwYD
+# VR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMG
+# A1UdJQQMMAoGCCsGAQUFBwMDMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYY
+# aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2Fj
+# ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNV
+# HR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRU
+# cnVzdGVkUm9vdEc0LmNybDAcBgNVHSAEFTATMAcGBWeBDAEDMAgGBmeBDAEEATAN
+# BgkqhkiG9w0BAQwFAAOCAgEAOiNEPY0Idu6PvDqZ01bgAhql+Eg08yy25nRm95Ry
+# sQDKr2wwJxMSnpBEn0v9nqN8JtU3vDpdSG2V1T9J9Ce7FoFFUP2cvbaF4HZ+N3HL
+# IvdaqpDP9ZNq4+sg0dVQeYiaiorBtr2hSBh+3NiAGhEZGM1hmYFW9snjdufE5Btf
+# Q/g+lP92OT2e1JnPSt0o618moZVYSNUa/tcnP/2Q0XaG3RywYFzzDaju4ImhvTnh
+# OE7abrs2nfvlIVNaw8rpavGiPttDuDPITzgUkpn13c5UbdldAhQfQDN8A+KVssIh
+# dXNSy0bYxDQcoqVLjc1vdjcshT8azibpGL6QB7BDf5WIIIJw8MzK7/0pNVwfiThV
+# 9zeKiwmhywvpMRr/LhlcOXHhvpynCgbWJme3kuZOX956rEnPLqR0kq3bPKSchh/j
+# wVYbKyP/j7XqiHtwa+aguv06P0WmxOgWkVKLQcBIhEuWTatEQOON8BUozu3xGFYH
+# Ki8QxAwIZDwzj64ojDzLj4gLDb879M4ee47vtevLt/B3E+bnKD+sEq6lLyJsQfmC
+# XBVmzGwOysWGw/YmMwwHS6DTBwJqakAwSEs0qFEgu60bhQjiWQ1tygVQK+pKHJ6l
+# /aCnHwZ05/LWUpD9r4VIIflXO7ScA+2GRfS0YW6/aOImYIbqyK+p/pQd52MbOoZW
+# eE4wggd3MIIFX6ADAgECAhAHHxQbizANJfMU6yMM0NHdMA0GCSqGSIb3DQEBCwUA
+# MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE
+# AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEz
+# ODQgMjAyMSBDQTEwHhcNMjIwMTE3MDAwMDAwWhcNMjUwMTE1MjM1OTU5WjB8MQsw
+# CQYDVQQGEwJVUzEPMA0GA1UECBMGT3JlZ29uMRIwEAYDVQQHEwlCZWF2ZXJ0b24x
+# IzAhBgNVBAoTGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMSMwIQYDVQQDExpQ
+# eXRob24gU29mdHdhcmUgRm91bmRhdGlvbjCCAiIwDQYJKoZIhvcNAQEBBQADggIP
+# ADCCAgoCggIBAKgc0BTT+iKbtK6f2mr9pNMUTcAJxKdsuOiSYgDFfwhjQy89koM7
+# uP+QV/gwx8MzEt3c9tLJvDccVWQ8H7mVsk/K+X+IufBLCgUi0GGAZUegEAeRlSXx
+# xhYScr818ma8EvGIZdiSOhqjYc4KnfgfIS4RLtZSrDFG2tN16yS8skFa3IHyvWdb
+# D9PvZ4iYNAS4pjYDRjT/9uzPZ4Pan+53xZIcDgjiTwOh8VGuppxcia6a7xCyKoOA
+# GjvCyQsj5223v1/Ig7Dp9mGI+nh1E3IwmyTIIuVHyK6Lqu352diDY+iCMpk9Zanm
+# SjmB+GMVs+H/gOiofjjtf6oz0ki3rb7sQ8fTnonIL9dyGTJ0ZFYKeb6BLA66d2GA
+# LwxZhLe5WH4Np9HcyXHACkppsE6ynYjTOd7+jN1PRJahN1oERzTzEiV6nCO1M3U1
+# HbPTGyq52IMFSBM2/07WTJSbOeXjvYR7aUxK9/ZkJiacl2iZI7IWe7JKhHohqKuc
+# eQNyOzxTakLcRkzynvIrk33R9YVqtB4L6wtFxhUjvDnQg16xot2KVPdfyPAWd81w
+# tZADmrUtsZ9qG79x1hBdyOl4vUtVPECuyhCxaw+faVjumapPUnwo8ygflJJ74J+B
+# Yxf6UuD7m8yzsfXWkdv52DjL74TxzuFTLHPyARWCSCAbzn3ZIly+qIqDAgMBAAGj
+# ggIGMIICAjAfBgNVHSMEGDAWgBRoN+Drtjv4XxGG+/5hewiIZfROQjAdBgNVHQ4E
+# FgQUt/1Teh2XDuUj2WW3siYWJgkZHA8wDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQM
+# MAoGCCsGAQUFBwMDMIG1BgNVHR8Ega0wgaowU6BRoE+GTWh0dHA6Ly9jcmwzLmRp
+# Z2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNENvZGVTaWduaW5nUlNBNDA5NlNI
+# QTM4NDIwMjFDQTEuY3JsMFOgUaBPhk1odHRwOi8vY3JsNC5kaWdpY2VydC5jb20v
+# RGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZTSEEzODQyMDIxQ0Ex
+# LmNybDA+BgNVHSAENzA1MDMGBmeBDAEEATApMCcGCCsGAQUFBwIBFhtodHRwOi8v
+# d3d3LmRpZ2ljZXJ0LmNvbS9DUFMwgZQGCCsGAQUFBwEBBIGHMIGEMCQGCCsGAQUF
+# BzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wXAYIKwYBBQUHMAKGUGh0dHA6
+# Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNENvZGVTaWdu
+# aW5nUlNBNDA5NlNIQTM4NDIwMjFDQTEuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZI
+# hvcNAQELBQADggIBABxv4AeV/5ltkELHSC63fXAFYS5tadcWTiNc2rskrNLrfH1N
+# s0vgSZFoQxYBFKI159E8oQQ1SKbTEubZ/B9kmHPhprHya08+VVzxC88pOEvz68nA
+# 82oEM09584aILqYmj8Pj7h/kmZNzuEL7WiwFa/U1hX+XiWfLIJQsAHBla0i7QRF2
+# de8/VSF0XXFa2kBQ6aiTsiLyKPNbaNtbcucaUdn6vVUS5izWOXM95BSkFSKdE45O
+# q3FForNJXjBvSCpwcP36WklaHL+aHu1upIhCTUkzTHMh8b86WmjRUqbrnvdyR2yd
+# I5l1OqcMBjkpPpIV6wcc+KY/RH2xvVuuoHjlUjwq2bHiNoX+W1scCpnA8YTs2d50
+# jDHUgwUo+ciwpffH0Riq132NFmrH3r67VaN3TuBxjI8SIZM58WEDkbeoriDk3hxU
+# 8ZWV7b8AW6oyVBGfM06UgkfMb58h+tJPrFx8VI/WLq1dTqMfZOm5cuclMnUHs2uq
+# rRNtnV8UfidPBL4ZHkTcClQbCoz0UbLhkiDvIS00Dn+BBcxw/TKqVL4Oaz3bkMSs
+# M46LciTeucHY9ExRVt3zy7i149sd+F4QozPqn7FrSVHXmem3r7bjyHTxOgqxRCVa
+# 18Vtx7P/8bYSBeS+WHCKcliFCecspusCDSlnRUjZwyPdP0VHxaZg2unjHY3rMYIa
+# tjCCGrICAQEwfTBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIElu
+# Yy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgQ29kZSBTaWduaW5nIFJT
+# QTQwOTYgU0hBMzg0IDIwMjEgQ0ExAhAHHxQbizANJfMU6yMM0NHdMA0GCWCGSAFl
+# AwQCAQUAoIHIMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcC
+# AQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCBnAZ6P7YvTwq0fbF62
+# o7E75R0LxsW5OtyYiFESQckLhjBcBgorBgEEAYI3AgEMMU4wTKBGgEQAQgB1AGkA
+# bAB0ADoAIABSAGUAbABlAGEAcwBlAF8AdgAzAC4AMQAyAC4ANQBfADIAMAAyADQA
+# MAA4ADAANgAuADAAMaECgAAwDQYJKoZIhvcNAQEBBQAEggIAoXbLeBCFQhwr4rTK
+# R0WSySG7AtpuY1n5vhwkJPE0JgQ11PFJYphroU2ouWWM8ifejqa6m21JEWGjC9En
+# Rpzpe1+eps7ClsdO+y5NxZc/3vD1j7IddJdzZh77QqDFMqJEeDNY+00OxxnnhbN1
+# wJk29w8qRyIJ7HpCM0E5b8R8Atooip5ihAgrdrIsyyA3Mnl5Y+YMdqtQYe4QtOhE
+# QcEoxAMoI5nLSGsbLhEM8CArl36EmX31eHTVMRJMaM98p0DkURHL030ALmW2V70h
+# M7ovmhOezFyndR1d3HtcfwRB3nr5vHWZe6ythZ3wVgpsN++RdDOvHjb9LC9lkth/
+# BGbcmVqsA9ZHnub1iPt89GsQBSiXjaOnWUxgJi0Qd3s2pwswLxHp05QDUE/d8EF7
+# Wy6aNPI43+G2BjPLVeM3iVbMWd/yxhH6pddaVPAMKVvxJoJ7PfDLihMNyonHt0on
+# xuaM5r2KaVMWpHIkgLiB9tyvdIQb0IW+YU05VAnOqh7CDaEtP7jM6P0usxY9ufEC
+# BFZnOGb3M/c4KbcOuHOIkY3jGqw+DLZFrcWiIe2wbi2TsXDixs+pz8vm/KQczrQ2
+# RJ1R8jrbK7IIRyZmTYf+dStZG3NhNQn1xcPYraHKNOm9CzNmeXJTdfAe0BEApqUN
+# 9AiLj6uvSEp278ysr/EE3ayw2Qmhghc/MIIXOwYKKwYBBAGCNwMDATGCFyswghcn
+# BgkqhkiG9w0BBwKgghcYMIIXFAIBAzEPMA0GCWCGSAFlAwQCAQUAMHcGCyqGSIb3
+# DQEJEAEEoGgEZjBkAgEBBglghkgBhv1sBwEwMTANBglghkgBZQMEAgEFAAQgpuSq
+# fyINa45wSs5Sa6msoQk+zCLDcSK24OqaBM/0/2cCEFtb0VJATq3jxU9l7ewmqjcY
+# DzIwMjQwODA2MjEwMDM5WqCCEwkwggbCMIIEqqADAgECAhAFRK/zlJ0IOaa/2z9f
+# 5WEWMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdp
+# Q2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2
+# IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0EwHhcNMjMwNzE0MDAwMDAwWhcNMzQxMDEz
+# MjM1OTU5WjBIMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4x
+# IDAeBgNVBAMTF0RpZ2lDZXJ0IFRpbWVzdGFtcCAyMDIzMIICIjANBgkqhkiG9w0B
+# AQEFAAOCAg8AMIICCgKCAgEAo1NFhx2DjlusPlSzI+DPn9fl0uddoQ4J3C9Io5d6
+# OyqcZ9xiFVjBqZMRp82qsmrdECmKHmJjadNYnDVxvzqX65RQjxwg6seaOy+WZuNp
+# 52n+W8PWKyAcwZeUtKVQgfLPywemMGjKg0La/H8JJJSkghraarrYO8pd3hkYhftF
+# 6g1hbJ3+cV7EBpo88MUueQ8bZlLjyNY+X9pD04T10Mf2SC1eRXWWdf7dEKEbg8G4
+# 5lKVtUfXeCk5a+B4WZfjRCtK1ZXO7wgX6oJkTf8j48qG7rSkIWRw69XloNpjsy7p
+# Be6q9iT1HbybHLK3X9/w7nZ9MZllR1WdSiQvrCuXvp/k/XtzPjLuUjT71Lvr1KAs
+# NJvj3m5kGQc3AZEPHLVRzapMZoOIaGK7vEEbeBlt5NkP4FhB+9ixLOFRr7StFQYU
+# 6mIIE9NpHnxkTZ0P387RXoyqq1AVybPKvNfEO2hEo6U7Qv1zfe7dCv95NBB+plwK
+# WEwAPoVpdceDZNZ1zY8SdlalJPrXxGshuugfNJgvOuprAbD3+yqG7HtSOKmYCaFx
+# smxxrz64b5bV4RAT/mFHCoz+8LbH1cfebCTwv0KCyqBxPZySkwS0aXAnDU+3tTbR
+# yV8IpHCj7ArxES5k4MsiK8rxKBMhSVF+BmbTO77665E42FEHypS34lCh8zrTioPL
+# QHsCAwEAAaOCAYswggGHMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMBYG
+# A1UdJQEB/wQMMAoGCCsGAQUFBwMIMCAGA1UdIAQZMBcwCAYGZ4EMAQQCMAsGCWCG
+# SAGG/WwHATAfBgNVHSMEGDAWgBS6FtltTYUvcyl2mi91jGogj57IbzAdBgNVHQ4E
+# FgQUpbbvE+fvzdBkodVWqWUxo97V40kwWgYDVR0fBFMwUTBPoE2gS4ZJaHR0cDov
+# L2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0UlNBNDA5NlNIQTI1
+# NlRpbWVTdGFtcGluZ0NBLmNybDCBkAYIKwYBBQUHAQEEgYMwgYAwJAYIKwYBBQUH
+# MAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBYBggrBgEFBQcwAoZMaHR0cDov
+# L2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0UlNBNDA5NlNI
+# QTI1NlRpbWVTdGFtcGluZ0NBLmNydDANBgkqhkiG9w0BAQsFAAOCAgEAgRrW3qCp
+# tZgXvHCNT4o8aJzYJf/LLOTN6l0ikuyMIgKpuM+AqNnn48XtJoKKcS8Y3U623mzX
+# 4WCcK+3tPUiOuGu6fF29wmE3aEl3o+uQqhLXJ4Xzjh6S2sJAOJ9dyKAuJXglnSoF
+# eoQpmLZXeY/bJlYrsPOnvTcM2Jh2T1a5UsK2nTipgedtQVyMadG5K8TGe8+c+nji
+# kxp2oml101DkRBK+IA2eqUTQ+OVJdwhaIcW0z5iVGlS6ubzBaRm6zxbygzc0brBB
+# Jt3eWpdPM43UjXd9dUWhpVgmagNF3tlQtVCMr1a9TMXhRsUo063nQwBw3syYnhmJ
+# A+rUkTfvTVLzyWAhxFZH7doRS4wyw4jmWOK22z75X7BC1o/jF5HRqsBV44a/rCcs
+# QdCaM0qoNtS5cpZ+l3k4SF/Kwtw9Mt911jZnWon49qfH5U81PAC9vpwqbHkB3NpE
+# 5jreODsHXjlY9HxzMVWggBHLFAx+rrz+pOt5Zapo1iLKO+uagjVXKBbLafIymrLS
+# 2Dq4sUaGa7oX/cR3bBVsrquvczroSUa31X/MtjjA2Owc9bahuEMs305MfR5ocMB3
+# CtQC4Fxguyj/OOVSWtasFyIjTvTs0xf7UGv/B3cfcZdEQcm4RtNsMnxYL2dHZeUb
+# c7aZ+WssBkbvQR7w8F/g29mtkIBEr4AQQYowggauMIIElqADAgECAhAHNje3JFR8
+# 2Ees/ShmKl5bMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
+# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNV
+# BAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0yMjAzMjMwMDAwMDBaFw0z
+# NzAzMjIyMzU5NTlaMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwg
+# SW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2IFNIQTI1
+# NiBUaW1lU3RhbXBpbmcgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
+# AQDGhjUGSbPBPXJJUVXHJQPE8pE3qZdRodbSg9GeTKJtoLDMg/la9hGhRBVCX6SI
+# 82j6ffOciQt/nR+eDzMfUBMLJnOWbfhXqAJ9/UO0hNoR8XOxs+4rgISKIhjf69o9
+# xBd/qxkrPkLcZ47qUT3w1lbU5ygt69OxtXXnHwZljZQp09nsad/ZkIdGAHvbREGJ
+# 3HxqV3rwN3mfXazL6IRktFLydkf3YYMZ3V+0VAshaG43IbtArF+y3kp9zvU5Emfv
+# DqVjbOSmxR3NNg1c1eYbqMFkdECnwHLFuk4fsbVYTXn+149zk6wsOeKlSNbwsDET
+# qVcplicu9Yemj052FVUmcJgmf6AaRyBD40NjgHt1biclkJg6OBGz9vae5jtb7IHe
+# IhTZgirHkr+g3uM+onP65x9abJTyUpURK1h0QCirc0PO30qhHGs4xSnzyqqWc0Jo
+# n7ZGs506o9UD4L/wojzKQtwYSH8UNM/STKvvmz3+DrhkKvp1KCRB7UK/BZxmSVJQ
+# 9FHzNklNiyDSLFc1eSuo80VgvCONWPfcYd6T/jnA+bIwpUzX6ZhKWD7TA4j+s4/T
+# Xkt2ElGTyYwMO1uKIqjBJgj5FBASA31fI7tk42PgpuE+9sJ0sj8eCXbsq11GdeJg
+# o1gJASgADoRU7s7pXcheMBK9Rp6103a50g5rmQzSM7TNsQIDAQABo4IBXTCCAVkw
+# EgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUuhbZbU2FL3MpdpovdYxqII+e
+# yG8wHwYDVR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQD
+# AgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMIMHcGCCsGAQUFBwEBBGswaTAkBggrBgEF
+# BQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRw
+# Oi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNy
+# dDBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGln
+# aUNlcnRUcnVzdGVkUm9vdEc0LmNybDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglg
+# hkgBhv1sBwEwDQYJKoZIhvcNAQELBQADggIBAH1ZjsCTtm+YqUQiAX5m1tghQuGw
+# GC4QTRPPMFPOvxj7x1Bd4ksp+3CKDaopafxpwc8dB+k+YMjYC+VcW9dth/qEICU0
+# MWfNthKWb8RQTGIdDAiCqBa9qVbPFXONASIlzpVpP0d3+3J0FNf/q0+KLHqrhc1D
+# X+1gtqpPkWaeLJ7giqzl/Yy8ZCaHbJK9nXzQcAp876i8dU+6WvepELJd6f8oVInw
+# 1YpxdmXazPByoyP6wCeCRK6ZJxurJB4mwbfeKuv2nrF5mYGjVoarCkXJ38SNoOeY
+# +/umnXKvxMfBwWpx2cYTgAnEtp/Nh4cku0+jSbl3ZpHxcpzpSwJSpzd+k1OsOx0I
+# SQ+UzTl63f8lY5knLD0/a6fxZsNBzU+2QJshIUDQtxMkzdwdeDrknq3lNHGS1yZr
+# 5Dhzq6YBT70/O3itTK37xJV77QpfMzmHQXh6OOmc4d0j/R0o08f56PGYX/sr2H7y
+# Rp11LB4nLCbbbxV7HhmLNriT1ObyF5lZynDwN7+YAN8gFk8n+2BnFqFmut1VwDop
+# hrCYoCvtlUG3OtUVmDG0YgkPCr2B2RP+v6TR81fZvAT6gt4y3wSJ8ADNXcL50CN/
+# AAvkdgIm2fBldkKmKYcJRyvmfxqkhQ/8mJb2VVQrH4D6wPIOK+XW+6kvRBVK5xMO
+# Hds3OBqhK/bt1nz8MIIFjTCCBHWgAwIBAgIQDpsYjvnQLefv21DiCEAYWjANBgkq
+# hkiG9w0BAQwFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5j
+# MRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBB
+# c3N1cmVkIElEIFJvb3QgQ0EwHhcNMjIwODAxMDAwMDAwWhcNMzExMTA5MjM1OTU5
+# WjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL
+# ExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJv
+# b3QgRzQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1K
+# PDAiMGkz7MKnJS7JIT3yithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2r
+# snnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C
+# 8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBf
+# sXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGY
+# QJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8
+# rhsDdV14Ztk6MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaY
+# dj1ZXUJ2h4mXaXpI8OCiEhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+
+# wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw
+# ++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+N
+# P8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7F
+# wI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo4IBOjCCATYwDwYDVR0TAQH/BAUw
+# AwEB/zAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wHwYDVR0jBBgwFoAU
+# Reuir/SSy4IxLVGLp6chnfNtyA8wDgYDVR0PAQH/BAQDAgGGMHkGCCsGAQUFBwEB
+# BG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsG
+# AQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1
+# cmVkSURSb290Q0EuY3J0MEUGA1UdHwQ+MDwwOqA4oDaGNGh0dHA6Ly9jcmwzLmRp
+# Z2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwEQYDVR0gBAow
+# CDAGBgRVHSAAMA0GCSqGSIb3DQEBDAUAA4IBAQBwoL9DXFXnOF+go3QbPbYW1/e/
+# Vwe9mqyhhyzshV6pGrsi+IcaaVQi7aSId229GhT0E0p6Ly23OO/0/4C5+KH38nLe
+# JLxSA8hO0Cre+i1Wz/n096wwepqLsl7Uz9FDRJtDIeuWcqFItJnLnU+nBgMTdydE
+# 1Od/6Fmo8L8vC6bp8jQ87PcDx4eo0kxAGTVGamlUsLihVo7spNU96LHc/RzY9Hda
+# XFSMb++hUD38dglohJ9vytsgjTVgHAIDyyCwrFigDkBjxZgiwbJZ9VVrzyerbHbO
+# byMt9H5xaiNrIv8SuFQtJ37YOtnwtoeW/VvRXKwYw02fc7cBqZ9Xql4o4rmUMYID
+# djCCA3ICAQEwdzBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIElu
+# Yy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQgUlNBNDA5NiBTSEEyNTYg
+# VGltZVN0YW1waW5nIENBAhAFRK/zlJ0IOaa/2z9f5WEWMA0GCWCGSAFlAwQCAQUA
+# oIHRMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcN
+# MjQwODA2MjEwMDM5WjArBgsqhkiG9w0BCRACDDEcMBowGDAWBBRm8CsywsLJD4Jd
+# zqqKycZPGZzPQDAvBgkqhkiG9w0BCQQxIgQglCIBxGudJQwqEBh+XAoT3nqSoAuS
+# uMjmJTX95zFjdk0wNwYLKoZIhvcNAQkQAi8xKDAmMCQwIgQg0vbkbe10IszR1EBX
+# aEE2b4KK2lWarjMWr00amtQMeCgwDQYJKoZIhvcNAQEBBQAEggIAOkILAZviyFOU
+# Qzt10RYNFHl0zO4rgXcR5oCeJlU1n9y+DwjCTvcrax9qdkEuiEJWDewXbak3TPQK
+# 0ts7jhUIFMDTEn8GZXysruzDlYNLstKM4RbYIK+f2772phehvABS5mn70+L63GXe
+# A5UFYM5M7BAvEY+3DKEwUnN9lAl8YKi1xS545MXYm1B96gI/7oEBDkNV2DoNIZAw
+# R2B4wPTcpI2aG5zZ0jFgVtq8bOXLZ9b9pBrhKbf4PZWxPqAFwUtZryQKdt770u3Y
+# l0WR2SgemKq4aOEvajD1J4fC56lnUoekXt4yH8/fBueCXYx+ADoEkU4/ota7C1oL
+# aCZE4G0iQOH9XFtMUjA87oEPisJG63onir6tsurTjjm/wK8VnFQBSii4ILtfSOfR
+# kDMsu7kS0H5SWliY3sPlDTn4Kwl14EThMmyXUr7SFFHnsibHtfLATTmV6XyeJ03l
+# BmwDl8hdzt5G0pjH/u3bTFcdJu7J0RQuGYgpmNsVYjHCQnZDrJjzIE2os/QYgL6D
+# B/ZYSv96jnYs6cFd93R0ixZMsQPQKcs2gbVYz3nymJL7t605LzW86tENmORsUdgm
+# qh0ky+qe/+D/f88WLLjdHi/xfskiFKEL66Y4EWkECoUUMBRcJlIg1GszTCVmwD1N
+# foIJo8CaFGMoR+QHwDeamNbOOlrCFMQ=
+# SIG # End signature block
diff --git a/lab_3/aimenv/Scripts/activate b/lab_3/aimenv/Scripts/activate
new file mode 100644
index 0000000..8cf30bf
--- /dev/null
+++ b/lab_3/aimenv/Scripts/activate
@@ -0,0 +1,70 @@
+# This file must be used with "source bin/activate" *from bash*
+# You cannot run it directly
+
+deactivate () {
+ # reset old environment variables
+ if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then
+ PATH="${_OLD_VIRTUAL_PATH:-}"
+ export PATH
+ unset _OLD_VIRTUAL_PATH
+ fi
+ if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then
+ PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}"
+ export PYTHONHOME
+ unset _OLD_VIRTUAL_PYTHONHOME
+ fi
+
+ # Call hash to forget past commands. Without forgetting
+ # past commands the $PATH changes we made may not be respected
+ hash -r 2> /dev/null
+
+ if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then
+ PS1="${_OLD_VIRTUAL_PS1:-}"
+ export PS1
+ unset _OLD_VIRTUAL_PS1
+ fi
+
+ unset VIRTUAL_ENV
+ unset VIRTUAL_ENV_PROMPT
+ if [ ! "${1:-}" = "nondestructive" ] ; then
+ # Self destruct!
+ unset -f deactivate
+ fi
+}
+
+# unset irrelevant variables
+deactivate nondestructive
+
+# on Windows, a path can contain colons and backslashes and has to be converted:
+if [ "${OSTYPE:-}" = "cygwin" ] || [ "${OSTYPE:-}" = "msys" ] ; then
+ # transform D:\path\to\venv to /d/path/to/venv on MSYS
+ # and to /cygdrive/d/path/to/venv on Cygwin
+ export VIRTUAL_ENV=$(cygpath "C:\Users\Egor\Desktop\ULSTU\AI\aim\aimenv")
+else
+ # use the path as-is
+ export VIRTUAL_ENV="C:\Users\Egor\Desktop\ULSTU\AI\aim\aimenv"
+fi
+
+_OLD_VIRTUAL_PATH="$PATH"
+PATH="$VIRTUAL_ENV/Scripts:$PATH"
+export PATH
+
+# unset PYTHONHOME if set
+# this will fail if PYTHONHOME is set to the empty string (which is bad anyway)
+# could use `if (set -u; : $PYTHONHOME) ;` in bash
+if [ -n "${PYTHONHOME:-}" ] ; then
+ _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}"
+ unset PYTHONHOME
+fi
+
+if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then
+ _OLD_VIRTUAL_PS1="${PS1:-}"
+ PS1="(aimenv) ${PS1:-}"
+ export PS1
+ VIRTUAL_ENV_PROMPT="(aimenv) "
+ export VIRTUAL_ENV_PROMPT
+fi
+
+# Call hash to forget past commands. Without forgetting
+# past commands the $PATH changes we made may not be respected
+hash -r 2> /dev/null
diff --git a/lab_3/aimenv/Scripts/activate.bat b/lab_3/aimenv/Scripts/activate.bat
new file mode 100644
index 0000000..11bc012
--- /dev/null
+++ b/lab_3/aimenv/Scripts/activate.bat
@@ -0,0 +1,34 @@
+@echo off
+
+rem This file is UTF-8 encoded, so we need to update the current code page while executing it
+for /f "tokens=2 delims=:." %%a in ('"%SystemRoot%\System32\chcp.com"') do (
+ set _OLD_CODEPAGE=%%a
+)
+if defined _OLD_CODEPAGE (
+ "%SystemRoot%\System32\chcp.com" 65001 > nul
+)
+
+set VIRTUAL_ENV=C:\Users\Egor\Desktop\ULSTU\AI\aim\aimenv
+
+if not defined PROMPT set PROMPT=$P$G
+
+if defined _OLD_VIRTUAL_PROMPT set PROMPT=%_OLD_VIRTUAL_PROMPT%
+if defined _OLD_VIRTUAL_PYTHONHOME set PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME%
+
+set _OLD_VIRTUAL_PROMPT=%PROMPT%
+set PROMPT=(aimenv) %PROMPT%
+
+if defined PYTHONHOME set _OLD_VIRTUAL_PYTHONHOME=%PYTHONHOME%
+set PYTHONHOME=
+
+if defined _OLD_VIRTUAL_PATH set PATH=%_OLD_VIRTUAL_PATH%
+if not defined _OLD_VIRTUAL_PATH set _OLD_VIRTUAL_PATH=%PATH%
+
+set PATH=%VIRTUAL_ENV%\Scripts;%PATH%
+set VIRTUAL_ENV_PROMPT=(aimenv)
+
+:END
+if defined _OLD_CODEPAGE (
+ "%SystemRoot%\System32\chcp.com" %_OLD_CODEPAGE% > nul
+ set _OLD_CODEPAGE=
+)
diff --git a/lab_3/aimenv/Scripts/deactivate.bat b/lab_3/aimenv/Scripts/deactivate.bat
new file mode 100644
index 0000000..62a39a7
--- /dev/null
+++ b/lab_3/aimenv/Scripts/deactivate.bat
@@ -0,0 +1,22 @@
+@echo off
+
+if defined _OLD_VIRTUAL_PROMPT (
+ set "PROMPT=%_OLD_VIRTUAL_PROMPT%"
+)
+set _OLD_VIRTUAL_PROMPT=
+
+if defined _OLD_VIRTUAL_PYTHONHOME (
+ set "PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME%"
+ set _OLD_VIRTUAL_PYTHONHOME=
+)
+
+if defined _OLD_VIRTUAL_PATH (
+ set "PATH=%_OLD_VIRTUAL_PATH%"
+)
+
+set _OLD_VIRTUAL_PATH=
+
+set VIRTUAL_ENV=
+set VIRTUAL_ENV_PROMPT=
+
+:END
diff --git a/lab_3/aimenv/Scripts/debugpy.exe b/lab_3/aimenv/Scripts/debugpy.exe
new file mode 100644
index 0000000..6d0e480
Binary files /dev/null and b/lab_3/aimenv/Scripts/debugpy.exe differ
diff --git a/lab_3/aimenv/Scripts/ipython.exe b/lab_3/aimenv/Scripts/ipython.exe
new file mode 100644
index 0000000..c5d0b33
Binary files /dev/null and b/lab_3/aimenv/Scripts/ipython.exe differ
diff --git a/lab_3/aimenv/Scripts/ipython3.exe b/lab_3/aimenv/Scripts/ipython3.exe
new file mode 100644
index 0000000..c5d0b33
Binary files /dev/null and b/lab_3/aimenv/Scripts/ipython3.exe differ
diff --git a/lab_3/aimenv/Scripts/jupyter-kernel.exe b/lab_3/aimenv/Scripts/jupyter-kernel.exe
new file mode 100644
index 0000000..cc1b7f4
Binary files /dev/null and b/lab_3/aimenv/Scripts/jupyter-kernel.exe differ
diff --git a/lab_3/aimenv/Scripts/jupyter-kernelspec.exe b/lab_3/aimenv/Scripts/jupyter-kernelspec.exe
new file mode 100644
index 0000000..72bf4e7
Binary files /dev/null and b/lab_3/aimenv/Scripts/jupyter-kernelspec.exe differ
diff --git a/lab_3/aimenv/Scripts/jupyter-migrate.exe b/lab_3/aimenv/Scripts/jupyter-migrate.exe
new file mode 100644
index 0000000..2033e15
Binary files /dev/null and b/lab_3/aimenv/Scripts/jupyter-migrate.exe differ
diff --git a/lab_3/aimenv/Scripts/jupyter-run.exe b/lab_3/aimenv/Scripts/jupyter-run.exe
new file mode 100644
index 0000000..1d34b22
Binary files /dev/null and b/lab_3/aimenv/Scripts/jupyter-run.exe differ
diff --git a/lab_3/aimenv/Scripts/jupyter-troubleshoot.exe b/lab_3/aimenv/Scripts/jupyter-troubleshoot.exe
new file mode 100644
index 0000000..de9c4d6
Binary files /dev/null and b/lab_3/aimenv/Scripts/jupyter-troubleshoot.exe differ
diff --git a/lab_3/aimenv/Scripts/jupyter.exe b/lab_3/aimenv/Scripts/jupyter.exe
new file mode 100644
index 0000000..77e316a
Binary files /dev/null and b/lab_3/aimenv/Scripts/jupyter.exe differ
diff --git a/lab_3/aimenv/Scripts/pip.exe b/lab_3/aimenv/Scripts/pip.exe
new file mode 100644
index 0000000..e378251
Binary files /dev/null and b/lab_3/aimenv/Scripts/pip.exe differ
diff --git a/lab_3/aimenv/Scripts/pip3.12.exe b/lab_3/aimenv/Scripts/pip3.12.exe
new file mode 100644
index 0000000..e378251
Binary files /dev/null and b/lab_3/aimenv/Scripts/pip3.12.exe differ
diff --git a/lab_3/aimenv/Scripts/pip3.exe b/lab_3/aimenv/Scripts/pip3.exe
new file mode 100644
index 0000000..e378251
Binary files /dev/null and b/lab_3/aimenv/Scripts/pip3.exe differ
diff --git a/lab_3/aimenv/Scripts/pygmentize.exe b/lab_3/aimenv/Scripts/pygmentize.exe
new file mode 100644
index 0000000..9c1459b
Binary files /dev/null and b/lab_3/aimenv/Scripts/pygmentize.exe differ
diff --git a/lab_3/aimenv/Scripts/python.exe b/lab_3/aimenv/Scripts/python.exe
new file mode 100644
index 0000000..b58faef
Binary files /dev/null and b/lab_3/aimenv/Scripts/python.exe differ
diff --git a/lab_3/aimenv/Scripts/pythonw.exe b/lab_3/aimenv/Scripts/pythonw.exe
new file mode 100644
index 0000000..ca33b90
Binary files /dev/null and b/lab_3/aimenv/Scripts/pythonw.exe differ
diff --git a/lab_3/aimenv/Scripts/pywin32_postinstall.py b/lab_3/aimenv/Scripts/pywin32_postinstall.py
new file mode 100644
index 0000000..147f0cd
--- /dev/null
+++ b/lab_3/aimenv/Scripts/pywin32_postinstall.py
@@ -0,0 +1,783 @@
+# postinstall script for pywin32
+#
+# copies PyWinTypesxx.dll and PythonCOMxx.dll into the system directory,
+# and creates a pth file
+import glob
+import os
+import shutil
+import sys
+import sysconfig
+
+try:
+ import winreg as winreg
+except:
+ import winreg
+
+# Send output somewhere so it can be found if necessary...
+import tempfile
+
+tee_f = open(os.path.join(tempfile.gettempdir(), "pywin32_postinstall.log"), "w")
+
+
+class Tee:
+ def __init__(self, file):
+ self.f = file
+
+ def write(self, what):
+ if self.f is not None:
+ try:
+ self.f.write(what.replace("\n", "\r\n"))
+ except IOError:
+ pass
+ tee_f.write(what)
+
+ def flush(self):
+ if self.f is not None:
+ try:
+ self.f.flush()
+ except IOError:
+ pass
+ tee_f.flush()
+
+
+# For some unknown reason, when running under bdist_wininst we will start up
+# with sys.stdout as None but stderr is hooked up. This work-around allows
+# bdist_wininst to see the output we write and display it at the end of
+# the install.
+if sys.stdout is None:
+ sys.stdout = sys.stderr
+
+sys.stderr = Tee(sys.stderr)
+sys.stdout = Tee(sys.stdout)
+
+com_modules = [
+ # module_name, class_names
+ ("win32com.servers.interp", "Interpreter"),
+ ("win32com.servers.dictionary", "DictionaryPolicy"),
+ ("win32com.axscript.client.pyscript", "PyScript"),
+]
+
+# Is this a 'silent' install - ie, avoid all dialogs.
+# Different than 'verbose'
+silent = 0
+
+# Verbosity of output messages.
+verbose = 1
+
+root_key_name = "Software\\Python\\PythonCore\\" + sys.winver
+
+try:
+ # When this script is run from inside the bdist_wininst installer,
+ # file_created() and directory_created() are additional builtin
+ # functions which write lines to Python23\pywin32-install.log. This is
+ # a list of actions for the uninstaller, the format is inspired by what
+ # the Wise installer also creates.
+ file_created
+ is_bdist_wininst = True
+except NameError:
+ is_bdist_wininst = False # we know what it is not - but not what it is :)
+
+ def file_created(file):
+ pass
+
+ def directory_created(directory):
+ pass
+
+ def get_root_hkey():
+ try:
+ winreg.OpenKey(
+ winreg.HKEY_LOCAL_MACHINE, root_key_name, 0, winreg.KEY_CREATE_SUB_KEY
+ )
+ return winreg.HKEY_LOCAL_MACHINE
+ except OSError:
+ # Either not exist, or no permissions to create subkey means
+ # must be HKCU
+ return winreg.HKEY_CURRENT_USER
+
+
+try:
+ create_shortcut
+except NameError:
+ # Create a function with the same signature as create_shortcut provided
+ # by bdist_wininst
+ def create_shortcut(
+ path, description, filename, arguments="", workdir="", iconpath="", iconindex=0
+ ):
+ import pythoncom
+ from win32com.shell import shell
+
+ ilink = pythoncom.CoCreateInstance(
+ shell.CLSID_ShellLink,
+ None,
+ pythoncom.CLSCTX_INPROC_SERVER,
+ shell.IID_IShellLink,
+ )
+ ilink.SetPath(path)
+ ilink.SetDescription(description)
+ if arguments:
+ ilink.SetArguments(arguments)
+ if workdir:
+ ilink.SetWorkingDirectory(workdir)
+ if iconpath or iconindex:
+ ilink.SetIconLocation(iconpath, iconindex)
+ # now save it.
+ ipf = ilink.QueryInterface(pythoncom.IID_IPersistFile)
+ ipf.Save(filename, 0)
+
+ # Support the same list of "path names" as bdist_wininst.
+ def get_special_folder_path(path_name):
+ from win32com.shell import shell, shellcon
+
+ for maybe in """
+ CSIDL_COMMON_STARTMENU CSIDL_STARTMENU CSIDL_COMMON_APPDATA
+ CSIDL_LOCAL_APPDATA CSIDL_APPDATA CSIDL_COMMON_DESKTOPDIRECTORY
+ CSIDL_DESKTOPDIRECTORY CSIDL_COMMON_STARTUP CSIDL_STARTUP
+ CSIDL_COMMON_PROGRAMS CSIDL_PROGRAMS CSIDL_PROGRAM_FILES_COMMON
+ CSIDL_PROGRAM_FILES CSIDL_FONTS""".split():
+ if maybe == path_name:
+ csidl = getattr(shellcon, maybe)
+ return shell.SHGetSpecialFolderPath(0, csidl, False)
+ raise ValueError("%s is an unknown path ID" % (path_name,))
+
+
+def CopyTo(desc, src, dest):
+ import win32api
+ import win32con
+
+ while 1:
+ try:
+ win32api.CopyFile(src, dest, 0)
+ return
+ except win32api.error as details:
+ if details.winerror == 5: # access denied - user not admin.
+ raise
+ if silent:
+ # Running silent mode - just re-raise the error.
+ raise
+ full_desc = (
+ "Error %s\n\n"
+ "If you have any Python applications running, "
+ "please close them now\nand select 'Retry'\n\n%s"
+ % (desc, details.strerror)
+ )
+ rc = win32api.MessageBox(
+ 0, full_desc, "Installation Error", win32con.MB_ABORTRETRYIGNORE
+ )
+ if rc == win32con.IDABORT:
+ raise
+ elif rc == win32con.IDIGNORE:
+ return
+ # else retry - around we go again.
+
+
+# We need to import win32api to determine the Windows system directory,
+# so we can copy our system files there - but importing win32api will
+# load the pywintypes.dll already in the system directory preventing us
+# from updating them!
+# So, we pull the same trick pywintypes.py does, but it loads from
+# our pywintypes_system32 directory.
+def LoadSystemModule(lib_dir, modname):
+ # See if this is a debug build.
+ import importlib.machinery
+ import importlib.util
+
+ suffix = "_d" if "_d.pyd" in importlib.machinery.EXTENSION_SUFFIXES else ""
+ filename = "%s%d%d%s.dll" % (
+ modname,
+ sys.version_info[0],
+ sys.version_info[1],
+ suffix,
+ )
+ filename = os.path.join(lib_dir, "pywin32_system32", filename)
+ loader = importlib.machinery.ExtensionFileLoader(modname, filename)
+ spec = importlib.machinery.ModuleSpec(name=modname, loader=loader, origin=filename)
+ mod = importlib.util.module_from_spec(spec)
+ spec.loader.exec_module(mod)
+
+
+def SetPyKeyVal(key_name, value_name, value):
+ root_hkey = get_root_hkey()
+ root_key = winreg.OpenKey(root_hkey, root_key_name)
+ try:
+ my_key = winreg.CreateKey(root_key, key_name)
+ try:
+ winreg.SetValueEx(my_key, value_name, 0, winreg.REG_SZ, value)
+ if verbose:
+ print("-> %s\\%s[%s]=%r" % (root_key_name, key_name, value_name, value))
+ finally:
+ my_key.Close()
+ finally:
+ root_key.Close()
+
+
+def UnsetPyKeyVal(key_name, value_name, delete_key=False):
+ root_hkey = get_root_hkey()
+ root_key = winreg.OpenKey(root_hkey, root_key_name)
+ try:
+ my_key = winreg.OpenKey(root_key, key_name, 0, winreg.KEY_SET_VALUE)
+ try:
+ winreg.DeleteValue(my_key, value_name)
+ if verbose:
+ print("-> DELETE %s\\%s[%s]" % (root_key_name, key_name, value_name))
+ finally:
+ my_key.Close()
+ if delete_key:
+ winreg.DeleteKey(root_key, key_name)
+ if verbose:
+ print("-> DELETE %s\\%s" % (root_key_name, key_name))
+ except OSError as why:
+ winerror = getattr(why, "winerror", why.errno)
+ if winerror != 2: # file not found
+ raise
+ finally:
+ root_key.Close()
+
+
+def RegisterCOMObjects(register=True):
+ import win32com.server.register
+
+ if register:
+ func = win32com.server.register.RegisterClasses
+ else:
+ func = win32com.server.register.UnregisterClasses
+ flags = {}
+ if not verbose:
+ flags["quiet"] = 1
+ for module, klass_name in com_modules:
+ __import__(module)
+ mod = sys.modules[module]
+ flags["finalize_register"] = getattr(mod, "DllRegisterServer", None)
+ flags["finalize_unregister"] = getattr(mod, "DllUnregisterServer", None)
+ klass = getattr(mod, klass_name)
+ func(klass, **flags)
+
+
+def RegisterHelpFile(register=True, lib_dir=None):
+ if lib_dir is None:
+ lib_dir = sysconfig.get_paths()["platlib"]
+ if register:
+ # Register the .chm help file.
+ chm_file = os.path.join(lib_dir, "PyWin32.chm")
+ if os.path.isfile(chm_file):
+ # This isn't recursive, so if 'Help' doesn't exist, we croak
+ SetPyKeyVal("Help", None, None)
+ SetPyKeyVal("Help\\Pythonwin Reference", None, chm_file)
+ return chm_file
+ else:
+ print("NOTE: PyWin32.chm can not be located, so has not " "been registered")
+ else:
+ UnsetPyKeyVal("Help\\Pythonwin Reference", None, delete_key=True)
+ return None
+
+
+def RegisterPythonwin(register=True, lib_dir=None):
+ """Add (or remove) Pythonwin to context menu for python scripts.
+ ??? Should probably also add Edit command for pys files also.
+ Also need to remove these keys on uninstall, but there's no function
+ like file_created to add registry entries to uninstall log ???
+ """
+ import os
+
+ if lib_dir is None:
+ lib_dir = sysconfig.get_paths()["platlib"]
+ classes_root = get_root_hkey()
+ ## Installer executable doesn't seem to pass anything to postinstall script indicating if it's a debug build,
+ pythonwin_exe = os.path.join(lib_dir, "Pythonwin", "Pythonwin.exe")
+ pythonwin_edit_command = pythonwin_exe + ' -edit "%1"'
+
+ keys_vals = [
+ (
+ "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\Pythonwin.exe",
+ "",
+ pythonwin_exe,
+ ),
+ (
+ "Software\\Classes\\Python.File\\shell\\Edit with Pythonwin",
+ "command",
+ pythonwin_edit_command,
+ ),
+ (
+ "Software\\Classes\\Python.NoConFile\\shell\\Edit with Pythonwin",
+ "command",
+ pythonwin_edit_command,
+ ),
+ ]
+
+ try:
+ if register:
+ for key, sub_key, val in keys_vals:
+ ## Since winreg only uses the character Api functions, this can fail if Python
+ ## is installed to a path containing non-ascii characters
+ hkey = winreg.CreateKey(classes_root, key)
+ if sub_key:
+ hkey = winreg.CreateKey(hkey, sub_key)
+ winreg.SetValueEx(hkey, None, 0, winreg.REG_SZ, val)
+ hkey.Close()
+ else:
+ for key, sub_key, val in keys_vals:
+ try:
+ if sub_key:
+ hkey = winreg.OpenKey(classes_root, key)
+ winreg.DeleteKey(hkey, sub_key)
+ hkey.Close()
+ winreg.DeleteKey(classes_root, key)
+ except OSError as why:
+ winerror = getattr(why, "winerror", why.errno)
+ if winerror != 2: # file not found
+ raise
+ finally:
+ # tell windows about the change
+ from win32com.shell import shell, shellcon
+
+ shell.SHChangeNotify(
+ shellcon.SHCNE_ASSOCCHANGED, shellcon.SHCNF_IDLIST, None, None
+ )
+
+
+def get_shortcuts_folder():
+ if get_root_hkey() == winreg.HKEY_LOCAL_MACHINE:
+ try:
+ fldr = get_special_folder_path("CSIDL_COMMON_PROGRAMS")
+ except OSError:
+ # No CSIDL_COMMON_PROGRAMS on this platform
+ fldr = get_special_folder_path("CSIDL_PROGRAMS")
+ else:
+ # non-admin install - always goes in this user's start menu.
+ fldr = get_special_folder_path("CSIDL_PROGRAMS")
+
+ try:
+ install_group = winreg.QueryValue(
+ get_root_hkey(), root_key_name + "\\InstallPath\\InstallGroup"
+ )
+ except OSError:
+ vi = sys.version_info
+ install_group = "Python %d.%d" % (vi[0], vi[1])
+ return os.path.join(fldr, install_group)
+
+
+# Get the system directory, which may be the Wow64 directory if we are a 32bit
+# python on a 64bit OS.
+def get_system_dir():
+ import win32api # we assume this exists.
+
+ try:
+ import pythoncom
+ import win32process
+ from win32com.shell import shell, shellcon
+
+ try:
+ if win32process.IsWow64Process():
+ return shell.SHGetSpecialFolderPath(0, shellcon.CSIDL_SYSTEMX86)
+ return shell.SHGetSpecialFolderPath(0, shellcon.CSIDL_SYSTEM)
+ except (pythoncom.com_error, win32process.error):
+ return win32api.GetSystemDirectory()
+ except ImportError:
+ return win32api.GetSystemDirectory()
+
+
+def fixup_dbi():
+ # We used to have a dbi.pyd with our .pyd files, but now have a .py file.
+ # If the user didn't uninstall, they will find the .pyd which will cause
+ # problems - so handle that.
+ import win32api
+ import win32con
+
+ pyd_name = os.path.join(os.path.dirname(win32api.__file__), "dbi.pyd")
+ pyd_d_name = os.path.join(os.path.dirname(win32api.__file__), "dbi_d.pyd")
+ py_name = os.path.join(os.path.dirname(win32con.__file__), "dbi.py")
+ for this_pyd in (pyd_name, pyd_d_name):
+ this_dest = this_pyd + ".old"
+ if os.path.isfile(this_pyd) and os.path.isfile(py_name):
+ try:
+ if os.path.isfile(this_dest):
+ print(
+ "Old dbi '%s' already exists - deleting '%s'"
+ % (this_dest, this_pyd)
+ )
+ os.remove(this_pyd)
+ else:
+ os.rename(this_pyd, this_dest)
+ print("renamed '%s'->'%s.old'" % (this_pyd, this_pyd))
+ file_created(this_pyd + ".old")
+ except os.error as exc:
+ print("FAILED to rename '%s': %s" % (this_pyd, exc))
+
+
+def install(lib_dir):
+ import traceback
+
+ # The .pth file is now installed as a regular file.
+ # Create the .pth file in the site-packages dir, and use only relative paths
+ # We used to write a .pth directly to sys.prefix - clobber it.
+ if os.path.isfile(os.path.join(sys.prefix, "pywin32.pth")):
+ os.unlink(os.path.join(sys.prefix, "pywin32.pth"))
+ # The .pth may be new and therefore not loaded in this session.
+ # Setup the paths just in case.
+ for name in "win32 win32\\lib Pythonwin".split():
+ sys.path.append(os.path.join(lib_dir, name))
+ # It is possible people with old versions installed with still have
+ # pywintypes and pythoncom registered. We no longer need this, and stale
+ # entries hurt us.
+ for name in "pythoncom pywintypes".split():
+ keyname = "Software\\Python\\PythonCore\\" + sys.winver + "\\Modules\\" + name
+ for root in winreg.HKEY_LOCAL_MACHINE, winreg.HKEY_CURRENT_USER:
+ try:
+ winreg.DeleteKey(root, keyname + "\\Debug")
+ except WindowsError:
+ pass
+ try:
+ winreg.DeleteKey(root, keyname)
+ except WindowsError:
+ pass
+ LoadSystemModule(lib_dir, "pywintypes")
+ LoadSystemModule(lib_dir, "pythoncom")
+ import win32api
+
+ # and now we can get the system directory:
+ files = glob.glob(os.path.join(lib_dir, "pywin32_system32\\*.*"))
+ if not files:
+ raise RuntimeError("No system files to copy!!")
+ # Try the system32 directory first - if that fails due to "access denied",
+ # it implies a non-admin user, and we use sys.prefix
+ for dest_dir in [get_system_dir(), sys.prefix]:
+ # and copy some files over there
+ worked = 0
+ try:
+ for fname in files:
+ base = os.path.basename(fname)
+ dst = os.path.join(dest_dir, base)
+ CopyTo("installing %s" % base, fname, dst)
+ if verbose:
+ print("Copied %s to %s" % (base, dst))
+ # Register the files with the uninstaller
+ file_created(dst)
+ worked = 1
+ # Nuke any other versions that may exist - having
+ # duplicates causes major headaches.
+ bad_dest_dirs = [
+ os.path.join(sys.prefix, "Library\\bin"),
+ os.path.join(sys.prefix, "Lib\\site-packages\\win32"),
+ ]
+ if dest_dir != sys.prefix:
+ bad_dest_dirs.append(sys.prefix)
+ for bad_dest_dir in bad_dest_dirs:
+ bad_fname = os.path.join(bad_dest_dir, base)
+ if os.path.exists(bad_fname):
+ # let exceptions go here - delete must succeed
+ os.unlink(bad_fname)
+ if worked:
+ break
+ except win32api.error as details:
+ if details.winerror == 5:
+ # access denied - user not admin - try sys.prefix dir,
+ # but first check that a version doesn't already exist
+ # in that place - otherwise that one will still get used!
+ if os.path.exists(dst):
+ msg = (
+ "The file '%s' exists, but can not be replaced "
+ "due to insufficient permissions. You must "
+ "reinstall this software as an Administrator" % dst
+ )
+ print(msg)
+ raise RuntimeError(msg)
+ continue
+ raise
+ else:
+ raise RuntimeError(
+ "You don't have enough permissions to install the system files"
+ )
+
+ # Pythonwin 'compiles' config files - record them for uninstall.
+ pywin_dir = os.path.join(lib_dir, "Pythonwin", "pywin")
+ for fname in glob.glob(os.path.join(pywin_dir, "*.cfg")):
+ file_created(fname[:-1] + "c") # .cfg->.cfc
+
+ # Register our demo COM objects.
+ try:
+ try:
+ RegisterCOMObjects()
+ except win32api.error as details:
+ if details.winerror != 5: # ERROR_ACCESS_DENIED
+ raise
+ print("You do not have the permissions to install COM objects.")
+ print("The sample COM objects were not registered.")
+ except Exception:
+ print("FAILED to register the Python COM objects")
+ traceback.print_exc()
+
+ # There may be no main Python key in HKCU if, eg, an admin installed
+ # python itself.
+ winreg.CreateKey(get_root_hkey(), root_key_name)
+
+ chm_file = None
+ try:
+ chm_file = RegisterHelpFile(True, lib_dir)
+ except Exception:
+ print("Failed to register help file")
+ traceback.print_exc()
+ else:
+ if verbose:
+ print("Registered help file")
+
+ # misc other fixups.
+ fixup_dbi()
+
+ # Register Pythonwin in context menu
+ try:
+ RegisterPythonwin(True, lib_dir)
+ except Exception:
+ print("Failed to register pythonwin as editor")
+ traceback.print_exc()
+ else:
+ if verbose:
+ print("Pythonwin has been registered in context menu")
+
+ # Create the win32com\gen_py directory.
+ make_dir = os.path.join(lib_dir, "win32com", "gen_py")
+ if not os.path.isdir(make_dir):
+ if verbose:
+ print("Creating directory %s" % (make_dir,))
+ directory_created(make_dir)
+ os.mkdir(make_dir)
+
+ try:
+ # create shortcuts
+ # CSIDL_COMMON_PROGRAMS only available works on NT/2000/XP, and
+ # will fail there if the user has no admin rights.
+ fldr = get_shortcuts_folder()
+ # If the group doesn't exist, then we don't make shortcuts - its
+ # possible that this isn't a "normal" install.
+ if os.path.isdir(fldr):
+ dst = os.path.join(fldr, "PythonWin.lnk")
+ create_shortcut(
+ os.path.join(lib_dir, "Pythonwin\\Pythonwin.exe"),
+ "The Pythonwin IDE",
+ dst,
+ "",
+ sys.prefix,
+ )
+ file_created(dst)
+ if verbose:
+ print("Shortcut for Pythonwin created")
+ # And the docs.
+ if chm_file:
+ dst = os.path.join(fldr, "Python for Windows Documentation.lnk")
+ doc = "Documentation for the PyWin32 extensions"
+ create_shortcut(chm_file, doc, dst)
+ file_created(dst)
+ if verbose:
+ print("Shortcut to documentation created")
+ else:
+ if verbose:
+ print("Can't install shortcuts - %r is not a folder" % (fldr,))
+ except Exception as details:
+ print(details)
+
+ # importing win32com.client ensures the gen_py dir created - not strictly
+ # necessary to do now, but this makes the installation "complete"
+ try:
+ import win32com.client # noqa
+ except ImportError:
+ # Don't let this error sound fatal
+ pass
+ print("The pywin32 extensions were successfully installed.")
+
+ if is_bdist_wininst:
+ # Open a web page with info about the .exe installers being deprecated.
+ import webbrowser
+
+ try:
+ webbrowser.open("https://mhammond.github.io/pywin32_installers.html")
+ except webbrowser.Error:
+ print("Please visit https://mhammond.github.io/pywin32_installers.html")
+
+
+def uninstall(lib_dir):
+ # First ensure our system modules are loaded from pywin32_system, so
+ # we can remove the ones we copied...
+ LoadSystemModule(lib_dir, "pywintypes")
+ LoadSystemModule(lib_dir, "pythoncom")
+
+ try:
+ RegisterCOMObjects(False)
+ except Exception as why:
+ print("Failed to unregister COM objects: %s" % (why,))
+
+ try:
+ RegisterHelpFile(False, lib_dir)
+ except Exception as why:
+ print("Failed to unregister help file: %s" % (why,))
+ else:
+ if verbose:
+ print("Unregistered help file")
+
+ try:
+ RegisterPythonwin(False, lib_dir)
+ except Exception as why:
+ print("Failed to unregister Pythonwin: %s" % (why,))
+ else:
+ if verbose:
+ print("Unregistered Pythonwin")
+
+ try:
+ # remove gen_py directory.
+ gen_dir = os.path.join(lib_dir, "win32com", "gen_py")
+ if os.path.isdir(gen_dir):
+ shutil.rmtree(gen_dir)
+ if verbose:
+ print("Removed directory %s" % (gen_dir,))
+
+ # Remove pythonwin compiled "config" files.
+ pywin_dir = os.path.join(lib_dir, "Pythonwin", "pywin")
+ for fname in glob.glob(os.path.join(pywin_dir, "*.cfc")):
+ os.remove(fname)
+
+ # The dbi.pyd.old files we may have created.
+ try:
+ os.remove(os.path.join(lib_dir, "win32", "dbi.pyd.old"))
+ except os.error:
+ pass
+ try:
+ os.remove(os.path.join(lib_dir, "win32", "dbi_d.pyd.old"))
+ except os.error:
+ pass
+
+ except Exception as why:
+ print("Failed to remove misc files: %s" % (why,))
+
+ try:
+ fldr = get_shortcuts_folder()
+ for link in ("PythonWin.lnk", "Python for Windows Documentation.lnk"):
+ fqlink = os.path.join(fldr, link)
+ if os.path.isfile(fqlink):
+ os.remove(fqlink)
+ if verbose:
+ print("Removed %s" % (link,))
+ except Exception as why:
+ print("Failed to remove shortcuts: %s" % (why,))
+ # Now remove the system32 files.
+ files = glob.glob(os.path.join(lib_dir, "pywin32_system32\\*.*"))
+ # Try the system32 directory first - if that fails due to "access denied",
+ # it implies a non-admin user, and we use sys.prefix
+ try:
+ for dest_dir in [get_system_dir(), sys.prefix]:
+ # and copy some files over there
+ worked = 0
+ for fname in files:
+ base = os.path.basename(fname)
+ dst = os.path.join(dest_dir, base)
+ if os.path.isfile(dst):
+ try:
+ os.remove(dst)
+ worked = 1
+ if verbose:
+ print("Removed file %s" % (dst))
+ except Exception:
+ print("FAILED to remove %s" % (dst,))
+ if worked:
+ break
+ except Exception as why:
+ print("FAILED to remove system files: %s" % (why,))
+
+
+# NOTE: If this script is run from inside the bdist_wininst created
+# binary installer or uninstaller, the command line args are either
+# '-install' or '-remove'.
+
+# Important: From inside the binary installer this script MUST NOT
+# call sys.exit() or raise SystemExit, otherwise not only this script
+# but also the installer will terminate! (Is there a way to prevent
+# this from the bdist_wininst C code?)
+
+
+def verify_destination(location):
+ if not os.path.isdir(location):
+ raise argparse.ArgumentTypeError('Path "{}" does not exist!'.format(location))
+ return location
+
+
+def main():
+ import argparse
+
+ parser = argparse.ArgumentParser(
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ description="""A post-install script for the pywin32 extensions.
+
+ * Typical usage:
+
+ > python pywin32_postinstall.py -install
+
+ If you installed pywin32 via a .exe installer, this should be run
+ automatically after installation, but if it fails you can run it again.
+
+ If you installed pywin32 via PIP, you almost certainly need to run this to
+ setup the environment correctly.
+
+ Execute with script with a '-install' parameter, to ensure the environment
+ is setup correctly.
+ """,
+ )
+ parser.add_argument(
+ "-install",
+ default=False,
+ action="store_true",
+ help="Configure the Python environment correctly for pywin32.",
+ )
+ parser.add_argument(
+ "-remove",
+ default=False,
+ action="store_true",
+ help="Try and remove everything that was installed or copied.",
+ )
+ parser.add_argument(
+ "-wait",
+ type=int,
+ help="Wait for the specified process to terminate before starting.",
+ )
+ parser.add_argument(
+ "-silent",
+ default=False,
+ action="store_true",
+ help='Don\'t display the "Abort/Retry/Ignore" dialog for files in use.',
+ )
+ parser.add_argument(
+ "-quiet",
+ default=False,
+ action="store_true",
+ help="Don't display progress messages.",
+ )
+ parser.add_argument(
+ "-destination",
+ default=sysconfig.get_paths()["platlib"],
+ type=verify_destination,
+ help="Location of the PyWin32 installation",
+ )
+
+ args = parser.parse_args()
+
+ if not args.quiet:
+ print("Parsed arguments are: {}".format(args))
+
+ if not args.install ^ args.remove:
+ parser.error("You need to either choose to -install or -remove!")
+
+ if args.wait is not None:
+ try:
+ os.waitpid(args.wait, 0)
+ except os.error:
+ # child already dead
+ pass
+
+ silent = args.silent
+ verbose = not args.quiet
+
+ if args.install:
+ install(args.destination)
+
+ if args.remove:
+ if not is_bdist_wininst:
+ uninstall(args.destination)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/lab_3/aimenv/Scripts/pywin32_testall.py b/lab_3/aimenv/Scripts/pywin32_testall.py
new file mode 100644
index 0000000..a54f9d4
--- /dev/null
+++ b/lab_3/aimenv/Scripts/pywin32_testall.py
@@ -0,0 +1,124 @@
+"""A test runner for pywin32"""
+import os
+import site
+import subprocess
+import sys
+
+# locate the dirs based on where this script is - it may be either in the
+# source tree, or in an installed Python 'Scripts' tree.
+this_dir = os.path.dirname(__file__)
+site_packages = [
+ site.getusersitepackages(),
+] + site.getsitepackages()
+
+failures = []
+
+
+# Run a test using subprocess and wait for the result.
+# If we get an returncode != 0, we know that there was an error, but we don't
+# abort immediately - we run as many tests as we can.
+def run_test(script, cmdline_extras):
+ dirname, scriptname = os.path.split(script)
+ # some tests prefer to be run from their directory.
+ cmd = [sys.executable, "-u", scriptname] + cmdline_extras
+ print("--- Running '%s' ---" % script)
+ sys.stdout.flush()
+ result = subprocess.run(cmd, check=False, cwd=dirname)
+ print("*** Test script '%s' exited with %s" % (script, result.returncode))
+ sys.stdout.flush()
+ if result.returncode:
+ failures.append(script)
+
+
+def find_and_run(possible_locations, extras):
+ for maybe in possible_locations:
+ if os.path.isfile(maybe):
+ run_test(maybe, extras)
+ break
+ else:
+ raise RuntimeError(
+ "Failed to locate a test script in one of %s" % possible_locations
+ )
+
+
+def main():
+ import argparse
+
+ code_directories = [this_dir] + site_packages
+
+ parser = argparse.ArgumentParser(
+ description="A script to trigger tests in all subprojects of PyWin32."
+ )
+ parser.add_argument(
+ "-no-user-interaction",
+ default=False,
+ action="store_true",
+ help="(This is now the default - use `-user-interaction` to include them)",
+ )
+
+ parser.add_argument(
+ "-user-interaction",
+ action="store_true",
+ help="Include tests which require user interaction",
+ )
+
+ parser.add_argument(
+ "-skip-adodbapi",
+ default=False,
+ action="store_true",
+ help="Skip the adodbapi tests; useful for CI where there's no provider",
+ )
+
+ args, remains = parser.parse_known_args()
+
+ # win32, win32ui / Pythonwin
+
+ extras = []
+ if args.user_interaction:
+ extras += ["-user-interaction"]
+ extras.extend(remains)
+ scripts = [
+ "win32/test/testall.py",
+ "Pythonwin/pywin/test/all.py",
+ ]
+ for script in scripts:
+ maybes = [os.path.join(directory, script) for directory in code_directories]
+ find_and_run(maybes, extras)
+
+ # win32com
+ maybes = [
+ os.path.join(directory, "win32com", "test", "testall.py")
+ for directory in [
+ os.path.join(this_dir, "com"),
+ ]
+ + site_packages
+ ]
+ extras = remains + ["1"] # only run "level 1" tests in CI
+ find_and_run(maybes, extras)
+
+ # adodbapi
+ if not args.skip_adodbapi:
+ maybes = [
+ os.path.join(directory, "adodbapi", "test", "adodbapitest.py")
+ for directory in code_directories
+ ]
+ find_and_run(maybes, remains)
+ # This script has a hard-coded sql server name in it, (and markh typically
+ # doesn't have a different server to test on) but there is now supposed to be a server out there on the Internet
+ # just to run these tests, so try it...
+ maybes = [
+ os.path.join(directory, "adodbapi", "test", "test_adodbapi_dbapi20.py")
+ for directory in code_directories
+ ]
+ find_and_run(maybes, remains)
+
+ if failures:
+ print("The following scripts failed")
+ for failure in failures:
+ print(">", failure)
+ sys.exit(1)
+ print("All tests passed \\o/")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/lab_3/aimenv/pyvenv.cfg b/lab_3/aimenv/pyvenv.cfg
new file mode 100644
index 0000000..b18a31c
--- /dev/null
+++ b/lab_3/aimenv/pyvenv.cfg
@@ -0,0 +1,5 @@
+home = C:\Users\Egor\AppData\Local\Programs\Python\Python312
+include-system-site-packages = false
+version = 3.12.5
+executable = C:\Users\Egor\AppData\Local\Programs\Python\Python312\python.exe
+command = C:\Users\Egor\AppData\Local\Programs\Python\Python312\python.exe -m venv C:\Users\Egor\Desktop\ULSTU\AI\aim\aimenv
diff --git a/lab_3/aimenv/share/jupyter/kernels/python3/kernel.json b/lab_3/aimenv/share/jupyter/kernels/python3/kernel.json
new file mode 100644
index 0000000..cca38a4
--- /dev/null
+++ b/lab_3/aimenv/share/jupyter/kernels/python3/kernel.json
@@ -0,0 +1,14 @@
+{
+ "argv": [
+ "python",
+ "-m",
+ "ipykernel_launcher",
+ "-f",
+ "{connection_file}"
+ ],
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "metadata": {
+ "debugger": true
+ }
+}
\ No newline at end of file
diff --git a/lab_3/aimenv/share/jupyter/kernels/python3/logo-32x32.png b/lab_3/aimenv/share/jupyter/kernels/python3/logo-32x32.png
new file mode 100644
index 0000000..be81330
Binary files /dev/null and b/lab_3/aimenv/share/jupyter/kernels/python3/logo-32x32.png differ
diff --git a/lab_3/aimenv/share/jupyter/kernels/python3/logo-64x64.png b/lab_3/aimenv/share/jupyter/kernels/python3/logo-64x64.png
new file mode 100644
index 0000000..eebbff6
Binary files /dev/null and b/lab_3/aimenv/share/jupyter/kernels/python3/logo-64x64.png differ
diff --git a/lab_3/aimenv/share/jupyter/kernels/python3/logo-svg.svg b/lab_3/aimenv/share/jupyter/kernels/python3/logo-svg.svg
new file mode 100644
index 0000000..467b07b
--- /dev/null
+++ b/lab_3/aimenv/share/jupyter/kernels/python3/logo-svg.svg
@@ -0,0 +1,265 @@
+
+
+
+
diff --git a/lab_3/aimenv/share/man/man1/ipython.1 b/lab_3/aimenv/share/man/man1/ipython.1
new file mode 100644
index 0000000..0f4a191
--- /dev/null
+++ b/lab_3/aimenv/share/man/man1/ipython.1
@@ -0,0 +1,60 @@
+.\" Hey, EMACS: -*- nroff -*-
+.\" First parameter, NAME, should be all caps
+.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
+.\" other parameters are allowed: see man(7), man(1)
+.TH IPYTHON 1 "July 15, 2011"
+.\" Please adjust this date whenever revising the manpage.
+.\"
+.\" Some roff macros, for reference:
+.\" .nh disable hyphenation
+.\" .hy enable hyphenation
+.\" .ad l left justify
+.\" .ad b justify to both left and right margins
+.\" .nf disable filling
+.\" .fi enable filling
+.\" .br insert line break
+.\" .sp insert n+1 empty lines
+.\" for manpage-specific macros, see man(7) and groff_man(7)
+.\" .SH section heading
+.\" .SS secondary section heading
+.\"
+.\"
+.\" To preview this page as plain text: nroff -man ipython.1
+.\"
+.SH NAME
+ipython \- Tools for Interactive Computing in Python.
+.SH SYNOPSIS
+.B ipython
+.RI [ options ] " files" ...
+
+.B ipython subcommand
+.RI [ options ] ...
+
+.SH DESCRIPTION
+An interactive Python shell with automatic history (input and output), dynamic
+object introspection, easier configuration, command completion, access to the
+system shell, integration with numerical and scientific computing tools,
+web notebook, Qt console, and more.
+
+For more information on how to use IPython, see 'ipython \-\-help',
+or 'ipython \-\-help\-all' for all available command\(hyline options.
+
+.SH "ENVIRONMENT VARIABLES"
+.sp
+.PP
+\fIIPYTHONDIR\fR
+.RS 4
+This is the location where IPython stores all its configuration files. The default
+is $HOME/.ipython if IPYTHONDIR is not defined.
+
+You can see the computed value of IPYTHONDIR with `ipython locate`.
+
+.SH FILES
+
+IPython uses various configuration files stored in profiles within IPYTHONDIR.
+To generate the default configuration files and start configuring IPython,
+do 'ipython profile create', and edit '*_config.py' files located in
+IPYTHONDIR/profile_default.
+
+.SH AUTHORS
+IPython is written by the IPython Development Team .
diff --git a/lab_4/aimenv/Scripts/Activate.ps1 b/lab_4/aimenv/Scripts/Activate.ps1
new file mode 100644
index 0000000..3045241
--- /dev/null
+++ b/lab_4/aimenv/Scripts/Activate.ps1
@@ -0,0 +1,502 @@
+<#
+.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 VIRTUAL_ENV_PROMPT altogether.
+ if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) {
+ Remove-Item -Path env:VIRTUAL_ENV_PROMPT
+ }
+
+ # 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
+ }
+ $env:VIRTUAL_ENV_PROMPT = $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
+# MIIvIwYJKoZIhvcNAQcCoIIvFDCCLxACAQExDzANBglghkgBZQMEAgEFADB5Bgor
+# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
+# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBnL745ElCYk8vk
+# dBtMuQhLeWJ3ZGfzKW4DHCYzAn+QB6CCE8MwggWQMIIDeKADAgECAhAFmxtXno4h
+# MuI5B72nd3VcMA0GCSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
+# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNV
+# BAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0xMzA4MDExMjAwMDBaFw0z
+# ODAxMTUxMjAwMDBaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ
+# bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0
+# IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
+# AL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsbhA3EMB/z
+# G6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKyunWZ
+# anMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGbNOsFxl7s
+# Wxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclPXuU15zHL
+# 2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJBMtfb
+# BHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFPObURWBf3
+# JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTvkpI6nj3c
+# AORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWMcCxBYKqx
+# YxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5SUUd0
+# viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+xq4aL
+# T8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjQjBAMA8GA1Ud
+# EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTs1+OC0nFdZEzf
+# Lmc/57qYrhwPTzANBgkqhkiG9w0BAQwFAAOCAgEAu2HZfalsvhfEkRvDoaIAjeNk
+# aA9Wz3eucPn9mkqZucl4XAwMX+TmFClWCzZJXURj4K2clhhmGyMNPXnpbWvWVPjS
+# PMFDQK4dUPVS/JA7u5iZaWvHwaeoaKQn3J35J64whbn2Z006Po9ZOSJTROvIXQPK
+# 7VB6fWIhCoDIc2bRoAVgX+iltKevqPdtNZx8WorWojiZ83iL9E3SIAveBO6Mm0eB
+# cg3AFDLvMFkuruBx8lbkapdvklBtlo1oepqyNhR6BvIkuQkRUNcIsbiJeoQjYUIp
+# 5aPNoiBB19GcZNnqJqGLFNdMGbJQQXE9P01wI4YMStyB0swylIQNCAmXHE/A7msg
+# dDDS4Dk0EIUhFQEI6FUy3nFJ2SgXUE3mvk3RdazQyvtBuEOlqtPDBURPLDab4vri
+# RbgjU2wGb2dVf0a1TD9uKFp5JtKkqGKX0h7i7UqLvBv9R0oN32dmfrJbQdA75PQ7
+# 9ARj6e/CVABRoIoqyc54zNXqhwQYs86vSYiv85KZtrPmYQ/ShQDnUBrkG5WdGaG5
+# nLGbsQAe79APT0JsyQq87kP6OnGlyE0mpTX9iV28hWIdMtKgK1TtmlfB2/oQzxm3
+# i0objwG2J5VT6LaJbVu8aNQj6ItRolb58KaAoNYes7wPD1N1KarqE3fk3oyBIa0H
+# EEcRrYc9B9F1vM/zZn4wggawMIIEmKADAgECAhAIrUCyYNKcTJ9ezam9k67ZMA0G
+# CSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ
+# bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0
+# IFRydXN0ZWQgUm9vdCBHNDAeFw0yMTA0MjkwMDAwMDBaFw0zNjA0MjgyMzU5NTla
+# MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE
+# AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEz
+# ODQgMjAyMSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDVtC9C
+# 0CiteLdd1TlZG7GIQvUzjOs9gZdwxbvEhSYwn6SOaNhc9es0JAfhS0/TeEP0F9ce
+# 2vnS1WcaUk8OoVf8iJnBkcyBAz5NcCRks43iCH00fUyAVxJrQ5qZ8sU7H/Lvy0da
+# E6ZMswEgJfMQ04uy+wjwiuCdCcBlp/qYgEk1hz1RGeiQIXhFLqGfLOEYwhrMxe6T
+# SXBCMo/7xuoc82VokaJNTIIRSFJo3hC9FFdd6BgTZcV/sk+FLEikVoQ11vkunKoA
+# FdE3/hoGlMJ8yOobMubKwvSnowMOdKWvObarYBLj6Na59zHh3K3kGKDYwSNHR7Oh
+# D26jq22YBoMbt2pnLdK9RBqSEIGPsDsJ18ebMlrC/2pgVItJwZPt4bRc4G/rJvmM
+# 1bL5OBDm6s6R9b7T+2+TYTRcvJNFKIM2KmYoX7BzzosmJQayg9Rc9hUZTO1i4F4z
+# 8ujo7AqnsAMrkbI2eb73rQgedaZlzLvjSFDzd5Ea/ttQokbIYViY9XwCFjyDKK05
+# huzUtw1T0PhH5nUwjewwk3YUpltLXXRhTT8SkXbev1jLchApQfDVxW0mdmgRQRNY
+# mtwmKwH0iU1Z23jPgUo+QEdfyYFQc4UQIyFZYIpkVMHMIRroOBl8ZhzNeDhFMJlP
+# /2NPTLuqDQhTQXxYPUez+rbsjDIJAsxsPAxWEQIDAQABo4IBWTCCAVUwEgYDVR0T
+# AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUaDfg67Y7+F8Rhvv+YXsIiGX0TkIwHwYD
+# VR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMG
+# A1UdJQQMMAoGCCsGAQUFBwMDMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYY
+# aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2Fj
+# ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNV
+# HR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRU
+# cnVzdGVkUm9vdEc0LmNybDAcBgNVHSAEFTATMAcGBWeBDAEDMAgGBmeBDAEEATAN
+# BgkqhkiG9w0BAQwFAAOCAgEAOiNEPY0Idu6PvDqZ01bgAhql+Eg08yy25nRm95Ry
+# sQDKr2wwJxMSnpBEn0v9nqN8JtU3vDpdSG2V1T9J9Ce7FoFFUP2cvbaF4HZ+N3HL
+# IvdaqpDP9ZNq4+sg0dVQeYiaiorBtr2hSBh+3NiAGhEZGM1hmYFW9snjdufE5Btf
+# Q/g+lP92OT2e1JnPSt0o618moZVYSNUa/tcnP/2Q0XaG3RywYFzzDaju4ImhvTnh
+# OE7abrs2nfvlIVNaw8rpavGiPttDuDPITzgUkpn13c5UbdldAhQfQDN8A+KVssIh
+# dXNSy0bYxDQcoqVLjc1vdjcshT8azibpGL6QB7BDf5WIIIJw8MzK7/0pNVwfiThV
+# 9zeKiwmhywvpMRr/LhlcOXHhvpynCgbWJme3kuZOX956rEnPLqR0kq3bPKSchh/j
+# wVYbKyP/j7XqiHtwa+aguv06P0WmxOgWkVKLQcBIhEuWTatEQOON8BUozu3xGFYH
+# Ki8QxAwIZDwzj64ojDzLj4gLDb879M4ee47vtevLt/B3E+bnKD+sEq6lLyJsQfmC
+# XBVmzGwOysWGw/YmMwwHS6DTBwJqakAwSEs0qFEgu60bhQjiWQ1tygVQK+pKHJ6l
+# /aCnHwZ05/LWUpD9r4VIIflXO7ScA+2GRfS0YW6/aOImYIbqyK+p/pQd52MbOoZW
+# eE4wggd3MIIFX6ADAgECAhAHHxQbizANJfMU6yMM0NHdMA0GCSqGSIb3DQEBCwUA
+# MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE
+# AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEz
+# ODQgMjAyMSBDQTEwHhcNMjIwMTE3MDAwMDAwWhcNMjUwMTE1MjM1OTU5WjB8MQsw
+# CQYDVQQGEwJVUzEPMA0GA1UECBMGT3JlZ29uMRIwEAYDVQQHEwlCZWF2ZXJ0b24x
+# IzAhBgNVBAoTGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMSMwIQYDVQQDExpQ
+# eXRob24gU29mdHdhcmUgRm91bmRhdGlvbjCCAiIwDQYJKoZIhvcNAQEBBQADggIP
+# ADCCAgoCggIBAKgc0BTT+iKbtK6f2mr9pNMUTcAJxKdsuOiSYgDFfwhjQy89koM7
+# uP+QV/gwx8MzEt3c9tLJvDccVWQ8H7mVsk/K+X+IufBLCgUi0GGAZUegEAeRlSXx
+# xhYScr818ma8EvGIZdiSOhqjYc4KnfgfIS4RLtZSrDFG2tN16yS8skFa3IHyvWdb
+# D9PvZ4iYNAS4pjYDRjT/9uzPZ4Pan+53xZIcDgjiTwOh8VGuppxcia6a7xCyKoOA
+# GjvCyQsj5223v1/Ig7Dp9mGI+nh1E3IwmyTIIuVHyK6Lqu352diDY+iCMpk9Zanm
+# SjmB+GMVs+H/gOiofjjtf6oz0ki3rb7sQ8fTnonIL9dyGTJ0ZFYKeb6BLA66d2GA
+# LwxZhLe5WH4Np9HcyXHACkppsE6ynYjTOd7+jN1PRJahN1oERzTzEiV6nCO1M3U1
+# HbPTGyq52IMFSBM2/07WTJSbOeXjvYR7aUxK9/ZkJiacl2iZI7IWe7JKhHohqKuc
+# eQNyOzxTakLcRkzynvIrk33R9YVqtB4L6wtFxhUjvDnQg16xot2KVPdfyPAWd81w
+# tZADmrUtsZ9qG79x1hBdyOl4vUtVPECuyhCxaw+faVjumapPUnwo8ygflJJ74J+B
+# Yxf6UuD7m8yzsfXWkdv52DjL74TxzuFTLHPyARWCSCAbzn3ZIly+qIqDAgMBAAGj
+# ggIGMIICAjAfBgNVHSMEGDAWgBRoN+Drtjv4XxGG+/5hewiIZfROQjAdBgNVHQ4E
+# FgQUt/1Teh2XDuUj2WW3siYWJgkZHA8wDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQM
+# MAoGCCsGAQUFBwMDMIG1BgNVHR8Ega0wgaowU6BRoE+GTWh0dHA6Ly9jcmwzLmRp
+# Z2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNENvZGVTaWduaW5nUlNBNDA5NlNI
+# QTM4NDIwMjFDQTEuY3JsMFOgUaBPhk1odHRwOi8vY3JsNC5kaWdpY2VydC5jb20v
+# RGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZTSEEzODQyMDIxQ0Ex
+# LmNybDA+BgNVHSAENzA1MDMGBmeBDAEEATApMCcGCCsGAQUFBwIBFhtodHRwOi8v
+# d3d3LmRpZ2ljZXJ0LmNvbS9DUFMwgZQGCCsGAQUFBwEBBIGHMIGEMCQGCCsGAQUF
+# BzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wXAYIKwYBBQUHMAKGUGh0dHA6
+# Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNENvZGVTaWdu
+# aW5nUlNBNDA5NlNIQTM4NDIwMjFDQTEuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZI
+# hvcNAQELBQADggIBABxv4AeV/5ltkELHSC63fXAFYS5tadcWTiNc2rskrNLrfH1N
+# s0vgSZFoQxYBFKI159E8oQQ1SKbTEubZ/B9kmHPhprHya08+VVzxC88pOEvz68nA
+# 82oEM09584aILqYmj8Pj7h/kmZNzuEL7WiwFa/U1hX+XiWfLIJQsAHBla0i7QRF2
+# de8/VSF0XXFa2kBQ6aiTsiLyKPNbaNtbcucaUdn6vVUS5izWOXM95BSkFSKdE45O
+# q3FForNJXjBvSCpwcP36WklaHL+aHu1upIhCTUkzTHMh8b86WmjRUqbrnvdyR2yd
+# I5l1OqcMBjkpPpIV6wcc+KY/RH2xvVuuoHjlUjwq2bHiNoX+W1scCpnA8YTs2d50
+# jDHUgwUo+ciwpffH0Riq132NFmrH3r67VaN3TuBxjI8SIZM58WEDkbeoriDk3hxU
+# 8ZWV7b8AW6oyVBGfM06UgkfMb58h+tJPrFx8VI/WLq1dTqMfZOm5cuclMnUHs2uq
+# rRNtnV8UfidPBL4ZHkTcClQbCoz0UbLhkiDvIS00Dn+BBcxw/TKqVL4Oaz3bkMSs
+# M46LciTeucHY9ExRVt3zy7i149sd+F4QozPqn7FrSVHXmem3r7bjyHTxOgqxRCVa
+# 18Vtx7P/8bYSBeS+WHCKcliFCecspusCDSlnRUjZwyPdP0VHxaZg2unjHY3rMYIa
+# tjCCGrICAQEwfTBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIElu
+# Yy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgQ29kZSBTaWduaW5nIFJT
+# QTQwOTYgU0hBMzg0IDIwMjEgQ0ExAhAHHxQbizANJfMU6yMM0NHdMA0GCWCGSAFl
+# AwQCAQUAoIHIMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcC
+# AQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCBnAZ6P7YvTwq0fbF62
+# o7E75R0LxsW5OtyYiFESQckLhjBcBgorBgEEAYI3AgEMMU4wTKBGgEQAQgB1AGkA
+# bAB0ADoAIABSAGUAbABlAGEAcwBlAF8AdgAzAC4AMQAyAC4ANQBfADIAMAAyADQA
+# MAA4ADAANgAuADAAMaECgAAwDQYJKoZIhvcNAQEBBQAEggIAoXbLeBCFQhwr4rTK
+# R0WSySG7AtpuY1n5vhwkJPE0JgQ11PFJYphroU2ouWWM8ifejqa6m21JEWGjC9En
+# Rpzpe1+eps7ClsdO+y5NxZc/3vD1j7IddJdzZh77QqDFMqJEeDNY+00OxxnnhbN1
+# wJk29w8qRyIJ7HpCM0E5b8R8Atooip5ihAgrdrIsyyA3Mnl5Y+YMdqtQYe4QtOhE
+# QcEoxAMoI5nLSGsbLhEM8CArl36EmX31eHTVMRJMaM98p0DkURHL030ALmW2V70h
+# M7ovmhOezFyndR1d3HtcfwRB3nr5vHWZe6ythZ3wVgpsN++RdDOvHjb9LC9lkth/
+# BGbcmVqsA9ZHnub1iPt89GsQBSiXjaOnWUxgJi0Qd3s2pwswLxHp05QDUE/d8EF7
+# Wy6aNPI43+G2BjPLVeM3iVbMWd/yxhH6pddaVPAMKVvxJoJ7PfDLihMNyonHt0on
+# xuaM5r2KaVMWpHIkgLiB9tyvdIQb0IW+YU05VAnOqh7CDaEtP7jM6P0usxY9ufEC
+# BFZnOGb3M/c4KbcOuHOIkY3jGqw+DLZFrcWiIe2wbi2TsXDixs+pz8vm/KQczrQ2
+# RJ1R8jrbK7IIRyZmTYf+dStZG3NhNQn1xcPYraHKNOm9CzNmeXJTdfAe0BEApqUN
+# 9AiLj6uvSEp278ysr/EE3ayw2Qmhghc/MIIXOwYKKwYBBAGCNwMDATGCFyswghcn
+# BgkqhkiG9w0BBwKgghcYMIIXFAIBAzEPMA0GCWCGSAFlAwQCAQUAMHcGCyqGSIb3
+# DQEJEAEEoGgEZjBkAgEBBglghkgBhv1sBwEwMTANBglghkgBZQMEAgEFAAQgpuSq
+# fyINa45wSs5Sa6msoQk+zCLDcSK24OqaBM/0/2cCEFtb0VJATq3jxU9l7ewmqjcY
+# DzIwMjQwODA2MjEwMDM5WqCCEwkwggbCMIIEqqADAgECAhAFRK/zlJ0IOaa/2z9f
+# 5WEWMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdp
+# Q2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2
+# IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0EwHhcNMjMwNzE0MDAwMDAwWhcNMzQxMDEz
+# MjM1OTU5WjBIMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4x
+# IDAeBgNVBAMTF0RpZ2lDZXJ0IFRpbWVzdGFtcCAyMDIzMIICIjANBgkqhkiG9w0B
+# AQEFAAOCAg8AMIICCgKCAgEAo1NFhx2DjlusPlSzI+DPn9fl0uddoQ4J3C9Io5d6
+# OyqcZ9xiFVjBqZMRp82qsmrdECmKHmJjadNYnDVxvzqX65RQjxwg6seaOy+WZuNp
+# 52n+W8PWKyAcwZeUtKVQgfLPywemMGjKg0La/H8JJJSkghraarrYO8pd3hkYhftF
+# 6g1hbJ3+cV7EBpo88MUueQ8bZlLjyNY+X9pD04T10Mf2SC1eRXWWdf7dEKEbg8G4
+# 5lKVtUfXeCk5a+B4WZfjRCtK1ZXO7wgX6oJkTf8j48qG7rSkIWRw69XloNpjsy7p
+# Be6q9iT1HbybHLK3X9/w7nZ9MZllR1WdSiQvrCuXvp/k/XtzPjLuUjT71Lvr1KAs
+# NJvj3m5kGQc3AZEPHLVRzapMZoOIaGK7vEEbeBlt5NkP4FhB+9ixLOFRr7StFQYU
+# 6mIIE9NpHnxkTZ0P387RXoyqq1AVybPKvNfEO2hEo6U7Qv1zfe7dCv95NBB+plwK
+# WEwAPoVpdceDZNZ1zY8SdlalJPrXxGshuugfNJgvOuprAbD3+yqG7HtSOKmYCaFx
+# smxxrz64b5bV4RAT/mFHCoz+8LbH1cfebCTwv0KCyqBxPZySkwS0aXAnDU+3tTbR
+# yV8IpHCj7ArxES5k4MsiK8rxKBMhSVF+BmbTO77665E42FEHypS34lCh8zrTioPL
+# QHsCAwEAAaOCAYswggGHMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMBYG
+# A1UdJQEB/wQMMAoGCCsGAQUFBwMIMCAGA1UdIAQZMBcwCAYGZ4EMAQQCMAsGCWCG
+# SAGG/WwHATAfBgNVHSMEGDAWgBS6FtltTYUvcyl2mi91jGogj57IbzAdBgNVHQ4E
+# FgQUpbbvE+fvzdBkodVWqWUxo97V40kwWgYDVR0fBFMwUTBPoE2gS4ZJaHR0cDov
+# L2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0UlNBNDA5NlNIQTI1
+# NlRpbWVTdGFtcGluZ0NBLmNybDCBkAYIKwYBBQUHAQEEgYMwgYAwJAYIKwYBBQUH
+# MAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBYBggrBgEFBQcwAoZMaHR0cDov
+# L2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0UlNBNDA5NlNI
+# QTI1NlRpbWVTdGFtcGluZ0NBLmNydDANBgkqhkiG9w0BAQsFAAOCAgEAgRrW3qCp
+# tZgXvHCNT4o8aJzYJf/LLOTN6l0ikuyMIgKpuM+AqNnn48XtJoKKcS8Y3U623mzX
+# 4WCcK+3tPUiOuGu6fF29wmE3aEl3o+uQqhLXJ4Xzjh6S2sJAOJ9dyKAuJXglnSoF
+# eoQpmLZXeY/bJlYrsPOnvTcM2Jh2T1a5UsK2nTipgedtQVyMadG5K8TGe8+c+nji
+# kxp2oml101DkRBK+IA2eqUTQ+OVJdwhaIcW0z5iVGlS6ubzBaRm6zxbygzc0brBB
+# Jt3eWpdPM43UjXd9dUWhpVgmagNF3tlQtVCMr1a9TMXhRsUo063nQwBw3syYnhmJ
+# A+rUkTfvTVLzyWAhxFZH7doRS4wyw4jmWOK22z75X7BC1o/jF5HRqsBV44a/rCcs
+# QdCaM0qoNtS5cpZ+l3k4SF/Kwtw9Mt911jZnWon49qfH5U81PAC9vpwqbHkB3NpE
+# 5jreODsHXjlY9HxzMVWggBHLFAx+rrz+pOt5Zapo1iLKO+uagjVXKBbLafIymrLS
+# 2Dq4sUaGa7oX/cR3bBVsrquvczroSUa31X/MtjjA2Owc9bahuEMs305MfR5ocMB3
+# CtQC4Fxguyj/OOVSWtasFyIjTvTs0xf7UGv/B3cfcZdEQcm4RtNsMnxYL2dHZeUb
+# c7aZ+WssBkbvQR7w8F/g29mtkIBEr4AQQYowggauMIIElqADAgECAhAHNje3JFR8
+# 2Ees/ShmKl5bMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
+# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNV
+# BAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0yMjAzMjMwMDAwMDBaFw0z
+# NzAzMjIyMzU5NTlaMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwg
+# SW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2IFNIQTI1
+# NiBUaW1lU3RhbXBpbmcgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
+# AQDGhjUGSbPBPXJJUVXHJQPE8pE3qZdRodbSg9GeTKJtoLDMg/la9hGhRBVCX6SI
+# 82j6ffOciQt/nR+eDzMfUBMLJnOWbfhXqAJ9/UO0hNoR8XOxs+4rgISKIhjf69o9
+# xBd/qxkrPkLcZ47qUT3w1lbU5ygt69OxtXXnHwZljZQp09nsad/ZkIdGAHvbREGJ
+# 3HxqV3rwN3mfXazL6IRktFLydkf3YYMZ3V+0VAshaG43IbtArF+y3kp9zvU5Emfv
+# DqVjbOSmxR3NNg1c1eYbqMFkdECnwHLFuk4fsbVYTXn+149zk6wsOeKlSNbwsDET
+# qVcplicu9Yemj052FVUmcJgmf6AaRyBD40NjgHt1biclkJg6OBGz9vae5jtb7IHe
+# IhTZgirHkr+g3uM+onP65x9abJTyUpURK1h0QCirc0PO30qhHGs4xSnzyqqWc0Jo
+# n7ZGs506o9UD4L/wojzKQtwYSH8UNM/STKvvmz3+DrhkKvp1KCRB7UK/BZxmSVJQ
+# 9FHzNklNiyDSLFc1eSuo80VgvCONWPfcYd6T/jnA+bIwpUzX6ZhKWD7TA4j+s4/T
+# Xkt2ElGTyYwMO1uKIqjBJgj5FBASA31fI7tk42PgpuE+9sJ0sj8eCXbsq11GdeJg
+# o1gJASgADoRU7s7pXcheMBK9Rp6103a50g5rmQzSM7TNsQIDAQABo4IBXTCCAVkw
+# EgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUuhbZbU2FL3MpdpovdYxqII+e
+# yG8wHwYDVR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQD
+# AgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMIMHcGCCsGAQUFBwEBBGswaTAkBggrBgEF
+# BQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRw
+# Oi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNy
+# dDBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGln
+# aUNlcnRUcnVzdGVkUm9vdEc0LmNybDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglg
+# hkgBhv1sBwEwDQYJKoZIhvcNAQELBQADggIBAH1ZjsCTtm+YqUQiAX5m1tghQuGw
+# GC4QTRPPMFPOvxj7x1Bd4ksp+3CKDaopafxpwc8dB+k+YMjYC+VcW9dth/qEICU0
+# MWfNthKWb8RQTGIdDAiCqBa9qVbPFXONASIlzpVpP0d3+3J0FNf/q0+KLHqrhc1D
+# X+1gtqpPkWaeLJ7giqzl/Yy8ZCaHbJK9nXzQcAp876i8dU+6WvepELJd6f8oVInw
+# 1YpxdmXazPByoyP6wCeCRK6ZJxurJB4mwbfeKuv2nrF5mYGjVoarCkXJ38SNoOeY
+# +/umnXKvxMfBwWpx2cYTgAnEtp/Nh4cku0+jSbl3ZpHxcpzpSwJSpzd+k1OsOx0I
+# SQ+UzTl63f8lY5knLD0/a6fxZsNBzU+2QJshIUDQtxMkzdwdeDrknq3lNHGS1yZr
+# 5Dhzq6YBT70/O3itTK37xJV77QpfMzmHQXh6OOmc4d0j/R0o08f56PGYX/sr2H7y
+# Rp11LB4nLCbbbxV7HhmLNriT1ObyF5lZynDwN7+YAN8gFk8n+2BnFqFmut1VwDop
+# hrCYoCvtlUG3OtUVmDG0YgkPCr2B2RP+v6TR81fZvAT6gt4y3wSJ8ADNXcL50CN/
+# AAvkdgIm2fBldkKmKYcJRyvmfxqkhQ/8mJb2VVQrH4D6wPIOK+XW+6kvRBVK5xMO
+# Hds3OBqhK/bt1nz8MIIFjTCCBHWgAwIBAgIQDpsYjvnQLefv21DiCEAYWjANBgkq
+# hkiG9w0BAQwFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5j
+# MRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBB
+# c3N1cmVkIElEIFJvb3QgQ0EwHhcNMjIwODAxMDAwMDAwWhcNMzExMTA5MjM1OTU5
+# WjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQL
+# ExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJv
+# b3QgRzQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1K
+# PDAiMGkz7MKnJS7JIT3yithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2r
+# snnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C
+# 8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBf
+# sXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGY
+# QJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8
+# rhsDdV14Ztk6MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaY
+# dj1ZXUJ2h4mXaXpI8OCiEhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+
+# wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw
+# ++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+N
+# P8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7F
+# wI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo4IBOjCCATYwDwYDVR0TAQH/BAUw
+# AwEB/zAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wHwYDVR0jBBgwFoAU
+# Reuir/SSy4IxLVGLp6chnfNtyA8wDgYDVR0PAQH/BAQDAgGGMHkGCCsGAQUFBwEB
+# BG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsG
+# AQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1
+# cmVkSURSb290Q0EuY3J0MEUGA1UdHwQ+MDwwOqA4oDaGNGh0dHA6Ly9jcmwzLmRp
+# Z2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwEQYDVR0gBAow
+# CDAGBgRVHSAAMA0GCSqGSIb3DQEBDAUAA4IBAQBwoL9DXFXnOF+go3QbPbYW1/e/
+# Vwe9mqyhhyzshV6pGrsi+IcaaVQi7aSId229GhT0E0p6Ly23OO/0/4C5+KH38nLe
+# JLxSA8hO0Cre+i1Wz/n096wwepqLsl7Uz9FDRJtDIeuWcqFItJnLnU+nBgMTdydE
+# 1Od/6Fmo8L8vC6bp8jQ87PcDx4eo0kxAGTVGamlUsLihVo7spNU96LHc/RzY9Hda
+# XFSMb++hUD38dglohJ9vytsgjTVgHAIDyyCwrFigDkBjxZgiwbJZ9VVrzyerbHbO
+# byMt9H5xaiNrIv8SuFQtJ37YOtnwtoeW/VvRXKwYw02fc7cBqZ9Xql4o4rmUMYID
+# djCCA3ICAQEwdzBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIElu
+# Yy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQgUlNBNDA5NiBTSEEyNTYg
+# VGltZVN0YW1waW5nIENBAhAFRK/zlJ0IOaa/2z9f5WEWMA0GCWCGSAFlAwQCAQUA
+# oIHRMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcN
+# MjQwODA2MjEwMDM5WjArBgsqhkiG9w0BCRACDDEcMBowGDAWBBRm8CsywsLJD4Jd
+# zqqKycZPGZzPQDAvBgkqhkiG9w0BCQQxIgQglCIBxGudJQwqEBh+XAoT3nqSoAuS
+# uMjmJTX95zFjdk0wNwYLKoZIhvcNAQkQAi8xKDAmMCQwIgQg0vbkbe10IszR1EBX
+# aEE2b4KK2lWarjMWr00amtQMeCgwDQYJKoZIhvcNAQEBBQAEggIAOkILAZviyFOU
+# Qzt10RYNFHl0zO4rgXcR5oCeJlU1n9y+DwjCTvcrax9qdkEuiEJWDewXbak3TPQK
+# 0ts7jhUIFMDTEn8GZXysruzDlYNLstKM4RbYIK+f2772phehvABS5mn70+L63GXe
+# A5UFYM5M7BAvEY+3DKEwUnN9lAl8YKi1xS545MXYm1B96gI/7oEBDkNV2DoNIZAw
+# R2B4wPTcpI2aG5zZ0jFgVtq8bOXLZ9b9pBrhKbf4PZWxPqAFwUtZryQKdt770u3Y
+# l0WR2SgemKq4aOEvajD1J4fC56lnUoekXt4yH8/fBueCXYx+ADoEkU4/ota7C1oL
+# aCZE4G0iQOH9XFtMUjA87oEPisJG63onir6tsurTjjm/wK8VnFQBSii4ILtfSOfR
+# kDMsu7kS0H5SWliY3sPlDTn4Kwl14EThMmyXUr7SFFHnsibHtfLATTmV6XyeJ03l
+# BmwDl8hdzt5G0pjH/u3bTFcdJu7J0RQuGYgpmNsVYjHCQnZDrJjzIE2os/QYgL6D
+# B/ZYSv96jnYs6cFd93R0ixZMsQPQKcs2gbVYz3nymJL7t605LzW86tENmORsUdgm
+# qh0ky+qe/+D/f88WLLjdHi/xfskiFKEL66Y4EWkECoUUMBRcJlIg1GszTCVmwD1N
+# foIJo8CaFGMoR+QHwDeamNbOOlrCFMQ=
+# SIG # End signature block
diff --git a/lab_4/aimenv/Scripts/activate b/lab_4/aimenv/Scripts/activate
new file mode 100644
index 0000000..8cf30bf
--- /dev/null
+++ b/lab_4/aimenv/Scripts/activate
@@ -0,0 +1,70 @@
+# This file must be used with "source bin/activate" *from bash*
+# You cannot run it directly
+
+deactivate () {
+ # reset old environment variables
+ if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then
+ PATH="${_OLD_VIRTUAL_PATH:-}"
+ export PATH
+ unset _OLD_VIRTUAL_PATH
+ fi
+ if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then
+ PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}"
+ export PYTHONHOME
+ unset _OLD_VIRTUAL_PYTHONHOME
+ fi
+
+ # Call hash to forget past commands. Without forgetting
+ # past commands the $PATH changes we made may not be respected
+ hash -r 2> /dev/null
+
+ if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then
+ PS1="${_OLD_VIRTUAL_PS1:-}"
+ export PS1
+ unset _OLD_VIRTUAL_PS1
+ fi
+
+ unset VIRTUAL_ENV
+ unset VIRTUAL_ENV_PROMPT
+ if [ ! "${1:-}" = "nondestructive" ] ; then
+ # Self destruct!
+ unset -f deactivate
+ fi
+}
+
+# unset irrelevant variables
+deactivate nondestructive
+
+# on Windows, a path can contain colons and backslashes and has to be converted:
+if [ "${OSTYPE:-}" = "cygwin" ] || [ "${OSTYPE:-}" = "msys" ] ; then
+ # transform D:\path\to\venv to /d/path/to/venv on MSYS
+ # and to /cygdrive/d/path/to/venv on Cygwin
+ export VIRTUAL_ENV=$(cygpath "C:\Users\Egor\Desktop\ULSTU\AI\aim\aimenv")
+else
+ # use the path as-is
+ export VIRTUAL_ENV="C:\Users\Egor\Desktop\ULSTU\AI\aim\aimenv"
+fi
+
+_OLD_VIRTUAL_PATH="$PATH"
+PATH="$VIRTUAL_ENV/Scripts:$PATH"
+export PATH
+
+# unset PYTHONHOME if set
+# this will fail if PYTHONHOME is set to the empty string (which is bad anyway)
+# could use `if (set -u; : $PYTHONHOME) ;` in bash
+if [ -n "${PYTHONHOME:-}" ] ; then
+ _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}"
+ unset PYTHONHOME
+fi
+
+if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then
+ _OLD_VIRTUAL_PS1="${PS1:-}"
+ PS1="(aimenv) ${PS1:-}"
+ export PS1
+ VIRTUAL_ENV_PROMPT="(aimenv) "
+ export VIRTUAL_ENV_PROMPT
+fi
+
+# Call hash to forget past commands. Without forgetting
+# past commands the $PATH changes we made may not be respected
+hash -r 2> /dev/null
diff --git a/lab_4/aimenv/Scripts/activate.bat b/lab_4/aimenv/Scripts/activate.bat
new file mode 100644
index 0000000..11bc012
--- /dev/null
+++ b/lab_4/aimenv/Scripts/activate.bat
@@ -0,0 +1,34 @@
+@echo off
+
+rem This file is UTF-8 encoded, so we need to update the current code page while executing it
+for /f "tokens=2 delims=:." %%a in ('"%SystemRoot%\System32\chcp.com"') do (
+ set _OLD_CODEPAGE=%%a
+)
+if defined _OLD_CODEPAGE (
+ "%SystemRoot%\System32\chcp.com" 65001 > nul
+)
+
+set VIRTUAL_ENV=C:\Users\Egor\Desktop\ULSTU\AI\aim\aimenv
+
+if not defined PROMPT set PROMPT=$P$G
+
+if defined _OLD_VIRTUAL_PROMPT set PROMPT=%_OLD_VIRTUAL_PROMPT%
+if defined _OLD_VIRTUAL_PYTHONHOME set PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME%
+
+set _OLD_VIRTUAL_PROMPT=%PROMPT%
+set PROMPT=(aimenv) %PROMPT%
+
+if defined PYTHONHOME set _OLD_VIRTUAL_PYTHONHOME=%PYTHONHOME%
+set PYTHONHOME=
+
+if defined _OLD_VIRTUAL_PATH set PATH=%_OLD_VIRTUAL_PATH%
+if not defined _OLD_VIRTUAL_PATH set _OLD_VIRTUAL_PATH=%PATH%
+
+set PATH=%VIRTUAL_ENV%\Scripts;%PATH%
+set VIRTUAL_ENV_PROMPT=(aimenv)
+
+:END
+if defined _OLD_CODEPAGE (
+ "%SystemRoot%\System32\chcp.com" %_OLD_CODEPAGE% > nul
+ set _OLD_CODEPAGE=
+)
diff --git a/lab_4/aimenv/Scripts/deactivate.bat b/lab_4/aimenv/Scripts/deactivate.bat
new file mode 100644
index 0000000..62a39a7
--- /dev/null
+++ b/lab_4/aimenv/Scripts/deactivate.bat
@@ -0,0 +1,22 @@
+@echo off
+
+if defined _OLD_VIRTUAL_PROMPT (
+ set "PROMPT=%_OLD_VIRTUAL_PROMPT%"
+)
+set _OLD_VIRTUAL_PROMPT=
+
+if defined _OLD_VIRTUAL_PYTHONHOME (
+ set "PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME%"
+ set _OLD_VIRTUAL_PYTHONHOME=
+)
+
+if defined _OLD_VIRTUAL_PATH (
+ set "PATH=%_OLD_VIRTUAL_PATH%"
+)
+
+set _OLD_VIRTUAL_PATH=
+
+set VIRTUAL_ENV=
+set VIRTUAL_ENV_PROMPT=
+
+:END
diff --git a/lab_4/aimenv/Scripts/debugpy.exe b/lab_4/aimenv/Scripts/debugpy.exe
new file mode 100644
index 0000000..6d0e480
Binary files /dev/null and b/lab_4/aimenv/Scripts/debugpy.exe differ
diff --git a/lab_4/aimenv/Scripts/ipython.exe b/lab_4/aimenv/Scripts/ipython.exe
new file mode 100644
index 0000000..c5d0b33
Binary files /dev/null and b/lab_4/aimenv/Scripts/ipython.exe differ
diff --git a/lab_4/aimenv/Scripts/ipython3.exe b/lab_4/aimenv/Scripts/ipython3.exe
new file mode 100644
index 0000000..c5d0b33
Binary files /dev/null and b/lab_4/aimenv/Scripts/ipython3.exe differ
diff --git a/lab_4/aimenv/Scripts/jupyter-kernel.exe b/lab_4/aimenv/Scripts/jupyter-kernel.exe
new file mode 100644
index 0000000..cc1b7f4
Binary files /dev/null and b/lab_4/aimenv/Scripts/jupyter-kernel.exe differ
diff --git a/lab_4/aimenv/Scripts/jupyter-kernelspec.exe b/lab_4/aimenv/Scripts/jupyter-kernelspec.exe
new file mode 100644
index 0000000..72bf4e7
Binary files /dev/null and b/lab_4/aimenv/Scripts/jupyter-kernelspec.exe differ
diff --git a/lab_4/aimenv/Scripts/jupyter-migrate.exe b/lab_4/aimenv/Scripts/jupyter-migrate.exe
new file mode 100644
index 0000000..2033e15
Binary files /dev/null and b/lab_4/aimenv/Scripts/jupyter-migrate.exe differ
diff --git a/lab_4/aimenv/Scripts/jupyter-run.exe b/lab_4/aimenv/Scripts/jupyter-run.exe
new file mode 100644
index 0000000..1d34b22
Binary files /dev/null and b/lab_4/aimenv/Scripts/jupyter-run.exe differ
diff --git a/lab_4/aimenv/Scripts/jupyter-troubleshoot.exe b/lab_4/aimenv/Scripts/jupyter-troubleshoot.exe
new file mode 100644
index 0000000..de9c4d6
Binary files /dev/null and b/lab_4/aimenv/Scripts/jupyter-troubleshoot.exe differ
diff --git a/lab_4/aimenv/Scripts/jupyter.exe b/lab_4/aimenv/Scripts/jupyter.exe
new file mode 100644
index 0000000..77e316a
Binary files /dev/null and b/lab_4/aimenv/Scripts/jupyter.exe differ
diff --git a/lab_4/aimenv/Scripts/pip.exe b/lab_4/aimenv/Scripts/pip.exe
new file mode 100644
index 0000000..e378251
Binary files /dev/null and b/lab_4/aimenv/Scripts/pip.exe differ
diff --git a/lab_4/aimenv/Scripts/pip3.12.exe b/lab_4/aimenv/Scripts/pip3.12.exe
new file mode 100644
index 0000000..e378251
Binary files /dev/null and b/lab_4/aimenv/Scripts/pip3.12.exe differ
diff --git a/lab_4/aimenv/Scripts/pip3.exe b/lab_4/aimenv/Scripts/pip3.exe
new file mode 100644
index 0000000..e378251
Binary files /dev/null and b/lab_4/aimenv/Scripts/pip3.exe differ
diff --git a/lab_4/aimenv/Scripts/pygmentize.exe b/lab_4/aimenv/Scripts/pygmentize.exe
new file mode 100644
index 0000000..9c1459b
Binary files /dev/null and b/lab_4/aimenv/Scripts/pygmentize.exe differ
diff --git a/lab_4/aimenv/Scripts/python.exe b/lab_4/aimenv/Scripts/python.exe
new file mode 100644
index 0000000..b58faef
Binary files /dev/null and b/lab_4/aimenv/Scripts/python.exe differ
diff --git a/lab_4/aimenv/Scripts/pythonw.exe b/lab_4/aimenv/Scripts/pythonw.exe
new file mode 100644
index 0000000..ca33b90
Binary files /dev/null and b/lab_4/aimenv/Scripts/pythonw.exe differ
diff --git a/lab_4/aimenv/Scripts/pywin32_postinstall.py b/lab_4/aimenv/Scripts/pywin32_postinstall.py
new file mode 100644
index 0000000..147f0cd
--- /dev/null
+++ b/lab_4/aimenv/Scripts/pywin32_postinstall.py
@@ -0,0 +1,783 @@
+# postinstall script for pywin32
+#
+# copies PyWinTypesxx.dll and PythonCOMxx.dll into the system directory,
+# and creates a pth file
+import glob
+import os
+import shutil
+import sys
+import sysconfig
+
+try:
+ import winreg as winreg
+except:
+ import winreg
+
+# Send output somewhere so it can be found if necessary...
+import tempfile
+
+tee_f = open(os.path.join(tempfile.gettempdir(), "pywin32_postinstall.log"), "w")
+
+
+class Tee:
+ def __init__(self, file):
+ self.f = file
+
+ def write(self, what):
+ if self.f is not None:
+ try:
+ self.f.write(what.replace("\n", "\r\n"))
+ except IOError:
+ pass
+ tee_f.write(what)
+
+ def flush(self):
+ if self.f is not None:
+ try:
+ self.f.flush()
+ except IOError:
+ pass
+ tee_f.flush()
+
+
+# For some unknown reason, when running under bdist_wininst we will start up
+# with sys.stdout as None but stderr is hooked up. This work-around allows
+# bdist_wininst to see the output we write and display it at the end of
+# the install.
+if sys.stdout is None:
+ sys.stdout = sys.stderr
+
+sys.stderr = Tee(sys.stderr)
+sys.stdout = Tee(sys.stdout)
+
+com_modules = [
+ # module_name, class_names
+ ("win32com.servers.interp", "Interpreter"),
+ ("win32com.servers.dictionary", "DictionaryPolicy"),
+ ("win32com.axscript.client.pyscript", "PyScript"),
+]
+
+# Is this a 'silent' install - ie, avoid all dialogs.
+# Different than 'verbose'
+silent = 0
+
+# Verbosity of output messages.
+verbose = 1
+
+root_key_name = "Software\\Python\\PythonCore\\" + sys.winver
+
+try:
+ # When this script is run from inside the bdist_wininst installer,
+ # file_created() and directory_created() are additional builtin
+ # functions which write lines to Python23\pywin32-install.log. This is
+ # a list of actions for the uninstaller, the format is inspired by what
+ # the Wise installer also creates.
+ file_created
+ is_bdist_wininst = True
+except NameError:
+ is_bdist_wininst = False # we know what it is not - but not what it is :)
+
+ def file_created(file):
+ pass
+
+ def directory_created(directory):
+ pass
+
+ def get_root_hkey():
+ try:
+ winreg.OpenKey(
+ winreg.HKEY_LOCAL_MACHINE, root_key_name, 0, winreg.KEY_CREATE_SUB_KEY
+ )
+ return winreg.HKEY_LOCAL_MACHINE
+ except OSError:
+ # Either not exist, or no permissions to create subkey means
+ # must be HKCU
+ return winreg.HKEY_CURRENT_USER
+
+
+try:
+ create_shortcut
+except NameError:
+ # Create a function with the same signature as create_shortcut provided
+ # by bdist_wininst
+ def create_shortcut(
+ path, description, filename, arguments="", workdir="", iconpath="", iconindex=0
+ ):
+ import pythoncom
+ from win32com.shell import shell
+
+ ilink = pythoncom.CoCreateInstance(
+ shell.CLSID_ShellLink,
+ None,
+ pythoncom.CLSCTX_INPROC_SERVER,
+ shell.IID_IShellLink,
+ )
+ ilink.SetPath(path)
+ ilink.SetDescription(description)
+ if arguments:
+ ilink.SetArguments(arguments)
+ if workdir:
+ ilink.SetWorkingDirectory(workdir)
+ if iconpath or iconindex:
+ ilink.SetIconLocation(iconpath, iconindex)
+ # now save it.
+ ipf = ilink.QueryInterface(pythoncom.IID_IPersistFile)
+ ipf.Save(filename, 0)
+
+ # Support the same list of "path names" as bdist_wininst.
+ def get_special_folder_path(path_name):
+ from win32com.shell import shell, shellcon
+
+ for maybe in """
+ CSIDL_COMMON_STARTMENU CSIDL_STARTMENU CSIDL_COMMON_APPDATA
+ CSIDL_LOCAL_APPDATA CSIDL_APPDATA CSIDL_COMMON_DESKTOPDIRECTORY
+ CSIDL_DESKTOPDIRECTORY CSIDL_COMMON_STARTUP CSIDL_STARTUP
+ CSIDL_COMMON_PROGRAMS CSIDL_PROGRAMS CSIDL_PROGRAM_FILES_COMMON
+ CSIDL_PROGRAM_FILES CSIDL_FONTS""".split():
+ if maybe == path_name:
+ csidl = getattr(shellcon, maybe)
+ return shell.SHGetSpecialFolderPath(0, csidl, False)
+ raise ValueError("%s is an unknown path ID" % (path_name,))
+
+
+def CopyTo(desc, src, dest):
+ import win32api
+ import win32con
+
+ while 1:
+ try:
+ win32api.CopyFile(src, dest, 0)
+ return
+ except win32api.error as details:
+ if details.winerror == 5: # access denied - user not admin.
+ raise
+ if silent:
+ # Running silent mode - just re-raise the error.
+ raise
+ full_desc = (
+ "Error %s\n\n"
+ "If you have any Python applications running, "
+ "please close them now\nand select 'Retry'\n\n%s"
+ % (desc, details.strerror)
+ )
+ rc = win32api.MessageBox(
+ 0, full_desc, "Installation Error", win32con.MB_ABORTRETRYIGNORE
+ )
+ if rc == win32con.IDABORT:
+ raise
+ elif rc == win32con.IDIGNORE:
+ return
+ # else retry - around we go again.
+
+
+# We need to import win32api to determine the Windows system directory,
+# so we can copy our system files there - but importing win32api will
+# load the pywintypes.dll already in the system directory preventing us
+# from updating them!
+# So, we pull the same trick pywintypes.py does, but it loads from
+# our pywintypes_system32 directory.
+def LoadSystemModule(lib_dir, modname):
+ # See if this is a debug build.
+ import importlib.machinery
+ import importlib.util
+
+ suffix = "_d" if "_d.pyd" in importlib.machinery.EXTENSION_SUFFIXES else ""
+ filename = "%s%d%d%s.dll" % (
+ modname,
+ sys.version_info[0],
+ sys.version_info[1],
+ suffix,
+ )
+ filename = os.path.join(lib_dir, "pywin32_system32", filename)
+ loader = importlib.machinery.ExtensionFileLoader(modname, filename)
+ spec = importlib.machinery.ModuleSpec(name=modname, loader=loader, origin=filename)
+ mod = importlib.util.module_from_spec(spec)
+ spec.loader.exec_module(mod)
+
+
+def SetPyKeyVal(key_name, value_name, value):
+ root_hkey = get_root_hkey()
+ root_key = winreg.OpenKey(root_hkey, root_key_name)
+ try:
+ my_key = winreg.CreateKey(root_key, key_name)
+ try:
+ winreg.SetValueEx(my_key, value_name, 0, winreg.REG_SZ, value)
+ if verbose:
+ print("-> %s\\%s[%s]=%r" % (root_key_name, key_name, value_name, value))
+ finally:
+ my_key.Close()
+ finally:
+ root_key.Close()
+
+
+def UnsetPyKeyVal(key_name, value_name, delete_key=False):
+ root_hkey = get_root_hkey()
+ root_key = winreg.OpenKey(root_hkey, root_key_name)
+ try:
+ my_key = winreg.OpenKey(root_key, key_name, 0, winreg.KEY_SET_VALUE)
+ try:
+ winreg.DeleteValue(my_key, value_name)
+ if verbose:
+ print("-> DELETE %s\\%s[%s]" % (root_key_name, key_name, value_name))
+ finally:
+ my_key.Close()
+ if delete_key:
+ winreg.DeleteKey(root_key, key_name)
+ if verbose:
+ print("-> DELETE %s\\%s" % (root_key_name, key_name))
+ except OSError as why:
+ winerror = getattr(why, "winerror", why.errno)
+ if winerror != 2: # file not found
+ raise
+ finally:
+ root_key.Close()
+
+
+def RegisterCOMObjects(register=True):
+ import win32com.server.register
+
+ if register:
+ func = win32com.server.register.RegisterClasses
+ else:
+ func = win32com.server.register.UnregisterClasses
+ flags = {}
+ if not verbose:
+ flags["quiet"] = 1
+ for module, klass_name in com_modules:
+ __import__(module)
+ mod = sys.modules[module]
+ flags["finalize_register"] = getattr(mod, "DllRegisterServer", None)
+ flags["finalize_unregister"] = getattr(mod, "DllUnregisterServer", None)
+ klass = getattr(mod, klass_name)
+ func(klass, **flags)
+
+
+def RegisterHelpFile(register=True, lib_dir=None):
+ if lib_dir is None:
+ lib_dir = sysconfig.get_paths()["platlib"]
+ if register:
+ # Register the .chm help file.
+ chm_file = os.path.join(lib_dir, "PyWin32.chm")
+ if os.path.isfile(chm_file):
+ # This isn't recursive, so if 'Help' doesn't exist, we croak
+ SetPyKeyVal("Help", None, None)
+ SetPyKeyVal("Help\\Pythonwin Reference", None, chm_file)
+ return chm_file
+ else:
+ print("NOTE: PyWin32.chm can not be located, so has not " "been registered")
+ else:
+ UnsetPyKeyVal("Help\\Pythonwin Reference", None, delete_key=True)
+ return None
+
+
+def RegisterPythonwin(register=True, lib_dir=None):
+ """Add (or remove) Pythonwin to context menu for python scripts.
+ ??? Should probably also add Edit command for pys files also.
+ Also need to remove these keys on uninstall, but there's no function
+ like file_created to add registry entries to uninstall log ???
+ """
+ import os
+
+ if lib_dir is None:
+ lib_dir = sysconfig.get_paths()["platlib"]
+ classes_root = get_root_hkey()
+ ## Installer executable doesn't seem to pass anything to postinstall script indicating if it's a debug build,
+ pythonwin_exe = os.path.join(lib_dir, "Pythonwin", "Pythonwin.exe")
+ pythonwin_edit_command = pythonwin_exe + ' -edit "%1"'
+
+ keys_vals = [
+ (
+ "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\Pythonwin.exe",
+ "",
+ pythonwin_exe,
+ ),
+ (
+ "Software\\Classes\\Python.File\\shell\\Edit with Pythonwin",
+ "command",
+ pythonwin_edit_command,
+ ),
+ (
+ "Software\\Classes\\Python.NoConFile\\shell\\Edit with Pythonwin",
+ "command",
+ pythonwin_edit_command,
+ ),
+ ]
+
+ try:
+ if register:
+ for key, sub_key, val in keys_vals:
+ ## Since winreg only uses the character Api functions, this can fail if Python
+ ## is installed to a path containing non-ascii characters
+ hkey = winreg.CreateKey(classes_root, key)
+ if sub_key:
+ hkey = winreg.CreateKey(hkey, sub_key)
+ winreg.SetValueEx(hkey, None, 0, winreg.REG_SZ, val)
+ hkey.Close()
+ else:
+ for key, sub_key, val in keys_vals:
+ try:
+ if sub_key:
+ hkey = winreg.OpenKey(classes_root, key)
+ winreg.DeleteKey(hkey, sub_key)
+ hkey.Close()
+ winreg.DeleteKey(classes_root, key)
+ except OSError as why:
+ winerror = getattr(why, "winerror", why.errno)
+ if winerror != 2: # file not found
+ raise
+ finally:
+ # tell windows about the change
+ from win32com.shell import shell, shellcon
+
+ shell.SHChangeNotify(
+ shellcon.SHCNE_ASSOCCHANGED, shellcon.SHCNF_IDLIST, None, None
+ )
+
+
+def get_shortcuts_folder():
+ if get_root_hkey() == winreg.HKEY_LOCAL_MACHINE:
+ try:
+ fldr = get_special_folder_path("CSIDL_COMMON_PROGRAMS")
+ except OSError:
+ # No CSIDL_COMMON_PROGRAMS on this platform
+ fldr = get_special_folder_path("CSIDL_PROGRAMS")
+ else:
+ # non-admin install - always goes in this user's start menu.
+ fldr = get_special_folder_path("CSIDL_PROGRAMS")
+
+ try:
+ install_group = winreg.QueryValue(
+ get_root_hkey(), root_key_name + "\\InstallPath\\InstallGroup"
+ )
+ except OSError:
+ vi = sys.version_info
+ install_group = "Python %d.%d" % (vi[0], vi[1])
+ return os.path.join(fldr, install_group)
+
+
+# Get the system directory, which may be the Wow64 directory if we are a 32bit
+# python on a 64bit OS.
+def get_system_dir():
+ import win32api # we assume this exists.
+
+ try:
+ import pythoncom
+ import win32process
+ from win32com.shell import shell, shellcon
+
+ try:
+ if win32process.IsWow64Process():
+ return shell.SHGetSpecialFolderPath(0, shellcon.CSIDL_SYSTEMX86)
+ return shell.SHGetSpecialFolderPath(0, shellcon.CSIDL_SYSTEM)
+ except (pythoncom.com_error, win32process.error):
+ return win32api.GetSystemDirectory()
+ except ImportError:
+ return win32api.GetSystemDirectory()
+
+
+def fixup_dbi():
+ # We used to have a dbi.pyd with our .pyd files, but now have a .py file.
+ # If the user didn't uninstall, they will find the .pyd which will cause
+ # problems - so handle that.
+ import win32api
+ import win32con
+
+ pyd_name = os.path.join(os.path.dirname(win32api.__file__), "dbi.pyd")
+ pyd_d_name = os.path.join(os.path.dirname(win32api.__file__), "dbi_d.pyd")
+ py_name = os.path.join(os.path.dirname(win32con.__file__), "dbi.py")
+ for this_pyd in (pyd_name, pyd_d_name):
+ this_dest = this_pyd + ".old"
+ if os.path.isfile(this_pyd) and os.path.isfile(py_name):
+ try:
+ if os.path.isfile(this_dest):
+ print(
+ "Old dbi '%s' already exists - deleting '%s'"
+ % (this_dest, this_pyd)
+ )
+ os.remove(this_pyd)
+ else:
+ os.rename(this_pyd, this_dest)
+ print("renamed '%s'->'%s.old'" % (this_pyd, this_pyd))
+ file_created(this_pyd + ".old")
+ except os.error as exc:
+ print("FAILED to rename '%s': %s" % (this_pyd, exc))
+
+
+def install(lib_dir):
+ import traceback
+
+ # The .pth file is now installed as a regular file.
+ # Create the .pth file in the site-packages dir, and use only relative paths
+ # We used to write a .pth directly to sys.prefix - clobber it.
+ if os.path.isfile(os.path.join(sys.prefix, "pywin32.pth")):
+ os.unlink(os.path.join(sys.prefix, "pywin32.pth"))
+ # The .pth may be new and therefore not loaded in this session.
+ # Setup the paths just in case.
+ for name in "win32 win32\\lib Pythonwin".split():
+ sys.path.append(os.path.join(lib_dir, name))
+ # It is possible people with old versions installed with still have
+ # pywintypes and pythoncom registered. We no longer need this, and stale
+ # entries hurt us.
+ for name in "pythoncom pywintypes".split():
+ keyname = "Software\\Python\\PythonCore\\" + sys.winver + "\\Modules\\" + name
+ for root in winreg.HKEY_LOCAL_MACHINE, winreg.HKEY_CURRENT_USER:
+ try:
+ winreg.DeleteKey(root, keyname + "\\Debug")
+ except WindowsError:
+ pass
+ try:
+ winreg.DeleteKey(root, keyname)
+ except WindowsError:
+ pass
+ LoadSystemModule(lib_dir, "pywintypes")
+ LoadSystemModule(lib_dir, "pythoncom")
+ import win32api
+
+ # and now we can get the system directory:
+ files = glob.glob(os.path.join(lib_dir, "pywin32_system32\\*.*"))
+ if not files:
+ raise RuntimeError("No system files to copy!!")
+ # Try the system32 directory first - if that fails due to "access denied",
+ # it implies a non-admin user, and we use sys.prefix
+ for dest_dir in [get_system_dir(), sys.prefix]:
+ # and copy some files over there
+ worked = 0
+ try:
+ for fname in files:
+ base = os.path.basename(fname)
+ dst = os.path.join(dest_dir, base)
+ CopyTo("installing %s" % base, fname, dst)
+ if verbose:
+ print("Copied %s to %s" % (base, dst))
+ # Register the files with the uninstaller
+ file_created(dst)
+ worked = 1
+ # Nuke any other versions that may exist - having
+ # duplicates causes major headaches.
+ bad_dest_dirs = [
+ os.path.join(sys.prefix, "Library\\bin"),
+ os.path.join(sys.prefix, "Lib\\site-packages\\win32"),
+ ]
+ if dest_dir != sys.prefix:
+ bad_dest_dirs.append(sys.prefix)
+ for bad_dest_dir in bad_dest_dirs:
+ bad_fname = os.path.join(bad_dest_dir, base)
+ if os.path.exists(bad_fname):
+ # let exceptions go here - delete must succeed
+ os.unlink(bad_fname)
+ if worked:
+ break
+ except win32api.error as details:
+ if details.winerror == 5:
+ # access denied - user not admin - try sys.prefix dir,
+ # but first check that a version doesn't already exist
+ # in that place - otherwise that one will still get used!
+ if os.path.exists(dst):
+ msg = (
+ "The file '%s' exists, but can not be replaced "
+ "due to insufficient permissions. You must "
+ "reinstall this software as an Administrator" % dst
+ )
+ print(msg)
+ raise RuntimeError(msg)
+ continue
+ raise
+ else:
+ raise RuntimeError(
+ "You don't have enough permissions to install the system files"
+ )
+
+ # Pythonwin 'compiles' config files - record them for uninstall.
+ pywin_dir = os.path.join(lib_dir, "Pythonwin", "pywin")
+ for fname in glob.glob(os.path.join(pywin_dir, "*.cfg")):
+ file_created(fname[:-1] + "c") # .cfg->.cfc
+
+ # Register our demo COM objects.
+ try:
+ try:
+ RegisterCOMObjects()
+ except win32api.error as details:
+ if details.winerror != 5: # ERROR_ACCESS_DENIED
+ raise
+ print("You do not have the permissions to install COM objects.")
+ print("The sample COM objects were not registered.")
+ except Exception:
+ print("FAILED to register the Python COM objects")
+ traceback.print_exc()
+
+ # There may be no main Python key in HKCU if, eg, an admin installed
+ # python itself.
+ winreg.CreateKey(get_root_hkey(), root_key_name)
+
+ chm_file = None
+ try:
+ chm_file = RegisterHelpFile(True, lib_dir)
+ except Exception:
+ print("Failed to register help file")
+ traceback.print_exc()
+ else:
+ if verbose:
+ print("Registered help file")
+
+ # misc other fixups.
+ fixup_dbi()
+
+ # Register Pythonwin in context menu
+ try:
+ RegisterPythonwin(True, lib_dir)
+ except Exception:
+ print("Failed to register pythonwin as editor")
+ traceback.print_exc()
+ else:
+ if verbose:
+ print("Pythonwin has been registered in context menu")
+
+ # Create the win32com\gen_py directory.
+ make_dir = os.path.join(lib_dir, "win32com", "gen_py")
+ if not os.path.isdir(make_dir):
+ if verbose:
+ print("Creating directory %s" % (make_dir,))
+ directory_created(make_dir)
+ os.mkdir(make_dir)
+
+ try:
+ # create shortcuts
+ # CSIDL_COMMON_PROGRAMS only available works on NT/2000/XP, and
+ # will fail there if the user has no admin rights.
+ fldr = get_shortcuts_folder()
+ # If the group doesn't exist, then we don't make shortcuts - its
+ # possible that this isn't a "normal" install.
+ if os.path.isdir(fldr):
+ dst = os.path.join(fldr, "PythonWin.lnk")
+ create_shortcut(
+ os.path.join(lib_dir, "Pythonwin\\Pythonwin.exe"),
+ "The Pythonwin IDE",
+ dst,
+ "",
+ sys.prefix,
+ )
+ file_created(dst)
+ if verbose:
+ print("Shortcut for Pythonwin created")
+ # And the docs.
+ if chm_file:
+ dst = os.path.join(fldr, "Python for Windows Documentation.lnk")
+ doc = "Documentation for the PyWin32 extensions"
+ create_shortcut(chm_file, doc, dst)
+ file_created(dst)
+ if verbose:
+ print("Shortcut to documentation created")
+ else:
+ if verbose:
+ print("Can't install shortcuts - %r is not a folder" % (fldr,))
+ except Exception as details:
+ print(details)
+
+ # importing win32com.client ensures the gen_py dir created - not strictly
+ # necessary to do now, but this makes the installation "complete"
+ try:
+ import win32com.client # noqa
+ except ImportError:
+ # Don't let this error sound fatal
+ pass
+ print("The pywin32 extensions were successfully installed.")
+
+ if is_bdist_wininst:
+ # Open a web page with info about the .exe installers being deprecated.
+ import webbrowser
+
+ try:
+ webbrowser.open("https://mhammond.github.io/pywin32_installers.html")
+ except webbrowser.Error:
+ print("Please visit https://mhammond.github.io/pywin32_installers.html")
+
+
+def uninstall(lib_dir):
+ # First ensure our system modules are loaded from pywin32_system, so
+ # we can remove the ones we copied...
+ LoadSystemModule(lib_dir, "pywintypes")
+ LoadSystemModule(lib_dir, "pythoncom")
+
+ try:
+ RegisterCOMObjects(False)
+ except Exception as why:
+ print("Failed to unregister COM objects: %s" % (why,))
+
+ try:
+ RegisterHelpFile(False, lib_dir)
+ except Exception as why:
+ print("Failed to unregister help file: %s" % (why,))
+ else:
+ if verbose:
+ print("Unregistered help file")
+
+ try:
+ RegisterPythonwin(False, lib_dir)
+ except Exception as why:
+ print("Failed to unregister Pythonwin: %s" % (why,))
+ else:
+ if verbose:
+ print("Unregistered Pythonwin")
+
+ try:
+ # remove gen_py directory.
+ gen_dir = os.path.join(lib_dir, "win32com", "gen_py")
+ if os.path.isdir(gen_dir):
+ shutil.rmtree(gen_dir)
+ if verbose:
+ print("Removed directory %s" % (gen_dir,))
+
+ # Remove pythonwin compiled "config" files.
+ pywin_dir = os.path.join(lib_dir, "Pythonwin", "pywin")
+ for fname in glob.glob(os.path.join(pywin_dir, "*.cfc")):
+ os.remove(fname)
+
+ # The dbi.pyd.old files we may have created.
+ try:
+ os.remove(os.path.join(lib_dir, "win32", "dbi.pyd.old"))
+ except os.error:
+ pass
+ try:
+ os.remove(os.path.join(lib_dir, "win32", "dbi_d.pyd.old"))
+ except os.error:
+ pass
+
+ except Exception as why:
+ print("Failed to remove misc files: %s" % (why,))
+
+ try:
+ fldr = get_shortcuts_folder()
+ for link in ("PythonWin.lnk", "Python for Windows Documentation.lnk"):
+ fqlink = os.path.join(fldr, link)
+ if os.path.isfile(fqlink):
+ os.remove(fqlink)
+ if verbose:
+ print("Removed %s" % (link,))
+ except Exception as why:
+ print("Failed to remove shortcuts: %s" % (why,))
+ # Now remove the system32 files.
+ files = glob.glob(os.path.join(lib_dir, "pywin32_system32\\*.*"))
+ # Try the system32 directory first - if that fails due to "access denied",
+ # it implies a non-admin user, and we use sys.prefix
+ try:
+ for dest_dir in [get_system_dir(), sys.prefix]:
+ # and copy some files over there
+ worked = 0
+ for fname in files:
+ base = os.path.basename(fname)
+ dst = os.path.join(dest_dir, base)
+ if os.path.isfile(dst):
+ try:
+ os.remove(dst)
+ worked = 1
+ if verbose:
+ print("Removed file %s" % (dst))
+ except Exception:
+ print("FAILED to remove %s" % (dst,))
+ if worked:
+ break
+ except Exception as why:
+ print("FAILED to remove system files: %s" % (why,))
+
+
+# NOTE: If this script is run from inside the bdist_wininst created
+# binary installer or uninstaller, the command line args are either
+# '-install' or '-remove'.
+
+# Important: From inside the binary installer this script MUST NOT
+# call sys.exit() or raise SystemExit, otherwise not only this script
+# but also the installer will terminate! (Is there a way to prevent
+# this from the bdist_wininst C code?)
+
+
+def verify_destination(location):
+ if not os.path.isdir(location):
+ raise argparse.ArgumentTypeError('Path "{}" does not exist!'.format(location))
+ return location
+
+
+def main():
+ import argparse
+
+ parser = argparse.ArgumentParser(
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ description="""A post-install script for the pywin32 extensions.
+
+ * Typical usage:
+
+ > python pywin32_postinstall.py -install
+
+ If you installed pywin32 via a .exe installer, this should be run
+ automatically after installation, but if it fails you can run it again.
+
+ If you installed pywin32 via PIP, you almost certainly need to run this to
+ setup the environment correctly.
+
+ Execute with script with a '-install' parameter, to ensure the environment
+ is setup correctly.
+ """,
+ )
+ parser.add_argument(
+ "-install",
+ default=False,
+ action="store_true",
+ help="Configure the Python environment correctly for pywin32.",
+ )
+ parser.add_argument(
+ "-remove",
+ default=False,
+ action="store_true",
+ help="Try and remove everything that was installed or copied.",
+ )
+ parser.add_argument(
+ "-wait",
+ type=int,
+ help="Wait for the specified process to terminate before starting.",
+ )
+ parser.add_argument(
+ "-silent",
+ default=False,
+ action="store_true",
+ help='Don\'t display the "Abort/Retry/Ignore" dialog for files in use.',
+ )
+ parser.add_argument(
+ "-quiet",
+ default=False,
+ action="store_true",
+ help="Don't display progress messages.",
+ )
+ parser.add_argument(
+ "-destination",
+ default=sysconfig.get_paths()["platlib"],
+ type=verify_destination,
+ help="Location of the PyWin32 installation",
+ )
+
+ args = parser.parse_args()
+
+ if not args.quiet:
+ print("Parsed arguments are: {}".format(args))
+
+ if not args.install ^ args.remove:
+ parser.error("You need to either choose to -install or -remove!")
+
+ if args.wait is not None:
+ try:
+ os.waitpid(args.wait, 0)
+ except os.error:
+ # child already dead
+ pass
+
+ silent = args.silent
+ verbose = not args.quiet
+
+ if args.install:
+ install(args.destination)
+
+ if args.remove:
+ if not is_bdist_wininst:
+ uninstall(args.destination)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/lab_4/aimenv/Scripts/pywin32_testall.py b/lab_4/aimenv/Scripts/pywin32_testall.py
new file mode 100644
index 0000000..a54f9d4
--- /dev/null
+++ b/lab_4/aimenv/Scripts/pywin32_testall.py
@@ -0,0 +1,124 @@
+"""A test runner for pywin32"""
+import os
+import site
+import subprocess
+import sys
+
+# locate the dirs based on where this script is - it may be either in the
+# source tree, or in an installed Python 'Scripts' tree.
+this_dir = os.path.dirname(__file__)
+site_packages = [
+ site.getusersitepackages(),
+] + site.getsitepackages()
+
+failures = []
+
+
+# Run a test using subprocess and wait for the result.
+# If we get an returncode != 0, we know that there was an error, but we don't
+# abort immediately - we run as many tests as we can.
+def run_test(script, cmdline_extras):
+ dirname, scriptname = os.path.split(script)
+ # some tests prefer to be run from their directory.
+ cmd = [sys.executable, "-u", scriptname] + cmdline_extras
+ print("--- Running '%s' ---" % script)
+ sys.stdout.flush()
+ result = subprocess.run(cmd, check=False, cwd=dirname)
+ print("*** Test script '%s' exited with %s" % (script, result.returncode))
+ sys.stdout.flush()
+ if result.returncode:
+ failures.append(script)
+
+
+def find_and_run(possible_locations, extras):
+ for maybe in possible_locations:
+ if os.path.isfile(maybe):
+ run_test(maybe, extras)
+ break
+ else:
+ raise RuntimeError(
+ "Failed to locate a test script in one of %s" % possible_locations
+ )
+
+
+def main():
+ import argparse
+
+ code_directories = [this_dir] + site_packages
+
+ parser = argparse.ArgumentParser(
+ description="A script to trigger tests in all subprojects of PyWin32."
+ )
+ parser.add_argument(
+ "-no-user-interaction",
+ default=False,
+ action="store_true",
+ help="(This is now the default - use `-user-interaction` to include them)",
+ )
+
+ parser.add_argument(
+ "-user-interaction",
+ action="store_true",
+ help="Include tests which require user interaction",
+ )
+
+ parser.add_argument(
+ "-skip-adodbapi",
+ default=False,
+ action="store_true",
+ help="Skip the adodbapi tests; useful for CI where there's no provider",
+ )
+
+ args, remains = parser.parse_known_args()
+
+ # win32, win32ui / Pythonwin
+
+ extras = []
+ if args.user_interaction:
+ extras += ["-user-interaction"]
+ extras.extend(remains)
+ scripts = [
+ "win32/test/testall.py",
+ "Pythonwin/pywin/test/all.py",
+ ]
+ for script in scripts:
+ maybes = [os.path.join(directory, script) for directory in code_directories]
+ find_and_run(maybes, extras)
+
+ # win32com
+ maybes = [
+ os.path.join(directory, "win32com", "test", "testall.py")
+ for directory in [
+ os.path.join(this_dir, "com"),
+ ]
+ + site_packages
+ ]
+ extras = remains + ["1"] # only run "level 1" tests in CI
+ find_and_run(maybes, extras)
+
+ # adodbapi
+ if not args.skip_adodbapi:
+ maybes = [
+ os.path.join(directory, "adodbapi", "test", "adodbapitest.py")
+ for directory in code_directories
+ ]
+ find_and_run(maybes, remains)
+ # This script has a hard-coded sql server name in it, (and markh typically
+ # doesn't have a different server to test on) but there is now supposed to be a server out there on the Internet
+ # just to run these tests, so try it...
+ maybes = [
+ os.path.join(directory, "adodbapi", "test", "test_adodbapi_dbapi20.py")
+ for directory in code_directories
+ ]
+ find_and_run(maybes, remains)
+
+ if failures:
+ print("The following scripts failed")
+ for failure in failures:
+ print(">", failure)
+ sys.exit(1)
+ print("All tests passed \\o/")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/lab_4/aimenv/pyvenv.cfg b/lab_4/aimenv/pyvenv.cfg
new file mode 100644
index 0000000..b18a31c
--- /dev/null
+++ b/lab_4/aimenv/pyvenv.cfg
@@ -0,0 +1,5 @@
+home = C:\Users\Egor\AppData\Local\Programs\Python\Python312
+include-system-site-packages = false
+version = 3.12.5
+executable = C:\Users\Egor\AppData\Local\Programs\Python\Python312\python.exe
+command = C:\Users\Egor\AppData\Local\Programs\Python\Python312\python.exe -m venv C:\Users\Egor\Desktop\ULSTU\AI\aim\aimenv
diff --git a/lab_4/aimenv/share/jupyter/kernels/python3/kernel.json b/lab_4/aimenv/share/jupyter/kernels/python3/kernel.json
new file mode 100644
index 0000000..cca38a4
--- /dev/null
+++ b/lab_4/aimenv/share/jupyter/kernels/python3/kernel.json
@@ -0,0 +1,14 @@
+{
+ "argv": [
+ "python",
+ "-m",
+ "ipykernel_launcher",
+ "-f",
+ "{connection_file}"
+ ],
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "metadata": {
+ "debugger": true
+ }
+}
\ No newline at end of file
diff --git a/lab_4/aimenv/share/jupyter/kernels/python3/logo-32x32.png b/lab_4/aimenv/share/jupyter/kernels/python3/logo-32x32.png
new file mode 100644
index 0000000..be81330
Binary files /dev/null and b/lab_4/aimenv/share/jupyter/kernels/python3/logo-32x32.png differ
diff --git a/lab_4/aimenv/share/jupyter/kernels/python3/logo-64x64.png b/lab_4/aimenv/share/jupyter/kernels/python3/logo-64x64.png
new file mode 100644
index 0000000..eebbff6
Binary files /dev/null and b/lab_4/aimenv/share/jupyter/kernels/python3/logo-64x64.png differ
diff --git a/lab_4/aimenv/share/jupyter/kernels/python3/logo-svg.svg b/lab_4/aimenv/share/jupyter/kernels/python3/logo-svg.svg
new file mode 100644
index 0000000..467b07b
--- /dev/null
+++ b/lab_4/aimenv/share/jupyter/kernels/python3/logo-svg.svg
@@ -0,0 +1,265 @@
+
+
+
+
diff --git a/lab_4/aimenv/share/man/man1/ipython.1 b/lab_4/aimenv/share/man/man1/ipython.1
new file mode 100644
index 0000000..0f4a191
--- /dev/null
+++ b/lab_4/aimenv/share/man/man1/ipython.1
@@ -0,0 +1,60 @@
+.\" Hey, EMACS: -*- nroff -*-
+.\" First parameter, NAME, should be all caps
+.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
+.\" other parameters are allowed: see man(7), man(1)
+.TH IPYTHON 1 "July 15, 2011"
+.\" Please adjust this date whenever revising the manpage.
+.\"
+.\" Some roff macros, for reference:
+.\" .nh disable hyphenation
+.\" .hy enable hyphenation
+.\" .ad l left justify
+.\" .ad b justify to both left and right margins
+.\" .nf disable filling
+.\" .fi enable filling
+.\" .br insert line break
+.\" .sp insert n+1 empty lines
+.\" for manpage-specific macros, see man(7) and groff_man(7)
+.\" .SH section heading
+.\" .SS secondary section heading
+.\"
+.\"
+.\" To preview this page as plain text: nroff -man ipython.1
+.\"
+.SH NAME
+ipython \- Tools for Interactive Computing in Python.
+.SH SYNOPSIS
+.B ipython
+.RI [ options ] " files" ...
+
+.B ipython subcommand
+.RI [ options ] ...
+
+.SH DESCRIPTION
+An interactive Python shell with automatic history (input and output), dynamic
+object introspection, easier configuration, command completion, access to the
+system shell, integration with numerical and scientific computing tools,
+web notebook, Qt console, and more.
+
+For more information on how to use IPython, see 'ipython \-\-help',
+or 'ipython \-\-help\-all' for all available command\(hyline options.
+
+.SH "ENVIRONMENT VARIABLES"
+.sp
+.PP
+\fIIPYTHONDIR\fR
+.RS 4
+This is the location where IPython stores all its configuration files. The default
+is $HOME/.ipython if IPYTHONDIR is not defined.
+
+You can see the computed value of IPYTHONDIR with `ipython locate`.
+
+.SH FILES
+
+IPython uses various configuration files stored in profiles within IPYTHONDIR.
+To generate the default configuration files and start configuring IPython,
+do 'ipython profile create', and edit '*_config.py' files located in
+IPYTHONDIR/profile_default.
+
+.SH AUTHORS
+IPython is written by the IPython Development Team .
diff --git a/lab_4/lab3.ipynb b/lab_4/lab3.ipynb
new file mode 100644
index 0000000..7c9e25e
--- /dev/null
+++ b/lab_4/lab3.ipynb
@@ -0,0 +1,545 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Вариант задания: Прогнозирование цен на автомобили\n",
+ "### Бизнес-цели:\n",
+ "Повышение эффективности ценообразования на вторичном рынке автомобилей:\n",
+ "Цель: Разработать модель машинного обучения, которая позволит точно прогнозировать рыночную стоимость автомобилей на вторичном рынке.\n",
+ "Ключевые показатели успеха (KPI):\n",
+ "Точность прогнозирования цены (например, RMSE, MAE).\n",
+ "Сокращение времени на оценку стоимости автомобиля.\n",
+ "Увеличение количества продаж за счет более конкурентоспособных цен.\n",
+ "Оптимизация рекламных бюджетов для онлайн-площадок по продаже автомобилей:\n",
+ "Цель: Использовать прогнозы цен на автомобили для оптимизации таргетинга рекламы и повышения конверсии на онлайн-площадках.\n",
+ "Ключевые показатели успеха (KPI):\n",
+ "Увеличение CTR (Click-Through Rate) рекламных объявлений.\n",
+ "Повышение конверсии (процент пользователей, совершивших покупку после клика на рекламу).\n",
+ "Снижение стоимости привлечения клиента (CPA).\n",
+ "### Цели технического проекта:\n",
+ "Для бизнес-цели 1:\n",
+ "Сбор и подготовка данных:\n",
+ "Очистка данных от пропусков, выбросов и дубликатов.\n",
+ "Преобразование категориальных переменных в числовые.\n",
+ "Разделение данных на обучающую и тестовую выборки.\n",
+ "Разработка и обучение модели:\n",
+ "Исследование различных алгоритмов машинного обучения (линейная регрессия, деревья решений, случайный лес и т.д.).\n",
+ "Обучение моделей на обучающей выборке.\n",
+ "Оценка качества моделей на тестовой выборке с помощью метрик RMSE, MAE и др.\n",
+ "Развертывание модели:\n",
+ "Интеграция модели в существующую систему или разработка нового API для доступа к прогнозам.\n",
+ "Создание веб-интерфейса или мобильного приложения для удобного использования модели.\n",
+ "Для бизнес-цели 2:\n",
+ "Анализ данных о пользователях и поведении:\n",
+ "Анализ данных о просмотрах, кликах и покупках на онлайн-площадке.\n",
+ "Определение сегментов пользователей с разным уровнем интереса к покупке автомобилей.\n",
+ "Разработка рекомендательной системы:\n",
+ "Создание модели, которая будет рекомендовать пользователям автомобили, соответствующие их предпочтениям и бюджету.\n",
+ "Интеграция рекомендательной системы в рекламные кампании.\n",
+ "Оптимизация таргетинга рекламы:\n",
+ "Использование прогнозов цен на автомобили для более точного таргетинга рекламы на пользователей, готовых к покупке.\n",
+ "Тестирование различных стратегий таргетинга и оценка их эффективности."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Index(['ID', 'Price', 'Levy', 'Manufacturer', 'Model', 'Prod. year',\n",
+ " 'Category', 'Leather interior', 'Fuel type', 'Engine volume', 'Mileage',\n",
+ " 'Cylinders', 'Gear box type', 'Drive wheels', 'Doors', 'Wheel', 'Color',\n",
+ " 'Airbags'],\n",
+ " dtype='object')\n"
+ ]
+ }
+ ],
+ "source": [
+ "import pandas as pn\n",
+ "import matplotlib.pyplot as plt\n",
+ "import matplotlib\n",
+ "import matplotlib.ticker as ticker\n",
+ "df = pn.read_csv(\".//static//csv//car_price_prediction.csv\")\n",
+ "print(df.columns)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Разделим на 3 выборки\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Размер обучающей выборки: 12311\n",
+ "Размер контрольной выборки: 3078\n",
+ "Размер тестовой выборки: 3848\n"
+ ]
+ }
+ ],
+ "source": [
+ "from sklearn.model_selection import train_test_split\n",
+ "\n",
+ "# Разделение данных на обучающую и тестовую выборки (80% - обучение, 20% - тест)\n",
+ "train_data, test_data = train_test_split(df, test_size=0.2, random_state=42)\n",
+ "\n",
+ "# Разделение обучающей выборки на обучающую и контрольную (80% - обучение, 20% - контроль)\n",
+ "train_data, val_data = train_test_split(train_data, test_size=0.2, random_state=42)\n",
+ "\n",
+ "print(\"Размер обучающей выборки:\", len(train_data))\n",
+ "print(\"Размер контрольной выборки:\", len(val_data))\n",
+ "print(\"Размер тестовой выборки:\", len(test_data))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkQAAAHHCAYAAABeLEexAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAABI9UlEQVR4nO3deVxVdf7H8fdlVxRckK1IERVzNysHHbdCFJdyssylxMbSccAWW4yZTLQF08bMdHSaUmu0sWyxpmks3LKS1FTcM3Uw0wR3rmKiwPf3hz/ueL2gQsIFz+v5eJzHg3PO95zzOd+7vTnLvTZjjBEAAICFebi7AAAAAHcjEAEAAMsjEAEAAMsjEAEAAMsjEAEAAMsjEAEAAMsjEAEAAMsjEAEAAMsjEAGAm5w4cUK7d+9Wfn6+u0vBVWSM0bFjx7Rr1y53l4JSIBABQAU5d+6cJk+erNatW8vX11e1a9dW48aNtWzZMneXViVs3bpVixcvdoxnZGTo3//+t/sKusDJkyf1zDPPKDo6Wj4+Pqpbt66aNGminTt3urs0XCEvdxeAymHevHl64IEHHOO+vr664YYbFBcXp3HjxikkJMSN1QFVX15enuLi4vTtt9/qD3/4g5577jlVr15dnp6eateunbvLqxJOnjypkSNHKjQ0VHXr1tUjjzyi+Ph49e7d2611HT16VF26dNG+ffs0evRodezYUT4+PvL29laDBg3cWhuuHIEITiZOnKjIyEidOXNGX3/9tWbNmqXPPvtMW7duVfXq1d1dHlBlvfTSS1qzZo0+//xzde3a1d3lVEkxMTGOQZKaNGmihx56yM1VSU8++aQOHjyo9PR0NW/e3N3loIwIRHASHx+vm2++WZL04IMPqm7dupo6dao+/vhjDRo0yM3VAVVTfn6+pk2bpscff5ww9CstXrxY27dv1y+//KKWLVvKx8fHrfUcOnRIb731lmbPnk0YquK4hgiXdNttt0mSMjMzJUnHjh3TE088oZYtW6pGjRoKCAhQfHy8Nm3a5LLsmTNnlJKSoiZNmsjPz09hYWG66667tGfPHknS3r17ZbPZShwu/OBYuXKlbDab3n33Xf3pT39SaGio/P39dccdd+inn35y2faaNWvUs2dPBQYGqnr16urSpYu++eabYvexa9euxW4/JSXFpe38+fPVrl07VatWTXXq1NHAgQOL3f6l9u1ChYWFmjZtmpo3by4/Pz+FhIRo5MiROn78uFO7Bg0aqE+fPi7bSUpKcllncbVPmTLFpU+l86dxxo8fr0aNGsnX11cRERF66qmnlJeXV2xfXahr165q0aKFy/SXX35ZNptNe/fudZp+4sQJPfroo4qIiJCvr68aNWqkl156SYWFhY42Rf328ssvu6y3RYsWxT4n3n///RJrHDZs2BWdsmjQoIHj8fHw8FBoaKjuvfde7du377LLStJf//pXNW/eXL6+vgoPD1diYqJOnDjhmL9z504dP35cNWvWVJcuXVS9enUFBgaqT58+2rp1q6PdihUrZLPZ9NFHH7ls45133pHNZlN6erqj5mHDhjm1KeqTlStXOqZ99dVXuueee3TDDTc4HuPHHntMv/zyi9OyKSkpLs+lBQsWqE2bNvLz81PdunU1aNAglz4ZNmyYatSo4TTt/fffd6lDkmrUqOFSs3Rlr6uuXbs6Hv9mzZqpXbt22rRpU7Gvq+Jc/DoPCgpS7969nfpfOv/6SUpKKnE98+bNc3p+r1u3ToWFhTp79qxuvvnmS/aVJC1fvlydOnWSv7+/atWqpTvvvFM7duxwalP0WHz//fcaMGCAAgICHKcIz5w541Lvha/3/Px89erVS3Xq1NH27dud2l7p+5dVcYQIl1QUXurWrStJ+u9//6vFixfrnnvuUWRkpLKzs/W3v/1NXbp00fbt2xUeHi5JKigoUJ8+fbRs2TINHDhQjzzyiE6ePKm0tDRt3bpVUVFRjm0MGjRIvXr1ctpucnJysfW88MILstlsGjt2rA4dOqRp06YpNjZWGRkZqlatmqTzbzjx8fFq166dxo8fLw8PD82dO1e33XabvvrqK916660u673++uuVmpoqSTp16pRGjRpV7LbHjRunAQMG6MEHH9Thw4f12muvqXPnztq4caNq1arlssyIESPUqVMnSdKHH37o8kE3cuRIx/VbDz/8sDIzMzVjxgxt3LhR33zzjby9vYvth9I4ceKEY98uVFhYqDvuuENff/21RowYoRtvvFFbtmzRK6+8oh9++MHp4tVf6/Tp0+rSpYsOHDigkSNH6oYbbtDq1auVnJysgwcPatq0aVdtW2XVqVMnjRgxQoWFhdq6daumTZumn3/+WV999dUll0tJSdGECRMUGxurUaNGaefOnZo1a5bWrVvneAyP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EcA3bdqkJ554wtFmy5Yt+uGHH/TWW29p6NChjulpaWkl9kNsbKwCAwP17LPPlljv1fqywdK+rqTzd/QdOnSo2LtAL6d27dpOj3HXrl0VHh6uuXPnOt3Icf311zu1q1GjhoYMGVLsKcYLH9ui081FLuyrC58rF/v+++8VFBTk8hzftWuXY/2StHv3bhUWFrr0f/fu3TVr1iydOXNGixcv1ogRIxx3HEpl62cr4hoilIqnp6eMMU7TFi1apAMHDjhN69+/v44cOeLyX60kl+VL4+2339bJkycd4++//74OHjyo+Ph4SVK7du0UFRWll19+WadOnXJZ/vDhwy61e3p6FntL+4XuuusueXp6asKECS71G2Mcd5pI5297/eCDD3Trrbde8j+vAQMGqKCgQM8995zLvPz8/F91TUx6ero+/vhjTZo0qcSwM2DAAB04cEB///vfXeb98ssvys3NLfP2i9tWenq6Pv/8c5d5J06cuKq/5VVYWCgPD49fHfKKbku/1FcQxMbGysfHR9OnT3d6Xrz55pvKyclxfINyvXr1dPPNN+utt95yOm21Z88effLJJ4qPj3f6zz0oKEjx8fGaP3++FixYoJ49exZ7V5eHh4datGih2NhYxcbGunzjddE6L6zNGKNXX331kvvepk0bhYSE6O9//7tOnz7tmP7VV1/pu+++u+zr5UqV5nUlnb9e7IUXXtBjjz12yaOvV+pKHmPpf0eeizu60rZtW4WGhmr27NlO67m4r8LCwtSmTRu99dZbTq/trVu36osvvnC501Y6fwnDhV577TVJcrzfFenQoYM8PT3l7++v2bNna9WqVU6v69L2s1VxhAil0qdPH02cOFEPPPCAOnTooC1btmjBggVO/x1L5w/5v/322xozZozWrl2rTp06KTc3V0uXLtUf//hHl4v+rlSdOnX029/+Vg888ICys7M1bdo0NWrUyHE6xcPDQ2+88Ybi4+PVvHlzPfDAA7ruuut04MABrVixQgEBAfrXv/6l3NxczZw5U9OnT1eTJk2cvi+lKEht3rxZ6enpiomJUVRUlJ5//nklJydr79696tevn2rWrKnMzEx99NFHGjFihJ544gktXbpU48aN0+bNm/Wvf/3rkvvSpUsXjRw5UqmpqcrIyFBcXJy8vb21a9cuLVq0SK+++qruvvvuMvXTF198oe7du1/yiMz999+v9957T3/4wx+0YsUKdezYUQUFBfr+++/13nvv6fPPP7/skbNTp05pyZIlTtOK/gP+8ssv5e3treuuu05PPvmkPvnkE/Xp00fDhg1Tu3btlJubqy1btuj999/X3r17y3wbd0ZGhmrUqKH8/HytX79eb7/9tu68885iP7wu5b///a/mz58v6fzF6DNmzFBAQMAlL6yuV6+ekpOTNWHCBPXs2VN33HGHdu7cqb/+9a+65ZZbnC6Cnjx5suLi4hQTE6MHH3zQcdu9n5+fXnjhBZd1Dx061PH4Fxear0TTpk0VFRWlJ554QgcOHFBAQIA++OADl2uJLubt7a2XXnpJw4YNU8eOHZWQkKBjx47p1Vdf1XXXXedyu3tBQYHT8yAjI0PS+VM5F174X1BQoAMHDmjt2rW69dZbr/h1VWTDhg0KCgoq8dTr5WRnZzse4yNHjuhvf/ubvLy8XALevn37tGTJEscpsxdeeEH169dX27ZtXY5Se3l5afLkyRo6dKg6deqkIUOGOE7HXX/99U59NWXKFMXHxysmJkbDhw933HYfGBhY7BGvzMxM3XHHHerZs6fS09M1f/58DR48WK1bty5xH3v06KH77rtPTz31lPr27auwsLBS97NlVeQtbai8im4dXbdu3SXbnTlzxjz++OMmLCzMVKtWzXTs2NGkp6cXe0vr6dOnzZ///GcTGRlpvL29TWhoqLn77rvNnj17jDFlu8X6n//8p0lOTjbBwcGmWrVqpnfv3k63DhfZuHGjueuuu0zdunWNr6+vqV+/vhkwYIBZtmyZ07YvN1x8K/YHH3xgfvvb3xp/f3/j7+9vmjZtahITE83OnTuNMcaMHj3adO7c2SxZssSlpotvuy/y+uuvm3bt2plq1aqZmjVrmpYtW5qnnnrK/Pzzz442pb3t3mazmfXr1ztNL+4xOnv2rHnppZdM8+bNja+vr6ldu7Zp166dmTBhgsnJyXHZ3sXru1z/zZ0719H+5MmTJjk52TRq1Mj4+PiYoKAg06FDB/Pyyy+bs2fPGmPK9pwoGry8vEz9+vXNww8/bI4fP26MKd1t9xeuKygoyMTFxZn09PTLLmvM+dvsmzZtary9vU1ISIgZNWqUo4YLLVu2zHTs2NFUq1bNBAQEmN69e5stW7YUu868vDxTu3ZtExgYaH755ZcrqqO42+63b99uYmNjTY0aNUxQUJB56KGHzKZNm1wen+KenwsXLjRt2rRxPDfuvfdes3fvXqc2CQkJV/RaunC4+Hl4udeVMf97vr3yyitOy5b0urrYxc/XWrVqmY4dO5rPPvvMqd2FbWw2mwkNDTV33XWX2bFjhzHG9bb7Iu+9955p27at8fX1NXXq1DGDBg0q9r1p6dKlTs+Bvn37mu3btxe7T9u3bzd33323qVmzpqldu7ZJSkpyeS7ooq/ZMMaYI0eOmHr16pnf/e53TtOvpJ+tzGbMrzh/AVSQlStXqlu3blq0aFGZj5pcaO/evYqMjFRmZmaJ10OkpKRo7969mjdv3q/enhU1aNBAKSkpxX4zMS4vPz9f4eHh6tu3r8s1e1XZvHnzNG/ePJdvscb/FH3Z5+HDh6/aF2Di8riGCAAqocWLF+vw4cNOF0MDKD9cQwRLKrpr5FIXPbdq1crxUyQovS5duji+0BNXbs2aNdq8ebOee+45tW3bVl26dHF3SVfVddddV+zP5wDuRiCCJQUFBTkurizJXXfdVUHVXJveeustd5dQJc2aNUvz589XmzZtrsnTtd27d7/s934B7sA1RAAAwPK4hggAAFgegQgAAFge1xBdgcLCQv3888+qWbNmuf/EAQAAuDqMMTp58qTCw8Odfqi8OASiK/Dzzz9f1R+6BAAAFeenn37S9ddff8k2BKIrULNmTUnnOzQgIMDN1QAAgCtht9sVERHh+By/FALRFSg6TRYQEEAgAgCgirmSy124qBoAAFgegQgAAFgegQgAAFgegQgAAFgegQgAAFgegQgAAFgegQgAAFgegQgAAFgegQgAAFgegQgAAFgegQgAAFgegQgAAFgegQgAAFgegQgAAFgegQgAAFgegQgAAFgegQgAAFgegQgAAFgegQgAAFgegQgAAFgegQgAAFgegQgAAFgegQgAAFgegQgAAFgegQgAAFgegQgAAFgegQgAAFgegQgAAFgegQgAAFgegQgAAFgegQgAAFieWwPRqlWr1LdvX4WHh8tms2nx4sVO8202W7HDlClTHG0aNGjgMn/SpElO69m8ebM6deokPz8/RUREaPLkyRWxewAAoIpwayDKzc1V69atNXPmzGLnHzx40GmYM2eObDab+vfv79Ru4sSJTu1Gjx7tmGe32xUXF6f69etr/fr1mjJlilJSUvT666+X674BAICqw8ud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jR49WmPHjr3iOu12uwIDA5WTk3PZU3YAAKByKM3nt1sDUVVBIAIAoOopzed3pb6GCAAAoCIQiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOURiAAAgOWVKRA1bNhQR48edZl+4sQJNWzY8FcXBQAAUJHKFIj27t2rgoICl+l5eXk6cODAry4KAACgInmVpvEnn3zi+Pvzzz9XYGCgY7ygoEDLli1TgwYNrlpxAAAAFaFUgahfv36SJJvNpoSEBKd53t7eatCggf7yl79cteIAAAAqQqkCUWFhoSQpMjJS69atU1BQULkUBQAAUJFKFYiKZGZmXu06AAAA3KZMgUiSli1bpmXLlunQoUOOI0dF5syZ86sLAwAAqChlCkQTJkzQxIkTdfPNNyssLEw2m+1q1wUAAFBhyhSIZs+erXnz5un++++/2vUAAABUuDJ9D9HZs2fVoUOHX73xVatWqW/fvgoPD5fNZtPixYud5htj9OyzzyosLEzVqlVTbGysdu3a5dTm2LFjGjJkiAICAlSrVi0NHz5cp06dcmqzefNmderUSX5+foqIiNDkyZN/de0AAODaUaZA9OCDD+qdd9751RvPzc1V69atNXPmzGLnT548WdOnT9fs2bO1Zs0a+fv7q0ePHjpz5oyjzZAhQ7Rt2zalpaXp008/1apVqzRixAjHfLvdrri4ONWvX1/r16/XlClTlJKSotdff/1X1w8AAK4NNmOMKe1CjzzyiN5++221atVKrVq1kre3t9P8qVOnlr4Qm00fffSR47uOjDEKDw/X448/rieeeEKSlJOTo5CQEM2bN08DBw7Ujh071KxZM61bt04333yzJGnJkiXq1auX9u/fr/DwcM2aNUt//vOflZWVJR8fH0nS008/rcWLF+v777+/otrsdrsCAwOVk5OjgICAUu8bAACoeKX5/C7TEaLNmzerTZs28vDw0NatW7Vx40bHkJGRUZZVusjMzFRWVpZiY2Md0wIDA9W+fXulp6dLktLT01WrVi1HGJKk2NhYeXh4aM2a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",
+ "text/plain": [
+ "