Packages! Packages! Packages!
Published July 19, 2024
This video features Tim Allen at Wagtail Space US 2019 in Philadelphia, Pennsylvania, USA.
Alcoholics Anonymous and other 12-step groups are decentralized, guided by suggestions and traditions that emphasize equality, service, unity, autonomy, and welcoming anyone who wants recovery. Those principles also shape the Meeting Guide project: local AA organizations manage their own meeting data, which is shared through a common API to a mobile app and, increasingly, a React front end backed by Wagtail. Wagtail gives volunteers and office staff a clearer interface for maintaining locations and meetings, while keeping the front end separate from the data source. Allen connects this work to the urgency of addiction and to his own recovery, saying that asking for help changed his life and urging anyone who needs help to ask.
Summarised automatically from the transcript.
Automatically transcribed, so expect mistakes in names and technical terms.
Speaker 1: All right. Well thank you everybody for sticking out to the end of the day. Uh I'm Timothy Allen. My pronouns are he, him. I'm flipper PA pretty much everywhere, Twitter, GitHub. So you can track me down there. I'm an IT director here at Orton. I did want to give a bit of a content warning before we get started here. My initial intention with this talk up until a couple weeks ago had just been to do a deep dive into the technology But a couple things happened in my life which sort of reminded me that it's important to get the message about alcoholism and addiction out there. And it's a deadly progressive disease. So if at any time during this talk you feel uncomfortable or there's a topic I'm going over that uh makes you feel a little queasy, feel free to get up and leave
Speaker 1: or just raise your hand and tell me to pause Because this is a disease that, you know, to remove the stigma around addiction, we really do have to talk about it openly and frankly. So I just wanted to state that up front. There will be times when feel free to laugh during this talk. There are plenty of absurd moments about addiction. We think laughter is better than pills for what ails you in many cases. And feel free, I'm an open book, so feel free to ask any questions at the end about uh anything I might cover. So with that out of the way. Let's talk a little bit about 12-step recovery. There are a lot of things people don't understand about 12-step recovery. You know, you see it kind of on TV, or I remember uh how House of Cards displayed it.
Speaker 1: It was kind of amusing for those of us in it But there's a reason I chose this logo. And really 12-step recovery groups, all of them are anarchies in the best sense of the word. And uh I'll be talking about Alcoholics Anonymous, which is the largest and most familiar to most people, but most other 12-step fellowship programs follow the same steps and traditions. including Narcotics Anonymous, Overeaters Anonymous, Gamblers Anonymous, Cocaine Anonymous, Crystal Meth Anonymous, Marijuana Anonymous, Sex and Love Addicts Anonymous, there are a ton of these groups And one thing that's important to understand is everything in recovery is a suggestion, not a rule. So the steps are just suggestions, not rules. In fact, uh one of AA's earliest members with an
Speaker 1: was an AC atheist named Jim Burwell He is the one who started AA here in Philadelphia. And he is the one responsible for them making sure in the all the writing that the steps were referred to as suggestions and not rules. And he was also very involved in the formation of AA's earliest traditions. So in addition to the twelve steps, there are also twelve traditions, which are sort of guidelines and traditions for keeping AA afloat, trying to avoid it ever becoming political or anything of that nature. And I think there are a lot of great lessons in these 12 traditions that open source communities can learn from. Anonymity also does not just mean not revealing what I hear in the fellowship or in a meeting about another alcoholic or addict.
Speaker 1: It also really underscores the equality between all members. So within recovery groups, we are all considered equals From Yale to jail, from uh state pen to pen state, we are all equals within recovery. So, unity. A couple of these traditions speak about unity. And this is definitely something I feel, you know, within the Python community and within the Django community and within the Wagtail community. Our first tradition states that AA's common welfare should come first and that personal recovery depends upon AA unity. Our second tradition states that AA leaders are trusted servants who do not govern.
Speaker 1: And I do feel that a lot in quite a bit of the open source projects that I work with, that rather than having some sort of uh top down management style, you know, the best ideas grow from the bottom up. And if you look at Guido Van Rossom in Python, I think, you know, i the the BDFL title of Benevolent Dictator for Life was kind of a tongue in cheek way of saying it 'cause So infrequently did he ever use that. He was very much a consensus builder who believed that everybody's opinion was as valid as his own. Tradition 12 also speaks to the equality of placing principles before personalities. So membership and purpose within recovery groups. Tradition 3 states that the only requirement for membership is a desire to stop drinking.
Speaker 1: So basically anyone who states they are a member of Alcoholics Anonymous or another recovery group are a member. So it's like on day one, if you decide you're a member of AAA, congratulations, you have now achieved the highest rank you will ever get Within AA. Um the concept within AA is if you do get into service, you actually step down from the highest rank of member. Into a lowerarchy, not a hierarchy, the lowerarchy of AA to serve the membership. And this is a lesson I think our quote-unquote leaders in Washington could definitely take. a lesson or two from. Every time I hear that our leaders in Washington, it's no, it's our servants in Washington, our elected servants. They could uh definitely take a lesson in this as well. Tradition 5 also says that each group has but one primary purpose, to carry the message to the alcoholic who still suffers.
Speaker 1: Tradition 10 also says that AA has no opinion on outside issues, hence the AA name ought never be drawn into public controversy. So we stay focused on the one thing we need to do, and that is helping the alcoholic who still suffers. So being inclusive is absolutely important. There's a great story going back to 1940. So AA was a group of rich white businessmen initially, as it was founded. The original preamble was a fellowship of men who share their experience, strength, and hope. It eventually got changed to A fellowship of men and women who share their experience, strength, and hope. And we'll get into a little bit more of that later. But in 1940, These white businessmen helped spread AA because they were traveling salesmen from city to city. That's how it initially started in t
Speaker 1: in Akron, then went to New York, and eventually came down to Philadelphia, then Baltimore. And uh In 1940, a African-American gay man who was a heroin addict, who was a cross-dresser, came into their meeting. And they had no African-American members, they had no gay members, they had no heroin-addicted members, and they also had uh They definitely had no cross-dressing members or members of trans experience. And in the history of AA, in the book Pass It On, it talks about how they were debating what to do. And they decided at that time to come up with a third tradition that the only requirement for membership is a desire to stop drinking.
Speaker 1: And this person had a desire to stop drinking, so he was welcomed as a member Which by a group of, you know, sort of rich entitled white men in 1940 is a pretty amazing story to hear. And uh and one that I like to that that I like to share far and wide because it does show sort of um People had found a way to you know accept humility as as a form of strength back then. And uh it's it's one of those stories that really underlines how AA has continued to evolve. and survive as long as it has. Um it also sort of underlines the importance of inclusion. If you think about these pronoun stickers we're all wearing,
Speaker 1: you know most of us probably have the pronoun of the gender that we were born. And that's just fine. But by sharing in this responsibility, we can make the space more inclusive for anybody who might not typically feel welcome in a space like this And that's especially important in recovery because people of trans experience have a much higher rate of alcoholism and addiction and suicide. Much higher than cisgender people. So making our meetings welcome, welcoming to these people is literally a life and death situation. So you know it may be, you know I do occasionally hear people joking around about oh pronouns shouldn't it be obvious? What bathroom do you want to use? And you know it it's a lot more important than that.
Speaker 1: And in some situations it can be a life or death matter. If somebody doesn't feel welcome at a recovery meeting and leaves and goes out, especially here in Philadelphia where we have a heroin epidemic, four times as many people died last year of heroin overdoses as murders in Philadelphia. That's how important inclusion can be. And you may say that's an extreme example, but it's an absolutely true example that I see every day So it's absolutely essential for me, not just in my recovery life, but in all walks of life, to make sure that the spaces I choose to be a part of are inclusive. So getting on to what does this have to do with Wagtail? Our fourth tradition states that each group should be autonomous, except in matters where it affects
Speaker 1: another AA group or AA as a whole. So basically you have the freedom to do whatever you want as an AA group as long as it doesn't infringe on the freedom of another group or AA as a whole. Which is kinda nice, 'cause going back to that preamble of AA, AA is a fellowship of men, uh no, AA is a fellowship of men and women A couple of our local groups in Philadelphia here have started changing our preamble to be AA is a fellowship of people who share their experience, strength, and hope. And some of the people who've been around a long time kind of bristle and say, Oh, you know, you're you're changing stuff that hasn't been changed since nineteen fifty eight, but we go back and point out that it was changed from men to men and women in nineteen fifty eight after being originally written in nineteen forty seven. And there have been a couple other tweaks over the years too.
Speaker 1: It used to be the only requirement for membership is an honest desire to stop drinking. And that honest was taken out to just be a desire to stop drinking. So every time this has been rev uh Every time this has been changed within the history of AA in the literature, it's become more inclusive. So I think that's a good tradition to keep going as we continue to evolve as a society. So this fourth tradition that says each group should be autonomous, you know, once again lends to the anarchy of AA. A totally flat structure where member is the highest rank and each group can kind of do what they want, kind of becomes a technical nightmare. So inner groups, which are groups of meetings in an area. So for example, in the Philadelphia area, we have the southeastern Pennsylvania inner group of alcoholics.
Speaker 1: There are 1,775 meetings in this local area. Um each one is made up of volunteers who each make their own technology choices. So since the nineteen forties AA has been trying to get a mass centralized database of all the meetings in the world that can be distributed. And this has ended in spectacular failure every time because it's tried to have a centralized organization do this within an anarchy of an organization. So it has never quite worked out. We are trying to change that. And we're embracing AA's nature of anarchy to do it. So we started by uh looking at local intergroups and what most we're using, and most were using WordPress.
Speaker 1: So we created a WordPress plugin which allowed people to manage the meetings on their websites. A lot of places were using flat HTML files up to that point, or you know, custom written PHP with MySQL behind it not even using WordPress. So this started to kind of standardize some of the groups, but it was all entirely opt-in. Groups could choose to use it or not use it. And uh You know, some of the more advanced groups, some of the bigger cities were using things like Django or the Microsoft Stack, but you know, there's still a fair amount of cities that were on flat HTML. And our goal was to create an app. Which has since been created largely by a friend of mine in San Jose. And Meeting Guide
Speaker 1: is the name of the app. You can actually find it in the Android or iPhone stores. And uh it was created and launched with two cities, uh San Jose and Philadelphia. We were the first two intergroups included. And uh we actually I'll show you some of the uh bubblegum and duct tape we uh had to make this happen in Philadelphia and then multiply that by the 300 intergroups that are now members. So we started with two. We are now over three hundred intergroups. Hong Kong just joined last week so it really is going global. It's nice to see, but there's still a lot more work to be done. Um so meeting meeting guide polls from each intergroup by an API spec we've built, typically still fed by WordPress, but other groups have customized their systems
Speaker 1: to provide the API feed to our spec. So this is CPS current setup, and this is a large improvement over what we inherited from them a couple years ago. But um they've got a couple PCs in the office behind a router served by Comcast. They've got a file server that has Microsoft Access on it. as well as QuickBooks and various other stuff. But MS Access, they have a custom MS Access app written for maintaining their meetings, which jumps into an MS Access database. The way it currently works is that we set it to once a day. Well, anytime they do updates in this MS Access database, we've given them a single button that says publish to web. Which dumps all the data from Access to a flat
Speaker 1: table in MySQL on the web server, which is LampStack Linux Apache MySQL PHP with WordPress And every morning at 5. 40 a. m. a Python script uh takes all the data out of that flat table And through a very, very ugly ETL process and geocoding process against Google's API with a caching system, loads all the meetings into WordPress. The meeting and the location data are stored in WordPress, and then WordPress exposes all the meetings and locations within it via an API to our central database to feed the app. And uh, you know, once again, each intergroup is controlling their own meetings, but now many of these intergroups can do it through a WordPress interface When they get updated, the API attached to WordPress updates the central database.
Speaker 1: So our central database that controls all the meetings checks with each intergroup URL that we've added twice a day and gets any updates that they've added since then. The problem with this is that a lot of our intergroups have done things like this. So this is currently the Southeastern Pennsylvania Intergroup of Alcoholics. uh WordPress admin site. You can see along the left that there are one or two plugins that have been installed. And uh You can see along the right, that's the full length of the screenshot on the opening of the admin. So I've kind of done, you know how Sublime has like the code map on the right? I kind of went for that effect. So you can kind of see here the myths we've gotten into. And you know, WordPress is a great blogging system.
Speaker 1: I'm not going to slag on another technology here, but in our use of WordPress, and what I've seen often with what I what I want to do with the site is You know, if my WordPress site needs a certain functionality, I grab a plugin that sorta does what I need, so I install it But now I have two problems. And uh rinse and repeat, and exponentially I sort of end up with this spaghetti western the spaghetti bowl of things that are sort of linked together, but sort of not And I try to look at the underlying database and there's some things that are just sort of crammed into these uh weird sort of formats that I have had to decode. Writing the importer from MS Access to WordPress was certainly an education and and how fields can be overloaded and how it always causes pain.
Speaker 1: The other thing, you know, WordPress likes to sort of market itself as, oh, with WordPress you won't need a developer. But then it's like you install one plugin and now suddenly you need ten developers. You know, for a CMS that doesn't need any developers, there sure are a whole hell of a lot of WordPress development shops out there. Which gives me pause to consider. As a blogging engine, once again, it's great. You know, I don't want to sit here and slag on another technology. This is my use of it. I let this happen. I absolutely let this happen. So this is where we ended up. The site got so busy and so complex with so many options in the admin interface that the office staff who are not highly technical really struggled to use it. And to be honest, I struggle to use it.
Speaker 1: Yesterday I got a text from somebody in the office that the recent thunderstorm we had had knocked out our interphones. And they wanted me to put a message up on the current homepage. And it took me about 15 minutes to figure out the custom themes WYSIWYG plugin interface to actually get this message onto the site. Now, again, that's my fault. I made a bad choice in thinking that we could choose this WYSIWYG plugin to actually work. So we started to ask questions because we're seeing a lot of intergroups end up in this area with basically sites where the office staff can't do the updates they want to do. They end up having to call the development staff to take care of the existing WordPress sites. And frankly, that some of the intergroups are less happy with the WordPress solution than they were with their custom homegrown homespun solution.
Speaker 1: So we asked ourselves the question, what if we could decouple the web front end from WordPress? And what if instead of the that that web front end coming directly out of WordPress, what if we could make the web front end consume the same API we already had spec'd out and made for the mobile app? So with those questions in mind, we got to work on a new React. js front end that could consume that API and use the Wagtail interface to keep things as straightforward as possible for the office staff. So without further ado, since I'm a total masochist, why don't we dive into some live code on Vagrant on an underpowered Mac and see what happens?
Speaker 1: Well first I'll show you. So this is uh I I'm gonna switch over to mirrored mode for a moment. So this right here Is the meeting guide app. You can download it on your phones if you want Like carrying Narcan, if somebody ever comes up to you and says, hey, I really need to find a meeting, you could help them out by having it on your phone And you'll see what started as uh Philadelphia and San Jose has now grown to 322 AA service organizations, over 110,000 meetings. Those are weekly meetings. So if you do the math there that there may be 15 people in every meeting and they're an average of an hour long, that's a lot of time per week that people spend in recovery.
Speaker 1: So you can see here we have the Continental Europe region, Alberta, Canada, and if we come down here to Philadelphia PA, you'll see it's there. We've got Hawaii. East and West Hawaii. It's kind of fun to look at their meetings because they have a lot of meetings on the beach. I got really jealous about that. Why am I spending all this time sitting in church basements? And uh, you know, there are about 10 of us who contribute to this. And uh we have various different repositories. We're always looking for help with it The original WordPress plugin is here. Our next generation React base front end is there. And uh you'll see the Wagtail meeting guide is over here, last updated 21 days ago. And you'll see it's been seeing a fair amount of activity lately, so it's coming along.
Speaker 1: And within Wagtail, here's how it looks. So if I come to pages, you'll see the way this is a tact we took, which is interesting. So we're actually using Wagtail here to manage the location and meeting data, but we don't want it to appear as pages. So we have made locations and meetings a top-level page within Wagtail without it being attached to any site. So it's kind of a detached top-level page, which is a great way for keeping us within one admin interface. So the same place they go to update their locations and meetings at the same place they go to update the website. So within the CPA website, another shout out to CodeRed CMS. We have integrated code red CMS with our main site. You can do that. And these are all code red pages
Speaker 1: here. But within the locations and meetings, you'll see that we actually have all the locations that host meetings, and then all the meetings are our child pages of that. So if we come into locations. You'll see that there is no site set up for this location, as I mentioned. That's intentional. And within each location, all the meetings within it are child pages. So if I go ahead and edit this top meeting, we use this great little uh geocoded address plugin Which is wonderful. It does autocomplete on it. It's uh it's one that I absolutely love so that people can so that our office users can in a straightforward manner Pick what region this meeting is in.
Speaker 1: It also gets geocoded automatically by uh by Google. And then uh just put in the address and see with a pin on a map in real time. So for example, if I were to change this, and I won't save it, but if I put in 3730 Walnut Street, Philadelphia PA, address has been geocoded, it automatically updates the lat long, and you will see here we are in Huntsman Hall. There is the building. You can see the Death Star part of it right there. And then also within it you can come in and see the individual meetings
Speaker 1: So the day of week it's on, the start time, the end time, if it's associated with an actual group or whether it's just a meeting, and then the different types of meetings that are available
Speaker 2: What's the map budget that you called?
Speaker 1: Sorry, what was that?
Speaker 2: What's the map budget that you called?
Speaker 1: I want to say it's Wagtail G Maps, I believe is what it was called. I'll have to double check. We can look at my requirements file in a minute. So this is a much less intimidating interface for our office staff to use than what you saw in WordPress. You know, to underline what Thibaut was saying earlier about when you improve accessibility, you improve the use for everybody. I think that is truly the case here. because that kind of thinking has made this for people who are not tech professionals very usable and they've been very excited to start using this. We're still in the process of finishing it. The new React front end still needs some work. But here's a look at the API. So I'll just hop over to the raw data.
Speaker 1: This is actually the data that's provided by the API. So within Wagtail, rather than presenting any of that data that is input through the Wagtail admin on typical pages, We just made a separate Django view that returns type textjson and do an ORM query to pull out all of these data we need. And then we present it as an API for the front end to consume. And uh within the front end Here's the actual React app so far. It still has some work that needs to do, but this is entirely built off the same API feed that we use for the mobile app as the front end We've also completely decoupled all this front-end code to only require the API. So this could be used with flat HTML and flat JSON.
Speaker 1: We've made it so it can do flat HTML using uh Google spreadsheets with JSON output as an in as an ingress point. We have made it so this will eventually replace the WordPress front end with the React front end. This will be part of the Wagtail plugin And if people want to do it for Drupal or whatever else, you can basically, if you've already coded up the API, you can plug in this React front end on that API on the back end and use it with your intergroup with your preferred technology out there. So if I go ahead and want to see the meetings tomorrow on Friday, I can pop over to a map And oh, that's a heck of a lot of meetings. Maybe let's just look at the newcomer meetings.
Speaker 1: Okay, that's a little more manageable. I can click on anyone that I want. There's a bug with the Z indexing, but we'll get that fixed. And I don't think we have directions plugged in or anything like that, but as you can see it's coming along. You can go ahead and click on any meeting you want and it will list all the other meetings that are at the same address. So We Are Not Saints is on Monday. Franklin Town is another one on Monday, so you can scroll right through. and see all the meetings that are an individual location. So it's coming along nicely. And you know I'd intended to go into a deeper tech dive, but I wanted to talk a little bit about something else for a moment. Um c so a couple weeks ago, um
Speaker 1: I had put out a call For help with the website. So right now, if uh you know I were to get hit by a bus or something, the local intergroup would be in would be a little hard-pressed to keep things up and running. uh especially with the development of the new Django site. And uh this is not our Tom D here, but uh a guy called Tom D reached out who is a local Python Django developer and expressed interest in getting involved and he seemed really psyched. And uh we met for coffee and uh it was really nice to kind of get to know him over coffee and he had started to work. Uh we are also working on making it so you could output from that API for the printed guides that people pass around. And uh I hadn't heard from him in a couple days, so I emailed him on July 3rd
Speaker 1: and uh you know asked how he was doing and he said his grandfather had died and he was hoping to get back to coding that weekend uh you know july sixth, July seventh. And uh I found out a couple days after that that he had relapsed, overdosed, and died. So it's a reminder that this is a deadly progressive disease. And uh You know, it really sucks. It really, really sucks sometimes. And uh You know, I was just getting to know him and he was really bright. He was 31 years old. He was a volunteer firefighter, part of the volunteer firefighter scuba diving unit who actually, you know, when they're electrical fires, they like scuba underwater to figure out what the heck's going on and
Speaker 1: you know it's a it's Th this disease is uh you know something I have to deal with every day. And uh you know there's they they say probably between ten and fifteen percent of Americans are dealing with active addiction, which probably means there are a couple people in this room who are, or at least friends of people in this room who are. And uh you know getting into recovery is the best thing I've done in my life It's been the most majestic journey I've ever had. There are a couple people in this room who uh remember me before I got into recovery a couple years ago. And uh it wasn't always a pretty picture. But I I don't want to leave on on a total-down note, so I wanted to share a uh this was originally a lightning talk I gave at uh at DjangoCon last year, so
Speaker 1: Let me uh swap over to mirrored mode again real quick. So, I've always loved writing code. I started coding when I was about six years old. My godfather was named Charles Capps. He was a professor of computer science here at Temple University. And in 1974, he wrote a book called An Introduction to the Theory of Computer Science. So he lived three doors down from my parents. And uh, you know, I got into coding very young. I remember eight and a half inch floppies, just absolutely fell in love with it I also loved Legos and now you know I consider myself extremely lucky to basically get paid to uh play with
Speaker 1: grown-up Legos, you know, putting stuff together and being able to say at the end of the day, here's what I made. It's a pretty darn good feeling But uh this is my GitHub contribution chart for 2014. Does uh does that look like the chart of somebody who loves to write code? Not really. The truth is in 2014 I wasn't doing what I loved. I'd been slipping further and further away from doing what I loved for a long, long time. While I still worked hard and you know I had a lovely home, squaring who I thought I should be with how I acted was uh was getting harder every day. It was getting harder and harder to uh to look at the guy in the mirror So, come 2015, I decided that I had to change just one thing.
Speaker 1: So, uh what happened right about here? In April I had asked for help with my alcohol addiction problem. And in May I got out of rehab and I've been clean and sober since. And you can see right here that in May, my contributions immediately almost spiked up. And, you know, so that was a That that was a big life changer. And you might ask it, what happened over here? That was a very, very tragic mistake. I reopened my World of Warcraft account So productivity took a little bit of a dive. And then throughout 2016, uh it's a little bit sparse, but I was uh
Speaker 1: helping organize this thing called DjangoCon. And also contributing to some private repositories. But as you'll see, by 2017 , I had really hit my strive. I'd gotten involved in some open source projects that I absolutely love, including Wagtail by that point. And uh we also started to open source some projects that we had made here at Wharton within private repertor repositories. We moved them over to public GitHub repositories, so the activity started to pick up. And uh you know by 2018 This is what things look like. So as you can see now, I'm pretty active again in doing what I love, writing code with a community of friends, old and new. So I just want to leave you with a thought. If you could change just one thing about yourself, what would it be? If you need help to make this change, ask for it.
Speaker 1: You know, I waited for so long and all I had to do was ask for help. My friends were so incredibly supportive. You know, it saved my life And as Gandhi said, we must be the change we want to see in the world. So if you have a problem, whether it's addiction or otherwise, sometimes changing one thing can change everything. And uh it's meant the world to me. I'm really proud to call you all friends and be part of this community. Thank you all for being here today. Thanks.
People who don’t feel welcome may leave without getting support, and the consequences can be fatal. The speaker emphasizes that trans people face higher rates of addiction and suicide, making inclusive meeting spaces especially important.
Discussed at 7:50Each intergroup manages its own meeting data and provides it through a shared API specification. The central database checks each intergroup’s feed twice a day and gathers updates for the app.
Discussed at 13:17The WordPress setup had become complicated and hard for office staff to use, often requiring developer help for routine updates. The team wanted a simpler Wagtail admin and a React front end that could use the API already built for the mobile app.
Discussed at 18:02They represented locations and their meetings as nested Wagtail pages, but kept them detached from any public site so they could be managed in the same admin without appearing as regular pages. Editors could enter addresses and have them geocoded automatically.
Discussed at 20:23A separate Django view queries the meeting data with the ORM and returns it as JSON through an API. The React front end consumes that API, which is also used by the mobile app.
Discussed at 23:42Ask for help. The speaker says that asking for help with his alcohol addiction saved his life and that his friends were supportive.
Discussed at 31:31Note: We understand that names change, people change, and bodies change. We respect each individual's journey and privacy. If you have any concerns about a video or need us to remove content, please don't hesitate to contact us. We will handle your request with care and promptly address any issues.
Published July 19, 2024
Published July 19, 2024
Published July 19, 2024
Published July 19, 2024
Published July 19, 2024
Published July 19, 2024