 This is Charlie, we work at Red Hat, Red Hat's generous enough to allow us to work on JRuby. We co-lead the project and it will be no surprise that we're going to talk about JRuby. The first thing JRuby is Ruby. It's just an alternate implementation. If you've written any Ruby code that runs in CRuby, you should just be able to run it with JRuby. Sometimes people get confused after our talk, as we'll mention Java several times, but if you never use any of our extra features, just know that you can run your Ruby code and it'll work. So you can think of Java as just an implementation detail, like C is an implementation detail of regular Ruby. So we just released JRuby 9-1-14 last week. It's compatible with Ruby 2-3, and you need Java 7 or higher to run it. 9-2 is going to be Ruby 2-4 based, and it's actually sort of feature complete now, but we want to do some things. So we're thinking about Christmas, but as you know, CRuby also releases on Christmas, and they're only putting out Ruby 2-5. So we're one point behind. Okay, so let's talk about why we implemented Ruby on the JVM and why that's useful. Both of these projects, they have their people. Sometimes those people are in both teams. And we go and try to target where we want to run it, like Mac OS. But in JRuby's case, we mostly just target running it on top of Java itself. We have this little thing off to the side for when we need a little more power to get around some limitations in Java. Now MRI pretty much has no dependencies, so they have to go it alone. And we're going to argue why we like going on top of Java better. So this isn't a criticism of how CRuby is implemented, it's just a different perspective. They have to have all the expertise they need to go and make a fast, efficient version of Ruby. But we have this army of extra people on our project that are working on Java. They're experts, they know what they're doing, and they give us all this stuff for free. So we have choices of multiple garbage collectors we can use. There's a fantastic JIT that does all these crazy optimizations to our code. Java is based on native threading, so this is like one of the big, big differences between JRuby and CRuby is that we have native threads. So we can light up all the cores. There's lots of tooling for us to debug problems. And it's cross-platform. And when I say cross-platform, I mean JVM is literally everywhere. From normal platforms to IBM mainframes, we actually have a user on an IBM mainframe. Android microcontrollers, you name it. So JRuby actually gets a lot of reach just by being built on the JVM. Java also compiles to this intermediary format of Java bytecode. Once you compile something once, you can take that format and run it on Windows or run it on a microcontroller and whatnot. So it's only compiled once. So these are JRuby Java native extensions, so they have a little bit of Java inside them. JVM authors compile it once. They publish the JVM. Now you just install the JVM. You don't have to have a Java compiler tool chain set up to install your JVMs. And it's just going to work on Windows, which is sort of an issue with native C extensions that they typically don't. Maven is the equivalent of Ruby JVMs for the Java world. And there has to be more than 47,000 libraries in there. But there's tons and tons of useful libraries, like the case that I've seen on a few occasions is someone wants to go and use Pran for PDF generation, and then at some point, they get stuck. They needed to do something, and Pran's not working. We have a feature in JRuby that allows you to go and load Java libraries and pretend the Ruby libraries. And they'll just switch over to iText, which is some ancient, crusty, but super mature PDF generation library, and they solve their problem. You can also call multiple languages. There's many languages now that target the JVM. So you can sort of use the right tool for the job. You can maybe write 80, 90% of your app in Ruby, but if there's something really good with transactional processing or immutability, you could go and call out to Clojure. And they both run in the same VM, so they still use the same garbage collector. You can look at tools to figure out how much memory is being used by each, and so forth. Oh, yeah, and every language always has its own libraries. So this is just additional dimensions of options, so if you need to hook up to some commerce API, there might be something written in Scala that you can just use. And I said you could go and pull in Java type and access it as if it was a Ruby class. So I'm going to turn things over to Charlie to demonstrate. See if we can do a quick little demo here. All right, let's see what I got. All right, so all the typical Ruby installers can install JRuby. All you really have to have prerequisite-wise is a JVM on your system. Is there any way you can move that up? They can't see the bottom part. Okay, let's go like that. Okay. And of course, we're JRuby, so we put a J in front of everything. We have our IRB, which is JIRB. But as Tom mentioned, we can pull in any Java classes at any time we want and use them as if they're regular Ruby code. So let's do, let's see, frame equals JavaX.swing.jframe.new, okay? So we have a frame, a window frame. Let's make that visible. We can see it here. There it is. It doesn't look like much right now. Let's fix that here, frame.set, size 3, got boxed into a little window here. All right, there we go. So now we have a 300 by 300 frame, and we can just keep doing this. So let's add a button to it. equals JavaX.swing.jbutton.new, press me. And that set underscore size is set capital size in Java. We just allow a shorthand syntax to make it look more like Ruby. Maybe it's a longhand syntax, it's an extra character. All right. We'll lay it out again so we can see it. Now we have our button. Maybe we can keep doing this. Of course, we can respond to events from the button in Ruby. And you'll notice this would have to take an interface or implement the action listener interface and pass it in here. Add action listener. But in JRuby, of course, we put a lot of niceties in here that make it feel more like Ruby, so we can just pass a block. Button.txt equals, yay JRuby. All right, we go back to our window, and of course it works. So this is a really fun way to get to know different libraries that are on the JVM. As you see, none of this really looks like Java except for when we import the package and we actually pull the class in. But this isn't typically how you would want to build a GUI application. So we have another GUI library on the JVM called JavaFX that we have been using to basically wrap with Ruby and build a better way of writing JavaFX apps using Ruby code. Let's go in the demos. Okay. Let's see. What do I just run this here? That's right. All right. Go ahead. I kind of set this up a little janky. I should have probably required that instead of did it all in command. Oops. No, that's not going to work. It seems like it's... No. Oh, now it's working. Whoa, hello. Hello. I'm back. It's always exciting to see a live demo network. Yes. Oops. That didn't actually change. All right. Bear with me for just one moment. So all those classes in Java, it's really hard to tell when you add just a few extra lines in a library, you can go and wrap those types up and you have no idea that you're using Java until maybe you see a backtrace. The dreaded backtrace of JRuby sometimes includes Java. That's strange. Okay. Well, so that one's not going to show. We'll go back to the slide here. That's all right. I sort of have a picture. Okay. Okay. So JRubyFX is a gem that we wrote that wraps the JavaFX GUI library in Java. It basically has two modes. One has this DSL builder, which is really clean, but it doesn't scale for very long. So people switch to this model view controller format and involves XML. Although we won't look at any XML because we don't need to. What people do is they use this application called scene builder. So there's a canvas in the center. On the left side, there's a palette. You can import custom controls. There's tons of controls like these gauges. This one guy made like 55 different kinds of gauges that are total eye candy like this. Once you lay that onto your canvas on the right, you get properties and you can customize how it looks. You can give it a name. So I gave this left one gauged and the right one slider. If they had the demo worked, when you move the slider up and down, you would have saw the gauge go with it. It's a pretty simple demo. But then when you save it, it generates some XML, but you don't have to look at it. Then you just go and write a little bit of Ruby code. You load that XML and then we'll just look at a pretty tiny app. Slider, which was the name we gave to the slider. We add a listener. If anything changes on the slider, we just assign that same value to the gauge and it just moves around. So it's pretty slick. Maybe something a little more realistic. There's a product called Breakman Pro. It does static analysis of Ruby on Rails applications, probably just Ruby applications in general, but it's an intense user interface. It's huge and it's super polished and it uses JRBFX. All right. So the other things that we get from the JVM, of course we've got GCs and Jits and whatnot, but we also have some excellent tools that we can use. So for example, we have parallel GCs. We have GCs that run concurrent with your application. We have real-time GCs, tools for analyzing the JIT, watching the heap, looking for memory leaks and so on. One of the best ones and one that I use on almost the regular basis, on almost every daily basis is Visual VM. This provides a graphical view into what your application is doing. You just connect up to a running application. You can see threads executing. You can see the GC running and so on. Here's two live views of Visual VM. On the left, we are just monitoring the basic aspects of the JVM, how much CPU is being used, how many threads are running and so on. On the right, we have a live view of what the GC is actually doing. So we could watch and see if garbage is getting collected. We can see if it's leaking over time. We can actually see if we're gathering up old objects versus just a bunch of new garbage. All of this is just running on a regular JRuby application and you can monitor these applications in production or in development or whatever using lots and lots of different tools. This one, Visual VM comes with OpenJDK. On the right there, the plug-in is actually the Visual GC plug-in for Visual VM. Here's another view of Visual VM actually doing some method profiling, monitoring the JVM to see what code is taking the most amount of time. And over here on the left, we have what we use for our internal names and we pass Ruby code into the JVM to be jitted. We have our modified names here, our mangled names, but still pretty easy to figure out. We've got the RBTBM method. We've got Minimum, Add, Delete, Fix Up and so on. And then we can see exactly how much time is being taken for each of these methods. So we're profiling Ruby code using Java profiling tool. And with a little parsing by eye, you can figure out exactly what your Ruby application is doing and again, hook it up to a development or production or whatever. So we've also been working on optimizing Ruby and improving our performance. We have the JVM's JIT, but it turned out over the years that the JVM JIT is really good at compiling Java code. There's certain aspects, certain patterns of Ruby that it doesn't know how to optimize as well. So what we've been doing to improve that is write it, we have our own interpreter. So we run code through our interpreter. We profile the code over time and see what it's doing, try to figure out the types and the paths that are being followed. Then after we've gathered that information and run for a while, then we JIT compile down to JVM byte code. The JVM also has a feature called Invoke Dynamic, which allows us to do dynamic calls, constant lookups, global variables, all those sorts of things in a way that the JVM will optimize much better. And so by using all of these features together, we're essentially optimizing Ruby a little bit before we send it to the JVM to make sure that it can optimize it the rest of the way. We're also starting to utilize a new JIT that's available for the JVM. It's a pure Java JIT called Grawl. And I've got some numbers here to show how that's working. So let's talk performance on a couple little benchmarks here. So this is a benchmark, basically just a bunch of blocks and loops, sort of like you would implement a array each if you were going to do it in pure Ruby. That's essentially what this is benchmarking. So you can see with J Ruby and JIT, this is how much faster we are than Ruby 2.4. Without doing any tricks, the JVM has a little bit of trouble seeing through these blocks and optimizing them. We are still faster than C Ruby, but in this case, we don't get as much of a benefit from the JVM. If we throw invoke dynamic in, that helps a little bit. But blocks and closures are still a pattern that the JVM is not really familiar with. They've only just recently even added closures to Java. So getting those to optimize takes a little more work. But Tom and some of the other folks that work on the compiler have been working on doing our own inlining of those blocks so that we can optimize them like Java would like to see and make it faster. And that starts to make a big difference for performance. Now we're starting to get closer to five or six times as fast as C Ruby. If we throw invoke dynamic in here, we're eight plus times faster. And then actually we can even utilize the Grawl JIT a little bit to push us up a little bit more. Now where Grawl really helps is when we're doing numeric algorithms. So on the right here we have a Mandelbrough benchmark basically, and we'll see how much faster we are. Now I say that we do get a big benefit from JVM's JIT and invoke dynamic, and that is pretty good. Three times faster on a numeric benchmark when every number we create has to be another object. Unlike in C Ruby we can't just have special pointers on the stack, but the JVM still can't see through all these objects. It's going to create these objects. It's going to garbage collect these objects. The benchmark just doesn't run as fast as we'd like it to. If we throw Grawl in here, give it some hints about how to optimize numbers, how to make the objects go away, then things really start to pick up speed. And this is just early experiments basically saying optimize our numbers as if they're just regular primitive numbers on the JVM 23 times faster on this particular benchmark. So don't walk away from the slide thinking that J Ruby is going to be between nine and 29 times faster in a few months. The left case is something that the JVM just doesn't do particularly well for us, which is calling a method with a block. But it is a big problem for us, so this is a big solution. Yeah, absolutely. Here's another one that we like to show. This is a benchmark of two red-black tree libraries. At the top we have MRI, C Ruby running the pure Ruby red-black library, two and a half seconds or so. Then MRI with the C extension, which often is done for performance, move that library into a C extension, it'll speed up. But J Ruby here, with all the tricks that we're doing, we actually run the regular Ruby version of the red-black tree library faster than C Ruby with the C extension. So we're doing a lot of work in trying to make Ruby run as fast as possible on J Ruby. And then finally, of course, concurrency and parallelism. We do have concurrency in C Ruby, but it only runs one thread at a time. There'll be multiple native threads, but they're all blocked on the one global lock, right? In J Ruby, that's not the case. So you will be able to light up all the cores in your system, you'll be able to have one J Ruby process, take the entire applications load, all of the concurrent requests you need, and so on. You really do get both with J Ruby, and we've worked very hard to make this work well. So how does all this help? Performance, concurrency, whatnot. Why would you want to make a move to J Ruby if you're happy with C Ruby? Well, MRI requiring a process per concurrent request, even with copy on write, it's gonna take up more and more space, depending on how many requests you need to have. After you get past three or four MRI processes, individual listeners for your application, J Ruby will generally be using less memory, potentially a lot less memory, and still only require the one process to run the entire application. This is a quote from a friend of ours. He wanted to remain nameless, but they had a large application that moved from 40 extra large instances on EC2 down to 10. Saved them tens of thousands of dollars a month, hundreds of thousands of dollars a year, just by making a move to J Ruby and a few adjustments to the application. So this really does pay off if you make a move. All right. So let's talk about J Ruby on Rails. You know, we've been running it since 2006. Lots of people have deployed Ruby on Rails on J Ruby, but around the time Rails 5 came out, we were working on two, three, and two, four support. We just fell a little behind. And actually, almost all of Rails passed all the tests, except for one, ActiveRecord. So running Rails without a database isn't very useful. So let's talk about ActiveRecord JDBC and how we've decided to kind of address the fact that we fell behind. Oh, but before I do, I'm gonna talk about compatibility. I don't know how many people have worked on compatibility projects, but they're a lot harder than they look. So here, just for this project, we'll just look at some of the details. So ARJWC is the marriage between ActiveRecord and this API in Java called JDBC. It just gives you the ability to talk to different databases using the same API. So obviously we have to be compatible with ActiveRecord. But it's a JRuby project, so we have to be compatible with JRuby. We have bugs, we change versions, we change compatibility. JDBC, as a standard, is like 20 years old now. It changes over time as well. So we have to worry about that. We go a little further. Well, obviously JRuby is trying to be compatible with Ruby. Ruby changes versions, it has bugs, so forth. Java is also changing. In fact, Java 9 came out two months ago and there's been a lot of activity to try to make JRuby work well on Java 9, but we can just keep peeling this onion back, because we have to actually talk to databases and databases are versioned. They all have little one-off features that you have to support and those features have bugs and it's a lot of work. So if we look at our previous version of ActiveRecord JDBC 1.3, we were supporting versions JRuby 1.6 all the way through 9.1 that goes back like five, six years. It was generating Java 1.5 bytecode, but I'm not sure it actually ran on Java 5, but it was supporting multiple versions of Java. I think it supported every version of ActiveRecord from two up to four to. I saw a line of code for JDBC that was making a check against a version of JDBC that was 10 years old and we supported at least 10 databases, all in a single project for a single release. And the result of this is it's too much to support. And it required a lot of domain knowledge. This is like one of my, I crack up every time I see this, can I remove this line now? That's like the classic problem is you have a line of code, you have no idea why it's there. You have a lot of tests, but how good are your tests, right? Sometimes I think our tests aren't that great. So you have this question and the more dimensions of compatibility you have to maintain, the more this question is harder to answer. We actually made this mistake once before and it was for JRuby 1.7. You could pass dash dash 1.8 and JRuby would act like it was 1.87. You could pass 1.9 and it would be 1.93. 2 and it would be 2.0. And our code base started to get pretty messy. Over like a two year period where like this is a horrible idea. So we're no longer doing that. And that's kind of a clue to our solution here. So now we have a version 50 which will support AR50, 51. 51, I think you can see the pattern here. We're only supporting, well, we're supporting the big three, MySQL, SQLite and Postgres, but we're also gonna support Microsoft SQL server. Four hours ago, I released version 51. So this is sort of a just in time development pun intended. So here's one use case where I think this is gonna work out for us. This was sort of a best case, but MySQL, we were able to get rid of about 80% of the lines. And one of the reasons why we could do this is we're effectively taking a copy of ActiveRecord and we kept mutating it so that it would work with every version of ActiveRecord. But now that we only support one, we just call into ActiveRecord so we could delete all that code. 160 lines of this last 284 is some connection processing options. So that probably is mostly gonna go away as well. But the neat thing is for version 51, I had to add a three line method for all the tests to pass. And then a three line comment because I shouldn't have had to add that three line method but hey, everything passes, ship it. And as I said, we mostly pass all the tests. We actually are doing better than this looks because there's some tests that, they're not actually broken, so. I think you mentioned there's a couple tests with JRuby exceptions that no longer need to be exceptions now. So little things like that that we just have to clean up. It's looking for a string zero but now we return number zero because we're using ActiveRecords code. So we just need to work with the Rails team and try to push more and more of our Ruby code into reduce our footprint. And I think this is gonna totally work. I wanna give a couple of special thanks. One is to Carol. He's been working on JRuby for years and he is pretty much was the sole contributor to ActiveRecord JDBC for several years. We'd get pull requests and stuff too but he did a tremendous amount of work. It's like mind blowing that he could make all those versions work together. And he's helped us a lot with the Rails five or two. And then I'd like to put a shout out to Final Sight. They've sponsored Rob Widmer who happens to be sitting over there. Raise your hand higher. Thank you very much. Thanks. So he's been doing the PostgreSQL work and once that's finished he's gonna be doing work on Microsoft SQL server. So great. So let's talk about getting up and running on JRuby. Hopefully you are close to being convinced now that JRuby worth looking at. The next question we always get is how do I do this? Well, it's pretty simple. It's just a Ruby implementation. So setting up JRuby is pretty simple. I'll show you the process for that in a moment. You go to your application or your library and bundle install. If that works, you're pretty much there. Like it's very likely that everything's going to work from that point on. For Rails, a database application setup, you'll migrate your data and do whatever you're supposed to do to get the application up and going. If something fails here, it's probably going to be our fault, something we should fix. But usually if you're able to bundle install an application that's all you're gonna need to do. That's the only challenge. So setting up JRuby. Of course you can go to JRuby.org and download it. We have installers for Windows as well. Or you can just use any of the typical Ruby switchers. So JRuby requires at least Java 7. JRuby 9.2 will require Java 8 or higher. So RVM install JRuby or CHRuby or whatever else you're used to switch between Ruby implementations. Most of the Linux's have packages and they're fairly up to date lately. They've been doing a pretty good job of keeping up with our releases. I mentioned that we have a Windows installer. Anybody on Windows? Yeah. But it works. That's one nice thing about JRuby. Because we don't have to compile extensions because we don't have a lot of C code, JRuby installs pretty much the same on all platforms and the gems will just download and install. There's no need for compilers and other stuff. And it really is as simple as just adding it to the path and then running JRuby, or running our version of the Ruby command. Setting up your app. Like I mentioned, bundle install is gonna be the biggest thing. What you're most likely to run into is C extensions that don't have a JRuby version. The vast majority of gems out there are pure Ruby but there are some C extensions. Some of them have been adapted to JRuby so they have a Java or pure Ruby version and some haven't. And I'll show some examples a little bit later. RakeDB migrate, again, most likely it's gonna be some edge case that we didn't cover an active record, just something for us to fix. So come talk to us, we'll get it fixed up and get you on your way. And then run your tests. Make sure your application works. Hopefully by this point, everything is generally functional. And again, any tests that don't pass or don't behave like C Ruby, that's our problem. Come talk to us and we'll fix it. So what about deploying JRuby? We've made the move to a JRuby-based system and we wanna deploy it. Well, the typical Ruby ways of deploying applications all work just fine with JRuby. We recommend Puma as your small server. There's also a project called TorqueBox that does more of a larger enterprise sort of scale server with a bunch of additional features. The standard deployment mechanisms work like Capistrano or deploying to Heroku. All the different clouds have some sort of support for either Java or JRuby. Pretty easy to get up and going there. And then there are some tools for basically packaging your application up. You can basically turn a Rails application with JRuby and all its dependencies into a single jar file and just run it on a production server. You don't have to have it exploded on the file system. You don't have to do all your installs there, bundle it up. Best way to deploy a Ruby application ever. And of course, the Java style way works for all this stuff too. TorqueBox is actually a Java EE server and so you can deploy there and you can have all those features. You can use Warbler to create a war file, a web application archive that you deploy on any Java server. But again, we're Rubyists here. We typically would just recommend doing the Ruby style. Just do what you do today as far as deploying applications. If you wanna know more about getting your application deployed, this is an excellent book from Joe. Joe Kutner, he works at Heroku and he covers Heroku stuff in this as well as all these other different ways of deploying Java application servers, JAR files, little self executables. Lots of great information in this book so definitely go pick that up. So after we got all this work done and active records caught up now, I thought I would try and take a couple applications and do this process, go through migration and see how it works. So the first one is Redmine. Most of you should be familiar with Redmine. It's a pure Ruby, largely pure Ruby, project management app. Basically like a forge, bug tracker, wikis and so on. It's Rails 5.1 base, so they've been keeping up with Rails as well. And this had about 58 gem dependencies. A stack of them had native extensions. There were C versions of them. So Redmine on JRuby, well the good news is Bundle install actually worked. All of the C extensions that Redmine uses worked fine. They have JRuby versions, they installed no problems, didn't have to modify anything in the gem file to get it going. The database migration also just worked. That's using the 51 version of ActiveRecord JDBC. I was able to load the database up, put all the default data into it, and start up the application and actually run it. So it does work. Redmine on JRuby out of the box worked perfectly with the new adapters. That's awesome, we're really excited about that. And again, like Tom said, this was after we updated the 5.1 MySQL driver for JDBC with only a six line change. We're good to go. So if you do run into issues, you have a library that doesn't work right, usually it's gonna be something we can find and fix pretty quickly. So I thought I would take it up a notch and try something a little bit larger and more complicated. Mastodon is basically like an open source Twitter, sort of clone decentralized Twitter that you can do all the same sort of things on Twitter. This had lots and lots of native extensions and some of them did not have JRuby versions. Let's see what we've got here. Those slides are out of order. Yep, Rails 5.1 based, about 100 dependency gems. So this is almost twice as large dependency wise as Redmine. And it's definitely a bigger challenge. So the good news for Mastodon was that all of these, all of these different libraries actually did have JRuby versions. Several of these I've never even heard of. So these are other people that are doing the work to make them supported. All right, so that's pretty cool. The bad news, unfortunately, was that there were a bunch of extensions that didn't have JRuby versions. Binding of Caller was only in development time, so that's not a huge deal. There is a JRuby, it's possible to support this in JRuby in development mode, but we haven't gotten that out yet. The Rainbow Library had an extension, but the unreleased 3.0 version no longer has the extension. So as soon as this is updated and that's released, Rainbow's not a problem anymore. Hamlet is a native Hamel parser. You could just use Hamel here and it would probably run just as well on JRuby. Charlock Holmes is a file encoding detector. So it uses a character set encoding information to figure out what encoding a file actually is in. This could easily be done with existing JVM character set logic. What else, CLD3, this is a wrapper around a library, could easily be an FFI wrapper. OJ, we have a mostly working port of it, that we're going to get to the OJ project and get it released. We'll have to do a similar process for the OXXML, FastXML parsing library. Fast blank, I did a very quick port of it. It was only about 200 lines of C code, so I made a JRuby version and sent them a pull request. You'd be able to swap something in for OJ anyways. Yeah, you should be able to swap something in for OJ or OX and just use a different XML library or whatever. IDNRuby was another one with a very little code, should be an easy port. Nocogumbo reps the Gumbo HTML parsing library, of that could probably be FFI also, or use a JVM library for it. And of course OpenSSL, we have an OpenSSL library, ours is called JRuby OpenSSL. And really the only change needed would be to, say, use JRuby OpenSSL instead of CRuby's OpenSSL. And in the gem file, you can just put a platform comment and put MRI or JRuby, and you can have both of them in your file and just build for whatever platform you want. And Bundler supports having both platforms in the same gem file lock, so you can run on MRI and then deploy on JRuby if you want, or develop on JRuby, whatever. So obviously there's lots of areas where we could use some help. There are lots of non-coding tasks that we have in the JRuby world, triaging all of our hundreds of open issues that are almost certainly not still issues, updating Wiki, documentation, so on, looking for, we've had several typo and small documentation PRs come in recently, and that's awesome. We love that kind of contribution too. Just participating in the community. Be on the mailing lists. We have the JRuby list that's actually hosted along with the Ruby Talk list on the same server, but talk about JRuby on the list, ask your questions, talk about JRuby on the Ruby Talk list, and so on. Tell people about JRuby. Get out there and just let people know that you're trying it out and what you like and maybe what you don't like, but spread the word. If you want to write Ruby, you actually can contribute to JRuby using Ruby code. We do have a growing kernel of code that's internal in JRuby that actually implements parts of Ruby using Ruby code. Mostly a little additional methods that came in in Ruby 2.3. If there's something that's missing or if there's a bug that seems like you could fix it with some Ruby code, that can go into a pull request and we can put it in JRuby and get it out in the next release. Reducing issues, so people will provide lots of interesting bug reports from strange things that have happened to their application, but we don't often get a good reproducible test case, so if you can go in and help us come up with a test case that reduces it down, that will speed things up as well. Let's see, what else? Yeah, so we're not really concerned about the performance of Ruby code that goes into JRuby. Performance is usually gonna be fine, but we just want it working first, so if you want to contribute to JRuby using Ruby code, that's just fine. Of course, you can also help us by writing Java code. Java's come a long way in the past 10 years, it's a much nicer platform to build applications on these days, so help us with missing extension libraries, help us patch core classes that aren't behaving properly and so on. If you want to get into the deeper parts of JRuby internals, we're happy to help you with that, too, and I'll show you where the compiler bits are and all the other pieces. All right, so to close this out here, we'd like to thank a lot of the different companies that we've worked with over the years, folks that are running JRuby in production. Some of these are very exciting, like BBC News, all of the election results for any election in the UK, comes through on JRuby. That's actually a JRuby-based application and so on. We're very happy for our users and we're very proud that we've got such great companies out there using JRuby. And I think that's all we have today. Again, I'm Charlie and this is Tom. We're happy to have you here. We hope you try out JRuby and I think we've got time for a couple of questions. Right, so what's the trouble with supporting all of these different databases given that JDBC should be a common API around all of them? Keith, have you used JDBC? Okay. Yeah, I know every database has so many wrinkles that you end up having to write a fair amount of code. And then, like even writing the code initially isn't the biggest problem. It's what happens afterwards when you make a small change and then you have to test 10 databases to make sure that everything's still working. Right, and they have different ways of mapping types, different types in their system. Small differences in SQL grammar and so on. So, by leveraging what we've got in ActiveRecord, we're able to get a big bootstrap, a big jump ahead on MySQL, SQLite and so on. That can be done for these other databases but it's going to be all on us to support them. So, there is a call out if you're really interested in a database that we're removing support for in this new model, you can probably get it added back as long as you commit to it. All right, that beep tells me the time to stop. So, we're going to stop. Thank you very much for coming. Grab us around the conference. Do you have any other questions?