WEBVTT

00:00:00.001 --> 00:00:04.900
Hello and welcome to Python Bytes, where we deliver Python news and headlines directly to your earbuds.

00:00:04.900 --> 00:00:10.140
This is 394, recorded July 30th, 2024.

00:00:10.140 --> 00:00:11.440
I am Michael Kennedy.

00:00:11.440 --> 00:00:12.620
And I'm Brian Okken.

00:00:12.620 --> 00:00:16.140
And this episode is brought to you by Scout APM.

00:00:16.140 --> 00:00:18.340
Thank you, Scout APM, for sponsoring the show.

00:00:18.340 --> 00:00:20.200
We will tell you more about them later.

00:00:20.200 --> 00:00:26.060
If you want to connect with us on the socials, the best but not the only place is over on Mastodon,

00:00:26.060 --> 00:00:32.840
where all the links, me, Brian, and the show, all have our accounts list at the top of the page of the show notes.

00:00:32.840 --> 00:00:35.480
You'll see in your podcast player or the website.

00:00:35.480 --> 00:00:42.020
Also, if you're not joining us live and you would like to, we record Tuesdays at 10 a.m. Pacific time.

00:00:42.020 --> 00:00:43.760
Check that out, pythonbytes.fm.com.

00:00:43.760 --> 00:00:48.160
You'll see all the older versions under the live section on our YouTube channel there.

00:00:48.160 --> 00:00:54.080
And finally, you probably do want to also get a summary of this episode in your email.

00:00:54.080 --> 00:00:55.080
I'm sure you do.

00:00:55.080 --> 00:00:59.580
A handcrafted, artisanal Brian Okken special email.

00:00:59.580 --> 00:01:01.440
So just visit pythonbytes.fm.

00:01:01.440 --> 00:01:02.220
Click on newsletter.

00:01:02.220 --> 00:01:03.340
Enter your information.

00:01:03.340 --> 00:01:05.240
We won't give it away.

00:01:05.240 --> 00:01:06.400
Share with other people.

00:01:06.400 --> 00:01:07.100
Resell it.

00:01:07.100 --> 00:01:07.780
Retarget you.

00:01:07.780 --> 00:01:08.360
Do evil things.

00:01:08.360 --> 00:01:12.220
We just will communicate with you about stuff we're up to, mostly the show.

00:01:12.220 --> 00:01:13.680
Brian, I learned Python.

00:01:13.680 --> 00:01:14.400
It was a good weekend.

00:01:14.400 --> 00:01:15.460
Is that the same?

00:01:15.460 --> 00:01:18.060
Is that what you're telling me for your first item here?

00:01:18.060 --> 00:01:19.140
Oh, okay.

00:01:19.140 --> 00:01:20.880
Look, where are you going with this, Michael?

00:01:20.880 --> 00:01:22.960
Michael, I think you've known it for a while.

00:01:22.960 --> 00:01:26.860
No, I bundled the joke a little bit, but yes.

00:01:26.860 --> 00:01:27.440
That's all right.

00:01:27.440 --> 00:01:29.080
I thought Python is easy, I hear.

00:01:29.080 --> 00:01:32.500
Yeah, Python is easy now, apparently.

00:01:32.500 --> 00:01:34.460
No, I love Python.

00:01:34.460 --> 00:01:39.620
Anyway, what I wanted to talk about was beyond hypermodern or postmodern.

00:01:39.620 --> 00:01:41.440
I'm not sure what the tagline is, really.

00:01:41.800 --> 00:01:45.120
So this is an article by Chris Ardern.

00:01:45.120 --> 00:01:45.840
Chris?

00:01:45.840 --> 00:01:46.740
Sorry about it.

00:01:46.740 --> 00:01:48.040
I probably mangled your last name.

00:01:48.040 --> 00:01:50.340
But I really like the article, Chris.

00:01:50.340 --> 00:01:51.760
So what is this?

00:01:51.760 --> 00:01:57.820
So the title is Beyond Hypermodern, Python is Easy Now.

00:01:58.020 --> 00:02:04.820
And this is a reference to hypermodern Python that was, he says it came out like, as a series

00:02:04.820 --> 00:02:07.280
that came out four years ago or something.

00:02:07.280 --> 00:02:08.580
Interesting.

00:02:08.580 --> 00:02:13.620
But it's, what was, who was the hypermodern person again?

00:02:13.620 --> 00:02:14.260
Can't remember.

00:02:14.260 --> 00:02:17.180
Oh, I should have looked this up anyway.

00:02:17.180 --> 00:02:22.860
Claude, Claudia, Claudio, Claudio, oh, I'm not going to try.

00:02:22.860 --> 00:02:27.600
Claudio's book, Hypermodern Python Tooling, is now as a book, which is cool.

00:02:27.600 --> 00:02:28.520
Good job.

00:02:28.520 --> 00:02:29.580
But that's not what we're talking about.

00:02:29.580 --> 00:02:34.840
We're talking about beyond hypermodern or from the URL postmodern.

00:02:34.840 --> 00:02:35.760
So what is this?

00:02:35.760 --> 00:02:40.320
Basically, it's talking about all the tooling and it's all in Rai now.

00:02:40.320 --> 00:02:44.820
So this is what Chris's idea is, is you could do so much in Rai.

00:02:44.820 --> 00:02:52.980
And actually, I knew Rai did a lot, but Rai actually does more than I thought you could.

00:02:52.980 --> 00:02:57.580
So Rai is a tool that's like kind of does a lot of stuff around Python.

00:02:57.580 --> 00:02:59.360
So there's setup.

00:02:59.360 --> 00:03:03.880
It goes through setup, linting, typing, testing, documentation, CI/CD.

00:03:03.880 --> 00:03:06.000
And then there's a bonus section on monorepo.

00:03:06.000 --> 00:03:12.280
But I really liked just walking through, like if you wanted to try out Rai, all the different,

00:03:12.280 --> 00:03:16.320
like the workflow, going through the entire workflow of building a Python project.

00:03:16.320 --> 00:03:24.260
Like the setup part is setting up an initial directory, including setting up your pyproject.toml

00:03:24.260 --> 00:03:29.440
and setting up some different directories, which is great.

00:03:29.440 --> 00:03:31.160
Just sets up the structure for you.

00:03:31.160 --> 00:03:36.600
There's a lot of files here that like I don't often, to tell you the truth, I don't use lock

00:03:36.600 --> 00:03:37.240
files a lot.

00:03:37.240 --> 00:03:44.340
Partly because I'm using, I'm often developing Python modules or packages, which I don't really

00:03:44.340 --> 00:03:44.940
lock stuff.

00:03:44.940 --> 00:03:48.400
Locking is more regularly around applications.

00:03:48.400 --> 00:03:52.560
So do you have lock files for some of your application stuff, Michael?

00:03:52.560 --> 00:03:53.520
All of them.

00:03:53.520 --> 00:03:54.020
All of them.

00:03:54.020 --> 00:03:56.220
I use the pip compile workflow.

00:03:56.220 --> 00:03:56.720
Okay.

00:03:56.720 --> 00:04:00.880
So I've got like one thing that specifies the top level requirements and then another one

00:04:00.880 --> 00:04:04.700
that is the lock file using a uv hip compile.

00:04:04.700 --> 00:04:05.300
Okay.

00:04:05.300 --> 00:04:11.220
One of the things that I didn't think about was like requirements for the requirements dash

00:04:11.220 --> 00:04:12.100
dev lock.

00:04:12.100 --> 00:04:18.720
So instead of requirements on text, these are the dependencies are in your pyproject.toml,

00:04:18.720 --> 00:04:20.760
but there are a lot of requirements lock files.

00:04:20.760 --> 00:04:28.060
But a dev lock file, that I might actually have even for a package to make sure all the developers

00:04:28.060 --> 00:04:29.080
are using the same thing.

00:04:29.080 --> 00:04:30.080
So that's kind of interesting.

00:04:30.540 --> 00:04:31.160
It makes a lot of sense.

00:04:31.160 --> 00:04:33.660
I was just had, when did I publish it?

00:04:33.660 --> 00:04:35.520
This, was that this week's episode?

00:04:35.520 --> 00:04:36.140
I can't remember.

00:04:36.140 --> 00:04:37.320
Very, very, very recently.

00:04:37.320 --> 00:04:41.320
David Lord from Flask on Talk Python.

00:04:41.320 --> 00:04:41.900
Yeah.

00:04:42.180 --> 00:04:47.780
And one of the things they're working on is creating a more repeatable environment for contributors

00:04:47.780 --> 00:04:49.100
and developers to Flask.

00:04:49.100 --> 00:04:53.320
So like you Flask, you don't want to just pin the versions of everything because that wrecks

00:04:53.320 --> 00:04:55.500
everybody else's options to work with different versions.

00:04:55.500 --> 00:05:00.200
But you do want to make sure that people who do PRs have the same setup as people who are

00:05:00.200 --> 00:05:01.220
reviewing the PRs.

00:05:01.300 --> 00:05:08.720
So he talked a lot about having a hind requirements for developers of the project, but not the

00:05:08.720 --> 00:05:09.380
project itself.

00:05:09.380 --> 00:05:09.780
Yeah.

00:05:09.780 --> 00:05:10.640
That's a cool idea.

00:05:11.640 --> 00:05:13.200
So that's set up.

00:05:13.200 --> 00:05:15.540
There's, you can do linting with it.

00:05:15.540 --> 00:05:18.020
The testing section talks about pytest.

00:05:18.020 --> 00:05:18.300
Yay.

00:05:18.720 --> 00:05:23.520
But the, one of the things that I thought was kind of neat was this, and I think I knew

00:05:23.520 --> 00:05:25.520
this, but anyway, this idea of scripts.

00:05:25.520 --> 00:05:29.460
So within your PyProject Tomo, you can set up Rai scripts.

00:05:29.460 --> 00:05:37.300
So they're basically extra commands that do things like, so you can say like Rai run test.

00:05:37.300 --> 00:05:39.840
And so the run command runs your script.

00:05:39.840 --> 00:05:46.260
So you can say run in a test is a thing that you've said that just like defaults to Rai test.

00:05:46.260 --> 00:05:54.040
But things like Rai run check might be running Pyright or for linting or for type checking

00:05:54.040 --> 00:05:58.340
or linting is a Rai lint with a fix or something.

00:05:58.340 --> 00:06:03.540
So all these different, if you, if you've, especially if you've got other people on the team, having

00:06:03.540 --> 00:06:06.260
some way to do all of this is good.

00:06:06.260 --> 00:06:12.940
And then a kind of a neat thing that I, that's probably as nice as being able to chain scripts.

00:06:12.940 --> 00:06:18.720
So if you've got like running your form auto formatting and linting and their type checking and

00:06:18.720 --> 00:06:19.760
also running your tests.

00:06:19.760 --> 00:06:25.320
But then if you want to do all of them, there's a way to just chain them up within the PyProject

00:06:25.320 --> 00:06:26.980
Tomo's, which is kind of cool.

00:06:26.980 --> 00:06:28.000
Yeah, that's very cool.

00:06:28.000 --> 00:06:32.180
It's kind of takes the place of where I would use either where I used to use make files.

00:06:32.180 --> 00:06:35.560
Now I use talks commands for.

00:06:36.100 --> 00:06:41.820
But so a lot of this around if you don't need it, I'm guessing this doesn't create a

00:06:41.820 --> 00:06:43.660
new virtual environment, but I haven't played with it yet.

00:06:43.660 --> 00:06:46.860
But that's where talks would do that.

00:06:48.560 --> 00:06:50.960
So there's a discussion around documentation.

00:06:50.960 --> 00:06:54.580
It isn't really a Rai thing, but just talking about documenting things well.

00:06:54.580 --> 00:06:58.860
But I really kind of like this article about like, if you want to try out mostly because

00:06:58.860 --> 00:07:03.160
I do want to try out Rai and this kind of walks through all the different things it does within

00:07:03.160 --> 00:07:05.460
your workflow and where you might want to pull it in.

00:07:05.460 --> 00:07:09.380
And I do, I do appreciate that Rai has some configuration.

00:07:09.380 --> 00:07:19.340
So apparently the default packaging tool is hatch, but this person, Chris, wanted to use PDM.

00:07:19.340 --> 00:07:24.080
So you can set that, but I'd probably leave it as hatch because I like hatch, but might do

00:07:24.080 --> 00:07:24.740
something different.

00:07:24.740 --> 00:07:28.720
But you can even set a dependency operator.

00:07:28.720 --> 00:07:34.380
So whether you want it to be like approximately equal to or greater than equal or whatever, kind

00:07:34.380 --> 00:07:34.720
of neat.

00:07:34.720 --> 00:07:37.620
The bonus is really kind of fun.

00:07:37.620 --> 00:07:46.440
I actually just ran into a project where I have to help support, which is a large repository

00:07:46.440 --> 00:07:48.300
with multiple Python projects in it.

00:07:48.300 --> 00:07:56.220
And so I'm looking forward to reading through how possibly this documentation around dealing

00:07:56.220 --> 00:07:57.620
with monorepos in Python.

00:07:57.620 --> 00:08:01.180
This is on my to-do route, to read next list.

00:08:01.180 --> 00:08:02.140
That's cool.

00:08:02.140 --> 00:08:03.380
That's next level stuff right there.

00:08:03.380 --> 00:08:05.260
Yeah.

00:08:05.260 --> 00:08:06.760
Well, very, very cool.

00:08:06.760 --> 00:08:12.660
Well, I, Brian, am happy to report, I think, that the GIL has been vanquished.

00:08:12.660 --> 00:08:13.440
But-

00:08:13.440 --> 00:08:16.940
We are now in the epoch of free-threaded Python.

00:08:16.940 --> 00:08:22.160
So how might you test this out and see if it's actually worth it and so on.

00:08:22.160 --> 00:08:22.580
Okay.

00:08:22.580 --> 00:08:28.800
So Simon Willison, one of his Today I Learned, is trying out free-threaded Python on macOS.

00:08:28.800 --> 00:08:30.120
Could be others as well.

00:08:30.440 --> 00:08:32.800
But you can just go to, this is interesting.

00:08:32.800 --> 00:08:36.380
I didn't realize that you would be able to get free-threaded Python this way from the PEP.

00:08:36.380 --> 00:08:38.780
It's like, you've got to get a special build of it.

00:08:38.780 --> 00:08:41.060
And it's just like its own thing.

00:08:41.060 --> 00:08:41.360
Right?

00:08:41.360 --> 00:08:41.840
Yeah.

00:08:42.040 --> 00:08:46.180
But if you get the macOS installer, I don't know about the others, but presumably the Windows

00:08:46.180 --> 00:08:48.220
one has something similar or will.

00:08:48.220 --> 00:08:48.740
I don't know.

00:08:48.740 --> 00:08:49.920
Go to install this.

00:08:49.920 --> 00:08:52.360
You can set up the options, custom install.

00:08:52.360 --> 00:08:59.220
And you can just check off a checkbox to install a separate binary for free-threaded Python 313

00:08:59.220 --> 00:09:01.180
instead of guild Python.

00:09:01.380 --> 00:09:01.680
Wow.

00:09:01.680 --> 00:09:04.060
And that's just from the python.org download.

00:09:04.060 --> 00:09:05.020
Yeah, exactly.

00:09:05.020 --> 00:09:05.660
Wow.

00:09:05.660 --> 00:09:06.340
Exactly.

00:09:06.340 --> 00:09:06.680
Yeah.

00:09:06.680 --> 00:09:08.960
Just to get that downloads beta 3 of it.

00:09:08.960 --> 00:09:09.880
And there it is.

00:09:09.880 --> 00:09:12.440
So you just hit customize your install and boom.

00:09:12.440 --> 00:09:14.200
So that alone is kind of interesting.

00:09:14.200 --> 00:09:14.840
Yeah.

00:09:15.040 --> 00:09:22.300
And then once you do that, you get not just a Python 3.13, but a Python 3.13 T.

00:09:22.300 --> 00:09:24.520
It's interesting.

00:09:24.520 --> 00:09:25.940
But not FT.

00:09:25.940 --> 00:09:28.260
I mean, the other one should have a T on it.

00:09:28.260 --> 00:09:28.520
Come on.

00:09:28.520 --> 00:09:29.300
If it's going to be threaded.

00:09:29.300 --> 00:09:30.060
I don't know.

00:09:30.060 --> 00:09:31.400
Anyway, T, whatever.

00:09:31.400 --> 00:09:35.680
You get one that is like, that's the one you can run in the command line for free-threaded

00:09:35.680 --> 00:09:35.920
Python.

00:09:35.920 --> 00:09:39.400
And Simon points out, like, didn't really put this in the path because it's beta.

00:09:39.400 --> 00:09:40.740
I don't want to mess stuff up.

00:09:40.740 --> 00:09:42.900
But nonetheless, there it is.

00:09:42.900 --> 00:09:44.300
So let's test it out.

00:09:44.300 --> 00:09:48.720
It comes up with a simple little program that just does some CPU bound thing.

00:09:48.720 --> 00:09:49.720
This is the important thing.

00:09:49.720 --> 00:09:56.900
We've, for a long time since Python 3.4, had really good options to parallelize IO bound

00:09:56.900 --> 00:09:58.560
or waiting types of things.

00:09:58.560 --> 00:09:59.540
I'm talking to a network.

00:09:59.540 --> 00:10:00.480
I'm talking to a database.

00:10:00.480 --> 00:10:03.360
I'm talking to whatever with asyncio, right?

00:10:03.360 --> 00:10:03.780
Yeah.

00:10:03.780 --> 00:10:08.360
But the CPU bound stuff, the GIL would stop and go, yeah, no, I don't care how many cores

00:10:08.360 --> 00:10:08.600
you got.

00:10:08.600 --> 00:10:09.700
You got one, right?

00:10:09.700 --> 00:10:10.160
Yeah.

00:10:10.160 --> 00:10:13.920
And so this is just summing up a bunch of numbers, the squares of the numbers,

00:10:14.040 --> 00:10:16.900
just like doing some computational busy work, right?

00:10:16.900 --> 00:10:20.960
So it says, okay, well, let's set up a little app that'll take some parameters so we can feed

00:10:20.960 --> 00:10:26.460
it different information and see what we'll get and then run it on a thread pool executor

00:10:26.460 --> 00:10:28.880
with as many threads that are specified.

00:10:29.300 --> 00:10:31.220
So it starts out just to skip ahead.

00:10:31.220 --> 00:10:32.720
So look, I ran it once.

00:10:32.720 --> 00:10:34.260
I get one core.

00:10:34.260 --> 00:10:41.300
It says 99% CPU usage on macOS that it reports this as a hundred percent basis as being one

00:10:41.300 --> 00:10:42.160
core fully busy.

00:10:42.160 --> 00:10:44.860
So if you've got eight cores, this could go up to 800%.

00:10:44.860 --> 00:10:45.440
It's kind of weird.

00:10:45.780 --> 00:10:48.940
Anyway, 99% CPU if you run the regular one.

00:10:48.940 --> 00:10:52.960
But if you run the free threaded one, he was getting some number that was a little low.

00:10:52.960 --> 00:10:53.640
There's a bug.

00:10:53.640 --> 00:10:56.900
It's not super relevant about him fixing the bug or not.

00:10:56.900 --> 00:10:58.580
I don't really think that matters.

00:10:58.700 --> 00:11:06.700
But what the takeaway is, if you run it with four threads, that whole workload ran in 1.3 seconds.

00:11:06.700 --> 00:11:08.420
You run it with 12 threads.

00:11:08.420 --> 00:11:10.400
It went down to one second.

00:11:10.400 --> 00:11:11.920
I don't know how many cores he has.

00:11:11.920 --> 00:11:12.760
I don't believe it said.

00:11:12.760 --> 00:11:18.840
But with the gill, that's four seconds versus one second or 1.3 seconds for the basically

00:11:18.840 --> 00:11:19.980
four times as fast.

00:11:19.980 --> 00:11:21.960
Presumably, this is a four core system.

00:11:21.960 --> 00:11:22.480
I'm not sure.

00:11:22.820 --> 00:11:23.840
Anyway, pretty cool, right?

00:11:23.840 --> 00:11:25.500
That is pretty cool.

00:11:25.500 --> 00:11:27.160
So yes, that's faster.

00:11:27.160 --> 00:11:29.780
Four times faster is 400%.

00:11:29.780 --> 00:11:30.480
That's no joke.

00:11:30.480 --> 00:11:31.860
That'll make a difference for some people.

00:11:31.860 --> 00:11:35.680
But I think more relevant is just like, hey, look, apparently the installers have it.

00:11:35.680 --> 00:11:36.940
Right?

00:11:36.940 --> 00:11:37.460
That's kind of cool.

00:11:37.460 --> 00:11:37.960
Yeah.

00:11:37.960 --> 00:11:38.500
Okay.

00:11:38.500 --> 00:11:41.100
I was chuckling because I said testing it out.

00:11:41.100 --> 00:11:45.100
It says, I asked Claude 3.5 Sonnet to write me a quick test script.

00:11:45.100 --> 00:11:50.040
But the script it come up with is something I know that he can write on his own.

00:11:50.040 --> 00:11:52.440
Yeah, exactly.

00:11:52.440 --> 00:11:52.620
Exactly.

00:11:52.620 --> 00:11:53.700
Exactly.

00:11:53.700 --> 00:11:55.580
Yeah.

00:11:55.580 --> 00:11:57.920
It didn't come up with something all that interesting.

00:11:57.920 --> 00:11:58.940
And it introduced a bug.

00:11:58.940 --> 00:12:00.080
He should have just written it himself.

00:12:00.080 --> 00:12:02.620
Oh, well.

00:12:02.620 --> 00:12:03.620
But this is neat.

00:12:03.620 --> 00:12:08.680
Actually, I saw the announcement that there were some builds of the free threader one,

00:12:08.680 --> 00:12:11.700
but I didn't know you could just do it, like click it from the installer.

00:12:11.700 --> 00:12:12.480
That's cool.

00:12:12.480 --> 00:12:12.960
Yeah.

00:12:12.960 --> 00:12:15.320
That's the big news I took away as well.

00:12:15.320 --> 00:12:15.720
Very cool.

00:12:15.720 --> 00:12:16.180
Neat.

00:12:16.180 --> 00:12:17.000
Very neat.

00:12:17.000 --> 00:12:21.060
And you know what you don't have to build yourself is an APM platform.

00:12:21.060 --> 00:12:21.620
Right.

00:12:21.620 --> 00:12:23.700
We could let Scout do that for you.

00:12:23.700 --> 00:12:27.440
Let me tell you real quick about Scout APM.

00:12:27.440 --> 00:12:29.640
They're big supporters of Python Bytes.

00:12:29.640 --> 00:12:31.160
So we appreciate that very much.

00:12:31.160 --> 00:12:36.940
So if you are tired of spending hours trying to find the root cause of issues impacting your

00:12:36.940 --> 00:12:40.240
performance, then you owe it to yourself to check out Scout APM.

00:12:40.600 --> 00:12:49.500
They're a leading Python application performance monitoring tool, APM, that helps you identify and solve performance abnormalities faster and easier.

00:12:49.500 --> 00:13:00.420
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.

00:13:00.420 --> 00:13:02.820
And then you say, oh, no, why is it so slow?

00:13:02.820 --> 00:13:05.160
Why are you doing 200 database queries for what should be one?

00:13:05.160 --> 00:13:06.580
So you can find out things like that.

00:13:06.780 --> 00:13:13.980
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.

00:13:13.980 --> 00:13:16.960
And you'll love it because it's built for developers by developers.

00:13:16.960 --> 00:13:18.620
It makes it easy to get set up.

00:13:18.620 --> 00:13:21.140
Seriously, you can do it in less than four minutes.

00:13:21.260 --> 00:13:21.960
So that's awesome.

00:13:21.960 --> 00:13:25.020
And the best part is the pricing is straightforward.

00:13:25.020 --> 00:13:30.500
You only pay for the data that you use with no hidden overage fees or per seat pricing.

00:13:30.500 --> 00:13:32.980
And I just learned this, Brian.

00:13:32.980 --> 00:13:38.120
They also have they provide the pro version for free to all open source projects.

00:13:38.120 --> 00:13:45.540
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.

00:13:45.540 --> 00:13:49.420
So you can start your free trial and get instant insights today.

00:13:49.900 --> 00:13:52.100
Visit pythonbytes.fm/scout.

00:13:52.100 --> 00:13:54.360
The link is in your podcast player show notes as well.

00:13:54.360 --> 00:13:55.780
And please use that link.

00:13:55.780 --> 00:13:59.740
Don't just search for them because otherwise they don't think you came from us.

00:13:59.740 --> 00:14:01.340
And then they'd stop supporting the show.

00:14:01.340 --> 00:14:03.900
So please use our link pythonbytes.fm/scout.

00:14:03.900 --> 00:14:04.840
Check them out.

00:14:04.840 --> 00:14:06.760
It really supports the show.

00:14:06.760 --> 00:14:07.800
What's next, Brian?

00:14:07.800 --> 00:14:10.640
I want to iterate into the next topic.

00:14:10.640 --> 00:14:12.920
I want to talk about iteratools.

00:14:12.920 --> 00:14:19.680
So this comes from Rodrigo from Maths.

00:14:19.740 --> 00:14:21.000
pp.com.

00:14:21.000 --> 00:14:23.660
And he writes a lot of great articles.

00:14:23.660 --> 00:14:29.620
But I and I know we've covered iteratools before and people have heard of iteratools and it's built into Python.

00:14:29.620 --> 00:14:35.680
But there's so many goodies in there that I like to have people tell me what their favorites are and reshaping.

00:14:35.680 --> 00:14:44.880
So this is an article that groups all of the, I think there's more than 20 in there.

00:14:44.880 --> 00:14:49.500
But anyway, 20 tools that every Python developer should be aware of from iteratools.

00:14:49.940 --> 00:14:52.700
And it's broken into five categories.

00:14:52.700 --> 00:15:01.800
There's reshaping iterators, filtering iterators, combinatorial, infinite, and iterators that complement other tools.

00:15:02.320 --> 00:15:05.540
And there's, I just did a quick list of this.

00:15:05.540 --> 00:15:10.200
And I really think there's a few of these in here that I need to use more.

00:15:10.200 --> 00:15:12.520
So I'm glad I ran across this article.

00:15:12.520 --> 00:15:18.140
One of them, so right off the bat, it says the three most useful iterators are product.

00:15:18.580 --> 00:15:25.120
And what product does is it simplifies, like let's say you've got a nested loop of like width and height, for instance.

00:15:25.120 --> 00:15:30.780
For X in range of width and for Y in range of height, you do something with X and Y.

00:15:30.780 --> 00:15:38.600
Well, you can use iteratools product and have it just be one does a product of two ranges or product of two iterators.

00:15:38.600 --> 00:15:44.540
And it gives you the two, like all of the combinations in order.

00:15:45.060 --> 00:15:50.160
So that's a really cool thing that I always forget about, that I probably should write that more.

00:15:50.160 --> 00:15:54.180
Especially if you've got more than two, when you get like three, it gets ridiculous.

00:15:54.180 --> 00:15:58.100
And so using iteratools to simplify that, it's a really great idea.

00:15:58.100 --> 00:16:05.100
And because, you know, with Python, every time you indent into a for loop, you're going to indent your code.

00:16:05.100 --> 00:16:11.040
It helps you keep the horizontal width of your code a little bit more reasonable.

00:16:11.040 --> 00:16:13.060
Flats, better than nested, all that kind of stuff.

00:16:13.060 --> 00:16:13.540
Yeah.

00:16:14.300 --> 00:16:15.860
Chain, I always remember about.

00:16:15.860 --> 00:16:20.480
So Chain is a way to combine two lists and iterate through all of them.

00:16:20.480 --> 00:16:24.680
Instead of adding the lists, adding is kind of, it creates a new one.

00:16:24.680 --> 00:16:25.620
You might not need that.

00:16:25.620 --> 00:16:28.320
Whereas Chain will iterate through both of them.

00:16:28.320 --> 00:16:34.240
And I have to remind people, if you're not aware, all these really cool things within the iter tools,

00:16:34.240 --> 00:16:38.440
they're a way to manipulate iterators such that you're not copying things.

00:16:38.440 --> 00:16:40.320
You're not making a new list of something.

00:16:40.320 --> 00:16:43.760
You're just iterating through existing iterators without doing the copy.

00:16:43.760 --> 00:16:45.580
I think that I'm pretty sure that's true.

00:16:45.580 --> 00:16:46.160
Yeah.

00:16:47.000 --> 00:16:53.260
The third one on is everybody should know about that I thought was great was pairwise.

00:16:53.500 --> 00:16:56.160
And I actually apparently never knew about this.

00:16:56.160 --> 00:17:06.520
And this is a way to, like, let's say you've got the example is a bunch of names and you want to be able to make sure that everybody says hi to the person on their right.

00:17:06.940 --> 00:17:07.940
You can go through it.

00:17:07.940 --> 00:17:08.080
And you can go through it.

00:17:08.080 --> 00:17:09.880
Well, this might be a silly example.

00:17:09.880 --> 00:17:21.280
But if you want to go through an entire sequence and make sure each pair in a, like, you're just walking it down, like the first number one and number two, and then two and three and then three and four.

00:17:21.280 --> 00:17:23.000
This is an easy way to do that.

00:17:23.000 --> 00:17:32.060
And actually, there's an old way of using zip with the, you can, you can combine two lists and do slices.

00:17:32.060 --> 00:17:33.820
But that's a little confusing.

00:17:33.820 --> 00:17:36.960
Whereas pairwise just gives it to you right away.

00:17:36.960 --> 00:17:39.800
It returns two pointers to objects.

00:17:39.800 --> 00:17:41.040
So that's really cool.

00:17:41.040 --> 00:17:49.860
A couple more things I wanted to bring up that I thought were great in here was zip longest, which I do remember because I use it frequently.

00:17:50.100 --> 00:18:00.020
But if you're zipping two things together, which means you're going to go through and go through two sequences using zip, by default, zip picks the shortest.

00:18:00.020 --> 00:18:04.300
And whereas, and it just chops it off, I think.

00:18:04.300 --> 00:18:06.180
Actually, I don't remember what it does at the end.

00:18:06.180 --> 00:18:08.660
But zip longest will have a fill value.

00:18:08.660 --> 00:18:13.120
So you give it a fill value and it goes through everything and you'll have something empty.

00:18:13.120 --> 00:18:14.460
So you make sure you go through everything.

00:18:14.460 --> 00:18:19.100
And then the last thing is T, which is kind of neat.

00:18:19.260 --> 00:18:24.760
It allows you to do, normally iterators are exhausted once you go through it.

00:18:24.760 --> 00:18:26.680
So you have to like regenerate an iterator.

00:18:26.680 --> 00:18:30.940
But T allows you to iterate through something a couple times.

00:18:30.940 --> 00:18:36.180
It allows you to iterate without exhausting the iterator, which is interesting.

00:18:36.180 --> 00:18:38.580
So nice.

00:18:38.580 --> 00:18:44.000
And then at the end, a discussion of, which I think is cool that he did this.

00:18:44.000 --> 00:18:49.080
So a discussion that there is, he wrote a book on iter tools.

00:18:49.080 --> 00:18:51.060
So there's a little book of iter tools.

00:18:51.060 --> 00:18:52.700
He's not paying for this ad.

00:18:52.700 --> 00:18:55.220
I just think it's neat that somebody wrote a book about iter tools.

00:18:55.220 --> 00:18:55.880
That's nice.

00:18:55.880 --> 00:18:56.400
Neat.

00:18:56.400 --> 00:18:57.220
Yeah.

00:18:57.220 --> 00:18:58.160
Yeah, it's pretty neat.

00:18:58.160 --> 00:19:01.960
So there's a lot of, a lot of powerful stuff there.

00:19:01.960 --> 00:19:02.540
Yeah.

00:19:02.540 --> 00:19:05.280
It's all a lot of simple, hard problems in simple ways.

00:19:05.640 --> 00:19:10.580
I like, I really appreciate that he picked out those first three though, of like, even if

00:19:10.580 --> 00:19:14.800
you're not really wanting to go through all of this, take a look at these three.

00:19:14.800 --> 00:19:17.640
You might, you probably need them and you just don't realize it.

00:19:17.640 --> 00:19:18.520
So, yeah.

00:19:18.520 --> 00:19:19.140
So.

00:19:19.140 --> 00:19:19.660
Indeed.

00:19:20.020 --> 00:19:22.160
What do you, what do you got for us next, Michael?

00:19:22.160 --> 00:19:27.580
You would love to know if your website was down and not up or your Docker container or

00:19:27.580 --> 00:19:28.860
your other service.

00:19:28.860 --> 00:19:31.140
And you would like to be notified in interesting ways.

00:19:31.140 --> 00:19:36.640
And there are services you can pay for this or free services that have weird limitations

00:19:36.640 --> 00:19:39.020
or I don't know, just funky stuff, right?

00:19:39.020 --> 00:19:43.620
Some of those in order to answer really good questions, you'd have to give them pretty serious

00:19:43.620 --> 00:19:47.180
internal access to your code or to your infrastructure potentially.

00:19:47.180 --> 00:19:53.740
So I present to you the Uptime Kuma, which is trying hard to resist Uptime Karma, but no

00:19:53.740 --> 00:19:57.340
Uptime Kuma, a fancy self-hosted monitoring tool.

00:19:57.340 --> 00:19:58.020
Okay.

00:19:58.020 --> 00:19:59.360
So this thing is pretty cool.

00:19:59.360 --> 00:20:05.480
It comes with a Docker variant, so you can just Docker compose it into life.

00:20:05.780 --> 00:20:10.160
And I'm thinking about setting this up for Python bytes and talk Python and other things

00:20:10.160 --> 00:20:13.640
because I've already got that Docker cluster and all the infrastructure to run it.

00:20:13.640 --> 00:20:14.940
So adopting it should be really easy.

00:20:14.940 --> 00:20:17.420
It just takes one container to run.

00:20:17.420 --> 00:20:22.320
And I believe it stores its data into a SQLite database in there.

00:20:22.320 --> 00:20:24.320
So file copy is kind of a backup.

00:20:24.320 --> 00:20:25.520
It's kind of the backup option.

00:20:25.520 --> 00:20:27.140
So anyway, check this out.

00:20:27.140 --> 00:20:28.020
Doesn't this look neat, Brian?

00:20:28.020 --> 00:20:30.300
You tell it different things you want to do.

00:20:30.300 --> 00:20:32.280
Like I want to check that the port is open.

00:20:32.380 --> 00:20:37.100
I want to check that this example is, you know, some example.com website is up.

00:20:37.100 --> 00:20:38.620
You can see that MySQL is running.

00:20:38.620 --> 00:20:41.320
You can ping the server to see that the server is up.

00:20:41.320 --> 00:20:43.900
All sorts of things you can put as tests in here.

00:20:43.900 --> 00:20:45.840
And you can even have an anti-test.

00:20:45.840 --> 00:20:51.600
Like for example, if you're ever able to directly connect to the database, that should be flagged

00:20:51.600 --> 00:20:57.120
as an error that like a down moment, not an up moment because something's gone wrong with the infrastructure

00:20:57.120 --> 00:20:58.220
and you need to go fix it.

00:20:58.220 --> 00:20:59.900
But in a reverse sort of way.

00:20:59.900 --> 00:21:00.780
So what does it say?

00:21:00.780 --> 00:21:04.760
First of all, 54,000, 53,000 GitHub stars.

00:21:04.760 --> 00:21:07.320
So really, really quite popular.

00:21:07.320 --> 00:21:10.600
It has a little test, a little test server.

00:21:10.600 --> 00:21:13.180
You can set up, point at your website for 10 minutes and play with it.

00:21:13.420 --> 00:21:14.380
That's a really nice feature.

00:21:14.380 --> 00:21:22.840
What it says, uptime monitoring for HTTPS, TCP, HTTP keywords, JSON query, ping, a DNS record.

00:21:22.840 --> 00:21:25.340
You can make sure your DNS records don't go insane.

00:21:25.340 --> 00:21:31.080
And like your MX, DCAM, or I don't know, whatever, game servers, and even check that your certain

00:21:31.080 --> 00:21:32.440
Docker containers are still running.

00:21:32.800 --> 00:21:37.980
So it's got a nice UI and it has notifications for telegram, discord, slack, pushover, email,

00:21:37.980 --> 00:21:40.000
and 90 other notifications.

00:21:40.000 --> 00:21:43.400
Can have as fine grained as every 20 seconds checking.

00:21:43.400 --> 00:21:45.560
It comes with status pages.

00:21:45.560 --> 00:21:54.620
So if we had a Python bytes monitor set up with this, I could set up status.pythonbytes.fm

00:21:54.620 --> 00:21:57.180
that people could go and see if the RSS feed is live.

00:21:57.180 --> 00:21:58.640
Is the Docker container running?

00:21:58.640 --> 00:22:00.120
Is X, Y, and Z, right?

00:22:00.120 --> 00:22:01.540
So it has that for you.

00:22:01.780 --> 00:22:06.860
And it'll also, one thing I really like, because I use Let's Encrypt, but the auto renewal

00:22:06.860 --> 00:22:08.100
is a little bit janky.

00:22:08.100 --> 00:22:10.680
Long story, I don't want to go into it, but it's a little bit janky.

00:22:10.680 --> 00:22:14.380
And so it works, but it requires a little fiddling.

00:22:14.380 --> 00:22:18.200
So having it will actually check SSL certificates to see if it'll expire.

00:22:18.200 --> 00:22:21.400
So it'll say like, your certificate is good for 29 more days.

00:22:21.400 --> 00:22:25.920
Maybe you want to get on that before it goes like, you know, something terrible.

00:22:25.920 --> 00:22:28.280
So all of that, isn't that sweet?

00:22:28.280 --> 00:22:29.260
It is cool.

00:22:29.560 --> 00:22:32.260
Yeah, there's a bunch of sponsors and it's got this nice UI.

00:22:32.260 --> 00:22:35.160
You can bump over to the status page.

00:22:35.160 --> 00:22:40.100
It'll prepare you a little demo app and it runs for a certain amount of time.

00:22:40.240 --> 00:22:42.380
So how long are certificates good for?

00:22:42.380 --> 00:22:46.320
If you do Let's Encrypt, it's a year, I believe.

00:22:46.320 --> 00:22:46.880
Okay.

00:22:47.140 --> 00:22:51.120
So anyway, you can go over here and create this and actually go and add a little monitor

00:22:51.120 --> 00:22:52.880
and pick all the different kinds.

00:22:52.880 --> 00:22:54.100
And look at all these things.

00:22:54.100 --> 00:22:58.980
You can monitor MongoDB and SQL Server, Postgres directly.

00:22:58.980 --> 00:23:00.420
Yeah, it's really neat.

00:23:00.620 --> 00:23:02.040
So I'm thinking of setting this up.

00:23:02.040 --> 00:23:04.340
And if you want to play with it, just click on that little thing.

00:23:04.340 --> 00:23:06.320
You can see here, Brian, I clicked on it.

00:23:06.320 --> 00:23:09.880
Now it says I have nine minutes to 21 seconds before my app gets blown away.

00:23:09.880 --> 00:23:11.900
But I can test it out, which is pretty cool.

00:23:11.900 --> 00:23:20.520
Anyway, it will give us potentially a really nice way to sort of monitor and get notifications

00:23:20.520 --> 00:23:21.040
about it.

00:23:21.180 --> 00:23:23.400
I have that from other services, but don't like it.

00:23:23.400 --> 00:23:28.240
I could set it up once a day on the free one and make sure that my website at least is

00:23:28.240 --> 00:23:29.620
live for 10 minutes a day.

00:23:29.620 --> 00:23:30.060
Yeah.

00:23:30.060 --> 00:23:35.100
Yeah, if you don't mind reconfiguring it every time.

00:23:35.100 --> 00:23:35.600
Yeah.

00:23:35.600 --> 00:23:36.080
Okay.

00:23:36.080 --> 00:23:36.800
Yeah, sure.

00:23:36.800 --> 00:23:37.300
All right.

00:23:37.300 --> 00:23:37.840
Pretty cool.

00:23:37.840 --> 00:23:38.800
How about some extras?

00:23:38.800 --> 00:23:45.060
The only extra I got was last week I talked about making a new pytest course.

00:23:45.060 --> 00:23:52.720
I've been working on that and I'm on version three because I'm a perfectionist and want to

00:23:52.720 --> 00:23:54.640
make sure that it's smooth and quick.

00:23:54.640 --> 00:23:58.160
So I do hope to get that out sometime soon.

00:23:58.160 --> 00:24:01.900
I was going to say maybe next week, but you know, I don't want to put too much pressure on

00:24:01.900 --> 00:24:02.240
myself.

00:24:02.240 --> 00:24:02.940
Yeah.

00:24:02.940 --> 00:24:05.700
When I go, that's, that's very exciting.

00:24:05.700 --> 00:24:06.800
I know people are looking forward to it.

00:24:06.800 --> 00:24:11.480
I also had to basically put DaVinci Resolve down to come record the podcast.

00:24:11.480 --> 00:24:13.080
So I was in the middle editing some videos.

00:24:13.420 --> 00:24:15.100
I got coming on for a new course as well.

00:24:15.100 --> 00:24:16.400
So very exciting stuff.

00:24:16.400 --> 00:24:17.140
All right.

00:24:17.140 --> 00:24:20.720
There's, there's a never ending dream of things to talk about, right?

00:24:20.720 --> 00:24:21.180
Yeah.

00:24:21.180 --> 00:24:21.820
All right.

00:24:21.820 --> 00:24:22.600
I've got a couple.

00:24:22.600 --> 00:24:29.120
Kenneth writes, talks, pointed out that, you know, requests and more fame talks

00:24:29.120 --> 00:24:35.520
about this, move that Switzerland pulled Switzerland, Switzerland now requires all government

00:24:35.520 --> 00:24:37.000
software to be open source.

00:24:37.000 --> 00:24:37.920
That's cool.

00:24:37.920 --> 00:24:38.200
Cool.

00:24:38.200 --> 00:24:38.720
Yeah.

00:24:38.720 --> 00:24:40.000
So what does that mean?

00:24:40.000 --> 00:24:41.980
They, you gotta read it carefully.

00:24:41.980 --> 00:24:47.540
It doesn't mean the government has to only use open source as in Linux and Firefox, but

00:24:47.540 --> 00:24:51.840
the thing, the software that the government makes has to be open source of what this is.

00:24:51.840 --> 00:24:53.600
So we bump over to omnivore.

00:24:53.600 --> 00:24:54.320
You can see my notes.

00:24:54.320 --> 00:24:59.220
Switzerland has taken a major step forward with its federal law on the use of electronic

00:24:59.220 --> 00:25:01.540
means for the fulfillment of government tasks.

00:25:01.920 --> 00:25:04.180
SIM bag is the acronym.

00:25:04.180 --> 00:25:09.880
This groundbreaking legislation mandates releasing open source software of the federal government.

00:25:09.880 --> 00:25:15.060
The law requires all public bodies to disclose the source code of software developed by or

00:25:15.060 --> 00:25:19.640
for them unless 30 part third party rights or security concerns prevented.

00:25:19.640 --> 00:25:20.840
So that's pretty neat.

00:25:20.840 --> 00:25:22.440
There's actually, there was some pushback.

00:25:22.480 --> 00:25:26.680
For example, one of the main areas this was around is the justice system.

00:25:26.680 --> 00:25:34.820
This, was trying to get all the software that runs, basically runs the justice system,

00:25:34.820 --> 00:25:37.560
the court system for Switzerland open source.

00:25:37.560 --> 00:25:38.520
But guess what?

00:25:38.520 --> 00:25:42.200
The proprietary legal software company, web law, wasn't happy.

00:25:42.200 --> 00:25:43.360
Right?

00:25:43.360 --> 00:25:43.920
Yeah.

00:25:44.220 --> 00:25:44.840
No, they weren't.

00:25:44.840 --> 00:25:47.560
But, after a decade of fighting, it came out.

00:25:47.560 --> 00:25:49.180
And there's one other point to make.

00:25:49.180 --> 00:25:54.600
In addition to mandating open source software, it also requires the release of non-personal,

00:25:54.600 --> 00:25:58.240
non-security sensitive data as open data.

00:25:58.240 --> 00:26:03.220
So it's like open software and open, open data as well.

00:26:03.220 --> 00:26:04.260
So pretty cool.

00:26:04.260 --> 00:26:04.920
Interesting.

00:26:04.920 --> 00:26:05.360
We have stuff.

00:26:05.360 --> 00:26:06.120
Yeah, it is.

00:26:06.120 --> 00:26:08.580
We do have some stuff like that, like over at Talk Python.

00:26:08.580 --> 00:26:10.160
What was it?

00:26:10.160 --> 00:26:12.380
Elections, I think if I look for that.

00:26:12.380 --> 00:26:12.580
Yeah.

00:26:12.800 --> 00:26:15.280
Python at the U.S. Federal Elections Commission.

00:26:15.280 --> 00:26:17.560
I talked to Laura Beaufort.

00:26:17.560 --> 00:26:21.260
And I believe they are open sourcing their stuff as well.

00:26:21.260 --> 00:26:22.920
A lot of things going on there.

00:26:22.920 --> 00:26:25.260
Like, yeah, open source at the FEC, for example.

00:26:25.260 --> 00:26:30.840
So we have some stuff in like spotty examples of that, but not as a overall statement.

00:26:30.840 --> 00:26:31.800
So it's pretty interesting, right?

00:26:31.800 --> 00:26:32.320
Yeah.

00:26:32.320 --> 00:26:34.120
I'm curious to look at some of the stuff.

00:26:34.120 --> 00:26:34.780
Like, um.

00:26:34.780 --> 00:26:35.100
Yeah.

00:26:35.100 --> 00:26:36.920
How clean is your code?

00:26:36.920 --> 00:26:37.900
Like, yeah.

00:26:37.900 --> 00:26:42.060
How many AWS keys will be in there?

00:26:42.060 --> 00:26:42.660
We'll find out.

00:26:43.420 --> 00:26:45.380
Thanks indirectly, Kenneth, for that.

00:26:45.380 --> 00:26:46.280
one more.

00:26:46.280 --> 00:26:52.880
Remember last week I talked about the PySimple GUI and it's switching to a commercial license,

00:26:52.880 --> 00:26:57.440
which again, I'm not super against, but sort of the rug pull aspect of it.

00:26:57.440 --> 00:26:58.980
Like, hey, it's open source for a long time.

00:26:58.980 --> 00:27:02.420
And I'm going to take everybody's contributions and then, you know, change the license.

00:27:02.420 --> 00:27:05.860
That sort of thing got some people's nerves up.

00:27:05.860 --> 00:27:07.000
Well, um.

00:27:07.320 --> 00:27:20.820
FFalcon31415 on Mastodon pointed out, hey, check out FreeSimple GUI, which I linked to in the show notes, which is an actively maintained fork of the last release of PySimple GUI with an open source license.

00:27:20.820 --> 00:27:24.260
So if you were like, oh, I was going to use that, you still can.

00:27:24.540 --> 00:27:24.860
Yeah.

00:27:24.860 --> 00:27:34.080
Actually, it's got a really good, the read me on that has some really good to, like, has some good tutorial examples of, of how to write a simple GUI on it.

00:27:34.080 --> 00:27:40.580
So, not only is it the open source free version, but it's, it's also some pretty good documentation on there.

00:27:40.580 --> 00:27:41.340
Cool.

00:27:41.340 --> 00:27:42.420
All right.

00:27:42.420 --> 00:27:43.440
How about some jokes?

00:27:43.440 --> 00:27:44.100
Yeah.

00:27:44.100 --> 00:27:45.100
Joke, joke time.

00:27:45.100 --> 00:27:46.040
Singular joke.

00:27:46.040 --> 00:27:46.780
A singular joke.

00:27:46.780 --> 00:27:52.420
So this one is kind of a meme with Will Smith and it doesn't really have that much to do with Will Smith.

00:27:52.420 --> 00:27:53.540
I think it's just the attitude.

00:27:53.540 --> 00:27:54.740
I like Will Smith.

00:27:54.740 --> 00:27:58.700
Anyway, it says, just because I know Java doesn't mean I know JavaScript.

00:27:58.700 --> 00:28:01.400
I mean, I do, but not because I know Java.

00:28:01.400 --> 00:28:03.460
That's good, right?

00:28:03.460 --> 00:28:04.060
Yeah.

00:28:04.060 --> 00:28:04.560
Yeah.

00:28:04.560 --> 00:28:04.760
Yeah.

00:28:04.760 --> 00:28:12.820
I was just talking, talking to, whenever you talk to kids trying to learn like software, it is, it's still confusing to people.

00:28:12.820 --> 00:28:15.280
I mean, like, it's not confusing to us because we've been around it.

00:28:15.280 --> 00:28:25.220
We knew that the history, but it seems weird now to tell people, yeah, the JavaScript that everybody uses, it was named that because Java was popular at the time.

00:28:25.220 --> 00:28:29.320
so anyway, are you muted?

00:28:29.320 --> 00:28:30.700
I was sorry.

00:28:30.700 --> 00:28:32.860
fun episode as always, Brian.

00:28:32.860 --> 00:28:33.300
Yeah.

00:28:33.440 --> 00:28:34.960
And yeah, thanks, man.

00:28:34.960 --> 00:28:35.840
Thanks for being here.