 All right, so my name is Pratik and I run supportb.com. Avinash is also around here if you want to check out what we do. And before this, I used to run a service called Musubu, which I still sort of run. And a couple of other things like Hacker Street, I kind of host it. And so anyway, today we'll talk about Backbone.js. And I think, oh really? Wow. So today I will talk about Backbone.js. Also, so I think the talk is not exactly about Backbone.js, but it's about actually, you know, kind of learning to love JavaScript. And so most of us look at JavaScript as this language which we just sort of pick up on the way, you know. How many of you guys are familiar with Douglas Crockford, the good parts, right? So if you attend his talks, that's what he says, right? We just pick up JavaScript and we never really learned it. So it's about actually learning to see, like, that you can build, like, really cool applications in JavaScript. You can structure your code and you can give it as much love as you give, you know, Python or Ruby or PHP. So let's get started. And, I mean, typically most people just, like, love jQuery and stick with jQuery, right? And I also really love jQuery. And I have done a prototype app before, prototype JS. And so coming from that background, I really love jQuery. But still, I think jQuery is, like, good for simple stuff. You know, you want to animate something. You want to change a little DOM or something like that. But if you want to build a full-page app, right, you know, it's not really that good. So it's good for a simple website. But if you want to build a single-page application, it's not so great. And what do I mean by a single-page web app? Just to be on the same page. You know, something like Gmail or the mobile me or the new Twitter. If you've seen the new Twitter web interface, that's a single-page app, right? There's no page refreshers. And, you know, it behaves almost like a desktop app. So that's what you're talking about here. And so Jeremy is the guy who created Backbone. And so as he says, unless you're a really fastidious coder, some sort of library to help structure large-scale JavaScript applications is important. It's far too easy to degenerate into nested files of jQuery callbacks, all tied to the concrete DOM. And so I think this is the biggest problem if you're using jQuery to build big applications. You'll be writing so much event, you know, so many callbacks, so many events, and, you know, they'll all be tied to your DOM. If you change a class name, it will all just sort of break down. And so that's where I think something like Backbone comes in. There are a lot of other alternatives like Sproutcore, which there's a talk on. But I'll not really be comparing any of this. We'll just dive into Backbone and keep it short so you can ask questions. So just a few properties of complex web, you know, single-page apps, which makes it necessary that we have a framework, right? One is all of the logic, client logic is typically on the client side. So how many of you guys have used, you've all used Gmail and like Pivotal Tracker. They have almost all of their, you know, a big chunk of their logic on the client side. And then, you know, they just keep it in sync with the server. And so they have all of their logic in JavaScript. They have, they have a lot of updates to the UI when the data changes. So, you know, every time a new mail comes in, the listings change, the counters are changing. If a new reply comes in, it says you have a new reply. So the whole bunch of stuff is happening on the screen at any time. And typically the templating is happening on the client side. So if you've done a little bit of Ajax, I mean, how many of you've done it in Rails, for instance Ruby on Rails, right? Or so what you do is you make a call and, you know, you send free rendered HTML back and you just insert it in the right div and it just gets rendered there. Typically in a single page app, you don't do that. You send the data back and then you do templating on the client side. So there was a talk in the morning on Mustache. So something like that. You keep your templating here because it just keeps it all clean. And yeah, lessed it on the wire, exactly. And so to not go crazy building it, because it's pretty easy to go crazy building it, you need like an MVC-like pattern to keep the code clean. You need a templating language like Hamel or ERB or Mustache or Handlebars to render view elements. You need a really good way to manage events and callbacks. And you want to preserve the back button because, you know, the expectation is set. People don't care whether it's a single page app or not. If they press back, it should go back to the previous state. And that's a big deal. And you need easy testing. I mean, I'm assuming everybody here test drives their code, right? It's 2011. Test drive your code. So fortunately there's help. There's backbone.js. It's just 4KB packed in GZEPT. The only dependency is underscore.js. How many of you have played with underscore in the past? Okay. So it gives you all these, you know, maps, select, all these typical functional programming sort of things. And it makes it really easy. So it's like the missing link in JavaScript. And you need jQuery or Zepto to do Ajax or to do DOM manipulation. And so this is one great thing about backbone that it's giving you all this stuff to structure your code. But you can still use jQuery to do your DOM manipulation. You can use all of your familiar jQuery plugins for rendering or for doing table sorting. So you don't have to, versus if you go to Sprout code where you have to use everything that's provided by the framework. So you can just use backbone to structure your code and then you can just stay in your familiar territory of jQuery or, you know, Zepto or whatever. And that's a very good, very well annotated source code. And that tool is also written by this guy. So it's very easy to, it's just 700 lines of code, 750 lines of code. So you can pretty much go through the entire source code and there's no magic happening there. So what does it give us? It gives us MVC, which is Model Views and Collections. It's not Model Views and Controllers. It's Model Views and Collections. So we'll look at, we'll just go through a little bit of code to build something like this. So this is something like gmails. In our case this is like ticket listing. So, you know, you have a, so that, so this is on a whole ticket listing element. Then it has individual ticket rows or emails. I mean, if you prefer that. So basically what we'll be building is like rendering using, using backcode, building something with render this. And then when you click on it, it opens up a particular email. So we'll see how to do this using backcode. If you want to do this using jQuery, I don't know. I can't remember how to do this using jQuery. So anyway, leave that. So you can build models, model, data is represented as model. So if you have an email, the email object as such which has that, you know, subject and the content, that's a model. So data is represented as models. Models can be, you can create models, validate them, destroy them and possess them on the server. So, you know, you can fetch a model, you can make some changes to it, and then when you save it, it makes a call to the server and saves it back. So it, it, it maps really well to, you know, your server's restful paradigm. And the great thing about models is that if you change an attribute, let's say if you change a subject, so you can bind to a change event. And then in the right place in the UI, you can say, oh, every time this model subject changes, change the subject here. So, so this way you don't have to manually keep track of things. You just keep binding to events. So you, so there are a lot of events and for every attribute is an event, model as a whole, there's a change event. So there are a lot of events that backbone gives you that you can bind to. And that's the right way of doing things in backbone. So this is how you make, so I'm assuming everybody's familiar with this namespacing in JavaScript, right? I mean, are you, are you different? So you just don't make like global or like you make like, just as we support the namespace, dot model, dot ticket summary. So you extend from a backbone model and you can do your unit code here and that's pretty much it. So every time you get a JSON object back, backbone will take that and, you know, all the attributes that will, all the fees it will take and create attributes automatically. So all of that work is done for you. You don't have to worry about all that. So, so this is like the ticket summary model which will be used to render that row. And, and then we have collections. So collections are basically a collection of models. So you have one model and then you have n models. So you, so you have a ticket summary model and then you can have a ticket summary collection which has a lot of models. And so collections again have their own event. So every time you add a model to a collection, it has an add event. Every time you remove it, you have a remove event. So let's say, you know, a ticket is deleted. So you can bind to the remove event and take it out of your DOM. So, you know, the recurring theme in backbone is like to use events for everything. To not like stores, you know, pointers to rows or pointers to the views, but to use events and like keep things that way. Because the great thing about that is you don't have to worry about who else is using that event. So, you know, three or four views could be getting updated based on the change to a particular attribute, but you don't have to worry about it. You just write self-contained code. Yeah? Yeah. Yeah. No, so actually you'll see, which obviously what happens is, I mean, so we'll just wait. We'll come to it. It's not as simple as that, but we'll come back to it. So, so if collections, collection of models, triggers events. And so what you can do is you can, how many of you are familiar with the restful paradigm, right? Where you have like slash tickets and then you have slash tickets, slash ID. So, you can give your collection a URL saying slash tickets and it fetches a bunch of tickets and then it understands that this is a collection of these models. So, it will initialize individual models for you. At the same time, it will keep calling those add callbacks. So, you can do something about it. So, you can fetch from a collection and then you're saving, if let's say an individual model back, it will derive its own URL from the collection. So, it knows collection is slash tickets. So, my ID must be slash ticket slash ID. So, it all maps really cleanly with, you know, restful sort of URL structure. And really well, I'll show that actually. So, and one other thing is that you can define a comparator in your collection. So, what happens, every time you add a new model, it will invoke that comparator and insert it in the right order. So, you can be sure that your, if you worry about order of models, you can be sure that it stays in that particular order. So, they have this one neat thing. And so, this is how collections look like. This is a ticket this connection. It's a connection of the model that we just defined. We get some new model. This is the URL you should fetch from. So, this is a neat ticket. This can be used for passing, like, if you send your JSON with a top level namespace thing, you know, you can decide if you want. So, you can use something like this for that. And again, this has an initialized. So, you can do some stuff here, whatever you want to do. So, you can, I don't know what you might want to do here. Yeah, so, I'll show that actually. So, let's come back, let's come to the views. So, unlike, like, let's say you're familiar, you know, if you're comfortable with Rails or, you know, Python or typically the views there are very dumb things which just pretty much like render stuff in. Here, actually, views are more like controllers. Views are the ones responsible for initializing things and hooking them up to each other. So, views are actually like pretty intelligent in backbone. So, they are more like Rails controllers and they are responsible for instantiating collections, binding events, doing the fetches, as you asked, all of that stuff. So, if you see this view is pretty complicated. So, what you do is initialize the view. Now, see, what we wanted to do is see, this is like a typical UL-LI thing, right? View, have a talk. So, you can just say this, this ticket lists view, the entire view is a UL. So, if you initialize it with a div, sorry, with a tag UL. So, you say it's a UL and then here you initialize the collection. So, you say, okay, let's start taking lists, this is collection. Now, buying knowledge, if you are in the stock, the first stock of objects, this basically makes you every time add or add on the stock, the list is already bound to this object here. So, this is an understood thing, you don't have to, don't worry too much about it right now. The interesting thing is you can say that on the ticket list, add, you can find add-on and on a refreshment, find add-on. So, what, when you fetch from the server a collection of tickets, the refresh event is going to be called, which will basically, which will call add-on of these. And when you see add-on of what it does, it passes that particular model and initiates another view. So, those will be the actual rows. So, this is the big view, this is the one which contains all of these and then each of them will be individually initialized over here. So, every time this is done, it will initialize a view, take this and append with that dot. And now what interesting thing over here is, you see, we are not worrying about the actual class name or the actual ID of the thing. So, when you do add-on of this dot tl, we have already the selected already spoke to this ul tag. So, everything is happening inside that ul now. So, you don't have to worry about where it is placed in the page, what is its ID, it doesn't really matter anymore. So, this way you can just worry about the particular component you are working on and you don't have to worry about the page as a whole. So, right away all your worries like drop by like a factor of 10 or something. So, you initialize a ticket summary view, pass it a model and then once you are done with that, you basically start appending it. And as we'll see in this one. So, ticket summary, I think that is not here. So, this will have a copy of that. So, this will be the allies. So, this will be the each individual allies which will be created and appended to the ul. And so, again the same kind of thing what you do over here is actually, so one thing that you can use is you can pass it events. So, you can say on click do this. And again as you see you are not particularly, you are not really thinking in terms of the DOM. I know you are just saying this view as a whole has this click event and on click event open ticket. And on open ticket what you do is we change the href. You know we change the location and that should somehow get handled. So, you are just worrying about like little pieces of function. You are never worrying about app as a whole or the page as a whole. You are decoupling from the DOM and even when you are like conventionally when you know you would like render ul and then you would run a for loop and then li. You are not doing that anymore. So, the benefit of that is let's say now you have a new ticket. You add it to the collection. Immediately the ad will be fired which will file the ad one, which will insert it into the DOM. So, like you know it just stays like really clean. Can you take it later? This finishes flow. It was very hard for it to stay in your head for too long. So, one thing which we are doing over here is in the render here we are actually calling a template and you are passing it on. So, this is like client side template that I was talking about. So, if you see and you should not have that because your html can change but this structure as such is going to stay the same. So, for that you use client side yeah. So, it just defined in handlebars. So, we use a templating language for handlebars which is a super set of moustache. So, this is your template. So, here it is here because the code went out of the scene. So, what you can do here is like a very logical system. If you can't do too much logic you can't earn loops here. Like you can do simple text. So, this is like a text. If it's 100 and bold it, if it's not 100 and bold the subject. This is a helpers. You can define and you can define some helpers. You can say from the requester object extract a name or email. So, if you want to do anything complicated you define helpers. But overall your template stays very very simple. So, what it is how you do is it would just pass it a right object a ticket object with a top level an empty gate. And it will render this. This will come back and be rendered as a ticket row. Yeah, it's your just personal preference. I mean. So, this has you know you can go one level up in the namespace in JSON and so you can do a bunch of fancy things with handlebars. So, it just makes it a lot easier. So, yeah this is the URL thing which you know we were talking about. So, collections have a URL. The models derive the URL from the collection or you can define individually if you want. And they map really well. So, create maps to post slash read get update export delete is delete. So, it maps like really well with the restful thing. And finally, backbone gives you some. You have to write a logic for that. So, you have to write some custom logic for that. And so, actually I can kind of tell you in this. So, finally you have the router. I mean, this is the one which makes sure that you are responding to particular URL. So, like in the ticket summary we saw when we click it just changes the URL. But then what happens? So, the router is one which makes that magic happen. So, when the URLs change, this is the one which catches the URL and calls the right functionality. So, they are used for setting up routes the great thing is you can add routes during runtime. So, you know as and this So, you may not immediately see the benefit of that but it's like really useful if you have I don't know if you start building a real app and so you can add routes during runtime. And so, this is how it looks like. So, what is this? Right when my app is served if it's like let's say the app is app.com, right? app.com where there's nothing after that that's the dashboard route. So, the app you are able to match this now. The dashboard route in our case what we're going to do is it would create that ticket list view, that big listing, a new instance of that. And it will actually update it. So, this is how you update it to a particular page of that now until now you don't actually care about where it's not even in the page actually as such. So, this is where you update it to the DOM and show it. And when you match ID, you know something like this or hash ID, then you match the open ticket now and how do you do that? So, automatically, all that, if you say it's not good, does it automatically follow that route or not? I'll just show that actually. So, this is where the sort of magic happens. So, that's why it's very easy to support you know people can copy a URL and send and it's not dependent on the state at all because the right URL will be matched and then you can say this is a default URL. So, match this one or whatever you want. So, it's very easy to prevel because of back button now also like have people be able to copy and recreate a state of that in a new browser. And- What does it mean to go on long route? This is the entry point. Yeah, so that is the entry point. Yes. So, yeah, so what you do is, you basically, you just say, you initialize that and then you say you start the history. And this is where you can copy to push state but you'll have to change the URL to slash. But if push state is not supported back button will change them back to hash. Or if people- So, what if they say a slash or a hash or nothing? No, so if you want estimate it should be slash actually. Don't want to use a hash for this. But back button will change it if it's not supported. Why not just ask us who the, I don't have, we don't have a slash and this back button will take care of it. Yeah, that's true, I don't know. And one thing is back button is itself like a moving time. So they do keep changing stuff. So, you know, for all that may change. And so you basically to run your app, you initialize a new router instead. Yeah. Yeah. And what if I happen to, so if you said that the history state is preserved, does that mean that on the server I have to want to access that anything? Yeah, yeah, yeah, yeah. So you have to, it's not so much true for the hash URL because the hash URLs are ultimately loading the same page. But if it's a slash URL, yeah, your server should understand that you have to configure a server like that. Yeah. So it needs a server-side support. And so we initialize a router instance since that is the default one. It matches the dashboard route which creates a new instance of ticket list view which creates a ticket list collection and fetches it. The fetch calls refresh. The refresh is already bound. So the refresh handler renders ticket summary for each of the tickets fetched and starts appending them through the DOM. So basically this is the process. Now once it is rendered, each of these tickets summary as we saw at our on-click handler. So you click on it. It changes the URL to hash ticket ID which matches the second route that we have defined. Which is responsible for instantiating an individual ticket view. We did not see the code for that but you can write the code for that. So basically the paradigm is you initialize your app, match the default route or something and then after that, at least that's the way I do it. I just keep changing URLs and keep matching those URLs to some handlers. So you can always on-click just change the page but that way you will not get the benefits of the back button or browser history or anything. So you should avoid that. But if you opt into HTML5, then it can be slashed too. No, this was, I did that, I mean, but you can define slash actually. No, but, no, no, HTML5, it won't reload. It's a push state. So it won't, it will just, so that's like if you have seen that Github's code browser, right? It's actually, the URL is seen but the page doesn't reload. So you can go and check it out. When you click browse your repositories there, the URLs will keep changing but the page won't be reloading. So, so one thing is that so far we have looked at models as things which are bound, which have something on the server. So if you have a ticket model, you'll have a ticket API but backbone models are not just for API, you know, for API back models. So what, like in our application, what we have done is, I can, so, so this is something like how our app looks like. And so what you've done is actually even these things are rendered using code. So you can define a JSON that says give me a my ticket screen which renders these screens and renders these buttons. So in a way, that's also data, that's some data, right? But there is no corresponding API in the backend. But you can, the great thing that happens is what you can do is you can use your views and you can use a collection and say, oh, every time a new screen is added, insert an element over here and find these events. So this is where your time without income helps. So you can say, okay, this is where you are for this. So you should use this code organization even for other things in your application, not just for things that you're fetching from the server. So, let's see, what do you want to do and fix, like in something that's lost in this case? Yeah. So the way we have done it is, let's see if the code is here. Yeah, so if you can see what we do, as I said, everything in ours is triggered by rows. So what we need to do is, we change the URL to slash, slash, slash, query. And then we handle this around in the open source system. And so that's why we can add validation to it. So we use this slash, slash, query, and page, column, page. And you open the same source, you see? But in the handle, you pass a page parameter. So when you are making an API call, you pass that page there. So, as I said, we just handle everything using URLs actually. But how will the collection change there? No, so you, the collection will define a new, you will instantiate a new screen, a new view. And then you will replace your current view with that view. What we do is we keep a stack of views. So when you press the back button, the older one is just like popped out and made the current one. So yeah, so these are some of the patterns that you can use. So what we have is, we have something called, so, so what, so we just say, okay, current view, set this particular view as a current view. So then that case set and set, et cetera, current view, and for all the older views, we will hide it and also for something like, you are not a current view. So then you can either recycle them and remove them from your account, or you can reduce the polling frequency or do whatever you want. So we have to sort of tell us this framework for ourselves. So, ultimately you would have to do something like this if you are writing a very complicated app. And so, Backbone has a module called Backbone Sync. You can overwrite it to, so people have written local history thing, adapters, and so you can do all of that. So just wanted to test, touch one testing. So we, we at least like, so this is like really, really, really complicated code. So, you know, there are refreshes happening, they're like whole, if you're writing it without test cases, you are just insane. I mean, you're really insane because you can never iterate on it, ever. Because whether it's polling every five second or not or whether it's removing or not, you will just go crazy manually testing. So you should write test-reven code. So we use Jasmine for it, which is a very popular choice right now. And so we can write something like this. So, so we can say, okay, create a new ticket summary. Now, expect the top level element to have a ticket, have a new request here. Or if you click it, so you know, this is a view.vl.click, you should expect the windows location to change. So you can write, you know, your Jasmine code like this, and it makes it a lot more manageable. And you don't want to make network calls. So you can use Synon, there's something called Synon.js for mocking and stubbing. So you can do something like this. You can say, okay, create, give me a fake server. At this one, it should be in this fact. So it has a create and do list and I do fetch. It will actually give me this thing back. So you don't really top your backend. And so it keeps the test very fast and very manageable. And you can use test unit or whatever, but I mean, if you're familiar with RSpec, Jasmine has a very behavior-driven development sort of flavor to it. So you know, expectations and, you know, nice error messages and all of that stuff. And yep, so this is what we do. And if you find all this exciting, you should come and work for us. So we work on cutting it stuff. Like we said, we give you a MacBook Pro, we have Xboxes, you'll be programmer number three. So we're not just number two, I'm number one. We're number three. We are already sort of public beta. Another thing is if you're a company, you should definitely check us out for your customer support. We have a couple of customers including some really big ones which unfortunately we cannot disclose until we have officially signed them up. And yep, so, so much for that. And yep, questions. I think we, okay. You mentioned Jasmine. Right. So how do you automate this? What do you have to do with this? No, so Jasmine gives you a command line rate task which you can put as a part of your continuous integration build or something. And that's what it does probably. So I've just run Firefox in the virtual frame buffer. In the radius, phantom. Phantom, yeah. Yeah, we want to, but yeah, so that's the thing, right? You know, when you are two people, you can only do so much. So, but yeah, phantom is, I think, definitely an emerging choice. It's a headless browser, so. This is Jasmine. Where's the gate? There is something of Jasmine headless. Oh really? Something very simple. But anyway, we run our Cucumber specs and so in our continuous integration, we run our spec Cucumber which needs a Firefox thing. You can probably do phantom, but it is proven to work on Firefox, so we just, and then we do Jasmine. So we have just, so we just, in the virtual frame buffer, you can run our Firefox. So it will invoke it in memory and it will just keep, you can connect to it using VNC if you want and debug. Yeah, it's pretty straightforward. So yeah, that's actually a pretty cool question to ask. So what do we have done? We have written a pretty fancy thing on top of it. So, what do we have done and we have? So actually, so we have written a little wrap up. So what it does is, because there's only like a deep and sink route. So what it does is, like every time now you initialize a model, it will actually, it's like an identity map thing. So you know, it will actually take, if already a model exists with that ID, it will take that object, but it will sort of re-initialize it with new attributes that you pass or if you do a fetch, it will fetch. So what happens is, even if you have, so like there's a ticket summary with a ticket item for a particular ticket, then there's a full ticket view. And as I said, you keep the views so that you know, when you go back and forth, it's really fast. But if you initialize different models, which is the backbone's default behavior, then if you change something here, it won't be reflected there unless you do the next refresh. But if you do something like that, it's basically all bound to the same object. And so you change one attribute here and if you're bound to the call, everything changes for, or everything bound to that object. So is there a lot of talking on the model? No, so when you do the same, it will be preserved there. And you have to express it? Yeah, you have to express it. And it's always difficult. Yeah, it's a crud app. So I'll try it. So one thing, when you're kind of doing something like back one or single page app is that you have fully functioning API right when you know you have a version one of the product. Yeah, in our case, the admin side of things we still do using Rails, Rails views, but everything else is just, yeah, it's a JSON API. This would be like, it's equal to the plate, right? Yeah, yeah. Though we recommend using Postgres. Yeah, so this is the thing which we have written. So it's like a little cache store which keeps a copy of each layer, reference to each layer, models, and then when you are creating a new model, it basically checks if it already exists and all that. So it works pretty well. You also use, it's like, the app can actually run through the cache. No, not yet, not yet. I mean, we can do all of that. It's already pretty snappy actually. Unfortunately, there's no internet, so it's not fetching the right font. But if you see the URLs change and the back button is like pretty snappy, you know, you can go to a new listing and this is coming locally, so it's kind of slow. That's a good question. I don't know. I personally don't really care that much about it because I mean, it's like, if you're using Gmail, people are already used to downloading a big file. So as of now, I don't really care about it. Maybe when we go like really mainstream and you know, we have to optimize. So, yeah, first time now. Because everything gets, even your handlebars, everything gets compiled into one big ass file and it gets downloaded. After that, it's only JSON transferred. So after that, every time you do... Oh, really? Okay, I don't know. So here, anyway, it's a development, so everything is not concatenated, but you can concatenate and send. And then after that, it's just, you know, XHR requests. Right now, it's all server. But as I said, you can override that Backbone sync module and so every time you do save, you can save a local copy and then save. So it's pretty easy to override all of that stuff. No, actually, we want to open-source this app because if you think about it, it's like the de facto reference for our own API. So, I mean, I actually wrote a blog post about it. So my philosophy is that the core of your product is actually the API and, you know, all the user experience. And if you want people to adopt your API and if you put this code out, it's actually like a very good rep because it always stays in sync. So people can just look at it and see how the API functions. So there's actually no reason to try to protect it. The underscore comes with a templating language. Oh, no, no, no. That's what I said. So you can use your regular jQuery plugins for all of that. There is no, so this dollar is a jQuery dollar. So you can do whatever you want. So when you say dollar of certain element, it gives you a jQuery, whatever, the DOM object or something like that. And you can do whatever you want with it. So you can use any plugin. Yeah, you can use, handlebars is just our choice. I mean, you can use whichever templating language you want. And one thing which we use is we use something called jammit, at least for Ruby projects, it's like really, so that will compile your templates and make it available in a global namespace. And so it makes it very easy to use. But yeah, you are free to use any templating language you want. Yeah, so a spine came out after backbone. So some of the things which are missing in, which spine did better than backbone were like this identity map, but we had already written our own. So I think give both a good shot and see which one works for you. No, we have a poll right now. We want to, I mean, if you were in the last talk, I don't know, so we want to do more like a push assisted polling thing, which is like, because polling, so push works really well when everybody is tied to one channel. So if you are on a ticket and you want to update that, it works well. But if it's here, there are a lot of combinations depending on who's logged in, which company, which view they are on. So what you wanna do is we wanna broadcast an event saying, okay, in your company, tickets have been updated. So then you can initiate a poll. So maybe we'll do that later. You can use it if you want. I mean, I think you just have to make sure that the dollar, but why would you wanna use prototype? Yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah, yeah. Sorry, you can use it if you want. We use Capybara, yeah. Capybara, so you can integrate Serenity with this Capybara, then you can translate your, because you are basically running which app, so you need Serenity testing right now. Yeah, yeah, yeah, yeah. You can use it if you are, like, you can have this here, sir, or not, sir, right? You cannot run that, like. No, you can, that's what I was saying. So you can, there's something called XVFB, X Virtual Frame Buffer, which is like having a display, but in memory. So your browser will launch in memory and if you want, you can even connect to it using BNC. So, I mean, it's like having a real browser, so you don't have to do any changes. I mean, that's, you can just get a model, sir. Are there tools, there's a transaction, there's something like that? Now there are some gems. If you use awesome Ruby, then you have gems for all of them. Yeah, yeah, yeah, yeah, yeah, yeah, it does. You can opt into HTML5, push it. This is older browsers. No, older browsers, it will fall back to the hash thing. Yeah, older browsers, you'll fall back to the hash thing. Yep, thanks, any other question? I'm, anyway, hanging out here. So if you guys want to chat, okay, thank you.