 Today, I want to share with you some of the good stuff we've been doing the last year on the Chrome DevTools team. And to speak for the team, we want to enable you and equip you with the tools to make you a productive developer. And that means powerful tooling to help you understand and improve your application. And we want that experience to be fun, too, and delightful. So today, we're going to cover a few things. Debugging your scripts, performance. We're going to look at auditing for excellence. We're also going to look at Node.js and Headless. A lot of good stuff in here. We're going to start off with debugging and some console kind of ergonomics. The console is part of our core experience. It's you spend a lot of time there, and so we enjoy investing in these workflows. So these are a few of the things that we noticed might need some sprucing up a little bit. So the console. I'm going to show you object previews and some new, improved autocomplete. Object previews, we're going to show a little video. This is an object. We're just opening it up. We're exploring it. This is a bunch of network requests, so it's an array of objects. And to hunt around and find that one object that I'm really looking for, it takes a bit of work, right? Same thing here. I'm just clicking around. We're just wondering maybe that we could provide this a little bit more proactively. And so we're going to switch over to what it looks like now. Take this object, open it up. Now when you click on Open it, so we get the previews of all the child objects immediately. So just instantly browse. You see all the sub properties, and you're in a good state of knowing immediately what's happening inside the data. All right. So that's object previews and just another view of that. In the left, we've got what it was, well, last week, to be honest. But in today's Chrome Canary, you'll see something a little bit more like this. So an array of arrays, and now you get to see exactly what is in there without having to click in all the time. This is good stuff. All right. Yeah, I like it. I like it. It's good. All right. Now I'm going to show you some autocomplete stuff. I'm going to come over here to my machine, take a little sip of water, and we're going to pop over into the console. All right. So we're here in the console, and I'll bring it in on a About Blank solid page. Now you're at the console, you like to type things, and we want to make sure that it's very fast for you to get completions so that you are just able to do the work that you want to do. I'm going to look at document and we'll look at document.head. And now I want to make sure that I want to look at the child nodes. So I'm going to switch over to child nodes. Now at this point, I've had these little autocompletion as I type all these things in, because we know exactly what document head is. But then we reach this point where we type in $0. And we've done this kind of array access. Now when we do $0, then all of a sudden the completions, they used to just completely fail. So I'm just happy to report that now you hit period, we're like, no problem, array access, you got the completions too. All right, now another one. Let's say that you have an object. Object looks maybe like this guy. So the properties have dashes. And so you might know where I'm going with this. If I switch this over, if we take this and now we run this in the console, then classes dot net, I can't because there's dashes, right? Not a problem. Square bracket notation, no big deal. And square brackets will just make sure that you have the key names right here too. So good stuff, but we can do a little bit better. You might be more on kind of the bleeding edge of things than the new side. So let's take this object here of classes, and we're going to make it a map, all right? So we'll do map equals new map. And we're going to use object.entries. I think this is ES7 even. So object.entries, new map. We create a map of the exact same information. Now we do map.get, open up the parent, and there are keys too. So making sure that you have all of your data right at your fingertips. All right. Now while we're in the console, sometimes we spend a little bit more time typing something out than we actually thought. We create not just a one-liner, and we're like, OK, well, there's some work to do. So we'll type out this function, and I call it log. And we'll just say args, and we'll open up our bracket. At this point, you're like, OK, well, I want to do a function. Do I hit Shift-Enter so that it doesn't evaluate? I don't want it to air. Don't worry about it anymore. Just hit Enter. We know that you're not done. It's good. We're just going to give you a new line. We're going to indent. You're in a good place. Now type in console.log, args, log that out. We hit Enter again. We know you're not done, but we close off that brace, and we're like, yeah, you're good. We'll fix the indentation. You hit Enter once more. Evaluate it. All right. That's good. So now we have a nice multi-line console that's aware of what's happening and is not going to evaluate something that's obviously incorrect. Now, this console, too, has some upgrades. Since text highlighting, this was not here a year ago. Also, other text editor features. For instance, I'm going to hit Command-D. I can do multiple selections and easily just change whatever I need right there inside the console. All right. So this is something cool stuff in the console. Thank you. Thank you. And now I'm going to switch gears a little bit and talk about asynchronous JavaScript, right? So do you guys write a lot of asynchronous JavaScript hands? Yeah. OK. Me, too. Do you guys use promises? Yes. Promises all the time. I mean, because what would it be like if we didn't have them? It's nice. But on the other hand, debugging promises? Not as much fun, really, is it? So I want to talk a little bit about async debugging. I'm going to show it with a little trio of examples. So we're going to come back over here. And I like the About Blank page. This is good. And I'm going to look at these snippets. OK. So here we got this snippet here. Zoom out, just a tad. Right. So this snippet, we start out with a job. Job runs, we call a process. In the process, we log out a little bit. We get some data. We print that, it's just logs. We finish up, and I got a debugger statement here so that I break, right? Synchronous execution flow, we're good. I'm going to run this. This is a snippet, so I can just click this button or hit Command Enter, and we're good. Well, we do have a reference error. So we're not perfectly good. But if I just put that in there, then I think we're good. OK. It was just a necessary adjustment. That's all, no big deal. All right. Now I'm paused here. Synchronous, right? So we look over the call stack. OK, call stack. We start off at anonymous at the instantiation of this job function, and the process gets called. We go in, we call finish, and we end up there. This should be straightforward, right? We're good, we're good. All right. Now that we have that out of the way, we're going to take it up a notch. So we're going to go from synchronous to async, but we're going to use async await. So just some small changes. So now we're going to call job. But we've also introduced a little sleep function, just delay a few milliseconds. So now inside of process, we'll log out, but we'll sleep. We'll go fetch a favicom. We'll print out that result. We'll sleep a little bit more, and we'll finish. OK? Now let's try that out. I'll just run that. And we pause. And OK. Now the difference here is that we have the same four call frames in the stack. And they're pointing at the same location. But in the middle of this, we have this asynchronous hop. Because going from job over to this call point in finish, we had an asynchronous operation. Inside process, all of these are asynchronous. Sleep, print, and sleep again. So this also works. It makes sense. But promises are how I think a few more of us these days are doing async work. So let's switch over to that. Same basic approach, but with promises this time. Inside job, we do a resolve, and then we go into here. And inside process, we have a promise to resolve. Sleep, fetch, get the result, sleep, finish. So we run that. Call stack, again, four call frames here, but two asynchronous hops in there. Now the important thing here is that we are able to show the history of why we got here. I know admittedly these are kind of toy examples. But in the real world, things get a bit more complex. So this is a slightly more real world stack. This is just the immediate stack of five synchronous call frames, and looks like something coming from jQuery. There's not a lot of context. But if we have a synchronous stacks enabled, and we have that feature behind this call stack, then it looks a little bit more like this, taller stack. But it gives us much more context. So even down at the bottom, I actually see that this came from an event handler into submit handler and submit data. So I know even at the top, it doesn't really communicate much, I know why this actually happened. This is increasingly the default look of stacks. In the browser, we have many short spurts of synchronous work held together by asynchronous operations, so set timeout, request the animation frame, promises, they sink away, plenty of other APIs. Not even to mention, React's new core algorithm, Fiber, this is designed to break up big chunks of work into small asynchronous chunks of work. The browser runtime is all about a synchrony. Just for a look at how this is in reality, this is a view of all of the asynchronous operations happening over the course of a quarter of a second. And we're taking all the asynchronous operations and rendering them as little arrows. I don't expect you to get a lot out of this, but just suffice it to say it's busy. There's a lot going on. But DevTools is able to track what is going on from one call frame, asynchronous hop over to the next. We think it's imperative for the tools to communicate why you arrived at a specific call frame. So to pull this off, we've had to do a lot of work under the hood. So we've instrumented all of the browser points where a synchrony emerges, the timers and the rafts and the promises. We worked closely with the V8 team, and we tracked all the dangling asynchronous execution hooks, and so that we know from the entirety of the program execution, back to the beginning of the page load. In order to pull this off and do this efficiently at scale, we needed to do some work because we were really driven to flip the switch on this feature, making it from something that was like an opt-in checkbox in the corner to something that everyone should just get for free all the time. So there's no reason to collect expensive snapshots from the VM, replay execution, or switching out into another tool. So what this really means is that stopping at any point of your program execution shows you the complete asynchronous history of how you got there. It's right there at your fingertips. But OK, sounds cool. What does this actually enable? I'm going to show you. So I have three new features I'm going to show to you. Continue to point, inline breakpoints, and step into async. Well, to do that, we're going to come back to these same demos. And all right, the synchronous one. Place a little breakpoint here on line 8. And we're just going to start the execution. We pause. I'm going to hit step over, because I just want to work my way down, the result, the print the results. OK, at this point, I can inspect the result. OK, great. Perfect. This is a common debugging scenario. But let's bring it over to the asynchronous world. So here, I'll place the breakpoint. I'll run pause. Now step over. And I get to step over. And this time, all of this work is asynchronous. But we're still able to use the nice convenience of step over. We've made that asynchronous debugging experience feel just like it was synchronous. Now, step over. So it works great with sync code and with away day sync. But we often do this a lot of times. Either you're stepping over, or you'll be like, you know what? I'm here on this log, here on this line, and I want to jump down to this. I'll just set a breakpoint right now. I'll play execution. But it happens a lot. So we wanted to make sure that there was a bit more of a convenient shortcut for this. So that's continued to point. So now if you're paused, you hold down the command key or the control key. And we're going to highlight and blue a few destinations inside this function that are available for you to just jump to. So when you click on one of these destinations, we're going to allow the execution to go forward. And then we're going to pause you right there. So I'll do that. I'll just click on this print. And we just let the execution go forward. Now I'm paused here. And of course, I could just inspect this response. It's just a little bit of a convenience. Cool, thanks. Now promises. OK, I'll pause here and step over. And step over again. What do you think? I mean, how do you feel about me stepping over at this point? It's like, yeah, what happens? Oh, what does? Yeah, we just jumped right to the end. We are now exiting with a return value of a promise. None of this work has even happened yet. And it's just like, eh, eh, ah. So we don't have the power of a sync of weight and the nice convenience to step over. That's not going to work for us. But we want to have this power. So we actually thought about this and figured, maybe there's another way that we can do this. And that led us to inline breakpoints. So now, because what I really want is I really just want to pause here. I want to see what this result is. So I want to pause here. So I'm just going to put my breakpoint on 14. We're going to highlight a few areas in that line where we can actually pause. And so that spot right there, I'll turn that on and flip that one off. And now, when I go forward, I start off there and I continue execution. And now I pause inside of that function. And now I can inspect the result like I want. It is good. And that works. But to be honest, if you're using promises as much as I am, you will be doing this all the time. So again, we're like, we could make a little more of a convenience function. We want to be able to pull this off with a single gesture. So I'll break. And now, this time, I'll hold down Control or Command. Again, now there's the blue destinations. But there's also these green destinations. The green means I'm going to step into this asynchronous function. So this time, I'm going to step into this result print result. And now I am paused inside of this asynchronous function and I can inspect the result just like that. So a single gesture, we're handling the step into async. All right, guys. So there's a lot of stuff in the asynchronous debugging. And we're really excited about it. I know that was a lot. I'm going to switch gears a little bit and talk about performance. OK? When we talk to our users and we ask questions like, all right, when you guys work on performance, what sort of panels do you use? What do you guys use? Do you use the Profiles panel? Timeline panel? Yeah, good. Network panel? Yeah. Obviously, there's a few things. And admittedly, the tools are a little distributed. But we're talking about browser performance here, where the completion of a JavaScript file downloading immediately leads to main thread work. And it's critical to see that connection. And when the JavaScript finishes executing, the browser takes a moment to calculate the layout and then it sends off pixels to the screen. This pipeline is very integrated, so we knew we needed a single integrated tool to visualize the entire picture. So that's led us to the Performance panel. All right, so I'm going to show you a little bit of the Performance panel in action. To do that, come back to my browser, clear those out. And we're just going to look at the home page of Nest just for fun. Bring open the DevTools. Now, this is the Performance panel. We have screenshots enabled. That seems good. And you know what? Capture a profile of the reload of the page, just the load. So I'll hit that one button. And what we're just going to do is capture the entire thing. And we'll stop it automatically when the page is done loading. All right, so I have some stuff on the screen, sure. Up in the top is a little overview and a film strip. And I can just drag my mouse along and see screenshots of the page as it loaded. Go from just the very top bar to a little bit more, these images, the text. But like I said, we want to see kind of how this worked. So I'll just zoom in on, well, everything up to, yeah, where things are looking good. And of course, the page load starts with some network requests. So I'm going to open up network, I'm going to zoom in. This is our HTML, some JavaScript, some style sheets, and so on. This JavaScript catches my eye, right? Nest web component bundle minjs. So the network connection goes out, waiting for the bytes. And then it starts downloading right here. So it's downloading, downloading, downloading. What happens when this file stops downloading? Well, it stops downloading right here. The main thread gets it right here. And then look at this, main thread. Evaluate script web components bundle. Yeah, that makes sense. OK, so there's a nice connection between the network and the main thread. So we see that work there. And we're just going to look to the right. OK, we parse some HTML. Some other things happen. Soon enough, the browser calculates what it's going to look like. The recalculate style, the layout, the paint. So I imagine somewhere around here, it's actually going to ship these pixels to the screen. So now you can open up the frames track. And in the frames track, we have just the screenshots of what was happening in the page just positioned exactly where it actually happened. So now I can see, well, this was when, yeah, we got the top bar with the little Nest logo at the top. That's something. I expected more, to be honest. We'll just scroll to the right a little bit. OK, yeah, yeah, yeah, there we go. So now we got these images and then the text. OK. The fact that the text took a little bit more time leads me to an idea. I bet that we're dealing with web fonts here. And we were waiting for the web fonts to download. I close up, well, open up Network and zoom out a little bit. And I bet you that web fonts just finished downloading. So if I zoom out and scroll over here, well, yeah. I spot them here. We have at least the WAF files of light and regular. And these are just completed. And once they completed, then the browser had a chance to recalculate the style, which it needs to do, and layout, and then we were able to ship that frame. So we have this nice integrated view from the beginnings of network requests to pixels on the screen. Now some of you who might have been using the Profiles panel to do JavaScript development, I just want to orient you with what we have available here. So if I collapse again the network, on the main thread, we're dealing with just over time what is happening. But oftentimes, you're looking for what consumed the most time at an aggregate view, right? So we'll zoom out and open up the bottom and the bottom-up view. The bottom-up view is just a summary of everything that took time sorted by its own self-time. So here we can see, well, there was some JavaScript on the page that took a little bit of time. The function E, yeah, not so. He was a little slow, I guess, and R also not so fast. So E and R, watch yourself. But the other important thing is that you see this in context. The browser was doing a bunch of other work, right? It was compiling scripts and laying things out and recalculating style. I know you get to understand that maybe E isn't so bad after all. Maybe I need to make sure that I need to recalculate style a little bit less or lay things out less or make those take less time. Pro tip, fewer DOM elements will help this one. Anyways, that was a good quick look at the performance panel. And we hope you dig it. Now, did that. The fastest code in the browser, we're talking about profilers, right? The fastest code is the code that never even runs. And better yet, the fastest code is the code that isn't even downloaded. So we're thinking about that and wondering what if we could provide you with a better view of what is actually being used in the page. And that's led us to the coverage profiler. I'm going to give you a short video of how this works. All right, so this is a little progressive web app that I made. And we're going to scroll down to the bottom, open up inside the drawers menu, the coverage panel. All right, at this point, we could just hit record and start collecting data. We're actually going to get instant data, especially from our CSS, because we know what's applying to the page right now. So here we actually see all of the selectors, in which selectors have already been matched to the page. The ones that haven't are in red. Now, select focus. There's no dropdown that's been focused. Let's try it. We're going to click in and hit Tab. And that green, sorry, that red rule went to green. So instant live updates here over in the coverage panel. Now JavaScript is also available now. This is the JavaScript file. Half of it is unused, which isn't great. We're going to look down, and there's a getTrips function. It's not executed. Feels like it should be. All right, well, we could just try it out. We're going to select a schedule. We'll go from San Francisco down here to Mountain View. And yeah, all right. Drop down the 50% unused to just 10% unused, which is good. Yeah, you're making good use of all the bytes. So the coverage profiler gives you this sort of insight. Armed with this data, you can go to town. The red unused bytes, they are not your friend. They are not your user's friend either. Don't send users red bytes. Nobody likes that. Check it out, the coverage profiler. But then again, thanks, thanks. Then again, sometimes all the bytes that you're running on the page are not necessarily yours. They're someone else's. They're third party code. So when you see a network waterfall of a big site, you're like, a lot of stuff going on. Like, who is this? And this is a challenge. You should know exactly what is happening on your site and who it is. So it's all about attribution. We thought about this, and we have a new feature to show you. You can try this out in Chrome Canary now. And it's some third party attribution. Now the command palette is a great place to turn this on. Command Shift P, type in third party, type in badges. Flip this on. And once you have this on, you go over to something like the network panel. Now next to the network requests, we're going to throw a little badge next to it. So next to the file name, we'll say something like DC. When you click on DC, you'll just be like, it's double click. And then you'll see a GA badge and be like, who is it? Google Analytics. And we're doing this for a lot of different third party code, ads, analytics, tracking, all sorts of stuff. This is available in other places too. So in the console, whether you have logs or errors and you're like, who is this coming from? Like VM script, I don't even know. That doesn't tell me much. We're going to tag it there too and put the little badges in. You can find out. Also over in the timeline, you can take that bottom up view and group it by product and see, okay, it looks like these guys are spending a lot of time on my main thread. It's cool. Yeah, I know. That is good. All right, so come back here. Yeah, that's good. We got a good amount of data in here. We're recognizing over 1400 different projects, products, and that means over 5,000 domains that we're keeping track of and showing. The data is just kind of built in there, but we have a little link report mismatch. If anything looks fishy to you, click it, report it to us. We want to make sure that the data is super useful to you and as accurate as we can be. All right, that brings us to authoring. We've covered debugging, performance insights, but there's some other key actions in your workflow, and we've added some features there. I think you're going to like them. Some good stuff. This one, cookie editing. You've been able to view cookies for a while, not been able to edit cookies. I know, I know, I know you were excited about this one. Yes, it's been a long time coming. We have cookie editing. We're good now, we're good. Okay. The next one is a good one, change tracking. So often you get into this case, right? You're editing CSS, you're just tweaking something. You make a bunch of changes. At this point, you've got it to where you want it to look like you kind of have lost track of all the changes that you've made. So down in the drawer, you can open up the changes view, and we're going to summarize. We're going to give you a diff of all of the changes that you've made, file by file. Yeah, thanks. This is an experiment as of today, but we'll be turning it on in Canary by default. Oh, Monday, Monday. Let's do that. Okay, good. All right, screenshots. Oh yeah, all right. Check this out. So we're looking at the Google Store, right? We want to take a screenshot of the page. Now we're going to use that command palette, right? Command Shift P, type in screenshot. Yeah, and we can just capture the screenshot, captures it a ping, we can open it up. Boom, easy. All right, this is good. It's been there for a little bit, but I can do better, I can do better. We're going to open up the device menu, and we can do the same thing there, but what I like to do is I like to turn on the device frame, get that nice art around it, then you capture a screenshot, and you got that good look. Looks good in presentations. Puppies and dogs are really impressed with that. Show them, they'll love it. And then there's one more that I like even more, the full size screenshot. We're going to get the full page, capture it, and now single ping, full resolution. Yeah, I'm right there with you. I'm right there with you. All right, there's one more. I had to sneak this in. I like to call it Breakpoint Resolving. You know how sometimes you put a breakpoint on a page, then you're going to change it around, and then all of a sudden it's not on the line that you meant for it to be on. It's like, that's kind of a pain. So I'll do that here. I'll place this breakpoint, put it on, I put the breakpoint on, construct select. Now I'm going in my editor, I'm moving things around, adding the log, come back, it's there, but when I refresh, it's in the first run function. It's a different thing. It's not where I left it. I'm like, all right. And now you'll see this in Canary, Beta, use refresh, we keep the position, we track where that was, and even if you change things around a little bit, we're going to make sure that the breakpoint stays on the same line. All right, yeah, it's good. Not going to work all the time if you completely change things. We're going to lose track, but we're going to do our best. All right. Now I wanted to share with you one of my favorite parts here. It's good. So about the past year and a half, personally, I've been working on the Lighthouse project. And Lighthouse is great. It gives you a lot of insight into what's happening and the sorts of improvements that you can make. It's available as a Chrome extension, a command line app, a node module, access it in a variety of ways. But we always knew that there was value in having it more deeply integrated into the development workflow. So I'm going to show you what this looks like with the DevTools integration. So we'll look at Chrome experiments as an example. Pop open the DevTools. And we're going to go over to the Audits panel. Audits panel been refreshed a little bit. We'll go down. We'll run an audit. We're just going to do the full audit of everything. At this point, we're emulating a Nexus 5x. We're throttling network. We're even throttling CPU to slow it down a little bit more like a phone. And we're looking at a lot of things. We're looking at the load performance and capturing a bunch of different metrics. Also looking at things like accessibility, how much of a progressive web app it is, and all that. Then we get the report right here in the DevTools. And so a few things going on with this site. Progressive web app side, not so good for them, but they're HTTPS, some good stuff. In the performance section, a filmstrip and some of the high quality metrics you might have heard about, first meaningful paint, first interactive, and how those line up against the screenshots. And then other things like image optimization. We're giving you an idea of how much value you're going to get out of all those recommendations. So you don't have to guess and be like, it really wasn't that impactful. Now, I'll show one more thing while I'm at it, though. Google, I just ran this on the Google home page. And the accessibility results were kind of interesting to me. So I opened that up. And because we're in DevTools, now when you hover over this node result, we're just going to highlight it up there. You can click through and just start inspecting it in the elements panel. So we'll do that again with a color contrast. So now a few things, looks like in the footer that don't hit the color contrast mark. And we see them highlighted, and we can see immediately the actual elements that we're talking about. So this nice integration between the deep insights of Lighthouse and the runtime of DevTools together brings a lot of power. I've saved a developer favorite till now. Headless browsers, they enable you to create automated tools that can run in a variety of different settings. And people do a lot of things with this. Text extraction, screenshots, and performance testing, security testing, unit testing. I mean, everyone here, raise your hand if you're using a headless browser of some sort in your workflow. Yes, of course, a lot of things. And we've seen this happening. And for the longest time, us on the Chrome team, we've been wanting to provide a contribution to that scenario, to those workflows. And so today, we're happy to officially announce the availability of Chrome Headless. Chrome Headless works great on all OSes, Linux, and Mac, and Windows. It's working great in all these places. Windows, Chrome 60, a little bit newer. The other ones are in great shape. And so this enables quite a bit, has a lot to come. Selenium support, for instance, is right on the way. We're really excited about this. Now, right now, things are a little bit low level. There'll be higher level APIs coming soon. There's a big, flourishing developer community coming around Chrome Headless right now. And it's primary API, which is the DevTools protocol. So I encourage you, if you're curious about this, check it out. There's a great blog post from Eric Bideman about Chrome Headless. And it's going to get you started with how things work and all sorts of tools available right now. All right, last thing, Node.js. So who here develops with Node? Yeah, yeah, yeah, me too. There's a lot going on. Last year, a year ago here, we announced that Node.js could be debugged and profiled with DevTools. Well, we announced a pull request that enabled it. The pull request is submitted. We're like, we'll announce that, because that's what we got. But soon enough, yes, the pull request got merged into Node.js, and it shipped. And so now we're in a great place. Because a lot of us developers, we spend time, both in the browser and in Node. And we want to make sure that the experience in debugging Node is good. And so I'm going to show you some improvements to the workflow that we've made. And to contrast it to what debugging Node was like two years ago is good. It's so good. All right, I'll show you a little bit of stuff here. OK, now I'm actually just going to be, this is how I debug Lighthouse when I'm working on it. And I'll bring back open this browser, this one. Yeah, great. Now I'll do something like this, this command, right? Node. And I'm going to be running this script. But anyways, the important thing is Inspect Break. This allows, this says that I'm going to start inspection. And I want to put a break point on the very beginning, OK? Otherwise, I'm just running Lighthouse. So the first thing I hit Enter, this URL pops out. Now if you've done this before, you've seen this URL and you're like, OK, well, I guess I'll copy and paste it. And you can. You certainly can, but there are better ways. So one better way is we can type in About Inspect, and we see this panel. And the best one here that I recommend you click in instead of this shiny looking guy is the Dedicated DevTools for Node. Now this window is going to be dedicated to Just Node. And so you can see immediately we broke on the program execution. And I, again, have all of the power that I need. I can continue, step in, and just go crazy. So that's good, but we can do a little bit better. All right. Now this time, I'm thinking it would be good if I didn't have to remember that URL about Inspect every single time. And this functionality was available to me in a bit more of an immediate place where I spend a lot of my time. So now I'm going to open up DevTools. And when I run this command again, I don't have you spotted this. But right up next to the Inspect element icon, there's a new one, a little green node icon. It's snuck in there, right there. We detected that there's a debuggable node. And we're like, you know what? If you want to debug that, we got you right here. So you can just come over and click that. We're going to pop open that same dedicated DevTools for node window. The cool thing about this dedicated window, I love this, is, OK, this works. And I'm debugging. And I do what I need. And they're like, OK, found a bug. And so now I'm going to need to fix a bug. And da-da-da-da, I'm changing things. I need to run it again. And so I'll run it again. But because we have that dedicated window, it's like, hey, I'm right here. I got you. I'll pop right back open. So it's always there and connecting. So even if you have to restart node, you have that one single window. And that's going to take care of you the entire time. All right. So we're going to have to stop that. There we go. OK. You guys have made it. We've covered a lot. We've covered a bunch of new features and DevTools from that great new experience with object previews, the autocomplete in the console, all the asynchronous debugging goodies, performance panel, coverage, third-party attribution, Chrome headless node, all sorts of good stuff. If you like this kind of a thing, follow us on Twitter. Great docs, updated regularly. And if ever you have bugs, we definitely want to know. If you have feature requests, we also definitely want to know any feedback. Just tell us about your workflow and the sorts of things that work for you. new.crbug.com is where you can find us, reach us. For us a message, we'd love to hear from you. Anyways, that's it for me. Thank you guys very much. Appreciate it.