diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c285830 --- /dev/null +++ b/.gitignore @@ -0,0 +1,72 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ +*.egg +*.egg-info/ +dist/ +build/ +Lib/ +*.whl + +# PyInstaller +*.manifest +*.spec + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +*.cover +*.py,cover +.cache +nosetests.xml +coverage.xml +*.hypothesis/ +pytest_cache/ +cover/ + +# Jupyter Notebook +.ipynb_checkpoints +*.ipynb + +# Pyre type checker +.pyre/ + +# Environments +.env +.env.* +*.env + +# Editor configurations +.idea/ +.vscode/ +*.sublime-workspace +*.sublime-project + +# macOS +.DS_Store + +# Windows +Thumbs.db +ehthumbs.db +Desktop.ini + +# Logs and databases +*.log +*.sqlite3 + +# Other +*.lock diff --git a/QuickMail.py b/QuickMail.py new file mode 100644 index 0000000..9d70146 --- /dev/null +++ b/QuickMail.py @@ -0,0 +1,106 @@ +import smtplib +import pandas as pd +from tkinter import Tk, Label, Entry, Button, filedialog, messagebox, ttk + +# Send emails and update status +def send_bulk_emails(): + sender_email = sender_email_entry.get() + sender_password = sender_password_entry.get() + smtp_server = smtp_server_entry.get() + smtp_port = smtp_port_entry.get() + + if not sender_email or not sender_password or not smtp_server or not smtp_port: + messagebox.showerror("Error", "SMTP configuration is required!") + return + + try: + with smtplib.SMTP(smtp_server, int(smtp_port)) as server: + server.starttls() + server.login(sender_email, sender_password) + + for index, row in email_data.iterrows(): + try: + message = f"Subject: {row['Subject']}\n\n{row['Body']}" + server.sendmail(sender_email, row['Email'], message) + email_data.at[index, 'Status'] = 'Done' + except Exception as e: + email_data.at[index, 'Status'] = f"Failed: {e}" + + update_table_status(index, email_data.at[index, 'Status']) + + messagebox.showinfo("Success", "All emails processed!") + except Exception as e: + messagebox.showerror("Error", f"SMTP Error: {e}") + +# Update table status +def update_table_status(index, status): + tree.item(tree.get_children()[index], values=( + email_data.at[index, 'Email'], + email_data.at[index, 'Subject'], + email_data.at[index, 'Body'], + status + )) + +# Load Excel and display data +def load_excel(): + global email_data + file_path = filedialog.askopenfilename(filetypes=[("Excel files", "*.xlsx *.xls")]) + if not file_path: + return + + try: + email_data = pd.read_excel(file_path) + if not {'Email', 'Subject', 'Body'}.issubset(email_data.columns): + messagebox.showerror("Error", "Excel must contain Email, Subject, and Body columns!") + return + + email_data['Status'] = 'Pending' + populate_table() + except Exception as e: + messagebox.showerror("Error", f"Error loading Excel file: {e}") + +# Populate table with email data +def populate_table(): + tree.delete(*tree.get_children()) + for index, row in email_data.iterrows(): + tree.insert("", "end", values=(row['Email'], row['Subject'], row['Body'], row['Status'])) + +# GUI setup +root = Tk() +root.title("Bulk Email Sender") +root.geometry("800x600") + +# SMTP configuration +Label(root, text="Sender Email:").grid(row=0, column=0, padx=10, pady=5, sticky="w") +sender_email_entry = Entry(root, width=30) +sender_email_entry.grid(row=0, column=1, padx=10, pady=5) + +Label(root, text="Sender Password:").grid(row=1, column=0, padx=10, pady=5, sticky="w") +sender_password_entry = Entry(root, show="*", width=30) +sender_password_entry.grid(row=1, column=1, padx=10, pady=5) + +Label(root, text="SMTP Server:").grid(row=2, column=0, padx=10, pady=5, sticky="w") +smtp_server_entry = Entry(root, width=30) +smtp_server_entry.grid(row=2, column=1, padx=10, pady=5) +smtp_server_entry.insert(0, "smtp.gmail.com") + +Label(root, text="SMTP Port:").grid(row=3, column=0, padx=10, pady=5, sticky="w") +smtp_port_entry = Entry(root, width=30) +smtp_port_entry.grid(row=3, column=1, padx=10, pady=5) +smtp_port_entry.insert(0, "587") + +# Load Excel button +Button(root, text="Load Excel", command=load_excel).grid(row=4, column=0, columnspan=2, pady=10) + +# Email table +columns = ("Email", "Subject", "Body", "Status") +tree = ttk.Treeview(root, columns=columns, show="headings", height=15) +for col in columns: + tree.heading(col, text=col) + tree.column(col, width=200, anchor="w") +tree.grid(row=5, column=0, columnspan=2, padx=10, pady=10) + +# Send Emails button +Button(root, text="Send Emails", command=send_bulk_emails).grid(row=6, column=0, columnspan=2, pady=10) + +root.mainloop() diff --git a/README.md b/README.md new file mode 100644 index 0000000..c3072a8 --- /dev/null +++ b/README.md @@ -0,0 +1,34 @@ +# QuickMail utility + +Bulk mail sending application + +![Screenshot](./assets/img/screenshot.png "Screenshot") + + +## setup + +```python +git clone https://github.com/hitswa/QuickMail.git +``` + +```python +cd QuickMail +``` + +```python +python -m venv . +``` + +```python +python -m pip install -r requirements.txt +``` + +```python +python QuickMail.py +``` + +## Compile code to executable .exe file + +```python +pyinstaller QuickMail.py +``` \ No newline at end of file diff --git a/Scripts/Activate.ps1 b/Scripts/Activate.ps1 new file mode 100644 index 0000000..0672d3c --- /dev/null +++ b/Scripts/Activate.ps1 @@ -0,0 +1,547 @@ +<# +.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 + +$env:VIRTUAL_ENV_PROMPT = $Prompt + +if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) { + + Write-Verbose "Setting prompt to '$Prompt'" + + # Set the prompt to include the env name + # Make sure _OLD_VIRTUAL_PROMPT is global + function global:_OLD_VIRTUAL_PROMPT { "" } + Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT + New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt + + function global:prompt { + Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) " + _OLD_VIRTUAL_PROMPT + } +} + +# Clear PYTHONHOME +if (Test-Path -Path Env:PYTHONHOME) { + Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME + Remove-Item -Path Env:PYTHONHOME +} + +# Add the venv to the PATH +Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH +$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH" + +# SIG # Begin signature block +# MII3ewYJKoZIhvcNAQcCoII3bDCCN2gCAQExDzANBglghkgBZQMEAgEFADB5Bgor +# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG +# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBALKwKRFIhr2RY +# IW/WJLd9pc8a9sj/IoThKU92fTfKsKCCG9IwggXMMIIDtKADAgECAhBUmNLR1FsZ +# lUgTecgRwIeZMA0GCSqGSIb3DQEBDAUAMHcxCzAJBgNVBAYTAlVTMR4wHAYDVQQK +# ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xSDBGBgNVBAMTP01pY3Jvc29mdCBJZGVu +# dGl0eSBWZXJpZmljYXRpb24gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAy +# MDAeFw0yMDA0MTYxODM2MTZaFw00NTA0MTYxODQ0NDBaMHcxCzAJBgNVBAYTAlVT +# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xSDBGBgNVBAMTP01pY3Jv +# c29mdCBJZGVudGl0eSBWZXJpZmljYXRpb24gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRo +# b3JpdHkgMjAyMDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALORKgeD +# Bmf9np3gx8C3pOZCBH8Ppttf+9Va10Wg+3cL8IDzpm1aTXlT2KCGhFdFIMeiVPvH +# or+Kx24186IVxC9O40qFlkkN/76Z2BT2vCcH7kKbK/ULkgbk/WkTZaiRcvKYhOuD +# PQ7k13ESSCHLDe32R0m3m/nJxxe2hE//uKya13NnSYXjhr03QNAlhtTetcJtYmrV +# qXi8LW9J+eVsFBT9FMfTZRY33stuvF4pjf1imxUs1gXmuYkyM6Nix9fWUmcIxC70 +# ViueC4fM7Ke0pqrrBc0ZV6U6CwQnHJFnni1iLS8evtrAIMsEGcoz+4m+mOJyoHI1 +# vnnhnINv5G0Xb5DzPQCGdTiO0OBJmrvb0/gwytVXiGhNctO/bX9x2P29Da6SZEi3 +# W295JrXNm5UhhNHvDzI9e1eM80UHTHzgXhgONXaLbZ7LNnSrBfjgc10yVpRnlyUK +# xjU9lJfnwUSLgP3B+PR0GeUw9gb7IVc+BhyLaxWGJ0l7gpPKWeh1R+g/OPTHU3mg +# trTiXFHvvV84wRPmeAyVWi7FQFkozA8kwOy6CXcjmTimthzax7ogttc32H83rwjj +# O3HbbnMbfZlysOSGM1l0tRYAe1BtxoYT2v3EOYI9JACaYNq6lMAFUSw0rFCZE4e7 +# swWAsk0wAly4JoNdtGNz764jlU9gKL431VulAgMBAAGjVDBSMA4GA1UdDwEB/wQE +# AwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTIftJqhSobyhmYBAcnz1AQ +# T2ioojAQBgkrBgEEAYI3FQEEAwIBADANBgkqhkiG9w0BAQwFAAOCAgEAr2rd5hnn +# LZRDGU7L6VCVZKUDkQKL4jaAOxWiUsIWGbZqWl10QzD0m/9gdAmxIR6QFm3FJI9c +# Zohj9E/MffISTEAQiwGf2qnIrvKVG8+dBetJPnSgaFvlVixlHIJ+U9pW2UYXeZJF +# xBA2CFIpF8svpvJ+1Gkkih6PsHMNzBxKq7Kq7aeRYwFkIqgyuH4yKLNncy2RtNwx +# AQv3Rwqm8ddK7VZgxCwIo3tAsLx0J1KH1r6I3TeKiW5niB31yV2g/rarOoDXGpc8 +# FzYiQR6sTdWD5jw4vU8w6VSp07YEwzJ2YbuwGMUrGLPAgNW3lbBeUU0i/OxYqujY +# lLSlLu2S3ucYfCFX3VVj979tzR/SpncocMfiWzpbCNJbTsgAlrPhgzavhgplXHT2 +# 6ux6anSg8Evu75SjrFDyh+3XOjCDyft9V77l4/hByuVkrrOj7FjshZrM77nq81YY +# uVxzmq/FdxeDWds3GhhyVKVB0rYjdaNDmuV3fJZ5t0GNv+zcgKCf0Xd1WF81E+Al +# GmcLfc4l+gcK5GEh2NQc5QfGNpn0ltDGFf5Ozdeui53bFv0ExpK91IjmqaOqu/dk +# ODtfzAzQNb50GQOmxapMomE2gj4d8yu8l13bS3g7LfU772Aj6PXsCyM2la+YZr9T +# 03u4aUoqlmZpxJTG9F9urJh4iIAGXKKy7aIwggb+MIIE5qADAgECAhMzAAE6wJsA +# snAfNTDUAAAAATrAMA0GCSqGSIb3DQEBDAUAMFoxCzAJBgNVBAYTAlVTMR4wHAYD +# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKzApBgNVBAMTIk1pY3Jvc29mdCBJ +# RCBWZXJpZmllZCBDUyBFT0MgQ0EgMDIwHhcNMjQxMjAzMDk0MTAzWhcNMjQxMjA2 +# MDk0MTAzWjB8MQswCQYDVQQGEwJVUzEPMA0GA1UECBMGT3JlZ29uMRIwEAYDVQQH +# EwlCZWF2ZXJ0b24xIzAhBgNVBAoTGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9u +# MSMwIQYDVQQDExpQeXRob24gU29mdHdhcmUgRm91bmRhdGlvbjCCAaIwDQYJKoZI +# hvcNAQEBBQADggGPADCCAYoCggGBAOb6O8bNcUcKFE6vSWXiMf3/EALRFfo4QQDq +# m/XTiKG7GeHjRzVGTGhooTagMmKc4m52JNEPsQxCwXYCcTz9bRt/I+CYfHcqIAKL +# Ga46L/7a7T6qFF0tcAX15uMED8xwApWO8GP4wYxGS/a0GD3OGpl2qsZmw0lKFm+f +# rD8ip4F4z6KrnmsVlC0qMdCndPH+2NAstO7k+ArRhqDvsu5Jt39O2M7LuaX6loEp +# 43CWmkr7i+cLlkNbRx5hBrN/8MJQDhnprS2a6y+3PGLNDDUvN9Yb9UMZFwu5xcjM +# AP8VqdQYmgdz7PZDlIncayelUgxG1Zdx6CWqngNOKpc4lkTKzxf3Q8m+awDXCw7L +# 18jWlFL1Jki2khRmU4HhPzKf2WcgQCHtUPekmvnNUeNFT3TZsxXyhXuDTmB+BOV7 +# TpUO594HbMIhdktkdZ2mA/mcKPN4NnYJy55pUmwQIOuqPY1dlR+nv2ko466xxd8x +# pUO3R/pAse5WXaNx6fy9jj0ChNuNmQIDAQABo4ICGTCCAhUwDAYDVR0TAQH/BAIw +# ADAOBgNVHQ8BAf8EBAMCB4AwPAYDVR0lBDUwMwYKKwYBBAGCN2EBAAYIKwYBBQUH +# AwMGGysGAQQBgjdhgqKNuwqmkohkgZH0oEWCk/3hbzAdBgNVHQ4EFgQUJrRvpIJJ +# B/SCh4T20kb8yCbcj7MwHwYDVR0jBBgwFoAUZZ9RzoVofy+KRYiq3acxux4NAF4w +# ZwYDVR0fBGAwXjBcoFqgWIZWaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9w +# cy9jcmwvTWljcm9zb2Z0JTIwSUQlMjBWZXJpZmllZCUyMENTJTIwRU9DJTIwQ0El +# MjAwMi5jcmwwgaUGCCsGAQUFBwEBBIGYMIGVMGQGCCsGAQUFBzAChlhodHRwOi8v +# d3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMElEJTIw +# VmVyaWZpZWQlMjBDUyUyMEVPQyUyMENBJTIwMDIuY3J0MC0GCCsGAQUFBzABhiFo +# dHRwOi8vb25lb2NzcC5taWNyb3NvZnQuY29tL29jc3AwZgYDVR0gBF8wXTBRBgwr +# BgEEAYI3TIN9AQEwQTA/BggrBgEFBQcCARYzaHR0cDovL3d3dy5taWNyb3NvZnQu +# Y29tL3BraW9wcy9Eb2NzL1JlcG9zaXRvcnkuaHRtMAgGBmeBDAEEATANBgkqhkiG +# 9w0BAQwFAAOCAgEAvsdWH8gSPoZt5yblw1MghytJmjs6zeME3/iAYXPzcwwXfB08 +# RLMesfF0svS4P1GEdP+CcIIqFl7/48ECI4eregPZjypMWhqPQQWuT8+gMDiWRtYj +# KGEhu+faY+U8Bqv/OrRRS6MHNAoJAGH3t/oxeLXTaeW1URtswm+gvEx+K9KFpHP9 +# j1mF0wh4wuVvUJAGYc4KpcorLk7P9vQTLCDmFZi08HMcRYQURHEpskWiSS4czpfv +# ImpRPD5RbIqkQnK7M5wX8X+cI/0hCUb0TjIuxBo92FU726ivQ2vqpzuuRo2Uw1wR +# hzerJI2Bilj66tBzPNn02EZt978Ju/f6+N7b0tFD0kSz1DwTYAR3eK9CwRxIXCGf +# 2rrHz/T9ATSlF71xw2g0R5HBPaJKaySj7PXIU5Nq9sEVCuUSJmNmiZRdBkF76LKH +# mg3cCM5QbgpKfnc46Hi6I7D9q8F1XF0IJwRgP/fwDquWnkTHOoWC9nA0+eLedlAh +# oKYQGEKzAdNLdXdWyUNTjnUKhEXLQgPyDPP9ZLHK+jjQwc6ptwPoX3uuSHtrNmnu +# EIFibcHCp6JVIIu5B94xKS99hGXhaxbuaOMyCvTEVmoLMxAWpF1lVyUUTgj9Lr4W +# /qdqUE+7a1QTDLLswxY8djZCJejn0pDLoKoNfjaeIaRKXXrRs2BND+qKDaowggda +# MIIFQqADAgECAhMzAAAABft6XDITYd9dAAAAAAAFMA0GCSqGSIb3DQEBDAUAMGMx +# CzAJBgNVBAYTAlVTMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xNDAy +# BgNVBAMTK01pY3Jvc29mdCBJRCBWZXJpZmllZCBDb2RlIFNpZ25pbmcgUENBIDIw +# MjEwHhcNMjEwNDEzMTczMTUzWhcNMjYwNDEzMTczMTUzWjBaMQswCQYDVQQGEwJV +# UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSswKQYDVQQDEyJNaWNy +# b3NvZnQgSUQgVmVyaWZpZWQgQ1MgRU9DIENBIDAyMIICIjANBgkqhkiG9w0BAQEF +# AAOCAg8AMIICCgKCAgEA0hqZfD8ykKTA6CDbWvshmBpDoBf7Lv132RVuSqVwQO3a +# ALLkuRnnTIoRmMGo0fIMQrtwR6UHB06xdqOkAfqB6exubXTHu44+duHUCdE4ngjE +# LBQyluMuSOnHaEdveIbt31OhMEX/4nQkph4+Ah0eR4H2sTRrVKmKrlOoQlhia73Q +# g2dHoitcX1uT1vW3Knpt9Mt76H7ZHbLNspMZLkWBabKMl6BdaWZXYpPGdS+qY80g +# DaNCvFq0d10UMu7xHesIqXpTDT3Q3AeOxSylSTc/74P3og9j3OuemEFauFzL55t1 +# MvpadEhQmD8uFMxFv/iZOjwvcdY1zhanVLLyplz13/NzSoU3QjhPdqAGhRIwh/YD +# zo3jCdVJgWQRrW83P3qWFFkxNiME2iO4IuYgj7RwseGwv7I9cxOyaHihKMdT9Neo +# SjpSNzVnKKGcYMtOdMtKFqoV7Cim2m84GmIYZTBorR/Po9iwlasTYKFpGZqdWKyY +# nJO2FV8oMmWkIK1iagLLgEt6ZaR0rk/1jUYssyTiRqWr84Qs3XL/V5KUBEtUEQfQ +# /4RtnI09uFFUIGJZV9mD/xOUksWodGrCQSem6Hy261xMJAHqTqMuDKgwi8xk/mfl +# r7yhXPL73SOULmu1Aqu4I7Gpe6QwNW2TtQBxM3vtSTmdPW6rK5y0gED51RjsyK0C +# AwEAAaOCAg4wggIKMA4GA1UdDwEB/wQEAwIBhjAQBgkrBgEEAYI3FQEEAwIBADAd +# BgNVHQ4EFgQUZZ9RzoVofy+KRYiq3acxux4NAF4wVAYDVR0gBE0wSzBJBgRVHSAA +# MEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMv +# RG9jcy9SZXBvc2l0b3J5Lmh0bTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTAS +# BgNVHRMBAf8ECDAGAQH/AgEAMB8GA1UdIwQYMBaAFNlBKbAPD2Ns72nX9c0pnqRI +# ajDmMHAGA1UdHwRpMGcwZaBjoGGGX2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9w +# a2lvcHMvY3JsL01pY3Jvc29mdCUyMElEJTIwVmVyaWZpZWQlMjBDb2RlJTIwU2ln +# bmluZyUyMFBDQSUyMDIwMjEuY3JsMIGuBggrBgEFBQcBAQSBoTCBnjBtBggrBgEF +# BQcwAoZhaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNy +# b3NvZnQlMjBJRCUyMFZlcmlmaWVkJTIwQ29kZSUyMFNpZ25pbmclMjBQQ0ElMjAy +# MDIxLmNydDAtBggrBgEFBQcwAYYhaHR0cDovL29uZW9jc3AubWljcm9zb2Z0LmNv +# bS9vY3NwMA0GCSqGSIb3DQEBDAUAA4ICAQBFSWDUd08X4g5HzvVfrB1SiV8pk6XP +# HT9jPkCmvU/uvBzmZRAjYk2gKYR3pXoStRJaJ/lhjC5Dq/2R7P1YRZHCDYyK0zvS +# RMdE6YQtgGjmsdhzD0nCS6hVVcgfmNQscPJ1WHxbvG5EQgYQ0ZED1FN0MOPQzWe1 +# zbH5Va0dSxtnodBVRjnyDYEm7sNEcvJHTG3eXzAyd00E5KDCsEl4z5O0mvXqwaH2 +# PS0200E6P4WqLwgs/NmUu5+Aa8Lw/2En2VkIW7Pkir4Un1jG6+tj/ehuqgFyUPPC +# h6kbnvk48bisi/zPjAVkj7qErr7fSYICCzJ4s4YUNVVHgdoFn2xbW7ZfBT3QA9zf +# hq9u4ExXbrVD5rxXSTFEUg2gzQq9JHxsdHyMfcCKLFQOXODSzcYeLpCd+r6GcoDB +# ToyPdKccjC6mAq6+/hiMDnpvKUIHpyYEzWUeattyKXtMf+QrJeQ+ny5jBL+xqdOO +# PEz3dg7qn8/oprUrUbGLBv9fWm18fWXdAv1PCtLL/acMLtHoyeSVMKQYqDHb3Qm0 +# uQ+NQ0YE4kUxSQa+W/cCzYAI32uN0nb9M4Mr1pj4bJZidNkM4JyYqezohILxYkgH +# bboJQISrQWrm5RYdyhKBpptJ9JJn0Z63LjdnzlOUxjlsAbQir2Wmz/OJE703BbHm +# QZRwzPx1vu7S5zCCB54wggWGoAMCAQICEzMAAAAHh6M0o3uljhwAAAAAAAcwDQYJ +# KoZIhvcNAQEMBQAwdzELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1pY3Jvc29mdCBD +# b3Jwb3JhdGlvbjFIMEYGA1UEAxM/TWljcm9zb2Z0IElkZW50aXR5IFZlcmlmaWNh +# dGlvbiBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDIwMB4XDTIxMDQwMTIw +# MDUyMFoXDTM2MDQwMTIwMTUyMFowYzELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFU1p +# Y3Jvc29mdCBDb3Jwb3JhdGlvbjE0MDIGA1UEAxMrTWljcm9zb2Z0IElEIFZlcmlm +# aWVkIENvZGUgU2lnbmluZyBQQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +# ADCCAgoCggIBALLwwK8ZiCji3VR6TElsaQhVCbRS/3pK+MHrJSj3Zxd3KU3rlfL3 +# qrZilYKJNqztA9OQacr1AwoNcHbKBLbsQAhBnIB34zxf52bDpIO3NJlfIaTE/xrw +# eLoQ71lzCHkD7A4As1Bs076Iu+mA6cQzsYYH/Cbl1icwQ6C65rU4V9NQhNUwgrx9 +# rGQ//h890Q8JdjLLw0nV+ayQ2Fbkd242o9kH82RZsH3HEyqjAB5a8+Ae2nPIPc8s +# ZU6ZE7iRrRZywRmrKDp5+TcmJX9MRff241UaOBs4NmHOyke8oU1TYrkxh+YeHgfW +# o5tTgkoSMoayqoDpHOLJs+qG8Tvh8SnifW2Jj3+ii11TS8/FGngEaNAWrbyfNrC6 +# 9oKpRQXY9bGH6jn9NEJv9weFxhTwyvx9OJLXmRGbAUXN1U9nf4lXezky6Uh/cgjk +# Vd6CGUAf0K+Jw+GE/5VpIVbcNr9rNE50Sbmy/4RTCEGvOq3GhjITbCa4crCzTTHg +# YYjHs1NbOc6brH+eKpWLtr+bGecy9CrwQyx7S/BfYJ+ozst7+yZtG2wR461uckFu +# 0t+gCwLdN0A6cFtSRtR8bvxVFyWwTtgMMFRuBa3vmUOTnfKLsLefRaQcVTgRnzeL +# zdpt32cdYKp+dhr2ogc+qM6K4CBI5/j4VFyC4QFeUP2YAidLtvpXRRo3AgMBAAGj +# ggI1MIICMTAOBgNVHQ8BAf8EBAMCAYYwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0O +# BBYEFNlBKbAPD2Ns72nX9c0pnqRIajDmMFQGA1UdIARNMEswSQYEVR0gADBBMD8G +# CCsGAQUFBwIBFjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL0RvY3Mv +# UmVwb3NpdG9yeS5odG0wGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwDwYDVR0T +# AQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTIftJqhSobyhmYBAcnz1AQT2ioojCBhAYD +# VR0fBH0wezB5oHegdYZzaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9j +# cmwvTWljcm9zb2Z0JTIwSWRlbnRpdHklMjBWZXJpZmljYXRpb24lMjBSb290JTIw +# Q2VydGlmaWNhdGUlMjBBdXRob3JpdHklMjAyMDIwLmNybDCBwwYIKwYBBQUHAQEE +# gbYwgbMwgYEGCCsGAQUFBzAChnVodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtp +# b3BzL2NlcnRzL01pY3Jvc29mdCUyMElkZW50aXR5JTIwVmVyaWZpY2F0aW9uJTIw +# Um9vdCUyMENlcnRpZmljYXRlJTIwQXV0aG9yaXR5JTIwMjAyMC5jcnQwLQYIKwYB +# BQUHMAGGIWh0dHA6Ly9vbmVvY3NwLm1pY3Jvc29mdC5jb20vb2NzcDANBgkqhkiG +# 9w0BAQwFAAOCAgEAfyUqnv7Uq+rdZgrbVyNMul5skONbhls5fccPlmIbzi+OwVdP +# Q4H55v7VOInnmezQEeW4LqK0wja+fBznANbXLB0KrdMCbHQpbLvG6UA/Xv2pfpVI +# E1CRFfNF4XKO8XYEa3oW8oVH+KZHgIQRIwAbyFKQ9iyj4aOWeAzwk+f9E5StNp5T +# 8FG7/VEURIVWArbAzPt9ThVN3w1fAZkF7+YU9kbq1bCR2YD+MtunSQ1Rft6XG7b4 +# e0ejRA7mB2IoX5hNh3UEauY0byxNRG+fT2MCEhQl9g2i2fs6VOG19CNep7SquKaB +# jhWmirYyANb0RJSLWjinMLXNOAga10n8i9jqeprzSMU5ODmrMCJE12xS/NWShg/t +# uLjAsKP6SzYZ+1Ry358ZTFcx0FS/mx2vSoU8s8HRvy+rnXqyUJ9HBqS0DErVLjQw +# K8VtsBdekBmdTbQVoCgPCqr+PDPB3xajYnzevs7eidBsM71PINK2BoE2UfMwxCCX +# 3mccFgx6UsQeRSdVVVNSyALQe6PT12418xon2iDGE81OGCreLzDcMAZnrUAx4XQL +# Uz6ZTl65yPUiOh3k7Yww94lDf+8oG2oZmDh5O1Qe38E+M3vhKwmzIeoB1dVLlz4i +# 3IpaDcR+iuGjH2TdaC1ZOmBXiCRKJLj4DT2uhJ04ji+tHD6n58vhavFIrmcxghr/ +# MIIa+wIBATBxMFoxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y +# cG9yYXRpb24xKzApBgNVBAMTIk1pY3Jvc29mdCBJRCBWZXJpZmllZCBDUyBFT0Mg +# Q0EgMDICEzMAATrAmwCycB81MNQAAAABOsAwDQYJYIZIAWUDBAIBBQCggcgwGQYJ +# KoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQB +# gjcCARUwLwYJKoZIhvcNAQkEMSIEICpXe3RS3b2coD0CJveEHlglqtPUYZ2FqSrO +# UfP6C6Y4MFwGCisGAQQBgjcCAQwxTjBMoEaARABCAHUAaQBsAHQAOgAgAFIAZQBs +# AGUAYQBzAGUAXwB2ADMALgAxADMALgAxAF8AMgAwADIANAAxADIAMAAzAC4AMAAx +# oQKAADANBgkqhkiG9w0BAQEFAASCAYBU5OBEfzxwvr57Bg/J75JKzgnwOxcTwRRU +# qo6mLWDGouoJTSX8wqdAiYarbWDLWaf7q5joMEP6j4IoSm+27tBco6g5sufaLd4z +# 7c5d3sHMQrxMD1BIRkMNAmLGnQ1aYIOOxjYDPEP+m23R1kLjqLcwL5MVTwYGQCUv +# 0/Y59Ggh1rWzOYgQusxGpIF6ipaM3srGTAUD9N5isN5GqZJQ9UgM/XzhEyTjhJxG +# p5jfpgGtPPH8ZY1BKJ0meYB/vUBkWzp4sipr/b3FtNELRV5iQ99ZgOn///3NzeGY +# iC05lCwvXaCGxGGwgkMJeLS7kaTGj9NzmOXMJJ+ug8zQhBQXndhgI1Y7jFIMwyuM +# 8aKMXBpPo9G2qyp1t3B+Za4mLzDYB035AjHUR3miLOJwDNi1WNeO5oAun559qRg/ +# w35W3cmmWLBBt+LaaLfF8sXkongpS1tfZbcaDDLgFgLvEARYml0bhUkH5rihoOyp +# Wx7mGcJ34lpx2WMGwboBx/+CfIudsCmhghgUMIIYEAYKKwYBBAGCNwMDATGCGAAw +# ghf8BgkqhkiG9w0BBwKgghftMIIX6QIBAzEPMA0GCWCGSAFlAwQCAQUAMIIBYgYL +# KoZIhvcNAQkQAQSgggFRBIIBTTCCAUkCAQEGCisGAQQBhFkKAwEwMTANBglghkgB +# ZQMEAgEFAAQgFphm7PxRBeThqujqqwAWPIXz7NwaNefMAd7IlfgybrICBmdEXsfu +# MBgTMjAyNDEyMDMyMDE0NDkuNTY4WjAEgAIB9KCB4aSB3jCB2zELMAkGA1UEBhMC +# VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV +# BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFt +# ZXJpY2EgT3BlcmF0aW9uczEnMCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjdEMDAt +# MDVFMC1EOTQ3MTUwMwYDVQQDEyxNaWNyb3NvZnQgUHVibGljIFJTQSBUaW1lIFN0 +# YW1waW5nIEF1dGhvcml0eaCCDyEwggeCMIIFaqADAgECAhMzAAAABeXPD/9mLsmH +# AAAAAAAFMA0GCSqGSIb3DQEBDAUAMHcxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVN +# aWNyb3NvZnQgQ29ycG9yYXRpb24xSDBGBgNVBAMTP01pY3Jvc29mdCBJZGVudGl0 +# eSBWZXJpZmljYXRpb24gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAyMDAe +# Fw0yMDExMTkyMDMyMzFaFw0zNTExMTkyMDQyMzFaMGExCzAJBgNVBAYTAlVTMR4w +# HAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29m +# dCBQdWJsaWMgUlNBIFRpbWVzdGFtcGluZyBDQSAyMDIwMIICIjANBgkqhkiG9w0B +# AQEFAAOCAg8AMIICCgKCAgEAnnznUmP94MWfBX1jtQYioxwe1+eXM9ETBb1lRkd3 +# kcFdcG9/sqtDlwxKoVIcaqDb+omFio5DHC4RBcbyQHjXCwMk/l3TOYtgoBjxnG/e +# ViS4sOx8y4gSq8Zg49REAf5huXhIkQRKe3Qxs8Sgp02KHAznEa/Ssah8nWo5hJM1 +# xznkRsFPu6rfDHeZeG1Wa1wISvlkpOQooTULFm809Z0ZYlQ8Lp7i5F9YciFlyAKw +# n6yjN/kR4fkquUWfGmMopNq/B8U/pdoZkZZQbxNlqJOiBGgCWpx69uKqKhTPVi3g +# VErnc/qi+dR8A2MiAz0kN0nh7SqINGbmw5OIRC0EsZ31WF3Uxp3GgZwetEKxLms7 +# 3KG/Z+MkeuaVDQQheangOEMGJ4pQZH55ngI0Tdy1bi69INBV5Kn2HVJo9XxRYR/J +# PGAaM6xGl57Ei95HUw9NV/uC3yFjrhc087qLJQawSC3xzY/EXzsT4I7sDbxOmM2r +# l4uKK6eEpurRduOQ2hTkmG1hSuWYBunFGNv21Kt4N20AKmbeuSnGnsBCd2cjRKG7 +# 9+TX+sTehawOoxfeOO/jR7wo3liwkGdzPJYHgnJ54UxbckF914AqHOiEV7xTnD1a +# 69w/UTxwjEugpIPMIIE67SFZ2PMo27xjlLAHWW3l1CEAFjLNHd3EQ79PUr8FUXet +# Xr0CAwEAAaOCAhswggIXMA4GA1UdDwEB/wQEAwIBhjAQBgkrBgEEAYI3FQEEAwIB +# ADAdBgNVHQ4EFgQUa2koOjUvSGNAz3vYr0npPtk92yEwVAYDVR0gBE0wSzBJBgRV +# HSAAMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lv +# cHMvRG9jcy9SZXBvc2l0b3J5Lmh0bTATBgNVHSUEDDAKBggrBgEFBQcDCDAZBgkr +# BgEEAYI3FAIEDB4KAFMAdQBiAEMAQTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQY +# MBaAFMh+0mqFKhvKGZgEByfPUBBPaKiiMIGEBgNVHR8EfTB7MHmgd6B1hnNodHRw +# Oi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBJZGVu +# dGl0eSUyMFZlcmlmaWNhdGlvbiUyMFJvb3QlMjBDZXJ0aWZpY2F0ZSUyMEF1dGhv +# cml0eSUyMDIwMjAuY3JsMIGUBggrBgEFBQcBAQSBhzCBhDCBgQYIKwYBBQUHMAKG +# dWh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0 +# JTIwSWRlbnRpdHklMjBWZXJpZmljYXRpb24lMjBSb290JTIwQ2VydGlmaWNhdGUl +# MjBBdXRob3JpdHklMjAyMDIwLmNydDANBgkqhkiG9w0BAQwFAAOCAgEAX4h2x35t +# tVoVdedMeGj6TuHYRJklFaW4sTQ5r+k77iB79cSLNe+GzRjv4pVjJviceW6AF6yc +# WoEYR0LYhaa0ozJLU5Yi+LCmcrdovkl53DNt4EXs87KDogYb9eGEndSpZ5ZM74LN +# vVzY0/nPISHz0Xva71QjD4h+8z2XMOZzY7YQ0Psw+etyNZ1CesufU211rLslLKsO +# 8F2aBs2cIo1k+aHOhrw9xw6JCWONNboZ497mwYW5EfN0W3zL5s3ad4Xtm7yFM7Uj +# rhc0aqy3xL7D5FR2J7x9cLWMq7eb0oYioXhqV2tgFqbKHeDick+P8tHYIFovIP7Y +# G4ZkJWag1H91KlELGWi3SLv10o4KGag42pswjybTi4toQcC/irAodDW8HNtX+cbz +# 0sMptFJK+KObAnDFHEsukxD+7jFfEV9Hh/+CSxKRsmnuiovCWIOb+H7DRon9Tlxy +# diFhvu88o0w35JkNbJxTk4MhF/KgaXn0GxdH8elEa2Imq45gaa8D+mTm8LWVydt4 +# ytxYP/bqjN49D9NZ81coE6aQWm88TwIf4R4YZbOpMKN0CyejaPNN41LGXHeCUMYm +# Bx3PkP8ADHD1J2Cr/6tjuOOCztfp+o9Nc+ZoIAkpUcA/X2gSMkgHAPUvIdtoSAHE +# UKiBhI6JQivRepyvWcl+JYbYbBh7pmgAXVswggeXMIIFf6ADAgECAhMzAAAANQkF +# tbLnhO8MAAAAAAA1MA0GCSqGSIb3DQEBDAUAMGExCzAJBgNVBAYTAlVTMR4wHAYD +# VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBQ +# dWJsaWMgUlNBIFRpbWVzdGFtcGluZyBDQSAyMDIwMB4XDTI0MDIxNTIwMzU1MloX +# DTI1MDIxNTIwMzU1MlowgdsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5n +# dG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9y +# YXRpb24xJTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVyaWNhIE9wZXJhdGlvbnMxJzAl +# BgNVBAsTHm5TaGllbGQgVFNTIEVTTjo3RDAwLTA1RTAtRDk0NzE1MDMGA1UEAxMs +# TWljcm9zb2Z0IFB1YmxpYyBSU0EgVGltZSBTdGFtcGluZyBBdXRob3JpdHkwggIi +# MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCx16enGZJGQ7gaMJThjoXc/yyT +# S/41wvM+DZRPvRK61Rx8wriql3ja+Dmrx6RSEEQs9ijogniNkfjyBLL7HdCbFZ8r +# Vyua6JQZovO+iwXS6BS+OvBHSiH45Ze880I/zai2TNDQGaFgVrg9w+U7V7l7lXoy +# dq82jqZNQN1vIyfAEauFdOhUt8zQQqFYWOAgM9timvHZpwC67yr3U+H1GCun3nv3 +# VE9P5vSZ1ZGZcT+bVF31r9U5hFNMhVQKQmTyW7cAJ3PY04eTCl//zwMfI5C0ZsWf +# tB2s/+sSLehrDGLGrMlAb/gmspPiDoubFxwyhZTw+o+1tI2DLloG0iu3jw7aiNBU +# o//yQnPcxx7K0r2yixxIAS6HFQ+KIEnQXBoKOkefAFDfC6csv4DgsrZ8J0dHf+5K +# WekOpPBr8BhtRfQOZctnKjs6e6tKjNukCDEDIJQfap1EcaO8Xp/D03F60ZkR3ti/ +# jUaly0YBIzSVl3P1O/UsATePOpaaICGF64becM3YhdQWiueZCRB1eynHyiexHPIC +# tOdGYmvBbSwgGtTnjkBDBZmYRmBZQ7oO9HpY6uAzqel4v/x2M9hxdR58CxtR67Wa +# 19G7MIXHrjWOW9P/S9LWHxCmv8rBYH/XJ6gO0LMG1y7RVNfVa74sTkFdw3rXYOqI +# gAK3P/RAVsl+nJkUOQIDAQABo4IByzCCAccwHQYDVR0OBBYEFC0MHwijOlgxGLFY +# nUf/1KvFITwrMB8GA1UdIwQYMBaAFGtpKDo1L0hjQM972K9J6T7ZPdshMGwGA1Ud +# HwRlMGMwYaBfoF2GW2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY3Js +# L01pY3Jvc29mdCUyMFB1YmxpYyUyMFJTQSUyMFRpbWVzdGFtcGluZyUyMENBJTIw +# MjAyMC5jcmwweQYIKwYBBQUHAQEEbTBrMGkGCCsGAQUFBzAChl1odHRwOi8vd3d3 +# Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY3Jvc29mdCUyMFB1YmxpYyUy +# MFJTQSUyMFRpbWVzdGFtcGluZyUyMENBJTIwMjAyMC5jcnQwDAYDVR0TAQH/BAIw +# ADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAOBgNVHQ8BAf8EBAMCB4AwZgYDVR0g +# BF8wXTBRBgwrBgEEAYI3TIN9AQEwQTA/BggrBgEFBQcCARYzaHR0cDovL3d3dy5t +# aWNyb3NvZnQuY29tL3BraW9wcy9Eb2NzL1JlcG9zaXRvcnkuaHRtMAgGBmeBDAEE +# AjANBgkqhkiG9w0BAQwFAAOCAgEAJDLwG5EIN52DlyO+3UmsZ80QS5kP4cWW5Dgu +# DG+E1+zTP9YJm+zNreELGi6Nwy/wRUSxXL1BN3IFQ7aYc1iAO0oaEtmR7WHq3jBk +# ILx6BnlQ1BhXHfOcSXotJQAHWO3M0p3rVV4yqVLfx+QWPUKCRQXvhdK2UdPKin9m +# BLlhlvSLtMpGWHyThMRlSw1LH2IVNGwV/B7IYPPaQ8OMkhy15/IrnnKpM67ljpJU +# d0IC6W17QXnm43ASqp2r49VE6cWZ5k7toBLp+7JhbxBudhewd8zZh0uZoOYZqUw8 +# X/teuxs27s4Na4Y62N37o29ElE+YuSQHELoz+veBkm6ArSp2OI2BWi9+vmrFRgsi +# 7yQSTJFJKAOI5/a/Dk4gt2LnlFnTMCCoUwwRPpxyXe5ijmGnMLHLu0C4lOdRgh8m +# ExfncZMssMXSfhmf3ntHGWoY6Xs4G1hSlwMsdfx/O4pOj5SKLACTK1FW2cEBelYA +# wki5938BnR4IUjXG8jX8Z0fAEoPYOQSRDeYGK0z6IBPmCIrfCfk8ulzN3bdura2y +# wPOUOR79SCPQhBDFsvUQsZhoZcEGQjkC/4AvsCqHJpDOp/m8SydWTznjl47CzdJg +# 3/ofsKDMzzYOm7O9Xx8LQ6CCmYjNG+ajRyA4fm7xyS6tMMGkIs4zWYgFxzXzxMer +# 0JdC/6IxggdGMIIHQgIBATB4MGExCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVNaWNy +# b3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBQdWJsaWMgUlNB +# IFRpbWVzdGFtcGluZyBDQSAyMDIwAhMzAAAANQkFtbLnhO8MAAAAAAA1MA0GCWCG +# SAFlAwQCAQUAoIIEnzARBgsqhkiG9w0BCRACDzECBQAwGgYJKoZIhvcNAQkDMQ0G +# CyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yNDEyMDMyMDE0NDlaMC8GCSqG +# SIb3DQEJBDEiBCARuvDtg/OtiUPuQ1cnypuU6FIoeJLlKd548IchTQuRpDCBuQYL +# KoZIhvcNAQkQAi8xgakwgaYwgaMwgaAEIHxTAGEmWoTCPM6feK8tcQboGIcIUl3z +# +ltjDiZ1V+qAMHwwZaRjMGExCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVNaWNyb3Nv +# ZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBQdWJsaWMgUlNBIFRp +# bWVzdGFtcGluZyBDQSAyMDIwAhMzAAAANQkFtbLnhO8MAAAAAAA1MIIDYQYLKoZI +# hvcNAQkQAhIxggNQMIIDTKGCA0gwggNEMIICLAIBATCCAQmhgeGkgd4wgdsxCzAJ +# BgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25k +# MR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJTAjBgNVBAsTHE1pY3Jv +# c29mdCBBbWVyaWNhIE9wZXJhdGlvbnMxJzAlBgNVBAsTHm5TaGllbGQgVFNTIEVT +# Tjo3RDAwLTA1RTAtRDk0NzE1MDMGA1UEAxMsTWljcm9zb2Z0IFB1YmxpYyBSU0Eg +# VGltZSBTdGFtcGluZyBBdXRob3JpdHmiIwoBATAHBgUrDgMCGgMVAC/su4aSCBq3 +# tZboiqOg5xcAy2LZoGcwZaRjMGExCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVNaWNy +# b3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBQdWJsaWMgUlNB +# IFRpbWVzdGFtcGluZyBDQSAyMDIwMA0GCSqGSIb3DQEBCwUAAgUA6vlpTDAiGA8y +# MDI0MTIwMzExMjYwNFoYDzIwMjQxMjA0MTEyNjA0WjB3MD0GCisGAQQBhFkKBAEx +# LzAtMAoCBQDq+WlMAgEAMAoCAQACAhkDAgH/MAcCAQACAhDCMAoCBQDq+rrMAgEA +# MDYGCisGAQQBhFkKBAIxKDAmMAwGCisGAQQBhFkKAwKgCjAIAgEAAgMHoSChCjAI +# AgEAAgMBhqAwDQYJKoZIhvcNAQELBQADggEBAIWyU6IzqcBXLYPsonhWRrEAgS+L +# ExMIDtcILcqgVdYMj1qQT3pF02mlQtuYyOu/HAA74Fv7hqZ8XLIJQaafC65pdRWu +# P1axYYNzhRWeXa+Lqq7TqPq3u1hUykEs3LlO4WRYs/0HcJDpCDmbOAx117JNhrPf +# vSyRHQR/8u+Tu/ZWOW1Ye3bT8KVXj2s1fjDimjBlEKERScugA074CsNIE/4KsBhd +# HvVpIispoWvhDccvVfoub5gYVWcQnACIWS+FPgvBfSfNe3Hyr1qOFQS1waktCptT +# VWivtjvSU4lbDGQkhGVRAABuz/uLlWqGQG8VbcX/M4hpdHKMlehzGW9KisgwDQYJ +# KoZIhvcNAQEBBQAEggIANbepN5rP7UsfA/dgVt0IMclFLkWkVyYzMO3RG9xWAKOv +# Ctr+vfnu2YYqpO3bqypxXq63XYpt1zYXvcYv0K/lWGh19U594B3Jpo9vwx862ULQ +# dXhN04ll1R3TN0cNc8NG4gKTxpn0frVEhaL8xAuPTOECjSFtXapiddCagIeWiCHw +# 8C/KM13bsxTrd43DLVYh1PpruAdaP+lQiNtl6mJZ3Kt3Modi9TkVhIDalfsKxFxt +# ew+ocLzWtDeoJa4dAX0Vn8RMTRMeanH9DlCpa69MQktpyeoPUqXjltV2k1D9luHh +# a3IOoDowfFToJOwLRvbUUeqmYShX1SEkaDglinJX2g3qUrSwjKe5HuxSSaUIuAOP +# yENfP6E8TpO+ZJlybcJElYtlzSa3sZQvXMF4fkcKUlpxL6EPs95wJv3s/V0/nyqL +# alocU1ghfmon80C9Tir4wdQ50dDlL0OQSKxoibj+hiLsvD+zns0XemqAypIINm02 +# C4Wp0Y/H/ayEXbmN3nHFkBJ13//fAIiwEuo+4s9LtA/2rdMTkHg3Bz2HTde2XBOb +# cBLqxu5q1ty9v6ck+OANSHnLA/0msGAdgN72EEgx44c+UgIBik9Pe7zB5mnO4y1r +# d38ANNiSo4F75l1XdDMrz5/seXsBNjZ7u21uyc/qVeY0nMWtf0kwaCo/uQz6WLA= +# SIG # End signature block diff --git a/Scripts/activate b/Scripts/activate new file mode 100644 index 0000000..5f5b872 --- /dev/null +++ b/Scripts/activate @@ -0,0 +1,76 @@ +# 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 locations. Without forgetting + # past locations the $PATH changes we made may not be respected. + # See "man bash" for more details. hash is usually a builtin of your shell + 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: +case "$(uname)" in + CYGWIN*|MSYS*|MINGW*) + # transform D:\path\to\venv to /d/path/to/venv on MSYS and MINGW + # and to /cygdrive/d/path/to/venv on Cygwin + VIRTUAL_ENV=$(cygpath 'C:\Users\Hitesh\Desktop\GUI') + export VIRTUAL_ENV + ;; + *) + # use the path as-is + export VIRTUAL_ENV='C:\Users\Hitesh\Desktop\GUI' + ;; +esac + +_OLD_VIRTUAL_PATH="$PATH" +PATH="$VIRTUAL_ENV/"Scripts":$PATH" +export PATH + +VIRTUAL_ENV_PROMPT=GUI +export VIRTUAL_ENV_PROMPT + +# 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="("GUI") ${PS1:-}" + export PS1 +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/Scripts/activate.bat b/Scripts/activate.bat new file mode 100644 index 0000000..31df331 --- /dev/null +++ b/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\Hitesh\Desktop\GUI" + +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=(GUI) %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=GUI" + +:END +if defined _OLD_CODEPAGE ( + "%SystemRoot%\System32\chcp.com" %_OLD_CODEPAGE% > nul + set _OLD_CODEPAGE= +) diff --git a/Scripts/activate.fish b/Scripts/activate.fish new file mode 100644 index 0000000..7aebeb5 --- /dev/null +++ b/Scripts/activate.fish @@ -0,0 +1,69 @@ +# This file must be used with "source /bin/activate.fish" *from fish* +# (https://fishshell.com/). You cannot run it directly. + +function deactivate -d "Exit virtual environment and return to normal shell environment" + # reset old environment variables + if test -n "$_OLD_VIRTUAL_PATH" + set -gx PATH $_OLD_VIRTUAL_PATH + set -e _OLD_VIRTUAL_PATH + end + if test -n "$_OLD_VIRTUAL_PYTHONHOME" + set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME + set -e _OLD_VIRTUAL_PYTHONHOME + end + + if test -n "$_OLD_FISH_PROMPT_OVERRIDE" + set -e _OLD_FISH_PROMPT_OVERRIDE + # prevents error when using nested fish instances (Issue #93858) + if functions -q _old_fish_prompt + functions -e fish_prompt + functions -c _old_fish_prompt fish_prompt + functions -e _old_fish_prompt + end + end + + set -e VIRTUAL_ENV + set -e VIRTUAL_ENV_PROMPT + if test "$argv[1]" != "nondestructive" + # Self-destruct! + functions -e deactivate + end +end + +# Unset irrelevant variables. +deactivate nondestructive + +set -gx VIRTUAL_ENV 'C:\Users\Hitesh\Desktop\GUI' + +set -gx _OLD_VIRTUAL_PATH $PATH +set -gx PATH "$VIRTUAL_ENV/"Scripts $PATH +set -gx VIRTUAL_ENV_PROMPT GUI + +# Unset PYTHONHOME if set. +if set -q PYTHONHOME + set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME + set -e PYTHONHOME +end + +if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" + # fish uses a function instead of an env var to generate the prompt. + + # Save the current fish_prompt function as the function _old_fish_prompt. + functions -c fish_prompt _old_fish_prompt + + # With the original prompt function renamed, we can override with our own. + function fish_prompt + # Save the return status of the last command. + set -l old_status $status + + # Output the venv prompt; color taken from the blue of the Python logo. + printf "%s(%s)%s " (set_color 4B8BBE) GUI (set_color normal) + + # Restore the return status of the previous command. + echo "exit $old_status" | . + # Output the original/"old" prompt. + _old_fish_prompt + end + + set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" +end diff --git a/Scripts/deactivate.bat b/Scripts/deactivate.bat new file mode 100644 index 0000000..62a39a7 --- /dev/null +++ b/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/Scripts/f2py.exe b/Scripts/f2py.exe new file mode 100644 index 0000000..82d95f9 Binary files /dev/null and b/Scripts/f2py.exe differ diff --git a/Scripts/numpy-config.exe b/Scripts/numpy-config.exe new file mode 100644 index 0000000..a97fce7 Binary files /dev/null and b/Scripts/numpy-config.exe differ diff --git a/Scripts/pip.exe b/Scripts/pip.exe new file mode 100644 index 0000000..b2f3967 Binary files /dev/null and b/Scripts/pip.exe differ diff --git a/Scripts/pip3.13.exe b/Scripts/pip3.13.exe new file mode 100644 index 0000000..b2f3967 Binary files /dev/null and b/Scripts/pip3.13.exe differ diff --git a/Scripts/pip3.exe b/Scripts/pip3.exe new file mode 100644 index 0000000..b2f3967 Binary files /dev/null and b/Scripts/pip3.exe differ diff --git a/Scripts/pyi-archive_viewer.exe b/Scripts/pyi-archive_viewer.exe new file mode 100644 index 0000000..28bc679 Binary files /dev/null and b/Scripts/pyi-archive_viewer.exe differ diff --git a/Scripts/pyi-bindepend.exe b/Scripts/pyi-bindepend.exe new file mode 100644 index 0000000..4b8880f Binary files /dev/null and b/Scripts/pyi-bindepend.exe differ diff --git a/Scripts/pyi-grab_version.exe b/Scripts/pyi-grab_version.exe new file mode 100644 index 0000000..f43ffd2 Binary files /dev/null and b/Scripts/pyi-grab_version.exe differ diff --git a/Scripts/pyi-makespec.exe b/Scripts/pyi-makespec.exe new file mode 100644 index 0000000..5872703 Binary files /dev/null and b/Scripts/pyi-makespec.exe differ diff --git a/Scripts/pyi-set_version.exe b/Scripts/pyi-set_version.exe new file mode 100644 index 0000000..4acc323 Binary files /dev/null and b/Scripts/pyi-set_version.exe differ diff --git a/Scripts/pyinstaller.exe b/Scripts/pyinstaller.exe new file mode 100644 index 0000000..58e0e86 Binary files /dev/null and b/Scripts/pyinstaller.exe differ diff --git a/Scripts/python.exe b/Scripts/python.exe new file mode 100644 index 0000000..24f36b7 Binary files /dev/null and b/Scripts/python.exe differ diff --git a/Scripts/pythonw.exe b/Scripts/pythonw.exe new file mode 100644 index 0000000..d4ab4b3 Binary files /dev/null and b/Scripts/pythonw.exe differ diff --git a/assets/img/screenshot.png b/assets/img/screenshot.png new file mode 100644 index 0000000..2a903e0 Binary files /dev/null and b/assets/img/screenshot.png differ diff --git a/pyvenv.cfg b/pyvenv.cfg new file mode 100644 index 0000000..a7c603e --- /dev/null +++ b/pyvenv.cfg @@ -0,0 +1,5 @@ +home = C:\Program Files\Python313 +include-system-site-packages = false +version = 3.13.1 +executable = C:\Program Files\Python313\python.exe +command = C:\Program Files\Python313\python.exe -m venv C:\Users\Hitesh\Desktop\GUI diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..790459e --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +secure-smtplib==0.1.1 +tk==0.1.0 +pandas==2.2.3 +openpyxl==3.1.5 +pyinstaller==6.11.1 \ No newline at end of file diff --git a/sample.xlsx b/sample.xlsx new file mode 100644 index 0000000..fd2118f Binary files /dev/null and b/sample.xlsx differ