about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rwxr-xr-xawk/scheme/s.awk139
-rw-r--r--chibi/pi.scm17
-rw-r--r--html/matt-chat/ChicagoFLF.ttfbin0 -> 31256 bytes
-rw-r--r--html/matt-chat/cat.pngbin0 -> 2573 bytes
-rw-r--r--html/matt-chat/com.user.server.plist16
-rw-r--r--html/matt-chat/index.html1266
-rw-r--r--html/matt-chat/pokemon.js157
-rwxr-xr-xhtml/matt-chat/server.sh23
8 files changed, 1618 insertions, 0 deletions
diff --git a/awk/scheme/s.awk b/awk/scheme/s.awk
new file mode 100755
index 0000000..7c8bba6
--- /dev/null
+++ b/awk/scheme/s.awk
@@ -0,0 +1,139 @@
+#!/usr/bin/awk -f
+
+# Set debug mode
+DEBUG = 1  # Change to 0 to disable debug output
+
+# Environment to store variable bindings
+BEGIN {
+    print "Welcome to the AWK Scheme Interpreter!"
+    print "Type your Scheme expressions below (type 'exit' to quit):"
+    while (1) {
+        printf "> "
+        if (getline input <= 0) {
+            print "Error reading input. Exiting."
+            break
+        }
+        if (input == "exit") {
+            print "Exiting the interpreter."
+            exit
+        }
+        if (input == "") {
+            print "Empty input received, continuing..."
+            continue
+        }
+        
+        print "Input received: " input  # Echo the input
+        ast = parse(input)  # Parse the input
+        
+        # Print the entire AST for debugging
+        for (i = 1; i <= length(ast); i++) {
+            print "AST[" i "] = " ast[i]
+        }
+        
+        # Evaluate the AST
+        if (length(ast) > 0) {
+            result = eval(ast)  # Evaluate the AST
+            print "Result: " result  # Print the result
+        } else {
+            print "Parsed AST is empty."
+        }
+    }
+}
+
+# Function to parse input into an AST
+function parse(input) {
+    # Remove outer whitespace
+    gsub(/^\s+|\s+$/, "", input)
+    
+    # Check if input is empty after trimming
+    if (input == "") {
+        print "Input is empty after trimming"
+        return ""
+    }
+    
+    # Debugging: Print input before processing
+    print "Debug: Raw input for parsing: " input
+    
+    # Remove parentheses at start and end
+    if (substr(input, 1, 1) == "(") {
+        input = substr(input, 2)
+    }
+    if (substr(input, length(input), 1) == ")") {
+        input = substr(input, 1, length(input) - 1)
+    }
+    
+    # Debugging: Print input after removing outer parentheses
+    print "Debug: Input after removing outer parentheses: " input
+    
+    # Split the input into tokens
+    gsub(/\(/, " ( ", input)
+    gsub(/\)/, " ) ", input)
+    gsub(/\s+/, " ", input)  # normalize whitespace
+    gsub(/^\s+|\s+$/, "", input)  # trim
+    
+    # Debugging: Print input after tokenization
+    print "Debug: Input after tokenization: " input
+    
+    n = split(input, ast, " ")
+    
+    # Debugging: Print the number of tokens
+    print "Debug: Number of tokens: " n
+    
+    return ast
+}
+
+# Function to evaluate the AST
+function eval(ast,    i, result) {
+    # Debugging: Print the current AST being evaluated
+    print "Debug: Evaluating AST: " ast[1] " " ast[2] " " ast[3]
+    
+    # Handle numbers directly
+    if (ast[1] ~ /^[+-]?[0-9]+$/) {
+        print "Debug: Returning number: " ast[1]
+        return ast[1] + 0  # Convert string to number
+    }
+    
+    # Handle addition
+    if (ast[1] == "+") {
+        result = 0
+        for (i = 2; i <= length(ast); i++) {
+            print "Debug: Adding operand: " ast[i]
+            result += eval(ast[i])  # Recursively evaluate operands
+        }
+        return result
+    }
+    
+    # Handle subtraction
+    if (ast[1] == "-") {
+        result = eval(ast[2])  # Start with the first operand
+        for (i = 3; i <= length(ast); i++) {
+            print "Debug: Subtracting operand: " ast[i]
+            result -= eval(ast[i])  # Subtract subsequent operands
+        }
+        return result
+    }
+    
+    # Handle multiplication
+    if (ast[1] == "*") {
+        result = 1
+        for (i = 2; i <= length(ast); i++) {
+            print "Debug: Multiplying operand: " ast[i]
+            result *= eval(ast[i])  # Multiply operands
+        }
+        return result
+    }
+    
+    # Handle division
+    if (ast[1] == "/") {
+        result = eval(ast[2])  # Start with the first operand
+        for (i = 3; i <= length(ast); i++) {
+            print "Debug: Dividing by operand: " ast[i]
+            result /= eval(ast[i])  # Divide by subsequent operands
+        }
+        return result
+    }
+    
+    # If we reach here, the operation is not recognized
+    return "Error: Unknown operation " ast[1]
+}
+
diff --git a/chibi/pi.scm b/chibi/pi.scm
new file mode 100644
index 0000000..a32742c
--- /dev/null
+++ b/chibi/pi.scm
@@ -0,0 +1,17 @@
+(define (greory-leibniz-terms n)
+  (cond ((= n 0) '())
+        ((even? n) (cons 1/g (greory-leibniz-terms (+ (- n 1) /2))))
+        (else (cons (/(-1) (* 2 n +3)) (/(*x^2) x))))))
+
+(define pi-approximation 
+  (define x '())
+  (define f (lambda (y) y))
+
+  (display "Approximating Pi using Gregory-Leibniz series...\n")
+  (for-each
+    lambda (term)
+    (define n (car term))
+    (set! x (+ x (* 4 / n)))
+    (f (f (g (g (/(*f f 4)) (/(*x^2) x))))))))) ))
+
+(display pi-approximation))
\ No newline at end of file
diff --git a/html/matt-chat/ChicagoFLF.ttf b/html/matt-chat/ChicagoFLF.ttf
new file mode 100644
index 0000000..60691e1
--- /dev/null
+++ b/html/matt-chat/ChicagoFLF.ttf
Binary files differdiff --git a/html/matt-chat/cat.png b/html/matt-chat/cat.png
new file mode 100644
index 0000000..7d4c0b9
--- /dev/null
+++ b/html/matt-chat/cat.png
Binary files differdiff --git a/html/matt-chat/com.user.server.plist b/html/matt-chat/com.user.server.plist
new file mode 100644
index 0000000..b5fb9dd
--- /dev/null
+++ b/html/matt-chat/com.user.server.plist
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+    <key>Label</key>
+    <string>com.user.server</string>
+    <key>ProgramArguments</key>
+    <array>
+        <string>/Users/eli/Code/institute/tour/html/matt-chat/server.sh</string>
+    </array>
+    <key>RunAtLoad</key>
+    <true/>
+    <key>KeepAlive</key>
+    <true/>
+</dict>
+</plist>
\ No newline at end of file
diff --git a/html/matt-chat/index.html b/html/matt-chat/index.html
new file mode 100644
index 0000000..2bc8119
--- /dev/null
+++ b/html/matt-chat/index.html
@@ -0,0 +1,1266 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <meta name="description" content="Chatty chat chat chat. A super simple chat interface for the Ollama API.">
+    <title>matt chat is not a cat</title>
+    <meta name="theme-color" content="#007BFF">
+    <link rel="icon" href="cat.png" type="image/x-icon">
+    <link rel="shortcut icon" href="cat.png" type="image/x-icon">
+    <link rel="apple-touch-icon" href="cat.png">  
+    <link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap" rel="stylesheet">
+    <style>
+        body {
+            font-family: Arial, sans-serif;
+            font-size: 22px;
+            margin: 0;
+            padding: 20px;
+            background-color: #f7f7f7;
+            max-width: 800px;
+            margin: 0 auto;
+            display: flex;
+            flex-direction: column;
+            align-items: center;
+            height: 100vh;
+            overflow: hidden;
+        }
+        #chat-container {
+            background-color: white;
+            border: 1px solid #ccc;
+            border-radius: 8px;
+            padding: 1em;
+            margin: 0 auto;
+            flex: 1;
+            overflow-y: auto;
+            width: 100%;
+            max-height: 400px;
+            scroll-behavior: smooth;
+        }
+        #user-input {
+            width: 100%;
+            padding: 10px;
+            border-radius: 4px;
+            border: 1px solid #ddd;
+            font-size: 16px;
+            margin-top: 10px;
+            box-sizing: border-box;
+        }
+        #send-button {
+            padding: 10px 15px;
+            border-radius: 4px;
+            background-color: #007BFF;
+            color: white;
+            border: none;
+            cursor: pointer;
+            margin-top: 10px;
+            width: 100%;
+        }
+        #send-button:hover {
+            background-color: #0056b3;
+        }
+
+        .model-select-container {
+            align-self: flex-start;
+            width: 100%;
+            display: flex;
+            justify-content: space-between;
+            padding: 1em;
+        }
+
+        .model-select-container label {
+            margin-left: 10px;
+        }
+
+        .message {
+            white-space: pre-wrap;
+            margin-bottom: 10px;
+            padding: 1em;
+            border-radius: 8px;
+            background-color: #f1f1f1;
+            display: block;
+            max-width: 100%;
+        }
+
+        .user-message {
+            background-color: #007BFF;
+            color: white;
+            text-align: right;
+            margin-left: 20px;
+        }
+
+        .bot-message {
+            background-color: #f0f0f0;
+            color: #333;
+            text-align: left;
+            margin-right: 20px;
+        }
+
+        @media (max-width: 600px) {
+            #chat-container {
+                max-height: 300px;
+            }
+        }
+
+        body.dark-mode {
+            background-color: #333;
+            color: #f7f7f7;
+        }
+
+        #chat-container.dark-mode {
+            background-color: #444;
+            border: 1px solid #555;
+        }
+
+        #user-input.dark-mode {
+            background-color: #555;
+            color: #f7f7f7;
+            border: 1px solid #666;
+        }
+
+        #send-button.dark-mode {
+            background-color: #007BFF;
+            color: white;
+        }
+
+        .message.dark-mode {
+            background-color: #555;
+            color: #f7f7f7;
+        }
+
+        .user-message.dark-mode {
+            background-color: #007BFF;
+            color: white;
+        }
+
+        .bot-message.dark-mode {
+            background-color: #666;
+            color: #f7f7f7;
+        }
+
+        .bot-time {
+            margin: 0.5em 0;
+            font-size: 0.9em;
+            color: #888;
+            text-align: center;
+        }
+        
+        /* Professional theme */
+        body.theme-professional {
+            font-family: Arial, sans-serif;
+            font-size: 22px;
+        }
+
+        /* Molly Millions theme */
+        body.theme-molly-millions {
+            font-family: "Courier New", monospace;
+            font-size: 22px;
+            margin: 0;
+            padding: 20px;
+            background-color: #0a0a0a;
+            color: #00ff00;
+            max-width: 800px;
+            margin: 0 auto;
+            display: flex;
+            flex-direction: column;
+            align-items: center;
+            height: 100vh;
+            overflow: hidden;
+        }
+
+        .theme-molly-millions #chat-container {
+            background-color: #000000;
+            border: 2px solid #00ff00;
+            border-radius: 0;
+            padding: 1em;
+            margin: 0 auto;
+            flex: 1;
+            overflow-y: auto;
+            width: 100%;
+            max-height: 400px;
+            scroll-behavior: smooth;
+            box-shadow: 0 0 10px #00ff00;
+        }
+
+        .theme-molly-millions #user-input {
+            width: 100%;
+            padding: 10px;
+            border-radius: 0;
+            border: 2px solid #00ff00;
+            background-color: #000000;
+            color: #00ff00;
+            font-family: "Courier New", monospace;
+            font-size: 16px;
+            margin-top: 10px;
+            box-sizing: border-box;
+        }
+
+        .theme-molly-millions #send-button {
+            padding: 10px 15px;
+            border-radius: 0;
+            background-color: #000000;
+            color: #00ff00;
+            border: 2px solid #00ff00;
+            cursor: pointer;
+            margin-top: 10px;
+            width: 100%;
+            font-family: "Courier New", monospace;
+            text-transform: uppercase;
+        }
+
+        .theme-molly-millions #send-button:hover {
+            background-color: #00ff00;
+            color: #000000;
+        }
+
+        .theme-molly-millions .message {
+            white-space: pre-wrap;
+            margin-bottom: 10px;
+            padding: 1em;
+            border-radius: 0;
+            border: 1px solid #00ff00;
+            background-color: #0a0a0a;
+            display: block;
+            max-width: 100%;
+        }
+
+        .theme-molly-millions .user-message {
+            background-color: #001100;
+            color: #00ff00;
+            border: 1px solid #00ff00;
+            text-align: right;
+            margin-left: 20px;
+        }
+
+        .theme-molly-millions .bot-message {
+            background-color: #000000;
+            color: #00ff00;
+            border: 1px solid #00ff00;
+            text-align: left;
+            margin-right: 20px;
+        }
+
+        .theme-molly-millions .bot-time {
+            color: #005500;
+        }
+
+        /* Cloud theme */
+        body.theme-cloud {
+            font-family: "Press Start 2P", "Courier New", monospace;
+            font-size: 18px;
+            margin: 0;
+            padding: 20px;
+            background: linear-gradient(135deg, #1a1b4b 0%, #162057 50%, #1a1b4b 100%);
+            color: #ffffff;
+            max-width: 800px;
+            margin: 0 auto;
+            display: flex;
+            flex-direction: column;
+            align-items: center;
+            height: 100vh;
+            overflow: hidden;
+        }
+
+        .theme-cloud #chat-container {
+            background: rgba(0, 0, 32, 0.75);
+            border: 3px solid #4080ff;
+            border-radius: 3px;
+            padding: 1em;
+            margin: 0 auto;
+            flex: 1;
+            overflow-y: auto;
+            width: 100%;
+            max-height: 400px;
+            scroll-behavior: smooth;
+            box-shadow: 0 0 15px rgba(64, 128, 255, 0.3);
+        }
+
+        .theme-cloud #user-input {
+            width: 100%;
+            padding: 10px;
+            border: 2px solid #4080ff;
+            background: rgba(0, 0, 32, 0.75);
+            color: #ffffff;
+            font-family: "Press Start 2P", "Courier New", monospace;
+            font-size: 14px;
+            margin-top: 10px;
+            box-sizing: border-box;
+        }
+
+        .theme-cloud #send-button {
+            padding: 10px 15px;
+            background: linear-gradient(to bottom, #4080ff 0%, #2048c0 100%);
+            color: white;
+            border: 2px solid #2048c0;
+            cursor: pointer;
+            margin-top: 10px;
+            width: 100%;
+            font-family: "Press Start 2P", "Courier New", monospace;
+            font-size: 14px;
+            text-transform: uppercase;
+            text-shadow: 2px 2px #000000;
+        }
+
+        .theme-cloud #send-button:hover {
+            background: linear-gradient(to bottom, #50a0ff 0%, #3060e0 100%);
+        }
+
+        .theme-cloud .message {
+            white-space: pre-wrap;
+            margin-bottom: 10px;
+            padding: 1em;
+            border: 2px solid #4080ff;
+            background: rgba(0, 0, 32, 0.5);
+            display: block;
+            max-width: 100%;
+            font-size: 14px;
+        }
+
+        .theme-cloud .user-message {
+            background: rgba(64, 128, 255, 0.2);
+            color: #ffffff;
+            border: 2px solid #4080ff;
+            text-align: right;
+            margin-left: 20px;
+            text-shadow: 1px 1px #000000;
+        }
+
+        .theme-cloud .bot-message {
+            background: rgba(32, 64, 128, 0.2);
+            color: #ffffff;
+            border: 2px solid #4080ff;
+            text-align: left;
+            margin-right: 20px;
+            text-shadow: 1px 1px #000000;
+        }
+
+        .theme-cloud .bot-time {
+            color: #80c0ff;
+            font-size: 12px;
+            text-shadow: 1px 1px #000000;
+        }
+
+        .theme-cloud #counter {
+            color: #80c0ff !important;
+            text-shadow: 1px 1px #000000;
+        }
+
+        .theme-cloud .model-select-container {
+            background: rgba(0, 0, 32, 0.75);
+            border: 2px solid #4080ff;
+            padding: 10px;
+            margin-bottom: 10px;
+            width: 100%;
+            box-sizing: border-box;
+        }
+
+        .theme-cloud #model-select {
+            background: rgba(0, 0, 32, 0.75);
+            color: #ffffff;
+            border: 1px solid #4080ff;
+            padding: 5px;
+            font-family: "Press Start 2P", "Courier New", monospace;
+            font-size: 12px;
+        }
+
+        /* Classic Mac theme */
+        @font-face {
+            font-family: 'ChicagoFLF';
+            src: url('/ChicagoFLF.ttf') format('truetype');
+        }
+
+        body.theme-classic {
+            font-family: 'ChicagoFLF', 'Monaco', monospace;
+            font-size: 14px;
+            margin: 0;
+            padding: 20px;
+            background-color: #DDDDDD;
+            color: #000000;
+            max-width: 800px;
+            margin: 0 auto;
+            display: flex;
+            flex-direction: column;
+            align-items: center;
+            height: 100vh;
+            overflow: hidden;
+            image-rendering: pixelated;
+        }
+
+        .theme-classic #chat-container {
+            background-color: #FFFFFF;
+            border: 2px solid #000000;
+            border-radius: 2px;
+            padding: 1em;
+            margin: 0 auto;
+            flex: 1;
+            overflow-y: auto;
+            width: 100%;
+            max-height: 400px;
+            scroll-behavior: smooth;
+            box-shadow: 2px 2px 0px #000000;
+        }
+
+        .theme-classic #user-input {
+            width: 100%;
+            padding: 8px;
+            border: 2px solid #000000;
+            background-color: #FFFFFF;
+            color: #000000;
+            font-family: 'ChicagoFLF', 'Monaco', monospace;
+            font-size: 14px;
+            margin-top: 10px;
+            box-sizing: border-box;
+            border-radius: 2px;
+        }
+
+        .theme-classic #send-button {
+            padding: 4px 15px;
+            background-color: #FFFFFF;
+            color: #000000;
+            border: 2px solid #000000;
+            border-radius: 2px;
+            cursor: pointer;
+            margin-top: 10px;
+            width: 100%;
+            font-family: 'ChicagoFLF', 'Monaco', monospace;
+            font-size: 14px;
+            box-shadow: 2px 2px 0px #000000;
+        }
+
+        .theme-classic #send-button:hover {
+            background-color: #000000;
+            color: #FFFFFF;
+        }
+
+        .theme-classic #send-button:active {
+            box-shadow: 1px 1px 0px #000000;
+            transform: translate(1px, 1px);
+        }
+
+        .theme-classic .message {
+            white-space: pre-wrap;
+            margin-bottom: 10px;
+            padding: 8px;
+            border: 2px solid #000000;
+            background-color: #FFFFFF;
+            display: block;
+            max-width: 100%;
+            font-size: 14px;
+            border-radius: 2px;
+        }
+
+        .theme-classic .user-message {
+            background-color: #FFFFFF;
+            color: #000000;
+            text-align: right;
+            margin-left: 20px;
+            box-shadow: 2px 2px 0px #000000;
+        }
+
+        .theme-classic .bot-message {
+            background-color: #FFFFFF;
+            color: #000000;
+            text-align: left;
+            margin-right: 20px;
+            box-shadow: 2px 2px 0px #000000;
+        }
+
+        .theme-classic .bot-time {
+            color: #666666;
+            font-size: 12px;
+            text-align: center;
+            margin: 4px 0;
+        }
+
+        .theme-classic #counter {
+            color: #000000 !important;
+        }
+
+        .theme-classic .model-select-container {
+            background-color: #FFFFFF;
+            border: 2px solid #000000;
+            padding: 8px;
+            margin-bottom: 10px;
+            width: 100%;
+            box-sizing: border-box;
+            border-radius: 2px;
+            box-shadow: 2px 2px 0px #000000;
+        }
+
+        .theme-classic #model-select {
+            background-color: #FFFFFF;
+            color: #000000;
+            border: 2px solid #000000;
+            padding: 2px;
+            font-family: 'ChicagoFLF', 'Monaco', monospace;
+            font-size: 14px;
+            border-radius: 2px;
+        }
+
+        .theme-classic input[type="checkbox"] {
+            appearance: none;
+            -webkit-appearance: none;
+            width: 16px;
+            height: 16px;
+            border: 2px solid #000000;
+            background-color: #FFFFFF;
+            position: relative;
+            vertical-align: middle;
+            margin-right: 5px;
+        }
+
+        .theme-classic input[type="checkbox"]:checked::after {
+            content: '✓';
+            position: absolute;
+            left: 1px;
+            top: -2px;
+            font-size: 14px;
+        }
+
+        /* LCARS Theme */
+        body.theme-lcars {
+            font-family: "Helvetica Neue", Arial, sans-serif;
+            font-size: 18px;
+            margin: 0;
+            padding: 20px;
+            background-color: #000;
+            color: #FF9966;
+            max-width: 800px;
+            margin: 0 auto;
+            display: flex;
+            flex-direction: column;
+            align-items: center;
+            height: 100vh;
+            overflow: hidden;
+        }
+
+        .theme-lcars #chat-container {
+            background-color: #000;
+            border: none;
+            border-radius: 0;
+            padding: 1em;
+            margin: 0 auto;
+            flex: 1;
+            overflow-y: auto;
+            width: 100%;
+            max-height: 400px;
+            scroll-behavior: smooth;
+            position: relative;
+        }
+
+        .theme-lcars #chat-container::before {
+            content: '';
+            position: absolute;
+            top: 0;
+            left: 0;
+            right: 0;
+            height: 2em;
+            background: #CC6699;
+            border-radius: 20px 20px 0 0;
+        }
+
+        .theme-lcars #user-input {
+            width: 100%;
+            padding: 10px;
+            border: none;
+            background-color: #000;
+            color: #FF9966;
+            font-family: "Helvetica Neue", Arial, sans-serif;
+            font-size: 16px;
+            margin-top: 10px;
+            box-sizing: border-box;
+            border-left: 2em solid #CC6699;
+        }
+
+        .theme-lcars #send-button {
+            padding: 10px 15px;
+            background-color: #CC6699;
+            color: #000;
+            border: none;
+            cursor: pointer;
+            margin-top: 10px;
+            width: 100%;
+            font-family: "Helvetica Neue", Arial, sans-serif;
+            font-weight: bold;
+            font-size: 16px;
+            text-transform: uppercase;
+            border-radius: 0 0 20px 20px;
+        }
+
+        .theme-lcars #send-button:hover {
+            background-color: #FF9966;
+        }
+
+        .theme-lcars .message {
+            white-space: pre-wrap;
+            margin-bottom: 10px;
+            padding: 1em;
+            border: none;
+            display: block;
+            max-width: 100%;
+            position: relative;
+        }
+
+        .theme-lcars .user-message {
+            background-color: #000;
+            color: #FF9966;
+            text-align: right;
+            margin-left: 20px;
+            border-right: 1em solid #CC6699;
+        }
+
+        .theme-lcars .bot-message {
+            background-color: #000;
+            color: #99CCFF;
+            text-align: left;
+            margin-right: 20px;
+            border-left: 1em solid #9999CC;
+        }
+
+        .theme-lcars .bot-time {
+            color: #CC6699;
+            font-size: 0.8em;
+            text-align: center;
+            margin: 4px 0;
+        }
+
+        .theme-lcars #counter {
+            color: #99CCFF !important;
+        }
+
+        .theme-lcars .model-select-container {
+            background-color: #000;
+            border: none;
+            padding: 10px;
+            margin-bottom: 10px;
+            width: 100%;
+            box-sizing: border-box;
+            display: flex;
+            align-items: center;
+            border-radius: 20px;
+            position: relative;
+            overflow: hidden;
+        }
+
+        .theme-lcars .model-select-container::before {
+            content: '';
+            position: absolute;
+            top: 0;
+            left: 0;
+            bottom: 0;
+            width: 2em;
+            background: #9999CC;
+            border-radius: 20px 0 0 20px;
+        }
+
+        .theme-lcars #model-select {
+            background-color: #000;
+            color: #FF9966;
+            border: none;
+            padding: 5px;
+            margin-left: 3em;
+            font-family: "Helvetica Neue", Arial, sans-serif;
+            font-size: 16px;
+        }
+
+        .theme-lcars input[type="checkbox"] {
+            appearance: none;
+            -webkit-appearance: none;
+            width: 16px;
+            height: 16px;
+            border: 2px solid #CC6699;
+            background-color: #000;
+            position: relative;
+            vertical-align: middle;
+            margin-right: 5px;
+        }
+
+        .theme-lcars input[type="checkbox"]:checked {
+            background-color: #CC6699;
+        }
+
+        .theme-lcars input[type="checkbox"]:checked::after {
+            content: '✓';
+            position: absolute;
+            left: 2px;
+            top: -2px;
+            color: #000;
+            font-size: 14px;
+        }
+    </style>
+</head>
+<body>
+
+    <div class="model-select-container">
+        <select id="model-select"></select>
+        <label>
+            <input type="checkbox" id="retain-history" /> Build Context As You Chat?
+        </label>
+    </div>
+    
+    <div id="chat-container">
+        <!-- Messages will appear here -->
+    </div>
+
+    <!-- New container for user input and send button -->
+    <div id="input-container" style="width: 100%; display: flex; flex-direction: column; margin-top: 10px;">
+        <div id="counter" style="text-align: left; font-size: 0.9em; color: #555;">
+            Characters: <span id="char-count">0</span> | Words: <span id="word-count">0</span>
+        </div>
+        <textarea id="user-input" placeholder="Type your message..."></textarea>
+        <button id="send-button">Send</button>
+    </div>
+
+    <script>
+        // ==================================================
+        // MATT CHAT IS NOT A CAT
+        // This is a simple chat interface for the Ollama API
+        // ==================================================
+        //
+        // This configuration object is used to define all local variables for your needs
+        // Set the base url for the ollama api, and then list all the models you want to use
+        // The context window size is the number of previous exchanges to keep...
+        // though this is relatively naive at the moment
+
+        const config = {}
+
+        const localConfig = {
+            apiUrl: "http://localhost:11434/v1",
+            completionsEndpoint: "http://localhost:11434/v1/chat/completions",
+            modelsEndpoint: "http://localhost:11434/v1/models",
+            contextWindowSize: 6,
+            systemMessage: "You are a helpful assistant. If you don't know something you'll let me know. Your name is Matt.",
+            maxTokens: 4096,
+            summarizeThreshold: 3584,
+        };
+
+        const mattConfig = {
+            apiUrl: "http://100.108.91.106:11434/v1",
+            completionsEndpoint: "http://100.108.91.106:11434/v1/chat/completions",
+            modelsEndpoint: "http://100.108.91.106:11434/v1/models",
+            contextWindowSize: 6,
+            systemMessage: "You are a helpful assistant. If you don't know something you'll let me know. Your name is Matt.",
+            maxTokens: 4096,
+            summarizeThreshold: 3584,
+        }
+
+        let conversationHistory = {
+            summary: null,
+            current: [],
+            full: []
+        };
+
+        let isCatMode = false; // Flag to track cat mode
+
+        const API_MODELS_ENDPOINT = config.modelsEndpoint;
+
+        // Add this near the top with other constants
+        const AVAILABLE_THEMES = {
+            'professional': 'Professional -- boring, like wearing a tie',
+            'molly-millions': 'Molly Millions\' manicure',
+            'cloud': 'Cloud -- it took a lot of self control not to add sound effects',
+            'classic': 'Classic -- this is not a fish',
+            'lcars': 'LCARS -- boldly going'
+        };
+
+        function handleError(message) {
+            console.error(message);
+            addMessage(message, "bot");
+        }
+
+        function showLoadingMessage() {
+            return addMessage("Loading models...", "bot");
+        }
+
+        async function populateModelSelect() {
+            const modelSelect = document.getElementById("model-select");
+            modelSelect.innerHTML = ""; // Clear existing options
+
+            const loadingMessage = showLoadingMessage();
+            const modelIds = [];
+
+            try {
+                const response = await fetch(config.modelsEndpoint);
+                if (!response.ok) throw new Error('Failed to fetch models');
+
+                const data = await response.json();
+                console.log("API Response:", data);
+
+                if (Array.isArray(data.data)) {
+                    data.data.forEach(model => {
+                        const option = document.createElement("option");
+                        option.value = model.id;
+                        option.textContent = model.id;
+                        modelSelect.appendChild(option);
+                        modelIds.push(model.id);
+                    });
+                    console.log("Model IDs:", modelIds);
+                } else {
+                    handleError("Expected an array of models, but got: " + JSON.stringify(data));
+                }
+            } catch (error) {
+                handleError("Error fetching models: " + error.message);
+            } finally {
+                loadingMessage.remove();
+                if (modelIds.length > 0) {
+                    addMessage(`Models loaded successfully! Ready to chat.\n\nAvailable models: ${modelIds.join(', ')}`, "bot");
+                } else {
+                    addMessage("No models available to chat.", "bot");
+                }
+            }
+        }
+
+        document.addEventListener("DOMContentLoaded", () => {
+            populateModelSelect();
+            const modelSelect = document.getElementById("model-select");
+            const savedModel = localStorage.getItem("selectedModel");
+            if (savedModel) {
+                modelSelect.value = savedModel;
+            }
+            modelSelect.addEventListener("change", () => {
+                localStorage.setItem("selectedModel", modelSelect.value);
+            });
+            const savedTheme = localStorage.getItem('selectedTheme') || 'professional';
+            switchTheme(savedTheme);
+        });
+
+        function addMessage(message, sender = "user") {
+            const chatContainer = document.getElementById("chat-container");
+            const messageElement = document.createElement("div");
+            messageElement.classList.add("message", sender === "user" ? "user-message" : "bot-message");
+            messageElement.textContent = message;
+            chatContainer.appendChild(messageElement);
+            messageElement.scrollIntoView({ behavior: "smooth", block: "end" });
+            chatContainer.scrollTop = chatContainer.scrollHeight; // Make sure the chat is scrolled to the bottom
+            return messageElement; // Return the message element so it is easier to use
+        }
+
+        // Fancy format milliseconds into a more readable format
+        function formatDuration(duration) {
+            const minutes = Math.floor(duration / (1000 * 60));
+            const seconds = Math.floor((duration % (1000 * 60)) / 1000);
+            const milliseconds = duration % 1000;
+            
+            if (minutes > 0) {
+                return `${minutes}m ${seconds}.${Math.floor(milliseconds / 10)}s`;
+            }
+            return `${seconds}.${Math.floor(milliseconds / 10)}s`;
+        }
+
+        // Character and word counter
+        function updateCounter() {
+            const userInput = document.getElementById("user-input");
+            const charCount = document.getElementById("char-count");
+            const wordCount = document.getElementById("word-count");
+
+            const text = userInput.value;
+            const characters = text.length;
+            const words = text.trim() ? text.trim().split(/\s+/).length : 0; // Count words
+
+            charCount.textContent = characters;
+            wordCount.textContent = words;
+        }
+
+        // Event listener to update the counter on input
+        document.getElementById("user-input").addEventListener("input", updateCounter);
+
+        function toggleCatMode() {
+            isCatMode = !isCatMode; // Toggle the flag
+            if (isCatMode) {
+                config.systemMessage += " You are a cat."; // Append the phrase
+            } else {
+                config.systemMessage = config.systemMessage.replace(" You are a large, fluffy cat. You are a little aloof, but kind.", ""); // Remove the phrase
+            }
+            addMessage(`Cat mode is now ${isCatMode ? "enabled" : "disabled"}.`, "bot"); // Inform the user
+        }
+
+        async function sendMessage() {
+            const userInput = document.getElementById("user-input");
+            const userMessage = userInput.value.trim();
+
+            if (!userMessage) return;
+
+            // Check for slash commands
+            if (userMessage.toLowerCase() === '/dark' || userMessage.toLowerCase() === '/darkmode') {
+                toggleDarkMode();
+                userInput.value = ""; // Clear input after command
+                updateCounter(); // Reset counters
+                return;
+            }
+
+            if (userMessage.toLowerCase() === '/clear') {
+                clearChat();
+                userInput.value = ""; // Clear input after command
+                updateCounter(); // Reset counters
+                return;
+            }
+
+            if (userMessage.toLowerCase() === '/help') {
+                displayHelp();
+                userInput.value = ""; // Clear input after command
+                updateCounter(); // Reset counters
+                return;
+            }
+
+            if (userMessage.toLowerCase() === '/cat' || userMessage.toLowerCase() === '/catmode') {
+                toggleCatMode(); // Toggle cat mode
+                userInput.value = ""; // Clear input after command
+                updateCounter(); // Reset counters
+                return;
+            }
+
+            if (userMessage.toLowerCase() === '/context') {
+                const context = viewCurrentContext();
+                addMessage(`Current conversation has ${context.currentMessages} messages\nEstimated tokens: ${context.estimatedTokens}`, "bot");
+                return;
+            }
+
+            if (userMessage.toLowerCase().startsWith('/theme')) {
+                const requestedTheme = userMessage.toLowerCase().split(' ')[1];
+                if (!requestedTheme) {
+                    // If no theme is specified, lets show all available themes
+                    addMessage(`Available themes: ${Object.keys(AVAILABLE_THEMES).join(', ')}`, "bot");
+                } else if (AVAILABLE_THEMES[requestedTheme]) {
+                    switchTheme(requestedTheme);
+                } else {
+                    addMessage(`Unknown theme. Available themes: ${Object.keys(AVAILABLE_THEMES).join(', ')}`, "bot");
+                }
+                userInput.value = "";
+                updateCounter();
+                return;
+            }
+
+            if (userMessage.toLowerCase() === '/matt') {
+                Object.assign(config, mattConfig);
+                addMessage("Switched to Matt's config", "bot");
+                userInput.value = "";
+                updateCounter();
+                populateModelSelect(); // Refresh the model list for the new endpoint
+                return;
+            }
+
+            if (userMessage.toLowerCase() === '/local') {
+                Object.assign(config, localConfig);
+                addMessage("Switched to local config", "bot");
+                userInput.value = "";
+                updateCounter();
+                populateModelSelect(); // Refresh the model list for the new endpoint
+                return;
+            }
+
+            addMessage(userMessage, "user");
+            userInput.value = ""; // Clear input after sending the message
+            
+            // Reset the counter
+            document.getElementById("char-count").textContent = "0";
+            document.getElementById("word-count").textContent = "0";
+
+            // Create and add loading indicator
+            const loadingIndicator = document.createElement("div");
+            loadingIndicator.id = "loading-indicator";
+            loadingIndicator.classList.add("message", "bot-message");
+            loadingIndicator.textContent = "...";
+            document.getElementById("chat-container").appendChild(loadingIndicator);
+            scrollToBottom();
+
+            // Start animation for this specific indicator
+            const animationInterval = animateLoadingIndicator(loadingIndicator);
+
+            const startTime = Date.now(); // Capture the start time
+
+            try {
+                const modelSelect = document.getElementById("model-select");
+                const selectedModel = modelSelect.value;
+                const retainHistory = document.getElementById("retain-history").checked; // Check the checkbox state
+
+                // Prepare the messages for the API
+                const messagesToSend = await prepareMessages(userMessage);
+
+                const response = await fetch(config.completionsEndpoint, {
+                    method: "POST",
+                    headers: {
+                        "Content-Type": "application/json",
+                    },
+                    body: JSON.stringify({
+                        model: selectedModel,
+                        messages: messagesToSend,
+                    }),
+                });
+
+                if (!response.ok) {
+                    throw new Error('Error communicating with Ollama API');
+                }
+
+                const data = await response.json();
+                console.log("API Response:", data);
+
+                if (data.choices && data.choices.length > 0) {
+                    const botResponse = data.choices[0].message.content;
+                    
+                    // Clear loading indicator
+                    clearInterval(animationInterval);
+                    loadingIndicator.remove();
+                    
+                    // Add bot's response to chat and history
+                    addMessage(botResponse, "bot");
+                    conversationHistory.current.push({ role: "assistant", content: botResponse });
+
+                    // Calculate and display duration
+                    const duration = Date.now() - startTime;
+                    const timeTakenMessage = formatDuration(duration);
+                    const timeDisplay = document.createElement("div");
+                    timeDisplay.classList.add("bot-time");
+                    timeDisplay.textContent = `Response time: ${timeTakenMessage}`;
+                    document.getElementById("chat-container").appendChild(timeDisplay);
+                    scrollToBottom();
+
+                } else {
+                    console.error("No response from API");
+                    loadingIndicator.remove();
+                    addMessage("Sorry, I didn't get a response from the assistant.", "bot");
+                }
+
+                if (conversationHistory.current.length > 10) {
+                    conversationHistory.current.shift(); // Remove the oldest message
+                }
+
+            } catch (error) {
+                console.error("Error:", error);
+                clearInterval(animationInterval);
+                loadingIndicator.remove();
+                addMessage("Sorry, there was an error processing your request.", "bot");
+            }
+        }
+
+        function animateLoadingIndicator(indicator) {
+            let dots = 0;
+            return setInterval(() => {
+                dots = (dots + 1) % 6;
+                if (indicator && document.contains(indicator)) {
+                    indicator.textContent = '.'.repeat(dots || 1);
+                }
+            }, 500);
+        }
+
+        document.getElementById("send-button").addEventListener("click", sendMessage);
+
+        document.getElementById("user-input").addEventListener("keypress", function (e) {
+            if (e.key === "Enter") {
+                e.preventDefault(); // Prevent line break
+                sendMessage();
+            }
+        });
+
+        function toggleDarkMode() {
+            const body = document.body;
+            const chatContainer = document.getElementById("chat-container");
+            const userInput = document.getElementById("user-input");
+            const sendButton = document.getElementById("send-button");
+
+            body.classList.toggle("dark-mode");
+            chatContainer.classList.toggle("dark-mode");
+            userInput.classList.toggle("dark-mode");
+            sendButton.classList.toggle("dark-mode");
+
+            // Update message classes
+            const messages = document.querySelectorAll(".message");
+            messages.forEach(message => {
+                message.classList.toggle("dark-mode");
+            });
+
+            // Save preference to local storage
+            const isDarkMode = body.classList.contains("dark-mode");
+            localStorage.setItem("darkMode", isDarkMode);
+        }
+
+        // Load dark mode preference from local storage on page load
+        document.addEventListener("DOMContentLoaded", () => {
+            const darkModePreference = localStorage.getItem("darkMode");
+            if (darkModePreference === "true") {
+                toggleDarkMode(); // Activate dark mode if preference is set
+            }
+        });
+
+        function clearChat() {
+            const chatContainer = document.getElementById("chat-container");
+            chatContainer.innerHTML = "";
+            conversationHistory = {
+                summary: null,
+                current: [],
+                full: []
+            };
+        }
+
+        function displayHelp() {
+            const helpMessage = `
+Available commands:\n
+  /dark - Toggle dark mode when using the professional theme
+  /cat - Toggle cat mode
+  /context - Show the current conversation's context
+  /clear - Clear the chat history
+  /help - Show this message
+  /theme [theme-name] - Switch theme (available themes: ${Object.keys(AVAILABLE_THEMES).join(', ')})
+      without a theme name, this will show all available themes, too
+  /local - Switch to local Ollama instance
+  /matt - Switch to Matt's Ollama instance
+            `;
+            addMessage(helpMessage, "bot");
+        }
+
+        function estimateTokens(text) {
+            // Rough estimation: ~4 chars per token for English text
+            return Math.ceil(text.length / 4);
+        }
+
+        function getContextSize(messages) {
+            return messages.reduce((sum, msg) => sum + estimateTokens(msg.content), 0);
+        }
+
+        async function summarizeConversation(messages) {
+            try {
+                const modelSelect = document.getElementById("model-select");
+                const selectedModel = modelSelect.value;
+
+                const response = await fetch(config.completionsEndpoint, {
+                    method: "POST",
+                    headers: {
+                        "Content-Type": "application/json",
+                    },
+                    body: JSON.stringify({
+                        model: selectedModel,
+                        messages: messages,
+                    }),
+                });
+
+                const data = await response.json();
+                return data.choices[0].message.content;
+            } catch (error) {
+                console.error("Error summarizing conversation:", error);
+                return null;
+            }
+        }
+
+        async function prepareMessages(userMessage) {
+            const messages = [];
+            
+            // Always start with system message
+            messages.push({ role: "system", content: config.systemMessage });
+            
+            if (document.getElementById("retain-history").checked) {
+                // If we have a summary, add it more naturally
+                if (conversationHistory.summary) {
+                    messages.push({
+                        role: "system",
+                        content: `Previous discussion: ${conversationHistory.summary}`
+                    });
+                }
+                
+                // Add current conversation segment
+                messages.push(...conversationHistory.current);
+            }
+            
+            // Add the new message to history before we check for summarization
+            const newMessage = { role: "user", content: userMessage };
+            conversationHistory.current.push(newMessage);
+            messages.push(newMessage);
+            
+            // Do we need to summarize?
+            const totalTokens = getContextSize(messages);
+            if (totalTokens > config.summarizeThreshold) {
+                // Move current messages to full history, except for the newest message
+                conversationHistory.full.push(...conversationHistory.current.slice(0, -1));
+                
+                // Supposedly this is a more natural summarization prompt...
+                const summary = await summarizeConversation([
+                    {
+                        role: "system",
+                        content: "Summarize this conversation's key points and context that would be important for continuing the discussion naturally. Be concise but maintain essential details."
+                    },
+                    ...conversationHistory.full
+                ]);
+                
+                if (summary) {
+                    conversationHistory.summary = summary;
+                    // Keep only the most recent messages for immediate context
+                    conversationHistory.current = conversationHistory.current.slice(-4);
+                    
+                    // Rebuild messages array with new summary
+                    return [
+                        { role: "system", content: config.systemMessage },
+                        { role: "system", content: `Previous discussion: ${summary}` },
+                        ...conversationHistory.current
+                    ];
+                }
+            }
+            
+            return messages;
+        }
+
+        // Clean up old messages periodically
+        function pruneConversationHistory() {
+            if (conversationHistory.full.length > 100) {
+                // Keep only the last 100 messages in full history
+                conversationHistory.full = conversationHistory.full.slice(-100);
+            }
+        }
+
+        // Call this after successful responses
+        setInterval(pruneConversationHistory, 60000); // Clean up every minute
+
+        function viewCurrentContext() {
+            const context = {
+                summary: conversationHistory.summary,
+                currentMessages: conversationHistory.current.length,
+                fullHistoryMessages: conversationHistory.full.length,
+                estimatedTokens: getContextSize(conversationHistory.current)
+            };
+            console.log("Current Context:", context);
+            return context;
+        }
+
+        function scrollToBottom() {
+            const chatContainer = document.getElementById("chat-container");
+            chatContainer.scrollTop = chatContainer.scrollHeight;
+        }
+
+        function switchTheme(themeName) {
+            // Remove all theme classes
+            Object.keys(AVAILABLE_THEMES).forEach(theme => {
+                document.body.classList.remove(`theme-${theme}`);
+            });
+            
+            // Add the new theme class
+            document.body.classList.add(`theme-${themeName}`);
+            
+            // Update meta theme-color
+            const metaThemeColor = document.querySelector('meta[name="theme-color"]');
+            if (metaThemeColor) {
+                switch(themeName) {
+                    case 'molly-millions':
+                        metaThemeColor.setAttribute('content', '#00ff00');
+                        break;
+                    case 'cloud':
+                        metaThemeColor.setAttribute('content', '#4080ff');
+                        break;
+                    case 'classic':
+                        metaThemeColor.setAttribute('content', '#DDDDDD');
+                        break;
+                    case 'lcars':
+                        metaThemeColor.setAttribute('content', '#CC6699');
+                        break;
+                    case 'professional':
+                    default:
+                        metaThemeColor.setAttribute('content', '#007BFF');
+                        break;
+                }
+            }
+            
+            localStorage.setItem('selectedTheme', themeName);            
+            addMessage(`Theme switched to: ${AVAILABLE_THEMES[themeName]}`, "bot");
+        }
+
+        // Initialize with localConfig
+        Object.assign(config, localConfig);
+    </script>
+</body>
+</html>
diff --git a/html/matt-chat/pokemon.js b/html/matt-chat/pokemon.js
new file mode 100644
index 0000000..e707e7b
--- /dev/null
+++ b/html/matt-chat/pokemon.js
@@ -0,0 +1,157 @@
+// Pokemon API functionality using functional programming approach
+
+// Base URL for the PokeAPI
+const POKE_API_BASE = 'https://pokeapi.co/api/v2';
+
+// Utility function to fetch data from the API
+const fetchPokeData = async (endpoint) => {
+    try {
+        const response = await fetch(`${POKE_API_BASE}${endpoint}`);
+        if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
+        return await response.json();
+    } catch (error) {
+        console.error('Error fetching Pokemon data:', error);
+        throw error;
+    }
+};
+
+// Function to get Pokemon basic info
+const getPokemonInfo = async (pokemonName) => {
+    try {
+        const data = await fetchPokeData(`/pokemon/${pokemonName.toLowerCase()}`);
+        return {
+            name: data.name,
+            id: data.id,
+            types: data.types.map(type => type.type.name),
+            abilities: data.abilities.map(ability => ({
+                name: ability.ability.name,
+                isHidden: ability.is_hidden
+            })),
+            stats: data.stats.map(stat => ({
+                name: stat.stat.name,
+                value: stat.base_stat
+            })),
+            height: data.height / 10, // Convert to meters
+            weight: data.weight / 10, // Convert to kilograms
+            sprite: data.sprites.front_default
+        };
+    } catch (error) {
+        throw new Error(`Could not find Pokemon: ${pokemonName}`);
+    }
+};
+
+// Function to get ability details
+const getAbilityInfo = async (abilityName) => {
+    try {
+        const data = await fetchPokeData(`/ability/${abilityName.toLowerCase()}`);
+        return {
+            name: data.name,
+            effect: data.effect_entries.find(e => e.language.name === 'en')?.effect || 'No effect description available.',
+            pokemon: data.pokemon.map(p => p.pokemon.name)
+        };
+    } catch (error) {
+        throw new Error(`Could not find ability: ${abilityName}`);
+    }
+};
+
+// Function to get move details
+const getMoveInfo = async (moveName) => {
+    try {
+        const data = await fetchPokeData(`/move/${moveName.toLowerCase()}`);
+        return {
+            name: data.name,
+            type: data.type.name,
+            power: data.power,
+            accuracy: data.accuracy,
+            pp: data.pp,
+            effect: data.effect_entries.find(e => e.language.name === 'en')?.effect || 'No effect description available.'
+        };
+    } catch (error) {
+        throw new Error(`Could not find move: ${moveName}`);
+    }
+};
+
+const getEvolutionInfo = async (pokemonName) => {
+    const data = await fetchPokeData(`/pokemon-species/${pokemonName.toLowerCase()}`);
+    return data.evolution_chain;
+};
+
+// Function to format Pokemon info into a readable message
+const formatPokemonInfo = (info) => {
+    const spriteImage = info.sprite ? `<img src="${info.sprite}" alt="${info.name} sprite" style="width: 100px; height: auto;" />` : '';
+    return `
+🔍 Pokemon: ${info.name.toUpperCase()} (#${info.id})
+📊 Types: ${info.types.join(', ')}
+💪 Abilities: ${info.abilities.map(a => `${a.name}${a.isHidden ? ' (Hidden)' : ''}`).join(', ')}
+📈 Stats:
+${info.stats.map(s => `  ${s.name}: ${s.value}`).join('\n')}
+📏 Height: ${info.height}m
+⚖️ Weight: ${info.weight}kg
+${spriteImage}
+    `.trim();
+};
+
+// Function to format ability info into a readable message
+const formatAbilityInfo = (info) => {
+    return `
+🔰 Ability: ${info.name.toUpperCase()}
+📝 Effect: ${info.effect}
+✨ Pokemon with this ability: ${info.pokemon.join(', ')}
+    `.trim();
+};
+
+// Function to format move info into a readable message
+const formatMoveInfo = (info) => {
+    return `
+⚔️ Move: ${info.name.toUpperCase()}
+🎯 Type: ${info.type}
+💥 Power: ${info.power || 'N/A'}
+🎲 Accuracy: ${info.accuracy || 'N/A'}
+🔄 PP: ${info.pp}
+📝 Effect: ${info.effect}
+    `.trim();
+};
+
+const formatEvolutionInfo = (info) => {
+    return `
+🔗 Evolution Chain: ${info.name.toUpperCase()}
+    `.trim();
+};
+
+// Main handler for Pokemon commands
+const handlePokemonCommand = async (args) => {
+    if (!args.length) {
+        return "Usage: /pokemon [pokemon|ability|move] [name]";
+    }
+
+    const [type, ...nameArgs] = args;
+    const name = nameArgs.join(' ').replace(/\s+/g, '-'); // Replace spaces with hyphens
+
+    if (!name) {
+        return "Please provide a name to search for.";
+    }
+
+    try {
+        switch (type.toLowerCase()) {
+            case 'pokemon':
+                const pokemonInfo = await getPokemonInfo(name);
+                return formatPokemonInfo(pokemonInfo);
+            case 'ability':
+                const abilityInfo = await getAbilityInfo(name);
+                return formatAbilityInfo(abilityInfo);
+            case 'move':
+                const moveInfo = await getMoveInfo(name);
+                return formatMoveInfo(moveInfo);
+            case 'evolution-chain':
+                const evolutionInfo = await getEvolutionInfo(name);
+                return formatEvolutionInfo(evolutionInfo);
+            default:
+                return "Invalid type. Use: pokemon, ability, or move.";
+        }
+    } catch (error) {
+        return `Error: ${error.message}`;
+    }
+};
+
+// Export the handler for use in main application
+export { handlePokemonCommand }; 
\ No newline at end of file
diff --git a/html/matt-chat/server.sh b/html/matt-chat/server.sh
new file mode 100755
index 0000000..b294acd
--- /dev/null
+++ b/html/matt-chat/server.sh
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+# check that the ollama server is running, if it isn't, start it in the background and continue with the script
+if ! pgrep -f ollama; then
+    ollama start &
+fi
+
+# check that port 38478 is free
+if lsof -i :38478; then
+    echo "Port 38478 is already in use. Please choose a different port."
+    exit 1
+fi
+
+# Start a simple HTTP server using Python on port 38478 and run it in the background
+python3 -m http.server 38478 &
+
+
+#   nvim ~/Library/LaunchAgents/com.user.server.plist
+#   cp com.user.server.plist ~/Library/LaunchAgents/
+#   launchctl load ~/Library/LaunchAgents/com.user.server.plist
+#   launchctl start com.user.server
+#   launchctl list | grep com.user.server
+#   launchctl unload ~/Library/LaunchAgents/com.user.server.plist
\ No newline at end of file