Well good morning everybody or good afternoon or good evening as the case may be and thank you very much for attending our presentation and what we'd like to do is to spend a bit of time telling you about the project which we're running at Hong Kong Baptist University which is about translated material in Wikipedia articles. So the title of the project is understanding Wikipedia's dark matter, translation, knowledge and point of view and we see translation in Wikipedia as Wikipedia's dark matter because we know it's there, we don't always know where it is and indeed we don't know how much of it there is. So our research focuses on analysing multi-lingual sets of articles in Wikipedia on a number of current affairs stories, current affairs events. We'd like to acknowledge the grant that we were awarded by the Hong Kong University Grants Committee and if you're interested do take a look at our blog which is called Wikipedia's Dark Matters, a WordPress blog at that URL. So in brief the objectives of the project we have a number of objectives, we've been working on Wikipedia for a number of years and we have a few ideas as to how to investigate this somewhat complex topic but we're wanting to see if we can improve the way we search for and analyse translated material. Our research is based on multi-lingual case studies and we are aiming to carry out further case studies which we'll be looking at the location of translated material in Wikipedia articles and the role that it plays, more of that in a minute. We're interested in extending the research into new areas, possibly areas that we haven't anticipated but I think in a way most importantly we want to contribute to the growing body of knowledge about Wikipedia translation. As you all know Wikipedia exists in more than 300 languages and there is a lot of translation that takes place. Wikipedia is an incredibly important resource as you all know but it's useful, we consider to know exactly where the information and the knowledge comes from that you read, who puts it there, where does it come from. So we're hoping to contribute to an answer to that question. We're looking to develop one or two new analysis tools and I'll give you a brief preview of one of them a little bit later. Hopefully we'll make some of our data sets available and as I said we have the project blog.  In fact we like to follow the principle of using Wikipedia or the materials and the resources and the tools on Wikipedia in order to study Wikipedia. So we look at the revision history statistics for example. We look where relevant at the talk pages. Those are a bit hit and miss, we're interested in translation and in many cases that's not a topic of discussion but where it is obviously that's a useful source of information. The page view statistics, the lang view statistics and the site view statistics as well to obtain numerical information on the different language editions that contain a version of the article on a particular topic that we're looking at. Wiki blame is a tool that we use quite a lot. The point of Wiki blame is it allows you to trace back the first use of a word or a phrase in an article's revision history and that's quite convenient or quite useful rather. You can see when a word is first used firstly in English and then secondly in another language and if that's forming a part of the sentence pair and you're not sure if one has been translated from another this can give you an insight depending which one was the first to appear, which was the original source and which language it was translated into. There's also a tool called Wiki Who that some of you I'm sure are aware of and this is a kind of add-on to Wikipedia and you can get it to highlight the sentences and the material in a particular article that are attributed to a certain editor and there's a slightly cut-down version of that also called Who Color and then we have the project alignment tool that our research assistants is working on developing and this is extremely useful. It makes the process of identifying potentially translated material a whole lot easier. So this is a, it's not fully developed yet. This is where it's at at the moment. These are sentences taken from an article in English and the corresponding article in Chinese and you'll see the score on the left-hand side. This is a score reflecting the probability that those two sentences correspond to each other. In other words, one is a translation of the other and I'm sure you'll appreciate that that takes out very much of a lot of the sweat involved in identifying translated material. If you're interested in that, do take a look at our presentation on this tool, which you can find in the on-demand section of the conference. So if you're researching Wikipedia translation, I think I've hopefully made it clear by now that there is a huge lack of clarity regarding how much translation there is, what its focuses are and where it's likely to be found in the course of a particular article. I like to think of Wikipedia articles as objects that exist in four dimensions, including the dimension of time. As you know, all past versions of an article are archived in the revision history and they're available to inspect via that revision history, which is attached to every article, as everybody knows. Untangling the way in which two articles have evolved in parallel can be rather complex and painstaking. Typically, this would be the English Wikipedia article and one in another language you might be interested in, English is rightly or wrongly for better or for worse, it tends to be the go-to version if editors in another language are looking to populate their own developing article. Wikipedia translation, which is the term we used to refer to this, it's not only involving bringing a material from one language version of an article into another but very frequently, possibly more frequently, it involves translation from outside the encyclopedia and with multiple editors working on an article and the information, the content coming from a range of different sources, Wikipedia articles very quickly come to look like collages. We're interested in news stories and in particular rapidly developing news stories and translation in the news has been researched in quite a lot of detail and translation in the news does not generally involve translation of an entire text, it involves a number of processes like the ones enumerated in the first bullet point selection, correction verification and so on. So it's putting together, it's compiling a new text on the basis of different sources and this is what we see in Wikipedia and one of those sources may well be another article in another language. The special role that Wikipedia will play in news reporting or chronicling news events is that it falls between the timescales of newspapers, news broadcasts and so on and history writing, somewhere between the two and in the articles we're looking at the time frame tends to be very short and I suppose I'm particularly interested in the early stages of reporting on a recently breaking news story. The typical way of reporting on a news story in Wikipedia is for quotations from press sources to be brought in and then to be worked into a coherent article. So translation on Wikipedia is rather atypical. First of all a translator, a translator editor will decide what they want to translate and then once it's been uploaded, been published then or any other editor obviously can mercilessly edit their translated text which takes on a life of its own. This means that both the source text and the target text, they're both subject to change. I tend to refer to them as moving objects which means that the equivalent that might exist after a translated segment has been inserted might not persist for very long. As you know, no finalised version of a Wikipedia article or indeed of a particular translation is usually arrived at and following on from what I was saying about news translation, the distinction between translation and original writing summarising, paraphrasing and source sharing can get somewhat blurred. Now a point of view is a concept that's very important in Wikipedia particularly since the official policy is to pursue a neutral point of view principle. And I know that editors do strive after this very conscientiously but in reality of course complete neutrality is very difficult to achieve. Now of course that being the case one would expect different versions of an article to have different points of view and that is indeed very often what we do see sometimes it's referred to as linguistic points of view, the points of view that is specific to a specific language version of an article. Points of view has not perhaps been theoretically formalised to the extent that another related concept has been and that's a concept of narrative, a narrative being an underlying story that gives events a particular meaning to a particular group of people. There is a clear overlap between points of view and narrative and that is being actively investigated in translation studies but at the moment points of view has not been theorised at in any detail. Now when you're looking at a Wikipedia news article you can look for clues as to the point of view or sets of point of view or narratives that it contains in quite a number of different features of the article for example the way it's structured or balanced, the information that's excluded or highlighted or maybe excluded, the selection of comments and reactions that are included, the sources for quotes and expert opinions the number of references in different languages as well that's quite significant, also the tolerance of controversy the general tone of discussion and so on and of course as an article is developed the point of view that it represents may also slowly shift. So it's difficult to answer this question generically I'm going to be focusing on a particular case study very shortly and we're going to be looking at the English an English article and its translation into Chinese and it does contain a lot of translation typically translation will involve text fragments which can be from another Wikipedia article or from an external source and also copying of major features from one to the other. Now I'm going to perhaps jump on a little bit because I do want to look at the case study itself which is involving an event that happened about three years ago I'm sure many of you or all of you will remember this there was a poisoning event a former Russian spy living in the UK and his daughter who was visiting suddenly fell ill after an attack by a nerve agent called Navichok and this was widely reported and written about in Wikipedia in fact there are now 25 different versions of the article in the multilingual encyclopedia. The English article has been developed in great detail by many editors over 500 editors and it's now approaching 10,000 words in length. There is the brief breakdown of contents a very wide-ranging article and then the Chinese version somewhat shorter and worked on by fewer editors and not as actively developed as you'll see and they're a much shorter, more succinct table of contents. So without our tool finding the translation was painstaking it was a highly painstaking in fact because you had to if you found a... if you're looking at a particular sentence you had to search for its equivalent using keywords, people's names and so on and then you could trace back to where each one first appeared in the revision history you can see those snippets at the bottom of the screen and in cases where this was a matter of some doubt it would allow you to see exactly which one appeared first and then what the direction of translation was in this case it's fairly apparent that the translation was from English to Chinese. So that's an example of a snippet, a small piece of text which was translated from one version to another I also looked at the Russian there was a lot of translation mostly from English to Russian partly also in the other direction but for the Chinese there was a massive amount of translation Now the other feature I would like to look at following this event there was a tit for tat a series of tit for tat expulsions of diplomats and this was presented in a number of Wikipedia articles in the form of a table it actually appeared first in the Russian and then it was added shortly afterwards to the English and then to the Chinese and also it appeared in a number of other Wikipedia versions so we see that in English it was put in alphabetical order


Welcome to the Pyramid Insider. I'm Tyler Patner and today we're going to give you seven stocking stuffers that you need to have on your list for the air gunner in your life or if you're an air gunner buying your own Stuffing things for your stocking. This will help you too So first things first on our list. We have ballast all now This is my favorite kind of cleaner lubricant kind of do all everything You know it comes in an aerosol can here You can also buy it if you want to buy just the lube and like screw on one of those spray heads You could do that too. They have this in a couple different bottle sizes as well, but this is great I use it for cleaning barrels keeping the metal the wood surfaces on my guns clean Keeps those fingerprints off of there and make sure that you're not going to have any rust or pitting or anything like that So definitely one I recommend and fits nicely into your stocking now next up is my favorite barrel cleaning tool Now this is the patchworm kit. This is a 1 7 7 kit here You could see it's just a long rope here with a kind of a Flared end there and that's gonna actually fit nicely into your 17 caliber barrels But they also make this in a 22 to kind of 45 or 50 cal Kit as well that comes with all the different adapters for the different caliber sizes comes with a nice little holder for your patches This is a really easy system nice and compact You're gonna be able to keep this in your gun case with you and when you you know hit a couple patches with some ballast I'll pull a couple dry ones through your barrel. You're gonna be nice and clean ready to go It's a very quick system and my favorite way to clean barrels Next up we have the fix it sticks scope jack now this thing is awesome helps Mounting and leveling your scopes Without any of the levels and any of that stuff having to worry about making sure the guns level the scopes level or the mounts level This thing takes care of all of that for you in one shot You mount this onto a Picatinny rail section and basically you just use that jack on the saddle of the scope And it levels it right out for you It's actually a really awesome tool and one you absolutely have to have if you do a lot of scope swapping or if you end up mounting Scopes frequently a real godsend. It's gonna save you a lot of time when you're setting up a new gun and To go along with that but something that you should absolutely have in your kind of air gunners tool kit as well Our Picatinny to dovetail adapters so these adapters here We have a set from BKL and we also have a UTG set That's a little bit lower profile. These will actually clamp on to your dovetail those 11 millimeter dovetails That are so common on air guns and give you a little Picatinny section So for those of you that are using Picatinny rings or you prefer to use weaver Picatinny mounts This gives you the option to do that or swap scopes between guns Even if you have an 11 millimeter dovetail and kind of going along with that scope jack earlier You can actually use this as an adapter so you can still use the scope jack on your 11 millimeter dovetail Airguns a really handy tool again these lower profile ones from UTG nice and inexpensive I wouldn't recommend these for a spring gun but for your PCPs These will work great if you do have something you need to adapt on a spring gun BKL is gonna be the way to go but either way these are great tools to have in your kit and gonna make great stocking stuffers Next up on the list is an absolute essential particularly for the PCP air gunners out there This is silicone grease now. This is a tube a hill silicone grease. You can see I've already used quite a bit of it You can buy a few different varieties of this on our website and whether it's silicone grease or silicone lubricant Which is you know a little bit more liquidy Either way gonna do a great job of keeping your O-rings lubricated keeping them nice and lively So an absolute essential and one you have to have in your air gunner toolkit Next up are my new favorite target here at Pyramid air. These are the Firebird bio targets This is the bio 50. This is the bio 65 the 50 and the 65 refer to the diameter of the target these explode All right, you put them up against a hard surface you shoot them with your air gun and they go boom They are awesome a ton of fun add a nice lively experience to your shooting But you're only gonna want to use them outside So not for those of you that are gonna be shooting either in a residential backyard or in your basement All right get into it some nice open space put up some of these Firebird targets You are gonna have a great time. They come in packs of 10 There's a lot of fun to go around some big booms some big explosions Buy some have fun with them. They are a great time and you need to have them Last up on our list of stocking stuffers is probably something that won't fit in the stocking But a nice thing to have anyway. This is the kind of newly redesigned air venturi quiet trap This is gonna be great for these 10 meter targets. You see here will pull them up So you actually have some ballistic putty back there Obviously you take it out of the packaging and kind of form it to the trap But this is a great trap that's nice and quiet especially for those basement shooters out there And if you are worried about over penetration or you want to shoot more powerful air guns at this trap get the version with the Steelbacker it's gonna give you that little bit of extra reinforcement and protection But overall a really nice target trap that works great And you can cut your own targets for it when you run out of these 10 meter ones They slide right into this slot here an awesome system for under a hundred bucks So that wraps up our list of seven stocking stuffers for all of you air gunners out there Whether you have an air gunner that's just come into your life or you're in a seasoned vet And you're looking for small things to put under the tree or into your stocking or whatever kind of holiday Gifting you're into these are some great options. So definitely check them out next time you're on pyramid air calm If you agree with the list here, or if you think we missed something Let us know down in the comments below. Don't forget to like and share as well We appreciate it a ton also subscribe if you're not already. I'm Tyler Patner and we'll see you next time


The five main types of teaching styles. The activity of any teacher necessarily has its own style. This is a permanent set of techniques that manifests itself with varying degrees of intensity depending on the situation. The stylistic pedagogical activity depends on several factors, both on the activity itself and on the students. The style is very much due to the individual characteristics of the teacher's personality. There are five main types of teaching styles. Teacher as an authority. The first one is called the authority style. The teacher considers his students as objects of influence, and not equal partners in the activity. For this reason, the teacher separates himself both from the educational team and from each student individually. This type of teachers always controls independently. In fact, this particular style is more popular in universities. The advantage of the authority method is that it's a better approach for older students during classes which necessitate memorization and don't require teachers' feedback. However, this style of individual lessons is unacceptable. Students become closed. Contact with a teacher is not established, which has a negative influence on students' success and progress as they don't have any desire to study. Some students resist such an impact and provoke conflict. As a result, most children lose their self-confidence and independence. Teacher as a demonstrator. The demonstrator style is the second teaching type of behavior. This style is also called coach style and has many similarities with the authority style. In other lessons, a teacher might include multimedia presentations or different class activities. This style is perfect for subjects where you can provide a full understanding of a topic only through demonstration. For instance, teaching music, arts, science, etc. The main problem is that interaction between the teacher and students is small. Teacher as a facilitator. The third style is named the facilitator style. The main task of the teacher facilitator is to facilitate and at the same time stimulate the learning process, by creating an appropriate intellectual and emotional environment in the classroom and an atmosphere of psychological support. This style of teaching encourages self-learning, which means that students should find answers and information through exploration. Learning is structured as follows, the teacher helps to formulate goals and objectives for a group of students or individual, and then creates a free and relaxed atmosphere that will encourage students to solve problems. In this case, as a teacher it is important, to be yourself, openly express your thoughts and feelings, to show children full confidence in them and in their capabilities and abilities, to show empathy, that is, an understanding of the feelings and experiences of each student. This technique should be used in small groups because a teacher facilitator needs to interact with students individually. Teacher as a delegator. The fourth style is the delegator style. This method is often used for group work and activities. The teacher has the role of observer and has to involve students into such activities as different team projects, creative writing or debate. The advantage of this teaching strategy is that students feel their independence and freedom of choice. On the other hand, some people may criticize this style because it influences teacher's authority. Teacher as a conductor. The last, fifth style is the hybrid style or blended learning is a modern digital teaching approach that combines traditional classroom techniques with computer mediated learning activities. The strength of this training is the combination of different technologies into one integrated learning approach. Teachers prefer blended learning because of the quantity and quality of interaction between the participants and the educational process increase. This teaching method helps to create a sense of community in large classes and allows students to access course materials and master them at a convenient time in place. On the contrary, there are many arguments against this learning method because it has a negative impact on students and teachers. For students, it might be a cognitive load or some usage difficulties for very young inexperienced learners. For teachers, one of the main problems is overwork. Each time, they have to develop a unique content adapted to their students needs.  To summarize I can't claim that there's one particular style which is considered to be the best. All of them have their pros and cons. In my opinion, the teacher's behavior and teaching style should be flexible, balanced and appropriate. I believe that the best teaching style includes such qualities as being sensitive to your students, being able to motivate them and hear theirs requires and complains. Speak with an ITTT advisor today to put together your personal plan for teaching English abroad. Send us an email or call us toll free at 1-800-490-0531 to speak with an ITTT advisor today.


Good evening. By now, I think most Team Fortress 2 players have accepted the fact that we are likely never getting a major Valve-made update again, and that the final TF comic is probably never coming either. But that's no fun to talk about, so why don't we instead speculate on what we could have gotten if things had turned out a little different? I've got a theory. I think RD asteroid, the scrapped robot destruction map from 2014, and the final TF2 comic may have been linked. It's possible we were to expect a space-themed update to release with the series finale. Let me explain. In TF comic number 4, Blood in the Water, the reader is armed with the knowledge that Sniper's mother has escaped to outer space with the last known package of Australia, which Miss Pauling desperately wanted to acquire for the administrator. This comic was posted only three months after testing for RD asteroid, which takes place in outer space, began. Since then, neither asteroid nor the TF comics have been finished. It's very strange that asteroid's development was totally abandoned given how much effort was put into it. The whole new setting was crafted, with concept art that seems to have been made in-house by Moby Frank. The map had enough unique parts created for it to warrant its own asset folder called Moonbase, and it also carried with it new gameplay models for its robots and reactor cores. The announcer's voice actor, Ellen McClane, even performed unique lines just for asteroid. Given all this, I'd say it definitely seems Valve had plans for this map beyond what we got. So, is there any definitive proof? To be totally upfront, no. But it is at least conspicuous how well the timelines match up. Science concept art was teased on the same blog post they promoted comic number three on. This timing implies that comic number four and RD asteroid were conceived around the same time. I think it's also worth noting that a good amount of community members anticipated a space or moonbase theme update for TF2 during this era. A notion Valve never publicly dispelled. Here is an example of a publication speculating about a moonbase update. Here is an example of a user created cosmetic created during this hype. Some people also point to the announcer's dramatic dialogue and hurried tone on RD asteroid, as evidence that this mission was more closely intertwined with the game's story than we initially thought. This is total speculation, but interesting to think about nonetheless. We must launch that transport ship! We are running out of time! Is it possible that an arc in the comics where the mercenaries go into space to get Australian was in the works, with an in-game space update planned to coincide with its release? Unfortunately, unless more information is made available, we have no way to know. But given the circumstantial evidence we have, I do feel comfortable saying that the TF2 story writers most likely did, at least at one point, contemplate moving the game's story into outer space. Isn't that fun to think about?


Video equipment rental costs paid for by peep-code screencasts. Hi, I'm Jake Speggs. I work at Abtivo, and I'm here to tell you about how to use metrics to improve your code quality. Your code is in red to emphasize that it's not just other people's code that's bad. So I should just say that I come from a very lucky special place that I used to teach high school physics, and then I sort of got an apprenticeship at Object Mentor, and I turned that into a gig at Bow Works, where I did six projects, and now I'm a consultant at Abtiva. And that is just a great place to learn about code. Like all these places are known for just being kind of ludicrously obsessed with like what's good quality. I mean especially Object Mentor right there. They're all about training people to be better at code and they get paid a lot of money to do so. So I've been at all these places that stand up here on stages just like this and tell you how to write your better code. So having worked there, you might wonder like, how much bad code is he, right? I probably just saw a perfect code. And that's not true at all, right? I saw plenty of bad code, some truly truly horrible code while working at all of these places. And that doesn't say that these places are bad or anything, but it does mean a very important fact of the matter is that you can't just hire a bunch of really smart people and feel like you're done. Like there's a number of places out there that will say, you know, we've got this great system where we check everybody and we do code reviews and we go through and we take a look at everybody from a bunch of different angles, from management, from code point of view and then we hire them and they're really good. My second ThoughtWorks project was this monstrous 7-year-old Java app that paid the bills at ThoughtWorks. And you know what? Everybody around there was a ThoughtWorker. There was no way to say, oh it was the client who did it, right? It was totally staffed by and coded by ThoughtWorkers and it was really horrible. It was brutal. I think the code coverage when I first got there, like IU actually turned down the code coverage and it was like 21% and it was bad. It was a lot. At one time it was the largest entity being application in the world, which I'll tell you a little bit. So the thing about writing bad code is pretty much everybody does it. And even if you're real smart, it doesn't necessarily mean you're going to end up with a great code base. So strategies for cutting down on crappy code. By the way, the only valid measurement of code quality is WTS per minute. My favorite thing about this little thing is that even in the good code room, there's a couple of WTS. Like what? Strategies you've all heard about pair programming is a good strategy, right? You get two people, odds are there's one guy sitting there going, you know, maybe we should call that variable X. Something else. Okay, all right. Keeping the maintainer in mind is something that, you know, a lot of people have trouble with because they feel like, hey, I write my own good code and everybody else, like that's their deal. But you're going to write code and then somebody else is going to come along and be in there.  And maybe it's not really a problem. Maybe it was some guy came along and said, well, I just need to have this one extra feature and they didn't really understand your code. You know, there's this idea of sort of where you're at right now. You write for that place because that's where you're at right now. But people tend to forget like dudes are coming on to your project all the time and they may not be great at whatever language you're writing in. Another strategy is to review your old code and see if that hot piece stands up after six months. You know, that is one of my favorite things to do, you know, like you go, I'm in love with this code. This is genius. This is, ah, people are going to love it. And then six months later, you're looking at it and you're like, this is a bunch. This is terrible. I can't stand this. So you can do all these things. Probably a fair amount of guys in this audience actually do do all these things.  I've seen these practices applied. I've been in full-on XP teams where everybody's doing everything in every practice and I've still run into bad parts of town. That one controller where everybody's like, you know, I'm going there. That's bad. That's scary. Just leave it alone. Push some logic down into view so you don't have to go into that.   I've seen pairs get excited about metaprogramming and they just learned about metaprogramming and I think we're going to use metaprogramming for this and it's going to be great. No, it's not great. The other thing is the late, great George Carlin, you probably realize that he had things to say about software, but he did. And one of his big bits was like, you ever notice when you're on the highway that you're driving along and everybody's going faster than you? You're crazy, man. That guy's going way too fast. Everybody's going slower than you?  You're driving along.  And it's the same thing with coding, right? Like where you're at right now as a coder tends to be what you think is good for a level of coding, right? It's just something you internalize for yourself, right? So there's been times where I've seen RubyCode when I first got into Ruby and I was like, that's nuts. And then later saw that same RubyCode and went, oh, that's a clever application of X, right? So things to keep in mind is that where you're at right now is not necessarily where everybody else is.  I mean, of course, my favorite looking at old code is the occasional SVN blame, which implicates yourself. That is when you know you've arrived as a coder, right? You're like, this is horrible. Who wrote this? Never mind. The other thing is that every time I ran into a bad pile of code, I would usually go track somebody down and say, why did you write this? And they'd tell me some perfectly reasonable story. Two years ago, the client demanded that we be able to maintain, to talk to the database two different ways so they could deploy two different parts of the apps in two different places, right? Or at separate times. And so they had to have two different ways to access the database. And I was like, cool. So you wrote all that, you wrote to access the database using metaprogramming and Java, okay. So did we ever use that? Like nobody ever deployed that app again, you know, separately. So you could have just taken all that out. Great code plus time often equals trouble. The other thing is that oftentimes you'll have like a neat little piece of like framework code or something that does something hot. And the next guy comes along and goes like, I just add a little bit more to that. And then the other person comes in and puts, I'm going to put a little bit more in there. And before you know it, that method is huge and bad. And there's a lot of things. So no big surprise from the title of this talk. I promote metrics, code metrics as another perspective, right? A way to sort of get outside your own head and outside of the, you know, collective speak of the team and say, you know, what are we really doing and is this good? So I'm going to start off with code coverage. Code coverage. So easy. You're probably already doing it, right?  Cool. And they ran it, you know, maybe they even run it as part of the build. You know, so you have like code coverage stats. So great, huh? How's that working out? You doing anything with that? Like a lot of times metrics, people get a little hot on them and they kind of install them and then they go, oh, look, we have code coverage now. Cool. And then two weeks later, like, nobody ever looks at it again, right? Like, I've been on projects for like, there's code coverage and it's been busted for three months and no one noticed. All right? Like, that's the project I'm on now, right? Like, I was like, hey guys, did you notice the code coverage is working? And they're like, no. Let's fix that. So code coverage inspires a lot of debate. One of them is what's a good coverage number, right? Your tests cover your code. So you've got this thing that's figuring out which lines of code are getting hit by your tests. And so you have code coverage and you have a percent. And you can get to 100% with Ruby. Like, when I was back in the Java days, 85%, much past that was kind of hard. You had to figure out how to get inside all those exceptions. But Ruby, get to 100%. Great. The problem is, is that even though you know 30% is bad, 100% may not be good, right? Like, especially if you have like a team that's kind of pressuring everybody to code covered or maybe even a manager who's saying, we got to cover code. You know, you can write one spec or test. It'll cover like 50 lines of code, right? It might not be any good.  And it does a bunch of things and then it just asserts success, right? Oh, okay. So it didn't go up. I guess that's coverage of a sort. But not necessarily good.   But they hit all those lines. So the question is, is my test any good? I'm going to talk about this more, but a good goal is as many tests as there are paths to a given method, right? So if there's nine ways to get through that method, in theory, that means nine tests. I don't often do that, but it's a good goal, right? It's a good place to try and say, where am I going to?  Just about the worst. It has its uses, right? What I don't like about it is it promotes a false sense of security, is that if you're doing any testing at all, very often you'll like install coverage and you go 93, 92%, great. We're perfect. And then you just sort of wander away, right? And that is not really a good tool then, right? It doesn't told you anything. It just sort of validated you and you felt good in your heart and you moved on. If you have low code coverage, then it tells you where to test. And so that's useful. A lot of people don't know that our code is C0 coverage, right? It's just whether the line got hit. C1 or C2 coverage would be pretty cool.  Maybe you only got through the first one that short circuited, right? Return false, ooh, nothing else like got evaluated. So you hit that line, but you may not have written all that line. And C2 has to do with like different paths to the app, right? If you have big hunks of code, like a big if statement, another if statement, and there's three ways through this if statement, and there's two ways through that, then three times two is six paths, like that's how many paths to the app. But that's, that's tricky, right? Somebody wants to write that. Thanks. I don't know if that's coming anytime soon. So another way to measure metrics on code is complexity measurement. And there's a couple of ways to do this. The first and probably well known in this room, but not super well known in the Ruby community is a FLOG scores. So you can use FLOG to run on your code and it will give you some sort of score.  What does that mean? I got a score of 168.5. Is that bad?  First of all, FLOG uses what's called an ABC metric, which is assignments, branches, and calls. So assignments, assigning two variables, branches, branching, all right, how many paths, and then calls, like a call off to another method. So here's an example. Pretty straightforward. And here's a FLOG score for it. So in the first one, I'm doing an eval. The next one, I'm doing a branch, very simple branch, then an assignment, then a call. And you can see the FLOG scores over on the right hand side. And the first one, do an eval, gives you six points. The second one, you got a branch, okay, 1.2, and then you have an equal equal, 1.2, and that adds up to 1.7. Yeah, okay, all right. Moving on. All right, so you got assignment, 1.2, and then literal fix. Oh, punishes you for a magic number. Nice, okay. That adds up to, yeah. Oh, and the bottom one works. That's cool. All right, fits. That's a straightforward call. One of the issues with FLOG is that if you go to the FLOG website, first of all, it's scary, right?  And there's like a picture of some code and then it explains how the numbers come out. And that's a lie. Like if you run FLOG on that code, it doesn't give you that number because he changed it a while ago to use some other algorithm. So it used to be like 1.2 plus 1.2 would be 2.4. It's not anymore. He uses some others. He made a cryptic reference to some sort of distance algorithm, which I'm not really sure what he's doing, but even though FLOG is kind of weird and sort of magical, I really like its relative numbers. Because when you run FLOG on your app, it scores all your methods in the app and it starts right at the top with the most complex one. So you don't really need to know too much about how it works, although it's nice. And you can just say, hey, here's my 10 worse methods. And that's a powerful thing. But to answer your question of what's a good FLOG score, I've run FLOG on a couple of different applications I've worked on. And here's a couple general guidelines. So FLOG score between 0 and 10. Awesome. That method probably doesn't do anything at all, but it's got a really low complexity. 11 to 12. This is possible, right? This is an actual method that maybe does something. And this is good enough, complex, but not bad. 21 to 40. Might need refactoring. 41 to 60. Possible to justify. I've seen things in this range. And the 21 to 60 range is the interesting range for me. I've seen things in there that are horrible and should be refactored immediately. And I've also seen things in there where you're like, nope, it's complex. It's a complex problem space. That's an okay complexity for that particular method. We're in judgment call territory. Once you get much bigger than that, start running the danger zone. Okay. Alarm start going off in your head. You know, like 100. And then this is bad. This is bad. Let me tell you, I've seen these. That's a good time. When you get into the 300s, we got a couple of them on an application that I've been called in to consult on.  And guess what? It's in a controller. And yeah, we're going to have to refactor that. And it's going to be complex. It's going to be fun. So here's those are your general guidelines. Vlog is opinionated, which is a good, right? Opinions are good. But documentation is lacking. You go inside the flood source. There's all sorts of interesting methods like bad dog and bleed. And so, yeah. That's, you know, figure it out. That's fun. If I get time to it, I will talk about flame, which is actually a fork of flog, which is an attempt to re-rate flog and put some specs around it. But I might not get to that. Let's see. Relative scores. Excellent. Right. And the really cool thing about flog is that it knows what a badness in Ruby is. Is that if you remember that slide a couple of slides ago where I called out to eval, and then I called out to puts. And the eval gave six points to, and the puts it gave 1.2 points to. Flog knows what's tricky in Ruby.  Which is good, because you could write like a pretty short little method and use some really complex stuff and start, you know, open up the module and redefine in something. And that's, you know, that's a part where a new guy in the Ruby is really going to stumble. So the badness in Ruby gets punished by flog appropriately. Now, badness, right, that's a strong word. It could be totally good. You could be writing something really cool. But it is complex. And you should know about it. You should know where the complexity in your code lives. Secure. Secure is a way to measure cyclomatic complexity inside of Ruby. Cyclomatic complexity is a thing that Java developers are really familiar with, but maybe not so much Ruby developers. If you look at this example, this is the code I used before, but I've added a few more examples. I added a branching with some more complex branching, and I also added some metaprogramming down at the bottom just because metaprogramming is cool. And here's a secure readout for this. So secure comes in and measures the cyclomatic complexity of this. Now, cyclomatic complexity can be measured a couple of different ways. Secure takes about the easiest way to measure it. It's, they're measuring just closed paths in your code, right? So if you have ifs, how many ways do you have to get through and get to the end? So if you look at the more branching example, you can get to that line puts B, but then there's two choices there. So you're like, okay, that's two. And then you get that line puts C, but then there's two ways to be there. So that's two more. And then you get to that last puts, but there's another sort of maybe it'll happen, maybe it won't.  Why seven? Oh, because there's an if and if else maybe none of those things are true. So there's a seventh way to get through that method. All right? Secure does not do the sort of pass through it, right? If you have two big chunks of code and one has five ways to get through it and one has two ways, it doesn't multiply those two together to get 10. It tends to take a more simple way of measuring a cyclomatic complexity is still a useful thing, but you should know that which way it's measuring. And they're totally honest about it if you look at the documentation. Interesting thing here is though, where's the dynamic one? Right? There's a dynamic method down there and it doesn't show up at all. And that's one of the gaping holes right here is that it's not going to pick up dynamically defined methods at all. So be aware. Like on my last project, dynamic methods everywhere. Yes, it was pretty exciting. And I ran secure on it and I'm like, hey, nothing's much above 10 or 12, we're okay, right? No, it was just ignoring all the dynamic stuff. Right? So I was like, oh, darn. So then I ran flood on it. And flood actually does a pretty good job of picking it up, right? So if you'll notice that the dynamic method on the bottom, flood comes along and says, oh, okay, here's this thing defined method branch puts, and it's just sort of in that class. And it measures it up and it just piles it into there. It says like, here's those sort of class secure example, none.  So that is pretty useful. Now you've measured your complexity. What do you do? Well, one of the things I did on a couple of projects I've been on is create a hit list. So we just have a list, put up in the dev room, like here's our 10 worst methods, right? And we play dev tasks. And so like you got some time, maybe you should just go look at that method and see what it does. And sometimes the answer is, this is great. This does exactly what it's supposed to do. Other times it's, ooh, this is bad. Wow, this thing's doing 10 different things. Maybe we can break this apart. So I really like the method hit list because you can examine the worst offenders and you can refactor, right? And it's piecemeal and it prioritizes. Because a lot of times we want a project and everybody's like, oh man, the code's so bad. And you got 10 developers in the room and they're all agreeing that the code's bad, but nobody agrees where to start. The cool thing about ranking your methods in order of complexity is, you know where to start. Start with the most complex one. All right.  So I like real code. Very often at talks, you'll see people say, hey, I'm going to show you like a contrived example, you know? They'll probably even own up to it. They'll say, this is just something I cooked up. This is a real method I found in our source code a couple weeks ago. I did a flawed one on it and I came up with this guy and I said, hey, this is kind of neat. I have no idea what this does. So I'm going to take a look at it. All right. It's a flag score of 155. So that's definitely in the probably should refactor range. And down around 11 Stein is did you mean functionality? So you have a search engine, you have a little box and people type in pizza that they spell it with one Z. So instead of coming back and saying, I have no idea what you're talking about. It'd be cool if you could say, oh, P I Z A is very close to P I Z Z A. Maybe you meant this. So did you mean, right? Google does it really well. We do it okay. So here's demo 11 Stein. This measures the distance between two words. And it's kind of complex. So if you come in here and you scroll down, you see, it's doing a lot of stuff. There's some more over here. Keeps going. And then we return something. So it's like creating a matrix, looping, okay. Got some cases. So various cases, we assign some costs. Then we stick stuff into the matrix. And then if something happens, we stick a different thing in the matrix. Gotcha. Piece of cake. So I said, you know what? Let's take a look at this and see if we can make it a little better. So my first pass at refactoring this, I've now kind of broken it up a little bit. So I said, all right, demo 11 Stein, let's just say that there's this thing called construct starting matrix, right? Because that's just populating a matrix with starting values. Fine. And then we do this loop and there's a part where we calculate the cost. So you take a look at wherever you are in the matrix of these two words and you compute the cost between the two letters. I don't really know how that works quite yet at this point in refactoring, but I know that they're commuting the cost. And then we stick some stuff in to the matrix and we do something called a demoral extension. Let me explain. So here's constructed a starting matrix, pretty much just copy pasted and moved. Here's the cost. Here's the demoral extension. Demoral extension is interesting because it has to do with transposed letters. So say you spell something like, but in Chicago there's this restaurant called Magianos and everybody spells it differently. There's like a million ways to spell Magianos.  That's not so bad. We're going to give you a discount for that, right? Which is nice. You can find, you know, what's a common human mistake. So you can now say, all right, this thing has a little bit, is a little bit closer in the space to something that transports letters. The interesting thing is that now that I've started pulling this out, I can actually think about it. Like, what are these costs doing? Like, well, this is interesting. Like, they're basically saying if the two letters are the same, then give them a cost of zero. Okay, that makes sense. Like, if you have an R and an R at the same place in those two words, then, okay, they're similar there. Good. And then this does some weird stuff like, okay, got an S and an apostrophe. Well, that's minus two. And this is minus one. That's apostrophe S. Right? So what you're doing is you're saying, like, if I want to get a Geno's East Pizza and I spell it Geno, I want to give you a discount for Geno's. Right? So if I'm suggesting Geno's apostrophe S versus Geno, those are similar. Those are closer. And this one is also doing a similar thing. This has got an O and an apostrophe. O apostrophe. Like, O mallies versus mallies. Which is cool. Now that I've actually pulled this apart into something smaller, I can actually think about this and actually realize what the heck they're trying to do here. The scores are okay. Right? This is 52, 15. Oh, nice. 50, 40. Okay. I did a little bit of the refactoring past pulling out the smaller methods that I did to actually put a word and suggest it into instance variables. I didn't have to pass them around quite so much. I can go farther, though. Right? More. More refactoring. You don't seem that excited. Okay.  I'm going to pull this apart. So now I just sort of put this in. I construct the starting matrix. Then I just populate the matrix. And then I return some stuff. Construct starting matrix hasn't changed much at all. It's still doing the same stuff. Let's see. Populate matrix. Okay. Loop through this. And then insert Damerrill-Levenstein into matrix. Okay. Okay. Come down here. This guy does the Levenstein cost. And then also the Damerrill extension. Right? So put something in the matrix. And then the Damerrill extension happens if the letters are just transposed. So you get a little discount for that. And then here's the calculate Levenstein cost. Here's an interesting thing. I love of these guys. Right? Same letter just to tell you what that means. Apostrophe S. Oh, apostrophe.  And it has a nice little name for it, which is cool. Here's the Damerrill extension, our friend. And here's something I labeled transposed letters. Right? So we had this if here that was doing something kind of interesting. I just called it transposed letters to give the next person in a little bit of a clue as to what's happening. It's a couple other factors that happened along the way. I used up to instead of one dot dot three dot each do, just because why not? And there was this weird thing. I don't know if you saw it earlier where like they inserted like some blank spot into the matrix and then populated it. Why not just populate it right away? But and I hope maybe some of you are feeling a little uneasy right now, because that's sort of my point is I think I'm going a little too far here. I've now taken this one method and pulled it apart so much that somebody coming in here may not actually have any idea what's going on. And if I could find my darn mouse, I could go up. It'd be great. Oh, I'm on the screen. Nice. Awesome. Have you ever been in code that's too much refactored? Has had too much refactoring? I have.   Okay, well, we'll find that other method. That guy doesn't do anything at all. He just calls a bunch of other methods, right? And you do that and you do that. And then by the time you figure out what's going on, you're like, wait, I'm five layers in. I don't remember what was going on up in the top level method. I think that the sweet spot is somewhere between the medium method and the small methods.  There's also some things I hate about the fact that you have to travel through this whole file just to keep figuring out what's going on. I think if I had to do this over, or if I was going to put this in to the code, I would probably not break it down quite so much. Like one red herring for me is like this populate matrix is just kind of mysterious. What does it do? There's a lot of stuff that doesn't actually refer, you know, like have to do with each other. It seems to break like single responsibility here, right? Like insert, dammer out 11, what are you doing? Two different things here. Why not just do them separately on separate lines instead of creating one method that does these two different things? My personal opinion. And that's an interesting thing about refactoring is that's to taste. That's about you as a team deciding what are good codes to enders. So anyway, you wouldn't of course attempt to do this without having some tests. So here we are. I have a bunch of specs for this guy. And I run them. It would be really cool if that would have popped up over there. And they all don't pass. What's going on? If you look down here, the things that don't work are apostrophe S and O apostrophe. You know why they don't work? Because they don't work. They're not doing anything. Like when I was refactoring this guy, and this is production code that's been lived for a year, I realized that those discounts don't work at all. Like if I just commented them out, I get the exact same numbers. So somebody is very clever and said, I understand Damerall Levinstein.   And they all did this like some transpose letter thing. And then they were done, right? And then they checked it in and it went out to production. It doesn't work at all. I tracked the guy down and I said, hey, what's going on here? And he was like, you know, I guess it doesn't work. So we sat down and he fixed it, right? We actually just used a G sub to pull out the down apostrophe S. So then it gives it a discounted score, right? It was actually much easier than we were making it. And cool. And this happens all the time. Whenever you find the most complex methods in your app and refactor them, you find bugs. And I've done this on many projects. And I'm already surprised, and I shouldn't be, right? Where do bugs live? Well, you can't see them in the complex areas. So that was my Damerall Levinstein example to the presentation. Okay, refactoring complex methods yields many benefits. So the first very obvious, smaller, easier to understand methods gives somebody a fighting chance when they come in there. You find bugs. This is like, if you need a way to sell this operation to your manager, this is the way to sell it, right? Like, you have bugs, you just don't know it. And we're going to find them using this complexity tool. You can see past the craziness in the code. I don't know about you, but when I see like a method like this big, I just sort of glaze over and I'm like, oh, man, I don't know what that does. It's not magic. It's not that bad. You just got to pull it apart into chunks. And you learn, right? You learn what these methods do as you try to pull them apart. You also can, so when you see into the code, you start thinking about like, hey, one dot dot, wavelength, each, why not one dot up to? Or what's all these i and j's? Like, I still got to go back in there. I think maybe rows and columns. What do you think? Because if you look up in the Wikipedia reference for Levinstein distance, they actually have like a nice little drawing of a matrix and they show you the pass through like, it's rows and columns. Why not call it rows and columns instead of i's and j's? I'm about to start a fight here. Why inject sucks? So when I first got into Ruby, I started working into it and I came across and inject pretty early on in my Ruby life. So I have a little bit of, a little bit of a sore spot with inject, right? And it was, it was like this line of code, right? Like there was some weird thing and there was something I didn't know and then they injected whatever that is. And there was M and O, okay. M, O, some crazy method. M. What's that semicolon? What's that doing? I gotta add no idea, right? I was a Ruby newbie. I didn't have any idea how this worked. And of course, this isn't actually the method, but that's how it read to me, right?  You know, it was just like, it was, it might as well have been magic. So like, you know, I kept like trying to like test it and run things through. I just couldn't figure out what the hell was going on. It was, you know, it was a one liner too. It was just, I don't know. Something to keep in mind is that new developers always join your team, right? People leave, get run over by buses, whatever. You, you get new developers and they're going to have to figure out this code that you write. And sometimes inject is great. Sometimes you're like, that's exactly what I need. It should have been 40 lines, but now it's like a couple of lines great. Other times it's like, ooh, I got, I took it from two lines to one. Good for you. But now it's tricky, right? Now it's a newbie trap.  Or that you're going to understand it six months from now, right? Right now you get it. To prove my point, here is an example that has been changed to protect the innocent. But I found this in our code and we had something like this, where we had is something and you pass into stuff and we had to compare a bunch of stuff in some of these two objects, right? And this actually went down much longer, right? It was actually about 10, 10 lines maybe longer. And it had a very high flog score. And so we were like, hey, big flog score, that's a factor. So, okay, cool. So we changed it into this. So, inject true, okay, start out with true, gotcha. Start out with, okay, so it's a true and then x.send b and y.send b, cool. And then, oh, if it ever becomes false, you're doing an and. So they're short circuit, right? So if anything's false, it all becomes false. Woo-hoo, easy, huh? No, not a flog score though. Yeah, hey, numbers, metrics, they're a guideline, right? This was actually a much bigger difference in the wild, right? The flog score was something like 50 and we got it down to like, you know, close to 15 or something. And it was great, except that it was horrible, right? Like, if I look at that top part, I know exactly what that's doing.  Yeah, easy. If I glance at this part, like, I don't know, I gotta think about it.   One thing to do, say, is to explain yourself. So you've decided that you're going to write a framework inside your code, right? You've decided that, hey, we do this thing all the time.  It's like Rails, right? Rails is complex, but now you can say simple things. That's good. However, you need to explain it, right? It's justifiable if it's framework code or the complex problem space. But I've had examples where not only is it not tested well, but nobody ever talks about it. So, you know, this dude who's real smart went off and wrote, like, well, I'll give you an example, data serialization, right? Inside this project I worked on, we had this data column inside one of the big models.  It's a serialized group of stuff, right?  And you find out there's still like everything in there. It's like 50 different fields that are being jammed into data, serialized and jammed in there.  And it was just like, I don't want to deal with this. So, like, I would just ignore that stuff, right? I would just say, like, someday we're going to refactor that. That was a mistake of the past. I'm just going to, like, do my own thing. And then, kind of by accident, just by trolling around the code one day, I realized that it was a framework. They had a whole array of, like, you could just declare some method at the top of the model and say, this is a data thing. And then it would just handle everything. And then they actually had a whole framework for inserting it in the CMS in order, in the object, right? It would take care of order. They also made sure that it got indexed by solar automatically, right? There was this whole, cruel framework that I didn't know about. I just ignored it, right? I was just like, oh, what is this doing? So I moved on.  And not just give up there once and talk about it, although that would help, right? At some sort of dev lunch. But, you know, get around, pair with people.  Let me show you how cool this is. First of all, that opens it up to criticism, right? People might say, you know, why didn't you just do this? Or everybody loans it and uses it instead of, like, rewriting it. I mean, I literally have spent days rewriting all the functionality that already existed because I didn't know that this thing existed and it just looked weird. The other thing is test it well, right? You need more complexity? That's fine. Lots of tests. The last bit I want to talk about for as far as metrics is a source control churn. So this is an interesting little thing. Like, it could mean nothing and it could mean a lot. The idea is if you have a file that changes all the time, that may be a code smell, right? You might have a controller that changes all the time, right? Why does that controller have to always change? You might have a model that has to change all the time. It might be doing way too much. That model might be sort of a God object starting to happen. And, you know, it's all about relative scores, right? If you run this and, like, something changes 96 times in the last three months and everything else is at three or four, well, maybe you want to look at that. And maybe it's benign. Maybe it's like marketing always changes the language and this is some configuration file, right? Like, oh, and marketing always changes that file. That's all right. But it could tell you something. So something to think about. Metrics, the downside. First thing I should point out is that numbers do lie, right? You know, they do. They all have an opinion. Somebody had to write this thing, right? Somebody wrote this. Whoever wrote the tool that you're using to analyze it has an opinion and it doesn't necessarily mean that the bad numbers are bad. The bad numbers could be good. That is shown in the flow example, right? You might add something that, like, has a great flow score but it's just, you know, no good. You might have something that has a very low cyclomatic complexity. There's only one path to it. Okay, but it might be huge, right? One very long path. Bad numbers can be good. This is, you know, these are things that provide information to you but you shouldn't religiously follow them. Managers and code metrics. Bad idea. Um, you don't want managers to look at code. I mean, they can look at them. They can even talk about them. They cannot pressure people. It's just bad. It's the old rule of if you want to measure anything and you really want to punish people until it becomes better, that number will become better that your code won't, right? If you really want code coverage, you can get 100% code coverage and if you're walking out with a baseball bat in your hand like, code coverage, we want it. You know, cool. Your developers will write really lousy tests that cover the code. If you get all obsessed about flog scores, they'll make things that have low flog scores except that we pull the part into like 90,000 methods that are all like two lines long and will be, you know, it's basically like sweeping the dirt under the covers, right?  Let's pull it apart into like 90 methods. Well, I don't know if you've really helped. So gaining the system is constantly a problem, right? If you, if it's not like a team decision and everybody sort of goes, yeah, I agree to this and it becomes sort of an on-high decision, then things can go horribly awry. So what can code metrics do for you? First, helps you prioritize. We know it's bad. Where should we start? Code metrics can tell you where to start. Shine's lights on unknown problems like bugs and hidden complexity. Like a lot of times when I run the flog report, the top four worst methods, you're like, yeah, I knew that. I know that method was bad. But then there'll be like a couple of methods in there and you're like, what? XML, something, something, something parser? Why are we, why don't we write a little XML parser? What?  You're like, oh, there's some open source thing we can use instead of this. You know, but the other thing is that, and I just keep returning to this, is that it provides them on a perspective, right?  Maybe you should take a look at this. It's another opinion. I wrote a plugin called Metric Foo because I was tired of rewriting the same couple of rake tasks. So really it's just a series of rake tasks that aggregates a couple of things. So it does code coverage with our code, complexity with flog and secure, source control with SVN. I don't use git. It'd be really easy if I did use git for you to submit a patch to me to use git, but I don't. So maybe I will in the future. And if you want to submit some sort of patch to let me work on that, then that'd be great. And then real stats. First of all, because it was easy, right? Just rake stats. And it's also kind of cool to see historic data. So what the goal of this is, is that you integrate this with cruise control, right? And you have it run like once a night, every night at midnight or whatever, whenever you feel like running it. And then you get historical data. So the cool thing is you can look at like, how's my code coverage? Or my complexity? Or my secure, second amount of complexity doing overtime. And so you get like all these sort of outputs for free, right? It's a pretty easy world plug-in to install.  I also added one thing in there for the flogscorp. You see there's an average flogscorp per method that I thought was kind of a neat thing to know about.  You go, I don't know. And if you write any more lines of code, that goes up. So it's not the world's greatest number, but your flogscorp per method could actually tell you something. Like if that's going up over time, maybe things are going in a poor way. Metrics are not a fire and forget operation, right? If your code is not getting better every day, then it's getting worse. And this is a fight I have with every manager I've ever had. They're all like, we'll have a tech release sometime in the future. I want to do it every day because the future doesn't come, right? If you're going to have a tech release, and you have to weigh that in your hand versus like, ooh, new features or refactoring code, like it's really, really hard for anybody on the upper level not to choose new features. So what you really want to be doing is using this every day to make your code better moment by moment, day by day. The other advantage is that you start thinking about it. Once you start refactoring bad methods, it puts you in this mindset of like, I don't want to make that mistake again. And you start writing better code because it's influenced by the fact that just yesterday, you had to take this 60 line method apart. I'm Jake Scrubbs. I work at Optiva. That's where Metric Foo is. And then I have a blog that's innovatively titled, Jake Scrubbs. Questions? Yes. Sure. Sure, it's actually on my blog. I published it and so you can... All right, thanks. I want to be associated with bad numbers. Any other questions? So when you worked in the Java world, did you ever use PMD and FindBugs and various other tools like that? You know, when I worked in the Java world, the only thing I knew about at the time was code coverage. So I used Emma a lot. And then? Yeah, Emma to do... Yeah, and that was cool. And then after I got into the Ruby world, I saw a talk by Julyesh Shah about Panopticoad, which is awesome.  Panopticoad is this really cool open source Java project which aggregates a lot of metrics, kind of like MetricFoo does. Well, so PMD and FindBugs use the spec for the language to actually go through, review your code, and find the patterns that will give you a yellow or a red. Like this is a flagrant bug. You're going to have problems, or this could lead to problems. And I was wondering if you know of anything like that. It's on my radar. It may get into MetricFoo at some point. I just haven't gotten around to doing it. But yeah, it's a good idea. Anyone else? This may be a political question, but so on the one hand, you say, you've got to have the commitment to keep doing this. You can't just run the metrics once and then drop it. On the other hand, you say, don't ever let managers run metrics. So how do you manage to pull that off? I mean, how do you, it seems like you're going to have one or the other. So you mean to have a conversation with management about like, hey, these are important, but this is kind of a developer tool, right? This is sort of an inward-facing team developer deal. So it's a value, but it doesn't help if you walk around and say like, flog scores are too much. Like Joey, you wrote a flog score of 156. That's not a helpful thing, right? It's kind of like the no blame environment, right? If you say like, oh, this code is really bad and you start yelling at somebody, it doesn't really help, right? It just makes them cower in fear and learn really bad habits. And that's, you got to have a good manager, right? Like if they don't, you don't think they can handle it. Maybe you don't tell them about it. Anyone else? All right. If we have a moment, I got bonus slides. You got two minutes. Hector was really cool. I didn't have time to talk about it, but it's another thing to vote by Ryan Davis, you run your specs or your tests and it mutates your stuff and it tells you if there's problems. So it changes, like, unless to if and when he runs the tests and says, those tests better fail. And if they don't, you've got a problem, right? So it just inserts random junk into your code and then he runs the test and says, those better fail, right? And if they don't, you don't probably as good a test as you think you do. It's not something I run like on a nightly basis, but it is kind of a cool learning tool to see if you have good tests for a complex plate piece. The other thing is Flame is a fork of FLOG with specs written around it. There was a really cool talk at Ruby Hoedown by Rick Bradley, which I watched on Confreaks, which is my new favorite site. And you can just, you know, check that out and he goes through and looks at FLOG, takes it apart, makes it more understandable, and yeah, it's on that fancy new git somewhere. Anyway, well, thanks again.