Minimal exceptions, time wardens, and ultimate validation
Download MP3This is the Laravel News podcast, your one stop podcast to find out about Laravel related news, tutorials, packages, and more. Here are your hosts, Jake Bennett and Michael Dyrynda.
Jake:Hi-de-ho and and welcome back to the show, everyone. Today is June 5, 2124, and this is episode 216. Thanks so much to Mailtrap for sponsoring the show. We'll tell you more about them later in the show. But for now, my wonderful cohost, mister Michael Dyrynda, with his Lakers jersey Lakers warm up.
Jake:Not jersey. His Lakers warm up on. How's it going, my friend? No.
Michael:It's a yeah. It's a it's a jacket. It's going well. It's you know, I feel like I'm gonna complain about how cold it is for the next 4 or 5 months. So let's let's breeze past that.
Michael:Let's talk was it this was it this no. It was not. It was our other podcast that we talked about the basketball. So maybe we can skip the basketball talk.
Jake:We can skip the basketball talk. We can skip the basketball talk.
Michael:All I'm gonna say is Dallas in 6.
Jake:Okay. Dallas in 6. Hey. It's since we're gonna skip basketball, I'll ask you real quick. Have you ever played pickleball?
Michael:No. I know what it is. I've seen, like, about the place that it's becoming a thing here, but I've never never played.
Jake:Yeah. It's kinda fun. So my brother-in-law just texted me. He was here for Memorial Day in in the US, and he taught me how to play pickleball. It was really fun.
Jake:And he just won a tournament, I guess, at a conference that he was at. So that was that was kinda cool. So they had, like, a little mini pickleball tournament he won. So I was like, that's fun. So anyway, yeah, I just got a couple of new pickleball paddles in the mail.
Jake:And so any of you folks we should do this at Laracon. If there's if there's a good weather in Texas and there's a pickleball court around, which I'm sure there will be, we should do a pickleball tournament. That'd be fun.
Michael:If it's not like a 120 degrees
Jake:We probably will be.
Michael:Dallas is in August.
Jake:I know. I think that's why he did a little bit later than usual this year is because because he wanted to give a little bit of time to cool down. So, hopefully, we'll see everybody there in August at Laracon. That'd be really fun. Well, my friend, should we jump into it?
Jake:We've got some releases to talk through. We've got some news, some packages and some tutorials. So for the most
Michael:time in a while.
Jake:I know. For tutorials, let's we've had our, the writing staff here has been busy. We've got, Paul Redmond who has got a new profile photo who's been who's been doing some writing. He's got 2 of the 3. Let's take a look.
Jake:Is he got the third one as well? I don't think he does. This is a little bit Ash Allen. Oh, Ash Allen.
Michael:Ash Allen has written a a novel.
Jake:I don't know what he has. I was gonna say this one's longer than the typical Paul Redmond one.
Michael:30 minute. Yeah. 30 minutes of grading there. So
Jake:Josh Allen. He's a he's a good one. He's a good one. Okay. So let's get into it then, starting with releases.
Jake:Laravel 11 dot 8, a new validation rule and the ability to manually fail a command in Laravel 11.8. This week, which was the week of May 22nd, the Laravel team released version 11.8 with this new validation rule and exactly what we talked about just a moment ago. So show events in the model show command. Wendell Adriel contributed an events section to the model show commands. This is if you type PHP artisan model colon show in the command line.
Jake:What this will do is this will, display any events defined on the dispatches events property. So what this does, I believe, is you can, specify what events should be dispatched on a particular model event, I think, is what that does. Does that sound right?
Michael:Dispatches. Yeah. Like, you're seeing that only specifically in there in that dispatcher's events property.
Jake:Mhmm. Correct. Only in that dispatcher's events property. Correct. Yep.
Jake:And so you can take a look at that through the command line now, which is a nice little thing to to be able to do without having to get into the code. You can just throw that right in the command line and get that data out of there. Secondly, Andrew Brown contributed a contains validation rule that checks to make sure that expected values are included in the given array of input. So for example, here, in the PR's description, we have, an example that ensures that the user's IP is in the allowed IPs. Alright.
Jake:So you can also pass multiple parameters, which would require that all the parameters are present in the array of data. So you can check that out in 51348, poll request 51 348. And so, thank you to Andrew for contributing that one. Len Woodward. Is this somebody I know?
Jake:Len. Please. I'm thinking I think yeah. I was thinking, Leonard, but, Len Woodward. Len Woodward contributed the ability to manually fail an artisan command outside of the handle command.
Jake:So, what you would do is inside of a method maybe called trigger failure, you can call this fail and that will manually fail the job. So you don't have to be inside of the handle method of that command in order to make it fail. You can make it fail from anywhere within that command using that this fail convenience method. The pull request has details and examples for how this could be useful, over a few other existing approaches to failing early in the command. Ryan Chandler contributed a view flag to the make mail command that will create an empty blade file and configure the created mailable to use it by default.
Jake:It works the same way as the existing markdown option, so it just saves you the manual step of creating and writing a blade mail template. So, if you use dash dash markdown, it will do the same thing, just generate something that uses markdown. But in this case, since using dash dash view, it will create a blade file and configure it for that. That is all for 11.8. You can find the diff between 11,718 on GitHub, of course, and you can find a full change log on GitHub.
Michael:Nice. Just before we do move on to the next release, Len Woodward was tweeting the other day about this project that he's working on called Conductor, which is like a PHP version of npx. So npx, to my understanding, is is this thing that you can install and it allows you to run a NPM dependency in your application that isn't actually installed. So it's not it's not a dependency of your package of your application. It's not installed globally.
Michael:You can just run it. It'll fetch the binaries. It'll run the script, and it'll clean up after itself. So this Conductor is the same thing. It leverages composer to kind of pull down the thing in a way that is not going to conflict with your application structure.
Michael:It'll run that binary or whatever it is, and then it'll remove it again, which is an interesting project, something that we haven't really had. I know I've seen a few attempts of it in the past, but, yeah, Len's Len's working on that. I'll include a a link to his a little announcement about that in the show notes as well. It's just Yeah.
Jake:He does he does a good job. He's created a couple of these sort of command line utilities, in the past. The other one that he did was oh, boy. What was it? Was it whiskey?
Jake:I think it was whiskey. And so that was, like, get hooks. And, I remember so we I we actually met at, PHP Tech in Chicago last year, and he was working on that there. And the stuff he puts out is really high quality. It's it's really good stuff.
Jake:And so definitely check that out. And I think also he's I think he might be looking for some extra clients right now. So, Len, shout out to Len if you, if you need some good work done. I think he's got some availability.
Michael:Okay. A new minimal default accepts exception page with dark mode support is coming in the Laravel 11.9. So the Laravel team announced, the week of 28th May that Laravel 11 will now ship with a minimal default exception page when your application debug mode. The updated error page has both light and dark mode support, and it really kind of cleans up. So we've we've had in Laravel sparsity's ignition package for a long time.
Michael:And I think the the general crux of of this change from Taylor's perspective, what he what he was posting about on on x was that it's just something that the Laravel team can then have first party control over so they don't have to worry about anyone else to sort of keep it updated. If there's any issues, they can just address it straight away and and and fall under the same kind of maintenance structure. So this collapses a lot of the vendor frames, gets them out of the way. It shows you basically the things that that you actually need to see when it comes to the exceptions. You can still, of course, if you want and prefer to use the Ignition package, this is just what will be the new default moving forward.
Michael:The exception page will continue to render the default Symphony view unless you've defined a custom renderer when debug mode is set to false. The update only affects new Laravel applications, so existing apps will still use Ignition if installed. And if you would like to continue using the sparsity Ignition Exception page, in new Laravel apps, you can install it manually, as I said, by using a composer require Sparsity Laravel Ignition. Jmac, Jason McCreery, and Joel Claremont have contributed a new prohibitable trait along with code that prevents destructive commands from running in your applications. You can also add these to your custom artisan commands that might have destructive behavior that you don't intend to run-in some environments, which usually is production.
Michael:So you can attach the use prohibitable trait to your commands, and this will effectively prevent it from being run. And then you can call, for example, in a service provider somewhere, some destructive command, dodop, prohibit, and then pass it a a truthy or a false, you know, a Boolean evaluation in there. So in this case, you'd say some destructive command, dotop prohibit, and then pass it this app is in production. The Laravel framework does include some database commands that include the prohibitable trait by default. This includes db wipe, migrate fresh, migrate refresh, and migrate reset.
Michael:You can prohibit them individually or use the DB facade to prohibit all of those commands in production using the DB.op prohibit destructive commands and then pass it again this thing. So this is one step further. We already have already had in place the ability to detect if you are running in production and you would get a prompt to say you're running in production. Are you sure you want to do this?
Jake:Mhmm.
Michael:This takes that a step further. So if you just, like, go yes, it will actually then prevent you from running that destructive command, irrespective of you wanting to try and force. So just that extra layer of protection. I'm sure, you know, there is a non zero number of people out there that have accidentally dropped a production database because they haven't been on the correct host or whatever when they were doing things.
Jake:So Yeah. Exactly.
Michael:To J Mac and Joel for that one.
Jake:So question on that. So would you would you run that or have that prohibit inside of, like, a app service provider or something? Is that what you Yeah.
Michael:Where you put that in there? Yep. Yep. Yeah. So we usually put all of that kind of controlling stuff that is environment based into an app service provider, until, you know, we need to split it into scrape providers for different functionality or things like that.
Michael:But absolutely, this provider is in place to just dump all that stuff to begin with.
Jake:I was wondering if there was a way to do it from inside the command itself. Like, it's using the command is using that prohibitable trait, and then if there was, like, some way to say, like, prohibit when, and then you would say app as in production inside of the command. So you don't have to go inside of the command. So you don't have to go somewhere else, but I don't think so.
Michael:Current iteration
Jake:of it, but
Michael:I think, potentially, it could be something that could be added later on.
Jake:Yeah. Yep.
Michael:Yeah. Kennedy Tadesco contributed a without delay method to the queueable trait. So if your job has a default delay time, you can use this in cases where you want to skip that delay instead of passing 0 to the delay method. So you just do instead of saying dispatch new my job arrow delay, you can now say, without delay instead, and that will then circumvent. So this is useful.
Michael:Like, you might have some situations where you want to, do something instantly. You know, from Nova, you might wanna dispatch a job to run straight away, or you might wanna dispatch something from Tinker yourself manually. So, thanks to Kennedy for that addition. But you can see the complete list of new features and updates. We'll include all of that for you in the show notes.
Jake:Very nice. Okay. Let's talk about 11 dot 10. So 3rd release that we've got here we're talking about, the first item here is that Mark Erickson contributed the ability to pass a callback as the second argument to the update or insert query builder method. So let's just break that down for a second here, update or insert.
Jake:So what that's doing is it's looking for a value, it's looking for a record that exists in your database. And if it does, it's going to try attempt to update that value with whatever it is you're passing in. And if it does not exist, it's going to try to insert it. So, as a second argument to this update or insert now, what you can do is you can pass a closure with custom logic to determine whether or not this record exists. So again, as, you know, as the name, assumes, we are looking for a record here.
Jake:So how are you going to look up that record to see if it exists so you can know whether you need to update or insert it? That's what you're passing in as a second argument there. So it's, just a it's a closure. That's all it is. Right?
Jake:And so they've got some examples inside of the pull request, and an example here in the show notes you can take a look at as well for if you're interested in learning about that. Graham Bradley added support for soft deleted models when using explicit route model binding. So what this does is it allows the resolution of soft deleted models when using Laravel's explicit route model binding feature. If you're using implicit route model binding, what it'll do by default is if a if a model is soft deleted, it will return a 404 in the case that you try and look up that model. Right?
Jake:So if you have a user that has been soft deleted and you have that ID that's passed into that route, it will return a 404 because it is soft deleted. If you wanted to still resolve that thing, your only option was to use explicit route model binding and define it yourself to say, no. No. No. You should still return this in the case that it's soft deleted.
Jake:You would have to define that binding yourself. However, now you don't have to define it explicitly anymore. You can just on the route say, I'm going to include values that are soft deleted. So you just do the route, you do the binding just like you normally would. It can still be implicit, and then you just put arrow with trash at the end of that route, and that will automatically resolve those soft deleted models for you instead of returning a 404.
Jake:That's what it is. That's pull request 51651. Graham Bradley contributed that one. I have needed this before, and I've had to do this before. So this is really nice, actually.
Jake:So thanks, Graham, for contributing that one. We've also got, the ability to set the resend API key directly in the mailer config instead of in the services config. So if you use resend, you can now set that directly inside of the mailer config. That's everything. That's everything in 11 dot 10.
Jake:There's a couple fixes as well, like some typos and things like that, but that is the vast majority of the changes that you'd be interested about in 11 10. There we go.
Michael:Made it. We survived. Made
Jake:it. We survived.
Michael:Alright. Just the one news item which, you know, Flip a coin could be news, could be packages. But the eloquent join with package written by Mohammed Safadi lets you join existing hasone and belongs to model relationships with a new join with method. According to the packages readme, join with will execute a single query instead of 2 separate queries, which can translate to faster and more more efficient queries. To use the package, you can either use the join with trait or extend the packages provided join with model class, and then call the join with method, which resembles the with method.
Michael:So you would say something like user.op, double colon, join with profile, and then select users. Idusers. Namearrow first. And then it allows you to handle also nested relationships and and more complex things where you want to use the query builder and and provide some additional filtering on that. The package works specifically with hasone and belongs to model relationships at the time of writing.
Michael:Other relationships are unsupported, but you can learn more about the package and get full installation instructions and view the source code on GitHub. We'll have links to all of that in the show notes.
Jake:Very nice. Hey. We talked about this at the top of the show, but this episode is sponsored by Mailtrap, an email delivery platform that developers love. An email sending solution with industry best analytics, SMTP, and email API, SDKs for major programming languages, and 247 human support. You can try it for free at Mailtrap dot io.
Jake:Thanks so much, Mailtrap, for sponsoring the show. Do you want me to read the next one? I can go. I can do it. Oh, so the package is Real time real on two packages.
Jake:Real time. Real time command line monitoring with Laravel Top. Hey. Have you ever used htop? Yes.
Jake:Htop is good stuff. Also, n
Michael:c Get on to btop.
Jake:Btop? Oh, man. I don't know what btop is. What is btop?
Michael:Need a prettier version of h top.
Jake:Oh, okay. How about n c d u? Have you used n c d u before?
Michael:No. I have to look
Jake:It's like disk usage. It's really good. So the other day, I had a, server that was filling up the disk space was filling up, and I'm like, what is going on? Like, this is the 3rd time I've had to add disk space in, like, 2 months. Like, what is happening?
Jake:So I dug in. NCDU will scan your entire, will scan your machine, and then you can it'll it'll tell you, hey. This is, you know, with little, like, pound symbols. It'll say, like, this is where the most data is in this list. Then you drill onto that, and it'll say, this is where the most data, and it kinda, like, just shows you, like, percentage breakdown.
Jake:Here's what it is. And then so you kinda just drill down into it and be like, oh, that's where all the time oh, it's in a telescope. It's in the telescope database table. What the heck? Like, that's, like, 4 gigs.
Jake:Okay. I need to start pruning that thing more often. So, anyway, really good. NCDU. Okay.
Jake:That's all we're here to talk about, though. We're here to talk about Laravel TOP. So this provides real time monitoring directly from the command line for your Laravel application. So it helps you track critical measures and metrics to see the busiest routes in your application. Since data is stored in Redis, theoretically, the top command output should represent data from all application servers, not just the specific server that you run the command from.
Jake:So it works by listening to Laravel events. And from those events, it displays aggregated data that's stored in Redis to calculate these metrics. So this uses, like, a time to live, so that the data is stored I'm sorry, stored for a short amount of time without historical data. It's based on the last 5 seconds of data. So PHP artisan top, they have a little GIF here of, what it looks like when it's running.
Jake:So we'll show you for this period of time, here are the most frequently visited methods. Sorry. Not methods. The most frequently visited routes, how many requests you're getting per second, how much memory you're using, what your average response time is, your queries, and the average execution time on your database, as well as cache hits and things like that. So, they're also available programmatically via the top facade that this package provides.
Jake:So you can say, request summary, average, request per second, and whatever. Those things that we just talked about that you can get on that little command line dashboard, you can also get access to those from the top facade and then, do whatever you'd like with those. So the read me provides examples of programmatically accessing that data from Redis in your application, and you can read more about it on GitHub. Thanks, Paul Redmond, for writing that one up. It strikes me as a more real time version of, like, Pulse, I think.
Jake:It's kind of Yeah.
Michael:That was my sense.
Jake:Nearly as detailed, but it's, like, it's what's happening right now. It's not necessarily, like, what's happened over the last week or last 24 hours, the last hour even. It's, like, what's happened over the last 5 seconds. You know?
Michael:Yep. Very cool. Especially for those those of you command line fans like me, I'd sit there and just have that running somewhere all the time.
Jake:Yep.
Michael:The DB auditor package for Laravel helps you audit your MySQL database standards and provides options to add missing constraints via the command line. The package can help you identify areas of your database that need work during development to optimize your production database and offers the following features. Audit and review an existing MySQL database, scan MySQL databases to provide insights of MySQL standards and constraints, apply scan results automatically via the command line, and show a list of tables that fail audit and don't follow recommended standards. You can access all of the tools via Laravel's Artisan console, and one command that Paul Redmond, who wrote this article, found particularly interesting is the db:track command, which gives you information about migrations such as when they were created, the fields that were created, and which Git user created them. The projects readme also includes instructions for enabling a web UI feature to see recommendations from the browser.
Michael:We can link to the package for you in the show notes. It does it does things like, we're doing standard status here. You can use a chart type instead of VARCHAR if data values in the column are all of the same length. Spaces between words is not advised. Use underscores.
Michael:This is for field names. Did you know that you can create MySQL fields with spaces in them?
Jake:I did not know this.
Michael:Today, I learned that sounds like it's gonna cause all kinds of havoc. Mhmm. I recommend not doing that. It recommends setting all of your, field names to lowercase. Numbers are what numbers are not for names and is not advised.
Michael:Please use alphabetical characters, things like that. So all kinds of things that I I suppose follow MySQL best practices in terms of how you would name things, how you would store things, and so on and so forth. So interesting, interesting package there. So thanks to
Jake:I can see this being useful for somebody jumping into, like, a database that there are project that they're wanting to sort of, like, do a refactor on or wanting to get a quick look at maybe some things that might possibly cause problems or be causing problems if it's a code base you're not familiar with, just pulling this tool in and doing a little audit on it and be like, oh, okay. There's some interesting things we could fix up here. So that's kinda cool.
Michael:A package from the Vitor Cloud Technologies, who I believe they're based out of India, and they're big supporters of the, Laracon India conference. So
Jake:Nice.
Michael:Definitely check that check that out.
Jake:Very cool. Well, have you ever wanted to monitor your code processing and will output the stuff for you, which I just recently learned, but it's pretty cool. TimeWarden can do it as well. So TimeWarden is a lightweight PHP library that enables you to monitor the processing time of tasks and then take actions on thresholds exceeding the defined execution time limit. So it's probably best illustrated with an example from the read me.
Jake:So in there, you say time warden, which is just a global helper, time warden. And then task, you give it a name, checking articles, and then you arrow start. So this is where I'm starting this task. And then you go ahead and do your task. So you loop over a bunch of articles and you do your checks, whatever you're going to do.
Jake:And then at the end, you say, time warden, stop. And then when you have that stop, you get to pass in a closure there that accepts the task. And then, what you can do is you can define behavior in there based on how long the task is taking to complete. So if it says, you've exceeded a certain second, a certain, amount of milliseconds when that task was being completed. You can send an email off to somebody or you could throw something into Slack or you could even report an error, to Sentry.
Jake:Right? You could, send something to your error monitoring process. So this would be something where, you know, it's not necessarily an error, but it's something where you want to raise an alert. Hey. This is taking longer than it should, and we know that if it starts to take much longer, this job is going to fail because it's going to time out.
Jake:So you could sort of give yourself a little bit of a threshold before that point and say, if it's taking longer than this, it's still completing, but if it started to get bigger, maybe we need to prune that database. Maybe we need to reduce, the number of files that we're looping over per, you know, per run, whatever it might be. Right? So the being able to monitor the amount of time it's taking and then respond to that is really what this time warden is doing for you. There's a couple there's also another syntax you can use that allows you to use, an arrow function instead of the traditional anonymous function.
Jake:So that's that's in the show notes here, but there's a really good documentation in the projects read me read me, which in summary has the following features. Monitoring processing time of critical tasks in both development and debugging, reactive actions when time is exceeded. So you can do both milliseconds, seconds, minutes, hours, execution time, debugging output. So you can take a look at it as just for the purposes of debugging, measuring the execution time of an individual task or groups of tasks. This also is framework agnostic, meaning you can use it with Laravel, Symphony, standalone PHP application, etcetera.
Jake:And it is PHP 8.2 plus So you have to be at least on PHP 8.2 to make this work. They also, mentioned in the show or I'm sorry, in the notes here in the blog post that the output of tasks, which is pretty interesting, you can throw it right directly in your log. And it gives you this nice little markdown table looking thing where it just has, like, hey. Here's the task name. Here's the duration, and here's what it was doing during this period of time.
Jake:It looks really nice that you can tell they put some effort into making this, look really digestible for the developer. So, nice job on that from let me see if there's an author here that I can that I can give, some I don't think so. Tamil Tomloprad? Tomloprad. Not sure who that is, but Tomloprad.
Jake:Thomas is the name. Thomas Tom Loprod. Yeah. Good stuff. Looks very interesting, actually.
Jake:Yeah. And, like you said, I think or not like you said. Like I said, this is framework agnostics. So this is not just a Laravel thing. And I don't think Ray has the ability to do these sort of reactionary
Michael:Yeah. It Yeah. It's definitely definitely good for tracking slow code paths, especially in production. You know, Ray is is very good during development, but you wouldn't typically ship it to production. Whereas this time warden package, you could put into production, and and you could sort of monitor these intermittent things and and get notifications when some things are starting to be a bit slow.
Michael:So Yeah. Absolutely. To us. Alright. Tutorials.
Michael:As I said at the top of the show, we have returned. We've got some tutorials. We haven't had any for a while. So I'm gonna run through these 3, your homework, as always with tutorials, is to go and read these articles because they're too much to go through on air. The first one is an article by Paul Redmond talking about configuring Laravel with additional additional environment files.
Michael:How many have you forgotten? How many of you have forgotten to either configure the database in your PHPUnit. XML or you haven't created a dotenv dot testing, and you've run PHP artisan test and then found that you've destroyed your local development database. So this talks about this is the common one. Right?
Michael:You would create a dotenv for, you know, doing your development, but you'd have a dotenv dot testing as well. At work, we've got like a dotenv dot review that we keep in our version control, and we use one password to to hydrate that file as part of the deploy process to the review environments. So we set the app env to review. The dotenv dot review file is filled using credentials from 1 password, And then that is then used all of our review environment. So you can do all this kind of stuff.
Michael:And really, because we're using references to 1 password vault, you can just commit that to version control. You never have to worry about secrets leaking or anything like that.
Jake:That's really nice. Yeah.
Michael:In there. So, you know, this article talks about using different environments for different situations, as I said, dotenv.testing being the most common one. But you might have if you're deploying to Docker, for example, you could have environments configured for your key workers separately to your web application separately to your any artisan command runners. So definitely check that one out. The next article here from Paul Redmond as well is how to use Eloquent factories with PHPUnit data providers.
Michael:If you've ever tried to have, like, a dataset, or a data provider with your test in order to use a single test function to test multiple scenarios. Maybe you're testing different user types or different permissions, and you're trying to use a factory inside that data provider, the thing that you're going to run into is because the data providers are run before the application is bootstrapped, you're gonna run into errors because it doesn't yet know how to create a user factory, for example. So this talks about using in PES, they're called bound context. I don't know if the terminology is the same in PHP unit, but it helps you to do that kind of stuff. And we use them quite extensively in our test suite as well.
Michael:So check that one out. And the last one, as I said, this is this is a big meaty article from Ash Allen. This is the ultimate guide to Laravel validation. It talks about what validation is, why it's important, talking about client side validation versus server side validation, how Laravel specifically handles validation, and then validating data either automatically or manually, validating using form requests. It goes on and on, and talks about some handy validation rules, how to validate arrays and arrays of data and all of that kind of stuff.
Michael:So, I look. I've I've said a lot. There's a lot of stuff happening here. I'm about, halfway 40% through scrolling through this article. So it might be a couple of sittings to get through it, but it is good.
Michael:Ash always provides good value content, and he's always bringing stuff out into the world. So thank you very much, Ash, for that article. And that is that is all that we have.
Jake:Nicely done. Yep. Thanks, folks, for hanging out with us. This was episode 216. You can find shown us for this episode at podcast.laraval news.com.
Jake:Dotlarvaledashnews.com, sorry, slash 216. If you liked the show, we would really appreciate it if you'd rate it up in your podcast of choice. That'd be amazing. 5 stars would be awesome. And, of course, if you have any questions, hit us up on Twitter at michael debrin@jagobennettoratmariamnews.
Jake:Thanks, folks. Until next time. We'll see you.