 Video equipment rental costs paid for by peep code screencasts. Well, first of all, thank you all for coming to learn a little bit about our humble little framework. I hope you'll find this stuff kind of interesting. Before I get into the details of what I'm presenting on, basically the big picture is that waves is a framework that attempts to leverage the fact that that HTTP already defines a sort of a functional protocol. And so the idea is that we define resources that implement the basic methods of HTTP, and that's basically what this is about. There are a lot of other aspects of waves that I'm not going to get into today, but hopefully this will spur your interest, and you'll be motivated to learn a little bit more about some of the other features. This is also not kind of a tutorial on how to build a waves app or how to do a blog in five minutes or any of that sort of thing. It's really about what the point of waves is, and I get asked a lot about how is waves different than MIRB or Rails or any of these other frameworks for Moz, Sinatra. And this is sort of my attempt to answer. It's very difficult. I found it difficult to answer the question in a 30-second spiel, because to some extent I think waves is exploratory and we're still trying to figure out even really what it is, and as Matthew Cain will tell you, who's one of our major contributors, I keep breaking all the specs because we'll get an idea and reimplement some stuff. So it's not a framework that's sort of necessarily found itself yet, and I think that's very much in the spirit of the Ruby community. I think Evan Phoenix alluded to it last night that it's a community of constant change. So we're trying to explore some new areas with waves and sometimes we stub our toe and sometimes we find some neat things out and I'm going to just try to touch on some of the coolest stuff that we've been working on or what I think is some of the coolest stuff. Just real quickly, a little bit of background about myself so you kind of know where I'm coming from. I work with Yellowpages.com out in Los Angeles. We do a lot of very cool stuff. We're definitely hiring, so please see me or Kobe Rankwis who's doing the Confreaks stuff, videoing everything here. Many of you are familiar already with his work from other conferences. If you're interested, if you're looking for work or you're interested in what we're doing, it's a Ruby shop and we're doing a lot of fun stuff and some of it is coming out in this project. So also I've done a number of other things. I've been programming in Ruby for about three years now. I'm a longtime programmer, so I've done, I've got some other open source projects I've listed up there to kind of give you a feel for the stuff that I've worked on. So that's my background. So some quick facts about Waves, just to give you an idea of where it is in its lifespan. The initial release was last February. We got a lot of very kind of early attention, which was exciting but also a little difficult because we had to keep, as I said, we kept kind of breaking things as we were learning and figuring out what Waves was about. So that's been kind of a mixed blessing, but it did bring us some contributors and I want to emphasize that anybody is welcome to participate in what we're doing. It's not a kind of a closed thing. We're looking for people to take hold of some of these ideas and run with them or help us improve them. Some of this stuff is not stuff that we're 100% sure that we've got figured out. So please don't be shy about letting us know what you think or ideas that you have for improving what we're doing or how it might be able to benefit other projects. We have a Git repository. Oh, yeah. I was hoping to announce the 080 release today. That didn't happen. We're not quite there yet. Kobe made the joke that we were pioneering another technique called conference-driven programming. So there's a Git repo, Google groups, and a website, rubywaves.com. Hope you'll check those out and jump on the group. We also have an IRC channel. That information is also all on the website. A quick overview of all the various features. Since I'm not going to dive into all these, I thought I'd do a quick and dirty just run through so you can get an idea of some of the things that make waves interesting. One of the things that we are going to talk about is the resource-oriented nature of waves. The thing about resource-oriented is that HTTP is resource-oriented. I think the whole web community came to this realization a little bit belatedly that, wait a minute, there's a protocol there. It's got methods. It's specifically about modifying and getting resources. And yet we don't have anything really in our Model View Controller mindset that really reflects the nature of HTTP. So there's a bit of an impedance mismatch. And a lot of the frameworks are trying to say, okay, we'll just never mind about HTTP. Waves is sort of the other way and it says, hey, let's embrace the fact that HTTP is there and what it's about and maybe say, hey, you know what, maybe it had some good ideas that should actually flow into the way that web frameworks work. As you'll see, there's also a pretty heavy functional programming influence. We have a layered architecture approach which has explicit support for layers within the context of Ruby modules. A lot of the emphasis is on making the mechanisms that, in a lot of frameworks like Rails, for example, that are magical. They're still magical but they're a little less mysterious and they're more accessible directly and hopefully you'll see a couple of examples. That's one of sort of the guiding philosophies. Another one is trying to encourage reuse A good example is applications are encapsulated in modules so that you can have multiple application components in the same server container without them clobbering each other. We have a lot of emphasis on saying, Ruby sort of has what we do with HTTP saying it's already a rich protocol. We put a lot of emphasis on the fact that Ruby is a fantastic language and the first question we're always asking is, can we do this or can we express this idea naturally in Ruby rather than trying to come up with a configuration file or some other construct that would take us away from Ruby as a language? Again, I think with some of the examples you maybe will hopefully see that today. A lot of the talk yesterday, Matt's alluded to DSLs and the importance of DSLs and a lot of the approach that we take is we just say, hey, you know what, ultimately we're going to have classes and modules and methods and all the ordinary things but we may be doing some stuff to generate those or make it easier to code those using a DSL rather than making it going away from Ruby and creating some kind of runtime engine. We have a class and module loader that's a little more sophisticated than what some of the other frameworks are using. I was corrected earlier by Yahuda that actually Merb actually has a very similar mechanism and in fact they're doing some really interesting things with class loading but for the most part the class loaders and the frameworks out there are fairly basic and leave a lot of room to be desired in terms of side effects of loading and reloading classes so if you wanted to have features like hot patching and so on it's difficult to implement. Waves is experimenting with some ideas to try to make that workable. And this is not, the last point on here is not something that was really intentional but if you're interested in kind of alternative frameworks one of the things that seems like Waves is sort of evolving into is being a little bit of a meta framework. The way that Rack abstracts the notion of an HTTP request response Waves layers yet a bunch of other stuff on there for how you match or how you take a request and map it into code, how you deal with configurations and so on but it's actually kind of architecture agnostic. The layered architecture approach allows you to layer in for example an MVC architecture or a very, I'll show you an example later of just a simple application that's just sort of the one file version. So it's application architecture agnostic but yet it gives you a lot of tools for layering in your own ideas for how a good application architecture should work. So it's kind of evolving into a little bit of a meta framework and certainly at this state it's more for the, it's not for the faint of heart as far as, you know, if you were trying to use this to just do, you know, something for business purposes that you couldn't afford to have a little bit of of slack in there for having to rework some things because, you know, it's evolving rapidly and again the mechanisms, there's some magic in there but it's a little more transparent and a little bit more oriented towards the hacker wanting to go in and say, you know what, I don't quite like the way the dispatching works. So the bottom line, if I had to pick one thing and I think about this every day because I get asked this question and I don't have a very good answer and I usually mumble, well, functional programming and HTTP and inheritable configurations, I don't know. I mean, the reality is that this is one of those things that we started working on because we found it interesting. There's no big, you know, magic purpose or, you know, we're solving this problem that Rails had or something like that. It's really just something that we're enjoying working on. But if I had to pick one thing about functional programming, if you think REST is cool, if you kind of like the idea of if at all possible it's something that's just expressed in terms of Ruby's object model, not in terms of a whole other runtime structure or something, then Waves might be something that you want to check out. So into the meat of the presentation, so HTTP as I have sort of alluded to a couple of times, if you think about it, there's a call that defines a set of methods on resources for the basic CRUD operations that we see all the time in just about every application in one form or another. So, you know, it's funny because once you really look at that it looks suspiciously like something that you would want to implement in Ruby, right? So in this particular, this is not Waves, by the way, but this is sort of like, you know, this thought might be okay. I'll have a resource object that takes a request and then the different methods that can be invoked by HTTP with a request and then each of those methods would then return the response and so on, right? Now, this is a little bit of a naive example but the gist of it is, hey, you know, it's a protocol that defines methods on resources, so let's implement that. If you go a little deeper you can even think about the various components of a request as a method signature. You have a content type, the type of the data that's in the request. You have an ID, okay, I'm modifying or requesting this particular object. You have an accept thing that says, look, this method returns these values or a value of this type. You have a query string that has two word arguments, right? So, you could sort of say, okay, well, I'm going to define methods with these signatures. Again, it's not quite that simple but conceptually that's where we're going. The problem, of course, is that what you end up doing in Ruby at least is it starts looking like this and a lot of frameworks in one form or another basically boil down to something like this. They have some pieces that allow us to pull things out of the route or specify a the type of the accept response or something like this. But we end up sort of with the equivalent of sort of a big case statement and trying to do that within each method is even worse in a sense. So, we don't want to do this because it's basically kind of unmaintainable and it leads to a lot of redundant code which brings me to Functor. So, Functor is a piece of code that I actually wrote a few months ago and this gives you an idea of sort of how much waves is evolving because waves is now completely based on Functor whereas I only wrote it a few months ago and the framework is like nine, seven months old now. We've really rethought things once Functor came into the picture and what Functor does is it introduces pattern based argument or pattern based argument matching it's not a very eloquent way to put it but I can do pattern matching on the arguments to determine which block of code or which method I want to invoke. So, I'm going to dive into a really quick little segue here just to give you an idea of how Functor works. So, here's a simple example. This is the canonical functional program an example where I implement the Fibonacci sequence and I have actually I sort of define zero and one to return one and then I define the actual need of the thing to match on integer. And then if I call it, you know, I get I'm not even sure that's actually that's the wrong answer. Cut and paste mistake. So, just I'll leave that there for a second just so you can get the gist of what Functor is doing. If you've worked with Haskell or other functional programming languages, this this example is well known and it's sort of second nature but for those of you unfamiliar with it you know it could be a little tricky to grasp the the idea here. But basically what I'm doing is I'm dispatching my methods not just based on the method name but also the arguments and this can match on types, regular expressions and even lambdas. Here's an example where alright, so Waves is one of the primary offenders of Evan Phoenix's directive not to use base we do that everywhere. I was kind of cringing while he was giving that part of the talk and every time he would go to a new meme I would think, uh oh you know is this one also going to be one that we fell for? He didn't really do a whole lot, I thought he might go off on a whole functional programming rant and completely make me want to not do this presentation but fortunately. Anyway, so here we have a case where we've got the pattern matching on regular expressions so this is a little better but we're still probably not quite where we want to be. This also illustrates putting a functor in a class so this is a little different than the sort of functor new given given approach it's conceptually the same though it's just that I mix in some features into my class that allow me to treat functors as more or less ordinary methods although when you see the stack trace you probably wouldn't agree but they are actually Ruby methods it's just the stack trace sort of becomes a black hole and we're still working on that unfortunately we're still not there because the method signature isn't just the URL it's actually quite a complicated thing that we're trying to match against and if you think of it again in terms of that method signature with a response type which is the accept header content type query parameters I mean there's a lot of stuff to actually match on so we need a more sophisticated approach fortunately functor allows you to use lambdas to match against things so you know when I was first kind of toying around this was sort of the okay I've got it now I'll just define lambdas for everything and it'll work great now as you can see I mean I'm actually showing this here you know okay I'm gonna match I'm gonna define a lambda that matches on the path and also matches the request header the problem is that and then I've got the functor where I use the lambda here the problem is this is actually even messier than what we had before although it's a little more functional what I quickly realized is that if you actually want to do lambdas for all this stuff you need a DSL that will actually create them for you conveniently and so that's sort of where we moved with the whole thing so that's what waves is trying to do for you and since this is a largely male conference I figured it wouldn't hurt too much to put up a gratuitous picture of a girl in a bikini so we have the basic principle what waves is really trying to do with you is it says I'm gonna give you a DSL that's gonna allow you to define methods using these complex patterns on your resource classes I'm gonna allow you and this goes back to the idea of the modularity I'm gonna allow you to mount the resources much like we mount file systems with NFS I'm gonna allow you to mount a resource and so that I can have you know multiple resources and there's some pattern matching there so there's if you think about it the request comes in waves says okay let me look at your mounts let me figure out which request is the one I need to be or which resource is the one I'm interested in and then I'm gonna call the request method on that resource and lastly there's to actually do something once you're inside the functor method the request functor get put post delete we have the layered architecture stuff which layers in for example MVC and so on so alright I don't know how easy this is to read but this is just to give you an idea of waves and some of the flexibility can people read that okay okay alright so this is sort of the one file version of the applications not quite as simple as Sinatra but it's also we can also go and do much more complex things potentially so here's an example of the use of a layered architecture construct so I'm including a foundation which is just a set of layers that gives you sort of a basic application shell so I'm not doing much I'm gonna include the simplest possible foundation I've got my configuration waves configurations are inheritable you can see I'm inheriting from a default configuration but I could have sort of a main configuration that I use for different deployments like test production staging whatever and then inherit you know 90% of the configuration only have to actually configure you know what's left over it uses rack as you can see right here it's creating a little rack app right there and then using and again the dispatcher is pluggable so you can actually plug in your own dispatcher code if you have the the heart for it and then here's where we get into the actual resource stuff so let me highlight the two or three lines here that are relevant so first I'm mounting on this case since there's only one resource it's there's no conditions associated with it basically says mount that resource no matter what I that's the only one I've got you can use that as a default like if I had seven or eight mounts I might say you know at the end okay here's the one if everything else fails go to this resource then I'm defining a resource class hello and that implicitly references this hello because they're in the same application module called boogie board then I'm defining these this is the DSL I'm defining this is an actually define a method an actual Ruby method called get that will match on on the root pattern and then pull the the name query parameter so that's not a very complicated pattern we could probably implemented that a lot easier some other way but this gives you the the basic structure of how wave apps works kind of in a nutshell alright so since I just showed you a really simple example let me go through some more interesting examples again if you've seen Erlang has a framework that kind of has a similar flavor on the pattern matching but there's a few twists here that I'm not even sure are in the Erlang version but basically we have the path is an array strings are literal things to match symbols are parameters we're going to extract so syntactically it actually looks a little bit like a rails route but it's just broken into these array elements and part of the reason for it is I can do things like create you know more complex things to match against if I want so just taking us quickly through these the first one's just going to match the literal path admin nothing else the second one will extract whatever it is that the first path component is into the name parameter and then and then the second parameter will have to match the literal edit the next pattern says if there is a parameter extracted into name otherwise defaulted to the value of home that's a default value in that case this one basically says okay blog and then the name of the blog extract that in the query param but only accept an error in RSS accept header so only match if the accept header specifies RSS continuing on true works as a wild card so if I have true in the middle of my path components at that point that will match anything I can say I can if I actually will match the whole rest of the path not anything path will match anything and extracted into the path parameter here we have one that matches on query strings where basically I'm saying I want a path called location but it should also have Latin long parameters otherwise don't match there's a lot more that I'm not going into but this gives you an idea I hope of how the DSL works so this will go in and it will create a whole set of constraint lambdas that are passed into the functor method to get put post delete on the resource is everybody still with me yes yeah it's funny that you mentioned that I don't have it on the roadmap slide but one of the things that I'm kind of looking forward to do there's some real interesting similarities between Rinda as a protocol and HTTP and how you might be able to map those any other questions before I so let me just this is from a real and again if hopefully that's readable it's a little bit maybe a little smaller fun even than before but I'm not going to go through all of this but if you kind of just look at this you can kind of see you can get a feel for some examples of you know I'm defining a post method matches on name the way we get named routes where I can actually call and generate the path later is with this syntax so this is a post but I'm naming it updates so that I can then later call paths update on that resource and generate that path to link to it some other highlights you can see we've layered in the MVC layer here so we get some helper methods that give us the controller that corresponds to that resource name also the view so I won't go into a lot of detail on how the MVC layer works but you can see that there's some helper methods in there and one other thing that's probably a little confusing is these widths there's been some debate as to whether or not that's really the right idea but if you think of mounts as being able to have labels sort of a scope parameter that I can define around okay I mounted with these these criteria so over here in the resource I only want to match on the mounts that were that were matched with those criteria so that sort of encapsulates the notion of you know this is what I already know is true about this request so I can have in the mount for example accepts RSS and now if I have a width statement around my ons here then I know that I'm in an RSS feed so I might have one called feed for example this one is oriented around the perspective so in this case if the mount matched the admin path however that's defined in the mounts then I know I'm in author mode I've got somebody coming in through my administrative interface another thing you see is sort of the equivalent of filters they're just methods you have a bunch of these besides put get put post and delete you have before and after which will be run by the dispatcher before and after the request is the main method is run there's always which is going to get run even if there's an exception handler so you can define handlers again that matches on the exception type using functor so you can say okay you know I want to handle these types of exceptions and so on so there's quite a bit here that I'm just kind of touching on but hopefully that gives everybody a kind of a flavor in the real world how this starts to look everybody everybody still with me the cool thing though is at the end of the day and this is sort of my proof that okay the DSL isn't doing anything too dramatic it's really just defining methods on Ruby and you can see that by actually just calling here I'm just doing a union of the instance methods with the main HTTP protocol methods and you can see those methods are in fact in defined on that resource so the real Ruby methods and it's a real class it's just an ordinary class with methods on it the methods just happen to implement some really crazy pattern matching so that's so if you're with me so far you're kind of thinking okay you know that's an interesting model but what is the benefit of doing it that way why is that better maybe than doing things the way say normal route oriented frameworks are doing it some of the benefits I've kind of outlined here one is since they're normal classes I can actually inherit routes the method functors are inheritable so you can actually override a base classes implementation for example of a particular functor or or just pick up you know a bunch of functionality from a base class so if I want to have if I know I have a lot of kind of common features shared by a bunch of resources I want to create some sort of default code a good example was in the thing this morning when with the make restful helper right the DSL for say okay I'm going to generate a bunch of methods for rest a restful controller this is kind of a similar thing in that you know at the end of the day I might have a base class that has all that implemented and then I can just override specific things in my derived classes I can use relative paths because the mounts can actually say okay here's the path prefix that makes it a lot easier for me to reuse resources and other applications where I might have a slightly different convention so I could for example take the blog apps resources entry and comment and so on and mount them on any URL that starts with blog and that could coexist with my wiki application where I mount all the all the resources using the prefix wiki and the last thing which can be a drawback if you're a manage if depending on how you think about it you know is the modularity that you get with this if you have a a lot of it's not a big deal if you only have a small number of routes but if you start to get into more complex applications and then you've got 30 and 40 routes going I mean it starts to become kind of a headache to manage all that there's ways to me you can certainly break them up yourself but it's this is sort of supported almost enforced I would say by the framework to some extent to say you know what divide up your the way that you do the request handling the same way you do anything else you know break it into chunks separation of concerns and so on I can let's see the mount points reuse I've talked about performance is an interesting question functor is at this point and probably will never be super speedy but the because it's doing all this pattern matching although you have to do some kind of pattern matching to process a request anyway but one of the things that happens that speeds this up a little bit is because I'm using mounts and I've got the resources broken up into these chunks I'm actually only looking at how you know I go through all my you know or up until I find one I go through my mount conditions the patterns that I can match on for that and once I find one then I only have to look at the patterns that that resource is trying to match on so I don't have to end up going through if I have 25 routes I don't have to go through the whole routes file and and you know in the worst case I only need to go through you know worst case 10 of them to find a match if I'm if given this model where I have five resources with five different methods that are implemented here's just an example to make the mount point concept a little bit more concrete again this is from the CMS app that we're building in pages that's sort of the you know the app that Waze was extracted from originally if you will so it's become a nice little test bed but I'm mounting a bunch of different resources these I'm mounting just based on the accept header or the accept header so if I you know I'm saying look I want all images I don't want to go over you know about anything else if it's an image if the browser is asking for an image send it over to my image resource class similarly with you know CSS and Javascript if it's an RSS feed send it to the blog class now this one's a little interesting because this is a wild card and what it's doing is it's saying pull that out from the path so I'm saying okay the resource is going to be embedded in the path so pull that out and use that to determine the resource class I want to use and this is a good example of how we set up a label for a mount so now I have scope in my resource so I can say well I don't want just you know anything any mount point I want specifically only the case where I'm matching the admin path how are we doing on time does anybody have the time 10 minutes okay so I've talked a little bit about foundations and layers real quickly just a conceptual idea of what waves is trying to accomplish here so we've talked a lot about this piece the resource allows you to essentially encapsulate you know say okay I want for this HTTP request I want to do this thing but that thing is going to depend on your application architecture waves is agnostic about the architecture and it does this through a layered approach so you know I have a foundation which is enough to basically some set of layers that guarantees you hey this will run as a waves app it's not going to suddenly you know oh I don't know how to you know I don't know how to find this file I don't know how to load a class or something and then you can add additional pieces on to that so just a quick example of the default foundation to give you an idea of how this works and this is definitely an area where it's still evolving and I'd love to have people working on kind of jumping in and working on and saying okay you know we're going to build out a you know we're going to build out a you know a layer to do service-oriented architecture that focused around rich internet apps this is kind of one of the core driving things is this belief that hey some of these things are a little different you know they're not all sort of MVC they don't fit that pattern and we end up sort of retrofitting stuff into MVC where we you know like if you have MVC implemented in the browser there's now a javascript MVC it's actually several of these that do javascript MVC like stuff and then I've got MVC on the server you know I'm it's kind of redundant so how do I get around that well maybe I need a different approach and again it would be great if we had people kind of helping us out and building out some of these additional layers in this case you can see you know we're we're adding the inflection we're adding sort of a really basic simple layer than adding MVC on top of it and then some error handling but that's you know just the tip of the iceberg of what you could do so there's a lot of places in the Waves code with that comment right now so there's still ways to go and a quick and not in any particular order although I did sort of try to prioritize this you know the documentation is a little behind where this presentation is at so if you we used to have a really nice tutorial and you know some some nice the R docs were reasonably solid and so on but they're all a little out of date at this point so that's something where you want to jump if you want to get involved now you probably need to get on IRC with us or on the Google groups in another couple of weeks I think the documentation will be caught back up again it's the conference driven development syndrome some of the other things I won't go through this whole list but basically you know we're trying to kind of round out a lot of the things there's a few places where the features are missing or the different sample amps aren't really demonstrating properly how this resource oriented approach goes there's some cool gems that we want to be able to leverage and integrate Matthew's implemented a really cool thing is it called is the official name now Cassandra oh okay Cassuistry so Cassandra was a little easier I'm excited it was a female male yeah it's got to be one of the most whimsical IRC channels you should jump on just because John what's his name John Holtwanger he's a very witty guy and is constantly you know punny I mean he's just there I think sometimes just to provide some levity while we're sitting there and he just comes on with some goofy joke did you tell him what Cassandra is? no I didn't I got distracted so it's a sort of markaby but for CSS there's a couple of these out here but Matthew's is I think taking it to the next level we'd like to integrate that into the way that views work erector has a nice one of the things that was very big in waves early on is the views are actually classes you can inherit views but we didn't really do anything with it because we just dumped you out into markaby templates or whatever templates you wanted but erector has a nice implementation that's sort of like markaby but is class based and we're probably going to make that sort of the default mode to leverage the fact that in waves views are just classes and just like again it's just ruby we're just trying to use classes objects methods just like you would in anything again I can't emphasize enough that we'd love to have more people involved I think it's a good time I think we're starting to get our feet as to you know what the I'm really determined to stop breaking all of the specs so it would be awesome to have people again working on different aspects of this we'd love to have you involved or at least have even your ideas and feedback if this approach is interesting or intriguing so any questions before there isn't anything in waves per se no I mean so there's not like a resource repository you'd have to sort of know you know looking at the the different apps that were loaded you can get a list of apps basically from waves you can say give me all of the application modules that are loaded and then from there you could say okay presuming they all follow the same naming convention of having resources as the sub module containing all the resources you could do it that way but there's no there's no like formal or first class mechanism for that yes I just love Ruby I'm trying I don't know I mean maybe I'm a little bit guilty of trying to turn Ruby into Erlang there's a lot of stuff about Erlang that I just find kind of ugly I love the syntax and simplicity of Ruby and so I'm you know we're trying to kind of cherry pick a few good ideas and then and then make see if we can make them workable in Ruby rather than saying you know what let's scrap all the great things about Ruby and do it in something like Erlang any other questions have you shared resources from one application to another and how are you going to plan on battling the resource itself and then secondly you know a resource is more than just a controller code or model right there is especially for web applications there is a study concerning things like that so how are you going to plan on sharing such a thing you should become a contributor that's the answer I have well you can put or you can put anything you want in a layer and slide it into the stack that's what I'm going to do yes I mean for instance the no go ahead the ORM that you use is dependent on the layer in your application you declare I want to include waves, layers, ORM SQL or waves, layers ORM it's a module that includes itself in your application and if there is basically some little trickery it does and it adds, it's like a plug-in but we think of it more as like just a stack and then a stack it's a normal module except that overrides included and goes in and fiddles with your app basically that's what it does that's why I was making a distinction because the layers are really intended to layer functionality into the overall framework although you could use them that way and probably what we will have is a mechanism like layers for doing what you're talking about where I can bundle in a bunch of pieces you know but what we're trying to do is do it just to say a gem as opposed to having a gem with maybe a module that overrides included or something that's very ruby-esque and so I'm not I can't say that we've thought out things like how you would bring the assets with you that's kind of an open problem at this point I think it's a very right now we're at this stage of trying to make that possible or realistic to even think about bringing in an entire application and having it coexist with another application without all these collisions on what's the route supposed to be what about the name spacing and all this kind of stuff but we're not at this stage of okay we've solved that problem so now let's move on to making it nice and neat to package an entire app anything else I think we're probably close to time well thank you very much I appreciate your attention