 Hello, I am Ronald, this is Adrian, and we are two-thirds of the founding team of RUMIFI. The other person is sitting right there. Yes, somehow we're doing this. I'm sure you've all heard of RUMIFI, right? We're the darling of the startup world. VCs keep knocking on our doors asking us, they just want to give us money, no? I was hoping. Now we are a startup. Our products are based on Drupal, we started about a year ago, and what we do is we build applications with a booking component, and there's lots of different scenarios where you want to manage booking, kind of travel and accommodation is an obvious one. There's libraries that want to book out conference rooms. There's lots of sharing economy scenarios, kind of sharing things and booking when you're actually going to share this stuff. Our main product is something called RUMIFI for Accommodations, and it's, what is it? It's the Airbnb for Airbnbs, no? Does that work? No. It's an open source version of Airbnb, so if you want to build your own Airbnb, you can have this either as SaaS or you can download it and run it yourselves. A lot of what we do every day is stare at this type of screen, so with these calendars and there's different availabilities and different states that things are in, and we reason about whether something is or is not available and how much is it going to cost to change a state from available to something else and so on, right? So a lot of what we do is reason about booking and the state things are in. Now even though our products are Drupal centric, the main thing that reasons about the state of things and whether you can book them and how much is it going to cost and so on is not based on Drupal at all. And the entire thesis of this presentation is this is a really good idea. You should be doing this in other situations that have nothing to do with bookings obviously. So we're going to talk, so the getting off the island part is this, to see whether it makes sense to have a separate library that does a lot of hardcore reasoning for your application, whatever that might be. And we'll see if you agree by the end of this I guess. We then come up with a title for the talk. We completely stole it from Krell, Larry Garfield who in 2013, late 2012, encouraged the entire Drupal community to go and get off the island and look at what else can they use within their Drupal applications. And we kind of took that on and said, you know, how can we do things differently? That's not the standard Drupal way, let's say. Okay, so what I'm going to do is talk a bit about what was our island. What led us to actually do something about it and get off it and how we built this library and talk about ways that you can integrate your library in Drupal. And then I'm going to pass it on to Adrian that's kind of going to get into the more practical aspects of this. So our island for a long time was a little module called rooms. It's not so little actually, it's lots of different modules within rooms. And rooms was our first attempt at trying to build something that reasons about bookings and availability and so on. And we tried to build it as well as we could. So we separated concerns, you know, in terms of the booking problem you have things like the stuff that you're going to book and we call those bookable units. And there's a module that just handles bookable units and their entities. And you have a little API to reason about bookable units. Then there's a separate module that deals with the availability of these things. Another module deals with the pricing, something to deal with bookings and a booking manager that kind of ties all these things together, right? So we tried to separate concerns as much as possible remaining within the Drupal island. So yeah, we used entities and we tried to take out the booking-related concerns and put them into their own classes so that we could isolate them as much as possible. Now whenever I say booking-related concerns, you should be thinking about whatever is the specific thing about your application that you think it's worth isolating. As I said before, the entire point is to motivate why you should try and isolate this as much as possible and put it into its own completely standalone library that can exist in the wider PHP world, right? So with Rooms, we put things in classes and it was in a separate file. That was nice. You could instantiate it and call methods. That's nice as well. But there wasn't much more to it. And the final point is in terms of the front-end, because the front-end, in our case, was actually a JavaScript jQuery plugin called Full Calendar that shows the availability and so on. Almost we were forced to immediately think about how we're going to provide an API to our data so that we can get the JSON that's required to display in the plug-in. So there was a natural separation that was forced on us because of what we wanted the front-end to be. But that actually motivated having a separate API module to get data in and out, which proved to be useful. Are you with me so far? Yeah, cool. Okay, so we did this and it's kind of working. We're very pleased with ourselves. But we still got code that looked like this. So you have a class, availability agent. And within this class, at some point, it says variable get. So this is Drupal code. Means this class cannot work anywhere other than Drupal. And you could argue it's our fault. Why did you put that there? You shouldn't have. But it lets you do it. And it's really quick and easy way to solve that problem, right? And you can, we're calling C tools, plugins, code in there and so on. And yes, you can be more disciplined with yourself and not do things like this. But the fact that you can actually do it in a sufficiently complex application means that it's eventually going to happen. Someone is going to do it and someone else is just going to be too tired to complain yet again. And congratulations, your code just got coupled to Drupal just a bit more, right? So this is the type of things we would really like to avoid and have a very precise way of avoiding it. So yeah, the approach was okay. It helped to some extent, but it was not complete and it was not consistent. It allowed you to make mistakes. It didn't save you from yourself, right? The booking logic ended up being quite coupled to Drupal related stuff. In particular, there was no easy way to completely isolate it and test it. And again, if something is sufficiently complicated and you can't test it completely on its own, it's a huge nightmare. Because we didn't have any namespace management, this was 2011, right? It was really hard to keep track of where all the dependencies were. It's kind of as you were developing the module, all the code was available to you pretty much anywhere. And you just did stuff, and it worked. Excellent, the result is roomify, sorry, not roomify. Well, roomify as well. But rooms in particular became this really complicated thing. So this module kind of worked and you did not want to touch it because it would break things. And that's the worst situation you can find yourself in, right? When you're literally scared of changing your code. We've all been there, I know this. Now, I talk badly about rooms and it's kind of my little baby. So this slide is purely here to alleviate my guilt. Rooms is great, it really works really well. And if you have a small hotel and you need to manage bookings, it's a good solution. But, yeah, it's very insecure and fragile and has various complexes. And it's kind of hard to talk to and it doesn't listen to you. So as any good parent, you just abandon that kid. Well, is that not what you do? So yeah, we decided it's not abandoned. I mean, we still care and nurture for it. But we kind of let it be in its room and don't deal with it. So we build new stuff, right? So these are our ships, together off the room's island. And there are four components to it. I'll talk about that in a bit. So the first thing is this library. The Booking and Availability Management Toolkit abbreviated to BAT, as in the flying thing. It wasn't supposed to be BAT, it was supposed to be, the acronym was supposed to be B-A-M, right? And my wonderful American colleagues were able to pronounce it really cool and it's BAM. And it's so difficult to say BAM, I just want to say BAM. And that didn't work. So it's BAT, which is OK and I can pronounce it without effort. It's, trust me, BAM is just the entire, anyway, sorry. Yeah, I forgot to mention. So I live in Italy, Colorado, Missouri, so we're kind of spread across. So yeah, we have this library in which I'll talk about quite a bit. And then what we did is build a Drupal module that's essentially a configuration layer around the library. What it does is connect the booking specific reasoning and functionality to the Drupal world. It uses the library to achieve things, right? Then we have yet another module, which is an API. And when I say API in this case, I mean REST API. So you can just ask for information, get Jason back, and do whatever you want with it. So that's like another layer of encapsulation that isolates you from the library and from Drupal itself at this point. And in terms of the front end, we're still using full calendar, which is this jQuery plugin. It's a really powerful plugin in terms of showing calendar data. Now, it would be great to be able to say this was all a well thought out plan and the reason we have this four components is because we sat around the table and thought it through and yes, this is the right solution. Essentially what happened is we had decided we wanted to abandon rooms. I shouldn't be saying that, really. Anyway, we were going to build something new. And we wanted to start from scratch, and this would be great. And it would all be as much as possible, but it's still within Drupal. And we would do stuff, do stuff, do stuff. And then we ended up in some discussion about how Drupal does things. And that discussion became even worse once we started thinking about, okay, how am I going to do this thing in a way that I would be able to use it in D8 as well, because D8 was not released at the time, but it was about to be released. So we started doing things like we should use the part of the plugin framework for D8 to D7. So it's kind of similar the way we do that sort of thing. It's just all these Drupalisms kept getting into what we were trying to do about bookings, which is its own isolated thing. And eventually we had something there. And Adrian said, this really feels like it should be its own thing. Completely standalone. And when you're a startup and everything feels so urgent, you have to build this thing so you can sell it and so on. You're thinking, great, so now we're going to re-architect this again, because Adrian had this awesome idea how it should all be wonderfully built. And we were literally having this discussion on the 31st of December. And Adrian and I were looking at our comments as we were preparing this presentation and saying, that was not a good moment in our lives. The thing we were doing New Year's Eve was discussing whether we should build a standalone library for booking and availability management. I think you can at least feel a little interpersonally led into New Year's Eve. But anyway, in the end, we kind of sufficiently got ourselves worked up, that we decided, you know what, this does sound like the correct engineering solution. And a lot of it was cultural. It was kind of saying, yeah, Drupal, thank you, but we're going to go do this thing for a bit and then we'll meet up again. And yeah, that's what we did. We created the backlight. Oh, I should kind of parenthesis. Actually, the first thing we did is we said, well, maybe there is a library out there. And that's the other thing that anyone should be doing, right? Kind of part of getting off the island is not get off the island and go build your own stuff as much fun as that can be. It's go see if this stuff exists. Now, unfortunately, there was no booking and availability management library, which might be something we should think more about. Why has no one ever done this before? Anyway, so we had to build it ourselves, right? Now, how do you build a PHP library? That was kind of my big question. We know how to build Drupal modules, right? We're part of the Drupal world and there's lots of information out there. So we kind of had to educate ourselves in how do you go about doing this? What's the right way? Thankfully, there's just a lot of information out there. And the easiest thing is find something you like and copy it. That's what we do. In particular, what we did is look at the interoperability group and see what they say about PHP code in general. The story behind looking at their coding standard and style guide is that I think it's great, but we're too used to the Drupal style guide and it's not exactly the same. So that's one thing that we said, as a tribute to Drupal, the style guide for our library or PHP library is going to be the way we're used to doing things. But beyond that, everything else in there is really useful. If you're thinking of building your own library, there is a great group of PHP developers called the league of, sorry, I can't read this from here. Yeah, and they are really good quality packages. You'll probably find something in there that you'll want to use. In particular, the reason I'm mentioning them is they have a skeleton package. Like all the bits and pieces from the read me file to integration with packages to tests how your composer file should look. It's like all there and you can just clone it and start working on your own package. And it's going to look and act like a good citizen of the PHP world. So definitely recommend that. The thing that I was really excited about was finally we get to do tests without crying every day. Because, right, you have PHP unit and actually in our case, as we were writing the library, there was no UI at this point. There was nothing other than writing a test to see if the code works. And that was fantastic because it means the library, while not 100%, it's all the important components are completely covered by unit tests. And finally, we're not scared to change our code anymore. So it's like with rooms, whenever you said something, it will answer back and argue and so on. Here, you just, okay, I haven't broken any tests. It's okay, I can go on with my life. The other thing you get access to is automated code analysis. And because it's, everything is very straightforward. There are no interdependencies and so on. You can actually get a lot of useful information. And if you haven't tried this service, they have a free layer. It's called scrutinizer. It's a really useful thing to be doing. It just goes through your code, identifies obvious things, identifies less obvious things. It grades you, which is kind of annoying. You get A's and B's and I'm only showing the classes that got A's here. That's not the whole story, but I'm not showing you the rest. And in general, the developer experience becomes a much more positive one. You feel like you're actually building something that's going to be a standard test of time, it's tested, and you kind of know what to expect. The next step for us was to actually take this library and start using it within Drupal. And there, you start dealing with kind of the day to day experience of using the library and you have to be ready to go back to your library and maybe re-architect some of the concepts. You're going to find ways of calling functions or structuring things that become, you just have different ideas about how to use them and so on. What I wanted to spend a bit of time talking about are the two things that we found kind of the most complicated in terms of integrating with Drupal itself, which is storage, because obviously you still have to deal with the Drupal database layer and output formatting and translation and so on. So in terms of storage, and so just a small side track. In our case, what we have to do is store information about the state things are in over time and be able to reason about that and ask questions such as how many units find themselves in state five or state six or state seven over this time and how much is it going to cost to transform that state to something else, right? And the way to do that is to take time and split it up and reason about this individual piece of time. So the storage that we're doing is atypical, right? So the library had to reason about it. But then we actually wanted to be able to store it in a Drupal database. So what we have is a very simple store interface that just says, get data and put data, get events and put events. Then we have an SQL specific implementation of that which was then extended. So we have one which is SQLite, which we use in the tests within the library. So it's all self-contained. And then there is a Drupal DB store, which is the one that actually interacts with Drupal. And the way we pass that to the rest of the library is we inject it in the class that is going to need it, which in this case is a calendar, right? So you instantiate the store. You tell it where it's going to go find the database and all of that. And you inject that into the calendar, which is then going to use it to interact. And the calendar obviously doesn't know that it's interacting with the Drupal DB store, it's just interacting with something that implements the store interface. There's other ways you could do it, but we found this was a good balance between separating concerns and kind of not doing, not over-engineering anything. And that one library, the Drupal DB store, has two functions which are Drupal functions. So that one class is not independent of Drupal. It will only work within Drupal. And this is how it looks. You instantiate the store, instantiate the calendar, give it the store, inject it in, and then you can go get events, right? Then the next thing, which is a very similar solution, is how to deal with formatting the information that comes back from your store. If you want to, in this case, it's literally decorating JSON information so that we can pass it to the calendar. And it's a very similar thing. You define a formator interface. In this case, the Drupal module has an implementation of that. And you give that to your event and you tell it, use this thing to format your data and give it back to me. So you just inject dependence injection. You just inject what you're going to need in the class to get it to do what you wanted to do. Okay, so what the BAT library allowed us to do is separate the domain logic completely. It wasn't our intent, but as a free extra. It's now, you can use it in any PHP application, right? You can write a little Silux application that uses this to do bookings and so on. It was a really good exercise in terms of saving you from yourself because you had to think about the problem of bookings purely on its own. Outside of any UI concerns, outside of any specific framework concerns and so on. And it means we get to use exactly the same code. We get to maintain the same repository for D7 and D8. We don't have to change anything. And we're talking about this with someone today and saying, another reason it makes a lot of sense is Drupal literally promises that they're going to break their APIs, right? That's, and it's a good thing, great. But this way, that doesn't mean the code that reasons about something that's very application-specific and has nothing to do with Drupal is going to break as well. You can kind of separate that and manage it on its own. Okay, so that's kind of the introduction to the bat library and how we built it and why we built it. Now Adrian is going to talk about how that looks within Drupal itself and pass it over. Yeah, so when the rubber hits the road and you're the person that has to actually write the code that does these things, then things get interesting. But it actually, it works a lot more easily than I thought it might going into this. And it's really a worthwhile thing. So anyway, so when you're bringing a library into Drupal 7, in this case bat, but this information is applicable to anything you might want to use, like Guzzle or another third party library. Then there are a couple of things you have to do. You can do them yourselves, but I'd highly advise that you use the kind of standardized tools that are out there. And the first really important one is called Composer Manager. And what that does is it intermediates between Drupal 7 and the Composer Packaging Tool to take care of dependency management for you. And what that means is it's actually going to go and look in each Drupal module that's enabled, see if it has a composer.json file, gather those dependencies. And resolve them into a single composer.json file for composer to do dependency management. So Composer Manager depends on X auto load. And what that does is it brings in auto loading for third party libraries and does namespace management. And technically you don't have to have these dependencies, but doing these things lets your library act as a good citizen in the Drupal 7 world. And be easily accessible to custom modules that other people might want to write against your code, your library. A couple of other benefits to consider that X auto load also improves performance and memory usage by consolidating the auto load stack for third party modules. And as I was saying, Composer Manager helps resolve dependency conflicts. Okay, and so what does all that look like in Drupal 8? Well, these concepts are actually baked into the cake in Drupal 8. You just saw the Composer.json file for our module in Drupal 7, which just literally says bring in the roomified bat library. This file is the same as far as bringing in the library, and then it just also describes the bat for Drupal module to Drupal. Because these are native concepts as far as Drupal 8 is concerned. And so adding your own libraries technically just a matter of modifying Drupal 8's central Composer.json file and running ComposerUpdate. However, if you don't have a specific process in place for that or you're not working with a platform as a service that does these things, then it's useful just to go ahead and use the Drupal 8 version of ComposerManager. And that'll again take care of the dirty work of gathering dependencies for many third party modules in your site and managing the central file. And so once you have things properly set up and the library's available for your Drupal site to use, then the nice part is things are really simple from there. You import your classes in the standard PHP way. Just use roomified bat unit and use them like any other code. And there's nothing more to it than that. And so how do we actually use the bat library in practice? And again, it's just like bringing in Guzzle or another PHP library and that's kind of the point is that we can use standard practices to interact with our own code. And again, like Ron was saying, kind of save ourselves from ourselves, in terms of being forced to use best practices. And we do have a Drupal aware storage controller, but it's not required to use the library. The distinction we've made to help us know, okay, we've got some code we need to write. Does that go in the Drupal module? Does that go in the library? The distinction we've made is that the metadata and the presentation layer live in Drupal. And the code that deals with how these objects that are represented in bat the library, how they behave, and what state they find themselves in at a given time, that gets put in the library. And so to pull out kind of the well-worn car analogy, if I was gonna write an application that talked about cars. Information like I have a car. It's red, that's one attribute of it. It's got a 240 horsepower engine. That's Drupal entities and fields, like we're all familiar with. And the code that answers questions like how long does it take my car to get from right here to the airport, based on information we know about the car, that lives in the car library. Maybe that would be cat for Drupal or something. Sorry. Okay, so in the real world, you've got a stick lines of code in the right places. How do we do that? So we model bat objects as Drupal entities. The bat has the concept of an event, and that's a class. And we also have a Drupal custom entity called event. And those are typed and they're fieldable. All those good things that you get for free with Drupal. We implement Drupal hooks to update the bat store at the appropriate times. And then profit, it's actually, it kind of is that simple. There's no third step. We just, we have the hooks implemented. Where you update a Drupal entity and the information that matters to the bat library gets updated in the store. And then the rest gets thrown in. So there are two layers to how we use Drupal with the bat layer, kind of in general, and one is completely direct. And that's a way to intermediate between the user and the capabilities of the bat library. And the other is more kind of a meta capability. And that's that the bat module for Drupal actually provides a way for site builders to build booking applications. So we're not opinionated with what a unit is. We're not opinionated with what an event is or a state when you're using bat, then you describe these things to Drupal. And it takes care of talking to the library and providing the library's functionality to end users. And so here's the end game. When you put it all together, we've got a graphical UI representing events. Users can manipulate this full calendar. Ron mentioned it's a really good library for representing events. But it actually does more. You can actually manipulate shorten events. If we had another unit here, say this was a hotel, then you could say, okay, this booking makes more sense to go in room 202, you just drag it. And because everything is implemented, those changes percolate all the way down to the library. And everything's always kept up to date in terms of what state things are in. And so Drupal's kind of the special sauce that we used to bring all these things together. And so what was, so we've kind of made a lot of claims. You should pull your code into a library. You should be a good citizen in the PHP world. It's gonna do all these good things for you. Okay, what was the experience actually like when it comes to getting this big supposed benefit of porting code between modules without a lot of effort? And so I would not want to suggest in any way that we're procrastinators or I wouldn't want to suggest that launching multiple SAS products at once is a hugely time consuming endeavor. Okay, maybe I would. Anyway, for science, we waited until just a few days before Drupal Khan to actually try this, just to prove how good the approach is. That's supposed to say that. Oh, I thought this was one of these soul bearing sessions. No? Well, why didn't you tell me before? Okay, maybe we did put it off a bit. Maybe we should have tried this earlier. However, the really cool thing is in a day's time, I was able to create a working start for the BAT module for Drupal 8. And that includes fieldable unit and event entities. And those are content entities, if you're familiar with the kind of the new types of entities in Drupal 8 and a configuration entity for the states events find themselves in. The relationships are there. You can relate an event to what unit it describes to the states that it's in. And the connection to the BAT library is there. And that was in a day. And side note, if you haven't tried out the Drupal console yet, then definitely go and check it out. It's a really nice way to get good clean code for making custom entities. And no offense, man, but it's easier than the model module. He wrote that for Drupal 7 at the time. That was kind of the best way to get started on a custom entity. So anyway, we have an interface to the library. We can prove the concepts work. We know that we have thousands of lines of high quality code that's working. And it's tested. And we didn't even have to move code around like, oh crap, this function changed in Drupal. We've got to move this thing here. If you've ever kind of done it like from six to seven, you know, even doing those little things like, okay, this function is now in a class here. It leads to really kind of annoying and unexpected problems. And so now I wanted to just kind of show some of the differences in working with the code between Drupal 7 and Drupal 8. And you're looking at the save method of the Drupal 7 BAT entity controller, or sorry, the event entity. And so when events are created or updated in Drupal, we simply do the work to determine which unit and state they're associated with. And we update the BAT library store. And things are kept in sync. So that's Drupal 7. And what does this look like in Drupal 8? It's very similar. The changes actually that you see actually just have to do with how you access an entity's properties and fields in Drupal 8 because everything is more properly OO than you're more isolated from the properties. And so another example, this is actually the method we're calling in the event entity controller to save data to the BAT store. And what we do, as Ron mentioned, we instantiate storage controllers for the state and event stores. And that's using the BAT library as Drupal aware storage controller. And we load BAT's calendars, pass the storage controllers to them, and save the event data. And so this is where it actually gets really interesting. I'm going to show you, there's quite a few changes to get this code to work with Drupal 8. Maybe not. So it's actually just some arcana about pulling the database prefix because we have to be able to tell the storage controller if there's a table prefix. But otherwise, there wouldn't even be that. It's literally just taking the code and using it in another version of Drupal. And we just find that really cool. And we find that, to us, this validates the concept we've been hammering on, that using an external library really does enforce separation of concerns and makes porting your application between super different frameworks, different versions of Drupal, it makes it quite easy. And so, kind of with all that in place, then let's talk about what a good architecture for a system like this actually looks like. I apologize for the slide, I did not expect that. Anyway, we found it refreshing not to have to ask the question, how do I build a good booking and availability API in Drupal? But instead, we can just ask ourselves, how do I build a really good booking and availability tool or API? And so, that means that we're able to kind of abstract the concepts we're working with on their own terms. And what do I mean by that? It means we can think about a bookable thing as a bookable thing, just that. Not a Drupal entity with a field that makes it bookable. We have some funny field module or any kind of those other mental gyrations that we're used to after years inside the Borg or the Drupal way. And so, the combination of starting from a well-defined framework and having automated code quality reviews and thinking about individual pieces of functionality at the same time that we're testing them really led us towards proper encapsulation of functionality. We have independent classes and a pretty nice, rigorous approach. And so, one kind of nice benefit to all of this is when we started thinking about performance. We really started out like, okay, we've got this problem, we've got to solve it, we've got to make a good architecture for the library. But we didn't think specifically, okay, what's gonna make this perform well? And so, doing it this way really again led to nice benefits. In the Drupal native world, if you're approaching problems from the kind of site builder, Drupal module developer perspective, it can be really attempting to do things in a certain way. For instance, you might say, oh, I already have a view of units that are in a given state, say, available units. I'll just load that view programmatically on my API callback and pass on the list of units I get back. And that might seem a little contrived, but it's been done. I've seen it done by people, other people, maybe myself. But it's really getting rid of those layers of abstraction means that your code is probably gonna perform pretty well from the start. And you don't have to deal with, okay, is this not working because Drupal actually cashed the results of this callback? Or is it not working because my code's broken? And worst case, you find out your code is broken, you fix it and you put in a test case and you make sure it's not gonna happen again at the level that you need to do that. You're not trying to kind of write a B-hat test that goes and loads a Drupal page and is it doing the wrong thing for this reason or seven other reasons? And so, all right, at this point, I've spent a lot of time talking about how great libraries are, like kind of ditch the islands, what's Drupal good for anyway, but what about our old friend? Well, it turns out that Drupal really still does have a ton to offer. It's a great way to make a powerful admin interface for your application and it's gonna really be instantly familiar and usable for experienced content managers. Won't necessarily be beautiful as Dries was mentioning this morning about the site about breast cancer, but you know what, like your user base can go ahead and use it. And so we've put our kind of many collective years of Drupal experience. Let's not think about how many collective years maybe. And we've put those to work building a great framework that lets people build sharing economy applications in Drupal without even requiring coding skills. And we're super excited about the things we think are gonna come out of it. And so finally, kind of just to wrap up, I wanted to talk about, so that's great. Good job guys, you built a booking application. What's in it for me? When should I think about actually doing this? And so here are a few things like if you see your use case meeting these that you might really want to think hard about doing this. If the solution is interesting to the community beyond Drupal, and honestly I hope it is, a lot of things should be. If you have more than a single class to include, if you're really dealing with kind of a multifaceted piece of functionality, or you want your module to be easier to upgrade, a side note, like we didn't actually even have to change the line in our DB storage controller, the Drupal aware one, to go from Drupal seven to Drupal eight. I think for nine it looks like the DB merge is deprecated, so we're gonna have to change a couple lines. So that's gonna suck, but we'll manage. And finally, if the functionality is not Drupal specific, like it's really cool to be out there, and we haven't seen for sure, plenty of people have kind of forked our library and we're kind of waiting to see the first thing get used with the library that's not a Drupal application. Just think that'd be pretty neat and have more eyes on the code and improve it that way. So in conclusion, we found a lot of benefits to this approach, we really think you ought to give it a whirl, and if nothing else, then you're going to broaden your experience and add some tools to your kit. So that's it. Thanks for coming. It's a little bit of housekeeping, just want to remind everyone about the sprints. All Friday there's things to do, it's always a great experience, I recommend it to anyone that hasn't tried it. And we'd really just ask for your help to help us improve what we're doing, please come and review our session. I don't know if anyone actually uses the robot barf, but it's there for you. So thank you very much.