Ah, we're back. So you're still with us here in the Optiver room and the next talk we get is marked as advanced. But don't let you get scared for that because we also have a very advanced Python trainer who's going to help you get the best out of this talk. So let's welcome to the stage Reuben Lerner from Israel. Hey. Hey Martin. Hi there, how are you doing? Ah, I'm fine. It was a fun day today. We had all kinds of problems in the morning, but things are now running smoothly. So I hope we won't have any problems. So I see that your screen share is ready. So if anybody has questions about this, you can type them in the main chat and we'll do a Q&A later and talk about that afterwards. So the stage is yours. Excellent. Thanks so much. Hey everyone. Welcome to my talk. This is called Generators, Co-Routines and Nano Services and I will describe all of these in just a little bit. So just a few words about myself. I am a full-time Python trainer. So just about every day I'm in a different city, different country, working with a different company. Okay, in the last year and a half, I've not really traveled that much, but I've been doing a lot on Zoom and WebEx, a lot of corporate training. I have individual courses, including something called Weekly Python Exercise. I published my first book on Python last year, Python Workout, with exercises to improve your Python fluency. And I'm currently working on a new book, which will very, very soon be released, at least in initial form called Panda's Workout, with exercises to improve your fluency with the Pandas Library. And I've got a free weekly newsletter about Python called Better Developers that currently has about 20,000 subscribers. And I'm on YouTube and I'm on Twitter, but let's concentrate on our real topic. And the real topic is, this is not an async.io talk. I know whenever someone talks about coroutines nowadays, you assume it's about async.io. Now, I will tie this together with async.io later on. But for now, we're not going to be talking about that, which raises the question, what am I talking about? I'm glad you asked. So let's start off with the dumbest function in the world. So here we go. I say def myfunk. And then it has three lines in it, return one, return two, and return three.  Well, I did warn you, right? And so what's going to happen when I call this function and then I print its output? Well, not surprisingly, when we run this, we're going to get one. And that is it. That is the end. And of course, that's because return in a Python function says, that's it. We're ending the function now, and we are returning this value. Every function has a return value. And what happens if we have those calls to return after that first one? Well, we're never really going to get to it, right? It makes sense. Return means stop the function, return a value. And even if I run pylint on this function, it says, hey, those final lines are unreachable. And here's the most impressive thing to me. Python is, of course, a byte-compiled language, meaning that whatever code we have is turned into byte codes, and then those byte codes are interpreted very similar to what happens in .NET or in Java with the JVM, just that the Python compiler tends to be pretty dumb. And this is on purpose. It's supposed to be more or less a one-to-one translation between what we've written and what happens. So you would think in some ways that our three lines in the function body would actually be translated to byte codes. But that turns out not to be the case. If we use the disk module for disassembly, we can actually look at the byte codes that are generated from a function. And if I say disk.disk, so that's the dysfunction in the disk module, and I run on my funk, this is what we get. These are the byte codes that Python is actually running. It's going to load the constant one, and then it's going to return the value. That's there. It's going to return one. And that's it. So even those second two calls to return are ignored completely. So they're really ignored. Now let's take this to the next level. What about this function? And this function is different. I call it my gen. So the name is different. But the real difference is that I'm no longer using return. I'm now using a keyword called yield. And so I say yield one, yield two, and yield three. So what's going to happen now when I call my gen and I run print on it? What are we going to get back? What happens when we run this code? And here's the amazing thing. We don't get one. We don't get two. We don't get three. Rather we get this. We get this generator object. And so yield makes the whole difference here. The fact that we use yield in our function body turns our function from a regular old function into what's called a generator function. And I'll, by the way, add that many, many people call these functions generators. They're not really generators, but a lot of people call them that. We really should call them generator functions. And so when Python compiles your function, it notices the yield in there and says, wait, we're going to tag this function as a generator function. And so when you run the function, it no longer runs the code. Rather it returns a generator object. And we're going to come back to what those are and how those are important in just a moment. So let's try now disassembling our generator function. Well, first of all, I'm going to use this.showCode. And showCode allows us to get like a high level view of our function object. It shows us the name. It shows us where it was defined. It shows us many arguments and so on and so forth.  And those flags are used for Python to understand what's going on with our function. You can see here that there's a flag in here called generator, meaning, hey, this is a generator function. If you don't have yield in a function that it will not be tagged as generator. By the way, these flags also are around. If you use splatR double splatKWR, that's where Python keeps track of this being the case. Okay. And if I actually disassemble my function, my generator function, what do I get? Well, you see it's a whole different kettle of fish here. Now what's happening is it's going to load the constant one and yield it and then pop the top and then load the constant two and yield it. Load constant three and yield it.  So what's going on here? What is actually happening? And how does this help? What is yield doing? We see that yield then is a low level bytecode thing inside of Python. Right? Bitecodes aren't really that low level Python, but this is as low as it gets. So yield is really important to the language. So what is a generator after all? What is this object that we got back that our generator function is creating? And the answer is that a generator is an object that implements Python's iterator protocol, meaning we can get the iterator for an object with the iter function. And in this case, the generator's iterator is itself. And we're going to talk about this more in just a moment. You get each value, each next value by calling next. And when it gets to the end, it raises the stop iteration exception. So let's see how this protocol works in general. And then we'll come back to our generator. So let's say I have a simple for loop. So I say for one item in ABCD, print one item. So what's happening here? Well, the first thing that happens in a for loop is Python says, is this object iterable? The second thing it does is it says, OK, if it's iterable, then we're going to ask it for the next thing, the next thing, the next thing. And when we get stop iteration raised, when that exception is raised, then we exit the loop. This is how literally every for loop in Python works. And so sure enough, if we run this for loop, we're going to get A, B, C, and D. That's probably not much of a surprise. But what happens if I put my generator in here in the same for loop? The question is, is what we got back from calling my gen iterable? The answer is yes. It is a generator. We get back a generator and a generator implements the protocol. So the for loop says, oh, you're an iterator. You're iterable. I'm going to ask you for your next thing, your next thing, your next thing, your next thing. And then when we get stop iteration that exits. And what happens then when I run this for loop? I'm going to get one, and then I'm going to get two, and then I'm going to get three. What the heck? What is happening here? Well, let's do this manually. Maybe we'll understand it a little better. So I'm going to say g equals my gen. So I'm going to call my generate function and stick the results in generator object. We can see here is the generate object inside of the g variable. So g is now a generate object. You can see by these ID numbers here that we get, which is really memory location truth be told. We see that g and iter of d are exactly the same thing. So a generator is its own iterator. So when you ask a generator, are you iterable? We recall iter on it. Are you iterable? And if so, who's your iterator? It says I'm iterable. And this is I am my own, my my own iterator, right? Same address, same ID, same objects. That's great. So what happens with next? Well, this is on the right here, my generator function body yield one, yield two, yield three. So what happens if I take then g equals my gen? I say next on g. See what happens? It returns one.  We get two. Then we run next on g. We get three.  And we get the stop iteration exception. So what happens when we use next? Next in general, in general tells an iterator, give me your next thing. But when it comes to a generator function, next says run through. And here's the key thing run through the next yield that you see up to and including the next deal and then go to sleep. Go to sleep and wait for further instructions. Well, how much code is between now and the next deal? It could be a tiny bit of code. It could be a lot of code. We don't know in advance. What's basically happening is that Python is running up to and including the next yield and then it goes to sleep. Now the cool thing here is that the function state remains across those calls.  But all the local variables in the function stick around and our stack frame sticks around. Okay, let's see some examples of this. So first example is a fib, right? I'm sure all of you in your day jobs, you're constantly calculating the fibonacci sequence. Here is how we can use a generator function to do that. So I'm going to define fib. We're going to say first equals zero, second equals one. And then I'm going to have it in Phil Loupier, while true, yield first, and then I'm going to use people unpack. I'm going to say first comma second equals second, second comma first plus second. Meaning each time I ask for the next value back from this, I'm going to get the next number in the fibonacci sequence, zero, one, one, two, and so on and so forth. By the way, if you do this, if you call fib and you stick the result inside of list or something else, make sure you do it on someone else's computer because this will take a very, very long time to run because what's happening? Well, it's never going to run stop it. It's not going to erase the stop iteration exception, right? So it's just going to run and run and run until you basically run out of memory. This is great, by the way, if you charge by the hour, but don't do this. All right, let's try one other example. I should ask, by the way, I should add, by the way, that the whole business with fibonacci shows that a generator function is a great way to describe an infinitely long sequence, something that we know will take forever, but we only want it in little bits and little bits and little bits. Next example, readn. This is a favorite example of mine. We know that if we read from a file in general, we're in Python, we're going to get one line, then the next line, then the next line. But a lot of times, files are not in one line records. They're in two line records, five line records, 10 line records. So readn is a generator function that when I read from a file, I'm going to get n lines back. Okay, so what's going on here? Well, we're going to read line. We're going to run f.readline. That reads from the file. How many lines did we read? Well, one, up to and including the next new line. How many lines are we going to read? Well, I'm going to read n. I'm calling the function with the name of a file and n, the chunk size that I want. And then I'm going to read that many lines and I'm going to join those together in a string and put them to output. And then I'm going to say if output, meaning if I have a non-empty string, I'm going to yield that output. So if we have something in the string, yield it. If not, then we're going to break. What happens when we break out of our while loop the function ends? What happens when the function ends? It raises stop iteration. So this is a great way for us to get n lines back. We're going to get a string, another string, another string, each of them being n lines long except for the final one, which could be a little shorter. Okay. Here's another third example. So here's a get vowels generator. So let's say I want to open a file. I only want to get the vowels. Why would I want to do that? I don't know, but let's say I want to. So what are we going to do here? Well, we're going to open the file. We're going to iterate over one line at a time. We're going to iterate over the current line with character at a time. And then the key thing, if the character is in AIOU, then we're going to yield one character. We're going to yield, and what happens after yield? The generator goes to sleep and awaits for the next time that we call next on it. Okay. And what happens when we get to that end of that line? We go back up to the for loop. We're basically going to go through every character in the file one at a time, only returning the vowels. So when are we going to use generators? Well, when we have a potentially larger infinite set of values to return, it's often easier to express the idea as a function, right? That instead of expressing something as a bunch of classes or as even one class, which we can do, and then we can use the iterator protocol to implement it. So it's easier to express as a function. So we have to set things up. So let's say I want to set up a network connection and a database connection, something like that. And then inside of my generator, I can take advantage of the fact that local variable has been set with that database or network connection. And then I can also keep state across runs in local variables because it's just going to sleep. It's not actually exiting. In technical terms, you can think of it as, well, I mean, when I define a function and then I run a function, every time I run a function, I get a new stack frame. And in that stack frame, I have my local variables. But when it comes to a generator function or a generator object, I should say, the stack frame sticks around across the calls to it or across the use set. What if I do this, though? This is a little different than what we've seen so far. Now I'm going to say def my gen, x equals none, while true. And then I do something really weird. I say x equals yield x. Wait a second. What's going on here? Yield returns the current value of x and the function goes to sleep, right? Yes, that's true. But here, in the case of yield x, it's on the right side of assignment, meaning that it's going to get a value from somewhere. Where the heck is it going to get a value from? Well, from us, of course. When we use yield as an expression, the same rules apply. Each time we call next, the generator runs to the next yield and after yield goes to sleep. But yield is now for two-way communication. Our function, or our generator, I should say, sticking around in memory across the calls to next, it can now receive messages from the outside world. We can send something and another something and another something. And whatever we send to it replaces that yield in the expression, typically in assignment. And the way we send something, well, we send something with the send method. So we can advance a generator, next, next, next, next, with the next function. We can send a value to a generator with send. And so the difference between them is that when I say next, it's just like saying g.send of none. It's basically sending a none. Now I should add, here, let's take a look at this. So if I now say def my gen, x equals none, while true, x equals yield x, then x times equals five. So I'm going to create my generator. I'm going to now say next of g. I have to do what's known as priming it. I have to get it past that first yield so I get a value back. What is that value? Well, it's going to be none. Who cares? Then it went to sleep just after that yield. We're still stuck on the right side of the assignment there. And so now I can say g.send of 10. What happens? 10 replaces the right side of that assignment. So now it's x equals 10. Then we say x times equals five. And then we come back to the yield. We get back 50. And then it goes to sleep again. Now I say 23. We get back 115. And it goes to sleep again. It's always going to continue up to and including the next yield. The difference now is that yield is both receiving and sending. And what if I say g.send of ABC? Well, as always in Python, variables don't have types. And so as long as I send something that is, you know, can be multiplied by an integer, we're doing fine. I can even send a list, right? One, two, three, one, two, three, one, two, three, and so on and so forth. This is what's known as a coroutine. A coroutine is a generator. It waits to get input from elsewhere using send. The data is received with yields and expression used on the right side of assignment. And our local state remains across calls. So here's another way that I can do exactly the same thing just in a cooler, more modern and more controversial way to do it. I can use the walrus operator, the assignment expression. What's going to happen if and when I send a null value or a non-value, I should say, or something that's false in a boolean context, then it will be seen as false and will exit from the loop. So what's happening here? I'm saying def my gen, x equals none. And then while x colon equals yield x. So we're going to yield, we're going to wait, and whatever is sent to our generator is going to be assigned to x, and while it's going to see that and say, oh, it was false in a boolean context, I'm going to exit now. And this yield here, you have to put it in parentheses in order for it to work, but it works just fine. By the way, David Beasley gave a great talk like more than 10 years ago about generators and so forth, and he suggested that you don't want to prime a generator, or I'm sure to say a coroutine, you can use the decorator to do that, that it will automatically run next, and then it moves ahead. So what? So what? This is all like fascinating technically, but I've often said that these sorts of coroutines kind of seem like a solution looking for a problem. Like, okay, it's technically really cool, but where can I use it? And that was sort of the genesis of this talk. Like people have talked about coroutines for a while, but it's not clear necessarily where you can use them or how you can use them. And so what I want to do is give you some ideas of how you can take advantage of this technology inside of your programs. Food for thought, and I think it can help with certain kinds of architectures. And my sort of proposal is that you think about coroutine as a nano service, right? Really tiny, timeier than a microservice. So think of it this way. Many applications use what's called a microservice architecture. So you divide your application to many, many, many different parts. And each part is on a different server. Because it's own state, it's separate, but it keeps that state across calls and so forth. And then you access each microservice via a distinct API. So what you can do is you can think of your coroutines as nano services, as services that are sitting inside of your program. They're not on external servers, right? And so there's no network overhead. There's no object or thread of process overhead. It's just like sitting around. It's always running. It keeps its state. And you can just contact it via an API. What does that API send? You say, here's some new data. What do you think? It comes back with an answer. Now you will need to create your own protocol. This is very low level, right? But you can use Python's data structures in order to do this. So let's use an example here. MB5, right? MB5 is a popular hash function. It's in hashlib. It's a little bit of a pain to use it in Python. So it'd be nice if I had like a little service running in memory. Like you just handed a string and I get back the MB5 signature from it. So let's create a coroutine that does that. So here I'm going to do that. I'm going to say import hashlib. That's MB5 gen. And here I'm going to say output equals none because I have to get something at first. And while s colon equals yield output. So what's going to happen? I'm going to get something from the user, right? That's going to be output here. I'm going to turn that. I'm going to do MB5 on it. Well, I'm going to initialize the MB5 engine. I'm going to encode whatever I got into bytes. I'm going to turn that into M update, which you have to do in order to get the MB5 signature. I'm going to get the hex digits from it. And then I'm going to output that. And then we wait around for the next one, the next one. So if I say G equals MB5 gen, I'm going to send none, have to prime it. And then I send hello. And I get back the MB5 of that. I send goodbye. You get back the MB5 of that. And here's the cool thing also. I can say G dot send of none, and that stops the service. Then what happens? Well, it's false in the while. And so it exits from that. Fantastic. Here's another example. Let's get weather forecast. So I'm going to have here a service where deaf get forecasts of city. I'm going to pass at the number of a city. You can see the like world weather dot WMO dot inch. This is like the world meteorological, meteorological organization. So you could basically pass the number for any city you want. And you'll get back JSON indicating what is the weather forecast.  I had like, you know, poke around, but we're getting weather for that city, for that forecast, the forecast day. And I'm going to get each of the forecast for the next two days.  And I get each of those in turn. Right. Looks pretty great. Right. Sort of. That's not a co routine because our yield is yielding. It's not actually getting anything from us. So let's rewrite this a little bit. I'm not going to rewrite the same function. It's still going to be a generator function, but no longer am I going to pass the city ID as a argument. It's not going to be captured by a parameter rather on that first line there. I'm going to say while city ID colon equals yield, send a city number or not. So if the person sends none, then well, the coroutine exits, but if someone sends a city number based on the numbers in the World Meteorological Association organization, which we find. And so now I can say get forecast. We started up next G, my primate. Tell me about city 44 and 44 and 44. Right. We're going to get it again and again and again, but I can then say send 44. I can get like, I got to the next one there and I'm going to send 45. Give me the next city and the next one and the next one. I'm interested in each of these one at a time and it's going to sort of forward. You can see for city 45, we're getting the next one here. We're getting the next one here. And so basically when we get to the end of the forecast for a particular city, then it comes back to this and said, okay, I'm done with that. Send me a city number or none to exit. Here's a third example and then we're going to pull this together.  So if you're not wearing any. So here I have a database connection, right? Connect using psychopg2, which is a pretty standard PostgreSQL connector in Python. And what am I going to do? I'm going to just like select from up. I created a tiny, tiny database for this example that has first names, last names and birth dates from people. And what is it going to do? Well, it's basically going to have a really primitive sort of API. It's like an object relational mapper and ORM where this is going to get a dictionary and it's from the caller and that dictionary is going to allow us to sort through the results that we only get a few results at a time. And then we're going to iterate over all days and return them. Let me give you an example of how this will work. So I'm going to say G equals people API. So I'm starting up my co-routine and I say next to prime it and then saying send a query and under quit. So I'm going to send a query and the query is going to be in the form of a dictionary. So I'm going to say here last name learner. Send whatever. Okay. And then send again. And now you can see that I'm getting different things and I get a next one and next one and next one. But really we're doing okay on this front. Like we have this nice little object relational mapper thing going on. And I can query my database through this service. I don't have to worry about connecting to the database. Now how can I tell the generator that I'm completely done? I'm going to use the close method. That tells the generator and now. Oops. But what if I want to exit from the current query? Then wouldn't it be nice if I could send a signal. Tell it, hey, I want to finish. Well, guess what? We have another method. We have the throw method. So I can exit early from the generator with close. And I can send it an exception with throw. So look what happens here. I've now got this try accept block here. So if someone on the outside wants to get out of the current list of weather forecasts, they can do that just by raising an exception. So we've now got this whole API going. So watch this. I can get the forecast. So I can do the same with the primary one, like the prime said. Send 44. Send 44 for the next thing. We're going to raise the exception different city exception. And it gets out of that loop and allows me now to get a different city altogether. Our nano service is available through the simple request response interface. And I can cache data. I can keep state across. I can do whatever I want. Now what if I want to have lots of functionality in our code Q&A time, but I will be in the breakout room afterwards. I just want to get to this last point or two. Watch this. I'm going to combine md5 and weather into the same coroutine. So I'm now going to have my combined generator, and it's going to say, hey, send one for weather and send two for md5 or none to exit. So if the person selects one, if they send one to the generator, they'll get this. And if they send two to the generator, they'll get that. But this is ugly as thin, right? This is terrible. The whole point of having these nano-services, the whole point of coroutines is to break things up. We want things to be small. So I know what I'm going to do. I'm going to refactor it so it's much smaller. I'm going to have a combined generator here. And it's going to say, if s equals equals one, we'll call the city generator. If s equals equals two, we're going to call the md5 generator. Guess what? This will not work. This will not work because how we'll throw, go from our outside generator to this inside generator, how will clothes go from the outside one to the inside one? It will not work. What we need to do is yield from. Yield from is this piece of syntax that no one seems to understand. Everyone's like, oh, that's instead of doing a for loop on something internal. No, no, no. It's so that you can have a generator, a coroutine that has, in fact, a bit other generators and coroutines, and it will pass through the calls to close and it will pass through the calls to yield and throw and yield from. It allows this to be a conduit from the outside world inside. And with this in place now, what does yield from do? Bidirectional communication. So with this in place, I can create my combined generator. I can choose two to get md5s. I can then none back up to the top. I can then choose one to get weather. I can do that. I can even raise an exception. I can throw the exception there. So basically yield from allows me to write these coroutines in a decomposed way, breaking them apart so that I can get them into a more serious kind of place and take them seriously, not have either these gargantuan generators that have lots of functionality in them or just ignore the functionality altogether. Now, I have to say a few words about async.io because everyone in the async.io world says, oh, those are coroutines. What do you mean these are coroutines? Well, these coroutines came first. The generated based coroutines came first. And this is how async.io was originally implemented. Nowadays, we have async.f, we have a weight, we have a whole new set of keywords that we can use. But the basic idea of async.io comes from generators, comes from coroutines. And this is what's known as cooperative multitasking. This is what operating systems used to do back when your grandparents were using computers. Okay, even when I was using computers like in college. But basically, it means that a process, a task will run up to and including the yield that it has there. Now, all this is very nice, but should you use coroutines? On the one hand, they're really useful. They're speedy in-memory arbitrary API. They can allow us to work with large data one chunk at a time and we can divide them into smaller pieces using yield from. But they're not so well understood. It definitely seems weird to many people to use send in this way. And when things go wrong, debugging can be kind of hard. But I think this is an interesting way of understanding and working with certain types of data and certain types of functionality in Python. And I hope that this opened your eyes to how these things work. We still have a few minutes left for questions. I'll be very happy to take them either now or later. And contact me afterwards if you want. I will be in the breakout room as well. Hey, the camera is on and I think you should then head over to the breakout room. Because there was a lot of activity in the chat and we will not have time for any complicated question where anybody can learn something. So just a short reminder that the whole slides for this talk are linked in the schedule. So you can just get them and look at them again. And there's also information about how to get your newsletter, which I really recommend getting. Okay, so let's get you over to the breakout room and after a short break we'll continue here with the next talk.


Hello and welcome back here to the channel. We are staring at the back of an Audi RS4 wagon, that wagon fighter from KNC Giraffe here for today's driver spotlight. So make sure you follow me on all social media, all that's found in the description box below. Let's get to it. So KNC Giraffe sent me this beautiful Audi wagon, all carbon fiber, Nasa energy drinks logo, KNC all over the glass and the seats, all in it, definitely in a very beautiful model. I love the carbon fiber look and I love the texturing of the carbon fiber and everything of that nature. I love how the back half is covered in glass and then it's vented out with the whole back end. Definitely something you don't normally see in a drift car, but this thing is done very well. The model is very gorgeous, got that nice, looks like part shops max and field suspension going on back there and then the interior is definitely, we got a fuel cell safe back there. Looks like a fire suppression or nitrous bottle, it might be both in there somewhere. Definitely a very good and amazing looking model. Oh, there is a fire extinguisher, so that's got to be Nasa. That is a nitrous express. This car is definitely a very gorgeous looking car, but we're not here to just look at it. We're also here to drive it and see how this thing reacts to that big V8 poking out of the hood. This is definitely something I'm excited when he said, would you like to give my wagon fighter a shot? I said yes please. So without further ado, let's go drive this thing. So we are on a tune that he did send me, so we are going to run it how he sent it, maybe adjust boost pressures and things of that nature because I noticed that when we were first, it's down at like 50% boost, so we're going to run it. The car does have over a thousand horsepower, so we're going to heat up the tires, we're a Poshito circuit, Texas, the old Texas scores with the outer zone, so we're going to heat up these next tires that are on here. All this car sounds good. Definitely sounds amazing, so let's get the wheel cam turned on for you guys. Get the wheel cam turned on, get the tires a little bit more roasted up in here. This thing's definitely a big girl, so we're going to need to be careful of that last wall. Definitely a very glossy American flag on the top, so let's go full send. With the setup he sent me, fourth gear, kick it in, reach out to the outer zone a little bit. Kind of come back in, I think we may need to up the boost a little bit for this track. Cut it back across, left foot brake there. End of the wall ride, definitely so much grip in the front, able to pull that back in. I'm impressed. Like for a first run out, that was a very impressive run, and we're going to bump the boost up a little bit for that power alley because I feel like the boost needs to be a little bit higher for that power alley. Then again, the setup is very dialed, the set up he sent me with suspension settings, tires and everything like that. Definitely a very well set up car, a little more boost, kick it in, reach out to the outer zone, should have been out there sooner, and definitely feel like we have the power now to do the power alley, gentle transition, a little left foot brake, all very hard, managed to be able to keep that, that car was able to keep that on that snap, I'm definitely having a blast with this car. I think we need to go up to 100 boost, just to see what it does because well, we have the power, let's just throw it up there, his tune at the 50, 40, 50 boost does feel good and it's very manageable, but let's see what happens when we go. No fifth gear. Got it. Power on command, oh yeah just banging off fourth gear, we're probably going to pop this motor if we keep doing this, don't want to pop this man's motor, it was definitely nice to let me get the keys or the little push button for this car, that is extremely powerful car and it's definitely rowdy, I love the look of it like I said the carbon fiber and you know, lost energy drinks and everything, very Chris Forsberg reminisce, but it's definitely a fun car and I'm super thankful that he allowed me access to this car to give it a rip and kind of have this car for the day. Oh yeah, no handbrake, there was a wall alley, there we go, modular throttle would come back in right on the clip, this car is rowdy. So I've driven a lot of handfuls of different cars but I've never driven a wagon like this and this car is so much fun to drive, I think we need to take it where we always take every car but we're going to try and drift a bank, we may have to go up to 100 boost but we're also going to run out of gear, oh I feel like this car could do it if we put up the gears, let's see what gears we can get into this, maybe we can run a really big bank run on this car, so let's go check maybe into gears, 205, I don't think we're going to go that high but we're going to go up to a 2 or down to a 2.9 and go up to 100% boost, oh super boggy, once that boost kicks in, Texas Miller Speedway we're going to try to run this bank, nope, sorry can't see, these cars are not meant for banks, man I was hoping we'd be able to but the car just has so much grip that I don't think we're going to be able to brake loose, so let's hit Irwindale, see what it can do on the bank, so let's go line up at Irwindale, so we're going to hit up Irwindale because you know this is always where we end every one of these driver spotlights running on my favorite track Irwindale, so we're going to run the tune that he gave us, see how we can do on the banks of Irwindale, I don't think doing 160, 170 miles an hour on Texas was a good idea, kind of biff the car in the wall, sorry can't see, I hope you're not mad, I wrecked you guys the car, but it's okay, we're going to buff out, all right so Irwindale we got to definitely warm up our tires, I keep forgetting always do that, we got to warm up these tires because we do run full damage and tire wear and everything on these episodes to make sure we get full effect because they run that in competition, so if you guys want to get in on the driver spotlight episode you should guys hit me up on discord, so let's go full send Irwindale, the blog you have to start by, that was all me, got to kick it in, oh yeah, oh that holds very nice, that holds a very nice line, we need a little bit smidge more power, maybe up a percentage in the boost but this car gets down, this car's rowdy and fun, it's a very stable car and you know what, you would think because it's so big that it would have this weird transitional weight but the car's pretty stripped out in the back so you know the weight is not much back there so it's very very well balanced and it feels super good, we're gonna up the boost to 60 and we're gonna go for another full send and see what we can do with this car, we're gonna try to get all the way up on that wall, fourth gear, flick in, not as close to the wall as I want to be but higher than the first run, up on the third hash there, right on the front clip, oh almost taking the back bumper off this car, or this wagon I should say, K&C giraffe definitely with a very solid wagon, something you don't see every day, definitely super glad and thankful that he allowed me the chance to get behind the wheel of his you know car and you know kind of give my impressions on it and I can officially say I definitely like this car, it's very stable, very handles very well and it's uh it looks very visually appealing so one final run here for today's episode, flick initiation, no handbrake, running way low on the bank but you know what it's fine, massage your way back up, clutch kick there, no handbrake there, just a little clutch kick and a little left foot brake, oh this car, this car gets done, you don't need handbrake at all in this car, so make sure you guys follow me on all social media, all the travel description box below, once again a big thank you to K&C giraffe for hooking me up with the chance to drive his car, super thankful to everybody who's getting in on this driver spotlight, you guys want to get in make sure you guys message me on discord, so as always I think guys for coming back and watching, I'm EvilRabbit, I'll see you guys on the track.


Putin gives Sergei Shoigu deadline of one month to improve situation on front lines. A Kremlin insider source claimed that Putin reportedly gave Russian Defence Minister Sergei Shoigu a deadline of one month until early October 2023 to improve the situation on the front lines, stop Ukrainian counter-offensives and have Russian forces regain the initiative to launch an offensive operation against a larger city, said US Institute for the Study of War. The insiders claim, if true, may indicate that the Russian military command may be ordering relentless counter-attacks in hopes of forcing the Ukrainian counter-offensive to culminate even at a high cost to Russian military capabilities. The ISW has previously observed instances in which the Russian Ministry of Defence, fearing the imminent loss of Putin's favour, intensified its efforts to purge commanders who offered honest but negative views and advice and pursued unachievable military objectives at the expense of Russian forces. The Russian Ministry of Defence, for example, launched an unsuccessful and costly offensive on Volodar in February 2023 to undermine the domestic Russian informational effects of the Wagner Group's progress in Bakhmut and maintain favour with Putin. Russian insider sources and mill bloggers, who have advocated for Teplinsky, claimed that Shoigu has been focusing on setting conditions to convince Putin to remove Teplinsky from command, which would likely be achievable if Shoigu is able to achieve Putin's objectives during the counter-offensive. One pro-Teplinsky channel even claimed that chief of the Russian General Staff, Army General Valery Gerassimov, had already removed Teplinsky from overseeing the defensive operation in southern Ukraine. The Ukrainian counter-offensive is in an extremely dynamic phase and the ISW is not prepared to offer any confident forecasts of events despite recent positive indicators.


What are you all doing here? Good afternoon, baby seals. This is Sam Vaknian author of Malignan self-love narcissism Revisited and a professor of psychology in the Center for International Advanced Professional Studies Outreach Program of the CS Consortium of University Universities Satisfied then we can move forward into the topic of today's video, which is essentially intermittent reinforcement Now we tend to think of intermittent reinforcement in a very stereotypical way, but actually many behaviors many decisions many choices Have to do with intermittent reinforcement. The middle reinforcement is a very all-pervasive phenomenon in multiplicity of relationships not all of them abusive dysfunctional and pathological but let's start With a definition of course because I'm an academic and academics define before they discuss What is intermittent reinforcement? intermittent reinforcement Involves two people at least but not necessarily only two you can have intermittent reinforcement on a collective level The government can engage in intermittent reinforcement Social media companies do it all the time intermittent reinforcement is when a receiving party aka victim in intimate relationships a receiving party receives regular regular signals messages and treatment Which are cruel? callous abusive disempathic indifferent and so on I Repeat when there is a receiving party a recipient Who is subject to? behaviors or treatments treatment or decisions or choices Which on the surface appear to be sadistic? cruel callous abusive disempathic Etc. Etc. And then Every once in a while There's a display of extreme affection interspersed with the abuse their instances of reward This is very unsettling. It's Discombobulating look it up When you are subjected to an endless stream of abuse You know what to expect You know the rules of the game. You know all the ropes You prepare yourself mentally and physically But what do you do when abuse? is then Gives place to love love succumbs to pain pain follows affection Affection results in hurt. What do you do? When the signaling Is inconsistent What do you do? When you keep receiving mixed signals Information that information beats that contravene each other. What do you do when your data don't fit in? neat frameworks How do you interpret the world? How do you make sense of anything and everything that's happening?     You're inadequate a bed object signaling and then Suddenly it gives place to the most warm empathic understanding accepting Sack or How do you reconcile these two streams of messages? The answer is you don't and it gives rise to traumatic bonding but Intermittent reinforcement Is often described in the literature in a very one dimensional caricaturistic way Intermittent reinforcement is much more deep complex and pervasive than we imagine Let us examine two phenomena false hope false hope giving someone false hope And then withdrawing this hope and then giving hope again That's a form of intermittent reinforcement any time You give anyone a reason to hope a reason to get up in the morning A reason to exist and then you take it away You are engaging however, unwittingly in intermittent reinforcement Another phenomenon which many of you may be acquainted with from my videos is approach avoidance repetition compulsion Repetition compulsions in general, but especially approach avoidance their forms of intermittent reinforcement the borderline personality Frequently engages in this people with borderline personalities order frequently approach and then avoid Because they are subject to the twin anxieties engulfment anxiety versus abandonment anxiety The approach in order to allay to mitigate abandonment anxiety And then they avoid in order to calm down and ameliorate the engulfment anxiety This approach avoidance I hate you don't leave me I love you. I want you dead These messages conflicting messages from borderlines their forms of intermittent reinforcement indeed many partners of borderlines and partners of even co-dependence describe the relationship It's a kind of trauma and the bonding is especially intense Because the person who causes you pain is the only person who can take it away The person who has locked you into a position of hurt and agony and Uncertainty and indeterminacy and fear and stress The person who locked you into this is the only one who's holding the key to release you from it Intermittent reinforcement is a is an attribution error You tend to think that only the person who had mistreated you can make it all go away with a kiss And so There are four types of intermittent reinforcement fixed interval schedule fi Very common in relationships The abuser awards the victim the reinforcement reinforcement is simply behavior Or a message which alters or modifies your behavior when you're subject to reinforcement Which is positive You're likely to repeat the behavior that elicited the positive reinforcement more And when you're subject to a negative reinforcement, it's likely to inhibit the behavior that had produced it or had led to it So the abuser awards the victim a reinforcement think of it as a cookie or a candy So he awards reinforcement after A specific interval A specific period from the last reinforcement and usually it's a fixed interval This is also known as partial intermittent reinforcement So every two weeks on the dot according to schedule There is a tradition of positive reinforcement following two weeks of harrowing harassment and punitive actions And fear and pain inflicted on the victim the victim then learns to survive these two weeks In order to reach the final point where she is awarded with something a candy The abuser Ways for a specific time to offer for example affection or understanding Or attention or listening ear or shoulder to cry on And this causes the victim to display slower reactions after the reinforcement behavior In the presence of this kind of reinforcement the victim becomes Inured more tolerant Inured to the abuse as the time passes. He develops the victim develops abuse tolerance the same way alcoholics develop alcohol tolerance This is the fixed interval schedule intermittent reinforcement There's another type known as variable interval schedule intermittent reinforcement the reinforcement reward the gift the candy the soothing come after A time that is unpredictable A time that is variable from the previous time that had elapsed The victim receives the reinforcement by surprise It's abrupt. It's sudden. It's not schedule. And therefore it is much stronger much more potent Such cases Increase The anticipation of the reward and the affection the victim becomes Addicted to the reinforcement the victim tolerates abuse of any kind from their partner in order to get this spontaneous spontaneous relief Because intermittent reinforcement is about building up your anxiety your stress your fear And then relieving it with a kind word with a touch with a smile It's cruel There's nothing more cruel than intermittent reinforcement except possibly listening to my videos And then there's the fixed ratio fixed ratio schedule intermittent reinforcement In fixed ratio schedule intermittent reinforcement the abuser Delivers an affectionate display after several responses The abuser is actually focused on the victim's response He wants to get a rise out of the victim. He wants to elicit The kind of reaction in the victim that is discernible and visible So the victim continues to produce higher and higher rates of responsiveness Until they get the reward Clinically speaking, this is Pavlovian conditioning Pain is inflicted and it gets attached in the victim's mind to an ultimate reward So the victim learns to actually anticipate the pain Want the pain crave the pain in order to finally Benefit from The offered reward behavior pauses The victim continues the same pattern After the following abuse incident And finally, there's the variable ratio schedule intermittent reinforcement The reinforcement is awarded After a variable number of responses in the variable ratio schedule intermittent reinforcement Remember that the previous variation the previous variation the fixed ratio schedule intermittent reinforcement Is when the abuser provides a reward After a fixed number of responses, let's say five The victim has to respond five times for example by crying or begging or supplicating Or self-harming And then the abuser provides the reward and again the reward could be a smile Could be a kind word Could be a tiny gift or a big gift, but there's always a reward And in the fixed ratio schedule This has to do With a fixed number of responses naturally in the variable ratio schedule The reinforcement the reward the award come after a variable number of responses Once The abuser would comfort you and soothe you and hold you and love you And lick away your tears After three times of crying after three events of crying And then Next time he would do it after two after seven lacrimose incidents There's no predictability. There's no way to tell There's no way to prepare yourself The abuser offers affection faster Or delays the affection at his or her sole discretion And this in turn causes the victim to display a high and steady steady rate Or response upon receiving the reinforcement. All these Have devastating consequences on the body Hormonally and otherwise ultimately These behaviors wear down the victim Victim becomes kind of zombified And much more amenable to manipulation Which is precisely the idea behind intermittent reinforcement Trauma bonding is about control Watch my interview about trauma bonding on this channel Thank you for listening. I hope I haven't traumatized you too much And here's my smile to soothe you and comfort you down Yes, yes, I know. Sorry about that See you next time


So, we have an expression for the osmotic pressure, which is a fairly simple equation to use, but we can work an example, see how it works, and also provide some discussion for what the values in that equation mean. So, for this example, let's say that we have a solution that is 0.1 molar in some solute. It might be a sugar water solution, 0.1 molar sugar water solution. And if our temperature is 298 Kelvin, so our sugar water solution is at room temperature, that's enough information for us now to calculate the osmotic pressure. So the osmotic pressure of that solution is easy to calculate. C times r times t, 0.1 moles per liter is our concentration. The gas constant turns out not to be convenient to use the value of the gas constant joules per mole Kelvin, because what we're going to want out on the left side when we're done is a pressure with units of pressure, units of atmosphere, for example. So it's going to be more convenient if we use a value like 0.08206 liter atmospheres per mole Kelvin. And if I multiply that by the temperature 298 Kelvin, now Kelvin will cancel, moles will cancel, liters will cancel, and I'm left with just units of atmospheres. And if I work that math out, 0.1 times this value of the gas constant times 298, that works out to a pressure of 2.4 atmospheres. So as a numerical calculation, that's not a difficult calculation. The osmotic pressure for a 0.1 molar sucrose solution is 2.4 atmospheres. What does that mean physically? What it means is that if I have two beakers, one with a pure water solvent, and one with 0.1 molar solution, 0.1 molar in some solute, and water as a solvent, that means that the height of this column will be enough that it's generating a full 2.4 atmospheres worth of pressure. Either we can think of it as the height of this column of solution, force generated by its mass, mgh divided by the area, that pressure is equal to 2.4 atmospheres. We can think of 2.4 atmospheres, if I convert that to units of tor, if I multiply by 760 to get units of tor. That value, I can think of it as 1900 tor, or the more old fashioned name for the tor unit is a millimeter of mercury. So this column will weigh as much as a column of 1.9 meters, almost 2 meters high column of mercury, or since mercury is much denser than water, if I were to have that column of water rather than mercury, the density of water is I think 12 or 13 times larger than the density of mercury is more dense than water, so that corresponds to a column of about 25 meters of water. So that illustrates that osmotic pressure is actually a pretty strong force, the pressure with which pure solvent will attempt to pass through this semipermeable membrane to dilute this .1 molar solution will be enough to support a column of water that is a full 25 meters high, so that's much larger than just the size of two beakers in the lab, for example. And that's perhaps not all that technologically interesting phenomenon, it happens all the time in biological systems for example, but we usually don't want to dilute a solution by allowing water or solvent to pass through a semipermeable membrane, if we really wanted to dilute this solution, all we would have to do is just pour some extra solvent into that half of the beaker. Often where this becomes more interesting is in the reverse case, let me go back to a case before the osmosis had happened, so here's two beakers separated by a semipermeable membrane, in this case I'm going to let the heights of the solution be equal at the start, aqueous solution .1 molar in some solute, before osmosis happens this is what the system looked like, if I allow osmosis to happen the solvent will drop and the solution side will rise, if I want to prevent that from happening I need to push down with an additional pressure equal to the osmotic pressure on this side, if I push down with pressure harder on this side than this side, if that osmotic pressure, if that pressure is equal to the osmotic pressure of 2.4 atmospheres then I can keep these two sides in equilibrium. If I push less hard than that, if the atmospheric pressure here is p0 and over here I push with p0 plus pi, I'm in equilibrium, if I push with only atmospheric pressure or atmospheric pressure plus a smaller amount then osmosis will occur, but what if I push with the pressure greater than p0 plus the osmotic pressure, if I push not with 2.4 atmospheres but with 2.5 or 3 atmospheres, I can actually cause solvent to flow the other way. That's contrary to the direction thermodynamics tells us it will spontaneously flow, so I have to provide energy for that to happen, that's why I have to exert so much pressure more than 2.5 atmospheres to cause that to happen, but if the pressure on this side is greater than p0 plus pi, what will happen is solvent will flow in this direction. That process, because it's the opposite of osmosis, is called reverse osmosis. So if you exert a pressure greater than the osmotic pressure, you can cause the solvent to flow from the concentrated side to the diluted side, reverse osmosis. So that's useful, for example, in purifying seawater, in many places around the world with shortages of freshwater and in abundance of seawater like many islands, they purify some of their water by this process of reverse osmosis. They take seawater, concentrate it in some ions, exert a pressure and we can force pure water to flow through a semiperbium membrane to get pure solvent water. Water has a concentration greater than 0.1 molar, it's also not an ideal solution, so the osmotic pressure isn't exactly concentration, we'd have to go back to an equation that used activity to get an accurate prediction for the osmotic pressure required to purify seawater. That value turns out to be 27 atmospheres. If you want to purify seawater, you need to exert 27 atmospheres of pressure to squeeze it through a semipermeable membrane, but in fact that can be an economical way to purify water in some circumstances. So that's the summary, not just of the calculations for osmotic pressure which are relatively simple but some of the physical picture of what's going on. We've now covered four different colligative properties, so the next thing we'll do is compare and contrast them in a little bit of a summary.