‫Hello and welcome.
‫And in this lecture, we are going to start implementing filesystem functionality, so in this lecture
‫we're going to create a path, Pausa, which will essentially take a fall path like this and it'll split
‫it into drive no directory and fail.
‫So we're not actually going to be reading anything from the desk in this lecture, but we're going to
‫be creating some special functionality that will split the given path into different sections that we
‫can work with later on.
‫So that's what we're going to be doing in this lecture.
‫OK, so in your source directory, we're going to create a new folder called Air Force, which obviously
‫means filesystem.
‫We're going to create a new file called P Pasdar.
‫So, you know, Path Pasdar, right.
‫We're going to go F, F and Def Path Pausa.
‫Hajj to find path paths of Hajj.
‫OK, hash tag.
‫And if OK, nice.
‫And we're going to create some structures here.
‫So we're going to go struct path route and this will contain a drive number and it will contain a path
‫paths.
‫OK, and now down here we're going to go struct path paths and this will contain a const part.
‫So be where we'll be strong the name of a path and it will also contain a next variable.
‫So it's kind of a linked list.
‫This is right.
‫So what we're going to do then is let's say we have a path zero, test 60.
‫So what will happen is we'll have a path route that contains the drive number zero and we'll have a
‫path part whose part variable is equal to test T t and the next variable will be zero because there's
‫no more path parts.
‫If we add test for such A.B.C. texte, then again, this, this would be our path through here.
‫The zero drive here test here would be our first path path.
‫So that so test would be in, in the pop variable here and in our next variable will point to another
‫path path that contains ABC data.
‫So splitting the functionality in this way allows us to easily iterate through paths rather than have
‫to parse the string every single time.
‫So we're going to be implementing this functionality.
‫OK, so let's create new Philco paths.
‫The dots.
‫See, that's going to include people a hate each.
‫And we're going to create a function here that ensures that the path is a valid format.
‫So we're going to go static in its path Vialet format, and that's just going to take a file name here,
‫like a path of some kind.
‫Right.
‫Way to go in Atlantic, then file name PCOS Max Path, which we haven't created yet.
‫We're going to create that.
‫And, you know, we don't actually have a streamlined function, so we're going to have to create that
‫too.
‫But first, let's define Peatross max path.
‫So we go to Canada.
‫Hajjaj We're just going to go to define Peatross max path and we'll do one hundred and eight bytes.
‫Should be plenty for the path.
‫And we're now going to need to create a string dot file in the source directory here.
‫So before we do that, let's create a string directory.
‫So we've got string directory, we create a new string directory.
‫We're going to have String DaGian here F and F String H, and we're going to define our string line
‫in here essentially,
‫and we're going to go in it.
‫String Lenn Khanjar, Peterhof Appointer.
‫I'm going to create new forclose string dot C and string dot C.
‫We're going to include string dates
‫and we're going to go in it string then const char pizza.
‫And this is quite a simple operation.
‫Now we're going to go in it.
‫I equals zero while pizza does not equal zero ei plus plus pizza plus equals one and then we're going
‫to return I and that should give us the length of any string.
‫So for example, let's say that we have a and I know Terminator.
‫Right.
‫So what will happen is, is equal to zero.
‫We check the the first bite of this pizza is pointing at which is a does it equal zero.
‫No.
‫So we add one to I and that we increment the pointer right by one by.
‫So then when it does this next time it says no, it equals zero.
‫So we can't go into this.
‫All right.
‫So then is equal to one, which is one byte.
‫So yeah, this is a nice simple routine for counting the length of strings here.
‫Just looks for the null Terminator.
‫Essentially, right, and we now need to create another function that will basically take a digits of
‫some kind, like an aski digit, so like five, for example, and then it will convert it to an integer
‫for us, like integer five, because let's show you the ASCII table.
‫You guys probably aware of this, but just in case and we're going to go to Google and we're going to
‫type ASCII table.
‫And if I just zoom in.
‫Here we see decimal five, right, that charge, the inquiry charge here, right, and in here we see
‫Askey five, which is fifty three.
‫So if we look here at ASKI Zero, if we subtract forty eight, that'll give us decimal zero.
‫Now for aski one.
‫If we subtract forty eight that will give us a decimal one.
‫So we're going to make it to numeric digit function which just subtracts forty eight essentially.
‫And that said, job done.
‫So we're going to do that now.
‫So we're going to go in it to numeric digit and that's going to accept a single TCHI won't convert large
‫strings.
‫This will work on a per child basis.
‫OK, and here we're just going to go return C minus forty eight.
‫Now obviously, if you pass something that isn't a digit here, you're going to get some weird value.
‫So we assume the call of this function knows this character's is already a digit.
‫OK, and we're also going to need is digit function.
‫OK, so we're going to go pull is digit and that's going to have to char.
‫And all we're going to say is return C above Errico forty eight and then see below equal 57 and that'll
‫ensure that they pass us the digit.
‫Right.
‫Because we check its imbalance here with the ASCII table.
‫Right.
‫And we'll use this for validation later on.
‫And you can see us complaining.
‫So we are going to need to include acidy Baldor Hajjaj.
‫But if we go to String d.H now, we're going to paste that one in here and we're going to paste to numeric
‫digit in here as well.
‫OK, and we're just going to include ascribable Derg.
‫OK, nice.
‫And we're now going to go to the Makefile and we're just going to add string and also we're going to
‫add Poza into that.
‫Right.
‫So before we do that, go to the Bell Directory Crania folder the cold Air Force and create a new folder
‫called String.
‫OK.
‫Now before I forget, don't forget the semicolon here on two numeric digit guys can't forget that.
‫So let's go to the Makefile then.
‫We're going to copy and paste one of these compilations here, we'll go for the paging one.
‫This one will be fine.
‫We're going to copy and paste it here and we're going to change this belt to FS Pausa Dotto.
‫Makes you spell it right and we're going to change the source to AIFS passwords, see, OK, so we've
‫done this a few times now, so you understand how to do this and we're just going to paste that in here.
‫And we're going to change this one here to EFS, parse the Dotto.
‫OK, we're going to copy and paste this.
‫Into our bills at the top here.
‫OK, so it's like that.
‫And finally, winds of change to include here.
‫It's a source AIFS, OK, which will allow us to just include pedophiles local to the feds directory
‫when compiling the positive file.
‫I'm going to copy and paste this and we're going to do the same for the string file that we just created.
‫So we're going to go string, string, Dotto, String, String, Dot C and the includable string here
‫and then we're going to compile string, string, dot C.
‫And before I forget, we've done 2.0.
‫Should be one dot guys, one dot only.
‫So dot source fsp poza dot source string string dot c ok.
‫Because the two dots implies we're going back to directory when we're not doing that.
‫So uh yeah.
‫Change this to string string Dotto as well.
‫OK, now we're going to copy that.
‫I'm just going to check this over string that string dot C includes string.
‫Yeah that looks fine.
‫I'm going to go to the top here and just after the pause are in our files, we're going to paste that.
‫They're OK now if we just make clean and then we build, OK, we can see how positive it is complaining,
‫but that's no problem because the makefile is working.
‫So we can ignore these areas for now.
‫OK, that's fine.
‫We change the makefile.
‫OK, so we're going to go the presidency and we're going to include Colonel Hatch and we're going to
‫include String String W.H, OK?
‫And we're also going to include memory keep keep G.H. because we're going to be declaring some information
‫on the heap at some point.
‫OK, and I was supposed to do a string and then he another string line.
‫So just your string and line, which basically means that it won't pass this buffer.
‫Right.
‫So you can see here we have the max path.
‫It'll only go through this file name up to the max path.
‫Right.
‫So we'll not overflow anything.
‫We need to now create this function to go back to string and we're going to copy and paste string line
‫here, OK?
‫And we're just going to change this to have maximum variable.
‫OK, so we're going to rename String Len here to String and then because we have our string land here
‫and we're going to remove everything in this body here.
‫Right.
‫I we're just going to go in Chaika zero four I equals zero I below max I plus plus.
‫I'm just going to say if Pointer II is equal to zero then break and we're just going to return I hear.
‫Right.
‫So if we had something like Hi with Arnold Terminator, we're going here I zero OK it go through here,
‫go back around now C++.
‫So there's that one included.
‫Right.
‫We go back around I plus plus there's that one included, we go back in and we see that the point is
‫the character zero.
‫So we break and then that means the string length is two.
‫OK, so that is correct.
‫And now let's just copy and paste this into the header file here.
‫OK.
‫Excellent.
‫We can now continue with our path poza.
‫OK, so our path is valid if the length is above or equal three because we are not going to allow for
‫relative pass at the moment, we're just going to keep it simple.
‫So if the land sorry, the land is above or three and the first bite is a digit.
‫And bites with the index one and two should have something like this, so something like this would
‫be valid path format, something like this wouldn't be essentially the idea with this kind of winemaking
‫is, you know, how Windows users drive numbers while we're going to use digits for our drive numbers.
‫So that's the design I'm going for here.
‫Right.
‫So men compare and we need to include memory at the top here.
‫Now.
‫OK, so men compare
‫void's and file name one.
‫Equals zero.
‫So what this will do, this will get the address of the first index on our file name.
‫OK.
‫And then we check if the two bytes are equal to column forward slash because we already know the first
‫bytes a digit because we check here because we're looking for something like this.
‫Right.
‫This is valid.
‫This is not so.
‫This just validates the path.
‫OK.
‫All right.
‫Very well.
‫So let's go to memory memory dot.
‫See, and we can see we don't have a main compare yet, so we're going to create that now.
‫OK, so to create the meme compare, we go in it.
‫Men compare voids as one void as to an account and you guys should know what a man compared does if
‫you don't look at the reference on the C manual, because then you'll understand what we're actually
‫implementing here.
‫So we go Chassy one equals as one char C two equals s two while counts minus minus above zero.
‫If askaris see one plus plus does not equal Lascaris C two plus plus, then return C one minus one.
‫So axis in the as an array here below C two minus one.
‫Minus one one.
‫So a little bit of Tenebrae going on there as well guys.
‫So we're going to return zero here.
‫OK, so this should work.
‫This should tell us if the memory matches or not.
‫Right, essentially.
‫So we're going to copy and paste this into memory.
‫So we have a prototype to use here.
‫Backed Pasdar C and now we can see men compares resolved successfully.
‫OK, so we've just finished path filing formats and now we're ready to carry on with the path poza here.
‫OK, so we're going to create a function which will get the drive number from a given path and return
‫it to us.
‫So what we're going to do then is we're going to go static in a path, get drive by path const char
‫path.
‫And we can rename these functions here the passport of the valid format and passport powers get drive,
‫bypass, bypass, I mean.
‫And rather than path, parts of California will actually do path, paths, path, violent format, path,
‫paths, the path followed format.
‫Yeah, that makes sense.
‫OK, so now in here we're going to say if path paths.
‫Path file format.
‫Then return minus Ebad path, but before we do anything else, this should be a multidimensional pointer,
‫right?
‫Because we will actually be changing the path point pass to us in this function.
‫So it should be like that.
‫What to ask this, not one.
‫OK, and then we use the one asterisk here to access one level down past the actual path provided to
‫us to this function, which doesn't change it.
‫OK, nice.
‫So minus Ebad path, we need to create this.
‫So if we just go to set stage and we're just going to go define Ebad path for.
‫OK, and that's done, OK, so we actually also need to include status as well so that it can resolve
‫and we're going to go in it drive no equals to numeric digit askaris path zero.
‫So that'll get the very first bite passed to us and we'll convert it to a numerous digit from its ASCII
‫equivalent.
‫And then we need to add three so that we can skip this.
‫Right.
‫So add three bytes to skip drive number, you know, something like that.
‫Right.
‫So this is easy to do.
‫We go askaris plus plus equals three.
‫All right.
‫And that that should change the pointer provided to us so that the function is path actually changes,
‫it gets incremented by three bytes, their actual pointer pushing it three bytes along and then we're
‫going to return the drive number.
‫OK, and so that is now implemented.
‫This will extract the drive number from a path and it will also reposition the path whereby they pass
‫to us three bytes ahead so that it becomes from this.
‫To this.
‫OK, so it'll extract this, it'll it'll realize the drive zero and then it will return test subject.
‫Well, not Tsarevich until just the pointis points three bikes ahead to test static state.
‫OK, so we've implemented that function now.
‫OK, so we're now going to create a function that creates the path route.
‫So we're going to go static struct path routes, path paths, create routes in it.
‫Drive.
‫No.
‫OK, so that'll create a path through for the give and drive.
‫No path to us.
‫All right, so we're going to go struct path, route, path equals Kasar block size of struct path routes.
‫OK, so we just allocate the memory there and we're going to a Partha drive, no equals drive.
‫No.
‫OK, path are first equals zero return path.
‫So if we just go to path through here, essentially this is the drive number and this is appointed to
‫the first part of the path.
‫OK, so as I've explained this path here.
‫This becomes the path through which just gives us the drive, no, this becomes the first part.
‫OK, nice.
‫So we're going to go to people that see and now we're going to implement a function that will get the
‫path pop for us.
‫So we're going to go static const char path paths get path, const char path.
‫OK, again, that's a multidimensional pointer that I'm going to go char result path part equals K Zadok
‫s max path and it equals zero.
‫While path does not equal forward slash because again we're looking for a forward slash for when the
‫path ends right.
‫And the path does not equal zero.
‫The null terminator.
‫Then the result path parts.
‫I equals ask Chris path, path equals access because path essentially.
‫Now, this coming here is a mistake, so just delete that.
‫OK, so while the pacta we're currently on in the path is not a forward slash and the character we're
‫currently on is not a Terminator, then we'll set some of the result path part here.
‫OK, so we set it to the character we're currently on, OK, and now we're going to go path plus equals
‫one to increment that point to one by the head.
‫And remember, this also changes the path for the caller.
‫OK, so the caller's path is going to affect affected here because they passed us the two dimensional
‫pointer here.
‫Right.
‫And we're changing their pointer, their actual real pointer.
‫Right.
‫So we're going to go eight plus plus just doing current AI and then we're going to say if accessors
‫path equals forward slash, OK, then skip the forward slash to avoid loop to avoid problems because
‫we will be having problems if we don't do that right.
‫Because Path plus equals one here as well.
‫And the reason we'll be having problems if we don't do that is because here we say if the current by
‫the way, accessing is not a forward slash and the Kombai is not null, then we can access this.
‫Right.
‫We can go into the slope.
‫But if it is a forward slash in this loop, it's not called we break out of that loop.
‫Right.
‫So then obviously we take that into account because otherwise the next time that they pass the path
‫to this function, it will immediately terminate because the bite we're currently on is the forward
‫slash.
‫Right.
‫So here we say if the current forward slash, add one to it so that it goes one by the head.
‫OK, so I hope that makes sense.
‫Right.
‫And obviously, we don't care if an old Terminator, because if they call that again, it'll come through
‫and yes, it's an old Terminator and we'll leave.
‫So final bit then.
‫If the eye is equal to zero, then we didn't actually pause anything.
‫And we need to free the point pass to us.
‫So this could be written a little bit better, guys, but I'm trying to keep it as simple as possible.
‫If we could probably optimize this to only allocate the data if we resolved anything.
‫But it's really not a big deal.
‫I mean, it's not too bad, right?
‫So we're going to go result path pod equals zero and there we go.
‫So that's what happens if I zero.
‫We essentially delete the pointer here and set it to zero and then we're going to return the result
‫path pod.
‫OK, so this will extract the different parts of our path.
‫So, you know, at this point what we pass to this is we're now passing something like zero.
‫Hello, Dottie.
‫We're passing hello dot text.
‫Right.
‫Or maybe bend forward slash Basche Dobbyn or something like that.
‫Yeah, this is what we're passing when we first call this in the return bin to us eradication data put
‫Ben into it.
‫Yeah.
‫On the second time we call this, it will put bashed up Bin into into this buffer and it'll return it.
‫OK, so yeah, that's basically what this function is doing.
‫OK, so that function is implemented now.
‫OK, so we're now going to create a function that will create that path, power structure elements.
‫Right.
‫And put them in there for us.
‫So we're going to go struct path paths, path paths, paths, path paths.
‫OK, so we went from get path, path to paths path part.
‫I'm going to go struct path, path last.
‫And this is the last path path that was created.
‫Now this will be null if this is the first path back created.
‫Right.
‫And we're going to again accept the path provided to us and now we're going to go koncz path path string
‫equals path paths get path, part path.
‫So we're calling that function.
‫We just create it up here right now.
‫It's how I'm breaking everything down into multiple functions.
‫This is how it should be done, right.
‫It keeps things clean.
‫If the path paths string is no, then we finished parsing and we should just return zero.
‫OK, otherwise we're going to go subtract path part part equals K Zadok size of struct path part and
‫then we're going to go part parts equals pop path, part string.
‫OK, so then we're going to go part next equals zero zero and then we say if the last part exists and
‫just rename is variable, here goes the last part.
‫So if the last part exists, then the last part next is equal to the part, as I hope that makes sense,
‫guys.
‫You know, so we go through here, we parse some of the string, we create some data for the path pop,
‫and then we set the path to that part string, OK?
‫At this point in time, we don't know if there's any more parts, so we said next to nothing.
‫OK, now after the last part, then we said the last part next to ARTPOP.
‫OK, so then the next time they call this, they were packed.
‫So here, for example, you know how we create this here, right?
‫The next time someone calls this function, they would pass this part we created as the last part.
‫Yeah.
‫And then during that iteration, the last part of it will exist and we set the next of this one we've
‫created here, OK.
‫I hope that makes sense, guys.
‫A bit confusing.
‫You might want to go through with a debugger if you're confused or ask some questions.
‫So we're just going to return the part here.
‫OK, so that is how that is working there.
‫So we now need to make a free function, which will basically help the memory.
‫We created the string here, by the way, as you remember, it would be dangerous to use the path provided
‫to us.
‫That's why we have to create new memory, because we don't know if this is created on the stack.
‫We don't know who owns it.
‫So it's important that if we copy it right, which is why in our path paths to get path, path, function,
‫we create some memory to copy the string into and we copy the string into it here.
‫OK, I just want to make that clear.
‫So we're going to have to create the path paths of free.
‫So we're going to go voie path, paths of free.
‫Struct path, routes, routes.
‫We're just going to say struct path, part particle's route first and we're going to loop through all
‫of the parts now and we're going to say straight path part next part equals part next.
‫OK, and we're just going to say Kifri void parts.
‫Parts.
‫OK.
‫And then we're going to say free parts and then we're going to say particle's next part, OK, so you
‫can see here the pop variable path part has a variable called part, which is the char that we allocate
‫here.
‫OK, so we have to free that and we also free our part and then we set the parts for the next part.
‫So you might be thinking, well, why don't we just go particle's pop next?
‫What?
‫We don't do that because we just freed the memory, OK?
‫Which is why you have to declare the variable here and set it because we just freed the memory.
‫So that's a common mistake.
‫Some people make someone I to make that clear.
‫So here we're going to go Kifri roots, which will clean up the memory for our roots.
‫So there we are.
‫We've just created a path positive, free function.
‫So that's pretty good.
‫So we're nearly done.
‫We need to create a path perspires function now.
‫OK, so our path paths, the paths function.
‫We're going to obstruct path routes, path, paths of paths.
‫It's going to take a path.
‫And this will be the public function that parts the colonel can call this basically right.
‫So we go const char current directory path.
‫Now, we're actually going to use this current directory path at the moment.
‫But I want it here in case we want to do things like relative paths and stuff like that later on, because
‫the idea is they can pass this the current directory path.
‫And then whenever we see a dog forward slash, you know, we know the current directory path because
‫this is quite a low level function.
‫So this function shouldn't be in charge of finding out the directory path itself.
‫It should require someone to pass it to them.
‫OK, so we're going to implement this now and it rests equals zero claunch path equals path.
‫And the reason we're doing that is because we're going to be changing where this pointer is pointing
‫to in these functions up here.
‫Remember, I was saying how we do path plus equals one stuff like that.
‫Right?
‫We don't want to change in the path past to us in case we want to use this again in the future, a non
‫corrupted version.
‫So that's why we set the term path here, because they can do what they want with that.
‫Right.
‫So then we go straight path through the path.
‫Route equals zero.
‫And we say if the string length of the path is above the Peatross max path, then this isn't a legal
‫path.
‫We don't want to deal with it.
‫So we'll go to out.
‫OK, and there's I would label that makes you make the out label.
‫So now we're going to say rest equals path, get drive by path.
‫But while path paths that get drive by path I should say, and then we're going to pass in the address
‫of the ten path, OK.
‫And that allows that function to change it by doing that.
‫And we're going to say if the response is below zero, then goes out, OK, now we're going to say path,
‫route equals path paths create routes and we're going to pass in the response there because path paths
‫again drive by path returns, either a negative value, which means an error or returns a drive.
‫No.
‫Right.
‫We already know it's not negative value because we check for it here.
‫So it must be a drive number.
‫So we're going to say if the path route is no, then we fail to create the route.
‫So then we go to about.
‫And we're going to say struck the path part first.
‫First part, XPath poza Porres path, part we're going to pass in here, because this is the first part,
‫right, and we're going to pass in the address of the time path so it knows which one to pause and change.
‫And I was going to say, if the first part exists, i.e., they created it successfully, then through
‫first equals first part, OK?
‫And I'll tell you what, no, what we're actually going to do is we're going to get rid of this and
‫we're going to say if the first part fails, go to out.
‫That's what we're going to say.
‫And then down here, we're going to say passthrough first equals first part.
‫That's more clean and it's less error prone.
‫So the first way I just did it, there may have been issues with that.
‫So this is much better because we check if there's an error and then we leave straight away.
‫If there is otherwise, there's no error.
‫So we can set the path first variable to the first part here.
‫OK, because if this function returns null, then it fails.
‫Pass the positive part.
‫Remember, maybe there was no part.
‫OK, so we're going to carry on now.
‫So we're going to obstruct path paths.
‫Paths equals path paths, paths, parts first paths ampersand tempesta so pass in the address again.
‫And now this is so simple.
‫We're just going to say well parts particle's path poza paths path.
‫Paths, paths, ampersand path.
‫OK, and then finally after out, we're going to do return path through.
‫As simple as that, guys, and now we have a path, paths that we can use, so that's confusing, just
‫break down each function, go through it.
‫It might seem confusing at first, but this is rather logical.
‫Essentially, the path function is changing the path that we provided to it, which is how this is working.
‫Right.
‫That's why we can just have a while loop and call itself over and over again.
‫OK, so the final thing to do now then is to test it.
‫So just copy and paste path paths of paths.
‫This is the only function we should be exporting apart from free.
‫We're going to smoke free as well.
‫Go to Pasada and we're just going to paste that in here.
‫Back to people, zc and ways people are free here.
‫It is our path, paths of free pace that nadifa to and that we are the only ones we want to export to
‫the outside, really the only ones who want to give prototypes for.
‫And we're going to go to Canada to see and we're just going to test this.
‫So just the very topia just include Pipas, the dot org.
‫And then just down here we're going to say path paths of paths and we're going to pass in a path.
‫So zero been shelled out.
‫Been something like that.
‫Yeah.
‫Or Yeah.
‫Shelved or something like that.
‫Yeah.
‫And the current directory path we'll just in and no here we don't really care about, we're not using
‫it and here we're going to say struct path through.
‫Route path equals that, and I was going to say if route path and yeah, we're now going to compile
‫that.
‫So make clean build that I say and we can see multiple definition of string, then scroll up in Canada.
‫See, that's because we defined it here, which was my mistake.
‫So just get rid of that.
‫And we're also going to have to scroll up and we're going to have to include string string here as well,
‫guys.
‫OK, and if you now run that again, you can see it compiled.
‫Fine.
‫We're going to do a CD, Ben JDB at Simbel File, dot, dot, backslash, build kind of 4.0.
‫And we've loaded our colonel at this address.
‫OK, and we're going to now say break Colonel Dot C 95 and we're going to do Target remote and we're
‫going to pipe out to Kumu Kumu System I 386 dash stop, stop and dash capitalist's.
‫That's GDB Studio Press Center.
‫And we're now going to see to continue.
‫Can see it stopped here.
‫We're going to go next.
‫And I were going to print every path we see the path we're going to print now, askaris route path,
‫we see it's drive number zero, we see the first entry here.
‫So we're going to print out first century.
‫And what you see, we see Ben.
‫Ben is our first entry and it has an X, so we're going to go first next.
‫Then we have show today and the next there is zero signifying the end of the path.
‫So we've just broke up the path and into a drive number and into two separate parts, which is amazing
‫because it means we can easily loop through this positons difficult, right?
‫So we needed to write a positive.
‫We couldn't loop through the string.
‫Every time we wanted to figure this stuff out, we broke it down now into something that makes sense.
‫And we can now pass this path through around the filesystem when we make the file system.
‫And then finally, when we're done with it, we can call our free on, which will delete the memory.
‫So, OK, I hope that makes sense, guys.
‫And congratulations.