 All right, my clock is showing two o'clock. So let's begin. All right, welcome everyone to LeoBuilder Components Can Break Your Site. Here's how. Part two, I just want to point out that I will be speaking fairly quickly because there's a lot of content here to cover. And that's a great reason why we record these. So let's just dive right in. All right, so first of all, who am I? I'm Andre Angel Antonio, I'm the founder of Performant Labs. I've been working with Drupal since 5.0 and those are some of my clients. Performant Labs is sponsoring LeoBuilderKit, CampaignKit, PaymentStripe, and is the founder of the Drupal Quality Initiative. So today we'll talk a little bit about the LeoBuilderKit because it has something to do with components but we won't be talking about the other modules that you can go find them on Drupal.org if you'd like. All right, now where to find this talk? The notes for the talk and the video will be at that URL. It won't have the video right away. That'll take possibly as much as a week for it to go up. We'll see. And this is part two of this important topic. So definitely watch part one to understand how important this topic is and its impact when building modern Drupal websites using LeoBuilder. And that's where you'll find part one and the video is there ready for you to watch. All right, what we're gonna cover today, we're gonna do an instant introduction to. I'm going to review and demo the problem. Going to go through a little bit of component anatomy. Gonna talk about where content of components is stored. Look at how complex are the components and if the component is stored efficiently, we're gonna look a little bit on LeoBuilderKit and some of the design choices that reflect what we'll have talked about. Some LeoBuilder rules to live by. I'll go over a clever workaround that I promised in part one and some interesting notes. Finally, I'll go through some resources and then we'll do some Q and A. All right, so let's start. A note on nomenclature when discussing LeoBuilder, a component is the same thing as a block. And Drupal 8 is an entity, which you could call a component of some sort or a block in the context of using LeoBuilder. And in most instances, a page is the same thing as a node. If you hear me use node or page, that's usually what I'm talking about in this presentation. All right, introduction to LeoBuilder instance. LeoBuilder is a souped up panelizer if you've worked with that module. If you haven't, LeoBuilder is a way to control the presentation of several parts of Drupal, including nodes, blocks, taxonomy terms, and even menus. Today we're gonna just focus really on blocks inside of LeoBuilder, but a lot of what I'm talking about today applies everywhere. Sorry, all those four areas, that's just the specific. So LeoBuilder allows you to create rigid layouts that content editors can't change or layouts that are almost completely editable by content editors or somewhere in between. Hey, Matt, welcome. All right, let's do a review of the problem. There are many ways to store the content of components. Some of them will break features such as versioning workflow and workspaces. This is the hub of the problem. And if you're not careful, there are ways to avoid this, but if you're not careful, you will break those features and I'll show you how. So let's do a demo. Okay, so let's see, I start the video. I've learned my lesson to record ahead of time. So here's what we're doing here. I'm going inside the custom block library and I've got already a custom block type, but I'm gonna create a new one. And this is the typical way that people make blocks in Drupal right now. And this is a way that can get you into trouble. Okay, so now I've got my custom block type. I'm going to make a block of that type. There we go, it's a super welcome message. Yeah, thanks for saying that, Tori. You can click twice on the screen share to make it bigger. Very simple block and boom, now I have a welcome message. So people will typically go create a block like this because this is how you've done it for years inside of Drupal. And now we're gonna go create a basic page. Now ahead of time, I've already turned on layout builder for the basic page content type. So I'm not gonna show you how to do that. I'm gonna assume you know how to do that. All right, so now I go inside of the filter. I type in the welcome message title so that I pull up that block and I go click on it. All right, so now it's inside of our layout. And then you say to yourself, well I'm gonna go change the content of that block. Somehow I click save, go back here, refresh. Huh, okay, that probably makes sense though because I'm pointing at the most current version of the block inside of the layout. So now I'm gonna go create a new revision of the layout and I'm going to differentiate it by adding that new block so I can tell that it's a new revision. And you saw that the checkbox has turned up. So there you go. There's the new revision. You saw the powered by Drupal. Let's go make another change. I go to move that or bold it rather over here. Okay, well, maybe that makes sense too. I should have seen that change but now let's go back in time. Wait a second, that was the old version. And I am seeing the latest version of my block. Just to prove it for sure, for sure. I went and clicked on revert and there you go. You're still showing the latest version. And boom, all of a sudden your revisioning is not working. And if you have a client that's expecting that they can go back in time and get an old version of the site or an old version of the layout, that's not gonna happen. Now I don't recommend using this sort of mechanism if you're going to do a, if you're gonna use it for legal needs. There are external tools that companies should be using if you have to have old versions of your page. And you shouldn't be relying on revisioning because it's just not accurate. Okay, so I go through. I'm just proving my point. I've added another block. Sorry, I've made another change. This time I'm making sure that there are new revisions in the block. I don't know if you caught that. So this time now I'm using new revisions and boom. So this is a problem. This is a problem. All right, let's keep on going. Let's take a look at how it should work. Okay, we're gonna do this again. I'm gonna start this time from an empty page. I've still got the super welcome message block type this time. Now I'm going to go add a page. This part's the same as the last time. All right, I go down, I click on add block. But this time I say create a custom block. So instead of choosing it from the initial list, I choose it from the custom block. It's a huge difference here. So watch what happens. It uses the fundamental structure of the block type that I created. But it's not using the content because I get to add the content inside of the panel on the right hand side, the editing panel. Okay, so I've got now a component in there. Let's go take a look inside of the database and you'll see there's my block ID. So sure enough, it's storing it there. But it's now inside of this different set of tables. That's the inline block usage table. And let's go take a look at what's being stored inside of the layout table. So we pop over here, we reformat that, paste it in the larger section. And this time, look at what you see. Look at that, there's a revision ID that's being stored with the layout. Now I didn't show that to you before. The reason I didn't show that to you before is because it wasn't actually storing it. When you use the block, it does not store the revision ID. So let's prove that this is gonna work by making some changes to the content. Notice, gonna create a new revision, save the layout, boom, you see it. Okay, so now let's go back in time and ta-da, it is in fact the old version. Now let's go back to the revision ID. I showed you that there is a particular revision ID attached to that. And there you see the most recent version of the body value. That's what's always stored in the main tables. And let's go now take a look at what's being stored inside of the layouts. Whoops, I had made a mistake. So we're gonna go try that again by reformatting it. And ta-da, take a look now at that line, you see a different revision ID. So when you use custom inline blocks, your revisioning inside of Layout Builder will work. But if you don't, it won't work. And there you go, I'm just showing a little bit more of what's happening behind the scenes. By the way, this is really valuable for developers to really understand how things are being stored under the hood inside of the database. Don't be afraid to go looking inside of there and learning all about it. So now I'm gonna revert just to make the ultimate proof. Take a look and ta-da, it's the old version. Did the revision number change? The revision ID, let's go take a look. Paste the new one, reformat it. Got the new format. And ta-da, it's back to revision ID number one. So you can see Layout Builder is just simply handling everything properly. Benjam just about to move to the next slide. So I'm gonna come back to your statement because I'm just concentrating on where I am. Now notice that you don't see the content, you don't see that block that you just created inside of inline blocks in the custom block library. So it is really and truly a different way of saving content. All right, let's keep on going. Okay, so the problem basically is what you're seeing in this diagram is that even though you can have multiple revisions for Layout Builder, it can point to the same child. And often it's the most recent one and that's what gets into trouble. So if the child doesn't have a revision as well as the parent, every page will always show the current value of the child. If the parents don't record the revision ID of the child, which is what happens in the first case, every page will always show the current value of the child. So you actually need both of those to be true. You need to be revisioning the children and you may need to make sure that the parents are keeping track of the revision IDs. So let's now take a deeper dive by looking into some component anatomy. So the three basic standard types of Drupal components, you've got the global component, that's what I showed you at the beginning and that's the custom block library where people tend to create the blocks ahead of time inside of that separate page and then they drop them wherever they want all over the site. Then you've got the custom inline, that was the second demo. They're non-reusable components for now but I'm gonna show you a patch that's gonna change that. And then the third way is serialized. And I'll explain these. So what are we gonna look at? Well, we're gonna look at where is the component content stored? How complex is the component? Is the component stored efficiently? Okay, how are components made? Well, you could say that components are divided into three parts. The first part is the front end, that's the rendered HTML. The second part is the configuration and an example of the configuration might be the location on the page. And then the third part is the content itself, what it's supposed to display. So how is the configuration stored? Let's get that handled right away. The placement of the component in its configuration is always stored as a serialized string in the appropriate table. And I discuss what the appropriate tables are when you're looking at taxonomies, nodes, blocks and menus in part one. I go through that in some depth. So go take a look at that if you're curious. But for now we're just talking about blocks. So where is the content stored? Well, you've got basically two options. You can put it in separate tables or you can put it in the page. Let's take a look at the separate tables first. This is option one. The content can be stored in tables. This is the customary way people know how content is saved by using custom blocks. That's what the table structure looks like under the hood when looking at blocks. Adding more fields to your custom block type will add more tables because the way Drupal now is working is it gives every field its own table. The second place is in the page. You could store the content and the configuration in the page layout as part of the serialized string. Content and configuration is automatically revisioned this way. Version one of LeoBuilderKit components use this mechanism. So does Aquiasite Studio. So does Project Gutenberg and so does DXPR formerly GlazeBuilder. We all went down that path probably because it's actually the easier way and you don't mess up the revisioning. So where is the content saved? Again, well, option two is you could by making a custom object store that content with the configuration just add the content to the serialized string at the end. Oops, I think I've already covered that. Wait a second, I got a mess up there. Well, the two different ways of the table are in the serialized string. So we've already covered both of those. Now, the next thing we wanna look at is how complex is the component? Because this makes a difference. If you've got just a single tier sort of component that you're making a custom component, then things are much easier on you. If you've got parent-child relationships, then they get a little bit more difficult and then you've got parent-child-child relationships, they get more difficult again. So here's the single tier, something simple. Here's a single tier with revisions. Then you've got two tier. You've got a main parent up above that then you can have a second table that stores values that the parent uses. And then you can do the same thing, but you can add revisioning everywhere. Okay, so that's generally how these things work. We're not gonna go parent-child-child, we're just gonna do parent-child. So how do you wanna proceed? Carefully, be very aware of how your component content is stored, especially if older versions, revisions, or workflow or workspaces are needed immediately or in the future. Understand the details of each component type and test everything thoroughly. Yes, Benji points out, and then there are translations, no kidding. Do not assume, test and keep detailed notes. You will forget this stuff in three months if you're anything like me. So have someone on your team or you personally learn all this stuff, record all the decisions you make as you go and keep that handy for everyone to refer back to. Teach everyone on the team about this issue because it's quite possible that you have someone come on to the team. They don't know it and they go make an error and all your good work is down the toilet. So rule number one, if you aren't using serialized string storage, everything must have a revision ID. But remember what I said earlier, rule number two, make sure the revision ID is actually being stored and used. Okay, now the next piece we're gonna look at is the component stored efficiently. So you've got basically four options when you're storing the content using tables. First option is one table per field. That's using the field API. Second one is one table for all the fields and that's using the entity API. You have to do some custom programming to get that to work, whereas the first one happens automatically. And then you have a hybrid possibility, which is using the entity API and the field API. Again, you need to do a custom module for this. And then the third one is you could use NoSQL. Now, I haven't come across anyone who's used NoSQL yet, but I think at some point one of us is gonna try it. So let's take a look at each one in turn. One table per field, consider a component that has three fields, the event, title, date, and location. And each one of those is stored in its own table. Drupal fetches these in a single query with SQL joins and populates an internal object with the result. So it goes and grabs all the data from the separate tables and puts it together in one object and hands that back to the developer. Does this automatically for us. Now, as you add more fields per component, it gets slower. And as you add more components to the page, it gets slower. That's another problem people can get into, which is they merely make all their components, add lots of fields, add lots of components to a layout, and then all of a sudden it's just dog slow. The next one is one table for all the fields. So you can make your components and custom modules and store all the content for the component in a single table using the entity API, not the field API. And that's what it's gonna look like actually on the database. Everything, all your fields are gonna be in one table. Drupal moved away from this system for some flexibility, which I'll discuss a little bit later. But that's how it used to work in Drupal 6 and earlier. And a lot of other website management systems or content management systems still work that way. What's the advantage of this? Well, Drupal fetches with far fewer joins. So it's much faster. Or you could do a hybrid model. You could use the entity API to store a whole bunch of fields in one table and then add extra fields that go in their own table using the field API. That's also valid. And this gives you a mix of flexibility and performance. And if you're keeping track of all the revision IDs, that can work. Then the third one is NoSQL, which is using a semi-structured form of data storage. And I hope at one point in the future to be able to make another presentation showing how great it is by storing everything there. But we're not gonna cover that today. Okay, so what was the problem again? Well, there are actually three parts to it. Problem number one, revisioning can break. If people use Drupal the way they're used to with Layout Builder, not using the inline blocks and do not use custom components that use serialized storage, revisioning reliant features will break. Problem number two, a table per field. Recall that when the component content is stored in fields instead of serialized and stored with configuration, Drupal creates a table for every field. It does this in part to allow for fast database structure changes on production databases. What was happening in Drupal 6 was it was taking hours, eight hours sometimes for a add field or a delete field to be executed on a MySQL database. And you just can't take a production database out of commission for that long. So to provide more flexibility in various ways which I won't get into and also to make working with really large databases easier in the sense that they actually, you can make changes to the data structure without taking down the database for eight hours. We move to this one table per field mechanism. To collect all the content for a single component requires a SQL join statement between the multiple tables. And if you have many, if you have a page with many components collecting all the content for all the components will be really slow. And I'm not joking. We tested this. It was unusably slow on pages with many components. Now, I should say we had a lot of components. These are very, very long pages. I can't divulge which client that was. I was supposed to say it's slow. Okay. And problem number three can't leverage the framework. If there's so many problems with storing content in tables why not just store everything in the serialized string and call it a day? There are other parts of Drupal that open up to you by using tables like using the diff module to compare what changed between two versions of the page or getting your content easily into the search index. And many more contributed modules exist and will be made that work with content stored in fields instead of serialized strings. It's just kind of a pain to work with serialized strings harder to do searches. It's kind of the equivalent of in Drupal 7 or rather earlier, I guess because we started to have the render pipeline in Drupal 7. It's like trying to work with HTML just before you're about to send the page to the browser and trying to do some sort of last minute changes. It's fussy. It's difficult. It's error prone. So working with serialized strings is not always the best idea. So you want to use table-based storage if you can. So how do we get table-based storage to work for us? Well, it's really the parent-child relationships that are the problem. And what you're looking at there is an example parent-child relationship. The parent is the component as a whole and then the children are each one of those tabs. The moment you want a custom parent-child relationship such as a tab or a carousel component, you could add another table. This is again in a custom module. This is not using the UI. You could add another table via the entity API to hold the children. Totally viable. If you do that, though, you are in charge of propagating changes to the children when there are revisions, right? Standard Drupal will help you do that. Using the inline block mechanism. But if you're going to make your own custom ones, you have to be careful and you have to make sure that you're propagating all the revision IDs. And if you don't do that, revisioning will break. But is there a way for Drupal to handle that for us? Well, there is. There's a clever workaround. Fellow Drupalista Andrew Thornton came up with this. Thornton came up with this clever workaround. Create a new custom field definition and add it as an unlimited field to the parent entity. That's equivalent to in the UI, choosing unlimited when you're specifying the storage for a field where it says a loud number of values. So instead of it saying one or a specific number, say unlimited. This leverages Drupal's built-in machinery because the children, which in this case are individual tab elements or slides in the carousel, are simply values for a field. And Drupal already knows how to organize all that and keeps track of the revisions. And when using an inline block, we'll properly store the revision ID when it's needed. Under the hood, this is employing the Delta field for those developers who know that. So the Delta field helps store multiple values per field. This is what it looks like under the hood. The normal base table stores the parent fields, maybe just the title, and the field table stores the children. And you can see that there's a Delta there, zero, one and two, and each one of those refer to each child, okay? You're gonna have to create your own inline block and you're gonna wanna implement this hook in order to use it. Okay, so that's another piece you're gonna have to do. And you're gonna need to create your own field definition. Here's an example. And when you do your own field definition, you have to be sure to set the cardinality to unlimited. All right, so that's the clever workaround. Now, instead of using this clever field-based workaround, we could create as a community, we could create some helper classes that support parent-child relationships and even parent-child-child relationships that use tables. You could do all that. I have a suspicion somebody at one point is gonna try that. And for parent-child-child relationships, if you don't wanna go down that route, we could also store the second child in a serialized field. Once the data are in the serialized field, any data structures is possible. But then you have the same problems as we had before. Might not be as much of an issue because if it's the child and the parent or the second child, maybe you don't need it to be searchable in your index or maybe you don't need to compare it between revisions, stuff like that. Okay, so what does LayoutBuilderKit do? Well, version 1.0 currently uses serialized string storage. And as far as I can tell, all the other page mechanisms or page layout systems use the same system. So here are the components so far. So you can use those right away. They will not break revisioning. Why? Because all of the content is stored inside of the serialized string, which is stored with the configuration. And if you want a full walkthrough and learn how to contribute components, there's a link for you. Okay, so what's next? Well, I'd like to get these other pieces working so that we can get the diff module working and whatnot and make sure that the content is in tables in a performant way. And so version 2.x of LayoutBuilder will add components that use the entity API and Andy's clever field technique. Site builders can then assess competing requirements and choose the storage mechanism that makes sense for their build. In other words, they can use version 1.0 branch or version 2.0 branch. Now contact me if you'd like to help develop these base classes. I think it's gonna be fun. Okay, in summary, I fear that there will be many broken Drupal sites made by teams unaware of these issues. Unfortunately, Drupal will be blamed when it's actually a site build issue, AKA it's our job as site architects to know about this and make sure that we don't mess up our builds and then have unhappy clients. Because boy, backing out of this stuff once you have an entire site full of content is not gonna be a fun conversation to have with your client. Don't let your site be one of these. Really, really pay attention to this, please. We don't want a black mark on Drupal for no reason. Okay, so let's take a look at some interesting notes that I think most people here would be interested in learning about. It's not yet possible to export and import layouts, but it should be ready soon. And that's the issue. You can follow that. I think they're on like patch. No, I think they're like 100 comments or so. So you might be able to try to get it work. You might be able to apply the patch and then you can do export and import of layouts or you may not have tried it recently. Another interesting note, layout builder everywhere will extend layout builder to regions of the page other than the main content area. And that's the link for that. So right now, layout builder, you get to only work with the content region and the header and the footer, you can't do anything with it. Well, layout builder everywhere actually allows you to do it in the headers and the footers. What's the holy grail? The holy grail is that at some point, the entire page, you can just use layout builder. That's coming. Okay. There's a patch that brings layout builder into page manager. Now, page manager is the part of panels that a lot of people think about when they make variants. And so that issue, which is create a layout builder variant, which actually has been committed, allows you to use layout builder inside of a variant inside of page manager. I have been waiting for this for a long time. This is fabulous. Okay. So I'm interested in notes number three. Work is underway to allow blocks created within layout builder to be reusable, specifically the inline blocks. I should have written that inside of that comment. It's we're now specifically talking about inline blocks. Now, will a reusable block be versionable? If so, will each of the components, will each use of the component on separate pages show the latest version? Like if you change a component on one page, will it automatically change on the other one? But what if on the first page, when you updated the component, it used a new version ID. And on the other page, it uses the prior version ID. Interesting, right? We don't know yet. Or will it show the version it was last saved with? Answers are as yet unknown. So don't forget to check this additional use case when the patch lands. There will be a checkbox that says reuse this block. And you might wanna be very quick and put in a hook that takes away that checkbox or we might land ourselves in real trouble once that patch lands in core. All right, so here's some resources. Okay, if you'd also like to learn about layout builder extra modules, there's a really great group of contributed modules now for layout builder. I think they're probably up to about two dozen. As per normal, a lot of these features are gonna get rolled into core over time, but right now you do really wanna look at the entire emerging layout builder ecosystem, all the different modules like symmetric translation or asymmetric translation, those immediately are required if you're gonna do some translation. But there are many, many, many more, very helpful modules, okay? And then if you'd like a current list of them, go to that page, all right? You should also check out DXPR. You should check out Aquia Site Studio, although I do believe that you have to be one of their clients in order to get access to Site Studio. So that was a cohesion. They renamed it to Site Studio, but cohesion was made by, I don't remember, but the brand name was cohesion and then Aquia wanted a cool systems for marketers to make pages very quickly. Cohesion had probably something like 25 or 30 modules or components rather. Now compare that to layout builder kit, which has only seven and there's another module called pattern kit that I need to check out. I don't know how many components they have, but in any case, right now our alternatives to these private sort of offerings don't have as many components as they do. So we have a lot of catching up to do. Oh, perfect. Thanks, Martin. Okay. Elementor, that comes from WordPress. I know nothing about it, but apparently it's now available inside of Drupal, which is interesting. And Gutenberg is actually, the WordPress project Gutenberg is now actually available in Drupal. And now we move to Q and A. All right, so I'm gonna try to go back in time to see if all the questions got handled. JSON API will help with export, but import. Let's see, did anyone answer that? I can't tell you about the JSON API. I think Benji, what was happening is that patch that I showed you about how to export layouts is required in order for JSON API to work. I think that what they found is, correct me if I'm wrong, but I believe that the team who was trying to make the JSON API a really full-fledged system discovered that there was no way actually to export layouts. So they had to get to work on that patch. So I think that's what's happening there. Double field. Interesting, Joe, I don't know what double field is. That's cool. I will check that out. Okay, there were some modules in D7, multi-field and composed field, but I don't think they ever got a port to D8. No, I don't think they did either, James. And the interesting thing is that Andy and I were talking this week. One other possibility that that team is using is actually paragraphs. And they're finding that the revisioning is working. So you could use this custom system that I showed you with the base definition, the base field definition that you make it yourself. And since you're gonna be using the entity API, it should be super, super fast. But if you use like usable in a high throughput sort of website, but if you are not so interested in performance and you just want the convenience of what paragraphs does, people should check that out too, because it might actually still work. Okay, so Benji is saying, right, that patch will expose LB field to JSON API. Work is just beginning on adding JSON API as a source for the migrate API. Yeah, okay, so as is the case often, you start going down one path and you find it, oh, I need to do this. I need to do this. I need to do this. Let's see, Caroline. So if you want a custom block to appear the same on multiple pages, you use the traditional way and live with the lack of revisions. Right now, yes, that's true. Until that patch lands with the checkbox that allows you to make inline blocks global and reusable, then the way to do it is using the other one, the typical way by going into the custom block user interface. Okay, traditional blocks are reusable and the LB just stores the entity ID. Blocks created in LB are non-reusable inline and LB saves the revision ID just like me are. Okay, I think that's all correct. I think I've been saying that it's just sort of coming from different verbiage. All right, so let's see. Okay, I think I got all the old questions. Let's see, in other words, importing layouts will require migrate API no matter how they are exported. What about YAML? No, I don't think that's true. I think that you can, you'll be able to import and export layouts without using migrate API. I think what happened is they just discovered that they need to make that connection as well. Yeah, what about YAML? I don't think that's true. I think once that patch lands, we will be able to import layouts using configuration entities. All right, no worries, Matt. So Benji says the references to double field and others were in response to my question about compound fields using field API. If we have that, then we could use entity plus field APIs and reduce the number of tables since the field table would have lots of columns. Right, okay, so maybe Benji, are you saying we could avoid making our own custom field because there's a module that would allow us to do it for us? And then that's yet another way to do it. Maybe save us some development effort. Yeah, okay, so now it's double field ready in Drupal 8, do you know? All right, well, I'll try clicking on it and see what happens over here. Looks like it's gotten up to date. Okay, sweet. Yes, looks like there's a beta one for 4.0, but the 3.x branch is well used. Fantastic. Okay, definitely wanna check that out. Great, thanks for that, Benji. Okay, he does not know, just discovered that module a minutes ago. Okay, that makes a bunch of us, me too. All right, I think it is, but it's limited in how many subfields you can add is what Joe says. Yeah, probably, I mean, it's the usual. If you want exactly what you want, then you're gonna have to roll up your sleeves and create it yourself with custom code. Right now, we're at the very beginning of this whole process. So we're spending extra investment in time and energy to learn how to do it the right way. And as usual, this period will pass and then we'll just know how to do it and we'll be able to create all the custom modules we want and custom components we want very, very quickly in the future. Okay, if there are no other questions. Oh, Matt, you're very welcome. Matt says, thanks. This is one of the best bad camp talks so far. Benji, there are also problems with parent child relations using inline blocks since LB adds access control. Can you say more about that, Benji? When I was working with them, we just did typical access control and it wasn't a problem. Do you know, did you hit this yourself? Okay, he might be typing up a response there. We had a site that added call out blocks with button block references. Oh, interesting, yeah. So now you have access control in two separate places. Yeah, I got it. Pip, pip, pip, pip. I think we just kept it easy and maybe just kept it all open. We figured if people had access to all those UIs, they should be able to do all that stuff. Yeah, using IEF and the block, child blocks did not show up. Interesting, okay, that's another concern. I didn't personally hit that, but that's great for everyone to watch out. But like I said, if you're being really careful and watching every step you make and making sure that you've documented everything and you understand what's happening actually at the database level, you know precisely where the revision IDs are being stored, you've got use cases where you walk through the people who are reading your document and say this is how it works, then hopefully you discover that before you start building your site. I'm not seeing any more questions here. All right, last chance, another 10 seconds. Okay, all right, let's call it. So thank you everyone for attending. Please share this information far and wide. I mean, we might need some sort of fancy, some sort of fancy name for this problem, the layout block breaking problem in Drupal or something. Anyway, we need something cool so that we can just say to people, hey, have you looked into this problem? Yeah, you should definitely look into this. It's really an issue. And I think there's a way to get around it immediately and then if you're gonna make custom blocks, we've got that clever little workaround. And I think over time, there are gonna be some other interesting ways to get this all sorted out. The first version or the first component that I'm gonna go to work on with the layout builder kit in using the custom field definitions is gonna be the tab component. And like I said, please just ping me. And if you wanna work on it together, I think it'll be fun. It's much more fun to work on this stuff as a group than solo. All right, have a great rest of this year's bad camp. I've been also in charge of working with the speakers in the sessions. And so it's been my pleasure to work with everyone. We've had 40 plus great sessions or we will have had 40 plus great sessions by the end of bad camp, but really it's not just the speakers, it's everyone who shows up without you guys attending these things. We have no one to talk to. So thank you as well for coming, for supporting bad camp. We're non-profits. And our mission is to spread Drupal knowledge and expand the Drupal community so that we have a great future for Drupal. I think we still have a great future for Drupal, especially with all the moves that we're making. And it's been my pleasure to speak with you today. Okay, take care.