Hello. So welcome to the building Blazor applications on a Mac. Definitely check out the Weather app that Scott Hunter just mentioned. It's really cool, but we have some kind of simpler stuff to get started to talk more about what Blazor is and take you through an intro app. How to get your feet wet and then we'll move to a more realistic app and make some changes there as well. Yeah. Oh, and I'm Kendra Havens. I'm a Program Manager on .NET and Visual Studio and. I'm Dan Roth. I'm a Program Manager on the ASP.NET team. Cool. Okay. So Dan, what is Blazor? What is Blazor? There's so much talk about it. I know. It's so much excitement. So Blazor is a modern web framework for building client-side web apps using C-Sharp and .NET instead of JavaScript. It's cross-platform, it's open-source, and it's based only on open web standards. Ooh. Now, we've had ways to build web apps with .NET for a long time. Traditional .NET web app, you take your .NET code and you put it on the server. Then the browser sends requests to your server and it responds with dynamically generated HTML or JSON. That's pretty typical .NET web application. But if you wanted to do anything that ran in the browser, well, that meant you had to use some JavaScripts, like using whatever the popular JavaScript framework of the day is. That's cool. I mean, JavaScript is great. I mean- Yeah. It's great. You have to switch contexts though and that can slow you down. So if I can stay in .NET code. That's convenient if we can use that same tool belt and the same language, the same frameworks, the same tools, same build system across your entire application. That's what Blazor is all about. It's enabling you to build full stack web apps using .NET and C-Sharp. That's what we've been working on. Sweet. Okay. So Blazor, you build client-side web apps using just .NET and C-Sharp code. It also comes with a component model. So you can build reusable web UI components. You can package them up as Nougat packages and libraries and share them with your friends. It also enables you to use the same code on both sides of the wire. If you have some common logic like validation logic, or data models that you want to use both on the client and on the server, you can do that with Blazor. It's full stack web development with .NET. At the same time, if you have existing JavaScript code or you want- Sorry. So we're sharing .NET code. So even working in F-Sharp or Visual Basic if I have libraries that I want to call from Blazor. Yeah. You can do that.  Absolutely. Also, if you have JavaScript, you can still use that as well. You can call into existing JavaScript libraries from your Blazor code and even call back from the JavaScript code back into .NET through JavaScript interop. You can use that to also leverage all of the native functionality of the browser. Okay. So if I'm slowly migrating my app to Blazor, I try and it out in some section. I can still use JavaScript at the same time. Don't have to throw your JavaScript away. You can just reuse it in your existing Blazor application. How does that work? How is that possible? I know. It seems like magic. Well, there's two ways that Blazor apps function. The first mode we call Blazor server. The way Blazor server works is that we set up a real-time connection with the browser. We use SignalR to do that. It's basically a WebSocket connection. Brady has a talk on all on SignalR later today. All about SignalR later today. Definitely check out that then. Once we've got that real-time connection with the browser, we run your Blazor UI components on the server. Any UI events that happen in the browser, we send them over to the server, dispatch them to your components. The components run, they render, and then Blazor very cleverly figures out just the parts of your UI that have changed and serializes that diff back down to the browser to then be rendered and updated. So it's a thin client model. You're still running your UI components on the server, but you get that rich interactive feel that you would expect from a JavaScript-based single-page application. Okay. In server, all of my C-Sharp is compiling on the server still, not at all inside the browser. All the compilation happens at build time, but your build code is going to be running on the server on .NET Core. It's not actually going to execute in the browser. Right. But you still get the rich interactivity of being able to handle all the UI events and update the DOM seamlessly without having to do a full browser refresh. But I have heard about things that would have allowed you to do that. Yes. Not compiling, but executing. Executing, that's right. In the browser. With Blazor WebAssembly. Blazor WebAssembly. What we do is we can download with your app a full .NET runtime that's implemented in WebAssembly. Now, WebAssembly is an open web standard. It's basically a byte code for the web. If you can compile your code to WebAssembly, that code can now run in any browser on any platform at near native speeds. Native as in like browser native. Well, pretty close to the wire. Like it's almost like an assembly language that's been standardized for the web. So it's pretty fast. Super fast. It is fast. So we built a .NET runtime in WebAssembly that you can bring with your app. It's small and compact. Then you just download normal .NET assemblies into the browser and execute them using that runtime. Okay. The same UI components, the Blazor components, in this case they're running in the browser itself. They handle UI events, they calculate the diff about what needs to be updated, but that's all happening in process in the browser client side. So I see our little slide here says Preview. That's right. So Blazor WebAssembly is in Preview. Blazor WebAssembly is in Preview. Blazor Server however, is ready to go for production. Go ahead and click to the next slide. Yeah. When do I want to use which one here? Server versus WebAssembly. So Blazor Server shipped with .NET Core 3.0. Okay. LTS. Also shipped with 3.1 LTS. LTS is a long-term support release. So Blazor Server is ready for production use today. You can put it in your websites, put it out in production, it's fully supported with a long-term support lifecycle. Blazor WebAssembly still in Preview, isn't quite done yet, but we're working real hard on it. We expect to have that finished up in just a few months later this year. How do you pick between the two? Well, there's some trade-offs with Blazor Server. The benefits there is, well, first of all, it's production ready. Yeah. You can actually use it right now. Your code is also running on a full .NET Core runtime. So it's super fast on the server, and it treats the client as basically a thin client. It has less demands on what the browser or the client device needs to do. So for example, if you want to support older browsers like IE11, you can do that with a Blazor Server application because there's no requirement to support WebAssembly. Blazor WebAssembly on the other hand, gives you that option of pushing an offloading load from your server onto the client because it's a true client-side application. It can support things like offline scenarios. That's still in preview, so it's not ready for use today, but it will open up some really cool scenarios in the future. Oh my gosh. I'm so pumped. Now, regardless of which model you pick though, don't get too hung up on picking one versus the other because the component model is the same. You write your components once, and then you can use them in either hosting model. So you could start out, for example, with a Blazor Server app. If you want to switch to Blazor WebAssembly in the future, that's pretty trivial to do. Maybe when it goes to production, we can switch our components over. If that's what you wanted it? You can use it everywhere. Oh my gosh. I'm so pumped. Shall we get started? Let's get started. Okay. Let's do some Blazor. I know you can get started by going to blazor.net, so we have a really simple URL to remember, just blazor.net and it'll take you to our main Blazor landing page and we can go to this get started documentation. This will walk you through everything that you need to do to get started with Blazor, all the stuff you need to install. If you're on a Mac, like I see that you are, there's a tab there for Visual Studio for Mac that has all the steps for getting Visual Studio for Mac set up with Blazor. So it's already installed.net core 3.1, and actually, since you're here, I won't read this. I'll just launch Visual Studio and you can walk me through it. Since you've already done it, you've already installed Visual Studio for Mac. You have.net core 3.1 on your machine, which comes with Visual Studio for Mac. So you're all ready to actually go with Blazor development right now. All right. So since I got 3.1 installed, I already have a Blazor server template, and if I didn't see that there, I could actually just find that in just the regular app templates, Blazor server app. Under.net core, that's right. Cool. Okay. See, it's already targeting 3.1. We have a little authentication tab. So in the latest preview of Visual Studio for Mac, they now have support for the authentication options for Blazor server. So you can create Blazor server apps that support Auth using ASP.net core identity. Cool. All right. I'll go ahead and initialize one. I called it Blazor app 7. That's a wonderful name for a Blazor application. Seven is just my favorite number. It has nothing to do with the precise number of times we practice this. Nothing at all. Just lucky. It's a lucky number. It is. So this will create you a new Blazor server application. It's all ready to go. A Blazor server app is just an ASP.net core application with a couple of additional things wired up to support Blazor server. Why don't we go ahead and just run it so we can see what the application looks like. Yeah. Sounds good. So the Visual Studio can now build your application, get it running, you can debug, you have full support for Blazor development within Visual Studio for Mac. Once this gets building and actually running, we should see a sort of standard single-page app style UI. Give it a second. It's coming. Slowly. I believe. My Visual Studio might have fallen asleep as we were talking. Cool. We'll blame that on the browser. Yeah. So you can tab around, you have different tabs for different pages. This is all being handled through client-side routing. On the home page, you have some simple static markup, nothing too fancy going on there. On the counter page though, you have a button that you can click, and as you click, the count goes up. There's no page refresh happening here. The DOM is just getting fluidly updated. Normally, that would require some JavaScript to do, but that's all happening using C-Sharpen.net. Neat. Not to see how that's working. Yeah, and then this fetch data page is basically a dynamically generated table of weather forecast data. Ooh. So let's take a look at that counter page. So that's implemented in this counter.razor file. And you can see it's pretty simple. It's mostly just a standard HTML markup. At the top, it says that this is a routable component. So app page says that we would browse to slash counter. We should end up here. So if you go to the browser, you should see in the URL at the counter tab. Yep, slash counter. That's where we're at. And then you have some normal HTML markup. We've got a button that we can click, and there's that on click attribute. Normally, that standard HTML on click attribute would have some JavaScript in it, but here we're using a razor syntax, a little at sign to say, no, no, no. I would like to use some C-Sharpen. We've got C-Sharpen code here. Go down to that. And it's pointing to your C-Sharpen method increment count. That's incrementing the current count field, which then gets re-rendered on the page. Now to show that that really is running C-Sharpen code when every time we click that button, set that break point. Let's see if we can hit a break point. So that was on my counter page. And there we go. Got it. We're in our C-Sharpen method. Neat. Writing client-side web UI using Blazor. So let's see. What else is going on here? Well, the nice thing about these components, like all these .razor files, they get turned into normal .NET classes as part of the build. And now you can reuse them. Like if you wanted to have another counter component someplace in your app, you can do that by just adding that component wherever you'd like it to be. So for example, if we wanted to add a counter component to the home page, like let's say we wanted two counters. One on the counter tab, one on the home page. If you go back to the index.razor file, that's the home page for the application. Got it. OK, so here it just has markup. There's nothing really interesting going on. But let's start typing bracket counter, angle bracket counter on here. So yeah. And you can see you get awesome IntelliSense and Visual Studio for Mac. And now it's showing up purple. That's signaling to you that this is a component. Yeah. You know what, a blazer component. If we rerun the application on the home page now. Wait, is that purple or brown? I think it's purple. I might be a little bit colorblind. Purpley. .NET purple. Every once in a while, you learn new things about how you perceive the world. Yeah, maybe my. OK, so I added the counter component, and I'm going to go ahead and F5 again. Yeah. And so now when I go to the index, yeah, it has a completely new component apart of it. So it didn't need to copy in the counter code or anything. It's just inheriting that component. A reusable chunk of UI. You can click on it. It works just like the other one did. And if you go to the other counter page, you see it has an independent count that's separate from the counter on the home page. You can also pass data into components. Like components can have parameters to define a parameter on a component. Let's go to counter and make it configurable, parameterized how much it counts with each click. So to do that, you just add a property. And the property can be made a component parameter by attributing it with the parameter attribute. Gotcha. I have a little tip I want to show in here. Visual Studio for Mac does indeed have snippet. So if I just type prop and tab tab, it automatically loads in my property. Sweet. OK. Save some typing. What were you saying? So let's make it an int. Yeah, and let's call it increment amount, I think would be good. And let's default the value of that property to just one. Yeah, give it the parameter attribute, too. That's cool. So that's what's really going to make this a parameter for the component that we can pass in. So by default, it'll be one. And now in the increment count method, instead of incrementing by one each time, doing a standard increment, we'll increment by increment amount. So current count plus increment amount. Perfect. You get lovely IntelliSense for your C-sharp code inside your razor files. I like that, getting over my local variables. Now go back to the index page and let's use that parameter. Let's pass in an argument. So if we go to index, now just add some space after the R and then you can see increment amount shows up. Wow. The way you set parameters in Blazor is just using standard attribute syntax. And now the counter on the home page should increment by 10, whereas the one on the counter tab should just default to the standard increment amount of one. I just kind of chose 10. I hope that's a good number. That is a great number. 10 times better than it was before. Good.  And we should see. OK, let's check this. Yeah, so now it's incrementing by increments of 10, whereas the counter on the counter tab should still be doing by one. Because we didn't pass any parameter value. Yeah, so it's still going by one. Now how is this working? Like we said, this was all based on that magic real-time pipe. We can actually see that happening if you inspect the browser depth tools. Let's look at the network. And if you do a full reload, so we can see all the stuff that's being downloaded, like holding the shift key or something. There we go. So you can see that this app's pretty thin. It's not downloading very much stuff. It's just a little over 400 kilobytes of download. And all the magic is really happening in that first request, that underscore blazer web socket request. Yeah, you see, when you look at the messages, you can see there's all these binary messages flying on that web socket connection. Yeah, it's updating as they speak. If you clear it, let's clear them all out. And then go click on the button on the, sorry, yeah. Here, I'll clear again and use the keyboard shortcut. There's lots of buttons to click on. Try the, yeah, that'll work. And then click clear and click on click me. Click me button, that's insane. So see, every time you click, every time you click, we send the UI event to the server, your counter component gets the message, it re-renders itself and then the DOM updates gets sent back to the client. That's what's happening here. That's how this app is working. This is a blazer server-based app. Cool, so that's counter. Now, I know, if you go back to the code real quick on the counter.razor file, some people really, like you noticed that there was that at code block at the bottom, yeah, right there. So at code, that's basically a chunk of code that's gonna get added to the generated class for this counter.razor file.  And some people really like that that code lives in the same file, cause all your UI codes in one place. Other people would prefer to have that in like a normal C-sharp file, like in a code behind file. Which is totally cool, you can do that in blazer as well. What you can do is add a, let's add a C-sharp file to the pages directory. Let's call it counter.razor.cs. That's sort of the standard naming convention for a code behind file. Look good? Yeah, that looks good. What? It automatically put it underneath my counter got razor. I put a whole bunch of licensing information. Sorry, I was messing with my header demo for later today for the productivity talk. I'd elit that. We won't add it. You don't get to see this yet. You have to wait till this afternoon and we'll talk about how to put headers at the top of new classes. And we don't automatically license like all your C-sharp files that get added. No, no, no. We just did it for math. That would be bananas. I specifically chose the MIT license. Cool. Well, we have a counter class now. Now this matches the name of the class that will be generated from counter.razor. So let's make it a partial class. So can this? Oh, okay. Yeah, grab that code. Go ahead and grab that. That's fine. Go ahead and copy that out of there. And we're going to move it into here. We don't need the constructor so we can just copy over the constructor. But make the class a partial class so it will be combined with the generated class for the component. And then you probably need to resolve some namespaces. Right. And I can do that with alt enter. So that opens up the little light bulb that I get so I can automatically add usings. Beautiful. Love it. I guess all the normal C-sharp productivity enhancements and features now are available to you in this C-sharp file. Yeah, and I'm getting another little suggestion. So this actually might have annoyed some people when I did this originally. I didn't use a compound assignment. It was all part of my plan. And BS for math just takes care of that. Yeah, so BS for math gave me the suggestion that I can simplify that. That does look better. Yeah, cool. So this should be the same as what you had before. Like there's no difference in the code. It's just that we've refactored the code. Should I run it to prove it? Yeah, go ahead and run it to make sure it's still working. That's pretty nice, like the C-sharp. So I got a lot of nice features and languages. Oh my gosh. All of the little things. That's what I work on. That's nice C-sharp little things. Beautiful. Refactorings, cofixes, productivity. That looks like it was before. So you should still have like increment by 10. All that stuff, yeah. Increments by 10, looks good. What other C-sharp stuff can you do in VS for Mac? Does it support all the Visual Studio? It does. So right now we actually share the same editor. So basically everything that we've added actually latest in like Visual Studio and Windows 16.5 Preview 2, I believe is what we're on. All of those are actually already piped in to Visual Studio for Mac. Nice. I can demo those later today with Mikayla. There's a whole talk on that stuff. Yeah, there's like a shared editor. So it's all piped in. Okay. So like adding an overload? Like is that? Oh, yeah. So if I do Alt-Enter, our keyboard shortcut to open the little tooltips, I can- Override, I'm not saying. Override, sorry. I'm always getting my C-sharp terminology messed up. You can do something like initialize. The thing about this is you can see all of the component lifecycle events in this UI. Like the uninitialize on parameter set. These are all standard events in the lifecycle of a component. So yeah, if you wanted to like run some code when this counter component is first, after it's initialized, you would override oninitialize or oninitialize async if you have some async logic. I think the fetch data component actually does that. So this is the component that was generating that dynamic table of weather forecast data. And if you look at the bottom, all the way at the bottom, there's a, yeah, there. So you see oninitialize async. There's the example. I was distracted by how cool it was to have a C-sharp for each loop printing out your table. Razor. It's super cool. Okay. Sorry, continue. That's good. So yeah, there's oninitialize async. That's, when this component gets initialized, you see it's using that weather forecast service to get all the weather forecast data. Where's that forecast service coming from? If you scroll all the way back up to the top, there's this atinject directive. And what atinject is doing is it is a way to do dependency injection into your components. You can get services that you've configured. Here we have a weather forecast service that we're injecting into this particular component.  It's mostly standard HTML markup, but intermingled with C-sharp logic. It's statement, yeah. If statements for each loops, like we're just looping over each weather forecast instance to generate the rows in that table. That's how that weather forecast table is being generated. Super cool. So we started sort of to get more into realistic scenarios. This was just the file new template. This is the basic stuff. Is there like a level two app that we can use and show off? Sure. So I've been working on a recipe app in Blazer. To like, you know, manage a list of recipes and do recipe ratings and those types of things. Why don't you pull that up? I think I found it. That's my repo. If you guys want to download and see my code. Like. Dan Ross 27. Okay, got it. Best for you recipe. Best for you recipes. All right. So let's see if I can open this up. Now I usually, I've been developing this on Windows actually on Visual Studio, but it opens great on Visual Studio for Mac, builds, runs, debugs, all those things just work as expected. Once this opens up, why don't we just go ahead and run it first just to see what the app is capable of? I'm going to wait till I load my workspace document. Perfect. And maybe restore my new get packages. That's probably important. I always kind of want to do that. Restore your new get packages before you build and run. You get that kids. It's okay. It's lifestyle choice. Okay. So I'll try to. It's saving. Might have gotten a weird state. While we're waiting for that, we can go ahead and look at the homepage at least. Let's open index.razor. So we can see a little bit what the, when we see the app, we'll have an idea of what the code looks like. This is the homepage for the application. And you can see at the top, it's mostly just a, there's a search box. And then a little bit of an if, if else then to see if the recipes have loaded. And once they've loaded, it's just generating an unordered list with the list item for each recipe that it loads from a recipe store. And again, we're using dependency injection to get a recipe store service and to initialize the list of recipes. So that's all that's doing. That search box at the top is a custom component for handling the searches. Why don't you scroll back up to the top and then we can look at that real quick. Yeah. So you can see that on the search box, we're passing in normal HTML attributes to like specify a placeholder. But we're also able to specify a delegate for when a search has occurred so that we can hook into that and actually then run the query against our store. So it looks like the app's now up and running. Yeah. So here's that homepage that actually rendered. Oh my gosh, beautiful. Nice, nice images. You must have got some help. You can- A little bit. A little bit, yeah. You need a beautiful app. Design is not my forte. You can click on recipes. You can see details about the recipes. Yeah, I can. Some basic functionality. We've got a little search bar. Search for chocolate stuff. Yeah, now notice that as you type, the search is updating. Like you're not hitting enter as you're typing. It's just looking at the current state of the search query and running a search. But it's not doing it on every single keystroke. It's like a little, there's a little pause that it waits to see if you're done typing and then it does a search. And that's nice because it's throttling all the searches to your database. You're not just hammering the database with every single keystroke. So it's interesting to see how that's implemented in Blazor. If we look at the search box component, that's where all that logic is encapsulated. So search box dot razor up there at the top. Now, this is that component just implements the search text box.  So mostly you can see that this is just an input. Like scroll scroll to see the markup at the top. It's an input. And that- That's not about timers. Yeah, and it's bringing in the timer's namespace. The attributes, attributes attribute there, what that's doing is allowing you to grab any additional attributes that are passed on the component and sort of splatting them wherever you want them to be. That's how that placeholder attribute is getting onto the input. And then that at bind is binding the value of the input to the search query property. So as you type, Blazor will see that the text has changed and then set that text onto the search query property, which I think you have below. Yeah, right there. And it's actually even specified as a parameter. So if you wanna pass it in, you can do that. And we know that it's gonna do that on every single keystroke because after at bind, back at the top at the end of the input, all the way to the end, see that at bind colon event, that's specifying which event we want to use for the bind. Like by default, it will do it on change. Here we're saying, no, no, no, I want it on every single input. Every time you type, please update the value of the search query property. And then now let's look at search query because that's where the little bit of cleverness is happening. Search query, when it's set, like when the value gets bound, it just starts a normal.net timer. And this is just like you saw up above, system timers or whatever the namespace is. It's a normal.net timer from the base class library where it will stop the timer if it's already been started and start a new one. And if that timer completes, then you know there was a pause without any keystrokes hit. And that's when it'll actually call back into the search query changed event callback that was passed in. So that's- You've got that debounce parameter there that 300 milliseconds? That's the amount of time we wanna wait. Then you can see in an onInitialize, there's that component lifecycle event again. That's where we're newing up the timer, setting up the debounce timeframe and wiring up the event handler for when the timer actually completes.  That's debouncing logic in, you know, 50 some odd lines of code all done in C sharp. No JavaScript required. That's great. So should we go back to slides? Are we short on time? I think. I forgot what time we were supposed to- We wanna make one change. Oh, we got five minutes. Oh, go ahead. Let's make an edit to this app. Let's make a change to this app. Okay. So if you go back to the app- What do we wanna do? Yeah. Let's go back to the app and look at the- Yeah, reload. Oh, right. I stopped the button. So click on the recipe that brings you to a recipe details page. Okay. And most of that's just markup and there's even a form where you can do star ratings. But there's also these tags and currently if you click on a tag, they are links, but they don't go anywhere. Oh. Like they don't do anything. So what we wanna do, it is going to a new URL. It's going to slash tag and then the name of the tag that you clicked on. Let's wire that up so that we actually end up on the search page but with the correct list of recipes. Okay. So go back to index.razor. What we wanna do is grab that value out of the URI. So in order to do that, we're gonna add another route. So add another app page directive and make it slash tag and then slash, now that's in curly braces because this is the value we wanna grab out and we'll call the value that we're gonna grab out tag. Okay. Now to get that value, we're gonna bind it as a parameter on this component. So add a new parameter. Remember we added a property before to create a parameter. Do in the code block, let's create a new property. So prop, tab, tab. In the code block. Oh, regular recipes. All right. Anywhere, it doesn't matter where. Prop, tab, thank you. Love it. Let's make a tag string and call it tag. Tag. Oops. Tab again. There you go. Okay. So and then put the parameter attribute on it. So now what the Blazor will do is it will take the value from the route and set it on that property. So now we can just pass it in to the. Can you tap the get recipes? Yeah. All right. If it's not specified yet then we probably just will pass empty. That will give us all the recipes when the tag is initialized. One more thing is up above in the search box. Let's make sure we populate the search box with the tag if there's one there. So set the search query parameter. Did I? Get a little space in there. There you go. There you go. There you go. You get a lovely IntelliSense. I wanted it to just fill all that out for me. Do at sign and tag. Oh, so we're actually getting into the C sharp property with that at sign. Okay, cool. That's all you need to do. So now it should populate the tag. So go ahead and run it. Okay. Restart it. And that should populate the search box with the tag as you click on tags. That will filter the search. So just that tag. Whenever you click on a tag leak on the page and it should be just that easy. Okay, so click on a recipe. Let's go down to the tags. Let's, I don't know, fruit. There's only one fruit. Got it. But that works and it populated the search box. It populated. You just added a feature to my app. Thank you so much. Hooray, you're welcome. Now let's hop back to slides real quick. Sure. So that was getting started with Blazer and some Blazer in action. We know the number one question on a lot of people's minds if we have time for Q&A and stuff is what is next for Blazer WebAssembly? When we get it, when will it be out of preview? Yeah, so this was all Blazer server work that we were doing with Visual Studio for Mac. Visual Studio for Mac fully supports Blazer server, which is great. Blazer WebAssembly is still in preview. It hasn't shipped yet. It is the focus of the Blazer team right now and we are planning to release it in May of this year as a supported release. And that will include full support in Visual Studio for Mac. The initial release of Blazer WebAssembly will be based on .NET Core 3.1. In fact, we plan to add the template in an update to the .NET Core 3.1 SDK. It will be a current release, not an LTS release. So it's not gonna inherit the LTS status of the rest of .NET Core 3.1. It is the first release of Blazer WebAssembly. We wanna give it a little bake time before we bless it as an LTS release. To try and make that clear, we're gonna update the versions of the packages to be 3.2. We've actually already started doing that. So the latest preview is our version does 3.2. After May, Blazer WebAssembly will become a part of .NET 5 and will then be just part of the normal .NET update release cycle. So I just need to remember to keep clicking yes on that update prompt. Keep, keep, keep updating and look in May for the release version of Blazer WebAssembly. Got it. So in summary, we talked a little bit about being productive in Blazer on VS for Mac. Blazer server is what we showed today. It is in production. You can go and use it with .NET Core 3.1 and get excited for May, 2020. For Blazer WebAssembly. For Blazer WebAssembly. So Q&A time? Questions? Are there questions? That's exactly it. I'm gonna actually start with a statement. Somebody said, I want Dan Roth's Visor Studio T-shirt. You can be an Uber geek too. I know, but you know what? We have some exciting t-shirts for this event and we'll be giving them out as part of our party. So make sure you stick around until the end of the day. So not just that, but more. And we actually have some questions as well. So the first one is, hey, VS for Mac, is there any way I can explore on Blazer WebAssembly in Visor Studio Mac? That we were just talking about that. You can actually open a Blazer WebAssembly app in VS for Mac today. You'll need to use the AceNet Core hosted version of the template. The standalone version of the Blazer WebAssembly template isn't working just yet in VS for Mac, but it will by the time we ship Blazer WebAssembly in the May timeframe. You don't have the ability to create Blazer WebAssembly apps from VS for Mac just yet, but that is coming as well. So you can create apps from the command line as long as they're hosted in an AceNet Core app and run and develop your components and all that. The rest of the functionality will be coming later as we get closer to the May release. That's great. Well, there you have it. And next one is, let me just close this one down. Is there a performance benefit using Blazer Server over Blazer WebAssembly? Yeah, so Blazer Server runs on a full .NET Core runtime. Your components are running on the server. So you get all the performance benefits of .NET Core, which is honestly one of the fastest stacks on the planet. It really treats the client machine also as a thin client. So it has very little requirements on the client side of the application. Blazer WebAssembly runs on an IL interpreter-based runtime today. So if you have components that are doing really computationally intensive stuff, it can drag a little bit when you're running that type of code in the browser. You might want to offload that to a web API, somehow onto your server so you're running on the full .NET Core runtime. Perfect. I think we have time for just one more question. So the question is, is there a benefit using Blazer over Angular or React or some other spa? Well, yeah, I mean, because you get to use C-Sharp. Yeah, no context with scene. You get all that syntactic goodness. All the productivity features in Visual Studio. Yeah, it's a full stack solution for web app development with .NET and C-Sharp. I think also there's just a lot of really nice simplicity that comes from the Blazer programming model and tooling. Like it's really easy to get started, file a new project, and you're up and running in less than five minutes. So that can be really nice. That said, if you love Angular and React and View and you want to continue to use those for your front-end development, you can absolutely still do that and still use .NET Core for your back-end APIs, GRPC services, signal or hubs, and so forth. Great. Well, thank you very much for your time. It was fantastic to hear about all the Blazer coolness out there. And I'm looking forward to the 2020 build announcements that we're probably going to have.


Hello, everybody. I hold now a talk about putting support for these nice little gadgets into build service. My name is Martin Moring, and I'm one of the external contributors to the OpenSUSE build service. Yeah, first, the barriers how to join such a project. I'm from a small company that had worked with embedded over years, and I know the Nuremberg R&D people from Suze for a long time, and it was, I think, two years ago that they decided we want to design a new build service system. And that was my time also to say, okay, we had also build services, a build service in place for embedded applications, and let's join forces and also redesign that and put it in. So the barrier was that I had to do with lots of experienced people that had released lots of distributions over the years, so it was not a very community approach in that sense that there were entry barriers from your know-how to solve, so to say. Second thing was that it started with a company open source project that is something different than a community-driven open source project, and yeah, the third thing was we both wanted to re-engineer existing things, improve it, and put together a new generation of that kind of system that had to solve new requirements. Okay, and yeah, the answer, how did I join then, was a pragmatic approach, nevertheless, as in very many other projects in open source space, fill a gap and take some work that is not done and start with that and gain credibility so that there is trust what you can achieve, so you can let you know what the others do and what they are, let's say, what they can achieve, get a feeling and so that you get a team. The result is that I'm now the package maintainer also for the development package of Ops for over a year, and we successfully put in all kinds of cross-bill support into the project, so it was a successful merger. Okay, so much for the social aspect of team building. Okay, let's start. What kind of cross-development systems can we have or do exist? There is, I have also here examples for that so that you know what I mean, not only by theory and category, but also by some example. We started with experimenting with what I call type one cross-built environment, that means you put together something like busy box or build route, put it all in one, that was also our first experiment that we did and build your complete system in one bunch. Okay, that is only the first approach, we tried it, but I will explain why that is not a good solution later. The next variant, and that was already successful and used in the field, that was to implement a tool chain and modified packages in the system and put the build environment for this into the capabilities of the build service, build environment. That was the first practical approach where we had a real result with a real distro build in the end, that is what I call type two. I have two examples here, ST Linux and open embedded. They modify packages, they write own, build descriptions for every package. So this was first approach to get something working fast, but it has usually the disadvantage of much work. I mean, that is acceptable for 400 packages, that is the usual embedded distribution, but if you want to achieve something like open Zusa factory with 4,000 packages, you either need many resources, you have to keep in mind you need to fiddle around at least one day per package and multiplied by 4,000, you can just easily cocculate what that means. So that was no approach for getting open Zusa and existing systems in. Then we had also said we want to have some kind of type three that is use the original source somehow, don't use an emulator with a small modification in the packages as possible. What also turned out to be the fastest method to cope with existing distributions was what I call type four, that is using emulation. Packages typically contain for cross build bad things like build an executable and try if it works. If you have an X86 processor and want to do that with ARM, it results in failing. Or if you want to run at least some test suits, that is not possible. And there is already lots of Linux distributions running around that are more or less natively compiled even on ARM and these kind of embedded processors. And we wanted to cope with them. So we implemented also the so-called type, what I call type four, cross-development, cross-build with an emulator. Let me summarize a little bit up what we had for requirements to solve before we started implementing. Cross-build service is a feature where you can just with adding a repository just build your application for a new distribution. So it's a quite autogonal feature, what I call. You have one dimension that is the processor architecture and you have the other dimension that is build it for that distribution or for another one with different releases. And our goal was to still keep that approach and the user doesn't have to care about some internals of cross-building there. So it should be what I call autogonal. And the next thing is that we had to cope with existing distributions. So it was not acceptable to rebuild everything from source. We wanted, as with current build service, keep the paradigm that you could use and reuse existing build distributions. That means Fedora, Ubuntu, whatever. We had that for PowerPC and X86, but we wanted that also for architectures where our workers are not natively working on. And then something more internal was when we implemented that, the execution path of existing build service shouldn't be disrupted. That might be not something very of interest to an outsider, but for those 12,000 users of the build service, it was interesting because, yeah, not to disrupt current service. I always come to the wrong. Yeah. Another thing is, Adrian told you already, we have a means of putting load to the server and distributing the work with the scheduler to our workers. So if you have a big setup currently, I think we have 250 nodes, right? Something like that. The work should be distributed so that big loads of package builds can be handled. And we wanted to keep that. And also the users should be able to use the local build feature also. So that had also to be enhanced. And yeah, then I as a developer with not having at hand a big disk array to store 35 Linux distributions on my hard disk, I had the problem of how to test that. So for and also usually the normal embedded developer doesn't buy a server with 20 terabytes of hard disk space and 60 nodes to make embedded development. So we had to work a little bit with scalability. You have to keep in mind that a big distribution like OpenSUSE Fedora, etc., they need 20 gigabytes of hard disk space per architecture. And yeah, on the other hand, we wanted compatibility. So we were forced to implement also a way to download the distributions on demand. We have already a feature in the system to couple build services between each other. But that was not usable in this case because, I mean, those 30 distributions were not in the main system. So we decided also to implement some form of demand download of Linux distributions that are stored in FTP trees. And to pick also the metadata of the distribution from the original FTP trees. That feature we called download on demand. It means that Debian or RPM packages are downloaded on demand. And the metadata is parsed when you create a new project from these FTP trees. Currently we support the big three systems in this area. Okay, virtualization. We said, okay, this is a new form of virtualization. Currently our workers use Xen for virtualization and for other processes I put QMU just on top of. So it's a mixed form of virtualization that is used for maximum compatibility. We've also experimented with system emulation, but that was considered too slow. You have to wait endlessly when you have to set up a system in the system emulation. So we had to make some kind of trade-off between compatibility and performance. So it ended up that I used user mode emulation in the cross-built system. Okay, download on demand. Maybe all of you that had used build service locally already is faced with that problem. You want some distribution to build against and need to find out, okay, how do I bring all these DVDs into my system? It's a hard disk space. Adrian has to cope with that every day because people want more and more built targets to build against. And on the other hand, I wanted to make some progress with development and not with getting bigger internet pipes to download all distributions I could take care of. So we said that we had to implement some on-demand system that does that without that developer has to take care of it. And so we said implement it from the original FTP tree. It means download on demand caches only the needed packages. So depending on your workload, you end up with up to this 20 gigabyte being downloaded, but you need lots of packages to build against to achieve this. In average, if you have some hundred packages, you only need up to 500 max per distribution that is the usual subset that you have if you build an X application or GTK, KDE, whatever. It's not so much. Many packages in the distribution are never used when you build a system because they are in the end of the leaf and only the user that wants to run it needs it but not for building. That's a good thing, otherwise it would have been useless what we had designed. And what we implemented is the three metadata systems that currently exist for distributions that is Debian Metadata that is used for all Debian and Ubuntu distributions. We implemented RPM metadata that was used for SUSE until recently until the table overflow and it's used with Fedora and it's usually used with normal RPM distribution. And to run around a temporal problem, we also implemented the all SUSE text system in addition. So we can handle now with download on demand all RPM or Debian based package distribution also for cross build. And as I said, it should be fire and forget and not what version does this package have. I missed it. Where do I get it? I will tell you also something about the implementation what we had to change in the system. And first, there's a little overview slides you might have already seen in Adrian's talk. I will not explain the implementation on that one, but I will explain it with the code base where we had to change. What you see here is usually active or components in the build service source code or active components that run if you set up a system on the server side. Let me first explain where is my implementation. Okay. Yeah, okay. Let me explain it on that one. The build service backend is composed of several servers that keep care of your package base, the scheduling, the patching of jobs, the jobs itself, and generating the build results in the end so that you can use that with your package manager so that you can cascade it. The source server was one of the components we didn't even touch. It's responsible for doing the work when you check in a package in the build service. It handles the source revisions. It does the work what was explained here in the track before when you do branching and everything. Usually there was, I think, nothing to change. I had to check, but at least it's not worth noting. In this area, there was no changes to do for implementing cross-build. Repository server, yeah. That implements that when you start a build that your packages get delivered, that dependencies are calculated that when you build a package that it knows where to get its package from. Usually, in that area, we had to change things, especially for implementing the download on demand service. The dispatcher was changed to handle the new architectures. We have new schedulers for the new architectures. The workers now have to take care about that emulation needs to start when you have an ARM package that needs to be built or run in a worker. I think I don't go into more detail here because it needs too much internal know-how. You can ask me if you have some questions here or start with Michael Schröder's talk on this area first as a starter. If you want to know more details inside how that was implemented, I just want to mention that it's more in the back end that we had to change. The web client and so on, there is only things like that the new architectures are known. Testing results. We wanted maximum compatibility to be implemented. So I put together a large testing base at the moment mostly for ARM because QMU later is not in the shape at the moment to run this completely for all architectures. Help is welcome to change that. And for, okay, PowerPC that is used in embedded space, we have a solution that is faster. We needed a starting point and since ARM is widely used and the emulator is well running, we started with ARM in this area. Yeah. And testing results. We have Debian Ubuntu Fedora, even Mamo was put in. And as an example for this type two build, we have also implemented the old ST Linux distribution, also working, running, building, everything. Debian means edge as well as Lenny Ubuntu means all ports that are present running for ARM. And for PowerPC Fedora is the same. Mamo, I think there's only two versions, one for x86 and for ARM. And yeah, my colleague here, he managed to build packages for the Nokia N810 and to get CSYNC running on his calculator. And yeah, that is also implemented. It was only a test case. It needed two days to implement. We just put the packages in and it worked. Yeah. And for ARM processors, we implemented all the processor levels that you need to run the different types of ARM cores. There was a change in the ABI of the Linux operating system in between. We had to take care also of that. It's called the so-called O-ABI that was the old ABI used in the Linux system in past times. For example, in Debian Edge. But today we have a new ABI that is capable of multi-threading and multi-processing in ARM. And to handle also the newer ARM cores we had implemented also in the emulator away to distinguish between that automatically and so that you can automatically mix and match all the packages. The newest is I think ARM processor level seven. They have a vector unit that means floating-point and multi-processing capability that is implemented. And yeah, to check if that really works, we just installed a Linux distribution on an ARM board and tried out if that works what we compiled. And the next step is what Zonker already told you. If you were on the main track here on 14 hours that we started now building OpenSUSE for ARM with the build service, that's a usual choice to do so. You know that OpenSUSE is built already with build service on PowerPC and X86. And we want the same for ARM. And yeah, so we started bootstrapping OpenSUSE now with that as a little test if it works. And yeah, that test succeeded. So we have the base set of a bootstrap Linux distribution OpenSUSE factory running. Yeah. Road map, yeah, the road map. We want to put that as fast as possible into the OpenSUSE build service in the public one, that's for sure, so that every of you can use it and build ARM packages. I'm looking for what the reaction at Adrian is for this. Okay, let's discuss that in the questions. Yeah, download on demand is a little bit error prone at the moment, so you need to cross check all the time to make no errors. So we want to improve user friendliness of this. You can also use that not only for cross build, that's for sure. So if you have a smaller build service and don't want big copies of all the Linux distributions, you can also use this for X86. Yeah, then optimizations, emulation is sometimes quite slow. And since we also implemented cross compilation, our next step will be to implement compile to optimize compile times by combining what we can do here. Yeah, set up an ARM version of OpenSUSE. I said it already at status that we are at this point. I mean, maybe if all works well, it's achievable that 11.2 could run on ARM, but it needs confirmation to do so. We are discussing that at the moment. If that is achievable and will it be achieved? Yeah? Okay. I hope you didn't mention that's actually building the ARM OpenSUSE on ARM processors itself. Yeah, that works. But you didn't mention that as a type. Okay, yeah. I didn't mention it. It works. Yeah. But the usual mobile phone is not that powerful to build open office with it. Nobody, if you have 60 nodes of PCs, maybe you should have a couple of hundred boards with ARM processors. Yes. We were discussing that. It's more a question of memory needed to compile and not of processor power. I mean, you can do that with lots of them. That depends on the packages. I think factory needs one gigabyte of memory to compile all the packages. But yeah, we could drop packages that, yeah, Adrian. I think once we have a build with an emulator or with a cross-build running, building natively will be a rather trivial task if you have a capable machine to build it natively. So it's actually harder to make it work with cross-compiling and with emulation, I think. Yeah, it works already. Yeah. It's actually the more interesting and the more daring task to implement it and probably potentially more useful to lots of people because there's probably lots of unused PC processing power lying around. Not so much in my home, there's more unused PC power than unused ARM power or unused power PC, for example, what's for me. Yeah. So it's probably a good idea to do it that way in the beginning. Of course, if you have lots of ARM boards, you will be able to use them. Yeah, okay. Roadmap, what happens when we put that in the public service is that there's also lots of these tiny little things popping up that work 100 times, but when you do it 20,000 times, it works one time not. So it's these tiny little bugs hiding that only pop up if you do that in a broad way in the big service. So I expect some work here, as always. We had the same thing with the virtualization thing and it needed a while until it was really stable and I expect the same thing here, work to fix the emulation in cases we could not yet even think of. Yeah. The next thing is non-arm architectures. I said for power PC, there was not that big pressure to implement cross build, but it might be for other targets for embedded space. We need that. And I've discussed that with the QMU people already. We need some help in this area to improve situation, but that is mostly a QMU issue at the moment. And yeah, imaging and these kind of things should be more suited for embedded use. I mean, at the moment, image generation generates DVDs, bootable USB sticks and these kind of things and what embedded developers think of is image types that are used in embedded areas. That means that you directly generate some form of root file system for flashes or whatever. That is not a big issue. It should work already. It's more fiddling around with Kiwi to get that solved. And in the end, what do we want to achieve? Assimilate with build service all these tiny little computers you have in your pockets with ARM cores and others. You have to consider per year, there is a number of, I think, 1.2 billion ARM cores sold per year. That's at the moment mostly mobile phones and most of them are not running Linux at the moment, but this drastically changes at the moment. That is with ARM 5 and later there is no problem at all running Linux. So there will be a huge demand for this new type of service, also in a build service. I mean, for example, the Google phone is one of these examples. They have a Linux inside. The Nokia is one of those devices. Others, many others I expect. There is a big curve of improvement in horsepower in this area. I mean, at the moment, we have systems in embedded area that are as big as my thumb and they can decode HD video streams, have a 3D engine on and reach 1 GHz. So that is, it's a PC in principle. What do we do with that? That is what I mean with lots of embedded devices to assimilate and here comes a mind to build service, right? Okay, questions. Yeah, maybe. Yeah, I have, yeah. I do that, yeah. Andrew? Yeah, I take it then if you can compile on the ARM processor, would that mean that you- I don't- can you please close the door? I don't understand you. Is it possible then once you compile on the ARM processor then that can then be moved to any ARM processor or is it a specific processor class that you can then install on or is it across the board regardless of ARM 5, ARM 7? Yeah, there is already a kind of ABI in place also for ARM so that when you compile something it works on all ARM cores of this class. So it's the same situation then with the x86. If you build a Linux kernel for an ARM, you normally build it for a specific chip. Because it's integrated a lot of peripherals. So how do you have any plans for supporting multiple, how are you going to support the kernel? Are you only going to support the file system or are you also going to support the kernel? No, no. We will also provide kernel for let's say some generic type of kernels for the devices also. I mean that is no problem. We do that also for other architectures. Maybe not in that big number because these devices differ more than in... They differ a lot more. I mean I work at that, but I think for us you would need to build maybe 10 different kernels. Yeah, but that's no problem. I mean we have 50,000 packages inside build service so if we need 100 kernels for it it's more a question how to handle that from the process and who contributes that and who maintains them. But I mean we could solve it by that the silicon maker provides a kernel for its silicon for example for the class of silicon. I mean we should try to combine things and not make more versions of it than needed but in principle I would opt for that kernels are provided by those who know their chip. Okay, I think what you need to do then is that you need to specify that there are some configurations the kernel needs to be on. Okay. Yeah, yeah. Right. So there needs to be recommendations. Yeah. But that will be some new frontier for our kernel team to integrate that from a single source of kernel package with let's say 100 variants built. Okay, thanks. I just want to make one comment. I mean this ARM is an embedded platform and I personally would expect it that plenty companies maybe want to re-roll the ARM distribution for their needs. So it's important that we have ARM in the open user build service to show it builds for ARM and it works in general. But with the build service you can re-roll, re-compile the entire distribution then easily with a different compiler flag for example to support your particular ARM chip. And that's a similar question that I had when talking about... If the door is open I don't understand you. For example on embedded PowerPC there are at least a few different processors that have slightly different options for when you build a compiler or machine options and they are not all compatible. They are usually compatible into one direction but not the other way around. So can I handle this somehow without forking a complete new distribution by saying okay I want to have a PowerPC 405 GCC and a PowerPC 823 GCC or something like that and specify to use that is something like this plan because basically the rest of the user space I only need a different kernel, a different compiler and then re-compile everything with this compiler. Is something like this easily possible? Yeah, I would solve it with the same methods that we do it for x86 at the moment so we optimize for a certain class of processor target with a specific compiler flex but we don't use maybe the instruction set. We have already, I've implemented at least the basic instruction levels as different schedulers so that you can, it's like x86 64-bit or 32-bit so that you can say okay I want to run it on a level x capable ARM core. We are at 7 I think at the moment and for Linux everything from 4 to 7 counts so we have implemented three classes for it that's basically the old ABI and no floating point and then everything up to this level 5 instruction set and everything up to the newest that is 7 with vector unit and everything so I would usually build for one of those targets with pre-optimized I mean it's also a question of what you want to achieve with compiling with a special compiler flex. We have benchmarked that and it usually did generic flex help more in improving speed than if you compile for a specific processor. Just I think you've asked more to recompile the entire distribution but to replace a package for example. And that's something that we can do at the moment but not nicely and there will be more nice way in the future to say simply define recompile open to the factory but use this compiler. Is there was another question on there? I can give an example for, I could give an example for that. With G-Lib C we could provide five versions of G-Lib C that it means you don't need to recompile five times 3,500 packages but it optimizes nicely already. I think we have one last question what Jürgen said that the time is running. I have a question I saw the list of all the supported platforms will the open moco free runner also be supported? I didn't understand you sorry. Will the open moco free runner, neo free runner also be supported in the ARM platform? We have the SDK for open moco. We have implemented and running the open moco or memo. Is that debian based? Yeah, there are a lot of distributions on it. It's also debian based as they ever saw on it. There's a lot of this. Yeah, if it's debian based it should work. Debian packaging we can handle. Okay, then we close the talk here. Thank you Martin.


Hey, what's good y'all should boy down from the Don show was popping it's your boy James. Yes, sir Yes, sir. Check this out. So just what we doing today don't show them friends, but So look this will be doing today we doing choreography video 17 getting closer. All right, so we never disappoint 17 never disappoint office looking crazy already, you know quite frankly none of the groups ever disappoint like Like I always have high expectations for 17 specifically factory, you know That is on your cruise. So that's one of your crews and companies. You know I'm saying like yeah, I like sorry I'm saying the wrong favorite music group. You know I'm saying music group You know I'm saying doing a thing, you know factions, right? Okay, okay, I'm good. So We're gonna do this right now. We're gonna knock this out for y'all, but we got more on the way So just get ready for that. So let's get into it. Three two Sheesh Notice nobody breaks formation by the way. Nobody until it's time to transition crazy. Wow Yo, so smooth Sharp yo, nice yo Go ahead, bro They got so many members, right, right? They have a lot of people in a group right like If you need to transition in and out so cleanly so smoothly Without bumping into anybody nobody's out of place. Everybody's at their spot when they're supposed to be that is hard That takes a lot of preparation a lot of practice my biggest thing is like when you have one individual and chemistry They all gotta be in sync. Yeah, cuz my part is God was right here. Mm-hmm slid in snap Hit the spin boom boom boom get into formation. Let's get crazy. Let's not waste any time Let's get this start going off right here in there Like that type of quality right there is what I'm all about Like I'm all about that because of the fact that it's like if we're going to do this song if we're gonna perform at this level Then let's make sure we go all the way out. You know what I mean? Let's let's not waste time if we're gonna be explosive then you go all out No wasted movements either. Everything is point a point B Next letter yeah next letter Let's keep it going y'all. Let's get crazy We 30 seconds end up 30 seconds. We already ran Oh Yo a lot of Musicality you see how each side was doing the same movements, but opposite of each other. Yes One started on the right arm and the other side started on the left Did you see when guy was walking and he kept doing this with his hands and they had kept doing this?  Yes as it was moving nice and I hear the song and they're killing the song So I'm the song. Yes, if y'all want us to do this music video, please make sure that you comment Drop that in the comments. Yeah, we'll do it. Yeah, we'll do it, but we don't want to drop it if you're not gonna watch it exactly Okay, let's get back in this Hey, I see that chest pop nasty What's up? You can't go wrong You already know bro in a ripple in a wave what back to that back to that. Yeah Yes, they're bringing it back. Nice their formations are so creative in this kid is so good Yes, I Think that's my favorite part.  Yeah Nice, let's go Time you guys very sharp movements this time where we get real sharp and real clean. Uh-huh Nice. Yes Yes, I see it. I see it. I see it No way to go off everybody was switching as they go all very sharp very explosive choreo Shout out to the courier. That's it. That's it. What shout out to the choreographers What y'all nice? Yo, y'all nice nice So nice I got said twice didn't mean to rhyme, right? Just happens that oh man, that was cold that was cold. I mean a I'm yeah, you got me You got me you got me. I stand up and clap my hands, but I'll be out of the shot. You'll be out of shot Yeah You need me in the shop, but you ain't trying to see this all up in the camera.  That's all I know. I got a gut. So what you eat? I'll battle any one of y'all, too Okay, you will though. I will though but he's funny, but I'm serious Okay, so let's see y'all. Um dope choreography video 17 is definitely we bring it back more 17 High expectations every time I see every time every time we do them when when is we did a video for them for the dance practice I wasn't good, you know There's a couple of the groups that are like on that level. Yeah, you know, these are the artists These are a lot of dope artists not saying they're and not saying it There's not a huge gap Between any of the groups first dance wise skill wise facts, right, but There's like two or three that are just different Yeah, and they different and they stand out like why like they different. Yeah, the ones y'all been requesting for us We've been we've been recording we've been watching and recording them and getting ready to upload them It's like it's a set of these artists that are just like That just doesn't like this is like do it It's like playing in the NBA We're playing in the NFL Everybody's talented everybody's super talented true Everybody's elite, but you know, it's there. There's your Michael Jordan's in your Lebron's and Tom Brady's.  Thank y'all again. We're over 10,000 subscribers We have more for y'all. So keep sharing keep like and Keep commenting it helps so much for the algorithm. Yes, just keep we're gonna keep bringing that Zero seconds, please Yep, yep, just we're gonna keep that like yep. So we see the comments y'all. So thank y'all so much Thank you. Thank you. Thank you. So we don't get a body here We're gonna give you more video ring that bell by the way ring it and we're gonna get subscribe subscribe like comment Share do something we out of here