Salaam. This is People's Dispatch and you're watching The Daily Debrief coming to you as always from our studios here in New Delhi with me, Siddhantani. On the show today we're looking at what the foreign ministers of the G7 grouping had to say at the end of their meeting in Nagano in Japan and of course how the rest of the world is receiving that communique. We also talk about what a second term for Miguel Diaz-Canel means for the people of Cuba. And finally, the WHO has launched a data repository, the first of its kind. We look at what this means, what kind of tools it holds and how it will empower policy makers in the public health sector. First up, the G7 in its communique at the conclusion of the meeting that I was mentioning of the foreign ministers in the city of Nagano which hosted the Winter Olympics of course once upon a time. In Japan, the Western dominated group called for, wait for it, the denuclearization of North Korea in a statement that many commentators are calling insubstantial. They also called out Russia and others while completely glossing over the fact that members of this very grouping need to be at the center of the global push for denuclearization. Anish joins us now via video chat for a further exploration of the latest in an ongoing absurdist drama. Anish, activists in the nuclear disarmament space have responded quite equivocally to the statement by the G7 foreign ministers calling it empty and not having any sort of concrete, any substance to it in terms of the parties that are actually holding the vast majority of nuclear weapons, nuclear warheads in the world today and also sort of the irony of this whole situation is that Hiroshima will host the G7 summit in about a month from now. What do you make of the statement North Korea being mentioned in it and the whole stand that the G7 has taken? Yeah, I think we can, yeah, that's a, it's an interesting situation right now because previously we never see in such interest by the G7, at least in the recent times on the North Korea's nuclear weapons, not because it wasn't often interest them, it was just that it wasn't something that they thought was necessary to have a communique. Now, in this case, we're not very sure what kind of messaging they're trying to say. Obviously, there have been some missile tests. Now, missile tests are not the same as a nuclear test. And so North Korea has not really violated any kind of, if you go by some of the statement made in that communique, where they alleged that North Korea has violated Security Council resolutions, it hasn't really done any of that sort in recent times that we can think of. Nevertheless, the statement is made and it targets very clearly the North Korean nuclear arsenal for basically no good reason. And so, and obviously there is that hypocrisy because considering the fact that then the head of states are going to meet in Hiroshima, the first ever nuclear bomb detonated site of that. And we will have the United States talking about, and its allies talking about smaller countries, smaller nuclear arsenal, while they uphold about thousands in their own kitty. It shows a certain hypocrisy. They actually used one of these weapons. Exactly. So all of these factors and the fact that the United States has recently not really worked towards actually completing the nuclear disarmament goals that it has set for itself and for the rest of the world as well. So there is no attempt to talk to say countries like Russia, France, UK, China, which are legally allowed according to international laws to hold nuclear weapons, or for that matter countries like India, Pakistan, and whether or not depending on which side you are Israel as well, to actually deal with that, to actually do away with nuclear weapons as a whole around the world. But obviously the specific targeting of North Korea is definitely showing us that there is an obvious, we also need to look at other parts of the communique where they're focusing a lot on the Indo-Pacific on China. So it is very clear that they're apart from Ukraine, obviously, it is very clear that they are trying to focus a lot more tensions in the East and Southeast Asian region. And that is definitely a sign, so to say, of G7 trying to maybe salvage its relevance in today's world, where some of these countries are not really that major economies to begin with. But all for that matter, it is trying to raise a certain kind of war or a war like rhetoric in a time when tensions are flying high in literal terms even in the region. So that is definitely a sort of disturbing development that we're looking at right now. Also a trend in so many ways, we've spoken about so many of these issues on Daily Debrief as well before, we've talked about the United States' own sort of take on upholding treaties that it has entered into and how it unilaterally decides to exit when the time is inconvenient or convenient for it. We've also talked about the statements made by South Korea's president ahead of the visit to the United States. And so the timing of it seems like this process of drumming up Cold War era narratives and bringing in all sorts of players into the situation. But essentially kind of creating this sense that there are lines. Yeah. Yeah. So it's going to be quite interesting. Well, interesting is the most mildest term to use. It's going to be something that we really need to watch out for because as I've said multiple times before and the risk of retreating myself, this is one of the regions which hasn't seen conflict or large scale conflict in decades in which for nearly more than half a century. And at this point in time, when you're trying to drum up Cold War rhetoric, not only against North Korea, but also China, it is going to be significantly problematic for everybody involved and not just, and when I'm saying everybody involved, it's basically the whole world at this point. So and we have to remember when we also need to talk about how with the whole talk about North Korean denuclearization, you need to remember the Korean peace process that was basically thrown under the bus because of the United States own sort of brinkmanship in the region. It included denuclearization as one of the aims of the whole peace process. And this was something that the two Koreas had decided on. So when something of that sort of achievement on itself, like something of this scale was completely disregarded because of US's own foreign policy problems and its gestures and statements and provocations in the Korean peninsula, it shows that the US's and its allies are not really that concerned about whether or not there is a dukey of free Korea or for that matter, peaceful Korea. But just the fact that they want to target North Korea at this point in time and use that as a proxy to target some of the countries that are not on, say, unfriendly terms with the North Korean government and its administration. So which is, which includes obviously China, Russia, but also other countries in the third world who still maintain a certain kind of relationship, which is just not neither friendly nor unfriendly. So it is sort of that, you know, a very pragmatic position and countries are being forced to take such unfragmatic positions. And as you said, lines are being drawn for no good reason when that shouldn't be the case. Many of the issues are quite, you know, something that countries can deal with themselves if they talk it out and use diplomacy. Exactly. And rather than giving space to that, interfering in such situations is definitely going to amplify what of the tensions we are seeing right now. And that is the most disturbing part at this point. I can't imagine that some of it is also not geared up to taking attention away from the recent stories of leaks and other things where so many of the US's G7 allies are very much a part of the story. All right, but thanks very much for that update, Anish, today and have a good weekend. Next up, Cuba's National Assembly voted in Miguel Díaz-Canel as president of the island nation for a second five year term, a decision that has been viewed in terms of maintaining stability and continuity in the face of a deep economic crisis. A crisis, of course, that's been fueled by decades of blockade and economic sanctions by the United States. The legislative body voted overwhelmingly in favor of a second term for Díaz-Canel. Zoe has more. She's been covering Cuba extensively. Zoe, what are the challenges ahead in terms of this second term for Miguel Díaz-Canel? Miguel Díaz-Canel was elected for second term as president on Wednesday, April 19th. He was elected by Cuba's National Assembly, which was in turn elected on March 26th in the legislative elections. He was elected alongside Salvador Valdez Meza, who was serving as vice president, and also the head of the leadership of the National Assembly was also elected this day. There are major challenges ahead for Miguel Díaz-Canel already in his first term, the first five years that he served as president. He had to face some of the most challenging years that Cuba has had to face. This includes both the intensification of the blockade under the Trump administration, looking, for example, the over 200 measures, the unilateral coercive measures that were imposed by Donald Trump, his administration during his presidency, the inclusion of Cuba on the state sponsors of terrorism lists, and both of the motivations or justifications for both of these moves, the increased unilateral coercive measures and the inclusion of Cuba on the state sponsors of terrorism lists, both of the reasons that the Trump administration gave for actually taking these actions have been proven to be not legitimate, have no base. But still, Diaz-Canel has had to face this moment in which already Cuba's limited ability to engage in financial transactions with foreign banks, not even banks in the United States, but banks in Europe, banks across the country, across the world, engaging in any of those transactions has become extremely difficult. Trade, any sort of cooperation, even medical cooperation, Cuba's ability to buy medicine, ability to buy food, all of this has been made more difficult with these measures that happened, of course, during the Trump administration. And then in 2020 is when the COVID-19 pandemic starts, which puts Cuba, again, in a very, very difficult situation. It's a country that relies a lot on tourism. And of course, in order to protect its population, Cuba closed its borders to the world for many months. They lost, of course, this revenue from tourism, which is again, one of the biggest external contributors to GDP. So a lot of lost income there. But Diaz-Canel has really taken on these challenges with an extremely a position that's of great commitment to the revolution of continuing Cuba's process. And I think that in the coming period, there's definitely going to be continued challenges, even though Joe Biden, who's from the Democratic Party, who was Obama's vice president, Obama, of course, historically, started to warm the relations between Cuba and the United States. And despite Biden having some promises of changing and reversing some of the Trump-era policies, all of these do remain in place. So these challenges continue for Diaz-Canel. And of course, Washington has also been very interested in intensifying political opposition and fomenting different groups into taking actions. There's been Diaz-Canel, of course, had to face the very challenging day of July 11th when people were on the streets upset, of course, because of the socioeconomic conditions that they're subjected to because of this blockade. But from there, of course, it's been the justification for Washington to impose and to have rhetoric about human rights in Cuba, about the silencing of protests of dissent. And so all of these factors have kind of come together in the last several years, not to mention the natural disasters that have hit Cuba, the different hurricanes, the fire at the Matanzas Supertanker Facility. These have been tremendous, tremendous challenges for Cuba, for the Cuban people, for the Cuban government, and of course with Miguel Diaz-Canel at the head of all these efforts. So it's likely that these challenges are going to continue. And it remains to see how the international pressures against the blockade against US policy against Cuba will play out. Will this actually cause force the US to change their approach towards Cuba? This will make it a lot easier for Cuba to survive and thrive. But it seems like that's going to be a lasting challenge. Right. And in continuation from there, what has been the policy direction so far for those who might be a little bit less informed on what's been going on in Cuba, that Diaz-Canel has taken. And are we likely to see him build on it? Or maybe are some changes necessary? So as I mentioned, there have been tremendous challenges for Cuba in the last several years. And in the five years that Miguel Diaz-Canel already served as president, many of these challenges remain. And so far, his, his orientation towards these tremendous difficulties facing Cuba has not been to shy away from the goals or the dreams of the revolution, which have to do with guaranteeing health care education, and the a good standard of life for the people. Miguel Diaz-Canel has not given up on these promises and of course has has even tried to bring the revolution and take it even further. So under his leadership, Cuba passed one of the most progressive codes on families that exist in the world, legalizing same sex marriage, redefining what it means to be a family, giving more rights to children, to elderly people, to disabled people. He's taken forward many, many important initiatives across the country, and across the world and in the region. So as Latin America has become every day more and more progressive with more progressive leaders being elected, Miguel Diaz-Canel in his leadership has been at the forefront of many of these regional initiatives, not only regarding these political issues of sovereignty regarding the United States, but also economic cooperation amongst the country's medical cooperation. Miguel Diaz-Canel has really insisted on the importance of medical cooperation with many countries after different disasters that have taken place over the past several years, including the COVID-19 pandemic, medical internationalism has remained at the forefront of the country's strategy to engage with the world. Also very important initiatives in addressing inflation on a regional level. So it we're likely to see continued and especially with the changes that have happened in the region, continued regional cooperation, being a priority under Miguel Diaz-Canel's leadership, continuing to deepen the revolution, expanding people's understanding of politics and their political rights, continuing Cuba's commitment to free and quality education and health care and a standard of life. The challenges continue. Cuba's in a very, very critical moment. But Diaz-Canel has showed that this is not a moment to abandon all of the promises that the country made and that the people have fought so long for and sacrificed for. Right. Thanks very much for that update. And finally the WHO launched yesterday, the Health Inequalities Data Repository. It's a global accessible repository, the largest of its kind and designed to equip a host of stakeholders in the public health sector, whether it's government or NGO, with information and tools to better tailor the delivery of vital programs and interventions. Basically, it aims to get policy design more streamlined, to be more locally effective, while also allowing for better informed decisions at the macro level. And Avrachar of the People's Health Movement has been looking at these developments or this repository, and has this to say about how it might work or might not. Anna, this is quite a major sort of data repository, nothing like it exists currently in the world. So plenty of potential, I would imagine. Yes, definitely. So this new repository of global health inequality data that the WHO launched. The idea behind it is to actually look at the data in a different way. So for now, you know, we get the data, but it's not, it's aggregated. So we don't usually have the breakdown into different elements. This is interesting, because it provides people, researchers, activists, and people who actually make the policies to look into how the health of specific populations is affected by some things in in the world. So for example, you know, it's, it's a very big repository. So it looks at different aspects, it looks looks at how COVID-19, for example, impacted mental health among people from different education backgrounds from different economic backgrounds. It also compares, you know, how, for example, maternal and infant health is going in different parts of the world, but also then broken down into income categories. And ideally, and it's a very, very ideally, it should mean that the governments that are thinking about improving their health policies can now look at this data and say, okay, so we have a major problem in this field, let's do something about that. We have the WHO has provided us with the technical guidance to do it. So, you know, ideally, we should be able to come up with targeted policies that can actually make a major difference in the lives of people. But then on the other hand, you know, we already know that this kind of thing, it's a bit of it gets messed up. So it's not in the past, also, it has been shown that data collection is essential. So we cannot work if we don't have access to data. But it it's not all about it, of course, then, you know, you do need the resources to actually sit down and to look at the data and say, okay, I have money to do this. If you don't have money to do this, then it's, it can get very frustrating. Also, I suppose one of the first challenges would be that yes, the WHO is providing the technical know how and how to do this. But much of the reporting as well as the company or the input of the data would come from the very same governments that are then using this tool, which, you know, across the spectrum of at least low and middle income countries presents all sorts of issues. Yeah. And I think that's a very good point, because you know, different countries report on different things. So if you look at the repository now, for example, you'll find data on well, actually, you'll find plenty of data from low and middle income countries, which are stepping up in the reporting and really making an effort. But then even if you look at some formally classified high income countries like Croatia, Croatia has reported on very few of those things, which the repository wants to address. So it's, it's still a process. And also it's something that I think that the WHO is counting on that it's something that's going to take time, that it's also going to take some pressure and some encouragement to countries to actually, you know, feed into this repository and make the most of it. So, so quickly, if we can, like, so if I, if I'm a country that is being asked to sign on to this database, and if I say, I already know what my specific health concerns are. And in fact, I, you know, so I don't need the rest of your data. I'm happy with what I have. How do you sort of respond to that sort of attitude if it all drops up? Well, I mean, it depends on what kind of data you already have. If you have the very elementary data, I think that now it's already understood, or at least shared, you know, shared approach that it's not, it doesn't address the specific problems that we want to address adequately. If you, I don't know, if you look at the impact of COVID-19 on a population, let's say you want to look at people who with high education, you also need to look at how it, if it impacted differently, men and women of this, this education background, you cannot just take one, one category and then say this, the solution that I make for this will cover all it won't. It actually makes it easier for you. It's not easier. It's it takes more time, but it's informed. Yes. And it makes more, it makes a greater impact, which is what we want to achieve at the end of the day. Thanks very much, Anna, for that. And we will, of course, see how that goes, but also speak to you soon for more updates probably next week until then have a good weekend. Thanks. All right, this was our last episode of the Daily DB for this week. We'll be back on Monday, but in the meantime, our website will be up and running, of course, and then we'll have updates and stories as always. We invite you to head there to check those out. It's peoplesdispatch.org. Also, don't forget to follow us on the social media platform of your choice. We'll be back on Monday. Until then, have a good weekend. Goodbye.


Did everybody get a program that would like one? Oh, shoot, what's that? There you go, there's another one. Can I have a program? All right, so we're going to start with time group. Let's get going, guys. Yeah, we're doing it in order. This is going to be the same group. So I just want to welcome you all here today. Thanks for braving the elements. So this has been our capital city rock camp for the week. And I think you're in for a real treat. I'll read to them the lyrics. So this first tune is an original that these guys wrote. It's kind of a genre of funk. So it was a whole process of writing the lyrics, like poetry, doing the changes, coming up with all the different components for the song. And could you just read to them really slowly the lyrics that you guys came up with? Sunshine on the flowers gave us the power. Come on, feel the light, more light by the hour. We're all feeling higher, go get what you desire. Springtime groove makes you move. Crank out the beat, feel all the heat. Here comes the worms crawling through the mud.  Let's break out, no need to pout, everybody, freak out. All right, also what's the name of your band, Molly? Molly and the Jets. Molly and the Jets. Let's give them a big hand. The instruments that I brought in, we do lots of listening to these artists. And a lot of these are, we're doing covers. They're cover tunes, right? So we're covering these artists. And while listening to standby, percussion instruments are a guiro. And what's that other one you're playing? Triangle. And a triangle. So Lucius will be doing them great just whenever you're ready, guys. Simba, I'm in my shoes. Oh, baby, baby, bring me some clothes. Thank you, guys. Whenever you're ready, drive safely. We've got a little reception.


All from this slide, my name is Randy Coleman, apparently, since I'm so creative in choosing my online identities. This slide is an exercise in just how many times I can get my name to show up on one slide. As of two weeks ago, I worked for Zeal, so a new job. It's kind of fun. I'm still getting my feet under me, but I'm enjoying it a lot. So a lot of us probably flew into this conference. So you've been on an airplane, long flight, maybe across the country. You get in, you need to find a way to your hotel. And let's say you decided that maybe a bus was the best way to come, because if you're like me, you're cheap, and you maybe don't have the best judgment sometimes.  There's these nice little bars on the side that maybe you think you should push, but no. You have to touch that yellow stripe in the middle, and that's not obvious, so they had to add the yellow stripe with the documentation on it. And apparently, that wasn't even enough. They had to add the white arrows as well, and say, no, you got to touch here. So documentation on top of documentation.  And you have this button for doing this. And there's these bright red lights at the top or orange lights at the top that kind of scream, push me, push me, but no, that's not how you cross the street. You have to push that much dimmer button down below. And because that wasn't obvious enough, they had to add these arrows to point you at the right button to push.  It's been a long trip. You're tired. You get to your hotel. You just want to get cleaned up a little bit, and you find a sink faucet that looks like that. In theory, you can get water out of that somehow. I'm not quite sure how. It's not really clear, but fortunately with this one, they provided instructions. Or not. So at this point, you're about to rage quit life. But fortunately, so what we're talking about here is something called affordances. Now, this is a physical design concept. I first read about it in Donald Norman's book, The Design of Everyday Things. I actually read it back when it was called the philosophy or psychology of everyday things, but I think he renamed it for more mass market popularity or something like that. But the idea of an affordance is that physical objects afford certain operations or actions. You got the crash bars on the doors out there are made for pushing. Door knobs are made for turning. Those are affordances. And affordances have also come to me in a little bit. How well does an object communicate its intended use? So these ones I just showed you were poor affordances, but what if you walked up to an escalator that looked like that? How many of you can figure that out pretty quickly just by looking at it? I think it's a brilliant design. Stand on the right, walk on the left. So there are good affordances and bad affordances. That's the physical design world. Affordances, I think, also apply to software. The most obvious place would be in UI design. You want your UIs to be intuitive. You want people to be able to figure out how to use them well. There's a saying that if you have to provide a manual for your website or your web app, you've lost. And that's probably true in a lot of ways. Affordances can also apply to APIs as well. You want APIs that are consistent, discoverable, easy to use. I've seen examples of APIs where not only do you get your payload back, but you also get a list of here are the URLs that are now valid given the current state of the application. And so those are also a form of affordances. In this talk, I want to argue that affordances also apply to programming languages. Different languages afford different kinds of solutions. And so by using the affordances of one language, we can solve problems in a way that's kind of unique to that language. But maybe we can take those ideas and bring them back to Ruby as well. Since this is a Ruby conference, all my examples will be applying back to Ruby. So let's look at an example of what I'm talking about. Let's look at a simple point class. So here's a point class in Ruby. I know you can use a struct. I'm using a class here. And you initialize it with an x and a y coordinate. And then you construct it by newing it up, just like normal Ruby. But what happens if you also wanted to support polar coordinates? I absolutely love the Cartesian bear. I have to keep that slide in this talk. No matter. I could change the whole talk, but I have to keep this slide. So if you don't know polar coordinates or you don't remember them, the idea is that you can specify points like we normally do with an x and a y coordinate. But you can also specify a point with a distance from the origin or a radius or r, it's called, and an angle from the positive x axis or theta. And there's trigonometry formulas for converting between the two. Those are polar coordinates. They're great for orbital mechanics, radio motion equations. It makes the math a lot simpler if you use polar coordinates. So if you're writing a library that uses points or a general purpose library for points, you probably want to support both Cartesian coordinates and polar coordinates just so that the class is flexible enough to be used where it needs to be used. So how do we do that in Ruby? We already have our initialized method defined. It takes two numbers. The r and the theta are also numbers. So how do we distinguish between Cartesian and polar coordinates? We could maybe add a third parameter that's like a tag that says, oh, this is polar. I know this is Cartesian. That's kind of ugly. Let's look at small talk instead. I know most of you probably don't know small talk. I'll try to teach you just enough for the syntax to understand the code. But this is the identical code in small talk. In small talk, all method names are keyword messages. So you have the colons there. So the x colon and the y colon are the keywords. And the nx and a y are the parameters. And so we have a class method. And this is actually the constructor of the point class. It takes an x and a y. And the little carrot is a return. So we're sending self the message new, which gives us back a new object. And then we're sending that new instance and initialize y colon method. And that's how it initializes. And then that method just assigns the parameters to instance variables. And we construct the object by sending the x colon, y colon message to the point class. So point x colon, 3, y colon, 4 at the bottom. So that's exactly the same as the Ruby code I just showed you. So in small talk, supporting polar coordinates is completely obvious. You just add a second named constructor method, r colon, theta colon, that takes the radius and the angle. This one forwards to the other constructor, the x, y constructor, and constructs the object. And so internally, it's still representing the point as an x and y coordinate. But you can construct a polar coordinate point. No problem. So small talk is providing this affordance of named constructors. And it's just the natural way to write constructors in small talk. There isn't one initialized method. There's just named constructors. And so the solution is completely obvious. It's affordance provided by that language. So can we apply that to Ruby? Well, sure we can. We can write a class-side method x, y, and another one called polar, that take the right kind of coordinates. Again, the polar constructor is forwarding on to the x, y constructor. And now we can construct a Ruby point, either with x, y, or with polar. And it's very clear that way, using named constructors. For bonus points, I pretended to make the new method private, although in Ruby, nothing's ever really private. But at least I'm communicating my attention here. Private class method, I think, is relatively new, 1, 9, or 2, 0, or something like that. So older Ruby's didn't have it, but you can actually do that. So that's one example. Here's another example. What if we want to find something in a collection, or detect is the other name for it? Small talk uses detect. Ruby has both. So here's small talk again. The hash with the parentheses is a literal array. And we're looking for an element in that array that's odd. So detect is the message name with the colon on the end. And then the square brackets is a block. And the colon each is actually the block variable. I know it's weird having a variable named each when Ruby, you have a method named each. But this is the small talk idiom, so I used it. The one difference from Ruby, though, is that if there isn't an element that matches the condition, then it raises an exception, whereas Ruby would just return nil. So here's the same code in Ruby, exactly identical. I use find here, because that tends to be more idiomatic Ruby, whereas detect is used more in small talk. But what if you want to do something other than returning nil or raising an exception when an element isn't found? Well, in small talk, there's a variant of detect called detect if none. And you pass a second block with the if none keyword. And that block is what gets evaluated if an element isn't found. So in this case, we're going to return the none symbol. That hash none is a symbol. So small talk has this affordance of being able to pass multiple blocks to a method. And it's used in a lot of places.  And they're implemented as methods on the true class and the false class. So it's actually a polymorphic message send to do a conditional in small talk, which is a completely different talk. So I'm not going to go into any more details on that. But passing multiple blocks in small talk is just natural. You do it all the time. Can we do this in Ruby? Well, it turns out that the find method in Ruby does take an optional parameter, and you can pass a proc or a lambda to it. So it's like passing a second block to it. How many of you knew that Ruby could actually do that? I see a few hands. I did a version of this talk at Mount Westrow this year, and there was one hand raised, and it was tender love. So not very many people know about this. But it works in Ruby as written. I didn't do anything special to make this work. So you can actually pass a proc or a lambda. I'm using the stabby lambda here, which should make maths happy, I think. And that lambda will get evaluated if no elements are found that match the pattern. People don't use this in Ruby because I don't think it reads as well as in the small talk. The focus of this code should really be, what am I looking for in the list, the main block looking for odd numbers? And this new, the second lambda kind of takes the focus away from that. So I don't think this code communicates as well, but it's perfectly valid code and it works fine. There's actually another example in active support testing assertions. Assert difference actually can take a lambda or even a ray of lambdas in it. So there are cases in Ruby where this is used, it's just not quite as common, but it's a neat trick that you can use when you need it. It is possible to pass a second block-like thing to a Ruby method. So there's a theory called linguistic relativity, or you might also know it as disappear-warf hypothesis. I have no idea if I'm pronouncing that correctly, but that's what it is. And the idea is that the language you use influences the kinds of thoughts you have or the way you conceptualize your world. Now there's a bunch of debate about whether this is actually a valid theory or a valid description of the way things are. There's a strong form and a weak form and you can go read up about that on Wikipedia like I did. But the idea is that our language influences our thoughts. Now this is talking about natural languages, but I think this also applies to programming languages. Corey Foy did a talk at Software Craftsmanship North America a couple of years ago called When Code Cries, which I love the title of the talk, it's awesome. But he asked two really interesting questions in that talk. And one is, what does a language allow you to say? What kind of ideas can you express in the language? And also, what does a language force you to say? Does the language force you to say things that you don't want to have to say? And he used an example from natural language where some languages have gendered nouns.  And unless you're my wife, I'm probably going to say, well, that's really none of your business. But if I was speaking to you in French where they have gendered nouns, then when I used the word for neighbor, I would instantly be telling you whether my neighbor was male or female because of the gender form of the noun that I used. And so French is forcing me to say something that English doesn't force me to say. And that's also true in programming languages. Some languages force you to say things that you don't want to say. For Java, for example, you have to say your types over and over and over again. But also what languages allow you to say is important as well. Now, all of our languages these days are basically Turing-complete. You can express any computation in them, but they're not all equally expressive, and that's important. When I was researching this talk, I came across an old presentation by Maths at OSCON in 2003 talking about the power and philosophy of Ruby. And one of the things he said on one of the slides is languages are not only tools to communicate, but also tools to think. And he wanted Ruby to be a good thinking tool, and I think he succeeded very well, but that's important. So the languages we use influence the thoughts we have and help us to think better thoughts sometimes. So let's look at a few more examples. When we're programming, we often have to clean up after ourselves. Now we have garbage collectors now, so that helps with one kind of cleanup, but there are other kinds of resources we have to clean up, file handles, socket handles, threads, locks, et cetera. And so we often have to worry about cleaning up after ourselves. We have to free up resources when we're done with them. So I'm gonna show you some really nasty C codes, so there's a warning. Fortunately, there's a party right after this, so you can kind of go drown the sorrows of what I'm about to show you. How many of you have seen C code that looks like this or this specific C code? Yeah, there's more hands than probably you're comfortable admitting there are. Anybody recognize this particular piece of code? Yeah, there's a few. This was an SSL bug that Apple had back eight or nine months ago. It's called the go-to-fail bug. And the problem is that somebody deleted a line of code in the middle there, and because this code uses a particularly egregious set of coding styles, it introduced a bug. But the whole point is that there was a necessity to clean up no matter how we finished this function. We had to go down to the bottom and free up those buffers at the end. So there's gotta be a better way than this that doesn't result in bugs like this. And I'm not gonna try to clean up Apple's code. I'm gonna give you a slightly more simple example. I have this very expressively named function called foo or a method called foo. And in it, we have to acquire some resource, do some things with it, and then release the resource when we're done. Now, there's at least three or four ways that you can get out of this method, and only one of those ways is actually gonna release the resource when it's done. And that's the natural progression right through the end. There's an early return in there. That's the obvious way that you can get out. But also any of the methods I call in there might raise an exception. And if they do, I'm gonna leave this method and I'm gonna blow up and not free my resource. So I've acquired the resource and I've caught the exception out of an outer layer and I did not free my resource. I just leaked it. And if I run this code a lot in my system, eventually I'm gonna run out of resources and my program's gonna blow up in production. And that's not cool. So we have to write our code differently to protect ourselves against these problems. So here's one way you could do it that actually solves the problem. It releases the resource when the exception is thrown. But look at what we had to do. We had to change the early return into a nested if statement. And so now we've got what I call wedgie code, where it's all shaped like a wedge because of all the levels of nesting. We had to catch an exception that we really don't care about here and then re-throw it. We had to duplicate the code for releasing the resource.  And I'm not saying the original code was all that great, but this is worse. Feels to me like running a stove like this where if you want medium heat, you have to press a button like six times to get it. Fortunately, they give you two buttons so you don't have to press it 12 times to get high heat. But still. Or maybe dialing a phone like that. Anybody remember those? Interesting thing I read once is that the bigger cities in the US have area codes using lower numbers like New York is 212 and Chicago is 312. I think LA is 213 if I remember right. And the idea is they were actually optimizing for the more frequently dialed area codes. They figured the more populist places, those area codes would be dialed more often. And so they made those as efficient as possible with the dial. That's totally a side note, but I thought it was kind of cool when I read it. So what can we do instead? We can use an idiom from C++ called resource acquisition is initialization, which speaking of affordances is not a well-named idiom at all. But the whole idea is that you acquire your resources in constructors and you release them in destructors. And the reason that works in C++ is because C++ has deterministic to structure semantics. When an object goes out of scope, its destructor is called immediately right then.  It's not never. It's always right when that scope ends. And it doesn't matter whether the scope is ended normally by just exiting out of it or abnormally by raising an exception. It always calls the destructor right then. And so there's a pattern you can use in C++ that takes advantage of that. And so we can write a safe resource class. And safe resource, we acquire the resource in the constructor, we release it in the destructor, and I added a get method so that other code can work with the actual resource itself. And then we can look at our foo method and now we create a safe resource at the top of the function. On the stack is what it's called in C++. And when that function exits, safe resource goes out of scope, its destructor gets called, and it releases the resource. And it doesn't matter how we exit the scope, that will get called. And so now our code looks basically like it did before. There's a couple extra get calls in there. But it has the same form as it did with the early return. We're not catching the exception we don't care about. We don't even have to call the release call anymore because the destructor does it for us automatically. So this is even a little bit better. And this works. It releases the resource. So we have this affordance from C++ called deterministic destructors. Can we take that affordance and the solutions that it allows us to create and apply those to Ruby? Well, Ruby doesn't have deterministic destructors. So what can we do instead? Well, we could use begin and ensure everywhere, which is kind of ugly. Every client would have to do that. It's like using try and finally in Java. And if you've ever read much Java code, there's tons of that littered everywhere. I don't like that idea very much. You can actually define a finalizer in Ruby. You can define a method that will get called when the garbage collector finalizes an object. That's not quite deterministic because it only happens when the garbage collector runs. But you can do that. Not very common. People don't do it very much. But Ruby has blocks. And so maybe we can do something with blocks instead. So here's a safe resource class in Ruby. There's a class side method called acquire that allocates the resource, acquires the resource, yields the resource to a block provided to this method and then has an insurer that releases the resource when it's done and then initialize and release or the acquire and release of the resource. And we can use that in our foo method just like we did in C++. We have to do it a little bit differently where we have to use this class side acquire method. So we can say safe resource dot acquire and then the do end is the block that we're passing to it and that code will get executed while the resource has been acquired. And when the block exits, whether normally or abnormally, the insurer block in the acquire method will make sure that we release the resource when we're done. So this is very similar to the C++ code. We're using blocks to give ourselves those semantics. You've probably used this idiom before in your Ruby code. If you use file open that takes a block, it opens the file. The block executes while the file's open, closes the file when you're done. There's lots of places in Ruby where this idiom is used and that's basically the way you solve the problem in Ruby and actually Smalltalk as well uses the same idiom for this. Blocks are great for this. And just showing you that works as well. All right, another example, kind of similar to cleaning up after yourself and this is places where you need to restore state. So for example, in a graphics program, you might want to use a certain pen or a certain foreground color, do some drawing and then set that state back to where you were. This time I'm actually gonna use Emacs list for my example language because I used to program list years ago and I love it, it's pretty cool language. So here's some code where we want to delete some text between a couple of delimiters and so the interactive there just means that this is code that's gonna be executed interactively by the user or it can be, it's not just a function to be called by other code. Emacs list is the language used to customize Emacs editor by the way. And then there's a save excursion thing that I'll talk about in a minute and within the code we're just skipping backwards to find a delimiter and then skipping forward to finding a delimiter, remembering the two places where we found those delimiters and then deleting the region between those two points. That's what that code's doing. What save excursion does is it basically remembers the state of what buffer you're in, where's the cursor located, where's the selection, all that kind of stuff and once save excursion is done, it restores that state back. So in Emacs list when you're writing functions to manipulate some text or find things, you can put everything in a save excursion and then you can go all over the buffer, do whatever you need to do and then save excursion will take you back to where you were. And the way it works is, now the actual implementation is in Emacs C code but it works as if it was written as a macro. List macros are really cool. They're probably more powerful than most things you've seen. There's a little back quote there that basically quotes all of the rest of the form there and so when the macro is expanded, it's like it generates that code that's protected by the back tick. So what we're doing is we're remembering the current buffer, the current location of the point, the current location of the mark which is another Emacs concept. Unwind protect is like an insure block in Ruby. Progn says here take a list of forms and treat them as one form and return the value of the last one and then the comma at sign basically splices in the body we provided to this method into that location in the macro. And so this is gonna expand out to code with the let form, the unwind protect, then all of the code that we provided in the body of save excursion and then the three forms at the end are what's done by unwind protect as that code exits. So you don't need to understand the list very much but this is a very common pattern in a list macro where you do some stuff, splice in some forms and then do some other stuff. Okay, so we have this affordance of macros in Lisp. What can we do in Ruby? Well, the answer again is blocks. Blocks help us here again. So we can write a version of save excursion in Ruby where we remember the state at the beginning, we yield to a block and then we ensure that we restore the state at the end. And so again, we've been able to use Ruby's blocks to substitute for at least one kind of macro that you might write in Lisp. And there's our delete and close text where we call save excursion, we pass it a block where we do the work we wanna do and save excursion takes care of restoring the state back where it need to be. So any kind of code where you write, where you kinda want something in a certain state while you run the code and then you wanna automatically restore it back at the end, again, you can use this pattern with blocks very much like Lisp macros. There's some other examples in this blog post I read recently by Kevin B. Cannon of 8th Light where he takes a couple of other Lisp macro ideas and applies them back to Ruby again using blocks. Interesting article to read. I have one last example for you and this is the idea of an image reader. This is again from Smalltalk. I programmed Smalltalk for like 13 years before I started my new job two weeks ago. So I like Smalltalk a lot, it's a great language. But the image reader ideas, we've got this base image reader class and we want it to be able to read any kind of image and we wanna be able to even support images we haven't even thought of yet or we haven't implemented yet without having to change our image reader class. So this is code actually in the VisualWorks Smalltalk base image. I've changed it a bit for presentation purposes but it's essentially the same. This is a little bit of a wall of Smalltalk but what this is is a class side method called from file, you pass it a file name. It opens a binary read stream on the file and then it sends itself the reader class four method with that stream and assigns the result to reader class. If you can't find one it raises an exception but otherwise it instantiates the reader class on the stream and then closes the stream when it's done. So the idea is it's gonna search somehow for a class that can handle this format of file and we're not looking at file extensions here, we're actually looking at the contents of the file. So reader class four takes the stream and what it's doing, a Smalltalk class knows all of its subclasses. So you can ask actually for its direct subclasses which is what we're doing here or it's all of its descendants, there's an all subclasses method that does that. And so we're asking the class for its subclasses and then we're doing a detective none which we saw earlier. So we're looking for a class that satisfies this first block. We're resetting the stream back to the beginning and then we're asking the class, hey, can you read this stream? And the class is gonna return true or false depending on whether it understands that format or not. And when we find one that answers true, that's what we'll return from this method. So that's how we find our reader class. So we have this affordance in Smalltalk again of being able to ask a class for its subclasses and iterate them all. Can we do this in Ruby? Well, let's see. We have a read method on the class side, takes file name, opens a binary stream on it and then calls this findReader class method with the stream. Raised as an exception if we can't find one otherwise creates the class on that stream. So far it looks pretty much like the Smalltalk. Well, here's findReader class. How does that work? Saying subclasses.find, so reason find instead of detect and ask the reader class, can you read this stream? Again, very much like Smalltalk but how do we get subclasses in Ruby? Ruby doesn't keep tracking that for us, does it? No, it actually doesn't. But we can simulate it with two little methods here. So a class has a hook method that's called when a subclass is defined. And so when you define a subclass of imageReader, this hook method inherited will get called and it'll pass in the subclass that was just defined. And so what we can do is we can shovel that onto a lazily initialized array and remember it. So this class is keeping track of its subclasses as they're defined. And that's how we can iterate them. We just were calling the subclasses method and iterated them all. If you're using active support, it actually does this for you. There's a subclasses method defined by active support. There's also a descendants method that gives you all of the descendants of the class. So active support is doing this for you but you can do it yourself in plain Ruby with these two methods. And so we can write a bitmap imageReader and all we have to do is implement the canRead method and it's looking for the bitmap signature which is the first two bytes have to be VM. The read image is the method that would actually read the image here. I'm just printing out a string so you can see it's doing the right thing. There's a JPEG imageReader. It looks for the JPEG signature and that dot B on the end of the string there is because encodings. That's about all I have to say about that. And we can have a ping imageReader which looks for the ping signature which is actually eight bytes long and it's kind of actually fascinating. There's things in there to detect byte ordering and carriage return line feed conventions and so on that whole signature has meaning there. It's there for a very particular reason which I found kind of interesting. And so we can run this code over a set of files. I ran this over directory with one of each kind of file and it reads each one by just looking at the content. And so because it's looking at stream content you can even use this class directly on a stream by reading it back from like an HTTP endpoint or something like that, getting back image data. You don't even have to have it in a file if you don't want to. So that's kind of cool. Very similar example is a blog post by Andre Bernardis I just read a few weeks ago called Inverting Dependencies where he's trying to solve a very similar problem. The way he solved it is the subclass when you define it it would actually call a method on the base class to register itself with it. You can solve it the way I did here with just keeping track of subclasses as well. But it's very similar problem. You see this from time to time. I've seen it for like URI scheme handlers where you want to define new handlers as a subclass of a basic handler. And you really don't want to have to go back to the base class and change it like to add a case to a case statement or something like that. So this technique is great for that where basically as long as you have something that requires in the class that you need it kind of automatically participates in the resolution of what you're trying to resolve. So it's kind of cool. So what have we learned today? The first thing is that languages afford certain kinds of solutions or designs and inhibit others. So you just naturally solve problems certain ways in certain languages and other solutions don't come so naturally in those languages. Our languages influence our thoughts. So when we're programming all the time in one language we think one way and we solve problems one way. Whereas if we use a bunch of different languages it expands our thoughts. And so by learning new languages you can increase your solution space. So when you're trying to solve a hard problem the more things you have to draw from the wider the set of solutions you'll have to consider and the more creative your solutions will be. You'll come up with better ideas, better designs because you know more things. So I guess my encouragement is to learn as many languages as you can. And even if you don't ever use them for real code just becoming fluent enough to understand how to think in them will help you with your Ruby or whatever other languages you're working in. But don't go too crazy with it. You can get a lot of great ideas from functional programming for example but if you tried to go full on immutable data structures in Ruby you're gonna give the garbage collector fits. Other languages are much more optimized for that kind of thing but certainly take the ideas that work and don't go too far. You also want people to be able to understand the code you write and you want to use the language for what it's good for and its strengths. Years and years ago I was forced to write code in VB6 and I'm almost done with my therapy finally. But VB6 does not have implementation inheritance. And back then I didn't know this but implementation inheritance is quite overrated but when you need it you really need it. And so I came up with a way to kind of simulate it in VB6 using composition and delegation. And I'm not sure my coworkers really understood my code all that well. I kind of taught them the pattern but I'm not sure they really got it. That was probably too far. So don't go too crazy with this but certainly take the ideas. It's amazing how many times I learned something that doesn't seem related to my job and yet within two weeks we'll come across a problem that's like oh I just read about this thing and it works here. This happens all the time. So just learn what you can and expand your space and your ideas. If you're interested in this topic if I caught your attention a little bit I actually wrote a whole series about this on my blog. I cherry picked the examples that applied to Ruby but I kind of gave some other examples that applied to other languages as well. Tom Stewart did a great talk at GoGuruko a couple of months ago called refactoring Ruby with Monads. Probably the best introduction to Monads I've ever seen and also is very much along these lines where you can take the Monad idea from functional languages and apply it to Ruby code to come up with better solutions. So I highly recommend checking that talk out. I want to thank Zeo for sending me here. And there's references to everything I talked about. Thank you Adam. I'll have the slides up on speaker deck later today or tomorrow. And I'm on speaker rate. If you want to give me feedback on the talk I'd appreciate it. I'm always trying to get better. Thank you very much. Enjoy the party tonight.


Everybody forced here rip in 2021 illusions basketball team all 10 box number 15 to your random teams I'll show the results right here. You can always find them in late sports cards.com Thanks for joining everybody. Good luck. I Did drop your Lincoln chat to go 10 boxes. Yeah, we'll see a big auto here team all I'm not sure the odds I think it's One every few boxes or so like one or two a case 20 box cases There's like a you know looks like groove almost trade jones jade mcdaniels. There's a Yanis It's got Demi Lillard season highlights living legends durknewitzky cool die acetate And it'll be top and rookie living legend Tyrese halibut and rookie Bonnie Walker read the bonte gram career lineage ray allen um So let's roll for the whole break here Go one two three left for sonics or thunder four five six right for uh, selts That's a six. I just rolled so this is going to go right side I'll show them in a second. I'll show you that Um, roll a dice for this too So yeah goes right side on those and then one two three top four five six bottom So the top is the rookie the bottom is the bet and every single one of those that's how it's going to be too One two three top four five six bottom A one these will go top Cole anthony top bottom goes top left right goes right There's a desmond bane rookie team all silver I would call it Zane joe dearen fox Mystique james harden There's no coral rookie Zeke naji Russell westbrook Chua and okong woo Got them to sell rookie for the spurs Payton pritchard seltsix Foltz mystique lebron james lakers And an rj hampton silvers mcdaniels vooch Paul mill sap red There's a toppen and lamello All right guys just flawless football effort tonight. Everything else is sold out only flawless football. There's another haliburton Jay shantate Amazing acetate kevin durant These are Cole anthony Everybody in this room except me has met Cole anthony Is a joe hoku and chris stops Isaac coro von dotson All right box three CV's off what the heck I thought anything was on anyway We had to start tomato going More exciting than a bears commander probably right? Yep That's what the score is Scoreless yep No guys to be okay rookie Anthony jimel murray living legends tim duncan big fundamental And rookie josh green pretty gay towns malachi flinn Let's see a big rookie team all man And a mason jones rookie It's not up Yeah, his trophy collection autotroy brown jr bulls There about donovitch a gold Looks like gold 325 though wizards russell westbrook Nice one wizards All right good box here Yalta Murray red wiseman for the warriors now great box actually Isaiah thomas and achillian hayes so that would go to the top there Lebron james mystique again Nathan knight and kira louis jr. Um, yeah, I pulled two walle pit bat relic one of ones actually Pretty sure I did but yeah, I didn't pull one thing was like last week they'll mallet on poku incident impact shining stars kairi erving brooklyn vine boucher poku nestsmith rookie and and a manual quickly erin gordon jordan pool paul reed rookie beer shots paul george anesa deek bay rookie Oh, nice guy. Yeah, congrats. It's a pretty cool piece Blondie walker damey littered paul milsap red There is an edwards incident impact Water reggie parry obi toppy obi toppy obi toppen lamello ball I think I've said that before too. I think you have I think I remember you saying living legends ben wallis only with lakes here, dude Wara Dude, you see if I'm nice stop wool even this face game right here. Oh, yeah. Yeah. Yeah Cole anthony rookie I am on the hunt for a game. I honestly have no idea tie I don't think I've ever seen I've never followed walle pip sales before red rookie jordan warrow bucks season highlights edwards quickly meryl Oh, man, that's things, dude Watson got lewis and section. That doesn't count, dude The guy's helmet his fault mystique jalen brown. He made some of her opponents.  Yeah, I know kung-wu Incident pack nalara That's number 25. That's really tough. That's numbered. This is the one behind. It's not this one's red. I guess or yellow I was number for the bucks It's a dig bay. There's a number on the back though. That's what the other one looks like I guess someone's like yellow and red or something Uh, the crown break is next mark a lewis king trophy collection auto for the kings Stricts while the fills and breaks earlier. So urged behind a bit williams killian haze career lineage Dirk Maze you got a maze red rookie for the hawks One more stevens james wiseman Maybe have to be intimidated by it's not like I mean, I'm honestly not sure. It's it's only a bat rally Okay, new martin tyrese maxi rookie tatum Living legends was uh tim duncan again Jay shuntate rookie my favorite basketball player is trace mcgrady The uh, oh, yeah covington so dig bay Y'all look at that there. He is right there team act Savin lee moses brown Tyrese maxi rookie carmelo devin booker The more stevens rookie Kenyon martin jr. jordan pool red killing haze pistons rookie Well being there's a lamello incident impact moses brown jay shuntate Payton pritchard rookie jenny avd All right last pack of this box only got three more There's a vacelle rookie Lamello and rj hampton. I don't know if I have anybody going to fancy tonight I guess basically all you would have is like one more Or mcgummery I think he's here. I don't know Hey word turner. You got payton pritchard rookie, you know demie lillard amazing scouther maize Keldon johnson donna mitchell got vacelle One thing I was doing Kenny martin jr. Tyrese maxi Daniels shining stars donna mitchell Denny avd Vice harris kyle larry red nathan knight It's my word lana my red sauce team got cell rookie payton pritchard rookie All right two more is jaylen green europe air player great All right, we got jaylon smith pressures atua Amazing cp3 robert woodard. Do you see what they're doing for the pro bowl? red mcow bridges Yeah, it's a flag football game now. It's like that like skills challenge stuff It should just can't just cancel it. Yeah nagi marshal How do I gotta make more money, I guess they're not making enough Shining stars kairi erving. I will say it was really sick when they came here for that Because they had stewart to go out to disney. That was the only good part about the pro bowl. That was here They're like, oh, that's cool. I got so many sick autos and pictures that day anthony edwards I got to meet comorra. I love mellow season highlights Going off on that fan No Tyrese maxi rookie steeke bae inson impact Rubio harris kenny martin jr. Rookie Must be something big. Xavier tommy rookie. Everybody's involved and we're going d&b. It's gonna be big Big in a good way, I would think We'll see dandy green d angelo russel denny up the orookie George mystique anthony edwards again Last pack Yeah, well, we'll hit some big stuff tonight too. Sure Kiki that young kawaii lennard red Is there any zappy in there? Oh, I didn't see him.  He's all over the place in iMac really he's everywhere All right, that'll do it. Thanks again everybody. We've got uh team all crown way out coming up next


Welcome to this deeper dive into color representations. Colors are everywhere and as such we all have an intuitive understanding of how colors work. So how hard can it be to represent colors? It turns out to be very hard. Let's start with our GB, red-green-blue. We've probably all seen a color cube like this before and it is the standard representation of color because the way we mix colors is by combining red, green and blue light to make the other colors. However, it's bad for data visualization because red, green and blue are not so-called visual variables. I've covered visual variables before in my introduction to the core concepts of data visualization. For this reason it's popular to use HSV instead, Hue Saturation Value. Here the colors have been organized into a cylinder instead with the different hues going around the circle, the saturation going from inside to the perimeter and the value, the brightness, going from bottom to top. So let's play again, which are brightest? Here are five circles and I guess we can all agree that they are organized from the brightest on the left to the darkest on the right. But according to HSV, the three on the left are all equally bright. They have the same value. Another question, which are the most colorful? Looking at the same five circles, we can probably all agree that the most blue, the most strongly colorful circle is the blue one in the middle. But according to HSV, the three on the right are all equally saturated. They have the same saturation value. So what's happening here? With these circles I was moving from the top center, white, towards the perimeter getting blue and then down the value scale to black. So white to blue is saturation, blue to black is value. That's not how we think about colors as humans. For this reason we have HSL, Hue Saturation Lightness. Again the colors are in a cylinder, but now you see the whole top layer is white, the bottom layer is black and you have a lightness axis. The strong colors, the clean hues are going around the center at 50% lightness and you have saturation going from gray to these colors. So let's ask again, which are the most colorful? We are looking at the same five circles. The one in the center is the most colorful, right? Well according to this system, they are all five are equally saturated. What's happening here? I moved along the lightness scale. From white to blue to black is all along the lightness scale at 100% saturation of blue. And that's why we have HSL, Hue Chroma Lightness. Now it's no longer a cylinder. You see we have a single point representing white and a single point representing black. The lightness scale is still the same, the hue is still the same but we have now replaced saturation with chroma. And you see it's only possible to reach 100% chroma at 50% lightness and at 100% lightness or 0% lightness, white and black you cannot have any chroma. This makes more sense. So let's play the game, which are brightest? Here are five new circles. And again, I hope you would agree, they are sorted from the lightest on the left to the darkest on the right. But according to this metric, they are all equally light. They have the same lightness value. What did I do this time? I changed the hue. They were all 50% lightness. They were all 100% chroma. And I was moving along the hue axis from cyan towards blue. And cyan looks brighter than blue. This finally gets us to the C-Lab representation of color. C-Lab puts emphasis on human perception of color. Specifically, it's based on the so-called opponent color model. In C-Lab, we have three different coordinates. The first being L-Star, which is perceptual lightness, not to be confused with lightness in the previous metrics. A-Star, which is an axis going from green to red. And B-Star, representing the other opposing colors, going from blue to yellow. If we take the RGB cube from before, looking like this, and we map it into L-Star, A-Star, B-Star coordinates, it gets bent all out of shape and looks like this. But this makes sense. You see white being the lightest color, but yellow is almost as light, and green and cyan are quite light as well. Black is the darkest, but blue is pretty close. And red and magenta are somewhere in between. This is how we actually perceive lightness. Another important property of C-Lab color space is that it is perceptually uniform. That means Euclidean distances within these coordinates correspond closely to similarity of the colors, at least approximately. However, we still have the problem that these are not visual variables. Well, L-Star is, but A-Star and B-Star, red to green, blue to yellow, they are not visual variables. However, it's easy to put this into polar coordinates, and when we do that, we get this representation. The shape is still the same, we just replace the A-Star and B-Star coordinates with hue and a variable closely related to chroma that we discussed before. So to sum up, RGB is great for controlling pixels, but not much else. You don't want to use it for graphics design. HSV, HSL and HCL are all much better alternatives if you're trying to choose colors and make graphics illustrations. However, they are not great for mapping quantitative data in an accurate fashion. For that, you want to use C-Lab. C-Lab allows you, thanks to the perceptual uniformity, to make accurate representations of data as colors. However, it's complicated. It's not well supported on many systems, and it's tricky to use C-Lab because you have to map your values into this weird shape of colors, not a simple cube and not a simple cylinder. That's all I want to say about colors this time. If you're interested in data visualization, I suggest you go have a look at this presentation as well. Thanks for your attention.