 So, this talk is basically about a project that I announced a long time ago in March. And I've been working on it not as full-time as I would have liked, but I'm finally at a point where I feel like I can show off some of what I've been doing, so I'm going to be doing a little bit of that today. But I think more importantly, I'm going to talk about the architecture, what parts of what I did were hard, and what sort of the scope of the project is. So, first of all, we have a logo, it's cool, awesome. So we have a logo now, this is cool, I'm pretty excited about it. It took us some time to get this straightened out, and talk is over now. Okay, so we have a logo, and believe it or not, little things like having a logo really impact how much it feels like a real project, so pretty excited about this. So I want to start by talking about sort of how we got to here, where we are today, and how that impacts what I've been working on. So first of all, in case you don't know what Tokaido is, I announced a project called Rails.app, which I renamed to Tokaido at some point along the lines. And the tagline of Tokaido was, let's make Rails and all is 10 easy again. And interestingly, this was very controversial. And the reason why it was controversial was that a lot of people who saw my proposal did not think that what I was tackling was a real issue. So this is one comment that someone said as much as I like Huda, he's tackling a non-issue here. Here is a more colorful, so installing Rails on a Mac is largely trivial, it's five shell commands depending on the current level of breakage of RubyGems, that's a different story, write a tutorial on your blog. And I think what was kind of interesting about this for me, this is basically how I felt. What was kind of interesting about it for me is I don't actually, my full-time job is not really building Rails apps, I write a lot of Ruby code, and I write a lot of Rails apps, but I write a lot more JavaScript code these days. And what that ends up meaning is that I end up building new Rails apps on new systems for new clients all the time. So I don't bootstrap a Rails system and then use it for two years, so all the pain is in the past, every few months I have a whole new system I need to bootstrap. And so it's very clear to me that when Homebrew is doing a weird thing or Apple shipped a new version of GCC or SQLite.h is not on my system or this stuff happens to me as a relatively advanced user. And another sort of interesting anecdote, there's a guy on TC39 who is not a Ruby guy at all, TC39 is the JavaScript committee, but he's a badass JavaScript guy. He has a, I think a PhD in computer science, works on TC39 and he was trying to use Octopress, and he offhandedly mentioned to me at one of the committee meetings like, I can't get Octopress working, it used to work and I'm trying to edit my blog post and it's completely not working anymore. And I was like, oh, I'm sure I can get it working, ping me a few weeks later, he pings me on IRC, and he's like, oh, I'm trying to get Octopress working, here's the error, and I'm like, oh, I'll take a look at it. And like two hours later, he was like, I just give up entirely, I cannot do this. So as much as you as a programmer who at some point went through the pain and got everything working and now your system works, so you think everything's great as much as you feel that way, in practice, huge numbers of people, including I am guessing most people who feel like it's not a real problem, go through a fairly significant amount of pain. And to make matters worse, I know a lot of people like Homebrew, I use Homebrew. Homebrew is not exactly a repeatable, reliable package manager. So lots of little things about how Homebrew work and change over time could impact the five quick steps that you just pasted into your terminal. And in fact, do impact that, especially when you take and do operating system upgrades into consideration. So here's sort of the overview, I'm not gonna talk about any of these items because I'm gonna go into them in more detail. But the overview of what it ended up meaning to build something like Tokaido was basically thinking about dynamic loading versus static loading. The fact that Ruby normally builds binaries with hard-coded absolute load paths and how to make statically linked stuff in the first place. And then somewhat importantly, and this is something that I think people just forgot about when they were originally thinking about the problem, is how do you set it up so that the steps that you say that work in October 2012 will probably work in October 2013, right? How do you make it so that every single time there's a new release of Ruby, you don't have to go dig up the script and figure out again how to do the entire thing from scratch. I mean, that would already be better than what people are doing today, which is that every single Ruby user has to do it. But still, it would probably mean that we wouldn't get timely updates of Tokaido as there were new patch releases because someone would have to go figure out what's going on with Libyaml, what URL was that at that again, etc., etc. So for me, the last bullet point turned out to be more of a headache and I think more of a triumph at the end than a lot of the other parts. So let's start with something simple. RequirePsych. In between those two lines, there's a lot of stuff going on that you don't see. But something simple like this, you requirePsych and you get back a true and now you have a psych miner. So what exactly is going on? How many people here know what dynamic linking or dynamic loading is? And how many people know how it is different from static linking or static loading? Okay, so like half the room, so that's already a good step. So OS 10, first of all OS 10's dynamic linking and dynamic loading are not the same as the dynamic linking and dynamic loading on Linux. They're similar, they bear a family resemblance, but I'm going to show there are some differences. One interesting thing that OS 10 provides is there's a lot of environment variables you can set that will dump out information about what's going on. So that actually turned out to be very useful for both figuring out what was going on in the first place and also figuring out whether what I had done to improve the situation was actually successful, whether it was effective. So one thing you can do is when you run a Ruby, when you run any program, you can say print out all the dynamic libraries that are being loaded. And what you can see here is that libyaml02.dialib is being loaded dynamically. So there is a libyaml dialib that's somewhere in the system and a dialib is basically just a bundle of executable code that instead of being hard coded into your executable inside of Ruby, it's actually just sitting there on the side in the system somewhere and the system will go find it. I'm not going to talk at all about how the system actually finds it, which again is a little bit different from how Linux works and has its own share of craziness. Mainly because I just decided I'm not going to bother with this at all. I'm going to eliminate all the failure scenarios that come from the craziness around dynamically linking code. So you can also, if you look and do the same thing with OpenSSL, you get actually a bigger list. So there's libz, libcrypto, libSSL. You can see that it's actually loading a private framework called Trust Evaluation Agent. It's loading libz again for reasons unknown. And why does this happen? So the reason why it happens is that if you go and you look inside of psych parser.c, you'll see some stuff like yaml parser t, yaml parser t, yaml parser initialize that obviously Aaron, so Aaron wrote psych. Aaron obviously did not write the right libyaml, but he wants to be able to in his C code call out to libyaml. So basically the way that you do this in C is you say, you tell the linker, hey, I need libyaml. Please make sure that you remember to tell the program that's going to run later, like please load in libyaml. So instead of having to essentially what you could imagine, copy and paste all the C code, instead of doing that, you basically say, hey, later on, the place where you're going to find this code is in libyaml, and there's usually a .h file involved that actually lets the compiler know what those declarations are doing. Another tool that OS X provides, which is pretty cool, is called O-Tool. And O-Tool lets you see for a given executable unit what dependencies it has. So you don't have to actually run the code and see all the spewage that spits out what's going on. You can actually just say, hey, OS X, please tell me what the dependencies of openssl.bundle are, and here you can see the same list, right? libssl, libcrypto, libz. There's no crazy private framework, but in fact that is a dependency. Okay, so what actually happens at runtime? So what happens at runtime is you load Ruby, and when you load Ruby, it dynamically links openssl. Dynamically linking openssl is pretty fine. It doesn't really introduce any problems, because openssl.bundle is part of Ruby. So Ruby knows where to look it up, where to find it, and it doesn't really introduce any external dependencies. It's just a dependency that happens to be a separate file, because you don't want to necessarily load every single bundle that Ruby generates every single time you load some stuff. These other things, libssl, libcrypto, and libz, are actually external dependencies. So each one of those three things is something that, when you compiled Ruby in the first place, it found on the system somewhere, and now when you run it again, it wants to find it in the same place. So that's an external dependency. So based on what I just said, which is that it expects to find it in the same place, you could already start to understand why distributing a binary distribution of Ruby might be a problem, because maybe it found libz on my system in a particular location, and then it said, okay, this is where you're going to find it later, but then when I give the entire package to you, it happens to be in a different location. Now, if you're a Linux guy, you're probably thinking, hey, that's no problem at all. You can just, the system will take care of it. The system will find libz. That is not how OS 10 works. OS 10 needs you to hard code exactly where the location is into the bundle. There's ways around it with a special ad executable path and some R path stuff, but this is a rabbit hole. You don't really want it to go down. OS 10 basically doesn't give you the tools that are necessary. And I think even if all that worked, relying on the user to have installed and put Libyaml somewhere in the load path is an external dependency that easily causes pain. So I'm sure some of you have seen, at some point, using something like RVM, like could not install Psyche, does, do not have Libyaml. And that's because Psyche was not able to find Libyaml, and now there's an external dependency. You are required to install it first. And every, so I only showed a few external dependencies. Ruby has many more. Every single external dependency is an opportunity for something to fail. So even something that you would expect to be relatively stable, like OpenSSL, Apple deprecated OpenSSL and will probably remove it at some point in the future. So you can't really rely on OpenSSL to exist. If you try to compile it, you're gonna get a bunch of deprecation warnings. Apple does all kinds of crazy shenanigans with it. So even relatively stable things, Apple does not promise will exist forever. So you might upgrade to Mountain Lion, try to run something, and now, whoops, OpenSSL does not exist anymore. Libzy is no longer included in the distribution in a place the linker can find it. So that has not, neither of those have happened, but OpenSSL is deprecated. So I would imagine in the next release it will probably be removed. So here is an interesting, another interesting anecdote. So here's a Stack Overflow post, how to solve Ruby installation is missing Psyche. And someone said, hey, have you tried to install Libyaml following these instructions? So first of all, this is a fail for me already. The fact that someone tried to follow the easy five instructions and got a fail and had to go to Stack Overflow, obviously bad. So this guy provided a link and he said, yes, I have, no luck, and that's the end of the thread. Right, so, so some guy, there's some poor soul who was trying to do something with Ruby and was unable to because there was an external dependency that for some reason that it's impossible for us to divine exactly what failed, failed. So what is the solution to these problems? The solution to these problems is to not rely on a compiler to compile and find the bundle on the, or dial up on the file system and to not rely on finding it again when you run it. So both of those are, that's a brittle association, but even just finding them in the first place involves things like, Libyaml does not exist on my file system, how do I make sure it's there in an appropriate place? And basically what that ends up looking like is that instead of Ruby opening OpenSSL, which then loads a shared LibSSL, you basically just essentially copy and paste LibSSL, LibCrypto, and LibZ into the OpenSSL bundle. And once upon a time when memory and file space was limited, people really didn't like this, they wanted to be able to share LibSSL across as many parts of the system that use this. When they tried to do that on Windows, that ended up with DLL, and on most systems where you distribute like an app package, either as an MSI or a .app, people tend to move away from shared libraries because there's just too much likelihood that something will have gone wrong between the time that you package up your .app and the time that the computer goes to look for it. It could be something like, you ran some bad homebrew uninstallation and it removed user local or something. Anything could happen, crazy, crazy stuff happens. So basically the idea is that you get LibSSL, you get LibCrypto, you get LibZ and you just put them in the OpenSSL bundle and now you don't, someone like me does it for you and now you have it in a bundle and you never have to worry about it again and your system doesn't have to go looking for it. And the way that this works in practice is LibSSL, LibCrypto and LibZ, when you compile them, you can compile them in a special mode called static and it will give you what is called an archive file, a .a. And the goal of an archive file is to be able to take the actual binary and again essentially copy and paste it into another binary. So it's not exactly a copy and paste, I would not recommend using cat or something like that. But the basic idea is that it's a relocatable binary that you can just put inside of something else. Now, the cool thing is that once you get this working, do O2 again, these things go away and now you have only LibSystem and LibObsc which Apple is extremely, extremely stable about. So if they made LibSystem go away that would be extremely bad. That has not changed since OS 10.000. Definitely stable. And if you go and you run Dial-Lib, Dial-LD, print libraries, OpenSSL, again a bunch of stuff goes away and you get to only bundles that actually came with Ruby, only bundles that are part of the Ruby distribution. Now the problem that I had here is I was like, okay, so how do I actually statically compile? And there's a lot of documentation and good tutorials for Linux and there are fewer good tutorials for OS 10 and when I went to read the linker documentation there are many, many lines of it and it changes across different versions of OS 10. So I'll just save you some time and this is the part that you care about and the part that you care about is that there's a setting that is only the default since Xcode 4 so you actually cannot compile Tokaido in Xcode 3. And basically I will show you how this works but the idea basically is here is how you tell OS 10's linker to statically compile. Again, if you're familiar with Linux you're probably familiar with like dash, B static or something like that. No, this is not how it works in OS 10. The way it works in OS 10 is that when the linker is told to find Libyaml it is not told whether it wants to do it statically or dynamically, it is just told Libyaml is, this program is interested in Libyaml linking. So for every item that is in the linker path it goes and it says, is there a Libyaml.a? If the answer is yes, then it statically links. If the answer is no, it goes looking for a Libyaml.dialib. If it finds a Libyaml.dialib, dynamically linked. Otherwise, go to the next LD path. So what you have probably noticed is that there is no way to set up a .slash configure to say I would like to statically link Libyaml. That is a thing that is determined purely dynamically when the linker happens to go looking in the file system. So when you want to build a static distribution you have to make sure your path is properly configured or else. It's easy to, this is one of these, it must be repeatable. If you don't make sure that the process that you're using to build it on an OS 10 system makes sure that the LD path that contains the .a files is at the front and does not have dialybs in it, you're going to mysteriously start dynamically linking instead of statically linking. So this is not desirable, this is not what you want. Now there's another sad story here which is that there is no standard way that you ask when you configure a UNIX program to give me a .a file. There are many, many different solutions. So Libyaml uses disabled shared, open SSL is no shared without a dash dash, SQLite you often will say enable static and disable shared. So basically, and there's more, basically every single one does a slightly different thing. And when I found this out this also made me very sad. That is a lion face bombing. And what I learned is that I decided to write Tokaido at the right time because there is this thing called SM. And no, no, no, SM is not what you're thinking. It's the system management framework, but this is the logo. So anyway, so the idea behind the system management framework is to provide a standard way of talking about things like I would like to compile a static version of Libyaml. So if you go look at the Libyaml configuration in the SM framework, there's basically a whole bunch of packages. And I would not use this as your standard package manager. It's more like a package manager for package managers. What you'll find is that you have the current version of Libyaml, where to download it from. And then if you say please compile a statically, what is the flag? And SM doesn't have this static for everything. It mostly has them for things that Tokaido needs because I went around and said, hey, can you have this static thing? Otherwise it assumes it's that static, which is basically never the case. But basically, this provides a way for us to talk about this. It provides a way for us to say in open SSL, it's no shared and here are some configuration flags that you're going to need. It provides a way for us to talk about it. And basically what that means is that there's an easy way to build local.aarchives for packages using a static flag, a flag that's just static, and then there's going to be a thing that actually abstracts that away. And one of the really awesome things about using SM is that Tokaido's distribution itself can be compiled for Linux for Windows for whatever because I'm just using, under the hood, I'm using the standard, some standard tools that work in environments with a C compiler. So I don't actually know how well it will work on Windows, but it definitely works on Linux. We've tested it on Linux and obviously the UI parts don't work, but the static distribution works. And SM also manages the LD path. So SM makes sure that if you have created an archive or something, that that is going to be at the front of the LD path when you try to compile something else. So this is how we manage to do this repeatedly, is that I am not actually in charge of this. There's another thing that's in charge of it and it offers me this guarantee. SM is by the RVM guys, so RVM, they're building the next version of RVM on top of SM. So it's pretty well maintained. It's, they're smart guys. It's based on shell scripts, which definitely not my cup of tea, but reliable. And another really cool thing about all this is that because I work closely with the RVM guys to use SM, RVM eventually realized that actually reliably compiling Ruby on OS X is as hard as it looks like, as I said it was. Now RVM always had a slight leg up, which is that they could just, oh, you need Libyamo. We'll just go download it and put it in a directory and then we'll link against that and we'll hard code that path and they could do hacks. But over time, what RVM realized was that some non-zero percentage of RVM users would simply fail for reasons unknown. They would try to add more hacks, but eventually RVM realized, you know what, Yehuda and us are together building this thing called Tokaido. Why don't we just download the binary that we have built together and use that. So at some point in the near future, when you say RVM use 193, you're going to get a statically linked, reliable build that came out of this process, which is, I think, a nice thing. There's another thing which I sort of hand-waved over a bit, which is that if you actually do this O-Tool, you'll see that it is relying on, I snipped this out before, but it's relying on a full absolute path to Ruby. Obviously, this is not going to work for me to give you a copy because you don't have a user's lycats. And apps in everyone creating a user's lycats seems bad. So you can see there's a hard-coded path here, which is not great. And the cool thing is that Ruby has a feature called enable load relative, which is completely undocumented. But basically what it does is, is when you load Ruby, if you have compiled with enable load relative flag, instead of it having hard-coded the exact path, it basically says, okay, where is the Ruby binary? And, ah, the Ruby binary's here, so go dot dot, go into lib, and that's where you should find the standard library. And that basically means that there's a little bit more cost to that than hard-coding the paths, but it makes the whole binary relocatable, which is really great. There have been a wide variety of bugs in enable load relative, which is why it would be impossible to ship Tokaido for Ruby 187 or even 192. Probably the most important bug that exists with enable load relative is that OS10 does not actually provide a mechanism for getting the location of an executable that was not dynamically loaded. So if you run Ruby, that's not dynamically loaded, that's just like the path looked it up somewhere, and OS10 does not provide a mechanism for getting that. So it would always just look at ArchV and completely fail. And what Ruby 193 does, which is pretty awesome, is it basically just looks in the path for where Ruby came from, and then that's gonna be where it is. So if you dynamically load Ruby, that's fine, but we're not doing that here. And if you statically load Ruby, then it has a hack, basically. It looks in the path from whence it came. And basically what that means is that I can't even make Tokaido for 192 because enable load relative doesn't actually work on OS10 on 192. So 193 is actually the first version of Ruby that for all these various reasons actually works reliably. And if you actually look at it, you'll see that instead of, so why did Ruby want the Ruby to have the dynamically loaded? It wants to not have to smash the dial up for Ruby inside of the binary. Basically the solution is if you say enable load relative, it's like, well, I guess I have no choice. I'll just smash the entire Ruby executable into the binary. So the actual Ruby binary gets bigger, but the only cost is that now you don't have Ruby dial up that you're loading. It's instead in the Ruby binary. It's not clear to me why this is not the default. It's not clear to me why there's a Ruby dial up. Okay. And now if you run O-Tool, we already talked about the fact that we removed lib SSL, libCrypto, and libZ, and we also now remove libRuby, which basically means, again, no external dependencies. I hand waved over the libRuby one before. So another thing that is, so sort of along the same lines, if you actually go to the Ruby bug tracker, there's like fix enable load relative on systems with lib64. I'm pretty sure Tokaido is the first time anybody has tried to use enable load relative for anything. So Mpappus, who did a lot of the work on building the statically compiled Ruby using SM, has been filing a lot of tickets against enable load relative. So hopefully, enable load relative will turn out to have worked reliably on 193. Hopefully I won't have to say use 20, seems great. Okay. So that's basically statically compiled Ruby. So now that I'm done with all that, now there is a way to actually build a package, which is a Ruby that doesn't have any hard-coded pass, that doesn't have any weird external dependencies that actually works like a regular Ruby. So how do we actually get this onto people's system? So how do we deliver it? So I'm going to just show you a quick demo of what is already working. So let me do that real quick. So mirror displays. So here's Xcode, I'm going to boot it up. And the first time it ever boots up, it asks for your password. I'll explain why in a bit. So you type in your password. And here's Tokaido. So nothing really is going on here. I'm just going to add an app, which is Ember. And then I'm going to open it in terminal. And now we have it open in terminal. So obviously there's a little bit of unpolish in some of how this works. But if you go which Ruby, you'll see that it's the Ruby that came with application support. So this is basically, I consider this the MVP of Tokaido of you can add things and there's a statically compiled Ruby that comes with the app package that will work. And so why did I do it like this? Why did I ship it as part of an application instead of installing in the system? So the problem with installing in the system is that it will probably work immediately after you install in the system. But it's basically a fixed point in time. And if someone screws up the system after that, it's basically game over. So the cool thing about how this works is that what open in terminal does is it opens a terminal. And then once the terminal is open, it basically makes sure the path is set to the right place, make sure the gem home is set to the right place. So it basically guarantees that all the environment variables are set correctly. And there's no way to screw it up because we're running after your system that may be screwed up is running. So we'll definitely, I don't think I have a slide for this, but we're gonna have a way to run it as your system Ruby initially through RVM and possibly through other ways. But I think for, even for me personally, I like knowing that when I open a terminal window, it's definitely, it's basically guaranteed to work. It's not going to have weird system stuff. It's not gonna mess it up. And another thing worth pointing out here is that there's a reason it opens a terminal window. I'm not trying to write a GUI for Rails or a GUI for Ruby. I'm just trying to make a much more, much less error prone way of getting Ruby to people's machines that will work reliably. This is a tool that I personally would like to use. Okay, so let me un-mirror it. So that's a quick demo. Now if you looked closely, you would see that there's a thing there that says ember.js.tokaito. So what is that about? And what it's about is that as part of this process, I have also written what is essentially a pure Ruby version of PAL. I'm gonna talk next about how that is working. So the main difference between PAL and my pure Ruby version of PAL is that my version works with a proc file. So instead of it relying on a rack app to boot up, it basically will just run the web section of your proc file with a port and it will then connect to it. So you don't have to, if you want to use like Jekyll or some other program, or if you happen to use Formen already, basically it'll do the right thing. It'll allow you to boot stuff up with a port instead of requiring a configure RU. I know I personally can't always figure out how to get like a Jekyll configure RU or a static-matic configure RU. It's probably usually possible, but it's not always obvious how to achieve that versus I already know how to run this program, so please just do it. So here's what a proc file looks like. I think this was invented by Heroku. And basically the idea is that you just have different sections. So here I only have a web section and $port is basically just the way of saying I would like to use this port. This is also what Heroku uses. So if you're already using a proc file for Heroku, everything will work fine with Tokaido. So let me show a quick demo of the pure version of PAL. This is not integrated into Tokaido yet. So I will, I appear to have closed. Here we go. Okay, so here I'm just going to bootstrap. So, oh, seems very bad. Okay, mirror displays. Okay, so here's my terminal and I'm basically just bootstrapping it. You can see I'm setting some environment variables here for where some sockets should go and I'll talk more about this architecture in a minute. So you bootstrap and it basically runs a bunch of stuff. And I'm going to open IRB over here. So let's require socket and then I'm going to get a new socket. So basically the idea behind this is that this socket is at a place determined by the environment variable and this is something that the Tokaido UI will set up for you. So obviously, oh, this is in. To the code, bootstrap slash temp slash muxer. Okay, so now I have a socket and I can write, I can write to the socket. Here I'm writing, please add this program that is at some location with this host and this port. So I'll do that and you can see over here that it received a message. There's obviously more verbose logging. This is still in a not fully complete state and you can see it booted up WebRick which is basically what the proc file told it to do which is just to run rackup. And there's actually a bunch of stuff going on here. So let's just curl http colon slash slash. We asked the for temp.tokaito. So now we got hello world which is great. And if we want to run, we can do the same thing. We can run a different thing and we'll put it at a different port. And again, you can see it got the message. And now if we curl temp2.tokaito, it works. So I'll talk about the architecture in a second but basically the idea is it's a system that works similarly to PAL except using a proc file. And it's written in Ruby. I didn't want to have to ship Node with Tokaito. So that's the demo. So how does it work? So basically the way it works is when you say give me an app.tokaito, it goes into etsy resolver slash tokaito. So OS 10 has this feature called etsy resolvers and basically you can say inside of etsy resolvers like hey for this domain which is tokaito, please go get the name server at this particular port. So there's a project that I created called Tokaito DNS which basically lives at that port and it will say okay, local host. The answer is local host. And then there's a way to create a firewall rule in OS 10 which requires pseudo permissions, pseudo IPFW, blah, blah, blah. And that will basically say okay, don't go to port 80, go to port 23456 and that will go to another project that I created called MUXER which is basically doing the proxying which will then say go to local host, the whatever port that you told it and then that will go to your app. So that's basically the architecture. It's a little bit crazy but it's actually almost identical to Paus architecture. It's just if you want temp.tokaito you have to actually do all these steps unfortunately. So how does this actually get delivered? So obviously people are not going to be opening IRB and typing stuff in. So basically the way it works is that the first time you load Tokaito it's going to install a firewall rules launch daemon. And basically this launch daemon, the reason you need a launch daemon is that IPFW requires pseudo and you don't want to have to be typing in your password every single time you open Tokaito. So we create a launch daemon that has pseudo permissions that we can talk to. And the way this works is that there's a socket that it listens on and you can, I'll show you in a second how that works. And then another thing that Tokaito does when it boots up is it boots up Tokaito Bootstrap and creates a manager and listens on the Tokaito socket. So basically it runs on only the first boot it launches the launch daemon otherwise it launches the manager and the manager loads Tokaito DNS and Muxer which are the two programs I talked about and manager is basically in the same memory space as Muxer. So the first thing now when you boot the application it just sends a message called enable firewall rules slash end to the launch daemon which will actually go and now that it has pseudo control it can do the IPFW command so the idea here is that unlike PAL I don't want this running all the time I only want everything running when you actually have the app open so that way when you close the app everything continues to work as expected. So that's just a philosophical Tokaito is supposed to be self-contained it's not supposed to take over your system. So the next thing so now after it does that now it just goes off it stays off in the side and listens for things at localhost 80 calls it a day. And now the first thing that's going to happen is it's going to go and it's going to send all the it's going to send a bunch of commands to the manager which are basically add these add these applications at these ports so it's like a little line protocol and the manager is going to go and add the application which is in Ruby and then eventually immediately assuming that there were no errors like you didn't try to find to the same port multiple times or use the same host otherwise you get an error response you're going to get a thing that says added and the idea here is that Tokaito can use this information to like show that it's loading right and then at some later point you'll get a ready message which allows you to show like a green button. Yeah that happens because that happens it's backwards and you can also go if the user says I actually don't want this app anymore to be on disable it where you can call remove and that's going to call remove app and then at some later point it's going to say okay I remove the app and that's going to send removed and that's how the application is aware so one really cool thing about this project is that because the point of the project is to have a reliable version of Ruby I can actually write a lot of Ruby code with not a lot of stress because I know that I can test on the exact Ruby that I'm shipping and if it works I don't have to worry that the user has some crazy Ruby so I'm writing a lot of sort of network code that would normally give me heartburn like who knows what kind of crazy stuff is going on but I know exactly what kind of crazy stuff is going on because I already shipped it so it's cool so that's sort of the architecture of the PAL stuff I think it's pretty cool I think it will I think people like PAL and I think they will like a more scoped version of it I think this is cool and finally I want to show some mockups of what the full UI is going to look like so this is what we showed already this was the original mockup it was replaced with a Ruby icon which you saw in the quick demo before and you can see the little green icon there and there's like a drop down stuff like that so this is like the new app screen this is the logger so basically specifically for Rails apps there will be a visual logger that you can use for to see what's going on and the idea basically is now that you're using Tokaido like you would be using PAL you don't really have a terminal tab open with your logs so you would like to see some logs somewhere and I guess we could just dump your logs or we could spend some time to make something that actually adds some value and I did a lot of thinking about what makes sense to be in a UI and I think I came to the conclusion that people are not particularly attached to their like tailing log workflow so if I provide something that's better than the tailing log workflow I don't think I'm going to get a lot of pain like for example if I added a run this rake task I think people would be very emo about that because I would be taking over something that really belongs in the command line I don't think tailing the logs is a thing people are particularly attached to so you can see here there's some stuff there's some cool stuff I think the top thing is going to change because the exact response time in development mode doesn't really matter but you can see like you can see which which request came from the parent so if you hit a page and that asks for a bunch of assets you can see that they're nested together you can see whether things were errors how long things took what the whether something was a 500 or 200 or whatever and additionally there will be a bunch of notifications so obviously like your page had an error as a notification but also will periodically run stuff like bundle outdated for you and give you a yellow notification that says like hey this is outdated maybe you care about it and the X will basically be like I actually don't care about this particular bundle outdated and then if it changes you'll get the message again things like deprecation warnings things like maybe even like code climate right so things like running code cleanliness against your app and then telling you like hey you should maybe look at this here's some code to look at basically just having a place to put notifications that are either urgent the red or more just like this might be something you're interested in and I think we won't initially but we'll eventually have a plug in architecture so people can add their own notifications like the compass deprecation warning we probably won't ship with but it should be easy to add also this screen is it's the only part of the OS 10 app that will be written as a UI web view and again the idea is that if you're SaaS and you want to provide your own logging view that's not going to be the exact same thing as a Rails view you should be able to drop that in there'll be some kind of JavaScript to OS 10 protocol for like you'll get notified when there's a request that came in etc and then finally this is just the creating of the application editing screen and the idea here is you can do stuff like choose an icon or we'll find one for you whatever that's great change the host name you can see it tells you what if you want to share so one cool thing here is that because every single app has their own port it's easy to share over a local network like hey check this out and it tells you like austin.local, colon, blah you can choose to auto assign to public port or not we also want to support people who don't want to use Tokaido Ruby sandbox so like if you want to say I'll just use rvm that's great we want the UI to work for you and then we also want to have these settings should be should be configurable via yaml file so that people can say like I always want this icon I always want auto assign public port I want this to be my application name and have that checked into source control so everybody is basically on the same page so that's basically that's basically where we're heading I think we'll probably have something in between what we have now and this in within a month or so so I don't want to announce any specific dates but we're making good progress I want to say thank you to some awesome people so MPAPIS was the one who helped me initially with all the SM stuff getting it to a reliable place so really big thanks Wayne helped me with some SM stuff that MPAPIS was not sure about so SM is definitely not a a thing that regular mere mortals want to be using but I think it provides a lot of value for our use case Austin Bales did all the mockups that you saw and it's driving basically the implementation Patrick who works with me at Tilda is working on the cocoa app and Terrence front row he's been doing a lot of testing so something I didn't talk about is Terrence has actually been taking the static build bringing it to Rails Girls not without the UI and just seeing if the static build actually holds up to a tutorial and we got really really good feedback I think there were a couple of issues that we hit early on with ZSH or something but by and large it was a massively improved experience versus the just follow these five steps for people who are just starting so that's really great and Terrence thank you for that so thank you very much and I actually want to close by saying one thing which is when I started I think it's there's a tendency to look at this tool and say this is mostly a tool for noobs it mostly solves a pain point that I don't have and it is a very important goal for me for at least me to use it I want to use it so we're not really making trade-offs where if you're a noob it's going to be great but then oh I want to build real stuff with this this is impossible like and I think DHH says this right which is everybody has to cross a barrier between being a noob and being an advanced user and if suddenly they fall off a cliff because the tool stops working that's terrible so you should build tools that are good for real developers and they and if you do a good job they'll happen to work well for noobs so that that's my philosophy on the project thank you very much