 All right, hello everyone. Good afternoon and happy Friday to all. Let's see here. A few of these chat windows around. I think we'll be ready to go. Looks like I got sound going to OBS at least. Did I start up the YouTube one? I always want to double check that these days. YouTube, it looks like we're going YouTube as well. All right. How's it going, Sea Grover? All right. So hello, everyone. My name is Tim. I go by FOMI guy on GitHub and Discord. This is the deep dive program, which is a weekly live stream program where we are working on things related to circuit Python. Sometimes we are getting into the core of circuit Python, such as today, in fact, we're looking at a core PR tried out again. And sometimes we work on like libraries, sometimes we work on projects, sometimes we work on infrastructure. It just depends week to week. Whatever happens to be on my mind that week is what we get up to during this live stream program that occurs at the same time every week. Friday at, well, it's 4 p.m. central time, which is my time, but it's usually built in Pacific and Eastern. So it's 2 p.m. Pacific time and 5 p.m. Eastern time, I believe. And whoop, I really need this one necessarily bookmarked. So just for anybody that might be new, though, if you have never joined us on the deep dive stream before, if you don't know what we're working on, circuitpython.org is kind of the base website for the project. You can head there to learn more about it. Basically, circuit Python is an implementation of Python that runs on tiny computers called microcontrollers. There's a bunch of pictures of those over here. Each of these devices has circuit Python that can run on it, and when it's running circuitpython, you can plug it into your computer. It will show up like a thumb drive, and then you can edit a Python code file on that thumb drive and have it execute on the microcontroller. Microcontrollers typically have some available iopins along the sides of these devices here. Lots of the different ones have that, which you can connect other hardware devices to. Other ones are more built in, fully featured. In lieu of the iopins, this one has a bunch of built-in hardware, so it's got a grid of Cherry MX keys. It's got a rotary encoder knob. It's got a screen, a couple buttons and things, a couple other bits of built-in hardware. So all these little different microcontrollers come in different shapes and sizes. Some of them are made for more general projects where it's just iopins, and you can hook them up and do whatever you want. Others are more built to be a specific thing like this macro pad here, where it's got a bunch of stuff built in, but the common thread for all of them is that they can use this circuitpython language in order to execute your code with minimal software tooling and things like that. You can just open it up in a text file. If you're interested in learning more, recommend you to head over to circuitpython.org. You can find out a bit more of the high-level information about the project there, as well as join us over on Discord, which is linked down below, I believe, on the screen, a.d.a. fru.it slash discord. All the development takes place out in the open, and we coordinate through Discord. So you can, you know, if you want to ask questions or just have comments or anything that you're interested in about circuitpython, you can chat over on the Discord about that stuff. The Discord, that is also the chat that is below me on the screen right there. That is the live broadcast chat channel over on the Adafruit Discord, and that is where we tend to hang out when there's a live show, such as this one going on. How's it going, Jose? Let's see, what do we got? Testing the new... This is from Siegerover, testing the new Streamcar Racer Featherwing today. Be able to choose almost any MCU and STEM ascensor. This will make a fun and flexible robot. Nice. Yeah, that looks pretty cool. Got the big old switches on the sides there. Built switches. Nice Feather... Feather... I don't know, is it technically a Featherwing plug-in? I don't know, but it's like the kind of standard Feather plug-in there. Nice. Looking cool. Imagine using this, which is a... I cannot see this one. Blue. Is it a... I can't make out what's on that chip there. Thanks for following the Feather form factor. I don't recognize the main chip, though. FPGA. I got you. Probably much harder to use, but it'd be interesting. I see. Okay. How's it going, Jose? As well, in SCUR, as well as Beotograph over on YouTube. How are you doing today? How's it going? All right. So that's kind of the quick, high-level version of CircuitPython. Like I said, you can learn more in a couple of these places, circuitpython.org, as well as the Discord and stuff like that. CircuitPython is an open-source project. It's free to use, it's free to put on your own devices, it's free to run it on your devices and use them for your projects and all that sort of stuff. The development for CircuitPython is funded primarily by Adafruit. This is their website, Adafruit.com, their hardware and software company based out of New York and the United States. They manufacture some of the microcontrollers as well as some breakouts and all sorts of different things that you can hook up to the microcontrollers to do with them. They also resell other people's electronic projects as well. So head over to Adafruit.com. You can see all the stuff that they've got including all of the CircuitPython microcontrollers and all the things that you can hook up and do with them. Then I'll just say, of course, thank you to Adafruit for paying the folks who work on the project. There's a team of folks that work on the project full-time that Adafruit pays. There's also some folks like me who work on the project part-time, all who are paid by Adafruit to do so. Thank you to them and of course, thank you to anybody who wants to purchase hardware from them. That is how you can help out the CircuitPython project in your own sort of way by buying yourself some toys there. That helps them, obviously, pay the bills, which is helping them pay the folks working on the software. How's it going, Niradak? Today, I want to look back at the GIF new animated GIF support, which is currently in a PR for CURS core of CircuitPython, although it's looking like it's fairly close, I think. There's a couple of review action going on with it today and there's a couple updates since the last time I looked at this. We did take a look at this last week on, I don't think it was on Friday for the deep dive, but I think I did it on Saturday for my morning stream. And there have been, there were a couple of changes, I think, earlier in the week that I hadn't gotten back to see or try out yet, and then there's some new changes as of today as well. So we'll test out the new version of this on a couple of different devices and try it out with a couple of different GIFs and just see how it's going here. Definitely super excited for animated GIF support. So I'm happy to test this out, leave a comment if it's working and see if there's anything that we find that's not working and just help it move along however we can. Because definitely excited to have that support in display. A few generations younger than this one, basic stream car racer. Okay, okay. The ones that balance, I see what you mean, stream car. So it's, they balance on the string there and then it uses a motor kind of with a little grippy bit to ride itself along the string. I have seen some bots like that. Okay, so you've got the new designed one here which is, looks like this original one was just kind of wire circuit. You got the new one built around the PCB there. Are the big tilt switches part of the balancing mechanism? Are those like these little hooky, I assume this is like a paperclip or just some kind of metal wire hooky bit here? Are the tilt switches somehow replacing that thing or the tilt switch is something entirely different or are those even tilts? Yeah, I think those are, right? These big tilt switches here one on each side. A little speaker maybe it looks like on there, on off switch. Looks like probably a battery plug, is that one up there? Nice. So yeah, animated GIF, that's what we're looking at. Kind of fair warning blanket statement. Everything that we're going to look at related to this is in a PR7549. So it has not been merged yet. This is not part of CircuitPython support yet, although hopefully it will be soon. So yeah, if you want to be able to use this, you do have to build from this PR branch right now, but hopefully we will get merged in at some point. And then, you know, obviously then you'll be able to just use it in your CircuitPython starting after, you know, whenever it gets merged, whenever there's a new release after that. So that's where we're at today though, is we are just going to build it. So I've actually got it open here. And I think I'm on the most up-to-date version. I kind of want to just double check though. So I think what I'm going to do is if we can find the latest commit and then check and see if my version has it. So this is on one. Shared bindings on disk if I checked out a few minutes ago before I started up the stream ran that. So I think we're on the newest one, but I don't know if there's been commit since then or I also don't know like since I already had the branch, I don't know if it like updates itself correctly or not. Okay, we don't have this one yet. This minimizes, which has been changed. Okay, so let's just let's just go back to main. This could have just been committed after or it could be the way I'm checking it out. Didn't actually work for updating it. I think what I'm going to do is I'm just going to go back to main. I'm going to go delete my local copy of this branch. Then we're just going to check that out fresh again. That way we no longer have old version. I don't know if this updates. Sometimes I feel like it does. Sometimes I feel like it doesn't. So should put us there. Stuff all got closed again though. The switches detect the end of the string. Okay, so you get all the way to one end and that will bump on the edge or whatever. That way you know to turn around and go back the other way. Nice. It's a good way to do it or to stop or whatever you want to do. Doesn't necessarily have to go back the other way I suppose, but so then is this like a string car racer? Is this kind of like what are the wooden cars? Pinewood Derby? Is this like a derby race type thing where everybody is building their own one of these little string rider things and then you'll get together and there's like certain length or whatever. You'll race them to see whose time is the best. Is that the idea there or are you just kind of building it as that bot to play around with? Like a more organized race thing going on? Because I've definitely seen that for the wood cars. I've never seen a string one, but that sounds like a lot of fun. Definitely be into it. I'm a sensor. Okay, so we want shared bindings on this gift. We're back into here. Okay, now we got the latest one with the updated comment there. So we know we're on the most up-to-date version, so we'll go. We want a Raspberry Pi. I think let's do a expressive first. I have a couple of different devices we could try it on, but Feather TFT is kind of just like my default grab-and-go testing device these days typically. So here's our drive. We'll start on that one. Move them out for speed, smarts, autonomy, and longevity. I gotcha. Okay, so there's a different, what do they call it, different kind of like different versions, different classes or something different competitions to take part in, whether it's like fastest or most automated. Oh, let's go up to expressive, and then let's go make clean first so that we rebuild entirely. We need to do export this one dot, dot, slash, ESP, export. I think we're really successful, but it doesn't look normal. Right, usually it prints out like firmware.uf2, something, something, and then there's like, I don't know, file sizes or something, I think. It prints out on a nice little table at the end there. I did see some stuff back here that was, goodness, please, not this again. I can't climb in the window. Okay, these are warnings though. Unused operation type. Is this in anything to do with what we're doing? Panic Arch? No, I don't think so. Okay, let's try just try another clean real quick. Clean one again. Just verify that's like that. I don't know if we're actually back. Probably the YouTube link is broken, I guess, right? I don't think I can make the YouTube link work again. We are back. Are you watching on Twitch or YouTube, Jose? Very curiosity. I'm not sure if I need to be doing something for YouTube more. Still say live here. Back on YouTube, okay. I don't know how they got it linked up right, but that is good to hear. Thank you for the confirmation there. Okay, I think we're back. We're back. Should be back on both. Let me double check here. I don't know what that was. Usually that coincides with like weird stuff with USBs, but I... Nothing actually got plugged or unplugged when that happened. I don't really know what that was. Hopefully that's not going to be a thing that is happening a whole bunch. Or at all anymore would be good. Let me get a couple more. So yeah, I just locked up. Total computer just locked up all the way on me there. Had to have a forced power restart it. Okay, let me get back to where we were here. I guess let me just leave Py... Well, we're gonna have to have PyCharm at some point, right? I think we'll need it. I think this thing has a new IP finally for some reason. Brush the first time. Yeah, sorry, folks, for the technical issues here. Thanks for sticking with me a bit while we get back up and running. All right, good for now. Switch that around. We're definitely going to want to clean build after that. I wonder if the build was part of it. So we need to get back in expressive. We need to get back on this export thing. Fingers crossed. Moving my mouse around as if that's gonna help it somehow. Playing the cat partially. I looked over at the cat and I started to grab the octopus on a stick to entertain the cat for a minute so that he would stop trying to climb the window. And then when I looked back, my mouse no longer worked. Slowly realized that everything was frozen. Okay, we got a good build this time. Looks like this is what table of stuff I was expecting last time, which we didn't get. We do have it now, so we're good. So I do have to restart the device. Unfortunately, I kind of... I'll try not to just warn every time I do anything, but obviously since we already had an issue once, if we have an issue again, then I'll just try to hook it back up. Same as I did before. Thanks for bearing with me while I work through any additional issues, which hopefully there will be none of, but we do need to get this to bootloader mode. Which means we have to reset it, which is one of the things sometimes, ever so occasionally, the unplug, replug there tends to be, especially if I do it a ton of times in a row really fast. Sometimes we'll wig out my computer. I'm going to try not to do that. Should probably not be an issue if we just do it once, if we do it slow enough. But just in case, I'll mention that. Let's go copy that one, which is going to be what? Media? Is that media? This feather? But we need the file first. Obviously, build 50. Also, Ronald Covington over on YouTube. I don't know if you're still here. I don't know exactly if this message came before we crashed and came back or after, but I do see the message there. Hello, what are you building? Hello, first of all, thanks for tuning in. If you're still here, appreciate you watching along. I am building, well, if you meant literally, what was the thing, what was the code that was building? It was CircuitPython, the CircuitPython core, but in particular, the version with this PR that has GIF support. If you mean more generally, as far as a project, generally speaking, what am I building? I'm just working on testing the GIF support for CircuitPython. If you are interested and don't know what any of that stuff is or want a more in-depth explanation, let me know, and I can share more about it, obviously. Like most of the folks watching know most of what's going on, so I don't want to spend too much time explaining something if you already know what it is, but I'm happy to explain it if you are new and don't know anything more about what we're doing, but that's it. CircuitPython in particular, we're working on the GIF supports right now, so I believe we have hit the point where we pretty much are going to have to have this back open, so we'll do that, kind of just do as little as possible in the hopes that we don't anger the computer elves in there again. All right, we are maybe back again? Yeah, that one we did not. I don't even know. I don't even know. So yeah, all I could say is I'm sorry for all the issues we're having. Thank you to everybody sticking with us. I don't even know what happened that time just so BS died. Yeah, I don't know. We at least didn't lock up all the way this time, so I was able to get back a little bit quicker, I think, but fingers crossed. Hopefully, like, we're done with that kind of stuff for now. I'm not really ever had this much issue, so I don't exactly know what to do to troubleshoot it too much, so we're just going to, we're back up and running now. I got everything back. We're just going to fingers crossed and hope for the best. Let me just, I'm going to, let me put, let me turn off the preview. Let me keep OBS window open, but just turn off the preview that way. It's just chilling there, we're not touching it, we're not doing anything with it, but it's like over there. Having fun, I hope. Okay, goodness. All right. Yeah, thanks again, folks. Thanks for the heads up. Yeah, I will say too, also thank you for the folks that mentioned. I guess let's go for the remainder of the chat, if you wouldn't mind. If I do ever cut out again, just drop a note in the chat. That way I have another chance to see it, because this time it actually, it took me a second to notice that OBS was gone. The notes in the chat actually are what tipped me off there, so definitely appreciate that. Thank you to the folks doing that. And like I said, fingers crossed, hopefully we're just, I'm going to have you more issues. That would be the best. That would be ideal, certainly. So let's try for that. Otherwise, we'll, we'll trudge along here. Do we want to use party pair of tests? So will anything else need to change? I was not using any of the other arguments here. I don't know that, well, I don't know if we'll need this one. Maybe we could possibly be all right with, I want to say this one, we didn't use the swap done, right? For the party parrot. However, this is still the party parrot with transparency. We may also need to get one with out the transparency in it. I'm not sure where we ended up on that. So I'll have to try that out. What is this frame? So it's just counting. Okay. Need to sleep's anymore of refresh through this. The current version here is auto refresh false. And then it's calling refresh after it calls play frame. I don't know where my browser is that anymore. Third one over. No party parrot gift. We have Homer. Well, Homer's too, too big for this one. Maybe. But I don't have the party parrot that I deleted afterwards. Maybe I deleted it to make space. This one's not doesn't have a huge amount of space for a call rate. I just have to delete stuff. Actually, I do have this here. This one was on six, but I pasted it without any version or whatever. So there's no attribute play frame. Okay, so we have to see what's the new API. So this is still an older one. Was there another new commit fix? No, that was the one we saw a dog fix, I think. We do need to see what's the API now, though, because it seems like it's not the same. So let's see. Next frame, we just change it to next frame. Okay, the first time. Do we need to call this one? We could. Well, it's, yeah, I guess. I don't know. It may not matter, honestly. We might could just not call it here. And then it's like, we're not even, we don't even have the tile grid yet. So I guess this is probably loading the bitmap data. It's not really going to get drawn until it gets added to the tile grid, which has to have the palette created, then added to the group and then just shown on the display. Realistically, we probably could just let it fall into here and then the first time it gets called will be inside the loop. Yeah, so the transparency is still, that's still an issue. Let's see, I guess maybe we turn that off or do we try to angle it? Not great at showing the color when it's straight on, but so we would need to basically have this one filled in with non-transparency, which I think, did somebody say easygif my effects? Let's cut rotate resize video. Maker, skip and copy, loop count, crossfade, don't stack. Use, don't stack frames. Remove the frame when it's time to display the next one. Use the first frame as the background. No, we want it to use, I don't know, just black probably if we could. I don't know that that's going to be any different. 13k, how big is it currently? 13k, I don't think this is going to make a difference. Maybe if we put the, maybe if we added, but I don't really want it to show a blank frame either. Let's see, we could add a blank black frame to the front and then we could go check that box that said use the first frame as the background, but then it will flash when it loops basically. It's still doing that one. So we need to actually fill it in, I think. Overlay, cut, split, frames, don't crossfade, don't stack, why these are like the nesting checkboxes. Interesting. And I make a gif with a transparent background. How to add a background to a transparent gif. Adding the background, upload the background with the gif, drag and drop the background, pull the desired background image together with the gif, drag the background image to the first position, set the duration to one, select don't stack frames. Isn't it going to show, like it works with this one because the guy, the stick figure here leaves frame, right? The first frame in this case is the background by itself, but in our case the first frame, we want it to be the party parrot, but we don't want the first party parrot to get drawn behind all the other party parrots. How big is this? I'm 26 by 128. I'm going to drop frames. Can I upload a new one here? Seems like it. Here we go. Two files selected, delay one, this. Oh, yeah, I didn't read this enough. That's actually what we want. Okay, now we're looking good. It's 18k now. Try to optimize it better. I'm at 16k. A little bit difference. All right, delete that. That starts failing. Repair at seven, paste that there. Now we do need to set that to seven. Interesting dots. I'm actually going to try the one that is, oh wait, did I download this one or that one? Is that 18k? 16.8. Okay, let's do this one. I'm curious to see if those dots are from the compression. With the siren siren coming through too loud. Once we get this merged in, I think we should add a page to display a learning guide as well. Which will actually be good because we could probably show this process of fixing the gifs with transparency in them since it kind of needs to be opaque. Otherwise, it will stack like it was. So having a learn guide page where it explains how to do that process that I just did to give this an opaque background is probably a good idea. Because I suspect we'll have people asking about how to do it. I mean, even if we do provide it, probably some people will ask but we'll have a chance hopefully at least for some folks to see that and know how to do it from the jump. All right, eight. Okay, yeah, yeah. The dots were definitely part of the compression. I don't see the dots anymore. Like I said, the colors don't exactly come through the best. I wonder, so we did, I did try a few other ways of this the other day. Like we tried auto refresh and then not calling refresh here. And this is just calling as fast as it can. That's way quicker. So and then but this does return the result of the amount of time to wait. Theoretically we could go, there we go, and that will get it down to the speed that is embedded in the GIF itself, which makes it much easier to see the actual individual colors rather than just kind of like a chameleon of blinking neon or whatever. You can actually kind of make out the different colors in this one now. And then I think these are all declared in here. So the reason that was .04 was because of the four here, I guess this is in milliseconds. And then we had it as seconds. So .04, about four milliseconds. It seems really fast. Is this the one with the background? Where did our background go away after we optimized? And we came from here. Okay. Here. Partially I'm also learning about the GIF format. Like I don't really mess with GIFs that much. I'm also partially here just like trying to make sure that my understanding of this is correct. Like I'm thinking we got a .04 there because these were on four. So we changed this to 100. We should be getting .1 here, which then would be 10 frames per second on all of that stuff. We go make GIF. That seems way slower though, but it's not 100 seconds. I mean, is that 10 times a second? It's not. It can't be right. That's way too slow for that. This is almost like one time per second. Are these one one hundredths of a second? Does this say? Probably somewhere in the hell, but at least say what the units is. Straight 10. Or enough. My mental decimal math is not so good, TBH. 9. 9 is the 10 frames per second GIF, which does look a lot slower, but it is like artificially slowed down. Like it can actually render much faster than this. At this speed, it pretty much gets rid of the tearing as well, or it lessens it, I guess. You can still kind of see it there if you're watching for it. The tearing on the left side there, where it's just like in between refresh frames or whatever. Should we try back to this one? Maybe we should not have audit refresh on. Is that going to make the tearing better? Is it then this way? It will never refresh partway through? Oh, I took the refresh call out. Yeah, yeah, yeah. So we should refresh before we sleep or after before we sleep, I think. Now we do still get the tearing a little bit on the left over there. Maybe it's like garbage collection running or something. Every now and then you can see kind of like that horizontal line. It's like in between the refreshes or something. That's pretty darn good still. And then we're not even. So if we wanted, so this is 10 per second, if we wanted, if we wanted to try to hit 30 frames per second, that's three times faster than this, which would be this over three, which is pretty close to where we started, I guess, actually. It's not the exact same. We started on four, which would be rounded, I guess, 3.33, repeating three and a third would be exactly. But this is a weird unit, though. So that means that this is in one hundredths of a second. Why is this highlighted? But I can't actually type in it. I will say to this camera, I can't really keep up with it. Like there's more, there's, it looks weirder. It looks worse coming to this screen here, which is what's feeding through to the stream that you all can see. Then it does directly just looking straight at the screen. The camera that's capturing this, I think is not actually, well, and it's also streaming over Wi-Fi. So like, whether, you know, the camera is probably plenty capable, but the network connection and everything is slowing it down to the point where I think what we're doing is we're missing every now and then we are, we're not seeing frames here that actually did occur on this screen. They just occurred and changed too fast. So we don't actually see them up here, but looking direct, you don't have that same phenomenon going on. It doesn't really give you those jumps. The head bob is smooth on the old party parrot. Did we change the xy of this? Is this thing xy at top left corner or who did not change anything with xy? Is there a blank space above it? Or did it start in bottom left? What do you, what even orientation is, well, it must be, okay, it must be face up in this orientation. How big is the actual screen on this? Is it too short for the party parrot? Let's see. I want the product page 240 by 135. So 135 tall and then party parrot was like 126 by 128, I think. So that does fit within 135. We have between 35 and 28, we have seven pixels of extra space. It does look like we're at the bottom left though, right? Let's put a background behind this so we can tell what's part of the GIF and what's part of the background. Let's put a white background in there. So let's see. Easiest way to make a white background, I think. Probably just vector IO, vector IO rectangle maybe, bg-rect. If you want to see frames, you could put digit 1234, 30 as images, generate the GIF, then display, then film with the high speed. Yeah, there we go. Slow it down, but then film at high speed. It'd be interesting to do a zoetrope type thing where you fed it more and more frames that made it seem like it was speeding up the zoetrope and then getting into focus how it, once you get it fast enough, it starts looking like no longer horizontal motion but instead just animation. It'd be interesting to make a GIF that tried to encompass that. So like you'd see the motion to start with and then it would kind of like lock in to just the animation and then slow back down, bring back the motion. I was looking at the GIF writer module as well. I have not played with that. I understand Jeff implemented that I think around the time he was working on cameras. I'm curious if we could just output a GIF from that module as well. I think it's made to work on files though, so I guess we would need, I mean, easiest thing would be to do it on a device with a SD card probably. I need pixel shader. Let's just go bgpallet equals displayo.just one color. Color is white. Oh, oh, oh, oh, that's not good. There we go. Pixel shader bgpallet. What else? Width height xy. Okay, we are top left. We just have a bunch of blank space, which does make sense, I guess. See it in that, but it's like you can see the blank space here. We basically have seven pixels below, which means if we do y equals seven, we should be touching the bottom edge, I think. Could also turn this off. The print probably is slowing it down some. So, can we get the width of it? Let's see. Can we write a line it by saying x equals display width minus GIF dot width? Can we get the width of it? Nice. Yeah. And like if we wanted bottom right, we could go tile dot y equals display dot height minus GIF dot height on the right corner. We wanted it centered. We go display width over two minus GIF width over two. Same thing for the height, although the height will just be a few pixels off. Could we still use make transparent? No, because, well, maybe. Well, but it's going to just return black. Is that right? We still use make transparent? I don't think we can. I mean, I don't think anything will stop us from calling it, but I don't think it will work. What was wrong? It does work, but the problem is that, okay, okay, hold on a second though. So the problem is that there's black in the thing also, but if we chose a different color, it was a different color, we could still do that maybe. Okay, let's try that. Do we have, I mean, we have cool pinks, cool greens. Is that like, should we, that like full green green? That not quite, I think not quite, right? I think it's, oh yeah, we have plenty of room to use like actual green. Okay, let's go here. Let's go full green, full green, make bucket that, save this. I think I can like change this out. And now I, only thing I know is just go back to here kind of but change it to two new files. How's it going, Johnny? Orange is the new black. That's called the green screen. We go this. I want to, one of these times maybe we'll try Crossfade. I think, I don't know if, oh, this is probably not the right kind of gift for that. Crossfade, I guess, is if you want like a slideshow basically, more so than an animation because you're a delay. I will just leave that on four. It's weird this is highlighted but doesn't actually let me type, start typing. Number 10, puppy number 11. That's interesting. Did we get the swapped palette now? We end up on the swapped palette. Maybe we were already on the swapped palette but didn't notice it because the colors are still rainbowy. Now we have our green is green but it's not, well, that's because I took out this. That did not, oh, black is still on zero though because that got rid of the black. It's kind of an interesting effect but not quite what we were after. So let's open this in Gimp. Move green to there. Export this back out. Yeah, it was not actually zero in my case. Should be zero now though. Oh, okay, yep, yep, yep, yep, yep. We turned that back off again. Oh, we got black again. That's weird. I think that doesn't seem like it actually saved our palette. I moved that to zero. Did I not save again? I think transparent is doing white. Yeah, yeah, yeah, white. Well, it's letting, yeah, yeah, letting the white show through from the background. Yeah, okay. I mean green is still, green is zero on this in Gimp at least. So this is number, this is parody part 13. Maybe I just didn't save the last one. Pick that. Delete this. Copy this one. Make sure we got the right one for 13. Paste that there. Close this and update that. Maybe 50 shades of green. Did you look at the right one? Yeah, there are more, there are more shades of green and I am not positive that I got the right one but I'm pretty sure that I got the right one because it's the most highlightery one. And the other thing is even if I didn't get the right one, I definitely put a green at index zero. So the fact that it made black disappear tells me that the palette is not actually working quite how I thought it did basically. Yeah. Oh, this takes color. This takes color, I think. Not, not index. This is not a palette. It's a color converter. Which in a circle like it, it haves kind of like a palette but it's actually a different thing. I need the docks. I think I need to give it a color though instead of an index. I'm trying to give it, I'm trying to give it index zero. It's interpreting it as zero x zero zero zero i.e. black, which black was at index zero before. So things get a bit confusing because I thought it was working one way but now the more I think about this, I'm thinking this thing wants me to give it a color. So we would want like zero x zero zero ff zero zero for green, I think. I'm just going to check the docks before I change it though. As long as this is quick, otherwise we'll just change it and hope for the best. Oh, it does say or index. Color or index. How could that work? It can't tell those two apart, can it? I guess if, well, but it doesn't say tuple here either. I'm going to say maybe if you did color as a tuple instead of x. Interesting. Should probably update, I'm not sure. We should probably update the docks here. I think this doesn't, can't actually work for both. It wouldn't know how to tell them apart. I don't think. That still didn't work also though. But maybe the swapping is part of the problem now, is this? No, that didn't make any difference. Other than that, like obviously now the red is green, but that didn't cut out any parts of it. And this, eyedropper. Oh, oh no, no, no, I clicked. I clicked. Okay, yeah, zero zero ff zero zero. Index only works on palettes lists. Yeah, I think that's right. But the docks here, this one's for color converter and it says it. So I think we should probably update the docks to not say or index unless this can't actually work somehow. Although truth be told, like, it's not actually working the second way how I thought it would work anyway. So it seems kind of possible at this point that I just don't understand how it works altogether, truthfully, because it doesn't seem to be working with color either. So with on disk bitmap, it gives you a, how do you get your palette with on disk bitmap? It gives it to you. It's either like it gets returned by this or it gets, it's on the object after you create it. Does this have one of those? I would love to see the palette and be able to just print the color and see if it's like, it thinks it's this green or what. And as a parsec with make transparent, is it, I'll take it, I'll take a look. I think that's probably with palettes. If it's the one, I do remember seeing one. And I think it was with palettes, but I will check it out. If I can search it up relatively easily goes bitmap.pixel shader. Does that exist for GIF? It's not how this example works. Pixel shader, there is. Can we try that? It's transparent sprites. Yeah. This one is with a palette, which this one does behave more like a list and it does use indexes rather than colors. But it's not quite the same, which color converter is still a bit of a mystery to me truthfully. I thought I understood how color converter worked and what it was and I'm realizing the more time goes on that I'm not quite, my understanding of it's not actually, not actually right, doesn't have attribute. Does have get pixel shader though. Have multiple palettes, one master and one for each frame. Could be. If it's the question mark on the end, I assume you're posing that as a question. I do not know the answer for certain personally. There's definitely, I mean, GIMP. As far as I can tell, GIMP believes there is at least this palette, which does show the most highlighter a green at zero. This just doesn't have pixel shader at all. I wonder if this exists. This exists. So it's not implemented in. We did have get height. Why are some of these are white and some of them are yellow? Why is that? I mean, is it get pixel shader? I believe that's like, there's our height and width. Get bitmap. So I guess we could look at the, can I have an animated GIF more than 256? I don't know that that will apply to me. I'm not necessarily trying to go over 256. I don't quite follow it. It feels like you need a special reader, right? Like, I don't know if I follow that quite right, but it feels like you need a special playback that's built to handle that different kind of GIF there. Not entirely sure though. I definitely don't. How's it going, DJ Devin? I definitely don't necessarily follow what they're saying on that post. Play max delay. We could be testing those things. We are GIF player has limitation. It will fail on those. You try to break the limit? Yeah. The way I understood that post, which I didn't, like I said, I don't think that I did actually understand it all the way. So everything I think I know about it's certainly subject to being wrong, but my understanding was it's like, it needs a special kind of player. You could implement the logic in our player to be able to do it, but you would have to actually do it. My guess is that by default, it would not actually work. And then on circuit Python, my next guess is that it would be even trickier still, because our system, as far as I know, kind of does have that limitation. I don't think palettes can be bigger than 255. But I also don't know that for a fact either. So like, I don't know, but that would be further potential problem on circuit Python, compared to like PC or browser or something. So I'm kind of thinking, is this extra? It doesn't feel like we can ever call this, right? Does anything not work if we remove that? Oh, is that not how you comment? Let's comment this way. Got a lot of tricks possible. Next partial updates, firmware. Let's just see if this one works. The loader, here's crossed, okay. Let's have this in here somewhere, right? Yeah. We could maybe get an individual bitmap, and that has, does that have a pixel shader? It does, actually. I don't think it does, because then you would, you need a tile grid, which will then come together with a, doesn't help you. I mean, we could do it to test it, but it doesn't actually help us get the color. Did I break it? I'm not sure. I used color converter for this, palette support would be nice, but I hadn't built it yet. Does this, you are here? I just posted on the thing, so you probably like just wires crossed me, but the, does this pixel shader? I'm assuming this is leftover. I'm starting to make a build without it and test it out. But I'm guessing that that's leftover, because of exactly what you say, which is that it uses color converter, which is different than palette. Whereas pixel shader here, I think, I think refers to a palette. It doesn't bitmap land or refers to a thing that behaves like a palette, let's say. Probably it's like technically different in a way that I don't quite understand yet, but does it, is it actually expected to work or do anything with GIFs? And if so, how do we do it? Because I actually didn't figure that part out either. If it's there, it's leftover. Okay. I will test without it. I made a build with it commented out. We will test that. Let's do frame count too, actually. We have our delays here. Frames, I, is that print somewhere down here, maybe? FPS, no. Well, it's just counting itself. Frames. Surprised the build didn't throw a warning about the unused reference. Yeah, that's actually, that's a good point. I could do a, I'll do a grep for it also. We are on the wrong colors right now. Sounded in the dictionary. Oh, the thing at the bottom down here? Like this thing, you mean? Yeah, dict table. That's true. Yeah, no, it isn't. I found it only in H. Let me, I will do a, I'll do a grep. Yeah, only one reference in dash H file. Inside shared bindings. And then my build currently has it commented out. So we will see if removing it causes any trouble. So far it seems fine. I was trying to work on transparent. I was trying to figure out if I could make this green transparent, but I, because like color converter here, color converter has a make transparent, but that works. It doesn't, it, like if we do make transparent zero, we can make the black transparent. So I have hope I have, like I'm thinking there's a good chance that like probably we could get a transparent background somehow. But I don't know what number to give this to make it happy. The zero index was my first thought. And then the zero X, like 00 ff 00 for green, that was my next thought, like, like, see here, our black is transparent now, but it doesn't work the same with green. Each frame has its own transparent. Now that can't be true, though, it's got to be shared. It's got to be shared, right? Because I did this make transparent zero here. And this makes all the frames have all the black gone. This is like none of the frames have any black now. And I only called this once. So this has to be affecting every frame. It seems to me at least. You don't look how a tile grid slash bitmap handles it. That's part of the tile grid bitmap drawing as opposed to the GIF. Yeah, well, it's yeah, I mean, it boils down to the kind of the color converter in this space in this case and the make transparent, which I don't know. I don't know how it works or how it's supposed to work, I guess, either. I definitely don't know how it does work. I don't even really know how it's supposed to work. But I know that some portion of it does work, though, that part I do know, because we did manage to successfully make all the parts that would be black transparent. And so they're showing the white through. So like if we let's make sure they're actually transparent, though, let's change this to like blue in the background or something. Yeah, so now all the parts that would be black on the parrot, they're actually showing through to the blue. So our transparency is working, we just need to figure out the right thing to tell it to transparent. I feel like it should be close to green, right? Does anything appreciably different happen if we do one? Yeah, all of our black comes back. Of course, I can tell nothing is really transparent, though. Not updating. I don't think this is updating either, actually. What are we expecting to throw? What am I expecting to show through the transparency? Do you have something behind it? I do. Yeah, the white. The white is a vector IO that's behind it. Vector IO rectangle. And so like what my goal hopefully is I'm trying to make it to where the green that's all around the outside there, we want that one to be transparent. Because if I can get that to work, that would basically bring us back to kind of pretty close to the original how the GIF was with its transparency inside of it. I know the actual transparency in it isn't supported directly because it would need all the logic about like which parts need to be dirty or whatever. But now it has backgrounds in it. But if we could then use color converter make transparent, we could kind of add that transparency after the fact kind of like we do with bitmaps. It's interesting. These don't appear like even when it's on zero, it doesn't do the same thing like it never shines through anymore. I don't think it's updating. Where's the green come from? The green I added to the GIF. The green is now part of the GIF. And to be more specific, if you're curious where it came from, I made a green box in here exported it as a PNG. And then I uploaded both the green box and the original GIF into easy GIF. And they have a setting inside of here called don't stack and then use first frame and then zero delay for first frame, which will basically make it so that whatever the first frame, which in my case was my background image there, this now becomes the background of every frame. And then because it's on zero itself, it means it doesn't get shown as its own frame, just all the rest of the frames contain it as the background. That makes sense. So that's where the green came from in my case. I added it in. I started with black actually. And we did with the black one, I was able to successfully, it was the same thing. It just like same thing we got a second ago where we were making all the black disappear. Yeah, yeah, I just, I hadn't ever used this bit before. I had to search around a bit to find this thing, but we got it going. I think what we'll do is once this gets merged in, I think we will want to update the display.io learn guide with a section for GIFs and we can have the steps for this process because I suspect people, I don't know how many transparent GIFs are out there. I assume kind of a lot like I just searched up party paired and this was the first one I found and it had the transparency in it. So I think it will be good for us to document these steps so that we have a thing for people to follow who want to make their GIFs opaque instead. Let's see also what's over there on the YouTube. Try a different RGB order. We could do that. We did have to swap it. I would think this thing should account for that. Is it different than FF because of the way it's 565? I would expect 00FF00 to work unless there was at least 65536 pallet entries. How many pallet entries? There should be 256 total pallet entries by my understanding because this, excuse me, this is, as far as I can tell, this is our pallet. I don't know if there's a better way to check it or whatever but this is the only way I know how to check it and we have 0-255. Look at GIF.Bitmap0. So I was starting down the road of pulling out the Bitmap0 so the cat has gone back to just tearing back and forth across the house. So if you hear what sounds like an earthquake in the background, that's actually just my cat running around or that for now. I had thought I'd learn guide pages to show how to use it will be good. Yeah. As we, meaning me, see what's being used for or not, we can add features. We could try to pull out an individual one. Let's do this. Let's not put that in there. So instead of 0, use the number for green. So I don't know, I'm not sure what you mean the number for green. If you mean the index for green, so like in this, in this list, green is on 0. So that 0 would be the index. If you mean the color number, like 0xff00. I did try that earlier. Like this one, we can put it back. Yeah, we can put it back. But it did not end up working. Okay, hold on because I took the, yeah, yeah, yeah, I took this out. With make transparent 0x00ff00, we do still get our green. But even if I could get individual bitmaps, like where like an individual bitmap, are they individual on disk bitmaps? Because the actual bitmap object doesn't have colors, doesn't have a palette. If you use a bitmap, meant the index. Yeah, so 0, the index as far as I can tell of green is 0, and we did do 0 in there, and that did black for us instead of green. Like if we do this one, just 0 there. And this will make the black transparent, basically. Everything that was black is now transparent. So yeah, it's like it's, it's contradictory or whatever, right? Like this makes it feel like it's doing black, the literal color, like 0x, you know, like this. But when we try green, it doesn't, if we remove the first frame, 0x is 24 bit, we need the 565 value. How do we find that? Maybe it always does black. Could be. See if this does something other than what we put in. Okay, we can try it. Sure, that's the right number still. If I remove the first frame, if I remove the first frame, I think, like I'm pretty sure I need the first frame because of the way that we used this to use like the first frame became the background. If we get rid of the first frame, then we're not going to have the background. We're going to be back to transparent like like actual transparent rather than just green. Black is 0 and what's that position? No, green is that position 0. And like if you mean in the, in here, green is that position 0. Black used to be at position 0. We did move green to be here, but currently right now with the one we're using green is that color index number 0 inside of the what I'll call the color map is what GIMP calls it. Try that 0x 07e E0. Is green some kind of special color that's hard coded? It shouldn't be, huh? No, to the best of my knowledge, there's no hard coding. I mean, like in user code, right? Like where I'm hard coding it here, like that is the special spot. That's the only place that I know of that it is hard coded. Let's see maybe it always does black and the number is the transparency. A lot of this isn't in the GIF itself in the Python code. A lot of this isn't in the GIF itself in the Python code. Try one, see whether it's still transparent. We did try one earlier. It was not still transparent. I will do it again. So yeah, when we do one, we can see the black. And I don't spot anything that has been made transparent. But I mean, if it was just a couple of pixels in there somewhere near an edge or whatever, just because I like the fading to the edges, then I probably would not know that I'd be able to see it. So for example, bitmaps without a palette. So bitmap equals that color converter, how great and then you give that as the palette basically, I need to figure out more about that. I don't really know what that I don't know how that works basically like, in my mind, like, is it a new thing that YouTube stops streaming if I switch to a different browser tab? Personally, for me, my YouTube will keep going if I switch browser tabs. Yeah. Because I use it a lot for music and other stuff in the background. So I don't have it running right now. So like, maybe it's broken right now or something, not actually checking it. But typically for me, if I am running a YouTube video, I can change to a different tab in the same browser and that video will keep running. And if I can even change to like a different window altogether, I can minimize and everything and it will still just keep playing on desktop, I will say on mobile YouTube does everything it can to not play in the background unless you have like paid YouTube or whatever. Can you toss the GIF into discord? Yeah. Not logged in. I am logged in when I do it. If you mean logged into YouTube, yeah, I am typically logged in when I do it. This is the current one that we are working on. Could be some weird internet glitch. I would not, I will try it not logged in at some point. I would not be surprised if it was treated differently, honestly, unfortunately, I don't think it should be, but Google is I'm sure would prefer you to log in basically. So unfortunately, they might make their services worse when you're not logged in. Try the palette number for green and not your GIMP palette. I'm not sure what you mean the palette number for green. If you mean like the color, like this one, we did try that earlier. It didn't seem to work. Or if you mean something else, I'm not not entirely sure. Sorry. Come on desktop, not logged in. Okay. The mobile requires premium. What does this do if you don't pass this at all? Oh, hey, we got a different output this time, which looks more like what somebody posted a minute ago. That's interesting, right? So all the colors are messed up on this one. It's like we only have green and blue. There's like no more reds. That's weird. No, the palette number that GIMP originally. I will try. I'm not sure if we have an easy way to get back to it. I guess maybe if I open the old one, I open the old one, it might still be there. I'll try. Yeah, that's a good idea. Maybe I just like isn't actually changing the index or whatever. Yeah, man, color converter. The more I do with color converter, the less I understand what it does. Like, where did our reds go? How does the default one have no reds in it? That's like, I'm so confused. Let's see. How can we find it? I guess if we open this one, it was 42 originally. Makes sense, I guess. Can you believe if that works? Setting it to 42 is what makes it work. Should be kind of hilarious. Keep watching the recording, but that GIF animation is a really great addition to CPL. I love it. Nice. Super stoked to have GIF. Yeah, when we did, one thing that is interesting, when we did, well, let's go to the docs. What is the default here? The default input color space. Default is 8888. If we don't specify, then we're going to get 8888, which is what this one did. Maybe that makes sense why reds are gone is because now we don't have numbers that are big enough or numbers that are too big or something like that, right? I guess that kind of maybe makes sense. And so then if we used 565 swapped instead, this now says converted to this though, but I want to input 8888 and output 565 default. Big small indian hurts my brain. So that gives me, this is going from 8888 to 565 and it has 0x7e0, which is similar to one of the ones we tried before, but not the exact same. Just totally put an O in there instead of a zero. That's right at all. There's one out there. Try this, make transparent E07. E007. I don't know how you knew that, but that was it. How'd you do that? Was that like, is that little indian versus big indian? Just swap the highest bit order or whatever, the color, the color is 070e0, but the things are byte swapped to where it's becoming. Okay, and then byte swapped is each one is flipped. So the zero and the seven are flipped, the E and the zero are flipped, and then actually the two together are also flipped, so that we ended up with E007. So somehow we could get that, right? Yeah. So that's the technically the top left pixel, is that right? Of the first frame? It's not swapping within them. I may have made a typo earlier. Oh, okay. No, I don't know. I probably explained it bad, but it does, to me, it looks like they both swapped like the zero or oh, no, no, no. Okay, okay, okay. I'm with you. I'm with you. Yeah, yeah, yeah. Data, I see. I see. Yeah, yeah. Okay. The two different two sets swap, not that they don't swap in internally. So we got that from this. We can, like let's say we didn't want to count on knowing that the first pixel, this is a nice trick, I guess. If you always set up your GIF like I did, where your background is your first frame and your background is full, you know, green screen or whatever transparency color, then this actually is pretty easy because you could pass this in, right? Like we could take this. Well, let's put it back for now. We could take this and be what we passed to here, and then it should still work, right? What do we do there? Can convert string to int. Maybe we don't want hex. I don't know why it broke to REPL somehow, which is odd. There we go. Yeah, yeah, that works. But there should be, we should be able to do it without relying on the pixels too, right? Like we could use another color converter. So we pass in, we know we started with 888. That's what the computer is. And we know we want green in 8888. And so we can get that in the converter, but then can we, should we should be able to do like, how do we do that byte swap over here? Python change byte order? That would work if you don't know your background color. Yeah, using the, as long as the first pixel though, right? As long as the first pixel is actually your background color. Reverse? Is that what we need? Is that what we need? Is it? Actually, no. See it as Oh, something to think about is how the bitmap stores the color versus what the human seat is. Yeah, I would agree. That's a good thing to think about. And I, you're not necessarily understand all the ways in which it works. How do we get from a number to bytes? So our outputted value was this. So I'm trying to start from there. And how do we go back to int int from bytes byte order? Ruck unpacked. I don't know the code. If you can put the code in there, that would help me out. I don't know how to use it that way. Do this. Then bytes, bytes to little honestly, never use ripple and see why it's useful. Yeah, it's really good for testing short stuff, testing little stuff. Long story short, the gift parser reads a gift, which has a palette and converts it to our maybe 565 little Indian. So it gets stored in the bitmap object reading left to right as a human seems backwards. But that's how the display reads them. We could parse the gift into RGB 565 big Indian reads more like human left to right. But the color converter has to swap the bytes. Did it this way with an ion future optimization to Talgrid and the converters. We don't have to convert the color at save time. I gotcha. Yeah, I'm pro whatever is fastest. I think as long as we can provide sample code for people to be able to do make transparent to whatever color they want, like once I figured this out, what the process is to go through this, I'm definitely pro whatever is the fastest way. I'll take a speed at the expense of user code has to swap a few things around. I think that's totally fine personally. It's not up to me all the way. But that's my take on it, at least back to the wrong thing. One of these supposed to be big. There we go. Okay, so I will say no, I was thinking was wrong. Okay, so if you know your color is green, you can go convert my color in my 888 color converter. From there, we can take it to bytes, big Indian, we can then go back to a little Indian there. And we're then ready to pass it into here. And it works. So this kind of pipeline gets us from our hex on the computer are 888 that we're getting from here into working inside of here. So that I think is fine. It might be nice if color converter had a helper function that could help you with this, right? This feels like a thing. It feels like a common thing that you would want to do, right? Like, I guess the crux is here, though, that the GIF reader has like inside of here, it's done the conversion from 888 to 565. It sounds like unpacked with optimized state. Yeah, it is. So then you got the bytes, and you go struct dot unpack, zero, we had your x seven e, zero, it's not actually bytes. Okay, that's how we can use that one. So now when we go to bytes little, and then we go unpack from there. And then though, I think would we also need to go or is no, that's just the number. Yeah, okay. That's not right. Here we go. Oh, that's the wrong color converter. Yes, the wrong color converter. There we go. Yeah. She's the wrong one there. So if you know your transparent color, you can use an 888 color converter with struct or with two bytes from bytes, in order to tell it to make that color transparent. Or if you set up your GIF the same way I did where the first pixel of the first frame is the color that you want to use for transparency, then you can do it the bitmap way, which is actually like, probably more convenient, truthfully, right? Like this is one way. If you know the color, but if you know that first pixel is going to be what you want, then this is like, even way more convenient, right? So you can just go GIF, bitmap, zero, that works. Those are your two options there. Okay, you should make it make that into a function into the GIF library. It would be nice to have a helper function somewhere for sure. Yeah, I would agree. I don't know if it needs to be in the core. I'm hesitant to put it in the core. I don't think we need the speed of the core, but maybe the core is the best place to put it so that it can just be inside GIF IO and not need another library or whatever. The thing is, off the top of my head, I would think to write it in Python just like I did, but we don't really have a Python library that's in the mix here with GIFs, so not really a good place to put that Python code necessarily. I'd be happy if color converter, now, I guess, I don't know how, I'll have to look at, look at internally how it works maybe. Could it not be the case where you pass this in? Could it somehow work where you can make a conversion and give it the color space? Like, could it, instead of declaring it when you initialize it, could it be something like you know, cc.convert and then my color and then input the 8881? If we could do this on the convert call, then we wouldn't need the second one at least. That would basically make it to where the single color converter could basically do this for you. Yeah, we'll have to figure out the best place to put it. Probably could expand color converter. So I understand it though correctly just to double check. The GIFs will always be 565, right? You said it converts internally to 565 inside the GIF and then depending on your input, like maybe it's swapped or maybe it's not, but that depends on your input somehow. If that's the case, then I think maybe GIF, maybe the GIF object or inside GIF IO is probably the place you have some kind of helper function, since GIF is actually the thing technically that's converting it from 888. And then we're using, and I'm confused where the color converter, I really need to figure out color converter better just so I fancy the LED has color conversions. Okay, we'll have to look in there. Maybe there would be a more direct one. GIFs are pallets. I saved them as RGB 565 and the library converts them for display. We'll have to think about where that makes the most sense. If it's in the core or maybe it's like we make a Python layer for GIFs as well, like we have image load for bitmaps, which is like a Python layer for showing bitmaps, for loading them into memory specifically. We're not doing with the GIFs. The GIFs are on disk rather than memory, so it's a bit different, but maybe we need a GIF Python library as well for some of the helper stuff. I don't know. We'll have to think about where's the best place to put it. But I think I'm going to wrap it up there. We're a little bit about 20 minutes over two hours, so feel free to ping me later with questions or thoughts. Yeah, so far, I mean, so far everything looks good to me. The one that I did already comment was the pixel shader is the only thing so far I found that does seem extra. We did make a build with that commented out and it is still working. I'll go back and delete it and make a build. Try it like fully gone, but I mean theoretically it should be gone already because it's commented. So removing that is the only thing I saw as far as like potential change. Everything else seems good to me. Functionality seems all good to me, especially we got it worked out doing transparency now, which I think is super sweet. Yeah, thank you by the way. Yeah, huge hug report for Mark for working on this for folks that don't know Mark Gambler in the chat there is who did the work to make this work inside the core to make gifts actually be a thing that can happen inside Circle Python. So huge thanks, hug report for that. Thank you to everybody for watching. And yeah, I'll be back tomorrow morning if anyone is interested. I think I probably will not be working on this stuff directly. I got some other stuff in mind to work on tomorrow, but I may still change my mind too, so I don't want to say what it is right now. But I will be back tomorrow morning at 10 am central time over on my own channel. If you want to follow along with some more circuit Python stuff. I hope everyone has a good night. The good you know have a nice rest of your evening or day whatever time it is for you. And yeah, I will see you back here next Friday if you don't want to follow up tomorrow morning with me. We'll be back at the same time same place next week as well on the Adafruit channel here for deep dive. Otherwise that's going to do it. So yeah, see you later everybody. I will say real quick again, thanks for hanging in with all of the technical difficulties. Was bumpy there for a little bit. Luckily we kind of got it going and it didn't really wreck us anymore after the second time. So knock on wood, hopefully we won't be having that issue. But yeah, thanks for hanging out and especially hanging in there during all of the...