Noah Meyerhans

The weblog

2016 Bavarian Bike & Brew Race Report

This post could easily have been titled “Why did this hurt so much?” or even simply, “What happened!?” It’s nice to come away from a race having learned something. Unfortunately, the lessons aren’t always pleasant. The best way I can phrase the lesson from this year’s Bavarian Bike & Brew race is like this If you want to find out whether your training is working, stop doing it for a year and see what happens. You’ll learn something, I promise. That’s basically what happened here.

Last year at this time, I was well into preparations for the BC Bike Race. I had spent time doing core work in the gym, focused rides on the trainer, and endurance rides on both the road and the dirt. I was in reasonably good shape, and my race results reflected that. Once the BC Bike Race was over, though, I basically began an early and very unfocused offseason. With no major event planned for 2016, I did nearly nothing to maintain the fitness I’d built up in the first half of 2015. I barely rode my bike at all, and certainly didn’t race.

So, jumping forward to this season, I missed the first couple of races with excuses that wouldn’t have worked last year. When the time did finally come to race, I really didn’t have a clue how I’d do. I knew that the weather would be similar to last year (HOT), and I knew I did well last year. So, maybe I’d do well this year, right? Eh, not so much, as it turned out. There are a lot of numbers to point at to tell the story, but most notably are these: My average speed for the race dropped by 0.8 mph from last year, and my time increased by more than 14 minutes. Not only that, but it hurt more and was less fun.

So at this point, what’s next? The next two weekends are race weekends, and both races are longer than Bike & Brew. I can’t expect my results to look like they did last year, that much is clear. My best chance to salvage something respectable out of this season is to effectively start from scratch. There are some worthwhile races later in the season (July, August, and September). It will be interesting to see if I’m able to rebuild any of that fitness in the next two to three months. It’s awfully discouraging, though, knowing that you’re starting from scratch in June something that you should have been working on since February.

This is going to be an interesting lesson to look back on during those dark, cold winter nights this coming winter. We’ll see if it provides sufficient motivation to get back on the trainer. Maybe committing to Singletrack Six or the the BC Bike Race again will help there, too.

Echo Valley Race Report

A couple of notable things stand out from last weekend’s race.

It was a super fast course and the weather was beautiful. It had rained the day/night before, so there was no dust and the traction felt infinite. (unlike a couple years ago, where a rider 20 feet in front of you would literally vanish in a dust cloud)

I didn’t take any time to warm up before the race, and it starts with a mile of climbing right out of the gate. Bad idea. I felt ok for the first half mile, which was fire road, and entered the singletrack in 6th position. Unfortunately, the next half mile was a disaster, as my lack of warmup caught up with me and I blew the engine completely. Several riders passed me, and I dropped to probably 12th to 15th position. Once I recovered from this mess, I rode strong for the rest of the day. I never caught the lead group, but was never passed again either.

Unfortunately, the course, while extensively marked, somehow got really confusing for a lot of riders. Lots of people, myself included, ended up taking wrong turns at various points. At one point, despite following guidance from course marshalls and signs, I wound up doing two laps of a mile-long section that should only have been ridden once. Other people had similar stories. While stopped at the second aid station, I had about 25 miles logged so far, and heard from another rider who had just crossed the 30 mile point! So the results of the race a largely meaningless. Oh well. Fortunately it’s not like this was my big priority for the season (That one is still coming up!)

Technically, this was my first race (first dirt ride, really) on the new XTR build on the Niner. Holy crap, it did not fail to impress! Despite only having done a short shakedown ride on pavement with this setup previously everything worked well. I don’t think I could have said that about the previous build at any point in its lifetime.

The one technical drawback was that the fork, which was recently serviced by a nearby shop, had spewed all its oil and had thus completely lost all its rebound damping functionality. That was seriously annoying, and I expected much higher quality work out of this shop. I’ve since replaced the seals and oil in the fork myself, so I’m back in business. Took a lot less than the week-and-a-half turnaround at the shop, too…

Stottlemeyer Race Report

A whole mess of stuff has changed since the Beezley Burn race. Mostly this involved training and bike fit stuff. I had a new saddle and freshly dialed geometry, and this was also the first race in which I rode with Time’s ATAC pedals. I was interested to see how things would go. This is also the race I’ve done the most in my time in Washington, so there’s a lot of data to compare it with. The field is larger than the Beezley Burn race, especially since it’s not broken up by categories, only by age. This means that I’m going up against everyone from first-time racers to Really Fast Guys.

I’ve never been really good about starting near the front in large mass-start races, and I’ve run in to trouble because of this in the past. This race was different, though, as I managed to sneak in to the first line at the start. It quickly became apparent, though, that while this tactic worked at the Beezley Burn, it was a different story against these Really Fast Guys. My immediate feeling was of being left behind. I hadn’t done any warming up before the start, since the race is fairly long and I didn’t want to expend too much energy too soon. This likely impacted my explosiveness (ha!) at the start.

On the initial doubletrack climb, I found a reasonably comfortable and fast pace, though it was no match for the group up the road. My only hope there was that they went too hard and the beginning and would fade later. Meanwhile I had to contend with some difficult singletrack. Stottlemeyer is a fun course, with a bit of an East Coast feel. It’s really tight, wooded, and relatively flat. All it needs to be a proper East Coast trail is a whole lot of granite. I like riding in this type of terrain, but I really am not super fast at it. It really rewards good efficient bike handling skills. It’s a real challenge to keep the speed up. I tend to do better in more open trails where I can kick in to time-trial mode. So all this while, I was pretty sure the lead group of riders was getting further and further away. Turns out I was right.

I carried one water bottle with me and planned to refill it at the aid stations as needed. At the third aid station, just at the end of the first lap, I did so. Unfortunately, the process was really slow. There were volunteers there filling bottles, and they worked as fast as they could at their jobs. Unfortunately, there were just two big orange gatorade coolers with filler spigots, and they don’t fill nearly fast enough to satisfy a racer! I feel like I lost at least 3 minutes there, though in reality I bet it was only one. Either way, it was a slow process! While waiting for my bottle to fill, I grabbed a mini Clif bar and ate the whole thing in one bite. This was not a great idea. My bottle finished filling just as I put the bar in my mouth, and I took off into the singletrack with 3 other racers. Working to stay with them and eventually pass one of them didn’t leave me much time to drink from my bottle, but I really had to! I was having a hard time chewing and swallowing the Clif bar, and had to choke back gags before I finally was able to grab a quick shot of water and get everything moving properly.

In past years, lap 2 of this race has been really challenging. Particularly the second half, after passing the fourth aid station. The remaining miles have always seemed to go on longer than they should have, and my legs felt weak. This year was different, though. I felt strong throughout the second lap and was able to pass some other riders with authority. Certain sections of trail even seemed faster, probably due to familiarity. Unfortunately here is where I ran in to some mechanical issues.

A few relatively minor things went wrong mechanically this year. None was catastrophic, but all were annoying. First, likely due to a seized pivot bearing, a linkage bolt worked itself free and fell out. I should have dealt with the seized bearing sooner, as I knew it was a problem, so this is my own fault. Ultimately it didn’t stop me from finishing the race, but it certainly could have. The inconvenience of having to now replace both the bearing and the fancy custom bolt could have been far worse had the lack of support damaged the frame or swingarm. Fortunately that didn’t happen!

The second mechanical issue was that the shifter cable endcap at the rear derailleur got caught in the chain and wedged itself between two of the cogs. This screwed shifting up pretty bad in some gears.

Another mechanical issue that has probably been impacting me a bit for a while is that the front shifter housing seems to be torsioned in such a way as to cause it to twist itself against the barrel adjuster knob on the front shifter. This has the effect of essentially screwing the barrel adjuster in, decreasing the tension on the cable. This meant that my front shifting, particularly from small ring to big ring, degraded over the course of the race until I realized what seemed to be happening and made adjustments. I should be able to deal with this better in the future now that I’m aware of what’s going on. Of course, I may not be racing again with this same drivetrain because…

XTR is on the way! Assuming Shimano ever manages to ship the whole thing, anyway! I’ve got a whole pile of fancy brakes and drivetrain bits in the basement but I lack a crankset and front shifter lever! More on that later!

Race results are at webscorer.

Beezley Burn Race Report

Rode hard out of the starting gate and put a lot of hurt into my competitors (not to mention my own legs!). The first 2 km were on a wide open straight fire road with a headwind. Didn’t really want to be leading the charge into the wind, but I didn’t want to be following anybody else’s pace either. Shortly before we entered the singletrack, I let Peter Super and Steven Moe pass, and the three of us remained together for most of the first lap. Steven ran out of gas late in the lap, leaving me and Peter together, with Peter leading. Staying on his wheel was tough, but manageable. After some time, we were caught by Matthew Faunt in the 19-34 category. He didn’t stick around long, and to my eye looked easily ready to upgrade to Cat 1. He passed us an intersection at the top of a short climb where the trail marker had fallen over and it wasn’t clear which way to go. Peter and I both paused, but Matthew appeared to have pre-ridden the course and took of in the right direction without hesitation. I never really saw him again. Peter gained several seconds on me at this point, accelerating faster than me following of our moment of indecision. I chased hard to catch Peter again, and wasn’t sure I’d manage to do so. After maybe 4 km of chasing, I caught him again just past the feed zone entering the second lap. I lead into the singletrack off the long fireroad straightaway, with Peter right on my wheel, then exchanged positions on the next stretch of road. We road together for the first half of this lap. When the trail opened up into some wider doubletrack around the midpoint of the lap, I decided to test Peter’s legs with an attack. He didn’t appear to respond, which was a good sign, but there was still a fair bit of racing to go and he didn’t necessarily need to respond immediately. If he had the energy, he could take his time and reel me in slowly. However, when I looked back after a leg burning climb and saw him struggling to get up some of the punchy steep sections, I knew I had a good chance to hold him off over the last few kilometers. In the end, I managed to do exactly this. The only disappointment was when I was caught within a kilometer of the finish by the second and third place riders from the 19-34 age group and didn’t really have the gas to stay with them as they finished with a strong head-to-head sprint.

Some technical details, mostly for my own reference:

Shock setup:

Air pressure Rebound damping Notes
110 psi 2 clicks Ran wide-open (descend mode).
Generally felt good; didn’t lose efficiency.
Need more rebound damping (already increased 2 clicks, post-race)

Fork setup:

Air pressure Rebound damping Notes
75 psi ? Felt soft, so I ran in Trail Mode, which helped. Traction was good. Want Descend Mode to feel a little closer to this setup.

Tire pressure was 30 psi, which is higher than I often run. Worked out well though.

Other notes:

  • Rear derailleur worked well; shifting felt good throughout.
  • Front derailleur = sadness. Chain kept falling off the big ring onto the small ring. Chain stretch or limit adjustment issues.
  • Brake pads were brand new and hadn’t been fully bedded in. Felt really grabby early on but fine later on.
  • Short enough race that there was no need/time to eat.
  • Not a lot of time to drink. I brought 2 bottles, each 2/3 full. Drank most of the first bottle during and just before the first lap; very little of the second bottle during the second lap.

Building OpenWRT With Docker

I’ve run OpenWRT on my home router for a long time, and these days I maintain a couple of packages for the project. In order to make most efficient use of the hardware resources on my router, I run a custom build of the OpenWRT firmware with some default features removed and others added. For example, I install bind and ipsec-tools, while I disable the web UI in order to save space.

There are quite a few packages required for the OpenWRT build process. I don’t necessarily want all of these packages installed on my main machine, nor do I want to maintain a VM for the build environment. So I investigated using Docker for this.

Starting from a base jessie image, which I created using the Docker debootstrap wrapper, the first step was to construct a Dockerfile containing instructions on how to set up the build environment and create a non-root user to perform the build:

FROM jessie:latest
MAINTAINER Noah Meyerhans <frodo@morgul.net>

RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get -y install \
asciidoc bash bc binutils bzip2 fastjar flex git-core g++ gcc
util-linux gawk libgtk2.0-dev intltool jikespg zlib1g-dev make \
genisoimage libncurses5-dev libssl-dev patch perl-modules \
python2.7-dev rsync ruby sdcc unzip wget gettext xsltproc \
libboost1.55-dev libxml-parser-perl libusb-dev bin86 bcc sharutils \
subversion

RUN adduser --disabled-password --uid 1000 --gecos "Docker Builder,,," builder

And we generate a docker image based on this Dockerfile per the docker build documentation. At this point, we’ve got a basic image that does what we want. To initialize the build environment (download package sources, etc), I might run:

docker run -v ~/src/openwrt:/src/openwrt -u builder -t -i jessie/openwrt sh -c "cd /src/openwrt/openwrt && scripts/feeds update -a"

Or configure the system:

docker run -v ~/src/openwrt:/src/openwrt -u builder -t -i jessie/openwrt make -C /src/openwrt/openwrt menuconfig

And finally, build the OpenWRT image itself:

docker run -v ~/src/openwrt:/src/openwrt -u builder -t -i jessie/openwrt make -C /src/openwrt/openwrt -j3

The -v ~/src/openwrt:/src/openwrt flags tell docker to bind mount my ~/src/openwrt directory (which I’d previously cloned using git) to /src/openwrt inside the running container. Without this, one might be tempted to clone the git repo directly into the container at runtime, but the changes to non-bind-mount filesystems are lost when the container terminates. This could be suitable for an autobuild environment, in which the sources are cloned at the start of the build and any generated artifacts are archived externally at the end, but it isn’t suitable for a dev environment where I might be making and testing small changes at a relatively high frequency.

The -u builder flags tell docker to run the given commands as the builder user inside the container. Recall that builder was created with UID 1000 in the Dockerfile. Since I’m storing the source and artifacts in a bind-mounted directory, all saved files will be created with this UID. Since UID 1000 happens to be my UID on my laptop, this is fine. Any files created by builder inside the container will be owned by me outside the container. However, this container should not have to rely on a user with a given UID running it! I’m not sure what the right way to approach this problem is within Docker. It may be that someone using my image should create their own derivative image that creates a user with the appropriate UID (creation of this derivative image is a cheap operation in Docker). Alternatively, whatever Docker init system is used could start as root, add a new user with a specific UID, and execute the build commands as that new user. Neither of these seems as clean as it could be, though.

In general, Docker seems quite useful for such a build environment. It’s easy to set up, and it makes it very easy to generate and share a common collection of packages and configuration. Because images are self-contained, I can reclaim a bunch of disk space by simple executing “docker rmi”.

Spamassassin Updates

If you’re running Spamassassin on Debian or Ubuntu, have you enabled automatic rule updates? If not, why not? If possible, you should enable this feature. It should be as simple as setting "CRON=1" in /etc/default/spamassassin. If you choose not to enable this feature, I’d really like to hear why. In particular, I’m thinking about changing the default behavior of the Spamassassin packages such that automatic rule updates are enabled, and I’d like to know if (and why) anybody opposes this.

Spamassassin hasn’t been providing rules as part of the upstream package for some time. In Debian, we include a snapshot of the ruleset from an essentially arbitrary point in time in our packages. We do this so Spamassassin will work “out of the box” on Debian systems. People who install spamassassin from source must download rules using spamassassin’s updates channel. The typical way to use this service is to use cron or something similar to periodically check for rule changes via this service. This allows the anti-spam community to quickly adapt to changes in spammer tactics, and for you to actually benefit from their work by taking advantage of their newer, presumably more accurate, rules. It also allows for quick reaction to issues such as the one described in bug 738872 and 774768.

If we do change the default, there are a couple of possible approaches we could take. The simplest would be to simply change the default value of the CRON variable in /etc/default/spamassassin. Perhaps a cleaner approach would be to provide a “spamassassin-autoupdates” package that would simply provide the cron job and a simple wrapper program to perform the updates. The Spamassassin package would then specify a Recommends relationship with this package, thus providing the default enabled behavior while still providing a clear and simple mechanism to disable it.

Debconf by Train

Today is the first time I’ve taken an interstate train trip in something like 15 years. A few things about the trip were pleasantly surprising. Most of these will come as no surprise:

  1. Less time wasted in security theater at the station prior to departure.
  2. On-time departure
  3. More comfortable seats than a plane or bus.
  4. Quiet.
  5. Permissive free wifi

Wifi was the biggest surprise. Not that it existed, since we’re living in the future and wifi is expected everywhere. It’s IPv4 only and stuck behind a NAT, which isn’t a big surprise, but it is reasonably open. There isn’t any port filtering of non-web TCP ports, and even non-TCP protocols are allowed out. Even my aiccu IPv6 tunnel worked fine from the train, although I did experience some weird behavior with it.

I haven’t used aiccu much in quite a while, since I have a native IPv6 connection at home, but it can be convenient while traveling. I’m still trying to figure out happened today, though. The first symptoms were that, although I could ping IPv6 hosts, I could not actually log in via IMAP or ssh. Tcpdump showed all the standard symptoms of a PMTU blackhole. Small packets flow fine, large ones are dropped. The interface MTU is set to 1280, which is the minimum MTU for IPv6 and any path on the internet is expected to handle packets of at least that size. Experimentation via ping6 reveals that the largest payload size I can successfully exchange with a peer is 820 bytes. Add 8 bytes for the ICMPv6 header for 828 bytes of payload, plus 40 bytes for the IPv6 header gives an 868 byte packet, which is well under what should be the MTU for this path.

I’ve worked around this problem with an ip6tables rule to rewrite the MSS on outgoing SYN packets to 760 bytes, which should leave 40 for the IPv6 header and 20 for any extension headers:

sudo ip6tables -t mangle -A OUTPUT -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 760

It is working well and will allow me to publish this from the train, which I’d otherwise have been unable to do. But… weird.

Bianchi Rebuild

Infusing an old bike with new life

I bought this early/mid 1990’s Bianchi Brava from my officemate at MIT in 2005 or 2006. For some time before I bought it, it had been sitting unused in our office and had fallen in to disrepair. When I bought it, I promptly converted it to a singlespeed with the help of Tyler from Paramount Bicycle Repair in Somerville. I rode in that configuration for a couple years, then bought bull-horn bars, scrapped the brakes, and converted it to a fixed-gear, which I rode for another couple of years. When I moved to California in 2010, I bought a road bike so the big hills surrounding the South Bay Area would be accessible, and didn’t ride the Bianchi very much. In Seattle, I’ve been commuting on a newer (but not particularly fun) Raleigh One-Way singlespeed. The Bianchi has once again been left to collect dust. Considering how much fun I had on this bike for several years in Somerville, I always felt a little sad about neglecting it.

Finally, a month or so ago, I decided I’d convert the bike back to a geared road bike. That’s a useful thing to have around here, considering how hilly Seattle is. I’d been tossing around this idea for a while, and finally decided it was time to go ahead and do it. This time, it was a couple trips to Recycled Cycles to get the process started, but I was going to build my own wheels. So, the first trip has me come home with the following:

Lots of wheel parts

And I get to work on the wheel. This was my first real wheel build. I had rebuilt an old mountain bike wheel a while back, and that seemed to go reasonably well, but I never actually rode on it, so it doesn’t really count. Wheelbuilding has always seemed like something of an arcane art to me. It doesn’t really compare to anything else, so you can’t really prepare for it except by actually doing it, which makes it seem rather daunting. Fortunately, as it has done so many times in the past, Sheldon Brown’s website proved a valuable source of information.

After a short time (less than an hour, for sure), the wheel went from the above collection of parts to the following, roughly 80% laced:

Lacing a wheel

And shortly after that, it’s a wheel:

Brand new wheel

In the truing stand, with a tire mounted, making any last adjustments:

Final adjustments

Following the wheel build, there were still several tasks to complete. I wanted to switch back to drop-bars from the bull-horn bar that I used when it was a fixed-gear. And I needed brakes, and of course, shifters and a derailleur. That generally went smoothly. Aside from the cables and rear tire, everything else was either already laying around the house or bought used at Recycled Cycles. The only problem that came up was that I didn’t buy a long enough pieces of brake cable housing, and ended up having to buy more. The derailleur is a long-cage mountain bike derailleur, which is a bit weird on this bike. If I find a used Shimano 105 derailleur I’ll probably swap it out, but in general it works as is.

And this is what it looks like!

The finished product!