 I don't even think I can top that introduction. So, can everybody hear me? It's good. OK, so this talk is Backbone Discuss, a post-mortem. Basically, I just want to talk about a project we did last year in which we converted the Discuss application to use Backbone. And not just that, we did a complete client-side re-architecture. So I'm going to talk about that and explain what Discuss is and why we did it and all that. And just to start off, just want to, you know, some people don't like the word post-mortem because it's death and it's like I'm doing an autopsy or something. But technically speaking, in the dictionary, it's an analysis or discussion of an event. After it's over, I just want to get that out of the way for people who are upset about it. So just a little bit about me. Earlier this year, I released a book with my co-author Anton Kovalev, he's a JavaScript guy. I don't have a guy thing, so I'm just Ben. But we put out this book. And it's about building third-party widgets, writing JavaScript code that goes on other people's websites, how to make it not break and stuff like that. It's a pretty good book. You should check out the Amazon reviews because they're very insightful and they may convince you to purchase the book. And there's some legit people out there who've said some nice things. Rekha Murphy was a speaker last year, I understand. So just based on 45 pages, I think that's pretty good. She recanted everything 60 pages in. So I'm not here really too much to talk about the book, although definitely some of the stuff is related. So I work at Discuss. And that's Discuss, like discussion, not discus. I'd say it's about a 50-50 split that people say one or the other. And once you hear Discuss, you're like, oh, that makes sense, why didn't I think about it? Don't worry about it, now you know. So what we do is we do a conversation platform, embedded, commenting thing. We're all over the web. A lot of big sites, a lot of small sites. Lately, I'm more into about some of the non-traditional uses of Discuss that really get me excited. We're actually on the Redis documentation. So this is just a page. It's the expire command. And there's a legitimate conversation taking place at the bottom about how to use the command and people participating. And I think that's pretty cool. So how Discuss actually gets on your page, if you don't know, it's a third-party script. You put this snippet, kind of like a Google Analytics snippet that everybody's seen. You put it on your web page. You sign up on our website. And you get comments on your website. So just quick recap. We're on a lot of big sites as well. I showed the Redis documentation. But we also do comments for CNN, Wired, IGN, Rolling Stone, NPR. It's a big list. Also the Ruby on Rails blog, Ruby.dot.org, stuff like that, a lot of personal blogs, et cetera. Just some obligatory fancy stats. We do about a million uniques a month right now. That's like Google's measure of unique, which would put us in like the top 10 sites overall if we were just at destination sites. That's kind of crazy. We get almost a million comments a day. But that's just comments. We also have a lot of other events that are taking place. There's votes. There's favoriting things and sharing things. There's a lot of stuff that's happening. And we also have a real-time service that's new. And it was part of what we built in the last year. And on any normal day, we get about three million active connections. And then my last stat is that there's 16 of us that are building this, which I think is pretty cool. Apparently, 18 today. I got an email because we hired a bunch of people. And then lastly, I just thought this was neat because I'm here. Discuss was a YCO 7 company. At the time, it was in Cambridge. So probably just a couple of blocks from here. I actually only just learned that a couple of months ago, so it's kind of neat. All right, so that's like Discuss Today. That's kind of what we're doing today. But I want to bring you back in the time machine. We're going to set the time machine back one year. That's the most interesting time you would go to if you had a time machine. So our two years, year and a half. So in 2011 Discuss, it's kind of a little different. We're trying to do this software as a service thing. SAS, not SASS. We could be both, I don't know. And it was the kind of thing like you went to our website, we had a free service. But you could go to the website and there'd be that familiar like choose a plan. $20 a month, $50 a month, $100 a month. And depending on what you got, you got access to different stuff. Analytics, a beaming thing, a template editor. And also the application is really customizable. Like anybody could just write CSS, target some stuff, make it look different. It was like your comments. And that worked really well. And we were getting really big, really fast. And a lot of people were using us. And they were pretty happy. But things started kind of like snowballing, getting out of control for us. For starters, when everybody can customize Discuss, it starts to look different everywhere. And then people don't really know what Discuss is anymore. It could be as simple as just taking off our branding or just completely eliminating a feature or whatever. People, depending on the community, went to something like, I hate Discuss because in some cases they just completely modify how it worked. And then somebody else would be like, I love it. It was kind of irritating. It was difficult for us to introduce new features because people were taking parts out and doing whatever. So if we want to introduce a new feature, we couldn't always depend on what was there. We kind of worked around this idea that people were just kind of taking stuff out. And we do a lot of ifs and buts. Really frustrating. It was brittle, it was buggy, and we had some security and privacy issues. So I'll just cover those a little bit more. So just to give you an idea of how customization-wise what Discuss looked like, here's a screenshot from the MLB comments that you've discussed. You notice the word Discuss doesn't appear anywhere. That's just one example. This is people.com, I think. I think it's supposed to say power about Discuss in the corner, but it's like a broken image link. So nobody knows. And it looks completely different there. And then this is AV Club. They've taken some stuff away in the header, and it's different as well. Kind of annoying. So I just gave you an idea of how it looked differently. So I'm talking about introducing new stuff. We were rendering elements. We were rendering comments on the DOM. We call them publishers, because I guess when we got started, a lot of people used Discuss are like web publishers, like CNNs and stuff. So it's just like our internal talk, a publisher, website person, use CSS to hide stuff. And even if they couldn't target stuff with CSS, even if we were getting super clever with CSS, they could always just remove it with JavaScript. So you can do stuff to play this game. But it's on your DOM, you can traverse it, you can do whatever you want with it. It's really hard to stop people to do that. So just to give you an idea, we got these CSS nuclear arms races, where we really over-specified things with we'd use important tags everywhere. We'd use double ID selectors, because nobody uses double IDs. So and then somebody would be like, fine, well, now we're going to use triple IDs. And then it was just getting really silly. And that's how easy it was to just take stuff up. And obviously, some of the stuff we wanted people to customize, but then we kind of had this global stuff that we didn't want anybody to change. We wanted the login thing to look the same everywhere. So you knew how to log out or how to log in. That's the stuff that people would change. It was really irritating. So lastly, I'm sorry if this is a lot of setup. I just want everyone to understand what we're working with. I feel like there's a crazy story. We're running a lot of code on the host page, on the publisher page. A lot of people have messy JavaScript environments. People talk about how our code base has all these globals, it's gross, it's legacy. We have to deal with that at times like everybody's website. And it's really hard to predict what people are doing. You often find yourself debugging cnn.com or whatever. And you'd find plug-ins or whatever. It might not even be them. It may be that they had another third-party script. And we would all mess with each other and just have fun. So this is a true-to-life example of something that we encountered where somebody decided to override a rate of prototype and push. I don't know what purpose they were serving. They actually removed functionality. Because even though this works, like it's just pushing on top of the array, the actual array prototype and push takes multiple arguments. So you could push one, two, three, four, five values. So we had some code that did that, and it broke. And that would just be the kind of thing we'd need to do debugging. I would cry. And so now this is the last thing. We also have privacy issues. And this is the thing that I don't think a lot of people understood. And we didn't understand for a while. But if you think about it, it's all about having this like global identity, and you go to different websites, and you can sign in and post. But for us to do that for you to see like, oh, I'm logged in here, and I'm over here, and I can post somewhere, we're putting information about you on the DOM. We're not sharing private information, but it's enough to identify you. Like it could be your name, it could be whatever. And if you think about it, we're kind of sharing that as you browse the web. So to give you an idea, here's like the old discuss, and here's me logged in. And I'm just kind of highlighted with my terrible Photoshop skills. Like places where you can kind of gleam information about the visitor. So for example, I've written this post, and although you can't see post below it, it's highlighted in red. So I think that's not even something we did. I think that's like a tool that a publisher did. But they could say, oh, this person is highlighted in red. Well, now I know the author has been vinegar, or whoever's visiting this page, it's red. Who's the author it's been? They could conceivably start collecting that information. It's kind of scary stuff. Horror story. So I guess at the end of 2011, we had this idea, we're kind of getting tired of all this. It was very miserable, and this is not cool. So we had an idea, which was, what did we discuss? And we put everything in an iframe, just entirely. We used iframes before. I know a lot of things about iframes. But we didn't use them like everything. We used them sparingly in places that really needed to be secure. Like the post box itself would be an iframe, because we didn't want people to hijack the post box and write comments on your behalf and stuff like that. But now we're talking about taking everything. So that's effectively what the project was. So this diagram might explain what we were going for. So just take everything and put it in an iframe. So why would we do that? And that's really because of the same origin policy, which is stuff on different origins, can't access each other, that iframes as well. So we put this iframe, it's on discuss.com, parent page can't mess with it. It can't find, you know, glean any details about it. They can't inspect it. We're running in our own code environment completely. Never have to deal with, you know, messy parent JavaScript environments. And I didn't really talk about cross-site scripting, but in the hypothetical, you know, what's the word I'm looking for, let's say that there was a cross-site scripting vulnerability in our application, OK? Worst case, we could put that all over the web. We could put it on everybody's web page. And that's super bad. In the iframe case, at least it scoped our iframe. And it's just us that's affected. I prefer that, you know, like that's just a million times better. And I'd like to think that nobody has cross-site scripting vulnerabilities, but the reality is that almost everybody does. I think there was a Google Finance one the other day. Even, you know, the biggest websites, the biggest development firms have a nonstop. So we embarked on the grand rewrite, as Joel Spolsky has called it, except not quite, because we just did the client-side. Client-side codes is all JavaScript, basically, and like templates and that kind of stuff. We still had an API. So we had an API, it was pretty decent. We built on top of that. We didn't rebuild really very much server stuff. And we made a decision that we were only going to do IE8NUP, which was a little contentious going back to 2011, because IE7 was still used a fair bit by our customers. But the reason we did is that IE8NUP has a very critical feature for working with iframes. Window.postMessage, that's the method that you use to communicate between iframes in a safe way. There are tons of hacks to go back with older browsers. But now that we're in 2013, there's really no point in talking about them. So it was just like a bit of a problem here, which is we were selling this product, and one of the big sales was that you could customize it. It was your thing. So as product engineers, we're like, here's what we're going to do. Here's the new version. It's totally awesome. We're going to fix all this stuff. And then you talk to the business people, and they're like, what? So it wasn't enough to just refactor it. We couldn't just refactor it. So we actually, we were going to take stuff away. We felt that to make it compelling, to make people want to switch, we also had to add new stuff. So we did a brand new UI. We had designers crank out a new user interface. We built a real-time system. We were going to bring real-time comments to everybody for free, was the idea. And you saw my, if you remember the quote from earlier, we do a lot of concurrent connections. That's what started here. So choosing a framework. Spoiler alert. I won't spoil it. So now that we have our own iframe, we're like, OK, we control this thing from top to bottom for the first time, which was very exciting. And we wanted to use a framework. We just thought that we needed something. We're not good programmers. So, but a lot of the stuff that's out there isn't necessarily fit what we're trying to do. Discuss is an iframe. There's no address bar, there's no permalinks, there's no, do we really need a router? Not really. When you refresh the parent page, the parent page doesn't remember the state of all the iframes and restores them to some URL. That doesn't happen. Discuss is loaded repeatedly. A lot of single page or a lot of backbone apps, ember apps, you open them up and they kind of hang out there and you browse around and they stay. With us, you see Discuss everywhere. You're loading it up, you're closing the tab, you're linking, you probably hit a ton of times in a day. You may even load it multiple times on one page. And the last thing is that it's actually kind of short-lived. Unless you're the kind of person who browsers with 200 tabs open, I know those types of people, usually you don't keep Discuss open that often or that long. So we really felt like backbone. We looked at ember a lot, this is the end of 2011. We looked at ember a lot and we looked at backbone and we thought that backbone would fit much better. We weren't 100% sure what it was going to look like in the end, but we just thought the lightness, there's a lot of arguments that are made about backbone doesn't do too much and that's good. And for us it was very, very good because we didn't have that much. The extensibility was important because we had some legacy stuff that we're bringing, some old libraries and maybe even some newer and non-traditional libraries that we thought backbone would do a better job at. Just looking at the code, looking at how everything fit together, it looked good. And lastly, file size. I'm not a file size guy. I don't think size matters that much. But I think that we have a different application in which you go to a website and discuss, get served, and a lot. I think that we have a higher obligation than other websites to try and be as tight as we can. And maybe we're not the best, but we try. So we felt that file size was a goal. We really wanted this to be the leanest thing that you could do. To that point, we decided not to use jQuery with this. We decided to go, jQuery was too mainstream for us. So we decided to try Ender, which is like a collection of microlibraries. People aren't going to like this, but it's a little defunct right now. But at the time, it felt like really up and coming. And it felt like it fit our needs very well. Like it came in at maybe a fifth of the size of jQuery. Probably did 70% or 80%. We thought that was enough. And technically, Backbone supports it. These will be one line of code in which it just looks for Ender. And that's in Backbone today. Doesn't mean it works, but it will at least be initialized to use it. So and then just finally, we did less in Bootstrap. So that may also be surprising. If you look at Discuss Today, it is actually Bootstrap. Probably about 25% of it, or even less. It's really the foundational stuff. But we built off of that as well. So stuff happened. We built all this in about six months. Probably the first month was prototyping. And then we did four to five months, which I think is pretty fast. I don't know. So we did this beta in May. And then we just released it in June. For some reason, we called it Discuss 2012. And there's a kind of a funny story behind that, which is that internally, we called it Discuss Next. And you may or may not be aware, but Next is a very popular project name for companies. There was SoundCloud Next. And then Basecamp Next came out. And all of a sudden, calling your thing Next didn't sound very, very sexy. And we ran out of ideas. And 2012 happened. I'm sure it was smarter than that, but that's just a little backstory. And now I'll regale you with this video we made when it came out. So a little bit what it's like. I'll turn on this music. It's got like this. It's got like this, you know, aptly kind of like music thing going on in the back. You'd never believe that it works this good, but it kind of does. Anywho, oh man, didn't like videos very much. So we did it. That's basically what the video is trying to say. We actually built something. And it works out pretty good. Now, what you see today is basically that project. And it's just been iterated on in the foundations of what we built then are just still cranking along. So now that I've got that very incredibly long intro done, oh my god, it's been 25 minutes. OK, so now that I've got that gone, I just want to talk about sort of technical hurdles we ran into and solutions, stuff we do with Backbone that I think are a little interesting and maybe a little different. So first off, just want to talk a little bit about iFrames. How did that work out? It kind of solved everything that we thought it would set it to do, so that's pretty good. It adds some pain points, though. Working with iFrames is a little finicky. Talk a little bit about that. But actually, we also got some bonus stuff of iFrames that we didn't even plan for, which is really surprising. I'll talk about that really quickly at the end. So what is painful about working with iFrames does an embedded application. Basically, inside the iFrame, just as the parent page can't access you, you can't access the parent page. So you don't know what's going on in the world around you. You don't know what events are happening on the outside. You don't know if the viewport is changing, if you want to know where the viewport is, because you wanted to furlode some stuff. You don't know if the URL is changing, if there's push state happening, your document fragment, stuff like that. But we do a post message. And the way that basically the application works is we have code running on the parent page. Very little, I would say about 5%. And all that's doing is really relaying information about the parent page into the iFrame. So it kind of looks like this. So just to really understand, why is this a problem? Let's say that this is droidlife.com. And let's say that I open up this menu. And now I want to close the menu by clicking away because that's how applications just work. If I click somewhere else, I want to close the menu. We don't know, unless we track events on the parent document and send that down, we don't know. The iFrame has no idea if you click outside the iFrame. So an early version of this is you just can never close this. So that's the kind of stuff we would do. So just if you're curious, just to show you how we did this is on the parent document, we have some code. We'll have an event listener. We're looking for the click event. When it happens, we'll just send a message using post message to the iFrame and say, hey, click event happened. This is probably the absolute simplest thing we do with this. And this is of course not the actual code. It's just kind of a simplified teaching kind of one. The last parameter to post message, I don't know if any has anybody who's used post message here. Just said a curiosity. OK, 20%. Check it out on MDN. It's pretty simple. You take a window reference. You call post message. You give it a message. It can be a string. It can be JSON and newer browsers. And then the last parameter is just like a target origin. And that's so that the browser will only send the message to a domain that you expect. That's just a little security thing because people can be quirky and you may think that you have a reference to a window but somebody can redirect it somewhere else that you don't like anymore. So on the other side, now we're inside the iFrame. We've got to know this click event is happening. There's an onMessage event. So we just listen to the onMessage event and we're getting these messages down that we're sending. And if the clicked event happens, we do something. If the scroll event happens, we do something. If the hash change event happens, we do something. This is just a really simplified version of that. So this is kind of like, it's not very nice. And we decided to throw some backbone on it. So we really like backbone. We like the API. We like the event-driven stuff. And people have been talking about the events mix-in. We put that event mix-in on everything. So we put it on our messaging wrapper as well. So that we can do the lifecycle events and everything about what's happening on the parent page, just as you were like model changes or something. So if you want to write the easiest post-message wrapper in the world, this is what it looks like. We call this the messaging bus. Somebody talked about the messaging bus earlier. And all it is is an empty object with backbone, or extended with backbone events. And then on the onMessage event, we just trigger something on that object. That's it. Works surprisingly well. Obviously, we do a lot of some other stuff. But that's 80% of it right there. So now, if you have a view, here's like, let's pretend this is a user menu. It's a user menu I showed you earlier. When I initialize a view, I'm going to listen to the bus. So when I get that window click event, I'm going to close it. That's just how it works. It's just like if the model changed and your name changed, you're going to do something as well. So kind of neat, we get to keep working within the backbone ecosystem, even though we kind of have this weird embedded way of doing things. So one last bonus about iFrames is we get to use this feature called content security policy. How many people know about content security policy? Oh man. Like 2%. Content security policy is kind of like a bleeding edge feature. It's in Chrome and Firefox right now, but very recently in Firefox. And it basically lets you define headers with your resources on a document so that nobody can execute inline code. And that prevents attackers from injecting inline code, because it won't execute. So everybody can use it right now. And I recommend looking into it, because it's a huge, huge mitigator for across-excerpting attacks. The upside for us is that now that we're in an iFrame, we can just say, hey, the iFrame can't execute any inline code, so nobody can inject anything. So if you're using a modern browser, you're actually prevented from being affected by any cross-excerpting vulnerabilities. Super cool. I've been giving some talks about this over the last six months. And there's a talk there if you want to check it out just to learn about it. It's pretty neat. I think the number of sites that are using this is extremely low. It's like Twitter and Disgust and GitHub. And I'm not even joking. It's that short of list. I keep asking more people if they're using it, but nobody gets back to me. So the next thing that we deal with is a lot of instance wrangling. So we kind of have this uniqueness problem where we have a lot of different collections. And models appear multiple times. I feel like probably everybody deals with this. Some models, in our case, are fresher than others. And when we want to change one model that represents like the same database-backed object, we want it to update every other instance. So to give you a quick example, let's pretend that this is posts in the Disgust system. This is a collection of posts. I've got two posts. They're both written by me. So there's sort of like a sub-object here, which is author, and that's me. And I'm just complimenting my own article. So let's say that after I got that data, I decided to log in as me. But I've also, in the interim, since I made those posts, I decided to change my username. I want to be called Ben, Salt, and Vinegar. And so I request this session. And I get this newer data. But on the posts, I still have the old display name. They don't sync up. And that's kind of how backbone works out of the box right now. If you have the same database-backed object in multiple collections, they'll leave different instances. So why does that matter? Why would that even happen? Why would I get, when I fetch data that's me, why would it be mismatched with a post data that came earlier? There's plenty of reasons. A big reason for us is that most of the traffic that we get is people who are logged out of Disgust. And a lot of it is also stale and doesn't change. So a commenting thread from six months ago usually doesn't change very often. It's really heavily cached to the point where we even put entire commenting threads on a CDN. So what we'll do is if you change something about yourself and you visit an old thread and you just want to admire your old comment, we will augment that comment automatically with your freshest data. So that's sort of a way that we deal with this. There's a whole bunch of other benefits. You would just say memory if you have duplicate models and stuff like this. But this is something that's helpful for us. We wrote a backbone plugin called Unique Model. I think there's a bunch out there. What Unique Model does is you wrap it around a class and it wraps the constructor. So whenever that model is created, whether it's in a collection, whether you do it, it's always unique. So this is a quick example if we went back. I created one instance with my old name and I created a new instance with my second name. The two instances would be identical. And we assume that any object that comes later is actually the newest record. So it updates as that. So to extend on that, what if you have the same instance in a single document? What if you have the same instance across multiple windows? Wouldn't it be cool if you could synchronize data from one window to another? So it's just like carrying this forward. And this is affecting us because we're starting to do multiple live frames. Our application is spread around just multiple windows, multiple live frames. So we've been experimenting this and taking that backbone plugin, unique model, and putting it on session storage to synchronize data as they appear in different places. I'm not going to go too deep into it, but if you check out the repo, I had this demo in which to do MVC appears again. And I added, basically it includes this plugin. It adds two lines of code in which it just, it's literally just two lines of code. You can check out the repository. And then it does this, which is this is four windows up to do MVC. And every modification that happens in one window automatically gets spread to the other. At some point, I should go to the other window and show that it goes the other way. Am I going to do that? Nope. All right. Well, it does. Ha! Ha! We don't do this yet. This is really experimental for us. But we think of it really cool. So lastly, last thing I'm going to talk about is event proxies. Just another pattern that we use. We represent a session inside of discuss, like the state of a session using distinct classes. When you first, when we first load discuss, we assume that you're an anonymous user. And that is the session. It's the session of an anonymous user. When you log in, now you are a completely different user. You are a full-fledged user. And if there's a single sign-on integration, maybe you're a single sign-on user. Why have different models? They each validate differently, depending on if you want to post as that user type. So there's some, you know, we can test them individually. So there's some benefit to that. So, but there's just a bit of a problem here, which is, let's go back to my user menu. And let's say that as I initialize this user menu, I'm going to listen to the session object. I'm going to say, hey, when you change, I'm just going to re-render the menu, right? The user, like, I was logged out, now I'm logged in. I got to render, re-render that user menu to reflect the fact that now there's a user there. But if the way that I log in is to just replace the session instance completely with a completely new object, my view is actually just like it's listening to a dangling reference that is no longer in the application, which is not good. So the way that we've done that is we use a proxy model that wraps a user. So the session is a model. You can bind to it. And it just kind of, it has, like, it contains a user. And any events that trigger on the user event will just get propagated to the session. So I bind to the session. I'm like, hey, if the session, if the user name changes, the display name changes, re-render, it doesn't matter if the logged in state becomes a completely different user. It will totally work. I never have to do crazy cleanup or whatever. So that's been helpful for us. And again, this is pseudo code. Maybe I wrote it and it totally works. I'll try that out later. So I'll probably spin off the stuff that we actually use. I'll spin it off into a guest or something because I'm seeing a lot of nodding heads. That seems cool. So today, this is now, like, just over a year later, this version has been out for a year. Obviously, I highlighted some security concerns and private security concerns. And probably when I showed that, we were freaking out like, oh my god. The good news is that we basically deprecated that version. And we're phasing it out today. Over 99%, it's probably 99.9% of discusses using this newer, secure version. And we hope that soon, that will be 100. And even though we had all these crazy fears about, like, no one would want to use discuss if they couldn't customize it as you know. And you can customize it a little bit just not to the degree that you could for. You just can't target whatever and change it. We've still managed to grow a colossal amount. I think 50% when you're doing billions of pay views is pretty big. And just to show you what that actually progression looked like, when we rolled to that in May, looked kind of like this. So blue is the new discuss or discuss from 12. And red is the old one. I think the number, this is not a present, I borrowed this from somebody else's presentation, but I think the number upon the left is like daily total events. Stuff that is happening or stuff that we're logging. So you can just kind of see how that's what it started. And by the time we get to the end, we've actually grown significantly, completely with the new version. So I think that's pretty cool. And then lastly, like I said, we're still iterating on that. We're still evolving it. We're trying to use more and more new stuff. Mocha sign on, I saw a lot of that today. We use that too. So that's pretty cool. We use handlebars and we've been developing a ground build process and stuff. And my last thing is that we actually got rid of Ender and switched to jQuery. And that literally happened like in the last couple of weeks, or I just finished the last couple of weeks. That could probably be an entirely new talk or an entirely different talk. But if anybody's curious, Ender just didn't really work out very well for us. I think, I remember the summer of the micro library. Does anybody remember the summer of the micro library? And although I think I had really good ideals, it's hard, you just can't, I would bet on jQuery. It's just basically, you can't, a lot of people have tried to say like, I can build the 80% library of jQuery. And it's really, really hard. There's a reason why jQuery is where it is today. With Ender, we were patching just a ton of stuff. We used an AJAX library. Oh, this AJAX library doesn't support cores. Okay, we got it implemented. The DOM API was just randomly broken, inconsistent in a bunch of places that people didn't think about, stuff like that. And we would spend a lot of time debugging Ender and not writing code, and that really depressed us. So that's what ultimately facilitated the change. So, am I like super over, by the way, to the start? 30? So just final thoughts. I'm very big on iFriends. If you're doing embedded applications, obviously I highlighted a lot of reasons why you should explore that. I also think, this is a little controversial, but there are other applications out there that worked today in the way that we used to work. And I think people should be critical of that because they have a lot of issues, privacy issues, security issues, et cetera, that I think are kind of concerning. That's all. I'm not saying that we're awesome or anything, but I would like to see everybody move to the model of iFriends. iFriends are not scary. They shouldn't be this ridiculous thing that everybody is like, ooh, that's gross. They're actually pretty awesome, and they let us do a lot of cool things, so. That's all I got. Clap. Clap! So I'm gonna do the shameless plug, which is that we're hiring really badly. I'd love for some backbone people to join me and discuss some work on backbone and reach a lot of people and stuff like that. Any questions for Ben? If there weren't any, if you weren't showing any private data and there were no privacy concerns, which is not the case for you, would you still prefer iFriends just because of the CSS conflict problems and sort of the namespace problems? Well, there's still a security problem there, right? Even if you're not showing private data, you're probably showing some sort of user-generated data, or at least a lot of people are. If you're not, then don't mind. I do know that there are like, there are widget people out there who are building stuff without iFrames because iFrames are slow and they are inputting user data directly into DOM. I think that's a problem as well. But the CSS angle or whatever? I mean, I say that, but you're right. It really matters on what you're trying to do. If you are not, if you don't have user data and you don't have session kind of data, I think it's really fine. At that point, it's just how much do you wanna suffer in terms of being, you know, possible to be manipulated by another party? Does that make sense? Okay, cool. I was just wondering, mostly, just very roughly, what sort of size is the, you know, the payload when you load a disk is, like, your application? I'm trying to think off the top of my head. Discuss, very much. I think that the initial script that runs on the host page, I was looking at this the other day, is 12 kilobytes, so that's what runs on the host page. Just 12 kilobytes. And I don't mean the application in the script. Yeah, I'm getting there. I need answers. Yeah, I don't know how to research the jQuery. I know that we knew that this would be like, this would be 20 more kilobytes. Can you handle that? And we were like, yes. Probably, like, I think approach it, like everything, everything is probably approaching 300, I think. So my follow-up question to that is, you said that on a single page, you might get multiple embeds. Yeah. Do you have any way to avoid each of those embeds, including 300 kilobytes of download? I mean, well, the one upside is that you'd be requesting the exact same asset and the browser won't be downloaded, right? I mean, it's still a lot of code. We actually- We're gonna have to be parsed three or four part times. Yeah, there would be the possibility of that. I feel like you could imagine, like, if we downloaded the code as an XHR bundle and then we passed it to an empty iframe and executed it there. That would be really cool. The thing is, that could be okay. One thing that we're really- I mean, this is also like a fringe case, you know? Almost never see that. So it's not really something we think about too much, but it was a thought. And we do open, like, we do a profile model now. So if you click on somebody's face, you're gonna see a model pop up. That's actually a full screen iframe, which is a really cool effect that I'd love, I would love to talk on another time. You can't tell that it's an iframe, but it just overlays the whole thing. It's really neat. And that could be something. One thing that we try to do is, because of this privacy thing, we don't transfer anything on the parent page, anything even remotely private. No user data, no anything. So if we wanna transfer data from one thing to another, it's through session storage, or we just request, again. I don't know, that's sort of a, kind of an answer. Anything else for Ben? He said breathing into the microphone. Nothing? All right. All right, cool. Thank you.