My name is Laila Viner, I'm the fundraising and development manager for the Wildlife Habitat Protection Trust. I was speaking to a lady from the Lottery in Leeds and she told me about O-Poll, the project, and she said that you were based in York, or one of the bases in York, and she knows what I do here. So she said, oh, would you like to get in touch with them? So I thought, okay, so I had to look up your website and got your contact number off the website and gave you a ring. And what sort of work do you do here, generally? Generally, we do conservation, habitat management, we do training with volunteers, we have volunteers in, and we also do training with probationers, and we have the forest schools in and we have schools in and lots of other groups. Cool, so then I came down, we had a walk round, didn't we, and we showed them the site. So what have we been doing, what sort of stuff have O-Poll been doing with you since then? We've got a lot of knowledge, but we haven't got the specialist knowledge that you guys have got. So you've helped us to, well, you've kind of built for us 15 self-led activity packs as it happens. And that's going to be great because it's for schools to come in, because the problem we had was schools bring kids in all the time, but teachers only have a limited knowledge of what they can do here. So these activity packs you've made, we've got pre-site visit stuff, stuff they can do all their hair and then post-site visit stuff. So that's really cool for them. Yeah, it's really nice isn't it, because the idea is they get a box and it's got all the equipment in and everything that they can use so they can do activities here. And the hope is, I think, that people will do one pack and then they'll be able to use others and things like that. And there's ideas in there as well about what they can do extra as well. So we've made 15 self-led education packs for the Wildlife Habitat Protection Trust. And the idea with these is that a teacher will be able to look at the website and think about what they want to cover with their class and look at the curriculum links on the pack and decide which pack they would like to use. There are 15 different themes in the packs. There's one for each season. There's one on trees. There's one on environmental art. There's one on senses. So there's a whole variety of things that go across the curriculum. The packs are mainly designed for the Wildlife Habitat Protection Trust and their sites, but we're already starting to get inquiries from other groups, groups like Friends of Parks or individual schools who are interested in using the packs in their own sites. So we're hoping that there'll be much wider applicability.


w list, something that combines the value of position zero from the first list with the thing that's at position zero in the second list. So it combines the three and the one to get four. The next time we get to position six, i is now bound to one and so we're gonna combine the two things that are at position one in the two lists. So you can sort of think of this as that we zipped the two lists together and then combined the elements at position zero, combine the elements at position one and so on. Now iterating through the indexes or positions can be done in Python but it's not really the Pythonic way of doing things. It obscures the structure of what's going on which is that we're matching the two lists together position by position. Instead, Python provides the zip function which makes that structure clearer. So here's doing the same thing using the zip function. The zip function takes two or more sequences and it makes a list of tuples. Each tuple gathers together the items from the corresponding position in the list. So you can see on line three that I've invoked the zip function, passing it L1 and L2. The zip function actually returns an iterator, that list-like object that we've seen before that map and filter also return and seen it with the dictionary method.keys. If we're just gonna iterate through the results that zip produces, we don't need to do anything but if we actually want to see it as a list, we have to pass it to the list function. So let's see this in code lens. This isn't actually gonna combine the values.  It's gonna produce a zip-together list. So we start with our two lists and then we make a list that zips the two together. It's still gonna have three elements but now each of those elements is a tuple that is stuck together the three and the one from position zero. It's stuck together the four and the two from position one and stuck together the five and the three from position two. Once we have this zip-together list, then we can do an additional operation to combine the three and the one to combine the four and the two. So let's see how that happens. So here I've created that zip-together list and then on line six and seven, I'm going through each of those tuples and for each of them I'm adding the two elements together and appending that result into my accumulator list, L3. Let's see how that one looks in code lens. We create our two lists, we zip them together. So now the first element is a tuple of three and one and we're now gonna iterate through those tuples and we're doing that clever little unpacking thing so that on our first iteration, X1 is gonna be bound to three and X2 is bound to one. So we've unpacked this tuple into two different variables, X1 and X2. X1 gets the value three and X2 gets the value one. Having done that, we're gonna add the three and the one together to make four and append that into L3. You can see the four is there and we'll go on the next time X1 and X2 have the values four and two and we've appended the value six into L3 and now when X1 and X2 have five and three we end up appending eight. So we get to the end and we print out four, six, eight. Now having developed this code, we could combine it and simplify some things. So I'm gonna show you how we can do it with a list comprehension that puts it all together. Instead of doing that manual accumulation where we start L3 having an empty list and each time we append to it, I'm gonna use a list comprehension. This was our L4, our zipped list and we are iterating through it each time we're unpacking the tuple into the two variables X1 and X2 and our transformer expression takes those variables X1 and X2, adds them together and the sum is the thing that we accumulate into our final list. If I run this, I'll get the same result. This is the pythonic way of doing things. We zip the two lists together then we use a list comprehension to iterate through that zipped list with each tuple, we transform the tuple by adding the two elements together and we accumulate that set of sums into our final list. So that's the zip function. It takes multiple lists all of the same length and creates a new list of tuples. Each tuple groups together one element from each of the original lists. We'll see you next time. Welcome back. We're gonna write a program today using zip that you might use as part of a program that plays the game hangman. Just to make it clear what we're talking about, I'm gonna play part of a hangman game with Andre, my videographer.  Yes, I am. All right, well, okay, I've got a gallows here. It's just set up all waiting to hang Andre and I've thought of a word but I'm gonna leave it blanked for now. So the blank word has six letters in it and I'm also gonna keep track of whatever guesses he makes. He's gonna make a guess. If his guess is in the word, I will unblank from the appropriate spot. If not, then one of his body parts is gonna get added to our gallows and hopefully he will guess the word before he runs out of health.  Yes, I am. Okay, give me a letter. Let's go with A. Going with A. Well, that's a reasonable guess. It's in a lot of words in English, however, it is not in my word. So we have a guess of A and we've added a body part to the gallows. Give it another shot. I'm thinking E. It's a good idea to stick with vowels to start. Yeah, another good idea, but it's getting dangerous for you here. Try again. That's not looking good for me. Let's go with S. S is a nice, solid consonant. Oh boy. I have a feeling you're just avoiding all of the common letters with this one. No, no. It's just a regular word. I'm thinking U. Let's go with a U. Oh boy. Man, I am not doing so hot. I'd like to take a guess from our audience out there, but we're not live, so. All right, I'll take a B. A B, oh boy. So. I will go P. Oh, he's got one. I know what you did there. I see what you did. I'll go with a T. A T. Let's go H. And H. I think Andre was well on his way to guessing that word. Let's step back and think about how we might write a program to do what Andre did, that is make guesses. Imagine that we were gonna use a kind of brute force approach. We have a dictionary that has every possible word in English. And the computer program at every stage of the game is gonna go through every single word and figure out is this word still possible? And given that set of words that is still possible, it will figure out which letter should I guess next? We're not gonna write that whole program together. I'm just gonna write a component of it, a function called possible, that will take three inputs and will determine if it's gonna return true or false, whether the word that we pass in, down to the parameter word, whether that word is still possible, given what things have been unblanked so far and what guesses have already been made. So rather than our example that I was playing with, Andre, imagine that our blanked word is a little bit longer. The hidden word has actually 10 letters in it. And some letters have already been unblanked. So we have blank, O-N, blank, blank, R, blank, blank, L-L. We have a couple of different possibilities for what guesses have already been made. In one version, O-T-N, Q-U-R and I'll have been guessed and in the other letter W has also been guessed. So is Wonderwall still possible, given what has already been guessed? So basically we can rule out the word Wonderwall if it has a letter that's already been guessed but hasn't been revealed, like W. Since W has been guessed but it hasn't been revealed here, Wonderwall is not possible. This ought to return false. Another possibility not shown here is where a letter at some position has been revealed but that letter doesn't match the letter that's in Wonderwall. That would be another reason to rule out Wonderwall. So let's actually run this code in code lens. I think it's gonna be clear what it's doing. So we define this function. Now we're gonna invoke the function the first time, checking whether Wonderwall is still possible and we have the values for blanked and for guesses made. Our first check on lines two and three is just to make sure that the word that we're interested in has the same number of letters as blanked because if it doesn't, it definitely isn't possible and we should just return false and give up but in this case it does have the right number of letters. The next thing we're gonna do is index through the positions. We're gonna check at position zero does W match blank. W match blank. We're gonna check whether O matches O at position one and so on. So remember that line of word just tells us how many letters are in word and range of that produces a sequence. So I is gonna get the value zero and then one and then two and so on. When I is zero, the character from blanked is underscore and WC, the character from the word is W and now we do our first check. Is the blanked character compatible with the word character? If the blank character is an underscore and W, the word character is one of the letters that's been guessed, then we have an incompatibility and we would return false. That's not what's gonna happen here because WC is not in guesses. It hasn't been guessed yet. So we also check if the blanked character is not the underscore. Well that's not the case here because the blank character is the underscore. We passed the test for I equals zero. Now we're gonna go on to the second position. Now I is one and we're gonna have both BC and WC are both the letter O. Well that's compatible so we're not gonna fail there and we keep going. Now they're both N, we don't fail there. We actually get all the way through this. We're gonna get all the way through all the positions. None of them has an incompatibility and now we've finished the iteration. We've gone through all of the positions since we didn't find an incompatibility anywhere we're okay and we can now return true. So the first invocation gives us the value true. But our second invocation is gonna come out differently. Now we have one more guess that's been made and when we get to position zero with a blanked character of underscore, the word character is W and W is one of the guesses that's been made. We return false and as soon as you hit a return false it's an immediate return from the function so that breaks out of the whole iteration. We don't go on to anything else we just return false and we're done. Now I wanna show you how we can simplify and clarify the code by introducing a named helper function and by switching to using zip rather than indexing through the positions in word. So I'm first going to define a little helper function called compatible and it's gonna take a character from the blanked word and a character from the word that we're trying to check on and the guesses that have been made. And it's gonna return either true or false and it's basically gonna take this code. So that's one simplification that I'm gonna make that makes it just a little easier to read the code. Now you know those four lines of code we're really trying to just check whether BC the character from the blanked and the character from the word were compatible. If they're not compatible we're returning false. Let's just test this to make sure that I haven't made any syntax errors or anything and it looks like I did do something wrong. Yes I did which is that if I didn't find incompatibility I needed to return true. So if the pair of characters was not incompatible for one of our two reasons I need to say that they were compatible and now everything is working as it did before. The second simplification that I'm going to make is that I'm going to use the zip function rather than going through the positions in word and blanked in parallel. Because I was really trying to go through them in parallel that should suggest to you that zip is the right thing. So I'm going to say for BCWC in zip of blanked with word and that is equivalent to the code that I had above but once you get used to it I think you'll find is much easier to read. We are first zipping together blanked in word at each position we're going to have a tuple and then I'm iterating through those tuples unpacking each tuple into the character from blanked and the character from the word. And this should also work let's check it and sure enough we get the same answer. So that's a little example showing you how you can use zip to make it more clear what your code is doing. You can implement the blank function without it as I did at the beginning but the switch to zip along with making a name function for this compatible character code makes it easier to understand what the code is doing. See you next time. Welcome back. That was the zip function. You can use it whenever you want to do pairwise operations. For example, if you wanted to take three lists of words and generate a single list that had the longest of the three words in each position you could first zip all three lists together to generate a list of tuples and you could write a list comprehension to do a mapping operation transforming each tuple of three words into a single string, the longest of the three words. I'll close with a little zipper joke. One day I was picking up my son from preschool. It was winter. Hey, this is Ann Arbor and he was having trouble zipping up his coat. I explained it as I was showing him. The secret is you have to get the left part of the zipper to fit in the other side before you try to zip it up. He looked at me quizzically and said, why does it have to be a secret? I'll see you next time. Hey everybody, welcome back. REST API is this lesson. API, it's an acronym that stands for Application Programming Interface. It's an interface that lets one computer program interact with another computer program and REST. Not REST is in take a deep breath and relax. It's another acronym. It stands for Representational State Transfer, which actually isn't all that helpful either. Purists will be happy to explain to you at length the more abstract meaning for a representational state transfer. But in everyday parlance, a REST API just means a website that produces data intended for another computer program to consume rather than something intended to be displayed to people in a browser. A REST API will respond to requests in a particular format. Some things are common across many APIs about the format, but some things are specific to the particular API. This week, you'll learn how to write programs in Python that interact with REST APIs. You'll learn to read the documentation in order to figure out the specific format that the API is expecting. And you'll learn how to use the Python request module to make the API of calls. Finally, you'll learn about caching as a way to reduce the total number of calls that you have to make to the APIs. Before we dive into details of requests to APIs, though, we're going to take a little detour to give you some background on what goes on behind the scenes when two computers talk to each other over the internet. It'll give you a mental model of what's going on so that if things don't work perfectly the first time and they never do, you'll know how to think about what might be going wrong and have a good path toward fixing it. At the end of this lesson, you'll be able to parse a URL into its component parts, the protocol HTTP or HTTPS, the host, typically a domain name, and the path. And you'll also be able to use the Python request module to fetch the contents of a URL. Let's get started. I'll see you at the end. Welcome back. Before I show you how to write a program that will fetch data from a REST API from another website on the internet, let's take a little time to figure out how the internet really works and what URLs are and all that kind of stuff. So you're, I'm sure I'll use to using a web browser. Like we see here, this is a web browser where we're fetching a page from the umich.edu website. You see in the URL bar that URL HTTP umich.edu slash about. You can think about parsing that as that there's a certain part before the colon. And we'll call that, we'll call that the protocol. In this case, HTTP is our protocol. Then we have a colon slash slash. That's just a separator. And then all the stuff until the next forward slash is called the domain or the server. Then we have another slash as a separator. And then we can have some other stuff which we'll call the path or the arguments. So the server says where to fetch something from and the argument says what to fetch from that remote server. The protocol says how to communicate with that remote server. Next, let's talk about those servers. Those servers are referred to by name. Usually you get a name like umich.edu or si.umich.edu or www.google.com. Those are called domain names and they say what remote computer you're trying to talk to. Every computer that's attached to the internet has a unique identifier and address. It's called the IP address. IP stands for internet protocol. And no two computers that are connected to the internet have the same IP address at the same time. When the computer disconnects, you might get another computer getting to reuse that IP address. When we have a domain name like www.si.umich.edu, that's sort of a more permanent name, but the actual server that is responding to that name may change over time. And each server will have an IP address. So the internet has something called the DNS, the domain name system, that is set up to resolve names like www.si.umich.edu and turn them into these unique identifiers, the IP addresses. An IP address will look something like <IP_ADDRESS>. The dots are just there to help us divide it up and think about it as four chunks. In each of those chunks we have to have a number between zero and 255. Do you ever see an IP address that has a number bigger than 255? That's not really an IP address. The numbers go from zero to 255. It turns out that you can represent that with eight bits, eight zeros and ones. We're not going to go into the details of binary arithmetic here, but we get these four sets of eight bits and so we have a total of 32 bits. Sometimes these are called 32-bit addresses and we have the decimal representations with the dots <IP_ADDRESS> just to make it a little easier for people to speak them and write them. So how is it that www.si.umich.edu gets converted into that number and how does every computer on the internet know to find that number whenever they're trying to communicate with www.si.umich.edu? Turns out there's a distributed lookup system, the domain name system, and you can go to various sites that will let you do this lookup. Your computer has a way of doing that lookup. It has a server that it talks to in the background, but here's one that's public. So I've gone to look. I've already set this up here and you can see I've looked up www.si.umich.edu and I actually got back two possible IP addresses. The main IP address is the first one, so it's that <IP_ADDRESS>. That's the basics of URLs, domain names, and IP addresses. We'll see you next time. Welcome back. Let's talk about how data gets from one computer to another on the internet. When your browser talks to some remote server, say www.si.umich.edu, it establishes a connection and then it sends some data, pieces of text or other formatted data, and each of those pieces of content gets chopped up into a bunch of packets.  Routers are just computers whose sole job is to receive these data packets and pass them on. And each packet will go along, goes from one router to the next. Each of those routers has a big lookup table that says if this packet that I've received is destined for some particular address, what's the next hop? What's the next router I should send it to? And magically, all of these routers have managed to coordinate their routing tables so that when a packet gets sent here, it eventually makes its way to the destination. It's a rather remarkable system that there are trillions of these packets getting routed around and they all mostly managed to get to their destination. Occasionally, things go wrong and packets don't make it. Here's the first few lines of a trace route that I did. This is something that gives some diagnostics about if I'm trying to send data packets from my computer to si.umich.edu, what happens to them? And the first line is telling me where does that packet go first? Well, first it goes to a computer that has the address <IP_ADDRESS> and it took 71 milliseconds to get it there. In fact, when I run this trace route program, it does this three times and so one time it took 71 milliseconds, the next time it took somewhat less, the third time somewhere in the middle at 58.4 milliseconds. The second line is saying where does a data packet go if it's eventually trying to get to si.umich.edu? Where does it go next? Well, it went from a computer at address <IP_ADDRESS> to a computer at <IP_ADDRESS>. And we can see this is called two hops. The first hop went to 100.68, the second hop to 172.19. The third hop was another router at <IP_ADDRESS>. And so on, I haven't shown you all the way, but after eight or 10 hops, the packets eventually get to si.umich.edu. And typically to go two hops, it takes a little longer than to go one hop. So that gives you a little sense of what's going on behind the scenes. We're not gonna have to deal with all of this technical detail. I just wanted to give you a sense of what's happening when one computer is talking to another. So that's the basics of internet routing, how one computer can send data to another computer by way of intermediate routers. We'll see you next time. Welcome back. Let's talk about what happens behind the scenes when your browser fetches data from a remote server. The particular way that we're gonna be most interested in having one computer talk to another is using the HTTP protocol. So that's when we have a URL that begins HTTP colon slash slash, something like www.si.umich.edu and maybe something after the slash. The first thing that's gonna happen is my computer is gonna take this domain name www.si.umich.edu, convert it into an IP address as I illustrated a minute ago. Then my computer makes a connection to the remote computer. If I were using HTTPS, that's the secure version, then the first thing that my computer would do was send some information back and forth to the si.umich.edu server that would establish encryption keys so that all of the rest of the communication would be encrypted and nobody who intercepted that communication would be able to figure out what we were saying to each other. After that setup has happened, now my browser will start to send messages and it'll actually send text. It'll send the word get and then it'll send whatever arguments were after the slash. It'll say what path we're looking for. It'll also send some headers saying things like hey, I'm a Chrome browser or I'm an internet explorer browser. The current time is a certain time.  We will then receive back from that server some response headers. Those response headers will say things like, I'm sending you HTML and the current timestamp is such and such and there are a few others. I'm gonna show you this in a minute. And then most importantly, si.umich.edu is gonna send me some HTML. And that HTML my browser is gonna take and turn into what we are used to seeing in a browser, a web page. So the browser renders that HTML. Let's take a look and see what this looks like for the umich.edu website. Here I have a web page open in my browser. The URL is https colon slash slash dub dub dub dot si.umich.edu. And you can see that it's all pretty on the screen. But what's really happening in the background? What's happening in the background, I'm using the Chrome Debugger tool and I've got it set up to show us that when I made that request, my browser opened a connection and the first thing it did was that it made a get request. And this is the full URL that it asked for. We can see all of the request headers. So we asked for a get. We sent the path was backslash was just slash because I didn't have anything after the slash. If I had asked for a particular page, then we would see something more in the path down here. The scheme or protocol was https.  The user agent was compatible with all of these things. It's actually the Chrome browser that I'm using. So these are all things that my browser sent to the server and the server responded by sending back a whole bunch of response headers. There's the timestamp of when it sent it back. There's various things here including, you can see a little information that the website is powered by PHP as its back end. And the content type is text slash html in the UTF-8 encoding and so on. So these are all things that my browser uses. And then the most important stuff that we get back was actually all of this html. And all of this stuff got sent back and the browser managed to parse all of this. This is just text. This text is not what's normally shown on the webpage. What's shown on the webpage is this pretty thing. And that's the browser rendering all of that html. If you don't know how to use the Chrome debugger, it can be a little confusing, but if you just want to see what the html is for any page, you can do a right click and U-page source and see all of that stuff that got sent back from the server. So to summarize, when your browser fetches data from a remote web server, it makes a connection. It sends a few headers and asks for the path, the arguments that it would like to receive.  See you next time. Welcome back. Let's talk about a particular URL structure that's very common. We're gonna talk about what happens after the slash. And a very common format is to have some path name, in this case, just slash list. And then we have the character question mark. And after the question mark, we get query parameters. So as before, we have a protocol, HTTPS, we have a host, in this case, events.umich.edu, and then we have the arguments, everything after the slash. Now, any web server gets to decide what format of arguments it's willing to accept, but this is a very common one where you'll have some path name and then question mark and then these query parameters. And these query parameters are very often formatted in these key equals value, key equals value. So we have two of these keys. One key is called filter and the other one is called range. The value of filter is tags, colon, arch, comma, and the range has the value 2018-10-01, first of October, 2018. The server is going to interpret this request as a request to search on the server to find out those events that are happening on 2018, or beginning 2018, October 1st, and that somehow are tagged with the word art. So if we visit that URL, the web server is interpreting the request as a query and it is returning information just about artistic activities that are happening around campus starting on October 1st. And you can see some of the interesting artistic things that are happening, especially in the university hospitals, but also elsewhere around campus. So this URL structure, where we have as arguments a path and then a question mark and key equals value pairs, this is a very common URL pattern and one that we'll be using in our coming lessons to write programs that fetch data from the internet. We'll see you next time. Welcome back. This lesson takes us deep into using REST APIs. First, we'll see how to use the request module to generate long URLs with query parameters and automatically substitute for text characters that aren't permitted in URLs. Next, I'll show you what to look for in the documentation for REST API. Third, I'll give you some hints for debugging requests when they don't work right the first time and we'll conclude by introducing the caching pattern. It's especially useful when using the request module so that you don't run into rate limits or problems of servers being inaccessible from the Roonstone textbook. At the end of this lesson, you should be able to read the documentation for REST API, extract the key information you need to use the request module to interact with it, debug your invocations of request.get and understand how our request with caching module works. Bye for now, I'll see you at the end. Welcome back. Remember this URL that we used before to find out what words rhyme with funny? And it's got the base part and then a question mark and then key equals value. Well, how did we know what to put into that base part? And how did we know to use rl underscore rh y in order to ask for things that rhyme? The answer is you use the documentation for the API. So let's take a look at the documentation of that API and we'll see they have lots of things in here. So in this documentation, they tell us that the main URL is going to be api.datamuse.com and then they tell us some things that might go after that. You might have slash words, question mark something or we'll see a little later on that there's some other things. There's one other endpoint besides words. So we'll describe slash words as being one endpoint and then the things after the question mark as being query parameters. So you can ask for ml and give a value, ring in the ears. So in their documentation, they tell you if you want to find out words with a meaning that's similar to ringing in the ears, you would give the query over on the right hand side. And we can scroll down and see some other things that you can do, lots of opportunities, lots of different things you can do. And here's that rally that I found. That's for words that rhyme with forgetful. Now they've started by giving us a bunch of examples but then down below, they'll give you even more detail. So they're saying you can access most things at datamuse.com slash words. So that's going to end up being our base URL. And then we have to figure out what are we going to put into that params dictionary. And we can use the examples above or we can try to look at some of the things below that are giving more detailed information. So we can have the key, the ml, we could have a key, sl for sounds like or there's a whole set of r-e-l underscore things. There's r-e-l underscore j-j-a or r-e-l underscore t-r-g or r-e-l underscore r-h-y for rhymes with. So that's how I figured out what some of the possible keys could be in my params dictionary. And then for the value, I really got it from my examples where I said, oh, well the value is just the word that I'm trying to pass as an input. I'm trying to get things that rhyme with forgetful or things that rhyme with funny. So that's telling me what kind of queries I can give to this REST API. And at the bottom, they'll tell me a little bit more about interpreting the results. So I've passed over the other endpoint slash sug and I've found something about what the responses will look like. And it's gonna be a list. That's what the square brackets tell me. And they tell me it's always gonna be in the JSON format, which you've been seeing already. And it's a list of dictionaries. Each dictionary is telling us information about one of the words that is related to our query. If our query was for words that rhyme with funny, then we would get each word that is a good rhyme for funny would have one dictionary in this list. So this is a relatively simple API and the documentation is pretty clear. You can figure out pretty well how to use it. The other thing I wanna show you with this API is just a nice practice.  You might make a lot of calls to get rhymes. And so I've defined a little function here that I can call multiple times. So I can call get rhymes on a word and I'll get back a list of some other words. So with funny, I'm getting back three things and I can get rhymes on something else. I wanna get rhymes with dash, I get cash flash and crash. Now how did I implement this get rhymes? Well, get rhymes is gonna take as an input a word like funny or dash. So that's gonna be bound to my word parameter and it's going to return a list of three rhyming words but you saw that what we actually get back is not a list of words, it's a list of dictionaries with information, each dictionary has information about one rhyming word. So the base URL is always the same and I'm gonna create a blank parameters dictionary and then I'm gonna fill in relry should equal word and max should be three. So we're asking it to only give us three results back and then I call request.get passing in that params dictionary. I get a response object. I turn that into a Python object by calling the JSON method on it and now I'm gonna use the list comprehension which you learned about recently. We're iterating through each of the list of dictionaries and for each of those dictionaries we're just extracting the word. So that produces a list like this and then I'm just returning it. I just noticed that on line 13 I have another return statement where it's returning something different but of course once we execute the return on line 12 we won't ever do line 13. That's left over from a previous version I was trying to do of this where instead of extracting just the words I was returning the whole dictionaries. In fact, it might be instructive to look at that. Let's comment at line 12 and see what happens if we return the dictionaries rather than extracting just the words from those dictionaries. So now we get a list of the three dictionaries instead of just getting money, honey and sunny we're getting this whole dictionary instead of just the word money. So this is the kind of thing that's pretty helpful if you know that you're gonna do the same thing make a bunch of requests to the same API just passing a little different parameter each time you might wanna make a little function out of it like I did here on lines four through 13. That's an introduction to reading the documentation for a REST API and also to making a function to repeatedly make similar kinds of requests to a single API. We'll see you next time. Welcome back. I'm gonna introduce you to a programming pattern called caching. We have some expensive or maybe unreliable operation. We'll have a little function, takes an input produces an output but it might take a long time to run it. Each time we run it, we're gonna take the results and we'll stick them into a cache and that cache is gonna save our previous results. You can think of it sort of like a squirrel's cache of nuts. It's spelled C-A-C-A-G pronounced cache and it just associates some inputs with outputs. I'll call them keys and results. And now the next time I was gonna ask this expensive operation to do the very same operation that's been done before, I would first check and see, hey, is this result already available to me in the cache? If it is, just send back the same result I would have gotten if I'd run that expensive operation but don't bother, just take the result from the cache. Now in our case, the expensive operation is request.get. It's expensive because it takes a little bit of time to go out over the internet to make a connection to another server. It's also a little unreliable. Sometimes you don't have a good internet connection, sometimes the server that you're connecting to doesn't respond in the way that it did yesterday. In our textbook, there are some sites that have restrictions on cross-site scripting and some days it works to connect to them, some days it doesn't. There's another problem that sometimes when we call request.get, we're doing some debugging and we run our code a bunch of times and the site that we're talking to has a rate limit. It says you can only make 15 calls every 15 minutes and you've run this more than 15 times in the last 15 minutes. So these are all reasons why it's gonna be a good idea to save our results when we run a request.get, put them in a cache and get the results from the cache the next time rather than calling request.get again. So we've implemented this caching pattern in a module. It's available only in the textbook and it's called, as you might guess, requests with caching. So in the code window here, I've got an import statement, import requests with caching and then request with caching is available to us and we're going to call the method get. This get method and request with caching is going to return exactly the same result, a response object just like if I were to call request.get. But the way it works is that it's going to first look in the cache and see if it can find the result there. If so, it'll give us the results from the cache. If it can't find it in the cache, it calls the real request.get and it returns that but it also saves the result in the cache so that the next time we'll get the result from the cache. There's one little twist is that I've actually got in this request.caching module we've implemented two caches. There's stuff that we've provided as part of the textbook and that goes into a permanent cache file. And then there's a temporary cache. You can sort of think of us having two caches, the permanent cache, and then there's a temporary cache. If you can think of it as a second little database. And that's stuff that's saved between code runs while you're on the current page but it disappears when you reload the page. So when you call requests with caching.get it checks in both of the caches. If it's found in either place it returns that. If it doesn't find it in either place then it does call request.get and it saves the result in this temporary page specific cache. So let's see what happens when we run this code. So we have a cache file, a permanent cache file called datamusecache.txt. And our first call to request with caching.get asks for the datamuse API and it asks for words that rhyme with happy. And then we can see the results. The request with caching.get tells us whether it found the result in the caches or whether it didn't. In this case it didn't find it in the cache and so it says it's adding it to the cache. Then on line four I've printed the first 100 characters and you can see the things that are rhyming are snappy and nappy and so on. On line six I'm making exactly the same request. I'm asking for the same word for words that rhyme with happy again and this time we're told that it found it in the page specific cache because it saved it from the first time that we made the call. The last call that we make we're asking for a different word. We're asking for words that rhyme with funny and we have a cached result in the permanent cache file for words that rhyme with funny so it found that in the permanent cache. Now if I were to run this whole thing again now it's gonna run where it already has the page specific cache and by the way you can see the results of that page specific cache. It's telling us it's stored in this data file called thispagecache.txt and it's the things that rhyme with happy like snappy and nappy and scrappy. If I run this again instead of showing new here it's gonna tell us that it found it in the cache so let's do that. Takes a little while to run some inefficiencies but we're gonna see that new adding to cache is gonna change because it's gonna find it in the cache. So now it says it found it in the page specific cache. If I were to reload this whole page which I'll do now I'm gonna clear my markings and I'm gonna reload the page. Now I've reloaded the page and that got rid of the page specific cache when I run this again the first time it's gonna have to do a call to request.get and add it to the cache. That's the request with caching module that we've provided. It's really easy to use just import request with caching and then you call requestwithcaching.get the same way as you would call request.get and it just makes it so that when you make the same request multiple times the additional times that you make the same request you'll get data from the cache. See you next time. Welcome back. Let's take a look at the code for the request with caching module. It's not very complicated and it's pretty instructive plus it's good practice to read slightly longer code chunks and try to make sense of them. Let's start here with the definition of the get function. It takes the same parameters as request.get a base URL and the optional parameters dictionary but it also has a few extra optional parameters like private keys to ignore. We'll come back to those. In the previous video I described conceptually how a cache works. Now we've got the data store where we're gonna store the results of our previous invocations of request.get but how are we actually gonna implement that in Python? The answer is we're gonna do it as a dictionary where each key will represent one invocation of request.get. The key has to somehow encode what the base URL and what the parameters were of that invocation of request.get and then the results will be some text that was what we got back from running request.get. So in our code here we're going to compute a cache key. We're gonna make this value k by calling a function, a little helper function that I'll show you in a minute called make cache key. And it's gonna take the base URL and the params and turn it into a string. We'll take a look at that make cache key function in a minute. But just think of it for now is that it's producing some string that we'll use as a key in the cache dictionary. Now the heart of this get function is this if, l, if, else. So we're gonna check whether this cache key is in either of our two caches, the page specific cache or the permanent cache. So if it finds it in the temporary cache, let's say it's here, then we're going to take these results and return them. So if we found them in temp cache that is the cache key that we're looking for is in the temp cache, then we go get the value associated with that cache key and that's what we're gonna return. And you may recall that we're trying to produce the same kind of object that request.get produces and that was a response object that has not only the text but also the URL. Now, if we actually called request.get, this would be the URL that we fetched from the remote server. In this case, it's gonna be the URL that we would have fetched if we had actually gone to the remote server, but instead we'll produce that URL that we would have used if we had to go out to the remote server.  If it didn't find it in the temporary cache, it'll do the same thing. It'll check in the permanent cache. If it was in the permanent cache, return the text and the URL. If it didn't find it in either of the two caches, then we will actually call request.get, passing the base URL in the params. We will add those, whatever the result was, gets added into the cache. And again, this is another helper function that we'll look at in a minute called add to cache. So the basic structure is we calculate what the cache key oughta be and then we check in the two caches, is that key there? Is it in either spot? If it's in either spot, we return the results from that cache dictionary and if it's not there, then we call request.get and we add it to the cache so that it will be there the next time. And the only other little tricky part in here that I glossed over is that we want these caches to live beyond the current run of the active code window. And so to make it be a little more permanent, at least to live a little longer than the current run, we want to save it in a file. I've shown the cache as if it's just a dictionary, but actually this dictionary we're going to store in a file. So we have to read this dictionary from a file and I'll show you this underscore read from file as another little helper function. So let's take a look at those helper functions now now that we understand the basic structure. The first one is this make cache key. So it's taking the base URL and the params dictionary and it has to make a string out of that request, a text string that we can use as a key in the cache dictionary. Now the URL itself, we could just make the full URL out of this base URL and the parameters dictionary, but we're making something slightly different in our case because there are some keys that we want to exclude in particular there may be private data that's used for authentication and we'll see more about this when we get to the Flickr API. The other thing that we want to do here is to make sure that we always get the parameters in the same order. If there's a couple of different parameters, remember this dictionary, the params D, the keys could come out in any order and if one time we call it, we get the keys in one order and another time we get them in a different order, we might fail in our lookup trying to find something in the cache. So we've created a canonical order. We alphabetize the keys by sorting them and the default order is to sort them in an alphabetic order and then we go through each of the keys and we just create a little string that puts together the key and the value. So we're getting all of the keys and values from params D and we're sticking them together into one giant string separated by underscore characters. So what we're gonna get is something that looks a lot like the full URL, but might be a little bit different. Let's look at the other helper functions. First, let's look at this read from file. Basically, we're just taking the contents of a file and reading them into a Python dictionary. So most of the action is right here. We open the file and then we read it and we call JSON.loads, which takes the text of the file and turns it into a Python object. In our case, it's gonna be a dictionary. When I've wrapped this in something called try and accept, if you haven't seen that before, don't worry about it too much. It's covered in the next course in the specialization. It just lets the code fail gracefully. So if it can't find this file or if it can't load it as JSON, then we'll just return an empty dictionary. So it'll fail gracefully. So that's reading it from the file and turning it into a Python dictionary. The other helper function is this add to cache. So we've got some cache file name and we've got some new key and results that we wanna save into the cache. So we first read that dictionary using read from file. We add a key to it with the value that's been provided and then we just write that back out to the file. And write to file, you can see up here is another helper function that just opens the file and writes the dictionary out. So that's a simple caching pattern that we've implemented. It's a wrapper around the expensive and unreliable operation request.get. You can just call request with caching.get. It returns the same thing as request.get. If it has a saved previous version of the request, it returns those contents and if not, then it calls request.get. It's useful because it helps you avoid problems with rate limits when you're debugging your code that's working with external REST APIs. I'll see you next time. Welcome back. At this point, you should be able to read API documentation in order to formulate and debug invocations of the request.get function. And you should be able to understand and appreciate the request with caching module. And you may be wondering where I get all my corny jokes from. Well, some of them are favorites I've accumulated over the years and retold probably too many times. And of course, there's a REST API to search for these jokes at icanhasdadjoke.com. That's has with a Z. The base endpoint gives you a random dad joke. Here's what I got back the first time I invoked the API. What do you call a crowd of chess players bragging about their wins in a hotel lobby? Chestnuts boasting in an open foyer. That one's an old chestnut. Here's a more profound one I got another time. What was a more important invention than the first telephone? The second one. The API also lets you do searches when I ask for slash search question mark term equals hipster, I got back three. How much does a hipster weigh? An Instagram. How many hipsters does it take to change a light bulb? Oh, it's a really obscure number. You've probably never heard of it. How did the hipster burn the roof of his mouth? He ate the pizza before it was cool. Okay, okay, I can hear you groaning through the screen enough with the puns. I hear you. I'll give it a rest. See you next time. Hi, welcome back. This lesson just gives you more practice at reading API documentation and constructing calls to request.get or requestwithcaching.get. Along the way, we'll also learn about API keys which are the simplest form of authentication that are sometimes required when your program tries to interact with the REST API. There's no new learning objective for this lesson. The goal is just to increase your fluency so you'll be ready for the final project where you have to decipher the documentation for two different REST APIs and create a mashup that combines results from both of them. So, bye for now. I'll see you at the end. Welcome back. Let's take a look at another REST API, iTunes. iTunes is Apple's media store. The REST API lets us make queries asking what's in the store. This page is their documentation. There's a base URL which goes up through search, so, HTTPS colon slash slash itunes.apple.com slash search. And then as we've seen before, they're query parameters. There's a question mark and then some key value pairs. What are the keys and values that iTunes understands for those query parameters? Let's scroll down and we'll see. We've got a whole table of them. There's a bunch. In the left column are the key names, things like term, country, media, or entity. In the right column, there's some information about what are the allowable values. So, the term, that's gonna be what we're searching for and you can put any text string in there. But for media, there's only certain allowable values like movie or podcast or music. So, in our URL, when we make a request to iTunes, we're gonna have something like media equals podcast. The other two columns tell us whether we are required to include this query parameter. Yes, you have to include term and you have to include country, but the other ones are optional. And then there's just description that gives you some hints about what you're getting. So, let's try to figure out what we would pass in for the params dictionary when we make a call to request.get. I'm gonna go back to Runestone and we'll come back and look at this documentation as we need it. In the textbook, we've got a couple exercises. Suppose we were trying to look for podcasts originating in Ann Arbor and we're gonna pass in a params dictionary to request.get. What value should we put here as the value associated with term? So, this is the thing we're searching for. And so, since we've said we're looking for podcasts that mention Ann Arbor, let me put Ann Arbor in here. Check me and it says, oh, don't forget the quotes. It needs to be a string. And we're gonna be putting a value here and it's gotta be a string. So, let's put that value in quotes. When it gets encoded into the URL, it won't have the quotes around it. But in order to be a value in this params dictionary, it does need the quotes. And that's all good. So, let's look at our next question. There's another parameter. If we're searching for podcasts, we're gonna have to give another query parameter whose value is gonna be podcast. Which query parameter is it? Well, you could try to guess. Perhaps you remember from the documentation page, but let's go look. And it turns out we can say podcast for the query parameter media. If we scroll down a little farther, it turns out we also can say entity equals podcast. If we say media equals podcast, then we'll be doing a little bit broader search. We can do a slightly narrower search where we say entity equals podcast and that will be limited to searching for Ann Arbor in the podcast title, excluding looking for it where Ann Arbor is part of the author. So we could say either media or entity. We've actually set this up so that it'll accept either media and says, yes, you can use that. But in our code below, we're gonna use entity, so entity is also okay. So here's a request that we can make. We're using requests with caching rather than requests just to make sure that if there's any problems getting to iTunes on a particular day that it'll still work. And we're passing in term Ann Arbor and entity podcast. It'll take us a minute and we'll get a result. It founded in the permanent cache. Now we haven't chosen to do anything with this, but I could also, for example, print what the full URL was that was created. And that's this URL. Now because we used caching, it didn't actually go and make the request to iTunes.Apple.com, but this is the request it would have made. It got the saved results, the cache results for that URL. Now at this point, I've loaded the response text into a Python object. I've saved that in the variable called pydata. And at this point we would have to go through our usual understand, extract, repeat process to pull out the data that we want from whatever is in pydata. I'm going to skip ahead because I've already done that process of doing the understand, extract, and repeat and this is what I got to. So I found that the top level object was a dictionary. It had a key called results and I have extracted the value associated with results and that value is a list. It's a list of dictionaries, one dictionary for each podcast result. Each of those podcasts is a dictionary that has a key called track name and I've extracted the track name. So when I run this, I will get the names of podcasts that have the word Ann Arbor in them. So it's telling us that it's founded in permanent cache and then on each line, we have one track name. As you can see, there's one from the Ann Arbor District Library, the award-winning Ann Arbor District Library, I should say. We love our library in Ann Arbor and we love libraries in general at the School of Information.  You can see the Harvest Mission Community Church, Grace Bible Church, and so on. And actually, there's a few more podcasts from the Ann Arbor District Library. So that's an example of deciphering the iTunes API documentation and using it to construct REST API queries. We'll see you next time. Welcome back. Let's try querying another REST API, this one from Flickr, one of the first popular photo sharing sites. Still used by a lot of excellent photographers. It's run by Yahoo now. Here's the overview documentation page for the Flickr API. We're going to use the photo searching endpoint. There are lots of other things you can do with the Flickr REST API, including posting photos and lots of other things. We'll just look at searching because you can do that even if you only like looking at photographs and you don't have a Flickr account where you've uploaded photos. So first, at the bottom of this page, notice that they give what they call an endpoint. That's what we will call the base URL. Everything after that is going to have question mark key equals value pairs. The next notice that they have a required parameter called the API key. So one of these is going to have to be API key equals something. That's a developer specific key that you get from Flickr by signing up for it. If you access one of our few cached queries, you actually won't need an API key. But if you want to run any other queries that we haven't put into a cache for you, you will need to get an API key from Flickr. A third thing to notice on this page is that they have another required query parameter called method. So we're going to have to have something that says method equals something. In our case, it's going to be something about search. And we'll find that on a more specific documentation page. So let's look at the documentation page for searching. I already have it loaded here. We're going to have to say method equals Flickr.photos.search. There are also a bunch of other keys that we can provide, what they call arguments. I'm just going to clear my marking here and scroll down to show you that there's a lot of options or arguments and it just keeps going. These are all things that are going to affect what gets retrieved. So we can ask for only things that are photos that are taken indoors or only photos that are taken outdoors. We can provide a latitude and longitude and it'll bring us back photos that are within some radius of that location on Earth. So there's a bunch of them here. We're not going to use them all in the examples that I show you, but we can come back to them whenever we need. It's worth noting that the API key is required. I talked about that already. And then we're going to search for tags. So photos on Flickr, the photographer, when they upload them, they can give them tags like this is indoors or this is still life or this has mountains in it or they can put a city name, any tag that they choose. So we're going to use that to search for photos of mountains and rivers. And then there's this tag mode. If you provide more than one tag, that can either be treated as you want to search for photos that have one of those tags, that's the or combination, or that you want to search for photos that have all of those tags, that's the and combination. Now if I scroll all the way down, we'll see something about what the results look like. Here's an example response. You'll notice that it doesn't look much like our favorite JSON format. This is actually XML format. So by default, Flickr returns data not in the JSON format but in XML. It's possible to parse XML in Python. It's not that difficult, but we're not going to go into that in this specialization. Most sites that provide XML also have some way to ask for JSON instead. Flickr does have a way to ask for JSON instead. They don't make it that easy to find out how. I didn't find it anywhere on this page. But I did do another Google search. And if I just search for Flickr API JSON, the first response that comes up is a documentation page about how to get things in JSON format. So the trick is, let me show you somewhere here. It's right here. Send a parameter called format with a value of JSON. So we're going to have in our URL, format equals JSON. There's one other little tricky thing. I'm just going to get rid of those markings and we'll scroll down. Turns out the bottom of the page, they have a little thing that says something about callback functions. Turns out we have to send nodeJSON callback equals one. It's a little more technical than we're ready for, but here's the basic idea. Without that nodeJSON callback equals one, you would get JSON results that are wrapped in basically a JavaScript function invocation called a callback. So that wrapping is part of a standard called JSONP. In any case, what we need to do is we need to include nodeJSON callback equals one in order to just get pure JSON without any extra characters around it. So with that basics from the documentation, let's look at some code for making API requests. As with the other APIs, we're going to use requests with caching so that we can avoid you having to actually get an API key from Flickr. You'll just get data from our cache where we won't check for needing an API key. And just like we did for the Datamuse API, I've defined a function getFlickerData. We'll pass in as a parameter, this tag string, that's saying what tags we want to search for. So when I call it on line 26, I'm going to pass in this comma separated list of tags, river comma mountains. Inside this getFlickerData function, you can see that I'm going to get set up to make a recall to the requestswithcaching.get. In order to set up for that, I set my base URL, I make an empty parameters dictionary, and then I set a bunch of key value pairs. I'm going to have API key equals whatever I have for my Flickr key, which is just a variable up here. For the tags key, I'm going to set it to be river comma mountains, or whatever the current value of tag string is, whatever it's been passed into this function. For the tag mode, I'm going to say all. I want photos that have both river and mountains as a tag. The method is flickr.photos.search. I only want to get five results back. I would like only photos, not videos, and I want the format to be JSON and no JSON callback equals one. So that creates that whole dictionary. I pass that in to my request.get or requestwithcaching.get, and I'm telling the request with caching to use the file called flickrcache.text as its caching file. So I get a response object back and I'm just going to print the URL from that. That's the URL that we would have gone to if we didn't find it in the cache. And then we return a Python object. We turn the text string into either a list or a dictionary by calling this .json method. So I'm going to invoke that on line 26 and then once I get the results back as a Python object, in this case, it's going to be a dictionary. I have to go through my understand, extract, repeat process to figure out how to pull out the data that I want. Again, I've already done that so I'm not going to walk you through that process but I've discovered that the result dictionary has a top level key called photos. As the value associated with the photos key, there's another dictionary and that dictionary has a key called photo. I find that a little confusing because that's the way the data comes back from Flickr. The value associated with that photo key is a list. It's a list of dictionaries, one dictionary for each photograph and the dictionary for one photograph has a key called owner and another key called ID. So for each of the photo dictionaries that's returned, I'm going to extract the owner and the photo ID and I can stick those two values into a URL because I've looked up what is the format that Flickr uses for making URLs to actually load a page with a single photo in it and I'm just substituting owner and photo ID in to make this URL straight. So if I run this, I'm going to get a printout of five different URLs. You can see the five URLs are here and above it, we got the URL that we would have fetched if we hadn't found the result in the cache. If this were a full Python environment, we would be able to import the web browser module and we could call web browser.open which would make this URL open up automatically in another tab. I don't have that option available to me so I'm just going to, we printed it out and I'll go and make a new tab. We will visit that URL and there we have a photo that's tagged with mountains and river. I can see the river. I'm not quite sure where the mountain is for this one and we got some more. Here's another one. I put that URL in instead. Here's one that does have a river and a mountain. Now notice that on line 23 I have the code printing out the URL. That's the URL that we would have visited if we hadn't found it in the cache. And if I copy this, I can go to another tab and see what I would get if I actually went to that URL for the API call. The answer is I get a message saying we failed because it's an invalid API key. I didn't provide a valid API key and so I can't actually make that query. That's one of the advantages of getting the stuff from the cache is that we're not requiring you to have that API key. Now if I were to change this and instead of asking for say river and mountains ask for cows and mountains. I've tried this before and we tend to get beautiful pictures from Switzerland and the Pyrenees in Europe. If I try to do this, it won't find it in that cache and so it will try to fetch it. So it's new and adding it to the cache. Here's what the URL is. But we get an error. And the error is on line 30. When we go to try to extract the photos and photo IDs on line 30, we're finding that we get a key error. In the dictionary of results, we don't have anything called photos. So let's see what the result really was and it's gonna be the same error message that we saw in the browser window. So we get the error message that it was an invalid API key. So you can make this work if you sign up for an API key and put your API key on line eight, you would be able to make new queries with this code. We didn't show it here, but there are other operations with Flickr that require user-specific authentication like if you wanna post photos to somebody's account. You'd need to prove that you have permission from them. APIs provide features for doing that kind of user authorization through a protocol called OAuth, but that's beyond the scope of this specialization. And once you've authorized, each request would get digitally signed and Python provides a module for doing that called requests with OAuth. Again, it's beyond the scope of this specialization. The key takeaways from this lesson, one sometimes you need to pass a lot of query parameters. Take a look at lines 13 through 20. Sometimes there are a lot of choices about what the query parameters are. Remember that long list in the documentation. Sometimes you have to specify that you want things in JSON format because that might not be the default. And sometimes you have to specify other idiosyncratic things like this no JSON callback equals one query parameter. Finally, many sites require you to provide an API key which you get by registering with that site. See you next time. Hi, welcome back.  There's nothing like practice and repetition for building fluency, which reminds me of one of my favorite old jokes. A young tourist from a small town in Michigan is wandering around Midtown Manhattan. He looks at his watch and realizes that he has tickets to a symphony orchestra concert at Carnegie Hall starting in half an hour, but he's not quite sure where Carnegie Hall is. So he sees an older woman carrying a violin and figures, she must know. And he asks her, excuse me, can you tell me how to get to Carnegie Hall? She looks at him slowly and says, young man, practice, practice, practice. I'll see you next time. Hello, and welcome to the project for course three. In this project, you'll be making what's called an API mashup. You'll be getting and using data from two different APIs. So ultimately in this project, you will get data from two different places on the internet, process all of that data in a step-by-step way and achieve a new result that comes from getting the data from two different places. Just like other APIs you've examined before in this course, you will need to read and understand the documentation that goes with each of these APIs. And your goal with reading and understanding that documentation will be to pull out the information from the documentation that you need in order to make a request to each API. So you might need to read through some stuff that's complicated or includes things that you don't necessarily need or words that you haven't heard before just to find those pieces of information that you really wanna find. Like for example, the base URL for the API request. You'll wanna keep in mind as you work on this project, what you know already about building functions because that's something else that you'll do throughout this process of building a result and processing data. You'll wanna remember that as you work on this project, you'll be using the special tools that we've built in this specialization to allow you to get and cache data from the internet and retrieve data from the cache. As you work through each step, make sure to take each slowly, think carefully about what exactly it is you want to achieve at a given moment, make your plan in words, you've probably heard me say this before, and then translate those words into code. And that will make the process of building up a result from these brand new APIs much easier and make it seem much more like the other things that you have already done in code before. This is a type of program, getting data from two different places and doing something new with it that is useful in all kinds of situations, in all kinds of work, in all kinds of different disciplines. I wish you a lot of luck and I hope you have fun.


Hi everyone, Joe for jasphyscasebrakes.com. Happy Saturday, coming at you with 2020 Panini Absolute Football. Six box intercase picker team number six from jasphyscasebrakes.com. All card chip. I think this is our last absolute case for a little while unless we get some more. I think this might be it. Oh, camera, where are you? Yes, you can play, there you go. Hi, there's picker team six right there. Let's actually slide this camera over this way. So we can get a little skycam action happening here. There you go, so you can see all the card set up there as well. Adjust the white balance on this. Let's roll off the brightness just a tad. All right, we're good there. Okay, so there's picker team six. Looks like Sean did pick your team five few nights ago. So let's see what we have in the second half here, the second intercase. 10-10 equals 20, right there. Six box picker team six. Oh, Illuminati numbers there. Thanks everyone for getting into the action. Really appreciate it. We got plenty more football. We might be out of absolute, but we've got a lot of other football on the side right now, boys and girls. We've got a football mixer that we can do. We've got immaculate football. We've got spectra football pre-orders. We've got prism football. And we've got no huddle, mosaic no huddle football, ladies and gentlemen. And that mosaic, no huddle football, 20% off until 3.30 Pacific, 6.30 Eastern tonight only on the Saturday the 10th. I would take advantage of that while you can. There's still, I think there have been some teams being snapped up, but there's still 21 teams left. So chances are your teams there. You can get 20% off a $20 team.  Have a little skin in the game. That's fine. Or you can go for one of some of the big teams. Go for some of the big teams and get 20% off that too. You ever thought, man, I'd get that high end team if only there were just 20% off? People always ask, hey, I'm a new customer. Do you have a new customer deal? Yes, we do. 20% off, Panini, no huddle football. Mosaic, no huddle football on jaskyscasebreaks.com till 3.30 Pacific, 6.30 Eastern. Take advantage of it. We usually don't do this too often. Our prices are already good enough. But check it out, folks. All right, so all hardship. I'm just gonna set those aside right here. There's Chase Young to $199. That's for Washington. That's for Jerry. Our first hit is, ooh, and a plate down there. Triple Relic and autograph, Michael Pittman Jr. Unfortunately banged up, but hopefully we'll get well soon. Hold on to this, could be a good keeper right there. Uh-oh, let's put that over there. That's for the Colts and that's gonna be for Derek Disser. There you go, Derek. The plate is Jeter Gross Matos, one of one. And that'll be for Carolina. Matt Medlin with the Panthers. All aboard the Big Hit Express. Woo-hoo! We got Xavian Howard, Drew Brees, and a redemption. Behind the redemption is Clyde Edwards-Elair, 90 out of $199. That'll be for Rich Ferrettis and the Chiefs. There's Hightower, the fourth to 100. There's MVP Mitch and Daniel Jones behind him. We got Darynton Evans to 75. That's for EA and his Titans. Titan Up, and we've got T.J. Hawkinson, Dual Relic, Tools of the Trade, 22 out of 99. Lions, that'll be for Ryan Redman.  And the redemption is gonna be Seedy Lamb, tiny of cards, Seedy. Seedy, Silence of the Lamb. That's gonna go to Rich and Dallas Cowboys, nice. There you go. And that spectrum parallel Pat's telling me is to 99. So that guy, Seedy Lamb's been working well together lately. Cowboys defense is still, that's the rough part. The defense has been letting them down. Oh yeah, they're all right. The Masters are in November. I think Tony was asking me earlier if I play video games. I really don't. Like, I bought a PS4. That was like totally a pandemic purchase. I was like, yeah. And I don't really play it that often, but I did recently get, from a Nick Jaspie recommendation, I did get a PGA Golf, 2K, one, 2K, 20, 2K, whatever, from 2K sports. It's pretty fun, if you're into golf. All right, there's Quintez Cephas to 25. That'll be for the Lions. That's gonna be for Ryan. Ryan with the lion. There's Keyshawn Vaughn to 199. That'll be for Karen and the Buccaneers. Karen, you'll also get this. What, Karen, what? She's a Patriots fan. What happened with this guy? Three, four, three, lost, lost, losing track. Getting old, I guess. Isaac Bruce to 100. Aaron Donnell, DJ Moore, CJ Henderson to 199. And the Bear is Cole Comet. Oh, a lot of nice colors in here. Triple Relic and Autograph. Rookie Premier, Triple Relic and Auto. That goes to Da Bears. That'll be for Sanford with the Bears. He picked up the Bears last, last bottom mojo. 60% of the time, it hits 100% of the time. CJ Mosley to 25. That'll go to the Jets. Anthony McFarland Jr., five out of five. Another train whistle, boys and girls. Out of fives and under, get it. Michael Gulucci, Steele, Curtin and his Steelers. There you go. All aboard the Big Hit Express. Woo-hoo. We got Dalvin Cook, Triple Relic, Tools of the Trade, 68 out of 75 for Minnesota. Conrad with the Vikings. And then we've got Mark Ingram to 100. Is this the game to be watching, folks? I've got Arkansas Auburn on. I don't know. My college football knowledge, my college knowledge. Not super strong. I don't know if there's a better matchup I should be watching. Georgia, Tennessee. I know those teams. One is a Bulldog. One is a volunteer. What channel, what network is that on? Ben, if you don't mind. On CBS, okay, I can handle that. I think that's channel two. Got it, thank you. Oh, this is a good game. Thanks, Ben. Tennessee up 21. The 14th ranked Tennessee volunteers up 21, what, 17? On the Georgia Bulldogs. All right, did they stop a Georgia running attack? At fourth and short? I think they did. All right, we got T.Y. Hilton, Raheem Moster. I think Moster might be back in action this week. Nice Alexander Madison, dual relic and autograph. 83 out of 99. So we had the Dalvin Cook tool to the trade. Now we've got some of Alexander Madison's, some of his tools. That goes to Conrad and the Vikings. That's a good duo right there. And there's Debo Samuel, quad relic. 16 out of 25 for the Niners. John with the Niners, John G. All right, we got Tyler Johnson for the Buccaneers. To 100, I thought I heard his number called a little bit on the Thursday night game. Karen with the Bucs. And here's the Bear, Mitchell Trebisky, triple relic. 48 out of 75, looks like his day's in a Chicago or done. Hopefully he was renting. It goes to Sanford and the Bears. And there's Light's Camara action to 25. That goes to Matt and the Saints. There's Chase Claypool to 199 for the Steelers. And we got Denzel Mims, nice. Triple relic and autograph. 75 out of 99 for Adam and his Jets. There you go, he's banged up too, but this could be an important weapon for the Jets going forward. And there's Noah Ibinogeini to 50, nailed it, nailed it. We're halfway through this break, another three boxes. In my, I made some super crazy, super long shot picks. Jets was one, to win divisions. Jets was one of the teams. I don't know if they're gonna do it. 0-4 though, could they still win the division? I guess Buffalo would have to lose every game. It's possible, I think mathematically it's possible. They have not been eliminated from playoff contention yet or division contention yet. It's nice throw by the Tennessee Corps back here. Ooh, that was even better. There's Damon Arnett to 75 in an alternative universe Ben saying the Jets win the division for being 0-4, right? A lot of strings out there. A lot of strings in the world, in the universe. Damon Arnett, part of the Raiders defensive rebuild that goes to Pat Cologne and the Raiders. And then there's Team Tandem Chargers, Hunter Henry, Joey Bosa, 187-199. That will be for Sean Matik and the Chargers. There's Clyde Edward D. Lair to 100. Kyle Dugger for the Patriots to 149. What's going on with Cam? Is he coming back? That's Karen with the Pats. And we got Randall Cunningham, old eagle right here. 11 out of 199. And that is for EA and the Fly Eagles Fly. Christopher, what's going on? It's going. And someone was saying, Alice, you got upset today? By Missouri? Oh, Missouri's happy. Got Chase Claypool right here to 199. And there's a Tua Tagovaiola autograph. Triple Relic and Otto. 129 out of 149 for Richard Ferrettis and the Miami Dolphins. There he is. When does he make his premiere in the NFL? We're on to a watch. Definitely on to a watch. Joe Burrow obviously has been playing. He's been doing well. Justin Herbert got into the action. Now he's the Chargers quarterback for the rest of the season. That's official. I feel like Jalen Hertz for the Eagles have been in for a couple trick plays here and there. I don't think it's too often, but after their bi-week, thinks Pat. Yeah, I guess they're really in no hurry to win, right? No hurry to win. In no hurry to risk his hip. Maybe when their Dolphins, yeah. I think they have a late bi-week too. No pre-season for two and yeah, just maybe just keep him marinating, but unveil him late in the season. There's Ben D'Nucci to 50 for the boys. That'll be for Rich. We've got Duel Relic, Drew Locke, Jerry Judy to 199. Yeah, Miami Dolphins bi-week isn't until like mid-November. They host the Jets, then they have a bi-week, then they play the Jets. Actually, that's not a bad spot for him, right? He can preview the team at home, you know, and then have another week to prepare for them, and then he plays the Jets. Might be a good spot. Get some plays coordinated for him. There's Jalen Rhaegor, Quad Ralligan Autograph, 44 out of 50. That'll be for EA and the Fly Eagles Fly EA and the EA Eagles. There's CD-Lan and there is Devin Asiasi to 50. Yeah, I'm telling you, Pat says, gives him a break late in the year, probably out of it by then, and then just get him experienced in 2021, yeah. Do you start him the rest of the way? Cause they still have one, two, three, four, five, six weeks of football. That'll go to the Pat, that's for you, Karen. Air raid gardener Minchew to 199. John McCall, I guess once you start him, I guess, pending health, you just gotta keep going with him at that point. It's Plaxco, 75, unless he's super ineffective. All right, final box. So if we go by our thought that Tua, and I think it's a good thought, Tua, makes his first start after the Dolphins Bi-week and week, I guess their week, it's gonna be week 12 for the NFL. It'd be at New York versus, and then hosting Cincinnati. That'd be a Tua burrow. That'd be a nice matchup for Tua's second start if we're going by our theory that he'll get, he'll get some work in after the Bi-week. Then it's Tua versus Mahomes, hosting Mahomes in Miami. Then the following, there's three home games in a row. Then they're hosting New England and Cam Newton and Tua. Then they go to Vegas, right? So it'd be Tua versus my Raiders. And then the last game of the year for the Dolphin would be at Buffalo, Tua, and Josh Allen. That's some good matchups there. Some fun matchups. Showcase Tua, right? Oh yeah, NFL will love it. There's some good matchups there. And that means a lot of highlights. Think about it. Whether he has a good game or not, there'd just be a lot of highlights of Tua because they're playing some big teams. You know, Kansas City, New England. A lot of attention there. Tua height. We got a Nikhil Harry. 34 out of 49, Duel Relic, and is that a piece of his helmet, I think, Karen? Looks like the glittery bit of the Patriots' helmet, the tools of his trade. We got Derek Henry, Triple Relic, 75 out of 75 for E-8. North Carolina's ranked eighth? What's this world coming to? Are they turning into a football powerhouse as well? There's Neville Galamour to 75. That'll be for the Cowboys. That'll be for Rich. We've got Josh Kelly to 199. He's gonna get some love, too. Austin Eckler is banged up. And Austin Eckler might be out for four to six, I think, four to six weeks, maybe. Give or take? I mean, is this guy Shawn Matic? We've got a flashback, fantasy flashback. Plasko Burr is putting up 46 points. Wow. The Steelers battled the Falcons to a 34-34 tie in week 10, back in 2002. But Plasko Burr has still put up nine catches for 253 yards and two touchdowns. Wow. The Marks had a franchise record for receiving yards in a game that would stand for another decade. This is Jerry Judy to 199. We've got Antonio Gandy-Golden, triple relic and autograph as our last hit of the break, 247 to 399. That goes to the Washington football team, Jerry Bennington. And last but not least, here is Joe Reed, three out of 10 for the Bolts. That's gonna be for Shawn Matic. And there you have it, ladies and gentlemen. I'm Joe for jaskiescasebreaks.com. Thanks for breaking with us. Thanks for watching. We'll see you next time for more. Remember, the 20% off discount Mosaic football, no huddle addition if you wanna get into some more gridiron trading cards. I'm Joe. I'll see you next time. Bye-bye.


So, before we go ahead, how many people know about the docker here, great, how many people heard about the Kubernetes, great, so okay, so now open shift right, it is a red hat product actually and what how we actually advertise it, it is like run Kubernetes with the enterprise as stuff added to it right, so we actually based our stuff on the Kubernetes and add some more enterprise values added and then we tell the customers or even we have the open source version of it which we call origin right, which we call origin, open shift origin which actually we always make sure that it parallel to the Kubernetes development right, now okay, just who am I, my name is Praveen Kumar and then I works at red hat, I works in a team which is the developer experience group team and we make sure that when developer start developing the applications right, they are easy to deploy it over any past infrastructure or if they needed any you know run times then we tell them okay, we can use that and so those kind of tooling where we work, what is mini shift actually, so how many of you heard about mini cube right, so it is the same thing like mini cube, we forked from the mini cube only but in the open shift what we do is that we use OC cluster up which is what we do it will actually start a cluster, one single node cluster of open shift right and locally, so and the underlying things is lib machine which we are going to talk about, now the question occurred why we needed mini shift when we already tell user okay directly install open shift, the thing is that directly installing open shift the configuration part and all those things are quite node user friendly, it takes some time to user to grab all those things how to you know change the configuration making sure the nodes are working, making sure the connections are working right, for that what we did is that what we actually do, we make sure that the things are already part of one single the tool which we are shipping like mini shift and user just have to do like mini shift start and it will just start the cluster and then user just have to worry about their application development instead of the configuration part of it right, now the same thing why mini shift we use we, so single command which is easy to use, everything whatever a developer usually require it's already there, you don't have to install anything extra because the mini shift is written in go, so static binary right, so no other dependency and then we can what we can the user the benefit user will get is that they can run their application locally on the open shift before they move their application to the production level for open shift, in the production level there are that the operational team might have some you know different kind of security okay, this container doesn't run in this particular user permissions this container doesn't run, so user can do all kind of experiments locally before they push it to the production scenario, so you don't believe me that's fine there is a demo let me just clear it very fast I'll try to do because I'm already we have last time, so I just did mini shift start can you see the screen, so I just increase the font a little bit, so two things here you can see it is starting mini open shift with the XI hypervisor, how many of you know about XI right, so it's like it's natively right now on the Mac the support is there it's on be higher based on be higher but it's open source, so people are using now to making sure that the things is work without any extra virtualization tool like virtual box or something else, so we are also using the same capability because Lib Machine already have those kind of capabilities to use, sorry guys a live demo usually don't work very well, so let's hope, so it was I think because of network issue but let's see if it is start, okay before let it going to be here let me just increase the font a little bit here, just tell you about what are the options we have in the mini shift right now, so one assume that you are running your cluster right now you want to make some change in the configurations, so there is a something called config right which will modify the mini shift configurations option, so like right now I am using jive driver but I want to switch on the virtual box and next one I always want to be to virtual box so I can see mini shift config set whatsoever right, whatever the driver I use, then there is a console which will open the web console for the mini shift and then delete is what it's supposed to be and then docker environment is that like if you want to add some more insecure registry or if you want to add the proxy settings or if you want to provide something else with the docker environment variables you can set it up, IP provide the IP of the running cluster, logs and all those things are there what happened to it, okay it started actually, it just terminal phase for something, so now it started so as I told let's see, so the IP which I got here is the cluster IP and the VM which is running inside the using the jive, so what I can do is fast now, so okay let me log out, so by default we create a one user for the cluster which is developer-developer username and password will be developer-developer and by default also under the user developer we create a project called myproject, so now what I will do is that very fast is deploy applications right, so what I will say, I will say okay I want to add something to the project, now what kind of project I want to deploy right and what are the strategy I can use to deploy my project or application, so let's say I have a docker image already right, I want to just deploy the docker image and my docker image are on the docker hub right, so I will say that I have a docker image, I am using a road so image which we usually use for presenting during the road so for the open shift, so I am using that image I will deploy it, search it out right and then, so there are options like if you have some like in the docker file you can create the environment and then you can pass it along right, so if you have environment variable you can pass it along labels and all those things, so now I will say create, now you can see it's started and you can see the continue to overview where it started the port right, now you can here you can see the log, anyway the application is up and running now, if I want to see the application I have to create a route because right now this application is what is inside registry you can access it but the creating is route is very easy, you can see this, you can just do a create route and I don't want to do any extra things, it will create a route for me, now I can access this application using this route, so when I click here you can see this map visualizer which is on my local system working here right, you can see in the street, you can see in the grayscale right, so the map is working all things locally working fine, now another thing that usually what developer actually do they just want to commit their code to GitHub right and then they want that okay once the code is commit to the GitHub or any version control it's supposed to have a web book which will deploy the applications on based on that, so what we can do is that let's do first assume I have a Python project right and I am using the latest Python I will again use a, so right now the project which I am deploying is a kind of backend service which is doesn't have any database but it have the json to coordinates of the national park which are there which we can see in the map visualizer, so the GitHub URL is there, so it's very simple I'm just telling the demo is only the purpose to understand how the things works in the open shift, how easy to the deploy the applications on the open shift, so I will just create it, I will just go to and start, so the application is running if you want to see the logs for any application which you deployed you can see, so what it actually do is that it clone the repository then there is some concept called ashty which is source to image builder, what it do is that it will take your source because we selected the Python 3.5, the base Python image will be there which source to image understand that how to integrate that code right and where to put that code so that it will run as a docker container, so once it the container is up and running it will post I think it's successful already, so it will be available, so now you can see the port is up and running right and it because we use the template which have already by default the route creation we don't have to create the route, so yes you are right, so the Resolver which we are using DNS Resolver it's actually need Wi-Fi come on, well it was easy anyway so this is the way so that the application is running up and running here you can see the port is running right and once the Wi-Fi up I will show you again okay, okay let's go back to the slide it's not up right, I will turn it off, so that's how we actually deploy the application on OpenShift the help section I already did, now under the hood like I talked about it's forked with the minicube sorry minicube right and then what it do is it's runs the single node OpenShift cluster within a VM using the native hypervisor of the box like in Windows if you want to run the mini shift it will use hyper the hypervisor will be hyper V right in the Linux if you use it will use the KVM as a default, so you don't have to install any extra tooling around the virtualizations and then use the lib machine to manage the VM management because lib machine have different drivers for the different hypervisors like KVM driver it have docker what driver it have excite driver and then the KVM drivers right and then it will use the cluster up for provisioning the OpenShift cluster right so once the VM is up we just run opens a OC cluster up so that it will start the cluster why red hat is actually investing for the mini shift because in the inside the red hat we have product called CDK container development kit if anybody want to know more I'll be outside we can talk about it but it's a it's zero price subscription base things which you have the rail ISO you can run your stuff on the rail and the OpenShift with the OCP which is the OpenShift container platform OpenShift the downstream OpenShift will be there right OCP future roadmap so we recently did the beta 5 release of it and it's working pretty pretty good so these are the roadmap we have so the people who use boot to docker ISO anybody use boot to docker right so they have something so they already use the different kind of VM drivers like virtual box they are using VM drivers the VM we be gassed to making sure the host and gassed mounting happens without any problem so we are actually so and the thing is that it only happened with the virtual box right so what we are doing is that we want to make something like SSH SSH way SSH FS way to so that it will doesn't matter with the operating system which we are using instead of that okay the SSH base sharing will be up and running for each and every operating system so that thing we have already ability to configure and patch the OpenShift mastern node and yeah where can I get it this is the GitHub URL go to religious download the binary started community we are very active we closed 300 start not that big but yes we are still counting we are working towards it we have a free node channel on IRC still not on slack but works fine mailing list we have container tools at head.com in the mailing list right now it's a public mailing list you can join ask questions resources we have a documentation page on the open shift .org slash mini shift and then the current examples as per demo which I showed you right now is actually is on that data code dot com open shift you can just run through it and you can see how the open shift actually works thank you any question I think I was on time let's see little bit so the OC is the open shift client binary which have the options called cluster what it do is that it will just provision one cluster and node on the local host and then provision it so and the same thing which we use because we don't want to invent same thing again so we use the OC cluster okay so thank you very much


My name is Angela Hathaway. I had the bariatric gastric sleeve surgery through Mid Michigan Medical Center Midland and I've lost 134 pounds. I am a wife to my husband Keith and I have two little boys. I've had problems with my knees since I was junior high age and they were just getting worse, problems with my back. Everybody suggested maybe if I got the weight off it might help with my problems. I actually was with my family physician Dr. Paul Berg and he was helping me out with one of my foot problems. I said well I've heard that being overweight affects your feet and all your joints of course and he suggested that maybe I should look into gastric surgeries. The first six months after my procedure was a difficult time because you're still not allowed to eat a lot of things but progressively as the weight kept coming off I got so much more energy. I was actually doing 5k's, was able to play with my kids and I didn't mind going shopping or doing all those normal things that a lot people take for granted because I was always too tired to do them. I was able to do the things that normal people would do and actually enjoy them. When people ask me about bariatric surgery I don't really sugarcoat it. I let them know that it is not easy. It is a tool to help them and that with some hard work and dedication to the program that is outlined to them that they can be very successful and it's rewarding and it's the best decision I ever made.