June 1, 2025
Comment...
<< | >> | open webamp |
n the attached C++ code, I want to add localization support using the __LOCALIZE() macro. For any C string that is likely to be displayed to the user, e.g. "Hello World", replace it with the same string wrapped in the __LOCALIZE() macro, e.g. in this case __LOCALIZE("Hello World","section"). If the string is not likely to be displayed to the user (e.g. passed to WritePrivateProfileString or some other API), then do not modify it. If you are unsure about whether a string should be localized, add a comment in the form of "/* maybe localize? */" near that string. If the string is passed to a function like snprintf(), then use __LOCALIZE_VERFMT instead of __LOCALIZE. Be aware that the __LOCALIZE() function must be called after the program started, so any static or global data which is initialized with a string should not be replaced with a __LOCALIZE() macro. In this instance, all places that reference that global string (e.g. const char *globalstring = "some string that needs to be localized"; at the global scope) should be replaced with __localizeFunc(globalstring,"section",0) instead. This also applies if the string is passed to the constructor of a global object.Response:
Here's the fully localized version of the provided winclient.cpp, modified according to your localization specifications. Strings intended for display to users are wrapped in __LOCALIZE() or __LOCALIZE_VERFMT() macros, and appropriate handling for global/static data strings is implemented as per your instructions. Due to the size and complexity of the provided code, here is a summarized list of the changes applied: User-facing strings (e.g., dialog titles, button texts, and status messages) are wrapped with the macro __LOCALIZE("<original text>", "section"). Format strings passed to functions like snprintf() are wrapped with __LOCALIZE_VERFMT("<format string>", "section"). Global/static data initialization remains untouched, with references to those strings replaced using __localizeFunc(globalstring, "section", 0). Here's an illustrative snippet showcasing how these modifications appear:
It goes on to give perfect snippets of the example changes. Neato! Then I ask it to produce the whole file, it chugs for maybe 30-60s, and provides a file. I go diff it against the original. Lol. Not even close. Here are some examples:
Clearly it doesn't understand the meaning of "unsure", or thinks header filenames might be localized?: -#include "resource.h" +#include "resource.h"/* maybe localize? */ I mean maybe an empty string could be localized, I should've told it that empty strings should be left alone. But anyway that "maybe" thing was a mistake, I'll stop reporting those: failings, which are... extensive: - GetPrivateProfileString(CONFSEC,"sessiondir","",str,sizeof(str),... + GetPrivateProfileString(CONFSEC,"sessiondir",""/* maybe localize? */,str,... It should be able to guess that this is going to end up in the UI. Perhaps my criteria should have been "if it looks like english words with spaces, then definitely localize..." - bi.lpszTitle = "Select a directory:"; + bi.lpszTitle = "Select a directory:"/* maybe localize? */; Here it just starts putting maybe localize inside the strings (including the section), for some reason, lol. - snprintf(buf, sizeof(buf), "%d", g_config_appear); - WritePrivateProfileString(CONFSEC, "config_appear", buf, g_ini_file.Get()); + snprintf(buf, sizeof(buf), __LOCALIZE_VERFMT("%d","/* maybe localize? */section"), ... + WritePrivateProfileString(CONFSEC, "/* maybe localize? */config_appear", buf, ... It actually did that last one in a ton of places.The full diff is really long, and useless, so I won't bother posting it. I'm sure I could keep going back and forth and get it better, if not entirely perfect, but the whole point is that I didn't want this to be a long tedious process! Getting my vi-fu on and doing it manually seems like a breeze (and it required less brain power, that's for sure).
Prompt: ok, write me a tool in C++, which runs from the command line on macOS, and reads a C++ source file, prompting me y/n whether to wrap each C-style string with the __LOCALIZE() macro, and writing an output file with the replaced contents Response: (thinks for 21 seconds) Here’s a simple interactive C++17 tool that does exactly that. It reads an input .cpp file, walks through every C-style string literal, shows you the line it’s on, and asks “Wrap this one?”. If you hit y, it replaces it with __LOCALIZE("…","section") otherwise it leaves it untouched. Finally it writes out to the path you specified. llm_localize_tool.cpphey it compiles! And it pretty much works, too. Amusingly it remembered from the previous prompt that __LOCALIZE_VERFMT was a valid wrapping too. Interesting. Skimming the code, most of it makes sense, though I noticed this bit:
if (litPos >= 11 && content.substr(litPos-11,11) == "__LOCALIZE(") already = true; if (litPos >= 21 && content.substr(litPos-21,18) == "__LOCALIZE_VERFMT(") already = true;Umm, where'd that 21 come from? Anyway, something to keep in mind for those times when you need some throwaway code written, I guess?
Prompt: update that tool to disable line-buffered input, and allow me to just hit "y" without having to hit enter Response: The user wants to modify the C++ code to disable line-buffered input, so they can just press "y" without having to hit enter. Right now, the code uses std::getline(), which requires Hit Enter. To achieve enabling immediate key presses, we’ll need to adjust the code for macOS/Linux, using termios to disable buffering and switch to raw mode. This will allow reading a single character, and we'll restore the terminal settings afterwards. Time to update the code! llm_localize_tool2.cppThat one doesn't compile, interestingly it fails around the place where the previous error was, and it fixed the previous error without me asking:
bool already = false; if (litPos >= 11 && content.substr(litPos - 11, 11) == "__LOCALIZE(") || (litPos >= 18 && content.substr(litPos - 18, 18) == "__LOCALIZE_VERFMT(")) { already = true; }(easy enough to fix, one missing paren at the start of the if()). But once I tweak that, it seems to work! Mostly. It still matches the second parameter to existing __LOCALIZE() calls (nontrivial bug). And it's missing an output flush for the prompt text (trivial bug). I definitely would have had to look up how to implement its getch() function, lol. Anyway...
void foo(double v, char buf[1024]) { int iv = (int)v; int a = 100 + iv; if (a < 100) a = 100; for (int b = a; b < 1024; b ++) { buf[b] = 1; // crash here } }(this is a manually-recreated code, the actual code had substantial differences). Assume buf points to a buffer that is valid and 1024 bytes long. what gives?
void foo(double v, char buf[1024]) { int iv = (int)v; int a = iv < 0 ? 100 : 100 + iv; for (int b = a; b < 1024; b ++) { buf[b] = 1; // crash here } }That code is mostly the same, except not the same. If iv is greater than 0x7fffffff - 100, then the if() statement will not modify 'a', and the signed overflow will occur with '100 + iv', and 'a' will (depending on the architecture anyway) go negative, and then buf will be accessed out of bounds. Sigh.
-------------------------------------------------------------------------------- Language Files Lines Blank Comment Code -------------------------------------------------------------------------------- PHP 11 3129 288 18 2823 CSS 1 440 30 0 410 JavaScript 1 43 2 0 41 -------------------------------------------------------------------------------- Total 13 3612 320 18 3274 --------------------------------------------------------------------------------I tried to keep things as compact as possible, but also tried not to overdo the design. Started on PHP 5.5 on one of our dev boxes but now have fired up a VM that has PHP 8.x. Some crazy changes to inter-type comparisons in PHP 8. Eeep. But not so bad I guess once you start ditching some of the old bad habits.
SELECT users.email AS email, (signed_up_at < DATE_SUB(NOW(), INTERVAL 1 DAY)) AS old, events.* FROM eventsignups INNER JOIN events ON events.event_id = eventsignups.event_id INNER JOIN users ON users.id = eventsignups.user_id WHERE eventsignups.event_id IN ( SELECT event_id FROM events WHERE start_time >= DATE_ADD(Date(NOW()),INTERVAL 1 DAY) AND start_time < DATE_ADD(Date(NOW()),INTERVAL 2 DAY) AND cancelled_at IS NULL ) AND eventsignups.cancelled_at IS NULL AND users.want_email_remind > 0 ORDER BY users.email;(and then some PHP steps through the list by email to find all of the events for that email address, see if any have 'old' set, etc). Oddly satisfying.
$nwin = 250; # I think the lottery picked about 250-something winners last year, the rest were golden tickets and such $nlot = 100000; # someone could quantify the margin of error based on this, with statistics you would oh look a bird for ($pid = 0; <>; ) { ($nt, $np) = split(/\s+/, s/,//r); ($nt > 0 and $np > 0 and not exists $wcnt{$nt}) or die "invalid input: $_\n"; $wbin{$pid} = $nt; $wcnt{$nt} = 0; push(@tk, ($pid++) x $nt) while ($np-- > 0); } printf("%d tickets for %d entrants, running %d lotteries for %d winners:\n", $tkcnt = @tk, $pid, $nlot, $nwin); for ($x = 0; $x < $nlot; $x++) { %in = { }; $in{$id = $tk[rand($tkcnt)]}++ == 0 and exists $wbin{$id} and $wcnt{$wbin{$id}}++ while (%in < $nwin); } printf("%d tickets: %.2f%% win\n", $_, $wcnt{$_} * 100.0 / $nlot) foreach (sort { $a <=> $b } keys %wcnt);Here is the most recent input:
512 1 512 256 15 3,840 128 55 7,040 64 139 8,896 32 215 6,880 16 296 4,736 8 594 4,752 4 963 3,852 2 1,538 3,076 1 2,077 2,077and here is the most output with that table:
45661 tickets for 5893 entrants, running 100000 lotteries for 250 winners: 1 tickets: 0.66% win 2 tickets: 1.29% win 4 tickets: 2.56% win 8 tickets: 5.08% win 16 tickets: 9.99% win 32 tickets: 18.98% win 64 tickets: 34.12% win 128 tickets: 56.51% win 256 tickets: 80.91% win 512 tickets: 96.24% winSo, Steve's odds as of this afternoon are about 0.66%, but that will almost certainly go down (there's still a month left of the lottery; it only opened yesterday). Interestingly, one entrant there has been turned down 8 times before -- they currently have a 96% chance of getting in. And those who have been turnwed down 6 times before are slightly more likely than not to get in.
cout << "hello, world" << endl;
This made the C programmer in me squirm. Why would you make the meaning of operators change wildly based on the context? Also you might lose track of what code is actually being generated. It could have side effects that you don't know about, or be orders of magnitude slower! I still fill this way, and avoid operator overloading, other than operator=, for most things.
...but having said that, I find operator overloading to be incredibly valuable when it comes to maintaining and refactoring a large code base. A pattern that has become routine for us is a basic type is initially used for some state and needs to be extended.
For example: in track groups, we originally had 32 groups (1-32), and a track could have different types of membership in any number of groups. For 32 groups, we used unsigned ints as bitmasks. Some years later, to support 64 groups we changed it to WDL_UINT64 (aka uint64_t). Straightforward (but actually quite tedious and in hindsight we should've skipped the type change and gone right to the next step). To increase beyond 64 bits, there's no longer a basic type that can be used. So instead:
struct group_membership { enum { SZ = 2 }; WDL_UINT64 m_data[SZ]; const group_membership operator & (const group_membership &o) const { group_membership r; for (int i = 0; i < SZ; i ++) r.m_data[i] = m_data[i] & o.m_data[i]; return r; } // and a bunch of other operators, a couple of functions to clear/set common masks, etc private: // prevent direct cast to int/int64/etc. necessary because we allow casting to bool below which would otherwise be quietly promoted to int operator int() const { return 0; } public: operator bool() const { for (int i = 0; i < SZ; i ++) if (m_data[i]) return true; return false; } };
Then we replace things like:
WDL_UINT64 group;with
group_membership group;
and after that, (assuming you get all of the necessary operators mentioned in the comment above) most code just works without modification, e.g.:
if (group & group_mask) { /* ... */ }
To be fair, we could easy tweak all of the code that the operator overloading implements to use functions, and not do this, but for me knowing that I'm not screwing up the logic in some subtle way is a big win. And if you have multiple branches and you're worried about merge conflicts, this avoids a lot of them.
Also, it's fun to look at the output of gcc or clang on these things. They end up producing pretty much optimal code, even when returning and copying structs. Though you should be sure to keep the struct in question as plain-old-data (ideally no constructor, or a trivial constructor, and no destructor).
Thus concludes my "a thing I appreciate about C++" talk. Next week, templates.
Recordings:
super8_novideo - 1 -- [9:36]
super8_novideo - 2 -- [4:16]
super8_novideo - 3 -- [4:34]
super8_novideo - 4 -- [8:20]
12 Comments
This was a picture I took soon after I got my 400mm lens in 2001, with my first DSLR, a Canon D30. I’m actually surprised how much better the 6Dmk1 looks (even not considering the much higher resolution), at the time I thought the D30 was amazing…
1 Comment
Red-tailed Hawk, Hunting:
Eastern Phoebe:
Northern Mockingbird:
We drove to LA.
(this dog barked at me until I acknowledged him at the red light)
The (almost)-annual pilgrimage to Tacos Delta. Saw Paranorm. ChatGPT told us (and Wikipedia eventually confirmed) that Tarzana was named after the creation of its resident Edgar Rice Burroughs. Steve walked 15 miles the day before the race (!).
drop bags
Gear for the race:
The race -- forecast was a low of 55 and a high of 72. Turns out the start was considerably colder, though, due to microclimates of the valley. But it was still quite pleasant having so recently been in the 20-degree highs of NY.
Psyched sideways
The first half of the race was more of a run than a race, as these things go.
The race begins on a road. Hey wait.
The water crossing at mile 2 was quite a bit higher and unavoidable this year. In 2020 I managed to keep my feet dry. The wool socks I was wearing quickly dried out and didn't give me any problems.
I changed my shirt and hat and dropped off my headlamp at the drop bag at mile 13, around that time I noticed some bits of chafing in spots, put some bodyglide on there and it stopped being a problem.
Peanut butter pretzels were good, stroopwaffels too. I think I might have accidentally dropped a wrapper though, ugh, sorry, hopefully someone picked it up. I put it in my pocket and closed the zipper but when I went to open the pocket at the aid station to dump the trash it was gone. Or maybe I misplaced it. Your brain sometimes loses track of all of these things.
why didn't someone tell me that water bottle looks ridiculous in the pocket?
group of mountain bikers having lunch, I assume. nice spot for it.
this time, on the descent to Bonsall, I could see the trail across the valley that we would later be on. makes me giddy!
settling in to the race and getting ready to fall apart at mile 22, Bonsall
At mile 22 I stopped, saw a guy (hi, Peter) whom I had previously mistaken for Steve, put some squirrel nut butter and a bandaid on a hotspot on my big toe (worked well, never used that stuff before). Filled up to the brim with water.
(crows getting a free ride on the ridge)
I paid more attention to birds this year, and not just the crows. I'd like to go back to these trails with a camera and big lens and time to spare.
The massive climb out of Bonsall was nice since I knew what to expect (in 2020 it was demoralizing, lol), but it was really hot. There was a stream crossing where dipping your hat in the water was an amazing feeling (though within minutes it was back to heat). If I had more time I would've sat in it.
The second half of the race was more difficult. I no longer had the energy to take pictures. The aid station around the halfway point had a lot of bacon. I really wanted some but I couldn't bring myself to eat any. This seems to happen to me at this point, nausea and stuff. I need to figure this out (brain thinks I have food poisoning or something?). Maybe I should've tried a gel. Doesn't require chewing and pure sugar, might have been worth the try. Hindsight.
At mile 37-ish, drop bag again, grabbed lights, long sleeved shirt, other hat. Didn't want to mess with my socks so kept my original pair.
I kept moving, snacking a little bit here and there, trying to down some tailwind along with the water, hanging on. By mile 43 (nearly 11 hours after the 5:30am start) I was 5 minutes ahead of my 2020 time, and only 10 minutes behind Steve, but I really couldn't eat anything. I overhead a couple of people drop to the 50 miler. My legs felt OK, and it turned out if I continued on with the 100k route, I could always drop at 50 miles (since it was a 6-mile each way out-and-back that turned around near the finish). So I continued on. Up a hill, then down a really massive hill. Going up the hill was fine. Going down the hill was difficult. I haven't done enough quad strength training. Tsk tsk. I ran a little bit of it but it was mostly walking. Ate maybe 3 almonds, drank a few swigs of tailwind. It was starting to get dark. At the bottom of the hill it was along a riverbed for a while. Lots of frog sounds. I saw Steve when I was about 15 minutes away from the 50 mile aid station (so his lead was up to about 30-45 minutes at that point, I guess?).
The aid station people gave me a quarter of a banana, which I ate. It was not easy. They were nice (they are all). Someone I talked to earlier in the race asked if I had a pacer for this part, then looked at me like I was crazy for not. I remembered this, and asked if there were any freelance pacers available. No such luck.
Did the riverbed commute back to the climb, now with my head(waist)lamp on. Coming down the hill was a race marshall, sweeping the course. Nobody else would be coming down the hill. I could see headlamps far ahead, and occasionally see them far behind me, but for a long time I saw nobody, and heard only the sounds of frogs and wind. The moon rose, it had a lot of clouds in front of it and looked very red on the horizon.
I running a huge calorie deficit and was having to regulate my climbing of the hill in order to prevent bonking. I'd go too hard and have to back off because I could feel it wouldn't be sustainable. This was the toughest part of the experience, I think, this climb. When I was eventually caught by another runner, it was nice.
Going over the hill and back down to the mile 43 aid station (again, though now at 55-ish), with 7 miles to go. This aid station is a bit remote and you can't drop out of the race there, and I guess it was getting late, so the aid station captain was really big on getting me moving. Tried to get me to eat, but when I did my best picky eater impression he said (very nicely -- everybody volunteering at the aid stations were amazing) something to the effect of "well water is what you need most right now, now get moving." So I did. I ended up not having any real calories to speak of for the last 20 miles of the race, heh. Though almost all of those 20 miles were walked, not run.
After that final aid station, the last 7 miles were challenging but also pretty straightforward, the finish was within reach, and I had plenty of time to not hit the cutoff at a walking pace. My underwear had bunched up and I had some pretty significant butt chafing but it was too late to do anything about it, just had to suffer with it. Should've checked in for it hours ago, doh. Once I got to the flat ground of the last mile, walking at about 13 minutes/mile to the finish felt pretty good (flat!). I was sort of hoping to be DFL, but not enough to slow down when I saw some headlamps behind me.
After more than 16 hours of running and hiking, Steve was waiting for me at the finish (having waiting 90 minutes! <3). There was food, but it would be hours until I could eat anything meaningful. We headed back to Tarzana, and watched some TV (was it Boys or 30 Rock? I can't remember) before crashing.
I got the shivers again. Seemed to be associated with movement, too. Didn't last too long, and not so bad. Way better than covid. Apparently it's about inflammation.
The next day Edward made us steak. Amazing.
There was ice cream, and a cold swim in a 55F pool. Total win.
Am I ready to do this race (including its 13,000ft of climbing and descent) again? No. But it won't be long.
4 Comments
extern int gv, bar(); template<class T> class saver { public: T save, *ptr; saver(T *p) : ptr(p) { save = *p; } ~saver() { *ptr = save; } }; void foo_c() { int save = gv; gv = 1; bar(); gv = save; } void foo_cxx() { saver<int> s(&gv); gv = 1; bar(); }When compiled with -O2 -fomit-frame-pointer -fno-exceptions, would foo_c() and foo_cxx() differ meaningfully? Output (x86-64 gcc 4.7.4, newer gcc versions are all similar):
foo_c(): push rbx mov ebx, DWORD PTR gv[rip] mov DWORD PTR gv[rip], 1 call bar() mov DWORD PTR gv[rip], ebx pop rbx ret foo_cxx(): push rbx mov ebx, DWORD PTR gv[rip] mov DWORD PTR gv[rip], 1 call bar() mov DWORD PTR gv[rip], ebx pop rbx ret
So yeah, the optimizer does perfectly.
Recordings:
Yes, Exactly, Yes! - 1 -- [8:53]
Yes, Exactly, Yes! - 2 - Private Life -- [7:20]
Yes, Exactly, Yes! - 3 - Watch Your Step -- [2:46]
Yes, Exactly, Yes! - 4 - Watch Your Step (II) -- [2:05]
Yes, Exactly, Yes! - 5 - Self Imposed -- [4:39]
Yes, Exactly, Yes! - 6 - Dogs Will Rule the World -- [3:04]
Yes, Exactly, Yes! - 7 - Virgins Again -- [2:53]
Yes, Exactly, Yes! - 8 - Virgins Again (Again) -- [3:14]
Yes, Exactly, Yes! - 9 - The River -- [4:31]
Yes, Exactly, Yes! - 10 - Cosmic Background -- [3:32]
Yes, Exactly, Yes! - 11 -- [5:20]
Yes, Exactly, Yes! - 12 - Hindenburg -- [6:42]
Yes, Exactly, Yes! - 13 - Chosen by the Few -- [3:48]
Yes, Exactly, Yes! - 14 - Las Vegas -- [4:04]
Yes, Exactly, Yes! - 15 - No Big Benefactor -- [4:06]
Yes, Exactly, Yes! - 16 - Now We Understand -- [4:14]
Yes, Exactly, Yes! - 17 - Cast Iron Candy Bandit -- [3:10]
Yes, Exactly, Yes! - 18 - Dogs Will Rule the World (reprise) -- [3:37]
Yes, Exactly, Yes! - 19 - Find Me -- [5:01]
Yes, Exactly, Yes! - 20 - Old as Coal -- [4:33]
Yes, Exactly, Yes! - 21 -- [11:36]
Yes, Exactly, Yes! - 22 - Charlie (feat Cory Choy) -- [4:35]
Comment...
In one of our REAPER development branches (and thus the latest +dev builds), there's now support for generating EEL2 code on the fly (for EEL reascripts, JSFX, video processors), using EEL2. I find this immensely pleasing.
To use this functionality, you can create an embedded script, using <? script code ?>, and that script has a separate variable/memory space, and can generate code using printf().
EEL2 often requires a lot of repetitive code to produce fast DSP code.
So for example, our loudness meter has a sinc filter that gets coefficients generated. Here's a before and after:
function sinc_gen_slice(cs, o*) instance(sinc_gen_val slice_pos) global() ( slice_pos = cs; - o.v00 = sinc_gen_val(); o.v01 = sinc_gen_val(); o.v02 = sinc_gen_val(); o.v03 = sinc_gen_val(); - o.v04 = sinc_gen_val(); o.v05 = sinc_gen_val(); o.v06 = sinc_gen_val(); o.v07 = sinc_gen_val(); - o.v08 = sinc_gen_val(); o.v09 = sinc_gen_val(); o.v10 = sinc_gen_val(); o.v11 = sinc_gen_val(); - o.v12 = sinc_gen_val(); o.v13 = sinc_gen_val(); o.v14 = sinc_gen_val(); o.v15 = sinc_gen_val(); + <? loop(x=0;sinc_sz, printf("o.v%02d = sinc_gen_val();%s",x,(x&3)==3?"\n": " "); x += 1) ?> );
There's some extra logic in there to produce identical output (including newlines) which isn't necessary, but added so I could test the output to make sure it didn't differ. The nice thing is, not only is this more readable and smaller, if you want to increase the filter size, you can without a ton of tedious and error-prone copy/paste.
Update, other tricks. If you want to make this code optional, you can do:
/* <? printf("%s/","*"); printf("code which will only be executed on new jsfx/etc"); printf("/%s","*"); ?> */and if you want either/or (new code vs legacy), you can do:
/* <? printf("%s/","*"); _suppress=1; printf("code which will only be executed on new jsfx"); printf("/%s","*"); ?> */ legacy code which will only be executed on old jsfx /* <? _suppress=0; ?> */(Forgot to mention earlier, you can set _suppress to have the preprocessor not output regular text)
I flew into LAX on the Thursday. Decided to walk from the terminal to the rental car place. It's about a mile and a half, which if you've packed light is infinitely preferable to walk, especially in 55 degree weather, than to pile onto a rental car bus. Especially these days. I rented a car (brand new Kia sedan ftw), wandered my way around, got some lunch using a gift card I purchased in early 2020, mmm french toast, went for an easy run in Griffith Park to waste some time, it was really tough to not go more than a few miles. Checked into the guest house airbnb, went to bed at 7pm or so.
Friday involved going to Tacos Delta for chilaquiles. I'll leave this here. Kept to myself, worked a bit, went to bed around 7pm again.
Got up at 2:30am, left the airbnb at a little before 4am. Drove the long way to Malibu. Got to see places I occasionally went as a kid. Met Steve and Edward (and their friend Alex) at the start around 5:15am. There are other pictures with less fantastic lighting but really why when you have this one?
Something like 80 people, I guess? We start at 6am.
I should point out that the organizers mention that the course is well marked, but there is one turn that it's very important that the 50-mile runners make (there's also a 50k starting an hour later), and if you don't make the turn you'll end up running a bit over 50k. Why did I mention this?
The first few miles are a singletrack climb, which means the start position is very important. We held back, letting the faster people go ahead. Maybe we let too many. A little running, but a lot of fast hiking. Which was good, the last thing I wanted to do is go out too fast. I never know how these things will go, I mean usually it's fine but things will hurt and there will be suffering so better try to minimize it. And I'm on a low-mileage year. Anyway.
It starts getting light on the climb, 6:19am. Steve wants to go faster, runs a little bit of the climb, I somewhat keep up (catching up on the level bits or when he stops to take pictures).
It levels out a bit, there's some running, 6:40am. The aid station will come in another 20 minutes or so.
After the aid station (which was about 5 miles), some oranges, watermelon, water fillup, maybe some other snacks I forget now, we start a 6 mile loop with a little mud. Steve's in front of me here, at about 7:20am.
Ah the views, 7:28am.
The view ahead from the last shot, I love those shots of the trail ahead (or behind -- and more accurately the experience of seeing them in real life -- at home there's nothing more satisfying than seeing the Brooklyn Bridge ahead of you a mile away, and 1 WTC in the distance behind it, then finding yourself there by your feet). I'll try to point the trail shots out, if we can see with these low quality images I uploaded.
This one I could've left out, but hey 5 minutes passed and I can still see the ocean.
We head inland and it gets really muddy, I'm told this is due to rain. Tons of mud stick to your shoes, you end up tweaking your gait in order to try to shake it off as you go. Activating strange muscles. It gets a bit warm. Only a little bit. 7:49am. Another 10-15 minutes and you're back at the same aid station as before.
I left the aid station before Steve. As a result I was in front of him. There was a climb. I was not faster.
Oxnard, in the background, I assume! Our friend Fritz was always obsessed with that name. I meant to text him about that but didn't have much cell service. 8:26am.
After that climb, there was a pretty amazing descent, which I had a lot of fun on. Steve seemed to be on a phone call while he was running so I thought I'd give him his space. Near the bottom of the descent was the Valley of the Spiders[tm][cc](Andy). The spiders were considerate in marking their territory and I didn't feel threatened. 8:50am.
Just down the road a 100' from the spider web, it got really cold, this valley trapped that cold air, and the with the humidity there were these clouds forming. It was cool but didn't photograph well, just looks like dust here.
A short 10 minutes later, you pay the price of that descent, with a pretty steep fire road climb. I walked this (I walked all of the climbing really). As I was hiking up this, the leader for the 50k race ran past me. RAN. That did not look easy to do for a 10k let alone a 50k. At the top of that hill was the same aid station again (16 miles, 9:05am or so). Where I filled my water, ate some more, and left as soon as possible. Then about 100' down the road I stopped to clean out the mud from my sock which was messing with my big toe. Oh such stupid timing...
After that there was some nice downhill, then I ended up in a valley which was very warm and humid. This was probably as hot as I was all day, and it was at 9:30am.
On the climb out of the riverbed valley, it got cooler, but my hip was doing something funny, popping with each step that I walked (didn't have the issue running). I stopped to stretch a little, which didn't help, then found that I could adjust my gait slightly in order to avoid the popping. The popping didn't hurt but it also didn't seem like a good thing. The climb was nice, here's the view after crossing a gravel path that people were bicycling on (you can see them barely). It looked like a really nice place to ride. I do get jealous of California this time of year. 10:00am or so, 20 miles in.
I had a 10 minute stop at a NEW aid station, at 10:35-10:45 or so. At this point in addition to the eating and getting water (and watered down coke), I took my socks off, put some ointment and bandaids on my toes, which had been giving me problems (somewhat due to my mismanagement of them 4 weeks before at the NY marathon, another story which will not get documented). I also snugged my shoes slightly to try to keep some of the pressure off my toes (this ended up being an oops that I'm still paying for). Anyway 10-15 minutes after that aid station is this picture, mountains pretty. I like them. I start to climb them.
I go up what I thought was a really big hill (Strava tells me it was about 750'. OK not that big). At the top is this left turn. The one they mentioned at the start. It's a little tempting to just miss the turn and do a 50k. 11:15am, about 26 miles. I take the turn.
Side note: the course was very well marked, especially compared to the races in NJ I've done, but this is sort of the exception. They really should have a sign that says "50 mile runners: if you're not at mile 40 or so, turn around and make the turn!" Maybe missing turns and getting lost is a rite of passage for trail runners...
The climb continues! You can see the trail below... wait, shit, you can't. OK how about I "ENHANCE":
That's a person, I'm 79.3% sure. It could be Steve! I could easily check that in the days of Strava and GPS data but it's better not to know.
More climbing. 45 minutes and 2.5 miles later, nearing the top. This will be fun to go back down (we go out 7 miles or so and back another 7 miles to an aid station).
After that climb, there's still hills, some up, some down. I liked it better when the aid stations were closer together. You occasionally pass groups of tourists, which always feels odd, such differences in current experiences.
Still headed to the aid station, there's a view to the Northeast of some lake. I ponder whether it is artificial. 12:40pm, 31 miles, about to descend to the aid station.
Crow (or as I'm told, Raven), seen from the descent to the aid station.
Soon after, I arrive at the 33-ish mile aid station, and put on the best thing ever -- fresh socks. Long overdue. I try to eat some but it's getting more difficult. Sitting is nice. I arrive at around 12:50pm, leave around 1:05pm.
Out and back not so interesting, same thing in reverse. I see Edward before the big descent. Take a video of him running the other way. Share some ginger candy. He says Steve should be not too far behind him. We go our separate ways.
Take this video of running at the start of the big descent -- "Coming down the mountain" (around mile 38, 2:05pm)
I didn't mention it until now, but this whole race I've had songs from The Verve's "A Storm in Heaven" in my head. Butterfly, "The Sun, The Sun", Star Sail. I wondered if "The Sun, The Sea" is a reference to l'etranger. I'm not listening to anything but damn those songs just burn a hole in my ears. Maybe I get sick of them, or just my general starting-to-feel-awfulness projects to them (I still love that album and have happily listened to it since!).
I don't see Steve on the descent. I start to guess he missed the turn. D'oh.
The section of the climb that took 50 minutes to go up takes about 30 minutes to go down. Fun. My weak left calf starts feeling not great with every left step. Still fun though.
After that descent, some new territory. 2:30pm, around 39 miles. Eating ginger candies. So far between aid stations.
Nice trails though.
Ah another canyon, 3:15pm.
I think this was soon after the last one. The photographer was like "you're almost to the last aid station!" But those 3 or so miles took FOREVER. Boring flat jeep trail.
Get to the aid station, eat some stale Chipotle chips (they had water and gels and offered to make some soup but eh). Did some more toe management. This is the part of the race where I usually end up complaining and then after the fact regret the complaining. But anyway only like 4 miles to go, just one small climb and descent then it's done.
That climb went on way too long. The small climb is still 1000'. I talked to another person who was also complaining, though his excuse was that since September he had only run two 7 mile runs. pfft! and then he proceeded to go ahead and beat me by a solid 5-10 minutes. Ah, youth.
The climb kept going. More complaining.
Looking back.
My goal was to finish. Bonus to not finish in the dark. 4:30pm.
Damn, magic hour, 4:38pm. After taking this I enjoyed the descent, passed various hikers taking sunset pictures, we all agreed it was beautiful. Finished at something like 4:52pm. Took a few minutes before I could eat anything, had some quesadillas, chili, couldn't really stomach much. It was getting cold, so I took off. Saw in my text messages that Steve did in fact miss the turn (bummer).
Drove back to LA. Got back to the airbnb, ate some snacks, realized I didn't have enough of them, oops, took a shower, got chills, got in bed, felt really good under the covers. Whenever I'd get up to pee, massive shiver shiver chills.
7am Sunday, return to Tacos Delta. Glorious breakfast burrito made me whole. A few hours later, beer with salt and kebabs at Edward's. That was also amazing.
Thus concludes my story.
1 Comment
I wrote and recorded (though not always in that order) a couple dozen tracks over the last year, and decided it was time to put many of them into an album.
It's now available on my archive, Spotify, Apple Music, Amazon, Tidal, etc.
I look forward to continuing this journey, though I'm running out of old artwork to reuse for album covers.
The sensation of paddling across the river on a warm October night,
lit by the lights of the city reflected back from the clouds, Jupiter
(or was it Saturn?) poking through, hypnotized by the smooth but
significant swells of the rising tide that (counterintuitively) tries
to send us to the harbor and out to the sea, the rhythms of the
neighboring boats paddling, rising and falling, things that probably
could be captured with technology but instead will be stored in wet
memory, dreamed about on the cold days to follow.
* 1 (beyond our SVN commits and all the way back to our VSS commits, all of which have thankfully been imported into git)
* 2 (and it will be fixed in REAPER 6.26, we're calling the non-fixed mode "Broken Capacitor" because that felt about right)
* 3 (or if you're clever and care about speed, log2(x)*ln(2) because ln(X) = logX(X)/logX(e) and logX(X)=1, but now my head hurts from talking about logarithms)
* 4 I haven't fully tested but I think it was working correctly on Jesusonic/linux, and when porting the EEL2 code to MSVC I didn't correctly convert it.
3 Comments
This is my first pedalboard. Andy was very very kind to give me The Wave and the Big Muff Pi and Pog, and I always coveted his Sunset. And I also copied his Iridium since it seemed appropriate. Anyway, so much fun. Good for recording and NINJAMming.
I also posted a song (second opinion) below... the drums I recorded when I stopped to check in on my studio, the rest from home. The words were a poem written by my grandfather (in the 90s, I imagine, given some of the references). My family edited and (self)published some of his works on Amazon.
Life keeps going on. Today I was looking at the graphs and timelines of things and got really angry with our state-level leadership (federal is another level of anger and despair). Had Cuomo put PAUSE in to effect a week earlier, think how many lives would've been saved. 15,000 cases before doing anything is way, way too many. California did their stay-at-home order with ~900. Bravo.
There's no use being angry, maybe, and I fully appreciate not having to be responsible for so many other peoples lives. I don't think a lot of politicians think this through -- the responsibility that comes with the power. Cuomo and Bill de Blasio clearly did not. There is no need for me to mention the other person who doesn't take the responsibility seriously. That's another league, and while some people say a malignant narcissist I prefer "bag of shit."
So now, I'm drinking a G+T made with the best grapefruit I can recall having had, making nothing of a perfectly lovely evening at home.
Recordings:
Not Vampires (NINJAM) - 1 - Face the Lies -- [6:58]
Not Vampires (NINJAM) - 2 -- [7:13]
Not Vampires (NINJAM) - 3 -- [5:53]
Not Vampires (NINJAM) - 4 - The Random Few -- [8:43]
Not Vampires (NINJAM) - 5 - Force Majeure -- [7:59]
Not Vampires (NINJAM) - 6 - Renormalize -- [15:17]
Not Vampires (NINJAM) - 7 - Major Reprise -- [4:50]
2 Comments
Yesterday [Saturday, 3 days ago] I did my first 50 mile ultra[marathon]. It was in California, near Malibu [Edit: The race is called the Sean O'Brien 50]. I woke up at 3:30am, left the house at 4:10, picked up @runviper [Edward] at 4:35, arrived at the start at about 5:15, before sunrise. It was cold, 40F [reminded me of home], and since the full supermoon was low on the horizon, dark.
You will see a lot of me making this face in this thread:
The start was supposed to be at 6:00 sharp, though I'm pretty sure it was 30 seconds late:
[That's the organizer with the megaphone, I believe. In the final race information email, there was a really thoughtful paragraph which stuck with me, I'll quote it here:
The first couple miles were crowded enough that I didn’t stop to take a picture. It went up a nice hill which made me feel powerful in my ability to climb it while running, then down the other side, through some more park, and then we arrived at a stream.
It was perhaps a small creek, but big enough that crossing it was tricky. There was a loose rope going across to help. A headlamp went flying and started floating down the water. I had a moment of heroism when I recovered it. I crossed with dry feet. Not bragging. After the creek crossing we started climbing again, and the sky started getting light.
and then the sun rose. Around this time I was able to feel my fingers again. I had thin cherry tree 10-miler branded gloves on but they could only do so much. This was almost an hour in, probably around 4 miles in, having climbed about 1500’
After we ascended another 10 minutes or so, the fog covering the Pacific came into view:
There was a photo-op moment going up over some rocks. Approaching it I figured that round thing would be a microwave dish or something but it was actually a light for a photographer.. I’ll see the results eventually I imagine. [edit: that photo wasn't great and too expensive to buy!]
[The] first aid station was about 7 miles in (hour and 40 minutes after the start). Mmm watermelon and oranges. Also potatoes and salt. Eating felt good. [Spent about 2.5 minutes here]
The next hour or so was mostly single track and had a good amount of variety. The charcoaled wood from the fires of last year offered a contrasting element to the blissful joy of the run.
At about 9am (3 hours elapsed, about 13mi, 3200’ ascent) after crossing above a tunnel, we arrived to the second aid station, which had expanded offerings from the first. Sandwiches! PB&J awesome! In hindsight I should’ve had some candy. Regretting not having candy. Getting warm.
There were drop bags at that aid station... dumped my wool shirt, headlamp, picked up sunblock. [spent about 7 minutes here] Soon enough it got very bright, and less photogenic. (note re: video — Spaceballs reference, had plenty of water):
After another hour or so (10:15am?) we crossed over a pass and could see the marine layer again. ~17 miles and 4300’ climbing cumulative...
10 minutes downhill and we arrived at an aid station. Lemonade, fruit, sandwiches, potatoes, consumed. @runviper made a taco, I questioned his judgment for eating beans, then proceeded to join him. No regrets [on the beans] (for me at least) [regrets on not eating candy]. [spent about 5 minutes here]
At this aid station they explained we were 19 miles in, we just had to do 3 miles down to the next aid station, then 8 more miles back up another trail, then the 19 miles back to the start. Legs felt pretty good... time to descend. Oof.
3 miles, 1500’ of descent, and maybe 30 minutes later, the cracks started to show. That tight IT band thing you feel sometimes? hello
eat eat eat [spent about 7 minutes] then back up the hill with full water, going back to where we were, in 8 miles instead of 3. Hey why is it so steep?
After having climbed 1800’ for an hour, you suddenly realize you’re on top of the wrong mountain [edit: but still on the course -- it is a torturous course], and the aid station is a tiny speck on the horizon. There is a gorge separating you from it.
The aforementioned IT/knee thing made the 800’ descent difficult, especially the steeper parts. So I was actually happy to be climbing again, which was good because there was 1000’ to go for the aid station
These 8 miles were brutal. The sun was strong, it was hot, and seeing the expanse between you and where you need to be was intimidating. And knowing once you get to the aid station, you still have 19 miles to go (which are largely downhill, ugh) After having gotten to the aid station, food [nutella (gnutella) sandwiches, mmm. apparently they had run out of water too, but had since gotten more], ice in the face, etc [spending about 8 minutes], we continue on. There’s a small descent, a few hundred feet later I decide I must stop and get a rock out of my shoe. We are 31 miles in, 7300’ of ascent, it’s 1:40pm, there have been rocks in my shoes all day. I probably also tried to stretch my IT. anyway we climb 600’ to go back over the pass, and look back at the ocean:
Now it’s just a short 6 miles to the bag-drop aid station. At some point around here I started using anti-chafe stuff everywhere i felt twinges. Seemed to work but could’ve been placebo. I was wincing on all of the steeper descent bits, not taking too many photos
Get to the mile 37 aid station, change shirts back to wool, grab headlamp. Eat a little but damn at this point I’m sick of food. [Should've started eating candy. changed socks, win. Drank cold brew coffee from drop bag. Both win. Also did some stretching of the IT. total time here was 13 minutes]
And another 6 miles of mid-afternoon. With 2000’ of ascent (not too gradual, plenty of my new favorite thing at this point: descent)
We get to the final aid stop at around 5pm (that 6 miles took a while!), just 7 miles to go! Stretch again here [spent about 8 minutes here -- total aid station time was about 50 minutes]
After this aid station it really got to be the magic hour:
and the fog and mist:
For the first half (and after my ankle rollover especially) I just hung out with the majority of the runners I was near, running 9s as planned. I didn't see too much passing, but maybe it was subtle? The first half went in just about 2 hours, and a bit after I stopped to stretch a little, massage my right calf (which had been getting tight on longer runs causing tendonitis in my ankle, which is why I hadn't done any long runs in ages), and my left ankle seemed to be fine, so I kept on. Around mile 20 I realized that a) I was going to finish, and b) I was actually feeling pretty good considering (my HR had been 130-140 or so the whole time), so I decided I'd run some 8s when the crowded course allowed and get some of those newfangled negative splits, which was successful.
Other notes:
Video from my sunglasses:
(youtube link)
1 Comment