Ride Notes for July 22nd, 2015

Today was a fun day of mountain biking with family members, at least for a little while. Here's the scoop: my wife's relatives were hosting a family reunion at the Tanque Verde Ranch at the base of the Rincon Mountains, (which is an awesome place), and one of the activities available to guests was an hour of Mountain Biking.

2015-07-22

There were four of us who decided to go mountain biking today: my brother-in-law, Mike, and I are both road cyclists, so mountain biking sounded like it would be a little different from our usual routines; one of my nephews, Nate, likes to go mountain biking when he's back home in Washington state; and my son-in-law, Curt, is a fan of myriad outdoor activities (namely surfing).

We showed up at the cycling office at the ranch around 6:45am and met with Chuck, who was to be our guide for the day. After some basic fitting of cyclists to full-suspension mountain bike frames, we took off around 7:00am. Chuck took us through some easy trails at first to get everyone acclimated to their bicycles, then he navigated the group to a small track which the ranch has created on its property. The track is a small oval with lots of bumps and high-berm corners. Chuck had each of us make several passes around the track to get used to working with the full-suspension systems on the bicycles, and then we headed off into the desert.

Our route primarily consisted of extremely narrow paths between rows of cacti and other pointy plants, which kept everyone on their toes. At one point I had to mention to Curt that he shouldn't brush up against the cholla cactus, because they have a tendency to break off and painfully attach themselves to people. We also traversed a lot of small hills, and Chuck took us to one particular hill where everyone could jump off and get a little air under their bicycle.

After riding around for a while Chuck asked if we'd like to go on the harder trails, and everyone agreed; sometime around that decision the injuries started to happen:

The first mishap was when Curt flipped his bike trying to cross a small wash. (Note: Curt was wearing his GoPro camera at the time and managed to get that on video.)

The later mishap occurred when we were climbing a hill over some rocks, and my left leg slipped off the pedal. Since I was pushing hard with my legs to climb the hill and over the rocks, this meant that I had nothing to slow the speed of my right leg as it pushed down hard on the remaining pedal, which spun the empty pedal around and smashed broad-faced into my left shin at full force. This hurt more than you can possibly imagine; I went from a 0 to 10 on the pain scale instantaneously, and I immediately formed two golf-ball-sized welts on my shin where the pedal collided with the bone. I quickly pulled to a halt, exclaimed something a little more dire than "Oh Crap," and it took me a couple of minutes to get myself together.

I walked my bike to where the rest of group was waiting and announced, "I'm done for the day." I explained what had happened, and by now the contusions on my leg were so large that everyone else thought that I had broken my leg, and the swollen areas were the bone jutting out. I assured everyone that my leg wasn't broken because I could put weight on it, but I didn't want to risk injuring it again, so my day of cycling was over.

We walked our bikes toward the ranch for a little bit, which was out of courtesy for me, but I informed everyone that it would be easier for me to ride than to walk. With that in mind, we boarded our bicycles and headed back to the shop at the ranch. Once we arrived, Chuck brought me a bag of ice and a crash kit, and I started to ice the swelling on my leg.

The following photo shows my injuries (on the left) and Curt's injuries (on the right); unfortunately the photo is from the front of my leg, so you can't see how high the swelling was at this point - all you can see are light shadows.

WP_20150722_08_34_45_Pro.edited.cropped

Once we had returned our bikes to the shop, we met the rest of the family for breakfast, where my wife - the nurse - took one look at me and asked something like, "So, where did you hurt yourself this time?" After breakfast I headed back to our room, and after a couple hours of icing my injuries the swelling had disappeared; all that remained was a nagging pain in my left leg when I walked.

All that being said, despite the injuries it was a fun time. And my injury serves to illustrate why riders should clip in when mountain biking.

Ride Stats:

  • Primary Statistics:
    • Start Time: 7:00am
    • Distance: 7.8 miles
    • Duration: 1:03:57
    • Calories Burned: 490 kcal
    • Altitude Gain: 182 feet
  • Speed:
    • Average Speed: 7.3 mph
    • Peak Speed: 19.7 mph
  • Temperature:
    • Average: 85.4 F
    • Minimum: 78.8 F
    • Maximum: 87.8 F
  • Heart Rate:
    • Average: 133 bpm
    • Maximum: 163 bpm

Ride Notes for Seattle to Portland 2015

This past weekend I completed the two-day, 206-mile Seattle to Portland (STP) ride with my brother-in-law, Mike. This event is hosted annually by the Cascade Bicycle Club (CBC), and despite its daunting length, the ride sells out with 10,000 registered riders. Just to clarify, you read that correctly: every year ten thousand cyclists are willing to endure almost two-dozen hours of self-inflicted physical abuse for little more than bragging rights.

And this year, I was one of those masochists.

Prologue

I do not recall whether it was Mike or me who first suggested participating in this year's STP ride, but I am pretty sure that it quickly evolved into one of those "I'll do it if you'll do it" kind of conversations that guys often find themselves in. (And once the gauntlet has been thrown, you have to accept the challenge.) In any event, at some point back in 2014 we decided that riding in the STP seemed like a good [sic] idea, so I did some preliminary research about the ride on the CBC website. Once I had put together some rough details about the event, (e.g. when to register, where to stay, etc.), I sent everything to Mike. I let him know that the STP sells out quickly, so we both set calendar reminders to register on the day that registration opened.

When the starting day for STP registration arrived, Mike and I were both able to register for the event. Although in keeping with tradition, the STP was quickly sold out at 10,000 cyclists.

I received my official packet in the mail a few weeks before the ride, which brought a sense of reality the whole affair. My bib number for the ride was 8564, which was easy to remember, but it wasn't one of the numbers that I'd like to have. (e.g. I'd prefer to have something like 1024, 2112, 2600, 4096, 6502, 8088, etc. And no - I will not explain any of those numbers to you.)

My STP Packet! Bib Number 8564!

Once all of the event registration details were in place, I booked a hotel in Seattle for my stay before the ride, and Mike booked us a hotel in Centralia for the mid-point of the ride. After that, all that was left to do was buy a travel case for my bicycle, fly to Seattle to meet with Mike and his wife, Tesa, and prep our gear for the big day.

Packing my gear into our car for the ride to the airport.
Prepping my gear in my hotel room on the night before the ride.

Day One - Saturday

Mike and Tesa picked me up from my hotel shortly before 5:00am, and we headed across the 520 bridge in Seattle to the University of Washington where the ride was scheduled to begin. As we neared the parking lot for Husky Stadium, we could see that there was a long line to get to the drop-off location, so I suggested that we pull into the parking lot across the street in University Village; this turned out to be the best idea and saved us lots of time. Mike and I got the last of our things ready for the ride, said our goodbyes to Tesa, and we rode to the start line.

We dropped off our bags with one of the trucks that was headed to Centralia, and then we got in line for the next wave of cyclists. Note: In order to keep the hordes of cyclists from bunching up at the start, the event organizers combine riders into large groups and release them every few minutes; it was a very organized and efficient system. (One-day riders were allowed to start 30 minutes before two-day riders; this was also a great idea, because at a 16 mph pace that means that you could be eight miles away from the first wave two-day riders.) As we waited in the chilly morning air for our wave to start, Mike grabbed a quick cup of coffee, and we chatted for a few minutes until they announced that our group was ready to go.

Queuing at the Start Line.
Mike's last cup of coffee before the ride.

When they pulled back the tape around 6:00am, I made sure to start both my Garmin GPS and the GPS app that I had written for my Windows Phone that allows family members to track our progress, and then we took off amidst a sea of exuberant riders.

Waiting to start.

The first leg of our journey took us through a series of neighborhoods and parks that line the western shore of Lake Washington. The day was overcast, so we couldn't see any volcanoes, but it made the day cooler overall. There were a few small hills here and there as we started out, but nothing of significant difficulty.

Mike and I riding along Lake Washington.

Mike and I had set our goal for the morning to ride straight through to the 40-mile stop in Puyallup, so we quickly bypassed the first official stop at Seward Park around the 10-mile mark. (Actually, I couldn't believe that anyone was bothering to stop there; we were barely a half-hour into the ride.) I should mention that I pushed Mike's and my pace pretty hard at the beginning of the day for the first hour or so; I wanted to get past several groups of slow-moving cyclists, and that way we would be riding with more of the serious cyclists who would keep a better pace.

Route map for the first half of Day 1.

Shortly after we passed the 24-mile stop in Kent, Mike and I pulled up to a stoplight with a hundred or so riders. I unclipped my left foot so I could stand on it while waiting for the light to change. But as I came to a stop, I suddenly lost my balance to the right, and I couldn't unclip my right foot before I fell over. (Thankfully I was wearing a helmet when I hit the ground.) There were a half-dozen or so concerned cyclists surrounding me and asking if I was okay, but I chose to reply by jumping up and addressing the entire crowd of cyclists by exclaiming, "Nothing wounded but my pride, folks! Did anyone get that on video? I'd like to post it online later." This had the desired effect of assuring everyone that I was all right while allowing everyone the opportunity to laugh along with me at my own expense. However, this little mishap left a lovely, little series of gashes on the back of my left leg, and I got lots of comments about it for the rest of the day. (e.g. "Nice tattoo!", "Blood and grease make great lubricants!", etc.)

My first War Wound of the day.

A couple of hours into the ride we had passed the one-third point for the day, and I tried something kind of stupid: I pulled out my camera and held it backwards over my shoulder in order to snap a few photos of Mike. All of the photos came out pretty well, but just the same - I resolved not to try that again.

Mike looks pretty good after two hours of riding.

We arrived at the 40-mile stop in Puyallup around 8:30am, and it was nice to get off the bike for a few minutes and walk around. Mike and I refilled our water bottles, ate some chocolate cookies that were for sale, and we split a banana. (Bananas are a good source of potassium, which helps cut down on muscle cramps.) After a quick 10-minute break, we hopped back on our bikes and headed south towards Portland.

Taking a quick break in Puyallup.
Back on the road.

I knew from looking at the elevation profile before the ride that the largest hill climbs of the day were immediately ahead of us, and we hit the base of the first hill somewhere around the 44-mile point. As Mike and I made our way up the hill, Mike found a great opening amidst the mass of cyclists and attacked the hill with some serious gusto. Unfortunately for me, however, I managed to get myself boxed in by a group slow-moving cyclists. By the time that I managed to maneuver my way past them around the mid-point of the first hill it was too late; I had lost all of my initial momentum to launch a proper attack, so I was forced to slog my way up the first hill. I was still passing scores of cyclists, but I should have been moving a lot faster. (Darn. Darn. Darn.)

Once Mike and I were past the big hills for the day, (which comprised about four miles of the day's riding), it was fairly easy cycling for the next ten miles to the 57-mile stop at Joint Base Lewis McChord (JBLM), where lunch awaited us. (Note: There were some serious winds as we rode around the base's airfield; that was no fun.) We arrived around 10:00am, and we were pleased to discover that there was a fairly decent spread of food at this stop; I had a turkey sandwich, a Rice Krispy Treat, some fruit, another cookie, etc. But to be perfectly honest, by this point I was so ravenously hungry I could have eaten just about anything. After resting for 20 minutes, Mike and I refilled our water bottles and we got back on the road.

Hundreds of cyclists taking a lunch beak on JBLM.
Mike and I taking a quick photo before heading out.

As we weaved our way through the base housing, that brought back memories of being raised as a kid on various military bases, and also of my own years serving in the military and living on base. (Note: Those nostalgic reminiscences weren't necessarily happy memories for me, because base housing usually leaves a lot to be desired.) Anyway, many of the cyclists were giving high-fives to the MPs and other military personnel who were directing traffic for us. They were all enlisted personnel, so I'm sure that most of them were ordered to guard the roads for the cyclists, but nevertheless their efforts were greatly appreciated by all of the riders.

Route map for the second half of Day 1.

The route took us through some of the back woods on the base, and eventually we exited the base near the town of Roy, WA. Mike and I pressed on to McKenna, which was the next official stop at mile 72 for the day. We arrived around 11:40am, and we took a break to rest our weary legs for about 20 minutes. After we refilled our water bottles, it was time to head out.

Stopping briefly in McKenna

Shortly after we left the stop at McKenna, we faced a steep hill climb. Mike was ahead of me, so he didn't notice the following incident: I attempted to shift from my top chain ring to my small chain ring in order to climb a little easier, but my bicycle threw its chain off the small chain ring. I tried to backpedal out of the situation, but my chain became completely lodged and it wouldn't move. This predicament caused me to quickly lose all of my forward momentum in the middle of the hill, and in one of those moments that seems like an eternity at the time (but was really just milliseconds) I weighed my options. There was obviously nothing that I could do to dislodge my chain, but if I unclipped my left foot (which I always unclip) I would be leaning (or falling) into traffic. This risk was unacceptable, so with no other options available to me, I threw all of my weight to the right side of the road, where my bicycle and I tumbled over the concrete curb and into the grass and dirt that lined the road. This undoubtedly looked much worse than it felt; several approaching cyclists called out to me to see if I was okay. I assured everyone that I was fine, (although my fall had bruised my right arm and torn up my right knee a little). I explained that my bicycle had simply thrown its chain, and I encouraged everyone to continue pedaling uphill. After that, I spent the next 10 to 15 minutes attempting to untangle my bicycle chain. This proved to be a very difficult task; my chain was stuck fast, but I eventually succeeded - although my hands were filthy by the end. (It's a good thing that I had packed hand wipes with me.) Mike eventually noticed that I was nowhere to be seen, so he pulled off the road into an unofficial stop at mile 81 and sent me a text message to let me know that he was waiting for me. When I caught up with Mike, I explained what had happened, then we quickly got back on the road.

My second War Wound of the day.

The next segment of the ride Mike and I both agreed was the best part of the day's ride; we rode along the well-paved Yelm-Tenino Trail for 14 miles or so. First and foremost - there were no cars on the trail, which was a pleasant change. In addition, the trail was wide enough for Mike and I to ride together, and yet there was still enough room for other cyclists room to pass when necessary. This trail was also the smoothest part of the day's ride, which was greatly appreciated.

Riding along the Yelm-Tenino Trail.

Note: As we were riding along the trail, Mike and I saw the aftermath of a female cyclist who had suffered some sort of major catastrophe; medical personnel were treating her myriad injuries, and I make no exaggeration by stating that she was covered in blood.

Mike and I stopped in Tenino at the 89-mile point around 1:25pm, which was the last official stop before our destination for the day in Centralia. Our decision to stop in Tenino was mainly due to my earlier accident; I wanted to have some bicycle repair technicians check out my bike to see if they could determine why it threw its chain. The technician ran my bike through all of its gears but couldn't reproduce the problem, so he commented that it must have been a fluke. His diagnosis put my mind at ease, although that later proved untrue. (But I'm getting ahead of myself.)

Taking a break at the Tenino stop.

When Mike and I left Tenino, we had only 14 miles to go for the day, and the miles passed pretty quickly as we rode for the next hour or so. (To be perfectly honest, I can't recall anything of importance from that hour's worth of riding.)

Finishing up the day's ride.

We crossed the Day 1 finish line at Centralia College shortly before 3:00pm, so we made pretty good time for the day. My wife, Kathleen, had been tracking our progress throughout the day via the GPS app that I had written, and she sent me a text message to congratulate Mike and me for completing the first day's ride.

Mike crossing the Day 1 finish line.

As various cyclists made their way across the finish line, an announcer was having fun calling out the various jerseys and costumes worn by the participants. Mike and I pushed our bicycles out of the way to allow arriving cyclists more room to exit the course, and as we did we were met by volunteers who were handing out orange-flavored popsicles. Mike and I both gladly accepted the proffered popsicles, although at that point the volunteers could have frozen just about anything and I would have eaten it. (e.g. "Here's your frozen kale!", "Get your frozen lutefisk here!")

Mike enjoying some well-earned reclination.

After a little rest and relaxation, we decided that we should either find something to eat for dinner, or we should depart for our hotel. We looked at our dining choices, and we chose to order a pizza at the hotel later. Our next step was to retrieve our backpacks, and it took us a few minutes to discover where the pickup point was located. (This was due to a misunderstanding of what the announcer said.) Once we found the right place, it was well-organized and we quickly found our things.

Our hotel was a little less than two miles from the college, and once we got settled into our room we both took long showers to wash off the grime from the day's activities. We ordered a pizza to be delivered to our hotel room - which was fantastic. We ate most of the pizza, but we set aside two pieces for breakfast the following morning. (For some people, cold pizza in the morning is the breakfast of champions.)

After dinner we put together our riding plan for the next day, and I wrote up a cheat sheet with the distances for all of the stops. The pickup up time for our backpacks at Centralia College wasn't until 6:00am the following morning, so we both set our alarms for 5:00am, and we headed off to sleep by 8:00pm.

Putting together my cheat sheet for the next day.

We had averaged a little over 15 mph for the day, which wasn't bad. Here are some quick stats for the first day's ride:

  • Total Distance: 102.1 miles
  • Riding Time: 6 hours, 39 minutes
  • Total Time: 9 hours, 4 minutes
  • Elevation Gain: 3,290 feet
  • Average Speed: 15.4 mph
  • Calories Burned: 3,444 kcal

Day Two - Sunday

Mike and I both woke up shortly before our alarms, and since neither of us could sleep, we got up and started to put our things together for the day. We pulled the pizza out of the mini-fridge from the night before, although by now neither of us wanted to touch it. (It's funny how appetites can change overnight.)

Mike and I preparing to start our Day 2 ride.

We got on the road by 5:40am, which was close to our goal. As we pulled up to a stoplight near the hotel, I pulled my bicycle onto the sidewalk in order to push the button to change the traffic signal. Unfortunately I decelerated too quickly and - surprise, surprise - I lost my balance and fell over. Seriously - one minute into the day's ride and I had already fallen over. Who DOES that? (Apparently I do. And just to clarify, my count for falling over during this trip was now at three. Darn.)

Route map for the first half of Day 2.

Mike and I arrived at Centralia College within ten minutes of leaving our hotel, and we quickly dropped off our backpacks. Once that task was taken care of, we got on the road shortly before 6:00am. Even though my muscles were a little sore when we got up and headed out from our hotel, much of that soreness quickly passed as we started the actual ride.

Dropping our backpacks off at Centralia College.

We skipped the first stop in Chehalis at the 7-mile point, but as we rode through town we realized why some of the more experienced STP riders push on to Chehalis or some other town during the first day; it diminishes the length that you need to ride on the second day, and it probably helps psychologically to know that your ride will be shorter. You would miss out on all the half-way point festivities in Centralia, of course, although you could hang out there for a half-hour or so before riding on to your ultimate destination.

Riding through Chehalis in the early morning.

Our plan for the day was to ride a little slower than the previous day and to hit all of the stops. We had made good time the day before, but we didn't want to kill ourselves during the second day's ride. With that in mind, Mike and I started off together, and the road was wide enough for us to carry on a conversation as we rode. Sometime later I started to break away on the hill climbs, and at the next stop Mike suggested that I ride at my own pace and simply wait for him at each successive stop. With that in mind, I routinely sped off after each stop, but I only arrived at each stop about two or three minutes before Mike, so he was riding at pretty much the same level as me. What's more, Mike passed me during a couple of the hill climbs and I somehow didn't notice, so I was perplexed when I found myself passing him later. ("Hey, how did you get here?") Once I discovered to my amusement that Mike was waiting at the next stop for me, and I queried when he had managed to pass me; Mike replied that he had passed me following a climb, and he had arrived at the stop just 30 seconds before me.

At one point I was passing a bunch of cyclists and I kept hollering "On your left" to announce my intention to pass each cyclist. I started hearing a woman behind me announcing the same as we passed several cyclists, so I thought she was drafting behind me. But as I was passing another cyclist the woman behind me exclaimed, "I'm not kidding; ON YOUR LEFT!" This meant that she wanted me to get out of her way, but I need to point out that there was no shoulder on the right, so the cyclist to my right had nowhere to go. I was in the middle of our lane passing that cyclist with only inches to spare between our bicycles, whereas the woman behind me had the rest of our lane and the entire oncoming traffic lane (with no traffic visible for at least a mile) with which to pass me. As I couldn't get out of the way without pushing the cyclist to my right off the road, I ignored the woman behind me. When she eventually pulled alongside I remarked, "In case it wasn't obvious, I was passing someone, too. Just a thought." (I got no reply as she sped off.)

I knew from studying the ride profile the day before that we had a big hill awaiting us near the start of the day, and sure enough we hit the base of the hill around the 14-mile point. However, this hill was a little different than the big hill on the previous day, because it was more like a series of hills that seemed to go on and on for five or six miles, and for a little while it became kind of annoying. (Well, it was annoying for me, anyway.) But I was really glad that I train on the Pistol Hill Loop back in Tucson, which has a long, uphill climb for seven miles or so. As I was riding I kept thinking about Rule #10 from The Rules: "It never gets easier, you just go faster." (Of course, Rule #5 always applies, too.)

That being said, as I attempted to shift my bike onto the smaller chain ring, my bike threw its chain again. But since I had a sneaky suspicion that it might do so, I chose a time to shift when few people were near me, and when my chain was thrown I was able to quickly pull to a stop and get off the road in a controlled manner. A few of the passing cyclists asked if everything was okay, and I replied, "Yup - I just threw my chain." They just nodded sympathetically and rode on. It took me about five minutes to fix my chain, and once I had done so I wondered what to do with all the oil on my hands. I decided that my cycling shorts were black for a reason, and I just wiped my hands off on them.

Rejoining a hill climb in the middle is tricky; you have to find a good gear to get started, and you have to find a good interval between cyclists to get back on the road. Nevertheless, I managed to get back on the road pretty quickly.

As we neared the summit of a really tough climb, I loudly asked everyone around me, "Why are we doing this? Is ANYONE having fun?" Most people just laughed, but the woman riding next to me said this was the best thing that had happened to her all year. I replied, "Really? This climb is the best thing that's happened to you this year?" She responded, "Yeah, I've had a really awful year." (I said I was so sorry for her; and I really meant it.)

Our first official stop of the day was in Winlock around 7:15am. Mike and I both bought a small cup of coffee, and we split a simple breakfast sandwich. (Which at the time tasted better than filet mignon.) As we arrived, medical personnel were loading an injured cyclist into an ambulance, which was yet another reminder that I was fortunate that my previous day's injuries had been pretty minor.

Arriving in Winlock.
Thankfully the ambulances were not there for us.
This may not have been the breakfast
of champions, but it was fantastic.
Mike insisted on this photo. I kind of regret it now.

The next official stop was in Vader (no relation to Darth) at 8:20am, but Mike and I were both feeling pretty strong so we decided to bypass this stop and we hopped back on the road in order to push on to the next stop.

Bypassing the mini-stop in Vader.

The sun broke out, which made it much warmer, and I finally had a need for my sunglasses. Some of the cyclists complained about the heat, but it was cooler than my usual riding temperatures in Arizona so I didn't mind. (Although I did increase my water intake.) Unfortunately, since the first day had been overcast, Mike had packed his nice sunglasses for this trip, so he only had his normal glasses with him. (Even though his normal glasses automatically tint in sunlight, it's just not the same.)

We pulled into Castle Rock around 9:00am, which was the 38-mile stop for Day 2. I think Mike may have refilled his water bottles, but I was doing fine for supplies so I just stretched my legs for a few minutes before we got back on the road.

The stop at Castle Rock.
Mike expressing his elation upon our arrival.
My bike leaning against a rock in Castle Rock.
It might have been the actual "Castle Rock," but I couldn't be sure.
(Note: That was meant as a joke, of course.)

The next stop was in Lexington at the 45-mile point, which was the first major food stop of the day. We arrived at 10:00am, so we were a little behind a timeline that I would have liked. But we had kept our pace pretty well; we had simply been following our plan to hit more of the stops along the way, which slowed us down a little. However, this approach was arguably worth the sacrifice from a psychological perspective; it was nice to know that our next stop was never more than 10 to 15 miles away, even if we decided to skip it. In any event, Mike and I ate a leisurely lunch in Lexington and we relaxed for a while before getting back on the road.

The Lexington stop had a much larger crowd
than normal, but that was to be expected.
Mike enjoying lunch.

Unfortunately we discovered as we got ready to leave the Lexington stop that there was a really long line to refill our water bottles, so that set our departure time back a little. Apparently there was a problem with the water pressure, so they only had a single tap working for hundreds of cyclists. (If we had known that fact a little sooner, we could have got in line when we arrived. But in the grand scheme of things it wasn't that much of an imposition; and we were glad to have enough water to depart safely.)

Sorting through the food that I picked up and choosing what
comes with me on the road and what gets eaten immediately.

Mike and I got on the road around 11:00am, and about a half-hour later I arrived at the Lewis and Clark Bridge over the Columbia River, which signified the border with Oregon. The ride organizers and police were corralling cyclists onto a frontage road while allowing southbound road traffic to continue over the bridge unabated, with the intention of stopping traffic at some point and allowing the mass of cyclists to make their way across the bridge. Mike arrived about ten minutes after me, so he was further back in the mob of bicyclists than me. About ten minutes after Mike arrived the police finally blocked off the traffic and allowed the cyclists to cross the bridge; this action was greeted by a number of cheers from the assembled throng of cyclists.

The hundred or so riders who had
arrived at the bridge before me.

As we approached the bridge, several of the ride organizers called out to the crowd to say that the descent on the opposite side of the bridge was going to be very bumpy. With this in mind, they were recommending that everyone should make sure that all of their gear was securely fastened to their bikes, and to watch out for lost gear as they descended. I reached down and made sure that my water bottles were snugly fastened into their cages, and I made my way up the bridge climb.

I have to admit, when I first saw the bridge from a distance, I thought that the climb would be exceptionally terrible. But as it turns out, the climb wasn't that bad. However, what was bad was that there was a large number of cyclists who were riding very slowly, but we had been grouped into such a thick horde of cyclists that it was difficult to maneuver around the slow-moving riders. Meanwhile, we had fast-moving traffic approaching in the opposite direction. As a result, the ride across the bridge was often terrifying - just for fear of accidents. (PS - some people simply gave up and walked their bikes across the bridge.)

The Lewis and Clark Bridge from a distance.

As I approached the mid-point of the bridge, the crowd around me had thinned out considerably. A group of cyclists (including me) had broken away from the main group, and as a result I had enough of a buffer behind me that I felt comfortable enough to pull out my camera and snap a couple of photos before starting my descent. As I coasted down the far side of the bridge, I put on a lot of speed due to the steep decline, so I was braking constantly as I hit the series of bumps about which we had been warned. True to the predictions, there were somewhere between 50 and 100 water bottles lying beside the road. I guess some people failed to heed the warnings. Once we were past the bridge, we were back to road riding - only now we were in Oregon.

Entering Oregon!

Sometime later my bike threw its chain again, and this happened a few more times. However, each time I was able to catch the problem before I wiped out, and I pulled to the side to fix the problem. (I waved Mike on whenever this happened.) But I decided that I no longer trusted my bicycle to shift to the small chain ring, so I chose to ride for the rest of the day on my small chain ring in order to avoid throwing my chain again. (This is, of course, unacceptable for a bicycle, so I resolved to have to have that looked at when I got home.) However, this also meant that I forfeited my highest gears, and therefore I lost my top speeds.

After a while I had so much oil and grease on my fingers due to resetting my chain that it was kind of gross to eat. That being said, there simply wasn't a place to properly wash off all of the fifth, so I was forced to make do. (In my military days I called this condition "perma-grime," and I learned to live with it or starve.)

Route map for the second half of Day 2.

At some point during the day I started to ride with a group of women with Skull/Butterfly gear. We rode together for quite awhile because we seemed to ride at the same pace for the flat sections; I would climb hills faster than them, but they were willing to take the downhills faster than me. I can't remember when we started riding together, and I can't remember when we stopped. It was probably at one of the stops, but I don't recall.

Mike and I stopped in Goble at the 62-mile point around 12:30pm, although we didn't stay long. We refilled our water bottles, and I had a couple snacks that I had saved from an earlier stop that day. After 10 minutes or so we were back on the road.

Stopping for water in Goble.

The next big stop of the day was in St. Helens, which was shortly before the 75-mile point. We arrived around 1:50pm, and we found a good place to ground our bikes while we wandered off in search of food. The sandwiches and snacks were largely the same as other stops, except that they had watermelon, which was fantastic. They also had a water mister operating, and it was fun to see people walk through it again and again.

Mike pulling into St. Helens.
Navigating through the sea of
cyclists to find our lunch.

Mike needed to pick up something from the medical tent, and one of the volunteers asked if I wanted her to wrap my knee from the previous day's accident. I replied, "No, I earned that." (She laughed and walked away.) After an hour's rest, we packed our things and got back on the road.

Visiting the medical tent.
Mike leaning back, kicking his shoes off, catching some shade...

Somewhere after we left St. Helens, I realized that I had not been pulling up on my legs during the climbs; I had just been pushing down. So I decided to change pedaling techniques, and I discovered that I had so much power in reserve that I found myself climbing a few of the difficult hills at 18 to 20 mph. That being said, I realized that this was going to be a short-lived discovery; after a few hills I recognized that I was quickly burning up that reserve, and all of it was gone by the time I hit the uphill climb to St. John's bridge an hour or so later.

Our last stop of the day was in Scappoose at mile 87, and we arrived around 3:30pm. This stop was pretty small; it was really just the last chance to fill up on water before starting the final 17-mile stretch to Portland. Kathleen sent me a text message that the GPS app that I had written had stopped uploading data at Goble, so I quickly reset it and it started transmitting again. (If Kathleen hadn't sent me that message I would never have known, and Kathleen would have thought that something had gone wrong in Goble.) After Mike and I topped off our water bottles, we got back on the road.

My bike was helping to point the way to water.
Taking stock of my snacks for the final push.

Mike later remarked that he started to listen to music through his iPhone about three or four hours from the end of the ride, although I didn't turn on my music until the last hour or so before the St. John's bridge. (Then I turned off my music for the ride through Portland.)

Mike and I had agreed to meet up at St. John's bridge, which crossed the Willamette River into Portland, in order to finish the ride together. The distance from Scappoose to the finish line was roughly 16 miles, and the bridge was about midway between the two locations, so from a psychological perspective it helped to subdivide the last of the ride into two shorter segments. (At this point in the ride, it's all about the mind games.)

I arrived at the bridge less than a minute before Mike, who pulled along side as I took a photo of the bridge. We had to wait for a stoplight to change, and then we made our way across the bridge with a small group of cyclists.

Crossing the St. John's bridge into Portland.

The ride through Portland was predominantly a nice respite from all of the up and down hill riding over the past several days, except that there was one small hill near the finish line that was a brief moment of difficulty, for which I loudly remarked, "Okay, who added THIS hill to the ride?" That being said, we were forced to stop for a large number of stoplights as we rode through Portland, which probably added at least a half-hour to our ride time.

Nevertheless, before we realized it, Mike and I were crossing the finish line at Holladay Park, and our second century ride of the STP was over. (Note: I should have taken off my sunglasses as I crossed the finish line, because you probably can't see my face in official ride photos. But perhaps that's a good thing.) Mike and I were handed our "STP Finisher" patches, and then we pulled our bikes off to the side to allow room for arriving cyclists who were completing the ride.

Approaching the last few meters to the finish line!
Mike's opinion of what it feels like to finish.
Proudly displaying my hard-earned "Finisher" patch!

We walked our bikes through the crowds, and we found a tree off to the side of the park on which to lean them. Mike watched our bikes while I picked up our backpacks.

My bike finally earned its own rest.

Shortly thereafter we were met by Tesa and her sister, Mary, who showed up to congratulate us. After a few minutes of visiting with Mary and Tesa, Mike and I ventured off in search of something to replace the thousands of calories that we had just burned.

We decided on Greek Gyros, (which were amazing), and we picked up some free souvenir STP cups from the Cascade Bicycle Club. After that, Mike and I ordered our 2015 STP jerseys. (Note: I don't pre-buy my jersey before a ride, which is kind of like a minor superstition for me; I don't want to jinx the ride by buying the jersey and then failing to complete the ride.)

What this year's jersey looks like.

We were informed that we won't receive our jerseys until October, which was unfortunate, but what choice did we have? Once we were done eating and buying our jerseys, we packed up our bikes and headed off to spend the evening with family.

Mike and I had averaged just under 15 mph for the day, which once again was pretty good. Here are some quick stats for the second day's ride:

  • Total Distance: 106.2 miles
  • Riding Time: 7 hours, 8 minutes
  • Total Time: 11 hours, 39 minutes
  • Elevation Gain: 3,809 feet
  • Average Speed: 14.9 mph
  • Calories Burned: 3,954 kcal

Epilogue and Random Thoughts

I had jotted several things down in my notes that didn't apply to either day in particular, so I thought that I would add a special section to this blog in order to share them.

  • Ford Prefect described Earth as "Mostly Harmless." If I was following his lead, I would label STP Day 1 as "Mostly Flat," and STP Day 2 as "Mostly Hills."
  • Mike and I saw several bad accidents during the ride, with several people being whisked away in ambulances. So in the grand scheme of things, my minor injuries were nothing. (Although it should be noted that Mike had no injuries; only I did.)
  • Throughout the ride, most cyclists did their best to thank the volunteer staff and police officers who provided food, drinks, directed traffic, etc.
  • Two words: Honey Buckets. Enough said.
  • On Day 1, Mike and I both wore our El Tour de Tucson jerseys, and Mike got lots of comments about his jersey. It was from the 2012 El Tour, and I have to admit, that year had my favorite artwork; it appears that everyone else agrees with me.
  • On Day, 2 Mike wore a plain jersey while I wore a Microsoft jersey. At some point another cyclist from Microsoft noticed my jersey, and we started a small conversation as we rode. The guy asked me if I work on Visual Studio, since that logo was on my jersey, and I replied, "More or less." (I work in the division that creates Visual Studio, and I designed the development web server that ships with Visual Studio.) I asked where he works, and he replied, "I work on HoloLens." I said, "Dude, you work on the cool stuff." To which he responded, "Yeah, and I use your stuff to make my stuff."
  • I had several groups of cyclists touch on one of my pet peeves: they failed to queue properly at a stoplight. In several specific instances, a group of cyclists was already queued at a stoplight, when an approaching group of cyclists would glide past the whole queue in order to take the best position for when the light changes. This was especially frustrating to me when it was a group of cyclists that I had already passed, which meant that I would have to pass them again! (If I recall correctly, I politely chastised a couple of groups of cyclists for failure to queue properly. After all, we were in it together, right? Weren't we supposed to cooperate? Sheesh.)
  • Unlike the El Tour de Tucson, which has thousands of people cheering cyclists on, most of the Seattle to Portland course was devoid of anyone other than angry motorists who appeared to hate the inconvenience of cyclists taking up their precious roadways.
  • Some groups of fast-moving cyclists speed up on your left side unannounced and it scares the poop out of you. (I did my best to announce all of my passes.)
  • We saw some interesting bicycles on this ride. For example, one group of cyclists riding for charity were doing the entire ride on vintage, single-speed bicycles. (That's either gutsy or foolish - but either way I admired their bravery.) I saw two cyclists on commuter bikes that resemble Brompton Folding Bikes, which was even more insane than riding a single speed bike. There were also a few recumbent bikes completing the ride, several tandem bicycles, a Penny-farthing, and one hand-pedaled cyclist who was making pretty good time.
  • At most of the stops (full and mini) they had water, Clif bars, and sometimes fruit, while at the full stops they also had sandwiches a greater selection of snack foods. The full stops also had lots of vendors selling their wares or offering free samples.
  • I over-packed for my supplies, but that's actually a good thing; I would rather have something with me and not need it than to need something and not have it.
  • There is an old adage that says, "If you ain't the lead dog, the view never changes." This applies to cyclists as well.
  • I made good time for a lot of the ride; I was able to keep a pretty good pace even climbing the moderate hills, and I found myself climbing with a good deal of power. (I was nowhere near competitive, of course, but I was really glad that I always train with hills.)
  • After the ride was over I did the math, and I could have done the ride in a single day if I started at 4:45am with the rest of the single-day riders. Now I am not suggesting that I wouldn't have been in a great deal of pain after the ride, and during the ride I would have been psychologically punishing myself for being stupid enough to attempt a 206-mile ride in one day, but the math definitely proved to me that it could be done by me. (I should point out that I am not suggesting that I ever intend to do such a thing, but it is possible.)
  • Throughout the ride I tried to joke around with other cyclists; I complimented people on their jerseys, silly things they attached to their bicycles or helmets, funny costumes, etc. I tried anything to take people's minds off the immediate suffering that we were all experiencing. I used to do the same thing in my Army days; I am not trying to be a "comedian" and make people laugh - I am just trying to spread a little joy and alleviate a little pain when it's needed most.
  • Mike later made fun of me for a few of my verbalizations to other cyclists during the ride. For example, I chastised one guy for tossing a plastic wrapper to the ground: "Dude, you should pack out your own garbage." (Note: I always do.) And I chastised someone else for cutting me off with an abrupt lane change: "A little warning next time would be great. Thanks."
  • I alluded to this earlier, but several of The Rules applied during this ride; I mentioned Rules #5 and #10 earlier, but the more you ride, you start to realize how many of those rules are apropos for any big riding event.

At the end of the event, Mike and I averaged just over 15 mph for the entire ride, which was better than I had anticipated during our planning. Here are some quick stats from both days:

  • Total Calories Burned: 7,398 kcal
  • Total Elevation Gained: 7,099 feet
  • Final Average Speed: 15.1 mph
  • Total Cycling Time: 13 hours, 48 minutes
  • Total Participation Time: 20 hours, 43 minutes

The day after the ride was over I told Mike that 7,400 calories seemed too low, and he agreed: "That seemed a lot more like 10,000 calories."

As a parting thought, there are five stages to dealing with grief - Denial, Anger, Bargaining, Depression, and Acceptance - and I've learned that it's much like that for distance rides:

  • Denial: "Hey, this 206-mile ride won't be that bad..."
  • Anger: "Why am I doing this ride? I am such an idiot!"
  • Bargaining: "Dear God, if you help me to survive this ride, I promise that I will be nicer to all of humanity."
  • Depression: "Oh my gosh, I still have another 20 miles to go. I could just die right now."
  • Acceptance: "Well, that ride is over. I will never do that again."

The problem is, within a few weeks the vicious cycle will begin again. Immediately after a long ride like the STP is over you think, "I will never ride my bicycle again, so I'm going to sell it and take up an indoor hobby." On the day after the ride you think, "Well, maybe I'll keep my bicycle as a souvenir." One month later you start to think, "Hmm. I might ride the STP again." After another month passes you think, "Hey, I wonder when I can register for next year's STP?" And then in another month or so you find yourself telling your friends, "Hey! Do you guys want to ride the STP with me? It's LOTS of fun!" When that happens, denial has set in, and that's pretty much how it starts.

More 511th History: Happy 4th of July

Here's a 4th of July story for you from our days in the 511th...

Anyone who remembers Steve Meyers will recall that he had no fear - although sometimes he had no common sense, either. Steve backpacked across Europe with no cash as a teenager, wandered off in Turkey without knowing the language or telling anyone where he was going, and managed to pull off a two-week vacation using his MAC flight privileges to visit Athens, Jerusalem, and Cairo and still made it back in time for duty. Steve was an amazing guy who simply went where no one else would think to go.

But what some of you who joined the 511th after the Fall Of The Wall may not know is that our unit used to work with members of the British RAF before they rotated back to the UK. We deployed to the border with them several times, and a few of us were sent to work with the RAF somewhere further north (in locations about which we cannot speak). ;-)

Anyway, during one of those deployments along the border, we were having coffee with a few of the Brits, when Steve turned to them out-of-the-blue and asked, "So, how do you guys feel about when you lost the Revolutionary War? Are you guys still upset about that?"

For a flash of a second you probably could have heard a pin drop all the way across the border, then one of the Brits - without looking up from his coffee - replied in his best British accent, "Lost? I think not. We simply left it to you. Have you been home lately? Ah, what a piece-o-crap."

This comment was followed by a well-deserved round of laughter, and all was well in the world. :-D

Happy 4th of July everyone!


UPDATE: I found the following image, which seems apropos for this topic:

Happy-Treason-Day

Ride Notes for June 27th, 2015

Despite having ridden in temperatures over 100 degrees (Fahrenheit) in the past, I appear to have failed in learning the important lesson that riding in extreme temperatures really takes a lot out of you. That was abundantly evident during today's 60-mile ride; even though I started early to avoid the hotter temperatures, as the day wore on I found myself suffering through the worst temps of the day, as evidenced by the following photo of my GPS when I approached the 50-mile mark of the ride:

Way-Too-Hot

When I'm riding during the hotter times of year, I tend to arrange my rides in something like a cloverleaf pattern, where I am always trying to get back to the entrance of Saguaro National Park (SNP) in order to refill my water bottles. (I try to do that every 15 to 20 miles.) During this ride, however, I was still several miles away from SNP when I realized that I wasn't going to have enough water to get back.

With that in mind, I called Kathleen, and the following conversation transpired:

  • Kathleen: Hello? Where are you?
  • Me: [Panting.] I'm not sure; somewhere way out on east Tanque Verde.
  • Kathleen: Are you okay?
  • Me: I've just realized that I don't have enough water to make it back to my refill location.
  • Kathleen: Okay, I'll come get you.
  • Me: Oh no, I don't want to quit - I just need you to bring me some more water.
  • Kathleen: You realize that you're nuts, right?
  • Me: Yup.

And my darling spouse, being the wonderful person that she is, drove out to meet me and brought me several bottles of water so I could refill and continue my ride for another 10 miles.

Ride Stats:

  • Primary Statistics:
    • Start Time: 9:25am
    • Distance: 60.1 miles
    • Duration: 4:32:22
    • Calories Burned: 2526 kcal
    • Altitude Gain: 2681 feet
  • Speed:
    • Average Speed: 13.4 mph
    • Peak Speed: 33.3 mph
    • Average Cadence: 71.0 rpm
  • Temperature:
    • Average: 99.6 F
    • Minimum: 78.8 F
    • Maximum: 111.2 F
  • Heart Rate:
    • Average: 152 bpm
    • Maximum: 182 bpm

Still More Examples of Bad Technical Support

Here is another entry in my on-going list of examples for both good and bad technical support experiences. For this situation, I will show an example of bad technical support as provided by the Microsoft Outlook Support Team.

Here is the scenario: about two months ago one of my Hotmail accounts stopped working with Windows Live Mail. When I attempted to sync that particular email account, I received an error message that was similar to the following example:

Bear in mind, however, that I made no changes to my Windows Live Mail settings, and I have several other Hotmail accounts which are working perfectly with the same settings on the same computer.

So I started a support issue with the the Microsoft Outlook Support Team, and over the next several weeks I went back and forth with several people on that team who were clearly uninterested in working on this issue. (In fact, at one point they simply closed the case without notifying me!) As of today the issue is still not resolved, and I have not heard from anyone at Microsoft within the past month.

As I said before, this is an example of really bad technical support.

With that in mind, listed below is the full thread from my support case in order of the events. Note that I have substituted the following variables where necessary to hide my actual account name, email address, and support number:

  • %ACCOUNT_NAME% is my Hotmail account name
  • %EMAIL_ACCOUNT% is my email address for my Hotmail account
  • %TICKET_NUMBER% is my ticket number for my Microsoft support case (e.g. SRX12345678ID)

So without further narrative, here are all of the notes from the support case.

04/18/2015 15:14

Service: General Issue

What type of problem do you have?

  • Selected Product
    • Outlook
  • Selected Issue
    • Your account has been temporarily blocked

Enter a short description of your issue: Cannot Sync Email from Windows Live Mail

Enter the email address (Microsoft account) affected by this issue: %EMAIL_ACCOUNT%

Enter your contact email address: %EMAIL_ACCOUNT%

Enter a detailed description of your issue:

I was able to sync my %EMAIL_ACCOUNT% account in Windows Live Mail until a week or so ago, and now I receive the following error message:

Unable to send or receive messages for the Hotmail (%ACCOUNT_NAME%) account.
Server Error: 3219
Server: 'https://mail.services.live.com/DeltaSync_v2.0.0/Sync.aspx'
Windows Live Mail Error ID: 0x8DE00005


For reasons that are completely unrelated to this issue, I completely reinstalled Windows 7 Ultimate on this computer, and yet after reinstalling Windows and Windows Live Mail on this computer I still see the same error. In addition, I have a couple of other Hotmail accounts that I use with Windows Live Mail on the same computer and they work without any errors.

With that in mind, the problem should not be caused by any settings on my computer. However, I did not make any changes to my account settings at Hotmail before I started seeing this problem.

There is one thing that I have noticed, though - when I log into the Hotmail.com website, when I use one of my other Hotmail accounts the title bar says Outlook.com, whereas the title bar for my %EMAIL_ACCOUNT% account says Outlook Mail (Preview).

04/18/2015 15:18

From: Microsoft Support

We are writing to let you know that we have received your request for support and will reply within 24 hours.

If you don't see a message from us within 24 hours, check to see if email from @css.one.microsoft.com is in your junk mail folder. You can check the status of your request on the Microsoft Support site.

https://support.microsoft.com/oas/default.aspx?tp=il&tenant=WOL&sd=winlive&incno=%TICKET_NUMBER%

Thank you,
The Microsoft Support team

04/19/2015 22:51

Subject: %TICKET_NUMBER%
From: Escalation Agent

Hi,

Thank you for contacting Outlook.com support.

My name is Therese and I'm glad you have reached us today. I have read your description and I understand that you are getting an error message when syncing your account at Windows Live Mail. Let me see what I can do for you.

To start off, we appreciate your efforts in isolating the case by uninstalling and reinstalling your Operating System and Windows Live Mail on your computer. You also mentioned that other Microsoft accounts are working fine on Windows Live Mail which tells us that this is not an issue with the mail client but can be an account-related issue.

With that, I would like you to know that I have escalated this case to our Support Specialist for further evaluation. We will get back to you as soon as we have a resolution or if we need more information.

Your patience is highly appreciated.

Regards,
Therese

04/21/2015 11:12

Subject: RE: %TICKET_NUMBER%
From: %ACCOUNT_NAME%

Has there been any progress on this issue?

FWIW - I have included a screen shot of the error message in Windows Live Mail.

Thanks.
--------------------
Attachments:
0x8DE00005.png

04/21/2015 13:17

Subject: %TICKET_NUMBER%
From: Escalation Agent

Hello,

Good to hear from you again. This is John from Outlook.com support.

We appreciate the screenshot that you have provided us. I have checked your service request and found out that your issue is still being handled by our Support specialists and the investigation is still ongoing. Once we got any developments or if there is anything that our Support specialist would need from you, we'll inform you right away.

Thank you for your cooperation and patience on this matter.

Regards,
John

PS: Please do not delete the first email notification from us. If you did not receive another notification in 24 hours, please check the link on the first email notification to see the case progress.

04/25/2015 12:33

Subject: %TICKET_NUMBER% (Reopen)
From: %ACCOUNT_NAME%

It has been a week since I first opened this support case, and from what I could tell - nothing was ever done. So imagine my surprise when I logged in today and I discovered that this support case had been closed without a single notification from Microsoft. This is terrible customer service, and I AM A VERY DISSATISFIED CUSTOMER!!!

At this point I expect three things:

1. I demand that this issue be escalated to someone who can actually work on the issue and resolve it; I no longer want to suffer through working with incompetent 1st-tier support people.

2. I expect to hear from someone within the next 24 hours with an actual update on this issue; I do not want to hear another blasé response which says "the investigation is still ongoing," because it very clearly was not being investigated.

3. I expect to hear from a manager within the next 48 hours as to why this issue was never worked, never resolved, and closed without contacting me.

If I do not hear from anyone within the times that I have put forth, I will escalate this issue through appropriate channels on my own, which will reflect even more poorly on those who have been doing a terrible job thus far.

04/25/2015 16:52

Subject: %TICKET_NUMBER%
From: Escalation Agent

Hi %ACCOUNT_NAME%,

Thank you for your response and for sharing your feelings with us. I'm Froilan, at your service.

We apologize for taking your valuable time in trying to resolve your issue with the error message when syncing your account in Windows Live mail. I fully understand how you feel about the inconvenience this has brought you. Please be informed that I will get back to our Support Specialist to get update about the status of your case. We understand the urgency of this issue; however, we cannot provide you with the time when a reply will be available. Rest assured that this post is being tracked and we will inform you immediately once we get any updates from them.

We appreciate your continued patience in going through this issue.

IMPORTANT REMINDERS:

Please save and keep the first email notification you received after submitting this request. That notification contains the link for this service request. If you did not receive another notification in 24 hours after your reply, you can check the status of this case and view our response by clicking the link on the first notification.

Best regards.

05/01/2015 09:54

Subject: %TICKET_NUMBER%
From: Escalation Agent

Hello %ACCOUNT_NAME%,

How is it going? We received an update coming from our Escalations Engineer and based from what we've observed, it seems the issue is encountered when the server settings for IMAP is not selected.

What you need to do is to make sure that you've selected and followed the Manual Server Settings for IMAP. This should allow the syncing of your accounts.

For more information about this setting, please refer to the IMAP setting that can be found in the link below.

http://windows.microsoft.com/en-US/windows/outlook/send-receive-from-app

Kindly share us the outcome afterwards.

Regards,
Microsoft Support Team

05/03/2015 22:22

Subject: RE: %TICKET_NUMBER%
From: %ACCOUNT_NAME%

This simply does not make sense; I have several other Hotmail accounts which I simply add them to Windows Live Mail and they automatically work. In the Properties dialog for each of my other accounts, the Server Information tab lists "My mail server is an HTTP server" with the following URL:

https://mail.services.live.com/DeltaSync_v2.0.0/sync.aspx

These are the EXACT same settings as the %EMAIL_ACCOUNT% email account. So why would this one account require custom IMAP settings?

Also, this account was working fine until a few weeks ago when I started seeing the errors. I made no changes to my settings, so it would seem that Microsoft has changed something about this specific Hotmail account. As I pointed out before, the web page banner when I am using this account reads "Outlook Mail (Preview)", which leads me to believe that this account was only partially migrated to the new Outlook Mail servers. With that in mind, I would theorize that the problem is due to a failed attempt on Microsoft's behalf when trying migrate my account from the old Hotmail.com servers to the new Outlook.com servers.

05/03/2015 22:23

Subject: %TICKET_NUMBER%
From: %ACCOUNT_NAME%

By the way, while I sincerely appreciate the assistance of the escalation engineer, I still have not heard back from a manager with an answer as to why my support case was closed by the initial support engineer after no work was completed and no attempts were made to contact me.

05/03/2015 23:56

Subject: %TICKET_NUMBER%
From: Escalation Agent

Hi %ACCOUNT_NAME%,

Thank you for providing us additional details. I'm Hyver from Outlook.com Support and I have reviewed the exchange of responses that you had with my colleagues. I'm truly sorry if the issue still persists after a week of communicating with us. I understand the displeasure that you've expressed for the support that you experienced. We're still here to help you on your issue.

I really apologize for the inconvenience that you've faced. I know you're expecting an email from a manager explaining why the support ticket was closed without someone trying to attempt to contact you. I'd like to let you k now that we are actively monitoring cases that are being reviewed by the Escalations Team and we do not close cases with open escalations. So we would like to ask for a copy of the email notification that indicates that the case was closed. I will include this to my reports as this could be an honest mistake or a system glitch,

I totally recognize that you deserve a valid explanation about what happened and we are not letting our customers to be upset at any point of our investigation. We don't like to see our customers upset and inconvenienced and we always strive to create a positive customer experience. With that being said, this should be reviewed again by our Escalations Team and should be taken care with utmost urgency. Please do not lost faith in us as we are doing our best to resolve this issue the soonest possible time.

As we speak, this support request is in our Escalations Team queue and should be treated with immediate attention. We appreciate your cooperation and understanding.

Should you have other questions or clarifications, please do not hesitate to contact us back.

Sincerely,
Hyver

05/05/2015 18:04

Subject: RE: %TICKET_NUMBER%
From: %ACCOUNT_NAME%

Hello Hyver,

There was never an email when the case was closed, which was part of my complaint. If you look at the case notes, you will see that I had to reopen the case on 04/25/2105 when I discovered that the case had been closed when I logged into this support website to check on the status.

05/05/2015 19:47

Subject: %TICKET_NUMBER%
From: Escalation Agent

Hello,

Thank you for letting us know that there was no email with regard to this case that was closed. We will report this to our higher support team and we'll get back to you immediately once we have the latest update from them.

Again, your patience and understanding are much appreciated.

Kindest regards,
Glenda

05/12/2015 22:46

Subject: %TICKET_NUMBER%
From: %ACCOUNT_NAME%

Another week has passed by, and yet I still have not heard anything, which leads me to believe that no one at Microsoft is actually doing nothing with this case. From my perspective, it seems that the "Escalation Agents" with whom I am working are simply stalling for time and hoping that either the problem will go away or I will quit trying and give up.

With that in mind, I will keep everyone up-to-date: the problem is still there - which should be expected since no one at Microsoft appears to be doing anything to fix the problem.

So let me recap the past week or so: I have heard nothing from Microsoft since the last time that I requested an update, my issue is not resolved, and I never heard from a manager at Microsoft with an explanation as to why the front-line engineers closed the case without contacting me or to discuss a plan of action to resolve this issue.

All of this reflects very poorly on the support engineers with whom I am working. As such, I want to work with someone else. Someone who knows what they're doing. Someone who can actually resolve an issue.

05/13/2015 03:37

Subject: %TICKET_NUMBER%
From: Escalation Agent

Note: To check the status of your request, kindly refrain from deleting our email notification. If you haven't received another notification in 24 hours, you can view the agent's response on URL link provided on the notification email.

Hi,

This is Audrey and we apologizer if this case has been going on for so long without any results. Upon checking your concern is still under investigation by our support specialist. We will be making a follow up regarding this and once we have received a word from them it will be immediately relayed to you.

Rest assured that we are exhausting our resources to resolve this matter as soon as possible.

Thank you,
Outlook.com Support Team

05/19/2015 13:36

Subject: %TICKET_NUMBER%
From: Escalation Agent

Hello %ACCOUNT_NAME%,

Sorry for the wait. We received an update coming from our Escalations Team and there's a possibility that your account's server settings were changed. With this, configuring your account to Windows Live Mail using this server "Windows Live Hotmail" will not work.

We are still working on your issue but what you can do is to use IMAP as your server type if you want to sync your emails.

Thank you for consideration and cooperation.

Regards,
Microsoft Support Team

05/29/2015 13:19

Subject: RE: %TICKET_NUMBER%
From: %ACCOUNT_NAME%

I do not wish to use IMAP; I have used that before and it has presented me with a separate series of issues. I will continue to wait for you to fix the problem with the server settings.


To be honest, at this point I have little faith that the Microsoft Outlook Support Team will do anything to resolve this issue. It is abundantly clear to me that the support team is ignoring my support case and simply waiting for me to close it, which I refuse to do since my problem is not resolved.

So once again I reiterate the obvious - this is a perfect example of truly awful technical support, and it demonstrates why many people eventually give up on Hotmail and switch to Gmail.

Simple Java Wrapper Class for raspistill on the Raspberry Pi 2

Like many self-proclaimed geeks, I can't resist a change to play with new technology. So when the Raspberry Pi 2 was released a short time ago, I didn't hesitate buying one. My first impressions was: for $35, that's a lot of computer power in a very small package. And because I really am a geek, I will admit that the first thing I tried to do with it was to install DOSBOX and run Microsoft Flight Simulator 4.

Once I got that out of my system, I started experimenting with some simple Java programming and the Raspberry Pi camera module. (It's great that Java is built-into Raspian Wheezy; in the past you had to install it.)

That being said, there isn't any direct I/O control of the camera via Java, although that's pretty much expected. When considering ways to control the camera I came across the Pi4J library, which provides Java-based APIs to control the Raspberry Pi's I/O. This looks like it will be great for me eventually, but for the moment the best idea that I could come up with was to write a simple Java-based wrapper class for the raspistill command line executable.

With that in mind, here's a sample class that you can use to take photos from Java on a Raspberry Pi. I added lots of code comments to explain how everything works, and I'll provide a little more detail after the code sample.

// This class is a very simple Java wrapper for the raspistill executable,
// which makes it easier to take photos from a Java application. Note that
// there are considerably more parameters available for raspistill which
// could be added to this class. (e.g. Shutter Speed, ISO, AWB, etc.) 

public class RaspiStill
{
   // Define the path to the raspistill executable.
   private final String _raspistillPath = "/opt/vc/bin/raspistill";
   // Define the amount of time that the camera will use to take a photo.
   private final int _picTimeout = 5000;
   // Define the image quality.
   private final int _picQuality = 100;

   // Specify a default image width.
   private int _picWidth = 1024;
   // Specify a default image height.
   private int _picHeight = 768;
   // Specify a default image name.
   private String _picName = "example.jpg";
   // Specify a default image encoding.
   private String _picType = "jpg";

   // Default class constructor.
   public void RaspiStill()
   {
      // Do anything else here. For example, you could create another
      // constructor which accepts an alternate path to raspistill,
      // or defines global parameters like the image quality.
   }

   // Default method to take a photo using the private values for name/width/height.
   // Note: See the overloaded methods to override the private values.
   public void TakePicture()
   {
      try
      {
         // Determine the image type based on the file extension (or use the default).
         if (_picName.indexOf('.')!=-1) _picType = _picName.substring(_picName.lastIndexOf('.')+1);

         // Create a new string builder with the path to raspistill.
         StringBuilder sb = new StringBuilder(_raspistillPath);

         // Add parameters for no preview and burst mode.
         sb.append(" -n -bm");
         // Configure the camera timeout.
         sb.append(" -t " + _picTimeout);
         // Configure the picture width.
         sb.append(" -w " + _picWidth);
         // Configure the picture height.
         sb.append(" -h " + _picHeight);
         // Configure the picture quality.
         sb.append(" -q " + _picQuality);
         // Specify the image type.
         sb.append(" -e " + _picType);
         // Specify the name of the image.
         sb.append(" -o " + _picName);

         // Invoke raspistill to take the photo.
         Runtime.getRuntime().exec(sb.toString());
         // Pause to allow the camera time to take the photo.
         Thread.sleep(_picTimeout);
      }
      catch (Exception e)
      {
         // Exit the application with the exception's hash code.
         System.exit(e.hashCode());
      }
   }

   // Overloaded method to take a photo using specific values for the name/width/height.
   public void TakePicture(String name, int width, int height)
   {
      _picName = name;
      _picWidth = width;
      _picHeight = height;
      TakePicture();
   }

   // Overloaded method to take a photo using a specific value for the image name.
   public void TakePicture(String name)
   {
      TakePicture(name, _picWidth, _picHeight);
   }

   // Overloaded method to take a photo using specific values for width/height.
   public void TakePicture(int width, int height)
   {
      TakePicture(_picName, width, height);
   }
}

The wrapper class should be pretty self-explanatory: calling the TakePicture() method with no parameters will use the application defaults, and calling the overloaded methods will allow you to specify the output filename and the width/height for the image. You specify the image type based on the file extension; (e.g. ".jpg", ".png", ".gif"). There are a bunch of additional raspistill options which you can easily add to the application; see the Raspberry Pi camera module page for more information.

Here's a simple application to test it out:

public class CameraTest
{
  // Define the number of photos to take.
  private static final long _numberOfImages = 5;
  // Define the interval between photos.
  private static final int _delayInterval = 5000;

  public static void main(String[] args)
  {
    try
    {
      // Create a new RaspiStill object.
      RaspiStill camera = new RaspiStill();
      // Loop through the number of images to take.
      for (long i = 0; i < _numberOfImages; ++i)
      {
        // Capture the image.
        camera.TakePicture("image" + i + ".jpg",800,600);
        // Pause after each photo.
        Thread.sleep(_delayInterval);
      }
    }
    catch (Exception e)
    {
      // Exit the application with the exception's hash code.
      System.exit(e.hashCode());
    }
  }
}

Now that I've shared this odd little sample, I'll wander back to my dungeon so I can keep playing with my Raspberry Pi.


Note: This blog was originally posted at http://blogs.msdn.com/robert_mcmurray/

Sunset On This Evening's Ride

Sunset during this evening's 52-mile bicycle ride...

WP_20150606_19_33_07_Pro
Sunset Over the Desert

Which reminds me, I should point out that there are both good and bad things about heading out for a long ride in the evening; one of the good things is getting to see sunsets like this. However, one of the bad things is when you realize that you're seeing a sunset like this while you're still 15 miles away from your house, which means that in a few minutes you will be plunged into a darkness that will surround you like an encroaching evil, where you are never more than one menacing pothole away from certain death.

Did I mention that the light on my bicycle failed five minutes after I turned it on? It's a good thing that I was once a Boy Scout and I had a backup light; it was better than nothing, but it barely offered enough light to see the road.

WP_20150606_19_42_40_Pro
Just Before Darkness Fell,
(And I still needed to ride half-way to the far horizon)

That being said, I can see that I have digressed from my original thought... it really was a nice sunset.

Ride Stats:

  • Primary Statistics:
    • Start Time: 5:14pm
    • Distance: 52.5 miles
    • Duration: 3:29:01
    • Calories Burned: 1656 kcal
    • Altitude Gain: 2181 feet
  • Speed:
    • Average Speed: 14.8 mph
    • Peak Speed: 30.8 mph
    • Average Cadence: 76.0 rpm
  • Temperature:
    • Average: 83.7 F
    • Minimum: 78.8 F
    • Maximum: 89.6 F
  • Heart Rate:
    • Average: 144 bpm
    • Maximum: 175 bpm

Follow Up: Converting Text Files to Audio Files

A couple of days ago I posted a blog which I titled Creating an HTML Application to Convert Text Files to Audio Files, in which I showed how to create an HTML Application that will convert a text file to an audio file. I thought that I would follow up that article with a quick demonstration which compares some of the built-in text-to-speech voices that ship with Windows 7 and Windows 8.

For the text in this demonstration I will use Edgar Allan Poe's famous poem titled The Raven, which is one of my personal favorites. (I used to have the poem memorized as a teenager... that might have been when I was going through a Fahrenheit 451 phase.)

Click the above image
to download the text file.

Microsoft Anna (Windows 7)

For the first demo we will take a look at the poem as read by the Microsoft Anna text-to-speech voice, which ships with Windows 7. This voice is acceptable, and certainly better than the text-to-speech voices which shipped before Windows 7 was released. But still, it has a few odd quirks to it, and as a result this voice typically sounds unnatural to me.

Click the above image
to download the MP3 file.

Microsoft David (Windows 8)

For the second demo we will take a look at the poem as read by the Microsoft David text-to-speech voice, which ships with Windows 8. This voice is considerably more acceptable that Microsoft Anna, and it sounds very natural to me. It is obviously a male voice, and several people with whom I have discussed this subject seem to prefer the Microsoft David voice over all the others.

Click the above image
to download the MP3 file.

Microsoft Hazel (Windows 8)

For the third demo we will take a look at the poem as read by the Microsoft Hazel text-to-speech voice, which also ships with Windows 8. This also much better than the text-to-speech voices which shipped before Windows 7, and it has an English accent which makes it fun for converting literary works.

Click the above image
to download the MP3 file.

Microsoft Zira (Windows 8)

For the fourth and final demo we will take a look at the poem as read by the Microsoft Zira text-to-speech voice, which also ships with Windows 8. This voice is my personal favorite, as I find it the most-natural sounding of all the text-to-speech voices which ship with Windows 7; this is the voice that I used for all of my textbook reading assignments.

Click the above image
to download the MP3 file.

In Closing

As a parting thought, the text-to-speech voices which ship with Windows 8 are extremely good in my opinion; they sound very natural, and they are very easy to understand. As a result, I have a tendency to speed up the playback a little when I am using the script which I shared in my previous blog. That being said, I hope these samples help to demonstrate the various text-to-speech voices that are available in the recent versions of Windows.


Note: This blog was originally posted at http://blogs.msdn.com/robert_mcmurray/

Creating an HTML Application to Convert Text Files to Audio Files

I'd like to take a brief departure from my normal collage of web-related and server-management examples and share a rather eclectic code sample.

Here's the scenario: I am presently working on another college degree, and I was recently taking a class which required a great deal of reading.  These assignments were all in digital form: I was using PDF or Kindle-based versions of the textbooks, and the remaining reading consisted of online articles. However, I am also an avid bicyclist, and the voluminous amount of reading was preventing me from going on some of my normal weekly rides. This gave me an idea: if I could convert the digital text to audio, I could bring my assignments with me on my longer rides and have my MP3 player read my assignments to me as I pedaled my way around the Arizona deserts.

I had experimented with Microsoft's built-in text-to-speech features some years ago, so I thought that this would be the perfect opportunity to revisit some of those APIs and write a full application to do the conversions for me. That being said, I could have written this application by using C# (which is my preferred language), but I decided to create an HTML Application for two reasons: 1) it is easier for me to share HTMLA applications in a blog, and 2) I keep this application in my OneDrive, so it's easier for me to modify the source code on systems where I don't have Visual Studio installed.

With that in mind, here is the resulting script which will convert a Text File to a Wave (*.WAV) File.

Using the HTML Application

As with most of my HTML Applications, the user interface is pretty simple to use; when you double click the HTA file, it will present you with the following user interface:

Clicking the Browse button will obviously allow you to browse to a text file, clicking the Close button will close the application, and clicking the Write File button will create a Wave file that is in the same path as the source text file. For example, if you have a text file at "C:\Text\Test.txt", the script will create a Wave file at "C:\Text\Test.txt.wav".

That being said, there are a few options which you can set:

  • Depending on your version of Windows and which languages you have installed, you will be presented with a list of available voices in the first drop-down menu; the following example is from a Windows 8 computer:
  • The second drop-down menu allows you to vary the playback speed; sometimes I prefer the playback speed to be slighter faster than normal:
  • The third drop-down menu allows you to alter the volume of the resulting Wave file:

Note: You can modify the script to alter the values that are used in the playback speed and volume drop-down menus, but the list of voices is obtained dynamically from your operating system.

Creating the HTML Application

To create this HTML Application, save the following HTMLA code as "Text to Wave File.hta" to your computer, and then double-click its icon to run the application. (Note that in a few places I added code comments which contain the MSDN URL for the APIs that I am using for this sample.)

<html>
<head>
<title>Text-to-Speech Writer</title>
<HTA:APPLICATION
  APPLICATIONNAME="Text-to-Speech Writer"
  ID="TextToSpeech"
  VERSION="1.0"
  BORDER="dialog"
  BORDERSTYLE="static"
  INNERBORDER="no"
  CAPTION="yes"
  SYSMENU="no"
  MAXIMIZEBUTTON="no"
  MINIMIZEBUTTON="no"
  SCROLL="no"
  SCROLLFLAT="yes"
  SINGLEINSTANCE="yes"
  CONTEXTMENU="no"
  SELECTION="no"/>
</head>

<script language="VBScript">

Option Explicit

Dim blnCancelBubble

' ----------------------------------------
' 
' OnLoad event handler for the application.
' 
' ----------------------------------------

Sub Window_OnLoad
  blnCancelBubble = False
  ' Set up the UI dimensions.
  Const intDialogWidth = 550
  Const intDialogHeight = 125
  ' Specify the window position and size.
  Self.resizeTo intDialogWidth,intDialogHeight
  Self.moveTo (Screen.AvailWidth - intDialogWidth) / 2,_
    (Screen.AvailHeight - intDialogHeight) / 2
  ' Load the list of text-to-speech voices into the drop-down menu.
  ' See the notes in WriteFile() for more information.
  Dim objSAPI, objVoice, objSelect, objOption
  Set objSAPI = CreateObject("SAPI.SpVoice")
  For Each objVoice In objSAPI.GetVoices("","")
    Set objSelect = Document.getElementById("optVoices")
    Set objOption = Document.createElement("option")
    objOption.text = objVoice.GetDescription() 
    objSelect.Add objOption
  Next
End Sub

' ----------------------------------------
' 
' Click handler for the Write button.
' 
' ----------------------------------------

Sub btnWrite_OnClick()
  ' Test for a file name.
  If Len(txtFile.Value) > 0 Then
    ' Test if we need to cancel bubbling of events.
    If blnCancelBubble = False Then
        ' Write the input file.
        Call WriteFile(txtFile.Value)
      End If
    End If
    ' Specify whether to bubble events.
    blnCancelBubble = IIf(blnCancelBubble=True,False,True)
End Sub

' ----------------------------------------
' 
' Change handler for the input box.
' 
' ----------------------------------------

Sub txtFile_OnChange()
  ' Enable the Write button.
  btnWrite.Disabled = False
  ' Enable event bubbling.
  blnCancelBubble = False
End Sub

' ----------------------------------------
' 
' Click handler for the Close button.
' 
' ----------------------------------------

Sub btnClose_OnClick()
  ' Test if we need to cancel bubbling of events.
  If blnCancelBubble = False Then
    ' Prompt the user to exit.
    If MsgBox("Are you sure you wish to exit?", _
      vbYesNo+vbDefaultButton2+vbQuestion+vbSystemModal, _
      TextToSpeech.applicationName)=vbYes Then
      ' Enable event bubbling.
      blnCancelBubble = True
      ' Close the application.
      Window.close
    End If
  End If
  ' Specify whether to bubble events.
     blnCancelBubble = IIf(blnCancelBubble=True,False,True)
End Sub

' ----------------------------------------
' 
' This is an ultra-lame workaround for the lack
' of a DoEvents() feature in HTA applications.
' 
' ----------------------------------------

Sub DoEvents()
  On Error Resume Next
  ' Create a shell object.
  Dim objShell : Set objShell = CreateObject("Wscript.Shell")
  ' Call out to the shell and essentially do nothing.
  objShell.Run "ver", 0, True
End Sub

' ----------------------------------------
' 
' This is an ultra-lame workaround for the lack
' of an IIf() function in vbscript applications.
' 
' ----------------------------------------

Function IIf(tx,ty,tz)
  If (tx) Then IIf = ty Else IIf = tz
End Function

' ----------------------------------------
' 
' Main text-to-speech function
' 
' ----------------------------------------

Sub WriteFile(strInputFileName)
  On Error Resume Next
  Dim objFSO
  Dim objFile
  Dim objSAPI
  Dim objFileStream
  Dim strOldTitle
  Dim strOutputFilename
  Const strProcessing = "Creating WAV file... "
  
  ' Define the audio format as 44.1kHz / 16-bit audio.
  ' See http://msdn.microsoft.com/en-us/library/ms720595.aspx
  Const SAFT44kHz16BitStereo = 35
  ' Allow text to be read as well as written.
  ' See http://msdn.microsoft.com/en-us/library/ms720858.aspx
  Const SSFMCreateForWrite = 3
  
  ' Define the output WAV filename.
  strOutputFilename = strInputFileName & ".wav"

  ' Create a file system object and open the input file.
  Set objFSO = CreateObject("Scripting.FileSystemObject")
  Set objFile = objFSO.OpenTextFile(strInputFileName, 1)
  
  ' Disable the form fields.
  optVoices.Disabled = True
  optRate.Disabled = True
  optVolume.Disabled = True
  txtFile.Disabled = True
  btnWrite.Disabled = True
  btnClose.Value = "Cancel"

  ' Test for an error.
  If Err.Number <> 0 Then
      MsgBox "Error: " & Err.Number & vbCrLf & Err.Description
  Else
    ' Store the original dialog title.
    strOldTitle = Document.title
    ' Display a status message.
    Document.title = strProcessing & Time()
    ' Pause briefly to let the screen refresh and capture events.
    Call DoEvents()
    ' Create a text-to-speech object.
    ' See http://msdn.microsoft.com/en-us/library/ms720149.aspx
    Set objSAPI = CreateObject("SAPI.SpVoice")
    ' Create a SAPI file stream object.
    ' See http://msdn.microsoft.com/en-us/library/ms722561.aspx
    Set objFileStream = CreateObject("SAPI.SpFileStream")
    ' Specify the stream format.
    ' See http://msdn.microsoft.com/en-us/library/ms720998.aspx
    objFileStream.Format.Type = SAFT44kHz16BitStereo
    ' Open the output file stream.
    objFileStream.Open strOutputFilename, SSFMCreateForWrite
    ' Specify the output file stream.
    ' See http://msdn.microsoft.com/en-us/library/ms723597.aspx
    Set objSAPI.AudioOutputStream = objFileStream
    
    ' Specify the speaking rate.
    ' See http://msdn.microsoft.com/en-us/library/ms723606.aspx
    objSAPI.Rate = optRate.Options(optRate.SelectedIndex).Value
    ' Specify the speaking volume.
    ' See http://msdn.microsoft.com/en-us/library/ms723615.aspx
    objSAPI.Volume = optVolume.Options(optVolume.SelectedIndex).Value
    ' Specify the voice to use.
    ' See http://msdn.microsoft.com/en-us/library/ms723601.aspx
    ' See http://msdn.microsoft.com/en-us/library/ms723614.aspx
    Set objSAPI.Voice = objSAPI.GetVoices("","").Item(optVoices.SelectedIndex)
    
    ' Loop through the lines in the input file.
    Do While Not objFile.AtEndOfStream
      ' Test if we need to cancel bubbling of events.
      If blnCancelBubble = True Then
        Exit Do
      Else
        ' Display a status message.
        Document.title = strProcessing & Time()
        ' Pause briefly to let the screen refresh and capture events.
        Call DoEvents()
        ' Speak one line from the input file.
        ' See http://msdn.microsoft.com/en-us/library/ms723609.aspx
        objSAPI.Speak objFile.ReadLine
      End If
    Loop
    ' Close the output file stream.
    objFileStream.Close
  End If

  ' Close the input file.
  objFile.Close

  ' Destroy all objects.
  Set objFileStream = Nothing
  Set objSAPI = Nothing
  Set objFile = Nothing
  Set objFSO = Nothing
  
  ' Reset the original dialog title.
  Document.title = strOldTitle

  ' Notify the user that the file has been written.
  MsgBox "Finished!", vbInformation, strOldTitle
  
  ' Re-enable the form fields.
  btnClose.Value = "Close"
  optVoices.Disabled = False
  optRate.Disabled = False
  optVolume.Disabled = False
  txtFile.Disabled = False
  btnWrite.Disabled = False

End Sub

</script>

<body bgcolor="white" id="HtmlBody">
<div id="FormControls">
  <table>
    <tr>
      <td align="left">
        <input type="file"
        style="width:250px;height:22px"
        name="txtFile"
        id="txtFile"
        onchange="txtFile_OnChange">
      </td>
      <td align="left">
        <input type="button"
        style="width:125px;height:22px"
        name="btnWrite"
        id="btnWrite"
        value="Write File"
        disabled
        onclick="btnWrite_OnClick">
      </td>
      <td align="right">
        <input type="button"
        style="width:125px;height:22px"
        name="btnClose"
        id="btnClose"
        value="Close"
        onclick="btnClose_OnClick">
      </td>
    </tr>
    <tr>
      <td align="left">
        <select name="optVoices"
          style="width:250px;height:22px">
        </select>
      </td>
      <td align="left">
        <select name="optRate"
          style="width:125px;height:22px">
          <option value="-2">Slowest</option>
          <option value="-1">Slower</option>
          <option value="0" selected>Normal Speed</option>
          <option value="1">Faster</option>
          <option value="2">Fastest</option>
        </select>
      </td>
      <td align="right">
        <select name="optVolume"
          style="width:125px;height:22px">
          <option value="25">25% Volume</option>
          <option value="50">50% Volume</option>
          <option value="75">75% Volume</option>
          <option value="100" selected>Full Volume</option>
        </select>
      </td>
    </tr>
  </table>
</div>
</body>
</html>

Note that I intentionally chose to have this HTML Application convert the text to audio one line at a time; this slows the down the conversion process, but it allows the conversion to be cancelled if necessary. (My original version of this script would convert an entire text file at one time; since there was no way to cancel the operation, the script appeared to hang when converting larger text files.)

Additional Notes

Once you have created a Wave (*.WAV) file, you can optionally convert it to an MP3 file for use in an MP3 player or mobile phone. (Most devices should playback Wave files, but MP3 files are considerably smaller and more portable.) There are a variety of Wave-to-MP3 converters out there, but I prefer to use the LAME encoder, which is an open-source code project that is available on SourceForge. Once you have the LAME encoder project compiled, (or you have located and downloaded a pre-compiled version), you can use LAME.EXE from a command prompt to convert your Wave files into MP3 files.

That being said, I prefer to automate as much as possible, so I have written a batch file which converts all of the Wave files in a directory to MP3 files and renames the source Wave files with a "*.old" filename extension:

@echo off

for /f "usebackq delims=|" %%a in (`dir /b *.wav`) do (
  for %%b in (^"%%a^") do (
    if not exist "%%~db%%~pb%%~nb.mp3" (
      lame.exe -b 128 -m j "%%a" "%%~nb.mp3"
    )
    if exist "%%~db%%~pb%%~nb.mp3" (
      move "%%a" "%%a.old"
    )
  )
)

Note that the above batch file was written for text-to-speech use, and as such it defines a bit rate of 128kbps, which would be pretty low for music files. If you want to repurpose this batch file for higher bitrates, modify the value of the "-b" parameter for the LAME.EXE command.

That wraps it up for today's post.


Note: This blog was originally posted at http://blogs.msdn.com/robert_mcmurray/

How to create an HTML Application to configure your IIS SMTP Username and Password settings

Like many IIS administrators, I usually install the local SMTP service on my IIS servers when I am setting up a new server from scratch. When I install the SMTP service, I configure it so that it only listens on the IP address of 127.0.0.1, so it can only send emails which originate on the server itself. What's more, I configure the SMTP service to relay all emails to a downstream SMTP service which can send emails out to the Internet. By configuring these options, I can write my ASP.NET, PHP, and Classic ASP applications so that they use the local SMTP service for all email-related functionality, which acts as a sort of message server for my applications. This system works great, and I have used this particular setup since the days of IIS 4.0. (Which was released in late 1997, as you may recall.)

That being said, in the interests of security, sometime ago I started using a downstream SMTP service which requires user credentials, (that way no one could use the downstream server anonymously). As an additional security step, I use an account which requires that the credentials are changed every 30 days or so. This is always a good security practice for myriad obvious reasons, but this meant that I needed to update the SMTP username/password settings in my IIS configuration settings every 30 days.

With that in mind, many years ago I wrote a simple VBScript application which I would use to update those credentials. At first I would simply enter the credentials directly into the script, then I would run it to update IIS, and then I would strip the credentials from the script. Needless to say, this was pretty low-tech - even considering that this was 17 or 18 years ago. I eventually updated the script so that it would use VBScript Input Boxes to prompt me for the credentials, so I no longer needed to store the credentials in the script itself. (Sometime after that I rewrote the script so that it would read the existing values from the IIS settings and pre-populate the input boxes.)

Jumping ahead a couple of years, I decided to rewrite the script as an HTML Application, which offered me considerably more options from a user interface perspective. That script has been serving me faithfully for some time now, so I thought that it would make a good blog subject.

Using the HTML Application

Using the application is pretty straight-forward; when you double click the HTA file, it will present you with the following user interface:

The script will read any existing credentials from your IIS settings and use those to pre-populate the interface. If no existing credentials are found, it will pre-populate the interface with the username of the currently-logged-on user.

Clicking Update will update your IIS settings, clicking Reset will reset the values back to the last saved version, and clicking Close will obviously close the application, but only after it has checked if you have any unsaved changes.

Creating the HTML Application

To create this HTML Application, save the following HTMLA code as "Reset SMTP Password.hta" to your computer, and then double-click its icon to run the application.

<html>
<head>
<title>Reset SMTP Password</title>
<HTA:APPLICATION
  APPLICATIONNAME="Reset SMTP Password"
  ID="ResetSmtpPassword"
  VERSION="1.0"
  BORDER="dialog"
  BORDERSTYLE="static"
  INNERBORDER="no"
  CAPTION="yes"
  SYSMENU="no"
  MAXIMIZEBUTTON="no"
  MINIMIZEBUTTON="no"
  SCROLL="no"
  SCROLLFLAT="yes"
  SINGLEINSTANCE="yes"
  CONTEXTMENU="no"
  SELECTION="no"/>
<style>
<!--
body,input
{
font-family:calibri,arial;
font-size:9pt;
color: #000;
background-color: #fff;
}
table,td,th
{
border:none;
}
--> </style> </head> <script language="VBScript"> Option Explicit ' Define the global variables. Dim objWMIService, objIIsSmtpServer Dim strRouteUserName, strRoutePassword Dim blnCancelBubble, blnPendingUpdates ' ---------------------------------------- ' ' Initialization method for the application. ' ' ---------------------------------------- Sub Window_OnLoad ' Define the local variables. Dim objNetwork ' Set up the UI dimensions. Const intDialogWidth = 280 Const intDialogHeight = 220 ' Specify the window position and size. Self.resizeTo intDialogWidth,intDialogHeight Self.moveTo (Screen.AvailWidth - intDialogWidth) / 2, _ (Screen.AvailHeight - intDialogHeight) / 2 ' Enable events. blnCancelBubble = False blnPendingUpdates = False ' Set up some base objects for the local computer and default SMTP instance. ' Note that these settings can be customized for a different computer or SMTP instance. Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2") Set objIIsSmtpServer = GetObject("IIS://localhost/SmtpSvc/1") ' Retrieve the current username/password from the SMTP settings. strRouteUserName = objIIsSmtpServer.RouteUserName strRoutePassword = objIIsSmtpServer.RoutePassword ' Verify that a username was retrieved; otherwise, use the logged-on user. If Len(strRouteUserName)=0 Then Set objNetwork = CreateObject("WScript.Network") strRouteUserName = IIf(Len(objNetwork.UserDomain)>0, _ objNetwork.UserDomain & "\","") & objNetwork.UserName Set objNetwork = Nothing blnPendingUpdates = True End If ' Store the username/password values in the UI. txtUsername.value = strRouteUserName txtPassword.value = strRoutePassword End Sub ' ---------------------------------------- ' ' Implement the missing IIf() function. ' ' ---------------------------------------- Function IIf(tx,ty,tz) If (tx) Then IIf = ty Else IIf = tz End Function ' ---------------------------------------- ' ' Click handler for the Close button. ' ' ---------------------------------------- Sub btnClose_OnClick() ' Test if we need to cancel bubbling of events. If blnCancelBubble = False Then ' Check if there are pending updates. If blnPendingUpdates = False Then ' If not, then close the application. Window.close ' Prompt the user to exit. ElseIf MsgBox("You have not saved your changes." & vbCrLf & _ "Are you sure you wish to exit?", _ vbYesNo+vbDefaultButton2+vbQuestion+vbSystemModal, _ ResetSmtpPassword.applicationName)=vbYes Then ' Enable event bubbling. blnCancelBubble = True ' Close the application. Window.close End If End If ' Specify whether to bubble events. blnCancelBubble = IIf(blnCancelBubble=True,False,True) End Sub ' ---------------------------------------- ' ' Change handler for text boxes. ' ' ---------------------------------------- Sub Textbox_OnChange() ' Flag the application as having updates pending. blnPendingUpdates = True End Sub ' ---------------------------------------- ' ' Focus handler for text boxes. ' ' ---------------------------------------- Sub Textbox_OnFocus(objTextbox) ' Select the text in the textbox. objTextbox.Select End Sub ' ---------------------------------------- ' ' Click handler for the Reset button. ' ' ---------------------------------------- Sub btnReset_OnClick() ' Reset the username/password values in the UI. txtUsername.value = strRouteUserName txtPassword.value = strRoutePassword blnPendingUpdates = False End Sub ' ---------------------------------------- ' ' Click handler for the Update button. ' ' ---------------------------------------- Sub btnUpdate_OnClick() ' Catch bubbled events. If blnCancelBubble = True Then blnCancelBubble = False Exit Sub End If ' Verify valid data. If Len(txtUsername.value)=0 Or Len(txtPassword.value)=0 Then ' Inform the user that they made a mistake. MsgBox "An invalid username or password was entered.", _ vbCritical + vbOKOnly, ResetSmtpPassword.applicationName ' Cancel event bubbling. blnCancelBubble = True Else ' Store the username/password values for the SMTP server. objIIsSmtpServer.RouteUserName = txtUsername.value objIIsSmtpServer.RoutePassword = txtPassword.value objIIsSmtpServer.SetInfo ' Save the username/password values. strRouteUserName = txtUsername.value strRoutePassword = txtPassword.value ' Flag the application as having no updates pending. blnPendingUpdates = False ' Cancel event bubbling. blnCancelBubble = True End If End Sub </script> <body bgcolor="white" id="HtmlBody"> <div id="FormControls"> <table> <tr><td>Please enter your SMTP credentials:</td></tr> <tr> <td align="left"> <input type="text" style="width:250px;height:22px" name="txtUsername" id="txtUsername" onchange="Textbox_OnChange()" onfocus="Textbox_OnFocus(txtUsername)" /> </td> </tr> <tr> <td align="left"> <input type="password" style="width:250px;height:22px" name="txtPassword" id="txtPassword" onchange="Textbox_OnChange()" onfocus="Textbox_OnFocus(txtPassword)" /> </td> </tr> <tr> <td align="right"> <input type="button" style="width:125px;height:22px" name="btnUpdate" id="btnUpdate" value="Update" onclick="btnUpdate_OnClick()" /> </td> </tr> <tr> <td align="right"> <input type="button" style="width:125px;height:22px" name="btnReset" id="btnReset" value="Reset" onclick="btnReset_OnClick()" /> </td> </tr> <tr> <td align="right"> <input type="button" style="width:125px;height:22px" name="btnClose" id="btnClose" value="Close" onclick="btnClose_OnClick()" /> </td> </tr> </table> </div> </body> </html>

That's all that there is to it, although you might want to restart your SMTP service after you have made these changes.

Additional Notes

On a related topic, I get asked from time to time why I like to use HTML Applications (HTMLA) for some of my scripting examples, and the answer is quite simple: it is very easy to create powerful scripts in a very short amount of time which have sophisticated user interfaces and no compilation requirements.

I use Adersoft's HtaEdit as my IDE for HTMLA, which allows me to do normal development tasks like configuring project options, setting breakpoints, and stepping through my code.


Note: Click the image above to open it full-size in a separate window.

That being said, I have been experimenting with creating user interfaces in PowerShell, and it looks like it has some real promise for creating great UIs, too. But for now I only use PowerShell to create command line scripts, I use HTMLA to create cool UIs for administrative scripts, and I use C# to create "real" applications.


Note: This blog was originally posted at http://blogs.msdn.com/robert_mcmurray/