Our health, our children's health, and the health of the planet are intimately connected, and in general the choices that are healthiest for us turn out to be healthiest for our planet as well. Many of us know that vegetables are important for our health and that we should try to kind of limit the amount of meats in our diets or the frequency with which we eat meat. But it turns out that if we replace some of the meat in our diets with vegetables that actually turns out to be better for the earth as well. Modern methods of producing meat actually hurt our environment. Let's take a look at beef for example. So historically cows got energy from grass and the grass got energy from the sun. Now the cows in turn give nutrients back to the grass that they're eating through their manure. I don't know if they've ever heard the saying don't poop where you eat, probably not, but the point is that that manure actually fertilizes the grass to grow even more. And this is what we call a closed loop system because the inputs, in this case sunlight which is free and the outputs of this closed loop are in this case manure and this manure becomes a nutrient input again and this is why we call it a closed loop system. These days we produce meat very differently. Instead of grazing on grass in a pasture, most cows are typically found eating corn in factories that we call concentrated animal feeding operations and the abbreviation for that is CAFO and a CAFO is kind of like a city or a slum for cows. The reason that we raise cattle in CAFOs and feed them on corn comes down to simple economics. Corn is cheaper than grass because the government incentivizes or pays farmers to grow lots of corn. Because CAFOs are really tightly packed like slums, they can yield thousands more cows per acre than a pasture can and when cows eat corn instead of grass they fatten up more quickly which means that they can go to market more quickly as well. But these cheaper prices don't take into account the enormous cost to the environment and to our health. Meat is free and it's free of greenhouse gases but when we move to CAFOs where cows are eating corn there are a lot of inputs besides sunlight. When farmers grow corn they use fossil fuels and fossil fuels are used to make pesticides and fertilizers and to power the tractors of the machinery that harvest and transport the corn.  Also huge amounts of manure collect around the CAFOs in enormous lagoons of waste which harm the air and the water for miles around. Unlike in the system where cow manure fertilizes the grass that it eats, this manure has nowhere to go and it's produced in such enormous quantities that it's difficult to move anywhere else. When cows live in such crowded conditions they're also much more likely to get diseases so farmers feed them antibiotics to make sure that they stay healthy. Eighty percent of the antibiotics used in the United States go to this kind of commercial production of animals and it's really dangerous for our health because it leads to antibiotic resistant bacteria. These are superbugs that can cause diseases that we can't treat with regular antibiotics. So let's look at a chart that will kind of help us see the difference in greenhouse gas emissions of meat versus other things like fruits, vegetables, tofu, and beans. So for a kilogram of beef twenty seven kilograms of greenhouse gases are added to the environment. Now for a kilogram of let's say broccoli or a kilogram of tofu only about two kilograms of greenhouse gases are released into the environment. Also different meats are relatively better for the environment. For example chicken is more energy efficient than beef and also because it has less saturated fat than beef it's probably better for your health as well. So the message is limit red meat consumption, pick lean or energy efficient proteins like chicken or vegetable sources of protein more often and in general choose vegetables more often.


Many people know how to repent, even fewer know how to return. Repent.  But now it's not just a matter of not doing what you shouldn't do. Now it's a matter of doing again what you know you ought to do. Not just giving up wrongdoing, but picking up right living. And I'm talking of course about the basics of the Christian life to where now we begin to embrace again the reading of the Word, prayer, tending church, accountability, worship.


On the pitch, unbeaten BSU, looking for win number 13. Scoreless in the 22nd minute, Rachel Norton deflects the clear and passes it to Aaron Becker. Just 41 seconds after she subs in. That's a debut. She gives the Beavers the one to nothing lead. Same score, second half, Devin Bregman with room to shoot, fires it from 25 yards out, beats the diving keeper for the goal, it's two to nothing. And in the 75th minute, Megan Dahl with the free kick, the boot, cash, money, her first goal of the year. Bemidji State wins three to nothing big match on Sunday against Minnesota State. If you enjoyed this segment of Lakeland News, please consider making a tax deductible contribution to Lakeland PBS.


Hello everybody. Today we're going to be talking about data types in Python. Data types are the classification of the data that you are storing. These classifications tell you what operations can be performed on your data. We're going to be looking at the main data types within Python, including numeric, sequence type, set, boolean, and dictionary. So let's get started actually writing some of this out and first let's look at numeric. There are three different types of numeric data types. We have integers, float, and complex numbers. Let's take a look at integers. An integer is basically just a whole number, whether it's positive or negative. So an integer could be a 12. And we can check that by saying type. We'll do an open parentheses and a close parentheses. And if we say the type of 12, it's going to give us an integer. Or if we say a negative 12, that is also an integer. We can also perform basic calculations like minus 12 plus 100. And that'll tell us it is also an integer. So whether it's just a static value or you're performing an operation on it, it's still gonna be that data type if those numbers are whole numbers, whether negative or positive. Now let's take this exact one and let's say 12 and we'll do plus 10.25. When we run this, it's no longer gonna be a whole number. It'll now be a float. So let's check this. Now this is a float type because it's no longer a whole number, it's now a decimal number. And the last data type within the numeric data type is called complex. Let's copy this right down here. Now personally, this is not one that I've used almost ever but it is one just worth noting. So you can do 12 plus and let's say three J. And if we do this, it's gonna give us a complex. The complex data type is used for imaginary numbers. For me, it's not often used but if you do use it, J is used as that imaginary number. If you use something like C or any other number, it's gonna give you an error. J is the only one that will work with it. Now let's take a look at Boolean values. So we'll say Boolean. The Boolean data type only has two built-in values, either true or false. So let's go right down here and say type true. And when we run this, it'll say bool which stands for Boolean. We can do the exact same thing with false and that it's also Boolean. And this can be used with something like a comparison operator. So let's say one is greater than five. And let's check this. This is giving us a Boolean because it's telling us whether one is greater than five. Let's bring that right down here. This will give us a false. So it's telling us that one is not greater than five. And just as we got a false, we can say one is equal to one and this should give us a true. So now let's take a look at our sequence type data types and that includes strings, lists and tuples. We'll start off by looking at strings. In Python, strings are arrays of bytes representing Unicode characters. When you're using strings, you put them either in a single quote, a double quote or a triple quote. I call them apostrophes.  So right here, we have a single quote and that works well. We can do a double quote and that works also. And as you can see, they are the exact same output. And then we have a triple quote just like this and this is called a multi-line. So we can write on multiple lines here. So let's write a nice little poem. So we'll say, the ice cream, vanquished, my longing for sweets. Upon this diet, I look away. It no longer exists on this day. And then if we run that, it's gonna look a little bit weird. It's basically giving us the raw text, which is completely fine. But let's call this a multi-line. And we're gonna call this a variable multi-line. And we're gonna come down here and say print. And before I run this, I have to make sure that this is ran. So now let's print out our multi-line. And now we have our nice little poem right down here. Now something to know about these single and double quotes is how they're actually used. So if we use a single quote and we say, I've always wanted to eat a gallon of ice cream. And then we do an apostrophe at the end. Obviously something went wrong here. What went wrong is when you use a single quote and then within your text, within your sentence, you have another apostrophe. It's gonna give you an error. So what we wanna do is whenever we have a quote within it, we need to use a double quote. These double quotes will negate any single quotes that you have within your statement. They won't, however, negate another double quote. So you need to make sure you aren't using double quotes within your sentence. If you wanna do something like that, you need to use the triple quotes like we did above. So we can do double, double. And then let's paste this within it. And anything you do within these triple quotes will be completely fine as long as you don't do triple quotes within your triple quotes. And we'll say this is wrong. So even though it's between these two triple quotes, it doesn't work exactly. Again, you just have to understand how that works. You have to use the proper apostrophes or quotes within your string. And just to check this, we can always say, here's our multi-line. We can always say type of multi-line. And that is still a string. One really important thing to know about strings is that they can be indexed. Indexing means that you can search within it and that index starts at zero. So let's go ahead and create a variable. And we'll just say A is equal to, and let's do the all-popular hello world. Let's run this. And now when we print the string, we can say A and we're gonna do a bracket. And now we can search throughout our string using the index. So all you have to do is do a colon. We can say five. What this is gonna do is gonna say zero, position zero all the way up to five, which should give us the whole hello, I believe. Let's run this. And it's giving us the first five positions of this string. We can also get rid of the colon and just say something like five. And then when we run this, it's actually going to give us position five. So this is zero, one, two, three, four, and then five is the space. Let's do six so we can see the actual letter and that is our W. We can also use a negative when we're indexing through our string. So we could say negative three and it'll give us the L because it's negative one, two, and three. We can also specify a range if we don't want to use the default of zero. So before we did zero to five and it started at zero because that was our default but we could also do two to five. Let's run this. And now we go position zero, one, and then we start at two, L, L, O. Now we can also multiply strings and we have this A hello world. So we can do A times three. And if we run this, it'll give us hello world three times.  Now let's go down here and take a look at lists. Lists are really fantastic because they store multiple values. The string was stored as one value multiple characters but a list can store multiple separate values. So let's create our very first list. We'll say list really quickly. And then we'll put a bracket and a bracket means this is going to be a list. There are other ones like a squiggly bracket and a parentheses. These denote that they are different types of data types. The bracket is what makes a list a list. So to keep it super simple, we'll say one, two, three and we'll run this. And now we have a list that has three separate values in it. The comment in our list denotes that they are separate values and a list is indexed just like a string is indexed. So position zero is this one, position one is the two and position two is the three. Now when we made this list we didn't have to use any quotes because these are numbers but if we wanted to create a list and we wanted to add string values we have to do it with our quotes. So we'll say quote cookie dough and then we'll do a comment to separate the value and then we'll say strawberry and then we'll do one more and this will just be chocolate. And when we run this we have all three of these values stored in our list. Now one of the best things about lists is you can have any data type within them. They don't just have to be numbers or strings you can basically put anything you want in there. So let's create a new list and let's say vanilla and then we'll do three and then we'll add a list within a list and we'll say scoops comma spoon and then we'll get out of that list and then we'll add another value of true for Boolean. And now we can hit shift enter and we just created a list with several different data types within one list. Now let's take this one list right here with all of our different ice cream flavors. We'll say ice underscore cream is equal to this list. Now one thing that's really great about lists is that they are changeable. That means we can change the data in here we can also add and remove items from the list after we've already created it. So let's go and take ice cream and we'll say ice cream dot append and this is gonna do append it to the very end of the list. We'll do an open parentheses and let's say salted caramel. Now when we run this and we call it just like this it's gonna take this list add salted caramel to the end and we'll print it off and as you can see it was added to the list and just like I said before, let me go down here we can also change things from this list. So let's say ice cream and then we need to look at the indexed position. So we're gonna say zero and that's gonna be this cookie dough right here. We can say that is equal to so we can now change that value. So let's call that butter pecan and now when we call it we can now see that the cookie dough was changed to butter pecan. Another thing that you saw just a little bit ago is something called a list within a list basically a nested list. So we had scoops spoon true. Let's give this and we'll say nested underscore list is equal to. Now when we run this we now have this nested list. So if we look at the index and we say zero we'll get vanilla. If we say two we'll get scoops and spoons. Now since we have a list within a list we can also look at the index of that nested list. So let's now say one and that should give us just spoon and you can go on and on and on with this. You can do lists within lists within lists and all of them will have indexing that you can call. Now let's go down here and start taking a look at tuples. So a list and a tuple are actually quite similar but the biggest difference between a list and a tuple is that a tuple is something called immutable. It means it cannot be modified or changed after it's created. Let's go right up here. We're gonna say tuple and let's write our very first tuple. So we'll say tuple underscore scoops is equal to and then we'll do an open parentheses. Now these open parentheses you've seen if you do like a print statement but that's different because that's executing a function. This is actually creating a tuple which is gonna store data for us. So we'll say one, two, three, two and one. Let's go ahead and create that tuple and we can just check the data type really quickly and it's a tuple. And just like we saw before, a tuple is also indexed. So if we go at the very first position which is a one we will get the output of a one but we can't do something like append and then add a value like three. If we do that it's gonna say tuple object has no attribute append. It's just because you cannot change or add anything to a tuple just like we were talking about before. Typically people will use tuples for when data is never going to change. An example for this might be something like a city name, a country, a location, something that won't change. They definitely have their use cases but I don't think they're as popular as just using a list. So now let's scroll down and start taking a look at sets but really quickly let me add a few more cells for us and let's say sets. Now a set is somewhat similar to a list and a tuple but they are a little bit different in fact that they don't have any duplicate elements. Another big difference is that the values within a set cannot be accessed using an index because it doesn't have an index because it's actually unordered. We can still loop through the items in a set with something like a for loop but we can't access it using the bracket and then accessing its index point. So let's go ahead and create our very first set. So we're gonna say daily underscore pints. Then we're gonna say equal to, and to create a set we're gonna use these squiggly brackets. I don't know if there's an actual name for those if I'm being honest. I call them squiggly brackets and that's what we're gonna go with. We're gonna put in a one, a two, and a three. So let's go ahead and run this and let's look at the type and as you can see it is a set. Now when we print this out it's gonna show us one, a two, and a three and those are all the values within our set but if we copy this and we'll say daily pints log this is gonna be every single day. Maybe I had different values. Now when we run this and we do the exact same thing now when we print this it's gonna have just the unique values within that set. Now a use case for set and this is something that I've done in the past is comparing two separate sets. Maybe you have a list or a tuple and you convert that into a set and that will narrow it down to its unique values and then you can compare the unique values of one set to the unique values in another set and then we can see what's the same and what's different. So let's go down here and let's say wife's underscore daily and I'll just copy this right here. We'll say is equal to let's do our squiggly lines. Let's do one, two, let's do just random numbers. So now this is my daily log and this is my wife's daily log and now we can compare these values. So let's go right down here. Let's say print, we'll do my daily logs and then we'll do this bar right here and this is gonna show us the combined unique values. It's basically like putting them all in one set and then trimming it down to just the unique values. So we'll take wife's daily pints log and when we run this, we actually need to run this first. When we run this, we should see all the unique values between these two sets. And so as you can see, zero, one, two, three, four, five, six, seven, 24, 31. So these are all the unique values between these two sets. We can also do another one. And instead of this bar, we're gonna do this symbol right here, which I believe is called an ampersand. Don't quote me on that. But when we run this, it's gonna show what matches. That means which ones show up in both sets. So the only ones that show up in both sets are one, two, three and five. We can also do the opposite of that by doing a minus sign. And this is gonna show us what doesn't match. So we have four, six and 31. Now where is our 24 that was in our wife's daily pints log? It's in this one, but we're subtracting the values on this one. So let's reverse this and we'll say daily pints log and let's run it. Now those are our other values. So we're taking the values of this and then we're subtracting all the ones that are the same and getting the remaining values. And then for our last one, we can get rid of this and we'll do this symbol right here. And this is gonna show if a value is either in one or the other, but not in both. So let's run this. So these values are completely unique only to each of those sets. Now the very last one that we are gonna look at in this video is dictionaries. So let's go right down here. Let's add a few cells and let's say dictionaries. Now I saved dictionary for last because this one is probably the most different out of all the previous data types that we've looked at. Within a data type, we have something called a key value pair. That means when we use a dictionary, it's not like a list where you just have a value, comma, value, comma, value. We have a key that indicates what that value is attributed to. So let's write out a dictionary to see how this looks. So we're gonna say dictionary underscore cream. And just like a set, we use a squiggly line. But the thing that differentiates it is that in a dictionary, we'll have that key value pair. Whereas in a set, each value is just separated by a comma. So let's write name and this is our key. And then we do a colon and this is then where we input our value. So we're gonna say Alex Freeberg. And then we separate that key value pair by a comma and now we can do another key value pair. So we'll say weekly intake and a colon and we'll say five pints of ice cream, the comma and then we'll do favorite ice creams. And now what we're gonna do is we're gonna put in here a list. So within this dictionary, we can also add a list. We'll do MCC from Mint Chocolate Chip and then we'll add chocolate, another one of my favorites. So now we have our very first dictionary. Let's copy this and run it. And let's just look at the type. And as you can see, it says that this is a dictionary. Let's also print it out. Now if we want to, we can take our dictionary cream and say dot values with an open parentheses. When we execute this, we'll see all of the values within this dictionary. So here's our values of Alex Freeberg, five Mint Chocolate Chip and chocolate. We can also say keys. And when we run this, all of the keys, the name, weekly intake and favorite ice creams. And we can also say items. So this key value pair is one item and this key value pair is another item. Now, one difference between something like a list and a dictionary is how you call the index. But you can't call it by doing something like this where you just do a bracket and say zero. So this would in theory, take this very first one, right? Our very first key value pair. That's gonna give us an error. How you call a dictionary is actually by the key. So it doesn't technically have an index, but you can specify what you wanna call and take it out. So we're gonna say name. And this is gonna call that key right here. And when we run this, we'll get the value, which is Alex Freeberg. One other thing that you can do is you can also update information in a dictionary, which we can't with some other data types. So for this, for the name, it was Alex Freeberg. Now let's say, Christine Freeberg. And when we update that, I'm also going to print the dictionary, get rid of this. So it's gonna update Christine Freeberg in that value of the name. So let's go ahead and run this. And now it changed the name from Alex Freeberg to Christine Freeberg. We can also update all of these values at one time. So let's copy this. And I'm gonna put it right down here. I'm gonna say dictionary.cream.update. Then we're gonna put a bracket or not a bracket, but a parentheses around these. So now what we're gonna do is update this entire thing. Let me take this, say print this dictionary. Now we can update this to anything we want. So instead of here, I can say, I'll say wait. And because of all that ice cream, I now weigh 300 pounds. So let's run this. And as you can see, it did not delete our key value pair right here. Instead it just added to it. When you're using the update, we can't actually delete. That's the delete statement and I'll show you that in just a second. But all we did was added this new value. It also was gonna check and see if you changed anything with your key value pair. So we can go in here and change this value and we'll say 10. So now when we run this, the value of this key value pair was changed. But let's say we do wanna delete it. We'll say DEL, that stands for delete. Part of this dictionary cream. And now let's specify the key which will also delete the value with it. Well, let's specify the key that we wanna get rid of and let's say wait. And then let's print that again. And as you can see, the wait was deleted from that dictionary. So that is all we're gonna cover in this data types video. Thank you guys so much for watching. I really appreciate it. If you liked this video, be sure to like and subscribe below and I'll see you in the next video.


fel ydych chi'r rhaglenau yn dweud ymwyllfa newydd yn fawr. Mae ydych yn fawr ffa o'r gyda'r newydd. Mae hwn yn fawr yn holyda i gael gyda'r newydd. Mae wedi ydych yn gweithio ymdweith ym Mwgol Cysolwyr, ac mae'n rhai oherwydd yng Nghaerthau. Felly mae'n gweithio'r cyfnodau, mae'n gweithio'r cyfnodau, lle mae'n gweithio'r cyfnodau. Mae'r iawn wedi bod ni'n gweld yn byw'n gweld yn gwybod maen nhw ymwn i ddiogelor. Rwy'n meddwl i'n ddarn wahanol lleol, oes yn ymddir yng Nghymru, mae'n meddwl i'r parwg i'r hoffi'n gwirionedd, a'r hoffi'n fath o'r hoffi, bod yn ddechrau. Yn ddiddordeb, yna lleol yn gwybr. Mae'n ddiddordeb ar hoffi, rydw i'n ddim yn gen i fod y lemur hyn nhw, i ddim yn ddiddordeb. But the thing that we need to think about is speed. So, there's a great article. Who knows what this is? That's correct. It's the save icon from Microsoft Office. It used to be a physical object, but you don't see them any more particularly. This article from a guy called Pete Davis, and he asks how many floppy disks a modern article on the Atlantic takes. If you were to download it and put on some floppy disks and pass it around to your friends. So, it was this article about dinosaurs, which is awesome, because dinosaurs are awesome, as my toddlers tell me. So, how big, if you were to take the four pretty large images, stick them in an RTF file with the text of the 6,000-word article, how big would you say that is? Any guesses? Sorry? Actually, only 400K, and most of that's images. So, the text is about, I don't know, 37K worth of just, you know, ASCII text. Fits on a floppy disk with space to spare. If you were to download this over the internet, on the Atlantic website, a modern publication, that's how big it is. We're on the extreme end here. A lot of that stuff is video ads and stuff. When I visited with an ad blocker, it was only about 3Meg. So, that's sort of nuts. It's this many floppy disks. That was a productive half an hour on the internet, by the way. Anybody recognize any of those, still got them in their loft? My particular day of the tentacle. Absolute classic. There's a small coder, of course. This article, by Pete, was published on Medium. Oh, well. So, at this point, I'd like to apologise that despite my keynote foo, it doesn't have like a ddiddledoo, ddiddledoo, Wayne's World style take us back into history animation. So, this is what we have. Let me take you back to 2010. The impossible chasm of the Rails 2-3 migration. Ruby 1.92. People were walking around with iPhone 4Ss, like giant-handed savages. In those five years, Marvel and Disney have built an entire cinematic universe. Bigger, bigger, bigger. More characters per film, even larger giant ships crashing into even larger things, buildings, planets. As web developers and designers, we've been doing the same thing. This is the growth of web pages from archive.org, which takes a snapshot of the web as much as it possibly can. You can see here, JavaScript has exploded over the last five years. This is my frowning face. You can also see the rise of web fonts on the top there in the last couple of years. However, even this ballooning JavaScript framework fonti nonsense pales into insignificance next to images. A great deal of our pages are images. As Ruby is, this sits in that weird halfway world between us and the front-end guys, or if you are someone who does the front-end as well, that is your problem. Our pages have got three and a half times bigger in five years. That's bonkers. The average page is two megabytes big, the average page. Thankfully, now that we live in the future, this is no longer a problem. That is true to a certain point of view. We have a regulator in the UK for broadband, and we've gone from five megabit to just over 20 megabit in those same five years. You're like, okay, pages are three and a half times bigger, and we've got 4G now, so everything's cool. Obviously, high speeds all around, as we all know from our experiences, is not the whole story. Only a third of connections in the UK are high speed, and even amongst those at peak times, only 10% of people are actually seeing the speed they're paying for. This is why Netflix doesn't work in my house on a Friday. Smartphone connections have also increased from 20% of the market to 60%. Basically, as we've been making pages three and a half times bigger, our networks have got nearly the same faster, but everything is a lot more shambolic in terms of the network connections. Things are harder. Everyone's used a phone and gone, why isn't this gone on website loading? Well done, everybody. We've done a really brilliant job. There are countless examples of speed being a good proxy for how customers work with your service. Famously, Amazon are able to financially measure the differences in page load time in the size of the carts that people are paying for. I've personally seen similar things at House Trip. We make pages faster, users get further down towards buying their holidays. It's actually helpful for people. All this talk of cash, however, is slightly unseamly for a Ruby conference. What if it's just about doing the right thing? There was a guy called Chris who was in a meeting at YouTube listening to his senior engineer rant as senior engineers all want to do. He thought he'd have a go at getting a 1.3 megabyte YouTube video page under 100K. He called this project feather and took a few days. Getting down to 250K was easy. He dug into the code. He began to optimise the HTML, the CSS, the JavaScript. After three painstaking days, he was still not under the 100K limit. Pleasingly, he'd also just built the HTML5 video player. He dropped that into the page in favour of the enormous flash monstrosity that they had before. Boom! 98K, only 14 requests. He added some basic monitoring because it's Google. He launched the opt-in to a fraction of Google's traffic. They collected some data and the numbers came back. They were completely baffling. The average aggregate time to video view under feather had increased. Not just increased the tiny bit, increased a lot. The total page rate is a tenth of what it was. Somehow the numbers were showing that it was taking longer for people to get to viewing the videos. Nothing made sense. Cats and dogs living together mass hysteria. He was about to give up on the project when his colleague discovered the answer. Geography. When they plotted the data geographically, there was a disproportionate increase from places in South East Asia, South America, Africa, even Siberia. Even now, the average load time under this feather page was over two minutes. This meant that the regular video page at one point Something Meg was taking more than 20 minutes to load. So entire massive populations of people had just simply not been able to use YouTube because it took too long. So despite the two-minute load time of this feather project, watching a video actually became a real possibility for people. Large numbers of people who were unable to use the service were suddenly able to. So all these stories are well and good, Andrew. But what can we do? So that's it. Thank you very much. There's various things we can do. We can test things properly. Good start. Test things on actual devices. Also good. So this is an example of a programme at Facebook where they're trying to think about the privilege they have as Facebook developers, but only in terms of their internet connection. On Tuesdays at Facebook now, they have a ball across the top of the Facebook website that says, do you want to experience this page as if you were on a 2G connection?  When we are developing, typically, we are wired in, we have nice shiny internet connections, we have high speed. We're not thinking about users who don't have connections as good as we have. So we're going to do some responsive imagery code here. I used to be a front-end guy. I still do a bit. Inevitably, I'm the guy who gets the CSS on an existing Rails project. Do not be scared.  There will not be a test. So this is new syntax. Some of you may be familiar with it. It just looks like a normal image tag. You'll notice there's a source set attribute. This acts as a suggestion to the browser that if you have a high resolution screen, a high resolution version of these images. This is a suggestion for the browser. It's not a compulsion for the browser to load these things, but it stops us doing that crazy thing where you serve a two-times image and then just box it in using the width and height. The best thing about HTML, of course, is that if a browser, and in this case, old IE, not new fancy IE from Windows 10, but old IE just ignores the old stuff, you might have heard your friendly local CSS nerd use the term progressive enhancement and this is an example of that. So getting a little bit more complicated here. So via source set here, you can see the browser knows the resources. So it says if the size of the image there, the poster, is 600 browser pixels wide, load the 600 version of the JPEG. If it's 1200 pixels wide, load the 1200 version. The sizes attribute provides the width of the image at a given window width. So it's like a CSS media query. So in this case, it says if the screen has a minimum width of 640, it's going to take up 60% of the viewport width. That's what the VW stands for. And otherwise, it's going to take up the whole width. So on smaller devices, this image is going to take up the whole width. And then the browser can interpret this stuff to find the right images. And as you can see, only bad old IE doesn't understand this. But even then, it drops back to the source on the image tag. So this is where we're starting to get a little bit crazy. Do not try and read this. Do not note this down. This allows you to provide alternative sources. So in the world of responsive web design, when you change the browser and there's a drastic change in page layout, so you can provide, say, a portrait image at certain sizes using the source tags inside a picture tag. This is supported well in everything except for Safari. There are, like, JavaScript picture fills and stuff like that. But this stuff is coming into browsers now. You can also serve multiple formats as well. So, for example, Chrome out on their own support an image type called WebP, which is a very well-compressed image. And you can just provide a mind type and then provide an alternative inside a picture tag as well. So this works in Chrome, Firefox, Opera, and falls back. And again, falls back to the image in other browsers. This is all non-destructive enhancement for your users. If you really want to blow your mind and have a little cry at work one time, you can read this article on the Opera website. The fact is, we are going to need to start providing a lot of appropriately sized imagery if we want fast pages. So this, I'm pretty sure everybody has this in one of their Rails apps. This is genuine code from House Trip. I apologise. This is paperclip. This is how you specify an attachment on a model. And to be honest, I've actually tidied this up and taken a couple of bits out because it wouldn't fit on the slide. I'm pretty sure everybody's seen this. Show of hands for anyone who doesn't have something or has seen something like this. Good. Blank faces everywhere. Yeah. So get to the point. This is all about serving images at sizes and not having to go through that step that you do with things like paperclip and carrier wave where you upload them and then you preprepare lots and lots of different sizes of images. That basis, that basis you that you know what's coming down the line, what design changes you're going to have, what image dimensions you're going to need in the future. So at House Trip, I took on a sort of little side project. Bearing in mind the code from the previous project, every time we add a new image, you know, House Trip is a, it's a holiday website. It's lots of pictures of people's houses and flats and villas. Every time we add an image size, a new image size, we have to generate all of those images, which obviously makes our architecture cry because when you're shopping for a holiday, you're mostly looking at images. So I had these constraints. We have these original large images already available on S3. We know where they are. We don't do anything funky with resizing. We just resize and crop and expect the image to fill the size of image that we've built. We serve everything from a CDN because we're not crazy. And for me, I wanted to see if it would be a small enough service to deploy on Heroka and this is the less code track, so good thinking crawl. And also, we didn't want to like do any big bang launches. We didn't want to switch it off and then switch on the brand new image thing and have it all fall over. So being a sensible thinking small, I grabbed hold of Sinatra and I also grabbed hold of Dragonfly, which is a simple wrapper, it's a very nice, well-written wrapper around the Unix command line craziness of image magic. Image magic, you might remember, is the thing that constantly causes your app to fail to compile and cause deployment problems between the years of 2010 and 2012, as far as I can remember. A logo for image magic, that little wizard. God bless. So it's really simple code. It's three gems. One of them is only because I wanted to get a multi-threaded web server on Heroku. Inside your app, you take, you configure Dragonfly, very simple, nice syntax there. I'm the kind of nerd who thinks in URLs. This is basically the simplest API to this service that I could think of. Those little bits at the beginning are mostly the same as the constraints of the images, a geometry string in image magic terms. That first one is a fixed width of 400. So resize the image to 400 wide and then whatever keeps it in proportion height-wise. The next one is fixed height and keep the width in proportion. The last one, not exactly true, is fixed both. So you basically resize the image to 400 by 300 and fill as much of that space with the images you can. So I built a little utility class inside my Sinatra app that basically checks that that string is valid and then adds the little hash on the end to make it understandable by image magic. And one single root. So checks for the validity of the size geometry string. Then it takes all of the params from the rest of the string and presumes that is where you go and get the original image over HTTP. Then you resize it and then you turn it back into a response that RAC understands. So pretty straightforward code. However, now we get into the architecture of how I'm putting this together. So simply put, we're letting the internet take the strain in a way that we all do pretty much already and getting this logic away from the application. These are just the services that I chose to use. We already had images on S3. We were already using Heroku. Other CDNs are available. This is my super simple. Can I build a small version of this architecture? So you add your devices browsing the modern internet. The devices make a call to the CDN. It calls the Sinatra app. The Sinatra app runs off and gets the S3 image, takes it in, transforms it, serves it back to the CDN and then the CDN serves it back to the device. And then subsequent calls for that URL. Obviously, it's a CDN. It only hits the cache there. I put it live on GitHub. No stars. No, two stars. Sweet. There's somebody giving me a slow hand clap there. That's very good. So how does it perform? So you basically just grab any old images from the internet. I'm so excited about Star Wars. In this case, this image is about, it's a photographic image from a trailer. 1.1 megabytes, about 2,000 pixels wide. It's a decent size of image. It's fairly typical to what we were using at House Trip for the uploaded images. So in order to test this, I take my lovely sexy architecture and explode some of it. You put the image directly onto S3. Anyone know what this is? Any guesses? This is an Apache bench, which is a command line utility which you can use to basically hammer your website. It's a great little tool. It's fairly unsophisticated. It comes with the standard Apache distribution. So basically, if you have a Unix-based laptop, you have this command line program. Hammers are not sophisticated. So let me prefix all of my testing with that. So this URL basically says, do 1,000 requests with a concurrency of 20. So do 20 at a time. So basically, I'm trying to hammer my Heroku app without the CDN to see how it performs. Say you've got a whole bunch of new images happening. Just hammer that app and see how it behaves. If your Wi-Fi was slow when you arrived at the hotel yesterday, that was probably me. So this is the stats for taking that original 1 meg image and doing a 500 pixel-wide version and a 1,000 pixel-wide version. So roughly a third the size and 2 thirds the size. Watching the logs as this was happening, there was quite a large variation in the time it was taken. But even as I expanded out, I did a couple of tests where I did even more requests or shorter requests, but the average time to do this was about the same. Even as I added more workers to the larger dino sizes. These different graphs are the various different sizes of dinos you can pay for on Heroku. We can see here that actually, on Heroku at least, there's not seem to be much of an advantage to the more expensive stuff. It's possible I'm doing something wrong here. You should probably ask the Heroku guys if I am. I certainly will be. But certainly at the lower end, the free, the hobby, and the one-times dinos are all basically the same machine.  So I did notice, as I was doing some testing yesterday, that I did some more tests last night when I've been doing some testing in the afternoon, and the times were different, but between the different dino sizes about the same. So like depending on how much you're sharing your resources, it made a difference. But the main point is that these response times are feasible as response times. Well, they're not brilliant, but they're not sort of like, oh my god, it's going to take forever to transform these images as I do them. So the benefits of using the right size images for the end user in terms of file size are really not bad at all. So rather than serving an original image and letting the browser shrink it down, if you serve the appropriately sized image, you know, you can save, you know, all images 10% the size. It makes sense. So not bad, not bad at all. One of the benefits, however, of the human eye is its fallibility. It's the reason we have JPEG compression, that sort of stuff. We can do better. Well, actually, somebody else can do better and I can copy them. So a much more intelligent man than I, Dave Newton, spent a lot of time learning how image magic works. And these settings, simply typed into your command line program, give us much, much better compression than the standard image magic resize. How much better than these? A lot better. 15% the size of the original naive resize implementation, which is huge. So I reran my benchmarks again. And it looks like, obviously, that some time elapses when you're doing 1,000 image requests over hotel Wi-Fi. It looks like it takes about two to two and a half times the length to do the more detailed compression for the saving of 85% of the file size at the end of the day. The other thing I did notice when I was doing the benchmarking is that there's a lot more variation on the image resizing times. So some of them are really slow, really slow. Some of them are very fast. They all produce exactly the same file. So it's completely repeatable.  But equally again, you can see, I think what you're actually seeing in those graphs is the progression of time into the evening, which is why it's going up over the free hobby one times and two times dinos. But it actually seems to be that the resize doesn't really matter about the size of image either. That seems to matter less. So you tend to get more predictable average performance. So does the slower performance matter if you're getting the image sizes down? I guess the answer is yes and no. No because we're using a CDN in the final solution. And that gives us protection against this and the file size benefits are then available to everybody. And they're brilliant. Also no because you can always prepare your CDN. You can run a script that runs all of these things and caches lots of the images before like users eventually hitting them. So you don't accidentally start a denial of service on your own image server. However, when I passed another completely random image from the internet that I'm not at all excited about to the image server put on S3 and try to run it, it made everything fall over. So this image is 6 meg, it's 3,500 pixels wide by 1.4 which is getting to where we are in some of our photography for House Trip. It just made everything fall over, even the powerful performance dinos. So at this point I'm thinking I could throw more powerful CPUs at this problem, I could set up like a graphics Amazon AWS EC2 instance. But whilst that's an interesting exploration for the guy preparing his talk in real life there are already solutions to some of this. So Refile is from Jonas Nicholas, the author of Carrier Wave. It's pretty similar in concept. It's just got the benefit of 5 years of learnings of writing on Carrier Wave and building that out. It's broadly very similar when you throw it in your Rails app your Ruby app and it operates in very the same way. It kind of winds its tendrils deep into your active record models, bad idea in general. Atashe is from a buddy of mine in Singapore Chinkeyat. And behaves a lot more like the solution that I built very simply. It's a lot more fully featured. It does uploads, which I completely threw away for this particular experiment. It's got a really nice API. He's super keen to see if he can build an open source alternative to these third party services. So all of these are pretty decent. They're all pretty relatively super expensive. If you're starting a green field project and you're thinking about images, use one of these.  They're pretty reasonably priced for anyone who's actually, you know, trying to run a business. You know, Cloud News has got a, particularly it's got a good free plan as well. So in summary, be fast. You know, limit your assets, deliver what is needed to the browser and make it as small as it can be. And, you know, think about what your app actually needs to know about. Like this is one approach to microservices that, you know, doesn't involve queues and stuff like that. It's just utilising the internet for things that the internet actually is quite good at. You know, if I was to speak more broadly than just images, you know, speeds of feature through any software you build. You know, and we are talking speed over the network as much as, you know, speed of your actual code on any machine. And you need to think about your user's devices. And with that, thank you very much. Any questions that I must remember to repeat when you ask them? Am I using the code live? No, is the answer. I think the benchmarking that I did as part of this proved that we'd have to have a slightly more robust solution than my initial, you know, 100 lines of code. It's an interesting thought project and certainly something we're thinking about in terms of maybe breaking out into a slightly more sophisticated app rather than the very simple thing that I built. My recommendations for caching and CDNs do it. Don't serve assets from your Rails app. That's crazy talk. Particularly from platforms as a service like Heroku, it's not so great. Most decent caching stuff, say Cloudflare or even Cloudfront from Amazon, let you expire things on a fairly granular basis. So that's not the problem that it was. So basically my suggestion is just cache for as long as you possibly can. Most of the CDNs are pretty good at providing the correct headers to the browser so that the local browser caches them as well. But yeah, basically do it. Don't serve images from your app. Cheers. Thank you very much.


This incident that just happened between two Chinese tourists and their South Korean Airbnb host is going viral right now because it kind of perpetuates the negative stereotype that mainland Chinese tourists are the worst. Oh my gosh, man. I can't believe this turned into such an international incident. Perhaps it is more complicated. Once we look at the internals, but I must say immediately a first look, it does not look good for the Chinese. Yeah. We're going to go through the multitude of comments on this guy. So, uh, yeah, again, why, why would I care so much about this? Well, guess what? It leads to a larger idea and it's a proxy for something else. So please hit that like button. Check out other episodes of the hot pop boys. Long story short, Andrew, there's a couple from mainland China. They want to take a vacation to Seoul, Korea for a month. They book a spot, but right after they book it and they're flying over, they realize that they feel like the host misrepresented how close that spot was to the city core. Like basically maybe they thought it was like 10 minutes out, but it's like 40 minutes out. So then they asked for a refund. The guys look, no, I cannot give you a refund.  Right? I'm going to turn on all the lights and all the water and then leave. And then they racked up a $1,500 bill that the host had to foot. Of course, it got crazy. They were like, oh, yeah, we're going to report it to Chinese embassy. Once they started arguing. And then of course the internet piled on Andrew, this side came in saying, oh man, I've been screwed by Airbnb host before.  I'm on the Korean side. And it just turned into a bigger thing than you would possibly think it should be. Yeah, let's get into the comment section. Somebody said Airbnb ain't even worth it no more in 2023, man. Just book hotels, man. Everybody's going to war with each other. Litigation, all these fees and cleaning fees. What the F? No, at least hotels, you can argue with someone at corporate or they have like customer service people who are dedicated to dealing with these issues. Because sometimes Airbnb hosts, you're dealing with one other person and they might be nice or they might not be. And it's not and it's within the contract. You got to read the fine print. Somebody said, yeah, man, being a landlord just comes with risks guys. And sometimes landlords themselves are deceitful when they list their own properties Andrew, we've actually been victim to this before. By the way, I am not saying I would ever do what the Chinese couple did. I'm just saying initially it is true that sometimes people misrepresent how close their thing, how convenient their locations are. No, I mean, I think leaving the water on for a month straight is crazy. I mean, that's like, that's pretty bad. It's wasteful. But I've heard a lot of stories from people who weren't Chinese and about hosts who weren't Korean and, you know, people of all different colors, leaving Airbnb's in a big mess and everybody getting mad. So it definitely does happen to everybody. Somebody did say, one opportunist meets another, ha, greed clashes with pettiness. Somebody said, yeah, I like their revenge style because they tried to get screwed early and then they screwed them back.   And this sort of goes along with this narrative right now, Andrew, that Chinese mainland people, I'm not saying it's true, but I'm just saying there's a stereotype right now. But there might be some truth to it that they don't care about the environment. Yeah. And this is seen in a lot of different ways. And by the way, when we're talking about mainland Chinese, we're not talking about all mainland Chinese. We're just talking about a certain group. So it's kind of hard to stick with people, though. You're talking about a certain group. Yeah. It seems like it's been seared into the consciousness. I mean, is it the same group where two Chinese international students buy like six dishes at a restaurant and then eat like 25% of each dish and then leave the rest of it? Or is it more of the same people who don't really like to line up in lines? You know, when they're going on tours in different countries. Oh, yeah, is this a sacred starfish in Thailand? I like it. Yeah. Or when they go to Europe, they're kind of acting rude, not necessarily doing violent and illegal things, but definitely doing things that are breaking the decorum of the environment. Certainly not cooth fully, but I would gladly take their travel money. You know, things that were like Taiwanese people would go. No, no, no, Taiwanese people don't do that. They don't do any of that. Taiwanese, we're from Taiwan. No. No, for sure. I mean, there are incidents that really show that there is some pattern. Obviously, it's not all Chinese tourists, not even a majority, but that slice that's getting out there to the world. And apparently people people really, really don't like that group. Yeah, I do think David, would you say it's like, how do we describe the class? Like oftentimes it's people who just got money and they don't. And they were like, maybe like farmers in a village, they got money. So they don't really like what they're saying in China called to how to how was like potato fortune, right? Basically, people who are potato farmers, maybe the government needed to take their land for a project or reclaim it and they got paid out just, you know, and maybe not to become super rich, but like enough to travel. Let's just say this. I don't think that they're bad people. I just don't think that manners is the first thing on their mind. And of course, that led to the negative Chinese comment section. And we got to get to, yeah, that is. Oh, yeah, I can't do the Chinese action. Someone was like, yeah, that is just Chinese being Chinese.  Oh my gosh. See, look, everybody says that we are racist for not liking the Chinese. But look again and again, we have all these incidents to prove that our feelings are correct. You know what I wish? What if this news story, instead of saying Chinese tourists and South Korean, because now it's like a national geopolitical thing? Right, it's turned into a proxy war for like everything. Because these two people are no longer individuals. They represent the countries that they're from. But in the mannerisms of 100 percent of the people. Yeah, what if it was just the names were Ludi versus Park Soo Jung, you know, but like then they're individuals and then maybe it's not as racial and nationalistic, I don't know. But other people chimed in, they weren't Korean.  Japanese are the best. I noticed it when I was in Europe. OK, I do agree. I think Japanese tourists are the best. All right, but but but what if they were going by who bought the most Louis bags to stimulate the French economy by foreign capital inflows? Then it would go to those terrible Chinese tourists that they're referring to.  Oh, some of the years behaving at the Louvre. And that's a great point because it's like I think a lot of department stores and a lot of Airbnb hosts and business owners are like, dang, the Chinese are bringing in so much money and they're such good customers.  So I don't know how to feel about them because they're pissing me off or they're paying me. Well, what a conundrum.  And I think Koreans feel it, too, because obviously Korea is very trendy right now.  But like, why do they have to have no manners? And like, there's so many of them, but they like they buy a lot of things. So I don't know. Yeah, well, what we call this was a conundrum, a classical quandary, if you will. Somebody said, obviously, guys, this is the new stereotype or reputation that the new money tourists from China, mainland China have developed over the past what 10, 20 years, would you say? Yeah, I thought the stereotype was going down, but stories like this kind of reinforce it. But I do think it's getting better because I remember 10 years ago, there was some really bad stories of them mess like Chinese tourists messing with artifacts and like just doing really stupid, kind of like disrespectful things, I would say. Yeah. And I don't think they always knew what they were doing by like holding up the starfishes in the light that were supposed to be like left in the ocean and stuff like that, but are wearing the face keenies everywhere. But, you know, it's like a process for these people. And they were like working in the potato fields and now they got money to travel internationally. It's, you know, it's crazy to say, all right, let's get into our takeaways. Why do you think that this whole piece of news went so viral? Is it because essentially it was just super stereotypical? It was just super stereotypical, you know, South Korea, obviously, is like the good Asians right now in media, especially. And then obviously Chinese tourists always have a reputation to be honest. So I guess, yeah, just kind of fitting to it. But there's a lot of like different stereotypes of different Asian groups. I would say that new any time there's news, Andrew, from Asia, where like, for example, a Japanese guy marries a Vocaloid, does like a marries a waifu pillow or maybe denies a war crime. That's going to go viral, right? Because those are almost like stereotypical talking points that people say about the Japanese. Right. Yeah. Or when the Japanese fans at the World Cup are super polite, that also fits the stereotype, but a good stereotype, right? That they're like unbelievably almost like Nintendo Wii lobby type behavior that you can't even imagine. Right. What about Koreans being like thinking they're the best Asians and like talking down on other Asians or talking about their soft power dominance, possibly some plastic surgery or anything that fits the K rage stereotype of maybe like going out super hard. Yeah, yeah, yeah. I mean, that that's definitely those are all like the the Korean stereotypes. And what we mean, Korean, I'm talking about like from Korea, right? Like Korea. If Chinese have really bad manners, if they're ruining Mother Earth, I think this particular case about Airbnb turning on the water and the lights, that was both because it was bad manners and technically ruining the earth. I would say another Chinese stereotype is like just studying to death. Like those that one video where that Chinese brother is crying because he couldn't teach his sister math problems. Or when that Chinese father or when that Chinese father like is crying in agony because the kid like got couldn't understand calculus, right? Or man, yeah, that is so Chinese, super Chinese man. Viet's maybe doing something in the streets, something gangster, maybe gambling. I don't know. I would think that that would go viral, right? Because people are like, yeah, that's what you guys do. Maybe the Philippines having some sort of color is colorism issue or some corruption in some sort of beauty pageant.  Yeah, I guess. What do you think right now? Like, Andrew, these are the things that are going viral in Asia. I guess in America, it would be like if people whitewash a show that was originally minority characters or people black or Latinized a show that was originally a white character. And then people have like an anti-anti-reverse like basically what I'm saying is there's just certain stories coming out of every country that on an international basis is going more viral because they fit the stereotype. Yeah, and I think for a lot of Chinese people, like if you're a mainland Chinese student or international student or tourist, right, it's like, do you have to act extra good to make up for the bad Chinese? You're saying if you're traveling out of mainland China and you are aware, I don't know if a lot of them are, it's difficult for them to act on it. That there's this overarching archetype. Do you got to try to reverse it on them? I mean, I don't think people do, to be honest. I mean, I would say I just think they're not the bad stereotypes, but they're not like trying to act Japanese. Do you put that responsibility on yourself? Some people do and some people don't depends on how their group is viewed.  And I'm like, yeah, I mean, I guess if that's the stereotype and you feel like that's your obligation or that's your duty to try to combat that, then that's that's a lot to carry though. And probably internally within a group, there's disagreements on how to handle societal archetypes that are thrust on you. And at the same time, it's not wrong to be like, well, that's not me. I don't care. I'm just going to be me. Why should I have to be defined by the worst people in my group? All right. Should Chinese be ashamed of this stereotype? Even though, of course, it's not even 50 percent of the population. It's just one pie slice. But apparently that one pie slice, that one layer of a seven layer cake is so like so obtuse that it really sticks with people. People just only think about that. There's a seven layer burrito and people are only thinking about one of the seven layers.  You think they're just like, yeah, that it was crazy. That Chinese group of Chinese tourists had like three Japanese people in it. Or like, yeah, I thought that group, I guess they must be Japanese influenced Chinese people. Oh, yeah, they were Taiwanese. I would say this, like to me, one thing I noticed is that, like, as far as like internally within the Chinese world, only the middle class to upper middle class people care about how they're perceived. Because think about it, if you're poor, you're almost in survival mode.  And if you're rich, you almost have so much wealth and like ability to like shape shift with like liquidity, your world and like the spaces you're in, like, of course, everybody's going to be catering to you when you're in first class, right? But the middle class is more like interfacing, I guess, like having their experiences swayed by people's overarching images of the countries they come from or their heritage. Yeah, yeah, exactly. If you're really rich, you probably don't even care how your group is viewed. You just care how you're viewed.  Yeah, the average person is definitely defined more by the worst group of people or like the worst acting, I guess, a group of people. So I guess I don't know. I mean, it's very interesting. I don't I think honestly, if you're Chinese and you know that there's so many Chinese people out there, you just know that it's almost like, man, I can't even feel bad about it because there's just it's just going to happen again. Yeah, honestly, I would say that if you really know what it's like to be Chinese, man, there's it's the biggest group on earth, right? Obviously, India is going to overtake it this year. But it's like there's so much variance. Like if you were to graph like income ranges and behavioral ranges on a plot chart, it would not look like very standardized. It would just be like all over the place. All right, everybody, we're going to wrap up right there. You let us know in the comments down below what you think about it because yet is the stereotype changing? Are Chinese stories getting better or should you just not worry about it because you're an individual and there's nothing you could do about the other millions of people out there? And do you think in this specific host versus customer Airbnb case, it was 50-50 or do you think it leaned more one way or the other? Actually, on the internet, Andrew, I was surprised to see it was actually kind of even. I thought everybody was going to support the South Korean host. Right. But I guess some so many people have had bad experiences with Airbnb hosts that swung it the other way to be 50-50. I don't know. Let us know in the comments down below what you guys think. Thank you. Thank you so much for watching. We are the hot pop boys. And until next time, we out.