Archive: November, 2020

Pandemic waiting when you're running out of time

posted by Jeff | Monday, November 30, 2020, 9:15 PM | comments: 0

There was an article in The New York Times today about how there's finally a lot of reason for optimism about the pandemic, provided you're willing to deal with a whole lot of death and packed hospitals in the near term. You know, because even the good news is bad in 2020.

It got me to thinking, what really causes me anxiety about the situation? I have a great job in a growing company, so I'm thankfully and gratefully relaxed in that sense. I'm frustrated that the amount of death is unnecessary, and frankly discouraged that the relatively well-understood math and science is still rejected by some people, which means even with vaccines it will take longer to get beyond the pandemic. But even that, I can largely let go of because there's so little that I can do about it. The thing that's really difficult for me, at the end of the day, is the waiting when I feel like I'm running out of time.

As I slide into midlife, I have all the things that usually come with it: Am I making the most of life? Am I happy? Am I going to leave the world better than I found it? What should I be doing to increase the odds that I'll live a little longer? Am I screwing up my kid? At this point in your life, you've spent a lot of time making mistakes, learning and figuring out how to navigate the planet. You hopefully start to develop some confidence that, believe it or not, you're battle-tested enough that you can move forward with more wins than losses. There's some urgency associated with this, for sure, because as I said before, you're now half-way between wearing diapers and wearing diapers again.

What's the enemy of urgency? Having to wait. The pandemic requires us to wait for a lot of things. Look, I'm not talking about this stupid YOLO thing where people insist you've just gotta "live your life anyway," or the BDE that dudes have proving how fearless they are against the virus. I haven't stopped living, nor am I living in fear, but I accept that it's just going to be awhile before I can go back to licking subway handles or jumping in a mosh pit. For us, it also means we're not traveling, at a time when we most desperately want to see more of the world. It means not having or going to epic parties to celebrate our friendships and relationships. It means I won't see the view from the company office up in One World Trade Center any time soon. It's not even a good idea to go hang out at my in-laws neighborhood pool near the gulf coast, for the sake of their health and our own. We just have to wait.

It all makes me wonder what will happen when, maybe in the summer, as we emerge from this fog, what people will do. People always declare changes and aspirations at the new year or their birthday, and never follow through since there's another one a year away. But what happens when you've been somewhat limited in what you can do for a year? Will people in general have a sense of urgency when they've had to wait? I imagine for a great many people, things are already urgent when unemployment is huge and the service industry is in shambles (our community in Central Florida is certainly feeling that). It seems critically important to help in any way we can.

I feel like I'm in a hurry and have to wait.


Without 89X, FM radio is REALLY dead

posted by Jeff | Saturday, November 28, 2020, 4:40 PM | comments: 0

Right at the end of my freshman year in college, May, 1992, the big Cleveland top 40 radio station flipped formats to "modern rock." It was called 107.9, The End, because it was at the end of the radio dial, when some radios still had dials. That first year of school was musically weird, because while I already was in to some of the "new wave" and "weird" stuff out there, like Jesus Jones, anything on the Pump Up The Volume soundtrack, and bigger acts like U2 that were strangely not getting airplay, we were also seeing the last popular wave of music from bands like Def Leppard, Poison and Motley Crue. It was the year when Nirvana's Nevermind and Pearl Jam's Ten came out. INXS put out the brilliant Welcome To Wherever You Are, and R.E.M. released Out of Time.

Impressionable almost-19-year-old me who wanted to work in radio was absolutely electrified with this new radio format. It seemed like a transition to something that combined the best of the 80's music with obscure bands that never quite got their chance. It embraced the Seattle sound, while it wasn't afraid to play female-led bands and singers. It was the radio format that popularized The Cranberries, The Breeders, No Doubt, and yes, even Sarah McLachlan. Think about that for a minute... the same radio station played Sarah and Nine Inch Nails. It was glorious, and it was glorious because like those of us who identified proudly as Generation X, it did not want to be defined. (Yes, of course I see the irony in identifying with something not wanting to be labeled... that's the paradox of my people.)

I couldn't get The End very well at Ashland University, about an hour south from the outskirts of Cleveland. I also didn't make a lot of headway getting alt rock on our college station, which followed a classic rock format, mostly. It was cosmically stupid that we had a format at all, but by my junior year, with me as the creative director and a friend as music director, we started going where the rock music was, which was a lot of grunge at the time. Our college station's frequency was 88.9, and with 3,000 watts, adequately covered neighboring Mansfield. But when the transmitter was off, we could hear something amazing at 88.7: a station from Detroit called 89X.

89X was actually out of Windsor, Ontario, south of Detroit (that sounds weird, Canada being south, but for real, look at a map). "CIMX Windsor-Detroit is 89X!" I don't know if it's because they were Canadian or what, but they gave few fucks about the conventions of radio formats in North America. While The End seemed to combine these weird unrelated sub-genres of music into something of a wonderful mix tape, 89X just let it rip and would abruptly play Sarah McLachlan right after Nine Inch Nails. And with Canadian content rules applying, you'd not only hear a lot of Sarah, but also great bands like The Tragically Hip and a fair amount of Barenaked Ladies, before they really caught on. I loved it, and when I was home the summer after my junior year, I put an antenna on my parents' roof so I could easily hear it from the Cleveland south suburbs. It would be the station of choice for years when visiting Cedar Point, too.

My academic advisor and chief engineer for the radio/TV department once showed me a little device he wired up to hear 89X while our college station was on the air. He would point his high gain antenna at Detroit, and then with this thing that had an alligator clip and a wire, he would essentially use phase cancellation, the same phenomenon used in noise-cancelling headphones, to block the college station and let 89X in. He also had to rewire his receiver to include a more narrow frequency filter (most allow +/- .4 MHz, because normally stations don't geographically overlap much). This way, he could isolate 88.7 from 88.9, which was amazing considering on-campus the station bled into the phones!

I listened to 89X when I was in Sandusky, Ohio, back in January, for a conference. It was still pretty weird, but seemed to lean more on older stuff. Any station that goes nearly 30 years without changing much is pretty crazy. They oscillated a bit between "old" alternative and newer stuff over the years, but it was always a delightfully strange mix. When I had my last shift on a commercial radio station in 1996, I had largely accepted that it was a terrible business getting worse because of the rapid consolidation occurring in light of the deregulation that lifted ownership limits. Everything was becoming automated, and programmed by some dicks in New York or LA with no regard to the local scene. I'm sure it helped that 89X was Canadian, but what a comfort that it was still out there.

Now, it's not. A little over a week ago, after 30 years, it flipped to another f'ing country station. Terrestrial FM radio is crap, and it has been for a long time, but it felt good knowing that 89X was still out there. These days, I still listen to a combination of AltNation and Lithium on SiriusXM, and between those two stations, offer a good, curated mix of music spanning the decades. Satellite radio is clearly making a transition to streaming, and I hope that it survives. They have a great thing going when they're not stuck having to survive on advertising and can make these genre stations. It's a great way to discover stuff, and humans still do it way better than algorithms.

Interestingly, The End came back as a streaming station, and they do a pretty solid job of it. It leans a little heavy on nostalgia for me, but it's solid.


We have to stop devaluing experience, expertise and success

posted by Jeff | Monday, November 23, 2020, 10:33 PM | comments: 0

If there's a broader theme to Trumpism, I mean, beyond the general tenets of fascism, it's the extraordinary push to discredit and distrust experience and expertise. Historians and anthropologists are already writing about this, and we've seen it continuously throughout the pandemic. The left is not without sin either, as it has been on a campaign to scapegoat the successful and rich people. Collectively, we've broken our value system and replaced it with narcissism and arrogance that suggests we all have all the answers.

We should stop doing this.

Two things today really triggered me over this. The first was that a 16-year-old girl has 100 million followers on TikTok, apparently for... dancing. (Seriously, I could point you to a dozen Broadway dancers who dance for 90 minutes, 8 times a week, and that seems like a serious achievement.) She's made $4 million in one year from endorsements for doing something that doesn't appear to stand out in any meaningful way. I'm not hating the player, because good on her for figuring out how to profit from this strange world, I'm hating the game. This is what the world rewards now: a person who posts 10-second videos dancing to random music.

Then I made a joke about how, now that Covid is getting pretty bad again, we would likely see hydroxychloroquine in the news again. Sadly, a friend pointed out that it already happened last week. It was an actual Senate hearing called by a politician that doesn't care if drug trials, the medical community at large, the FDA, the top doctors and scientists in government, all determined months ago that this is not a thing. We're talking about a senator who graduated from college in 1977 with a BS in business and accounting, who ran a plastics company, questioning the an entire community of professionals who all spent twice as much time in school and actively pursue science every single day.

These are two angles on the same problem: Our society has devalued experience, expertise and success, believing that anyone can be an expert in anything, and we keep the bar so low that you don't need to do anything truly remarkable to be celebrated. The latter part shouldn't be that surprising, since we did in fact elect a reality TV host to be president.

Experience is something that comes from doing things, even if it's doing them wrong. My experience is valuable not just for the wins, but the losses from which I learned how not to lose. Not all experience is created equal, certainly. I've worked with people a year out of school who very naturally absorb and use experience to build impressive skills, as well as PhD's who've worked for 20 years and are less effective (certainly the opposite is also true). Regardless, experience matters when it comes to trust and evaluating what a person is capable of doing.

Expertise is the acquisition of deep knowledge of a particular field. This isn't just doctors, who we trust to cut us open and fix our innards, or engineers who will build bridges that don't fail. We trust carpenters, electricians and other tradespeople to do work that requires deeper knowledge than what we have. Whether the expertise comes from years of school or mentoring from others, expertise matters since we can't have deep knowledge of everything.

Success is having a track record of positive outcomes. I don't care if it's winning a Lego building competition or retiring from Microsoft as the world's richest person, we shouldn't be suspect of people who achieve success. Sure, sometimes success is achieved by immoral means, but why do we now treat every successful person, especially those who are financially successful, like they're right out of The Wolf of Wall Street? I know a lot of people who have worked very hard, some of them making millions, and they're the kindest, most generous people I know. They earned their success, and will leave the world better than they found it. They're not the villains in your story. (There's another don't-hate-the-player thing here, but that's a pretty big aside for another post.)

We all have our share of problems, some of them serious, some of them not so much. The world has infinitely more problems, and we hope that some combination of people can help solve them. It has been my experience that surrounding myself with people who have greater expertise than myself for the problems I need to help solve result in greater success every time. Honestly, that's the entire theme around my leadership philosophy. If someone is going to trust me to be in charge of something, that's the way I roll. Don't take my word for it... I gleaned this from watching successful people.

We have to stop this nonsense where we arrogantly second guess people with experience, expertise and success, for no other reason that we have a feeling or opinion about something. Stop it. Your feelings and opinions do not have the same weight as others. And by the way, this isn't just true when it comes to doctors, scientists and engineers. There are even politicians who have experience, expertise and success in governing that is valuable and worth our respect (though definitely not the guy who thinks he knows better than doctors). We trust a wide range of people with our safety and prosperity every day, whether it's the butcher to handle meat safely, or the paramedic to help us when our life is at risk, or the mechanic inspecting a roller coaster. It doesn't make sense to elect people to office who lack experience, expertise and success, and especially those that don't respect any of those attributes.

You aren't weak for what you don't know or understand, you're self-aware. Anything else is not a good look on you.


Rights are not inseparable from responsibility

posted by Jeff | Friday, November 20, 2020, 10:50 PM | comments: 0

If I can draw a consistent theme from people across the vast political spectrum, it's that people often talk about rights with complete disregard to the responsibility that comes with rights.

Participating in any society comes with certain social contracts, whether they're explicit or implied. We work a job with the expectation that we're compensated for it. We follow laws and we don't have to go to jail. We hold doors for old ladies because not doing so would just make you the worst kind of asshole. Most functional adults even understand that expressing an opinion will have consequences. For every right, there's a responsibility.

People who are progressively motivated in politics believe that the system of higher education is broken, because of the costs and debt associated with higher ed. I think the costs are certainly worthy of discussion, as well as the role higher ed plays in the development and training of young people as they transition into adulthood. But at the same time, I'm not sure why people should get a pass for borrowing money they don't have a plan to repay. A lot of that is a change in expectations, because 25 years ago, people were not borrowing for tuition and living expenses, and they weren't spending extra years in grad school because they felt it was necessary. Keep in mind, I'm the first to say that universal health care and/or a single-payer system makes infinitely more sense than what we have today, but when education is available equally among people (it's not yet), we still have a responsibility if we choose to borrow money.

At the other end of the spectrum, in the midst of a pandemic, we've observed that "conservative" leaning people find that mask wearing and participating in the mitigation of disease transmission is a violation of rights of some kind. Worse, some consider mask wearing to be "virtue signaling," which seems cosmically stupid to me, but let's overlook that for a moment. The larger problem is that the science on mitigating the pandemic is relatively understood at this point, and while vaccines will become more common over the next six months, we're a long way from "normal." Participating in a society where the death toll does not keep mounting requires something of everyone, and that shouldn't be controversial. Yes, you do have rights to move about freely to do your thing, but we are all our brother's keeper. (And yes, I understand the Bible first mentions this in the Cain and Abel story, but looking out for others is a recurring theme in the Bible.) We have a moral obligation to our communities, even when we assert our rights.

I strongly believe that this is an important aspect of our existence as individuals. There are absolutely things we are entitled to morally, but we do not exist in a vacuum. Everything we do has consequences, and so, there are responsibilities that go along with our rights. We would all be better off if we kept that in mind when conducting ourselves.


Creative gyration

posted by Jeff | Thursday, November 19, 2020, 11:10 PM | comments: 0

If I can say anything positive about this year, it's that I've at least partially reclaimed the creative spirit that has been in decline for a long time. When I tally it all up at the end of the year, I fully expect to catalog a ton of stuff that I made. Lots of software, video, radio shows... I'm honestly surprised myself.

I've also been somewhat critical of myself for skipping around between these things, often not finishing things or not doing them consistently. I don't know why I'm treating that as a flaw, exactly. The cultural expectations around follow-through and consistency can be kind of toxic even for important things, so applying them to leisure time activities seems like a bad idea.

Late in the summer I got into this idea around making video content about stuff we care about, and that's still on the table and half-realized. It's just not published. I'll come back to that, probably soon. I can probably put together a dozen of those in pretty short order. I cranked out 21 episodes of my radio show, Modern Gen-X, then kind of abruptly stopped. I reserve the right to suddenly do that again, too. I cranked out my MLocker open source software project, a personal music cloud player, mostly across four weekends, and I'm really proud of that. In fact, since I started, my total play count is at about 2,000 already! From August to October, I committed to writing on average a blog post a day, and while I missed the first month (only 28), I got there the next two. This month, probably not.

What does this mean for me? I think I'm generally happier and less stressed overall, or at least, better off than I would be considering the year we're having. The hardest part about it is that I feel like I'm being a little selfish, because these are largely solo activities. I have found ways to get Simon involved to a degree though. He did the ID stabs for the radio show ("Trickle-down economics... how did that work out for you? The Modern Gen-X!"), and he'll show that anyone can flip a bottle of liquor to pour two ounces in a video. Yeah, definitely parenting wins.

All of this to say, sometimes suboptimal circumstances force you to get creative, quite literally in this case. I haven't left the state since January, and haven't left the country since late last year, but dammit, I made stuff.


Blazor discovery part 2: WASM and glorious components

posted by Jeff | Wednesday, November 18, 2020, 10:48 PM | comments: 0

(If you missed part 1 of my Blazor exploration, check it out.)

One of the more useful paradigms that came along with modern front-end frameworks is the use of components. The idea is that you can create these little islands of functionality that can be reused, tested in isolation, and even shipped in libraries. I used to naively think that this was overkill and unnecessary beyond plain vanilla form controls that have been around for centuries, but the ability to move data around between them and build compound thingies is of course indistinguishable from magic. Each of the big three Javascript frameworks, in my opinion, had a better approach than the previous one (Angular, React, then Vue). I thought Vue in particular was the least clumsy and I've enjoyed messing with it. My hang up is still the crazy chain of npm dependencies and the fact that the tooling is still hard to get just right quickly without a lot of experience. I think Blazor improves on this in every way. It felt completely natural to try it out for MLocker, my personal cloud music locker app.

Web assembly (WASM) is shockingly fast in all of the browsers already, and the binaries for the app are pretty tiny. The somewhat valid criticism of Blazor is that there's an initial bandwidth cost to download the .NET bits one time. MLocker requires about 4.5MB compressed of stuff the first time down, which is expensive-ish compared to a React app that has been properly webpacked. However, I compare that to the average news or content site, where it pulls more than that on every page (because of ads and trackers), and it seems like less of a big deal. In fact, the trade-off I've made is that I cache as much as possible on the client, because your library and playlists don't change all that often. For my library of almost 8,000 songs, the start up cost for MLocker is about 11k. Yeah, 11,000 bytes. If I version up, the framework bits are still cached, and the new binary is around 150k.

Where I have not yet gone is the full progressive web app route. I've gone as far as making it "installable," and it works great on Windows and Android, but it does still require connectivity. Again, if the pull is 11kb on average to start up, that's not a big deal, but I've not yet enabled full-on airplane mode yet. As it turns out, that's a lot trickier, and the boilerplate code shipping with Blazor only covers the simplest of use cases.

Back to components... Blazor by convention uses the file name of a component, like Widget.razor, to identify an instance of the component in markup. So in this case, <Widget /> would predictably create an instance of the component in the file of the same name. You can nest these to your heart's content, but the trick is to of course move data and events through these components, and there are a number of ways to do that. I've done this three different ways in MLocker: Cascading values, parameters and different flavors of shared state.

Cascading values are the most weird of the three ways, and the first thing I tried. The playlists, albums and artists all use these when persisting values from the parent to the child, and I suspect that won't last after some refactoring. For example, you'll find this nugget in the Album component:

<CascadingValue Value="_currentAlbum">
   <Albums_Detail/>
</CascadingValue>

Weird, right? The detail component then has a property like so:

[CascadingParameter]
protected Album Album { get; set; }

The idea here is that children further down the stack can all have access to this object, but that seems cosmically weird that you would ever want to do that, trusting that something down the tree has a value there set by an ancestor. Like I said, this will not likely last in the code base, because a straight-up parameter makes more sense. Let me get into this deeper and combine with the third thing where we move data and state around through a class added via dependency injection.

Playlists and albums can both be added to the songs queued in the player, and the easiest way to do that is via a shared component. To do this, I have a component called AddListToQueueButton, which is added to other components via the simple markup:

<AddListToQueueButton SongList="_songList" />

You'll notice that this takes a parameter called SongList, which in HTML we call an attribute. Albums and playlists keep a List<Song> object on hand, and since that's the data we need to add songs to the queue, it's what we want to pass to this button component. The component is pretty simple, so here's the whole thing:

@using MLocker.Core.Models
@using MLocker.WebApp.Services
@inject IPlayerService PlayerService

<span class="@_queueButtonClass" @onclick="EnqueueList" title="Add to queue"></span>

@code {
	[Parameter]
	public List<Song> SongList { get; set; }

	private string _queueButtonClass;

	protected override void OnParametersSet()
	{
		_queueButtonClass = "addToQueueButton";
	}

	private void EnqueueList()
	{
		_queueButtonClass = "doneAddToQueueButton";
		foreach (var song in SongList)
			PlayerService.EnqueueSong(song);
	}
}

Let's start with the [Parameter] attribute, which maps to the value we passed into the markup above. Like I said, this is way more deliberate and obvious to me than cascading parameters. So now we have this tiny component with a button, which is to say there's a <span> with a click handler wired up. We have all the songs involved, too, so now we need to get those to the player I wrote about in part 1.

I'm not going to go deep into dependency injection here, but it works the same as it does in the server-side bits. The Blazor docs explain this pretty well. By adding @inject IPlayerService PlayerService to the top of the component, we now have access to the same singleton instance that the rest of the app has. When the user clicks the button, it fires EnqueueList(), which feeds the songs from the parameter to the service and those will play after the existing queue is exhausted.

Binding data is well documented, so I won't do that here either, but it's important to call out that Blazor can do one or two-way data binding. For the unfamiliar, one-way means that some source of truth can change the view of that data, while two-way means that changing the view of the data can change the source of truth. It has been debated to death about why two-way data binding is bad, usually pointing to performance issues, since you could by way of changing text in a box cascade a bunch of events responding to the change, or that it's simply harder to debug and maintain. I don't think it's necessary to be dogmatic about it, as long as you understand the implications of what you're doing, and the person who sees your code next can also understand.

There are some obvious cases for component reuse in MLocker, starting with the song lists. They appear on the part of playlists, artists and albums, and they all use the same code. Using simple boolean parameters, I can turn on the display of track numbers for albums, but not for playlists. The song lists themselves render thousands of row components, and these communicate state to a separate context menu component via a series of properties in a dumb state box of static members.

There is some other magic available for components, like CSS that rides along side of the components. That's probably more of interest to people building component libraries, but it's a nice touch. You can build templated components, which is like a throwback to the ASP.NET Webforms repeaters, in a good way. The best magic of all though is the Virtualize element, which is like a foreach loop, only the stuff not on screen is not rendered. Like I said, I have almost 8,000 songs in my library, and that list scrolls, even on my phone, like it's native, especially after all of the album art is cached. It's really fantastic.


Blazor discovery part 1: You can't entirely escape Javascript

posted by Jeff | Monday, November 16, 2020, 11:44 PM | comments: 0

Way back in July, I thought I was mostly joking to myself when I said, "I should build my own cloud music locker service!" But the dire warnings from Google about the forthcoming end of Google Music were alarming, and doubly so when I saw that migrating my stuff to YouTube Music led to a pretty horrible experience with videos and ads, just to listen to the music I already owned. A few weeks later, I messed around to see how hard it was to extract the metadata of MP3's with various .NET libraries, and of course that was easy enough. A month and a half passed, when something convinced me I should look harder at Blazor as a viable alternative to Vue.js or something else as a front-end. A few weekends later, I have something totally usable, on my phone as a progressive web app, and I use it every single day.

I put the project on GitHub, because I felt like someone else might get some use out of this, even if was just experimentation. I called it "MLocker," as in "music locker," the term used to describe services where you upload your tunes and listen to them anywhere. By early October, I was able to prove out that I could extract song data and persist it, and save the file in Azure storage, so on October 11, I went into extreme prototyping mode to see if I could actually play back some music in the browser. I had never touched an HTML audio tag in my life, so it was new territory. I made some totally amazing discoveries at this point, among them the fact that API's in .NET already supported byte ranges and HTTP 206 responses, so the audio tag in every modern browser already knew how to quasi-stream by chunking up a song and not getting the whole thing up front. Neat!

Before I get to the meat of this post, the high level architecture is that there's an API that acts as the plumbing between the front-end Blazor WASM app, a database and Azure blob storage. Blazor for the server seems like a terrible idea for anything beyond pre-rendering, so these posts are just about WASM. For simplicity, I have the API project serving up the Blazor front-end, but you could serve it from literally any static location, if that's your thing. Please don't consider anything here as a "best practice." This discovery process has been fun, and this stuff is way easier than I expected, but the result thus far is not necessarily well-factored or battle tested.

I learned that I would have to get to know Javascript interop a bit, because the audio object has some events not surfaced via Blazor, and controlling it would also require mostly Javascript. In this post, I'll go into how I arrived at the place I am for the player component.

While I've never gone hardcore into any of the modern front-end frameworks (because enormous npm dependency trees give me anxiety), I have gone deep enough into Vue.js and been around React enough to understand the rich component model and the use of shared state machines. Blazor works in largely the same way, only with C#. You can break down these bits of user interface into reusable parts and hook them up to code that they use to respond to events or source data. The player for an app like this gets hit from a lot of different angles. Fortunately, there's only ever one instance of it, so after some iteration, I decided to break it up like this (links go to the source code):

  • Player.razor: This is the component with the HTML markup and code to tie it to a service.
  • PlayerService: This is where the real playback logic happens. It's a C# class that let's callers know what song is playing, where in the queue the player is, etc.
  • m.js: This is the fairly simple library of Javascript functions to support the things that Blazor can't do directly.

The markup in Player.razor is really simple, with a few lines to display the current song, and some span's that act as buttons. C# code in this file responds to button clicks and manipulates CSS classes on those elements. For example, the play/pause button calls a simple method:

@inject IPlayerService PlayerService
...
<span class="@_playClass playerButton" @onclick="PlayPause"></span>
...
@code{
	string _playClass;
	private async Task PlayPause()
	{
		var isPlaying = await PlayerService.TogglePlayer();
		UpdatePlayerButton(isPlaying);
	}
	private void UpdatePlayerButton(bool isPlaying)
	{
		_playClass = isPlaying ? "pauseButton" : "activePlayButton";
		StateHasChanged();
	}
}

Calling the PlayerService.TogglePlayer(), it returns a boolean letting you know if you're playing or paused, and the second method sets that class on the button, which has either a play or pause icon. Easy right? The service in this case isn't doing anything exotic at all, and in fact it's just a pass-through to the Javascript that will do the actual interaction with the audio tag. This works because the PlayerService uses dependency injection to resolve an instance of IJSRuntime, which Blazor automatically wires up for you.

    public async Task TogglePlayer()
    {
        var isPlaying = await _jsRuntime.InvokeAsync<bool>("TogglePlayer");
        return isPlaying;
    }

Moving down the stack, we can see a straight forward call here that finds the audio element, checks its play status, then either plays or pauses it, sending the new state back up the chain.

window.TogglePlayer = () => {
    var player = document.getElementById('player');
    if (player.paused) {
        player.play();
        return true;
    } else {
        player.pause();
        return false;
    }
}

In the event that you have Javascript returning promises, make sure that your chain is always returning (I learned this the hard way). Blazor will unwrap the promise and give you a result. 

There are certainly times though that you need to go in the opposite direction. For example, Android and Windows fully support the MediaSession API, which is the thing that shows you playback controls and album covers on your lock screen (Android) or next to the volume as it appears on the desktop (Windows). So if someone pushes the play/pause button, I want to respond to that. In Javascript, I have to wire up an event handler and then call the interop library that Blazor loads:

navigator.mediaSession.setActionHandler('play', () => {
	player.play();
	DotNet.invokeMethodAsync('MLocker.WebApp', 'IsPlaying', true);
});
navigator.mediaSession.setActionHandler('pause', () => {
	player.pause();
	DotNet.invokeMethodAsync('MLocker.WebApp', 'IsPlaying', false);
});

These calls take two or more parameters: The compiled assembly name of your app, a static method being called, and then any parameters to pass in. As far as I can tell, the static methods can be in any class or component, but in my case I've got it in the Player.razor component. The trick here is that you need to wire up the static method to a static event, which has handlers attached to it from the instance of the component. Let's walk through that. The player component has the static method, with the JSInvokable attribute (important!), and all it does is call the static action.

private static Action<bool> _isPlayingAction;
[JSInvokable]
public static void IsPlaying(bool isPlaying)
{
	_isPlayingAction.Invoke(isPlaying);
}

Right now nothing will happen, because we haven't added any instance methods to the Action that should fire. We can set these up in the OnInitialized() or OnInitializedAsync() overridden methods in the component, as simply as this:

_isPlayingAction = UpdatePlayerButton;

Wait, UpdatePlayerButton, haven't we seen that? Yes. Yes we have. We used that above to change the CSS class on the button. The Javascript did the work of making the audio element play or pause, so we just needed to let Blazor know and change the look of the button. We already had some bits for that, so we're done.

There are a number of other events that are wired up from the Javascript calling into the Blazor bits, and you can check the source code for that. Specifically, we want to react when a song ends, so we can play the next one in the queue, and also react to the next/previous buttons from the MediaSession API.

This wasn't the only thing I needed to hook into JS interop for. I'm using context menus on songs, to add them to playlists, add to the queue, go to artist, etc., and I'm using the awesome Popper.js library for that. It allows you to attach a DOM element to another, while staying visible in the window. I'm not going to get deep into that implementation, but basically there's a click handler in the ListRow.razor component that passes the element ID of the button to a JS interop call that uses Popper.js to attach the context menu, already in the markup but hidden, to the context menu button. Sure, you could render the context menu for each song in the list, but that would mean thousands of them!

There's more interop to talk about, but it gets into the caching of the songs and the album covers using a service worker. I'll get into that in a later post. Next time, I want to talk about the navigation and the act of hiding and showing markup based on state.


Brain stuff and brain drugs make me uneasy

posted by Jeff | Monday, November 16, 2020, 9:34 PM | comments: 0

Anyone who knows me, or thinks they know me because of social media, probably knows that I talk pretty freely about mental health and seeing a therapist. It's just a matter-of-fact kind of thing that causes no shame and I feel like it needs to be more "out there" and accepted, because I don't think that it's materially different from talking about having a cold or needing a hip replacement.

I have to admit though that I'm uncomfortable still with the role of drugs in mental health, and I'm not sure why. When it became clear that my boy was dealing with ADHD and anxiety, I felt very strongly that those weren't things that you treated with a revolving door of drugs alone. And in fact, he sees a therapist weekly, which mercifully got cheaper now that she's independent. We're at the cycle again where we needed to try a different drug, and this one seems to work pretty well so far, for at least part of the day. It also seems to be responsible for a new verbal tick that is frequent enough that I can't block it out. As much as I hate the remote learning, I know how unkind other kids would be if they heard it, so finally something positive comes from the pandemic.

At the end of last year, my doctor prescribed just 15 doses of lorazepam for me, because I was having what he described as minor panic attacks. They were infrequent, maybe a month apart, and they happened not in moments of stress, but seemingly random times, and usually it included tightness in the chest, a change in breathing, dizziness... the kinds of things that happen when you're having a heart attack. I've resisted any kind of mental health drug for years for a lot of reasons, but he framed it the way I needed to hear it: "You want to be sure that's the stress talking, so take the drug and if you're still having those symptoms, you need to go to the hospital." Well, a week or two later, I had just such an episode, and sure enough, the symptoms went away within 30 minutes. The rest lasted through July, and I have a small supply on hand because they work.

Yesterday, I was feeling anxious about nothing in particular, except maybe the observation that the pandemic is getting worse and no one seems to care if they put others at risk. But I wasn't having the panic symptoms, so I worked very hard to bring my racing mind under control, without drug intervention. Let me first say that I got there, and I was pretty proud of that, but a day later I feel embarrassed that I resisted the pharmaceutical option. I still have hang-ups about the use of a drug to "fix" a suboptimal state of mind. My kid can't help it when he can't focus, and we can see tangible improvement with ADHD drugs. He's still himself. Why do I resist?

Of course, I have some idea. There's enough history of addiction in my family that I know some "medicate" with alcohol or heroin. That's not the same as being prescribed a controlled substance under doctor supervision, but sometimes my brain doesn't differentiate between those scenarios. There's also a fair amount of depression in my family, and seeing that, I wish more of those folks were medicating, because they seemed needlessly miserable.

All of this to say that I have hang-ups, and I need to figure those out. I have to be self-aware about depression as I get older, because while I may not have the addiction gene, I worry about the potential for depression and the limits of therapy to combat it.


The promise of a new year of college

posted by Jeff | Sunday, November 15, 2020, 10:58 AM | comments: 0

I have a repertoire of recurring dreams, which is to say that they differ in the details, but have a consistent theme. One of these is the "moving into the dorm for a new year of college" dreams. These generally appeal to my anxiety... I'm always an RA, so I'm worried about who the problem residents are, whether or not the lock on my door is secure, when I'm on duty, how to get my class schedule, whether or not the Internet works (which wasn't even a thing when I was in school), etc.

Last night, I had the dream again, but it was curiously optimistic and translated into an adult setting with overlapping and illogical timelines. It started as many of these dreams do, with me trying to make-out with someone I just met. This actually occurred 50% of the time, so that part is realistic at least. Then I met up with a bunch of guys who were people I worked with at various jobs, including my current job, where I've not met anyone in real life, and I was coaching them for volleyball. The location was more the Microsoft campus than Ashland University. I walked into a group gathering that was residence life people having their first meeting, where I was supposed to be, at which time I had told Simon he had to go off on his own. Yeah, my kid was in it... told you the timelines didn't make sense.

What was different about the dream though is that, while it did connect back to a little anxiety, it was mostly tied to the feelings of new beginnings and possibilities. When I look back at school, honestly I enjoyed it half the time at best, but the start of a new year was ripe with potential. New people, new classes, a step closer to "the real world..." it felt like you could make it into whatever you wanted. It was a feeling of hope and excitement.

In adulthood, it seems like we rarely have those kinds of moments. The closest thing I can think of is when you move, and by move, I mean out-of-state. I definitely had those feelings moving to Seattle and Central Florida. Maybe having a child is like that, but you're so exhausted most of the time that you don't feel much else. A new job might be like that for some, but not for me. Not even getting married carries that excitement, since at that point, the biggest change is how you file your taxes.

The manifestation of this dream in this particular case brings some serious realizations. The first is that all of the situations in the dream I approached with experience and wisdom, neither of which you have when you go away to school in real life. I get caught up in the realization that midlife means you're about equidistant from wearing diapers to wearing diapers again, but while learning is a lifelong endeavor, we're definitely better equipped to handle life than we are two decades prior. The other big thing is that change does bring opportunity. Maybe it's the timing of the election, but with rampant and emboldened racism, failing government, a global pandemic, climate change, the bar for things getting better is certainly not high. There's reason for cautious optimism.


Self evaluation shouldn't be self loathing

posted by Jeff | Thursday, November 12, 2020, 11:16 PM | comments: 0

Between yesterday and today, I was able to bang out my self-eval for the annual review cycle, and a week before it was due even! I'm pretty excited about that. I was also pretty excited about what I've been able to knock out in seven months, because when I write it down, it's more than I thought.

But why is it so easy to forget all the wins when you look at the losses, OK, let's call them "challenges," and feel just crappy about them? There was one result I wasn't really happy about, and I just got hooked on that today. Maybe the standard form should reverse the order of the questions, so you can put your "things that didn't go well" before the "why are you awesome" bits.

I've talked a lot about self-awareness since, well, basically since always. It is one of the most critical keys to success. I'm immediately skeptical of anyone who thinks they can bat a thousand (is that the correct use of that sportsball metaphor?). In fact, if you don't suffer a little, it's like everything else, in that you can't know the good without the bad. Artists get harsh criticism, salesfolk lose the deal, couples break up, chefs make shitty food, cats fall of things.

Celebrates success. If you're self-aware, you'll learn from the mistakes and next time you'll avoid them.


Ronald Reagan hides alien love child from Nancy

posted by Jeff | Thursday, November 12, 2020, 9:30 AM | comments: 0

When I was a kid, my mom somehow managed to mostly spare us from having to go to the grocery store. But when we did, I was always amused by the tabloids at the checkout, and the completely absurd headlines and images on the covers. They were really into aliens in those days. I wondered who exactly was entertained by such silly things.

Later, when I got a little older, I learned that the silly things were taken seriously by some people. Maybe it was those goofy grandmas out there, bored, or maybe it was folks genuinely willing to believe that Walt Disney's head was frozen in a jar.

Of course, it didn't take a ton of critical thinking to see the absurdity of this. If any of these things were true, we would see Peter Jennings talk about it on ABC News, or see it in the Cleveland Plain Dealer. The truth was definitely more obvious via critical thinking than the trust of its source.

Now, in 2020, a non-trivial number of people believe that there is a cabal of Satan-worshipping pedophiles, drinking blood, made up of Hollywood elites and Democrats, that are controlling everything and undermining President Trump. This would have been fine if the folks that believed this were hard to find, but they're not. Reporters find them and publish their accounts. A few years ago, some dude walked into a pizza joint armed, where he believed kids were being trafficked. You can't make this stuff up.

Back in the day, we discounted the "crazy" people who bought the tabloids and believed them. We gave them no more credence than that. The spread of the nonsense was fairly contained, and you had to actually buy the content. These days, the cost of obtaining that information is essentially zero, as it's fueled by advertising and social media, for which you are the product. That by itself shouldn't be that big of a deal, right? Well, it's like the X-Files... do you want to believe? If so, disregard critical thinking, and go for it.

You've seen plenty of this. A person posts a link online to a blog that was started last week, or by a lobbyist with a clever name like, "Americans For High Fidelity Freedom And Sandwiches" or some such shit. The source doesn't matter, because they want to believe. And the "mainstream" press? Well, they're naturally part of the aforementioned cabal, because the people I want to believe said so.

Cognitive dissonance and bias aside, what we're looking at now is the tabloids of the modern era. It may take a little deeper looking and critical thinking to sniff out bullshit, but not that much. We used to look at the old lady at the grocery store checkout as harmless, but this behavior now is not harmless. What's worse, some are willing to disregard this as a difference in opinion that we should just respect. We don't need to respect the beliefs of the modern equivalent of tabloid readers.

Reality, facts, observable truth, are still real. We have to get back to honoring that. All of the conspiracy theories about election fraud, in the same election that won back House seats and will likely retain the Senate for Republicans, are the alien baby headlines. It's not because I said so, it's because the facts and observable truth are right in front of you and basic critical thinking confirms them.

Let's stop pretending that there's something elite or uppity about critical thinking.


Biden won, but it feels like we're losing anyway

posted by Jeff | Wednesday, November 11, 2020, 9:48 PM | comments: 0

I've been sitting on this for awhile, trying to process the election. Eventually it became clear that Joe Biden was the winner, but it was close enough that it never felt like a foregone conclusion, which was troubling in many ways.

It really started when a friend of mine made a Facebook post on Wednesday, the day after the election, expressing his frustration that the results being close had harmed his faith in humanity. It's important to note that he's gay, and a vocal advocate for equality for the LGBTQ community. An hour later, another friend (more acquaintance, but "friend" in the context of social media), also gay, made a similar post. On Thursday, an African-American friend expressed similar concern about not being seen, and only feeling slightly less in danger for the color of his skin. When Biden's win was a statistical certainty on Saturday, the emotional response of CNN commentator Van Jones was widely shared, and it got to the core of the problem:

"The 'I can't breathe,' that wasn't just George Floyd. That's a lot of people have felt they couldn't breathe. Every day you're waking up and getting tweets and you're going to the store and people who have been afraid to show their racism are getting nastier and nastier to you and you're worried about your kids and you're worried about your sister, and can she just go to Walmart and get back into her car without somebody saying something to her. "

That's why this didn't feel good. Racism isn't something you just casually disregard when it comes to an elected official, as I've said before. The same goes for homophobia, xenophobia, misogyny and the various -isms that we as a polite and maturing society should find abhorrent. For a Trump supporter, overlooking these traits for the sake of some perceived policy benefit is to overlook the identity, and very essence of being alive, of others. It's really that deep. Think of something that identifies you as a core part of your being, and then imagine that 30% of the people who can vote support a candidate that actively and publicly speaks against that identity. If you're a white person, I implore you to take a moment to consider that, because as a white, employed, hetero guy, I'm aware of the extraordinary privilege I have to not worry about it.

Someone may critically say, "What about your contempt for Trump supporters? Maybe they don't feel heard either." First off, I don't have contempt for anyone, only frustration. That's where it gets really hard to find common ground. I'm not interested in the business of ranking who hurts more (because, R.E.M.), but it's very difficult, if not impossible, to empathize with a person who exercises the kind of cognitive dissonance required to dismiss basic facts, embrace conspiracy theories, reject science and education. It's also not easy to reconcile a person who finds moral equivalence where there is none. In fact, if you defend the immoral acts of one person with "everybody's doing it," with accusations that the opposing actors do the same thing, then how can you claim that the morals matter to you at all? Wouldn't you want "your" candidate to be bound by those morals?

It's also difficult to find that empathy with someone who is not interested in seeing that the very acts that marginalize minorities are not merely a side effect of policy decisions. You can in fact have strong opinions about limiting immigration without arguing (falsely) that immigrants are rapists and drug dealers. You can argue the merits (if there are any) of limiting reproductive rights without (falsely) suggesting that the opposition is out to crush your religion. You can debate the reform of law enforcement without (falsely) suggesting that victims of police brutality deserved it. You can argue against government subsidized health insurance without (falsely) suggesting that it's used by freeloaders and a government that wants to take over your life.

It's difficult to find empathy for a person willing to overlook the immoral acts of a man who represents our worst. It should have been over before it started when Trump spread the racist birther conspiracy. It should have been over when everyone heard that Trump likes to "grab them by the pussy" and "move on them like a bitch." It should have been over when he mocked a disabled person. It should have been over when he suggested he likes veterans who weren't captured (in reference to John McCain, who regardless of policy represents the ultimate record of public service). It really should have been over when he asked a foreign government to dig up dirt on his opponent. It should have been over when he said there were good people on the side of white nationalists. None of these occurrences are a matter of opinion... they all happened in plain view of the world. If my then-6-year-old child associates the angry man on TV with the worst of school bullies, why is it so hard for adults?

Despite all of that, I want to understand. I want to understand what drives white people to believe that they are being oppressed and at risk of losing their lifestyle, and to whom. Like I said, I am a white, hetero guy, with a great job and a 401k, and there is nothing that anyone on the "radical left," to use the parlance of our time, can do to take away my advantage. Immigrants, people of color, non-Christians, gay people, none of them pose a threat. The boogeyman socialists pose no threat. Trust me, if I was worried about my survival, I'd speak up about all of this, and likely express frustration that my alleged survival politics are tied to the horrible 'isms and hateful acts of those fearing brown people.

For now, cautious optimism is all I've got. The world certainly can get better if it doesn't involve an American president saying outright hateful things every single day. I can't think of many people less inspiring than Joe Biden, but maybe a big pile of boring normal is what we need.


Not sure how we avoided a real hurricane this year

posted by Jeff | Wednesday, November 11, 2020, 8:33 PM | comments: 0

If there's anything that you could count on for 2020, it's that it would keep throwing crap at you. With a particularly active hurricane season where they ran the whole series of named storms, it seems almost impossible that none of them really hit Central Florida in a meaningful way.

Right now the outer bands of tropical storm Eta are messing with us for the second time, and we'll have sustained wind around maybe 20 mph, with gusts up to 40. That's not quite bring-in-your-patio-chairs weather, but it's interesting enough. We haven't had anything serious here since Irma, three years ago, which is just fine.

In fact, after seven years living here, we've only had Irma, and Matthew which ended up not being serious (and we were in North Carolina when it hit anyway). I always had a mental picture of it being a more frequent thing in Florida, but weather reputations are rarely earned. People seem disappointed to hear that it doesn't rain every day, all year, in Seattle, that you need to water your lawn in the summer or it will die.

I do imagine that it's going to get weird in Florida, especially the southeast coastal areas, in the next few decades. If you don't believe the science of climate change, believe the risk profile that insurers place on property there. Insurance is not an emotional issue, it's just numbers. I know those areas are very low-lying, with the sea literally coming up through the ground in places, but I wonder if further up the coast that's less likely. Even in places like Cocoa Beach and around Merritt Island, it seems like the land is high enough to survive. I wouldn't mind living out there someday in a tiny place on top of a sand dune.

I know the odds of a storm viewed in any single year don't change much, but karma feels like we're due.


The 2020 cell phone product cycle

posted by Jeff | Tuesday, November 10, 2020, 6:42 PM | comments: 0

This has been another weird year for phone product releases, which is to say that it's unsatisfying again. Google doesn't seem to have a single product manager that can make good decisions, Apple is still chasing absurd pricing (mostly), and Samsung is just doing whatever and relying on carrier deals.

First off, I continue to believe that anything more than $600 for a phone you'll use for two years is absurd. That's where I'm at. Without subsidies or credits, I can't see going higher than that.

Apple is still offering anemic storage with insane prices, which surprises me because they're still stagnant in global market share, and Apple's results show little growth for phones. This year they have a $700 "mini" model, which is a step in the right direction, and they're still offering the SE for $400. They're still making amazing hardware, but is it worth spending 2.5x, a grand, on a phone? I doubt it's $600 better. I bought a cheap iPod to mess with for development purposes, and iOS seems to be getting jankier. The settings are a mess, and the widget model they're using is inferior to what's on Android or even the defunct Windows Phone. Don't get me started on how developer hostile they are.

I can't really tear into Samsung, because while I find their flagship phones absurd in pricing, they have so many skus and market-specific models that there's a reason they're only slightly behind Huawei globally. If the distrust in Huawei continues, I imagine they'll be back to number one. If they were better about OS updates, I would seriously consider them, but I'm turned off by the color science and exposure they use on their cameras. They make photos look like the demo mode of TV's at Best Buy, which isn't good.

Google did a summer release of the Pixel 4a, pricing it at $350, and I couldn't believe it. It's not a premium phone in terms of CPU, but it's all the same camera magic they've been shipping in the flagships. If I didn't already have a 4, which is fine except for the face unlock (because masks and Covid), the 4a would be a no-brainer. What makes even less sense is the new 5, which at $700 is not twice the 4a. It's a weird mix of features and compromises that again make for a weird phone and a high price point that doesn't make sense. All they had to do was take a 4a, add the water resistance, and put in a better processor, and bam, they would have a great phone.

If they again offer some big Fi credit and trade, sure, I'll look at upgrading, but I really don't need to. Cell phones seem like a solved problem. If the batteries are working and they're still getting software and security updates, there isn't a lot of incentive to upgrade anymore.


Deeper into mobile and progressive web apps

posted by Jeff | Wednesday, November 4, 2020, 2:01 AM | comments: 0

As I've gone deeper into the looking at mobile app development and progressive web apps, I'm getting more annoyed with the iOS side of things. In terms of PWA's, it's pretty clear that Apple is not interested in supporting anything that isn't coming through their app store.

I looked for a hot moment at Xamarin for cross-platform development for iOS and Android, and honestly, I'm not feeling it. I remember now that Xamarin as a XAML-based platform, using the MVVM pattern, kind of sucks. I know that Microsoft didn't yet own Xamarin back in the day, but XML as the thing that drives all the things in the early part of the decade isn't great. (I know that HTML is technically XML, but it's way simpler and easier to work with.) In messing with that, even getting Xcode installed on my old Mac was a pain, as it's necessary to compile an iOS app. I'm definitely not going to learn Swift to start working with iOS.

But the PWA story, that's not ideal either. What I've found so far is that Chrome/Edge are all-in on supporting PWA's as a concept, on Android and even Windows. Firefox is good-ish, but Safari is dreadful. It lends some credence to the old Steve Jobs thing where he said, "The Web is the app." A part of me wishes that he would have stuck to that. Developers put out some early open source style and touch frameworks that made it possible for web apps to look like native iPhone apps. Since then, a combination of standards have made it possible to do amazing things in the browser, again Safari not withstanding.

Relative to my music locker project, obviously I'm biased to the things I have, which is Android on the phone. I've been using it lately on my phone, and it is indistinguishable from using a native app. Because Chrome on Android even supports the media metadata API (as well as Edge, even though it reportedly does not), my app even puts the current track data and play/pause and skip functionality on the lock screen. It doesn't work on iOS. Worse, there's a quirk where iOS won't even allow and HTML audio element to play a track without direct human intervention. Lame.

Service workers and the cache API though allow me to save music metadata, the album covers and even the music itself using just the browser. It is effectively as good as native, at least for Android (and even Windows and desktop Mac). I've really enjoyed working on it so far, and relieved that I don't need to build something native. The first use case was the desktop browser, where I sit all day during the day, and using the same thing for my phone is a huge win. I'm frustrated that it doesn't work on iOS as well, but given the fact that I don't primarily use that OS for anything, I'm not sure that I care. It's an open source project. If someone else is passionate about it, they can do a pull request. 🙂


Three years in the house, now refinancing

posted by Jeff | Tuesday, November 3, 2020, 5:30 PM | comments: 4

We closed on our house three years ago today. As of spring, this will be the longest that Diana and I have lived in once place, and we've been living together for 13 years with six moves. What I never thought that I would be doing is refinancing it already, but there are a lot of things about 2020 that don't entirely make sense.

Our home ownership journey has been exceptionally weird the whole time. When we got married in 2009, we owned two houses in the Cleveland area, when the market was a mess. We moved to Seattle at the end of that year as renters, and were able to shed her house as a short sale but couldn't sell mine. Eventually we moved back to Cleveland into my house, because even with Seattle wages, we weren't getting ahead. Then we moved to Central Florida, sold my house in 48 hours, and put a deposit down to build a house within a week or two. Getting the loan for that house was a struggle because I was working contract at the time (which in bank terms might as well be unemployed), but it eventually got worked out and we landed a surprisingly decent rate of 4.375%. I was thrilled!

We were in that house for almost three years when we felt the walls were closing in a bit because I work mostly remotely, Diana's quilt machine was partially in a closet, and Simon was sprawling out, as kids do. Property values were going up and the house appreciated, and rates were going even further down, so we pulled the trigger and built another house. This time I got a rate of 3.999%, which seemed even more crazy.

And that leads me to today. Normally one doesn't really consider refinancing unless they've been at it for years, they can get a better rate, or want to shrink to a shorter term. I kept seeing ads for rates under 3%, so I figured, what the heck, I might as well look into it. I found some crazy low rates that involved putting big sums down or buying points, but the break even point, where the reduction in monthly payment compensates for the up front cost, was three or four years, which is too long. I went back to the guy who scored my first Florida loan, and he came back with a rate of 2.875%, more than a point lower than where I am! Best of all, rolling the cost of the loan into it, I don't have to put anything into it. I'll come out $300 ahead monthly and be break-even in 19 months. That's crazy. If we stay put for a dozen years, our net savings will be about $30k.

The flip side of this interest rate madness is that saving money straight up (not investing) is basically pointless. The savings account I have used to pay 3%, and now it's like 0.39% or something silly like that. What a crappy thing when in "uncertain times" you want to hold on to a little money in a risk-free and liquid way in case of an emergency. This also illustrates why home ownership is such a huge key to American "success." With a house appreciating by at least 5% per year and paying 2.875% interest on only a portion of the house's value, I'm wealth building and I have a place to live (assuming here the housing market doesn't take another shit). A renter just has an expense that they'll never get anything back for. That's messed up. It feels like an old European aristocracy, where the land owners have all the power.


The Orville is the best show I had not seen

posted by Jeff | Sunday, November 1, 2020, 3:21 PM | comments: 0

Seth MacFarlane, you know, the Family Guy, decided he wanted to roll a science fiction show with humor, because he'll never have to worry about money again. I mean, he talked Fox into rebooting Cosmos, so why not? So he got The Orville made, and it's completely brilliant.

I've never been that into Star Trek, though I've admired the stories they told as these quasi-morality plays set in a future where there is no money and we're able to cross light years in short order. What I've learned about the genre is that what's usually missing is humor. The Orville is not really a comedy, but there are just enough dick-and-fart jokes to make it not take itself so seriously. The show is both an homage to, and rip-off of, Star Trek, and it's great. In fact, a ton of Trek alumni have made cameos in the show, as well as a ton of other great character actors like Patrick Warburton.

They've cranked out two seasons so far, and they're available on Hulu. The third season was apparently half-shot when Covid hit, so there will eventually be more to come. If you're looking for something to binge watch, do it. It's surprisingly well written and I found myself really invested in most of the characters.