Monday, October 22, 2018

Adventures in ratpoison keymaps - Caps Lock, Windows Key and Retraining My Brain

I can't imagine there are ton of ratpoison users out there, but for the benefit of anyone who does discover the greatest all of Linux Window Managers, here's some thoughts on my latest config.

For years, I operated ratpoison with the Caps Lock key set to the Hyper-L key, and Hyper-L set as the primary Escape key:

;; ~/.xmodmap
;; Turn Caps Lock into the Hyper_L key
keycode      66 = Hyper_L

# .ratpoisonrc
escape Hyper_L

This put the easy-to-hit Caps Lock key to good use.

Lately, however, I've been on a mission to turn Caps Lock into a clone of the Escape key. I have this setup on Windows, Mac and my Android device. When I'd fire up Linux, I found myself hitting Caps Lock when I wanted Escape. Except, Caps Lock was already allocated. This past week, I re-arranged things so that ratpoison no longer uses the Caps Lock key as the primary Escape directive. Here's my current config.

First off, I'm using .xmodmap to turn Caps Lock into the Escape key, not the Hyper_L key:

!! Turn Caps Lock into Hyper
clear      lock 
clear   control
clear      mod1
clear      mod2
clear      mod3
clear      mod4
clear      mod5
keycode      66 = Escape  ;; CHANGED
add     control = Control_L Control_R
add        mod1 = Alt_L Alt_R Meta_L
add        mod2 = Num_Lock
add        mod3 = Hyper_L
add        mod4 = Super_L Super_R
add        mod5 = Mode_switch ISO_Level3_Shift

Next, I've setup ratpoison to use Hyper_L, which is the Windows key, as the primary Escape command:

## Thanks to xmodmap, this is my windows key
escape Super_L

##  ___ - bindings
definekey root Up exec chvolume 2%+
definekey root Down exec chvolume 2%-
definekey root Left exec chbrightness dim
definekey root Right exec chbrightness bright
definekey root e exec rpwin goto emacs
definekey root g exec snipit
definekey root z exec xtext ts

I then defined a new keymap, something I'd yet to do previously in ratpoison:

## Make   execute
## what's on the 'custom' keymap
newkmap custom
definekey root Escape readkey custom

To use that keymap, I setup Escape on the root keymap to invoke the readkey command using the custom keymap. In other words, ratpoison listens for a key and when it hears Escape it invokes readkey, which in turn, listens for a new key stroke. This allows you to have arbitrarily nested keystrokes, and is a brilliant way to handle key definitions.

To avoid clashing with existing ratpoison commands, I setup the majority of my custom keys to hang off of this new keymap:

##   ___ - Bindings
definekey custom j exec rpwin restore J
definekey custom k exec rpwin restore K
definekey custom l exec rpwin restore L
definekey custom h  exec rpwin restore H
definekey custom J exec rpwin capture J
definekey custom K exec rpwin capture K
definekey custom L exec rpwin capture L
definekey custom H exec rpwin capture H
definekey custom p exec mkpass | xclip -selection clipboard
definekey custom o exec rpwin goto Gimp

unbind K
bind j nextscreen
bind k prevscreen

Using this config, I now have to press Windows Key - Caps Lock - j to return to the 'j' window configuration. And training my brain to hit the extra key stroke has taken a bit of practice. But in another week or two, this should be second nature.

I've now turned Caps Lock into Escape on all my computers and learned a clever protocol for handling nested key strokes. I'm telling you, ratpoison is the ultimate Linux Window Manager. Try, you'll see.

Friday, October 19, 2018

The Mountains Called. I Answered. A Little.

Getting to run trails in the desert has been a real treat. What runs have lacked in length, they've made up for in interesting terrain. The climbs haven't been easy, but the vistas at the top easily make up for the effort. Wildlife encounters have been sparse: just a road-runner and what appeared to be an itty-bitty hummingbird. But it's the plants, with their nasty collection of thorns, that have really been out to get me.

Happy Trails indeed!

Tuesday, October 16, 2018

Gotcha of the Day: A Quick and Dirty Approach to Comparing Apache Web App Running Times

For the last couple of days I've been troubleshooting a customer's server. I ended up firing up a replacement server and found myself wanting to compare the two. One simple approach I've used in the past to do this is to add a new Apache log configured to capture timing information. Adding this to Apache is easy, just add the following to the relevant virtual hosts:

CustomLog logs/ssl_timing_log "%{ms}T:%U:%a"  # « Added this custom log
ErrorLog logs/ssl_error_log
TransferLog logs/ssl_access_log

With this configuration in place, Apache now generates ssl_timing_log which has this shape:


The leading number is the number of seconds it took to generate the page (hopefully 0!).

I collected up this timing data on both the old and new servers and then analyzed the data with this quick and dirty PHP script:

$fd = fopen($argv[1], "r");

$min = [];
$max = [];
$avg = [];
$cnt = [];
while($line = fgets($fd)) {
  $line = trim($line);
  if(!preg_match('/^[0-9]/', $line)) {
  list($t, $u, $i) = explode(":", $line);
  $min[$u] = min(g($min, $u, $t), $t);
  $max[$u] = max(g($max, $u, $t), $t);
  $avg[$u] = isset($avg[$u]) ? ($avg[$u] + $t) / 2 : $t;
  $cnt[$u] = g($cnt, $u, 0) + 1;

uasort($cnt, function($a, $b) {
  return $b - $a;

$i = 0;
foreach($cnt as $u => $t) {
  echo sprintf("%-80s %0.2f - %0.2f - %0.2f | %d\n", $u, $min[$u], $avg[$u], $max[$u], $cnt[$u]);

  if($i > 50) {

function g($a, $i, $d = false) {
  return isset($a[$i]) ? $a[$i] : $d;

Here's a sample, yet masked, run of the script:

$ sudo php analyze_timing_log.php /var/log/httpd/ssl_timing_log
/                                                                       0.00 - 0.00 - 1.00 | 3777
/xxxxxxxxxx/                                                                     0.00 - 2.00 - 11.00 | 889
/xxxxxxxx/xxxxxxxx/                                                              0.00 - 0.26 - 2.00 | 673
/xx-xxxxxxx/xxxxxxx/xxxxxxxxxxx/xxx/xxxxxxxxx/                        0.00 - 0.00 - 0.00 | 363
/xxxxxxxx/xxxxxx/                                                                0.00 - 0.00 - 0.00 | 359

The values shown are min, average, max and request count for a given path. The paths are sorted with the most frequently accessed pages at the top.

The results of this testing gave me confidence in the new server. This timing_log hack may be crude, but it runs anywhere Apache does and makes for command-line friendly data sets. It just works.

Monday, October 15, 2018

Bringing a Bic Lighter Back from the Dead

I found not one, but three discarded lighters while running yesterday. I picked one up, planning to convert it to a handy Spark Lite fire-starter knock-off. Rather than grab a needle nose pliers and other tools, I decided to see if I could do the conversion using whatever items I had on my keychain. My thinking: if I ever needed to turn an empty Bic Lighter into a sparker in the field, I probably wouldn't have the benefit of a toolbox to rummage around in.

I used a P-51 can-opener to gently pry the metal cover off. From there, I used no tools, just gentle pressure to unsnap the rest of the components. The tricky part was getting the tiny flint back into the spring-loaded chamber. I managed to launch both the spring and flint into the air, and spent most of the the build time on my hands and knees looking for these fly-away parts. I used my keychain tweezers to help set the flint back in place.

For just a couple of bucks, it's hard to imagine a more glorious piece of gear than the Bic Lighter. Even out of fuel, it still has much utility to offer.

Sunday, October 14, 2018

Hiking Frankling Mountain State Park - Sunset Loop Trail

Yesterday we completed a delightful hike through Franklin Mountain State Park. We attempted to follow the Sunset Loop Trail but wandered off it a couple of times. The desert landscape was truly gorgeous, and the generous cloud-cover meant that we never suffered under the heat of the sun.

We saw almost no wildlife (unless you count trail runners as wildlife), just a few birds and a few bugs. Comparing one of those bugs to this infographic tells me that we may have found an Arizona Bark Scorpion. He was hiding under a random rock I picked up to inspect. I assumed he was a harmless baby, but the web tells me otherwise. Apparently Bark Scorpions are the most dangerous scorpion in the US, and the venom is quite poisonous. So yeah, be careful which rocks you pick up while in the park.

Here's a few tips that I'd wish we had known about the Sunset Loop Trail before starting it:

  • While the trail does connect the Lower and Upper Sunset Trails, it starts on the Bike Loop trail. To begin the hike, head North West from the parking lot to find the Bike Loop Trail.
  • I missed that the trail incorporates Bike Loop and started us off by taking a trail down from the Overlook near the parking lot area. That trail took us to Lower Sunset Trail, it's just not what the hike calls for. We were able to re-join the recommended hike by following the Lower Sunset Trail North.
  • Nearly all the trail junctions lack usable signage. Most contain no signs, some contained numbers that didn't mean anything to us. There's also no blazes or trail markings to be found. So do be careful that you don't wander off trail.
  • Despite being named the Sunset Loop trail, the route leaves the Lower Sunset Trail and heads off into territory that the map shows no trail for. We found trails to follow out there, but they required Shira keep an extra close eye on the GPS to make sure we were on course.
  • The Upper Sunset trail is appropriately named, as it takes you up onto a ridge. This makes the last mile or so of the hike physically more challenging than all the previous miles. The views from the Upper Sunset trail are well worth the effort. The trail never gets especially technical and my fear of heights never kicked in.
  • The route is marked as Hard, and I'm not entirely sure it deserves that rating. The lack of blazes and the fact that the route leaves established trails does make this one trickier to follow. And the Upper Sunset Trail will get your heart pounding while climbing onto the ridge. But there was nothing technical or terrifying about this hike, and it wasn't especially long.

All in all, it's a great hike and was a terrific way to soak up some desert rays!

Thursday, October 11, 2018

A Travel Photography Checklist

Inspired by my Digital Packing Checklist, I decided to make a similar one for photo gear.

Deliberately walking through this checklist, I've found I can sidestep a number of photography traps. From the annoyance of DSLR pictures with incorrect timestamps, to the agony of capturing important photos with the quality setting set to low, to a smattering of issues in between, this list has me covered.

I'm careful to review this list for each camera I'm bringing, though obviously some steps don't apply to some devices.

  • Clean lenses and look for damage.
  • Consider replacing UV filters used to protect lenses.
  • Insure batteries are fully charged, and noted as such.
  • Insure the date and time is properly set.
  • Set the timezone where you'll be shooting pictures. Insure the daylight saving option is correctly set.
  • Review photo quality setting, insure the highest quality setting is selected.
  • Review the age of SD cards and consider replacing them.
  • Purge SD cards of old photos.
  • Purge backup areas of old backups.
  • Run your photo backup procedure, insuring all cards are backed up.
  • Check cloud backup settings to insure 'Original' photos are being saved. Review Roaming and Upload over Cellular options.

Happy shooting!

Wednesday, October 10, 2018

Courage, Bravery and Life Before GPS

I'm making my way through Phantom Warriors, a series of stories about Long Range Reconnaissance Patrols that operated during the Vietnam War. It's hard to overstate how remarkable these stories are. Take your most riveting, white knuckle adventure movie, add it to the most courageous, brave and skilled characters you can imagine, and you still won't match the tales in this book. It's that good.

One observation I've had while reading this book is how modern a war Vietnam was. The soldiers have relatively reliable communication systems, air support from helicopters and fighter jets, on-demand artillery and plenty of on-person fire power. One obviously lacking piece of tech: GPS. While in the field, soldiers had to depend on map, compass and protractor for their navigational needs.

Under ideal circumstances, this meant navigating thick jungle for days without established routes. But these soldiers never operated under ideal circumstances. Walking in a straight path was a recipe for being ambushed, so they followed strategies to randomized their path. To avoid discovery, they avoided well known trails. The consequences of getting it wrong could be deadly; from a missed landing zone to calling in artillery fire on your own position. And all of this navigation needed to be completed under massive stress. It's one thing to subtract two angles in a classroom, it's altogether a different prospect when someone is shooting at you.

Like I said, these guys had mad skills.

Inspired by the living history community's philosophy that hands on activities are the best way to understand the past, I downloaded FM 3-25.26, the Army Land Navigation Manual, grabbed a few paper maps and started playing around. What better way to appreciate the challenge of map and compass navigation than to try it out?

Here's a few take-aways from this experiment:

Margin notes are key. In classic bureaucratic style, FM 3-25.26 lists 23 different pieces of information that are contained in the margins of a military map. Can you think of anything more mundane? Yet, to my surprise the physical maps I'd grabbed off the shelf had many of these same pieces of information. And more importantly, many of the notes were quite useful. I'd never stopped to consider them, writing off much of the text as fine-print legalese.

Latitude and longitude math is painful. One of the table top exercises I went through was deriving coordinates from a position on a map and finding a position on a map given a set of coordinates. I did this using the Monongahela National Forest map, which is marked off in 0°7'30" intervals. I found myself needing to answer questions like: What's 5/11ths of 0°7'30"? The answer: write some code to find out.

I grabbed my cell phone and coded up a quick Scheme library to work with degrees, minutes and seconds (DMS). You can find the code for the library here. Here's an example of me using this code to derive coordinates that are 5cm above, and 3.75cm to the left of a particular point on the map:

 (let* ((grid-size (dms->sec '(0 7 30)))

        (lat (sec->dms (+ (dms->sec '(38 52 30))
                          (* grid-size (/ 5 11)))))

        (lng (sec->dms (+ (dms->sec '(79 37 30))
                         (* grid-size (/ 3.75 8.5))))))

   (string-append (dms->string lat "N") ", "
                  (dms->string lng "W"))))

While this exercise is simple math (it's all based on proportions), I found every possible way to screw it up. Which leads me to my next point.

The UTM grid is awesome. After futzing with latitude and longitude, I quickly came to appreciate the value of the UTM grid. Being able to work in meters, rather than DMS values, is such a win. The Military Grid Reference System, which sits on top of the UTM, is also quite clever. I love the notion that you can lop-off digits from a series of coordinates to give a rougher, yet still valid, description of a location.

As I've poked around maps, I've also come to appreciate that UTM Grid isn't the only game in town. The USGS Virginia Map, for example, notes the presence of the Virginia and Maryland Coordinate System which is marked off in 100,000 foot increments. This tidbit is in that fine print I'd normally gloss over.

My little experiments may expose a bit of the how these soldiers were able to accomplish their task, but the fact that they did it so routinely, and under such difficult circumstances only underscores their remarkable skill and courage.

Next up: I need to get out into the field and try some of these techniques. Preferably without someone shooting at me.

Tuesday, October 09, 2018

Wait, That Can't Be Right. Can it?

Over the weekend, while walking along the Mall, the group I was with spotted this guy:

I do believe that's an albino squirrel! It even had red eyes to match its white fur. Apparently, seeing white squirrels in DC isn't unheard of, but still they're rare. I'd certainly never seen one.

There was a family next to us, and as if to check my own sanity, I asked them if they'd ever seen a white squirrel. Their response: we're from Australia, until last week we'd never seen any kind of squirrel.

The next day, while driving across the Woodrow Wilson Bridge I spied a distinctive looking plane along the Potomac river:

Given the color and size of the plane it seemed like it was almost certainly Air Force One. But, and I double checked this to be sure, there's no runway anywhere near where it was parked. And even if there was one, what would it be doing there?

A quick Google search explained the mystery. What I was looking at was a replica of Air Force One, not the real one. Still, I'm surprised that I could recognize this plane from so far off.

Apparently, starting on October 19th, you can tour the replica and get a sense of what it's like to truly travel in Presidential style.

Thursday, October 04, 2018

A Little Mid Flight Color Hacking

While I work with colors all the time while building apps, I still have questions. What's the best algorithm for fading between colors? Is there an optimal way to randomly select a color scheme? How can you programmatically decide what color text is legible on a given background?

I used one of the flights this last summer to build a small JavaScript library to let me investigate these questions. Because I was mid flight while building this code, it meant that I was programming this on my Galaxy S9+ phone without the benefit of the Internet. This library was less about building a production tool and more about fully understanding a topic.

While planning out the library, it occurred to me that I could get by with two core components: an abstract representation of colors and a classic 'fold' function. Implementing a representation would let me stop thinking of colors as hex sequences (#A23F40) and start thinking them as a cluster of red, green and blue values (say, 63% Red, 18% Green, 25% Blue). The fold function is also a no-brainer, as it lets you implement map, filter, for-each and countless other functions by cleverly providing a different function and init value.

In terms of implementation, given the graphical nature of the task, it seemed programming directly in JavaScript would be ideal. But that led me to one of my first challenges: how can I get the browser on my phone to effortlessly load a particular JS file?

A solution came to me in the form of the utilitarian, yet powerful, kWS web server. This app turns your phone into a web server, hosting the directory of your choice on the port of your choice. In my case, I configured the server to show /sdcard/Projects on port 8080:

With the server running, I created a simple bootstrap HTML file:

I was able to execute main.js by visiting: http://localhost:8080/color_hacking/. Thankfully, there's no caching, so every change requires only a simple browser reload to view it.

With the development strategy figured out, I went to work building my library. First off, I tackled the representation issue by implementing cpack and cunpack. This let me write code like so:

var bg = cunpack("#A23F40");
var inverted = { red: 1 -, green: 1 -, blue: 1 - };
var hex = cpack(inverted);

cfold was even easier to write. This function takes in a start and end color, a number of steps to transition the colors, an initial value and function which is delivered each of the color steps. Here's an example of generating 100 different colors between #0000AA and #FFAA00:

var html = 
  cfold("#00 00 AA", "#FF AA 00", 100, "",
       (html, color) => {
        return html + "<div style='height: 3px; background-color: " + cpack(color) + "'></div>\n";

You can find the complete source code for the library here.

This was a fun exercise. While I still have my questions from above, I've got a clearer understanding as to how I might solve them, and I've got a handy library to help. If nothing else, working with kWS has added a new tool to my mobile-development toolbox.

Here's some screenshots that were generating using my library:

Wednesday, October 03, 2018

Dave Chappelle - From Cruel and Insensitive to Brilliant and Thought Provoking

Dave Chappelle's How Old is 15 Really? starts off irreverent and gets downright cruel from there. But wait for it, he delivers a surprisingly poignant bit of commentary by the end:

This video is as relevant today as it was when it was posted 9 years ago. And while we may be living in the golden age of comedy-as-education-vehicle, it's still impressive when this is done right.

Put another way: want to change the world? Use what got. And as Chapelle shows us, if you've got jokes, that will do nicely.

Thursday, September 27, 2018

Review: Drawing with Children

I reluctantly checked out Drawing with Children by Mona Brookes from the library. I've experimented enough with sketching to be confident that what's holding me back isn't a particular skill or bit of wisdom, but the commitment to practice, practice, practice. At least, that's what I assumed. Still, I have a firm policy when visiting the library: if a book sparks even the slightest interest, I check it out.

When it comes to learning to draw, I'm a fan of Danny Gregory's approach. I'm oversimplifying here, but it essentially works like this: learn a few basic concepts and then practice daily. Eventually, you'll start creating drawings you're proud of.

As I perused Brookes' Drawing with Children I realized that her method falls on the other end of the structured-learning spectrum. She covers topics from creating an art-friendly environment, to specific language students can use to analyze subjects. She provides exercises and specific works to draw that maximize a learner's chance of success.

Some may chafe under this regimented approach, but I've grown to see it as something quite positive. Through carefully planning Brookes has flattened the learning curve of drawing. If, for example, I had the opportunity to teach my niece to draw I'd almost certainly use Brookes' approach.

But the impact of Drawing with Children on me didn't stop there. It provided me with nothing short of a sketching epiphany. On page 114, in classic Brookes style, she spells out a 20 step algorithm for creating a drawing. This starts with warm-ups and ends with finishing touches. In her recipe she instructs students to start with a central point and build out from there. You see this approach in the sample drawings in the book. For example, one still life starts by drawing the knob which sits on top of the tea pot, which is one of the primary objects in the scene.

I realized this is exactly the opposite strategy I've been using for drawing. I've been attempting to draw the bounds of the scene and fill in detail from there.

Consider these objects:

I'd normally attacking this drawing like so:

The problem with this strategy is that I need to maintain a mental map as to how the contour lines I've drawn correspond to the scene. Compare that to Brookes' method, which focuses on drawing the focal point and building out from there:

I had assumed my frustration with drawing was lack of practice and general anxiety about failing. Instead, I realized I'm just trying to hold too many complex ideas in my head at one time. Using Brookes' approach, I was able to finish the sketch with relative ease:

The contour-approach I started above clearly has value. I think the proportion between the phone, medicine bottle and Lego-character is more accurate than my second attempt. But what good is accurate proportion if the process is mentally exhausting?

Perhaps I'll graduate away from Brooke's approach, but for now I'm telling you, this is a game changer.


Related Posts with Thumbnails