Books in 2023

Happy new year! Both 2024 and 2023. And 2022. I don’t think I wrote anything here in 2022 or 2023. Oops.

2023 was a pretty good reading year.

  1. Lessons in Chemistry
  2. Expanse: Leviathan Falls
  3. The Hundred-Year Marathon: China’s Secret Strategy to Replace America as the Global Superpower
  4. The Shortest History of China
  5. The Russia House
  6. The Soul of a New Machine (recommended)
  7. Russian Roulette: The Inside Story of Putin’s War on America and the Election of Donald Trump
  8. Journey to the Edge of Reason: The Life of Kurt Goedel
  9.  Breakfast of Champions
  10. American Prometheus (recommended)
  11. This Is How They Tell Me the World Ends: The Cyberweapons Arms Race (highly recommended)
  12. The End of Everything: (Astrophysically Speaking)
  13. Project Hail Mary (highly recommended)
  14. Turtles All the Way Down
  15. Titus Groan
  16. Too Big to Fail (recommended)
  17. Life in Code (recommended)

If I Have to pick a single book that I enjoyed the most, it was probably “This Is How They Tell Me the World Ends: The Cyberweapons Arms Race.”

Share

Working from Home During the Pandemic

I’ve been exclusively working from home now for over a year. The last day I was at the office was Friday, February 28, 2020. At that point, I decided the risk of getting on public transportation and being around hundreds of co-workers was too high.

Early during the next week, we stocked up and beat the rush on supplies and toilet paper, which allowed us to not shop for several weeks. In retrospect, we were probably a little too concerned (for example, we let mail sit for a couple of days before opening it, even though fomite transmission has later shown to not be a problem), but we just didn’t know. And it was relaxing to not need to go anyway.

I had a pretty good setup at home already, with a standing desk and two vertical 20″ screens (which I’ve had since early in grad school). I got the standing desk because standing was the only way I my infant daughter would let me work. The standing desk definitely saved my back. Early on, I also used a $300 subsidy from my employer Oracle to buy a 27″ 4K monitor. The screen real estate without having things split between the 20″ monitors definitely helps. I just wish I had got a 32″ 4K monitor. On the 27″, the pixels are too small.

Our schedule has definitely changed. My commute from home to work was actually pretty good, but I nonetheless save about 2 hours combined. This has allowed us to actually work out every morning. Again, if we hadn’t started that in March 2020, this past year probably would have been much less healthy for us. I’ve read that about 60% of Americans have had undesired weight changes (mostly gains) during the last year. Our weight has stayed the same, but we’ve definitely gained muscle mass. I don’t think I’ve ever been this fit on a whole-body level. My legs are less fit than during climbing season, particularly the 2017 Rainier season, but overall, my body is doing great.

I probably still spend more time working than I did before. Especially in the beginning, in March and April 2020, it was difficult for me to set boundaries. I worked early, I worked late, I worked a lot. That was draining, and I had to find the self-discipline to not look at the work computer even though it is right there. In general, self-discipline has become much more important.

Initially, I thought I’d quarantine and work from home for maybe a month or two. Now we’re reaching the end of month 13, and it will still take a few more month for sure, even though an end is in sight.

Microsoft recently announced that they are letting employees back on campus, even though they are still encouraging employees to work from home. Oracle hasn’t made that announcement yet, and I don’t think anyone will be required to come back at least until they are vaccinated, but Microsoft’s announcement made me search my feelings about returning to the office.

I’ve realized I’m not close to ready.

I anticipate it will be a few more months, maybe three, of working from home exclusively. And even after that, I plan to work from home most days of the week. There simply are lots of benefits, and my team and I have demonstrated that we can be productive even though we work remotely.

Share

My Erd?s Number

I listened to Moshe Vardi’s World Logic Day talk “From Aristotle to the iPhone” (recording to be released later). The chain of influences was quite illuminating.

That made me think of how I fit into the world of mathematics. I know I had calculated my ErdÅ‘s number at one point, but I couldn’t find it anymore. I myself haven’t authored any mathematics papers, of course, but there are computer scientists who bridge that gap.

So I used a list of Erdős collaborators, which I confirmed using the MathSciNet tool. Then I used a similar tool for computer scientists from csauthors.net.

It turns out my ErdÅ‘s numbers is at most 4 (I didn’t check all of ErdÅ‘s’ collaborators, so it could be lower, although I find that unlikely).

Here’s the collaboration chain:

4. Mathias Ricken co-authored 2 papers with
3. Vivek Sarkar co-authored 2 papers with
2. Nimrod Megiddo co-authored 3 papers with
1. Miklós Ajtai co-authored 1 paper with
0. Paul Erdős

Small, small world.

Update:

Turns out I didn’t have to do any of this search manually. My author page on csauthors.net already states:

Collaborative distances:

Dijkstra number of four.
Erdős number of four.

Share

Buffalo LinkStation and DreamHost Email

Over the holidays, I migrated from 1&1 to DreamHost, and I got almost everything to work. The only thing that didn’t work anymore were the email notifications from my Buffalo LinkStation NAS. Normally, they report once a day that everything is okay, or immediately if there is an error.

I had re-created the email account that I use for that in DreamHost, updated the SMTP server and credentials in the LinkStation admin interface, but it wasn’t sending any emails. It was saying “Test email sent.” when I tested the new settings, but nothing ever arrived. No combination of login mode and SSL/TLS/disable worked.

I had to figure out if there were logs anywhere. I know the NAS has SSH access, but I hadn’t done that in a really long time. It seems like somehow, it got disabled again. No problem, yesterday evening I ran an easy-to-use Java application called ACP Commander GUI to re-enable SSH access and set a new root password. Then I could SSH into the NAS.

The logs were fortunately easy to find in /var/log. The file messages contained the following line every time I sent a test message:

550 5.7.1 Sender domain not allowed

What in the world does that mean? It turns out DreamHost has a policy against spoofing the sender. But I don’t think I was doing that. All I was doing was sending it from nas.machine@domain.com (which had the email account set up with DreamHost) to personal.email@gmail.com. I wanted the sender to be nas.machine@domain.com, which shouldn’t be blocked, and I wasn’t setting a different sender email anywhere!

After searching a bit for the ssmtp.conf file, I found it at /etc/melco/ssmtp.conf, and it contained the following line:

FromLineOverride=YES

Whenever I set it to NO, it got overwritten again and set to YES. I don’t know from where or why, but I assume this somehow sets the sender email to the destination email. So when I was trying to send to personal.email@gmail.com, the NAS was inadvertently also setting the sender to personal.email@gmail.com, which was prohibited by the DreamHost policy.

This means I can’t send to personal.email@gmail.com from the NAS. Instead, I have to send to an email account on my DreamHost domain (e.g. nas.forward@domain.com) and forward it from there.

Oh, I love troubleshooting my tech in my free time.

Share

Down the Rabbit Hole

I’m totally going down the rabbit hole this morning…

  • I need to test an rpm package.
  • The host in the cloud can’t access the QA yum repository.
  • So I download the package to my work laptop, copy it to the cloud host, and try to install it locally.
  • Of course, it has dependencies
  • I try to download the dependencies too and copy them over to the cloud.
  • It looks like there is a cyclic dependency.
  • Screw rpm -i, let’s try to get yum to work so it can get the dependencies for me.
  • I should set up a local mirror of the QA yum repository.
  • I try to use wget to mirror the QA yum repo.
  • wget fails because some library doesn’t work.
  • I try to uninstall wget, but it fails because of permissions.
  • I fix the permissions and uninstall wgett.
  • I tell it to re-install wget, but now it needs to update Homebrew.
  • Now it’s running make.

40 minutes later, and it’s still building.

Then I try to blog about it, but this WordPress blog can’t connect to its database. Apparently, 1&1 has silently changed the database hostname. Thanks!

At least that is (obviously) fixed now.

Share

Glass Break Detector for Ring Alarm System

A little while ago, we installed a Ring alarm system in our house. We like it quite a bit. The initial installation hurdle was the need for three range extenders; then, two motion detectors were unreliable, but that turned out to be a battery issue. For the last month or so, it has run without a hitch.

Price was one of the main reasons to go with Ring instead of SimpliSafe. Both the equipment and the professional monitoring was cheaper (monitoring is $10/month or $100/year for Ring, compared to at least $15/month with SimpliSafe). Compared to ADT and Brinks, we didn’t want a long-term contract.

One thing that had me pause for a few days before purchasing the Ring system was the lack of a glass break detector. It’s really surprising that Ring doesn’t have one. In the end, though, I convinced myself that it’s really not a big issue. There are two situations: either we’re home and the system is armed, or we’re not home and the system is armed. If we’re not home, then the motion detectors are armed, and anyone stepping into our house will be detected. If we are home, then the system is armed in such a way that the motion detectors are disabled, but I’m pretty sure we’d hear the sound of glass breaking.

Still, this bugged me a little. I ended up buying another Ring contact sensor, the same little sensors we’re using on all our doors and windows. I opened it up, and it has a little magnetic reed switch in it. If I don’t use the magnet, and instead use a couple of wires to bypass the reed switch, I can simulate opening and closing the contact switch by disconnecting or connecting the wires, respectively.

There are third-party glass break detectors, for example the Honeywell IntelliSense FG-1625. It has a “normally closed” connection, which is exactly what I need: Normally, I want the wires connected, thereby bypassing the (always open) reed switch. If breaking glass is detected, I want the wires to be disconnected.

I wired up both the Ring contact sensor and the Honeywell glass break sensor accordingly, but unfortunately, the Ring wouldn’t register the glass break sensor opening the connection. In the end, I added a 2k Ohm resistor as an end-of-line resistor from C (“closed”) to EOL (“end-of-line”), and now it appears to work. When nothing is happening, Ring shows the contact sensor as closed. When the glass break sensor detects breaking glass, Ring shows the contact sensor as open, and I can alarm on it.

I’m trying this out, for now, without actually alarming and possibly calling the cops over. I’m looking for two things:

  1. Are there false positives? I’ve got the combined sensor sitting in our living room, where the most action happens. But unless we actually break glass, I shouldn’t see an alarm.
  2. What’s the battery life for the glass break sensor? It’s not really meant to be run on a 9 V battery. If the battery drains too quickly (which would register as “open connection” and therefore “glass break”, unfortunately), I probably have to hard-wire it. See update below.

Update: A day in, and the battery has drained sufficiently that it’s not outputting 9 V anymore, but only about 6.4 V. That was enough for the glass break detector to go offline (and show as “open” in Ring). I’ve now hardwired it to a 9 V power supply, and am continuing to test item #1 above.

Share

Fay Peak-First Mother Mountain Traverse

On Friday, I went on my first solo hike this year. It’s truly a different year.

I had never been in the Mowich Lake area of Mount Rainier National Park, and it looked like there were a number of good-looking peaks to visit. It had rained the days before, but I had the day off. I left home around 4:30 AM and arrived at Mowich Lake Campground right around sunrise, just as planned.

From the Mowich Lake Campground, I headed north on the east shore past the patrol cabin. Then I followed a boot path up in the direction of Knapsack Pass. At about 5400 feet elevation, I turned south to follow the Fay Peak trail. Finding this turn-off was a bit tricky. The map seemed to indicate I should climb up a small waterfall, but upon reversing my track, I found a short westward section that crossed a small creek and then immediately turned south towards the Fay Peak ridge.

I continued following that trail all the way onto to the ridge. I thought about climbing the rocks at the west end of the ridge, where the boot path arrives, but it was too slippery. In general, I was soaked already from squeezing past trees, and I put my rain pants and rain jacket on. This way, at least I was wet and warm instead of wet and cold.

View eastwards of the Fay Peak, from just below where the boot path arrives on the ridge.

On the ridge, I traversed the boot path towards Fay Peak. Mount Rainier showed itself briefly through the low clouds for the first time.

Mount Rainier, from near Fay Peak.

Initially, I attempted to scramble it from the west side, but with the slippery rocks, that wasn’t all that easy. I succeeded on the northwestern flank, but then discovered that it would have been a walk-up from the east (not too surprising, looking at the map). My next objectives, East Fay Peak and First Mother Mountain, still lay in the mist.

East Fay Peak (right), Knapsack Pass (center), and First Mother Mountain, in the low clouds.

I really wasn’t sure I would do much more, it was so wet and slippery, and I didn’t want to do any dangerous scrambling. But I could see the trail down from Knapsack Pass, and decided it was probably easier to continue along Fay Peak ridge to Knapsack Pass. But the other peaks were optional now. Well, they all are always optional.

I continued along the ridge past the middle rocks, which I climbed, to East Fay Peak. Judging by the map, it looks like it would be easier to climb from the south, and I got almost to the top, but again, the last few feet were very slippery. I circled around on the north side of the peak, and again, found the peak was a walk-up from the east.

The weather was starting to clear, and First Mother Mountain looked amazingly beautiful. I sloped north and down to the path up to Knapsack Pass, to which I connected just below the pass. I decided to head up to the pass, take a break, and look at First Mother for a bit.

First Mother Mountain and Knapsack Pass from somewhere below East Fay Peak.

The closer I got to First Mother Mountain, the more awesome it looked, but it also got scarier, and I was getting tired. I decided to take a look and only scramble it if it’s also a walk-up, which it was.

Beautiful First Mother Mountain.

The trail goes up to the westernmost little peak of the Mother Mountain ridge, then behind the 2nd little peak on the north side. First Mother Mountain can easily be scrambled from the northwest side.

View down from the summit of First Mother Mountain.

In the picture below, taken on the summit of First Mother Mountain, you can pretty much see the entire traverse I did. I came up on the far side of Fay Peak, the big massif in the center background. Then I traversed the ridge to the left, with East Fay Peak at the far left. The path up to First Mother Mountain goes up the heather slope in the center, around and behind the rock tower, and then up the chossy slope in the foreground.

View of Fay Peak from the summit of First Mother Mountain.

After that, I went back down to Knapsack Pass and down the main trail to the lake and the campground. It was a wet suffer fest — almost every step, I could wring out my gloves — but so much fun. The whole day there were only goats and I.

Share

Escaping in JSON Pointers

Do you guys want to know how to refer to the /instances node under paths using a JSON pointer?

#/paths/~1instances

~1 is the escape sequence for /. And ~0 is the escape sequence for ~. I’m really learning more than I want to know.

Why ~ and not \, for example? Okay, maybe you don’t want to have a third escape sequence, \\ to denote \. But then, why not ~~ for ~ and ~/ for /?

I guarantee you, I will never be able to remember if ~1 is slash or tilde.

<~1rant>

Share

Climbed Mount Baker

For the last few weeks, some Mountaineer friends, Jenny, and I had been planning to climb Mount Baker, Washington’s 4th highest mountain (if you count Little Tahoma as number 3). The last two weekends, though, we were weathered out.

This weekend, the weather looked great, though. We went up the Coleman-Deming route, starting leisurely on Saturday around 10 AM. We roped up at the top of the Hogsback, at the toe of the glacier. Snow was very soft. We put crampons on, but in retrospect, they weren’t helpful.

We camped at around 6800 feet, not at the Heliotrope Ridge camp (which was unnecessarily high and out of the way) or at the Black Butte High Camp (which had rock fall and, as far as we could tell, no running water). We had running water, but needed to shovel platforms.

Because of the very hot day and soft snow, we got up 11 PM and departed at midnight. We reached the summit around 6:30, but we also went very slowly and didn’t push at all. The snow was perfect styrofoam for cramponing in the morning.

We unroped just above the Colfax col and scrambled up the dirt ridge. Upon reaching the snow slope below the Roman wall, we decided to stay unroped. There were no visible crevasses, and we decided it was safer to not pull someone else down on a possible slip (there were lots of teams making questionable rope decisions, like three climbers with about 3 feet of rope in between climbers…). In the end, it was less steep than it appeared from below. I still think we made the right decision to stay unroped. We roped up again on the descent after the pumice portion, just above Colfax col.

After tearing down camp, we roped up yet again, even though the crevasses were tiny, but we wanted to set a good example. Most of us didn’t put their crampons on again. The snow was too slushy at that time (around 1 PM).

There was new ice fall debris below Colfax peak, and on the way up, my rope team didn’t find the best way through. At around 8320 feet, we headed nearly straight up-slope (south-southeast), when we should have tried to cross the ice fall (southeast). That would have gotten us to a nice flat glacier section again. We found a better way on the descent during daylight.

There were a few crevasses, but most of them were small, less than a foot. They started around 6600 feet. The two biggest ones were below the Colfax col, at around 8800 feet. The lower one was several feet wide but had a huge, solid snow bridge across; the higher one was a little over a foot wide and could be stepped over or jumped. Near the summit rim, a crevasse/bergschrund was starting to form on the climber’s left, but it didn’t reach across yet.

The road to the trailhead was in good condition, for the most part, but there were some rather big potholes, and it’s a one-lane road, so my maximum speed was probably about 20 mph. Still, no problem for my Camry.

Equipment used: poles (to the top of the Hogsback), ice axe (from toe of glacier), crampons (useful midnight to around 10 AM), rope (40 meter per team of 3, interval 10 meter, with 10 meters coiled on both ends), two pickets per team, standard personal glacier gear, GPS.

Hiking up the Hogsback.
Hiking up the Hogsback.

Camp on Saturday at 6800 feet. Photo by Sharon.
Camp on Saturday at 6800 feet. Photo by Sharon.

Summit and sunrise.
Summit and sunrise.

Summit group photo.
Summit group photo.

Rajan descending the snow slope next to the Roman Wall.
Rajan descending the snow slope next to the Roman Wall.

Descending into the ice fall below Colfax Peak. You can clearly see where the cornice broke.
Descending into the ice fall below Colfax Peak. You can clearly see where the cornice broke.

In the ice fall below Colfax Peak. Picture by Vicki.
In the ice fall below Colfax Peak. Picture by Vicki.

Jenny and I in the summit crater of Mount Baker:

Arriving on Grant Peak, the true summit of Mount Baker. Sharon is excited:

Third team on the summit of Mount Baker:

Rajan, Sean, and I heading down towards the ice fall below Colfax Peak:

Here are two links to my trip reports on Peakery and PeakBagger.

Share

Honeymooning on Black Peak

Jenny and I decided not to do an immediate, long honeymoon trip right after our wedding. Instead, we’re going to do a number of trips.

The first one was this past weekend, to Black Peak in the North Cascades. Black Peak is Washington’s 20th highest peak, and we had been talking about climbing it since fall of 2016.

The hike in was quite enjoyable, despite carrying our tent and everything else we needed to camp. The trail to Heather Pass was completely snow-free and easy. After that, our journey was mostly on snow, with a few boulder fields in between. The summer climber’s trail is beginning to melt out, though. I think in a few weeks, getting to Wing Lake will be even easier.

Above Lewis Lake in the North Cascades, on our way to camp below Black Peak.
Above Lewis Lake in the North Cascades, on our way to camp below Black Peak.

We camped right next to Wing Lake, which was still frozen over with a thin layer of ice.

Black Peak, Washington's 20th highest mountain.
Black Peak, Washington’s 20th highest mountain.

Camp at 4 AM for our summit attempt of Black Peak.
Camp at 4 AM for our summit attempt of Black Peak.

The snowfield below Black Peak’s south col was still solid, and at 5 AM, it was perfect styrofoam snow for cramponing.

Jenny climbing the steep, frozen snow to the col south of Black Peak.
Jenny climbing the steep, frozen snow to the col south of Black Peak.

The 900 vertical feet of scrambling were easy for the most part, although we once headed into the wrong gulley and had to downclimb. We were about 50 feet too far to the east.

The crux of the scramble was just below the true summit: A steep, unprotected section of three steps, totaling maybe 10 feet (picture from SummitPost, not by us). The rock was solid, and there were a number of good footholds, but the handholds were all on the side, under an overhanging rock protrusion. There was a lot of loose rock on top of the steps. On the downclimb, it was difficult to see the feet into the holds. We managed to find them, but even if we hadn’t, we could have held on to rock protrusion and ungracefully scraped down the rock face. It was probably less dangerous than it felt.

The view from the top was gorgeous, and we were happy we didn’t push to climb Black Peak on Saturday, when the weather was cloudy.

View from the summit of Black Peak, high above Wing Lake.
View from the summit of Black Peak, high above Wing Lake.

All in all, it took us four easy hours from car to camp, and three hours from camp to summit. We were back at camp before 10 AM, tore down and left camp at 11 AM, and were back at the car at 2:30 PM on Sunday.

Share

Dragontail Peak Climb

It’s been a little harder for me to get out into the mountains this year. It’s already end of May, and I don’t have much under my belt.

That’s why I’m even more excited that Jenny and I climbed Dragontail Peak last Saturday. Dragontail is 26th on the Washington Bulger List of Washington’s highest mountains, and it has been a goal for Jenny and me ever since we first set foot in the Enchantments. Last year, we climbed its neighbor, Colchuck Peak (33rd on the list).

We had permits at Stuart Lake, since I had originally planned to climb Mount Stuart, but for that, I simply wasn’t in good enough shape. So instead, we camped at Stuart Lake, then Saturday morning at 4 AM hiked to Colchuck Lake, around the lake, and then up Aasgard Pass. We were at the top of the pass around 10:30 AM and turned west-southwest towards Dragontail’s key col. From there, it was a simple scramble to 8,845 feet.

I had trouble standing up on the summit, the exposure felt so threatening. Perhaps my fear wasn’t quite unreasonable, considering Dragontail Peak drops 3,300 feet down to the lake, almost vertically.

It was a pretty amazing spot. We could see Rainier, Adams, Baker and Glacier Peak. Just St. Helens was hiding in the clouds to the south of Rainier. I haven’t been to many five-volcano spots before.

We had originally planned to head south and through Pandora’s Box, so we could glissade down the Colchuck glacier, but the snow going up Pandora’s Box was too soft. We decided it was safer, albeit much more annoying, to hike down Aasgard Pass.

We were back at our tent just before 8 PM. It was a strenuous but successful, and even enjoyable, trip of almost 16 hours.

Dragontail Peak from Colchuck Lake.
Dragontail Peak from Colchuck Lake.

Hiking up the lower slopes of Aasgard Pass.
Hiking up the lower slopes of Aasgard Pass.

Scrambling near the top of Aasgard Pass.
Scrambling near the top of Aasgard Pass.

Heading towards Dragontail's key col.
Heading towards Dragontail’s key col.

Looking into the core of the Enchantments.
Looking into the core of the Enchantments.

Aasgard Pass is below in the background.
Aasgard Pass is below in the background.

On the key col, with Rainier and Adams visible.
On the key col, with Rainier and Adams visible.

Looking back at the key col, after just having started the summit scramble.
Looking back at the key col, after just having started the summit scramble.

Looking at Pandora's Box, with Rainier right behind it.
Looking at Pandora’s Box, with Rainier right behind it.

The sharp cliffs on the east side of Dragontail.
The sharp cliffs on the east side of Dragontail.

Jenny enjoying the summit. Glacier Peak in the background.
Jenny enjoying the summit. Glacier Peak in the background.

Looking 3,300 feet down to Colchuck Lake.
Looking 3,300 feet down to Colchuck Lake.

Share

Lombok @Builder with Required Parameters?

I would really like a Lombok @Builder annotation that properly deals with required parameters at compile time.

Here is what I have in mind:

[cc lang=”java”]
@lombok.Builder
class Foo {
@lombok.Builder.Required final String name;
@lombok.Builder.Required final int age;
final String email;
}
[/cc]

This should generate the following:

[cc lang=”java”]
@lombok.Builder
class Foo {
@lombok.Builder.Required final String firstName;
@lombok.Builder.Required final String lastName;
@lombok.Builder.Required final int age;
final String email;

private Foo(String firstName, String lastName, int age, String email) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.email = email;
}

public static FooBuilder builder() {
return new FooBuilder();
}

private static class FooBuilderBase {
private String firstName = null;
private String lastName = null;
private int age = 0;
private String email = null;
private FooBuilderBase() {}
private FooBuilderBase(String firstName, String lastName, int age, String email) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.email = email;
}
public FooBuilder email(String email) {
this.email = email;
return this;
}
}

// builder with no value fixed

private static class FooBuilder extends FooBuilderBase {
private FooBuilder() {}
public FooBuilderWithFirstName firstName(String firstName) {
this.firstName = firstName;
return new FooBuilderWithFirstName(firstName, lastName, age, email);
}
public FooBuilderWithLastName lastName(String lastName) {
this.lastName = lastName;
return new FooBuilderWithLastName(firstName, lastName, age, email);
}
public FooBuilderWithAge age(int age) {
this.age = age;
return new FooBuilderWithAge(firstName, lastName, age, email);
}
// no build method yet, because the builder doesn’t have all the required info
}

// builders with one value fixed

public static class FooBuilderWithFirstName extends FooBuilderBase {
private FooBuilderWithFirstName(String firstName, String lastName, int age, String email) {
super(firstName, lastName, age, email);
}
// no more firstName method, so the user can’t clear it
public FooBuilderWithFirstName_LastName lastName(String lastName) {
this.lastName = lastName;
return new FooBuilderWithFirstName_LastName(firstName, lastName, age, email);
}
public FooBuilderWithFirstName_Age age(int age) {
this.age = age;
return new FooBuilderWithFirstName_Age(firstName, lastName, age, email);
}
// no build method yet, because the builder doesn’t have all the required info
}

public static class FooBuilderWithLastName extends FooBuilderBase {
private FooBuilderWithLastName(String firstName, String lastName, int age, String email) {
super(firstName, lastName, age, email);
}
// no more lastName method, so the user can’t clear it
public FooBuilderWithFirstName_LastName firstName(String firstName) {
this.firstName = firstName;
return new FooBuilderWithFirstName_LastName(firstName, lastName, age, email);
}
public FooBuilderWithLastName_Age age(int age) {
this.age = age;
return new FooBuilderWithLastName_Age(firstName, lastName, age, email);
}
// no build method yet, because the builder doesn’t have all the required info
}

public static class FooBuilderWithAge extends FooBuilderBase {
private FooBuilderWithAge(String firstName, String lastName, int age, String email) {
super(firstName, lastName, age, email);
}
// no more age method, so the user can’t clear it
public FooBuilderWithFirstName_Age firstName(String firstName) {
this.firstName = firstName;
return new FooBuilderWithFirstName_Age(firstName, lastName, age, email);
}
public FooBuilderWithLastName_Age lastName(String lastName) {
this.lastName = lastName;
return new FooBuilderWithLastName_Age(firstName, lastName, age, email);
}
// no build method yet, because the builder doesn’t have all the required info
}

// builders with two values fixed

public static class FooBuilderWithFirstName_LastName extends FooBuilderBase {
private FooBuilderWithFirstName_LastName(String firstName, String lastName, int age, String email) {
super(firstName, lastName, age, email);
}
// no more firstName, lastName methods, so the user can’t clear it
public FooBuilderComplete age(int age) {
this.age = age;
return new FooBuilderComplete(firstName, lastName, age, email);
}
// no build method yet, because the builder doesn’t have all the required info
}

public static class FooBuilderWithLastName_Age extends FooBuilderBase {
private FooBuilderWithLastName_Age(String firstName, String lastName, int age, String email) {
super(firstName, lastName, age, email);
}
// no more lastNam, age methods, so the user can’t clear it
public FooBuilderComplete firstName(String firstName) {
this.firstName = firstName;
return new FooBuilderComplete(firstName, lastName, age, email);
}
// no build method yet, because the builder doesn’t have all the required info
}

public static class FooBuilderWithFirstName_Age extends FooBuilderBase {
private FooBuilderWithFirstName_Age(String firstName, String lastName, int age, String email) {
super(firstName, lastName, age, email);
}
// no more firstName, age method, so the user can’t clear it
public FooBuilderComplete lastName(String lastName) {
this.lastName = lastName;
return new FooBuilderComplete(firstName, lastName, age, email);
}
// no build method yet, because the builder doesn’t have all the required info
}

// builders with three values fixed

public static class FooBuilderComplete extends FooBuilderBase {
private FooBuilderComplete(String firstName, String lastName, int age, String email) {
super(firstName, lastName, age, email);
}
// no more firstName, lastName, age methods, so the user can’t clear it
// but now we have a build method
public Foo build() {
return new Foo(firstName, lastName, age, email);
}
}
}
[/cc]

So basically, if we have n required parameters, we 2^n builder classes. For each r required parameters that have been set already, we need n-choose-r builders.

In the example above, we have three required parameters. We have one builder that has no required parameters set, three that have one value set, three that have two values set, and one that has all of them set.

Unfortunately, the source code for rewriting the bytecode in response to a [cci lang=”java”]@Builder[/cci] annotation is almost 1000 lines long. Not exactly the best example of well-structured code.

Share

Looking for a Replacement for Amazon Music Uploads

Now that Amazon Music is shutting down the ability to upload and play your own songs, what do you use as a replacement?

I have hundreds of CDs that I imported — complete Mike Oldfield, almost complete Depeche Mode, lots of classical music of which I’ve found one performance I prefer.

How will I get those to play on my Amazon Echo devices and my Android phone?

Share

Rerun: My favorites pictures of 2017

In preparation for the WTA’s Northwest Exposure photo contest, I was reviewing my favorite pictures from this year, just like I did last year.

But there are just too many this year. I’ve been to so many gorgeous places, gone on so many amazing trips, I just have a really hard time reducing my set of photos to just a top 5. With a lot of heartrending, I think I can manage to cut it to a top 12.

Camp Schurman, in front of Mount Rainier.
Camp Schurman, in front of Mount Rainier.

Climbers on the Emmons route to the summit of Mount Rainier.
Climbers on the Emmons route to the summit of Mount Rainier.

Sunrise at Camp Schurman, Mount Rainier.
Sunrise at Camp Schurman, Mount Rainier.

Mountaineers descending Silver Star Mountain.
Mountaineers descending Silver Star Mountain.

Mount Adams and Mount Hood, seen from Mount Rainier.
Mount Adams and Mount Hood, seen from Mount Rainier.

Mountaineers on the Emmons Glacier of Mount Rainier.
Mountaineers on the Emmons Glacier of Mount Rainier.

Camp near Dome Peak.
Camp near Dome Peak.

View from the "Sidewalk" of Dome Peak, with climbers on the Dome Glacier.
View from the “Sidewalk” of Dome Peak, with climbers on the Dome Glacier.

Mountaineers and penitentes at sunrise on Mount Rainier.
Mountaineers and penitentes at sunrise on Mount Rainier.

On the Winthrop glacier on Mount Rainier.
On the Winthrop glacier on Mount Rainier.

Summit block of Mount Hood at sunrise.
Summit block of Mount Hood at sunrise.

Exploding with sunlight near the summit of Mount Hood.
Exploding with sunlight near the summit of Mount Hood.

Share

Comparison between GPSMAP 64st and InReach Explorer+

We’ve been shopping around for a handheld GPS, since many climbs require the ability to retrace our route. Since I have an InReach SE, it made sense to check out the InReach Explorer+, which combines a satellite messenger with topographic maps. We also tried out the GPSMAP 64st. Both devices are by Garmin.

We took both up on our August climb of Mount Rainier. The InReach Explorer+ is nice, since it means we only have to carry one device, instead of a messenger and something with topographic maps. Unfortunately, in terms of map detail and accuracy, it is quite far behind the GPSMAP 64st.

Here are our tracks, from just before the Disappointment Cleaver to somewhere on the Emmons or Winthrop glaciers, as seen in Google Earth. First, the track recorded by the GPSMAP 64st:

Track recorded by GPSMAP 64st
Track recorded by GPSMAP 64st

And here is the track recorded by the InReach Explorer+:

Track recorded by InReach Explorer+
Track recorded by InReach Explorer+

You can see that the track on the InReach is much less uniform, and there are a few points that are actually quite far away.

In terms of detail that can be discerned on the display, the InReach also can’t compete with the GPSMAP 64st. Here is the topographic map around Camp Muir, first on the GPSMAP 64st:

Topographic map on GPSMAP 64st
Topographic map on GPSMAP 64st

And here is the same map location on the InReach Explorer+:

Topographic map on InReach Explorer+
Topographic map on InReach Explorer+

You can’t even see Muir Peak, to the east of the camp!

I think we’ll return the InReach Explorer+ and keep the GPSMAP 64st. We just have to figure out a way to keep the latter from turning on accidentally and draining the battery.

Share

Kaspersky SafeMoney, LastPass, and Yubikey?

I’m using Kaspersky SafeMoney to redirect requests to websites that deserve a bit more security to a sandboxed browser. I don’t have any extensions in it, except for LastPass. I think it makes sense to still get the benefits of a strong master password and different strong passwords for each site that I don’t have to remember.

Unfortunately, when I added Yubikey to the mix, LastPass started asking me for the Yubikey every time the secure browser launches.

The option to “trust this browser for 30 days” doesn’t seem to do anything anymore. Has anyone got this to work?

Share

Second Mount Rainier Climb

On August 4 and 5, Jenny and I climbed Mount Rainier again, this time with Tatiana, Daniel, and Ian. I’m going to write a longer trip report again, but here are a couple of 360-degree pictures from the summit, and a 360-degree video from crossing a crevasse using a ladder.

My second time on the crater rim of Mount Rainier:

Dan, Jenny, Tatiana, Ian and I, on the summit of Washington’s highest mountain:

Crossing a crevasse using a ladder:

It was another great trip!

Share