Web Programming with Flask - Intro to Computer Science - Harvard's CS50 (2018)

Web Programming with Flask - Intro to Computer Science - Harvard's CS50 (2018)

Show Video

Alright, this is cs50, and this is lecture seven wherein we pick up where we left off last time and talking more about Python, but this time using Python for even more powerful, purposes. And. Alliteration I didn't intend until I just said it there but the goal here with Python now is to actually use this language to, generate, another language in particular HTML. And what we'll do is start to provide, all the more of a mental model for what you would call separation, of concerns whereby. When you design more complicated. Web based rather, when you design more complicated, software you, tend to try to adopt certain design patterns, so that you're not just writing everything in one big file that gets a little confusing, unwieldy, to maintain, and to add to over time but you start to separate, your concerns, and your functionality, and your features and your collaborators, work into different files and different, methodologies. So we'll try to give you some of these industry, standard approaches today and why they actually solve problems but of course how did we get here a few weeks ago we talked about this thing this virtual envelope that just represents packets of information zeros. And ones going across the internet from, point A to point B and among, the messages in these envelopes might, be for web requests, and we talked about HTTP. A protocol. Hypertext. Transfer, Protocol, that just sends message like this inside. Of the envelope and this is requesting, of course the default page of a website as implied, by the slash and in many cases but not always this implies, the default file name of, index.html. But that's a human for convention. Not, a requirement. Hopefully. The server responds, with a numeric, code equal to what integer. 200. Hopefully, a number that we never actually really, see unless you get more comfortable and start poking around Chrome's, inspector and, you look at your network traffic right so here, is an actual successful. Response which means everything, is indeed okay and if the browser looks a little farther, down in the virtual envelope if you will it will see another language called. HTML hypertext. Markup. Language which is the stuff we wrote a couple of weeks ago and you'll continue writing this week as you now dynamically. Generate. Websites, but what we'll introduce today, is what's. Also known as a framework or more precisely a micro, framework. Because we'll saved in just a few minutes time that it can actually be really annoying and really tedious to, generate, websites, automatically. Using Python if you have to write Python, code alone and so humans, over the past several years have noticed wow every, time I make a web application, using Python, I find myself typing, the same lines of code again and again just to get started or when, I'm collaborating with someone else I find that whoo it's a little hard to collaborate if we're all working in the same file so, humans, have invented what are called frameworks, and this is an example, of code written, in Python, but, using, a framework called, flask. So whereas, bootstrap. Which you played with a little bit is a framework for CSS, and kind of sorta JavaScript, they have some dynamic features as well a flask. Is a framework for Python, that, just gives you some library, code that you can use freely in. Your own applications, and it, just makes it ultimately a little easier, to get your work done and build, the thing you want to build as opposed, to having to re-implement. Or reinvent, the wheel again, and again like people before you and so here is a methodology. To which I alluded earlier just, to have a mental model for the coming weeks so up until now pretty, much every program we've written in C, and most, recently in Python, you. Could call like controller. Code, or controller, logic, or business, logic right it's all about getting. Something done logically, usually, in one file maybe two files if you have another. Helpers dot C or header file or or whatnot but we've been writing logic, but today and two weeks ago when we will focus on web programming, in HTML, and CSS there's this second part of our world there's like the logic, that just gets the interesting, work done with loops and conditions and all that but, there's also now going to be the aesthetics, the stuff that the user actually sees and, the way you present your data so, we're gonna just introduce two letters.

Of An acronym today moving forward anytime. You start writing logical, code in Python it's, going to be called your controller, it's sort of like the machine that operates your entire web application, but anytime you do something more aesthetic, we're gonna call that your view, code so C and V, being the letters here and this just refers to like a separation, of concerns your, logic goes in this file and your aesthetics, and formatting, go in this other file next, week we'll introduce databases. And SQL, structured query language and will introduce an M here, because the acronym that's invoked. For quite some time now is MVC, though there are alternatives, to this mental model and that just means there are three different types of things you should be thinking about but when building an application but today we're gonna focus on these two controller, and view and up until now we've pretty much didn't been doing entirely controller. Stuff when writing code so. The motivation ultimately, will be to get to the point of building, essentially. This the, freshman intramural, sports website, which I was, the first one to make back in, 1996. As a sophomore, maybe, 1997. As a junior after having, only taken cs50 and a follow-on class cs50, one and even, though this is horrifying, to see now a days underneath. The hood was, a whole bunch of controller, logic and a whole bunch of model, code even though I don't think MVC, existed, as an acronym back then until humans kind of figured out the pattern but, what it did have via the menu up here was, a whole lot of functionality, so no longer did you have to walk across campus filling, out a form and drop off a sheet of paper and like an RA or Proctor's dorm room. You can instead just go on the web which all of us surely take for granted today fill, out a web-based form and then at the time the, proctor in charge of frosh, IMS would get an email confirming, who had actually registered for sport and eventually we added CSV, files comma separated, value files like spreadsheets in which the data was saved then we had this really cool tournament, bracket thing which is all very dynamic and impressive I'm sure at the time but. We'll focus on really just the, fundamentals, today so. How do we get there well let me go ahead and open up cs50, IDE and propose, that if we want to make a website. A web, application really. And by, application, I mean something that does have logic by website, it's generally, something that's static so that's what a web app is it's something that changes based on who's using it when you're using it and what you're doing with it let, me go ahead and in most the most annoying tedious, way possible. Implement. A web application using, Python, so I'm gonna go ahead and open a file called.

Serve, Dot, tie, to, serve up a website and I'm gonna go ahead and import some library, code so from HTTP, server import. Something called base HTTP. Request, Handler. And also something called HTTP. Server and then I'm going to go ahead and use this new keyword class which, is HTTP. Server. Server. Request. Request. Handler. Base. HTTP. Request, handler. Then. Handler. Then, I'm going to go ahead and in here implement, a function called do. Def. Do, gets which, implies this is a function, in Python, that should be called anytime a user visits. My web server via. Gets, the type of verb that we talked about in the context of the web so suppose that my only goal here is to make a web based application, that for the moment just says hello world we know how to do this with HTML, but with HTML that's just a file let's write a program that, not just prints, HT a hello, world but generates, a web page containing, hello world so the way I might do this is this I can literally say self, because self refers to the web server in this case and I can go ahead and send a response code, of 200, just kind of presumptuously, assuming everything's gonna be ok in a moment then I'm gonna go ahead and send a header which, recall we've discussed briefly in the past whereby. This header is gonna, be content. Type. And its value is going to be text HTML which, is a clue to the browser that it's receiving not a jiff or a JPEG or something else but, an actual HTML, page and then I'm gonna go ahead and say that's it for the headers I'm gonna call function, called end headers. And then, lastly, I'm gonna use Python, code to dynamically, generate my. Website now what is the website have to have just hello world at the end of the day but there's a whole bunch of HTML we need to do in order to get to that point so I'm gonna use a function, called. W. File right, in order to write out the following let me go ahead and write out doc. Type, whoops, exclamation. Point doctype, HTML. Then. Let me go ahead and do the same thing W file that's, right let. Me go ahead and copy pasted this moving forward which of course is always a bad instinct, then let me go ahead and output 'html lang, equals. En. For, English and, notice I'm using single, quotes inside, my double quotes so that Python doesn't get confused then let me go ahead and output, alright. It's head tag here. Then, what comes after the head tag typically. Yes. So usually title, lately, so title will be like hello whoops. Hello, title, close the title tag and now, we're, gonna go ahead and what, comes after title. Closed. Head I think from doing this right and then after this we probably have, body. And then, hoe my god this is the worst way to build a website but, let's go ahead and now say something simple like hello world and, now, let's go in here and say something like. Body. And, then, finally. Let's go ahead and end the page and, say. Slash HTML. Done. Okay, and now I actually need to configure the server to listen on a port so let me go ahead and define a tcp, port of 8080 which we've been using let, me go ahead and define the server's address as being o 0, dot 0 dot 0 dot 0 which is what the IDE uses by default like a lot of servers and then let me create the web server, HTTP.

Server, Server. Underscore. Address, HTTP. Server. Request. Handler. HTTP. D dot serve forever. Ok. That is how you make a web based application that dynamically, generates, HTML. Retrospect. I really regret typing all that out because the whole point now is to throw this code away like this is why frameworks. Exist, if my goal quite simply at hand is to write Python code that dynamically. Generates. HTML, then. Calling. Lots of functions, like right which is essentially the equivalent of print in this context, it's just tedious I got bored writing, it I accomplished so terribly, little at the end of the day and so frameworks, exist to make our lives easier, but what's going on underneath the hood is exactly. This when, we start using this framework called flask it's just gonna make all of this automated, for us it's going to make it easier, to specify, the IP address, that you want to run your web server on it's, going to make it easier to specify the port number that you want your server to be listening on and it's, gonna make it easier, to, respond. To, get requests. Because flask, will take care of the implementation of, some function, like this one called do, get so, all of this is there underneath the hood but the flat of the flask framework, gives us essentially an abstraction, on top of that so, do I actually mean by that if we want to distill this now into a, web, simpler, web application, first let's go ahead and do this let me go ahead and open up a terminal window and let, me go into, my, code here and go, ahead and run Python observe. PI and you'll, see nothing seems to be happening just yet so I'm gonna go to cs50 IDE web server to open, up a tab containing. The web server that I'm now running and you'll see that's it that's the only thing I accomplished, right now it's not dynamic to be sure but, there is code in Python code there with which I could actually do, something dynamically. But, let's instead do this now with. Flask, this framework that seems to make our lives easier I'm gonna go ahead and make a program called. Application. Dot, Pi which is just a convention I could call it anything I want and I'm gonna go ahead and say the following let's, first go ahead and import this framework called flask and specifically. Import, capitalised, flask, which is the name of the framework itself and then let me preemptively, import, a couple of functions called, render, template and then this special global variable, called request, you would only know to do this from reading the documentation, but, now let me go ahead and say hey flask could you please give, me a web, application. And this is copy paste you need this at the top of any flask application, and it just means turn, this file application. Dot PI into. And web, application. Then, lastly I'm gonna go ahead and do this I'm gonna tell flask I want to build an app that has a route that's, listening for slash, inside. Of that virtual envelope and, whenever. Flask, you see a request for. Slash from. Some user go, ahead and call this function which I'll arbitrarily called, index but I could call it foo or bar or whatever and what, I want you to do is this return. Hello. World and, that's. It so. All of those other lines I tediously, wrote out a moment ago are now distilled, into just seven, lines which none of which are completely obvious how they work just yet but, if you assume that this means give, me access to the library turn. My file into a web application, and listen. Now for get requests. On slash, then. It kind of makes sense and fits into the mental model that we introduced a couple weeks ago with, HTML, and CSS itself, and to run this server what I'm going to go do now in my hello directory which is where a online, copy of this is on the courses website I'm gonna go ahead and quite simply say flask run so, a flask is not only a framework or code that what you have access to as. Free and open source code but it's also a program, you can run at the command line that also figures out how to return the server on and just run it forever you're gonna see some diagnostic, output at first glance most of which you don't have to care about but, there will be a URL that's a spit out which is based on your own username mine, today is J Harvard 3 just, for demonstration, purposes and if you click on that URL and then, click open you'll, see now this version.

Of The same application, doing. Just this now I'm kind of cheating though because if I open up Chrome and view my page source notice, that of course, I'm cheating, because, all I've done is print, out hello world and if I view the source of this page I'm literally only going to see hello. World and no actual HTML, because I literally didn't type out any HTML, in my, file, but it turns out that flask's, makes this easy as well, so let me go ahead and stop the server here for just a moment ctrl C is your friend it gets you out of whatever program is actually running and let, me go ahead and do this let, me go ahead and not just return quote unquote hello world as, a hard-coded, value let, me go ahead and return, the rendering. Of a template, called. Index.html. And. So, this is a feature of flask 2 if you want to separate your logic, your controller, from, your HTML. Your view you literally put the former in application, dot PI and you put the latter in an, HTML, file like this and you tell the controller, code application. PI, to, show the user to render for the user the, index.html, file. So, where do I put this the convention, would be to make a directory, called templates. And then. In that directory, go, ahead and put a file called, index.html, and. If I go ahead and open up the file that I already created in advance of class here let me just show you what this looks like and then, we'll take a look at it in a browser here. Is HTML. Now, with. A pretty, fancy, feature, that. We're about to reveal the utility, of what. Jumps, out at you as new in this file. Yeah. Yeah. Two curly, braces and, somehow or other that used to be saying world but, in my final version of this I actually am hinting at some more powerful. Capabilities, this kind of looks like a placeholder if you will maybe someones actual, name and here's, where the power of something like flash comes into play it makes it really easy to do something like this so let me go ahead and actually, turn this into something a little more interesting, let me go into application up, high and before, I actually render, this HTML, file let me go ahead and do this let me AHA go ahead and declare a variable called name and let.

Me Go ahead and check the incoming, requests the inside of that virtual envelope. Let me check its arguments, or any of the HTTP. Parameters, that were passed in and try, to get something called name. Like, this let, me go ahead and save that and, then, notice, this render, template takes multiple arguments, the first one should be the name of the template you want to render but if you want to pass in data dynamically, you, can use. Named. Parameters, in, Python recall from last week that you can do things like this x equals y and z, equals W you can pass in the names of the things you want to pass in and their corresponding, values, so, if I want to pass in a name. Variable. And set. It equal to the, name variable, that I just defined watch. What we can do here let me go back to my console. Let. Me go ahead and rerun, in my. Hello directory, which is available online flask, run and now. Let me go over to this where it previously said hello world let, me now just like with our Google example, a couple weeks ago type in not Q equals cats which, is what we did last time but, maybe name equals, David. To simulate a get request and if I did everything right when I hit enter I now. See this dynamically. And if I change this now from David to say Veronica. Of course this is going to dynamically, output, this can someone now try to break my code propose an input that I should try to see if I messed, up somewhere. No entry okay no input or what's that I, say. Again. Name. Equals name I like that one too so let's try that name equals name so. Okay. I mean it's kind of a lot maybe, like a grammatical. Bug or semantic bug but not really a code bug per se, that's, just user error but what if I just get rid of it okay. That just looks a little stupid so an aesthetic bug but we should probably start handling this what if I get rid of name altogether. Interesting. It seems that my final version actually has some built-in functionality, so where is that coming from well what if I did this it turns, out that, I could say something like this if not named then, go ahead and set name equal to world would be one way of doing it or I. Could actually use the, dysfunction, here turns out that this get function, can take a default, value and so, if you read the documentation you'll see that the second value provide, will be used if the user hasn't provided, one and so indeed if I reload now and see nothing I get world and if I instead do name equals, say Brian I get, that dynamic, output and so when I mean when I say web application, this is just a hint of what I mean this is dynamically. Generated content. It's not hard-coded, because it's actually coming from the user so when Google implements. Its slash search web. Application. This is the kind of thing they're doing it's way more involved of course they're searching a database looking, for cats and dogs or whatever it is you're searching for and then generating, HTML but, notice with just this simple, approach can. We ourselves generate. Any HTML. We want dynamically, because, all we have to do in that template, called, index dot HTML is. Exactly. This hello. Comma and then a placeholder, where name is the variable, you're passing, in and so to be clear it doesn't have to be called name I could do something like foo, which would be a little nonsensical. But if I do that the variable, I plug-in needs to be called foo here, and so there's a one-to-one correspondence, between, the things before, the equal signs and where. They get plugged in down here, are. Any questions, then on this simple. Example but building, block yeah. Sure. By dynamically, generated, I mean, I have. Not written in advance by. Typing it out manually a web page that says hello David or hello Brian or hello Veronica, that. Page of those pages are all generated. Dynamically, based. On user input I wrote most of those pages I wrote everything up into and after the comma but, then I'm sorry up to the comma but, then the names are dynamically added, good. Question other questions. All. Right so. Why. Don't we rewind, to. 1997. Or so and, see if we can't build a more dynamic web, application, that actually, allows students, to register for, something that's, a little more compelling, than just providing their name so let me go ahead and open up frosh I am which. Is the first, larger-scale. Application, we have here today and notice, that I have a few, files so, already things are going to escalate quickly whereby.

We're Gonna suddenly introduce, multiple templates but we'll do this in order to solve a problem but first let me go ahead and open up application, PI which just like your main function, in C is kind of the entry point now to a web-based application so. Notice, that. Let's. Start like this let me go ahead and delete that and start, from the beginning here let's. Go ahead and, do. This. In, frosh. IMG, row we. Have this default route of slash and notice that it's going to render index.html. So when you start to read someone else's code you kind of follow these breadcrumbs, so let me go ahead and open the same folder frosh I am let. Me go into. Let. Me go ahead rather let's do this from scratch actually, let's do this index.html, and, let, me do the familiar. Doctype. HTML. Then. Let me go ahead and do an HTML, tag here it finishes my thought for me the head tag here the title tag, here, frosh IMS will, be 0 will be the title here let me go ahead and create a body and now, for, this web, page I want to go ahead and have a few things via which the user can actually register for. Frosh I am so let me go ahead and have just some title text here like register, for frosh IMS like. I did back in the day then let me go ahead and start a form tag and then, in here what information, might student wanna provide when registering for something like a sports team. Okay. The students name so input. Type. Equals text. The. Name of this input probably, shouldn't be something generic like Q it should probably be more descriptive like name so it's a little weird looking, but name equals name and we'll go ahead and do this and if we really want to be fancy we can do like a placeholder text, of name just to in light gray text show the user what we want and then back in the day minimally, the students registering for sports how to provide their, dorm so the building in which they lived, so in HTML, we've got a bunch of input types we've got text boxes turns out there's text areas which are even bigger check, boxes radio buttons, what's.

Most Apt perhaps, for choosing your dorm. Like. A drop-down list otherwise, called a a. Menu. But which tag, I'm. Sorry, not. A container a little more precise than that what with what tag can you generate a drop-down. List if, you've done this before in HTML. Select. So it's not perfectly. Clearly named but it's indeed a select, menu by name and so I can actually do this select and the name of this field will be dorm for instance, and then, inside, of this I'm gonna go ahead and have a few options so, one option might be, lets. Say a plea court which is one of the buildings in, which freshmen, live there. Might be another one called. Kanaday and then there's going to be bunches of others and then notice too if you've never used a select menu which wouldn't refer Lee had occasion to yet unless you've done this before these. Options, also have to have values, which for my purposes are going to be exactly, the same but. Whereas, what's. Between the tags is, what the human sees it's, what's between these quotes as the value of value that the computer, actually sees so, these are the words that populate the drop-down menu these are the values that actually get stuffed into the virtual envelope, that the student him or herself actually. See so let me go ahead and save this let, me go ahead and now, open up my console, and I'm. Gonna borrow a little code just so that we can do this from. Scratch here, so let, me go ahead and grab from frosh I am my, application. Dot. Pi file, and go. Into my, workspace. So. Let me go ahead now and run, flasks run wherein. I have this application dot, PI file I'm gonna see the URL at which my code now lives and if I open this up I'm gonna see an internal server error so, intended. At some point because internal, server error recall was one of the more arcane status, codes 500. That you probably have not seen unless you're visiting a website where something has actually gone wrong so, how do I begin to figure out what has gone wrong now that I'm actually writing code and not just writing hard-coded, HTML, well all of the clues are gonna be found here, inside, of the. Console, window so when you're running flask you, are running a full-fledged webserver, you are listening, via tcp/ip.

For. Incoming, requests. From users and so what you'll see in the console is not just a diagnostic, output when you first start scratch start, flask but you're gonna see all of the error messages, that might actually happen, thereafter, and this is a little cryptic looking frankly, it's overwhelming, to see this text at first glance but whereas in clang and in C it generally, helps to look at the very top sometimes. The error messages here in this context, of flask you're kind of toward the bottom and here, we have template, not found template. Because you can't find index.html. And that's just because I screwed up so let me actually exit, flask by typing ctrl C and if i type LS in, my directory, notice. That I haven't quite practiced, what I've preached it's, perhaps a little subtle, but I haven't organized, myself, in the right way what have I done wrong. Yeah. Yeah. It's kind of a silly mistake I didn't make a templates, directory so, you can do this in a few different ways by the folder, icon up here you can create a new folder by right-clicking or ctrl-clicking, or in, Linux you can do make der for make directory, and so I can do make der templates, enter, and then, I can move my index. Dot HTML file, which I wrote a moment ago into, my templates, directory by, just using MV, for move and now, I can go ahead and run flask run cross. My fingers go, back to the browser tab, and click reload and, voila, now I actually see the form so have these kinds of instincts, I didn't actually intend, that but I forgot to create the folder I got this server error you don't have to just stare at the browser which is not gonna have much information but if you look at the console, the terminal, window, that you have control over will, you see those clang like errormsgs so, here we have a basic HTML form, it's not complete because I didn't bother typing, out all of the dorm names but I do have an input of type text as well as the Select menu and I'm also kind of missing a key detail it seems what. Should I probably add to this form. Yeah. Well I'm selecting, I could be selecting dorm so I could clean this up in a couple ways I also am missing a, submit. Button now it turns out you could probably hit enter and it would actually be submitted by default but we can fix this so let me go into index.html.

Let Me shrink this tab just a little bit and let me fix both of these things so let, me go ahead and open up, this latest, version which is now in that templates. Directory. Let. Me go ahead and at the bottom here do an input type equals submit, the. Value, of which is gonna be say register, just to make clear to the human what's going on let, me go ahead and go. Back to my form click. Reload and nothing's. Happened just yet and that's because, by default when. You make changes to some of your files flask. Is not going to notice and we'll fix this actually in the coming problem set by adding more code and a little more complexity, to automate this for you but when in doubt just ctrl, C to quit flask then, go ahead and rerun, flask that'll reload, all of your HTML all of your Python code and if I now go back here, and click reload we'll. See the register button so no there should never be any surprises, and if there are just try to get to the. To. The diagnosis, thereof this is also a little unclear to as to what this menu is so, it turns out that if you actually create, a bogus, option, like this that has no value and say, something like dorm you, can save, this let's. Go ahead and restart flask and reload. The page here you'll, see that now you see dorm. Unfortunately. This is kind of stupid because, now dorm, is where you can literally live apparently, which doesn't quite feel right so there's HTML, fixes for this too I can actually go in here and technically, say disabled. So you can't actually select, that now, if I rerun flask and reload now, it still, shows. It there but, because I already selected a plea court you can see it in grey and we can actually be a little more specific if you want to not only disable, it but select, it by default and then, go ahead. And reload, the page here, now you'll see hopefully what's familiar on most websites it says dorm but, it's disabled, and even though the silly checkmark is there like you're forced to choose an actual. Dorm so these are minor aesthetics, but the kind of things you now have control over so what's, gonna happen I haven't, actually specified, where this form should go when I actually register.

Because I'm missing some key details on the form tag and we haven't done this in a couple of weeks but when we were playfully. Re implementing, Google what, else did we add to the form tag. What. Attributes. Anyone. Remember. Yeah. Oh so. You again action. Which is means. What. What. To do alright so the action we want to take even though this is not necessarily, perfectly. Net well name is where, do you want to submit the form to and I could actually submit this in a few different ways I'm gonna go ahead and say you know what submit it to a a reasonably. Named route slash, register, Google, for instance might have code that instead says to submit their form to slash search but we're not searching for something we're registering so the name of the route is entirely up to us and via, what method should we submit, this information what. Are our two options. Get. Or post re get it tends to be the default if you don't mention in links why much you want to use post instead. Yeah. You want it to go to a database and do something, in the right verb to use there is to post information as opposed to getting information and, even more specifically, when it comes to privacy when you use post the information, doesn't end up in the users URL, and therefore it doesn't end up in his or her history and therefore doesn't end up in a place that siblings, or roommates or anyone else can actually see just by poking, around so we'll go indeed go ahead because this is my name and dorm and maybe my phone number and email and credit, card number or the like on some other website I'm gonna use post for that instead, so, the catch here is that this week, we, now have the ability to implement, slash register. Two weeks ago we could just send people to Google's, slash search but, now we have, the ability to make our own routes, but how many routes have we defined thus far in application, PI. Just. The one and it's, again some new syntax with the funky at sign and the route keyword here, but let, me actually just intuitively. Guess that you know if I go ahead and say app dot route slash.

Register. I bet, I could implement a second route and tell the web server to listen in two places on slash as well, as on slash register, but if I wanted to listen, specifically. On post it actually, has to be this, methods. Equals, quote unquote post. Because. That by default just for convenience it assumes only gets so I need to add that you'd only know that from the documentation, now, I want to go ahead and define a function this, is slightly an annoying feature of flask you have to give the function a name even, though you'll probably never reference, it anywhere so I'm gonna go ahead and just reasonably, call this register, and now, I have to, do what, am I gonna want to do when. The user clicks that submit button I. Want. To store it somewhere so I probably want to store it but what what, might I want to do first before he or she is actually allowed to register even though they've clicked that submit form. Maybe. Confirm, their information, right because if a lazy user comes in or if a user accidentally, clicks the button or hits enter they might actually submit nothing, no name no dorm that's not useful information, it could just be perceived as spam so we probably want to ask some kind of logical question like if they didn't give us a name or they didn't give us a dorm like yell at the user in some, way so, I'm gonna go ahead and do that so let me actually express this in Python kind of like we did last week with some error checking so, recall, that the. User's name can. Be gotten from an HTTP, parameter, from the request dot, args, get and, then. Ask for the name parameter, their dorm meanwhile, can come from request args, get dorm. And again this, request args, is something. We gave ourselves access. To up here when we said hey flask please give me access to the users request that virtual, envelope request. Args, refers to all of the HTTP parameters in the URL and, get, it's just a function or a method built, into that special, flask, feature that, allows us to get a specific parameter, like name or dorm or anything, else and recall, that in Python what's kind of nice is that you can say pretty English, like if not, door if, not name or not not. Dorm, let's, go ahead and reprimand, the user for, instance we could say. Failure. The, see or she did not actually cooperate, as we intended otherwise, if they did cooperate, I'm gonna go ahead and render. Template. Success. And we'll flesh this out in just a moment so I've got two scenarios handled, if they didn't cooperate or if they did render. Quote/unquote, failure or a full fledged HTML, template, so, now. That I've implemented slash, register, and I'm listening for a route of via. Post let's go ahead and reload the page for good measure type in my name not, gonna tell you my dorm but you're. Gonna notice as much okay. So now the, server has noticed, that I didn't actually cooperate, and provide both a name and a dorm and so it's returning to me just quote unquote failure. So that's good because now I know all right I did something wrong clearly let me go back let me go ahead and maybe do candidate, here and now let me go ahead and register but, but but but this I know in advance is gonna error why I, don't. Have a success dot HTML, okay so let's preemptively, address this let, me actually go in here to my templates directory I'm gonna go ahead and create a new file called, success. Dot, HTML. Let me go into the templates to save it there and you know what success can be pretty simple page and let me open my index page let, me copy that let me go into success let me paste this let me get rid of all of that body and just, say success. For instance all right so let, me now go ahead and go. Restart. Flask because I've made a new template let, me go ahead and reload the form just for good measure let me go ahead and give you my name this time and okay I live in Canada and register. And, what. Did I do wrong this time so. It turns out you can't. Do it this way obviously, so. When. You're actually submitting. Information to a form, via. Form via, get flask, very. Cleverly, puts, that information, in a different place because by definition as, I claimed very correctly earlier in request arcs, or all of the key value pairs that are in the URL that, are coming in from the users request but, when you submit by a post for, reasons I wish were now otherwise you, actually have to access those values, via, a different variable, so, instead of using request args, you have to use request dot form both here and here, to make clear and this is horribly, named for exactly the reasons, I think I'm trippin over here because, they actually, are both, coming in via form, via get or post but flask puts, get arguments, in orgs, and poets, post arguments, in form, thereby. Leading clearly, to potential confusion but if I go ahead now and load, this version of the site and I, keep, keep.

Hoping. I'm gonna go ahead now run. Flask, restart. This page, type. In David to. Give you my dorm and register. And successfully. Register, for frosh I am see how easy web programming is. So. Hopefully. Now we can at least focus, on the, structure, of what I've done and now begin to improve it because notice that I kind, of did not practice what I preached a moment ago what habit, did, I violate when, I whipped up success, HTML. How. Did I get to that point yeah yeah. I copied, and pasted which again usually in programming, not the right thing to do might get the job done superfast, but it's probably the wrong instinct, because it's gonna get harder and harder to maintain now why is that you've played with HTML, a couple of weeks ago and recall. From that problem said when you had to make a home page you, probably found yourselves, copying, and pasting across. Your two or three or four pages because. You wanted them to kind of look the same and therefore it made sense for them to have some commonalities, but in HTML alone there. Was no way to say use, the same layout for my whole site use the same color scheme the same fonts the same CSS but just change the body of the page for each individual. Page and so some of you very rightly on discourse and beyond like posted, questions asking, could you do this and you, can't really in HTML. Alone but, now that we have access to Python, an actual programming, language that can do things logically, now you can actually start to factor those things out too and notice, in this file success, HTML. As well as in. Index.html. What. Are some of the commonalities, suffice. It to say the form is only in one of them but. What else is obviously redundant, everywhere. The. Title, the. Head of the page more generally, the doctype at the very top the body tag alone and you could imagine there be even more details, like from your own home pages that, you wanted to be the same, multiple, pages, so let's actually take a look at a refactor. Is a ssin of this code the one I did write in advance in frosh I am and, you'll, see why it actually, makes sense to have not only multiple, files each, of which represents, one of your routes. Or your views but, also to have this file called layout HTML. In, flask, when, building a web application that, you know is going to follow a certain structural, pattern commonalities. Across all of your pages you, can actually do this so, in this file here, layout, dot HTML, is a. Whole bunch of hard-coded HTML, and it's pretty simple it's got my HTML tag head tag title tag body tag and a few other things but, that's the general structure of the page and notice, it has this funky, syntax in the middle in white, here, is what's, called a block this, is now flask specific. Just like flask supports, those two curly braces on the left and the right that says put a value here flask, also, supports this other notation, curly. Brace percent, and percent. Curly, brace that actually, allows you to put placeholders. For actual. Chunks of HTML, not just variables but actual, chunks of HTML, and so, this layout, you can think of as a mold or a template, literally, that, all of your other pages are going to be structured based on but they are going to vary in this, line and only this line and we're gonna put as much HTML, between the body tags as we want the open and the close tag this just indicates the flask this is the stuff that should be changing, so, if I now look at my. Index.html. Which recall earlier contained, my form. Index.html. Notice. That here's the form and I finished it earlier I went ahead and typed out all of the freshmen dorms not just the two of them and you'll see that the file starts, almost the same and then continues, with more stuff but. Notice what's missing from, index.html, this time no doctype, no, HTML. Tag no head tag no title tag no body tag all of the common stuff has been factored, out but, there's, some funky new syntax, that again is flask specific, this first line is the. Link between this file and the layout that first line says hey flask this, index.html file, extends. The definition, of layout on HTML, so says grab that template and plug myself in there what do you want to plug in the same syntax here when you actually put stuff between the.

Block Tag and the end block tag which is down below that's, when you say two flasks go ahead and take this stuff and plug, it into the placeholder. In the layout so. Meanwhile, the success, page also, now can be a little more sophisticated if, I go into success, it's not very complicated, and honestly, it doesn't even look like HTML. Anymore because we're using these more dynamic, features but, this just says hey flask use the same layout so the page is structured exactly, the same but, for the body go, ahead and plug in this value, instead so. Indeed when you go ahead and load, this success message you see this message here not just success i expound it here and said you are registered, well not really that's cuz there's no database yet but, that's, gonna generate a full-fledged HTML page and what about failure before I was just cheating and just saying return failure, quote unquote no HTML, at all the failure, page is going to be almost the same but. Now I can actually provide, some descriptive, text this. Body just as you must provide your name and dorm thereby, admonishing, the user for not having cooperated. Properly, so now your home pages, if you kind of extrapolate from this could, have the exact same layout aesthetics, and sort of menu bars and all of that fanciness, but, only the content, would have to change and you can get out of the business of just copying and pasting so there to your question earlier about dynamism. The, dynamism, doesn't have to just come from the user it can also come from the construction. Dynamically. Of a website based, on multiple, pages so at the end of the day the browser has no idea that Python exists, has nothing, to no, familiarity with flask all the browser still sees as an HTML page but what flask and intern Python are doing for us is constructing. That page dynamically. Following. The rules from two weeks ago on HTML and CSS and following last week's rules on how, Python works. Questions. Yeah. It's. Not, good, question the this new syntax, the double curly braces that we saw earlier and now the curly, brace percent signs this, is actually, yet another language called, Jinja, ji nja. Which. Is a templating. Language, which, and there's dozens of these things in the world people just come up with their own syntax and the, reason for the funky syntax is that the author of Jinja presumably. Could think of no other language, that uses like a curly brace and a percent sign and a, percent sign into curly brace and so therefore they decided you know what I'm gonna use this syntax because it will look distinct, from HTML, and CSS and Python. So that frameworks, like flasks don't confuse it with something, else. It's. Automatically, supported, so flask by, default, supports. Jinja it could have come up with its own templating. Syntax but whoever invented, flask decided, I don't need to reinvent this wheel someone else already made a templating, language that gives me this functionality, so I'm gonna combine our works into, one and I didn't call it a language a moment ago because frankly HTML, CSS Python.

JavaScript I mean we're already like running out of fingers here but Jinja, is indeed yet another language it's, just not a programming, language per, se though, it will have some control flow features that we'll see in a little bit it's just much more limited than Python, other questions. Good. Question could you combine the, success, and the fail your pages into. One short. Answer yes and let me not show it yet because it'll get a little more complicated but yes I could imagine, passing. A variable. In that's a boolean true or false into just one of these templates and maybe I call the new template result, dot HTML, I can, actually then have an if condition, in my template, that says if the result is true say this else, if the result is false say this other thing so you could do that yes generally. Though it's, probably cleaner to keep messaging, separates, if they functionally, do something else after all these files are pretty small anyway. Yeah, just. For question, what does the user see on if they were to take a well, open up the you know the debugging, console on Chrome, look at and see what do they see and, the tech is, the HTML that shows. Up really good question what does the user see we can answer this by just literally, opening Chrome and opening, the view page source or, the inspector, this, is what the browser sees so when Iced claimed earlier that the browser has no idea Python or flask or even involved, that is indeed true because, what the browser is receiving, at the end of the day is just this that dynamically, constructed, HTML, good, question yeah. Good. Question we'll see more of this in just a little bit the question is can you between, the. Curly, brace and percent signs put actual Python code you, can put stuff that looks like Python, code but not all of Python and so more on that in the bit. Only. Certain functions, templating. Languages long story short our sandbox so that they are not as expressive, as a real programming language otherwise you are vulnerable to potential. Hacks you. Want their functionality to be very limited because they're only about displaying data not about thinking or doing logic, generally. More, on that in a bit all. Right that was a lot all at once in the sake of 5 minute break here turnarounds music come back and we'll make this app better. All. Right we are back so to recap we're. Frosh I am off. We now have this structure which, is pretty much conventional. Any web application we make here on out is, going to follow this pattern of having an application, PI entry, point where all the interesting stuff starts, and layout. On HTML, file in your templates directory that lays out the whole site in any commonalities, and then, one or more other pages that actually represent, your individual, views, that correspond, to one or more of your actual routes, so now we're at the point of like a stable baseline, but have we dived in right to this I would. Perhaps not make as much sense as to why we, did this various factorization. So let's, now improve, this because of course if you look at success H tml it just claims you are registered, well not really because, in, application, PI did, we do anything, with the users information. No. We just checked did they give us information and if so we claim success else if they miss their name and/or their dorm we just claimed failure. So where what would might a data structure be in Python. Where we could store registrants, we don't have databases yet we don't have sequel, yet that's a ahead, yeah.

We Could use an array otherwise known as a list in Python so let me propose how we might do this let me actually open up frosh IMS one. For. Our second, iteration of this program, and in application, PI notice, this at the, very top of the file not only am i creating. My application. Using, the same line as before and I've commented things this time in advance using the hash symbol notice. That I claimed that on line six and seven here here is an empty list for, all of the students who have registered this way we can keep the information around and we only did this briefly last time but does anyone remember how you add, something. To a list in Python via. What function. Append. Yeah so if you have dot append at, the end of a lists name you can add something to it so where is that going to go well, here is my route for slash which, implies again get by default that's the default route that a human might get and they are gonna see index dot HTML which. Contains that form if I scroll down now, you'll, see that I have a register, route just, like before but I'm, doing, one additional, step which. Is the new line here to be clear. Yeah. 26. So, I could implement this in any number of ways but the key detail is that I reference, the list name students, but I could have called it anything dot. Append as someone proposed is how you add something to the end of the list and then I can add anything I want to keep it simple I'm just gonna add a string, and I'm, gonna keep it super simple and just say the string is so-and-so from such-and-such a dorm so David from Matthews Hall or Brian from, wherever and so, here we have placeholders. Using, F strings in Python so this has nothing to do with flask that has nothing to do with Jinja or anything we just talked about this, has to do everything with last week's syntax, in Python. Alone so, this appends, to that list this. Name from, this, dorm so let's, go ahead now and try, this version out if I go into my source 7 directory for, today's code into frosh IMS one and run flask run will, see a URL that I can now visit let me go ahead and open that for frosh IMS 1 notice, that I have that complete, drop down now let, me go ahead and say David. But, I'm not gonna tell you my dorm yet and try to register now, I see a more friendly, message not just failure, and that's because of my new, and improved temp, okay. I'll go ahead and be David and I'll be from Matthews here let me go ahead and register and voila now, we see, David, from Matthews has registered and it seems to be all of a sudden in the form of a new bulleted, list but where did that actually come from well I don't know let me try this again let me go back to slash which, is the route that gives me the form let, me go ahead and type in not David this time but say Brian and Brian which dorm are you in Pennypacker. So let me choose this from the menu instead and click register and now, we see Brian from Pennypacker, so somehow the application, is changing, State and notice the URL that we're at is called slash registrants. Okay, so that seems to be a third route this time that. Apparently is not interactive, per se it just spits out the list of registered students so let's just put the proverbial engineering, hat on if we, go about implementing, this slash registrants. Route logically. What must that code be doing in, super. Bowl pseudocode if you will. Like. A for loop iterating, over what. Yeah. Over. The list of students, which contains all of those registrants, and the template, meanwhile probably. Has like an li tag for, list item, and a UL tag for unordered list which gives me the bulleted list so let's take a look at that so how do we follow. These breadcrumbs well if I scroll up in application. Dot pi will, see a route called slash registrants. And you'll see that all it does apparently. Is it returns a template called registered, dot HTML, where registered HTML, is probably a template that's generating, that list but there's something different this time I'm, passing.

In An argument, and we saw this earlier when I wanted to pass a name equals, David or name equals Brian I just, grabbed that from, a variable this time I'm not doing request args, I'm not doing request form, because what is students. Where. Did this come from. That's. The list from higher-up recall that we have this global variable at the top of the program students. Which is initialized to an empty list but recall that we keep appending, to it in my, register, route so, I can go ahead and say you know what go ahead and pass into register HTML. A template, or rather a list called, students, whose value, is exactly. That and again it's stupid-looking that you have the word on the left and the right of the variable. Name you could do this differently you again you could say foo you could say X or Y or anything but, frankly it tends to make Samoans just pass in the same name as the variable. That you care about so that the template can see exactly, that so what's the next breadcrumb if I want to understand exactly what, is happening what file should I open up next perhaps. Probably. Registered HTML, so let's go in there it's in my templates, directory by definition and you'll see indeed a failure message which allows, me to error check index, which contains the form layout, which contains the overall structure and finally, registered. Dot HTML, and now, we can answer the question that you asked earlier about Python, code in the template, so this one looks more advanced, than before, but, notice it follows a pattern, registered. HTML, extends. That same layout so it borrows from that same mold so it looks the same the, body of this page though is just this snippet of HTML, give me an unordered list open, and closed and this, is what you can do now with Jinja, again it's almost identical to Python so you don't have to worry about thinking, about learning yet another language it's, just a subset, of Python essentially, so if I want to output in list. Of all, of the students, I use. My ginger syntax, here my template syntax with curly brace % and I say for student in students, just like in Python that induces, an iteration over, that list and then, what do I want to output well we can borrow our curly braces from our name example and just do, list, item plug, in the name of the student close, list item and then end for, so, this is the one stupid thing with the templates whereas in Python proper.

Recall, That you can just say for student in students, you have a colon, and then indentation. Handles everything the, problem with that in the world of HTML, is that browsers recall ignore, all whitespace. Like white space has no special significance but, in Python it does so the way people solve, this is you, literally, if a little weird lease a end for, one word no space and that's it an indentation, helps you read something like this so, what is the HTML I'm getting back I can actually look at this let me go ahead and view page source in, Chrome and you'll see it's not quite as pretty as might be ideal because there's a lot of white space which comes from those templates from my having pretty printed those as well but this is syntactically, correct, and I'm dynamically, outputting this part, inside, of this layout. Any, questions. Then on this. Good. Question let's kill flask with ctrl C let's, rerun the server and let. Me go back to my, registrants. Route and reload and sadly. Yes this is not the best way to register, students first sport because if the server ever goes offline loses, power you hit ctrl C you, obviously indeed lose everyone, and notice, - even though we've generally frowned upon using, global variables, which, this students, list indeed is why. Did I define it up here in line 7 and not, for instance in my, register. Route here, because indeed I'm appending to the list here but I very deliberately did not declare. The list there. Yeah. I'm. Using it elsewhere in my other routes the registrants route and also even more to the point if I declared, a list here it becomes by definition a local variable which means as soon as this function exits, now I've just thrown away those, students, who register immediately. Not, even after a ctrl C so this was a better approach to do it but it's not what I did way back in my day I actually did something that was a little fancier, so at the time I didn't really know at least in what 1997. Anything about databases, I don't think I even knew about CSV, files just yet or at least how to create them dynamically, so, I instead took this approach let me go into frosh IMS - dot. HTM. Stew and it has noticed the same templates, as before and indeed I pretty much copied and pasted for this second example but, in application, PI, notice, this fanciness, so. Here I have almost the same thing up top in terms of flask but. I'm also using this OS library, more on that in a bit but, what about line 2 it's. Subtle I rattled. This acronym off I think just once weeks ago, SMTP. Does, anyone know what that stands for. Yeah. Simple, Mail Transfer Protocol. Email, that is soap icon comes with built-in functionality via which you can send emails and this is exactly what I did when I first made this website didn't know anything about databases, I didn't know anything about saving, things to files just yet I was still learning but, I did real hmm I could use programming, to send an email to the proctor or the RA who was overseeing the sports program, so that they could just like save it in a folder and know who had registered it's not super user friendly but it at least got the job done because they were then able to track everything so, in this program notice. That I have my route. For my forum and I. Have this register, route but a few new lines of code and you would only know how to do this by reading the documentation, but in this case here notice what I'm doing in my register, route I'm first getting the user's name and their, email this time and their, dorm, then. I'm error checking if they didn't give me a name or their email or the dorm render, failure dot HTML, to apprise them as much then. Go ahead and do these lines of code and this is more of a mouthful, and you would only again, know this from the documentation, but it turns out if you read the documentation for this SMTP. Lib or library, you, can use lines of code like this too as follows, you, can tell the library what server to use for sending email and it turns out if you read emails documentation.

You Can use SMTP, Gmail. Comm to automatically, send emails not using the web UI but using code, 587. Is the TCP port, that they use so it's not 80 it's not 443, its 587. By convention, start. TLS if you read the documentation says turn on encryption so the email is encrypted between, you and Gmail, then, go ahead and log in with a certain username, and password I created an account in advance called Jay Harvard at cs50.net, and my password is in my IDs, environment, I stored it elsewhere so that it's not visible on screen otherwise, people could send emails as John, then, I go ahead and call literally, a function called, send mail and if you read the documentation this, one takes as argument, who, you want to send email to the, contents, of the email, that you want to send and, the. Message that you actually want to send here or rather this is the from address the, to address and the actual message that, you want to send after that, you just go ahead and render template, and assume success I could add more error checking like I should probably check if anything went wrong here but I'm keeping it simple but, these new lines that are highlighted actually. Send an email so, let's try this let me go into frosh IMS too and, let. Me go ahead and do flask run, let. Me go ahead and open up the page here. /and, notice I do indeed have a second field for text now so this will be David, and. This will be let's, see how about. Let's. Go ahead and just register not myself since it's not my email account but John Harvard who we claims email, is cs50 dotnet, J Harvard they're at and he, lives in say weld let's. Go ahead and click register. Alright. It's, taking a little longer this time but it was doing a little more work sending, an email so now let's try to go to Gmail. Comm. Open. This up in. My inbox you. Are registered, if I open this up notice, J. Harvard at cs50.net, has, sent me an email by a BCC to at least keep part of the information private and it just says in the subject in, the body of the message if I move the cursor you. Are registered. So I did a little more back in 1997. But I included, like the user's name and their email address, and their dorm and maybe their phone number or whatnot and the sports they were interested, in but the idea is exactly that you can send any information you want just, by now using code you could not do that with HTML, or with, CSS, alone.

Any. Questions then on this. Yeah. Okay. That. Was all in JavaScript so that illusion to if name, equals, and then you assigned it to a function I think you're referring to our JavaScript. Examples, now. Okay. So we'll actually come back to that in a little bit where we reintroduce, a bit of JavaScript, which actually gives us some more functionality, reminiscent. Of those examples other questions. Yeah. It's a really good question so via what email address did, I send that and to whom was it sent so again this, is the from address this, is the to address and this is now the message and just because I only have one email account open, I had John sent himself an email in this case theoretically. If I were running the freshman intramural sports program I could try to do, this and change. This from address, to be myself the, catch is that Gmail actually, has protections, in place so that if you've logged in as J Harvard with his password. Then, the email no matter what you specify, as the from address is actually going to be overridden to be from John Harvard however. This, does speak to the potential insecurities, of email if you don't use Gmail but you use a third-party service, that is not so rigorous, with its error checking it is incredibly. Easy to fake, emails, from one person, to another I mean look through your spam folder sometime, most, of those people who sent you those spams don't exist, like the email addresses and/or the names are fake, and yet they might appear to actually be from a sibling of your as a family, member or a friend even, though those humans did not send the emails and that's because some spammer, has written code like this in Python or some other language but has overridden, these fields, but, used a server that's not Gmail that doesn't enforce, these policies. Other. Questions. Fun. Fact also in 1995. I learned how to send ie or how to change the firm address on an email and, turns out at Harvard there's this entity called the ad board who doesn't like doing this so you don't do that there's. A sometimes. There's human defenses, in place for this not just technological thankfully. My. Friend whom, I faked an email from did not work, that okay all, right that. You have now great power don't use it for for, evil all, right so let's go ahead now and do, another example but that takes this a further, step, adding. Finally. Some persistence, of information, let's go ahead into frosh IMS three now and open, up application, pi so, recall, that we. Can, use. CSV, files comma separated value files to create the illusion of like spre

2019-02-02 16:30

Show Video

Comments:

This is the eighth video in the course. Check out the full playlist: https://www.youtube.com/playlist?list=PLWKjhJtqVAbmGw5fN5BQlwuug-8bDmabi Here is a forum to discuss CS50 with other people from freeCodeCamp: https://www.freecodecamp.org/forum/c/harvard-cs50

Thank you very much☺☺

If i find the guy who has disliked, i m gonna kill him

Despite studying C Sharp and Kotlin, Python remains my favourite language.

This man is a genius. He knows the art of teaching. No doubt! He is one of the best teacher in the world.

David J Malan looks like George Eads ( CSI Nick Stokes)

Thanks for the video

He is one the best teacher in the world

good tutorial, thanks.

I am doing research about this topic for a long time and still couldn't find enough but this video covers everything I need! Thank you!

Which topic he actually covered? I didn't watched as I am thinking it is about building a basic flask app. Am I wrong?

I'm kinda obsessed with coding, i barely sleep these days writing code.

Sergi that’s awesome bro but I’m looking into getting my CCNA cert so I’m studying for that but I’m looking into this so I will be taking your advice

+Fat Boy You just need structure to study yourself. For example the freecodecamp curriculum privides a good visualization of what a good structure is. Html first, then Css, then javascript, then frameworks, libraries, API's...I would find good resources so you can go deeper on each one. Get some web developer bootcamp Udemy courses for example which also provide a structured path. Just advice from someone who started this journey 3 years ago and now I work doing this : )

Hlomani Job I agree

+Hlomani Job coding

+Virasman Learning what exactly, coding or?

+Fat Boy that's the cheapest University of all time

And what exactly is the meaning of doing it? How can you learn it?

Hlomani Job I’m trying to get into it. Looked at a few schools but they are expensive. Trying the university of YouTube first

Wow, he is full of energy... Great teacher. Thank You David J Malan, Harvard and freeCodeCamp

To the staff @freeCodeCamp.org @cs50: At the 49:24 mark, the obfuscated part of the URL can be seen very briefly on the auto suggest list of the browser. You might want to edit that part out as well.

This playlist is a gem! Thanks a ton for making this available. Never had so much fun learning!!

good video

Nice Explanation...

This man has amazing energy!

Priceless, was stuck with learning Flask but now not anymore Thank you! Great teacher!

+Virasman udemy also have good/cheap courses

dude, where is the green screen?!

Wow! The Harvard lecture is surprisingly, great! Thanks for posting these Harvard people. :)

What a talented teacher he is!

OKAY. suppose i put the JavaScript in another file. how do i access Jinja variables from that javascript file like i would normally do using the double curly brackets. {{ *variable* }}. Pls help

Once you add the students list I get an internal error. I cannot figure out what it is.

Other news