 Okay. So I was talking about this presentation and basically the idea behind this presentation came from, remember back in the days where it seems like eons ago, but we did like events in people. We would actually travel and meet some people. And I had this idea because when I do that as part of my job, I go and I attend a lot of events. And one of the things that I've noticed is that it's great. It's nice. I really enjoy meeting other software developers and hearing about their struggles and what they're dealing with under their day-to-day life. And I've had great conversations. But I've also had not so great conversations at times, which is a bit sad. So I figured what if I could come up with an application that would help me to be able to rate people so that I could decide whether I want to have a conversation with them or not at a conference. Of course, that is a very unethical thing to do. You should never do that thing. That was kind of an idea. I was just playing around with the idea with some people and we're having fun about it. But I thought, what if I could actually build that? I wonder if I can actually get that thing up and running and see where it goes. So today I'm going to talk a little bit about the journey that I've had when I build this application. Before I get started, hi, my name is Joel. I work, I'm based in Canada for those of you who missed the intro. I'm based in Canada and I love beer because I've been talking about beer for the last 10 minutes. I work as a developer advocate for Red Hat OpenShift. So basically what I do, I go to events. I talk about stuff like Kubernetes and then I get some feedback from new software developers and I bring that to our PM teams. I love Twitter. If you ever want to get in touch with me, Twitter is always the best way. So that's Joel with two underscores. So Joel underscore underscore lord. It's like the worst Twitter handle ever. I know, but it is what it is. There's a funny story around that anyways, but I won't go into it. Okay. So let's talk about what I wanted to build. So I had this idea. So I, hey James. So I wanted to build an application and I wanted to be able to rate some people. So I was thinking, what could I use to do that? So the first thing that I thought I would need is to find some public data source, right? I would need to find somewhere that I could get some sort of information. And then based on that, I want to detect faces, do some face recognition score, give a score to those people. And then I wanted to deploy all the things. When I originally started with this idea, I figured this would be a lot of fun. Just writing that code and building that application. I thought it would be kind of an interesting challenge, especially the face recognition part. But it turns out the deployment part was really where I had the most fun. And I've learned a lot. So I'm going to talk about that as well today. So the first thing I needed was a public data source. And I was trying to think, all right, so I need pictures of people. So I needed a place where I can find pictures and associate that with their names. And I need to find like information where people could post some information. And, you know, why would people start giving away all that information? I was trying to figure out, and well, Twitter is exactly what Twitter is. It's a great source of public information. Out of Twitter, I can get, you know, your profile pictures, I can do some sentiment analysis and figure different things about followers. And most importantly, well, they have an API. So you can actually use that to build your application. So that's kind of what I decided to use. So I'm a JavaScript developer. That's what I've been doing for the last, I can't even remember many years now, but for a while. So I've decided to use Node.js. And with Node.js, there's, of course, library. So if you're not a JavaScript developer, here's a secret. JavaScript developers, the only thing that we do basically is just download a package from NPM and just glue everything together. So everything is done for us. We've solved that problem. So NPM install, I managed to install those dependencies. I now had that library called Twitter installed. And you can use it very easily. Just create a new Twitter, pass it your API keys. And then you have access to some get methods to get some information from the Twitter API, such as the followers list. Now, if you want to play with a Twitter, there's, it's a great API to mess around with. There's so much information that is available there. There's a few caveats, though. A lot of calls such as this one will, will only return a limited number of records. So in the case of the followers list, it will return the full information about the followers, but it will only return 200 of them at a time. And then you have a cursor to fetch the next 200. So in, in my case, that wasn't very useful just because I have 2000 of them and there's a rate limit as well. So you can't really do more than one request per second. So that was, that was getting a little bit tricky. So there's other calls that you can use still. So I've looked at the documentation. I found this followers slash IDs, which returns the IDs of all my followers. And that one is not limited to 200. It returns all the dataset. So that was great. Now I have the IDs of all of my followers and I can create a stream. So basically with this library or with the Twitter API, you can use a, you can create a stream to have access to some sort of information. Basically you can, in theory, create a stream for all the tweets that are going on. That is a lot of information. And I don't know, your laptop will blow up if you try to do that. It's just too much. Like if you tried to use a statuses, which is tweets, it's a lot of information. So you kind of need to add some filters. In this case, I took everything that had to do with my followers. That was kind of a base set. And now every time that there's a tweet that comes in, well, I have this event that is triggered and then I can extract the username and the actual tweet. I actually have it running right now. So you can kind of see that I'm monitoring some of the tweets. Actually, they're also right here in this application or in this slide deck. So you can see here that any tweet that, and let me refresh, just in case you've recently followed me, if you didn't, you should. You've missed your chance to come up on the screen, right? That's your five minute of glory right there. All right. So now everything that has to do with any of my followers, whether it's a mention about them or they are tweeting something or a retweet from one of my followers or anything basically will be displayed on the screen while I'm monitoring right now. Let's see if we can get anything to pop. Why is it not showing up? That is so funny. It's actually showing up on my screen, but you don't see it on yours. What is going on with the internet today? I swear, it's right there. Okay. Well, that's a demo failure right there, but we can live with that. That's fine. That is the funniest thing I've ever seen. Okay. So I can see Natali just tweeted. Thank you, Natali. That is the weirdest thing. I am... Okay. Anyways, let's move on. So in theory, you should see various tweets coming up on the screen right now. Okay. So let's talk about... This one shows up. Okay. So now I have your face, I have your tweets. Well, you can see that they are here right now. So right there's some information. That's the tweet that I was answering back to. So now I have your face, I have your tweets. Now what? Well, it's time to rate you. So that was the whole goal, right? I wanted to create this application to be able to see if I should have a conversation with you or not. So time to rate you. Here's the criteria that I've used. First of all, you need to be one of my followers. That is just for technical issues. It's easier because I can get that information out of Twitter. Now, of course, I wanted you to have a good following because I want you to speak to people who are important. That was a very important criteria for me. I want to make sure that you follow other people as well, just so that you have a broader range of opinions. And finally, I wanted to be sure that your tweets are generally positive. I don't want to talk or spend time talking with someone who is always bashing in. So I wanted someone positive. And that was one of the good criteria for evaluating whether I want to have a conversation with you. All right. Keep in mind that this is not a real application. So don't come up with me with force and torches. All right. So what I'm going to use for that one, I'm going to use machine learning, of course, because everybody, all the cool kids, they're all using machine learning nowadays. And I absolutely love this image. I think it represents machine learning so well. Okay. So what is machine learning? Just in case you're not sure, machine learning is the study of computer algorithms that improve automatically through experience. It is seen as a subset of artificial intelligence. Machine learning algorithms build a mathematical model based on sample data known as training data in order to make predictions or decisions without being explicitly programmed to do so. All right. So what it is is that you take some information, you transform that into some mathematical data or a model, and then based on that, you do some warm-ups and you come up with something. So I figured, you know, yeah, I can totally do that. So let's, you know, get started. TensorFlow is the one library that most people use. There's a JavaScript version of it, or you can also use the Python original library. I figured, you know, it'll be easy, but turns out that it is not as easy as I thought. Transforming that data, you kind of require a very good understanding of data and how to use all of those models in order to build your own models. So I quickly came up into a bunch of issues. Training those models, it's hard. Like I said, you need a good understanding of what you're trying to do. It is complex. There is some maths involved. There are some very good tools that you can use. Cloud providers will give you some tooling that you can use, and it makes it a lot easier. But it's still very costly. So I wasn't sure. I wasn't sure. And I was just about to quit when I read about those pre-trained models. I figured, hey, some people already did all the effort of training your models. Why not use one of those? So this is what I ended up doing. I've used a pre-trained model with the FaceAPI.js library that is an open source project that is available at the address right there. I'll be sharing all the links at the end. And with that, I can do a lot of really cool stuff. So I've seen that I can do face detection. So let's take a look here. So I took a quick picture, and there it is. And there it is. So OK. So I can do some face detection. I can actually see my face right there. So that's good. And so when I saw that, I was like, OK, that's interesting. Let's see if I can try to trick the system a little bit and try to maybe hide in a corner. And wow, I can still detect my face. So that was pretty good. So I figured I'll try something else. I'd try with no glasses in another corner and still detects my face. I don't know why I thought that no glasses would be harder for the algorithms, probably the opposite in theory. But hey, so I was having fun. And yeah, I saw that. Well, face detection works great. So what else can I do with that? It can also detect face landmarks. And face landmarks are very important. That's a good first step into where we want to go, which is face recognition, right? So face landmarks, 68 points in your face, which represent your face, basically. And it's a little bit hard to see right now because I'm kind of on the side. But if I take the first picture that I shown, you can really see those points for here. It maps your, there, let me make it bigger. So your face, you can see the nose, the mouth, the eyes. So you can really see those. And it's the ratio between all of those points, which will be called later on face descriptors, and it's what will be used for face recognition. Another fun thing about that library, which was absolutely not very useful for me, but it does face expressions as well. So I was like, oh, wow, this is neutral, which is kind of fine. But of course, what do you do when you see something like this? I can't use that button anymore. There it is. Of course, I started doing some funny faces and tried to see, well, okay, this is angry and surprised. Okay. Let's try another one. This is my angry face. And that was good. All right. So fun stuff that you can do with that library, absolutely not very useful for my project, but still a fun thing to do. Face API, you can use it in a browser or in Node.js. So just import from Node.js or use a script tag in your browser. What I did here is that I've used a file input, and I read the file and then just pasted that into a canvas. Once I have that in a canvas, I can load my models. That is the first step to do. So you need to load those pre-trained models. In this case, I'm loading the SSD Mobile NetV1 model. There are some that are faster, some slower. I'll get back to that in a few seconds, but just, you know, you can use the one that is best suited for you. And face landmark 68, which is the one that gives me my face landmarks here. Once I have everything, my image, I copy that into a, or I draw it into a canvas as seen right here. And then I can get my face description. So that is those points, everything about that face, expressing a mathematical model. Once I have those, I can do some fun stuff directly with face API. I can just directly draw the face detection as seen here. So that was the blue square. So that was all built in face API, very easy to add to your images. If you want to use it in Node.js, it is the exact same syntax, both in Node.js and in the browser. The only difference is that you need to monkey patch your canvas, your image, and your image data objects. And those can be done by using the Node canvas library, which is available on NPM. Once you've monkey patched that, everything will work exactly the same way. Okay. So now that I have my canvas or my face API monkey patched, I can use the exact same syntax to detect all faces with the face landmarks. So same syntax in both the browser and Node.js. So so far, so good. I just read some comments there. Sorry. So what about face recognition? So so far, I can do detection, but that's not very useful. What I want to do is recognition. So here's my, I'm still using face API here. I've trained it with one image. So just the image of my neutral face here. And if I go and pick an image, there you go. It recognizes me. Perfect. With zero difference. That's because it's the exact same image. So I'm kind of cheating here. But yeah, it kind of works so far. If I try with another one of those images, wow, wow, how cool is that? Right? It recognizes me. So I thought, well, let's try to see if I get something with a completely different context. So not that image that's, oh, no, that's ruining my punch for the end. It actually detected me on that image. Did you notice? There it is. I'm right there. Okay. With a bunch of unknown people. That's the image that I wanted to use. So completely different image. I'm still detected there. And all that time, I've only used a single image that I've trained my model with. But who am I with right there? That's my lovely wife. So let's try to add more training data here. So I'll just put in more pictures of myself. And I'll add one single picture of my wife here with sunglasses. May I add? And I'll just take that image again. And wait for it. There it is. So I can actually now recognize different people in an image. And I can add more, more pictures. And you will see that the detection is a little bit better this time. The rating, the number for the next to it. That's how accurate it is. So it's getting better and better as I'm training with more data, but with a single data point, I was able to actually detect those two people in the image. So face recognition. Basically, I won't go through all of that code. But what I do here is that I detect all of the faces in an image. Actually, I start by training my model instead. So I give it an image with a label. So I say this is an image of Joel. And it will take all the face descriptors and create a labeled face descriptors object right here. Once I have my labeled face descriptors, I can then use a face matcher to which I will pass my labeled face descriptors. And I will pass, I will ask it to find the best match with a new face descriptor. So I take a new image, I say, Hey, here are all the pictures, all the faces in that image, give me the best match for it and return me the label, those labels. All right. If you want to play around with face API.js, great library. Like I said, it comes pre-trained with models. There's a lot of information that you can use. Here's they have this kind of kitchen sink application that you can play around with. I thought this was an interesting one just because you have the big bank theory characters here. And you can see that the face detection works really well. And I've mentioned this one uses SSD mobile and that v1. But there's also a tiny face detector, which is blazing fast. You will see how quick it is. Like it's almost instantaneous. And there it is. But not as accurate. So it really depends on what you're trying to do. You might want to use one or the other. It can do all kind of different stuff. It can actually track faces on videos and a lot of fun things. So face recognition with a single reference point. That was the most important thing for me because I wanted to use the Twitter profile picture. Now, of course, I'm assuming that your profile picture is an actual picture of you. So I think Natalia I've tried to use yours and it didn't work because you don't have an actual picture of you. So I can't rate you. And it doesn't work if you wear a mask or things like that. Like we see on a lot of profile pictures and nowadays. Okay. So how cool is that, right? I am now able to recognize you based on an image. But I wanted to do more machine learning because machine learning is fun. Although, you know, I'm not doing the training model part, which is, you know, the boring part. So I'm just using everything that is done. So sentiment analysis basically is a process to determine whether a piece of writing is positive or negative or neutral. It will give you a score between five and minus five based on how positive or negative the text is. So it's great for if you want to do, if you want to monitor your brand or if you want to, you know, see what people are thinking about something, you can actually use that with Twitter and just kind of gauge what is going on. Once again, there's a library for that on npm. So just install the library requires sentiment and then use the analyze method just to see if a text is positive or negative. And that will return you an average of all the words. In this case, this is positive. There's three words positive is a very positive words with scored five. And this and is our neutral. So the total score of this is five divided by three, which is 1.6. And then the other one is something negative negative is very negative. So it's a minus five something is neutral. So that's a minus five divided by two. So that's a minus 2.5. So you can kind of get that a mathematical value out of a piece of writing. Let's try to see if I can actually use Twitter again. I'm hoping that it will show up in here. In just a few seconds, I'm kind of depending on people to tweet right now. So I'm hoping that somebody will post something great about this talk. Now, I hate it to wait on. Oh, we've got one. Oh, see, it's working this stuff. I don't know why it wasn't working the other time. Okay, well, it works. No, it stopped working. This is so funny. Okay, I am, I don't even know. Oh, I think it's like, hmm, okay. Probably if I change view like it night. I, okay, this is so cool. Like it's the coolest bug ever, because there's things going on on my screen, but not there. Okay, anyways, moving on. So what I do here is that I take those tweets and you see it right here. This one is a very neutral. Oh, now, okay. So you can see that one is a little bit more positive. So it comes in green. And you can see the average score right there. And the reason why it's colored at that green. Okay, I'm completely thrown off by this bug there. Okay, so what do we have so far? Well, I've got some public data. I've got your face. I can do face recognition on that. I've got your tweets. So what can I do? Well, I had all those little pieces now, but I wanted to connect everything together. So that was the deployment part. I needed to put that somewhere so that I would work. And that is what I said. The part where I had the most fun actually. And it kind of surprised me. I didn't expect that. Because, you know, you can see that I've already had a lot of fun. But okay, so what I needed to do now is that I had all of those little pieces. I had, you know, just a little proof of concept of being able to do some sentiment analysis. And I had this other little piece where I did some face recognition. And I had, like all, and I had another little piece that would, you know, extract the data from faces and pictures and to train that model. So I had all those little pieces. And I needed a way to connect everything together. So I figured I would use microservices. So use Node.js containers just to containerize all of those little bits and pieces and have them speak to each other. The first thing, my first reflex was to, because I'm an old timer, I've been doing software development since the other millennium. But so my first reflex was to build, you know, one big application that would do everything. But then, you know, I thought I have all those samples already. So why not build those tiny containers and use them as microservices? My other reflex was to use REST APIs for each one of those microservices so that they could talk to each other. And it turns out that that was getting really, really messy. So my first iteration, I was trying to use REST APIs and it was a mess. And I was trying to figure out and getting the answers. And it was getting really weird because I would send a message to one microservice who would then send another message to another service and another one. And then I would wait for a response to trigger back to the first one. It was a big mess. So I was trying to think, like, how can I figure out all that? How can I get everything? And I started building, like, a centralized place for messages to be sent through WebSockets. And as I was building that, I was like, hmm, I think there's something that already exists that does that. So I'll get back to that. I needed the database to store that information because I've told you there's a rate limit on Twitter. So I can't just go and download all the information every time. So I just wanted to store it somewhere in my system so that I could actually get quick access to it. And of course, I needed to orchestrate all of those containers. So I needed to use Kubernetes. I ended up using OpenShift for this. So microservices, that was the first thing. It really, really helped me to have all of those little bits and pieces. And even now, whenever I give this presentation, I tend to always tweak it a little bit. And it's very easy to just go in, find that little piece of code, and actually change that and redeploy that tiny microservice. So it really, really helped me to build that. I use containers for each one of those. If you're not familiar with containers, there's a talk by yours truly available called Containerization for Software Developers, which I recommend. I will share the link at the end. You can take a look at that one. But in a nutshell, a container is a standard unit of software that packages up code, all its dependencies. So the application runs quickly and reliably from one computing environment to another. So basically what that means is that a container is like this big, huge zip file that contains your source code, but also all the runtimes. So in this case, it contains not only my JS files, but no JS itself and NPM and all that stuff. So you really package everything together. So it's a lightweight, standalone, executable package of software. It's a disposable unit as well. So if you need to persist some data, you need to keep that in mind. You'll have to make sure that it is persisted somewhere. But apart from that, it's great, mainly because if you take it down, you can just restart and it will restart the exact same state. So it's a stateless application, basically. To build containers, to use containers, Docker Run is the way to use those. Or you can also use Podman. If you're running on Linux, map some port, give it a base image. In this case, I'm telling it to use the node base image and then just the command to execute once the container is started. You can also create your own containers. So in this case, you can, you know, Docker Run and my image, the one that you've built. To build your images, you will use a Docker file. So you start from the base image again. You expose reports, copy the files over, run NPM install inside that container, and then just execute node dot once the container is started. So that's kind of in a nutshell what's going on here. Docker build to create that image. And then you can push that to a shared registry. All right. So that is for containers. That's kind of what it looks like. Now, how do I get all of those containers to talk to each other? That was my big challenge here. And this is where I've had a lot of fun. So I started looking into messaging queues. So message queue is a form of asynchronous service to service communication used in serverless and microservices architectures. I was like, hmm, that sounds pretty much like what I need. Messages are stored in the queue until they're processed and deleted. Each message is processed only once by a single consumer. Message queues can be used to decouple heavyweight processing to buffer or batch work and smooth spiky workloads. So that sounded exactly like what I needed. And in fact, it was. So how it works very quickly. You've got a publisher that publishes message to a queue and you've got a consumer that consumes message out of the queue. So when I get some information, when I have a new Twitter, a new follower on Twitter, I immediately take the profile information and send that into a server or microservice that will just transform that information in a way that I want to store into the database. And that process is very, very quick. But then when I send that to my server that will store it into the database, if it recognized that there's a new profile image there, it will actually send that to my, to my messaging queue to process the image for face recognition. So, and that process is a lot longer. It takes like almost a full second to actually do that recognition there. So what happened there is that my publisher was sending more and more and more messages to my, my consumer and my consumer was not available to consume them fast enough. Not that it really mattered, but I just wanted to, you know, get it done with. So what you can do is that you can have competing consumers. So you can just add more consumers and they'll all extract the data. What's interesting is that you also need to acknowledge that the message was received and processed. So then once it's acknowledged, it will actually remove that from the messaging queue, which is very useful in case something crashes, something goes wrong. The message stays in the queue until it's actually been completely processed. So I was able to use that. Of course, I needed Kubernetes to increase and scale those, those, those containers, but we'll get back to that. There's also a request, request, reply pattern, which was available. Turns out that I didn't need it. I was thinking in terms of REST APIs. And so that's why I wanted to use them. But it turns out that I was able to just use simple messaging queues. So in order to use those in Node.js, once again, just use the AMQP lib library that you can find on NPM. You can connect to your server. In this case, I'm connecting to local host and create a channel called hello and just send a message to the queue. That's it. That's all you need to do. And in order to consume those messages, very similar, just connect to your server, create that channel, and then just consume. So every time that there's a message that comes into the queue, you will just consume it and process it. Rabbit and queue, great documentation. Take a look at that. All right. So now it's time to deploy all of those things. And how can I get everything working together? So what I've used for that was Kubernetes. There's a great talk called Kubernetes Kitchen, which is available on YouTube. I'll share a link at the end. Kubernetes is an open source system for automating deployment, scaling, and management of containerized applications. So basically, it's an orchestrator for containers. So if you need to spin up more containers, you'll do it with Kubernetes. So my phase detection container, I just spun up a few more using Kubernetes, and it takes care of all the networking between all of the different components. In Kubernetes, you'll have those basic building blocks, so pods, deployment services. And I know that there are some talks about Kubernetes specifically during this event. So feel free to take a look at them. In here, you see a deployment. So I'm describing what I want. I want one container or a pod that will run a single container to do the phase detection running on this port 3000. I want three replicas of that one, because that's my phase detection. I want a little bit more. So you really describe what you want in your system. You can also expose all of those pods through a service. So I have all those three containers running or those three pods running. So how can I find them into my system? I'll use a service. In this case, I'm using it. I'm naming my service RabbitMQ. So all of the pods inside my system will be able to address this by calling RabbitMQ. And there it is. So you can see now that my code sample instead of referring to local host, I'm referring to RabbitMQ. And Kubernetes took care of all the networking for me. So RabbitMQ will be found. The containers that will hold my RabbitMQ will be found inside my system. So really cool stuff. So I've deployed everything on OpenShift, of course. And this is what it looks like. OpenShift has this great UI that you can use and visualize all of your applications. So that was actually very useful for me to try to figure out what was going on at some point, because there are so many things in here. But you can see here that I have my Twitter microservice that is listening on Twitter to see if there are any messages coming or any new followers coming in. If there's a new follower, it sends a message to RabbitMQ, which will then be picked up by my server. Or my server will, not my server, my transformer, sorry, my transformer will transform that data into a format that is read or that I want to save in my database and send a message back to RabbitMQ, which will then be picked up by my server, which is just the server that interacts with my Mongo database here. Once it's saved, if the server detects that this is a new profile picture, well, it will send a message back to my face processor, which will take the face descriptors out of that image and send a message back to my server to save those in here. It can also detect if there's a new tweet, well, it will send that to my sentiment analyzer, come back back to my server. It will then score all of those. So it does all the back and forth between all those micro, all those tiny services. All right, very quickly, I've got like two minutes left. So let's do a quick demo. So that's my resulting applications. That's what I have now. So I'll use that picture that I've shown earlier, run it through my system. This is one of the last events that I did with some of my friends here. And let's see at how everybody was detected. Well, first of all, I was not detected. So that's a fail, but it kind of makes sense because I'm not one of my followers. So it was looking through for a follower that looks like this guy. Turns out that Todd Albert apparently looks like me. So that was kind of a fail. This is Aaron here, not Vincent. That was also a fail. But then I've looked at Aaron's profile picture and he's wearing a mask. So that it kind of makes sense that it wasn't picked up accurately. This one is funny because it up until yesterday wasn't picking him up because he had a cartoon as a profile picture, but he changed to an actual picture and this one works. But notice how he was scored zero. So I should never talk to Jeremy again apparently. And Bailey, very similar, which is accurately detected here, was scored a 16. So not very good. So I guess I shouldn't talk to those people if I ever meet them at a conference, which kind of brings me to my last point here, which is very important actually. If you're using machine learning or any type of algorithm where you kind of need to process some information, always keep in mind the ethical side of what you're doing. I think it's very important. In this case, and I kind of knew about it, but I still got a few surprising results. So that Jeremy picture at the end, he was scored as zero. I have no clue why that is actually. So you know, when you build some algorithms like that, be careful about what you're doing. Have some consideration. Make sure that you don't put in some biases in your application. So that's it. That's all I had. So thank you very much. I'll leave you with a few links for my other talks about containers, Kubernetes, RabbitMQ, and FaceAPI. You can find all the information at this link here, easy URL to slash unethical. Thank you very much for being here. I'll stick around for any questions. And I will be monitoring the Discord channel for the next hour or so, because I have something where I have to run afterwards, but I'll be monitoring everything. Feel free to ping me. Joel underscore underscore lord is my Twitter handle. If you ever have any questions, thank you very much. What is the Red Hat software that you use? So I'm guessing you are referring to, where's my cursor? This one, this one is OpenShift. So OpenShift is Red Hat's distribution. Oh, I'm actually in the way. It's Red Hat's distribution of Kubernetes. That's all right. So OpenShift, yeah. So it runs vanilla Kubernetes, but on steroids basically. So you have a lot of different things. One of the good things about that I really enjoy is the developer view. So for software developers, I think this is very valuable to actually see all the information that is going inside your Kubernetes cluster. So that's a very good one. But there's a lot of stuff. I'm actually giving, I shouldn't, yeah, I'm totally going to plug myself. I'm giving a talk in two and a half hours. You can take a look at my Twitter, where I'll be demonstrating OpenShift and a free version that you can use if you want to use that. So yeah, I'll post it on Discord. Very unethical of me. But, you know, we've already established that I'm not ethical. I saw that there was a question that came in. Where's the Red Hat software? How long did it take to build the demo app? Probably way longer than I should have taken me. But I'd say all in all, probably, probably a week or so. But keep in mind that it's a demo application. There's a lot of happy path only. It crashes all the time and so on. But overall, yeah, probably kind of a week or so.