 Hey, so I'm here to talk about error-ception. It's a project that I've been working on for about a month, two months or so now. It lets you track errors that happen inside your browser, inside your users' browsers, and then post them to the error-ception service so that you can come back and review your errors whenever you want to. The talk is not going to be a product pitch as much as I want it to be, and I want people to start paying me and stuff like that, but I'm not going to talk about that right now. I'll instead focus on the several different approaches I could have taken for catching errors and reporting them back, and I think that would be interesting to this audience as well. And I'll talk about the decisions that I took and there are pros and cons to that. Everything's not perfect, and you will get to know about why I took the decisions that I took, right? First of all, my name is Rakesh Pai. I blog, I tweet, and I'm a veteran, so to say, in the JavaScript world. I've been doing heavy JavaScript deployments since 2004. This is before Ajax was coined. This is before, you know, there were frameworks in JavaScript. This is way back, right? There was only IE6 and IE5 for Mac, I think. That's the only thing you had to worry about back then. So why report errors, first of all, right? We have to understand the problem. I'm sure you all know the problem, but let's just go over this really quickly. First of all, JavaScript is unlike a lot of other deployments that we do. For example, if you're working, if you're comfortable with PHP or Java or what have you, you're running on very controlled environments where there is, you know, you can compile your operating system the way you want to, right? It's a very different world. JavaScript is not like that at all. Your code is running on the wild. There are, there is this three-dimensional grid, so to say, of browsers, browser versions, and operating systems, and it's crazy. There's no way you can build a test suite that is going to cover all of this, right? There are going to be bugs for sure in your code, and if you think there are no bugs, then please come talk to me. I will, you know, I'll shatter your confidence. But if you think there are, you know, there's no way you could have released software without bugs, however much you might have tested them, right? Errors when they happen are locked to your user's console, which is absolutely useless for you. There is nothing you can get from that, right? These errors are essentially lost. You don't find out about these errors at all. And when such errors happen, your users are not going to pick up the phone and complain, right? In fact, like I said, I've been programming since 2004. I have only had two complaints so far for my code, which is two complaints more than most people get. The first one was where his credit card number got exposed by mistake, and so it's obvious he would complain to me. And the second one was where I asked developers, my friends, because I could not just reproduce this bug that I was trying to track. So I told all of my friends who are using this site to call me in case they find this bug so that I can help them, you know? And that's how I got the second complaint. So these are the only two times when I have got complaints. Your users are not going to complain. They are going to leave. Their computer sites work. Your sites do not work. There's no reason they need to bother complaining to you, right? But you know all this. I'm preaching to the choir. When JavaScript fails, it fails spectacularly, right? Everything stops working. You're lucky if maybe the ad network that you have signed up with, that is the one that gave an error, and ads stop showing, that's okay, that's tolerable. But if your app stops working, that's simply not tolerable. So like I said, we're going to go through several mechanisms of catching errors. And there are at least six or seven that I have over here. And we'll go over that in some amount of detail. While we're doing this, we're going to come up with a bunch of, you know, we have to try to sound scientific and all that, right? We have the computer science fraternity, so to say. We have to sound scientific. You know, come up with good metrics, do evaluations, you know, all of that, so we'll do that, right? So there are a bunch of criteria that I'm going to establish. Some of which, and these are my personal opinions, and this is what has helped in the design of error exception, your opinions might vary. I'm just telling you what my opinion is, right? As far as these things go. So the most important criteria for me is performance. However important it is for you to catch errors, or for you to find out what's happening in your users' browsers, there is no excuse whatsoever for you to cause any performance hit in your site because of your need to catch errors, right? That's simply not acceptable. Performance is, to me, a user experience metric. Users, performance is something that directly impacts the usability of your website in my opinion. And there is no way that can be compromised at all. So performance is number one. If any method that we are going to choose is going to cause a performance hit, we are going to discard that method because it does not work, right? The second important metric is reliability. Now my definition of reliability here is weird. I guess I could have come with a better word, but with reliability what I mean is that you don't take a hard dependency on this system. And in case, for whatever reason, that this error reporting system does not work, your code should still continue to work. There is no reason for your code to break in case the error reporting system does not work, right? If you are going to take a hard dependency on an error reporting system, that's a bad system in my opinion because you are now at the mercy of some other code to ensure that your code works right. And that's not acceptable to me. The third is, of course, implementation effort. The amount of effort you have to put in to ensure that your system is up and running. More than up and running, more than setup implementation, my concern is more about ongoing implementation rather than setup information. For example, your error reporting system requires you to put try-catch blocks around each one of your code blocks. You can feel free to do that, but honestly, if I was forced to do that every single time I write a block of code, I'm going to stop writing try-catch blocks, right? And that will mean that the system has failed because it requires effort from my end for implementation. So these three metrics, performance, reliability, and implementation effort, are the three most important metrics. There are these good-to-haves as well, which I'm willing to compromise on a little bit, but if I don't have them at all, it's still all right. The number one is rich errors, which gives you ability of getting stack traces, getting each of your stack frames, which files they belong to, which line number they are from, which what are the arguments that are passed into each of those stack frames? They are important pieces of information as well, and that's a good to have. Coverage is how much of your code is covered by the error reporting system? Does it cover if you have on click in your HTML inline on a link, right? Is that going to be covered by error reporting system? Is global code that is written inline inside your HTML? Is that going to be covered? These are questions as well. If they have that coverage, then that's great. If they don't, maybe I won't really miss it, right? Simplicity, I value simplicity. I don't like systems to be too complicated. If a system is simple, that's great. And so simplicity has its value. And browser support as well, obviously, that goes without saying. These last four ones are not super critical. The first three ones are super critical to me, right? I'm not going to compromise on the first three. And if there is a tie there, then I will choose based on the last four. And I'm going to come up with this, to look scientific, of course. I'm going to come up with this stupid scorecard system, which has got performance, reliability, and effort. And then Richard has covered simplicity and browser support. And then we will see how they match up over time, right? The first method is manually adding tri-catch blocks, right? Now, this might seem simple at first. I also call this spaghettification. If anyone here is interested in astrophysics by any chance and is familiar with the term spaghettification, it's the effect that when a piece of matter enters through the event horizon into a black hole, and the black hole has got opposing gravity effects in them, and that thing just gets stretched and elongated and broken into pieces, unless it's like a stream of atoms and falls down into. So adding tri-catch blocks manually is similar to that, where you get split up and broken into pieces and elongated and shout down. To give you an example, this is some very simple jQuery code, which basically waits for this button to be available, and every time the button is clicked, it alerts the next sequential number, right? Pretty simple code. If we had to add tri-catch blocks to this manually, this is what it would look like, right? Just a digression, the post-error function. So there are two parts to handling errors, right? One is obviously catching the error, and the second is posting that error to the server. I'm hiding that away in this function called post-error. Let's assume that does it somehow, that's irrelevant at this point of time. You need, for something as simple as that, you need code that complex to be able to catch an error. The reason being that the stacks are different, right? The outermost block of code is executing in a different stack. Dollar dot ready, which is when your page load is ready, you are asking it to execute this next function, which is lying in a different stack. It's gonna be called at a different time. Your previous stack has unrolled. Your previous stack's tri-catch is not going to work on the inner function, right? So your inner function now has to have its own tri-catch, which the outer one does not work on that, right? Similarly, the button click is another stack now, which is gonna happen at another point of time, and that requires its own tri-catch. So now, for something as simple as that, we have nearly doubled the lines of code just to be able to add tri-catch blocks to it, and this does not even include the post-error function that's gonna be done somewhere else, right? Yeah, this spaghedification is what I was talking about. So this method, so let's look at the scorecard. Performance depends, and I'll come to that in a second. It is reliable in the sense that there is no real dependency on an external system. If that post-error function does not work for whatever reason, your code is still not breaking, right? Your code still works, so it's reliable in that sense, right? Effort is definitely not low. Effort is very high. We could look at the rest of the points. It does not matter. We have already hit a high effort barrier, but in any case, you do get rich errors. Every time you get an error object, you can get, depending on which browser you are on, you can get a fair amount of details about that error. You can get, depending on the browser, you can get stack frames, you can get which arguments were passed in at each level in the stack, and so on, so that's interesting. You don't have too much coverage. The reason I have said coverage is bad is because you have to do it manually. You will invariably miss areas that you have to cover. And so I'm going to put coverage is bad. It's a fairly simple system to reason with. It's not hard at all. And you have decent browser support. Browser support stretches as far as trycatchers are supported. Trycatchers are supported since JavaScript 1.2, which is every browser out there in the market. I said I'll come back to performance. Performance, I said depends because this system, this mechanism is going to depend on that post error function that we showed right here. This post error function will have to be available beforehand for the system to work. So there are several ways now you can make that post error function available inside the context of your, or inside your global context. One way for example would be to make that post error function available inside a JavaScript file and then you have a script tag that will include the JavaScript file. So now you can reuse that post error function so to say on so many pages. The problem is that now you have got JavaScript file include on your page that is going to make a network request and this will have to be done before any other code of yours loads. Hence now you are creating a bottleneck that is going to be network dependent and so your performance is going to go down. If you have a post error function like this that's going to be sitting inside another external JavaScript file. You could decide that you want to inline that code instead and that could lie inside your HTML page now but then you would have to figure out a way to manage that in the sense that you would have that maybe on 10 pages and maybe that changes in the future you would have to figure out a way to update all of those 10 pages. So it's a little difficult to manage but maybe that mechanism will give you a better performance. So performance really depends on the implementation. You could make it faster, you could make it slow. Sorry, go ahead. Great point, I should have addressed that. I should have addressed that. So try catch blocks turns out if you actually try catch blocks are not that bad in performance. If you look at those stupid benchmarks that you run the same thing like a million times you'll figure out that the difference between code with try catch and without try catch is negligible to the extent that you would think that it is just recording noise. You are right though when your code does break and it goes into the catch block because at that point now your stack has to be unrolled and rolled back up. I'm going to assume, we'll have to assume that most of our code does not break that often that going into the catch block is going to cause a performance hit. But you're right, using a try catch in general and if your code does enter a catch block there is a certain amount of, it's like a 200% 200X difference when you enter a catch block. So yeah, that is something to watch out for. But we're going to assume that it happens rarely enough so that we don't have to worry about it too much. No, no, it does not actually. It just demarcates that code that you want to catch that errors in that block, that's about it. Since adding try catch blocks is so tedious manually we could consider adding them automatically to our code. There are several ways of doing this. One mechanism is to add your try catch blocks at build time. So you write code normally, have a build script that's going to take your code and then add try catch blocks to it and then deploy your try catch code so to say on the server. This has got its complications as well. It's obviously fairly complicated to do this because you cannot just take your code and put one huge try catch outside of it. You have to identify every single function and to those functions, inside of those functions, you have to add try catch blocks. So it will require starting analysis of your code. You will have to take your code, dump that into something that will generate an AST and then into that AST you will have to start adding try catch blocks. So it is fairly complex and it could potentially introduce its own bugs. So it might take some time before this build system based thing becomes reliable. So those are, that's that, right? So this is the scorecard based on that. Performance depends in the same way that the previous one's performance depended because you have to make that function available somehow. Reliability is great. You don't have too much of a dependency on anything else. Effort is low, so this is awesome as well. Almost everything else is great except it's not a very simple system because you are now going to depend on a build process to help you out with this. You know, it's very rare for all the mechanisms that I have. This one is probably one of the best behaving where you have got everything green. So if you are really concerned about catching errors on your production websites, you have to consider this mechanism the most. I'm saying this even though I'm building a product that will generate revenue for me eventually that I'm hoping will, you know. But this is the best mechanism really. You have to tweak your build process to ensure that you can add tri-catch blocks right there. It's going to take a lot of effort. It's not easy at all. But moving on. There are services out there in the wild that do this for you. There are services that add tri-catch blocks to your code, believe it or not. And you could use one of those. So the way it works is that when you are referencing a script tag inside your page, you don't actually load the script tag from your domain. Instead, you load the script tag from their domain, the proxy's domain. They will in turn make a request to your web server, pick up your code, add tri-catch blocks to it, and then flush down this tri-catched code to your client. Takes away the complexity in a sense because they are supposed to be good at handling how to manage tri-catch blocks. So better they take care of it than you try to build a system that will do this. Sorry, yeah. It's sort of like a real-time outsourced build service sort of thing. You do take a heavy dependency on the proxy. What happens if the proxy goes down is a huge concern. Your code is exposed anyway. Your code is exposed anyway. Your code is exposed anyway. Your code is all public anyway. And can still introduce its own bugs, though this is a lesser of a concern because we're gonna trust that those guys know how to do this well, right? So the scorecard in this case is that performance depends for the same reason. Again, you can make this high or low depending on how you choose to do it. Sure, sure. That's what I meant by it can maybe introduce its own bugs or it will not have decent coverage. So that's likely. That's likely for sure. Oh, and I have, all these cases I've said, coverage is good mostly. That's because there are cases where it just cannot do this. What if your code is not inside a JavaScript file? You know, what if it's inside your HTML? What if you have got AHRF onclick equal to something? You cannot handle that in these cases. So performance depends for the same reason. Its reliability has gone down drastically because now you're going through a proxy. You're gonna trust somebody else for your servers uptime, for your apps uptime, right? And that's horrible. Almost everything else is good, but it's a big red in the top three that I wanted. A new service launched recently got funding from Y Combinator as well. What they're doing is an interesting technique where they provide you a proxy but then they also have a failover mechanism where you can, in case their proxy is down, they will detect that and they will route the traffic to your web server instead. Now, you will not get the instrumented or the souped up with the try-catch block kind of code down, but at least your app will not go down, right? So it helps with the reliability in this case. The problem is the performance deteriorates big time and the reason the performance deteriorates is because the way this works is from the client. There's really no other way this can work. It introduces a script loader into your page first. This script loader makes requests to their proxy and if their proxy is down for whatever reason, it finds out that there was a bad response from the proxy and then it will try to connect with your web server, right? So if everything is hunky-dory, if their web server is fine, if their proxy is up, then it's all cool. You're talking directly to the proxy getting code down and it's working. If it goes down, then now you are going to have painfully bad experience for all of your users only when their proxy is down, right? And when their proxy is down, it's actually going to be worse than just connecting to your web server because the script loader will have to first connect to their proxy, discover that the proxy is down and then connect to your server. So it's going to be at least one extra network request every time, right? This is not to say that there is a script loader itself which will be required. So you will have to download a script loader first and that is going to cost, that's going to have its own performance cost, right? So you are going to have a JS file that you will have to use. Yeah, you're right, you're right. They should probably do that. Actually, I'll take that down as a product idea. I'll maybe add that to a reception. That's a great idea. I didn't think of that. Anyway, so here goes, reliability is improved. Performance has dropped. Everything else is fairly okay. It's still not simple but like I said, I'm not going to give that too much weightage. But top three, performance has dropped. That's unacceptable to me. This is a pure client-side solution where rather than doing this to your code, they start mucking with, or that's a bad word to use. They start playing with your runtime itself where what they do is they do things like this where, and this is a very simplified implementation that I'm showing you here. What they do is that they are overriding the document.addEventListener itself in this case and they are, every time you pass it a new handler, they wrap a try-catch around that handler before they pass it on to the actual document.onError, or document.addEventListener. Now, this is better in some regards and worse in some regards, better because in case, this system does not work. In case this mechanism does not work for whatever reason. Let's say this is lying in some JavaScript file that's external. If that file cannot load for whatever reason, your code does not break. Your code continues to work because your code is still using only document.addEventListener in this case. So in a sense, this is reliable. So this is good in that regard. But the problem is that for this mechanism to work, ideally, you would have to first do operations like this or the script tag that will be included will have to do operations like this before any of your code runs again. So this is going to be a performance cost for sure. But it's going to improve reliability in some sense. So I'm going to give it decent reliability and good performance. I'm going to say it's low effort in general for you as a developer, at least, adding this to your page is going to be as simple as adding a script tag from somewhere. So effort is low. Coverage, I'm going to say, is not great because you are only catching errors that happen inside event handlers, right? It's very hard to do other kinds of overriding. So for example, you cannot override ready state of an XHR call. It's very hard to do that. So coverage is, I'm not going to give it full marks. I'm not going to give simplicity full marks either because what I've shown you is actually a very, very simplified version of this. If you think about it, you will have to override, like for example, add event listener on every single node element that you have inside your DOM as well. Since you can't do that, you would have to think about doing this to prototypes instead, right? So you take the prototype of an element and you add this to that. But it turns out you can't muck with prototypes of elements inside IE6 and older browsers. So now you have to have other workarounds for that. So it's actually rather complex to implement this. And so I give simplicity a low rating because you will need to do this before any of your code runs, right? And so you will need to add a script tag to your page that is going to be blocking that will have to do this first to your code. The point is that it will require a network request, it requires to get that script file down first, right? So you're going to be blocking on your page load till that network request completes. Oh, there's going to be a lot of code. So you're going to have to replicate this chunk in every single HTML file if you want to inline this. It's going to be a lot of code. It's not simple. I mean, there is one company that is doing this right now. Their code is something like 50K. What happened? Oh, that only works for one, that is only for one event over here in one case. Yeah, there are so many cases that you would need to handle. Right? So finally, the elusive, I don't know if people are aware of this. It's non-standard behavior. It's not there in any spec. It's not standardized even in HTML5, as they call it. Aditya is going to kill me for saying that. But window.onerror has been around for donkeys years now, and is reasonably well supported in almost every popular browser. So window.onerror, the way it works is that anytime there's an error in your page, it's going to call this one function that you assign to window.onerror, which gives you the error message of what the error was, the line number and the file at which the error happened. And now you can just have your posterer function over there, right? All of a sudden, this looks very beautiful because if you compare this to other approaches that we have used so far, other approaches have played with either the runtime or your code. This thing is not doing that. This thing is sitting somewhere else separately, completely. And so in itself, it is isolated. And automatically it makes me trust this more than any of the other mechanisms. Right? There are downsides to this. You don't have access to the error object itself. All the other techniques that use tri-catch blocks gave you an error object to play with. Here you don't have an error object to play with. So necessarily the errors that you get from here will not be rich. In particular, you cannot even get things like stack traces, right, in this case. Now from my experience, having done this for some time, I think that is not such a big deal personally. I think that it is good enough for me to know that an error has occurred and in what scenario that error occurred. Right? On which browser was it? On what operating system was it? Which version of the browser was it? Do I see that same problem on another version of the browser or not? Those things are far more important to me than knowing what exactly the stack was. Once I know which browser it was at, I can go and try to replicate that error myself and figure out if I can replicate the same thing at my end. So I'm not going to give the rich error thing too much weightage. Take my point with a pinch of salt because error reception uses this mechanism anyway, so I'm basically evangelizing in some sense, but I'm saying that error reception cannot give you very rich errors and this is the reason why. By this time, your stack has already unrolled, which is another reason why you cannot build a stack trace, right? The stack has already unrolled by this point, so trying to get hold of each stack frame is very hard. But as a pro, this thing is very, very simple to implement, right? So the scorecard in this case looks like this. Performance, again, depends because it depends on how you change this window dot on error, assign the window dot on error function beforehand. Reliability's gone up, effort has gone up. So this of all things, other than the build process thing that you would have to insert yourself, this looks the most appealing. It has got the coverage here is the best of all. It covers errors that happen inside on-click handlers. It covers errors that happen inside. You will not believe the coverage that you get for errors. It catches errors that happen inside Google Bot. That's the number one source for errors that I've been catching inside Errorception, right? It catches errors in ad networks. It catches errors in the craziest places. It's amazing. It's very simple. It's very easy to reason. Browser support is decent. This is the worst in terms of browser support. Everyone has browser support was green throughout. This is the worst in that regard. It only supports the most popular browsers, which is all of your IEs, all of your Firefoxs, Chrome 10 onwards, everything. And Opera is now going to be implementing this very soon. So Opera support will come in. It supports Safari 3 Plus. So practically every popular browser out there that you are working with has got support already for this, right? Now, performance is still... Well, the ones that don't have support, the ones that don't have support currently, this cannot catch those errors at all because it depends on when you're being there. So for example, I'll give you an example, right? There's Mobile Safari, for example. Mobile Safari has no support for this right now. So it's useless to have this on a Mobile Safari website at this point of time. This is not meant for that. It will... Oh, right, you're right, you're right. So, but we're talking about older browsers is this has been there in IE forever. This has been there in IE since IE 3, I think, IE 3.5 or something like that, or some such really old version of IE. This has been there in Chrome 10 onwards and Chrome, I don't think, should be a problem as far as upgrades go. This has been there in Firefox since version two if I'm not mistaken. So, you know, a large part of your old browsers already covered in this, right? That's not a problem at all. Yeah, rich errors is a big minus here. It just takes a point of receiving a... Right, right. I have got such plans and... I don't have to take... Yeah, yeah. I do have such devious plans, but... But, yeah, I want to keep the simplicity there intact as well. I'm still playing with that idea. The problem is that then I will have to be a proxy for the JavaScript file, which, you know... Yeah, yeah, maybe. Maybe. I didn't understand. Oh, no, no, no, it's... Window.onError is a listener. It's, so I'm assigning a listener to it. It's just an, it's like an event. It's like document.onload. I'm just assigning a listener to it, a handler to it. Yes, yes, that's right. Yeah, no, I guess I was not clear there. You're mixing up two things. So the process of actually adding the modifications that I had shown on the screen there, that is actually not expensive. That can happen rather quickly. That's not too expensive. The problem is that has to be done beforehand. So that will require an... Yes, yes, this can, this has to be done beforehand. Well, well, to be absolutely fair, this still requires the posterer message to be defined. You know, so, and so that's why I have said that that performance here still depends. It depends on how you define that posterer message. So the challenge here is that now if I want to improve performance in this case, if I want to improve performance in this case, I will have to speed up the process of not speed up. I have to find an alternative to how to include the posterer function without having to block the loading of the JavaScript. So anyway, so this is the epic scorecard. As you can see, like I've been saying, as long as I fix the performance problems, having your own build, which is the second column there, having your own build is the best mechanism. And after that, it turns out that window.onerror is the next best mechanism, right? Other things have got somewhere or the other there's a red in the top three rows. So either have your own build at your end or use window.onerror, that's the best way. But performance still remains a problem. You have to figure out how to fix performance, right? Turns out it's gone out of the screen, but let's say this is a very simplified implementation of what error reception is actually doing right now, where what it does is that it creates an array first, right? And every time window.onerror gets called, it is dumping stuff into that array. Nothing is being posted yet, right? I'm not doing a network call, right? Nothing is being loaded. This thing is loaded in line into your page when you log in, you create, you sign up for error reception, you get this little snippet which is a greatly minified and sort of a zombie version of what is essentially just this, where the errors are taken and put into an array and then whenever the window load event happens, which is far later in your page load cycle, right? Usually your dollar dot ready and all of that happen at DOM loaded, DOM content loaded, which is far earlier. Window.onerror, window.onload happens far later. So far later in your code cycle, in your page load cycle, it will decide that it wants to add asynchronously the rest of the code that is going to process this array and then post that to the server, right? So essentially the performance impact of this has come down to zero because, well, there is whatever effort has to be taken to parse this code and that's about it, right? There's no network call at all. So your performance is super high. It's not going down at all, right? So there is no load time performance, like I said. This is even more important. There is no hard dependency on the system. In case the JavaScript loading fails for whatever reason, your system is not going to go down because I'm not touching with your code. Your errors are just going to lie in that array and I will never process that array, that's about it, right? It's, there's no hard dependency on my system at all. So that is what error section is. It's high performance by design. It's highly reliable by design. It catches all errors, catches more errors than anybody else can. But as a con, and I'm stating this explicitly, there are no stack traces. I'm saying yet because there are a couple of workarounds I'm still exploring those. Turns out IE is a little more helpful than other browsers are in this regard. So it's possible to pull out some amount of stack information from IE. I'm trying to explore that yet though, but there are no stack traces as of now. But you know, it is the fastest and the most reliable error catching system of all the two or three people that are there in the market who are doing this, right? A couple of other features is that you know, if you have ever worked with something like this, the number of errors that get posted to your server are tremendous, you will not believe it. I'll pull up some stats, I have it with me, right? So there's a lot of duplication of errors that you get. You will not believe it, I'm getting, on an average day, on an average, every average three seconds I get a new error, right? So you need duplication, you'll go bonkers if you have to parse so many errors in your head, right? All errors anyway get into the window.onEller handler, all sorts of errors, right? Right, so it does not matter, right? So because, oh, you're right, I know what you're talking about. So what I do at this point of time, after the array has loaded, sorry, the script has loaded, that's going to process the array, what I do is I change errors.push to mean something else, errors, I change errors from being an array to an object and then errors.push is now calling my internal script to upload the error directly. No, you, arrays don't have, arrays don't emit events, so can't listen to it. So I change errors to mean an object now and .push on that will cause the error to be posted on the server, right? Also, because everyone loves graphs, I have got a couple of metrics also on the error section UI that, you know, graph your progress in terms of, you know, how frequently the errors happen and don't. There are very few graphs yet, I plan to add more graphs because graphs are pretty and everyone loves graphs, right? It also weeds out errors that you don't care about, so, you know, errors in Google Analytics, they are far more frequent than you think they are. You know, errors in kiss metrics, errors in, you know, what have you are all weeded out because you don't care about them. Facebook, Twitter, you will not believe it, how many errors happen in those places, right? Some amount of marketing talks, they're already being used by several big internet brands, caught over a million errors already. It's only a month and a half old now, right? So if you think you don't have errors in your site, think again, these are guys who actually, these are internet brands, they care about their website, they care about their user experience and have caught more than a million errors in their sites, right? It has, you know, as much as much as I have tried to make reliability a non-issue, there is no problem anyway, it's never gone down since it has been launched, right? It's in closed beta, I plan to start charging for it, but I want to fix problems that you guys might be facing first. So it's in closed beta where I'm still, you know, sort of playing with the system. Sign up now, it's free for the mean while, for the mean time, you know, no obligations, come sign up, feel free. Just some quick screenshots. You know, things have been hidden away to not catch the, to not implicate anyone, but, you know, these are some sample UIs from the system. For those who are interested, this is built with Node and Mongo. That's it, errorception.com, the Twitter handle is errorception, feel free. Thanks a lot. Any questions? Yeah. Right. If what you're saying is right, then that's right, but I'm surprised that a tri block is going to add its own scope to it. I'm surprised, I wouldn't expect that. That's interesting, I did not know that myself. That's interesting. Secret sauce, right? If I tell you I'll have to kill you. No, I'm joking. It's just creating a hidden iframe. It's just creating a hidden iframe inside of it. It's posting, it's creating a form and then posting that to my server. The response of the form does not matter because you don't care to find out what happened to that post itself. Anything else? So please sign up. Let me know what you think. Feedback's always welcome. I hope to improve based on your feedback. You guys matter after all. Thanks a lot.