Hi everybody. When I give a presentation somewhere, I'm pretty much contractually obliged to have some Lisp cartoons in there somewhere. So I was trying to think of what kind of Lisp cartoon I could start with, and then it kind of occurred to me. I wanted to bring in the whole politics thing that's happening right now. And then I realized, oh, the closure logo could be kind of like a basketball. And so then I had this idea, and I thought, well, we need some tension in the cartoon. So Obama has to trip on something. And first I was thinking, well, maybe I should make him trip. Maybe Mitt Romney is throwing some money, and he trips on it because he's throwing money on the cart. But then, like, that has nothing to do with Lisp. So I had to come up with something to trip on that has to do with Lisp. And the solution to this, of course, was slime. All right. I'm going to talk about Webfui. This is a functional client-side JavaScript framework for ClojureScript. Now, there's a million client-side frameworks. I'm sure if you Google the term yet another JavaScript framework, you'll find 10 different frameworks with that name. Now, so, you know, the most important thing when you're looking at a framework is, you know, what were the goals of the designer? And, well, before I get into that, let me just talk about some basic terms. Most people here probably know it, but since there will be a video, I figure I should define a few things. The first one is, what is the DOM? So when you write HTML and the web browser displays your web page, it creates this internal data structure that represents the web page. And the thing about that data structure is it's mutable. So when you write JavaScript, you can actually muck around with that DOM to change the web page in real time. And so Clojure people don't really like things that are mutable. Now, the second thing is, what is EDN? So EDN is basically the serializable part of Clojure. So it has the maps, the vectors. So it's a subset of Clojure of just the data structures that are serializable. So if you're not familiar with EDN, if you just pretend every time instead of saying EDN, I say syntax expression or I say JSON, you'll pretty much know what I'm talking about. The final thing is what is Ajax? So I'm using Ajax in the broadest sense, meaning any time after a web page loads, if the client talks to the server, I'm going to call that Ajax, even though, of course, we don't use JavaScript and we use Clojure script and we probably wouldn't use XML. We would use EDN to send to the server. Now, so what are the goals of my framework? The first thing is, we want to do things the Clojure way. So I tried to come up with something that I feel embodies the Clojure way. Now, of course, everybody has a different opinion on what the Clojure way is and there is no one person who gets to decide what the Clojure way is. Well, maybe there's one person, but anyway. The next thing is I really like functional programming and so I wanted to do something that let me write most of my code as functional. Now, the last goal is something very specific. What I would like is that we just have an atom that contains EDN data, so just serializable Clojure data structures, and that I want to be the DOM. So I want to just be able to stuff information into this atom and I want the framework to just synchronize that with the DOM for me. Now, the standard way that we represent web pages in the Clojure community is to use Hiccup and that's what I really want the EDN to look like. So now there's other people, of course, who have done this sort of thing. So one example is the Singult framework that Kevin Lina has come up with and there's other folks that have played around with these ideas and also in other languages like Haskell, you know, this kind of idea isn't that uncommon. But what I've done is I've tried to take this idea to the extreme to see what it would look like and I feel like you end up with something that's actually a pretty pleasant framework to do web development in. Okay, so there's four parts to Webfui. These are pretty much independent libraries and I'm going to go through them all one after another. The first one and the most low level is Webfui DOM. Now, Webfui DOM has only one job and that is to take a Clojure atom and synchronize it with the DOM of the browser. Now, let's look at a demo application that does this. So here's the simplest application possible. It has two text fields and it adds them together and then shows the result. Now, let's look at the code for that example. So here's the server-side HTML. This is the only time I'm going to show anything server-side. Basically, you can see this is braindead HTML. All it does is load a style sheet, load a JavaScript file, which is, of course, ClojureScript, and then everything else from there happens in the JavaScript. So all examples have exactly the same structure, HTML. Uh-oh. All right. I was warned to use the ethernet and now it's coming to bite me here. Let me see if we can switch over. Oh, dead air. Okay, that looks like it's performing well. I should be up and running again in just a moment here. Okay, so let's look at the actual client-side code that runs this example. Now, the thing about this code is it's very ugly because all this low-level library does is it only solves the last of my three goals, which is synchronizing with the DOM, but it doesn't solve the first two. It's not functional and it's not the Clojure way. So what you can see here, what we do is, you know, we load the libraries. Then we, here's my DOM. It's just an atom that starts off as nil. And then there's a function where I, that I call in the library saying, I want this to be my DOM. Then we have a couple of global variables here that we just set to zero, which are the A and B values we're going to add together. And then we have this function called render all. And this actually just generates hiccup and it embodies our web page. So this is where the HTML is generated. And you can see all we do down at the bottom is we just add A and B to show our result. Now, we need a function that actually takes this rendering and sticks it into the DOM. That's right here. So this is the imperative function here. And then we want to actually call that so that when you first load the page, we see this instead of a blank web page. And then here's the rest of the code. Here's a validator because, of course, browsers don't have text fields that numerically are limited numerically. So you have to implement that yourself so we have to make sure they type in a valid integer. And then here we have watch functions. And this is what actually performs the work. So you can see if I go back right over here, I declare a watch inside my HTML. So this is an extension beyond hiccup that you can attach watches to elements in your data structure. And then, so why am I using watches? Why am I not using events? So personally, I found working with this that events are really not very good for doing functional programming like this because events only have a lifespan that's instantaneous. So an event happens, then it's over. What really, when you deal with functional programming, what you want is you want to deal with entities that have a lifespan. So what I would really like is, instead of getting an event saying, oh, somebody changed text, what I really want to see is just, you know, what did the element look like before they changed the text and what did the element look like after they changed the text. And if I have access to those two things, then I don't need some complicated event object. And I no longer have to read the JavaScript documentation on the event object to remember when I deal with a text area of field, what attribute do I have to check on the event object to figure out what the new value is or whatever. Like, that's just a lot of complexity. And of course, we're familiar with this enclosure in the closure world because we don't have, you can attach watches to atoms in closure and there's no such thing as add event to an object, to an atom. So somebody could have written that, right, where every time you modify an atom, you also send in an extra data structure that says, here's what I did and why I did it. And then you could read that event object, but that's just extra complexity. We just want to see the before and after and we can handle everything ourselves. So, and the way you can describe this is basically show me, don't tell me. I don't want you to tell me the event that happened. I just want you to show me the before and after of the event. So that's why we have watches. So you can see, just to run through this, you can see that when you add a watch to your DOM, you get as a result the old element and the new element. And then this new element, we can actually just read the value right out of it. By the way, Hiccup, of course, has lots of shortcuts where you can, if you don't want attributes on an object, you can just leave off the attributes or you can do things like where you add a class identifier or ID directly to the tag name. So the WebFui library will automatically normalize that so that you're guaranteed that the first item is in the list after the tag name is always an attribute list. So then we just need to check, is this a valid integer? And if so, then we're going to set our global variable equal to that new integer. And then, of course, we have to call update DOM so that we see the result. And then the second one is exactly the same thing. Now, as I said, this is on purpose ugly code. It's just supposed to show the simplest thing possible here. So here's the resulting program. So I can go in here and... What's going on here? Oh, you know what? I think I loaded an old version of this. There we go. So, okay, great. So I can type in... I can just type in numbers here and you can see it automatically updates the result. Now, when this page first loaded, it basically initialized the page with the HTML from the render all function. But then after the initial load, it won't regenerate all the HTML. Instead, what it does is it performs a delta calculation between the previous HTML and the new HTML and it only updates the minimum amount possible to bring it into the new state. That's why when I type things, we actually see that the cursor here, the first item remains focused because if I was to just delete all of this and rebuild the entire page, it wouldn't have focus anymore. And there's many other reasons why you never want to do a wholesale replacement of the page. For instance, CSS transitions have dependencies that will cause your animations to look wrong if you erase items and replace them with identical items. And this will automatically now validate wrong inputs. So if I try to type in alphabetic characters, as I'm doing now, nothing happens because as you saw, only when it validated did I update my global variables and those global variables decide what appears. And then also I validate that the number isn't too long. So if I keep in typing numbers, it will limit it. If you go much past that, it'll start showing it in scientific notation and it looks ugly. So, yeah, so that's basically it and for the basic example. But as we saw, the code was really ugly for this. So how can we make it better? So how do we make webfui pleasant to use? Well, what we want to do is we want to add another item into this chain. We want to make this functional and we want to have a world state object inside our program. And when the DOM atom changes and our watchers get called, we just want to update that state object. And then the render off function, instead of taking the previous version of the HTML, it actually takes the state object as a parameter. And so if we do it this way, we can now write all of our code as functional. So the watchers and the render off function are now functional. They don't have to talk to the outside world. And this kind of design is basically what people used to call data flow programming where we have these boxes with data structures and when one of them changes, we propagate that. So here's the add DOM watch function I showed you a minute ago. And let's see how we can improve this now. So first of all, we get rid of the old element and we replace it with a state. So now you can see it receives the state as a parameter. And now what I have to do is return the new state. So what I do is I take the state variable and I associate to the key a the new value of a in this case. And then if a was a valid integer, we just return the state. Now this is ugly for several reasons still because for one reason I'm a believer in declarative programming and that a soak in function isn't very declarative in nature. What I want is I want a function where the body of the function looks like the data that it operates on and the soak in kind of breaks that rule. What I really want is something like this where we load in our state and then we build a new state and you can see a map literal in there where we're constructing it and you can see what the end result of the function looks like. Now this has a new problem though because now you can see there's references to b, the other variable. But we're writing a function to just handle a right now. So we don't have proper separation of concerns. So what we really want to do is we want to say oh, I just want to modify a in the state. I don't want to modify the whole thing. So how can we do that cleanly and still have it be declarative? So that's what the second library is for. It's called state patches. And basically what this library does is it takes, it lets you write just a diff description of how you want the state to change and then it will apply it to the state for you. Now the reason this works is that when the state in your program is always going to be very similar to the problem domain that you're dealing with, and so when the user performs an action, it will usually only modify one or maybe a couple of variables in your state because of how you have organized it. So it's highly localized. So we want to make pinpoint changes to the state. Now this is different from the DOM, right? So if you have a website for selling widgets and the user picks a new widget, the entire web page may change because you're showing all the data on this new widget. However, the state on the web page is probably only going to change like one variable that's called selected widget ID or something like that. So we don't want this for modifying the DOM. We just want it for modifying the state. And usually a diff has three parts, right? Things that have been added, things that have been edited, things that have been deleted. Well, I don't want to worry about all this stuff because usually with a diff, we have to worry about all these things. But when you create state in Clojure, you're usually going to have a map. And so with a map, editing and adding are exactly the same, right? If you just reuse a key you already had, then it edits it, otherwise it adds it. And we can simulate deleting by simply setting a key to nil. And that's almost as good as having deleted. So it's not a true diff with the system because you can delete keys. But what this allows us to do is we don't have to do all this bookkeeping with three different types of diff. So here's what the function looks like. Essentially in its basic form, this state, this patch function, is just a recursive map merging function. So if it encounters anything that's not a map, it simply does a wholesale replacement. And the one exception is that if you have a vector in the second to last example here and the diff that you're applying into that vector is a map, then it will treat the first item as an index into that vector. And it turns out that just from practical use, this is something you often want to do. You often have a vector of similar items and you just want to modify one single item in that vector. So that's the one case where you can do a diff on something that's not a map. And so I find this particular function very useful when you have a world state object in your program and that's what I use for this library. So with this new function, we can now rewrite our code like this where we just send back the value of a and we don't have to reference b. So now we have proper separation of concerns. It still looks declarative because we're just declaring the new structure of the state. Now the last thing I do is if you saw before, I actually have a function that I place in here. So I rewrote it as a macro so that it looks more like the add DOM watch function is like a command, kind of like a function definition and we don't have to explicitly send in a function. So this is what, after all the transformations, what we end up with and this is a much cleaner way of writing a watch. So what you see here is this is the second version of the program and this is all the code. So you can see up here we import our stuff. Here's our render all which hasn't changed except that we now use state variable that's passed in so it's functional. This didn't change. And then just to make it even more elegant, I got rid of the code duplication by just pulling the ID of the element out of the watch result I get back and so I can just handle A and B simultaneously. So this is, in my view, a pretty elegant way of writing something like this. Now, sometimes things don't change the DOM but we still want to capture them. So as you saw this watcher does is it watches a part of the DOM. So what if the DOM doesn't change? How do we handle that? Well, there's a mechanism for putting in plugins. So there's a plugin protocol and there's basically two different things that a plugin does in WebFui. The first thing is it makes hidden DOM changes visible. So there's a lot more you can do with DOM than you can do with HTML. So, oh, that didn't format. Well, no, that's good. So in this example you can see, you know, we have the two plungers and you can see the DOM plunger has all these extra features. So what am I talking about here? So let's say you wanted to display a web page and you want a, you have a scroll bar in your web page and you want that scroll bar scrolled all the way down to the bottom. Well, there's no way you can write HTML that says, oh, place this scroll bar all the way down on the bottom when you display this page. The only way to do that is through JavaScript. You have to call the scroll top property on that item. Another thing that you can't do is that obviously a browser knows when you've pressed a button because when you hold down on a button, the image of the button changed into a pressed down button. But we don't really have access to that. There's no way to display a web page with a button already pushed down. But there is a pseudo class in CSS called active. Now, why that isn't just a regular property on an item? I don't really see any good reason for that. So with this type of model I'm showing, since we're trying to avoid working with the DOM, we have to lift items that are only available in the DOM into the regular HTML so that you can modify them directly. And so that's one thing that you can do with plugins. The other thing is that you might want different type of watches. So I just showed you the basic type of watch. But if you're dealing with something like mouse, somebody is wiggling the mouse around the screen and generating all kinds of points with a mouse move, that isn't even a hidden DOM property. So we have to somehow be able to capture that. So the first plugin I'm going to show is the scrolling plugin. So the demo of that is right here. It's pretty basic. We just have a scroll bar here. And if I move the scroll bar, you can see it changes the number down here. I can go down here and edit the number. Oh, another little technical glitch. I should be able to edit the number in here. And it would move the scroll bar so these two are synchronized. So this is what the code looks like for this. So this is just the part that responds to moving the scroll bar or changing the number. So the first one, all it does is it just gets the scroll top of the element, which is now lifted into the regular HTML that gets returned as the new element variable. And we just set the position in our state to that new scroll top. If they change the number in the text field, you know, I have a function here called triparse that simply makes sure it's a valid number just like we saw earlier and just sets it to zero if somebody types in alphabetic characters. And so it does the same thing. It just sets that same position variable. And that position key in the state drives the values for both of those items. Now let's talk about something more complicated. How would we handle a mouse? Now, the way people have been handling mice has actually changed a lot in the last couple of years because people use mobile devices. And so one thing that you used to see a lot is that web pages would give you hints when you had your mouse hovering over an item or would highlight items when a mouse hovers over it to show that they're active. But of course, there is no such thing as hovering on a touch device. So usually, most mouse actions now are more like gestures where we capture when somebody pushes down on the screen what movement they do with their finger and when they release it. So just capturing that covers 90% of what people want to do. And that's what this plugin does. So if you need to do hovering, which most people don't these days, then you can write your own plugin that adds that feature. But this simplifies it by treating gestures as a separate entity. So, well, let me show you the sample code for this. So here's just a circle of numbers. I can click on a number. And you can see it automatically highlights that number out of the set of numbers and gives you a little ghost. And I can drag this ghost somewhere else and it will add that number together. And we can keep doing that. And we go like this. It will keep making larger and larger boxes. So this would be like the start of a simple game like what's that called? Not Gattica, there's a Galcon. It's sort of a game where you drag planets together in order to do strategic stuff. So this is my idea of how a modern web app usually handles input from the mouse. And of course, I want this to also work on an iPad. So here you can see the same circle on an iPad and I can click on an item here. And I get a ghost and I can drag that to another location. So this plugin automatically handles both of those modalities. Now, let's look at the actual code. All I'm going to look at is this, most of the code is just involved with rendering these boxes in the hiccup format. This is the only code that actually performs an action. And the important thing here is that this mouse watch, which is a new type of watch and it adds an extra parameter called points, which gives you the entire vector of all points as the mouse movement happened between pressing the button before it was released. So that's the one change. And then the other thing is that it gives you the first element and last element of the motion. So if somebody drags from one point to another, you get the first and last element. And so this is the only function that exists in WebFui for mouse interaction and it handles dragging and it handles mouse up, mouse down, mouse move just in this one function. And of course we don't want to function like mouse down, because what do you usually do in mouse down? There's a global variable called isMouseDown and you set it equal to true so that later on in your mouse move you can then have something happen only when the mouse was down. So that's already imperative programming. So having, treating the mouse action as a gesture, we can be completely functional. And the most interesting thing that I'm just going to explain is this sizes part. This is the part that increases the size in our state to be the new size where it adds the location we're moving from to the location we're moving to. And the interesting thing is that, as you saw, if I decide not to let go the mouse on one of those bubbles, but instead just go into the white area, it will cancel my action. And in the same way, if I move into a box and I move my finger away, I want it to subtract that value that was temporarily shown as a preview. So this code handles all those cases. So it handles the previewing, it handles the addition and the subtraction because the state that is passed in here is actually the state at the time the mouse was pushed down. So what this means is one of the nice things about functional programming is that if we have a world state, we can keep old copies of that state. And for mouse movement, the most important state that we want to keep is the one at the time the mouse was pushed down because if the user wants to cancel the action halfway in their gesture, we want to be able to get them back to that default state. And so this one function handles all those things at once. Now let's look at a slightly more complicated example. This is just a simple calculator. So this has all the functionality of a typical 80s desk calculator. And it has memory. It properly performs overflow. So if I multiply this by a large number, let's do that again. Then it'll say overflow. And there's tricky things you have to do. Like if somebody presses the decimal point and then types in trailing zeros, you have to display those. So it handles all those cases. So this program in Webfui is 92 lines of code. And just to show you quickly, here's the actual code. I won't go into this in detail, but you can see it just declares some data structures here. And then here we handle all the cases of overflow and the decimal point and all that. Here's where we watch the watch functions for the number keys and the operator keys. And then the important thing is that right down there, when you use the framework library, that's what gives you the ability to work with state. So that's a layer, a library that is on top of the lower level DOM library. You just call this function launch app. And that one function out of all those 92 lines of code, that's the only one that's truly imperative code. Everything else is just regular functional code. So now let's talk about the elephant in the room, which is performance, right? Because every time a user action is performed, we generate this giant hiccup structure that represents the entire web page. Then my library performs a delta calculation on that data structure. And then we update only that part. So all of that has to take time. So to see what kind of effect that has, here's an example where I just created 40 of these calculators. So this page has over 2,000 DOM elements in it. And each individual calculator, you can press the buttons and it does work. Now, if I do timing on this on my laptop, it takes about 250 milliseconds to handle a key press. So that's not really great. I mean, we want to have it feel responsive. We want at least 20 frames a second response, which would be like 50 milliseconds. So I think to make this approach really work, I would want this particular example to run in 50 milliseconds. Now, there would be one easy way to do this immediately. And that would be to simply write the library itself, most of the work instead of the library, in JavaScript. And I've done that in the past, created similar libraries that do this sort of thing. And I found that JavaScript will give you this level of performance. Now, I'd like to avoid doing that. I'd like to keep the library in closure code. But even if it was rewritten partially in JavaScript, it would, of course, be invisible to the user that can just continue to write closure script. Now, let's talk about Ajax. So that's the next thing we have to deal with. So Ajax is tricky because we have this beautiful functional program. And anytime we talk to the server, it means that we have side effects. So how do we deal with that? Now, one way of doing it is that we have a request queue in our state atom. So what we can do is, in all our functional code, if the functional code realizes, oh, we need something from the server, we have inside the state variable some kind of queue where we say, oh, fetch this extra thing from the server for me, and then we have some other imperative code that pops stuff off of that queue. You don't want to do that. Just like I was talking before with events, you really don't want to deal with things that only have an instantaneous lifespan. And putting these requests into a queue in a state atom, that's not really the job of the state. The job of the state atom is to show things that persist over time, not to just, for an instantaneous second, pop in a little message and then have somebody else consume it. That's not what state is for. What I find, just in terms of my own practices, what works for me is to always think of Ajax as a flaw in the state object. And so the way you want to think about this is inside our closure script program, we have this world state object that's supposed to hold all the state for our program. Now, the moment we do an Ajax call, we can see that this is a lie because the only reason we would do an Ajax call is because there has to be some other state out in the world that we either want to write to or read from. So the moment we do that, we know that this world state that we have is a corrupt system. And so the best way that I like to think of it is that the places in our program where we have to communicate with Ajax, it's almost like a form of corruption in our world state for our program. And as we know with corruption, corruption tends to spread like a virus. So if you have corruption somewhere in your data and you keep using that data, it's going to break other things in your program. So I like to think of server communication as a virus. So the idea here is that we want most of our functional code to say to itself, oh, this world state, that's all there is in the world. But then there's another part of your program that knows no, no, this isn't true. There's other state. Now what will happen is that if you think that your world state is the entire world, then eventually you're going to run into problems and you're going to run into the situation where you get corruption into your program because there's updates happening from a separate location. So now if you think of it that way, if you think of it as a virus, there's three different ways that you can handle Ajax inside of your program. So let me give you an example. Let's say you have a web page for browsing widgets. Somebody clicks on a picture of a widget and now we want to load in all the information about that widget. Well, that information about the widget is on the server and we're pulling it with an Ajax call. So now all of a sudden the functional, our state has like an item called selected widget ID. But inside of the state there's the information about that widget doesn't exist. So now our state has become corrupt. Well, we might get lucky because it might be that so we just display a blank page because we don't have anything better to show. But then immediately a couple seconds later the user clicks on another item and we do have the information about that. The other thing is we can try to contain it. So we can say, okay, if you click on an item and we can't display that information, let's stop you from doing anything else until we get a message back from the server with the result. And the final thing is we can cure it. So the only way to cure this virus is to get a response back from the server. So what we do, so I created a calculator with persistent memory. And the only way the program differs from the previous program is that I set the memory, instead of setting it to zero, I set it to unknown. So this is like a little bit of corruption in our program. And so if we try to read that memory, that means the amount displayed on the calculator will also be unknown, which isn't a valid number. And so this corruption has propagated. But however, I put a watch on the state variable and that watch checks to see if the amount in the calculator is unknown. And if so, it sends off a AJAX request to get the memory that's stored on the server for this calculator. And simultaneously, if somebody changes the state and the amount was already unknown, in this particular example, I simply prevent people from doing anything with the calculator while the amount is an invalid value. So we're containing the damage caused until we get a proper message as a response. Now you could make this more fancy and let the person continue working. If they want to do things like hit the AC button, then we don't care that there's a corrupt memory because that'll get overwritten anyway. So you could get really fancy and let people work a little longer even if the AJAX result isn't back yet. So this is just a model that I found useful of working with this type of library and doing AJAX. And this is completely orthogonal to Webfui. So there's nothing in Webfui that deals with AJAX, but you can just have a separate function that you use to watch your state and have that function be imperative and it's responsible for talking to the server. And the rest of your code can be completely unaware that anything like AJAX exists or that it has to talk to the outside world. So I won't bother demoing that. So the very last thing I want to show is something that's a little flashier. So this is an example of a little inverse kinematics engine I wrote on top of Webfui. So here we have a little guy and I can click on his arm here and the arm will move like that. And this is completely functional, 100% functional code. I can move him every which way here and I can move his little ball around here. So yeah, so if you download the example on the Webfui examples on GitHub, so it's under Dr. Code Webfui, you can play around with this inverse kinematics library. And yeah, and you can see the performance is pretty good and this will work on an iPad, though it's a little bit slower on an iPad. And that's pretty much my demonstration. All right, I think that's it. All right, thanks everybody.


short I don't think a lot of people know this information if they did it'd be very off-putting.  What's up brother? How are you? We're doing debates on why aren't you why aren't you vegan? Why am I not vegan? Because I need to be able to eat fish and salmon.  I eat chicken. Yeah. I don't buy chicken and all other animals I don't eat it.  Chicken? Someone else cooks it for you? Yeah, yeah.  But the only meat I buy is fish. Okay and do you think fish feel pain? Do you think fish suffer? I don't think they know it's happening to them. I think they feel it, but I don't think they know it's happening to them. So is that good or bad? If they suffer and they don't understand what's happening to them isn't that worse? Wouldn't that make you suffer more? Probably, but I need to be able to eat fish. I can't not eat fish.  You'll die? Yeah, I can't just eat vegetables. What do you think I just eat vegetables? Do you think I just eat vegetables?  No. So what do you eat then? Vegan burgers, burritos and vegan pizza and vegan cheese and vegan ice cream vegan whatever I want.  Why did you become vegan?  You know what I mean? So if I wouldn't do it to my worst enemy why would I do it to these innocent animals including fish? With me it's the fact that I've grown up eating meat so it's like right now for me to stop eating meat and eat vegetables would be like that'd be crazy.  That'd be crazy. I think like if I grew up just on vegetables and I was taught these things I think it would be different. I was eating meat for 26 years. I don't see it as like I'm going to get bad karma if I eat meat because they're reliable. Do you believe in karma? Yeah I do but... Why do you think it applies to animals? What do you mean? And even think about it. So he believes in karma was to stop eating meat. Yeah. The world will just be full of animals running around like they'll keep reproducing. Do you eat meat to keep the numbers down? No I don't. I'm just saying. Okay. That would happen. No it wouldn't. Because what happens in ecosystems is they find their natural balance. The chickens that you eat they don't exist in nature. They're selectively bred human created chickens. Are they serious?  They can't hold themselves up and they... I know like salmon and prawns is what I eat. Yeah but salmon will never be bad. What do you think the salmon feels when they get hooked in the face and dragged out of the water? I don't know. The salmon is not human. The salmon hasn't got... It might have feelings but I don't have feelings like a human and it's not... They don't have to. It's not the dominating predator. Are you a predator bro? To the animals that I'm eating then I am.  No I don't but... That's not a really predator of you though bro. Here's what it is. I'm saying I don't eat like pork and stuff like that. You don't eat pigs? I don't eat pigs. I rarely eat chicken. What about cows? You eat cows? I would say no because it's so rare. And what about like you don't eat lambs? You don't eat lambs? No. Just fishing eggs? Yeah. You know about the egg industry? Do you know what happens to those hens? No. I mean like I know I know all companies in the world they do something bad. I know that. I know that's a fact. I don't want them to but I'm not there. I can't stop them. I can't go to a farm and say oh do this this way. But you could you could say I don't want to pay for it because it's against my values. I'm saying like in the egg industry. The animals gonna die. Do you know what I'm saying?  I feel like if the animal had the same abilities as a human it would be a different story. They do. They do have the same abilities but not the same but not equal but they feel pain and they suffer and they don't want to die.  The fish would probably do it. The fish would probably do it. Yeah but cows are bigger than us. They don't eat us. And just because let's just say an animal would do something doesn't mean that we should copy their behaviour. I don't know. It's what it is. I eat fish. I eat fish and eggs and I don't think I'll ever stop you. You don't think you'll ever stop? Would you watch a movie then? A documentary on it? I've seen them. I've seen them. I've seen them. What did you what have you seen? I've seen Seaspiracy. You've seen Seaspiracy? Yeah that was quite shocking. Did that make you want to not eat fish? It made me want to not eat fish but like I don't know. I really enjoy eating meat. I don't enjoy eating fish but I also love eating like vegan food as well. So I'm not too bothered. I have gone vegan before like for a month. Oh really? But I'd never make it alive so I'll probably have more of like a healthier diet. Why was it difficult? Because like alright I'll see you soon. So you want to sit down with me?  Because I really enjoy eating meat and like eggs for breakfast and stuff. So it was hard but I guess I just had like granola and like do you know Oatly? Yeah. Like it's like yogurt. It was hard because that's just not something I'm used to. But I do eat like vegan food because I'm from Uganda so we have a lot of like you know vegan food. So I enjoyed it. What is a Ugandan staple? Isn't it cornmeal? Or they have lots of like sweet potatoes or what do they have? Yams? We have like this like banana called Matauke and then we have like beans like it's good. It is really nice food. There's a lot of like plant based food. Yeah of course there's a lot of plant based stuff. Like if you're from the village and you can't afford meat then you're going to be having vegan food anyway. Yeah yeah yeah of course. So why did you try to go vegan? I always do the spiritual reasons and you know what the crazy thing is when I did it I felt a lot better. I had more energy. It was just hard to maintain. It's not exactly cheap either. I can't lie to you like trying to get good vegan food. It's not cheap. Okay. So it wasn't cheap when you tried to do it. Yeah. When did you try to do this? January. This January? Yeah. That's interesting. So you did it for spiritual reasons. Do you think there's some negative energy attached to eating the bodies of animals that have died in slaughterhouses? No. I'm just doing it for reasons because obviously on Christians we're supposed to like fast. We're supposed to like give up certain foods and stuff so we'll be able to do that. Like it's a sacrifice but it's not easy but you get like you reap the benefits. But a lot of the stuff like that's that God has made is better for you compared to all like the unhealthy food like all like the meat and stuff like. Yeah but you know the animals that people eat if you believe in the Creator are not created by God. What do you mean by that? The animals that people predominantly eat are human created. Like please give me an example. So there was originally like wild animals and humans enslaved them, dominated them and then started to selectively breed them with each other to produce whatever product outcome they wanted from them. So like for hens they would selectively breed them to produce more eggs for chickens. In the meat industry they selectively bred them with other chickens to become like Frankenstein chickens to produce all of this meat really really quickly and they feed them with antibiotics to make them grow quicker. In the dairy industry they are selectively bred to produce more milk so they breed so that if they get good milk producers they just keep breeding them together over generations until they're like really really productive. So like these animals are just human selected over time to be meat machines or milk machines or egg machines you know. What about you know the people in like third world countries that only have like let's say like animals around them like should they just go vegan if they don't have anything else to eat? So I don't feel comfortable with someone in a survival situation telling them to starve which is why I do my debates here in the UK actually with people because I know people in the UK they do have a choice you know. If someone was in a survival situation they didn't have a choice and they killed a native fish it's a different situation actually it's much different so should that person go vegan? Well I don't think they have the choice to so. I have a question for you why is it you feel like people wouldn't want to be vegan? Is it the sacrifice or do you feel like the vegan community are positive with spreading their message? The messenger matters a bit but people will say well I would go vegan but that person was rude to me or they're not positive or their movement's not positive. I think that's usually an excuse because they don't actually want to because they habitually eat meat. They prefer the taste and it's inconvenient for them to change. The animals' lives and suffering does not on the scale weigh enough for them to change their lifestyle. That's what I think and then what happens is they begin to look for ways out of it and excuses out of it. That's what I see most commonly. It's hard to explain what goes on to animals in a positive way. Do it, yeah.  There's no industry, there's been no tragedy that has caused as many deaths as meat, dairy and egg industries. Nothing comes close. Are you sure? Let me just give you the numbers. At this point 80 billion land animals each year and between 1 and 3 trillion marine animals each year. I think it's in around four weeks. Yeah.  There is nothing on earth that could... Even if you make the argument that a human suffers much more than a chicken. A human suffers much more than a fish because we have a deeper experience. Even if you were to use that logic, the amount of animals that are being killed is so great, so vast that the animals would have multiplied that suffering a long time ago. We don't do anything else that causes this much suffering and killing. I can't believe that. That's crazy. I think it's good to educate people though about these things. You see with the food industry how the packets and I have the labels of chemicals and stuff and they won't actually put everything else on there. Even with vegan food, what's the state of all the chemicals? Is it actually good for you? Because that's like my little hindrance because if... I don't know what I'm actually eating. Do you get what I'm saying? I get what you're saying. So would you not recommend just being a raw vegan? No. Why is that? I would say a lot of raw food is really good and it makes you feel really good and it's full of fiber and nutrients and fiber chemicals and really good to be a lot of raw. I just don't think it's doable. You think so?  If I want a burger, I can go there. If I'm not spent, so I can get a sandwich. That's true. But if you restrict yourself as a vegan, then you've got to go back to... I need a burger and go back to eating animals. Eat whatever you want as a vegan as long as you're not eating the animals and the animal products. So if you want a burger, if you want a vegan chocolate, if you want an ice cream, good but I still think you should look after yourself with lots of fruits and vegetables. 100%. So you were saying like, what's in like a vegan burger kind of thing? Do you know what's in there? How do you know it's healthy kind of thing? Yeah, because like I said, the packaging, they'll be like, oh, this and this and this stuff isn't it but they're not going to 100% tell you what's on there. So how do I know they're not doing that the same vegan food? Yeah, true. When you eat fish, right? Yeah. Let me give you an example here in the animal products. Okay, so when you're eating fish, you're not just eating the fish. Like you're eating everything that fish ate in their environment. So there's something called bioaccumulation. Oh yeah, I know that. You know about it? Yeah, I learnt in school. So yeah, the big fish eats a little fish and then all that mercury, the PCBs, I don't know the chemicals, we'll put them up here somewhere. But they will accumulate in that fish over time. 100%. The human comes and eats that fish and they accumulate in you. And the same is true of the land animals, so the chickens and the pigs and the cows because they're eating the pesticide-laden, you know, plants and that accumulates in them.  The animals are eating it over their life and it's accumulating in their body with the antibiotics and things like this. Oh really? Yeah. So you don't see that on a meat package. No, of course not. Yeah. But with vegan food, processed vegan food is not healthy for you. What is processed vegan food like chips? Like chips, potatoes, fried in oil, that's not too bad. But like, you know, if you're getting like a Burger King vegan nuggets, for example. Oh, okay, no, no, yeah, yeah. I'll eat them, but I know they're not healthy. Of course not.  That's why I go and get a vegan burger because I want a vegan burger. I don't go, ah, I'm trying to be healthy. I'm going to go get a vegan burger. Better be healthy. No, I eat a burger for pleasure. Exactly. I just don't think my pleasure is enough to justify animals being butchered and killed. And for my health, I go for the whole food plants, you know what I mean? Yeah. Like with no packet on there. No packaging on there. So it's just like, are there strawberries? Yeah. So that's beans. Mm-hmm. You know what I mean? And how long have you been spreading this message for? For nearly nine years. Nine years? Around the country or have you? So when as soon as I went vegan, I started telling everyone about it. So I was like, at first it was health, but then I started, I've seen a great activist called Gary Urofsky, who's a fantastic animal rights activist. And he's talking about all the things that happen to animals and the injustice of it, you know, and you know, it was the injustice of it that really got to me because they're voiceless. They, you know, they do have, they do make sounds that they can't speak for themselves in society. You know what I mean? Human beings can form coalitions and have other humans defend them. Yeah. But who's going to defend the chickens from us? The chickens can't. They've got no one. But like, wouldn't you say like an argument is just a chicken like, they're not going to live long anyway? Obviously like, that's a very, you know, kind of wicked thing to say. I don't really agree with it, but like, I do feel like a lot of people would just say that. I know. Do you get what I mean? And people do do that with the lives of chickens. They say, oh, it's only a bird. Like, who cares?  But to that chicken. Yeah. Because when you look at it from human perspective, you will go, ah, from my perspective, that's just the chicken. But what I ask people to do is like, flip it and look at it from the chicken's perspective. Like that's the only existence they have. And they didn't even ask to exist. Yeah. They didn't ask to exist. They were forced into existence, into a factory farm, and then they're forced into a slaughterhouse to die. I don't even know the full industry. I can't lie to you. Like, I think I've seen a few videos, but I don't know, like, the extent of, like, what is going down. Do you know? Yeah. Do you like to explain? My words can explain it. But actually, video footage explains it much better. So, I mean, I can show you a little bit of video footage if you wanted to. Yeah, go ahead. So, like, I'm going to just flick through for you so you get an idea. Because this goes for 40 minutes. Oh yeah. What about the propaganda? Like, green grass. And this is what people see. Yeah. You know, you see commercials, green grass, and happy animals, and then they'll show you on the plate. Yeah. They don't show you the in-between part. These are called barrowing crates. And this is where they give birth to their young. And they stay in these cages for up to five weeks. Five weeks. But they'll be... This is where they buy the cages and they go insane in here. This is so insane. It's why they're weaning in their young. And these are mothers. See, the piglets get stuck under here. Oh my goodness. This is so sad. These are dead piles. Are we supposed to eat them or not? No, no, they're just discarded. Oh. They're left out the front. At the front? Just at the front of the farm. Or at the back of the farm. This isn't even hygienic. You'll see this very often inside. That's a baby. Yeah. This is very common. I've been in these farms too. How did you find them? They're everywhere. You just look on Google Earth and you can see big long sheds with feeders in them.  They're everywhere in the UK. There's a sadness in her eyes. It's actually heartbreaking. The antibiotics, they feed to them.  Wait, why do you have to... Oh, because of how small it is. They get sick because of the contained space and all the disease in there. And feces everywhere. See these slats? They let the feces drop in. Yeah. But that's pigs and they clip their tails. Snip their tails off without anesthetic and clip their teeth down. And they thump the piglets on the ground, on the concrete to kill them or hit them with a bar. I don't know if I can watch this. It's too far away. Yeah. They thump them to kill them because they might not grow fast enough or they might be sick. But it's actually Red Tracta approve this as a euthanasia method. I want to show you this. Wait, is that a pig? Is that a pig? They're eating a dead pig. The pigs are eating themselves.  It's called cannibalism. It happens in factory farms all the time.  This is a gas chamber. Gas chamber? Oh, just like they're being sprayed with gas. They're being suffocated. Yeah, they're going into a dungeon filled with gas. CO2 gas. This method of slaughter is used for U.S. supermarkets. Yeah. Supermarkets? Yeah. 86% of pigs in England and Wales are killed in gas chambers. Oh, goodness. This is wicked. But that's pigs. Dairy industries. Yeah, let's have a look at the dairy industry. So they force her into pregnancy. Force? They stick it... It's actually quite perverted what they do. They ejaculate a bull to get the semen out of him. They sometimes use a big electro-ejaculate.  So this is him doing it. Are they constantly pregnant? So this is him doing the insemination thing.  It's incredibly uncomfortable for them and so she'll have a nine month pregnancy and then she give birth right. Yeah. And then she's producing milk. Oh, yeah. Because otherwise how's she going to produce milk? She's going to have a baby, don't she? Yeah. Is that the baby? Yeah. They take him away? They separate him so they don't drink the milk. The farmers will say it's for their own good in case the cow tramples the calf. What? It's a lie. The baby. Yeah. They take him away. And this is standard practice. Standard? Standard. Across the board.  So they both experience trauma, trauma of the cow and their baby because they're very maternal animals and they keep the females in these hutches here. Are they going to see them again? No. They don't see their mums again. Maybe a backyard farm here in Nehrmite but not in the industrial dairy industry. But I don't see why they have to separate them. Because they'll drink the milk. They've got to sell the product. So if you want milk and cheese and yogurt they can't let the calf drink that milk, can they? So where's the calf going? So female calves will go on to, they either make up the dairy herd so they'll keep them in the hutches separate and then they'll grow them until they're of age to be inseminated themselves and they'll become a mother, really young and get their calf taken. And then they'll have that cycle happen to them as well and it happens about three or four carvings. They have their calf taken three or four times and then they get slaughtered for beef. Is that one pregnant? It's a dairy cow. Oh no. A lot of dairy cows are slaughtered while still pregnant. Whilst pregnant? They can be, yeah. I forgot the statistic. We'll put it up here on the screen. There's a lot. And they cut the little fetus out of them as well in the slaughterhouse. That's a dairy industry. The male calves can be shot on the farm. Shot? Because they don't produce milk, male calves. Are they not meat then? A lot of them are too scrawny. The males? So the male dairy breed calves can be shot on the farm on their first day of life. But that's being outlawed at the end of this year. Otherwise they get raised for veal or beef. Or what they can use is a specific type of semen from a beef cow and they'll impregnate that into the dairy cow so that she produces a beef cow. And then they get the milk out of her and then a calf will be basically raised for beef and killed for burgers. It's like they're just like slaves. Yeah, they are slaves. And this is her, these are called hobbles. Yeah.  Abused? Yeah. Why are they getting abused?  They don't do what they want. But do you think like this industry, there was good farmers, would it be better or would you not think it would make a difference? I think it's better if the farmers are better. Of course.  You prefer a slave didn't get whipped 12 times and only got whipped three times. But you know, I'd prefer they weren't enslaved at all. Yeah. And that's what being vegan is, it's saying we don't want animals to be subjugated and treated as property at all. If we're going to have animals, it's to care for them, it's to protect them like they do. To love them and care for them and let them be themselves and not to take something from them. Because we're only doing this, they're only doing this to the animals because people want to eat them, eat the cheese. They're this meeting of demand and all these people out here, they're the demand. And the farmers are going, okay, we'll supply you and this is what we're going to do to the animals for you on your behalf. You know, it's crazy. Like the things that we've just discussed, the video you just shared with me, I don't think a lot of people know this information because if they did know this, it'd be very off-putting. Yeah. But that's why they market to people. That's why they spread the propaganda. It's why you only ever see... Propaganda. Propaganda is like marketing, it's like you see the green grasses, the happy animals and then you see the meat. But they don't show you this. Yeah, they can't. Because these are all customers to them. You know what I mean? So they have like Red Tractor and RSPCA assured and all of these humane labels and free range and all this stuff. Do you agree with those? No. Why don't you agree with the RSPCA or like PETA and all them ones? So RSPCA are not like PETA. PETA are a vegan organization. RSPCA are not a vegan organization. Yeah, so you can go into the supermarket and you can buy a meat that has an RSPCA label on it. Don't you think that's just a bit... doesn't really make any sense? No. If they really cared about animals, you wouldn't want to see them chopped up and eaten. But they'll say, oh it's because our farming practices are better. But if you care about animals you don't want them to be slaughtered either. You know what I mean? The majority about like the main topic out all of this is money. It is money because they're making so much money. Like, I know I've even spoken to people like would you ever be... they've asked me would you be vegan but I've done it but would I do it a long time? Probably not. But if I was to do it, I'd start cutting out red meat, then I'd start cutting out like chicken, then I'd start cutting out fish and I'd like alternatives. It's just difficult. And I don't know if it's like student-friendly being vegan. I don't think it's like a cheap decision. How is it a cheap... how can it be a cheap decision? It can be cheap and you're right. This all happens because of money and the money that you give them and that's why like we were talking about supply and demand before. But to be vegan on a budget is actually quite easy actually because the cheapest foods in the supermarket by far are the bread, the grains, the beans, the rice. Rice is the cheapest food per calorie on earth really. So all of your whole foods, the healthy foods that are good for you actually are the cheapest unless you're going to get some fancy berries and stuff. Yeah. But like whole grains, all the... you talk about your Gandham food. Like all of those to make the plant-based your Gandham food. That's all cheapest food in the supermarket. When you talk about like okay I'm going to go get a fancy pre-made vegan sandwich from M&S. Yeah. That's going to be like four quid or something. Yeah. But for four quid you could do like a quarter of a week shopping. You can get oats and you can get frozen berries and you can get pasta and you can get pasta sauce and you can get lentils to put in the pasta sauce. You can get this stuff called TVP it's a textured vegetable protein and you can rehydrate it and it's like mints. So there's ways of doing vegan super cheap.  I'm really thinking about what you've just said like I didn't realize you could do it on a budget. I've got a YouTube video called vegan on a budget. Yeah. Extreme budget or something. Yeah. I went to the test going like 20 quid or something. I come back and I've cooked like a week's worth of food because you get lentils right like red lentils and you can make a big curry out of it. Potatoes and it's super healthy. Yeah. Full of iron and fiber. Yeah.  Vegan cheese is not like I'm sorry that's the one thing I can't I don't like vegan cheese is really disgusted but the vegan like dairy ice cream all that sort of stuff is nice but the cheese I'm still not happy with it. Have you tried applewood? Applewood no. Try that. But I don't want to be deceived.  This here is this will help you what's your YouTube restaurant and your videos on there I made this documentary here and this is this is the one I showed you Land of Hope and Glory and here's some little food swaps tofu right if you like eggs if you love eggs if you scramble it in the morning you scramble tofu and you get it's called black salt kalam namak or something like this but it's got an egg taste and you sprinkle it on the tofu and it tastes like eggs and this here is the best app happy cow find vegan restaurants wherever you are and you can always come my name is Ida Ida and you Joey nice to meet you it was really nice having a discussion with you I really love talking to you thank you you're just amazing and I'm sure everyone's got to love you thank you good talking to you see ya


Hi, beautiful. Today, we're watching people. Hi, beautiful. DIY bangs. They never go good. They never go bad. They always stay rad. Hi, beautiful. Are you ready to get banged? Okay. Hi, beautiful. Bangs. Bangs. Bangs. Bangs. Bangs. Lenny, I don't know. Wait a minute. Let's watch people cut their own bangs and f**k them up. So bathy. A first-person video by Alexandria Zeal. I am going to be cutting my own curtain bangs. I am kind of nervous because I do have longer hair. If I cut it too short, it's going to take a long time to even out with the rest.  It's so thick and luxurious and so blonde. It's so naturally blonde. You have gorgeous hair. And when people have gorgeous hair to start with, I get even more worried about what the outcome is going to be. Very worried so far. I have zero experience whatsoever except for watching a couple tutorials. So I'm just hoping for the best and I'm going to try my best and do it. Great. Zero experience. I've watched a couple tutorials. Quickly pin back this hair. So this is the hair. Okay. The two front sections look relatively even. Not super crazy amazing even, but relatively even. We're all to a good start. Sort of. She definitely went a little too low with the section. This stuff at the top of the eyebrow, the, the, the, like there, you know, this one's going all the way down to the side of her head and I'm like, stop it right there. Don't go so far down. You're supposed to make sure you have a super center part. That's not looking to center to me. It's actually looking like a zigzag. I have this little score bottle I got from the Dollar Tree and I'm just going to spray it down. We're whipping up the water. It's getting hot in here. It's so hot. So whip out that water baby. I love that she's wetting her bangs. Nobody ever wets their hair before they start cutting and it's like, why? It's not that hard. Just take that extra step and just do it. It's going to help make the cut so much more easy and even and it's going to clump all that hair up into a little pile and it's going to fall to the floor and a little clump of wet hair instead of all those shards of hair everywhere that gets stuck in your foot. Definitely a PTSD from shards of hair. I've had an infected nail one time because of a shard of hair so be careful with shards of hair. They're dangerous. And comb it out and I've seen a video like this. I thought like in my mind this was just going to be a super easy process. Honestly, it should be because you just pull on one side to the other side and snipping it off. That's all you got to do to get a decent looking curtain bang. It's not going to be perfect. It's not going to be professional looking, but it's going to look good.  And that's all we're going for here. You got this. I believe in you. I have this marker and since I don't trust myself I'm going to just mark in the hair so I can make sure like it looks right. What? Yo, this is definitely a new technique. This is something I have not seen before. Congratulations. You get an award for doing something that nobody's ever done before. Finally, I get something unique these days. I don't know what she's really doing with that marker. I don't know what she's marking like maybe the length she doesn't want to go past. I'll see. That's how it would play. I don't know if you guys can see it or not. I mean, it looks like it would work but it looks really dramatic. Should I do it? Do it, do it, do it, do it, do it, do it, do it, do it. So I'm going to mist it one more time. Brush it out. So far so good. I just looked at the title while I was saying that and said, watch me fail so you don't have to. Okay.  I don't understand how because so far so good. I don't know. I can't do it. I can't. That cut looked amazing. It was exactly how you're supposed to do this. So what's wrong? Oh my gosh. You're kidding. It definitely should be longer than that, right? Whoa. It looks perfect. All you need right now is a blowout.  I guess I'm going to try the other side too because I'm not going to have one weird side. No. Why do you look confused about the result? The result looks perfect. And how are we going to go wrong? Because there's still a lot of time left in this video. And all that hair, that's pretty long. I don't know if this worked or if I just cut my hair. I feel like it worked, right? It did work. Are we not seeing the same thing? Am I watching something different? What's going on? I guess the moment of truth. I'm not ready for this. Well, um... It's a sleigh. It's a sleigh for me. I'm impatient. I'm not going to watch another video. I'm going to just wean it and hope for the best. Well, where are we going now? I thought we were done. She needs some face framing in the front. But other than that, she looks like she's up to something. She looks like she's going to do a lot more to her hair. So I'm going to spray all of this hair down. Brush it out. What? Your hair next time? Like, actually wet it. I don't know what this damp stuff is. Wet it. You know what? I can cut my hair short again. Won't be the end of the world. Look at all that hair. Gone. Gone. I think that was also a very non-smart decision. All the rest of my hair is going to be a lot longer.  I mean, this will blend together better. Going to see the curtain bang coming up. No, I don't. What just happened is what I'm wondering right now. Like, what exactly was the point of that? Now she has a bob in the front and long hair in the back. I don't think that's what you wanted. I thought you wanted curtain bangs. Where are we going with this? Look at all that hair. This is what it would look like with the short hair. She's, like, acting like it's a wig. Like, you literally just cut your hair short. You literally have short hair now. This is not a joke. That was your real hair. Are we good? Do I keep cutting? That's the question. And pretty deep. This is going to be, like, intense curtain bangs. Tomorrow, we'll come around now and we'll be, like, wet. What? Intense curtain bangs? It's a bob in the front and a party in the back. I have just completely lost track of what's going on at this point. I'm confused. So is she.  Last year, I rage cut my hair all the way probably down here or even longer to, like, right here. All of it. I'm sorry. Is a rage cut different than what just happened? Probably not good. Okay. So we're going for a mullet. I'm here for a mullet, but I just don't think that's what she wanted. Even though, like, I don't know if this is exactly what she was looking for. Like, it doesn't seem like it was. It's a very, like, anime haircut. If she styled it, like, flippy on the ends, it will look so good. I don't even have any critiques in the technique because I feel like she's just kind of creating her own haircut at this point. I, is it, yeah. I have no comment. Oh, it keeps getting worse. It's, like, curt. Cool. What would you do if that was your head? I would freak out. I decided I'm going to just keep cutting. This isn't okay. Do you know if I have to cut short? Do you know what? Coming through the screen. I'm coming through the screen. I'm coming through the screen and I'm grabbing those f***ing shears out of your hand. I've seen enough. So I'll cut this section. That was really sloppy. So I think I'm gonna have to cut all my hair.  Hey guys, I'm back. It's been a couple days after the tragedy. It's not near as bad as I thought it was. It was still definitely a mistake. I think as long as I curl it, it'll be fine. I also think that after a couple months, once it grows out a little bit, it will, like, fit my face and the length a lot better. It's just really short. You're gonna tell me that at the end of the video? That whole thing was confusing. I don't know how we went from a curtain bang to the entire thing chopped in layers. And she seems fine with it. I think that if we just worked with this style and did the whole MMA princess moment like I want her to and just flipped everything out, I think it would be such a vibe and a look. What if we did the tips of her hair black? Dude, just like an inch of the tip of her hair. That would look fire to accent those tears that she just cut. By now, I'm not totally sure I align with what's going on. But as long as you're happy, I am happy or I'll try to be.  What? Up next we have a video by Ms. Bliss. I have this thing plugged in. I have scissors. I'm sweating. I am scared. Well, that makes two of us, Ms. Bliss. My palms have been sweating since the beginning of this video when it all started, when we started cutting cake tears into our hair. But let's see if you can do it better. Hopefully we don't get the same result we just saw. I'm over the middle part. Don't want to go back to the side part. I'm going to put some deodorant on so I can feel fresh after this and not like a stinky mental patient. You look so nervous, which makes me so nervous because if you're nervous, then it's probably not going to come out good. We haven't really started to do anything yet. So let's go into this with confidence and be like, I can do this, I'm going to kick a a** instead of the opposite, you know, because then you're just setting yourself up for failure. And here is where I'll begin the voiceover because in my head, I was thinking exactly what you were thinking right now. Your hair is not meant for this. Wet your hair! See how it's like she's trying to do a middle part but it's like popping back to their side.  If you just wet it, you guys, it'll have weights and it'll be able to section it whichever way you want and it'll just stay there. We're making this hard for ourselves. Damn. Just don't do it. Just stop there. Just stop. Yeah, it's not working, is it? Okay, but convince yourself it is. Fine, fine, just do whatever. The part looks sickening. It's very even, very crisp, very beautiful. And then to the edge of her eyebrow. That's a lot of hair. Okay, those are going to be very little bangs from what I can see. Honestly, they look like they already are bangs. They're already up to here. I don't know how much shorter we're going to cut them. We need a little more fringe, a little thicker. All right, sometimes with finer, thinner hair, we need to add more hair to that fringe section to make it look nice and full and not like little tiny pieces of hair.  Not that that's what yours look like yet. For some reason, this hair just does not grow right there. This side inevitably will have more hair, which is really frustrating. All right, it's already short. I'm just going to cut the tip of my nose. Oh, hold on. Hold on. Okay, so we're doing bang bangs. She's doing a full front fringe bang. Okay, I thought we were doing curtain bangs. I feel like I was like a front fringe on her. I feel like that would suit her face and I'm glad she's working her way up. Like she's doing it pretty long. She's going like down to the bottom of her nose with the first cut. It's a great idea. Well, there she blows and we did end up wetting the hair. Yeah. I win. Put her down the middle. Now I'm going to take this side, pull it over. Okay. Okay. All right. Um, okay. So we are doing curtain bangs. Why did we cut them so short? And why did we cut them in the front first and not just the second step she's about to do? Why don't we do that first? Open the corner. I'm going to pull it over.  It's just a short curtain bang. But it's all about the styling. We'll see if she can pull it together. Now I'm going to blow dry it and see if that was short enough. She's going to blow dry and see if it was short enough. Uh, I think it was short enough. Now I'm going to do the second trick guys. It's with dry bangs. Going to pull all of them together. So then I'm going to pull it back, twist it once, and then two fingers down. Let me process. Let me take it in. These videos are really throwing me for a loop today. Um, what? I don't understand why would she decide to go shorter. And then she decided to put layers in her bangs. That's the part where she elevated the hair and then cut it. But her hair is already fine and thin. So layering it is just going to make it look like it's sparse. And that's the result we got.  Oh, but don't worry. We keep going.  It's cute for you. For me, not for me. I love how she just continues to try to style them. They just look like that and they are not going to change. Like that is all you're going to get. Mental breakdown initiated. Yeah, what did I just do? If you cut your bangs at home and you don't like them, don't continue cutting them. Just stop cutting them anyway and get them done by somebody. There's not much you can do here. You can get a clip on bang to just hold you over for a few months while this grows out. Um, you know, you're going to want to sell them very flat though. Glad to your foreheads that you don't get that bump at the top. You don't see your hairline. But otherwise, don't do it again. And I would love to see you with some face trimming layers just to blend everything in. Please. That was a major fail. I'm sorry. I don't mean to make you feel worse. Somebody just can't help but express what I'm feeling, you know? That's kind of my job these days. You made the video. I didn't. I didn't tell you to do it. Well, I probably did, but you did it. Up next, we have a video by Chloe Danielle. I have watched the breadmondo tutorial on how to cut curtain bangs. So that's what I'll be referencing today. Um, I see mail on the title and I see breadmondo in the title. I don't like those two things together, particularly. I'm going to say it wasn't my fault. Even before the video starts, it wasn't my fault. Mm-mm, it was all your fault. I blame you, Chloe. I've got scissors. I've got this comb with a pointy thing so that I can make proper sections. We got the tools and we got beautiful hair. Looks so silky and so soft and so long and luscious. But again, when we start with beautiful hair, all we can do is go down, you know? The first thing that I have to do is make myself a middle part. I don't know if this would work with a side part or like maybe you have to cut it in a middle part and then put your side part back. I am going to try and give myself a middle part. I cut everybody's bangs in the middle because either way, you part your hair, it's going to look good. And a lot of women and men and ladies and gents love to part their hair.  And if you cut your hair in the middle, it'll look good no matter what you do with it.  You know, like there's going to be like really odd and off and it's not going to look right. Oh, yuck. It feels so weird to move your part. Like it feels wrong. What? Your hair. I was going to get very aggressive with it. But I decided to just be nice today, just be nice, be kind to people. Am I struggling? Why am I struggling? If I can't even do a part, how am I going to cut my hair? I feel like I don't suit a middle part. Oh, yuck. Ah, yuck. I'm going to start saying yuck, yuck instead of yuck. Feel like that's on a slight diagonal. Why is just parting my hair like harder than I thought? Because that's not too much. According to the Mondo Man, we need to grab like a triangle section. That is way too thin. Oh, girl. Look at those baby hairs. I didn't realize how many baby hairs I had. That looks like a lot of hair. You have quite thick hair. So maybe be a little conservative if you have thicker hair when you're doing a curtain bang. Otherwise, that's going to be a huge section of hair just cut up. And it's going to look very disconnected from the rest of your hair. But it is possible to blend it nicely and make it look good. I just don't know if you're going to do it at home very well. I'm just going to start with this. We can always add more to it, I feel like. No, don't add more. No, no, no, no, no, no. I'm going to try and match that amount on the other side. There's so many baby hairs under there too. This is the look. This is the hard part, matching the hair on both sides. So now we're going to like brush the whole part together. Oh, great. If I thought I couldn't see before, I definitely can't see now. Wait, how the frick frick? In the video, he says, how am I going to talk to you guys? What did I say in the video? Tell me. Because somehow everybody's skewing my words, all right? Doing things that I never said to do. I'm sure I said to wet your hair and your hair is not wet. Usually, one would use one of those spray sprints bottles. I, however, don't happen to have one. So I'll be using, I'm just going to... Guys, get it wet however you want. It doesn't matter the technique on getting it wet. You just want it wet. That is not wet enough. That's wet enough, right? Okay, so in the video, he cuts it like just below the chin. Been kind of a tiny bit longer. Room for some error. Where are we going with this? Why did we cut it straight across? I thought we were doing curved bangs. We got a crisscross, you know? We can't just boop. And then I expect the bangs to be like, boop. Doesn't work like that. We got to get the angling in there. Over direction creates beautiful, wispy angles within the hair. It's like the cat brought in a small animal. Okay, it's looking crazy. Uh-huh. Okay, so the next thing he does in the video is he kind of pulls it all forward like this. He gets one piece. He pulls it to the side and then he has it kind of on an angle. And I was like, a stair effect. Did I do that right? That looks amazing. That looks so good. She definitely needs a cleanup. And then he says, you check your work by making sure that the two front pieces are even and then you take the two end pieces. I would say they're even. Okay, I'm just going to clean them up. You're doing a brilliant job so far. Maybe they're too long and that's why they're throwing me off. The cutting bangs he cut end up like sitting about here and he cuts a lot more off when he does the cruise crossing thing. I'm going to try this again. You can definitely over direct even farther and cut more hair off and that will make that angle really steep. The more you over direct, the steeper that angle gets and the shorter the shortest piece gets. I like you love the sound of cutting hair. Like, look, that is not what I thought was going to happen. I'm just going to try my own method. All right. Okay. I've had enough today. Why does it look like that? I'm going to like stop actually taking more centimeters off and I'm just going to try and feather it because I don't want to take any more hair off. I'm scared. Put the scissors down on the ground. Throw them away. Don't ever look at them again. Just stop because they were looking good and now we're pushing it. We just keep going. They're not the curtain effect. They just go like, listen, they could look good with just a blow drive and reevaluate. A curtain bang is never complete until you have a nice wispy blow out. I don't know how the salvage is. I have to take my hair out because I have to see what it looks like. Oh my God. So I watched this video again and I hate to say it, but I think they're not short enough. He starts off with it like like just below the nose and I start them on way down here. Oh, I really don't want to take more off though. I'm just genuinely terrified. No. If you don't want to take more off, I don't want you to either. No. It feels so short. Give me a homework. Look at me, Brad. Does this look like I'm wrong to you? I just started cutting again. I didn't do it. Okay. Wait, I feel like they're kind of like that time. We just keep cutting. Just put the scissors down. It was good like five cuts ago, but we just keep going and from what? I'm just going to cut it again because I don't think the angle is like half enough. Okay. It's got a nice gradient here, but there's like a short piece here and I'm not sure how it got where the long stuff is supposed to be. I think that's not too bad. Wait, is that one side longer than the other? Ooh, we're going to pull it up to the side. I am just going to go in with that feather technique now because I want it to look blendy. I feel like that one looks all right. I'm going to put down the scissors now. I think I salvaged them, but I still don't think they're like perfectly blended. I think any hairstylist would cringe watching this. I guess we'll just start by... That looks wet enough, right? Why do we have a Dyson blow dryer and no round brush? If we're going to do bangs, at least have a round brush on hand.  Put it on. Look at one of my videos. I don't know.  But we need a round brush.  And then it'll make that nice sweeping thing we all love. But blow drying one side and then the other side, you're not going to get that sweepy bit. It's going to be very complicated to do it that way. I promise. Don't do it like that. I don't know how I feel about this one, Chief. I am genuinely trying my best. I don't want to look like this. I don't think it looks much different to before. They're just not working out for me. I don't know what to tell you. Like I can't say I didn't try. I was hoping that these bangs would be like a redemption arc for my hair because it's so like lifeless and boring.  So in conclusion, I have regrets. They're not the bangs I asked for, but they're probably the bangs I deserve considering I didn't go to a hairdresser. The thing is like they're not bad. They just need help. For me, everybody with curtain bangs needs to have nice, wispy face framing that connects to the bangs. Or else it just looks like and with no layering, it's just like not for me. I think the length actually looks good. I think we need to get a better technique with the blow dry. Again, blow drying them forward, blow drying them back and letting them go and letting them just be wispy in the face. I think this is fixable. I know it is. And it's not that bad, but it's not great. But good job. I guess. Oh my God. Those were some of the scariest bang cutting videos I've ever seen. We're fine. If you want to check out my hair care or my hair color products, go to xmodohair.com. That's all for today, guys. Thank you so much for watching.  I'll see you next time. Bye.


So this is an update, actually, representation that I made last year. So last year, I had to introduce Janus for the first time. I don't know if everybody here is familiar with Janus or not. I mean, there probably won't be much time to explain what Janus is in general. So I referred to the presentation I made last year for my information. Just as a quick introduction, it's basically a WebRTC server that will seem to be pretty much involved in our way. It's all open source, and I get to know how to do that. There are demos and documentation in an active community out there for you to play with. And just to summarize it a bit, we have a WebRTC core that is part of the Janus story itself. And then we have different plugins to different things, specifically how you can transport the Janus API over different transport protocols, actually, and how you actually want to end on the media. So whether you want to use an SFQ and a loop bridge, or all of them together within the same applications by doing some combination on the right side. So that's basically what Janus is in a nutshell. And here is a quick link to this life of last year. We're interested in knowing more. This presentation is more about how you can actually monitor and troubleshoot what is happening within a Janus instance in particular, which is far from general. And as the first presentation showed today, it's hard sometimes to find out what's wrong in a WebRTC core for some reason. And for a while, we only had a single way to do that. Specifically, our item was because the admin API, which is basically a request-response kind of protocol, where you basically query Janus with respect to a specific kind of a specific peer connection for information. And we will return a bit of stuff out there, the results will drop off the right track with a bit more in detail how you can use this information in order to troubleshoot a peer connection. And it typically works as you can imagine as a polling protocol. You know, Mike, do you want me to explain it now? OK, sorry. Is it OK? I mean, the real stuff is just going to start now. So you didn't miss anything. And then it really works just as polling really does. So at any time during the peer connection, you can ask Janus for information. It will return a snapshot of whatever is happening in there, so how many packets were sent, what's the current state of eyes, DTLS, all those kind of things. And if you are familiar enough with all of those things, you can have a look at those snapshots, maybe one or more snapshots in time to figure out what's going wrong, which, of course, is far from the ideal solution. I mean, this is just a quick view of how this information is returned. So it's split in different parts so that you can actually study different pieces of what's happening. What would be more interesting is that kind of an asynchronous approach. So something where you actually Janus notifies you in real time about whatever is happening either within the core or within different plugins, which is actually what we started working on some time ago. And we call them event handlers. So basically all the core plugins can generate events and there is an internal mechanism within Janus that then broadcasts these events to different new plugins within Janus that can then handle these events in different ways. And so as we'll see later, you can use these plugins for different things. So one plugin may save to a database or other plugins you may use for different things and so on. The idea is that it's not the event handlers that provide the trouble shooting, they just provide you with the means to actually either integrate with existing platforms or do the stuff yourself in order to do something more creative. And I'll also talk a bit about the sample event handler that we implemented in the meanwhile. And so the idea is that internally it pretty much works this way. So Janus generates an event, there's an event manager within Janus that relays these events to all the plugins that are registered within Janus to receive these events and then each event can do whatever it needs to do with these events. So one may just format the event to JSON and send it via HTTP to something else for processing or it may save to database or it may populate a CDR of some sort of whatever you need it to do. I mean, it really is up to what you implement in your own plugin there. And there are different types of events that you can generate and subscribe to really much, pretty much depending on what you want to troubleshoot. So if it's just session related stuff or if it's anything related to the WebRTC setup or statistics in real time and things like this, we'll see a brief example of this in a minute. And the idea is of course that each of those events which of course presents you a partial view of what is happening can then be used together with other events in order to correlate and have a better picture of whatever is happening also, let's say within the context of a conference rather than a single peer connection just to make a single example. And to make this easier also to integrate with other platforms we started writing a single event handler for the moment, it's the only event handle that is currently available. Hopefully this will change in the future. And this event handle does nothing more than getting an event that Janus originates, format it to JSON and then shoot it out via HTTP to an external backend so that in this external backend you can do some fancy stuff with it. And so it does, it is a bit much smarter than this, we can aggregate events so that you do not shoot a single message per event and something like this, some basic or transmission mechanism or authentication and so on, it's nothing more than that in principle. It's really just a way to take this event, shoot it somewhere else so that you can play with them in a nice way which I will also try to describe a bit in some examples and blog posts. And if we refer to the previous image where I mentioned that admin application that was calling for information in this case, the admin application is notified in real time whatever happens. So anytime a session is created the admin is aware of that. Anytime something happens, whatever you see wise it is also being notified. It is notified about any offer that happens, anytime the ice state changes and things like this so that you are immediately aware of whatever is happening within the platform which would make it easier to be monitoring and troubleshooting things on top of that. And the nice thing about this first interaction is something that is actually related to the presentation you'll see later on. In fact, Lorenzo is going to talk a bit about how they use these events to within the Homer framework in order to monitor a Janus framework which was really exciting and interesting for me. And I won't have too much on these in this slide but I just wanted to say that I'm really excited about this for several reasons. Most of all because Janus and Homer are both figures from mythology which is something that I really like about. But most importantly, I'm from Miteco or Miteco how people call it. And we call it Miteco B which means awesome in English. We called it like that also because it's what Homer Simpson says in the Italian version of the Simpsons anytime something exciting happens. So it's really like a match made in heaven for us. And you can, there's a YouTube video over there. Let's use it. So just to show this a bit more in practice I didn't really make some demos up and running but I did make some dumps in order to show you how this all works, at least from an events perspective. And I studied a couple of different demos within Janus. So we have different demos to showcase different plugins.  So whatever I send to Janus is being sent back to me. So we create a single peer connection that we can monitor. And so I captured some dumps of the event and the mechanism in order to see what Janus is actually telling me about whatever happens. And it is also summarized in a blog post that I wrote some time ago that shows how I actually wrote a simple Node.js application that gets all the events from the sample and the plugin as a JSON object and then saves these events to a database formatted somehow so that I can then make some processing over the database or the tables to see if I can get some information about what happened during a specific session. And so if we look at the events that are formatted as JSON as I said, we get a lot of events about anything that happens. In this case, we see a session as being created using the HTTP transport in particular. We see a handle has been attached to the eco test plugin and there is also this piece of information that is actually very important for correlation and I'll show this in the next demo that I'll show after. After we created a handle that is basically an abstraction of a connection between a user and the plugin, we can create a peer connection over it which is exactly what happens in this other event. So we get an event saying that the remote peer starting sending us an SDP and offer to basically create a peer connection. This gets passed to the eco test plugin and the eco test plugin sends back an answer to establish the communication which is exemplified in this other event that we get here. So the owner is local because it's basically the SDP that John has generated for itself. In this case, it's an answer. So as soon as the offer and answer has been exchanged the actual peer connection setup starts which means that we start getting events about the ice state machine. So whatever starts happening within ice. In this case, for instance, we might get events related to ice that is in the connecting phase. So the ice connectivity checks start taking place. After this, eventually the connection succeeds from a nice perspective and we are also notified about the selected pair that has been chosen for that specific peer connection which may be important for several different reasons. Once ice has been done, we come up to the DTLS information. So after ice is done, we still need to do a DTLS send shake to exchange the SRTP keys. So even in this case, we see that DTLS is still trying and that gets to a connected phase. If this doesn't happen, we know that there is something wrong, for instance, in the DTLS send shake and so gives us some ideas about why something is wrong in the connection setup and so on. Once this is being done, media starts being exchanged and so we get the events on that as well. So first of all, we are told that the peer connection is up from the John's perspective. We get information about audio and video that are being received by John's which is also important because it means that John's is getting now media from the user and so can start using it. We also get live statistics about H-second or so for each peer connection so that you can, for instance, see live statistics that tell you about the packets being exchanged and things like this and so may be useful for several different reasons and these happen for both audio and video. So all kind of information that as you can imagine are really important for understanding whether or not the peer connection is actually doing its job or not. More importantly, this is also important for the next demo. We also get event from plugins themselves and considering that plugins may be written by third-party implementers by whoever, they are very much plugin-specific as you can imagine. So we just provide a framework for allowing plugins to notify you about anything that happens within a plugin. In this case, the Echo Test user was just adjusting the bitrate settings to force a different bitrate for the communication so nothing really important. So if we want to look instead at a more complex application like a media conferencing application maybe and here I am talking with myself because I don't have any friends. Just kidding, of course. This is also explained in another blog post where I tried to explain a bit how things work. In this case, we were more interested in knowing whether or not we can figure out the relationship between peer connections belonging to different users. First of all, if we are able to associate peer connections belonging to the same users to a specific user and if we are able to reconstruct the topology of the video room. So who is subscribed to who? Who is publishing and things like this? Which is basically what the next dump tried to provide. So I will not go through the same session or webRTC event. We assume that everything is fine in that sense. We focus instead of the plugins generated by the video room plugin which give us some context about what the video room does with the subscriptions in principle. So in this case, we see that this session handle combination has a participant joined. In this case, it's called Chitro. Chitro is one of the users I always use in my demo. He has a specific ID in the room, one, two, three, four. So I know that this handle is being used to publish the contribution by Chitro in the room. At the same time, people instead is using those session and handle combination to publish his own contribution in the room. And then we see different events related to subscriptions. Instead, we see another handle being used to subscribe. In this case, this is subscribed to feed 83, something that is basically the ID, the Chitro head. And then we see another subscription instead for the feed 52 something. So we know that somebody has subscribed to people's feed instead. So intuitively, we know that they are both publishing and they're subscribed to each other, but it is not to be given for granted because you can actually use this plugin for things that are much more complex than that. And so we want to be sure of this. What we can do is basically looking at the events that were associated to the handle creation. And we see that these two different handles over here have the same opaque identifier. And so have these other two, which means that they both were originated by the same user basically. So we know that those handles were created by the same user. And looking at the session and handle identifier and things like these, we can basically reconstruct the topology which is that people is using a specific handle to publish. He's subscribed to a specific ID via different handle and so on. We know which handle belongs to whom. We can figure out that they are basically subscribed to each other, which is what we wanted to figure out. And this is basically how you can correlate information related to different plugins with each other, which is kind of cool. And just to conclude basically, because I managed somehow to talk about 95 slides in 15 minutes. So I deserve a prize for this. This is really something really new that we've been experimenting with. And the idea is that in the future, more and more plugins will come to basically handle these events in more creative ways. In the next presentation, Lorenzo will show us how they actually handle these to integrate these within the Homer framework. And it would be really nice to have actually a native plugin that acts as an event handler within Janus itself rather than relaying on a plugin that shoots events, an event to an OJS application, which then introduces the event in Janus, which could be quite cool. We will also have a student working on this kind of interaction in the future, which is kind of nice. But more importantly, I mean, help us play with these if you're interested in these. Just start using it. Let us know if there is anything more that is needed on this, or if you think it's actually just as nice as it is. And this is all I've got. So I'm open to questions if there is any time for that. We have like one minute left. Okay, that's good. Thank you very much. Thank you.