Good afternoon everybody. My name is Andrew, now at least, and I'm here to talk about Anger, which is a tool that we have developed to do static analysis and symbolic execution using VEX. Like I said, I am a researcher. I'm an undergraduate student at the University of California, Santa Barbara. We work in what we call the sec lab. We are, like most of the people in this room, interested in finding bugs in software, and because we are researchers, we are interested in publishing papers about finding bugs in software. The more automatic, the better in this case. And also, we are CTF players. CTF, as maybe some of you may know, is Captcha the Flag. It's a computer security game. It's fun, you know. It's about taking the security tasks and making them into fun challenges that you can solve for points, occasionally money. But what we really like to do, as all these different categories of people, is have some way to perform binary analysis tasks in useful modular, modularizable, abstracted ways. And to that end, we have developed a system called Anger. And Anger is, the tagline is, a highly modular Python framework that performs binary analysis using VEX as an intermediate representation. In fact, the name Anger is a pun on VEX because when something is vexing, it makes you angry. Probably half of our code base's name is pun-based. Oh, no, that's totally true. The graphical interface for Anger is called Anger Management. And so the idea of Anger is made of many interlocking parts which provide useful abstractions for analysis. So the point, so the first part of this presentation is going to be detailing the pile of abstract web fractions that we call Anger. So interlocking part one is Pyvex, which is effectively a FFI form functions interface wrapper around libvex. So this is the, this is the bread and butter of all of our further analysis that we'd like to be able to do. We would like to be able to run a line of Python and have out a Python object, which is the intermediate representation superblock, the IRSB, that contains the VEX IR code that is much more easily analyzed than just x86 bytes or armbytes or what have you. So the way that we've done this is there's a whole lot of hacking into libvex in order to actually get the IRSB object out and then we deep copy it into a set of Python classes that represent the internal VEX structs that are easy to work with in Python. So you can just drill into an IRSB and say, well, what's the third statements operation and what are its arguments, which are read temp and a constant statement. Oh, good. That's much better. There we go. And technically, this can be totally independent of libvex, the library, because we have an interface in which you can write lifters in pure Python and we've done this for AVR, MSP430 and BrainFuck. Yeah, no. So that's interlocking part number one, interlocking part number four is called Cinevex. Cinevex is jumping ahead a little, the actual symbolic execution that we do with IRSBs. So I'll explain what exactly symbolic execution is in the moment and how exactly it works. But for now, you just need to know that it takes the IRSBs that we have generated via Pyvex and executes them. But it technically supports execution from other interfaces that aren't vex. Cinevex has grown into a little bit of a misnomer as we've grown and expanded the library to support more things, but it's the first and the best supported and it's also in the name. So most importantly, if you're going to emulate IRSBs, you're going to need to emulate the effects of each of the kind of IR statements, expressions, operations, dirty calls and clean calls. But ultimately, the abstraction you got out of Cinevex is this concept of a simulated state, which is a representation of a program state at a given time. And the symbolic execution process is one that produces, given a state, any number of successors that could possibly result from executing that state. So once we get into the part, once we start thinking about executing things, we need to start thinking about the environment in which we execute things. So we need to start thinking about how do we model memory, how do we model registers? Vex has sort of decided the answers to those questions for us. We have a flat memory space and a flat register file. But other than that, you need to start providing, well, what happens when you hit the IJK sys and you need to emulate a sys call? What happens when, how do you actually model those sys calls and their events symbolically and et cetera? So one of the things that we use to make this work whatsoever is this module called Clarify and our locking part number two. So Valgrind and its friends will want to use vex and emulate these things and all the registers that will be integers. But what we want is we not want not integers, but symbolic bit vectors, which are effectively variables that can be built up into trees. And then you can end up with ASTs of just variables and values and operations. And then you can reason about, well, what if there were a constraint saying that this value must be greater than this value? And you just say that that is an assertion over the current program state. Then once that assertion is in place, you can use an S&T solver such as Z3 in order to reason about additional values that therefore must be a certain value given this constraint. So Clarify is the abstraction layer that allows us to reason about bit vectors, as well as integers, as well as any number of domains that we will sometimes choose to use for static analysis. So as a brief introduction here, let's talk about what the actual process of symbolic execution looks like. So we're going to show you how symbolic execution executes a program and what we can do with that.  So pretend for a moment that we have this code slide so you don't even have to pretend. There it is. So we're going to start execution up here, the blue line. And we're going to start with a sort of blank slate, blank state that contains sort of the, we'll say is that, well, we don't know what X is yet, and there's no constraints on this state yet, but we do know our instruction pointer is there. So when we tick forward, we're going to, I should have said, okay, so when I say X is question marks, what I actually mean is X is a symbolic value, that is, X is user input. And we don't know how to have any idea. We don't have any conception of what that value could be. So we'll just create a symbol X and say that is X. Then as we tick execution forward, we will hit that branch statement. And there are two possible things, places that the CPU could jump to after that instruction. It could either jump to here or it could jump to here. And in symbolic execution, we take both. So this initial state produces two successor states, state AA and state AB. In it, X, we still have no conception about what the actual value of X is, but we do now have a constraint, an assertion over the domain of values X may take on. That is, in this state AA, we know that X must be less than 10, and in state AB, X must be greater than or equal to 10. And so then, yeah, so the process of, the process of Cinevex, the symbolic execution, is effectively computing that this constraint is extracting the idea of this constraint from the code and placing it in the actual state. So if we just sort of continue the example, we are now going to take the state AB, because that's the one that's getting us closer to the U win, because we're trying to win here. That's what we're here to do. So then state AB is going to further branch on the second if statement, and it's going to add the constraint, again, add the constraints on the state X is less than 100, X is greater than or equal to 100. And so now we can say that that state ABA is the state that ends up being at the U win spot, and we can tell that. So therefore, we just invoke a constraint solver on the value of X, given those variables. And we end up with, well, there is a possible value of X that could, and it does, cause the program to take that path. So that's symbolic execution. That's the goal here. So as sort of a side note, the third interlocking part, and I'm very out of order list of interlocking parts, is a binary load that we implemented for the Angular project. It's called clay, stands for clay loads everything. It's very complicated. Talking about it is not at all within the scope of the presentation, but it ought to be mentioned since it is important. It takes, it does the job of a dynamic loader. It takes a library and executables and turns them into an address space. I did most of the work on that. It's very hard. Don't ever try to do that. So the interlocking part number five, the last part, there's an infinite number of interlocking parts, but let's pretend that there's a finite number, so there's five of them, is anger, the actual top level control module. So this takes all these abstractions and puts them together into a control interface called a project, which allows convenient access to symbolic execution and also several built-in analyses that do a lot of common tasks, like control flow, graphic recovery, data flow analysis, et cetera, et cetera. And additionally, it has a knowledge base that allows analyses to store artifacts of truth that is found about the program and isn't analyzing. So here in this example, this is just copied from our homepage. It inputs anger, loads a sort of fake firmware binary for where it performs a control flow graph analysis on it, and now the project's knowledge base has been populated with a listing of all the functions in the binary. For example, here's the entry point, here's the main function, here's two functions conveniently called accepted and rejected, et cetera, et cetera. And then we create an abstraction called a path group, which is a control interface for symbolic execution, and tell the path groups to just blindly tick forward until it finds any state that lives at this address, which is conveniently... I'm pretty sure this hex address is the same as this accepted state address in hex. So we just search for a state at that address, and then when we find one of those states, we ask for a concretization of standard input, and it tells us the password for this firmware. So that's that example. That's just the firmware example that's the tour de force of here's anger doing static analysis and symbolic execution really fast. That was a lot. Anger is big and complicated, but a lot of care has been taken to make it a stack of useful abstractions so that any part of the binary analysis process can be easily instrumented. And what can we do with anger? Well, we can analyze a lot of things. We can do symbolic execution as I've shown. We can do analysis that ship with anger, control flow graph, binary diffing, disassembly, backward slicing, data flow analysis, value set analysis, et cetera. We wrote and then published on a static binary rewriters that can do reassembly of binary programs with instrumentation. There's some limited ability to type inference. We can do symbolically assisted fuzzing, which is very good for bug finding. We can do automatic exploit generation. And also if you're us, we have anger to build a huge system to play an automated form, to play CTF automatically and win third place in the world's first automated CTF called the Cyber Grand Challenge. Oh, God, I need to talk about the CGC now. So... How much time do I have? I've only used 15 minutes. Okay, I can talk about the CGC. So in the United States of America, there's this part of the government called DARPA, and their job is to throw a lot of money at researchers to do research that they want to do. So one of the things they've done recently is they decided, well, we want the state of the art for binary analysis and auto exploitation, et cetera, to be advanced. So they said, hey, researchers in the United States, we want you to build a machine that can play against other machines totally autonomously playing the standard game that we call Captcha the Flag. Now, this is sort of a format that DARPA has done in the past. DARPA, their original grand challenge was for self-driving cars. You may have heard of that. The grand challenge was let's take this established human sport of car racing and say, can we build AIs to do the same thing? And so the Cyber Grand Challenge is the same thing but for the game of CTF. So this ultimately turned into a huge engineering effort of putting a lot of trauma associated with the four months of horrifying development that went into the CGC. But ultimately, we built a system called the Mechanical Fish to use anger at its core to analyze binaries, find vulnerabilities, and then patch those vulnerabilities, turn total vulnerabilities into exploits and then launch those exploits against a series of opponents on a closed network and win us a million and a half dollars. That was pretty good. Yeah, this is all open source. The anger is totally open source. All of the mechanical fish is also open source, I should mention. It's just sort of sitting up on GitHub. If you wanted to kick-start a robot uprising, it's probably a good place to start. So there's some of the analysis capabilities of anger, but what you can also do is build a community. That's what we've done, because a lot of people seem to be using anger for some reason and we've got 100 people idling on our IRC channel and we've got over 100 people on our Slack channel asking questions about why did my script break and we've got a really nice community on GitHub where people are submitting pull requests, opening issues, and people are servicing pull requests that aren't the core research team in the Slack lab and it's mind-boggling that people do this for us. And what we've also done is we've also made friends with other open source projects that we use. For example, Z3, Capstone, Unicorn Engine, we've all, I've mostly, made patches to those systems and then submitted them and had them accepted. And for some of these, for Z3, Capstone, we're not quite Capstone yet, Capstone's being finalized, but Unicorn Engine, we manage, I manage, I manage package distribution for some of those things. So we're making friends. We're doing lots of good things out in the open source world. So that's fun. And ultimately all this is possible because we can lift binary code to Vax and execute it symbolically. That's the primary operation down here. We started building Anger. I shouldn't say we, I like taking credit for all these things, but Anger was started before I came into the SecLow around 2013. And when I started building Anger, the question was, well, what analysis IR do we actually want to use? So that's part two of this talk, which is a brief summary of other analysis IRs. First up is BAP, the binary analysis platform, which is an IR that comes out of CMU, Carnegie Mellon University also in the United States, for their research. Most notably, their bug-finding tool called Mayhem is powered by BAP. As a brief side note, CMU was originally using Vax, but they were completely unable to deal with implementing all the clean helpers and dirty helpers, so they just made their own lifter. And it's also important to note that CMU's research is a spin-off company for all Secure, one first place in the CGC.  Not by much, though. We published an interesting paper looking at the actual gameplay of the CGC and saw the politics. So BAP is pretty cool. It's written in OCaml by people who actually have a background in program analysis. So it's got some cool stuff in it, but on the other hand, it's written in OCaml. And the IR is tied to the larger binary analysis platform that they use. But even further and furthermore, it only supports Intel and ARM. I'm not even sure if it supports ARM64. And furthermore, furthermore, when they started Angular in 2013, BAP was very heavily fragmented and required a copy of their code base in Rotary in order to use. Since then, it has been totally rewritten. So it's a little better now. If you wanted to use it, you wouldn't be totally insane. Next is real, rile. I'm not sure how to pronounce that. It's the reverse-engineering intermediate language. It's someone published a paper in 2009 describing the ideal binary analysis IR, which is ideal. However, it doesn't actually exist. No one really implemented it. So there is an open-real project that is trying to implement this for x86, but if you decide to implement a binary lifter, you will not implement an analysis platform. You will spend three years turning a binary lifter. So back in 2013, we're not using real. So then there's LLVM. This is a pretty serious contender. It's the Clang IR. It is wildly, wildly popular for program analysis. We've started getting program analyst experts coming into our Angerslack and spouting Haskell at us and like, all right, I sort of know what a monad is. Anyway, so LLVM is very robust. It's very established. It's very good. And there's a large community and body of knowledge about how to use it for certain analysis tasks, like various optimization tasks. And symbolic execution with LLVM is 200 times of C++. So that's nice. But on the other hand, it's not really good for our use case. It's designed for compilers, not lifters. There's no real... It's very difficult to reason about register allocation from LLVM. And there doesn't really exist an official lifter from binary code to LLVM. It's all the other way. There's some community projects. MCCMA comes to mind by Trail of Bits that are meant to do that, to lift binary code into LLVM. They sort of work, I guess. Last I heard Trail of Bits has abandoned MCCMA, though don't quote me on that. And it's not... So this isn't really something that we're very interested in using for binary analysis. So then there's TCG, which is the QEMU IR. This is very good. This is what QEMU uses internally to do its optimization and jitting. And one of the really interesting things about being in QEMU is that it suddenly supports everything QEMU supports, which is everything. Everything is supported by QEMU. But then there's... It's designed to be used for QEMU and nothing but QEMU. So the only implementation is just buried in the depths of QEMU that we once burned an entire intern trying to get it out. But... That was weird. But interesting enough, one of our colleagues in the last few months has successfully done this. So there are packages going into QEMU being talked about right around now that have to do with being able to compile QEMU as LibTCG. So once that goes through, we would actually be able to run anger on other things that QEMU supports. Now there is VEX. Does VEX see people in the audience? Does VEX stand for anything? This is very important. This is very embarrassing. It actually stood for Valgrind Experimentals. Valgrind Experimentals. Interesting. It would be better if you didn't know. I'll forget that, don't worry. So good things, very good things about VEX. It's obviously got an official implementation. LibVex, there it is. And it supports tons of architectures. Anything Valgrind supports, that's very good. And it is designed for binary analysis and instrumentation. That's also very good. And it's written in C, so its structures are well-defined and easy to export to other languages. Under active development, it supports a very wide range of ISAs. Like if you look into other analysis platforms, they've got long-running issues open for months and years about, well, we've got to support the SSE extensions to x86. Who wants to write that? Nobody. But VEX has that, that's good. There are some issues with VEX, though. It is designed for the Valgrind use case. So dynamically executing user mode programs is what it caters to. And then, furthermore, there's no real way to get the IR out of LibVex. The LibVex workflow is just this one function, LibVex underscore translate, which does this entire pipeline that Julian had on the screen earlier, of lift instrument optimize code gen. And we only really care about the first part of that. We only really care about the lifting. So for a while, we had this really, really janky solution that commended out half of LibVex translate and then used one of the instrumentation function to copy up the IRSB. I fixed that recently. That's good. Furthermore, you do have to implement a billion IR ops and C calls. And some of them are pretty weird. Like there's IR ops for floating point sign and cosine, et cetera. And furthermore, it's not really SSA. Julian talked about this in the previous talk as well. The IR has no interconnectivity of control flow. There's no ability to reason with just the IR about control flow. And furthermore, from a real SSA IR, you want the memory rights and register rights to also be single static assignments. I'm talking some pretty nasty program analysis stuff, so sorry if this is going over people's heads. But none of these are showstoppers. That's the important thing. Vex is the one that we want to use, and Vex is the one that we ended up using. So, that's what the next part of the talk about. That's what the next part of the talk is about, in words. So, what did we do? We forked Vex. There was our fork of Vex sitting at github.com slash anger slash Vex, and it makes a lot of changes to it. And I'm not going to lie, a big part of giving this talk is me being able to be in the same room as a lot of our ground people, so we can pitch a whole lot of changes we want to upstream to Vex. There's a lot of them. This is the part where things are going to get very, very technical. So, if you're not interested in the specific lines of Vex slash priv slash guest on 2IR.C, this might be a little weird. So, ultimately, so I talked about the issue of the whole gigantic LibVexTranslate function. So, what we did is we split it into two functions, Lyft and CodeGen. There's still the LibVexTranslate function that just calls one and then the other. We've made sure to maintain all the interfaces, so theoretically you can just merge these in the background, we could still totally continue working. I haven't tested this, which means it's broken. But, yeah. So, then there's the problem that LibVex's multi-arch mode doesn't actually work, which is to say that there's this idea of Vex that it can lift from any host and compile to any guest and compile to any host, and this will all magically work, and it really, really, really doesn't. Oh, I've got some good news about you, about some patches we'd like to upstream. And furthermore, there's a lot of assumptions made in various parts of various lifters that the host is the same as the guest. And that's nasty. So, we have patches for that. Furthermore, we'd like to be able to use anger to analyze things that aren't just used in the program. We had a project a few months ago, a few years ago, about analyzing some x86 firmware. So, we have some patches that make it feasible to analyze real mode programs in x86. And then, again, then one of the final things that we want to do is just sort of generally improve the meta-properties of the IR that dynamic execution ignores, but static execution really, really means. Like, for example, making sure that all the jump kinds are always accurate. So, at the end of each vex block, when you translate from one block of vex IR to another block of vex IR, there is a jump kind, which is what kind of jump is it? Is it a boing jump? Is it a function call? Is it a function return? Is it a sys call? What do you want to do? So, that's not really necessary if you're just executing through the code. But once you're performing analysis on it, you need to sort of start keeping track of what function you're in. It's very important that that's right all the time. So, there's a couple of cases where that was wrong, and now it's right. Is it even really knowable? Nothing is ever really knowable. Yep. Seriously. Some of the jump kinds, particularly the spot function, in terms of the impossible, we'd really not love to know that because then we could make code and work on a lot of platforms. But it seems to me impossible to know. Yeah. There's actually currently an issue open on our end about one of our post processors that is overzealous about marking something as a return. So, we need a better heuristic for that. But all the patches that I'm about to present are good as far as we know. They're strictly better. Okay. Let me know if that's true. Yeah. So, let's take a look. I'm going to run that huge bash command and we're going to cycle through all the commits, all 30 of them, and we're going to take a look at what exactly I've done. Uh-uh. Please tell me that's my history. Please. Okay. I guess I can just copy that. I'm glad I kept it around.  That's the one. Anyway. So, we use Git, not SVN, because we love ourselves. So, our first commit in our repository is just importing our 3299 SVN. This is, that was the most recent commit as of about a week ago. I re-based everything on top of the current master. So, this should all be good. So, this is just import Vex into Git. So, the next thing we do is just adding a Git into Git. So, I'm going to run that one character and move the terminal that one character to the right. Ah. That's important. Hang on. Good. All right. First off, Tile GX doesn't work in multi-arch mode for some reason. The make file just sitting in the Vex repository seems to have been not updated in a very long time. It doesn't even include the object files for the Tile GX code. Yeah. Yeah. I was looking at those messages and thinking, maybe I shouldn't put in the effort to support this. So, disable Tile GX in multi-arch mode. Second one. In the x86, it's important that we make, we switch these LDT and GDT registers from being h-words to being relongs. The goal is that they take up a consistent amount of space regardless of the host architecture. And this is important because we have a static mapping and anger of all of the offsets in the guest register file. And we'd like to not have to have some magic way of updating that regardless depending on what your analysis platform is. Next, we clean up the build system. This is just a big cleanup of the Vex build system. It is big and it is clean and it paves the way and oh, this is actually an important change I should go over. Where's the GenOffsets program? Right. So, there's this public I'm doing my best. So, there's this program called GenOffsets in the libvex build process which generates this public header pub slash libvex underscore guest underscore offsets dot h. And the idea is to hold on to how there'd be a public record of what the actual offsets into the host file, into the guest register files are. Like what offsets do you need to look into the register file to find EAX or R0 on ARM or R0 on PowerPC? Previously, there was a real hacked up grep into said into something to make everything work. But because of that change that we just made, the one with changing the h-words to the u-longs, now everything is consistent across every platform and we can just we can use something much simpler in order to actually, in order to grab those offsets. In this case, it's just compile a program that includes that just runs the size of macro a billion times and dumps them all out and just dumps them all out into that header file. Does this work even when cross-compiling? Huh? Does this work even when cross-compiling? Yes, that's the idea. Next, support compiling for windows via NSVC. This is this was not fun. It's a lot. It's basically a whole bunch of the real kicker is deaf. We conditioned out a whole bunch of weird vlogs, code with another version of MSVC understands. Okay, and then here's the stuff where we just do a bunch of defines to step out all the GCC specific functionality. I haven't, I got it to work at one point and then my windows machine fell over and died so I'm not really sure how well it works right now, but it worked and it can probably work given about 30 minutes of dead time and a working windows machine.  It shouldn't be any overhead, it's just weird stuff. Next is Next is we replace there's this adder type which is this generic host word that sort of switches between 62 and 32 bits based on the architecture. That's no good because then you can't analyze 64 bit from a 32 bit host. Yeah, that's a pollution, it should never go in there. Yeah. So we just, and this is a bit of a hack it should probably be addressed more carefully but for the time being it just needs to be 64 wide. Next we add a next we add a function called libvex update control. There's this vex control struct which is sort of a global variable floating around vex that can add that adds the ability to have just sort of global options for how the optimization process should work and we want you're only allowed to set this once that was the problem you set this in the libvex init function and then you're never allowed to touch it again which is not ideal when you want to update for example the maximum number of instructions that you'd like to lift and later on in this thing I'm going to add a couple more options and it's useful to have them partitioned out like this, so cool. Next, next is the thing I'm talking about we split libvex translate into libvex lift and libvex codegen so it's not a huge deal we just here is it ah it's you can't really see it but there's but libvex translate has just become just these green just these green lines right here which calls libvex lift, libvex codegen which turns out as you're done not super hard. Next is we add a parameter to the vex control that is the maximum number of bytes per lift there is the there's already a concept of maximum number of instructions per lift but we would also like to be able to have a maximum number of bytes per lift useful. Furthermore, there are a lot of weird optimizations that happen in the lifting process which we which are have negative effects on analysis for example in the arm mode on the thumb lifting it tries to do this look back behind the current instructions to see if any of them could have been a conditional instruction and if they're not it means you can optimize the hell out of that code. However there's use cases from Pyvex that doesn't make sense where there doesn't exist code behind the current code where there's not a continuous mapping of just the code segments so we need to be able to disable that behavior. So then so then previously the onlifter's endness endness was dependent on the host which doesn't really make a whole lot of sense so now we're dealing with the guests and furthermore involves just some changes to make sure that you lift the you pull words out of memory with the correct endness etc etc. Next I have no idea why this code ever works but here it is at some point you just take the guest access cast it to a host pointer and try de-referencing it and that makes absolutely no sense so here's a fix Yes This is a lot of relatively small changes Yes Did you want to talk about changing the IRR? That's a much harder problem This is like Yeah There are no real changes to the IRR We like VEX a lot We like the way it is and we don't have any solutions for sort of the architectural problems For example it doesn't give many real representation of what happens in between basic blocks We don't have an answer for that I thought you had this No No I wish I guess I can talk about this in one sort of general patterns that Valgrind doesn't support what we would like to For example there's previously the assertion that when you have a service call on an arm the service call number must be zero and when you're analyzing good firmware that's not always the case There's a lot of small changes Yeah This is really the architecture level stuff that's hard to do The top level structure Yeah I think at this point I've explained all the structural changes I stuck those pretty early in the history If you've been watching the dates they've been jumping back and forth What's something structural that we can talk about MIPS to So can I just say if you actually just jump this law into the standard Valgrind I haven't tried it but it should It really should I took some care to make sure all the interfaces are preserved and any new options that I added are defaulted to the original behavior Let's see Anything else that's interesting Anything interesting Then this is a huge commit that adds support for analyzing x86 real mode code So we add a parameter to the arch info that is the CR0 x86 register and so that controls a big chunk of the new x86 lifting logic and also involves handling the GDT registers correctly and it's just reorganization It's pretty fundamental and needs to drive home the idea that VEX has uses outside of analyzing real mode programs dynamically So optimization and there's a weird type error I found and that's all 30 commits So go back to here That was a lot less than it could have been I spent the last two weeks cleaning up our three years of mess of commit history and packaging into this series of 30 meaningful patches So I've put in a lot of work to make this nice and hopefully just ready to be accepted given some testing So some future ideas that these are some more architectural, some architectural, some structural changes My understanding is that the origin of the C calls in VEX are that they were originally copied from QEMU. I don't know how true this is but the idea that there's some that these, for example when VEX wants to calculate the E flags for an x86 jump instruction like we will so in x86 you can say jump if less than or equal to and what that actually does is it checks just a bit in the condition flags that get set every time you do a math operation and so VEX doesn't want to recalculate those condition flags every single instruction so it saves off the operators and the operand for every math instruction it does all the unnecessary ones get filled up by the optimizer and then when it actually sees that it needs to calculate the bits of the E flags register all these C calls out to this sort of external function which magically knows how to take the operation and the operands and return whether the branch passes or not so and it's totally possible that the existence of these C calls is a hindrance to analysis and optimization and lots of things so it would be nice in the future if we could inline all these C calls and just IR um through them having there be a concept helping there be thread safety in LibVex would be very very very nice because I mean we're in Python so it doesn't make a whole lot of difference but there are many applications for us which are, which live mostly in LibVex for example we do have a blockchain generator that most of its lifetime is spent in LibVex so if we could multi thread that this is hard because Vex is designed to make zero assumptions about its outside model so it has no access to anything that could possibly give it thread local storage so it would probably end up being a callback that it would call but it's just saying hey whoever is invoking me please give me my thread local storage block and it would do that but that would involve moving literally every single global in LibVex into that huge thread local storage struct so it's hard but it would be useful and require a lot of refactoring so multi arch mode works at least now from a little endian host we've tested this pretty extensively from 32 bit and 64 bit little endian hosts you can lift without faults all architectures we haven't tested this with big endian hosts and my feeling is that it's going to fail if you try to lift on a MIPS processor et cetera et cetera et cetera that's not important this is very urgent the indentation in LibVex is three spaces that feels like some sort of joke and one space would be better than three spaces honestly so we need to discuss how to pay the bike share yeah so on a separate note on a less joke filled note licensing is a bit of an issue so LibVex is GPL this is a little scary because we don't want anger to be at GPL our university wants anger it wants all our code to be BSD and we have this belief that we've sufficiently developed ourselves from dependency on LibVex through having multiple backends to Pyvex having no real strict dependency on the exact list of enums that come out of LibVex but in the end it ends up being this weird legal question of what does the GPL cover does the GPL cover the implementation of LibVex or does the GPL cover the concept of the Vex IR we really don't want to find out the answers to that question so the easiest thing that would the easiest thing we think would be for there to be a there's this library license exception runtime library exception that gets added to LibC for example which is GPL but there's no but just because you link with LibC doesn't mean that you're required for your program to also be GPL so that's probably something that needs to be discussed in depth but that's a important issue that's important to the livelihood of anger and me so that's pretty much it that's the anger project that's our interactions with LibVex and that's me being funny on stage for an hour I'm glad to take any questions that you have but is it okay is it mostly because of organizations and my inlining or is it is there anything else more fundamental that stops you from knowing is he said that you need more information he said that you can't leave the analysis and strength so the nightmare case is on arm and thumb there's no such thing as ret instruction there's just this weird instruction which pops a number of things off of the stack and puts them into various registers and this can include the program counter so yeah so it's just but that's like a return yeah so that's the heuristic that he tried to implement and it's not the exact issue that's coming up isn't right but it's an instruction problem it's an instruction problem I think I think there are some CFG problems but like absolutely and I think I'm not the person who deals with CFG that's a very smart person named fish a PhD student in our lab fish named person we have lots of we have a very complicated control flow recovery algorithm it I'm pretty sure there are considerations for the CFG cases in there so everything is perfect everything is unknowable anything else how do you deal with C score deductions memory locations that depends on things you might not know for example yeah so you mentioned memory locations this is a general problem in symbolic execution what do you do when you have a store to a memory address that's symbolic and the answer is we give you a lot of tools to decide what to do you can either concretize the memory storage address you can concretize it to a range of possible addresses in some store conditionally to all of them the less tractable it is that's an open question what's the best way to do it there's lots of publication on what to do it and we try to provide everything you can so you can pick what you need to do with your analysis that's why we call anger a sweet so you can access tools to do that you can access tools to show us something to do longer about that yeah oh wait a minute you mentioned syscalls we're in the middle of refactoring the precise relationship between a program running in anger in its environment but the idea is that oh boy so I mentioned that SimiVex can do things other than just execute Vex well one of them is execute a syscall the main top level loop is well if we see that the previous jump kind is IJK sys instead of running Vex we run the syscall engine then the next time we see that we're all trying to execute more Vex it depends on the actual attacks you're running your your relation basically how do you how do you because it's static and it's static analysis so if you have files in parallel something that does not exist at the analyze time so you're talking about for example what does the open file syscall do yeah for us it just creates the idea that well there's two cases either the open succeeded and it didn't if it didn't succeed you can create a successor state with a failure state at that state and if it did succeed you create a concept of an open file with unknown contents symbolic contents so that any so return a file descriptor and then any time you read off that file descriptor it will return symbolic data and also the possibility of the OF basically you're also embracing this it's big this is a project we've been doing basically nonstop for the last three years it's big about your SMT calling how do you handle 40 point numbers Z3 has primitive support for loading point numbers it does work it's very very buggy we've found numerous seg faults in C3 unable to track down to a root cause so sometimes what we do is I think the approach that we took during the CGC for maximum resiliency was every time we see a floating point operation we just say throw up our hands nothing we can do concretize any symbolic values that turn into floating point and then every time we see an actual operation we just turn them into python floats add them put them back into bit vectors so then this maintains tractability and usually when there's bugs they don't often come from floating point nonsense if we wanted to really if Z3 works then we could just put everything through Z3's symbolic IEEE 754 I work with Z3 as well and recently I found this so it's much better there's an interesting amount of research out there about for frameworks like this which just want a solution to something what you can just do is you can spin up any numbers of SAT solvers in parallel and just use the one of whichever one returns first use the result so that's an approach that we've wanted to implement for a while using which one did he say was good? matzat okay thank you very much anything else? that will be all


guys subscribe and turn notifications on leave a like and drop a comment down below get here first and win giveaway calls i will pin as first comment on some of my videos be fast and good luck what is going on guys welcome back to the channel and i appreciate you being here today i bring you another destiny 2 video and today i bring you this glitch on how you can skip the older boss in the shattered throne mission and get the quest for the exotic boulder wish ender this can also be used to skip this boss as it's by far the hardest in the mission so if you're struggling use this simple glitch to skip this boss but before we go any further guys if you do enjoy the video leave a like and showing your support really helps me in the channel out and also if you are new around here and enjoy daily destiny 2 videos be sure to subscribe also guys this info and footage was provided by my good pal mod life crisis a great destiny 2 youtuber definitely worth your time checking out for those daily videos guides and much much more his channel link can be found within the video description okay so this glitch no doubt will be patched soon so hey use it while you can so you have to have a minimum of two players in this mission to do this glitch if you don't know anything about this mission or how you get the exotic wish ender bow i seriously suggest you check out my full guide on this exotic which you can find linked within the video description the quest is long it's hard and you will die a lot but if you stick to it and are seriously dedicated to getting it you will get it it's as simple as that okay so load up the shard thrones mission make your way to the ogre room you know the ogre the massive ogre the four light or paths around him that's the boss we can get to glitch if you have the checkpoint even better so once you are here people you simply start the encounter now the person who isn't the host has to die and wait on his character selects screen yes that ogre which works here if you know what i mean so the person who isn't host dies and waits on that changed character screen the host then dies and when the three second countdown timer starts have the player on that changed character screen select to change character when the time hits one second if you time this rides when you spawn back in when the host spawns back in you can either wait for your teammate to rejoin you or go on into the ogre encounter and the ogre will not spawn and it can simply just progress through this mission now at first i thought this wouldn't open the door to your progress but it does it also gives you the triumph for beating this big old ogre bastard so that's pretty cool what you can then go and do is progress to the statue and pick up the stars the wish and the exotic ball once you speak to the statue you will then get a secret mission and a tangled sure again all that info and what else is needed within this exotic ball quest is in the exotic ball quest guide video linked within the video description if you want to check it out but hey the ball at this stage doesn't interest you you can just go on to defeat the final boss of dawning crow who is pretty difficult for first timers but you really shouldn't be having much of a problem here people but hey guys this is how you skip the ogre and get the exotic ball quest or just skip the ogre in the shattered throne mission and on that note we have come to the end of the video people if you enjoyed it leaving a like really helps out and if you are new around here and enjoy daily destiny videos like top fives guides gameplays reviews just about everything be sure to subscribe and if you never want to miss a video upload turn on notifications by hitting that bell button again thanks for stopping by and hopefully I will see you on that next one


So, my name is Danielle Adams, I'm a software engineer at a company called Blue Apron where I aid our warehouse team and converting millions of raw produce into meals across the country. And so, today I'm going to talk about Ruby Racing. Okay, so let's get started. Show of hands. How many of you are programmers here? Excellent. Me too. How many of you write in Ruby? Cool. Me too. How many of you write primarily in Ruby? Every day? Awesome. Good ratio. And then, how many of you would you say that you are with absolute confidence that your code is running as quick as it could? One person. Awesome. Okay. And that's okay. As developers, we are, you know, we have a lot of stuff to do. We're writing code, we're involved in some sort of Git versioning, so we're pushing it up to GitHub, so to speak, we're deploying code, we're making sure that our apps don't break, we're making sure tests don't break, we're writing tests, we've got a lot going on. So, it's natural to trust what we're using, the open source software we're using, such as Ruby. And that's okay. Ruby was designed to make us happy, too. It wasn't necessarily, you know, it's not something that we've always been trained to question. Just by the look of this, can anybody tell me what method this is? Somebody preferably that is not on the Ruby core team, because they probably know, but other than that, somebody tell me what method this is. To us. Good. Much smaller, much simpler. This is why we love Ruby, because we don't want to write an entire block of code just to convert something into a string. Okay. So, just a little background, just to give you something. How do Ruby methods work? We have code. We save it to, you know, mycode.rb. This is converted into tokens, which is then parsed into an abstract syntax tree. To us, it might look like nested arrays, but it's actually a tree structure. And that's converted into byte code. As of 1.9, we're using byte code. And then that's interpreted by the Ruby VM. So, the YARV, and that's actually an acronym for yet another Ruby VM, just kind of a tongue twister. So what does that mean? It seems kind of simple, but we don't really think about it, or at least I didn't before I started investigating this. So basically, just to give you a background on what I actually, how this talk came about was, I was talking with some of my coworkers, and we were having a conversation about how to make our code faster and, well, what if we do it this way versus this way? And so we were on the whiteboard, and as most of us do, and so we're writing, oh, this looks better than this one. Well, this one's shorter than this one. This one's more readable. Okay, that's fair. As Ruby programmers, that's what we look for. We like smaller, more readable code. So then we actually put it to the test. First we put some RSpec tests to make sure it was actually doing what we wanted to do, because we don't want to base this off of buggy code. And then after that, we actually benchmarked it. So we measured it to see how fast it was, and we were actually discovered that some of the Ruby code that we were writing was actually faster in Ruby than it was in the C implementation.  And then I, so I started looking for patterns that I could follow in Ruby that I could also, that I could implement my own Ruby methods. So yeah. So I rewrote a bunch of methods, all array methods, that's very easy, input, output. And yeah, I found that I was actually able to make some of the Ruby code faster. So and then I made an open source project. I made a little game, basically what you do is you pass in your own implementation of the Ruby methods. As of right now, it's, I think it can work with any type of method that, for any strings or array methods and whatnot, you find that that's not the case, come find me. And yeah, and so now I'm going to give you a little demo on how that works. So first I started with, with sort. Ruby sort is a, oh, you can, can you see that? Is that too small? Is it good? So I started with Ruby sort method, which is a quick sort algorithm. And so I tried to implement that in Ruby, much smaller, much shorter, longer as you can see. Clearly did not, did not be Ruby, which is fine. And then I tried samples. Sample is an interesting method because, yeah, find something at random, oops, that's the wrong file, erase, is that it? Yeah. Okay. So I tried, failed, whatever. Okay. And then I tried unique. It was faster. And then I tried max. Also was able to make it faster. So naturally, since I tried max, I also tried rewriting min, follows a similar algorithm. Also one. Okay. So just to give you a little preview of how, what I, how I actually implemented these. So as you can see, max was, was a basic, I was able to just use a very low level iterator, a while loop, and that just iterated through the, the array, chose the highest number, and returned it. Very simple. Unique was a little more complex. I had to, it was also using a while loop, which I found were the, was the way to make the Ruby methods faster. Using each loop actually implemented each, which was written in C. And so that created a layer of complexity. Using a while loop made was instrumental in making the Ruby methods faster. So, and I wrote my own version of contain, which is also used a while loop, which isn't most optimal way to do it, but worked, it was faster. Okay. So things to note about this. So first, doesn't necessarily mean that because of the input I'm, I'm providing that it's actually the most optimal way to, to implement, to implement that version of the method. So inputs could be a number of things and Ruby covers all of these different edge cases, best case scenario, worst case scenario. And my tiny little method just assumes that the programmer is smart and just does what exactly what we're supposed to do, because that's what we do. We always do what we say we're going to do. Benchmarking, also my method of benchmarking was just my version. It might, might be good, it might be bad. I took the difference of the time, start time, end time, made the difference, and ran that 50,000 times. So that's just, just to get a good sense of what the average number is. The average runtime. And then efficiency, just because I think it's efficient because it runs faster, it might not work for, for everybody that, anyone in this room. This efficiency I'm measuring by time, but efficiency could be measured by memory. Efficiency could be measured by scalability, by readability. There's a lot of ways to, to rate code as efficient. And so this is just my definition of efficient. So resources, so any of you that have a Python background, you might know, recognize some of these concepts. There's actually a language called PyPy. And what it did, they did is they rewrote a bunch of the Python language in Python. And it's actually proven to be faster than the original Python. Interesting. There's also a book called Ruby Under the Microscope by Pat Shaughnessy, which is a really good, really good explanation of what happens under the hood for Ruby code, highly recommended. Also, this was, this was interesting because this was something that came about just from interacting and collaborating with my coworkers. This is not something that I would have come up with alone or even bothered to think about. So I just thought it was really cool that they, they influenced me to do that. And then also, Ruby source code. I don't know how many, maybe I'm the only person that actually looks at the Ruby source code because I'm curious about how it works. I don't know C, but I try, try to understand it. Okay, so, there we go. Okay, so why do you care? You might not care, that's okay. But basically, what I want you guys to get out of this is that I think that we are taking, not taking advantage, not taking advantage, taking for granted how Ruby works. But we definitely want to be thinking about how it works under the hood and not just trusting that it's the most efficient way or it's the fastest way. And that's okay. That's what we, it's okay if it's not, but Ruby is, yeah, just be more curious about it. Okay, and also you can try this out for yourself. Gem install, Ruby racer, other readme has a very small example of how to use it. So if you have any questions, you tweet me or whatever, email, maybe. And that's it. If anything, I hope you guys can take away. It's a cute picture of a puppy, I love puppies. But if not that, then I hope that you will walk away from this a little more curious about your Ruby code, what's going on under the hood. And yeah, just break them and put them back together and be curious. Thank you.


The study compares the clinical efficacy, dermoscopic results, and safety of triumcinolona setonide, TA, and beta-methasone depropionate, BD, injections at different concentrations in localized scalp and beard alopecia. The results show that BD 1-quarter dilution, 1.25 mg per deciliter, is the best corticosteroid for intralesional injection in the treatment of localized alopecia areata in adults, with similar sixth-month hair regrowth scores and overall treatment success rates as TA 1-quarter dilution, 1.25 mg per deciliter, but with fewer adverse effects. This article was authored by Pelina Stuna, Ali Balevi, and Mustafa Ustami.


Hello everyone. Welcome back to another video. This one is going to be like a pencil portrait sketch practice session because if you didn't know, I just recently got back into drawing once again after a really long hiatus and that's why I need to practice. So I've got my pencil over here, my eraser, my sharpener, my sketchbook. I also have a reference image and I will definitely be using the basic shapes and guidelines that I talk about in my How I Draw Faces tutorial video in order for me to practice how to draw portraits once again. That video actually came in really handy when I started to get back into art and then I realized that my skills were not up to par with where I left off, especially with my facial proportions. Like they just weren't looking great. And so I had to refer back to my old self through that video and kind of see how she used to draw portraits back then and apply those same techniques into how I will draw portraits from today and in the future. And yeah, I was pretty impressed with myself. Like I can't believe I actually put out a video of that quality. Like I'm pretty proud of myself. But anyway, I am using the exact same shapes and guidelines in this video that I also used in that video. But this one isn't really a tutorial video, but I'm using the circle. I'm using the upside down triangle. And then, of course, I divide that vertically in half. And then I have a horizontal line at the top of the circle, which is the top of the head and a horizontal line at the bottom of the upside down triangle. And then you basically divide that horizontally in half and the top half you divide into thirds. And then the bottom half you do the exact same thing divided into thirds. So you end up with six total spaces or seven lines. And I actually just draw the guidelines very lightly because when it comes to pencil sketches, I usually don't like to erase because it leaves like, you know, like a smudge or a gray ghost on the page. I don't know, maybe that's just the way that my erasers aren't that great, but I just haven't I've just always tried to avoid it ever since. And the way that I do that is anything that I'm not so certain of just yet, I always will draw very lightly. When it comes to pencil sketching, I tend to go with a technique of building it up. So going from just really, really light and then building up each layer so that it just becomes darker. I normally don't start very dark. After that, I start drawing the eyes and I map out where the eyes are going to be.  And the ideal facial proportions is the distance between the eyes is another eye. So that's what I've done and I've just drawn the very, very basic shapes like a leaf shape for the shape of an eye and a circle for a pupil. And I draw this very, very lightly, especially because I'm actually filming the drawing. If I wasn't, I would draw the very basic shape and then I would immediately start shading it. But similar to the guidelines because I don't really want to erase anything. And because I'm filming, I'm actually sitting at a really awkward angle around the camera. So I just want to draw it lightly in case I'm not happy with it. Normally after that, I would kind of move around the sketchbook to see whether I'm happy with it with the position. And if I am, then then I would add the shading. After that, I add the eyebrows and I draw this just under line three. And I also draw like these diagonal lines from the outer corner of the eye upwards to denote the length of the eyebrows. So the eyebrows tend to be longer than the length of an eye. But you know, like different people have different lengths of eyebrows or even shapes of eyebrows. So it really doesn't matter. But for this specific video, I am doing a very, what would you call it? Like a typical beauty standard. Like she's got the ideal facial proportions. And then after that, I start drawing the nose. This one falls on line five and it also sits on the vertical center of the head. And I am drawing a circle because that is the ball of the nose. And then after that, I will be drawing curves for the nostrils and kind of like a C shape. I don't know, or like a backwards C for like the sides of the nose. But it also doesn't really look like a C. Like it really just depends on what kind of nose you're drawing. Like there's so many different kinds of noses, so many different kinds of eyebrows, eyes, mouths, faces, lots of variety. And that's actually something that I want to do with this practice session and the future of practice sessions that I'm planning on doing. Because I want to be able to confidently draw a variety of faces, like a diverse range of faces. And you could do so much of that with just small changes to how you draw specific lines or where you put specific facial features within these guidelines. Because I do say in that tutorial video that you don't necessarily have to follow these guidelines to a T because people have different faces and facial proportions. So you don't have to follow this. However, as a beginner or when I was learning how to draw from the very start, I did start with a very Eurocentric standard of beauty as the ideal facial proportions. And once I've mastered those ideal facial proportions, I was then confident enough to branch out and do things differently. And that's what I'm hoping to do. So this one I would consider a very typical beauty standard, ideal facial proportions kind of face. And in the next one, which I'm hoping to do soon is I'm planning on doing like either different face shapes or different kinds of eyes and applying that into the faces that I draw. So for example, like I'm drawing the lips or the mouth right here and I start with just like the very basic shape. And this one, I drew it on top of line six, but it doesn't even really have to be like that case. Like you could draw just a little bit below line six or a little bit above because like I said, there's so many different mouths. Like it could be a thin lips or it could be full lips or heart shaped lips or wide lips like so many. For this one, once again, like I'm going for this standard full lips. And here I'm actually starting to shade it because I am quite happy with like where this is sitting. And the way that I start shading and I start darkening lines is I don't actually put a lot of pressure on the pencil. I'm holding it the exact same way as I'm drawing like the guidelines very, very light as a feather. And that's because like throughout the years that I've been drawing and holding something in my hand and applying pressure, it like hurts my hand.  And so what I've realized and what I've trained myself to do is to just especially when it comes to pencil sketches is to hold it very lightly. And in order to get the darker lines is I basically just create a bunch of lines on top of each other like as if I'm scratching the paper so that it just builds up rather than a one time hard stroke with a lot of pressure. Also, when I'm putting a lot of pressure on the pencil, then it starts to kind of show through at the back and I don't really like that. I feel like I gain more control by holding the pencil exactly with the same pressure throughout and kind of just like layering and layering and building it up. So then here I start adding the outlines to the face. I'm starting to round out the jaw and the chin and then I even added a hairline, which sits right on line two. And I use like the round hairline because like for this one I am doing an oval face shape, even though my reference image I think she's more of a heart face shape. I'm not really sure I'm actually not good at telling what kind of face shape people have. But anyway, we're just going to stick with the oval face shape because like I said, we're just going to go with the basics for this one. And I forgot to mention that I added circle for the chin and then I added like these ovals for the cheeks and also an oval around the forehead. That just helps me visualize like the shapes like for example the chin is quite round and so are your cheeks and so is like your forehead. And I also use that same exact motion when I'm drawing the ears, even though the ears themselves aren't round, they're more like a C shape. And specifically for this particular reference image, her ears don't really protrude as much so they're more like a flat C on the side of her face falling between line four and line five.  And then now I'm adding the hairline. No, I'm adding the hair, sorry, which I draw just on top of the circle and the very first line, which is line number one. And I draw that on top because like there's a little bit of volume on top of the head. If she were to be bald or like have a very slick hairstyle, then I probably would draw it exactly on line number one. But to give it a little bit of volume, I'm drawing it just a little bit above that. Also different hairstyles like if someone had like really poofy hair or spiky hair, then that would definitely be way above line number one. And for this video, I'm not going to talk about the hair because number one, I didn't actually put that much effort into drawing the hair in this specific drawing. And also because I also lack way more practice when it comes to drawing hair because even though like, I don't know, like 10 years ago, I was so into drawing hair like I was drawing every single strand.  I am really lazy, like I actually really don't like drawing it anymore.  But then it's just like the same repetitive strokes of the pencil and I kind of just get bored. But that's obviously just like a cop out. So I really need to practice how to draw hair once again. So hopefully in the next video, I'll actually do both the face and the hair. So kind of like combine those two and even maybe the shading maybe I'll talk about the shading as well because that is also something that I need to practice. But one step at a time for this one, it's more just focus on the facial proportions. The next one, I might start doing the hair, but yeah. Anyway, so now I am adding some darker lines to the eyes and to the other details of the face because I'm pretty happy with where everything is sitting. And what I'm doing is I'm actually as I'm darkening the lines, I'm actually changing the curves a little bit so that they look more like the reference image. And so they don't look as cartoony because I am going for a semi realistic style here. And like I said before, I'm not pressing hard on the paper. I'm just holding the pencil really lightly and just creating lots of small marks with the pencil to build up that tone. And I know I literally just said that I feel really lazy when doing repetitive strokes with the pencil for the hair, but I'm literally doing the exact same thing for shading. But I think the only difference is that with hair usually they're like long strokes and with shading they're a lot smaller and I prefer the latter obviously. But anyway, that is pretty much how I draw this face and the proportions and everything like that. So after this I'm pretty much just going to start shading and like I said, I will hopefully progress the way that I shade in future videos because I normally just have like a default shading. Like I just know to add shading around the eyes, I just know to add shading under the nose, or like I shade the mouth the exact same way I always do. And I just feel like I need to mix it up, which is why I use references like for this one for the shading of this. I realized that I should actually refer to the reference image and where the shadows are because for this specific reference image, the shadows are kind of dominant on one side. So I try to replicate that in this. But yeah, I definitely need to practice shading because I usually just revert back to my default mode. And I feel like it would benefit me a lot if I actually practice different types of lighting. But yeah, the general places that I normally like to add shading to especially when I'm doing a pencil sketch and shading definitely adds that extra oomph to a pencil sketch. It kind of makes it look a little bit more finished than just a rough sketch. And those places normally are like around the eyes, especially around the eyelids. And with the crease of the eyelid, I usually just shade like at the very end of it like the outer end and then the inner around the inner eye. I usually like to leave the middle part of it like very light to kind of show that shape because like the eyelids are wrapped around a spherical eyeball. So it kind of that makes it look like that middle area is like the highlight. And then I also add some shading to the inner corner of the eye and then the outer corner of the eye to really show that the eyeball is spherical. And then right here I am adding some shading to the pupils. I try to kind of map out where the highlight is going to be. And then here I am doing the eyelashes. That is also something that I feel like I need work on. But I think this one in particular like other other concepts like shading and hair like I understand them, but eyelashes, I can't. I cannot understand eyelashes. And I've practiced drawing eyelashes before and even then like I pretty I'm pretty sure like I kind of gave up because like I just was not sure how to draw it because I want to be able to draw it. Like realistically in a sense where it looks like their eyelashes are quite long and full but not like too long like it would look like if someone was wearing false lashes or not too dramatic. I feel like for this drawing in particular I made it a little bit too dramatic for my liking like I they're definitely uneven but like that's fine. It's just a sketch just a practice sketch. Anyway, that's also something that I need to work on. I also add shading to the under eye that is another thing that I really really really like to shade even if the reference image doesn't call for it. And I kind of take that from like Korean makeup they refer to that part of the eye as the egg yosal. And that's kind of like when I started to really love adding that detail on to the eye. Even though some people might like my dad for example like thinks that they're just eye bags, and they kind of look like I bags but they look cute. Anyway, I also like to add dark shading around the corner of the lips. I definitely did it a little bit too dark in this one and then I erased it and then they kind of made it look gray and smudgy but that's totally fine, because it looked better than it did before. And then now I'm just adding shading around the nose and the reason why I add those like shadings like on the sides of the nose and on the corner of the lips is because it kind of just like creates that juxtaposition between like that area but being kind of like sunken in compared to the cheeks. And it kind of just makes the cheeks a little bit puffy. I don't know. I have absolutely no idea how to explain it. But then, of course, I add shading to the cheeks. And for this one I'm just following the reference image and kind of just like seeing how the face like where the shapes are when it comes to the dark areas and the light areas and for this one in particular like the dark area for the cheek is quite large because the light is very prominent on the right side. And the way that I also like to shade is I will kind of like draw the line of where the dark area is as like an outline. And then I shade and I do like a hatching in within that shape. I kind of like how that looks. That's just something that I've been doing ever since. And then here I'm darkening up the eyebrow so that it kind of matches the rest of the face and I'm just doing that by like drawing like little hair strands kind of just like following the motion of it. Instead of just actually color blocking it I feel like that just makes it a little bit more realistic. And here I'm kind of just erasing the eyebrows because it actually points a lot more downwards than outwards. So just little fixes like that and then yeah, maybe in the next one I might also add some watercolors. I'm not entirely sure I'm going to try and take it one step at a time but I'm definitely feeling very excited about the prospect of just drawing more and more again. So yeah, I'm like after doing this practice portrait sketch, I'm really keen to do another one. Hopefully exactly like what I said before which is possibly different face shapes. I might even do like kind of list out all of the different eye shapes, all of the different nose shapes, face shapes, things like that. And maybe do like a random draw so that I can mix and match all of those things and create whatever face I create. Maybe I won't use like a reference image because I feel like having to find like a specific reference image for a specific face shape or for someone with like a specific nose type or eyes. I feel like that will just take some time so I might just actually do like a random draw like a mix and match so that I will be able to apply like the things that I actually talk about in my tutorial video into actual practice portrait sketches. So we are pretty much finishing up the drawing just adding the final touches. I also added the hair and the hair for this one. It actually looks pretty good. I just did all of the like strokes to mimic the hair strands and even though I don't like doing it. I actually feel like I persevered in this drawing. Like it's not as detailed as the rest of the face, but I think that's perfectly fine because it is just a sketch. However, that is it for this particular video and this drawing and that is it also for the voice over part for me. I'm very, very happy with how this drawing turned out. I think she looks very pretty and also this whole practice session has definitely got me pumped up and excited for future practice sessions like all of the different things that I want to improve on and share in a video format. But that is definitely it. I hope you enjoyed this video. I don't know if you got something out of this, but if you're drawing with me, you're practicing drawing with me as well, then I hope that your drawing session turned out really great. And I will see you in my next one.


What's good y'all, Shibora, let's back out again with another video. So we're gonna check out WWE Top 20 Lights Out Returns in history, man. You know, when the lights go out in the arena, somebody makes their surprise return or somebody pops out of nowhere. It's always a hokey moment in wrestling, but it's always an entertaining moment for the most part.  How did he get there? Who knows? But we're going to check it out. Appreciate all the love and support on the channel, y'all. Man, road to 70K. And let's get right into this bad boy. Yeah, gotta love it. Yup. You deserve so much better, bray. You always deserve so much better. Oh, yeah. He had been talking trash to the Undertaker for a little minute and then to see this moment finally happen, even though it was a glorified squash match was cool to see. Just to see that. That was it was just cool to see. See the Undertaker. Just always cool to see in my wrestling. Man, I can't be to get my belt back because I'd be. Uh-oh. I've been locked with destruction. Man, look at this quality. I can't. Wow. It's the war. Look at Hulk Hogan selling it. No. This was such a dope entrance, bro. Oh my God. This is a dope entrance. And then. Oh man. That to me was one of the best matches as Summer Slam. Oh, it was so good. Him coming out to the brood entrance, the lights go out and then on this day, I see clearly. Oh my gosh, man. It's definitely one of the matches. You gotta go see it. If you haven't seen it, go watch this match. This was really, really good. It's not too many times that, you know, I can sit up here and give WWE a lot of praise, but I give him a lot of praise for this match to set up in that entire feud between him and Seth Rollins. Fantastic. Extreme hours of wrestling. Uh-oh. Hey, wait a minute. This is great. Once again, you deserve so much better. And I hope you do get better, man. So wherever you go, whether it's AEW, whoever company, I hope they treat you better and take better care of the characters that you've created. Because what you've given us in WWE, we may not ever receive from, you know, we may not ever get again. He's created. He's reinvented himself multiple times in both times. Was fantastic. Of course, The Undertaker is going to be all in this clip. He's all about popping out of the darkness. Love it. You think you know me? That's a young age right there, man.  Let's go back, bro. May you rest in peace, my guy. Rest in peace. All you wise asses over here, cut their lights out. Wait, wow, that's, I've never seen this segment before. This is actually the first time we've seen this. He said, cut their lights out.  That's cool. Wait a minute. I've never seen this segment. I don't remember this segment at all. This is actually, I'm not making this up.  Wait, this is so funny, bro. This was like the shaking camera effect. There is a recent report. We're saying Jericho, I believe he was doing a concert with Fawzi overseas. And he had to be sent to the emergency room, well, not emergency room to the hospital. So I'm not sure how, you know, how he's doing, but prayers go out to him.  Not sure what happened exactly. So if you guys know, comment down below, let me know. But I did see people were talking about it in my sub box about Jericho being hospitalized. So wishing them a speedy recovery, man. He's definitely a legend in wrestling. And we always got to show our flowers, you know, show them flowers while they're still here. That's, that's always the goal to show that we appreciate everything they've done for us. Whether it's in WWE, AEW, Ring of Honor, New Japan Pro, we appreciate them for always entertaining us, no matter wherever they went. So. You got to love it every time. The authority, it's authority power ring. And then Steam coming out still one of the most iconic things to see Sting in the WWE ring, only for him to lose at WrestleMania, the Triple H. Just still irritates me. I like how Randy Orton was like, all right. Undertaker, man. He will always, honestly, it could be a compilation of just all the times the lights went out and it was the Undertaker, you know what I'm saying? It's just, I really wish I could have seen him in person in my wrestling, just that entrance alone. Uh-oh. Who was that? I don't see who that is. ECW was a different time. Damn, man. I wish you the best, Jeff. Hope you okay, man. And just take care of yourself, man. That's all that matters. I think this is when, yup, it's the gong. That's awesome. You hear the pop from the crowd. But he was dripping with sweat. He was dripping with sweat. He was busted open. This was a cool moment. And then this made that segment even more better, though. That was pretty cool to see all three of them in the same ring. Yup, Kane. Kane, this is a cool moment. I can see why that being number one. I can see that. Potentially, I can see that. Would I have made it my number one for this type of video? I'm not sure if I would have made it my number one. I think for me personally, the number one clip, for me, gotta be the Stone Cold. I may have probably forgotten about this clip, that clip. I don't remember seeing that live. So the Stone Cold one for me would probably get number one in this video. Just a simple fact that he cut off the lights in each section because they kept saying the what chance, only for them to turn back the lights on. And he's right there. Just what? What?  Let me know what was your favorite clip from this video. Appreciate all the love and support. Road 2. Seventy K. Appreciate y'all kicking with me. See y'all next time. Peace.