Adam is a software engineer at The Motley Fool and the author of multiple open source packages including Django Unicorn, Coltrane, and minestrone. We discuss his approach to writing software, the perfect settings file set up, and more.
This podcast does not have any ads or sponsors. To support the show, please consider purchasing a book, signing up for Button, or reading the Django News newsletter.
Carlton Gibson 0:05
Hi. Welcome to another episode of Django Chat podcast on the Django web framework. I'm Carlton Gibson joined by Will Vincent. Hello Will!
Will Vincent 0:12
Hi, Carlton.
Carlton Gibson 0:14
Hello, Will. And today we've got with us Adam Hill, who's a longtime developer and author of Django unicorn and lots of other exciting packages that I'm going to talk to talk about today. Hello, Adam, thank you for coming on the show.
Adam Hill 0:25
Hello. I've been listening for a long time. So normally, it's at like, two times the speed. So this is a little bit different. But I'm excited to talk to you guys. I really appreciate you
Carlton Gibson 0:35
be slightly lower pitched. Yeah.
Adam Hill 0:37
That's right. That's right.
Carlton Gibson 0:39
That's good. So we always ask him, I'm, I don't wanna jump straight into Django unicorn. She's got lots of other things. We always ask about the backstory. And you've been around for a long, long time. So perhaps you could tell us how you got into programming? How Fandango? You know, what's your origin story?
Adam Hill 0:54
Hi. So, yeah, I've been programming for over 20 years. So I've been around for a while. And in my day job at The Motley Fool, we use C sharp and a lot of the Microsoft stack. And so
Carlton Gibson 1:11
before you carry on it, I want to ask you so the I'm always fascinated by the Microsoft stack and the C sharp stack. When you're working when you're working on Django. What are the sort of bits that you miss? What's, what's the, what's really nice bits of working in that in that ecosystem
Adam Hill 1:26
in the Microsoft stack, so I mean, I started working in Django, because I wanted to get away from the Microsoft stack. But the nice thing about it, I guess, is that it's sort of all integrated with each other. If you're on Windows, you SQL Server use, you know, just the whole the whole stack together, whereas Django, you kind of have a little more flexibility. And with that comes a little bit more choice. So you have to choose Postgres or MySQL, and you have to choose Gunicorn. Or, you know, what your serving platform and so it becomes a you know, there's just more choices there. Okay, but there's
Carlton Gibson 2:07
not one bit that when you eat, like even today, you can read Django and you think, Oh, do you know that bit from the from dotnet? That I wish I had that? I wish I had?
Adam Hill 2:16
Personally? I'm sure some people do.
Carlton Gibson 2:18
That's a good, that's a fair answer. I'll accept it. Okay, so anyway, you're at Motley Full full programming, C sharp, you think?
Adam Hill 2:24
Yeah, so I'm looking around, it's like to 2010 and, you know, all the all the fancy startups are using Ruby on Rails, and they're kind of outside of this ecosystem. But my friend introduces me to someone who wants to start a startup, which is for house auctions. So it's the idea is about as dumb as it sounds. It's like, we're gonna start, you know, a house auction at $1, and let people bid and then they get a house at the end. So I was ahead of
Will Vincent 2:58
your time ahead of your time, right? That's an open door and stuff do sorta,
Adam Hill 3:04
yeah, I was, I was like, well, this, this might not work out. But it'll be a fun excuse to try something different outside of the whole Microsoft ecosystem. And so I was reading about Rails, and I was reading about other frameworks. And I came across this Django thing. And it was mostly I think, the ORM. And at the time, it was south, which you could do migrations, and I was like, mind blown, like, I don't have to manually write stored procedures, like sign me up. So I tried working with this startup for a while. And I used Django at the time, I think it was one 1.2. And I really loved Django. And I found all these things that I really loved about it. And I found out that the startup was, was not going to work out for for all sorts of reasons. But that was fine. And so that was my that was my first introduction to Django. And then around 20 2011, our CTO at the time, kind of looked at a couple of us techies and said, if there was any tech stack that you would use, what what would we use if we're starting from from scratch? And so I advocated for Django at the time, some other people advocated for rails and some other things.
Carlton Gibson 4:21
How did you sign up pistols at dawn?
Adam Hill 4:23
Yeah, that was basically it. So it was a I don't remember. It's a long ago. Mostly a conversation. It was like, let's try this. So let's try that. And I maybe I just convinced a lot of people that we should we should try it out. But
Carlton Gibson 4:41
so so so does does that is the long and short of that that a Motley Fool is built on Django with the snake. So
Adam Hill 4:46
yeah, so most of the user facing site is isn't Django. We have some back end services that are still in C Sharp because you don't want to have to rewrite everything and they still work and it's perfect. And we have some WordPress sites as well. So it's a couple of different technologies. But most of what you see when you hit the site is also from Django.
Will Vincent 5:09
Okay, super canal came out, I thought had you use Python before Django or? Because that's also, you know, a big part of the Django experience as opposed to the Microsoft stack.
Adam Hill 5:21
You know, I haven't, or I didn't, I think, when I looked at, when I was evaluating other frameworks, Python was a big point in there. It was like, Oh, I really liked the way that this looks. It was aesthetic. And, and sort of the ecosystem around Django and Python, even at that time, it was still like, oh, there's all these packages that I can use and pull in. And I don't have to rewrite all this stuff. That was really appealing to me.
Will Vincent 5:51
Yeah, I think because for me, I think it was around 2010 ish. When I, I got into programming, and I was in San Francisco, and it was rails Django, and really, I waited it Rails was way more popular. But I thought Python looked better to me than Ruby, and also even then had more applications. And, yeah, I'm always interested to hear what you know. But you know, because a lot of people, they come into their first framework with no knowledge of web frameworks. And so they kind of blame the framework for the learning curve of that. But if you already kind of know how websites work, you skip that blame, right? It's only kind of like your second or third, you're like, oh, maybe it wasn't rails or Django that was so hard. It's just the web is a little bit trickier than I gave it credit for.
Adam Hill 6:34
Yeah, it turns out these things are are just hard in general. So
Will Vincent 6:39
yeah, that's why I tell like, I generally don't deal with technical people in my personal life. And sometimes they're like, there's like hundreds or 1000s of employees, these companies I'm like, Yeah, well, if it was easy, you know, because they're like, Well, you can build Instagram in a weekend. I'm like, yeah, for like, 10 people, but like, you know, a billion. There's a reason, because a lot harder.
Adam Hill 7:01
It's always the scaling that becomes tricky.
Will Vincent 7:04
Right? Yeah. It's like one or two front end a couple Django and then DevOps infrastructure. Yeah. Yeah, for sure. Restart, Carlton, you were you had a thread of questioning?
Carlton Gibson 7:14
Well, Adam, I want to speak to you about your open source packages. Namely, which way round? You want to take it you want to unicorn first or last?
Adam Hill 7:23
Sure. Yeah, that sounds good. That's
Carlton Gibson 7:29
good. come first or last?
Adam Hill 7:32
First? First one.
Carlton Gibson 7:33
Okay. Let's talk. Let's talk about Django unicorn. Thank you. For people who don't know it, can you tell us what it is, and then we can discuss, you know, various aspects around?
Adam Hill 7:40
Sure. So this short pitch is basically it's a reactive component framework on top of Django. So it basically lets you have a Python class and a template. And they kind of are tied together, they're bound. And you can render that Python template inside of a regular, you know, Django template. And then you can have attributes on the HTML. So you could like click a button, and it will call something in the Python class, and then rerender on the front end, and things have changed. So it's, it's the easiest way to explain it.
Carlton Gibson 8:22
And when you say reload on the right, it just realized that bit of the page, right, it's
Adam Hill 8:26
just that little portion of your template. And you can actually target even if you want it smaller pieces to like, reduce the payload. But basically, you know, when I was looking around at things, I don't know if you've seen like, elixirs LiveView? Yes. So basically, they use WebSockets in the back end, and they do this sort of reactive functionality. And I looked at I was like, you don't have to write any JavaScript to have interactivity on your website. That's like crazy, right. And I kind of wanted that for Django. So I actually built a prototype using Jango channels, which Carlton I know you you work on. And I found it more cumbersome than I wanted it to be. So I didn't want to run Redis I didn't want to run a separate process. And so I was looking around a little bit more. And in PHPs Laravel, they have Livewire and instead of WebSockets, to, you know, make that interactivity. They use regular old Ajax requests. So it sounds a little when you first think about it, you're like, I mean, you're gonna make an Ajax request for every update. And then you get a pass back HTML from the server side. Some people are like, that doesn't make a lot of sense. Like it's not going to be performance and you know why? Do you do it when you can just use these WebSockets. But the upside is that it makes deployment really simple, because you're just just Ajax it's, it's already what the server is dealing with. And if you look at sort of GitHub, or there's other examples, but GitHub is the canonical one, if you watch the network inspector, they're passing back snippets of HTML, it's not JSON, you know, with some SBA on top, that's re rendering it. So it's a, it's a pattern that, that lots of big sites use. And unicorn, basically, it gives you an easy way to do that without wiring up all the bits, by yourself. Because I know in Django right now, htm X is really hot, and people love it. And I love it, too. I've used it on some of my side projects. It's really great. And Carson is, you know, an awesome developer and a great advocate for this style of web programming, I guess. But you still have to create your Urals great new routes, you have to make sure your templates are set up in a certain way. And so the one thing that unicorn does is it kind of handles it all. I call it it's magic. But you know, it basically it gives you a pattern for doing that sort of thing.
Carlton Gibson 11:27
Right? So that was the question, I was going to ask you this, this HTML over the wire thing. So the rails, they use the hot wire, right, which is their version, and then htm X has been blown up. It's very big. And I was going to ask you, so you are in exactly the same sort of place the same strategy? What, you know, can you just go over again? What is the selling point of Jenga? unicon versus HGMS? For all the folks that have seen that HDX explode and bigger than that, what do I get extra when I come and check out Jenga unicorn? What would be the selling?
Adam Hill 12:01
Yeah, so the the selling point is that it it sort of gives you this little pattern that you can add indirect interactivity easily to your site, without having to wire up all the manual bits. It also integrates, it's basically Django aware, right, it tries to play nicely in the ecosystem. You can use Django messages inside of your Python class. And things just work sort of as you expect. Validation works the same way you can use forms. It basically it knows about Django, and so it can be a little bit smarter about what it's doing. There's support for Django models and query sets. You know, I tried to just sort of integrate it into the whole, you know, ecosystem. So it feels like it's part of a Django project, as opposed to something that you kind of add on and then have to fiddle with,
Will Vincent 13:01
I want to mention that you have, I think, two screencasts. Now with plans for more, where you go over, like a basic Those are, those are great, like, because it's exactly that question, right? I'm sure I saw, like, researching this episode on Reddit and other places, everyone asks you, Why not htm X? And, you know, I feel like those are the two you have, certainly show it. And then the plans for more. Kind of eager, I hope you get a chance to do those as well.
Adam Hill 13:26
Yeah, it turns out screencast take way more time.
Will Vincent 13:31
That's why I don't do there. So
Carlton Gibson 13:32
it's not it's not just sit down and
Adam Hill 13:35
know. So yeah, I mean, it's just like a conference talk. Honestly, it's, but it's three minutes, as opposed to, you know, 45 or whatever. But between trying to write out a script and make code that makes sense that I can show and then finding a quiet space in my house that I can record it, it's like, I'd rather write some code and just like, put some new features out there, as opposed to making a screencast. So, you know, that's my own fault.
Will Vincent 14:05
I think that's every developer, right? It's like you, you build this thing. And then the demands are like nine out of 10 the selling of it, rather than the doing of it. So
Adam Hill 14:14
yeah, I mean, I have a blog post in my head about sort of, like open source and how, you know, just writing the code and getting something out there is like, just, it's the first step. You're, you're like step zero, basically at that point. And then a lot of the, you know, the were unicorns sort of, like caught on a little bit was more on the marketing side. So like, I built a whole site that has little, you know, small demos that people can play with and see. And, you know, I went on Reddit and I tried to advertise it a little bit. And so, you know, there's a, there's that whole other part of writing code when you're in the open source ecosystem that like, people don't know Really think about or, or maybe don't want to work on because it's the less fun part.
Carlton Gibson 15:05
And I know you're building the bookmarking site dev mocks, I Oh, is that built with unicorn?
Adam Hill 15:11
Yeah, uses unicorn. Basically, I have side projects so that I can dog food, my own side projects. So it's sort of like turtles all the way down
Carlton Gibson 15:26
the Harris Jack in the world.
Adam Hill 15:30
So Denmark teases unicorn and a bunch of my other libraries. And basically, I just wanted to make something to store all my GitHub stars. I mean, that's basically what the the genesis of that project was. Because, you know, I wanted to have a better interface that I could see all those stars, and I could sort of attach notes to them. Now they have lists and GitHub, which is kind of nice, you can organize. But yeah, I wanted someplace where I could you grab all that stuff. And I was like, well, if I'm getting GitHub scars, there's probably other things that I could also pull in and bookmark for later. So there's like Hacker News favorites. And there's all sorts of other sites that I want to integrate with, but that was the plan.
Carlton Gibson 16:19
So that is dead. marks.io? Obviously, your mother, and that's to sign up for? Yeah. Go Go.
Adam Hill 16:28
Go ahead, go, oh, no, yeah, it's free. You can sign in with GitHub. And yeah, there's, there's plans to monetize it, if you want to pay me $5 a month, feel free, you can. But for you know, for most people, they just use the free sign. And that's, that's fine, too. It's, most of my things are just scratching my own itch. So I don't I don't think I'm ever going to make a lot of money off of these things. I have a day job. And that's fine. That's how I that's how I survived. So it's all good, what
Carlton Gibson 17:01
it was good to ask him. Do you have any thoughts on the I have a sort of a bookmark a lot of sites, you know, if KI KI Kumar commands, I see that see them, it's kind of like an append only list in that. They go on to the list. And it might be like 510 links a day. And it saves me having to read them there. And then but the reality is, I very rarely go back sort of process that this is that. I mean, I think that's normal. I've spoken to a lot of people that have the same phenomenon. He's got any thoughts in how we might use something to, you know, surface this
Will Vincent 17:33
crowd and I just want to add that Jeff triplet who I do the news, the Django newsletter with was jokingly saying, Maybe I should just publish, like all my tabs. I did or didn't read on Twitter. And I think most people are like, Yeah, like that. Because
Carlton Gibson 17:45
it types I've got open to this date.
Adam Hill 17:50
Yeah, yeah, I don't. I mean, I have no help for you, because I have the same problem. But if you figure out something, I would love to hear about
Carlton Gibson 18:00
it. Okay. I'm hoping somebody's going to come up with something that will just say, oh, you know, you've bookmarked a site on this three years ago.
Will Vincent 18:09
And you're, like, you know, Matt monastic in some ways, reading Kant at night, you just gotta let it go. And just, you're never going to read them. Like I don't. Like I started today, and it's just empty, because I don't even pretend I don't want that burden of like, I should do this.
Carlton Gibson 18:24
Right. But this is, this is why I use it. So I used to have this problem where I'd have like, 4000, tabs open, I can never find any, any. And I just keep them open at all. And so what I decided was that if I just bookmark every single site that I see the ideas that strikes me interesting like that, every site that I would leave open in a tab, I bookmark it and close the tap. And it's amazing, because now I have like, one, two tabs. And you know, it's really hectic end of the day, there might be 10, tabs open, I never had 50. And it's like a closed loop. Because if you've got an open tab, it's constantly sort of in your decision cycle going do I need to read this now? Do I need to? Yeah, it's
Will Vincent 19:01
an endless loop. Yeah, but like recursive loop or something you need? I use a search history. So like, yeah, very often I'm like, oh, yeah, what was that thing? I wish I hadn't closed it. And I just go into my search history. And, and there it is. Okay,
Carlton Gibson 19:14
so we will do listeners will do a listener shout out to ideas, if you send them
Will Vincent 19:21
attention, though, it's a tension between, you know, endlessly curious, which I think many good developers are and then, you know, not getting bogged down with trying to learn everything, right. I think especially for people, I get this email pretty often from readers who like, I just don't even know where to go. Like, there's so many things to read. And, you know, I think with time, you're kind of like, well, if I needed to turn over that stone, I could, but there's sort of a context. You don't need to like Master everything and, you know, like React stuff. It's like, yeah, it's gonna change every couple of months like, but it can kind of let go of that anxiety around not knowing anything, I think but the first couple years, you feel like you have to keep But with that, whereas I mean, there, you know, so many things. I don't know. I don't go around telling everyone it but like, I don't pretend otherwise. It's just like, oh, I need to do, like, sign up. For me. That's a coping mechanism.
Adam Hill 20:11
I think after the first couple of years, you basically know enough to start. And that's, that's good enough. And then you can figure out as you're going along, and build on that knowledge. But that first couple of years, that's the tricky part is like, Where do I even start here? Like there's, there's so much?
Will Vincent 20:29
Yeah, well, just come out. Yeah, this will come out. So not. So Django con us is coming up, Carlton just got back from Django con Europe. And my talk is a 45 Minute Talk on aligning the Jenga puzzle pieces, where I'm going to try to present the tapestry of Django as a whole as a roadmap for people, because I feel like many people learn it, you know, it's like puzzle pieces, but they're all flipped upside down, you have no idea where you're going, and somehow they fit together. So to at least say, here's the map of Django, and it will take a long time to cover it. But here's kind of context I wish I had those first couple of years.
Adam Hill 21:05
So those are all the pieces of Django to like, build
Will Vincent 21:08
both, both of how both of how a web websites work, and then the Django parts. So models, models, URLs, templates, views, admin, but also like, what are signals middleware, like ORM query sets, you know, so dig, dig deeper into things, that geo stuff, just give a sense of here is, like the entirety of Django. And, you know, so here's the fundamentals. And then here's all this cool goodies. deployment, like as I mean, deployment is such a big topic. But in Carlton, actually, I was thinking of you because you still like multiple settings, files, right? For your deployments, as opposed to one setting file.
Carlton Gibson 21:47
Even these days, is that is that not sorry? Yeah, I don't know. I do like not, I still like multiple things fails. Because you know what, I see people jumping through a lot of hoops trying to fit everything into the environment variables only pattern. And I think it's time for the pendulum starts swinging back and other way where it's like, you know, what, if you're fighting with your environment settings, or environment variables, trying to put everything into an environment variable, so that you can just, you know, change your m file or change your folder in order to change your deployment settings, maybe you want to just, you know, stick that in a separate settings file where it's easy to read, and you don't have these massive amount of machinery generat enable that's needed to be put in place in a view switch environment, maybe it's time for the dependent switch back and other way. And then of course, we'll end up with novel sending files and everybody hardcoding secrets in the wrong places and everything that and will swing back to environment variables or, you know, something, because apparently, we're not allowed to use environment variables anymore, because they can be
Will Vincent 22:48
added, what do you think this? Yeah, I
Adam Hill 22:50
was gonna say, I tend to do both of those things. So maybe I'm like, Yeah, I have multiple settings files for each environment. And then for anything that's secret, I use a m file, to pull the things in. So that might be even more, you know, messier than then out those approaches. But
Carlton Gibson 23:12
the one thing I do agree is you shouldn't put your secrets in the file itself. But sometimes there's various bits and bobs that you need to customize per environment, there's much more suited to have a separate settings file for then trying to push all of that into environment variables. Yeah. You don't want to hard code secrets in the in the file itself. Yes. That's when when the community decided to emphasize not doing that, that was a good step forward that everyone should follow. But, you know, like, all these things, we end up sort of gravy Cheney gravy,
Will Vincent 23:44
the word I mean, now I sound like an old man, but the you know, get out back in the day when it first came out, you could search for AWS secret keys, like you could do, you know, you could find everything. And now I'm sure get lab is the same. You know, they they don't let you just search for that stuff. But you could just, you know, get anything. So I think there's a little more guardrails. But
Carlton Gibson 24:06
I think these days, they might even send you like they might sort of walk up behind, you're quite into a little cough and get your hands dirty. Tell
Will Vincent 24:12
you Yeah, yeah. But I think, like, pedagogically to teach to someone new saying one file, and then you have your local environment variables and your production environment variables. Don't worry about staging, don't worry about all this other stuff is a little bit simpler than a custom command to load different settings files, plus all the platforms as a service require environment variables anyways, so if you're using Well, what used to be Heroku? Then, but yeah, I agree. It's not it's not a canonical thing.
Adam Hill 24:43
Oh, I mean, my Oh, my gosh, Google. my pitch for Django is that, you know, we that there is a canonical way to solve for this. I think that would be nice. And it would kind of get around some of this conundrum of what You're supposed to do
Will Vincent 25:01
with what specifically there is a like Django is a canonical way to do these things. No,
Adam Hill 25:05
no, like, inside of Django, when you you know, create new project, then it basically sets up your files the way. So you have multiple settings files, or, you know, you have the end file, and you you know, and it kind of just like, it lets you down, you know, into the pit of success. And so people just know that like, this is the way to do this thing. Because it is the thing that that pops up all the time. It's the same with, you know, should I deploy my react app with my DRF app? You know, that I see the same sort of questions on Reddit over and over and over again, and like, how do I do this thing, and I think the more that Django can provide, doesn't have to be super opinionated. But if it can provide some guidance, and like, and this is how you want to do this thing that 80% of the people want to do, I think that would be beneficial.
Carlton Gibson 26:03
Okay, so I don't know normally say things that are on the forward agenda, because it just ends up with people going, why isn't it really Yeah, it's but this summer, I will state very much focusing on async tickets, I've got one more pair of things to try and get into 4.2 for on the async front. And then we want to swing around to a proposal to modernize the request object, and maybe add JSON passing to the request object. So you just go request dot data. And if it's a JSON request, you'll get JSON data. Whereas if it was a, like a form encoded request, you'd get, like the equivalent of post data now like the dot post, so you get form encoded data, but either way, you're gonna get that back as a nice dictionary. After that, there is a there is a proposal to actually get round to okay, what, you know, what can we look at, in terms of making a better story here, for people? It's difficult because every time it comes out, there's massive differences in opinions, including to the extent that no, actually environment variables aren't the way to go. Because what you want is a is a file that you put in place that's read at process, launch, and then deleted, and then it's sold in a single thing. So it's not when the process gets dumped. It's not all leaked in the environment, you know, this. It's, the trouble is, you know, there's so many opinions in so many different ways, but we're gonna sit down, okay, can we make this can we make the template that start project template, one step up. And it's not an instant process? And you know, it takes a while to go through, but there are proposals in place. And it's, it's coming to the point where that's bubbling to the top of the backlog to the process. So we'll see. We'll see. Anyway, one thing
Will Vincent 27:45
I want to talk to people about at Django con us like in the hallway, I should go research a little bit the past more, but I think that's a big thing.
Carlton Gibson 27:56
I have not yet right. As long as you write up those opinions, that's fine. Yeah, okay. It needs to be scientific. I need numbers and bar charts, just a histogram or make it up. So Adam, Jiang a unicorn. Very good. I know Andy, I'd who built horse read as he I can't stop him talking about we're hoping to get him on the show soon. He can't, he just absolutely raves about it. So you know, I think people should go and check it out. I want to talk about some of your other products. So I can I talk about the one that I'm really excited about, which is minestrone, which is a which is a way of selecting DOM elements from elements from the DOM, right? It's a HTML sort of search library. Tell us about that. Because I tell you why I want to use it for simplifying HTML test cases where you're testing against rendered HTML. But
Adam Hill 28:44
yeah, so I think, you know, if you've been in Python for a while, you've used BeautifulSoup, if you want to parse HTML, because it's basically the best thing that you can use. It's very lenient, and let you sort of find things in there. There are a couple other libraries that are floating around, but it seems like everyone sort of uses BeautifulSoup. And I use it in all my projects, or a lot of my projects. And I love it. So there's that. I find personally, the document documentation is a little hard to read just one big long, you know, list of methods. And so every time I'm like, How do I find just this elements, and so I have to kind of read through stuff. And the API is sort of it's, there's, there's a lot if you look at all the, you know, attributes, and all the classes that are available. So my basic idea was, well, I'm just gonna make a little wrapper library. It's gonna it uses BeautifulSoup underneath the hood, because there's nothing better. But maybe I can provide just a nicer API for people to do sort of I'm always looking for solve the 80%. Because like the last 20%, that's the hard stuff. And I'm maybe not smart enough to figure that stuff out. But like the 80%, I can definitely get. So I have nice methods to basically get elements loop over all of them, look at your attributes, get the classes. And I tried to do, you know, I tried to make the API as nice as I possibly could. And that was another thing that I was really trying to sort of get out of this exercise. And this is, this is just like unicorn where it's like, you know, I'm, I'm just looking around, and I'm like, I feel like this could be better. Like, it doesn't have to be this hard. Like, maybe I can make something and provide it and, you know, make things a little bit easier for people to use the documentation and use the API. So that was that was the basic thought about it. Okay.
Carlton Gibson 30:57
And, and, like you said, the basic API is just,
Adam Hill 31:02
it is loading the HTML, and you have a class, and then you can loop over that get all the elements, you can grab classes from those elements. So it's, you can search using, it's basically looks like, like CSS selectors. Yeah.
Carlton Gibson 31:20
So that. Yeah, that was the point. I wanted to get into that you choose a CSS selector? Which, yeah, totally happy with rather than Excellent. What's the XPath?
Adam Hill 31:29
Yeah. All that stuff. I don't like that. So
Carlton Gibson 31:34
like, in my entire career, I've never had success with XPath expression. So I just couldn't, they just wouldn't go into my brain in the right way. So every time I needed to construct one, I had to go and look up the scent, or look up. Query query syntax was CSS selectors, because you're using them all day, every day. You know them. And you can, yeah.
Adam Hill 31:54
Yeah. It's, it seemed like an easier approach for people to sort of find things was the CSS selectors.
Carlton Gibson 32:01
And so my migrate sort of what I want them to see I'm not really writing a scraper and extracting links to, you know, crawl the web or any of that stuff. Because yeah, if I wanted that, this frameworks that do scraping for you, but what I want is, when you've got HTML, HTML, you want to assert assert equal on the context, right? Yep. So you render the template, you want to make sure that the template, you write your template tag did is it functioning how you want it to, so you want to get the, the HTML and you normally you want to pull it out of a bigger a bigger page, you know, what did, did the page render with the HTML? I expect it? So if you can query that down to a small HTML element and just match against that, rather than is this string appearing anywhere in this in this HTML, and no, it didn't appear? And then it prints the entire page? So no, no, no, no, no, it was if you've, if you've extracted the one element, you can just have the HTML that for that element appear, and it's our I see I missed an attribute or something.
Adam Hill 33:05
Yeah, that's a perfect use case for this. You can use BeautifulSoup if you want to. But this might be a little bit easier. So
Carlton Gibson 33:13
yeah, so that's why that's, that's, that's why I'm excited about minestrone. It's worth so it's worth checking out. What other projects are you?
Will Vincent 33:21
Yeah, I want to ask you about Coltrane. I mean, you have so many. But I mean, this is like, sort of like a static site via Django, which,
Adam Hill 33:31
yeah, yeah. So Coltrane was a will the the author of Rich and textual Oh, mcgoon. Er, yeah, yeah. I didn't want to, you know, ruin his last name. So I don't know how to say it.
Will Vincent 33:45
So I'll do I did it. But yeah,
Adam Hill 33:48
he, he, he made a tweet a while ago. And it was, you know, like, what static site generators should I use? And it sort of made me start thinking because all the answers are, are great, you know, like, it's Pelican or Lecter? Or there's all these Python ones, right? And there's Hugo and there's Jekyll. And there's, there's so many. But I sort of just like triggered a thought for me of Django does 90% of what all these other things have rebuilt and done. And maybe Django could do something like these other projects. And so it was it was just a prototype and I was like, Ah, I wonder if I can do this. So I started by just I use actually Carlton I think you had a talk at Django con us at some point with the single file and then we'll I think you have the repo so this encompasses both of you which is fine we're
Will Vincent 34:48
gonna talk about Carlton stuffing like Pelican into Django, but yeah,
Adam Hill 34:51
oh, no, no, no.
Will Vincent 34:55
Excuse me, excuse me.
Carlton Gibson 34:56
So carry on. Fall to use a sink Well, template, yeah.
Adam Hill 35:02
Oh, so I can use this little single file thing and I can make, I can make sort of, I can reduce the complexity, right of what you need when you have a Django project. And so I use both those ideas in this. And basically, it's a Django app. And it looks in a particular folder for markdown files. Everything it sees in there, it renders them to HTML, and then outputs them to a different folder, sort of just like every other static site generator. The other fun thing that I did was, there's no databases, right in Django in them in a static site. So in I think it's Hugo and elector, there's a couple of options for this. But basically, it uses JSON. So you could have sort of sort of a database where you, you know, have data inside of JSON, and you can pull that out and then shove it into a Django template. And it will get rendered as part of your static site generation.
Carlton Gibson 36:12
And that that that JSON lives alongside the Markdown file, is that,
Adam Hill 36:16
yeah, it's in a sense, that basically, you can basically reach out and interact with it sort of like it was the database is the way that it's set up. Okay. Yeah, it was. And the other thing that I did was I used Adam Johnson's, there's like a browser reload library that he has. So when you're working, and you're like, you know, typing up Markdown and stuff, it'll automatically reload the contents. So that's a nice little dev experience. And basically, I took Jango. And I tried to make it as simple as possible for an end user to start up a project. And now it's, it doesn't do everything, right. It's just static content. But it's sort of it's again, that 8020 rule, just like if you just need a blog, system, like this is a pretty simple way to just start that up. And, but it still provides all the power of Django behind the scenes. So you can use Django libraries. You have Django templates. So you have template tags that you can do things in mostly other Python static site generators use Jinja. So like, it's just a different, you know, it's a different approach. Right. But it was really fun to work on. And so I really like it.
Carlton Gibson 37:38
Yeah, that's good. So if you I mean, I think that that point about being simple. So it's literally just a folder of markdown. So the important thing, right, because if there are, there's a whole, you can that you can start there, then if you need a full Django site, there are things if you don't, but you still need it static, you could use as a Django bakery project, right, which takes so then what that does is it sort of reads your URL comp, and then crawls the URL comm for every to enumerate the URLs, and then write to Sac State site. And I think there's a wagtail bakery project, if you've got a wagtails it, but that's like a lot more machinery on top and then. But then you still able to just host to the output of a folder or static HTML files, rather than I've got to spin up a Django process and have that running all the time. And everything that's entailed on that.
Adam Hill 38:22
Yeah, so I have a, I have a site called all django.com. And so it's, it's all a static site. So I use render.com, because Heroku is going away, sadly, but render will host your static sites for free. So I push to a push a change of markdown to GitHub, render will pick that up, it runs a it's basically a Django Management Command in the background, and then outputs the static HTML, and then it's on the site. So it's a nice flow.
Carlton Gibson 39:01
Let's contract so going, Oh, I was gonna say oh, django.com So I thought that was your homepage and it's like your sort of personal this you know, we're all doing it doesn't know
Will Vincent 39:10
that I have out there that's all I mean, like our question this fall in these two guests needs to be like what platform hosting service do you like and why? Because there there's there's quite a few and I've been deep diving on this. It sounds like is rendered the one currently you like Adam for
Adam Hill 39:25
that's, that's what I it's what I've been using the most. When I looked at fly, it looks like it was a little harder to start with me. I might be wrong about that. But render the documentation for render was really nice for Django, and it was an easy transition from Heroku Heroku was my was my you know, standard for ever. And so when I was looking around it seemed like render was was really the replacement for that but
Will Vincent 39:58
so far Fly will, that will be changing. I'm contracted with them to write the Django, nice Docs. So suppose to do that this week, actually. So because they are lack, they don't have a dedicated Django Doc's. And so I've been talking to them. And that's they're gonna have something both, you know, an existing site and migrating from Heroku. But rent, render hat render is great stuff, too. I'm not making a judgment on platforms. But that is a whole fly has, and it will be filled shortly.
Adam Hill 40:32
It's interesting when you look at some of the other ecosystems like Laravel, I think they have their own hosting platform.
Will Vincent 40:40
That's how they make most of their money. Yeah, yeah. And so,
Adam Hill 40:43
you know, I know, they have a different sort of philosophy in that, in that framework than Django does. But it is, I, I look at that ecosystem a lot to be like, and this is a different way to approach the same problem. And maybe there's some learnings there, maybe it doesn't really work out, because, you know, just different, different approaches by different, you know, communities, which is totally fine. And I love Django, I'm not gonna move away from it. So, but
Will Vincent 41:12
I agree, I think I have I have a friend is a Laravel developer, and he's constantly telling me about all the things they're doing. And I, you know, sitting on the Django Software Foundation Board, I will admit, sometimes I look longingly at what they do, because it's just, I think it's Taylor is his name, there's, like, he can just do stuff. And they, they make, they make basically all their money, they make millions of dollars a year on hosting. And then also they have a starter project, like an official starter project. And then from that, he's able to do all this all, you know, give away all this stuff and do new things. So it is appealing, you know, the it's one less layer of complexity. On the other hand, it's completely dependent on one person, but like, it would be great if Django had Django start project gave you a site, you know, kind of like their starter projects, like I have Django X, there's a whole bunch of them, if there was also an option for like, a deployable, start, deployable project, and then click a button, it was up to the vendors, but you could deploy on render fly, you know, take your pick, that would be friendlier to put,
Carlton Gibson 42:20
I think, the project that I hear what you're saying about Laravel. There's two things one now, I think, is that it is one person's project, rather than a community owned project, I think there's something very, very important that Django has the kind of structure, the community owned project, the community project that is, and I would, I would defend that against some these kinds of costs that I think if we were to, we were to make it into, if we were to make it into an entity that had a revenue proper revenue stream of its own, then there would be a real danger that the revenue stream gets hijacked. So you know, the example we're not saying it's necessarily right, but in the Apple world, which, you know, part of and follow that all the really long standing people, they're decrying the fact that its revenue stream is now services, because it's taking away everything that made Apple the company that they loved over the last 30 years. And I feel the same thing would happen to Django or an analogous thing would happen to Django, your Django became a money making enterprise. So I'll just put that as a sort of something that we could discuss a Django con sometime over a few bevvies. But Eric Mathis since Django simple deploy project, it looks like it's just hitting the the absolute button here on you know, being able to just go automate, all deploy, pick your platform. And okay, he started with Heroku and is now like, right, I've got to get the other platforms on, but I think he's got platforms or shell going, they responses that Django
Will Vincent 43:56
fly in almost flying, and he's going to plans to add, I've talked to him quite a bit about this. So yeah,
Carlton Gibson 44:02
subsequent platforms, right. And what looks as well is that it's, it would be very relatively easy for other platform vendors once they realized that this is the way to instead of relying on Eric to build the integration that they could build it themselves and be like and submit it as a pull request or as a plugin. And so it may be there with the with the to work we were talking previously about improving the start project that even though we get a bit slower, we might have had to get there you know, anyway without needing to sell the project into a play, convert or sell the project but converting the project into a commercial enterprise. So you know, I hear every second I just think maybe it's not as bad as all that.
Will Vincent 44:48
Oh, well, come on. I have so much internal experience. I can just you know, grass is greener a little bit, but I wouldn't trade I wouldn't trade places at all. Yep, agree. So
Carlton Gibson 44:59
Okay, let's have let's let's, you got one more project that we maybe got other projects. But we'll come back now if you have any other projects. But there's one more project I want to talk about, because it's kind of you know, you've got your Django and Django function, or FBV for function basically. Yes, yes. That's very interesting. Tell us about that. Because obviously, function based views and class based views, the eternal, you know, potato versus baton of Django.
Adam Hill 45:22
Yeah, sure. So Django fdv. So at work I was, I was making a presentation with my coworker about class based views and function based views. And, you know, for a long time, I was just like, cbva is too complicated, I don't want to deal with it. I don't want to understand the inheritance hierarchy and everything. But I did this presentation. And so I had to sort of dig into it more than I normally can to avoid. And there, there are some nice things about cdvs. And so, but I kind of wanted to make a library that provided some of the niceties of class based views, but still stay in the function based view world, because, to me, it's more simple to understand a request comes in here. And there's a response out here, and I don't have to look into any mixins. And figure out, you know, what is happening inside of here, with a class based view. So for the longest time, there's a library called Django annoying, which is not the best library name. But I would use it all the time. And it has, it has a bunch of decorators and other, you know, model fields and stuff. But two of the decorators that I would use, there's, I think it was render two, and then there was an AJAX one. And it basically is just a decorator that you put on top of a function based view. And you can return a dictionary from it instead of render to response or, you know, to be response or whatever. And it will take that dictionary, throw it in the context. Oh, and you specify the template name in the inside the decorator function call. And it sort of cleans up your, your function based view, which I kind of I like, and the code, there's not a lot of code. So I was like, Okay, this, this is all fine. And then for the Ajax one, it would do something very similar, just render JSON response. And it would take that dictionary and and pass it back. So I use that library for a long time. And I saw those two functions. And then I started thinking of some other things that I tend to do with class based views, like redirect view from your URLs, or just like a, you know, template view from your URLs to sort of like, some little nice shortcuts, basically, yes. And I was like, Well, I can do that in a function based view as well. It's just, I have to write some code to do it. So I took that code. And I made it into this library. And it sort of it tries to encapsulate some of those patterns, but stay in the function based view world. And so
Carlton Gibson 48:24
the example there is when you're talking about passing in a key works keyword args to the eyes view function, so you get your template view as view and then you pass in some in that keyword, args. So you don't have to get those per request. Right. Is that? Yes. Yeah.
Adam Hill 48:38
Yeah. So So I have the same thing. It's just a function inside of my library. So
Carlton Gibson 48:44
that's the other the other side, because we talked about multiple settings files earlier, that's the other really old school thing that you're not allowed to admit to doing. But which I do all the time? Is a URL conflict, like my views, kind of just sort of in it? And then okay, I'll have a few stock pie for, you know, more elaborate stuff.
Adam Hill 49:01
I mean, if it works, right, like, it's not the worst thing in the world,
Carlton Gibson 49:07
but it seems to be sort of the sort of shaded apart.
Adam Hill 49:12
Yeah, I mean, it does, it's sort of, you know, you're like mixing two responsibilities, right, in one thing, and so, but
Carlton Gibson 49:23
to cut back to go and before we move on to cut back before to HTML, Carson Gross has done loads of essays on his site, which I think, regardless of whether you use htm X or some other library, they're just really good. And one of them is about locality of behavior. And one of the advantages of these kinds of HTML over the wire type things is it keeps, it keeps the behavior in the same place, you're not writing CSS in your JavaScript file, or you're not writing your business logic over here, and you have you. It's kind of like I'm writing this template and I just add a few little tags on and all of a sudden, it works. You spend a lot more time working in the same file and you don't have to have five files I was open to read them. And so a lot of these practices that you know about mixing behaviors that you end up with, you know, a forms file that's got one form in it, and then a serializers file that's got one serializer in it and a filters file that's got one filter in it, and a view file that's got one view in it. And it's like, but hang on, I could put all of those in one file, and they could fit on one screen, or maybe have to scroll down a teeny bit. And it would all be in one place. And I wouldn't have to have four files, open four tabs where I can't see, why can't I just put it in one file. And I've been sort of advocating that to clients for years, and maybe they sort of look at me as if it was unprofessional. And I didn't have the tech the sort of the jargon to to give an argument as to why it wasn't. It was in fact, the opposite of unprofessional. It was a lesson I'd learned hard over, you know, a decade or more of experience. And then Carson wrote that essay, and I was like, that's, that's the locality of behavior is ah, anyway, so, like, just got excited it.
Will Vincent 50:59
Also, it's also good, you're, I'm remembering. I think I still have it, I had a blog post on an about page, a Django About Page Six ways, and basically showing because I think, like, we all are pretty fluent in Django, right. But like, a lot of people don't understand, like, know how to import, it's like, Wait, if I have, you know, this filed forms file, how do I bring it in? You know, so just being like, okay, like, Let's do you know, an about page six different ways, like, Let's jam it all into one file, and let's break it out, is a really great teaching method. I think no one ever read that post. But I was like, really proud of it when I wrote it. And I keep thinking, like, I think there's a lot more here to this. I mean, you're talking Carlton, I mean, part of why I was so excited about your talk was getting at this idea of just, yeah, it has guardrails, but like you can do whatever you want, and Django, but you kind of need to understand that. Enough of it to feel comfortable doing that, right. Where it's like, yeah, we could do it that way. We could do it this way. Versus beginners, just like what, like one file like that breaks all the laws I've just been taught and, you know, memorize but don't understand.
Carlton Gibson 52:02
Ya know? I mean, yeah, yeah, you got it. If you're beginning, you could go with what it doesn't just follow along until you're 100% Sure, but sometimes it's easier. Literally, you know, it's only 100 lines total, just have the 100 lines next to each other. And,
Will Vincent 52:18
you know, what's like, learn all the rules, and then break all the rules. That's that's
Carlton Gibson 52:21
massively got massively got sidetracked by the fact that of so excited that you were saying you, you wanted to put your view template view in the URL? Yes.
Will Vincent 52:34
Can was there more that was more to add on that.
Carlton Gibson 52:37
So you were saying before the you wanted to do the same as being able to instantiate a class based view, or we call the as view within a keyword arcs, but with function based view, so I didn't let you finish? Because?
Adam Hill 52:51
Oh, yeah, I mean, so I started with that. And then I added a couple more just little helper methods, like, there's one that serves a fav icon. I think I stole that from Adam Johnson's post at some point, where you can sort of like an emoji as your fav icon, instead of setting up an actual image. What else do I happen, oh, I have a middleware. So the other thing that people seem to like, with class based views is, like having a method explicitly forget and for post, so you kind of split those two pieces. And so the way that I tend to do that now is I have this middleware, and it's really simple. It just looks at the method, and then adds a property onto the request object, which is, is post is get is head is, you know, all the different HTTP verbs. And then, so in my function based view, I can just do if request.is, get, do my get stuff, or is post and do my post stuff, instead of request dot method equal equal, you know, get, which looks a little messy and feels not super dry. When you see that over and over and over again. And yeah. So it's just little helper things that I that I added that seemed like they're useful.
Carlton Gibson 54:16
I think that's a nice example. Because I fun, absolutely get the the sauna on the more or less class based view, and I'll write a function based view from time to time, but more or less, I use a class based view. And I normally start at class, my view, inherits from view, and then def get, you know, self request, args, keyword, args, whatever. And at that point, I look at it as I've got exactly the same as a function based view, which is the request comes in here and I return it from there. But I've got what I've got is a namespace to break it down. And of course, it's indented. And there's a bit of boilerplate and there's a self argument which gets in the way. But the sort of advantages when you get to if get if it request is get or if request is post, it's sort of outdated because you've got separate handlers for that. And it's, what's nice about that sort of circle of examples there is to show that it's entirely equivalent. It doesn't matter which way you you do it or which way you like or what you use, because one day is one way is more indented in one type. And the other way is more indented than the other. It's all the same, right? So what are we arguing about? We're arguing about when I like blue? No, I like red. Which blue says someone else? Which read someone? We might check me, but it's fun to do. But I like I like that example. Anyway, funk functional bass. Did we mentioned Luke's piece?
Adam Hill 55:52
Yeah. So we didn't. But that was a big mention that quickly, then. Yeah. So Django views the right way. It's pretty brilliant. It's, it sort of lays out a case for function based views. And I actually, you know, borrowed some code from that as well, for the redirect view. And it basically, you know, you're talking about Carson's essay about cardinality, like, when I read Luke's Django view the right way. It was like, This is what I've been thinking all along, and I just cannot, like put it into words, but like, this is so you know, like, my thought process when I was reading it. So highly recommended. Super super.
Will Vincent 56:38
Yeah, that's, that's an amazing piece, I would say, of the top five questions I get from my books, you know, function based versus class based is one of them. And, and people now cite Luke's piece to me and, Mike. Well, I agree, but you know, I'm still gonna, I think, yeah,
Carlton Gibson 56:57
I do have one question, which is, if you if you ignore the, the inheritance structure of the generic class based views that are provided in Django, which we all agree is very complex and difficult to master. But if you just take the simple, simple class based views, you know, where we literally declaring them by hand, and then you build, and you use the namespace to break your logic up, if you need help, or methods, which is what I like, versus I find functional composition, to be quite a complicated subject, for even the advanced programmers, and it's can be difficult to get your head around and difficult to think in the right ways. And is this is just literally question. Do you think for beginners, which particularly you target more will recommending function based views and decorator approaches and things which I think Well, are they hard to grok? And is it not easy to teach a class with a namespace with separate bits? I don't know. That's a question.
Will Vincent 57:56
To me, or to Adam. Weight
Carlton Gibson 57:58
loss. But I mean, what do you think I mean, it really,
Will Vincent 58:02
what do you think, Adam? Yeah, you're the special guest.
Carlton Gibson 58:07
Is it clear, the concern isn't clear what I'm saying. So I didn't really Yeah. And that's it.
Adam Hill 58:10
I think for new, if you're brand new, to programming, and you just want to start, maybe the class based view makes more sense. I think a lot of my, you know, bias is that I already knew how HTTP worked. And so to me, I'm like, I want a request. And I want a response. And I understand that what what to do with those things, where it's not so abstract. And a lot of my, what I've realized over the years is that I have a, I have a reaction, because of where I came from, with C sharp, where everything is a class, it has everything is alone to the nth degree, and you have interfaces, and you have, you know, class hierarchies and things. And so, for a long time, I was like, I don't want that I understand these functions, and you can compose them. And I, you know, it was a visceral reaction to those things. That doesn't mean that they're wrong, or they're right. It's just, you know, I think everyone goes through their own learning experience, and what makes the most sense to them. And I, I sort of love hate that Django has these two ways to render responses because they different people, like each of them. And I just think it makes it harder when you're starting. But at the end of the day, like you said, they're their equivalent. So you know, pick your poison. As far as I
Carlton Gibson 59:42
know, I think just come back to me, the Gang of Four pattern. Four is a method object where you've got a complicated function and you convert it to a class in order to break the function into separate steps, which are then called from a sort of from the get handle from the main request. And so it's a it's a method or patent for decomposing your logic in. Anyway, that was well thought,
Will Vincent 1:00:07
Well, yeah, so I, the earlier versions of my books I've mentioned function based views and shown like a Hello World with it but said, I want to get you up and going and we're going to backfill and so I haven't gotten more into it, I get a lot of emails about it, I have been convinced I want to build at least crud with function based views, do both. But then I want to show like, build something out that's like a 20 line, function based view, and then be like, This is why generic class based views exist. And, you know, you got to do some research, but like changing one line versus having this custom code that repeats a lot. I think, you know, I go if I can use a generic class based view, I do. But as you're learning, I think you need to learn both. And so I'm, I'm going to add both in more than I currently do. But I still think it's it's sort of like, if you're teaching college class, we like, Yeah, let's talk about HTTP. And let's do it all fundamental principles. But if someone's like, I want to build a website. It's, it's a question of, when do you introduce it? For me, like, that's the tension I have is, I don't want to just overwhelm everyone. So I think that I will, for the for two versions, have function based views, crud, and show a sprinkling of how messy function based views can get, because, you know, Luke writes them or, you know, they can be really nice, they can be awful, awful, awful, awful. Whereas, you know, manipulating one or two lines of an existing generic class based view. I prefer doing,
Carlton Gibson 1:01:30
I've got a an old, I've got an old book called Pro Django by Marty out in which, when I was getting up, you know, upping my skills, it was really handy one, he sort of opens the book with a chapter on Python. He's like, yes, yes, fundamentally, Django is just Python. And so you need to learn about this. Like, you have decorators and properties and descriptors, and you're like all these advanced Python bits he's like, but if you know these, then you'll understand how Django works. And if you know that Python, then you'll understand that you know that these different ways, you know, just are options.
Will Vincent 1:02:06
Well, this is the problem, I find myself. I wrote my books, because I didn't like those kinds of books. But now that I've more experienced, I understand them more. And I find myself rewriting my books to be like those books. So I have
Carlton Gibson 1:02:15
to eat well, it's a Python book.
Will Vincent 1:02:18
Oh, my God. Right, yes. All right, Adam, well, I think we're basically out of time, I know you have Python utils site, which is built with unicorn, which is kind of cool. We're gonna link to in the show notes. I don't know if you have a quick snippet need to say or something you
Carlton Gibson 1:02:35
want to plug or call out you want to do or anything, anything.
Adam Hill 1:02:38
You can follow me on GitHub or on Twitter. I don't tweet very much. But occasionally I do. And if you want to keep up to date with I sort of posts, updates to what I'm working on and tried to be somewhat witty on Twitter. So
Will Vincent 1:02:53
Well, I think Django unicorn, you're, you're looking for some funding, right? I mean, you have these other screencasts. And things if you get more community support. Is that still the case? Yeah, I
Adam Hill 1:03:02
have. I have GitHub sponsors set up. And I should say I have I think I have 13 right now. And so I love everyone who you know, has sponsored unicorns been awesome. I never thought that anyone would sponsor it. So that's been great. And it is sort of, you know, when you're building something like this, it's like, you need some intrinsic motivation, obviously, because it's like, it's a slog. I've been working on this for two years. So like, you don't just it's not, it's not overnight, or whatever. But the extrinsic motivation is also kind of nice. I've just like, yeah, people love this, and they're using it and they want to support open source. I really appreciate that. So,
Carlton Gibson 1:03:47
Adam, thank you for coming on the show. Really interesting. Thanks for all the work you're doing the project should you just prolific and super and it's really great to chat to you.
Will Vincent 1:03:55
And we are Jango chat.com, chatting on Twitter, and we'll see everyone next time. Bye bye. Bye bye.