Devreal

Scala Scripting

Event: Scala by the Bay

scala.bythebay.io: Li Haoyi, Scala Scripting

Recording: scala.bythebay.io: Li Haoyi, Scala Scripting

uh my name is har and this talk is about Scala scripting so in for next 40 50 minutes or so I'll be talking about how to use a Scala programming language for small scale oneoff scripting tasks quite different from the normal like large scale application building compiler writing or distributed distributed system tasks that you normally use the scalar language for so as a motivation for this I believe that Scala has bit of a code size Gap in that on one end you have the Scala repple which is this really small thing that's really nice for I think small snippit of code if you have like a problem which causes compil to crash or one of one line Half line demo to show someone you can use a scalar reppel to quickly bang out something and show it like this is what this is what the code is and this is what the output is on the other hand it doesn't really work well if the output gets large because then it does it's pretty hard to read output like that or if your input gets large not even very large for example this is a three line input but if you make a mistake and you want to change it you end up paging up line by line trying to figure out which line you want to edit and making sure you enter them back in the right order such that you can reconstitute the same command so together this makes it kind of hard to work with slightly larger bits of code so although one liners may work two liners become difficult and three liners get outright annoying because of this behavior and on the other hand you have SBT which is great as a large scale bu build tool it has a it works great for downloading external dependencies it works great for dealing with internal dependencies between projects so you can have like a project with 15 different sub projects and when you ask for it to compile it will compile the minimal set of sub projects in the correct order to maximize the parallelism in order to compile those 15 projects and do what you want but it's a bit of overkill for for small scripts so for example if you have this tiny hello world application here this small the smallest hello world Standalone scy application you can write it takes three and a half bit more than three seconds for you to run this application using SBT and this is after compilation is already been completed and all the class files already cached so you can see the scal compiler is slow and it is slow but this is not a scal compiler being slow this is purely the build tool overhead in in comparison you look at something like python is 30 milliseconds and Bash is 4 milliseconds so that's 100 to, times faster apart from the time overhead there's also the space overhead so SVT leaves a lot of temporary stuff around your file system which again doesn't matter if you are having a large scale like if I'm deploying to a cluster of a th000 machines I don't mind that there's a Target folder in on my build box but if I'm trying to write a script that just mangle some files in my folder I don't want this script to create another 104 folders and 59 files just to mangle one file in one folder um so that's why I think that Scala has a bit of a code size Gap in that in between the on liners and the Thousand liners there's nothing that really fits writing Scala code um many people will drop down to bash for the one Niners that deal with the file system other people will drop down to python for one liners that may or may not deal with the file system or maybe 100 liners or 200 liners that don't deal with the file system but in there is at least in my opinion no reason you can't use Scala to use Scala for things from one to a thousand lines and uh the what's lacking is a nice build tool that lets you write Scala and run it without as much overhead as SVT but with more convenience than a Scala rapple so that's where I think the amonite project comes in which is something I've worked on for past two years on and off it gives you a nicer scalar repple and a nice Syntax for scalar scripts which lets you expand beyond what scalar repple does and lets you take care of things which maybe too small to be worth a whole SBT project so the ammonite is a it's not a new project so if the documentation is online there's quite a lot of it but in short it has has two things it has a rapple that's like the Scala rapple except prettier so you don't feel so bad using it if you have lots of output or lots of input um and it has a script Runner which lets you run files kind of like SBT does or the normal Scala um executable but it does it caches things transparently after compiling and runs it reasonably fast so here we're looking at the first run it takes three seconds that's largely from for compilation and the second run over here we're looking at about half a half a second so this is still more than 10 times slower than Python and 100 times slower than Bass but it's still almost seven to eight times faster than SBT and maybe make script WR writing small scripts and running them acceptable rather than being a huge pain in the neck so I'll just show off these two in series so first we have the the Amite rapple so this is something you can download download from the website you can add it to SBT project or use stand as a standalone executable um it looks just like the scalar rapple you can do scalar rapple things like one plus one very important first one is slow because the compiler needs time to warm up after that it becomes acceptably Not So Slow um what's better than the scalar rapple well you can do things like sis. end when it shows you thing it shows you the output nicely formatted and colored if you shrink the window it correspondingly truncates at a shorter distance so you don't flood your output with lots and lots of text and you can use show to print a whole thing if you don't mind flooding your output um it has multi multi-line editing and syntax highlighting so for example I could say def Fu equals print line hello uh what sorry oh sure um I'll make this like that can you see here okay so if I Define a function like that which takes up three lines the first thing might notice is that it's syntax highlighted which makes it kind of nice to read if you have lots of code black and white code is difficult at least for me and when we deal with the history you have a nice multi-line single block history editor so you can go back and like erase parts of it make it more excited and when you're done you you run it and all the changes have taken effect so that's more or less the short the the short demo of what Amite rapper lets you do and lets you that makes it plausible for you to write slightly larger chunks of code then can be written using the normal Scala repple for example if you want to write that famous or inFAMOUS phys Buzz interview question that people here use as a judge of programming aptitude or whatever you can say like 4X from from zero until 20 and then X percent Tre x per 5 then you match on it maybe the first maybe they're both zero in which case you print line pheb maybe the first one Z Z in which case you print line Fizz Buzz or do nothing and when you're done maybe you don't want to run this yet maybe you want to tweak it maybe the interviewer asked you to say Capital phase and capital Buzz maybe you want to go up to like 15 as extension question to the interview because that's really hard and then when you're done you submit it and you get fiz Buzz which is kind of nice and you so this this is something which you probably can't do in a normal scal rapple or you could do but it'll be annoying and it's also something you don't want to set up SBT project to do because setting up SBT project to do a fbuds interview is seems way Overkill but with Amite rapple things from like one to five maybe even 10 20 lines of code you can acceptably deal with them in the rapple and if I want to go back and edit it run it again you can do so without doing the weird counting lines thing that the normal Scala rapper forces you to do um so that's the Mite rapple um so while the normal scal rapple fails what when things get bigger than one line the mlet rapple lets you scale a bit more 10 lines not quite web scale but almost um and the next thing that I think that that will show off that I think lets you scale from maybe 10 to maybe a thousand lines is ammonite SC scripts so M scripts basically let you take what you write in the rapple dump it in a script file and run it so for example if I look at a file here let me make this bigger and turn this off so over here I have a file called F.C and it says print line H Fu and I can run it from the command line using amm foodd you can also use a hashack Unix like hashbang to make it directly executable if you wish and this after it compiles f it then prints out f um as you see if I change it and let's I add a time so you can see exactly how long it takes um the first compile takes more than 3 seconds needs to compile and scal compiler is slow 3 seconds with like three threads in user land apparently and subsequent runs take like half a second which is okay it's not great it's not near as fast as python or bash you don't want to XR 10,000 files and pipe each one through this individually but maybe if you're running it as a standalone executable maybe it's okay so you can put basically anything can put a normal Scala file on on the scalar Apple in a Scala script for example if I want to place fizzbuzz in here I can do so um I can take this paste it and I can run it first time it compiles again slow so print line fizzbuzz second time it's acceptably fast you get your fizzbuzz um so this is so far not nothing that the normal Scala executable cannot do so anyone here who who used app get install Scala or bre install Scala from home brew can simply run Scala f.s and it does the same thing more or less let's see if that works so first time should be a bit slow second time it's cach in acceptably fast so nothing special yet so where what makes Amite scripts interesting well what I think makes Amite scripts interesting is what the question to ask is why don't people use scalar scripts for real work I mean people use Python scripts for real work I've worked at place where you have millions of lines of python and clearly it SC scales from one file to two files to 50,000 files and you may not like it but it works but no one uses scalas script so real work and I think the cor problem is it lacks too main features one is can you use third party libraries and one is can you import other scripts so the reason for this is that if you want to write any piece of code that does anything non-trivial that's not a hello world programming 101 problem you're going to need to use third- party libraries someone's going to give you yaml and you'll need to parse yaml and you do not want to write your own yaml parser or someone's going to want to like someone's going to want o want the o or token and and you you you're going to need some logic to create the O token and do this back and forth to make the o server happy and you do not want to write that yourself the second part can you import other scripts almost go goes without saying because if my script gets from one line to 100 lines to 10,000 lines I probably want to break it into two or more different scripts just to keep it maintainable um but with a normal scholar script Runner this is not really plausible so you can use third party libraries but you have to manage it yourself using downloading jars and using the dash class path to like pass the jars manually to the um to the Scala executable or or the Scala bootstrap jar and you can do it you can definitely do it it's just kind of annoying to do um and you can't really import other scripts there are some like textured include things they can include things texturally but it's not quite the same um so with the Mite the Amite script Runner this solves both of these problems where lets you pretty trivially import third part executables using this import dollar IV syntax and let's import other scripts using import file. or import file. f. bar syntax so for example this import IV syntax is more or less equivalent to what this snippet in the SBT build file and these two import file syntaxes basically import those corresponding files and make them available to you as object you can call methods you can use values you can instantiate classes from them and all of those are now available once on that object once you import file. F or file. f. bar the first one on the F object the second one on the f

bar object kind of like a normal scalar import so let's show that off um so over here I'm back to my full script um let's take a look at another script I've written called scraper so scraper wants to use JP to connect to lea.com which is my blog and get all the headers from it select all the H1 headers um get the text of those headers and print them all out so this is a kind of small thing you probably don't want to deploy to production on your AA cluster but maybe you want to do it cuz your boss wants to know who's hiring because he's looking for a new job um so if you try running this using the Scala rapple the Scala script Runner it's called scraper SC you see it doesn't work because JP is not on the class path and why should it Scala script the Scala repple is not a web scraper so it should not have J soup on it and similarly you can if you try doing using ammonite it fails the same error because ammonite as a rap and script Runner does not have a HTML scraper but just because it doesn't have it by default doesn't mean it you shouldn't be able to pull it in without too much difficulty and with the Scala with ammonite um IV syntax you can import IV dot I think it's or. JP colon JP not Json P J soup uh 1.7.2 and this will pull down this should if I didn't make a mistake pull down JP cash it and make it available locally on your machine um looks like I screwed it up let's see uh no that's that worked and I'm I'm missing the HTTP prefix for my blog URL HTTP colon slash and first compile is slow as always but after that it becomes acceptably fast again it's still few hundred milliseconds but it's a kind of thing where you may feel okay with running it manually it's not going to make you annoy you don't need to keep a continuous process Damon server SBT thing running you just come in on your shell you run it you go on live come back maybe run it later maybe don't doesn't matter um so that's JP maybe you want to do something else maybe you want to render some HTML similarly scal if you want to use for example my Scala text HTML rendering Library um the ammonite does not have Scala tags built in by default so can't find it because why would the r the HTML templating Library um but you can import it so if we import dollar IV do com. leeha double code on for scalar dependencies scalar tag 0.6.2 and after that we still import the normal scalar tag tags thing you can run templ template. and we get our HTML out first time is slow subsequent times is eh okay um the last thing to show off for the script Imports is uh my my neat little uh one file play play framework server so this is a file called web. and while people talk about play framework as this big reactive web scale thing all it is is it is some jars and it is some Java objects so all you don't need to download the type safe activator to do this you don't need to have SBT project with a bunch of plugins all you really need is some jars and some imports and some instantiations and again you may not want if you're going to work on this for the next six months maybe want to use SBT project for the additional benefits but if you on the server for the next 5 minutes maybe you don't care um and if you run web. here you can see this route is there's a single route which routes hello with a segment and it returns hello that segment as a string here and if I go to Local Host I think is 1900 I can do a Hello Scala by the bay hello Fubar or FB and you have you have a play framework server in this let's see in this much code more or less and you maybe you don't want it you kill it maybe you want it again you start it up in about half a second it's up it's running it's a play framework server and can get on with your life so this is a kind of a silly demo but there actually many cases where I I in person have had to start up a one file python HTTP server or one file python like websocket server just for one small thing and throw it away later and that case you don't really want a big heavyweight project you just want one file which can run that does what you want and does nothing else so this is so this is what the amonite lets you do as a script Runner let's you build larger things which are not buildable using the Scala normal script Runner but which are maybe too small to be worth the SVT project and you can actually tie all these together because kind of like python you can import third party dependencies and you can import other files and all the compilation and stuff gets handled somewhat transparently for you so you may have to wait a bit longer but when it's compiled you don't need to have a separate like compile and run stage um or you don't need to like have a long startup time even after it's compiled so for example I could take this play framework server and this web scraper and this templating engine and I could hook them together because why not they're just different scripts and I can import scripts from other scripts so if I want to render this hardcoded snip of HTML for my play framework web server I could instead of printing out I I could make this script of Define a method that renders it um render page equals that um on my play framework server I could import file. template and let's give myself a new line here so I'm just do file. template

render page page two and let's make the render page function take some f to embed on the page H1 hello a paragraph of f so if we run this um compiling compiling it should start serving you see now we're getting back HTML for HTML for the page and this is the HTML that is being rendered this HTML is being rendered by this script so this script defines a render page object and the render page object is sorry this script defines the render page function on the script object and when I import the script object in the main script in the web script I import file. template I now have this template object accessible to me and this template object now has the random page function as you'd expect so this is kind of copied from the python semantics because I like I've used Python and I like it um and it kind of gives you a nice abstraction for here's a thing I can do stuff with and in this case a thing just happens be another script um so I've made it render HTML the other thing we could hook it up with is a scraper so again we we had a hard-coded scraper here which I could run using amm scraper dosc to scrape my blog and instead of using a hardcoded um scrap leh how.com URL we could Define a scrape function which then takes in a URL and puts these things on top in in the function and doesn't print it out because I want to return it so the main web server could use it um so let's have card coding how I'll add it to a URL now if I run scraper SE it'll compile but nothing should happen because it defines a function and then it exits because there's no actual code to be run yet um but what I can do now is I can import file. scraper and I can say well instead of rendering directly the URL segment you passed to me over here I can instead scraper do scrape the URL segment I'm going to call URL segment a bit longer and then sorry sorry oh yeah okay I'll get to that in a second the the types are wrong too yeah what oh higher sorry um like that okay so um just call this headers because scrape scraper and scrape all sound too similar so headers is what I scrapes and I'm going to render the headers in as part of the page if you try to compile this it should fail because headers is a sequence of strings and render page takes in a single string um so the solution is to go here and update the rendom page function sequence string maybe I'll make this unordered list with uh for header in headers yield a list item which is the header um and then we can should be able to run that so it looks like it's serving and I could run here it fails cuz there's no there's no plain scal by the bay but if I do the io maybe it will work uh no that doesn't work let's try lear.com that hopefully should work okay so lear.com Works um if you go to gizmodo.com there's a bunch of stuff about about animes and other things um go to the New York Times um so in by now we've spent maybe 20 minutes and we have a three file three file I think it's maybe 50 lines 10 15 20 yeah it's about 50 to 60 lines worth of scalar code in three files and we can run it in a as a script form without needing to set up SBT project so this has some the same Advantage advantages I showed you earlier um I could kill it and I could rerun it and the web server just starts up basically instantly as soon as a jarus load um without needing to set up a big build build framework or web frame web framework infrastructure if I want to add more things or more third party dependencies I can just import IV them as shown here and they'll be made available as part of the class path um and you can just write code you can even you can even write code top level without wrapping it the object not because it's any magic simply because gets wrapped in object for you but it makes it kind of convenient for you to start off with small things and you can let's you scale up that small thing such that even when it's not so small you can keep working in it and eventually when you're ready you can convert it to a full-fledge SVT project pay the cost of using SVT and get all the many benefits SVT gives you so that's where I think the amonite script format comes in um while the Mite rapple satisfies everything from one to 10 lines of code you don't really want bew writing 30 line Snippets in the rapple even though you can and anything more than a 100 lines is probably totally out of the question but you can write 100 lines in a script just fine and maybe it's not worth paying the 3 seconds to start up SBT project but with am with ammonite script Runner you can simply run the three run the 100 lines at in a script and it starts up reasonably fast without all the overhead so let's talk about some use cases um I've used this a bunch in various places some of them very random so my blog which is lear.com actually is built using ammonite using ammonite scripts so if I let's kill Safari and go back to Chrome um if you go to github.com the how blog you'll see that all we have here is we have one page Styles script we have one Pages script which renders HTML and we have one build script which does the actual building and we can just clone this down do I have it already maybe I have it already let's clone this down well while it's cling we can take a look at what what's inside each of these scripts um so build. SE it pulls down it pulls down Peg down for markdown rendering for markdown passsing because the blog is written markdown it pulls down Scala tags for HTML rendering it Imports the page Styles and the pages the Pages which are HTML pages and it does a bunch of things it formats dates using git um uses Java youtil datee to format the dates nicely so if you go to lea.com these dates you have here not uh formatted using normal Java apis like which are those um it generates a bunch of posts using for Loops it has it uses the um it uses a peg down markdown library and override some stuff in order to give it custom like HTML Snippets for parts of the markdown and at the end you it removes the target folder writes a HTML and writes a bunch more HTML and that's all there is to it so there's no real framework here all it is is three files that you execute while while this doesn't give you any good defaults also gives you the ultimate flexibility like you could turn this into Angry Birds app if you really wanted to like there's nothing that's stopping you from doing that um and it does a bunch of G operations to push to push to the GitHub Pages if that's what you want again there's no plugin there's no GitHub Pages plugin it just shells out to git and that works great um if you look at the page Styles this is just CSS and this is just and pages is just HTML pulls down bootstrap cuz that's how you make things look pretty pulls down on highlight JS because that's how you syntax highlight code on the internet um so that's one use case of of um amonite let's see if it actually works um plog and buil yeah so the first time you run it the earlier ones like you didn't see this cuz it was already cach but the first time you run it it's going to pull down whatever it needs and compile everything compile compile compile I don't know why it's compiling it twice um then it runs its code prints out a bunch of spam because it's a script so I don't care about printing out things unnecessarily and we're done and once we done I can go into that folder workspace blog all Rand to Target and I have the blog as like a bunch of HTML that just got sted out to a file um and if I run it again you it won't compile it just does all the norm normal Scala code execution and does the same thing pretty pretty quickly uh next use case would be uh resume is an even smaller version of this so this was generated using Scala is like this much Scala with a bunch of HTML Generation Um the build script for amonite itself so amonite has continuous integration using Travis and continuous deployment so I set it up every time I push a master it get deployed to Maven Cent using a commit using a like commit Dash like ox whatever um artifact that is done using again using amonite scripts let me paste this into Chrome so it's AMAC script so you can import other scripts in this case another script that handles upload just so I could test it manually you can print line stuff all over the place because that's handy when it's a script and you don't know what's happening um can check some environment variables you can shell out to G get this you can shell out to git in this case we're even like writing SBT files and executing them because why not like that's that's something you do in the Bas script right if you're in the Bas script you'll be writing files you be doing stuff to them and in this case because the script is managing SBT project because Mite itself is big enough is worth using SBT this y script just run writes out SBT and shells out to SBT so this is where it's writing the SBT file um is writing more SBT files at some point it calls Sona type release SBT Sona type release all see I scroll this up a bit over here um so it's making it takes advantage of the fact that SBT has a plugin to do this to do the actual release and for the parts SBT makees sense this happily delegates SBT but for parts which SBT doesn't really give me anything I want it doesn't really make sense to put everything inside SBT just because SBT is my main build script I mean for the things like creating a file or making HTTP request to GitHub like I don't need to wait 3 seconds just to make a HTTP request to GitHub that doesn't make sense um so all that stuff is pulled out of SVT and SVT is focused on just the building with all the random GitHub HTTP file mangling all done within ammonite script and this is what gets run every time I push a new version of ammonite to G to the main GitHub Branch um so so those are the use cases I've seen for this um in terms of next steps like this is a project that never really had a well- defined goal and therefore isn't finished um it started off as purely uh rapple and after that I realized that a script Runner is just a rapper but with the commands pasted into files so now it's also a script Runner but there's lots of stuff to do and here are some of it so as with most projects it could definitely use more usage currently it's about six to s 7K downloads a month which is okay but with more users that always helps because more edge cases get found more people can help fix bugs and I guess probably most importantly more users help set the direction of development because as in many of these projects we could do anything but just because you could doesn't mean you should so ideally this project would be something that's useful to a broad range of people and in order for that to happen you need people to I need people to use it and give feedback on like what what they want to do what they want to use it for and what they can't or don't want to use it for next steps apart from that you have more contri we we probably need more contributors so we've had a few dozen people contribute small fixes but mostly been myself driving development um I was lucky enough to get two Google sum of code inters to help out over 2015 and 2016 Summers and they're actually the ones who built most of the script running um that I showed you earlier like before that it was just a rapple and purely due to the interns that it became a script Runner but despite that like most interns they've moved on gone back to school and they're not they're not really working on this full-time and I would need more people to help drive this project forward sustainably as for concrete tasks to do so now I've done all the hand waving Community stuff there's a lot of actually pretty hard work that actually should happen in order for this to become much more useful to people and many of these things are things which I have zero experience in doing and zero like expertise in doing so for example um intell support for scripts item number one if you noticed earlier intell thinks everything is wrong and intell thinks everything is wrong because intell J doesn't know what dollar IV is and since intell intell J doesn't know what dollar IV is it doesn't know that play is being added doesn't know that this must come from play it doesn't know that template comes from file. template means importing the file it does not know that template then has a render page method so it kind of works you can still write cod in it it kind of Falls black back to a Vim Sublime level of coding but it' be much better if we had actual like intell Scala support for this and currently we I I don't I've never worked with intell and we ran out of time last summer to implement it during Google summer of code uh next item number two complete convert autocomplete to use Scala 212 rapples better autocomplete so the Amite R's autocomplete is better than Scala 21's autocomplete but Scala 212 is better again than ammonite and the code is open source so you should just steal it but I haven't had time to steal it and I don't really know much about the scy compile internals so if someone could help me steal it and like Chuck it in here that' be great um experiment using shapeless for more stable printy printing so if you look at the pretty printing in the rapple for example I can do seek. fill 10010 and it like um you can see it prints it nicely for you you you can seek. fill seek. fill like three 44 five and it does this nice thing where it lays it out vertically as well as horizontally and tries to give it like ni for things which she needs to spread out vertically it spreads out but for things I can put out in one line it fills out in one line and it works for case classes and stuff as well so I could do like option one two 3 Su one two 3 so this looks great now because I'm only showing you small examples but there are lots of bugs with it where it fails to work and that is because the pretty printing like the derivation of trying to figure out what needs to be pretty printed is done really hacky because I no clue what I was doing and the shapeless people seem to know what they're doing so someone should go and try using shap that to make it actually work for things like nested case classes or nested recursive case classes with sealed traits where it sometimes works right now but too often it does not uh better SBT integration so currently if you look at the main doc the main docs for SBT integration you can run amonite as a standalone executable you just curl it down and run it or you could add a snippet to SBT project to make it runable as part of your SBT test console so then you can run it you can run the N rapple with all your SBT project stuff inside of it all your class path loaded um but some basic things like compiler plugins aren't automatically given to a reple so if you have a compiler plugin inside SBT and you have a rapple by default rle won't have it unless you also add it to the to the rle and SBT plugins obviously don't affect the rapple and compiler settings don't go to the rapple automatically and these are things that could work should work don't work right now and if someone could help do it that' be great and lastly there's spark support which is a hip thing apparently that I know nothing about but since a spark uses a repple a lot and this is a nice repple in theory it usable for spark but because I don't really use spark and I don't know anything about spark we would need someone who's like an actual user who cares about it in order to make this happen I don't think it I don't think it'll be that difficult we just need someone to know who who knows what they're doing to go and do it so yeah in conclusion um my view is that Scala has always had a bit of a Cod size Gap where small things are great huge things are great and small mediumsized things were not so great kind of annoying on on both sides and the am ammonite is meant to provide two tools to kind of bridge that Gap so previously where you'll be writing a python deployment script or a python web scraper to scrape your competitor's jobs page or a python whatever um with amonite in theory could use Scala to do so um it wouldn't be as fast as startup as python it's still more than 10 times slower um you won't have as much IDE support as python ironically because although it's Scala intell J doesn't understand it and intell actually does understand python pretty well to give you all a nice autocomplete for python um but despite that the assumption is you you people are here at a Scala conference so you guys like Scala and this could be something they'll be willing to try out if you want to try swapping out some of your Python scripts for Scala scripts or your python I python repper work for Scala and Mite reper work so that's scalar scripting and I'll take [Applause] questions go for it miles um please repeat the question okay uh the question is do you have Vim bindings for the multi line repple and answer is kind of so if you look if so the the repple is basically written from first principles using bash using shell Escape codes so if you look at um amonite itself the repple is just like a sub project something like a thousand lines of code is not a lot um and there are a bunch of like hardcoded Bindings that we've implemented and each one is basically hardcoded to do something so we have some vimb bindings you have some emex bindings basically whatever anyone has felt they they wanted to implement we also have some some guey bindings so you could do things like um you could do things like M you can do things like select and replace things or multi-line like tabs and un tabs so it's kind of a hge podge of things you can sorry you can't see at the back so you have multi-line like tabs and un tabs in the rapple and you can replace in highight and replace things before I finally edit so it's kind of a hod pod of everything that people liked um in theory there could be more G bindings I don't think it would be difficult but you just need to add to this huge list of hardcoded bindings uh any other questions one over there have you thought about doing some sort of like a nail gon of like a background uh server because you talked a lot about the fact that it's not as fast as so the way make it yeah so um we've talked about using nail gun and have and using drip to have like a background jvm um my current feeling is that what we really want is something like sbts listen and listen and recompile when files change cuz that should get 99% of the use case um but yeah you're right in that currently when you when you time it when you if I go back to talks if you if you time it once you're done with the compile um most of the half a second is actually jvm class load time so it's not going to get any faster until you can keep the jvm hanging around so possibly nail gun possibly watch and recompile and re rerun but hasn't happened yet so I would like it to happen uh any other questions one over here uh depends how you uh question is is it production ready can I can you go and replace all your scripts um the answer is maybe so so different parts of it are are production ready to different degrees um the repple is the oldest thing and it's the most production ready so the repple I know like I know lots of people at Twitter are using it cuz they've been asking for 212 support I haven't given it to them um like apparently Julie is using it for her scripts um I'm using it for my scripts but if you want to replace all our shrips you have to try it out and see what problems you run into um like obviously it will not be as polished experience as writing python at least for now like writing python using intell is a really wonderful experience and this won't be it until all those things I showed earlier are done um but you could start trying and see if it makes you happy if it doesn't make you happy roll back um yeah any other questions going on yeah yeah also the um the shell Ops yeah that you didn't talk about do you know if anybody's using the& shell as their fulltime like B replacement um I know a few people on the internet who are using it which is probably a very unsatisfying answer PE like people on the internet have used it before and have given me like feedback about it um I don't know any large company that is using it on a large scale for like that that is answering question of using ammonite not just as a scalar rapper but as a bash replacement who's using that and answer is people on the internet any other questions going once going twice I guess we're done thank you