Brought to you by Michael and Brian - take a Talk Python course or get Brian's pytest book


Transcript #287: Surprising ways to use Jupyter Notebooks

Return to episode page view on github
Recorded on Tuesday, Jun 7, 2022.

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

00:05 This is episode 287, recorded June 7th, and I am Brian Okken.

00:09 I'm Michael Kennedy.

00:11 It's good to talk to you, Michael.

00:12 Yeah, good to see you again, Brian.

00:13 Yeah.

00:14 Again, we've got our wardrobe matching our background here, which is fantastic.

00:19 Yeah.

00:19 We like, you know, texted each other in the morning to make sure.

00:22 [laughter]

00:24 I'm feeling purple. I'm going to get a new shirt.

00:25 [laughter]

00:25 No, it's great.

00:26 Good to see you as always.

00:28 Lots of fun Python things to talk about here.

00:30 >> Yeah. Well, let's jump into the first one.

00:32 >> The first thing that I want to talk about here is distributing Python applications.

00:39 Now, this is a little bit in the Python GUIs side of thing.

00:43 Something you just can't get enough of in terms of like, "Hey, could we have more ways to do this that are awesome?" How about if we had ways that were automatic?

00:52 >> Yeah.

00:52 >> So I want to talk about this thing by Brent Bolle-Bregret called autopy2exe.

01:00 It basically does what it says right in the name there, converts a .py file to a .exe using a simple graphical interface.

01:10 Now, this GitHub description is a bit of a Windows bias because it'll also create it to Mac apps as well, to .app files, so it's not just a Windows thing.

01:21 >> Cool.

01:21 >> It's pretty popular. It has 2,000 stars, 400 forks.

01:25 And what it is is a UI on top of things like Py2App or PyInstaller, specifically PyInstaller.

01:33 So what you do is you fire this thing up and out pops this user interface that if you're watching the YouTube stream, you can see there's a user interface here and it just says, pick the starting Python file for your application.

01:46 And you can say, what do you want the output to be?

01:49 One file or one directory?

01:51 >> Okay. >> I think we all want it to be one probably generally, but maybe a directory, I don't know.

01:56 What else you're gonna, maybe you wanna do some other things there.

01:59 But what I did is I tried this against my URLify little appy thing, which, let me pull that up.

02:08 This is something I built a while ago with Rumps, which is fantastic, ridiculously uncomplicated menu bar apps or something like that for Mac.

02:19 And all it is is a little thing that goes up in your Mac bar and it has like, you know, Slugify text or Trimit or lower cases, just, I'm constantly taking names of like file names and turning them into something I could put as a URL or like a title of a video or something and turning it into something that would be a good URL.

02:40 So that's what this little app is for.

02:41 But here's the thing is it's a Python app that runs in the menu bar on my Mac with no terminal view.

02:47 And I wanted to be able to distribute it to people.

02:49 And so the way you get it is you just download a zip file, which is just the zip up dot app executable, right?

02:56 So I had done a bunch of stuff with the setup and all those kinds of things with PI installer to build this.

03:02 So my test case was, well, let me take this auto high to EXE thing and just point it at that and see what happens.

03:10 And what happened was good things.

03:12 It was really interesting.

03:13 There's the, an app dot PI, but there's dependent Python files that it uses.

03:19 I mean, I'm not a beast. I don't write my entire application in one file.

03:23 Like there's other things broken apart in there and that gets bundled up.

03:26 And it somehow discovered that, pulled those all in.

03:29 So I just picked the top level file and it found the dependencies, you know, the requirements.txt type dependencies and so on.

03:38 And it created a .app file that, as far as I could tell, ran just fine.

03:42 >> That's cool.

03:43 >> Isn't that cool?

03:43 >> Yeah, I like it.

03:44 >> You can decide if it's a window-based application, so hide the console, which is what I said, because I want it to run in the menu bar.

03:51 But if it was a console-based app, but you just wanted to distribute it as a single thing with no Python, well, no Python requirements, you could create a console-based app.

04:00 You set the icon, you can add in additional files.

04:03 So if there's like, you know, JSON configuration files or YAML files or images or something like that you need to take along, you can configure that there.

04:12 And then there's an advanced section that expands out to be like pages of stuff that I don't remember, same thing for settings.

04:18 Then you just click the big convert to py to exe button and you get ironically not an exe but a .app file.

04:24 There you go.

04:25 >> That's cool.

04:26 >> Isn't that cool?

04:26 >> Yeah.

04:27 >> For people who are playing around with this, I think they even have, they must be listening to us here, they even have a little animated gif of how this all works right on the GitHub.

04:38 >> That's pretty cool.

04:39 >> If you want to see how it works, I guess there's not a whole lot, but you browse for the icon, you go in there and you check out some things, And then you just hit build and it takes a little while, but you know, that's pi2exe. That's how it goes. And it just sits there and it cranks away for a while, bundles it all up and yeah, got a little executable. So if this is something you want to play with, but you're like, ah, it's kind of a real pain to go and figure out, you know, all the setup pi commands in order to get it to do the pi installer commands and whatnot, then you know, you can definitely give this a shot. I think it's pretty neat.

05:12 I think with mine, I didn't use py2 installer.

05:15 I think I used py2app.

05:16 Yeah, that's what I used.

05:18 So pretty neat.

05:19 Yeah, check that out.

05:20 I think people will find it helpful for ways to distribute Python apps.

05:24 - Yeah, and I like that it looks pretty professional looking and then also, especially, I mean, especially with internal, like internal company stuff, that happens a lot where you wanna share something around.

05:36 - Yeah, yeah, like just download this and run it.

05:37 Please don't ask me how to set up a path so that your Python that's not Python 3.3, or whatever, is the one that runs it.

05:45 >> Nobody needs to know that it's Python underneath.

05:47 >> Yeah, exactly.

05:49 >> Cool. I like it.

05:51 >> One other thing, by the way, it's a GUI application.

05:54 It's self-written in Python.

05:56 So you may wonder, what is it doing?

05:59 Maybe it's bundled itself.

06:01 Obviously, that'd be very meta.

06:02 If autopy2xe could deliver an autopy2xe itself, that's obviously lovely.

06:08 It reminded me that I have Chrome installed when I ran it.

06:13 What it does is it runs something in the background, then it fires up Chrome, which becomes the UI in this Windows looking Chrome window.

06:23 It's not quite an Electron app, but it's Electron in a style.

06:28 Anyway, it's an interesting little UI app itself.

06:32 I'm not sure what it's doing, but it works.

06:34 >> Nice. All right.

06:36 Well, I'd like to talk about Jupyter.

06:38 So Jupyter notebooks.

06:40 Oh yeah.

06:40 Yeah.

06:41 So this is how do you use it?

06:42 How do you use it?

06:43 So like, I was just fascinated by the click baitiness of this, but it's okay.

06:49 Eight surprising ways to eight, eight surprising ways how to use Jupyter notebooks, and I gotta say, I didn't know you could do some of this stuff with Jupyter, so it's pretty cool.

06:58 So, the first one package development, why would you, I don't know why, but you know, some people that are more comfortable in Jupyter than they are in IDE or something, maybe it's good.

07:09 So there's a package called mbdev that you can use to, and it's by a company called FastAI, that you can use to help with package development, including, you know, trying to get your CI working and your tests all in one place and demos and documentation and stuff.

07:30 So that's kind of neat.

07:32 Like that idea.

07:33 I definitely should try to play with that to see how that works.

07:36 Apparently, there's a video.

07:39 Somebody gave a talk around it.

07:41 >> Lovely.

07:42 >> Yeah. Build a web app.

07:44 Building a web app with Jupyter, I think that's actually a pretty cool idea.

07:49 There's several suggestions using Voila.

07:52 I think we covered that.

07:53 >> Yeah, we've covered that before, but the other one I don't think we have.

07:56 >> IPyWidgets, I'm not sure what that one is.

08:00 So I haven't looked at the widgets thing, but more widgets within your window, sure, why not?

08:07 Why are there no, it's a widgets thing.

08:08 You'd think there'd be images on the readme, but anyway.

08:13 And then a framework called Mercury, and this shows up several times in this.

08:17 So Mercury does a lot of stuff around Jupyter Notebooks and doing extra things.

08:25 So this shows up several times in this list.

08:28 So for one, for creating a web app, which is kind of neat, especially if you're sharing data and have interactive stuff, you might have doing stuff with a web application, be cool.

08:41 Slide deck, gotta love it.

08:44 I definitely wanna try this out because using NB convert or Mercury, apparently Mercury does that too, uses reveal.js.

08:54 I think a lot of people have tried reveal.js before for slides, but having, building it within notebooks, building your slide decks within notebooks, and then having that just run, that's cool.

09:06 Building a book.

09:07 This is something else that sounds pretty interesting.

09:09 I'd like to try doing some code, a notebook, a book-like thing.

09:15 Now I don't have, I'm curious about this.

09:17 So the book, you build a website that looks like a book, but that's not a book.

09:22 So it says it can be exported to a PDF file, but I don't see anywhere you're exporting to an EPUB or Mobi.

09:31 So, you know, I call BS on whether that this is a book.

09:36 This is a website that holds book contents as far as I can tell.

09:39 Still cool though.

09:41 Running a blog.

09:42 This is something I had no idea Nikola could do.

09:44 So Nikola, Nikola, I don't know how to pronounce that.

09:48 I've ran across it before.

09:50 I'm not sure what we, if we've covered it, but it's a static site generator.

09:56 and it apparently can take notebooks files and just run notebooks as a blog.

10:02 So that's pretty cool.

10:04 - Like notebooks as a blog, oh, that's interesting.

10:07 - Well, yeah, especially if you're gonna write about like some Python technique or something, you just do a little demo of it and then publish that as a text thing, or I don't know if it outputs, I didn't read it close enough, outputs the exports every notebook to an HTML file and then publish all the files on a static website.

10:23 That's pretty neat.

10:26 Doing reports and dashboards, that's kind of like Jupyter would rock at that.

10:30 And I think we've covered stuff like this before.

10:33 But one of the things in the dashboard section that I thought was neat was this Mercury tool has a schedule option.

10:39 So once you set up the report, you can schedule it to execute, you know, like once a day or every hour or something like that.

10:47 And that's pretty neat to not have it do constantly, but update your dashboard at a time.

10:54 - I do like that.

10:55 - That's really cool, so you could have some kind of dashboard instead of creating it in the full web app.

11:00 You just publish this, but obviously you want it to refresh, right?

11:03 - Yeah, yep.

11:04 Anyway, oh, last one, REST API.

11:09 This is interesting.

11:12 I wouldn't have thought to build a REST API with Jupyter.

11:15 So I guess you can do all this stuff.

11:18 Whether or not you should, I guess it's up to you.

11:20 Anyway. - Yeah, for sure.

11:23 Anthony on the audience says, "Nicola works well as a static blog generator, preferred over Pelican." - Well, that's saying something, nice.

11:32 - That is.

11:33 - Yeah.

11:35 - Brian, wouldn't it be good to know which ones are more popular, which ones maybe you should depend upon?

11:39 - Yeah.

11:40 - All right, well Al.

11:41 - I took it over.

11:42 - Let's, that's all right.

11:44 So this one is from, let me get it right here.

11:48 This is from Tancala Ashok, And they built this thing called pip Trends.

11:55 It's modeled a little bit after NPM Trends.

11:58 And it just lets you compare the popularity of packages based on their GitHub statistics.

12:04 So GitHub statistics, that's one metric of popularity, but let's give it a bit of a run.

12:10 So what about if we type Flask?

12:12 It says, it immediately pulls up a nice little autocomplete that says Flask, a simple web framework for building complex web applications.

12:20 But then all the other ones like Flask to Postman and so on.

12:23 It's kind of interesting.

12:24 I didn't really know about Flask to Postman.

12:26 Maybe we'll talk about that next time.

12:28 But let's pick Flask.

12:28 And then it immediately says, well, what else might you consider along with this?

12:34 Like, well, how about FastAPI and Django?

12:37 And what do we have?

12:39 It also suggested Bottle for a little while.

12:41 So we'll throw Bottle in there maybe.

12:42 And let's do a search.

12:44 And it comes up with a graph that honestly surprised me a fair amount.

12:48 There's different levels of popularity, but that's not the first thing that surprised me.

12:53 The first thing that surprised me is the regular cycles that all of these packages seem to go through.

12:59 Does that seem strange to you?

13:00 - Well, I've noticed it before, and I don't really know what's going on.

13:04 Is it the weekends?

13:05 - Yes, very good.

13:06 So four or five was the weekend, six, four, six, five, and that's where the dip is.

13:11 So people download stuff less on the weekends because there's less.

13:15 Create me a new environment, create me a new project, check it out, set it up, all that kind of stuff.

13:19 Which is healthy, but there's still a decent number of downloads going on the weekend there.

13:23 - Yeah, I kind of wish that I'd like to see like a seven day moving window, moving average for API.

13:29 - Yeah, yeah, like a different window averaging or projecting function.

13:34 Anyway, what we get here is we see that Flask, sorry, FastAPI and Django are super similar, like almost tied according to GitHub statistics.

13:44 And these are downloads.

13:45 I don't think you get downloads from GitHub.

13:47 I think this is probably from PyPI or BigQuery or something.

13:51 I'm not sure where those numbers are coming from because I don't know where those are on these time series download numbers are on GitHub.

13:59 They're probably coming from somewhere else.

14:01 But yeah, you can throw different projects in here and say, "Oh, this one's relatively popular compared to that or whatever." What do you think?

14:08 >> I think it's neat, especially with comparing.

14:10 I mean, there's other ways to get the stats, but being able to grab a few related ones.

14:16 Having suggestions is neat too.

14:18 >> Yeah.

14:19 >> So it looks-

14:20 >> It also has some more information about the package.

14:22 Like if you go to Flask, it's 12 years old, it has 45 versions.

14:26 Its last release was one month ago.

14:29 Its dev status is stable.

14:31 It requires Python 3.7, gives the license and who it's intended for.

14:35 You can see similarly for FastAPI, for Django, and Bottle, and so on.

14:40 >> Cool.

14:41 Also down here in the GitHub stats, you can see like Flask, there's 59,000 stars.

14:47 For Django, there's 64,000 stars.

14:49 Number of open PRs.

14:51 Wow, FastAPI has a lot of open PRs and issues.

14:54 That's crazy.

14:56 When was the last update and so on.

14:57 So yeah, and it also gives you more comparisons down here like, well, that was fun.

15:01 What about Flask versus Django versus FastAPI, which is what we did.

15:05 But or NumPy versus Pandas, for example, you can see them and so on.

15:08 >> That's pretty neat. I like it.

15:10 Yeah, yeah. So, piptrends.com, you can check it out.

15:13 So, I want to talk about, what do I want to talk about?

15:17 Class, being classy.

15:19 Actually, being callable.

15:22 So, Trey Hunter put this blog post out called, "Is it a class or a function? It's a callable." And this is actually something that I guess I realized, I just sort of got used to with Python.

15:34 It's a lot more, if you call something, Like as if you would call a function, it might not be a function.

15:43 It might be a class, it might be an object that's callable, it might be a class object.

15:47 All sorts of stuff you could do.

15:50 Like for instance, just to be clear, we were talking about, or he talks about classes or callables.

15:57 So in like some, in like JavaScript or C++, you'd have to say new something.

16:03 So you'd have to say like a new data object or something.

16:07 But in Python, you just call date time with some parameters and you get back a date time object.

16:12 That's neat.

16:14 But so it's just, I guess, this is a good article to go through just to realize that you don't really have to care.

16:22 There's a whole bunch of stuff that act like functions and it's okay if they're not functions.

16:27 You just have to know if it's callable.

16:29 And he talks a little bit about using a dunder init to make something callable that works.

16:38 Properties are like decorators or a thing that are a callable item.

16:44 It's just a good discussion about all of this.

16:50 I thought this was a fascinating article and I'm not sure I ever really thought about partials before.

16:56 Like a partial function is like a function that creates an object and then you call it with some more stuff, and then it creates the rest of it or creates in anyway.

17:07 Maybe I got that wrong.

17:08 >> Interesting. Yeah, from Functools.

17:10 I'd never used partial before.

17:12 >> Okay.

17:12 >> Yeah. Then there's a call decorator or a call dunder method that you can use that helps out with making partials.

17:23 Talks about iterators and decorators and all sorts of stuff like that that actually act like callables, but they're not, they're like objects. The thing that I don't know where this is, but the thing there's a statement in here that I thought was amazing. So there's a, there's a page on the PyPI documentation of the built in functions within Python. And, and Trey points out that of the 69, there's 69 listed built in functions within Python, only 42 are actually implemented as functions. 26 of them are classes and one is an instance of a callable class.

18:06 And some of them in Python 2, there were more and some of them got converted. Like map and filter and range and zip used to be functions and now they're objects or classes or something.

18:20 The len function, I use that all the time, right? It's not a function. It's a callable class.

18:27 - Okay. - And zip, the like reversed enumerate range filter, use those all the time.

18:34 They're not functions, but they're callable.

18:36 So anyway, I just thought that was an interesting take on Python is different than other languages.

18:42 - It's different.

18:44 Yeah.

18:44 A lot of languages, you would never have that ambiguity, right?

18:48 But it's the kind of ambiguity that you don't need to know or be aware of.

18:51 So, I'll get all this. - Yeah, so maybe ignore this article.

18:54 No, no, no. I mean, it's interesting to know. I'm just saying like, it's not necessarily a problem that it's not super clear whether it's a class or function because you call it and it does the thing you want it to do. So you're good to go.

19:05 Yeah, like Sam Morley pointed out here, partial is useful. I think it can be pickled unlike typical closures that can't. Might be wrong.

19:16 But it just made me think about we, in other languages, they really do talk about closures a lot and things like that.

19:23 We just don't have to care. It just works.

19:25 I don't know. It just works.

19:26 >> Yeah. Very nice.

19:29 >> Well, we're at the-

19:30 >> Brian, we flew through those.

19:32 >> We did fly through them.

19:33 We forgot to plug our stuff.

19:36 >> We did.

19:37 >> Instead of a sponsor today, we've got work sponsored by us.

19:41 I want to make sure that everybody that is thinking about trying to learn something new in Python, First, check out Talk Python Training because Michael has a whole bunch of awesome courses.

19:52 And I'm sure you can learn something for just a few bucks.

19:56 Good prices.

19:58 And a new book, version 2, edition 2.

20:01 Yeah, I've had a lot of good feedback.

20:03 One of the things I love is getting pictures.

20:05 I don't know why, but having somebody take a picture either of themselves holding the Python testing with pytest second edition, heck, you can do the first edition too if that's what you got.

20:16 But either holding it somewhere unique like out in a park or near a monument or something.

20:22 That would be so cool. I love it when people send me pictures.

20:24 >> Yeah, that's awesome.

20:26 >> Got any extras for us?

20:27 >> I have some extras. Yes, you know that I do.

20:30 >> Okay.

20:30 >> All right. So this first one here, let's check this out.

20:33 So this is interesting.

20:35 This comes by way of Dan Bader, and it's the Orion Browser.

20:40 Just when you thought there was no more room for new browsers, here's a new browser.

20:44 This one is different. So you see I'm running Vivaldi these days. I love that.

20:48 Other people are using Brave, right?

20:51 And so all of those browsers take the Chromium engine, strip off the Google stuff, and then put their own shell, many times more privacy-protecting and so on, around them, right?

21:05 And we've got Firefox, which is awesome.

21:08 It's got its own engine. It doesn't do that.

21:10 But almost every other browser is, let's take Chrome and Chromium and wrap it up in our own flavor of our thing with our own philosophy on how the web should be.

21:19 So this Orion browser is that, but for Safari.

21:23 Okay.

21:24 Interesting.

21:25 So if you're into Safari, you know, it has things like on your Mac, it has better battery life and so on.

21:31 But think of it as like, I think Brave is probably the closest analogy.

21:35 It's like Brave for Safari without the crypto, but it's, you know, got built in ad blocking that's got built-in tracker block blocking and all that.

21:43 One of the big drawbacks of Safari is you don't get access to the Firefox or the Chrome extensions, right?

21:52 You just get the Safari ones.

21:54 But this one has compatibility both for Firefox and Chrome extensions in there.

22:00 So isn't that cool?

22:02 So you can run this privacy protecting anti-tracker Safari with Chrome extensions.

22:09 So it's just out in beta, I believe.

22:11 It's out in beta right now.

22:13 So I'm not sure where it is or where it's going to go, but it's a pretty interesting take, isn't it?

22:18 >> Yeah. It's certified snappy.

22:21 >> Certified snappy.

22:22 >> I like it.

22:23 >> Indeed. I really like its privacy aspect.

22:28 >> I think the privacy space, and you brought this up, the privacy space is there's convenience and there's speed, but I think that's a place where people can, we can open up the browser wars again.

22:42 - Yes, for sure. - Because in a good way to try to limit some of the privacy concerns or minimize them.

22:51 - Yeah, nobody at Mozilla asked me, but I'll give it.

22:54 You know, Firefox is having trouble sort of keeping its market share.

22:58 I think if it could triple down as the browser that you cannot be tracked with, the browser that will absolutely preserve your privacy and then add services around that.

23:09 I think that would be great.

23:10 The big challenges, well, I guess, you know, they're 99, 90% funded by Google, an ad company who doesn't want that.

23:18 So there's this, this interesting tension, but I think, you know, that's a path that I think Firefox should be taking as well, but.

23:24 - I guess I forgot about that, that Google was so, such a big stake in Firefox.

23:31 - Right, I think that limits their playbook.

23:33 I think they can't do things like we're going to make it.

23:35 So we're invisible if you use Firefox basically, because their biggest supporter would not totally love that.

23:42 Would they?

23:43 So anyway, this is a zero telemetry, a telemetry browser and whatnot.

23:48 And you can go and download it.

23:49 Apparently it works on, Apple Silicon and Intel, but obviously being a Safari wrapper, I believe it only works on.

23:58 I, I think, Mac and iOS things.

24:02 I think iOS, iPad and macOS, but if you're on those, it's a pretty interesting take.

24:07 And just from the browser wars in general, I think it's pretty interesting to track.

24:10 Yeah, definitely.

24:12 It's cool.

24:12 All right.

24:13 One more quick extra and then off to you.

24:15 So last year we all did the PSF plus JetBrains developer survey, which is supported by and analyzed by JetBrains, but is really a PSF survey.

24:27 and we had 23,000 Python developers and enthusiasts participate.

24:32 Well, the results are out, so people can go check those out.

24:35 Now, I've got a whole lot more analysis that I'd like to do before I talk about it.

24:40 But they're already out, so people can start looking on there, and I'll give you more details next week.

24:46 Yeah, cool. We should definitely cover it next week. That'd be fun.

24:49 Absolutely. All right, how about you?

24:51 I've got a small thing. I'm not sure, really needed an entire section, but Ned Batchelder did what's in which Python. So it's a page that has basically everything from, what did he have, from 2.1 to 3.11, just a hand, not like everything that's in every version, but some of the big hitters that you might, you know, you might know. So like 310 has union types and structural pattern matching. And what, what do you get with 311? Well, we know it's faster, but do we get like how much, and it's 10 to 60% faster than 310. That's amazing. And then exactly.

25:35 That's really amazing that after 30 years, they're like, oh, you know, this year we're going to make it 50% faster. Like that's, that's incredible. I'm glad that's happening.

25:43 >> Yeah, and then the new module Tomlib is coming, which is interesting that we've got pyproject.toml, and it wasn't part of the standard library yet.

25:55 But a whole bunch of things, like if you can't remember, if for some reason you forgot f-strings came in, then what was it?

26:03 3.6, apparently I forgot.

26:05 They came in 3.6 because it's on the list, unless Ned got it wrong, which probably didn't.

26:11 >> No, I think 3.6, I think that's the biggest mover for 3.6 there.

26:15 >> Yeah. Data classes in 3.7.

26:19 Yeah. Lots of cool stuff.

26:21 >> Fantastic. Henry Schreiner out in the audience says it's the top features from each of the versions since 3.0.

26:28 So not everything, not extensive, but the big hitters.

26:31 >> Yeah. I wasn't going to say top because there's a lot of people that worked on a whole bunch of other stuff that are on the list and I appreciate them as well.

26:39 >> Yeah, absolutely. Some of it's just setting the groundwork for the next amazing thing.

26:43 >> Yeah. Well, let's wrap up the show with something funny.

26:47 >> All right. Ready for a joke?

26:49 All right. This is a joke by Jen Gentleman, but called to our attention by Luke Morley.

26:55 Jen says, "A programmer had a problem.

26:58 He thought, I know, I'll solve it with async.

27:00 Has problems now, period, to he." Because of race conditions, of course.

27:06 >> Yeah, I like it.

27:08 >> I like it too. Quick and simple, but there's a lot of variations on that joke and they're all good.

27:14 >> Yeah.

27:15 >> Most of them are good, I guess.

27:16 >> Anyway, well, thanks again, Michael, for joining me today and it's a great episode.

27:20 >> Yeah, as always.

Back to show page