logo

NJP

[E23] You & I Builder Live! ServiceNow Next Experience

Import · Apr 04, 2024 · video

[Music] he [Music] [Music] hello everybody and welcome to another fantastic episode of you and I Builder live the show where sometimes it works and sometimes it doesn't today we are joined by two awesome guests my but first my name is Maria Gabriella a chz wector I am an outbound product manager with the experiences team over at service now and today uh one of my two special guests is gonna uh introduce themselves go for it ay hi everyone I'm ay Anderson I am a developer at Yona labs and I'm here for all of the UI builder stuff yay youi builder stuff ah no that that intro was rough but the reason why let's introduce our second guest today you guys hear that thumping noise in the background that is a bird that will keep hitting its head against A's window so we have a little bird counter going on in the bottom there so if you see us kind of distracted kind of off our game it's because we just keep hearing the thumping hopefully it's not too much fre you guys I can't stop laughing every time it hits it just like throws off my groove why does it do that any idea I have no no idea and I tried like closing the curtains so that it can like see in and it's still like every few seconds flies right into the window I I don't well anyway so if this was live coding happy hour we could like do shots or take a drink anytime it hits and we would be destroyed by halfway through but it's a Thursday it's still 4M not 500 PM yet on the East Coast so ay what are we doing today today we are improving the oh another bird hit from a different window sorry I'm I'm distracted um today we are improving the wish Hub application to include viewports um to kind of show how we can communicate like to and from um a page and a viewport on a page so that's that's the plan for today awesome before we get started going to go ahead and share my little slides here you guys may have heard about this last week but next month we're not going to have any you and I Builder live shows on our usual second and fourth Thursday of the uh Thursday of the month instead we're taking a monthlong break because of knowledge um if you're not familiar with it knowledge is the yearly big convention that service now hosts it is a blast and a half if you ever have a chance to go I would strongly recommend it ay do you have any particularly fun memories about knowledge um last year was my first year and honestly like the whole thing was super fun I loved like the hackathon was definitely a highlight and just all the sessions and like meeting people in person that you see like always on a screen was really cool yes it it it really makes it feel like the community is a bit closer than it really is um these sessions on this side are some sessions that my team is doing that if you have a chance to make it to you should totally try to make it to if any of these sessions are full you can queue up in front of the room uh in about five minutes before the session will start they'll start letting people do walkin in order to um fill in the seats if there's any seats open the first one is her live you and I Builder live it's going to be this show but live and it's going to be chaotic it's going to be a bunch of fun uh the next couple the next one is build a killer single page app with UI Builder it's um going to be building a h a killer single page app if you remember the Notes application we've been working on on you and I Builder live that's the one that that's going to be focused around we've also got two workspace related um labs and then I've got my Advanced theming Mastery lab which will kind of take you from theme Builder to custom theming um and everything in between we've also got some ask the experts more and more of these keep getting scheduled so check the agenda again and make sure in case you missed being able to join one of them but it's basically going to be like 20 people in a PM in a room and you can ask questions it's going to be great I had a lot of fun at my ask the experts last year and then we have some Community sessions that I wanted to highlight and or sessions from people outside of us our theme our team the you sunk my Mothership creating complex interactivity in the next experience session is going to be amazing I am super excited a good friend of mine Travis Tolson has made the game Battleship inside of um next experience inside of a UI Builder and it's going to be fantastic um then we have two new sessions on a new design system that we're debuting at knowledge I can't say very much about it just yet but after knowledge be you're sure you're certain that I'm going to talk about it a whole bunch I'm very excited ay do you have any uh presentations at knowledge I sure do um I'm doing a session that's kind of like a Harry Potter parody um showcasing custom configurable workspaces with UI Builder and kind of showing like the power of them and how you can make them do whatever you want for your company so that's my session it's going to be a party if anyone want oh that sounds amazing do you do you want to try to dig up the number real quick so we can put it in the chat uh yes I do want to do that other than this we have a whole bunch of meetups that you should look up on the agenda Builder and to any ladies out there on Tuesday morning at 7 AM we're having the yearly women now breakfast it's going to be in front of the Chipotle on the second floor of the Venetian food court um we're going to have pastries we're going to have drinks it's going to be an awesome networking time ay have a B you enough time you did plus Earl threw it in the chat so that was nice and I put the session number to it's thank you 10 1089 CCB 1089 thank you so much ay I'm gonna stop sharing my screen here um let me see if there's anything else I got to plug I already said we're not going to be here in May our next you and I Builder live session is going to be on June June 13th um and I think I think we have some um I realized that we never celebrated our one year anniversary on you and I Builder live well a tragedy I know so I think we're gonna try to do like a a one-ear special in June and we'll we'll see where we go from there ay are you ready to go I am ready to go let's go then now I think there was something you wanted to share with us first right yeah yes let me switch to my notes on it okay so let me pull open oh man I forgot I was um I was testing a question that we got on snev slack about theming and I set that awful lime green theme and I totally forgot to remove it let me fix that real quick because that looks disastrous you know I was wondering what the okay where's my little search oh and one last thing if you aren't able to make it to knowledge all of my team's uh Labs will be made available after knowledge on a separate site that I'll let you guys know about at a later time it's not live yet donk Okay so uh I think it's this one you want me to give a little background for what we're doing or are you gonna do that when you can show it I'm I'm gonna do it right as soon as I get the page pulled up I mean you can you can give the background that's all good oh that's a big picture of me that's and I'm so sorry for my naming conventions they are great I'm trying to figure out which live variant we're talking about okay this is it so if I open this page okay so this is our our portal um that we've been working on and when we refresh this page sometimes I don't know if it'll reproduce it since we're you know live and everything live but sometimes when you refresh oh it did it worked okay well it broke um it just gives you like this blank screen and like the only way to get around it is to refresh it and it's super annoying and it happens like all the time on this application um and I ran into this for like a client project I was doing too and it was like a big deal because they didn't want to send it off to like their customers if it didn't load half the time um this is happening because we're using the portal app shell yes yeah it only happens on the portal app shell and it only is in um experiences where it was created like before Vancouver so since this wish Hub app has been around since Utah I think um then it has the issue so any portal experience created like I can't remember if it's Washington or Vancouver but a couple releases ago is g to have this issue for like the rest of its lifespan so I just wanted to fix it because it's kind of annoying to work with so Al's kind of show us how to fix it which is fantastic I haven't had any I haven't had a chance nor the time to figure this out we've been dealing with this with the wish Hub app since day one so I am super excited um we also have a KB that we're going to end up linking in the description of this video um so ay what do we do to fix it okay so we are going to go to um the settings for that page and and we'll click on not the variant itself but the actual page settings um and then and we can go to open records and then I think it's the app config we will we will see if this is correct um that is not correct okay I'm just going to go straight to the so the table that we're looking for if we just open up it's this ux page Reg um and there's a way to get to it from UI Builder I just can't remember what it is um but that brings up all of our UI Builder experiences so if we open up the one that we were working on which is this wish Hub application um there's this field down here called parent app and it's missing a value and that is what causes the refresh issue I don't know what's going on behind the scenes to do that but if this is blank then that refresh blank page issue will happen um oh so you just have to put a value in I think the one that's like out of the box is this uxr base unified app parent app so this is set automatically when you create a new experience um on later releases that's why it works like in Washington DC um but it was not being set automatically in older releases so this value is just like not there unless you go in and set it manually so add that and save it and if this if this is in like a custom app you can always uh make a copy of this parent app and use that instead in your app scope but we'll just use the global one for right now so now if we come back here it should load it and there it is bastic okay so I get kind of what I was thinking for loading viewports um or for using viewports with this fancy little portal experience we have um last time we built out like the my wish list page or Tab and the friend wish list Tab and I was thinking it would be kind of cool if like if I clicked on one of these wish lists if it would open up their wish list over to the side right and there are lots of way to do this like you could you could just have things shown and hidden conditionally based off of what you click um but a view port's a good way to handle this just to separate functionality too um so I think we're we'll go that route to show kind of how you can use viewports sounds good I love how Earl has given up on cataloging the bird Saga I know I'm just grateful that I've like moved past the point where where I acknowledge it now it's just in the back that is just so funny to me me too okay so the first thing we need to do is we kind of need to create two columns one that can have the different lists in it and one that can have the like the list details I guess the list items so let's go to our tabs and we're going to just not worry about my wish list right now we're going to go to friends wish lists okay so this is where we can use the new layout options right to create two columns yeah look at this okay to be honest I haven't used the layouts much so this is going to be a good a good learning experience for me I keep trying to type component I mean a container whoops I know I I mean I am a fan of my containers not going to lie but we'll we'll try the column for today so I think I can just drag this container into this column boom and now all of our I don't know why this ISS let's workload it I don't think that's I think that's hidden yes okay so we've moved the lists into the left side of the column and then these can be resized with the little drag drop thing which is really cool so we'll do it we'll do like let's say 35 and 65 that sounds oh that's going to bug me but it's gonna stay okay um and then we also need to make these containers let's go back to our this right now you can't like click on these so we need to make it so that we can click on them um Gabby in your opinion what is the best way to make something clickable like what component do you like for making things clickable see I I have a bias for the card component slowly because that's usually what I like to make clickable but don't you have some solution for that yourself you know I do um in in share um I don't want to go through the time to like load it in okay here but yes I do have one that's just kind of like a generic wrapper that adds that fires a click event so that you can just wrap it around anything which is kind of nice so how do you prefer uh I don't really have a preference that's why I asked because I mean obviously like my own because it was yeah let's that sounds good I think it's based container oh yep I just skimmed right over there and that should have the click yes so if we go to events yes card so we will use that um and we can just keep all of our container stuff in there for now I think well let's yeah okay so let's add a card clicked and for now let's just um I don't know let's just let's create a client State parameter to store which um which card we've clicked so clients such a nice new UI I know I'm a fan oh we already have one look at that selected wish list so I think we can just use that so on the card click we will update client State parameter to wish list go ahead could us using that cause issues somewhere else because these are tabs on the same page if that's already populated with something for example from a previous use of it um it's possible especially where we kind of revamped this page I think we just didn't delete anything that was there previously so that's that's a good point we should probably just create our own if it'll if it'll load there we go client State oh oh man it's wigging out that was so weird okay well hopefully I didn't break anything oh there it goes let me I'm just going to refresh I yeah we'll still just refresh we didn't make that many changes yeah that was very weird okay let's try this again so we have this container in the friends wish list we threw it in uh two column layout so we'll go to layouts tab two columns so while ay uh gets us back to where we were before hitting save this time anybody have any fun uh Creator con memories in their that they want to share in the chat and for those of us who may not be familiar Creator con is kind of like the developer convention inside of knowledge um I love Creator con it is a ton of fun typically they have print Farms um a whole bunch of Awesome um oh SEMA that'd be really funny bu could we build Earl's counter into the wish Hub that would be very funny um yes hackathon is a great fun time in um at Creator conon um just do it so I I have this thing whenever people ask me anything about job hunting or should I apply to jobs I'm always like just do it and it's reference to uh one of the greatest philosophers of our time um shy abuff um he's uh really funny and he just made this whole video that you should look up just do it um so for my very first Creator con uh presentation I ended it with me basically reenacting that video and it was really funny um so great question confus between Creator con and hackathon Creator conon the hackathon is a part of Creator conon Creator con is the overall developer Centric side of knowledge and the hackathon is one of the events that occur within Creator con um the hackathon is a uh kind of like a a contest where teams get together build an application according to certain criteria and basically spend like over I don't know maybe 24 hours or something on an app um you know it would be great at explaining what hackathon is no he's he's okay he doesn't want to come on I'm sure he'll correct is Earl runs the hackathon if you have any questions message him on LinkedIn [Music] it's not your show sure but you're a producer intern it'll be funny um are did I buy you enough time ay you sure did I think I'm good per what are we doing now okay so now um we are adding the event handler or event mapping to update our new client State parameter when a card is clicked so um yeah so we will update actually let's change it to selected because I think it has both it has card clicked and card selected but selected means It'll like maintain its its selected state so let's use that oh let's do that one yeah so I have this selected friend list now and then it we've got this nice modess dialogue to help us pick what we want so I think our repeater has each of the unique um wish lists so if we go in our repeater and look at the value um we probably want to save just the CIS ID of the list that we're grabing and I love that it shows the value on there that is so nice so nice oh and then I got to click the up Arrow I always forget that part and apply me too and we'll add that and then one gotcha with the card I think is that there's this interaction config property and I don't think it will let you click or select on it unless you choose which interaction type you want so we'll go with select what does selected mean click on the little I oh like what it means oh oh so this shows like if that card is selected in the list okay so you should also set this yes yep except I lost my okay so we'll we'll do the data Bing again and this time we'll say if the client State selected friend list um oh let's try formulas because we want to see if the we want it to be selected if our client state is the same as the item we're on in our repeater right so let's try the equal oh left I think you're yeah go back okay so if our selected friend list in the left oh that's so cool that is so cool is equal to the current CIS ID in the repeater that we're on we'll apply that nice look at that okay and then we'll save it so let's just make sure that we can select things let's come back here refresh it doesn't show us a blank page nice oh nice okay so these are inside of cards now Gabby birthday selected PA's birthday back and forth nice that looks good okay so let's slap a viewport on it now okay so we're we want to come to this other column in our layout and it's nice and empty right now um so let's go to whoops there's this nice viewport component okay so there's kind of two different concepts here there are page Collections and there's viewports um and correct me if I'm wrong but the page collections are more like reusable sections of a page kind of that you can like in lots of different places like if you wanted a contextual side panel on a record you could add a page collection for it and then you could put it on like all your record variants um is only like a onetime use sort of thing that sounds like a good way to describe it I'm sure there's other differences too like I think viewports you can have properties passed down from parent to child whereas page collections used use more like URL prams and stuff but for this one we're just going to go with the like more of a classic viewport um so we'll click this replace with viewport button okay and then we will edit the content all right so a viewport lets you have a sub page kind of a synonym I guess for it so we'll create a new page and we'll call it friend list and I don't think we need any parameters right now so we'll say it looks good and create and we'll open the [Music] editor and then let's just throw Brad's favorite comp component on there just to make sure that it's working why don't we throw in the um the name of the returned list to make sure it's showing the same we will do that um you just want to make sure the view Port works first yeah yeah because there's some steps that we have to go through to get to that point so we'll kind of walk through through those that we hopefully don't lose people um in that process did we already set up and that's okay so that's what I'm yes there it is yeah so viewports you can't just put the component on the page and then have it work which is kind of intuitively like what you would want to have happen um but you have to actually tie the parent page to the viewport um otherwise you'll get this error that says says no content available which is totally what we yeah what you were just getting at I think so the way that we do this I'm going to open this in a new tab so that we don't have to go back and forth every time okay so on our parent page um is there a specific spot you like to put it I always just put it on the body but I don't know if there's like a better place to put it I think the body's fine no opinion here so I usually slap it on the page ready event mapping for the body of the parent page so if we click page ready there's this um page level event handler for viewport load requested so we have to use that um and then there's some configuration that we have to do in order to tell it like which which viewport to load like or which page so we need the viewport element ID and we need the route um so we can get that by let's grab the viewport element ID so if we come to our viewport this ID right here that's the element ID so ours is just a viewport underscore one and it change it oh interesting and then our route um was just the route that we put for our page which was friend list and we don't need to set the fields or pams for this one because it's a pretty simple example we'll save that and then if we come back and refresh hopefully we should be able to see that stylized text that we put on there yeah okay so that's good but let's replace this with the selected list as you as you mentioning earlier so um with viewports the way that you pass data from the parent page to the child page is through the page properties so if we go to body and we go to configure then on the properties we can add our own um that are inherited from the parent page so we'll add a new property here and we'll call it um friend list ID and we will add it so it it adds it to this list over here that you could remove later we're going to save it and then um one thing that kind of tripped me up at first with these page properties in viewports is that the data binding in them is tied to the parent page not this page so like if you have client State parameters on the viewport and you do like the at State it'll pull it from the parent page um which is how you pull stuff in except maybe it doesn't work with state it grab the data resources from the parent page do we want to try just uh manually coding it um yeah we can try sorry I meant um if you you should be able to click into that the top square oh there you go Gotta double click and it should let you do the at yeah it might be a display issue with the new visual data binding so let's see if this works and it it very well could be since it's inherited like from the parent page let me make sure I let's see selected friend list is that what we called it Cent State parameters yes that is what we called it okay so let's refresh and see if that does the trick did we hit save um I think so yes what about on the other page oh we did uh oh it's not switching so let's come wait did we set the text at all though yeah we did it oh you're right silly me okay yes we actually have to bind with the stylized text so we pass the property in um we go to properties yep and friend list ID which it's saying it's not set right now but that's because we had to manually do the data binding okay let's try this again cross your fingers okay okay so right now it's blank hey look at that pH I didn't know what I would do if it didn't work and just a reminder if you also want the visual data binding feature in Washington you have to update UI Builder from the store it is now a store app so if you upgrade to Washington and wonder why visual data binding isn't there that's why okay so now I think we should load the friend list like their items instead of society so if we come down to our data resources we have inherited data resources which are from the parent page and we have local data resources so since we're using well I mean you could do this anyways but we're going to add a data resource that grabs the wish list items um for that specific spe ific list that we've selected so that bird up is it multiple birds or is it just two birds there's two it's mostly just one I've got I've got two windows one to my right and one in front of me and they've definitely hit both windows next time we got to get a bird cam going that would be funny okay look up oh friend list items and the table is I don't even remember anymore wish I don't either there we go oh that that just hit window to window so there are two birds unless it's just super quick okay so let's see the we want the wish list is so now we've got our page properties props friend list ID so items where the list is our friend list ID we'll apply it let's see what fields we want let's just like put a bunch on there got our di di [Music] by image okay and we'll order it by the name Probably sounds okay do I have to click like add somewhere is it just not SC okay so now uh in Washington it's displaying in a modalist window that you can move around the screen and resize it's really nice but yeah it is kind of confusing it does feel like there needs to be like an apply or save button there doesn't it yeah just because it was there all the time before so it's I mean I'm a huge fan of the change but takes some adjusting exactly um okay so let's we'll keep oh wait no we need to add a repeater to kind of go through each of our elements or wish list items probably delete this guy now I know it's a little late to be saying this but let me know if I need to like turn my mic up or down at all I gu no you're good I think we've lost the people we were gonna lose to the birds so everybody left is just Troopers I love it way to hang in there okay so We're looping [Music] through our friend list items oh results not the my 3D printer is making the most concerning noises and I'm shocked you guys can't hear it you know I right before you said that I did hear this like beeping is that what that was I don't know what it's doing okay so now we're going to just throw a styliz text on there that has the name of the item and then we'll save and just make sure that it's working still next April Fool's episode I should have Brad on the show and I will plan the show to be an exploration of every other text fieldi Builder that could be used instead of stylized text you just aggressively start using like the heading or the rich text yes okay so nothing is coming through sometimes it works sometimes it doesn't so wait do we know if it's the thing not coming through or if it's that the viewport isn't displaying um I'm pretty sure the viewports displaying but we could we could put our stylized text back on there that was working maybe let's change the background of the body to a different color sure how about to that same green header color just kidding you're the best slash worst uh I mean I guess we do have our theme colors so you shouldn't have it anymore because I fixed the you fixed it okay we're gonna do my fav color since I'm in charge go for it there we go I'm G refresh this just for my own sanity there we go much better okay let's try this again let me make sure I sa yes it did man isn't it so nice to not have to refresh multiple times it is so nice oh oh you're right no oh where'd it go unless it was just loading still okay I'm still going to put the sty just because sometimes it'll have a height of zero if there's like nothing in it which will make the background sure just Just for kicks and dickles and then we have to do look at that not doing stylized text just for you we'll just leave the generic message for now do we need to click on something in order for that viewport to display because we're having it set to visible only when oh no we does display regardless yeah it should show up okay so that was it I mean that's why it wasn't blue is because it didn't have anything in it so so our repeater something is just wrong so let's look at this we are looping through friend list items there are 10 results and then in our stylized text we're showing the value of the repeater that seems like it's right um uh go back to the data binding again because it works here yeah why does it work oh because we're doing a data resource are we saying when the data resource should be loaded um let me check do we care about that uh it should change because the conditions are Dynamic it should change whenever they click on a new thing you're right maybe we just put a event to trigger a pop-up message when it succeeds or when it fails so we know when it's running just in case okay this is one of my favorite troubleshooting mechanisms so I know Brad always likes to create a client script to do the log statements um I just to show kind of a different way to debug I do the update client State parameter and I switch it to script form because then it doesn't add an applic record behind the scenes oh cool delete them they don't get actually deleted I think on the client State parameter just the connection gets deleted um not the client State parameter sorry the client script so if you do an event handler then it will get deleted properly neat also and then we'll do api. friend [Music] LS let's just start here for now and then do another console log okay and then you said do one on failed too so we know either way ini sounds good okay let's save and refresh Earl yay is not better than Brad yay is just different than Brad oh it loaded items but do we need to trigger a Refresh on the viewport um oh wait there's no items need to yeah the items is is coming back empty so it is successful it is running and both of them should have items or do you have quick access to check and see if they both have wish list items that would be a as if they just didn't didn't no I know mine for sure should have some but are we using the right field then no because it is returning items there we are using the wish list D I'm going to put that stylized text back on there just to make sure it's oh are we how are we um no the data resource is returning items because we're tying it by the wish list itself not by the wish list T so I didn't know what we were doing but if our data resource is working that should be fine if it's pulling back the right items but it's saying it's pulling back nothing right yeah properties ID slap that on there oh but you bring up an interesting point is that this should run every single time one of these is clicked and it's only running yes so are we refreshing the viewport once it gets clicked I don't know probably not okay or we're not refreshing like we might need to okay so um where did our card go here's our card select High Chad update client State okay so let's put on here [Music] um you know another thing that we could do that might be might be better because then we don't have to change it in as many places is on the body isn't there an event to like take care of um if something change yeah page property changed so if a page property so that way if the um State changed where the data resources is called friend list item thank you why is it you can see it under local data resources it might be because it's so the page configuration often points to the parent page not the child page ah I wonder if it just thinks it doesn't have access to it um so maybe not oh no I don't know why it didn't come up that was weird oh I probably needed to type refresh not friend list item oh okay we could conditionally set it so that if it was our selected friend list ID that changed but for now we'll just refresh it anytime a page property changes okay let's try try that and if not sometimes it works sometimes it doesn't I mean yeah we put the disclaimer in slogan okay so zero items that's what we expect so then we click [Music] one okay so it is updating the state correctly but it's not refreshing data resource correct refresh friend list items let's do it on let's add another one on [Music] initiated I guess we're running out of time too so if this doesn't work then we'll just you're good tap for now so we's see you're a okay okay it is my job to worry about time but you're not wrong oh my God Earl is gonna clip one of the verd thunks and play it randomly for us in the future it's gonna be like PTSD I know right oh oh maybe I just didn't okay slow down I clicked it too many times I'm just going to refresh and do that again I was not expecting that to work okay so click on this avocado house helpful on community and stickers that looks right why and then we'll click here I wonder if it just hadn't like cashed or refreshed properly Cactus and Orchid so it is working that is am amazing um yeah let's remove all those and let's see what happens okay so let's do a hard refresh wondering why it's taking so long to load this should not be taking that long to load it might be my network to look at that it must have been a cashing issue awesome yeah I'm sure it probably was we need like some form of like Fanfare like sirens hash cashing issue kind of situation going on because uh this is amazing so thank you so much for walking us through further enhancements to our wish Hub app ay is there anything you want to close on uh and tell our lovely viewers yeah I would just say viewports are cool if you know how to pass data back and forth um then it's a good tool to use and sometimes it works and sometimes it doesn't hey you took my line so where can people find you um I am on LinkedIn um I'm also on the snev slack you can always DM me there um I will say with LinkedIn I do better if you like send me a message with it saying like how you know me even if we haven't met but if you're like hey I saw you on you and I Builder live like I'd love to connect you then I have a better you have a better chance of like actually connecting so just send a little message with it if you're going to connect with me on LinkedIn but those are probably the two best places to find me do you make any content um yeah I've been doing blog posts and live streams like this um work's been super busy the last little bit so I haven't been nearly as active but I I'll be at knowledge you can find me there where can people find your blog posts um the yansel labs. website is where a lot of my blog posts are um I also have a personal website ay anderson.com um that's got like all of my community content from all of the different sources kind of pulled into one spot so that's also a good place to go fantastic you should go out and get yay.com before it's taken oh my goodness I should what a good fantastic do it right now so thank you so much for joining us today ay and thank you guys so much for joining us in the chat as a reminder we are not going to have another episode until June the very next episode is going to be June the 13th um funny story in Venezuela it's not it's not Friday the 13th for us it's Tuesday the 13th and it's just like really weird uh fun trivia so again thank you guys so much for joining thank you for watching and uh interacting with us in the chat and I hope you have a lovely rest of your Thursday goodbye I [Music] [Music]

View original source

https://www.youtube.com/watch?v=2EV9klT590g