 Okay, so hold my beer and watch this This was a challenge put to me by an old friend who said you should you should submit titles or submit talks Entitled this and I said well, what should they talk me about and he said I don't care I just always submit the talks like that so I had one at London for workshop But I wasn't able to attend so Fosdham gets to hear this and then maybe some of the ones So unfortunately, too. I also was I was writing slides right up until like two minutes ago So I didn't get a beer so I don't have a beer for anybody to hold so If anybody wants to pass one up that's So let's see so who am I my name is Steven little but I also respond to Steve on because that's how it's spelled And all the Russians at work pronounced that way so whatever just call me Steven In 2005 I wrote moose in 2010. I started a project called the P5 mop Which was an attempt to put moose into the pro core I've spoken about it previously at Fosdham and at other workshops and pearl things like that It's been a long time running and There's been multiple different versions But now I'm done So that's what this talk will actually be about We'll talk about the different pieces that I've built for this and then I'm putting them out to the community to test them Play with them experiment with them to see where it goes and hopefully then in 2020 I will profit from this in some way But we'll see assuming the world is still around. Let's let's let's go through so anyway So P5 mop through the ages it had a bunch of different iterations the first one was obviously called P5 mop it ended up being over complicated mess There was a P5 mini mop Which was an attempt to do a small version of it that we could bootstrap the first version with so we could write The mop inside the mop and then it just got really really messy and complicated didn't work I took a year off and sort of like let my brain refry P5 me mop a redux was another yet another attempt that one ended in just a giant mess of excess Code which which led me to write P5 P5 mop excess which pretty much just segfaulted really reliably and did nothing else well I'm not a C programmer. And so finally This was the last version of it So again, seriously, what the fuck and that one actually proved fruitful It took a little while I had to refine it and it's been it's been I've been playing with it for about a year and a half but it's essentially What I what I've done in the last maybe month or so is I've taken all the pieces and I've split them up and Part of the reason I split them up was I wanted to be able to I Actually wanted to be able to use some of these parts and not have all of them So some of these parts require 522 some of these parts require 514 some of these parts require 510 Some of these parts actually can are backwards compatible to 5.6 So at work we mostly use modern pearls. I work for booking.com We're mostly on 518 to and we're about to upgrade to 524 So don't really worry about these things, but in my personal work I do a lot of stuff that I want to support across many versions So what I'm about to present to you is six different c-pin modules that when you put them all together You can get yourself a very nice modern looking pearl object system that uses all the new bells and whistles You'll see that at the very end, but we're going to start first with something that actually is backwards compatible to 5 5.6 So I call this universal object. It is on c-pin right now and what this essentially is Ames to be is your your your core base class So if you have Java you have C sharp you have things like this you get an object already That has a built-in constructor and it understands certain things This was one of the things that moose provided that people really liked was it was it's basically its own constructor So you could just say use moose and then immediately you got a new and you could make the instances of your object And it was very easy out of the box. So this This module basically does that and What it does is it provides it provides a certain set of conventions about how to build your objects So the first convention is that you put all your slot information meaning all the information about the fields that you want To have inside your class you put that inside a package variable called uppercase has This is very similar to how you would do inheritance which would be with the at is a Okay, so it's building on those same types of conventions and essentially you put in there a key for the slot name and then a sub ref Which will provide the initial version of that slot From there. It also gives you other things. It gives you new build args Blast create repper slots and build demolish which I'll explain as we go here So has as I said was a slots. So here's an example of that So we we want to inherit from a universal object and then we define two slots x and it does fall value is a zero Why and the fall value is a zero so a very simple point class and that's it We have a constructor now because we inherited it from universal object and all other fun stuff comes along with that So this is really just a convention. There's no code that actually implements this There's just code that uses this and understands this convention This convention also works great for inheritance. Okay Because of the way pearl does list flattening and stuff like that This point has is basically brings in all those fields and inherits them In there and we can actually tell the difference between an inherited field and a non inherited field because this sub If we actually dig under the covers a little bit, we know what which package it was actually compiled in So we know that this was there's a slot for for package 3d and the other inherited ones are for point And we always can know that because we can always track that information So new is your it's very similar to moose constructor You can take a hash ref or you can take key value pairs also very similar to how pearl six does things so we have that in place Bill dogs is also something that comes out of moose which also we stole from pearl six Which is a way to essentially mangle the arguments on the way in so? Key value arguments are really simple really straightforward very easy to use and everything like that But they're not always the API you want sometimes you want a different API So sometimes you want to just pass in maybe two two integers and you want it to basically to inflate into the key value pairs So this is what you would do with bill dogs If you've done any bill if you've ever used the bill dog feature in moose or anything like that You'll you should be really familiar Basically, I noticed that I only have two elements in my arrays and I say okay I'm going to assume that's that's my two element form and I'm going to turn it into this and return it Or I'm just going to call the super and all bill dogs does is it mangles the arguments turns them into canonical representation of a hash ref Which is key value pairs The next step is bless and create which is very tied to repper and slots So I want to explain this this is rear really where all the extension mechanisms are Situated within this work. So you pass your args into new new calls bless Bless is actually going to get that that canonical hash ref that bill dogs just created so bless gets that first Bless's responsibility is can we guess the bless? Yes That's really literally all does because it just calls create to construct your instance So most of your extension points if you wanted to do different kinds if you want to do array based instances or scale of references or How you inherit from non? Universal object classes all that ends up being done and create so create can construct your instance however you want It calls repper which the default version just gives you back an empty hash ref So that's the representation. This is all very pearl six ish More of my pearl six people Okay, yeah, is that so that's still in there. It's still part of pearl six repper. Yeah, okay, so just want to make sure So return to hash ref and then it also calls slots which gets that has information there So say you wanted to do all this but you don't like the fact that I'm storing the slot information It has override slots put it wherever you want. I don't care it because as long as that gets it all the other construction protocol bits They all fit together So as I said Overwriting a class that itself doesn't use universal objects. So has its own different set of constructors is as simple as this So if you think most times with the constructor you call the super constructor And then you do things to it yourself and make sure it's blessed into your class This will actually end up resulting being blessed into our class properly But we're calling the legacy constructor. We're passing anything into it So setting up their arguments as they expect and the result of that will then go through all of our other steps So it'll get blessed properly into our class all the slots that we expect will go into it things like that It's also how you get custom instances so return the representation is an arreara Well, so this will essentially put all that together So it gets the slots from the class it gets the the representation and then it basically pulls the things out of the Protos which is the the arguments and if it doesn't have them It just calls the slot initializer right there and it puts the whole thing together And we always know that x is at zero and y is at one and it's very easy Of course, this doesn't inherit well So you have to do this but this is kind of weird map sort keys slots This gets really kind of cryptic and messy But this is how it would work to to inherit stuff you can also do scalar references You can do whatever you want in here if you wanted to do a custom C type instance you could do this So all these extension points exist That was a little heavy did that did that that wasn't explained well What's that? Yeah, well because you want consistent Otherwise keys are just gonna give you random things and you want you want to know the position of your things in your instance Yeah, yeah, so it's an array Yeah, messy. I didn't even bother showing how multiple inheritance would not work and all this kind of stuff So so anyway that they get a little fancy But it allows you to pretty much have a lot of freedom with your expression or with you with your representation types and things like that And then there's build and demolish which was part of moose Basically new calls build all and build all will look all the way through your inheritance chain Call every build that it sees in it in the proper order and then on the opposite side destroy will call demolish all Which will then demolish in the exact opposite order that that build happened so that you can properly Yeah, basically get rid of or set up and get rid of resources in your class if you want to so and all this 5.6 who here uses 5.6 still Nobody if you did Now this works for this it actually it uses MRO Which is a 510 feature and MRO compact if you need something before that Otherwise it has zero dependencies and it is basically ready to go into core as soon as we feel it stable enough and and Sawyer says Okay, or I'd buy him enough vegan cookies one or the other So anyway, so that's universal object universal object I specifically pulled out because I wanted to use that in a lot of places I wanted to just be able to write a very small c-pin module with minimal overhead and be able to have a nice Nice base class a nice construction protocol because I ended up Reimplementing this over and over and over again. So that's there. It's out on c-pin The next phase is something that I I've fiddled with a number of times And this is this is yeah, this is a bit of a weird one, but I think this is really useful So Pearl has within it a set of compiler phases. Okay Do we all know what these are? Anybody any a little confused on these anybody just seen them, but never knew quite what the hell they were good for Okay, all right good. So everybody knows okay, so begin happens immediately You have a begin block as soon as it's parsed it's executed It doesn't know if there's no more begin blocks in front of it It doesn't care if there's any begin blocks before it just immediately runs check We'll run last in first-out order and it blocks will run first in first-out order unit check is one of my favorites unit check So begin check and in it will all work with the the The compile phase of the interpreter unit check. However, every time a unit A compilation unit is created so every time you use a module or every time you load a bit of code or eval a bit of code Unit check gets fired at the end of that compilation stage. So that becomes very very useful in terms of Finalizing things or cleaning up resources at the end of the compilation phase before you hit Runtime and then of course, there's the end blocks in there So these you can just write, you know begin and then put a block there or check and put a block there and stuff Like that. That's all well and good. However, you can't easily programmatically install a new unit check block or a new begin block or or a new thing like this if you had that ability You could do all sorts of things for what's called multi-phase programming. It's basically macros on crack is how I look at it If you think of macros macros have an expansion time So they expand and then the code gets compiled Well, this is these can essentially work in a similar sense in that they can expand the code now There's no it's not just text expansion like see it's a little bit closer Maybe list but not even that because there's no real syntax it it's pearl You can just manipulate the shit out of everything Because the interpreter leaves everything open and so you can do all that. So what what is this useful for? Well, not a whole hell of a lot. It's a very it's a low-level internal thing But you can do interesting stuff So what I've done is I've created a module allows you to programmatically either in queue meaning just run this in the next The next iteration or you can specifically append or prepend to the list because actually what pearl does internally for all these These blocks it just has a an AV a pearl array And it just stores them in there so you can push on to it. You can pop on it. You can unshift you can do whatever you want I don't recommend doing whatever you want because it probably will segfault for sure because you're going to confuse pearl Very quickly, but what this tries to do is give you sensible versions of it. So For the most part the most useful part that I found of it is when you're in a begin block You can actually in queue for something to run in the next begin block Which just becomes really useful for weird mop stuff, which I'll show you later But this right now will give you some idea of maybe where you might be fine be able to use this So in your import if you were to do a bunch of things in your begin routine, I mean nobody does that right? We don't have a million-dollar euro companies built on on that. We do that badly at booking. It's proud. Yeah, Liz She's guilty So so at booking we do a lot of preload stuff and we we try and preload as much as we can in the compile time of Of the pearl interpreters so that yeah all our worker lifetimes are very nice and very clean This would be a way maybe to check it So we would check we'd start the timer and then actually at the end of compilation for sure We could we could then check the timer. So if we were to do a lot of stuff, we could test things like that It's hard to really come up with examples for this module Because it's so weird, but it's one of those things that when you so when you find yourself When the solution presents itself and it's this there's no other way to do it So it's really but it's really about controlling the different Compilation steps and the reason why is because a lot of the things that I'm doing in here is we'll see as we go Long it's really important that they're all finished by By the by the beginning of runtime and this ends up with two two main benefits one for the pre fork So you're not doing you're not pre forking and then doing a bunch of work You're you're you're you're able to do all the work in the pre fork and then handle the copy on right and things like that and then also Modules like B double colon C which compiles your pearl application is C which C panel uses should theoretically be able to also benefit from this because the way they work is they get to the check phase and they freeze and Then that's where the that's where your C program starts out from so all that work should be done beforehand And you can have it there. So anyway, this is again silly little stuff Okay, next module is also a bit. Why didn't that go forward? There we go. Okay, next module is also a little a little funky Do we have okay? I'm running low begin lift. Okay? How many of you fucked around with Haskell at all? Ask okay So Haskell has this idea of being able to lift subroutines and being able to run them at earlier points and stuff like that This is basically a ripped off half-assed pearl version of that What begin lift does is it allows you to create? Basically things that look pretty much like a statement keyword and They operate very much like a statement keyword and they also do all their work within the compile phase And then they leave literally no trace of themselves afterwards. So it becomes a no-op when it's actually run and executed in In runtime so This one it's very easy to show a simple example, but there's a lot of stuff under the covers I'm not going to get into it because I'm running low on time. I want to get to the next stuff But it's this simple. So if you wanted to write a moose style clone and call it caribou You could do begin lift begin lift and we install into the caller. So the calling person we Install extends and then whatever whenever extends runs it does this so this is obviously pushing on to the is a So it's just basically mimicking some sort of inheritance relationship And then you can do this in your code and it is functionally equivalent to in a begin block doing the is a there so again all the work is done in the earliest time possible and There is nothing left for the interpreter to do at runtime So this was also one of the things with moose is that moose did a lot of stuff in runtime And so it had a lot of overhead in that sense this cuts out a lot of these these overhead because it does it as Early as possible into the interpreter so That one's weird. So but those two parts are very important bits. You'll see later Sorry to build up like I said, I just wrote this talk beforehand. So I I'm Improvising so the actual mop. So the mop is a meta object protocol mop is essentially an interface to things like classes and methods and slots and also in this case roles. So roles are a concept that Well, they go back to small talk in the traits paper a long time ago pearl six picked them up We introduced them to pearl five with with moose and some other things and they've actually they've gotten pretty good traction Most other languages are starting to have something like this traits and Scala What was the other one? There was a Rust has traits stuff like that. So Mop role is basically an API to all that kind of stuff It is based on universal object in the sense that it follows the has convention convention for the slots Okay, it is also stateless This was one of the big problems with moose was that moose kept all this state in the meta object And all this state in basically was in the pearl interpreter And it had to keep them in sync at all times and that that cost a lot This doesn't care at all. All state is stored in the package in some way. So methods are stored in the stash Slots are stored in has Inheritance relationships are stored in is a etc. We don't store any state. So this makes them very easy. They're minimal overhead They have very little extra memory added because they essentially just bless a reference to whatever is they're introspecting so bless reference to the the code bless a reference to the to the actual stash of the class And so this allows them to be to be built lazily built lazily And and and then have minimal overhead. So again fixing some of the stuff in and Fixing some of this stuff in moose This is essentially how they work how they fit together A roll is going to have a bunch of methods one for each Method in the in the class and have slots one for each corresponding slot Mop roll covers all this functionality because a roll pretty much is something that has methods and Basically the only difference between a roll and a class is that a roll can't be instantiated and a class can So a mop or a class can pretty much have all the same capabilities of a roll So mop or a class does a roll roll roll class class does Roll roll if that makes sense, right? Okay, that was clear, right? Anyway, so it's it's meta circular in that way, but it's but it's low overhead Um, uh, so, uh, sorry. This was what I was talking about before inheritance information is in the is a the methods are stored in the actual package stash The roll relationships and does and the slot information in has produces a very small overhead So you end up um What was I going for with this one? Okay, oh, oh, sorry. Sorry. Yeah, so if you remember this before we had Sorry, like I said just was writing the slides as I was standing out there Um, we have the has so we have the x and the y for the point and then we want to inherit Uh here in point 3d. Well, this is a pain to have to do this And and one of the things about pearl o that has always been painful is that you repeat the same strings all the time So there's always a possibility of a problem there so Here comes the mop So, uh mop roll new, okay now if you all remember before that looked like a class, right? So why am I doing a roll here? Well because a roll is a subset of a class and I don't care about the function for what I'm going to do I don't care really about the the functionality actually. No, should I do Never mind ignore me forget about that. Um, anyway, I create a bunch of rolls in there go in the mro. That's the uh, the uh Post-fix dereference syntax very nice. You should all try and use it So what this does though is this goes through all the different classes that I inherit it from Okay, so that's going through all the mro's there that first loop in the second loop I get all the slots in all those classes and then I go through And if if I have the slot of that name or if I have an alias slot of that name I skip this but otherwise I put it in there and what this essentially does is it grabs all the inherited slots Pulls them up and merges them cleanly into one spot So this is the type of thing that the the mop can do it can manipulate and and combine all these things together Uh, uh for the for inheritance, uh, you could it you the roll composition works in the same way So it's the api into the methods the slots the the rolls and the classes and you can build so for that So um, and I'm running way low on time. So, um, real quick here method traits. Um How many of you know, uh pearl six traits? Or python decorators Java annotations Okay, so it's like that, but it's better described as an actual use case for code attributes Do we all know what code attributes are those things after a colon? On on a subroutine that nobody ever uses and everybody's like what the hell Yeah, you probably use it. Yeah, a few of us have used them in anger here and there Um, I've never found a good way to good a good use for them because there's such an annoyingly tricky and difficult api To get your head around so every time you get five minutes into it you go forget it. It's not worth it So I finally persevered so because I really do like annotations in java I want a similar feature in pearl and it's and I want it to behave in very much the way the pearl six traits do Um, so that's what we have So you have to load a trait provider, which is essentially a package with uh with subroutines named For your traits. Okay, you're basically just associating a handler with with other stuff So what this will do in the background is it'll actually use that b compiler phase hooks To install a begin block that will install all the things that you need to collect to all the the weirdness of the pearl api to collect uh this information and and to apply or i'm sorry and to apply the the uh Provider um, and then it'll remove itself It'll then encode another inject another begin block to remove all evidence of that So you don't see that you just use the feature in pearl It takes it all away. It cleans it all out because essentially otherwise you mess up your namespace So That's how to implement that It's all you do. That's your provider uh thing the uh The handler gets the meta object. So this is a mop class object The method name that you had that you attached this to And then any any other additional information. So if you remember beforehand We have the type read only read write and then the slot value in there So basically just write this and it uses the mop again to add a method of the name And it creates a a read only accessor or a read write accessor and using the slot name there Um This uh Is also introspective. So if you if you get a mop method object You'll find that the code attributes are there. So we do leave them leave those in there for because pearl expects them Then you can also grab the actual trait object, which will have it broken down into the actual Name of the trait the arguments for the trait and then you can actually find out the fully qualified name of the handler That's going to be calling it as well Um You can get crazy with this if you want Uh get opt here So we're getting this string We're going to obviously turn this into an ops spec, right? And then we got these this is also by the way Not only is this maybe a good use case for these this feature It's also maybe a good use case for the uh The pre-declared subroutines because i'm going to build the entire guts of this I might as well just not bother setting it up here. Um Get opt is implemented like this Okay, now you're all going what? That's because get opt and again if you've worked with java annotations java annotations Just smack some stuff onto your class and then you can tell java annotations Whether you want you want them to keep it at runtime or or do it at at uh, or just keep it for compile time But another class has to inspect that and do something with it So it separates the concerns a little bit there. So in this case just for this case I implemented to get up in this way So, uh, I can loop through all the methods in my meta. So assume that's my class Uh, I can get the if I have a code attribute that is opt. So I know that I'm looking for that I can get rid of them if I don't have it Uh, get the trait make sure that the trait is also opt and then from there I can build the ops spec So I had all those strings I can start to slice them up and build the ops spec And then I can pass it in to get up long and then I can get my values out and I can be done I actually have a test of this that works with all the code that's missing and I'll comment it out here Um, but uh, there's this, uh, this is also if you're familiar with Jackson, which is a Java library for for, um, uh, JSON serialization and data binding this same thing can be implemented through the same way also have a test that shows that working Uh, if you've used the jacks rs, uh, web service, uh, annotation sets Those are also very nice hibernate hibernate has some annotation sets for, uh, validation Basically porting all these things to pearl would give us a lot of a lot of stuff and as I said before all this happens at begin time So it all happens early early early in your process outside of your pre fork. So, okay 10 minutes. So this is fast. Um, moxie is, uh The moose redo but not really so, uh, I don't have a better name for it. Um, if anybody hasn't good name for it We can come up with one. Uh, but essentially it uses all those things that I just showed you before So extends and has are both implemented with the begin lift. So again, these things all happen, uh, very early in the compile time Um, and turn into the the canonical versions of themselves We're using method traits. So we have, uh, all your all your standard, uh, moose things You have your read only accessors your read write accessors. We have predicates that we can you can, uh, uh, set up Clearers like a lot of those those features in moose to generate different types of accessors It did it here or we have versions of it here. Um, and you can see also with the extents now One of the things I know some of you might be looking at these and saying, okay We've got some redundancy here, right? We we got x up there and y. Why aren't we associating our our accessors with that? Well, again, uh compile time it'll know it's here. It's there's less for me to generate I just have to stick in a new version or a new sub, uh, but the glob is already there. So we're we're doing we're doing less work number one and two Sometimes you want encapsulation So one of the biggest criticisms I've always gotten with moose is it encouraged Struct style classes meaning you create a bunch of of fields for your class And then you have accessors for all of them and everybody can get to everything and everything's public So with moxie, that's not the case you can you can set uh your your accessors and and your and your slots are separated differently And then oh crap and I don't have it in here and there's also private accessors And when I say private accessors and I totally forgot to put a slide in here for this When I say private accessors, I mean we generate lexical subroutines that are not available in the dispatch of the actual Class and they are also not available In to to anybody outside of the class because they're truly lexical subroutines within the scope of the package And they know what they know what self is automatically. So you can basically do all stuff I totally forgot to get a slide for that. It's in the test suite Anyway, the point is we're generating a lot of these accessors for you in a slightly different way Um than normal moose, but it allows you a better set of of of uh encapsulation So you can have a better separation between what is your state? Which is the the slots that you have and then what is your access and how do you how do people access that state? It also works with overloading and stuff like that. So, uh, we got the accessors there This is just because signatures, uh, because apparently overloading sends a whole bunch of extra arguments into your thing. I don't know why Um, oh, oh, so moxie moxie also turns on signatures Um, and moxie turns on post-fix deref. It turns on current sub. It turns on lexical sub It turns on post-fix deref qq. It turns on ref aliasing It turns on every cool new feature that you could ever want including strict and warnings in uh in in in its import So it's sort of like moose in that sense and then it forces you Forcefully into the future if it can Um So this is a test that sort of runs, but but uh doesn't actually entirely work yet Uh in there and i'm just these are my last little bits here But I just wanted to show how you could extend things with the traits. Uh, the method traits mechanism Uh moxie supports it already. So, uh, we can guess what this does. It's a read only Accessor for the description json parameter just tells it. Hey when you're collapsing this object from json Make sure you turn you store a field for description and a store for a field for is done And when you pull it back out, you can do the same thing and and and get it out of there Um, so these are just annotations again. They were on outside. Yeah, I know it's you're looking at me like what? Yeah, I'm sorry. I'm going really fast here Anyway, wouldn't this stuff kind of stuff be cool? I mean catalyst did did uh all sorts of messy shit with this stuff But now we have subroutine signatures. We can add these annotations here. Here we go. Ta-da web service done Okay Okay, and and what's happening is there's not much going on in the class So the class is very very testable because what's going on with put and consumes. It doesn't do anything to the class So the class on its own is entirely testable by itself in this way now I may have a runner that generates understands all this meta information in all these places And then creates something that runs this And properly delegates to these other bits that are just doing the data bits Again, if you look at jacksrs and some of the java annotation stuff It works out very nicely because you add all this meta information And you don't really need to care about it when you want to test in isolation But then when you want to run it in in a particular environment, you you the meta information adds to it. Anyway Sorry, getting all crazy What? So, um, yeah We're building on this. It's getting there the status Um, universal object is stable. I've been fiddling with this thing for jeez. I don't know like Eight nine months now. Um, I've been writing a bunch of new classes in it stuff like that. That's entirely stable I totally recommend people trying to use that Uh playing with it. I love bug fixes feature suggestions Other stuff like that. Um doc fixes, please Um Other one the other two those are those are they involve xs that I wrote So i'm not going to put them above alpha until I get somebody else to look over my c code Um, but uh, but those ones they work something they didn't work Just that I wrote the c so that's a bad thing um The mop i'm calling it beta But this has been around for at least a year and a half now and i've been using it in various places For at least a year and a half now I'm calling it beta because also there's a bunch of stuff that should be moved into xs that is currently using the pearl Pure pearl horrible crazy weird approach to it. Um, you move it into excess. It'll be a lot faster But again, I shouldn't write that excess. Um, and that's complicated excess. Uh, but that's fairly stable from an api perspective Uh method traits and moxie. I was hoping to get released Like before the talk, but I didn't uh because I was working on the slides So but these things are moving forward. Um, I I spent five years fiddling with this project and this idea of Let's get some more modern, uh stuff into pearl but get it into the core Uh, and finally now we're moving we're moving forward in this. So, uh, yeah Questions thoughts, I don't know if I have time enough for questions actually Three minutes three minutes three questions one minute one minute each When is this expected to get into the core? So the plan and the rule was always put it down in cpan Give it a little bit of time to shake out all the bugs and and stuff like that. Then we'll move it into core It's a negotiation. I basically the Sawyer and everybody in p5p Running through stuff like that. Um at the moment, they're all very minimal on their dependencies. So should be Pretty easy, uh to to install from cpan Worst cases you have to get a new test more or something like that and that pulls down the whole world or something But uh, but yeah Question So I couldn't figure out his Thing um the the the the only thing that I was able to sort of figure out at one point was um There's a develop begin lift which raffle wrote but that's full of crazy stuff as well No, this is everyone. So a couple of people have tried this in various different ways Um, I didn't care about some of the things that they cared about and they didn't care about some of the things I cared about eventually I'd like to see them all merge because I think they all try and do the same thing But uh, there's just level of crazy Yeah, so any other questions? Was there no we're good. Okay. We're done. Thank you You