 All right. Hello, everybody. Happy Friday to everyone. Looks like... Looks like I got sound going to OBS, so we should be good there. Looks like we got a couple of folks in. Sea Grover, how's it going? Happy Friday. Scott, awesome to see you. How are you doing today? Thanks for tuning in and hanging out and all the work that you're doing as always. Retired Wizard, Beata, how's it going to you folks? So quick introduction. Hello again to everybody. My name is Tim and I go by FomeGuy on GitHub and Discord. This is the deep dive program. We're going to be taking a deep dive into various aspects of Circuit Python. If you are new to the program though, and you don't know what that is, you can learn more here at circuitpython.org. Basically, this is an implementation of Python that runs on tiny computers called microcontrollers. There's a bunch of pictures of them on the downloads page here. So you can see there's all different shapes and sizes of these things. And we are writing Python code that runs on these devices and can interact with other hardware that is connected. So, you know, RGB lights, buzzers, beepers, buttons, levers, you know, switches, GPS, radio modules, screens. You know, you name it, you can hook it up to these microcontrollers. And then we can interact with it using this Python code. So again, circuitpython.org, this is where you can go to learn more. This is the main page for the project. A couple other ways that you can learn more if you want to get involved. Definitely join us in the Discord, which is linked down below. The Adafruit Discord, A-D-A-F-R-U-D-I-T slash Discord. There's a Circuit Python Dev channel on there, which is where all of the folks who work on the project congregate and organize the effort, the development effort. And there's a bunch of other channels as well, like Help With Channels and some other things, you know, in and around the Circuit Python world, even stuff that's outside of Circuit Python a bit, but generally related to Adafruit products. You can find discussions on the Adafruit Discord for all that kind of stuff. Circuit Python is an open source project so anybody can contribute. If you want to get involved, there's a contributing link at the top of CircuitPython.org right here, where you can go to see a list of the open pull requests and the open issues. In particular, if you are brand new and you want to get involved, open issues that are marked as good first issue is a good place to get started. Lots of these require a little bit less experience, a little bit less, you know, grounding in the whole project and all the intricacies of it. So that's a good place to start. And like I mentioned, Circuit Python, it's an open source project, but it is primarily funded by this company, Adafruit. This is their website, Adafruit.com. So if you want to help support the Circuit Python project and those of us that are paid to work on it, please do consider purchasing hardware from Adafruit. They sell the microcontrollers, they sell all sorts of sensors and lights and beepers and buzzers and all those kinds of things that you can plug into the microcontrollers. So, you know, kind of one stop shop for anything that is fun to play with using these electronic widgets and things. OK, let me catch up a little bit on the chat and then I'll talk about what I'm going to jump into today. So how's it going? Dexter and Paul SK. Let's see, this afternoon received a shipment from Adafruit. Nice, always a great day when the Adafruit ferry visits. That's one of my favorite days, Matrix Portal M4 ESP box. I'm not familiar with the box. Is that the is that the white is that the little white box one with the couple of buttons on the bottom? Is that what that one's called? Yeah, OK, I am familiar actually with the with the format with the hardware, but I didn't know the name. Yeah, I'll probably be picking up one of these two. This is definitely appealing to me. So for folks that have watched my streams before, one thing you'll know is I'm definitely drawn to devices with screens. I do like working on screens a whole lot, and this is kind of, you know, a bit like a pie portal in some ways. It's got some extra buttons built in and it's got a bit of a bigger frame and an actual box, whereas the pie portal is just the board in the in the display on the front there. This looks like a nice little all in one. You know, not quite tablet, I guess, because it's a it's a little small for a tablet, but a nice little all in one kind of player device, you know, little what is that? I don't know, inch and a half, two inch, three inch screen, something like that is the actual screen on this thing. This is S3 as well. Oh, got some jingle jingles coming on here on the phone. One second. Sorry. OK, that's nothing really that we need. I don't actually see the is there any double quotes for inches? No, I don't see that. Not sure on the size, but yeah, it's a couple inches there on the screen. It definitely looks like a nice little device. So I will be stoked to play with that one as well. Once I get my hands on one. USB 32 S3. It's the light version. Mine has software buttons. Oh, nice. Screen does work. Got one on my desk. Oh, nice. That's good to get to here. Yeah, I know they have this whatever if this is LLVGL or something. I know there's a couple of different layout libraries. And I definitely have have seen that they have some real nice looking layouts, so I'm really interested in this one. OK. So let's talk about more specifically today. That's kind of the broad high level introduction today. What I'm going to jump into is the latest and greatest hot off the press. So Scott is here with us in the chat. Scott's the lead developer of Circuit Python. Some of the stuff that Scott has been working on, even within the last couple of days is this web workflow, which I'm definitely quite excited about. So I've been tinkering around with it just a bit, but I wanted to play with it some more on the stream here as a way to kind of show folks, you know, where it's at today and how it kind of works and where it's headed. And then also play with the code some and see if we can't change it up a bit and make some of the pages look a little different. So I will need we will want Circuit Python open. So let's do that. I'm also going to let's see. We can probably get rid of. Yeah, let's close that. We don't need any of that stuff. Me double check what else is open here. OK, we're looking pretty good. So that stuff. OK. Let me get this preview. We don't really need another preview running here. Nice. OK, it's got the little stand on there as well. Cool. Yeah, I like that. I like that as a little all in one sort of box. One of the things that I have worked on for work, my other job, my day job, is digital price tags. This would might be a decent kind of a dice device for a digital price tag. OK, so one thing I'm going to do is be careful. Careful not to actually docks my Wi-Fi network. Let me. Yeah, that's code pie. This doesn't actually have it in there. OK. We'll just make sure not to open. Ian V. One thing that I could do, though, is maybe make a fake one just so I can show folks the format of this. I don't know if it does it matter the actual name of it, fake.m. Make a fake one of those. And then for just a second, I'm going to pull it over here. Where it's not visible. I'm going to double check that it's not visible. And I'm going to put like a mock entry in here. And then we're going to pull it back after I. Double check that I have saved it and that it is definitely. Not real. So I have a .env file, which I'm not going to open, but inside of it, it basically has the same thing as what I'm showing in this file. Circuit Python Wi-Fi SSID, Circuit Python Wi-Fi, or it's actually CircuitPie, not CircuitPython, CircuitPie, Wi-Fi password. So you fill in your credentials here. This is a bit different than some of the ways that it's been done in the past, like with the secret.py file. I'm also not going to open up. I wonder if there's like a safety thing built into PyCharm somewhere. I wonder if I could mark certain files as like don't open when I'm in streaming mode or something. I know Discord has some helper stuff for that. IDEs would be smart to add some of that stuff. So that is how we get connected to the network. And one of the really cool things about this is that the network connection actually is happening in the background. So I'll try to focus on this. This might get a little better if I turn on the light. I feel like it can focus the screens better sometimes with the light. Let's see here, where's my beanbag? Oh, there it is. Okay, this one here. Try to get this at a bit of an angle kind of. Yeah, that's a bit better. We're not quite straight, but well, okay. When we get straight, we got too much glare. So this is a Feather S2 TFT. This has kind of quickly become one of my, one of my favorite little handy devices to grab to test something because it has a built-in display, has built-in network stuff, right? It's a ESP32S2 so it can connect to the Wi-Fi and grab stuff from the internet. It's a Feather form factor. So I don't have pins on this one, but I have another one right beside it here which does have pins on it. So it fits into these Feather Doubblers. You know, this one's using this Neo-key, two-key thing. So I got a couple of these now and they're a great little all-purpose testing device with the display built-in and everything. So that's what I tested this on. And the first thing I'll do is actually upload the, I'll grab the newest version of this. So like I started to say, I think I probably got lost in the rabbit hole there, but this build, this new build of Circuit Python that Scott's working on, it automatically connects to the network as part of the system. So like my user code right now is unrelated entirely. There's no Wi-Fi anything in here. I don't import Wi-Fi, I don't do anything with Wi-Fi. This one in particular, what it is, is a script that is the simple test for this touch expander, 12 capacitive touch thing right there. So no Wi-Fi in my user code, but this special build, this new build automatically connects, automatically shows its IP at the top of the screen there. So we can then start interacting with this. One thing I noticed, Scott, yesterday, let's see if it's any different today. One thing I noticed though is I actually was not able to access it from Firefox, which was super bizarre, because I did get there from Chrome. Yeah, okay, so no, we're different today. So I did access it today. So on our display there, it has the IP, which is 119 right now. Oh, auto Wi-Fi is checked into main. Okay, I didn't know that was already in there. And so I can hit that IP here. Of course, the base page here is just a little simple test. You know, hello world, gotta start somewhere. FS is gonna be the new page for the file system. Oh, the emojis are different in this one compared to Chrome. Let's see here. Oh weird, is it gonna be opposite today? Can get it in Firefox, but not Chrome? That's super weird. It's still like loading or something? Different font, not MDNS or the HTTP server. Oh, I gotcha, okay, just the connecting is checked into main. I don't know why that's not, so I actually had the reverse when I played with this last night. I had it pulled up in Chrome, but not Firefox. But we really only need one, and we have gotten Firefox so far. Keep going with this one. So, slash FS, this gives you a list of all your files. You can see there's a couple little emojis there like a trashcan and a pencil emoji. So I assume the idea is like you could click that and go to an edit page. And then for trashcan, you click that. Hopefully it would ask you if you're sure, and then it would prompt you to delete that file. And if you click into one of these files, which I will not click into Mv or Secrets Pi, but I'll click into Code Pi right here, it will actually load the content of the file as well. So you could actually download this back off of here or do whatever you want with it. And ultimately, we wanna be able to edit this like when you click the pencil there. I was thinking we should have them close after each request. Oh, this is because only does one socket at a time. Oh, I gotcha, okay. So basically I can have it open in one or the other. But not both at the same time. When does the socket close? Does it close if I close this tab? Or I don't know if I actually have ever looked into the specifics of how that works. The one thing we're gonna do is update this to the newest version. Because Scott did let me know there's new commits newer than the ones that I have. I think we're on the branch. I think we could just pull probably, right? What are we on here? Yeah, I think so. Well, fetch probably first. Don't know when the browser closes it. Ah, okay, so it's up to the client, basically. Depends on the browser and the keep alive settings. Okay. I missed anybody back here. Dexter got an IP. Felt similar, trying to show off a project with GPS. Plus side, it was accurate. Downside, it's yeah. Yeah, I had something like that a couple weeks back as well. I was testing something with GPS and it was like, had to keep cutting stuff out of it to not accidentally put my exact location in there. Okay. You also have it handle multiple sockets concurrently. I don't know. I'd say, I mean, one is probably fine for most intensive purposes. If it, I guess if it could have a, if it could have a second one, even if just for like an error message, like busy right now or something, that might be nice to the user. I don't know if there's a way for it to like, give it a nice error message if it doesn't have any sockets. But, so we fetched, we're gonna pull, I guess it's also gonna fetch, but let's see. We probably need to do export this thing. So yes, it's a, we gotta do this to build my device. Excuse me. So we'll do that while it's checking out here. There is an HTTP code for too busy. Oh, interesting. Okay. Yeah. They returned back to it the code. Too busy. 503. 503 is service, I think it's service unavailable, which I guess could be because it's too busy. I should have, I should have updated before we got on the stream here. Is that right? Not too long here. So the latest version of this that we're about to build and update to has credentials for one thing. So actually I do need to add something to my environment, which I'll need to be able to see the code for. Don't wanna copy paste the name of the field. Like what I'll do is actually have this open over here. Is it, it's API something? Okay. So I'm gonna add a password to my M file, but of course I'm gonna do that off of the screen. I'm gonna pull this over here, double check. Yeah. Going back. Still updating here? Really? Yeah, like recheck it out. Sometimes it gets in a weird state where it wants to take forever to pull. But if I just delete and check it out again, it go quicker file from patch because it's a directory. All right. Oh yeah, it's gonna wanna merge this stuff. I get, well okay, I guess because I changed my IP, but the IP is no longer hard coded at all. You know what I think I'm gonna do is just we're gonna take all new stuff only. We're gonna throw away any changes that I had, which should have just been the IP I think, but it's possible I tweaked something else. So we're gonna go accept write, failed to apply. Yeah, I'll have to figure this one out. I'm not sure I've been having this problem lately on this repo. Rollback, yeah, we'll do rollback. Not building that device anyway, rollback failed. All right, well, at least we tried. I'm gonna make sure that we do have the most up-to-date version. Oh, it doesn't wanna do shouty. Yeah, there it is, okay. Okay, so let's build this one. Make before. Problem is you need an open socket to send a reply. Yeah, got the old chicken and egg problem with sockets. Did that finish that fast? No, it must have failed. We, oh, we don't want that, come on. Back to the doc, what are you doing? CircuPy creation ID undeclared, 637. Creator ID, oh, creator and creation. 637, where does this thing come from? Oh, yeah, got only one usage, both of those. I don't actually know what those are. Oh, USB, looks like USB HID codes, different board. Meant to act like, okay, that's what I was thinking it looked like was a VID, PID, but it's non-USB. So could it, would it have one of those compile time ifs on it? The default to USB, PID. Did I clean? I did not clean. I will do a clean though. We had something left over? Yeah, I probably should have cleaned since we did check out a whole new thing. Okay, should be given on the compiler command line. Nope, I still get the same one after a clean. It's weird that my clean in my history is broken. Make V2 another clean. Is that a actual just uppercase V2 like this? Or does it need a dash flag output to the command line? Oh, okay. Is that, that must be verbosity, verbosity? Let me actually see where the first one went. This one ended up here though. Can IO? Oh, that's just a guess though. It's trying to like, trying to guess what we meant. But I don't think that's right. Can IO? Some dead beef in there. Say free start word. This kind of goes through each one of these files. Auto.c, it's gated behind BLEIO now. Provider make. Pi USB, USB host web workflow. So probably, this is gonna probably throw off the chat while I rearrange this. Yeah, it cuts it off a bit. I'll put it back in a minute though. Move these out of the if. They got just above it or below it anywhere. An extra different looking black box right there. I have no idea what that is. That back down, looking here. Okay, we're all on the screen now. Back, I don't have a sense for how long it got before it failed last time, but feels longer. Pretend like it's longer, even if it's not. Definitely feel like it failed before we got to this long. So looks like we're looking good. Super hot off the presses stuff though, right? This is all pre-alpha stuff. So anybody would like to play along, you are welcome, but there is still active development. V2 is slowing me down because of the printing. Okay, I'll take V2 back out after this one. Nice, we got the build. So we're gonna go to bootloader mode. Oops, there's not a lot to see, but I'll show you the camera while I do it anyway. Back to here, just gonna double tap reset, loader mode, copy to our device. I'm gonna connect also with TO here. We don't need it right away, but I'm sure we will want it at some point. Go back to here, now we're back there, FS. And this time we get prompted for this, although come to think of it, I think I only put a password. Do I, what if I don't do a username? Okay, that seemed to work. No, we don't need to save that. Some of these icons are different. Do the tried Chrome. I don't remember what they looked like in Chrome. I thought they were like a bulleted list, but maybe, well, it's not folders versus, yeah, I don't know, I don't spot the pattern. I haven't tried upload at all. Is upload the browse here expected to work? Let's give it a try. I'll make a, I think I'll just make a dummy file maybe. Let's go, upload doesn't work. Okay, leave that one for later. We can still click into these though, so we're back. We got our authentication, we're on the newest one. It's TXT, TXTpy versus other files. Okay, oh, I see. Okay, I got you. So one thing I wanna try to do is make a page that will give us this in a text area, so we can start trying to be able to edit it. So I am guessing that's gonna be fairly slow going, but I'm gonna give it a try, because it sounds fun to me and I have some ideas that I think will be pretty cool to play with. So to start with, I'm actually gonna just make an HTML file on my computer, because I wanna be able to like see and visualize the page I'm building as HTML code before I start getting it into the C code to return from the server. Download versus view. Oh, when you choose a different file, like whether or not you will, I see. So if I did, I don't think I have a good one. I guess I could do fake in, or does that count as text? No, okay, that one counts as a download. So if you had images or something like that, BMP files, it would download those, but like code files, it will actually let you go in and see the code, and then ultimately hopefully edit as well. Code, edit, I don't know, HTML. So I'm gonna start super basic, edit, code edit, edit, and I'm gonna just have a text area. I'm gonna have a button for save, whoop. Server changes the content type. I did see that, yeah, to application something. I saw the content type in there. And so obviously this is super, super, super basic. I get to choose a browser? Nope, I can copy this after I have it. Oh, that probably killed the chat for a second. Hopefully we're back now. I do want the text area to go below, save button. Doesn't matter, we're not really, we're not really gonna be too picky about style right now, but that one's an easy one we can do with a break tag. And then I don't know, will it get bigger if I have a bunch of stuff in it? I guess it doesn't. 100%, is that gonna be like wider? 100, maybe 90%. Totally guessing at a bunch of this stuff. Mostly I just want a big old box on the page, and then I'm gonna try to put the code inside of it. Oh, it doesn't like to do height, I guess because it wants to wrap. Oh, no, I don't know, hmm. It might not work, it doesn't seem like it does, does it? Maybe it doesn't want, maybe it's because it can't do a percent because that's gonna be limited to the size of the height of the page and the page doesn't have anything else on it, which means the height is almost nothing. So I guess we could just, maybe just hard code some pixels for now. That should make us bigger, yeah. Okay, let's start with that. Nope, we don't need to save that, we already have it. So basically what I wanna do then is where we return this stuff. I guess we have a couple of options. I could either make a new endpoint or I could just reuse the one that's here to see how difficult it would be to make a new endpoint. I've only taken a brief look at all of the code here, so. And I will say too, like I'm still definitely learning C. So we're getting our request in, we're checking the path of it here, so we could theoretically make a new branch of this. Don't bother hosting it from CPY. Hosting the, just use Python HTTP. Well, it's already hosted, I mean, for my local, for viewing it locally, I can, it runs automatically inside of there, so it does have a hosting server inside of here. But I'm gonna try not necessarily host, while hosting it, I guess it is gonna host it, but I'm gonna try like, so inside FS here where it deals with a single file. Just do Ajax from there. Ajax back to local host or oh, to load, I guess it could use what'll be cross browser, could it load? I think maybe I see what you're saying, so let's see. I don't know, well, does the CircuitPy server have allow origins or whatever? Or I guess that would need to be the CircuitPy server or does it need to be the server hosting this file? I guess that's probably the server hosting this file, wouldn't it be? I will need jQuery, honestly, probably to do a request. I guess I could look up a vanilla JavaScript one. Oh man, these kinds of spams, this is the thing that kills me about the YouTube chats. I get these, thankfully I will say I get these a lot less on the Adafruit account for some reason. When I stream deep dives, but I get these a lot on my own account. And see YouTube, I know nobody here is YouTube, but YouTube, if you're out there and you're listening, like this is kind of a ridiculous workflow because like we deleted this because it had offensive stuff in it and the name is still here, which still kind of has offensive stuff in it if we're gonna be honest about it. So like it would be nice if YouTube gave us an actual way, disappeared. I tried delete, I tried delete, remove. I don't know, it doesn't let me. Can you see my remove thing popping up here? Or here, I'll do it on this one. See I do remove and it doesn't go anywhere. Put user in timeout, I guess I could refresh maybe. I don't even refresh it's still there. I think it's cause I'm like the admin user or whatever, right? It's showing me, I don't know. It's super frustrating if I'm honest about it though. This is why I don't, I turned the YouTube chat off for my streams now cause we got too many of these and there's no effective way to delete it. And it's like, I don't know what to do. The user in timeout report, I guess I'll report it too. Okay, I removed it after I reported. Okay, so we just, I have to report to remove. Okay, try to remember that. Okay, let me put them back so we can actually see it over there. Yeah. So I'm actually, I'm going to use jQuery. I don't know JavaScript Ajax. I mean, truthfully, I don't really know jQuery Ajax off top of my head, but I use it more commonly than Vanilla, my other chat go. Here we go. Fetch, fetch API. Is this a newer one? It's like an HTML5 thing, fetch API. I don't think I've seen this before. Who shared this? God shared this. Thank you. Here's an example in here using fetch. That's actually really nice. And that's Vanilla, well, yeah, I guess it must have been Vanilla JavaScript. They added it, does it say for supports? Yeah, everything except IE. Works for me. How will it, it won't be able to authenticate though, or I, it would need to do multiple things, I guess, to authenticate. Why does it have two thens, actually? I don't quite follow the way the promise works. How's it going in future reality? Thanks for tuning in with credentials included. Maybe that one's more like what we'll need for now. Let's just try to print the data, I guess. Can I please help? I don't know. It depends on what you need help with, I guess. Is it circuit Python related? So there's probably a decent chance that I or somebody else in the chat could at the very least point you in the right direction. Yeah, this was one of the things I was afraid of. So this page won't be able to request from the circuit Python device unless it's actually on the circuit Python device. Or I guess if I, I guess if I, I want to learn everything about Arduino, but I didn't find any good source. Unfortunately, I will say I am definitely not the person who can help you learn about Arduino. I know very, very, very little about Arduino myself, honestly. I have used it a couple of times and it got me interested in microcontrollers and things like that, but I quickly moved on to circuit Python and have done a lot more in that world. I find Arduino to be a little bit closer to my actual work, which is programming stuff that's less fun. And circuit Python, I actually do find a lot more fun to build stuff with. So Arduino, I don't end up doing it as much because it feels more like the actual work that I do for work in terms of the types of problem solving and stuff where a circuit Python is a different kind of a thing. It's solving a lot more problems just about how to do the thing in the real world you want rather than like as much mundane code intricacies and stuff like that. I think you would need a course header. Yeah, I think so. I think, well, I think, I forget the exact way it goes if it needs to be. I think it would have to be the server that's hosting this file would have to allow the page to make the request from the other server, possibly the other server, in this case, the circuit Python device may also have to have the right kind of header thing. One thing I could do, I guess, is we could mock the whole thing. Let's go through this way, actually. I mean, we could take code from here, put it in here, and theoretically this page could be local host. Won't be FS, but I could request CodePy, I suppose. Network error? That one's not really, I guess is it still cross origin because it's on a different port? That make it count as cross origin? Observer hosting the HTML file needs to return a course header. Yeah, I don't know how to do that, though. So, I mean, this one is inside of PyCharm is what's making this server. We could put our page inside of here as well, and then instead of loading the PyCharm one, we could load, yeah. Now we actually got data, I think, and we got all the content back. I think our code is still treating it as JSON. Now we got it printed. So let's not print it, but instead drop it into the text area. I'm gonna redo this thing. I don't care for this syntax. I'm gonna make sure I didn't break it. Nope, still works, okay. So then instead of console log it, we're gonna put it in the text area, which we can go document.query selector. Maybe it can just do text area. I guess we only have the one. Ideally, well, I guess we do have an ID on it. Let's do it by ID, let's do it by ID. Enter, enter this, I guess. I'm a lot more used to jQuery for setting stuff like this. I don't do a lot of vanilla JavaScript. This will be a good adventure, though. So let's put data there. So I think that makes it show up, right? Let's see. Yeah, now we've got code inside of here. So I guess one thing we could do to make this closer is we could go directory FS. We could put code pi in here. We could say FS here. The port will have to change, I guess, when it gets hosted inside CircuitPython. Man, I know your country. Yeah, if you mean me, the country I am in right now is the United States. This would be pretty close, at least, though. So we're still fetching that. Okay, so let's see, can we get the device to return this page to us? So, Scott, are you thinking like a new URL, basically? So right, because right now we have slash FS the root, and then if you go to any particular file, it's FS in that file. Are you thinking like edit like this or something like that in order to go to the edit page for that file? Or were you thinking directly on FS, this page would allow you to edit? Although I guess we do need one that returns the content by itself, especially if we are gonna populate this thing with Ajax, so we will still need one. That's just the thing by itself. I was thinking slash edit, okay. So let's see, I'll see if I can add a new one. I may be able to copy paste what's there for FS and get the working, or I guess it's actually probably pretty similar to what's there for the index, which is just the hello world, where does that one come from right there? Maybe that one is not the best one, because it, oh okay, it's just else. Oh, what's on CP? CP stuff is simpler, CP version JSON. Oh, I see, let's check in here, devices, conversion, no one has none, because I don't have any other devices on. Interesting, okay. This part's all the same. Reworked it more now, is it pushed already? Am I behind on the commit? Actually, maybe FS, it probably would make sense to copy the FS one. Is it already has all the stuff for the file in the path as well? Don't think so. Do we wanna authenticate it on the edit page for sure? Who did we end up here? Feels like we have like an extra thing, doesn't it? Is N need to be a count of the number of characters? That need to be six for slash edit slash. It's been compared to do a starts with sort of a thing. Oh, okay, string compare should work for a single path. Well, I think we need the, I think we'll need the starts with too though, because it'll be edit slash, and then you'll have this still, I think, right? In the actual request. I'm gonna split this so I can look side by side without going up and down over and over. So for one thing though, I am gonna try to just like, let's return something. Let's make sure I can actually create a new URL and respond to it here before we get too far ahead of ourselves. I was thinking it'd have a hashtag, which isn't sent to the server. Oh, okay, I didn't catch the hashtag in your thing there. So then it would, I see, the JavaScript can access the hashtag, which will then allow it to make the Ajax request with the name that's in it. Okay, that makes sense. So does, is there one of them that is a string compare? Is honestly my level of C coding here. Yeah, here's, well, that's string compare method get. I think that's close enough, right? My level of C coding is definitely copy paste. So then we would not use this one because it looks like string compare does only take the, really want this over here though. Of course now we're totally, really no, stop, why? This one, find in this one, slash edit, there we go. Got two things, two things we're comparing and then if it equals to zero, then we know that they're the same, okay. And so I do want to be able to just return something here. So let's see, probably makes sense to start with the most simple one. So if they're authenticated, then return them a hello world. They're not authenticated, then return them nothing for now or while return them, whatever this does. I think I probably messed up the closing brackets. Inner bells, rain, see ya. Retired wizard, thanks for hanging out for a bit. Looks like I had the chat paused for a bit. Shrink and perk, yep, was thinking to have hashtag, yep, C code in this decade, in a circuit path on live stream, that's right, yep. A deep dive one specifically, but, yep. What have I done wrong here? I swear I must have just, there must be my brackets or something has gotten, oh okay, well what is, these things are just randomly here. That's definitely gonna be part of the problem. How did I get that? Randomly added it. Okay, maybe fat fingered an enter or something. Somehow I got those, had a place there. There we go. Missed my double tap. I guess maybe we should have changed it from hello world at least to something else since all of the other end points already return us hello world. You'd get hello world though. Either that worked or it happened to break in such a way where we still got that. Let's try one more like that. Always paranoid when I do stuff like that that I didn't actually make it work. I just made it do the correct thing accidentally. So one thing is eventually we'll be text HTML. There we go, oh, oh, content, yeah, content length is hard coded. Okay, that's all right though. We don't necessarily need that. We're gonna send something else anyway. So what is the best way for me to send back an HTML page though? About like FS, FS is dynamically generating a page. Oh okay, so it sends more after the fact, interesting. Sends like the beginning of the response and has it chunked and then it can basically send chunk over and over. And I guess then with send chunk it's not having to know the size of each chunk like it does for this one. I guess that's a pretty good place to start. I don't know how to log out. I guess we could have tried unauthenticated. It didn't have me log in again actually. Are we still authenticated? Probably does like keeps it cookie or something. Yeah, we are still, okay. Okay, so can I maybe minify my page? Is it bad to put it all in one thing? We'll find out. You to make FS set the HTML type. What is FS doing today? Oh, FS the root by itself or FS with a file. I guess with a file it gets the file type. Did I miss it? Where did it go? Oh, now we have another one of these though. Here we go. Oh, yeah. Oh, well, no, it has text HTML. Maybe that's not what you mean. You to make slash FS set the HTML type. Then you could edit it on circuit pi. Look for that text. Text in the file name? Not sure I follow. Let's go back to bootloader. See this one. All right, fingers crossed. If this gets us to return this HTML page, this is a pretty decent workflow. It'd be nice. I'm sure we could make a Python script that would minify for us. That way we wouldn't need to use whatever page this is. But we had something like that. This is pretty doable as far as being able to iterate the pages if it ends with file name. Yeah, I think I did see some stuff like that. So that's the list right there, isn't it? Yeah, it ends with, but this I guess is still the list. Yeah, it's like inside here. Okay, next one. I see, I see. Okay, so do we have HTML page? Oh, look at that. Okay, we didn't get the fetch, but that's fine. That's pretty good. Uncaught syntax error. That probably means our minification broke something, actually. Opened at line one column 36. This is good, though. We got the page back. It's gonna be minified, I guess. So it's not gonna let me see the source very well. Also, I may have, we break it here for function body. Yeah, I'm thinking something in the minification broke it. And then I think, unfortunately, are we stuck now too? No, okay, we can come back to here. Does it keep loading? So it stays loading, actually, the whole time. Seems like our fetch maybe is breaking it. So one thing we can do is let's take the minified code and actually try that, because that should work in a server the same way. Pretty sure. This will tell us we do have something wrong. With the minified version. Oh, my single line comment. Yeah, that makes sense. Can't do that, if we're gonna minify. Let me change the chat here. Sorry, this is probably gonna get huge. Or what's that bit? That these ones that we're replacing this? So the reservoir load HTML. Copy this? Why is it not giving me just copy? Copy, and I copy. What does that look like, actually? I'm curious. Oh, it just gets too big, I see. Make sure we're looking good still. Yeah, now we're back, okay. And let's see, I need to get the updated. We should, maybe I should try already. Let's see, Python minify HTML. It's got its own thing, minify HTML. One pass. How do I run it? Rust HTML minifier. If we bake an HTML page in verbatim, then we could gzip it. Then unzip it and show it to the end user. Pretty cool. Oh, the browser will unzip before you, even better. So we don't even have to waste time or CPU power on unzipping it. Nice, ends with file name undeclared. Was it, what was it before? No worries. Not a problem. We are on the cutting edge. We are definitely expecting stuff to change. I guess one thing is we're not gonna be on this port, so it's not actually gonna load for real. But if we get the HTML and it finishes loading and the JavaScript doesn't have an error, other than not being able to load the content we told it to, then we're doing pretty good. And it still shows loading forever, though. Maybe that's what the fetch does. Oh, okay, this time we did get same origin, so that is probably because of the 8,000. So actually, we are getting pretty close. Does local host work? Ah, gosh, dang it, really? Okay, at least I know how to take care of it this time. Yeah, I don't know, put the fuelers out there. If anybody knows anybody that knows anybody that knows anybody at YouTube, like that's a pretty big downer for YouTube. Like honestly, in my own streams, like I said earlier, I pretty much always just turn the YouTube chat off because of those things. If we could get that message to them, I'm sure they got all kinds of people bigger than me and us telling them that, but it'd be really great if we could have a chat that didn't get that stuff in it. We'll push changes once put works. Oh, nice, yeah, so then ultimately our page here we'll be able to, when you push the save button, it'll make a put request back to that view that you're working on, or I call it a view because I'm coming from Django world most of the day, but that endpoint that you're implementing. You know if local host will resolve or should I just go like slash FS? Maybe I should just not put anything on there. Will that know to, this one we could test local as well, couldn't we? Yeah, this one does work, okay. We actually do have the right code, right? Review page source, source. Yeah, that should work, I think. That should be better than local host even, I think. Circuitpython.local. I did try Circuitpython.local yesterday and I didn't end up getting anything. Although thinking back on it, I think I may have tried it after I already had one open or whatever, so I might have been running into the only single socket issue when I did try it. Think you want to omit domain, okay. No slash, that's what we ended up on. Good, let's see here. You should not put the host name in the locally served, okay. The command line, you can try dig Circuitpython.local. What is dig? I've never seen that one before. Invalid option. Oh, okay, domain lookup. All right, so I did reload it. We're back up and running now. Dig local like that. Quite know what I'm looking at, truthfully. I see, and that looks like a local IP kind of. I don't see any 119s, which is where I'm actually, whoop, where I'm actually finding it in the browser at least for right now and what it shows here. Let's try it back to here. Okay, FFS, oh hey, whoa. Wow, we still have infinite loading syndrome so I'm guessing we still have a script trouble. Maybe it's trying to load now slash edit slash FS slash whatever, maybe that's the next problem we have. Oh, we actually have no output to get a response. I guess this is our infinite loading thing is this does not think that it has finished yet. Can you use the debug screen in the browser to see what it's doing? Yeah, I think, I mean, a little bit here we can. Right now, at least it's not actually printing anything so we, oh, okay, so we don't have any errors or at least it didn't un-cott, impromptu type error, network error, attempting to fetch resource. What, we saw that on something earlier, didn't we? Your network error. It does, that does sound very familiar. Ah, okay. Yeah, I think there's also a bit of a delay as well. Sometimes, so the chats come in a little before or after I'm ahead a little bit, whoop. Okay, this thinks it's like some kind of, not just a cross origin. Okay, let's look at what it's requesting. Okay, FS code pie, yeah, it looks like it should be the right one, right? Is that path work if we, oh, these ones are stuck now too, hmm. Oh, there we go, okay, I stopped that. As soon as I stopped that, this one was allowed to resolve. These probably show fail now, I guess, right? Well, the page succeeded, but this one, yeah, shows like didn't complete, basically. That does return fine. Do anything more in the console? Let's say. But time here, thanks Tim, thanks Scott, have a good weekend, yeah, thanks Paul, thanks for tuning in, have a good night, good weekend, all that. That is weird, copy URL. It's the same thing that definitely does load this page. And it's not the same error that we got with the course. Do it, or it hasn't done it yet at least. I wonder, probably the authentication is the next, goodness gracious. I hope this is not the new normal for the deep dive YouTube chat. Credentials is my guess. I bet you it's basically, it's made the request and it's sitting on that alert pop up essentially, right? Obviously it doesn't have a screen or whatever in there, but that's my guess, is that it's waiting for the credentials. So I did start to see, where's that MDN page? I mean, I know the right place to learn CircuitPython. Yeah, the Learn, Adafruit Learn system. Do a couple of good places. Welcome to CircuitPython. CircuitPython Essentials, Community One. This is probably a good one as well. I mean, this is a high level look and shows you the Discord and some other stuff. Sorry about that. And then Essentials is another really good one. And then beyond that, I would say just like, look for a guide that either has a project that you're interested in, or look for a guide that matches a piece of hardware. So like buy a Circuit Playground Express or a Circuit Playground Bluefruit or whatever device interests you and then use the guide for that device. But those are some good places to get started. So let me see that MDN fetch. Cause I think this started talking about credentials, right? The other option is we could try turning off the credential check in the code and just see if it's able to make the fetch without it. Fetch won't send cross origin cookies. All right, so this was actually two pages, right? I needed the usage page or whatever to get to the one. Yeah, quest options. Credentials. Just credentials, same origin, which seems strange. Credentials include. Well, that like piggyback off of the fact that I have already answered it once on my own page there. Or was that? That was inside of fetch. You know, the weird thing is though, well locally, but it doesn't write. It doesn't actually have the, doesn't actually have the authentication locally. I guess that's gonna want to comma there. Definitely got to make a Python script to do this. They can just ride alongside the repo there. So I can just make the edits in the HTML, run the Python and then copy the minified one. Let's see. Diveolve in the YouTube chat there. Hey, I recommend getting the best data fruit circle Python. Aboutable you can afford and try in a few guides. Yeah, that's a good way to do it. Definitely find a device that's in your price range. Get that and then look for the guides that show projects with that device. And also the main guide for the device. All the data fruit devices will have a guide that's specific to that product. And if you're like brand new to coding altogether, I recommend probably a circuit playground device. If you're already have some coding knowledge, then I would say which device you pick probably depends on the kind of projects that you're most interested in. No headers. Okay, let's see if we can add our authentication headers here. Not gonna worry about, not gonna worry about it. I chose a, I didn't choose the most secure password. Obviously I'll change this before I do anything else with it. So I did, I was able to log in with a blank username. So I assume that can be blank. Should we need a space? Feels like we would need a space after basic. It's like we would need a space. It doesn't show one. It does here though. Yeah, yeah, yeah. I think we gotta need, I'm gonna definitely need this. I'm gonna double check too actually because I'm not positive that that was the password I did, something like that. I don't wanna show this file. So I am gonna move over here and double check. Yeah, okay, close that. Move it back here. All right, so nobody come to my house and log into my circuit Python device and change my files please. Even though the file changing doesn't work yet. Instead of credentials then we'll say headers and we'll say headers and that will send headers for us. We will see if it works. Fun house is fun. Definitely agreed with that. Plus one for the fun house. Are you doing connection close header so the browser won't reuse an open socket for additional requests? Very good question. I do not know. If that is something that I would have to do explicitly myself in one of these pieces of code then no, I don't believe that I am doing that explicitly in any of the pieces of code that I have touched. But that being said, I don't know for sure if that's a thing that would have to be done in the code or automatic or if the browser chooses or if it's a default setting or whatever. Those parts I don't know. We did build. We can go back to loader mode. Maybe should be. Definitely do code pi no problem. Still nothing. Dang it. This time it actually didn't make, I mean it doesn't show the request actually. Oh, I guess I should have tried that, huh? We can't do base 64 in code? So blank. Well, what was it? Basic, so blank, nothing, colon, password. Don't need to manage the, oh, let me catch up, sorry. Alternately is the server closing the socket at the end of the response. Also know I had a problem with it closing too fast. You don't need to manage the credentials yourself. Credentials when we make the Ajax request? But I haven't tried. Let me run this one back here. Let's look at what request we're sending. Request headers. You do have that this time. Do we have that over here as well? Oh, all right, we need to stop. Yeah, ah, okay. I think we're on the right track here. And is that, that looks the same to me, right? Oh, and blah, blah, blah, blah, blah. Blah, blah, blah, blah, blah, blah. I think so. Okay, I got a good feeling about this one. I think we got this one. I didn't just mess that up, did I? Oh my goodness, okay. I think we got it. Nope. Just bootloader mode. Oh, still not. Dang it. No headers, so it's like it's not showing. I think the request is just not going for some reason. This one, when I use the same page, does end up working. Of course, it's got a bunch of other stuff in it. Google Analytics, which is nice of got brains to insert Google Analytics tracking in my testing of my own page. Definitely appreciate that, fellas. Thank you. What could be different between these two, though? Why would we not be completing the request? Maybe it's the sockets, I guess, right? Because we would need one socket for the browser to load this slash edit page, but then when this page loads, it contains the JavaScript, which is then making the Ajax request, which would then need a second socket, wouldn't it? In order to actually fetch the content? Yeah, I think that's it, because while this page is loading, I also can't load this file by itself, but as soon as I stop this page, this one will be allowed to complete. So that one finished. It could it just need a delay? Should the JavaScript have a wait for a second? Is there any chance that it's not done sending the page before the page starts executing and makes the Ajax request? Maybe let's just wait like three seconds. HTML blob. You could try adding the connection close header to your HTML blob. This one in. Connection close blob, how would I put that in? Is there an example of that happening anywhere in here? Connection close. Oh, yep, okay. Where would that go? Just at the very end, after all of the content? So it would be in the HTTP headers, okay. It's where are you slash edit stuff here. Capital close, lowercase close. If for sure could delay on closing the connection with KEPA lives, there's are ended by the new line, new line RR connection close and separated. Does that look right for connection close? Heading along with content type. Pushing up slowly, there's the delay. So I think we got it right now. I will go ahead and minify this one as well. Waiting for the three seconds. Maybe that will make a difference as well. One thing I'll do before I just try it live is I will try that on this page. First loads, it finishes loading. We wait three seconds, nothing happens and then we make our Ajax request fill in our stuff. So that does look like it worked. Let's grab that, go back to our minify. Yeah, thanks for the help folks, definitely. Super duper appreciated. Let's go here, build. All right, 13 seconds that build took, not bad. Okay, I could add the close connection every response but I don't want it to close on my side. Since I can't flush the response. I will definitely have to defer to all of you and or anybody because I am not well studied at all and the specific details of HTTP protocol. Let's go back to FS. Okay, and then this will load as well. All good there. All right, three seconds, fingers crossed. It still doesn't finish loading. We still have infinite loading syndrome here. I think it's not gonna work but I do think it waited. There's, yeah, so we are waiting three seconds but we are, still thinks it's loading before it actually finishes. If we turn off Ajax altogether and just return the HTML by itself, will it think that it's finished or will it still do the loading dance? Maybe I should use smaller chunks. Should I not send chunk this entire thing with one sent chunk call? Oh, we need to send an empty chunk. That's definitely gonna make a difference for sure. Let's get a new rebuild there. So we may not need some of the stuff we did. Connection close or possibly the waiting. We'll see what we get this time. Feeling good about it again though. We're taking lower to build. Oh, 14 seconds, okay. So we took one second longer. Just felt longer I guess. We need like a building and loading animation or something for the stream. Have this go, let's have this at least stop for now. I will say it is super quick at starting up the server and being able to respond back to you. It's like really fast at connecting and being available after it boots up. Good night to Shippoon. Thanks for hanging out for a bit. Okay, moment of truth. What do we think? Okay, it does not do the loading dance. And I commented out the Ajax. So we're not expecting anything else. So now the question is, do we want the three second timeout or do we wanna just go straight on? Let's try it with the three second timeout. And then if that works, I'll try it without the three second timeout and we'll see. It actually does make a difference. Feel like we're getting super close now though. Super duper close. Yeah, build. HTTP10 does not do chunked responses, which are nice. Copy paste, paste goes inside the code block, not in the middle of the word code. Yeah. I have some fun copy pastes like that sometimes. Where I end up pasting into the middle of a sentence or something when I was trying to like overwrite the whole sentence or something like that. Let's get the bootloader. Here we go. So we still have our three second delay. We're expecting the page to finish loading. Wait three seconds and then either fail to load the stuff in here or succeed to load the stuff in here. Back to here. Oh, I didn't copy. Wait, what? Hold on. I ran make again. So I can break my UF2. Probably just, it seems like it didn't complete the whole thing. Probably noticed that it's the same or something. Hopefully. Find out. Oh no. What have I done? I'm 119. Oh, interesting. I don't know how we got that, but it makes sense. I know we don't have a cert, so it's definitely not gonna succeed that. All right, one Mississippi, two Mississippi. Oh, nice. I not update it. It doesn't look like it ever made the request. Unexpected token identifier 231. I will say this is kind of tough, huh? Let's check this one. Okay. One seems to work all right. Expected token identifier. How are we gonna find 231? Okay, over there somewhere. Doesn't show us what anything is. Could be sea escaping. Is this part of sea escaping? Is it changing this to have an exclamation point in it? Maybe we should just take that part out. Oh, no it has. Wait, what? Did we get that? I guess when I did this? Indeed. Interesting. I don't even know what that's about. It's like double commented or something. Huh, okay. Okay. Another one. One more try. One more try. Gotta go to boot loader. There's no escaping from sea. Dun, dun, dun. Like we need like a monster emoji or something. I don't know. Or a Sparky. I think Sparky seems apropos for that, right? Okay. I'm gonna keep that open, but I'm gonna pull it over here. Oh yes, look at that. Okay. Do we actually need, we probably don't need to sleep, right? Why are these indented? That's really the default formatting? Hmm, all right. Well, let me say so. It was weird to me, but. One thing that might be possible is, is like I'm thinking back through all the steps I've taken here. And I know right now I have this hard coded, but I think the JavaScript might be able to access the headers that this page has been loaded under. So it might be able to pull this out of the actual headers from the page that it's on when it renders this. And then it wouldn't need to be not only not hard coded, but the user wouldn't even have to enter it again or whatever. They would just enter it the once, or I'm sure it expires at some point, but they would enter it once kind of upfront and then wait for it to expire again. I take the, okay. Yeah, this is the one without set timeout. My second guessing. I feel like I made the build, but I'm not sure. And for 14 seconds, we might as well just make another one. I gotta go to bootloader mode here anyway. So let's do that. Copy it. And did this one finish loading too? Yeah, it does not stick in loading mode, which is nice too. So we should be free to make another request. Of course, right now, I think it won't come up because we're still busy copying firmware, but here in a moment maybe. Here we go. Yeah, don't gotta wait at all. That's awesome. Thank you. Honestly, everybody who's been here in the chat, but especially Scott, Todd Botte, a couple of you guys that were helping me with headers here. Mark, I definitely would not have probably gotten this far without help from all of you. So huge thanks to all the folks in the chat. So that's pretty good though. We're pretty far down the chain. There's still definitely stuff to do, but this I think helps lay out, at least in my head, the way that these things can interact together because at this point, we are able to load any code files from the device. We don't have this part hooked up yet. So, you know, we're not putting this in, but we could, because JavaScript can read this and then use it to decide where this request is gonna go. If we can get our credentials out of the headers, then hopefully we can just reuse that and not need to add it. Credentials include will work if the HTML page prompts for the password. Well, I don't know how to make it prompts for the password, I guess. I know the view does, like this part does check for it and then I guess I don't know actually if it will show it. I assume, actually, I guess I don't know how it works. I assumed inside one of these, it would do the thing that does that pop-up that asks you for it. You know, I wonder, maybe we should go back and try it without those altogether. Maybe it's not actually needing them because when I did add the headers, we didn't, that was before when we weren't closing the response properly. Maybe it doesn't actually need the headers. I feel like I'd be better off not having all kinds of weird multi-line comments. Why don't we, we'll just, it's not the most organizationally efficient thing, but maybe we'll just do the old copy-paste to a new one here. Let's try it without, maybe it might even just work. Prompt is caused by the unauthorized. Oh, okay, so the client knows how to do that then apparently the client when it sees that unauthorized it will automatically do the pop-up. Well, this client, the browser, I guess common browsers probably will do that. Make it. This would be cool if it works without, truthfully. Even if not, I think it should be able to grab it from the header too though. I guess we didn't see, did it have it in the header for this page? Maybe it didn't. Scott had the actual working solution and I was just the peanut gallery. Ah, I mean, look, suggestions help. Even if they don't end up being the exact thing we go with, like, I definitely appreciate the help. Peanut gallery, backseat driving, all of it. Honestly, it's super helpful, to be honest. It's one of the most fascinating things about streaming. Honestly, it's one of the things that keeps me coming back to this exercise, right? It's like super fun to be kind of pair programming with sort of hive mind out in the world. Yeah, so it doesn't need, doesn't need to mess with it at all. It just automatically has it because when we load this page, it's already on there and then this request just uses the parent headers, like reuses them, I guess, so it's actually already there too. And this one doesn't have the code at all. Let me just make sure I actually put that in here and that's what we're testing, but I'm pretty sure. Yeah, this one has no headers or anything. That's weird, we're minified and we ended up with an extra space here. I feel like that space is not required, is it? Surely that would work just the same and be less dense in the file system. Wouldn't that be what you want if you're minifying? Not sure. Okay, so what are the next things we would need to do? We would need to look at the hashtag. If we did want to support like code pie here, we would need the JavaScript to look at this thing, which it can, and then use that to determine the URL to put here. And then the save button, we would have a click listener for it that says when you click it, we're gonna make a put request back to some URL, probably, I guess, including the file name like this, and it's gonna send the data of whatever's inside the text area and then back inside this file, there's gonna be another one of these things that's set up for the put request, instead of get request, and it will actually take all that data, write it into the file, save it on the file system. Does that sound right, Scott? I feel like that's kind of where we're headed here. I'm certainly getting a much, feel like I have a much more full picture now than when I started for sure. So hopefully I'm at least on the right track. I do think that's probably it for me right now, though. So I will be back tomorrow morning if folks are interested. I don't know if I'll be picking up right on this stuff. I may be, because I am pretty interested in trying to work out the hashtag and maybe even start trying to put request stuff. I think so, I was debugging while you went over it. Nice. Nice. Should I, I should push my version of this or something did just get put working. Nice, so we're pretty close. We could meet. We can meet. I can hook up my save button to your put request. And then once all of this stuff is working, the next thing I think, which will be really cool is I'm pretty sure with just a little bit of like linking a style script and linking another JavaScript, I think if you're on the internet when you view this, which is not guaranteed, you might be on the local network without internet access, in which case this is basically kind of what you get. You're gonna get the basic one with no bells and whistles. But I think we might be able to set it up as well where we add external CSS and external JavaScript, which could make this into like super fancy code editor. Like this thing called, is it code mirror? I feel like this is the one I've used before, but I think there's a bunch of these things. I'm sure this is not the only one, but like this where it gives us line numbers and syntax highlighting. I think pretty easily we could make this page have that stuff and make it still fall back to, if you don't have internet access, then you still get this and everything still works. You just don't get fancy line numbers and syntax highlighting and all that stuff, which is all helpful, but not necessarily required obviously. You can still do a lot without it. Okay, I think that is gonna do it for me tonight. So thank you to everybody for watching and thanks again as well to all the folks in the chat for helping me out. Again, I will be back tomorrow morning for my own stream on my own Twitch and YouTube. I'll put links in the Discord when I get started on the same live chat channel in the Discord so you can hang out there and watch for the links or you can follow me on Twitch, phomeguy underscore Twitch over there. That's what I'll be tomorrow morning. Definitely huge thanks to Scott for helping me get through this and obviously just working on all of this stuff in general. I think this is definitely gonna be a really, really neat new way to write code and interact with devices. So I'm super excited to see it evolve and I'm actually really happy to be able to help out even in some small way like this, trying to figure out some of the nuts and bolts of it. So thank you for all of that stuff. Thanks to everybody watching and yeah, I'll catch you all tomorrow if you watch me there. Otherwise, next week we should be back for another deep dive on Friday evening next week. So everybody have a good night, good weekend, all that kind of stuff and I'll see you next time. Nice, pushed the put shortly. Cool, sounds good.