 now on my computer. Okay, great. Yeah, so once again, Kevin will be showing you us a little bit about how to create your own Facebook Messenger bot using a Vonage API. So today most of our practices will be done with Node.js and make sure you have your editor and stuff set up. Once again, if you haven't signed up for the developer account, I'll just share the link again. Go check that out and use the coupon code to redeem your free credit speech. I think I also understand you also lift the limit on your account when you get the free credit, so that'll be helpful later for the tutorial. Right, and now I'll hand it off to Kevin, who will walk us through the rest of the day. Hello, I'm just going to check. I need to reshare my screen, I believe, so let me go ahead and do that. What am I sharing? Can you see my screen? We can see your browser. Oh, okay. There used to be a little border on it, and it's disappeared, but I'm glad you can see it. Hello, everyone. My name is Kevin Lewis, and I am a developer advocate at a company called Vonage. Now, you may previously have heard of us as a company called Nexmo. We are now called Vonage, but that's why in a couple of places you'll still see the Nexmo terminology, but we are now firmly Vonage. We are a cloud communication platform that lets developers integrate voice, video messaging, and security into their applications using our APIs and SDKs. Our goal is really to give you a set of solid foundational building blocks to integrate communications into your applications, and then let you do that in whatever way you feel happiest. We have a set of APIs sending and receiving SMS messages, programmable voice, which is not only voice over IP, voice over the web, but also traditional phone numbers that you can rent from us and then write code to power, programmable video. Two-factor authentication can sometimes be a bit tricky, but we've turned it into quite a pleasant to use API, actually one that I underestimated. And the first time I used it, I was like super blown away at how easy it was. And a whole bunch of other APIs. Today, we're going to be using the Vonage Messages API that lets you send and receive messages with SMS, Facebook, WhatsApp, and Viber using a single API. So that's pretty cool. So just by changing a couple of keys in an object in your request, you can send using different platforms. Today, we'll be using Facebook, but the exact same code would stand should you be using WhatsApp, SMS, or Viber. So that's pretty cool. So yeah, that's what we'll be doing today. We've got plenty of time and I have the chat open. So if you have any questions, by all means pop them. And as and when I can, I will answer them for everyone. While I'm here, I'm going to do a quick shameless plug as well, because I think it's particularly relevant to this audience. I also run a conference series called You Got This, which is all about core skills, sometimes called soft skills that you need to kind of excel in your tech career. There's currently almost 50 talks available for free in the talk library. And I recommend that you go and take a look at them because some of this stuff is like super, super valuable, also regardless of where you're at in your career. Right, enough of the shameless plug. Let's talk about what we're going to be doing today. Today, we're going to be building a Facebook bot, shock horror. I think we kind of knew that one. We'll be putting a Facebook bot using the Vonage Messages API. It's not going to be a clever bot. It's not going to do anything to advance. But what it will do is take messages that are sent to a page, store them in a database, and then when a user sends a specific command, I think we're going to use the word recap. We'll go and get all of the messages from that user and just send it back to them. However, when you receive messages, you can do anything. You can go off to third-party services and APIs and then respond. You can start conversational flows. You can use machine learning platforms to understand what the user is asking for. But today, we're very much going to focus on the foundational part of building bots, which is getting messages in, storing them, and replying to them with specific functionality on certain commands. You don't need a lot of technical skill to take part in this workshop, but we are going to be doing it in JavaScript. A bit of JavaScript, if you know it, will be useful. You need to have Node.js installed before now. If you don't, this is your kind of five-minute warning, I guess, to go ahead and do it. Node.js.org, download the latest version. I always recommend the LTS, the long-term support. Install that, and we'll need that to run some of our code today. You're also going to need a code editor. I'm going to use Visual Studio code here. And you'll need access to a terminal or command line. I'm going to use the one that's built into Visual Studio code here. You're also going to need a Facebook account, and you are going to need a Vonage API account. So if you haven't already got one, you can click Start Building for Free here and sign up for an account. And then in the Zoom chat, I'll paste it just once more. I think at this point, most people here have seen this, but you can go ahead and sign up for an account. There's a coupon code that will give you 10 euros of credit, and it will also lift the initial restrictions on your account, which means after this workshop, you can also play with some of the other APIs we have. Right, let's get to it then. Open your code editor and create a new folder for this project. I'm going to just create one on my desktop here, and I'm going to call it, there we are, I'm going to call it Facebook-bot. I'm going to recommend you don't put spaces in it. I'm just going to drag that into Visual Studio Code to open it. So here we are, we've got this empty directory to work with. Now, when we run applications on our computer, they're only accessible via a local host URL to devices that are on our local network. But for our application to work, the Vonage API platform needs access to our application via a publicly accessible URL, because obviously we can't see as Vonage what's happening on your local network. So we're going to use a tool called ngrok to make that work. Open up a terminal, and this is a terminal you're going to want to keep running throughout this workshop. And we're going to type in the following command. So when we enter in a moment, what this is going to do is use the ngrok platform to provide a publicly accessible, temporary URL. And when people access that URL, all of their requests will be sent to our local host application. This is going to save us having to constantly go and upload this application somewhere on the public web and restart it. So let's hit enter, npx ngrok, http 3000. And you get this little dialogue here. So it's given us this temporary URL. We'll want to take note of that for later. And any requests that come in here will get forwarded to our local host application running on port 3000. We don't have an application running on port 3000, so we'll need to build that. Just a note, if ngrok stops running and you rerun it, this URL will change. So it's important to leave this open. And if you do restart, I'll point out where, but you'll need to update this value in a couple of places. I'm going to click plus here to open another terminal. So that's still running in the background. And then we have our kind of working terminal here, which we'll use in just a moment. So we've got our empty directory. We've got our terminal here. Our terminal is inside of our directory. If you aren't using the baked in terminal here, oh, you're not in the same directory that is open in Visual Studio Code, you'll want to move into that directory. Just a reminder, if I go back to my home folder, in order to do that, we type in cd for change directory space. And then wherever this folder is, for me, it's on the desktop and then Facebook bot and hit enter. And that'll move us into the folder. Sweet. The next step is to go and create a Vonage API application. So let's go back to our browser and go to start building for free. This is your point to sign up or sign into your account. And you'll end up here on the Vonage API dashboard. And just a reminder for everyone, I have my eye on the chat. So if I'm going a little quickly or you have any questions or issues, by all means throw them in the chat. So what we want to do is set up a Vonage API application because we can set up many applications within our Vonage API dashboard. So we're going to go to your applications here and create a new one. You can give it any name you want. So that's what I'm going to call mine, SG Juniors. And you'll want to generate a new public and private key. Oh, so, yeah, so I see Ngrok installation takes time. Yeah. So when you run MPX, what it actually does is exactly as was posted here in the chat, it will go off and grab the files needed. And then without installing it, it will run the application. Sometimes that takes just a moment. I'm going to finish the explanation of this part because you can be doing what we're doing now while Ngrok installs. And then our pause. And Steve, if you don't mind, it would be great if you tell us when you are, when you've got it installed. And if anyone else needs a moment, by all means, let us know. And if it's taking a couple of minutes, then I'll move on in the interest of time as this is being recorded. So the next thing we want to do is generate a public and private key. So we just click this button. I see that you have got Ngrok now, which is great. And it will ask to download a private .key file. Make sure you save that. And that's currently in our downloads folder, but we will want to move that into our application directory. So let's go and do that quickly. So we've got this private key here. We've got this Facebook bot folder here. So we're just going to drag that in. So that's now in our Facebook bot folder. So let's talk about what these keys are for. Well, actually, we don't need to spend that long on what these keys are for. We're going to need the private key to authenticate ourselves with the Vonage API platform in our code. That's basically it. So it needs to be in the folder where our code lives. Now, this application can have a number of capabilities. We can do kind of phone calls and voice over IP. What we want here is the messages API. So we turn that on and it requires two pieces of information. It requires two publicly accessible URLs, a spoiler. We're going to use Ngrok for this. So it pipes it to our local application. So what are these two URLs? The first one, inbound URL, will receive data from the Vonage API platform every time our Facebook page receives a message with information about that message. So that's what the first one is, inbound URL. Status URL, what that will do is, when we send a message, there's quite a few states that that message goes through. It's been sent, it's been delivered, it's been read. The status URL will receive data from the Vonage API platform to keep you updated on the status of your messages. We're not really going to use the status URL too much today, but we do need to provide it and we do need to build it in its most simple form. So what are we going to do here? We're going to pop our Ngrok URL. So let me go back to my Ngrok terminal here and copy this HTTPS URL. So copy that and we'll pop that in here. At the end of it, we should type in slash inbound. So what this will do is send an HTTP post request to this URL, which is equivalent to localhost 3000 on our machine slash inbound. Whenever we receive a message, and exactly the same on the status, paste your Ngrok URL, but this time we'll go slash status. So let's just recap these settings, give it any name you want. It doesn't really have a bearing. Generate a public and private key. Your private key you should have moved into your project directory. We've turned on messages. In inbound URL, we've put the Ngrok URL, which pipes messages, which pipes request to localhost 3000 slash inbound on the status URL, which will give us updates when we send a message slash status. Let's hit generate new application. And that is our application generated. Now just as a note, this application ID here, we're going to want that later. I'm going to copy it, but you may well need to come back here later to grab that if you don't have it on your clipboard. So you can get to this page, your applications, SG juniors, and this is our application page, which also has details about our webhook URLs. Now we're actually almost at the point of being able to write code. The last step is to actually link a Facebook page to this application. Now we have a really nifty feature called the messages sandbox. So in the sidebar, if you go to messages and dispatch, then you click on sandbox. I really like this. I didn't use it until quite recently, but it's really cool. So instead of needing to sign up for your own Facebook page to test this, the sandbox lets you use our page to test this. So here's how it works. But here's what you need to do in the Facebook Messenger section. There'll be a button that says add to sandbox. And when you click that, it will pop open in a little view like this. There are two things that are important here. The first is this link, which you can also scan from your phone and use on your phone, if that's how you're going to use Messenger, but you can click on the link and that will take you to a brand new message on Facebook with the Vonage sandbox. The second thing that's important is this three word passphrase right here. So you can copy these three words and what you do is you just send it as a message to the account. And what that does is it makes, is it kind of links your account with this application based on those three words, which means we have hundreds or thousands of users all using the same sandbox, but because they used a different passphrase, their applications are linked to different accounts. It's pretty cool. So you want to go to that Facebook message and type in or copy these three words and send a message. If you hit refresh down here, you should then see you have one user white listed, which means everything is connected correctly. Now I'm going to give you a moment to do that. This is a moment where I'm going to encourage some participation. Just come into the chat and let me know you've done that. Okay. Let me know if you have issues. I'll wait just a moment. And I will wait for a few people to tell me that before I move on. Thank you, Owen. Owen's got that sorted. Brilliant. Thank you. I think we're good to go on. I think we're good on time. Excellent. People have got it. Thank you. So now our application is linked or our Facebook account is linked with the sandbox. At the end of this workshop, I'll show you how to get this set up with your own Facebook page, but it really is not a lot of additional work. I'm impressed with how easy this part of it was. Now, if we scroll down this page, we have to provide two more URLs specifically for the sandbox. Now in this case, we're just going to use exactly the same ones, exactly the same one we used for our application. So your ngrok URL slash inbound and our ngrok URL slash status. And then we'll hit save webhooks. And I'll give you just a moment to do that as well. Now, I'm not going to scroll down any further in this page because if I do, you'll see my API key in secret. But there is actually a code snippet just below here. If you just want to open up your terminal, you don't have to do this. Thank you for joining us, Ryan. Have a great day. Hope everything's okay. If we weren't building a complex application and you just wanted to check everything worked, you can copy the whole request as written in this black box just here at the bottom of the page. Paste it in your terminal and hit enter. You don't have to do that. It's not an important step for this workshop, but the code is there. But we're going to use a Node.js library for Vonage to get this to work. Now, this is everything we need to do in the setup. And in fact, I think it might be the last time we need to touch the dashboard, apart from at the end where I'll show you how to link your own Facebook page. So let's just recap what we did. We have set up the sandbox. Locally, we have set up ngrok. So we have a public URL which will go through to localhost 3000. Alfred, no, it doesn't actually matter where you kick ngrok off. It can go anywhere. It will just indiscriminately look for applications running on port 3000. Owen, do you need to hit the save webhooks button? Yes, please. Once you've done this, just hit save webhooks and you should get this little success dialogue up at the top. So we set up ngrok locally. So our application can actually get, so the Vonage API platform can actually send data to our application. We set up a Vonage API application with our ngrok URLs. We set up the Vonage Messages API sandbox here so we can use this page instead of our own. And again, I'll show you how to set up your own at just the end. And we've also downloaded our private key from our application and popped it in the Facebook bot folder. So we're now firmly at the point where we can go and start writing some code. So go to your code editor, open up your terminal, and we're going to start in the terminal. We're going to grab our dependencies or install some dependencies. So a couple of commands we're going to need to do this. In fact, let's just take a step back and talk about installing packages in general. So NPM, or the Node package manager, contains thousands of packages that developers have written, which we can include in our JavaScript projects. And in fact, our own Vonage Node SDK is available through NPM. Instead of including tens of thousands of lines of other people's code, when we share the project, we can store the packages we want in a file called packages.json. We can just list off all of the packages that we want to install. And then developers can install those packages using this one file as a reference to what needs to be downloaded. So we want to create a package.json file that we can then describe our dependencies in. And we can do that by opening up our terminal in the Facebook bot directory and typing in NPM space init for initialize space dash y and hit enter. And what that does is it creates a new package.json file for us with all of the default answers. If you leave off dash y, it'll ask you a bunch of questions. Typing in dash y just answers default with all of them, because for this, it doesn't really matter terribly. Thank you for joining us, Nicholas. So now we're going to go and install all of the dependencies we need for the whole workshop. We're going to install them, and I'm going to explain what they will do, and we'll get to see them each in play as this workshop progresses. So let's type in NPM, space, install, space. And we're going to install express space, body dash, parser, NEDB. And again, I'll explain what each of these do while they install space and the at sign, Vonage, forward slash server, and I'll pop this in the Zoom chat as well, dash SDK, and then the at sign again and beta. The reason we're going to install the beta is because the message's API is still in beta, so we need the beta version of the SDK. Hit enter, and that'll go. I'm going to copy all of that. I'm just going to pop it in the chat here, and I'll give you just a moment to install all of those while I explain what each of them do. So by installing these packages, they get added here to the package.json file, so it's the name of the package and the latest version, as we can see there. So express.js is a web application, which is a web application framework for Node.js, so we can build web applications more easily using express. BodyParser lets us access data sent to our applications more easily as well. The Vonage server SDK for Node.js gives us an easier way to interact with the Vonage APIs. So what this means is we actually have, as Vonage, let me pop over here, we actually have an API that you can use without installing any dependencies. So each of these API calls comprise of a method and a URL, all of the information you need to send along, and any authentication details you need to send. Using the Node.js SDK, we can interact with this API in an easier way, and if you've written JavaScript before, we'll be writing it in a more JavaScript way as well. Finally, NEDB is a simple file-based database. What that means is when we start using it, there'll be a little file that pops up in our directory, and it'll be that file that contains all of the data from our database, and we'll read right to that file. It's not really suitable for anything serious, and it's used in a very similar way to MongoDB. So if you want to move later and use this in the real, moving from NEDB to MongoDB isn't a huge step, but we're going to keep it light today. Right. I hope everyone's got those dependencies installed. This is your chance to come into the chat and tell me that you haven't got them installed, but we are now going to write some code for the fact that no one's told me they haven't got it installed. I'm going to assume we're all good. So let's create a new file, and this will be the way we do all of our application logic, and we'll call it index.js. So the first thing we're going to do is set up our web application with Express and BodyParser. So the first thing we do is create a new app, const app. I'm not sure if you will be at the point where you've kind of experienced const, const, let, and var. Const is a way of creating a variable that will not change later and cannot change later. You may well have seen var or let. It doesn't really matter for this workshop, but what I do is I always use const unless something needs to change, and then I'll use let. So const app, and what we'll do is require express and initialize it with the default settings. So what this will do is go grab all the functionality of the Express package, initialize a new instance of an Express application, and store that in a variable called app. Next, we're going to, we're going to include bodyParser, require body-parser. None of these extra brackets on the end, sorry, const bodyParser equals. Oh, Butterfingers this morning. There we are. Now just as a note, you'll notice that I'm using body and then the capital P, this is a convention in JavaScript. A dash is not a valid character inside of variable names, so we'd leave that off. So that is us requiring bodyParser. Yes, and it's called camelCase. There's a whole set of variations, so I think bodyParser awesome. I think this is called kebab case. Anyway, yes, it's called camelCase, lowercase, first letter, and every subsequent word has an uppercase. Next, we're going to actually tell our Express application to use bodyParser. Now, there are two lines of code we need to do this. I'm going to type them in quite quickly, then I'm going to copy and paste them into the chat. So we're going to tell our application to use bodyParser, bodyParser.json, and we're also going to say URL encoded, and then put in here extended, true, like so, bodyParser.json, round brackets, bodyParser.url encoded, rounded brackets, and inside of that is an object with extended, true. So let's pop all of that in the chat here. These are lines of code, these two that I almost always end up copying and pasting. So we've required an initialized Express, we've required bodyParser, we've set up bodyParser, and now we're going to start our web application that currently does nothing, but we are going to get it set up. So we're going to say app.listen, round brackets, and we can put the number 3000 in here. And this number here is the port that this application will run on. Now, you may cost your mind back now to when we set up Ngrok, we said send any requests to localhost 3000, we said MPX, Ngrok, HTTP, 3000. If that number wasn't 3000, if that number was 3001, this would also want to say 3001, for example. So this is the kind of skeleton of an Express.js application. Right, let's set up our inbound and our status endpoints now. Remember when the Vonage API platform receives a Facebook message to the sandbox page and later our own Facebook page, it will send a request to our localhost 3000 via Ngrok slash inbound. When we send a message, it will send updates to slash status. And you may remember these were, where is it? HTTP post requests. So this web application will have a number of endpoints. Each of the endpoints will contain a path such as slash hello or slash inbound, slash status, and a method, which in this case is post. And when an incoming request matches that method and that path, collectively known as an endpoint, a function, a set of code is going to be run. And that will be our custom functionality. There are a number of supported methods, like HTTP methods. So we'll be using post. There's also get requests as well and several others. All endpoints should send a response, whether it is a success, whether there is an error, whether there is or is not data to accompany the response. There should always be a response. Now, when working with the Vonage messages API, as mentioned, there are two endpoints we're going to need to create. The first will be used when there's an incoming message that will be a post request containing the message information itself. And the other will be used when there's an update to a message status that we send. It's also a post request. It contains some information. And remember, you always need to respond to requests. If you don't send a response to a request that the Vonage API platform sends you, the data, it never knows that you received it and it will constantly try and send it, which means you could end up with multiple messages in your database that are actually the same. Right, enough repetition. Let's get on with it. So we're going to build these route handlers, is what they're called, just above this app.listen line. So this should be the last line. So what we do is we say app.post, and that's because it's a post request, app.get would be a get request, but we're going to do a post request. Brackets. Now, the first parameter, the first argument, the first option, is going to be a string which contains the path. So in quotes now, forward slash inbound. So this route handler will be triggered whenever we get a post request to slash inbound. So the other side of that close quote now, comma, we are going to write a function that will run when this endpoint is hit. Function. And this function has two parameters, request, and request contains all of the data that is sent to us from Vonage. The second argument is response, which is something that we need to prepare and then send. Fantastic. All we're going to do is we're going to console.log.request.body. So the whole request, everything to do with the request, every tiny little bit of metadata is inside of an object called request, but the data that sent along is in request.body. And it's in request.body because we have included an initialized body parser. Makes it way nicer to work with. And then remember we have to respond. So we're going to send a very basic response. It almost doesn't matter what it is. We're going to say response.send and then inside of brackets and quotes, just okay. But what this will do is let us see what the request is. So to recap, when we get a post request to slash inbound, this function will run. This function will just console.log. The data that came to us from Vonage. And then just respond. So the Vonage API platform knows that we received it. Let's just copy all of this and duplicate it and just change inbound for status. Hit save. And now we're going to test this out. We should now be able to see something, which will be quite exciting. So we've set all of this up. We've got our two route handlers that should receive data when we send a message to this Facebook page. Inside of Facebook bot now, inside of your terminal, sorry, let's start this application. Node space index.js. Hit enter. And your terminal should just hang. It's a web application. It continuously runs. So that's good. If it's erred at this point, there's a problem. So before we test this, I'm going to give you just a moment to come into chat just a few seconds and tell me if there was anything that doesn't look like this, basically. If there was any error that may have occurred. Things to watch are things like brackets. Sometimes it'll be things like misspelling log, little bits like that. Let's go test this out. Let's go to the Vonage sandbox, which we should have already whitelisted our account. We can type anything we want in there. Hello. Nice to see you. I'll just bump that up. Hit enter. Now, we shouldn't expect anything in response. But if we go back to our terminal, you should now see a set of data. This is your chance to come into chat. Let me know if this worked. And we can, in just a moment, talk about what all of this data means. But come into chat. Let me know if it worked. Let me know if it didn't work. And if it didn't work, we can try and unpick it together. Excellent. Brilliant. Glad to see it's working for you. Let's talk about the data. Message UUID. It's a unique identifier for this individual message. Every message that you get sent will have a different UUID. Oh, and why does yours look different? Let us know. Yeah, it shouldn't look different at all. I'd be interested. I'd rather you didn't share your screen. You can describe the difference in the chat and we can relay that to everyone. So I'll keep going through the explanation while Owen shares the differences that they're getting. From describes the user account that sent you the message. Oh, excellent. So this is not just a little different. This is a straight up error. So what I'm going to ask you to do, Owen, is you're going to copy all of index.js and you're going to just pop it in the chat and I should be able to spot what it is. Hopefully, it won't be anything too difficult to fix. So this ID here is actually the ID for my Facebook page, like my personal one that just messaged this page. Every account has a unique identifier. Two, this is the ID of the Vonage sandbox. Oh, and you seem to have fixed it. Wonderful. Now, the message is the actual message that was sent. So inside of message, which is an object, we have a property called content object. It has a type of text. Remember, it's not always going to be text. It could be an image. We'll be working with text today and the actual message that was sent. And then finally a timestamp. This is exactly when this message was received. So that's this route handler slash inbound console logging. Brilliant. And Owen, just to clarify, I think you fixed it, right? You found the small type. I'm just wondering, whatever is in defunction, must it be corresponding to whatever is in the console log? For example, if you use request within the function brackets, within the console log, you have to use spell the entire word request. Exactly. Okay. So what you'll often find when you're looking at code snippets is, and when I write applications, you'll see people short it to rec and res request response. And if you do that, this must also be rec. And I think that's what God hung up here. When I run workshops, I generally full word them. So it's a bit more explicit. But yeah, this word here that's highlighted has to correspond here. Oh, thank you so much for just running through the steps we've done today. The private key, yes, came from when you created an application. I won't be going back there right now. But yeah, the steps are right here. Now, if you've created an application, actually, I will say this because this gets people, if you've created an application already, and let's say you didn't save your private key, you can hit edit, you can generate a new one and store the new one, you must hit save changes here. I have lost hours to not hitting save changes down here. So make sure you're doing that. Okay. So this is our incoming data. Now, the next thing we're going to do is actually store this message in a database, because right now the message comes in. And then, apart from it being here in our terminal, it vanishes from thin air. There are lots of databases available. Lots will be hosted for you on the web. In this workshop, we're going to be using a database called nedb, and it works by storing JavaScript objects in a file in this directory on your computer. I chose it because it's the most straightforward, but it can easily be swapped for MongoDB later. At the start of this workshop, we installed nedb as a dependency. So now it's time to require it and use it inside of our project. So let's include it up at the top. So I generally like putting all of my requires at the very top, then kind of all of my setup and configuration, then my route handlers, and then my app.listen at the bottom. That's just the way I do it. So up here. But just to be clear, you could quite easily write this code down here as well. It doesn't matter. But I'm going to pop it up here. So let's create a new variable called nedb, and we will require, in the same way we did bodypasser, nedb. This gives us all the functionality of nedb. Now we're going to go set up a database. So I'll do that down here in this kind of configuration section, create a new variable. I'm going to call this messages, but you can call it anything you want. You could just call it db for database. I'm going to say messages equals. And again, I'm going to copy and paste this into the chat. In fact, I'll do it first, and then I'll type it out. We are going to set up a new nedb instance. And in here, we're going to put an object with two options. The first is a file name. And this will be the file that all of our code, all of our messages are saved to. I'm going to call this messages, messages.db. You can call it anything you want, and it doesn't need to already exist. After that, we're going to create one more option, autoload true. And just remember, true does not have quotes around it. And this, as soon as the application starts, will make this database available to us because we are autoloading it. Now, when a message comes in, we're going to delete this console log. We're going to go ahead and we're going to store this whole object here, this whole object, which was request.body inside of our new database. This is how we do it. Messages, or whatever you've called this variable, messages.insert, and there are two options that we need to provide, two parameters. The first parameter is the actual data we want to put in the database. And the second one is a function that will run after that has happened, either successfully or unsuccessfully, a callback. So we could do lots here. We could pull out specific information from this object, because I think all we actually need is the timestamp, the text, and the account that sent us the message. But for this, we're just going to throw in this whole object. So we can straight in here, request.body. We could stop now. That will work. That will put data in the database. But we will want to do something once the entry has gone in, or once that's been attempted and failed. So after body, we're going to write a new function, two parameters, error, and record. Again, you can call them whatever you want, but this will be the data held in them. You will only ever get an error, or you will get a record. So first thing we should probably do is check if there's an error. If error, we will return. We're going to put the return word here, so it will end at this line. It won't continue this function. Return, we're just going to go console.error. Error. So whatever the error is, just pop it in our terminal. Hopefully, this will never happen and we won't see it. Maybe we will. We'll find out in a moment. After this if statement, we're going to write the logic that will happen if this application didn't return here, which means there isn't an error. And what we're going to do is console.log record, so we can see what happens there. So just to recap, messages or whatever our database is called, .insert, we pop our object in here, and then a function that we'll run after that has happened. If there's an error, we will stop the function running further. No more logic will run, and we will console.error the error. If this didn't happen, we'll just console.log the record. Now we need to restart our application. If we go to our terminal here, ctrl-c to stop our application running, tap up so it says node index.js again or type it and hit enter. That will restart our application. Now, just as a note, this application has just restarted, and you'll notice that messages.db got automatically created for us because it didn't already exist. If it did exist, it wouldn't recreate it, it wouldn't wipe it, but it would load it in so it's available to us. But that happened because of this line here. So let's go back to our page and type in another message. Can't wait to eat lunch. We're having a mac and cheese. Hit enter. Go back to our code. Look at that. Brilliant. Now, a few things have happened here. This happened successfully, we're not seeing an error. This is the data that got inserted into the database, so it's the whole record. What you will notice, though, is that there is this new property called underscore ID. NEDB automatically adds this value for us when we put data into a database, and it is a unique value for every single record. You won't have two with the same underscore ID. Even if we pass it to identical objects, the underscore ID will make sure that they are different. We don't really need to care too much about this, but just know that NEDB has done that. If we go into messages.db, we see that is our object right there, including our underscore ID value. Chat, let me know. Did that work for you? Because we're making really good progress. We can receive messages to a Facebook page and interact with them. All we're doing right now is storing them. We'll do more in a moment. Brilliant. This seems to be good. Fantastic. Steve, I'm glad you're no longer coding on a train. That is my personal idea of hell. Yes, I'm glad that's no longer where you're at. Right. We know that items are being stored in the database because as developers, we can go into the database and we can see them there. We can see the terminal. This is great for us, but our users, they have no idea what happened to this message. They had no idea that it actually was successfully received. We need to provide some feedback to them, both when there is a success, but also when there is a failure. To do this, we're going to use the Vonage Messages API. Up until now, we set up an application we've received messages in, but we've not actually done anything with our Vonage account details at all. Our time to do that is coming up. Let's do that. Let's require at the top the Vonage server SDK for Node.js. I'm going to call this Vonage with a capital V. I'm doing this to match our documentation. Require, and we're going to have to go at Vonage slash server SDK because that is the name of the package in NPM. As a note, when we installed it, we installed the beta by putting app beta at the end. That describes the version. The actual package name is at Vonage slash server dash SDK. The results are not coming up after I entered Node index.js. It worked earlier though. This is your chance again, by all means. This is a fairly small application, so you can always just grab your code, pop it here in the chat. We can look at it together. We can figure out what the issue is. I have eagle eyes for stuff like this. By all means, we can try and work that out. Okay. Let's take a look at this. App dot post slash inbound function, request response, great. Messages dot insert, request dot body, great. With a callback function. If error return console log error, otherwise console log record. Now that does look right to me. I'm going to ask you a few questions. Have you restarted your application? Is your application running? Is Ngrok still running successfully? You haven't restarted it because if you've restarted it, the URL will change. You'll need to go into both your Vonage API application and the sandbox settings and update the URL. This code though, I can't see anything wrong with it. I don't think it's this. Yeah. I'll let you troubleshoot that if you have other questions and or you get it working or you're still struggling, let us know. Just to recap where those URLs go in the dashboard, they go both in your application here and in messages and dispatch sandbox. To use the sandbox, you pop them here. Remember, if you restart Ngrok, this part of the URL changes, so you will need to go in and update those. We have required the Vonage server SDK. Now let's initialize it. Let's set it up. We're going to create a new variable called Vonage with a lower case V because remember JavaScript is case sensitive here. So const Vonage equals new Vonage with a capital V, brackets, squiggly brackets for an object and hit enter. There are four pieces of information that need to go here in order to configure this correctly. The first is your API key. This is going to be a string, which you can find if you go to the homepage on your dashboard by clicking copy here. So you can copy that, paste that right in. Now I actually have this available in a slightly different way just for me because I don't want to show you my key in secret. So Vonage in the code anyway, Vonage underscore key. But what you'll want to do inside of quotes is just copy and paste that value. The next one is the API secret. Don't let other people see your secret. It is a string. But if you do let other people see this secret, it basically lets them use your account, including charging credit to your account. So if people see it, you can go into your account settings and refresh it. You can get to it by hitting copy here and then pasting it in here as a quote. Again, I have this available in a slightly different way for the sake of this workshop. So your API key in secret will link this application to your account. There are two other things we're going to need. Your application ID. And again, note that camel casing I in ID is uppercase. And in here, we're going to put our application ID. So let's go get that your applications go into it and copy it here application ID. Just pop that straight in there. And then finally to authenticate with your account and your application. This is where that sneaky private key comes in. Private key capital K. And in here, we are going to put the path to that file in Node.js. To do this, we go dot slash, which means this current directory private dot key. These are the four things we need to set up your to initialize the Vonage server SDK for Node.js. Now, because we're using the sandbox, there was one final step that we need that changes things just very slightly. When we get onto showing you how to do this with your own page, this step goes away. But for using the sandbox, there's one final step. And I'm going to I'm actually just going to copy and paste a part of this in into the chat. Alfred's asking, could I repeat where to get each of the fields on the Vonage website again? Absolutely. On your dashboard home dashboard dot next mode dot com API key API secret. That's API key and secret and applications inside of the application we made earlier application ID and your private key you generated here. And if you don't have if you can't put your finger on it anymore, redownload it hit save changes and pop it in this directory as private doc key. That might require you to rename it if you downloaded it a couple of times. If you're uncertain, just regenerate it like you'll think time into going was it that one or was it that one or did I hit save? So is it that one or that one? So just regenerate it and pop it in here is private doc key. Hope that helps Alfred. So this final step after the API key secret application ID and private key object is to add a comma and one more object. Not that. We are going to put in an API host. I'm going to type this quickly. Oh, and you can get the application ID at the top of inside of your applications, your application and up here at the top is called application ID and there's a little copy button here at the side. API host to use the sandbox. I'm going to type this quickly and I'm going to copy and paste it messages dash sand box next mode.com. So I'm just going to copy this pop it in the chat. So this should go after this first object. And when you're doing this in the real, you don't need this step, but you do if you're using the sandbox. So I'll give you a moment just to make yours look like this. Remember, I'm doing process dot m dot Vonage key, but you'll just want to put your key here and same with your secret. Just in the interest of me sharing stuff, I don't want to share these values right now. Well, you shouldn't share them. So I don't want to share. So I'll give you just a moment to do that. So just to recap, we required it here. We're initializing it here. So in order to send a message with the Vonage messages API or send a Facebook message, you're going to require three pieces of information. You're going to require the Facebook page that is going to send the message. The in this case, it's the Vonage sandbox. You're going to require the Facebook page ID for the recipient. So that's my personal ID and the actual message you want to send. That's all we need. We're going to send messages in two different places. We're going to send them when there has been a successful, you know, a successful, you know, message received entry into the database and also one where there's an error. And because we're going to do this more than once, we're going to create a reusable function that we can use in both cases. So just above this first app.post below our Vonage initialization, let's create a new function called send message. There are going to be three pieces of information, sender, recipient, recipient. Yes, I spelled that right. And the actual text. We'll just open that function up. So as I said, we're going to need these three pieces of information. They need to be formatted in a certain way. So let's do that together. I'm going to go through this bit just a tiny bit more quickly. And then I'm going to take the whole function text. I'm going to pop it in the chat. So first thing we're going to do is create a value called two. This is the person who will receive the message. It's going to be an object with a type of messenger and an ID of whatever we've passed in as the recipient. Just note here, we're saying messenger. We could easily say Vibe or WhatsApp, as long as we have the correct recipient ID or phone number. We're going to do exactly the same for from type messenger ID of sender. Then we're going to set up a message. And this structure, by the way, completely mimics what we got in from type messenger ID to type messenger ID. And the message contains a content, which contains a type of text and the actual message. You can see here the actual message itself. I think we call it text. So now that we've got these three pieces of information ready and formatted, it's time to send our message. This is how we do it. Vonage, which is our initialized SDK with our API key, secret application ID, private key, and API host. Vonage.channel.send. Who are we sending it to? Who are we sending it from? What is the actual message? That's everything we need to do. There is an optional fourth parameter, which is a function that will tell you if something went wrong or if something went right. So here we're going to just do exactly the same thing. If there's an error, then we're just going to return a console.error. And if that what didn't happen, we'll console.log the result. So that's our reusable function. It takes in a sender, a recipient, and the text you want to send. It formats it correctly, which again is exactly the same format that we got the data in from and the message. And in fact, I thought of a slightly nicer way we can do this. But I won't because there's no reason to change things up. But I thought of a slightly nicer way to do this for the next time I run this workshop. Very good. Anyway, so we have this send message to from message and we send it via messenger back to the person. Now let's actually use this function. If there's an error, we are going to send message. And we're going to remember the first value is going to be the sender recipient text. So sender is going to be request.body.to.id. So this is when we get an inbound message, they sent it to a page. We get that value and we're going to make that person the sender. Request.body.from.id. And finally, the message. Sorry, there was a problem. Please, if you are using this in the real, give more descriptive errors. We'll copy and paste that and we'll replace this console log here. So at this time, we'll tell the user that we received their message. Thanks for your message. Save. So now we've got this reusable function. It's set up. It will basically just respond with either there was a problem if we couldn't store it in the database or thanks for your message. And remember, we have to respond to this whole API request, this whole webhook. We have to respond on the Vonage API platform. We'll continuously try and send us the same message. Let's restart our server again. Control C, up, enter. Let's send another message to our page. This should work. Hit enter and we get a response. And we don't only get a response, we stored that in the database as well. Did that work for you? Come let me know. Because this is the bulk of it. The final step where we build this recap, where we send messages back to the user that they sent to us, just an example of extending this, this is the bulk of it. We get messages in. We do some work with them. We respond. Don't even need to respond immediately. And yes, exactly as Clarice said, if you have questions, pop them straight in the chat. I'm here to help. We've got plenty of time. We're going to come in under time. There will be time to ask questions either now or at the end. You can ask me about how to extend it. I'll tell you more about some of the other APIs as well. But you should have received a response. Hopefully a positive one as well. So storing messages is fine. I think that's the core thing. It's just we're doing something with that data. We could easily go off to, you know, we could put in a city. We could go off to a third party service, find the weather in that city, and reply with an answer. What we're going to do, though, is build a recap keyword. So if the user, if they send us anything, we'll store it. But if they send us the word recap, we won't store it. Instead, we'll go to the database or get every message they've sent, and we'll send it back to the user in just a list. So let's do that. So a message comes in, right? And let's just start at the top. We're going to check if that message is the word recap. So that data might sneeze. If I do, I'll mute my mic. So if request.body.message.content.text, I know it feels ridiculous, but that is how you access. That's how you kind of go down the chain. Request.body.message, and then content, and then the value of text. If request.body.message.content.length, say that five times quick, is equal to two equal signs, because we're checking where the things are equivalent, quote, recap, then do something. Now, this doesn't quite factor in what if, you know, someone types in recap with a capital R, or they type in all caps, recap, this won't work. So what we're going to do is take the message that came in, and we're going to force it to lower case, and then we'll compare it versus the lower case version of the string. We could go further, like there are so many things you could add here, we could go dot trim, which if someone adds a space at the beginning or end, it will strip that off as well. This gives us the biggest coverage. If you type the word recap only in your message, even if there's spaces at the beginning and ends of your message, even if one or more of those characters isn't lower case, this will now match. So if it's recap, we're going to do something, and if that isn't the case, if it isn't recap, then we're going to take this code, and we're going to pop it in here. So if it isn't recap, do the same thing, store it, message back, you know, there was a problem or thanks for your message. Now we are going to interact with the database, get all the messages from this user, and then we're going to reply with them. This is how we do it. Messages or whatever you called your database variable here, messages dot find, and the first parameter will be our filter, our actual search. So if we look at the structure of the data, I know this isn't too nice to look at, let me think about how to fix that toggle word wrap. There we are. The from dot ID is the user that is currently sending a message from dot ID. So that's what we want to grab. So what we'll do is we'll in quotes from dot ID. So if from dot ID is the same as, yes, this workshop's being recorded, from dot ID, if that is equal to the person sending us this message, request dot body dot from ID, then grab it, and if not ignore it. I'm going to just hide that sidebar. Then we do a function, same kind of pattern in many JavaScript libraries, error, and then the results or records. Now, you probably want to do Solomon, if you're asking me to get the key in secret, we've covered it a couple of times, and we're reaching the end of the workshop. So I'm going to encourage you to watch the recording, but in short, you can get it from your Vonage API dashboard. So in here, you'll want to check if there was an error. So if error, console log, console dot error, error return, we're not going to do that this time because you've seen this pattern a couple of times. You've seen it here, and you've seen it here. Let's assume we've got the data fine. What we're going to do is we're going to send is we're going to send a message with all of the records. So request.body.to.id, request.body.from.id, and a message. Let's create the message because we need to do something with this. Now, at the start, this message is going to be an array. In fact, let's just respond with, okay, and let's just console.log the records so you can see what comes back from the database. Hopefully, there won't be anything too surprising here. So I'm going to restart the server, and I'm doing this a little quicker because you don't need to follow this part. This is more illustrative. What we get back from the database is an array. This is it here. It's an array of objects, of matching items. The message that we send has to be a string. We somehow have to get this array into a string. Now, there is a quite elegant way of doing this. What we'll do is we'll say records.map. What map does is it takes an input and takes an input of an array, and it does some work on every item of that array, and it returns a new manipulated array because all we really want out of here is the, I suppose, the message you sent and maybe when you sent it. So records.map, function, record, and we will return. What are we going to return? Record and record, which is the item, the specific item in the database, dot message, dot content, dot text, and then we'll add to that, like, you know, sent at record.timesamp, and then we'll just add on to the end of that string. So now this is going to be an array of strings. Let's do the same thing again. So I'm going to just call this a for a moment. I know that's not great. I'm going to just know. You know what I'll do is I'll call this, I'll just put that in as that. I'll call that message. Right. Let's see what this message is all about now. So we're using dot map. It takes in each of the records, and it will return just a string that contains the message, the word sent out in brackets, the time, and a closed bracket. And then we're just going to console log this just so we can see what it looks like. So I'm going to restart the server, send another message, recap. We should just get an okay back again. But now our array just has a single string in it. Just has a single string, because that's what we returned from the map. So instead of that big object, we just send back this. Okay. Now we're at the point of needing to actually turn it into a string. Fortunately, there is a way of taking an array and turning it into a single string. And it's called dot join. And inside of here, we put what we want to separate it by. So let's just say a comma restart our server. We'll do recap again. Where is it? Oh, didn't console log it. That helps. You know, we're at the point where we can send the message now. So let's change this to message. And again, I'll provide this code for you in just a moment. Let's restart the server. Recap. And what do we get back? We should get back all of our messages. Yes, this should work. Sent at timestamp. Can't wait to eat lunch or have a mac and cheese. Sent at time. Bit ugly. Bit ugly. So let's instead of just separating them by a comma, let's separate them by a couple of new lines. So backslash n, backslash n, restart the server. And we'll do that again. Recap. There you are. In, you know, if we were actually building this and we had more time and we were interested, we would probably also do something about the date formatting, but I can leave that to you to do. Let me copy and paste this code into the chat. And I'm just going to give you what was inside of, I'll give you the if part and everything else should go in the else part. So let's recap what we did. We set up a Vonage API application and the Vonage API messages sandbox. When messages come in, the first thing we do is check if the recap word was sent. If it wasn't, we'll store that message in a database and just respond to the user. That was good or, you know, that didn't work for whatever reason. They did set the word recap regardless of whether there's some, you know, extra spaces on the left or right of the word recap. So if we tapped in recap space in the message, it would still match whether or not any of its uppercase or not, it will match. We'll go to the database, grab every item that this user sent, form a message, which is all of the, all of the resulting messages put into just a nicer, shorter string that a user may want to see. Make sure there's a couple of empty and make sure there's like an empty line between each message and send it on. That's our whole application. Let me show you now. Actually, this might be the point. I'll show you how to do this with your own page in just a moment, but this is a perfect point if you have any questions. There are lots of things we could do. You know, we just stored it in a database. We could send it off to a translation service or use something like dialogue flow to add some conversational intelligence to the bot or, you know, get the status of trains or buses or the weather, banking. You could use this just to gather data, you know, like a Q&A. Now, I could have set up a Facebook bot and had you submit your questions straight through the bot. And just by changing messenger and the ID, you can use exactly the same code for Viber, WhatsApp and SMS. Now, just before I get onto the page, do we have any questions at all? And if you don't, don't worry about it. I'll give you just a couple of moments if you do have any plans to expand to Telegram. I don't know. I think there's always plans to increase the number of channels supported by the messages API, but I am not privy to what they are. I wouldn't be surprised if we see more channels being added there. It's pretty nice because, you know, you could absolutely just use the Facebook Messenger API and build something like this. You could easily build, well, actually not so easily, but, you know, you can just use the WhatsApp for business API and do that. And all of that's fine. You're having to rewrite the entire implementation every time. This makes it nicer to work with any single one of them, but also the fact you can use multiple. I'm going to show you how to set this up with your own Facebook page. It's actually not a lot of steps. So what we do inside of Messages and Dispatch, we had Sandbox. There's also social channels. You can connect to your Facebook page. Log in with Facebook. Give it access to the specific pages. So I've got one here. Then you can select your page and complete the setup. Then inside of your application, there's a link to social channels. You will see your new pages pop up here. So you can just link it to your individual Facebook page. And then in your code, just delete this. That's it. Now you're sending and receiving messages from a real Facebook page. It's pretty nifty. Different applications could be linked to different applications, can be linked to different pages, and you can have multiple pages per application. You may have ultimately the same intelligent, like the same underlying code. If you have variants of your page for different countries, different groups, different clubs, but underlying it all there the same, you can use the same application running for that. So that's the end of the workshop. Hopefully you found it valuable. As mentioned, it is being recorded. There's also some lovely instructions that have been written up. Wow. I wasn't expecting that at all. That's lovely. Look at this. Fab, thank you. If you have any questions, I'll give you a couple of minutes if you're about how you could further expand this. But while you might be formulating those, if you are, and again, no pressure to, of course. It's just worth noting a couple of the other APIs. Programmable voice is pretty cool. You can send and receive calls and control those calls and what happens in those calls with code. The way this basically works is we have a service called Numbers. You can rent numbers from us. They cost a different amount in every country. And then you have these numbers in your account. And then you can, these are programmable, both when you receive and when you make calls. Really cool. One use case of numbers I quite like is called proxy numbers. So if you ever use something like Uber, Lyft, Grab, you often will be able to contact your driver via a phone number to text them or to call them. That isn't their real number. It's actually a virtualized number like this. And likewise, the number they see for you is the exact same virtualized number. There's an application running with logic that says, okay, well, this person is currently in a ride. So if this person or they've requested a ride, so if this person calls this number, route it to this driver and vice versa. These numbers don't even need to exist before you click contact driver. They could be acquired immediately via an API to work with numbers to rent and release numbers and then released. Or they might have a pool of them that they use for multiple users at the same time and then cycle those in and out. The video API is one of my faves. It is a really lovely way to build multi-user video applications on web, iOS, Android, Linux, Windows, Mac. And I think maybe there's a unity beta as well. If you ever need to factor authentication, I think this is one of the easiest ways to do it. The Verify API sits on top of our SMS and voice APIs, and it handles the creation of codes, the exploration of codes, sending out those codes including multi-steps. So you might text it, then three minutes if they haven't done it, call them, wait three minutes, text them again, and then finally expire the code. All inside of one API. Really, really lovely. Number insight kind of does what it says. Get insights for numbers, understand where it's from, who owns it, and so on. And then basically everything you can do inside of the dashboard, you can also do via an API. So numbers, yeah, you can list the numbers you own, search them, buy them, cancel them, update them. Everything you can do here in the dashboard. So that's pretty cool. So for lack of other questions, I think that probably brings us to our conclusion today. Thank you so much for having me. I hope you found this valuable. If you want to kind of get more support or ask more questions, I'm going to encourage you to check out our community Slack. I think that's over here on community and down at the, I think it's developer.nextman.com slash Slack. Let's find out. It is so you can get an invite for it here. If you have other questions, we're there to help you. We have a team of developer advocates in a range of languages. So if you want to learn how to do something like this in another language and the getting started guides or tutorials aren't quite hitting the spot, check that out. Just a couple of other quick, quick, quick things before I go. We have a new startups program that's just launched. You can find out more about it on the page. We have this program called voyages. If you are using Vonage APIs and you are interested in kind of getting early release, early access to different APIs, understanding more about how we work at Vonage, we help you learn how to create better content for developers, things like blog posts and videos. I will answer your question in just a moment. And also have a nice community supportive community. You can apply to be a Vonage voyager and we also have learn.vonage.com, which has a ton, an absolute ton of blog posts showing you how to use different APIs in different ways in different languages written by different members from our team. So I think that's very much worth checking out. So I've got a question here. What else can we do with the status endpoint? Fantastic question. Let me quickly show you what my terminal was actually looking like. So when we sent the message, right, we've got a bunch of data. In fact, do you want to know what? Let's quickly show you how this status endpoint works by turning off all of the console logs other than status. So we don't need that one anymore. Don't need that one anymore. Right. Let's restart the application and message it once more. So that should still all work just without the console logs. Now let's look what happened here in the terminal. We received an update. So this is from the status endpoint. Looks the same as what we got from inbound, but it has a status and that status will change at multiple points in time. So you may receive multiple statuses for one message when it's been submitted, delivered and read. You know, you see that in Facebook Messenger, the little tick and the tick goes like solid and then the person's head replaces it when they see it. You receive a status every time that happens. So if you want to keep track of what's happening with a message that you send, you can do that. Now I did something fun with this a few months ago. I built a chess bot. The way the chess bot worked was you had sent a picture of the board and your color. You were able to move a piece. You know, you said A2 to A4 and then it would send the other person a picture of the updated board. The moment they see that, their timer starts counting, not until they see it. So if, you know, they're busy and they don't see that message for a couple of hours, that doesn't chip away at their time. More practically, you may just want to know within your application when your messages have been delivered and read by users. You may want to build your own dashboard for that. I hope that answers your question about the status endpoint. Any other questions at all? Oh yeah, I realized I didn't talk too much about it. It does need to exist even if you don't use it. You don't need to console log. The minimum viable status endpoint is this and that's quite often what it will look like. Yeah, someone just asked why didn't turn to red now. I don't know. I assume it is a sandbox quirk limitation. Yeah, I don't know. I noticed that too. I just wasn't going to draw attention to it, but as I was asked, yeah. But like, I've used it with an actual page and it works grand. I think you get three or four for every message that you send. Yeah, I only used the sandbox for the first time a couple of days ago. This workshop I wrote maybe eight months ago before the sandbox was a thing. And I thought, oh, let me let me go update it, make sure everything still stands. And the sandbox made it way nicer to get started. But it also means I haven't explored it in like a huge amount of depth. Cool. So I assume there's no other questions. So thank you so much for having me. Again, Slack, if you need us, I'm in the Slack. If you have questions, there's a channel for each of the APIs. If you have questions and all of our language specific advocates across many programming languages are there to be able to help you if you have questions. So thank you very much. Great. Thanks. Thanks, Kevin. That was really helpful. I think I speak for everyone that says that by saying that we really appreciate you spending your time in the morning on the weekend sharing with us all this knowledge of how to create our own Facebook Messenger bot. We appreciate that. And yeah, cool. And yeah, that's, that's, that's all we have. Clarisse, do you actually have any, do you have any other thing you'd like to share with the group? No, that's all. Great. Yeah, without further ado, that's, you know, that's that's our workshop. And I really appreciate everyone staying all the way through and yeah, the links are all on in the chat. I believe you should be able to save a copy. What you can do is that you can try maybe try and save a copy of the chat. Otherwise, you can also find the link to the tutorial, the sample code. Let me just share the sample code again. It's just me following along and kind of like typing along. So yeah, you, yeah, so I was at all the links to helpful links that we should also share just now. Yeah, and it should be a working copy of the app. I also update the URL for the YouTube on meetup.com as well as in the GitHub page later. Yeah, so that's all we have. Thanks again, Kevin and Clarisse for arranging this. And thanks everyone for attending. That's all we have for developers too. Have a great day. Yep. Thank you. Bye. Thank you. Bye.