Good evening everyone, welcome back to theCUBE, the leader in live tech coverage. We're live in Las Vegas at Caesars Palace, CrowdStrike Falcon 23, the seventh Falcon event. Over 4,000 people here. We've seen a lot of growth in the ecosystem of CrowdStrike. We're pleased to welcome Beyond Identity next. Couple of guests, Jason Casey, CEO. Kurt Johnson, Chief Strategy Officer. Welcome gentlemen, it's great to have you on the program. Thanks for having us. Thank you. Jason, start us off, give us an overview of Beyond Identity. Who are you guys? Why was the company founded? So we are a four year old startup and the inception of the company really was kind of two key ideas.  And solving that was kind of a very obvious do this thing with like a mobile HSM and use what's available in phones and modern laptops today. And the second idea was, well, wait a minute, if I now have a footprint on your device that's actually managing this authentication that doesn't involve a password, I now have an ability to answer other security questions. Are the security controls I expect relative to what you're trying to do present on the device you're actually working from? And that really is like the most important question you can answer from an access perspective, right? Access is the bridge. Everyone drives over to get it data and to get it services. It is the ideal place to answer the question not just who you are and what you're trying to do but are the things I expect on the device that's going to receive the data actually present. That was the original impetus. That was four years ago, fast forward today where we've got more than a hundred employees. We've got, now I'm actually remembering who can I actually talk about and not talk about? We have a lot of paying customers. Some of the big ones you can see on our website. But yeah, this is the use case we saw. Kurt, talk to us about this strategy that you've employed and how the partner ecosystem is really a catalyst for that. Yeah, it's been a critical aspect of our strategy from the beginning is bringing in the partner ecosystem. To Jason's point, how can we provide the highest level of assurance not just on who is gaining access but what is gaining access? And while our application does that very well it was built to design to tie in to the identity ecosystem that was already in place at these companies. They've made investments and identity provider and single sign-on solutions for years. And how do we enhance that and add a layer of security on top of that? Because as we've seen in the news lately a lot of the identity aspects are, identity management started really an administrative task to make it easier for people to get applications, get access to them, not necessarily secure them. So tying into that ecosystem but the reality today is we've seen the requirement of organizations investing heavily in their security ecosystem a lot around detective response. So almost the philosophy and the ideas we expect somebody's going to get in. So now let's find it as quickly as possible and prevent any kind of actions. What we were thinking is how do you take all of that rich signals, that rich data and bring it to the point when you want it most which is when somebody's gaining access? So we really built out the platform to tie into products like CrowdStrike that can read risk signals on the endpoint and make authentication decisions about them. With partners like Zscaler to make that a continuous process because the other big aspect of our strategy is that we're calling it zero trust authentication. First eliminate the passwords. First and foremost make authentication fishing resistant pulling in the device signals as Jason just mentioned but then tying in through third party integrations the rest as many risk signals as we can to make a true determination at that point of authentication that you know exactly who and what is gaining access.  We all hate them.  Across because we have application creep.  Now you're like, another app. Did you download the event app? No, I haven't and I'm not going to. But the ones that we really use are vital. You know, our airline apps, they're critical and we constantly going through lost password, going through the questions that we can't remember the answer to, update the app, close it, re-install it. So what's needed, I mean, I wonder from, you know, if this is even feasible, a horizontal platform that we can bring across the industry and have a common user experience. I mean, it's, I know the big internet companies have tried to do that with single sign on but that doesn't work either and there's a feature rich or lack of feature richness. So is that the objective to create that horizontal user experience? And is that even feasible? So, yes. And it kind of starts with two key observations at least from a security perspective. If you're the average company, 80% of your security incidents have to do with some sort of access compromise. And the two large buckets that mostly contribute to access compromise, credential theft, right? And the second, it's a little bit more technical sounding called the signing full exploits. Maybe you've heard them like man in the middle, man in the browser attacks, those sorts of things. The easiest way of solving credential theft is what if you could ensure a credential couldn't move? Turns out modern hardware now comes with these things called enclaves.  You can create a credential in the enclave with a property that it can't move. Can't move, it's never in memory. It's never in memory, can't be dumped to the file, can never leave the system, never goes through the internet, never touches any of these third parties. So if it doesn't move, you can't steal it. The second category, how do I guarantee that I can't actually interdict the authentication? The weakness of passwords, the weakness of TOTP, the weakness of Microsoft number match authenticator, the weakness of push notification, they all require a human to execute the protocol on the client side, right? It's a machine on the server side. Humans have error rates, right? Maybe some are worse than others, but we all have error rates. Why can't we mechanize the client side of the protocol?  And yeah, your company's going to have a bunch of controls trying to screen this out, trying to screen that out, but they're going to have error rates too, right? It's a probabilistic problem. Doesn't have to be, right? The challenge can be part of the protocol. The challenge can include who the challenger is. The key that's going to assign the challenge can have some associated data saying who the valid challengers are. There can be a bi-directional signature verification and only move forward if the challenge itself is signed by the appropriate person that originally agreed to enroll the key, right? So you can mechanize the elimination of that man in the middle, that man in the browser attack. Those two categories can actually be prevented or eliminated, not reduced, but actually eliminated. So the credentials crisis can be solved. For that, and there's a couple other things that sound and smell and taste like credentials. What is a session cooking? What is an access token, but a password by another name? Most companies implement them terribly, treat them like symmetric secrets, move them around all over the place. Turns out you can buy those on forums just like you can buy passwords and credit card numbers. That can be solved using the same mechanics as well. So our mission, we're a security company solving identity problem. We don't really believe identity companies solve security problems. We believe they solve productivity problems, maybe create security problems. And we think it takes a principled approach to really kind of get there. It's so true.  I was just going to add, Dave, I mean, to your point, the system we created into, you know, when password just became the way to do it, then we had to layer on multi-factor authentication. Somehow we created a process in a system that made it increasingly difficult for the good guy, the end user, to gain access while making it increasingly easy for the adversary to do it. So we created this balance here. And we often say, you know, you don't need to break in anymore, you just log in. And so that is how we've come to accept the fact that we can train that away. I mean, we train people that smoking's bad for you, but I don't know if you walk through the casino. It's not eliminated. So like we need to ship this to JSPO at any time the humans involved in the equation. We've added friction. And we've also increased vulnerability because unfortunately, humans are going to do something wrong at some point in time. What's your vision of a passwordless future? Is that a direction we're going in? No credential of any type should ever move, whether it's a password, whether it's a session cookie, whether it's an access token, whether it's an SSH key, whether it's a GPG key, like all credentials should never move. They don't move, they can't be stolen. Credential usage should always be guarded by policy. As much of that policy that can be baked into something called trusted computing should be, and that's just a fancy way of saying there's a hardware proof that what I expect is happening is happening. There's a log that gets created that I can always validate offline and see if something went wrong. And my only real assumptions in this whole process is that the foundry at Infineon hasn't been compromised, right? So is there a vulnerability in the system at some point? There could be a particular avenue, but it would almost require taking over the chip industry. So the vision for the future, ultimately, is authentication should always answer the question, not just of who you are, but are the things I would expect on your device, action on your device, relative to what you're trying to do? It should prevent credential theft, not reduce it. It should eliminate man in the middle attacks, it should not reduce it. It should be easy on the end user and it should be easy on the administrator. Writing policy to be really restrictive on people that cause problems versus permissive on people that don't is another key part of the equation. So you know, part of what we've been saying forever, it's changing the way that the world logs in. We know there's a few billion passwords out there, so it'll take a little time, but we've really made it our direction. We do this for the workforce, for employees and the applications they log into each and every day. We do it for customers and companies customer facing applications. So this applies equally as well, whether it's a user experience that they love it so they don't have to log in with passwords, they can do it from one device, they don't even need a second device. We'll at the same time making it hardened and more secure for the organization. It's a true win-win, so I think we have that, but as I said, we have a few billion passwords to get rid of out there. Explain why push notifications through SMS for the audience, why push notifications through SMS don't cut it. Sure, there's two reasons. The dumber reason is actually easier to explain, which is I have your password and I'm trying to log into an account and your phone keeps getting a push. You just hit no, you go back to watching TV and Netflix or TV, I do it again, you hit no, I do it again, you hit no, I do it again and finally you're like hitting yes just because you want it to stop, right? And that's called push fatigue.  But again, if you turn it up and you spray, you're going to get success. The slightly more sophisticated, but still you can execute this with a tool that you downloaded in five minutes. That phone, that push notification doesn't have any context with what's going on in your device. It doesn't know, like if you're holding your phone and you're holding your device, there's no concept in that push that the device in your left hand is actually what's actually initiating the authentication. Those are two disparate channels with no shared context.   So you're like, oh yeah, I'll do it real quick. And then you approve, right? With the push or you put your TOTPM that goes through in the side channel. The adversary now gets the release on the access token. They can push it back to you so you still know nothing's happened. But now if they want to, they can jack your session, they can move the token to another endpoint and they are you. They can enroll another device, they can do a password reset if it's a legacy system. There's no shared context. We think this is like what Jason's talking about is the skill of an advanced adversary. You can get these kits available for free and with just the most basic of skills you can spend if they made it a paint by numbers approach. So it's not in a sophisticated adversary. I was talking with a CISO, they had a real incident where their head of treasury got a call from one of their employees because there was an emergency need to wire a significant amount of money and it required the head of treasury's approval level. It was a legitimate claim, a legitimate transfer, a legitimate employee calling them. He just happened to be eating breakfast in the concierge lounge of the hotel. And so instead of going back to his room to his company-hardened machine, since there was an urgent need, just went to the computer in there, logged in with his password, got the push notification, entered it, wired the money, signed out, there was malware sitting on that machine that allowed somebody to see all this and collect all this, went immediately back into that system, wired a whole bunch of more money to the wrong places. So you think it's rare to find it's increased happening just over and over again. Another common question, explain why facial recognition doesn't solve this problem. Oh, so there's a couple of things with facial recognition. First of all, if you just stop with facial recognition, that's kind of a password with another name, it's a symmetric piece of data. So it's in the minute someone steals that data, they can now present as you. There's also a privacy concern, a lot of people don't want, they're biometrics stored on services that aren't healthcare or gov or even in those conditions. There's another technology called biohashing where you take the facial, just call it the data that represents the face, take a random number, you run those both through a hash, it's kind of like salting passwords if you will. There's some challenging issues with those. They're not a substitute for asymmetric cryptography. Asymmetric cryptography, just doing digital signatures is truly how authentication should work. When you do that, the private key doesn't have to move. If you do that on a machine with an enclave, you have a guarantee it won't move. That's really the bulletproof way of eliminating these two classes of problems. Everything else is really just trying to chip it ice. Yeah, big trade-offs. Not to mention, by the way, when you're on a laptop, it's a completely different experience than when you're on a mobile app. No, right. It's just, again, the consistency, I love to what you said, Jason, you look at identity as a productivity problem. Because that's what it is. We waste so much time, we get so frustrated, and it leads to mistakes that we make because you just push on the wrong button. So how do we get to that point where the user experience is that nirvana that you're envisioning? Well, I mean, obviously we want the answer to be call us. But if you're not going to do that, what you need, you need an authentication system that's based on digital signatures, asymmetric crypto, that's actually leveraging the enclaves that exist in all three of these devices on the desk. Almost any device that you could buy is going to have an enclave. Even the cloud providers now provide enclaves in their virtual machines, right? Amazon calls it Nitro. So you need an authentication solution that uses those. It also needs to do something called fish resistance. That's the man in the middle prevention. NIST gives it this really simple name. They call it verifier impersonation resistance. But it's a thing. So you need a solution that does those two things delivered by a company that cares about user experience. And I think that's why the password list has become a very popular thing.  Where it starts and stops the similarities that takes the password away from a user experience. Doesn't take it away from an adversary who can use it. Doesn't take it out of that sequence. So yes, user experience, critically important, but it needs to be combined with all the other aspects. Which is architecture that takes advantage of these capabilities so that credentials aren't moving. I mean, that's the bottom line. That's what I wanted to do. Just to double on what he just said, if you go search for password list, you're going to find 300 vendors. Login through email magic link is technically considered password list. What we're talking about here is like actual secure authentication that has a great user experience. Bit different. I'm sorry, go ahead. No, that's a great point. But again, it gets back to architecture. Actually taking advantage of modern capabilities. First principles. It absolutely comes back to first principles, right? For 10 years, so it's like the blessing in the curse. 10 years ago when this all got started, the best we could hope for was great forensic tools that let us respond quickly. And it's built this whole industry. Now, modern electronics have advanced to the point and authentication protocols have advanced to the point where we actually can solve some of the root problems that were causing breaches or at least initial access back to those two categories. So yeah, technology, architecture is fundamental. It does require principle thinking. You do have to kind of go back to the basics. But at the core of it, it is still pretty simple. Credential shouldn't move. You should have a guarantee they don't move. You should take the human out of the loop. If there's any part of the protocol that the human is ever responsible for, that's an entry point that an adversary's going to study and take advantage of. What's your favorite customer story you mentioned? I'm looking at the website right now, a lot of great names that you think really articulates the value of what's beyond the known names delivery. I'll talk about the stories I won't name the customer. Cool. So we basically have a couple different variations on a theme. So one variation on a theme was customer started deployment, very conscientious, scaled over a very long period of time, experienced an incident, didn't impact any of the devices we were installed on. And then within 30 days, we were on everything. So it was just like we played a role in an incident to very quickly kind of secure the solution. As well as when you have a credential anchored in hardware, whether it's anchored in the adversary's hardware or the customer's hardware, it's anchored in hardware. So you actually know most people have an inventory of your hardware. So even during incident response, you can actually partition the adversary or they're in a VM in which case they can't pass the hardware TPM check.  That was pretty interesting. Another one was discovered by a CISO at one of our own companies. It was a use case, we didn't even fathom. So in our authentication system, we have this big policy engine in the cloud. So it lets our customers basically say, you know, for BYOD, we only want to check a few things but let's limit only to these apps for managed devices. We want to check that, you know, crowdstrikes running and they have a zero trust score of X and all of these other controls. We want to check that the process that's asking for the authentication was launched from a signed executable built by Microsoft or Google and no one else. A customer had started writing policy rules but rather than using actions like allow and deny, they were using these actions called monitor. And what this does is anytime one of these rules hits it generates an event. And then they were basically building a picture of compliance issues across their fleet just using an analysis of this event flow from the policy engine. All of a sudden we realized there's this passive device trust angle to the product that we didn't even think about. So now we've kind of turned around and practiced it to push it out quite a bit. But understanding what's going on in your fleet, understanding where you have hardware issues, where you have software issues, helping you actually prioritize based on what's going on in the world. Where am I going to get the most bang for my buck? What should I actually work on next? And then the other one, less from customer deployments and more from just selling, getting in and showing actual exploits against products and systems. It's been fun actually. It's also been a little scary in terms of like, it's pick a vendor. Yeah. Yeah. I'll have one quick story. One of our early customers, COVID happened, everyone went working from home, everybody accessing from home on these devices. They had to crank their VPN through the roof in order to kind of get some better visibility. Really came and bought beyond identity, specifically to make sure only corporate managed devices were getting access to the applications. It was really that device posture, visibility, the assurance and went full to every employee, every end user. And all of a sudden the end users no longer had a password. He said, he finally got the visibility needed to get rid of having to put all of this through the VPN with multiple hops and push notifications. All of a sudden he started getting thank you emails from his end users who are like, oh my gosh, this experience is incredible. And he said, I've never rolled out a security product in my life and got a thank you. That's for sure. Kudos to you guys. Great stuff. Great stuff. Thank you so much both of you, Jason and Kurt for coming on, sharing what beyond identity is doing. The immense capabilities and progress we have going forward to really combat the credentials crisis. We appreciate your time and your insights. Thanks for having us. Our pleasure. For our guests and for Dave Vellante, I'm Lisa Martin. You're watching theCUBE live in CrowdStrike Falcon 23. We back with our last guest of the day. Stick around.


So, I'm only, this is Jacob, we have been working on these kind of things like compiler for a couple of years now, two or three I guess, and still unfortunately not too many people know about this kind of stuff. And so, we're going to talk a little bit about compilers as an intro and so on, but more specifically, we are trying to get you to understand what is necessary for someone to actually write optimized code, because believe it or not, it's not just a matter of you specifying an option at the compiler command line, compiler tries to do something, but it might not actually be what you're expecting it to be done. And so, you will see a little bit in this direction, but none of that will replace you actually doing something yourself in this area, and there's a lot, believe me, a lot which you can do and which you have to do to actually write highly optimized code. For those who know, well that may be the first question, so who actually works on compilers and not with compilers on compilers, all right, so that's your audience. So a little bit of an overview, so what compilers are, so most of, for most people it's a black box, but they're actually pretty structured in some way or form you can see here. So we have, as a compiler, the inputs are some form of source code, obviously, and for most of the programming languages, there's some form of library, whatever form it comes, including some from the system, so either text form, binary form, whatever. It all is accumulated in a part of a compiler usually called the front end, so probably everyone heard about these kind of things. That's the part of a compiler of the well designed compiler system, which is the only part specific to a programming language. The rest of the compiler, if it is done correctly, is language independent. So for GCC, for instance, this means we have front ends for C, C++, Fortran, but also then for other things like whoever uses this Go and D or whatever, so that, these parts are completely implemented only in the front end itself. The rest is identical. There might be some specific pieces in the rest of it, which is tailored for a programming language, but as in general, it's not. So everything is fed into the front end, then it's passed on to the various pieces. The second piece on the slide, which you see here, is what's called the optimizer. So the optimizer itself is what is the most interesting thing which most of this talk will be about. We don't have to execute the optimizer, but we can immediately proceed to generating code from this, and that part is the architecture-specific part of the compiler. So we have the language-specific part in the front end, and we have the architecture-specific part in the back end. So that knows, for instance, you have X86, you have ARM or whatever, and it knows how to generate code for that. But it spits out in the end what is called machine code, which is what the processor actually can execute. So in the front end, so I have a little bit of an example code, so I took this from somewhere so I don't take this too serious, the code, so everyone knows Euclid's algorithm to actually compute GCD, and that's the code in a kind of a Python notation. I used that for various reasons, which should not be of interest here, so the same thing. So what the front end basically does, that's, as a first step, it's called tokenization. It spits out the serial code of the program, in many cases, as in normal programming language or in many of the programming languages, it's independent of the lines in Python. It's dependent of the line ending and so on, also have a meaning, but in specifically it creates a token for everything, which is of substance inside the source code. So for this specific piece of code, for instance, I mean it can look something like that. So you have tokens, in this case, depth, it's not just a character sequence, it's recognized as the keyword depth, in this case. For things which it does not recognize, they are variables. It says something, oh yeah, this is a specific thing, it's a variable, and the name of the variable is, for instance, in the first, in the second box there, it's Euclid. That's one of the things. So this is the first task of the compiler. It's very boring stuff. If you read all compiler books, they are harping on these kind of topics. Now no one cares about this. We have tools to do these kind of things. The interesting thing is that once you get into the point that we have the tokenization form, it's still a very linear form. We have not yet discovered what it actually means for the nesting and for the dependencies of all this kind of code. This is then expressed in something called the abstract syntax tree, which is an example which you can see here. So there's absolutely no demand that there's a unified form for the syntax tree. Every compiler comes up with its own firm, and some of the compilers have multiple forms. So GCC, for instance, has multiple ways of representing the same information internally. But this is one possible way of representing, for instance, the abstract syntax tree for the program which we saw before. Now we can see this is not linear anymore. We actually uncover the structure of the program by encoding it into this kind of tree form. We see what is depending on what. That's part of the language syntax, and the grammar describes how the compiler actually understands the source code to make this possible. So once we have that, we actually get to the point that we can do the next level, get to a more complicated level, and actually translate this into basic blocks. So after the lexical analysis is done, after the syntax analysis is done by the front-end and perhaps some from the language specific of definitions like that, usually compilers create the control flow graph, which is a directed graph where the vertiges are the basic blocks. Basic block is a sequence of statements. The important properties are that there are no jumps into the middle of the basic blocks and there are no jumps out of the middle of the basic block. You can have jumps to the start of the basic block and then from the end of the basic block you have some branches as well. The edges in the graph are either normal control flow, for instance, you can have a go-to, then it's a single edge, or you can have conditional branch, then you have two edges. But you can have other special kinds of edges, for instance, the exception handling edges are something when an exception is thrown, and that needs to be represented for the optimizations to be able to find out other ways of control flow. For instance, long jump and set jump have very complicated control flow as well, and that needs to be expressed in the edges as well. In this, on this picture you have the Euclid hardware from lowered into simple operations. Various compilers have different forms of the internal representation language, usually it's language neutral, and various compilers have multiple forms of the internal representations. For instance, GCC starts with a code like this after the front end is passed to the middle end, and then this is lowered into a single static assignment form, which is something which has been developed by IBM in 1988, and these days it's used in most of the compilers. A single static assignment form has some very good properties for the optimizations, namely that each variable is assigned just once, so you can stick various properties to these assignments, or as I say, name versions, and this is achieved by adding some subscript version of each variable. So, if you assign to a variable new value, you create a new subscript for the variable, and this page shows some weird functions at the beginning of some of the basic blocks, and those are fined in five, and that's the way how you express that the value, for instance, of A3 is either A2 or A1, depending on which branch branch into this particular basic block. So, the point here is that with SSA we got through this notation the possibility to actually express algorithms, optimization algorithms. So, before we have this, there was really no way for an algorithm to be really expressed as a kind of a formula. We had to say, yeah, we have this index, we have some sort, and if this condition is met, well, then we can potentially perform this kind of optimization. The thing which I showed you before, every single optimization inside this optimizer and so on is a transformation in a mathematical sense. It's something which keeps the semantic of tree completely intact while transforming one tree into another one, where the second one is hopefully easier to compute. That's the whole thing. And when we are defining optimization steps, we have to do this in some way or form, and SSA finally gave us the possibility to actually express this. We can write down the specific algorithms in mathematical formulas. We can say, if this variable is in this set, not in this set, and this condition is met, then you can do the following transformation on the block. That's the great thing about SSA. This is why everyone is using it, and if you're really honest and you really want to learn about writing optimized code, unfortunately, you have to learn about this as well, as Jakob will show us. So for the optimizations, I would note that the optimizations only care about valid programs. If they have defined behavior, then it's completely valid to optimize it away or do anything. So the optimizations are based on the knowledge that valid programs should not have defined behavior. For the SSA form, I would note that not all variables are actually transformed into the SSA form, at least in GCC variables, which are aggregates, structures, and so on, live in memory, and they need some different treatment, and variables which have address taken from them also need to be treated similarly. And you also see here the temp1 and temp2. So if you draw the line theoretically, you can code back and see temp1, temp2 again. Well, the point here is that these variables live inside the block. Their usefulness or their use does not survive the stepping out of the block, and therefore they also don't have to be handled. But once some program is converted into SSA form, basically it doesn't matter that much what the variables actually are. All you care about are the indexes of the SSA versions. In some compilers, the versions are unique in the whole function. Like in this example you have a1 and b1, but for instance in GCC you have a1 and b2, because you can't use the same version for multiple variables. So this makes it easy. You can just... And then after you do this transformation, for most of the things, except for debugging for, you don't care what the variable originally was. It's just something that holds a value and holds it here. And you can hopefully see that this makes things so much easier. So you don't have to worry about the difference between different variables. It's just every single variable gets one value assigned for the entire lifetime, and every variable even after it has one single name. So that's nice. The control program also shows a loop. You can see there's a header with a a1-t node. That's the loop header. And there is a loop latch, which is the basic loop A3, which is the... It's usually a single basic block inside of the loop that is the predecessor of the loop header. If the loop has multiple latches, then some algorithms don't work very well. But it's easier to transform them. So, for instance, in this case, you could think that the two blocks above the latch could have latches directly to the loop header. They can in some form, but you can have multiple latches. So, GCC has over 100 optimization passes, and some of the optimization passes do multiple optimizations as well. And it has also hundreds of optimization options. There is unfortunately no one mapping between the options and the passes. And while we have some infrastructure, for instance, the minus O, some level options, enable some optimization options and disable others, which optimization pass has also some gates test, which says if the pass will be run at all, and those gates can include not just the latch for the options, which control the optimization, but also other properties, like does this function have some loop or whatever else, and some of the passes also have some passes. So, if they have their own gate, and that gate says no, then no pass from the subpasses are run. And that's important, for instance, because you can see that many options, optimization options are, if you dump GCC options or GCC minus minus half or something similar, then it can show even for minus O, zero, many optimization options enabled, but those passes are actually not run, because there are passes with many subpasses which are gated on optimization more than zero. So, this is a little script which I wrote. You can see the address there, you can download it, which tries to summarize this in some way or form. So, this is information which is gathered from GCC. So, the important thing here, the most important thing I want to point out, the blue lines, these header lines, they list all the possible optimization options. There is no O99. There used to be... Well, we parsed it. We parsed it. And that's the point. So, many people believe, because the compiler accepts it, it is there. There is no O99. Believe me. You can see, there are some people who have this in the early, early Linux days. So, we have people who are leaving this and putting this in every single makefire out there. But these are the ones which exist out there in the script. It would help us just discover this. So, this is just a subset of, as Jakob said, we have a hundred of them. This goes on screen after screen after screen to show you. But it helps you perhaps discover a little bit about what the options are for each of these individual ones. So, the thing is that if it's... If you don't like what the specific option, whether it's enabled for your O2 or O3 or whatever you're using, you can enable or disable it individually by using the appropriate option there. So, just use dash f on the new option name or dash f NO dash on the new option name to actually enable or disable it. You can individually do this and GCC allows that. Sometimes not advisable to disable hundreds of optimization options because then you can get into the... Yeah, but for some things, especially when you're running into compiler bugs, very useful. Aside from blaming him, so... So, this is the... GCC algorithm written in C. So, adjust as a reference because now we are going into compiler territory. This slide shows how you can use a dump option to dump actual text files which represent the intermediates, represent the nation of the program at each pass. Those... The graph suboption tells the compiler to also emit a dot file. A dot file which can be processed by job and you can create a picture from that which contains the CFG visualization. So, here... the entry block is something virtual. And... Hopefully you can see the correspondence between the code and also between the correspondence of the... from the previous slide. This is exactly this kind of thing, exactly the same structure. And the compiler can construct this even for a very large one. So, dot comes from the GraphWits project and so on for the package, if you install it. It works reasonably well even for large graphs. And I, at least I don't know whether Jacob is still using, I always use this kind of thing when I'm hunting for things which don't compile to the code which I expected to do. I like it better than the texture representation in some cases. But the one here, you would see here on the bottom there, so it's hinted that's exactly the same information. Exactly the same. The way how it's actually represented at least for the... Well, as I said, GCC has multiple internal representations and one major, one is... which is statements written in two-plied form and that's what you can see here. This is from very early past, right after the CHE construction. There is still no... There's no... But you already have the CHE. We have some other examples later on where SSH information is in there and then you can see also correspondence there. Machine generator part of the compiler. This is a different intermediate language which is at least written, less polite and it's much more closer to the actual instructions but still commonly enough that you can use many optimizations which are common to all the architectures. The textual dumps are numbered from the first pass to the following ones and the T1 indicates the game pool, the tree. There are also I dumps which are for the interprocedural optimization and then there is R which is for the RTL. For the game pool dumps, the language is C-like except the basic quotes are expressed there and the phenotes are written as comments after double hash or debug statements are written similarly. It's not exactly C but... If you want, you can nowadays write programs in game pool. So this shows we have many policies and the slides. So at the top you see there, it's OFAS, it's a Euclid program again compiled with this except that it uses a little compiler plug-in which I wrote again at the bottom there, you can get it which just prints the name of the pass. So this is a subset, it's not even everything. It's a subset of the passes which GCC does if it runs with audio optimization or almost audio optimization enabled. Again, not all passes do... Sometimes passes exit early and don't actually walk the CFG or the intermediate language. Other passes do walk it but don't find anything interesting there. Well, in this program specifically you can imagine there's not that much to optimize. But still they're running. These are the dumps. Again, the list is incomplete because it doesn't even include I... You see at the bottom there, there are 252 files after I do that in the directory. So huge amount. So this is a dump from the end of the... Gimple or three optimizations when we remove the SSA form. Some other compilers keep the SSA form even longer until it reaches our location. We do not, but we still keep the basic blocks around until end of compilation but just switch the language in the basic blocks. What you can see there is there on the edges there are probabilities. Those are either guessed by various algorithms like if you are testing for non-null pointer then be predicted as likely that the pointer is non-null and many other reasons like that. Or the probabilities can be measured actually. That's what we call feedback directed optimization profile guided optimizations which is something which is very useful especially for compute intensive applications that when you actually build them that you build them twice once with special option that tells them to gather this information then you run the application with some typical workload and this generates some data which counts for the different edges and other information like the string copied by string instructions and so on. Then you run the compiler again and it uses this information instead of the guest information this part of code is code and so can be optimized for size and this part is important so let's vectorize it and let's do other optimizations. It's quite important also you have the possibility to overwrite this so for a long time we have built an expect as a compiler built in and C++ 17 has likely unlikely attributes which you can just use and you're overriding whatever you get and that information will then plugged in I think it's 90% 10% or something like this then you will find that in the branches and this is quite important also for you to look at so if you look at your programming and you know where the hot loop is make sure that that part actually is annotated appropriately in the compiler-generated data structures though because as Jakob said the compiler will use this information to guide the level of optimization we are doing so not everything gets heavily inla out loop unrolled for instance or vectorized or something like this this would blow up the code size it would also potentially make things for some situations actually worse so the compiler is concentrating the heavy duty optimizations which might require a lot of compilation time might require a lot of memory at runtime to those part which it knows will be executed more often so if you have a loop which is then always there and you have an if which handles an error condition which almost never happens you never want to spend much effort on that and you can mark this explicitly or through PGO and so on have this automatically uncovered by running your code and then recompiling using the information so this is something which is not new so the PGO staff, the profile-guided optimization part have been in there for 15 years at least something like that so that's something which everyone should already know about and use in their programs the only thing is that you actually need to have a representative workload for you to actually run on the code before you do the recompilation and that's what most often breaks things so sometimes if you run the test suite then the test sheet covers the common cases and not the usual workload on the other side if you write just a simple benchmark then the benchmark will be fast but the other staff the workload needs to be typical for the application and what GCC does is also an optimization which splits the publishing into multiple code sections one is for code code for the code code in that case as well for the cache iCache you want the code code to be together so that's the the title, sorry the book that's this, this is the only real book which I still know which handles really SSA as an optimization and so on so if you're really interested in this I think that's still the book to get it's quite over 2004 very simple examples of optimizations dead code elimination is removing non-useful code there are actually two kinds of dead code elimination in that function one is the return F can be optimized by removal of unreachable code basically you create a basic block and then you find the guarding condition is never true because unsigned value is never smaller than zero so you throw it away immediately and other dead code elimination is afterwards because you have the 10th variable which is assigned some value and you never use it and it has no side effects so you can be thrown away as well dead store elimination is usually for memory in this case it's more like dead code elimination again but if you thought about L as being memory something that has way in memory then the value in memory you write A2 is then overwritten by writing the result from the function to and then it's not used even until the end of the function so you can again remove the stores of course if you don't know about the function whether it has any side effects you can call it common expression elimination is something which is done in several places in GCC both on the GIMPOL and on the RTL as well it's done through some value numbering and finds out that the two expressions are common and can just use a temporary on the GIMPOL it's usually called full written full written non-seal elimination partial written so in this case what I oftentimes see people they're making that code ugly because they think oh yeah I don't want to write something like this again although this might to someone who's observing the code easier to understand introducing yet another obscure variable somewhere on something like this so in general you don't have to worry about this the compiler is pretty good at doing this so this is an optimization which has been around for decades and we are pretty good at that and then it shows also a possible optimization that if you compare the if you test for a range of TMP variable then can be done more efficiently than two comparisons in this case by subtracting the low value and comparing actually the comparison should be done already in unsigned type so that it doesn't feature undefined behavior like there are there are other optimizations for the comparisons of a set of values like you can use and not for the subtraction or after it and that can cover even bigger sets of so this just shows the comments of expression elimination so there is just a single underscore two I haven't mentioned that for writing SSA variable in GCC is that some variable name underscore and the variation number and if the variable name is missing then it's anonymous SSA version just doesn't bind to any variable it's temporary and at the start of the function there is a list of the types and you see here the SSA form has a phi node here at the end you see phi it comes I'm the first node comes from it's a value 12 which you can see is in basic block 3 so BB basic block comes there and the second one is 0 which comes from 2 so it's an absolute value it's not a variable so this is in this notation also possible you can directly translate that into this in the code which you see on the right hand side so this is actually pretty easy to understand once you get over the hamper with this strange phi stuff even without the powers it's actually not very hard to transform it into valid C variables are declared and you can use just the valid variables and you just need to find out something so this shows another optimization which is value range propagation GCC that is only for a subset of types like integers or pointers to some extent it doesn't do it here for vectors it doesn't do it for voting point values in some cases might be interesting as well so what the value range propagation figures out is that because of the testing and if in the alismog the value of A is always smaller or equal to 3 in that case it can optimize the way one of the cases from the stage because it will never come and another thing which is thus it's able to build a value range for the A at the return statement because if it's initially bigger than 3 then it will be bigger than 0 and if it's if it's initially 3 then it will be 13 and if it's otherwise it will be 0 you can see it in the final see the final block it has A3 or 0 or 13 so the compiler does a pretty good job and so the A A is smaller than 0 that can be optimized now we can actually do the same thing even if there is A plus plus equals 3 and the reason for that is that this is done in teacher type in the side in teacher type and in C C++ it's undefined behavior so this is an important thing to see so I put this in deliberately because people don't expect this so the optimizer as Jakob said at the very beginning we are only doing the transformations based on the assumption that the code is correct incrementing an integer variable so that it wraps around is an ill-formed program and you cannot expect anything from the optimizer at that point it will transform it to the code as the previous one but all of a sudden if you look at the variable A at that point it will actually be negative but the compiler will treat it as positive you are writing bad code there are some use it but these are lousy programmers but that's the thing so if you can't handle that 0 is your friend so live with that just some positions as well alright we have to go but for this I would mention that we have the sanitizers if sanitize it would something in UBSEN to find the front-end the back-end do you mean side or does it hold for unsigned for unsigned the braking is well defined at that point so if you want to make it well defined just cast it to unsigned and cast it again to integer then it's implementation defined in C in C++ 20 well defined forces the choose component that everybody sees alright so this is another thing so when we are looking at optimizations and so on often times it's not obvious when the compiler which of the compiler passes and so in GCC 9 one of our colleagues has added an option called GCC itself which writes out yet another file which you can get in this case it's based on the file name .opt .json.js so it's a compressed .json file which often times has tremendous amounts of data in it unfortunately we are at the very beginning of using this file but it's really not usable by looking yourself looking at the code itself so I wrote yet another script the third one today which you can also get called .opt mark in this case so if you get that and run it on one of these .json files which are generated it annotates the source code with the information from this file and this gives you that information about what the compiler actually rejected in this case for instance the red lines so red lines with this thing oh yeah this is a negative thing we have to do this operation for some things it actually would show yeah I did the following optimization the other ones are annotations which the compiler currently spits out so we are at the very beginning of using these kind of things so this is something which we have to work on a lot more for GCC 10 at least so I will have to work with what David actually make this much more usable don't expect the word from this right now sometimes it works sometimes it doesn't so because the compiler doesn't but well if you find some use for that or if you find some problems with this so let me know what David Malcolm is the one who actually wrote the other code so we are actually looking in there so we have now a couple more slides where this so we are supposed to finish off so but we already took some of the questions so let's go on a couple more minutes here are a couple of examples of optimizations so the first one is called tail calls so anyone who has ever done functional programming specially scheme something like that knows the term because there is a well defined mechanism this is that a function which calls another function as a very last operation can in theory be generating code for which does not return to the intermediate function so in this case the function f so that's a good thing so you see on the right hand side the second block there see one fi that's the implementation of the fi function for the correctly performed tail call optimization so instead of using the call instruction it actually jumps to the other function after doing something so often times you have to actually work to make this work so for the second column on the right hand column here you see that there is some additional operation which is performed on the tail call function and so on in this case of course we cannot perform tail call optimization because we have to add one to this so this is nothing the compiler can handle by itself you have to do something so if using tail call optimization can be really really useful because if you have lots and lots of recursion which looks like recursion in there but you use tail call optimization you don't use up the stack so this is really important in simple situations and languages like scheme actually demand tail call optimization but to make it work you actually have to rewrite the code a little bit so but there are other things which are standing in the way and this you only discover if you're looking at the code so take a look at the code on the left hand side again it looks like normal tail call operation so similar to the code which you saw in the previous slide so it has tail through something like this but there is a little bit of code in there in the middle so at the beginning of the function and that code screws everything up because after the tail call and so on the compiler thinks oh yeah I have to generate some code to actually unwind the stack frame one that Jacob earlier today this optimization in GCC actually doesn't escape analysis on which variables escape and if they escape like in this case then then it stops doing the tail call optimization but the thing is that while the string escapes it actually is that it is not alive because the scope in which the clarity goes out so the the so the destructor for the string could have been caught before but it isn't GCC doesn't handle it so it prevents tail call optimization so again this is something which you have to do explicitly so if you rewrite the code slightly in this case and this comes from a real-world example I did this for a project another project out there so I can't continue basically this kind of patch where I then said so I split out the code into a separate function specifically in this case in that case it was some error handling but also to get tail call optimization in this case I have a function which I mark as not inlinable so and in this case I'm actually getting the code which you see here it's much much shorter than what we had before so this is possible but it's oftentimes not possible automatically so you have to actually look at the code because you have no information from the compiler actually saying oh I didn't do this in this case you already see so for this for the talk so I came up with all kinds of example and Jacob as well and everything why didn't GCC do this automatically why didn't it do it automatically it's bug-fighting bonanza here so you saw this kind of code before I had this the case statement so what if you know that in the function G here the parameter A actually can only have a couple of values but the function F in this case here is a general one for instance this can be error handling but in some cases you might know well the error which you get here can only have the following error codes so how do you do this so the full code is actually pretty long it has a conditional jump in there and has a long table but if you just add a little bit of code in there so the highlighted pieces here which you see here there's a compiler intrinsic called unreachable which tells the compiler that if it gets in here well basically this cannot actually happen this branch is dead which means that the other part the else part so the consecutive ones for those the condition of the if actually holds this is a way to tell the compiler I know something about this variable we have contracts coming up so that's a different thing but this kind of thing exists today and they can have a remarkable impact on the code which the code quality you are getting out of compiler again the sanitizers are able to catch it because instead of having something well they transform the built-in unreachable into a library called which kills the application so why would you use another compiler you're talking to GCC guys that's nasty talk alright so last class of things we are talking about is vectorization yeah so you do that so this is a loop which can be on many torches like in this case but we first also the code is smaller we first 128 bits vectors it can be vectorized either way but if you don't tell the compiler that the res and a arrays or whatever objects they may point to don't overlap the compiler has to insert some additional runtime checks which check that those two arrays so you see there in the prepare loops in the prepare loops you get very large code and some runtime check but in many cases you know that those two don't overlap and there are many ways written in this test case how you can tell the compiler about that she has the rest rates but we have underscore we understand that or you have prime mass so this this is one of the differences between cc++ and Fortran and if people come from the Fortran side they forget about restriction get bad performance because in Fortran you cannot have overlapping objects that's why sometimes if you try hard in c++ you still don't get what would you get so until you see why we are having on this the first three instructions there they have a P in there and that indicates that these are vector instructions and actually performs multiple instructions at the same time so in this case two doubles in this case but you can have it more and if you use the full AVX512 or AVX5256 you get even more out of this but then you have something after the loop this L3 label which you see here this is the cleanup part so this is one and a half an odd number of array elements then you have to do something on the scalars and that's what happens there but again if you know that there will be always a multiple of 16 or something then you can again tell the compiler about that using for instance the built-in on the chable and it will be able to optimize the way the scalar loop idea is that important so we have to go to the next slide I think we have just a couple more examples on vectorization so we have the possibility to have functions like square root and this kind of thing there are on Linux at least there are parallel versions of that so in this case we don't even have to do this because it's not the library function it's an instruction on most of the architectures but for things like sine, cosine tangent and exponential logarithm and so on which do that's the computation of the values multiple times and we can still paralyze these loops completely so this works really well nowadays but the test case shows that if you try it with for instance O2 or O3 it actually does not work because post-exit I think mandates that the square root sets R now if the value is smaller than 0 and that's very unlikely case and that's why GCC normally for the scalar code uses the hardware instruction and then just compares the value against 0 and if it's if it's smaller than 0 then in some code code actually calls the original function to do the kernel handling and that's what breaks the vectorization of the space and that's why you need to use O fast or something so F fast and so no O fast both work around these kind of things and that's another one is another one so we'll make the slides available there's only one more slide there so hopefully you get an impression how complicated this is actually right optimized code and how hard the compiler actually works behind the scenes and to actually verify that the code the compiler generates for you actually corresponds to what you think there's no way you have to either look at the Gimbal code or just magically trust the magic of the compiler doing the right thing all the time all right hopefully you got an impression so thanks


Hello everybody! In today's video, I'll show you my top 10 new features in Windows 10 19.03. If you need to recover deleted data, view or restore removed browser history. Hetman software products will help you. Follow the link in the description, download the necessary program for free, install it and analyze the disk. The utility will show you the data you can recover, so you will be able to view it or get it back. In our channel and blog you will find solutions to any problem, from installing an operating system or configuring it, to fixing possible bugs and errors or optimizing mobile gadgets. Our specialists will answer any questions you ask in your comments, under the videos or articles. Another update to Windows 10 version 19.03 is already available for download and installation from the Microsoft official website. As usual, it represents a set of new functions and features and you might find some of them really useful. For today's review, I selected the 10 most interesting ones that affect interface, settings, new functions and other novelties. So let's have a closer look at them. Let's start with visual changes. As you may have noticed, the most obvious change here is the new light theme. Nobody is the default theme for common user settings. While previous light themes still had some of their menus in darker colors, now the entire theme looks well balanced in color and shade. If you don't like it, never mind. The usual theme with light windows and darker system panel is still there for you. Dark mode in Windows 10 doesn't look too well yet due to a number of third-party apps which don't support it. On the contrary, the light theme looks more balanced and natural. Microsoft have also changed default wallpapers for Windows 10 so that they look more suitable for the new light theme. Also, some fluent design elements have been added, the transparent start menu, notification center, shadows and so on. You can change these settings by opening settings, personalization, colors and checking the corresponding option. In addition, now Windows 10 has got a reserved storage. The disk space allocated primarily for a smooth upgrade process. Previously, you would often hear complaints about computers suffering from update errors due to low system disk space and the difficulties users faced when trying to recover the operating system after such errors. Also, this storage is used for some third-party apps and temporary system files. Find it by going to Settings, System, Storage, System and Reserved. Some computers that upgraded to Windows 10.0.3 may not have the reserved storage, as in my case. To enable it, open the Run window and type raggedit and follow this path. Double-click on the key with the name Shipped with Reserves and change its value to 0. Click OK, close the registry editor and restart the computer. As you can see, now this feature is enabled. Like in May this year, Windows 10 developed a new feature, Windows Sandbox. It is designed to save the trouble of worrying about running unknown executable files on your computer. Sandbox is basically a light virtual machine that allows to run and test applications in an isolated environment. Actually, this is a safety-type feature, so after you close the tested application, all Sandbox data will be removed. On this feature, you don't need to set up a virtual machine, as most power users do. The computer should support virtualization and bias, so remember about it. Meanwhile, this feature is available in professional and enterprise editions of Windows, as Microsoft believes options like that are more in demand among advanced users rather than everyone else. What is more, a freshly installed Windows doesn't have it. Sandbox needs to be added through control panel as a separate feature. By default, Sandbox is disabled, but turning it on is extremely easy. Go to control panel, program then features, turn Windows features on or off, Windows Sandbox. After installation and restart, the Windows Sandbox shortcut will appear on the start menu. One of the best new features in Windows 10 May 2019 update is recommended troubleshooting. This function lets the operating system fix automatically many critical issues on your device. For example, it can automatically restore default settings for critical services, change system settings to match your hardware, or adjust specific settings to keep your device working properly. Fixing critical issues is completely automatic and cannot be disabled. So you can disable this feature, you can use the diagnostic and feedback page to manage how the feature works. Just ask yourself, how many times have you realized you forgot to change the active hours to prevent the computer from suddenly restarting and installing updates while you are working or playing? Now, you can take this burden off your back. Just enable this function and the operating system will configure it automatically based on when and how long this computer is typically used. To enable this option, open settings, update in security, change active hours, adjust active hours for this device based on activity. Finally, Microsoft heard Windows 10 users' complaints and gave them more control over update management. Now, all users can pause updates for a week and they can even choose when exactly to install the latest large update. Nobody is possible to keep to the current version of the operating system and receive monthly security updates while avoiding the need to install the latest functional builds. Actually, people have long been able to pause Windows 10 updates even before that, but they had to be using Windows 10 Pro only. So this change is especially significant to users of the home version, as large updates are not always stable enough. Microsoft has also changed the principle of allocating disk space for Windows updates. Some updates could not be installed if the system disk was low on space. As I said before, now the operating system can reserve about 7 gigabytes of disk space for Windows update service. If you ever wrote a text containing some special symbol for characters, you know how inconvenient it can be to remember the alt key codes or to search the Internet for the symbol you need. Beginning with the May 2019 update, you can quickly find and insert the symbol you need into the text or a messenger in social media. To open the updated MLG panel, just press the key shortcut Windows plus. This MLG panel contains a new feature to quickly find and insert symbols and even car emoji that isn't face characters. For your convenience, there are symbols for punctuation, currency, geometry, math, Latin and language symbols. In addition, the operating system will remember the ones you pick the most often and put them into a special tab, where you can find them even faster next time. The search function is not new to Windows 10, but in this version there are huge changes. Microsoft separated search and Cortana in the Windows 10 test bar, which is good news for those not too fond of the voice assistant. From now on, Windows will process voice queries separately from typing text in the search field. Windows 10 will use the system-integrated search function for text queries and Cortana for voice queries. By the way, the new interface shows popular apps, recent actions and files, as well as options to filter stuff by apps, documents, email and web history. Generally, search has retained many of the older things, but now it will search across all folders and connected drives. It looks like Microsoft will be focusing on this area in the nearest future, and new updates will give us access to even more powerful search tools. In addition, you will find a new settings page to configure all search aspects, including a new setting that allows you to search virtually every directory, and not only documents, photographs, videos and desktop as before. Step-by-step, Microsoft enables Windows 10 users to remove more and more shareware apps that come supplied as a part of the operating system. In version 1903, you can disable such applications as group music, mail, calendar, movies and TV, calculator, Paint 3D and 3D viewer. By now, there is no simple way to remove programs like Camera or Edge, but with your Microsoft's browser switching to the Chromium engine, it's quite possible we will see the magic button for Edge one day. Visit our channel to watch a good video about removing Windows 10 built-in apps. Check the link below. Among the minor improvements worth mentioning, I'd like to note a new brightness slider. It is available in the Action Center and lets you adjust brightness in a second. The stool is supposed to replace the tile that allows switching between several preset brightness levels. So now, you can easily set your screen to, say, 33% of brightness. This option is available to laptops, but if you use an external monitor, you are unlikely to find a slider in the notifications area. Of course, this is by no means the complete list of all new and updated features in Windows 10. If you find something new and interesting that I missed today, you are most welcome to leave a comment. And that is all for now. I hope this video was useful. Hit the Like button and subscribe to our channel. Check the bell button to receive notifications about any future videos, leave comments to us, questions and share your opinion. Thank you for watching. And good luck.


This video is for all the graduates out there. Happy Nursing School graduation fall of 2022. I was asked by my latest students at San Diego City College to give the keynote speech at the graduation, but unfortunately I couldn't be there in person. So I thought I would make this video for them and for all the other graduates out there and give my keynote speech right here on Nursing School Explained. You've worked hard for the last few years, not only in Nursing School, but also during the prerequisites. You've been through COVID, you've been through modified clinicals, modified classroom, online learning, and all of this might make you feel a little bit insecure about your nursing career. Have I received all the training that I can possibly get to be there for Nursing School? And there's a quote that I found that really exemplifies nursing to me. It says, the character of a nurse is as important as the knowledge they possess. This is by Carolyn Javis. And I think it's very true because nursing is a lifelong learning job. So your knowledge is very important, but also it's defined by your character. So as you go out into the world after you pass your NCLEX exam and you find your first job, maybe it's your dream job, maybe it's a good first job. But remember, nursing, there is a lot of jobs out there and a lot of different ways to do nursing. So even if you don't get your dream job first, keep looking and keep getting out there and keep persevering because you have persevered through these last few years in Nursing School and you made it. You are here today. There's always lots of options and lots of demand for nurses, new graduates as well as experienced nurses. And when you go out into your new job, be confident that you have the skills and what it takes to be a nurse because you have succeeded being through this rigorous nursing program. But at the same time, don't be overconfident.  So it is okay to ask questions. Nobody's gonna know all the answers. Every experienced nurse always learns something new. So don't be afraid to ask questions whether it's to your preceptor, your coworker, a fellow nursing school friend who might work at the same unit with you or maybe they're not even working with you but always ask questions. That's how you learn and how you become better at this job. And also accept and offer help. We know that nursing is a team sport. Nobody works alone. It all depends on the quality and the ability of your teamwork. So ask for help if you don't know it but also offer help if you got done with certain tasks already. Don't be afraid to do that and also show appreciation for your fellow teammates whether those are other nurses or nursing assistants, transporters, physical therapists, physicians, nurse practitioners, it's a whole team effort.  It's gonna serve you well.  So that SBAR report that you've heard of for so many years now it's gonna come very hand in very handy. So the communication be very succinct. Make sure you have all the information that you wanna communicate and communicate very clearly and calmly. The prioritization is going to become more comfortable as you continue in your nursing career and as you become more confident in the department that you're working with and in this new role. And then one of the beautiful things about nursing is that we have the ability to participate in lifelong learning. So learning is going to be a continued process. Initially it might be through a new grad program on the job training, certain specialized classes, maybe ACLS and PALS and trauma nurse or whatever it is that you decide to work in. But then there's also the ability to get an advanced degree if that is what you want to do. So be open to this lifelong learning. Maybe if it's not an advanced degree but still look at those continuing education units and those classes that are offered to you because there's always something new to be learning patient care and that's one of the beauties of our profession. Then make sure you take breaks. If you decide you're gonna work at a hospital, you might work 12 hour shifts and those are heavy shifts. They can be very tasky and taxing on your body, on your mind, you're running around before you know it. It's two o'clock in the afternoon. Make sure you take some time and take some breaks, not only to take care of your physical body and those needs such as drinking water and eating a snack but also to take that breather and step away for a few minutes from that patient care and make sure that you refresh your brain as you're continuing through the shift maybe in the afternoon. Take care of yourself. And that includes taking care of your physical, your mental, your emotional wellbeing. And it starts with the very simple things that we tend to teach our patients a lot and that includes making sure that you eat well, a well-balanced diet, that you move your body in whatever capacity suits you and that you get enough rest and sleep and also get out into nature whenever you can to balance those demands that the nursing profession brings with itself. Cause really if we don't take care of ourselves we're not really able to take care of others.  Be kind to your patients, to your coworkers, to your loved ones at home that are also now starting or adjusting to this new role that you are in. And be kind to yourself. Again, the character of a nurse is as important as the knowledge they possess. So go out there, share your knowledge, share your characters with the world. Good luck, you've got this. Congratulations class of 2022. Go City College.


This study found that wave-cycline prage had comparable diagnostic performance to conventional prage for detecting and diagnosing enhancing intracranial lesions. It showed improved image quality and reduced scan time compared to conventional prage. This article was authored by Hianji Oh, Yang Hee-Yim, Mi Sun Chung and others.


Hell yeah, what's up guys, it's CursePike, my friends call me Bigsy, back in action today, we're in HitFilm, the free video editor, and I'm gonna show you how to adjust audio, including how to make your videos louder, quieter, and how to make sections and different audio tracks, different levels of loud, so if you've got multiple voices on a game recording, for example, you can increase one track and decrease the other track, let me show you what I'm talking about here. Here's where the old slider put the playhead at the beginning, and as I slide through, there you go, you'll see that I've got audio, if this is too loud, let me show you here.  If something is too quiet, for example, one of the people on your voice call is just not talking loud enough, just really lift the line up, and I lift it up, it can go to 12 decibels, which is quite a bit, so if I was to hit play here, and I move it through, you'll see that it's way high in the meters here, so that's the first step, let's go ahead and lower it down to a lower rate. The next step is if you want specific sections of the audio to be louder, as opposed to the whole thing, so this does the whole track all at once. There's a couple ways to do it, but I'm gonna show you the best way.  Go ahead and get that crosshair, and then left click, and when you do that, you're gonna see that it's applied a point. This is basically the ability that we're gonna now do what's called keyframing. So if this is the part where I think it should go quieter, and I think here's the part where I want it to end to be quieter, like this part here, this part now, I want it to reduce, so watch this. Hold on, I'm gonna put a third point right here in the middle, and watch what happens. I'm just gonna drag that point down, and you see what's happening? I'm going ahead and decreasing and increase. Once you have three or more points, you can increase, decrease the loudness of your footage in specific areas. So if I was to scan through this, loud, quiet. Very quiet. You'll see it on the meters here. This is how you do excellent audio editing and make your video sound professional, and make all the voices the same levels inside HitFilm, a free video editor. Thanks for watching guys, ton more stuff coming up. Stay tuned.


In the previous video, we proved that every cyclic group is up to isomorphism determined by its order. There's only one cyclic group for every possible order you could consider, both finite and infinite. Well, what about other families of groups? Could we classify finite abelian groups up to isomorphism, just like we did with cyclic groups? And the answer is yes, finite abelian groups will be determined up to isomorphism as direct products of cyclic groups. And that's something we'll do later on in this chapter, not in this lecture right now. The question of classifying finite non-abelian groups up to isomorphism is a much bigger task. Up to the present, this is not done. In fact, the state of the art is that only within the last few decades have group theorists been able to classify finite simple groups up to isomorphism, which the simple groups a term will define later on in this lecture series, not in this lecture, though. Simple groups you can think of as the atomic building blocks of finite groups. And so we've only barely determined all of the atoms on the periodic table. Coming up with molecules is gonna be much, much more difficult. Even classifying finite P groups is still a very, very unsettled question in group theory. And so these topics take us way beyond what you would see in a first semester algebra class. Very important topics, but we would be insufficient to be able to prove them right now. In the meanwhile, though, we will prove the very first so-called representation theoretic theorem of group theory, known as Keighley's theorem. I've sprinkled here and there things which I refer to as representation theory, but Keighley's theorem is really the first step towards representation theory, which as I've many times in the past said that representation theory is like equipping group theory with linear algebra. The way we're gonna try to mention it right now is representation theory, a very active research branch of group theory. It aims to represent abstract groups as more familiar groups such as cyclic groups, permutation groups, matrix groups, we could call these concrete groups. And so the advantage of representing a group as a group of matrices allows one to employ linear algebra in the study of groups. By representing a group as a permutation group, we can use things like combinatorics and group actions to help us better understand the abstract group. So similar benefits exist for representing abstract groups as other concrete ones. So Keighley's theorem, which we will prove in this video, allows us to represent every group as a permutation group. This is a very useful result in many situations. In some regard, it's like almost too useful that we actually never have not to use it. It's like that perfect gift you got for Christmas, but it's so perfect. You don't know what to do with it. I know that might not make any sense, but what it basically means for us is that if you can prove something about the symmetric group, it's almost like the Holy Grail, because in some respect, it proves it about every group. And because of that, it almost becomes too grand to prove certain things because otherwise you cover all groups at the same moment. So I digress. Let's prove Keighley's theorem in this video here. We're gonna do it in parts. There's two limits I wanna prove first because the limits actually have some broad ranging consequences. And then we'll prove Keighley's theorem as following those two limos. The first one, essentially, we've already proven it in this series many times, but we're gonna prove it officially right now. Let G be a group with an element little G inside of it. Then we're gonna define a map. We're gonna call it lambda of G, which is gonna be a map from G to G. And it's gonna be given by the rule lambda G of X equals G of X. So this is the left multiplication map by G. Or as I've referred to it in this series earlier, this is the left translation map. All right, translation, I ran out of space there. Analogously, we could talk about the map rho of G of X, which would be defined to be X times G. This is called right translation. And I want you to convince yourself that everything I'm gonna say about left translation, that analogous statements could be set about right translation. We're gonna focus on left translation right here. Again, just for the sake of argument, we need to pick one. So in this lemma, we're gonna prove that left translation by G is a permutation. So what is a permutation, after all? It's a map from a set back into itself, so the domain and codemand are the same. We have to prove this is a bijection. So it's not too difficult of an argument. Let's go through it. So we have to show that phi of G is bijective for any element G. G will be arbitrary so that when we prove it for G, we'll take care of everything at the same time. So let's take two elements inside of the group, X and Y, which might have nothing to do with little G.  We wanna prove that it's one to one. So lambda of G of X is assumed that's equal to lambda G of Y. Well, by definition, that means you're gonna get GX equals GY. But as we have a factor of left on both sides, we can cancel the X and the G, excuse me, we get X equals Y. So left cancellation shows that this map will be injective. Now, if this was a finite set, you'd be like, oh, an injective set here would have to be surjective at the same time. But I wouldn't want this argument also to apply to infinite groups. So we need a supply argument for surjectivity. Well, okay, imagine you have X. This is our target. Who's gonna map onto little X? Well, we're gonna take G inverse of X. Well, notice that lambda G of G inverse of X. This will equal G times G inverse of X, which equals G G inverse of X, which equals X. And so this is gonna turn out to be surjective. And therefore, lambda G is a permutations, both injective and surjective. And like I said, we could also talk about these the same argument would have worked for right translation, which you'll actually notice that row G of X I defined. Despite what I said earlier, I actually could say X G inverse. There's a little bit of advantage of doing an inverse sign there. But don't worry about that too much in this conversation. Again, we're gonna focus on left translation. This G inverse really comes into play if we wanna talk about the regular representation, the right regular representation. What I said earlier about times in by G, that right translation that would also, that's also would turn out to be permutation. It's just later results would be more useful to have this G inverse. And that's because we can't assume the group is abelian. I wanna illustrate this as an example before we go on to the next lemma. Let's take the cyclic group of order four with respect to addition, of course. And so you have the elements zero, one, two, three, and zero, one, two, three, you see them like that. If I were to highlight a row of the Cayley table here, so we have the zero row. If you look at that, what does that mean? So zero will send zero to zero, one to one, two to two, three to three. And so we end up with the permutation, which turns out just to be the identity, okay? If we take the next row, if we take the first row, notice the first row sends zero to one, one to two, two to three, and three to zero. For which if we just record that right here, like if we just record the index row with row one, that actually is the permutation in question right here, for which we can then write that with cyclic notation, the zero goes to one, goes to two, goes to three, go back to zero, okay? If we do this again for the second row, so we take our index row and we take the second row, this gives us the permutation zero, one, two, three, well that's just the index, zero goes to two, one goes to three, two goes to zero, and three goes to one. So we get this permutation to two, two cycle, zero, one are on an orbit, one and three are on an orbit. And then finally, if we take the third row, we see that zero goes to three, one goes to zero, two goes to one, and three goes to two. And so here's the four cycle, zero, three, two, one. So we can represent, we can represent these permutations by really looking at the Cayley table and seeing, oh the row, the rows in the Cayley table correspond to these permutations. Now with our right representation here, row of g-remory is supposed to take the inverse, it's kind of like looking at the columns of this, but again, you have to take inverses. Again, that's a subtlety that we'll worry about a little bit later. So let's look at our second lemma right here. Let g be a group, we're gonna define a new set, we're gonna just call it g-bar for the lack of a better name. Take g-bar to be the set of all left translation maps. Okay, and I claim that g-bar is a subgroup of sg. Now, technically this should be sg really, right? Cause we're talking about permutations on the set g, but these permutations up to isomorphism, it only depends on the size of the set. So I can identify, I can say this is s sub g, the order of g, so it's just the number. So don't worry about that nuance so much right there. So I claim that g-bar is a subgroup. So we have to show it has the identity, it's closed under multiplications, closed under inverses. All right, so let's first show that we have the identity. Well, our candidate, notice over here g, it has an identity element cause it's a group. So let's take left translation by the identity. Notice if you take left translation by the identity, so lambda e of x will just be ex, which is just x, which is just the identity map, right? x didn't matter here. And so the left translation by the identity is the identity permutation. And so therefore we have the identity of the symmetric group. So g-bar has an identity. Great, that's step number one, we have an identity. Next thing, we need to show it's closed under multiplication, okay? Well, let's take two elements of g-bar. They would look like lambda g and lambda r, or lambda h, excuse me. And so what happens when you multiply lambda g with lambda h on x? Now what we have to argue is we have to show that when you multiply these things together, so permutation multiplication, we need to show that this is equal to lambda of something, right? And the candidate actually is gonna be lambda g times h, okay? So when you multiply together these permutations, you actually get the permutation associated to the product g-8. So that's what we wanna show right now. Now how do you show the two functions are equal to each other? You're gonna take an arbitrary element of its domain and show that the two functions agree on that element. If the two functions agree on every element of the domain, that means the functions are actually equal to each other. So consider with the left side over here, lambda g of lambda h of x. Well, by function composition, we're just gonna put lambda h of x inside of lambda g. Well, lambda h of x just means h times x. Lambda g of anything will just be g times that thing. So we get g times h of x. Well, okay, g times h of x, well by associativity, this is gonna be gh times x. But hey, that's what's just what left translation by g times h does, left translation by gh. And so that then proves that lambda g times lambda h is equal to lambda of g times h. Therefore, the product of two of these left translations is in fact the left translations. So g bar is closed under multiplication. So we've proven that it's closed under multiplication. So the last thing to prove is that it's closed under inverses. So we need a candidate for the inverse, right? Well, notice here that the identity translation was just to translate the identity. And the product of two translations was equal to the translation of a product. So if I'm going with this analog I see right here, it would seem that the inverse of a translation should be the translation by an inverse. So that's kind of my conjecture here. So notice what happens if I take the inverse of one of these things. So this is the inverse of a function, the inverse of a permutation. That's also a permutation. Now notice that lambda g to the inverse function of x. This is actually gonna map to g inverse of x. How do I know that? We'll notice that, why does that say phi right there? Lambda g of g inverse of x will go, that'll map to g of g inverse x. Whoops. Oh boy, it's falling apart there. Try it again. So lambda g of g inverse of x, well that you'll get g times g inverse of x which gives you x like so. So notice if we wanna pull this thing backwards, right? If we reverse the process because the inverse function goes the other way around. If g inverse of x maps to x, that means x will map to g inverse of x, great. But wait a second, g inverse of x is the image of lambda g inverse of x. And so since these two functions agree on all elements of their domain, excuse me, that means they're actually equal to each other. So in particular what we've shown is that lambda g to the inverse is equal to lambda of g inverse. So our set is closed under inverses and therefore we've proven that g bar is a subgroup of the appropriately sized symmetric group. And so let's see, what do I wanna say here? And so this argument here, it's really this argument right here which is why we define rho g of x as x g inverse. Because the previous lemma about, are these things permutations, those would be permutations, but in order to get g bar to be a subgroup of the symmetric group, the identity would work out the same. Close your under multiplication, you need the inverse map here because if you take rho g times rho h of x, let's actually spell this out for a second. This would look like doing it one step at a time, rho g of rho h of x, you end up with rho g of x h inverse. And then that turns into x h inverse of g inverse. So that looks like x times h inverse g inverse for which that then becomes x times g h to the inverse by the shoe sock principle which would then look like x. Whoops. This would then look like rho of g h of x. So in order to show that this g bar is actually a subgroup, that's why we take the inverse on the right-hand side just so you're aware. The argument is essentially the same left versus right, doesn't make much of a difference. So now we've reached Kayleigh's theorem where we then, we started off with a group g and then using that group g, we produced a subgroup of the symmetric group. Kayleigh's theorem then is gonna argue that these two groups are the same, that g and g bar are the same. And as g bar is a subgroup of SN, this then proves that every group up to isomorphism is a subgroup of SN. This, that is every group can be represented as a group of permutations like the Kayleigh table approach we saw earlier for Z4. All right, so let's prove that this map phi is an isomorphism where the map, we're gonna send phi of g to lambda sub g. So we'll just send g to left translation. You could also send g to rho of g if you prefer right translation, it doesn't matter. We're gonna stick with left translation so we don't have to bother with the extra inverse there. So imagine we have two elements of g, okay? So we have phi of g and phi of h. Let's assume they're equal. We wanna then prove that this is injective, right? So assume, well that is we're gonna improve injectivity by showing that g and h are actually equal to each other. Well, if phi of g equals phi of h, that means lambda g equals lambda h, okay? And then pick an arbitrary element of the group g, like x. Well, if these two functions are equal, that means that their images will be the same for every choice of x. So lambda g of x equals lambda h of x. But what does left translation do? Lambda g of x will give you gx. Lambda h of x will give you hx, like so. And as x here was chosen arbitrarily, we'll just cancel x from the right-hand side and we end up with g equals h. And therefore this shows that phi is an injective map. That's the first step, right? To show surejective, this is fairly clear, right? Because the way that we constructed g bar, everything in g bar looks like phi or, excuse me, lambda of g and therefore g will map onto lambda of g. So surjectivity could chink, it's super easy. Now the homomorphic property, how does this look? Well, we have to show that the product, that phi of a product is equal to a product of phi's, right? So phi of gh, this will look like phi, excuse me, lambda of gh, which we saw in the previous proof that lambda gh is actually the same thing as lambda g times lambda h, which lambda g is just phi of g and lambda h is phi of h. So honestly, my lima's kinda stole all the thunder behind Cayley's theorem here, but this gives us the final proof here that lambda phi is gonna, sorry, lambda phi here is gonna be an isomorphism. So the map, g maps over to lambda g, this is what we refer to in representation theory as the left regular representation. Whoops, left regular representation of the group. And similarly, if you take g mapping to rho of g, this is what we call the right regular representation. And so that's Cayley's theorem, it's pretty, yeah, it's pretty cool. Every group can be realized as a subgroup of the symmetric group.