[00:00.000 --> 00:09.640] And let's welcome the next show from zero to here of the solid. [00:09.640 --> 00:11.200] Thanks Noel for presenting. [00:11.200 --> 00:12.200] Okay. [00:12.200 --> 00:13.200] Thank you. [00:13.200 --> 00:22.200] So, my name is Noel, I'm from Barcelona, I'm currently working at Moodle for days [00:22.200 --> 00:27.840] a week, but I'm also in the site making solid apps, site projects, and that's mostly what [00:27.840 --> 00:29.280] I will talk about today. [00:29.280 --> 00:34.320] I usually work in the open, this means that I journal about my development, so you can [00:34.320 --> 00:38.720] follow my work in my website and here you have all the socials and everything. [00:38.720 --> 00:42.560] So if you are more interested in something I say, you probably can find more detail in [00:42.560 --> 00:44.320] my website. [00:44.320 --> 00:48.720] So before we start, how many people know what solid is or heard about it? [00:48.720 --> 00:52.280] Well, maybe half the room, okay, that's nice. [00:52.280 --> 00:57.160] So for those of you who don't know, before I say what solid is, I have to go back to [00:57.160 --> 00:59.040] the creation of the web. [00:59.040 --> 01:04.880] So when the web was created, these technologies were invented like web browser, HTTP, HTML, [01:04.880 --> 01:10.280] I'm sure most of us are familiar with these ones, but later on, there was something called [01:10.280 --> 01:14.880] the semantic web and how many people know what the semantic web is or is familiar with [01:14.880 --> 01:15.880] that? [01:15.880 --> 01:16.880] Okay. [01:16.880 --> 01:17.880] Almost the same as solid. [01:17.880 --> 01:18.880] So, yeah. [01:18.880 --> 01:24.560] Basically, the semantic web is an idea that in websites other than human readable content [01:24.560 --> 01:31.520] and linked documents, users can also have linked data, which is machine readable data, [01:31.520 --> 01:33.440] not only human readable. [01:33.440 --> 01:38.880] And like this, some technologies were introduced like the resource definition framework, JSON [01:38.880 --> 01:40.560] LD, Tartel, etc. [01:40.560 --> 01:43.840] We will see more about this later. [01:43.840 --> 01:49.600] And finally, the solid protocol, it's the next iteration of this idea and it brings the [01:49.600 --> 01:52.240] centralized storage to the web. [01:52.240 --> 01:58.120] The web, I see it and the way they say it, web 3.0 by the creators of the web. [01:58.120 --> 02:01.760] But it doesn't have to be confused with web 3, which is blockchain. [02:01.760 --> 02:04.440] As you will see, solid doesn't have anything to do with blockchain. [02:04.440 --> 02:07.760] It's something completely different. [02:07.760 --> 02:14.440] And the basic idea of solid is that users have a pod and applications and services store [02:14.440 --> 02:16.560] the data in the user pod. [02:16.560 --> 02:22.600] So for example, if you have a, here on the left, we have the traditional architecture. [02:22.600 --> 02:26.840] Each application you use stores the data in a backend and that's how most applications [02:26.840 --> 02:29.080] work nowadays, right? [02:29.080 --> 02:35.360] The idea of solid is that you can use different applications, but these applications can store [02:35.360 --> 02:37.040] data in the same pod. [02:37.040 --> 02:40.640] So it's the user, the one deciding where the data goes. [02:40.640 --> 02:46.440] And it's important for privacy, but also for interoperability and a better user experience [02:46.440 --> 02:51.240] because this way they can share data between different apps seamlessly, right? [02:51.240 --> 02:52.840] That's the basic idea. [02:52.840 --> 02:57.160] And if you are more interested in the idea of solid in general, more division, you can [02:57.160 --> 03:03.560] watch a talk from 2019 that was given here at Fosnum and you can see more about that. [03:03.560 --> 03:06.400] This talk will be a bit more technical. [03:06.400 --> 03:10.680] So when you saw the title of this talk, maybe this is what comes to mind. [03:10.680 --> 03:15.440] But before we begin, I want to clarify that there are different types of heroes, right? [03:15.440 --> 03:18.060] So what type of heroes do I mean? [03:18.060 --> 03:22.960] So there are many ways to use solid, just like there are many ways to make websites. [03:22.960 --> 03:25.720] In this talk, we will focus on making solid apps. [03:25.720 --> 03:31.480] So I will not talk about hosting pods or making solid services, mostly I will talk about making [03:31.480 --> 03:33.120] solid apps. [03:33.120 --> 03:37.760] And this is because this is what I have been doing for the last four years as site projects. [03:37.760 --> 03:43.520] So I have not worked either in any enterprise level application or anything, but I don't [03:43.520 --> 03:47.120] want to discourage you from learning from this. [03:47.120 --> 03:50.720] Because my goal with these apps is to make them usable for people. [03:50.720 --> 03:55.440] It's not only some random site project to try technology. [03:55.440 --> 03:58.680] My end goal is to actually make useful apps. [03:58.680 --> 04:03.640] And also, it will be road strokes because I cannot get into many of the details, but [04:03.640 --> 04:06.520] we will get into some of the widths. [04:06.520 --> 04:10.280] So the first app I developed was in 2018. [04:10.280 --> 04:12.360] It's called Solid Focus. [04:12.360 --> 04:15.080] And basically, it's a task manager, right? [04:15.080 --> 04:19.440] So the first application you do, it's always like a to-do app. [04:19.440 --> 04:23.280] So this is what I decided to do with Solid to learn about it. [04:23.280 --> 04:28.120] So the only thing we care about is that you have tasks and you can mark them as done or [04:28.120 --> 04:29.120] not done. [04:29.120 --> 04:31.200] That's the basic, right? [04:31.200 --> 04:35.280] And when you open the application for the first time, this is what you see. [04:35.280 --> 04:41.680] So normally, people is used to register an account with an email and a password or something [04:41.680 --> 04:42.680] like this. [04:42.680 --> 04:46.960] In Solid, it's different because what you have to do when you open an account is to [04:46.960 --> 04:48.800] give the solid pod. [04:48.800 --> 04:52.280] And you are telling the app where it should get the data, right? [04:52.280 --> 04:57.080] In this case, I also added a login of line button because I know many people are not [04:57.080 --> 04:58.640] familiar with Solid. [04:58.640 --> 05:02.400] And if they only want to try the app, they can do it like this without a pod. [05:02.400 --> 05:07.320] I also think it's very aligned with the vision of Solid that users decide where to store [05:07.320 --> 05:08.320] data. [05:08.320 --> 05:13.160] So they can decide to store it in their local device without hitting the network, right? [05:13.160 --> 05:15.280] So this is how it works. [05:15.280 --> 05:19.720] And when you are making a solid app, there are actually three actors you are interested [05:19.720 --> 05:20.720] in. [05:20.720 --> 05:22.600] One of them is your application. [05:22.600 --> 05:24.240] Another one is your pod. [05:24.240 --> 05:27.560] Well, the user's pod where the data will be stored. [05:27.560 --> 05:29.760] But there is also the identity provider. [05:29.760 --> 05:36.280] And actually, when users are authenticating, you are communicating with the identity provider. [05:36.280 --> 05:41.960] It will give you a token, and it's this token, the one you use to do the data exchange in [05:41.960 --> 05:42.960] the pod. [05:42.960 --> 05:46.280] This is the basic architecture of how it works. [05:46.280 --> 05:51.560] But in general, you don't have to care too much about this because you just use a library, [05:51.560 --> 05:56.840] you give it the URL, and then it gives you the token and you can make authenticated requests. [05:56.840 --> 06:01.360] But I think it is important to at least know that before you get into it. [06:01.360 --> 06:06.120] So once you have the token, then you want to create data, right? [06:06.120 --> 06:10.800] So usually, when you think about a task manager, this is the type of data you will see, right? [06:10.800 --> 06:13.360] You have an ID, a description, and a don. [06:13.360 --> 06:14.360] It's a Boolean. [06:14.360 --> 06:18.880] But when you are working with solid, this is how you would do it. [06:18.880 --> 06:21.560] Now before, people want to leave the room. [06:21.560 --> 06:26.240] One of my goals with this talk is to actually convince you why this is better. [06:26.240 --> 06:29.720] And in the end, when you get used to it, it's not so different, actually. [06:29.720 --> 06:32.680] So hopefully, I will do it. [06:32.680 --> 06:34.480] So we have a context. [06:34.480 --> 06:38.240] This indicates the vocabulary of this piece of data. [06:38.240 --> 06:42.680] That's important because if different applications are using the same data, they need to share [06:42.680 --> 06:48.160] an ontology, or they need to be using something that is the same so that the data can be shared [06:48.160 --> 06:52.360] or understood by different implementations. [06:52.360 --> 06:54.080] The ID, it's a URL. [06:54.080 --> 06:57.000] This is also important because it's where the data is actually stored. [06:57.000 --> 06:59.720] We will see more about this later. [06:59.720 --> 07:01.000] And then there is the type. [07:01.000 --> 07:05.840] So if you think about object-oriented programming, this would be like the class of the object. [07:05.840 --> 07:11.040] And then you have other properties, which can be just literals, or there can be links [07:11.040 --> 07:14.640] to other objects or other properties. [07:14.640 --> 07:20.160] So the one before was JSON-LD, which is maybe more familiar for most people because it's [07:20.160 --> 07:21.160] JSON. [07:21.160 --> 07:26.440] But when you are working with solid most of the time, you will be seeing RDF. [07:26.440 --> 07:28.960] And this is a format called turtle. [07:28.960 --> 07:32.840] And actually, it's not so different from the first JSON I showed you. [07:32.840 --> 07:35.800] It's only that if you are not familiar at first, it may be striking. [07:35.800 --> 07:39.560] But eventually, it's quite similar to use, and it's not so different. [07:39.560 --> 07:43.400] So this is why I think it's not so bad in the end. [07:43.400 --> 07:47.480] I have been talking about the solid pod, like it's only a black box. [07:47.480 --> 07:51.760] But the thing is that inside of the solid pod, you actually have containers. [07:51.760 --> 07:55.200] You can think of these as folders in a file system. [07:55.200 --> 07:59.960] Inside of these folders or these containers, you have the documents, and you can also have [07:59.960 --> 08:00.960] binary. [08:00.960 --> 08:05.720] Like, for example, you can have a video, an image, a JSON file, whatever. [08:05.720 --> 08:10.840] But this is something that will be not structured using this vocabulary data. [08:10.840 --> 08:14.840] So it's important that what is useful for your app and what you want to be interoperable [08:14.840 --> 08:17.360] is structured using RDF. [08:17.360 --> 08:21.560] And inside of the documents, you have resources. [08:21.560 --> 08:27.160] So what I mentioned before, that the ID says where the data is stored, if we look at the [08:27.160 --> 08:33.160] ID of a task in this example, we can see that the root of the URL is the solid pod. [08:33.160 --> 08:37.560] So this tells you where the user is storing its data, right? [08:37.560 --> 08:42.480] The directory tells you the container where the task is stored. [08:42.480 --> 08:48.320] The URL is the document, and the complete URL, including the hash, is the RDF resource. [08:48.320 --> 08:52.000] So this is nice, because whenever you see a piece of data in solid, you immediately [08:52.000 --> 08:55.480] know its structure and what it is stored. [08:55.480 --> 08:59.400] This is useful as well if you export data and all of this. [08:59.400 --> 09:04.560] So now we have the authentication token, we have the data, and we know where to put it. [09:04.560 --> 09:08.800] So now this is the easy part, because this is built using web technologies. [09:08.800 --> 09:10.960] You only have to do a post request. [09:10.960 --> 09:16.080] So you do a post request to the URL with the document, and you create the document, and [09:16.080 --> 09:20.080] the body of this request will be the data in turtle format. [09:20.080 --> 09:24.480] It can also be in other formats if you want, but most of the time you will be using turtle. [09:24.480 --> 09:27.040] It's the most common, right? [09:27.040 --> 09:31.240] If you want to get the data, you do a get request to the document. [09:31.240 --> 09:34.400] If you want to delete the data, you do a delete request. [09:34.400 --> 09:39.560] If you want to get a list of all the tasks, you do a get to the container, and you will [09:39.560 --> 09:42.440] get the list, and so on and so forth. [09:42.440 --> 09:48.440] The basic idea is that it works like the web, because it's built from those technologies. [09:48.440 --> 09:51.640] And actually the good news is that that's it. [09:51.640 --> 09:57.200] This is how you make solid apps, and now in this talk I will go into more things, but [09:57.200 --> 09:58.520] these are the basics. [09:58.520 --> 10:03.560] If you understand this, you can already do a lot of things with solid, and I think that's [10:03.560 --> 10:07.320] nice because it's building up on existing technologies. [10:07.320 --> 10:10.760] So it's always important in that regard. [10:10.760 --> 10:15.040] Here you have some links if you want to get into the width with some things, and here [10:15.040 --> 10:19.560] you have my journal when I explained how I learned solid. [10:19.560 --> 10:24.360] This is the first time I saw solid, so it may be more interesting to some of you. [10:24.360 --> 10:25.360] Some takeaways. [10:25.360 --> 10:30.440] We learned the solid basics, and something that maybe was unobvious is that there is [10:30.440 --> 10:31.520] no server. [10:31.520 --> 10:36.200] You make the application, and the application works in the frontend, because the data will [10:36.200 --> 10:38.760] be stored in the solid pod, right? [10:38.760 --> 10:44.040] So this is nice because you don't have to manage any servers, and you are only building [10:44.040 --> 10:47.040] frontend applications, which is static assets. [10:47.040 --> 10:51.960] And these static assets, they can be downloaded in a zip file and put into a computer or whatever. [10:51.960 --> 10:55.560] It's only JavaScript and HTML. [10:55.560 --> 10:57.120] But we also have some challenges. [10:57.120 --> 10:59.840] For example, the onboarding UX is not great. [10:59.840 --> 11:04.440] We have some issues with the page speed, and also I didn't get into some of the things [11:04.440 --> 11:07.160] important for interoperability. [11:07.160 --> 11:11.080] So the next application I worked on, it's called Media Kraken. [11:11.080 --> 11:13.320] In this case, it's a media tracker. [11:13.320 --> 11:17.240] So the point is that you store all the movies that you have watched and all the movies you [11:17.240 --> 11:20.080] want to watch, and you can keep track of them. [11:20.080 --> 11:23.400] The use case is this, and it's quite simple, right? [11:23.400 --> 11:27.000] You can see how you can filter the movies, et cetera. [11:27.000 --> 11:30.640] So in this case, this is how the login looks like. [11:30.640 --> 11:35.200] In philosophy, it's very similar to the other one, but it improved a little bit because at [11:35.200 --> 11:39.760] least I explained what is solid, and I helped users a little bit if they don't understand [11:39.760 --> 11:41.160] what to do. [11:41.160 --> 11:47.000] But also, once you are inside of the application, you can export the data, and it will be exported [11:47.000 --> 11:49.200] as JSON-LD. [11:49.200 --> 11:53.000] Later on, when you log in with your solid account, you can import it. [11:53.000 --> 11:59.080] So in this way, I added one way for people who started using it offline to upgrade to [11:59.080 --> 12:00.080] using solid. [12:00.080 --> 12:06.200] And I think this is also important so that they can make it more easy. [12:06.200 --> 12:11.040] The other issue about the page speed, also maybe this was an obvious, but when you do [12:11.040 --> 12:15.080] a great request to the movies container that I mentioned, you can get all the tasks in [12:15.080 --> 12:16.680] the previous example. [12:16.680 --> 12:19.120] You get a list of movies, right? [12:19.120 --> 12:21.960] But then you only get the idea of the movie. [12:21.960 --> 12:25.600] You don't get all the metadata, like the name and the image and everything. [12:25.600 --> 12:30.240] So if you want to get the movies, then you need to make another request for each of them. [12:30.240 --> 12:32.120] So in the end, this is not great. [12:32.120 --> 12:35.480] You are doing N plus 1 requests, right? [12:35.480 --> 12:38.280] In case you are wondering, why would you get all the movies? [12:38.280 --> 12:42.680] Like, why don't you get just the 10 first movies and you do pagination, right? [12:42.680 --> 12:47.680] The point is that I want my application to be snappy and that you can filter things quickly [12:47.680 --> 12:48.880] and it works. [12:48.880 --> 12:53.760] If you have to do HTTP requests every time you do any interaction, it will be very slow, [12:53.760 --> 12:55.800] not just the page reload. [12:55.800 --> 13:00.320] So that's why I wanted to have all the movies in the front end. [13:00.320 --> 13:05.160] Then what happens doing this is that the first time you open the app, you see this. [13:05.160 --> 13:08.800] And depending how many movies you have, you will be seeing this for a long time, which [13:08.800 --> 13:10.640] is not great, right? [13:10.640 --> 13:15.920] So what I did is that there is a movie cache of the data using indexdb. [13:15.920 --> 13:20.800] And this way, the next time I make, I open the application, I can look at the last modified [13:20.800 --> 13:22.960] date of each one of the documents. [13:22.960 --> 13:25.040] And only request the new ones. [13:25.040 --> 13:28.400] This is a big improvement compared with solid focus. [13:28.400 --> 13:30.040] This makes it more usable. [13:30.040 --> 13:35.600] Still, if you have many movies, for example, I have more than 2,000, the first time you [13:35.600 --> 13:38.240] open it in a new device, it's not great. [13:38.240 --> 13:42.520] It can still be improved by a little bit, right? [13:42.520 --> 13:48.120] And finally, the thing I mentioned about interoperability, I don't have time to get into this a lot, [13:48.120 --> 13:52.720] but I wrote a blog post called Interoperable Serendipity. [13:52.720 --> 13:56.000] And I think this is actually the most important point of solid. [13:56.000 --> 14:01.440] In the end, if you are using solid and you are making apps, but they are not interoperable, [14:01.440 --> 14:03.720] you will end up in the same scenario we are now. [14:03.720 --> 14:08.720] The power of solid is that you use different applications and they use your data, right? [14:08.720 --> 14:12.280] So I think this is important to have into account. [14:12.280 --> 14:16.080] So for example, which vocabulary would you use? [14:16.080 --> 14:20.640] There are some websites where you can see the vocabulary that are already used and you [14:20.640 --> 14:22.640] can see which ones are the most popular. [14:22.640 --> 14:26.520] So they are the most likely to be more useful, right? [14:26.520 --> 14:28.480] You can also create your own vocabulary. [14:28.480 --> 14:32.800] If you are doing a new use case, there's nothing wrong with creating your own vocabulary [14:32.800 --> 14:38.080] and then other people will be able to use it to make other apps, right? [14:38.080 --> 14:43.280] And finally, at the beginning, I wasn't sure about this, but now that I've learned more, [14:43.280 --> 14:46.800] I think mixing and matching vocabularies is actually okay. [14:46.800 --> 14:52.000] So you shouldn't be taking a back by doing this, right? [14:52.000 --> 14:54.880] And then we have solved which vocabulary to use. [14:54.880 --> 14:57.320] The other thing is, where do you store data? [14:57.320 --> 15:02.320] For example, if I am storing movies in slash movies, maybe another app can do it in slash [15:02.320 --> 15:06.160] films, so they will not work correctly together, right? [15:06.160 --> 15:10.960] So the point is that when you log in and you get the identity of the user, you will get [15:10.960 --> 15:15.680] a document describing all its information, all the public information, and if you are [15:15.680 --> 15:21.160] making the request with an authentication token, you also get the private information. [15:21.160 --> 15:25.800] And some of this information is something called a type index, and this type index tells [15:25.800 --> 15:32.040] you these users have tasks in this container, movies in this container, et cetera, right? [15:32.040 --> 15:36.360] So once you do that, then you can already use the proper container without hard coding [15:36.360 --> 15:38.800] anything in your application. [15:38.800 --> 15:44.480] If you are the first one adding movies or whatever to a pod, then you can just create [15:44.480 --> 15:47.400] the type index, if it doesn't exist. [15:47.400 --> 15:53.320] I have to mention that right now it's a draft, but you can still use it, and I have been [15:53.320 --> 15:57.320] using it for years, because it's a client-to-client standard. [15:57.320 --> 16:01.760] This means that the clients, so the applications, are the only ones that need to know about [16:01.760 --> 16:03.440] this type index. [16:03.440 --> 16:07.080] From the point of view of the pod, it's just a simple document, right? [16:07.080 --> 16:09.280] So this is something you can use today. [16:09.280 --> 16:13.720] There is also something else called the solid application interoperability spec, but this [16:13.720 --> 16:16.080] one is a client-to-server standard. [16:16.080 --> 16:20.800] So until servers start implementing this, this will not work. [16:20.800 --> 16:25.520] Just to clarify, in case it's not clear, server is the pod, right? [16:25.520 --> 16:32.160] Okay, so final thing about this app is that if you have all the data in your pod, you [16:32.160 --> 16:35.520] will not have all the movies in existence in your pod. [16:35.520 --> 16:40.880] So how do you make this work to have a good user experience, so that people can search [16:40.880 --> 16:43.120] and get the movie they want, right? [16:43.120 --> 16:47.320] In this case, something that I think it's very important to do with solid apps is to [16:47.320 --> 16:49.800] reliance on public information. [16:49.800 --> 16:55.880] So in this case, I am using a website called the Movie Database, which gives you a database [16:55.880 --> 16:58.520] and a free API to query that. [16:58.520 --> 17:04.240] Depending what type of data you are working on, you can search different APIs, but this [17:04.240 --> 17:06.880] is the basic idea. [17:06.880 --> 17:12.000] And if you want to learn more about how I built this app, you can check it out here. [17:12.000 --> 17:17.800] Some takeaways, type indexes are nice, I encourage you to use them, and also that catching [17:17.800 --> 17:18.800] is nice. [17:18.800 --> 17:24.000] It improves the performance a lot, so this is something to keep in mind. [17:24.000 --> 17:29.760] Things we still have to improve on boarding UX and page speed, they are still not great, [17:29.760 --> 17:30.760] right? [17:30.760 --> 17:32.680] The next application I built is called Umai. [17:32.680 --> 17:36.440] I don't want you to scare you with the time frame in this. [17:36.440 --> 17:41.560] The thing is that, as I mentioned, this is a project and I don't only work on solid, [17:41.560 --> 17:46.320] I also experiment with different technologies, and for this one in particular, I started [17:46.320 --> 17:51.760] doing some animation things and all that, so it was entirely solid, what made this take [17:51.760 --> 17:52.760] so long. [17:52.760 --> 17:58.920] But in any case, Umai is a recipes manager, so the point is that you have a collection [17:58.920 --> 18:02.000] of recipes, and you can search them and browse them. [18:02.000 --> 18:07.560] So Inspirit is quite similar to Media Kraken, but instead of movies with recipes, right? [18:07.560 --> 18:10.520] This is the basic idea of the app. [18:10.520 --> 18:15.320] So the onboarding UX, at first sight, it may seem very similar to the other ones, but [18:15.320 --> 18:17.120] I think it's a lot better. [18:17.120 --> 18:18.120] Why? [18:18.120 --> 18:21.040] Because this button here says, create your free recipe. [18:21.040 --> 18:25.720] It doesn't say, use browser storage, and this is important because for people who don't [18:25.720 --> 18:30.440] understand how things work, maybe they are scared, like, what is browser storage, you [18:30.440 --> 18:31.440] know? [18:31.440 --> 18:35.520] But if they just create a free recipe, they can just go ahead and do it without worrying [18:35.520 --> 18:39.360] about solid or any technical aspects, right? [18:39.360 --> 18:45.600] Then when they start using the application, they can see the status of their data in here, [18:45.600 --> 18:50.960] and what I'm trying to convey to users is the concept of a cloud. [18:50.960 --> 18:55.880] So I still mention solid when they have to log in and create the account and everything, [18:55.880 --> 19:00.360] but I think this way they understand that they have a cloud where the data is stored, [19:00.360 --> 19:05.440] which is using solid, but they also have the local data, and I think this type of concept [19:05.440 --> 19:08.560] is something maybe they are already familiar with. [19:08.560 --> 19:13.240] And this got me to the realization that the application is offline first, so that is quite [19:13.240 --> 19:14.240] nice. [19:14.240 --> 19:19.840] But there are some issues or some challenges when you are doing an offline first solid app. [19:19.840 --> 19:27.280] For example, when you authenticate with a solid pod, you should then store the authentication [19:27.280 --> 19:31.400] token in the frontend, and if you want to see the details why, you can read this for [19:31.400 --> 19:37.560] a thread, and also every time you open the app, you have to redirect to do the authentication. [19:37.560 --> 19:41.280] This is also something that could be improved in the future, but that's how it currently [19:41.280 --> 19:42.280] works. [19:42.280 --> 19:46.600] So the way I have solved this for now is that I have some settings, and depending on the [19:46.600 --> 19:50.280] device you are using, you can reconnect automatically or not. [19:50.280 --> 19:55.160] For example, in my desktop device, I have this with everything automatic because I have [19:55.160 --> 20:00.360] a stable internet connection, but in my mobile phone, I don't reconnect automatically. [20:00.360 --> 20:03.760] I only synchronize manually whenever I want to, right? [20:03.760 --> 20:05.840] This is the basic idea. [20:05.840 --> 20:10.680] And the second thing, this will get a bit into the width as well, but imagine you have [20:10.680 --> 20:14.400] this delicious ramen recipe in your pod, right? [20:14.400 --> 20:16.200] And you have it in two devices. [20:16.200 --> 20:20.600] You have it safely stored in your solid pod, and you have a copy in your mobile phone and [20:20.600 --> 20:23.600] another copy in your desktop, right? [20:23.600 --> 20:27.720] You change the title of the recipe in your mobile phone, but it's not connected to the [20:27.720 --> 20:31.480] internet, so they change it and stay local for now. [20:31.480 --> 20:34.040] Then you change the description in your desktop device. [20:34.040 --> 20:36.360] This one is connected to the internet. [20:36.360 --> 20:40.720] So you will synchronize with the pod, and you will push the changes. [20:40.720 --> 20:42.080] But now we have an issue. [20:42.080 --> 20:47.840] When the phone finally synchronizes, you will see that it has been updated because you look [20:47.840 --> 20:52.120] at the timestamp of the last update, but you don't know what has changed. [20:52.120 --> 20:57.480] So now you have to decide if you discard the local data or you discard the remote data. [20:57.480 --> 20:59.400] So this is not ideal. [20:59.400 --> 21:03.760] The way I solve this is using something called CRDTs. [21:03.760 --> 21:06.560] You can also read more about the details here. [21:06.560 --> 21:09.400] And in this case, I had to create a vocab for this. [21:09.400 --> 21:15.000] And that's fine, and I'm mixing both the recipes vocabulary and the CRDT vocabulary. [21:15.000 --> 21:17.560] So let's go through that again. [21:17.560 --> 21:18.560] You do the same thing. [21:18.560 --> 21:23.320] You modify the name in the mobile device, but this time you also store the operation [21:23.320 --> 21:25.840] in the data. [21:25.840 --> 21:29.920] So not only the change, but also what happened and what time, right? [21:29.920 --> 21:31.640] Then you do the same in the desktop. [21:31.640 --> 21:34.240] You synchronize and you push the changes. [21:34.240 --> 21:39.160] And then when you synchronize with the mobile phone, you will see that what changed remotely [21:39.160 --> 21:40.880] was only the description. [21:40.880 --> 21:47.120] So in this way, you can pull the changes and then you push your change without any conflicts. [21:47.120 --> 21:48.560] And this is the basic idea. [21:48.560 --> 21:52.120] And when you do this, then you have everything synchronized. [21:52.120 --> 21:57.560] If your head is spinning right now, don't worry, because this is a bit esoteric. [21:57.560 --> 21:59.840] But not all solid applications have to do this. [21:59.840 --> 22:05.040] It's just this is the way I found to make my user experience how I wanted it to be. [22:05.040 --> 22:10.440] But you don't need to do this if you are getting started or want to see how solid works, right? [22:10.440 --> 22:14.640] So something else, and I think this is one of the most interesting things about this [22:14.640 --> 22:21.040] app, is that before I was saying that for movies, for example, you search an API, right? [22:21.040 --> 22:26.000] But if you have to search an API with all the recipes in the world, it doesn't exist. [22:26.000 --> 22:27.720] How does people search recipes? [22:27.720 --> 22:29.720] Or at least how do I search recipes? [22:29.720 --> 22:33.000] I go to a search engine and I search for the recipe. [22:33.000 --> 22:36.480] So the point is that the data itself is the web. [22:36.480 --> 22:39.360] It's websites that are already there, right? [22:39.360 --> 22:45.440] So the point is that for recipes, when you make a search, most search engines show you [22:45.440 --> 22:48.120] the results and they know that they are recipes. [22:48.120 --> 22:49.760] This is not just a website for them. [22:49.760 --> 22:51.600] They know these are recipes. [22:51.600 --> 22:55.520] And if you look under the hood, you inspect the source of these websites. [22:55.520 --> 23:00.360] You will see that in the header, they have some data called application ldjson. [23:00.360 --> 23:03.560] And the nice thing is that this is actually semantic data. [23:03.560 --> 23:06.600] So this is what I mentioned while at the beginning. [23:06.600 --> 23:12.240] And many websites are already using this website that don't even know that solid exists or [23:12.240 --> 23:13.240] anything. [23:13.240 --> 23:17.280] So this is very nice because this is one way to leverage the data that already exists [23:17.280 --> 23:18.280] in the wild. [23:18.280 --> 23:22.400] And I think this is a nice way to showcase what the future could look like. [23:22.400 --> 23:27.720] If solid was more used and data were more interconnected, right? [23:27.720 --> 23:32.560] So yeah, you just import, you just put the URL of the website and you import the data. [23:32.560 --> 23:37.240] Unfortunately, because the application leaves in the front end, there are course issues, [23:37.240 --> 23:39.680] so you cannot make HTTP requests. [23:39.680 --> 23:42.480] And the way I've solved it for now is to use a proxy. [23:42.480 --> 23:46.480] But depending the application you do, this will not be an issue because you can also [23:46.480 --> 23:51.040] use the server where you are hosting the app or something. [23:51.040 --> 23:56.840] So yeah, and finally, the last thing to mention is that in this app, I also implemented the [23:56.840 --> 23:58.720] ability to share things. [23:58.720 --> 24:04.600] So by default, when you create data in a solid pod, you should create it private, right? [24:04.600 --> 24:08.120] But you can also change the permissions and make it public. [24:08.120 --> 24:11.560] And this way, you can share this link with other people. [24:11.560 --> 24:15.960] Then if you share this, you can give the link to someone who doesn't even have a solid [24:15.960 --> 24:18.880] account or doesn't even know what solid is. [24:18.880 --> 24:24.280] And they will be able to see the data using the URL of your document. [24:24.280 --> 24:29.880] And something interesting to realize here is that this is not only a URL of my application. [24:29.880 --> 24:32.400] Like with my app, you can share recipes. [24:32.400 --> 24:38.000] No, you are sharing the document URL in the solid pod. [24:38.000 --> 24:43.240] What this means is that visitors don't need a solid account because it's public, but also [24:43.240 --> 24:49.120] that any of you here in this room and anybody can make an application that already uses [24:49.120 --> 24:54.560] this URL because you only have to read the solid document that is following the solid [24:54.560 --> 24:56.040] protocol, right? [24:56.040 --> 25:03.840] So in this way, you can already see how doing data in this way is useful in the end. [25:03.840 --> 25:08.160] And you can learn more here if you want more of the details. [25:08.160 --> 25:11.160] You can also read more about how I implemented this application. [25:11.160 --> 25:16.240] And if you are curious why it took me three years, this is where you can see why. [25:16.240 --> 25:19.320] And some takeaways is that offline first is really nice. [25:19.320 --> 25:23.000] I think I'm probably going to do it for most of my apps, at least the ones that follow [25:23.000 --> 25:24.960] this schema. [25:24.960 --> 25:25.960] Sharing is caring. [25:25.960 --> 25:31.760] What I mean with this is that hopefully sharing these recipes or using this type of feature [25:31.760 --> 25:37.200] inside of a solid app will show people why solid is useful. [25:37.200 --> 25:41.800] And maybe without even knowing what solid is, they can realize the power of this. [25:41.800 --> 25:46.280] Like, look, someone shared with me this URL and then I use the same URL in another app [25:46.280 --> 25:47.760] and I can get the data. [25:47.760 --> 25:51.760] I think there are very different interactions that we can see here. [25:51.760 --> 25:52.920] And finally, keep it simple. [25:52.920 --> 25:55.360] This is something I always try to remind myself. [25:55.360 --> 26:00.320] I don't always make it, but I think it's important to keep it in mind, especially with solid [26:00.320 --> 26:03.240] because things can get out of hand. [26:03.240 --> 26:09.840] But as I said at the beginning, the basic things, get, post, RDF, those are the basics. [26:09.840 --> 26:15.400] And if you have that in mind, I think you can go a long way with solid. [26:15.400 --> 26:16.960] And I still have some challenges. [26:16.960 --> 26:20.920] I cannot give you the solution because this is where I am right now. [26:20.920 --> 26:25.800] So the onboarding, I think it has improved a lot, but still when people want to connect [26:25.800 --> 26:28.680] to the cloud and they see solid, they don't know what that is. [26:28.680 --> 26:30.680] So this is one of the challenges. [26:30.680 --> 26:35.720] And also the course issue, if I want to make front-end applications, this is very difficult [26:35.720 --> 26:36.840] to get around. [26:36.840 --> 26:41.360] So this is some of the challenges I also haven't solved yet. [26:41.360 --> 26:42.360] And that's it. [26:42.360 --> 26:50.360] You can follow my work and use the apps, and if you have any questions, let me know. [26:50.360 --> 27:02.440] Thank you. [27:02.440 --> 27:03.440] Thank you. [27:03.440 --> 27:05.520] It was a wonderful presentation. [27:05.520 --> 27:12.400] I'm wondering when do you think it will be ready to be used in a more mature application? [27:12.400 --> 27:18.040] Because just for example, one thing is that you are taking full control of the pod, meaning [27:18.040 --> 27:22.600] that I would never share with you my credential of the pod so that you would have access to [27:22.600 --> 27:23.920] everything. [27:23.920 --> 27:29.520] And if you have any thoughts about a timeline for that? [27:29.520 --> 27:30.520] Yeah. [27:30.520 --> 27:34.680] So I cannot speak about the timeline because I'm not part of the specification process. [27:34.680 --> 27:39.640] So the answer to this would be when the specification includes some mechanisms to do that. [27:39.640 --> 27:42.720] And they already have it in mind and they are working on it. [27:42.720 --> 27:46.640] But I cannot give you any answers about the timeline because I'm not involved in that [27:46.640 --> 27:47.640] process. [27:47.640 --> 27:51.320] What I want to tell you is that I know what people who use Solit that have these type [27:51.320 --> 27:55.520] of concerns, they just have different pods. [27:55.520 --> 28:03.960] I have a pod for my private or sensitive information and I have another pod for my public information. [28:03.960 --> 28:09.440] And this is also nice because you can use the same app with different pods. [28:09.440 --> 28:14.720] If you are using something for your professional life and then your personal life, you can [28:14.720 --> 28:17.440] have it in different pods and that's okay. [28:17.440 --> 28:20.200] So yeah, that's my opinion on the topic for now. [28:20.200 --> 28:22.320] It's something still being worked on. [28:22.320 --> 28:23.320] Yeah. [28:23.320 --> 28:25.960] Any more questions? [28:25.960 --> 28:26.960] Okay. [28:26.960 --> 28:27.960] Thank you. [28:27.960 --> 28:28.960] Yeah. [28:28.960 --> 28:29.960] Thank you. [28:29.960 --> 28:43.000] Well, it's a bit of a related question but it's more specific to the type indices. [28:43.000 --> 28:44.000] So I didn't know about that. [28:44.000 --> 28:45.000] I've never used them. [28:45.000 --> 28:50.000] So you're saying that it's part of the spec or soon to be part of? [28:50.000 --> 28:55.320] The point about type indexes is that they are a different spec made by people who are [28:55.320 --> 29:01.840] working on Solit but it's a client spec which means that from the point of view of the pods [29:01.840 --> 29:02.920] it's just a document. [29:02.920 --> 29:07.280] So maybe you can call it more a convention than anything else. [29:07.280 --> 29:11.920] And the point is that if people start using this convention, then it will become more [29:11.920 --> 29:13.440] interoperable in the wild. [29:13.440 --> 29:14.440] Yeah. [29:14.440 --> 29:18.520] But it's a convention, you could say, because the pods don't need to implement anything [29:18.520 --> 29:19.720] for this to work. [29:19.720 --> 29:20.720] Yeah. [29:20.720 --> 29:21.720] Thank you. [29:21.720 --> 29:24.920] And so my question was, and this is where it relates to the previous question, is, so [29:24.920 --> 29:30.560] I find it very interesting but isn't it a bit risky to basically grant the apps to go [29:30.560 --> 29:34.720] and mess with the global type indices? [29:34.720 --> 29:40.040] It means you can maybe mess up the type indices with someone else or I mean, shouldn't it be [29:40.040 --> 29:43.560] the responsibility of the pod provider to build up that type index? [29:43.560 --> 29:48.840] Eventually, when it gets into the spec, yes, for example, the Solit application interoperability [29:48.840 --> 29:54.840] spec, which is also a draft, it does this type of thing in the site of the pod. [29:54.840 --> 29:59.360] So yeah, the thing about Solit, as I said at the beginning, is that there are many ways [29:59.360 --> 30:04.280] to do things because the building blocks are basic but you can combine them in many ways, [30:04.280 --> 30:05.280] you know. [30:05.280 --> 30:11.600] And the point is that right now, and that's what I'm thinking about when I do this. [30:11.600 --> 30:17.080] If you have to build a Solit application today, the type index is your best choice because [30:17.080 --> 30:21.720] the Solit application interoperability requires implementation in the server and it's not [30:21.720 --> 30:23.120] happening yet. [30:23.120 --> 30:25.000] So you cannot rely on that. [30:25.000 --> 30:27.840] So type indexes are the best thing we have. [30:27.840 --> 30:32.760] You can also choose not to use type indexes but then it will be even less interoperable [30:32.760 --> 30:35.840] and to me it's very important that an app is interoperable. [30:35.840 --> 30:37.840] Yeah, you're welcome. [30:37.840 --> 30:42.840] Yes, hello, yes, here. [30:42.840 --> 30:43.840] Okay. [30:43.840 --> 30:50.440] Yeah, so with Media Kraken, we saw that it can be complicated to fetch a lot of movie [30:50.440 --> 30:55.960] and also it's the same if you want to fetch from different pod, it can be very complex. [30:55.960 --> 31:02.640] I wanted to know what you're feeling about like speed and all that on Solit or do you [31:02.640 --> 31:06.960] think like Solit is doomed to be used with really low data app or do you think it's possible [31:06.960 --> 31:09.840] to have big data with Solit? [31:09.840 --> 31:12.360] I think it depends a lot on the use case of the app. [31:12.360 --> 31:19.080] For example, for my apps, even if I had perfect querying APIs, I think I would still use this [31:19.080 --> 31:23.480] because I found the offline first approach and I like it a lot, you know. [31:23.480 --> 31:28.280] But eventually, there is something called Spark UL, which means you can run queries [31:28.280 --> 31:29.800] on linked data. [31:29.800 --> 31:32.960] These type of things could get into the specification. [31:32.960 --> 31:38.960] But again, all of these depends on the specification and I really don't know when it will happen [31:38.960 --> 31:39.960] or if. [31:39.960 --> 31:44.360] I mean, I know that people working on the spec, they are aware of these issues and they [31:44.360 --> 31:48.480] are working on this, but I don't know the timeline, really. [31:48.480 --> 31:54.120] I just can say that for my apps at least, this use case, that's what I do offline first [31:54.120 --> 32:00.360] and even if I had good query endpoints, probably I wouldn't use them, but I don't know. [32:00.360 --> 32:03.240] I guess it depends on the implementation. [32:03.240 --> 32:04.240] Thanks. [32:04.240 --> 32:05.240] Yeah. [32:05.240 --> 32:06.240] Hi. [32:06.240 --> 32:14.400] If you have that offline first mode with a CRDT, is there a way to do it or there is, [32:14.400 --> 32:18.320] but have you looked into doing it in such a way that someone doesn't need to bring their [32:18.320 --> 32:24.360] own pod, that they can use their own devices and have their devices sync between each other [32:24.360 --> 32:25.360] directly? [32:25.360 --> 32:26.360] Yeah. [32:26.360 --> 32:31.440] Technically, it would be very easy and very possible because you just have the operations [32:31.440 --> 32:33.440] and you just have to do it. [32:33.440 --> 32:40.200] Personally, I have not done it in my apps because I'm interested in having easy experiences [32:40.200 --> 32:46.240] for users and what I am going to tell them if they have to synchronize two devices. [32:46.240 --> 32:49.360] Maybe I can use WebRTC or something like this. [32:49.360 --> 32:52.240] Yes, but I think they are still devices. [32:52.240 --> 32:57.240] I think what they like is the idea of having a cloud and everything is safe in the cloud [32:57.240 --> 33:00.040] and this is also what I personally would do. [33:00.040 --> 33:03.960] I don't know if I would want to have only things in devices. [33:03.960 --> 33:07.200] But to answer your question, yes, it would be very easy to do. [33:07.200 --> 33:10.640] I just haven't done it, but it would be very easy. [33:10.640 --> 33:11.640] Yeah. [33:11.640 --> 33:17.680] And by the way, well, all of this is open source, so you are welcome to fork it or ask [33:17.680 --> 33:19.520] me about the code or anything. [33:19.520 --> 33:28.040] I would be happy to help you if you want. [33:28.040 --> 33:37.200] I'll get my exercise. [33:37.200 --> 33:46.560] RDF and link data exist for so long and we don't see a lot of open source projects unleashing [33:46.560 --> 33:50.880] the potential of such a system. [33:50.880 --> 33:57.760] Why do you think it's not more mainstream and do you think there is enough learning [33:57.760 --> 34:01.120] material that are easy to understand for developers? [34:01.120 --> 34:02.120] Yeah. [34:02.120 --> 34:07.360] So I cannot answer for everybody because I don't know, but my personal opinion is that [34:07.360 --> 34:12.720] in theory, RDF is awesome, I like it a lot and this is why I am working on this. [34:12.720 --> 34:18.760] But in practice, the developer experience is not great and people when they see Tartel [34:18.760 --> 34:22.720] and RDF and all these things, they don't like it. [34:22.720 --> 34:29.060] So my opinion is that it's because lack of learning materials and the developer experience [34:29.060 --> 34:30.060] to get started. [34:30.060 --> 34:35.400] But I don't know, I think if you learn the building blocks, because I learned about RDF [34:35.400 --> 34:40.560] four years ago when I learned about SOLID, I didn't even know about the semantic web. [34:40.560 --> 34:45.880] But I learned the basic things like the specs I linked at the beginning, RDF and all of [34:45.880 --> 34:46.880] this. [34:46.880 --> 34:52.560] And I think once you understand those basic things, it's very easy to work with, I think. [34:52.560 --> 34:57.400] But I don't know, it depends on that and there are not a lot of learning materials that [34:57.400 --> 34:58.480] I know of. [34:58.480 --> 35:02.640] And there is like not one framework you can use that it's super easy, has a very nice [35:02.640 --> 35:04.800] developer experience. [35:04.800 --> 35:09.240] So I think it's still a thing of tooling and documentation at this point. [35:09.240 --> 35:10.720] But this is my personal opinion. [35:10.720 --> 35:14.120] I can't speak for what people, that's my, I don't know. [35:14.120 --> 35:20.040] Yeah, can you just tell me about the, when you stored the pod on a, I'm just, I just [35:20.040 --> 35:24.280] could do a quick read of the actual FAQs on the SOLID website. [35:24.280 --> 35:29.720] And it does, it's easily a lot of the details of how the pod providers store the data up [35:29.720 --> 35:33.640] to the provider so that options such as encryption is left to them. [35:33.640 --> 35:36.200] So that seems to like move a lot of the privacy concerns. [35:36.200 --> 35:41.760] We have existing cloud services to the pod providers, unless you self-help stun a server [35:41.760 --> 35:43.520] that you encrypt yourself and such. [35:43.520 --> 35:50.720] So do you have any like thoughts on that, on how that works with the provider escape [35:50.720 --> 35:52.120] at that moment? [35:52.120 --> 35:59.200] Yeah, so the point is, so the biggest issue today for someone to start using SOLID is [35:59.200 --> 36:00.920] which pod provider to use. [36:00.920 --> 36:05.800] Basically, if I have to recommend a friend of mine to use SOLID, I don't even know [36:05.800 --> 36:08.080] what I would recommend them. [36:08.080 --> 36:15.000] But I like the point that users choose and if you are super worried about privacy and [36:15.000 --> 36:20.080] you want everything super encrypted and everything, then you choose a pod provider that encrypts [36:20.080 --> 36:21.080] everything. [36:21.080 --> 36:23.680] But if you don't care so much, then you don't have to. [36:23.680 --> 36:26.800] You just self-host something in your home. [36:26.800 --> 36:27.800] So I don't know. [36:27.800 --> 36:31.160] I think this, this is part of the flexibility of SOLID. [36:31.160 --> 36:37.240] So it's nice that it's the choice of the user, but I don't have many thoughts about that. [36:37.240 --> 36:43.880] Personally, I self-host and I don't mind about encryption. [36:43.880 --> 36:51.160] I'd like to ask you how to find vocabularies, because I know there are a lot of vocabularies, [36:51.160 --> 36:53.440] but it's quite a chaos. [36:53.440 --> 36:57.920] They're very difficult to find and to understand what the words are. [36:57.920 --> 37:03.480] So at first I also worried a lot about this, but now it's like the least of my problems, [37:03.480 --> 37:08.400] because really you just search if there is one that already exists, like in this website [37:08.400 --> 37:12.080] I shared, there is a website with a lot of vocabularies. [37:12.080 --> 37:17.240] Just search one and if you don't search, if you don't find one that works for you, you [37:17.240 --> 37:20.040] create your own and it's not so difficult. [37:20.040 --> 37:26.680] I think it's, at first I understand how it's confusing, but once you decide that you can [37:26.680 --> 37:30.000] make your own vocabularies, it's not so difficult. [37:30.000 --> 37:34.680] Also I recommend a lot this talk I linked called a bag of chips. [37:34.680 --> 37:38.960] This is the one that changed my mind about this, that it's fine to mix vocabularies and [37:38.960 --> 37:40.840] make your own. [37:40.840 --> 37:43.000] So I recommend watching that. [37:43.000 --> 37:44.000] Yeah. [37:44.000 --> 37:46.600] Hi there. [37:46.600 --> 37:53.520] Given that you've got different pod providers and you can never be sure like what the infrastructure [37:53.520 --> 37:58.400] that you're working with is going to be like, it could be a very slow pod provider or whatever, [37:58.400 --> 38:04.280] do you have to design your apps quite defensively because you can never be sure that actually [38:04.280 --> 38:08.840] the pod provider is actually going to be able to service the HTTP request that you want [38:08.840 --> 38:09.840] to make? [38:09.840 --> 38:10.840] Yeah. [38:10.840 --> 38:15.840] My answer to that is that no, because you just follow the solid protocol and that's it. [38:15.840 --> 38:21.480] I mean if the pod provider is slow, users will be unhappy and they will use another pod [38:21.480 --> 38:22.560] provider. [38:22.560 --> 38:23.720] So I don't worry about that. [38:23.720 --> 38:28.720] I just code to the solid spec and I don't mind about that. [38:28.720 --> 38:33.040] The only thing is things that are not in the spec yet and they are drafts and different [38:33.040 --> 38:37.960] pod providers implement differently, but hopefully when the spec is more stable, this will not [38:37.960 --> 38:41.200] be an issue. [38:41.200 --> 38:43.640] Hi thanks for the great presentation. [38:43.640 --> 38:48.200] All your examples were single user applications. [38:48.200 --> 38:54.280] How would you apply the philosophy of solid to, let's say, for example, forum software? [38:54.280 --> 38:58.800] Would you either store all posts from all users in their own pods and somehow get access [38:58.800 --> 38:59.800] to all those pods? [38:59.800 --> 39:05.340] Or would you just not use it for that and just use it, for example, for public information [39:05.340 --> 39:06.840] on the user? [39:06.840 --> 39:11.800] So I haven't done anything about that, so I'm only going to say what I think about it. [39:11.800 --> 39:15.840] But basically my intuition tells me that it would be something very similar to activity [39:15.840 --> 39:21.720] pub, which is the protocol that powers Mastodon and the Fediverse, and underneath it also [39:21.720 --> 39:23.400] uses linked data. [39:23.400 --> 39:28.160] So I think it would be very similar to that, the way it works, and I don't know exactly [39:28.160 --> 39:29.160] how it works. [39:29.160 --> 39:35.480] I have not coded activity applications, but I think the information is duplicated in the [39:35.480 --> 39:36.720] servers or something. [39:36.720 --> 39:38.920] I guess it would be something like that. [39:38.920 --> 39:43.800] I don't know, but I think my answer to thinking about social applications with solid is look [39:43.800 --> 39:52.200] at activity pub, because it's the same idea, I think, or similar, at least. [39:52.200 --> 39:57.400] Just as an FYI, there's also an active discussion going on in the matrix room associated with [39:57.400 --> 39:58.400] this death room. [39:58.400 --> 40:01.240] So you might want to look there, there's also the data. [40:01.240 --> 40:06.360] I will take a look and answer, but also you guys might want to check it out. [40:06.360 --> 40:07.360] Yeah. [40:07.360 --> 40:08.880] Well, so that's it, I guess. [40:08.880 --> 40:09.880] Thank you, everybody. [40:09.880 --> 40:16.880] Thank you. [40:16.880 --> 40:17.880] Okay. [40:17.880 --> 40:18.880] Come on. [40:18.880 --> 40:19.880] Let me see. [40:19.880 --> 40:20.880] Okay. [40:20.880 --> 40:21.880] Okay. [40:21.880 --> 40:22.880] Okay. [40:22.880 --> 40:23.880] Okay. [40:23.880 --> 40:24.880] Okay. [40:24.880 --> 40:25.880] Okay. [40:25.880 --> 40:26.880] Okay.