Tom DeMay Headshot

About This Site

This site was built as an excuse to learn new technologies.

It's pure overkill, but I learned a lot or deepened my existing understandings of different technologies. Here's what I learned...

GitHub Pages

GitHub Pages is a free hosting service provided by GitHub that allows users to publish and host static websites directly from their GitHub repositories. It simplifies the process of deploying HTML, CSS, and JavaScript files to a publicly accessible website. My GitHub Repository tomdemaypro is used to build this site.

HTML, CSS and JavaScript

Creating this site gave me a deeper understanding of CSS, JavaScript and the DOM object model. I better understand how easy it is to change the layout of a site based on different criteria. With minor CSS changes the layout of this site is radically different whether it's being viewed on a desktop computer, mobile phone, printed or exporting to PDFs.

Jekyll and Liquid

Jekyll generates static HTML files during the build process. Jekyll uses the "Liquid" templating language to create reusable templates for this sites layout and structure. With Liquid, you can include variables, conditionals, loops, and other logic to dynamically generate content.

GitHub only serves static web pages. Initially I had to copy elements that are common to every page to each HTML document. It quickly became a pain to keep them in sync and I was constantly breaking something.

The solution to this problem was solved by moving everything to Jekyll. This allowed me to break every element down to separate files that get pulled together during the build process to build and deploy static web pages to my website. The main pages of this site basically include the name of the Liquid template, the title of the page and the content for the page. I do not need to include anything else. Jekyll will combine everything using my default Liquid "layout" template.

Previously a page like this would have been over 1000 lines of HTML and probably 80% would be duplicated on every page. The code below is what makes up the HTML file you are viewing right now. The content for each section is in each of the listed HTML files. You can see how the Liquid templates are broken up for this site at my GitHub Repository tomdemaypro .

---
layout: default
title: "About This Site"
---

{% include aboutsite/headline.html %}
{% include aboutsite/githubpages.html %}
{% include aboutsite/htmlcssjavascript.html %}
{% include aboutsite/jekyllliquid.html %}
{% include aboutsite/githubactions.html %}
{% include aboutsite/ruby.html %}
{% include aboutsite/githubwebhooks.html %}
{% include aboutsite/goodsync.html %}
{% include aboutsite/pythonflask.html %}
{% include aboutsite/pythoncelery.html %}
{% include aboutsite/rabbitmq.html %}
{% include aboutsite/pythongit.html %}
{% include aboutsite/docker.html %}
{% include aboutsite/selenium.html %}
{% include aboutsite/pythonasyncio.html %}
GitHub Actions

GitHub Actions is a workflow automation platform that allows you to automate tasks in your GitHub repository, triggered by events like code changes or support tickets. It uses YAML files to define workflows with jobs and steps, and integrates with other GitHub features and external services.

This is how I'm able to break all my pages into separate managable parts. When I check a change into my GitHub Repository tomdemaypro GitActions pipeline is triggered to run and uses Jekyll to combined my Liquid templates, and run any Ruby code I might have, to build my static web pages and deploy them to this site.

Ruby

Jekyll supports Ruby scripts in the build process. I have obfuscated my contact information in the Liquid templates files committed to my repository so web crawlers won't pick it up. This information is excluded from the generated HTML when viewing the site online. But when I run this site on my Jekyll installation on my local machine Jekyll runs my Ruby scripts to deobfuscate my contact information during the build process and embeds the information in the generated HTML files. From there, I can export my site to create my CV and Resume PDFs and it will include my contact information. This is what I provide to potential employers.

GitHub WebHooks

When I commit a change to my GitHub repository, GitHub will invoke a "webhook" running on my local computer. This WebHook is essentially a REST API. When the WebHook is called, it triggers downloading the code from the remote GitHub repository, starting a Jekyll server locally to regenerate my pages with the contact information and exports my CV and Resume to PDF files and uploads them to various cloud providers so they are available to me on my mobile devices. If I wanted to, I can make a change to my Professional Skills or fix a typo in my Resume from my mobile device. When I commit the change my new PDFs with the changes are available on my phone within 50 seconds of making a change. I can send it to future employers from there, or upload them to a job application site.

GoodSync

GoodSync is a free tool that will keep files in sync. When my webhook finishes creating my CV and Resume PDFs GoodSync detects the changes and then uploads my PDF to various cloud providers so I can access these files from my mobile device.

Bottom line, I fix a typo in the code for my Resume using the GitHub mobile app and without 50 seconds I have updated PDFs for my CV and Resume on my mobile device through Apple iCloud, Google Drive and Dropbox.

Python Flask

Flask is a lightweight and flexible web framework for Python that allows you to build web applications and APIs with simplicity and control for very small projects (not intended to be used in a production environment).

I use Python Flask to host a REST WebServer on my local machine. When the REST API is called, it kicks off a background task to download any changes from the remote GitHub repository to my local machine, rebuilds the pages locally and recreates my CV and Resume PDFs.

Python Celery

Python Celery is a distributed task queue system that enables you to perform asynchronous and distributed processing in Python. It allows you to define tasks that can be executed asynchronously in the background.

I needed a solution that will allow my Python Flask REST API web server to kick off a task to recreate my CV and Resume PDFs without blocking calls to the server while the task is running. In order to do so, I needed a background task. Here's the catch, Python's multi-threading is limited by Python's Global Interpreter Lock (GIL). Therefore, running my task in a separate thread can make my WebSite unavailable to callers until the task is done.

Using Celery I can post a notification to a "Message Broker". A separate Celery Worker process pulls that task from the Message Broker and executes it in the Worker's process, freeing up my REST Web server to just respond to REST API calls and queing work to be done elsewhere.

The Flask REST Website accepts a call from the WebHook and responds with 200: "Task Scheduled", or 429: "The requested work is already being processed" and hands the task off to Celery to run the job.

RabbitMQ

Celery supports various message brokers, such as RabbitMQ or Redis, to handle task message passing and result storage. It provides a straightforward way to scale and parallelize tasks, making it suitable for handling time-consuming or resource-intensive operations in a distributed environment. When a call is made to my WebHook in my Python Flask application, Python Celery posts a message in RabbitMQ and the Celery Worker process pulls the message from RabbitMQ to perform the task to recreate my CV and Resume PDFs.

SQLite

RabbitMQ is a message broker that focuses on facilitating communication and message exchange between different systems. It primarily acts as a middleware for handling message queues and routing messages between producers and consumers.

By default, RabbitMQ does not provide built-in support for storing data in a database. Its main purpose is to handle the reliable delivery of messages between applications or services. However, you can integrate RabbitMQ with other systems or databases to store data if needed.

I created a local SQLite database that stored all the information and result data from RabbitMQ.

Python Git Module

Python Git Module is used in my background task to download any changes from my remote GitHub repository to my local repository whenever a change is made. This permits me to modify the content of my site from anywhere, including on my mobile phone and have it pushed to my local machine where PDFs with my contact information are created programmatically.

Docker and Python Docker Module

Docker is an open-source platform that enables developers to automate the deployment and management of applications in lightweight, isolated containers. Containers provide a consistent and reproducible environment for running software, allowing applications to be easily packaged with their dependencies, and ensuring consistency across different systems.

RabbitMQ has a reputation as being hard to install and configure. So I choose not to. A RabbitMQ docker image is available in the Docker hub repository. Simply executing the following command pulls a fully functional pre-configured RabbitMQ server and starts it on my local machine.

docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq

I was able to integrate the Python Docker module into my Python Flask website to download the RabbitMQ docker container from the Docker repository and start it when the Flask website starts and stops the RabbitMQ docker container when the Flask website stops.

Python Selenium Module

Selenium is an open-source framework that allows developers to automate web browsers for tasks like web testing and web scraping. It provides a programming interface for controlling browsers, simulating user interactions, and extracting data from websites.

Selenium is the key to putting this all together. The background task will start the Jekyll server and then uses Selenium to download the generated HTML for my Resume, export it to a PDF, then checks the "Show Cover Letter" box on my site and then exports my CV to another PDF.

Python AsyncIo

Python asyncio is a module introduced in Python 3.4 that provides a way to write asynchronous, concurrent, and non-blocking code. It is built upon the concept of coroutines and event loops.

Ignoring for a moment that Celery is no longer supported on Windows platform, the Celery/RabbitMQ solution was over kill for what I needed to do. But it was a good oportunity to learn something new. After I got that working I threw it all away and decided to use Python AsyncIo to start the background task. Starting this as a background task is what allows my WebHook to be able to respond to callers to notify them that the Task has been Scheduled without blocking future calls to the REST API while the background task is running.

So at most, two tasks can be scheduled and they would run asynchronously, one after the other, allowing my REST Web Server API to be extremely responsive for my purposes.