 to my longer talk about GraphQL. This was initially a 25 minute talk, but now it's a 45 minute talk, which gives me the chance to add some more examples. And I added some more concepts of GraphQL as well. And also, if you guys are web developers, so who is a web developer here? Everyone, I guess? OK, great. So if you guys have later ideas for use cases or questions or want to know how you can use GraphQL in your own project or when you should use it, there will be some time for questions, I guess. Just very short about myself. So I started business initially, but I was pushed into programming when I started selling tailor-made shirts from China about 10 years ago. And my partner was even less techy than I was. So I had to do some programming for our website to sell our shirts. So that's how it started. Then last year, I started a new company for hosting backup services called Borgbase. This is where I used GraphQL on a larger scale for all the communication between the front end and the back end. And I'm mostly here today to share what I've learned during this project, because GraphQL is like an emerging technology. Many people hear about it, but they didn't use it. It's not really hard to get into it. And actually some people will have built something similar to GraphQL themselves in the past. I know I did. I had a project about four or five years ago where we were doing querying, some data, and then building some charts. And I was reading about the rest specification, and I couldn't really fit my stuff into it, because I had so many parameters to send to the back end every time. So we just posted a JSON string every time for every request. And this is very similar to what GraphQL does. Then what other things do I do? I maintain an accounting library for Python. Then more recently, I built an open source desktop backup client in Python. There will be a lightning talk about this on Sunday. And also, if some of you are thinking about doing a startup, I have a support group for startups on WhatsApp, where it's like 10 or 15 people of us, and mostly solo founders. And we share marketing ideas. And if you want to join that, then just talk to me later. OK, so the target audience for this talk is web developers. So this is not a beginner talk. It's a beginner talk for GraphQL, but not a beginner talk for web design. So you will profit the most when you're already a web designer, when you know some JavaScript for sure, when you're probably doing some stuff in the back end as well, and maybe currently you're using REST or some other technology to talk to your back end. And after this talk, you should be able to sit down and use GraphQL instead for your next project. So this is my goal for the talk. And if you have any questions or if something is unclear, then just interrupt me, and we'll discuss it further. So very shortly, the contents. So first, I will compare GraphQL with REST, which is like a classic. And we'll see what's the issue with REST once your back end and your data gets more complicated. Then you will learn how to write the GraphQL scheme and how to write queries. There's also a web interface that you can use by default with most GraphQL servers. So this is very easy to debug. It's almost like a built-in documentation. Then I built two sample apps for this talk very quickly. So you see how this stuff looks in code. So there's one back end in Python and Django, which I'm sure many are using. Anyone using Django here, here? So Django, and then there's a very simple one file front end in Vue.js, which we'll talk to our back end, and we'll be doing some stuff there. And then I have some bonus content if we have time about security and how to do authentication with GraphQL, because this is not built into the specification, and everyone has to define it themselves. So I'm giving you some options there, and then a summary, and then time for questions. OK, so REST, I don't know how long it has been around, maybe quite a long time. Problem with REST is it basically maps the HTTP methods, like get, put, post, delete. It maps those to your data instances and to your data models. But it's not always clear which operation to use. Get is usually clear. Post is somewhat clear. But then put and patch is not so clear. Then as I said, my first REST API was always posting JSON, which is when you have complex data structures, this is what you end up doing probably. Then in the REST model, I'm sure you guys are familiar, usually every data class that you have, every data model, has its own URL endpoint. So for example, you will see it in the next slide. You have slash posts, slash persons. And then when you talk to this endpoint, you can do stuff if it's deleted or get a list or something like that. And I mean, for example, BorgBase has about 20 or 30 data classes, about 15 of those are used in the web interface. It's not a big app. I guess an app like Facebook or complex CRM app would have like 50 of those data classes. So in theory, they would need 50 endpoints. And this can get very complex. Then also GraphQL in the name, graph, means like a focus on relationships. You have the social graph, you have the knowledge graph. So it's always stuff that you have some things, like some entities that are connected to other stuff. And most data models are modeled very well as a graph. Because for example, you have a user, like a user class. The user class is connected to, for example, posts or to a login log or to images. So a user owns multiple images or something like this. And this is pretty much impossible to model with rest if you use it as it's intended. But GraphQL gives you like a much nice and nested structure, as you will see. And then the last class of issues is over and under fetching. Just think of your average data class. It has maybe 10, 15, 20 columns. And in many cases, when you use the data in the web front end, you only need a few of those columns. But how do you tell the API which columns do you want so often you will be getting more data than you actually need? And this is also an issue. This was one of the main motivations why Facebook developed GraphQL in the first place to avoid this stuff. OK, so here are some pictures that are stole from one of the official tutorials. They're like the official tutorial by Facebook, which is a little bit more complicated. They have Star Wars examples. And there's a newer one which is called How to GraphQL, which is a little bit simpler. So the pictures are from there. So here, again, we see the rest model. So here we have like the different URLs, right? So we have users, and then we have the ID, and we do a get request, and then we get like a data model of this user in JSON format, for example. So for example, if you want to build a user interface that displays some details about the user, about the blog post that he has done, and about the followers he has, could be Twitter, for example. Then we have to do three requests, zuck, zuck, back and forth, to get all this data. So this is the rest model. Like it's one after the other, and I have to fetch every single endpoint to get all my data, which also introduces some complexity in the front end. In the back end, it's mostly automatic. So you can just wrap your data class if you're done. So this is in comparison. This is GraphQL. So this is a GraphQL query. We'll be talking about this much more in like 10 minutes. So basically, you make a query. Then you have an argument for the query, which is you want to have the user with a specific ID. And then you tell it which fields you want to retrieve from this user. So in this case, you want only the name. And then you have this concept of graphs. So you can retrieve the data instances that are connected to this user. In this case, we are also retrieving posts. But we don't want, for example, we don't want to post content, the text, or the creation data, whatever. But we only want the title, because this could be maybe a list or some kind of preview. So we only fetch the title here. And then follow us. We only want the most recent followers, the joint. And we only want the name, right? We're not interested in the posts. We're not interested in the date of birth or anything. So this is very precise. We tell it exactly which data we want and which related data we want. So you see, this is very powerful. And it's much when you compare to rest. So here, we get a lot more stuff than we actually need. So here, you see, we also get the content. We get the comments that we don't really want, right? So here, we get the birthday as well. We don't need any of this, right, in this case. And GraphQL allows us to very precisely get exactly the data that we want and also model the connections. OK. Now let's go to the main concepts of GraphQL, how it's built. It's actually quite easy. Usually, you can learn it in probably one or two hours and then start writing. And the tutorials have very nice playground, like interactive features where you can write your own queries and you can test it. And there's some sample data. We'll be showing that later as well. So the first thing you will need is a type. This is usually defined automatically by your back end. At least that's how it works in Django, in Python. So here we have two types, which is post and person. Every type has some fields, which can be another type. So you can nest the types. This is usually done when you think of Django. You can have the set. You can connect it to a set. And then this links to a foreign key. So we have this concept. You can see it here. Then there are some primitives like integers, string, boolean, float that you can use in your type definitions. But usually, you won't be writing this. It's very unusual that you will be writing this. But the GraphQL client will still have some knowledge about this type. So you can have some error correction. So if you send an invalid query, then the client will already know it, because the client will know the schema. The back end will know the schema. So it's much easier to write code. Then this is where it gets interesting, a query. This is basically similar to a select. So a query, it retrieves data. But it doesn't change any data. So you can do multiple queries in one GraphQL request, for example. So you could, for example, if you have two different GraphQL functions, you can run them after another. And you can get back all the data in one request. The query keyword is the default keyword. So you don't have to write it. It's enough to just put the curly brackets. And then we are running the query all persons. So these queries are also taken from the how to GraphQL example, and also the code I did is also, so we'll be seeing this more often. And then as a result, if you don't do any limiting, you will just get all the available persons that the server knows about. That's a query. Then a mutation is like update request. But it could also be delete request if you want to map it to a database. But GraphQL only knows two different operations, which query and mutation. Mutation changes stuff, and query only retrieves stuff. And you should be able to do a query as often as you like, because it shouldn't change any data. So in this case, we have a mutation that's called create a person. And we pass it to arguments, like the name and the age. And then we are asking it to give it the ID back, which is very common when you have a list in your front end, and you're tracking an ID and a name. And the front end will already know the name and the age, because we pass it. But it won't know the ID, right? And to keep the data in sync with the remote server, you also get the ID back. Then arguments. This is not necessary when you're learning it, but it's necessary when you're using it. Because in practice, you will hard code the GraphQL query or you put the GraphQL query in a file somewhere in your front end application. And then you reuse the same GraphQL query over and over, but with different arguments. And these arguments are a way to make it easier to reuse it. So let's just go through it. So here we have a mutation. So we have to use the mutation keyword as opposed to the query, right? Query, we use the query keyword or nothing, because it's a default. Then we have the new person. And then we define the arguments that our query supports. So we have to give it the data type that the argument is, it can be string integer, or it could even be a different GraphQL type. Then here, so basically this new person here, this is a name I can pick and choose. So I give the mutation a name. And then inside, I put the mutation that I want to run on the server. So this new person, I could make up any name that I want to. But the great person has to match a mutation that's available on the server. And then here, I'm mapping the variables to the input variables of the function. So here, because it's a simple example, they are named the same, which makes life easier. But there's no need to name them the same. You could also, for example, if your application uses some different names in the front end and the back end, and you don't want to change it, you could easily map different names to different variables here. And then when we run it, we get back a response. The response will be the name of the mutation that we ran. And again, we want to get back the ID. OK, then nesting. We have already seen this at the very beginning. So when I do queries, I can always choose to retrieve some related fields. So for example, a user has multiple posts. And when I'm nesting stuff, I can retrieve those nested fields as well. And I can go down any level that I want to pretty much, which also causes some security concerns. So it's usually limited. So here we have an example. It's a mutation. So we are creating a new blog post. So basically, we have a title. We just give it a title and an offer ID. And then as a response, we want to have the ID of the new post. We want to have the ID of the new post. Then we want to have the title. So we can use it in the front end. And then in addition, we are also asking it for some details about the offer. So here we put the ID of the offer. And then we ask it for the response to also give us the ID, the name, and the age of the offer that wrote this article that we just created. And here's the response again. So every response is just a JSON format, which is nested in exactly the way that you defined in your query, which is very nice because it's always very predictable. And you can also rename stuff if you want to, or you can rearrange it. This is more an experimental feature, but it just shows us that GraphQL is still in its early days. So there's still a lot of tooling that's being developed. And the tooling for many libraries is by no means. I mean, it's usable, but it's not very mature, and it's not totally complete in some cases. So this will be a nice feature. It's already available in the Node.js Apollo GraphQL server, but it's not really available for Python, for example. So what it does, it's called a subscription query. So basically, the client asks the server to get updates about the specific data class. So for example, in this case, the client would get all new persons. When a new person is created on the server, the client would get it, which is used quite often. For example, when you're having a chat application, you will want to subscribe to new chat messages. Or if you have a Twitter-like application, you will want to subscribe to new tweets, for example. And this will be a very powerful, simple way to build these applications in a very easy way. As I said, the GraphQL specification doesn't tell us anything about how to implement it. So most people implement this with web sockets at the moment. So basically, it combines GraphQL with web sockets. At the moment, people just use web sockets directly. But eventually, when the tooling is more mature, web sockets will just run in the background. And we will be able to just use the subscription query type of GraphQL to get those updates. OK, and then the last thing I want to mention is because I learned it very late, but it's very useful. It's fragments. For example, when you have a larger app, you will have a folder of 20 different queries that you want to make. And in many cases, you will want to retrieve the same set of fields. And this is where fragments come in. So you define a fragment. This case, I called it address detail. And you define on which type you want to define this fragment. And then you define the fields that you want. And then you can just reuse the fragment in all your queries. You just import it. And then, so this part here would request those fields here, which is very useful. Because, for example, there are always changes to the backend. There are always new columns being added. And for example, if you have this address field and you want to add the country, or you want to add a second line for the street, for example, then you just change the fragment one time. And it will be changed in all your queries. So just like the dry principle, you only change one thing, and then it will be available everywhere. OK, then let's talk about some code. I will just quickly explain the code at a high level. And then we see how it looks like and how it works like when it runs. So I'm using graphene here, which is the most popular Python implementation of GraphQL at the moment. It's not moving particularly fast, but they cover the basic features. And people are writing some plugins for it that will be merged eventually. And as I said, the tooling is kind of a work in progress. So since some of you already know Django, you will already know about this. So this is just a standard Django model definition that maps to some kind of database later. So I'm still using the same example. So this is a person. It has a name. And it has an age, that's all. And then, so I define this because I need it anyway. And then I define a GraphQL query on this data model. In this case, it's all persons. And it's very simple to do it because I just reuse the data type from Django. And then I map it to a GraphQL query called all persons. And as you have seen before, all persons, I think query. So all persons. So it's doing some changing to the writing. It's changing snake case to the kebab case. And so this happens transparently. So you can keep the code style of either language because it's slightly different between JavaScript and Python. So this is the back end. Then this is how it looks in future S, the JavaScript part. So as I said, usually you will hard code your GraphQL query, and then you put some arguments in it. In this case, we don't have arguments, but we will see arguments a little bit later. And this piece of JavaScript will talk to Django and retrieve our persons. OK. Now, demo time. So this is good to see. OK, so here I have a very simple Django project. It took like 20 minutes to make. So here we have the data model again. So we have the person, and we have the post, which we've seen before. Then this is like, then you have a file called schema and mutations. In this case, we don't have mutations. I put it all in one file in this case. But you could split it off if you have a lot of queries and mutations. You just use two of them. So here we define, we map our person model to a GraphQL data type called person type. It's just convention. You just add the word type at the end, and that's a post type, person type, post type. So this here defines the types. We can quickly go back. So this is this here, the type. This is the first thing. So this defines the stuff here. Then here we have a query. These are all the queries. So this is read only. And we can execute this as often as we want, because it doesn't change any data. So I have two queries here. All persons and all posts very boring. So every time they just return all the objects that we have for persons or for posts. And then here we have our mutations. Mutations are a little bit more complex because you're changing data, and usually you want to handle some kind of authentication and some kind of validation. So this is the place where you would do that. So I put the required arguments for the mutation. I give it the type again, which maps back to here, queries mutations. So here we have a string and an integer again, which is the same as here. And then here is the actual function that it gets called when I call this mutation. I'm just creating a new person, and I'm just passing it the arguments that come, and then I'm saving it. In practice, I would do some more validation here. Maybe I would check for the length of the name. I would maybe check if the age makes sense, if it's more than 100 years, for example. Maybe you want to reject it with a meaningful error message. And then post type is roughly the same. We have a string of the title. We have the offer ID. And here we create a new post. We give it the title. Here I'm using the input arguments directly. And here I'm finding the relevant person object from the database using the ID that I'm getting. And then I save the new post type. So that's pretty much everything. There's nothing else to this application. It's just the default. When you just start a new Django project, this is what you get, and that's all there is. Yeah. So there is a GitHub repository where you can clone this and play with it, make some small changes. This is how I like to start very often. Then let's see how it looks like. So I'm running this Django server. I'm running it on port 8,000 now. And by default, Graphene will provide you with a kind of browser, with a kind of explorer that allows you to play with your GraphQL schema. And this is what I did here. I'm cheating a little bit because I've saved some stuff here. Actually, I want to see some more stuff here. So for internal projects, this can totally replace documentation to a degree. What I would like to see in the future is maybe the ability to add some comments to your GraphQL classes. And then they show up here in the browser. So basically, this is a JavaScript interface that's running on the Django server. It's built in already. I recommend you disable it for production deployments. Except if you want to expose the API, some services will want to expose the API. And with this, it's very quick and easy to provide people with an API. So let's see what we can do with it. So here's a simple query. As I said, I can commit the query keyword or I can write it. I can give it a different name, for example, GetMyPersons. And then here's the actual GraphQL query that I'm running. I could also browse that here. So for example, if I click at query, it tells me all the queries the server can do. Again, this simply maps back to this stuff here. So this is all the code I've written. This is all the code. I only need those five lines. And then I can browse this stuff here. Then here I can look at the mutations that the server supports. Again, it will use my data types. It will tell me which return type I can expect. Same here. For example, if I get all persons, I get a person type. And I can browse the person type, which is very nice. So now let's run this. And we get back a list of all the persons. I already put some test data in the database. But we will add some more in a bit. Yeah, typo here. So let's look at the database content. So I'm just using an SQLite database here to keep stuff simple. So this is the content of the database at the moment. So I'm running this GraphQL query. Then the GraphQL query runs my Python code, which is just this here. And as an end result, I get a JSON list of all my persons. So this is very simple. Let's see what else we can do with it. We can do some, or we can get our posts. So here's a nice example for a nested query. Same thing. We do a query. The query is called all posts, as we've seen in the Python thing. Then I tell it I want the ID. I want the title. If I forget stuff that my post type has, I can look it up here. So these are all the fields we have anyway. But I could get more fields from the offer. For example, I could also get the ID. And I run it. This is what I get. So at the moment, there's one post. It's called my GraphQL musings. It's done by Lisa. And for example, if my front end changes, and I also want to display the age of Lisa, I just add age here. Then I run it again. And it will add the age field as well. So the client has full control, which data he wants, which connected data he wants, and which fields he wants to retrieve. So it is very flexible. Then let's do a mutation and change some stuff. So here we have a mutation. I didn't give it a name, but I could give it a name. Then I'm using the createPersonMutation. Again, this simply maps to this code here. And specifically, it runs this Python code here. That's all. We're just adding a new person object. And we're saving it. And then we're returning this person object. So let's see how we can run it. Anyone wants to put a name? Test, OK, very creative. Test, and let's make it a little bit older. Let's make it 35, right? And then we want to get the ID. And in addition, we want to check that the age was saved correctly. So let's also put the age. Then we run it. And then we get, as a result, we get createPerson, which maps to the name of our mutation. So if you have multiple mutations, which you could all do, for example, I could just copy this and create two persons at the same time. Test, two. Let's say, test, three. Test, two. Yeah, I think I have to give it a different name, if I want to do this. So you have to use aliases. So you know which mutation, return, which result. We can look into this if there's time. So we run it, and a new person is being created. 10 minutes left, so I will now switch to the JavaScript part. So this is my JavaScript front end. This is written in Vue.js. It's just a few lines of code. Let's see how it looks like. So again, I only have a single file here. This is my app view. So I have here the list of. So I have two lists. I have the list of persons. And I have a form that can help me to add some more persons. And here I have a Vue.js loop that just displays all the persons. So this is quite readable. Even I'm not sure who knows Vue.js. Here, here. OK, quite a few. OK, so this is very simple stuff. So this is just my template that displays the data. Here's a form that helps me to input the data. Then I'm using a library called GraphQL Request, which is not the main library. It's a smaller library for simple use cases, which is perfect for this year. Then I'm giving it the endpoint. So it's important to note, as opposed to REST, every GraphQL query is sent to the same URL, the same endpoint. And just the JSON is different that you send it to. As opposed to REST, REST has many different URLs. So in a kind of simpler to manage and to restrict access to one URL. Then here you can see the query. This is the same as we had before here. And we look at all persons. I just copied this from over here. This is the same. I hard-coded it. In a bigger project, you would put this in an extra file, one file per query, to keep a good overview. And then here I have a JavaScript statement that actually runs the query. So I'm having the GraphQL endpoint, which is just a property of the future as component. And then when it's succeeding, I'm resolving the promise. And I'm just setting the persons to the data that I got. Let's see if it works. I tried it before, so it works. But let's see. We can look at the inspector to see how a request looks like. So I do the all persons. So it does two requests to GraphQL. The first is just the options to make sure I'm not doing some shady things. And then the second request is the actual request. You can see the JSON format of the GraphQL here. This is pretty much the same as you saw up here. I think it even copies the line breaks to a degree. Yeah, it does. Then you can see the response. This is the same as we saw in the Explorer over there. So this is very nice to debug in this way. So here we get a list of all the persons. Again, it's in JSON format. And I think I also asked it for the post title. So I asked it for the persons. And if the person has a post, it will also give me the title of that post. So here we see it did that. For most offices, it's empty because we didn't give them any post yet. But for this one, for Lisa, she has one post, which is like about GraphQL. Then let's see how mutation looks like. Anybody wants to give a different name? Tango, Tango. John, OK. John, any particular age? Nine, OK, good nine. Very young, very young quota, very young offer. So we click Add Person. Let's look at the JavaScript code first. Where do we have it? So Add Person. I made this a function of the Vue.js component. Here's again the mutation, which is almost the same as we saw before. But I'm using the parameters here. So I can easily pass the arguments by Vue.js. And then here I'm running it. Here I'm building the arguments. So I'm giving it a name and an age, which is currently used in the form, the same name as the model here. So Vue.js makes this very simple. And then when it's done, I'm doing the alert that we saw here, Add Person, blah, blah, blah. And let's see, OK. And now we can run this again. No, let's look at this here first. So once again, we see our GraphQL query here and also our variables. This is in addition now. So it gives a dictionary of variables. And it gives the query that we want to run. And it will do some replacing for that on the server. And then as a result, we get back our data, the name of the mutation, the person, and the age, and also the ID that the instance of the model got on the server. And then we can run our getPersons again. And we see John was added to the database. And when we look into our database, we see John was also added here. Yeah, so that's the sample code. Five minutes, OK? OK. So that couple of popular JavaScript libraries, you can use, I mean, there are some back end libraries, some front end libraries. For front end, Relay was the first client that was released by Facebook. But I don't think it's very widely used today. Apollo is probably the most widely used for big projects. But it needs a little bit more work to set it up. And for this small example, I used a smaller project called GraphQL Request, where you just put a string like this. I think I will just talk about this very briefly. Because as you've seen, there was no authentication. Everyone can add an offer or a person. Everyone can add a post. So you, as a developer, you need to handle the authentication. The two major options for this are you can use a cookie, a session cookie, which Django already does by default. Or you can use something fancy like a JWT token that you save into local storage. And then, usually, you would use in Django, you would use a decorator. So only an authenticated user can run this mutation. So the access control happens at the mutation and query level and not at the URL level. And a few other security considerations are, in practice, usually want to limit the query depth. Because otherwise, I could attack your server by just doing a loop and always requesting other stuff from a nested object, which can get very big. So very short the summary. So GraphQL solves some problems that REST has, particularly for web applications and for mobile applications as well. You can also use this stuff in an Android app or an iOS app. And you will get faster results because you can, instead of three, request to the server, you only need to do one, and you get exactly the data you need. So you need to download less if you have a lot of, like, if you have a very big data model, you only download the fields that you need. So this can make a big difference. Then GraphQL has its own schema definition. You have queries. You have mutations. You have post types. And then you define operations for that. So for Django, I'm not aware of any other implementation that can be used in production, apart for Graphine. And, yeah, Apollo is, for a bigger project, you will probably want to use Apollo. OK, so any questions or any? Yeah, yeah, you can. So the Facebook implementation of GraphQL has some default arguments that you can pass it that takes care of filtering, of ordering, and this kind of stuff. If you use this particular library, you get it for free. And, for example, the Apollo client still expects this kind of structure by default. You can also use it in Graphine. Or you can do it yourself. For example, you pass an extra argument, which is called ordering. And then you put it to a string, for example. And then you order it in your application. So you would do this in your Python code. So here, for example here, instead of just passing the posts unordered, you could just take in one addition argument to the query. And then you use this argument to do some filtering or to do your ordering on your Django ORM objects. So this can be added. And it already exists in some libraries as well. I think it's probably not a good use case, because you would have to implement the backend in your client. So probably it's easier to have some JavaScript functions to load the JSON and to do the ordering and the filtering there. No, I don't think it's a good use case. I wouldn't do it for that, because you would have to implement the filter function and the ordering function in JavaScript in your client anyway. Makes sense? And if you do that, it's easier to just use something like low dash to do the ordering directly. So GraphQL really shines when you talk to a backend which has a nested structure. This is the main use case. I'm not aware of such a tool and the standard ways to hard code the query. And then you use variables to replace stuff, which is probably good practice, because then the client cannot. I mean, this is a secure way to keep control of your queries because only certain variables can be replaced. And the client is not in control of the whole GraphQL query. And usually there's no need for this. So I haven't seen a use case for that. But what would be the use case, for example? The query is defined in JavaScript. So I hard-coded it here. But you could also put it in a separate file. Yeah, everyone can change it. It's true, it's true. That's true. That's true. Yeah. Yeah. Yeah. So I want to have a tool, GraphQL, and then generate it. I don't want to worry about syntax errors and all that. Yeah. Yeah. No, I understand the concern, but I'm not aware of a tool and the ways I've seen it, usually it's put in a separate file, which has like a .graphql. And then your build system, webpack or whatever, will pull it from those files and add it to the JavaScript files in the right place. And the cleanest solution is to have variables. And then you replace them as you need them, like here. You just pass an object. And this will be inserted here into the variables. Thank you.