Search Windows Tree View Items
Search online for tree-item values in desktop windows applications, via memory chip injection using kernel32.dll & VirtualAllocEx (hardest one & capstone)
C++
Click for Portfolio
                #include <iostream>
#include <Windows.h>
#include <Commctrl.h>
#include <shellapi.h>
 
 
#include "windows_gui.hpp"
 
 
///////////////////////////
//
// NOTES:
//
//		- The following .hpp files are included in this file:
//			- windows_gui.hpp
//			     - windows_gui.hpp in turn calls the following .hpp file:
//					- search_strategy_factory.hpp
//
///////////////////////////
 
 
 
using namespace std;
HWND get_hwnd_by_title_part(const char*);
HHOOK _hook;
HMENU menu;
HWND hwnd_main_window;
LRESULT __stdcall MouseCallback(int nCode, WPARAM wParam, LPARAM lParam)
{   
    switch(wParam)
    {
        case WM_LBUTTONUP:
        {
            // get the text of the tree item
            DWORD pid = 0;
            DWORD bytes_read = 0;
            DWORD bytes_written = 0;
            BOOL debug = false;
            int text_buffer_size = 256;
            char text[256];
 
            //get the point & get the hwnd from that point
            POINT pt;
            GetCursorPos(&pt);
            HWND hwnd_clicked = WindowFromPoint(pt);            
            char class_name[256];
            GetClassName(hwnd_clicked, class_name, 256);
            //do not go any further if it's not a TreeViewList item
            if (strcmp(class_name, "SysTreeView32") != 0) break;
 
            //get HTREEITEM from hwnd
            TreeView_GetSelection(hwnd_clicked);
            HTREEITEM htreeitem_selected = (HTREEITEM)SendMessage(hwnd_clicked, TVM_GETNEXTITEM, TVGN_DROPHILITE, 0);
 
            
            //new TVITEM to place in the remote prcess
            TVITEM item;
            item.hItem = htreeitem_selected;
            item.mask = TVIF_TEXT | TVIF_HANDLE;
            item.pszText = new TCHAR[256];
            item.cchTextMax = 256;
            //open process
            GetWindowThreadProcessId(hwnd_main_window, &pid);
            HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
 
            //VirtualAllocEx (treeview)
            //VirtualAllocEx (text)
            //
            // Both functions return a pointer to the allocated memory. Since it has EX at the end, it goes to another process.
            LPVOID remote_item_address = VirtualAllocEx(hProcess, 0, sizeof(TVITEM), MEM_COMMIT, PAGE_READWRITE);
            LPVOID remote_text_address = VirtualAllocEx(hProcess, 0, text_buffer_size, MEM_COMMIT, PAGE_READWRITE);
            //
            //
            //This following line is very important. The whole TVITEM  structure will be sent to the process. The TVITEM.psText will have the results of the the second call we made to VirtualAllocEx, which is for text. It's like a double pointer.
            //
            // According to https://docs.microsoft.com/en-us/windows/win32/controls/tvm-getitem
            // "If the TVIF_TEXT flag is set in the mask member of the TVITEM or TVITEMEX structure, the pszText member must point to a valid buffer and the cchTextMax member must be set to the number of characters in that buffer"
            item.pszText = (LPTSTR)remote_text_address;
 
            //WriteProcessMemory    (Puts OUR local TVITEM object into the remote process)
            //SendMessageA          (message is TVM_GETITEM, and fills out the TVItem structure we put in)
            //GetLastError          (error checking)
            //ReadProcessMemory     (gets the remote TVITEM object at remote_item_address, and puts it in local &item)
            //ReadProcessMemory     (gets the remote text object at remote_text_address, and puts it in local &buffer)
            BOOL write_process = WriteProcessMemory(hProcess, remote_item_address, &item, sizeof(TVITEM), &bytes_written);
            BOOL sent_message = SendMessageA(hwnd_clicked, TVM_GETITEM, TVGN_CARET, (LPARAM)remote_item_address);
            // get last error
            DWORD last_error = GetLastError();
            ReadProcessMemory(hProcess, remote_item_address, &item, sizeof(TVITEM), &bytes_read);
            CHAR buffer[256];
            ReadProcessMemory(hProcess, remote_text_address, &buffer, text_buffer_size - 1, &bytes_read);
            
 
            //print out 
            if(debug)
            {
                cout << "write process: " << write_process << endl;
                cout << "sent message: " << sent_message << endl;
                cout << "last error: " << last_error << endl;
                cout << "bytes_written: " << bytes_written << endl;
                cout << "bytes_read: " << bytes_read << endl;
                cout << "Text: " << text << endl;
                cout << "Buffer: " << buffer << endl;
                cout << endl;
            }
           
            //free memory 
            VirtualFreeEx(hProcess, remote_item_address, sizeof(TVITEM), MEM_RELEASE);
            VirtualFreeEx(hProcess, remote_text_address, text_buffer_size, MEM_RELEASE);
            CloseHandle(hProcess);
 
            //search
            if(strlen(buffer) < 1) break;
 
            //search instance is defined in 
            search_instance.search(buffer);
            
 
            break;
        }
        case WM_COMMAND:
        {
            cout << "Command" << endl;
            break;
        }
        case WM_INITMENUPOPUP:
        {
            cout << "Goon" << endl;
            break;
        }
    }
    return CallNextHookEx(_hook, nCode, wParam, lParam);
}
 
HWND get_hwnd_by_title_part(const char* title_part)
{
    HWND hwnd = NULL;
    while (hwnd = FindWindowEx(NULL, hwnd, NULL, NULL))
    {
        char title[256];
        GetWindowText(hwnd, title, 256);
        if (strstr(title, title_part))
        {
            return hwnd;
        }
    }
    return NULL;
}
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
    // get the hwnd of the main_window window
    hwnd_main_window = get_hwnd_by_title_part("Explorer");
    cout << "hwnd_main_window: " << hwnd_main_window << endl;
    // set the hook for left mouse clicks
    if (!(_hook = SetWindowsHookEx(WH_MOUSE_LL, MouseCallback, hInstance, 0)))
    {
        MessageBox(NULL, "Failed to install hook!", "Error", MB_ICONERROR);
    }
 
    // create the window to search in different pages (windows_gui.hpp)
    HWND hwnd_search_window = create_basic_window();
 
 
    // getdlgitem at 5 (the text box that is not the buttons). The reason it is 5 is because it corresponds to the index of the text box in the windows_gui.hpp file when it is created by the CreateWindow function.
    HWND hwnd_search_text = GetDlgItem(hwnd_search_window, 5);
    char hwnd_main_window_hex[256];
    sprintf(hwnd_main_window_hex, "Window found in: 0x%x", hwnd_main_window);
    SetWindowText(hwnd_search_text, hwnd_main_window_hex);
 
    ShowWindow(hwnd_search_window, SW_SHOW);
    UpdateWindow(hwnd_search_window);
 
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    }
    return 0;
}
            
Search Windows Tree View Items
Strategy Design Pattern to search different sites based on the user choice with BS_PUSHLIKE on CreateWindow function in user32.dll & gdi32.dll (Raw MSDN, no framework)
C++
Click for Portfolio
                #include <iostream>
#include <Windows.h>
#include <Commctrl.h>
using namespace std;
 
#include "search_strategy_factory.hpp"
 
//search instance to be used for the radio push buttons in the window
Search search_instance = Search();
 
LRESULT APIENTRY WindowProcedure(HWND , UINT , WPARAM , LPARAM );
 
 
HWND create_basic_window()
{
    int window_width = 400;
    int window_height = 250;
 
    WNDCLASSEX wc;
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = 0;
    wc.lpfnWndProc = WindowProcedure;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = GetModuleHandle(NULL);
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(191,184,191));
    wc.lpszMenuName = NULL;
    wc.lpszClassName = "WindowClass";
    wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    if (!RegisterClassEx(&wc))
    {
        MessageBox(NULL, "Window Registration Failed!", "Error!",
                   MB_ICONEXCLAMATION | MB_OK);
        return NULL;
    }
    HWND hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, "WindowClass", "Search Tree View",
                               WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, window_width, window_height, NULL, NULL, GetModuleHandle(NULL), NULL);
    if (hwnd == NULL)
    {
        MessageBox(NULL, "Window Creation Failed!", "Error!",
                   MB_ICONEXCLAMATION | MB_OK);
        return NULL;
    }
    return hwnd;
}
 
 
LRESULT APIENTRY WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_COMMAND:
        {
            if (LOWORD(wParam) == 1)
            {
                search_instance.setStrategy("youtube");
            }
            else if (LOWORD(wParam) == 2)
            {
                search_instance.setStrategy("spotify");
            }
            else if (LOWORD(wParam) == 3)
            {
                search_instance.setStrategy("discogs");
            }
            else if (LOWORD(wParam) == 4)
            {
                search_instance.setStrategy("google");
            }
 
            return 0;
        }
        case WM_CREATE:
        {
            int window_width = 400;
            int window_height = 250;
 
            //create two buttons in this window with padding of 10 pixels on every side
            short int top_padding = 10;
            short int left_padding = 50;
            short int right_padding = 50;
            short int bottom_padding = 10;
            short int button_bottom_margin = 10;
            // I don't know why I needed to put -20 for the width, because it should have worked without it. 
            short int button_width = (window_width - (left_padding + right_padding)) - 20;
            short int button_height = 30;
 
            //Create three buttons and attach them to the window. They will show up as RADIO BUTTONS in the menu. The BS_PUSHLIKE style is used to make the radio buttons look like push buttons.
            HWND button1 = CreateWindowEx(0, "BUTTON", "YouTube", WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON | BS_PUSHLIKE, left_padding, top_padding, button_width, button_height, hwnd, (HMENU)1, NULL, NULL);
            HWND button2 = CreateWindowEx(0, "BUTTON", "Spotify", WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON | BS_PUSHLIKE, left_padding, top_padding + button_height + button_bottom_margin, button_width, button_height, hwnd, (HMENU)2, NULL, NULL);
            HWND button3 = CreateWindowEx(0, "BUTTON", "Discogs", WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON | BS_PUSHLIKE, left_padding, top_padding + (button_height * 2) + (button_bottom_margin * 2), button_width, button_height, hwnd, (HMENU)3, NULL, NULL);
            HWND button4 = CreateWindowEx(0, "BUTTON", "Google", WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON | BS_PUSHLIKE, left_padding, top_padding + (button_height * 3) + (button_bottom_margin * 3), button_width, button_height, hwnd, (HMENU)4, NULL, NULL);
 
            //Run the code that would usually happen when clicking the button. The 1 corresponds to the first button when the radio buttons are created.
            SendMessage(hwnd, WM_COMMAND, 1, 0);
            //Make button 1 the default selection (pushed down)
            SendMessage(button1, BM_SETCHECK, BST_CHECKED, 0);
 
 
            //put some text 25 pixels below button4 with background color of RGB(191,184,191)
            //background color is determined by the case in the switch statement in the WindowProcedure function below for the case called WM_CTLCOLORSTATIC
            //the (+5) is to make the text appear below the button
            HWND text_box = CreateWindowEx(0, "STATIC", "Goon", WS_VISIBLE | WS_CHILD | SS_LEFT | SS_CENTER, left_padding, top_padding + (button_height * 4) + (button_bottom_margin * 4) + 5, button_width, button_height, hwnd, (HMENU)5, NULL, NULL);
 
            break;
        }
        //Sole reason is to make the background color of Text Label with the same background as the rest of the window
        case WM_CTLCOLORSTATIC:
        {
            HDC hdcStatic = (HDC)wParam;
            SetTextColor(hdcStatic, RGB(0, 0, 0));
            SetBkColor(hdcStatic, RGB(191, 184, 191));
            //create brush
            HBRUSH hBrush = CreateSolidBrush(RGB(191, 184, 191));
            return (LRESULT)hBrush;
        }         
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        default:
            return DefWindowProc(hwnd, message, wParam, lParam);
    }
 
    return 0;
}

            
Search Windows Tree View Items
Generate the GUI for the user to choose the site, without any high-level easy abstracted framework (done in RAW C++ Win32 MSDN)
C++
Click for Portfolio
                #include <iostream>
#include <Windows.h>
#include <Commctrl.h>
using namespace std;
HHOOK _hook;
HMENU menu;
LRESULT APIENTRY WindowProcedure(HWND , UINT , WPARAM , LPARAM );
HWND create_basic_window()
{
    WNDCLASSEX wc;
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = 0;
    wc.lpfnWndProc = WindowProcedure;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = GetModuleHandle(NULL);
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(191,184,191));
    wc.lpszMenuName = NULL;
    wc.lpszClassName = "WindowClass";
    wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    if (!RegisterClassEx(&wc))
    {
        MessageBox(NULL, "Window Registration Failed!", "Error!",
                   MB_ICONEXCLAMATION | MB_OK);
        return NULL;
    }
    HWND hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, "WindowClass", "Search Tree View",
                               WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 100, 180, NULL, NULL, GetModuleHandle(NULL), NULL);
    if (hwnd == NULL)
    {
        MessageBox(NULL, "Window Creation Failed!", "Error!",
                   MB_ICONEXCLAMATION | MB_OK);
        return NULL;
    }
    return hwnd;
}
 
 
LRESULT APIENTRY WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        //add clickable buttons to this hwnd
        case WM_CREATE:
        {
            break;
        }
        case WM_COMMAND:
        {
            if (LOWORD(wParam) == 1)
            {
                // MessageBox(hwnd, "Open", "Menu", MB_OK);
            }
            return 0;
        }
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        default:
            return DefWindowProc(hwnd, message, wParam, lParam);
    }
 
    return 0;
}
 
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    HWND hwnd = create_basic_window();
    
    //create two buttons in this window with padding of 10 pixels on every side
    RECT rect;
    GetClientRect(hwnd, &rect);
    int window_length = rect.right;
    int window_height = rect.bottom;
    short int top_padding = 10;
    short int left_padding = 10;
    short int right_padding = 10;
    short int bottom_padding = 10;
    short int button_bottom_margin = 10;
    short int button_width = (window_length - (left_padding + right_padding));
    short int button_height = 30;
 
    //Create three buttons and attach them to the window. They will show up as RADIO BUTTONS in the menu. The BS_PUSHLIKE style is used to make the radio buttons look like push buttons.
    HWND button1 = CreateWindowEx(0, "BUTTON", "Button 1", WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON | BS_PUSHLIKE , left_padding, top_padding, button_width, button_height, hwnd, (HMENU)1, NULL, NULL);
    HWND button2 = CreateWindowEx(0, "BUTTON", "Button 2", WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON | BS_PUSHLIKE , left_padding, top_padding + button_height + button_bottom_margin, button_width, button_height, hwnd, (HMENU)2, NULL, NULL);
    HWND button3 = CreateWindowEx(0, "BUTTON", "Button 3", WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON | BS_PUSHLIKE, left_padding, top_padding + (button_height * 2) + (button_bottom_margin * 2), button_width, button_height, hwnd, (HMENU)3, NULL, NULL);
    //Make button 2 the default selection   
    HWND button4 = CreateWindowEx(0, "BUTTON", "Button 4", WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON | BS_PUSHLIKE, left_padding, top_padding + (button_height * 3) + (button_bottom_margin * 3), button_width, button_height, hwnd, (HMENU)4, NULL, NULL);
    SendMessage(button2, BM_SETCHECK, BST_CHECKED, 0);
 
    ShowWindow(hwnd, SW_SHOW);
    UpdateWindow(hwnd);
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}

            
Linux Mouse Button Remapping (near kernel evdev event driver)
Linux remapping of mouse buttons right above Linux Kernel level directly altering "evdev kernel event driver" before user-level linux "libinput"
Python
Click for Portfolio
                ###########################
##
##    Imports
##
###########################
 
 
from Xlib import X, display
import time, evdev
from evdev import UInput, ecodes
import os
import ctypes
import ctypes.util
 
###########################
##
##    Get Kernel Device Representation and Simulate Clicks
##
###########################
 
 
mouse_name = "USB OPTICAL MOUSE "
device = None
for input_device in [evdev.InputDevice(path) for path in evdev.list_devices()]:
	# print(input_device.name, mouse_name)
	if input_device.name == mouse_name:
		device = input_device
		break
 
if device is None:
	print(f"Device with name {mouse_name} not found.")
	exit()
 
 
# Create a virtual input device
ui = UInput.from_device(device)
 
 
def click(button):
	ui.write(ecodes.EV_KEY, button, 1)
	ui.write(ecodes.EV_SYN, ecodes.SYN_REPORT, 0)
	ui.write(ecodes.EV_KEY, button, 0) 
	ui.write(ecodes.EV_SYN, ecodes.SYN_REPORT, 0)
 
def press(button):
	ui.write(ecodes.EV_KEY, button, 1)
	ui.write(ecodes.EV_SYN, ecodes.SYN_REPORT, 0)
	
 
def left_click():
	# print("Simulated Left Click")
	click(ecodes.BTN_LEFT)
 
def middle_click():
	# print("Simulated Middle Click")
	click(ecodes.BTN_MIDDLE)
 
def right_click():
	# print("Simulated Right Click")
	click(ecodes.BTN_RIGHT)
 
def left_press():
	# print("Simulated Left Press")
	press(ecodes.BTN_LEFT)
 
def middle_press():
	# print("Simulated Left Press")
	press(ecodes.BTN_MIDDLE)
	
 
 
 
###########################
##
##    disable wheel of mouse
##
##########################
 
 
 
#########
# get the device path of the mouse
#########
mouse_name = "USB OPTICAL MOUSE "
device = None
for input_device in [evdev.InputDevice(path) for path in evdev.list_devices()]:
	if input_device.name == mouse_name:
		device = input_device
		break
if device is None:
	print(f"Device with name {mouse_name} not found.")
	exit()
 
# Create a virtual input device
ui = UInput.from_device(device)
 
speed_factor = .96
 
debug = None
for event in device.read_loop():
	if event.type == evdev.ecodes.EV_REL:
		event_code = evdev.ecodes.REL[event.code]
		event_value = event.value
		
		# if event_code in ['REL_X', 'REL_Y']:
		# 	event.value = int(event_value * speed_factor)
		# el
 
		if event_code == 'REL_WHEEL_HI_RES':
			if event_value == 120: # WHEEL UP
				left_click()
				continue
			elif event_value == -120: # WHEEL DOWN
				left_press()
				continue
 
	# Write all other events to the virtual device
	#time.sleep(.01)
	ui.write_event(event)
	ui.syn()
            
TODO List (C++ Kernel Version)
TODO List with NO FRAMEWORK except for bare Win32 C++ with NO external wrappers/libraries. Pure raw masochastic C++ Win32 without MFC/QT Framework.
C++
Click for Portfolio
                #include <iostream>
#include <Windows.h>
#include <Commctrl.h>
#include <math.h>
#include <vector>
#include <fstream>
 
using namespace std;
HHOOK _hook;
HMENU menu;
 
class AgendaList; // let the compiler know such a class will be defined, namely inside of AgendaItem which contains a pointer to an AgendaList
 
using namespace std;
//AgendaList prototypeg
 
int window_width = 400;
int window_height = 400;
int global_index = 0;
string agenda_items_filename = "agenda_items.txt";
 
const HFONT levi_windows_font = CreateFont(13, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, VARIABLE_PITCH, TEXT("Levi Windows"));
 
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK DestroyChildCallback( HWND , LPARAM);
 
//resets every single control, for the add & delete operations
BOOL CALLBACK DestroyChildCallback( HWND   hwnd, LPARAM lParam)
{
  if (hwnd != NULL) {
    DestroyWindow(hwnd);
  }
  return TRUE;
}
 
 
 
class AgendaItem
{
    //get a static class variable to keep track of the number of agenda items
private:
    int id;
    static int last_id;
    
    string text;
 
    AgendaList *parent_list;
    int agenda_item_margin = 10;
    int agenda_item_padding = 20;
    int agenda_item_height = 60;
    int agenda_item_x = 0;
    double agenda_item_y = id * agenda_item_height;
    //I don't know why i had to do the (2 * agenda_item_padding) twice
    int agenda_item_width = window_width - (2 * agenda_item_margin) - (2 * agenda_item_margin);
    int groupbox_x;
    int groupbox_y;
    int groupbox_height;
    int groupbox_width;
    int text_box_x;
    int text_box_y;
    int text_box_height;
    int text_box_width;
    int add_button_x;
    int add_button_y;
    int add_button_height;
    int add_button_width;
    int close_button_x;
    int close_button_y;
    int close_button_height;
    int close_button_width;
 
    HWND groupbox;
    HWND textbox;
    HWND button_add;
    HWND button_delete;
    vector<HWND> agenda_item_controls;
 
public:
    AgendaItem(HWND& parent_hwnd, string text_in)
    {
        this->text = text_in;
        this->id = last_id;
        last_id++;
        calculate_positions();
        draw(parent_hwnd);
        ///get the userdata from a previous call of SetWindowLongPtr(parent_hwnd, GWLP_USERDATA, (LONG_PTR)this);
        ///that will represent the Parent Agenda List
        this->parent_list = (AgendaList*)GetWindowLongPtr(parent_hwnd, GWLP_USERDATA);
    }
    void calculate_positions()
    {
        agenda_item_y = id * agenda_item_height;
        groupbox_x = round(agenda_item_x + agenda_item_margin);
        groupbox_y = agenda_item_y + agenda_item_margin;
        groupbox_height = round(agenda_item_height);
        groupbox_width = round(agenda_item_width);
        text_box_x = round(agenda_item_x + agenda_item_padding);
        text_box_y = round(agenda_item_y + agenda_item_margin + agenda_item_padding);
        text_box_height = round(agenda_item_height * 0.33);
        text_box_width = round(agenda_item_width * 0.6);
        add_button_x = round(agenda_item_width * 0.75);
        add_button_y = round(agenda_item_y + agenda_item_margin + agenda_item_padding);
        add_button_height = round(agenda_item_height * 0.33);
        add_button_width = round(agenda_item_width * 0.07);
        close_button_x = round(agenda_item_width * 0.85);
        close_button_y = round(agenda_item_y + agenda_item_margin + agenda_item_padding);
        close_button_height = round(agenda_item_height * 0.33);
        close_button_width = round(agenda_item_width * 0.07);
    }
    void print_all_values_in_calculate_positions()
    {
        cout << "agenda_item_x: " << agenda_item_x << endl;
        cout << "agenda_item_y: " << agenda_item_y << endl;
        cout << "agenda_item_height: " << agenda_item_height << endl;
        cout << "agenda_item_width: " << agenda_item_width << endl;
        cout << "groupbox_x: " << groupbox_x << endl;
        cout << "groupbox_y: " << groupbox_y << endl;
        cout << "groupbox_height: " << groupbox_height << endl;
        cout << "groupbox_width: " << groupbox_width << endl;
        cout << "text_box_x: " << text_box_x << endl;
        cout << "text_box_y: " << text_box_y << endl;
        cout << "text_box_height: " << text_box_height << endl;
        cout << "text_box_width: " << text_box_width << endl;
        cout << "add_button_x: " << add_button_x << endl;
        cout << "add_button_y: " << add_button_y << endl;
        cout << "add_button_height: " << add_button_height << endl;
        cout << "add_button_width: " << add_button_width << endl;
        cout << "close_button_x: " << close_button_x << endl;
        cout << "close_button_y: " << close_button_y << endl;
        cout << "close_button_height: " << close_button_height << endl;
        cout << "close_button_width: " << close_button_width << endl;
        cout << "------------------------------------" << endl;
    }
    void draw(HWND& parent_hwnd)
    {
        
        calculate_positions();
        //** NOTE. For some reason, I had to have the buttons in the groupbox have a parent that is not the groupbox, but the parent of the groupbox. The buttons weren't showing up. **//
 
 
        //define the text string to display for the groupbox
        string groupbox_text = "Agenda Item #" + to_string(id);
 
        //define group box with different id's so that we can identify them later
        groupbox = CreateWindowEx(0,
            TEXT("BUTTON"),
            TEXT(groupbox_text.c_str()),
            WS_CHILD | WS_VISIBLE | BS_GROUPBOX,
            groupbox_x,
            groupbox_y,
            groupbox_width,
            groupbox_height,
            parent_hwnd,
            (HMENU)id,
            GetModuleHandle(NULL),
            NULL);
 
        textbox = CreateWindow("EDIT",                                                       //
            text.c_str(),                                                 // text
            WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | ES_AUTOHSCROLL | WS_GROUP, // styles
            text_box_x,                                                   // x
            text_box_y,                                                   // y
            text_box_width,                                               // width
            text_box_height,                                              // height
            parent_hwnd,                                                  // parent
            (HMENU)1,                                                     // menu
            NULL,                                                         // hInstance
            NULL);                                                        // no extra parameters
 
        button_add = CreateWindow("Button", //
         "+",  // text
         WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, // styles
         add_button_x, // x
         add_button_y, // y
         add_button_width, // width
         add_button_height, // height
         parent_hwnd, // parent
         (HMENU)2, // menu
         NULL, // hInstance 
         NULL); // no extra parameters
 
        button_delete = CreateWindow("Button", //
         "x",  // text
         WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, // styles
         close_button_x, // x
         close_button_y, // y
         close_button_width, // width
         close_button_height, // height
         parent_hwnd, // parent
         (HMENU)3, // menu
         NULL, // hInstance 
         NULL); // no extra parameters
 
 
        //Set the UserData for the buttons with the AgendaItem of the AgendaList, via the "this" variable. If I had to do multiple variables, it was possible to put them in a struct. If you know other ways to do this, please let me know.
        //I researched CreateDialogParam, but I hit an impasse
        //
        //in Short, this links the buttons to the AgendaItem
        SetWindowLongPtr(textbox, GWLP_USERDATA, (LONG_PTR)this);
        SetWindowLongPtr(button_add, GWLP_USERDATA, (LONG_PTR)this);
        SetWindowLongPtr(button_delete, GWLP_USERDATA, (LONG_PTR)this);
 
        //every button uses the font in the variable "font"
        SendMessage(groupbox, WM_SETFONT, (WPARAM)levi_windows_font, TRUE);
        SendMessage(textbox, WM_SETFONT, (WPARAM)levi_windows_font, TRUE);
        SendMessage(button_add, WM_SETFONT, (WPARAM)levi_windows_font, TRUE);
        SendMessage(button_delete, WM_SETFONT, (WPARAM)
        levi_windows_font, TRUE);
 
        //fill the vector with the buttons
        agenda_item_controls.push_back(groupbox);
        agenda_item_controls.push_back(textbox);
        agenda_item_controls.push_back(button_add);
        agenda_item_controls.push_back(button_delete);
 
 
    }
    int get_id()
    {
        return id;
    }
    string get_text()
    {
        return text;
    }
    void set_id(int new_id)
    {
        id = new_id;
    }
    HWND get_textbox()
    {
        return textbox;
    }
    void set_text(string text_in)
    {
        text = text_in;
    }
    vector<HWND> get_agenda_item_controls()
    {
        return agenda_item_controls;
    }
};
 
 
//get a static class variable to keep track of the number of agenda items
int AgendaItem::last_id = 0;
 
 
 
 
class AgendaList
{
private:
    HWND parent_hwnd;
    vector<AgendaItem*> agenda_items;
public:
    AgendaList(HWND& parent_hwnd)
    {
        cout << "AgendaList this: " << this << endl;
        //set userdata to this window
        cout << "this: " << this << endl;
        this->parent_hwnd = parent_hwnd;
    }
    //mainly done in initial creation
    AgendaItem* create_agenda_item(HWND &parent_hwnd, string text_in)
    {
        AgendaItem* item = new AgendaItem(parent_hwnd, text_in);
        agenda_items.push_back(item);
        return item;
    }
    void delete_agenda_item(AgendaItem* agenda_item)
    {
        //error if trying to go out of bounds
        if(agenda_items.size() <= 1)
        {
            MessageBox(parent_hwnd, "You must have at least one agenda list item.", "Error", MB_OK | MB_ICONEXCLAMATION);
            return;
        }
        //find the item in the vector and delete it
        for (int i = 0; i < agenda_items.size(); i++)
        {
            if (agenda_items[i] == agenda_item)
            {
                agenda_items.erase(agenda_items.begin() + i);
            }
        }
    }
    AgendaItem* add_new_agenda_item_below(AgendaItem* agenda_item)
    {
        int id = agenda_item->get_id();
        //new AgendaItem
        AgendaItem *new_agenda_item = new AgendaItem(parent_hwnd, "");
        //set the id of the new AgendaItem to the id of the old one + 1
        new_agenda_item->set_id(id + 1);
        //insert the new AgendaItem into the vector
        agenda_items.insert(agenda_items.begin() + id + 1, new_agenda_item);
        //raise the ID's of all the other AgendaItems after the new one
        for (int i = id + 1; i < agenda_items.size(); i++)
        {
            agenda_items[i]->set_id(agenda_items[i]->get_id() + 1);
        }
        return new_agenda_item;
    }
    int get_num_agenda_items()
    {
        return agenda_items.size();
    }
    void redraw(HWND& parent_hwnd)
    {
        //clears the window
        RECT rect;
        GetClientRect(parent_hwnd, &rect);
        FillRect(GetDC(parent_hwnd), &rect, (HBRUSH)CreateSolidBrush(RGB(240, 240, 240)));
        //Destroy all the child windows in the parent window (Parent HWND Handle)
        EnumChildWindows(parent_hwnd, DestroyChildCallback, (LPARAM)&parent_hwnd);
        //Set the new ids, AND draw the new buttons
        int index = 0;
        for (auto &item : agenda_items)
        {
            item->set_id(index++);
            item->draw(parent_hwnd);
        }    
    }
    vector<AgendaItem*> get_agenda_items()
    {
        return agenda_items;
    }
    BOOL save_into_text_file()
    {
        //open the file
        ofstream file;
        file.open(agenda_items_filename);
        //if the file is not open, return false
        if (!file.is_open())
        {
            return FALSE;
        }
        //write the text from each AgendaItem into the file
        for (auto &item : agenda_items)
        {
            file << item->get_text() << endl;
        }
        //close the file
        file.close();
        return TRUE;
    }
};
 
 
 
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
        case WM_CREATE:
        {
            AgendaList* agenda_list = new AgendaList(hwnd);   
            //Initialize via filename
            ifstream file;
            file.open(agenda_items_filename);
            //FILE DOES NOT EXIST
            if (!file.is_open())
            {
                AgendaItem *a1 = agenda_list->create_agenda_item(hwnd, "test");
                AgendaItem *a2 = agenda_list->create_agenda_item(hwnd, "grell");
                AgendaItem *a3 = agenda_list->create_agenda_item(hwnd, "grain");
            }
            //FILE DOES EXIST
            else
            {
                string line;
                while (getline(file, line))
                {
                    agenda_list->create_agenda_item(hwnd, line);
                }
            }
            //attack agenda_list to the parent main window
            SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)agenda_list);
            break;
        }
        case WM_COMMAND:
        {
            switch (LOWORD(wParam))
            {
            //clicking on the text edit box
            case 1:
            {
                //HIWORD(wParam) is the control-defined notification code according to the docs at https://docs.microsoft.com/en-us/windows/win32/menurc/wm-command
                //The notification codes for this edit box is located in https://docs.microsoft.com/en-us/windows/win32/controls/en-killfocus
                //I was unable to use WM_NOTIFY, it only worked with WM_COMMAND
                if(HIWORD(wParam) == EN_KILLFOCUS)
                {
                    HWND textbox = (HWND)lParam;
                    //get text
                    char buffer[256];
                    GetWindowText(textbox, buffer, 256);
                    //get the agenda list
                    AgendaList* agenda_list = (AgendaList*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
                    //get the current agenda item
                    AgendaItem* agenda_item = (AgendaItem*)GetWindowLongPtr(textbox, GWLP_USERDATA);
                    //set the text of the current agenda item
                    agenda_item->set_text(buffer);
                    agenda_list->save_into_text_file();
                }
                break;
            }
            //add agenda item
            case 2:
            {
                //get the button
                HWND button = (HWND)lParam;
                //get the userdata from the button (agenda item)
                AgendaItem* agenda_item = (AgendaItem*)GetWindowLongPtr(button, GWLP_USERDATA);
                //get agenda list (attached to this HWND durig WM_CREATE)
                AgendaList *agenda_list = (AgendaList *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
                cout << "size: " << agenda_list->get_num_agenda_items() << endl;
                AgendaItem* new_agenda_item = agenda_list->add_new_agenda_item_below(agenda_item);
                agenda_list->redraw(hwnd);
                SetFocus(new_agenda_item->get_textbox());
                cout << "size: " << agenda_list->get_num_agenda_items() << endl;
                break;
            }
            //deleting in an agenda item
            case 3:
            {
                //get the button
                HWND button = (HWND)lParam;
                //get the userdata from the button (attached to the agenda item)
                AgendaItem* agenda_item = (AgendaItem*)GetWindowLongPtr(button, GWLP_USERDATA);
                //get agenda list (attached to this HWND durig WM_CREATE)
                AgendaList* agenda_list = (AgendaList*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
                cout << "size: " << agenda_list->get_num_agenda_items() << endl;
                agenda_list->delete_agenda_item(agenda_item);
                agenda_list->redraw(hwnd);
                cout << "size: " << agenda_list->get_num_agenda_items() << endl;
                break;      
 
            }
            }
            break;
        }
        //change the colors of buttons
        case WM_CTLCOLORBTN:
        {
            //get the button
            HWND button = (HWND)lParam;
            //get the userdata from the button (attached to the agenda item)
            AgendaItem* agenda_item = (AgendaItem*)GetWindowLongPtr(button, GWLP_USERDATA);
            //get the color of the button
            COLORREF color = RGB(128,255,128);
            //set the color of the button
            SetBkColor((HDC)wParam, color);
            return (LRESULT)CreateSolidBrush(color);
        }
        case WM_LBUTTONDOWN:
            cout << "Left button down" << endl;
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}
HWND create_window(int width, int height)
{
    HWND hwnd;
    WNDCLASSEX wc;
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = 0;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = GetModuleHandle(NULL);
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    //the typical gray background color
    HBRUSH gray;
    gray = CreateSolidBrush(RGB(240, 240, 240));
    wc.hbrBackground = gray;
    wc.lpszMenuName = NULL;
    wc.lpszClassName = "Class";
    wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    if (!RegisterClassEx(&wc))
    {
        MessageBox(NULL, "Window Registration Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return NULL;
    }
    hwnd = CreateWindowEx(
        WS_EX_CLIENTEDGE,
        "Class", //
        "Agenda",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, 
        CW_USEDEFAULT, 
        width, height,
        NULL,
        NULL, //
        GetModuleHandle(NULL), NULL);
    if (hwnd == NULL)
    {
        MessageBox(NULL, "Window Creation Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return NULL;
    }
    return hwnd;
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    HWND hwnd;
    hwnd = create_window(window_width, window_height);
    //divide three sections of that window  
    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
        if (IsDialogMessage(hwnd, &msg) == 0)
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    return 0;
}
            
Homemade Task Manager (Win32)
A lightning fast pop-up view of the currently running processes on a computer (Win32 C++ with no external wrappers). There are no magic Win32 kernel functions to get the CPU percentage of a process, unlike other metrics. Manual calculation.
C++
Click for Portfolio
                #include <iostream>
#include <Windows.h>
#include <Commctrl.h>
#include <tlhelp32.h>
#include <psapi.h>
#include <algorithm>
#include <vector>
#include <map>
#include <math.h>
#include <ctime>
 
int pop_up_width, pop_up_height;
using namespace std;
 
int pop_up_padding = 5;
int size_of_font = 18;
HFONT windows_95_font = CreateFont(size_of_font, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, VARIABLE_PITCH, TEXT("System"));
 
struct ProcessTimes
{
    FILETIME fileTimeCreation;
    FILETIME fileTimeExit;
    FILETIME fileTimeKernel;
    FILETIME fileTimeUser;
    FILETIME lastFileTimeCreation;
    FILETIME lastFileTimeExit;
    FILETIME lastFileTimeKernel;
    FILETIME lastFileTimeUser;
};
 
map<DWORD, ProcessTimes *> processTimesMap;
 
double get_cpu_percentage(HANDLE hProcess)
{
    DWORD process_id = GetProcessId(hProcess);
    //if the structure is NOT IN MAP, ADD IT
    ProcessTimes *processTimes;
    if (processTimesMap.find(process_id) == processTimesMap.end())
    {
        processTimes = new ProcessTimes();
        FILETIME creationTime;
        FILETIME exitTime;
        FILETIME kernelTime;
        FILETIME userTime;
        int unit_of_process_usage;
        GetProcessTimes(hProcess, &creationTime, &exitTime, &kernelTime, &userTime);
        processTimes->fileTimeCreation = creationTime;
        processTimes->fileTimeExit = exitTime;
        processTimes->fileTimeKernel = kernelTime;
        processTimes->fileTimeUser = userTime;
        processTimesMap[process_id] = processTimes;
    }
    //if the structure IS IN MAP, UPDATE IT
    else
    {
        processTimes = processTimesMap[process_id];
        FILETIME creationTime;
        FILETIME exitTime;
        FILETIME kernelTime;
        FILETIME userTime;
        GetProcessTimes(hProcess, &creationTime, &exitTime, &kernelTime, &userTime);
        processTimes->fileTimeCreation = creationTime;
        processTimes->fileTimeExit = exitTime;
        processTimes->fileTimeKernel = kernelTime;
        processTimes->fileTimeUser = userTime;
    }
 
    //get the difference between the last time and the current time
    ULARGE_INTEGER kernelTimeDifference;
    kernelTimeDifference.HighPart = processTimes->fileTimeKernel.dwHighDateTime - processTimes->lastFileTimeKernel.dwHighDateTime;
    kernelTimeDifference.LowPart = processTimes->fileTimeKernel.dwLowDateTime - processTimes->lastFileTimeKernel.dwLowDateTime;
    ULARGE_INTEGER userTimeDifference;
    userTimeDifference.HighPart = processTimes->fileTimeUser.dwHighDateTime - processTimes->lastFileTimeUser.dwHighDateTime;
    userTimeDifference.LowPart = processTimes->fileTimeUser.dwLowDateTime - processTimes->lastFileTimeUser.dwLowDateTime;
 
    double unit_of_process_usage = (double)((kernelTimeDifference.QuadPart + userTimeDifference.QuadPart));
 
    double cpu_percentage = ((double)unit_of_process_usage / (double)GetTickCount()) * 100;
 
    ////THE RATIOS OF THE PROCESSES ARE ACCURATE, BUT NOT THE EXACT NUMBER FROM TASK MANAGER, unless I divide by 18. The numbers in the task manager were 18 times less the number calculated above. Sorry if this is not perfect. I don't know the exact way to calculate the cpu usage with the factor below. My interest lies in many other projects.
    cpu_percentage /= 18;
 
    processTimes->lastFileTimeCreation = processTimes->fileTimeCreation;
    processTimes->lastFileTimeExit = processTimes->fileTimeExit;
    processTimes->lastFileTimeKernel = processTimes->fileTimeKernel;
    processTimes->lastFileTimeUser = processTimes->fileTimeUser;
    return cpu_percentage;
}
 
vector<vector<string>> get_processes_information()
{
    // get list of processes
    HANDLE hProcessSnap;
    PROCESSENTRY32 pe32;
    vector<vector<string>> processes_information;
    int total_processes_to_show = 30;
 
    hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hProcessSnap == INVALID_HANDLE_VALUE)
    {
        return {};
    }
    pe32.dwSize = sizeof(PROCESSENTRY32);
    if (!Process32First(hProcessSnap, &pe32))
    {
        CloseHandle(hProcessSnap);
        return {};
    }
    do
    {
        HANDLE hProcess;
        PROCESS_MEMORY_COUNTERS pmc;
        hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pe32.th32ProcessID);
        if (hProcess == NULL)
        {
            //do nothing if process is not opened
            continue;
        }
        if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc)))
        {
            int memory_kbs = (int)(pmc.WorkingSetSize / 1024);
            string process_name = pe32.szExeFile;
            DWORD process_id = pe32.th32ProcessID;
            vector<string> process_info;
            double cpu_percentage = get_cpu_percentage(hProcess);
            PDWORD handle_count_struct_instance = new DWORD;
            GetProcessHandleCount(hProcess, handle_count_struct_instance);
            int handle_count = *handle_count_struct_instance;
            process_info.push_back(process_name);
            process_info.push_back(to_string(memory_kbs));
            process_info.push_back(to_string(process_id));
            process_info.push_back(to_string(handle_count));
            process_info.push_back(to_string(cpu_percentage));
            processes_information.push_back(process_info);
            process_info.clear();
            delete handle_count_struct_instance;
        }
        CloseHandle(hProcess);
    } while (Process32Next(hProcessSnap, &pe32));
    CloseHandle(hProcessSnap);
 
    // sort processes by memory
    sort(processes_information.begin(), processes_information.end(), [](vector<string> a, vector<string> b)
         { return stoi(a[1]) > stoi(b[1]); });
    //slice this vector to show only top 20 processes
    processes_information.erase(processes_information.begin() + total_processes_to_show, processes_information.end());
    return processes_information;
}
 
LRESULT WINAPI WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    switch (Msg)
    {
    case WM_CREATE:
    {
        break;
    }
    //paint the popup to salmon
    case WM_TIMER:
    {
 
        int cell_width = 125;
        int column_2_distance = 125;
        int column_3_distance = 225;
        int column_4_distance = 325;
        int column_5_distance = 450;
 
        //adds a box
        HDC hdcWindow = GetDC(hWnd);
        RECT rect;
        GetClientRect(hWnd, &rect);
        HBRUSH salmon = CreateSolidBrush(RGB(255, 127, 90));
        COLORREF dark_blue = RGB(20, 0, 80);
        FillRect(hdcWindow, &rect, salmon);
        //font for the text
        SelectObject(hdcWindow, windows_95_font);
        SetTextColor(hdcWindow, dark_blue);
        SetBkMode(hdcWindow, TRANSPARENT);
        //add text
        auto processes_information = get_processes_information();
        // SelectObject(hdcWindow, windows_95_font);
        // SetTextColor(hdcWindow, dark_blue);
        // SetBkMode(hdcWindow, TRANSPARENT);
        // DrawText(hdcWindow, TEXT("Processes"), -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE );
        for (int i = 0; i < processes_information.size(); i++)
        {
            int line_height = size_of_font - 2;
            RECT text_rect = {pop_up_padding,                     //left
                              (i * (line_height)),                //top
                              pop_up_padding + cell_width,        //right
                              (i * (line_height)) + line_height}; //bottom
            DrawText(hdcWindow, TEXT(processes_information[i][0].c_str()), -1, &text_rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
            // draw the text of memory usage right after the process name
            text_rect.left = pop_up_padding + column_2_distance;
            text_rect.right = pop_up_padding + column_2_distance + cell_width;
            DrawText(hdcWindow, TEXT((processes_information[i][1] + " KB").c_str()), -1, &text_rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
            // draw the text of process id right after the memory usage
            text_rect.left = pop_up_padding + column_3_distance;
            text_rect.right = pop_up_padding + column_3_distance + cell_width;
            DrawText(hdcWindow, TEXT(("ID: " + processes_information[i][2]).c_str()), -1, &text_rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
            // draw the text of process id right after the memory usage
            text_rect.left = pop_up_padding + column_4_distance;
            text_rect.right = pop_up_padding + column_4_distance + cell_width;
            DrawText(hdcWindow, TEXT(("Handles: " + processes_information[i][3]).c_str()), -1, &text_rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
            // draw the text of process id right after the memory usage
            text_rect.left = pop_up_padding + column_5_distance;
            text_rect.right = pop_up_padding + column_5_distance + cell_width;
            DrawText(hdcWindow, TEXT(("CPU: " + processes_information[i][4] + "%").c_str()), -1, &text_rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
        }
        DeleteObject(salmon);
        DeleteObject(hdcWindow);
        return 0;
    }
    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdcWindow = BeginPaint(hWnd, &ps);
        RECT rect;
        GetClientRect(hWnd, &rect);
        HBRUSH salmon = CreateSolidBrush(RGB(255, 127, 90));
        COLORREF dark_blue = RGB(20, 0, 80);
        FillRect(hdcWindow, &rect, salmon);
        DeleteObject(salmon);
        DeleteObject(hdcWindow);
        EndPaint(hWnd, &ps);
        return 0;
    }
    case WM_ERASEBKGND:
        return 1;
    case WM_CLOSE:
    case WM_DESTROY:
    {
        PostQuitMessage(0);
    }
        return 0;
    }
    return DefWindowProc(hWnd, Msg, wParam, lParam);
}
 
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrev, LPSTR lpCmdLine, int nShowCmd)
{
    int screen_width = GetSystemMetrics(SM_CXSCREEN),
        screen_height = GetSystemMetrics(SM_CYSCREEN);
 
    int padding = 30;
    int left_padding = padding;
    int top_padding = padding;
    int right_padding = padding;
    int bottom_padding = padding;
 
    pop_up_width = round(GetSystemMetrics(SM_CXSCREEN) * 0.45);
    pop_up_height = round(GetSystemMetrics(SM_CYSCREEN) * 0.66);
 
    //salmon brush HBRUSH
    HBRUSH salmon = CreateSolidBrush(RGB(255, 127, 90));
    //salmon pen HPEN
    HPEN salmon_pen = CreatePen(PS_SOLID, 1, RGB(255, 127, 90));
    WNDCLASS wndClass = {0, WndProc, 0, 0, hInstance, NULL, LoadCursor(NULL, IDC_ARROW), 0, NULL, "popup_process"};
    if (!RegisterClass(&wndClass))
        return MessageBox(HWND_DESKTOP, "Cannot register class!", NULL, MB_ICONERROR | MB_OK);
    HWND hWnd = CreateWindowEx(WS_EX_TOPMOST, "popup_process", "popup_process", WS_POPUP,
                               screen_width - pop_up_width - right_padding, screen_height / 2 - pop_up_height / 2, pop_up_width, pop_up_height, NULL, NULL, hInstance, NULL);
    //start timer
    SetTimer(hWnd, 1, 1000, NULL);
 
    if (!hWnd)
        return MessageBox(HWND_DESKTOP, "Cannot create window!", NULL, MB_ICONERROR | MB_OK);
    MSG Msg = {0};
    //show & update window
    ShowWindow(hWnd, nShowCmd);
    UpdateWindow(hWnd);
 
    while (Msg.message != WM_QUIT)
    {
        if (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&Msg);
            DispatchMessage(&Msg);
        }
        if (GetAsyncKeyState(VK_ESCAPE) & 0x8000)
            DestroyWindow(hWnd);
    }
    return 0;
}

            
Stop Frozen Windows Processes above 250000 KB
Raw C++ Win32 program to terminate processes that are above 250000 KB, to speed up the computer instantaneously. Very great tool to use with AutoHotKey (Win+K)
C++
Click for Portfolio
                #include <iostream>
#include <Windows.h>
#include <Commctrl.h>
#include <tlhelp32.h>
#include <psapi.h>
#include <algorithm>
#include <vector>
#include <ctime>
using namespace std;
HHOOK _hook;
HMENU menu;
void terminate_process(int pid);
 
LRESULT __stdcall HookCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
    return CallNextHookEx(_hook, nCode, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    // get list of processes
    HANDLE hProcessSnap;
    PROCESSENTRY32 pe32;
    hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hProcessSnap == INVALID_HANDLE_VALUE)
    {
        return 0;
    }
    pe32.dwSize = sizeof(PROCESSENTRY32);
    if (!Process32First(hProcessSnap, &pe32))
    {
        CloseHandle(hProcessSnap);
        return 0;
    }
    do
    {
        HANDLE hProcess;
        PROCESS_MEMORY_COUNTERS pmc;
        hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pe32.th32ProcessID);
        if (hProcess == NULL)
        {
            cout << pe32.szExeFile << " could not be opened" << endl;
            continue;
        }
        if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc)))
        {
            cout << pe32.szExeFile << " has " << pmc.WorkingSetSize / 1024 << " KB of memory" << endl;
        }
        int memory_kbs = (int)(pmc.WorkingSetSize / 1024);
        // if memory is greater than 250000 MB, kill the process
        if (memory_kbs > 250000)
        {
            cout << endl << "Killing " << pe32.szExeFile << endl;
            //DWORD to INT
            int pid = pe32.th32ProcessID;
            terminate_process(pid);
        }
 
        CloseHandle(hProcess);
    } while (Process32Next(hProcessSnap, &pe32));
    CloseHandle(hProcessSnap);
    return 1;
}
 
 
 
void terminate_process(int pid)
{
    HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
    if (hProcess == NULL)
    {
        cout << "Could not open process" << endl;
        return;
    }
    if (!TerminateProcess(hProcess, 0))
    {
        cout << "Could not terminate process" << endl;
        return;
    }
    CloseHandle(hProcess);
}
            
Colliding Objects On Desktop
Win32 C++ pop-up app (using WS_POPUP) to show words colliding, with a transparent background
C++
Click for Portfolio
                #include <iostream>
#include <Windows.h>
#include <Commctrl.h>
#include <tlhelp32.h>
#include <math.h>
#include <psapi.h>
#include <algorithm>
#include <vector>
#include <ctime>
using namespace std;
 
int pop_up_height, pop_up_width;
int moving_speed = 5;
int total_words = 15;
int milliseconds_between_frames = 15;
int j = 0;
void add_transparent_text_to_desktop(HWND &, HDC &, HDC &);
BOOL did_rects_collide(RECT, RECT);
void bounce_rectangles(RECT, RECT);
struct Word;
vector<pair<Word *, Word *>> all_collisions;
COLORREF rainbow_generator(int);
 
struct Word
{
    string content;
    int x, y;
    POINT path_coordinates[2]{{0, 0}, {0, 0}};
    double x_speed, y_speed;
    int width, height;
    RECT rect;
    int id;
    bool currently_dragging;
 
    static int last_id;
    COLORREF color;
    int color_index;
    //constructor taking in word
    Word(string word_in)
    {
        content = word_in;
        x = rand() % pop_up_width;
        y = rand() % pop_up_height;
        //x_speed is random number between -20 and 20
        x_speed = (rand() % moving_speed * 2) - moving_speed;
        y_speed = (rand() % moving_speed * 2) - moving_speed;
        width = 0;
        height = 0;
        RECT rect;
        rect.left = x;
        rect.top = y;
        rect.right = x + width;
        rect.bottom = y + height;
        color_index = 170;
        color = rainbow_generator(color_index);
    }
    //new method
    BOOL is_clicked(int x, int y)
    {
        if (x > rect.left && x < rect.right && y > rect.top && y < rect.bottom)
        {
            return true;
        }
        return false;
    }
};
 
class Context
{
private:
    HDC hDC;
    HDC hCDC;
    HWND hWnd;
    static Context *instance;
    vector<Word *> words;
 
public:
    static Context &get_instance()
    {
        static Context instance;
        return instance;
    }
    void set_all_handles(HDC hDC_in, HDC hCDC_in, HWND hWnd_in)
    {
        hDC = hDC_in;
        hCDC = hCDC_in;
        hWnd = hWnd_in;
    }
    void add_word(string word)
    {
        Word *new_word = new Word(word);
        words.push_back(new_word);
    }
    void add_words(string content, int number_of_words)
    {
        for (int i = 0; i < number_of_words; i++)
        {
            add_word(content);
        }
    }
    vector<Word *> get_words()
    {
        return words;
    }
    HDC get_hDC()
    {
        return hDC;
    }
    HDC get_hCDC()
    {
        return hCDC;
    }
    HWND get_hWnd()
    {
        return hWnd;
    }
    void delete_words_from_memory()
    {
        for (auto &word : words)
        {
            delete word;
        }
    }
};
 
Context context = Context::get_instance();
 
double old_x_speed = 0;
double old_y_speed = 0;
 
enum direction
{
    nw,
    ne,
    sw,
    se
};
 
direction direction_path_coordinates_went(Word word_param)
{
    if ((word_param.path_coordinates[0].x - word_param.path_coordinates[1].x > 0) && (word_param.path_coordinates[0].y - word_param.path_coordinates[1].y > 0))
    {
        return nw;
    }
    else if ((word_param.path_coordinates[0].x - word_param.path_coordinates[1].x > 0) && (word_param.path_coordinates[0].y - word_param.path_coordinates[1].y < 0))
    {
        return sw;
    }
    else if ((word_param.path_coordinates[0].x - word_param.path_coordinates[1].x < 0) && (word_param.path_coordinates[0].y - word_param.path_coordinates[1].y > 0))
    {
        return ne;
    }
    else if ((word_param.path_coordinates[0].x - word_param.path_coordinates[1].x < 0) && (word_param.path_coordinates[0].y - word_param.path_coordinates[1].y < 0))
    {
        return se;
    }
    else
    {
        return nw;
    }
}
 
//define mouseproc
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode == HC_ACTION)
    {
        //drag behavior
        // if (wParam == WM_MOUSEMOVE && GetAsyncKeyState(VK_LBUTTON) == -32768)
        if (wParam == WM_LBUTTONDOWN || (wParam == WM_MOUSEMOVE && GetAsyncKeyState(VK_LBUTTON) == -32768))
        {
            //get mouse coordinates
            POINT p;
            GetCursorPos(&p);
            int arrow_x = p.x;
            int arrow_y = p.y;
            //check if any of the words are clicked
            for (auto &word : context.get_words())
            {
                if (word->is_clicked(arrow_x, arrow_y))
                {
                    word->x = arrow_x - word->width / 2;
                    word->y = arrow_y - word->height / 2;
                    word->rect.left = word->x;
                    word->rect.top = word->y;
                    word->rect.right = word->x + word->width;
                    word->rect.bottom = word->y + word->height;
                    //do not update the old speed during dragging, only restart it from the speed when mouse was first clicked
                    if (wParam != WM_MOUSEMOVE && GetAsyncKeyState(VK_LBUTTON) != -32768)
                    {
                        old_x_speed = word->x_speed;
                        old_y_speed = word->y_speed;
                    }
                    //if the path_coordinates[1] is not equal to arrow_x and arrow_y, then update the path_coordinates
                    if (word->path_coordinates[1].x != arrow_x && word->path_coordinates[1].y != arrow_y)
                    {
                        word->path_coordinates[0] = word->path_coordinates[1];
                        word->path_coordinates[1].x = arrow_x;
                        word->path_coordinates[1].y = arrow_y;
                    }
 
                    word->x_speed = 0;
                    word->y_speed = 0;
                    word->currently_dragging = true;
                    break;
                }
            }
        }
        //if mouse is released
        if (wParam == WM_LBUTTONUP)
        {
            //get mouse coordinates
            POINT p;
            GetCursorPos(&p);
            int arrow_x = p.x;
            int arrow_y = p.y;
            //check if any of the words are clicked
            for (auto &word : context.get_words())
            {
                if (word->is_clicked(arrow_x, arrow_y))
                {
                    word->currently_dragging = false;
                    direction path_coordinates_went = direction_path_coordinates_went(*word);
                    if (path_coordinates_went == nw)
                    {
                        word->x_speed = -abs(old_x_speed);
                        word->y_speed = -abs(old_y_speed);
                    }
                    else if (path_coordinates_went == ne)
                    {
                        word->x_speed = abs(old_x_speed);
                        word->y_speed = -abs(old_y_speed);
                    }
                    else if (path_coordinates_went == sw)
                    {
                        word->x_speed = -abs(old_x_speed);
                        word->y_speed = abs(old_y_speed);
                    }
                    else if (path_coordinates_went == se)
                    {
                        word->x_speed = abs(old_x_speed);
                        word->y_speed = abs(old_y_speed);
                    }
                }
            }
        }
    }
    return CallNextHookEx(NULL, nCode, wParam, lParam);
}
 
LRESULT WINAPI WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    switch (Msg)
    {
    //draw text with a transparent background (no black background
    case WM_PAINT:
    {
        return 1;
    }
 
    case WM_CREATE:
    {
        //get the context object
        context = Context::get_instance();
 
        //rect
        RECT rect;
        GetClientRect(hWnd, &rect);
        int width = rect.right - rect.left;
        int height = rect.bottom - rect.top;
        //Create DC
        //Create Compatible DC
        //Create Bitmap
        HDC hDC = GetDC(hWnd);
        HDC hCDC = CreateCompatibleDC(hDC);
        HBITMAP hBmp = CreateCompatibleBitmap(hDC, width, height);
        HBITMAP hBmpOld = (HBITMAP)SelectObject(hCDC, hBmp);
        add_transparent_text_to_desktop(hWnd, hDC, hCDC);
 
        //fill the context object
        context.set_all_handles(hDC, hCDC, hWnd);
 
        // context.add_word("One");
        // context.add_word("Two");
        // context.add_word("Three");
        // context.add_word("Four");
        // context.add_word("Five");
        // context.add_word("Six");
        // context.add_word("Seven");
        // context.add_word("Eight");
        // context.add_word("Nine");
        // context.add_word("Ten");
 
        // context.add_words("Win32 API", 5);
        // context.add_words("Rust", 3);
        // context.add_words("C++", 2);
        context.add_word("Python");
        context.add_word("C#");
        context.add_word("Juniper");
        context.add_word("Cisco");
        context.add_word("AWS");
        context.add_word("JavaScript");
 
        //Release DC
        ReleaseDC(hWnd, hDC);
        //Release Compatible DC
        DeleteDC(hCDC);
        //Release Bitmap
        DeleteObject(hBmp);
 
        break;
    }
    case WM_TIMER:
    {
        //remember that this context was created once at WM_CREATE
        // add_transparent_text_to_desktop(context.get_hWnd(), context.get_hDC(), context.get_hCDC());
 
        RECT rect;
        GetClientRect(hWnd, &rect);
        int width = rect.right - rect.left;
        int height = rect.bottom - rect.top;
        //Create DC
        HDC hDC = GetDC(hWnd);
        HDC hCDC = CreateCompatibleDC(hDC);
        HBITMAP hBmp = CreateCompatibleBitmap(hDC, width, height);
        HBITMAP hBmpOld = (HBITMAP)SelectObject(hCDC, hBmp);
        add_transparent_text_to_desktop(hWnd, hDC, hCDC);
        //clean
        DeleteDC(hCDC);
        DeleteObject(hBmp);
        ReleaseDC(hWnd, hDC);
        break;
    }
    case WM_ERASEBKGND:
        return 1;
    case WM_CLOSE:
    case WM_DESTROY:
    {
        PostQuitMessage(0);
        return 0;
    }
    }
    return DefWindowProc(hWnd, Msg, wParam, lParam);
}
 
BOOL did_rects_collide(RECT word1, RECT word2)
{
    if (word1.left < word2.right && word1.right > word2.left && word1.top < word2.bottom && word1.bottom > word2.top)
    {
        return true;
    }
 
    return false;
}
 
COLORREF rainbow_generator(int index)
{
    //index must be 0 to 255
    int red;
    int grn;
    int blu;
    int region = (int)floor((index / 255.0) * 6);
    int chunk = (int)((floor(index % 43) / 43) * 255);
    switch (region)
    {
    case 0:
        red = 255;
        grn = chunk;
        blu = 0;
        break; //red
    case 1:
        red = 255 - chunk;
        grn = 255;
        blu = 0;
        break; //yellow
    case 2:
        red = 0;
        grn = 255;
        blu = chunk;
        break; //green
    case 3:
        red = 0;
        grn = 255 - chunk;
        blu = 255;
        break; //cyan
    case 4:
        red = chunk;
        grn = 0;
        blu = 255;
        break; //blue
    case 5:
        red = 255;
        grn = 0;
        blu = 255 - chunk;
        break; //magenta
    }
    return RGB(red, grn, blu);
}
 
void add_transparent_text_to_desktop(HWND &hWnd, HDC &hDC, HDC &hCDC)
{
    RECT rect;
    GetClientRect(hWnd, &rect);
    int width = rect.right - rect.left;
    int height = rect.bottom - rect.top;
    //make font size as 50px
    LOGFONT lf;
    GetObject(GetStockObject(DEFAULT_GUI_FONT), sizeof(LOGFONT), &lf);
    lf.lfHeight = 50;
    HFONT hFont = CreateFontIndirect(&lf);
    //hfont with transparent background & white
    HFONT hFontOld = (HFONT)SelectObject(hCDC, hFont);
    //text must be transparent background. This will only work if there's a blending & UpdateLayeredWindow function below
    SetBkMode(hCDC, TRANSPARENT);
    //text color
    SetTextColor(hCDC, RGB(0, 255, 0));
 
    vector<pair<Word *, Word *>> collided_pairs_vector;
    vector<Word *> words = context.get_words();
    // cout << "words size: " << words.size() << endl;
 
    //Get a random rectangle & use DrawText function (not TextOut). Use the important DT_CALCRECT flag to get the size of the text to be drawn so I can later use the coordinates to detect collisions
 
    for (auto &word : words)
    {
 
        //honestly seems the only purpose of this RECT is to later calculate the height & width of the Text Box
        RECT word_rect;
        word_rect.left = word->x;
        word_rect.top = word->y;
        //After this call, word_rect will likely have the right & bottom fields filled
        //Also, this is actually not drawing the text
        DrawText(hCDC, word->content.c_str(), word->content.length(), &word_rect, DT_CALCRECT | DT_CENTER | DT_VCENTER);
 
        word->width = word_rect.right - word_rect.left;
        word->height = word_rect.bottom - word_rect.top;
 
        //Actually draw the text
        SetTextColor(hCDC, word->color);
        DrawText(hCDC, word->content.c_str(), word->content.length(), &word_rect, DT_CENTER | DT_VCENTER);
 
        word->x += word->x_speed;
        word->y += word->y_speed;
        //save the word's rect for collision detection
        word->rect = word_rect;
 
        //if word is off screen, move it back to the top
        if (word->x < 0)
            word->x = width;
        if (word->x > width)
            word->x = 0;
        if (word->y < 0)
            word->y = height;
        if (word->y > height)
            word->y = 0;
 
        // collision detection
        for (auto &word2 : words)
        {
            if (word != word2)
            {
                if (did_rects_collide(word_rect, word2->rect))
                {
                    //only add the pair IF the reverse pair flipped is NOT already in the collided_pairs_vector
                    pair<Word *, Word *> reversed_pair(word2, word);
                    //if the reversed pair does NOT exist in the collided_pairs_vector
                    if (find(collided_pairs_vector.begin(), collided_pairs_vector.end(), reversed_pair) == collided_pairs_vector.end())
                    {
                        collided_pairs_vector.push_back(make_pair(word, word2));
                    }
                }
            }
        }
    }
 
    //DEBUG
    // int cps = collided_pairs_vector.size();
    // if(cps > 0)
    // {
    //     for (auto &collided_pair : collided_pairs_vector)
    //     {
    //         cout << "collided pairs: ";
    //         for (auto &inner_collided_pair : collided_pairs_vector)
    //         {
    //             cout << inner_collided_pair.first->content << " " << inner_collided_pair.second->content << "     ";
    //         }
    //         cout << endl;
    //     }
    // }
 
    int distance = 5;
    //remove the pairs
    for (auto &collided_pair : collided_pairs_vector)
    {
 
        Word *word1 = collided_pair.first;
        Word *word2 = collided_pair.second;
 
        int word1_left = word1->rect.left;
        int word1_top = word1->rect.top;
        int word1_right = word1->rect.right;
        int word1_bottom = word1->rect.bottom;
 
        int word2_left = word2->rect.left;
        int word2_top = word2->rect.top;
        int word2_right = word2->rect.right;
        int word2_bottom = word2->rect.bottom;
 
        int x_diff = word1_left - word2_right;
        int y_diff = word1_top - word2_bottom;
 
        int word1_xspeed = word1->x_speed;
        int word1_yspeed = word1->y_speed;
        int word2_xspeed = word2->x_speed;
        int word2_yspeed = word2->y_speed;
 
        int margin = 1;
        //higher the dampening, the more the distance
        float dampen_difference = 0.2;
        int distance_between_words_to_turn = 2;
 
        int move_distance_x = round(x_diff * dampen_difference) + margin;
        int move_distance_y = round(y_diff * dampen_difference) + margin;
 
        //get the dragged word between word1 & word2
        Word *dragged_word;
        if (word1->currently_dragging == true)
        {
            dragged_word = word1;
        }
        else if (word2->currently_dragging == true)
        {
            dragged_word = word2;
        }
        else
            dragged_word = nullptr;
 
        word1->x = word1->x + move_distance_x;
        word2->x = word2->x - move_distance_x;
        word1->y = word1->y + move_distance_y;
        word2->y = word2->y - move_distance_y;
 
        double angle_of_collided_words = atan2(y_diff, x_diff);
        double angle_of_word1 = atan2(word1_yspeed, word1_xspeed);
        double angle_of_word2 = atan2(word2_yspeed, word2_xspeed);
        double angle_difference = atan2(y_diff, x_diff) - atan2(word1_yspeed, word1_xspeed);
        double angle_difference2 = atan2(y_diff, x_diff) - atan2(word2_yspeed, word2_xspeed);
        double angle_difference_to_turn = angle_difference / distance_between_words_to_turn;
        double angle_difference_to_turn2 = angle_difference2 / distance_between_words_to_turn;
        double new_angle_of_word1 = angle_of_word1 + angle_difference_to_turn;
        double new_angle_of_word2 = angle_of_word2 - angle_difference_to_turn2;
 
        // cout << "angle of word 1: " << angle_of_word1 << " angle of word 2: " << angle_of_word2 << " angle difference: " << angle_difference << " angle difference2: " << angle_difference2 << " angle difference to turn: " << angle_difference_to_turn << " angle difference to turn2: " << angle_difference_to_turn2 << " new angle of word 1: " << new_angle_of_word1 << " new angle of word 2: " << new_angle_of_word2 << endl;
        // cout << '-----------' << endl;
 
        word1->x_speed = (cos(new_angle_of_word1) > 0) ? cos(new_angle_of_word1) * moving_speed : cos(new_angle_of_word1) * moving_speed;
        word1->y_speed = (sin(new_angle_of_word1) > 0) ? sin(new_angle_of_word1) * moving_speed : sin(new_angle_of_word1) * moving_speed;
        word2->x_speed = (cos(new_angle_of_word2) > 0) ? cos(new_angle_of_word2) * moving_speed : cos(new_angle_of_word2) * moving_speed;
        word2->y_speed = (sin(new_angle_of_word2) > 0) ? sin(new_angle_of_word2) * moving_speed : sin(new_angle_of_word2) * moving_speed;
 
        // If the word is currently being dragged, then we need to NOT move it
 
        //change the direction
        if (abs(max(move_distance_x, move_distance_y)) > distance_between_words_to_turn)
        {
            //if approaching in opposite directions in X
            if ((word1_xspeed > 0 && word2_xspeed < 0) || (word1_xspeed < 0 && word2_xspeed > 0))
            {
                word1->x_speed = word1->x_speed;
                word2->x_speed = word2->x_speed;
            }
            //if approaching in opposite directions in Y
            if ((word1_yspeed > 0 && word2_yspeed < 0) || (word1_yspeed < 0 && word2_yspeed > 0))
            {
                word1->y_speed = word1->y_speed;
                word2->y_speed = word2->y_speed;
            }
            int placeholder;
            //if approaching in same direction in X
            if ((word1_xspeed > 0 && word2_xspeed > 0) || (word1_xspeed < 0 && word2_xspeed < 0))
            {
                placeholder = word1_xspeed;
                word1->x_speed = word2_xspeed;
                word2->x_speed = placeholder;
                // word1->x_speed = -word1_xspeed;
                // word2->x_speed = -word2_xspeed;
            }
            //if approaching in same direction in Y
            if ((word1_yspeed > 0 && word2_yspeed > 0) || (word1_yspeed < 0 && word2_yspeed < 0))
            {
                placeholder = abs(word1_yspeed);
                word1->y_speed = abs(word2_yspeed);
                word2->y_speed = placeholder;
                // word1->y_speed = -word1->y_speed;
                // word2->y_speed = -word2->y_speed;
            }
        }
 
        //the word that's dragging doesn't move
        if (dragged_word == word1)
        {
            cout << dragged_word->content << endl;
            word1->x = word1_left;
            word1->y = word1_top;
            word1->x_speed = 0;
            word1->y_speed = 0;
        }
        else if (dragged_word == word2)
        {
            cout << dragged_word->content << endl;
            word2->x = word2_left;
            word2->y = word2_top;
            word2->x_speed = 0;
            word2->y_speed = 0;
        }
    }
 
    // Call UpdateLayeredWindow
    BLENDFUNCTION blend = {0};
    blend.BlendOp = AC_SRC_OVER;
    blend.SourceConstantAlpha = 255;
    blend.AlphaFormat = AC_SRC_ALPHA;
    SIZE sizeWnd = {width, height};
    //ptpox & ptsrc in the center
    POINT ptPos = {(GetSystemMetrics(SM_CXSCREEN) - width) / 2, (GetSystemMetrics(SM_CYSCREEN) - height) / 2};
    POINT ptSrc = {0, 0};
    UpdateLayeredWindow(hWnd, hDC, &ptPos, &sizeWnd, hCDC, &ptSrc, 0, &blend, ULW_ALPHA);
}
 
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrev, LPSTR lpCmdLine, int nShowCmd)
{
    int screen_width = GetSystemMetrics(SM_CXSCREEN),
        screen_height = GetSystemMetrics(SM_CYSCREEN);
    int padding = 30;
    int left_padding = padding;
    int top_padding = padding;
    int right_padding = padding;
    int bottom_padding = padding;
    pop_up_width = screen_width;
    pop_up_height = screen_height;
    // pop_up_width = 400;
    // pop_up_height = 400;
    WNDCLASSEX wc;
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = 0;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    //blue brush background
    wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(20, 222, 80));
    wc.lpszMenuName = NULL;
    wc.lpszClassName = "popup_process";
    wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    if (!RegisterClassEx(&wc))
    {
        MessageBox(NULL, "Window Registration Failed!", "Error!",
                   MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }
    // make a transparent window
    HWND hwnd = CreateWindowEx(WS_EX_LAYERED | WS_EX_TOPMOST,
                               "popup_process",
                               "popup_process",
                               WS_POPUP,
                               left_padding,
                               top_padding,
                               pop_up_width,
                               pop_up_height,
                               NULL,
                               NULL,
                               hInstance,
                               NULL);
    //make a transparent window
    hwnd = CreateWindowEx(WS_EX_TOPMOST | WS_EX_LAYERED, "popup_process", "popup_process", WS_POPUP, screen_width - pop_up_width - right_padding, screen_height / 2 - pop_up_height / 2, pop_up_width, pop_up_height, NULL, NULL, hInstance, NULL);
    HHOOK mouseHookHdl = SetWindowsHookEx(WH_MOUSE_LL, MouseProc, hInstance, 0);
    if (mouseHookHdl == NULL)
    {
        MessageBox(NULL, "SetWindowsHookEx for MouseProc failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }
    ShowWindow(hwnd, nShowCmd);
    UpdateWindow(hwnd);
    //work with transparency
    if (!hwnd)
        return MessageBox(HWND_DESKTOP, "Cannot create window!", NULL, MB_ICONERROR | MB_OK);
    MSG Msg = {0};
    //show & update window
    ShowWindow(hwnd, nShowCmd);
    UpdateWindow(hwnd);
    //run timer every second infiniteyl
    SetTimer(hwnd, 0, milliseconds_between_frames, NULL);
    while (Msg.message != WM_QUIT)
    {
        if (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&Msg);
            DispatchMessage(&Msg);
        }
        if (GetAsyncKeyState(VK_ESCAPE) & 0x8000)
            DestroyWindow(hwnd);
    }
    return 0;
}

            
Uforia Alexa Skill to guess numbers
Number Guessing Alexa Skill for a gaming company with amazing entrepreneur, which was ranked in top 100 on Amazon. Sound clips stored remotely when I should have used S3.
Python
Click for Portfolio
                import os, sys
from random import randrange
import boto3
 
def lambda_handler(event, context):
    try:
        #FORCED TO HAVE PROGRAM FLOW witih Try & Catch BECAUSE OF A GLITCH IN AMAZON ECHO DEVICE vs Alexa Service Simulator
        try:
            response_session_attributes = event["session"]["attributes"]
        except:
            response_session_attributes = {'debug':'problem'}
            
        is_playing = get_session_value(event,'playing')
        is_game_over = get_session_value(event,'game_over')
        is_playing = int(is_playing) if is_playing is not None else 0
        is_game_over = int(is_game_over) if is_game_over is not None else 0
        
        one_second_break = '<break time="1000ms"/>'
        half_second_break = '<break time="500ms"/>'
  
        # s3 = boto3.client("s3")
        
        #AUDIO FILES#
        audio_1 = ('bd_countdown','1_game_bd_countdown_48k.mp3','https://a.clyp.it/hzvpcfai.mp3')
        audio_2 = ('bd_intro','2_game_bd_intro_48k.mp3','https://a.clyp.it/berksyah.mp3')
        audio_3 = ('bd_win_1','3_game_bd_win1_48k.mp3','https://a.clyp.it/dmno3wxu.mp3')
        audio_4 = ('bd_hard','4_game_bd_hard_48k.mp3','https://a.clyp.it/itskfkr3.mp3')
        audio_5 = ('bd_medium','5_game_bd_medium_48k.mp3','https://a.clyp.it/hmmoie01.mp3')
        audio_6 = ('bd_win_2','6_game_bd_win_48k.mp3','https://a.clyp.it/1eozk1qj.mp3')
        audio_7 = ('bd_instructions','7_game_bd_instructions_48k.mp3','https://a.clyp.it/sstiscoz.mp3')
        audio_8 = ('bd_easy','8_game_bd_easy_48k.mp3','https://a.clyp.it/2dw3nt21.mp3')
        audio_9 = ('bd_lose','9_game_bd_lose_48k.mp3','https://a.clyp.it/odikfqdd.mp3')
        #END AUDIO FILES#
        
        
        #PLAY AGAIN#
        #
        #   Note: Reason for a state design pattern is for things just like this!
        #
        
        #END PLAY AGAIN#
 
        if event["request"]["type"] == "LaunchRequest":
            response_session_attributes['playing'] = 0
            return build_ssml_response(generate_audio_tag(audio_2[2]), 0, response_session_attributes)
        elif event["request"]["type"] == "IntentRequest":
            intent_name = event["request"]["intent"]["name"]
            #SATISFIES #2 of Amazon requirements (2017-03-23)
            if intent_name == "AMAZON.CancelIntent" or intent_name == "AMAZON.StopIntent":
                return build_ssml_response('Thank you for using Bomb Defuse. See you next time!', 1)
            #menu
            if is_playing == 0:
                #choose level section
                if intent_name == "ChooseLevelIntent":
                    if is_playing == 1:
                        return build_ssml_response("You are already playing", 0, response_session_attributes)
                    chosen_level = get_slot_value(event,'level')
                    tries_left = 0
                    
                    if chosen_level is not False:
                        if chosen_level == 'easy':
                            tries_left = 10
                            response = generate_audio_tag(audio_8[2])+ one_second_break
                        elif chosen_level == 'medium':
                            tries_left = 9
                            response = generate_audio_tag(audio_5[2])+ one_second_break
                        elif chosen_level == 'hard':
                            tries_left = 8
                            response = generate_audio_tag(audio_4[2])+ one_second_break
                        elif chosen_level == 'testing':
                            tries_left = 1
                            response = "testing" + one_second_break
                        else:
                            return build_ssml_response("Please Choose Level between Easy, Medium or Hard", 0, response_session_attributes)
                    #this is where the game really starts. It starts when level is chosen (so far)
                    response_session_attributes['tries_left'] = tries_left
                    response_session_attributes['playing'] = 1
                    maximum_number = 1000
                    response_session_attributes['maximum_number'] = maximum_number
                    response_session_attributes['correct_number'] = randrange(1,maximum_number + 1)
                    response += "Guess a number between 1 and 1000. You have %s chances" % tries_left
                    return build_ssml_response(response, 0,response_session_attributes)
                else:
                    return build_ssml_response("Please choose level among Easy, Medium or Hard!", 0,response_session_attributes)
            #we are currently playing now
            elif is_playing == 1:
                #power up section
                if intent_name == "PowerUpIntent":
                    maximum_number = get_session_value(event,'maximum_number')
                    chosen_powerup = get_slot_value(event,'powerup_type')
                    if chosen_powerup is not False:
                        if chosen_powerup == 'yellow':
                            maximum_number -= 10
                        if chosen_powerup == 'blue':
                            maximum_number -= 50
                        if chosen_powerup == 'red':
                            maximum_number -= 100
                        if chosen_powerup == 'ultimate':
                            maximum_number -= 500
                        response_session_attributes['maximum_number'] = maximum_number
                        #the "correct number" changes when there is a powerup
                        response_session_attributes['correct_number'] = randrange(1,maximum_number + 1)
                    response = "%s %s" % (maximum_number, chosen_powerup)
                    return build_ssml_response(response, 0, response_session_attributes)
                elif intent_name == "TryIntent":
                    correct_number = get_session_value(event,'correct_number')
                    correct_number = int(correct_number) if correct_number is not None else -1
                    tries_left = get_session_value(event,'tries_left')
                    chosen_number = int(get_slot_value(event,'chosen_number'))
                    #between 1 and 1000?
                    if int(chosen_number) >= 0 and int(chosen_number) <= 1000:
                        tries_left -= 1
                        word = "tries" if tries_left != 1 else "try"
                        response_session_attributes['tries_left'] = tries_left
                    else:
                        return build_ssml_response("You said %s. Please pick a number between 1 and 1000" % chosen_number,0,response_session_attributes)
                    
                    if int(correct_number) == int(chosen_number):
                        response = generate_audio_tag(audio_6[2])+ half_second_break + "Do you want to play again?"
                        card_text = "Congratulations! You won! The correct number was %s" % correct_number
                        response_session_attributes['game_over'] = 1
                        return build_ssml_response(response,0,response_session_attributes, card_text=card_text)
                    elif int(tries_left) <= 0:
                        response = generate_audio_tag(audio_9[2])+ "The correct number is %s" % correct_number + half_second_break + "Do you want to play again?"
                        card_text = "Game over. The correct number was %s" % correct_number
                        response_session_attributes['game_over'] = 1
                        return build_ssml_response(response,0,response_session_attributes, card_text=card_text)
                    elif int(correct_number) > int(chosen_number):
                        response = "Higher. You have %s %s left." % (tries_left,word)
                        #response = "%s is incorrect. Guess a higher number. You have %s %s left" % (chosen_number,tries_left,word)
                        #debug
                        # response = "Guess a higher number. You have %s %s left. Hint: %s" % (tries_left,word,correct_number)
                        return build_ssml_response(response,0,response_session_attributes)
                    elif int(correct_number) < int(chosen_number):
                        response = "Lower. You have %s %s left." % (tries_left,word)
                        #response = "%s is incorrect. Guess a lower number. You have %s %s left" % (chosen_number,tries_left,word)
                        return build_ssml_response(response,0,response_session_attributes)
                    else:
                        return build_ssml_response("Unknown Error",0,response_session_attributes)
                elif intent_name == "PlayAgainIntent" and is_game_over == 1:
                    chosen_play_again_yn = get_slot_value(event,'play_again')
                    if chosen_play_again_yn == 'yes':
                        response_session_attributes['playing'] = 0
                        response_session_attributes['game_over'] = 0
                        return build_ssml_response("Choose A Level Between Easy, Medium, or Hard",0,response_session_attributes)
                    elif chosen_play_again_yn == 'no':
                        return build_ssml_response("Thank You For playing Bomb Defuse",1,response_session_attributes)
                    else:
                        return build_ssml_response("Unknown Error",0,response_session_attributes, card_text="PlayAgainIntent called")
                else:
                     return build_ssml_response(intent + ' I did not understand. Can you say it again?', 0,response_session_attributes)
    except:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
        card_text = str(exc_type) + ' ' + str(fname) + ' ' + str(exc_tb.tb_lineno)
        response_session_attributes['card_text'] = card_text
        return build_ssml_response("I did not understand you. Can you please say it again?",0,response_session_attributes)
 
def generate_audio_tag(url):
    #
    #url = 'https://s3.amazonaws.com/alexagamefilesbucket/' + filename
    #
    #IF PRIVATE
    #
    # url = s3.generate_presigned_url('get_object', Params = {'Bucket': 'alexagamefilesbucket', 'Key': filename}, ExpiresIn = 3600)
    # url = url.replace("&","%26")
    return '<audio src="%s"/>' % url
 
def put_in_audio_tag(url):
    return '<audio src="%s"/>' % url
 
def get_session_value(event,key):
    try:
        value = event.get('session').get('attributes').get(key)
        return value
    except TypeError:
        return False
    except:
        return False
 
def get_slot_value(event,key):
    try:
        attribute = event.get('request').get('intent').get('slots').get(key).get('value')
        return attribute
    except TypeError:
        return False
    except:
        return False
 
def build_ssml_response(speech_output, should_end_session, session_attributes = {}, **kwargs):
    response = {
        "version": "1.0",
        "sessionAttributes": session_attributes,
        "response": {
            "outputSpeech": {
                "type": "SSML",
                "ssml":"<speak>" + str(speech_output)[:7999] + "</speak>"
            },
            "reprompt": {
                "outputSpeech": {
                    "type": "SSML",
                    "ssml": "<speak>" + str(speech_output)[:7999] + "</speak>"
                }
            },
            "shouldEndSession": should_end_session
        }
    }
    #if problem playing on amazon echo device
    try:
        if kwargs['card_text'] is not False:
            response['response']['card'] = {"type": "Simple", "title": 'Defuse', "content": kwargs['card_text']}
    #except is GOOD in this case & normal
    except:
        pass
    return response

            
Uforia Alexa Skill Hangman
A Hangman game skill for Alexa.
Python
Click for Portfolio
                import os, sys
import urllib2
import random
 
def lambda_handler(event, context):
    try:
        #FORCED TO HAVE PROGRAM FLOW with Try & Catch BECAUSE OF A GLITCH IN AMAZON ECHO DEVICE vs Alexa Service Simulator
        try:
            response_session_attributes = event["session"]["attributes"]
        except:
            response_session_attributes = {'debug':'problem with session variables'}
 
        state = get_session_value(event,'state','menu')
        intent = get_intent(event)
        #return build_ssml_response(intent, 1, response_session_attributes)
        print intent
 
        bodyparts = ["Gallows","Body","Right Arm","Left Arm","Right Leg","Left Leg"]
        dict_of_bodyparts = {i+1:c for i,c in enumerate(bodyparts[::-1])}
        number_descriptors = {1:'first',2:'second',3:'third',4:'fourth',5:'fifth',6:'sixth',7:'seventh',8:'eighth',9:'ninth',10:'tenth',11:'eleventh',12:'twelveth'}
        
        if state == 'game_over': 
            if intent == "PlayAgainIntent":
                choose_play_again_yn = str(get_slot_value(event,'play_again'))
                if choose_play_again_yn == 'yes':
                    #fall-through
                    state = 'menu'
                    response_session_attributes['state'] = 'menu'
                elif choose_play_again_yn == 'no':
                    return build_ssml_response('Thank you for playing Hang Guy', 1,response_session_attributes)
                else:
                    return build_ssml_response('Do you want to play again?', 0,response_session_attributes)
            else:
                return build_ssml_response('Do you want to play again?', 0,response_session_attributes)
 
        if state == 'menu':    
            if intent == 'ChooseLevelIntent':
                #change this eventually
                chosen_level = str(get_slot_value(event,'level')).lower()
                if chosen_level not in ['easy','medium','hard']:
                    return build_ssml_response("Please choose a level between easy, medium or hard", 0, response_session_attributes)
                word = get_word(chosen_level)
                response_session_attributes['word'] = word
                response_session_attributes['state'] = 'guessing'
                response_session_attributes['puzzle'] = ""
                response_session_attributes['instruction_flag'] = 1
                response_session_attributes['correct'] = ""
                response_session_attributes['tries_left'] = len(bodyparts)
                instructions = 'Your word is %s letters. Start Guessing Letters' % len(word)
                return build_ssml_response(instructions, 0, response_session_attributes)
            else:
                return build_ssml_response("Please choose a level between easy, medium or hard", 0, response_session_attributes)
        elif state == 'guessing':
            if intent == "ChooseLetterIntent":
                chosen_letter = str(get_slot_value(event,'chosen_letter'))[0].lower()
                word = str(get_session_value(event,'word'))
                debug_text = "%s %s" % (chosen_letter, word)
                word_length = len(word)
                tries_left = int(get_session_value(event,'tries_left'))
                tries_left -= 1
                if tries_left <= 0:
                    response_session_attributes['state'] = 'game_over'
                    return build_ssml_response("You lost. The correct word was %s . Would you like to play again?" % word, 0,response_session_attributes)
                elif chosen_letter in word:   
                    correct = str(get_session_value(event,'correct'))
                    correct += chosen_letter
                    correct_position = 0
                    correct_count = 0
                    puzzle = ''
                    response_letter_placement = ''
                    for i in word:
                        correct_position += 1
                        if i in correct:
                            puzzle += i
                        else:
                            puzzle += "_"
                        if i == chosen_letter:
                            response_letter_placement += " %s is the %s letter, " % (i,number_descriptors[correct_position])
                            if correct_position == len(word):
                                response_letter_placement += '<break time="200ms"/> %s is the last letter. ' % (i)
                            correct_count += 1
                    times = "once" if correct_count == 1 else "%s times" % correct_count
                    response = "%s shows up %s. " % (chosen_letter,times) + response_letter_placement
                    #ONLY GIVE INSTRUCTIONS ON FIRST TRY
                    instruction_flag = int(get_session_value(event,'instruction_flag'))
                    if instruction_flag == 1:
                        response += ' Say, What Do I Have, to hear your progress. Put <break time="40ms"/>Is<break time="10ms"/>It<break time="50ms"/>before your answer'
                        response_session_attributes['instruction_flag'] = 0
                    #CORRECT IF ALL LETTERS ARE SOLVED
                    if puzzle == word:
                        response_session_attributes['state'] = 'game_over'
                        return build_ssml_response('Congratulations. You win! The word was %s. Do you want to play again' % word, 0,response_session_attributes)
                    response_session_attributes['correct'] = correct
                    response_session_attributes['puzzle'] = puzzle
 
                    return build_ssml_response(response, 0,response_session_attributes, exception=debug_text)
                elif chosen_letter not in word:
                    response = "Sorry, no <say-as interpret-as='spell-out'>%s</say-as>. drawing the %s." % (chosen_letter, dict_of_bodyparts[tries_left])
                    response_session_attributes['tries_left'] = tries_left
                    return build_ssml_response(response, 0,response_session_attributes, exception=debug_text)
                else:
                    return build_ssml_response("You said  <say-as interpret-as='spell-out'>%s</say-as>. If you want to solve, say I'd like to solve" % chosen_letter, 0,response_session_attributes,exception=word)
            if intent == "RemindIntent":
                puzzle = str(get_session_value(event,'puzzle')).lower()
                word = str(get_session_value(event,'word'))
                response = 'You have a %s letter word<break time="500ms"/>' % len(word)  + '<break time="300ms"/>'.join(['blank' if i=='_' else i for i in list(puzzle)])
                return build_ssml_response(response, 0,response_session_attributes)
            if intent == "SolveIntent":
                solve = str(get_slot_value(event,'solve'))
                word = str(get_session_value(event,'word'))
                if solve == word:
                    response_session_attributes['state'] = 'game_over'
                    return build_ssml_response('Congratulations. You win! Do you want to play again', 0,response_session_attributes)
                else:
                    response_session_attributes['state'] = 'guessing'
                    return build_ssml_response('%s is not the answer. Please choose more letters or solve again.' % solve, 0,response_session_attributes)                
            if intent == "AMAZON.CancelIntent" or intent == "AMAZON.StopIntent":
                return build_ssml_response('Thank you for using Hang Guy. See you next time!', 1)
            else:
                return build_ssml_response('Please guess more letters or solve the puzzle. Say, is it, before the answer', 0,response_session_attributes)
 
 
    except:
        exc_type, exc_obj, exc_tb = sys.exc_info()
        fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
        exception_text = str(exc_type) + ' ' + str(fname) + ' ' + str(exc_tb.tb_lineno)
        response_session_attributes['exception'] = exception_text
        return build_ssml_response("I did not understand you. Can you please say it again?",0,response_session_attributes,exception=exception_text)
 
#####
# PLEASE REPLACE URL IF YOU ARE CHANGING IT!!! WORDS MUST BE SEPARATED IN NEW LINES
#####
def get_word(level):
    results = urllib2.urlopen('http://pastebin.com/raw/baKjRnDu').read()
    list_of_results = results.split("\n")
    length_of_results = len(list_of_results)
    dict_of_lengths = {'easy':[3,4],'medium':[5,6],'hard':[7,8,9,10,11,12]}
    while True:
        list_index = random.randrange(0,length_of_results-1)
        word = list_of_results[list_index].strip()
        list_index += 1
        if list_index == length_of_results - 1:
            list_index = 0 
        if len(word) in dict_of_lengths[level]:
            break
    return word
 
 
 
def get_intent(event):
    if event["request"]["type"] == "LaunchRequest":
        return "LaunchRequest"
    elif event["request"]["type"] == "IntentRequest":
        return event["request"]["intent"]["name"]
    else:
        return False
 
def get_session_value(event,key,default=False):
    try:
        value = event.get('session').get('attributes').get(key,default)
        return value
    except TypeError:
        return default
    except:
        return default
 
def get_slot_value(event,key,default=False):
    try:
        attribute = event.get('request').get('intent').get('slots').get(key).get('value')
        return attribute
    except TypeError:
        return default
    except:
        return default
 
def build_ssml_response(speech_output, should_end_session, session_attributes = {}, **kwargs):
    response = {
        "version": "1.0",
        "sessionAttributes": session_attributes,
        "response": {
            "outputSpeech": {
                "type": "SSML",
                "ssml":"<speak>" + str(speech_output)[:7999] + "</speak>"
            },
            "reprompt": {
                "outputSpeech": {
                    "type": "SSML",
                    "ssml": "<speak>" + str(speech_output)[:7999] + "</speak>"
                }
            },
            "shouldEndSession": should_end_session
        }
    }
    #if problem playing on amazon echo device
    try:
        if kwargs['exception'] is not False:
            response['response']['card'] = {"type": "Simple", "title": 'title', "content": kwargs['exception']}
    #except is GOOD in this case & normal
    except:
        pass
    return response

            
Connecting to Network Devices with Low Level Network Sockets
An asynchronous socket connection to network devices. Do not use, Netmiko is better. Done for learning when I couldn't get Paramiko to work (before)
Python
Click for Portfolio
                import asyncio
import regex
import traceback
import sys
import time
from helper import *
class CiscoAsyncObject(object):
	command_timeout = 40
	def byte_to_string(self,obj):
		'''byte_to_string
		clean up a raw byte stream by recv. Chiefly used in read function.
		Arguments:
			obj {bytes (recv(1024))} -- messy bytes
		Returns:
			string -- so beautifully neat
		'''
		text = obj.decode('utf-8','ignore')
		text = ''.join([x for x in str(text) if ord(x) < 128])
		return text
	async def async_cisco_socket(self,loop,ip,port =23):
		'''async_cisco_socket
		
		This should be like the __init__ function of a socket class, but I don't know how to do init in an asynchronous context. So the end result will be that this will just populate self.reader & self.writer of this object
		'''
		connect_retries = 8
		tries = 0
		#try this the amount of connect_retries times
		while tries < connect_retries:
			try :
				reader, writer = await asyncio.open_connection(ip, port, loop=loop)
				if(reader is not None):
					hostname_line(ip,'Socket Created')
					#when the connection begins and you have to write "en" & password for Socket
					self.ip = ip
					self.hostname = get_hostname(ip)
					self.reader = reader
					self.writer = writer
					await self.initialize_socket()
					break
				else:
					print(reader,writer)
			except ConnectionRefusedError:
				tries = tries + 1
				hostname_line(ip,"Couldn't connect because of ConnectionRefusedError")
			except TimeoutError:
				tries = tries + 1
				hostname_line(ip,"Couldn't connect because of TimeoutError")
				await asyncio.sleep(1)
			except Exception as exc:
				tries = tries + 1
				hostname_line(ip,"Generic Exception -> %s" % (exc))
		if tries >= connect_retries:
			hostname_line(ip,"No socket connection because it exhausted it's maximum limit of retries.")
	async def sendline(self,command,**kwargs):
		'''sendline
		
		sendlines a command into the socket (Cisco here), and you could make it return the text to show up in the loop results, OR you could have it print as it goes. I prefer to have it print as it goes, and I did that option. 
 
		Kwargs is:
 
		expect = regex, which will break the recv read calls
		print = True/False, which prints the message as it goes
		newline = True/False (default True)
		'''
		chunks = []
		text = ''
		start_time_timeout_check = time.time()		
		reader = self.reader
		writer = self.writer
		ip = self.ip
		hostname = self.hostname
		print_it = kwargs.get('print',False)
		#expect regex that will break the recv loop
		expect_regex = kwargs.get('expect',None)
		default_regex = hostname + '.*' + '[#|\^|>]'
		#the default is in the right
		expect_regex = expect_regex if expect_regex != None else default_regex
		#IF NEWLINE KWARGS IS FALSE
		if kwargs.get("newline") is False:
			command = command
		else:
			command = command + "\n"
		#clear line
		for i in range(3):
			writer.write(b"\x15")
			await asyncio.sleep(.05)
		#do actual sending
		writer.write(command.encode())
		while 1:
			#Break up out of here no matte what, by the command timeout
			total_time = time.time() - start_time_timeout_check	
			# print("%s %s" % (command,total_time))
			if total_time > self.command_timeout:
				print('"%s" has timed out' % (command))
				return 'Time Out'
			try:
				chunk = await self.reader.read(8024)
				if not chunk:
					break
				chunk = self.byte_to_string(chunk)
				chunk_length = len(chunk)
				text = text + chunk
				# print("REGEX> ", expect_regex,  len(chunk), chunk.replace('\n', ' ').replace('\r', ' '),regex.search(expect_regex,chunk))
				#stop doing the recv at if the expect regex is not in the ENTIRE TEXT or the exception. It will stop at expect
				if regex.search(expect_regex,text) is not None:
					# print(command, "Expect happened")
					break
				
				
			except Exception as exc:
				print(hostname_line(ip, "Exception as %s" % (exc)))
				traceback.print_exc()
				await asyncio.sleep(.5)
				continue
			except:
				print("Error")
		#END READ
		#THIS IS DONE TO KEEP TRACK OF ? COMMANDS
		#This is for later text cleanup
		if len(command) > 0:
			self.current_command = command.strip()
		#just get the result without fluff
		#remove command in beginning & prompt at end
		text = text.replace(self.current_command,'')
		text = text.replace(self.current_command.replace(' ?',''),'')
		text = regex.sub(self.current_command,'',text)
		text = text.strip()
		#clean will remove the prompt, and other custom cleaning
		#remove the prompt in the end!
		text = regex.sub('\n%s.*[#|\^|>]' % (self.hostname),'',text)
		text = regex.sub('%s' % (self.current_command.replace(' ?','')),'',text)
		# text = text.strip()
		#clean up it for the console
		text = sanitize(text.replace('\n', ' ').replace("",'').strip())
		text = regex.sub('\r\s*','\r',text)
		#does the printing in each send line IF kwargs print is true (like print=True as parameter)
		if kwargs.get("newline") == True:
			header = wrap(wrap_hostname_line(ip,'Results of "%s"' % (command)))
			print(header + "\n" + text)
		return text
 
	async def initialize_socket(self):
		'''initialize_socket
		this is called by the async_connect to get to the config mode
		'''
		await self.sendline('en',expect="Password")
		await self.sendline('goon')
		await self.sendline('terminal length 0')
		await self.config_mode()
	async def config_mode(self):
		'''config mode
		Goes Into Config Mode of course
		'''
		await self.sendline("configure terminal")
	async def privileged_mode(self):
		'''privilged_mode
		the mode before global config mode, which is privileged mode
		'''
		await self.config_mode()
		await self.sendline("end")
	async def write(self,command):
		'''write
		
		Write raw BYTES
 
		command is in BYTES, not string
		'''
		# print("Writing: %s" % (command))
		self.writer.write(command)
	async def clear_line(self,command=b"\x15"):
		'''clear_line
		
		Simply writes b'\x15' into Telnet which clears the line! This is required for those ? help commands.
		This also represents Ctrl+U in the ASCII map, and is verified in Wireshark.
		'''
		await self.write(b"\x15")

            
Connecting to Network Devices with Low Level Network Sockets
A synchronous socket connection to network devices. Network Automation.
Python
Click for Portfolio
                import asyncio
import regex
import traceback
import sys
from async_socket_connection import *
from helper import *
 
 
class CiscoSyncObject():
	cisco_async_object = None
	loop = None
	def __init__(self,ip):
		'''__init__
		
		The Constructor will simply set an instance variable of an instance of the CiscoAsyncObject inside of async_socket_connection.py. The constructor runs the Asyncio Loop that will never end. 
		
		Arguments:
			ip {string} -- ip address of device to access
		
		Returns:
			nothing -- nothing
		'''
		async def instantiate_inner_func(loop,ip): 
			cisco_async_object = CiscoAsyncObject()
			await cisco_async_object.async_cisco_socket(loop,ip)
			return cisco_async_object
		self.loop = asyncio.new_event_loop()
		asyncio.set_event_loop(self.loop)
		tasks = [asyncio.ensure_future(instantiate_inner_func(self.loop,ip))]
		nodes = self.loop.run_until_complete(asyncio.gather(*tasks))
		object = l(nodes,0)
		self.cisco_async_object = object
	def __getattr__(self,name,*args,**kwargs):
		'''__get_attr
		
		__getattr__ and __call__ are the two methods that are called when an unknown function is ran in a Python Class, similar to the behavior to the PHP __get magic function. Here the method call is saved for later use in the __call__ function. GetAttr dunder method gets the function name.
		
		Arguments:
			name {string} -- method name
			*args {[type]} -- [description]
			**kwargs {[type]} -- [description]
		
		Returns:
			CiscoSyncSocket -- Self
		'''
		self.method_call = name
		return self
	def __call__(self,name=None,*args,**kwargs):
		'''__call__
		
		See the getattr method. __getattr__ and __call__ both deal with unknown functions. But there's a lot more. getattr(self.cisco_async_object,self.method_call)(name,*args,**kwargs) calls the function dynamically. It calls the self.method call (by call) on the self.cisco_async_object. 
		
		Arguments:
			name {string} -- argument inside of function
			*args {[type]} -- [description]
			**kwargs {[type]} -- [description]
		
		Returns:
			string -- result
		'''
		return l(self.loop.run_until_complete(asyncio.gather(getattr(self.cisco_async_object,self.method_call)(name,*args,**kwargs))),0)
 
 

            
Data ETL (Australian Company)
Convert messy phone log data into neat CSV via advanced regex. Done for an Australian company to clean unstructured data for data analysis. ETL.
Python
Click for Portfolio
                import regex, sys, csv, functools,operator,time
from helper import *
 
#########################
#    NONE DECORATOR EXCEPTION
#########################
def catch_exception(func):
	def func_wrapper(self,*args,**kwargs):
		try:
			#actually run function
			data = func(self,*args,**kwargs)
		except:
			data = None
		return data
	return func_wrapper
 
#########################
#    RULES
#########################
rules_d = {'0244230000':'Shandi Grenville (or another person who attended the phones at the Beechwood offices)',
'0242245500':'Shandi Grenville (or another person who attended the phones at the Beechwood offices)',
'0404821015':'Trevor Moffatt (Beechwood)',
'0242960139':'"Matt Slee (Building & Design Team - South Coast:\' Beechwood)"',
'0412605594':'Anthony Higgins (Southern Trenching)',
'0404821914':'Wayne Braid (Beechwood)',
'0296160999':'someone at the Beechwood Sydney Business Centre (Head Office)',
'0244221233':'someone at Leslie & Thompson Pty Ltd',
'0402350828':'"Thomas Smith (Building & Design Team:\' Beechwood)"',
'0244240012':'someone at the Twin Waters estate (Beechwood)',
'0414975583':'"Geoff Slee (Building & Design Team - South Coast, Beechwood)"'}
rules_d_k = list(rules_d.keys())
 
 
#########################
#    REGEX VARIABLES
#    //ANCHOR: Variables
#########################
format_regex = ''
time_regex = '\d{1,2}:\d{1,2}:\d{1,2}'
date_regex = '\d{4}\-\d{1,2}\-\d{1,2}'
space_new_regex = '[\s|\n]*'
any_regex = '.*?'
date_time_regex = date_regex + space_new_regex + time_regex
time_date_regex = time_regex + space_new_regex + date_regex
overall_date_regex = '(' + time_date_regex + '|' + date_time_regex + ')'
look_start_regex = '(?<=^|\s)'
look_end_regex = '(?=\s|$)'
series_of_words_regex = look_start_regex + '\d*\s*[A-Za-z]*[A-Za-z|\-|\s]*' + look_end_regex
disk_space_regex = look_start_regex + '\d{1,2}\.\d{1,2}MB|GB' + look_end_regex
currency_regex = look_start_regex + '\$\d*\.\d*' + look_end_regex
duration_regex = look_start_regex + '\d{1,2}:\d{1,2}' #00:22 + look_end_regex
phone_number_regex = look_start_regex + '[0-9]+' + look_end_regex
integer_regex = look_start_regex + '[0-9]+' + look_end_regex
input_base_path = 'C:/makeshift/files/australia_mobile/data/'
csv_base_path = 'C:/makeshift/files/australia_mobile/csv/'
csv_all_file_name = 'phone_all.csv'
csv_filtered_file_name = 'phone_filtered.csv'
csv_rules_file_name = 'rules_total.csv'
csv_all_file_path = csv_base_path + csv_all_file_name
csv_filtered_file_path = csv_base_path + csv_filtered_file_name
csv_rules_file_path = csv_base_path + csv_filtered_file_name
input_files = ['logs_mobile.txt','logs_2016.txt','logs_2017.txt']
input_files = ['logs_mobile_2.txt','logs_2016.txt','logs_2017.txt']
nodes = []
row = []
schema = ''
usage_type = ''
called_number = None
schema_allowed = ['mobile','phone','sms_national','data']
# input_files = ['logs_2017.txt']
#DO SHIT FOR RULES_COUNT_CSV!!! 
rules_count_d = {}
for phone_number, name in rules_d.items():
	rules_count_d[str(phone_number)] = {}
	rules_count_d[phone_number]['name'] = name
	for input_file in input_files:
		rules_count_d[phone_number][input_file] = 0
 
#note
#
#TWO TYPES OF ROWS
#
#1) data = ['Data', '0.02MB', '0.02MB', '$0.00000', '$0.00000', '$0.00000']
#
#
#2) calls =  ['Mobile', 'Call', '09:46', '0418695084', '0.00MB', '$9.35000', '$0.00000', '$0.00000']
#
#//ANCHOR: REGEX ROWS
data_regex_row = '(%s)%s(%s)%s(%s)%s(%s)%s(%s)%s(%s)' % (series_of_words_regex , space_new_regex , disk_space_regex , space_new_regex , disk_space_regex , space_new_regex , currency_regex , space_new_regex , currency_regex , space_new_regex , currency_regex)
calls_mobile_regex_row = '(%s)%s(%s)%s(%s)%s(%s)%s(%s)%s(%s)%s(%s)' % (series_of_words_regex , space_new_regex, duration_regex , space_new_regex , phone_number_regex , space_new_regex , disk_space_regex , space_new_regex , currency_regex , space_new_regex , currency_regex , space_new_regex , currency_regex)
sms_national_regex_row = '(%s)%s(%s)%s(%s)%s(%s)%s(%s)%s(%s)%s(%s)' % (series_of_words_regex , space_new_regex, integer_regex , space_new_regex , phone_number_regex , space_new_regex , disk_space_regex , space_new_regex , currency_regex , space_new_regex , currency_regex , space_new_regex , currency_regex)
calls_phone_regex_row = '(%s)%s(%s)%s(%s)%s(%s)%s(%s)' % (series_of_words_regex , space_new_regex, duration_regex , space_new_regex , phone_number_regex , space_new_regex , currency_regex , space_new_regex , duration_regex)
 
 
#########################
#    GET NODES!!! the nodes is a list of dictionaries, and the dictionaries have values of date_time & data
#########################
for input_file in input_files:
	input_file_path = input_base_path + input_file
	with open(input_file_path,'r') as f:
		lines = f.readlines()
		for index,line in enumerate(lines):
			#IF IT STARTS WITH DATE & TIME
			if regex.match("^" + any_regex + date_time_regex,line):
				date_time = regex.findall(date_regex,line)[0] + " " + regex.findall(time_regex,line)[0]
				data = regex.findall(date_time_regex + "(.*)" + look_end_regex,line)[0]
				nodes.append({'date_time':date_time,'data':data,'file':input_file})
				# pass
			#handles the very weird situation of DATE + DATA + TIME
			if regex.match("^" + time_regex + "$",line.strip()):
				#get date
				date = lines[index-2].strip()
				if(regex.match(date_regex,date) is None):
					for i in range(-1,-10,-1):
						try:
							date = regex.findall(date_regex,nodes[i]['date_time'])[0]
						except:
							continue
				date_time = str(date) + " " + line.strip()
				data = lines[index-1]
				nodes.append({'date_time':date_time,'data':data,'file':input_file})
 
#########################
#    CLIENT
#########################
#Inside File
csv_all_handle = open(csv_all_file_path,'w')
csv_filtered_handle = open(csv_filtered_file_path,'w')
csv_rules_handle = open(csv_rules_file_path,'w')
for node in nodes:
	#if the row is not neat, it will reflect in the default if statement below
	ignore_row = False
	date_time = node['date_time']
	messy_line = node['data']
	try:
		#VARIABLES THAT WILL BE IN THE ROW
		try:
			time_tuple = time.strptime(date_time,"%Y-%m-%d %H:%M:%S")
			date_row_value = time.strftime('%d/%m/%Y %H:%M:%S', time_tuple)
			description_date_value = time.strftime('%H:%M', time_tuple)
		except:
			#if reaching here, the row will likely not even show up
			overall_date = None
			date_row_value = None
			description_date_value = None
		#Note: string is already stripped in regex_groups function as it calls the strip_iterate function
		#CALL SCHEMA (MOBILE)!!! (follows call structure define above)!!!
		#['Call', 'to', 'non-Optus', 'GSM', '01:35', '0412977644', '0.00MB', '$2.15000', '$0.00000', '$0.00000']
		if regex_groups(calls_mobile_regex_row,messy_line) is not None:
			schema = 'mobile'
			rgo = regex_groups(calls_mobile_regex_row,messy_line)
			usage_type = l(rgo,0)
			duration = l(rgo,1)
			called_number = l(rgo,2).strip()
			# debug
			# print("CALL",row)
			# pass
		#DATA SCHEMA (follows data structure define above)!!!
		#['Data', '5.85MB', '5.85MB', '$0.00000', '$0.00000', '$0.00000']
		elif regex_groups(data_regex_row,messy_line) is not None:
			#according to Sarah, ignore all data
			ignore_row = True
			# debug
			# print("DATA",row)
			# pass
		#SMS NATIONAL TYPE OF DATA SCHEMA
		#['SMS', 'National', '1', '0406665748', '0.00MB', '$0.00000', '$0.00000', '$0.00000']
		elif regex_groups(sms_national_regex_row,messy_line) is not None:
			schema = 'sms_national'
			rgo = regex_groups(sms_national_regex_row,messy_line)
			usage_type = l(rgo,0)
			duration = l(rgo,1)
			called_number = l(rgo,2).strip()
			# print("SMS",row)
			# pass
		#CALL PHONE!!
		elif regex_groups(calls_phone_regex_row,messy_line) is not None:
			schema = 'phone'
			rgo = regex_groups(calls_phone_regex_row,messy_line)
			usage_type = l(rgo,0)
			duration = l(rgo,1)
			called_number = l(rgo,2).strip()
			# print("PHONE", row) 
			pass
		#Fits No Criteria
		else:	
			ignore_row = True
			pass
		#is_sms? 
		is_sms = 1 if 'sms' in usage_type.lower() else 0
		#what is person's name in the rule sheet
		person_name = dvkp(rules_d,called_number[1:])
		describe_event = 'At %s I called %s and spoke with %s on the telephone.' % (description_date_value, called_number, person_name)
		input_file = node['file']
	except KeyError:
		print("KeyError in " + str(index))
		pass
	except IndexError:
		print("IndexError in " + str(index))
		pass
	except ValueError:
		print("ValueError in " + str(index))
		pass
	except TypeError:
		print("TypeError in " + str(index))
		pass
 
	#########################
	#    WRITE CSV ROW HERE
	#########################
	if(ignore_row == False and date_row_value is not None):
		row = [date_row_value,duration,is_sms,called_number,input_file]
		# print(row)
		csv_all_handle.write(str(','.join(list(map(str,row)))))
		csv_all_handle.write('\n')
		csv_all_handle.flush()
	#FILTERED SHEET
	#ignore row here means don't print data
	#person_name filter means only show values inside the rules section
	#date_row_value means don't show funny looking rows
	if(ignore_row == False and date_row_value is not None and person_name is not None):
		row = [date_row_value,duration,is_sms,describe_event,input_file]
		print(row)
		#record tallies for the next rules csv sheet
		rules_count_d[called_number][input_file] += 1
		# print(rules_count_d)
		csv_filtered_handle.write(str(','.join(list(map(str,row)))))
		csv_filtered_handle.write('\n')
		csv_filtered_handle.flush()
 
#########################
#    WORK ON RULES CSV FILE
#########################
# for phone_number,node in rules_count_d.items():
# 	row = [node[input_file] for input_file in input_files]
# 	total_sum = sum(row)
# 	row.insert(0,node['name'])
# 	row.insert(1,phone_number)
# 	row.append(total_sum)
# 	csv_rules_handle.write(str(','.join(list(map(str,row)))))
# 	csv_rules_handle.write('\n')
# 	csv_rules_handle.flush()
Netconf
Network Automation via NETCONF + Configure both CLI/NETCONF via Python, to analyze all the key/value pairs & configurable values in a Cisco CSR V1000 router. Subclassing was separate for Netconf & regular CLI.
Python
Click for Portfolio
import paramiko
import xmltodict
import xml
import pprint
import sys
from helpers import *
from time import sleep
from functools import partial
from bs4 import BeautifulSoup
from itertools import cycle
 
 
class SSH():
    client = None
    session = None
    read_interval = .5
    connect_params = {"hostname": "192.168.0.201", "username": "goon",
                      "password": "goon", "port": 22, "look_for_keys": False, "allow_agent": False}
 
    def read(self):
        blocks = []
        chunk_size = 2524
        while True:
            sleep(self.read_interval)
            block = self.session.recv(chunk_size)
            # DEBUG
            # print(block.decode(),end="")
            # file_add_contents("add.xml",block.decode())
            # end debug
            blocks.append(block.decode())
            if len(block) < chunk_size:
                break
        text = ''.join(blocks).strip()
        return text
 
    def start(self, *args, **kwargs):
        self.client = paramiko.SSHClient()
        # overrides the default above
        self.connect_params.update(kwargs)
        hostname = self.connect_params.get("hostname")
        del self.connect_params['hostname']
        # debug
        print("LOGGING INTO:")
        print(hostname, self.connect_params)
        self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        self.client.connect(hostname, **self.connect_params)
        self.session = self.client.get_transport().open_session()
        # Only uncomment if sending command line arguments. Separate into separate class or function if expands.
 
    def s(self, *args, **kwargs):
        '''console shorthand'''
        self.start(*args, **kwargs)
 
    def close(self):
        self.client.close()
        print("SSH Session Closed")
 
 
class CommandLine(SSH):
    '''Command Line Specific'''
    # port 22
    connect_params = {'hostname': '10.10.20.48', 'username': 'cisco',
                      'password': 'cisco_1234!', 'port': 22, 'look_for_keys': False, 'allow_agent': False}
 
    def __init__(self, *args, **kwargs):
        self.start(*args, **kwargs)
        # invoke shell is specific to Command Lines (not netconf)
        self.session.invoke_shell()
 
    def send(self, command):
        command = command + "\n"
        self.session.send(command.encode())
        response = self.read()
        return response
 
 
class Netconf(SSH):
    '''Class & Functions & Values specific to NETCONF'''
    #
    # Cisco DevNet Params
    # port 830
    #
    cisco_namespace_prefix = 'http://cisco.com/ns/yang/'
    ietf_namespace_prefix = 'urn:ietf:params:xml:ns:yang:'
    connect_params = {'hostname': '10.10.20.48', 'username': 'cisco',
                      'password': 'cisco_1234!', 'port': 830, 'look_for_keys': False, 'allow_agent': False}
    terminator = ']]>]]>'
 
    def __init__(self, *args, **kwargs):
        # Cisco Devnet Params
        self.start(*args, **kwargs)
        self.netconf_hello()
 
    def n(self):
        '''console restart socket & netflow shorthand'''
        self.start()
        self.netconf_hello()
 
    def send(self, command):
        command = command + self.terminator + "/n"
        self.session.send(command.encode())
        response = self.read()
        return response
 
    def netconf_hello(self):
        self.session.invoke_subsystem('netconf')
        hello_rpc = '<?xml version="1.0" encoding="UTF-8"?><hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><capabilities><capability>urn:ietf:params:netconf:base:1.0</capability></capabilities></hello>'
        return self.send(hello_rpc)
 
    def change_hostname(self, hostname):
        self.send(
            f'<?xml version="1.0" encoding="UTF-8"?> <rpc message-id="101" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> <edit-config> <target> <running/> </target> <config> <cli-config-data> <cmd>hostname {hostname}</cmd> </cli-config-data> </config> </edit-config> </rpc>')
 
    def print_netconf_graph(self, xml_response):
        xml_response = xml_response.replace(self.terminator, '')
        try:
            print_structure(xmltodict.parse(xml_response))
        except xml.parsers.expat.ExpatError:
            print("Your XML is structured wrong")
 
    def console_send(self, xml_filepath="payload.txt"):
        '''meant for consoles. filename with XML to send must be in payload.txt'''
        self.print_netconf_graph(n.send(file_get_contents(xml_filepath)))
 
    def get(self, filter):
        rpc_get = '<?xml version="1.0" encoding="UTF-8"?><rpc message-id="101" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><get><filter>' + \
            filter + '</filter></get></rpc>'
        return self.send(rpc_get)
 
    def edit_config(self, filter):
        rpc_edit_config = '<?xml version="1.0" encoding="UTF-8"?><rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="111"><edit-config><target><running/></target><config>' + \
            filter + '</config></edit-config></rpc>'
        return self.send(rpc_edit_config)
 
    def pretty_print_xml(self, ugly_xml):
        bs = BeautifulSoup(ugly_xml, 'xml')
        print(bs.prettify())
 
 
if __name__ == '__main__':
    try:
        #cisco_namespace_prefix = "http://cisco.com/ns/yang/"
        #ietf_namespace_prefix = "urn:ietf:params:xml:ns:yang:"
        # CISCO DEVNET! CISCO ANYCONNECT MUST BE ACTIVATED
        cs = Netconf()
        client = cs.client
        rpc_fragment = '''<interfaces xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-interfaces-oper">
		<interface>
		<name>GigabitEthernet2</name>
		
		</interface>
		</interfaces>'''
 
        for octet_4 in cycle(range(4, 255)):
            rpc_fragment = f'<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"> <interface operation="replace"> <name> GigabitEthernet2 </name> <description> GOON </description> <type xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type"> ianaift:ethernetCsmacd </type> <enabled> true </enabled> <ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip"> <address> <ip> 10.10.50.{octet_4} </ip> <netmask> 255.255.255.0 </netmask> </address> </ipv4> </interface> </interfaces> '
            xml_response = cs.edit_config(rpc_fragment)
        xml_response = cs.get(rpc_fragment)
        print(xml_response)
    finally:
        sleep(1)
        client.close()
            
Netconf
Network Automation via NETCONF + Configure both CLI/NETCONF via Python, to analyze all the key/value pairs & configurable values in a Cisco CSR V1000 router. Subclassing was separate for Netconf & regular CLI.
Python
Click for Portfolio
                import paramiko
import xmltodict
import xml
import pprint
import sys
from helpers import *
from time import sleep
from functools import partial
from bs4 import BeautifulSoup
from itertools import cycle
 
 
class SSH():
    client = None
    session = None
    read_interval = .5
    connect_params = {"hostname": "192.168.0.201", "username": "goon",
                      "password": "goon", "port": 22, "look_for_keys": False, "allow_agent": False}
 
    def read(self):
        blocks = []
        chunk_size = 2524
        while True:
            sleep(self.read_interval)
            block = self.session.recv(chunk_size)
            # DEBUG
            # print(block.decode(),end="")
            # file_add_contents("add.xml",block.decode())
            # end debug
            blocks.append(block.decode())
            if len(block) < chunk_size:
                break
        text = ''.join(blocks).strip()
        return text
 
    def start(self, *args, **kwargs):
        self.client = paramiko.SSHClient()
        # overrides the default above
        self.connect_params.update(kwargs)
        hostname = self.connect_params.get("hostname")
        del self.connect_params['hostname']
        # debug
        print("LOGGING INTO:")
        print(hostname, self.connect_params)
        self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        self.client.connect(hostname, **self.connect_params)
        self.session = self.client.get_transport().open_session()
        # Only uncomment if sending command line arguments. Separate into separate class or function if expands.
 
    def s(self, *args, **kwargs):
        '''console shorthand'''
        self.start(*args, **kwargs)
 
    def close(self):
        self.client.close()
        print("SSH Session Closed")
 
 
class CommandLine(SSH):
    '''Command Line Specific'''
    # port 22
    connect_params = {'hostname': '10.10.20.48', 'username': 'cisco',
                      'password': 'cisco_1234!', 'port': 22, 'look_for_keys': False, 'allow_agent': False}
 
    def __init__(self, *args, **kwargs):
        self.start(*args, **kwargs)
        # invoke shell is specific to Command Lines (not netconf)
        self.session.invoke_shell()
 
    def send(self, command):
        command = command + "\n"
        self.session.send(command.encode())
        response = self.read()
        return response
 
 
class Netconf(SSH):
    '''Class & Functions & Values specific to NETCONF'''
    #
    # Cisco DevNet Params
    # port 830
    #
    cisco_namespace_prefix = 'http://cisco.com/ns/yang/'
    ietf_namespace_prefix = 'urn:ietf:params:xml:ns:yang:'
    connect_params = {'hostname': '10.10.20.48', 'username': 'cisco',
                      'password': 'cisco_1234!', 'port': 830, 'look_for_keys': False, 'allow_agent': False}
    terminator = ']]>]]>'
 
    def __init__(self, *args, **kwargs):
        # Cisco Devnet Params
        self.start(*args, **kwargs)
        self.netconf_hello()
 
    def n(self):
        '''console restart socket & netflow shorthand'''
        self.start()
        self.netconf_hello()
 
    def send(self, command):
        command = command + self.terminator + "/n"
        self.session.send(command.encode())
        response = self.read()
        return response
 
    def netconf_hello(self):
        self.session.invoke_subsystem('netconf')
        hello_rpc = '<?xml version="1.0" encoding="UTF-8"?><hello xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><capabilities><capability>urn:ietf:params:netconf:base:1.0</capability></capabilities></hello>'
        return self.send(hello_rpc)
 
    def change_hostname(self, hostname):
        self.send(
            f'<?xml version="1.0" encoding="UTF-8"?> <rpc message-id="101" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> <edit-config> <target> <running/> </target> <config> <cli-config-data> <cmd>hostname {hostname}</cmd> </cli-config-data> </config> </edit-config> </rpc>')
 
    def print_netconf_graph(self, xml_response):
        xml_response = xml_response.replace(self.terminator, '')
        try:
            print_structure(xmltodict.parse(xml_response))
        except xml.parsers.expat.ExpatError:
            print("Your XML is structured wrong")
 
    def console_send(self, xml_filepath="payload.txt"):
        '''meant for consoles. filename with XML to send must be in payload.txt'''
        self.print_netconf_graph(n.send(file_get_contents(xml_filepath)))
 
    def get(self, filter):
        rpc_get = '<?xml version="1.0" encoding="UTF-8"?><rpc message-id="101" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><get><filter>' + \
            filter + '</filter></get></rpc>'
        return self.send(rpc_get)
 
    def edit_config(self, filter):
        rpc_edit_config = '<?xml version="1.0" encoding="UTF-8"?><rpc xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="111"><edit-config><target><running/></target><config>' + \
            filter + '</config></edit-config></rpc>'
        return self.send(rpc_edit_config)
 
    def pretty_print_xml(self, ugly_xml):
        bs = BeautifulSoup(ugly_xml, 'xml')
        print(bs.prettify())
 
 
if __name__ == '__main__':
    try:
        #cisco_namespace_prefix = "http://cisco.com/ns/yang/"
        #ietf_namespace_prefix = "urn:ietf:params:xml:ns:yang:"
        # CISCO DEVNET! CISCO ANYCONNECT MUST BE ACTIVATED
        cs = Netconf()
        client = cs.client
        rpc_fragment = '''<interfaces xmlns="http://cisco.com/ns/yang/Cisco-IOS-XE-interfaces-oper">
		<interface>
		<name>GigabitEthernet2</name>
		
		</interface>
		</interfaces>'''
 
        for octet_4 in cycle(range(4, 255)):
            rpc_fragment = f'<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces"> <interface operation="replace"> <name> GigabitEthernet2 </name> <description> GOON </description> <type xmlns:ianaift="urn:ietf:params:xml:ns:yang:iana-if-type"> ianaift:ethernetCsmacd </type> <enabled> true </enabled> <ipv4 xmlns="urn:ietf:params:xml:ns:yang:ietf-ip"> <address> <ip> 10.10.50.{octet_4} </ip> <netmask> 255.255.255.0 </netmask> </address> </ipv4> </interface> </interfaces> '
            xml_response = cs.edit_config(rpc_fragment)
        xml_response = cs.get(rpc_fragment)
        print(xml_response)
    finally:
        sleep(1)
        client.close()

            
TreeView Search Python
Same TreeView Windows Code Injection search, done in Python instead of C++. I did the Python first, as it would be near impossbile for me to do it in C++ to start (in the beginning)
Python
Click for Portfolio
                import ctypes
import sys
import pprint
import time
import string
import webbrowser
from winapi_constants import *
from ctypes import *
from ctypes.wintypes import *
 
k = ctypes.WinDLL('kernel32', use_last_error=True)
u = ctypes.WinDLL('user32', use_last_error=True)
c = ctypes.WinDLL('comctl32', use_last_error=True)
 
 
def dvkp(dict, key_part, default=''):
    try:
        return [value for key, value in dict.items() if key_part in key][0]
    except:
        return default
 
 
hwnds = {}
 
 
def get_hwnd(window_part_name):
    def foreach_window(hwnd, lParam):
        if u.IsWindowVisible(hwnd):
            length = u.GetWindowTextLengthW(hwnd)
            buff = ctypes.create_unicode_buffer(length + 1)
            u.GetWindowTextW(hwnd, buff, length + 1)
            hwnds[buff.value] = hwnd
        return True
    EnumWindowsProc = WINFUNCTYPE(c_bool, POINTER(c_int), POINTER(c_int))
    u.EnumWindows(EnumWindowsProc(foreach_window), 0)
    return dvkp(hwnds, window_part_name)
 
 
def get_class_name(hwnd):
    class_name = create_unicode_buffer(50)
    u.GetClassNameW(hwnd, class_name, 50)
    return class_name.value.strip()
 
 
def get_window_text(hwnd):
    window_text = create_unicode_buffer(50)
    u.GetWindowTextW(hwnd, window_text, 50)
    return window_text.value.strip()
 
 
child_window = -1
window_index = 0
 
 
def get_window_children(hwnd):
    child_hwnds = []
 
    def child_callback(hwnd, param):
        nonlocal child_hwnds
        child_hwnds.append(hwnd)
        return True
    EnumChildProc = WINFUNCTYPE(c_bool, POINTER(c_int), POINTER(c_long))
    u.EnumChildWindows(hwnd, EnumChildProc(child_callback), pointer(c_long(0)))
    return child_hwnds
 
 
def debug_hwnds(child_hwnds):
    if(len(child_hwnds) > 0):
        for child_hwnd in child_hwnds:
            length = u.GetWindowTextLengthW(child_hwnd)
            window_text = create_unicode_buffer(length + 1)
            u.GetWindowTextW(child_hwnd, window_text, length + 1)
            print("EXAMINING: " + str(repr(child_hwnd)) + "\n\tCLASS NAME -> " +
                  get_class_name(child_hwnd) + "\n\tWINDOW TEXT -> " + window_text.value.strip() + "\n")
            get_window_children(child_hwnd)
 
 
def get_systreeview32_hwnds(child_hwnds):
    systreeview_hwnds = []
    if(len(child_hwnds) > 0):
        for child_hwnd in child_hwnds:
            class_name = get_class_name(child_hwnd)
            if(class_name == "SysTreeView32"):
                systreeview_hwnds.append(child_hwnd)
            get_window_children(child_hwnd)
    return systreeview_hwnds
 
 
# https://docs.microsoft.com/en-us/windows/win32/controls/tvm-getitem
# https://docs.microsoft.com/en-us/windows/win32/controls/tvm-selectitem
class TVITEMA(Structure):
    _fields_ = (('mask', UINT), ('hItem', UINT),
                ('state', UINT), ('stateMask', UINT), ('pszTextx', LPSTR),
                ('cchTextMax', c_int), ('iImage', c_int), ('iSelectedImage', c_int), ('children', c_int), ('lparam', LPARAM))
 
# class TVITEMEX(Structure):
#     _fields_ = (('mask', UINT), ('hItem', UINT),
#                 ('state', UINT), ('stateMask', UINT), ('pszTextx', LPSTR),
#                 	('cchTextMax',c_int),('iImage',c_int),('iSelectedImage',c_int),('children',c_int),('lparam',LPARAM),('iIntegral',c_int),('uStateEx',c_int),("hwnd",HWND),("iExpandedImage",int),("int",iReserved))
 
 
def get_selected_item_text():
    systreeview_hwnds = get_systreeview32_hwnds(
        get_window_children(get_hwnd("Redacted")))
    for hwnd in systreeview_hwnds:
        root_item_handle_int = u.SendMessageA(
            hwnd, TVM_GETNEXTITEM, TVGN_ROOT, 0)
        # print("Root Item", hex(root_item_handle_int))
        # SELECTING CODE
        selected_item_handle_int = u.SendMessageA(
            hwnd, TVM_GETNEXTITEM, TVGN_CARET, 0)
        # print("Selected Item", hex(selected_item_handle_int))
        text_buffer_size = 127
        # make item object
        selected_item = TVITEMA()
        selected_item.hItem = selected_item_handle_int
        selected_item.mask = TVIF_TEXT | TVIF_HANDLE
        selected_item.cchTextMax = 127
        item_memory_size = sizeof(selected_item) + 1024
        process_id_dword = DWORD()
        # note: DO NOT FORGET THE BYREF FOR PUTTING VARIABLES IN THAT WILL COME OUT WITH A NEW VALUE (IN SOME CASES LIKE THIS DWORD)
        thread_id = u.GetWindowThreadProcessId(hwnd, byref(process_id_dword))
        # note, if it was a long pointer, extracting it would be .contents (similar to dereferencing with &. Since it's not a pointer, you use .value
        process_id = process_id_dword.value
        # now that you have process ID, open Process
        k.OpenProcess.argtypes = [DWORD, BOOL, DWORD]
        k.OpenProcess.restype = HANDLE
        process = k.OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ |
                                PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION, False, process_id_dword)
        # print("PROCESS_ID", process_id)
        # print("PROCESS", process)
        # https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualallocex
        # allocate space for the item object & text object in this process
        address_item_remote = k.VirtualAllocEx(
            process, 0, item_memory_size, MEM_COMMIT, PAGE_READWRITE)
        address_text_remote = k.VirtualAllocEx(
            process, 0, text_buffer_size, MEM_COMMIT, PAGE_READWRITE)
        # when you copy the selected item in the remote process, put the new memory address pointer in that item
        selected_item.pszTextx = address_text_remote
        # print("address_item_remote", hex(address_item_remote))
        # print("address_text_remote", hex(address_text_remote))
        item_memory_size = sizeof(selected_item)
        bytes_written = DWORD()
        k.WriteProcessMemory(process, address_item_remote, byref(
            selected_item), item_memory_size, byref(bytes_written))
        u.SendMessageA(hwnd, TVM_GETITEM, TVGN_CARET, address_item_remote)
        text_buffer = create_string_buffer(text_buffer_size)
        bytes_size = text_buffer_size
        bytes_read = DWORD()
        k.ReadProcessMemory(process, address_text_remote, byref(
            text_buffer), text_buffer_size, byref(bytes_read))
        # print("BYTES READ", bytes_read)
        selected_item_text = text_buffer.value.decode()
        k.VirtualFreeEx(process, address_item_remote, 0, MEM_RELEASE)
        k.VirtualFreeEx(process, address_text_remote, 0, MEM_RELEASE)
        k.CloseHandle(process)
        return selected_item_text
 
 
def go_to_url(url):
    chrome_path = "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe"
    webbrowser.open(url, new=2)
 
 
LRESULT = LPARAM
ULONG_PTR = WPARAM
chrome_path = "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe"
LowLevelKeyboardProc = WINFUNCTYPE(LRESULT, c_int, WPARAM, LPARAM)
alphanumeric = [c for c in string.digits + string.ascii_uppercase]
 
 
class KBDLLHOOKSTRUCT(Structure):
    _fields_ = (('vkCode', DWORD), ('scanCode', DWORD),
                ('flags', DWORD), ('time', DWORD), ('dwExtraInfo', ULONG_PTR))
 
 
@LowLevelKeyboardProc
def keyboard_low_level(nCode, wParam, lParam):
    msg = cast(lParam, POINTER(KBDLLHOOKSTRUCT))[0]
    vk_code = msg.vkCode
    # character = chr(vk_code)
    # if alphanumeric, and only proceed if pressing down, not both up & down for duplicates
    if wParam == WM_KEYDOWN:
        # character = character.lower()
        print(f"You wrote {vk_code}")
        # leave if "e"
        query = get_selected_item_text()
        if vk_code == 186:  # ;
            go_to_url(f"https://open.spotify.com/search/{query}")
        elif vk_code == 222:  # '
            go_to_url(
                f"http://www.amazon.com/s/ref=nb_sb_noss_2?url=search-alias`%3Ddigital-music&field-keywords={query}")
        elif vk_code == 188:
            go_to_url(f"http://www.youtube.com/results?search_query={query}")
        elif vk_code == 219:
            sys.exit(0)
    return u.CallNextHookEx(None, nCode, wParam, lParam)
 
 
u.SetWindowsHookExW(WH_KEYBOARD_LL, keyboard_low_level, None, 0)
msg = MSG()
lpmsg = pointer(msg)
while u.GetMessageW(lpmsg, 0, 0, 0) != 0:
    u.TranslateMessage(lpmsg)
    u.DispatchMessageW(lpmsg)

            
Rust Sports Cards
A Rust program for managing sports cards.
Rust
Click for Portfolio
                #![allow(warnings, unused)]
mod players;
mod clear_console;
use std::ops::Deref;
use std::io;
use rand::Rng;
use rand::thread_rng;
use rand::seq::SliceRandom;
const amount_of_cards_in_pack:i8 = 7;
const amount_of_packs_in_box:i8 = 24;
#[derive(Debug, PartialEq,Clone)]
enum SportsCardEnum
{
    Plain,
    Insert(i32),
    Refractor,
    AtomicRefractor,
    Autograph,
    Jersey,
    Patch,
    PatchAutograph,
}
 
impl SportsCardEnum {
    pub fn odds(&self) -> i32 {
        match self {
            SportsCardEnum::PatchAutograph => 60000,
            SportsCardEnum::Patch => 7500,
            SportsCardEnum::Jersey => 2500,
            SportsCardEnum::Insert(7) => 360,
            SportsCardEnum::Insert(6) => 288,
            SportsCardEnum::Insert(5) => 144,
            SportsCardEnum::AtomicRefractor => 244,
            SportsCardEnum::Autograph => 128,
            SportsCardEnum::Insert(4) => 96,
            SportsCardEnum::Refractor => 72,
            SportsCardEnum::Insert(3) => 36,
            SportsCardEnum::Insert(2) => 16,
            SportsCardEnum::Insert(1) => 4,
            SportsCardEnum::Plain => 4,
            _ => 1
        }
    }
    pub fn name_of_insert(&self) -> &str {
        match self {
            SportsCardEnum::Autograph => "Autograph",
            SportsCardEnum::AtomicRefractor => "Atomic Refractor",
            SportsCardEnum::PatchAutograph => "Patch Autograph",
            SportsCardEnum::Plain => "Plain",
            SportsCardEnum::Patch => "Patch",
            SportsCardEnum::Refractor => "Refactor",
            SportsCardEnum::Jersey => "Jersey",
            SportsCardEnum::Insert(1) => "Jam City",
            SportsCardEnum::Insert(2) => "Season's Best",
            SportsCardEnum::Insert(3) => "Rock Stars",
            SportsCardEnum::Insert(4) => "Quick Strike",
            SportsCardEnum::Insert(5) => "Thunder & Lightning",
            SportsCardEnum::Insert(6) => "NetRageous",
            SportsCardEnum::Insert(7) => "Hardware",
            _ => "Plain"
        }
    }
    pub fn multiplier(&self) -> f32
    {
        match self
        {
            SportsCardEnum::PatchAutograph => 5000.0,
            SportsCardEnum::Patch => 2000.0,
            SportsCardEnum::Jersey => 1000.0,
            SportsCardEnum::Insert(6) => 150.0,
            SportsCardEnum::AtomicRefractor => 130.0,
            SportsCardEnum::Insert(5) => 100.0,
            SportsCardEnum::Autograph => 75.0,
            SportsCardEnum::Insert(4) => 75.0,
            SportsCardEnum::Refractor => 75.0,
            SportsCardEnum::Insert(3) => 25.0,
            SportsCardEnum::Insert(2) => 20.0,
            SportsCardEnum::Insert(1) => 8.0,
            SportsCardEnum::Plain => 1.0,
            _ => 1.0,
        }
    }
}
#[derive(Debug,Clone)]
struct SportsCard
{
    sports_card_type: SportsCardEnum,
    player_name: String,
    player_tier: i8,
    price: f32
}
impl SportsCard {
    fn get_price(&self) -> f32 {
        let base_price: f32 = match self.player_tier
        {
            _ if self.player_tier == 1 => 2.0,
            _ if self.player_tier == 2 => 0.5,
            _ if self.player_tier == 3 => 0.4,
            _ if self.player_tier == 4 => 0.3,
            _ if self.player_tier == 5 => 0.25,
            _ if self.player_tier == 6 => 0.20,
            _ if self.player_tier == 7 => 0.15,
            _ if self.player_tier == 8 => 0.05,
            _ => 1.0,
        };
        let multiplier: f32 = self.sports_card_type.multiplier();
        let mut price = (base_price * multiplier);
        price = match price
        {
            _ if price >= 50.0 => price - (price % 10.0),
            _ if price >= 20.0 => price - (price % 5.0),
            _ => price
        };
        price
    }    
}
impl Default for SportsCard 
{
     fn default() -> Self { 
        SportsCard { 
            sports_card_type: SportsCardEnum::Plain,
            player_name: "None".to_string(),
            price: 1.50,
            player_tier: 8
        }
     }
}
#[derive(Debug)]
struct Pack
{
    cards: Vec<SportsCard>,
    status_of_pack: SportsCardEnum,
    begin_border: usize,
    begin_insert_border: usize,
}
impl Pack {
    fn get_regular_card(&mut self) -> SportsCard
    {
        let mut player_tuples = players::player_tuples;
        let mut rng = thread_rng();
        player_tuples.shuffle(&mut thread_rng());
        let player_tuple_length = player_tuples.len();
        let shuffle_interval = 7;
        let mut end_border = self.begin_border + shuffle_interval;
        let index = rng.gen_range(self.begin_border..end_border);
        let player = player_tuples[index];
        //iterate to next level in tuple for the next function call
        self.begin_border = self.begin_border + shuffle_interval;
        let mut regular_card = SportsCard
        { 
            sports_card_type: SportsCardEnum::Plain,
            player_name: player.0.to_string(),
            player_tier: player.1,
            ..Default::default() 
        };
        regular_card.price = regular_card.get_price();
        regular_card
    }
    fn get_insert(&mut self, sports_card_type: SportsCardEnum) -> SportsCard {
        let mut player_tuples = players::player_tuples;
        player_tuples.shuffle(&mut thread_rng());
        // Only those ranked 1 to 4 ( Vec<&(&str, i8) )
        let mut player_inserts_tuple = player_tuples.iter().filter(|player| player.1 <= 4).collect::< Vec<_> > ();
        let mut rng = thread_rng();
        player_inserts_tuple.shuffle(&mut thread_rng());
        let player_inserts_tuple_length = player_inserts_tuple.len();
        let shuffle_interval = 7;
        let mut end_border = self.begin_insert_border + shuffle_interval;
        let index = rng.gen_range(self.begin_insert_border..end_border);
        let player_insert = player_inserts_tuple[index];
        //iterate to next level in tuple for the next function call
        self.begin_insert_border = self.begin_insert_border + shuffle_interval;
        let mut insert = SportsCard
        { 
            sports_card_type: sports_card_type,
            player_name: player_insert.0.to_string(),
            player_tier: player_insert.1,
            ..Default::default() 
        };
        insert.price = insert.get_price();
        insert
    }
    fn fill_pack(&mut self) -> () 
    {
        let mut cards: Vec<SportsCard> = vec![];
        let mut rng = thread_rng();
        let random_number = rng.gen_range(0..60000);
        let pack_insert_type: SportsCardEnum = match random_number
        {
            _ if random_number % SportsCardEnum::PatchAutograph.odds() == 0  => SportsCardEnum::PatchAutograph,
            _ if random_number % SportsCardEnum::Patch.odds() == 1  => SportsCardEnum::Patch,
            _ if random_number % SportsCardEnum::Jersey.odds() == 2  => SportsCardEnum::Jersey,
            _ if random_number % SportsCardEnum::Insert(6).odds() == 3  => SportsCardEnum::Insert(6),   
            _ if random_number % SportsCardEnum::AtomicRefractor.odds() == 4  => SportsCardEnum::AtomicRefractor,
            _ if random_number % SportsCardEnum::Insert(5).odds() == 5  => SportsCardEnum::Insert(5),
            _ if random_number % SportsCardEnum::Autograph.odds() == 6  => SportsCardEnum::Autograph,
            _ if random_number % SportsCardEnum::Insert(4).odds() == 7  => SportsCardEnum::Insert(4),
            _ if random_number % SportsCardEnum::Refractor.odds() == 8  => SportsCardEnum::Refractor,
            _ if random_number % SportsCardEnum::Insert(3).odds() == 9  => SportsCardEnum::Insert(3),
            _ if random_number % SportsCardEnum::Insert(2).odds() == 10  => SportsCardEnum::Insert(2),
            _ if random_number % SportsCardEnum::Insert(1).odds() == 0  => SportsCardEnum::Insert(1),
            _ => SportsCardEnum::Plain,
        };
        self.status_of_pack = pack_insert_type.clone();
        for i in (0..amount_of_cards_in_pack)
        {
            let mut card = self.get_regular_card();
            card.price = card.get_price();
            cards.push(card);
        }
        //If there is an insert, put ONE insert in
        cards[3] = match pack_insert_type
        {
            _ if pack_insert_type != SportsCardEnum::Plain => {
                let mut insert = self.get_insert(pack_insert_type);
                insert.price = insert.get_price();
                insert
            },
            _ => self.get_regular_card()
        };
        self.cards = cards.clone();
        //regular cards gone
    }
    fn display(&self) -> ()
    {
        let mut price = 0.0;
        println!("");
        for card in &self.cards
        {
            println!("You got a {:?} card of {} worth ${:.2}!", card.sports_card_type.name_of_insert(), card.player_name, card.price);
            price += card.price;
        }
        println!("");
        println!("The total price of your pack is ${:.2}!", price.round());
        println!("");
    } 
    fn get_price(&self) -> f32
    {
        let mut pack_price = 0.0;
        for card in &self.cards
        {
            pack_price += card.price;
        }
        pack_price
    }
}
impl Default for Pack 
{
     fn default() -> Self { 
        Pack { 
            cards: vec![],
            status_of_pack: SportsCardEnum::Plain,
            begin_border: 0,
            begin_insert_border: 0
        }
     }
}
#[derive(Debug)]
struct Box
{
    packs: Vec<Pack>,
    best_pack: Pack
}
impl Box {
    fn fill_box(&mut self) {
    }
    fn new() -> Box
    {
        let mut packs = vec![];
        for i in (0..amount_of_packs_in_box)
        {
            let mut pack = Pack::default();
            pack.fill_pack();
            packs.push(pack);
        } 
        Box { packs , ..Default::default()}
    }
    fn retrieve_pack(&self,numeric_choice: i8) -> &Pack 
    {
        let index = numeric_choice as usize;
        let packs = &self.packs;
        //zero-indexed
        let pack = packs.get(index-1).unwrap();
        pack
    }
    fn greatest_cards(&self) -> Pack 
    {
        let mut largest_pack_price = 0.0;
        let mut largest_pack_index: usize = 0;
        let mut best_cards: Vec<(SportsCard,usize)> = vec![];
        let packs = &self.packs;
        for (pack_index, pack) in packs.iter().enumerate()
        {
            let mut current_pack_price = 0.0;
            for card in &pack.cards
            {
                current_pack_price += card.price;
                best_cards.push((card.clone(),pack_index));          
            }
            //traverse the best cards vector
            if current_pack_price > largest_pack_price
            {
                largest_pack_price = current_pack_price;
                largest_pack_index = pack_index;
            }
        }
        let mut best_cards = best_cards.iter().filter(|a| a.0.sports_card_type != SportsCardEnum::Plain).collect::< Vec<_> >();
        best_cards.sort_by(|a,b| (b.0.price).partial_cmp(&a.0.price).unwrap_or(core::cmp::Ordering::Equal));
        println!("The best pack was pack #{}\n", largest_pack_index + 1);
        for best_card_tuple in best_cards
        {
            println!("In pack #{}, there was a {:?} card with 1:{:#} odds that was a {} insert worth ${:.2}", best_card_tuple.1 + 1, best_card_tuple.0.player_name, best_card_tuple.0.sports_card_type.odds(), best_card_tuple.0.sports_card_type.name_of_insert(), best_card_tuple.0.price);
        }
        (Pack{..Default::default()})
    }   
    fn ranking_pack(&self, user_pack: &Pack) -> () 
    {
        let mut pack_prices_vector = vec![];
        //fill vector of pack prices
        for pack in &self.packs
        {
            let mut pack_price = 0.0;
            pack_prices_vector.push(pack.get_price());
        }
        pack_prices_vector.sort_by(|a, b| a.partial_cmp(b).unwrap());
        let mut tracking_index = 0;
        let user_pack_price = user_pack.get_price();
        for (i,pack_price) in pack_prices_vector.iter().enumerate()
        {
            if user_pack_price <= *pack_price
            {
                tracking_index = i;
                break;
            }
        }
        let rank = amount_of_packs_in_box - tracking_index as i8;  
        let rank_suffix = match rank % 10
        {
            1 => "st",
            2 => "nd",
            _ => "th"
        };
        let percentile = ((tracking_index as f32/24.0)*100.0).round();
        //zero-index to human index
        println!("Your pack was the {:#}{} best of {:#} packs. You're in {}% percentile.\n", rank,rank_suffix,pack_prices_vector.len(),percentile);
    }
}
impl Default for Box {
     fn default() -> Self { 
        Box {
            packs: vec![],
            best_pack: Pack::default()
        }
    }
}
fn main() {
    clear_console::clear();
    let mut choice = String::new();
    while choice.trim().to_lowercase() != "q" && choice.trim().to_lowercase() != "quit" && choice.trim().to_lowercase() != "no" 
    {
        let mut box_instance = Box::new();
        println!("{}","---------------------------------");
        println!("{}","|   1   |   2   |   3   |   4   |");
        println!("{}","---------------------------------");
        println!("{}","|   5   |   6   |   7   |   8   |");
        println!("{}","---------------------------------");
        println!("{}","|   9   |  10   |  11   |  12   |");
        println!("{}","---------------------------------");
        println!("{}","|  13   |  14   |  15   |  16   |");
        println!("{}","---------------------------------");
        println!("{}","|  17   |  18   |  19   |  20   |");
        println!("{}","---------------------------------");
        println!("{}","|  21   |  22   |  23   |  24   |");
        println!("{}","---------------------------------\n");
        println!("{}","You're in Jondar's Comic Books & Sports Cards!!!!! Welcome to my Store, we're happy to have you! A pack of basketcall cards will run you $4.00.\n");
        println!("{}","Hope you pull a rare gem!!\n");
        let mut message_to_user = format!("Pick a number between 1 & {}\n", amount_of_packs_in_box); 
        let mut numeric_choice = 0;
        loop
        {
            choice.clear();
            println!("{}",message_to_user);
            io::stdin().read_line(&mut choice).expect("error: unable to read user choice");
            numeric_choice = choice.trim().parse::<i8>().unwrap_or(-1);
            //bad
            if numeric_choice <  1 || numeric_choice > amount_of_packs_in_box 
            {
                message_to_user = format!("Don't be silly. Choose a correct pack number between 1 & {}...  ",amount_of_packs_in_box);
                continue;
            }
            else
            {
                break;
            }
        }
        // Box.greatest_cards();    
        clear_console::clear();
        let pack = box_instance.retrieve_pack(numeric_choice);
        println!("\nYou picked pack #{}!",choice.trim());
        pack.display();
        box_instance.ranking_pack(&pack);
        box_instance.greatest_cards();
        println!("\nDo you want to open a pack from another box of cards?");
        println!("\n(Write \"No\" or \"Q\" or \"Quit\" if you want to leave)\n");
        choice.clear();
        io::stdin().read_line(&mut choice).expect("error: unable to read user choice");
        clear_console::clear();
    }
}
            
Rust Image Reducer
A Rust tool to reduce image sizes.
Rust
Click for Portfolio
                //allow dead code
#![allow(dead_code, warnings)]
 
use image;
use std::path::Path;
 
fn main() {
    // ask user for the File Path
    let mut directory = String::new();
    println!("Enter the file path>  ");
    std::io::stdin().read_line(&mut directory).expect("Failed to read line");
    // trim directory
    directory = directory.trim().to_string();
    // make a new directory if it doesn't exist
    let new_directory = directory.to_string() + "_r";
    if !Path::new(&new_directory).exists() {
        std::fs::create_dir(&new_directory).unwrap();
    }
    // get all files in directory
    let files_in_directory = get_files_in_directory(directory);
    let first_file = &files_in_directory[0];
    let mut index = 0;
    for file_name in files_in_directory {
        let file_metadata = std::fs::metadata(&file_name).unwrap();
        let file_size = file_metadata.len();
        let quality = get_quality(file_size);
        compress_image(file_name.as_str(), quality);
 
        // index += 1;
        // if index == 10 {
        //     break;
        // }
    }
}
 
fn get_quality(file_size: u64) -> u8 {
    return match file_size {
        0..=100_000 => 80,    
        100_001..=200_000 => 72,
        200_001..=300_000 => 71,
        300_001..=400_000 => 70,
        400_001..=500_000 => 60,
        500_001..=600_000 => 25,
        600_001..=700_000 => 22,
        700_001..=800_000 => 18,
        800_001.. => 13
    };
}
 
fn get_files_in_directory(directory: String) -> Vec<String> {
    let mut files = Vec::new();
    for entry in std::fs::read_dir(directory).unwrap() {
        let entry = entry.unwrap();
        let path = entry.path();
        let extension = path.extension().unwrap_or_default().to_str().unwrap();
        let image_extensions = vec!["jpg", "jpeg", "png", "bmp", "gif", "jfif"];
        if path.is_file() && image_extensions.contains(&extension) {
            files.push(path.to_str().unwrap().to_string());
        }
    }
    files
}
 
 
//compress image using image crate and have quality parameter
fn compress_image(image_path: &str, image_quality: u8) {
    let image = image::open(image_path).unwrap();
    let mut buffer = Vec::new();
    let path = Path::new(&image_path);
    let path_directory_parent = path.parent().unwrap().to_str().unwrap();
    let file_prefix = path.file_stem().unwrap().to_str().unwrap();
    let extension = "jpg";
    let new_full_file_path = format!("{}_r/{}_{}.{}", path_directory_parent, file_prefix, image_quality, extension);
    image.write_to(&mut buffer, image::ImageOutputFormat::Jpeg(image_quality)).unwrap();
    std::fs::write(&new_full_file_path, &buffer).unwrap();
    let size_in_bytes = buffer.len();
    // println!("{} bytes written in {}", size_in_bytes, &new_full_file_path);
}
            
Python OpenGL Pyramids
OpenGL of a spinning 3D pyramid in Python!!! Looks like an amazing video game & Nintendo 64!!! (love OpenGL)
Python
Click for Portfolio
                import OpenGL
from ctypes import *
import glm
import random
import sys
 
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
from OpenGL.GL.shaders import *
 
import random
from helpers import *
from PIL import Image
 
width = 800
height = 600
 
factor = 0.55
 
texcoord_0 = [1,0]
texcoord_1 = [0,0]
texcoord_2 = [0,0]
texcoord_3 = [0,0]
texcoord_4 = [0.5,2]
 
vertices = [
   # COORDINATES  /COLORS        / TexCoord
    0.5, 0.0, 0.5, 0.0, 1.0, 0.0, texcoord_0[0], texcoord_0[1], # Vertex 0 Top Right Green
    0.5, 0.0, -0.5, 0.0, 0.0, 1.0, texcoord_1[0], texcoord_1[1], # Vertex 1 Bottom Right Blue
    -0.5, 0.0, -0.5, 0.0, 1.0, 0.0, texcoord_2[0], texcoord_2[1], # Vertex 2 Bottom Left Green
    -0.5, 0.0, 0.5, 1.0, 1.0, 0.0, texcoord_3[0], texcoord_3[1], # Vertex 3 Top Left Yellow
    0.0, 1.5, 0.0, 1.0, 0.0, 0.0, texcoord_4[0], texcoord_4[1], # Vertex 4 Pyramid Top Red
] 
 
attributes_in_vertex = 8
total_vertices = int(len(vertices) / attributes_in_vertex)
 
# PYRAMID
indices = [
     0, 1, 2, # Triangle 1
    0, 3, 2, # Triangle 2
    0, 1, 4, # Triangle 3
    1, 2, 4, # Triangle 4
    2, 3, 4, # Triangle 5
    3, 0, 4, # Triangle 6
]
 
vertex_shader = """
#version 330 core
 
// Positions/Coordinates
layout (location = 0) in vec3 aPos;
// Colors
layout (location = 1) in vec3 aColor;
// Texture Coordinates
layout (location = 2) in vec2 aTex;
 
 
// Outputs the color for the Fragment Shader
out vec3 color;
// Outputs the texture coordinates to the fragment shader
out vec2 texCoord;
out vec4 position;
flat out int instanceID;
 
// Controls the scale of the vertices
uniform float scale;
 
// Inputs the matrices needed for 3D viewing with perspective
uniform mat4 model;
uniform mat4 view;
uniform mat4 proj;
 
 
 
 
float cube_root(float x)
{
    return pow(x, 1.0 / 3.0);
}
 
float dec(float x)
{
    return x - floor(x);
}
 
 
float strip_dec(float x)
{
    return int(x) % 1;
}
 
void main()
{
    // line the shapes next to each other on the x-axis based on gl_InstanceID
    // move the location of the pyramid based on the gl_InstanceID
    
    float distance = 4.0;
    float cube_radius = ceil(cube_root(2500));
    float squared = pow(cube_radius, 2);
   
    // left-right horizontal
    // floor(((77 % 16) / 16) * 5)
    float move_z = floor(((gl_InstanceID % int(squared)) / squared) * cube_radius) * distance;
 
    // 
    // height 
    //
    //    64 / 16 = 4th level
    //
    float move_y = floor(gl_InstanceID / squared) * distance;
 
    // towards me
    float move_x = floor(gl_InstanceID % int(cube_radius)) * distance;
 
    
    
    
    gl_Position = proj * view * vec4(aPos.x + move_x, aPos.y + move_y, aPos.z + move_z, 1.0);
    position = proj * view * vec4(aPos.x + move_x, aPos.y + move_y, aPos.z + move_z, 1.0);
	// Assigns the colors from the Vertex Data to "color"
	color = aColor;
	// Assigns the texture coordinates from the Vertex Data to "texCoord"
	texCoord = aTex;
    instanceID = gl_InstanceID;
}
"""
 
fragment_shader = """
#version 330 core
 
// Outputs colors in RGBA
out vec4 FragColor;
 
// Inputs the color from the Vertex Shader
in vec3 color;
in vec4 position;
// Inputs the texture coordinates from the Vertex Shader
in vec2 texCoord;
 
flat in int instanceID;
 
// Inputs the texture sampler
uniform float count;
uniform sampler2D imageTextureFoxNews;
uniform sampler2D imageTextureCnn;
uniform sampler2D imageTextureMsnbc;
uniform sampler2D imageTextureAbc;
 
 
 
 
void main()
{
 
    vec4 texture_colors;
    
    if(instanceID % 4 == 0)
    {
	    texture_colors = texture2D(imageTextureFoxNews, texCoord);
    }
    else if (instanceID % 4 == 1)
    {
        texture_colors = texture2D(imageTextureCnn, texCoord);
    }
    else if (instanceID % 4 == 2)
    {
        texture_colors = texture2D(imageTextureMsnbc, texCoord);
    }
    else if (instanceID % 4 == 3)
    {
        texture_colors = texture2D(imageTextureAbc, texCoord);
    }
 
   
    
 
    //shine light from position that was passed in
    vec3 diffuse_color = vec3(1.0, 1.0, 1.0);
    vec3 specular_color = vec3(1.0, 1.0, 1.0);
    vec3 ambient_color = vec3(1.0, 1.0, 1.0);
    float shininess = .60;
    float light_intensity = 0.05;
    float ambient_intensity = 0.0;
    float diffuse_intensity = 2.0;
    float specular_intensity = 10.0;
    
    vec3 normal = normalize(position.xyz);
    
    float locations[2] = {200.0,2.0};
    float location = 0.0;
 
 
    vec3 view_position, light_position, view_direction, light_direction, reflect_direction;
    float diffuse_factor, specular_factor;
    vec4 diffuse_color_final, specular_color_final;
    int j = 0;
 
    
    //to iterate through the location array
    for(j = 0; j < 3; j++)
    {
        location = locations[j];
        light_position = vec3(-5.0, location, 0.0);
        view_position = vec3(location, location, 300.0);
        light_direction = normalize(light_position - position.xyz);
        view_direction = normalize(view_position - position.xyz);
        diffuse_factor = max(dot(light_direction, normal), 0.0);
        reflect_direction = reflect(light_direction, normal);
        diffuse_color_final += vec4(diffuse_color * diffuse_factor, 1.0) * light_intensity;
        specular_factor = pow(max(dot(view_direction, reflect_direction), 0.0), shininess);
        specular_color_final += vec4(specular_color * light_intensity * specular_intensity * specular_factor, 256.0);
    }
    
 
    
    vec4 ambient_color_final = vec4(ambient_color * light_intensity * ambient_intensity, 1.0);
    vec4 final_color = diffuse_color_final + specular_color_final + ambient_color_final;
 
    // get x & y from the texture
    float texCoordX = texCoord.x;
    float texCoordY = texCoord.y;
    // get resolution variables from the texture
    float resolutionX = texture_colors.x;
    float resolutionY = texture_colors.y;
    
 
    FragColor = final_color * texture_colors;
 
}
"""
 
def bind_vao_to_vbo(vbo, location_in_shader, elements_in_attribute, element_type, values_as_is_bool, stride, offset):
    #
    # location in shader - a number that represents the attribute that's listed ON the top of shader
    # elements in attribute - how many elements are in the attribute
    # element type - the type of each element
    # values as-is bool - are the values as-is?
    # stride - stride is the size of a single vertex!! So if you have 3 for position, 3 for color, and 2 for texture, the stride is 8
    # offset - offset is the distance away from the zero element in the vertex/vertice array
    #
    # binds the vao to the vbo
    glBindBuffer(GL_ARRAY_BUFFER, vbo)
    # defines the attribute in the shader
    glVertexAttribPointer(location_in_shader, elements_in_attribute, element_type, values_as_is_bool, stride, offset)
    # enables the attribute in the shader
    glEnableVertexAttribArray(location_in_shader)
    # unbinds the vao from the vbo
    glBindBuffer(GL_ARRAY_BUFFER, 0)
 
def set_uniform_shader_variable(name, value):
    global program
    location = glGetUniformLocation(program, name)
    if type(value) == glm.vec3:
        glUniform3fv(location, 1, glm.value_ptr(value))
    elif type(value) == glm.mat4:
        glUniformMatrix4fv(location, 1, GL_FALSE, glm.value_ptr(value))
    elif type(value) == int:
        # typically used for scale & translation & textures
        glUniform1i(location, value)
    elif type(value) == float:
        glUniform1f(location, value)
    else:
        print("Unsupported type")
 
def file_get_contents(filename):
    with open(filename) as f:
        return f.read()
 
class Texture:
 
    def __init__(self, filepath):
        self.texture = glGenTextures(1)
        glBindTexture(GL_TEXTURE_2D, self.texture)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
        image = Image.open(filepath)
        image_width, image_height = image.size
        image_bytes = image.tobytes('raw', 'RGBA', 0, -1)
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image_width, image_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_bytes)
        glGenerateMipmap(GL_TEXTURE_2D)
 
    def use(self, fragment_shader_location):
        glActiveTexture(GL_TEXTURE0 + fragment_shader_location)
        glBindTexture(GL_TEXTURE_2D,self.texture)
 
    def destroy(self):
        glDeleteTextures(1, (self.texture,))
 
 
# make context
glutInit()
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH)
glutInitWindowSize(width, height)
glutCreateWindow("Pyramid")
# WITHOUT THIS YOU WILL HAVE TRANSPARENT COLORS & TRANSPARENT FACES OF THE SHAPE
glEnable(GL_DEPTH_TEST);
 
# compile shaders
vertex_shader = compileShader(vertex_shader, GL_VERTEX_SHADER)
fragment_shader = compileShader(fragment_shader, GL_FRAGMENT_SHADER)
 
# create program & link shaders
program = glCreateProgram()
glAttachShader(program, vertex_shader)
glAttachShader(program, fragment_shader)
glLinkProgram(program)
 
# use program that consists of shaders
glUseProgram(program)
 
# create a vertex array object (VAO)
vao = glGenVertexArrays(1)
glBindVertexArray(vao)
 
# create a vertex buffer object (VBO)
id = 0
vbo = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, vbo)
 
# create a element buffer object (EBO)
ebo = glGenBuffers(1)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo)
 
 
 
 
# copy index data to GPU (from the EBO)
glBufferData(
    GL_ELEMENT_ARRAY_BUFFER, # target
    len(indices) * sizeof(c_int), # size in bytes
    (c_int * len(indices))(*indices), # data to be sent to the buffer
    GL_STATIC_DRAW # usage 
)
 
# copy vertices data to the GPU (from the VBO)
glBufferData(GL_ARRAY_BUFFER, len(vertices) * sizeof(c_float), (c_float * len(vertices))(*vertices), GL_STATIC_DRAW)
 
# define each attribute of each Vertex Array Object (VAO) & bind it to the Vertex Buffer Object (VBO)
# these three functions pertain to ONE vertex each, which has attributes like position, color, and texture
bind_vao_to_vbo(vbo, 0, 3, GL_FLOAT, GL_FALSE, sizeof(c_float) * 8, c_void_p(0))
bind_vao_to_vbo(vbo, 1, 3, GL_FLOAT, GL_FALSE, sizeof(c_float) * 8, c_void_p(3 * sizeof(c_float)))
bind_vao_to_vbo(vbo, 2, 2, GL_FLOAT, GL_FALSE, sizeof(c_float) * 8, c_void_p(6 * sizeof(c_float)))
 
#unbind VAO & EBO (the VBO is already unbound)
glBindVertexArray(0)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
 
 
 
 
 
 
 
 
#
#
#   TEXTURES
#
#
fox_news_texture = Texture("fox_news_square_rbga.png")
cnn_texture = Texture("cnn_rbga.png")
msnbc_texture = Texture("msnbc_rbga.png")
abc_texture = Texture("abc_rbga.png")
 
# define variables for render function
rotation = 0.0
rotation_speed = 0.2
model_1 = 0.0
model_2 = 1.0
model_3 = 0.0
translate_1 = -10
translate_2 = -10
translate_3 = -20
proj_radians = 45.0
proj_1 = 0.1
proj_2 = 100.0
count = 0.0
 
# def debug():
#     model = glm.mat4(1.0);
#     view = glm.mat4(1.0);
#     proj = glm.mat4(1.0);
#     global rotation
#     rotation += 0.2
#     model = glm.rotate(model, glm.radians(rotation), glm.vec3(model_1, model_2, model_3))
#     view = glm.translate(view, glm.vec3(0.0, -0.5, -10.0))
#     proj = glm.perspective(glm.radians(45.0), width / height, 0.1, 100.0)
#     print("model: \n", model)
#     print("view: \n", view)
#     print("proj: \n", proj)
 
# debug()
 
def render():
    model = glm.mat4(1.0);
    view = glm.mat4(1.0);
    proj = glm.mat4(1.0);
    global rotation
    global rotation_speed
    global count
    rotation += rotation_speed
    model = glm.rotate(model, glm.radians(rotation), glm.vec3(model_1, model_2, model_3))
    view = glm.translate(view, glm.vec3(translate_1, translate_2, translate_3))
    proj = glm.perspective(glm.radians(proj_radians), width / height, proj_1, proj_2)
    set_uniform_shader_variable("model", model)
    set_uniform_shader_variable("view", view)
    set_uniform_shader_variable("proj", proj)
    set_uniform_shader_variable("imageTextureFoxNews",0)
    set_uniform_shader_variable("imageTextureCnn",1)
    set_uniform_shader_variable("imageTextureMsnbc",2)
    set_uniform_shader_variable("imageTextureAbc",3)
    set_uniform_shader_variable("count",count)
    count += .02
 
    # use texture
    fox_news_texture.use(0)
    cnn_texture.use(1)
    msnbc_texture.use(2)
    abc_texture.use(3)
    
    # bind vao
    glBindVertexArray(vao)
    # start drawing
    # glClearColor(0.5, 0.5, 0.5, 1.0)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    # glDrawArrays(GL_TRIANGLES, 0, len(vertices))
    # glDrawElements(GL_TRIANGLES, len(indices), GL_UNSIGNED_INT, c_void_p(0))
    glDrawElementsInstanced(GL_TRIANGLES, len(indices), GL_UNSIGNED_INT, c_void_p(0), 2500)
    glutSwapBuffers()
    # poll events
    glutPostRedisplay()
 
 
def key_pressed(*args):
    global model_1
    global model_2
    global model_3
    global rotation_speed
    global translate_1
    global translate_2
    global translate_3
    global proj_radians
    global proj_1
    global proj_2
    amount = 0.1
    if args[0] == b'q':
        model_1 += amount
    elif args[0] == b'a':
        model_1 -= amount
    elif args[0] == b'w':
        model_2 += amount
    elif args[0] == b's':
        model_2 -= amount
    elif args[0] == b'e':
        model_3 += amount
    elif args[0] == b'd':
        model_3 -= amount
    elif args[0] == b'r':
        rotation_speed += amount
    elif args[0] == b'f':
        rotation_speed -= amount
    elif args[0] == b't':
        translate_1 -= amount
    elif args[0] == b'g':
        translate_1 += amount
    elif args[0] == b'y':
        translate_2 -= amount
    elif args[0] == b'h':
        translate_2 += amount
    elif args[0] == b'u':
        translate_3 += amount
    elif args[0] == b'j':
        translate_3 -= amount
    elif args[0] == b'i':
        proj_radians += amount
    elif args[0] == b'k':
        proj_radians -= amount
    elif args[0] == b'o':
        proj_1 += amount
    elif args[0] == b'l':
        proj_1 -= amount
    elif args[0] == b'p':
        proj_2 += amount
    elif args[0] == b';':
        proj_2 -= amount
 
 
# define callbacks
glutDisplayFunc(render)
glutKeyboardFunc(key_pressed)
glutMainLoop()
 
# cleanup
glDisableVertexAttribArray(0)
fox_news_texture.cleanup()
glBindBuffer(GL_ARRAY_BUFFER, 0)
glBindVertexArray(0)
glUseProgram(0)
glDeleteProgram(program)
glDeleteBuffers(1, vbo)
glDeleteVertexArrays(1, vao)

            
AWS Transit Gateway
Terraform configuration for AWS Transit Gateway.
Terraform
Click for Portfolio
                # VPCS
 
resource "aws_vpc" "vpc_1" {
  cidr_block = "10.1.0.0/16"
  tags = {
    name = "VPC 1"
  }
}
 
resource "aws_vpc" "vpc_2" {
  cidr_block = "10.2.0.0/16"
  tags = {
    name = "VPC 2"
  }
}
 
# SUBNETS
 
resource "aws_subnet" "subnet_1" {
  cidr_block = "10.1.0.0/24"
  vpc_id     = aws_vpc.vpc_1.id
}
 
resource "aws_subnet" "subnet_2" {
  cidr_block = "10.2.0.0/24"
  vpc_id     = aws_vpc.vpc_2.id
}
 
# INTERNET GATEWAYS
#
# You must have an internet gateway inside of a VPC if you want to SSH into it's instance. Also make sure a network security group is in both the subnet & instance in AWS.
#
resource "aws_internet_gateway" "igw_1" {
  vpc_id = aws_vpc.vpc_1.id
}
 
resource "aws_internet_gateway" "igw_2" {
  vpc_id = aws_vpc.vpc_2.id
}
 
# ROUTE TABLES
#
# Appears that a Route Table in AWS goes into a VPC. Inside of it, it can be sent to certain subnets
# in it's VPC via the aws route_table_association resource
#
 
 
resource "aws_route_table" "route_table_1" {
  vpc_id = aws_vpc.vpc_1.id
  tags = {
    name = "route_table_1"
  }
}
 
resource "aws_route" "route_to_igw_1" {
  route_table_id         = aws_route_table.route_table_1.id
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = aws_internet_gateway.igw_1.id
}
 
resource "aws_route" "route_to_tgw_in_vpc_1" {
  route_table_id         = aws_route_table.route_table_1.id
  destination_cidr_block = "10.0.0.0/8"
  gateway_id             = aws_ec2_transit_gateway.tgw_mark.id
  depends_on             = [aws_ec2_transit_gateway.tgw_mark]
}
 
 
resource "aws_route_table_association" "subnet_association_1" {
  subnet_id      = aws_subnet.subnet_1.id
  route_table_id = aws_route_table.route_table_1.id
}
 
resource "aws_route_table" "route_table_2" {
  vpc_id = aws_vpc.vpc_2.id
  tags = {
    name = "route_table_2"
  }
}
 
resource "aws_route" "route_to_igw_2" {
  route_table_id         = aws_route_table.route_table_2.id
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = aws_internet_gateway.igw_2.id
}
 
resource "aws_route" "route_to_tgw_in_vpc_2" {
  route_table_id         = aws_route_table.route_table_2.id
  destination_cidr_block = "10.0.0.0/8"
  gateway_id             = aws_ec2_transit_gateway.tgw_mark.id
  depends_on             = [aws_ec2_transit_gateway.tgw_mark]
}
 
resource "aws_route_table_association" "subnet_association_2" {
  subnet_id      = aws_subnet.subnet_2.id
  route_table_id = aws_route_table.route_table_2.id
}
 
 
 
 
 
 
 
 
# NETWORK SECURITY GROUPS
# 
# in AWS, a security group is connected to the VPC
# 
# Define the first security group for VPC 1
resource "aws_security_group" "allow_ssh_group_vpc_1" {
  name        = "allow_ssh_group_vpc_1"
  description = "Allow SSH Group VPC 1"
  vpc_id      = aws_vpc.vpc_1.id
 
  # Define ingress rules directly within the security group
  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
 
  ingress {
    from_port   = 8
    to_port     = 0
    protocol    = "icmp"
    cidr_blocks = ["0.0.0.0/0"]
  }
 
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}
 
# Define the second security group for VPC 2
resource "aws_security_group" "allow_ssh_group_vpc_2" {
  name        = "allow_ssh_group_vpc_2"
  description = "Allow SSH Group VPC 2"
  vpc_id      = aws_vpc.vpc_2.id
 
  # Define ingress rules directly within the security group
  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
 
  ingress {
    from_port   = 8
    to_port     = 0
    protocol    = "icmp"
    cidr_blocks = ["0.0.0.0/0"]
  }
 
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}
 
 
#########################
# 
#    EC2 VIRTUAL MACHINES
#
#########################
#
# 
# ssh -i key_pair_2023.pem ec2-user@ec2-34-236-144-211.compute-1.amazonaws.com
#
# 1) Make sure there's internet gateway
# 2) Make sure there's security groups in VPC & EC2
# 3) Make sure there's a default route to the internet gateway
#
#
resource "aws_instance" "ec2_vpc_1_subnet_1" {
  ami                         = "ami-051f7e7f6c2f40dc1"
  subnet_id                   = aws_subnet.subnet_1.id
  instance_type               = "t2.micro"
  key_name                    = "key_pair_2023" 
  vpc_security_group_ids      = [aws_security_group.allow_ssh_group_vpc_1.id]
  associate_public_ip_address = true
}
resource "aws_instance" "ec2_vpc_2_subnet_2" {
  ami                         = "ami-051f7e7f6c2f40dc1"
  subnet_id                   = aws_subnet.subnet_2.id
  instance_type               = "t2.micro"
  key_name                    = "key_pair_2023" 
  vpc_security_group_ids      = [aws_security_group.allow_ssh_group_vpc_2.id]
  associate_public_ip_address = true
}
output "instance_public_ip" {
  value = aws_instance.ec2_vpc_1_subnet_1.public_ip
}
 
output "instance_public_dns" {
  value = aws_instance.ec2_vpc_1_subnet_1.public_dns
}
 
 
 
 
 
 
 
#
# TRANSIT GATEWAY
#
#
#
resource "aws_ec2_transit_gateway" "tgw_mark" {
  description = "Mark's Transit Gateway"
  default_route_table_association = "enable"
  default_route_table_propagation = "enable"
  amazon_side_asn = 64512
  tags = {
    name = "tgw_mark"
  }
}
 
#
# TRANSIT GATEWAY ATTACHMENTS
#
# Attachments to other VPCs
#
#
resource "aws_ec2_transit_gateway_vpc_attachment" "vpc_1_attachment" {
  transit_gateway_id = aws_ec2_transit_gateway.tgw_mark.id
  vpc_id             = aws_vpc.vpc_1.id
  subnet_ids         = [aws_subnet.subnet_1.id]
  tags = {
    name = "vpc_1_attachment"
  }
}
 
resource "aws_ec2_transit_gateway_vpc_attachment" "vpc_2_attachment" {
  transit_gateway_id = aws_ec2_transit_gateway.tgw_mark.id
  vpc_id             = aws_vpc.vpc_2.id
  subnet_ids         = [aws_subnet.subnet_2.id]
  tags = {
    name = "vpc_2_attachment"
  }
}
 

            
Azure Transit Gateway
Terraform configuration for Azure's version of Transit Gateway.
Terraform
Click for Portfolio
                 
# RESOURCE GROUP
 
resource "azurerm_resource_group" "resource_group_mark_mulcahy" {
  name     = var.resource_group_name
  location = var.location
}
 
 
 
# NETWORK SECURITY GROUPS
 
resource "azurerm_network_security_group" "security_group_mark" {
  name                = "security_group_mark"
  location            = var.location
  resource_group_name = var.resource_group_name
}
 
resource "azurerm_network_security_rule" "allow_ssh_rule" {
  name                        = "allow_ssh_rule"
  priority                    = 100
  direction                   = "Inbound"
  access                      = "Allow"
  protocol                    = "Tcp"
  source_port_range           = "*"
  destination_port_range      = "22"
  source_address_prefix       = "0.0.0.0/0" # You can change this to a more specific address or range
  destination_address_prefix  = "*"
  resource_group_name         = var.resource_group_name
  network_security_group_name = azurerm_network_security_group.security_group_mark.name
}
 
resource "azurerm_network_security_rule" "allow_ping_rule" {
  name                        = "allow_ping_rule"
  priority                    = 101
  direction                   = "Inbound"
  access                      = "Allow"
  protocol                    = "Icmp"
  source_port_range           = "*"
  destination_port_range      = "*"
  source_address_prefix       = "0.0.0.0/0" # You can change this to a more specific address or range
  destination_address_prefix  = "*"
  resource_group_name         = var.resource_group_name
  network_security_group_name = azurerm_network_security_group.security_group_mark.name
}
 
 
# VIRTUAL NETWORKS
 
resource "azurerm_virtual_network" "gateway_hub" {
  name                = "gateway_hub"
  location            = var.location
  resource_group_name = var.resource_group_name
  address_space       = ["10.0.0.0/16"]
}
 
resource "azurerm_virtual_network" "vpc_1" {
  name                = "vpc_1"
  location            = var.location
  resource_group_name = var.resource_group_name
  address_space       = ["10.1.0.0/16"]
}
 
resource "azurerm_virtual_network" "vpc_2" {
  name                = "vpc_2"
  location            = var.location
  resource_group_name = var.resource_group_name
  address_space       = ["10.2.0.0/16"]
}
 
 
 
 
 
 
# SUBNETS
 
resource "azurerm_subnet" "subnet_hub" {
  name                 = "subnet_hub"
  resource_group_name  = var.resource_group_name
  virtual_network_name = azurerm_virtual_network.gateway_hub.name
  address_prefixes     = ["10.0.0.0/24"]
}
 
resource "azurerm_subnet" "subnet_1" {
  name                 = "subnet_1"
  resource_group_name  = var.resource_group_name
  virtual_network_name = azurerm_virtual_network.vpc_1.name
  address_prefixes     = ["10.1.0.0/24"]
}
 
resource "azurerm_subnet" "subnet_2" {
  name                 = "subnet_2"
  resource_group_name  = var.resource_group_name
  virtual_network_name = azurerm_virtual_network.vpc_2.name
  address_prefixes     = ["10.2.0.0/24"]
}
 
resource "azurerm_subnet" "subnet_hub_virtual_gateway" {
  name                 = "GatewaySubnet"
  resource_group_name  = var.resource_group_name
  virtual_network_name = azurerm_virtual_network.gateway_hub.name
  address_prefixes     = ["10.0.1.0/24"]
}
 
 
 
 
# ROUTE TABLES
 
# VPC 1 / SUBNET 1 Route Table
resource "azurerm_route_table" "route_table_1" {
  name                = "route_table_1"
  location            = var.location
  resource_group_name = var.resource_group_name
}
 
resource "azurerm_route" "route_1" {
  name                = "route_1"
  resource_group_name = var.resource_group_name
  route_table_name    = azurerm_route_table.route_table_1.name
  address_prefix      = "10.2.0.0/16"
  next_hop_type       = "VirtualNetworkGateway"
}
 
resource "azurerm_subnet_route_table_association" "route_subnet_association_1" {
  subnet_id      = azurerm_subnet.subnet_1.id
  route_table_id = azurerm_route_table.route_table_1.id
}
 
# VPC 2 / SUBNET 2 Route Table
resource "azurerm_route_table" "route_table_2" {
  name                = "route_table_2"
  location            = var.location
  resource_group_name = var.resource_group_name
}
 
resource "azurerm_route" "route_2" {
  name                = "route_2"
  resource_group_name = var.resource_group_name
  route_table_name    = azurerm_route_table.route_table_2.name
  address_prefix      = "10.1.0.0/16"
  next_hop_type       = "VirtualNetworkGateway"
}
 
resource "azurerm_subnet_route_table_association" "route_subnet_association_2" {
  subnet_id      = azurerm_subnet.subnet_2.id
  route_table_id = azurerm_route_table.route_table_2.id
}
 
 
 
 
 
 
 
 
 
 
#########################
# 
#    VIRTUAL MACHINES
#
#
#
# Virtual Machine has a Network Interface
# Network Interface ID has a Public IP
# Public IP chooses location of this virtual machine
#
#
 
#########################
# 
#    VIRTUAL MACHINE IN HUB
#
#########################
 
##### PUBLIC IP #####
resource "azurerm_public_ip" "public_ip_hub" {
  name                = "public_ip_hub"
  location            = var.location
  resource_group_name = var.resource_group_name
  allocation_method   = "Dynamic"
}
 
##### NETWORK INTERFACE #####
resource "azurerm_network_interface" "network_interface_hub" {
  name                = "network_interface_hub"
  location            = var.location
  resource_group_name = var.resource_group_name
  ip_configuration {
    name                          = "ip_configuration"
    subnet_id                     = azurerm_subnet.subnet_hub.id
    private_ip_address_allocation = "Dynamic"
    public_ip_address_id          = azurerm_public_ip.public_ip_hub.id
  }
}
 
##### NETWORK INTERFACE TO SECURITY GROUP ASSOCIATION #####
resource "azurerm_network_interface_security_group_association" "nsg_association_hub" {
  network_interface_id      = azurerm_network_interface.network_interface_hub.id
  network_security_group_id = azurerm_network_security_group.security_group_mark.id
}
 
##### SUBNET INTERFACE TO SECURITY GROUP ASSOCIATION ##### 
resource "azurerm_subnet_network_security_group_association" "ssh_nsg_to_vpc_hub" {
  subnet_id                 = azurerm_subnet.subnet_hub.id
  network_security_group_id = azurerm_network_security_group.security_group_mark.id
}
 
 
##### VIRTUAL MACHINE #####
#
# Virtual Machine has a Network Interface
# Network Interface ID has a Public IP
#
resource "azurerm_linux_virtual_machine" "virtual_machine_hub" {
  name                = "VMHub"
  location            = var.location
  resource_group_name = var.resource_group_name
  network_interface_ids = [
    azurerm_network_interface.network_interface_hub.id,
  ]
  size                            = "Standard_B1ls"
  admin_username                  = var.vm_username
  admin_password                  = var.vm_password # Password
  disable_password_authentication = false           # Disable SSH so Text Password can be used
  source_image_reference {
    publisher = "Canonical"
    offer     = "UbuntuServer"
    sku       = "18.04-LTS"
    version   = "latest"
  }
  os_disk {
    caching              = "ReadWrite"
    storage_account_type = "Standard_LRS"
    name                 = "myosdisk"
  }
}
 
 
 
 
 
 
 
#########################
# 
#    VIRTUAL MACHINE IN SUBNET 1
#
#    
#
#########################
 
 
##### PUBLIC IP #####
resource "azurerm_public_ip" "public_ip_1" {
  name                = "public_ip_1"
  location            = var.location
  resource_group_name = var.resource_group_name
  allocation_method   = "Dynamic"
}
 
##### NETWORK INTERFACE #####
resource "azurerm_network_interface" "network_interface_1" {
  name                = "network_interface_1"
  location            = var.location
  resource_group_name = var.resource_group_name
  ip_configuration {
    name                          = "ip_configuration"
    subnet_id                     = azurerm_subnet.subnet_1.id
    private_ip_address_allocation = "Dynamic"
    public_ip_address_id          = azurerm_public_ip.public_ip_1.id
  }
}
 
##### NETWORK INTERFACE TO SECURITY GROUP ASSOCIATION #####
resource "azurerm_network_interface_security_group_association" "nsg_association_1" {
  network_interface_id      = azurerm_network_interface.network_interface_1.id
  network_security_group_id = azurerm_network_security_group.security_group_mark.id
}
 
##### SUBNET INTERFACE TO SECURITY GROUP ASSOCIATION ##### 
resource "azurerm_subnet_network_security_group_association" "ssh_nsg_to_vpc_1" {
  subnet_id                 = azurerm_subnet.subnet_1.id
  network_security_group_id = azurerm_network_security_group.security_group_mark.id
}
 
 
##### VIRTUAL MACHINE #####
#
# Virtual Machine has a Network Interface
# Network Interface ID has a Public IP
#
resource "azurerm_linux_virtual_machine" "virtual_machine_1" {
  name                = "VMSubnet1"
  location            = var.location
  resource_group_name = var.resource_group_name
  network_interface_ids = [
    azurerm_network_interface.network_interface_1.id,
  ]
  size                            = "Standard_B1ls"
  admin_username                  = var.vm_username
  admin_password                  = var.vm_password # Password
  disable_password_authentication = false           # Disable SSH so Text Password can be used
  source_image_reference {
    publisher = "Canonical"
    offer     = "UbuntuServer"
    sku       = "18.04-LTS"
    version   = "latest"
  }
  os_disk {
    caching              = "ReadWrite"
    storage_account_type = "Standard_LRS"
    name                 = "myosdisk_subnet_1"
  }
}
 
 
 
 
 
 
#########################
# 
#    VIRTUAL MACHINE IN SUBNET 2
#
#    
#
#########################
 
 
##### PUBLIC IP #####
resource "azurerm_public_ip" "public_ip_2" {
  name                = "public_ip_2"
  location            = var.location
  resource_group_name = var.resource_group_name
  allocation_method   = "Dynamic"
}
 
##### NETWORK INTERFACE #####
resource "azurerm_network_interface" "network_interface_2" {
  name                = "network_interface_2"
  location            = var.location
  resource_group_name = var.resource_group_name
  ip_configuration {
    name                          = "ip_configuration"
    subnet_id                     = azurerm_subnet.subnet_2.id
    private_ip_address_allocation = "Dynamic"
    public_ip_address_id          = azurerm_public_ip.public_ip_2.id
  }
}
 
 
#
#    Security group assignment to network Interface 
#
resource "azurerm_network_interface_security_group_association" "nsg_association_2" {
  network_interface_id      = azurerm_network_interface.network_interface_2.id
  network_security_group_id = azurerm_network_security_group.security_group_mark.id
}
 
#
#    Security group assignment to subnet
#
resource "azurerm_subnet_network_security_group_association" "ssh_nsg_to_vpc_2" {
  subnet_id                 = azurerm_subnet.subnet_2.id
  network_security_group_id = azurerm_network_security_group.security_group_mark.id
}
 
 
##### VIRTUAL MACHINE #####
#
# Virtual Machine has a Network Interface
# Network Interface ID has a Public IP
#
resource "azurerm_linux_virtual_machine" "virtual_machine_2" {
  name                = "VMSubnet2"
  location            = var.location
  resource_group_name = var.resource_group_name
  network_interface_ids = [
    azurerm_network_interface.network_interface_2.id,
  ]
  size                            = "Standard_B1ls"
  admin_username                  = var.vm_username
  admin_password                  = var.vm_password # Password
  disable_password_authentication = false           # Disable SSH so Text Password can be used
  source_image_reference {
    publisher = "Canonical"
    offer     = "UbuntuServer"
    sku       = "18.04-LTS"
    version   = "latest"
  }
  os_disk {
    caching              = "ReadWrite"
    storage_account_type = "Standard_LRS"
    name                 = "myosdisk_subnet_2"
  }
}
 
 
 
 
 
 
 
 
 
 
 
 
 
#########################
# 
#    VIRTUAL NETWORK GATEWAY
#
#########################
 
resource "azurerm_public_ip" "public_ip_hub_vnet_gateway" {
  name                = "public_ip_hub_vnet_gateway"
  location            = var.location
  resource_group_name = var.resource_group_name
  allocation_method   = "Dynamic"
}
 
resource "azurerm_virtual_network_gateway" "virtual_network_gateway" {
  name                = "virtual_network_gateway"
  location            = var.location
  resource_group_name = var.resource_group_name
  type     = "Vpn"
  vpn_type = "RouteBased"
  active_active = false
  enable_bgp    = false
  sku           = "VpnGw1"
  generation    = "Generation1"
  ip_configuration {
    name                          = "vnetGatewayConfig"
    public_ip_address_id          = azurerm_public_ip.public_ip_hub_vnet_gateway.id
    private_ip_address_allocation = "Dynamic"
    subnet_id                     = azurerm_subnet.subnet_hub_virtual_gateway.id
  }
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
#########################
# 
#    VIRTUAL NETWORK PEERINGS
#
#    Requires two way peering, and two way peering is a requirement for the Virtual Network Gateway to work
#
#########################
 
resource "azurerm_virtual_network_peering" "vpc_1_to_hub" {
  name                      = "vpc1_to_hub"
  resource_group_name       = var.resource_group_name
  virtual_network_name      = azurerm_virtual_network.vpc_1.name
  remote_virtual_network_id = azurerm_virtual_network.gateway_hub.id
  allow_virtual_network_access = true
  allow_forwarded_traffic = true
  allow_gateway_transit   = true
  use_remote_gateways     = true
  depends_on = [azurerm_virtual_network.gateway_hub, azurerm_virtual_network.vpc_1, azurerm_virtual_network.vpc_2, azurerm_virtual_network_gateway.virtual_network_gateway]
}
 
resource "azurerm_virtual_network_peering" "vpc_2_to_hub" {
  name                      = "vpc2_to_hub"
  resource_group_name       = var.resource_group_name
  virtual_network_name      = azurerm_virtual_network.vpc_2.name
  remote_virtual_network_id = azurerm_virtual_network.gateway_hub.id
  allow_virtual_network_access = true
  allow_forwarded_traffic = true
  allow_gateway_transit   = true
  use_remote_gateways     = true
  depends_on = [azurerm_virtual_network.gateway_hub, azurerm_virtual_network.vpc_1, azurerm_virtual_network.vpc_2, azurerm_virtual_network_gateway.virtual_network_gateway]
}
 
resource "azurerm_virtual_network_peering" "hub_to_vpc_1" {
  name                      = "hub_to_vpc_1"
  resource_group_name       = var.resource_group_name
  virtual_network_name      = azurerm_virtual_network.gateway_hub.name
  remote_virtual_network_id = azurerm_virtual_network.vpc_1.id
  allow_virtual_network_access = true
  allow_forwarded_traffic = true
  allow_gateway_transit   = true
  depends_on = [azurerm_virtual_network.gateway_hub, azurerm_virtual_network.vpc_1, azurerm_virtual_network.vpc_2,azurerm_virtual_network_gateway.virtual_network_gateway]
}
 
resource "azurerm_virtual_network_peering" "hub_to_vpc_2" {
  name                      = "hub_to_vpc_2"
  resource_group_name       = var.resource_group_name
  virtual_network_name      = azurerm_virtual_network.gateway_hub.name
  remote_virtual_network_id = azurerm_virtual_network.vpc_2.id
  allow_virtual_network_access = true
  allow_forwarded_traffic = true
  allow_gateway_transit   = true
  depends_on = [azurerm_virtual_network.gateway_hub, azurerm_virtual_network.vpc_1, azurerm_virtual_network.vpc_2, azurerm_virtual_network_gateway.virtual_network_gateway]
}
 

            
AWS Lattice
Terraform configuration for AWS Lattice.
Terraform
Click for Portfolio
                #######################
# 
#       LAMBDA
#
#######################
 
# Create an IAM role for Lambda
resource "aws_iam_role" "lambda_role" {
  name               = "lambda_role"
  assume_role_policy = data.aws_iam_policy_document.lambda.json 
}
 
# Create a data source for the IAM policy document for Lambda
data "aws_iam_policy_document" "lambda" {
  statement {
    actions = ["sts:AssumeRole"]
    principals {
      type        = "Service"
      identifiers = ["lambda.amazonaws.com"]
    }
  }
}
 
data "archive_file" "lambda_hello_world_file" {
  type        = "zip"
  output_path = "/tmp/lambda_hello_world.zip"
  source {
    content  = <<EOF
def lambda_handler(event, context):
    return {
        'statusCode': 200,
        'body': 'Hello, I\'m Lambda!!!'
    }
    EOF
    filename = "main.py"
  }
}
 
resource "aws_lambda_function" "lambda_hello_world_function" {
  function_name    = "lambda_hello_world_function"
  handler          = "main.lambda_handler"
  runtime          = "python3.8"
  role             = aws_iam_role.lambda_role.arn
  filename         = data.archive_file.lambda_hello_world_file.output_path
  source_code_hash = data.archive_file.lambda_hello_world_file.output_base64sha256
}
 
 
#######################
# 
#       EC2
#
#######################
 
 
# Create an EC2 instance with a user script that returns HTML using Alpine
resource "aws_instance" "ec2_hello_world" {
  ami           = "ami-051f7e7f6c2f40dc1" 
  instance_type = "t2.micro"
  subnet_id     = aws_subnet.subnet_ec2.id
  associate_public_ip_address = true
  # Specify the user script in heredoc format
  user_data = <<EOF
#!/bin/bash
sudo dnf update -y
sudo dnf list | grep httpd
sudo dnf install -y httpd.x86_64
sudo systemctl start httpd.service
sudo systemctl status httpd.service
sudo systemctl enable httpd.service
echo “Hello World from $(hostname -f)” > /var/www/html/index.html
EOF
  # Associate the security group with the instance
  vpc_security_group_ids = [aws_security_group.security_group_ec2_lambda.id]
  tags = {
    name = "ec2_hello_world"
  }
}
 
######################
#
#  VPCs
#
#  
#   Default VPC in AWS is the client VPC that will be associated with the service network, via vpc_lattice_service_vpc_association_ec2 resource. 
#   Two services of Lambda & EC2 will be associated with the service network.
#   The service network is not a VPC itself!
 
#
#
 
resource "aws_default_vpc" "default_vpc" {
  tags = {
    Name = "Default VPC"
  }
}
 
resource "aws_vpc" "vpc_ec2" {
  cidr_block = "10.2.0.0/16"
  tags = {
    name = "VPC EC2"
  }
}
 
######################
#
#  SUBNETS
#
#
#   The Lambda Service does not require it's own subnet like EC2 and Load Balancers for the target gruops
#
#
 
resource "aws_subnet" "subnet_ec2" {
  cidr_block = "10.2.0.0/24"
  vpc_id     = aws_vpc.vpc_ec2.id
}
#########################
# 
#    SECURITY GROUPS
#
#########################
 
 
# Create a security group that allows HTTP and HTTPS traffic from anywhere
resource "aws_security_group" "security_group_ec2_lambda" {
  name = "security_group_ec2_lambda"
 
  ingress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
 
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
 
  vpc_id = aws_vpc.vpc_ec2.id
}
 
resource "aws_security_group" "security_group_default_vpc" {
  name = "security_group_service_network"
 
  ingress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
 
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
 
  vpc_id = aws_default_vpc.default_vpc.id
}
 
 
 
 
#########################
# 
#    VPC LATTICE
#
#    Service Network -> Service -> Listener -> Target Group
#
#    Target Group is a VPC with Containers, EC2, Kubernetes, Load Balancers
#    Target Group has no VPC with Lambda
#
#    A Key Purpose of AWS Lattice is to have a consistent DNS name for services of different computing styles
#    And to have control security & monitoring consistently
#    Listeners & Rules can have weighted bias among different rules & paths 
#
#    Problems I came across was Terraform not setting up the Lambda Function in the Lambda Target Group
#    and the initialization script in the USER DATA not working as expected, resulting in endless troubleshooting
#    with the Health Check in the EC2 Target Group, until I directly accessed the instance in the private subnet
#    with a temporary internet gateway/route table entry.
#
#    VPC Lattice adds in the route tables in a route table like 167.*.*.*
#
#########################
 
##### VPC SERVICE NETWORK ##### 
#
#
resource "aws_vpclattice_service_network" "vpc_lattice_service_network_mark" {
  name      = "vpc-lattice-service-network-mark"
  auth_type = "NONE"
}
 
##### VPC LATTICE SERVICES #####
#
# 
resource "aws_vpclattice_service" "vpc_lattice_service_lambda" {
  name               = "vpc-lattice-service-lambda"
  auth_type          = "NONE"
}
 
resource "aws_vpclattice_service" "vpc_lattice_service_ec2" {
  name               = "vpc-lattice-service-ec2"
  auth_type          = "NONE"
}
 
##### VPC LATTICE SERVICE TO SERVICE NETWORK ASSOCIATION #####
#
#   Back End
#
#   Connects services to service network
#
#
resource "aws_vpclattice_service_network_service_association" "vpc_lattice_service_network_association_lambda" {
  service_network_identifier = aws_vpclattice_service_network.vpc_lattice_service_network_mark.id
  service_identifier = aws_vpclattice_service.vpc_lattice_service_lambda.id
}
 
resource "aws_vpclattice_service_network_service_association" "vpc_lattice_service_network_association_ec2" {
  service_network_identifier = aws_vpclattice_service_network.vpc_lattice_service_network_mark.id
  service_identifier = aws_vpclattice_service.vpc_lattice_service_ec2.id
}
 
 
##### VPC LATTICE VPC TO SERVICE NETWORK ASSOCIATION (DEFAULT VPC) #####
#
#   Client Side
#
#   Default VPC was used for my simplicity & sanity
#
#   Connects Client VPC to Service Network
#   Service Network is not a VPC itself, it's an abstraction
#
resource "aws_vpclattice_service_network_vpc_association" "vpc_lattice_service_vpc_association_ec2" {
  vpc_identifier             = aws_default_vpc.default_vpc.id
  service_network_identifier = aws_vpclattice_service_network.vpc_lattice_service_network_mark.id
  security_group_ids         = [aws_default_vpc.default_vpc.default_security_group_id]
}
 
 
##### VPC LATTICE LISTENER ##### 
#
#   Attaches Listener To Service
#
#
resource "aws_vpclattice_listener" "vpc_lattice_listener_lambda" {
  name               = "vpc-lattice-listener-lambda"
  protocol           = "HTTP"
  service_identifier = aws_vpclattice_service.vpc_lattice_service_lambda.id
  default_action {
		forward {
		    target_groups {
		        target_group_identifier = aws_vpclattice_target_group.vpc_lattice_target_group_lambda.id
		        weight                  = 100
		     }
	    }
    }
}
 
resource "aws_vpclattice_listener" "vpc_lattice_listener_ec2" {
  name               = "vpc-lattice-listener-ec2"
  protocol           = "HTTP"
  service_identifier = aws_vpclattice_service.vpc_lattice_service_ec2.id
  default_action {
	 forward {
	    target_groups {
	        target_group_identifier = aws_vpclattice_target_group.vpc_lattice_target_group_ec2.id
	        weight                  = 100
	     }
    }
  }
}
 
 
 
 
##### VPC LATTICE TARGET GROUP & ATTACHMENT (LAMBDA) #####
#
#   The attachment links the Lambda/EC2/EKS to the target group
# 
resource "aws_vpclattice_target_group" "vpc_lattice_target_group_lambda" {
  name = "vpc-lattice-target-group-lambda"
  type = "LAMBDA"
}
 
resource "aws_vpclattice_target_group" "vpc_lattice_target_group_ec2" {
  name = "vpc-lattice-target-group-ec2"
  type = "INSTANCE"
  config {
    port           = 80
    protocol       = "HTTP"
    vpc_identifier = aws_vpc.vpc_ec2.id
  }
}
 
 
##### VPC TARGET GROUPS
#
#     VPC LATTICE TARGET GROUP ATTACHMENT (Lambda) ##### 
#
#     The attachment links the Lambda/EC2/EKS to the target group  
#
resource "aws_vpclattice_target_group_attachment" "vpc_lattice_target_group_attachment_lambda" {
  target_group_identifier = aws_vpclattice_target_group.vpc_lattice_target_group_lambda.id
  target {
    id   = aws_lambda_function.lambda_hello_world_function.arn
  }
}
##### VPC LATTICE TARGET GROUP ATTACHMENT (EC2) #####
#
#   The attachment links the Lambda/EC2/EKS to the target group  
# 
resource "aws_vpclattice_target_group_attachment" "vpc_lattice_target_group_attachment_ec2" {
  target_group_identifier = aws_vpclattice_target_group.vpc_lattice_target_group_ec2.id
  target {
    id   = aws_instance.ec2_hello_world.id
    port = 80
  }
}

            
Terraform AWS CI/CD for ECS/ECR containers
Modifying & committing an HTML file in GitHub will spearhead a process with CodePipeline & CodeBuild to update an ECR container/ECS task with the new HTML
Terraform
Click for Portfolio
                 
resource "aws_default_vpc" "default_vpc" {
  tags = {
    Name = "Default VPC"
  }
}
 
variable "subnet_default_1" {
  description = "Subnet 1 in the default VPC"
  default     = "subnet-0d803ec41d0ce19a5" 
}
 
variable "default_security_group" {
  description = "Security Group Open Default"
  default     = "sg-06cb6cc7195fb5076"
}
 
 
 
 
////////////////////
//
//  S3
//
////////////////////
 
# Create an S3 bucket for the website
resource "aws_s3_bucket" "mark_bucket" {
  bucket = "mmulcahy222-aws-website-cicd" 
}
 
 
 
////////////////////
//
//  IAM
//
////////////////////
resource "aws_iam_role" "mark_cicd_role" {
  name = "mark-cicd-role"
  assume_role_policy = jsonencode({
    Version = "2012-10-17",
    Statement = [{
      Action = "sts:AssumeRole",
      Effect = "Allow",
      Principal = {
        Service = [
           "codebuild.amazonaws.com",
           "codecommit.amazonaws.com",
           "codepipeline.amazonaws.com",
           "codedeploy.amazonaws.com",
           "ecs.amazonaws.com",
           "ecs-tasks.amazonaws.com",
           "ecr.amazonaws.com",
        ]
      }
    }]
  })
}
 
resource "aws_iam_policy" "mark_cicd_policy" {
  name        = "mark-cicd-policy"
  description = "Temporary policy for CI/CD services"
 
  policy = jsonencode({
    Version = "2012-10-17",
    Statement = [
      {
        Action   = [
          "codebuild:*",
          "codedeploy:*",
          "codepipeline:*",
          "codestar-connections:*",
          "codecommit:*",
          "ecs:*",
          "ecr:*",
          //EC2 permissions are needed so CodeBuild can work with EC2
          "ec2:*",
          "s3:*",
          "iam:PassRole",
          "cloudwatch:*",
          "logs:*"
        ],
        Effect   = "Allow",
        Resource = "*",
      },
    ],
  })
}
 
resource "aws_iam_role_policy_attachment" "attach_cicd_policy" {
  policy_arn = aws_iam_policy.mark_cicd_policy.id
  role       = aws_iam_role.mark_cicd_role.id
}
 
 
////////////////////
//
//  ECS
//
////////////////////
 
resource "aws_ecs_cluster" "mark_ecs_cluster" {
  name = "mark-ecs-cluster"
  tags = {
    Name = "mark-ecs-cluster"
    Terraform = "true"
    Environment = "dev"
  }
}
 
resource "aws_ecs_cluster_capacity_providers" "mark_ecs_cluster_capacity_providers" {
  cluster_name = aws_ecs_cluster.mark_ecs_cluster.name
  capacity_providers = ["FARGATE"]
  default_capacity_provider_strategy {
    capacity_provider = "FARGATE"
    weight = 100
  }
}
 
resource "aws_ecs_service" "mark_ecs_service" {
  name            = "mark_ecs_service"
  cluster         = aws_ecs_cluster.mark_ecs_cluster.name
  task_definition = aws_ecs_task_definition.mark_ecs_task_definition.arn
  launch_type     = "FARGATE"
  desired_count   = 1
 
  network_configuration {
    subnets = [var.subnet_default_1]
    security_groups = [var.default_security_group]
    assign_public_ip = true
  }
 
}
 
 
resource "aws_ecs_task_definition" "mark_ecs_task_definition" {
  family                   = "mark_ecs_task_definition"
  network_mode             = "awsvpc"
  requires_compatibilities = ["FARGATE"]
  execution_role_arn       = aws_iam_role.mark_cicd_role.arn
  cpu                      = "256"
  memory                   = "512"
  container_definitions = jsonencode([
    {
      //
      //
      //   NOTE: The container name here must match what's inside of buildspec.yml in the image definition
      //
      //
      name  = "mark_container_nginx"
      image = "${aws_ecr_repository.mark_ecr.repository_url}:mark_nginx"
      portMappings = [
        {
          containerPort = 80
          hostPort      = 80
        }
      ]
    }
  ])
}
 
 
////////////////////
//
//  CODE BUILD (CODEBUILD -> ECR -> CODEDEPLOY -> ECS)
//
//  You will need to put DOCKERFILE & BUILDSPEC.YML in the github repository
//
//  Build has phrases, and build itself is a part of CodePipeline
//
////////////////////
 
 
# Create a CodeBuild source credential resource with the GitHub personal access token
resource "aws_codebuild_source_credential" "github_token" {
  auth_type   = "PERSONAL_ACCESS_TOKEN"
  server_type = "GITHUB"
  token = ""
}
 
# Create a CodeBuild project that uses GitHub as the source and personal access token as the authentication method
resource "aws_codebuild_project" "mark_codebuild" {
  name        = "mark_codebuild"
  description = "mark_codebuild"
  service_role = aws_iam_role.mark_cicd_role.arn 
 
  artifacts {
    type = "NO_ARTIFACTS"
  }
 
  environment {
    compute_type                = "BUILD_GENERAL1_SMALL"
    image                       = "aws/codebuild/amazonlinux2-x86_64-standard:5.0"
    type                        = "LINUX_CONTAINER"
    image_pull_credentials_type = "CODEBUILD"
    privileged_mode             = true
  }
 
  source {
    type            = "GITHUB"
    location        = "https://github.com/mmulcahy222/mark_aws_cicd" 
    git_clone_depth = 1
    buildspec       = "buildspec.yml"
  }
}
 
 
////////////////////
//
//  ECR
//
////////////////////
 
resource "aws_ecr_repository" "mark_ecr" {
  name = "mark_ecr_repository"
  image_tag_mutability = "MUTABLE" 
  image_scanning_configuration {
    scan_on_push = true
  }
}
 
output "ecr_repository_name" {
  description = "Name of the ECR repository"
  value       = aws_ecr_repository.mark_ecr.name
}
 
output "ecr_repository_url" {
  description = "URL of the ECR repository"
  value       = aws_ecr_repository.mark_ecr.repository_url
}
 
/*
data "aws_ecs_task" "mark_ecs_task" {
  task_definition = aws_ecs_task_definition.mark_ecs_task_definition.arn
  cluster         = aws_ecs_cluster.mark_ecs_cluster.id
}
 
output "public_ip" {
  value = data.aws_ecs_task.mark_ecs_task.eni_network_interface_ids[0].public_ipv4_address
}
*/
 
 
////////////////////
//
//  CODEPIPELINE
//
////////////////////
 
resource "aws_codestarconnections_connection" "github_connection" {
  name          = "github-connection"
  provider_type = "GitHub"
}
 
 
resource "aws_codepipeline" "mark_codepipeline" {
  name     = "mark_codepipeline_terraform"
  role_arn = aws_iam_role.mark_cicd_role.arn
  artifact_store {
    location = aws_s3_bucket.mark_bucket.id
    type     = "S3"
  }
 
  stage {
  name = "Source"
  action {
    name     = "SourceAction"
    category = "Source"
    owner    = "AWS"
    provider = "CodeStarSourceConnection"
    version  = "1"
    output_artifacts = ["source_output"] 
    configuration = {
      ConnectionArn   = aws_codestarconnections_connection.github_connection.arn
      FullRepositoryId = "mmulcahy222/mark_aws_cicd"
      BranchName       = "master"
      OutputArtifactFormat = "CODE_ZIP"
      }
    }
  }
 
  stage {
    name = "Build"
    action {
      name     = "BuildAction"
      category = "Build"
      owner    = "AWS"
      provider = "CodeBuild"
      version  = "1"
      input_artifacts = ["source_output"] 
      output_artifacts = ["build_output"] 
 
      configuration = {
        ProjectName = aws_codebuild_project.mark_codebuild.name
      }
    }
  }
 
  stage {
    name = "Deploy"
    action {
      name     = "DeployAction"
      category = "Deploy"
      owner    = "AWS"
      provider = "ECS"
      version  = "1"
      input_artifacts = ["build_output"]
      configuration = {
        ClusterName = aws_ecs_cluster.mark_ecs_cluster.name
        ServiceName = aws_ecs_service.mark_ecs_service.name
        FileName    = "imagedefinitions.json"
      }
    }
  }
}

            
Terraform AWS CI/CD for ECS/ECR containers
Build specification for Terraform AWS CI/CD pipeline.
Terraform
Click for Portfolio
                version: 0.2
phases:
  pre_build:
    commands:
      - echo Logging in to Amazon ECR...
      - export AWS_REGION="us-east-1"
      - export AWS_ACCOUNT_ID=""
      - export IMAGE_REPO_NAME="mark_ecr_repository"
      - export REPOSITORY_URI="${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com/${IMAGE_REPO_NAME}"
      - export COMMIT_HASH="$(echo ${CODEBUILD_RESOLVED_SOURCE_VERSION} | cut -c 1-7)"
      - export IMAGE_TAG="${COMMIT_HASH:-latest}"
  build:
    commands:
      - echo Build started on `date`
      - echo Building the Docker image...
      - docker build -t ${REPOSITORY_URI}:${IMAGE_TAG} .
      - echo Running NGINX in the Docker container...
      - docker run -d -p 8080:80 ${REPOSITORY_URI}:${IMAGE_TAG}
  post_build:
    commands:
      - echo Build completed on `date`
      - echo Pushing the Docker image...
      - aws ecr get-login-password | docker login --username AWS --password-stdin "${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com"
      - docker push ${REPOSITORY_URI}:${IMAGE_TAG}
      - echo Writing image definitions file...
      - printf '[{"name":"mark_container_nginx","imageUri":"%s"}]' ${REPOSITORY_URI}:${IMAGE_TAG} > imagedefinitions.json
artifacts:
  files:
    - imagedefinitions.json

            
Turn any Python Code to Alexa OR Google Home Skill
Decorator to turn Python code into Alexa or Google Home skills.
Python
Click for Portfolio
                import json
import os
import pprint
import sys
import operator
import functools
import time
import datetime
import urllib
import urllib.parse 
import urllib.request
from collections import defaultdict
from urllib.parse import unquote
from urllib.request import Request, urlopen 
import re
import copy
import boto3
import random
import string
from botocore.exceptions import ClientError
 
 
origin_type = ''
 
 
 
def handle_exception(default_value=None):
    def wrap(f):
        def wrapped_f(*args,**kwargs):
            try:
                return f(*args,**kwargs)
            except:
                return default_value
        return wrapped_f
    return wrap
 
 
def get_current_location():
    #only purpose is for portability between windows system & google functions 
    #if in local windows system
    if os.name == 'nt':
        return 'windows'
    #if in amazon
    elif os.environ.get("AWS_EXECUTION_ENV") is not None:
        return 'amazon' 
    #if google cloud or other cloud like azure
    else:
        return 'google'
 
 
 
class AmazonAWS:
    @handle_exception()
    def get_request_json(self,request):
        return request
    @handle_exception()
    def get_intent(self,response_json):
        return response_json['request']['intent']['name']	
    @handle_exception({})
    def get_parameter(self,request_json,key):
        #called slot values here
        return request_json['request']['intent']['slots'][key]['value']
    @handle_exception({})
    def get_parameters(self,request_json):
        #format it for the inner function in a decorator
        #looks like {'any': 'thriller', 'time': '00:00'}
        slots = request_json['request']['intent']['slots']	
        parameters = {k:v.get("value") for k,v in slots.items()}		
        return parameters
    def device_text_response(self, **kwargs):
        speech_output = kwargs.get("speech_output","OK")
        session_attributes = kwargs.get("session_attributes",{})
        should_end_session = kwargs.get("should_end_session",0)
        response = {
            "sessionAttributes": session_attributes,
            "response": {
                "outputSpeech": {
                    "type": "SSML",
                    "ssml":"<speak>" + str(speech_output)[:7999] + "</speak>"
                },
            
                "reprompt": {
                    "outputSpeech": {
                        "type": "SSML",
                        "ssml": "<speak>" + str(speech_output)[:7999] + "</speak>"
                    }
                },
            },
            "shouldEndSession": should_end_session
        }
        return response
    def device_audio_response(self,**kwargs):
        alphanumeric = list(string.octdigits + string.ascii_letters)
        random.shuffle(alphanumeric)
        token = ''.join(alphanumeric[:15])
        response = {
            "response": {
                "outputSpeech": {
                    "type": "SSML",
                    "ssml":"<speak>" + kwargs.get("text_speech","Ok") + "</speak>"
                },
                "directives": [
                    {
                        "type": "AudioPlayer.Play",
                        "playBehavior": "REPLACE_ALL",
                        "audioItem": {
                            "stream": {
                                "token": token,
                                "url": kwargs.get("audio_url",''),
                                "offsetInMilliseconds": 0
                            }
                        }
                    }
                ],
                "shouldEndSession": 1
            }
        }
        return response
    def return_trip_json(self,contents):
        # AMAZON AWS JUST REQUIRES PAYLOAD (you're calling Lambda directly)
        #
        # if isinstance(contents,dict):
        # 	contents = json.dumps(contents)
        # return_dict = {
        # 	"statusCode": 200,
        # 	"headers": {"Content-Type": "application/json"},
        # 	"body": contents
        # }
        return contents
    def response_text_facade(self,contents):
        return self.return_trip_json(self.device_text_response(speech_output=contents))
 
 
 
 
 
 
 
 
 
 
 
 
class GoogleCloud:
    @handle_exception()
    def get_request_json(self,request):
        return json.loads(request['body'])
    @handle_exception()
    def get_intent(self,request_json):
        return request_json['queryResult']['intent']['displayName']
    @handle_exception({})
    def get_parameter(self,request_json,key):
        return request_json['queryResult']['parameters'][key]
    @handle_exception({})
    def get_parameters(self,request_json):
        #format it for the inner function in a decorator
        #looks like {'any': 'thriller', 'time': '00:00'}
        return request_json['queryResult']['parameters']
    def device_text_response(self,**kwargs):
        response_json = {
            "fulfillmentText": str(kwargs.get('speech_output','Ok')),
        }
        return json.dumps(response_json)
    def device_audio_response(self, **kwargs):
        response_json = {
            #"fulfillmentText": str(speech_output),
            "payload": {
                "google": {
                    "richResponse": {
                        "items": [
                            {
                                "simpleResponse": {
                                    "textToSpeech": kwargs.get("text_speech","Ok")
                                }
                            }
                            ,
                            {
                                "mediaResponse": {
                                    "mediaType": "AUDIO",
                                    "mediaObjects": [
                                        {
                                            "contentUrl": kwargs.get("audio_url",''),
                                            "description": "Audio Book",
                                            "name": "Audio Book"
                                        }
                                    ]
                                }
                            }
                        ]
                        ,
                        "suggestions": [
                            {
                                "title": "Suggestion"
                            }
                        ]
                    }
                }
            }
        }
        return json.dumps(response_json)
    def return_trip_json(self,contents):
        # Amazon API Gateway JSON is here (on way back to Dialogflow) because we're using Amazon API Gateway
        # Change Accordingly
        #if isinstance(contents,dict):
        #	contents = json.dumps(contents)
        return_dict = {
            "statusCode": 200,
            "headers": {"Content-Type": "application/json"},
            "body": contents
        }
        return return_dict
    def response_text_facade(self,contents):
        return self.return_trip_json(self.device_text_response(speech_output=contents))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
class HTTPBrowser():
    @handle_exception()
    def __getattr__(self, name):
        def wrapper(*args, **kwargs):
            return None
        return wrapper
    @handle_exception()
    def get_http_header_host(self,event):
        return event['headers']['Host']
    def return_trip_json(self,contents):
        if isinstance(contents,dict):
            contents = json.dumps(contents)
        return_dict = {
            "statusCode": 200,
            "headers": {"Content-Type": "application/json"},
            "body": contents
        }
        return return_dict
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
def smart_speaker_decorator(type_of_output="text"):
    '''
    This is a Decorator to turn any regular code into an Alexa Skill or Google Home Skill using Amazon AWS for now
    '''
    def first_function(f):
        def second_function(*args,**kwargs):
            try:
                #get_item
                def get_item(iterable, index, default=None):
                    try:
                        return operator.getitem(iterable, index)
                    except:
                        return default
                #initial variables (lambda or google event,context)
                amazon_aws = AmazonAWS()
                google_cloud = GoogleCloud()
                http_browser = HTTPBrowser()
                event = get_item(args,0)
                context = get_item(args,1)
                global origin_type
                #########################
                #    DETERMINES THE ORIGIN
                #########################
                #	CHECKS TO SEE IF THERE'S A SESSION->APPLICATION->APPLICATIONID, characteristic of Amazon Event Objects.
                #It looks at the decorated get_request_json objects and sees if it put in an exception
                amazon_aws_alexa_request_json = amazon_aws.get_request_json(event)
                google_cloud_alexa_request_json = google_cloud.get_request_json(event)
                if google_cloud_alexa_request_json != None:
                    origin_type = 'google_cloud'
                    origin = google_cloud
                elif 'amazonaws' in str(http_browser.get_http_header_host(event)):
                    origin_type = 'http_browser'
                    origin = http_browser
                elif amazon_aws_alexa_request_json != None:
                    origin_type = 'amazon_aws'
                    origin = amazon_aws
                else:
                    origin_type = 'http_browser'
                    origin = http_browser
                #	Key Error is wrong attribute, Type Error is for doing getattr [] on a string
                #	Origin is for Google Cloud because most of the time we want Google Devices
 
                #########################
                #    END DETERMINE ORIGIN
                #########################
                #	Lambda Functions will read this. Not Google Cloud Functions yet. Google Cloud Functions deploy too slowly
                destination = amazon_aws
                #	Handle the event object that passes by differently
                request_json = origin.get_request_json(event)
                #	Get Intent
                intent = origin.get_intent(request_json)
                #	Amazon Slot values & parameters from Google Home
                parameters = origin.get_parameters(request_json)
                #	send intent to the function that called the decorator
                if isinstance(parameters,dict):
                    parameters.update({"intent":intent})
                else:
                    parameters = {}
                #	RUN ACTUAL CODE
                result = f(event,context,*args, **parameters)
                #	END DEBUG
                #	END RUN ACTUAL CODE
                #	
                #	
                #	IF THIS IS A WEB REQUEST IN THE AMAZON API GATEWAY!!! (LAMBDA URL)
                #	
                if 'http_browser' == origin_type:
                    return {"statusCode": 200, "headers": {"Content-Type": "application/json"}, "body": pprint.pformat(locals()) }
                #
                #	Make Destination account for Google Cloud Functions if for some reason the processign is done there
                #
                #	If it's audio, send it in either Google or Amazon format
                #	IF DOING AUDIO, SEND IT A DICT WITH AUDIO_URL & TEXT_SPEECH!!
                #	Destination means in this case, format JSON in Amazon AWS format
                #
                
                if 'audio' == type_of_output:
                    #usually for debugging, it will normally not be send that way
                    if isinstance(result,dict) == False:
                        result = {}
                    return origin.return_trip_json(origin.device_audio_response(**result))
                #
                #	TEXT is the fallback for either Amazon or Google
                #
                elif 'text' == type_of_output:
                    return origin.return_trip_json(origin.device_text_response(speech_output=result))
                #
                #	YOU should NEVER reach here. Fallback
                #
                return {"statusCode": 200, "headers": {"Content-Type": "application/json"}, "body": pprint.pformat(locals()) }
            except:
                exc_type, exc_obj, exc_tb = sys.exc_info()
                exception_text = str(exc_type) + ' ' + str(exc_obj) + ' ' + str(exc_tb.tb_lineno)
                #
                # DEBUG
                # 
                import traceback
                traceback.print_exc()
                # 
                # AMAZON AWS ONLY
                # 
                #return {'statusCode': 200, 'headers': {'Content-Type': 'application/json'}, 'body': exception_text + repr(locals())}
                #
                # IF EXTENDING THIS FOR GOOGLE CLOUD FUNCTIONS TO SEE THIS, ACTIVATE THE FOLLOWING
                #
                return origin.return_trip_json(origin.device_text_response(speech_output="Nothing was found. Say something else or be more specific. " + exception_text))
                #return origin.return_trip_json(origin.device_text_response(speech_output=exception_text + pprint.pformat(locals())))
        return second_function
    return first_function
 
 
 
 
 
 
 
 
 
 
 
def get_audio_url_from_web_url(url):
    global origin_type
    response = urllib.request.urlopen(url)
    if not response:
        raise Exception("Unable to open url: {0}".format(self.url))
    html = response.read()
    if isinstance(html, str):
        json_start_pattern = "ytplayer.config = "
    else:
        json_start_pattern = bytes("ytplayer.config = ", "utf-8")
    pattern_idx = html.find(json_start_pattern)
    # In case video is unable to play
    if(pattern_idx == -1):
        raise Exception("Unable to find start pattern.")
    start = pattern_idx + 18
    html = html[start:]
    def get_json_offset(html):
        '''called from get_audio_from_web_url. Gets YT Config inside of page, and returns the number offset to slice'''
        unmatched_brackets_num = 0
        index = 1
        for i, ch in enumerate(html):
            if isinstance(ch, int):
                ch = chr(ch)
            if ch == "{":
                unmatched_brackets_num += 1
            elif ch == "}":
                unmatched_brackets_num -= 1
                if unmatched_brackets_num == 0:
                    break
        else:
            raise Exception("Unable to determine json offset.")
        return index + i
    #get json offset is to get the starting and last curly braces of beginnign and closing end of config
    #json offset is a number value for later slicing, where it will turn into JSON by json.loads
    offset = get_json_offset(html)
    if not offset:
        raise Exception("Unable to extract json.")
    if isinstance(html, str):
        json_content = json.loads(html[:offset])
    else:
        json_content = json.loads(html[:offset].decode("utf-8"))
    player_response_string = json_content.get("args", {}).get("player_response")
    player_response_json = json.loads(player_response_string)
    video_audio_nodes = player_response_json.get('streamingData',{}).get('adaptiveFormats',{})
    #Run through the nodes containing bitrates & video urls & formats
    audio_nodes = []
    for video_audio_node in video_audio_nodes:
        #only get those with audio
        if 'audio' in video_audio_node.get("mimeType"):
            audio_url = video_audio_node.get('url',{})
            quality = video_audio_node.get('quality',{})
            content_length = video_audio_node.get('contentLength',{})
            mime_type = video_audio_node.get("mimeType")
            #append tuple
            audio_nodes.append((content_length,audio_url,mime_type,quality))
    #in a list of tuples, the first value in the tuple would be sorted in the list
    #size of file (lowest) will be first up to the largest files
    audio_nodes.sort()
    #the first [-1] means largest sized
    #the second [1] is the audio_url as specified in the append function above by virtue of it's placement
    audio_quality = 2
    if origin_type == 'google_cloud':
        audio_quality = -1
    #else if amazon or anything else, make it 2
    return audio_nodes[audio_quality][1]
 
 
 
 
 
 
 
 
 
 
 
# def get_audio_url_from_web_url_april_2019(url):
#     global origin_type
#     req = Request(url)
#     req.add_header('Connection', 'keep-alive')
#     req.add_header('User-Agent',  'Mozilla/5.0 (X11; Linux i686; G518Rco3Yp0uLV40Lcc9hAzC1BOROTJADjicLjOmlr4=) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36')
#     req.add_header('Accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8')
#     req.add_header('Accept-Charset', 'ISO-8859-1,utf-8;q=0.7,*;q=0.3')
#     req.add_header('Accept-Language', 'en-US,en;q=0.8')
#     html = urlopen(req).read()
#     if not html:
#         raise Exception("Unable to open url: {0}".format(self.url))
#     if isinstance(html, str):
#         json_start_pattern = "ytplayer.config = "
#     else:
#         json_start_pattern = bytes("ytplayer.config = ", "utf-8")
#     pattern_idx = html.find(json_start_pattern)
#     # In case video is unable to play
#     if(pattern_idx == -1):
#         raise Exception("Unable to find start pattern.")
#     start = pattern_idx + 18
#     html = html[start:]
#     def get_json_offset(html):
#         '''called from get_audio_from_web_url. Gets YT Config inside of page, and returns the number offset to slice'''
#         unmatched_brackets_num = 0
#         index = 1
#         for i, ch in enumerate(html):
#             if isinstance(ch, int):
#                 ch = chr(ch)
#             if ch == "{":
#                 unmatched_brackets_num += 1
#             elif ch == "}":
#                 unmatched_brackets_num -= 1
#                 if unmatched_brackets_num == 0:
#                     break
#         else:
#             raise Exception("Unable to determine json offset.")
#         return index + i
#     #get json offset is to get the starting and last curly braces of beginnign and closing end of config
#     #json offset is a number value for later slicing, where it will turn into JSON by json.loads
#     offset = get_json_offset(html)
#     if not offset:
#         raise Exception("Unable to extract json.")
#     if isinstance(html, str):
#         json_content = json.loads(html[:offset])
#     else:
#         json_content = json.loads(html[:offset].decode("utf-8"))
#     player_response_string = json_content.get("args", {}).get("player_response")
#     player_response_json = json.loads(player_response_string)
#     video_audio_nodes = player_response_json.get('streamingData',{}).get('adaptiveFormats',{})
#     #Run through the nodes containing bitrates & video urls & formats
#     def parse_stream_map(blob):
#         dct = defaultdict(list)
#         # Split the comma separated videos.
#         videos = blob.split(",")
#         # Unquote the characters and split to parameters.
#         videos = [video.split("&") for video in videos]
#         # Split at the equals sign so we can break this key value pairs and
#         # toss it into a dictionary.
#         for video in videos:
#             for kv in video:
#                 key, value = kv.split("=")
#                 dct[key].append(unquote(value))
#         return dct
#     encoded_stream_map = json_content.get("args", {}).get("adaptive_fmts")
#     adaptive_urls = parse_stream_map(encoded_stream_map)['url']
#     audio_url = adaptive_urls[-1]
#     return audio_url
 
 
 
 
 
 
 
 
 
 
 
 
def get_audio_url_from_web_url_may_2021(url):
    global origin_type
    req = Request(url)
    req.add_header('Connection', 'keep-alive')
    req.add_header('User-Agent',  'Mozilla/5.0 (X11; Linux i686; G518Rco3Yp0uLV40Lcc9hAzC1BOROTJADjicLjOmlr4=) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36')
    req.add_header('Accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8')
    req.add_header('Accept-Charset', 'ISO-8859-1,utf-8;q=0.7,*;q=0.3')
    req.add_header('Accept-Language', 'en-US,en;q=0.8')
    html = urlopen(req).read()
    if not html:
        raise Exception("Unable to open url: {0}".format(self.url))
    if isinstance(html, str):
        json_start_pattern = "ytplayer.config = "
    else:
        json_start_pattern = bytes("ytplayer.config = ", "utf-8")
    pattern_idx = html.find(json_start_pattern)
    # In case video is unable to play
    if(pattern_idx == -1):
        raise Exception("Unable to find start pattern.")
    start = pattern_idx + 18
    html = html[start:]
    def get_json_offset(html):
        '''called from get_audio_from_web_url. Gets YT Config inside of page, and returns the number offset to slice'''
        unmatched_brackets_num = 0
        index = 1
        for i, ch in enumerate(html):
            if isinstance(ch, int):
                ch = chr(ch)
            if ch == "{":
                unmatched_brackets_num += 1
            elif ch == "}":
                unmatched_brackets_num -= 1
                if unmatched_brackets_num == 0:
                    break
        else:
            raise Exception("Unable to determine json offset.")
        return index + i
    #get json offset is to get the starting and last curly braces of beginnign and closing end of config
    #json offset is a number value for later slicing, where it will turn into JSON by json.loads
    offset = get_json_offset(html)
    if not offset:
        raise Exception("Unable to extract json.")
    if isinstance(html, str):
        json_content = json.loads(html[:offset])
    else:
        json_content = json.loads(html[:offset].decode("utf-8"))
    player_response_string = json_content.get("args", {}).get("player_response")
    player_response_json = json.loads(player_response_string)
    video_audio_nodes = player_response_json.get('streamingData',{}).get('adaptiveFormats',{})
    #Run through the nodes containing bitrates & video urls & formats
    def parse_stream_map(blob):
        dct = defaultdict(list)
        # Split the comma separated videos.
        videos = blob.split(",")
        # Unquote the characters and split to parameters.
        videos = [video.split("&") for video in videos]
        # Split at the equals sign so we can break this key value pairs and
        # toss it into a dictionary.
        for video in videos:
            for kv in video:
                key, value = kv.split("=")
                dct[key].append(unquote(value))
        return dct
    encoded_stream_map = json_content.get("args", {}).get("adaptive_fmts")
    adaptive_urls = parse_stream_map(encoded_stream_map)['url']
    audio_url = adaptive_urls[-1]
    return audio_url
 
 
 
 
 
 
 
 
 
 
 
 
@smart_speaker_decorator('audio')
def lambda_handler(event,context,*args,**kwargs):
    #return "GOON"
    # return {"audio_url":"DEBUG","text_speech":"DEBUG"}
    intent = kwargs.get("intent","Unknown")
    choice = kwargs.get("choice","Unknown")
    original_choice = choice
    developer_key = 'AIzaSyBzh1miCVEe0jOOWrmLEjc-An8NWIb7IDc';
    #choice (for YouTube music)
    choice = choice.lower()
    choice = choice.replace('music','topic')
    list_video_url = 'https://www.googleapis.com/youtube/v3/search?q='+urllib.parse.quote(str(choice))+'&part=id,snippet&maxResults=20&type=video&key=' + developer_key
        #parameters intent because I dont' want to write new intents beyond the simple fallback
    if intent == 'youtube.parameters':
        time_choice = get_parameter(request_json,'time_range')
        time_days = {"today":1,"day":1,"week":7,"month":30,"year":365}.get(time_choice,365)
        date_begin_string = time.strftime('%Y-%m-%dT%H:%M:%SZ',time.gmtime(time.time() - (60 * 60 * int(time_days))))
        #duration is only in youtube.parameters for now
        if get_parameter(request_json,'duration') == 'long':
            list_video_url = list_video_url + '&videoDuration=long'
        list_video_url = list_video_url + "&publishedAfter=" + date_begin_string
    #read url
    results = json.loads(urllib.request.urlopen(list_video_url).read())
    title_id_nodes = []
    for list_node in results['items']:
        video_id = list_node['id']['videoId']
        title = list_node['snippet']['title']
        title_id_nodes.append((video_id,title))
    #FIRST [0] IS THE FIRST RESULT THAT CAME UP (change if expanding for future results)
    #SECOND [0] IS THE VIDEO ID IN ACCORDANCE TO THE TUPLE ABOVE
    video_id = title_id_nodes[0][0]
    #FINISHED DOING ALL THE WORK TO GET VIDEO ID
    #
    #ALL OF THE FOLLOWING JUST TO GET THE DURATION
    get_first_duration_match = lambda list,index: list[index] if index < len(list) else 0
    try:
        video_info_url = 'https://www.googleapis.com/youtube/v3/videos?id=' + video_id + '&part=contentDetails&type=video&key=' + developer_key 
        results = json.loads(urllib.request.urlopen(video_info_url).read())
        duration_result = results['items'][0]['contentDetails']['duration']
        hours = get_first_duration_match(re.findall('(\d*)H',duration_result),0)
        minutes = get_first_duration_match(re.findall('(\d*)M',duration_result),0)
        seconds = get_first_duration_match(re.findall('(\d*)S',duration_result),0)
    except:
        duration = "Unknown"
    duration = ''
    if int(hours) == 1:
        duration += "{} hour ".format(hours)
    elif int(hours) > 1:
        duration += "{} hours ".format(hours)
    if int(minutes) == 1:
        duration += "{} minute ".format(minutes)
    elif int(minutes) > 1:
        duration += "{} minutes ".format(minutes)
    if duration == '':
        duration = "Unknown Time"
    duration = duration.strip()
    #END DURATION
    video_url = 'https://www.youtube.com/watch?v=' + video_id
    audio_url = get_audio_url_from_web_url_may_2021(video_url)
    #START DYNAMODB
    current_location = get_current_location()
    if current_location == 'windows' and True:
        try:
            dynamodb = boto3.resource('dynamodb','us-east-1')
            table = dynamodb.Table('audio_api_queries')
            results = table.put_item(
                Item={
                    'time':int(datetime.datetime.now().timestamp()),
                    'ip_address': '44.55.66.77',
                    'query': choice
                }
            )
        except ClientError:
            pass
    #END DYNAMODB
    return {"audio_url":audio_url,"text_speech":original_choice + ' ' + duration}
 
 
 
 
 
 
 
 
 
 
    
if __name__ == '__main__':
    google_request = {"body":json.dumps({"responseId": "984cfbb7-35b2-4e64-bfe1-981dd6c01fce", "queryResult": {"queryText": "hybrid 2 aew theme", "parameters": {"number": 44, "choice": "awesome kong 8 million aew theme"}, "allRequiredParamsPresent": None, "fulfillmentMessages": [{"text": {"text": [""] } } ], "intent": {"name": "projects/read-agent/agent/intents/1f250750-1ebd-4f91-ad8d-c31461289c82", "displayName": "add_two"}, "intentDetectionConfidence": 1, "languageCode": "en"}, "originalDetectIntentRequest": {"payload": {} }, "session": "projects/read-agent/agent/sessions/a5e1dd4a-39aa-57fe-78c6-46dc1e7a8799"})}
    amazon_request = {'version': '1.0', 'session': {'new': None, 'sessionId': 'amzn1.echo-api.session.0b502c38-74cb-4d86-aed0-668297fa7851', 'application': {'applicationId': 'amzn1.ask.skill.6bcca7d1-6fc6-406d-af8a-042948edde49'}, 'user': {'userId': 'amzn1.ask.account.AGONDUNEBOGQACH2DYQOEAHKHAIYYQZKKMBQNLEGHN6ERTMYBOQLZZXVAV54GCGDTM6GU4AEVT6SH6JIBLBLQXHYWMKSZJCA4TZMHVZ2FV36NZBHOWB5EMO3R5UETE5PVDOCYPE7AF4KQ54IGKNJDOJ7ONPHXGK2facebookMTELZMUDYE4YOJQVIWMHJULABS6CIVVJTBCTUE2ZKPTLKJY'}}, 'context': {'AudioPlayer': {'playerActivity': 'IDLE'}, 'System': {'application': {'applicationId': 'amzn1.ask.skill.6bcca7d1-6fc6-406d-af8a-042948edde49'}, 'user': {'userId': 'amzn1.ask.account.AGONDUNEBOGQACH2DYQOEAHKHAIYYQZKKMBQNLEGHN6ERTMYBOQLZZXVAV54GCGDTM6GU4AEVT6SH6JIBLBLQXHYWMKSZJCA4TZMHVZ2FV36NZBHOWB5EMO3R5UETE5PVDOCYPE7AF4KQ54IGKNJDOJ7ONPHXGK2MTELZMUDYE4YOJQVIWMHJULABS6CIVVJTBCTUE2ZKPTLKJY'}, 'device': {'deviceId': 'amzn1.ask.device.AH3UWTZBQPA4AUHMYSTKPZWUWUHU6GS7HPCK42P64W6ENUBBWJRRFY4E4WP2IN2DPJE4WPBQMNBFO2K2W6GTQPVI4QOOIWMG2I7P62YJVOIEJL5FX6KOSJ2R7L2P25XGBGMWZ2FPX54WUL3GDXE3IUUDYG72AK4LLVZH2O5LDCX2EGKFB3RAS', 'supportedInterfaces': {'AudioPlayer': {}}}, 'apiEndpoint': 'https://api.amazonalexa.com', 'apiAccessToken': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IjEifQ.eyJhdWQiOiJodHRwczovL2FwaS5hbWF6b25hbGV4YS5jb20iLCJpc3MiOiJBbGV4YVNraWxsS2l0Iiwic3ViIjoiYW16bjEuYXNrLnNraWxsLjZiY2NhN2QxLTZmYzYtNDA2ZC1hZjhhLTA0Mjk0OGVkZGU0OSIsImV4cCI6MTU0NTg5MzM4OCwiaWF0IjoxNTQ1ODg5Nzg4LCJuYmYiOjE1NDU4ODk3ODgsInByaXZhdGVDbGFpbXMiOnsiY29uc2VudFRva2VuIjpudWxsLCJkZXZpY2VJZCI6ImFtem4xLmFzay5kZXZpY2UuQUgzVVdUWkJRUEE0QVVITVlTVEtQWldVV1VIVTZHUzdIUENLNDJQNjRXNkVOVUJCV0pSUkZZNEU0V1AySU4yRFBKRTRXUEJRTU5CRk8ySzJXNkdUUVBWSTRRT09JV01HMkk3UDYyWUpWT0lFSkw1Rlg2S09TSjJSN0wyUDI1WEdCR01XWjJGUFg1NFdVTDNHRFhFM0lVVURZRzcyQUs0TExWWkgyTzVMRENYMkVHS0ZCM1JBUyIsInVzZXJJZCI6ImFtem4xLmFzay5hY2NvdW50LkFHT05EVU5FQk9HUUFDSDJEWVFPRUFIS0hBSVlZUVpLS01CUU5MRUdITjZFUlRNWUJPUUxaWlhWQVY1NEdDR0RUTTZHVTRBRVZUNlNINkpJQkxCTFFYSFlXTUtTWkpDQTRUWk1IVloyRlYzNk5aQkhPV0I1RU1PM1I1VUVURTVQVkRPQ1lQRTdBRjRLUTU0SUdLTkpET0o3T05QSFhHSzJNVEVMWk1VRFlFNFlPSlFWSVdNSEpVTEFCUzZDSVZWSlRCQ1RVRTJaS1BUTEtKWSJ9fQ.PY4fLtwlu7c21PaMgxo8yWlsgsNLtMEnEGpNbKMUKxxTCRAwxUvJi83dtXXek6tN85njP0IYA_MiUTpsxcKuatO_pzW1fUHCNt51Uomn5UIlVUDQ1swCZppEq5c2zL05faBDJcOVr2OZFd3-QHG-m-7q2N8gIByTjgaRomy7duFhyWF0EApDT010Hj1xipePPNwZyfErQFVvyHzw508NtNDHttfOGI0taH-FTFfRPeIytzoRD0ZV_JRiYI61yyX00LTLdMzUc9EAGjXEIxDumcdpkEoLBSQVtuY5kvXPcubuu9X5I58m7tNFmJvNhTUKaP7DZFAlh_9WVzwvFwp-lg'}, 'Viewport': {'experiences': [{'arcMinuteWidth': 246, 'arcMinuteHeight': 144, 'canRotate': False, 'canResize': False}], 'shape': 'RECTANGLE', 'pixelWidth': 1024, 'pixelHeight': 600, 'dpi': 160, 'currentPixelWidth': 1024, 'currentPixelHeight': 600, 'touch': ['SINGLE']}}, 'request': {'type': 'IntentRequest', 'requestId': 'amzn1.echo-api.request.3b6a1e41-adf0-437e-8416-5779dc4b7131', 'timestamp': '2018-12-27T05:49:48Z', 'locale': 'en-US', 'intent': {'name': 'hear_audio', 'confirmationStatus': 'NONE', 'slots': {'choice': {'name': 'any', 'value': 'michael jackson thriller topic', 'confirmationStatus': 'NONE', 'source': 'USER'}}}}}
    http_request = {'headers':{'Host':'jo2yo0xn52.execute-api.us-east-1.amazonaws.com'}}
 
    print(lambda_handler(google_request,{}))
            
Extract audio URL from YouTube
Extracts audio URLs from YouTube for Alexa skills.
Python
Click for Portfolio
                import json
import urllib.request
import re
from pprint import pprint
from collections import defaultdict
from urllib.parse import unquote
import urllib
 
def lambda_handler(request):
    # if (event["session"]["application"]["applicationId"] != "amzn1.ask.skill.17266258-eecf-42a5-a328-b235199a76ef"):
    #     raise ValueError("Invalid Application ID")
    yt_url = 'https://www.youtube.com/watch?v=g4NhYg_oOk0'
    url = get_audio_url_from_web_url(yt_url)
def get_json_offset(html):
    unmatched_brackets_num = 0
    index = 1
    for i, ch in enumerate(html):
        if isinstance(ch, int):
            ch = chr(ch)
        if ch == "{":
            unmatched_brackets_num += 1
        elif ch == "}":
            unmatched_brackets_num -= 1
            if unmatched_brackets_num == 0:
                break
    else:
        raise Exception("Unable to determine json offset.")
    return index + i
def get_audio_url_from_web_url(url):
    response = urllib.request.urlopen(url)
    if not response:
        raise Exception("Unable to open url: {0}".format(self.url))
    html = response.read()
    if isinstance(html, str):
        restriction_pattern = "og:restrictions:age"
    else:
        restriction_pattern = bytes("og:restrictions:age", "utf-8")
    if restriction_pattern in html:
        raise AgeRestricted("Age restricted video. Unable to download "
            "without being signed in.")
    if isinstance(html, str):
        json_start_pattern = "ytplayer.config = "
    else:
        json_start_pattern = bytes("ytplayer.config = ", "utf-8")
    pattern_idx = html.find(json_start_pattern)
    # In case video is unable to play
    if(pattern_idx == -1):
        raise Exception("Unable to find start pattern.")
    start = pattern_idx + 18
    html = html[start:]
    #get json offset is to get the starting and last curly braces of beginnign and closing end of config
    #json offset is a number value for later slicing, where it will turn into JSON by json.loads
    offset = get_json_offset(html)
    if not offset:
        raise Exception("Unable to extract json.")
    if isinstance(html, str):
        json_content = json.loads(html[:offset])
    else:
        json_content = json.loads(html[:offset].decode("utf-8"))
    player_response_string = json_content.get("args", {}).get("player_response")
    player_response_json = json.loads(player_response_string)
    video_audio_nodes = player_response_json.get('streamingData',{}).get('adaptiveFormats',{})
    #Run through the nodes containing bitrates & video urls & formats
    audio_nodes = []
    for video_audio_node in video_audio_nodes:
        #only get those with audio
        if 'audio' in video_audio_node.get("mimeType"):
            audio_url = video_audio_node.get('url',{})
            quality = video_audio_node.get('quality',{})
            content_length = video_audio_node.get('contentLength',{})
            mime_type = video_audio_node.get("mimeType")
            #append tuple
            audio_nodes.append((content_length,audio_url,mime_type,quality))
    #in a list of tuples, the first value in the tuple would be sorted in the list
    #size of file (lowest) will be first up to the largest files
    audio_nodes.sort()
    #the first [1] means second most smallest
    #the second [1] is the audio_url as specified in the append function above by virtue of it's placement
    return audio_nodes[1][1]
def build_response(audio_file, should_end_session):  
    return {
        "response": {
            "directives": [
                {
                    "type": "AudioPlayer.Play",
                    "playBehavior": "REPLACE_ALL",
                    "audioItem": {
                        "stream": {
                            "token": "12345",
                            "url": audio_file,
                            "offsetInMilliseconds": 0
                        }
                    }
                }
            ],
            "shouldEndSession": True
        }
    }
 
 
def get_url_by_choice(choice):
    #search query list
    url = 'https://www.googleapis.com/youtube/v3/search?q='+choice+'&part=id,snippet&type=video&key=AIzaSyAdRNXjk5yVbUzalf-vh0qrF5VJHvwyFP4';
    results = json.loads(urllib.request.urlopen(url).read())
    for list_node in results['items']:
        video_id = list_node['id']['videoId']
        title = list_node['snippet']['title']
        print(title,video_id)
 
 
if __name__ == '__main__':
    choice = "history"
 
    # yt_url = 'https://www.youtube.com/watch?v=aRAQ-bNs32s'
    # audio_url = get_audio_url_from_web_url(yt_url)
    # 
    get_url_by_choice(choice);
            
Nimli
Imports 40000 items to the Nimli Magento Store from the boss's CSV, including configurable products.
PHP
Click for Portfolio
                <?php
 
set_include_path(get_include_path() . PATH_SEPARATOR . 'C:/makeshift/files/saffron');
 
 
require_once ("/app/Mage.php"); //to do Magento Library functions
Mage::app('admin');
 
$prodauct = Mage::getModel('catalog/product')->load(9);
//$helper_data = Mage::helper('custom/data');
$collection = Mage::getModel('catalog/product')->getCollection()->
    addAttributeToSelect('*')->addAttributeToFilter('brand', 'Trimark');
$category_model = Mage::getModel('catalog/category');
//foreach($collection as $h){echo $h->getName();}
 
 
////////////////////////////////////////
///FUNCTION FOR SETTING OPTIONS FOR A PRODUCT (LIKE ECO ATTRIBUTE OR COLOR)
////////////////////////////////////////
$options_array = array();
 
function get_magento_option_ids($attribute_name, $option_names)
{
    $options_array = &$GLOBALS["options_array"]; //this array grows over time
    $attribute_name = strtolower($attribute_name);
    if (!isset($options_array[$attribute_name]))
        //fill up array with new attribute & options (done to not redeclare model class every single row, which is memory intensive)
 
    {
        if ($attribute_name == '')
        {
            $attribute_name = 'attribute';
        } //only done for that one category with no attribute name but had values
        $attribute = Mage::getModel('catalog/resource_eav_attribute')->loadByCode('catalog_product',
            strtolower($attribute_name));
        $options = $attribute->getSource()->getAllOptions(true);
        foreach ($options as $array)
        {
            $options_array[$attribute_name][strtolower(trim($array[label]))] = $array[value];
        }
    }
    ///GET VALUES FROM ARRAY ABOVE
    foreach ($option_names as $option_name)
    {
        $values[] = $options_array[$attribute_name][strtolower(fix_name($attribute_name, $option_name))];
    }
    $string = implode(',', array_values($values));
    return $string;
}
 
function fix_name($attribute_name, $option_name)
{
    if ($attribute_name == 'eco_attribute')
    {
        if (substr_count($option_name, 'nottested') > 0)
        {
            return 'Not Tested On Animals';
        }
        if (substr_count($option_name, 'usa') > 0)
        {
            return 'Made In Usa';
        }
        if (substr_count($option_name, 'organic') > 0)
        {
            return 'Organic';
        }
        if (substr_count($option_name, 'sustainable') > 0)
        {
            return 'Sustainable';
        }
        if (substr_count($option_name, 'fairly') > 0)
        {
            return 'Fairly Traded';
        }
        if (substr_count($option_name, 'natural') > 0)
        {
            return 'Natural';
        }
        if (substr_count($option_name, 'handmade') > 0)
        {
            return 'Handmade';
        }
    }
    if (substr_count($option_name, 'Caf�') > 0)
    {
        return "Caf";
    }
    $option_name = str_replace("�", "e", $option_name);
    return $option_name;
}
//////////////////////////////////
 
 
 
/////////////////////
///CONNECT TO DATABASE AND MAKE QUERY
//////////////////////
$c = mysql_connect('localhost', 'root', '*');
mysql_select_db('puck', $c);
$sql = "SELECT * FROM item";
$result = mysql_query($sql);
 
 
//////////////////////////
//GET PRICES
//////////////////////////
echo "Making Array For Prices....\n";
$price_result = mysql_query("SELECT itemcode, price FROM keycodeitemprice k");
$price_array = array();
while ($price_row = mysql_fetch_row($price_result))
{
    $price_array[$price_row[0]] = $price_row[1];
}
 
////////////////////////////
//GET CATEGORIES
////////////////////////////
echo "Making Array For Categories....\n";
$category_collection = Mage::getModel('catalog/category')->getCollection()->
    addAttributeToSelect('omx_category_id');
$category_omx_id_array = array();
foreach ($category_collection as $category)
{
    $category_omx_id_array[strval($category->getomx_category_id())] = $category->
        getId();
}
$category_result = mysql_query("SELECT itemcode, catid FROM itemcategory");
$category_array = array();
while ($category_row = mysql_fetch_row($category_result))
{
    $magento_category_id = $category_omx_id_array[$category_row[1]];
    if ($magento_category_id != null)
    {
        $category_array[$category_row[0]] .= $category_omx_id_array[$category_row[1]] .
            ',';
    }
}
 
////////////////////////////////////
//GET CONFIGURABLE ATTRIBUTES
////////////////////////////////////
echo "Making Array For Attributes.....\n";
$product_entity_id = Mage::getModel('eav/config')->getEntityType('catalog_product')->
    getEntityTypeId();
$attributes_with_options = Mage::getResourceModel('eav/entity_attribute_collection')->
    setEntityTypeFilter($product_entity_id);
$attribute_array = array();
foreach ($attributes_with_options as $attribute_with_options)
{
    $attribute_array[$attribute_with_options->getName()] = $attribute_with_options->
        getId();
}
 
 
/////////////////////////////////////////////
//ATTRIBUTE SET ID's
////////////////////////////////////////
$attribute_set_collection = Mage::getResourceModel('eav/entity_attribute_set_collection');
foreach ($attribute_set_collection as $attribute_set)
{
    $attribute_set_array[$attribute_set->getAttributeSetName()] = $attribute_set->
        getId();
}
var_export($attribute_set_array);
 
 
////////////////////////////////////
//GET ATTRIBUTES FROM ITEM ATTRIBUTES BACKUP TABLE (brand, search, materialandfabric, etc)
////////////////////////////////////
echo "Making Array from Item Attribute backup table...\n";
$item_attribute_sql =
    "SELECT ItemCode, AttributeValue8 as Brand, AttributeValue7 as SearchTerm, AttributeValue16 as FulfillmentLatency,
AttributeValue18 as SmallImageUrl, AttributeValue19 as MainImageUrl, AttributeValue20 as Alternate1ImageUrl,
AttributeValue21 as Alternate2ImageUrl, AttributeValue22 as Alternate3ImageUrl, AttributeValue23 as Alternate4ImageUrl,
AttributeValue24 as Alternate5ImageUrl, AttributeValue25 as Alternate6ImageUrl,
AttributeValue42 as MaterialAndFabric, AttributeValue48 as SwatchImageUrl
FROM itemattribute";
$item_attribute_result = mysql_query($item_attribute_sql);
$item_attribute_array = array();
while ($item_attribute_row = mysql_fetch_assoc($item_attribute_result))
{
    $item_attribute_array[$item_attribute_row['ItemCode']] = $item_attribute_row;
}
 
 
 
////////////
///SKIPPING OVER ITEMS THAT ARE ALREADY IN THE SCARVES STORE
////////////
$existing_item_codes = Mage::getModel('catalog/product')->getCollection()->
    getColumnValues('sku');
 
 
$app = Mage::app(); 
 
while ($row = mysql_fetch_assoc($result))
{
	//if product already exists in magento store, skip and move on to next product
	if(in_array($row['ItemCode'], $existing_item_codes))
	{
		continue;
	}
	
	//timer
	$start = time();
	
	//variables
	$item_code = $row['ItemCode'];
	$type_id = ($row['HasChildren'] == 0) ? 'simple' : 'configurable';
	$surcharge = $row['SizeSurcharge'] + $row['ColorSurcharge'] + $row['StyleSurcharge'];
	$status = ($row['ProductStatus'] == 1) ? 1 : 2;
	$visibility = ($row['HasChildren'] == 0) ? 1 : 4;
	$visibility = (($row['HasChildren'] == 0)&&(empty($row['ParentItemCode']))) ? 4 : $visibility; 
	
	
	//fill values of product
    $product = Mage::getModel('catalog/product');
    $product->setWebsiteIds(array(1));
    $product->setSku($item_code);
    $product->setPrice($price_array[$item_code] + $surcharge);
    $product->setAttributeSetId(4);
    $product->setTypeId($type_id);
    $product->setName($row['ProductName']);
    $product->setDescription(strip_tags($row['InfoTextHTML']));
    $product->setShortDescription('Nimli');
    $product->setStatus($status);
    $product->setMetaKeyword(str_replace("|", ",", $item_attribute_array[$item_code]['SearchTerm']));
    $product->setVisibility($visibility);
    $product->setWeight($row['Weight']);
    $product->setCreatedAt($row['LaunchDate']);
    $product->setTaxClassId('2'); //2 is taxable goods
	$product->setOptionsContainer('container1');
	$product->setfulfillmentlatency($item_attribute_array[$item_code]['FulfillmentLatency']);
	$product->setmaterialandfabric(str_replace("|", ",", $item_attribute_array[$item_code]['MaterialAndFabric']));
	$product->setStockData(array('is_in_stock' => 1, 'qty' => 99999));
	$product->setbrand($item_attribute_array[$item_code]['Brand']);
	
	///eco attributes
	if(!empty($row['InfoText']))
	{
	$string = trim(str_replace(array('.gif', '|More Colors', '|More Colors,','|More Options','|More Scents','|More Sizes'), '', $row['InfoText']));
	$explode_string = explode(',', $string);
	$product->seteco_attribute(trim(get_magento_option_ids('eco_attribute', $explode_string), ','));
	}
	
	//set categories
	$category_ids = $category_array[$item_code];
	if(empty($category_ids) == false)
	{
	$product->setCategoryIds($category_ids);
	}
	
	//set configurable attributes for configurable products
    if ($type_id == 'configurable')
    {
    	$position_count = 0;
        $configurable_attribute_array = array($row['SizeLabel'], $row['ColorLabel'], $row['StyleLabel']);
        $configurable_attribute_array = array_filter($configurable_attribute_array, 'strlen');
        foreach($configurable_attribute_array as $key => $value)
        {
        	$configurable_attribute_array[$key] = ($value == 'Color') ? 'color_item' : strtolower(str_replace(array('|', '2'), '', $value));	
       	}
       	$configurable_attribute_data = array();
       	$position = 0;
        foreach($configurable_attribute_array as $value)
        {
        	$configurable_attribute_data[] = array('label' => $value, 'use_default' => '0',
    'position' => $position++, 'attribute_id' => $attribute_array[$value], 'attribute_code' =>
    $value, 'frontend_label' => $value, 'store_label' => $value);	
       	}
        $product->setCanSaveConfigurableAttributes(true);
        $product->setConfigurableAttributesData($configurable_attribute_data);
    }
	
	//give configurable attributes values, for item variations
	if(!empty($row['SizeLabel']))
	{
	$attribute_one = strtolower($row['SizeLabel']);
	$attribute_one = ($attribute_one == 'color') ? 'color_item' : $attribute_one;
	$attribute_one = str_replace(array('|', '2'), '', $attribute_one);
	$value_one = $row['SizeDescription'];
	$magento_product_data[$attribute_one] = get_magento_option_ids($attribute_one, array($value_one));
	}
	if(!empty($row['ColorLabel']))
	{
	$attribute_two = strtolower($row['ColorLabel']);
	$attribute_two = ($attribute_two == 'color') ? 'color_item' : $attribute_two;
	$attribute_two = str_replace(array('|', '2'), '', $attribute_two);
	$value_two = $row['ColorDescription'];
	$magento_product_data[$attribute_two] = get_magento_option_ids($attribute_two, array($value_two));
	}
	if(!empty($row['StyleLabel']))
	{
	$attribute_three = strtolower($row['StyleLabel']);
	$attribute_three = ($attribute_three == 'color') ? 'color_item' : $attribute_three;
	$attribute_three = str_replace(array('|', '2'), '', $attribute_three);
	$value_three = $row['StyleDescription'];
	$magento_product_data[$attribute_three] = get_magento_option_ids($attribute_three,  array($value_three));
	}
	$product->addData($magento_product_data);	
 
 
	//import images
    /*
    $images_array = array();
	$images_array[] = (($item_attribute_array[$item_code]['SwatchImageUrl']) != '') ? array('level' => 'thumbnail', 'url' => $item_attribute_array[$item_code]['SwatchImageUrl'], 'exclude' => true) : '';
	$images_array[] = (($item_attribute_array[$item_code]['MainImageUrl']) != '') ? array('level' => 'image', 'url' => $item_attribute_array[$item_code]['MainImageUrl'], 'exclude' => true) : '';
	$images_array = array_filter($images_array, 'is_array');
 
	foreach($images_array as $image_data)
	{
		//$product->addImageToMediaGallery($image_data['url'], array($image_data['level']), false, $image_data['exclude']); //last parameter is exclude, which should be true 
	}
    */
 
	//save product
	$count++;
	try
	{
    $product->save();
    $time = time() - $start;
    echo ($count) . ': ' . $item_code . " (" . $row['ProductName'] . ") is imported. (" . $time . " seconds)\n"; 
    }
    catch(Exception $e)
    {
    	echo $e->faultstring . "\n";
    	fwrite($log, "Excel Row: $item_code      This row was not inserted in Magento because of an error\n");
   	}
    //testing
    //if ($count == 1)
    //{
    //    break;
    //}
    
   	//reset for next iteration
	unset($configurable_attributes);
	unset($magento_product_data);
	unset($images_array);
	
	//clear product cache, so importing can go faster
	if ($a % 20 == 0)
    {
        $app->getCache()->clean();
        gc_collect_cycles();
    }
}
 
?>
            
Nimli
Imports attributes to the Nimli Magento Store
PHP
Click for Portfolio
                <?php
 
set_include_path(get_include_path() . PATH_SEPARATOR . 'C:/makeshift/files/saffron');
 
require_once ("/app/Mage.php"); //to do Magento Library functions
Mage::app('admin');
 
//connect and choose database
$c = mysql_connect('localhost', 'root', '');
mysql_select_db('puck', $c);
 
function get_all_attributes()
{
    $attributes = array();
    $sql_array[] = "SELECT sizelabel FROM item GROUP BY sizelabel";
    $sql_array[] = "SELECT colorlabel FROM item GROUP BY colorlabel";
    $sql_array[] = "SELECT stylelabel FROM item GROUP BY stylelabel";
    foreach ($sql_array as $sql)
    {
        $result = mysql_query($sql);
        while ($row = mysql_fetch_row($result))
        {
            $row[0] = ucwords($row[0]);
            if (!in_array($row[0], $attributes))
            {
                array_push($attributes, $row[0]);
            }
        }
    }
    sort($attributes);
    unset($attributes[array_search('', $options)]);
    return $attributes;
}
 
function get_all_options($configurable_attribute)
{
    $options = array();
    $sql_array[] = "SELECT sizedescription FROM item WHERE sizelabel = '$configurable_attribute' GROUP BY sizedescription";
    $sql_array[] = "SELECT colordescription FROM item WHERE colorlabel = '$configurable_attribute' GROUP BY colordescription";
    $sql_array[] = "SELECT styledescription FROM item WHERE stylelabel = '$configurable_attribute' GROUP BY styledescription";
    foreach ($sql_array as $sql)
    {
        $result = mysql_query($sql);
        while ($row = mysql_fetch_row($result))
        {
            $row[0] = ucwords($row[0]);
            $row[0] = str_replace(array('|2', '|'), "", $row[0]);
            if (!in_array($row[0], $options))
            {
                array_push($options, $row[0]);
            }
        }
    }
    sort($options);
    unset($options[array_search('', $options)]);
    return $options;
}
 
function get_attributes_with_options()
{
    $attributes_with_options = array();
    $all_attributes = get_all_attributes();
    foreach ($all_attributes as $attribute)
    {
    	$clean_attribute = str_replace(array('|2', '|'), "", $attribute);
    	if($clean_attribute == ''){$clean_attribute = 'attribute';}
    	if(ucwords($clean_attribute) == 'Color'){$clean_attribute = 'color_item'; }
        $attributes_with_options[$clean_attribute] = (substr_count($attribute, "|") >= 1) ? array_merge($attributes_with_options[$clean_attribute], get_all_options($attribute)) : get_all_options($attribute);
        echo "$attribute\n";
        $attributes_with_options[$clean_attribute] = array_unique($attributes_with_options[$clean_attribute]);
        sort($attributes_with_options[$clean_attribute]);
    }
    return $attributes_with_options;
}
 
function add_configurable_attribute($name)
{
    $attribute = Mage::getModel('catalog/resource_eav_attribute');
    $attribute->addData(array('entity_type_id' => Mage::getModel('eav/entity')->
        setType('catalog_product')->getTypeId(), 'attribute_code' => strtolower($name),
        'attribute_model' => null, 'backend_model' => null, 'backend_type' => 'int',
        'backend_table' => null, 'frontend_model' => null, 'frontend_input' => 'select',
        'frontend_label' => ucwords($name), 'frontend_class' => null, 'source_model' =>
        'eav/entity_attribute_source_table', 'is_required' => '0', 'is_user_defined' =>
        '1', 'default_value' => '', 'is_unique' => '0', 'note' => '',
        'frontend_input_renderer' => null, 'is_global' => '1', 'is_visible' => '1',
        'is_searchable' => '0', 'is_filterable' => '0', 'is_comparable' => '0',
        'is_visible_on_front' => '0', 'is_html_allowed_on_front' => '1',
        'is_used_for_price_rules' => '0', 'is_filterable_in_search' => '0',
        'used_in_product_listing' => '0', 'used_for_sort_by' => '0', 'is_configurable' =>
        '1', 'apply_to' => '', 'is_visible_in_advanced_search' => '0',
        'is_wysiwyg_enabled' => '0', 'is_used_for_promo_rules' => '0'));
    $attribute->setIsUserDefined(1);
    try
    {
        $attribute->save();
        echo "$name is now a Magento Attribute";
    }
    catch (exception $e)
    {
        echo '<p>Sorry, error occured while trying to save the attribute. Error: ' . $e->
            getMessage() . '</p>' . "\n";
    }
}
 
function add_options_to_attribute($name, $options) //options is an array of values
{
	$count = 1;
    $attribute = Mage::getResourceModel('eav/entity_attribute_collection')->
        setCodeFilter($name)->getFirstItem();
    $optionArr = array('value' => array(), 'order' => array(), 'delete' => array());
    foreach ($options as $key => $value)
    {
        $optionArr['value']['option_' . $key] = array($value, $value);
        $optionArr['order']['option_' . $key] = $count++;
    }
    var_export($optionArr);
    $attribute->setOption($optionArr);
    $attribute->save();
}
 
function add_attributes_with_options_to_magento()
{
	$attributes_with_options = get_attributes_with_options();
	foreach($attributes_with_options as $key => $value)
	{
		add_configurable_attribute($key);
		add_options_to_attribute($key, $value);
	}
}
 
 
add_attributes_with_options_to_magento();
 
?>
            
Nimli
Imports images to the Nimli Magento Store
PHP
Click for Portfolio
                <?php
 
set_include_path(get_include_path() . PATH_SEPARATOR . 'C:/MagentoProject' .
    PATH_SEPARATOR . 'C:/xampp/htdocs/adminfiles' . PATH_SEPARATOR .
    'C:/xampp/htdocs/chunk/');
 
require_once ("/app/Mage.php"); //to do Magento Library functions
Mage::app('admin');
 
 
$c = mysql_connect('localhost', 'root', '');
mysql_select_db('puck', $c);
 
 
 
//////////////////////////////////
//DELETE PRODUCT IMAGES
//////////////////////////////////
$media_api = Mage::getModel("catalog/product_attribute_media_api");
function delete_product_images($product)
{
	$attributes = $product->getTypeInstance ()->getSetAttributes ();
				if (isset ( $attributes ['media_gallery'] )) {
					$gallery = $attributes ['media_gallery'];
					//Get the images
					$galleryData = $product->getMediaGallery ();
					foreach ( $galleryData ['images'] as $image ) {
						//if image exists
						if (
							$gallery->getBackend ()->getImage ( $product, $image ['file'] )) 
							{
							$gallery->getBackend ()->removeImage ( $product, $image ['file'] );
						}
					}
					$product->save ();
				}
				echo $product->getSku() . " has it's images deleted\n";
}
 
 
 
 
foreach (Mage::getModel('catalog/product')->getCollection()->
    addAttributeToSelect('*')->addAttributeToFilter('brand', 'azuri') as $product)
{
    $sku = $product->getSku();
	delete_product_images($product);
    $suffix_array = array('main', 'swatch', 'alt2', 'alt3', 'alt4', 'alt5', 'alt6');
    foreach ($suffix_array as $suffix)
    {
        $filename = dirname(__file__) . '/azuri/' . $sku . "_{$suffix}.jpg";
        if (filesize($filename) != 0)
        {
         	switch ($suffix) {
		    case 'main':
		        $product->addImageToMediaGallery($filename, 'image', false, true);
		        break;
		    case 'swatch':
		        $product->addImageToMediaGallery($filename, 'thumbnail', false, true);
		        break;
		    case 'alt2':
		        $product->addImageToMediaGallery($filename, 'image', false, false);
		        break;
		    case 'alt3':
		        $product->addImageToMediaGallery($filename, 'image', false, false);
		        break;
		    case 'alt4':
		        $product->addImageToMediaGallery($filename, 'image', false, false);
		        break;
		    case 'alt5':
		        $product->addImageToMediaGallery($filename, 'image', false, false);
		        break;
		    case 'alt6':
		        $product->addImageToMediaGallery($filename, 'image', false, false);
		        break;
			}
        }
    }
    $product->save(); 
    echo "$sku now has images\n";
}
 
?>
            
Nimli
Imports brands to the Nimli Magento Store
PHP
Click for Portfolio
                <?php
 
set_include_path(get_include_path() . PATH_SEPARATOR . 'C:/MagentoProject' .
    PATH_SEPARATOR . 'C:/xampp/htdocs/adminfiles' . PATH_SEPARATOR .
    'C:/xampp/htdocs/chunk/');
 
 
 
require_once ("/app/Mage.php"); //to do Magento Library functions
Mage::app('admin');
 
 
$c = mysql_connect('localhost', 'root', '');
mysql_select_db('puck', $c);
 
////////////////////////////////////
//GET ALL IMAGE LINKS
////////////////////////////////////
$product_sheet_sql = "SELECT id1, brand FROM brands_csv";
$product_sheet_result = mysql_query($product_sheet_sql);
while ($row = mysql_fetch_assoc($product_sheet_result))
{
	$product_sheet_array[$row['id1']] = $row['brand'];
}
 
 
////////////////////////////////////
//GET ALL ITEMS IN SKU
////////////////////////////////////
$sql = "SELECT ItemCode, ParentItemCode FROM item";
$result = mysql_query($sql);
while ($row = mysql_fetch_assoc($result))
{
	$sku_array[] = $row['ItemCode'];
	$parent_array[$row['ItemCode']] = $product_sheet_array[$row['ItemCode']];
	if(empty($parent_array[$row['ItemCode']])){$parent_array[$row['ItemCode']] = $product_sheet_array[$row['ItemCode']];}
}
$parent_array = array_filter($parent_array, 'strlen');
 
//////////////////////////////////
//DELETE PRODUCT IMAGES
//////////////////////////////////
$media_api = Mage::getModel("catalog/product_attribute_media_api");
function delete_product_images($product)
{
	$attributes = $product->getTypeInstance ()->getSetAttributes ();
				if (isset ( $attributes ['media_gallery'] )) {
					$gallery = $attributes ['media_gallery'];
					//Get the images
					$galleryData = $product->getMediaGallery ();
					foreach ( $galleryData ['images'] as $image ) {
						//if image exists
						if (
							$gallery->getBackend ()->getImage ( $product, $image ['file'] )) 
							{
							$gallery->getBackend ()->removeImage ( $product, $image ['file'] );
						}
					}
					$product->save ();
				}
				echo $product->getSku() . " has it's images deleted\n";
}
 
 
 
 
 
 
 
 
////////////////////////////////
//LOOP THROUGH PRODUCTS (DELETE AND ADD ACCORDINGLY)
/////////////////////////////////
////////////////////////////////
//LOOP THROUGH PRODUCTS (DELETE AND ADD ACCORDINGLY)
/////////////////////////////////
/*
foreach(Mage::getModel('catalog/product')->getCollection() as $product)
{
	$time = time();
	$sku = $product->getSku();
	$brand = $parent_array[$sku];
	$product->setBrand($brand);
	//$product->save();
	$seconds = time() - $time;
	echo "$sku has been given a brand $brand ($seconds seconds)\n\n";	
	Mage::app()->getCache()->clean();
	unset($product);			
}
*/
 
fpve($parent_array);
 
 
?>
            
Nimli
Imports categories to the Nimli Magento Store
PHP
Click for Portfolio
                <?php
 
set_include_path(get_include_path() . PATH_SEPARATOR . 'C:/MagentoProject' .
	PATH_SEPARATOR . 'C:/makeshift/files/saffron/adminfiles' . PATH_SEPARATOR .
	'C:/makeshift/files/saffron/' . PATH_SEPARATOR . '/chroot/home/pashmina/pashminamall.com/html');
 
 
require_once ("/app/Mage.php"); //to do Magento Library functions
Mage::app('admin');
 
//instantiate category model
$category_model = Mage::getModel('catalog/category');
 
//connect and choose database
$c = mysql_connect('localhost', 'root', '');
mysql_select_db('puck', $c);
 
//get result
$sql = "SELECT cac1.*, cac2.category as parentcategoryname
FROM companyitemcategory as cac1
LEFT JOIN companyitemcategory as cac2 ON cac1.parentcatid = cac2.catid
WHERE cac1.parentcatid NOT IN (700, 739, 886, 889, 890, 892, 893, 891, 895, 894, 896, 897, 898, 899, 1254, 1712, 1781, 2258, 2268, 2259, 2280)
AND cac1.category NOT LIKE '%>>'
ORDER BY cac1.catid";
$result = mysql_query($sql);
 
//iterate through table
$count = 0;
$path = 4;
while($row = mysql_fetch_assoc($result))
{
	
	$count++;
	
	//SET VARIABLES FROM MYSQL ROW
	$category_name = $row['Category'];
	$parent_category_name = $row['parentcategoryname'];
	$omx_category_id = $row['CatID'];
	$omx_parent_category_id = $row['ParentCatID'];
	
	//GET CATEGORY PATH
	if ($parent_category_name != null)
	{
		$parent_category = $category_model->loadByAttribute('omx_category_id', $omx_parent_category_id);
		if($parent_category)
		{
			try
			{
				$path = $category_model->loadByAttribute('omx_category_id', $omx_parent_category_id)->getPath();
			}
			catch(Exception $e){}
		}
	}
 
	else
	{
		$path = "1/2";
	}
 
	
	///ADD CATEGORY
	$category = Mage::getModel('catalog/category');
	$category->setStoreId(0); 
	$general['name'] = $category_name;
	$general['path'] = $path; 
	$general['description'] = $category_name;
	$general['meta_title'] = $category_name; //Page title
	$general['meta_keywords'] = $category_name;
	$general['meta_description'] = $category_name;
	$general['landing_page'] = ""; //has to be created in advance, here comes id
	$general['display_mode'] = "PRODUCTS_AND_PAGE"; //static block and the products are shown on the page
	$general['is_active'] = 1;
	$general['is_anchor'] = 0;
	$general['omx_category_id'] = $omx_category_id;  //new attribute that Mark created, to resolve issues with 
								//categories of the same name
	$general['url_key'] = $category_name;//url to be used for this category's page by magento.
	
 
 
	$category->addData($general);
	try {
		$category->save();
		echo "Success! $category_name is now a category. Id:  ".$category->getId()."\n";
	}
	catch (Exception $e){
		echo $e->getMessage();
	}
	//END ADD CATEGORY
	
	
	//var_export($row);
}
 
 
?>
            
Nimli
Imports images to the Nimli Magento Store
PHP
Click for Portfolio
                <?php
 
set_include_path(get_include_path() . PATH_SEPARATOR . 'C:/MagentoProject' .
    PATH_SEPARATOR . 'C:/xampp/htdocs/adminfiles' . PATH_SEPARATOR .
    'C:/xampp/htdocs/chunk/');
 
require_once ("/app/Mage.php"); //to do Magento Library functions
Mage::app('admin');
 
 
$c = mysql_connect('localhost', 'root', '');
mysql_select_db('puck', $c);
 
////////////////////////////////////
//GET ALL IMAGE LINKS
////////////////////////////////////
$product_sheet_sql = "SELECT id1, image_link FROM products LIMIT 100, 1700";
$product_sheet_result = mysql_query($product_sheet_sql);
while ($row = mysql_fetch_assoc($product_sheet_result))
{
	$product_sheet_array[$row['id1']] = $row['id1'];
}
 
 
////////////////////////////////////
//GET ALL ITEMS IN SKU
////////////////////////////////////
$sql = "SELECT ItemCode, ParentItemCode FROM item";
$result = mysql_query($sql);
while ($row = mysql_fetch_assoc($result))
{
	$sku_array[] = $row['ItemCode'];
	$parent_image_array[$row['ItemCode']] = $product_sheet_array[$row['ItemCode']];
	if(empty($parent_image_array[$row['ItemCode']])){$parent_image_array[$row['ItemCode']] = $product_sheet_array[$row['ParentItemCode']];}
}
$parent_image_array = array_keys(array_filter($parent_image_array, "strlen"));
 
 
//////////////////////////////////
//DELETE PRODUCT IMAGES
//////////////////////////////////
$media_api = Mage::getModel("catalog/product_attribute_media_api");
function delete_product_images($product)
{
	$attributes = $product->getTypeInstance ()->getSetAttributes ();
				if (isset ( $attributes ['media_gallery'] )) {
					$gallery = $attributes ['media_gallery'];
					//Get the images
					$galleryData = $product->getMediaGallery ();
					foreach ( $galleryData ['images'] as $image ) {
						//if image exists
						if (
							$gallery->getBackend ()->getImage ( $product, $image ['file'] )) 
							{
							$gallery->getBackend ()->removeImage ( $product, $image ['file'] );
						}
					}
					$product->save ();
				}
				echo $product->getSku() . " has it's images deleted\n";
}
 
 
 
 
 
 
 
 
////////////////////////////////
//LOOP THROUGH PRODUCTS (DELETE AND ADD ACCORDINGLY)
/////////////////////////////////
 
foreach($parent_image_array as $sku)
{
	$product = Mage::getModel('catalog/product');
	$filename = dirname(__FILE__) . '/images/' .  $sku . '.jpg';
	if((filesize($filename) != 0)&&(empty($sku) == false))
	{	
	$time = time();
	$product->load($product->getIdBySku(trim($sku)));
	if($product->getId())
	{
	delete_product_images($product);
	$product->addImageToMediaGallery($filename, array('image', 'small_image'), false, true);
	
	
	$product->save();
	$seconds = time() - $time;
	echo "$sku has been given an image ($seconds seconds)\n\n";	
	 Mage::app()->getCache()->clean();
	
	}
	else
	{
		echo "$sku did not get an image\n";
	}
	unset($product);	
	} 
}
 
 
?>
            
Nimli
Imports Material & Fabric to the Nimli Magento Store
PHP
Click for Portfolio
                <?php
 
set_include_path(get_include_path() . PATH_SEPARATOR . 'C:/MagentoProject' .
    PATH_SEPARATOR . 'C:/xampp/htdocs/adminfiles' . PATH_SEPARATOR .
    'C:/xampp/htdocs/chunk/');
 
function cm($obj)
{
    var_export(get_class_methods($obj));
}
 
function ve($obj)
{
    var_export($obj);
}
 
function e($obj)
{
    echo ($obj);
}
 
function gc($obj)
{
    echo get_class($obj);
}
 
function fpve($obj)
{
    file_put_contents("C:/test/fp.txt", var_export($obj, 1));
}
 
function fpe($obj)
{
    file_put_contents("C:/test/fp.txt", $obj);
}
 
require_once ("/app/Mage.php"); //to do Magento Library functions
Mage::app('admin');
 
$product = Mage::getModel('catalog/product')->load(13);
$collection = Mage::getModel('catalog/product')->getCollection();
$category = Mage::getModel('catalog/category')->load(5);
//foreach($collection as $h){echo $h->getName() . "\n";}
$c = mysql_connect('localhost', 'root', '');
mysql_select_db('puck', $c);
$result = mysql_query('');
 
////////////////////////////////////////
///FUNCTION FOR SETTING OPTIONS FOR A PRODUCT (LIKE ECO ATTRIBUTE OR COLOR)
////////////////////////////////////////
$options_array = array();
function get_magento_option_ids($attribute_name, $option_names)
{
    $options_array = &$GLOBALS["options_array"]; //this array grows over time
    $attribute_name = strtolower($attribute_name);
    if (!isset($options_array[$attribute_name]))
        //fill up array with new attribute & options (done to not redeclare model class every single row, which is memory intensive)
 
    {
        if ($attribute_name == '')
        {
            $attribute_name = 'attribute';
        } //only done for that one category with no attribute name but had values
        $attribute = Mage::getModel('catalog/resource_eav_attribute')->loadByCode('catalog_product',
            strtolower($attribute_name));
        $options = $attribute->getSource()->getAllOptions(true);
        foreach ($options as $array)
        {
            $options_array[$attribute_name][strtolower(trim($array[label]))] = $array[value];
        }
    }
    ///GET VALUES FROM ARRAY ABOVE
    foreach ($option_names as $option_name)
    {
        $values[] = $options_array[$attribute_name][strtolower($option_name)];
    }
    $string = implode(',', array_values($values));
    return $string;
}
 
////////////////////////////////////
//GET ATTRIBUTES FROM ITEM ATTRIBUTES BACKUP TABLE (brand, search, materialandfabric, etc)
////////////////////////////////////
echo "Making Array from Item Attribute backup table...\n";
$item_attribute_sql =
    "SELECT ItemCode, AttributeValue8 as Brand, AttributeValue7 as SearchTerm, AttributeValue16 as FulfillmentLatency,
AttributeValue18 as SmallImageUrl, AttributeValue19 as MainImageUrl, AttributeValue20 as Alternate1ImageUrl,
AttributeValue21 as Alternate2ImageUrl, AttributeValue22 as Alternate3ImageUrl, AttributeValue23 as Alternate4ImageUrl,
AttributeValue24 as Alternate5ImageUrl, AttributeValue25 as Alternate6ImageUrl,
AttributeValue42 as MaterialAndFabric, AttributeValue48 as SwatchImageUrl
FROM itemattribute";
$item_attribute_result = mysql_query($item_attribute_sql);
$item_attribute_array = array();
while ($item_attribute_row = mysql_fetch_assoc($item_attribute_result))
{
    $item_attribute_array[$item_attribute_row['ItemCode']] = $item_attribute_row;
}
 
 
 
////////IMPORT
foreach(Mage::getModel('catalog/product')->getCollection() as $product)
{
	$sku = $product->getSku();
	$material_option_names = explode('|', $item_attribute_array[$sku]['MaterialAndFabric']);
	$material_id_string = get_magento_option_ids('materialandfabric', $material_option_names);
	//$product->setmaterialandfabric($material_id_string)->save();
	echo "$sku has materialandfabric updated with multiple select attributes ($material_id_string)\n";
	
}
 
 
 
 
 
?>
            
Wordpress WatuPro plugin
Automatically updates a student's test scores from a Wordpress Page & plugin that has functionality for students taking exams.
PHP
Click for Portfolio
                <?
////////////////////
//
//  MARKS CHANGES
//
////////////////////
//This wordpress hook was called in C:\makeshift\files\wordpress\goon_city\wp-content\plugins\watupro\controllers\questions.php (function: watupro_questions, line 248)
//This is at the point where a question has been changed in the Administration Panel
add_action( 'watupro_saved_question', 'watupro_saved_question_custom');
function watupro_saved_question_custom($question_id)
{
	global $wpdb;
$_watu = new WatuPRO();
//From the question id, get tkhe exam it's affiliated with (exam is a parent entity of the question)
//Left joining into the Exam table to get advanced settings
$exam = $wpdb->get_row($wpdb->prepare("SELECT questions.* , master.advanced_settings FROM " . WATUPRO_QUESTIONS." as questions LEFT JOIN ".WATUPRO_EXAMS." as master ON master.ID = questions.exam_id WHERE questions.ID=%d", $question_id));
$exam_id = $exam->exam_id;
//code from show_exam.php (before submit_exam.php)
$advanced_settings = unserialize(stripslashes($exam->advanced_settings));
//From the Student Taken Occurences Table (the answers that were chosen will be put here for comparison, to compare to the current answers located in the wp_watupro_answers table).
$takings = $wpdb->get_results($wpdb->prepare("SELECT * FROM ".WATUPRO_TAKEN_EXAMS." WHERE exam_id=%d ORDER BY ID DESC", $exam_id));
//Get all the questions from the Exam Id
$questions = $wpdb->get_results($wpdb->prepare("SELECT * FROM ".WATUPRO_QUESTIONS." WHERE exam_id=%d", $exam_id));
//Iterate through all student taking IDS, then iterate through the questions to calculate totals
foreach ($takings as $taking)
{
	$taking_id = $taking->ID;
	$total = $score = $max_points = $achieved = $num_empty = $num_wrong = 0;
	//Iterate through the questions to calculate totals
	foreach ($questions as $question) {	
		$question_id = $question->ID;
		//According to the store_result function in the watopro.php lib file, a $question object is a database row.
		$answers = $wpdb->get_results($wpdb->prepare("SELECT * FROM ".WATUPRO_ANSWERS." WHERE question_id=%d AND question_id>0 ORDER BY sort_order", $question_id));
		//this part is necessary for the WTPQuestion::max_scores function. It's looking at this q_answers variable I just put below
		$question->q_answers = $answers;
		$chosen_answers = $wpdb->get_results($wpdb->prepare("SELECT * FROM ".WATUPRO_STUDENT_ANSWERS." WHERE taking_id=%d AND question_id=%d", $taking_id,$question_id));
		//The entire purpose of getting $chosen_answer_ids is to put as a parameter to WTPQUESTION::calc_answer
		//THE FOLLOWING IS TO PROTECT the VALUES WHEN THERE ARE COMMAS
		$chosen_answer_ids = array();
		$answers_values = array_map(function($answer){return $answer->answer;},$answers);
		$answers_quotes = array_map(function($answer_value){return '"'. $answer_value . '"';},$answers_values);
		//unfortunately, you have to cross reference the answers the student chose with the correct answer known in the answers table (no join used here)
		foreach($chosen_answers as $chosen_answer)
		{
			//THIS IS THE ANNOYING LONG STRING WITH COMMAS!!!
			$chosen_answer_full_names = $chosen_answer->answer;
			$chosen_answer_full_names = str_replace($answers_values,$answers_quotes,$chosen_answer_full_names);
			foreach(str_getcsv($chosen_answer_full_names) as $chosen_answer_full_name)
			{
				$chosen_answer_full_name = trim($chosen_answer_full_name);
				foreach ($answers as $answer) {		
					if(strtolower($chosen_answer_full_name) == strtolower($answer->answer))
					{
						$chosen_answer_ids[] = $answer->ID;
					}
				}
			}
		}
		if($debug)
		{
			// echo "STUDENT ID: $taking_id\n";
			// debug_help("QUESTION",$question);
			// debug_help("ALL ANSWERS",$answers);
			// debug_help("CHOSEN ANSWER",$chosen_answers);
			// debug_help("CHOSEN ANSWER IDS",$chosen_answer_ids);
		}
		//THE POINT OF THOSE SQL CALLS WAS TO CALCULATE THE POINTS & A BOOLEAN IF THE QUESTION WAS CORRECT
		list($points, $correct, $is_empty) = WTPQuestion::calc_answer($question, $chosen_answer_ids,$answers);
		$question_max_points = WTPQuestion::max_points($question);
		//calculate total & score
		if(empty($question->is_survey)) $total++;
		if($correct) $score++;
		//calculate percent
	  	if($total==0) $percent=0;
		else $percent = number_format($score / $total * 100, 2);
		$percent = round($percent);
		//get total points that were acquired
		//the following is a separate grading system based on the amount of points, and not grading based on # right or # wrong. It is weighted.
		$achieved += $points;	
		$max_points += WTPQuestion::max_points($question);
		if($is_empty and empty($question->is_survey))
		{
			$num_empty++;
		}
      	if(!$is_empty and !$correct and empty($question->is_survey))
      	{
      		$num_wrong++;
      	}
		if($achieved <= 0 or $max_points <= 0)
		{
			$pointspercent = 0;
		}
		else
		{
			$pointspercent = number_format($achieved / $max_points * 100, 2);
		}
		//generic rating, doesn't matter as much as above
		$rating = $_watu->calculate_rating($total, $score, $percent);	
	}//end question iteration
	//Grade tabulating should not be in the question for-loop above, just as it is in submit-exam.php
	list($grade, $certificate_id, $do_redirect, $grade_obj) = WTPGrade::calculate($exam_id, $achieved, $percent, 0, $user_grade_ids, $pointspercent);
	$grade_value = $grade_obj->gtitle;
	if($debug)
	{
		echo "STUDENT TEST OCCURENCE: $taking_id\n";
		echo "POINTS: $points\n";
		echo "PERCENT: $percent\n";
		echo "SCORE: $score\n";
		echo "TOTAL: $total\n";
		echo "MAX POINTS: $max_points\n";
		echo "RATING: $rating\n";
		echo "ACHIEVED: $achieved\n";
		echo "POINTS PERCENT: $pointspercent\n";
		echo "GRADE: $grade\n";
		echo "GRADE: {$grade_obj->ID}\n";		
		echo "NUM EMPTY: $num_empty\n";
		echo "NUM WRONG: $num_wrong\n";
		echo "\n\n\n\n\n\n";
	}
	//points = all points combined ($achieved)
	//result = String HTML of Grade
	//grade_id = ID of Grade
	//percent_correct = 75 (based on right vs wrong)
	//percent_points = 82 (based on points) $pointpercent
	//num_correct = Number of Raw correct in entire exam (known as $score)
	//num_wrong = num_wrong
	//num_empty = num_empty
	//max_points = max_points
	$result = $wpdb->update(WATUPRO_TAKEN_EXAMS, array(
	    	"points" => $achieved,
			"result" => $grade,
			"grade_id" => $grade_obj->ID,
			"percent_correct" => $percent,
			"percent_points" => $pointspercent,
			"num_correct" => $score,
			"num_wrong" => $num_wrong,
			"num_empty" => $num_empty,
			"max_points" => $max_points
	    ),
		array(
			"id"=>$taking_id
		)	
	);
	echo "$result\n";
}//end taking exam occurence iteration
 
 
////////////////////
//
//  SECOND TWEAK (UPDATE THE OTHER TABLE AS WELL, WHICH IS THE WP_WATUPRO_STUDENT_PLUGIN APP. THE REASON FOR THIS IS TO UPDATE THE SINGLE PAGE VIEW OF THE EXAM TAKEN OCCURENCES, AS IT READS FROM THAT TABLE!!!
//
//////////////////// 
$student_answers = $wpdb->get_results($wpdb->prepare("SELECT * FROM ".WATUPRO_STUDENT_ANSWERS." WHERE exam_id=%d ORDER BY ID DESC ",$exam_id));
foreach ($student_answers as $key => $student_answer) {
	$student_answer_question_id = $student_answer->question_id;
    $answers = $wpdb->get_results($wpdb->prepare("SELECT * FROM ".WATUPRO_ANSWERS. " WHERE question_id=%d  AND question_id>0 ORDER BY sort_order",$student_answer_question_id));
    $question = $wpdb->get_row($wpdb->prepare("SELECT * FROM ".WATUPRO_QUESTIONS. " WHERE ID=%d",$student_answer_question_id));
    $question->q_answers = $answers;
    $answers_values = array_map(function($answer){return $answer->answer;},$answers);
	$answers_quotes = array_map(function($answer_value){return '"'. $answer_value . '"';},$answers_values);	
	$chosen_answer_ids = array();
	$chosen_answer_full_names = $student_answer->answer;
	$chosen_answer_full_names = str_replace($answers_values,$answers_quotes,$chosen_answer_full_names);
	foreach(str_getcsv($chosen_answer_full_names) as $chosen_answer_full_name)
	{
		$chosen_answer_full_name = trim($chosen_answer_full_name);
		foreach ($answers as $answer) {		
			if(strtolower($chosen_answer_full_name) == strtolower($answer->answer))
			{
				$chosen_answer_ids[] = $answer->ID;
			}
		}
	}
	list($points, $correct, $is_empty) = WTPQuestion::calc_answer($question, $chosen_answer_ids,$answers);
	if($debug)
	{
		echo "-------\n";
		echo "POINTS: $points\n";
		echo "CORRECT: $correct\n";
		echo "IS EMPTY: $is_empty\n";
	}
	$result = $wpdb->update(WATUPRO_STUDENT_ANSWERS, array(
	    	"points" => $points,
			"is_correct" => $correct,
	    ),
		array(
			"ID"=>$student_answer->ID
		)
	);
	echo $result;
}
////////////////////
//
//  END CHANGING THE SINGLE VIEW SECTION IN THE WP_WATUPRO_STUDENT_PLUGIN
//
////////////////////
}
            
React
(app.js)Test out when the hooks for a functional & class component are called with a counter in React.js
JS
Click for Portfolio
                import { Provider } from 'react-redux';
import '../styles/App.css';
import CounterClass from "./CounterClass.js";
import CounterFunctional from "./CounterFunctional.js";
import ReduxResult from './ReduxResult.js';
import Log from './Log.js';
import store from "./ReduxStore.js";
  
  
 
 
function App() {
  return (
    <Provider store={store}>
        <div className="App flex bg-red-500 min-h-screen">
                <div className="flex flex-1 justify-center items-center flex-col min-h-screen bg-slate-900">
                    <CounterClass id="1" />
                    <CounterFunctional id="2" />
                    <ReduxResult />
                </div>
                <div className="flex flex-1 flex-col w-full justify-end p-8 min-h-screen bg-slate-950">
                    <Log/>
                </div>
        </div>
           
        
    </Provider>
  );
}
 
export default App;

            
React
(counter.js) Test out when the hooks for a functional & class component are called with a counter in React.js
JS
Click for Portfolio
                import React, { useState } from 'react';
import styles from '../styles/styles.module.css';
import { Toaster, toast } from 'sonner'
 
 
function Counter() {
  const [count, setCount] = useState(0);
  const [text, setText] = useState('');
 
 
  const handlePlusClick = () => {
      setCount(count + 1);
      toast('Plus');
  };
 
  const handleMinusClick = () => {
      setCount(count - 1);
      toast('Minus');
  };
 
  const handleTextChange = (event) => {
    setText(event.target.value);
  };
 
 
  return (
    <div className="flex items-center justify-center">
      
      <div className="flex">
        <input value={count} onChange={handleTextChange} />
      </div>
      <button className="flex" onClick={handlePlusClick}>+</button>
      <button className="flex" onClick={handleMinusClick}>-</button>
    </div>
  );
}
 
export default Counter;
 

            
React
(counterclass.js) Test out when the hooks for a functional & class component are called with a counter in React.js
JS
Click for Portfolio
                import React, { Component } from 'react';
import styles from '../styles/styles.module.css';
import { connect } from 'react-redux';
import { increment, decrement, push_to_log } from './ReduxStore.js';
 
 
class ClassCounter extends Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
    // Order: 0 - Constructor: Initializes state, binds methods.
  }
 
  componentDidMount() {
    this.props.push_to_log('(Class Component) Component Did Mount');
    // Order: 3 - After component insertion. Good for API calls.
  }
 
  shouldComponentUpdate(nextProps, nextState) {
    this.props.push_to_log('(Class Component) Should Component Update');
    // Order: 4 (before each update) - Decides if re-rendering is needed.
    return true;
  }
 
  getSnapshotBeforeUpdate(prevProps, prevState) {
    this.props.push_to_log('(Class Component) Get Snapshot Before Update');
    // Order: 6 (before each DOM update) - Right before DOM updates.
    return null;
  }
 
  componentDidUpdate(prevProps, prevState, snapshot) {
    this.props.push_to_log('(Class Component) Component Did Update');
    // Order: 7 (after each update) - After updates are flushed to the DOM.
  }
 
  componentWillUnmount() {
    this.props.push_to_log('(Class Component) Component Will Unmount');
    // Order: 8 (before unmounting) - Before removal from the DOM. Good for cleanup.
  }
 
  handlePlusClick = () => {
    this.setState({ count: this.state.count + 1 });
    this.props.increment(this.props.id);
    this.props.push_to_log('(Class Component) ');
    this.props.push_to_log('(Class Component) Increment');
    // Order: 5 (during update) - Increment count.
  };
 
  handleMinusClick = () => {
    this.setState({ count: this.state.count - 1 });
    this.props.decrement(this.props.id);
    this.props.push_to_log('(Class Component) ');
    this.props.push_to_log('(Class Component) Decrement');
    // Order: 5 (during update) - Decrement count.
  };
 
  render() {
    this.props.push_to_log('(Class Component) Render');
    // Order: 1 (initial), 2 (on each update) - Outputs JSX to the DOM.
    return (
        <div class="flex flex-col mb-2">
            <div className="flex justify-center mb-1">
                Class Component
            </div>
            <div className="flex flex-row mb-1">
                <div className="">
                    <input className="h-8 p-1" value={this.state.count} />
                </div>
                <button className="h-8 w-8 ml-1 bg-slate-700" onClick={this.handlePlusClick}>+</button>
                <button className="h-8 w-8 ml-1 bg-slate-700" onClick={this.handleMinusClick}>-</button>
            </div>
        </div>
 
    );
  }
}
 
const mapStateToProps = (state, ownProps) => ({
    count: state.counter.counters[ownProps.id] || 0, // Access count for specific id,
});
 
const mapDispatchToProps = {
    increment,
    decrement,
    push_to_log
};
 
export default connect(mapStateToProps, mapDispatchToProps)(ClassCounter);
            
React
(counterfunctional.js) Test out when the hooks for a functional & class component are called with a counter in React.js
JS
Click for Portfolio
                import React, { useState, useEffect, useLayoutEffect } from 'react';
import { increment, decrement, push_to_log } from "./ReduxStore.js";
import { useDispatch } from "react-redux";
 
function CounterFunctional({ id }) {
    const [count, setCount] = useState(0);
 
    const dispatch = useDispatch();
  
  dispatch(push_to_log('(Functional Component) useState'));
  // Order: 0 (on each render) - useState: Adds state to functional components.
 
  useEffect(() => {
    dispatch(push_to_log('(Functional Component) useEffect - Mount'));
    // Order: 2 (after first render) - Similar to componentDidMount and componentDidUpdate.
    return () => {
      dispatch(push_to_log('(Functional Component) useEffect - Cleanup'));
      // Order: 7 (before unmounting) - Cleanup: Similar to componentWillUnmount.
    };
  }, []);
 
  useEffect(() => {
    dispatch(push_to_log('(Functional Component) useEffect - {count} Update'));
    // Order: 3 (after each update) - Runs on state/props update with dependency array.
  }, [count]);
 
  useLayoutEffect(() => {
    dispatch(push_to_log('(Functional Component) useLayoutEffect'));
    // Order: 1 (after each render before DOM updates) - Fires synchronously after all DOM mutations.
  });
 
  const handlePlusClick = () => {
    setCount(count + 1);
    dispatch(push_to_log('(Functional Component) '));
    dispatch(push_to_log('(Functional Component) Increment'));
    dispatch(increment(id)); 
    // Order: 4 (during update) - Increment count.
  };
 
  const handleMinusClick = () => {
    setCount(count - 1);
    dispatch(decrement(id)); 
    dispatch(push_to_log('(Functional Component) '));
    dispatch(push_to_log('(Functional Component) Decrement'));
    // Order: 4 (during update) - Decrement count.
  };
 
  return (
    <div class="flex flex-col mb-5">
        <div className="flex justify-center mb-1">
            Functional Component
        </div>
        <div className="flex flex-row mb-1">
            <div className="">
                <input className="h-8 p-1" value={count} />
            </div>
            <button className="h-8 w-8 ml-1 bg-slate-700" onClick={handlePlusClick}>+</button>
            <button className="h-8 w-8 ml-1 bg-slate-700" onClick={handleMinusClick}>-</button>
        </div>
    </div>
  );
}
 
export default CounterFunctional;

            
React
(log.js) Test out when the hooks for a functional & class component are called with a counter in React.js
JS
Click for Portfolio
                import React from 'react';
import { useSelector } from "react-redux";
 
 
export const Log = () => {
 
  const log_list = useSelector(state => state.log.log);   
 
  return (
    <div class="flex">
      <ul className="w-3/4">
        {log_list.map((entry, index) => (
          <li className="bg-gradient-to-r from-[#FF3300] to-purple-400 text-[#330033] font-verdana text-[13px] font-bold mb-2 rounded shadow px-2 py-[1px] border-white border-[0px]" key={index}>{entry}</li>
        ))}
      </ul>
    </div>
  );
}
 
export default Log;
 

            
React
(reduxresult.js) Test out when the hooks for a functional & class component are called with a counter in React.js
JS
Click for Portfolio
                import React from 'react';
import { useSelector } from 'react-redux';
 
function ReduxResult() {
  const counters = useSelector(state => state.counter.counters);
  const total = Object.values(counters).reduce((sum, current) => sum + current, 0);
 
  return (
    <div>
      <h2>(Redux) Total Count: {total}</h2>
    </div>
  );
}
 
export default ReduxResult;

            
React
(reduxstore.js) Test out when the hooks for a functional & class component are called with a counter in React.js
JS
Click for Portfolio
                import { configureStore, createSlice } from '@reduxjs/toolkit';
 
const counterSlice = createSlice({
    name: 'counter',
    initialState: {
        counters: {} // Object to hold individual counters
    },
    reducers: {
        increment: (state, action) => {
            const id = action.payload; // id of the counter to increment
            if (state.counters[id] === undefined) state.counters[id] = 0;
            state.counters[id] += 1;
        },
        decrement: (state, action) => {
            const id = action.payload; // id of the counter to decrement
            if (state.counters[id] === undefined) state.counters[id] = 0;
            state.counters[id] -= 1;
        }
    }
});
 
const logSlice = createSlice({
    name: 'log',
    initialState: {
        log: []
    },
    reducers: {
        push_to_log(state, action) {
            state.log.push(action.payload);
            if(state.log.length > 18) state.log.shift();
        }
    }
});
 
export const { increment, decrement } = counterSlice.actions;
export const { push_to_log } = logSlice.actions;
 
const store = configureStore({
reducer: {
    counter: counterSlice.reducer,
    log: logSlice.reducer
}
});
 
export default store;

            
LeetCode
Growing list of grinding LeetCode algorithms on my own (Note- ChatGPT did the comments)
Python
Click for Portfolio
                def permutation_in_string(small_string,long_string):
    '''
    is a permutation of small string in long string (true or false)
 
    NOTE: NEETCODE DID A FREQUENCY ARRAY OF A TO Z, OF 26 KEY ENTRIES
    '''
    length_small_string = len(small_string)
    length_long_string = len(long_string)
    
    # fill dict of small string
    char_map_small_string = {}
    for l in small_string:
        char_map_small_string[l] = char_map_small_string.get(l,0) + 1;
 
    # fill dict of sliding window that's fixed
    char_map_sliding_window = {} 
    for l in long_string[0:length_small_string]:
        char_map_sliding_window[l] = char_map_sliding_window.get(l,0) + 1;
 
    # sliding window from left to right, fixed size
    for right in range(length_small_string,length_long_string):
        left = right - length_small_string
        letter_right = long_string[right]
        letter_left = long_string[left]
        print(char_map_small_string,char_map_sliding_window)
        if char_map_sliding_window == char_map_small_string:
            return True
        # the character map will reflect when the sliding window moves right
        char_map_sliding_window[letter_left] = char_map_sliding_window[letter_left] - 1
        # do this for equality. Remove from charmap if it's zero
        if char_map_sliding_window[letter_left] == 0:
            del char_map_sliding_window[letter_left]
        char_map_sliding_window[letter_right] = char_map_sliding_window.get(letter_right,0) + 1
 
    return False
 
# permutation_in_string("abee","fibembaeewellon")
 
 
 
 
 
 
def minimum_window_substring(string_small, string_long):
    # Create a set of unique characters in the small string
    set_string_small = set(string_small)
    # Map each character in the small string to its count
    char_map_string_small = {}
    for c in string_small:
        char_map_string_small[c] = char_map_string_small.get(c, 0) + 1
        # Initialize a deque 
        stack = deque()
        # Initialize a map to keep track of characters in the long string
        char_map_string_long = {}
        # Initialize variables for the final result
        max_length = 0
        result = ''
        # Iterate over each character in the long string
        for index, character_long in enumerate(string_long):
            # If the character is in the small string
            if character_long in set_string_small:
                # Add the character to the window stack
                stack.append([character_long, index])
                # Update the character count in the long string map
                char_map_string_long[character_long] = char_map_string_long.get(character_long, 0) + 1
                # Update the right pointer to the current index
                right = index
                # If the window size exceeds the small string size, remove the leftmost character
                if len(stack) > len(string_small):
                    # Remove the leftmost character from the window
                    pop_node = stack.popleft()
                    removed_character = pop_node[0]
                    removed_position = pop_node[1]
                    # Update the left pointer to the removed character's position
                    left = removed_position
                    # Decrease the character count in the long string map
                    char_map_string_long[removed_character] = char_map_string_long.get(removed_character, 0) - 1
            # If the character counts in the small and long string maps match
            if char_map_string_small == char_map_string_long:
                # Calculate the length of the current window
                string_length = stack[-1][1] - stack[0][1]
                # Update the maximum length found so far
                max_length = max(max_length, string_length)
                # If the current window is smaller than the maximum length, update the result
                if string_length <= max_length:
                    result = string_long[stack[0][1]: stack[-1][1] + 1]
        # Return the minimum window substring
    return result
            
 
# minimum_window_substring("abc","adobecodebanc")