Hello and welcome to Python Bytes, where we deliver Python news and headlines directly to your earbuds.
This is episode 404, recorded October 7th, 2024.
I'm Michael Kennedy.
And I'm Brian Okken.
And this episode is brought to you by Scout APM.
We will, of course, tell you more about them later.
The link is in the podcast player show notes right at the top.
Brian, I've been looking for this episode for a while and I just can't find it, man.
I was like, where do I go?
404.
Everywhere I go, it's 404.
What's going on?
Yeah, I don't know.
We'll find it.
Let's make it.
It's going to be a journey.
We're going to try to get our way through it.
Speaking of a journey, you want to stay in touch with us, hit by them by Scout APM.
Click on newsletter.
Enter your info there.
We'll keep you up to date.
Brian will send you some show notes.
Find us on Mastodon and other social places.
And even subscribe right here on YouTube if you're watching the video.
And with that, were you able to find an item for your first item today?
Well, I almost did it.
So, okay.
The first item, I really wanted to cover Python 3.13.
Because Python 3.13 is released on October 7th.
And today is, text notes, October 7th.
So, it's today, right?
So, I went to python.org and go, well, the latest, it still says latest is 3.12.
So, they're working on it.
Thomas Wooters and others.
It's a process to get it out.
But it's really out already.
So, you just can't see it.
If you go to downloads, it still says 3.12.
I'm sure it'll be updated soon.
However, we've got the link for 3.13.0.
It's really not that complicated.
Downloads, release, python-3.1.3.0.
And then you got it.
So, it's got a stable release of 3.13.0.
I've been playing with it this morning and having a lot of fun.
If you go down to the bottom of this link, there's where the installers are.
The pre-built installers, if you want to grab those.
Or you can install it yourself if you want.
Or build it yourself.
But I'm on a Mac right now.
So, I grabbed the Mac installer.
And I want to cover some of the new stuff in 3.13.
But I really wanted to play with the multi-threading stuff, which I haven't yet.
I just wanted to make sure it was enabled.
And there's a bit of a trick.
So, if you look in...
Maybe it's not in here.
It's in the What's New page.
So, if you go to the What's New, it does talk about the Python, the macOS, and Windows installers.
And there's a link somewhere in here.
But we'll include the link also.
That when you're installing it, and on the Mac, when I did it, you go through this install process.
You have to hit customize and click the free-threaded.
Because free-threading is off by default.
So, when you install it, you have to turn it on.
So, just remember that.
And I will play with the free-threading later.
So, what do we have new in 3.13?
I think we've covered this before.
But now we actually have 3.13.
So, we can play with it.
We have the interactive interpreter changes, which...
Actually, let's back up a little bit.
This isn't even called out here.
My favorite feature of 3.13 is exit.
Oh, I guess it is here.
Direct REPL support for help, exit, and quit.
And thank you.
Thank you.
Whoever worked on this.
Because it used to say, oh, did you mean to exit out?
You have to type exit with the parans or quit with the parans.
And if you know what I want to do, just do it.
So, you know what it does.
It's really cool.
I can imagine somebody was like, well, what if we have a variable named exit and you want
to see its value?
But if there's no variable defined, just quit.
I love it.
So, exit and quit now work.
I didn't know quit worked.
That's neat.
So, the other couple things in interactive, there's a lot of stuff in the interactive REPL
that's changed.
Multi-line editing, amazing.
So, you type in a multi-line thing and you get the three dots, which is great.
But when you want to go and type something wrong and you want to go change that, now you
can go back and you can just hit the up arrow and it works.
It's great.
So, I'm really enjoying that.
There's F1 for command history.
History is, we've had history before, but now if you exit and then start the REPL again,
history is still there.
It preserves all of your history from the session.
Oh, that's nice.
Super nice for when you're debugging something, trying it out.
And the colors are amazing.
So, they've turned on colors by default.
So, in prompts and tracebacks.
So, even just having the little prompt be in a color, it's nice.
It helps.
So, love that.
We've also got improved error messages.
Like, before, if you named, like, random is built in, one of the built-in things.
But if you named a module named random, it would just mess up.
And it would, like, it would say stuff like, you know, module random has no attribute.
But now it says, hey, you've already considered renaming your own module something else because you're messing up.
So, if you rename them.
If you name a module or a script, the same thing as a built-in or now as one of your installed third-party libraries, Python will tell you that you've messed up, which is nice.
There's other improvements, too.
Like, if you misspell a keyword argument, it will suggest that maybe you had the correct spelling.
It will suggest that.
That's pretty cool.
And then, of course, there's lots of changes in 3.13.
But the REPL, I'm excited about.
I'm also excited about the error messages and free-threaded Python.
So, there's a lot of other stuff, too.
So, check out the What's New.
But I really am looking forward to playing with the free-threading.
Yeah, this is amazing.
I'm really excited to see this here.
I actually can't believe that free-threaded Python is a thing.
I know.
It's like.
It's been so long.
The journey's been so long.
I mean, I was walking this morning and I saw a pig flying through the sky.
It had imported free-threaded Python, rather than imported anti-gravity.
That's what it did.
Yes.
Yeah.
So, I know that a lot of people have worked a lot, long and hard, to make that work.
So, I'm looking forward to it.
Now, free-threading is still officially experimental.
So, I don't know what that means.
If they're going to take it back from.
Please don't take it away from us.
But we'll see.
Yeah.
The original PEP that got it accepted, 703 or something like that, said,
we are allowing this in.
But if it causes too much trouble, we're taking it back out.
Which I've never seen in a PEP.
Maybe it's happened before.
But we approve it.
But we might unapprove it.
Might unapprove it.
We'll turn this car around.
If you keep fighting, we'll turn it around.
Yeah.
That's right.
Don't make me turn this car.
Don't make me pull over.
Speaking of pulling over, this was supposed to be out a week ago, Brian.
Yeah.
And apparently, it was pushed back due to performance issues or some kind of issue with the incremental GC.
Right.
And I'll put the Python, the discuss.python.org link in my extras.
But I'm not going to cover it separately.
But it's kind of irrelevant.
Things are out now.
But yeah.
Very cool.
All right.
Well, what do you got for us next, Python?
Michael?
Well, let's stick with some core language topics and stuff like that.
I want to talk about PyPI bandwidth and PEP 759 external wheel hosting.
So right now, when you pip install, UV pip install, whatever, you go to get something and you,
as a publisher of a package like Flask, you send that to pypi.org, maybe as a wheel, maybe
as a multi-platform variations of different wheels, if it's got to compile differently or
something.
And then people pip install that and it downloads from there.
That results in an insane amount of traffic.
I actually want to talk a little bit more about that later in general.
But it's an insane amount of traffic.
Over 66 petabytes a month, which is six-figure level of bandwidth costs.
And luckily, Fastly, the CDN company, is basically donating all that bandwidth at reasonably high
expense for them.
Probably not the same as retail, but whatever wholesale that is in bandwidth, I'm sure it's
still a lot.
And they announced a five-year plan or five-year commitment to the PSF to do that at PyCon.
All right.
They're on the big keynote stage.
That was nice.
Thank you, Fastly.
However, there's still problems with this, even though they're covering it.
What if Fastly changes their mind eventually?
But more importantly, there's hard limits on how large your project's overall usage on
pypi.org can be.
It gets no individual package can be bigger than 100 megs.
You can't have 10 gigs total across all platforms, across all releases, things like that, right?
You can't apply for exceptions, but it's not great.
What if you could just say, here's my wheel, but when you actually download it, download it
from over there.
Download it off of Microsoft.com if it's a Microsoft package.
Or download it off of explosion.ai if it's some sort of spacey package.
Those things have to be quite large.
A lot of their models that you pip install.
I think they have to get an exception to be even uploaded in the first place.
All right.
So that's what this is about.
It's by Barry Warsaw.
Ethan Smith.
Delegate is Donald Stufft, who is a person largely behind the rewrite of pypi.org.
So here's the deal.
Brian, if you had a wheel, which is the metadata about a package and all of its binary details
and its source code and all that, and you ripped off a lot of the wheel stuff, like the binary
bits, what would you be left with?
I don't know.
A rim.
A wheel rim, you know?
Oh.
So this PEP literally defines a new package format called a rim file.
And the rim file is basically the wheel without the binary.
Instead, it's got a URL to where the binary lives.
And a checksum of the binary, which may already be there anyway, but it's left in the rim file,
if not added to it.
Okay.
Interesting.
So basically, you upload just the metadata if you want to participate in this.
And then you point somewhere else.
And there's a lot of motivation, things they tried, things that didn't work, limits.
You can see in this pep, they list the limits that I talked about.
And all the details, but most importantly, there's a security section way down here.
I was worried about that.
So, yeah.
Yes.
Here.
As well as stability constraints.
But so for example, the wheel checksum must be included in rim files.
Once it's uploaded, just like current wheels, it can't change.
Yeah.
So here's my metadata.
That's where the thing lives.
Here's the hash of it.
So it can't be tampered with.
It must be served over HTTPS.
Okay.
And you're only allowed to do this if you get pre-approved by the PyPI admin.
So it's not just all sorts of chaos.
People just upload and stuff everywhere.
All right.
But a lot of consideration about like malware and things like that.
And also a bunch of stuff about stability.
Like external wheels must be hosted over SSL.
And not just that, but it actually must be signed by Mozilla's root certificate store, which
is interesting.
And they should use CDNs.
They must be stable, et cetera.
What do you think?
So who would do this?
I mean, because then the person with the package doing this, they'd have to pay the hosting fees.
Or get it on GitHub and point to it as a raw or something, you know?
Oh, yeah.
Something like that.
I don't know.
Oh, okay.
Or if you're a big company and you want to ship ML models and you'd rather have more control
over that and how it works, right?
You could set that.
I don't think small individuals are going to be like, hey, I'd love to cover a terabyte
of bandwidth charges a month for no reason.
Yeah.
Right.
Well, also, like you said, it's somebody that's got a, it's going to be a large one.
You're not going to do this for just a little Python only package.
Yeah, exactly.
It's very unlikely.
Right.
It's very unlikely.
So they said this is only about hosting the binary downloads, not packages, package indexes,
package listings, none of that stuff.
Because that's already supported through having just a separate private white label.
You run it yourself.
PyPI, mirror, something like that, right?
Yeah.
I think this is cool, actually.
Neat.
Yeah.
Flexibility is good.
I think it's, I think it's all right.
So anyway, very cool.
That's, that's what I wanted to cover.
And before we move on, how about a quick shout out to our sponsor?
Yep.
Let me tell you real quick about Scout APM.
They're big supporters of Python Bytes.
So we appreciate that very much.
So if you are tired of spending hours trying to find the root cause of issues impacting your performance,
then you owe it to yourself to check out Scout APM.
They're a leading Python application performance monitoring tool, APM, that helps you identify and solve performance abnormalities faster and easier.
Scout APM ties bottlenecks such as memory leaks, slow database queries, background jobs, and the dreaded N plus one queries that you can end up if you do lazy loading in your ORM.
And then you say, oh no, why is it so slow?
Why are you doing 200 database queries for what should be one?
So you can find out things like that.
And it links it back directly to source code so you can spend less time in the debugger and healing logs and just finding the problems and moving on.
And you'll love it because it's built for developers by developers.
It makes it easy to get set up.
Seriously, you can do it in less than four minutes.
So that's awesome.
And the best part is the pricing is straightforward.
You only pay for the data that you use with no hidden overage fees or per seat pricing.
And I just learned this, Brian.
They also have, they provide the pro version for free to all open source projects.
So if you're an open source maintainer and you want to have Scout APM for that project, just shoot them a message or something on their pricing page about that.
So you can start your free trial and get instant insights today.
Visit pythonbytes.fm/scout.
The link is in your podcast player show notes as well.
And please use that link.
Don't just search for them because otherwise they don't think you came from us.
And then they'd stop supporting the show.
So please use our link pythonbytes.fm/scout.
Check them out.
How about the next one for you?
I feel like, just give people a little heads up.
We've got some, that's a pie test coming up here.
What do we got?
If you didn't know it, Python 3.13 is out.
So we already covered this.
However, it's got the free threading thing going on.
How do you know if your project supports it?
So that's the question that Anthony Shaw and others at, where was this at again?
Was that PyCon JP?
I think that's PyCon Japan.
Is that right?
I think so.
Okay.
So it was one of their sprints.
Looks like seven or eight people, Anthony, Mike, a bunch of people worked on this.
And the idea is that you'd like to be able to test that your project and your code works on the free threaded, right?
So if you're like, especially support libraries and packages.
So what, how do you do that?
And one of the thoughts was to just test, just run it.
But with the free threading turned on.
But pytest normally runs in single thread mode by default.
So how about XTest?
Because that's multiprocessing, right?
Yes, it's multiprocessing.
It's not multithreading.
So Anthony and others made this plugin.
It's called pytest-FreeThreaded.
And link in the show notes, of course.
But they made the plugin to be able to run the tests in a thread pool with the guild disabled and help identify that your tests are thread safe.
So, you know, as long as your tests possibly are testing your code in such a way to test that, great.
But at least your tests will be free thread safe compatible.
Anyway, they tested the first library that was marked as compatible with free threading.
I don't know how to do that.
So I guess that's a to-do item to look that up.
Okay.
So you think it might go in the classifiers of the package metadata?
I'm not sure.
Oh, okay.
All right.
Well, we'll take a look at that.
Anyway, they tested one and it caused a segfault in CPython.
So not really compatible if you're segfaulting.
So I haven't tried this out yet, but I'm going to try it on a few projects anyway.
So Python free threaded will help test this.
Well, I think this is awesome.
And some people might perceive this like, oh, it just means a performance boost.
But if you're writing code that's meant to be supported for free threaded Python, you should test it in that style as well.
Not just in some limited way, right?
Yeah.
And even if your tests pass, I think it would make sense to look at the different parts of your library to make sure that it really makes sense that your tests are actually testing your library in such a way that you have fairly good confidence.
But, you know, mileage may vary.
But this is a good step in the right direction.
So thanks to Anthony and others for doing this.
Yeah, that's awesome.
Speaking of Anthony, I was not going to point this out, but now that you mentioned it, just published an episode on Talk Python with him designing effective load tests for your Python app.
Nice.
Yeah, that's a really fun one.
So people can check that out.
But what I'm actually talking about for this section is more pytests.
Ryan, how did you not get this one?
pytest edit.
Do you know this?
No.
Okay, so here's the deal.
You're on the terminal CLI sitting there running something and you run into an error and you're like, ah.
My test crashed or my test failed rather.
I just want to see what's up.
So one way to do that is to see what test failed.
Go open your editor, find your project, load it up, search around until you find it.
Or the other way is to install pytest-edit from Mr. Minnow.
That's the GitHub name.
And then just type pytest-edit and it'll open a pre-configured editor to the line of the failing test.
Oh, wow.
Yeah, so you can say pytest-edit and it'll show you the last one.
Or you can say some index.
So for example, you can say edit equals two.
And it'll open the third failing test because, of course, it's zero-based.
Or negative two will open the second to the last one.
So you can kind of hone in on it with this number here.
And then you just set up your editor.
If you don't set it up, you get VI or Vim or even Windows.
On Windows, you get notepad.
So I recommend picking a better editor.
But anyway, you just set an environment variable to what you want your editor to be.
And I got a ton of extras to cover, so I don't want to go too deep on this one.
But there it is.
Neat.
Speaking of extras, what do you got for us?
Any?
I've got zero extras this week.
I must have stolen them all.
Look at my tabs.
All right.
Well, let's just jump into the extras then.
Extra, extra.
So I got a bunch here, but they're all pretty quick.
Last week, you spoke about Jade, D-J-A-D-E, for formatting Django templates, right?
Kind of like black or rough, but instead of being for Python, it's for Django templates and
HTML and so on, which is awesome.
So I'm linking to something from Adam Chains, Django pre-commit hook.
Or sorry, Jade pre-commit hook.
So if you want this to just happen automatically, there you go.
Super easy, right?
Cool.
Yes.
This one is really fun.
And remember I talked about Polyfill, Polyfill.js and somebody took over the domain.
I don't remember.
It was, I think it was sold even, but if it wasn't sold, it was taken over because it lapsed
or whatever.
However, it got into some nefarious hands and they took over polyfill.io, boot CDN, boot
CSS, static file.
And they had basically rewritten a whole bunch of CDN served JavaScript to hundreds of thousands
of websites with malware that would then go on to the visitors of those websites.
It's bad.
The only reason I'm bringing this is a quick follow-up.
How do they know?
That person had published, they accidentally published their Cloudflare secret keys.
And so then the security researchers will, you know, they basically logged into Cloudflare
and just looked at their cloud setup, which I think this is awesome.
Yeah.
And then, yeah, funny thing out in the audience.
We'll share that in a second.
All right.
This one is also really cool.
Over at pythonbytes.fm, created that site seven years ago.
How long have we been there?
Eight years?
Well, when I created it, I created it with Bootstrap, okay?
Because Bootstrap was probably the nicest way at that time to get a good looking site that's
consistent, responsive, all those things up in Atom, right?
Well, if you look at the Bootstrap CSS file, it's about 140 kilobytes, which is a lot to
just be serving as one of your static resources on every web request, right?
But it's pretty gnarly.
You don't want to mess with it, right?
Like, what are you using?
I don't know.
And what's the knock-on effect?
So I ran across this thing called Purge CSS, which is a Node.js CLI tool, but it doesn't
really matter how it's implemented, right?
It's just a CLI tool.
And you can run this thing against your CSS file, and you can say, hey, this CSS file,
I would like you to look at all the styles that I'm using, look at the CSS file, and if
there's any styles in there I'm not using, take them out of the CSS file.
Oh, wow.
Yeah.
So, and it doesn't have to work on just HTML.
I pointed at chameleon templates, or it could be Jinja templates, or we just talked about
Django templates.
You just give it a, like a star, star, slash, star, whatever your template extension is,
like .j, or if it was Jinja, or whatever.
And then it'll go through and look at all of those that are being used, and then it'll
rip them out, rip out all the stuff that wasn't.
So now, for example, if you go to pythonbytes.org, and you click on the CSS file, it's like 20k,
25k, something like that.
So it's six, seven times smaller, and all I had to do is run a command line thing against
it.
So maybe you're not using enough bootstrap.
I feel like that's still 20kb of bootstrap.
That's a lot of bootstrap.
I love your attitude, but there we go.
Last week, on the first go-round of 3.13 release, there's also Python 3.12.7 released.
So just so you know, if you're not ready for 3.13, there's also a new version of 3.12.
I want to give a quick shout-out to a video by Hynek.
It says, UV is the future of Python packaging.
Snake box emojis.
Anyway, this is a really good video.
Hynek is getting his YouTube game on quite well, and he's fun to watch.
So check that out.
I'll link that as well.
And I still got some more.
We're just tabs bumping around.
Chris over on Faucet On pointed out, hey, love all this UV talk, grouping these together
on 4.3 and others and so on.
It's interesting to be seeing it show up just broadly now.
And things like Home Assistant is now using it to reduce download and setup times.
Oh, yeah.
Cool.
Yeah, kind of cool.
Over here, Brian, do you think people are getting tired of LLMs and hearing about AI tools?
Yes.
I feel like there's a lot of AI fatigue out there.
I'm like, ah, but is that just me projecting this onto people?
Is this real?
So I posted on Faucet On and on Twitter and said, hey, just thinking about topics, how
do you guys feel about LLM topics and spending time talking about them?
Only 4% said, more LLMs, please.
22% said, ah, they're fine.
38% said, I've had enough.
And 36% fully said, if you say AI one more time, I will pile drive you.
Well, you just said it like four times.
Oh, no.
It's going to hurt so much, but I had to say it.
But that's 74% of people saying, oh, man, I've had enough.
Yeah.
So anyway.
One of the things that would have been funny is if you'd have added, do you want us to start
talking about blockchain again instead?
Oh, my gosh.
Yes.
That would definitely do it.
All right.
A couple real quick ones here.
JetBrains and the PSF have now released or opened up the Python developer survey 2024.
So check that out.
I'll link to how you can go and take it.
But yeah, everyone participate.
This is super important.
We really value all the information that we get in the spring or whenever we get the answers,
the responses and the write up.
But it's time to submit your notes.
Okay.
A couple real quick things.
I added a really cool way to explore courses over at Talk Python.
So there's a big tag cloud up at the top here.
And we get all the courses.
But now if you just click around, like if you want to find stuff about test, right, I just
click on testing and it'll show like your test course.
And this thing is super neat.
This is all implemented with HTMX.
All dynamic.
No page refreshes, but no JavaScript.
Love it.
Cool.
Anyway, go check that out.
And very last extra, extra, extra.
I wrote an article that says, let's go easy on PyPI, okay?
And I got some nice feedback from people on Updated.
But basically, it talks about a bunch of different steps that you can take to not keep that number
at 66 petabytes a month hitting PyPI.org, right?
Yeah.
I don't know how you feel, but my assessment is fully 75% or more of that has to be Docker
builds, continuous integration, all that crap, right?
It just, it has to be so over the top, just like machines talking to machines like, hey,
here's a requirements file with 200 things in it.
We're going to build a Docker container on it.
So let's start with this base one, like the Python one or whichever one, it doesn't really
matter and just build from it.
Every single time you want any kind of code change published or tested, it's going to download
all 200 over and over, right?
Yeah.
And then you're testing it against multiple versions of Python.
So it downloads it that many more times.
That's a really good point.
Yeah.
So this article talks you through different steps you can take to cache it over and over
faster and faster.
So basically, almost, unless a requirement changes, it will not ever, ever touch PyPI.org.
Ever.
Right?
So it starts out just saying, oh yeah, you just pip install your requirements.
What's wrong with that?
You know, every code change causes a download.
And then maybe you could run the requirements, copy just the requirements file over and run
it first and then do it.
That way, only if a requirement changes, does it get them all?
And then you could pre-list some of your top level requirements.
That would cache it in the Docker image.
And then after a lot of conversations with a lot of people, there's this mount command
that you can say for cache on a per command basis.
And this will cache the output to somewhere on the machine that does the building of the
Docker container.
So it'll cache either the UV or the pip cache.
So that way, if you get it again, it'll just go using cached version, even if it's a completely
fresh image, long as the machine has seen that download before, right?
That dependency.
And then finally, if you're on probably one of the biggest offenders in the sense of CI
on GitHub, over at GitHub, they actually have this thing called, maybe you know it, this
thing called a cache action or actions slash cache.
And you can set up a cache for your CI so that subsequent CI builds don't download and install
it again as well.
This will not just make it lighter on PyPI, but also every one of these things makes it faster
for you.
So it's like incentives are aligned.
Do you know what I mean?
Yeah.
That's pretty cool.
It's almost too bad that like GitHub itself can't notice that like multiple packages or
multiple builds on different projects are using the same version of something and caches.
Right.
Just have a universal pip cache or something like that.
One of my questions is, and I don't know if you know the answer to this, is I know that
UV does a lot of caching.
Will just using UV help with reducing hitting PyPI?
That's an interesting question.
I don't know if it'll make it less traffic.
It'll definitely make it faster.
There's no doubt about that.
But it might be the same traffic.
Okay.
Yeah.
Cool.
All right.
Henry says, set up dash UV has a cache option.
Excellent.
That's awesome to hear.
All right.
And then Jay Miller dropped in to say that he assumed he wouldn't be able to find this episode.
But like us, he eventually found his way.
And also, Tony out in the audience says, I was literally working on caching in CI while listening.
UV does support caching in CI too.
Yeah.
And by the way, if you're checking out these notes on the GitHub CI stuff down here for
the pip example, somewhere, pip, are you here?
If you just say this patch of .cache slash pip, if you just change that to .cache slash UV,
I'm pretty sure everything else will just flow from there.
So awesome.
Nice.
Indeed.
All right.
Let's be ready for a joke.
Well, I was hoping you didn't have a lost the joke.
So let's see if I can find it.
Let's see what I can find.
All right.
So, you know, when you go to a page, that's bad.
Like if you go to Python bytes slash blah, blah, blah, and it's not there, should it just
say 404?
No, you should have something amusing and interesting.
Like for us, we have a big empty microphone in a stage with nobody at the microphone that
just says 404.
Try our episodes listing instead.
And you can click on it and it takes you to our episodes, right?
That's all fun.
So my joke, which I think I'll just let people link to, but maybe we can find one or two just
give people a sense, is 28 clever and funny 404 pages.
So I love this.
These are so good.
It almost makes me want to like mess up a website just to see what they've got, right?
Like one of them is for a blue path.
I don't know what that is, but there's a big map with tons of little dots of like, here's
all the distribution of where people live around the city or things happening.
It says, this is everyone else.
And then like way over somewhere else, it has a little dot says, this is you way off
the map.
Please go find.
Some of them are not that great, but some of them are real good.
So anyway, if this kind of stuff amuses you, Pixar has one with a crying inside out person.
It's sad emotion.
Yeah.
Yeah, exactly.
Exactly.
Others are just weird.
One has a bear wearing like a gold 404 baller type.
Anyway, check it out.
Lego has a unassembled disconnected sort of thing.
So I thought that would be pretty good for our episode 404.
People can scroll through that and enjoy it.
Yeah.
And also, I love watching the, looking at these.
So if anybody has a, has some good 404 pages that they, that they want to share with us,
head on over to Mastodon and, or our show notes page and send us, send us a link to your favorite
404.
That'd be fun.
Yeah.
Awesome.
All right, guys.
Thank you.
Thank you everyone for listening.
Brian.
Thanks for being here as always.
Thanks.