diff --git a/Sources/Mhoush/String+Extensions.swift b/Sources/Mhoush/String+Extensions.swift
index d15aa6b..4fd63c8 100644
--- a/Sources/Mhoush/String+Extensions.swift
+++ b/Sources/Mhoush/String+Extensions.swift
@@ -27,4 +27,11 @@ extension String {
return prefix(length - end.count).split(separator: " ").dropLast().joined(separator: " ") + end
}
+
+ var removeBreaks: String {
+ replacingOccurrences(of: "
", with: "")
+ .replacingOccurrences(of: "
", with: "")
+ .trimmingCharacters(in: .whitespacesAndNewlines)
+ }
+
}
diff --git a/Sources/Mhoush/run.swift b/Sources/Mhoush/run.swift
index 2d26afe..54950fb 100644
--- a/Sources/Mhoush/run.swift
+++ b/Sources/Mhoush/run.swift
@@ -1,4 +1,5 @@
import Foundation
+import HTML
import PathKit
@preconcurrency import Saga
import SagaParsleyMarkdownReader
@@ -45,6 +46,12 @@ func permalink(item: Item) {
item.relativeDestination = Path(components: components)
}
+func removingBreaks(item: Item) {
+ // remove explicit
from items that show up likely due to how prettier formats
+ // markdown files inside of neovim.
+ item.body = item.body.removeBreaks
+}
+
@main
struct Run {
static func main() async throws {
@@ -56,14 +63,13 @@ struct Run {
folder: "articles",
metadata: ArticleMetadata.self,
readers: [.parsleyMarkdownReader],
- itemProcessor: sequence(publicationDateInFilename, permalink),
+ itemProcessor: sequence(removingBreaks, publicationDateInFilename, permalink),
filter: \.public,
writers: [
.itemWriter(swim(renderArticle)),
.listWriter(swim(renderArticles)),
.tagWriter(swim(renderTag), tags: \.metadata.tags),
.yearWriter(swim(renderYear)),
-
// Atom feed for all articles, and a feed per tag
.listWriter(
atomFeed(
@@ -84,27 +90,12 @@ struct Run {
)
]
)
-
- // All markdown files within the "apps" subfolder will be parsed to html,
- // using AppMetadata as the Item's metadata type.
- // .register(
- // folder: "apps",
- // metadata: AppMetadata.self,
- // readers: [.parsleyMarkdownReader],
- // writers: [.listWriter(swim(renderApps))]
- // )
- //
- // .register(
- // folder: "photos",
- // readers: [.parsleyMarkdownReader],
- // writers: [.itemWriter(swim(renderPhotos))]
- // )
-
// All the remaining markdown files will be parsed to html,
// using the default EmptyMetadata as the Item's metadata type.
.register(
metadata: PageMetadata.self,
readers: [.parsleyMarkdownReader],
+ itemWriteMode: .keepAsFile, // need to keep 404.md as 404.html, not 404/index.html
writers: [.itemWriter(swim(renderPage))]
)
diff --git a/Sources/Mhoush/templates/BaseLayout.swift b/Sources/Mhoush/templates/BaseLayout.swift
index 46104ef..74cf438 100644
--- a/Sources/Mhoush/templates/BaseLayout.swift
+++ b/Sources/Mhoush/templates/BaseLayout.swift
@@ -78,6 +78,9 @@ private func footer(_ rssLink: String) -> Node {
" | "
a(href: "mailto:michael@mhoush.com", rel: "nofollow") { "Email" }
}
+ script(src: "https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-core.min.js")
+ script(src: "https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/keep-markup/prism-keep-markup.min.js")
+ script(src: "https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js")
}
}
diff --git a/Sources/Mhoush/templates/RenderArticles.swift b/Sources/Mhoush/templates/RenderArticles.swift
index c1682fe..d685383 100644
--- a/Sources/Mhoush/templates/RenderArticles.swift
+++ b/Sources/Mhoush/templates/RenderArticles.swift
@@ -28,7 +28,7 @@ func renderArticleForGrid(article: Item) -> Node {
p {
a(href: article.url) {
div {
- img(alt: "banner", src: article.imagePath)
+ // img(alt: "banner", src: article.imagePath)
article.summary
}
}
@@ -56,7 +56,13 @@ func renderArticles(context: ItemsRenderingContext) -> Node {
}
}
-func _renderArticles(_ articles: [Item], canocicalURL: String, title pageTitle: String, rssLink: String = "", extraHeader: NodeConvertible = Node.fragment([])) -> Node {
+func _renderArticles(
+ _ articles: [Item],
+ canocicalURL: String,
+ title pageTitle: String,
+ rssLink: String = "",
+ extraHeader: NodeConvertible = Node.fragment([])
+) -> Node {
return baseLayout(canocicalURL: canocicalURL, section: .articles, title: pageTitle, rssLink: rssLink, extraHeader: extraHeader) {
articles.map { article in
section(class: "mb-10") {
@@ -73,9 +79,20 @@ func _renderArticles(_ articles: [Item], canocicalURL: String,
}
func renderTag(context: PartitionedRenderingContext) -> Node {
- let extraHeader = link(href: "/articles/tag/\(context.key.slugified)/feed.xml", rel: "alternate", title: "\(SiteMetadata.name): articles with tag \(context.key)", type: "application/rss+xml")
+ let extraHeader = link(
+ href: "/articles/tag/\(context.key.slugified)/feed.xml",
+ rel: "alternate",
+ title: "\(SiteMetadata.name): articles with tag \(context.key)",
+ type: "application/rss+xml"
+ )
- return _renderArticles(context.items, canocicalURL: "/articles/tag/\(context.key.slugified)/", title: "Articles in \(context.key)", rssLink: "tag/\(context.key.slugified)/", extraHeader: extraHeader)
+ return _renderArticles(
+ context.items,
+ canocicalURL: "/articles/tag/\(context.key.slugified)/",
+ title: "Articles in \(context.key)",
+ rssLink: "tag/\(context.key.slugified)/",
+ extraHeader: extraHeader
+ )
}
func renderYear(context: PartitionedRenderingContext) -> Node {
diff --git a/content/404.md b/content/404.md
new file mode 100644
index 0000000..f68d4e6
--- /dev/null
+++ b/content/404.md
@@ -0,0 +1,11 @@
+---
+section: notFound
+---
+
+# 404
+
+## Oops!
+
+Your page was not found.
+
+Looking for one of the articles?
diff --git a/content/articles/2023-08-10-coil-bypass-overview.md b/content/articles/2023-08-10-coil-bypass-overview.md
new file mode 100644
index 0000000..b48d984
--- /dev/null
+++ b/content/articles/2023-08-10-coil-bypass-overview.md
@@ -0,0 +1,101 @@
+---
+tags: HVAC, design
+---
+
+# Coil Bypass Overview
+
+This is the first article in a series that explores the idea of a coil bypass strategy in an HVAC system. This article introduces you to a
+coil bypass strategy at a high level, future posts will dive deeper into the features, benefits, as well as the challenges of this style of
+system.
+
+## What is a Coil Bypass
+
+A coil bypass is not to be mistaken for a zoning system bypass, where airflow is "relieved" from the supply side of the system back into the
+return. Instead, a coil bypass diverts a portion of the airflow around the coil using a bypass damper(s). The bypass can serve several
+functions depending on the application, but in general it allows for a constant volume of air to be delivered to the space while the output
+of the coil can be shifted towards more or less dehumidification. In other words, it decouples the total system airflow from the coil
+airflow.
+
+The bypassed air mixes with the supply air stream to act as a reheat source, however unlike a typical reheat source it does not add more
+sensible load to the structure, instead it just brings the supply air temperature closer to the existing home's temperature while still
+covering the latent and sensible loads of the home. A warmer duct system reduces the losses of the duct to unconditioned spaces as well as
+reduces the risk for duct condensation.
+
+The coil bypass strategy, as far as I know, was pioneered by [Harry Boody](https://www.linkedin.com/in/harry-boody-9b8a4366/) of Energy
+Innovations and Scientific Environmental Design, Inc. However their websites are no longer active, so I'm not sure if they are still active
+in the HVAC design space or not.
+
+## The Problem
+
+| Why | |
+| -------- | ---------------------------------------------------------------- |
+| Question | Why would we want to utilize a strategy such as the coil bypass? |
+| Answer | Improved indoor air quality (IAQ) |
+
+ASHRAE's recommandation for the amount of air changes per hour (ACH) in a residential structure to be in the range of 3-5 ACH, and in
+general the higher the better, along with a MERV 13+ filter. In some / most cases the system airflow does not meet that criteria, especially
+low load homes or high volume homes.
+
+For example, let's imagine a single story ranch home that is 2,500 square feet with 9 foot ceilings. This home is relatively tight
+construction and after doing the heating and cooling loads we've selected a 2.5 Ton system for this home. It is located in a green grass
+climate that needs some priority on dehumidification and requires an airflow of 350 CFM/Ton (875 CFM).
+
+We determine the volume of the conditioned space.
+
+2,500 x 9 = 22,500 ft^3
+
+
+
+| **Where:** | |
+| ---------- | ------------------------------------- |
+| **V** | _is the volume of the home_ |
+| **ACH** | _is the desired air changes per hour_ |
+| **60** | _conversion from hours to minutes_ |
+
+Below is a table of the required CFM to meet the different air changes per hour.
+
+| | CFM |
+| --------------- | :-----------------: |
+| (22,500 x 3)/60 | **_1,125 @ 3 ACH_** |
+| (22,500 x 4)/60 | **_1,500 @ 4 ACH_** |
+| (22,500 x 5)/60 | **_1,875 @ 5 ACH_** |
+
+As you can see we have a discrepency of meeting even the low end of 3 ACH. The high end of 5 ACH is over 2x the airflow for our 2.5 Ton
+system. The coil bypass strategy is one viable way, by decoupling the total system airflow from the coil airflow without, which eliminates
+the need of an auxilary fan / system that circulates air through some sort of filtration system.
+
+### Multi-Stage Systems
+
+A challenge with multi-stage systems, even when sized properly, is that we often run at part-load conditions, and spend the majority of the
+time in lower stages. The lower stages often do worse at dehumidification than when running at full load.
+
+When the equipment runs in lower stages on a traditional system the total system airflow is reduced even further from the recommended air
+changes per hour. This reduced airflow also causes the throw of the air from the registers to be reduced which can lead to increased odds of
+stratification, poor air mixing, and increased potential for poor mean radiant temperatures (MRT) of the surfaces. The decreased airflow in
+low stages, lowers the velocity in the duct system, while low velocity is not a concern, it does increase the duct gains and increase the
+possibility of condensation on the ducts when they're located outside of the thermal envelope of the building.
+
+Let's imagine we have a duct system that has high wall registers located in a soffit at the interior wall that moves 100 CFM and we are
+trying to throw the air to the exterior wall which includes a window. The wall is @ 12 feet from the register. We've selected a register
+that meets the criteria, at high stage airflow it has a throw of 11.5 feet (shown as the green rectangle). When the system runs in low
+stage, the airflow is reduced to 70% of high stage (70 CFM), which would give us a throw from the register of @ 7 feet (shown as the red
+rectangle).
+
+
+
+The reduced flow through the register causes the air to only make it about 60% across the room before reaching it's terminal velocity, which
+can cause the room to feel uncomfortable since the air never reaches the exterior wall and window.
+
+By decoupling the fan from the coil airflow it is possible to run in low stages, still have adequate dehumidification performance out of the
+system, and achieve the proper throw from the registers.
+
+## Conclusion
+
+In this article we've begun to scratch the surface of what a coil bypass strategy is in an HVAC system, as well as some of the challenges
+that it can help solve. We've learned about why we may desire to decouple the total system airflow from the coil airflow.
+
+In future articles we will continue to explore some of the features, benefits, and challenges presented by such a strategy.
+
+## Related Resources
+
+[HVAC School - Bypass Dehumidification / Airflow HVAC Design](https://hvacrschool.com/bypass-dehumidification-airflow-hvac-design/)
diff --git a/content/articles/2023-08-10-rss-feed.md b/content/articles/2023-08-10-rss-feed.md
new file mode 100644
index 0000000..e744914
--- /dev/null
+++ b/content/articles/2023-08-10-rss-feed.md
@@ -0,0 +1,38 @@
+---
+tags: software, how-to
+image: 2023-08-10-rss-feed.gif
+---
+
+# Rss Feed
+
+In this article I will show how to add this site's rss feed. In particular, we will be using [NetNewsWire](https://netnewswire.com) as the
+rss reader.
+
+## What is an RSS Feed
+
+An RSS feed will show you new posts, generally from a blog, without having to remember to check the website at regular intervals or signup
+for an email list for notifications.
+
+NetNewsWire puts an RSS feed as:
+
+**It's like podcasts** - but for _reading._
+
+You consume an RSS feed, using an RSS reader application or extension in your browser.
+
+## Step One
+
+First find and download an RSS reader, you can download [NetNewsWire](https://netnewswire.com) for macOS from the link, or for iOS from the
+[AppStore](https://apps.apple.com/us/app/netnewswire-rss-reader/id1480640210).
+
+## Step Two
+
+Add the rss feed to stay up to date when I publish new articles.
+
+1. Click the plus in the right side of the sidebar and select `New Feed...`
+1. In the URL field add: `https://mhoush.com/articles/feed.xml`
+1. Optionally give it a name
+1. Click the `Add` button.
+
+
+
+That's it.
diff --git a/content/articles/2023-09-08-pounds-of-water-removed.md b/content/articles/2023-09-08-pounds-of-water-removed.md
new file mode 100644
index 0000000..bea2f00
--- /dev/null
+++ b/content/articles/2023-09-08-pounds-of-water-removed.md
@@ -0,0 +1,68 @@
+---
+tags: tech-tip, HVAC, formulas, psychrometrics, psychrometric-chart
+---
+
+# Pounds of Water Removed
+
+This is an article that shows how to calculate the pounds of water removed from an air stream, given the entering conditions (return air
+stream) and the outlet conditions (supply air stream).
+
+This is useful in the field when you want to calculate the amount of moisture removed from an air-conditioner or a dehumidifier. This
+article assumes that you have knowledge of a psychrometric chart. If you do not have basic knowledge of the psychrometric chart, then here
+are a couple articles to familiarize yourself.
+
+## Articles
+
+- [Understand Dew-Point](https://hvacrschool.com/understand-dew-point-absolute-moisture-right-side-psych-chart/)
+- [Impact of Adding or Removing Water from Air](https://hvacrschool.com/the-impact-of-adding-or-removing-water-from-air/)
+
+## Scenario
+
+Let's imagine that we have an air-conditioner that has the following measurements taken:
+
+- Return Air: 75° / 50% RH
+- Supply Air: 55° / 81% RH
+
+We plot the two values on the psychrometric chart (black line represents the return air conditions and blue line represents the supply air
+conditions).
+
+
+
+We start by finding the corresponding dry-bulb temperature at the bottom of the chart and draw a straight line up to where it intersects the
+relative humidity curve. After that we draw a straight line to the right side of the psychrometric chart to find the grains of moisture per
+pound of air.
+
+This gives us the following values:
+
+- Return Air: 66 gr/lb
+- Supply Air: 52 gr/lb
+
+We can then use the following formula to calculate the pounds of water removed.
+
+
+
+| **Where** | |
+| ------------ | -------------------------------------------------------- |
+| **W** | _Weight of water in pounds per hour_ |
+| **4.5** | _Constant based on density / specific heat of moist air_ |
+| **CFM** | _Airflow in cubic feet per minute_ |
+| **∆G** | _Difference in grains of moisture_ |
+| **7000** | _Constant based on grains of moisture in saturated air_ |
+
+## Solution
+
+First, we solve for the difference in grains between the two air streams.
+
+∆G = 66 - 52 = 14
+
+Next, we've measured our airflow and have determined to have **797 CFM** of airflow across the evaporator coil, so we can substitute our
+values into the formula.
+
+
+
+So, we are removing about 7 pounds of water per hour at these conditions.
+
+Another thing to note is that 1 pound of water is approximately 1 pint of water, which can be useful when working with dehumidifiers that
+can often be rated in pints per day.
+
+I hope you've found this article helpful, thanks for reading!
diff --git a/content/articles/2023-09-14-why-mini-splits-stink.md b/content/articles/2023-09-14-why-mini-splits-stink.md
new file mode 100644
index 0000000..384e5d7
--- /dev/null
+++ b/content/articles/2023-09-14-why-mini-splits-stink.md
@@ -0,0 +1,66 @@
+---
+tags: HVAC
+---
+
+# Why Mini Splits Stink
+
+In this general article, I explain why I don't generally like to use mini-splits.
+
+## The Positive Sides
+
+When people say mini-splits, in general we mean "ductless" style units. These can either be high wall, floor mounted, or ceiling mounted
+consoles. These units do offer really high efficiency and becuase they're "ductless" you don't have duct gains/losses.
+
+These units are common in many other countries and have been around for a long time. They do are generally quick and fairly easy to install,
+but are mostly a pain in the tail to work on.
+
+So, the plus side to these units are that they are really efficient, they generally have models that have a high-heat output for colder
+climates, although this option is becoming more prevelant in traditional unitary style heat pumps as well. You do not have heat gains or
+losses due to ductwork being in unconditioned spaces.
+
+## The Down Sides
+
+Most mini-split systems do not do the greatest at humidity removal. This is partially because they use proprietary algorithms to control the
+blower and compressor. They do achieve long run-times, which is often good for comfort stand points, however there is generally not a good
+way to control / hack them to work towards achieving good IAQ.
+
+These units offer next to no filtration, so in order to have filtration you need to utilize a stand-alone / portable filtration means. Which
+a lot of the portable filtration systems have problems of their own (come bundled with UV / PCO technology or other "space" technology that
+can lead to their own IAQ problems). It also introduces another fan, which may / may not be that efficient. In other words, when considering
+other items to make them more comparable to what a traditional system offers, are they really that much more efficient?
+
+These systems also do not have a good method of offering basic fresh air control / management, so other systems, such as an ERV need to be
+installed to handle the fresh air requirements of the building.
+
+The controls for these systems are often hard to understand / use. They do allow you to change fan speeds, but they control the compressor.
+The fans often run all the time, which is not necessarily a bad thing, but they don't really offer many ramping profiles or adjustments to
+change the blower speed when the compressor is off vs. on.
+
+These systems get dirty quickly, are generally a pain to clean properly, and are not easily repairable. Manufacturer support is often poor,
+the documents aren't always translated very well, and most technicians hate to work on them.
+
+# What about ducted models?
+
+But what about the ducted models? Well, the ducted models are a step in the right direction. You can use filters on them, although some of
+the manufacturer's do not recommend installing better / improved filter cabinets (like a 4-5" media filter), however we have done that
+successfully many times and always include media filters as an option on our installations, but you do need to make sure that they have a
+very low pressure drop, as they a lot are not designed for very much static pressure.
+
+The ducted models still generally have the same control problems, previously mentioned. If you read my introduction to the
+[coil-bypass-system](https://mhoush.com/posts/coil-bypass-overview/), you have a basic understanding that even most traditional systems /
+designers do not focus on the proper air-changes in a structure to maintain proper IAQ levels.
+
+You can't easily pair mini-splits with larger fan-coils because they are "communicating" style systems.
+
+## Conclusion
+
+Don't get me wrong, there are applications that are well suited for mini-splits. These are often applications like sun-rooms, garages, small
+server-rooms / network storage rooms, and many others. But in my opinion these are not at all my favorite and are generally really far down
+my list of options that I want to recommend to my clients.
+
+As an industry, I feel we need to step back and refocus on the pillars of IAQ. Filtration, fresh-air, and humidity control. The
+manufacturers / government should put less emphasis on chasing efficiency just to shoot ourselves in the foot and loose the qualities that
+make traditional / unitary style systems cover more if not all of the 3 pillars of proper IAQ.
+
+There's plenty that I did not cover and I'm sure I missed some things, but just needed to rant for a few minutes... Thank you for making it
+to the end!
diff --git a/content/articles/2023-09-15-sizing-dehumidifier-by-latent-load.md b/content/articles/2023-09-15-sizing-dehumidifier-by-latent-load.md
new file mode 100644
index 0000000..a935e66
--- /dev/null
+++ b/content/articles/2023-09-15-sizing-dehumidifier-by-latent-load.md
@@ -0,0 +1,48 @@
+---
+tags: tech-tip, HVAC, formulas, design
+---
+
+# Dehumidifier Sizing by Latent Load
+
+This is a quick article to show how to calculate the size of dehumidifier needed based on the latent load of a building. This is useful if
+you've done a load calculation and know the latent load of the structure.
+
+## Formulas
+
+The formula above is used to solve for the pints per hour required to size a dehumidifier.
+
+| Where | |
+| ----- | ------------ |
+| Ql | Latent load |
+| Ph | Pints / hour |
+
+We can then convert to pints per day by multiplying the answer by 24 hours, below is the combined formula.
+
+
+
+| Where | |
+| ----- | ----------- |
+| Ql | Latent load |
+| Pd | Pints / day |
+
+In some cases you may want to size the dehumidifier for less than the full latent load, assuming that the air-conditioner (when sized
+properly) is going to cover the full latent load when at peak design temperatures and that the peak latent period for your area is during
+peak cooling demand.
+
+## Example
+
+Let's imagine we have done a load calculation and have a latent load of 4,334 BTU/h. So, plugging that into our above formula.
+
+
+
+Or if we just want to cover the latent capacity at 85% of the full latent load.
+
+
+
+This gives us some guidance that we would need to select a dehumidifier that is rated for 84-99 pints per day, depending on which condition
+we wanted to use.
+
+I don't feel oversizing a dehumidifier, within reason, is that problematic (or at least it does not come with the same problems as an
+oversized air conditioner), so I would personally go for a 100-120 pint per day model dehumidifier in this application.
+
+Thanks for reading!
diff --git a/content/articles/2023-09-18-introducing-psychrometrics-cli.md b/content/articles/2023-09-18-introducing-psychrometrics-cli.md
new file mode 100644
index 0000000..7dba2a5
--- /dev/null
+++ b/content/articles/2023-09-18-introducing-psychrometrics-cli.md
@@ -0,0 +1,102 @@
+---
+tags: HVAC, psychrometrics, software
+title: "Introducing Psychrometrics Cli"
+---
+
+# Introducing Psychrometrics CLI
+
+Today, I'm releasing a command line application that is built on top of my
+[swift-psychrometrics](https://github.com/swift-psychrometrics/swift-psychrometrics) package, that I open sourced over 2 years ago.
+
+The application consists of many calculations / conversions for psychrometric properties of an air stream. The tool works for both imperial
+and metric units. The application will work natively on macOS, but can also be ran through a `docker` container on other platforms.
+
+## Why
+
+I spend a lot of time in my terminal, because I can work so much more efficiently. I discovered many years ago that the more I can do using
+simple applications and keyboard over a mouse and a web browser or native application the more I can accomplish. I understand this is
+intimidating for many who think they are _"not good with computers"._ I can assure that was me several years ago, I would only encourage you
+to not be afraid and give it a shot. We are at a time in society where it is easier than ever to get informed and learned new skills.
+
+## Installation
+
+For complete installation instructions, you can view the [github](https://github.com/swift-psychrometrics/psychrometrics-cli) repository.
+
+The following instructions are based on using macOS.
+
+### Open your terminal application.
+
+Personally, I use [iTerm2](https://iterm2.com/), however you can use the default `Terminal` app. Found at
+`/Applications/Utilities/Terminal.app`.
+
+## Install Homebrew
+
+We use [Homebrew](https://brew.sh) for package distribution of the pre-built application binaries. You can follow their instructions to
+install.
+
+### Tap our custom formula tap.
+
+```bash
+brew tap swift-psychrometrics/formula
+```
+
+### Install the psychrometrics application
+
+```bash
+brew install psychrometrics
+```
+
+That's it!
+
+## Usage
+
+I will run through a couple of the commands that are supplied with the application and show what you can expect the outputs to be.
+
+### Properties
+
+The following command will output a bunch of the psychrometric properties of an air stream. There are several ways to call it, but generally
+you will supply the dry bulb temperature and the relative humidity.
+
+Below, we calculate the psychrometric properties based on 75°F and 50% humidity.
+
+```bash
+psychrometrics --dry-bulb 75 --relative-humidity 50
+```
+
+
+
+### Dehumidifier Sizing
+
+If you've read some of my recent articles on calculating the
+[dehumidifier size required based on the latent load](https://mhoush.com/posts/sizing-dehumidifier-by-latent-load/), the application also
+ships with a calculation that will do this for you and has the ability to calculate it at different `coverages` that you can supply.
+
+For example if we've done a load calculation and determined that we have a latent load of `4,334 BTU/h` then we could run the following
+command to see what size dehumidifier is needed for `100%, 85%, and 70%` of the latent load.
+
+```bash
+psychrometrics dh size --coverage 100 85 70 --verbose 4334
+```
+
+
+
+### Pounds of Water Removed
+
+I also recently wrote an article about [calculating the pounds of water removed](https://mhoush.com/posts/pounds-of-water-removed/) from an
+air stream given the grains of moisture removed.
+
+Below is an example of calculating the pounds of water removed per hour based on the example in the article (14 delta-grains)
+
+```bash
+psychrometrics dh pounds-removed --delta 14 --cfm 797 --verbose
+```
+
+
+
+### Help
+
+You can use `--help` option to show help and the list of commands provided.
+
+
+
+If you have any questions then feel free to email or message me. I hope some of you may find this application useful.
diff --git a/content/articles/2023-09-21-introduction-to-programming-for-hvac-1.md b/content/articles/2023-09-21-introduction-to-programming-for-hvac-1.md
new file mode 100644
index 0000000..ec6367f
--- /dev/null
+++ b/content/articles/2023-09-21-introduction-to-programming-for-hvac-1.md
@@ -0,0 +1,241 @@
+---
+tags: HVAC, programming, software
+---
+
+# Introduction to Programming for HVAC Part-1
+
+This is part one of a series of articles to help HVAC technicians (or others) get started in developing their skills to program. This can
+help to automate everyday tasks or just familiarize themselves with some of the tools used by programmers.
+
+## Why
+
+I think if nothing else, this series can help gain knowledge, tips, and tricks to make you more comfortable with your computer. I hope that
+you will at least learn how to use your `terminal` application and more specifically `vim` motions and keybindings (more on that in another
+article).
+
+The goal of this article is to just get a machine setup with tools and to start exploring. I am a shill for `macOS`, so all of these will be
+specifically geared towards that and my workflows, most everything that is showcased should also work on `linux` machines (not sure about
+`windows`), although you may have to search for specific instructions on installing software for other platforms.
+
+What I have learned on my journey in programming is that the more you can lean on small software packages that focus on a single task, but
+do them well, the better. The less you use your mouse, the more productive you can be. The more you can work with `text` files and formats
+the more portable and transformable your workflows can be.
+
+## Getting Started
+
+The first thing that we will focus on is becoming familiar with the terminal application. On macOS the terminal application is located at
+`/Applications/Utilities/Terminal.app`. However, rather than click around to find it, you can use the `⌘` to pull up your spotlight
+search, then type `Terminal` to select the terminal application.
+
+
+
+### Terminal Overview
+
+Your terminal is a program that allows you to run programs by typing commands into it's window. There are a lot of built-in commands and a
+bunch that you can install. The terminal is very customizable (and once familiar, you will constantly be tweaking / adjusting to suit your
+needs). Right now customization is not what we will focus on, however in future articles I will provide tips and tricks on customizing it.
+Right now, we only need to know how to open it up and type in commands.
+
+
+
+Below is an image / explanation of what the default status line includes.
+
+
+
+### Learn Basic Commands (Built-in)
+
+Here are a few basic commands that you should familiarize yourself with, as you will use them often when working inside of a terminal.
+
+### Change Directory
+
+`cd` (change directory) is the command that allows you to move around your file system when inside the terminal.
+
+> **Note:** `~` is a representation of your `Home` directory.
+
+```bash
+cd ~/Documents
+```
+
+The above command will move you into your Documents directory.
+
+> **Note:** If there are spaces in the name of the directory you try to move to then the easiest way is to wrap the name in quotes.
+
+```bash
+cd "~/Documents/Product Concepts"
+```
+
+Some other things to understand when moving around / supplying arguments to the `cd` command.
+
+You can use `..` to go backwards / move up to the parent directory. For example, say we are in the `~/Documents` directory, to go back up to
+the home directory we could use the following:
+
+```bash
+cd ..
+```
+
+These can be chained together as well. For example say we are located in the `~/Documents/Product Concepts` directory, we could use the
+following to go up two directory levels back to the home directory.
+
+```bash
+cd ../..
+```
+
+> **Pro-Tip:** You can use the `` key when navigating to auto-complete, generally typing a few characters followed with the `` key
+> will auto-complete for you.
+
+### List files
+
+Use `ls` to output a list of files and directories where you are located.
+
+```bash
+ls
+```
+
+_Example Output when in my ~/Documents directory_
+
+```bash
+Estimates.app
+InkscapeDrawings
+KwikModel
+MyAparment
+NCISummit
+Personal
+Product Concepts
+Receipts.receipts
+RingCentral
+SketchUP
+Tech-Tips
+desktop.ini
+espanso-migrate-backup
+espanso-migrate-backup-2
+```
+
+Using options with `ls` to show more statistics and hidden files. There are often hidden files on your computer that are used for
+application support or other purposes, these files are not shown using the default command. Hidden files start with a `.`, below is an
+example of showing hidden files in your home directory.
+
+```bash
+ls -la ~/
+```
+
+> **Note:** Above I added the `~/` which will allow you to list the files in your home directory even if you currently are not there in your
+> terminal, if you were already there (for example by using `cd ~/` then you would not need to use that at the end of the command.
+
+_Example Output_
+
+```
+total 168
+drwxr-xr-x+ 46 michael staff 1472 Sep 22 10:45 .
+drwxr-xr-x 6 root admin 192 Sep 22 09:08 ..
+-r-------- 1 michael staff 7 Apr 8 2021 .CFUserTextEncoding
+-rw-r--r--@ 1 michael staff 14340 Sep 18 10:15 .DS_Store
+drwx------+ 5 michael staff 160 Sep 20 17:03 .Trash
+-rw-r--r-- 1 michael staff 186 Sep 12 15:20 .actrc
+drwxr-xr-x 4 michael staff 128 Dec 13 2021 .bin
+drwxr-xr-x 3 michael staff 96 Mar 6 2023 .bundle
+drwxr-xr-x 7 michael staff 224 Sep 12 11:40 .cabal
+drwxr-xr-x 7 michael staff 224 Sep 12 15:20 .cache
+drwxr-xr-x 13 michael staff 416 Aug 10 08:47 .config
+drwx------ 3 michael staff 96 Jun 21 2021 .cups
+drwxr-xr-x 12 michael staff 384 Sep 15 15:22 .docker
+drwxr-xr-x 20 michael staff 640 Sep 19 08:11 .dotfiles
+drwxr-xr-x 4 michael staff 128 Jul 26 2021 .gem
+drwxr-xr-x 3 michael staff 96 Oct 11 2021 .jssc
+-rw------- 1 michael staff 20 Sep 22 10:45 .lesshst
+drwxr-x--- 3 michael staff 96 Mar 29 08:47 .lldb
+drwxr-xr-x 8 michael staff 256 Mar 1 2023 .local
+drwxr-xr-x 4 root staff 128 Apr 12 2021 .newtek
+drwxr-xr-x 5 michael staff 160 Dec 13 2021 .npm
+-rw------- 1 michael staff 27436 Apr 10 10:21 .psql_history
+drwxr-xr-x 7 michael staff 224 Apr 18 2022 .ssh
+drwxr-xr-x 6 michael staff 192 Sep 21 09:06 .swiftpm
+lrwxr-xr-x 1 michael staff 25 Dec 27 2021 .tmux.conf -> .dotfiles/tmux/.tmux.conf
+drwxr-xr-x 8 michael staff 256 Mar 27 16:14 .twilio-cli
+drwxr-xr-x 6 michael staff 192 Sep 18 11:08 .vim
+-rw------- 1 michael staff 23086 Sep 21 09:45 .viminfo
+-rw-r--r-- 1 michael staff 254 Sep 21 09:32 .wget-hsts
+lrwxr-xr-x 1 michael staff 43 Jan 3 2022 .zshenv -> /Users/michael/.dotfiles/zsh/config/.zshenv
+drwxr-xr-x 8 michael staff 256 Dec 14 2021 AmazonWorkDocsCompanion
+drwx------@ 4 michael staff 128 Dec 13 2021 Applications
+lrwxr-xr-x 1 michael staff 40 Jun 6 12:00 Applications (Parallels) -> /Volumes/Bucket/Applications (Parallels)
+drwx------@ 30 michael staff 960 Sep 21 08:54 Desktop
+drwx------@ 19 michael staff 608 Sep 14 10:15 Documents
+drwx------@ 21 michael staff 672 Sep 21 09:43 Downloads
+drwx------+ 115 michael staff 3680 Sep 14 10:04 Library
+drwxr-xr-x 3 michael staff 96 Sep 8 13:06 LocalProjects
+lrwxr-xr-x 1 michael staff 29 Dec 30 2021 Movies -> /Volumes/Bucket/Videos/Movies
+lrwxr-xr-x 1 michael staff 21 Dec 30 2021 Music -> /Volumes/Bucket/Music
+drwx------@ 2 michael staff 64 Mar 6 2023 Parallels
+drwx------@ 7 michael staff 224 Sep 14 09:52 Pictures
+drwxr-x---+ 4 michael staff 128 Apr 8 2021 Public
+drwxr-xr-x+ 3 michael staff 96 Sep 14 09:52 Sites
+drwxr-xr-x 3 michael staff 96 Jun 7 2021 WorkDocs Drive
+drwxr-xr-x 3 michael staff 96 Sep 18 11:36 go
+```
+
+As you can see, I have a lot of hidden files and folders, your output will probably look much different than mine.
+
+### Clearing the Terminal
+
+Often times you may want to clear the terminal screen. You can use the `clear` command to clear the screen of the terminal.
+
+```bash
+clear
+```
+
+Or use a keyboard shortcut `⌃l` (`l`)
+
+### Creating Directories
+
+Use `mkdir` (make directory) to create a directory.
+
+First, let's move into the `tmp` directory, the `tmp` directory is a directory on your file system that is typically used for applications
+to write temporary logs / files to, it get's erased everytime your computer is restarted. We can use the `cd` command that we learned
+earlier.
+
+```bash
+cd /tmp
+```
+
+Next, let's create a new directory called "MyDirectory".
+
+```bash
+mkdir MyDirectory
+```
+
+#### Gotcha's with 'mkdir'
+
+By default you can't create directories that are multiple levels deep, unless the directories already existed or we provide the `-p` option.
+For example, if we want to create a directory at `/tmp/MyOtherDirectory/Nested/Deeply` then we could use the following command when inside
+the `tmp` directory.
+
+```bash
+mkdir -p MyOtherDirectory/Nested/Deeply
+```
+
+Now, try out using the `` key with the `cd` command to navigate to the `Deeply` folder.
+
+```bash
+cd MyOther
+```
+
+### Open Command
+
+You can use the open command to open files or folders in the default application for the file type.
+
+For example, if we want to open a `Finder` window while in the `/tmp` directory, we can use the following command:
+
+```bash
+open .
+```
+
+### Manual Pages
+
+Lastly, to learn more about commands you can use the `man `. To bring up the manual pages for the command in the terminal. You can
+use the arrow keys to navigate around the manual pages and type the letter `q` to quit / close the manual pages.
+
+```bash
+man ls
+```
+
+That is it for the first installment in this series. I hope you learned something and have better understanding of using your terminal.
diff --git a/content/articles/2023-09-22-introduction-to-programming-for-hvac-2.md b/content/articles/2023-09-22-introduction-to-programming-for-hvac-2.md
new file mode 100644
index 0000000..383c211
--- /dev/null
+++ b/content/articles/2023-09-22-introduction-to-programming-for-hvac-2.md
@@ -0,0 +1,109 @@
+---
+tags: HVAC, programming, software
+title: "Introduction to Programming for HVAC Part-2"
+---
+
+# Introduction to Programming for HVAC Part-2
+
+In this article, learn about installing a package manager. If you missed it, check out the
+[first](https://mhoush.com/posts/introduction-to-programming-for-hvac-1/) article in the series where we learned about using your terminal.
+This article builds upon that foundation.
+
+## What is a Package Manager
+
+A package manager is a piece of software that helps to install software and manage updates for your system. For me, the first thing that I
+do with a new machine is install `Homebrew`. [Homebrew](https://brew.sh) is my preferred package manager for `macOS`.
+
+## Why
+
+A package manager is nice because often software relies / requires other dependencies in order to work properly. By using a package manager
+it will make sure that the correct dependencies are installed for the software that you need to run. It allows you to be able to update and
+manage software through a centralized interface.
+
+## Installation
+
+Installation is simple. Open up your terminal and enter the following command (easiest to just copy / paste from the homepage linked above).
+
+```bash
+/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
+```
+
+This will prompt you for your password in order to create some directories and install the required software for `brew` to work. The
+installation may take some time, while it downloads the command line tools for `Xcode`.
+
+When completed, follow the `Next Steps` and copy / paste the command listed, that should look like below.
+
+```bash
+(echo; echo 'eval "$(/opt/homebrew/bin/brew shellenv)"') >> /Users//.zprofile
+eval "$(/opt/homebrew/bin/brew shellenv)"
+```
+
+
+
+The first line of this command sets up some things in your shell profile (which we have not discussed yet) that will make `Homebrew`
+available to you anytime you start a new session in your terminal. The second line of the command makes it available in your current
+terminal session.
+
+Next run the following command and make sure that everything is setup correctly.
+
+```bash
+brew doctor
+```
+
+Which should output the following:
+
+```
+Your system is ready to brew.
+```
+
+### Terminology
+
+Homebrew calls command line applications `formula` and normal graphical applications `casks`. It has the ability to install both styles of
+applications.
+
+## Search Command
+
+The following command is used to search for software packages:
+
+```bash
+brew search chrome
+```
+
+## Open a Homepage
+
+The following command can be used to view the homepage of a formula or cask in your browser:
+
+```bash
+brew home google-chrome
+```
+
+## Update Homebrew
+
+The following command is used to update homebrew:
+
+```bash
+brew update
+```
+
+## Update packages installed on your system
+
+The following command is used to update software that is installed / managed by homebrew.
+
+```bash
+brew upgrade
+```
+
+You can combine the update and upgrade commands, which will update homebrew and upgrade all the software it manages on you machine with the
+following command.
+
+```bash
+brew update && brew upgrade
+```
+
+## Conclusion
+
+That is it for this article. I will say that for me, when I find a piece of software that I want to use, I generally try to search for it in
+`brew` first, before installing it via other means.
+
+I hope you've found this article helpful. In the next article we will start to use the skills that we've learned in these first two articles
+and write our first program / script.
diff --git a/content/articles/2023-09-24-introduction-to-programming-for-hvac-3.md b/content/articles/2023-09-24-introduction-to-programming-for-hvac-3.md
new file mode 100644
index 0000000..9887ab5
--- /dev/null
+++ b/content/articles/2023-09-24-introduction-to-programming-for-hvac-3.md
@@ -0,0 +1,125 @@
+---
+tags: HVAC, programming, software
+---
+
+# Introduction to Programming for HVAC Part-3
+
+In this article we will put together some of the pieces from the last 2 articles, and build our first program. If you have missed the first
+articles, then you can catch up [here](https://mhoush.com/series/programming-for-hvac/) before continuing with this article.
+
+## Getting Started
+
+We are going to make our first script / program. This first program is really just setting up some building blocks for our next program we
+will write, that will remove the background from an image.
+
+### Creating a scripts directory
+
+We learned in the [first article](https://mhoush.com/posts/introduction-to-programming-for-hvac-1/) how to use our terminal. Today we are
+going to use some of the commands we learned to create a directory where we can store our script and future scripts that we write.
+
+**Create a directory**
+
+```bash
+mkdir -p ~/.local/bin
+```
+
+The above command will create a "hidden" directory in your home folder. We can go ahead and move into the directory we just created.
+
+> **Note:** The `-p` option allows us to create nested directories if the parent directory doesn't exist.
+
+```bash
+cd ~/.local/bin
+```
+
+### Hello World
+
+It is common in programming to start out with a "Hello World" program when learning a new scripting paradigm. So let's jump in and get
+started.
+
+**Creating our script file:**
+
+```bash
+touch hello-world.sh
+```
+
+**Now open the file:**
+
+```bash
+open hello-world.sh
+```
+
+The above command should open the file in the `TextEdit` application. In order to make the text edit application to not auto-capitalize
+words and play more nicely, we need to adjust some settings. Open the settings by pressing `⌘,`.
+
+In the **Format** section, select _Plain text_ and in the **Options** section de-select _Check spelling as you type_.
+
+
+
+At this point for changes to take place, you will need to close the file and re-open.
+
+> **Tip:** In your terminal you can run the last command in your history by using the `↑` (Up) arrow key.
+
+Now that the file is open again, we will write our hello-world program. The contents of your file should look like the following:
+
+```bash
+#!/bin/sh
+
+echo 'Hello World!'
+```
+
+The first line is referred to as the `shebang`, this tells your computer which shell interperter to run your file. I have not explained the
+shell yet, but it currently would just muddy the waters a bit, but there are several shell interperters on your computer with the `sh` posix
+shell being one of the most universal / lowest level ones, which is why I'm choosing this one (in other words this script would work on just
+about any machine you were on).
+
+The second line we are using the built-in `echo` command and passing it the 'Hello World!' argument.
+
+Now save and close the file `⌘s` (to save) `⌘q` (to quit the text edit application).
+
+**Run the program from your terminal:**
+
+```bash
+/bin/sh hello-world.sh
+```
+
+You should see that `Hello World!` was printed to your console.
+
+
+
+### Make Executable
+
+Now that we have our basic script working, let's make it an executable.
+
+**In your terminal, type the following:**
+
+```bash
+chmod u+x hello-world.sh
+```
+
+This will change the mode of the file type to be an executable.
+
+Now move / rename the file so we don't have to call it using `.sh` extension:
+
+```bash
+mv hello-world.sh hello-world
+```
+
+Now that the file is executable, we can execute it by just calling the name of the file.
+
+```bash
+./hello-world
+```
+
+> **Note:** We have to prefix the file name with `./` in the above command so that it knows where to find our file. The `./` is saying run
+> this file in our current directory. In the future we will setup our shell so that it knows to look in our `~/.local/bin` directory for
+> scripts, so that we can call them without this prefix.
+
+## Conclusion
+
+Congratulations, in this article we wrote our first program. We learned how to edit the file, set it's permissions, and execute the program
+from our terminal. I should mention that the `TextEdit` application is generally not how you would program, people typically use what is
+known as an `IDE (integrated development environment)`, however I chose to use the `TextEdit` application because it is built-in to `macOS`
+and allowed us to accomplish our goal without downloading other software.
+
+In our upcoming articles, we will write a program that I hope is useful to you / something that you can build upon and use for a long time.
+Thank you for reading to this point.
diff --git a/content/articles/2023-09-26-introduction-to-programming-for-hvac-4.md b/content/articles/2023-09-26-introduction-to-programming-for-hvac-4.md
new file mode 100644
index 0000000..a933112
--- /dev/null
+++ b/content/articles/2023-09-26-introduction-to-programming-for-hvac-4.md
@@ -0,0 +1,205 @@
+---
+tags: HVAC, programming, software
+---
+
+# Introduction to Programming for HVAC Part-4
+
+This article builds upon our [last](https://mhoush.com/posts/introduction-to-programming-for-hvac-3/) article, so make sure to catch up
+before continuing with this article.
+
+## Arguments
+
+Before we start creating our program that will remove the background from images let's go over arguments in shell scripts. Arguments are
+supplied to shell scripts are separated by a space `" "`, as opposed to options which start with a `-` or `--`.
+
+To illustrate this, let's change our `hello-world` script we wrote in the last article.
+
+**Move into our scripts directory:**
+
+```bash
+cd ~/.local/bin
+```
+
+**Make a copy of the hello-world script:**
+
+```bash
+cp hello-world greet
+```
+
+Above we make a copy of the hello-world file and name the copy `greet`.
+
+**Open the greet file:**
+
+```bash
+open -a TextEdit greet
+```
+
+> **Note:** Because the greet file is an executable, in order to open it in the `TextEdit` application we must supply the `-a` option.
+> Otherwise it will just run our `greet` program in another terminal. Use `man open` to read more about the open command.
+
+**Edit the greet file:**
+
+```bash
+#!/bin/sh
+
+echo "Hello, ${1}!"
+```
+
+Make sure to save `⌘s` the file.
+
+Take note that the quotes need to be changed to `"` (double quotes) from our original `hello-world` program.
+
+The `${1}` is indicating that we will insert / interpret the first argument passed to our program and insert it at that location. Arguments
+are interpreted in order they are passed in with `${0}` always representing the filename of the program that is called (generally not needed
+/ used in your scripts).
+
+**Test it out:**
+
+```bash
+./greet Michael
+```
+
+
+
+If you'd like to supply multiple words (or arguments that contain spaces) as a single argument then you can wrap them in quotes.
+
+```bash
+./greet "Michael Housh"
+```
+
+> **Tip:** Wrapping in quotes is especially useful for commands that take file paths, if any of the folders or file names contain spaces.
+
+## More Useful Program
+
+At this point, it's time to build a more useful program that we can use. First, we must download some dependencies for our program.
+
+**Install imagemagick:**
+
+```bash
+brew install imagemagick
+```
+
+> **Note:** If you'd like to check out the documentation / website for imagemagick you can run `brew home imagemagick`.
+
+This will take a bit for brew to install imagemagick and it's dependencies. When it's completed, we can check to make sure that imagemagick
+is installed by running the following command.
+
+```bash
+magick --version
+```
+
+It should output something along the lines of this below.
+
+```bash
+Version: ImageMagick 7.1.1-17 Q16-HDRI aarch64 21569 https://imagemagick.org
+Copyright: (C) 1999 ImageMagick Studio LLC
+License: https://imagemagick.org/script/license.php
+Features: Cipher DPC HDRI Modules OpenMP(5.0)
+Delegates (built-in): bzlib fontconfig freetype gslib heic jng jp2 jpeg jxl lcms lqr ltdl lzma openexr png ps raw tiff webp xml zlib
+Compiler: gcc (4.2)
+```
+
+> **Tip:** Don't forget, you can use the `clear` command to clear the terminal.
+
+**Create our script:**
+
+```bash
+touch mktrans
+```
+
+We are going to name our script `mktrans` as a short for make transparent.
+
+**Open the file:**
+
+```bash
+open mktrans
+```
+
+**The program:**
+
+```bash
+#!/bin/bash
+
+# The input file path, passed in as the first argument.
+inputfile="${1}"
+
+# The color to make transparent, optionally passed in as the second argument.
+# by default we handle / make white backgrounds transparent.
+color="${2:-white}"
+
+# Use the built-in basename command to normalize the input file name
+# this will convert a file path, such as ~/Pictures/my-image.png to my-image.png.
+fullfilename=$(basename -- "$inputfile")
+
+# Use the text of the `fullfilename` up to the first '.' as the file name.
+filename="${fullfilename%%.*}"
+
+# Use the text after the last '.' as the file extension.
+extension="${fullfilename##*.}"
+
+# Create the output file name to use.
+#
+# For an input file of `input.png`, our output name would be
+# `input-transparent.png`.
+#
+# This will output the file in the directory that we are
+# in when we use our script (which may different than where
+# the image is located)
+outputfile="${filename}-transparent.${extension}"
+
+# Make the magick happen :)
+convert "${inputfile}" -fuzz 10% -transparent "${color}" "${outputfile}"
+
+```
+
+I've included comments in the program above, which is good practice, as there is high odds that you will forget what is going on when / if
+you open the file up in the future to look at it. We are using a lot of what is called parameter expansion magic in this file. You can read
+up more on what we are doing in the [bash documentation](https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html).
+
+This script is far from perfect, there are a lot of things to be improved upon. For example, if you download / save the banner image of this
+post and run this script, it will also remove some color in the wizards beard, eyes, and eye brows. However, it does work very well for my
+general use case, which is to remove the background from screenshots of pdf documents. It should be noted that it will not work on all types
+of images, some image types do not allow transparency, so it is safest to call this with input image being a `.png` image type, however you
+can use the `imagemagick` program that we downloaded to convert other image types to `.png`, but that will be left up to you to figure out.
+
+## Using Our Program
+
+This is going to assume that you have download the banner image at the top of this article. You can do this by right-clicking and choosing
+`Save As`. This should save the image in your downloads folder, and you can keep the name of `part4-banner.png`.
+
+**Make the program executable:**
+
+```bash
+chmod u+x mktrans
+```
+
+**Make the image background transparent:**
+
+```bash
+./mktrans ~/Downloads/part4-banner.png
+```
+
+**Open the image:**
+
+```bash
+open part4-banner-transparent.png
+```
+
+It should look like below.
+
+
+
+> **Note:** If you are viewing this site in _light_ mode, the image does not look that bad. Hit the moon button in the top above my profile
+> image to see some of the flaws of our program.
+
+---
+
+> **Tip:** Remove the image from the `~/.local/bin` by using `rm part4-banner-transparent.png`. Be aware that the `rm` command can not be
+> undone, so use with caution / knowledge. It is safer, until you are more comfortable to use the `Finder` application and move the file to
+> the trash. In `Finder`, you can show hidden directories by typing `⌘.` or go directly to the folder by typing `⇧⌘G` (shift + command + G)
+> and in the pop-up typing `~/.local/bin`.
+
+---
+
+That is it for this article. In the upcoming articles we will setup our `shell` environment so that we can use the commands we've built
+without having to navigate to the `~/.local/bin` directory. Thank you for reading to the end, I hope you're finding this series helpful.
diff --git a/content/articles/2023-10-04-free-quotes-are-bad-for-the-industry.md b/content/articles/2023-10-04-free-quotes-are-bad-for-the-industry.md
new file mode 100644
index 0000000..61c6c96
--- /dev/null
+++ b/content/articles/2023-10-04-free-quotes-are-bad-for-the-industry.md
@@ -0,0 +1,103 @@
+---
+tags: HVAC
+---
+
+# Free quotes != good
+
+I found myself re-reading the
+[ACCA Quality Installation Standard](https://www.acca.org/communities/community-home/librarydocuments/viewdocument?DocumentKey=b1d2a39d-fda8-4af9-b8de-0ae579bfe24a)
+recently and it got me thinking about the industries tendency of offering free quotes. In this article, I'd like to just focus in on the
+items that are required as what I'm calling "prior to installation" items.
+
+## Prior to installation
+
+1. Ensure ventilation calculations are performed.
+1. Building heat gain / loss calculation (Manual-J / Manual-N)
+ 1. Room x room for new construction or duct modifications.
+ 1. Block load for existing (can use original if available).
+1. Proper equipment capacity selection (Manual-S / Manual-CS)
+1. Properly matched systems (AHRI or CEE-AHRI)
+
+Let's break the above items down to a rough estimated time to complete each of the items.
+
+| Item | Time (minutes) |
+| ----------------------------------- | -------------- |
+| Ventilation calculations | 15 |
+| Manual-J (data gathering) | 30 |
+| Manual-J (data entry / calculation) | 30 |
+| Manual-S | 15 |
+| AHRI | 15 |
+| **Total** | 105 |
+
+> _The above items are obviously just estimations and the person's experience in the different areas / tools they use. Some of the items are
+> probably on the low side while others are probably on the high side._
+
+This is 1.75 hours just to do the calculations required to meet the QI Standard. This does not include any of the time spent with the
+customer building value in you or your product recommendations.
+
+When you want to not guess at some of the calculations then a blower door test is generally required in order to understand the leakage of
+the home, which adds even more time to the estimation process. Depending on the understanding you are looking for, the blower door test can
+add 30-180 minutes. This takes the total time to 2.25-4.75 hours.
+
+## Pushing boxes
+
+The majority of residential HVAC companies make the bulk of their income off of equipment sales, so they have to "feed the beast" by
+skipping steps in both the installation of equipment and the sales process in order to close jobs and keep the ship afloat.
+
+
+
+This has helped contribute to these industry statistics:[^1]
+
+- **Incorrect refrigerant charge in greater than 50-80% of systems.**
+- **Improper airflow:**
+ - **70% above the rated 0.5" w.c.**
+ - **47% above 0.7" w.c.**
+ - **85% undersized / inappropriate filter.**
+- **70-80% of systems have at least one fault.**
+- **90-100% if duct leakage is considered.**
+
+## Consumer responsibility
+
+Let me be clear, I don't think that all the blame is on the industry here. The culture today is that everyone wants things for free and
+fast. They have been conditioned by online services and box stores. Should we not cater to those that aren't willing to do their leg work?
+Is it really our fault, if they don't care?
+
+## Liability
+
+While it's generally easy to shrug our shoulders and think that it's ok to just continue on because all the competitors are doing the same
+thing. There is at least the possibility that skipping steps can come back to bite you. If things ever went to litigation and the steps
+outlined in the QI Standard are ignored, then there is high odds you would loose.
+
+No matter what you do to try and protect yourself (having customers sign-off, etc) does not adequately protect your company from litigation.
+There are stories out there where contractors were still held liable for not performing load calculations even though the consumer signed
+off on it, because it is not inline with "industry best practices."
+
+# Summary
+
+This has led me to the conclusion that free quotes are just bad for the industry in general. The path forward is a challenge (changing
+perception is hard). I don't know that I have answers on what the best path forward is, to be frank, but I do know that our current _status
+quo_ is subpar to say the least.
+
+Unfortunately, I don't think the change is going to come from the industry, but that it's going to require the consumer base to be more
+educated and demand more from the industry. There have been many organizations that have dedicated years to changing the skill levels of
+technicians in the industry, they are very well needed / don't mistake my words here, however unless a company has faced litigation or
+facing requests on a regular basis that demand better results, then why would a company change!?!
+
+I've been trying (unsuccessfully) to get rid of free quotes for 5+ years in my company. We try to educate customers during maintenance
+visits and when scheduling equipment estimates, however only about 10-20% choose to go down our paid Home Performance Assessment path. Our
+installation process does follow the QI Standard for the items that pertain to the setup / commissioning of the installed equipment, however
+there is just no sustainable way for us to completely follow the items outlined in this article without charging for our time, because at
+the end of the day we still have to be competitive in our market.
+
+There are days that I can justify our actions to myself and also days that I just want to throw in the towel / not sacrifice our integrity.
+Integrity is something that I take very seriously, after all our companies tag line is _"Since 1954, Integrity is in the Housh!"_
+
+As mentioned, I'm not sure what the best path forward is! I hate to not have answers, but some problems are just complex and somewhat beyond
+our control.
+
+Let me know what you think some good solutions are.
+
+- Does your company follow the QI Standard?
+- What are resources that you've found helpful in educating your customers?
+
+[^1]: DOE (2018)
diff --git a/content/articles/2025-01-05-vapor-htmx-todo-app.md b/content/articles/2025-01-05-vapor-htmx-todo-app.md
index d8c9693..9fc6acd 100644
--- a/content/articles/2025-01-05-vapor-htmx-todo-app.md
+++ b/content/articles/2025-01-05-vapor-htmx-todo-app.md
@@ -7,8 +7,8 @@ summary: Build an example application using Vapor and HTMX.
## Introduction
-This post is a quick example of creating a very basic todo web application using `Vapor` a swift web
-framework and `Htmx`, with no custom javascript required.
+This post is a quick example of creating a very basic todo web application using `Vapor` a swift web framework and `Htmx`, with no custom
+javascript required.
[Vapor](https://docs.vapor.codes)
@@ -30,9 +30,8 @@ Next, generate the project using the vapor command-line tool.
vapor new todo-htmx --fluent.db sqlite --leaf
```
-The above command will generate a new project that uses an `SQLite` database along with vapor's
-`Leaf` templating engine. You can move into the project directory and browse around the files that
-are generated.
+The above command will generate a new project that uses an `SQLite` database along with vapor's `Leaf` templating engine. You can move into
+the project directory and browse around the files that are generated.
```bash
cd todo-htmx
@@ -40,8 +39,8 @@ cd todo-htmx
## Update the Controller
-Open the `Sources/App/Controllers/TodoController.swift` file. This file handles the api routes for
-our `Todo` database model. Personally I like to prefix these routes with `api`.
+Open the `Sources/App/Controllers/TodoController.swift` file. This file handles the api routes for our `Todo` database model. Personally I
+like to prefix these routes with `api`.
Update the first line in the `boot(routes: RoutesBuilder)` function to look like this.
@@ -49,14 +48,13 @@ Update the first line in the `boot(routes: RoutesBuilder)` function to look like
let todos = routes.grouped("api", "todos")
```
-Everything else can stay the same. This changes these routes to be exposed at
-`http://localhost:8080/api/todos`, which will allow our routes that return html views to be able to
-be exposed at `http://localhost:8080/todos`.
+Everything else can stay the same. This changes these routes to be exposed at `http://localhost:8080/api/todos`, which will allow our routes
+that return html views to be able to be exposed at `http://localhost:8080/todos`.
## Update the Todo Model
-A todo is not very valuable without a way to tell if it needs to be completed or not. So, let's add
-a field to our database model (`Sources/App/Models/Todo.swift`).
+A todo is not very valuable without a way to tell if it needs to be completed or not. So, let's add a field to our database model
+(`Sources/App/Models/Todo.swift`).
Update the file to include the following:
@@ -97,8 +95,7 @@ final class Todo: Model, @unchecked Sendable {
}
```
-Since we added a field to our database model, we also need to update the migration file
-(`Sources/App/Migrations/CreateTodo.swift`).
+Since we added a field to our database model, we also need to update the migration file (`Sources/App/Migrations/CreateTodo.swift`).
```swift
import Fluent
@@ -118,13 +115,12 @@ struct CreateTodo: AsyncMigration {
}
```
-This just adds our new field to the database schema when we run the migrations, which we will do
-later on in the tutorial.
+This just adds our new field to the database schema when we run the migrations, which we will do later on in the tutorial.
### Update the Data Transfer Object
-We also need to add the `complete` field to our data transfer object (`DTO`). This model is used as
-an intermediate between our database and the user.
+We also need to add the `complete` field to our data transfer object (`DTO`). This model is used as an intermediate between our database and
+the user.
```swift
import Fluent
@@ -150,11 +146,9 @@ struct TodoDTO: Content {
## Generate the View Templates
-Our index template was already generated at `Resources/Views/index.leaf`, open the file and edit the
-contents to match the following.
+Our index template was already generated at `Resources/Views/index.leaf`, open the file and edit the contents to match the following.
-> Note: You can learn more about the
-> [leaf templating engine here.](https://docs.vapor.codes/leaf/getting-started/)
+> Note: You can learn more about the [leaf templating engine here.](https://docs.vapor.codes/leaf/getting-started/)
```html
@@ -182,18 +176,15 @@ contents to match the following.