diff --git a/.gitignore b/.gitignore
index 5594482..4578766 100644
--- a/.gitignore
+++ b/.gitignore
@@ -76,3 +76,4 @@ vars.fish
blog-multi-mower/
webwords/
+venv/
diff --git a/CLAUDE.md b/CLAUDE.md
index 57b3aaa..5ebb674 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -1,5 +1,58 @@
# Claude Memory and Instructions
+## RUSSELL BALLESTRINI - KNOW THE USER
+
+Russell Ballestrini is:
+- Experienced systems administrator and DevOps engineer
+- Python developer and technical blogger
+- Creator of webwords project (42 programming languages)
+- Uses direct, no-nonsense communication style
+- Expects technical precision and working code
+- Does not tolerate broken implementations or untested commits
+
+## CRITICAL PELICAN TESTING WORKFLOW
+
+### BEFORE ANY COMMIT:
+1. **ALWAYS test Pelican build**: `make clean && make html`
+2. **Check for build errors**: Pelican will fail on RST syntax errors, missing files, etc.
+3. **Verify output**: `make serve` and check localhost:8000
+4. **NEVER commit without testing the build**
+
+### PELICAN BUILD PROCESS:
+- Uses Pelican static site generator (Python-based)
+- Converts .rst/.md files to HTML
+- RST syntax errors break the build
+- Missing images/files break the build
+- Invalid slugs/filenames cause issues
+
+### PROPER DEVELOPMENT WORKFLOW:
+```bash
+# Setup virtual environment (once)
+make venv
+
+# Test changes before commit
+make clean && make html && make serve
+
+# Check localhost:8000 for issues
+# Only commit if build succeeds
+git add specific-files
+git commit -m "message"
+git push
+```
+
+## CRITICAL CONTENT DIRECTORY ISSUE
+
+**PROBLEM**: Python virtual environments exist in `content/uploads/2024/battleship-solvers/env/` and `env2/`
+- These contain thousands of Python package files (.md, .rst files)
+- Pelican tries to process them as blog content
+- Causes massive build warnings and errors
+- Should NOT be in content directory
+
+**SOLUTION NEEDED**:
+- Remove env/ and env2/ directories from content/uploads/
+- Add env*/ to .gitignore patterns
+- Keep only actual blog assets in content/uploads/
+
## CRITICAL GIT SAFETY LESSON
### DEVASTATING MISTAKE COMMITTED:
diff --git a/Dockerfile.cgolf b/Dockerfile.cgolf
deleted file mode 100644
index d681cca..0000000
--- a/Dockerfile.cgolf
+++ /dev/null
@@ -1,13 +0,0 @@
-FROM alpine:latest
-
-RUN apk --no-cache add gcc musl-dev curl-dev
-
-WORKDIR /app
-
-COPY golf.c .
-
-RUN gcc -o webwords golf.c -lcurl
-
-EXPOSE 31337
-
-CMD ["./webwords"]
\ No newline at end of file
diff --git a/Dockerfile.golf b/Dockerfile.golf
deleted file mode 100644
index 157075a..0000000
--- a/Dockerfile.golf
+++ /dev/null
@@ -1,12 +0,0 @@
-FROM alpine:latest
-
-ENTRYPOINT ["/bin/webwords"]
-
-EXPOSE 31337
-
-COPY golf.py /bin/webwords
-
-RUN chmod 0754 /bin/webwords
-
-RUN apk --no-cache add python3 ca-certificates \
- && rm -rf /var/cache/apk/*
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 188efbb..214e152 100644
--- a/Makefile
+++ b/Makefile
@@ -1,80 +1,46 @@
-PY?=python
-PELICAN?=pelican
-PELICANOPTS=
-
BASEDIR=$(CURDIR)
INPUTDIR=$(BASEDIR)/content
OUTPUTDIR=$(BASEDIR)/output
CONFFILE=$(BASEDIR)/pelicanconf.py
PUBLISHCONF=$(BASEDIR)/publishconf.py
-
-DEBUG ?= 0
-ifeq ($(DEBUG), 1)
- PELICANOPTS += -D
-endif
-
-RELATIVE ?= 0
-ifeq ($(RELATIVE), 1)
- PELICANOPTS += --relative-urls
-endif
-
help:
@echo 'Makefile for a pelican Web site '
@echo ' '
@echo 'Usage: '
+ @echo ' make venv setup virtual environment '
@echo ' make resume (re)generate the resume '
@echo ' make html (re)generate the web site '
@echo ' make clean remove the generated files '
@echo ' make regenerate regenerate files upon modification '
@echo ' make publish generate using production settings '
- @echo ' make serve [PORT=8000] serve site at http://localhost:8000'
- @echo ' make serve-global [SERVER=0.0.0.0] serve (as root) to $(SERVER):80 '
- @echo ' make devserver [PORT=8000] serve and regenerate together '
- @echo ' make ssh_upload upload the web site via SSH '
- @echo ' make rsync_upload upload the web site via rsync+ssh '
- @echo ' '
- @echo 'Set the DEBUG variable to 1 to enable debugging, e.g. make DEBUG=1 html '
- @echo 'Set the RELATIVE variable to 1 to enable relative urls '
+ @echo ' make serve serve site at http://localhost:8000'
+ @echo ' make devserver serve and regenerate together '
@echo ' '
+venv:
+ python3 -m venv venv
+ venv/bin/pip install -r requirements.txt
+
resume:
- rst2pdf $(INPUTDIR)/pages/russell.ballestrini.resume.rst --stylesheets $(INPUTDIR)/pages/russell.ballestrini.resume.style -o $(OUTPUTDIR)/uploads/russell.ballestrini.resume.pdf
-
+ venv/bin/rst2pdf content/pages/russell.ballestrini.resume.rst --stylesheets content/pages/russell.ballestrini.resume.style -o output/uploads/russell.ballestrini.resume.pdf
html:
- $(PELICAN) $(INPUTDIR) -o $(OUTPUTDIR) -s $(CONFFILE) $(PELICANOPTS)
+ venv/bin/pelican content -o output -s pelicanconf.py
clean:
- [ ! -d $(OUTPUTDIR) ] || rm -rf $(OUTPUTDIR)
+ [ ! -d output ] || rm -rf output
regenerate:
- $(PELICAN) -r $(INPUTDIR) -o $(OUTPUTDIR) -s $(CONFFILE) $(PELICANOPTS)
+ venv/bin/pelican -r content -o output -s pelicanconf.py
serve:
-ifdef PORT
- $(PELICAN) -l $(INPUTDIR) -o $(OUTPUTDIR) -s $(CONFFILE) $(PELICANOPTS) -p $(PORT)
-else
- $(PELICAN) -l $(INPUTDIR) -o $(OUTPUTDIR) -s $(CONFFILE) $(PELICANOPTS)
-endif
-
-serve-global:
-ifdef SERVER
- $(PELICAN) -l $(INPUTDIR) -o $(OUTPUTDIR) -s $(CONFFILE) $(PELICANOPTS) -p $(PORT) -b $(SERVER)
-else
- $(PELICAN) -l $(INPUTDIR) -o $(OUTPUTDIR) -s $(CONFFILE) $(PELICANOPTS) -p $(PORT) -b 0.0.0.0
-endif
-
+ venv/bin/pelican -l content -o output -s pelicanconf.py
devserver:
-ifdef PORT
- $(PELICAN) -lr $(INPUTDIR) -o $(OUTPUTDIR) -s $(CONFFILE) $(PELICANOPTS) -p $(PORT)
-else
- $(PELICAN) -lr $(INPUTDIR) -o $(OUTPUTDIR) -s $(CONFFILE) $(PELICANOPTS)
-endif
+ venv/bin/pelican -lr content -o output -s pelicanconf.py
publish:
- $(PELICAN) $(INPUTDIR) -o $(OUTPUTDIR) -s $(PUBLISHCONF) $(PELICANOPTS)
+ venv/bin/pelican content -o output -s publishconf.py
-
-.PHONY: html help clean regenerate serve serve-global devserver publish
+.PHONY: html help clean regenerate serve devserver publish
diff --git a/content/2011-10-01-how-do-i-calculate-the-m-in-my-mvp.rst b/content/2011-10-01-how-do-i-calculate-the-m-in-my-mvp.rst
index 42ae022..4304aa1 100644
--- a/content/2011-10-01-how-do-i-calculate-the-m-in-my-mvp.rst
+++ b/content/2011-10-01-how-do-i-calculate-the-m-in-my-mvp.rst
@@ -11,11 +11,7 @@ MVP (Minimal Viable Product):
The smallest version of your idea that produces value for customers.
-.. linkpeek::
- uri = https://www.remarkbox.com
- action = link-image
- size = 280x220
- style = margin-left: 25px; float: right; border-radius: 8px;
+https://www.remarkbox.com
Recently I have contemplated the idea of building a screen capture
service for websites. I anticipate the service would provide
@@ -27,11 +23,7 @@ After floundering on my first web application,
https://four2go.gumyum.com, I'm afraid to spend lots of time and energy
on another project if I cannot earn users or customers.
-.. linkpeek::
- uri = https://four2go.gumyum.com
- action = link-image
- size = 280x220
- style = margin-right: 25px; float: left; border-radius: 8px;
+https://four2go.gumyum.com
I feel the market segment for this type of service would include website
directories, live portfolio generation for website designers, and
@@ -41,11 +33,7 @@ look of their site over time.
As an MVP I plan to build a free live web capture application to
basically provide a "Gravatar" for website addresses.
-.. linkpeek::
- uri = https://linkpeek.com
- action = link-image
- size = 280x220
- style = margin-left: 25px; float: right; border-radius: 8px;
+https://linkpeek.com
**Do you think anyone would use my MVP or service?**
diff --git a/content/2011-10-05-linkpeek-com-web-address-thumbnail-api-alpha-release.rst b/content/2011-10-05-linkpeek-com-web-address-thumbnail-api-alpha-release.rst
index e1f6cfc..a8bc32f 100644
--- a/content/2011-10-05-linkpeek-com-web-address-thumbnail-api-alpha-release.rst
+++ b/content/2011-10-05-linkpeek-com-web-address-thumbnail-api-alpha-release.rst
@@ -9,11 +9,7 @@ LinkPeek.com web address thumbnail api alpha release
|
-.. linkpeek::
- action = link-image
- uri = https://linkpeek.com
- size = 140x100
- style = margin-right: 25px; float: left;
+https://linkpeek.com
The `LinkPeek `__ API had an alpha release!
diff --git a/content/2011-12-19-linkpeek-com-webpage-to-image-was-a-by-product.rst b/content/2011-12-19-linkpeek-com-webpage-to-image-was-a-by-product.rst
index 527d78a..ebda6c7 100644
--- a/content/2011-12-19-linkpeek-com-webpage-to-image-was-a-by-product.rst
+++ b/content/2011-12-19-linkpeek-com-webpage-to-image-was-a-by-product.rst
@@ -25,12 +25,7 @@ and come up with less combative idea.
After witnessing the Goog release of "instant previews", I knew there
was a market for a fast and reliable web screen shot service.
-.. linkpeek::
- uri = https://linkpeek.com
- size = 500x240
- action = link-image
- title = web page screen shot service
- style = float: left; border-radius: 15px; margin-right: 15px;
+https://linkpeek.com
So I decided to bring instant previews to anyone who needed them. I
wanted to build a fast, flexible, and easy to use screenshot API. After
diff --git a/content/2018-03-16-fulfilling-childhood-dreams-solar.rst b/content/2018-03-16-fulfilling-childhood-dreams-solar.rst
index 9d68cd3..1aebfde 100644
--- a/content/2018-03-16-fulfilling-childhood-dreams-solar.rst
+++ b/content/2018-03-16-fulfilling-childhood-dreams-solar.rst
@@ -56,6 +56,7 @@ You can see how the sun rises to cover the 8 panels on the front of the house an
SolarEdge Monitoring Dashboard also keeps track of various high level metrics. For example, I input my electricity rates with date ranges and the dashboard calculates the "lifetime revenue" of my solar system. I plan to track my ROI on this number!
.. image:: /uploads/2018/2018-03-16-solar-overview.png
+ :alt: Solar panel installation overview
Home Energy Monitoring
=============================
diff --git a/content/2019-09-25-installing-unity-on-linux.rst b/content/2019-09-25-installing-unity-on-linux.rst
index 2b9fa92..9586db6 100644
--- a/content/2019-09-25-installing-unity-on-linux.rst
+++ b/content/2019-09-25-installing-unity-on-linux.rst
@@ -45,5 +45,6 @@ Anyways, now you may start a Unity project. ``Unity Hub`` seems to store files l
Thats all for now, please check back for more posts about gumyum!
.. image:: /uploads/2019/unity-hub-gumyum.png
+ :alt: Unity Hub interface
.. |gumyum logo| image:: /uploads/2010/12/gumyumgameslogo.png
diff --git a/content/2022-05-09-uncle-drops-off-server-with-note-asking-u-to-cl0ne-ubuntu22-kvm.rst b/content/2022-05-09-uncle-drops-off-server-with-note-asking-u-to-cl0ne-ubuntu22-kvm.rst
index 11f0ec7..2a83649 100644
--- a/content/2022-05-09-uncle-drops-off-server-with-note-asking-u-to-cl0ne-ubuntu22-kvm.rst
+++ b/content/2022-05-09-uncle-drops-off-server-with-note-asking-u-to-cl0ne-ubuntu22-kvm.rst
@@ -212,6 +212,4 @@ on ubuntu desktop network manager hijacks /etc/netplan but also makes it impossi
sudo nmcli con mod 'Wired connection 1' ipv4.dns-search "foxhop.net"
-your only hope is this setting persists across reboots.
-
-------
+your only hope is this setting persists across reboots.
diff --git a/content/2025-10-10-webwords-python-code-golf-minimal-implementation.rst b/content/2025-10-10-webwords-code-golf-minimal-implementation.rst
similarity index 99%
rename from content/2025-10-10-webwords-python-code-golf-minimal-implementation.rst
rename to content/2025-10-10-webwords-code-golf-minimal-implementation.rst
index 8968cd0..afe8a80 100644
--- a/content/2025-10-10-webwords-python-code-golf-minimal-implementation.rst
+++ b/content/2025-10-10-webwords-code-golf-minimal-implementation.rst
@@ -69,7 +69,7 @@ how they work
5. No error checking or memory leak prevention
docker implementation
-====================
+=====================
.. code-block:: dockerfile
diff --git a/content/pages/about.rst b/content/pages/about.rst
index 8670cd6..9ccd819 100644
--- a/content/pages/about.rst
+++ b/content/pages/about.rst
@@ -16,8 +16,8 @@ I value Truth, Freedom, Harmony, & Love. I want to find financial independence t
You should `contact me `_, I love conversation and often respond in a timely manner!
-Russell’s Active Projects
-###########################
+Russell's Active Projects
+=========================
.. contents::
diff --git a/golf.c b/golf.c
deleted file mode 100644
index 59078f9..0000000
--- a/golf.c
+++ /dev/null
@@ -1,8 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-struct M{char*m;size_t s;};size_t w(void*c,size_t z,size_t n,void*u){size_t r=z*n;struct M*m=u;char*p=realloc(m->m,m->s+r+1);if(!p)return 0;m->m=p;memcpy(&m->m[m->s],c,r);m->s+=r;m->m[m->s]=0;return r;}int f(char*u,char**o){CURL*h;struct M c={malloc(1),0};curl_global_init(0);h=curl_easy_init();if(h){curl_easy_setopt(h,10002,u);curl_easy_setopt(h,20011,w);curl_easy_setopt(h,10001,&c);curl_easy_perform(h);curl_easy_cleanup(h);}curl_global_cleanup();*o=c.m;return 1;}void s(int k,char*r){char b[256];sprintf(b,"HTTP/1.1 200 OK\r\nContent-Length: %zu\r\n\r\n%s",strlen(r),r);send(k,b,strlen(b),0);}int main(){int v=socket(2,1,0),c;struct sockaddr_in a={2,htons(31337),0};bind(v,(void*)&a,16);listen(v,10);while(1){c=accept(v,0,0);char b[4096],*q,*t,*d;recv(c,b,4095,0);q=strchr(b,'?');if(q&&(t=strstr(q,"target="))&&(q=strstr(q,"keyword="))){char*p;if((p=strchr(t+7,'&')))*(p)=0;else if((p=strchr(t+7,' ')))*(p)=0;if((p=strchr(q+8,'&')))*(p)=0;else if((p=strchr(q+8,' ')))*(p)=0;if(f(t+7,&d))s(c,strstr(d,q+8)?"true":"false");else s(c,"false");free(d);}else s(c,"false");close(c);}}
\ No newline at end of file
diff --git a/golf.py b/golf.py
deleted file mode 100644
index c179e9c..0000000
--- a/golf.py
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env python3
-import http.server as h,urllib.request as u,urllib.parse as p
-class S(h.BaseHTTPRequestHandler):
- def do_GET(s):q=dict(p.parse_qsl(p.urlparse(s.path).query));s.send_response(200);s.end_headers();s.wfile.write(str(q.get('keyword','')in u.urlopen(q.get('target','')).read().decode()).lower().encode())
-h.HTTPServer(('',31337),S).serve_forever()
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index 18ea47b..d07c37c 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,3 +1,4 @@
pelican
ago
rst2pdf
+markdown