Python Bytes - #401 We must replace uWSGI with something else
Episode Date: September 17, 2024Topics covered in this episode: “We must replace uwsgi by something else” Let’s build and optimize a Rust extension for Python Fake recruiter coding tests target devs with malicious Python pa...ckages Monthly PSF Board Office Hours Extras Joke See the full show notes for this episode on the website at pythonbytes.fm/401
Transcript
Discussion (0)
Hello and welcome to Python Bytes, where we deliver Python news and headlines directly
to your earbuds. This is episode 401, recorded September 16th, 2024. And I'm Brian Ocken.
And I'm Michael Kennedy.
And this episode is brought to you by Scout APM. Check out their section later in the show.
Connect with us, Michael, Brian, or the show at Fostodon.org. But any Mastodon will work.
But the links are, we're all on Fostedon.
M. Kennedy, Brian Ocken, and Python Bytes.
And of course, those are in the show notes.
And if you'd like to join the show live, head to pythonbytes.fm slash live.
It's fun to do it at least once.
Check it out.
See what it's like to watch us in real time.
And we're going to try something new today.
We're streaming on X, no?
We're trying to stream on X, but when I hit go,
it actually said you need a premium account.
So maybe we'll try that next week.
Oh, nevermind, sorry.
Or maybe we won't do it at all.
I don't know, YouTube's good.
Oh, okay.
And Michael even said to keep that quiet, but I just, you know, sorry.
I was pretty excited.
All right. I know.
Well, we'll try it out.
I think, you know, reaching more people, letting them participate is great.
And we can give it a try.
And, you know, we've told people that we both have courses
and there's other stuff, but we're going to there's a there's a treat at the end.
If you wait till the end of the show, we've got some extras
that we're going to talk
about with some of the courses. It's pretty exciting. So, but that's not now yet. Now we have
whiskey, whiskey, anybody. This is, this actually might make you want to drink this whiskey,
micro whiskey in particular WSGI. And some people say it web service gateway interface,
the friend and sibling parent. I don't know what the relationship of, of ASC interface, the friend and sibling parent.
I don't know what the relationship of, of ASCII, the async gateway interface.
Anyway, this is something I ran across just, I was doing some work with.
Grannian.
So Grannian is the web server that powers Python bytes right now.
And a couple other things as you might imagine.
And I was looking at it and it had a back reference.
And one of the issues that was a feature I was asking about, namely worker restarting after a certain amount of
work gets done, things like that. And it was coming from, I believe this comes from edX,
some edX project, though I can't tell by the organization. Anyway, the title of this GitHub
issue is, this is them speaking amongst themselves
in this project called Tutor. We must replace micro-whiskey with something else. Like, wait a
minute, why must we do this? Wait, let me see what's going on here. So this is somewhat news to me.
The very opening here by, let's see, who wrote this? Regis Bemo wrote, micro-whiskey is now in
maintenance mode. And sure enough, if you go over to read the docs,
it says, note, this project is in maintenance mode.
Only bug fixes and updates for new language APIs.
Do not expect quick answers for GitHub issues
or pull requests.
Sorry about that.
A big thanks to all users who have contributed
over the last 15 years.
That's awesome.
However, I don't think that's awesome.
It's awesome that they've
been working on it for 15 years and people it's had such a good run. However, the part that's not
great, as you point out, Brian, is this is a critical piece of internet infrastructure when
you're on the internet. If this is running your app, right, this is the thing that handles all
Python requests and effectively has an open socket to the
internet and anything that just listens on an open socket on the internet especially stuff written in
c should make you nervous right it's just it's there uh for for whatever might go wrong and so
there's a couple of things going on here one it's kind of it's not fully fully abandoned but it's
nearly fully abandoned right and that's not great the other is it i kind of, it's not fully, fully abandoned, but it's nearly fully abandoned. Right. And that's not great. The other is it, I don't believe it
supports asynchronous programming. So if you want to do anything and async and
await in your web apps, which is becoming increasingly popular, there's
also not an option. So just for lots of reasons, it's probably time to find
something else. And so they listed four things, some of which I would not recommend, but maybe
they're, maybe I'm wrong about it. G-Unicorn, which by the way, some people pronounce Goonicorn,
but Brian, what is their logo? It's a unicorn. And what color is it? Green. It's a green unicorn.
I'm pretty sure G-Unicorn stands for green unicorn, not Goonicorn, but you know, y'all
say it how you wish, but G-Unic is how I say it because it's a green unicorn.
Mod Whiskey, Cherry Pine, Waitress.
I don't hear of any of these as being kind of high-end production servers.
Like Waitress is included with Pyramid as a debugging one, for example.
So looking through, it says some people are suggesting EngineX unit,
which is like a Python worker process that can run inside of EngineX that could be interesting.
This is how I found out.
Someone says, hey, maybe we should look at Granion.
And Granion, I've had Giovanni, the guy who creates it, on TalkPython to talk about it.
It's written in Rust.
It's super stable in terms of its performance fluctuations.
It's it's pretty nice.
And so that's what we're using now before that it was G unicorn.
I think there's some good options, but the long and short of it is
micro whiskey is now in maintenance mode.
And while that's not, you know, end of the line for it, I would start
making plans to not be running on my course if I was you anywhere.
You know what I mean?
Okay. I mean, that's, I'm actually actually i'm interested to hear if we get any feedback from listeners that
there might be other options or what the recommendations are let us know probably the
best place would be to comment on the youtube video put it below there that's that's kind of
our comment sections these days yeah nice okay all right Over to you. Well, I was interested.
Actually, I have a project where I was thinking about writing a little segment of it in Rust, even though I don't know Rust yet.
But I was interested in a lot of places are optimizing little bits of their code with Rust instead of C now.
So this is a great article from Itamar.
I think it's Itamar Turing. Turing is a great article from Itamar. I think it's Itamar Turing,
Turing, Turner, Turing, anyway, Itamar. It's an article called Let's Build and Optimize a Rust Extension for Python. And I really love the like the focus of this. It isn't like,
it's the focus of it really is, I've got one algorithmic function that I want to speed up.
And that's, I think that's a great place for maybe not building a package for the rest of the world to use, but internally for internal tools, that's a great way to look at things.
So his example is a thing of counting unique values.
And you could just count them.
The exact count is using sets and the length of a set, but everything in a set.
But but he says, if you've got 10 million items, it'll be a set with 10 million items in it.
So there's a space limit there.
So and then you take the length of that.
So I'm in there, you know, you probably count things or something.
But the how do we speed that up? And one of the algorithms is a,
it's called a very simple algorithm from,
I'm not going to try to pronounce that name,
but he has a link to the algorithm that's getting an approximation of the
answer of how approximately how many.
And so he just implements that whole algorithm in Python and then,
and then runs it and, and then, and then runs it and,
and it,
and then runs it against the exact count.
And it's pretty close.
He runs it a few times and he gets different answers,
but that's a crazy algorithm.
Yeah.
Oh,
did you read it?
Well,
just looking over it real quick.
It's,
you know,
given a iterable make some,
and how fast adding new items is increasing the duplicity or lack thereof.
Yeah.
That's pretty wild.
It is.
It's pretty close.
And I remember reading about this algorithm recently also.
But anyway, it's kind of a neat example of, okay, let's try this algorithm out.
And there's other algorithms for approximating uniqueness as well, comments later.
But he just took this one because it's kind of a
small algorithm. So it kind of works. And so let's, he did a speed comparison, and it's
significantly slower. It's the exact count is point is point one, four seconds, and the
approximation is point seven, eight seconds. So it's, it's a lot slower than the exact count.
But it takes up tons less memory so if you
have a like memory constraint that's important and also if you're just do an example from a
small count but you have a huge set that you're really going to count you want an approximation
so um so this is a great a great setup for how do we make this faster in rust and so he actually
walks through all of the steps like you haven't done this before
um let's get maturing and pi 03 and set up a project um so he's even like uh just maturing
new rust counterprox project um uh and then uh goes into it looks at looks at what the project
set up already it's got some cargo toml files pi project.toml and a source file
um and uh and then he just does it right there and and figures out how to install it you can already
install it even though there's nothing there in the example project which is kind of cool um he
did look into it it needs uh rust doesn't have a random in the example or the algorithm uses random
so um this is kind of neat too is is how do you, introduction of how do you add dependencies
and it's cargo add rand
and that adds a dependency to your project.
So that's it.
You've got PyO3 and rand as dependencies.
And then he just basically translated
that algorithm directly to Rust.
And I kind of like that idea
of having just a side-by-side
comparison and i'm thinking about like putting these in two editors so i could see them side
by side exactly um uh okay so so that that thing and then how is it faster it's it's it's like
twice as fast as the python version but you would think like aren't we supposed to have like blazing
speeds with rust?
So, and I kind of love that he picks something that like, isn't as, isn't as optimal. Like I don't want that much, but like twice as fast, I want it to be super fast. So
he also goes into some optimization. So first, first off is link time optimization.
It's just an ability. And since, since this is a Rust application that you're going to not, you know, it's fine to
take a little bit extra time in linking to make it faster runtime. Go ahead and turn that on.
And then he was looking at the random number generator. There's a couple of ways to speed
that up. One of them is to use the small random number generator. It's like less random, but,
you know, good enough. It's not cryptography yeah and then um and then
also there's uh instead of storing in part of the algorithm he's storing items and he's like
instead of and later taking hashes and instead of storing the items just store the hashes and then
um and then uh rust or rust is a thing like you can optimize the dealing of collections if you tell it that you're just storing hashes in there so it doesn't try to rehash your hash.
And so it's like a no hash hasher, another dependency.
But that optimization altogether makes it even faster.
But it's 0.21 um so it's uh uh like what almost four
times faster like a little three and a half times faster than the native the python version so
that's better uh then it talks about partially other things but it's i don't think this is a
really about how much faster his implementation of this was. These are the steps if you want to go through
and speed up a chunk of your Python code.
This is a good list of how to do that.
Yeah, looks great.
I love the walkthrough, and it's not a huge project.
It's not a huge rewrite in Rust.
It's just this function's slow.
Let's make this function fast.
And I think that's exactly how I'm going to try
to probably learn Rust,
is I'm not going to try to learn the whole language.
I'm just going to learn enough to optimize something,
and then build on that.
Yes.
Now, before we move on, two things really quick.
John out in the audience points out,
says, I believe ModWhiskey is an Apache plugin module,
which I think he's right.
And I think that's as well.
And I just wouldn't really want an Apache plugin.
I would kind of like a thing that's a little more dedicated.
But yes, I agree.
And then waitress is one of the few options available on Windows-based server platforms.
Okay.
That's interesting.
The context of the GitHub issue I talked about before was a Docker image.
And so I'm pretty sure it was Linux.
But yeah, I didn't know about the Windows aspect there.
And I didn't point out, well, what would I have picked?
So reasonable options to Michael sound like Grannion, which we're using
UVA corn, which used to be a kind of dev thing, and you could plug it into Gina corn with UVA corn workers, but actually it's now its own standalone
thing with worker management and stuff.
So UVA corn is its own possible option.
Now, hyper corn from Phillip Jones in court, and then Gina corn with UVA corn workers its own possible option now. Hypercorn from Philip Jones and Court.
And then G-Nucorn with UVA corn workers for async stuff.
So anyway, putting a bow on that one.
Okay, so you have a few things you do instead.
Yeah, I'm just using Grandian right now, but all those would be good options, I think.
Okay.
Let me tell you real quick about Gout 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
thorium 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
slash 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 slash scout. Check them out.
It really supports the show. Definitely. I'm next, huh all right what if brian what if you were super
excited finally be contacted by a recruiter for one of those jobs you're looking for yeah and
really all they wanted was your passwords your bank login and your crypto dear to hear that is so
why can't people be better you know some people just suck So the item I want to talk about comes to us from Reversing Labs.
And pretty cool logo there with the reversed R for Reversing Labs, I got to say.
And the title is Fake Recruiter Coding Test.
Target Devs with Malicious Python Packages.
That's not ideal.
And I don't know why we need to have the word Python packages in here.
Just malicious Python code.
Because a lot of it comes from GitHub repositories, not IPI. So yeah, I don't know. I think kind of put the packages to the
side. Like that's not germane to this really. What is, is people are using recruiting tests.
So a lot of, this is something that I never encountered in my, yes, I never encountered
this in my entire life, a take home exercise or something. It was interviews and it was live sort of code
performances or whatever, I guess you would call them, but never take home. And that's just
something that's becoming really popular for better or worse. All right. So reversing labs
found the VM connect campaign, which I don't really know much about continuing with malicious
actors posing as recruiters using packages and the names of financial firms to lure developers.
So that's pretty bad. What's happening here? So this is not exclusive to Python. It's happened
through NPM before and so on. And this seems to be tied to North Korea's Lazarus group,
a ATP group. That means bad stuff. They're pretty skilled. But here's what happens.
They found that people are getting these requests for coding tests and it says,
here's your, here's your coding tests. And if you look at it,
I think I can even zoom it here. Well, not really. It kind of assumes anyway,
it says here's a fully functional password manager in Python. Basically this,
you can see some grammatical errors in there. You might,
that might clue you off, but probably not.
This is a fully functional password manager that possesses almost all of its features.
And here's an image.
And this is the important part before making any modifications, ensure the project is running
successful.
And if you trusted this organization, you were really keen to get going like, all right,
well, let's just, uh, I know what I'm doing.
Python space, this boom, boom.
It's the running of this project that they delivered to you over GitHub or some other,
they just sent you a thing to unzip and run that then downloads all the code,
installs backdoors and various other malware into your machine.
And then you probably go on to finish the work and submit it and never hear back, oddly.
Yeah.
And then somebody is actually like finishing the assignment and not
yes i know it's so sad sucks so much oh that's terrible yeah let's do this the analysis revealed
that the direct parent of the detected malicious files is a python pyc file so that's how they
obscure it as part of what they give you are pyc files not python source files so
you can't really see inside them oh and you and you kind of think oh well that's legitimate because
it's a uh because it's an interview i there don't want to show me to show me the source code or
exactly yeah it totally makes sense because yeah if i saw this well then i would be able to nope
your job is to have this opaque thing and write this one part. But no, it's just the opaque part is a virus.
Oh, that so sucks.
It totally does.
Yeah, so I would...
Go ahead.
Do you have recommendations?
Well, let's hear yours first.
Oh, I was thinking that...
So I've both taken interviews like this, coding exercises, and given them.
But in, let's see, most of the times times i've only given them in text form i've
given a description and then somebody can like email me back or um or submit um on a form the
what code for answering it um and then also since there's ai and everything or you could just like
hire somebody to do the code for you um that code I then use as part of the interview process.
Like we'll talk about what choices they made in the code
during the actual talking interview.
The other thing, and I've had that happen with me as well
when I've done coding exercises.
The other thing is using platforms.
Like there's online platforms.
You don't install anything on your own computer during a coding exercise. And I would be more
willing to do that than, than believe somebody. But I know there's a lot of GitHub based,
like there's a private repo you get add to, and then you can go and try to take the,
do the coding assignment. I know that happens and I would just, I probably wouldn't do it,
I guess, or I don't know, but. Yeah, yeah sure i think some other things that i had in mind was if you're just
trying out a docker container and something real simple i'm sorry uh python package i'd do it in a
docker container you know if you just do it on the terminal or like a simple editor just fire up a
docker container shell into it you know docker exec GSH or bash or whatever, and then play with it over there and then throw the container away.
Or like you said, there's a lot of online platforms.
So for example, I think VS Code has, you know, code.dev.
Is that right?
I can't remember what it was.
Like if you open up GitHub and just press dot, whatever happens there, maybe you could do it there.
Maybe not. just press dot whatever happens there maybe you could do it there yeah maybe not uh probably what
i would actually do is i would fire up a virtual machine that has snapshotting capabilities and by
snapshot i mean like save how it is now on the on the disk and then make a differencing disk and
then when you're done with the project just throw away the snapshot the the different reset to the
snapshot right so that's long as it's you're not afraid of it being potentially on your network right but if
it's in a vm it's probably pretty safe right and then also you could go over to azure and get a
windows machine windows vm that you can remote desktop into that's a full windows machine in
the desktop yeah in the cloud as a desktop you log into right there and just throw away the virtual
machine because you know then it's not
even on your network right yeah i think and as much as i like using my own editor i think that
i'm i think that people that are giving coding exercises really should use a platform uh because
it's just more fair for everybody the um um and the even our friends at pybytes have their own
interview platform that you can do you Interesting. Do their little things. Matt agrees
with you. Plus one for coding platforms.
Alright.
Folks, be
on the lookout. Be careful out there.
It's the internet. Well, is it
my turn? I think so.
Let's talk about office hours.
So the PSF
has announced that the PSF
board is having office hours, which is kind of cool.
They're going to do it monthly.
So if you have a question, what do they say?
Greetings, Pythonista.
I'm not going to read all of this, but the PSF is going to open up office hours monthly.
The office hours will be sessions where you can share with us how we can help your community and express
your perspectives and provide feedback to the psf and hopefully everybody will be nice but
had an issue with people being nice so try to be nice um then also uh the joining of the office
hours there's there's we missed the first one it was september 10 but there's one in october 8th
and then um and then there's you
know there's a list here we've got well i'll just put the list in the show notes also um what do you
what are they going to talk about well they might have uh they might have a topic but um uh they
also might not so it says that you can bring up i can't remember where it said this but you can
bring up there'll either be a topic but if there's not a topic you can bring up something that's
python related or something that the board might be able to help you with so
that's really cool i love the accessibility the that that people have access to yeah i think it's
kind of cool i think it's kind of like it kind of reminds me of uh you know you can um i've never
gone but my my little local community that i live in um I can go watch the city board meetings if I wanted to.
I don't do that, but I like that it's possible that I can.
So it's a good thing.
So thanks, PSF.
Yep.
Yeah, very cool.
All right.
And I kind of made this one short
because I know we've got quite a few extras to talk about.
Do you want to kick off the extras?
Let's kick it off. This is a good
one to kick it off with because this is a joint extra. Big news is our courses, mine, yours,
and our friends are on Humble Bundle for a couple of weeks. So if you want to get what I think is
probably a ridiculous deal, like $1,882 worth of content for $25.
Check it out.
One of the things that's unique about Humble Bundle,
if you're not familiar with it,
and partly why we're participating is a lot of money goes to charity.
Right now it's just launched,
and so far it's already raised almost $3,000 for charity.
That's pretty cool. Traditionally, over the years, we've worked with Humble Bundle
and raised a lot of money for the PSF and for other organizations through this.
So this year's charity is Girls Who Code.
So check it out.
And there's stuff from me, from Brian, from JetBrains, from Matt Harrison, from Reuven Lerner, from PyBytes, RealPython.
And anybody I'm leaving out there? I don't think so.
But yeah, what else do you want to say about this, Brian?
I'm kind of excited about checking out the
CPython internals. I've put off
looking at that, and I think I might
grab it so I can read that.
Also, I think my
Visual Studio Code plus Python skills
are pretty good, but I'm curious to know
what your course has in there.
There's actually quite a few goodies in there.
And also, it's ridiculous.
I'm including both the new Hello PyTest course and the Complete PyTest course and the PyTest course on your side.
I know that's kind of a lot of PyTest, but I kind of think about it a lot.
So a lot of exciting people already joining
and I'm getting some great questions
in the community forum.
So that's really good.
Even some great feedback.
Yeah, it's awesome.
So I'm pretty excited about this.
All right, so this is one among many extras,
but do check that out if this sounds interesting to you.
It's a lot of stuff and it's for a good cause.
Okay, next, I believe we've talked about the Django knot program before, which is super cool.
I've had Sarah and Tushar on talk Python and linked about that as well in the show notes,
but the news here is that Django knot space session three applications are open. So get in
there and apply. This is a program that helps you become
a contributor, possibly on the path to core developer for Django. And I think it's really
cool program, free eight week group or group mentoring program. Cool. Yeah. So if you're
a fan of Django, you want to get better at open source. Here we go. I'll, like I said,
a link to this, um, two more things real quick, one planned and one, a surprise alt tab. If
you're on windows, all tab is the way you switch
between apps on mac os if you switch to mac os things get weird like command tab seems like the
alt tab but command tab switches between applications not between windows so for example if there's like
a hey there's an update available for your app and then it goes behind another window there may be no
way to keyboard over to it you might have to hit control down and then find it because it doesn't register as like
a top level application, but it's there.
And like you want to switch between two windows and web browser.
I know there's command tab, but that, or sorry, command tilde, but that just cycles.
That doesn't give you a list.
So alt tab is a free open source thing for Mac OS with a ridiculous amount of options that has a super cool ui for
switching between windows not um not applications and like i said it open source but also it doesn't
take over the typical commands so it's an either or whatever you feel like hitting while you're
working on mac what do you think brian cool yeah actually i don't i never even tried any of this stuff i just usually don't have very much open or i have no idea how to find my stuff yeah but if you look
over on github it's got 10 000 almost 11 000 stars it's pretty neat yeah so anyway people can check
that out if they want and this is the prize this was not true when i hit when we logged in to hit
record today however since then the Mac
OS Sequoia the new version of Mac OS is now out now if you go to the website
apple.com slash Mac OS it says it's in a preview but if you go to a system
settings it says would you like to install it so I don't know if people
want to live on the cutting edge there you go it's time I'll let you do it
first and then if you're if your computer
still works to log in next week i'll upgrade if you ever hear from me again then it'll be fine
yeah sounds good anyway those are my extras okay um i i think that we should cover this earlier but
oh well um high cascades has the call for proposals is open, maybe we covered it. I just don't remember.
But anyway, CFP is open, but you only have a few days.
It's September 16 right now, and the deadline is September 20th.
So if you haven't gotten those in yet, get those in.
And mostly I'm bringing this up because I forgot,
and I'm going to submit a couple.
But it's going to be exciting because it's in Portland.
Yay, it's in Portland.
At least i'll
be there will you be there probably unclear maybe clear okay let's give it a strong maybe
well i'm gonna try to make sure to be there so yeah that'll be nice i love pike escates okay so
that's uh my first um and that's in february um so last week we talked about all the UV Python stuff being super cool.
But we mentioned that you can't do Python 3.13.
Well, you can now.
So Python 3.13 is now available for virtual environments and for anything with UV.
So UV supports Python 13, but it does not subvert.
If the next question is, can do the man the uh the what
the other one uh free threaded can we do through free threaded no not yet um but hey it's i think
it's great to just support the normal one so that people can get their stuff in so uh i think that's
all my extras so awesome awesome awesome anyway thanks. Yeah, I just I just want to quickly add that I tried UV Python list dash dash
Python preference dash online only managed and it didn't show re 13 or 12.6.
But then a UV self update, run it again.
So I just beware, I think you have to update your UV to get it to show the
thing that you brought that up.
I was gonna say that.
Um, yeah, i forgot you and also i think uv self-update is such an awesome thing uh you
just have to it's it's a great name self-update i wish i wish i had brian self-update um that'd be
that'd be cool exactly he's getting a little old and beat up self-update oh there we go yeah nice power we can't rebuild them okay okay let's get something funny all right well i was saving this
for the in november when we have the election in the u.s this is not political people so please
don't write me but this is a tech joke but since biden dropped out, you know, the jokes kind of got a shelf life. Let's, let's go. So here it is, Brian errors, four or four and four or three went voting.
Four or four voted for Trump or three or three forbidden.
Oh, oh, Biden. Oh dear.
Cause four or three is forbidden. But anyway,
that's what I got for you today.
That's terrible. Yeah. it's definitely a dad joke okay uh i've got a good one for you next week so all right yeah let's do it all right looking forward to it and yeah thanks thanks
to everybody for showing up and and i'll remember uh check out um the humble bundle we appreciate it
yeah indeed all right bye