馃洃 Build ChatGPT in JavaScript (Super simple!!) | JavaScript, HTML, CSS

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey everyone it's so great to have you here today I am coming to you from Cape Town in South Africa and I'm going to be showing you the easiest way to make a chat the GPC clone using JavaScript okay so JavaScript HTML and CSS this is a great project for those wanting to learn how to use API specifically the chat GPT API in a simple JavaScript project now this is just for demo purposes okay we do not want to go and publish this code onto GitHub or deploy it because as we know right in a simple JavaScript Project without a backend or anything like that you can't hide your API key so you don't want anyone taking this API key because if they do they can rack up loads and loads of money on your account if you have a credit card or anything like that associated with it so this is just for demo purposes if you want to know how to build a chat GPD clone with a backhand then I'm going to be releasing the same video but building this in react with a node.js backend okay we can of course also have a JavaScript front and a node.js backend but I think the react app will be way more fun to build so what are we waiting for by the end you will have this chat GPT clone which we will be able to build using JavaScript HTML and CSS and then we'll be able to ask your questions as well as other history of all the things we answered before so let's do it okay so first off we're just gonna start a new project I'm in webstorm so I'm simply going to select new projects and I'm going to select an empty project so it's being saved in my webstorm projects directory or folder on my computer and I'm just going to call it JavaScript chat GPT Club and I'm going to create so that's going to spin it up for me and now I'm just going to add some files I'm going to create a new file it's an HTML file let's call it index.html you don't really need to put that HTML extension in webstorm but I'm doing it here for those who are not using webstorm and then I have this boilerplate code setup so if you don't have this boilerplate code set up please copy it here and I'm just going to do JavaScript chat GPT just like that and of course we also need to create some more files so I'm going to create a Javascript file called app check s and then also a star sheet so I'm going to create a new style sheet let's call it Styles because it holds all our styles.css so there we go that is what my project looks like at the moment I'm just going to make that smaller so what do we need to put in here well first off I'm going to create two sections one for the sidebar and one for the main bit this is actually not going to take much CSS and HTML of all so I'm just going to create a section there's my one section I'm going to give it the class name of side bar okay and another section this one's going to be the main section so I'm just going to give it a class of main to differentiate the two sections we can pick them out by their Style okay so what's gonna go in our sidebar first well in my sidebar I'm actually going to have a button that says new chat and it's going to clear our input okay our search input after that I'm also going to have a div and this is going to hold my history okay so all the previous uh commands that we wrote and I'm just going to style it up a bit so I'm going to give it a class of History like so you don't have to use the same style names but you know for the sake of the tutorial maybe copy along and you can change them later next I'm going to create a div and this is going to hold my nav items so I'm going to give it a class of nav and then for now I'm just going to have a p element that says made by Anya you can of course add as many elements in here as you want you can put in links and so on but I'm just gonna have this and now in my main section I'm gonna have an H1 element that says Anya GPT because that's what I'm calling my clone then under here I'm going to have a p element that is just gonna show the output of my search so I'm going to give this the ID of output so we can pick it out just like so so that's one tag and another tag and after that I'm going to have a div and this div is going to hold a few things that's going to hold the input and then a little button to submit our query right so I'm going to give this the class of bottom section so we can pick it out and in here I'm going to have a div and this is actually going to hold my input and my submit icon essentially so let's also give this the class of inputs container and then in here I'm just going to put in an input element just a self-closing element and a div and this div is going to have the ID of submit so just like that now under so this is a child of the main section this is a child this whole thing is a child I'm gonna also put a p element uh and this is just gonna be some Sub in first so let's give it a close-up info so we can make the text smaller by picking out this element and then I'm just going to put chat gpg this is just from the website itself March 14 version in fact I'm just going to paste this so we don't have to write or out but of course you can pause here if you want to have this full text right here so that is what that text is going to say okay so actually now we are done with the HTML part please post here uh to have a look at it or slow it down but essentially that's it maybe if I zoom out for some of you you can see everything that is everything okay with the correct formatting wonderful so at the moment if we open this up and webstorm I can just click here and that will bring everything up and if I inspect the page you will see that section that we made so there's our section there's the other section with all this stuff inside of it okay so now let's get to styling up the first thing I'm going to do is make sure the sidebars on the left and the main section is on the right and for that we need to link up our style sheet and I'm going to link up the Javascript file while we're at it for those of you who aren't using webstorm you can view this by again in the index Asian log page copying the path copying the absolute path and just pacing in here like so it's the same thing great so let's carry on so let's link up our style sheet first I'm just going to go link and I'm going to use Rel I'm just going to minimize this style sheet just like so and then href and I'm going to link this to the star CSS file which is in the same place as this file so we don't need to go into any folders or anything like that we just get the file name and like I said let's also do the script tag at the bottom to link up our JavaScript so make sure it's at the end so after all these other elements have been read then we want to read this script and there we go so great let's get up our Starship so first off I'm gonna get the whole body so the thing that everything is in and I'm just going to get rid of the default styling by adding margin and padding zero just like so next I'm also going to give it a background color now this background color I actually picked out from the website itself so there we go that is it that's our background color and now so at the moment it will look like this but these two are still kind of on top of each other I'm also going to change the font in the whole project so by adding this star like so that means everything everything my whole entire project is gonna have the font color of white which is Hash FFF okay you could do three F's but you know this is a shorthand for six s so that's what I have done so now the text will be white and to make this section to the sidebar section and the main section of your left and right of each other we're going to use display flux so all I'm going to do is on the parent of both of those which is the body I'm gonna just write display Flex save this file and there we go so now the sidebar is there and the main section is that wonderful we still have a bunch more stuff to do so let's carry on I'm actually going to import a font while we're here that font is open Sans and for that we're going to go here and then we're going to go to Google fonts okay and in Google fonts I'm going to pick out the open Sans font so all I'm going to do is search open Sans click on it and then I'm going to select a few we can select as many as we want so let's go ahead I'm going to select maybe all of these so basically just not the italic ones so that we have them to our dispersal in the project I'm going to choose to import them via these style sheets I'm just going to take this code in between these two style tags and then in my project I'm just going to paste it in like so okay so there we go there's the uh semicolon at the end and all the weights to my disposal and once that is done that means I can now use the font family open sense so font family open Sans and then as a backup I'm going to have Sans sir so if you didn't know which code to use you can actually get it from here here's the CSS rule to apply that family and you just get that one great and that's it so that just means that that font will now be applied to my project let's carry on so now that we have done that I'm also going to pick out any H1 elements in my project and assign them a different font size because I don't like the default one so I'm just going to go font size 33 pixels and a font weight so we just import a loads of font weights I want to go with 600 and I'm also going to pad it out so I'm going to use the padding property and I'm going to say 200 pixels from the top and bottom and zero from the left and right so that's a shorthand okay this is top bottom and it's the same as me writing this but because there's repetition I can remove it and that will now be applied to the top and bottom and this to the left and right so if we look at it now that's what it would look like there's my H1 element great now let's actually pick out the sidebar so I'm picking on LM or the class of sidebar that dot means class as you can see here we're looking here going ah here's an element with the class of sidebar so let's pick out the whole thing so that's what I have done now I'm going to give this a different background color again I have picked this out from the project so from the actual website itself and I'm going to say the width of this is going to be 244 pixels uh the height is going to be 100 of a viewport height so VH so whatever the browser size is the height I'm getting it and I'm also going to make sure that everything inside is going to be stuck on top of each other with equal spacing so I'm going to use display Flex for that I'm initializing a flexbox so then I can use flex Direction okay without this this will not work and I'm going to make sure that everything in the sidebar is a column so like stand over each other so that's what I would use so if I look at this now you will see okay there's a button there's basically everything in the sidebar so this this this stacks on top of each other but what if I want them to appear equally spaced right so the number is all the way at the bottom this is kind of in the middle space though equally between the button and the nav bar well I can use justify content space between so now if I refresh this there's our P element let's see let's maybe go in here so there's our div with the nav Clause that's our Dev with the class of history and there's our button so the spacing between all three is equal and no matter if I change this that space will always be equal no matter how big the browser is so I like that let's Carry On Let's also now maybe style the main section so the other section once again I'm going to use display flex and I'm going to use flex Direction column just to make sure they're all stacked over each other but this time I want to align items to the center so I'm actually aligning them from left to right because we've changed axis of display Flex if none of this makes sense please do check out my full stack developer course where I go into this in a lot more detail as flexbox can be quite confusing so that just means I've centered everything from right to left by using a line item Center and we're doing it from this axis as we've swapped the axis by actually making them a column so whatever direction we're going in if it's a column align items will be on the opposite axis great so this is looking good so far let's carry it on I'm also going to use text align Center to make sure that the text is in the center which it is but now in the bottom part is as well because at the moment it's being aligned to the left and once again I'm going to use justify content space between just to make sure that they are also spread out equally no matter how I make the browser that will always be at the bottom and this will be pushed to the top so I'm spacing everything out equally on this axis great so I'm happy with that the other thing we need to do is assign this a height so I'm going to go with height 100 of the viewport height so now that text will always be stuck to the bottom because we're taking the browser height into consideration next let's style up this text so it's a bit smaller and more transparent so we gave this the class of info so let's pick out this whole element the hobby element by the class name so I'm just going to grab the class name of info and I'm going to make the color of this a transparent so I'm going to use rgba I'm going to go with white and then I'm going to put 0.5 opacity so to make it consistent you might want to consider changing these to be rgb2 just so that we don't have hex colors and RGB colors in the same project so I might leave that as something I will do at the end next I'm just going to also change the font size to be 11 pixels because I want it to be a bit smaller and I'm also going to Pat it out I'm going to do 10 pixels packaging all around so now my text will look like that that is much more like the website wonderful let's carry on I think Nexus also maybe uh style what should we style next I think let's style the input itself so this thing right here so I'm just going to grab the input element I'm going to get rid of its default border so I'm going to go with border none and let's go with background color again I think let's just use this color so like a transparent white I'm going to make sure that the width is 100 of the pound container the font size is going to be 20 pixels let's Pat it out I'm going to pan out 12 pixels from the top and bottom and 15 pixels from the left and right and just round off the edges slightly so I'm going to do broader radius 5 pixels and now I'm going to do Buddha radius 5 pixels just to round off the edges oops don't forget to have that syntax right there okay and finally I'm just going to add a box Shadow because who doesn't love a box shadow and this time the color I'm going to go with this RGB black so that's black but I want to make it transparent so I'm going to go 0.05 and add a here to give it opacity I'm going to go zero pixels x-axis 54 pixels y-axis 55 pixels blur uh we don't need pixels here if it's zero so we're just going to get rid of that and we're going to Overlay with another color so actually I'm just going to maybe copy this as we're gonna have the same color however this time I'm gonna go minus 12 pixels here and then 30 pixels blur and then again the same thing so I'm going to paste again and this time I have zero four six so I'm just overlaying different box Shadows to get a desired effect that I want and zero 12. 13 and maybe let's have one more so 0.09 this time and this time minus three pixels y-axis 5 pixels blur so that is my whole box Shadow and the fact will be this and if I type in here that will happen we can get rid of this blue line in fact I'm gonna do that because I really don't like it so I'm gonna say that when the input is focused we're gonna do outline none so now if we look in here I have gotten rid of that so much better great now this input is stretched out 100 of its parent which is the input container or the input container I also want to be stretched I want to make it bigger so let's grab the input container so the element by the class name input container and I'm also going to make that 100 percent width of its parent I'm also actually going to assign a Max width so it's going to try to be 100 but then it's going to stop at 650 pixels okay great this also means that the parent of the input container needs to have some sort of width assigned to it in fact we can go and actually domain a width so let's go make sure that the main element is a hundred percent and now the child of Maine is bottom section so if this is 100 next I'm going to get the bottom section and also make sure that width is 100 percent great and now let's Center everything so main already has display Flex on it so we're gonna have to get the bottom section and make sure that everything in the bottom section is also aligned in the center so let's use display Flex so I'm going to do display Flex Flex Direction column justify content Center align items Center again if flexbox is so when you haven't covered before please consider checking out my full stack developer course where we go into this in a lot more detail so great so now everything in the bottom section is also centered how good is that and if we kind of make this as big or small as we want it will always be in the center wonderful so let's carry on just a few more styling things to do before we can continue so next I'm just going to style up the input container and submit button so for this I'm going to actually go in here and put in a text symbol so it's this little arrow right here that I've taken off the internet that's a text symbol if you want to get your own I mean I'm just going to Google it so you can see you can get it from here so just copy that that is the URL that you would need so now if I refresh this there's a little text symbol wherever I want it here right I want it to appear on the actual input itself which is why I put them both in an input container so that I can position them thanks to position relative and absolute so let's give the input a position relative relative to the whole page so we can use position absolute on these two things to position them based on the parent so let's do it again this is something that you can learn in my course so input container let's give it a position of relative so that we can give the children a position absolute to position them and I'm going to get the input container or the element by the class of input container and say that if an element with the ID of submit lives inside of it that is the Syntax for doing so I'm going to give it a position of absolute okay so now if I refresh this that shows up here and now I'm going to position it in relation to the input container so I'm just going to go right zero so it should appear on the right zero so if I save that there we go and I'm going to move up from the bottom 15 pixels okay so the from the bottom of the parent element so let's go bottom 15 pixels so now that should appear right there and again it will move based on the input container so the parent the other thing I want to do is change the cursor so that it's obvious I can click on it so I'm just going to add cursor pointer just like so and save that and now my casa will change so that will appear the icon click on this great we are so nearly done I'm just going to style these things a little bit more so the button the history and the nav container so let's do it so the button itself I'm just going to give it a border of solid 0.5 pixels and it will transparent white so we know that's two by five two five five two five five zero point five I'm going to go with a piece of T and then the background color let's go a transparent border radius five pixels padding 10 pixels and margin 10 pixels to space it out from everything else so with that styling this is what my button will now look like that is much more like the actual website and the nav well I just want to line above it really and to space it out a bit so I'm going to get the element that has a class name of nav we could have maybe used the nav element but you know that is up to you okay maybe let's just switch it out semantically that would probably make more sense so if we go ahead and get rid of this whole class and just use enough element instead that is also an option okay and that just means I can pick up the whole nav element and I'm going to give it a border top of solid 0.5 pixels in fact it's going to be the same color as this so let's pick that out oops just make sure that's a 0.5 so now that will look like this I just added a line and I'm just going to space it out so once again let's just add the same padding and margin that we did for the button and finally let's grab the element that has the class name of History also give it the same padding and margin and I'm also going to use display Flex to make sure that anything I put into it because I'm going to be putting stuff into it with JavaScript it's going to be stacked on top of each other so I'm going to use flex Direction column and I'm also going to make sure that it takes up 100 of the height that it can great next I know that I'm going to be putting P elements into this history so we're going to be using JavaScript doesn't just put elements in here we're going to be injecting elements with JavaScript and those are going to be P elements so I'm going to say that any P element that I put that lives inside an element with a class of History so that is the Syntax for doing so I'm just going to make sure that you can point on it so I'm going to put Casa pointer and there we go so our CSS is now done now time for the part that I'm sure you've been waiting for and that's using the chat GPT API so let's do it so I'm just gonna head over to openai.com of course you have to sign up this will be a free service I believe up to a certain amount and I'll just opened this up a new browser so we can differentiate so here is the URL that you need to be in as you can see I am logged in is platform.openai.com Introduction and if you go to API reference all you're going to need to do is get your open API key so under authentication if you actually visit your API Keys here you can create a new key so this is one I made before let's go ahead and create a new one so this is the thing that you need to keep safe okay because if you attach a credit card to this someone will be able to take it and rack up loads of money on your credit card or even if you don't maybe someone will use it and then you won't be able to use any free Generations anymore so keep this safe and of course we are putting in this in our project but please don't upload this onto GitHub or share it with anyone this is just for demo purposes if you want to learn how to actually deploy this app and keep your API Keys safe then we'll do that in the next video where I show you how to make the same thing but in react by building out a node.js backend okay again as I said you can build out a front end in JavaScript and use a node.js backend too so both options are viable okay so let's carry on so once we have that API key well we're actually going to go back to API references and we're going to look at completions so click on completions because this is the URL that we're going to have to post to so that's what we're going to do along with passing or along our open API key thanks to an authorization header and then as well as the text or the prompt that we want to pass on to the open AI API so let's do it I'm going to show you how so in your app.js file I'm going to save this as API key I will be disabling this so don't try to use it because it won't work I'm just showing you this for now I'm just going to put in this texture so it's super obvious to everyone not to deploy it or upload it onto GitHub next I'm going to write a function this is going to be an async function okay so you can write it like this if you want or you can use const it's totally up to you you can make it a function declaration or just a functional expression that choice is yours and I'm going to use get message I'm going to call it get message because that's essentially what we are doing and I'm going to use try and catch to try do something and catch any errors so this is the Syntax for this if you haven't seen it before this is how we can make a calls now I'm gonna hook this up to the submit button so if we click on this div with the idea of submit I essentially want to make that call so let's pick it out so all I'm going to do is go const submit button so we're saving it as submit button so you can use it in our Javascript file I'm going to look in my document look at my whole document for an element so I'm going to use Query selector I'm going to look for something by the ID of submits that's what this will do oh look at my whole document and look for an element that has the ID of submit so we can use it in our Javascript file so I'm going to get that submit button I'm going to add an event listener and say that if I click on it then I'm going to call the function the async function get message okay so that's what that will do so for now if I just console log clicked and then let's go back to this and click on this little thing and check our console it says clicked if I click it again two three four you'll see how many times we are clicking it so that's all I have done so far now let's get to actually passing stuff on to the API so what I'm going to do is well we're going to use the fetch keyword right so I'm going to use a weight fetch it's an async method which is why this is an async function and we're going to await for its response so we're going to await it and await an async keywords live together if I use a weight that means that that function needs to be an async function so again check out my course if this doesn't make any sense now I'm going to fetch well this is what I want to fetch I want to make a post request of this URL so let's grab this URL because we want to create completions we don't want to you know create images or anything like that even though we can but not for this project that's not what we're going to do so this is the URL that we're going to do is go into the chat and the completions okay so make sure to have that one right there chat chat completions this is the full URL and it's a post request and this we're going to use this okay in order to uh create our own post request so we're going to have the content type we're gonna have the authorization the model and the messages so let's go ahead and do it let's create that data that information and I'm going to Define it under options so let's define our options console options and we're just going to literally be taking that information so what I'm going to do is pass the method we know it's a post method as we just saw that making sure that is like this I'm also going to pass through the headers which we also just saw the headers are going to be authorization so let's grab that put it in here and then we're going to do back stick so we can write code in here because we're going to use our API token so dollar curly braces is how you'll put in code and I'm just going to pass through this API key so that's all I am doing next what else do we need we need to pass through the content type so content type and that is going to be once again I'm just going to paste it because I'm lazy application Json so that is how you would read what you are seeing here in order to create your own uh API call in your code we're also going to have to pass through some more information so essentially what model we want to use and the message we want to send over so I can just copy this essentially maybe let's do that and let's do a comma here and do body and then whoops we don't need two of these so body and then just paste it like so so great we have the model where you can use GPT 3.5 turbo silhouetting gpg4 or access to it we're going to have the messages in fact we don't need these we can actually get rid of that just like that same four that uh same for the Raw and same for the content the content though we can pass through the string of hello or we can pass whatever we put in our input so we will do that and we can also put the maximum number of token words the bot should return if we want uh or we don't have to so you can put Max token um if you wish but I think let's just leave it actually maybe let's do it just so you know how to do it if you want to limit the tokens so max tokens I'm gonna go with 100. okay and I think we just need to pass this through Json stringify just to make sure it's Json so I'm going to pass through that whole object like so wonderful so that is looking good okay so we're making the API call we're passing through the options so all the information it needs which is all of this now let's get the data so we're going to use a weight I'm going to await the responses Json so just like so and then once we have that let's save it as the const data okay so essentially it's doing the Fetch and then we're waiting for the response so let's save this under response and then when we get the response we're going to get the Json from it but uh oh this is actually an async method which you might not know but it is which is why we need to await it again and once we have it we can save it under data and once we have data I'm just going to console logout data for you great uh and now let's catch any errors I'm just going to pass through error and I'm just going to console error the error okay let's test it out well we can just do hello so that just means that let's refresh if I click on this it will make the call and we're just waiting for it and amazing we've just passed you hello and then this whole object comes back we're going to go into the object get the choices go into the first item in the array and get the message so the message is hello there how may I assist you so that's essentially what we want to show in the uh in the browser right so instead of just console logging out the data what I'm going to do is pick out the output element so this PL right here by its ID so let's look in the whole document again document we always selector this time I'm going to look for the ID of output let's save it as output elements so I'm just going to get that output element and I'm going to use text content to get the data however go into the object get the choices as I said go into the first item of that array get the message so let's have a look here again so we're gonna this is data right that's what we saved as data we then go into choices get the first item of the array as an array so it goes zero and get the message dot content so we're just gonna get that first uh item back each time so great let's check it out I'm gonna try once more so obviously this is just sending the string hello and then we should see hello there how mercies used today so this is looking good of course we want to send our own messages not just hello right so let's carry on one thing I also want to do is just save it as the history so if this exists right because we don't want to say empty strings we just want to make sure that if something exists then what I'm going to do is create a p element document create element and I'm going to create a p element so a paragraph element or maybe let's make it now let's make a p element that is fine uh and that P element I'm going to get the text content and I'm just going to get whatever we actually wrote in the input so actually maybe we should do the input first I'm just going to comment this out for now I'm going to pick out this input foreign query selector input we only have one so it's fine for me just to pick out the whole input and let's save it as input elements and instead of passing through hello I'm going to get input element value so whatever value that input has will be passed through and also I also want to pass it through to history so if a message comes back to us and it's successful I want to get the input elements value and just essentially add that text to the P element we just created however I don't remember this P elements just floating around we can't see it I need to append it to the history element so let's pick out the element by the class of History document query selector class of History so dot is class and let's say this as history element and I'm going to get the history element and I'm going to use a method called append to put in that P element so once again if text comes back to us from the API then we create a p element we add some text to it which is essentially whatever we put in the input and then we get it and we put it into the history element so that's all I have done for now so if we have a look at this let's put in something uh what can I ask it what day is it question mark and send this we wait okay oh it does not have I would have thought it would have tell me what day it is but it has not and we get that in the history okay so if we look in here the hist the div with the class of History which before had nothing in it now has a p element with the text that we wrote in here right so that is pretty cool and if we of course add more that will be appended to that as well so this is all looking wonderful so far we have done a lot whether we have a few more things to do if I will click on this I want to bring back the prompt and if I click on here I want to clear this input so let's do that next let's pick out the buttons so document query selector button there's only one so this should be fine what should we call this I think we should just call it button element as there is only one in this project so I'm going to grab the button element let's just do so down here and I'm going to add event listener and if I click on it I want to clear the input so let's write a function called clear input let's do so maybe up here function clear input and I'm just going to grab the input element get its value and just override it with an empty string so that should now work one last thing I'm gonna do is also add an event listener so if we click on anything in here it brings it essentially gets that text and puts it back in here so let's do it I think as soon as we create the P element right and we put in the text I'm also gonna add an event listener to it that says if we click on it all I want to do I'm going to make this a callback so just we can we so that we can essentially pass stuff through into a function that I'm gonna call change input so into here I am well let's actually maybe just pass through the P elements text content as that's what we're going to want to change it to and let's define our function so let's define up here function change input and then we're going to pass through a value that value is essentially what we want to change the input to uh and what I'm going to do is use document queries selector to look for the element of input again so whatever the freshest value of it is so if I'm just going to save it as input element for now and get that input element value and just assign it the value so there we go I think we have done it I think we've built our own chat GPT clone let's give it a go so let's ask it something else how are you today send and wait for that to come back okay so there we go we are getting some text to come back to us and it gets saved up here and then if I go what can I ask it now what is four plus two and send that over the answer is six and then if I click on here that will get back the same question so I don't have to type it out again as you will see that's updating and if I click on here that will or should clear the input why is that not working let's inspect here let's have a look in here uh We've misspoke value while we are here I'm just going to change the opacity of the input to be much more like the actual thing and I should also check that the input value exists and if the input value exists and the message that contacts exists then I only wanted to put it in the chat history so there we go let's try that again let's refresh what is six plus two and that should give me the response how old are you question mark and that should ask it the question and then I can bring back the previous input as well as clear this so we can start again great so I hope you've learned something new I hope you've learned how to use the chat GPT API or in other words the open AI API that powers chat GPT as a beginner it could be quite frustrating when you want to use this but you haven't learned react yet so that is how you would do it for your own personal projects if you want to level up check out my video on how we build the same thing but in reacts next
Info
Channel: Code with Ania Kub贸w
Views: 34,208
Rating: undefined out of 5
Keywords:
Id: 05ssqx-SZT0
Channel Id: undefined
Length: 45min 27sec (2727 seconds)
Published: Tue Mar 28 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.