Analyzing Star Trek episode titles

Oliver Brown
— This upcoming video may not be available to view yet.
Gorn from Star Trek episode Arena

I recently found myself idly wondering what the shortest Star Trek episode title was. The first to come to mind was the Original Series episode “Arena” (the one which Captain Kirk fights a humanoid lizard in one of the most striking examples of 1960 “makeup”).

I guessed there were probably shorter ones, but was rather disappointed I didn’t know the answer for sure. So I decided to find out.

While investigating, I also started wondering other things, like: what is the longest episode title? Which series has the shortest or longest titles on average? How many episodes begin with “the”?

I have decided to gather the answers to these questions and more together into a series of blog posts.

Some ground rules

I quickly realised even for “shortest episode title” there were some decisions I would have to make about what would count.

What counts as a letter?
Any character is a letter. So including (but not necessarily limited to):
  • The letters A-Z (regardless of case or accents).
  • The digits 0-9.
  • Any punctuation symbol.
  • A space.
  • An ellipsis (so three dots … is a single character).
What counts as a word?
Spaces separate words, nothing else does. 37's is one word, as is 11001001.
Which series/episodes are included?
I decided to include all episodes from The Original Series (including “The Cage”), The Next Generation, Deep Space Nine, Voyager and Enterprise. This is for the simple practical reason that no more episodes are being produced for these (with the recent annocunement that season 5 of Discovery will be its last, I may redo this including Discovery in the near future).
What about two-part episodes?
For two part episodes (that don’t have completely different titles), I’m just using the “base name”.

About those two-part episodes

The first two-part episode of Star Trek was called “The Menagerie”. In the episode title sequence it is styled as "THE MENAGERIE" PART I and "THE MENAGERIE" PART II, with the part information clearly outside the quotation marks used to identify the title. This suggests the title is in fact “The Menagerie”.

“The Menagerie” (as far as I am aware) was never produced as a single feature length episode. Many other two-part episodes were either broadcast originally as a single episode, or later made available as one (often with additional footage included). This means an episode could potentially have three different names (one for each part individually and one for the whole) and using the “base name” seems most sensible in this case.

It should also be noted, there is little consistency in how the two-part episode titles are handled. Some of them give the first part the “base name” and add “Part II” after whereas others include the part information in both titles. Whether the part information is inside the quotes varies, and even whether the word “part” is included.

So overall, I feel justified in in using the “base name”, just as a way of establishing some kind of order. Although I can already tell I’m going to have to write a detailed blog post covering all of this (especially if I get to including Discovery, since that messes everything up by having an episode titled as if it is the third part of a three-part episode, the first two parts of which are from another series).

Image copyright © Paramount Global and used under fair use.

Updated Discworld audiobook release dates

Oliver Brown
— This upcoming video may not be available to view yet.

New audio versions of all* of the Discworld books are being produced. They aren’t being released in order though and as far as I can tell there is no convenient page listing all the release dates.

So here are the release dates currently listed on Audible as of 15th March, 2023. There are a few different ways Discworld books get grouped. “Series” below is how Audible have grouped them (and I assume matches the narrator).

Release date

2021 December 21st

Title Series
Hogfather Death 20

2022 April 28th

Title Series
Equal Rites Witches 3
Wyrd Sisters Witches 6
Witches Abroad Witches 12
Lords and Ladies Witches 14
Maskerade Witches 18
Carpe Jugulum Witches 23
Small Gods Standalone 13

2022 July 7th

Title Series
The Colour of Magic Rincewind 1
The Light Fantastic Rincewind 2
Sourcery Rincewind 5
Eric Rincewind 9
Interesting Times Rincewind 17
The Last Continent Rincewind 22
Unseen Academicals Rincewind 37

2022 October 6th

Title Series
The Amazing Maurice and His Educated Rodents Standalone 28

2022 October 27th

Title Series
Mort Death 4
Reaper Man Death 11
Soul Music Death 16
Thief of Time Death 26

2023 February 23rd

Title Series
The Truth Industrial Revolution 25
Monstrous Regiment Industrial Revolution 31
Going Postal Industrial Revolution 33
Making Money Industrial Revolution 36
Raising Steam Industrial Revolution 40

2023 March 30th

Title Series
Pyramids Standalone 7

2023 May 18th

Title Series
Moving Pictures Industrial Revolution 10

2023 May 25th

Title Series
Guards! Guards! Ankh-Morpork City Watch 8
Men at Arms Ankh-Morpork City Watch 15
Feet of Clay Ankh-Morpork City Watch 19
Jingo Ankh-Morpork City Watch 21
The Fifth Elephant Ankh-Morpork City Watch 24
Night Watch Ankh-Morpork City Watch 29
Thud! Ankh-Morpork City Watch 34
Snuff Ankh-Morpork City Watch 39

2023 June 15th

Title Series
The Wee Free Men Tiffany Aching 30
A Hat Full of Sky Tiffany Aching 32
Wintersmith Tiffany Aching 35
I Shall Wear Midnight Tiffany Aching 38
The Sheperd’s Crown Tiffany Aching 41

Reading order

Title Series Release date
The Colour of Magic Rincewind 1 2022 July 7th
The Light Fantastic Rincewind 2 2022 July 7th
Equal Rites Witches 3 2022 April 28th
Mort Death 4 2022 October 27th
Sourcery Rincewind 5 2022 July 7th
Wyrd Sisters Witches 6 2022 April 28th
Pyramids Standalone 7 2023 March 30th
Guards! Gaurds! Ankh-Morpork City Watch 8 2023 May 25th
Eric Rincewind 9 2022 July 7th
Moving Pictures Industrial Revolution 10 2023 May 18th
Reaper Man Death 11 2022 October 27th
Witches Abroad Witches 12 2022 April 28th
Small Gods Standalone 13 2022 April 28th
Lords and Ladies Witches 14 2022 April 28th
Men at Arms Ankh-Morpork City Watch 15 2023 May 25th
Soul Music Death 16 2022 October 27th
Maskerade Witches 18 2022 April 28th
Interesting Times Rincewind 17 2022 July 7th
Feet of Clay Ankh-Morpork City Watch 19 2023 May 25th
Hogfather Death 20 2021 December 21st
Jingo Ankh-Morpork City Watch 21 2023 May 25th
The Last Continent Rincewind 22 2022 July 7th
Carpe Jugulum Witches 23 2022 April 28th
The Fifth Elephant Ankh-Morpork City Watch 24 2023 May 25th
The Truth Industrial Revolution 25 2023 February 23rd
Thief of Time Death 26 2022 October 27th
The Amazing Maurice and His Educated Rodents Standalone 28 2022 October 6th
Night Watch Ankh-Morpork City Watch 29 2023 May 25th
The Wee Free Men Tiffany Aching 30 2023 June 15th
Monstrous Regiment Industrial Revolution 31 2023 February 23rd
A Hat Full of Sky Tiffany Aching 32 2023 June 15th
Going Postal Industrial Revolution 33 2023 February 23rd
Thud! Ankh-Morpork City Watch 34 2023 May 25th
Wintersmith Tiffany Aching 35 2023 June 15th
Making Money Industrial Revolution 36 2023 February 23rd
Unseen Academicals Rincewind 37 2022 July 7th
I Shall Wear Midnight Tiffany Aching 38 2023 June 15th
Snuff Ankh-Morpork City Watch 39 2023 May 25th
Raising Steam Industrial Revolution 40 2023 February 23rd
The Sheperd’s Crown Tiffany Aching 41 2023 June 15th

Blazor Numbers Game

Oliver Brown
— This upcoming video may not be available to view yet.

Over the weekend I was playing around with Blazor and created a little number game based on part of a popular British TV show.

In the future this may expand in functionality as part of my exploration into Blazor.

You can try the number game full screen.

Mettle is probably not suitable for tech businesses

Oliver Brown
— This upcoming video may not be available to view yet.

Just to avoid any confusion, everything in this post is based on how things work in the UK and is for things available in the UK.

So far I have operated various business ventures off my personal bank account. Since I’ve been doing this as a sole trader, this is allowed. It does however make tax returns take more effort than necessary.

FreeAgent

I recently had reason to interact with FreeAgent, which is some pretty cool accounting software that makes a lot of things simpler. Unfortunately to really use it to its potential, you need to link it to a bank account used solely for your business.

Conveniently, they offer a free account to anyone who has a Mettle account. I had seen Mettle before, and it is described as “the free mobile business account with no hidden fees or charges”, and is operated by NatWest, one of the big UK high street banks.

E-money accounts

After a quick investigation, it seems one of the reasons it is free (which is the norm for personal accounts in the UK but not business accounts) is that it is not actually a bank account, but an “e-money account”. You get an account number as well as a debit card, but it is not subject to the Financial Services Compensation Scheme (a scheme in the UK in which the government guarantees bank balances up to a certain amount if a bank goes under).

That limitation seemed fine to me since I did not intend to keep a large balance, so I created an account. Sadly, I found out there are other limitations which basically rendered it useless to me.

Prepaid cards

Firstly, it does not come with an IBAN (international bank account number). This means I cannot receive payments from Apple. Secondly, the card is a prepaid card. Since it is tied to the e-money account they give you, it feels like a debit card to use, except some things just don’t accept payments using them. Crucially for me, Microsoft Azure and Google Ads.

Conclusion

In the end, I opened a business account with Royal Bank of Scotland. RBS and NatWest business accounts also get free FreeAgent accounts. The application was more involved (for Mettle, besides verifying your ID you just have to declare you aren’t in one of their list of prohibited business) but in the end was fine.

New Discworld audiobooks

Oliver Brown
— This upcoming video may not be available to view yet.

Updated release dates available here.

New audio versions of all* of the Discworld books are being produced. They aren’t being released in order though and as far as I can tell there is no convenient page listing all the release dates.

So here are the release dates currently listed on Audible. There are a few different ways Discworld books get grouped. “Series” below is how Audible have grouped them (and I assume matches the narrator).

Release date

2021 December 21st

Title Series
Hogfather Death 20

2022 April 28th

Title Series
Equal Rites Witches 3
Wyrd Sisters Witches 6
Witches Abroad Witches 12
Lords and Ladies Witches 14
Maskerade Witches 18
Carpe Jugulum Witches 23
Small Gods Standalone 13

2022 July 7th

Title Series
The Colour of Magic Rincewind 1
The Light Fantastic Rincewind 2
Sourcery Rincewind 5
Eric Rincewind 9
Interesting Times Rincewind 17
The Last Continent Rincewind 22
Unseen Academicals Rincewind 37

2022 October 10th

Title Series
The Amazing Maurice and His Educated Rodents Standalone 28

2022 October 27th

Title Series
Mort Death 4
Reaper Man Death 11
Soul Music Death 16
Thief of Time Death 26

2023 February 23rd

Title Series
Moving Pictures Industrial Revolution 10
The Truth Industrial Revolution 25
Monstrous Regiment Industrial Revolution 31
Going Postal Industrial Revolution 33
Making Money Industrial Revolution 36
Raising Steam Industrial Revolution 40
Pyramids Standalone 7

Release date - To be released

2023 April 27th

Title Series
Guards! Guards! Ankh-Morpork City Watch 8
Men at Arms Ankh-Morpork City Watch 15
Feet of Clay Ankh-Morpork City Watch 19
Jingo Ankh-Morpork City Watch 21
The Fifth Elephant Ankh-Morpork City Watch 24
Night Watch Ankh-Morpork City Watch 29
Thud! Ankh-Morpork City Watch 34
Snuff Ankh-Morpork City Watch 39
The Wee Free Men Tiffany Aching 30
A Hat Full of Sky Tiffany Aching 32
Wintersmith Tiffany Aching 35
I Shall Wear Midnight Tiffany Aching 38
The Sheperd’s Crown Tiffany Aching 41

Unknown

Title Series
The Last Hero Rincewind 27

Reading order

Title Series Release date
The Colour of Magic Rincewind 1 2022 July 7th
The Light Fantastic Rincewind 2 2022 July 7th
Equal Rites Witches 3 2022 April 28th
Mort Death 4 2022 October 27th
Sourcery Rincewind 5 2022 July 7th
Wyrd Sisters Witches 6 2022 April 28th
Pyramids Standalone 7 2023 February 23rd
Guards! Gaurds! Ankh-Morpork City Watch 8 2023 April 27th
Eric Rincewind 9 2022 July 7th
Moving Pictures Industrial Revolution 10 2023 February 23rd
Reaper Man Death 11 2022 October 27th
Witches Abroad Witches 12 2022 April 28th
Small Gods Standalone 13 2022 April 28th
Lords and Ladies Witches 14 2022 April 28th
Men at Arms Ankh-Morpork City Watch 15 2023 April 27th
Soul Music Death 16 2022 October 27th
Maskreade Witches 18 2022 April 28th
Interesting Times Rincewind 17 2022 July 7th
Feet of Clay Ankh-Morpork City Watch 19 2023 April 27th
Hogfather Death 20 2021 December 21st
Jingo Ankh-Morpork City Watch 21 2023 April 27th
The Last Continent Rincewind 22 2022 July 7th
Carpe Jugulum Witches 23 2022 April 28th
The Fifth Elephant Ankh-Morpork City Watch 24 2023 April 27th
The Truth Industrial Revolution 25 2023 February 23rd
Thief of Time Death 26 2022 October 27th
The Last Hero Rincewind 27 Unknown
The Amazing Maurice and His Educated Rodents Standalone 28 2022 October 10th
Night Watch Ankh-Morpork City Watch 29 2023 April 27th
The Wee Free Men Tiffany Aching 30 2023 April 27th
Monstrous Regiment Industrial Revolution 31 2023 February 23rd
A Hat Full of Sky Tiffany Aching 32 2023 April 27th
Going Postal Industrial Revolution 33 2023 February 23rd
Thud! Ankh-Morpork City Watch 34 2023 April 27th
Wintersmith Tiffany Aching 35 2023 April 27th
Making Money Industrial Revolution 36 2023 February 23rd
Unseen Academicals Rincewind 37 2022 July 7th
I Shall Wear Midnight Tiffany Aching 38 2023 April 27th
Snuff Ankh-Morpork City Watch 39 2023 April 27th
Raising Steam Industrial Revolution 40 2023 February 23rd
The Sheperd’s Crown Tiffany Aching 41 2023 April 27th

* There are 41 Discworld books. The website says “40 magnificent new recordings”. The one that seems to be missing is “The Last Hero”.

Interacting with this video is done so under the Terms of Service of YouTube
View this video directly on YouTube

IAB Transparency & Consent Framework does not meet GDRP requirements for transparency or consent

Oliver Brown
— This upcoming video may not be available to view yet.

I posted a while ago about a technical standard that was being used for consent gathering on websites and in apps known as the “Transparency & Consent Framework” by IAB Europe.

Well, the Belgian Data Protection Agency (the Belgian organization responsible for enforcing the GDPR) has fined IAB Europe €250,000 because the TCF “fails to comply with a number of provisions of the GDPR”.

I don’t know whether fining IAB Europe is the correct choice, as they themselves claim they aren’t a data controller and only provide guidance (and a spec) for other companies to use. But the fine itself is not really what is going to be turn out important. The judgement requires:

all recipients of the personal data processed in the TCF . . . to permanently delete all TC Strings and other personal data already processed in the TCF from all IT systems, files and data carriers.

One piece of irony - if you search for articles about this you will find they are nearly all protected by consent dialogs based on TCF.

Here is the full judgement in English.

Blazor custom elements

Oliver Brown
— This upcoming video may not be available to view yet.

There is now a preview package for Blazor that allows creating custom elements.

Custom elements are part of the Web Components standards and are intended to be a way of defining tags that can be consumed in HTML and interoperate with each other.

The docs mostly focus on using them with Angular or React, but that isn’t why they are interesting to me.

The site for Tic-tac-toe Collection includes pages that show some information about specific game mode (for example four-player Tic-tac-toe misère rumble).

That content is rendered as a custom element (in this case <ttt-settings short-code="T_D4_S6x6_W3_T0_P0_M1_O1_F0"></ttt-settings>). Since the site is statically generated with no frontend framework, I wrote the element in vanilla JavaScript. Blazor support for custom elements means I could rewrite that component in C#.

[SOLVED] Firebase Performance Monitoring in Xamarin Android

Oliver Brown
— This upcoming video may not be available to view yet.

I decided to add Firebase Performance Monitoring to the latest version of Tic-tac-toe Collection.

What is it

This allows you to collect timed traces of things that happen in your app. You can set up custom traces for anything you like, but it also tracks how long HTTP requests take by default. At least it’s supposed to. On iOS it worked well, but Android had nothing.

There is an open issue on the repo with the Xamarin binding that was created in December 2018. It includes suggestions to make sure your app is set to using the native HTTP handlers (which makes sense since whatever Firebase is doing it won’t be expecting a random third party HTTP stack to be used), however it still does not work.

How does it work

So I decided to investigate how the HTTP tracing is actually implemented. How found this Stack Overflow question which lead me to this video. It turns out the implementation works by doing some byte code rewriting that changes any references in your app to the HTTP classes to instead reference Firebase provided wrappers.

Why doesn’t it work for Xamarin Android?

I kind of assumed it was doing something like that, but didn’t really think through the implications. Specifically - it does the byte code rewriting as part of a Gradle plugin that is not executed as part of a Xamarin build.

Solution

It may be possible to get the Gradle plugin to execute it’s transformer, but that seems complicated. Luckily, Firebase does provide support for adding HTTP tracing to other libraries, so I decided to work with that.

I decided to implement my own HttpMessageHandler that sets up the HttpMetric and then delegates to a normal HttpClientHandler. This can be passed into the constructor of HttpClient.

public class FirebaseHttpMessageHandler : DelegatingHandler
{
    public FirebaseHttpMessageHandler() : base(new HttpClientHandler())
    {
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var metric = StartTracking(request);
        var response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
        StopTracking(metric, response);
        return response;
    }

    private HttpMetric? StartTracking(HttpRequestMessage request)
    {
        try
        {
            var url = new Java.Net.URL(request.RequestUri.AbsoluteUri);
            var metric = Firebase.Perf.FirebasePerformance.Instance.NewHttpMetric(url, request.Method.Method);
            metric.Start();
            if (request.Content?.Headers?.ContentLength is long length)
            {
                metric.SetRequestPayloadSize(length);
            }

            return metric;
        }
        catch (Exception ex)
        {
            Debug.Fail($"URL performance tracking failed: {request.RequestUri.AbsoluteUri} - {ex.Message}");
            return null;
        }
    }

    private void StopTracking(HttpMetric? metric, HttpResponseMessage response)
    {
        if (metric is null)
        {
            return;
        }
        try
        {
            metric.SetHttpResponseCode((int)response.StatusCode);
            if (response.Content?.Headers?.ContentLength is long length)
            {
                metric.SetResponsePayloadSize(length);
            }
            if (response.Content?.Headers?.ContentType?.MediaType is string mediaType)
            {
                metric.SetResponseContentType(mediaType);
            }
        }
        catch (Exception ex)
        {
            Debug.Fail($"URL performance tracking failed: {response.RequestMessage.RequestUri.AbsoluteUri} - {ex.Message}");
        }
        finally
        {
            metric.Stop();
        }
    }
}

Why does it work for Xamarin iOS?

I don’t know the exact method used on iOS, but I do know that iOS has a feature called NSURLProtocol that lets you intercept all HTTP requests by the app, as well as method swizzling which lets you replace basically any method implementation at runtime.

Either of those could be used, and they would both just work in Xamarin.

Accessing the UI in Xamarin.iOS

Oliver Brown
— This upcoming video may not be available to view yet.

An interesting discussion happened recently, triggered by a code review of (something like) the following C#:

public class ProductViewController
{
    private UIView _detailsView { get; set; }
    private ProductViewModel _viewModel { get; set; }

    private void Process()
    {
        if (_viewModel.ProcessDetails)
        {
            InvokeOnMainThread(() =>
            {
                if (_detailsView != null)
                {
                    UpdateDetailsView();
                }
            });
        }
    }
}

One of the reviewers suggested moving the second if outside the call to InvokeOnMainThread (and then combining it with the other if).

The theory was that it would more efficient to check if we need to be on the main thread before we do it, instead of doing the check on the main thread and finding out we have nothing to do.

The original author pushed back saying you can’t access _detailsView off the main thread since you would get an exception.

On the surface this sounds reasonable - everyone knows you can only access UIKit objects on the main thread. But it naturally leads to the question: what does “accessing a UIKit object” actually mean?

So I wrote a quick sample that intentionally tries to do lots of UIKit manipulation on background threads in various ways:

The tests

Quick refresher. The View property of a newly constructed UIViewController is not populated until it is first accessed. Some of the tests below refer to accessing this property either before or after it is created. By default properties declared in C# will not be visible to any native iOS code. They can be made visible by adding the [Export] attribute.

  • Create a UIViewController.
  • Create a UIView.
  • Create a UIColor.
  • Check if a view controller’s View property is equal to null.
  • Check if a view controller’s View property is null using pattern matching.
  • Check if a view controller’s IsViewLoaded property is equal to true.
  • Check if a view controller’s View property is equal to null after previously creating View on the main thread.
  • Check if a view controller’s View property is null using pattern matching after previously creating View on the main thread.
  • Check if a view controller’s IsViewLoaded property is equal to true after previously creating View on the main thread.
  • Check if a new UIView property, that is not exported is equal to null.
  • Check if a new UIView property, that is not exported is null using pattern matching.
  • Check if a new UIView property, that is exported is equal to null.
  • Check if a new UIView property, that is exported is null using pattern matching.
  • Check if a view controller’s NavigationController property is equal to null.
  • Check if a view controller’s NavigationController property is null using pattern matching.
  • Set a new UIView property, that is not exported, with a view created on the main thread.
  • Set a new UIView property, that is exported, with a view created on the main thread.

Results

Test Result
Create UIViewController Exception
Create UIView Exception
Create UIColor OK
Check if View is equal to null Exception
Check if View is null pattern Exception
Check if View is loaded Exception
Check if View is equal to null after creating View Exception
Check if View is null pattern after creating View Exception
Check if View is loaded after creating View Exception
Check if non-exported view is equal to null OK
Check if non-exported view is null pattern OK
Check if exported view is equal to null OK
Check if exported view is null pattern OK
Check if NavigationController is equal to null Exception
Check if NavigationController is null pattern Exception
Set non-exported view OK
Set exported view OK

Summary

This is by no means exhaustive, but it seems in general, acessing properties declared natively in iOS will throw an exception whereas accessing properties you have declared yourself will be fine. I had a suspicion that an exported view might behave the same as a native property, but apparently not.

The code for this test is available on GitHub.

Charles Dunstone in the news

Oliver Brown
— This upcoming video may not be available to view yet.

Charles Dunstone, a well known entrepreneur and founder of Carphone Warehouse has quit as chair of the Royal Museums Greenwich.

Apparently, the government refused to reappoint a trustee because they advocated for “decolonising” the curriculum. More information is available on the Financial Times.

Normally I wouldn’t be interested in posting about such things, but my blog has a bit of history with Charles Dunstone. He was in charge of UK ISP TalkTalk when it came out. Some people had problems and people complaining about it resulted in my most popular blog post.

Some of the complaints led to some interesting solutions, and I briefly included Charles Dunstone’s email address.