Bike to work: the month of May in review

I was only able to bike to work 8 times in May, due to a variety of reasons.. early in the month, I caught a cold, and various obligations at home made it necessary to take the car on several days I otherwise would have biked. Later in the month, I had a week where I couldn’t drag myself out of bed in time to get moving (it’s amazing how much a single late night out screws up my body clock nowadays). I also had this mysterious dry cough that came out of nowhere and persisted for about 4 days. But, now it’s the end of the month and I seem to be back in a good routine. Despite the relative infrequency of my rides, I managed to ride in at least one day each week of the month. My average speed is now consistently over 14mph. This morning I averaged 14.8mph, my high for the season so far.

This past weekend, I picked up two new pairs of biking shorts on sale at Performance. One has the standard chamois padding and the other has this gel stuff. The price was the same, so I figured I’d try ’em both. I’ve ridden once with each pair now. The chamois pair is fine, but the stitching on the gel pair bothered me a little bit. I’ll see how it goes as they break in, but so far I’m not crazy about these.

I’ve also logged almost 1000 miles on my cyclocomputer, a Cateye Astrale. Verdict so far: It’s nice, and I especially like the cadence feature. However, I wish it gave some kind of audio feedback when starting/stopping the timer. There have been a lot of times where I’ve thought I’ve started it but it wasn’t actually running, and vice-versa, and as a result I haven’t gotten any statistics for a particular ride. Forgetting to start/stop it is one thing, but it’s really annoying when I’ve actually made a point to do it, and still don’t get my stats. Otherwise, though, I really like it. Cateye has come out with a newer model since I got mine, so I wonder if they’ve addressed this problem.

June will start out with a week of no biking due to my business trip. However, I hope to get right back into it afterwards.

Next year’s pool project

I’m already thinking about next year’s pool project, and I haven’t even started this year’s yet…

For next year, I’m considering adding an automatic chlorine feed using a chemical metering pump, similar to the setup described here. The main goals of the project would be:

  • Save work;
  • Save money on chlorine by matching the supply more closely with the demand;
  • Provide a continuous feed of sanitizer, thereby eliminating the need for cyanuric acid in the pool.

If I go ahead with this, I’ll probably also move the pool’s electrical controls indoors, which I’ve always wanted to do for convenience more than anything else. I’d also need to run a dedicated 110VAC circuit to power the metering pump, so while I’m at it, I’ll install a convenience outlet near the pool equipment. Right now, I only have 220VAC there.

The metering pump can be had from Grainger for around $300, but I’m watching eBay to see if I can get a new one cheaper.

I’ll add random notes to this entry as I think about this one.

Portal Meltdowns

We had another portal meltdown this morning. I figure I’ll keep a “meltdown log” of sorts to record notes, etc. Hopefully it’ll help me get to the bottom of this.

Background: Every so often, the portal becomes unresponsive. There seems to be no correlation to system load (high demand etc). For example, spring final exams ended yesterday, and today is one of the quietest days of the year around here. Yet we had a meltdown this morning.


  1. In portal.log, there are always lots of these DBCP-related errors.
  2. The portal fills up its DB connection pool very quickly and I often see log messages that the pool is “exhausted”.
  3. Lots of ALM-related infinite loops, in getFirstSiblingNode and others. I’ve put loop-breaking code in various spots; otherwise, all the busy-looping threads would kill the JVM pretty quickly. I have it logging the portal userid when this happens, and it doesn’t seem to be limited to specific users. In fact, I picked one from an error log, checked his portal account later, and it worked fine.
  4. When the problem is occurring, restarting the portal (web server, JVM, the whole 9 yards) does not fix the problem.
  5. Both portal server boxes (uportal1 and uportal2) are always affected at the same time, ostensibly ruling out an issue involving the OS, Apache, or Tomcat.

I did a JVM thread dump. One thread was hung doing a database commit (?!?) inside portal.RDBMUserLayoutStore.getNextStructId, a synchronized routine. All other threads (98 of ’em) were hung waiting on this one thread.


Sometimes, this problem magically resolves itself. Other times, it’s resolved after the DBA restarts the Oracle instance. We’ve hypothesized that this is being caused by an errant app running at the same time, which is dragging down our database instance. I’m not sure if I buy that or not. But right now it looks like, somehow, a thread is hanging inside a critical section, thereby locking up all the other threads; and the locked threads are all grabbing DB connections from the DBCP pool and never releasing them, thereby hosing up the pool. Next time it happens, I’ll do another thread dump and see if the lockup is in the same spot.

I also did a dump of active portal sessions to see who was logged on around the time of the meltdown. When it happens again, I’ll do another dump and cross-check the two, to see if a particular user or users might be causing the problem.

6/1: Happened again. Lockup occurred in exactly the same spot, with all threads locked waiting on another thread trying to do a database commit. WTF is going on here..

Today’s PAGS tweak

Today I fixed the latest crop of users with portal-access issues: Previous students who took a semester off, or never completed a degree, who want to use myUMBC to register or retrieve a transcript. These students do not have a student affiliation in LDAP, because they’re not “current” students. They also lack an alumni attribute as they never completed degrees. As such, they don’t see the “Academics” tab because we limit display of this tab to users with student or alumni affiliations (well, and a few others as well, but that’s beside the point right now).

Our LDAP directory does not have an affiliation for “past-student-who-never-graduated”. However, we have an attribute for the last term a user was registered for classes. In theory, if a user possesses this attribute, that indicates that they were a student at some time in the past. We can give them the “Academics” tab by expanding the UMBC Student PAGS group to include people with this attribute.


Laundry list for doing this:

  1. Make sure the LDAP attribute in question is available in uPortal as a Person Attribute. If not, add the attribute to PersonDirs.xml.
  2. Edit PAGSGroupStoreConfig.xml and add any new groups (or edit existing ones) to incorporate the new attribute.
  3. Redeploy, restart and hope it doesn’t bomb.

In our case, I added an additional clause to check for presence of the umbclasttermreg attribute using the PAGS “Value Exists Tester”, org.jasig.portal.groups.pags.testers.ValueExistsTester.

The PAGS entry on the JA-SIG Wiki has improved quite a bit since I last visited it. Caveat emptor: It references ValueExistsTester and ValueMissingTester. Initially I blindly followed the docs and tried to use ValueExistsTester, and things didn’t work. It turns out these two testers are not present in uPortal 2.4.3.. I had to add ValueExistsTester manually. It’s only around 10 lines of Java, but the Wiki ought to mention that it’s not in 2.4.3.

Dell Widescreen Monitor + Linux: Utter & Complete Frustration

I just wasted an entire day trying to get a new Dell 2007WFP working with my 3-year-old Dell GX270 desktop, which runs Debian. The result: total failure. It works at 1280×1024 (and looks all stretched out), but flatly refuses to work at the monitor’s optimal resolution of 1680×1050.

In the xorg.config file, first I tried just adding a new “Screen” resolution for 1680×1050. This failed with “no such mode” or somesuch. After much head scratching and googling around, I learned that I needed to patch my video BIOS (Intel 810 series) to add the new mode. I did this via a utility called 915resolution. This seems to work.

With 1680×1050 programmed into the BIOS, I then tried several different ModeLine entries in the config file, with varying different modes of failure. At certain settings, X would refuse to use the mode, complaining about “vrefresh out of range” or something. At other settings, when I started X, the monitor would go into power-save mode as if it wasn’t receiving a signal. At other settings, the monitor would display a message stating that the signal was out of range and it couldn’t use it. I fiddled with turning DDC on and off, to no effect. Everything I tried resulted in one of these three failure modes. I’m pretty sure I’ve got good ModeLine numbers, as they match what’s reported by DDC in the log.

I’m pretty much at my wit’s end here, so I’ve given up for now and am back to using my old dual-monitor xinerama setup. Needless to say, I’m not too high on the whole Linux/X desktop scene right now. I’m ready to punt the thing and go to a Mac.

Portal session management tweak

I’ve decided to work a little harder to make myUMBC work for more users. Of course, the ulterior motive is to save work for myself and the help desk. Actually, sometimes my entire job seems geared towards doing things to save myself work. I guess once I’m completely successful, I’ll be able to just sit around my office and surf porn all day long. But anyhow..

We really need a way to make myUMBC work for people without a SSN (soon to be HP-ID) attribute in LDAP. Background on this problem is here. These people are able to log into the portal, but since we can’t look up an identifier for them, we can’t authenticate them to the legacy portal code. As a result, they can’t properly render any of the web proxy channels served by the legacy portal server. These channels handle all of myUMBC’s SIS related functionality (IOW, most of what you currently would want to do in myUMBC), so in effect, this leaves these users dead in the water.


Now, unless we know the user’s HP-ID, the user still won’t be able to do anything really useful in the portal. However, we’d still like for them to be able to navigate through the portal and see the channels. To fix the user “for real”, we need to do one of the following:

  1. Manually query SIS to see if the user has an HP-ID. If so, check LDAP to see if the user has multiple entries, and merge the entries if necessary. Otherwise, manually add the user’s HP-ID to LDAP, so we can map the username to the HP-ID. If no HP-ID in SIS, instruct the user to contact the registrar’s office and request one.
  2. Do nothing, and hope the problem resolves itself (might just have to wait for the user’s info to percolate through the various systems of record).

What we’d ideally like to do, is get the portal to do the work for us. If a user logs in and we can’t find an HP-ID for them, we need to get in their face and tell them to contact the registrar to correct the problem (duplicate LDAP entries are a difficult issue, though.. I’m hoping that some of our problems with them will go away after we finish with SSN remediation). But in the meantime, we should make portal navgation work for the user, so they can at least get to functionality that doesn’t require a “real” HP-ID.

The solution I came up with, was to assign the user a “fake” HP-ID on the fly when they initially log in. We can then use that as a primary key for the legacy session management table (auxil.www_sessions), and the user will be able to render the legacy web proxy channels.

The basic logic for getting a session table key now looks like this:

  1. Query auxil.myumbc_user_preferences table for an SSN (HP-ID) that matches the user’s UMBC username. If successful, use that. This allows us to map the user’s LDAP SSN to the SIS SSN when the two differ, which happens a lot when the user’s SSN changes and the change hasn’t percolated to one or the other system. Hopefully, we won’t need this step after SSN remediation, because the HP-ID is never supposed to change.
  2. Query LDAP for the user’s SSN (HP-ID). If successful, use that.
  3. If we couldn’t find the SSN that way, query the legacy session table for a temp SSN matching the username (indicating that we’ve already created them a temp identifier). If we find one, use it.
  4. If all else fails, generate the user a temp identifier within a specified range (currently 995000000-995999999) and use that.

The user is thus able to render legacy channels right away. And the nice thing here, is that once the user gets a “real” SSN (HP-ID) in our system, it’ll automatically stop using the temporary one without any intervention on our part.

All of this magic happens in edu.umbc.uportal.UmbcPersonFactory, which currently lives in the main uPortal source tree.

I have this in production now, and I’ll be keeping an eye on it to see what problems develop. If it seems to be working, we’ll need to see about somehow hassling the user to get the problem rectified. This might be something to do via the big, fancy, vaporware alerts system we’re supposedly launching this fall.

The fun never ends..

Leaf Blower/Vacs: Echo vs. Toro

Here we have it: a head-to-head comparison between the Toro Super Blower/Vac and the Echo ES-210 Shred ‘n Vac. I’ve used the Toro for 3 or 4 years now, and recently bought the Echo. First things first: I’ve always liked the Toro. But, it’s electric, and the cord has always driven me nuts. One of the things I use it for is clearing around my swimming pool. And, corded tools and swimming pools just don’t get along well. Half of the time is spent routing the cord so it doesn’t fall in the pool or get snagged on stuff. And then, the cord is never quite long enough to go everywhere I need to use the unit. So, my primary motivation for buying the Echo was to get a unit that performs similarly to the Toro, sans cord. With that in mind, here’s how the units compare in various departments.


Performance: Both units have about the same amount of power, that is to say, they’re both adequate for clearing paved surfaces, which is my primary use for them. The ES-210 has Echo’s smallest blower engine (21.2cc). It’s not going to move big piles of wet leaves in tall grass, but that’s not what I bought it for. Vac performance is similar for both units as well.

Controls: The Echo is a little more versatile in that it has a gas engine with a variable throttle, so I have more control over the blower velocity. The Toro has a two-speed motor (although there is a different model available, the “Ultra Blower Vac”, with a variable speed motor).

Ergonomics: Being gas powered, the Echo is heavier than the Toro, with a dry weight of 9.7lbs plus the weight of the gas. That’s a tradeoff you have to make with gas vs. electric. Operator fatigue will become an issue with any handheld blower after a certain amount of time which varies inversely with the weight. However, for the length of time I typically use the thing, it hasn’t been a problem for me. FWIW, 9.7lbs isn’t too bad as far as handheld gas blowers go — Echo’s next model up, the ES-230, is almost 2 pounds heavier.

In vac mode, the Toro’s ergonomics have always seemed a little awkward to me. The Echo is better in this department.

Convenience: For blowing, you can’t beat a gas blower for convenience. Just take it down, start it up, and blow away. No cord to unspool, set up, and put away when you’re done. Of course, that convenience goes away if the blower doesn’t start easily. With two-cycle gas engines, it’s worth it to pay a bit more and get a brand like Echo or Stihl. The payback is an engine that starts reliably every time, and saves countless hours of aggravation. Don’t waste your time or money on cheap two-cycle engines.

With these particular units, another important convenience aspect is the ease of converting from blower to vac and back again. The Toro has the edge here. With the Toro, I can convert in just a few seconds. All of the pipes have quick release tabs, so it’s just a matter of pulling off the blower pipes and snapping on the vacuum pipes and bag. With the Echo, I have to twist the blower pipe on and off, which is harder to do than with the Toro. Then I have to secure the vac pipe to the unit, which requires a screwdriver to tighten a band clamp. Tho whole process takes a couple of minutes, which is still acceptable, but it’s slow and cumbersome compared to the Toro.

Maintenance: Another department where the electric wins, for obvious reasons. A gas engine requires periodic maintenance while an electric one doesn’t. Of course, there’s not too much that needs to be done with a two-cycle blower.. very few moving parts, no oil to change, etc. End-of-season maintenance shouldn’t take more than 10 or 15 minutes. In my case, I already have 6-odd other gas engines that I maintain, and taking this one on wasn’t really an issue for me at all.

Price: Toro: $60. Echo: $200. Nuff said 🙂

In conclusion: It’s hard to go wrong with either unit. The deciding factor is the cord. If you can deal with the cord, buy the Toro. If not, buy the Echo. Of course, you may think you can deal with the cord at first (as I did), and then find that it’s too much of a hassle. In my case, it’s also a potential hazard. So, I switched to gas and I’m happy. YMMV!

Pool still covered

Yesterday was supposed to be the big pool-uncovering day, but it didn’t happen. The original plan was to open it early so I could get my coping project underway. But, yesterday it occurred to me that I could get started with the cover still on, and just pull the cover back to expose whatever area I happen to be working on. At that point it became a no-brainer: Leave the cover on for now and avoid the hassle of keeping the pool clean in late May when no one is using it.

I already had my help on the way over, so instead of uncovering the pool, we tackled the time-consuming job of scraping the old caulk out of the coping expansion joint. This was fairly easy to do with box-cutter type utility knives and plenty of sharp blades. However, on the decking side, it left a bit of residue because of the roughness of the concrete. I may try wirebrushing this area to get the last bit of caulk out.

Next up is to rent the big concrete saw and cut a true expansion joint (removing the caulk revealed that, as I expected, the joint is non-true around the entire perimeter of the pool). My current plan is to take a day off work and do it the week after Memorial Day. I’d like to get it done before my Vancouver trip; otherwise it’ll have to wait until June 10 at the earliest. Come to think of it, I suppose there’s nothing stopping me from doing it this week, either.. To deal with the dust, I’ll try duct-taping a tarp to the coping edge. With the cover still on, it’ll support the tarp and keep it from submerging. It might work.

I did my first water test yesterday, and surprisingly the numbers weren’t too bad: Free Cl 1.4, Combined Cl 0.2, pH 7.7, Alk 80, Hardness 170, CYA under 30. Water temperature was 63°. I’ll probably add some chlorine today.

Out-of-control Azaleas

It’s azalea-pruning time of year again. I’ve got a multi-year project going to tame the two huge azaleas outside our living room window. They were neglected for a long time and have gotten very leggy, woody and overgrown. One of them is actually two azalea bushes that have grown together. The big ones are way too big for their britches — that is, aesthetically, they don’t work well right alongside the house. I’d love to transplant them somewhere they can bush out to their hearts’ content. Then, I’ll get some more little dwarf azaleas to plant next to the house. The U.S. National Arboretum has a very informative Azalea FAQ page. An excerpt:

Azaleas have very shallow root systems, so even large azaleas may be successfully transplanted. It is important to dig a wide root ball. Don’t worry about digging deep into the soil since most azalea roots are near the surface. The best time to do this is early spring or early fall when the weather is cool. Begin by preparing the new planting site. Then dig the azalea, preserving a root ball as wide as can be safely moved. You can lift it onto a tarp and then use the tarp to drag the plant to its new location rather than picking it up. Be sure not to plant the azalea too deeply and water it thoroughly after transplanting.

So it seems like it should be doable. Maybe I can put it on the plate for this Fall.

More on Ademco Keyfobs

We’ve been using keyfobs with our security system for a couple weeks now, which is enough to get a good feel for how they work. First off, the reliability is a lot better since I relocated the panel’s wireless receiver about 40 feet closer to the garage door area. I have a feeling that the house’s aluminum siding was interfering with reception in the receiver’s old location.

Currently, I have the fobs programmed to arm/disarm totally independently from the garage door opener. That is, two keypresses are required when either coming or going: One to arm/disarm the system, and another to open/close the garage door. This has proven to be a little inconvenient, particularly when arming/closing/leaving. This particular process would be a lot smoother if I could get the “arm” button to shut the garage door as well as arming the system. I’ve come up with a tentative plan to accomplish that, if it works.


First things first: For this to work, the garage door needs to be set up as what Ademco calls a “vent” zone. With a vent zone, the system can be armed while the zone is faulted (i.e. the garage door is still open). Then, when the zone is restored, it is automatically armed. To set this up on my panel, I had to define a custom zone type for the garage door. See your panel docs for details.

With that out of the way, the plan is to use two dry-contact relays (these are provided by the panel as on-board triggers, as well as by zone expanders and add-on relay boards):

  1. Wire the two relays in series (connect N.O. terminal from relay #1 to C terminal on relay #2)
  2. Connect C terminal from relay #1 and N.O. terminal from relay #2 to the terminals on the garage door opener
  3. Program relay #1 to activate (close) when garage door zone is faulted and open when zone is restored
  4. Program relay #2 to close for 2 seconds when “Arm” button on keyfob is pressed
  5. Program both relays to close for 2 seconds when “Door” button on keyfob is pressed

Explanation: The garage door operation is controlled by shorting two terminals together. If you do this when the door is closed, it opens, and vice-versa. With this method, we have no idea what state the door is in. So, we can’t use a single relay and just blindly close the contacts when arming. Otherwise, if we armed when the door was already closed, it would open, which we obviously don’t want.

To get around this, we need some way to tell whether the door is open or closed. That’s where the garage door’s zone comes in. We assume that if the zone is faulted, the door is open, and if not faulted, the door is closed. So, wire two relays in series, so that when both are closed, the door triggers. Then program one to close only when the garage door is open (faulted), and the other one to close when the “Arm” button is pressed. So when arming with the fob, the door is only triggered if it’s already open. This should work reliably almost all the time; the door can occasionally get into a half-open state where the zone will be faulted but the door will open when tripped. But, this doesn’t happen all that often, and just tripping it again will close it.

For the “door” button, which triggers the door regardless of its state, we just program both relays to momentarily close. This unconditionally triggers the door. Only one potential “gotcha” here: I’m not sure what the panel will do if a relay is already activated and we send it another signal to momentarily close the relay. We need it to keep the relay activated. If it doesn’t, there’s a chance that the zone-activated relay could end up open at the wrong time, and the “Arm” button then wouldn’t close the door as expected. In this case, we’d need to add a third relay in parallel with the opener, to handle the “door” button. But I’m hoping that won’t be necessary.

What about disarming, you ask? Can we get the system to disarm automatically when the door is opened via the keyfob? Well, here’s the deal. When arming, you always want to close the garage door. However, the inverse is not always true: You might want to disarm the system without opening the garage door. So, for now, I’ve chosen to leave this as a two-step process. I may rethink it down the road.

5/18: I’ve been kinda busy to do much with this the past 2 days, but this morning I got around to doing a brief proof-of-concept, to see if the panel could activate two relays simultaneously. I currently have a keypad function key programmed to trigger the garage door opener. There are two steps necessary to set this up:

  1. Program the function key for “Device Activation” (*57)
  2. Program an output action (*80), triggered by “zone type” 66 (function key), which closes the garage door’s relay for 2 seconds when triggered.

To do my test, I just added an additional output action to turn an X10 light on/off with the same function key trigger (zone type 66). It worked — when I pressed the function key, the garage door opened and the X10 light turned on at the same time. That bodes well for this project; I should be able to do it with 2 relays and a bare minimum of wiring. Stay tuned!

5/19: Work on this continues at a glacial but steady pace. Today I identified the relay wires on the zone expander and verified that the relay is working, by programming a function key to toggle the relay and then checking the resistance between the C and N.O. wires. Wire IDs are as follows. Relay 1: C – Brown; N.O. – Yellow. Relay 2: C – Violet; N.O. – White. To wire in series: Splice yellow to violet, and connect brown and white to garage door opener terminals.

5/21: Wired the relays up in series this morning, and everything seems to work fine. Assuming there are no problems, the only thing left to do is solder the splices and clean up all my wiring. Then it’s done!

For programming… since I have a lot of keyfob zones that need to trip various garage door relays, I decided to create two zone lists (*81) for zones that trip relay #1 and #2, respectively. That saves me from defining identical output functions for each individual button zone. It seems to work well that way.