~jcc/hugo-site

3bb806fd33210b3276efe88f5345190025f1928d — Jason Cox 7 months ago bdcf53d
Use better image compression

Turns out jpeg is way smaller than png, and webp is even smaller. Make
images page resources in order to make auto-process them rather than
converting manually.
45 files changed, 67 insertions(+), 65 deletions(-)

M TODO.md
M assets/css/style.css
M build/hash-links
M content/_index.md
R static/images/atreus-unreachable-keys.png => content/blog/atreus-review/atreus-unreachable-keys.png
R content/blog/{atreus-review.md => atreus-review/index.md}
R static/images/my-atreus.png => content/blog/atreus-review/my-atreus.png
R static/images/banned-by-acm.png => content/blog/blocked-by-acm/banned-by-acm.png
R content/blog/{blocked-by-acm.md => blocked-by-acm/index.md}
R static/images/intentional-tech/bag.jpg => content/blog/my-journey-towards-intentional-technology-use/bag.jpg
R static/images/intentional-tech/books.png => content/blog/my-journey-towards-intentional-technology-use/books.png
R content/blog/{my-journey-towards-intentional-technology-use.md => my-journey-towards-intentional-technology-use/index.md}
R static/images/intentional-tech/pdas.jpg => content/blog/my-journey-towards-intentional-technology-use/pdas.jpg
R static/images/fcc-cognizable-challenge/full.svg => content/blog/what-does-it-take-fcc-challenge/full.svg
R static/images/fcc-cognizable-challenge/geo-3-accessible.png => content/blog/what-does-it-take-fcc-challenge/geo-3-accessible.png
R static/images/fcc-cognizable-challenge/geo-all-accessible.png => content/blog/what-does-it-take-fcc-challenge/geo-all-accessible.png
R static/images/fcc-cognizable-challenge/h3-hex-nesting.svg => content/blog/what-does-it-take-fcc-challenge/h3-hex-nesting.svg
M content/blog/what-does-it-take-fcc-challenge/index.md
R static/images/fcc-cognizable-challenge/overview.svg => content/blog/what-does-it-take-fcc-challenge/overview.svg
R static/images/fcc-cognizable-challenge/test-criteria.svg => content/blog/what-does-it-take-fcc-challenge/test-criteria.svg
R static/images/fcc-cognizable-challenge/tests-clustered.png => content/blog/what-does-it-take-fcc-challenge/tests-clustered.png
R static/images/fcc-cognizable-challenge/tests-spread.png => content/blog/what-does-it-take-fcc-challenge/tests-spread.png
R static/images/fcc-cognizable-challenge/threshold-geo.svg => content/blog/what-does-it-take-fcc-challenge/threshold-geo.svg
R static/images/fcc-cognizable-challenge/threshold-tests.svg => content/blog/what-does-it-take-fcc-challenge/threshold-tests.svg
R static/images/fcc-cognizable-challenge/threshold-time.svg => content/blog/what-does-it-take-fcc-challenge/threshold-time.svg
R static/images/kyria-stand/bottom.jpg => content/creations/kyria-vertical-stand-case/bottom.jpg
R static/images/kyria-stand/full.jpg => content/creations/kyria-vertical-stand-case/full.jpg
R content/creations/{kyria-vertical-stand-case.md => kyria-vertical-stand-case/index.md}
R static/images/kyria-stand/open.jpg => content/creations/kyria-vertical-stand-case/open.jpg
R static/images/kyria-stand/velcro.jpg => content/creations/kyria-vertical-stand-case/velcro.jpg
R static/images/kyria/full-front.jpg => content/creations/kyria/full-front.jpg
R static/images/kyria/full-top.jpg => content/creations/kyria/full-top.jpg
R content/creations/{kyria.md => kyria/index.md}
R static/images/kyria/led-wire.jpg => content/creations/kyria/led-wire.jpg
R static/images/kyria/right-side.jpg => content/creations/kyria/right-side.jpg
R static/images/kyria/side-no-switches.jpg => content/creations/kyria/side-no-switches.jpg
R content/creations/{vim-sway-nav.md => vim-sway-nav/index.md}
R static/images/vim-sway-nav-demo.gif => content/creations/vim-sway-nav/vim-sway-nav-demo.gif
R static/images/headshot.png => content/headshot.png
M content/style.css
A layouts/shortcodes/figure.html
A layouts/shortcodes/picture.html
D static/images/cell-watch-large.png
D static/images/logo.png
D static/images/measurement-planning-methodology-large.png
M TODO.md => TODO.md +0 -1
@@ 1,4 1,3 @@
# To-do

- [ ] use image processing to convert images to webp, with fallback (https://gohugo.io/content-management/image-processing/)
- [ ] use `<time>` element

M assets/css/style.css => assets/css/style.css +5 -5
@@ 101,7 101,7 @@ a:hover {
  background: var(--color-link-bg);
}

img, figure {
img, picture, figure {
  display: block;
  margin: 2rem auto;
  max-width: 100%;


@@ 111,12 111,12 @@ img {
  width: auto;
}

figure {
  width: fit-content;
picture img, figure img, figure picture {
  margin: 0 auto;
}

figure img {
  margin: 0rem auto;
figure {
  width: fit-content;
}

figcaption {

M build/hash-links => build/hash-links +1 -1
@@ 68,7 68,7 @@ process_file() {
    file_dir="$(dirname "$file")"

    # replace links in HTML src or href attributes
    grep -Eo '(src|href)=("[^"]+"|'"'"'[^'"'"']+'"'"'|[^ >]+)' "$file" | while read -r match; do
    grep -Eo '(src|href|srcset)=("[^"]+"|'"'"'[^'"'"']+'"'"'|[^ >]+)' "$file" | while read -r match; do
        if [ "${match%\?*}" != "$match" ]; then
            continue
        fi

M content/_index.md => content/_index.md +1 -1
@@ 3,7 3,7 @@ title: Home
---

<div id="photo-greeting">
  <img alt="" width="128" src="/images/headshot.png">
  {{< picture src="headshot.png" alt="" width="128" >}}
  <p><strong>Hi, I’m Jason</strong>. I’m a computer science Master's student, software engineer, bookworm, keyboard nerd, aspiring small business owner, and open source enthusiast. Welcome to my personal website!</p>
</div>


R static/images/atreus-unreachable-keys.png => content/blog/atreus-review/atreus-unreachable-keys.png +0 -0
R content/blog/atreus-review.md => content/blog/atreus-review/index.md +2 -2
@@ 6,7 6,7 @@ summary: I bought a Keyboardio Atreus in early 2021 -- here are my thoughts on i

I bought a [Keyboardio Atreus](https://shop.keyboard.io/products/keyboardio-atreus) in early 2021, and overall I've been quite happy with it. I purchased the bare-bones version (no switches or key caps) and got Kailh Silent Box Brown switches (from Keyboardio) as well as a set of [blank, Cherry profile key caps](https://kbdfans.com/products/epbt-pbt-blank-ortholinear-keycaps). I also threw in Keyboardio's switch and key cap pullers. Including shipping, I paid $190 for all of it.

![my Atreus](/images/my-atreus.png)
{{< picture src="my-atreus.png" alt="my Atreus" >}}

## My keyboard background



@@ 40,7 40,7 @@ I think it makes sense to start my review of an enthusiast keyboard by saying th

- **I can't *really* reach all of the keys comfortably.** One of the Atreus's big selling points is that all the keys are easy to reach without moving your hands, but I haven't found that to be entirely true. The top key on the pinky column is definitely a stretch -- that whole column feels too high, really. The outer three keys on the bottom row on each side aren't especially comfortable, either; my fingers have to curl too much to reach them. And I really can't figure out a good way to press the two middle keys on the second lowest row. Since comfort is high on my list of priorities, I only use the 34 remaining keys. (I'd also love for the inner most thumb keys to be farther down to match the downward arc my thumb makes when I extend it outward, but I do still use those keys anyway.)

  ![Atreus layout with sad faces on hard-to-reach keys](/images/atreus-unreachable-keys.png)
  {{< picture src="atreus-unreachable-keys.png" alt="Atreus layout with sad faces on hard-to-reach keys" >}}

- **The columns aren't angled quite enough.** Having the key columns angled inward is definitely nice, but I'd actually like the angle to be a bit steeper. It doesn't quite match the angle of my hands and causes me to bend my wrists just a bit.


R static/images/my-atreus.png => content/blog/atreus-review/my-atreus.png +0 -0
R static/images/banned-by-acm.png => content/blog/blocked-by-acm/banned-by-acm.png +0 -0
R content/blog/blocked-by-acm.md => content/blog/blocked-by-acm/index.md +1 -1
@@ 15,7 15,7 @@ done

I ran the script and... now I'm blocked from accessing any publications on the ACM's website. Oof.

![screenshot of the ACM website showing that my IP address is blocked with a support email listed for help](/images/banned-by-acm.png)
{{< picture src="banned-by-acm.png" alt="screenshot of the ACM website showing that my IP address is blocked with a support email listed for help" >}}

Let's hope they actually check that support email! If not, I'll be stuck using a VPN to read papers for school.


R static/images/intentional-tech/bag.jpg => content/blog/my-journey-towards-intentional-technology-use/bag.jpg +0 -0
R static/images/intentional-tech/books.png => content/blog/my-journey-towards-intentional-technology-use/books.png +0 -0
R content/blog/my-journey-towards-intentional-technology-use.md => content/blog/my-journey-towards-intentional-technology-use/index.md +10 -15
@@ 6,11 6,9 @@ summary: I've always been fascinated by technology; it's so shiny and exciting, 
 
I've always been fascinated by technology. I remember playing with my dad's old gadgets -- a little voice memo recorder comes to mind -- and was delighted whenever he let me keep one. I used my own money to buy a PalmPilot and later a PocketPC in elementary school, wishing I had phone numbers, calendar events, and notes to store, but mostly just tinkering with the devices and, of course, playing games. When I got my first cell phone -- a basic little Nokia -- I explored every entry in every menu to see what it could do. As an adult, I still love exploring new tech; it's so shiny and exciting, so full of potential uses.

{{% figure
  src="/images/intentional-tech/pdas.jpg"
  alt="Two very old handheld computers, a Palm m105 and a Dell Axim v50."
  caption="While still in elementary school, I bought a used PalmPilot -- something like this m105 -- and later a Dell Axim PocketPC. Oh, the memories. Images from <https://old-organizers.com/MorePicts/MP150.htm> and <https://www.theregister.com/2005/01/17/review_dell_axim_x50v/>."
%}}
{{< figure caption="While still in elementary school, I bought a used PalmPilot -- something like this m105 -- and later a Dell Axim PocketPC. Oh, the memories. Images from <https://old-organizers.com/MorePicts/MP150.htm> and <https://www.theregister.com/2005/01/17/review_dell_axim_x50v/>." >}}
  {{< picture src="pdas.jpg" alt="Two very old handheld computers, a Palm m105 and a Dell Axim v50." >}}
{{< /figure >}}

But sometimes those many uses are too much. Sometimes we use technology simply because it's there, and it gets in the way of what we truly care about doing. As my time and mental energy have become more scarce, and as technology has become more addictive and manipulative, my attitude towards the digital world has changed. I'm now rather skeptical of the real value of each new thing. I try to make deliberate choices about when and how to use technology, whether for work or play, rather than allow it to become the default tool or activity.



@@ 22,11 20,10 @@ Then, during 2022, I read several books[^books] that helped me change my mindset

I did Newport's suggested 30-day declutter, cutting out all non-essential digital activities for a full month and then re-introducing the ones that were worth my time only after creating a plan for their use. In the end, I reduced my podcast consumption, entirely cut out what little social media I was using, and silenced all notifications on my phone except for actual phone calls. My brain felt less busy, in a good way.

{{% figure
  src="/images/intentional-tech/books.png"
  alt="Covers of Digital Minimalism, Technology and the Character of Contemporary Life, and Bored and Brilliant"
  caption="Images from Amazon.com."
%}}
{{< figure caption="Images from Amazon.com" >}}
  {{< picture src="books.png" alt="Covers of Digital Minimalism, Technology and the Character of Contemporary Life, and Bored and Brilliant" >}}
{{< /figure >}}

<cite>Digital Minimalism</cite> pushed me from "I need to spend less time on my phone" to "I need to do more of the things I care about." During and after my 30-day declutter, I took Newport's advice and replaced the time previously spent using technology on other activities that meant more to me. I'd been reading quite a bit since the beginning of the year and was able to enjoy even more books without so many digital distractions. I also started spending more time outdoors, encouraged and inspired by several nature-related books that I read throughout the year.[^nature-books] And I increased the quality and quantity of family time.

While <cite>Digital Minimalism</cite> helped me take practical steps to redirect my energy, [<cite>Technology and the Character of Contemporary Life</cite>](/books/technology-and-the-character-of-contemporary-life/) by Albert Borgmann exposed me to a more philosophical view. (It's a dense book -- the subtitle is <cite>A Philosophical Inquiry</cite> -- but if you can handle that, it's a great read.) Borgmann argues that technological "devices" have altered the way we view the world, causing us to focus on commodified versions of what were previously "focal things", such as replacing live music with a stereo set.


@@ 39,11 36,9 @@ Around this time I read [<cite>Bored and Brilliant</cite>](/books/bored-and-bril

Zomorodi's book also inspired me to start carrying my phone in a bag. Although it seems like a small change, keeping my phone away from the easy reach of my pocket has made a big difference. I've managed to stop checking my phone so frequently now that getting it out takes a bit more effort. What's more, it's become easy to leave my phone out-of-reach; I often keep my bag on the kitchen counter at home or leave it with my shoes when visiting someone. (A bag also has the added benefit of letting me carry a few more useful things -- pen, notebook, etc. -- without stuffing my pockets.)

{{% figure
  src="/images/intentional-tech/bag.jpg"
  alt="A cross-body bag resting on the table"
  caption="My phone now spends much more time in this bag, sitting on a table or counter, than in my hands or pockets."
%}}
{{< figure caption="My phone now spends much more time in this bag, sitting on a table or counter, than in my hands or pockets." >}}
  {{< picture src="bag.jpg" alt="A cross-body bag resting on the table" >}}
{{< /figure >}}


Since making those last few tweaks, I finally feel like I've conquered my phone. It's a tool (or sometimes still a toy) that I use how and when I intentionally choose, not a distraction that's constantly begging for my attention. I actually manage to forget about it most of the time.

R static/images/intentional-tech/pdas.jpg => content/blog/my-journey-towards-intentional-technology-use/pdas.jpg +0 -0
R static/images/fcc-cognizable-challenge/full.svg => content/blog/what-does-it-take-fcc-challenge/full.svg +0 -0
R static/images/fcc-cognizable-challenge/geo-3-accessible.png => content/blog/what-does-it-take-fcc-challenge/geo-3-accessible.png +0 -0
R static/images/fcc-cognizable-challenge/geo-all-accessible.png => content/blog/what-does-it-take-fcc-challenge/geo-all-accessible.png +0 -0
R static/images/fcc-cognizable-challenge/h3-hex-nesting.svg => content/blog/what-does-it-take-fcc-challenge/h3-hex-nesting.svg +0 -0
M content/blog/what-does-it-take-fcc-challenge/index.md => content/blog/what-does-it-take-fcc-challenge/index.md +25 -28
@@ 49,12 49,9 @@ One important exception is that a challenge to a provider's claimed outdoor stat

Additionally, since service quality varies by location, challenges are specific to a certain geographic region. Regions are defined by the [H3 system](https://h3geo.org), which uses a nested hierarchy of hexagons in which each hexagon of resolution `r` contains seven child hexagons of resolution `r + 1`.

{{% figure
  src="/images/fcc-cognizable-challenge/h3-hex-nesting.svg"
  alt="a single parent hexagon contains 7 child hexagons, each of which contain 7 child hexagons of their own"
  caption="The blue hexagon contains 7 purple hexagons, each of which contain 7 green hexagons."
  class="h3-hex-nesting"
%}}
{{< figure caption="The blue hexagon contains 7 purple hexagons, each of which contain 7 green hexagons." class="h3-hex-nesting" >}}
  <img src="h3-hex-nesting.svg" alt="a single parent hexagon contains 7 child hexagons, each of which contain 7 child hexagons of their own" />
{{< /figure >}}

The FCC has determined that challenges are to be made against resolution-8 hexagons, which are relatively small; each has an area of [about 0.7 square kilometers](https://h3geo.org/docs/core-library/restable/#average-area-in-km2). You might successfully challenge the advertised speeds in your neighborhood, but additional data would be required to also challenge the speeds a few blocks away.



@@ 101,7 98,7 @@ The long version, of course, is more complicated. You'll need to ensure that you
It's important to note that the FCC will aggregate tests from all sources when considering whether a region is challenged. This fact means that it's impossible to be entirely sure that you've collected enough data to create a cognizable challenge -- the testing threshold requires that a certain percentage of tests within the region be negative, and you can't calculate that percentage accurately unless you know about *all* of the tests for the region, including those run by others. I don't expect to see tons of people submitting speed tests, though, so you can probably make a fairly confident assessment using only your test data.

{{% details "Flowchart: Overview of what makes a cognizable challenge" %}}
<img src="/images/fcc-cognizable-challenge/overview.svg" alt="flowchart of what it takes to create a cognizable challenge, at a high level" class="invertible" loading="lazy" />
<img src="overview.svg" alt="flowchart of what it takes to create a cognizable challenge, at a high level" class="invertible" loading="lazy" />
{{% /details %}}




@@ 126,7 123,7 @@ Additionally, since challenges are specific to a combination of cellular technol
There are a few possible exceptions to these requirements; the flowchart below shows the criteria in more detail.

{{% details "Flowchart: Criteria for including a test in a challenge" %}}
<img src="/images/fcc-cognizable-challenge/test-criteria.svg" alt="flowchart of the criteria for including a test in a challenge" class="invertible" loading="lazy" />
<img src="test-criteria.svg" alt="flowchart of the criteria for including a test in a challenge" class="invertible" loading="lazy" />
{{% /details %}}

{{% details "Example: Evaluating validity of tests" %}}


@@ 170,19 167,19 @@ In order to ensure that service is bad across an entire area, not just in a sing
Again, the process can be a bit more complex than that -- check out the flowchart below for more details.

{{% details "Flowchart: Determining if the geographic threshold is met" %}}
<img src="/images/fcc-cognizable-challenge/threshold-geo.svg" alt="flowchart of how to determine if the geographic threshold for a challenge is met" class="invertible" loading="lazy" />
<img src="threshold-geo.svg" alt="flowchart of how to determine if the geographic threshold for a challenge is met" class="invertible" loading="lazy" />
{{% /details %}}

{{% details "Example: Not quite meeting the geographic threshold" %}}

Consider the following resolution-8 hexagon. Although more of than four of its child hexagons contain tests, only three of the child hexagons contain at least two tests, one of which is negative. As a result, this resolution-8 hexagon does not meet the geographic threshold.

{{% figure
  src="/images/fcc-cognizable-challenge/geo-all-accessible.png"
  alt="All of a parent hexagon's child hexagons contain roads. One child hexagon contains two positive tests, one contains a positive and a negative test, one contains two positive and one negative tests, one contains two negative tests, one contains one positive test, one contains one negative test, and one contains no tests."
{{< figure
  caption="The purple hexagon is a resolution-8 hexagon being challenged, and the green hexagons are the resolution 9 child hexagons. Blue circles are positive tests, and red squares are negative tests. These hexagons are not accurately sized. Map &copy; [OpenStreetMap](https://www.openstreetmap.org/copyright)."
  class="map-hex"
%}}
>}}
  {{< picture src="geo-all-accessible.png" alt="All of a parent hexagon's child hexagons contain roads. One child hexagon contains two positive tests, one contains a positive and a negative test, one contains two positive and one negative tests, one contains two negative tests, one contains one positive test, one contains one negative test, and one contains no tests." >}}
{{< /figure >}}

{{% /details %}}



@@ 192,12 189,12 @@ Consider the following resolution-8 hexagon. Four of its child hexagons contain 

(Note that the hexagons with at least two tests don't have to be the same hexagons that are accessible.)

{{% figure
  src="/images/fcc-cognizable-challenge/geo-3-accessible.png"
  alt="A parent hexagon's child hexagons are shown. One child hexagon has roads and contains a positive and a negative test, one has roads and contains two positive and one negative tests, one has roads and contains a positive test, one has no roads and contains two negative tests, and the rest contain no roads or tests."
{{< figure
  caption="The purple hexagon is a resolution-8 hexagon being challenged, and the green hexagons are the resolution 9 child hexagons. Blue circles are positive tests, and red squares are negative tests. These hexagons are not accurately sized. Map &copy; [OpenStreetMap](https://www.openstreetmap.org/copyright)."
  class="map-hex"
%}}
>}}
  {{< picture src="geo-3-accessible.png" alt="A parent hexagon's child hexagons are shown. One child hexagon has roads and contains a positive and a negative test, one has roads and contains two positive and one negative tests, one has roads and contains a positive test, one has no roads and contains two negative tests, and the rest contain no roads or tests." >}}
{{< /figure >}}

{{% /details %}}



@@ 206,7 203,7 @@ Consider the following resolution-8 hexagon. Four of its child hexagons contain 
The FCC also wants to be sure that service is bad most of the time, not just at a single, particularly congested time of day. As a result, they require that tests meet a temporal threshold -- the earliest two negative tests and the latest two negative tests (by time of day only, not date) must be at least four hours apart.

{{% details "Flowchart: Determining if the temporal threshold is met" %}}
<img src="/images/fcc-cognizable-challenge/threshold-time.svg" alt="flowchart of how to determine if the temporal threshold for a challenge is met" class="invertible" loading="lazy" />
<img src="threshold-time.svg" alt="flowchart of how to determine if the temporal threshold for a challenge is met" class="invertible" loading="lazy" />
{{% /details %}}

{{% details "Example: Meeting the temporal threshold" %}}


@@ 252,19 249,19 @@ Finally, in order to have a certain statistical level of confidence that service
Take a look at the flowchart below for the exact details.

{{% details "Flowchart: Determining if the testing threshold is met" %}}
<img src="/images/fcc-cognizable-challenge/threshold-tests.svg" alt="flowchart of how to determine if the testing threshold for a challenge is met" class="invertible" loading="lazy" />
<img src="threshold-tests.svg" alt="flowchart of how to determine if the testing threshold for a challenge is met" class="invertible" loading="lazy" />
{{% /details %}}

{{% details "Example: Meeting the testing threshold" %}}

Consider the following resolution-8 hexagon. It has a total of 22 tests, 16 of which are positive and 6 of which are negative. That means that 27% of tests are negative, which meets the testing threshold for a hexagon with between 21 and 29 total tests.

{{% figure
  src="/images/fcc-cognizable-challenge/tests-spread.png"
  alt="A parent hexagon's child hexagons are shown. One child hexagon has three positive tests, one has a positive and a negative test, one has two positive and a negative test, one has eight positive and two negative tests, one has one positive and two negative tests, one has one positive test, and one has no tests."
{{< figure
  caption="The purple hexagon is a resolution-8 hexagon being challenged, and the green hexagons are the resolution 9 child hexagons. Blue circles are positive tests, and red squares are negative tests. These hexagons are not accurately sized. Map &copy; [OpenStreetMap](https://www.openstreetmap.org/copyright)."
  class="map-hex"
%}}
>}}
  {{< picture src="tests-spread.png" alt="A parent hexagon's child hexagons are shown. One child hexagon has three positive tests, one has a positive and a negative test, one has two positive and a negative test, one has eight positive and two negative tests, one has one positive and two negative tests, one has one positive test, and one has no tests." >}}
{{< /figure >}}

{{% /details %}}



@@ 272,12 269,12 @@ Consider the following resolution-8 hexagon. It has a total of 22 tests, 16 of w

Consider the following resolution-8 hexagon. It has a total of 31 tests, 24 of which are positive and 7 of which are negative. This ratio of 22.6% would normally be sufficient for a hexagon with between 30 and 45 tests, but in this case more than half of the tests are in a single child hexagon. As a result, the math gets a bit trickier because the child hexagon with more than half of the tests can only count towards half of the testing threshold.

{{% figure
  src="/images/fcc-cognizable-challenge/tests-clustered.png"
  alt="A parent hexagon's child hexagons are shown. One child hexagon has three positive tests, two each have one positive and one negative test, one has four positive and one negative test, one has thirteen positive and four negative tests, one has one positive test, and one has no tests."
{{< figure
  caption="The purple hexagon is a resolution-8 hexagon being challenged, and the green hexagons are the resolution 9 child hexagons. Blue circles are positive tests, and red squares are negative tests. These hexagons are not accurately sized. Map &copy; [OpenStreetMap](https://www.openstreetmap.org/copyright)."
  class="map-hex"
%}}
>}}
  {{< picture src="tests-clustered.png" alt="A parent hexagon's child hexagons are shown. One child hexagon has three positive tests, two each have one positive and one negative test, one has four positive and one negative test, one has thirteen positive and four negative tests, one has one positive test, and one has no tests." >}}
{{< /figure >}}

First, you need to compute the adjusted total number of tests by doubling the number of tests not in the child hexagon with the most tests:



@@ 318,7 315,7 @@ As I mentioned at the beginning of this post, I'm currently involved in [buildin
## Useful references

- The bulk of this information comes from the FCC's [Mobile Technical Requirements Order](https://www.fcc.gov/document/fcc-releases-bdc-mobile-technical-requirements-order).
- The flowcharts included above are all available in one [mega-flowchart of the full process](/images/fcc-cognizable-challenge/full.svg).
- The flowcharts included above are all available in one [mega-flowchart of the full process](full.svg).
- The H3 hexagon system has [thorough documentation](https://h3geo.org/docs) online.
- Details about the approval process for third-party speed test apps can be found in [OET Bulletin 75](https://www.fcc.gov/sites/default/files/oet75.pdf).
- The FCC has a [help center article](https://help.bdc.fcc.gov/hc/en-us/articles/10468786141723-How-to-Use-the-FCC-Speed-Test-App-to-Challenge-Mobile-Coverage) explaining how to use their app to run speed tests for the challenge process.

R static/images/fcc-cognizable-challenge/overview.svg => content/blog/what-does-it-take-fcc-challenge/overview.svg +0 -0
R static/images/fcc-cognizable-challenge/test-criteria.svg => content/blog/what-does-it-take-fcc-challenge/test-criteria.svg +0 -0
R static/images/fcc-cognizable-challenge/tests-clustered.png => content/blog/what-does-it-take-fcc-challenge/tests-clustered.png +0 -0
R static/images/fcc-cognizable-challenge/tests-spread.png => content/blog/what-does-it-take-fcc-challenge/tests-spread.png +0 -0
R static/images/fcc-cognizable-challenge/threshold-geo.svg => content/blog/what-does-it-take-fcc-challenge/threshold-geo.svg +0 -0
R static/images/fcc-cognizable-challenge/threshold-tests.svg => content/blog/what-does-it-take-fcc-challenge/threshold-tests.svg +0 -0
R static/images/fcc-cognizable-challenge/threshold-time.svg => content/blog/what-does-it-take-fcc-challenge/threshold-time.svg +0 -0
R static/images/kyria-stand/bottom.jpg => content/creations/kyria-vertical-stand-case/bottom.jpg +0 -0
R static/images/kyria-stand/full.jpg => content/creations/kyria-vertical-stand-case/full.jpg +0 -0
R content/creations/kyria-vertical-stand-case.md => content/creations/kyria-vertical-stand-case/index.md +4 -4
@@ 7,17 7,17 @@ summary: A stand for my Kyria keyboard that allows me to use it tented 90° and 

One of the reasons I built my [Kyria keyboard](/creations/kyria), which has two separate halves, was to allow me to tent the halves to a more comfortable angle for my hands. The keyboard has tripod mounts on the bottom of each side, and I tried using those for tenting, but I found that it wasn't super stable with large amounts of tilt; I was shooting for nearly vertical. Eventually I decided to use a cardboard box and some velcro to solve my problems.

![my stand for my Kyria keyboard](/images/kyria-stand/full.jpg)
{{< picture src="full.jpg" alt="my stand for my Kyria keyboard" >}}

![the stand also doubles as a case for transporting the keyboard](/images/kyria-stand/open.jpg)
{{< picture src="open.jpg" alt="the stand also doubles as a case for transporting the keyboard" >}}

I used a rather sturdy box that I had left over from something I bought online. It was about the right size to separate the two keyboard halves a decent distance, and it happened to fit them inside as well, so I could use it as a case when transporting the keyboard. I bought some fancy low-profile velcro, attached one half to the keyboard and the other half to the box, and voilà!

![the keyboard is attached to the box with velcro](/images/kyria-stand/velcro.jpg)
{{< picture src="velcro.jpg" alt="the keyboard is attached to the box with velcro" >}}

My contraption worked well for keeping the keyboard vertical, but the bottom of the box was too slippery against the desk, causing the whole thing to move side to side when I typed. I was about to just velcro it to the desk until I thought of a more portable solution -- adding some sort of non-slip covering to the bottom of the box. I found an old mouse pad and taped it on, and the slipping problems were solved.

![part of a mouse pad taped to the bottom of the box kept it from slipping on the desk](/images/kyria-stand/bottom.jpg)
{{< picture src="bottom.jpg" alt="part of a mouse pad taped to the bottom of the box kept it from slipping on the desk" >}}

With everything ready, I started using my vertical keyboard. ~~Everything worked as intended, except for one small detail -- it wasn't comfortable! I tried moving things around for quite a while and eventually concluded that with my hands turned vertically, my thumbs did not like having their keys on the same plane as the finger keys. Along the way I also discovered that having the keys at a different height/depth for each finger would be more comfortable. Basically I realized that what I wanted was something like the [Dactyl ManuForm keyboard](https://github.com/abstracthat/dactyl-manuform). Maybe someday I'll build one...~~


R static/images/kyria-stand/open.jpg => content/creations/kyria-vertical-stand-case/open.jpg +0 -0
R static/images/kyria-stand/velcro.jpg => content/creations/kyria-vertical-stand-case/velcro.jpg +0 -0
R static/images/kyria/full-front.jpg => content/creations/kyria/full-front.jpg +0 -0
R static/images/kyria/full-top.jpg => content/creations/kyria/full-top.jpg +0 -0
R content/creations/kyria.md => content/creations/kyria/index.md +5 -5
@@ 5,23 5,23 @@ lastmod: 2022-03-11
summary: A custom, split, ergonomic, tiny, mechanical keyboard that I built from a kit.
---

![my complete Kyria build](/images/kyria/full-top.jpg)
{{< picture src="full-top.jpg" alt="my complete Kyria build" >}}

I've really gone down the keyboard rabbit hole in the last year or so. [I love my Keyboardio Atreus](/blog/atreus-review), but for a while I've wanted a split keyboard that would allow me to keep my arms at shoulder width while typing. Back in November I funded the [Keyboardio Model 100 on Indiegogo](https://www.indiegogo.com/projects/the-keyboardio-model-100--4), but come January I started to think that building my own keyboard would be more fun than buying something pre-made. Eventually I cancelled my Model 100 order and instead bought all the parts to build a [Kyria](https://blog.splitkb.com/blog/introducing-the-kyria). (I'd still love to get a Model 100 someday, but I figure I shouldn't buy multiple $300-400 keyboards at a time...)

I went all out on my Kyria build -- socketed microcontrollers, two OLED displays, underglow LEDs, hot-swap switches, rotary encoders, tilting/tenting tripods -- and paid about $435 for everything ($85 of that was a soldering iron and tools for assembly).

![a close-up view of the right side of my fully-assembled Kyria](/images/kyria/right-side.jpg)
{{< picture src="right-side.jpg" alt="a close-up view of the right side of my fully-assembled Kyria" >}}

## Building the keyboard

The build process was fun! Soldering turned out to be pretty easy, at least for all the through-hole components. The LEDs are surface mounted, though, and I had a tough time getting them soldered onto their tiny pads.[^led] I've already re-soldered individual LEDs several times to get them all working, and in the process I accidentally broke one of the solder pads off the PCB and had to run a wire to make the necessary connection. I can live with bad LED connections, though -- they're not really a necessity, after all.

![the wire connecting the LED with the broken solder pad](/images/kyria/led-wire.jpg)
{{< picture src="led-wire.jpg" alt="the wire connecting the LED with the broken solder pad" >}}

My only real gripe with the whole kit is that the [acrylic plate case](https://splitkb.com/collections/cases-and-plates/products/kyria-acrylic-plate-case) I bought doesn't entirely secure the PCB. The case has spacers that go through holes in the PCB, but the PCB isn't actually attached to the spacers, so it can move vertically within the case and bump into both the top and bottom plates. I suspect that this movement is part of the reason the LED connections keep going out on me (the other part being my poor soldering skills). I've since put some washers around the spacers (four M4x8 washers on each side of each spacer) to force the PCB to stay put vertically, though, and it feels much more solid.

![a side view of the keyboard showing how the PCB fits between the plates of the case](/images/kyria/side-no-switches.jpg)
{{< picture src="side-no-switches.jpg" alt="a side view of the keyboard showing how the PCB fits between the plates of the case" >}}

I definitely would have gotten a better keyboard at a better price had I stuck with my Model 100 order, but the fun of building my own was worth the trade-offs.



@@ 29,7 29,7 @@ I definitely would have gotten a better keyboard at a better price had I stuck w

So far I'm enjoying using the Kyria as well. The thumb keys and the pinky column stagger of it fit my hands better than the Atreus does, although the difference does take some getting used to. Being able to spread out the two sides of the keyboard and tent them is nice as well, but I'm still working on figuring out a way to rest my palms on something when the keyboard is tented.

![a view of the Kyria from the front showing how it's tented](/images/kyria/full-front.jpg)
{{< picture src="full-front.jpg" alt="a view of the Kyria from the front showing how it's tented" >}}

The rotary encoders, displays, and underglow LEDs are all fun to have but not terribly useful in a practical sense. I currently use one rotary encoder for volume control and the other to control the color of the LEDs. The displays show me what layer of the keyboard I'm using and whether I have caps lock on. And the LEDs just make things look pretty :)


R static/images/kyria/led-wire.jpg => content/creations/kyria/led-wire.jpg +0 -0
R static/images/kyria/right-side.jpg => content/creations/kyria/right-side.jpg +0 -0
R static/images/kyria/side-no-switches.jpg => content/creations/kyria/side-no-switches.jpg +0 -0
R content/creations/vim-sway-nav.md => content/creations/vim-sway-nav/index.md +1 -1
@@ 12,6 12,6 @@ Seamless navigation between [Sway](https://swaywm.org/) windows and (Neo)Vim spl

<!--more-->

![demo of vim-sway-nav in action -- focus moves between Vim splits and Sway windows using only Super and the arrow keys](/images/vim-sway-nav-demo.gif)
![demo of vim-sway-nav in action -- focus moves between Vim splits and Sway windows using only Super and the arrow keys](vim-sway-nav-demo.gif)

Inspired by [vim-tmux-navigator](https://github.com/christoomey/vim-tmux-navigator).

R static/images/vim-sway-nav-demo.gif => content/creations/vim-sway-nav/vim-sway-nav-demo.gif +0 -0
R static/images/headshot.png => content/headshot.png +0 -0
M content/style.css => content/style.css +1 -1
@@ 6,7 6,7 @@
  align-items: center;
}

#photo-greeting img {
#photo-greeting picture {
  margin: 0;
  width: 8rem;
  max-width: 15rem;

A layouts/shortcodes/figure.html => layouts/shortcodes/figure.html +6 -0
@@ 0,0 1,6 @@
<figure {{ with .Get "class" }}class="{{ . }}"{{ end }}>
{{ .Inner }}
{{ with .Get "caption" }}
<figcaption><p>{{ . | markdownify }}</p></figcaption>
{{ end }}
</figure>

A layouts/shortcodes/picture.html => layouts/shortcodes/picture.html +5 -0
@@ 0,0 1,5 @@
{{ $p := .Page.Resources.Get (.Get "src") }}
<picture>
  <source srcset="{{ ($p.Process "webp").RelPermalink }}" type="image/webp" />
  <img src="{{ ($p.Process "jpg").RelPermalink }}" alt="{{ .Get "alt" }}" {{ with .Get "width" }} width="{{ . }}" {{ end }} />
</picture>

D static/images/cell-watch-large.png => static/images/cell-watch-large.png +0 -0
D static/images/logo.png => static/images/logo.png +0 -0
D static/images/measurement-planning-methodology-large.png => static/images/measurement-planning-methodology-large.png +0 -0