Recent posts (max 10) - Browse or Archive for more

LeoCAD 19.07.1 - Packaged for Linux

LeoCAD is a CAD application for building digital models with Lego-compatible parts drawn from the LDraw parts library.

I packaged (as an rpm) the 19.07.1 release of LeoCAD for Fedora 29. This package requires the LDraw parts library package.

Install the binary rpm. The source rpm contains the files to allow you to rebuild the packge for another distribution.



Grid-based Tiling Window Management

Many years ago, a coworker of mine showed me Window's "quick tiling" feature, where you would press Window-LeftArrow or Window-RightArrow to snap the current window to the left or right half of the screen. I then found that KDE on Linux had that same feature and the ability to snap to the upper-left, lower-left, upper-right, or lower-right quarter of the screen. I assigned those actions to the Meta-Home, Meta-End, Meta-PgUp, and Meta-PgDn shortcuts. (I'm going to use "Meta" as a generic term to mean the modifier key that on Windows machines has a Windows logo, on Linux machines has a Ubuntu or Tux logo, and Macs call "command".) Being able to arrange windows on screen quickly and neatly with keyboard shortcuts worked extremely well and quickly became a capability central to how I work.

Then I bought a 4K monitor.

With a 4K monitor, I could still arrange windows in the same way, but now I had 4 times the number of pixels. There was room on the screen to have a lot more windows that I could see at the same time and remain readable. I wanted a 4x4 grid on the screen, with the ability to move windows around on that grid, but also to resize windows to use multiple cells within that grid.

Further complicating matters is the fact that I use that 4K monitor along with the laptop's !FullHD screen which is 1920x1080. Dividing that screen into a 4x4 grid would be awkward; I wanted to retain a 2x2 grid for that screen, and keep a consistent mechanism for moving windows around on that screen and across screens.

KDE (Linux)

Unfortunately, KDE does not have features to support such a setup. So I went looking for a programatic way to control window size and placement on KDE/X11. I found three commandline tools that among them offered primitives I could build upon: xdotool, wmctrl, and xprop.

My solution was to write a Python program which took two arguments: a command and a direction.

The commands were 'move', 'grow', and 'shrink', and the directions 'left', 'right', 'up', and 'down'. And one additional command 'snap' with the location 'here' to snap the window to the nearest matching grid cells. The program would identify the currently active window, determine which grid cell was a best match for the action, and execute the appropriate xdotool commands. Then I associated keyboard shortcuts with those commands. Meta-Arrow keys for moving, Meta-Ctrl-Arrow keys to grow the window by a cell in the given direction, Meta-Shift-Arrow to shrink the window by a cell from the given direction, and Meta-Enter to snap to the closest cell.


Conceptually, that's not all that complicated to implement, but in practice:

Window geometry has to be adjusted for window decorations. But there appears to be a bug with setting the position of a window. The window coordinates used by the underlying tools for setting and getting the geometries do not include the frame, except for setting the position of the window, on windows that have a 'client' of the machine name instead of N/A. Getting the position, getting the size, and setting the size, all use the non-frame values. Windows with a client of N/A use the non-frame values for everything. A border width by title bar height offset error for only some of the windows proved to be a vexing bug to track down.

The space on a secondary monitor where the taskbar would be is also special, even if there is no task bar on that monitor; attempting to move a window into that space causes the window to shift up out of that space, so there remains an unused border on the bottom of the screen. Annoying, but I have found no alternative.

Move operations are not instantaneous, so setting a location and immediately querying it will yield the old coordinates for a short period.

A window which is maximized does not respond to the resize and move commands (and attempting it will cause xdotool to hang for 15 seconds), so that has to be detected and unmaximized.

A window which has been "Quick Tiled" using KDE's native quick-tiling feature acts like a maximized window, but does not set the maximized vert or maximized horz state flags, so cannot be detected with xprop, and to get it out of the KDE quick tiled state, it must be maximized and then unmaximized. So attempting to move a KDE quick tiled window leads to a 15 second pause, then the window maximizing briefly, and then resizing to the desired size. In practice, this is not much of an issue since my tool has completely replaced my use of KDE's quick-tiling.


I recently whined to a friend about not having the same window management setup on OS X; and he pointed me in the direction of a rather intriguing open source tool called Hammerspoon which lets you write Lua code to automate tasks in OS X and can assign keyboard shortcuts to those actions. That has a grid module that offers the necessary primitives to accomplish the same goal.

After installing Hammerspoon, launching it, and enabling Accessibility for Hammerspoon (so that the OS will let it control application windows), use init.lua as your ~/.hammerspoon/init.lua and reload the Hammerspoon config. This will set up the same set of keyboard shortcuts for moving application windows around as described in the KDE (Linux) section. For those who use OS X as their primary system, that set of shortcuts are going to conflict with (and therefore override) many of the standard keyboard shortcuts. Changing the keyboard shortcuts to add the Option key as part of the set of modifiers for all of the shortcuts should avoid those collisions at the cost of either needing another finger in the chord or putting a finger between the Option and Command keys to hit them together with one finger.

I was pleasantly surprised with how easily I could implement this approach using Hammerspoon.


Simple demo of running this on KDE:

(And that beautiful background is a high resolution photo by a friend and colleague, Sai Rupanagudi.)

LDraw Parts Library 2019-01 - Packaged for Linux maintains a library of Lego part models upon which a number of related tools such as LeoCAD, LDView and LPub rely.

I packaged the 2019-01 parts library for Fedora 29 to install to /usr/share/ldraw; it should be straight-forward to adapt to other distributions.

The *.noarch.rpm files are the ones to install, and the .src.rpm contains everything so it can be rebuilt for another rpm-based distribution.



LeoCAD 18.02 - Packaged for Linux

LeoCAD is a CAD application for building digital models with Lego-compatible parts drawn from the LDraw parts library.

I packaged the 18.02 release of LeoCAD for Fedora 29. This package requires the LDraw parts library package.

Install the binary rpm. The source rpm contains the files to allow you to rebuild the packge for another distribution.



LDraw Parts Library 201802 - Packaged for Linux maintains a library of Lego part models upon which a number of related tools such as LeoCAD, LDView and LPub rely.

I packaged the 201802 parts library for Fedora 29 to install to /usr/share/ldraw; it should be straight-forward to adapt to other distributions.

The *.noarch.rpm files are the ones to install, and the .src.rpm contains everything so it can be rebuilt for another rpm-based distribution.



Durable Chair Mat

One of the difficulties of having a desk and an office chair where there is residential carpet is the chair-mat. Especially when it sees full-time daily use. You can spend $50 for flimsy vinyl, or $200 for high-end vinyl chair-mats. In my experience, none of them last a year; as soon as you get into the colder months and the floor cools down, I'd flop into the chair one morning and hear that tell-tale snap of cold vinyl failing. Even before the failure, the vinyl develops divots where the wheels tend to rest, and once they start to develop, gravity ensures that same location is the natural resting place for the wheels every time you sit down.

You can make your own chair-mat, and you'll find many people online who have described how they've done it, with a variety of materials. But they only show you the newly finished product; they don't show you how it's held up over the course of years. Many of them won't last, despite their creators' confident claims. Here, I distill about a decade's worth of chair mat experience.

Attempt 0

I bought a vinyl chair-mat. It died quickly.


Attempt 1

Thinking that maybe this is a case of "you get what you pay for," I bought a high-end vinyl chair-mat. When the temperature dropped and I flopped into the chair, it died with a snap. And continued to crack, and crack, and crack.


Attempt 2

Let's try building something sturdier. I bought a sheet of plywood, cut it to shape, and stained the top of it. A hard, flat chair-mat that wouldn't snap when it got cold? Perfect!

Well... that lasted a while, but the rolling of the wheels across the wood grain compressed the wood unevenly, and the wood fibers began to separate.


That doesn't really do it justice; you need to look closer; so you can see how the wood separates with the grain.


But it just kept getting worse, and the damage kept getting deeper.


After a while, I was generating piles of wood splinters. I used that for about 3-1/2 years, but I put up with it falling apart for way too large a portion of that time.

Attempt 3

For my next attempt, I flipped the plywood over, and applied self-adhesive faux-wood vinyl laminate flooring (4x36" planks) directly to the plywood. I figured that would keep the plywood from coming apart, and the plywood would provide a solid underlayment for the flooring. Unfortunately, the slats of flooring immediately began sliding under the pressure of the chair. They didn't move rapidly, but as they edged away from their initial position, they exposed the gooey adhesive that was failing to hold them in place. And the slats under my feet went even faster. I had a mess under my chair in less than a week.

In fact, if you look back at the first picture of the torn-up plywood chair-mat, you can see the adhesive backing of the flooring sticking out from under it around the edges.


Again, the above picture doesn't look as bad as it was. If you look closely, you can see the seams don't quite line up, but it was only in this "good" of shape because I kept pushing the slats back into place.

Attempt 4

At this point, I did some research, and found that there are two kinds of office chair caster wheels. The normal kind that comes with any office chair you buy, and a second kind made from a different plastic intended for use on hardwood floors. Hardwood floors? Hmm...

I ordered a set of those wheels and installed them on my office chair in the hopes that they'd be gentler on my next attempt.


I bought a 4'x8' sheet of 3/4" particle board to use as the base because I wanted something more rigid than the plywood I had been using before.

For the flooring, I bought faux-wood engineered flooring that snaps together at the seams.

This is the label from the flooring sample of what I used; but I'm not finding any indication that they even make this stuff any more.


The planks were about 5-1/2"x48" planks; that allowed me to build the chair-mat with no end-to-end seams. I glued the flooring to the 4'x8' particle board using liquid nails.


The next day, after the adhesive had dried, I flipped the board over, cut off the excess length and trimmed the long edges.

Cutting the long edges was needed since the 48" long planks had the interlocking groove system on their ends as well; so I had to trim them to a bit less than 48" Then I rough-cut the inside corners ...


... so that I could reach with the drill press and a hole-cutter to fillet the inner corners.


I also cut the outside rear corners of the mat at a 45 to give the whole thing a more interesting shape, without reducing the usable surface of the chair-mat.


I bought matching quarter-round trim, and used liquid nails to glue it to the edges that would not be adjacent to the desk, with the top edge of the trim flush with the top of the flooring since I didn't want a lip. Yes, that means I can roll off the edge, but in practice that hasn't been a problem, and makes it easier to sweep stuff off of it.

construction-glue-edge.jpg construction-glue-edge-bottom.jpg


I also later added nylon furniture sliders to the edges of the mat that were rubbing on the desk; I should have done that to begin with.



One of the challenges building this was the weight of this thing. I damaged a bit of the edge one of the times I flipped it over because I had trouble with the weight.

The other was that cutting through the particle board and flooring caused my circular saw blade to over-heat, leading to this awful cut.


Fortunately I learned this on the first cut to remove the excess particle board so fixing it simply meant taking another cut and losing a quarter-inch of the over-all length.


So the real question is, "How has it held up?" From a photo taken the day it was installed, you can see that the corners were nice and clean.


Due to where this corner is, it sees a great deal of foot traffic; not just when I'm going to sit down. From this picture taken after nearly three years of daily use, you can see that the cut edges had worn noticeably, but is still very serviceable.


The other location which shows some wear was mostly due to damage sustained while I was building the chair-mat. The damage is a bit difficult to see in the original photo


but the surface of that damaged area eventually broke off.


I tried to get a picture that would clearly show the wear from the wheels, but found it surprisingly difficult... though I should not have been surprised, given that until I started working on this write-up, I had not noticed any wear at all on the main flooring. Most of the color differences you can see in the picture are due to shadows or reflections, not wear.


But if you look carefully, you can see that the floor is just slightly lighter in a ring (marked in blue) centered where the chair sits most of the time. This is where the wheels most often travel; but there aren't divots that the wheels roll into and stay; it's still a solid, flat surface.


And there is one part of a seam that is showing significantly more wear than the rest of the floor (circled in red) which may need some attention. Here is a close-up taken a year-and-a-half after that showing that the wear has increased some, but not rapidly:


At some point, I managed to step on the quarter-round edging with all my weight one time too many, and it separated from main body of the mat. A bit of liquid nails put it back on and it has held up fine since.

Looking at it overall after over 4 years of use, it has held up extremely well:



I'm happy with how this chair-mat has held up over the past 4+ years; when it eventually falls apart, I expect to build another much like it. Differences I may consider include using a thinner particle board so the weight is more manageable, being more generous with the liquid nails for the edge trim, and adding the nylon sliders on day one.

Power Strip, Extreme

I have power tools and those from whom I can borrow power tools which require several different types of power. The mundane things run on your standard 120V 15-amp receptacle. The less mundane tools require 240V 15-amp. And then they get interesting... 240V 30-amp, and two variants of 240V 50-amp receptacles.

Wiring up receptacles on the wall for each of those ties the tools to that one location, and for some things, I want to be able to use them outside, not just in one location. So that means an extension cord, but I didn't want five different flavors of extension cord, either. Maybe one extension cord to rule them all and a half-dozen dongles?

I really wanted a more elegant solution. Ok, maybe a less awful solution?

First, let's talk receptacles. Power receptacles follow a standard set by NEMA with identifiers like NEMA 5-15R, or NEMA L14-30R. The key to understanding these is presented in this document from Essentially, the first number indicates what wires you have available in that connection. An "L" prefix on that number indicates it is a "locking" variant. The second number indicates the amperage. And it ends in "R" for receptacles, and "P"for plugs. (That document is worth perusing; it improved my understanding of practical electrical power in a number of ways, and helped me see the logic in the design.)

The receptacles around your house are NEMA 5-15R; these provide one hot, one neutral, and one ground wire. Higher amperages (NEMA 5-20R, etc) change the configuration of the prongs and the gauge (thickness) of the wires needed, but they all have one hot, one neutral, and one ground wire. But 240V outlets require two hot wires, so for NEMA 6-series, the neutral wire is replaced with a second hot wire. That isn't the only choice for 240V though; the NEMA 10-30R and NEMA 10-50R that you often see for electric dryers have two hot wires and a neutral, with no ground wire. To get to a receptacle with all four wires you move to NEMA 14-series with two hot, one neutral and one ground.

For the selection of equipment I have or can borrow, I needed several types of receptacles:

  • NEMA 6-15R
  • NEMA 6-50R
  • NEMA 10-30R
  • NEMA 10-50R

I didn't want to set up 4 receptacles on the wall with 4 extension cords. I wanted to consolidate this to one extension cord to rule them all. So I needed one that had a superset of the wires of the desired receptacles. The NEMA-6's needed two hot and ground, while the NEMA-10's needed two hot and neutral. So between those, I needed all four wires. That gets us to the NEMA 14-series. And the highest amperage is 50, so the extension cord would have to be a NEMA 14-50P to NEMA 14-50R, with a matching NEMA 14-50R in the wall. As it turns out, those are pretty standard extension cords; they're used for RVs and Teslas. In 50-amp applications, you want 6-gauge wire, not 10-gauge like some on the market are. They aren't cheap; here's a 25' extension cord for $130 for instance, and building your own to cut that cost takes some dedicated comparison shopping for 4-conductor 6-gauge SOOW wire.

So that solves the extension cord; what about all the adapters? I really didn't want a pile of adapters, so I decided to build a power strip with each of the required receptacle types in it. And since I would already have all 4 wires coming into it, I decided to add a boring old NEMA 5-15R to the mix.

Oh, but there is one additional wrinkle. A NEMA 5-15P will plug into either a NEMA 5-15R or NEMA 5-20R. And a NEMA 6-15P will plug into either a NEMA 6-15R or a NEMA 6-20R. Which means that by opting for the 20-amp receptacle, I could gain additional flexibility with no downside.

So that gets us our requirements for the power strip; a NEMA 14-50P on one end, and a box with NEMA 5-20R, NEMA 6-20R, NEMA 6-50R, NEMA 10-30R, and NEMA 10-50R. Given that the wire size depends on the amperage, I chose to order them by amperage, with the highest amperage at the end where the cord comes in, so the most expensive wires are the shortest.




A few disclaimers are likely prudent here: this is showing how I approached the problem, not how to safely solve this. Note the lack of any fuses, and the fact that this is connecting devices that are designed to pull 15 amps to a power source capable of supplying 50 amps. Plug everything in at once, and this will easily throw a breaker. Not to be mixed with water. Use this information at your own risk.

This is working well for me. Combined with a massive extension cord, this gives me the flexibility to power what I need, where I need it.

Circles to Rectangles - Tortilla Wraps

Sometimes, algebra and geometry apply to food.

The problem I wanted to solve was how to make a wrap with a single large (10") flour tortilla. Being a perfectionist, I wanted a rectangular tortilla so that the amount of bread was reasonably even through the length of the wrap. With a round tortilla, the ends don't quite enclose the food while the center becomes rather chewy with all the tortilla layers. Knowing that moistening a tortilla and pressing it together will make it adhere, I decided to figure out how to cut a circular tortilla, rearrange the pieces, and wind up with a rectangular tortilla. The strategy I chose was to cut pieces to create corners which could fill the vacant corners.


But where should I make the cuts in the tortilla?

From the diagram, we can describe a few constraints on the lengths and angles.

  1. a + b = r
  2. r * sin(o) = b
  3. r * cos(o) + a = r

Solving the last equation for a yields a = r - r * cos(o). Substituting that and the second equation into the first equation gives r - r * cos(o) + r * sin(o) = r.


r - r * cos(o) + r * sin(o) = r
-r * cos(o) + r * sin(o) = 0
-cos(o) + sin(o) = 0
sin(o) = cos(o)

And for the sine and cosine to be equal, o must be 45 degrees.

Now that we know the angle, we can apply this pattern to a tortilla by eye-balling where we would cut the tortilla if we were to turn it into quarters. Once we have the points around the edge of the tortilla, we can cut opposite chords, then cut those parts into symmetric halves.

wrap-01.jpg wrap-02.jpg wrap-03.jpg wrap-04.jpg wrap-05.jpg

Now that the pieces are arranged, wet them and press them into place with the heel of your hand.


And now we have a rectangular tortilla. Time to add the meat (evenly!)

wrap-07.jpg wrap-08.jpg

and veggies

wrap-09.jpg wrap-10.jpg

and cheese


and dressing


and a dash of fresh ground red and black pepper.


Wet the upper portion of the tortilla


and firmly roll the wrap.


Cut it in half so it can fit in a sandwich bag.


These taste pretty good, if I do say so myself.


And that's how you apply geometry and algebra to get food fit for a perfectionist!

Adhoc RSS Feeds

I have a few audio courses, with each lecture as a separate mp3. I wanted to be able to listen to them using AntennaPod, but that means having an RSS feed for them. So I wrote a simple utility to take a directory of mp3s and create an RSS feed file for them.

It uses the PyRSS2Gen module, available in Fedora with dnf install python-PyRSS2Gen.

$ ./adhoc-rss-feed --help
usage: adhoc-rss-feed [-h] [--feed-title FEED_TITLE] [--url URL]
                      [--base-url BASE_URL] [--filename-regex FILENAME_REGEX]
                      [--title-pattern TITLE_PATTERN] [--output OUTPUT]
                      files [files ...]

Let's work through a concrete example.

An audio version of the King James version of the Bible is available from Firefighters for Christ; they provide a 990MB zip of mp3s, one per chapter of each book of the Bible.

mv -- "- FireFighters" FireFighters # use a less cumbersome directory name

There are a lot of chapters in the Bible:

$ ls */*/*/*.mp3 | wc -l

We can create an RSS2 feed with as little as

./adhoc-rss-feed \
    --output rss2.xml \
    --url= \
    --base-url= \

However, that's going to make for an ugly feed. We can make it a little less awful with

./adhoc-rss-feed \
    --feed-title="KJV audio Bible" \
    --filename-regex="FireFighters/KJV/(?P<book_num>[0-9]+)_(?P<book>.*)/[0-9]+[A-Za-z]+(?P<chapter>[0-9]+)\\.mp3" \
    --title-pattern="KJV %(book_num)s %(book)s chapter %(chapter)s" \
    --output rss2.xml \
    --url= \
    --base-url= \

That's simple, and good enough to be useful. Fixing up the names of the bible is beyond what that simple regex substitution can do, but we can also do some pre-processing cleanup of the files to improve that. A bit of tedius sed expands the names of the books:

for f in */*/*; do
    mv -iv $f $(echo "$f" | sed '

There are a couple of errors generated due to the m3u files the wildcard includes as well as 'Job' already having its full name, but it will get the job done.

Run the same adhoc-rss-feed command again, then host it on a server under the given base url, and point your podcast client at the rss2.xml file.

AntennaPod lists episodes based on time, and in this case that makes for an odd ordering of the episodes, but by using the selection page in AntennaPod, you can sort by "Title A->Z", and books and chapters will be ordered as expected. And then when adding to the queue, you may want to sort them again. While there is some awkwardness in the UI with this extreme case, being able to take a series of audio files and turn them into a consumable podcast has proven quite helpful.

Improving a Damaged Extension Cord

The humble extension cord is frequently overlooked relative to its value in a garage or shop. Over the course of years of abuse, one of my extension cords wound up with a cut in the insulation, exposing the copper wiring. This resulted in an electrical "POP!" when it was pulled across a piece of metal. I cut out the damaged portion of the extension cord, but didn't throw the cord away. Instead, I gathered up some electrical bits from stuff I had salvaged and bought a few parts from the hardware store.

  • two-gang metal box
  • power outlet
  • dual power switch
  • two-gang faceplate
  • two grommets
  • a bit of copper wire

I wired the switch so that one controls the outlets in the electrical box, and the other (the one closer to where the cord leaves the box) controls the plug on the last foot or so of the extension cord.

Pictures showing the internal wiring:

wired-1.jpg wired-2.jpg wired-3.jpg

Ready for the faceplate:


The end result: