Alright, just watching ways on 1st of December, WHO as a World Health Organization joined partners to commemorate World AIDS Day 2022 under the theme equalize, WHO is calling on global leaders and citizens to boldly recognize and address the inequalities which are holding back progress in ending AIDS and equalize access to essential HIV services, particularly for children at key populations and their partners, men who have sex with men, transgender people, people who use drugs, sex workers and people in prisons. This is a very important day because today also marks our 30th anniversary on Ways. I remember we launched the show on World AIDS Day in 2019 and you know three years down the line here we are. I mean AIDS is one, I don't know how to explain it, is there but it's not there. But there's so many people that you hear, I mean recently I don't know who was telling me of a couple that the man had died then later on the wife also passed on because again he had infected her with HIV. So I mean we talk about these things but people do not really pay attention. I think I saw on social media the governor of Lagos State distributing condoms you know as part of his campaign strategy saying that you know protect yourself, STIs, STDs are still very much prevalent. I think people also need to realize that there are other ways AIDS or HIV can be transmitted and not just through sexual intercourse, you know. Like frankly said through drugs, people that use drugs where you have to, what's it called now? Intervenous like the drug here. Yeah. And even in hospitals, even in places where you have a salon, shop, object, I know people just need to be very careful. I think there's a lot of awareness but you know we often consider people that are not open to you know this kind of information, very real areas as well. But I think yeah, the government is probably trying to do a very, they're trying, they're putting in efforts to make sure people are aware of you know this virus so to speak. But to never hear your thoughts on AIDS then we come to your what's in the news. I think that we've come a long way from where it started, right? But I also think that there's become some complacency in terms of awareness. It's not at the forefront of people's minds anymore, right? We all know it's out there. We know somewhere in the back of your mind. But then if you think about the amount of young people who have grown up or become teenagers in this period who may not necessarily have gone through that time of like the 80s and 90s when it was at the forefront of everybody's mind, right? So now we need to continue drives like this. So days like this, when we continue to raise awareness, particularly like Chinala said that there's so many other ways that it can be transmitted and then creating sort of that awareness as well of people living with HIV, removing the stigma because the lack of information or awareness that's been created is because we still have stigma around it. Even though people are living with it now, what are those drugs called? Retroviral drugs, yeah. Yeah, retroviral drugs, right? That people are able to live, ritualize. I remember a lady once coming to speak to us at my workplace and she was pregnant when she was talking to us and she had given this whole entire talk only for her to then say she was HIV and I was like, you know, what's going on? So it's actually, you know, creating a robust awareness of it and just having people be sure and be clear what what they need to know, how they need to protect themselves and if in fact they know anybody that is living with it and how it can be. I think even one of our first guests on the show, the very first show, it's important to keep raising awareness of it, it's so powerful. Absolutely, absolutely. I mean, we'll keep on talking about it because we're not only celebrating what's called an anniversary, it's a very important day to actually just keep the conversation in the media. All right, so Uti, your story, what did you find for us in the news today? My headline, in fact, is a very interesting one. When it caught my attention, I thought, ah, finally. So my headline says, NNPC breaks silence, explains reason for recent field scarcity in Lagos and other countries. Now, nobody is in the last few weeks can say they've not been impacted by this field scarcity, at least certainly here in Lagos and I was expecting, I mean, this has been going on and off, you know, every so often and it either comes down to transportation and logistic issues or it comes to the actual loading, the cost of loading the fuel from the market, what's it called, from the depots. So seeing this headline, I think it's myself, OK, the NNPC is coming out with a valid explanation only for me to see the explanation that the gridlock is due to bad roads in Napa Pa and access road challenges and that Abuja is affected because Lagos is affected and how normalcy is going to return soon because they have sufficient products and they increase in product loading and they're working with all the different stakeholders. Like I read through this story and I was like, hmm, that doesn't sound right.  You're struggling to believe it. I'm struggling because I'm like, ah, well, well, OK. I mean, I have to believe you have to take your word for it, you know. Believe it's a stretch, you have to take your word for it. But I mean, does this sound funny to you? Because it sounds funny to me. I believe it's a fact. What's it? Let's believe them and leave it there. I believe it's a fact. She doesn't know your story. OK, on today's episode of funny stories. Yeah. So I found this post from a popular Nigerian actor where he received a standing ovation as he visited the Nigerian immigration service two days ago. And we saw him bowing for the top officials in the video. The what's he called now the controller general at the NIS office in Ikwe. And he received a very warm reception. You see, everybody came and they were shaking me. And you know, he was even introducing it and I'm like, wow, very interesting. I remember when I went to that place to go and get my passport. And I'm like, shall I not be a celebrity like this now? So that when I go there, I don't have. But like I said, he went there to get his passport to Japan in quotes. And then this was the warm reception. So I don't know if this reception is making him change his mind from Japan or if he's going to. But I think, well, I think because when I went to first start to do my passport term, I mean, the same way was he called the two pictures. They also took pictures with me. But the only difference is that I did not post it online.   You know, the star stroke, right? That's okay. That's perfectly fine. My one thing is that treat everybody with some level of, OK, yes, the person is important. Don't just treat only voluntarily, because there are some people that have been waiting for months have not gotten their passports. I'm sure you've seen that I have been going there for the past how many weeks. And then this is the treatment that voluntarily got. But then it's all right. It's so cute. All right.  But this one is not in Nigeria. So apparently Adee Dami had posted on social media how she got robbed in London, right? According to the post, let me just read it. She said, regardless of where you are or where you plan to go, the most important thing is for God to be with you. My handbag was stolen some weeks ago in London. My phone and all my money for the trip gone in a second, literally, that she said the Met Police even had to get involved. It was like a movie. Thank God for a helper. I would have been stranded in a foreign land. The world has really changed, guys. It's not the destination. I mean, it's not about where we will flourish, prosper. I mean, sorry, it's about where we will flourish, prosper and be happiest. You know, the second slide, she said the second slide has gone a lot from Apple, saying that her phone had gotten to China before her. So apparently, I think so a few weeks back, you know, Token Makiwa had also posted how she got robbed in London, that she's speechless, that all her valuables are gone. Gosh, how could this happen to me and all of that? So I then heard that the UK, the federal government had advised Nigerians traveling to the UK and the US, telling them that the federal government had advised them traveling to UK, Europe to take extra precaution to avoid being dispossessed of their belongings that the Minister for Information had given that advice on the 28th of November, actually, at a news conference in Abuja, according to him, said it has come to the attention of the government that Nigerian travelers to the, Nigerian travelers to the United States, some countries in Europe are having their belongings, especially money and international passports stolen at an increasingly alarming rate, right? Yeah. So, I mean, when you hear these kinds of things, you think, oh, you know, they said the most recent of their travelers to the UK, most of whom were dispossessed of their belongings at the high-growth shops, particularly high streets of Oxford.  When I also went to France, right? I was in Paris, I was on a train, and some guys started trying to phone one kind of, this thing I say, so they don't know who I'd be, you know? They were like, you know, but you could tell that they had very bad intentions, right? But I just kept my calm, because that's the good thing about me, no matter how everything is, I try to be calm because it is in calmness that you can really respond to situations like this. So I think people should just be careful. Again, this is the season for all of these things. People tend to want to steal at this time because they feel like Christmas is coming, I have to do things, and you know, again, because of the global recession that has hit the world, UK is really facing a crisis right now, do you understand? So it is only natural for you to now have some level of crime increasing, yeah. Kuti, you want to say something?  The, this particular, I love how our media called it High Street of Oxford, because it's Oxford Street in London. But I actually got that feedback, because when that story came out the other day, I was like, naturally, anywhere where you have high tourist populations, you tend to find that a lot more pickpocketing, and crime goes on. Now the UK is seeing, I mean, this is, we used unprecedented for COVID, they are literally in a really bad state, economy-wise, they're talking about a cost of living crisis, how people really cannot afford to survive. So the fact is, this is a real reality. So the way we also have seen crime rise, the same thing is happening there, like the cost of food, the cost of everything has skyrocketed. So we are seeing all sorts of creative ways. I mean, in fact, the person I spoke to when she was describing how her bag got picked, it sounded like the scene in a movie.  So it really, I mean, it's a prime destination for Nigerians, so we really do need to take as much precaution as possible wherever we are. But security consciousness can never go wrong. Absolutely. So on that note, we'll take a break now when we come back from the break, we want to discuss religion and culture. Stay with us, we'll be right back.


Cyber infrastructure is something important. I'm unsure. A subgenre of cyberpunk. Stuff in a computer. I think of just an Excel table that you post online. Cyber, obviously, internet. Infrastructure, I think, building. So building the internet, I'm guessing. I saw it on the news recently and a prime minister to the north had a lot to say about it, but I don't get it. But I think it's something that our congressmen should be paying attention to for the benefit of own citizenry and our ignorance. Cyber infrastructure is the combination of computational data storage and network resources that connect them together that are used to perform research. In the late 90s, the U.S. government coined the term cyber infrastructure as they were discussing the critical elements of the U.S. infrastructure that included the computational data storage and communication networks and the other systems that were connected to those systems as a way of identifying those assets that might be vulnerable and needed to be protected. In 2003, the National Science Foundation really started to extend that definition to include those similar capabilities in terms of computation, data management, network connectivity, but to recast it in terms of how those resources can be used to do data intensive and computationally intensive research. As a part of the cyber infrastructure development for the project, we focused both on technical capacity and developing skills and knowledge in our current and future research workforce. EDAC's role at EFSCORE is that we provide all the cyber infrastructure for the EFSCORE projects. We provide all the servers, the websites, the security, data management, data storage. Everything you can imagine about data that needs to be housed for the project is housed here at EDAC. The big things we have here is the data storage. So when researchers do all their projects and do their research, they need a place to put their data. We take that data upload to our servers and then we're connected with data one and data one can consume that and be found out throughout the world through the data one portal. Also with our students, they're great help managing that data because our students will tackle things like metadata coming with metadata standards and helping researchers understand that metadata and apply that metadata so their data can be found. And with the data entry itself is just helping researchers get their data into the data portal and update it to the databases.


Dirty, dirty. Morning, everybody. Feel like going to America today? We've got a trailer that's sitting at Gas Tracks in Pembina, North Dakota, just over the border. And we gotta go pick it up and bring it back here. Remember our slogan? No man left behind. We believe in that up here. Someone left a trailer behind in America and we're gonna go and extract it and bring it home. Like I said last time, good thing our neighbors are our friends. I'm sure they're taking good care of it. Wait for a second. Called the pins on south of the border. Coming up to U.S. Customs here. Just gotta go about one mile past the line down into America. So not too far again today, but we can say that we went to America today. That is a factual statement. As soon as we cross past the Canadian Customs right here on our left, we are on U.S. soil. Which means I will talk to you on the other side. We'll talk to you in a bit. It's a rain. Oh yeah, they got a new side here. North Dakota. Walk right across them. Interstate on and off ramps. They just make so much sense. It almost hurts the brain. Look at this, you get off the highway. Nice, long exit ramp to slow down so you don't have to slow down on the highway. It's a nice overpass to go over the highway so you don't have to risk, you know, getting T-boned by someone or anything along those lines. They got border patrol right here making sure as Canadians stay in line. 28. I'm here for you, gas tracks. The first truck stop in the United States when you crossed from Manitoba at Emerson Pemedu. I see one flat bit over there. Oh no, it's a step. I see it. I wonder if they left it tied down. And I hope they did so I don't have to tie it down on this miss. I'll probably just have to tighten the straps because it seems like some people, the last load I picked up here, they didn't tighten the straps. They were all loose. Kind of scary. You always gotta remember, stop and tighten your straps as the load settles. Straps get loose. Yeah, there it is right there. Trailer on 28. Someone tied down anyway. The trailer was left here. And I don't know why the last trailer was left here. I didn't think we did that very often but maybe we have drivers that only stay in the US.  I don't think we have anyone because in order to work with us you have to have Canadian citizenship and the ability to live and work in Canada. Or at least the ability to, yeah well we had the legal ability to work. So there's probably a reason for it but you know it's a need to know basis I guess. And all I need to know is I have to hook up to this and bring it back to the yard. Take a look at what we're feeling with here. What this is, well it's tight. Feels like plastic. Tight, tight, tight. Just one strap over this. And just one over that. Really? I'm gonna add another one on there for sure. Another one on here. It's a little risky just having one. And there's this back here. Yikes, cardboard's getting all wet now. Okay, well let's get this done and hooked up and get out of here before it starts to rain any harder again. A little wet out here but that's okay. I feel much better about my load. Just because someone else ties down a load for you don't always trust it, okay? I don't trust anybody. Always double check it and make sure it meets your standards. For me at the back here, there's only one strap over this, these two bundles and one strap over that bundle. Now weight-wise it's enough, right? But you want, at least I want to have two straps over here to stop this thing from shifting and to secure it better. So I sat out here in the rain, tightened the straps that needed tightening and added straps where I felt straps were needed. So just because someone else left it tied down, don't just assume it's good because if something falls off and it's hooked up to your truck while you're driving, that's on you. You can't say, well, the other driver tied it down that way. No one's gonna buy that, no one's gonna listen to that. It's gonna be your fault. Tie it down so that you feel comfortable with it. I feel a lot better about this. Yes, it was not fun getting all soaking wet but at least I know that I feel better about what my load securement looks like back there. And it's back to Canada we go. You can see the border from where we were. Literally just like a mile. I think it's almost exactly a mile inside the US. This is North Dakota here. Welcome to North Dakota. If I didn't tell you it was the US, would you know? Our two countries are so similar. Very different in some ways but to anyone who is not from Canada or the US they probably assume we're the same thing. We look the same, we sound the same, we act the same, we eat the same but once you get to know us there are differences, there are definitely differences but they're minuscule compared to other things. We are very close friends. We have the longest unprotected border in the world. Don't get me wrong, they're border checkpoints. You have to check in at the border but there's no military, it's a demilitarized border. Absolutely no military on either border. No buildup anyways. We watch each other, we watch each other, keep an eye on each other but we're not worried about problems on this border. I'll see you on the Canadian side. I can't film here. Oh we're just getting going now. We're on the Canadian side and you can see the Canadian border out the window there but I had to wait here for two hours. Paper work was something wrong with the paperwork. No, it was something that hadn't happened to me before. There was a glitch in the system and my trip number got canceled. Trip number is for our purposes, not for the border's purposes. My par's sticker, my par's number, my entry number for the border purposes, those were good, they were legit and everything went through there. Our trip number for our records had been canceled in their system so they couldn't let me cross. I know I called into the office and I'm like, I don't know why they care about our records but our records apparently were canceled but their records are good but they don't want me to go until our records are good too. Goody, look at how bad we are. I had a really good supper yesterday and they're gonna be so disappointed in me. Probably gained a few pounds again. It's a really good thing that I went and secured the load better. I don't think these guys here in the scale house would like the way the load was tied down before. I wonder if the guy took some straps off before leaving the trailer there. That's what I want to believe. I want to believe that that wasn't, it wasn't pulled down the highway like that. Hope could easily shift if it was tied down but I'm sure he took some straps off and didn't want to leave all the straps there or something. Must have been what happened. More straps than you think you'll need. You look at it and you're like, ah, one strap and hold that down. No, no, no, you better put two. All right, if you're looking at it and you're like, you know what? Three straps will do. Put four, five if you're feeling lucky. Stop before the scale, go on the scale, roll the window down in case they want to yell at me. See them in there looking at my load. Here's pretty high. This used to be a lake at one point. Well, first of all, this was under a glacier. There was a glacier. Everything you see here was under ice, it was under a glacier. That's pretty neat to think of right there. So I mean, things have been warming up for a very long time. It used to be literal ice. North, obviously. I'm facing east right now. That way south, edge of the glacier was melting faster than the north, right? So this all turned to water. Onwards here, all the water drains towards the Hudson's Bay. Glacier up there, blocking all of the waters of the melted glaciers here. That bird just got hit by that door. Did you see that? Rest in peace, little birdie. It flowed north, because the Red River here flows north. Everything drains to the Hudson's Bay around here, right? But there was, like I said, a big wall of ice, a big glacier that was blocking the floodwaters from entering the ocean. So this turned into a big freshwater link. Learned the history of the area you live in. And then, you know, as the climate kept warming and warming, eventually the ice dam up north, that glacier melted away far enough that this water here could all drain into the Hudson's Bay. And that must have been like a cataclysmic world-changing event, because it was like a huge inland ocean, a fresh water, got dumped into the ocean all at once, raising the ocean levels 100 feet, as we know today, became an island and became disconnected from Europe. And these are the things that I believe are there to see it. And all I can say, this is exactly what happened. I'm no scientist, I'm not a geologist, but I do read a lot, and from what I've read, that theory makes the most sense. Where you were a year from, have you ever researched like the history, the area you live in, like what it was like thousands of years ago? Because if I travel back in time, but this exact spot, a few thousand years ago, I would be sitting on top of a glacier. Actually, I'd be sitting under a glacier. I'd be getting crushed. I would be dead. The thoughts that go through the mind of Trucker Josh, while he's staring out the windshield, I tell you, I got lots more, saved some of the others for another time, real one sort of panic, and says everything's heating up. I know it is, and we're probably not helping that, especially driving trucks and stuff and you're making so much CO2. We're probably making things heat up faster than they would have naturally. I'll give you that. But things weren't warming up. I think this land would be kind of useless up here. I mean, who wants to buy a plot of land under a glacier? Nobody wants that. Sort of raised the property values around here, if you ask me, when the ice was melted away. It's not all bad when things get warmer. You don't want it to get too warmer if people start frying alive. You don't want that either. Experts are saying we should be worried. Well, maybe we should have our antennas up and pay attention to what they have to say. This all stemmed from the fact that we're getting rain now when we've been in and throughout all summer, so it's very nice to see the water falling from the sky. It's nice to see water pooled up in the ditches. It's good. Of course, fires too. Diesel, how would you like to come with me to work? You want to go in the truck? Yeah, oh, oh, I think Chevy might want to come sometimes too. I miss having you with me in the truck, buddy. Chevy, what are you doing? What are you doing? I want to come with you to work. I can go trucking. You're going to be scared. It's a lot of noises in there, man. You sure? Tough guy. Diesel, I know every once in a while you would love to come along. I would really like to make this work. I'm thinking of making a little bit of a platform in front of the passenger seat. I think I've told you this before. Just a simple thing. You can just throw in there and you can take out at any time. Nothing permanent. Just something like a platform and then put a blanket or a bed over it so that it turns into a nice little place for him to lay down, right?  He sort of have like a little bed area there. And then on the days when I know that I'm just taking off to Canora and back or doing some other just highway driving. You know what I mean? Come with me every now and then. I like that be all right. I think that would work, mm-hmm. What are you guys thinking? You guys want to see more of Diesel? I miss the conversation. Talking to myself is just not the same. I like it when I have him there to talk with and when he talks back. It's just not the same when it's just me talking all the time. So what do you say, Diesel? It probably can't be every day. Every now and then? Maybe? Yeah, don't get my hopes up, man. Don't get my hopes up.  I paralyzed with happiness. Except for my tail.  This thing was shaking like that just a second ago. Heh! Ghosts. Thanks for watching today, everybody. I hope you guys have a great weekend. I had a great week and I'll see you again on Monday, if not sooner. Take care, everybody.


Hi, I'm Denchy and today I'm going to be showing you how to install RetroArch on Arch Linux and how to also configure it and everything.  The first thing you can do is install RetroArch and just do pacman-s RetroArch. However, that's not the full story because if you just install RetroArch, you won't get any UI element or at least you won't get any working GUI or proper icons in the GUI and all that kind of stuff. So what we're going to do is add an S at the bottom next to this little command over here, so SS RetroArch, and it's going to list every single RetroArch package or package with the word RetroArch in it. And we should install all of these to get everything installed. You notice that it's part of the libretro group, so if you really want to, you can do sudo pacman-s libretro. That won't only install everything you need to get RetroArch running with a GUI as well, but also every single emulator you could possibly need. But I'm only going to need a couple of emulators. So I'm going to do sudo pacman-s RetroArch and RetroArch assets XMB over here, assets Ozone as well, and assets GLUI, so you want to install all of these. And I'm going to need some kind of emulator, so I want a Nintendo 64 one, so I'm going to do libretro-mupin64 plus next. Alright, so press enter, yeah, and that will install everything you need. So that's installed, I already had those packages in my cache, so it didn't download them. It might take a while to download, because it's 88 megabytes, but anyway. Now if you run the RetroArch command, you'll see that RetroArch will launch with the GUI, it will create a config file in our home directory and everything. And we'll be able to move around the UI, we can use our mouse, but I don't really recommend that. You should plug in a controller, but for now I'll just use my arrow keys, X to select something, and Z to go back. So we can loader one existing core, so this mupin64 plus next, so press A to load that.  Yeah, there is Super Mario 64, and there is Mario 64, but that's not all we really want to do, might want to do other things. We do want to do a couple of things to make this whole process a little bit easier, so we'd have to always load the core and load the content, but we can automate that. That's where going to the online updater can help. Now, if you don't touch any of this, and you go to something like import content and scan the directories, for example, at my desktop, and I want to scan this directory for, I don't know, ISO files, and all it finds is that one Mario64 file. We'll go back, and as you can see, it's not anywhere here, despite the fact that they just scanned it. That's because we don't have a database of video games, and we need to actually get that, so we can go to main menu, online updater, update databases. So once again, using X to select those options, and there it is. So now, if we go back to import content, and we go to scan the directory over here, we're going to go to desktop and scan it again. This time we go back, and as you can see, there's a Nintendo 64 icon, it shows up with Mario 64, but the thumbnail isn't there. You can go to main menu again, online updater, and we can update the playlist thumbnails. There you go, and it will download that one, and then we can go here, and as you can see, look, there's a little Mario 64 thing, so you click that, and we can launch it and everything. There is one more thing I do want to cover, it's controller setup. Now, the first time you plug in something like controller, I'm going to just plug in an Xbox one at the moment, get this up here and plug it in. You'll notice that, well, it detects it, but nothing happens when I do anything on the controller, because we haven't actually set up the controls. So I'm going to go to settings, I'm going to go all the way down to input. We're going to go down here to port one control, it's a little bit odd with how it manages it. And now we're going to, we can set all these up, so press bottom key for this, and go down, and set this key for that, go down, and set that key for that, and do this, and basically just set everything up. So I've set all of this up, so now I'm using my controller to input everything, and that's pretty much it, besides a couple of caveats to look at when it comes to Arch Linux. If I try to go here, and go to the online updater, and download content via this, let's say I want to install the Game Boy engine. Yeah, you can't really do that in this. The only way to get new cores is to open up the terminal, and actually install them manually. So do sudo packman dash sss libretro, and it will list every single lib retro thing you can do. So if I want to install, let's say, I don't know, something for SNES, I would do this and maybe pipe it to grep and search for SNES. Those are all the ones I can get, so let's do sudo packman dash s libretro dash SNES 9x, for example, and there you go, that's my SNES 9x core installed. You don't install things via the retro rock interface as you would on other devices, or on Windows, or whatever. You do it via the terminal, because these are packages in it, so that's the one thing that I found a little bit confusing when using it for the first time. So anyway, that was just a short little tutorial, because I always forget how to do this every time I do it, I'm super confused as to, oh my god, where to get the assets, why isn't my database is loading and stuff, it's because I forgot to do the steps in this. So I hope you enjoyed this video, and goodbye.


Well, it's that time of the week again. It's time for Chitchat Across the Pond. This is episode number 774 for July 29, 2023. And I'm your host, Alison Sheridan. This week, our guest is Bart Bouchotte, with Programming Myself 153. And we're going to talk about my favorite subject, Scope. Well, I think this is an episode I'm really looking forward to because after, I thought this was going to be a three-episode arc, but we're finally getting to the end of our journey in terms of learning new stuff. So we are going to come back and do a sort of a farewell episode where we put everything into context. And what I'm hoping is the farewell episode would be like a quick reference for me and I'm assuming many others. Good idea. Wrapping in a bow where we know how to get back to all the goodness. This has been a great series. I'll actually be sad to see it go. I've really enjoyed it. I think I like these smaller bite-sized pieces of something that's not. JavaScript was a long haul. What was that, two and a half years or something? Right. And it was also your very first language. So that makes it a longer haul. Our two more unexpected ones were Gate and Bash. And they've both ended up really good. People are writing to us now going, hey, I just found this Git series. This is really cool. So very cool. I use my own show notes a lot. One of the things I'm really excited about is I have started opening the terminal when I'm coding or when I'm working on the show notes so that I can do my Git stuff right from the command line. And that makes me feel really, really happy.  But I mean, I set up a text expander snippet, Gitcom. And that's my Git commit message with Git commit-am. So I'm just ready to go doing it from the command line. It makes me happy. Excellent. Well, with my work hat on, I do a lot of Git stuff over SSH at which point. You don't have a client, right? So you're in on the terminal at the time. And it really is very liberating, empowering even. Yeah. To be able to do it on the command line. I think that's a really great word to use for the terminal itself. It's liberating. It's powerful. It gives you something you don't have. It seems like it's more limited, but almost its limitations are at strength in some ways. I don't know. It can do pretty much everything. Yeah. Finding the right magic word. All right, so as I say, this one is kind of bittersweet. This is our last bit of new content. But it's actually rather important because as you start to write bigger things, you find yourself copying and pasting the same piece of code multiple times in your script. And that sets off all of your, this is a bad smell from a software engineering point of view thing. And in JavaScript, you would have immediately gone, this is either a function or a class. And I have been finding it ever more difficult in examples and in sample homework and stuff, not to use functions. Because I find myself doing the same thing multiple times. And then it's like, this is wrong. I should do it right, but I can't do it right because we haven't talked about functions and we can't talk about functions unless we talk about scope and scope and bash is weird. And I've been a little bit afraid of it. I'm kind of glad I had a couple of extra weeks on this one. So I'm much more comfortable now. In my talk at Macstock this last week, it was about how I learned by teaching and I used you as an example of how you say that you're often one step ahead of the audience, you know, one week ahead as you're learning stuff. So you've learned a lot in this sequence too. I have, I absolutely have. So today we're going to learn how to use POSIX functions because POSIX is a super set of bash and bash has its own special syntax that only works in bash or we can use the POSIX syntax that will work in bash and SH and ZSH and lots of other places too. So I was like, well, I'm only going to learn one or I'll confuse myself. So let us learn the POSIX way so that our knowledge is portable. And then the other thing is, yeah, we'll get to lexical versus dynamic scope a little bit later, but let's start with functions but before we even do that, I did set you a challenge last time, which is a bit of a cheat of a challenge because the challenge was to take your existing sample solution for our multiplication table printer script and to rewrite it to make use of XRX and or arithmetic expressions as appropriate to your particular code. But of course I used my example to show why XRX is great. So I'd already done the XRX part of the assignment. Cheater. Cheater a bit, yeah. So all I ended up doing, now I have included my full sample solution in the zip file PBS152 dash challenge solution that SH. So for me, it was about changing the mathematics into arithmetic expression. So instead of writing, of echoing a string and piping it to the basic calculator BC, which is a bit messy, instead I was just using the dollar per end per end and then writing out the mathematical equation properly and then catching the value that way, which does make nicer code, let's be honest. Right, right. So the other thing that that let me do in the challenge solution was to revisit one of those little things I told you to turn into a text expander snippet and not to think about too much, which is that every time we're finished with opt args, sorry, with getting optional arguments, yeah, with opt args, sorry, get opts. Why does my show not say opt args? It should say get opts. Oh, fix that. Yes, that's interesting. So every time we use get opts, we have to finish afterwards with this little bit of boilerplate that basically says take all of the optional arguments that may or may not exist and take them off the front of the array of arguments so that they're out of our way and then continue the script so that dollar one and dollar two are the normal arguments. And so we've been doing that with the shift keyword and then we've been telling the shift keywords to use the value which we compute by echoing opt ind, which is the index for get opt minus one and piping that to the basic calculator, which is really weird looking code. We can replace that with the much nicer shift dollar per end per end opt in minus one per end per end. I think you were really mean to teach us that basic calculator first and then show us, yeah, the arithmetic's here. Well, you were already cranky that there were so many brackets and they meant so many things. I was like, no, I'm gonna keep this one on the back bowler for a bit. There is too much confusion happening here. I stand by that decision. Sure. So let us jump into functions. And the first thing I'm going to do is say that all of us are at a disadvantage because we know how to program in other languages and we think we know what the function is because we've come from JavaScript or PHP or all these kinds of languages. And in those languages, a function takes its input through arguments and gives its output as a value that is returned. And we use the return keyword to return that value. But in Bash, functions don't really work like that. Think of them as a script within a script or think of them as a custom terminal command. They want their input primarily via standard in. They want their output via standard out and they do return something. They return an exit code. They don't return a value, they return an exit code. And so you use the return keyword not to return your value and that's gonna drive you nuts. Okay. So the normal way to return your value is just to echo it. So it goes to standard out. And then whoever's using your function will use the standard terminal plumbing to take standard out. And yeah, what do they wanna do? Is this the middle of a pipeline? Do we want this to go to a file? Do we want this to go to a variable? You don't know. And arguably the function shouldn't care. The function's job is to make some data exist and put it on standard out. Okay. Now, just like terminal commands do have arguments, bash functions do have arguments, but don't think you have to send everything into an argument, right? Bash function, the terminal commands really like to use standard in. So so should your functions. So think of your function as a custom terminal command. I wish there was a terminal command to do blah, blah, blah. Let me make one. Function. Okay. So that's how you should think of it. They're custom terminal commands. Okay. So we're gonna learn the POSIX syntax and there's another thing we're at a disadvantage of. So the POSIX syntax is name of function, space, openParents, closeParents, space, open and curly bracket, all of the commands that make up your function close your curly bracket. Those two parents to you and me and to everyone else who's on JavaScript or C or Java or Perl or PHP or I could list a million more languages, we think that the names of our arguments go in the parents, right? That's what we're used to. Think of those parentheses as one single character that means nothing more than this is a function. It is just a marker to say this is a function. Nothing goes in there. They are purely ornamental. They serve no function other than to say I'm a function. I have a little confession to make. It was a very long time at a programming by stealth before I actually ever put anything inside the parentheses. I sort of always thought of it as just a, this is just to tell me that that's a function. So Dorothy was always telling stuff inside her parentheses and I was always like, well, I'm afraid to do that. I don't know what that means. Well, I guess if you go back to your old self, you'll be just fine because in Bash land or in POSIX land, they are just there to demarcate this thing I'm about to make as a function. And so it's basically name of function, the two parans and then KERDI brackets to contain our function. At least it's KERDI brackets. At least that much makes sense to us. Yeah, yeah, no, that's good. So the easiest way is to show. So let us start with a very simple function that, what am I, yeah, so it's a simple function to do hello world because I think that's compulsory. Yeah, there are laws. We must obey all laws. There are laws. So our function is going to simply print out hello world on one line and then on the next line it's gonna print out inside parans from inside a POSIX function. Just so that our function isn't too tidy. So the script itself, you will find in pbs153a-fn.sh and the script itself will call our function three times by default or if we pass our script a number it will call our function that many times. So we can see our function do its thing multiple times. And I say in the show notes I'm going to do it once by default and then I think I wrote my code to do it three times. I fixed it in the show notes. You had it in the show notes as, you must be missing one poll because it does say function counter equals one and that's what it said in the file it actually says one. Yes, okay, so is it the file of the show notes because it should say one. So I'm wondering. They both say one now. Oh, good, good, good, good. Okay, I did actually pull. Yeah, I'm curious. We might be, we'll have to double check that. I'll make a note for us to check that after the show but yeah, it's a three and I was like. Okay, good, good, the sample output. I was like, how is it three? But it says one, but I fixed it. Yeah, it is one. Yeah. And the sample output in the show notes also clearly shows it as one, so yeah. Yeah. I mean, okay. So looking then at the definition for our function is simply hello w, which is what I named my function, space our two parents, space curly bracket and then echo hello world, echo from inside the POSIX function. And that's it. At the call the function, we just treat it like any other terminal command on planet Earth. We just say the name of the function and it will call the function. Okay. And that really is all there is to it. Okay. Well, that looks like it makes perfect sense. Yeah. Sorry, I can't multitask. I was just sending Bart a little note telling him that something's dinging in his room heard it a couple of times, so. Which it shouldn't be because I have personal focus on but I guess I'll switch you to do not disturb. Okay. Which is even more restrictive. Good. Personal focus. Right. Oh, didn't mean to put my screen saver on. That definitely doesn't help. The audience is like, what are they doing? These clowns, have they never done this before? Yeah, you think not. Anyway, interesting. Okay. So we just call the function by just saying the name of it. There's no parenthesis. Just say the name of it. No two parentheses for that. Just. Nope, because again, it's a custom terminal command. Just think of it as I wrote a terminal command. Okay. So like cat doesn't have parentheses on it. You know, LS doesn't have parentheses. One of the things. Exactly. I was telling Bart before we started, he named his function hello with a W, which I thought was hilarious because I always misspell hello and my fingers just want to put a W on the end of it. So I thought he had done that and I started fixing it all over the place. Then I realized, no, it was hello world. It's going to make my brain even hurt even more. So that'll be even harder. Yeah. The other thing just to draw your attention to, since it's new in our exploration of bash is I am making a point in my examples, this installment to make heavy use of arithmetic expressions to help embed them in. So when I decrement my counter inside my while loop, I'm using double round per ends without the dollar sign because I don't want the value of, I just want it to do the action. So take my counter and decrement it. Good. That actually helped when I saw it again, when I was pre-reading the show notes to see that you're using the arithmetic expressions. I like it. Excellent. And just a reminder that if you put the dollar in front of the arithmetic expression, you get the answer of the math. And if you don't put the dollar, you get the exit code. So that means we can use the arithmetic expressions for conditionals, like for example, only printing an empty line unless we're at the last hello world. So it says round per end, round per end, FN counter greater than zero, round per end, round per end and echo blank string. So that means take the, if the function counter is still greater than zero and it started say at three, it goes three, two, one, it's gonna echo it in as soon as it gets to zero. So we're not getting the, we are getting the execution of the function. So what we're getting there, because we didn't put a dollar front, but we're basically getting true or false or rather successor fail. Oh, oh, wait a minute. From the greater than. Oh, from the greater than, but function counter is a value that's getting decremented. So it's just a variable. Well, that's the line above it. It's a variable. Yeah. It's just a variable. Correct, yes, function counter is a variable. Okay, got it. Yes, because also as a reminder, inside an arithmetic expression, you don't give functions the dollar sign because it's like, this is math. If it isn't numbers, it's a variable. Right. Because the only thing allowed inside your two parentheses is math. So in math universe, you don't need to say dollar X, you just say X. Right, right. Again, it's batch trying to be helpful, but it does have the side effect of sometimes being confusing, which is why I'm making a point of repeating it. Okay, so every function is like a script within a script, I said, or like a custom terminal command. Well, we know that our script gets its very own copy of standard in, standard out, and standard error. And every time our script calls another script or calls a command on a terminal command, that command gets its own copy of standard in, standard out, and standard error, which is why we can use the pipes to manipulate these things, right? The standard out from the cat command is piped into the standard in of the grep command or whatever, so they each have their own. Okay. Functions are like terminal commands. So every time you run a function, that running copy of the function gets its very own standard in, standard out, and standard error. And what they're connected to completely depends on how you call your function. So if you put your function into the middle of a pipe, then your function standard in will be whatever the pipe has just connected to it. If you, like if you just call a command without doing any terminal plumbing, then the standard in for the command is your standard in, the same is true with the function. If you just use standard in without a pipe, then the function has the same standard in your script hat. So it just inherits it, but it does have its own one. So that's just, you know, to note. And also, it can write the standard out, and it's its own standard out. So you can use it inside a pipe just like you can on any other terminal command. So it basically, it behaves like you expect, is what I'm trying to say in very convoluted ways. It works like it should. So the next example I'm going to give is a little function. So you're gonna find that in PBS135B, FNStreams, where we're going to write a bash function that uses the streams, that uses standard in and standard out to be terminal like. And we're gonna write a function that is a terminal command called pal, which is short for palindrome. That's gonna take some input from standard in and it's gonna print it the right way around once and then immediately follow with it backwards. So it becomes a palindrome because you've printed forward and then backward. So you're on mute, Alison. I hope that's intended. I was moving my chair a minute ago and didn't wanna make a racket. No, good, okay. So our function is going to, is gonna take its input from standard in and then write its output to standard out. So inside the function, again, we just say pal, open friends, close friends, curly. So we're saying make me a new function, name pal, and all the rest is just window dressing. So the first thing we do inside our function is we read from whatever happens to be the function standard input, which will be different every time you call the function. Sometimes you might call it inside a pipe. Sometimes you might call it inside a script. The function doesn't know what it will be. It just knows it will have a standard input. And we wanna take that standard input and save it in a variable, which I'm choosing to call stor for string, because it really could be anything. Right, we're just gonna palundromize. So we're using the cat function, the cat command, which by default, reads standard in and prints the standard out and we're catching it with the dollar friends syntax. So we're basically saying the output of the cat command, save it in this variable called stor. And then we're gonna print that variable as is without a trailing new line. So echo minus n for minus no new line. And then we have to reverse it. So there is a terminal command called rev, which reverses things. So we're going to echo our string and pipe it to rev. Why does that exist? That seems like such an odd thing. I mean, it's perfect for this little example, but why does it exist? I generally find that if something might be useful somewhere, so the terminal thinks of itself as a bunch of Lego bricks and you can build any hassle you want. So one thought that would be an idea. So there it is. So that's our entire function. So it reads from standard in and it just uses the echo command for its output. So you'd be used to in JavaScript, creating a string, building up the string and then returning the string. But here the primary output mechanism is standard out. So just echo the stuff, just echo it. That is how you give output from your functions in the normal course of things. Different, not difficult, but different. So how do we use our function? Well, the easiest way to use it is to pipe something to it. So we're going to say echo your palandromic username and then we're going to send, we're going to... So the variable dollar user in all caps is one of those variables that exist in every Unixy system, which is your username. So we're going to take the result of running the command echo dollar user pipe pal and then print that out after the words your palandromic username. So basically the bit that's actually going to pal is echo dollar user pipe pal. So we're going to send your username to our new function. Okay. And it will write to it standard out. The dollar per ends is going to capture that and print it out as a string, a part of the echo command that came before it. So when you run this script, you will see that it does what it says in the tin now. We also then give another example of using our function within a pipeline. So it's not at the end of a pipe, it's in the middle of a pipe. And so we're going to write the host name in all caps. So we're going to take the host name command, which we'll just print your host name. We're going to pipe that to our pal function. So our pal function receives our host name. It will write to it standard out, which we're now going to pipe to the transliterate command, tr, which is going to take all the lowercase a to z and transliterate them to uppercase a to z. So in other words, convert them to uppercase. And so when you echo that out, pal host, which is the variable we're saving all this in two is going to be the uppercase shouty version of our computer's name. So if you run that script, I guess yours is going to say Allison Slyats whatever Allison backwards is. Oh, come on. You know what Allison backwards is? Oh, Nocella.  There probably, isn't anybody else whose name you absolutely should know what it is backwards. Yeah, so it says Allison Nocella, and then it writes my computer name and then runs it right into itself backwards and the whole thing's in all caps. Yeah. So I mean, it's not an exciting function. No, I like it as an example, but it does just what you would expect it to do. Precisely, so we have made a terminal command, right? Whenever we're writing functions, we're making terminal commands and we're being all terminally and we are using the streams. Yeah. So the other very terminally thing is exit codes, right? If you need to communicate success or failure, you do that through an exit code. An exit code of zero means all good and any other exit code means not happy. So we're going to, a very common thing you might wanna customize your exit codes on is a function to test something. Is this a, duh duh duh duh duh duh. Well, that's a very much a success, fail sort of answer. So exit codes are a fantastic mechanism for communicating that. So our third example, 153cfnreturn is going to show how we can use the return keyword to do two things. It stops the function in its tracks and ends the function with the return code we give it. So it's exactly like the exit command for a script, but instead of ending the whole script, it just ends the function. Okay, okay. So if there were other code further down, it would never happen, right? So you might say, if some condition return zero and that will just stop executing the function, like in JavaScript, you can at any point, say, return my string and that will stop the function running. But it's not gonna stop the script, it's just gonna stop this function for a minute. Correct, correct. So the exit command would stop the whole script, the return command stops the function with the appropriate exit code. So we're gonna write a very boring function called is underscore int, which is going to check if something is an integer. So we are going to take our input from standard in and we're not going to write anything to standard out. We're just simply going to return the exit code zero if it is an integer or one if it is not an integer. So again, is in space, per end, per end, space curly. So we're gonna start by taking whatever is in standard in, which is what the cat command does if you don't give it any arguments, and we're going to pipe that to eGREP, which we're going to tell to be quiet. So minus Q for just be quiet eGREP, just give me a return code, don't print anything to the screen. And the pattern we'd like it to match is starts with an optional minus sign and then one or more digits. Okay. And then we're going to do that ampersand ampersand thing and then return zero. So if the eGREP evaluates to true, then we will go ahead and return zero, which means all is okay because in bash world, everything's upside down. Yeah, that was what that pause was because you're going, wait a minute, it should be okay to run. So zero is true, one is false. Yeah, so zero is success. I like to say success in my head. Okay, good. Yeah, that's easier. Or no error. Zero is absence of error. That's actually where it comes from. Okay, that's, that's, and then. So assuming the grep matches, our function will cease at that point. It will say, I'm happy and it will stop running. Oh, because you did a return. Because I did a return. Okay. If that has not happened, I am not happy. Then the second line in the function happens, return one. But it still stops. Yes, there is an error. It still stops. It stops no matter what. It's done now. Okay. Yes. And in fact, it would stop even if we didn't do anything else, but you know. Oh, okay. I see, I was a little confused by just the way this was formatted. It looked like this was all what, everything that was in the script, but actually that's two, you're doing, you're running it. No, is that all in the script? So the function, so the whole script is what's in the show notes, which is just a tiny little four line function followed by yours actually using the function. And that's, that's what's coming next. So check some values. It's also using the function. That's inside the script. Inside the script? Yes, not inside the function. Okay. Okay. Oh, right, right, right. So the function has stopped, but the script can have more stuff in it. In case this is gonna be the input. That's odd. You did the input stuff afterwards. Well, right, you define a function, then you use it. Yeah, okay. All we've done here is define the function. So now it exists, or you can't use a function until it exists. JavaScript does clever things like it, JavaScript will read all of your file and then pretend you'd written the function definitions to the top, it's called hoisting. So when it goes to run your code, all of your functions are at the top of your file. Doesn't matter where you wrote them, when JavaScript runs under all at the top of the file. But in Bash, you better define them before you use them, or Bash is gonna go, oh no. What are you talking about? Is int, never heard of that. Okay, but you haven't walked through the second half of this, but you don't ever use the function. I do, I do, many times. Every time you see is underscore int for the rest of the file, we're calling our function. I don't see is underscore int in the second half of this block of code that we're looking at. So inside the do, on the first line inside the do, we use it. Oh, there it is. Yeah, that's right. Okay, all right, good, it is there. You can see it. Yeah, again, you're looking for parentheses. I am, I am, yeah, you're right, that's what's wrong. Okay. Yeah, so you gotta get into that, but we're making custom terminal commands here. Custom terminal command, custom terminal command. So in order to test our function, we should run it against some values, and I got lazy of copying and pasting. So I made an array with my test values, and then I looped through my array. So my array contains the values 42, which is an integer, 4.5, which is not an integer, minus one, which is an integer, and waffles, which is most certainly not an integer. But I would like an integer of waffles. One, please. No minus one, no waffles for you. No. So we then loop over it with a standard for loop. So for val in, and then that syntax we all love so much to get up all the values in an array into a loop. A dollar, parentheses, name of array, open square bracket, add close square bracket, close or curly brackets, it's a lovely syntax. I can't walk across the keyboard syntax, okay. Pretty much. So then we say inside our for loop, we're saying if, and then we're piping our value into our isint function. So if echo dollar val pipe isint, so we're making standard in for our function b, our variable that we're testing, and then we're echoing out either the value is an integer, else the value is not an integer. So that will then run four times, and when you run it, you will see that it says that 42 is an integer, 4.5 is not an integer, minus one is an integer, and waffles is not an integer. Good. So there we go. So that is an example of us using exit codes. Again, we're behaving just like a terminal command because that's what we're doing here. We're making our own terminal commands. Now, you and I both know that terminal commands can take arguments. Sure, they work on standard in for a lot of their work and they work on standard out for most of their output, but they can take arguments. LS most certainly can take an argument of what folder would you like me to list? If you don't give it anything, it will do something sensible, but it can take arguments. You can give it flags, optional arguments or flags like minus a for show me everything, minus l for give me a long listing. So we know we can have arguments. So of course our functions can do the same. And the way it works is that as well as each of our functions getting their own standard in, standard out and standard error, they also get their own dollar octo slope for how many arguments was I given, dollar at for all of my arguments and dollar one, dollar two, dollar three, et cetera. So all of those special variables we've been using as the arguments to our script, every function gets their own copy of that self same set of arguments. Wait a minute, are you saying that these functions are like we've written our own terminal commands? Hmm. They are. You should also think of your scripts the same. Ha, ha, ha, ha, it's terminal commands all the way down folks. So that actually means we already know how to use our arguments as we've done it before. So let us now make our isn't function a little bit more clever. So just like the cat command will either print whatever's on standard in to standard out or if we give the cat command some arguments it will use those arguments instead of standard in. So why don't we have our isn't function say did I get any arguments? If I got arguments, then I should check if they're all integers. And if they're all integers, then I'm going to be happy. So I'm gonna return success. If even one of them is not, I'm going to return error. Okay, so let us start by first off. So our function is a little bit longer this time because we're making it do some things here. So for the first time, our function actually stretches to about 15 or 20 lines here. So the first thing we do inside isn't is we make a variable named int or e for int regular expression so that I don't have to keep copying and pasting that lovely bit of gibberish that means starts with an option minus followed by one or more digits. Please tell me that's a text expand or snippet by now. Do you know what isn't because I typed, I am so fluent in regex language that it's easier for me to type with and remember an abbreviation. I don't know if that's something to be proud of or ashamed of, but I really, I have a t-shirt that has to be or not to be as a regular expression. It's stupendously nerdy. I love it, I love it. I use it as like a one t-shirt test and so far, four people have laughed.  Anyway, I have saved my regular expression. This is again, avoid code reuse, because if I made a mistake, if I copied and pasted that instead of making it a variable, I would have to find everywhere I made the same mistake where as by saving it as a variable, I only make the mistake, I have one place to correct my unavailable mistakes. It's good practice. Anyway, so we save our regular expression and the first thing we need to do is figure out do we have more than zero arguments? If we have zero, we wanna read from standard A and otherwise we wanna do something else. So the first thing is we say if and then inside of our square brackets so we can test a condition, we're going to test if dollar octo-thorpe or dollar pound or dollar hash or whatever we're calling it this week is greater than zero. So the greater than is minus gt if we're inside our test command. So the square brackets are our test command. And which one is dollar octo-thorpe? What does that mean again? Is that all of the arguments? And it's the number of. The number of arguments. No, all of them. It's gotta, oh good, it's got a number symbol. Yes, one I can remember. So if that is true, we're going to do something new. So put a pin in that for about 15 seconds. Else we wanna do exactly what we did before which is process standard in. So I copied and pasted from the previous, I didn't copy and paste the previous script I used as my starting point and these are the two lines that remain. And all the rest was built around those two lines. So they are exactly what we had before because processing standard in is just like it always was. So the other part of the if is new. Okay, so we did have an argument. There is something to process in the arguments. What shall we do? We shall loop over the arguments. So for val in open single, oh, sorry, open double quote, dollar at close double quote, which is our syntax for exploding our arguments into the loop. So each time we go through the loop, val, the variable dollar val will contain the argument we're processing at the moment. And so we're gonna take the current value we're testing, we're gonna pipe it to eGREP, we're gonna shove it through our regular expression and now we're going to invert our logic. So previously you said and and return zero because there was only one thing to test so we could just do that. I was like, well, this matches our expression. Great, we're done. Well, if I wanna say all the arguments have to be integers then I can't just say, I can't declare victory when the first one checks out. You know, I've won the battle but not the war, right? So I need to just flip my logic around here. And so what I'm saying here is I am only going to exit the function if I fail because if even one of them fails, we're done, right? They can't all be integers if one of them isn't. The first, second, third, fourth, it doesn't matter. As soon as you hit one, return one. Precisely. So now instead of saying ampersand, ampersand return zero, I'm saying, or return one. So I've inverted my logic. I've done a little Boolean trick there. Now, if we make it the whole way to the end of the loop and we have not exited the function, then they must all have passed. They must all have been integers. So therefore I now end that part of my F statement with return zero. Okay. I just thought of something. Your else is taking the form of processing standard in that you did in your previous example. And in that case, I forget, did you have it be that they all had to be? No, your previous example, they didn't all have to be integers. Right, because standard in is one thing. Standard in has a value, so it was simpler. We just had a value to test. Well, now we could have one arc or five arcs or a million arcs. So that's why it's more complicated. Okay, but you're gonna get two different answers from this. If you sent it the same four values, your 42 minus one pancakes and whatever the other one, 4.5, if you send it those as arguments, you would get false. You would get no, there's no integers. But the second test, within the same function, if you are the same script, I'm sorry, if you don't give it any arguments, it's gonna actually to answer you four times. It's not gonna take the collective. Only if you call it four times. Well, you're giving it four. Right, but we did it in a loop. So each time we called it last time, we gave, we called it with one value. We piped a single value into standard in. If we pipe all the values into standard in, that'll arrive as one big string, which is gobbledygook. So it's actually gonna behave exactly like it did last time. I know, I'm saying it is gonna behave exactly like last time. But the first half of your function, if you get, you're gonna get two different ways of looking at the problem. You could give it the same four arguments. If you gave it as arguments, it'll come back false. It'll say you failed. But if you don't give it any arguments, it'll give you one success and three fails. Even though they were the same four values. Not quite. So if you, so last time we called the function four times with one value each time. If we do the same thing and call the function four times with one argument each time, we will get exactly the same output. But if we're interested in answering a bigger question. So basically what we have now done is we've made our script more powerful. It can answer the question, is this one thing an int? Or it can answer a new question it couldn't answer before. Are these all integers? Which is a different, which is a more powerful question. Yeah, yeah, I'm just, I'm showing off that I understand how this works. By saying that you're getting two different answers from the same set of data. Given those four inputs. Fair. If you give them as arguments, you'll get one answer. But if you don't give them as arguments, you're gonna get four separate answers. That is completely true. And it is also true that if you give them as an argument one at a time, you'll also get the four separate answers. True, true. Okay. Interesting. So, yes. Okay, so we can use our self same for loop as last time. But this time we're gonna say instead of piping and stuff, we're just gonna call our function directly. So the code is much cleaner. If isn't dollar val. Wow, that's a lot easier than saying if echo dollar val pipe isn't, that's faffin' about, we just say if isn't dollar val. Well, hey, that's much more Englishy. Then echo yes, else echo no. Okay, it's nice and clean. We can also show it multiple values now. So we can say if isn't 42 minus one, then echo all integers, else echo not all integers. And we can also send it 11 and waffles. And then echo all integers or not all integers. So when you run that code, what you will get is the nice clean answers basically that the first two are all in the first time. Sorry, let me say all that again. The first loop through, we get exactly what we had before. Yes, no, yes, no. The second time when we call it with 42 and minus one, we get, yep, they're all integers. And then we call it with 11 and waffles. We get, nope, not all integers because waffles is not an integer. Okay. So what I sort of wanted to draw your attention to is that the same function isn't within that example there is called in three different ways, right? We can say if echo dollar val pipe isn't and it works just fine because we're taking standard in and our function handles that. Or we can say if isn't a single argument and it works just fine. Or we can say if isn't with two arguments and it works just fine. So we're now starting to write something which behaves awfully like a real world terminal command, right? Yeah, yeah. Okay, so now I need to bring us to variable scope. The cause. We have unwittingly created spooky action at a distance.  And I have had to be stupendously careful in these examples. These examples work despite the fact that I have not taken into account how Bash's scope works. This is where you want to back up and give that description that we inserted at the beginning. This is where I'm leading into that description in about 30 seconds. Okay. So at the moment our code works because I have been really careful to use unique variable names everywhere and never have a clash because all those variables are global. All of them, they're all globals. So they would all stump on each other because Bash by default makes every variable a global variable which is sort of the big picture view of a mechanism for handling scope that is known as dynamic scope which is nothing we have used before uses dynamic scope. We have lived in a universe of, well, I don't think I've ever told you we use lexical scope or static scope as it's also known. No. But we have been. And the reason I haven't said it is A because very few computer scientists even speak that kind of jargon and almost every language that you're ever going to come across with the sole exception to my knowledge of shell script is lexically scoped because that's how our humans tend to work. So what is lexically scoped? What's that definition? Lexical means wordy things, right? A lexical analysis, you're analyzing the word. So a lexical scope where in the code your variable is defined determines the variable's scope. Okay. So you're used to me saying to you if I define a variable inside the function it comes into being at the opening curly bracket and ceases to exist at the closing curly bracket. Right. So it is lexically scoped in your source code within its containing curly brackets. Okay. And no matter how deep you nest the variable the curly brackets are always what's giving it its lexical scope. So the line on the file tells you the scope. So lexical and slash static which are synonyms in this case static is the opposite of dynamic but neither one of those sound like where I define it matters versus it doesn't matter where I define it. So what is the other word of you? I'm gonna have to come back to the definition every time because those words don't mean that. I know. They do mean that. But again, they're hard to define. Yeah, yeah. It's hard to, I don't like the names but I can't think of a better one. Yeah. Okay. So let me see if I can say it again because we've been talking a lot about it. Static slash lexical is where like JavaScript where you define it that defines its scope but dynamic means it's always global. Yes, and. Okay. There's a very important and here. So what makes dynamic scope dynamic is that the scope is figured out by how your function is called. So if you have a variable called waffles and that variable is inside a function inside a script. Depending on how you call that function waffles may have a different value. So you could have another function called pancakes and pancakes could set the variable waffles to 42 and then call the function waffles. And then waffles will see, I've mixed up my names here horribly. That's okay. I lost you in the waffles anyway. Yeah. We're gonna say the variable is called waffles and the functions are called function one and function two. Okay. How's that? All right. So we have a variable called waffles and if I say in my script waffles becomes equal to 42. And then inside function one I print out the value of waffles. It will get the 42 because it was set in the function before I, because it was set in the script before I called the function. Okay. If in function two, I have a line that says waffles becomes equal to minus one. And then the next line is called function one. Then the value is actually going to be minus one. Oh, come on. The code hasn't changed. Where I call the code affects the value it sees. That's horrible. It's horrible until you think about how shell scripts work and then it makes perfect sense because we have been using this dynamical scope all along. We just haven't known it. So by default, everything is global but it doesn't have to be. You can expressly say, I want to make these variables local to me. So inside your function you say to bash these variables are mine. I want my own copy of these but you then create a new universe. So every function or terminal command you call inside your function sees your value. So it's like you're casting a shadow, right? So there was a global value and you made a new value when you're casting a shadow on everything you call. Okay. And if something you call changes the value it can make another littler scope for everything it calls and cast a shadow inside the shadow inside the shadow. So you're projecting down. So now think about how variables like the input file separator work, ifs. So I have told you to be really wary of messing with ifs because ifs is global. I haven't told you about functions. If you would like to use ifs within a function you are 100% safe to do so as long as you will localize it. So if you say local ifs which we're gonna get to the syntax in a second but if you basically say I want to make my own ifs then your spooky action at a distance is gone. Oh. Because now your change only applies inside your function and everything you call from your function. So if you want to make the input separator be the comma instead of the new line character if you do it inside a function and you've expressly say make it a local variable spooky action at a distance evaporates because you haven't messed with all the rest of your script, right? Okay. It's only being constrained by your function. So when you're writing functions that use variables you always have to ask yourself global or do I want my own? Okay. So probably be safer to do local unless you're sure you want a global. Bing, bing, bing. So by default you should get into the habit of starting every function with a line that localizes your variables. So the syntax to say this one is local is the keyword local followed by the names of one or more variables. And just like with a for loop we don't say we don't say for dollar val, we say for val in you say local var one, var two not dollar, var one, dollar, var two it's just the names of the variables. And so we can use those to localize our variables. Now I have jumped to go in slightly on the show notes because it just was being if that flowed really well. Okay. It did and I wasn't going to stop myself just because my show notes were a different word. I noticed that and then I went, no, it's working.  So if you were unaware of this reality of how bash works and you naively wrote a function to say add an optional argument to or isn't, right? So the get ops command manipulates dollar one, dollar two, et cetera. Well, every function gets its own dollar one and dollar two. So you would immediately assume that get ops will work just fine within a function and it does but it won't work just fine without spooky action at a distance if you don't remember to localize things. So we're going to do it without localizing things so we break everything. Okay. So we are going to make our isn't function take one optional argument, a flag minus a and if that flag is set, then we will accept any integer instead of all integers. So in our previous one, if you gave it three values they all had to be integers. If you say minus a then any can be an integer. So effectively an or instead of an and. Okay. Seems like a reasonable thing to do. So if we just take the syntax we're used to and we shove it in our function before we do the test for whether or not we have any arguments we do the normal get ops stuff. So I'm still saving my regular expression to a variable called int or e because I still want that. I'm making another variable called any okay and I'm setting it to the empty string. That's just going to be my variable to know whether or not we're in anything or everything mode. It's just my variable to hold that fact. Then we're going to use get ops and the pattern is colon ooh, colon a, no colon, typo Bart. What should it be? Just a because a doesn't need a value. And no colon after? No, so colon a for I want my own error messages but a is a flag that doesn't take a value. Yeah. So just colon a. Okay. So while get ops a so while get ops our pattern is colon a and then we're going to save the current value in a variable called opt. Then we're going to do our usual case opt in. If it's an a we set any okay to be one. Otherwise we print out our error message and instead of saying exit one, we say return one because we don't want to kill the whole script just because they use the function wrong. We just want to end the function. So that's the only thing that's changed here from what we're used to. And then we have our code like before for the most part but we've added in an extra if statement to say if any is okay we need to do a third type of logic. So we're still going to have a loop but this time we say if we find any one that is a valid integer we can immediately jump to success without testing anymore. Oh, okay. So we now have a third different convoluted way of having this logic, right? So we have if statements inside of statements but it's just logic, right? It's nothing new to us. And if we run this function, the first time we call the function everything is fine. It does exactly what we want. So we call the function with multiple arguments we don't give it a minus a and it quite correctly gives us the answer we expect. And the second time we call it with the minus a and it still works fine. It still says, yeah, there's at least one interjournalist at test values. And then the third time we call it without the minus a with exactly the same input we used before and now it barfs.  What? Why? How? The answer is because the way getOpt works is it uses a variable called opt in to count where it is in the list of arguments. How far have I gotten looking for my optional flags? That's how we can do that little opt in minus one trick at the end. Right. So the opt in does counting. It's a global variable. Okay. So the first time we call our function, opt in starts at zero and moves forward until it meets the minus a. Right. The second time we call our function there is no minus so opt in doesn't move but it's not at zero. It's still sitting out here in the middle. The third time we call our function opt in is not at the start of our argument list it's in the middle of our argument list and the first thing it meets is minus one which is our test value. And it goes what minus one? That's not in my list. Error. So because it's a global variable. Okay. I think I lost you at how opt in is being used as an input to this function. Not to this function to get opt. Get opts uses opt in opt in's belongs to get opts. Okay. But we never. So when you say while get opts. Right. Get opts is using a get opts says start opt in at zero. So get opts the first time get opts runs opt in is at its default value of no value. So get opts says oh there is no opt in great make it zero. Okay. And it uses opt in to remember how far it's gotten on the list of arguments inside that while loop. We say while get opts. Okay. It's using opt in. Let me see if I get it. So when you're shifting it you're doing that while it's also changing. The reason we can shift is because get opts has been changing the value of opt in. So why is it barfing again? So the first time we call our function everything is as opt as get opts expect. Mm-hmm. Right. So we call our function three times the first time with a minus a. So the first time with a minus a opt get opt does everything it normally would. So it's slowly counts opt in and it goes how far do I get? I get as far as wherever minus a appears in the argument list. And so the value of opt in is going to be two I think. Okay. It doesn't matter. The value of opt in is not zero. It is wherever minus a appeared in the argument list and we shift by that amount minus one. Right. The second time we call our function we don't give it a minus a. So get opts doesn't actually move opt in because there is nothing there are no minus this process. Sorry, just got it. Okay. That's where the- The third time. Okay. Yeah. The third time it goes through the loop. Oopsie daisies. We now start to look for our options and the first option we find is minus one. Okay. Which is garbage. Right. It goes all wrong. So do we have to localize opt in? Yes, we do. Huh. We have to localize every variable we use inside this function. Okay. We have to localize into re every single variable, right? We don't want any global variables leaking out of this function, right? Like you say, unless you explicitly want it to be global unless there's a reason you want to address something global you shouldn't. So by default, localize all your variables unless you intentionally want to project something into the global scope. Okay. So basically you go through your code and every time you find a variable you localize it. So the working version of this script which doesn't do any weird spooky action at a distance is identical to that version but this very first line inside the script is simply local space and then all the variable names we use which is int or e any okay opt opt in opt arg and val. Okay. Now every time the function is called it gets an entirely fresh into re and entirely fresh any okay and entirely fresh opt and entirely fresh opt in and entirely fresh opt arg and entirely fresh val. So I'm struggling with we have a lot of the same code being replicated throughout this as you're doing these buildup of examples. Where am I looking for where you actually use the syntax of local? So in the final version of this file which is pbs 153 f opt args but I'm in the show notes at the very first line of the function in the function in the show notes is just I just copied the one line rather than copying the entire function again cause I thought it'll be too confusing. So it says localize the appropriate variables local int or e any okay just it's the two paragraphs above reusing functions with source. Okay. I'm looking for localize the and it's not in here a spooky action a distance. I scroll up and down and I'm lost. I'm lost. We're passed to use look. Okay. Oh, got it. Okay. Oh, and I know you said this for the audience but I was busy trying to find it. So local and then you just list all the variables int or e any okay opt opt in opt arg and val. Okay. Yeah, just list them and that's it. All the spooky action and distance just evaporates because now we have a proper scope on our function. So do you start by localizing everything you're doing and then when you realize you need something global then you change it or you remove it from the local list. Okay. Yeah. So when I start a function I put the word local and just leave it there and then every time I go to use a variable I scroll up, type my variable name up there and then I use it. I pretend bash needs me to declare variables. It doesn't. But if you pretend it does then you'll get it right. Oh, okay. So I just pretend that local is declaring my variables which it sort of is, it's declaring them as local. So the final piece of the puzzle for today is I've been saying that the reason we want functions is to avoid code reuse, which is very true. But if you're working in a very specific script that does something really one off you're gonna write a function that has no meaning anywhere ever again, right? It does this one weird thing and you need it in this one script and that's great. But that's not how coding often goes, right? You find yourself doing something quite generic that you would like to use in 20 scripts. Do you write a function in your first script then say, oh great, that one works and then copy and paste it into the other 19 scripts and then three weeks later you find that you've made a typo and then you have to remember the other 19 scripts. No, you don't of course, or you don't want to. So you can pull the content of one bash file into another script as if you had typed it there. Oh really? Basically you import it as if you had just typed it there and the command is source followed by the file name to go get. And so you can give it a relative path and it will be relative to the current working directory which is dangerous because if you have your script sitting in your home directory and you're off in some other directory then your dot is not your home directory and so a relative path would be dangerous. So you can use the trick of Dear Name $0 which we used when we were doing our menu example which is probably what you want to do 99% of the time because that will basically say include this file next to my script. Not next to where I am, next to where my script is. So it gives you a relative path relative to your script. Or the other way to do it is to have a single folder in your home directory where you put all of your utility scripts and then use the full path. Actually you could use tilde, you could say source tilde slash. Sure, but having a relative path lets you know that you're where you are, yeah. Exactly, so I tend to go with the relative path. The point is source followed by a file path will suck all of the code in as if you had typed it at that point in the file. So it's just import basically.  I like it, do you have a lot of these? I do have a few, I do have a few, yes. And I keep them all in sync across my Macs using Shea Maw. I didn't tell you a couple of days ago or I was just doing, oh, I was working with you on making some changes to my git config and then I realized, oh man, I have to go over to my, now that I have two laptops, I had to go over to my other laptop and change it. I was, man, I wish there was some way to like version control this, but no, oh, he's gonna spank me if I say that out loud. Well, that's an easy answer. So if you picked up a series while we were just on bash, you might wanna go back and take a look at the Shea Maw series. Indeed, yes. Which will get you into the gist rabbit hole because Shea Maw is very giddy, which is a good rabbit hole to be in. Exactly. So we have now arrived at a point where we really have covered not just the bash basics. I had intended this to be a very superficial view of bash, but you know something, we've actually covered more bash than most sysadmins will ever use. Because most sysadmins use other people's bash and they don't quite know what it does. We now have truly covered all of the important features of bash.  But in terms of new stuff, in terms of ideas and concepts, we actually have a really good grasp of shell scripting now. And we have all of the means we need to do this as the English expression goes in anger, because we can use functions and the source command to break apart our reusable pieces and stick them in such a place that we really can build up a library of shell scripts to do powerful things for us. And you know, you could then combine that with something like TextExpander to call your various little scripts and things, but you know, we're building up really powerful stuff here and we've learned a lot of very powerful tools here. So I think the big takeaway from today is that we know how to make functions, we know how scope works. And finally, I can stop saying, never mess with ifs. I can change my advice to be only mess with the localized copies of ifs. So once you localize it, you're not doing spooky action at a distance anymore, you're doing very controlled action at a distance because you are deciding that you need the inputs everywhere to be the comma for your purposes within this defined piece of your code base. That is powerful, not spooky, that is good. So three months ago when I tried to use ifs and you said, no, now we know the answer why. Now we know why I was very, I didn't want to really go into too much detail of why it was dangerous, but I definitely said it could cause spooky action that this instead of might bite you. And I worked very hard in my examples to avoid it, which sometimes was a bit circuitous. Right. I was like, I know there's a right way to do this, it's the local keyword, but I can't say it yet. No, I can. So I always like when we get to this stage of a series because I can stop remembering what it is I'm lying by omission about cause I never tell you an untruth, right? I work really hard never to give an untruth. I just very judiciously don't mention the things that would be confusing until we're ready. And I'm done, they're all gone. I don't have any more hidden little mustn't say, mustn't say, and I love that cause then I can just do stuff. That's a lot of mental work you've been carrying. Yep. Well, it's always the case. And it's like I say, I never want to lie, but I do want to not confuse, which is difficult. So we're going to wrap it up in a bow next time. If you would like a challenge, I'm afraid I wasn't very imaginative of this time, but I can promise you that your code for printing out your multiplication table reuses some logic in a few places. It must have some bad smells of code reuse. Find them, replace them with functions. There we go. Easy enough. Well, this, I've got to give you a tip of the hat. I know there have been a lot of times I've struggled with trying to understand things. These show notes are amazing this week. These are, not that they aren't always, but the clarity and the simplicity of your examples really helped that they weren't big complex things. They were small bite-sized pieces that I could go, okay, I know what, check him to see if something is an integer. Okay, let's just do that little tiny thing. So I appreciate that. Thank you. I know it takes extra work to be simpler than it does to be complex sometimes. I'm just really happy we by accident had quite a few weeks to write these notes because they went through a few iterations. Okay, good. But I'm really happy where they ended up actually. I went out for my cycle in a very good mood and even though I got a puncture, I still came home in a good mood. Good, good. All right. Okay, well until we convene for one more bit of bashing, happy computing. If you learn as much from Bard each week as I do, I'd like you to go over to let's dash talk dot IE and press one of the buttons over there to help support him. He does 98% of the work here.  If you go over to let's dash talk dot IE, you can support him on Patreon. You can donate via PayPal or you can use one of his referral links. I really hope you'll go over and help him out. In the meantime, you can contact me at Podfeet or check out all of the shows we do over there over at podfeed.com. Thanks for listening and stay subscribed.


I am welcome to the session. My name is Shashi and I am going to help you with the following question. Question says, find all points of discontinuity of f, where f is defined by fx is equal to modulus of x upon x, if x is not equal to 0, fx is equal to 0 if x is equal to 0. First recall, let us understand that function f is discontinuous at x is equal to a, if left hand side limit of the function is not equal to right hand side limit of the function at x is equal to a, or we can say limit of x tending to a plus fx is not equal to limit of x tending to a minus fx. This is the key idea to solve the given question, how start the solution? We are given fx is equal to modulus of x upon x, if x is not equal to 0, fx is equal to 0, if x is equal to 0. Now, first recall, let us consider fx is equal to modulus of x upon x, modulus function we know modulus function is continuous at all real numbers and this is a polynomial function, polynomial function is also continuous at all real numbers, so fx is equal to modulus of x upon x is continuous at all real numbers except for x equal to 0, as we can see for x is equal to 0, fx is not defined, so we can write function f is continuous real numbers x is equal to 0, only we can see function is defined at x is equal to 0, so we can write fx is equal to 0, function f is defined, now let us find out left hand side limit of the function, that is limit of x tending to 0 plus fx which is equal to limit of x tending to 0 plus modulus of x upon x, this is further equal to limit of x tending to 0 plus x upon x, now x and x will get cancelled and we get limit of x tending to 0 plus 1 which is equal to 1, here we have taken modulus of x equal to x as we know for x greater than 0 modulus of x is equal to x, so here for right hand side limit modulus of x is equal to x, so we get right hand side limit of the function at x is equal to 0 as 1, so we can write limit of x tending to 0 plus fx is equal to 1, now let us find out left hand side limit of the function at x is equal to 0, so we can write limit of x tending to 0 minus fx is equal to limit of x tending to 0 minus modulus of x upon x, now this is equal to limit of x tending to 0 minus minus x upon x below for x less than 0 modulus of x is equal to minus x, now this is equal to limit of x tending to 0 minus minus 1 x and x will get cancelled and we get minus 1, now this is equal to minus 1, so left hand side limit of the function at x is equal to 0 is equal to minus 1, we know value of the function at x is equal to 0 is 0, so therefore limit of x tending to 0 minus fx is equal to minus x tending to 0 plus fx is not equal to limit of x tending to 0 minus fx is not equal to f0, we know right hand side limit is equal to 1, left hand side limit is equal to minus 1 and value of the function at x is equal to 0 is 0, so all 3 values are unequal, so we get limit of x tending to 0 plus fx is not equal to limit of x tending to 0 minus fx is not equal to f0, so this implies function at x discontinues at x is equal to 0, so this is our required answer, this completes the session, hope you understood the session, good bye.