 okay we should be live if people can hear me please let me know in the chat I am hoping that we are live okay here we go looks like I've got people watching just letting people know on WhatsApp that we are live in case they didn't notice okay so yesterday I went through a whole bunch of a kind of live code exercise and from some of the feedback I got there was a lot of stuff that I did fairly quickly that people didn't quite catch on to so tonight I'm gonna do this slightly differently and I'm gonna be covering a bunch of concepts starting with some of the make files etc well see make anyway which is what I use and then running through a whole bunch of bits and pieces if people have got comments thoughts questions etc please drop them into the Q&A or into the chat I'll see both alternatively you can check me in any of the WhatsApp groups that I'm in and I will grab them from there please keep in mind that there is a little bit of a delay between when I see the chat and you know when you actually make the request but I'll do my best to try and manage that I am running this in low latency mode so hopefully it works okay so first things first I normally use C-Line as my IDE mainly because it supports Cmake integration it does some nice cross-referencing etc now the first thing I do when I start any project is create a basic Cmake file the CmakeList file basically allows you to define your project choose what you're including set a whole bunch of flags etc certain basics so you'll see that if I find load the Cmake file there I've now got a configured project and I'm in my Cmake file here you need to set a Cmake minimum version required so I normally set my Cmake minimum required 318 that's just generally what I've got installed you need to give us a project name we're gonna call this this is just basically doing nothing more than kind of setting out your project there are a whole ton of different variables etc that you can set some built-in some stuff that you define manually I normally set my Cmake standard to C99 which is what I normally use then you can define kind of an absolute ton of flags etc as you go or you can do this with a bunch of different sets which make it kind of easier to edit so for example if I was using stuff like AVX 512 I could do something like AVX 512 flags I want to set some SSE flags which will be in SSE 4.1 and SSE 4.2 and SSE 3 we won't really be using any of these flags but for now they're there and it just allows you to define those you can then in addition do something to like set additional flags and we're gonna put a define in here for little indian because we're coding on a little indian platform and I will cover what these defines do and how they work in a little bit the alternative stack protection I wouldn't suggest that you use this flag normally but well it's just a kind of demonstration of what you can do here and then finally these are just sets so they're like variables for make you can then do something like Cmake C flags now this is a defined variable inside Cmake and we want to tell it to include what is already there and then from there I can start including what I've already defined so I'll have AVX 512 flags I'll have my SSE flags and that will set up my C of compilation so that when I actually compile this it'll use all of these various flags that I've defined here and I can play with those flags on an individual basis so for example there are a ton of AVX 512 flags I can include those as I need I can then take this thing and I'm gonna keep this relatively simple because there is so much that you can actually do with Cmake that I don't possibly cover you know that would be almost an entire video on its own but for now we're gonna go and we're gonna add an executable to this and we're gonna call it project name what that means is that my executable name is gonna come out as light code because that's my project name it'll just copy it and I'm gonna add main dot C to it one of the things to notice about when you do this if I reload the Cmake file right now you'll see that it's gonna throw an error because it can't find main dot C so it's also doing a check that the files that I'm compiling into the project actually exist the moment I go and create a new source file we'll call it main dot C for now I'm not I'll leave out the header files for now it's already added to the project because I already added it manually and now if I reload this it tells me that there is an error in this flag it's not a recognized flag because it should be like that and so now I've got a working Cmake file where which means I can now just run a make or a ninja dependent on how this thing is configured I believe that I've got this thing at the moment configured to do a ninja based build but you can do whatever you want in there I would strongly suggest that anybody who is kind of working with C learn how to use Cmake because it really really does make large complex projects a lot easier when you can start adding sub-direct trees you can turn on stuff like Doxigen and external packages you can do auto installation you can do library includes the whole lot and it's a lot simpler to work in an IDE with a Cmake file while I find it then to manually build make files which can be quite a pain in the backside to do but this effectively will build us a nice Cmake file and now we can start playing with some code so we're going to be working just with one file tonight we called it main.c I may go into a little bit of header files and some of the little bits and pieces later but before I do that has anybody got any questions comments thoughts on Cmake and so drop them in the chat drop them in well what's up and I can answer those before we kind of continue so thoughts questions oh and yes I vape constantly if that's not okay well okay not seeing any questions Steve I did see you mentioned something about sockets I'd strongly suggest that you take a look at last night's video though I will probably do a second video on sockets entirely set of video and yes I can do an entire video with regards to Cmake at some point that one will take a while because there is a lot to it I've got Cmake files that are literally a couple of hundred lines long so you can do a whole bunch of things in there now obviously we can start some very basic code now this last include that I include I always get a lot of core questions about this as in generic types.h I use that primarily because I'm used to using variables such as u64 blah and that is defined in the asm generic types of h on most Linux distributions it says me doing unsigned integer unsigned long unsigned this blah blah blah it just gives me some nice aliasing you can actually go and take a look at that file and I think if I remember correctly it includes a bunch of other stuff but it'll give you some fairly generic definitions and that's just typically a coding style that I use because I find it nice and easiest to work with those because I know kind of exactly what sort of format etc now obviously if we do some basic you know int u64 blah equals x that just defines a 64-bit unsigned integer now one of the things that I often get asked about is keep in mind that when you're working in C or any other language types are really just specifying the length of memory that you're dealing with they might define some stuff with regards to signed or unsigned but essentially a type is just a limit in size and if I were to do something like job demo 8 that is equals 1 2 3 4 5 6 7 8 so now I've got a string in title 1 2 3 4 5 6 7 8 that's what's in my string keep in mind the demo at this point while it's declared as a child demo 8 is actually the equivalent of demo 2 equals demo that will work because effectively demo 8 over here is an array of characters and any array in C like that is effectively a pointer so child demo 8 demo at this point will actually refer to a pointer to the first character but also keep in mind that memory is memory is memory and so you can cost this memory as any which way you like I could for example do something to this effect as you can see I've got 64 bits in blots it's a unsigned 64 demo has got eight characters since each character requires eight bits of information I could do something like law equals 64 star demo and if I would have print this and say law is equal to blah that would print me the numeric representation of this string over here and effectively it would just copy that memory into a 64 bit integer and I could then run this now if I were to actually run this you'll see that laws now this really huge number because it's a concatenation of the bytes that make up that string in the same way I could do something like a mem copy demo and copy that same value straight back into that string and if I print that string again I run this you can see my demo is still back there even though I've copied this number into the string it's still got the same character representation because at the end of the day this is all just memory this is a really important concept when working with anything in C because it means that you can practically in real terms manipulate pretty much anything on a byte basis or even a bit basis as if it were just raw memory there are times the types there are times for memory overlays there are times for a lot of things but this just gives you a way to demonstrate that you can manipulate pretty much anything right down at the memory level just by pointing at it etc you can also see here that demo right here printf is actually taking a pointer here if I were to take a reference to demo one and run this you'll see that I've now just chopped off the first part of the string in the same way I could do something along the lines of take a pointer to the third character and we're going to set this to and again strings in C are always null terminated so I could actually just set this to 0 like so and when I do that and I print this again except this time I'm just gonna print from the start of it you'll notice that I have effectively erased the last five characters of the string again just treating this like normal bits and bytes etc has is everybody following this have I got any questions etc in the chat WhatsApp whatever before I continue and start doing other interesting bits and pieces okay well while I wait for those questions to appear if there are any let me talk now so this is this is kind of your your basic memory okay so at the moment to answer Charlie's question first Charlie at the moment if I try and access past the fourth element provided I don't go past the eighth element I'm still okay because child demo 8 we basically reserved an 8 byte block of memory and in this particular case that would have landed on the stack because it's a static definition whereas if I've made that a pointer and done a caloc or a malloc it would have been on the heap but effectively provided I don't access past actually the ninth bytes because keep in mind it's a null zero terminated string I'm okay those will all be zero at the moment though because I zeroed them out but I still have the memory allocations if I were to try and access something like demo 20 over here the chances are that I'm gonna get zero because I'm lucky that could also segfault because I'm into undefined memory there you've got to be a little bit careful that you don't go past this the reason that when I do something like this it works is because remember the strings on null terminated so printf is going to terminate the first zero in the memory and I'm not going to get an overflow but I could access way past that then I'm into undefined territory and that's probably a bad idea Gerald any parts of this code that in particular that you want me to review so let me add some comments make this nice and okay so let's let's start from the top and I'm gonna I'm gonna add a little bit of comments here yes Charlie you can print pretty much anything in demo no matter what it is it's it's open to you to put in anything in there and you can print it okay so the asm generic types inklet gives you the following so this is unsigned 8 bits unsigned 16 bits unsigned 32 bits unsigned 64 bits if I remember correctly this would be a spawned 8 bit etc etc etc all of these types are defined by asm generic types why I do that is purely force of habit and it's a coding style I've used for a long time I find it to be shorter more precise as you point out you've got in 32 T in 64 T etc these are just kind of aliases that I am very familiar with across multiple platforms and just my kind of preference and you'll see them in a lot of code but they are effectively equivalent to things like in 32 in 64 the difference is is that an in 32 would be the equivalent of 32 bit so your inch types in C are typically signed unless you explicitly tell them they're unsigned whereas this you 32 is explicitly unsigned now does anybody need me to explain the difference between signed and unsigned in kind of binary terms basically speaking a signed integer uses one bit out of the length to specify whether or not this is a negative or a positive number so effectively a science 64 bit is actually only a 63 bit number science 16 bit is a 15 bit number so if you look at your range of numbers for a unsigned 64 bit it would be 0 through to 655 35 which is 2 to the 16 whereas your range on a science 16 bit number would range from negative 3 to 7 6 8 2 3 2 7 6 8 same length in terms of actual possibilities but one side is signed going to the negative and the other so you only get half the positive numbers on a signed integer that can become a problem when you're needing numbers into the multiple billions for whatever for example a U32 would range from 0 to 2 to the 32 which is roughly 4.2 billion after that you've got to go 64 bit I hope that answers your question Gerald does it make sense and actually I wouldn't say this is paranoia I would say this is just a way of doing things but you really don't want numeric overflows in your code as well because if you overflow a number it will start at zero gain and start overflowing and then you end up with a problem you effectively end up with a wrap around which is why if you look at a lot of things like network counters etc they're calculating the wraparounds using modulo to try and figure out when the thing is wrapped in what the remainder is I'm just reading the question Gerald I will be honest I haven't worked on systems that have been 32 but in a long long time but yes I see your point most of the systems I work on these days are 64 bit systems and I can actually go beyond the 64 bit using vectors so that I can operate on 128 256 and 512 bits at a time but in a vectorized format one of these nights I will cover vector code in some detail but it requires covering intrinsics and I think we're a little way of covering intrinsics considering I'm trying to keep this relatively simple tonight so that people can follow but that answers the question about the asm generic and why I use it I will I will definitely try and do a video on vectorized code at some point probably won't be tonight because that can take a little while to explain vectors tend to not be the way you would traditionally think because you have to stop thinking in terms of parallelization etc and it can get a little bit confusing and I want to kind of cover some basic concepts etc that came up off the last night's live coding session before we get into that too much then just to continue down this code to do a quick recap before we move in if you define law as 0 there so that gives me an 8 byte variable that will be sitting on the stack called blah it's 8 bytes because it's 64 bits 64 bit 8 bits per byte 8 bytes long that is actually one shy of what demo here is because demo being an 8 character string is actually a 9 character string because it's null terminated so in C strings by default when you declare them like this on null terminated they'll be one byte larger but because demo spots from 0 it's 0 to 8 9 characters you're not a problem then what I've done here is I dereference remember I said the demo because it's an array of characters demo itself is actually just a pointer to 8 characters of memory so if I dereference demo over here after telling it that demo is appointed to 64 bits of memory I can actually do a set on blog using this memory because it'll treat the memory as 64 bit and that will effectively just copy this right into block I hope that makes sense if I then print that out what's in blah I will get the numeric representation of the string which is 64 bits long I can then copy the memory back from blah into demo just to demonstrate that it is still there printed out again except in this particular point I am printing from character 4 note that because I've told it to print a string print F as a string wants a pointer because as I said demo is a pointer this is why I reference demo plus offset because the moment I do something like demo for I'm now not referencing a memory location I'm actually saying take one character at that memory and print that so if I would have put this as a character that is valid because it's one character but because I want a string I need a pointer to the string so I have to dereference the array at that particular position and that will then print it I can then again same thing with my men set here take the array position and get a pointer for it set it to character zero and set the next five characters printed again and the rest of the string is erased so that's kind of the basics of that now drop any questions before I move on here but I'm gonna move on a little bit here and we're gonna talk about something in C that a number of people don't quite seem to grasp and that is define define in C is so if I were to do this demo define 20 and I were to do something to the effect of let's just erase this well I'm gonna comment this out so that we've got it for later and I want to run this right you'll see that it's printing 20 the difference here is is that what I've actually written here is that define is still a macro here it is a replacement so if I hover over here it says this is a definition and I can change this but that is very very different from doing something like demo cost 20 here's the difference with a define this is basically a code replacement anything I put into a define when it compiles is simply inserted over here so it acts almost like a template whereas a constant is a constant value that can have a type or not have a type etc but this isn't simply replaced by the compiler this is why I could do entire you know entire functions etc in a define and I want to demonstrate this by if I write a quick function we'll call this block and we'll take a u64 call demo num into that and we're gonna do a printf llu demo num it turns zero oh the other thing about constants is where have I got my error here dirty dirty dirty dirty dirty dirty dirty dirty dirty news. so I've got a function there called from flaw and if I would have called this here click 20 and run that you will see that it's going to print 20 however if I've got something like this now. Use 64 garbage and we're going to make this 10. You'll tell it to print garbage. You'll see that it'll print 10 there. Now normally if I wanted to modify this and then return it, remember if I change demo because I'm pausing value not reference in the function, it won't change, right? But I have the option of doing something like in a macro which does this and we're going to say we'll call this orignu.create a macro that takes three parameters just as an example. And you'll notice here that every line I'm going to escape every line because this becomes replacement code. And if I then do this garbage equals use 64 temp. Now notice that I've put Oregon brackets and I do that because it's a variable into a macro and that's kind of required by C that you start bracketing things that are pausing in as functions. And this is where this gets a little bit interesting. And to write, one may have to double bracket that. If I were to then do something like change garbage, original is 10, 20, and I'm going to wrong place, sorry. Original is 10, 20, and I'm calling printblot. What you'll see here hopefully is that this thing now does a complete replacement of what is in that macro for that definite of what I've defined it as there. So effectively the macro acts as nothing more than a way to template code that you can basically insert and replace, etc. This is pretty useful for when you're doing things where you want to call a function with an action before it, and remember to call a function after it. For example, if you're doing thread locking, you don't want to enter a function, lock it, and it's got multiple exit points out of that function. And you've got to repeat that lock after every exit point. So what you would do is you lock the pointer before you go into the function, and you unlock the pointer after you go into the function, and you encase the entire function into a macro that then locks and unlocks. If I run this, you'll see that it printed 20, because I replaced the value with 20, but I also restored the value afterwards. So if I print the same value again after the macro, it's restored it again. That is macros in a nutshell, they are nothing more than templates. Does that make sense to everybody? Shout if it doesn't. Any questions? What I would say is, so on the intelligence, if you, a lot of the IDEs get a little bit confused over the macros. So, Tony, you're lost, you're going to need to be a little bit more specific about what I've said that's lost to you here. Charlie, what you can't see in the video, because, unfortunately, OBS is not picking this up, but if I hover over change garbage in the IDE, what it will do is, I'm just trying to think if I've got a way to actually show this on screen, but it will actually show you the definition and below it will show you replacement and it will show you exactly how that macro is being filled in within the function itself. I'm going to take a screenshot of this quickly and I'm going to drop it in WhatsApp, just so that people can see what I mean. So, I've just dropped that kind of replacement screenshot into WhatsApp chat so that people can see what it looks like in terms of the IDE, showing you how that replacement is actually using the macro definition to do code replacement and fill it in. Tony, I've dropped the replacement into the various WhatsApp channels that I'm in so you should be able to get it from there. Unfortunately, OBS doesn't show the pop-up window when I hover over it else you'd see it on the video. Now, Brian, with regards to C and compile time definitions, I'm going to go into that a little bit in a second because there's another concept that I want to cover because this is actually a good way to demonstrate compile time processing. So, Intel CPUs are what we are called little Indian. I'm going to go into a concept called Indianness and this refers to how numbers are stored and data is stored within Intel CPUs versus network processes, etc. Intel CPUs store numbers effectively in reverse. They install the data in reverse. So, for example, if in my main here, if I make a 16 bit variable and we're going to call this FF01, which is, if I remember correctly, 32,769, but I could be wrong on that. But effectively, because it's a 16 bit, it's made up of two bytes, FF and 01. That is the compound number. However, in memory at 16 bit is actually going to be stored as 01 FF and you can see that by doing something like this. Let's make this 02x and just put this on the next line, understand Indian demo. So, we cost it to eight bytes, the single bytes, and grab the first byte and then we'll put the second byte as well. What you'll see when I run this, let's just see where my error is. Well, let's just put the first byte all the rest of the syntax afterwards. It doesn't really matter. The first byte here, when I print this, you'll see that it's printing helps if I don't escape that twice. It's printing 01. It's not printing FF. If I would take this here and I would reverse this and run it, it now prints FF as my first byte. The reason for that is because it's effectively storing it in reverse. Now, what does this have to do with conditional compilation? You'll remember that in CMake lists here, I defined little Indian here. That's defined as little Indian. I could do something to say something like this. If there's little Indian, that's a conditional compilation right there. So, effectively, that says if little Indian is defined, then when it makes this variable, it'll make it a 01 FF. If big Indian is defined, it'll make it as FF01. So, if I run this right now with little Indian defined in my CMake file, you'll see that it's printing the second byte over there because of the reversal. If I go back to my CMake lists file, if I change this to say big Indian, hopefully it's going to pick it up. Yeah, there we go. It's now changed it to use this. So, it's complete conditional compilation that it's effectively compiling that hard into the code. That becomes really useful when you are doing stuff like complexed bitwise unions and structures. Just answer a question. It's just answering something in one of the WhatsApp channels. So, you can effectively create entire streams of code based on conditional compilation. If you want a better demo of this, print compile, if def function one, function two. Now, at the moment, if I were to call this over here, print compile 20, you'll see that I've got an error here right now because print compile is not defined because I don't have either of these conditional compiles in my make file. The moment that I do this may not be able to use underscores in these and I didn't reload the make file. So, if I do that and I reload CMake project, you'll see that print compile is now there and it's working. And if I run this, you'll see it says this is function one. If I go back to CMake file and I change this to function two, reload the CMake file, you'll see that my IDE has now blanketed that out and oopsie, fine. Get rid of the typo. Now, suddenly, this has gone blue and this is grayed out. And if I run it, it'll tell me this is function two. So, I've got two functions that are completely different, but they're set up entirely by conditional compilation. Um, I could also do a else in print compile demo and add this is the default if no conditional defined. And this is still using function two at the moment, but if I get rid of this whole thing over here to define anything and I reload CMake, it's now falling back onto my default. And if I run it, I've got an error in here somewhere. And I run it, it falls back to the default. Now, that is incredibly useful for when you are building code that effectively you want to build it with flags to do different parts of the code, or you want to say I want to enable this feature or I don't want to enable that feature. Because when I compile this, anything that doesn't fit the conditional compilation won't even get compiled into the binary, it will cease to exist. And so that conditional compilation can be incredibly useful in really large projects. Does anybody have any kind of questions, thoughts, anything about this before I move on to more fun things? This is Andrew's kind of tips and tricks night. So I'm going to be showing you some other I'm jumping around a little bit, but I'm just showing you guys some interesting bits and pieces. Okay, so I'm going to come back to this if I see any questions. But now I want to show you guys some pointer magic, because pointer magic is always fun. And we'll cover that for the evening. And then people can kind of watch it and digest it. And I will put something more structured together for the next talk. As I said at the moment, these ones, I'm just kind of winning it because I haven't really had the time to fully prepare. So I'm making it up as I go along. So if people have interesting topics that you want me to cover, I've had a request for an index socket tutorial, I will do that one. And if I remember correctly, somebody else also asked me to look at CMake, I will do something on CMake as well at some point. And if I missed anything else that somebody wants me to cover vectors, I will do another video on vectors as well. But as a kind of last thing for the evening, I wanted to show you guys this. We're going to make a structure here. So I've got this structure here. Now, normally, if I did something like come back to that, it should be, actually, we'll make this a void call this function alloc. Okay. So what I've done there is I've declared a pointer of type demo struct. And I've set it to a null value. If I were to try and access any of the elements in that, x is equal to %dy is equal to %d, y. Chances are when I run this, it's going to seg fault. Gives me a segment because that's a null pointer, there's nothing allocated to it. But what happens if I want to allocate for that within a function? If I pass this as a double pointer into the function, and yes, there are strange reasons to want to do this, I could do something like this. If dereference of the double pointer to give me the original pointer is equal to null, alloc size of struct demo struct.demo x equals 10, store demo y equals 20, else print this demo struct was already initialized. And I just need to include standard lib to get caloc here. What you'll see when I run this now, and I want to and take a pointer to block. What this is going to do is it takes a pointer to my pointer. It passes it into the allocation function here. It dereferences the pointer to the pointer so that you end up with the original pointer. If the original pointer is null, it allocates some memory for it. It sets x and y, and it bails. If this has already been allocated, it prints, sorry, this has already been allocated. So if I call this function again directly after the print, and I run this, you'll see it allocated, it printed, and on the second run it told me it was already initialized, and in both cases it freed up the memory afterwards. Because this is a single pointer over here, I don't need to dereference when I free. Does that make sense to everybody? Because that is effectively how you allocate for a pointer that is outside of a function in a function. There were some interesting use cases for that, but use with care because it's an easy way to introduce memory leaks if you screw it up. But I'm curious to hear if anybody's got any thoughts or questions about that one. So effectively you're using bracket star demo bracket because you're dereferencing the double pointer. So that will dereference the double pointer to a single pointer, and then take the element of the single pointer. Why are you using a pointer to a pointer, Brian, is because keep in mind that if I pass a single pointer, and I allocate for it, when I return, it's going to lose it because it's going to pass the pointer as a value instead of a reference. If I pass a double pointer, I can dereference, access the original pointer and allocate for it. And when it returns, I lose the double pointer because if I change the double pointer, that's passed as a value, not a reference, by inch to inner pointer, which is what allows me to change an inner pointer and return with that changed. I hope that makes sense. Does that make sense to everybody? Or does that make no sense? Let me give you another example of why you use a double pointer. So it's like another function here, for demo, for star, demo, and if demo is the same as demo, demo plus plus, and if demo is now the same as demo, so I just want to increase, what is on mist here? 26, it helps if I add a comma. Sure, demo, demo. Okay, so what this is going to do, right, is if I run this, it's going to print whatever's in that pointer, it's going to increment the pointer, and it's going to print it again, right? So if I run it, you can see there's the full string, there's the string minus the first character. But when I exit this, and I print this again, print off the exits, you'll see it's come back again because it's passed the pointer as a value, and therefore changing the pointer inside the function is just going to change the pointer itself. It's not going to change anything else. However, if I pass this as a double pointer, and I do this, if I pass this as a double pointer, that's giving me a grief here, that should actually still run, it's going to probably give me an error, but no. It'll be pointer to pointer demo zero, that should, let me do this another way. So if I do this now, and I run this, you can see that it prints the first pointer here, but now I've passed a pointer. So when I increment the dereference of the pointer, I'm incrementing the original pointer, and now when it returns, what's left is going to be the original pointer plus this increment. In the same way, I could now take this pointer, decrement the pointer again, and print it, and you'll see that it's distorted again. Does that make any sense? You'll need to kind of play with that, I think, and go through the code a little bit carefully on the video. So watch the video a few times, and yes, this does kind of hurt the brain a little bit, but effectively what you need to remember is that when you pass a pointer into a function, what you are really passing is a value. So you are not passing a pointer to a pointer, you're passing the value, and pointers are nothing more than 64 bit values to a specific point in memory. And so modifying that value in a function is not going to modify the actual pointer itself. What will happen is if you modify something that is pointed to, you'll modify the data, but you won't end up modifying the pointer itself. To modify a pointer within a function, you need to pass a pointer to a pointer, little tip and trick. But I'm going to leave it there for tonight because I think that there's quite a bit for people to digest. I've got some suggestions in the chat for more structured topics, and I'm going to try and put those together over the next day or two, and I'll let you guys know since I have time to hold another video. But I will say thanks for everybody who's taken the time to watch, and if you are enjoying the stuff, subscribe to the channel, put an alert on it, and that way you'll get notified if you don't see it in WhatsApp or whatever. And you guys can watch. I'm available on WhatsApp, you guys all of my details, I'm sure. Or just leave a comment in the chat with any ideas or topics or specific things that you want me to cover. It's easier than me just winging it. And hopefully this was useful. And thanks very much. And we shall see each other again soon. So thanks a lot guys. And I think that with that, we will call it a night. Cheers all.