
Shiny in Production 2023: George Stagg - R Shiny without a server: webR and Shinylive
R Shiny without a server: webR and Shinylive by George Stagg at the Shiny in Production 2023 conference, hosted by Jumping Rivers! Note from the speaker: Shinylive is now available on CRAN! https://cran.r-project.org/web/packages/shinylive/index.html Abstract -------------- WebAssembly (Wasm) is a technology that enables software that’s normally compiled for a specific computer system to instead run anywhere, including inside web browsers. WebR is a version of the R interpreter compiled for Wasm, bringing this technology to the R world. Earlier this year, the initial version of webR was released and users have already begun building new interactive experiences with R on the web. The latest release, version 0.2.0, includes improvements to graphics, accessibility and internationalisation, developer API updates, and introduces a new webR REPL app. The release also includes expanded support for Wasm R packages, including the ability to run fully client‐side Shiny apps. In this talk, I’ll introduce webR with some simple examples and discuss some details of how the system works. I’ll talk about how JavaScript APIs can be used to integrate webR into wider web applications and describe webR’s communication channel. Finally, I’ll give a description of how Shiny apps can be run using webR without an R server, ending with a demo of an in‐development “Shinylive for R”. This event was sponsored by: - Jumping Rivers - National Innovation Centre for Data - NU Solve - Posit - R Consortium - Royal Statistical Society
image: thumbnail.jpg
Transcript#
This transcript was generated automatically and may contain errors.
and a piece of software called shinylive that Winston and others from Posit Air were working on around the same time as I started working on webR.
So yes, running Shiny without a server, but one thing we've realised talking to people about this kind of thing is that we're not always clear about what we mean by the word server. What is a server anyhow? And really, one way to define what a server is, is a machine connected to the internet that runs 24-7, 365 days a year and it runs your Shiny app and serves it to people.
And this is a sort of pictorial representation of that. You have your R or Python server if you're using Shiny for Python. It sits there and services requests from clients who connect with a web browser. Now there are more complicated topologies that can happen. So for example, your R or Python code could be running on a server that's behind another web server that handles web requests. Or you could have something like an internal network or proxying or firewalls and all that kind of stuff. But really, fundamentally, it looks more like this. At some point, you have a machine that is running an R session or a Python session and in that session is running Shiny and that's what's servicing your users' apps.
Existing Shiny hosting options
Now, there are some good solutions for running a Shiny server already. If you're a place that works with on-premises Shiny servers, there's a few options there on the screen. At the simplest, you might simply have a laptop or a desktop that sits and runs RStudio. And one of the things RStudio can do is if you're developing Shiny apps, there's a preview button, you click that and you can see your app. What's happening underneath is that RStudio is starting a Shiny server for you and your machine is opening a web browser, which may or may not be built into RStudio, and then loading that app. And in that case, your client machine and your server machine are the same. And it can do that because your workstation or laptop that you're working with is quite powerful. It can do both of those things at the same time.
Now, the problem with that is what happens when you want to start sharing your Shiny app with people? Running your Shiny app on your machine is not a good place for that. It's not very scalable. So, the next step up in terms of scalability or enterprise-ready Shiny apps may be something like a server or a virtual machine sitting in a rack on-premises running a piece of software called Shiny Server, which is free and open source. You can download that and run it without paying a positive penny. And again, that might service, who knows, maybe 10 users, maybe more, 20, 50, who knows. It depends on your app, right? It depends on how much computational resources your app uses.
But eventually, you're going to reach a point where if you try sharing your app with too many people at the same time, it's going to start struggling under the load. And when that happens, then you have to start thinking about more enterprise solutions, the idea of scalability and reliability of your app. And that's where software that's more paid for, like Posit Connect or other offerings, come into play, where you have a more enterprise solution so that your app is reliable and can be accessed by many users and scales for that reason. And these are all on-premises solutions. It all ranges from very casual to very enterprise.
But not everyone has on-premises hosting. There's also cloud hosting, and this is a similar story. You could start by servicing a few users on ShinyOps.io, and there's a free tier that can service certain numbers of people. And as you get more enterprise, there's now Posit on Hugging Face available, and then there's the big cloud services like Amazon, Google, Microsoft.
Now, what you find is that generally people will fall into two camps. Either they'll be a very casual user with very few end users using their app, and they can usually get away with something like ShinyServer or ShinyOps.io is very popular. And at the other end of the spectrum, you end up with big enterprise apps that could have hundreds or even thousands of users. And in that case, those users will be able to and willing to pay for enterprise-level software with enterprise-level support.
However, there is one group of people that kind of sit in between and don't fall into either camp. And I used to be one of them. They're academics, people teaching. They will often have 50, 100, 150 people maybe trying to use a Shiny app at the same time or some kind of R server, and yet not necessarily have access to those enterprise-level solutions. Something like maybe their company just hasn't bought or had a contract with Posit to have something like Workbench or Posit Cloud. Or maybe just their institution, the department, just doesn't have the money. I mean, it happens.
Static web hosting and its limits
There is one solution to this kind of thing, and academics like to do this kind of thing, which is static web hosting. So you can actually, for free, put educational content or any web content, really, that's static, onto places like GitHub pages, Netify, Cloud for Web pages, or even QuartoPub has a free publishing platform where if you write a Quarto document, you can upload that Quarto document to QuartoPub for free and get a URL to share with your friends. If you haven't used Quarto before, by the way, it's kind of like the new R Markdown. It's brilliant. Do give it a go. I'll be talking more about Quarto later.
But there's an issue with this form of hosting. It's great because it's sort of abstracted away. You don't have to think about the service anymore. The people who run these services, they think about the service. You just think about your files and put them, give them to the service, and they will service them for you. They'll host them for you.
But it doesn't work with Shiny apps. And the reason it doesn't work with Shiny apps is explicitly because it's static web hosting. And that's why it's so cheap and scales so well, because those files, they're fixed. They don't change. You just give them to a user, and they display them on the screen. That's what static web hosting means. And in particular, it means that you can't have any dynamic R or Python code running on a server. That's just not how static hosting works.
But wouldn't it be great if we could run Shiny apps using static hosting?
And that's what shinylive does. shinylive was announced originally last year. And it's a way of running Shiny apps so that the client-side browser actually runs that Shiny R process or Python process in the web browser. So all you need to be able to run those apps is one of these static web servers that just gives you the files and says, run this in your browser.
But wouldn't it be great if we could run Shiny apps using static hosting? And that's what shinylive does.
And when it works, it works absolutely brilliantly. Python's been around a while, and shinylive for R was released just last month. It was announced at PositConf by Joe.
So what's happening here is that we're kind of taking advantage of the fact that these computers themselves have computational abilities. They're quite performant, and they have that ability to run the server and the client on the same machine, just like that RStudio desktop. And that's what this architecture of shinylive takes advantage of.
Back in the old days, before my time of computing, this kind of thing couldn't be done. It was more like the traditional Shiny architecture, where you have a big server. In the 60s, you'd have machines like this, an IBM mainframe that would take up an entire room, or maybe even earlier than this, an entire building. And instead of working directly in that room, you'd work on one of these machines. This is called a teletype. And there may be several teletypes within the building that all connect to that mainframe. And those teletypes, they're a bit like that web browser client, and the IBM mainframe is a bit like the server.
So it's an old architecture. I mean, it works well. I mean, even into the 70s and 80s, these teletypes, they were replaced with computer monitors. But they were called dumb terminals, because they didn't think. They just connected to a remote machine.
But everybody these days is probably carrying a device like this in their pocket. Or if not, they'll have something like a laptop with them. Or at the very least, a desktop that they can connect to. And there's all this computational power available to all of us that we just wouldn't be able to use without something like shinylive. So being able to take advantage of this, I think, is a real benefit.
WebAssembly: the technology behind webR
So how does this work, technically? Because, you know, I showed a picture of a phone. You can't have R installed onto a phone. So there's something magical going on here that makes this work.
The main technical detail that allows this to actually happen is something called WebAssembly, which was released in 2017. The technical description of what this is is a portable binary code format. And what that means is that traditionally, code, when you compile it to run on a machine, needs to be compiled for that specific type of machine. So you'll have a piece of code, and you'll compile it for a Windows machine that's a normal laptop. Or you'll compile it for a Mac machine, or a Windows machine, or even a phone or a tablet. And these are all producing what's called binary format, the output of compilation. The code that the CPU actually runs, they're all different, depending on the machine you're running on.
With WebAssembly, that's not true. Because what happens is that that output, which is called a binary, doesn't just run on the machine, but it runs inside a web browser. And most machines have a web browser. And the web browser understands that code format. So what you do is you compile your code once, and it will run anywhere, anywhere with a web browser that supports WebAssembly. That's what portable means.
And it's surprisingly good. You'd expect that this kind of thing would enact a performance impact. And it does, but it's much less than you would expect. You really can have high-performance applications running inside web pages with WebAssembly. There are even games that you can play through a web browser without installing anything to your machine. It's really quite impressive. And most modern browsers support it. Chrome, Firefox, and Safari all support it.
There are other benefits to using WebAssembly. There is security implications. Code that runs inside WebAssembly runs inside a container and is sandboxed. And it inherits all of the years of work of security that web browsers provide.
Another benefit of WebAssembly is something called numerical reproducibility. So this is important, particularly for scientific or statistical applications, because there are algorithms that's known as what's called unstable. And that means they're very sensitive to changes in the numbers. Different computers will actually compute numerical algorithms slightly differently because of something called floating point numbers. Which comes about because computers can't represent every number. You know, there's an infinite number of them. It can't represent all of them. So what happens is it has to do approximations. And those approximations are slightly different depending on what machine you run your algorithm on. And therefore, eventually, the algorithm can give you different answers. And that's not reproducible. That's kind of bad science, right?
So what WebAssembly does is one of the things it implements is a strict set of instructions for how floating point numbers should be calculated. So there are certain guarantees about numerical reproducibility of algorithms that you don't get with normal compiled software. So that's a nice bonus that WebAssembly provides.
The way that generally people use WebAssembly these days is either, some people will write it directly, but that's really rare. It's not designed to be written. It's more designed to be compiled to as a target. There are Rust compilers to convert Rust code into WebAssembly. But the compiler that I'm particularly interested in is something called Inscripten. And Inscripten is magical. It's brilliant. Because what it does is allows you to take some C or C++ code that's written for Linux and instead compile a WebAssembly binary using that code. And it provides a sort of Linux-like environment. It's been around for a few years. It actually predates WebAssembly. I first saw Inscripten in about 2014, I think. Back then, it didn't use WebAssembly, but it still worked really, really well.
And it's used for a few different projects. So there's SQLite, FFmpeg, DOSBox. These things can all run in the browser because they're using Inscripten to compile that C code into WebAssembly code.
Challenges of compiling R for WebAssembly
Now, the full process goes kind of like this. There are programming languages like Python and R that are written in C or C++. Their interpreters that read the input code are written in these languages. So, well, we'll just give that to Inscripten. Produce a WebAssembly binary. Job done. Off to the pub. But it's not that easy.
It's actually quite difficult because of restrictions that WebAssembly code runs under in the browser. So, for example, you can't open local files or any network sockets from inside WebAssembly. And that's a shame because things like R, you can do read.csv and give it a URL. And it will download that data for you. And that's really nice. So that's a shame.
Threading and forking is difficult in WebAssembly. There's no native threading instructions. Graphics and font support is a bit difficult because WebAssembly doesn't have access to something called the JavaScript DOM. So you have to kind of work around that. And probably the biggest problem is legacy code. It turns out that with these programming languages, it's not all C or C++. There is code from 1972 or whatever that does a numerical algorithm that has been around for years and nobody's touched. Written in something like Fortran. I've done my fair share of hacking at Fortran 77 code just to get WebR running. And you have to support these things. They've been around for a long time and they're a core part of the language.
So that's quite difficult. It makes things harder than it really needs to be. But it looks like Unix. It looks like a Linux environment. But there are browser security limitations. And the trick with things like this is to replace those older pieces of code with new pieces of code that use browser APIs that allow you to access networks or download files or show graphics on the screen in a safe and secure way. That's the game.
And it works. PyDyed is a port of Python to WebAssembly. It's been around a little while, longer than WebR. And you can install and run certain Python packages in a web browser. It supports a fair few packages, including the scientific stack of Matplotlib and Numbers and Pandas and various other packages. It works really, really well. And maybe two years ago at this point, I remember seeing PyDyed, trying it out and being blown away by being able to run Python in a web browser. I thought that was brilliant. But there was no equivalent for R.
And I kind of needed this because I was teaching at the time. And I had students. It was just as COVID was kicking off. And they didn't have access to a computer cluster anymore. They would have their own devices. And they'd have something like an iPad. And they were doing all their work on an iPad. And I was like, well, how am I going to install RStudio onto an iPad? We didn't have PositCloud or RStudio Cloud at the time. We didn't have access to anything like that. So I thought, well, there must be some way to make this work. It works for Python. It must work for R.
So I made WebR. It's a version of the R interpreter that's built for WebAssembly. And it allows you to execute R code directly in a web browser without supporting R server. That's because the R process runs directly in your web browser. For techie people who know about these kind of things, it does support Node.js to run R code server side. And it is being used, for example, by the R Universe team to run certain things server side with WebR. But really, we're focusing mainly on the front end, running R in a browser. That's mainly what we're focusing on.
WebR in action: demos and packages
I'm going to talk about running Shiny with WebR a little bit later. But before I do that, I just want to talk a little bit more about WebR itself. And the kind of things that you can do with WebR without necessarily using Shiny.
So this is a screenshot of what I've called the WebR demo application. What this is, it's an IDE running in the web browser with an R session. Now, I should say, I actually lied. This isn't really a screenshot. This is a live session. So I can actually interact with it. And this is one of the real benefits of web software in general, is that web software is very interconnected. You can plug things together very easily and communicate over this sort of universal language called JavaScript. And this is an iframe. So it's embedded into a set of slides, which are browser-based, written by Quarto. Quarto created these slides. So this is a real R session. I can get some numbers, do some random numbers, and access the console at the bottom left-hand side of the screen there.
And I actually have graphics as well. So let's do some demographics. And that was very quick. But over on the bottom right-hand side of the screen here, we have a way of plotting things in WebR and looking at the results. And you can download these images. There's a button to save that plot.
In the top left-hand side of the screen is a code editor. This is powered by a piece of software called CodeMirror. So it's very good. It allows you to type R codes. So let's do foo equals function. And you can see that I get autocomplete, powered by R itself. R has autocomplete built in. And because we're running R directly in this page, we can just plug into that to get suggestions.
So yeah, you can write R code and run it. And you can actually save these files. If I hit save, you'll see that it appears in the top right-hand side of the screen. And this is a virtual file system. And this is provided by Enscripten. It kind of looks like a Unix, Linux file system. But it's transit. It lives in the browser. And it's not actually accessing your local files, which makes it very secure, yet very flexible. And you can upload files to this virtual file system or download files.
So I should say this is kind of superficial. If you've used RStudio before, you can get a squint. It's kind of like RStudio in a browser. But I will caveat this by saying it's way less featured. It looks good, but this is really it. No one's going to be doing serious package development in this kind of software. It's a demo of what WebR can do when running in a web browser. But one thing I think is clear is that there's enough there to do the basics of data science. You could teach someone how to load some data, wrangle it with something like dply, and then make some plots. The basics are there. And that makes it very good for teaching, in my opinion.
Another useful thing for WebR is a quarter extension that I didn't actually write. Someone else wrote. James Balamuto wrote this. But the idea is that you can write a document in Quarto and have these runnable code blocks that you can edit your R code on the fly. Click a button and see the results. You can imagine this is really useful for teaching because it means that if a student or a learner is on a page and is taught an algorithm or how to use a piece of R code, they can click that button and see the results immediately. And they can experiment. They can change things and they don't break anything. And they can see what the results are immediately.
The important thing here, I think, is the lack of context switching. What you don't have is changing to a different window or opening RStudio and typing the code and copying and pasting and then pointing this out. Oh, you've got to read this bit of the screen. You don't have any of that. It's just there directly in the page. And that reduction in context switching, I think, is really important.
The important thing here, I think, is the lack of context switching. What you don't have is changing to a different window or opening RStudio and typing the code and copying and pasting and then pointing this out. And that reduction in context switching, I think, is really important.
And it's not just documents. It works in slides. It is going to work in slides, which is good. So if you want to try this out, download Quarto. If you've used R Markdown before, you'll get started with Quarto quite easily. It's Markdown based. And all you have to do is install this extension. And then if you want to add a runnable code block, there's this WebR-R type of code block that you can just put straight in there. And if you're in slides, it will look like this. And again, this is live and runnable. So imagine I'm teaching a workshop or a lecture. I can run the code to get the results and edit it.
You know, a student might ask me, you know, what happens if I remove the word island from group by? Well, I can try it out and just get directly on the screen there. Or I could do something completely different. I could delete all of this and just run any R code I want because it's a real R session. Now, if you've used something like LearnR before, you may have seen this kind of thing before. But LearnR is a bit different in that it relies on a shiny server running somewhere. While this is completely statically hosted, you can put this on something like GitHub Pages and you don't need to run that shiny server.
And again, these Quarto blocks, they run with graphics as well. So this is actually using a ggplot and putting it directly into the slides as I talk. And again, someone might ask me, oh, what happens if you remove the aesthetics to this plot? Well, you can do it live and find out. And it turns out it makes it go black and white. So it's really nice.
The way the graphics work in WebR is a bit different from normal. It actually has something called a graphics device that reimplements the primitive drawing commands of R for a web browser. It uses something called the JavaScript Canvas API. And this is really good because what it allows us to do is take advantage of features that exist in a web browser in our R plotting routines.
So this is an R plot that's designed to show off the internationalization features of WebR. And you can see we've got some Japanese text, so it's a different font. We've got some, I think that's Arabic and Hebrew, I think. And those are interesting because they're written right to left. And surprisingly, this doesn't always work. Even in native R installations, this is actually quite difficult to get right. You need to download packages to, in some cases, to make this work. So the fact that this is running in the browser and just works is really brilliant. And again, that's taking advantage of the years of text rendering features that have been built into web browsers over the years.
Packages are supported. So what we can do is compile packages, but they must be compiled especially for WebAssembly. What you can't do is use normal R packages in WebR. They have to be pre-compiled to work in this WebAssembly environment. And you can't install packages directly and build them within WebR because there's no compiler available in the web browser. But we've built as many packages as we can, and we have a repository, which lives up here. And we have about 50% of CRAN-built packages that you can try out. Now, I haven't tried all of these. They could be broken. These are just packages that compile without any errors. But the ones I've tried have pretty much all worked. So if you do have an R package you'd like to try with WebR, come talk to me. We'll give it a go and find out if it works.
Some examples of useful packages that are available. There's the tidyverse and tidymodels. It takes a little while to load because there's quite a few packages. But they do, the core packages load. Not all of tidyverse is available. The packages such as httr, I think, are part of tidyverse. But they won't work because they depend on network access, which is, as I say, very limited in WebAssembly for security reasons. So those packages won't work yet. But, in theory, they could be replaced with browser APIs. And the core packages for tidyverse do work.
Geospatial packages are available. And, again, this will take a little while to run just because it's downloading packages in the background. But what this does is do a plot of a map. So this is a plot of the US. And, again, these packages, like the sf package, is very big in geospatial statistics. And those geospatial packages depend on a big list of system libraries that normally would have to be compiled and installed to the local machine. And that can be tricky. It's not the easiest package in the world to set up on a new machine. But here it works because all of those packages have been precompiled for WebAssembly.
Databases are available as well. This is an example of running an SQLite SQL database. You can run some SQL code in R. So if you're teaching someone some SQL code, you can do exactly the same thing as before. You can say, oh, what happens if I change my query to say that? You can do that thing. Those packages are available, which is, again, really useful. Connecting to remote databases will not work, again, for security reasons. But we have some ideas on how we can handle database connections going forward in the future.
How Shiny runs in the browser with shinylive
The way this works is that web browsers have a feature called service workers. What service workers do, well, they do a few things. But one of the important things that they do is they can capture network traffic. So what you can do is when you open up a Shiny app in your machine, what will happen in the background is the Shiny app will go, oh, I need to connect to the Shiny server. I need to load, you know, johnswebsite.com, colon, whatever port Shiny is running on, or whatever. There's a connection that happens in the background to a Shiny server. Service workers can intercept that connection and say, no, don't go over there. Instead, go over here. In fact, don't even go anywhere. Just run this piece of code. And that's what service workers do. And that's how Shiny is able to run in WebR. What WebR will do is start a service worker and capture that network traffic that would normally be sent to a Shiny server. And instead, rather than sending it over the network, it will send it to a WebAssembly thread where WebR is running and say, WebR, what would Shiny do if it was running on a server? Give me the response that Shiny would give. And that's how that works.
So what that allows you to do is run the Shiny server itself on the local machine. The Shiny client can be opened in the web browser. And it looks and feels just like a normal Shiny client, because as far as the Shiny client is concerned, it really is connecting to a remote server. But the service worker allows that remote server to actually be running inside the browser.
Now, you can set this up manually. It's a bit of a pain. I do have a GitHub repo that explains how to do all this and set up a static web server and Shiny in the background. But like I say, you really have to be a JavaScript developer to really understand what's going on there. So instead, we use shinylive. And shinylive makes this much, much easier. And it makes it easy enough that everyone in this room could create their own serverless Shiny app. Even if you've never made a Shiny app before.
I mean, Andre's workshop yesterday, we had shinylive running for Shiny for Python. And we had people creating apps, even though they'd never used Shiny for Python before, directly in the web browser. I think anyone can do this with shinylive.
And there's a few options. The first option is an online editor, which I'll show in a minute. That's what we were using yesterday. The second option is to take a Shiny app that already exists and convert it into a shinylive app. And the third option, which I quite like as well, is embedding a Shiny app into a Quarto document or presentation.
So this is a real Shiny app running in a web page on the right-hand side here. And there's an editor on the left-hand side that you can change live and rebuild your Shiny app directly in the web browser. And this is statically hosted. There is no Shiny server running anywhere other than in your browser. And just to prove it's real, I can move that slider and get some reactive results. And if I did want to change the app, I could say, let's just put some Ys on Hello Shiny and rebuild that app. And it just appears straight away. So you can actually build a Shiny app live from practically nothing, very, very easily using this website.
And there's a bunch of examples on there as well. So if you wanted to change to a different example, these are the standard Shiny, R Shiny examples, you can do that and immediately see the results. So this is great for teaching Shiny. As we learned yesterday, it works really, really well.
That is just one way of using shinylive. It's probably the easiest way to actually just get up and running to try it out. The nice thing about the shinylive app is that there's a share button. So after you've edited your app in the web browser, it is transient. It doesn't save your changes. But there is a share button that gives you a URL that you can then give to your friend. And then if your friend opens that URL, it will open in shinylive and run that app for you, optionally with or without the editor component. So you really could write your app in the browser, give your friend the application URL, which it does end up being quite long, but it works.
The next option is to convert a Shiny app. I haven't done this very much. Barrett's the main developer of this R package, but there is an R package, shinylive, which allows you to take an app that exists already and turn it into a shinylive app. So there's a couple of commands there that will install that package. It's not on CRAN yet, but soon, soon. And then one line, shinylive export will take an app that exists in the myapp directory and produce an output directory site, which contains those static files. And it can be really quite small. This is an example that I run, and those files are there, ready to be uploaded to some static web server service, like GitHub Pages.
And all the shinylive service work is set up for you. You don't have to know how it works, really. You can just upload those files, and it should just work. If you want to preview the application, there's a function built into R that you can run, and that will open a web browser with that shinylive app loaded.
The final way to use shinylive is the Quarto extension. So again, there's a Quarto command here that will install the shinylive extension. Then once you've done that, what it allows you to do is in the middle of your Quarto document, literally just write a Shiny app with the right code block type, and that Shiny app will be automatically converted into a shinylive app and embedded into your document. And you really can just write your app directly into the page, and it will do it for you.
So this is a shinylive app that's running in my Quarto presentation, and it was embedded into the page directly using that method I just showed. It was written in the slides and made available on the page. Again, just to prove that this is a real Shiny app, what this is doing is producing some random numbers, and if you increase the number of samples, it should approach some limiting distribution there.
So if you want to create shinylive apps, I recommend the online editor and the Quarto extension. They're both very good.
And other than that, I think I'll just put some caveats. I'll just say shinylive is experimental. Things might change, and we are working on making package loading quicker. Part of the problem today was just that packages for R are just quite large, and they take a while to download on Wi-Fi and load, so we're working on making that quicker. And finally, one last thing to say is that there's no secrets with a shinylive app. When your shinylive app is available for users, they will be able to see the entire source code of your app. That's just the way it works. So if you have things like secret tokens or even passwords, don't put passwords in your Shiny apps. But if you do, definitely don't make a shinylive app, because it will be available to read by anyone who loads the page, so bear that in mind.
Yep, there's some URLs. Give it a go. And thank you very much for listening.

