 All right Welcome to day four of haskeling the advent of code I hope my audio is a bit better. I've turned on compression So even when I'm talking this direction, it shouldn't sound too bad Thing is I was testing it always by talking directly into the microphone And not looking in this direction, right, which is where I'm looking most of the time. So Hopefully it's better now Alright Let's look at today's problem But yeah, let me know if the audio isn't good enough Because I can monitor my output, but it's very hard for me to monitor the audio Because there's so much lag Because I don't have like direct feedback into the microphones like I do with The microphone like I don't have direct feedback of the entire mix Like I do With my microphone audio, so I can't really tell how the mix is Right Let's check out today's problem day four. Oh, no, it's day three day four passport processing, okay So we forgot our password and Okay, so we don't have a okay, so we aren't valid. We don't have a travel documentation For long line. Okay, due to some questionable average security, you might be able to solve both of these problems at the same time Are we gonna be doing hacking? Is that illegal? The automatic passwords can as well slow because they're having trouble detecting which passwords have all required fields The expected fields are as far as brr year ear hicked huckle huckle pid cid okay so Passports are validated in batch files your puzzle input each passport is represented as a sequence of key value pairs separated by spaces or new lines Passports are separated by blank lines. Here's an example batch file containing four passports Okay First part was a valid all eight fields of pressure second is invalid. It's missing height The third password is interesting. The only missing field is CID so it looks like data from North Pole credentials not a password at all Surely nobody would mind if you made the system temporarily ignore missing CID fields treat this password as a valid Fourth one here Missing two fields CID and beer missing CID is fine, but missing any other field is not so this password is invalid Okay, according to the bubbles you improve system would report to valid passports so In your batch file, how many passports are valid? All right, let's go Seems like we're gonna be doing a lot of string processing today. Let's make your day four CID day four and Then we open day four we say a new file Day four that it just But let's start off with saying new file here and let's Have our test input and put that Okay, so here's our test input now we will say Mainware Get input string IO Let's just return a list of passports, right? That's kind of cool Get input So this is gonna be so we're gonna take This should be file path, right? So we do we read file so line LMS is gonna be the read file of the file path and Let's see here passports How are you gonna represent passports? So I assume that later we will have to look at the values in problem two, that's like It doesn't make sense for it to have so many stuff if If it doesn't have all the values, so let's just make this a map for data dot map Okay So a passport It's going to be a map of strings to strings This is gonna be a list of passports. Okay, so to passport so this is gonna take a list of strings the fields of the passport and We are going to return the passport So first of all Um To passport equals And we haven't defined this yet So let's just say you print LMS. Let's just print it to start with The issue now is Okay, yeah, we have to return a list of passports. So let's say here main is IO main equals do Get input test input Let's run this GHD day 4.hs O day 4 and we run it day 4 What happens? Okay compiles links No typers We could only tell that from GHD ID. Okay, we got all the lines. So let us So passports are separated by blank lines So we won't go here we will map lines over this. Let's see here So now we have the lines But it might be so there's gonna be blank lines. So Let's Now we're gonna want we want a function to kind of split it at all the places where it has Split split Okay, we want a function that takes an a and Let's I think I think it's a bull and list of A's and we want a list of list of a's Split when oh, this is from another Okay, that's just that's just writes a function, right? Split when takes an EQ takes a A to bull and then And then a list of A's and returns a list of list of A's split when Okay, so How do we do this? F and then we have case if you have an empty list we will return empty list, right? And then it doesn't matter what F is split when Fx x is Let's save it a it's having a a And then case F a This so if if we have a match on the front we want it to We want to drop those right and I think it's easier just to split at That's in the prelude, right? Or What is a function called isn't like span? I mean this is kind of like span But there's I think it's drop when or something like that, right? Drop while a Yeah, so take while Not okay, so span Okay group because I think there should be a there should be a list here somewhere. It's a function that just does this Okay, let's just let's just let's just make it easier. Let's just say split when x is This is just gonna be where Break This is gonna be con So this is gonna be you know everything that doesn't satisfy the condition and then the thing that satisfies it so So it's just gonna be First and then the rest equals break con Texas So this will be First that's gonna be a list of things Concatenate it to split Okay, and this here will actually be You know the first value will be the one that it actually matches and we don't want those so we say split when a Con rest Okay, and let's see print passports Okay, right. Let's here we So print Split when Equal to the empty list illness Okay, run it all right, so it's Not accepted patterns in first rest. Okay. Yeah, okay, so I Think we have to say here Yeah, we have to say So we didn't we didn't count for the end right break con Excess of so first comma Rest It's gonna be your first This is gonna be first and rest We break it and we get something with the end we're gonna return that But if we we do get the empty list here So first and then We don't care We get the empty list here So it will always be the empty list right yeah But we don't care about that. So This is gonna be first comma empty list. Oh no That was an infinite loop Split when con the rest right and then Okay, so I think we should define this whole thing just like this Let's just say case break con fixes of Yeah, let's just do the entire thing here case Okay, so we're just doing this here Case break con of Right, so if we have First and then the rest then we will return First concatenate to split When con the rest Otherwise, we just return for first return list Getting first Okay, see and now we have This here So we get all the passwords Works great Okay, and then we're gonna join them. So first let's map Let's map words over them, right? let a P entries equals So we split these and then a Comp ps equals that is so let's map words over Over P Come up we map we map map words over P entries print comp Let's see what that does Okay, see and now we have all the words like this and then Okay, and then we will We will So we will join Or we will concat the lists After we map words over them. So what happens now? Okay, now we have this is an entire passport. Okay, this was so this is an entire Passport with all the words and then this is an entire okay good Okay, so now we've Now we've created the passports Okay, so So now we have all the nice passports. Okay, and now we will say This is the comp ps so over that So over those We will actually map map break equal equal so we want to break it at the At the at the these right So we get the kind of word Key key value pairs, right? So we map it at break And then we get this We get these key value pairs And now Yeah, okay, so now we have the key value pairs Let's just print the head here What is that the head is gonna be a list of key value pairs from one Passport but with colon and front, right? Okay, so Then we will just say so Google I think it's just from list, right? I think and then like ps equals map map dot from list over the comp ps So here we will print ps So here we just turn them into maps And they will be maps and then a So how do we map over the values in a map? Let's see We can probably use data strict right, but we don't we don't care adjust Up to the value. Okay, so Size combine difference intersection disjoint compose Yeah, we just want to map over the map. So let's map map Okay, no, no, we have a list of maps. Oh my god. Okay, so we will map dot map We want to drop the first element Drop one okay, and you see now a And then this will be Print ps and now we don't have the the annoying colon there. So this return ps All right, so we generated the passports and now we are supposed to Check if they are valid, right? so When are they valid? Well, all eight fields are present. So then we just check the We just check the size of the key set, right? How do we map over the keys, how do we just get the keys if I map keys, okay? Okay, so here we get the passports. So let's say Print map keys over the passports To be mapped on the keys Okay, and then So is valid is valid one. I'm gonna I'm just gonna call it. It's gonna be We're gonna apply it again later. So it's valid passports to boom It's valid one ps equals case length ps of So if it is eight then all eight attributes are present, right? If it is seven and a ps has the Let me just say member We just say CID Member It's gonna be mapped off member ps And this will be just, you know, check if Sid is a key If it is a key So this is gonna be not, right? So If Sid is not present, that's okay Otherwise seven is gonna be if Sid is there and there's something else missing. It's gonna be wrong So we don't even we don't even have to check, right, but this is I know it's not optimization, right? So if it's anything else, it's false Okay. Hey, so let's say map is valid I'm just writing it like this because I'm pretty sure in part two it's going to be It's going to be we're gonna have to check the values Okay, so let's see What is the length of? filter Filter id All right, that's two and for the first one You're supposed to say two Let's get the input and let's say Let's add a new file. Oh No, that's a new folder new file input and Let's see what happens Haskell syntax is kind of funny Come say that to my face Yeah, I mean You get used to it, right? And it's like it's whatever you get. It's whatever you're used to which is not funny, but this is I know I like it Like once you'd realize what's going on. It's quite nice So let's say This is just gonna be Let's just let's just copy paste here. We're not we're not gonna be maintaining this code Okay, and here we're gonna get the input and then we're gonna print is valid of passports by one of the passports 226 it says We're even printing it here You don't need that Let's see 226 you think it's correct I think it is It's correct. Yeah JavaScript and Python they're Very imperative Right, but here like the focus is on the expressions and not the statements But so it's only in do notations actually that we have statements. Otherwise, these are all just expressions That's where the syntax becomes a bit funny, but it makes it so that you can very easily Evaluate everything actually which is Which is pretty good Okay, let me see By the way, do you guys see the chat messages on stream because I I keep missing them. I hope you do All right, let's see here 226. Let's check if that's a great dancer Otherwise we have to see All right, you got the first one Now let's see if all our parsing work turned Was the right work Otherwise I mean because I assume we're gonna look into the values of the passport. All right So we fixed the system Airport security is talking about password with any valid data again. Okay. Oh, no Okay, so birth year four digits issue year four digits And at most 2020 expiration year height Hair color Eye color Passport ID Sid is ignored. Okay. All right, so now we're gonna write some validation code. Let's Okay, we're all required fields are both present and valid. Here are some example values. Here's some valid press ports Okay, so we still use the same input So, okay, so let's check it out. So there's only 226 valid passports So Let's just simplify it and say valid so let valid passports equal Filter is valid one passports Because they have to have all the fields But Sid is ignored So we can we can actually do this and we can then we could just say Length valid passports Yeah on it How fast is this actually? Okay, so it's How fast is just the four milliseconds. I mean, and we're parsing stuff and putting it into a map that is Quickest lightning. I mean, it's not nanoseconds. It's not like rust stuff where you can like I mean, but you know, it's Pretty good and you can see here that like three of those seconds were spent by the system Okay, so it's about 10 milliseconds. That's not bad And that's even like with the test. Okay, so let's so let's check Let's write here. Let's let's just copy pasted straight Have a bunch of things is valid Passport to Okay, so we're going to have all of these so beer is supposed to be four digits There's a valid fields Okay So here we're gonna we're gonna Let's just turn this into Let's let's do it. Okay, so it's valid fields. Okay, so let's say here Data valid passport Just so we can make use of some stuff valid Valid passport equals so we're gonna make a data constructor EP. So it's gonna have beer. It's gonna be a String, okay Here is gonna be string. So these are all gonna be strings, right? But we just want to be able to refer to them easily in The validation checker. So, okay Because like we only have strings and we want to we don't want to assume What they are right ECL Because like, you know, one of the issues we might run into is that It is it just doesn't parse, right? So Okay, easy up string bid string We don't actually need so these are all valid passports This one till take a valid so to valid passport it takes a Map of string to strings and returns a valid Passport to valid passport Map equals so how do we look up in maps? Okay, we can just have yeah, okay, it's just bang And we know that all the elements will be there. So we will say this is a VP beer equals map. Let's just write here M beer is map beer here equals M here And now it's a here. So this will be Eight will be This will be CL will be CL And this is PID Okay, see Okay Okay. Yeah, this will be Map dot bang. Okay Now, let's see here. We will be Deriving show and then let valid passports is map to valid passports Of the filter so what is it complaining? To valid passports. Yeah, okay. Okay. Now you see now it the speed A lot slower, right? Because now we have to like look up in a map Can we fix that import data dot map dot strict Book what I did a month strict So if we assume we will read it, okay, I mean, it's still a lot very slow How about we I think I mean I think what happens here is that essentially It never kind of checks the values or anything once we're generating the passport So that's the thing that Haskell does a lot is that you know It like it just doesn't put the values in there It doesn't evaluate that statement if it doesn't need to Right. So but now we're actually evaluating the thing and then we need it, right? So it is It's quite good at what it does like I'd like these crazy behind-the-scenes optimizations that we're We're you know, it's just magic, but you know This is not too bad actually. So this is with With compilation. Let me see. Oh So it's still super fast. I'm sorry. We're just compiling more code. That's all To other passport. Okay. So let me say here is valid passport So this one will take a valid passport and it will say Now let's call this has valid fields We'll go to a bull Has valid fields and then here we can take VP and we can do this dot-dot thing and that will complain because We haven't enabled the extension for that. It's record wildcards Lang language. Let's actually Run this and then time this This is good. Okay, so now we have all of these fields in scope. Let's check it out Has valid fields. Okay where Okay, so now we're just gonna we're just gonna do a Kind of a case break. So we can do this. I think we're saying Maybe valid passport So let's say say here So let's say here. So we're gonna use a do syntax and then we'll just kind of Escape early if one of them is wrong. So do So we're gonna go guard. I think we need to import guard from God control that monad right? Yeah, so we will guard against a bad valid beer So here we will say, okay, let's just say this. So it's gonna be valid beer And valid beer is birth is your year. So that is so we have beer in scope. So we'll say if So it has to be a little bit for digits the length beer equals equals four and So we will read add int So now we read we need we need type Applications and like last time we didn't need it, but now it doesn't know that it should be an int If length beer equals four so then I equals a read so we will we will use this value here read add int beer and then in We will say beer larger than let me say I larger than equal to 1920 and I less than equal to 2002 Okay So and this is also a case of lazy evaluation, right? Here we can actually just say We could just we could just let this be in the computation and We say length beer equals equals Four and it will actually never evaluate This thing And they will won't actually evaluate the eye there unless it's needed, right? So We'll never get a purse error, which is cool Okay So so valid year Valid here, so we read the year and then we check if it is Four and that it is Larger than 2010 and that is less than 20 20. Okay a Same here, that's that replace Here with expiration year And let's make sure that we are actually seeing valid Yeah, they are also So the length has to be four digits at least 20 20 and less than 20 30. Okay Hide a number followed by either cm or inch, okay So we will flip it and reverse it Flip it reverse it Valid height equals case Reverse height of Okay, if it if the reverse ends in m C And then the rest are Then we We say Read at int So okay, we were we were actually I think we should we should read and like do a case on the read because if the if it doesn't parse That uh, that shouldn't we shouldn't don't want an error in that case We want to maybe So we read maybe okay, so we say So here we will just say case read maybe at int this every beer of But here we actually we do the case split before So we will say here We will say length beer was four and Like this So yeah, this is a nice thing right this case thing. It's just the It's just a expression right so we can actually just do this Use it as an expression um Then we read the maybe here. This is why and this was Sorry about this and we just wanted all to be correct Yeah, I wonder if there's like a Probably like a super efficient way to Like make all these edits Super fast, but feel like it Um Just I okay And this should be eight right Is it not a standard sit sex? For programming in haskell. I mean this is haskell syntax. There's nothing Nothing wrong here. I think I hope not Let me see Let's let's like let's so we let's let's actually Let's make this a bit nicer. Let's say check range So it takes an int and an int and a string So let's say check Year it takes an internet and a string Returns a bull So check year so we have the low and the high and the string so then we will say length l equals four and Then we do the case maybe read maybe of the string so Stir, so here we have length stir And stir and then we just check this is largely equal to the low and this is less than equal to the high and then Valid b.i.r equals check year What was the what was it for b.i.r? It's 1920 And no 2002 read like this so e.r as this is 2010 2020 right Valid E.i.r. This is going to be 2020 and 2030 Like e.i.r. Yeah, this is too much copy paste, right? All right uh Yeah, I mean the white space is significant, right? So So if I do it wrong Eh, so yeah, the question is like is the white space of entertainment significant and it's like if I do it wrong It will complain, right if I don't have the correct syntax or the White space and I think this is a This is quite standard. I think I mean, I don't know what's I've been I've been working on ghc for a bit and This isn't so far away from ghc. So I'm Yeah, I don't know We could do this thing here with an f map But that seems a bit overboard actually Yeah, okay. So check year. So if it is 70 meters And then we say case Read maybe at hint of Of r of So if it's just Uh Just just a height Then we want it to be 150 They want to be height larger than equal to 150 and height less than equal to one are you three Uh, otherwise it's just false Uh case read maybe in cannot What is it saying this can't cannot apply type expression type t1 to a visible type argument in But now it doesn't know the type, right? Oh I think it has to be Now it's complaining that Okay, read maybe isn't defined. Yeah, okay. This is in data text dot read really should be imported by default, right? Okay, read maybe is now here and then Now it just works. Why it should complain. I think this is also a ghcid error. It's giving the Wrong complaint here All right, uh, let's actually just copy paste this. I don't want to we don't we're just gonna run it once we don't need We don't need to Abstract it if it's an inches then it should be 76 Oh, shit, we need to reverse the string back The numbers this could have failed us Okay, um Okay, uh, so and if it tends with anything else, it's just false Okay, so we need to have valid height as well Okay So for So, okay hair color followed by exactly six characters zero to nine or a to f Okay, a hair color. Let's do that. Uh, let's Let's copy this in like this So we have it by hand, right? Okay, so valid ACL So here we have to say I think we can just say is alpha numeric. Oh, we're not so it's supposed to be a to f Google So we go to data dot char I think we can also just you know, we can do Let's check it out gti Uh Can we do zero to nine? Wow, can we do To f Okay, so We can just do zero to nine plus a to f I mean, this should optionally optimally be like a regex, but then The like the Haskell doesn't have a standard regex library. So it's a bit of a pain So let's just use this. Um Valid ACL Uh, so case ACL um So if it starts with something here And so, okay first First of all We want a Length ACL equal to Seven Can I do this? What's a good planning about? Parts are an input valid ACL. Oh, yeah, I think like this Okay, uh I yeah, okay, let's not do it this way. Let's just say here case ACL of Okay, so let's say if Let's say length ACL equals seven and Okay, so ACL Of so it has to start with the Oh hashtag for a bang or And then all of these have to be set. Okay, so let's say here, uh ACL Chars equals Now let's use a set So we use a set and then we do Um, let's let's do this on the top field here Valid ACL Chars Should be set dot from list On list a So it's going to be zero to nine Uh plus a to f Valid ACL Chars equal they are this is a set of characters So, okay, so if it starts Then we say I think there's a function called And And it just checks that all of them are true So we say map We will map the set dot member Uh, so how does what is set dot member? He import data dot set Set dot member Oh, oh no, it's type member Okay, so it takes in an a and it takes a set. So this would be valid ACL charts, what would you call? Valid ACL charts Let's call them something else Valid ACL charts, uh, let's see set member valid ACL Chars Uh to R and then we say and Okay, this should work Uh, so we check that the first one is hashtag Followed by exactly six characters zero to nine or a to f So and then we just check that all of the characters are valid, right? Okay, uh, if this is wrong, this is gonna be this is gonna be so painful to Debug I hope the demo input has Like a good coverage because uh Okay, so valid ACL, okay Let's just write the other ones here Okay, we don't check valid seed because it is ignored So let's just write here. So we have valid height And we have valid ACL and valid ACL and valid pit So let's just add the list together It'll all return to the same valid ACL valid ACL And valid So that's seven fields That should be exactly uh, right ones Uh height Valid icolor exactly one of am blue burn gray gernson, okay So let's just write that right Let's just let's do this in a set this is gonna be a set not member of uh, what did they say? Am blue burn gray hazel And then we just check here if valid ACL is a member of valid ACL else Easy enough Passport ID is a nine digit number including leading zeros So let me just say pit The length of pit equals nine So here we can use the data dot chart is We can look at data dot char which has a bunch of these Is control is space is alpha is alpha num is print is digit I mean we could do it with the set membership thing But this is also just so it should be To be nine and let's see there's also the all function. I think Yeah, so this takes in a checks that whether that all are something So it's basically an and over first you map and then you do and So then we could just say here That all should be a set member of valid charts and here we can say that All is digit Pit okay Then let's check it out length valid passports length Filter has valid fields passports. Okay, it says 160 of them are valid How many of them how many of them are Right, so let's filter map is valid Let's make the Let's make the test passport also and then How many are length has valid fields test Okay, so it says the two should be valid I'm being rated That's cool Okay, two should be valid Let us see What they said So here are some valid passports. Okay invalid passports Let's see Okay, let's simplify the thing here so Let's see. Let's get the passports Let's dump these into it valid pass is In these are gonna be invalid These are gonna be valid. Okay. Hey, let's check it out Wow, there's so much happening in the chat the most Active chat I've ever seen And none of them are asking questions about Haskell Anyway, yeah, it is a nice keyboard. I got it like two weeks ago. Um It came in like Danish colors, but then I made it Icelandic because That's where it's at Uh Haskell is a a programming language Uh That's a functional. It's a lazy functional programming language Uh Which are urges It's my favorite language. I've uh, I worked on the compiler a bit So I I know like the a bit of the ins and outs. Um And it's a bit different from like the usual imperative languages In that, you know, everything is expressions So it's uh, it's It's fun. Yeah Okay, let me let me let me extract this away here. Um Uh all valid So that's gonna take a a file path and that's gonna return me a list of booleans Uh all valid So and then I'm gonna say just like this here And then we're gonna write IO And uh, we're gonna do We're not even gonna re rename it, right? We're just going to Do this And then we're gonna We're just gonna we're just gonna print. Yeah, okay. We're just gonna print. Uh We're going to print and we're just gonna Return dollar map Okay, and these are going to be applied to imp the name of the file and Let's see Okay, now it's complaining here that this is wrong. Oh, yeah, I Okay, let's let's look at the Let's not look at the input anymore. Let's look at all valid Of test input Let's uh print Into print We're going to check the the the In valid pass and we're going to check the valid pass compile so Oh, it Oh, yeah, it filters it filters out everyone. Okay, so so it says that all of the valid ones are Is it saying that? Is it is it like the exact opposite? Did I okay the okay, sorry. I mean I named the files wrong. So this is These are supposed to be the invalid passwords Let's copy this and let's see These are supposed to be the invalid ones Yeah, exactly. And I so I just I just made the files wrong oops Be careful kids when you're naming your files Okay valid invalid All right, we get four false Invalids we get four correct and let's Then let's just run it. Let's just see if it works Um, so we get the input we print the length of valid passports and then we print the length of Invalid passports And it says 160 so Let's just check the oracle 160 All right, we got the right answer Whoop whoo Uh, yeah, okay. We spent like so much time on on All of this stuff. We could have just run it immediately but, um Yeah, this is just a very kind of very crude Sort of way to do it, you know, I'm just parsing the strings And we're just looking at everything directly, you know, there's no trick Involved here. Okay. I mean we choose the right data structures. We choose sets and then we choose maps but I don't know like our people Because you know, I think so so some years, um The the advent of code like you you have to find the trick. Otherwise, it's going to be super hard and super long But here we just kind of You know, we the first one was just very simple. I just just check if it had eight fields. Okay We could have gone through it and checked if it had exactly the fields, but we just we didn't even care, right? Um Then we just like kind of mapped it to a passport and like we wouldn't we didn't have to do this actually it was just so that we We could use the values directly here um And like, you know, we didn't even have to do that so Yeah, we could have just parsed it On the fly but like we want it at least something it would be nice, you know, if he had a deriving function that took map of string to strings and a record that has only string fields and could kind of punt on it. Um We could probably have done this with like asin or something like that because like this would have been a adjacent data structure um And then, you know, we just made these sets here We kind of we made them outside. I think ghc would have lifted these Out of the has valid fields function I think because I have written code where I am like going into expressions and it's it's very good at lifting things. What does lifting mean? Well, it would essentially just You'll take this definition that doesn't depend on any argument And it would lift it all the way Here to the top level so it doesn't need to be evaluated um Yeah, I mean it only needs to be evaluated every now and then Okay, and yeah, I mean this this is just copy paste. We could have we could have said Could have said something else, right? We could have said Uh, let's just make it a bit nicer, right? We have we have some time Uh Check r equals what is oh no Check r is We could have done something like this, right just h Jack uh all lhr and then And then here we would have said, uh So Right, uh This will be low and high and then we would have said height is larger than the low and the height is larger than the high And then we would have said here, um Wait, what is that's not? check 59 76 r and then this check 150 193 r So we made that nicer, uh, so this is just less copy paste and Yeah Here also, you know, yeah, I you know all of these are kind of They just do what they're supposed to do, um I mean, yeah, this this could have been nicer. I mean we could have written this all valid right away, but Um, you know, we were just doing it as we went along, right? We didn't actually need anything more here Uh, oh no my playlist ended For some reason Yeah, this is uh harris heller the lo-fi christmas playlist It's quite nice to have underground. I like the lo-fi music when I'm programming. It's just It's not too distracting and uh It's yeah, it's nice Nice and cozy Okay. Yeah, so that's it for today Let's just make sure that it still works Yeah, it still works And uh, I'll be back tomorrow with day five so check Check it out. Um, so it's gonna be the same time tomorrow, but let's say I started at like Six o'clock european time, so I'll start I'll start around then and as we see like I've usually been taking like 40 minutes to do these things this time it was It's been an hour 15 minutes hour 20 minutes. So Uh, these are getting harder and harder, but you know the harder it gets the The more fun they get um so check it out tomorrow in case you're interested and uh I have a playlist on youtube where I've uploaded like the episodes so far and uh I make sure that the Um, I fix the audio essentially in in the videos. I've had some trouble with the audio, but I think I think it sounds okay now I I put in a bunch of compression and The the issue was like if I was talking like this and I was talking like this The difference in audio would be way too much, but Yeah, all right. So tune in tomorrow for more haskell programming and uh, yeah, you want to follow and uh If you're watching this on youtube, you know Like and subscribe. That's what that's what I'm supposed to say, right? Let me check. Let me do one more thing No, okay. I wanted to like map this map these things over, but I I don't think this gets much shorter. We could Could exchange this like with an f-map but But you know and then like f-map this check over read maybe Because we're also doing that here But yeah, I think this is quite good. All right. See you all tomorrow