 Actually, very easily, first, you need to have the very good Rails app, which I happen to have one. And as you can see, we're currently on Rails 4.0.2. And, yeah, so what you need to do is you can go to Jamfowl and say 5.0. And this is the most important step. You want to run the bundle update Rails. Now, as you can see, we are now on Rails 5.0 successfully upgraded to Rails 5.0. Alright, I was kidding. There's actually a, I don't know if you know this, but this is actually a Spongster talk, which means I'm required to sell you something, so I'm not sure why you're here. Anyway, I don't feel great while selling my little stuff, so I thought I would sell you other people's talk instead. That actually sounds like a very useful talk. I'm sure it's a lot more complicated than that to upgrade a big Rails app to Rails 5. So if you have to leave now, that is okay. I might get fired, but that's fine. So the other talk you're missing is called, it's dangerous to go home. It is in Room 164, which is just a pause from here, I believe. But I think the main takeaway for a talk is don't use Go. The other talk that you're missing is Ragnated and Rails. The title for the talk is a single code base for web and mobile, so I'm pretty sure the talk is actually about third-walling as far as... Room 160. And finally, the last talk that you're missing for this is enough people are Urius, and I had to look it up on Urbanitioner, I think, and it'll be sent for nobody likes Python. I'm just kidding, I promise I'll stop making jokes about religion. So I am actually Guffrey. You can find me in the inference of pink code. This is my colleague, Yehuda. You can find him on the internet. Why Katzi also has a baby, and his baby's Twitter account is why kittens. We're both Rails 14 alumni. We also make a JavaScript framework for EmberJS and Flima. Yehuda is also on the Rust4 team. We work for a company called Fuller. We are hiring a senior engineer, so if you're interested, please come talk to us. We actually have a product that I could sell you, but I didn't allocate enough time for it, so I'll just put it out there at Skylight and come to you. We'll be happy to sell you from there. I guess I'll tell you one feature. We worked on this thing this year called Grades, which compares your apps' performance to all other Skylight customers. So it basically gives you a sense of where you're at with your customers' expectations in 2017. So if you want to see that feature, or if you want to come to a booth, we'll show you that. So that's it for all the Skylight stuff, and now we're going to talk about something else. So last year I gave a talk called, I don't even know what it was called. You might have had the same name as this talk. Yes, I talked about a project that we're working on called Helix. Since I imagine not everyone here has been to that talk, here is giving you a version of that talk in one extra five minutes. Ten minutes. Let's say ten minutes. Okay, let's do ten minutes. We'll see. We spend most of the time working on Helix. The thing that we're showing you instead of the talk, so this is, you get to see the slide deck for the first time at the same time. Sorry, I also have sore throat, so I can't talk, but thankfully microphones work pretty well, so hopefully that will be okay. So as we discussed last year, everyone is here today because they like writing Ruby. Ruby's awesome, but we also know that Ruby is slow. People say Ruby's slow. Most of the time, the speed of Ruby doesn't matter, since the workloads that you're working with are IO bound workloads. You spend most of your time waiting for a response from a database or something like that, instead of doing heavy number crunching. But even though it usually doesn't matter most of the time you're waiting for a database, once in a while you end up with a CPU heavy workload, and the performance actually does matter. In Ruby, you can get the best of both worlds by using C extensions. For example, when you say require JSON in your Ruby file, you get a native gem on systems that support it and a pure Ruby version on systems that don't support it. The C version is very fast, and better yet, as a user, you can't tell the difference between the Ruby version and the C version. This suggests that one way to make Rails apps faster is to write fast versions of hot functionality in C and expose the implementation through the CAPI. And in fact, this is how Ruby itself made the date library and the path name library fast a few years ago, so that suggests let's do that. So a few years ago, Sam Saffron discovered that the blank question mark method was a hotspot for discourse, and he wrote a C library called Fast Blank that sped up the operations by 20 times. This is a pretty huge one, and it was only like 50 lines of C code. That's a pretty big deal, so you might ask, why don't we do it more? Why don't we write a lot more of Rails in C? In a nutshell, the problem with writing things in C is that it's C. C is annoying programming language to write in, but it's more importantly, it is also unsafe to write C code and it's risky. If you make a small mistake, your library can cause a seg fault and nobody likes seg faults. For the most part, people prefer to write to use slow code as opposed to the risk of crashing their Rails applications. Also, while C extensions are transparent to your users, or the user of the person writing the C extension, they are not transparent to the person maintaining the C extension. They significantly add burden on maintainers and contributors because C is such a painful programming language. So at Skylight, we sort of had the same kind of problem. The first version of our agent was written in pure Ruby and it was okay, but eventually we couldn't add some features that we really wanted to add, like the important one was tracking memory allocations without blowing all the budget. You don't want to install a performance monitoring tool and suddenly have your app do you super slow. That doesn't make any sense. So originally, we thought we would solve this problem by writing a C or C++ extension, but we had exactly the same problems that I discussed before. We had maintenance burden for our engineers. We really want everyone on the team, including junior engineers, to be able to write things across our entire code base and C is not a language like that. And also, if you make any mistakes, suddenly we're crashing our customers app and actually have many thousands of customers across many environments. We can't afford for people to be reporting seg faults to us on our GitHub or our Intercom. So eventually we decided let's try writing a bit of an agent in Rust and I did a couple weeks of a spiking experiment and it was so successful the first time I did it that we pulled more and more of the core functionality into Rust over time. So what is Rust? Just like C, Rust is a compiled and statically typed language that emits very fast code, but unlike C, Rust has an advanced type system and carefully designed features which are both fun, pleasant, enjoyable to use and guarantee runtime safety. One of the slogans is if it compiles, it doesn't crash. So it might sound crazy to hear about a programming language that's in the same performance league as C, but also offering you the kind of safety guarantees that you expect from Ruby, but it's really just the same kind of guarantee that languages like Ruby offer, right? If you write a program in Ruby, you don't have to worry like, maybe I make a mistake in my program seg faults and Rust offers a similar guarantee. The cool thing is that Rust figured out how to do it without a garbage collector using the ownership system, which you should go read about if you want to know more. As a side effect, the ownership system also provides concurrency without data races, so concurrency is built in very nicely. Now, in high-level languages like Ruby, there's a tension between writing or using abstractions and the performance of your program. When you decide to use really nice features like Symbol to Proc or like mapping over an array, you're paying a cost in overhead to get the sweet features. Most of the time this doesn't matter and Ruby programmers optimize for happiness in the 99% of cases where the extra overhead is worth the ergonomic improvement that you're getting, and that's a really good trade-off. I think that's why everyone's here. But sometimes it does matter, and in Ruby you end up writing very low-level, unedited matter code just to get performance in the case of where it starts to matter. In Rust, you don't have to worry largely about the cost of abstractions. That's because the compiler can see through all your code and magically make it fast and wave. For example, if you use map.map instead of a handcrafted loop, the Rust compiler is smart enough to see that you're really doing a loop to optimize it into a loop. And actually very often handcrafted, it's our high-level abstractions, can provide faster code in Rust than the handcrafted code because you're explaining your intent very clearly to the compiler. In loops, for example, if you use map, the compiler eliminates bounce checks to make it, because it knows, oh, I'm mapping over an array, I don't have to worry about checking all the time whether the thing I'm looking up is in the array because I'm mapping over an array. So if we go back to the original fast blank example, the one that Sam wrote in C, when we ported it to Rust, we ended up with a one-liner. It actually is a pretty nice one-liner. It looks pretty familiar to the programmers. But we ended up with roughly the same performance as the C version, but with a single line of code. And by allowing you to use high-level abstractions instead of without cost, small amounts of code can result in very fast but also very easy to write programs. Now, there's an asterisk here, which is that when we first did this, we got the unique code for fast blank as one line, but we didn't talk about the boilerplate. And last year we said, well, it sucks that you have to write all this boilerplate, so we announced last year a library called Helix, which allows you to write the same thing without all the boilerplate. This is what we showed last year. We've been writing Rust code in Ruby for a long time at Skylight, but historically there was just too much boilerplate to recommend this to regular people. There might be only a single line of Rust code to write fast blank, but there were only 50 lines of boilerplate to set it up, and we made Helix to eliminate the boilerplate and let you jump directly into writing classes and methods without having to write any of the code to wire it up. At a high level, like in the 90s, there was a division between scripting languages and systems languages. Scripting languages handled orchestrating I.O. bound tasks, and they delegated to serious tools written by serious programmers to do things like sorting, grepping, set off, all that stuff. Those things were delegated to do the heavy lifting. Actually, this kind of idea of scripting languages handling I.O. bound things worked pretty well for Rails, which is largely an I.O. bound problem. Most of the time you're just waiting for the database to give you something back, and there's not that much heavy computation going on. That division historically was like you write high-level scripting languages for the ergonomic pleasant to write, but then the serious programmers write in really baroque, old-school programming languages. But in the new era in 2017, we have system languages that started to adopt a lot of the things that are nice, that are ergonomic about scripting languages. And our goal with Helix is to allow you to write the Ruby code that you love without fearing that eventually it'll hit some CPU-bound wall that forces you to rewrite everything as a fleet of Go microservices. And so the idea is you can start with Ruby and you can move your CPU-bound code to Helix if it's appropriate. Now... So that was last year, that was my talk from last year, and we wanted to watch the whole thing in about five minutes so you can do that at home, but now we're on to new stuff. So last year we had a really good proof of concept. However, it was still too hard to use. Basically we're also like if in fact, we did generate the boiler code for you, but then there's more boiler code, boiler plate around how you set up and stuff like that, that it's hard to figure out. We're also missing some very basic features like we we don't support taking in bullions or a tonful. We don't have class methods. You can only have exactly one class in the macro. No borrowing and stuff like that. And then we don't really have exception support, so the type errors were just printed to your console. Basically nothing other than demo support. So this year we decided to focus on stopping all those problems and the last year we'll work on we work on we decided to focus on making it plausible for very restricted use cases and do that really, really well. So we decided to focus on the use case of dropping in some Rust code into your Rails app. Maybe you have some background job or whatever that's taking a while and would like to speed up that code. So that's the use case that we decided to focus on and we obviously we work on the missing features basically everything work now and the reason we decided to focus on the Rails scenario is because you control the end to end environment so you can just like it is not a big deal to have to install the Rust compiler on your part, like on your build servers or your production servers so you don't have to worry about pre-compiling and stuff. So it actually works like the code we have actually works also on Rails as well but we just decided to prioritize making the Rails experience nicer. So here is the demo. It is going to be an end to end example so I guess I will show you what we're building so what we're building here is a very simple Rails app that has a text field that you can type some text in there and then you can click a button to flip it upside down so the trick is we will implement the core functionality of flipping the text and Rust inside the Rails app so Rails app is going to do all the request handling, all the buttons and forms and stuff like that but then we're going to delegate to us for the very heavy operation of flipping text. And by the end of this we're actually going to deploy this to Kiroku so let's do it. Alright so we are building this from scratch so let's delete this and start over what could possibly go wrong and so let's start by generating a Rails app we're using the latest release candidate 510 RCT what could possibly go wrong. We're not going to need active record here so we're just going to skip that to make deploying to Kiroku a little bit easier so that's the Rails app now let's go and see the Rails app and then we'll just make sure everything is working fine so this is the Rails server and as you can see it is actually running so the next thing we'll do is we'll add the Helix Rails gem to the gem file so that's the Helix Rails and we're currently at version 050 as of like this morning so when we install it we're basically going to fetch your gems and that's it so we're pretty familiar so far then Helix Rails actually is a generator so we're going to use that to generate what we call crates which I'll explain in a moment so that's up and the the so this generated Helix in create slash text run form so this is simultaneously a gem, you can see that there's a gem spec and also it is a Rust create which is basically a Rust equivalent of a gem so there's a cargo.toml so the reason we did this is to encourage you to structure your Rust code as a self-contained library just like your other C extensions like a JSON gem is a library that do a limited amount of things so this is how we recommend you to set it up for now and the next step is you can see there's a lib directory for your Ruby code because there's a gem you can put whatever Ruby code in there there's also a source directory which is the Rust convention for Rust code you can see that the generator generated a text transform class with a single class method that prints the console so let's try that out we can do that by running rickrb in the create text transform directory so when you run rickrb it will automatically compile the Rust code for you and then put you into rb with access to your Rust code so you can type text transform.hello and as you can see it is indeed printing stuff to your console it is probably worth emphasizing that it might be not very obvious but we're actually building a native extension we're calling Rust code this everything here is implemented in Rust so that's pretty cool now that we have the role of borla played down let's actually implement the text transform library we are going to do a little bit of let's just try to SM test with our spectos very quickly and install now we have our spec I'll just cheat by pasting in the text I wrote earlier in the spec directory so we have a text transform spec and it's pretty simple basically we expect the text transform class to define a flip method that takes a string and it flips it so that's what we're implementing today so just to make sure we did everything correctly we'll run the test and as you can see it's failing because we didn't define text transform.flip so that's good we'll do that so we'll need to define a method called flip and basically this is like a Rust macro which is like a little DSL for defining Ruby classes in Rust so we'll type def flip so that's like the usual syntax we're used to for defining method and the way Rust distinguish between class and instance method is whether it takes a parameter called self in this case we're making a class method so there's no self we just take a text we can take a string and then we'll tell Rust that we are returning a string here it's fairly worth pointing out that these are actually Rust types all you need to do is you say oh this takes a Rust string and returns a Rust string and we'll figure out how to convert the Ruby string into Rust and then like convert your return Rust string into a Ruby string and if the user is passing a different type like if you're passing a number for example it would automatically raise a Ruby type error for you so basically all the things that you're used to and so I'm going to paste in the implementation here it looks a little bit long but it's basically just a large table right what you're really doing is you're taking a text sorry a string which we call text you're looping for each character you're calling .ref which reverses the characters and then you're mapping each character in the table and then at the end you join them back into a string so pretty familiar syntax pretty high level you might think that using all these high level features would make things very slow but again the compiler is basically magic so if you do .ref.map it doesn't actually make an array and then reverse the array and then map it and just figure out this is what you're going to do so we're just going to do the smart thing for you out of the box and it's probably going to be fascinating whatever smart things that you might try to do and like you notice how to allocate the right amount of size and output and how to look one byte at a time and all that stuff so what we did is we ran our spec again unfortunately the test is still failing it's still saying we didn't implement text transform.flip which we clearly did the problem is Rust is a compiled language so we actually need to recompile code after making changes that being said the Rust compiler is fairly fast so you're not going to spend a lot of time waiting for things to compile so to fix this problem we run rick build and if we run our spec again afterwards then it is going to work obviously it's a little bit annoying to have to remember to run rick build all the time so we're just going to make a rick test for it which you're probably going to do anyway so this is basically a standard rspec setup you have a rspec task the key here is to make rick build a dependency of rick spec just to show that it works I'm going to go add a new test for it it can flip table and basically if you give it a table it will flip the table if you give the table it will flip it back so now if we go run the test again it's not working as expected so now we can implement this again we'll go back to lib.rs and we'll paste in two special cases at the top and now we'll go back to the console and run rick spec remember we didn't actually run rick build but then it automatically noticed that we changed some files so we recompiled and then run the spec for it and now it's passing so that's now we have fully working, fully tested text transform library let's actually use it in Rails as you can see the generator already we'll map it to apps.gem file so we don't have to do anything special here so we'll start by adding a route a resource called flips and we'll so we'll go to rouserrb and then we'll do a resource of flips and then we'll map it to the root path and we only need the index and the create action in this case so we'll do that the next step is to add a so we'll go to app controllers and then we'll make flipscontroller.rb and then we'll paste some code but basically in the index action we default the string to either URL param or we default it to hello world and then in the create action we call the text transform.flip method that we implemented in Rust so finally we will make a template for this and so you go to views and then make a folder called flips and we'll make an index.html .erb for it it's just going to be a very very simple form that has a single text view and a button and the Rails defaults for all of these helpers worked out to be exactly what we wanted so that's very nice so now with everything in place we can test it out in the browser so we're going back to the app and run Rails S and so now if we refresh we have a flipper and you can see that it can flip X, you can flip so my god and you can also flip tables so that is it so as you can see with pretty minimal effort we were able to create a Ruby native extension written in Rust using Helix not have to worry about SecFox and it's like the code is still pretty high level pretty easy to work with and we even have a test for it so finally let's deploy our app to Heroku as promised as it turns out I actually have something to sell you so you need a Heroku account in the Heroku CLI but I already have those set up on my computer so we are just going to create a Heroku app and we'll call it Helix flipper because this is a Rust and Ruby app we have these built packs manually so first we will add the Rust build pack many things to Terence from Heroku for making this work and we'll then add the usual Ruby build pack for the Rails part of things and that's it so now as it is recommending we should from get push Heroku master to do it so so get push Heroku master so now you can see the Rust build pack is downloading the Rust compiler for you automatically and we're now into the Ruby part so this is just running bundle install and downloading all the Ruby dependencies and then now we're compiling the Rust code so this is downloading the Rust dependencies and it looks like that's it launching the Dino but now that's done we can go to the browser to see it in Helix flash flipper.heroku app.com you can try it on your phone if you want to so as you can see it works and now we have a Rails app running Rust code in production on the floppy internet yeah so back to you so I want to talk about how you might want to use Helix first of all you should take a breath to realize that that was pretty cool so I want to talk about what use cases Helix is good for so first of all in general Helix is good for problems that use heavy computation and simple inputs the boundary cost of crossing into Helix is still a little higher than we would like but for problems that do a non-trivial amount of work in Rust the cost of the boundary crossing pays off pretty quickly also things like data tables, file names JSON objects are all like simple inputs so you can get pretty far with the types that we already support in Helix think about it this way the Helix boundary is cheaper and supports more types than a background job so if you could have moved the work into a background job you can make it work in Helix as an example we built a demo that counts the number of words in a text file when we measure all the words in all the works of Shakespeare Ruby takes about 3 seconds to do it Rust does it in 30 milliseconds and this example takes advantage of Rayon which is a Rust library that lets you paralyze loops so here's the example basically using what Godfrey showed you before look at the inputs are both strings the return type is a 32 bit integer the string one of the strings is a file name and just note that .expect is a Rust method that raises a panic and that can get subverted into an exception in Ruby so what you can see is we open a file from the file name then we convert it into an iterator and then map over and count how many lines there are if you use the Rayon library in Rust which is just a library that you can get off the shelf if you change into it or into part it now it's paralyzed it works across however many cores you have on your computer so that's one of the ways that we get to 30 milliseconds is that we were able to use four cores or however many we use in that benchmark another really good reason to use Helix in general is if you want to use existing Rust libraries from your Ruby application one of the main reasons why this ends up being good and important is because Servo is a web browser written in Rust Firefox actually shares a lot of code with Servo so there's a lot of production quality libraries that already deal with the concept of web content turns out we're working on a web framework so things that deal with web content are very helpful so as an example I built a demo that inlines CSS into HTML like if you're building an email thing and you want to inline you have a CSS file you have an HTML file you want to inline it together and we were able to use Servo's CSS parser and Servo's HTML parser and only needed a bit of code to glue it all together which is actually pretty cool basically like here's an example so basically we're using the CSS parser from Servo then we're looping over all the rules that we got from the CSS parser and then we're looping over all the elements and inlining things with a style to attribute if we want to and so it's kind of like writing C bindings like if you're like oh I know there's a libxml library and I want to use it now I can write a C binding it's kind of like that except it's way easier to do it you can also use Helix in a request in a mail in a background job in action cable or in any part of Rails and since mailers in background jobs tend to be more CPU intensive don't discount those use cases I think those use cases are a really good fit for Helix it also means in general you might have moved some CPU intensive thing out of the request into a background job because it was just too expensive you might be able to move some of those back if it's good for you to put into the request as well I realize in the examples we showed we didn't actually show you all the features that we worked on last year we have a website that actually showed you all the things that some of the demos that I talked about are on the Helix website and like you can play with them in a Rails app some of the features that we worked on is you can have multiple classes now you can have public private classes you can have instance methods which somehow none of the examples use you can also have a struct in Helix for storing instance dates so it's like instance variables except you tell the compiler exactly what you will have so it can optimize the access a lot better but unfortunately with the RubyC API that's basically the data wrap struct API that we wrapped in the REST macro which is really cool unfortunately we don't have time for example to show you anyway I guess we'll close this off by telling you what doesn't work so a lot of things works already as you mentioned there's a lot of use cases that you can start playing around with it if you happen to have to write problems in your Rails app however as Helix is a pretty young project that works still to be done so this basically we're trying to give you a better sense of where we're at and maybe there are some opportunities for you to contribute back to if you happen to have one of those use cases that we don't support yet so we broke down the outstanding work in different use cases the first use case is a green food project which I considered done so basically you're developing a brand new feature or rewriting a feature inside your app as opposed to rewriting something or as opposed to implementing something in a library the difference is since it is in your app you have full control over the API so you can make adjustments in your API to work around the current limitations in Helix so you might use Helix for like a CPU bound everywhere from here in a request middle-life background job as you pointed out and basically the problems with a potential for parallelism is also a good fit as you already mentioned so we currently only support for the types, I think we only support strings, numbers, booleans, the basic types like that that sounds a little bit limiting but then if you think about it because HTTP requests and background jobs actually share the same constraint where you cannot put a Ruby object through HTTP request, you can marshal it and then send the bytes across you can do that in Helix too because you already are used to working with the string constraint in the HTTP request you can actually do a fair amount even with just strings, numbers and booleans so yeah, so that's the GreenTool project use case the next use case which we're currently working on which builds on top of the GreenTool project feature list is you're writing some code in a you're rewriting some code in a public library from Ruby to Rust so basically it's like how you have JSON calling calling pure and then you need to have API compatible version in a native extension that is it needs to be a high fidelity match because you cannot change the API so that's a little bit tricky because so the benchmark we're using for this, I don't mean in the performance sense but the example that we're using here to help ourselves understand how far along we are is exit support duration so it is a fairly simple class but because there are a lot of dynamic features in Ruby you end up having like there's one method that happens to take an optional argument and we happen to not support optional arguments yet so there are a lot of edge cases like that that we're still working on so this is maybe not quite there yet but it's probably the next thing to check off the list if this is what you're trying to do today though you can still accomplish a lot by mixing and matching Ruby and Rust you don't actually have to do literally everything in Rust as I show you there's a lib directory in the crates that you can put Ruby code in there and what you can do is perhaps do basically define a class in Rust have you're lifting in there and then you can define some sugar on top in the Ruby like you can reopen the class in Ruby and then you can take optional arguments or whatever and then you can normalize that and call back into Rust and that is not ideal but it works and the long-term goal is to make all of those work in Helix so some things that you will probably notice are missing are we don't support module yet we don't support optional arguments Rust arguments, keyword arguments like sometimes you want to take like a generic numeric like you don't want to care whether it's a float, an integer or a big num or complex, rational like so there's something, yeah so that's numeric and sometimes we overload in Ruby like the same parameter maybe one of many types we have plans to make all those work just still coming along but as I mentioned you can always normalize those differences in Ruby and call call back into Rust so that's that and then reopen is a little bit strange but a lot of echo support stuff reopen in core classes so it kind of works now but it's not amazing yet and we have some work to do there and this also is very easy to do a wrapping strategy, like a mix and match strategy so you can do a reopen in Ruby the key is you want to the parts that make sense to move in Rust is the algorithm have a lifting part so you can still do a lot of that in Rust and you can use those code in Ruby like we did in the Rails example I guess I'll just go through Rust very quickly because we're running out of time so shipping to production as you can see we actually kind of made that work with help from Terence like it actually works on Heroku and stuff the things I'm missing is like it works as long as you have to have a Rust compiler on the server but we don't have documentation for how to do it so if you're interested in figuring out you might want to contribute some documentation there and let's see binary distribution is interesting so if you are a library author and you want to use Helix you probably want to make sure that people can install your gem without having a Rust compiler on their computer so this is what we mean by binary distribution there are some other gems in the Ruby ecosystem like the thing that wraps libp8 does it basically and skylight we do it ourselves basically we have to make this work in a way that is automated because we need it ourselves we already have ways to make it work but we need to extract that into open source version you basically precompile the binary for all the major platforms there are like a handful of them and then people can just download when you gem install you can just download that binary and it works so that we still need to work on tooling to make it possible we know it is possible because so you could have said we actually do it in skylight and then there is some non-traditional use cases like mobile web assembly and Ruby and performance parity with C as you mentioned we are a little bit slower than C right now so we need to have some good benchmarks to figure out where the overheads are the long-term goal is we want to be on par with the equivalent C native extension that you would write but when we say a little bit slower than C Ruby is here so if you are moving code from Ruby into Rust and it is almost entirely the boundary cost that is more expensive Rust itself is very competitive with C so if you are treating it like a background job you don't have to worry about it all if you have a chatty API you should then you want us to fix this problem right so then finally there are some miscellaneous features and quality of live improvements we want to support more types we have the protocol down so it is quite easy to add more types we just haven't gotten around and you just have to decide what does it mean to convert a hash in Ruby to a hash map in Rust what is that we are quite reliant on the Rust macro system for the DSL so when you have syntax error in the macro the errors are quite brutal we are working on that if that is the kind of thing that you are interested in we should talk more and maybe you can help there too so that is basically it I guess I kind of ran out of time so here is the website for everything else that I didn't have time to cover usehelix.com you can go look at it and we are I think we have this setup in the skylight booth so if you want to come play with it or chat with us we are here today and tomorrow the website usehelix.com is a Rails app all the demos are written in Helix in the Rails app so if you go look at the repo for usehelix.com the source code for all the demos that we show today are in there and they are the same code that is running on the website a lot of you are probably looking for opportunities to contribute so we deliberately sprinkle up typos in the website the roadmap webpage is a more detailed description of what we talked about and the issues that everything is in ran out of time but this is the best slide thank you very much