So, we're down here in the basement in DrupalCon Latin America and we're going to talk about capturing the Drupal8 flag.  And yes, at 3 a.m. when I'm writing tests, I really do sound like that and make that expression. My name is Tess Flynn. I am SocketWench on Twitter on various other social networks. That's Wench, not Wrench. I am a developer with Blink Reaction. I'm the module co-maintainer for Flag, for Flag Friend, and for example, Module. So the first question is, why port flag, other than we really need a Drupal8 module? So it was back in 2013, and I was actually sitting in the auditorium watching WebChick at DrupalCon Portland talk about how we really need modules to be ported now to Drupal8. Because the idea was that they had plenty of time working on core itself, but they didn't have a lot of time actually using real modules and testing all of their ideas to make sure that they actually worked. So you might wonder, well, why not just contribute to Drupal8 directly instead of porting flag module? Well, I was doing that actually. I was doing that for about a year at this point. And I was going pretty well, but then I kind of got stuck. Working on issues, working on core every night, but then I started realizing I was stuck in kind of a pattern. I was in what I call, I had the reverse Sisyphus problem. Now, Sisyphus is a myth where we had a man condemned by the gods to roll a boulder up a hill for all eternity, and by the time he got to the very top of the hill, it rolled all the way back down again, and he had to start all over again. The problem is, with Drupal8, I had the opposite problem. The boulder was already running down the hill, and all I had to do was run after it as much as I could, try to catch up to it every night and hope that maybe, just maybe, I will impart some small sense of momentum into Drupal8 before it rolls away from me again. And this is the problem that I was facing. Every hour or every night, for about three hours I had available, I had to spend a lot of time studying Drupal8 and by the time I got caught up to actually contribute to an issue, I couldn't find anything or I was too tired to go to bed. So what was I going to do? I had this problem and I couldn't figure out what was going on. I was stuck in the valley of dirt. When you're a beginner and you're working and contributing to Drupal4, you're on beginner's hill. And there's plenty of stuff to do. Issue summaries, you can run tests, you can re-roll patches, but everyone really wants to be in Dev City, where there's real issues and you can contribute real code to the project. But the problem is, there's a big valley in between those two points. What do you work on there? API docs, code style? You tend to just sit there looking up at Dev City wanting to be there, but rarely finding the opportunity to actually contribute. So I was sitting trying to figure this out and as all good ideas come to you, this one came to me with a shower, and there's got to be a better way. And it occurred to me that I should just port flag module. I was a Comey beginner or flag module at the time, but I didn't have a lot of knowledge in how Drupal8 and Drupal7 work, the module was a little bit unfamiliar to me. I tried work contributing to it, but I didn't know it that well. And I was so focused on contributing back to Drupal8 that I never got back to it. So I was having a problem. What do I do? Importing flag module seems like the most bizarre, ridiculous idea that I could come up with that would satisfy both requirements. So before I go any further, who in this room doesn't know what flag module is? Anyone? Raise your hand. No one? Okay, you.  So here we have a node display, and it looks like any other typical node display in Drupal, except for these two little links at the bottom. These two little links are flag links, and we've attached them to the node. So if we generalize this a little bit, we imagine our node, our happy little node sitting out on Drupal, and we have a user come by, and they go, ooh, shiny, and they stick a flag in. The module that makes the point sound has yet to be developed. Other users come along. They also add flags to it. Now from this, we can actually define what flag module is. It enables administrators to define boolean fields that can be attached to site content which each user, they set or unset. It kind of works like this. There's three principal objects involved. An administrator defines a flag and attaches it to any kind of entity on the site. This entity is called a flagable, a term that makes my eighth grade English teacher cry. Once we've defined the flag, users can come along and actually use that flag on that piece of content. In so doing, they create a flagging. Users can also unflag an entity at any time if they flagged it and have the appropriate permission to unflag it. Administrators, obviously, can also delete the flag at any time and therefore remove all of the flaggings that apply to that flag. So let's break this down. Flags are an administrator-defined boolean field. They've been stored as an entity since 2.x. They may be attached to only one entity type but multiple bundles of the same entity type. So you can define a node flag and have that flag apply to articles, to stories, to pages, or any one of those or any combination of those. You can also define a user flag and have it work on users or a common flag and define it on common. In fact, any entity type. You can create flags under admin structure. Flags and flags may also be fielded since version 3.x. Flaggings are an entity that is created to store when a user sets a flag. It basically stores four pieces of information. Which flag was set? What entity the flag was set? When was the flag set? And who set the flag? Flagables are any piece of content on your site. Any entity that has a flag defined for it and for which flaggings may be created. All right, so we know what flag does. We're going to port it. So what's the first thing we're going to do? We're going to sit down. We're going to open our IDE. We're going to start writing code, right? No. The very first thing that you should do when you're looking at porting a module to Drupal 8 is to first do a code review. What you want to do is ask your module, how does it really work? When it comes to flag module, we had Drupal on the bottom and we had several implemented hooks and alters like any other module, a function-based API like itself also defined a number of flag hooks and also implemented those hooks for its own purposes. Behind that, we had a number of straight backend functions but the majority of the code was in handler classes. We had a base handler class called flag flag and then we had specific cases for each entity type. One for all entities, one for nodes, users, comments, and so on. We also had a special case flag, flag broken, that was used when an entity type no longer existed on the site. Mostly this is a pretty typical Drupal 7 module. We have a large surface area of straight functions. Entity support was refactored in later in its life. Object-oriented programming was used but what's a bit like the blob? Blob is a 1958 movie in which an alien space creature devours an entire town and that's what a lot of PHP 4 classes look like today. They have weird factory methods. We have all methods were public, all class variables were public. Basically, we had a big blob of functions. So now that we've done a code review, we need to pick where we need to start a reporting process. The first thing you can do to really help yourself is to question everything. Nothing is secret. Sit down and act. Does it really have to work this way? When we defined this module before, we had to assume certain assumptions. Do those really apply anymore? Do people really use it that way? Can we do this better? Can we do this simpler? Then sets on the expectations. If you're the kind of person who just wants to go sit down and get work done, you might want to wait. While Drupal 8 has largely solidified in the last year, of tooling and documentation, that's yet to be written. Or yet to be very well documented.  If, on the other hand, you're here to learn, go for it. Don't wait today. Don't wait. Just start right now, this minute, this second.  I'm waiting. If you're like most people, you're probably in the middle. You kind of want to learn, and in that case, you kind of want to keep it experimental. You want to start working on it, but don't really commit to it. Don't make a huge fuss that you're doing it. Just start working on it and see where it goes. You might be tempted to actually start by porting your test, so you can use test-driven development. Simple test is available in Drupal 8, but it's a bit of a double-edged sword. While it's easy to port your tests to Drupal 8, it might also limit your thinking. Then you're no longer questioning all the things. The best piece of advice is to start with the most central piece within your module and work your way out. Now, with Flag Module, it was the flag entity. That was the most central piece on which everything depended, so that's where I started my work. First, we wanted to design the flag class. Now, we could start with just a plain base class, but that's not very good object-oriented design. What we started with is we used an interface. An interface is a new concept in the PHP world, but it's been an object-oriented language for the better part of a decade. It's rather common. Also, once we find the flag interface, we also want to derive our class from a Drupal-provided class called config entity base. Now, I'll get back to that in a sec. We have flag interface. Flag interface is kind of like a contract. It sketches out what the object can do and what we can do with it. It is basically like a class, but it only has method names. It doesn't have any function bodies. It doesn't have any variables. It has no state assigned or attached to it. Defining an interface is best practice object-oriented programming, because it's a very light layer. And then we can define classes underneath that. It allows people to later on completely replace, in this case, the flag class, to do whatever you want afterwards. The flag entity is also a configuration entity. Now, in Drupal 7, we have entities. An entity was an entity was an entity was an entity. But in Drupal 8, we have configuration entities and we have content entities. Configuration entities are best for administrator-defined structures. While they live in the database, they may be exported to YAML. And it's basically structure, not data. Any time that you create, say, a node type, that's a configuration entity. Instead of doing a lot of work and implementing a whole bunch of hooks in order to define our entity type, we simply derive the flag class from ConfigEntityBase. ConfigEntityBase does all the foundation work that we need for configuration entities. It does all the Drupal stuff, so we configure it on our stuff. Now that we have our configuration entity, we need to add fields to it. This is done by defining a config entity schema. It defines what the config entity fields are, the data type of each field, and it basically tells Drupal what to save for this entity. This is what the flag schema looks like. It lives in the module root directory slash config slash schema, and it's a file called flag dot schema dot YAML. And it's a fairly straightforward YAML file. We actually have the kind of entity it is, so we can tell Drupal what to do with it, and then a number of fields. It's a very simple file to define. Once we have our schema defined, we need to actually take those schema variables and create class variables within our entity object. And what we want to do is we want to match every field we define in our schema to a class variable in our entity class. The reason for this is that it provides you code completion in your integrated development environment, and it's the easiest place to document your schema. Don't document it in the YAML file. Document it instead in the entity object. This gets to another point. Please, please use an IDE and a debugger. I'll get on with these, but I think the mic would fall off in my outfit. Yes, really, it's time. Drupal set 3,000 files, and some of those were very sizable and well-organized. Drupal 8 has at least four times as many and probably several more by this time. But the strategy is also different. Instead of large, single files that contain a huge suite of functions, it's many small files. Once we've defined our class variables, we want to define getters and setters. The best thing to do is to define a getter and setter for every variable in your schema. Your interface will not be complete unless if you do this first. Also, never mark schema class variables as private, because Drupal won't be able to read them. Drupal actually uses the config entity base class to actually read class variables. So any protected class variables that aren't visible outside of the class are still visible to the config entity. So we have our configuration entity, and now we need to plug it into Drupal. So what do we do? Well... So we have our flag object, and we have Drupal 8. So what do we do? We hand this on, we build this class, we hand it off to Drupal, and then Drupal says, that's just a class. What the heck am I supposed to do with that? And the flag is just sitting there going, I'm so lonely. What we need is we need an additional piece of information. We need to tell Drupal what this class does. It'd be really handy if we had, like, I know, a config entity assembly manual for flag. What this assembly manual is, is actually something we call, something we call an annotation. An annotation is an assembly manual that's used by Drupal to know what the class does. So Drupal can go off and build stuff. It's metadata that's included in the class doc block. It tells Drupal a few very important pieces of information. What the following class is, why it's important, and where to find other important pieces of functionality related to this object. This is a portion of flag's annotation. So we have a number of different things here. It's basically a hierarchical structure of key value pairs. We can actually see, at the very top, something called config entity type. So let's start there. Basically this annotation tells Drupal that the following class is a configuration entity. So any time that we perform a cache clear, it's going to appear within Drupal. Next we have a handler sequence. The handler sequence tells Drupal where to find other related pieces of functionality, such as the list all entities page, and also forms, like the add, edit, and delete form. Speaking of add, edit, and delete, it's time to build that administration interface. So this is what the flag administration interface looks like. It's very straightforward. We have a table of one flag per row. We have a button for add new flag, and we have some text at the bottom. How do we provide this page to Drupal? Well, what we do is we create a class called flag list controller. It derives from a Drupal provided class called config entity list builder, and basically it provides the admin structure flag page. It only has two important methods. The first method will actually tell you what the columns are in the build header method, and the other one is actually for to build each individual row. You don't even have to get the entity. Drupal does that for you. It grabs that and puts it in a parameter to the method. Next, we have the add and edit pages. The add and edit pages and flag are very similar. So similar that we might as well take advantage of that and reuse a lot of code. So what we do is we create the following class structure. So we start with a Drupal provided class called entity form, and for the add and edit form, we create another base class called flag form base. There's also the flag delete form, which tries from another Drupal provided class called entity confirm form base. And I'll get back to that. Flag form base does all the real form stuff. It builds the form. It handles this out of the validation. It handles the submit. It does all the real work. So what does flag add and flag edit form actually do? It modifies the behavior, and it tells you where the default values come from, such as with the add page, it just grabs them from static values, or the edit page, it loads them from the entity. And it also modifies the name of the submit button. This is actually a very common pattern within Drupal modules, to define a base class and then two very similar classes that will do the add and edit form. The delete form is a completely different animal. It derives from confirm form base, and it basically provides a simple yes-no question. Can and do you want to do this or not? The class that it uses is entity confirm form base, and it really only has a few different methods it has. What the question is, what the title of the page should be, what to do if someone clicks cancel, and what to do if someone clicks go ahead. So we have our forms, we have our entities, and we need to make it routable. So, user comes by with their web browser and goes to Drupal 8 and say, I want some content. Drupal 8 now, Drupal 8 needs to match whatever that path is to some other piece of code within Drupal. Now, in previous versions, we used hookmenu, but we don't have hookmenu anymore, so what do we do? Well, we actually define a new file called flag.routing.yaml. And this basically provides a list of route names combined with a list of path names. This is an important point. Drupal 8 doesn't think in paths. It thinks in route names. So, when we have route names, how do we add stuff to existing paths? Well, you'd think, well, we were going to add that to the routing page, right? I mean, that, oh, no, that doesn't work. Because flag.routing.yaml only adds new routes. It doesn't allow you to modify existing routes. For that, we need another file, flag.links.menu.yaml. This will allow us to add to existing routes. And it basically contains the destination route name followed by the parent route name. In this case, structure.system.admin structure is for the admin structure page. So now we have that. We need to connect our ad form to our page. And we do that through a local action. So how do we do that? Well, we have another file. flag.links.action.yaml. This allows us to attach click actions to existing routes. It also contains two really important pieces of information. The route name to attach and where it goes to. Okay. So we have all of our big entity stuff ready to go, and now we can actually start making flaggings. So we need to start porting the flagging entity. So how do we do that? Well, we pretty much the same way. We know it's a content entity because it's user created. So we create a flagging interface, just like we created a flag interface, and we create a content entity. We derive our flagging class from content entity base, another Drupal provided class. This is used for user defined objects. Fields are defined not by creating a schema, but by actually overloading a method called base field definitions. Interestingly enough, we don't need to use hook schema to actually define database tables. Drupal will use the information in the field definitions to actually create the tables for us, so we don't have to do all that extra work. The flagging contains a few pieces of information that maps it to other objects. A flag ID for the parent flag, the entity type an ID for the flaggable, and the ID of the user that created the flagging. Beyond that, flaggings are kind of weird because they're not really created with forms. So what do we do? What happens? Well, a user comes by and uses the web browser, and they go and view a node. And what happens is that we use flag entity view in order to attach that link to the node. The user clicks the flag link, and then it goes to Drupal in some route. Well, what happens then? Because what we really want to do is we want to get to entity save to create the flagging entity. So we need to figure out what we're going to do in the middle. Before, we have a great method called flag, but that's not really a very Drupal-8 way of doing things, so we don't want to do that. What we want to do instead is we create a flag service. The flag service is basically a plain old PHP object, but it's special in that it's registered container-wide through the file flag.services.yaml. So all other modules within Drupal know how to locate flagging configuration information and flagging methods. To flag your unflagged entity, we simply call flag service with the flag service and then flag... You can also inject the flag service into your own services for your own use. So we have the ability to flag stuff now, but now we need to make it expandable because there's still one more problem left. So we have our flag entity and we have several different target flagable entities, such as Node User and other entities. So if we're looking at this, you might say, well, okay, flag one, and, well, why don't we just create a new flag node subclass and a flag user subclass? I mean, that makes sense, right? Then we can handle all those special cases and configuration stuff. But then we get to entities, and then we get a problem because there are a lot of entities in Drupal 8. Drupal 7 had a lot of entities. Drupal 8 is even bigger. So this also looks really familiar, doesn't it? Oh, I need to get to our classes again. We don't want to create handler classes.  So we want to do something instead. The problem with handler classes is they're hard to expand because you have to derive from base class and they're not discoverable in any way. So if you're not the flag module, you can do nothing. So there's got to be a better one. So we have our flag entity and we have our flagables and we need some way to relate them. What we do instead is we use a plugin. In this case, a flag type plugin. The flag type plugin relates the flag to the flagable entity. Flag type plugins are also discoverable via a custom flag type annotation. It's not a subclass. It's added dynamically into the flag class. The wonderful thing about this is that any other module that needs to define their own flag type because they have their own custom entity has to create a flag type annotation and then they derive from flag type base and they can do whatever they want and flag will just pick it up automatically. So we have a very similar structure for the handler classes to the plugins. We have plugin base, which is a Drupal provided class which does all the plugin stuff. We have flag type base. We have entity flag type and then several specific flag types. What do we do with all those other entities? What we use is we use plugin derivatives. With plugin derivatives what we can do is we use data to create the appearance of multiple different plugin types, one for each entity, and we do so dynamically. So everybody gets their own plugin. So now we have how to handle the flag to the flagable, but we still have one more problem. We still have some route after we click the flag link. Where does that come from? Who does that? What we do is we have another plugin. We have a link type plugin. The link type plugin provides the route that will connect the clicked flag link to the flag service. Again, this is also discoverable. There's a link type annotation so that any other module can define their own link type. You can create all kinds of crazy link types. Because it's also a plugin, it's also dynamically selectable or add a flag. All right, we have most of our functionality. Now we need to open up even further. We need to create an API. So what we had in flag seven was hooks for everything. We did everything with hooks. If there wasn't a hook, we would make a hook for it. We did it to define flags, to validate racks, to interact with events, to provide flag types, to provide link types. There was a whole bunch of stuff. Well, in Triple 8 hooks aren't everything. It's a bigger world now. And it looks a lot like this. We use the configuration management in order to define flags. We use plugins for flag types and link types. We use events to react to events. And we use state and grant access. We actually still use hooks in Triple 8. What about this event thing? How does that work? We have the flag service and we have another service within Triple called the event dispatcher. People subscribe to the event dispatcher to receive particular kinds of events. I want to listen to whenever somebody flags a node or unflags a node, or something like that. Whenever that happens, flag service is going to dispatch a flag event class to the event dispatcher and then have that populated to all the different subscribers automatically. All flag service has to do is just submit that one event class once. There's only a few flag events so far but there might be more in the future. We still use hooks. How we do that is instead of having the straight invoke all method, what we do is we actually inject the modular handler interface into the flag service and from there we can call any other hooks that we need to. So there's flag. So there's a few things that I learned during this. How do we run our projects more effectively with Triple 8? Well, the first thing I can tell you is when you're starting your Drupal 8 project you're not sure if you're going to start and with the same code that you start with. You might end up in a back alley. You might go down an interesting idea and find it's not really viable. So you really don't want to just put it on your module page. You could. You could actually put it on your Drupal.org project. But is your module really ready? Do you really want to do that? I mean sure, you could work in private and develop all this stuff and then push it to Drupal. But then you're not doing it in public anymore. You're not generating that interest. Well then, so what do you do? We could put it in Sandbox. And that's easy, but few people see Drupal Sandboxes. It's hard to get visibility there. Although the community processes are exactly the same. So then you might wonder, okay, maybe I just need a clean break. Let's put it on a completely different public repo like GitHub or Bitbucket or something like that. What we did with flag is we decided to completely new break because I had no idea if I was going to get anywhere with this. I had no idea if it would work out. And I was getting some pushback from some of the other contributors. So it was probably a good idea to just move it off of the Drupal.org project page entirely. Next, when you're working on this you're going to have problems. You're going to have questions that you can't answer. You're going to update core at 7pm that night and then spend the next three hours wondering why nothing works again. And beg that some core developer will show up on IRC that you could beg for an answer for. And they're there to help, but you've got to be patient. And when they do help you, you need to really show your appreciation for it. I can't tell you how many beers that I owe people right now. There are plenty of places to find help. You can find it on Drupal Contribute. You can go to the Drupal.org list changes page. There's also the issue queue for Drupal itself. The list changes page is your one-stop shop or anything that's changed in Drupal core. After that, it contributes really useful for tracking down and debugging specific issues. Next, you might find yourself needing money in order to do stuff. You might need travel money to go get your team together so you can sit down and just hack. Maybe you need to attend a conference. Maybe you need to take them off from work just so that you can code. There's a lot of different reasons why you might need funding in order to support your module development efforts. So what you can do and what I did is I actually ran a crowdfund on Drupal Fund. My goal was to actually get me to Drupal Con Austin last year so that I could sit down with some core developers and really push the module forward. And in a few days, we went from no-view support to complete-view support. It was really, really impressive. Later on in your project, you might start wondering, especially if you've moved your project off of Drupal.org or into a sandbox, when should I move back to my project page? I'll make this official. You have a lot of different things that you need to balance. You'd be worried that being on your module out there right on your project page might result in a lot of people posting issues while you're still developing your module. Yes, I know that feature doesn't work yet because I haven't written it yet.  And now you reference pull requests that exist on Drupal.org, but you do that. On the other hand, if you put it in a project branch, you can leverage your community, but it also comes with a lot of visibility. And if you end up in a back alley, that can be really discouraging to a lot of people. You might be tempted looking at this to do this, to slide the fulcrum all the way over so that you keep it in the sandbox as long as possible until you're certain that it's ready to go. Don't do this. This will cause you problems. The problem is that the longer you keep it in the sandbox, the more the lack of visibility and the lack of leveraging your community will hinder your module development. What you want to do is this instead. You want to wait until your module is just done enough to do the major stuff it needs to do and then move it back to your project page. You need to define a minimum point of module viability. And that's when you should move your module and that will eliminate the issue cue noise and the get-in-a-log pollution a lot faster. The more you keep it off, the more that will accumulate. In reality, Flag actually only had about 120 issue tickets and most of them were reminders to myself. So these issues are way overblown. Also, things are a lot easier now than they were last year and even in 2013. We have an example module for Drupal 8 and it does a lot of stuff. We have a config entity example. We have a content entity example. We have a plugin example that's in progress and that will have you very far in doing stuff. There's also wonderful things like Drupal console which can actually provide you a lot of that stub code necessary to get your module off the ground a lot faster. Looking back at all of this, if you're looking at working on a Drupal 8 module, you want to learn port now. Right now, don't wait. Go.  Come on.  You might want to wait, but don't wait too long. Drupal 8 has actually been fairly stable module-wise for the last year. There's only been a few times that I've really needed to massively modify my module in order to make it work again because this base class changed, this interface changed, and then it took longer for me to track it down and figure out what broke than to actually fix it. So in reality, don't wait too long. Do a code review. Make sure that you know how your module really works. You have to get up at 3 in the morning after a long vacation to go and look at it with fresh new eyes. Do whatever you have to do. Also question everything. Nothing is sacred. Really look at your module and see if there's any way that you can make it work better. Please use an IDE and a debugger. I can't stress this enough. Finding your code completion is a wonderful thing, and you will thank yourself after you get over the initial frustration of not using one. There are lots of them available. Many of them are open source or free. There's also plenty of demo versions that you need help patiently ask for it and show appreciation when you get it. That will help people to be more encouraged to help you in the future. Do it in public. Don't sit in your basement and work like we are right now, and work on your module in the dark and then push it up to Drupal.org. Start working on it. Let people know, but also put a warning label on it. If money is your problem, consider crowdfunding. Move out of your sandbox as fast as possible. Don't get stuck in the sandbox. As soon as you hit that point of minimum module viability, move out. Things are a lot easier now because there's example module, there's Drupal code, there's a lot of things you can do to make your module development effort a lot easier. I'd like to take a moment to give special thanks to a lot of people that made flag the role of David Reed, Whizwon Solutions, which helped me a lot with this presentation. Lauren Shea, which is why I'm here today, and Blink Reaction, which I now work for. Thanks, everyone. You can find me on D.O. and Twitter on SocketWench, and you can find this presentation on...


Hey guys, it's up. It's Kinsey and welcome back to my channel for today's video. I am doing my 2018 favorites video. I have been so excited to film this. I've just been thinking about my products I really picked out the best of the best my favorite stuff Except I've used all year if you guys are into products like I am and you guys have anything you want me to Try out. Please let me know. I am back obsessed with like trying out a bunch of products right now So like I said leave them in the comments down below or tell me what your favorite product of 2018 was Also, if you guys are interested in a kind of like 2018 reflection like what I learned I did an entire episode on that on my podcast Which if you guys didn't know I have a podcast it is the I love you so much podcast with Kandila's with It's my favorite thing in the world. I'll have it linked down below It's my first solo episode which was exciting But yeah, just talk a lot more about 2018 and all that stuff if you guys are new here be sure to subscribe Instagram Twitter all that stuff. Okay. Let's get started. I have it all on my phone For my clothes this will come as no surprise with the I am Gia jackets guys I have them in black tan and red actually the red one is technically from garage But it's like the I am Gia Pixico Also bought five of them to give to people for Christmas. They are the best jackets ever. They're so cozy. They're cute They're fun. I love them. I'll have everything again every single thing that I mentioned in this video I will have linked down below. I know the Princess Polly was having like a crazy sale on the red one It was like $40. I don't know if it's still there. I'll have it linked down below if it is but They're the best jackets ever. It's worth it to spend the money on the I am Gia one I think they're like 110 or something I know there's a lot of knockoffs with the I am Gia ones are the cutest the most comfortable the best quality It's the best thing ever. These are the best jackets. The next thing is something that I just started wearing in the past month I bought it probably in like July because I credit on an app and then I didn't really have anywhere to wear it to until Probably like when I was Texas, but it is this revolve bomber and you guys have been asking me so many questions about it I can't find it online anywhere. They have a similar one From the same line or the same brand, but it's not like sparkly. They're just neutral I'll have it linked down below, but this bomber is so freaking cute. And it's just so fun I'm really into like fun pieces this year I say as I'm wearing all basics, but because I wear very like basic clothing. I really like fun things You got super into fun bags. You guys will see that this will come as no surprise I probably have this in last year's video as well my leopard coat I got a new one and this is also from forever 21 guys my last leopard coat forever 21 This one forever 21. It's so weird I'm like, okay I'll buy one from revolve or somewhere nice because I wear it all the time and then I just see it up forever 21 And I like the one there better. It's so weird I don't even shop there, but this is just so fun everything that I say like it's just so fun That's so annoying, but I shock it guys I swear it is the best thing ever and it's also almost like a neutral like if you have it's just the perfect thing to Wear at all times like you could wear it anywhere. I would wear it to like crover at like 9 a.m You know, I don't think there are croakers in my life, but you get what I'm saying Hoops guys as you guys can see I'm wearing these. These are my favorite that I've bought all year They're from H&M and they were like $6, but hoops came back in and I had to get my ears Re-pierced for them guys and I Love them. I'd like back on my ear and grind back on my accessory grind just made a few purchases from the M Driller, so that'll be coming in soon. I'll be like vlogging my unboxing and stuff. I'm very excited for that but Hoops are just the best thing ever I literally have not left the house without hoops on and I Couldn't even tell you like I just don't do it. It just doesn't happen I'll link down below a few of my favorite I also had like these really small gold ones from urban that I broke when I wore them a ton in Greece and they were amazing With my hoops I've been loving scrunchies because I pull my hair back I've been doing a lot of like slip-back looks because I wear hoops and then I'll like do minimal makeup and like big Browns and like a lip product or something But scrunchies have been amazing because when I pull my hair back. They look so cute or even like on top I just got super in scrunchies this year. I love them. They have really good packs in the urban I love the velvety ones. I pretty much besides now I took it off on purpose, but I always have a scrunchie like on my wrist at least to like they just there's the best They're so fun. Okay something that I have stopped wearing because I wore them so much my feel of sneakers guys These sneakers are $60. I bought two pairs of them in the past probably like six months I started wearing them when I went to Greece because I needed like sneakers that would be comfortable about the cute dresses and Then I wore them like pretty much every single day after it's so ridiculous I've never worn a pair of shoes more in my life than these feel of sneakers, but they're $60 and they're so comfortable and they're Gonna try to say a different word besides fun. They're cool They're definitely like on the whole like chunky dad sneaker trend which I love But yeah, I love those I wear those way too much this year Onto my fun bag of session the bag that started at all I used to always for the most part get pretty neutral bags Like I never really like stepped out and did something because I would like buy a nicer bag And then I wanted to be like neutral or whatever so I would like it's like timeless No, that is not the way to go get fun bags. It'll change your life now All I do is I buy fun bags. I just bought a new Rebecca Minkoff one That's so cute and I can't put it in my 2018 favorites They just bought it, but it is my favorite bag. I've owned in so long Also something I've noticed like you like I like my Mark Jacobs and like the bags that are like $300 more than the bags That I have that are like Thousands of dollars like I just I don't know what it is I think it's because I buy when they're like $300 I'll buy them as like a fun bag But wow this bag has been so cute. I have three bags in this whole collection I have the bigger one as well But I just wore the small one way more the big one I like it's really fun, but it's kind of annoying when you carry it I don't know. I like the smaller one better And then I also got just a black mark Jacobs backpack just for school and that backpack I've used for so many things is perfect for traveling. It is the perfect size for carrying on bag And it's not like too big to where it becomes a good turtle backpack But it carries a lot of stuff and it's just the best thing ever so I've been loving those I love mark Jacobs. I've always loved mark Jacobs like forever and ever I've just been the biggest fan. I love them Amazing She's telling me We'll be waiting, we'll be waiting She's big and I can't stop this I can't stop this skincare my favorite topic Okay, I don't know why I just said that But you guys know if you guys watch my videos that I had a very big drunk elephant obsession this year I think the drunk elephant is amazing. I honestly just ran out a lot of their products I've repurchased them a billion times that I've ran out So I don't have a ton right now, but I normally actually that's a lie. I still have a ton I'm lying. It's just because my idea of having a ton is like 30 products My favorite is their version marula luxury oil facial oil It has a dropper and it's just this really nice oil on your skin. It makes your skin look and feel Incredible like it is probably one of my favorite face products. I've ever used in my life But um drug outfit is a little pricier. I'd really recommend getting their minis I have a few of their minis because they were so nice and they sent me stuff for traveling this summer So I still have a lot of their mini sets, but it has like six products on there and they're amazing You can see what you like. I know a lot of people love their night serum That's the one that I'm not obsessed with honestly. I don't know. I just like I don't know I just love their version marula luxury facial oil That is the name it is the best thing ever you guys won't be disappointed to be tried out But I would recommend getting the minis because you guys can try out like all the products basically, okay? The next thing I have okay vitamin C serums as a whole well first off just really serums I got super super into them this year The one that I love the most is it summer Fridays, or is it Sunday Riley? I always get so confused between the two or is it Sunday Riley. It'll be on the screen. Um there serum is Amazing it's so expensive. I'm aware of that, but you put it on your face and like your face is so bright and like healthy looking It's incredible. The other one that I love is the oolah. I don't know oolah Henderson Truth serum this is a classic. This is an og. This is these two are tied to me I love them both this the truth serum smells amazing It has this like orange citrus scent, so it really wakes you up in the morning And you just feel incredible and I love it. It's so good So with these serums I've been using my nurse Jamie uplift roller This thing is amazing because it really do puffs your face my face started getting puffy in the past like 15 months when I would like wake up or travel or whatever so annoying So I got this tool and it has saved my life It really does make your skin just look a lot more firm and it helps so much like getting the serum really into your face I really like using it right after I apply my serums because I feel like they're way more like absorbed into my skin It also just deep puffs your face. It makes you look 20 times better. And then also we have the mario bedescu spray I have used them all I think they've probably been like every single one of my vlogs I have the purple one the green one the red one I have one of pretty much every purse every backpack everything that I own my car Everywhere that I go I have one this spray just like really refreshes me throughout the day And I just love it like it's amazing. I feel like it does good things for my skin I know a lot of people have like their own opinions on it But like it's just the process of it for me honestly like it calms me down it relaxes me It makes me like feel like my makeup is kind of getting a nice little refresh throughout the day I just have loved it. Last thing I have is my loving tan self-tanner my favorite self-tanner in the world It is so freaking good guys like I I just love this stuff and they come with their mitt is amazing They have they just have so many things that are so good and they're just an amazing self-tanner Moving on to makeup. I have my top three holy grail products you guys will not be surprised I don't want to talk about any of these but my in cosmetics easy cream is my favorite I feel like this is my favorite last year too. I don't think any Face products will ever talk this for me. It is the best CC cream It is so light it makes your skin just like literally it's your skin, but better like it looks So freaking good. I have a huge fan of their cosmetics I like everything that they do like I think every single product that they have I'm a huge huge fan So I really loved using that I apply that with the beauty blender fun fact I like the real tech sneaks. What tech sneaks? I like the real tech sneaks beauty blender better than the normal beauty blender and that one's like $7 and the beauty blunders like 20 Next thing is my hourglass powder These especially together that it cost my like CC cream in the hourglass powder make your skin looks so alive Like looks so incredible. I got that from Molly because she was using it like a year and a half ago And I'm still on it. I have the palette. I've had the singles. I might pretty much out of my palette I need another one, but it just gives your skin such a healthy glow And I just love it like it's one of those products that you wouldn't necessarily like think that you need But then once you use it you need it and you'll never go without it I promise you I've been using it for the past year and a half and I'll never go without it Then my last thing that I have is my bite beauty agave lip mask. This is the best lip product I've ever used I am super into moisturizing basically my whole entire body But um, so that's why I love like serums and moisturizers and all that. I also love like lip balms and stuff, right? This is the best one I've ever used. I've repurchased this I'm not exaggerating probably like 15 times like I've bought so many of them I use it as just like an everyday lip balm. I know that like it's a face mask or it's a lip mask But like I use it every day. I'm wearing it right now. It makes your lips first up They look really good. This it smells really great and it just gives you like such great moisture like It's the best product ever. I said about everything in here, but they're all really good. Okay for my hair I don't use a ton of hair products. Um at all but The one product that I swear by that I think is the best thing ever and I noticed a Very very big difference in my skin when I use this or not on my skin in my hair What I use this versus when I don't see it's tin Leavin plus keratin conditioner. It is So good. It does like 10 things for your hair I just spray it in my hair and then I brush it out with a rub brush and my skin I keep saying skin my hair feels so healthy and looks so healthy and it's shiny and just beautiful after So been loving that then for hair tools my two favorites I have this connor curling iron that I've been using for forever. That's 20 and it says really really big curls Um how I do my hair today ignore it. This is not normal. We're just gonna ignore this But um that gives you really big loose voluminous waves And then when I was in Chicago this year at my sister to my hair She used the dry bar 3d bender on me And I loved it because it was very like beachy waves like in my channel intro when I'm like turning at the very beginning I think that's what that was. Um, it's very beachy like bigger Tighter curls, but I don't know that's how I normally curl my hair like now But the dry bar 3d bender has been amazing. I love that product But if you guys don't want to spend much money on a curling iron or whatever get the connor one They are different curls though. Like the connor one is big curls. The dry bar one is like they're like tighter bigger Curls conners like looser dry bars tighter for music I just posted a drive with me of my top played songs for 2018 So if you guys want to check it out, I will have that link down below Definitely check out the video and if you guys are checking out from this video, let me know that it came from this video Okay, and then random. I have two random the first one. It's gonna come as no shock to any of you oat milk I love oat milk 2018 really was the year of oat milk for me and I'm only hoping that 2019 is as well like wow It is just so good. Like it's so much better I've never really liked auto milk and I love oat milk. It has changed my life. It's so freaking good My two go to order. It's an iced dirty chai with oat milk or a cold brew with oat milk If I make coffee from home, I just drink a black Um, and I can do a cold brew with coconut milk if I'm on starbucks. That's fine But typically if I'm like alfred That's what I get the last thing I have is a candle. It is the anthropology volcano candle Literally joe just was like walking by because it's supposed to get anthropology in here because I had the volcano Candle burning that's the candle that they burn in the store, but it smells so amazing and it's so pretty Normally, um, they have like the ones that look very anthropology. Yes, but lately I've been getting ones that are like blue I've just been trying out different things. I like all of the designs and all of the looks for the volcano candle It's amazing I know that if you go to target and you get island moonlight It's pretty much the same scent and it's like way cheaper Fun fact, but I just ordered a bunch and I obsessed even last night Like I was cleaning out my office and I found like volcano candles that I had never opened that I like Had delivered to my house That's how obsessed I am. Okay. So that is it for my 2018 favorites. I hope you guys enjoyed Let me know what was your favorite from 2018. I cannot speak I haven't filmed a normal sit down video in so long because so many of them have been vlogs But also let me know what your biggest goal of 2018 is again if you guys want to hear what I learned in 2018 how many times can I say that year? Um, I will have that podcast episode linked down below I think you guys would really enjoy it. But yeah, that's all I have for today I hope you guys enjoyed today's video and I will see you guys soon. Bye


This lecture is part of an online commutative algebra course and will be about associated primes of a module M. So the set of associated primes of M is a set noted by S of M and it's a collection of primes that sort of control where the module is geometrically, as we will see next lecture. So as motivation, let's look at the case for modules M of finite length. So if a module is finite length, then we can write nought equals m nought contained in m1 containing m2 and so on, contained in mn equals m. With each quotient mi plus 1 over mi, a simple module, this means that there's no submodules other than a zero or itself and is therefore isomorphic to something of the form R modulo a maximal ideal. Well that's fine for modules of finite length but the trouble is most modules we want to deal with are not of finite lengths and most of them tend to be finitely generated. So can we do, so can we find an analog for finitely generated modules? Well over arbitrary rings we can't really do an awful lot. So what we're going to do is assume that R is notarian and you remember that finitely generated modules over a notarian ring are also notarians, in particular the module M will be notarian. So let's start by looking at some examples just to see what's going on. Let's take our ring to be the integers z. Then modules are just finitely generated abelian groups and we know what a finitely generated abelian group looks like. It can be written as a sum of copies of z plus a sum over or p of a sum over various values mi of z over p to the n, i and z. It's just a sum of cyclic groups of various orders and we can build this out of the following modules. First of all we have the modules, the simple module z over pz which is z over the prime p so these are the simple ones but we can't build z over simple modules so we should also add the module z which is just equal to z modulo the ideal zero. So what's going on here well if we look at this we see that these ideals here are well these ones here are maximal but this one here is prime so really we're just getting prime ideals in the denominator so this suggests the following question. Can we break up m finitely generated over a notation ring into modules of the form r over p for p a prime ideal? In other words we want to find a sequence nought which is m nought contained in m1 contained in mn equals m with mi plus 1 over mi isomorphic to r over pi for some prime ideal pi. Well the answer is yes we can so well if the module is zero we obviously don't anything to do so let's assume the module m is non-zero and we first show m has a sub module isomorphic to r modulo p for p prime and for this what we do is we pick an ideal p in r which is maximal among the ideals so that such that r over p is isomorphic to a sub module of m and as usual I'll just be a bit sloppy with notation and pretend that r over p is a sub module of m. Now if r over p is a sub module of m this is the same as saying p is the annihilator of some element a in m so we're looking for an ideal that's maximal among the set of annihilators of course this doesn't mean p is a maximal ideal of the ring just means it's maximal among this set of ideals and we show that p is prime so you remember I mentioned before that if you've got a randomly chosen collection of ideals the maximal elements of that set have a really strong tendency to be prime ideals well if p is not we can find x y not in p such that x y is in p and we will get a contradiction from this well let's look at the image x bar of x in in m so you remember we've got r over p which we're pretending is a subset of m and x is in here and x bar is going to be its image there and let's look at the annihilator of x bar so this is an ideal of r and let's think it contains or it contains the ideal p rather obviously and it also contains the element y and it contains the element y because x y is in p so it's strictly bigger the ideal p and it's strictly bigger than the ideal b p because y is not in p by assumption and it's not the ideal r and it's not the ideal r because x is not in p which means x bar is not equal to zero so we've used the three conditions x y is in p y is not in p and x is not in p so this contradicts the choice of p because we assume that p was a maximum element of the set of ideals that annihilated something in m but here we found a bigger ideal that annihilates something in m so we've got this contradiction by assuming that p is not prime so p must actually be prime so now that we show that m contains a sub module of the form r over p we can very easily show that that m can be split up into some such sub modules so we start with m and if it's zero we just stop and if it's not zero then we can find a module m one such that m one is a subset of m and m one is isomorphic to r over p one with p one prime so we can carry out the first step now we've got to find a module m two how do we do this well we look at the module m modulo m one and apply the previous result to this so it contains something of the form r modulo p two a sub module and now we just take the inverse image of r over p two and take m two to be it's to be this inverse image it's the inverse image of r over p two where we have m goes to m over m one and this contains r over p two and then we see that m two over m one is then isomorphic to r over p two and now we can continue doing m three and m four in the same way and this must eventually stop and it stops because m is notarian so if we've got an increasing sequence of ideals of sub modules like this it can't go on forever well so that's all very well but there's a little problem that comes up so we can ask how often does the module r over p occur in m so we might call this the multiplicity of r over p in m and for m is at finite length we saw last lecture the multiplicity is the number of times r over p occurs in any maximal chain and more importantly it's additive so if we've got this sequence of finite length modules what goes to a goes to b goes to c goes to zero we know that we saw the multiplicity of r over p in a plus the multiplicity of r over p in b is equal to the multiplicity of r over p that should be a c i guess r over c in b so what happens if we try doing this for finitely generated modules well let's take a look at a module m being say z plus z over 2z over the integers say and then the multiplicity of z over naught in m well that's how many times does z occur in m well that's obviously one and how many times does z over 2z occur in m that's pretty obviously just c z over 2z just occur the once so that multiplicity is one okay well maybe not there's a little problem with this which we will see in the next next piece of paper the problem is the following we look at the universal counter example to everything which is naught goes to z goes to z goes to z over 2z goes to naught now let's look at what is the multiplicity of z over 2z in this well it doesn't occur there doesn't occur then it occurs once there so it's not additive so something has gone wrong and the problem is that you know we were saying z over 2z doesn't occur in z well in some sense it does because it occurs in this as a quotient so so this claim that the multiplicity of z over 2z in m is one is really dubious because z over 2z occurs in z and there's really no limit on how often it occurs in z because you know if it occurs in here once well the kernel of the map is z and then we could pick out another factor of z over 2z in here and so so z over 2z really seems to occur an infinite number of times in z and this really rather messes everything up well there are cases when the multiplicity is defined for instance if we want to know the multiplicity of z over zero in m this is sorry in m this is well defined because we can just define it to be the dimension over the rationals of the vector space m tensed with q and if m is equal to z to the n plus some finite group m tensed with q is just equal to q to the n plus well we've killed off the finite bit we just get zero and the dimension is just n and this is called this is just of course the rankover of the finitely generated group and it's additive and behaves really well and so on and you may think to yourself well if we define the multiplicity of z in m like this why don't we define the multiplicity of z modulo 2z in m like this so we could just define the multiplicity to be the dimension over the field with two elements of m tensed with z over 2z so what's wrong with this is a definition of the multiplicity well the problem is it's not additive that seems a bit odd because the um additivity of the dimension that the dimension of a vector space is certainly additive the problem is when we turn this into vector spaces over the field with two elements we run into the problem that tensuring with z over 2z does not preserve exactness as we've seen about 15 gazillion times in previous lectures so um we really run into a problem of trying to define the multiplicity of z modulo 2z in and in in a finitely generated abelian group so let's just summarize when the multiplicity as well behaved so the multiplicity of z over p in m so this is additive for p equals zero here m is finitely generated abelian group of course it's not additive or even clearly well defined for p equals um um sorry for p not zero it is additive for p even if p is zero for finite groups rather obviously so sometimes the multiplicity is additive and sometimes it isn't and you know you can ask when is it additive and when isn't it and we will see later but the answer is the multiplicity is additive for modules such that the associated primes of m has no elements strictly smaller than r over p that should say the multiplicity of r over p in a module so we're about to define the set of associated primes of m which among other things controls when the multiplicity is additive um actually um just before defining the associated primes i want to give an example which is even more disturbing than the previous one this time i'm going to take m to be the ideal in the ring of polynomials in two variables generated by x and y so as usual we can just draw a picture of this ideal to keep our um get some idea of what's going on so here i'm just drawing a dot for each basis element so this is one xx squared y and so on and we can think of the the ideal m as looking something like this you see the it's got a basis of all the monomials inside this blue region so there's a picture of m and now we can find several decompositions of m so we can first of all have the sequence north goes to r goes to m goes to r over y goes to zero and we can draw a picture of this we can understand this by most easily by drawing a picture and what's going on is just this so here we've got the module m which looks like that and then we can take a sub module isomorphic to the ring r consisting of all these bits here so it's just a sub module generated free sub module generated by that element there and then we can look at the quotient which looks like this green area here by the way i this this green area isn't a sub module it's a quotient it's the sort of sub quotient of r we're taking the um we're taking m and if we quotient out by this orange bit then then this green area is a quotient of m and you can see that it's actually isomorphic to r modulo y um this is really confusing at half the time i accidentally write it down as r over x um and this corresponds to the sequence nought equals m nought contains an m1 contained in m2 equals m where this quotient is r and this quotient here is r over y well that's fine what's the problem well the problem is we can also do things the other way round like this so we can take nought goes to r goes to m goes to r over x goes to nought and this time m looks like this and r um we're going to take r to be a slightly different sub module of m we're going to take it to be this one here and r modulo x of course looks like this stuff that's left over which looks like this so now we see that r modulo y doesn't really occur in m by looking at this sequence and r over x doesn't really occur in m by looking at this sequence so the only module that really occurs in m is r itself but the problem is we can't build m just out of copies of r you can easily check that if we try to write nought goes to r goes to m goes to r goes to zero we just can't do this um um so we seem to be kind of stuck that that doesn't seem to be a well defined notion of which modules occur in m well what we do is we define we now finally come to defining the associated primes of m so the associated primes of m is the set of prime ideals let's put that in a big box so you notice it um that um that are annihilators of elements of m so um there will be plenty of ideals that may be annihilate elements of n but aren't prime but we don't count these as being um elements of the associated primes of m we can also think of this as ideals p for p prime such that r over p is isomorphic to a sub module of m um so if m is none zero we've seen that the associated primes is none none empty so if m is not zero the associated primes of m is also not empty this is as you're assuming m is finitely generated r is notarian informally the associated primes of m is the set of p such that r over p is definitely occurs in um the module m um so for let let's just see some examples of this um so for example the associated primes of z is just the zero ideal of z the associated primes of z plus z modulo two z is now z and z and prime two and the associated primes of the funny module x y we had last time is just the zero prime um so um we can now ask what properties does the set of associated primes have so suppose we've got an exact sequence what goes to a goes to b goes to c goes to naught we can ask how do the associated primes of b compare with the associated primes of a and the associated primes of c let's ask the obvious question is set of associated primes of b equal to this union the most obvious guess and we answer this by using the standard counterexample to everything naught goes to z goes to z goes to z modulo two z goes to naught and here the associated primes of z is naught the associated primes of z is naught the associated primes of z modulo two z is naught so this is definitely wrong so what else can we do well we can at least say the associated primes of a is contained in the associated primes of b and this is completely obvious because if r over p is a sub module of a it's obviously also a sub module of b slightly more subtle fact is the associated primes of b is at least contained in the associated primes of a union the associated primes of c so although that these two aren't equal at least one side is contained in the other and this is easier to show so suppose r over p is isomorphic to a sub module and it's called a sub module x of b and there are two cases either x intersection a is empty or x intersection a is not empty and if x intersection a is empty this means x is isomorphic to a sub module of c which means that p is an associated prime of c on the other hand if x intersection a is non-empty let's pick so when I say non-empty I mean non-zero so let's pick a not equal zero in x with a in a and now we notice the annihilator of this element a is equal to p and the reason is the annihilator of any element x for x in r over p is p and we notice that because r over p is an integral domain so the annihilator of any non-zero element is is the is is is just zero which would be p so in this case p is an associated prime of a so that there are two useful consequences of this so here are some consequences first of all the set of associated primes of m is finite as usual m is finitely generated over a notarian ring if you drop those conditions there's no reason why this shouldn't be finite and what we notice is that if we have the sequence nought equals m nought contained in m1 so n contained in m n equals m then if we have mi plus one over mi equals r over pi we notice um the only associated prime is pi and now since um we see that if we've got any sequence like this then the associated primes of m must be among the associated primes of the quotients by induction and since the quotients all have only one associated prime we see that the associated primes of m must be contained in the set p1 p2 pn which is finite you remember we had some examples where the set of associated primes doesn't have to be equal to this set it might be strictly smaller but it's still finite the second property is that if we have a chain nought equals m nought contained in m1 and so on with all the mi plus one over mi of the form r over pi pi prime then any element p that is an associated prime of m um occurs in this chain and this again follows because um any associate is more or less what we said earlier um it must be one of these primes pi so so the set of associated primes is finite and they are primes that have to occur in any um decomposition of m into ideals of the form r over p so next lecture we'll be looking at um the the geometric meaning of the associated primes of m and in particular how it relates to the support of m in the spectrum of r