1 00:00:12,505 --> 00:00:17,920 >> Welcome back to Curlyboi Theatre, everyone.  Next up, we have Vibhu Agarwal to talk to us   2 00:00:17,920 --> 00:00:24,320 about Python web community. Vibhu is a student,  a Pythonista and an open source enthusiast.   3 00:00:24,960 --> 00:00:33,840 He likes to play around with web servers.  He discusses about snakes and unicorns   4 00:00:36,080 --> 00:00:41,840 in local tech groups like PyDelhi. Vibhu  is joining us, all the way from India.   5 00:00:43,680 --> 00:00:52,560 The talk is prerecorded. Vibhu will  be in the chat. Is there anything   6 00:00:52,560 --> 00:01:00,560 you'd like to say before we get started, Vibhu? VIBHU AGARWAL: Hi, everyone. I think there will be   7 00:01:00,560 --> 00:01:11,840 a few questions, do pose them in the chat. Even in  the text chat or the hall video chat. Let me know.  8 00:01:14,720 --> 00:01:19,360 Hey, everyone, what is going on, especially in  Python web? People trying out web development   9 00:01:22,240 --> 00:01:26,000 or they're trying it out for the first time,  ever, they find quite a lot of things to get   10 00:01:26,000 --> 00:01:32,320 started with. As the target moved  towards production ready website,   11 00:01:32,320 --> 00:01:38,400 a lot of parts get added up. Today, we'll  discuss all about those moving parts,   12 00:01:38,400 --> 00:01:44,960 what those tools are, how are they comparative  with each other, how do they work together,   13 00:01:44,960 --> 00:01:49,120 and we'll try to understand all of them, as  a whole, and not just individual components.  14 00:01:50,240 --> 00:01:59,680 My name is Vibhu, I live in India. I've been  using Python for four years. Okay. Let's start   15 00:01:59,680 --> 00:02:05,520 with basics. Where we have a client. We a  server. They establish a TCP connection.   16 00:02:06,960 --> 00:02:17,760 Client requests HTTP request. Talking about  static websites. They would request a particular   17 00:02:17,760 --> 00:02:29,200 HTML file. They will maybe tell the path, in  the HTTP path, and what the server would do is   18 00:02:29,200 --> 00:02:34,240 to embed the content of HTML into the HTTP  response and return to the response back.  19 00:02:36,240 --> 00:02:41,360 If we want to store information into a  database or maybe we want to calculate some   20 00:02:42,320 --> 00:02:49,480 data accessibility and return some complex,  we'd want to do it not in a static website,   21 00:02:49,480 --> 00:03:04,880 but a dynamic website. We load an script and  it processes the imports and returns a response   22 00:03:04,880 --> 00:03:12,240 back. Nowadays, you can write the script in  any language and that's good thing to have.  23 00:03:13,040 --> 00:03:18,400 Now, what do we want to have a hybrid kind of  a structure in which we want to support dynamic   24 00:03:18,400 --> 00:03:28,720 and static content. It needs to redirect from the  static content and direct to the backend server   25 00:03:28,720 --> 00:03:41,360 as well. That is serving the dynamic content.  I've seen a lot of projects which use Nginx. It   26 00:03:44,240 --> 00:03:50,640 is fetching for going to fetch for static  content, it will redirect to the static   27 00:03:50,640 --> 00:03:57,120 files and it will if it receives a request, which  needs a dynamic content, it redirects that request   28 00:03:57,120 --> 00:04:05,360 to the backend server, it redirects the requests. Now, it is capable of doing a lot more than   29 00:04:05,360 --> 00:04:14,960 redirecting the request, but I've seen a lot of  projects which have a tech stack. But today, we're   30 00:04:14,960 --> 00:04:20,400 going to focus on this thing, right now, that  is our backend server, our application server.   31 00:04:21,040 --> 00:04:27,600 Now, the main task or the first task which we  see for the application server, is to receive our   32 00:04:27,600 --> 00:04:35,600 listen to a lot of requests. How about we reserve  a process just for listening to a request and   33 00:04:36,480 --> 00:04:43,120 this circle is our process which will just  listen to the request and doing nothing else.   34 00:04:44,960 --> 00:04:50,560 Our request would be coming along and this process  would this main process would be listening to   35 00:04:50,560 --> 00:04:56,080 all of those requests. Now once it has these  requests, it needs to parse that request, it   36 00:04:56,080 --> 00:05:02,720 needs to under that request and break it down into  different tokens so they know what are the inputs   37 00:05:02,720 --> 00:05:08,000 of the HTTP request so that they can process  and do some [Indiscernible] based on those.  38 00:05:09,760 --> 00:05:22,480 Now, we talk about that, this backend server loads  the Excel script through forking. Just to listen   39 00:05:22,480 --> 00:05:30,400 to the request, now what this main process does is  whenever it receives a request, it creates invokes   40 00:05:31,200 --> 00:05:40,240 a new process and loads the Excel script from the  disk and then the imports of the HTTP request,   41 00:05:43,200 --> 00:05:47,440 which would then process the request  and returns a response back. Now,   42 00:05:47,440 --> 00:05:54,560 this kind of flow, or structure, is discussed  in this [Indiscernible] CGI, Common Gateway   43 00:05:54,560 --> 00:06:04,960 Interface. But they also discuss how to parse  the imports or the request into the process.   44 00:06:04,960 --> 00:06:09,840 This happens through environment variables. So, whenever a request arrives, it listens   45 00:06:09,840 --> 00:06:20,720 to the request, parsing it down, and puts all  of the HTTP inputs it and one it is created,   46 00:06:20,720 --> 00:06:29,120 it inherits it from the parent and once the script  is loaded into the memory, the loader script would   47 00:06:29,120 --> 00:06:34,880 then pick up those imports from the environment,  process these and return the response back.  48 00:06:36,000 --> 00:06:45,440 So, that's basically CGI. Okay. Let's notice that  we are doing a fork. Fork, as some people might   49 00:06:45,440 --> 00:06:51,600 have heard, is a heavy thing because that involves  a system call. Also, loading the excel script is   50 00:06:52,960 --> 00:06:59,840 low. These are the two tasks which are not  related to one particular request and you   51 00:06:59,840 --> 00:07:05,600 may not even want to do it because what you  just want to do is to just pass the request   52 00:07:05,600 --> 00:07:10,880 and return the response back by running the  script and you don't want the external overhead   53 00:07:10,880 --> 00:07:18,640 of forking a new process and loading the script  from the disk into the memory. To deal with this,   54 00:07:18,640 --> 00:07:28,240 we have the pre fork model. Whenever we set up our  backend server, we spin up a few processes which   55 00:07:28,240 --> 00:07:35,120 load the external script into the memory. So,  whenever a request arrives, what the server does   56 00:07:35,120 --> 00:07:44,880 is to pick up one of the processes and assigns  that request to one of to that process and then   57 00:07:44,880 --> 00:07:51,280 the process would just execute the script and  return the response back. So, there's overhead of   58 00:07:52,320 --> 00:07:57,040 forking a new process and loading the script as  the request arrives because that has been done   59 00:07:57,040 --> 00:08:02,960 previously, before even the request arrived. So, that saves a lot of overhead. Because   60 00:08:02,960 --> 00:08:10,400 we have introduced a lot of processes, this  process management feature also needs to be   61 00:08:10,400 --> 00:08:15,280 there at the backend server because we might  want to increase or decrease the number of   62 00:08:15,280 --> 00:08:22,320 processes or these processes, which process the  request dynamically and so as to optimize the   63 00:08:23,440 --> 00:08:29,040 usage of resources on a side. Okay. Let's talk about this external script   64 00:08:29,040 --> 00:08:34,640 we keep saying about. So, what can this external  script do about? It can do anything because it has   65 00:08:35,920 --> 00:08:40,880 maybe all of the permissions, but what are the  common tasks? One of the common tasks would be   66 00:08:40,880 --> 00:08:49,680 to embed the dynamic information into HTML,  that is done using the template. One of the   67 00:08:49,680 --> 00:09:02,320 tasks would be to map different parts to different  differentiation or URL patches. So, mapping one   68 00:09:02,320 --> 00:09:12,080 path to its corresponding dispatcher is known as  routing. And a lot of other tasks, which might   69 00:09:13,520 --> 00:09:19,120 must not have seen developers doing because  these all common tasks are separated out in a   70 00:09:19,120 --> 00:09:27,760 separate tool, and what we know as frameworks. Now, might be familiar with the frameworks in   71 00:09:27,760 --> 00:09:39,440 the form of Django, Flask, FastAPI. Flask  is a microframework because it helps us do   72 00:09:40,000 --> 00:09:49,840 micromanage our applications. We're importing  the Flask, and then defining our path, our URL.  73 00:09:51,120 --> 00:09:56,640 So, what is happening over here? So what is  happening is that you're defining, or you're   74 00:09:56,640 --> 00:10:04,640 writing a business logic and your dispatch  somewhere in the your code and it's forming   75 00:10:04,640 --> 00:10:14,960 a layer around your business logic so whenever it  arrives, it is the front line, executes some code   76 00:10:14,960 --> 00:10:22,000 and passes that result to your business logic,  which should then process [Indiscernible] produces   77 00:10:22,000 --> 00:10:28,320 some result. This is handed back to the web  framework and the web framework would then   78 00:10:29,280 --> 00:10:36,320 may or may not perform exit operations and return  the response back. So, that's how the framework   79 00:10:36,320 --> 00:10:41,440 forms a layer around your business logic and  handles and forms a front line and it may   80 00:10:42,080 --> 00:10:48,240 intercept the request somewhere, as well, because  it may just receive the request and then send   81 00:10:48,240 --> 00:10:53,040 it back after performing some operation and not  even hand it to your business logic, based on the   82 00:10:53,040 --> 00:11:01,840 depending on the implementation of that framework. Moving on, Django is very much framework. It has   83 00:11:01,840 --> 00:11:06,800 been there for a long, long time. Has a great  community and is one of my favorite frameworks.   84 00:11:08,240 --> 00:11:17,760 So, Django is as they say batteries included. And  one of the common theme common a lot of features   85 00:11:17,760 --> 00:11:26,800 have been provided using the use of middlewares.  So, if you've not used Django, what middleware   86 00:11:27,360 --> 00:11:35,120 is perform extra layers between your framework and  business logic. Once it receives the request, it   87 00:11:35,120 --> 00:11:43,600 passes the request or result [Indiscernible] after  executing code, it passes a result to the first   88 00:11:43,600 --> 00:11:50,960 meta layer and then it executes some code and then  passes the result back to the then it passes the   89 00:11:50,960 --> 00:11:56,320 code the results to the next layer and then  finally it hands it to your business logic.   90 00:11:56,320 --> 00:12:06,240 Now, the business logic then executes some code  and hands it back. That's how your middleware   91 00:12:06,240 --> 00:12:12,560 work in Django. And this is and this way, it adds  up to a lot of features in your entire system.  92 00:12:13,920 --> 00:12:20,480 Okay. We discussed about our application  server and a lot of people must have heard   93 00:12:20,480 --> 00:12:36,240 about this application server in the form of u  WSGI. This thing comes a lot of comes up a lot   94 00:12:36,240 --> 00:12:46,080 in a development. So, remember the CGI, which is  an [Indiscernible] load and execute the script.   95 00:12:46,080 --> 00:12:57,440 Well, WSGI went one step further in stretching it  further and restricting it and restricting it even   96 00:12:57,440 --> 00:13:07,360 further in the way to how to invoke that script.  What WSGI we're going to have two different   97 00:13:07,360 --> 00:13:14,400 things. One is the server and one is that external  script. They they should be kind of independent   98 00:13:14,400 --> 00:13:20,480 from each other and how can they be made  independent of each other? If one part knows what   99 00:13:20,480 --> 00:13:27,600 is expected from the other and what is expecting  of them, then they can be kind of independent of   100 00:13:27,600 --> 00:13:33,080 each other and kind of development independently  and they can be working independently.  101 00:13:33,840 --> 00:13:42,000 So, okay, that didn't make much sense, let's  quickly look at the code. So, the external script   102 00:13:42,000 --> 00:13:47,840 should be prototyped into a one function,  what is usually known as an application.   103 00:13:48,400 --> 00:13:54,960 That application would receive two  parameters and it should return one value.  104 00:14:16,880 --> 00:14:22,720 The HTTP response status,  you're going to finally pass   105 00:14:23,440 --> 00:14:42,320 pass back and the second is the response headers. And, somewhere in between all of this,   106 00:14:42,320 --> 00:14:48,480 you'll write your code, your business  logic. Now, remember the Flask code,   107 00:14:51,040 --> 00:15:00,480 this is the WSGI application. If you go and see  your Django projects, you'll notice a WSGI file   108 00:15:00,480 --> 00:15:06,960 and that will have this application variable.  This is WSGI application. So, what do their   109 00:15:06,960 --> 00:15:13,840 frameworks do is to form a WSGI application  and gives this one object or variable back,   110 00:15:13,840 --> 00:15:22,400 which it can be plugged into any web server. And, this is the point, because we discussed,   111 00:15:22,400 --> 00:15:29,840 this is the point where you [Indiscernible]  business logic. Wrap all of your business logic   112 00:15:29,840 --> 00:15:38,400 and then just plug it at this point. So, now, it  forms a layer around your business logic and your   113 00:15:38,400 --> 00:15:46,080 web framework so the app is the front line of  your request, it hands it off to the framework,   114 00:15:47,120 --> 00:15:54,240 it may pass through middleware and your business  logic handles it and reverse its way back.  115 00:15:54,800 --> 00:16:04,000 So, the one part of the so, this  external script part is handled by   116 00:16:04,000 --> 00:16:08,960 your framework and your business logic and  the other part is the application server,   117 00:16:10,400 --> 00:16:25,360 which are commonly used in the form of gunicorn  and UWSGI. It is to pass the request and receive   118 00:16:25,360 --> 00:16:32,000 the request, listen to the request and to process  management. So, [Indiscernible] over here.  119 00:16:32,800 --> 00:16:39,600 What these processes, which actually handle  the requests, we these are known as the   120 00:16:39,600 --> 00:16:46,080 process as which handled the request are worker  processes and the process which just listens to   121 00:16:46,080 --> 00:16:53,920 the incoming requests are master processes. These  are the two terminologies over here and let's   122 00:16:53,920 --> 00:17:00,480 quickly now summarize what we saw until now. So, you write your code, you write your   123 00:17:00,480 --> 00:17:05,120 business logic, along with all of the stuff  which is provided by your web framework.   124 00:17:06,640 --> 00:17:15,920 That gets wrapped into one app or app function. So  this script is then passed on to the web server,   125 00:17:15,920 --> 00:17:22,800 which may receive all which may receive extra  inputs, for number of workers if it has to set up.   126 00:17:23,600 --> 00:17:30,400 It may also receive some certificate files  or locations so it can have the location of   127 00:17:30,400 --> 00:17:38,560 those files. And, once everyone knows about the  these inputs, it can spin up that many number   128 00:17:38,560 --> 00:17:46,560 of processes. So, whenever a request arrives, it  picks up one of the available pool of processes,   129 00:17:46,560 --> 00:17:54,560 assigns that request to that process and  then that process executes they execute the   130 00:17:54,560 --> 00:18:01,760 thing and then returns a response back. That's pretty much all of it, over here.  131 00:18:03,920 --> 00:18:13,840 Okay. Now, let's move on to  asynchronous. Just a moment.   132 00:18:16,240 --> 00:18:23,200 Now, asynchronous development, in the last three  or four years, has seen a lot of maturity, a lot   133 00:18:23,200 --> 00:18:28,160 of tools and libraries and a lot of frameworks  have been developed using the asynchronous   134 00:18:28,160 --> 00:18:36,880 development. And similarly, in the web world, as  well, we've seen a lot of growth in web frameworks   135 00:18:36,880 --> 00:18:42,880 and libraries so before moving into into those,  let's quickly discuss what asynchronous is.   136 00:18:43,840 --> 00:18:50,800 So, let's let's take an example, you are playing  a cards game and you now you play your turn   137 00:18:50,800 --> 00:18:59,840 and your opponent is thinking about their turn  and is a little bit slow, what he thought is that   138 00:18:59,840 --> 00:19:06,000 you can attend a talk while they are playing the  cards game. So what you essentially did is to   139 00:19:07,200 --> 00:19:14,080 utilize your time efficiently and did some work  when the other person or some other task is not   140 00:19:14,080 --> 00:19:19,440 depending on you. So while you are listening  to the talk, you thought of a good turn and   141 00:19:19,440 --> 00:19:26,560 they played their card and as they were going to  disturb you just to poke you to play your card,   142 00:19:26,560 --> 00:19:31,920 play your card, there was a [Indiscernible]  standing and they asked your opponent to wait for   143 00:19:31,920 --> 00:19:41,440 a while. Once you're free, you will be available  back. So once you're done with the talk, you're   144 00:19:42,560 --> 00:19:50,240 hopefully happy with my talk. You go to the  negotiator and you see your opponent. You ask your   145 00:19:50,240 --> 00:19:56,960 opponent, hey, I'm ready to play the turn. You  go and you then play and then you play your turn.  146 00:19:57,840 --> 00:20:04,960 So this negotiator and this list kind of  act like an event loop so the task can be   147 00:20:04,960 --> 00:20:14,720 popped up from the list and then added back  by the negotiator into this list. So, you can   148 00:20:16,480 --> 00:20:23,520 essentially be doing one task and then if the  other if the task is not really depending on you,   149 00:20:23,520 --> 00:20:31,760 you can drop doing or processing that task and  you can pick some other task. That's kind of   150 00:20:31,760 --> 00:20:38,160 asynchronous that's kind of what asynchronous  is. And if you want to learn with more,   151 00:20:38,160 --> 00:20:42,080 you can definitely check this out,  if I don't explain it properly.  152 00:20:43,040 --> 00:21:01,680 Okay. Let's talk about ASGI. It is kind of a super  set to WSGI and provides a lot more flexibility.   153 00:21:03,840 --> 00:21:08,400 Similar to WSGI, there would be two parts. One  would be a server and one would be an external   154 00:21:08,400 --> 00:21:16,720 script and they would be independent of each  other and should be developed independently now.   155 00:21:18,560 --> 00:21:25,520 ASGI is scope, one is events. Scope is  something that stores the information.   156 00:21:26,880 --> 00:21:42,800 It stores some preferences about the connection.  Now, events are the messages are exchanged between   157 00:21:42,800 --> 00:21:48,480 the web server and the application. Let's look  at the code to understand it, even better.  158 00:21:49,600 --> 00:21:57,440 Again, it the excel script should be wrapped  up into one callable that is application.   159 00:21:57,440 --> 00:22:04,640 Now notice over here, it is a function and not  a normal function. It receives three parameters,   160 00:22:05,600 --> 00:22:10,080 one is the scope, this would contain the  information that is the same scope as   161 00:22:10,080 --> 00:22:14,880 we discussed just now. It's going to contain  the information about [Indiscernible] request   162 00:22:14,880 --> 00:22:20,320 headers and the connection or other connection  information. The second parameter is the receive.   163 00:22:20,320 --> 00:22:28,320 This is a callable. This is an async function  which you can await and get the message from the   164 00:22:28,320 --> 00:22:33,760 web server. Now once you get your message from the  web server, then you can take some action and once   165 00:22:33,760 --> 00:22:42,960 you've taken action, you can return the response  back. This, again, a callable, which is expecting   166 00:22:43,520 --> 00:22:51,440 something. This is expecting another event. Event  is just a small [Indiscernible] which represents   167 00:22:51,440 --> 00:22:59,760 one method. It may have the it has to contain  this type key, which categorizes which kind of   168 00:23:00,400 --> 00:23:06,560 message you're returning back and that  and you can await on this "send" callable.  169 00:23:07,680 --> 00:23:11,920 So, now you notice there is no  return statement over here, so   170 00:23:11,920 --> 00:23:18,400 what you can do is do it on a loop and you can  so, with one instance sharing of application,   171 00:23:18,400 --> 00:23:22,160 you can get multiple messages and you  can return multiple messages back.  172 00:23:25,040 --> 00:23:34,400 With along with our asynchronous app, we have  our we have a lot of asynchronous web frameworks,   173 00:23:34,400 --> 00:23:40,320 as well. Why do we have a lot of different  web frameworks, other than the ones which   174 00:23:40,320 --> 00:23:46,000 we discussed about earlier? Because they're  natively synchronous and natively synchronous   175 00:23:46,000 --> 00:23:53,520 [Indiscernible] transformed into asynchronous  that straightforward in a straightforward manner.   176 00:23:53,520 --> 00:24:00,640 A lot of work has to be done if you  want to develop fully if you want to   177 00:24:00,640 --> 00:24:10,240 fully optimize resources and take full advantage  of concurrency. Sanic is a fast framework. Quart   178 00:24:16,640 --> 00:24:27,680 is very similar to Flask. FastAPI is a recent  framework. It focuses on developing the web APIs.   179 00:24:28,480 --> 00:24:39,680 FastAPI is built on top of Starlette. It's  a fantastic [Indiscernible] framework,   180 00:24:39,680 --> 00:24:47,520 which I'll be using a lot. Django Channels is  one of the asynchronous framework, which comes   181 00:24:47,520 --> 00:24:53,840 under the Django project. Now, Django does have  some async [Indiscernible] I think, last year,   182 00:24:57,840 --> 00:25:02,560 the whole of Django is not natively  built or natively asynchronously built.   183 00:25:03,840 --> 00:25:13,040 It has been there for a long time. It does  best in what it's to do. But channels is   184 00:25:13,040 --> 00:25:18,560 a relatively newer project and it  is a fully asynchronous framework.  185 00:25:20,640 --> 00:25:27,840 Now, that was the that is the third that is  the second side, or the right side of our   186 00:25:28,800 --> 00:25:45,280 of the framework. We have these three three of the  most popular servers out there. Daphne comes under   187 00:25:45,280 --> 00:25:59,040 Django project. It is intended to be used along  with Django Channels. It seems to be just working   188 00:25:59,040 --> 00:26:09,600 fine and actually it seems to be working great. Hypercorn is one, two, and I think, three,   189 00:26:09,600 --> 00:26:16,560 as well. It's lightning fast  and it focuses on performance.  190 00:26:17,440 --> 00:26:30,880 And, Uvicorn I've [Indiscernible] the most. So, I  know a little bit about how [Indiscernible] works.  191 00:26:32,160 --> 00:26:36,000 And if you want to see a  little more about discussion,   192 00:26:36,000 --> 00:26:41,120 if you want to see a little more discussion about  servers, you can check out check out this link.   193 00:26:42,080 --> 00:26:50,960 And, the working of ASGI servers are similar to  how WSGI works. Whenever a request arrives, it   194 00:26:52,960 --> 00:27:00,960 web server takes a process from its available pool  of processes, which will have the ASGI app in its   195 00:27:00,960 --> 00:27:06,880 memory. It will then take on the request, process  the [Indiscernible] and return the response back.  196 00:27:07,520 --> 00:27:12,800 The only difference is that what WSGI does,  whenever it receives multiple requests,   197 00:27:12,800 --> 00:27:21,760 it processes those requests singly, even  if they [Indiscernible] operation, just the   198 00:27:22,400 --> 00:27:29,360 the [Indiscernible] just wait. But WSGI can  show you some other task when one of the   199 00:27:29,360 --> 00:27:34,640 process goes for [Indiscernible] operation,  it can show you some other task, which   200 00:27:34,640 --> 00:27:43,360 WSGI [Indiscernible] in the future, before,  and that utilizes the resources when nothing   201 00:27:43,360 --> 00:27:53,280 is dependent on us or the application. So, it gives a better response time to   202 00:27:53,280 --> 00:27:59,200 all the requests and also saves the overall  time. So, that improves performance.  203 00:28:00,720 --> 00:28:07,040 So, that was pretty much it. What we could  takeaway, from over here, is that we know about   204 00:28:07,040 --> 00:28:12,480 all of the different parts, how do they work.  So, let's say if if you [Indiscernible] imports   205 00:28:12,480 --> 00:28:17,600 and the output is not is not coming out correct,  there may be some error in your business logic and   206 00:28:17,600 --> 00:28:24,240 you might want to fix that fix that thing in your  business logic. And if you see that there's some   207 00:28:24,240 --> 00:28:31,760 error somewhere in your tech stack, we couldn't  pass the request, that may by an error on the   208 00:28:31,760 --> 00:28:40,160 HTTP, which is used by the web server. You may  want to file a bug report there. If you think of   209 00:28:40,160 --> 00:28:47,120 a feature that that may be used commonly, you  can re you can ask for that feature in one of   210 00:28:47,120 --> 00:28:53,440 the frameworks and if they do not accept it, you  always have the luxury to create a third parties   211 00:28:54,480 --> 00:28:59,120 library, which the people can plug it into  their web frameworks and that would just work.  212 00:29:00,720 --> 00:29:09,360 How did I where did I read about all of these?  Well, I read all of this. I read all of this from   213 00:29:09,360 --> 00:29:16,480 the amazing documentation provided by all of these  wonderful, wonderful projects. These just contain   214 00:29:16,480 --> 00:29:20,720 all of the information which I talked about,  most of information which I talked about today.  215 00:29:22,080 --> 00:29:31,760 And, I'm ready for some questions now. Thank you. >> Okay. We're back. Thank you so much for that   216 00:29:31,760 --> 00:29:37,680 talk, Vibhu. That was, like that was  really helpful. I know that I'm going   217 00:29:37,680 --> 00:29:43,200 to rewatch that to pay attention and to  learn a lot and I really appreciate you   218 00:29:43,200 --> 00:29:48,960 sharing what you learned through your journey  through all of the web frameworks with all of us.  219 00:29:50,560 --> 00:29:56,800 Is there anything you'd like to say? VIBHU AGARWAL: I do see a few questions,   220 00:29:57,920 --> 00:30:04,800 I'll answer them in the Curlyboi Theatre chat  and I'm glad that people found it helpful.  221 00:30:04,800 --> 00:30:13,840 >> I think I think a lot of people did. Thank you,  again. So, yes, you can talk to Vibhu some more   222 00:30:13,840 --> 00:30:19,440 and ask some more questions over in the Curlyboi  Theatre text chat, in the channel section and   223 00:30:19,440 --> 00:30:26,960 we are going into our afternoon or our time zone  appropriate time of day break. So, we'll see you   224 00:30:26,960 --> 00:30:34,800 back here, when I get the right tab open that's  got the right thing, in about 45 minutes. All   225 00:30:34,800 --> 00:30:48,400 right? Have a nice break, everyone. Have have have  a nice drink of water. Stretch your legs. Bye.