[MUSIC PLAYING] DAVID J. MALAN: Hello. Let's take a walk through Problem Set 8 Mashup, which is going to challenge you to draw upon elements for Google Maps with elements from Google News and mash them together into a web applet that allows a user to search a map for news local to specific towns, cities, and zip codes. To do this, we're going to integrate some HTML, CSS, PHP, SQL, JavaScript, and a technique generally known as AJAX in order to create this immersive user experience. Let's first for Google Maps itself. This, of course, is perhaps a familiar interface. But it turns out that Google Maps also provides an API-- application programming interface-- via which you can take elements of Google Maps and integrate them into your own applications. Indeed, throughout this process, you're going to find a couple of URLs particularly helpful that are mentioned in the specification for Problem Set 8, specifically this Getting Started Guide or the Developer's Guide for Google Maps API Version 3 as well as the Google Maps JavaScript API v3 reference, which is a bit more arcane to read but actually has all of the lower level details about what functions or methods and objects and properties and events actually come with the API, very similar in spirit to [INAUDIBLE] pages. Now if we take a look at Google News, you'll perhaps see a familiar interface here. But it turns out you can also search Google News for specific geographies via an HTTP parameter called geo. In fact, if I zoom in up here, you'll see that I'm at news.google.com/news/section?geo=02138. And, indeed, if I zoom out, you'll see that I'm looking at a page with a whole bunch of views about Cambridge, Massachusetts. Meanwhile, if I actually change the URL not to be a zip code like this, but something a little messier like Cambridge, +Massachusetts, where the plus is the way you encode a space character in a URL and hit Enter, you'll see that I actually see almost the same news. Perhaps it's a little bit different because Cambridge actually has multiple zip codes. Now how would I know that and, in fact, how could I somehow tie cities and towns to zip codes in case I want to allow the user to look up either? Well, it turns out that there's a website out there called geonames.org which is an initiative to have a freely available database of all sorts of geographic information, not only for the US, but also for other countries as well. In fact, if I go to this URL here, which is also mentioned in the problem set specification, you'll see it three listing of a whole bunch of zip files any of which can be downloaded by you. In fact, for this problem set you're going to download us.zip. Now within this file, is a whole bunch of data in text format. The files is very similar to a CSV-- Comma Separated Values file-- but it actually uses tabs to demarcate fields. Now, meanwhile, if you look here at what I've highlighted, the fields in this file are going to be things like country codes, postal codes, place names, and then, in some form or other, states and counties, communities, and more. In fact, I've already downloaded this file in advance. Let me go ahead and open it here-- us.text-- and, indeed, you'll see if I scroll down to line 16,792 you'll see a few records for Cambridge, Massachusetts and its various zip codes. What you also see there is the county, some numbers that I don't really understand, but also all the way on the right, some GPS coordinates-- latitude and longitude. This is great because one of the features of Google Maps API is the ability to detect where you are geographically in terms of GPS coordinates. Now let's begin to figure out how to start tying these things together. We've given you a whole bunch of distribution code, as well as MySQL database. In fact, if I pull a phpMyAdmin having already imported, as you soon will, pset8.SQL, you'll see a MySQL table that looks like this, an ID field, country code, postal code, place name and more. The types of all of those columns I derived simply by reading the readme.text file here that specified whether a field is an integer, or varchar or the like. So we've created that table for you and given you the SQL commands to execute to create that table in your own database, but there's actually no data in it yet. Rather, you're going to have to download us.zip or any country's zip file from that URL there. And then you're going to have to write a command line script in PHP that's going to open up that text file, iterate over its lines, and then for each of those lines do an insert into that places table in your MySQL database. So at the end of this process, you'll have run that script ultimately just once in theory. In reality you'll probably run it a bunch of times while trying to fix various bugs. Ultimately, you're going to have a really big database with thousands and thousands of geographic rows. Then you're going to put that import script aside once it's working and your database is nice and correct, and then you're going to move on to actually implementing the mashup itself. The mashup is going to look a little something like this. At mashup.cs50.net, we have a staff solution that looks a little something like this. Indeed, if I click on this newspaper icon for Cambridge, Massachusetts, you'll see a spinning icon briefly and then an ordered list, a bulleted list of articles related to Cambridge, Massachusetts. If I click on Charlestown, Massachusetts, I'll see the same for that town. And If I click on Watertown, Massachusetts, there might not be any news of from Watertown, so you'll see something like slow news day. Now, meanwhile, at top left are some familiar Google Maps controls to let you zoom out, pan up, down, left, and right, but also a search box that we put there. So if I search for, frankly, the only other zip code I know, 90210, we'll actually see Beverly Hills, California. When clicked it leads me to California and a whole bunch of news about Beverly Hills. Now notice, too, what happened there. If I this time search for 02138 or even Cambridge comma Massachusetts or some variant thereof, you get a little autocomplete dropdown. Now this is using a plugin for a library called jQuery, and that plugin is called typeahead. We simply read through the documentation, downloaded the .js file integrated into the distribution code so that you ultimately can write the code that fills that dropdown menu with the auto selections or the auto suggestions. Now the distribution code, though, that you received doesn't do nearly as much. You get the Google Map embedded, and you get the controls the top left, and you get the search box. But if I type something like 02138, no places are found yet. So that's going to be one of our goals here. Moreover, if you take a step back and look at the map itself, there's no news whatsoever. Even if I click and drag, no markers actually appear for news because that challenge is left for you as well. Let's take a look then at the distribution code. Once you've downloaded pset8.zip and unzipped it into your vhost directory in the CS50 Appliance, you'll see these directories here inside. Bin-- which generally stands for binary for executable programs-- includes, as in pset7, some PHP files that other files include, then public, which is the files that need to be publicly accessible to a user with a browser. Let's take a look in the bin directory, and we'll see that there's a file there already called Import. If we open this with gedit, we'll see that, unfortunately, there's not much there. All that is there, though, is a shebang at top which specifies which interpreter-- in this case PHP-- should be used to actually execute this file. But then where it says TODO is where you're going to need to write some code that probably requires the config file that's in the includes directory as we've done before with PHP files. And then you're going to have to somehow open up us.text which you presumably have unzipped already. Then you're going to have to iterate over the lines in that file, perhaps using some of the functions suggested in the specification. Then insert each of those lines into MySQL database by using the query function, which we've again provided you with-- or at least a variant thereof in functions.php, which we'll see in just a moment. Now let's close import and go back to our directory and this time go into includes. And if I do ls there, you'll see three files quite like Problem Set 7. And let's take a quick look, for instance, at config.php. In there, is fewer lines than before, and it seems this file includes constants.php and functions.php. We're using a slightly different technique this time around to actually specify that these files are relative to the current directory __ DIR__ represents whatever directory this file, config.php, is itself in. So this is a more explicit way of specifying what other files you want to require. Now if I close this file and open up constants.php instead, you'll see a file very reminiscent to Problem Set 7's as well, albeit with a different database called pset8. Finally, in functions.php, we'll see just one function this time called query. This is almost the same except we handle errors this time around a little bit differently, but it's usage is the same as in problem set seven. Now let's go back into our pset8 directory, go into public, and in there if I do ls, you'll see this-- articles.php, index.html, search.php, and update.php-- all files. And then the css fonts, img, and js directory quite like pset7. Let's take a look at index.html, which is going to be really the entry point to the smashup. Now in index.html, you'll see a whole bunch of link elements in the head, specifically, for bootstrap for our own CSS followed by a whole bunch of script tags for things like the maps, API itself, a special marker with label utility that we mentioned in the specification is available to you, jQuery itself, bootstrap itself, and another library called underscore which we talk about in the spec. Underscore.js like jquery.js is a JavaScript library that has a whole bunch of functionality that a lot of people in the world wish existed in JavaScript itself. So all of these are actually quite popular. We've also mentioned typeahead which is the library that does that autocomplete dropdown and finally a link to our own JavaScript. Meanwhile, and perhaps thankfully, this mashup is driven by relatively little HTML down here at the bottom. Notice that we've specified a div in our body of class-container fluid. This, per bootstrap's documentation, just means that this div is going to fill the viewport or the browser's window fully. Meanwhile, below that we have a div that's opened and immediately closed with the unique ID of map canvas. This now is from Google Maps documentation for its API, whereby I simply need to have an empty div into which to inject, ultimately, an actual Google Maps. But more on that in just a bit. Finally, there's a form inside of here which implements the text box up top left in our interface for searching. Notice that we've used a bit of bootstrap here too-- things like form-inline and form-group. We've given the former unique ID of form. And then, ultimately, I actually have an input type, which is pretty familiar, whose ID is q. Just a convention. Q for query-- could have been called anything. And then the placeholder, meanwhile, is city, state, and postal code which you might recall seeing in our mashup demo earlier. Let's close this file. Now take a look at the PHP files that await and then the JavaScript files. In our PHP files, we've already implemented for you, for instance, updates. Update.php-- we won't spend a huge amount of time on here-- in a nutshell is the file that our JavaScript code is going to contact via AJAX that asynchronous technique that's built into JavaScript these days that's going to allow us to ask update.php for more information. Specifically, anytime the user drags the map or performs a search that jumps the user to another location, our JavaScript code, as we'll soon see, is going to call update.php and ask for 10 or so markers within the viewport based on the GPS coordinates of the top and bottom corners of that map. We can then repopulate the map now that the user has moved the screen in order to see 10 probably new markers for different towns. Meanwhile, this file is ultimately going to execute a SQL query against our database table called places which is going to return those 10 or fewer locations. Meanwhile, in articles.php, is another file we've written in its entirety. It is very similar in spirit to Problem Set 7's LOOKUP function, which contacted Yahoo Finance for you. This file contacts Google News for you, ultimately grabbing a machine-readable version-- in something called RSS format-- of the news for Cambridge or Beverly Hills or whatever town you've searched for based on that geoparameter. We parse that RSS, which is just a type of markup language called XML, and then we actually return it to your browser and to your JavaScript code, specifically, in a format called JSON, JavaScript Object Notation. Now you'll see in the specification-- we point you at how you can actually see some of the JSON coming back-- that this functionality ultimately lets you populate those popup menus so that when you click on a marker in the map you actually see a whole bunch of bullets, each of which links to an article. Now let's take a look at one last PHP file which, fortunately, doesn't have much going on-- just a pretty big TODO. Right now this file declares an array called places. And then ultimately prints that array in JSON format-- pretty-printing it just so that things are easier to debug. Unfortunately, in the middle there is this TODO, which calls for you to search the database for places matching a geo HTTP parameter. And, indeed, this is going to be one of your challenges-- to implement this functionality here so that when you contact this file with a URL like search. php?geo= something, your code will ultimately return a JSON array of all of the places in your database table that match that input. So if the user types in Cambridge, your file here search.php should ultimately return a JSON array for all of the matches for Cambridge, which might be in Massachusetts but could be even anywhere else. Lastly, let's take a look at two files that are static ultimately-- your CSS file and your JavaScript file. If I go into our CSS directory, there's a whole bunch of files there, but most of them are libraries. I'm going to take a look, specifically, at styles.css, which is our own global CSS that's going to stylize this whole mashup. I'll leave it to you to read through the comments herein, but, in a nutshell, this is the CSS that ensures that our mashup, by default out of the box, looks exactly the way we want it-- with the map filling the view port and with the search box up at the top left. We've also taken the liberty of stylizing that typeahead dropdown menu a little bit as well. The most important file perhaps for this problem set is this last one, scripts.js. Inside of your JS directory is even more files. All of them are library files except for this one, scripts.js. If we open this up, let's take our final tour through the functions that are built into this file for you and call attention to the TODOs that lie ahead. At the top of this file, are three global variables. One for a map, which is going to be a reference to our Google map. You can think of it sort of as a pointer. Meanwhile, we have another global variable called info, which appears to be storing the return value of a call to new google.maps.InfoWindow. JavaScript supports objects which are very similar in spirit to Struts. And what this line for our purposes is doing is creating a new info window in memory and then keeping around a reference thereto in a variable called Info. And in between those, meanwhile, is what appears to be an empty JavaScript array called markers. All of those newspaper icons, or you might choose another icon altogether, are going to be stored ultimately in this array so that we can very easily add to the map and remove them from the map. Now let's scroll down a little bit and whiz through the code that's going to be executed as soon as the DOM or document object model or the page itself is ready. Recall that this syntax here simply specifies that the following code should be executed only when the browser has finished loading everything else. We first declare a whole bunch of styles, which end up stylizing the map as per the spec. We then declare a whole bunch of options, which further customize the Google map that we're about to embed. We then use a bit of jQuery code, which is explained in a bit more detail in the spec, to grab that element, map-canvas that we so uniquely identified. And then this line here is what seems to magically give us a Google map inside of our own application, storing a reference thereto in that variable called map. Finally, down here we register what's called a listener. Think back-- way, way back-- to week zero in CS50 when we looked at Scratch and its support through a walk through for things called events and broadcasts. You might not have used it yourself, but it's a mechanism whereby a browser in this case can get our attention when it's ready to actually execute some code. In this case, it's going to listen to the map for an event called idle. This means that the browser has finished loading the Google map. At this point a function called configure should ultimately be executed. That function, configure, we'll see, is written by us. Now down here is a function that, unfortunately, is just a TODO add marker. Per the spec. you're going to need to write the code that actually adds a marker-- whether it looks like a newspaper, or a thumb tack, or something else-- to the Google map. Here now is that function called configure. I'll leave it to you to read through this in more detail, but realize that we add a bunch more Listeners so that we can execute code when the user clicks on and drags the map. We also have code in here that initializes that typeahead plugin so that the dropdown menu actually works. But let's focus on just a couple of places herein. Specifically, this to do here. I'll defer to the online documentation and the specification for how to fill in this TODO. But in a nutshell, this library typeahead allows you to pass in what's generally known as a template, which has some variable placeholders very similar in spirit to printf's %.*s. But in this case, the template per the spec allows you to specify what variables you want to inject from data that's come back from something like the PHP files that you've written that are emitting JSON output. Now down here realize that we are listening for typeahead selections when the user actually conducts a search and selects a value. This is how we're actually going to listen for that and execute some code as a result. Then we continue to configure the mashup just a little bit. And, ultimately, we call this function update. It updates the markers on the screen. More on that in just a moment. Meanwhile, there's a few small functions in here. One of which is hideInfo which simply closes the InfoWindow. Another function here, which ultimately won't be too long, remove markers. That's going to undo whatever your add marker function does. And then down here is search. And this one is interesting because we have written the JavaScript code that's going to talk to search.php on the server and get back some response. You, of course, will still need to implement search.php, but we've implemented the JavaScript code that's going to handle actually performing searches from that text box. In particular, notice that this function here, search, does call search.php by a method called get JSON, which we saw in lecture. And the syntax here is a little different from lecture in that we're using jQuery so-called promise interface. More on that in the spec. This simply means for our purposes now that there are two special functions we need to call with dot notation here immediately after calling get JSON. One is called done. One is called fail. You can think of these as the success handler and the failure handler just in case something goes wrong. Now let's look at the last couple of functions in this file. Down here is a function called showInfo, which shows info in one of those little info windows that pops up when the user clicks a marker. Down here further is that update function that we have implemented for you. It determines the bounds of the map. What are the GPS coordinates of its northeast and southwest corners here. We've prepared some HDP parameters here and then passed them ultimately to update.php, which we've also implemented for you. That ultimately gets back some JSON from the file called update.php and then removes any markers on the screen and then iterates over the data that's come back from update.php, which again is just a JSON array. And then it ultimately adds a marker for each of those places, handling failure or errors which might very well happen. Now just to give you a taste of how you might go about debugging this project, realize that I've opened in advance this tab here to this URL, pset8/articles.php?geo=02138. Now, again, articles about PHP we implemented for you so this isn't so much what you'll be using to debug, but rather the technique. Notice that I've searched for Cambridge's zip code here, and I've gotten back, indeed, a JSON array of JSON objects inside of which are two keys-- link and title. So this functionality works already for you. But this technique of manually going to a URL like this for something like search.php?geo=cambridge or 02138 or whatever the user has typed in should prove invaluable as you, yourself, try to figure out exactly whether or why search.php is working or not. Ultimately then, you have a few TODOs ahead of you. You're going to first implements that import script that reads in us.text into your database. You're then going to need to implement search.php so that it behaves exactly as specified. You're then going to want to focus on scripts.js and ultimately implements those couple of TODOs, including for configure and that template, add markers, remove markers, and then last, but not least, one personal touch. Once you have your mashup working quite like ours, the goal at hand is for you to add a personal touch to your mashup, whether it's aesthetic or functional. Take the mashup ever so slightly to the next level. So long as you push yourself beyond your familiarity with the spec itself and pick up one technique new, even if it's just something aesthetic like changing the layout of the map that you're using, the scope that we expect will be satisfied. That then is Problem Set 8 Mashup. Stay tuned for more in the specification and best of luck tackling this, your last CS50 problem set ever. [MUSIC PLAYING]