summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile30
-rw-r--r--card24
-rw-r--r--cv.html400
-rw-r--r--cv.pdfbin549659 -> 0 bytes
-rwxr-xr-xcv.sh6
-rw-r--r--donate.php1
-rw-r--r--drafts/2020-11-24-i-like-hyper-more-than-actix.php (renamed from drafts/2020-11-24-i-like-hyper-more-than-actix.html)0
-rw-r--r--drafts/2021-07-28-devops-is-a-weird-word.php1
-rw-r--r--drafts/2021-reading-list.php (renamed from drafts/2021-reading-list.html)0
-rw-r--r--drafts/365 days of working from home.php (renamed from drafts/365 days of working from home.html)0
-rw-r--r--drafts/altrustic-angelshark.php (renamed from drafts/altrustic-angelshark.html)0
-rw-r--r--drafts/avoiding null in csharp.php (renamed from drafts/avoiding null in csharp.html)0
-rw-r--r--drafts/biz class internet is worth it.php (renamed from drafts/biz class internet is worth it.html)0
-rw-r--r--drafts/california is doing weird stuff.php4
-rw-r--r--drafts/clementine.php (renamed from drafts/clementine.html)0
-rw-r--r--drafts/dell-dock.php (renamed from drafts/dell-dock.html)0
-rw-r--r--drafts/dotnet 5.0: use it.php (renamed from drafts/dotnet 5.0: use it.html)0
-rw-r--r--drafts/form-fields.php (renamed from drafts/form-fields.html)0
-rw-r--r--drafts/frictionless software invites creative solutions.php (renamed from drafts/frictionless software invites creative solutions.html)0
-rw-r--r--drafts/het-club.php (renamed from drafts/het-club.html)0
-rw-r--r--drafts/home server evolution6
-rw-r--r--drafts/html-for-docs-2020.php (renamed from drafts/html-for-docs-2020.html)0
-rw-r--r--drafts/its-not-rust-vs-go.php (renamed from drafts/it's not rust vs go.html)0
-rw-r--r--drafts/latitude and longevity.php (renamed from drafts/latitude and longevity.html)0
-rw-r--r--drafts/living with freebsd.php (renamed from drafts/living with freebsd.html)0
-rw-r--r--drafts/living with linux.php (renamed from drafts/living with linux.html)0
-rw-r--r--drafts/mpv is literally a flawless video player.php (renamed from drafts/mpv is literally a flawless video player.html)0
-rw-r--r--drafts/my first car is a 1953 hudson hornet.php (renamed from drafts/my first car is a 1953 hudson hornet.html)0
-rw-r--r--drafts/oh sh*t (the case for better brakes and tires).php (renamed from drafts/oh sh*t (the case for better brakes and tires).html)0
-rw-r--r--drafts/programs i use all the time.php (renamed from drafts/programs i use all the time.html)0
-rw-r--r--drafts/quarantine to vaccine: Corona Blues Review.php (renamed from drafts/quarantine to vaccine: Corona Blues Review.html)0
-rw-r--r--drafts/rip-full-time-linux.php (renamed from drafts/rip-full-time-linux.html)0
-rw-r--r--drafts/scrum, agile, kanban, springs, delivery.php (renamed from drafts/scrum, agile, kanban, springs, delivery.html)0
-rw-r--r--drafts/server closets in the summer.php (renamed from drafts/server closets in the summer.html)0
-rw-r--r--drafts/stack-end-devs.php (renamed from drafts/stack-end-devs.html)0
-rw-r--r--drafts/surprisingly simple.php (renamed from drafts/surprisingly simple.html)0
-rw-r--r--drafts/used-refurb-2020.php (renamed from drafts/used-refurb-2020.html)0
-rw-r--r--drafts/value.php5
-rw-r--r--drafts/what is a script no really.php (renamed from drafts/what is a script no really.html)0
-rw-r--r--drafts/what is programming.php (renamed from drafts/what is programming.html)0
-rw-r--r--drafts/your company isnt doing SRE.php (renamed from drafts/your company isnt doing SRE.html)0
-rw-r--r--feed.php (renamed from templates/rss_head.xml)18
-rw-r--r--hire.php40
-rw-r--r--includes/head.php201
-rw-r--r--includes/icons/.!26569!card-account-mail.svg0
-rw-r--r--includes/icons/.!89047!card-account-mail.svg0
-rw-r--r--includes/nav.php44
-rw-r--r--includes/stylesheet.css145
-rw-r--r--includes/template.php6
-rw-r--r--index.html98
-rw-r--r--index.php31
-rw-r--r--info.html273
-rw-r--r--info.php147
-rw-r--r--payments.php139
-rw-r--r--posts/2019-04-06-why-have-a-website-in-2019.html170
-rw-r--r--posts/2019-04-06-why-have-a-website-in-2019.php112
-rw-r--r--posts/2019-06-07-how-to-start-and-drive-a-hudson-hornet.html322
-rw-r--r--posts/2019-06-07-how-to-start-and-drive-a-hudson-hornet.php267
-rw-r--r--posts/2019-07-04-the-best-way-to-transfer-gopro-files-with-linux.html127
-rw-r--r--posts/2019-07-04-the-best-way-to-transfer-gopro-files-with-linux.php72
-rw-r--r--posts/2019-07-04-yabs-yet-another-bad-shop.html235
-rw-r--r--posts/2019-07-04-yabs-yet-another-bad-shop.php183
-rw-r--r--posts/2019-07-21-dancing-the-shag-and-the-new-lion-king.html85
-rw-r--r--posts/2019-07-21-dancing-the-shag-and-the-new-lion-king.php33
-rw-r--r--posts/2019-07-28-i-finally-found-a-drink-i-like.html86
-rw-r--r--posts/2019-07-28-i-finally-found-a-drink-i-like.php31
-rw-r--r--posts/2019-08-11-marrying-my-best-friend.html68
-rw-r--r--posts/2019-08-11-marrying-my-best-friend.php17
-rw-r--r--posts/2019-08-30-keep-right-except-to-pass.html108
-rw-r--r--posts/2019-08-30-keep-right-except-to-pass.php46
-rw-r--r--posts/2019-09-28-my-preferred-method-for-data-recovery.html276
-rw-r--r--posts/2019-09-28-my-preferred-method-for-data-recovery.php224
-rw-r--r--posts/2020-04-10-the-obligatory-covid-19-post.html103
-rw-r--r--posts/2020-04-10-the-obligatory-covid-19-post.php51
-rw-r--r--posts/2020-04-10-wedding-photos-are-here.html96
-rw-r--r--posts/2020-04-10-wedding-photos-are-here.php40
-rw-r--r--posts/2020-07-11-why-computer-science-at-w-m.html249
-rw-r--r--posts/2020-07-11-why-computer-science-at-w-m.php194
-rw-r--r--posts/2020-07-26-now-this-is-a-minimal-install.html101
-rw-r--r--posts/2020-07-26-now-this-is-a-minimal-install.php49
-rw-r--r--posts/2020-11-30-titanics-last-signals.html73
-rw-r--r--posts/2020-11-30-titanics-last-signals.php14
-rw-r--r--posts/2020-12-01-the-guides.html117
-rw-r--r--posts/2020-12-01-the-guides.php65
-rw-r--r--posts/2020-12-04-aoc-2020-day-1-in-cbm-basic.html231
-rw-r--r--posts/2020-12-04-aoc-2020-day-1-in-cbm-basic.php179
-rw-r--r--posts/2020-12-08-useful-sprint-planning-from-a-certified-scrum-master.html203
-rw-r--r--posts/2020-12-08-useful-sprint-planning-from-a-certified-scrum-master.php144
-rw-r--r--posts/2020-12-22-why-does-everyone-use-adobe-acrobat-reader.html144
-rw-r--r--posts/2020-12-22-why-does-everyone-use-adobe-acrobat-reader.php84
-rw-r--r--posts/2020-12-29-antivirus-software-is-a-hack.html197
-rw-r--r--posts/2020-12-29-antivirus-software-is-a-hack.php137
-rw-r--r--posts/2021-01-15-adam-s-2020-reading-list.html196
-rw-r--r--posts/2021-01-15-adam-s-2020-reading-list.php137
-rw-r--r--posts/2021-01-15-root-on-zfs-a-zpool-of-mirror-vdevs-the-easy-way.html375
-rw-r--r--posts/2021-01-15-root-on-zfs-a-zpool-of-mirror-vdevs-the-easy-way.php306
-rw-r--r--posts/2021-01-28-undefined-javasript-is-undefined.html163
-rw-r--r--posts/2021-01-28-undefined-javasript-is-undefined.php108
-rw-r--r--posts/2021-02-12-louis-vierne-is-a-bamf-and-proof-that-organists-are-metal.html129
-rw-r--r--posts/2021-02-12-louis-vierne-is-a-bamf-and-proof-that-organists-are-metal.php67
-rw-r--r--posts/2021-03-19-how-to-automate-certbot-renewal-with-haproxy.html256
-rw-r--r--posts/2021-03-19-how-to-automate-certbot-renewal-with-haproxy.php198
-rw-r--r--posts/2021-04-20-how-to-make-your-website-boring-and-why.html214
-rw-r--r--posts/2021-04-20-how-to-make-your-website-boring-and-why.php156
-rw-r--r--posts/2021-05-23-web-designers-please-don-t-animate-page-titles.html133
-rw-r--r--posts/2021-05-23-web-designers-please-don-t-animate-page-titles.php69
-rw-r--r--rss.xml42
-rw-r--r--software.html102
-rw-r--r--templates/index_foot.html4
-rw-r--r--templates/index_head.html68
-rw-r--r--templates/rss_foot.xml3
-rw-r--r--templates/template.html63
112 files changed, 3829 insertions, 5512 deletions
diff --git a/Makefile b/Makefile
index 3f7c13c..8dcd6e5 100644
--- a/Makefile
+++ b/Makefile
@@ -1,35 +1,17 @@
# Written for FreeBSD make(1), or pmake. Not tested with GNU make.
EDITOR = $$EDITOR
-POST_T = templates/template.html
-INDEX_HEAD_T = templates/index_head.html
-INDEX_FOOT_T = templates/index_foot.html
-RSS_HEAD_T = templates/rss_head.xml
-RSS_FOOT_T = templates/rss_foot.xml
+POST_T = includes/template.php
-all: index.html rss.xml cv.pdf
-
-index.html: posts/*.html
- @grep h1 $> | sort -r | sed 's#^\(posts/\([0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\)[^:]*\):[ \t]*<h1>\(.*\)</h1>#<li><a href="/\1">\3 <code>\2</code></a></li>#' | cat $(INDEX_HEAD_T) - $(INDEX_FOOT_T) > index.html
-
-rss.xml: posts/*.html
- @grep h1 $> | sort -r | sed 's#^\(posts/[^:]*\):[ \t]*<h1>\(.*\)</h1>#<item><title>\2</title><link>https://www.53hor.net/posts/\1</link></item>#' | cat $(RSS_HEAD_T) - $(RSS_FOOT_T) > rss.xml
-
-cv.pdf: cv.html
- @mutool convert -o cv.pdf cv.html
-
-.PHONY: serve post clean
+.PHONY: serve post
serve:
- python3.7 -m http.server 3000
+ php -S localhost:8000
-post:
- @read -p "Title: " TITLE; \
+draft:
+ @read -rp "Title: " TITLE; \
SHORT_DATE=`date +"%Y-%m-%d"`; \
- FILENAME=posts/$$SHORT_DATE-`printf "$$TITLE" | tr -Cs "[:alnum:]" '-' | tr "[:upper:]" "[:lower:]"`.html; \
- cp $(POST_T) $$FILENAME; \
+ FILENAME=drafts/$$SHORT_DATE-`printf "$$TITLE" | tr -Cs "[:alnum:]" '-' | tr "[:upper:]" "[:lower:]"`.php; \
sed -i '' "s/{{ title }}/$$TITLE/g" $$FILENAME; \
$$EDITOR $$FILENAME
-clean:
- rm -f index.html rss.xml
diff --git a/card b/card
deleted file mode 100644
index f34fd5b..0000000
--- a/card
+++ /dev/null
@@ -1,24 +0,0 @@
-╓─────────────────────────────────────────────────────────────────────────────╖
-║ ,---. | ,---. | ║
-║ |---|,---|,---.,-.-. | ,---.,---.,---.,---.,---.|--- ,---.,---. ║
-║ | || |,---|| | | | ,---|| | ||---'| || |---'| ║
-║ ` '`---'`---^` ' ' `---'`---^` |---'`---'` '`---'`---'` ║
-║ |
-║
-║
-║ - Professional Computer Programmer & Software Developer
-║ - Experience with process automation, web applications, and IT operations ║
-║
-║
-║ https://www.53hor.net
-║ mailto:atc@53hor.net
-║
-║
-║
-║
-║
-║
-║
-║
-║
-╙─────────────────────────────────────────────────────────────────────────────╜
diff --git a/cv.html b/cv.html
index e242720..c9ecd92 100644
--- a/cv.html
+++ b/cv.html
@@ -1,208 +1,192 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- </head>
- <body>
- <h1>Adam T. Carpenter</h1>
-
- <label for="email">Email</label>
- <a id="email" href="mailto:atc@53hor.net">atc@53hor.net</a>
- <label for="www">WWW</label>
- <a id="www" href="https://www.53hor.net/info.html"
- >www.53hor.net/info.html</a
- >
- <label for="git">Git</label>
- <a id="git" href="https://git.53hor.net">git.53hor.net</a>
-
- <hr />
- <h2>Summary</h2>
-
- <p>
- I am a computer programmer who has been developing and maintaining native
- and web applications since 2018. I have also been providing systems
- administration services and technical mentoring since 2016. I aim to
- create simple, performant, and well-documented software that solves real
- problems with no surprises.
- </p>
-
- <p>
- I am fluent in Rust, C#, Python, JavaScript, Bourne Shell, and HTML+CSS. I
- am also familiar with Java, PHP, C, C++, TypeScript, and PowerShell. I
- have used a variety of frameworks and libraries, as well as a myriad of
- web servers, databases, and "DevOps" toolkits.
- </p>
-
- <hr />
- <h2>Skills</h2>
-
- <h3>Software Development</h3>
-
- <ul>
- <li>
- Build performant, correct applications and services with a focus on
- automating manual labor and making architects'/operators' lives easier.
- </li>
- <li>
- Contribute to internal and client-facing front-end software that is
- simple and easy to use.
- </li>
- <li>
- Integrating with organizational build chains and DevOps pipelines for
- deployments with zero surprises.
- </li>
- </ul>
-
- <h3>Systems Administration</h3>
-
- <ul>
- <li>
- Architect and arrange physical machines and the servers that run on them
- for minimal downtime and secure, speedy operation.
- </li>
- <li>
- Administer container orchestration clusters with dozens of
- "micro-services" that need to communicate together to achieve a common
- goal. Apply zero-downtime upgrade practices as well as high-availability
- horizontal replica scaling for high-use applications.
- </li>
- <li>
- Self-host a variety of tools, applications, and web servers for the
- purpose of learning and ownership of digital property.
- </li>
- </ul>
-
- <h3>Technical Mentoring, Leadership</h3>
-
- <ul>
- <li>
- Transfer knowledge and skills in a practical, enjoyable fashion in
- language that is [hopefully] easy to comprehend.
- </li>
- <li>
- Take a senior role in directing a flourishing new team of developers to
- get started quickly and achieve a state of production in little time.
- </li>
- <li>
- Co-host informal lectures and "lunch and learns" on a variety of topics,
- especially but not limited to computing.
- </li>
- </ul>
-
- <hr />
- <h2>Experience</h2>
-
- <ul>
- <li>
- <h3>
- Automatic Data Processing | Application Developer | June 2018 to
- present
- </h3>
- <ul>
- <li>
- Authored <em>Altruistic Angelshark</em>, an Avaya Communication
- Manager automation daemon, to ease friction caused by existing,
- interactive, and fragile tools and processes. This tool was used to
- save the company rougly half a million dollars per year by enabling
- unused license cleanup with little operator input. It was deemed
- appropriately useful to release as free and open source software. It
- was written in Rust and operates over the SSH2 library using an
- undocumented Avaya protocol.
- </li>
- <li>
- Co-authored an authentication/authorization API to specifically
- serve the needs of our team. This software interacted with Active
- Directory over LDAP, presented users with JSON Web Tokens, and was
- reworked be used as a reverse proxy in front of our container
- services.
- </li>
- <li>
- On-boarded and mentored team of six developers on organization
- DevOps technology and practices. This included configuring and
- knowledge-sharing a Jenkins CICD pipeline, local Docker Trusted
- Registry, and IBM Cloud Private flavor of Kubernetes. This also
- consisted of informal lectures on concepts such as continuous
- deployment and delivery, the "12-factor" methodology, and
- containerization.
- </li>
- <li>
- For multiple years in a row I offered my services for on-site
- training of new college hires. My responsibilities included
- mentoring and knowledge sharing for typical industry tools,
- languages, and frameworks, as well as the inner workings of the
- company. Classes typically consisted of 20-30 new employees.
- </li>
- </ul>
- </li>
-
- <li>
- <h3>
- Freelance | Web Application Designer & Developer | Jul. 2019 to
- present
- </h3>
- <ul>
- <li>
- Built a from-scratch art studio storefront to exactly fit the
- customer's specifications. Site is a mobile-friendly art gallery
- with a cart and checkout system. I used Rust and Vue JS for the
- majority of this project. Functionality was delivered ahead of
- schedule and I was able to quickly compensate for shifting
- requirements.
- </li>
- <li>Built and maintained a variety of static sites.</li>
- </ul>
- </li>
-
- <li>
- <h3>
- The College of William and Mary | Technology Support Specialist | Feb.
- 2015 to May 2018
- </h3>
- <ul>
- <li>
- Worked directly with customers to diagnose issues and install and
- configure software. Interactions were in-person and over the phone.
- Responsibilities also included performing basic repairs to
- enterprise laptops.
- </li>
- <li>
- Maintained three to four public access labs at a time during the
- Summer months, each with 20-30 machines.
- </li>
- </ul>
- </li>
- </ul>
-
- <hr />
- <h2>Academics</h2>
-
- <p>
- I have a Bachelor of Science in Computer Science and graduated from the
- College of William and Mary in May of 2018. While there, I participated in
- several group software development projects such as hybrid Android
- application testing and presided over the campus Game Design Club.
- </p>
-
- <hr />
- <h2>About Me</h2>
-
- <p>
- I wrote my first program on a TI-84 in BASIC to help finish my high school
- math homework faster. I quickly transitioned to building more complicated
- programs but have continued to enjoy finding the smallest amount of code
- to solve a problem quickly, correctly, and securely.
- </p>
-
- <p>
- I grew up in and still call Hampton Roads, Virginia my home. In my spare
- time I drive and maintain a classic car, a 1953 Hudson Hornet. I enjoy
- travelling and being at home with my wife and cocker spaniel. I also
- self-host a web server in a closet in my home.
- </p>
-
- <p>
- You can always find more on
- <a href="https://www.53hor.net">my web site</a>.
- </p>
- </body>
-</html>
+<h1>Adam T. Carpenter</h1>
+
+<label for="email">Email</label>
+<a id="email" href="mailto:atc@53hor.net">atc@53hor.net</a>
+<label for="www">WWW</label>
+<a id="www" href="https://www.53hor.net/hire.php">www.53hor.net</a>
+<label for="git">Git</label>
+<a id="git" target="_blank" href="https://git.53hor.net/explore/repos"
+ >git.53hor.net</a
+>
+
+<p>
+ I am a computer programmer who has been developing and maintaining native and
+ web applications since 2018. I have also been providing systems administration
+ services and technical mentoring since 2016. I aim to create simple,
+ performant, and well-documented software that solves real problems with no
+ surprises.
+</p>
+
+<p>
+ I am fluent in Rust, C#, Python, JavaScript, Bourne Shell, and HTML+CSS. I am
+ also familiar with Java, PHP, C, C++, TypeScript, and PowerShell. I have used
+ a variety of frameworks and libraries, as well as a myriad of web servers,
+ databases, and "DevOps" platforms.
+</p>
+
+<hr />
+<h2>Skills</h2>
+
+<h3>Software Engineering</h3>
+
+<ul>
+ <li>
+ Build performant, correct applications and services with a focus on
+ automating manual labor and making architects' and operators' lives easier.
+ </li>
+ <li>
+ Contribute to internal and client-facing front-end software that is simple
+ and easy to use.
+ </li>
+ <li>
+ Integrating with organizational build chains and DevOps pipelines for
+ deployments with zero surprises.
+ </li>
+</ul>
+
+<h3>Systems Administration</h3>
+
+<ul>
+ <li>
+ Architect and arrange physical machines and the servers that run on them for
+ minimal downtime and secure, speedy operation.
+ </li>
+ <li>
+ Administer container orchestration clusters with dozens of "micro-services"
+ that need to communicate together to achieve a common goal. Apply
+ zero-downtime upgrade practices as well as high-availability horizontal
+ replica scaling for high-use applications.
+ </li>
+ <li>
+ Self-host a variety of tools, applications, and web servers for the purpose
+ of learning and ownership of digital property.
+ </li>
+</ul>
+
+<h3>Technical Mentoring, Leadership</h3>
+
+<ul>
+ <li>
+ Transfer knowledge and skills in a practical, enjoyable fashion in language
+ that is [hopefully] easy to comprehend.
+ </li>
+ <li>
+ Take a senior role in directing a flourishing new team of developers to get
+ started quickly and achieve a state of production in little time.
+ </li>
+ <li>
+ Co-host informal lectures and "lunch and learns" on a variety of topics,
+ especially but not limited to computing.
+ </li>
+</ul>
+
+<hr />
+<h2>Work History</h2>
+
+<p>
+<h3>Software Engineer</h3>
+<em>Automatic Data Processing (August 2021-Present)</em>
+<ul>
+ <li>Promoted after three years of hard work as a junior application developer</li>
+</ul>
+</p>
+
+<p>
+<h3>Application Developer</h3>
+<em>Automatic Data Processing (June 2018-August 2021)</em>
+<ul>
+ <li>
+ Authored <em>Altruistic Angelshark</em>, an Avaya Communication Manager
+ automation daemon, to ease friction caused by existing, interactive, and
+ fragile tools and processes. This tool was used to save the company
+ rougly half a million dollars per year by enabling unused license
+ cleanup with little operator input. It was deemed appropriately useful
+ to release as free and open source software. It was written in Rust and
+ operates over the SSH2 library using an undocumented Avaya protocol.
+ </li>
+ <li>
+ Co-authored an authentication/authorization API to specifically serve
+ the needs of our team. This software interacted with Active Directory
+ over LDAP, presented users with JSON Web Tokens, and was reworked be
+ used as a reverse proxy in front of our container services.
+ </li>
+ <li>
+ On-boarded and mentored team of six developers on organization DevOps
+ technology and practices. This included configuring and
+ knowledge-sharing a Jenkins CICD pipeline, local Docker Trusted
+ Registry, and IBM Cloud Private flavor of Kubernetes. This also
+ consisted of informal lectures on concepts such as continuous deployment
+ and delivery, the "12-factor" methodology, and containerization.
+ </li>
+ <li>
+ For multiple years in a row I offered my services for on-site training
+ of new college hires. My responsibilities included mentoring and
+ knowledge sharing for typical industry tools, languages, and frameworks,
+ as well as the inner workings of the company. Classes typically
+ consisted of 20-30 new employees.
+ </li>
+</ul>
+</p>
+
+<p>
+<h3>Web Application Designer &amp; Developer</h3>
+<em>Freelance (July 2019-Present)</em>
+<ul>
+ <li>
+ Built a from-scratch art studio storefront to exactly fit the customer's
+ specifications. Site is a mobile-friendly art gallery with a cart and
+ checkout system. I used Rust and Vue JS for the majority of this
+ project. Functionality was delivered ahead of schedule and I was able to
+ quickly compensate for shifting requirements.
+ </li>
+ <li>Built and maintained a variety of static sites.</li>
+</ul>
+</p>
+
+<p>
+<h3>Technology Support Specialist, Repair Technician</h3>
+<em>The College of William &amp; Mary (February 2015-May 2018)</em>
+<ul>
+ <li>
+ Worked directly with customers to diagnose issues and install and
+ configure software. Interactions were in-person and over the phone.
+ Responsibilities also included performing basic repairs to enterprise
+ laptops.
+ </li>
+ <li>
+ Maintained three to four public access labs at a time during the Summer
+ months, each with 20-30 machines.
+ </li>
+</ul>
+</p>
+
+<hr />
+<h2>Academic History</h2>
+
+<p>
+ I have a Bachelor of Science in Computer Science and graduated from the
+ College of William and Mary in May of 2018. While there, I participated in
+ several group software development projects such as hybrid Android application
+ testing and presided over the campus Game Design Club.
+</p>
+
+<hr />
+<h2>About Me</h2>
+
+<p>
+ I wrote my first program on a TI-84 in BASIC to help finish my high school
+ math homework faster. I quickly transitioned to building more complicated
+ programs but have continued to enjoy finding the smallest amount of code to
+ solve a problem quickly, correctly, and securely.
+</p>
+
+<p>
+ I grew up in and still call Hampton Roads, Virginia my home. In my spare time
+ I drive and maintain a classic car, a 1953 Hudson Hornet. I enjoy travelling
+ and being at home with my wife and cocker spaniel. I also self-host a web
+ server in a closet in my home.
+</p>
+
+<p>
+ I keep a <a href="https://www.53hor.net">public journal on my web site</a>.
+</p>
diff --git a/cv.pdf b/cv.pdf
deleted file mode 100644
index 5df32c7..0000000
--- a/cv.pdf
+++ /dev/null
Binary files differ
diff --git a/cv.sh b/cv.sh
new file mode 100755
index 0000000..b61e9b3
--- /dev/null
+++ b/cv.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+# Converts CV to downloadable PDF.
+
+printf 'content-type: application/pdf\n\n'
+mutool convert -F pdf cv.html
diff --git a/donate.php b/donate.php
new file mode 100644
index 0000000..82fbd8a
--- /dev/null
+++ b/donate.php
@@ -0,0 +1 @@
+<a href="https://www.paypal.com/donate?business=F9QZQMC55PB4W&no_recurring=0&currency_code=USD">PayPal</a>
diff --git a/drafts/2020-11-24-i-like-hyper-more-than-actix.html b/drafts/2020-11-24-i-like-hyper-more-than-actix.php
index 33c5d9e..33c5d9e 100644
--- a/drafts/2020-11-24-i-like-hyper-more-than-actix.html
+++ b/drafts/2020-11-24-i-like-hyper-more-than-actix.php
diff --git a/drafts/2021-07-28-devops-is-a-weird-word.php b/drafts/2021-07-28-devops-is-a-weird-word.php
new file mode 100644
index 0000000..a0fc919
--- /dev/null
+++ b/drafts/2021-07-28-devops-is-a-weird-word.php
@@ -0,0 +1 @@
+https://blog.dijit.sh/devops-confusion-and-frustration
diff --git a/drafts/2021-reading-list.html b/drafts/2021-reading-list.php
index 46d4707..46d4707 100644
--- a/drafts/2021-reading-list.html
+++ b/drafts/2021-reading-list.php
diff --git a/drafts/365 days of working from home.html b/drafts/365 days of working from home.php
index e69de29..e69de29 100644
--- a/drafts/365 days of working from home.html
+++ b/drafts/365 days of working from home.php
diff --git a/drafts/altrustic-angelshark.html b/drafts/altrustic-angelshark.php
index a5e6ce6..a5e6ce6 100644
--- a/drafts/altrustic-angelshark.html
+++ b/drafts/altrustic-angelshark.php
diff --git a/drafts/avoiding null in csharp.html b/drafts/avoiding null in csharp.php
index e69de29..e69de29 100644
--- a/drafts/avoiding null in csharp.html
+++ b/drafts/avoiding null in csharp.php
diff --git a/drafts/biz class internet is worth it.html b/drafts/biz class internet is worth it.php
index e69de29..e69de29 100644
--- a/drafts/biz class internet is worth it.html
+++ b/drafts/biz class internet is worth it.php
diff --git a/drafts/california is doing weird stuff.php b/drafts/california is doing weird stuff.php
new file mode 100644
index 0000000..0fda874
--- /dev/null
+++ b/drafts/california is doing weird stuff.php
@@ -0,0 +1,4 @@
+https://www.theregister.com/2021/07/26/dell_energy_pcs/
+-> but all-evs by what year?
+
+mechanics not being able to fix own cars
diff --git a/drafts/clementine.html b/drafts/clementine.php
index e69de29..e69de29 100644
--- a/drafts/clementine.html
+++ b/drafts/clementine.php
diff --git a/drafts/dell-dock.html b/drafts/dell-dock.php
index 4a9dd9a..4a9dd9a 100644
--- a/drafts/dell-dock.html
+++ b/drafts/dell-dock.php
diff --git a/drafts/dotnet 5.0: use it.html b/drafts/dotnet 5.0: use it.php
index 766445e..766445e 100644
--- a/drafts/dotnet 5.0: use it.html
+++ b/drafts/dotnet 5.0: use it.php
diff --git a/drafts/form-fields.html b/drafts/form-fields.php
index 0aed689..0aed689 100644
--- a/drafts/form-fields.html
+++ b/drafts/form-fields.php
diff --git a/drafts/frictionless software invites creative solutions.html b/drafts/frictionless software invites creative solutions.php
index fbfd394..fbfd394 100644
--- a/drafts/frictionless software invites creative solutions.html
+++ b/drafts/frictionless software invites creative solutions.php
diff --git a/drafts/het-club.html b/drafts/het-club.php
index a144d91..a144d91 100644
--- a/drafts/het-club.html
+++ b/drafts/het-club.php
diff --git a/drafts/home server evolution b/drafts/home server evolution
index e69de29..ce9df51 100644
--- a/drafts/home server evolution
+++ b/drafts/home server evolution
@@ -0,0 +1,6 @@
+In my junior year in high school I set up my first home web server. I made it out of a used fleet desktop that my school was getting rid of. It was a Dell Optiplex GX400 with a Pentium 4 and (I think) 768MB of memory. It had Windows XP Professional and Microsoft IIS and Thunderbird mail on it. When I set it up it was the first time I had ever port-forwarded from a home router to a device on the network and configured a firewall to let traffic into my bedroom. Because I didn't know anything about networking, hosting, or web servers, I published web pages to it by emailing them to that Thunderbird instance. A scheduled task would unzip the attached files and copy them to the web root.
+
+My friends and I all had our own address so we could paste funny memes and jokes on our own "walls" while we were in class. The site had no domain name or certificate. Just an inscure, dynamic Verizon IP address which I had to re-share every time my parents got a new upstream IP. We called it the "Troll Nexus Center".
+
+Fast-forward a few years and I'm in college and I have my own place. I got really used to being able to remote into the Computer Science lab, run long-running or intensive jobs, disconnect, and then re-connect later.
+
diff --git a/drafts/html-for-docs-2020.html b/drafts/html-for-docs-2020.php
index 8b5462e..8b5462e 100644
--- a/drafts/html-for-docs-2020.html
+++ b/drafts/html-for-docs-2020.php
diff --git a/drafts/it's not rust vs go.html b/drafts/its-not-rust-vs-go.php
index c9273ff..c9273ff 100644
--- a/drafts/it's not rust vs go.html
+++ b/drafts/its-not-rust-vs-go.php
diff --git a/drafts/latitude and longevity.html b/drafts/latitude and longevity.php
index e69de29..e69de29 100644
--- a/drafts/latitude and longevity.html
+++ b/drafts/latitude and longevity.php
diff --git a/drafts/living with freebsd.html b/drafts/living with freebsd.php
index e69de29..e69de29 100644
--- a/drafts/living with freebsd.html
+++ b/drafts/living with freebsd.php
diff --git a/drafts/living with linux.html b/drafts/living with linux.php
index e69de29..e69de29 100644
--- a/drafts/living with linux.html
+++ b/drafts/living with linux.php
diff --git a/drafts/mpv is literally a flawless video player.html b/drafts/mpv is literally a flawless video player.php
index 75c09a0..75c09a0 100644
--- a/drafts/mpv is literally a flawless video player.html
+++ b/drafts/mpv is literally a flawless video player.php
diff --git a/drafts/my first car is a 1953 hudson hornet.html b/drafts/my first car is a 1953 hudson hornet.php
index e69de29..e69de29 100644
--- a/drafts/my first car is a 1953 hudson hornet.html
+++ b/drafts/my first car is a 1953 hudson hornet.php
diff --git a/drafts/oh sh*t (the case for better brakes and tires).html b/drafts/oh sh*t (the case for better brakes and tires).php
index e69de29..e69de29 100644
--- a/drafts/oh sh*t (the case for better brakes and tires).html
+++ b/drafts/oh sh*t (the case for better brakes and tires).php
diff --git a/drafts/programs i use all the time.html b/drafts/programs i use all the time.php
index fe7e63c..fe7e63c 100644
--- a/drafts/programs i use all the time.html
+++ b/drafts/programs i use all the time.php
diff --git a/drafts/quarantine to vaccine: Corona Blues Review.html b/drafts/quarantine to vaccine: Corona Blues Review.php
index e69de29..e69de29 100644
--- a/drafts/quarantine to vaccine: Corona Blues Review.html
+++ b/drafts/quarantine to vaccine: Corona Blues Review.php
diff --git a/drafts/rip-full-time-linux.html b/drafts/rip-full-time-linux.php
index e69de29..e69de29 100644
--- a/drafts/rip-full-time-linux.html
+++ b/drafts/rip-full-time-linux.php
diff --git a/drafts/scrum, agile, kanban, springs, delivery.html b/drafts/scrum, agile, kanban, springs, delivery.php
index 5e701c1..5e701c1 100644
--- a/drafts/scrum, agile, kanban, springs, delivery.html
+++ b/drafts/scrum, agile, kanban, springs, delivery.php
diff --git a/drafts/server closets in the summer.html b/drafts/server closets in the summer.php
index e69de29..e69de29 100644
--- a/drafts/server closets in the summer.html
+++ b/drafts/server closets in the summer.php
diff --git a/drafts/stack-end-devs.html b/drafts/stack-end-devs.php
index 7520133..7520133 100644
--- a/drafts/stack-end-devs.html
+++ b/drafts/stack-end-devs.php
diff --git a/drafts/surprisingly simple.html b/drafts/surprisingly simple.php
index 840f1b2..840f1b2 100644
--- a/drafts/surprisingly simple.html
+++ b/drafts/surprisingly simple.php
diff --git a/drafts/used-refurb-2020.html b/drafts/used-refurb-2020.php
index 87bd641..87bd641 100644
--- a/drafts/used-refurb-2020.html
+++ b/drafts/used-refurb-2020.php
diff --git a/drafts/value.php b/drafts/value.php
new file mode 100644
index 0000000..f638ed4
--- /dev/null
+++ b/drafts/value.php
@@ -0,0 +1,5 @@
+write (again) about adding value, not stories or code
+
+a large backlog isn't job security if your stories don't add value
+
+re-hash ADP presentation
diff --git a/drafts/what is a script no really.html b/drafts/what is a script no really.php
index 9d97844..9d97844 100644
--- a/drafts/what is a script no really.html
+++ b/drafts/what is a script no really.php
diff --git a/drafts/what is programming.html b/drafts/what is programming.php
index 4b4e26d..4b4e26d 100644
--- a/drafts/what is programming.html
+++ b/drafts/what is programming.php
diff --git a/drafts/your company isnt doing SRE.html b/drafts/your company isnt doing SRE.php
index fdb1e5e..fdb1e5e 100644
--- a/drafts/your company isnt doing SRE.html
+++ b/drafts/your company isnt doing SRE.php
diff --git a/templates/rss_head.xml b/feed.php
index 286ac21..309f97e 100644
--- a/templates/rss_head.xml
+++ b/feed.php
@@ -1,5 +1,6 @@
+<?php header('content-type: application/rss+xml'); ?>
+
<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE xml>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>53hornet's Feed</title>
@@ -11,3 +12,18 @@
<title>53hornet's Feed</title>
<link>https://www.53hor.net</link>
</image>
+ <?php
+ if ($posts = glob('./posts/*.php')) {
+ $early = true;
+
+ foreach (array_reverse($posts) as $post) {
+ if (!empty($post) && $post != '.' && $post != '..') {
+ $post_name = explode('/', $post)[2];
+ include($post);
+ printf('<item><link>https://www.53hor.net/posts/%s</link><title>%s</title></item>', $post_name, $title);
+ }
+ }
+ }
+ ?>
+ </channel>
+</rss>
diff --git a/hire.php b/hire.php
new file mode 100644
index 0000000..dd1a992
--- /dev/null
+++ b/hire.php
@@ -0,0 +1,40 @@
+<?php
+$title = "Carpenter Tech";
+include('./includes/head.php');
+?>
+
+<p>
+ My name is Adam Carpenter and I am a freelance, general-purpose computer programmer.
+
+</p>
+<ul>
+ <li>Does your business day consist of tedious, repetitive manual tasks? How do you go about streamlining the process and writing software to automate those tasks?</li>
+ <li>Maybe you've outgrown the limitations of DIY site designers such as Google Sites or Wix. How do you approach from-scratch web design and rich web applications?</li>
+ <li>Are you or your small business looking to take control of your IT by self-hosting? Wondering how to go about efficiently and securely serving your clients?</li>
+</ul>
+
+<p>
+ I run a business called <em>Carpenter Tech</em> that aims to help you answer these questions by offering the following services.
+
+</p>
+
+<ul>
+ <li>Software engineering, custom software design, development, and deployment</li>
+ <li>From-scratch web site construction, hosting, and maintenance</li>
+ <li>Programming, self-hosting, and IT consulting for small busineses</li>
+</ul>
+
+<p>
+ I am down to earth and enjoy solving problems. If you think I may be able to help solve yours, the best way to get in touch with me is writing to
+ <a href="mailto:atc@53hor.net">atc@53hor.net</a>.
+</p>
+
+
+<p>
+ Below is my CV and other related professional history. You may also <a href="/cgi-bin/cv.sh">download my CV as a PDF</a>.
+</p>
+
+<hr />
+
+<?php
+include('cv.html');
diff --git a/includes/head.php b/includes/head.php
new file mode 100644
index 0000000..c5e5287
--- /dev/null
+++ b/includes/head.php
@@ -0,0 +1,201 @@
+<head>
+ <style>
+ @font-face {
+ font-family: "Iosevka Slab";
+ font-display: swap;
+ src: url("/includes/iosevka-slab-regular.woff2");
+ }
+
+ :root {
+ --balboa: #195970;
+ --ruby: #9b111e;
+ --slate: #b9c2ca;
+ --charcoal: #798d94;
+ --white: white;
+ --box-radius: 0.5em;
+ --box-border: 0.5em solid var(--white);
+ }
+
+ body {
+ font-family: "Iosevka Slab", monospace;
+ font-size: 1.5em;
+ background-color: var(--balboa);
+ color: var(--white);
+ max-width: 50em;
+ margin: auto;
+ padding: 1em;
+ }
+
+ hr {
+ color: var(--white);
+ }
+
+ nav {
+ list-style-type: none;
+ text-align: center;
+ }
+
+ nav ul {
+ padding: 0;
+ margin: 0;
+ }
+
+ nav li {
+ display: inline-block;
+ margin: 0.5em;
+ padding: 0.5em;
+ }
+
+ nav svg {
+ padding-right: 0.5em;
+ }
+
+ nav a:link,
+ nav a:visited,
+ nav a:hover,
+ nav a:active {
+ display: flex;
+ align-items: center;
+ color: var(--white);
+ text-decoration: none;
+ }
+
+ a:link {
+ color: var(--slate);
+ }
+
+ a:visited {
+ color: var(--charcoal);
+ }
+
+ pre {
+ white-space: pre-wrap;
+ display: block;
+ background-color: var(--charcoal);
+ padding: 1em;
+ border-radius: var(--box-radius);
+ border-left: var(--box-border);
+ border-right: var(--box-border);
+ }
+
+ .description {
+ background-color: var(--ruby);
+ padding: 1em;
+ border-radius: var(--box-radius);
+ border-left: var(--box-border);
+ border-right: var(--box-border);
+ }
+
+ h1,
+ blockquote {
+ font-style: oblique;
+ }
+
+ header {
+ text-align: center;
+ }
+
+ article ul {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ }
+
+ article ul li {
+ padding: 0.5em;
+ }
+
+ article ul li:before {
+ content: "➙";
+ padding-right: 0.5em;
+ }
+
+ article ol li {
+ padding: 0.5em;
+ }
+
+ p img {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+ max-width: 75%;
+ height: auto;
+ border-radius: var(--box-radius);
+ border-left: var(--box-border);
+ border-right: var(--box-border);
+ }
+
+ iframe {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+ }
+
+ .list {
+ overflow-x: auto;
+ }
+
+ .list table {
+ width: 100%;
+ }
+
+ .list td,
+ th {
+ padding: 0.5em;
+ text-align: left;
+ border-bottom: 1px solid var(--charcoal);
+ }
+
+ svg {
+ width: 24px;
+ height: 24px;
+ }
+
+ .form {
+ text-align: center;
+ }
+
+ .form input {
+ font-size: 1em;
+ margin-top: 1em;
+ border-radius: 3em;
+ box-sizing: border-box;
+ padding: 0.5em;
+ border: 0;
+ }
+
+ .form .description {
+ display: none;
+ }
+ </style>
+
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
+ <meta property="og:description" content="The World Wide Web pages of Adam Carpenter" />
+ <meta property="og:image" content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview" />
+ <meta property="og:site_name" content="53hor.net" />
+ <meta property="og:title" content="Adam Carpenter (53hornet)" />
+ <meta property="og:type" content="website" />
+ <meta property="og:url" content="https://www.53hor.net" />
+ <?php
+ if (isset($title)) {
+ printf('<title>53hornet ➙ %s</title>', $title);
+ } else {
+ echo '<title>53hornet</title>';
+ }
+ ?>
+</head>
+
+<body>
+
+ <?php
+ if (!isset($nav) || $nav) {
+ include('nav.php');
+ }
+ ?>
+ <article>
+ <?php
+ if (isset($title)) {
+ printf('<h1>%s</h1>', $title);
+ }
+ ?>
diff --git a/includes/icons/.!26569!card-account-mail.svg b/includes/icons/.!26569!card-account-mail.svg
deleted file mode 100644
index e69de29..0000000
--- a/includes/icons/.!26569!card-account-mail.svg
+++ /dev/null
diff --git a/includes/icons/.!89047!card-account-mail.svg b/includes/icons/.!89047!card-account-mail.svg
deleted file mode 100644
index e69de29..0000000
--- a/includes/icons/.!89047!card-account-mail.svg
+++ /dev/null
diff --git a/includes/nav.php b/includes/nav.php
new file mode 100644
index 0000000..87b9175
--- /dev/null
+++ b/includes/nav.php
@@ -0,0 +1,44 @@
+<nav>
+ <ul>
+ <li>
+ <a href="/">
+ <svg viewBox="0 0 24 24">
+ <path fill="#ffffff" d="M19 16H22L12 7L2 16H5L12 9.69L19 16M7 8.81V7H4V11.5L7 8.81Z" />
+ </svg>
+ Home
+ </a>
+ </li>
+ <li>
+ <a href="/info.php">
+ <svg viewBox="0 0 24 24">
+ <path fill="#ffffff" d="M13.5,4A1.5,1.5 0 0,0 12,5.5A1.5,1.5 0 0,0 13.5,7A1.5,1.5 0 0,0 15,5.5A1.5,1.5 0 0,0 13.5,4M13.14,8.77C11.95,8.87 8.7,11.46 8.7,11.46C8.5,11.61 8.56,11.6 8.72,11.88C8.88,12.15 8.86,12.17 9.05,12.04C9.25,11.91 9.58,11.7 10.13,11.36C12.25,10 10.47,13.14 9.56,18.43C9.2,21.05 11.56,19.7 12.17,19.3C12.77,18.91 14.38,17.8 14.54,17.69C14.76,17.54 14.6,17.42 14.43,17.17C14.31,17 14.19,17.12 14.19,17.12C13.54,17.55 12.35,18.45 12.19,17.88C12,17.31 13.22,13.4 13.89,10.71C14,10.07 14.3,8.67 13.14,8.77Z" />
+ </svg>
+ Info
+ </a>
+ </li>
+ <li>
+ <a target="_blank" href="https://git.53hor.net/explore/repos">
+ <svg viewBox="0 0 24 24">
+ <path fill="#ffffff" d="M2.6,10.59L8.38,4.8L10.07,6.5C9.83,7.35 10.22,8.28 11,8.73V14.27C10.4,14.61 10,15.26 10,16A2,2 0 0,0 12,18A2,2 0 0,0 14,16C14,15.26 13.6,14.61 13,14.27V9.41L15.07,11.5C15,11.65 15,11.82 15,12A2,2 0 0,0 17,14A2,2 0 0,0 19,12A2,2 0 0,0 17,10C16.82,10 16.65,10 16.5,10.07L13.93,7.5C14.19,6.57 13.71,5.55 12.78,5.16C12.35,5 11.9,4.96 11.5,5.07L9.8,3.38L10.59,2.6C11.37,1.81 12.63,1.81 13.41,2.6L21.4,10.59C22.19,11.37 22.19,12.63 21.4,13.41L13.41,21.4C12.63,22.19 11.37,22.19 10.59,21.4L2.6,13.41C1.81,12.63 1.81,11.37 2.6,10.59Z" />
+ </svg>
+ Repos
+ </a>
+ </li>
+ <li>
+ <a href="/hire.php">
+ <svg viewBox="0 0 24 24">
+ <path fill="#ffffff" d="M3,3V21H21V3H3M12,10A2,2 0 0,1 14,12A2,2 0 0,1 12,14A2,2 0 0,1 10,12A2,2 0 0,1 12,10M12,15A1,1 0 0,1 13,16V19A1,1 0 0,1 12,20A1,1 0 0,1 11,19V16A1,1 0 0,1 12,15Z" />
+ </svg>
+ Hire Me
+ </a>
+ </li>
+ <li>
+ <a type="application/rss+xml" href="/rss.xml">
+ <svg viewBox="0 0 24 24">
+ <path fill="#ffffff" d="M6.18,15.64A2.18,2.18 0 0,1 8.36,17.82C8.36,19 7.38,20 6.18,20C5,20 4,19 4,17.82A2.18,2.18 0 0,1 6.18,15.64M4,4.44A15.56,15.56 0 0,1 19.56,20H16.73A12.73,12.73 0 0,0 4,7.27V4.44M4,10.1A9.9,9.9 0 0,1 13.9,20H11.07A7.07,7.07 0 0,0 4,12.93V10.1Z" />
+ </svg>
+ RSS
+ </a>
+ </li>
+ </ul>
+</nav>
diff --git a/includes/stylesheet.css b/includes/stylesheet.css
deleted file mode 100644
index a40bb5f..0000000
--- a/includes/stylesheet.css
+++ /dev/null
@@ -1,145 +0,0 @@
-@font-face {
- font-family: "Iosevka Slab";
- font-display: swap;
- src: url("/includes/iosevka-slab-regular.woff2");
-}
-
-:root {
- --balboa: #195970;
- --ruby: #9b111e;
- --slate: #b9c2ca;
- --charcoal: #798d94;
- --white: white;
- --box-radius: 0.5em;
- --box-border: 0.5em solid var(--white);
-}
-
-body {
- font-family: "Iosevka Slab", monospace;
- font-size: 1.5em;
- background-color: var(--balboa);
- color: var(--white);
- max-width: 50em;
- margin: auto;
- padding: 1em;
-}
-
-hr {
- color: var(--white);
-}
-
-nav {
- list-style-type: none;
- text-align: center;
-}
-
-nav ul {
- padding: 0;
- margin: 0;
-}
-
-nav li {
- display: inline-block;
- margin: 0.5em;
- padding: 0.5em;
-}
-
-nav img {
- padding-right: 0.5em;
-}
-
-nav a:link,
-nav a:visited,
-nav a:hover,
-nav a:active {
- display: flex;
- align-items: center;
- color: var(--white);
- text-decoration: none;
-}
-
-a:link {
- color: var(--slate);
-}
-
-a:visited {
- color: var(--charcoal);
-}
-
-pre {
- white-space: pre-wrap;
- display: block;
- background-color: var(--charcoal);
- padding: 1em;
- border-radius: var(--box-radius);
- border-left: var(--box-border);
- border-right: var(--box-border);
-}
-
-.description {
- background-color: var(--ruby);
- padding: 1em;
- border-radius: var(--box-radius);
- border-left: var(--box-border);
- border-right: var(--box-border);
-}
-
-h1,
-blockquote {
- font-style: oblique;
-}
-
-header {
- text-align: center;
-}
-
-article ul {
- list-style: none;
- padding: 0;
- margin: 0;
-}
-
-article ul li {
- padding: 0.5em;
-}
-
-article ul li:before {
- content: "➙";
- padding-right: 0.5em;
-}
-
-article ol li {
- padding: 0.5em;
-}
-
-p img {
- display: block;
- margin-left: auto;
- margin-right: auto;
- max-width: 75%;
- height: auto;
- border-radius: var(--box-radius);
- border-left: var(--box-border);
- border-right: var(--box-border);
-}
-
-iframe {
- display: block;
- margin-left: auto;
- margin-right: auto;
-}
-
-.list {
- overflow-x: auto;
-}
-
-.list table {
- width: 100%;
-}
-
-.list td,
-th {
- padding: 0.5em;
- text-align: left;
- border-bottom: 1px solid var(--charcoal);
-}
diff --git a/includes/template.php b/includes/template.php
new file mode 100644
index 0000000..5ff90f4
--- /dev/null
+++ b/includes/template.php
@@ -0,0 +1,6 @@
+<?php
+$title = "{{title}}";
+if (isset($early) && $early) {
+ return;
+}
+include($_SERVER['DOCUMENT_ROOT'] . '/includes/head.php');
diff --git a/index.html b/index.html
deleted file mode 100644
index 8e623a2..0000000
--- a/index.html
+++ /dev/null
@@ -1,98 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta
- property="og:image"
- content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview"
- />
- <meta property="og:site_name" content="53hor.net" />
- <meta property="og:title" content="Home" />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>53hornet ➙ Home</title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <header>
- <noscript>
- JavaScript? Where we're going we don't need JavaScript.
- </noscript>
- </header>
-
- <article>
- <h1 style="text-align: center">
- The World Wide Web pages of Adam Carpenter (53hornet)
- </h1>
- <ul>
-<li><a href="/posts/2021-05-23-web-designers-please-don-t-animate-page-titles.html">Web Designers, Please Don't "Animate" Page Titles <code>2021-05-23</code></a></li>
-<li><a href="/posts/2021-04-20-how-to-make-your-website-boring-and-why.html">How to Make Your Website Boring and Why! <code>2021-04-20</code></a></li>
-<li><a href="/posts/2021-03-19-how-to-automate-certbot-renewal-with-haproxy.html">How to Automate Certbot Renewal with HAProxy <code>2021-03-19</code></a></li>
-<li><a href="/posts/2021-02-12-louis-vierne-is-a-bamf-and-proof-that-organists-are-metal.html">Louis Vierne Is a BAMF (and Proof That Organists Are Metal) <code>2021-02-12</code></a></li>
-<li><a href="/posts/2021-01-28-undefined-javasript-is-undefined.html">Undefined? JavaSript Is Undefined. <code>2021-01-28</code></a></li>
-<li><a href="/posts/2021-01-15-root-on-zfs-a-zpool-of-mirror-vdevs-the-easy-way.html">Root on ZFS: A ZPool of Mirror VDEVs <code>2021-01-15</code></a></li>
-<li><a href="/posts/2021-01-15-adam-s-2020-reading-list.html">Adam's <del>2020</del> <ins>Quarantine</ins> Reading List <code>2021-01-15</code></a></li>
-<li><a href="/posts/2020-12-29-antivirus-software-is-a-hack.html">Antivirus Software is a Hack <code>2020-12-29</code></a></li>
-<li><a href="/posts/2020-12-22-why-does-everyone-use-adobe-acrobat-reader.html">Why Does Everyone Use Adobe Acrobat [Reader]? <code>2020-12-22</code></a></li>
-<li><a href="/posts/2020-12-08-useful-sprint-planning-from-a-certified-scrum-master.html">Useful Sprint Planning from a Certified Scrum Master <code>2020-12-08</code></a></li>
-<li><a href="/posts/2020-12-04-aoc-2020-day-1-in-cbm-basic.html">AOC 2020 Day 1 in CBM Basic <code>2020-12-04</code></a></li>
-<li><a href="/posts/2020-12-01-the-guides.html">𝔗𝔥𝔢 𝔊𝔲𝔦𝔡𝔢𝔰 <code>2020-12-01</code></a></li>
-<li><a href="/posts/2020-11-30-titanics-last-signals.html">Titanic's Last Signals <code>2020-11-30</code></a></li>
-<li><a href="/posts/2020-07-26-now-this-is-a-minimal-install.html">Now This is a Minimal Install! <code>2020-07-26</code></a></li>
-<li><a href="/posts/2020-07-11-why-computer-science-at-w-m.html">Why Computer Science at William and Mary <code>2020-07-11</code></a></li>
-<li><a href="/posts/2020-04-10-wedding-photos-are-here.html">Wedding Photo Debacle <code>2020-04-10</code></a></li>
-<li><a href="/posts/2020-04-10-the-obligatory-covid-19-post.html">Obligatory COVID-19 Post <code>2020-04-10</code></a></li>
-<li><a href="/posts/2019-09-28-my-preferred-method-for-data-recovery.html">How I Do Data Recovery <code>2019-09-28</code></a></li>
-<li><a href="/posts/2019-08-30-keep-right-except-to-pass.html">Left Lane is for Passing, Not Cruising <code>2019-08-30</code></a></li>
-<li><a href="/posts/2019-08-11-marrying-my-best-friend.html">I Married My Best Friend! <code>2019-08-11</code></a></li>
-<li><a href="/posts/2019-07-28-i-finally-found-a-drink-i-like.html">Finally Found a Drink I Like <code>2019-07-28</code></a></li>
-<li><a href="/posts/2019-07-21-dancing-the-shag-and-the-new-lion-king.html">Dancing the Shag & Two Left Feet <code>2019-07-21</code></a></li>
-<li><a href="/posts/2019-07-04-yabs-yet-another-bad-shop.html">YABS: Yet Another Bad Shop <code>2019-07-04</code></a></li>
-<li><a href="/posts/2019-07-04-the-best-way-to-transfer-gopro-files-with-linux.html">Offloading GoPro Footage the Easy Way! <code>2019-07-04</code></a></li>
-<li><a href="/posts/2019-06-07-how-to-start-and-drive-a-hudson-hornet.html">How to Start and Drive a Hudson Hornet <code>2019-06-07</code></a></li>
-<li><a href="/posts/2019-04-06-why-have-a-website-in-2019.html">Why Have a Web Site in 2019? <code>2019-04-06</code></a></li>
- </ul>
- </article>
- </body>
-</html>
diff --git a/index.php b/index.php
new file mode 100644
index 0000000..e94c87a
--- /dev/null
+++ b/index.php
@@ -0,0 +1,31 @@
+<?php
+include('./includes/head.php');
+?>
+
+<header>
+ <noscript>
+ JavaScript? Where we're going we don't need JavaScript.
+ </noscript>
+</header>
+
+<article>
+ <h1 style="text-align: center">
+ The World Wide Web pages of Adam Carpenter (53hornet)
+ </h1>
+ <ul>
+ <?php
+ if ($posts = glob('./posts/*.php')) {
+ $early = true;
+
+ foreach (array_reverse($posts) as $post) {
+ if (!empty($post) && $post != '.' && $post != '..') {
+ $post_name = explode('/', $post)[2];
+ $date = implode('-', array_slice(explode('-', $post_name), 0, 3));
+ include($post);
+ printf('<li><a href="/%s">%s</a> <code>%s</code></li>', $post, $title, $date);
+ }
+ }
+ }
+ ?>
+ </ul>
+</article>
diff --git a/info.html b/info.html
deleted file mode 100644
index 924d803..0000000
--- a/info.html
+++ /dev/null
@@ -1,273 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta
- property="og:image"
- content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview"
- />
- <meta property="og:site_name" content="53hor.net" />
- <meta property="og:title" content="Info" />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>53hornet ➙ Info</title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <article>
- <h1>Info</h1>
-
- <h2>About Me</h2>
-
- <p>
- My name is <em>Adam Carpenter</em> (on some sites I'm
- <em>53hornet</em>). I am a professional computer programmer, am married
- to my wonderful wife, Amy, and a puppy parent to Clementine, a Cocker
- Spaniel. This is my web site.
- </p>
- <p>
- You can find my <a href="/cv.html">CV here</a>. If you want a PDF you
- can <a href="/cv.pdf">get that here</a>.
- </p>
-
- <p>
- <img
- src="https://nextcloud.53hor.net/index.php/s/zL2AJHwtCWLX2Eq/preview"
- />
- </p>
-
- <h2>What Else Will You Find Here?</h2>
-
- <p>
- This site is my home on the web. I post things I've learned, things I
- want to share, and things I don't want to forget. I am generally
- interested in and generally post about:
- </p>
-
- <ul>
- <li>Antique automobiles, esp. my Fabulous 1953 Hudson Hornet</li>
- <li>Systems- and application-level programming</li>
- <li>Retrocomputing, esp. the Commodore 64</li>
- <li>Home servers and self-hosting</li>
- <li>FreeBSD and other *BSDs or UNIX-like operating systems</li>
- <li>Food: eating, baking, etc.</li>
- <li>Games, movies, and music</li>
- </ul>
-
- <h3>Web Log</h3>
- <p>
- I run a web log on this site. It's index is at the
- <a href="/">site index</a>.
- </p>
-
- <h3>Repos</h3>
-
- <p>
- I self-host all of my own Git repositories. You can
- <a href="https://git.53hor.net">access them here</a>.
- </p>
-
- <h3>Software, Self-Hosted Apps and Games</h3>
-
- <p>
- I self-host a variety of applications and games. A few of them are
- public. You may <a href="/software.html">access them here</a>. I also
- maintain a couple of open source projects with homepages there as well.
- </p>
-
- <h2>Contacting Me</h2>
-
- <p>
- You can write to <a href="mailto:atc@53hor.net">atc@53hor.net</a>.
- <span>
- If you want it,
- <a
- href="https://nextcloud.53hor.net/index.php/s/bX5K5JBHNnyZgr2/download"
- >here is my GPG public key</a
- >.
- </span>
- The best way to keep up with what I'm up to is to use an RSS reader on
- <a href="/rss.xml">my feed</a>.
- </p>
-
- <p>
- I've created accounts on the following sites but I check them rarely or
- not at all. The best way to reach me is by mail.
- </p>
-
- <p>
- <span>
- <a title="53hornet#2015">Discord (hover)</a>
- </span>
- <span>
- <a
- title="33FF8453F9A8E3583EFBC1185F17B466C2A76761AD7E35CBFEB9F1D977F71022FC8FBBC6AB41"
- >Tox (hover)
- </a>
- </span>
- <span>
- <a href="https://www.reddit.com/user/53hornet">Reddit</a>
- </span>
- <span>
- <a href="https://github.com/53hornet">GitHub</a>
- </span>
- <span>
- <a href="https://gitlab.com/53hornet">GitLab</a>
- </span>
- <span>
- <a href="https://www.youtube.com/user/my53hornet"
- >YouTube (53hornet)</a
- >
- </span>
- <span>
- <a href="https://www.youtube.com/user/STMUAC/about"
- >YouTube (STMUAC)</a
- >
- </span>
- <span>
- <a href="https://twitter.com/AdamCar09144367">Twitter</a>
- </span>
- <span>
- <a href="https://www.linkedin.com/in/adam-carpenter/">LinkedIn</a>
- </span>
- <span>
- <a href="https://steamcommunity.com/id/53hornet/">Steam</a>
- </span>
- <span>
- <a href="https://www.facebook.com/53hornet">Facebook</a>
- </span>
- </p>
-
- <h2>Disclaimer</h2>
-
- <p>
- The views on this web site are entirely mine! That should go without
- saying. They don't reflect my company, co-workers, friends, family, dog,
- or anyone I mention anywhere in any way.
- </p>
-
- <p>
- I prefer not to go back and edit old posts. So when you're reading
- something from 2 years ago, that was my opinion 2 years ago. Times
- change and so can I, so please try to keep that in mind.
- </p>
-
- <p>
- If I reference an external public profile or site as fact, I will do so
- with links so you can go and read the source.
- </p>
-
- <h2>Privacy</h2>
-
- <p>
- My web server has an access log. By visiting this site you're
- surrendering:
- </p>
-
- <ul>
- <li>Your public IP address</li>
- <li>Your browser's user agent</li>
- <li>The URL of the page you visited</li>
- <li>The time and date of your visit</li>
- </ul>
-
- <p>
- That's it. I do not advertise in this site, read your cookies, or
- perform any kind of social media tracking. I also proudly don't have any
- JavaScript on my site.
- </p>
-
- <h2>License</h2>
-
- <p>
- Content on this site is licensed under the
- <a href="https://creativecommons.org/licenses/by/4.0/"
- >Creative Commons Attribution 4.0 International License</a
- >.
- </p>
-
- <p>
- Source code on this site, unless otherwise stated, is licensed under the
- <a href="https://opensource.org/licenses/BSD-3-Clause">
- BSD 3-Clause license</a
- >.
- </p>
-
- <p>
- The structure and content of this page are loosely based on
- <a href="https://www.worthe-it.co.za/about.html"
- >Justin Wernick's about page</a
- >. The structure and content of my CV is loosely based on
- <a href="https://benhoyt.com/cv/">Ben Hoyt's Resume/CV</a>.
- </p>
-
- <img
- src="https://nextcloud.53hor.net/index.php/s/G3QG8FNb8aDmzcc/preview"
- />
- <img
- src="https://nextcloud.53hor.net/index.php/s/nKmSsrxa4LkRHdM/preview"
- />
-
- <p>
- <a href="https://jigsaw.w3.org/css-validator/check/referer">
- <img
- style="border: 0; width: 88px; height: 31px"
- src="https://jigsaw.w3.org/css-validator/images/vcss-blue"
- alt="Valid CSS!"
- />
- </a>
- </p>
-
- <p>
- <a href="http://www.anybrowser.org/campaign/"
- ><img
- src="path-to-graphic/graphicname"
- width="graphic-width-in-pixels"
- height="graphic-height-in-pixels"
- alt="Viewable With Any Browser"
- /></a>
- </p>
- </article>
- </body>
-</html>
diff --git a/info.php b/info.php
new file mode 100644
index 0000000..6ff3124
--- /dev/null
+++ b/info.php
@@ -0,0 +1,147 @@
+<?php
+$title = "Info";
+include('./includes/head.php');
+?>
+
+<p>
+ My name is <em>Adam Carpenter</em> (on some sites I'm
+ <em>53hornet</em>). I am a professional computer programmer, am married
+ to my wonderful wife, Amy, and a puppy parent to Clementine, a Cocker
+ Spaniel. This is my web site.
+</p>
+
+<a href="mailto:atc@53hor.net">atc@53hor.net</a>,
+
+<a href="https://nextcloud.53hor.net/index.php/s/bX5K5JBHNnyZgr2/download">GPG public key</a>
+
+<p>
+ <img src="https://nextcloud.53hor.net/index.php/s/zL2AJHwtCWLX2Eq/preview" />
+</p>
+
+<h2>What Will You Find Here?</h2>
+
+<p>
+ This site is my home on the web. I post things I've learned, things I
+ want to share, and things I don't want to forget. I am generally
+ interested in and generally post about:
+</p>
+
+<ul>
+ <li>Antique automobiles, esp. my Fabulous 1953 Hudson Hornet</li>
+ <li>Systems- and application-level programming</li>
+ <li>Retrocomputing, esp. the Commodore 64</li>
+ <li>Home servers and self-hosting</li>
+ <li>FreeBSD and other *BSDs or UNIX-like operating systems</li>
+ <li>Food: eating, baking, etc.</li>
+ <li>Games, movies, and music</li>
+</ul>
+
+<!--
+ <p>
+ <span>
+ <a title="53hornet#2015">Discord (hover)</a>
+ </span>
+ <span>
+ <a
+ title="33FF8453F9A8E3583EFBC1185F17B466C2A76761AD7E35CBFEB9F1D977F71022FC8FBBC6AB41"
+ >Tox (hover)
+ </a>
+ </span>
+ <span>
+ <a href="https://www.reddit.com/user/53hornet">Reddit</a>
+ </span>
+ <span>
+ <a href="https://github.com/53hornet">GitHub</a>
+ </span>
+ <span>
+ <a href="https://gitlab.com/53hornet">GitLab</a>
+ </span>
+ <span>
+ <a href="https://www.youtube.com/user/my53hornet"
+ >YouTube (53hornet)</a
+ >
+ </span>
+ <span>
+ <a href="https://www.youtube.com/user/STMUAC/about"
+ >YouTube (STMUAC)</a
+ >
+ </span>
+ <span>
+ <a href="https://twitter.com/AdamCar09144367">Twitter</a>
+ </span>
+ <span>
+ <a href="https://www.linkedin.com/in/adam-carpenter/">LinkedIn</a>
+ </span>
+ <span>
+ <a href="https://steamcommunity.com/id/53hornet/">Steam</a>
+ </span>
+ <span>
+ <a href="https://www.facebook.com/53hornet">Facebook</a>
+ </span>
+ </p>-->
+
+<h2>Disclaimer</h2>
+
+<p>
+ The views on this web site are entirely mine! That should go without
+ saying. They don't reflect my company, co-workers, friends, family, dog,
+ or anyone I mention anywhere in any way.
+</p>
+
+<p>
+ I prefer not to go back and edit old posts. So when you're reading
+ something from 2 years ago, that was my opinion 2 years ago. Times
+ change and so can I, so please try to keep that in mind.
+</p>
+
+<p>
+ If I reference an external public profile or site as fact, I will do so
+ with links so you can go and read the source.
+</p>
+
+<h2>Privacy</h2>
+
+<p>
+ My web server has an access log. By visiting this site you're
+ surrendering:
+</p>
+
+<ul>
+ <li>Your public IP address</li>
+ <li>Your browser's user agent</li>
+ <li>The URL of the page you visited</li>
+ <li>The time and date of your visit</li>
+</ul>
+
+<p>
+ That's it. I do not advertise on this site, read your cookies, or
+ perform any kind of social media tracking. I also proudly don't have any
+ JavaScript on my site.
+</p>
+
+<h2>License</h2>
+
+<p>
+ Content on this site is licensed under the
+ <a href="https://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.
+</p>
+
+<p>
+ Source code on this site, unless otherwise stated, is licensed under the
+ <a href="https://opensource.org/licenses/BSD-3-Clause">
+ BSD 3-Clause license</a>.
+</p>
+
+<p>
+ The structure and content of this page are loosely based on
+ <a href="https://www.worthe-it.co.za/about.html">Justin Wernick's about page</a>. The structure and content of my CV is loosely based on
+ <a href="https://benhoyt.com/cv/">Ben Hoyt's Resume/CV</a>.
+</p>
+
+<img src="https://nextcloud.53hor.net/index.php/s/G3QG8FNb8aDmzcc/preview" />
+
+<img src="https://nextcloud.53hor.net/index.php/s/nKmSsrxa4LkRHdM/preview" />
+
+<img style="border: 0; width: 88px; height: 31px" src="https://jigsaw.w3.org/css-validator/images/vcss-blue" alt="Valid CSS!" />
+
+<img src="https://nextcloud.53hor.net/index.php/s/JMqd6ACCdskmS5J/preview" width="graphic-width-in-pixels" height="graphic-height-in-pixels" alt="Viewable With Any Browser" />
diff --git a/payments.php b/payments.php
new file mode 100644
index 0000000..9a7d037
--- /dev/null
+++ b/payments.php
@@ -0,0 +1,139 @@
+<?php
+$title = "Payments";
+include('./includes/head.php');
+?>
+
+<!--PAYPAL-->
+<div id="smart-button-container" class="form">
+ <p id="invoiceidError" class="description">Please enter an Invoice ID</p>
+ <p id="descriptionError" class="description">Please enter a description</p>
+ <p id="priceLabelError" class="description">Please enter a price</p>
+
+ <div id="invoiceidDiv"><label for="invoiceid">Invoice ID</label>
+ <input name="invoiceid" maxlength="127" type="text" id="invoiceid" value="<?php echo $_GET['invoice'] ?? ''; ?> ">
+ </div>
+
+ <div><label for="description">Description of services </label>
+ <input type="text" name="descriptionInput" id="description" maxlength="127" value="<?php echo $_GET['desc'] ?? ''; ?> ">
+ </div>
+ <div><label for="amount">Amount (USD)</label>
+ <input name="amountInput" type="number" id="amount" value="<?php echo $_GET['amount'] ?? ''; ?>">
+ </div>
+ <div style="text-align: center; margin-top: 0.625rem;" id="paypal-button-container"></div>
+</div>
+
+<script src="https://www.paypal.com/sdk/js?client-id=sb&enable-funding=venmo&currency=USD" data-sdk-integration-source="button-factory"></script>
+
+<script>
+ function initPayPalButton() {
+ var description = document.querySelector('#smart-button-container #description');
+ var amount = document.querySelector('#smart-button-container #amount');
+ var descriptionError = document.querySelector('#smart-button-container #descriptionError');
+ var priceError = document.querySelector('#smart-button-container #priceLabelError');
+ var invoiceid = document.querySelector('#smart-button-container #invoiceid');
+ var invoiceidError = document.querySelector('#smart-button-container #invoiceidError');
+ var invoiceidDiv = document.querySelector('#smart-button-container #invoiceidDiv');
+
+ var elArr = [description, amount];
+
+ if (invoiceidDiv.firstChild.innerHTML.length > 1) {
+ invoiceidDiv.style.display = "block";
+ }
+
+ var purchase_units = [];
+ purchase_units[0] = {};
+ purchase_units[0].amount = {};
+
+ function validate(event) {
+ return event.value.length > 0;
+ }
+
+ // var result = elArr.every(validate);
+ // if (result) {
+ // actions.enable();
+ // }
+
+ paypal.Buttons({
+ style: {
+ color: 'white',
+ shape: 'pill',
+ label: 'pay',
+ layout: 'horizontal',
+
+ },
+
+ onInit: function(data, actions) {
+ actions.disable();
+
+ if (invoiceidDiv.style.display === "block") {
+ elArr.push(invoiceid);
+ }
+
+ elArr.forEach(function(item) {
+ item.addEventListener('keyup', function(event) {
+ var result = elArr.every(validate);
+ if (result) {
+ actions.enable();
+ } else {
+ actions.disable();
+ }
+ });
+ });
+ },
+
+ onClick: function() {
+ if (description.value.length < 1) {
+ descriptionError.style.display = "block";
+ } else {
+ descriptionError.style.display = "none";
+ }
+
+ if (amount.value.length < 1) {
+ priceError.style.display = "block";
+ } else {
+ priceError.style.display = "none";
+ }
+
+ if (invoiceid.value.length < 1 && invoiceidDiv.style.display === "block") {
+ invoiceidError.style.display = "block";
+ } else {
+ invoiceidError.style.display = "none";
+ }
+
+ purchase_units[0].description = description.value;
+ purchase_units[0].amount.value = amount.value;
+
+ if (invoiceid.value !== '') {
+ purchase_units[0].invoice_id = invoiceid.value;
+ }
+ },
+
+ createOrder: function(data, actions) {
+ return actions.order.create({
+ purchase_units: purchase_units,
+ });
+ },
+
+ onApprove: function(data, actions) {
+ return actions.order.capture().then(function(orderData) {
+
+ // Full available details
+ console.log('Capture result', orderData, JSON.stringify(orderData, null, 2));
+
+ // Show a success message within this page, e.g.
+ const element = document.getElementById('paypal-button-container');
+ element.innerHTML = '';
+ element.innerHTML = '<h3>Thank you for your payment!</h3>';
+
+ // Or go to another URL: actions.redirect('thank_you.html');
+
+ });
+ },
+
+ onError: function(err) {
+ console.log(err);
+ }
+ }).render('#paypal-button-container');
+ }
+ initPayPalButton();
+</script>
diff --git a/posts/2019-04-06-why-have-a-website-in-2019.html b/posts/2019-04-06-why-have-a-website-in-2019.html
deleted file mode 100644
index 067fe85..0000000
--- a/posts/2019-04-06-why-have-a-website-in-2019.html
+++ /dev/null
@@ -1,170 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta property="og:image" content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview" />
- <meta property="og:site_name" content="53hor.net" />
- <meta property="og:title" content="Why Have a Web Site in 2019?" />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>53hornet ➙ Why Have a Web Site in 2019?</title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <article>
- <h1>Why Have a Web Site in 2019?</h1>
- <blockquote>
- Adam, why on earth do you have a website? Wait... Is this a
- <em>blog</em>? It's 2019, why don't you just use Facebook?!
- </blockquote>
-
- <p>
- I've wanted to have my own website for a long time mostly because I like
- playing with technology. I think it's cool that I can make a few files
- on a computer in my closet available for the entire world to see. The
- web has become a near-necessity in our daily lives and it's only been
- around for a couple of decades. That has always fascinated me enough to
- drive me to see if I can do it on my own. I started self-hosting my own
- web server about a year ago now and it's been an awesome study in the
- way all of the tech we use on the web works.
- </p>
-
- <p>
- A written website is also a good way to keep up on my writing skills.
- I've graduated college and won't be writing essays for the foreseeable
- eternity. Which is fine except that I have no reason to write creatively
- or formally anymore. Having this site encourages me to continue turning
- thoughts into words, even though it's more casual than a term paper.
- </p>
-
- <p>
- This extends into the professionalism of a personal website. Normally
- you can't point your employer towards your Twitter profile as the
- distillation of your online footprint. Having a website, especially one
- that separates professional and personal interests, is ten times better
- than a resume, especially in the world of technology. It lets you tell
- people exactly who you are and what you do, without forcing them to
- navigate through an auth wall or a bunch of puppy photos. Your
- professional and personal lives don't bleed together quite as much and
- it makes for a kick-ass business card.
- </p>
-
- <p>
- Most importantly however, I enjoy the level of control that I gain with
- creating and operating my own website, something I have also sought for
- a long time. In high school I set up an old Dell from my school's
- recycling center with Windows XP and Microsoft Internet Information
- Services. It didn't have SSL or even a domain name but it was reachable
- over the WAN. I set up an upload system so that my friends and I could
- 'post' memes and funny messages for each other on raw html pages written
- with Microsoft Word. That was the extent of its functionality. It was
- slow, insecure, and went offline every time the router got a new IP
- assigned to it. But I didn't care. It was a site the school couldn't
- block. It had no name and no rules and nobody could tell us what to do
- with it because it was ours. And we called it the
- <em>Troll Nexus Center</em> because that's what you do when you're 15
- </p>
-
- <p>
- My reasons then for building the Troll Nexus Center still stand now.
- <em
- >Having your own website is having your own piece of internet
- property.</em
- >
- I first heard this wording from
- <a href="https://www.youtube.com/watch?v=azkWYxyqh3Y"
- >Luke Smith over on his YouTube channel</a
- >
- and it's one-hundred percent true. Tumblogs, Google Sites, Facebook
- profiles, and GitHub Pages are all like renting an apartment. Sure,
- there are some really nice apartments out there but it's not the same as
- owning your own home. You have to pay rent obviously, and rent is
- subject to change once your lease is up. If anything breaks you text
- your landlord and wait to have it fixed. You aren't allowed to fix it
- yourself and sometimes it doesn't get fixed at all. And of course you're
- limited by how much you can customize things to your own liking. Whether
- it's painting walls or knocking them down.
- </p>
-
- <p>
- These limitations may or may not apply to you. Whether you're paying for
- storage, server space, metrics, or watching an ad every five seconds,
- these services aren't free either. And you certainly can't fix
- everything that goes wrong with them. I started on Google Sites. It's a
- truly fantastic system. Building a site is like putting a PowerPoint
- slide together. I just plain outgrew it. There were too many things I
- wanted to do that I simply couldn't. I was also at the mercy of Google's
- constant change. After I finished constructing my first site, Google
- <a
- href="https://gsuiteupdates.googleblog.com/2016/11/a-totally-rebuilt-google-sitesnow.html"
- >announced they would be shutting down the old Google Sites in favor
- of an entirely new platform under the same name</a
- >. Weeks of work got thrown out the window. You might also not care
- about ads or customization. You may be intimidated by doing things
- yourself and prefer that the landlord take care of everything.
- Personally, I like the challenge and the craftsmanship that comes with
- doing something myself. And I like being in total control of my server,
- site, and content. Not from a tinfoil hat perspective but from a "gosh I
- really wish I could just share more than 15 gigabytes of family video
- with my relatives in New York and Ohio" perspective.
- </p>
-
- <p>
- So that's why I created my own website. If you want to know
- <em>how</em> I host my own website, look for another post about my
- server setup where I'll explain everything I'm hosting and how I got it
- all hooked up. And that's a wrap. Now you know why I'm here instead of
- somewhere else online. Sure, I do have Facebook and YouTube accounts but
- I don't frequently update anything on either of them. This site is my
- home online. It's where I keep all of my interests, hobbies, and
- memories for sharing with others.
- </p>
-
- <p>
- Now you know where to find me. If you want to keep up with me, be
- old-fashioned and subscribe to my RSS feed.
- </p>
- </article>
- </body>
-</html>
diff --git a/posts/2019-04-06-why-have-a-website-in-2019.php b/posts/2019-04-06-why-have-a-website-in-2019.php
new file mode 100644
index 0000000..b49d049
--- /dev/null
+++ b/posts/2019-04-06-why-have-a-website-in-2019.php
@@ -0,0 +1,112 @@
+<?php
+$title = "Why Have a Web Site in 2019?";
+if (isset($early) && $early) {
+ return;
+}
+include($_SERVER['DOCUMENT_ROOT'] . '/includes/head.php');
+?>
+
+<blockquote>
+ Adam, why on earth do you have a website? Wait... Is this a
+ <em>blog</em>? It's 2019, why don't you just use Facebook?!
+</blockquote>
+
+<p>
+ I've wanted to have my own website for a long time mostly because I like
+ playing with technology. I think it's cool that I can make a few files
+ on a computer in my closet available for the entire world to see. The
+ web has become a near-necessity in our daily lives and it's only been
+ around for a couple of decades. That has always fascinated me enough to
+ drive me to see if I can do it on my own. I started self-hosting my own
+ web server about a year ago now and it's been an awesome study in the
+ way all of the tech we use on the web works.
+</p>
+
+<p>
+ A written website is also a good way to keep up on my writing skills.
+ I've graduated college and won't be writing essays for the foreseeable
+ eternity. Which is fine except that I have no reason to write creatively
+ or formally anymore. Having this site encourages me to continue turning
+ thoughts into words, even though it's more casual than a term paper.
+</p>
+
+<p>
+ This extends into the professionalism of a personal website. Normally
+ you can't point your employer towards your Twitter profile as the
+ distillation of your online footprint. Having a website, especially one
+ that separates professional and personal interests, is ten times better
+ than a resume, especially in the world of technology. It lets you tell
+ people exactly who you are and what you do, without forcing them to
+ navigate through an auth wall or a bunch of puppy photos. Your
+ professional and personal lives don't bleed together quite as much and
+ it makes for a kick-ass business card.
+</p>
+
+<p>
+ Most importantly however, I enjoy the level of control that I gain with
+ creating and operating my own website, something I have also sought for
+ a long time. In high school I set up an old Dell from my school's
+ recycling center with Windows XP and Microsoft Internet Information
+ Services. It didn't have SSL or even a domain name but it was reachable
+ over the WAN. I set up an upload system so that my friends and I could
+ 'post' memes and funny messages for each other on raw html pages written
+ with Microsoft Word. That was the extent of its functionality. It was
+ slow, insecure, and went offline every time the router got a new IP
+ assigned to it. But I didn't care. It was a site the school couldn't
+ block. It had no name and no rules and nobody could tell us what to do
+ with it because it was ours. And we called it the
+ <em>Troll Nexus Center</em> because that's what you do when you're 15
+</p>
+
+<p>
+ My reasons then for building the Troll Nexus Center still stand now.
+ <em>Having your own website is having your own piece of internet
+ property.</em>
+ I first heard this wording from
+ <a href="https://www.youtube.com/watch?v=azkWYxyqh3Y">Luke Smith over on his YouTube channel</a>
+ and it's one-hundred percent true. Tumblogs, Google Sites, Facebook
+ profiles, and GitHub Pages are all like renting an apartment. Sure,
+ there are some really nice apartments out there but it's not the same as
+ owning your own home. You have to pay rent obviously, and rent is
+ subject to change once your lease is up. If anything breaks you text
+ your landlord and wait to have it fixed. You aren't allowed to fix it
+ yourself and sometimes it doesn't get fixed at all. And of course you're
+ limited by how much you can customize things to your own liking. Whether
+ it's painting walls or knocking them down.
+</p>
+
+<p>
+ These limitations may or may not apply to you. Whether you're paying for
+ storage, server space, metrics, or watching an ad every five seconds,
+ these services aren't free either. And you certainly can't fix
+ everything that goes wrong with them. I started on Google Sites. It's a
+ truly fantastic system. Building a site is like putting a PowerPoint
+ slide together. I just plain outgrew it. There were too many things I
+ wanted to do that I simply couldn't. I was also at the mercy of Google's
+ constant change. After I finished constructing my first site, Google
+ <a href="https://gsuiteupdates.googleblog.com/2016/11/a-totally-rebuilt-google-sitesnow.html">announced they would be shutting down the old Google Sites in favor
+ of an entirely new platform under the same name</a>. Weeks of work got thrown out the window. You might also not care
+ about ads or customization. You may be intimidated by doing things
+ yourself and prefer that the landlord take care of everything.
+ Personally, I like the challenge and the craftsmanship that comes with
+ doing something myself. And I like being in total control of my server,
+ site, and content. Not from a tinfoil hat perspective but from a "gosh I
+ really wish I could just share more than 15 gigabytes of family video
+ with my relatives in New York and Ohio" perspective.
+</p>
+
+<p>
+ So that's why I created my own website. If you want to know
+ <em>how</em> I host my own website, look for another post about my
+ server setup where I'll explain everything I'm hosting and how I got it
+ all hooked up. And that's a wrap. Now you know why I'm here instead of
+ somewhere else online. Sure, I do have Facebook and YouTube accounts but
+ I don't frequently update anything on either of them. This site is my
+ home online. It's where I keep all of my interests, hobbies, and
+ memories for sharing with others.
+</p>
+
+<p>
+ Now you know where to find me. If you want to keep up with me, be
+ old-fashioned and subscribe to my RSS feed.
+</p>
diff --git a/posts/2019-06-07-how-to-start-and-drive-a-hudson-hornet.html b/posts/2019-06-07-how-to-start-and-drive-a-hudson-hornet.html
deleted file mode 100644
index 569d925..0000000
--- a/posts/2019-06-07-how-to-start-and-drive-a-hudson-hornet.html
+++ /dev/null
@@ -1,322 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta property="og:image" content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview" />
- <meta property="og:site_name" content="53hor.net" />
- <meta
- property="og:title"
- content="How to Start and Drive a Hudson Hornet"
- />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>53hornet ➙ How to Start and Drive a Hudson Hornet</title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <article>
- <h1>How to Start and Drive a Hudson Hornet</h1>
-
- <p class="description">
- My understanding is there are a lot of people out there for whom driving
- a car from the mid-20th century is an oddity, a curiosity, or a life
- experience they can't relate to. This is for the non-experts, and
- non-Hudsonites to get an idea of what it's like.
- </p>
-
- <p>
- There are some significant differences between driving the Hornet and
- most other cars you come across today. Some of them are just because
- there are sixty-six years between the Hudson and the 2019 model year.
- Others are Hudson-specific. Many people who I've talked to have said
- that they would feel intimidated driving my car (whether that's because
- of its perceived complexity or obvious value to me). So, for those who
- just want to know how it's done: here is how you start and drive a
- Hudson Hornet.
- </p>
-
- <h2>The Gauge Cluster, Switches, and Controls</h2>
-
- <p>
- Open the door, slide onto the bench seat, and sit behind the [massive]
- steering wheel. For those who haven't experienced it before, it feels
- like you have a whole lot of room at your disposal, almost like there
- <em>should</em> be more matter occupying the space around you. In front
- of you is probably the shiniest dashboard you've ever seen. It's simple,
- and probably slightly familiar.
- </p>
- <p>From left to right above the steering wheel you have:</p>
- <ul>
- <li>
- A speedometer that tops out at 120 mph (with 99K odometer inside)
- </li>
- <li>
- Fuel and coolant temperature gauges (and two dummy lights; more on
- those later)
- </li>
- <li>A clock</li>
- <li>An AM radio</li>
- <li>A glove compartment</li>
- </ul>
-
- <p>From left to right under the steering wheel you have:</p>
- <ul>
- <li>A 2-speed wiper control knob</li>
- <li>A weather control (heater) temperature slider</li>
- <li>A 2-speed weather control fan knob</li>
- <li>The ignition barrel</li>
- <li>A headlight switch</li>
- <li>
- A cigarette-lighter (the owner's manual calls it a cigar lighter!)
- </li>
- </ul>
-
- <p>
- Also, underneath the dashboard on the left there is a parking brake
- handle and hood latch release and on the right there is an arm which
- raises and lowers the fresh air cowl vent. Think of it as "recirculate"
- in more modern vehicles. If you're looking for the turn signal lever
- it's the tiny stick to the left of the steering wheel. The indicator is
- the little yellow light on the far left of the dash. There's only one so
- it flashes when you're signalling left or right. We also added our own
- air conditioning system, something Hudsons never came with from the
- factory.
- </p>
-
- <h2>Dual-Range Hydramatic</h2>
-
- <p>
- The first thing that might confuse some folks when they first see the
- car running is the shift lever. Many Hornets came with three-speed
- manual transmissions that were shifted from the column (overdrive was an
- option). However, lots of owners paid extra for the optional "Dual-range
- Hydramatic", a fully automatic transmission from General Motors. Truly,
- this car has a 4-speed automatic that requires no manual shifting during
- normal use, making it that much easier to take a boatload of people to
- get milkshakes.
- </p>
-
- <p>
- Behind the steering wheel is a shift indicator that deviates from the
- "PRNDL" pattern most folks are familiar with. From left to right (shift
- arm fully at the top to arm fully towards the bottom), the 'gears' are:
- </p>
- <ul>
- <li>N (Neutral)</li>
- <li>4-Dr (Drive, all four speeds)</li>
- <li>3-Dr (Drive, three speeds only)</li>
- <li>Lo (Low gear)</li>
- <li>R (Reverse)</li>
- </ul>
-
- <p>
- Neutral isn't just a mid-way point between reverse and drive in this
- car. It's a necessity. With automatic Hornets (and Hydramatics in
- general), neutral is used to start the car. There is an electric lockout
- preventing the car from being started in any gear but neutral, so you do
- have to put the car in neutral before you turn the key (if you're on a
- hill put your foot on the brake or engage the parking brake).
- </p>
-
- <p>
- Drive is split into 4-Dr and 3-Dr, which basically decides whether the
- transmission utilizes high gear. In the owner's manual, Hudson
- recommends using 3-Dr for driving around town (as the low RPMs delivered
- by high gear means unnecessary shifting in and out of 4th gear) and 4-Dr
- for highway driving. It really depends on what speed you're going to be
- driving at but there isn't anything wrong with driving around in 4 all
- the time. I typically leave it in 4th at sustained speeds above 45MPH.
- You can switch between these gears any time while moving.
- </p>
-
- <p>
- Low gear basically locks the transmission in 2nd gear so you don't spin
- the wheels. The owner's manual says this is for pulling out of sand or
- dirt if you get stuck.
- </p>
-
- <p>
- Reverse works just about how you might expect but with an added catch:
- if the engine is off it acts as park. That's right. When you turn the
- car off you can put it in reverse and the transmission will engage a
- lock pin to prevent the car from rolling. You can't start the car in
- this gear because of the lockout however so you have to shift into
- neutral to start the car. So for starting, put it in neutral, for
- stopping, put it in reverse.
- </p>
-
- <h2>Choke and Gas</h2>
-
- <p>
- For cold starts, our Hornet (and I believe this was common for other
- Hudsons of the time) is equipped with an automatic 2-stage choke. Push
- the pedal all the way to the floor once to set the choke. After the car
- has started and has warmed up, kick the gas quickly to the floor and
- release to cancel the choke.
- </p>
-
- <p>
- For warm starts the engine doesn't need the choke but likes to be given
- just a little bit of gas while cranking.
- </p>
-
- <h2>The Keys, Ignition, and Warning Lights</h2>
-
- <p>
- Hudsons like mine come with two keys. The octagonal one is for starting
- the car, it's used in the ignition. The round one is used for the door
- and trunk locks (and I believe in my case the glove box). My
- understanding is this is actually reversed from the majority of Hudsons
- and is due to a locksmith error at one point or another.
- </p>
-
- <p>
- The ignition switch sits so that the teeth of the key enter vertically.
- Turning the key left powers accessories like the radio. Turning the key
- right once switches the car to "ON" which will allow the engine to be
- started and remain running.
- </p>
-
- <p>
- Here's where some things may vary depending on the year of the car. For
- '51 Hornets, there's a separate starter button located all the way on
- the left control pod. For these cars, you put the key in and turn it to
- "ON", and then press and hold the button until the car has started up.
- For '52 Hornets onwards, the ignition switch also activates the starter
- if you turn the key past "ON" (like in most modern vehicles).
- </p>
-
- <p>
- If you turn the key to "ON" you'll see two red warning lights appear on
- the dash next to the indicators marked "AMP" and "OIL". These are
- [alternator] charging status and oil pressure status lights. Our car is
- equipped with a 12-V alternator system so the AMP light really comes on
- if there is low voltage while the oil pressure light comes on when
- there's low oil pressure. These lights will only appear with engine off,
- key "ON" or if something has gone very wrong.
- </p>
-
- <h2>Starting and Driving</h2>
-
- <p>
- So now that I've gone over the basics of all the components, here is the
- normal starting procedure. It actually varies depending on whether the
- engine has been warmed up. That's life with carburetors.
- </p>
-
- <h3>From cold:</h3>
-
- <ul>
- <li>
- Put your foot on the brake, and shift the lever into neutral. Just
- push it vertically, pulling towards you slightly if you need to.
- </li>
- <li>
- Push the gas pedal all the way to the floor once and let your foot
- back up again to set the choke.
- </li>
- <li>
- Put the key in the ignition and start the car (the "AMP" and "OIL"
- lights should switch off.
- </li>
- <li>
- Wait for the engine to smooth out so you know that it's warm enough to
- cancel the choke, and kick the gas pedal once to cancel it. (If the
- RPMs are still higher than idle then it's not quite at operating
- temperature yet)
- </li>
- <li>
- Pull the shifter down into 4-Dr or 3-Dr (or R), and release the
- parking brake by twisting the handle towards the steering wheel
- </li>
- <li>Let off the brake and you're off!</li>
- </ul>
-
- <h3>From warm:</h3>
-
- <ul>
- <li>Put your foot on the brake and shift into neutral.</li>
- <li>
- While giving just a little bit of gas, start the car. Both warning
- lights should disappear. When the engine fires up you can let off the
- gas and let it idle.
- </li>
- <li>
- Pull the shifter into 4-Dr or 3-Dr (or R), and release the parking
- brake by twisting the handle towards the steering wheel.
- </li>
- <li>Done.</li>
- </ul>
-
- <h2>Stopping and Parking</h2>
-
- <ul>
- <li>
- Hold your foot on the brake and twist the parking brake handle towards
- the door of the car, and pull it towards you
- </li>
- <li>
- When you're ready to shut off the engine, you can shift it into either
- neutral or reverse and turn the key off. Shift it into reverse if you
- haven't already to lock the transmission.
- </li>
- </ul>
-
- <p>
- Note: I usually engage the parking brake AND put the car in reverse,
- just to be safe. If you had to pick one however I would use the
- transmission in case you're on a steep hill and your brakes fail for
- whatever reason.
- </p>
-
- <p>
- And there you have it! Not much is different from most cars around today
- but there are one or two quirks (more about old cars than about Hudsons
- in particular). The only major thing to keep track of while driving is
- that you have no power steering, so get ready to anticipate turns sooner
- and use more of the wheel with every turn.
- </p>
- </article>
- </body>
-</html>
diff --git a/posts/2019-06-07-how-to-start-and-drive-a-hudson-hornet.php b/posts/2019-06-07-how-to-start-and-drive-a-hudson-hornet.php
new file mode 100644
index 0000000..53e0f40
--- /dev/null
+++ b/posts/2019-06-07-how-to-start-and-drive-a-hudson-hornet.php
@@ -0,0 +1,267 @@
+<?php
+$title = "How to Start and Drive a Hudson Hornet";
+if (isset($early) && $early) {
+ return;
+}
+include($_SERVER['DOCUMENT_ROOT'] . '/includes/head.php');
+?>
+
+<p class="description">
+ My understanding is there are a lot of people out there for whom driving
+ a car from the mid-20th century is an oddity, a curiosity, or a life
+ experience they can't relate to. This is for the non-experts, and
+ non-Hudsonites to get an idea of what it's like.
+</p>
+
+<p>
+ There are some significant differences between driving the Hornet and
+ most other cars you come across today. Some of them are just because
+ there are sixty-six years between the Hudson and the 2019 model year.
+ Others are Hudson-specific. Many people who I've talked to have said
+ that they would feel intimidated driving my car (whether that's because
+ of its perceived complexity or obvious value to me). So, for those who
+ just want to know how it's done: here is how you start and drive a
+ Hudson Hornet.
+</p>
+
+<h2>The Gauge Cluster, Switches, and Controls</h2>
+
+<p>
+ Open the door, slide onto the bench seat, and sit behind the [massive]
+ steering wheel. For those who haven't experienced it before, it feels
+ like you have a whole lot of room at your disposal, almost like there
+ <em>should</em> be more matter occupying the space around you. In front
+ of you is probably the shiniest dashboard you've ever seen. It's simple,
+ and probably slightly familiar.
+</p>
+<p>From left to right above the steering wheel you have:</p>
+<ul>
+ <li>
+ A speedometer that tops out at 120 mph (with 99K odometer inside)
+ </li>
+ <li>
+ Fuel and coolant temperature gauges (and two dummy lights; more on
+ those later)
+ </li>
+ <li>A clock</li>
+ <li>An AM radio</li>
+ <li>A glove compartment</li>
+</ul>
+
+<p>From left to right under the steering wheel you have:</p>
+<ul>
+ <li>A 2-speed wiper control knob</li>
+ <li>A weather control (heater) temperature slider</li>
+ <li>A 2-speed weather control fan knob</li>
+ <li>The ignition barrel</li>
+ <li>A headlight switch</li>
+ <li>
+ A cigarette-lighter (the owner's manual calls it a cigar lighter!)
+ </li>
+</ul>
+
+<p>
+ Also, underneath the dashboard on the left there is a parking brake
+ handle and hood latch release and on the right there is an arm which
+ raises and lowers the fresh air cowl vent. Think of it as "recirculate"
+ in more modern vehicles. If you're looking for the turn signal lever
+ it's the tiny stick to the left of the steering wheel. The indicator is
+ the little yellow light on the far left of the dash. There's only one so
+ it flashes when you're signalling left or right. We also added our own
+ air conditioning system, something Hudsons never came with from the
+ factory.
+</p>
+
+<h2>Dual-Range Hydramatic</h2>
+
+<p>
+ The first thing that might confuse some folks when they first see the
+ car running is the shift lever. Many Hornets came with three-speed
+ manual transmissions that were shifted from the column (overdrive was an
+ option). However, lots of owners paid extra for the optional "Dual-range
+ Hydramatic", a fully automatic transmission from General Motors. Truly,
+ this car has a 4-speed automatic that requires no manual shifting during
+ normal use, making it that much easier to take a boatload of people to
+ get milkshakes.
+</p>
+
+<p>
+ Behind the steering wheel is a shift indicator that deviates from the
+ "PRNDL" pattern most folks are familiar with. From left to right (shift
+ arm fully at the top to arm fully towards the bottom), the 'gears' are:
+</p>
+<ul>
+ <li>N (Neutral)</li>
+ <li>4-Dr (Drive, all four speeds)</li>
+ <li>3-Dr (Drive, three speeds only)</li>
+ <li>Lo (Low gear)</li>
+ <li>R (Reverse)</li>
+</ul>
+
+<p>
+ Neutral isn't just a mid-way point between reverse and drive in this
+ car. It's a necessity. With automatic Hornets (and Hydramatics in
+ general), neutral is used to start the car. There is an electric lockout
+ preventing the car from being started in any gear but neutral, so you do
+ have to put the car in neutral before you turn the key (if you're on a
+ hill put your foot on the brake or engage the parking brake).
+</p>
+
+<p>
+ Drive is split into 4-Dr and 3-Dr, which basically decides whether the
+ transmission utilizes high gear. In the owner's manual, Hudson
+ recommends using 3-Dr for driving around town (as the low RPMs delivered
+ by high gear means unnecessary shifting in and out of 4th gear) and 4-Dr
+ for highway driving. It really depends on what speed you're going to be
+ driving at but there isn't anything wrong with driving around in 4 all
+ the time. I typically leave it in 4th at sustained speeds above 45MPH.
+ You can switch between these gears any time while moving.
+</p>
+
+<p>
+ Low gear basically locks the transmission in 2nd gear so you don't spin
+ the wheels. The owner's manual says this is for pulling out of sand or
+ dirt if you get stuck.
+</p>
+
+<p>
+ Reverse works just about how you might expect but with an added catch:
+ if the engine is off it acts as park. That's right. When you turn the
+ car off you can put it in reverse and the transmission will engage a
+ lock pin to prevent the car from rolling. You can't start the car in
+ this gear because of the lockout however so you have to shift into
+ neutral to start the car. So for starting, put it in neutral, for
+ stopping, put it in reverse.
+</p>
+
+<h2>Choke and Gas</h2>
+
+<p>
+ For cold starts, our Hornet (and I believe this was common for other
+ Hudsons of the time) is equipped with an automatic 2-stage choke. Push
+ the pedal all the way to the floor once to set the choke. After the car
+ has started and has warmed up, kick the gas quickly to the floor and
+ release to cancel the choke.
+</p>
+
+<p>
+ For warm starts the engine doesn't need the choke but likes to be given
+ just a little bit of gas while cranking.
+</p>
+
+<h2>The Keys, Ignition, and Warning Lights</h2>
+
+<p>
+ Hudsons like mine come with two keys. The octagonal one is for starting
+ the car, it's used in the ignition. The round one is used for the door
+ and trunk locks (and I believe in my case the glove box). My
+ understanding is this is actually reversed from the majority of Hudsons
+ and is due to a locksmith error at one point or another.
+</p>
+
+<p>
+ The ignition switch sits so that the teeth of the key enter vertically.
+ Turning the key left powers accessories like the radio. Turning the key
+ right once switches the car to "ON" which will allow the engine to be
+ started and remain running.
+</p>
+
+<p>
+ Here's where some things may vary depending on the year of the car. For
+ '51 Hornets, there's a separate starter button located all the way on
+ the left control pod. For these cars, you put the key in and turn it to
+ "ON", and then press and hold the button until the car has started up.
+ For '52 Hornets onwards, the ignition switch also activates the starter
+ if you turn the key past "ON" (like in most modern vehicles).
+</p>
+
+<p>
+ If you turn the key to "ON" you'll see two red warning lights appear on
+ the dash next to the indicators marked "AMP" and "OIL". These are
+ [alternator] charging status and oil pressure status lights. Our car is
+ equipped with a 12-V alternator system so the AMP light really comes on
+ if there is low voltage while the oil pressure light comes on when
+ there's low oil pressure. These lights will only appear with engine off,
+ key "ON" or if something has gone very wrong.
+</p>
+
+<h2>Starting and Driving</h2>
+
+<p>
+ So now that I've gone over the basics of all the components, here is the
+ normal starting procedure. It actually varies depending on whether the
+ engine has been warmed up. That's life with carburetors.
+</p>
+
+<h3>From cold:</h3>
+
+<ul>
+ <li>
+ Put your foot on the brake, and shift the lever into neutral. Just
+ push it vertically, pulling towards you slightly if you need to.
+ </li>
+ <li>
+ Push the gas pedal all the way to the floor once and let your foot
+ back up again to set the choke.
+ </li>
+ <li>
+ Put the key in the ignition and start the car (the "AMP" and "OIL"
+ lights should switch off.
+ </li>
+ <li>
+ Wait for the engine to smooth out so you know that it's warm enough to
+ cancel the choke, and kick the gas pedal once to cancel it. (If the
+ RPMs are still higher than idle then it's not quite at operating
+ temperature yet)
+ </li>
+ <li>
+ Pull the shifter down into 4-Dr or 3-Dr (or R), and release the
+ parking brake by twisting the handle towards the steering wheel
+ </li>
+ <li>Let off the brake and you're off!</li>
+</ul>
+
+<h3>From warm:</h3>
+
+<ul>
+ <li>Put your foot on the brake and shift into neutral.</li>
+ <li>
+ While giving just a little bit of gas, start the car. Both warning
+ lights should disappear. When the engine fires up you can let off the
+ gas and let it idle.
+ </li>
+ <li>
+ Pull the shifter into 4-Dr or 3-Dr (or R), and release the parking
+ brake by twisting the handle towards the steering wheel.
+ </li>
+ <li>Done.</li>
+</ul>
+
+<h2>Stopping and Parking</h2>
+
+<ul>
+ <li>
+ Hold your foot on the brake and twist the parking brake handle towards
+ the door of the car, and pull it towards you
+ </li>
+ <li>
+ When you're ready to shut off the engine, you can shift it into either
+ neutral or reverse and turn the key off. Shift it into reverse if you
+ haven't already to lock the transmission.
+ </li>
+</ul>
+
+<p>
+ Note: I usually engage the parking brake AND put the car in reverse,
+ just to be safe. If you had to pick one however I would use the
+ transmission in case you're on a steep hill and your brakes fail for
+ whatever reason.
+</p>
+
+<p>
+ And there you have it! Not much is different from most cars around today
+ but there are one or two quirks (more about old cars than about Hudsons
+ in particular). The only major thing to keep track of while driving is
+ that you have no power steering, so get ready to anticipate turns sooner
+ and use more of the wheel with every turn.
+</p>
diff --git a/posts/2019-07-04-the-best-way-to-transfer-gopro-files-with-linux.html b/posts/2019-07-04-the-best-way-to-transfer-gopro-files-with-linux.html
deleted file mode 100644
index 8a0e587..0000000
--- a/posts/2019-07-04-the-best-way-to-transfer-gopro-files-with-linux.html
+++ /dev/null
@@ -1,127 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta property="og:image" content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview" />
- <meta property="og:site_name" content="53hor.net" />
- <meta
- property="og:title"
- content="Offloading GoPro Footage the Easy Way!"
- />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>53hornet ➙ Offloading GoPro Footage the Easy Way!</title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <article>
- <h1>Offloading GoPro Footage the Easy Way!</h1>
-
- <p>
- Transferring files off of most cameras to a Linux computer isn't all
- that difficult. The exception is my GoPro Hero 4 Black. For 4th of July
- week I took a bunch of video with the GoPro, approximately 20 MP4 files,
- about 3GB each. The annoying thing about the GoPro's USB interface is
- you need additional software to download everything through the cable.
- The camera doesn't just show up as a USB filesystem that you can mount.
- The GoPro does have a micro-SD card but I was away from home and didn't
- have any dongles or adapters. Both of these solutions also mean taking
- the camera out of its waterproof case and off of its mount. So here's
- what I did.
- </p>
-
- <p>
- GoPro cameras, after the Hero 3, can open up an ad-hoc wireless network
- that lets you browse the GoPro's onboard files through an HTTP server.
- This means you can open your browser and scroll through the files on the
- camera at an intranet address, <code>10.5.5.9</code>, and download them
- one by one by clicking every link on every page. If you have a lot of
- footage on there it kinda sucks. So, I opened up the manual for
- <code>wget</code>. I'm sure you could get really fancy with some of the
- options but the only thing I cared about was downloading every single
- MP4 video off of the camera, automatically. I did not want to download
- any of the small video formats or actual HTML files. Here's what I used:
- </p>
-
- <pre>
- <code>
-sh wget --recursive --accept "*.MP4" http://10.5.5.9:8080/
- </code>
- </pre>
-
- <p>
- This tells <code>wget</code> to download all of the files at the GoPro's
- address recursively and skips any that don't have the MP4 extension. Now
- I've got a directory tree with all of my videos in it. And the best part
- is I didn't have to install the dinky GoPro app on my laptop. Hopefully
- this helps if you're looking for an easy way to migrate lots of footage
- without manually clicking through the web interface or installing
- additional software. The only downside is if you're moving a whole lot
- of footage, it's not nearly as quick as just moving files off the SD
- card. So I'd shoot for using the adapter to read off the card first and
- only use this if that's not an option, such as when the camera is
- mounted and you don't want to move it.
- </p>
-
- <p>Some things I would like to change/add:</p>
-
- <ul>
- <li>
- Download all image files as well; should be easy, just another
- <code>--accept</code>
- </li>
- <li>Initiate parallel downloads</li>
- <li>
- Clean up the directory afterwards so I just have one level of depth
- </li>
- </ul>
-
- <p>
- I could probably write a quick and dirty shell script to do all of this
- for me but I use the camera so infrequently that it's probably not even
- worth it.
- </p>
- </article>
- </body>
-</html>
diff --git a/posts/2019-07-04-the-best-way-to-transfer-gopro-files-with-linux.php b/posts/2019-07-04-the-best-way-to-transfer-gopro-files-with-linux.php
new file mode 100644
index 0000000..34685de
--- /dev/null
+++ b/posts/2019-07-04-the-best-way-to-transfer-gopro-files-with-linux.php
@@ -0,0 +1,72 @@
+<?php
+$title = "Offloading GoPro Footage the Easy Way!";
+if (isset($early) && $early) {
+ return;
+}
+include($_SERVER['DOCUMENT_ROOT'] . '/includes/head.php');
+?>
+
+<p>
+ Transferring files off of most cameras to a Linux computer isn't all
+ that difficult. The exception is my GoPro Hero 4 Black. For 4th of July
+ week I took a bunch of video with the GoPro, approximately 20 MP4 files,
+ about 3GB each. The annoying thing about the GoPro's USB interface is
+ you need additional software to download everything through the cable.
+ The camera doesn't just show up as a USB filesystem that you can mount.
+ The GoPro does have a micro-SD card but I was away from home and didn't
+ have any dongles or adapters. Both of these solutions also mean taking
+ the camera out of its waterproof case and off of its mount. So here's
+ what I did.
+</p>
+
+<p>
+ GoPro cameras, after the Hero 3, can open up an ad-hoc wireless network
+ that lets you browse the GoPro's onboard files through an HTTP server.
+ This means you can open your browser and scroll through the files on the
+ camera at an intranet address, <code>10.5.5.9</code>, and download them
+ one by one by clicking every link on every page. If you have a lot of
+ footage on there it kinda sucks. So, I opened up the manual for
+ <code>wget</code>. I'm sure you could get really fancy with some of the
+ options but the only thing I cared about was downloading every single
+ MP4 video off of the camera, automatically. I did not want to download
+ any of the small video formats or actual HTML files. Here's what I used:
+</p>
+
+<pre>
+ <code>
+sh wget --recursive --accept "*.MP4" http://10.5.5.9:8080/
+ </code>
+ </pre>
+
+<p>
+ This tells <code>wget</code> to download all of the files at the GoPro's
+ address recursively and skips any that don't have the MP4 extension. Now
+ I've got a directory tree with all of my videos in it. And the best part
+ is I didn't have to install the dinky GoPro app on my laptop. Hopefully
+ this helps if you're looking for an easy way to migrate lots of footage
+ without manually clicking through the web interface or installing
+ additional software. The only downside is if you're moving a whole lot
+ of footage, it's not nearly as quick as just moving files off the SD
+ card. So I'd shoot for using the adapter to read off the card first and
+ only use this if that's not an option, such as when the camera is
+ mounted and you don't want to move it.
+</p>
+
+<p>Some things I would like to change/add:</p>
+
+<ul>
+ <li>
+ Download all image files as well; should be easy, just another
+ <code>--accept</code>
+ </li>
+ <li>Initiate parallel downloads</li>
+ <li>
+ Clean up the directory afterwards so I just have one level of depth
+ </li>
+</ul>
+
+<p>
+ I could probably write a quick and dirty shell script to do all of this
+ for me but I use the camera so infrequently that it's probably not even
+ worth it.
+</p>
diff --git a/posts/2019-07-04-yabs-yet-another-bad-shop.html b/posts/2019-07-04-yabs-yet-another-bad-shop.html
deleted file mode 100644
index 371f151..0000000
--- a/posts/2019-07-04-yabs-yet-another-bad-shop.html
+++ /dev/null
@@ -1,235 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta property="og:image" content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview" />
- <meta property="og:site_name" content="53hor.net" />
- <meta property="og:title" content="YABS: Yet Another Bad Shop" />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>53hornet ➙ YABS: Yet Another Bad Shop</title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <article>
- <h1>YABS: Yet Another Bad Shop</h1>
- <p>
- Today I received a text message from a local mechanic/auto shop asking
- me to leave them a Google review. It was an automated message from a
- shop that I know well and have used many times in the past.
- Unfortunately, I have had several poor experiences (at the time they
- seemed horrific) with them in the past year and I can honestly say
- they'll never receive my business again. Now I could have used this as
- an opportunity to leave them an anonymous nasty-gram but instead I'm
- going to do the opposite. I'm going to write about everything I don't
- like about them without telling you who they are or hiding who I am. Why
- would I do that? Well for one, they were an excellent shop for many
- years. I believe a recent change in management is to blame and I'm not
- going to ruin their chances of making a comeback (because frankly I
- would like for them to rebound). And secondly, I don't believe in
- hiding. This page and its author are public knowledge. Now, in no
- particular order: a sample of awful work from yet another bad shop.
- </p>
-
- <h2>Mom's Truck -- Balls Out</h2>
-
- <p>
- Mom's truck is a 2007 Chrysler Aspen that she loves very much. Dad does
- a whole lot of work on it himself (the both of us do pretty much
- everything we can in-house so long as we have the right equipment).
- We've been taking her truck into this shop for years because we've found
- them to be reliable, efficient, and economical. As I said before, at
- some point in their recent history they changed hands -- either
- ownership or management, I can't remember which. It was around this time
- that Dad decided to overhaul Mom's front suspension. He replaced the
- ball joints, tie rod ends, and a few other worn out parts. He then did
- his own best-guess front-end alignment, but left everything loose so
- that YABS could finish up the alignment and tighten everything. Now read
- that again because it's important. Dad did his own alignment in our
- driveway (as a cost-saving measure), got it decently close, but then
- instructed this shop to finish the job and tighten everything up.
- </p>
-
- <p>
- Now here's where things fall apart. This shop full of professional
- mechanics took one look at the alignment Dad did and decided it was good
- enough. Hooray for Dad and supernatural mechanical skills, but the shop
- didn't even touch the car. They called Dad back to come pick up the car,
- telling him it was already good to go. They never tightened a thing,
- even after Dad explicitly told them everything was loose and needed to
- be tightened but they didn't to touch a thing. So what happened? Dad
- picked up the car assuming everything was A-OK and Mom drove the car for
- about a week before the two front tires wore down so badly they had to
- be replaced immediately. Everything fell out of alignment as things
- loosened further and further and the tires wore unevenly until they
- ripped themselves to shreds. The worst part? These weren't tires with 6+
- years on them. These were brand new tires. So YABS got to install two
- more front tires and then tighten everything. They did not cover the
- costs, presumably because it was Dad who had done the alignment. Strike
- one.
- </p>
-
- <h2>Friend's Minivan -- Crude Necessities</h2>
-
- <p>
- A good friend of ours drives a 2005-2006 Chrysler Town and Country. It
- was actually Mom's car before upgrading to the Aspen (the minivan was
- perfect in every way but it couldn't tow). Our friend has been using
- YABS for just a long as we have. Once again, things started getting
- kinda strange after several years of good service. She started getting
- charged extra for simple repairs she had them doing very consistently.
- They also started tacking on extra items for routine jobs. She would go
- in for an inspection and they would claim she needed a new Part X. Now
- this in and of itself isn't an uncommon or even strange request to make.
- As cars age they need things and sometimes you don't know what they need
- until you visit a professional mechanic. They remember the things you
- forget about.
- </p>
-
- <p>
- One day they did all the forgetting, and they forgot a pretty important,
- nay, crucial engine component: motor oil. Our friend took her minivan
- into YABS for a routine oil change. Good diligence on her part. And
- she's not the type to do that change on her own. She's too old to get
- under a car anyway (no offense!). So she took the van to YABS and they
- did a job they've done thousands of times: drain oil, replaced the
- filter, and gave her back the car. Easy peasy right? Now I know I'm not
- a professional but I'm thinking someone might have wanted to
- double-check that several quarts of synthetic had left the shop shelf
- and gone into the car they just backed out of the bay door. Now this
- part of the story I'm a little fuzzy on so take it with a large, heaping
- grain of salt, but I can say for a fact that they failed to
- <em>completely</em> refill the engine oil before returning her car.
- Supposedly there was enough in there such that the minivan survived long
- enough for them to realize it before she drove off.
- </p>
-
- <h2>Monty, My 2013 Ford Focus -- Nut Allergy</h2>
-
- <p>
- I decided to give YABS another try after a long leave of absence. I
- needed new tires all around for my daily driver. I also needed an
- inspection and an alignment. A simple set of tasks for any shop (you see
- where this is going). I initially tried to go to another local shop but
- they were all out of the tires I was looking to get so I caved and went
- to YABS. About halfway through the job they gave me a call and told me
- they had some bad news. They said that there were some issues getting
- the lug nuts off my wheels and that they had all been stripped, warped,
- or otherwise destroyed in the process. They told me the only fix was to
- get new ones from a supplier in town for about $160. Keep in mind the
- entire job (inspection, tires, etc.) was going to cost $650.
- Furthermore, dad and I had no problem getting those lug nuts off and
- back on again just a few weeks prior when we changed the transmission
- fluid.
- </p>
-
- <p>
- They didn't have an explanation that I could reconcile with. Joe Schmo
- over the phone told me this is typical of Fords and Chryslers these days
- and that they'd like to keep my lug nuts for a class action lawsuit
- they're participating in. Now why on Earth would any sane mechanic, with
- full knowledge they are dealing with a defective set of lug nuts, take a
- high power impact wrench to those wheels without speaking with the owner
- about it first? Smelled fishy to me honestly. But what was I gonna do?
- Dad went out and grabbed twenty new lug nuts for cheaper than they
- wanted to sell them for.
- </p>
-
- <p>
- Oh the tires were Cooper GTs by the way and they're amazing. They're
- smooth and quiet and came with a very nice warranty. They're also made
- in the USA, which is very important to me. 10/10 would recommend.
- </p>
-
- <h2>Ol' Blue -- Tunnel Vision</h2>
-
- <p>
- This was the real kicker. And this one doesn't really have any trailing
- narrative. I got four new tires on Ol' Blue, my 1953 Hudson Hornet. They
- were delivered to our house: four brand new Diamond Back wide white wall
- radials. Super nice tires, with a super nice road hazard warranty (as a
- side note I totally recommend you
- <a href="https://dbtires.com/">check out Diamond Back's website</a> if
- you're looking for white wall radials). So we brought the car to YABS
- with the new tires and asked them to mount them on the car.
- </p>
-
- <p>
- When we went to pick up the car everything looked great and I drove off.
- I made it all the way to the Monitor Merrimack Memorial Bridge Tunnel
- before I heard a loud rattling and a bang. I looked in the rear-view
- mirror and swore I could see my precious hubcap rolling off to eternity.
- When they replaced the hubcaps they didn't fully press one of them on.
- And it's not that difficult. These hub caps are very secure when pressed
- on the rim, we've never had problems with them. Oh and we're talking
- about Hudson hubcaps that came with the car, and aren't super easy to
- find. And I couldn't stop to get out and grab it because I was right at
- the mouth of the tunnel. We went back later to try and see it but we
- couldn't. And it was probably destroyed getting thrown from the car
- anyways.
- </p>
-
- <p>
- The worst part is, the hubcap took a chunk out of my white wall on its
- way out from under the wheel skirt. So the day I got the tires I had to
- take a picture and redeem my road hazard warranty. Luckily, Diamond Back
- were true to their word and sent me a new one no questions asked. The
- beat up tire is now my spare.
- </p>
-
- <h2>Not All Bad</h2>
-
- <p>
- Like I said before, YABS used to be a very nice shop with friendly
- people that did good work. And they didn't charge exorbitant prices for
- their work. Times have changed, and I believe management has as well.
- I've stopped visiting their shop completely. I found a new one that I
- trust and will be taking all of my cars to. They've already done a
- safety inspection on Ol' Blue and didn't put up a fuss. They're clean
- and friendly and don't seem to be out to screw me. But as with
- everything else, your mileage may vary.
- </p>
- </article>
- </body>
-</html>
diff --git a/posts/2019-07-04-yabs-yet-another-bad-shop.php b/posts/2019-07-04-yabs-yet-another-bad-shop.php
new file mode 100644
index 0000000..9594369
--- /dev/null
+++ b/posts/2019-07-04-yabs-yet-another-bad-shop.php
@@ -0,0 +1,183 @@
+<?php
+$title = "YABS: Yet Another Bad Shop";
+if (isset($early) && $early) {
+ return;
+}
+include($_SERVER['DOCUMENT_ROOT'] . '/includes/head.php');
+?>
+<p>
+ Today I received a text message from a local mechanic/auto shop asking
+ me to leave them a Google review. It was an automated message from a
+ shop that I know well and have used many times in the past.
+ Unfortunately, I have had several poor experiences (at the time they
+ seemed horrific) with them in the past year and I can honestly say
+ they'll never receive my business again. Now I could have used this as
+ an opportunity to leave them an anonymous nasty-gram but instead I'm
+ going to do the opposite. I'm going to write about everything I don't
+ like about them without telling you who they are or hiding who I am. Why
+ would I do that? Well for one, they were an excellent shop for many
+ years. I believe a recent change in management is to blame and I'm not
+ going to ruin their chances of making a comeback (because frankly I
+ would like for them to rebound). And secondly, I don't believe in
+ hiding. This page and its author are public knowledge. Now, in no
+ particular order: a sample of awful work from yet another bad shop.
+</p>
+
+<h2>Mom's Truck -- Balls Out</h2>
+
+<p>
+ Mom's truck is a 2007 Chrysler Aspen that she loves very much. Dad does
+ a whole lot of work on it himself (the both of us do pretty much
+ everything we can in-house so long as we have the right equipment).
+ We've been taking her truck into this shop for years because we've found
+ them to be reliable, efficient, and economical. As I said before, at
+ some point in their recent history they changed hands -- either
+ ownership or management, I can't remember which. It was around this time
+ that Dad decided to overhaul Mom's front suspension. He replaced the
+ ball joints, tie rod ends, and a few other worn out parts. He then did
+ his own best-guess front-end alignment, but left everything loose so
+ that YABS could finish up the alignment and tighten everything. Now read
+ that again because it's important. Dad did his own alignment in our
+ driveway (as a cost-saving measure), got it decently close, but then
+ instructed this shop to finish the job and tighten everything up.
+</p>
+
+<p>
+ Now here's where things fall apart. This shop full of professional
+ mechanics took one look at the alignment Dad did and decided it was good
+ enough. Hooray for Dad and supernatural mechanical skills, but the shop
+ didn't even touch the car. They called Dad back to come pick up the car,
+ telling him it was already good to go. They never tightened a thing,
+ even after Dad explicitly told them everything was loose and needed to
+ be tightened but they didn't to touch a thing. So what happened? Dad
+ picked up the car assuming everything was A-OK and Mom drove the car for
+ about a week before the two front tires wore down so badly they had to
+ be replaced immediately. Everything fell out of alignment as things
+ loosened further and further and the tires wore unevenly until they
+ ripped themselves to shreds. The worst part? These weren't tires with 6+
+ years on them. These were brand new tires. So YABS got to install two
+ more front tires and then tighten everything. They did not cover the
+ costs, presumably because it was Dad who had done the alignment. Strike
+ one.
+</p>
+
+<h2>Friend's Minivan -- Crude Necessities</h2>
+
+<p>
+ A good friend of ours drives a 2005-2006 Chrysler Town and Country. It
+ was actually Mom's car before upgrading to the Aspen (the minivan was
+ perfect in every way but it couldn't tow). Our friend has been using
+ YABS for just a long as we have. Once again, things started getting
+ kinda strange after several years of good service. She started getting
+ charged extra for simple repairs she had them doing very consistently.
+ They also started tacking on extra items for routine jobs. She would go
+ in for an inspection and they would claim she needed a new Part X. Now
+ this in and of itself isn't an uncommon or even strange request to make.
+ As cars age they need things and sometimes you don't know what they need
+ until you visit a professional mechanic. They remember the things you
+ forget about.
+</p>
+
+<p>
+ One day they did all the forgetting, and they forgot a pretty important,
+ nay, crucial engine component: motor oil. Our friend took her minivan
+ into YABS for a routine oil change. Good diligence on her part. And
+ she's not the type to do that change on her own. She's too old to get
+ under a car anyway (no offense!). So she took the van to YABS and they
+ did a job they've done thousands of times: drain oil, replaced the
+ filter, and gave her back the car. Easy peasy right? Now I know I'm not
+ a professional but I'm thinking someone might have wanted to
+ double-check that several quarts of synthetic had left the shop shelf
+ and gone into the car they just backed out of the bay door. Now this
+ part of the story I'm a little fuzzy on so take it with a large, heaping
+ grain of salt, but I can say for a fact that they failed to
+ <em>completely</em> refill the engine oil before returning her car.
+ Supposedly there was enough in there such that the minivan survived long
+ enough for them to realize it before she drove off.
+</p>
+
+<h2>Monty, My 2013 Ford Focus -- Nut Allergy</h2>
+
+<p>
+ I decided to give YABS another try after a long leave of absence. I
+ needed new tires all around for my daily driver. I also needed an
+ inspection and an alignment. A simple set of tasks for any shop (you see
+ where this is going). I initially tried to go to another local shop but
+ they were all out of the tires I was looking to get so I caved and went
+ to YABS. About halfway through the job they gave me a call and told me
+ they had some bad news. They said that there were some issues getting
+ the lug nuts off my wheels and that they had all been stripped, warped,
+ or otherwise destroyed in the process. They told me the only fix was to
+ get new ones from a supplier in town for about $160. Keep in mind the
+ entire job (inspection, tires, etc.) was going to cost $650.
+ Furthermore, dad and I had no problem getting those lug nuts off and
+ back on again just a few weeks prior when we changed the transmission
+ fluid.
+</p>
+
+<p>
+ They didn't have an explanation that I could reconcile with. Joe Schmo
+ over the phone told me this is typical of Fords and Chryslers these days
+ and that they'd like to keep my lug nuts for a class action lawsuit
+ they're participating in. Now why on Earth would any sane mechanic, with
+ full knowledge they are dealing with a defective set of lug nuts, take a
+ high power impact wrench to those wheels without speaking with the owner
+ about it first? Smelled fishy to me honestly. But what was I gonna do?
+ Dad went out and grabbed twenty new lug nuts for cheaper than they
+ wanted to sell them for.
+</p>
+
+<p>
+ Oh the tires were Cooper GTs by the way and they're amazing. They're
+ smooth and quiet and came with a very nice warranty. They're also made
+ in the USA, which is very important to me. 10/10 would recommend.
+</p>
+
+<h2>Ol' Blue -- Tunnel Vision</h2>
+
+<p>
+ This was the real kicker. And this one doesn't really have any trailing
+ narrative. I got four new tires on Ol' Blue, my 1953 Hudson Hornet. They
+ were delivered to our house: four brand new Diamond Back wide white wall
+ radials. Super nice tires, with a super nice road hazard warranty (as a
+ side note I totally recommend you
+ <a href="https://dbtires.com/">check out Diamond Back's website</a> if
+ you're looking for white wall radials). So we brought the car to YABS
+ with the new tires and asked them to mount them on the car.
+</p>
+
+<p>
+ When we went to pick up the car everything looked great and I drove off.
+ I made it all the way to the Monitor Merrimack Memorial Bridge Tunnel
+ before I heard a loud rattling and a bang. I looked in the rear-view
+ mirror and swore I could see my precious hubcap rolling off to eternity.
+ When they replaced the hubcaps they didn't fully press one of them on.
+ And it's not that difficult. These hub caps are very secure when pressed
+ on the rim, we've never had problems with them. Oh and we're talking
+ about Hudson hubcaps that came with the car, and aren't super easy to
+ find. And I couldn't stop to get out and grab it because I was right at
+ the mouth of the tunnel. We went back later to try and see it but we
+ couldn't. And it was probably destroyed getting thrown from the car
+ anyways.
+</p>
+
+<p>
+ The worst part is, the hubcap took a chunk out of my white wall on its
+ way out from under the wheel skirt. So the day I got the tires I had to
+ take a picture and redeem my road hazard warranty. Luckily, Diamond Back
+ were true to their word and sent me a new one no questions asked. The
+ beat up tire is now my spare.
+</p>
+
+<h2>Not All Bad</h2>
+
+<p>
+ Like I said before, YABS used to be a very nice shop with friendly
+ people that did good work. And they didn't charge exorbitant prices for
+ their work. Times have changed, and I believe management has as well.
+ I've stopped visiting their shop completely. I found a new one that I
+ trust and will be taking all of my cars to. They've already done a
+ safety inspection on Ol' Blue and didn't put up a fuss. They're clean
+ and friendly and don't seem to be out to screw me. But as with
+ everything else, your mileage may vary.
+</p>
diff --git a/posts/2019-07-21-dancing-the-shag-and-the-new-lion-king.html b/posts/2019-07-21-dancing-the-shag-and-the-new-lion-king.html
deleted file mode 100644
index 9ca4e97..0000000
--- a/posts/2019-07-21-dancing-the-shag-and-the-new-lion-king.html
+++ /dev/null
@@ -1,85 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta property="og:image" content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview" />
- <meta property="og:site_name" content="53hor.net" />
- <meta property="og:title" content="Dancing the Shag & Two Left Feet" />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>53hornet ➙ Dancing the Shag & Two Left Feet</title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <article>
- <h1>Dancing the Shag & Two Left Feet</h1>
- <p>
- Not all of my posts are huge, and they probably shouldn't be. Amy and I
- had a really great time yesterday at Two Left Feet Dance Studio,
- learning more about how to dance the Carolina Shag in preparation for
- our wedding (which is in less than 20 days)! An enormous swing band is
- going to play all of our favorites from the brass band/swing era, and
- one of the easiest dances to do to that music is the Shag. I wrote a
- paper on the Shag a few years ago for school but never actually learned
- how to do it. The steps are simple for us to remember and it's easy
- enough to add flair or mix it up so we look like we know what we're
- doing during our first dance.
- </p>
-
- <p>
- We also got out to see the new Lion King remake and I can honestly say
- it was worth it. If anyone's a Lion King purist, it's Amy. It's easily
- been her favorite movie since she was a toddler, and to see it
- tastefully redone almost 25 years after it was first released was
- thoroughly enjoyable. There were minor alterations to literal sentences
- in the script that all added some context to things that were always
- kind of assumed in the original (clarification on Scar's backstory,
- etc.). I did however feel like they were trying to throw Beyonce lines
- the way a middle-schooler tries to turn a 500-word paper into a 700-word
- paper. Regardless, it's definitely re-living the classic, not re-hashing
- it.
- </p>
- </article>
- </body>
-</html>
diff --git a/posts/2019-07-21-dancing-the-shag-and-the-new-lion-king.php b/posts/2019-07-21-dancing-the-shag-and-the-new-lion-king.php
new file mode 100644
index 0000000..e382f15
--- /dev/null
+++ b/posts/2019-07-21-dancing-the-shag-and-the-new-lion-king.php
@@ -0,0 +1,33 @@
+<?php
+$title = "Dancing the Shag & The [New] Lion Ling";
+if (isset($early) && $early) {
+ return;
+}
+include($_SERVER['DOCUMENT_ROOT'] . '/includes/head.php');
+?>
+<p>
+ Not all of my posts are huge, and they probably shouldn't be. Amy and I
+ had a really great time yesterday at Two Left Feet Dance Studio,
+ learning more about how to dance the Carolina Shag in preparation for
+ our wedding (which is in less than 20 days)! An enormous swing band is
+ going to play all of our favorites from the brass band/swing era, and
+ one of the easiest dances to do to that music is the Shag. I wrote a
+ paper on the Shag a few years ago for school but never actually learned
+ how to do it. The steps are simple for us to remember and it's easy
+ enough to add flair or mix it up so we look like we know what we're
+ doing during our first dance.
+</p>
+
+<p>
+ We also got out to see the new Lion King remake and I can honestly say
+ it was worth it. If anyone's a Lion King purist, it's Amy. It's easily
+ been her favorite movie since she was a toddler, and to see it
+ tastefully redone almost 25 years after it was first released was
+ thoroughly enjoyable. There were minor alterations to literal sentences
+ in the script that all added some context to things that were always
+ kind of assumed in the original (clarification on Scar's backstory,
+ etc.). I did however feel like they were trying to throw Beyonce lines
+ the way a middle-schooler tries to turn a 500-word paper into a 700-word
+ paper. Regardless, it's definitely re-living the classic, not re-hashing
+ it.
+</p>
diff --git a/posts/2019-07-28-i-finally-found-a-drink-i-like.html b/posts/2019-07-28-i-finally-found-a-drink-i-like.html
deleted file mode 100644
index 9350ae3..0000000
--- a/posts/2019-07-28-i-finally-found-a-drink-i-like.html
+++ /dev/null
@@ -1,86 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta property="og:image" content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview" />
- <meta property="og:site_name" content="53hor.net" />
- <meta property="og:title" content="Finally Found a Drink I Like" />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>53hornet ➙ Finally Found a Drink I Like</title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <article>
- <h1>Finally Found a Drink I Like</h1>
- <p>
- Anyone who knows me even slightly well probably knows that I don't
- drink. And it's not out of moral obligation or anything like that. I
- just plain can't stand the taste of alcohol. So it's no surprise that my
- entire family has been trying to throw different alcoholic beverages in
- my direction to see what sticks.
- </p>
-
- <p>
- But it finally happened! I finally found a drink with alcohol in it. And
- not only did I not gag, but I genuinely enjoy it, think it tastes great,
- and mix it myself.
- </p>
-
- <p>
- It's called <em>Blackberry Cream Soda</em>. It's just blackberries,
- ginger ale, and spiced rum. It's darn good. And it's going to be the
- signature drink at our wedding, whatever that means. All I know is I can
- finally order something at a bar and that's cool by me.
- </p>
-
- <p>
- <img
- src="https://nextcloud.53hor.net/s/Jdpp8QYwo6nY9Fx/preview"
- alt="Behold, Blackberry Cream Soda"
- />
- </p>
- </article>
- </body>
-</html>
diff --git a/posts/2019-07-28-i-finally-found-a-drink-i-like.php b/posts/2019-07-28-i-finally-found-a-drink-i-like.php
new file mode 100644
index 0000000..a73de9e
--- /dev/null
+++ b/posts/2019-07-28-i-finally-found-a-drink-i-like.php
@@ -0,0 +1,31 @@
+<?php
+$title = "Finally Found a Drink I Like";
+if (isset($early) && $early) {
+ return;
+}
+include($_SERVER['DOCUMENT_ROOT'] . '/includes/head.php');
+?>
+<p>
+ Anyone who knows me even slightly well probably knows that I don't
+ drink. And it's not out of moral obligation or anything like that. I
+ just plain can't stand the taste of alcohol. So it's no surprise that my
+ entire family has been trying to throw different alcoholic beverages in
+ my direction to see what sticks.
+</p>
+
+<p>
+ But it finally happened! I finally found a drink with alcohol in it. And
+ not only did I not gag, but I genuinely enjoy it, think it tastes great,
+ and mix it myself.
+</p>
+
+<p>
+ It's called <em>Blackberry Cream Soda</em>. It's just blackberries,
+ ginger ale, and spiced rum. It's darn good. And it's going to be the
+ signature drink at our wedding, whatever that means. All I know is I can
+ finally order something at a bar and that's cool by me.
+</p>
+
+<p>
+ <img src="https://nextcloud.53hor.net/s/Jdpp8QYwo6nY9Fx/preview" alt="Behold, Blackberry Cream Soda" />
+</p>
diff --git a/posts/2019-08-11-marrying-my-best-friend.html b/posts/2019-08-11-marrying-my-best-friend.html
deleted file mode 100644
index 24cb00a..0000000
--- a/posts/2019-08-11-marrying-my-best-friend.html
+++ /dev/null
@@ -1,68 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta property="og:image" content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview" />
- <meta property="og:site_name" content="53hor.net" />
- <meta property="og:title" content="I Married My Best Friend!" />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>53hornet ➙ I Married My Best Friend!</title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <article>
- <h1>I Married My Best Friend!</h1>
- <p>
- It was an inexplicable mixture of joy and butterflies getting to marry
- my best friend. It was truly like a dream come true, so much so that it
- drove me to tears multiple times. Now that we're on our honeymoon, it
- feels simultaneously like everything and nothing has changed but I think
- that's a good thing.
- </p>
-
- <p>More to come!</p>
- </article>
- </body>
-</html>
diff --git a/posts/2019-08-11-marrying-my-best-friend.php b/posts/2019-08-11-marrying-my-best-friend.php
new file mode 100644
index 0000000..83bde5b
--- /dev/null
+++ b/posts/2019-08-11-marrying-my-best-friend.php
@@ -0,0 +1,17 @@
+<?php
+$title = "I Married My Best Friend!";
+if (isset($early) && $early) {
+ return;
+}
+include($_SERVER['DOCUMENT_ROOT'] . '/includes/head.php');
+?>
+<h1>I Married My Best Friend!</h1>
+<p>
+ It was an inexplicable mixture of joy and butterflies getting to marry
+ my best friend. It was truly like a dream come true, so much so that it
+ drove me to tears multiple times. Now that we're on our honeymoon, it
+ feels simultaneously like everything and nothing has changed but I think
+ that's a good thing.
+</p>
+
+<p>More to come!</p>
diff --git a/posts/2019-08-30-keep-right-except-to-pass.html b/posts/2019-08-30-keep-right-except-to-pass.html
deleted file mode 100644
index 31f919b..0000000
--- a/posts/2019-08-30-keep-right-except-to-pass.html
+++ /dev/null
@@ -1,108 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta property="og:image" content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview" />
- <meta property="og:site_name" content="53hor.net" />
- <meta
- property="og:title"
- content="Left Lane is for Passing, Not Cruising"
- />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>53hornet ➙ Left Lane is for Passing, Not Cruising</title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <article>
- <h1>Left Lane is for Passing, Not Cruising</h1>
-
- <p>
- Greetings fellow drivers of Hampton Roads. You may have noticed a new
- sign on I264 today that befuddled or confused you. It went something
- along the lines of
- </p>
-
- <blockquote>LEFT LANE IS FOR PASSING NOT CRUISING</blockquote>
-
- <p>
- Believe it or not this has been the law throughout Virginia for years
- (<a
- href="https://law.lis.virginia.gov/vacode/title46.2/chapter8/section46.2-804/"
- >read about it here</a
- >
- and
- <a
- href="https://law.lis.virginia.gov/vacode/title46.2/chapter8/section46.2-842.1/"
- >here</a
- >). The law states you keep right except while passing. In most other
- states things work this way but in Virginia, especially around here, the
- left lane is treated as a moving, cruising lane. If you're in the left
- lane and you've completed a pass please be mindful of the cars behind
- you and move back over into the right-hand lane(s) so that other drivers
- can do the same.
- </p>
-
- <p>
- It's really nice when this is practiced (like I said, I've experienced
- it in other states) because you can easily move over when there are slow
- vehicles ahead and then continue on your merry way. It reduces
- congestion and prevents people from having to pass in the right lane,
- which is both annoying and dangerous. Especially since this is typically
- the lane cars from entrance and exit ramps are merging with.
- </p>
-
- <p>
- Don't forget too that it isn't rude or road-rage-y for someone behind
- you to honk their horn or flash their lights if you're moving too slowly
- in the passing lane. This is a perfectly polite request to pass you. You
- don't set or enforce the speed limit. The correct (and legal) thing to
- do, believe it or not, is to move over and slow down to let them pass
- you. It's all about safe and sane driving etiquette. If you aren't
- actively passing other cars, move on over to the right. It goes a long
- way.
- </p>
- </article>
- </body>
-</html>
diff --git a/posts/2019-08-30-keep-right-except-to-pass.php b/posts/2019-08-30-keep-right-except-to-pass.php
new file mode 100644
index 0000000..660733a
--- /dev/null
+++ b/posts/2019-08-30-keep-right-except-to-pass.php
@@ -0,0 +1,46 @@
+<?php
+$title = "Left Lane is for Passing, Not Cruising";
+if (isset($early) && $early) {
+ return;
+}
+include($_SERVER['DOCUMENT_ROOT'] . '/includes/head.php');
+?>
+<p>
+ Greetings fellow drivers of Hampton Roads. You may have noticed a new
+ sign on I264 today that befuddled or confused you. It went something
+ along the lines of
+</p>
+
+<blockquote>LEFT LANE IS FOR PASSING NOT CRUISING</blockquote>
+
+<p>
+ Believe it or not this has been the law throughout Virginia for years
+ (<a href="https://law.lis.virginia.gov/vacode/title46.2/chapter8/section46.2-804/">read about it here</a>
+ and
+ <a href="https://law.lis.virginia.gov/vacode/title46.2/chapter8/section46.2-842.1/">here</a>). The law states you keep right except while passing. In most other
+ states things work this way but in Virginia, especially around here, the
+ left lane is treated as a moving, cruising lane. If you're in the left
+ lane and you've completed a pass please be mindful of the cars behind
+ you and move back over into the right-hand lane(s) so that other drivers
+ can do the same.
+</p>
+
+<p>
+ It's really nice when this is practiced (like I said, I've experienced
+ it in other states) because you can easily move over when there are slow
+ vehicles ahead and then continue on your merry way. It reduces
+ congestion and prevents people from having to pass in the right lane,
+ which is both annoying and dangerous. Especially since this is typically
+ the lane cars from entrance and exit ramps are merging with.
+</p>
+
+<p>
+ Don't forget too that it isn't rude or road-rage-y for someone behind
+ you to honk their horn or flash their lights if you're moving too slowly
+ in the passing lane. This is a perfectly polite request to pass you. You
+ don't set or enforce the speed limit. The correct (and legal) thing to
+ do, believe it or not, is to move over and slow down to let them pass
+ you. It's all about safe and sane driving etiquette. If you aren't
+ actively passing other cars, move on over to the right. It goes a long
+ way.
+</p>
diff --git a/posts/2019-09-28-my-preferred-method-for-data-recovery.html b/posts/2019-09-28-my-preferred-method-for-data-recovery.html
deleted file mode 100644
index 8adb24c..0000000
--- a/posts/2019-09-28-my-preferred-method-for-data-recovery.html
+++ /dev/null
@@ -1,276 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta property="og:image" content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview" />
- <meta property="og:site_name" content="53hor.net" />
- <meta property="og:title" content="How I Do Data Recovery" />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>53hornet ➙ How I Do Data Recovery</title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <article>
- <h1>How I Do Data Recovery</h1>
-
- <p>
- This week Amy plugged in her flash drive to discover that there were no
- files on it. Weeks before there had been dozens of large cuts of footage
- that she needed to edit down for work. Hours of recordings were
- seemingly gone. And the most annoying part was the drive had worked
- perfectly on several other occasions. Just not now that the footage was
- actually needed of course. Initially it looked like everything had been
- wiped clean, however both Amy's Mac and her PC thought the drive was
- half full. It's overall capacity was 64GB but it showed only about 36GB
- free. So there still had to be data on there if we could find the right
- tool to salvage it.
- </p>
-
- <p>
- Luckily this wasn't the first time I had to recover accidentally (or
- magically) deleted files. I had previously done so with some success at
- my tech support job, for some college friends, and for my in-laws'
- retired laptops. So I had a pretty clear idea of what to expect. The
- only trick was finding a tool that knew what files it was looking for.
- The camera that took the video clips was a Sony and apparently they
- record into <code>m2ts</code> files, which are kind of a unique format
- in that they only show up on Blu-Ray discs and Sony camcorders. Enter my
- favorite two tools for dealing with potentially-destroyed data:
- <code>ddrescue</code> and <code>photorec</code>.
- </p>
-
- <h2>DDRescue</h2>
-
- <p>
- <code>ddrescue</code> is a godsend of a tool. If you've ever used
- <code>dd</code> before, forget about it. Use <code>ddrescue</code>. You
- might as well <code>alias dd=ddrescue</code> because it's that great. By
- default it has a plethora of additional options, displays the progress
- as it works, recovers and retries in the event of I/O errors, and does
- everything that good old <code>dd</code> can do. It's particularly good
- at protecting partitions or disks that have been corrupted or damaged by
- rescuing undamaged portions first. Oh, and have you ever had to cancel a
- <code>dd</code> operation? Did I mention that <code>ddrescue</code> can
- pause and resume operations? It's that good.
- </p>
-
- <h2>PhotoRec</h2>
-
- <p>
- <code>photorec</code> is probably the best missing file recovery tool
- I've ever used in my entire life. And I've used quite a few. I've never
- had as good results as I've had with <code>photorec</code> with other
- tools like Recuva et. al. And <code>photorec</code> isn't just for
- photos, it can recover documents (a la Office suite), music, images,
- config files, and videos (including the very odd
- <code>m2ts</code> format!). The other nice thing is
- <code>photorec</code> will work on just about any source. It's also free
- software which makes me wonder why there are like $50 recovery tools for
- Windows that look super sketchy.
- </p>
-
- <h2>In Practice</h2>
-
- <p>
- So here's what I did to get Amy's files back. Luckily she didn't write
- anything out to the drive afterward so the chances (I thought) were
- pretty good that I would get <em>something</em> back. The first thing I
- always do is make a full image of whatever media I'm trying to recover
- from. I do this for a couple of reasons. First of all it's a backup. If
- something goes wrong during recovery I don't have to worry about the
- original, fragile media being damaged or wiped. Furthermore, I can work
- with multiple copies at a time. If it's a large image that means
- multiple tools or even multiple PCs can work on it at once. It's also
- just plain faster working off a disk image than a measly flash drive. So
- I used <code>ddrescue</code> to make an image of Amy's drive.
- </p>
-
- <pre><code>
-$ sudo ddrescue /dev/sdb1 amy-lexar.dd
-GNU ddrescue 1.24
-Press Ctrl-C to interrupt
- ipos: 54198 kB, non-trimmed: 0 B, current rate: 7864 kB/s
- opos: 54198 kB, non-scraped: 0 B, average rate: 18066 kB/s
-non-tried: 63967 MB, bad-sector: 0 B, error rate: 0 B/s
- rescued: 54198 kB, bad areas: 0, run time: 2s
-pct rescued: 0.08%, read errors: 0, remaining time: 59m
- time since last successful read: n/a
-Copying non-tried blocks... Pass 1 (forwards)
- </code></pre>
-
- <p>
- The result was a very large partition image that I could fearlessly play
- around with.
- </p>
-
- <pre>
- <code>
-$ ll amy-lexar.dd
--rw-r--r-- 1 root root 60G Sep 24 02:45 amy-lexar.dd
- </code>
- </pre>
-
- <p>
- Then I could run <code>photorec</code> on the image. This brings up a
- TUI with all of the listed media that I can try and recover from.
- </p>
-
- <pre><code>
-$ sudo photorec amy-lexar.dd
-
-PhotoRec 7.0, Data Recovery Utility, April 2015
-http://www.cgsecurity.org
-
- PhotoRec is free software, and
-comes with ABSOLUTELY NO WARRANTY.
-
-Select a media (use Arrow keys, then press Enter):
->Disk amy-lexar.dd - 64 GB / 59 GiB (RO)
-
->[Proceed ] [ Quit ]
-
-Note:
-Disk capacity must be correctly detected for a successful recovery.
-If a disk listed above has incorrect size, check HD jumper settings, BIOS
-detection, and install the latest OS patches and disk drivers.
- </code></pre>
-
- <p>
- After hitting proceed <code>photorec</code> asks if you want to scan
- just a particular partition or the whole disk (if you made a whole disk
- image). I can usually get away with just selecting the partition I know
- the files are on and starting a search.
- </p>
-
- <pre><code>
-PhotoRec 7.0, Data Recovery Utility, April 2015
-http://www.cgsecurity.org
-
-Disk amy-lexar.dd - 64 GB / 59 GiB (RO)
-
- Partition Start End Size in sectors
- Unknown 0 0 1 7783 139 4 125042656 [Whole disk]
-> P FAT32 0 0 1 7783 139 4 125042656 [NO NAME]
-
->[ Search ] [Options ] [File Opt] [ Quit ]
- Start file recovery
- </code></pre>
-
- <p>
- Then <code>photorec</code> asks a couple of questions about the
- formatting of the media. It can usually figure them out all by itself so
- I just use the default options unless it's way out in left field.
- </p>
-
- <pre><code>
-PhotoRec 7.0, Data Recovery Utility, April 2015
-http://www.cgsecurity.org
-
- P FAT32 0 0 1 7783 139 4 125042656 [NO NAME]
-
-To recover lost files, PhotoRec need to know the filesystem type where the
-file were stored:
- [ ext2/ext3 ] ext2/ext3/ext4 filesystem
->[ Other ] FAT/NTFS/HFS+/ReiserFS/...
- </code></pre>
-
- <p>
- Now this menu is where I don't just go with the default path.
- <code>photorec</code> will offer to search just unallocated space or the
- entire partition. I always go for the whole partition here; sometimes
- I'll get back files that I didn't really care about but more often than
- not I end up rescuing more data this way. In this scenario searching
- just unallocated space found no files at all. So I told
- <code>photorec</code> to search everything.
- </p>
-
- <pre><code>
-PhotoRec 7.0, Data Recovery Utility, April 2015
-http://www.cgsecurity.org
-
- P FAT32 0 0 1 7783 139 4 125042656 [NO NAME]
-
-
-Please choose if all space need to be analysed:
- [ Free ] Scan for file from FAT32 unallocated space only
->[ Whole ] Extract files from whole partition
- </code></pre>
-
- <p>
- Now it'll ask where you want to save any files it finds. I threw them
- all into a directory under home that I could zip up and send to Amy's
- Mac later.
- </p>
-
- <pre><code>
-PhotoRec 7.0, Data Recovery Utility, April 2015
-
-Please select a destination to save the recovered files.
-Do not choose to write the files to the same partition they were stored on.
-Keys: Arrow keys to select another directory
- C when the destination is correct
- Q to quit
-Directory /home/adam
- drwx------ 1000 1000 4096 28-Sep-2019 12:10 .
- drwxr-xr-x 0 0 4096 26-Jan-2019 15:32 ..
->drwxr-xr-x 1000 1000 4096 28-Sep-2019 12:10 amy-lexar-recovery
- </code></pre>
-
- <p>
- And then just press <code>C</code>. <code>photrec</code> will start
- copying all of the files it finds into that directory. It reports what
- kinds of files it found and how many it was able to locate. I was able
- to recover all of Amy's lost footage this way, past, along with some
- straggler files that had been on the drive at one point. This has worked
- for me many times in the past, both on newer devices like flash drives
- and on super old, sketchy IDE hard drives. I probably won't ever pay for
- data recovery unless a drive has been physically damaged in some way. In
- other words, this software works great for me and I don't foresee the
- need for anything else out there. It's simple to use and is typically
- pretty reliable.
- </p>
- </article>
- </body>
-</html>
diff --git a/posts/2019-09-28-my-preferred-method-for-data-recovery.php b/posts/2019-09-28-my-preferred-method-for-data-recovery.php
new file mode 100644
index 0000000..d7b68d2
--- /dev/null
+++ b/posts/2019-09-28-my-preferred-method-for-data-recovery.php
@@ -0,0 +1,224 @@
+<?php
+$title = "How I Do Data Recovery";
+if (isset($early) && $early) {
+ return;
+}
+include($_SERVER['DOCUMENT_ROOT'] . '/includes/head.php');
+?>
+
+<p>
+ This week Amy plugged in her flash drive to discover that there were no
+ files on it. Weeks before there had been dozens of large cuts of footage
+ that she needed to edit down for work. Hours of recordings were
+ seemingly gone. And the most annoying part was the drive had worked
+ perfectly on several other occasions. Just not now that the footage was
+ actually needed of course. Initially it looked like everything had been
+ wiped clean, however both Amy's Mac and her PC thought the drive was
+ half full. It's overall capacity was 64GB but it showed only about 36GB
+ free. So there still had to be data on there if we could find the right
+ tool to salvage it.
+</p>
+
+<p>
+ Luckily this wasn't the first time I had to recover accidentally (or
+ magically) deleted files. I had previously done so with some success at
+ my tech support job, for some college friends, and for my in-laws'
+ retired laptops. So I had a pretty clear idea of what to expect. The
+ only trick was finding a tool that knew what files it was looking for.
+ The camera that took the video clips was a Sony and apparently they
+ record into <code>m2ts</code> files, which are kind of a unique format
+ in that they only show up on Blu-Ray discs and Sony camcorders. Enter my
+ favorite two tools for dealing with potentially-destroyed data:
+ <code>ddrescue</code> and <code>photorec</code>.
+</p>
+
+<h2>DDRescue</h2>
+
+<p>
+ <code>ddrescue</code> is a godsend of a tool. If you've ever used
+ <code>dd</code> before, forget about it. Use <code>ddrescue</code>. You
+ might as well <code>alias dd=ddrescue</code> because it's that great. By
+ default it has a plethora of additional options, displays the progress
+ as it works, recovers and retries in the event of I/O errors, and does
+ everything that good old <code>dd</code> can do. It's particularly good
+ at protecting partitions or disks that have been corrupted or damaged by
+ rescuing undamaged portions first. Oh, and have you ever had to cancel a
+ <code>dd</code> operation? Did I mention that <code>ddrescue</code> can
+ pause and resume operations? It's that good.
+</p>
+
+<h2>PhotoRec</h2>
+
+<p>
+ <code>photorec</code> is probably the best missing file recovery tool
+ I've ever used in my entire life. And I've used quite a few. I've never
+ had as good results as I've had with <code>photorec</code> with other
+ tools like Recuva et. al. And <code>photorec</code> isn't just for
+ photos, it can recover documents (a la Office suite), music, images,
+ config files, and videos (including the very odd
+ <code>m2ts</code> format!). The other nice thing is
+ <code>photorec</code> will work on just about any source. It's also free
+ software which makes me wonder why there are like $50 recovery tools for
+ Windows that look super sketchy.
+</p>
+
+<h2>In Practice</h2>
+
+<p>
+ So here's what I did to get Amy's files back. Luckily she didn't write
+ anything out to the drive afterward so the chances (I thought) were
+ pretty good that I would get <em>something</em> back. The first thing I
+ always do is make a full image of whatever media I'm trying to recover
+ from. I do this for a couple of reasons. First of all it's a backup. If
+ something goes wrong during recovery I don't have to worry about the
+ original, fragile media being damaged or wiped. Furthermore, I can work
+ with multiple copies at a time. If it's a large image that means
+ multiple tools or even multiple PCs can work on it at once. It's also
+ just plain faster working off a disk image than a measly flash drive. So
+ I used <code>ddrescue</code> to make an image of Amy's drive.
+</p>
+
+<pre><code>
+$ sudo ddrescue /dev/sdb1 amy-lexar.dd
+GNU ddrescue 1.24
+Press Ctrl-C to interrupt
+ ipos: 54198 kB, non-trimmed: 0 B, current rate: 7864 kB/s
+ opos: 54198 kB, non-scraped: 0 B, average rate: 18066 kB/s
+non-tried: 63967 MB, bad-sector: 0 B, error rate: 0 B/s
+ rescued: 54198 kB, bad areas: 0, run time: 2s
+pct rescued: 0.08%, read errors: 0, remaining time: 59m
+ time since last successful read: n/a
+Copying non-tried blocks... Pass 1 (forwards)
+ </code></pre>
+
+<p>
+ The result was a very large partition image that I could fearlessly play
+ around with.
+</p>
+
+<pre>
+ <code>
+$ ll amy-lexar.dd
+-rw-r--r-- 1 root root 60G Sep 24 02:45 amy-lexar.dd
+ </code>
+ </pre>
+
+<p>
+ Then I could run <code>photorec</code> on the image. This brings up a
+ TUI with all of the listed media that I can try and recover from.
+</p>
+
+<pre><code>
+$ sudo photorec amy-lexar.dd
+
+PhotoRec 7.0, Data Recovery Utility, April 2015
+http://www.cgsecurity.org
+
+ PhotoRec is free software, and
+comes with ABSOLUTELY NO WARRANTY.
+
+Select a media (use Arrow keys, then press Enter):
+>Disk amy-lexar.dd - 64 GB / 59 GiB (RO)
+
+>[Proceed ] [ Quit ]
+
+Note:
+Disk capacity must be correctly detected for a successful recovery.
+If a disk listed above has incorrect size, check HD jumper settings, BIOS
+detection, and install the latest OS patches and disk drivers.
+ </code></pre>
+
+<p>
+ After hitting proceed <code>photorec</code> asks if you want to scan
+ just a particular partition or the whole disk (if you made a whole disk
+ image). I can usually get away with just selecting the partition I know
+ the files are on and starting a search.
+</p>
+
+<pre><code>
+PhotoRec 7.0, Data Recovery Utility, April 2015
+http://www.cgsecurity.org
+
+Disk amy-lexar.dd - 64 GB / 59 GiB (RO)
+
+ Partition Start End Size in sectors
+ Unknown 0 0 1 7783 139 4 125042656 [Whole disk]
+> P FAT32 0 0 1 7783 139 4 125042656 [NO NAME]
+
+>[ Search ] [Options ] [File Opt] [ Quit ]
+ Start file recovery
+ </code></pre>
+
+<p>
+ Then <code>photorec</code> asks a couple of questions about the
+ formatting of the media. It can usually figure them out all by itself so
+ I just use the default options unless it's way out in left field.
+</p>
+
+<pre><code>
+PhotoRec 7.0, Data Recovery Utility, April 2015
+http://www.cgsecurity.org
+
+ P FAT32 0 0 1 7783 139 4 125042656 [NO NAME]
+
+To recover lost files, PhotoRec need to know the filesystem type where the
+file were stored:
+ [ ext2/ext3 ] ext2/ext3/ext4 filesystem
+>[ Other ] FAT/NTFS/HFS+/ReiserFS/...
+ </code></pre>
+
+<p>
+ Now this menu is where I don't just go with the default path.
+ <code>photorec</code> will offer to search just unallocated space or the
+ entire partition. I always go for the whole partition here; sometimes
+ I'll get back files that I didn't really care about but more often than
+ not I end up rescuing more data this way. In this scenario searching
+ just unallocated space found no files at all. So I told
+ <code>photorec</code> to search everything.
+</p>
+
+<pre><code>
+PhotoRec 7.0, Data Recovery Utility, April 2015
+http://www.cgsecurity.org
+
+ P FAT32 0 0 1 7783 139 4 125042656 [NO NAME]
+
+
+Please choose if all space need to be analysed:
+ [ Free ] Scan for file from FAT32 unallocated space only
+>[ Whole ] Extract files from whole partition
+ </code></pre>
+
+<p>
+ Now it'll ask where you want to save any files it finds. I threw them
+ all into a directory under home that I could zip up and send to Amy's
+ Mac later.
+</p>
+
+<pre><code>
+PhotoRec 7.0, Data Recovery Utility, April 2015
+
+Please select a destination to save the recovered files.
+Do not choose to write the files to the same partition they were stored on.
+Keys: Arrow keys to select another directory
+ C when the destination is correct
+ Q to quit
+Directory /home/adam
+ drwx------ 1000 1000 4096 28-Sep-2019 12:10 .
+ drwxr-xr-x 0 0 4096 26-Jan-2019 15:32 ..
+>drwxr-xr-x 1000 1000 4096 28-Sep-2019 12:10 amy-lexar-recovery
+ </code></pre>
+
+<p>
+ And then just press <code>C</code>. <code>photrec</code> will start
+ copying all of the files it finds into that directory. It reports what
+ kinds of files it found and how many it was able to locate. I was able
+ to recover all of Amy's lost footage this way, past, along with some
+ straggler files that had been on the drive at one point. This has worked
+ for me many times in the past, both on newer devices like flash drives
+ and on super old, sketchy IDE hard drives. I probably won't ever pay for
+ data recovery unless a drive has been physically damaged in some way. In
+ other words, this software works great for me and I don't foresee the
+ need for anything else out there. It's simple to use and is typically
+ pretty reliable.
+</p>
diff --git a/posts/2020-04-10-the-obligatory-covid-19-post.html b/posts/2020-04-10-the-obligatory-covid-19-post.html
deleted file mode 100644
index 15bd9bc..0000000
--- a/posts/2020-04-10-the-obligatory-covid-19-post.html
+++ /dev/null
@@ -1,103 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta property="og:image" content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview" />
- <meta property="og:site_name" content="53hor.net" />
- <meta property="og:title" content="Obligatory COVID-19 Post" />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>53hornet ➙ Obligatory COVID-19 Post</title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <article>
- <h1>Obligatory COVID-19 Post</h1>
- <p>
- We're alive! All three of us: Amy, Clementine, and myself. We're doing
- what we do best and that is being hermits with zero social contact.
- That's pretty okay by us though because it lets us slow down from all
- the fast-paced life changes we've made in the past few months.
- </p>
-
- <p>
- In January Amy and I bought a house! We couldn't have done it without
- the wonderful help of everyone who gave us wedding gifts. We got a nice
- little standalone place in Suffolk, much closer to where I work and
- centrally located for Amy's tutoring business. We spent all of January
- painting and prepping for the big move. Late January and early February
- were all moving and unpacking and trying to get back in the groove.
- Since the outbreak, we've been using the extra time at home to finish up
- all the move-in projects we wanted to: finishing painting, putting up
- shelves, hanging pictures, and rewiring electrical outlets.
- </p>
-
- <p>
- Amy also finally got the chance to pursue her dream job: she started up
- her own private tutoring business. She's been working hard with clients
- all over Hampton Roads, from college students all the way to
- first-graders. Business was booming before schools closed but I know
- she'll bring it back once things have returned to normal again. No
- worries though, she's spending this time helping William and Mary handle
- remote operations and students in need. She's also [supposed to be]
- writing her master's thesis so she can graduate in May but you know how
- it is.
- </p>
-
- <p>
- We're also working through a family illness, which adds difficulty . We
- expect a speedy recovery though and we're really excited for that.
- All-in-all, we're really enjoying our lives as a happily married couple.
- It's been about eight months now and I've enjoyed every minute of it:
- the glad, the slightly stressed, and the overarching worry as the world
- took a strange turn. But we're looking forward to a good Summer now. The
- weather has turned nice -- really nice -- and Clementine is forcing us
- to get outside. She's in love with her nice, big fenced-in yard and
- refuses to come in after catching hoops most of the time.
- </p>
-
- <p>Stay safe, smart, and sane!</p>
- </article>
- </body>
-</html>
diff --git a/posts/2020-04-10-the-obligatory-covid-19-post.php b/posts/2020-04-10-the-obligatory-covid-19-post.php
new file mode 100644
index 0000000..6cdabe9
--- /dev/null
+++ b/posts/2020-04-10-the-obligatory-covid-19-post.php
@@ -0,0 +1,51 @@
+<?php
+$title = "Obligatory COVID-19 Post";
+if (isset($early) && $early) {
+ return;
+}
+include($_SERVER['DOCUMENT_ROOT'] . '/includes/head.php');
+?>
+<p>
+ We're alive! All three of us: Amy, Clementine, and myself. We're doing
+ what we do best and that is being hermits with zero social contact.
+ That's pretty okay by us though because it lets us slow down from all
+ the fast-paced life changes we've made in the past few months.
+</p>
+
+<p>
+ In January Amy and I bought a house! We couldn't have done it without
+ the wonderful help of everyone who gave us wedding gifts. We got a nice
+ little standalone place in Suffolk, much closer to where I work and
+ centrally located for Amy's tutoring business. We spent all of January
+ painting and prepping for the big move. Late January and early February
+ were all moving and unpacking and trying to get back in the groove.
+ Since the outbreak, we've been using the extra time at home to finish up
+ all the move-in projects we wanted to: finishing painting, putting up
+ shelves, hanging pictures, and rewiring electrical outlets.
+</p>
+
+<p>
+ Amy also finally got the chance to pursue her dream job: she started up
+ her own private tutoring business. She's been working hard with clients
+ all over Hampton Roads, from college students all the way to
+ first-graders. Business was booming before schools closed but I know
+ she'll bring it back once things have returned to normal again. No
+ worries though, she's spending this time helping William and Mary handle
+ remote operations and students in need. She's also [supposed to be]
+ writing her master's thesis so she can graduate in May but you know how
+ it is.
+</p>
+
+<p>
+ We're also working through a family illness, which adds difficulty . We
+ expect a speedy recovery though and we're really excited for that.
+ All-in-all, we're really enjoying our lives as a happily married couple.
+ It's been about eight months now and I've enjoyed every minute of it:
+ the glad, the slightly stressed, and the overarching worry as the world
+ took a strange turn. But we're looking forward to a good Summer now. The
+ weather has turned nice -- really nice -- and Clementine is forcing us
+ to get outside. She's in love with her nice, big fenced-in yard and
+ refuses to come in after catching hoops most of the time.
+</p>
+
+<p>Stay safe, smart, and sane!</p>
diff --git a/posts/2020-04-10-wedding-photos-are-here.html b/posts/2020-04-10-wedding-photos-are-here.html
deleted file mode 100644
index 21ec27e..0000000
--- a/posts/2020-04-10-wedding-photos-are-here.html
+++ /dev/null
@@ -1,96 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta property="og:image" content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview" />
- <meta property="og:site_name" content="53hor.net" />
- <meta property="og:title" content="Wedding Photo Debacle" />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>53hornet ➙ Wedding Photo Debacle</title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <article>
- <h1>Wedding Photo Debacle</h1>
-
- <p>
- At long last we have all of our wedding photos together! Unfortunately a
- large portion of the professional ones were lost during editing but
- we're extremely fortunate to everyone who took pictures throughout the
- festivities so we have more to share! We hope you enjoy flipping through
- them as much as we did! There is also a collection of the photos we took
- while we were on our honeymoon on Mackinac Island, MI. It was an
- absolutely magical place and truly the experience of a lifetime for us
- to run away there. We're in contact with our videographer, who's working
- on the final cut now.
- </p>
-
- <p>
- Everything is available at the links down below. You can scroll through
- the photos, view them in fullscreen, and even download them or share
- them elsewhere. We hope you have as much fun flipping through them as we
- did!
- </p>
-
- <ul>
- <li>
- <a href="https://nextcloud.53hor.net/s/eYLqeMGnSPGRNFE"
- >Bachelor &amp; Bachelorette Parties</a
- >
- </li>
-
- <li>
- <a href="https://nextcloud.53hor.net/s/FxekyGQFTFKG5ot"
- >Wedding Day</a
- >
- </li>
-
- <li>
- <a href="https://nextcloud.53hor.net/s/mgZ6M4ayqX73DqL">Honeymoon</a>
- </li>
- </ul>
- </article>
- </body>
-</html>
diff --git a/posts/2020-04-10-wedding-photos-are-here.php b/posts/2020-04-10-wedding-photos-are-here.php
new file mode 100644
index 0000000..59344d6
--- /dev/null
+++ b/posts/2020-04-10-wedding-photos-are-here.php
@@ -0,0 +1,40 @@
+<?php
+$title = "Wedding Photo Debacle";
+if (isset($early) && $early) {
+ return;
+}
+include($_SERVER['DOCUMENT_ROOT'] . '/includes/head.php');
+?>
+
+<p>
+ At long last we have all of our wedding photos together! Unfortunately a
+ large portion of the professional ones were lost during editing but
+ we're extremely fortunate to everyone who took pictures throughout the
+ festivities so we have more to share! We hope you enjoy flipping through
+ them as much as we did! There is also a collection of the photos we took
+ while we were on our honeymoon on Mackinac Island, MI. It was an
+ absolutely magical place and truly the experience of a lifetime for us
+ to run away there. We're in contact with our videographer, who's working
+ on the final cut now.
+</p>
+
+<p>
+ Everything is available at the links down below. You can scroll through
+ the photos, view them in fullscreen, and even download them or share
+ them elsewhere. We hope you have as much fun flipping through them as we
+ did!
+</p>
+
+<ul>
+ <li>
+ <a href="https://nextcloud.53hor.net/s/eYLqeMGnSPGRNFE">Bachelor &amp; Bachelorette Parties</a>
+ </li>
+
+ <li>
+ <a href="https://nextcloud.53hor.net/s/FxekyGQFTFKG5ot">Wedding Day</a>
+ </li>
+
+ <li>
+ <a href="https://nextcloud.53hor.net/s/mgZ6M4ayqX73DqL">Honeymoon</a>
+ </li>
+</ul>
diff --git a/posts/2020-07-11-why-computer-science-at-w-m.html b/posts/2020-07-11-why-computer-science-at-w-m.html
deleted file mode 100644
index cd882bb..0000000
--- a/posts/2020-07-11-why-computer-science-at-w-m.html
+++ /dev/null
@@ -1,249 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta property="og:image" content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview" />
- <meta property="og:site_name" content="53hor.net" />
- <meta
- property="og:title"
- content="Why Computer Science at William and Mary"
- />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>53hornet ➙ Why Computer Science at William and Mary</title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <article>
- <h1>Why Computer Science at William and Mary</h1>
-
- <p class="description">
- Recently a rising high-school senior asked for input on what going to
- the College of William and Mary was like for a Computer Science degree.
- They were asking about the program itself as well as what it's like on
- and off campus. Here's what I sent to them.
- </p>
-
- <h2>Quick Intro</h2>
-
- <p>
- I graduated with a Bachelor's in Computer Science from W&amp;M in 2018.
- I'm a couple years in the workforce now but can still remember my
- experiences well enough to hopefully add my honest opinion on my time
- there as well as how it prepared me for my career. I will also add a
- little bit about my time on campus in a dorm and off-campus in Colonial
- Williamsburg.
- </p>
-
- <h2>Courses and Curriculum</h2>
-
- <p>
- I felt very positively about the array of courses that were offered
- while I was a student. I took a variety of core prerequisites, just like
- everyone else, and a good mix of electives. The courses I took include
- Data Structures and Algorithms, Software Development/Engineering,
- Computer Organization/Architecture, UNIX Systems Programming, Computer
- Graphics/Animation, and Computer and Network Security. This list is not
- exhaustive and I'm sure they aren't all offered anymore. I was also
- required to take a few math classes (Calc I, II, Discrete Math, Linear
- Algebra, and Finite Automata).
- </p>
-
- <p>
- It is true that the courses listed at <code>cs.wm.edu</code> aren't all
- offered at the same time. And it is also true that the higher-level
- electives pretty much all required my core prerequisites to be
- completed. The result is that the electives all came in my final two
- years. My understanding is the curriculum is designed to give someone
- the best possible background in computing as a whole. A lot of the
- topics may seem like they would never be useful in the "real world" but
- I have found the opposite is true. I am an application developer at a
- three-letter company. My day-to-day work is building and debugging web
- apps, but there's been a lot more to it than that. My first assignment
- on the job was scraping bytes off a remote shell and writing a parser to
- sift through them. The level of understanding I gathered from my core
- classes helped more than I expected they would. I think as a whole they
- give me an edge at work and help me teach my colleagues about
- algorithms, performance, and systems administration.
- </p>
-
- <p>
- That being said, course registration was always nightmarish. It was very
- difficult to get into the limited seats in the classes I was most
- interested in. Eventually the heads of the department had to pass around
- a sign up sheet and organize every student into courses, classrooms, and
- professors so that seniors would graduate on time and we could all get
- <em>something</em> on our schedules. I hope the shortage of teachers has
- caught up since I graduated. I learned from a long-time faculty member
- that this is largely a result of the exponential growth of incoming CS
- degree-seekers. The program has grown very popular in the last ten years
- and I like to think grads are catching on to that.
- </p>
-
- <h2>Teaching</h2>
-
- <p>
- CS@W&amp;M had neutral to good instructors for me. Some were far worse
- than others, as with all subjects. When I was there, lots of the older
- faculty were retiring and quickly being replaced with younger, newer
- instructors, which added to the growing pains of the program. The most
- important thing again was making sure there were enough teachers to
- teach all of the students.
- </p>
-
- <p>
- I know a few of my peers were very upset about what they described as a
- lack of communication or availability from their professors. Some have
- also mentioned they didn't like having to learn material on their own
- and wanted more to come from instruction. I don't deny that the material
- itself was difficult and there was a lot of hard work I had to do on my
- own to understand very involved concepts in intense, fast-paced courses.
- I think that hard work has paid off. I don't think there's realistically
- anywhere someone can learn about computing where they won't do any
- learning on their own. I am also a very visual, and hands-on learner so
- I suppose your mileage may vary.
- </p>
-
- <p>
- The most important takeaway from this for me was the ability to pick up
- new concepts and technologies quickly and apply them productively. The
- majority of professors had project-driven courses. Lots of due dates
- meant learning how to transform what I read or learned in class into
- practical applications in short amounts of time. This has become,
- according to those I work with, one of my greater assets. I am
- constantly learning new things in my career and I don't have a lecturer
- to explain things to me. It's very powerful to have that and I am
- thankful for it. It also helps me teach that knowledge to my colleagues
- so we can move faster as a team.
- </p>
-
- <h2>Campus</h2>
-
- <p>
- I agree with my peers about the conditions of classrooms and buildings
- on campus. Some are old. I guess that comes with an old university but
- there are a choice few that haven't been kept up as best they could.
- Since CS is growing so fast it's also long outgrown its own offices.
- Classrooms are scattered throughout every academic building on campus
- and I probably had a CS course in at least 80% of them. That meant
- jumping from one side of campus to another and back again in between
- periods.
- </p>
-
- <p>
- The College itself isn't too sprawling. I am long-legged and I found I
- could get from one end of campus to another in fifteen minutes on foot.
- I rode bike a lot to get to classes where I only had ten minutes to do
- it. It's also pretty marshy and woodsy in a lot of areas, so during the
- rainy season some walking paths got muddy or flooded. Good boots
- required. I have never been in as good shape as when I had to do all
- that walking but I definitely got soaked and winded making those
- transitions.
- </p>
-
- <p>
- I appreciate history and architecture and was drawn in by the look and
- feel of William and Mary as a result. Without getting too romantic, it's
- definitely a beautiful place to attend classes. The ancient Wren
- building still holds classes and it's a monument to the College's
- tradition. However, I really appreciated the modern academic buildings
- on the other side of campus where all of the new construction was taking
- place. Modern lab equipment and the library lived there.
- </p>
-
- <p>
- The dorms were nothing to write home about. Lots of them were nested in
- the woods and built ages ago so they were a little tired and even dingy.
- Others are brand new and well maintained; ask around and get opinions on
- which ones to go for first chance you get. I made do with what I got for
- the first couple of years by keeping it clean and decorated. My last two
- years I lived in a couple of off-campus apartments. It was well worth
- the switch. Depending on where you are on campus you may need at least a
- bike to access local restaurants, shops, and the grocery store. A bike
- is a good idea anyway but it's not necessary for every dorm.
- </p>
-
- <h2>Colonial Williamsburg</h2>
-
- <p>
- Lots of my peers didn't appreciate CW as a "college town" but I enjoyed
- my time there. I can't speak about parties or clubbing, I was boring and
- didn't do any of that. I made a great group of friends and we would walk
- into town to get ice cream, see historical attractions (most of which
- are free as a student, IIRC), and see movies or plays when we weren't
- studying or playing video games in the dorm. There are some good,
- sort-of-affordable restaurants but they're kind of driving distance.
- </p>
-
- <p>
- The best part about living there was meeting my wife. We would go on
- long walks to get away from studying and wound up seeing
- horse-and-carriages and the Governor's Palace and things like that. We
- would also escape with her car to go to some of the surrounding towns to
- get away to nice grocery stores and fun places to eat and explore on the
- weekends. I also have family in the area so it was easy for me to stop
- by home and say hi, although I know lots of students wanted to get as
- far away from home as possible.
- </p>
-
- <h2>Parting Words</h2>
-
- <p>
- I don't consider myself a gung ho alumnus. There are lots of things I
- think could be improved, both in CS and at W&amp;M as a whole but I do
- not regret my going there. There is no such thing as "everything is
- great" or "everything is terrible". It's not so definitive. I had my
- fair share of gripes and at times it strained me. There were pros and
- cons but I think I have a lot to be thankful for (I landed my job
- through W&amp;M recruiting and the career center as well, which are
- fantastic resources). I cannot say "do this instead of that." I haven't
- gone to any other colleges and don't know enough about them to recommend
- them as better or worse. What I can recommend is the same path I took
- for folks who want to pursue a degree in Computer Science. I think
- you'll come away from it all the more knowledgable, resourceful, and
- dedicated.
- </p>
- </article>
- </body>
-</html>
diff --git a/posts/2020-07-11-why-computer-science-at-w-m.php b/posts/2020-07-11-why-computer-science-at-w-m.php
new file mode 100644
index 0000000..f2fb3d1
--- /dev/null
+++ b/posts/2020-07-11-why-computer-science-at-w-m.php
@@ -0,0 +1,194 @@
+<?php
+$title = "Why Computer Science at William and Mary";
+if (isset($early) && $early) {
+ return;
+}
+include($_SERVER['DOCUMENT_ROOT'] . '/includes/head.php');
+?>
+
+<p class="description">
+ Recently a rising high-school senior asked for input on what going to
+ the College of William and Mary was like for a Computer Science degree.
+ They were asking about the program itself as well as what it's like on
+ and off campus. Here's what I sent to them.
+</p>
+
+<h2>Quick Intro</h2>
+
+<p>
+ I graduated with a Bachelor's in Computer Science from W&amp;M in 2018.
+ I'm a couple years in the workforce now but can still remember my
+ experiences well enough to hopefully add my honest opinion on my time
+ there as well as how it prepared me for my career. I will also add a
+ little bit about my time on campus in a dorm and off-campus in Colonial
+ Williamsburg.
+</p>
+
+<h2>Courses and Curriculum</h2>
+
+<p>
+ I felt very positively about the array of courses that were offered
+ while I was a student. I took a variety of core prerequisites, just like
+ everyone else, and a good mix of electives. The courses I took include
+ Data Structures and Algorithms, Software Development/Engineering,
+ Computer Organization/Architecture, UNIX Systems Programming, Computer
+ Graphics/Animation, and Computer and Network Security. This list is not
+ exhaustive and I'm sure they aren't all offered anymore. I was also
+ required to take a few math classes (Calc I, II, Discrete Math, Linear
+ Algebra, and Finite Automata).
+</p>
+
+<p>
+ It is true that the courses listed at <code>cs.wm.edu</code> aren't all
+ offered at the same time. And it is also true that the higher-level
+ electives pretty much all required my core prerequisites to be
+ completed. The result is that the electives all came in my final two
+ years. My understanding is the curriculum is designed to give someone
+ the best possible background in computing as a whole. A lot of the
+ topics may seem like they would never be useful in the "real world" but
+ I have found the opposite is true. I am an application developer at a
+ three-letter company. My day-to-day work is building and debugging web
+ apps, but there's been a lot more to it than that. My first assignment
+ on the job was scraping bytes off a remote shell and writing a parser to
+ sift through them. The level of understanding I gathered from my core
+ classes helped more than I expected they would. I think as a whole they
+ give me an edge at work and help me teach my colleagues about
+ algorithms, performance, and systems administration.
+</p>
+
+<p>
+ That being said, course registration was always nightmarish. It was very
+ difficult to get into the limited seats in the classes I was most
+ interested in. Eventually the heads of the department had to pass around
+ a sign up sheet and organize every student into courses, classrooms, and
+ professors so that seniors would graduate on time and we could all get
+ <em>something</em> on our schedules. I hope the shortage of teachers has
+ caught up since I graduated. I learned from a long-time faculty member
+ that this is largely a result of the exponential growth of incoming CS
+ degree-seekers. The program has grown very popular in the last ten years
+ and I like to think grads are catching on to that.
+</p>
+
+<h2>Teaching</h2>
+
+<p>
+ CS@W&amp;M had neutral to good instructors for me. Some were far worse
+ than others, as with all subjects. When I was there, lots of the older
+ faculty were retiring and quickly being replaced with younger, newer
+ instructors, which added to the growing pains of the program. The most
+ important thing again was making sure there were enough teachers to
+ teach all of the students.
+</p>
+
+<p>
+ I know a few of my peers were very upset about what they described as a
+ lack of communication or availability from their professors. Some have
+ also mentioned they didn't like having to learn material on their own
+ and wanted more to come from instruction. I don't deny that the material
+ itself was difficult and there was a lot of hard work I had to do on my
+ own to understand very involved concepts in intense, fast-paced courses.
+ I think that hard work has paid off. I don't think there's realistically
+ anywhere someone can learn about computing where they won't do any
+ learning on their own. I am also a very visual, and hands-on learner so
+ I suppose your mileage may vary.
+</p>
+
+<p>
+ The most important takeaway from this for me was the ability to pick up
+ new concepts and technologies quickly and apply them productively. The
+ majority of professors had project-driven courses. Lots of due dates
+ meant learning how to transform what I read or learned in class into
+ practical applications in short amounts of time. This has become,
+ according to those I work with, one of my greater assets. I am
+ constantly learning new things in my career and I don't have a lecturer
+ to explain things to me. It's very powerful to have that and I am
+ thankful for it. It also helps me teach that knowledge to my colleagues
+ so we can move faster as a team.
+</p>
+
+<h2>Campus</h2>
+
+<p>
+ I agree with my peers about the conditions of classrooms and buildings
+ on campus. Some are old. I guess that comes with an old university but
+ there are a choice few that haven't been kept up as best they could.
+ Since CS is growing so fast it's also long outgrown its own offices.
+ Classrooms are scattered throughout every academic building on campus
+ and I probably had a CS course in at least 80% of them. That meant
+ jumping from one side of campus to another and back again in between
+ periods.
+</p>
+
+<p>
+ The College itself isn't too sprawling. I am long-legged and I found I
+ could get from one end of campus to another in fifteen minutes on foot.
+ I rode bike a lot to get to classes where I only had ten minutes to do
+ it. It's also pretty marshy and woodsy in a lot of areas, so during the
+ rainy season some walking paths got muddy or flooded. Good boots
+ required. I have never been in as good shape as when I had to do all
+ that walking but I definitely got soaked and winded making those
+ transitions.
+</p>
+
+<p>
+ I appreciate history and architecture and was drawn in by the look and
+ feel of William and Mary as a result. Without getting too romantic, it's
+ definitely a beautiful place to attend classes. The ancient Wren
+ building still holds classes and it's a monument to the College's
+ tradition. However, I really appreciated the modern academic buildings
+ on the other side of campus where all of the new construction was taking
+ place. Modern lab equipment and the library lived there.
+</p>
+
+<p>
+ The dorms were nothing to write home about. Lots of them were nested in
+ the woods and built ages ago so they were a little tired and even dingy.
+ Others are brand new and well maintained; ask around and get opinions on
+ which ones to go for first chance you get. I made do with what I got for
+ the first couple of years by keeping it clean and decorated. My last two
+ years I lived in a couple of off-campus apartments. It was well worth
+ the switch. Depending on where you are on campus you may need at least a
+ bike to access local restaurants, shops, and the grocery store. A bike
+ is a good idea anyway but it's not necessary for every dorm.
+</p>
+
+<h2>Colonial Williamsburg</h2>
+
+<p>
+ Lots of my peers didn't appreciate CW as a "college town" but I enjoyed
+ my time there. I can't speak about parties or clubbing, I was boring and
+ didn't do any of that. I made a great group of friends and we would walk
+ into town to get ice cream, see historical attractions (most of which
+ are free as a student, IIRC), and see movies or plays when we weren't
+ studying or playing video games in the dorm. There are some good,
+ sort-of-affordable restaurants but they're kind of driving distance.
+</p>
+
+<p>
+ The best part about living there was meeting my wife. We would go on
+ long walks to get away from studying and wound up seeing
+ horse-and-carriages and the Governor's Palace and things like that. We
+ would also escape with her car to go to some of the surrounding towns to
+ get away to nice grocery stores and fun places to eat and explore on the
+ weekends. I also have family in the area so it was easy for me to stop
+ by home and say hi, although I know lots of students wanted to get as
+ far away from home as possible.
+</p>
+
+<h2>Parting Words</h2>
+
+<p>
+ I don't consider myself a gung ho alumnus. There are lots of things I
+ think could be improved, both in CS and at W&amp;M as a whole but I do
+ not regret my going there. There is no such thing as "everything is
+ great" or "everything is terrible". It's not so definitive. I had my
+ fair share of gripes and at times it strained me. There were pros and
+ cons but I think I have a lot to be thankful for (I landed my job
+ through W&amp;M recruiting and the career center as well, which are
+ fantastic resources). I cannot say "do this instead of that." I haven't
+ gone to any other colleges and don't know enough about them to recommend
+ them as better or worse. What I can recommend is the same path I took
+ for folks who want to pursue a degree in Computer Science. I think
+ you'll come away from it all the more knowledgable, resourceful, and
+ dedicated.
+</p>
diff --git a/posts/2020-07-26-now-this-is-a-minimal-install.html b/posts/2020-07-26-now-this-is-a-minimal-install.html
deleted file mode 100644
index 487c6e4..0000000
--- a/posts/2020-07-26-now-this-is-a-minimal-install.html
+++ /dev/null
@@ -1,101 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta property="og:image" content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview" />
- <meta property="og:site_name" content="53hor.net" />
- <meta property="og:title" content="Now This is a Minimal Install!" />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>53hornet ➙ Now This is a Minimal Install!</title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <article>
- <h1>Now This is a Minimal Install!</h1>
-
- <p>
- I just got done configuring Poudriere on Freebsd 12.1-RELEASE. The
- awesome thing about it is it allows you to configure and maintain your
- own package repository. All of the ports and their dependencies are
- built from source with personalized options. That means that I can
- maintain my own repo of just the packages I need with just the
- compile-time options I need. For example, for the Nvidia driver set I
- disabled all Wayland related flags. I use Xorg so there was no need to
- have that functionality built in.
- </p>
-
- <p>
- Compile times are pretty long but I hope to change that by upgrading my
- home server to FreeBSD as well (from Ubuntu Server). Then I can
- configure poudriere to serve up a ports tree and my own pkg repo from
- there. The server is a lot faster than my laptop and will build packages
- way faster, and I'll be able to use those packages on both the server
- and my laptop and any jails I have running. Jails (and ZFS) also make
- poudriere really cool to use as all of the building is done inside a
- jail. When the time comes I can just remove the jail and poudriere ports
- tree from my laptop and update pkg to point to my web server.
- </p>
-
- <p>
- This is, as I understand it, the sane way to do package management in
- FreeBSD. The binary package repo is basically the ports tree
- pre-assembled with default options. Sometimes those packages are
- compiled without functionality that most users don't need. In those
- situations, you're forced to use ports. The trouble is you're not really
- supposed to mix ports and binary packages. The reason, again as I
- understand it, is because ports are updated more frequently. So binary
- packages and ports can have different dependency versions, which can
- sometimes break compatibility on an upgrade. Most FreeBSD users
- recommend installing everything with ports (which is just a make install
- inside the local tree) but then you lose the package management features
- that come with pkg. Poudriere lets you kind of do both by creating your
- "own personal binary repo" out of a list of preconfigured, pre-built
- ports.
- </p>
-
- <p>FreeBSD rocks.</p>
- </article>
- </body>
-</html>
diff --git a/posts/2020-07-26-now-this-is-a-minimal-install.php b/posts/2020-07-26-now-this-is-a-minimal-install.php
new file mode 100644
index 0000000..3165b71
--- /dev/null
+++ b/posts/2020-07-26-now-this-is-a-minimal-install.php
@@ -0,0 +1,49 @@
+<?php
+$title = "Now This is a Minimal Install!";
+if (isset($early) && $early) {
+ return;
+}
+include($_SERVER['DOCUMENT_ROOT'] . '/includes/head.php');
+?>
+
+<p>
+ I just got done configuring Poudriere on Freebsd 12.1-RELEASE. The
+ awesome thing about it is it allows you to configure and maintain your
+ own package repository. All of the ports and their dependencies are
+ built from source with personalized options. That means that I can
+ maintain my own repo of just the packages I need with just the
+ compile-time options I need. For example, for the Nvidia driver set I
+ disabled all Wayland related flags. I use Xorg so there was no need to
+ have that functionality built in.
+</p>
+
+<p>
+ Compile times are pretty long but I hope to change that by upgrading my
+ home server to FreeBSD as well (from Ubuntu Server). Then I can
+ configure poudriere to serve up a ports tree and my own pkg repo from
+ there. The server is a lot faster than my laptop and will build packages
+ way faster, and I'll be able to use those packages on both the server
+ and my laptop and any jails I have running. Jails (and ZFS) also make
+ poudriere really cool to use as all of the building is done inside a
+ jail. When the time comes I can just remove the jail and poudriere ports
+ tree from my laptop and update pkg to point to my web server.
+</p>
+
+<p>
+ This is, as I understand it, the sane way to do package management in
+ FreeBSD. The binary package repo is basically the ports tree
+ pre-assembled with default options. Sometimes those packages are
+ compiled without functionality that most users don't need. In those
+ situations, you're forced to use ports. The trouble is you're not really
+ supposed to mix ports and binary packages. The reason, again as I
+ understand it, is because ports are updated more frequently. So binary
+ packages and ports can have different dependency versions, which can
+ sometimes break compatibility on an upgrade. Most FreeBSD users
+ recommend installing everything with ports (which is just a make install
+ inside the local tree) but then you lose the package management features
+ that come with pkg. Poudriere lets you kind of do both by creating your
+ "own personal binary repo" out of a list of preconfigured, pre-built
+ ports.
+</p>
+
+<p>FreeBSD rocks.</p>
diff --git a/posts/2020-11-30-titanics-last-signals.html b/posts/2020-11-30-titanics-last-signals.html
deleted file mode 100644
index 9335069..0000000
--- a/posts/2020-11-30-titanics-last-signals.html
+++ /dev/null
@@ -1,73 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta property="og:image" content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview" />
- <meta property="og:site_name" content="53hor.net" />
- <meta property="og:title" content="Titanic's Last Signals" />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>53hornet ➙ Titanic's Last Signals</title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <article>
- <h1>Titanic's Last Signals</h1>
- <p>
- I forgot to post this back in April but 108 years ago, a chilling and
- heroic conversation was had over the airwaves. This is a fascinating way
- to hear the real conversations that took place the night the Titanic
- went down with 1,496 souls.
- </p>
- <iframe
- width="560"
- height="315"
- src="https://www.youtube.com/embed/FxRN2nP_9dA"
- frameborder="0"
- allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
- allowfullscreen
- ></iframe>
- </article>
- </body>
-</html>
diff --git a/posts/2020-11-30-titanics-last-signals.php b/posts/2020-11-30-titanics-last-signals.php
new file mode 100644
index 0000000..03c0b96
--- /dev/null
+++ b/posts/2020-11-30-titanics-last-signals.php
@@ -0,0 +1,14 @@
+<?php
+$title = "Titanic's Last Signals";
+if (isset($early) && $early) {
+ return;
+}
+include($_SERVER['DOCUMENT_ROOT'] . '/includes/head.php');
+?>
+<p>
+ I forgot to post this back in April but 108 years ago, a chilling and
+ heroic conversation was had over the airwaves. This is a fascinating way
+ to hear the real conversations that took place the night the Titanic
+ went down with 1,496 souls.
+</p>
+<iframe width="560" height="315" src="https://www.youtube.com/embed/FxRN2nP_9dA" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
diff --git a/posts/2020-12-01-the-guides.html b/posts/2020-12-01-the-guides.html
deleted file mode 100644
index 28905d2..0000000
--- a/posts/2020-12-01-the-guides.html
+++ /dev/null
@@ -1,117 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta property="og:image" content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview" />
- <meta property="og:site_name" content="53hor.net" />
- <meta property="og:title" content="[The Guides]" />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>53hornet ➙ [The Guides]</title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <article>
- <h1>𝔗𝔥𝔢 𝔊𝔲𝔦𝔡𝔢𝔰</h1>
-
- <p class="description">
- This is partly satirical and purposefully strange to be humorous. These
- are my personal rules for software development (and other projects where
- I get carried away easily).
- </p>
-
- <p><em>The Guides.</em> The Guiding Principles.</p>
-
- <p>
- They guide you. They will not lead you astray. Obey <em>The Guides</em>.
- </p>
-
- <p>
- You've heard them go by different names. YAGNI. KISS. These are not
- falsehoods, but they are not <em>The Guides</em>. Seek the wisdom of the
- guides.
- </p>
-
- <blockquote>
- 𝔗𝔥𝔬𝔲 𝔰𝔥𝔞𝔩𝔱 𝔴𝔯𝔦𝔱𝔢 𝔞𝔰 𝔩𝔦𝔱𝔱𝔩𝔢 𝔠𝔬𝔡𝔢 𝔞𝔰 𝔭𝔬𝔰𝔰𝔦𝔟𝔩𝔢 𝔱𝔬 𝔤𝔢𝔱 𝔱𝔥𝔢 𝔧𝔬𝔟 𝔡𝔬𝔫𝔢 𝔯𝔦𝔤𝔥𝔱.
- </blockquote>
-
- <blockquote>
- O Guides, may I please just add this one extra feature? It won't take me
- long and it will be so nice to have later.
- </blockquote>
-
- <blockquote>
- 𝔗𝔥𝔬𝔲 𝔰𝔥𝔞𝔩𝔱 𝔴𝔯𝔦𝔱𝔢 𝖔𝖓𝖑𝖞 𝖙𝖍𝖊 𝖈𝖔𝖉𝖊 𝖓𝖊𝖈𝖊𝖘𝖘𝖆𝖗𝖞 𝔱𝔬 𝔤𝔢𝔱 𝔱𝔥𝔢 𝔧𝔬𝔟 𝔡𝔬𝔫𝔢 𝔯𝔦𝔤𝔥𝔱.
- </blockquote>
-
- <blockquote>
- O Guides, this can't be correct code. I haven't used proper software
- development patterns, processes, or practices.
- </blockquote>
-
- <blockquote>
- 𝔓𝔞𝔱𝔱𝔢𝔯𝔫𝔰 𝔣𝔬𝔯 𝔱𝔥𝔢 𝔰𝔞𝔨𝔢 𝔬𝔣 𝔭𝔞𝔱𝔱𝔢𝔯𝔫𝔰 𝔞𝔯𝔢 𝔞𝔫𝔱𝔦-𝔭𝔞𝔱𝔱𝔢𝔯𝔫𝔰.
- </blockquote>
-
- <blockquote>
- O Guides, how may I approach this project pragmatically?
- </blockquote>
-
- <blockquote>ℌ𝔢𝔢𝔡 𝔱𝔥𝔢𝔰𝔢 𝔯𝔲𝔩𝔢𝔰:</blockquote>
-
- <ol>
- <li>
- You may only write code directly related to the task at hand. Don't
- get distracted.
- </li>
- <li>
- Once you have working code, make it correct. Once it is correct, make
- it secure. Once it is secure, make it small. Once it is small, stop.
- </li>
- <li>The enemy of good is better.</li>
- </ol>
- </article>
- </body>
-</html>
diff --git a/posts/2020-12-01-the-guides.php b/posts/2020-12-01-the-guides.php
new file mode 100644
index 0000000..a3629be
--- /dev/null
+++ b/posts/2020-12-01-the-guides.php
@@ -0,0 +1,65 @@
+<?php
+$title = "𝔗𝔥𝔢 𝔊𝔲𝔦𝔡𝔢𝔰";
+if (isset($early) && $early) {
+ return;
+}
+include($_SERVER['DOCUMENT_ROOT'] . '/includes/head.php');
+?>
+
+<p class="description">
+ This is partly satirical and purposefully strange to be humorous. These
+ are my personal rules for software development (and other projects where
+ I get carried away easily).
+</p>
+
+<p><em>The Guides.</em> The Guiding Principles.</p>
+
+<p>
+ They guide you. They will not lead you astray. Obey <em>The Guides</em>.
+</p>
+
+<p>
+ You've heard them go by different names. YAGNI. KISS. These are not
+ falsehoods, but they are not <em>The Guides</em>. Seek the wisdom of the
+ guides.
+</p>
+
+<blockquote>
+ 𝔗𝔥𝔬𝔲 𝔰𝔥𝔞𝔩𝔱 𝔴𝔯𝔦𝔱𝔢 𝔞𝔰 𝔩𝔦𝔱𝔱𝔩𝔢 𝔠𝔬𝔡𝔢 𝔞𝔰 𝔭𝔬𝔰𝔰𝔦𝔟𝔩𝔢 𝔱𝔬 𝔤𝔢𝔱 𝔱𝔥𝔢 𝔧𝔬𝔟 𝔡𝔬𝔫𝔢 𝔯𝔦𝔤𝔥𝔱.
+</blockquote>
+
+<blockquote>
+ O Guides, may I please just add this one extra feature? It won't take me
+ long and it will be so nice to have later.
+</blockquote>
+
+<blockquote>
+ 𝔗𝔥𝔬𝔲 𝔰𝔥𝔞𝔩𝔱 𝔴𝔯𝔦𝔱𝔢 𝖔𝖓𝖑𝖞 𝖙𝖍𝖊 𝖈𝖔𝖉𝖊 𝖓𝖊𝖈𝖊𝖘𝖘𝖆𝖗𝖞 𝔱𝔬 𝔤𝔢𝔱 𝔱𝔥𝔢 𝔧𝔬𝔟 𝔡𝔬𝔫𝔢 𝔯𝔦𝔤𝔥𝔱.
+</blockquote>
+
+<blockquote>
+ O Guides, this can't be correct code. I haven't used proper software
+ development patterns, processes, or practices.
+</blockquote>
+
+<blockquote>
+ 𝔓𝔞𝔱𝔱𝔢𝔯𝔫𝔰 𝔣𝔬𝔯 𝔱𝔥𝔢 𝔰𝔞𝔨𝔢 𝔬𝔣 𝔭𝔞𝔱𝔱𝔢𝔯𝔫𝔰 𝔞𝔯𝔢 𝔞𝔫𝔱𝔦-𝔭𝔞𝔱𝔱𝔢𝔯𝔫𝔰.
+</blockquote>
+
+<blockquote>
+ O Guides, how may I approach this project pragmatically?
+</blockquote>
+
+<blockquote>ℌ𝔢𝔢𝔡 𝔱𝔥𝔢𝔰𝔢 𝔯𝔲𝔩𝔢𝔰:</blockquote>
+
+<ol>
+ <li>
+ You may only write code directly related to the task at hand. Don't
+ get distracted.
+ </li>
+ <li>
+ Once you have working code, make it correct. Once it is correct, make
+ it secure. Once it is secure, make it small. Once it is small, stop.
+ </li>
+ <li>The enemy of good is better.</li>
+</ol>
diff --git a/posts/2020-12-04-aoc-2020-day-1-in-cbm-basic.html b/posts/2020-12-04-aoc-2020-day-1-in-cbm-basic.html
deleted file mode 100644
index 66aabd2..0000000
--- a/posts/2020-12-04-aoc-2020-day-1-in-cbm-basic.html
+++ /dev/null
@@ -1,231 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta property="og:image" content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview" />
- <meta property="og:site_name" content="53hor.net" />
- <meta property="og:title" content="AOC 2020 Day 1 in CBM Basic" />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>53hornet ➙ AOC 2020 Day 1 in CBM Basic</title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <article>
- <h1>AOC 2020 Day 1 in CBM Basic</h1>
-
- <p class="description">
- I implemented the
- <a href="https://adventofcode.com/2020">Advent of Code 2020</a> Day 1
- challenge in CBM BASIC on a real Commodore 64. I haven't done anything
- in Basic in a long time, and probably never did anything actually
- meaningful with it. Part 1 of the challenge was to take a list of
- numbers, find the two that summed to 2020, and then multiply those two
- numbers together. Part two was to perform part 1 but with three numbers
- instead of two.
- </p>
- <p>
- Now I wanted to actually write the code on the Commodore 64 itself, but
- I gave myself some leniency. Instead of manually typing in all 200
- entries of input data (and inevitably making a breaking mistake) I used
- Vim on my PC to format the <code>DATA</code> entries at the start of the
- code. I then dropped that onto a 1541 disk image, plopped it on an SD
- card, and used my SD2IEC to mount the SD card's image on the Commodore.
- The rest of the programming was done on the Commodore itself.
- </p>
-
- <p>Here is my solution for Day 1 Part 1:</p>
- <pre>
- <code>
-10 DATA 1686, 1983, 1801, 1890, 1910, 1722, 1571, 1952, 1602, 1551, 1144
-11 DATA 1208, 1335, 1914, 1656, 1515, 1600, 1520, 1683, 1679, 1800, 1889
-12 DATA 1717, 1592, 1617, 1756, 1646, 1596, 1874, 1595, 1660, 1748, 1946
-13 DATA 1734, 1852, 2006, 1685, 1668, 1607, 1677, 403 , 1312, 1828, 1627
-14 DATA 1925, 1657, 1536, 1522, 1557, 1636, 1586, 1654, 1541, 1363, 1844
-15 DATA 1951, 1765, 1872, 696, 1764, 1718, 1540, 1493, 1947, 1786, 1548
-16 DATA 1981, 1861, 1589, 1707, 1915, 1755, 1906, 1911, 1628, 1980, 1986
-17 DATA 1780, 1645, 741 , 1727, 524 , 1690, 1732, 1956, 1523, 1534, 1498
-18 DATA 1510, 372 , 1777, 1585, 1614, 1712, 1650, 702 , 1773, 1713, 1797
-19 DATA 1691, 1758, 1973, 1560, 1615, 1933, 1281, 1899, 1845, 1752, 1542
-20 DATA 1694, 1950, 1879, 1684, 1809, 1988, 1978, 1843, 1730, 1377, 1507
-21 DATA 1506, 1566, 935 , 1851, 1995, 1796, 1900, 896 , 171, 1728, 1635
-22 DATA 1810, 2003, 1580, 1789, 1709, 2007, 1639, 1726, 1537, 1976, 1538
-23 DATA 1544, 1626, 1876, 1840, 1953, 1710, 1661, 1563, 1836, 1358, 1550
-24 DATA 1112, 1832, 1555, 1394, 1912, 1884, 1524, 1689, 1775, 1724, 1366
-25 DATA 1966, 1549, 1931, 1975, 1500, 1667, 1674, 1771, 1631, 1662, 1902
-26 DATA 1970, 1864, 2004, 2010, 504 , 1714, 1917, 1907, 1704, 1501, 1812
-27 DATA 1349, 1577, 1638, 1886, 1157, 1761, 1676, 1731, 2001, 1261, 1154
-28 DATA 1769, 1529
-100 DIM A(200)
-110 FOR I=0TO199
-120 READ A(I)
-140 NEXT
-150 FOR I=0TO199
-160 B=A(I)
-170 FOR J=0TO199
-180 IF I=J THEN 210
-190 C=A(J)
-200 IF B+C=2020 THEN PRINT "!",B,C,B*C:STOP
-210 NEXT J
-220 NEXT I
- </code></pre>
-
- <p>
- I basically put all 200 numbers into data fields, and then defined an
- array large enough to read them into with <code>DIM</code>. Then I
- iterated over the array twice, checking each element against each other
- element to see if they summed to 2020. If they did, I printed them both
- and the product of the two found numbers and stopped further execution.
- </p>
- <p>
- There weren't really any special tricks to this implementation except
- remembering that I shouldn't be checking whether a number could sum to
- 2020 with itself.
- </p>
-
- <p>
- Then I got to move onto Part 2, and this is where things got
- interesting. Comparing any three numbers from the data meant the
- cognitively easiest way to solve the problem was a triple loop. This of
- course meant <code>O(n^3)</code> time, which the Commodore struggled
- with. I waited about an hour before I decided I could optimize just a
- little bit to speed up the search.
- </p>
-
- <p>
- I figured that for three numbers to sum to 2020, they all had to be
- pretty small. Most likely they were most (if not all) three digits
- instead of four. So I figured I could sort the entry data to make the
- search finish probably near the start of the first layer of iteration.
- Keep in mind I didn't want to pre-sort the data, I wanted the Commodore
- to work with the same exact input set it had for Part 1. So I turned to
- the simplest sorting algorithm I could remember:
- <a href="https://en.wikipedia.org/wiki/Bubble_sort">bubble sort</a>.
- </p>
-
- <p>Here is my solution for Day 1 Part 2:</p>
-
- <pre>
- <code>
-10 DATA 1686, 1983, 1801, 1890, 1910, 1722, 1571, 1952, 1602, 1551, 1144
-11 DATA 1208, 1335, 1914, 1656, 1515, 1600, 1520, 1683, 1679, 1800, 1889
-12 DATA 1717, 1592, 1617, 1756, 1646, 1596, 1874, 1595, 1660, 1748, 1946
-13 DATA 1734, 1852, 2006, 1685, 1668, 1607, 1677, 403 , 1312, 1828, 1627
-14 DATA 1925, 1657, 1536, 1522, 1557, 1636, 1586, 1654, 1541, 1363, 1844
-15 DATA 1951, 1765, 1872, 696, 1764, 1718, 1540, 1493, 1947, 1786, 1548
-16 DATA 1981, 1861, 1589, 1707, 1915, 1755, 1906, 1911, 1628, 1980, 1986
-17 DATA 1780, 1645, 741 , 1727, 524 , 1690, 1732, 1956, 1523, 1534, 1498
-18 DATA 1510, 372 , 1777, 1585, 1614, 1712, 1650, 702 , 1773, 1713, 1797
-19 DATA 1691, 1758, 1973, 1560, 1615, 1933, 1281, 1899, 1845, 1752, 1542
-20 DATA 1694, 1950, 1879, 1684, 1809, 1988, 1978, 1843, 1730, 1377, 1507
-21 DATA 1506, 1566, 935 , 1851, 1995, 1796, 1900, 896 , 171, 1728, 1635
-22 DATA 1810, 2003, 1580, 1789, 1709, 2007, 1639, 1726, 1537, 1976, 1538
-23 DATA 1544, 1626, 1876, 1840, 1953, 1710, 1661, 1563, 1836, 1358, 1550
-24 DATA 1112, 1832, 1555, 1394, 1912, 1884, 1524, 1689, 1775, 1724, 1366
-25 DATA 1966, 1549, 1931, 1975, 1500, 1667, 1674, 1771, 1631, 1662, 1902
-26 DATA 1970, 1864, 2004, 2010, 504 , 1714, 1917, 1907, 1704, 1501, 1812
-27 DATA 1349, 1577, 1638, 1886, 1157, 1761, 1676, 1731, 2001, 1261, 1154
-28 DATA 1769, 1529
-100 DIM A(200)
-110 FOR I=0TO199
-120 READ A(I)
-140 NEXT
-141 GOSUB 300
-150 FOR I=0TO199
-160 B=A(I)
-170 FOR J=0TO199
-180 IF J=I THEN 250
-190 C=A(J)
-200 FOR K=0TO199
-210 IF K=I OR K=J THEN 240
-220 D=A(K)
-230 IF B+C+D=2020 THEN PRINT "!",B,C,D,B*C*D:STOP
-240 NEXT K
-250 NEXT J
-260 NEXT I
-300 REM BUBBLE SORT
-301 X=200
-310 N=200
-320 FOR I=0TON-2
-330 FOR J=0TON-I-2
-340 X=A(J):Y=A(J+1)
-350 IF X>Y THEN A(J)=Y:A(J+1)=X
-360 NEXT : NEXT
-370 RETURN
- </code>
- </pre>
-
- <p>
- I added a subroutine starting on line 300 to perform a basic bubble sort
- on top of the original array of data. Now bubble sort isn't fast by any
- means, but the Commodore was able to finish it in a couple of minutes.
- And the results were worth it because the subsequent triple
- <code>FOR</code>-loop completed in another few minutes. My instinct was
- right and two of the solution numbers were triple-digit.
- </p>
-
- <p>
- So there you have it, Advent of Code 2020 Day 1 in Commodore 64 Basic
- V2. You can run these samples on real hardware of course, or in an
- emulator. You can also run them with the
- <a href="https://github.com/mist64/cbmbasic"><code>cbmbasic</code></a>
- interpreter, which is a neat native C64 Basic interpreter for modern
- architectures. (Oh and I tested my samples on <code>cbmbasic</code> and
- they finished instantaneously. It helps to have a
- thousands-of-times-faster processor.)
- </p>
-
- <p>
- I was going to keep going with the challenge and finish them all in CBM
- basic for fun, but the Day 2 input data set was 1000 entries. No
- problem, I can just read them from a <code>SEQ</code> file. The only
- blocker I realized was the challenge requires string character counting,
- which I don't think there's a function for in CBM basic. Maybe I have to
- do a few <code>PEEK</code>s and <code>POKE</code>s to check memory
- locations for ASCII/PETSCII character codes. Or I could just put it off
- til next year :)
- </p>
- </article>
- </body>
-</html>
diff --git a/posts/2020-12-04-aoc-2020-day-1-in-cbm-basic.php b/posts/2020-12-04-aoc-2020-day-1-in-cbm-basic.php
new file mode 100644
index 0000000..5196d2c
--- /dev/null
+++ b/posts/2020-12-04-aoc-2020-day-1-in-cbm-basic.php
@@ -0,0 +1,179 @@
+<?php
+$title = "AOC 2020 Day 1 in CBM Basic";
+if (isset($early) && $early) {
+ return;
+}
+include($_SERVER['DOCUMENT_ROOT'] . '/includes/head.php');
+?>
+
+<p class="description">
+ I implemented the
+ <a href="https://adventofcode.com/2020">Advent of Code 2020</a> Day 1
+ challenge in CBM BASIC on a real Commodore 64. I haven't done anything
+ in Basic in a long time, and probably never did anything actually
+ meaningful with it. Part 1 of the challenge was to take a list of
+ numbers, find the two that summed to 2020, and then multiply those two
+ numbers together. Part two was to perform part 1 but with three numbers
+ instead of two.
+</p>
+<p>
+ Now I wanted to actually write the code on the Commodore 64 itself, but
+ I gave myself some leniency. Instead of manually typing in all 200
+ entries of input data (and inevitably making a breaking mistake) I used
+ Vim on my PC to format the <code>DATA</code> entries at the start of the
+ code. I then dropped that onto a 1541 disk image, plopped it on an SD
+ card, and used my SD2IEC to mount the SD card's image on the Commodore.
+ The rest of the programming was done on the Commodore itself.
+</p>
+
+<p>Here is my solution for Day 1 Part 1:</p>
+<pre>
+ <code>
+10 DATA 1686, 1983, 1801, 1890, 1910, 1722, 1571, 1952, 1602, 1551, 1144
+11 DATA 1208, 1335, 1914, 1656, 1515, 1600, 1520, 1683, 1679, 1800, 1889
+12 DATA 1717, 1592, 1617, 1756, 1646, 1596, 1874, 1595, 1660, 1748, 1946
+13 DATA 1734, 1852, 2006, 1685, 1668, 1607, 1677, 403 , 1312, 1828, 1627
+14 DATA 1925, 1657, 1536, 1522, 1557, 1636, 1586, 1654, 1541, 1363, 1844
+15 DATA 1951, 1765, 1872, 696, 1764, 1718, 1540, 1493, 1947, 1786, 1548
+16 DATA 1981, 1861, 1589, 1707, 1915, 1755, 1906, 1911, 1628, 1980, 1986
+17 DATA 1780, 1645, 741 , 1727, 524 , 1690, 1732, 1956, 1523, 1534, 1498
+18 DATA 1510, 372 , 1777, 1585, 1614, 1712, 1650, 702 , 1773, 1713, 1797
+19 DATA 1691, 1758, 1973, 1560, 1615, 1933, 1281, 1899, 1845, 1752, 1542
+20 DATA 1694, 1950, 1879, 1684, 1809, 1988, 1978, 1843, 1730, 1377, 1507
+21 DATA 1506, 1566, 935 , 1851, 1995, 1796, 1900, 896 , 171, 1728, 1635
+22 DATA 1810, 2003, 1580, 1789, 1709, 2007, 1639, 1726, 1537, 1976, 1538
+23 DATA 1544, 1626, 1876, 1840, 1953, 1710, 1661, 1563, 1836, 1358, 1550
+24 DATA 1112, 1832, 1555, 1394, 1912, 1884, 1524, 1689, 1775, 1724, 1366
+25 DATA 1966, 1549, 1931, 1975, 1500, 1667, 1674, 1771, 1631, 1662, 1902
+26 DATA 1970, 1864, 2004, 2010, 504 , 1714, 1917, 1907, 1704, 1501, 1812
+27 DATA 1349, 1577, 1638, 1886, 1157, 1761, 1676, 1731, 2001, 1261, 1154
+28 DATA 1769, 1529
+100 DIM A(200)
+110 FOR I=0TO199
+120 READ A(I)
+140 NEXT
+150 FOR I=0TO199
+160 B=A(I)
+170 FOR J=0TO199
+180 IF I=J THEN 210
+190 C=A(J)
+200 IF B+C=2020 THEN PRINT "!",B,C,B*C:STOP
+210 NEXT J
+220 NEXT I
+ </code></pre>
+
+<p>
+ I basically put all 200 numbers into data fields, and then defined an
+ array large enough to read them into with <code>DIM</code>. Then I
+ iterated over the array twice, checking each element against each other
+ element to see if they summed to 2020. If they did, I printed them both
+ and the product of the two found numbers and stopped further execution.
+</p>
+<p>
+ There weren't really any special tricks to this implementation except
+ remembering that I shouldn't be checking whether a number could sum to
+ 2020 with itself.
+</p>
+
+<p>
+ Then I got to move onto Part 2, and this is where things got
+ interesting. Comparing any three numbers from the data meant the
+ cognitively easiest way to solve the problem was a triple loop. This of
+ course meant <code>O(n^3)</code> time, which the Commodore struggled
+ with. I waited about an hour before I decided I could optimize just a
+ little bit to speed up the search.
+</p>
+
+<p>
+ I figured that for three numbers to sum to 2020, they all had to be
+ pretty small. Most likely they were most (if not all) three digits
+ instead of four. So I figured I could sort the entry data to make the
+ search finish probably near the start of the first layer of iteration.
+ Keep in mind I didn't want to pre-sort the data, I wanted the Commodore
+ to work with the same exact input set it had for Part 1. So I turned to
+ the simplest sorting algorithm I could remember:
+ <a href="https://en.wikipedia.org/wiki/Bubble_sort">bubble sort</a>.
+</p>
+
+<p>Here is my solution for Day 1 Part 2:</p>
+
+<pre>
+ <code>
+10 DATA 1686, 1983, 1801, 1890, 1910, 1722, 1571, 1952, 1602, 1551, 1144
+11 DATA 1208, 1335, 1914, 1656, 1515, 1600, 1520, 1683, 1679, 1800, 1889
+12 DATA 1717, 1592, 1617, 1756, 1646, 1596, 1874, 1595, 1660, 1748, 1946
+13 DATA 1734, 1852, 2006, 1685, 1668, 1607, 1677, 403 , 1312, 1828, 1627
+14 DATA 1925, 1657, 1536, 1522, 1557, 1636, 1586, 1654, 1541, 1363, 1844
+15 DATA 1951, 1765, 1872, 696, 1764, 1718, 1540, 1493, 1947, 1786, 1548
+16 DATA 1981, 1861, 1589, 1707, 1915, 1755, 1906, 1911, 1628, 1980, 1986
+17 DATA 1780, 1645, 741 , 1727, 524 , 1690, 1732, 1956, 1523, 1534, 1498
+18 DATA 1510, 372 , 1777, 1585, 1614, 1712, 1650, 702 , 1773, 1713, 1797
+19 DATA 1691, 1758, 1973, 1560, 1615, 1933, 1281, 1899, 1845, 1752, 1542
+20 DATA 1694, 1950, 1879, 1684, 1809, 1988, 1978, 1843, 1730, 1377, 1507
+21 DATA 1506, 1566, 935 , 1851, 1995, 1796, 1900, 896 , 171, 1728, 1635
+22 DATA 1810, 2003, 1580, 1789, 1709, 2007, 1639, 1726, 1537, 1976, 1538
+23 DATA 1544, 1626, 1876, 1840, 1953, 1710, 1661, 1563, 1836, 1358, 1550
+24 DATA 1112, 1832, 1555, 1394, 1912, 1884, 1524, 1689, 1775, 1724, 1366
+25 DATA 1966, 1549, 1931, 1975, 1500, 1667, 1674, 1771, 1631, 1662, 1902
+26 DATA 1970, 1864, 2004, 2010, 504 , 1714, 1917, 1907, 1704, 1501, 1812
+27 DATA 1349, 1577, 1638, 1886, 1157, 1761, 1676, 1731, 2001, 1261, 1154
+28 DATA 1769, 1529
+100 DIM A(200)
+110 FOR I=0TO199
+120 READ A(I)
+140 NEXT
+141 GOSUB 300
+150 FOR I=0TO199
+160 B=A(I)
+170 FOR J=0TO199
+180 IF J=I THEN 250
+190 C=A(J)
+200 FOR K=0TO199
+210 IF K=I OR K=J THEN 240
+220 D=A(K)
+230 IF B+C+D=2020 THEN PRINT "!",B,C,D,B*C*D:STOP
+240 NEXT K
+250 NEXT J
+260 NEXT I
+300 REM BUBBLE SORT
+301 X=200
+310 N=200
+320 FOR I=0TON-2
+330 FOR J=0TON-I-2
+340 X=A(J):Y=A(J+1)
+350 IF X>Y THEN A(J)=Y:A(J+1)=X
+360 NEXT : NEXT
+370 RETURN
+ </code>
+ </pre>
+
+<p>
+ I added a subroutine starting on line 300 to perform a basic bubble sort
+ on top of the original array of data. Now bubble sort isn't fast by any
+ means, but the Commodore was able to finish it in a couple of minutes.
+ And the results were worth it because the subsequent triple
+ <code>FOR</code>-loop completed in another few minutes. My instinct was
+ right and two of the solution numbers were triple-digit.
+</p>
+
+<p>
+ So there you have it, Advent of Code 2020 Day 1 in Commodore 64 Basic
+ V2. You can run these samples on real hardware of course, or in an
+ emulator. You can also run them with the
+ <a href="https://github.com/mist64/cbmbasic"><code>cbmbasic</code></a>
+ interpreter, which is a neat native C64 Basic interpreter for modern
+ architectures. (Oh and I tested my samples on <code>cbmbasic</code> and
+ they finished instantaneously. It helps to have a
+ thousands-of-times-faster processor.)
+</p>
+
+<p>
+ I was going to keep going with the challenge and finish them all in CBM
+ basic for fun, but the Day 2 input data set was 1000 entries. No
+ problem, I can just read them from a <code>SEQ</code> file. The only
+ blocker I realized was the challenge requires string character counting,
+ which I don't think there's a function for in CBM basic. Maybe I have to
+ do a few <code>PEEK</code>s and <code>POKE</code>s to check memory
+ locations for ASCII/PETSCII character codes. Or I could just put it off
+ til next year :)
+</p>
diff --git a/posts/2020-12-08-useful-sprint-planning-from-a-certified-scrum-master.html b/posts/2020-12-08-useful-sprint-planning-from-a-certified-scrum-master.html
deleted file mode 100644
index 01a9b3a..0000000
--- a/posts/2020-12-08-useful-sprint-planning-from-a-certified-scrum-master.html
+++ /dev/null
@@ -1,203 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta property="og:image" content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview" />
- <meta property="og:site_name" content="53hor.net" />
- <meta
- property="og:title"
- content="Useful Sprint Planning from a Certified Scrum Master"
- />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>
- 53hornet ➙ Useful Sprint Planning from a Certified Scrum Master
- </title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <article>
- <h1>Useful Sprint Planning from a Certified Scrum Master</h1>
-
- <p class="description">
- This is a small collection of sprint planning/story points allocation
- tips and tricks that I use at work. They pretty much all come from our
- in-house certified "Scrum Master". He's got much better experience than
- I do with building a real working backlog of stories and planning
- sprints based on those stories. That being said, any opinions here are
- my own and I don't speak on his behalf.
- </p>
-
- <h2>Points as a Measure of Work</h2>
-
- <p>
- In my understanding, points are approximate measures of the amount of
- work required to complete a given story or task. I do not think points
- correlate to an exact measure of time. I use them to determine the size
- of a task in relation to another task. For example, a simple-looking
- task may be allocated 1 point. In reality this 1 point may take 1 minute
- or 1 hour to complete. The time it takes is less important than the
- ratio of time it takes in comparison to a second given task. Say the
- second task appears to take twice as much time as the first (however
- much time that may be). The second task would therefore get 2 points.
- </p>
-
- <p>
- Some teams have a special system for incrementing points. Our team uses
- the
- <a href="https://en.wikipedia.org/wiki/Fibonacci#Fibonacci_sequence"
- >Fibonacci sequence of numbers</a
- >. So the smallest amount that can be allocated to a story is 1. Then it
- goes 2, 3, 5, 8, and so on and so forth. If a single story is going to
- use up 8 points, you should probably take a look at breaking it up into
- smaller tasks. A single story shouldn't take up almost half of your
- allocated work for a sprint.
- </p>
-
- <h2>How Much is Enough?</h2>
- <p>
- Our team aims for 10 points per 2-week per sprint. Simple enough for me,
- but the hard part is determining how many points to allocate to a given
- task.
- </p>
-
- <p>
- One thing I could never figure out is what the recommended starting
- position for 1 point looks like. I'm sure this is something that comes
- from experience, and our Scrum Master helped us out with that.
- </p>
-
- <ul>
- <li>
- 1 point: Small or basic text change. Updating configuration, fixing a
- typo or cognitively simple bug.
- </li>
- <li>
- 2 points: Task with light complexity. Some portions of code have to
- change, be debugged, tested.
- </li>
- <li>
- 3 points: Some complexity, will take time to implement. Potentially a
- few days' worth of work. May require front- and back-end work, or
- back-end and database work.
- </li>
- <li>
- 5 points: Half a sprint's worth of more complicated work. Full-on
- feature implementation for example.
- </li>
- </ul>
-
- <h2>Prioritizing Work</h2>
-
- <p>
- I do not see points as indicative of the importance or priority of a
- task or story. Just because one task will take longer to complete than
- another does not mean it's more or less important to me. There should be
- another method of gauging which stories should be taken off the backlog
- first. For example, one story might depend on another. One might relate
- to core functionality that a stakeholder has asked for. Another task
- might be required to make code build because it solves some major
- problem!
- </p>
-
- <p>
- To communicate how "important" a task is, every story we have is
- prioritized something like this:
- </p>
- <ol>
- <li>Critical</li>
- <li>Blocker</li>
- <li>Highest</li>
- <li>High</li>
- <li>Medium</li>
- <li>Low</li>
- <li>Lowest</li>
- </ol>
-
- <p>
- Tasks that align with some long-term project that management is waiting
- on are tagged "Highest". Stories that prevent lots of other stories from
- being completed may be labeled "Blocker".
- </p>
-
- <h2>Sprint Planning/Backlog Refinement</h2>
-
- <p>
- With all that in mind, at the start of the sprint I now take about 10
- points worth of priority work off of the backlog. I'll work through it
- the whole sprint through and then, ideally, it'll all be complete by the
- end of the sprint. If I bit off more than I could chew and the sprint
- ends before I'm finished, the incomplete work rolls over to the next
- sprint and is the first to be completed. If I find I've finished
- everything I had to work on and there are still a couple of days left in
- the sprint, I'll take one or two small items off the backlog and work on
- those.
- </p>
-
- <h2>Tools to Get the Job Done</h2>
-
- <p>
- Our team uses Jira at work, and I know some folks love it so much
- they've paid for a personal license. It's a bit overkill for my personal
- projects, so I've been using Nextcloud's Deck plugin. This is an okay
- solution but it doesn't integrate very well with source code
- repositories (although it can tie into a Nextcloud "project", or a
- collection of related files open to a team). I'm spinning up a Gitea
- server to replace my <code>git-web</code> server soon and this is one of
- the reasons for that. Gitea has a GitHub-style issue tracker where you
- can create issues of various kinds, assign them to users, reference
- commits to the source, and create a Kanban-style board of issues that
- are on the backlog, to-do, in-progress, or done.
- </p>
-
- <p>
- I'm still learning how to keep to a Scrum-like process of some kind,
- because I do see the benefit of using such a system, especially in a
- team. I'm definitely not an expert though so some of what I've got here
- may change over time. Right now it's working well and that's good enough
- for me.
- </p>
- </article>
- </body>
-</html>
diff --git a/posts/2020-12-08-useful-sprint-planning-from-a-certified-scrum-master.php b/posts/2020-12-08-useful-sprint-planning-from-a-certified-scrum-master.php
new file mode 100644
index 0000000..77aebdf
--- /dev/null
+++ b/posts/2020-12-08-useful-sprint-planning-from-a-certified-scrum-master.php
@@ -0,0 +1,144 @@
+<?php
+$title = "Useful Sprint Planning from a Certified Scrum Master";
+if (isset($early) && $early) {
+ return;
+}
+include($_SERVER['DOCUMENT_ROOT'] . '/includes/head.php');
+?>
+
+<p class="description">
+ This is a small collection of sprint planning/story points allocation
+ tips and tricks that I use at work. They pretty much all come from our
+ in-house certified "Scrum Master". He's got much better experience than
+ I do with building a real working backlog of stories and planning
+ sprints based on those stories. That being said, any opinions here are
+ my own and I don't speak on his behalf.
+</p>
+
+<h2>Points as a Measure of Work</h2>
+
+<p>
+ In my understanding, points are approximate measures of the amount of
+ work required to complete a given story or task. I do not think points
+ correlate to an exact measure of time. I use them to determine the size
+ of a task in relation to another task. For example, a simple-looking
+ task may be allocated 1 point. In reality this 1 point may take 1 minute
+ or 1 hour to complete. The time it takes is less important than the
+ ratio of time it takes in comparison to a second given task. Say the
+ second task appears to take twice as much time as the first (however
+ much time that may be). The second task would therefore get 2 points.
+</p>
+
+<p>
+ Some teams have a special system for incrementing points. Our team uses
+ the
+ <a href="https://en.wikipedia.org/wiki/Fibonacci#Fibonacci_sequence">Fibonacci sequence of numbers</a>. So the smallest amount that can be allocated to a story is 1. Then it
+ goes 2, 3, 5, 8, and so on and so forth. If a single story is going to
+ use up 8 points, you should probably take a look at breaking it up into
+ smaller tasks. A single story shouldn't take up almost half of your
+ allocated work for a sprint.
+</p>
+
+<h2>How Much is Enough?</h2>
+<p>
+ Our team aims for 10 points per 2-week per sprint. Simple enough for me,
+ but the hard part is determining how many points to allocate to a given
+ task.
+</p>
+
+<p>
+ One thing I could never figure out is what the recommended starting
+ position for 1 point looks like. I'm sure this is something that comes
+ from experience, and our Scrum Master helped us out with that.
+</p>
+
+<ul>
+ <li>
+ 1 point: Small or basic text change. Updating configuration, fixing a
+ typo or cognitively simple bug.
+ </li>
+ <li>
+ 2 points: Task with light complexity. Some portions of code have to
+ change, be debugged, tested.
+ </li>
+ <li>
+ 3 points: Some complexity, will take time to implement. Potentially a
+ few days' worth of work. May require front- and back-end work, or
+ back-end and database work.
+ </li>
+ <li>
+ 5 points: Half a sprint's worth of more complicated work. Full-on
+ feature implementation for example.
+ </li>
+</ul>
+
+<h2>Prioritizing Work</h2>
+
+<p>
+ I do not see points as indicative of the importance or priority of a
+ task or story. Just because one task will take longer to complete than
+ another does not mean it's more or less important to me. There should be
+ another method of gauging which stories should be taken off the backlog
+ first. For example, one story might depend on another. One might relate
+ to core functionality that a stakeholder has asked for. Another task
+ might be required to make code build because it solves some major
+ problem!
+</p>
+
+<p>
+ To communicate how "important" a task is, every story we have is
+ prioritized something like this:
+</p>
+<ol>
+ <li>Critical</li>
+ <li>Blocker</li>
+ <li>Highest</li>
+ <li>High</li>
+ <li>Medium</li>
+ <li>Low</li>
+ <li>Lowest</li>
+</ol>
+
+<p>
+ Tasks that align with some long-term project that management is waiting
+ on are tagged "Highest". Stories that prevent lots of other stories from
+ being completed may be labeled "Blocker".
+</p>
+
+<h2>Sprint Planning/Backlog Refinement</h2>
+
+<p>
+ With all that in mind, at the start of the sprint I now take about 10
+ points worth of priority work off of the backlog. I'll work through it
+ the whole sprint through and then, ideally, it'll all be complete by the
+ end of the sprint. If I bit off more than I could chew and the sprint
+ ends before I'm finished, the incomplete work rolls over to the next
+ sprint and is the first to be completed. If I find I've finished
+ everything I had to work on and there are still a couple of days left in
+ the sprint, I'll take one or two small items off the backlog and work on
+ those.
+</p>
+
+<h2>Tools to Get the Job Done</h2>
+
+<p>
+ Our team uses Jira at work, and I know some folks love it so much
+ they've paid for a personal license. It's a bit overkill for my personal
+ projects, so I've been using Nextcloud's Deck plugin. This is an okay
+ solution but it doesn't integrate very well with source code
+ repositories (although it can tie into a Nextcloud "project", or a
+ collection of related files open to a team). I'm spinning up a Gitea
+ server to replace my <code>git-web</code> server soon and this is one of
+ the reasons for that. Gitea has a GitHub-style issue tracker where you
+ can create issues of various kinds, assign them to users, reference
+ commits to the source, and create a Kanban-style board of issues that
+ are on the backlog, to-do, in-progress, or done.
+</p>
+
+<p>
+ I'm still learning how to keep to a Scrum-like process of some kind,
+ because I do see the benefit of using such a system, especially in a
+ team. I'm definitely not an expert though so some of what I've got here
+ may change over time. Right now it's working well and that's good enough
+ for me.
+</p>
diff --git a/posts/2020-12-22-why-does-everyone-use-adobe-acrobat-reader.html b/posts/2020-12-22-why-does-everyone-use-adobe-acrobat-reader.html
deleted file mode 100644
index bd1dba7..0000000
--- a/posts/2020-12-22-why-does-everyone-use-adobe-acrobat-reader.html
+++ /dev/null
@@ -1,144 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta
- property="og:image"
- content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview"
- />
- <meta property="og:site_name" content="53hor.net" />
- <meta
- property="og:title"
- content="Why Does Everyone Use Adobe Acrobat [Reader]?"
- />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>53hornet ➙ Why Does Everyone Use Adobe Acrobat [Reader]?</title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <article>
- <h1>Why Does Everyone Use Adobe Acrobat [Reader]?</h1>
-
- <p>
- <img
- src="https://nextcloud.53hor.net/index.php/s/Pq8ZPe8THoH3Eoo/preview"
- />
- </p>
-
- <p>
- This is something that I've never been able to figure out. All through
- high school I had to use PDFs. And if you wanted to open a PDF, everyone
- understood that you needed Adobe Acrobat Reader. Even web sites where
- you downloaded PDFs insisted that in order to open them, you were going
- to have to follow a download link to make sure you have Acrobat on your
- PC.
- </p>
-
- <p>
- Fast-forward a few years into college and I'm using PDFs more than ever.
- Every professor ever is scanning and uploading course material, so out
- comes Acrobat Reader for literally every teacher and student. At this
- point I was actually used to using Firefox (PDF.js) to view PDFs for a
- couple of reasons. First of all, Firefox usually opened PDFs faster than
- Acrobat Reader did. Reader was getting bigger with every release, and
- eventually had a monstrous UI to load up every time I wanted to open a
- tiny PDF file. Second, Firefox had smooth scrolling for page-width
- documents. Reader was getting slower and laggier with each release, to
- the point where scrolling through a PDF was no longer buttery smooth but
- jittery and stuttery. It also seemed like Reader purposefully wouldn't
- slide the page when you used a mouse wheel. It would jump down a few
- lines at a time like it was simulating the down arrow.
- </p>
-
- <p>
- By my senior year I had switched from Windows to Linux full-time and it
- was then I found out about <a href="https://mupdf.com/">MuPDF</a> and
- from then on things were never the same. It's literally the best PDF
- reader I've ever used, and I tried out quite a few. There are desktop
- and mobile apps. It opens almost instantly. It lets you easily resize
- the page with excellent keyboard shortcuts. There are no giant menu bars
- on either side of the page to squish the document down to an unreadable
- size. Having a dozen of them open at once doesn't bog down my PC. It's
- also available for all of the relevant operating systems I've used
- (Windows, Mac OS, Linux, FreeBSD)! Oh and password-protected PDFs are
- supported as well.
- </p>
-
- <p>
- It's a fantastic piece of software And the best part is it comes with a
- variety of tools to edit and manipulate PDFs as well. If the folks I
- went to school with thought you needed the free Acrobat Reader to view a
- PDF, they sure as heck thought you needed to buy Acrobat Pro to edit
- one. Some of them refused to pay for it and used a variety of online
- services to upload, split or merge, and download PDFs. I honestly for
- the life of me can't understand why. MuPDF comes with
- <code>mutool</code>, which does all of the things I would ever need to
- do with a PDF. It can attempt to convert a PDF to other formats, like
- HTML. It can split and combine documents. It can even create them from
- scratch and sign them.
- </p>
-
- <p>
- It's also free and open source. Can you imagine that? PDF viewing and
- editing being free and open source? It's AGPL (in addition to being
- commercially) licensed by the creators. The only slight drawback is the
- desktop version apparently does not yet let you fill out forms. Not sure
- why but this isn't something I use very frequently.
- </p>
-
- <p>
- It's not the hottest piece of tech out there, but it just plain works
- and works really well. Maybe the only reason more people I know don't
- use it is because Adobe is synonymous with the PDF format. It doesn't
- seem like that big of a deal, but I feel like Acrobat has always been a
- piece of software that has frustrated new or infrequent users in
- computing. And that's just not good. Maybe the barrier to using MuPDF is
- the lack of GUI and abundance of keybindings, but for me that's no
- sweat. I'd say to anyone to just try it out and see if they like it. It
- is free, after all.
- </p>
- </article>
- </body>
-</html>
diff --git a/posts/2020-12-22-why-does-everyone-use-adobe-acrobat-reader.php b/posts/2020-12-22-why-does-everyone-use-adobe-acrobat-reader.php
new file mode 100644
index 0000000..bb384f2
--- /dev/null
+++ b/posts/2020-12-22-why-does-everyone-use-adobe-acrobat-reader.php
@@ -0,0 +1,84 @@
+<?php
+$title = "Why Does Everyone Use Adobe Acrobat [Reader]?";
+if (isset($early) && $early) {
+ return;
+}
+include($_SERVER['DOCUMENT_ROOT'] . '/includes/head.php');
+?>
+
+<p>
+ <img src="https://nextcloud.53hor.net/index.php/s/Pq8ZPe8THoH3Eoo/preview" />
+</p>
+
+<p>
+ This is something that I've never been able to figure out. All through
+ high school I had to use PDFs. And if you wanted to open a PDF, everyone
+ understood that you needed Adobe Acrobat Reader. Even web sites where
+ you downloaded PDFs insisted that in order to open them, you were going
+ to have to follow a download link to make sure you have Acrobat on your
+ PC.
+</p>
+
+<p>
+ Fast-forward a few years into college and I'm using PDFs more than ever.
+ Every professor ever is scanning and uploading course material, so out
+ comes Acrobat Reader for literally every teacher and student. At this
+ point I was actually used to using Firefox (PDF.js) to view PDFs for a
+ couple of reasons. First of all, Firefox usually opened PDFs faster than
+ Acrobat Reader did. Reader was getting bigger with every release, and
+ eventually had a monstrous UI to load up every time I wanted to open a
+ tiny PDF file. Second, Firefox had smooth scrolling for page-width
+ documents. Reader was getting slower and laggier with each release, to
+ the point where scrolling through a PDF was no longer buttery smooth but
+ jittery and stuttery. It also seemed like Reader purposefully wouldn't
+ slide the page when you used a mouse wheel. It would jump down a few
+ lines at a time like it was simulating the down arrow.
+</p>
+
+<p>
+ By my senior year I had switched from Windows to Linux full-time and it
+ was then I found out about <a href="https://mupdf.com/">MuPDF</a> and
+ from then on things were never the same. It's literally the best PDF
+ reader I've ever used, and I tried out quite a few. There are desktop
+ and mobile apps. It opens almost instantly. It lets you easily resize
+ the page with excellent keyboard shortcuts. There are no giant menu bars
+ on either side of the page to squish the document down to an unreadable
+ size. Having a dozen of them open at once doesn't bog down my PC. It's
+ also available for all of the relevant operating systems I've used
+ (Windows, Mac OS, Linux, FreeBSD)! Oh and password-protected PDFs are
+ supported as well.
+</p>
+
+<p>
+ It's a fantastic piece of software And the best part is it comes with a
+ variety of tools to edit and manipulate PDFs as well. If the folks I
+ went to school with thought you needed the free Acrobat Reader to view a
+ PDF, they sure as heck thought you needed to buy Acrobat Pro to edit
+ one. Some of them refused to pay for it and used a variety of online
+ services to upload, split or merge, and download PDFs. I honestly for
+ the life of me can't understand why. MuPDF comes with
+ <code>mutool</code>, which does all of the things I would ever need to
+ do with a PDF. It can attempt to convert a PDF to other formats, like
+ HTML. It can split and combine documents. It can even create them from
+ scratch and sign them.
+</p>
+
+<p>
+ It's also free and open source. Can you imagine that? PDF viewing and
+ editing being free and open source? It's AGPL (in addition to being
+ commercially) licensed by the creators. The only slight drawback is the
+ desktop version apparently does not yet let you fill out forms. Not sure
+ why but this isn't something I use very frequently.
+</p>
+
+<p>
+ It's not the hottest piece of tech out there, but it just plain works
+ and works really well. Maybe the only reason more people I know don't
+ use it is because Adobe is synonymous with the PDF format. It doesn't
+ seem like that big of a deal, but I feel like Acrobat has always been a
+ piece of software that has frustrated new or infrequent users in
+ computing. And that's just not good. Maybe the barrier to using MuPDF is
+ the lack of GUI and abundance of keybindings, but for me that's no
+ sweat. I'd say to anyone to just try it out and see if they like it. It
+ is free, after all.
+</p>
diff --git a/posts/2020-12-29-antivirus-software-is-a-hack.html b/posts/2020-12-29-antivirus-software-is-a-hack.html
deleted file mode 100644
index 5c602a2..0000000
--- a/posts/2020-12-29-antivirus-software-is-a-hack.html
+++ /dev/null
@@ -1,197 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta
- property="og:image"
- content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview"
- />
- <meta property="og:site_name" content="53hor.net" />
- <meta property="og:title" content="Antivirus Software is a Hack" />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>53hornet ➙ Antivirus Software is a Hack</title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <article>
- <h1>Antivirus Software is a Hack</h1>
-
- <p>
- <img
- src="https://nextcloud.53hor.net/index.php/s/jJoFoA7Ppjb7rey/preview"
- />
- </p>
-
- <p class="description">
- I read a really terrific article today about computer security and
- really dumb ideas or trends that have developed in this field. It's
- <a
- href="https://www.ranum.com/security/computer_security/editorials/dumb/"
- >M. Ranum's <em>The Six Dumbest Ideas in Computer Security</em></a
- >, and I highly recommend reading through the whole thing. It's got
- great anecdotes and really simple language for what I consider to be
- some of the obvious issues with the way programmers and sysadmins think
- about security (myself included). One portion of it (idea #2), however,
- finally put something into words that I've felt for a really long time.
- It enables me to explain why I think all antivirus software is a total
- hack and is virtually useless.
- </p>
-
- <blockquote>
- hack<br />
- 1. n. Originally, a quick job that produces what is needed, but not
- well.
- <br />
- <cite>-- The Jargon File (version 4.4.7, 29 Dec 2003) [jargon]</cite>
- </blockquote>
-
- <p>
- This is the Jargon File's definition of a hack. And to me, this is what
- antivirus software is. Antivirus software, as I understand it, emerged
- in the mid to late 1980s and became prolific in the 1990s. In the 2000s
- it was considered an essential piece of software and people were paying
- for yearly subscriptions for antivirus suites from Norton, Avast, and
- McAfee.
- </p>
-
- <p>
- The most basic functionality of an antivirus program is to determine
- whether malware exists on a host operating system. The typical method of
- doing this is to use a collection of virus definitions and compare each
- and every potentially-infected file with each and every definition to
- determine whether the file is malware or has been infected by some. An
- over-simplified way of implementing this is to store a collection of
- hashes, each taken from a known potentially unwanted program or
- infectious executable. You can then hash entire files or portions of
- files and compare the checksums to see whether a file contains or is
- equivalent to the definition, and is therefore infected and shouldn't be
- executed. Some security suites go beyond this with heuristic matching,
- but if you run an antivirus that has to "update definitions" on a
- routine basis, it probably works something like this*. With any luck, it
- does it without being a total detriment to system performance. Ideally
- it also doesn't act like a piece of malware itself by making itself near
- impossible to remove (looking at you, McAfee).
- </p>
-
- <p>
- To me, a virus definition database is "enumerating badness" (Ranum's
- Dumb Idea #2). The premise is that it is not only logical but even
- possible to compile a list of <em>all</em> potentially unwanted
- programs, viruses, ransomware, and worms. An environment of trust should
- be built around the programs that you want to run (read:
- <em>allow to run</em>), not the other way around. Picture an operating
- system where no binary file can be executed unless it is specifically
- flagged as being allowed to. Oh and picture also being able to restrict
- this execution to just the file's owner, or other groups of users.
- Wouldn't it be easier to store the list of 30 odd programs that you and
- other system users trust to be run than the thousands (millions?) of
- programs that are infectious, forbidden, or unwanted? What about when
- those trusted applications become compromised? Would it not also be
- easier to maintain a list of checksums for those binaries and compare
- those checksums before they're executed to make sure they haven't been
- infected or replaced?
- </p>
-
- <p>
- The answer is yes, it would be easier. And yes, it is easier. Of course,
- your system has to work that way. Antivirus software is a hack because
- it's a hack-y solution to a problem that has a better, simpler solution.
- It also has the potential for making a ton of money but I won't go into
- that. It's easier to enumerate goodness, to specifically open up to a
- select few trustworthy applications. Good lists are usually shorter than
- bad lists. This builds on top of Ranum's Dumb Idea #1: Default Permit.
- You wouldn't configure a firewall to just block some known bad ports and
- traffic. You configure it to block all of it, and then whitelist the
- ones you know you can trust. You wouldn't configure a browser ad-blocker
- to permit all ads, and select the ones you don't want to see. You block
- all of them! Then, if there are sites or ads you're okay with seeing,
- you whitelist them. You shouldn't default permit all programs to be
- given control over your computer, and then meticulously list the ones
- that don't have that permission.
- </p>
-
- <p>
- Oh and of course, as always, there's free software that lets you do
- this. You don't have to pay for an antivirus suite, or even use an
- unpaid one that slows down your computer or barrages you with ads. On
- the BSDs and virtually all Linux distributions, there are built-in tools
- to control access and execution of binaries. There are additional tools
- that you can install that check whether binaries (in locations like
- <code>/bin</code> or <code>/usr/local/bin</code> have been modified
- since you last used them. On Windows, the story is a little different.
- Most home Windows 10 users are automatically allowed to install and run
- any software they want to by default. Windows Server does have Software
- Restriction Policies that allow you to create a "default deny" policy
- and whitelist only the software that's allowed to run. If you're using a
- home edition you probably have to look for software that lets you do
- this. I haven't tried any of them so I'm not going to endorse or even
- name them here.
- </p>
-
- <p>
- Preventing malware from running on your system is a problem. Solving
- this problem is the right thing to do. But please, try to solve it the
- right way. I stopped using an antivirus after I moved out and got to
- control my own computer. I don't think it ever did me any good besides
- flag false positives (a lot of the time with programs or applications
- that I wrote, which weren't malicious in any way!) and grind my spinning
- disk to a halt. Evaluate what software you use. Is most of it online?
- Are there one or two applications that you know you need to use? How
- often do you install and use unknown or untrusted software? Odds are you
- can come up with a list of very few programs that you want or need to
- use. If it's less than 100,000, you're probably better off with a
- default deny policy than an antivirus suite.
- </p>
-
- <p>
- * What I didn't mention here is that as soon as a new piece of malware
- is constructed, if it's different enough from its predecessors, it's
- impervious to all antivirus suites on the planet that don't have it in
- their definitions. So until that malware is used, detected, and added to
- the list, it has free reign.
- </p>
- </article>
- </body>
-</html>
diff --git a/posts/2020-12-29-antivirus-software-is-a-hack.php b/posts/2020-12-29-antivirus-software-is-a-hack.php
new file mode 100644
index 0000000..cc5f0d0
--- /dev/null
+++ b/posts/2020-12-29-antivirus-software-is-a-hack.php
@@ -0,0 +1,137 @@
+<?php
+$title = "Antivirus Software is a Hack";
+if (isset($early) && $early) {
+ return;
+}
+include($_SERVER['DOCUMENT_ROOT'] . '/includes/head.php');
+?>
+
+<p>
+ <img src="https://nextcloud.53hor.net/index.php/s/jJoFoA7Ppjb7rey/preview" />
+</p>
+
+<p class="description">
+ I read a really terrific article today about computer security and
+ really dumb ideas or trends that have developed in this field. It's
+ <a href="https://www.ranum.com/security/computer_security/editorials/dumb/">M. Ranum's <em>The Six Dumbest Ideas in Computer Security</em></a>, and I highly recommend reading through the whole thing. It's got
+ great anecdotes and really simple language for what I consider to be
+ some of the obvious issues with the way programmers and sysadmins think
+ about security (myself included). One portion of it (idea #2), however,
+ finally put something into words that I've felt for a really long time.
+ It enables me to explain why I think all antivirus software is a total
+ hack and is virtually useless.
+</p>
+
+<blockquote>
+ hack<br />
+ 1. n. Originally, a quick job that produces what is needed, but not
+ well.
+ <br />
+ <cite>-- The Jargon File (version 4.4.7, 29 Dec 2003) [jargon]</cite>
+</blockquote>
+
+<p>
+ This is the Jargon File's definition of a hack. And to me, this is what
+ antivirus software is. Antivirus software, as I understand it, emerged
+ in the mid to late 1980s and became prolific in the 1990s. In the 2000s
+ it was considered an essential piece of software and people were paying
+ for yearly subscriptions for antivirus suites from Norton, Avast, and
+ McAfee.
+</p>
+
+<p>
+ The most basic functionality of an antivirus program is to determine
+ whether malware exists on a host operating system. The typical method of
+ doing this is to use a collection of virus definitions and compare each
+ and every potentially-infected file with each and every definition to
+ determine whether the file is malware or has been infected by some. An
+ over-simplified way of implementing this is to store a collection of
+ hashes, each taken from a known potentially unwanted program or
+ infectious executable. You can then hash entire files or portions of
+ files and compare the checksums to see whether a file contains or is
+ equivalent to the definition, and is therefore infected and shouldn't be
+ executed. Some security suites go beyond this with heuristic matching,
+ but if you run an antivirus that has to "update definitions" on a
+ routine basis, it probably works something like this*. With any luck, it
+ does it without being a total detriment to system performance. Ideally
+ it also doesn't act like a piece of malware itself by making itself near
+ impossible to remove (looking at you, McAfee).
+</p>
+
+<p>
+ To me, a virus definition database is "enumerating badness" (Ranum's
+ Dumb Idea #2). The premise is that it is not only logical but even
+ possible to compile a list of <em>all</em> potentially unwanted
+ programs, viruses, ransomware, and worms. An environment of trust should
+ be built around the programs that you want to run (read:
+ <em>allow to run</em>), not the other way around. Picture an operating
+ system where no binary file can be executed unless it is specifically
+ flagged as being allowed to. Oh and picture also being able to restrict
+ this execution to just the file's owner, or other groups of users.
+ Wouldn't it be easier to store the list of 30 odd programs that you and
+ other system users trust to be run than the thousands (millions?) of
+ programs that are infectious, forbidden, or unwanted? What about when
+ those trusted applications become compromised? Would it not also be
+ easier to maintain a list of checksums for those binaries and compare
+ those checksums before they're executed to make sure they haven't been
+ infected or replaced?
+</p>
+
+<p>
+ The answer is yes, it would be easier. And yes, it is easier. Of course,
+ your system has to work that way. Antivirus software is a hack because
+ it's a hack-y solution to a problem that has a better, simpler solution.
+ It also has the potential for making a ton of money but I won't go into
+ that. It's easier to enumerate goodness, to specifically open up to a
+ select few trustworthy applications. Good lists are usually shorter than
+ bad lists. This builds on top of Ranum's Dumb Idea #1: Default Permit.
+ You wouldn't configure a firewall to just block some known bad ports and
+ traffic. You configure it to block all of it, and then whitelist the
+ ones you know you can trust. You wouldn't configure a browser ad-blocker
+ to permit all ads, and select the ones you don't want to see. You block
+ all of them! Then, if there are sites or ads you're okay with seeing,
+ you whitelist them. You shouldn't default permit all programs to be
+ given control over your computer, and then meticulously list the ones
+ that don't have that permission.
+</p>
+
+<p>
+ Oh and of course, as always, there's free software that lets you do
+ this. You don't have to pay for an antivirus suite, or even use an
+ unpaid one that slows down your computer or barrages you with ads. On
+ the BSDs and virtually all Linux distributions, there are built-in tools
+ to control access and execution of binaries. There are additional tools
+ that you can install that check whether binaries (in locations like
+ <code>/bin</code> or <code>/usr/local/bin</code> have been modified
+ since you last used them. On Windows, the story is a little different.
+ Most home Windows 10 users are automatically allowed to install and run
+ any software they want to by default. Windows Server does have Software
+ Restriction Policies that allow you to create a "default deny" policy
+ and whitelist only the software that's allowed to run. If you're using a
+ home edition you probably have to look for software that lets you do
+ this. I haven't tried any of them so I'm not going to endorse or even
+ name them here.
+</p>
+
+<p>
+ Preventing malware from running on your system is a problem. Solving
+ this problem is the right thing to do. But please, try to solve it the
+ right way. I stopped using an antivirus after I moved out and got to
+ control my own computer. I don't think it ever did me any good besides
+ flag false positives (a lot of the time with programs or applications
+ that I wrote, which weren't malicious in any way!) and grind my spinning
+ disk to a halt. Evaluate what software you use. Is most of it online?
+ Are there one or two applications that you know you need to use? How
+ often do you install and use unknown or untrusted software? Odds are you
+ can come up with a list of very few programs that you want or need to
+ use. If it's less than 100,000, you're probably better off with a
+ default deny policy than an antivirus suite.
+</p>
+
+<p>
+ * What I didn't mention here is that as soon as a new piece of malware
+ is constructed, if it's different enough from its predecessors, it's
+ impervious to all antivirus suites on the planet that don't have it in
+ their definitions. So until that malware is used, detected, and added to
+ the list, it has free reign.
+</p>
diff --git a/posts/2021-01-15-adam-s-2020-reading-list.html b/posts/2021-01-15-adam-s-2020-reading-list.html
deleted file mode 100644
index 46f0fba..0000000
--- a/posts/2021-01-15-adam-s-2020-reading-list.html
+++ /dev/null
@@ -1,196 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta
- property="og:image"
- content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview"
- />
- <meta property="og:site_name" content="53hor.net" />
- <meta property="og:title" content="Adam's 2020 Reading List" />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>53hornet ➙ Adam's 2020 Reading List</title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <article>
- <h1>Adam's <del>2020</del> <ins>Quarantine</ins> Reading List</h1>
-
- <ul>
- <li>
- Hammett, Dashiell. <em>The Maltese Falcon</em>
- <p>
- Excellent noir detective novel. Stolen treasure, murder, dames, all
- the good stuff.
- </p>
- </li>
- <li>
- Chandler, Raymond. <em>The Big Sleep</em>
- <p>
- More good noir detective work. Cool cars, alcohol, mansions, hit
- men, also dames. Yet more good stuff.
- </p>
- </li>
- <li>
- Lowry, Lois. <em>The Giver</em>
- <p>
- Second time I got to read this. Fantastic book just the same as
- before. Movie was totally carried by the fact that Jeff Bridges is
- the Giver. Super thought-provoking too.
- </p>
- </li>
- <li>
- Rowling, J.K.
- <em
- >Harry Potter and the Sorcerer's Stone, Harry Potter and the Chamber
- of Secrets, Harry Potter and the Prisoner of Azkaban, Harry Potter
- and the Goblet of Fire, Harry Potter and the Order of the Phoenix,
- Harry Potter and the Half-Blood Prince, Harry Potter and the Deathly
- Hallows</em
- >
- <p>
- Yep, all of them. I've read some of them multiple times but this was
- the first time I read them all to completion myself. My dad used to
- read them to me, so I only "listened" to the last couple. Always
- great, always better than the movies. And I pick up more and more
- forward- and backward-looking references when I read them in a row.
- </p>
- </li>
- <li>
- Miller, Rand, Miller, Robyn, Miller, David.
- <em>Myst: The Book of Atrus, Myst: The Book of Ti'ana</em>
- <p>
- The great first two books in the Myst novel series. My favorite is
- the second, it gives all of the meat-and-potatoes lore behind the
- D'ni, The Art, and The Fall that I always wanted. The first is good
- too, and I recommend book-and-game nerds read
- <em>Myst: The Book of Atrus</em> after playing Myst: Masterpiece
- Edition and before playing Riven: The Sequel to Myst.
- </p>
- </li>
- <li>
- Miller, Rand. <em>Myst: The Book of D'ni</em>
- <p>
- Probably my least favorite of the three Myst novels. It's
- fascinating and has lots of dark themes like enslavement. I
- recommend reading this one after Riven and before Myst III: Exile.
- </p>
- </li>
- <li>
- Paulsen, Gary. <em>Hatchet</em>
- <p>
- The last time I read this was probably in the sixth grade, and it
- was one of the few books I was really glued to then. It's still a
- great story about survival, nature, getting mauled by moose, etc.
- </p>
- </li>
- <li>
- Grisham, John. <em>Theodore Boone: Kid Lawyer</em>
- <p>
- Also a re-read for me. I kind of sort of wanted to be a lawyer
- growing up and this book was the "I can do it too!" book. It's still
- a good crime, evidence, trial style lawyer book. I need to read the
- sequels.
- </p>
- </li>
- <li>
- Wells, H.G.
- <em>The Time Machine, The Island of Dr. Moreau, The Invisible Man</em>
- <p>
- These are three of my favorite H.G. Wells novels.
- <em>The Time Machine</em> is super weird though and now that I'm
- re-reading it I'm picking up on a ton of Communist undertones.
- <em>Dr. Moreau</em> is fantastic. I love all books that take place
- on a desert island and this one really creeps me out with the
- doctor's surgically-humanized animals. <em>Invisible Man</em> is so
- short it's worth reading on a weekend just to know what it's about
- (spoiler: a man who is invisible).
- </p>
- </li>
- <li>
- Stevenson, Robert Louis. <em>Treasure Island</em>
- <p>
- Dude, I watched Treasure Planet when I was a kid and I was really
- into it for like a month. Now I finally got to read the real thing
- and there's a reason why this is one of those perfect examples of
- literature. It's the
- <em>absolute perfect, truly American story</em>
- about pirates, treasure, and sailing ships.
- </p>
- </li>
- <li>
- Dick, Harold G.
- <em
- >The Golden Age of the Great Passenger Airships: Graf Zeppelin and
- Hindenburg</em
- >
- <p>
- I'm a huge rigid airship junkie. They're freaking awesome, I wish
- they were still around. I hate flying, and not because of the act of
- being in the air but because airships make it seem more comfortable,
- luxurious, and adventurous than a half a bag of peanuts, motion
- sickness, and recycled oxygen. If you're at all interested in
- Zeppelins and you can only read one book, this is the
- <em>only</em> book worth reading. It chronicles the author's
- experiences actually flying on and operating Graf Zeppelin and
- Hindenburg, their flight logs, how they worked, how they were flown,
- and the history behind their creation and demise. It's awesome.
- </p>
- </li>
- <li>
- Brown, Dan. <em>Digital Fortress</em>
- <p>
- Great story, I actually listened to this audiobook while painting
- our house right around the start of 2020. It's an awesome story with
- an intelligent, sleuthy programmer and her globe-trotting professor
- significant other tracking down clues. It's got supercomputers and
- hackers and espionage and murder and viruses and it would be perfect
- if I knew nothing about cryptography or computing in general.
- </p>
- </li>
- </ul>
- </article>
- </body>
-</html>
diff --git a/posts/2021-01-15-adam-s-2020-reading-list.php b/posts/2021-01-15-adam-s-2020-reading-list.php
new file mode 100644
index 0000000..facfb32
--- /dev/null
+++ b/posts/2021-01-15-adam-s-2020-reading-list.php
@@ -0,0 +1,137 @@
+<?php
+$title = "Adam's <del>2020</del> <ins>Quarantine</ins> Reading List";
+if (isset($early) && $early) {
+ return;
+}
+include($_SERVER['DOCUMENT_ROOT'] . '/includes/head.php');
+?>
+
+<ul>
+ <li>
+ Hammett, Dashiell. <em>The Maltese Falcon</em>
+ <p>
+ Excellent noir detective novel. Stolen treasure, murder, dames, all
+ the good stuff.
+ </p>
+ </li>
+ <li>
+ Chandler, Raymond. <em>The Big Sleep</em>
+ <p>
+ More good noir detective work. Cool cars, alcohol, mansions, hit
+ men, also dames. Yet more good stuff.
+ </p>
+ </li>
+ <li>
+ Lowry, Lois. <em>The Giver</em>
+ <p>
+ Second time I got to read this. Fantastic book just the same as
+ before. Movie was totally carried by the fact that Jeff Bridges is
+ the Giver. Super thought-provoking too.
+ </p>
+ </li>
+ <li>
+ Rowling, J.K.
+ <em>Harry Potter and the Sorcerer's Stone, Harry Potter and the Chamber
+ of Secrets, Harry Potter and the Prisoner of Azkaban, Harry Potter
+ and the Goblet of Fire, Harry Potter and the Order of the Phoenix,
+ Harry Potter and the Half-Blood Prince, Harry Potter and the Deathly
+ Hallows</em>
+ <p>
+ Yep, all of them. I've read some of them multiple times but this was
+ the first time I read them all to completion myself. My dad used to
+ read them to me, so I only "listened" to the last couple. Always
+ great, always better than the movies. And I pick up more and more
+ forward- and backward-looking references when I read them in a row.
+ </p>
+ </li>
+ <li>
+ Miller, Rand, Miller, Robyn, Miller, David.
+ <em>Myst: The Book of Atrus, Myst: The Book of Ti'ana</em>
+ <p>
+ The great first two books in the Myst novel series. My favorite is
+ the second, it gives all of the meat-and-potatoes lore behind the
+ D'ni, The Art, and The Fall that I always wanted. The first is good
+ too, and I recommend book-and-game nerds read
+ <em>Myst: The Book of Atrus</em> after playing Myst: Masterpiece
+ Edition and before playing Riven: The Sequel to Myst.
+ </p>
+ </li>
+ <li>
+ Miller, Rand. <em>Myst: The Book of D'ni</em>
+ <p>
+ Probably my least favorite of the three Myst novels. It's
+ fascinating and has lots of dark themes like enslavement. I
+ recommend reading this one after Riven and before Myst III: Exile.
+ </p>
+ </li>
+ <li>
+ Paulsen, Gary. <em>Hatchet</em>
+ <p>
+ The last time I read this was probably in the sixth grade, and it
+ was one of the few books I was really glued to then. It's still a
+ great story about survival, nature, getting mauled by moose, etc.
+ </p>
+ </li>
+ <li>
+ Grisham, John. <em>Theodore Boone: Kid Lawyer</em>
+ <p>
+ Also a re-read for me. I kind of sort of wanted to be a lawyer
+ growing up and this book was the "I can do it too!" book. It's still
+ a good crime, evidence, trial style lawyer book. I need to read the
+ sequels.
+ </p>
+ </li>
+ <li>
+ Wells, H.G.
+ <em>The Time Machine, The Island of Dr. Moreau, The Invisible Man</em>
+ <p>
+ These are three of my favorite H.G. Wells novels.
+ <em>The Time Machine</em> is super weird though and now that I'm
+ re-reading it I'm picking up on a ton of Communist undertones.
+ <em>Dr. Moreau</em> is fantastic. I love all books that take place
+ on a desert island and this one really creeps me out with the
+ doctor's surgically-humanized animals. <em>Invisible Man</em> is so
+ short it's worth reading on a weekend just to know what it's about
+ (spoiler: a man who is invisible).
+ </p>
+ </li>
+ <li>
+ Stevenson, Robert Louis. <em>Treasure Island</em>
+ <p>
+ Dude, I watched Treasure Planet when I was a kid and I was really
+ into it for like a month. Now I finally got to read the real thing
+ and there's a reason why this is one of those perfect examples of
+ literature. It's the
+ <em>absolute perfect, truly American story</em>
+ about pirates, treasure, and sailing ships.
+ </p>
+ </li>
+ <li>
+ Dick, Harold G.
+ <em>The Golden Age of the Great Passenger Airships: Graf Zeppelin and
+ Hindenburg</em>
+ <p>
+ I'm a huge rigid airship junkie. They're freaking awesome, I wish
+ they were still around. I hate flying, and not because of the act of
+ being in the air but because airships make it seem more comfortable,
+ luxurious, and adventurous than a half a bag of peanuts, motion
+ sickness, and recycled oxygen. If you're at all interested in
+ Zeppelins and you can only read one book, this is the
+ <em>only</em> book worth reading. It chronicles the author's
+ experiences actually flying on and operating Graf Zeppelin and
+ Hindenburg, their flight logs, how they worked, how they were flown,
+ and the history behind their creation and demise. It's awesome.
+ </p>
+ </li>
+ <li>
+ Brown, Dan. <em>Digital Fortress</em>
+ <p>
+ Great story, I actually listened to this audiobook while painting
+ our house right around the start of 2020. It's an awesome story with
+ an intelligent, sleuthy programmer and her globe-trotting professor
+ significant other tracking down clues. It's got supercomputers and
+ hackers and espionage and murder and viruses and it would be perfect
+ if I knew nothing about cryptography or computing in general.
+ </p>
+ </li>
+</ul>
diff --git a/posts/2021-01-15-root-on-zfs-a-zpool-of-mirror-vdevs-the-easy-way.html b/posts/2021-01-15-root-on-zfs-a-zpool-of-mirror-vdevs-the-easy-way.html
deleted file mode 100644
index 01d25c8..0000000
--- a/posts/2021-01-15-root-on-zfs-a-zpool-of-mirror-vdevs-the-easy-way.html
+++ /dev/null
@@ -1,375 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta
- property="og:image"
- content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview"
- />
- <meta property="og:site_name" content="53hor.net" />
- <meta
- property="og:title"
- content="Root on ZFS: A ZPool of Mirror VDEVs The Easy Way"
- />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>53hornet ➙ Root on ZFS: A ZPool of Mirror VDEVs The Easy Way</title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <article>
- <h1>Root on ZFS: A ZPool of Mirror VDEVs</h1>
-
- <p class="description">
- I wanted/needed to make a root on ZFS pool out of multiple mirror VDEVs,
- and since I'm not a ZFS expert, I took a little shortcut.
- </p>
-
- <p>
- I recently got a new-to-me server (yay!) and I wanted to do a
- root-on-ZFS setup on it. I've really enjoyed using ZFS for my data
- storage pools for a long time. I've also enjoyed the extra functionality
- that comes with having a bootable system installed on ZFS on my laptop
- and decided with this upgrade it's time to do the same on my server.
- Historically I've used RAIDZ for my storage pools. RAIDZ functions
- almost like a RAID10 but at the ZFS level. It gives you parity so that a
- certain number of disks can die from your pool and you won't lose any
- data. It does have a few tradeoffs however*, and for personal
- preferences I've decided that for the future I would like to have a
- single ZPool over top of multiple mirror VDEVs. In other words, my main
- root+storage pool will be made up of two-disk mirrors and can be
- expanded to include any number of new mirrors I can fit into the
- machine.
- </p>
-
- <p>
- This did present some complications. First of all,
- <code>bsdinstall</code> won't set this up for you automatically (and
- sure enough,
- <a
- href="https://www.freebsd.org/doc/handbook/bsdinstall-partitioning.html"
- >in the handbook</a
- >
- it mentions the guided root on ZFS tool will only create a single,
- top-level VDEV unless it's a stripe). It will happily let you use RAIDZ
- for your ZROOT but not the more custom approach I'm taking. I did
- however use
- <code>bsdinstall</code> as a shortcut so I wouldn't have to do all of
- the partitioning and pool setup manually, and that's what I'm going to
- document below. Because I'm totally going to forget how this works the
- next time I have to do it.
- </p>
-
- <p>
- In my scenario I have an eight-slot, hot-swappable PERC H310 controller
- that's configured for AHCI passthrough. In other words, all FreeBSD sees
- is as many disks as I have plugged into the backplane. I'm going to fill
- it with 6x2TB hard disks which, as I said before, I want to act as three
- mirrors (two disks each) in a single, bootable, growable ZPool. For
- starters, I shoved the FreeBSD installer on a flash drive and booted
- from it. I followed all of the regular steps (setting hostname, getting
- online, etc.) until I got to the guided root on ZFS disk partitioning
- setup.
- </p>
-
- <p>
- Now here's where I'm going to take the first step on my shortcut. Since
- there is no option to create the pool of arbitrary mirrors I'm just
- going to create a pool from a single mirror VDEV of two disks. Later I
- will expand the pool to include the other two mirrors I had intended
- for. My selections were as follows:
- </p>
-
- <ul>
- <li>Pool Type/Disks: mirror mfisyspd0 mfisyspd1</li>
- <li>Pool Name: zroot</li>
- <li>Partition Scheme: GPT (EFI)</li>
- <li>Swap Size: 4g</li>
- </ul>
-
- <p>
- Everything else was left as a default. Then I followed the installer to
- completion. At the end, when it asked if I wanted to drop into a shell
- to do more to the installation, I did.
- </p>
-
- <p>
- The installer created the following disk layout for the two disks that I
- selected.
- </p>
-
- <pre>
-<code>
-atc@macon:~ % gpart show
-=> 40 3907029088 mfisyspd0 GPT (1.8T)
- 40 409600 1 efi (200M)
- 409640 2008 - free - (1.0M)
- 411648 8388608 2 freebsd-swap (4.0G)
- 8800256 3898228736 3 freebsd-zfs (1.8T)
- 3907028992 136 - free - (68K)
-
-=> 40 3907029088 mfisyspd1 GPT (1.8T)
- 40 409600 1 efi (200M)
- 409640 2008 - free - (1.0M)
- 411648 8388608 2 freebsd-swap (4.0G)
- 8800256 3898228736 3 freebsd-zfs (1.8T)
- 3907028992 136 - free - (68K)
-</code>
-</pre>
-
- <p>
- The installer also created the following ZPool from my single mirror
- VDEV.
- </p>
-
- <pre>
-<code>
-atc@macon:~ % zpool status
- pool: zroot
- state: ONLINE
- scan: none requested
-config:
-
- NAME STATE READ WRITE CKSUM
- zroot ONLINE 0 0 0
- mirror-0 ONLINE 0 0 0
- mfisyspd0p3 ONLINE 0 0 0
- mfisyspd1p3 ONLINE 0 0 0
-
-errors: No known data errors
-</code>
-</pre>
-
- <p>
- There are a couple of things to take note of here. First of all,
- <em>both</em> disks in the bootable ZPool have an EFI boot partition.
- That means they're both a part of (or capable of?) booting the pool.
- Second, they both have some swap space. Finally, they both have a third
- partition which is dedicated to ZFS data, and that partition is what got
- added to my VDEV.
- </p>
-
- <p>
- So where do I go from here? I was tempted to just
- <code>zpool add mirror ... ...</code> and just add my other disks to the
- pool (actually, I <em>did</em> do this but it rendered the volume
- unbootable for a very important reason), but then I wouldn't have those
- all-important boot partitions (using whole-disk mirror VDEVS). Instead,
- I need to manually go back and re-partition four disks exactly like the
- first two. Or, since all I want is two more of what's already been done,
- I can just clone the partitions using <code>gpart backup</code> and
- <code>restore</code>! Easy! Here's what I did for all four remaining
- disks:
- </p>
-
- <pre>
-<code>
-root@macon:~ # gpart backup mfisyspd0 | gpart restore -F mfisyspd2`
-</code>
-</pre>
-
- <p>
- Full disclosure, I didn't even think of this as a possibility
- <a
- href="ihttps://unix.stackexchange.com/questions/472147/replacing-disk-when-using-freebsd-zfs-zroot-zfs-on-partition#472175"
- >until I read this Stack Exchange post</a
- >. This gave me a disk layout like this:
- </p>
-
- <pre>
-<code>
-atc@macon:~ % gpart show
-=> 40 3907029088 mfisyspd0 GPT (1.8T)
- 40 409600 1 efi (200M)
- 409640 2008 - free - (1.0M)
- 411648 8388608 2 freebsd-swap (4.0G)
- 8800256 3898228736 3 freebsd-zfs (1.8T)
- 3907028992 136 - free - (68K)
-
-=> 40 3907029088 mfisyspd1 GPT (1.8T)
- 40 409600 1 efi (200M)
- 409640 2008 - free - (1.0M)
- 411648 8388608 2 freebsd-swap (4.0G)
- 8800256 3898228736 3 freebsd-zfs (1.8T)
- 3907028992 136 - free - (68K)
-
-=> 40 3907029088 mfisyspd2 GPT (1.8T)
- 40 409600 1 efi (200M)
- 409640 2008 - free - (1.0M)
- 411648 8388608 2 freebsd-swap (4.0G)
- 8800256 3898228736 3 freebsd-zfs (1.8T)
- 3907028992 136 - free - (68K)
-
-=> 40 3907029088 mfisyspd3 GPT (1.8T)
- 40 409600 1 efi (200M)
- 409640 2008 - free - (1.0M)
- 411648 8388608 2 freebsd-swap (4.0G)
- 8800256 3898228736 3 freebsd-zfs (1.8T)
- 3907028992 136 - free - (68K)
-
-=> 40 3907029088 mfisyspd4 GPT (1.8T)
- 40 409600 1 efi (200M)
- 409640 2008 - free - (1.0M)
- 411648 8388608 2 freebsd-swap (4.0G)
- 8800256 3898228736 3 freebsd-zfs (1.8T)
- 3907028992 136 - free - (68K)
-
-=> 40 3907029088 mfisyspd5 GPT (1.8T)
- 40 409600 1 efi (200M)
- 409640 2008 - free - (1.0M)
- 411648 8388608 2 freebsd-swap (4.0G)
- 8800256 3898228736 3 freebsd-zfs (1.8T)
- 3907028992 136 - free - (68K)
-</code>
-</pre>
-
- <p>
- And to be fair, this makes a lot of logical sense. You don't want a
- six-disk pool to only be bootable by two of the disks or you're
- defeating some of the purposes of redundancy. So now I can extend my
- ZPool to include those last four disks.
- </p>
-
- <p>
- This next step may or may not be a requirement. I wanted to overwrite
- where I assumed any old ZFS/ZPool metadata might be on my four new
- disks. This could just be for nothing and I admit that, but I've run
- into trouble in the past where a ZPool wasn't properly
- exported/destroyed before the drives were removed for another purpose
- and when you use those drives in future
- <code>zpool import</code>s, you can see both the new and the old, failed
- pools. And, in the previous step I cloned an old ZFS partition many
- times! So I did a small <code>dd</code> on the remaining disks to help
- me sleep at night:
- </p>
-
- <pre>
-<code>
-root@macon:~ # dd if=/dev/zero of=/dev/mfisyspd2 bs=1M count=100
-</code>
-</pre>
-
- <p>
- One final, precautionary step is to write the EFI boot loader to the new
- disks. In
- <a href="https://www.freebsd.org/doc/handbook/zfs-zpool.html"
- >zpool admin handbook</a
- >
- it mentions you should do this any time you <em>replace</em> a zroot
- device, so I'll do it just for safe measure on all four additional
- disks:
- </p>
-
- <pre>
-<code>
-root@macon:~ # gpart bootcode -p /boot/boot1.efifat -i 1 mfisyspd2
-</code>
-</pre>
-
- <p>
- Don't forget that the command is different for UEFI and a traditional
- BIOS. And finally, I can add my new VDEVs:
- </p>
-
- <pre>
-<code>
-root@macon:~ # zpool zroot add mirror mfisyspd2p3 mfisyspd3p3
-root@macon:~ # zpool zroot add mirror mfisyspd4p3 mfisyspd5p3
-</code>
-</pre>
-
- <p>And now my pool looks like this:</p>
-
- <pre>
-<code>
-atc@macon:~ % zpool status
- pool: zroot
- state: ONLINE
- scan: none requested
-config:
-
- NAME STATE READ WRITE CKSUM
- zroot ONLINE 0 0 0
- mirror-0 ONLINE 0 0 0
- mfisyspd0p3 ONLINE 0 0 0
- mfisyspd1p3 ONLINE 0 0 0
- mirror-1 ONLINE 0 0 0
- mfisyspd2p3 ONLINE 0 0 0
- mfisyspd3p3 ONLINE 0 0 0
- mirror-2 ONLINE 0 0 0
- mfisyspd4p3 ONLINE 0 0 0
- mfisyspd5p3 ONLINE 0 0 0
-
-errors: No known data errors
-</code>
-</pre>
-
- <p>
- Boom. A growable, bootable zroot ZPool. Is it easier than just
- configuring the partitions and root on ZFS by hand? Probably not for a
- BSD veteran. But since I'm a BSD layman, this is something I can live
- with pretty easily. At least until this becomes an option in
- <code>bsdintall</code> maybe? At least now I can add as many more
- mirrors as I can fit into my system. And it's just as easy to replace
- them. This is better for me than my previous RAIDZ, where I would have
- to destroy and re-create the pool in order to add more disks to the
- VDEV. Now I just create another little mirror and grow the pool and all
- of my filesystems just see more storage. And of course, having ZFS for
- all of my data makes it super easy to create filesystems on the fly,
- compress or quota them, and take snapshots (including the live ZROOT!)
- and send those snapshots over the network. Pretty awesome.
- </p>
-
- <p>
- * I'm not going to explain why here, but
- <a
- href="http://www.openoid.net/zfs-you-should-use-mirror-vdevs-not-raidz/"
- >this is a pretty well thought out article</a
- >
- that should give you an idea about the pros and cons of RAIDZ versus
- mirror VDEVs so you can draw your own conclusions.
- </p>
- </article>
- </body>
-</html>
diff --git a/posts/2021-01-15-root-on-zfs-a-zpool-of-mirror-vdevs-the-easy-way.php b/posts/2021-01-15-root-on-zfs-a-zpool-of-mirror-vdevs-the-easy-way.php
new file mode 100644
index 0000000..d67f582
--- /dev/null
+++ b/posts/2021-01-15-root-on-zfs-a-zpool-of-mirror-vdevs-the-easy-way.php
@@ -0,0 +1,306 @@
+<?php
+$title = "Root on ZFS: A ZPool of Mirror VDEVs";
+if (isset($early) && $early) {
+ return;
+}
+include($_SERVER['DOCUMENT_ROOT'] . '/includes/head.php');
+?>
+
+<p class="description">
+ I wanted/needed to make a root on ZFS pool out of multiple mirror VDEVs,
+ and since I'm not a ZFS expert, I took a little shortcut.
+</p>
+
+<p>
+ I recently got a new-to-me server (yay!) and I wanted to do a
+ root-on-ZFS setup on it. I've really enjoyed using ZFS for my data
+ storage pools for a long time. I've also enjoyed the extra functionality
+ that comes with having a bootable system installed on ZFS on my laptop
+ and decided with this upgrade it's time to do the same on my server.
+ Historically I've used RAIDZ for my storage pools. RAIDZ functions
+ almost like a RAID10 but at the ZFS level. It gives you parity so that a
+ certain number of disks can die from your pool and you won't lose any
+ data. It does have a few tradeoffs however*, and for personal
+ preferences I've decided that for the future I would like to have a
+ single ZPool over top of multiple mirror VDEVs. In other words, my main
+ root+storage pool will be made up of two-disk mirrors and can be
+ expanded to include any number of new mirrors I can fit into the
+ machine.
+</p>
+
+<p>
+ This did present some complications. First of all,
+ <code>bsdinstall</code> won't set this up for you automatically (and
+ sure enough,
+ <a href="https://www.freebsd.org/doc/handbook/bsdinstall-partitioning.html">in the handbook</a>
+ it mentions the guided root on ZFS tool will only create a single,
+ top-level VDEV unless it's a stripe). It will happily let you use RAIDZ
+ for your ZROOT but not the more custom approach I'm taking. I did
+ however use
+ <code>bsdinstall</code> as a shortcut so I wouldn't have to do all of
+ the partitioning and pool setup manually, and that's what I'm going to
+ document below. Because I'm totally going to forget how this works the
+ next time I have to do it.
+</p>
+
+<p>
+ In my scenario I have an eight-slot, hot-swappable PERC H310 controller
+ that's configured for AHCI passthrough. In other words, all FreeBSD sees
+ is as many disks as I have plugged into the backplane. I'm going to fill
+ it with 6x2TB hard disks which, as I said before, I want to act as three
+ mirrors (two disks each) in a single, bootable, growable ZPool. For
+ starters, I shoved the FreeBSD installer on a flash drive and booted
+ from it. I followed all of the regular steps (setting hostname, getting
+ online, etc.) until I got to the guided root on ZFS disk partitioning
+ setup.
+</p>
+
+<p>
+ Now here's where I'm going to take the first step on my shortcut. Since
+ there is no option to create the pool of arbitrary mirrors I'm just
+ going to create a pool from a single mirror VDEV of two disks. Later I
+ will expand the pool to include the other two mirrors I had intended
+ for. My selections were as follows:
+</p>
+
+<ul>
+ <li>Pool Type/Disks: mirror mfisyspd0 mfisyspd1</li>
+ <li>Pool Name: zroot</li>
+ <li>Partition Scheme: GPT (EFI)</li>
+ <li>Swap Size: 4g</li>
+</ul>
+
+<p>
+ Everything else was left as a default. Then I followed the installer to
+ completion. At the end, when it asked if I wanted to drop into a shell
+ to do more to the installation, I did.
+</p>
+
+<p>
+ The installer created the following disk layout for the two disks that I
+ selected.
+</p>
+
+<pre>
+<code>
+atc@macon:~ % gpart show
+=> 40 3907029088 mfisyspd0 GPT (1.8T)
+ 40 409600 1 efi (200M)
+ 409640 2008 - free - (1.0M)
+ 411648 8388608 2 freebsd-swap (4.0G)
+ 8800256 3898228736 3 freebsd-zfs (1.8T)
+ 3907028992 136 - free - (68K)
+
+=> 40 3907029088 mfisyspd1 GPT (1.8T)
+ 40 409600 1 efi (200M)
+ 409640 2008 - free - (1.0M)
+ 411648 8388608 2 freebsd-swap (4.0G)
+ 8800256 3898228736 3 freebsd-zfs (1.8T)
+ 3907028992 136 - free - (68K)
+</code>
+</pre>
+
+<p>
+ The installer also created the following ZPool from my single mirror
+ VDEV.
+</p>
+
+<pre>
+<code>
+atc@macon:~ % zpool status
+ pool: zroot
+ state: ONLINE
+ scan: none requested
+config:
+
+ NAME STATE READ WRITE CKSUM
+ zroot ONLINE 0 0 0
+ mirror-0 ONLINE 0 0 0
+ mfisyspd0p3 ONLINE 0 0 0
+ mfisyspd1p3 ONLINE 0 0 0
+
+errors: No known data errors
+</code>
+</pre>
+
+<p>
+ There are a couple of things to take note of here. First of all,
+ <em>both</em> disks in the bootable ZPool have an EFI boot partition.
+ That means they're both a part of (or capable of?) booting the pool.
+ Second, they both have some swap space. Finally, they both have a third
+ partition which is dedicated to ZFS data, and that partition is what got
+ added to my VDEV.
+</p>
+
+<p>
+ So where do I go from here? I was tempted to just
+ <code>zpool add mirror ... ...</code> and just add my other disks to the
+ pool (actually, I <em>did</em> do this but it rendered the volume
+ unbootable for a very important reason), but then I wouldn't have those
+ all-important boot partitions (using whole-disk mirror VDEVS). Instead,
+ I need to manually go back and re-partition four disks exactly like the
+ first two. Or, since all I want is two more of what's already been done,
+ I can just clone the partitions using <code>gpart backup</code> and
+ <code>restore</code>! Easy! Here's what I did for all four remaining
+ disks:
+</p>
+
+<pre>
+<code>
+root@macon:~ # gpart backup mfisyspd0 | gpart restore -F mfisyspd2`
+</code>
+</pre>
+
+<p>
+ Full disclosure, I didn't even think of this as a possibility
+ <a href="ihttps://unix.stackexchange.com/questions/472147/replacing-disk-when-using-freebsd-zfs-zroot-zfs-on-partition#472175">until I read this Stack Exchange post</a>. This gave me a disk layout like this:
+</p>
+
+<pre>
+<code>
+atc@macon:~ % gpart show
+=> 40 3907029088 mfisyspd0 GPT (1.8T)
+ 40 409600 1 efi (200M)
+ 409640 2008 - free - (1.0M)
+ 411648 8388608 2 freebsd-swap (4.0G)
+ 8800256 3898228736 3 freebsd-zfs (1.8T)
+ 3907028992 136 - free - (68K)
+
+=> 40 3907029088 mfisyspd1 GPT (1.8T)
+ 40 409600 1 efi (200M)
+ 409640 2008 - free - (1.0M)
+ 411648 8388608 2 freebsd-swap (4.0G)
+ 8800256 3898228736 3 freebsd-zfs (1.8T)
+ 3907028992 136 - free - (68K)
+
+=> 40 3907029088 mfisyspd2 GPT (1.8T)
+ 40 409600 1 efi (200M)
+ 409640 2008 - free - (1.0M)
+ 411648 8388608 2 freebsd-swap (4.0G)
+ 8800256 3898228736 3 freebsd-zfs (1.8T)
+ 3907028992 136 - free - (68K)
+
+=> 40 3907029088 mfisyspd3 GPT (1.8T)
+ 40 409600 1 efi (200M)
+ 409640 2008 - free - (1.0M)
+ 411648 8388608 2 freebsd-swap (4.0G)
+ 8800256 3898228736 3 freebsd-zfs (1.8T)
+ 3907028992 136 - free - (68K)
+
+=> 40 3907029088 mfisyspd4 GPT (1.8T)
+ 40 409600 1 efi (200M)
+ 409640 2008 - free - (1.0M)
+ 411648 8388608 2 freebsd-swap (4.0G)
+ 8800256 3898228736 3 freebsd-zfs (1.8T)
+ 3907028992 136 - free - (68K)
+
+=> 40 3907029088 mfisyspd5 GPT (1.8T)
+ 40 409600 1 efi (200M)
+ 409640 2008 - free - (1.0M)
+ 411648 8388608 2 freebsd-swap (4.0G)
+ 8800256 3898228736 3 freebsd-zfs (1.8T)
+ 3907028992 136 - free - (68K)
+</code>
+</pre>
+
+<p>
+ And to be fair, this makes a lot of logical sense. You don't want a
+ six-disk pool to only be bootable by two of the disks or you're
+ defeating some of the purposes of redundancy. So now I can extend my
+ ZPool to include those last four disks.
+</p>
+
+<p>
+ This next step may or may not be a requirement. I wanted to overwrite
+ where I assumed any old ZFS/ZPool metadata might be on my four new
+ disks. This could just be for nothing and I admit that, but I've run
+ into trouble in the past where a ZPool wasn't properly
+ exported/destroyed before the drives were removed for another purpose
+ and when you use those drives in future
+ <code>zpool import</code>s, you can see both the new and the old, failed
+ pools. And, in the previous step I cloned an old ZFS partition many
+ times! So I did a small <code>dd</code> on the remaining disks to help
+ me sleep at night:
+</p>
+
+<pre>
+<code>
+root@macon:~ # dd if=/dev/zero of=/dev/mfisyspd2 bs=1M count=100
+</code>
+</pre>
+
+<p>
+ One final, precautionary step is to write the EFI boot loader to the new
+ disks. In
+ <a href="https://www.freebsd.org/doc/handbook/zfs-zpool.html">zpool admin handbook</a>
+ it mentions you should do this any time you <em>replace</em> a zroot
+ device, so I'll do it just for safe measure on all four additional
+ disks:
+</p>
+
+<pre>
+<code>
+root@macon:~ # gpart bootcode -p /boot/boot1.efifat -i 1 mfisyspd2
+</code>
+</pre>
+
+<p>
+ Don't forget that the command is different for UEFI and a traditional
+ BIOS. And finally, I can add my new VDEVs:
+</p>
+
+<pre>
+<code>
+root@macon:~ # zpool zroot add mirror mfisyspd2p3 mfisyspd3p3
+root@macon:~ # zpool zroot add mirror mfisyspd4p3 mfisyspd5p3
+</code>
+</pre>
+
+<p>And now my pool looks like this:</p>
+
+<pre>
+<code>
+atc@macon:~ % zpool status
+ pool: zroot
+ state: ONLINE
+ scan: none requested
+config:
+
+ NAME STATE READ WRITE CKSUM
+ zroot ONLINE 0 0 0
+ mirror-0 ONLINE 0 0 0
+ mfisyspd0p3 ONLINE 0 0 0
+ mfisyspd1p3 ONLINE 0 0 0
+ mirror-1 ONLINE 0 0 0
+ mfisyspd2p3 ONLINE 0 0 0
+ mfisyspd3p3 ONLINE 0 0 0
+ mirror-2 ONLINE 0 0 0
+ mfisyspd4p3 ONLINE 0 0 0
+ mfisyspd5p3 ONLINE 0 0 0
+
+errors: No known data errors
+</code>
+</pre>
+
+<p>
+ Boom. A growable, bootable zroot ZPool. Is it easier than just
+ configuring the partitions and root on ZFS by hand? Probably not for a
+ BSD veteran. But since I'm a BSD layman, this is something I can live
+ with pretty easily. At least until this becomes an option in
+ <code>bsdintall</code> maybe? At least now I can add as many more
+ mirrors as I can fit into my system. And it's just as easy to replace
+ them. This is better for me than my previous RAIDZ, where I would have
+ to destroy and re-create the pool in order to add more disks to the
+ VDEV. Now I just create another little mirror and grow the pool and all
+ of my filesystems just see more storage. And of course, having ZFS for
+ all of my data makes it super easy to create filesystems on the fly,
+ compress or quota them, and take snapshots (including the live ZROOT!)
+ and send those snapshots over the network. Pretty awesome.
+</p>
+
+<p>
+ * I'm not going to explain why here, but
+ <a href="http://www.openoid.net/zfs-you-should-use-mirror-vdevs-not-raidz/">this is a pretty well thought out article</a>
+ that should give you an idea about the pros and cons of RAIDZ versus
+ mirror VDEVs so you can draw your own conclusions.
+</p>
diff --git a/posts/2021-01-28-undefined-javasript-is-undefined.html b/posts/2021-01-28-undefined-javasript-is-undefined.html
deleted file mode 100644
index 219b379..0000000
--- a/posts/2021-01-28-undefined-javasript-is-undefined.html
+++ /dev/null
@@ -1,163 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta
- property="og:image"
- content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview"
- />
- <meta property="og:site_name" content="53hor.net" />
- <meta property="og:title" content="Undefined? JavaSript Is Undefined." />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>53hornet ➙ Undefined? JavaSript Is Undefined.</title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <article>
- <h1>Undefined? JavaSript Is Undefined.</h1>
-
- <p class="description">
- So I've been working on a web app for my mom. Nothing too fancy, but
- it's a store front for her glass art. It's an easy way for her to keep
- track of inventory, update photos of her products, and for people to
- shop and search and sort and browse through it. This backend is an HTTP
- service written in Rust. The frontend is a Vue.js app. I've used Vue and
- JavaScript many times before but I recently ran into an incredibly
- strange bug. One that I would have hoped JavaScript would have some
- guard against. But JavaScript is an undefined language.
- </p>
-
- <p>
- I have a small component that uses a file input to collect an image from
- the user. Then I append that file to a FormData and set that FormData as
- a Fetch API request body. So I've got fetch API sending
- multipart/form-data across the network to my backend. Awesome! The
- backend is supposed to take each field of the request, turn the chunks
- into a single stream of binary data, and write them out to an image.
- Everything on the front seems like it's working great, it fires off the
- request and throws no errors. But then the backend only sees a few bytes
- of this multi-megabyte image. Not awesome! short chunks on the back-end.
- The array of data in the API is less than ten bytes long, when this is a
- many-kilobyte file I'm trying to upload.
- </p>
-
- <p>
- At this point I'm relentlessly debugging, trying to find out what's
- wrong with the API. Why is it truncating the request down to a few
- bytes, where's the rest of the data? It took me forever to actually
- inspect what those few bytes are and, lo and behold they're ASCII for
- <code>undefined</code> The request happily stringified an
- <code>undefined</code> object, instead of maybe throwing a null
- reference or undefined error during request creation because that's just
- what JavaScript does. <em>The linter didn't even catch it.</em>
- </p>
-
- <p>
- You can see what the debugging logs looked like on the backend below.
- Note that the <code>&data</code> is the field that spells out
- "undefined". Also note that the file picker/FormData was constructed
- alright because the key for the image name is correct.
- </p>
-
- <pre>
- <code>
-[src/handlers.rs:114] &field =
-Field: application/octet-stream
- boundary: ---------------------------175314640631070190963311652907
- headers:
- "content-disposition": "form-data; name=\"clu.jpg\""
-
-[src/handlers.rs:119] &chunk = Ok(
- b"undefined",
-)
-[src/handlers.rs:123] &data = [
- 117,
- 110,
- 100,
- 101,
- 102,
- 105,
- 110,
- 101,
- 100,
-]
-ImageWrite("The image format could not be determined")
- </code>
- </pre>
-
- <p>
- The <em>working</em> JS is here (it was late at night and I was so
- donion rings I just fixed it and pushed it without saving the errors for
- posterity):
- </p>
-
- <pre>
- <code>
-let file = event.target.files[0];
-if (!file) {
- return;
-}
-
-const fd = new FormData();
-fd.append(file.name, file);
-
-const response = await fetch("http://localhost:8000/photos", {
- method: "POST",
- body: fd
-});
-
-console.log(response);
- </code>
- </pre>
- <p>
- I've gotten frustrated by JS before but not like this. I don't know if
- TypeScript would have solved this issue but writing in a language that
- gets transpiled back into the language I'm trying to avoid doesn't seem
- like the way forward. I'm looking forward to Web Assembly as a way of
- using more type-safe languages in the browser.
- </p>
- </article>
- </body>
-</html>
diff --git a/posts/2021-01-28-undefined-javasript-is-undefined.php b/posts/2021-01-28-undefined-javasript-is-undefined.php
new file mode 100644
index 0000000..b70141c
--- /dev/null
+++ b/posts/2021-01-28-undefined-javasript-is-undefined.php
@@ -0,0 +1,108 @@
+<?php
+$title = "Undefined? JavaScript Is Undefined.";
+if (isset($early) && $early) {
+ return;
+}
+include($_SERVER['DOCUMENT_ROOT'] . '/includes/head.php');
+?>
+
+<p class="description">
+ So I've been working on a web app for my mom. Nothing too fancy, but
+ it's a store front for her glass art. It's an easy way for her to keep
+ track of inventory, update photos of her products, and for people to
+ shop and search and sort and browse through it. This backend is an HTTP
+ service written in Rust. The frontend is a Vue.js app. I've used Vue and
+ JavaScript many times before but I recently ran into an incredibly
+ strange bug. One that I would have hoped JavaScript would have some
+ guard against. But JavaScript is an undefined language.
+</p>
+
+<p>
+ I have a small component that uses a file input to collect an image from
+ the user. Then I append that file to a FormData and set that FormData as
+ a Fetch API request body. So I've got fetch API sending
+ multipart/form-data across the network to my backend. Awesome! The
+ backend is supposed to take each field of the request, turn the chunks
+ into a single stream of binary data, and write them out to an image.
+ Everything on the front seems like it's working great, it fires off the
+ request and throws no errors. But then the backend only sees a few bytes
+ of this multi-megabyte image. Not awesome! short chunks on the back-end.
+ The array of data in the API is less than ten bytes long, when this is a
+ many-kilobyte file I'm trying to upload.
+</p>
+
+<p>
+ At this point I'm relentlessly debugging, trying to find out what's
+ wrong with the API. Why is it truncating the request down to a few
+ bytes, where's the rest of the data? It took me forever to actually
+ inspect what those few bytes are and, lo and behold they're ASCII for
+ <code>undefined</code> The request happily stringified an
+ <code>undefined</code> object, instead of maybe throwing a null
+ reference or undefined error during request creation because that's just
+ what JavaScript does. <em>The linter didn't even catch it.</em>
+</p>
+
+<p>
+ You can see what the debugging logs looked like on the backend below.
+ Note that the <code>&data</code> is the field that spells out
+ "undefined". Also note that the file picker/FormData was constructed
+ alright because the key for the image name is correct.
+</p>
+
+<pre>
+ <code>
+[src/handlers.rs:114] &field =
+Field: application/octet-stream
+ boundary: ---------------------------175314640631070190963311652907
+ headers:
+ "content-disposition": "form-data; name=\"clu.jpg\""
+
+[src/handlers.rs:119] &chunk = Ok(
+ b"undefined",
+)
+[src/handlers.rs:123] &data = [
+ 117,
+ 110,
+ 100,
+ 101,
+ 102,
+ 105,
+ 110,
+ 101,
+ 100,
+]
+ImageWrite("The image format could not be determined")
+ </code>
+ </pre>
+
+<p>
+ The <em>working</em> JS is here (it was late at night and I was so
+ donion rings I just fixed it and pushed it without saving the errors for
+ posterity):
+</p>
+
+<pre>
+ <code>
+let file = event.target.files[0];
+if (!file) {
+ return;
+}
+
+const fd = new FormData();
+fd.append(file.name, file);
+
+const response = await fetch("http://localhost:8000/photos", {
+ method: "POST",
+ body: fd
+});
+
+console.log(response);
+ </code>
+ </pre>
+<p>
+ I've gotten frustrated by JS before but not like this. I don't know if
+ TypeScript would have solved this issue but writing in a language that
+ gets transpiled back into the language I'm trying to avoid doesn't seem
+ like the way forward. I'm looking forward to Web Assembly as a way of
+ using more type-safe languages in the browser.
+</p>
diff --git a/posts/2021-02-12-louis-vierne-is-a-bamf-and-proof-that-organists-are-metal.html b/posts/2021-02-12-louis-vierne-is-a-bamf-and-proof-that-organists-are-metal.html
deleted file mode 100644
index 2e7a528..0000000
--- a/posts/2021-02-12-louis-vierne-is-a-bamf-and-proof-that-organists-are-metal.html
+++ /dev/null
@@ -1,129 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta
- property="og:image"
- content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview"
- />
- <meta property="og:site_name" content="53hor.net" />
- <meta
- property="og:title"
- content="Louis Vierne Is a BAMF (and Proof That Organists Are Metal)"
- />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>
- 53hornet ➙ Louis Vierne Is a BAMF (and Proof That Organists Are Metal)
- </title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <article>
- <h1>Louis Vierne Is a BAMF (and Proof That Organists Are Metal)</h1>
-
- <p>
- Louis Vierne is a certifiable badass organist from the end of the 19th
- and early 20th centuries. He was born blind and had to have surgery to
- be able to distinguish shapes and objects. Did that stop him from
- playing the one instrument that literally requires you to distinguish
- hundreds and hundreds of small objects from each other? Nope, he just
- did it (and he learned from Cesar Franck, another great organist).
- </p>
-
- <p>
- In 1906 he got hit by a car and the doctors said they might have to
- amputate his leg. Did you know you play an organ with both your hands
- <em>and</em> both your feet? Well you do, and Vierne just re-learned how
- to play with his feet after the accident. Because nobody tells Louis
- Vierne no.
- </p>
-
- <p>
- And because he's a badass, Vierne went on to become the official
- organist at the Notre Dame in Paris, a position he won by competitively
- dunking on numerous other musicians. He considered this his greatest
- achievement, and what Louis Vierne says goes.
- </p>
-
- <p>
- In one final act of badassery, he carried out his lifelong dream: to die
- while playing at Notre Dame. In 1937, to a full recital hall in Notre
- Dame, he was giving his 1,750th performance and actually
- <em
- >had a heart-attack while playing and died at the console, and keeled
- over so that the low "E" played until they removed his body</em
- >. To this day, no rock band has ever been so metal.
- </p>
-
- <hr />
-
- <p>
- Alright, so without the decoration, Louis Vierne is my favorite Organist
- and composer from the period. The organ is, in my opinion, the coolest
- instrument on the planet. It's the biggest, the loudest, and the most
- impressive. It's also got the most wide and interesting array of sounds,
- like having an orchestra at your fingertips. Vierne made some of my
- favorite music for the organ (music that my lowly organ skills will
- never let me play). He's also, obviously, pretty badass.
- </p>
-
- <p>
- In truth, I think all organists are pretty cool. They play a cool,
- complicated instrument that really sounds like no other. They also play
- with their hands and their feet. Someone once said when a musician mates
- with an octopus, an organist is born. Come to think of it, Davy Jones
- plays the Organ and he's pretty cool. Coincidence? I think not.
- </p>
-
- <p>
- If you get the chance, give Vierne a listen, you can look up his work on
- YouTube or a Pandora Radio station in his name. Look especially for
- Symphony No. 1 for Organ in D Minor, Op. 14. That's the first song I
- heard of his live (and in my understanding is the one he was playing
- when he died).
- </p>
- </article>
- </body>
-</html>
diff --git a/posts/2021-02-12-louis-vierne-is-a-bamf-and-proof-that-organists-are-metal.php b/posts/2021-02-12-louis-vierne-is-a-bamf-and-proof-that-organists-are-metal.php
new file mode 100644
index 0000000..864265a
--- /dev/null
+++ b/posts/2021-02-12-louis-vierne-is-a-bamf-and-proof-that-organists-are-metal.php
@@ -0,0 +1,67 @@
+<?php
+$title = "Louis Vierne Is a BAMF (and Proof That Organists Are Metal)";
+if (isset($early) && $early) {
+ return;
+}
+include($_SERVER['DOCUMENT_ROOT'] . '/includes/head.php');
+?>
+
+<p>
+ Louis Vierne is a certifiable badass organist from the end of the 19th
+ and early 20th centuries. He was born blind and had to have surgery to
+ be able to distinguish shapes and objects. Did that stop him from
+ playing the one instrument that literally requires you to distinguish
+ hundreds and hundreds of small objects from each other? Nope, he just
+ did it (and he learned from Cesar Franck, another great organist).
+</p>
+
+<p>
+ In 1906 he got hit by a car and the doctors said they might have to
+ amputate his leg. Did you know you play an organ with both your hands
+ <em>and</em> both your feet? Well you do, and Vierne just re-learned how
+ to play with his feet after the accident. Because nobody tells Louis
+ Vierne no.
+</p>
+
+<p>
+ And because he's a badass, Vierne went on to become the official
+ organist at the Notre Dame in Paris, a position he won by competitively
+ dunking on numerous other musicians. He considered this his greatest
+ achievement, and what Louis Vierne says goes.
+</p>
+
+<p>
+ In one final act of badassery, he carried out his lifelong dream: to die
+ while playing at Notre Dame. In 1937, to a full recital hall in Notre
+ Dame, he was giving his 1,750th performance and actually
+ <em>had a heart-attack while playing and died at the console, and keeled
+ over so that the low "E" played until they removed his body</em>. To this day, no rock band has ever been so metal.
+</p>
+
+<hr />
+
+<p>
+ Alright, so without the decoration, Louis Vierne is my favorite Organist
+ and composer from the period. The organ is, in my opinion, the coolest
+ instrument on the planet. It's the biggest, the loudest, and the most
+ impressive. It's also got the most wide and interesting array of sounds,
+ like having an orchestra at your fingertips. Vierne made some of my
+ favorite music for the organ (music that my lowly organ skills will
+ never let me play). He's also, obviously, pretty badass.
+</p>
+
+<p>
+ In truth, I think all organists are pretty cool. They play a cool,
+ complicated instrument that really sounds like no other. They also play
+ with their hands and their feet. Someone once said when a musician mates
+ with an octopus, an organist is born. Come to think of it, Davy Jones
+ plays the Organ and he's pretty cool. Coincidence? I think not.
+</p>
+
+<p>
+ If you get the chance, give Vierne a listen, you can look up his work on
+ YouTube or a Pandora Radio station in his name. Look especially for
+ Symphony No. 1 for Organ in D Minor, Op. 14. That's the first song I
+ heard of his live (and in my understanding is the one he was playing
+ when he died).
+</p>
diff --git a/posts/2021-03-19-how-to-automate-certbot-renewal-with-haproxy.html b/posts/2021-03-19-how-to-automate-certbot-renewal-with-haproxy.html
deleted file mode 100644
index 34fbcf0..0000000
--- a/posts/2021-03-19-how-to-automate-certbot-renewal-with-haproxy.html
+++ /dev/null
@@ -1,256 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta
- property="og:image"
- content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview"
- />
- <meta property="og:site_name" content="53hor.net" />
- <meta
- property="og:title"
- content="How to Automate Certbot Renewal with HAProxy"
- />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>53hornet ➙ How to Automate Certbot Renewal with HAProxy</title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <article>
- <h1>How to Automate Certbot Renewal with HAProxy</h1>
-
- <p>
- So this is specifically for HAProxy on FreeBSD, but it should apply to
- other *nix systems as well. Basically, I use HAProxy as a reverse proxy
- to a bunch of servers I administer. I use Let's Encrypt for a
- certificate and I used <code>certbot</code> to generate that
- certificate. Generating the certificate for the first time is easy and
- has lots of documentation, but it wasn't initially clear on how I could
- easily set up auto-renewal. Here's how I did it.
- </p>
-
- <p>
- If you've already set up TLS termination with HAProxy and
- <code>certbot</code>, you know you need to combine your Let's Encrypt
- fullchain and private key to get a combined certificate that HAProxy can
- use. You can do this by <code>cat</code>-ing the chain and key together
- like so:
- </p>
-
- <pre>
-<code>
-cat /usr/local/etc/letsencrypt/live/$SITE/fullchain.pem /usr/local/etc/letsencrypt/live/$SITE/privkey.pem > /usr/local/etc/ssl/haproxy.pem
-</code>
- </pre>
-
- <p>
- In this example, <code>$SITE</code> is your domain name that you fed
- HAProxy when you created the certificate and <code>haproxy.pem</code> is
- wherever you're storing HAProxy's combined certificate. Your HAProxy
- config then points to that certificate like this:
- </p>
-
- <pre>
-<code>
-macon% grep crt /usr/local/etc/haproxy.conf
- bind *:443 ssl crt /usr/local/etc/ssl/haproxy.pem
-</code>
- </pre>
-
- <p>
- And that was the end of the first-time setup. Then a few months later
- you probably had to do it again because Let's Encrypt certs are only
- good for 90 days in between renewals. To renew the certificate, you
- usually run <code>certbot renew</code>, it detects which certificates
- are present, and uses either the webroot or standlone server renewal
- process. Then you have to <code>cat</code> the fullchain and privkey
- together and restart HAProxy so it starts using the new certificate.
- </p>
-
- <p>
- To automate those steps, newer versions of
- <code>certbot</code> will run any post renewal hooks (read: scripts)
- that you want. You can also configure HAProxy and
- <code>certbot</code> to perform the ACME challenge dance for renewal so
- that you don't have to use it interactively.
- </p>
-
- <p>
- First, if you haven't already done it, change your HAProxy config so
- there's a frontend+backend for responding to ACME challenges. In a
- frontend listening for requests, create an access control list for any
- request looking for <code>/.well-known/acme-challenge/</code>. Send
- those requests to a backend server with an unused local port.
- </p>
-
- <pre>
-<code>
-frontend http-in
- acl letsencrypt-acl path_beg /.well-known/acme-challenge/
- use_backend letsencrypt-backend if letsencrypt-acl
- ...
-backend letsencrypt-backend
- server letsencrypt 127.0.0.1:54321
-</code>
- </pre>
-
- <p>
- What this will do is allow <code>certbot</code> and Let's Encrypt to
- renew your server in standalone mode via your reverse proxy. As an added
- bonus it prevents you from having to open up an additional port on your
- firewall.
- </p>
-
- <p>
- Now you've gotta configure <code>certbot</code> to do just that. A
- config file was created in <code>certbot</code>'s
- <code>renew</code> directory for your site. All you need to do in that
- file is add a line to the <code>[renewalparams]</code> section
- specifying the port you're using in your HAProxy config.
- </p>
-
- <pre>
-<code>
-macon% echo "http01_port = 54321" >> /usr/local/etc/letsencrypt/renewal/$SITE.conf
-</code>
- </pre>
-
- <p>
- Now you need the post-renewal hooks. I dropped two separate scripts into
- the <code>renewal-hooks</code> directory: one does the job of combining
- the certificate chain and private key and the other just restarts
- HAProxy.
- </p>
-
- <pre>
-<code>
-macon% cat /usr/local/etc/letsencrypt/renewal-hooks/post/001-catcerts.sh
-#!/bin/sh
-
-SITE=(your site of course)
-
-cd /usr/local/etc/letsencrypt/live/$SITE
-cat fullchain.pem privkey.pem > /usr/local/etc/ssl/haproxy.pem
-macon% cat /usr/local/etc/letsencrypt/renewal-hooks/post/002-haproxy.sh
-#!/bin/sh
-service haproxy restart
-</code>
- </pre>
-
- <p>
- When <code>certbot renew</code> is run, <code>certbot</code> checks the
- <code>renewal-hooks/post</code> directory and runs any executable things
- in it after it's renewed the certificate(s). As a side note,
- <em>make sure you hit those scripts with <code>chmod +x</code></em> or
- they probably won't run.
- </p>
-
- <p>
- Now all that's left is dropping a job into <code>cron</code> or
- <code>periodic</code> to run <code>certbot renew</code> at least once or
- twice within the renewal period.
- </p>
-
- <pre>
-<code>
-macon% doas crontab -l|grep certbot
-# certbot renewal
-@monthly certbot renew
-</code>
- </pre>
-
- <p>
- You can always test that your scripts are working with
- <code>certbot renew --dry-run</code> just to be safe.
- </p>
-
- <pre>
-<code>
-macon% doas certbot renew --dry-run
-Saving debug log to /var/log/letsencrypt/letsencrypt.log
-
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-Processing /usr/local/etc/letsencrypt/renewal/53hor.net.conf
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-Cert not due for renewal, but simulating renewal for dry run
-Plugins selected: Authenticator standalone, Installer None
-Simulating renewal of an existing certificate for 53hor.net and 7 more domains
-Performing the following challenges:
-http-01 challenge for 53hor.net
-http-01 challenge for carpentertutoring.com
-http-01 challenge for git.53hor.net
-http-01 challenge for nextcloud.53hor.net
-http-01 challenge for pkg.53hor.net
-http-01 challenge for plex.53hor.net
-http-01 challenge for theglassyladies.com
-http-01 challenge for www.53hor.net
-Waiting for verification...
-Cleaning up challenges
-
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-new certificate deployed without reload, fullchain is
-/usr/local/etc/letsencrypt/live/53hor.net/fullchain.pem
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-Congratulations, all simulated renewals succeeded:
- /usr/local/etc/letsencrypt/live/53hor.net/fullchain.pem (success)
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-Running post-hook command: /usr/local/etc/letsencrypt/renewal-hooks/post/001-catcerts.sh
-Running post-hook command: /usr/local/etc/letsencrypt/renewal-hooks/post/002-haproxy.sh
-Output from post-hook command 002-haproxy.sh:
-Waiting for PIDS: 15191.
-Starting haproxy.
-
-</code>
- </pre>
-
- <p>
- And there it is. Automated Let's Encrypt certificate renewal on FreeBSD
- with HAProxy.
- </p>
- </article>
- </body>
-</html>
diff --git a/posts/2021-03-19-how-to-automate-certbot-renewal-with-haproxy.php b/posts/2021-03-19-how-to-automate-certbot-renewal-with-haproxy.php
new file mode 100644
index 0000000..634a57d
--- /dev/null
+++ b/posts/2021-03-19-how-to-automate-certbot-renewal-with-haproxy.php
@@ -0,0 +1,198 @@
+<?php
+$title = "How to Automate Certbot Renewal with HAPRoxy (on FreeBSD)";
+if (isset($early) && $early) {
+ return;
+}
+include($_SERVER['DOCUMENT_ROOT'] . '/includes/head.php');
+?>
+
+<p>
+ So this is specifically for HAProxy on FreeBSD, but it should apply to
+ other *nix systems as well. Basically, I use HAProxy as a reverse proxy
+ to a bunch of servers I administer. I use Let's Encrypt for a
+ certificate and I used <code>certbot</code> to generate that
+ certificate. Generating the certificate for the first time is easy and
+ has lots of documentation, but it wasn't initially clear on how I could
+ easily set up auto-renewal. Here's how I did it.
+</p>
+
+<p>
+ If you've already set up TLS termination with HAProxy and
+ <code>certbot</code>, you know you need to combine your Let's Encrypt
+ fullchain and private key to get a combined certificate that HAProxy can
+ use. You can do this by <code>cat</code>-ing the chain and key together
+ like so:
+</p>
+
+<pre>
+<code>
+cat /usr/local/etc/letsencrypt/live/$SITE/fullchain.pem /usr/local/etc/letsencrypt/live/$SITE/privkey.pem > /usr/local/etc/ssl/haproxy.pem
+</code>
+ </pre>
+
+<p>
+ In this example, <code>$SITE</code> is your domain name that you fed
+ HAProxy when you created the certificate and <code>haproxy.pem</code> is
+ wherever you're storing HAProxy's combined certificate. Your HAProxy
+ config then points to that certificate like this:
+</p>
+
+<pre>
+<code>
+macon% grep crt /usr/local/etc/haproxy.conf
+ bind *:443 ssl crt /usr/local/etc/ssl/haproxy.pem
+</code>
+ </pre>
+
+<p>
+ And that was the end of the first-time setup. Then a few months later
+ you probably had to do it again because Let's Encrypt certs are only
+ good for 90 days in between renewals. To renew the certificate, you
+ usually run <code>certbot renew</code>, it detects which certificates
+ are present, and uses either the webroot or standlone server renewal
+ process. Then you have to <code>cat</code> the fullchain and privkey
+ together and restart HAProxy so it starts using the new certificate.
+</p>
+
+<p>
+ To automate those steps, newer versions of
+ <code>certbot</code> will run any post renewal hooks (read: scripts)
+ that you want. You can also configure HAProxy and
+ <code>certbot</code> to perform the ACME challenge dance for renewal so
+ that you don't have to use it interactively.
+</p>
+
+<p>
+ First, if you haven't already done it, change your HAProxy config so
+ there's a frontend+backend for responding to ACME challenges. In a
+ frontend listening for requests, create an access control list for any
+ request looking for <code>/.well-known/acme-challenge/</code>. Send
+ those requests to a backend server with an unused local port.
+</p>
+
+<pre>
+<code>
+frontend http-in
+ acl letsencrypt-acl path_beg /.well-known/acme-challenge/
+ use_backend letsencrypt-backend if letsencrypt-acl
+ ...
+backend letsencrypt-backend
+ server letsencrypt 127.0.0.1:54321
+</code>
+ </pre>
+
+<p>
+ What this will do is allow <code>certbot</code> and Let's Encrypt to
+ renew your server in standalone mode via your reverse proxy. As an added
+ bonus it prevents you from having to open up an additional port on your
+ firewall.
+</p>
+
+<p>
+ Now you've gotta configure <code>certbot</code> to do just that. A
+ config file was created in <code>certbot</code>'s
+ <code>renew</code> directory for your site. All you need to do in that
+ file is add a line to the <code>[renewalparams]</code> section
+ specifying the port you're using in your HAProxy config.
+</p>
+
+<pre>
+<code>
+macon% echo "http01_port = 54321" >> /usr/local/etc/letsencrypt/renewal/$SITE.conf
+</code>
+ </pre>
+
+<p>
+ Now you need the post-renewal hooks. I dropped two separate scripts into
+ the <code>renewal-hooks</code> directory: one does the job of combining
+ the certificate chain and private key and the other just restarts
+ HAProxy.
+</p>
+
+<pre>
+<code>
+macon% cat /usr/local/etc/letsencrypt/renewal-hooks/post/001-catcerts.sh
+#!/bin/sh
+
+SITE=(your site of course)
+
+cd /usr/local/etc/letsencrypt/live/$SITE
+cat fullchain.pem privkey.pem > /usr/local/etc/ssl/haproxy.pem
+macon% cat /usr/local/etc/letsencrypt/renewal-hooks/post/002-haproxy.sh
+#!/bin/sh
+service haproxy restart
+</code>
+ </pre>
+
+<p>
+ When <code>certbot renew</code> is run, <code>certbot</code> checks the
+ <code>renewal-hooks/post</code> directory and runs any executable things
+ in it after it's renewed the certificate(s). As a side note,
+ <em>make sure you hit those scripts with <code>chmod +x</code></em> or
+ they probably won't run.
+</p>
+
+<p>
+ Now all that's left is dropping a job into <code>cron</code> or
+ <code>periodic</code> to run <code>certbot renew</code> at least once or
+ twice within the renewal period.
+</p>
+
+<pre>
+<code>
+macon% doas crontab -l|grep certbot
+# certbot renewal
+@monthly certbot renew
+</code>
+ </pre>
+
+<p>
+ You can always test that your scripts are working with
+ <code>certbot renew --dry-run</code> just to be safe.
+</p>
+
+<pre>
+<code>
+macon% doas certbot renew --dry-run
+Saving debug log to /var/log/letsencrypt/letsencrypt.log
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Processing /usr/local/etc/letsencrypt/renewal/53hor.net.conf
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Cert not due for renewal, but simulating renewal for dry run
+Plugins selected: Authenticator standalone, Installer None
+Simulating renewal of an existing certificate for 53hor.net and 7 more domains
+Performing the following challenges:
+http-01 challenge for 53hor.net
+http-01 challenge for carpentertutoring.com
+http-01 challenge for git.53hor.net
+http-01 challenge for nextcloud.53hor.net
+http-01 challenge for pkg.53hor.net
+http-01 challenge for plex.53hor.net
+http-01 challenge for theglassyladies.com
+http-01 challenge for www.53hor.net
+Waiting for verification...
+Cleaning up challenges
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+new certificate deployed without reload, fullchain is
+/usr/local/etc/letsencrypt/live/53hor.net/fullchain.pem
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Congratulations, all simulated renewals succeeded:
+ /usr/local/etc/letsencrypt/live/53hor.net/fullchain.pem (success)
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+Running post-hook command: /usr/local/etc/letsencrypt/renewal-hooks/post/001-catcerts.sh
+Running post-hook command: /usr/local/etc/letsencrypt/renewal-hooks/post/002-haproxy.sh
+Output from post-hook command 002-haproxy.sh:
+Waiting for PIDS: 15191.
+Starting haproxy.
+
+</code>
+ </pre>
+
+<p>
+ And there it is. Automated Let's Encrypt certificate renewal on FreeBSD
+ with HAProxy.
+</p>
diff --git a/posts/2021-04-20-how-to-make-your-website-boring-and-why.html b/posts/2021-04-20-how-to-make-your-website-boring-and-why.html
deleted file mode 100644
index 8bbcfb6..0000000
--- a/posts/2021-04-20-how-to-make-your-website-boring-and-why.html
+++ /dev/null
@@ -1,214 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta
- property="og:image"
- content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview"
- />
- <meta property="og:site_name" content="53hor.net" />
- <meta
- property="og:title"
- content="How to Make Your Website Boring and Why!"
- />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>53hornet ➙ How to Make Your Website Boring and Why!</title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <article>
- <h1>How to Make Your Website Boring and Why!</h1>
-
- <p class="description">
- I took the time last year to make my website more boring. Here's how you
- can do the same and why you'd want to.
- </p>
-
- <p>
- Up until recently I was using a static site generator
- <a>(cobalt-rs)</a> and a fancy CSS framework/library <a>(Bulma)</a> to
- build my website. I also had one or two scripts to do various fiddly
- things in the browser. I took the time to gut it and now I have a much
- more boring website. I don't use anything but HTML to write all of the
- posts and pages. This eliminated the need for a static generator or
- script to turn something like Markdown into HTML for me. I also scrapped
- all of the customized CSS framework style sheets that I had been using
- for a very small (145 lines including whitespace and braces) single-file
- stylesheet. I also dropped all of the fancy links, banners, most of the
- icons, and any JavaScript that I had originally. Now, my site is much
- more boring. And it's so much better.
- </p>
-
- <h2>How does one make their website boring?</h2>
-
- <p>
- Typically, ask yourself whether you need something. If the answer is
- "no", you can safely remove it and you won't need it again. Your website
- will become more boring (read: simpler). Here are some of the things I
- evaluated:
- </p>
-
- <ul>
- <li>
- How many 3rd-party assets, templates, CSS libraries am I using? How
- big are they? Are they slowing down rendering or annoying to
- maintain/upgrade?
- </li>
- <li>Do I need a Sass interpreter to "build" my styles?</li>
- <li>
- Am I using a static site generator? Does it make my life easier or
- more difficult?
- </li>
- <li>
- Am I using a bunch of JavaScript? What does it do and does it really
- need to do it to make my site work better?
- </li>
- </ul>
-
- <p>
- Do you use a lot of third-party assets, templates, or CSS for your site?
- Do you have to run a SASS tool to generate your stylesheets? Are your
- stylesheets really big (> 1000 lines I think anyone would consider on
- the bigger side)? Consider whether or not you really need them.
- Oftentimes, with CSS, less is more. Especially if your site is just a
- collection of pages of text with links to other pages of text. You can
- make your site attractive and compatible with 100% of browsers by
- keeping things simple. And then you don't have to worry about rebuilding
- your output stylesheets or keeping up with libraries and frameworks.
- </p>
-
- <p>
- Do you have a lot of dynamically-generated content on your site? Does
- the document need to change based on user input? Do you have a large
- number of script tags importing minified files from third-party CDNs?
- Odds are you don't need those either and you can completely get rid of
- them. Now you don't have to worry about making sure all browsers can run
- those scripts, or whether or not the CDNs are online, or you're
- requesting the latest version.
- </p>
-
- <p>
- Do you use a static site generator to build your site? Is your content
- complicated enough to write that you can't write it in plain HTML? Is
- Markdown really easier or more powerful? Odds are, it's easier to write
- directly in HTML without having to tell your generator what to do with
- your tags. And for the oddball tag that Markdown doesn't directly
- support, you might often end up writing HTML into your Markdown files
- anyways. And, you can better control what the output formatting looks
- like, making your site's code more readable. Furthermore, you won't have
- two acting copies of your site, a pre- and post-generator one. For me,
- it was annoying having "source code" for my web site that was different
- from what I was actually hosting. It's so much nicer to have a 1:1
- mapping between what I write, test, and deploy.
- </p>
-
- <p>
- Still not convinced? Still need to automate some part of building your
- site, like generating an RSS feed? Is there any chance you can write a
- quick Makefile to do that for you? I was able to do just that, and it
- was way nicer not having to install and learn how a generator worked to
- automate assembling my site.
- </p>
-
- <p>
- If you answered "no" to any of the above "do you need"-s, you just found
- a way to make your site more boring. Boring equates with simplicity.
- Simplicity is a good thing.
- </p>
-
- <h2>Why should you make your website <s>boring</s> simple?</h2>
-
- <p>
- Not relying on a bunch of libraries and assets is a good thing. It
- seemed like every time I wanted to add a quick post, I would notice
- there was an update for some library I was using and I was spending time
- upgrading and learning about it. You know, that thing that computer
- programmers enjoy doing and are good at but often doesn't actually help
- them accomplish anything: fiddling with shiny new stuff that doesn't
- solve a problem. Now I get to just focus on adding things to my site and
- I'm never worried about whether it looks broken.
- </p>
-
- <p>
- I also didn't like having a pre- and post-build site. If I wanted to fix
- one typo I couldn't remote into my live site, fix it, and then leave it
- there. I had to do something like fix the typo in my Markdown, commit
- and push it, and then re-run the generator and upload the new "live"
- files. The generator step wasn't making things easier, it was making
- them more annoying.
- </p>
-
- <p>
- You'd also be surprised at how easy it is to make your site fast and
- reliable on all modern and old browsers when it's boring (read: simple,
- again). Internet Explorer doesn't care about my site, it's a breeze to
- render and there's nothing in it that hasn't been in existence for at
- least a decade. (Alright, I do have a few SVG icons which it probably
- wouldn't know what to do with. You can't tell the difference between
- Firefox's and Chrome's renders of my site. And Google's PageSpeed
- Insights score is a hilarious 99.
- </p>
-
- <p>
- My site is also more functional now. It's less distracting. It's really
- easy to navigate and read. There's no runtime, no JavaScript that has to
- execute before the reader sees the page they're looking for. And there's
- practically nothing to maintain except my posts. It's also really easy
- for crawlers to quickly ingest all of my posts and turn them into search
- results. Hopefully, it's also easier for the visually impaired to zoom
- in and not mess up the document, or use a screen reader that extracts
- the article tags.
- </p>
-
- <p>
- The benefits are through the roof. My site used to be about tinkering
- with tools and libraries and frameworks. Now it's just a boring website.
- That leaves me with time to focus on tinkering with other stuff that's
- more interesting, and only focus on writing when I'm working on this
- site. So make your life easier and go make your website boring today.
- </p>
- </article>
- </body>
-</html>
diff --git a/posts/2021-04-20-how-to-make-your-website-boring-and-why.php b/posts/2021-04-20-how-to-make-your-website-boring-and-why.php
new file mode 100644
index 0000000..6f8136d
--- /dev/null
+++ b/posts/2021-04-20-how-to-make-your-website-boring-and-why.php
@@ -0,0 +1,156 @@
+<?php
+$title = "How to Make Your Website Boring and Why!";
+if (isset($early) && $early) {
+ return;
+}
+include($_SERVER['DOCUMENT_ROOT'] . '/includes/head.php');
+?>
+
+<p class="description">
+ I took the time last year to make my website more boring. Here's how you
+ can do the same and why you'd want to.
+</p>
+
+<p>
+ Up until recently I was using a static site generator
+ <a>(cobalt-rs)</a> and a fancy CSS framework/library <a>(Bulma)</a> to
+ build my website. I also had one or two scripts to do various fiddly
+ things in the browser. I took the time to gut it and now I have a much
+ more boring website. I don't use anything but HTML to write all of the
+ posts and pages. This eliminated the need for a static generator or
+ script to turn something like Markdown into HTML for me. I also scrapped
+ all of the customized CSS framework style sheets that I had been using
+ for a very small (145 lines including whitespace and braces) single-file
+ stylesheet. I also dropped all of the fancy links, banners, most of the
+ icons, and any JavaScript that I had originally. Now, my site is much
+ more boring. And it's so much better.
+</p>
+
+<h2>How does one make their website boring?</h2>
+
+<p>
+ Typically, ask yourself whether you need something. If the answer is
+ "no", you can safely remove it and you won't need it again. Your website
+ will become more boring (read: simpler). Here are some of the things I
+ evaluated:
+</p>
+
+<ul>
+ <li>
+ How many 3rd-party assets, templates, CSS libraries am I using? How
+ big are they? Are they slowing down rendering or annoying to
+ maintain/upgrade?
+ </li>
+ <li>Do I need a Sass interpreter to "build" my styles?</li>
+ <li>
+ Am I using a static site generator? Does it make my life easier or
+ more difficult?
+ </li>
+ <li>
+ Am I using a bunch of JavaScript? What does it do and does it really
+ need to do it to make my site work better?
+ </li>
+</ul>
+
+<p>
+ Do you use a lot of third-party assets, templates, or CSS for your site?
+ Do you have to run a SASS tool to generate your stylesheets? Are your
+ stylesheets really big (> 1000 lines I think anyone would consider on
+ the bigger side)? Consider whether or not you really need them.
+ Oftentimes, with CSS, less is more. Especially if your site is just a
+ collection of pages of text with links to other pages of text. You can
+ make your site attractive and compatible with 100% of browsers by
+ keeping things simple. And then you don't have to worry about rebuilding
+ your output stylesheets or keeping up with libraries and frameworks.
+</p>
+
+<p>
+ Do you have a lot of dynamically-generated content on your site? Does
+ the document need to change based on user input? Do you have a large
+ number of script tags importing minified files from third-party CDNs?
+ Odds are you don't need those either and you can completely get rid of
+ them. Now you don't have to worry about making sure all browsers can run
+ those scripts, or whether or not the CDNs are online, or you're
+ requesting the latest version.
+</p>
+
+<p>
+ Do you use a static site generator to build your site? Is your content
+ complicated enough to write that you can't write it in plain HTML? Is
+ Markdown really easier or more powerful? Odds are, it's easier to write
+ directly in HTML without having to tell your generator what to do with
+ your tags. And for the oddball tag that Markdown doesn't directly
+ support, you might often end up writing HTML into your Markdown files
+ anyways. And, you can better control what the output formatting looks
+ like, making your site's code more readable. Furthermore, you won't have
+ two acting copies of your site, a pre- and post-generator one. For me,
+ it was annoying having "source code" for my web site that was different
+ from what I was actually hosting. It's so much nicer to have a 1:1
+ mapping between what I write, test, and deploy.
+</p>
+
+<p>
+ Still not convinced? Still need to automate some part of building your
+ site, like generating an RSS feed? Is there any chance you can write a
+ quick Makefile to do that for you? I was able to do just that, and it
+ was way nicer not having to install and learn how a generator worked to
+ automate assembling my site.
+</p>
+
+<p>
+ If you answered "no" to any of the above "do you need"-s, you just found
+ a way to make your site more boring. Boring equates with simplicity.
+ Simplicity is a good thing.
+</p>
+
+<h2>Why should you make your website <s>boring</s> simple?</h2>
+
+<p>
+ Not relying on a bunch of libraries and assets is a good thing. It
+ seemed like every time I wanted to add a quick post, I would notice
+ there was an update for some library I was using and I was spending time
+ upgrading and learning about it. You know, that thing that computer
+ programmers enjoy doing and are good at but often doesn't actually help
+ them accomplish anything: fiddling with shiny new stuff that doesn't
+ solve a problem. Now I get to just focus on adding things to my site and
+ I'm never worried about whether it looks broken.
+</p>
+
+<p>
+ I also didn't like having a pre- and post-build site. If I wanted to fix
+ one typo I couldn't remote into my live site, fix it, and then leave it
+ there. I had to do something like fix the typo in my Markdown, commit
+ and push it, and then re-run the generator and upload the new "live"
+ files. The generator step wasn't making things easier, it was making
+ them more annoying.
+</p>
+
+<p>
+ You'd also be surprised at how easy it is to make your site fast and
+ reliable on all modern and old browsers when it's boring (read: simple,
+ again). Internet Explorer doesn't care about my site, it's a breeze to
+ render and there's nothing in it that hasn't been in existence for at
+ least a decade. (Alright, I do have a few SVG icons which it probably
+ wouldn't know what to do with. You can't tell the difference between
+ Firefox's and Chrome's renders of my site. And Google's PageSpeed
+ Insights score is a hilarious 99.
+</p>
+
+<p>
+ My site is also more functional now. It's less distracting. It's really
+ easy to navigate and read. There's no runtime, no JavaScript that has to
+ execute before the reader sees the page they're looking for. And there's
+ practically nothing to maintain except my posts. It's also really easy
+ for crawlers to quickly ingest all of my posts and turn them into search
+ results. Hopefully, it's also easier for the visually impaired to zoom
+ in and not mess up the document, or use a screen reader that extracts
+ the article tags.
+</p>
+
+<p>
+ The benefits are through the roof. My site used to be about tinkering
+ with tools and libraries and frameworks. Now it's just a boring website.
+ That leaves me with time to focus on tinkering with other stuff that's
+ more interesting, and only focus on writing when I'm working on this
+ site. So make your life easier and go make your website boring today.
+</p>
diff --git a/posts/2021-05-23-web-designers-please-don-t-animate-page-titles.html b/posts/2021-05-23-web-designers-please-don-t-animate-page-titles.html
deleted file mode 100644
index 65eea7a..0000000
--- a/posts/2021-05-23-web-designers-please-don-t-animate-page-titles.html
+++ /dev/null
@@ -1,133 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta
- property="og:image"
- content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview"
- />
- <meta property="og:site_name" content="53hor.net" />
- <meta property="og:title" content="Web Designers, Please Don't "Animate"
- Page Titles" />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>53hornet ➙ Web Designers, Please Don't "Animate" Page Titles</title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <article>
- <h1>Web Designers, Please Don't "Animate" Page Titles</h1>
-
- <p>
- If you visit
- <a href="https://www.expressoil.com">Express Oil Change's web site</a>,
- everything seems completely ordinary until you leave the tab. That's
- when the most distracting, broken, annoying example of over-the-top web
- "design" rears its ugly head.
- </p>
-
- <p>
- I'm talking about this scrolling page title. In my tab. Constantly
- moving from right to left to show me all of the text. It's the only tab
- that's "moving" or "animated" and it doesn't stop until you return to
- the tab. It's cheesy and gaudy.
- </p>
-
- <p>
- <img
- src="https://nextcloud.53hor.net/index.php/s/TWDbzjiSwzHbMcz/preview"
- />
- </p>
-
- <p>
- And it's also broken because there are emojis in the page title and the
- title is obviously being "scrolled" by some script that's moving
- byte-by-byte, so it scrolls halfway through a multi-byte UTF-8 emoji and
- for a brief moment there's a glyph error character where a little red
- car should have been. Bad judgment and bad programming. Worse than that,
- even if it worked perfectly, it's incredibly annoying.
- </p>
-
- <p>
- <img
- src="https://nextcloud.53hor.net/index.php/s/TbbDnnL3jnZMT3g/preview"
- />
- </p>
-
- <p>
- If you bookmark the tab when it's in the middle of scrolling, you'll
- bookmark this weird slice of the text that starts or ends in the middle
- of a word or with a random emoji.
- </p>
-
- <p>
- <img
- src="https://nextcloud.53hor.net/index.php/s/ocQofL2Goxd3AsQ/preview"
- />
- </p>
-
- <p>
- Page titles changing is typically used to notify the user that their
- action is needed, such as when a file is finished uploading. In this
- case, since the text is <em>constantly changing</em>, the tab is always
- in a state of "urgency." Most annoyingly, this causes the browser to
- highlight the tab when it's pinned. Even if you click the tab and leave
- it, this notification reappears.
- </p>
-
- <p>
- <img
- src="https://nextcloud.53hor.net/index.php/s/AcNgR4cDxGDsWCB/preview"
- />
- </p>
-
- <p>
- Don't do this. Stop. Get some help. It's distracting. It's the cheesy
- "web dev" equivalent of retina scan advertising in Minority Report. Just
- make a site that works and looks half decent without slowing to a halt
- and stop there please.
- </p>
- </article>
- </body>
-</html>
diff --git a/posts/2021-05-23-web-designers-please-don-t-animate-page-titles.php b/posts/2021-05-23-web-designers-please-don-t-animate-page-titles.php
new file mode 100644
index 0000000..1c28487
--- /dev/null
+++ b/posts/2021-05-23-web-designers-please-don-t-animate-page-titles.php
@@ -0,0 +1,69 @@
+<?php
+$title = "Web Designers, Please Don't Animate Page Titles";
+if (isset($early) && $early) {
+ return;
+}
+include($_SERVER['DOCUMENT_ROOT'] . '/includes/head.php');
+?>
+
+<p>
+ If you visit
+ <a href="https://www.expressoil.com">Express Oil Change's web site</a>,
+ everything seems completely ordinary until you leave the tab. That's
+ when the most distracting, broken, annoying example of over-the-top web
+ "design" rears its ugly head.
+</p>
+
+<p>
+ I'm talking about this scrolling page title. In my tab. Constantly
+ moving from right to left to show me all of the text. It's the only tab
+ that's "moving" or "animated" and it doesn't stop until you return to
+ the tab. It's cheesy and gaudy.
+</p>
+
+<p>
+ <img src="https://nextcloud.53hor.net/index.php/s/TWDbzjiSwzHbMcz/preview" />
+</p>
+
+<p>
+ And it's also broken because there are emojis in the page title and the
+ title is obviously being "scrolled" by some script that's moving
+ byte-by-byte, so it scrolls halfway through a multi-byte UTF-8 emoji and
+ for a brief moment there's a glyph error character where a little red
+ car should have been. Bad judgment and bad programming. Worse than that,
+ even if it worked perfectly, it's incredibly annoying.
+</p>
+
+<p>
+ <img src="https://nextcloud.53hor.net/index.php/s/TbbDnnL3jnZMT3g/preview" />
+</p>
+
+<p>
+ If you bookmark the tab when it's in the middle of scrolling, you'll
+ bookmark this weird slice of the text that starts or ends in the middle
+ of a word or with a random emoji.
+</p>
+
+<p>
+ <img src="https://nextcloud.53hor.net/index.php/s/ocQofL2Goxd3AsQ/preview" />
+</p>
+
+<p>
+ Page titles changing is typically used to notify the user that their
+ action is needed, such as when a file is finished uploading. In this
+ case, since the text is <em>constantly changing</em>, the tab is always
+ in a state of "urgency." Most annoyingly, this causes the browser to
+ highlight the tab when it's pinned. Even if you click the tab and leave
+ it, this notification reappears.
+</p>
+
+<p>
+ <img src="https://nextcloud.53hor.net/index.php/s/AcNgR4cDxGDsWCB/preview" />
+</p>
+
+<p>
+ Don't do this. Stop. Get some help. It's distracting. It's the cheesy
+ "web dev" equivalent of retina scan advertising in Minority Report. Just
+ make a site that works and looks half decent without slowing to a halt
+ and stop there please.
+</p>
diff --git a/rss.xml b/rss.xml
deleted file mode 100644
index d704b7b..0000000
--- a/rss.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE xml>
-<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
- <channel>
- <title>53hornet's Feed</title>
- <link>https://www.53hor.net</link>
- <atom:link href="https://www.53hor.net/rss.xml" rel="self" type="application/rss+xml" />
- <description>The World Wide Web pages of Adam Carpenter</description>
- <image>
- <url>https://www.53hor.net/includes/logo_diag.png</url>
- <title>53hornet's Feed</title>
- <link>https://www.53hor.net</link>
- </image>
-<item><title>Web Designers, Please Don't "Animate" Page Titles</title><link>https://www.53hor.net/posts/posts/2021-05-23-web-designers-please-don-t-animate-page-titles.html</link></item>
-<item><title>How to Make Your Website Boring and Why!</title><link>https://www.53hor.net/posts/posts/2021-04-20-how-to-make-your-website-boring-and-why.html</link></item>
-<item><title>How to Automate Certbot Renewal with HAProxy</title><link>https://www.53hor.net/posts/posts/2021-03-19-how-to-automate-certbot-renewal-with-haproxy.html</link></item>
-<item><title>Louis Vierne Is a BAMF (and Proof That Organists Are Metal)</title><link>https://www.53hor.net/posts/posts/2021-02-12-louis-vierne-is-a-bamf-and-proof-that-organists-are-metal.html</link></item>
-<item><title>Undefined? JavaSript Is Undefined.</title><link>https://www.53hor.net/posts/posts/2021-01-28-undefined-javasript-is-undefined.html</link></item>
-<item><title>Root on ZFS: A ZPool of Mirror VDEVs</title><link>https://www.53hor.net/posts/posts/2021-01-15-root-on-zfs-a-zpool-of-mirror-vdevs-the-easy-way.html</link></item>
-<item><title>Adam's <del>2020</del> <ins>Quarantine</ins> Reading List</title><link>https://www.53hor.net/posts/posts/2021-01-15-adam-s-2020-reading-list.html</link></item>
-<item><title>Antivirus Software is a Hack</title><link>https://www.53hor.net/posts/posts/2020-12-29-antivirus-software-is-a-hack.html</link></item>
-<item><title>Why Does Everyone Use Adobe Acrobat [Reader]?</title><link>https://www.53hor.net/posts/posts/2020-12-22-why-does-everyone-use-adobe-acrobat-reader.html</link></item>
-<item><title>Useful Sprint Planning from a Certified Scrum Master</title><link>https://www.53hor.net/posts/posts/2020-12-08-useful-sprint-planning-from-a-certified-scrum-master.html</link></item>
-<item><title>AOC 2020 Day 1 in CBM Basic</title><link>https://www.53hor.net/posts/posts/2020-12-04-aoc-2020-day-1-in-cbm-basic.html</link></item>
-<item><title>𝔗𝔥𝔢 𝔊𝔲𝔦𝔡𝔢𝔰</title><link>https://www.53hor.net/posts/posts/2020-12-01-the-guides.html</link></item>
-<item><title>Titanic's Last Signals</title><link>https://www.53hor.net/posts/posts/2020-11-30-titanics-last-signals.html</link></item>
-<item><title>Now This is a Minimal Install!</title><link>https://www.53hor.net/posts/posts/2020-07-26-now-this-is-a-minimal-install.html</link></item>
-<item><title>Why Computer Science at William and Mary</title><link>https://www.53hor.net/posts/posts/2020-07-11-why-computer-science-at-w-m.html</link></item>
-<item><title>Wedding Photo Debacle</title><link>https://www.53hor.net/posts/posts/2020-04-10-wedding-photos-are-here.html</link></item>
-<item><title>Obligatory COVID-19 Post</title><link>https://www.53hor.net/posts/posts/2020-04-10-the-obligatory-covid-19-post.html</link></item>
-<item><title>How I Do Data Recovery</title><link>https://www.53hor.net/posts/posts/2019-09-28-my-preferred-method-for-data-recovery.html</link></item>
-<item><title>Left Lane is for Passing, Not Cruising</title><link>https://www.53hor.net/posts/posts/2019-08-30-keep-right-except-to-pass.html</link></item>
-<item><title>I Married My Best Friend!</title><link>https://www.53hor.net/posts/posts/2019-08-11-marrying-my-best-friend.html</link></item>
-<item><title>Finally Found a Drink I Like</title><link>https://www.53hor.net/posts/posts/2019-07-28-i-finally-found-a-drink-i-like.html</link></item>
-<item><title>Dancing the Shag & Two Left Feet</title><link>https://www.53hor.net/posts/posts/2019-07-21-dancing-the-shag-and-the-new-lion-king.html</link></item>
-<item><title>YABS: Yet Another Bad Shop</title><link>https://www.53hor.net/posts/posts/2019-07-04-yabs-yet-another-bad-shop.html</link></item>
-<item><title>Offloading GoPro Footage the Easy Way!</title><link>https://www.53hor.net/posts/posts/2019-07-04-the-best-way-to-transfer-gopro-files-with-linux.html</link></item>
-<item><title>How to Start and Drive a Hudson Hornet</title><link>https://www.53hor.net/posts/posts/2019-06-07-how-to-start-and-drive-a-hudson-hornet.html</link></item>
-<item><title>Why Have a Web Site in 2019?</title><link>https://www.53hor.net/posts/posts/2019-04-06-why-have-a-website-in-2019.html</link></item>
-</channel>
-</rss>
-
diff --git a/software.html b/software.html
deleted file mode 100644
index a1d8ea8..0000000
--- a/software.html
+++ /dev/null
@@ -1,102 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta
- property="og:image"
- content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview"
- />
- <meta property="og:site_name" content="53hor.net" />
- <meta property="og:title" content="Self-Software Stuff" />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>53hornet ➙ Self-Software Stuff</title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <article>
- <h1>Self-Software Stuff</h1>
-
- <p>TODO:</p>
-
- <h2>Applications</h2>
-
- <ul>
- <li>
- <a href="https://pkg.53hor.net"> FreeBSD Package Repository </a>
- </li>
- <li>
- <a href="https://nextcloud.53hor.net">
- Nextcloud Files, Contacts, Calendars
- </a>
- </li>
- <li>
- <a href="https://plex.53hor.net">Plex Media Streaming</a>
- </li>
- <li>
- <a href="https://git.53hor.net">Gitea</a>
- </li>
- </ul>
-
- <h2>Game Servers</h2>
-
- <p>
- If I know you and you're welcome to join one of my game servers, you can
- find those here. Non-public ones are password-protected.
- </p>
-
- <h3>[The Ultimate] DooM (Co-op Chocolate Doom)</h3>
- <a href="doom.53hor.net:3343">doom.53hor.net:3343</a>
- <h3>DooM II (Co-op Chocolate Doom)</h3>
- <a href="doom2.53hor.net:3343">doom2.53hor.net:3343</a>
- <h3>
- Skyrim Together (The Elder Scrolls V: Skyrim Special Edition w/ "Skyrim
- Together" mod)
- </h3>
- <a href="st.53hor.net:10578">st.53hor.net:10578</a>
- <h3>Vanilla Minecraft</h3>
- <h3>Minecraft with Mystcraft mod</h3>
- </article>
- </body>
-</html>
diff --git a/templates/index_foot.html b/templates/index_foot.html
deleted file mode 100644
index 420b108..0000000
--- a/templates/index_foot.html
+++ /dev/null
@@ -1,4 +0,0 @@
- </ul>
- </article>
- </body>
-</html>
diff --git a/templates/index_head.html b/templates/index_head.html
deleted file mode 100644
index 502658e..0000000
--- a/templates/index_head.html
+++ /dev/null
@@ -1,68 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta
- property="og:image"
- content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview"
- />
- <meta property="og:site_name" content="53hor.net" />
- <meta property="og:title" content="Home" />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>53hornet ➙ Home</title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <header>
- <noscript>
- JavaScript? Where we're going we don't need JavaScript.
- </noscript>
- </header>
-
- <article>
- <h1 style="text-align: center">
- The World Wide Web pages of Adam Carpenter (53hornet)
- </h1>
- <ul>
diff --git a/templates/rss_foot.xml b/templates/rss_foot.xml
deleted file mode 100644
index 5c185ae..0000000
--- a/templates/rss_foot.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-</channel>
-</rss>
-
diff --git a/templates/template.html b/templates/template.html
deleted file mode 100644
index e5ae191..0000000
--- a/templates/template.html
+++ /dev/null
@@ -1,63 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <head>
- <link rel="stylesheet" href="/includes/stylesheet.css" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <meta
- property="og:description"
- content="The World Wide Web pages of Adam Carpenter"
- />
- <meta property="og:image" content="https://nextcloud.53hor.net/index.php/s/Nx9e7iHbw4t99wo/preview" />
- <meta property="og:site_name" content="53hor.net" />
- <meta property="og:title" content="{{ title }}" />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://www.53hor.net" />
- <title>53hornet ➙ {{ title }}</title>
- </head>
-
- <body>
- <nav>
- <ul>
- <li>
- <a href="/">
- <img alt="home" src="/includes/icons/home-roof.svg" />
- Home
- </a>
- </li>
- <li>
- <a href="/info.html">
- <img alt="information" src="/includes/icons/information-variant.svg" />
- Info
- </a>
- </li>
- <li>
- <a href="https://git.53hor.net">
- <img alt="git" src="/includes/icons/git.svg" />
- Repos
- </a>
- </li>
- <li>
- <a href="/software.html">
- <img alt="software" src="/includes/icons/floppy-variant.svg" />
- Software
- </a>
- </li>
- <li>
- <a type="application/rss+xml" href="/rss.xml">
- <img alt="rss" src="/includes/icons/rss.svg" />
- RSS
- </a>
- </li>
- </ul>
- </nav>
-
- <article>
- <h1>
- {{ title }}
- </h1>
-
- {{ content }}
- </article>
- </body>
-</html>